diff --git a/README.md b/README.md index 60deabb..283318a 100644 --- a/README.md +++ b/README.md @@ -36,7 +36,8 @@ const Demo = () => { } ``` -For including the styles, you should import them in the main `less` file after importing either the `antd/dist/antd.less` or `antd/dist/antd.dark.less` styles. +For including the styles, you should import them in the main `less` file after importing either +the `antd/dist/antd.less` or `antd/dist/antd.dark.less` styles. ```diff @import "~antd/dist/antd"; @@ -63,10 +64,31 @@ number into a single string. "countryCode": 1, "areaCode": 702, "phoneNumber": "1234567", - "isoCode": "us" + "isoCode": "us", + "valid": true } ``` +## Validation + +The `valid` property of the value object shows the real-time validity of the phone number depending on the country. So +this can be used in a `validator` like this: + +```javascript +const validator = (_, {valid}) => { + if (valid) { + return Promise.resolve(); + } + return Promise.reject("Invalid phone number"); +} + +return ( + + + +) +``` + ## Props | Property | Description | Type | diff --git a/package.json b/package.json index 4a344de..4926b66 100644 --- a/package.json +++ b/package.json @@ -1,5 +1,5 @@ { - "version": "0.1.1", + "version": "0.1.2", "name": "antd-phone-input", "description": "Advanced Phone Number Input for Ant Design", "keywords": [ diff --git a/src/index.tsx b/src/index.tsx index 6edddbb..c6d9e3a 100644 --- a/src/index.tsx +++ b/src/index.tsx @@ -5,6 +5,7 @@ import {ParsePhoneNumber, PhoneInputProps, ReactPhoneOnChange, ReactPhoneOnMount import masks from "./phoneMasks.json"; import timezones from "./timezones.json"; +import validations from "./validations.json"; import "react-phone-input-2/lib/style.css"; @@ -35,7 +36,14 @@ const parsePhoneNumber: ParsePhoneNumber = (value, data, formattedNumber) => { const phoneNumberMatch = value ? (value.match(phoneNumberPattern) || []) : []; const phoneNumber = phoneNumberMatch.length > 1 ? phoneNumberMatch[1] : null; - return {countryCode, areaCode, phoneNumber, isoCode}; + /** Checks if both the area code and phone number length satisfy the validation rules */ + const rules = validations[isoCode as ISO2Code] || {areaCode: [], phoneNumber: []}; + const valid = [ + rules.areaCode.includes((areaCode || "").toString().length), + rules.phoneNumber.includes((phoneNumber || "").toString().length), + ].every(Boolean); + + return {countryCode, areaCode, phoneNumber, isoCode, valid}; } const PhoneInput = ({ @@ -79,8 +87,8 @@ const PhoneInput = ({ const onMount: ReactPhoneOnMount = (rawValue, {countryCode, ...event}, formattedNumber) => { const metadata = parsePhoneNumber(rawValue, {countryCode}, formattedNumber); - /** Initiates the existing value when Antd FormItem is used */ - if (value === undefined) handleChange(metadata, event); + /** Initializes the existing value */ + handleChange(metadata, event); handleMount(metadata); } diff --git a/src/types.ts b/src/types.ts index 26d5ab1..fd72315 100644 --- a/src/types.ts +++ b/src/types.ts @@ -9,6 +9,7 @@ export interface PhoneNumber { areaCode?: number | null, phoneNumber?: string | null, isoCode?: string, + valid?: boolean, } export interface AntInputProps { @@ -17,9 +18,7 @@ export interface AntInputProps { style?: CSSProperties, className?: string, disabled?: boolean, -} -export interface AntInputEventsProps { onChange?(value: PhoneNumber, event: ChangeEvent): void; onPressEnter?(event: KeyboardEvent): void; @@ -37,9 +36,7 @@ export interface ReactPhoneInputProps { onlyCountries?: string[], excludeCountries?: string[], preferredCountries?: string[], -} -export interface ReactPhoneEventsProps { onFocus?(event: FocusEvent, value: PhoneNumber): void; onClick?(event: MouseEvent, value: PhoneNumber): void; @@ -63,7 +60,9 @@ export interface ParsePhoneNumber { (value: string, data: CountryData, formattedNumber: string): PhoneNumber; } -export interface PhoneInputProps extends AntInputProps, AntInputEventsProps, ReactPhoneInputProps, ReactPhoneEventsProps { - // TODO add onValidate: https://github.com/ArtyomVancyan/antd-phone-input/issues/19 - // onValidate?: (value: PhoneNumber) => boolean; +export interface PhoneInputProps extends AntInputProps, ReactPhoneInputProps { + /** + * NOTE: Interfaces of events may differ from the original interfaces + * of dependencies, so be careful and follow the linked documentation. + */ } diff --git a/tests/common.test.tsx b/tests/common.test.tsx index f4cdd08..6d5354b 100644 --- a/tests/common.test.tsx +++ b/tests/common.test.tsx @@ -33,9 +33,11 @@ describe("Checks the basic rendering and functionality", () => { assert(value.areaCode === 702); assert(value.phoneNumber === "1234567"); assert(value.isoCode === "us"); + assert(value.valid === true); }} value={{countryCode: 1, areaCode: 702, phoneNumber: "1234567"}} />); + assert(screen.getByDisplayValue("+1 (702) 123 4567")); }) it("Checks the component on user input", async () => { @@ -67,4 +69,19 @@ describe("Checks the basic rendering and functionality", () => { assert(input.getAttribute("value") === "+1 (702) 123 4567"); screen.getByTestId("button").click(); }) + + it("Checks input validation with FormItem", async () => { + render(
+ { + assert(valid === true); + return Promise.resolve(); + } + }]}> + + + +
); + await userEvent.click(screen.getByTestId("button")); + }) })