@xsolla/xui-input-phone 0.150.0 → 0.152.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.
Files changed (2) hide show
  1. package/README.md +155 -169
  2. package/package.json +3 -3
package/README.md CHANGED
@@ -1,212 +1,198 @@
1
- # Input Phone
1
+ # InputPhone
2
2
 
3
- A cross-platform React phone number input component with integrated country selector. Features a searchable country dropdown with flags and dial codes.
3
+ A cross-platform phone-number input with an integrated, searchable country selector (flags and dial codes); ships with a `usePhoneNumber` hook for formatting and country detection.
4
4
 
5
5
  ## Installation
6
6
 
7
7
  ```bash
8
8
  npm install @xsolla/xui-input-phone
9
- # or
10
- yarn add @xsolla/xui-input-phone
11
9
  ```
12
10
 
13
- ## Demo
14
-
15
- ### Basic Phone Input
11
+ ## Imports
16
12
 
17
13
  ```tsx
18
- import * as React from 'react';
19
- import { InputPhone } from '@xsolla/xui-input-phone';
20
-
21
- export default function BasicPhoneInput() {
22
- const [phone, setPhone] = React.useState('');
23
-
24
- return (
25
- <InputPhone
26
- value={phone}
27
- onChange={(e) => setPhone(e.target.value)}
28
- placeholder="+1 (000) 000-0000"
29
- />
30
- );
31
- }
14
+ import {
15
+ InputPhone,
16
+ usePhoneNumber,
17
+ allCountries,
18
+ defaultCountries,
19
+ getCountryByCode,
20
+ getCountryByDialCode,
21
+ getFlag,
22
+ } from '@xsolla/xui-input-phone';
23
+ import type {
24
+ InputPhoneProps,
25
+ Country,
26
+ UsePhoneNumberOptions,
27
+ UsePhoneNumberReturn,
28
+ } from '@xsolla/xui-input-phone';
32
29
  ```
33
30
 
34
- ### With Country Selection
31
+ ## Quick start
35
32
 
36
33
  ```tsx
37
- import * as React from 'react';
38
- import { InputPhone, Country } from '@xsolla/xui-input-phone';
39
-
40
- export default function CountryPhoneInput() {
41
- const [phone, setPhone] = React.useState('');
42
- const [country, setCountry] = React.useState<Country | undefined>();
43
-
44
- return (
45
- <InputPhone
46
- value={phone}
47
- onChange={(e) => setPhone(e.target.value)}
48
- selectedCountry={country}
49
- onCountryChange={setCountry}
50
- />
51
- );
52
- }
34
+ const [phone, setPhone] = useState('');
35
+
36
+ <InputPhone
37
+ value={phone}
38
+ onChangeText={setPhone}
39
+ placeholder="+1 (000) 000-0000"
40
+ />;
53
41
  ```
54
42
 
55
- ### With Validation
43
+ ## API Reference
56
44
 
57
- ```tsx
58
- import * as React from 'react';
59
- import { InputPhone } from '@xsolla/xui-input-phone';
60
-
61
- export default function ValidatedPhoneInput() {
62
- const [phone, setPhone] = React.useState('');
63
- const isValid = phone.length >= 10;
64
-
65
- return (
66
- <InputPhone
67
- value={phone}
68
- onChange={(e) => setPhone(e.target.value)}
69
- checked={isValid}
70
- extraClear={true}
71
- onRemove={() => setPhone('')}
72
- />
73
- );
74
- }
75
- ```
45
+ ### `<InputPhone>`
76
46
 
