51 lines
1.5 KiB
TypeScript
51 lines
1.5 KiB
TypeScript
import { forwardRef, useState, useEffect, useCallback } from 'react';
|
|
import { Input } from '@/components/ui/input';
|
|
|
|
function formatPhone(value: string): string {
|
|
const digits = value.replace(/\D/g, '').slice(0, 20);
|
|
return digits.replace(/(\d{4})(?=\d)/g, '$1 ').trim();
|
|
}
|
|
|
|
function unformatPhone(value: string): string {
|
|
return value.replace(/\s/g, '');
|
|
}
|
|
|
|
const PhoneInput = forwardRef<HTMLInputElement, Omit<React.ComponentProps<'input'>, 'value' | 'onChange'> & {
|
|
value?: string;
|
|
onChange?: (value: string) => void;
|
|
}>(({ value, onChange, name, ...props }, ref) => {
|
|
const [displayValue, setDisplayValue] = useState(() => formatPhone(value ?? ''));
|
|
|
|
useEffect(() => {
|
|
setDisplayValue(formatPhone(value ?? ''));
|
|
}, [value]);
|
|
|
|
const handleChange = useCallback(
|
|
(e: React.ChangeEvent<HTMLInputElement>) => {
|
|
const raw = unformatPhone(e.target.value);
|
|
const formatted = formatPhone(raw);
|
|
setDisplayValue(formatted);
|
|
onChange?.(raw);
|
|
},
|
|
[onChange],
|
|
);
|
|
|
|
return (
|
|
<>
|
|
<Input
|
|
ref={ref}
|
|
type="text"
|
|
inputMode="numeric"
|
|
value={displayValue}
|
|
onChange={handleChange}
|
|
{...props}
|
|
/>
|
|
{name && <input type="hidden" name={name} value={unformatPhone(displayValue)} />}
|
|
</>
|
|
);
|
|
});
|
|
|
|
PhoneInput.displayName = 'PhoneInput';
|
|
|
|
export { PhoneInput };
|