teqo/src/components/FormInput.tsx
Francisco Ignácio Fontoura Solla aff72f26af Improve FormInput
2026-03-20 17:54:22 -03:00

75 lines
1.9 KiB
TypeScript

'use client'
import type {
CompositionEventHandler,
FocusEventHandler,
InputEventHandler,
ComponentProps,
} from 'react'
import { Input } from './ui/input'
import { type FieldPath, type FieldValues, useFormContext } from 'react-hook-form'
interface FormInpuProps<
TFieldValues extends FieldValues,
TFieldName extends FieldPath<TFieldValues>,
> extends ComponentProps<'input'> {
name: TFieldName
format?: (value: string) => string
sanitize?: (value: string) => string
}
export const FormInput = <
TFieldValues extends FieldValues,
TFieldName extends FieldPath<TFieldValues>,
>({
name,
format,
sanitize,
...props
}: FormInpuProps<TFieldValues, TFieldName>) => {
const { onChange, onBlur, ...registerResult } = useFormContext<TFieldValues>().register(
name,
sanitize ? { setValueAs: sanitize } : undefined,
)
const handleUpdate = (e: EventTarget & HTMLInputElement, value: string) => {
const selectiondistance = e.value.length - (e.selectionEnd ?? 0)
e.value = value
const caretPos = value.length - selectiondistance
e.setSelectionRange(caretPos, caretPos)
}
const handleInput: InputEventHandler<HTMLInputElement> = (e) => {
if (e.nativeEvent.isComposing) {
return
}
if (format) {
handleUpdate(e.currentTarget, format(e.currentTarget.value))
}
onChange(e)
}
const handleCompositionEnd: CompositionEventHandler<HTMLInputElement> | undefined = format
? (e) => handleUpdate(e.currentTarget, format(e.currentTarget.value))
: undefined
const handleBlur: FocusEventHandler<HTMLInputElement> = (e) => {
handleUpdate(
e.currentTarget,
format?.(sanitize?.(e.currentTarget.value) ?? e.currentTarget.value) ?? e.currentTarget.value,
)
onBlur(e)
}
return (
<Input
{...props}
{...registerResult}
onInput={handleInput}
onCompositionEnd={handleCompositionEnd}
onBlur={handleBlur}
/>
)
}