77
- ## Anatomy
47
+ | Prop | Type | Default | Description |
48
+ | --- | --- | --- | --- |
49
+ | `value` | `string` | — | Controlled value. |
50
+ | `placeholder` | `string` | — | Placeholder shown when empty. |
51
+ | `onChange` | `(e: ChangeEvent<HTMLInputElement>) => void` | — | Native change handler. |
52
+ | `onChangeText` | `(text: string) => void` | — | Simplified change handler. |
53
+ | `size` | `'xs' \| 'sm' \| 'md' \| 'lg' \| 'xl'` | `'md'` | Control size. |
54
+ | `name` | `string` | — | Form field name. |
55
+ | `disabled` | `boolean` | `false` | Disable the control. |
56
+ | `error` | `boolean` | `false` | Apply error styling. |
57
+ | `errorMessage` | `string` | — | Error message; also marks the control invalid. |
58
+ | `countries` | `Country[]` | `allCountries` | Countries available in the dropdown. |
59
+ | `selectedCountry` | `Country` | — | Currently selected country. |
60
+ | `onCountryChange` | `(country: Country) => void` | — | Fired when the country changes. |
61
+ | `extraClear` | `boolean` | `false` | Show a clear button when the input has a value. |
62
+ | `onRemove` | `() => void` | — | Fired when the clear button is pressed. |
63
+ | `checked` | `boolean` | `false` | Show a success indicator (suppressed when `errorMessage` is set). |
64
+ | `checkedIcon` | `ReactNode` | `<CheckCr />` | Override the checked icon. |
65
+ | `id` | `string` | `auto` | HTML id. |
66
+ | `aria-label` | `string` | — | Accessible label when no visible label is present. |
67
+ | `testID` | `string` | — | Test identifier. |
78
68
 
79
- ```jsx
80
- import { InputPhone } from '@xsolla/xui-input-phone';
69
+ `InputPhone` also accepts the standard `InputHTMLAttributes` (excluding `size` and `onChange`).
81
70
 
82
- <InputPhone
83
- value={phoneNumber} // Phone number value
84
- onChange={handleChange} // Change event handler
85
- selectedCountry={country} // Currently selected country
86
- onCountryChange={setCountry} // Country selection handler
87
- countries={customCountries} // Custom countries array
88
- placeholder="+1 (000) 000-0000" // Placeholder text
89
- size="md" // Size variant
90
- disabled={false} // Disabled state
91
- error={false} // Error state
92
- errorMessage="Error" // Error message
93
- extraClear={false} // Show clear button
94
- onRemove={handleClear} // Clear button handler
95
- checked={false} // Show validation checkmark
96
- />
97
- ```
71
+ Inherits `ThemeOverrideProps` (`themeMode`, `themeProductContext`).
98
72
 
99
- ## Examples
73
+ ### Hooks
100
74
 
101
- ### Error State
75
+ #### `usePhoneNumber(options?)`
102
76
 
103
- ```tsx
104
- import * as React from 'react';
105
- import { InputPhone } from '@xsolla/xui-input-phone';
106
-
107
- export default function ErrorPhoneInput() {
108
- return (
109
- <InputPhone
110
- value="123"
111
- error={true}
112
- errorMessage="Please enter a valid phone number"
113
- />
114
- );
77
+ Manages a phone-number value with normalisation, formatting (via `libphonenumber-js`) and automatic country detection.
78
+
79
+ | Option | Type | Description |
80
+ | --- | --- | --- |
81
+ | `initialCountry` | `string` | ISO 3166-1 alpha-2 code (e.g. `'US'`). |
82
+ | `initialValue` | `string` | Initial phone-number value. |
83
+ | `onChange` | `(phoneNumber: string) => void` | Fired when the phone number changes. |
84
+ | `onCountryChange` | `(country: Country \| undefined) => void` | Fired when the country changes. |
85
+
86
+ Returns:
87
+
88
+ | Field | Type | Description |
89
+ | --- | --- | --- |
90
+ | `phoneNumber` | `string` | Raw phone number (with country code). |
91
+ | `formattedPhoneNumber` | `string` | Display-formatted phone number. |
92
+ | `country` | `Country \| undefined` | Detected/selected country. |
93
+ | `countries` | `Country[]` | All available countries (`allCountries`). |
94
+ | `handlePhoneChange` | `(value: string) => void` | Handle phone input change. |
95
+ | `handleCountryChange` | `(country: Country) => void` | Handle country selection. |
96
+ | `setPhoneNumber` | `(value: string) => void` | Set the phone number programmatically. |
97
+
98
+ ### `allCountries`
99
+
100
+ `Country[]` — full list of supported countries.
101
+
102
+ ### `defaultCountries`
103
+
104
+ `Country[]` — curated default subset.
105
+
106
+ ### `getCountryByCode`
107
+
108
+ `(code: string) => Country | undefined` — look up by ISO alpha-2 code.
109
+
110
+ ### `getCountryByDialCode`
111
+
112
+ `(dialCode: string) => Country | undefined` — look up by dial code (e.g. `'+44'`).
113
+
114
+ ### `getFlag`
115
+
116
+ `(code: string) => ReactNode` — get the flag icon for a country code.
117
+
118
+ ### Types
119
+
120
+ ```ts
121
+ interface Country {
122
+ code: string; // ISO 3166-1 alpha-2 (e.g. "US")
123
+ name: string;
124
+ dialCode: string; // e.g. "+1"
125
+ flag?: ReactNode;
115
126
  }
