import { type Accessor } from "solid-js"; import { type MaybeAccessor } from "../maybe-accessor.js"; /** * What a validator function may return. A returned string (or array of * strings) is a validation **message** — surfaced to the consumer through * `validity().errors`. Distinct from a validator that throws or rejects: a * thrown error is treated as a programmer/system fault and propagates to * ``. */ export type ValidationResult = string | readonly string[] | undefined | null; export type ValidatorChangeReason = "imperative" | "input" | "submit"; export interface ValidatorValidity { /** `undefined` until the first validation has settled. */ valid: boolean | undefined; /** Empty when valid or pre-validation. */ errors: readonly string[]; /** Convenience: `errors[0] ?? ""`. */ message: string; } export interface CreateValidatorOptions { /** * Reactive value being validated. Tracking the accessor in the * primitive's compute lets validation re-run when it flips. */ value: MaybeAccessor; /** * Pure validator. Returns a message string (or list) when invalid, * `undefined`/`null` when valid. May return a Promise of the same. * * **Throwing or rejecting is reserved for true errors** (network * failure, programmer bug). The primitive does NOT catch — exceptions * surface to the nearest `` boundary in the consumer tree. */ validate?: (value: V) => ValidationResult | Promise; /** * Recoverable side-effect that runs whenever a settled value lands. * Wired through a separate `createEffect({ effect, error })` bundle — * if it throws, the primitive logs and resets local bookkeeping * **without** propagating to ``. Use for autosave, telemetry, * cross-field reactions: things the consumer should not have to wrap a * boundary around. */ onValueSettled?: (value: V) => undefined | (() => void); /** * Pre-change cancellation hook. Called with the next validity snapshot, * the triggering event, and a structured `reason`. The consumer can * call `event.preventDefault()` to suppress the validity write. */ onValidityChange?: (next: ValidatorValidity, event: Event, reason: ValidatorChangeReason) => void; } export interface ValidatorApi { value: Accessor; /** * Latest committed validity. Reading inside an `` boundary * surfaces validator exceptions; reading inside a `` boundary * suspends while async validation is pending. * * **No `error` accessor accompanies this** — by design (RFC 05). * Returned message strings are not errors; they are typed feedback. */ validity: Accessor; /** * Imperatively trigger validation. Awaiting the returned promise * observes async-validator rejections at the call site; reading * `validity()` afterwards re-throws them into the graph for ``. * Pass an `event` to participate in pre-change cancellation. */ validate: (event?: Event, reason?: ValidatorChangeReason) => Promise; } export declare function createValidator(options: CreateValidatorOptions): ValidatorApi; //# sourceMappingURL=create-validator.d.ts.map