import { type Readable, type Signal } from '@vielzeug/ripple'; import { type CounterState, type FieldHandle, type FieldOptions } from './field-base'; /** Detach function returned by `wire()`. Call to remove element listeners. */ export type TextFieldDetach = () => void; export type TextFieldOptions = FieldOptions & { maxLength?: Readable; /** * Called synchronously before value extraction on every input event. * Use only for DOM side-effects (e.g. auto-resize measurement) that must * run before the reactive value is updated. */ onBeforeInput?: (event: Event) => void; onBlur?: (event: FocusEvent) => void; onChange?: (event: Event, value: string) => void; onFocus?: (event: FocusEvent) => void; onInput?: (event: Event, value: string) => void; /** * Bars the field from constraint validation while true — matches the native HTML rule that a * `readonly` field is never a candidate for constraint validation (a `readonly required` * field is always valid, per spec), so `validity`/`validationMessage` don't feed a false * `valueMissing` into `useField()` just because a read-only field happens to be blank. */ readonly?: Readable; /** Marks a blank value invalid — feeds `validity`/`validationMessage` (see below). */ required?: Readable; /** Message for the blank+required case. Defaults to `'This field is required.'`. */ requiredMessage?: Readable; /** `AbortSignal` from the component lifecycle. The internal value-sync watcher is disposed on abort. */ signal: AbortSignal; value: Readable; }; export type TextFieldHandle = FieldHandle & { /** * Registers the real form field handle (the return value of `useField()`) so that * `triggerValidation()` — called internally on blur/change — can call its * `reportValidity()`. `useField()` itself needs `value` (below) to exist first, so this * is a two-step wiring rather than a constructor option: * * ```ts * const tf = createTextField({ value: props.value, ... }); * const formField = useField({ value: tf.value, ... }); * tf.attachFormField(formField); * ``` */ attachFormField: (formField: { reportValidity(): void; }) => void; /** Clears the field value and fires synthetic input/change events. */ clear: (event?: Event) => void; /** * Reactive counter state. Non-null when `maxLength` was provided; `null` otherwise. * Components should only render a counter element when this is non-null. */ counter: Readable | null; /** * Restores the value to whatever the `value` option currently holds (native form * `reset()` semantics: a `` reverts to its *current* `value` content attribute, * not a frozen snapshot from element creation — so setting the attribute programmatically * after mount changes what a later reset reverts to). Wire into `useField({ onReset: tf.reset })`. */ reset: () => void; /** Reactive validation message paired with `validity`. Empty string when valid. */ validationMessage: Readable; /** * Reactive `ValidityStateFlags` — `{ valueMissing: true }` while `required` and blank, * `null` (valid) otherwise. Pass straight to `useField({ validity: tf.validity })`. */ validity: Readable; /** The local mutable field value (two-way bound to the input element via `wire()`). */ value: Signal; /** * Attaches event listeners to the underlying input or textarea element. * * When `signal` is provided, the listeners are detached automatically when * the signal's controller calls `abort()`. Without a signal the returned * `TextFieldDetach` must be called manually. * * Safe to call multiple times — each call attaches a fresh set of listeners * and returns a distinct detach function. Calling detach multiple times is * a no-op (guarded internally). */ wire: (el: HTMLInputElement | HTMLTextAreaElement, signal?: AbortSignal) => TextFieldDetach; }; export declare const createTextField: (options: TextFieldOptions) => TextFieldHandle; //# sourceMappingURL=text-field.d.ts.map