116
127
  ```
117
128
 
118
- ### Phone Input Sizes
129
+ ## Examples
130
+
131
+ ### With country selection
119
132
 
120
133
  ```tsx
121
- import * as React from 'react';
122
- import { InputPhone } from '@xsolla/xui-input-phone';
123
-
124
- export default function PhoneInputSizes() {
125
- return (
126
- <div style={{ display: 'flex', flexDirection: 'column', gap: 16 }}>
127
- <InputPhone size="xs" placeholder="Extra Small" />
128
- <InputPhone size="sm" placeholder="Small" />
129
- <InputPhone size="md" placeholder="Medium" />
130
- <InputPhone size="lg" placeholder="Large" />
131
- <InputPhone size="xl" placeholder="Extra Large" />
132
- </div>
133
- );
134
- }
134
+ const [phone, setPhone] = useState('');
135
+ const [country, setCountry] = useState<Country | undefined>();
136
+
137
+ <InputPhone
138
+ value={phone}
139
+ onChangeText={setPhone}
140
+ selectedCountry={country}
141
+ onCountryChange={setCountry}
142
+ />;
135
143
  ```
136
144
 
137
- ### Custom Countries
145
+ ### Using `usePhoneNumber`
146
+
147
+ Reach for the hook when you want normalisation, formatting (via `libphonenumber-js`) and automatic country detection bundled together; reach for the imperative `selectedCountry`/`onCountryChange` API when you already manage the value and only need a controlled country selector.
138
148
 
139
149
  ```tsx
140
- import * as React from 'react';
141
- import { InputPhone, Country } from '@xsolla/xui-input-phone';
142
-
143
- export default function CustomCountriesPhone() {
144
- const [phone, setPhone] = React.useState('');
145
-
146
- const countries: Country[] = [
147
- { code: 'US', name: 'United States', dialCode: '+1' },
148
- { code: 'GB', name: 'United Kingdom', dialCode: '+44' },
149
- { code: 'DE', name: 'Germany', dialCode: '+49' },
150
- ];
151
-
152
- return (
153
- <InputPhone
154
- value={phone}
155
- onChange={(e) => setPhone(e.target.value)}
156
- countries={countries}
157
- />
158
- );
159
- }
150
+ const { phoneNumber, country, handlePhoneChange, handleCountryChange } =
151
+ usePhoneNumber({ initialCountry: 'MY' });
152
+
153
+ <InputPhone
154
+ value={phoneNumber}
155
+ onChangeText={handlePhoneChange}
156
+ selectedCountry={country}
157
+ onCountryChange={handleCountryChange}
158
+ />;
160
159
  ```
161
160
 
162
- ## API Reference
161
+ ### Custom countries
163
162
 
164
- ### InputPhone
163
+ ```tsx
164
+ const countries: Country[] = [
165
+ { code: 'US', name: 'United States', dialCode: '+1' },
166
+ { code: 'GB', name: 'United Kingdom', dialCode: '+44' },
167
+ { code: 'DE', name: 'Germany', dialCode: '+49' },
168
+ ];
165
169
 
