v-phone-input
Version:
International phone field for Vuetify 3 and Vue 3.
464 lines (463 loc) • 15 kB
TypeScript
import { ParsedPhoneNumber } from 'awesome-phonenumber';
import { ComputedRef, ExtractPropTypes, MaybeRef, Ref, ShallowRef, VNode, WritableComputedRef } from 'vue';
import { ComponentSlots } from 'vue-component-type-helpers';
import { VAutocomplete, VSelect, VTextField } from 'vuetify/components';
import { default as makePhoneInputComposableProps } from './props/makePhoneInputComposableProps.ts';
import { default as makePhoneInputCountryDisplayProps } from './props/makePhoneInputCountryDisplayProps.ts';
import { default as makePhoneInputCountryProps } from './props/makePhoneInputCountryProps.ts';
import { default as makePhoneInputMessagesProps } from './props/makePhoneInputMessagesProps.ts';
import { default as makePhoneInputProps } from './props/makePhoneInputProps.ts';
/**
* Convert an options interface to a composable options interface.
*
* @internal
*/
export type VPhoneInputExtractComposableOptions<Props extends {}> = {
[K in keyof Props]?: MaybeRef<Props[K]> | undefined;
};
/**
* Country object.
*/
export interface VPhoneInputCountryObject {
/**
* Human-readable name.
*/
readonly name: string;
/**
* Two-letter code.
*
* @see https://en.wikipedia.org/wiki/ISO_3166-1_alpha-2
*/
readonly iso2: string;
/**
* Dial code (without the `+` symbol prefix).
*
* @see https://en.wikipedia.org/wiki/List_of_telephone_country_codes
*/
readonly dialCode: string;
}
/**
* Country object or valid two-letter code.
*
* @internal
*/
export type VPhoneInputCountryObjectOrIso2 = VPhoneInputCountryObject | VPhoneInputCountryObject["iso2"];
/**
* Country guesser function result.
*
* @internal
*/
export type VPhoneInputCountryGuesserResult = VPhoneInputCountryObjectOrIso2 | null | undefined;
/**
* Country guesser function.
*
* @internal
*/
export interface VPhoneInputCountryGuesser {
/**
* Guess a country.
*/
(): Promise<VPhoneInputCountryGuesserResult> | VPhoneInputCountryGuesserResult;
/**
* Previously memoized country two-letter code.
*
* @remarks
* Property should only be available when the country guesser function supports memoization.
* It is set to memoize the currently selected country.
* It is retrieved to avoid running guesser function when a memoized country is available.
*/
memoized?: MaybeRef<string | null | undefined>;
}
/**
* Props to customize country related features.
*
* @internal
*/
export interface VPhoneInputCountryProps<Country extends VPhoneInputCountryObject> extends Readonly<Partial<ExtractPropTypes<ReturnType<typeof makePhoneInputCountryProps<Country>>>>> {
}
/**
* Options for `usePhoneInputCountries` composable.
*
* @internal
*/
export interface VPhoneInputCountryComposableOptions<Country extends VPhoneInputCountryObject> extends VPhoneInputExtractComposableOptions<VPhoneInputCountryProps<Country>> {
}
/**
* `usePhoneInputCountries` composable.
*
* @internal
*/
export interface VPhoneInputCountryComposable<Country extends VPhoneInputCountryObject> {
/**
* List of available countries.
*/
readonly countries: ComputedRef<Country[]>;
/**
* List of available preferred countries.
*/
readonly preferredCountries: ComputedRef<Country[]>;
/**
* List of available unpreferred countries.
*/
readonly unpreferredCountries: ComputedRef<Country[]>;
/**
* Default country to use.
*/
readonly defaultCountry: ComputedRef<Country | null>;
/**
* Fallback country to use.
*/
readonly fallbackCountry: ComputedRef<Country>;
/**
* Find a country object using a country object or two-letter code.
*/
readonly findCountry: ComputedRef<(value: VPhoneInputCountryObjectOrIso2 | null | undefined) => Country | null>;
}
/**
* Message factory context.
*
* @remarks
* Context may vary depending on the message to build.
*
* @internal
*/
export interface VPhoneInputMessageFactoryContext<Country extends VPhoneInputCountryObject, Label extends string | undefined = string, Example extends string | undefined = string> {
/**
* Current country.
*/
readonly country: Country;
/**
* Current country's phone number example.
*/
readonly example: Example;
/**
* Current phone input's label.
*/
readonly label: Label;
}
/**
* Build a message for a given context.
*
* @internal
*/
export type VPhoneInputMessageFactory<Country extends VPhoneInputCountryObject, Label extends string | undefined = string, Example extends string | undefined = string> = (context: VPhoneInputMessageFactoryContext<Country, Label, Example>) => string;
/**
* Message string or factory.
*
* @internal
*/
export type VPhoneInputMessage<Country extends VPhoneInputCountryObject, Label extends string | undefined = string, Example extends string | undefined = string> = string | VPhoneInputMessageFactory<Country, Label, Example>;
/**
* Props to customize localization related features.
*
* @internal
*/
export interface VPhoneInputMessagesProps<Country extends VPhoneInputCountryObject> extends Readonly<Partial<ExtractPropTypes<ReturnType<typeof makePhoneInputMessagesProps<Country>>>>> {
}
/**
* Options for `usePhoneInputMessages` composable.
*
* @internal
*/
export interface VPhoneInputMessagesComposableOptions<Country extends VPhoneInputCountryObject> extends VPhoneInputExtractComposableOptions<VPhoneInputMessagesProps<Country>> {
/**
* Country to resolve messages with.
*/
readonly country: MaybeRef<Country>;
}
/**
* `usePhoneInputMessages` composable.
*
* @internal
*/
export interface VPhoneInputMessagesComposable<Country extends VPhoneInputCountryObject> {
/**
* Formatted example of phone number for current country.
*/
readonly example: ComputedRef<string>;
/**
* Label for phone input.
*/
readonly label: ComputedRef<string | undefined>;
/**
* `aria-label` for phone input.
*/
readonly ariaLabel: ComputedRef<string | undefined>;
/**
* Label for country input.
*/
readonly countryLabel: ComputedRef<string | undefined>;
/**
* `aria-label` for country input.
*/
readonly countryAriaLabel: ComputedRef<string | undefined>;
/**
* Placeholder for phone input.
*/
readonly placeholder: ComputedRef<string | undefined>;
/**
* Invalid message for phone input.
*/
readonly invalidMessage: ComputedRef<string | undefined>;
/**
* Resolve a message using current context.
*/
readonly resolveMessage: ComputedRef<(<Message extends VPhoneInputMessage<Country> | null | undefined>(message: Message) => Message extends null | undefined ? string | undefined : string)>;
}
/**
* Options for `usePhoneInput` composable.
*
* @internal
*/
export interface VPhoneInputComposableOptions<Country extends VPhoneInputCountryObject> extends VPhoneInputExtractComposableOptions<Readonly<Partial<ExtractPropTypes<ReturnType<typeof makePhoneInputComposableProps<Country>>>>>> {
/**
* Phone model value ref, formatted using `modelFormat`.
*/
readonly modelValue: Ref<string | null | undefined>;
/**
* Country model value ref.
*/
readonly country?: Ref<string | null | undefined>;
/**
* Country input component or element ref to bind listeners to.
*/
readonly countryInputRef?: Ref<{
$el: HTMLElement;
} | HTMLElement | null | undefined>;
/**
* Phone input component or element ref to bind listeners to.
*/
readonly phoneInputRef?: Ref<{
$el: HTMLElement;
} | HTMLElement | null | undefined>;
}
/**
* `usePhoneInput` composable.
*
* @internal
*/
export interface VPhoneInputComposable<Country extends VPhoneInputCountryObject> extends VPhoneInputCountryComposable<Country>, VPhoneInputMessagesComposable<Country> {
/**
* Country input component or element ref on which listeners are bound.
*/
countryInputRef: Ref<{
$el: HTMLElement;
} | HTMLElement | null | undefined>;
/**
* Phone input component or element ref on which listeners are bound.
*/
phoneInputRef: Ref<{
$el: HTMLElement;
} | HTMLElement | null | undefined>;
/**
* Phone input value.
*/
phone: Ref<string | null>;
/**
* Country object value (computed from country input value).
*/
countryObject: WritableComputedRef<Country>;
/**
* Phone object value (computed from phone input value).
*/
phoneObject: ComputedRef<ParsedPhoneNumber | null>;
/**
* Phone object valid state (might be null if validation is disabled).
*/
phoneValid: ComputedRef<boolean | null>;
/**
* Tells if a country is currently guessing.
*/
countryGuessing: Readonly<Ref<boolean>>;
/**
* Trigger phone input value formatting.
*/
formatPhoneInputValue: () => void;
}
/**
* Available implementation for country input component (either `VSelect` or `VAutocomplete`).
*
* @internal
*/
export type VPhoneCountryInputComponent = typeof VSelect | typeof VAutocomplete;
/**
* Component properties for country display components.
*
* @internal
*/
export interface VPhoneCountryDisplayProps<Country extends VPhoneInputCountryObject> extends Readonly<ExtractPropTypes<ReturnType<typeof makePhoneInputCountryDisplayProps<Country>>>> {
}
/**
* Component props for `VPhoneInput` (without models properties).
*
* @internal
*/
export interface VPhoneInputNonModelProps<Country extends VPhoneInputCountryObject, CountryInputComponent extends VPhoneCountryInputComponent> extends Readonly<Partial<ExtractPropTypes<ReturnType<typeof makePhoneInputProps<Country, CountryInputComponent>>>>> {
}
/**
* Component props for `VPhoneInput`.
*
* @internal
*/
export interface VPhoneInputProps<Country extends VPhoneInputCountryObject, CountryInputComponent extends VPhoneCountryInputComponent> extends VPhoneInputNonModelProps<Country, CountryInputComponent> {
/**
* Current phone number, formatted using `modelFormat`.
*/
modelValue?: string | null | undefined;
/**
* Currently selected country.
*/
country?: string | null | undefined;
}
/**
* Component events for `VPhoneInput` (without models events).
*
* @internal
*/
export interface VPhoneInputNonModelEmits<Country extends VPhoneInputCountryObject> {
/**
* Country object value has been updated (computed from country input value).
*/
"update:country-object": [value: Country];
/**
* Phone object value has been updated (computed from phone input value).
*/
"update:phone-object": [value: ParsedPhoneNumber | null];
}
/**
* Component events for `VPhoneInput`.
*
* @internal
*/
export interface VPhoneInputEmits<Country extends VPhoneInputCountryObject> extends VPhoneInputNonModelEmits<Country> {
/**
* Current phone number has been updated.
*/
"update:model-value": [string | null | undefined];
/**
* Currently selected country has been updated.
*/
"update:country": [string];
}
/**
* Component slots forwarded to `VSelect` or `VAutocomplete`.
*
* @interface
*
* @internal
*/
export type VPhoneInputForwardedSlots<CountryInputComponent extends VPhoneCountryInputComponent> = {
[K in keyof ComponentSlots<CountryInputComponent> as K extends string ? `country-input:${K}` : never]: ComponentSlots<CountryInputComponent>[K];
} & {
[K in keyof ComponentSlots<typeof VTextField>]: ComponentSlots<typeof VTextField>[K];
};
/**
* Component direct slots for `VPhoneInput`.
*
* @interface
*
* @internal
*/
export interface VPhoneInputCountrySlots<Country extends VPhoneInputCountryObject> {
/**
* Country display.
*
* @remarks
* `decorative` tells if the display should be ignored by screen readers or
* if it must have an accessible name (e.g. through `title` attribute).
*
* @defaultValue
* Country display component from `countryDisplayComponent` property if available,
* `'+<country.dialCode>'` otherwise.
*/
readonly "country-display": ((scope: {
country: Country;
decorative: boolean;
}) => VNode[]) | undefined;
/**
* Country list item title.
*
* @defaultValue
* `'<country.name>'`
*/
readonly "country-name": ((scope: {
country: Country;
}) => VNode[]) | undefined;
/**
* Country list item prepended content.
*
* @defaultValue
* Use the `country-display` slot with a decorative purpose.
*/
readonly "country-prepend": ((scope: {
country: Country;
}) => VNode[]) | undefined;
/**
* Country list item appended content.
*
* @defaultValue
* `'+<country.dialCode>'` if `countryIconMode` property, `country-display` or
* `country-prepend` is defined, nothing otherwise.
*/
readonly "country-append": ((scope: {
country: Country;
}) => VNode[]) | undefined;
}
/**
* Component slots for `VPhoneInput`.
*
* @interface
*
* @internal
*/
export type VPhoneInputSlots<Country extends VPhoneInputCountryObject, CountryComponent extends VPhoneCountryInputComponent> = Readonly<Partial<VPhoneInputCountrySlots<Country> & VPhoneInputForwardedSlots<CountryComponent>>>;
/**
* Component exposed values for `VPhoneInput`.
*
* @internal
*/
export interface VPhoneInputExposed<Country extends VPhoneInputCountryObject, CountryComponent extends VPhoneCountryInputComponent> {
/**
* Ref to the country input component.
*/
readonly countryInputRef: ShallowRef<CountryComponent | undefined>;
/**
* Ref to the phone input component.
*/
readonly phoneInputRef: ShallowRef<VTextField | undefined>;
/**
* Current phone object value.
*/
readonly countryObject: ComputedRef<Country>;
/**
* Current phone object value.
*/
readonly phoneObject: ComputedRef<ParsedPhoneNumber | null>;
/**
* Forwarded phone input's `VTextField.isValid` exposed value.
*/
readonly isValid: ComputedRef<boolean | null>;
/**
* Forwarded phone input's `VTextField.errorMessages` exposed value.
*/
readonly errorMessages: ComputedRef<string[]>;
/**
* Forwarded phone input's `VTextField.reset` exposed function.
*/
readonly reset: () => Promise<void>;
/**
* Forwarded phone input's `VTextField.resetValidation` exposed function.
*/
readonly resetValidation: () => Promise<void>;
/**
* Forwarded phone input's `VTextField.validate` exposed function.
*/
readonly validate: (silent?: boolean) => Promise<string[]>;
}
/**
* Injectable options for `VPhoneInput` and `usePhoneInput`.
*
* @internal
*/
export interface VPhoneInputPluginOptions<Country extends VPhoneInputCountryObject, CountryInputComponent extends VPhoneCountryInputComponent> extends VPhoneInputNonModelProps<Country, CountryInputComponent> {
}