import * as React from 'react'; import { TextControl, tailwind } from '@tesseract-design/web-base'; import { useClientSide, useFallbackId, useProxyInput } from '@modal-sh/react-utils'; import PhoneInput, { Country, Value } from 'react-phone-number-input/input'; const { tw } = tailwind; const PhoneNumberInputDerivedElementComponent = 'input' as const; /** * Derived HTML element of the {@link PhoneNumberInput} component. */ export type PhoneNumberInputDerivedElement = HTMLElementTagNameMap[ typeof PhoneNumberInputDerivedElementComponent ]; /** * Props of the {@link PhoneNumberInput} component. */ export interface PhoneNumberInputProps extends Omit, 'autoComplete' | 'size' | 'type' | 'label' | 'inputMode'> { /** * Short textual description indicating the nature of the component's value. */ label?: React.ReactNode, /** * Short textual description as guidelines for valid input values. */ hint?: React.ReactNode, /** * Size of the component. */ size?: TextControl.Size, /** * Should the component display a border? */ border?: boolean, /** * Should the component occupy the whole width of its parent? */ block?: boolean, /** * Style of the component. */ variant?: TextControl.Variant, /** * Is the label hidden? */ hiddenLabel?: boolean, /** * Should the component be enhanced? */ enhanced?: boolean, /** * Country where the phone number should be formatted for. */ country: Country, /** * Visual length of the input. */ length?: number, } /** * Component for inputting national and international phone numbers. */ export const PhoneNumberInput = React.forwardRef< PhoneNumberInputDerivedElement, PhoneNumberInputProps >(( { label, hint, size = 'medium' as const, border = false as const, block = false as const, variant = 'default' as const, hiddenLabel = false as const, className, id: idProp, style, enhanced = false as const, country, value, onChange, name, length, defaultValue, ...etcProps }: PhoneNumberInputProps, forwardedRef, ) => { const { clientSide } = useClientSide({ clientSide: enhanced }); const [phoneNumber, setPhoneNumber] = React.useState( value?.toString() ?? defaultValue?.toString() ?? '', ); const labelId = React.useId(); const id = useFallbackId(idProp); const { defaultRef, handleChange: handlePhoneInputChange, } = useProxyInput({ forwardedRef, valueSetterFn: (v) => { setPhoneNumber(v); }, transformChangeHandlerArgs: (v) => (v ?? '') as unknown as Value, }); const commonInputStyles = tw( 'bg-negative rounded-inherit w-full peer block font-inherit tabular-nums', 'focus:outline-0', 'disabled:cursor-not-allowed', { 'pl-4': variant === 'default', 'pl-1.5 pt-4': variant === 'alternate', }, { 'pr-10 h-10 text-xxs': size === 'small', 'pr-12 h-12 text-xs': size === 'medium', 'pr-16 h-16': size === 'large', }, ); return (
{label && ( <> {' '} )} {clientSide && ( )} {hint && (
{hint}
)}
{border && ( )}
); }); PhoneNumberInput.displayName = 'PhoneNumberInput'; PhoneNumberInput.defaultProps = { label: undefined, hint: undefined, size: 'medium' as const, border: false as const, block: false as const, variant: 'default' as const, hiddenLabel: false as const, enhanced: false as const, length: undefined, };