166
- **InputPhone Props:**
170
+ <InputPhone countries={countries} />;
171
+ ```
167
172
 
168
- | Prop | Type | Default | Description |
169
- | :--- | :--- | :------ | :---------- |
170
- | value | `string` | - | Phone number value. |
171
- | onChange | `(e: ChangeEvent) => void` | - | Change event handler. |
172
- | onChangeText | `(text: string) => void` | - | Text change handler. |
173
- | countries | `Country[]` | All countries | Available countries for selection. |
174
- | selectedCountry | `Country` | - | Currently selected country. |
175
- | onCountryChange | `(country: Country) => void` | - | Country selection handler. |
176
- | placeholder | `string` | `"+1 (000) 000-0000"` | Placeholder text. |
177
- | size | `"xl" \| "lg" \| "md" \| "sm" \| "xs"` | `"md"` | Component size. |
178
- | disabled | `boolean` | `false` | Disabled state. |
179
- | error | `boolean` | `false` | Error state. |
180
- | errorMessage | `string` | - | Error message text. |
181
- | extraClear | `boolean` | `false` | Show clear button. |
182
- | onRemove | `() => void` | - | Clear button handler. |
183
- | checked | `boolean` | `false` | Show validation checkmark. |
184
- | checkedIcon | `ReactNode` | Check icon | Custom checkmark icon. |
185
- | testID | `string` | - | Test identifier. |
186
-
187
- **Country Interface:**
188
-
189
- ```typescript
190
- interface Country {
191
- code: string; // ISO 3166-1 alpha-2 (e.g., "US")
192
- name: string; // Country name
193
- dialCode: string; // International dial code (e.g., "+1")
194
- flag?: ReactNode; // Optional flag icon
195
- }
173
+ ### Sizes
174
+
175
+ ```tsx
176
+ <InputPhone size="xs" placeholder="Extra small" />
177
+ <InputPhone size="sm" placeholder="Small" />
178
+ <InputPhone size="md" placeholder="Medium" />
179
+ <InputPhone size="lg" placeholder="Large" />
180
+ <InputPhone size="xl" placeholder="Extra large" />
196
181
  ```
197
182
 
198
- ## Keyboard Navigation
183
+ ### Error state
199
184
 
200
- | Key | Action |
201
- | :-- | :----- |
202
- | Arrow Down | Open dropdown / Next country |
203
- | Arrow Up | Previous country |
204
- | Enter | Select country / Open dropdown |
205
- | Escape | Close dropdown |
185
+ ```tsx
186
+ <InputPhone
187
+ value="123"
188
+ error
189
+ errorMessage="Please enter a valid phone number"
190
+ />
191
+ ```
206
192
 
207
193
  ## Accessibility
208
194
 
209
- - Country selector uses `role="combobox"`
210
- - Country list uses `role="listbox"` with `role="option"` items
211
- - Searchable dropdown with `aria-controls` linking
212
- - Phone input uses `type="tel"` and `inputMode="tel"`
195
+ - The country selector uses `role="combobox"`; the list uses `role="listbox"` with `role="option"` items, linked via `aria-controls`.
196
+ - The phone field uses `type="tel"` and `inputMode="tel"`.
197
+ - Keyboard: ArrowDown opens / advances; ArrowUp moves up; Enter selects; Escape closes the dropdown.
198
+ - `errorMessage` is linked via `aria-describedby` and marks the input invalid.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@xsolla/xui-input-phone",
3
- "version": "0.150.0",
3
+ "version": "0.152.0",
4
4
  "main": "./web/index.js",
5
5
  "module": "./web/index.mjs",
6
6
  "types": "./web/index.d.ts",
@@ -13,8 +13,8 @@
13
13
  "test:coverage": "vitest run --coverage"
14
14
  },
15
15
  "dependencies": {
16
- "@xsolla/xui-core": "0.150.0",
17
- "@xsolla/xui-primitives-core": "0.150.0",
16
+ "@xsolla/xui-core": "0.152.0",
17
+ "@xsolla/xui-primitives-core": "0.152.0",
18
18
  "libphonenumber-js": "^1.10.56"
19
19
  },
20
20
  "peerDependencies": {