diff --git a/index.d.ts b/index.d.ts
index 4eae448b9..ef85c2840 100644
--- a/index.d.ts
+++ b/index.d.ts
@@ -287,6 +287,7 @@ export interface InputProps
labelProps?: LabelProps;
maxLength?: number;
unlimitedChars: boolean;
+ rejectCharsRegex?: RegExp;
}
export type LabelProps = {
diff --git a/src/components/Input.jsx b/src/components/Input.jsx
index 03a115022..002775bc8 100644
--- a/src/components/Input.jsx
+++ b/src/components/Input.jsx
@@ -3,6 +3,7 @@ import React, { useState, forwardRef } from "react";
import { useId } from "@reach/auto-id";
import classnames from "classnames";
import PropTypes from "prop-types";
+import { replace } from "ramda";
import { hyphenize } from "utils";
@@ -29,6 +30,7 @@ const Input = forwardRef(
maxLength,
unlimitedChars = false,
labelProps,
+ rejectCharsRegex,
...otherProps
},
ref
@@ -50,6 +52,14 @@ const Input = forwardRef(
const onChange = otherProps.onChange || onChangeInternal;
const isMaxLengthPresent = !!maxLength || maxLength === 0;
+ const handleRegexChange = e => {
+ const globalRegex = new RegExp(rejectCharsRegex, "g");
+ e.target.value = replace(globalRegex, "", e.target.value);
+ onChange(e);
+ };
+
+ const handleChange = rejectCharsRegex ? handleRegexChange : onChange;
+
return (
@@ -101,7 +111,7 @@ const Input = forwardRef(
{...(isMaxLengthPresent && !unlimitedChars && { maxLength })}
{...otherProps}
value={value}
- onChange={onChange}
+ onChange={handleChange}
/>
{suffix &&
{suffix}
}
@@ -197,6 +207,11 @@ Input.propTypes = {
* To specify whether the Input field is required or not.
*/
required: PropTypes.bool,
+ /**
+ * To specify a regex to be matched against the user input. Any character that matches it
+ * cannot be input by the user. It will also prevent such characters from being pasted into the input.
+ */
+ rejectCharsRegex: PropTypes.instanceOf(RegExp),
};
export default Input;
diff --git a/stories/Components/Input.stories.jsx b/stories/Components/Input.stories.jsx
index c738d88d1..874a1f67f 100644
--- a/stories/Components/Input.stories.jsx
+++ b/stories/Components/Input.stories.jsx
@@ -22,6 +22,7 @@ const metadata = {
url: "https://www.figma.com/file/zhdsnPzXzr264x1WUeVdmA/02-Components?node-id=104%3A11",
},
},
+ argTypes: { rejectCharsRegex: { control: "text" } },
};
const Template = args =>
;
@@ -177,6 +178,20 @@ FormikInputStory.parameters = {
},
};
+const RejectCharsInputStory = args => (
+
+);
+
+RejectCharsInputStory.storyName = "Reject specific characters";
+RejectCharsInputStory.parameters = {
+ docs: {
+ description: {
+ story: `The prop \`rejectCharsRegex\` will accept a regex and any character that matches it
+ cannot be input by the user. It will also prevent such characters from being pasted into the input.`,
+ },
+ },
+};
+
export {
Default,
Sizes,
@@ -189,6 +204,7 @@ export {
SearchInput,
InputWithMaxLength,
FormikInputStory,
+ RejectCharsInputStory,
};
export default metadata;
diff --git a/tests/Input.test.jsx b/tests/Input.test.jsx
index 742fbdbab..519542228 100644
--- a/tests/Input.test.jsx
+++ b/tests/Input.test.jsx
@@ -27,6 +27,19 @@ describe("Input", () => {
expect(onChange).toHaveBeenCalledTimes(4);
});
+ it("should not show matched regex value", () => {
+ const { getByLabelText } = render(
+
+ );
+ const inputField = getByLabelText("Input Label");
+ userEvent.type(inputField, "12345");
+ expect(inputField).not.toHaveValue("12345");
+
+ userEvent.type(inputField, "abc123");
+ expect(inputField).toHaveValue("abc");
+ expect(inputField).not.toHaveValue("123");
+ });
+
it("should display error message", () => {
const { getByText } = render(
);
expect(getByText("Error message")).toBeInTheDocument();
diff --git a/tests/formik/Input.test.jsx b/tests/formik/Input.test.jsx
index e504e159c..5a5a45808 100644
--- a/tests/formik/Input.test.jsx
+++ b/tests/formik/Input.test.jsx
@@ -16,11 +16,7 @@ const TestForm = ({ onSubmit }) => {
Sign Up
);
@@ -77,8 +72,19 @@ describe("formik/Input", () => {
render(
);
userEvent.type(screen.getByLabelText("Email"), "john.doemail.com");
userEvent.click(screen.getByText("Submit"));
- await waitFor(() =>
- expect(screen.getByText("Invalid email address")).toBeInTheDocument()
- );
+ expect(
+ await screen.findByText("First name is required")
+ ).toBeInTheDocument();
+ });
+
+ it("should display validation error when string having only rejected characters is provided", async () => {
+ const onSubmit = jest.fn();
+ render(
);
+ userEvent.type(screen.getByLabelText("First Name"), "123");
+ userEvent.click(screen.getByText("Submit"));
+
+ expect(
+ await screen.findByText("First name is required")
+ ).toBeInTheDocument();
});
});