# InputPhone

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.

## Installation

```bash
npm install @xsolla/xui-input-phone
```

## Imports

```tsx
import {
  InputPhone,
  usePhoneNumber,
  allCountries,
  defaultCountries,
  getCountryByCode,
  getCountryByDialCode,
  getFlag,
} from '@xsolla/xui-input-phone';
import type {
  InputPhoneProps,
  Country,
  UsePhoneNumberOptions,
  UsePhoneNumberReturn,
} from '@xsolla/xui-input-phone';
```

## Quick start

```tsx
const [phone, setPhone] = useState('');

<InputPhone
  value={phone}
  onChangeText={setPhone}
  placeholder="+1 (000) 000-0000"
/>;
```

## API Reference

### `<InputPhone>`

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| `value` | `string` | — | Controlled value. |
| `placeholder` | `string` | — | Placeholder shown when empty. |
| `onChange` | `(e: ChangeEvent<HTMLInputElement>) => void` | — | Native change handler. |
| `onChangeText` | `(text: string) => void` | — | Simplified change handler. |
| `size` | `'xs' \| 'sm' \| 'md' \| 'lg' \| 'xl'` | `'md'` | Control size. |
| `name` | `string` | — | Form field name. |
| `disabled` | `boolean` | `false` | Disable the control. |
| `error` | `boolean` | `false` | Apply error styling. |
| `errorMessage` | `string` | — | Error message; also marks the control invalid. |
| `countries` | `Country[]` | `allCountries` | Countries available in the dropdown. |
| `selectedCountry` | `Country` | — | Currently selected country. |
| `onCountryChange` | `(country: Country) => void` | — | Fired when the country changes. |
| `extraClear` | `boolean` | `false` | Show a clear button when the input has a value. |
| `onRemove` | `() => void` | — | Fired when the clear button is pressed. |
| `checked` | `boolean` | `false` | Show a success indicator (suppressed when `errorMessage` is set). |
| `checkedIcon` | `ReactNode` | `<CheckCr />` | Override the checked icon. |
| `id` | `string` | `auto` | HTML id. |
| `aria-label` | `string` | — | Accessible label when no visible label is present. |
| `testID` | `string` | — | Test identifier. |

`InputPhone` also accepts the standard `InputHTMLAttributes` (excluding `size` and `onChange`).

Inherits `ThemeOverrideProps` (`themeMode`, `themeProductContext`).

### Hooks

#### `usePhoneNumber(options?)`

Manages a phone-number value with normalisation, formatting (via `libphonenumber-js`) and automatic country detection.

| Option | Type | Description |
| --- | --- | --- |
| `initialCountry` | `string` | ISO 3166-1 alpha-2 code (e.g. `'US'`). |
| `initialValue` | `string` | Initial phone-number value. |
| `onChange` | `(phoneNumber: string) => void` | Fired when the phone number changes. |
| `onCountryChange` | `(country: Country \| undefined) => void` | Fired when the country changes. |

Returns:

| Field | Type | Description |
| --- | --- | --- |
| `phoneNumber` | `string` | Raw phone number (with country code). |
| `formattedPhoneNumber` | `string` | Display-formatted phone number. |
| `country` | `Country \| undefined` | Detected/selected country. |
| `countries` | `Country[]` | All available countries (`allCountries`). |
| `handlePhoneChange` | `(value: string) => void` | Handle phone input change. |
| `handleCountryChange` | `(country: Country) => void` | Handle country selection. |
| `setPhoneNumber` | `(value: string) => void` | Set the phone number programmatically. |

### `allCountries`

`Country[]` — full list of supported countries.

### `defaultCountries`

`Country[]` — curated default subset.

### `getCountryByCode`

`(code: string) => Country | undefined` — look up by ISO alpha-2 code.

### `getCountryByDialCode`

`(dialCode: string) => Country | undefined` — look up by dial code (e.g. `'+44'`).

### `getFlag`

`(code: string) => ReactNode` — get the flag icon for a country code.

### Types

```ts
interface Country {
  code: string;       // ISO 3166-1 alpha-2 (e.g. "US")
  name: string;
  dialCode: string;   // e.g. "+1"
  flag?: ReactNode;
}
```

## Examples

### With country selection

```tsx
const [phone, setPhone] = useState('');
const [country, setCountry] = useState<Country | undefined>();

<InputPhone
  value={phone}
  onChangeText={setPhone}
  selectedCountry={country}
  onCountryChange={setCountry}
/>;
```

### Using `usePhoneNumber`

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.

```tsx
const { phoneNumber, country, handlePhoneChange, handleCountryChange } =
  usePhoneNumber({ initialCountry: 'MY' });

<InputPhone
  value={phoneNumber}
  onChangeText={handlePhoneChange}
  selectedCountry={country}
  onCountryChange={handleCountryChange}
/>;
```

### Custom countries

```tsx
const countries: Country[] = [
  { code: 'US', name: 'United States', dialCode: '+1' },
  { code: 'GB', name: 'United Kingdom', dialCode: '+44' },
  { code: 'DE', name: 'Germany', dialCode: '+49' },
];

<InputPhone countries={countries} />;
```

### Sizes

```tsx
<InputPhone size="xs" placeholder="Extra small" />
<InputPhone size="sm" placeholder="Small" />
<InputPhone size="md" placeholder="Medium" />
<InputPhone size="lg" placeholder="Large" />
<InputPhone size="xl" placeholder="Extra large" />
```

### Error state

```tsx
<InputPhone
  value="123"
  error
  errorMessage="Please enter a valid phone number"
/>
```

## Accessibility

- The country selector uses `role="combobox"`; the list uses `role="listbox"` with `role="option"` items, linked via `aria-controls`.
- The phone field uses `type="tel"` and `inputMode="tel"`.
- Keyboard: ArrowDown opens / advances; ArrowUp moves up; Enter selects; Escape closes the dropdown.
- `errorMessage` is linked via `aria-describedby` and marks the input invalid.
