@input-kit/phone 0.5.0 → 0.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,223 +1,240 @@
1
- # @input-kit/phone
2
-
3
- [![npm version](https://img.shields.io/npm/v/%40input-kit%2Fphone)](https://www.npmjs.com/package/@input-kit/phone)
4
- [![npm downloads](https://img.shields.io/npm/dm/%40input-kit%2Fphone)](https://www.npmjs.com/package/@input-kit/phone)
5
- [![CI](https://github.com/harshit-d3v/input-kit-phone/actions/workflows/ci.yml/badge.svg)](https://github.com/harshit-d3v/input-kit-phone/actions/workflows/ci.yml)
6
- [![license](https://img.shields.io/npm/l/%40input-kit%2Fphone)](https://github.com/harshit-d3v/input-kit-phone/blob/main/LICENSE)
7
- [![GitHub stars](https://img.shields.io/github/stars/harshit-d3v/input-kit-phone?style=social)](https://github.com/harshit-d3v/input-kit-phone)
8
-
9
- Headless React phone input with a complete world country-code dataset, searchable country selection, and `libphonenumber-js` powered formatting and validation.
10
-
11
- Source, issues, and contributions: **[github.com/harshit-d3v/input-kit-phone](https://github.com/harshit-d3v/input-kit-phone)**. If this package saves you time, a ⭐ there helps others find it.
12
-
13
- ## Latest update
14
-
15
- **0.5.0**: lighter install. Dropped the `world-countries` runtime dependency (~600 kB unpacked); the names and dial codes it provided are now generated into the package (about 26 kB). The country list is byte-identical, nothing else changes.
16
-
17
- **0.4.2**: documents and locks the built-in **format as you type**. Live national formatting on every keystroke was already there (`formatOnType`, on by default), but it was barely documented and had no regression tests. Added a README section and seven tests covering national, international, per-country, delete and paste formatting, plus proof that the stored and submitted value stays clean. No behavior change.
18
-
19
- **0.4.0**: **correctness fixes, please upgrade.** E.164 was built by concatenating the dial code onto whatever was typed, so the national trunk prefix people actually type survived into the international form: UK `07400123456` became `+4407400123456`, and India, Germany, France and Australia were wrong the same way. Around 106 countries were affected, validation still reported these as valid, and North American numbers never were, which is why it went unnoticed. Now resolved through libphonenumber metadata, so countries that genuinely keep a leading zero (Italy) still do. Also fixes: an inline `onValidationChange` causing "Maximum update depth exceeded"; input past the country maximum being discarded instead of truncated, which silently blanked an empty field on paste; a country selection that reverted on international numbers; the country button not announcing the selected country to screen readers; focus dropping to the top of the page when the dropdown closed; and types failing to resolve for CommonJS TypeScript consumers under `node16`/`nodenext`.
20
-
21
- **0.3.0**: auto-detect respects manual country selection, metadata-based length validation (no more false `too_long` in variable-length countries), input capped at the country's maximum length, `isPhoneTooLong()`, SSR-safe caret handling, dropdown `Home`/`End` + search→list keyboard navigation, unminified published output.
22
-
23
- **0.2.2**: npm README cleanup: release notes stay inline; removed pointers to repo-only markdown files.
24
-
25
- **0.2.0**: structured validation (`ValidationReason`, `validatePhoneNumber`, `onValidationChange`), `parsePhoneValue`, `getCountryOptions()`, improved `PhoneInput` a11y (click-outside, listbox ARIA) and RTL tests.
26
-
27
- ## Features
28
-
29
- - **245 supported calling regions** derived from `libphonenumber-js` metadata, with names and dial codes generated into the package so there is no heavy country-data dependency to install
30
- - **Headless hook** via `usePhoneInput()` plus an optional **unstyled reference** `PhoneInput` component (class names only, no bundled CSS)
31
- - **Searchable country selector** with country name, ISO code, and dial-code matching
32
- - **Format as you type** in the selected country's format, on every keystroke, powered by `libphonenumber-js`
33
- - **Real validation** powered by `libphonenumber-js`
34
- - **International detection** for pasted or typed `+` / `00` numbers
35
- - **TypeScript-first** exports for countries, helpers, hook return values, and component refs
36
-
37
- ## Installation
38
-
39
- ```bash
40
- npm install @input-kit/phone
41
- ```
42
-
43
- ## Quick Start
44
-
45
- ### Component
46
-
47
- ```tsx
48
- import { PhoneInput } from '@input-kit/phone';
49
- import './phone-input.css'; // your own stylesheet, the package ships no CSS
50
-
51
- function Example() {
52
- return (
53
- <PhoneInput
54
- defaultCountry="US"
55
- onChange={(phone, country) => {
56
- console.log(phone, country?.code);
57
- }}
58
- />
59
- );
60
- }
61
- ```
62
-
63
- ### Hook
64
-
65
- ```tsx
66
- import { usePhoneInput } from '@input-kit/phone';
67
-
68
- function Example() {
69
- const {
70
- inputProps,
71
- country,
72
- countryButtonProps,
73
- filteredCountries,
74
- selectCountry,
75
- isOpen,
76
- isValid,
77
- } = usePhoneInput({
78
- defaultCountry: 'US',
79
- onChange: (phone, nextCountry) => console.log(phone, nextCountry?.dialCode),
80
- });
81
-
82
- return (
83
- <div>
84
- <button {...countryButtonProps}>
85
- {country?.flag} {country?.dialCode}
86
- </button>
87
-
88
- {isOpen && (
89
- <div>
90
- {filteredCountries.map((candidate) => (
91
- <button key={candidate.code} onClick={() => selectCountry(candidate)}>
92
- {candidate.flag} {candidate.name} {candidate.dialCode}
93
- </button>
94
- ))}
95
- </div>
96
- )}
97
-
98
- <input {...inputProps} />
99
- {!isValid && <span>Invalid phone number</span>}
100
- </div>
101
- );
102
- }
103
- ```
104
-
105
- ## Format as you type
106
-
107
- `inputProps.value` reformats on every keystroke in the selected country's national format, so the field reads `(555) 123-4567` while the user types. Typing a `+` switches to international format (`+1 555 123 4567`). This is on by default; set `formatOnType: false` for raw digits.
108
-
109
- The formatting is display only. `onChange`, `phone`, `fullPhone` and `parsePhoneValue` still give you the clean value, so what you store and submit is never the formatted string.
110
-
111
- ```tsx
112
- const { inputProps, fullPhone } = usePhoneInput({
113
- defaultCountry: 'US',
114
- includeDialCode: true,
115
- onChange: (phone) => console.log(phone), // +15551234567, not "(555) 123-4567"
116
- });
117
-
118
- // user types 5551234567
119
- // inputProps.value -> "(555) 123-4567"
120
- // fullPhone -> "+15551234567"
121
- ```
122
-
123
- ## Phone values
124
-
125
- | Field | Meaning |
126
- | --- | --- |
127
- | `phone` | National digits stored by the hook (default) |
128
- | `fullPhone` | National number plus dial code when `includeDialCode` is `true` |
129
- | `onChange(phone, country)` | Same contract as `phone` / `includeDialCode` |
130
- | E.164 for APIs | `parsePhoneValue(phone, country).e164` when valid. Prefer this over raw concatenation |
131
-
132
- ## Known behavior
133
-
134
- Formatting, length checks, and validity follow **[libphonenumber-js](https://www.npmjs.com/package/libphonenumber-js)** (same family as `react-phone-number-input`). The package does not implement per-country rules outside that library.
135
-
136
- ## Form integrations
137
-
138
- Controlled `value` / `onChange` with `usePhoneInput` or `PhoneInput`. React Hook Form: wrap with `Controller` and pass `field.value`, `field.onChange`, and `field.onBlur`. Use `onValidationChange` to sync `isValid` / `message` with form errors. Submit-time checks: `parsePhoneValue(phone, country)` or `validatePhoneNumber`.
139
-
140
- ## Styled example
141
-
142
- A minimal Vite demo using only the hook lives in **[examples/react-styled/](./examples/react-styled/)**.
143
-
144
- ## Migration from 0.1.x
145
-
146
- Compatibility aliases remain exported. Prefer the newer names in new code:
147
-
148
- | Deprecated | Replacement |
149
- | --- | --- |
150
- | `setValue` | `setPhone` |
151
- | `value` (hook) | `phone` |
152
- | `allowedCountries` | `onlyCountries` |
153
- | `excludedCountries` | `excludeCountries` |
154
- | `autoDetectCountry` | `autoDetect` |
155
- | `toggle` / `open` / `close` | `toggleDropdown` / `openDropdown` / `closeDropdown` |
156
- | `countries` (hook list) | `filteredCountries` |
157
- | `countrySelectorProps` | `countryButtonProps` |
158
-
159
- Validation is unified in 0.2.0: `isValid` and `error` come from the same `validatePhoneNumber` call. Use `validationReason` or `onValidationChange` for structured form messages.
160
-
161
- ## Development
162
-
163
- Requires [Bun](https://bun.sh) (see `packageManager` in `package.json`).
164
-
165
- ```bash
166
- bun install
167
- bun run test
168
- bun run typecheck
169
- bun run build
170
- bun run lint
171
- ```
172
-
173
- Manual browser check: `test-demo/` (static HTML).
174
-
175
- ## Contributing
176
-
177
- Bug reports, feature requests, and pull requests are welcome, see [CONTRIBUTING.md](https://github.com/harshit-d3v/input-kit-phone/blob/main/CONTRIBUTING.md). In short: open an issue with a minimal reproduction (include the exact phone number and country for formatting/validation bugs), and for PRs run `bun run test`, `bun run typecheck`, and `bun run lint` before submitting.
178
-
179
- ## Exports
180
-
181
- ### Components and hooks
182
-
183
- - `PhoneInput`
184
- - `usePhoneInput(options)`
185
-
186
- ### Country data
187
-
188
- - `countries`
189
- - `getCountryByCode(code)`
190
- - `getCountryByDialCode(dialCode)`
191
- - `getCountriesByDialCode(dialCode)`
192
- - `getCountryOptions({ locale?, preferredCountries?, excludeCountries?, onlyCountries? })`
193
- - `detectCountryFromPhone(phone)`
194
-
195
- ### Utilities
196
-
197
- - `cleanPhone`, `formatPhone`, `unformatPhone`, `validatePhone`, `validatePhoneLength`
198
- - `validatePhoneNumber` `{ isValid, reason, message, error }`
199
- - `parsePhoneValue` → `{ country, nationalNumber, e164, isValid }`
200
- - `addDialCode`, `removeDialCode`, `filterCountries`, `getPlaceholder`
201
-
202
- Compatibility aliases: `stripNonDigits`, `detectCountry`, `formatPhoneNumber`, `parseToE164`, `getNationalNumber`, `isPhoneNumberComplete`, `formatAsYouType`, `normalizePhoneNumber`, `phoneNumbersEqual`, `getCountryDisplayLabel`, `limitInputLength`.
203
-
204
- ## `usePhoneInput(options)`
205
-
206
- | Option | Type | Default | Description |
207
- | --- | --- | --- | --- |
208
- | `defaultCountry` | `string` | `'US'` | Default selected country |
209
- | `preferredCountries` | `string[]` | - | Countries shown first in search results |
210
- | `excludeCountries` | `string[]` | - | Countries to exclude |
211
- | `onlyCountries` | `string[]` | - | Restrict selection to these countries |
212
- | `autoDetect` | `boolean` | `true` | Detect country from international numbers |
213
- | `formatOnType` | `boolean` | `true` | Apply live formatting |
214
- | `includeDialCode` | `boolean` | `false` | Return values with dial code included |
215
- | `required` | `boolean` | `false` | Empty value is invalid |
216
- | `validator` | `(phone, country) => boolean` | - | Custom validation override |
217
- | `onValidationChange` | `(state) => void` | - | Fires when validation result changes |
218
-
219
- Important returned fields: `phone`, `fullPhone`, `country`, `isValid`, `validationReason`, `error`, `onValidationChange`, `filteredCountries`, `inputProps`, `countryButtonProps`, `dropdownProps`, `getCountryOptionId`.
220
-
221
- ## License
222
-
223
- MIT © Input Kit
1
+ # @input-kit/phone
2
+
3
+ [![npm version](https://img.shields.io/npm/v/%40input-kit%2Fphone)](https://www.npmjs.com/package/@input-kit/phone)
4
+ [![npm downloads](https://img.shields.io/npm/dm/%40input-kit%2Fphone)](https://www.npmjs.com/package/@input-kit/phone)
5
+ [![CI](https://github.com/harshit-d3v/input-kit-phone/actions/workflows/ci.yml/badge.svg)](https://github.com/harshit-d3v/input-kit-phone/actions/workflows/ci.yml)
6
+ [![license](https://img.shields.io/npm/l/%40input-kit%2Fphone)](https://github.com/harshit-d3v/input-kit-phone/blob/main/LICENSE)
7
+ [![GitHub stars](https://img.shields.io/github/stars/harshit-d3v/input-kit-phone?style=social)](https://github.com/harshit-d3v/input-kit-phone)
8
+
9
+ Headless React phone input with a complete world country-code dataset, searchable country selection, and `libphonenumber-js` powered formatting and validation.
10
+
11
+ Source, issues, and contributions: **[github.com/harshit-d3v/input-kit-phone](https://github.com/harshit-d3v/input-kit-phone)**. If this package saves you time, a ⭐ there helps others find it.
12
+
13
+ ## Latest update
14
+
15
+ **0.6.0**: the country selector is now a real ARIA combobox. The search field drives `aria-activedescendant` while keeping focus, the active option is the selected one, and a live region announces how many countries matched. Headless consumers get `countrySearchProps`, `activeCountry`, `moveHighlight` and `countryResultsText`.
16
+
17
+ **0.5.0**: lighter install. Dropped the `world-countries` runtime dependency (~600 kB unpacked); the names and dial codes it provided are now generated into the package (about 26 kB). The country list is byte-identical, nothing else changes.
18
+
19
+ **0.4.2**: documents and locks the built-in **format as you type**. Live national formatting on every keystroke was already there (`formatOnType`, on by default), but it was barely documented and had no regression tests. Added a README section and seven tests covering national, international, per-country, delete and paste formatting, plus proof that the stored and submitted value stays clean. No behavior change.
20
+
21
+ **0.4.0**: **correctness fixes, please upgrade.** E.164 was built by concatenating the dial code onto whatever was typed, so the national trunk prefix people actually type survived into the international form: UK `07400123456` became `+4407400123456`, and India, Germany, France and Australia were wrong the same way. Around 106 countries were affected, validation still reported these as valid, and North American numbers never were, which is why it went unnoticed. Now resolved through libphonenumber metadata, so countries that genuinely keep a leading zero (Italy) still do. Also fixes: an inline `onValidationChange` causing "Maximum update depth exceeded"; input past the country maximum being discarded instead of truncated, which silently blanked an empty field on paste; a country selection that reverted on international numbers; the country button not announcing the selected country to screen readers; focus dropping to the top of the page when the dropdown closed; and types failing to resolve for CommonJS TypeScript consumers under `node16`/`nodenext`.
22
+
23
+ **0.3.0**: auto-detect respects manual country selection, metadata-based length validation (no more false `too_long` in variable-length countries), input capped at the country's maximum length, `isPhoneTooLong()`, SSR-safe caret handling, dropdown `Home`/`End` + search→list keyboard navigation, unminified published output.
24
+
25
+ **0.2.2**: npm README cleanup: release notes stay inline; removed pointers to repo-only markdown files.
26
+
27
+ **0.2.0**: structured validation (`ValidationReason`, `validatePhoneNumber`, `onValidationChange`), `parsePhoneValue`, `getCountryOptions()`, improved `PhoneInput` a11y (click-outside, listbox ARIA) and RTL tests.
28
+
29
+ ## Features
30
+
31
+ - **245 supported calling regions** derived from `libphonenumber-js` metadata, with names and dial codes generated into the package so there is no heavy country-data dependency to install
32
+ - **Headless hook** via `usePhoneInput()` plus an optional **unstyled reference** `PhoneInput` component (class names only, no bundled CSS)
33
+ - **Searchable country selector** with country name, ISO code, and dial-code matching
34
+ - **Accessible country selector** built on the WAI-ARIA combobox pattern, with `aria-activedescendant` navigation and a live region announcing the filtered count
35
+ - **Format as you type** in the selected country's format, on every keystroke, powered by `libphonenumber-js`
36
+ - **Real validation** powered by `libphonenumber-js`
37
+ - **International detection** for pasted or typed `+` / `00` numbers
38
+ - **TypeScript-first** exports for countries, helpers, hook return values, and component refs
39
+
40
+ ## Installation
41
+
42
+ ```bash
43
+ npm install @input-kit/phone
44
+ ```
45
+
46
+ ## Quick Start
47
+
48
+ ### Component
49
+
50
+ ```tsx
51
+ import { PhoneInput } from '@input-kit/phone';
52
+ import './phone-input.css'; // your own stylesheet, the package ships no CSS
53
+
54
+ function Example() {
55
+ return (
56
+ <PhoneInput
57
+ defaultCountry="US"
58
+ onChange={(phone, country) => {
59
+ console.log(phone, country?.code);
60
+ }}
61
+ />
62
+ );
63
+ }
64
+ ```
65
+
66
+ ### Hook
67
+
68
+ ```tsx
69
+ import { usePhoneInput } from '@input-kit/phone';
70
+
71
+ function Example() {
72
+ const {
73
+ inputProps,
74
+ country,
75
+ countryButtonProps,
76
+ filteredCountries,
77
+ selectCountry,
78
+ isOpen,
79
+ isValid,
80
+ } = usePhoneInput({
81
+ defaultCountry: 'US',
82
+ onChange: (phone, nextCountry) => console.log(phone, nextCountry?.dialCode),
83
+ });
84
+
85
+ return (
86
+ <div>
87
+ <button {...countryButtonProps}>
88
+ {country?.flag} {country?.dialCode}
89
+ </button>
90
+
91
+ {isOpen && (
92
+ <div>
93
+ {filteredCountries.map((candidate) => (
94
+ <button key={candidate.code} onClick={() => selectCountry(candidate)}>
95
+ {candidate.flag} {candidate.name} {candidate.dialCode}
96
+ </button>
97
+ ))}
98
+ </div>
99
+ )}
100
+
101
+ <input {...inputProps} />
102
+ {!isValid && <span>Invalid phone number</span>}
103
+ </div>
104
+ );
105
+ }
106
+ ```
107
+
108
+ ## Accessibility
109
+
110
+ The country selector follows the WAI-ARIA APG [combobox with listbox popup](https://www.w3.org/WAI/ARIA/apg/patterns/combobox/) pattern.
111
+
112
+ When the dropdown is searchable, the search field is the combobox: it carries `role="combobox"`, `aria-expanded`, `aria-controls` pointing at the listbox, `aria-autocomplete="list"`, and `aria-activedescendant` pointing at the active option. Focus stays in the search field while the arrow keys move the active option, so you can keep typing to refine the list. `aria-selected` marks the active option, as a single-select listbox should. Opening the list makes the country you already picked active, so a screen reader reads the current value first.
113
+
114
+ Keys: ArrowDown and ArrowUp move the active option, Home and End jump to the ends, Enter selects it, Escape closes the list and returns focus to the trigger button. A polite live region reports how many countries the query matched, or that none did.
115
+
116
+ With `searchable={false}` there is no combobox, so the options keep roving focus and the same keys apply to the list itself.
117
+
118
+ The trigger button is named with the selected country and its dial code, not just the action, because a constant `aria-label` would otherwise hide the flag and dial code from the accessibility tree.
119
+
120
+ Building your own UI on `usePhoneInput()` gets the same wiring: spread `countrySearchProps` on your search field, `dropdownProps` on the list, and `getCountryOptionProps(country, index)` on each option. `countryResultsText` is the localized live-region string. All the announcement strings go through the `labels` option.
121
+
122
+ ## Format as you type
123
+
124
+ `inputProps.value` reformats on every keystroke in the selected country's national format, so the field reads `(555) 123-4567` while the user types. Typing a `+` switches to international format (`+1 555 123 4567`). This is on by default; set `formatOnType: false` for raw digits.
125
+
126
+ The formatting is display only. `onChange`, `phone`, `fullPhone` and `parsePhoneValue` still give you the clean value, so what you store and submit is never the formatted string.
127
+
128
+ ```tsx
129
+ const { inputProps, fullPhone } = usePhoneInput({
130
+ defaultCountry: 'US',
131
+ includeDialCode: true,
132
+ onChange: (phone) => console.log(phone), // +15551234567, not "(555) 123-4567"
133
+ });
134
+
135
+ // user types 5551234567
136
+ // inputProps.value -> "(555) 123-4567"
137
+ // fullPhone -> "+15551234567"
138
+ ```
139
+
140
+ ## Phone values
141
+
142
+ | Field | Meaning |
143
+ | --- | --- |
144
+ | `phone` | National digits stored by the hook (default) |
145
+ | `fullPhone` | National number plus dial code when `includeDialCode` is `true` |
146
+ | `onChange(phone, country)` | Same contract as `phone` / `includeDialCode` |
147
+ | E.164 for APIs | `parsePhoneValue(phone, country).e164` when valid. Prefer this over raw concatenation |
148
+
149
+ ## Known behavior
150
+
151
+ Formatting, length checks, and validity follow **[libphonenumber-js](https://www.npmjs.com/package/libphonenumber-js)** (same family as `react-phone-number-input`). The package does not implement per-country rules outside that library.
152
+
153
+ ## Form integrations
154
+
155
+ Controlled `value` / `onChange` with `usePhoneInput` or `PhoneInput`. React Hook Form: wrap with `Controller` and pass `field.value`, `field.onChange`, and `field.onBlur`. Use `onValidationChange` to sync `isValid` / `message` with form errors. Submit-time checks: `parsePhoneValue(phone, country)` or `validatePhoneNumber`.
156
+
157
+ ## Styled example
158
+
159
+ A minimal Vite demo using only the hook lives in **[examples/react-styled/](./examples/react-styled/)**.
160
+
161
+ ## Migration from 0.1.x
162
+
163
+ Compatibility aliases remain exported. Prefer the newer names in new code:
164
+
165
+ | Deprecated | Replacement |
166
+ | --- | --- |
167
+ | `setValue` | `setPhone` |
168
+ | `value` (hook) | `phone` |
169
+ | `allowedCountries` | `onlyCountries` |
170
+ | `excludedCountries` | `excludeCountries` |
171
+ | `autoDetectCountry` | `autoDetect` |
172
+ | `toggle` / `open` / `close` | `toggleDropdown` / `openDropdown` / `closeDropdown` |
173
+ | `countries` (hook list) | `filteredCountries` |
174
+ | `countrySelectorProps` | `countryButtonProps` |
175
+
176
+ Validation is unified in 0.2.0: `isValid` and `error` come from the same `validatePhoneNumber` call. Use `validationReason` or `onValidationChange` for structured form messages.
177
+
178
+ ## Development
179
+
180
+ Requires [Bun](https://bun.sh) (see `packageManager` in `package.json`).
181
+
182
+ ```bash
183
+ bun install
184
+ bun run test
185
+ bun run typecheck
186
+ bun run build
187
+ bun run lint
188
+ ```
189
+
190
+ Manual browser check: `test-demo/` (static HTML).
191
+
192
+ ## Contributing
193
+
194
+ Bug reports, feature requests, and pull requests are welcome, see [CONTRIBUTING.md](https://github.com/harshit-d3v/input-kit-phone/blob/main/CONTRIBUTING.md). In short: open an issue with a minimal reproduction (include the exact phone number and country for formatting/validation bugs), and for PRs run `bun run test`, `bun run typecheck`, and `bun run lint` before submitting.
195
+
196
+ ## Exports
197
+
198
+ ### Components and hooks
199
+
200
+ - `PhoneInput`
201
+ - `usePhoneInput(options)`
202
+
203
+ ### Country data
204
+
205
+ - `countries`
206
+ - `getCountryByCode(code)`
207
+ - `getCountryByDialCode(dialCode)`
208
+ - `getCountriesByDialCode(dialCode)`
209
+ - `getCountryOptions({ locale?, preferredCountries?, excludeCountries?, onlyCountries? })`
210
+ - `detectCountryFromPhone(phone)`
211
+
212
+ ### Utilities
213
+
214
+ - `cleanPhone`, `formatPhone`, `unformatPhone`, `validatePhone`, `validatePhoneLength`
215
+ - `validatePhoneNumber` `{ isValid, reason, message, error }`
216
+ - `parsePhoneValue` `{ country, nationalNumber, e164, isValid }`
217
+ - `addDialCode`, `removeDialCode`, `filterCountries`, `getPlaceholder`
218
+
219
+ Compatibility aliases: `stripNonDigits`, `detectCountry`, `formatPhoneNumber`, `parseToE164`, `getNationalNumber`, `isPhoneNumberComplete`, `formatAsYouType`, `normalizePhoneNumber`, `phoneNumbersEqual`, `getCountryDisplayLabel`, `limitInputLength`.
220
+
221
+ ## `usePhoneInput(options)`
222
+
223
+ | Option | Type | Default | Description |
224
+ | --- | --- | --- | --- |
225
+ | `defaultCountry` | `string` | `'US'` | Default selected country |
226
+ | `preferredCountries` | `string[]` | - | Countries shown first in search results |
227
+ | `excludeCountries` | `string[]` | - | Countries to exclude |
228
+ | `onlyCountries` | `string[]` | - | Restrict selection to these countries |
229
+ | `autoDetect` | `boolean` | `true` | Detect country from international numbers |
230
+ | `formatOnType` | `boolean` | `true` | Apply live formatting |
231
+ | `includeDialCode` | `boolean` | `false` | Return values with dial code included |
232
+ | `required` | `boolean` | `false` | Empty value is invalid |
233
+ | `validator` | `(phone, country) => boolean` | - | Custom validation override |
234
+ | `onValidationChange` | `(state) => void` | - | Fires when validation result changes |
235
+
236
+ Important returned fields: `phone`, `fullPhone`, `country`, `isValid`, `validationReason`, `error`, `onValidationChange`, `filteredCountries`, `inputProps`, `countryButtonProps`, `dropdownProps`, `getCountryOptionId`.
237
+
238
+ ## License
239
+
240
+ MIT © Input Kit