import { InferFormValues, StandardSchemaV1 } from "./standard-schema/types.mjs"; import { EventSubscription } from "@mongez/events"; import React, { ReactNode } from "react"; //#region ../react-form/src/types.d.ts /** * Active forms list */ type ActiveForms = { [key: string]: FormInterface; }; /** * Resolve the shape of the values handed to `onSubmit` from the form's schema. * Falls back to a loose record when no schema is provided. * * The `[Schema] extends [undefined]` guard runs FIRST and is deliberate: under * a consumer's non-strict `tsconfig` (`strictNullChecks: false`), `undefined * extends StandardSchemaV1` is `true`, which would wrongly collapse the * schema-less case to `unknown`. Checking `[Schema] extends [undefined]` * up front catches the default generic correctly in both strict and non-strict * modes (a real schema object is never assignable to `undefined`). */ type FormValues = [Schema] extends [undefined] ? Record : Schema extends StandardSchemaV1 ? InferFormValues : Record; /** * Options for the bulk hydration helpers `form.fill()` / `form.setValues()`. */ type FillOptions = { /** * Whether filled controls should be marked dirty. * * @default false */ dirty?: boolean; /** * Whether filled controls should be validated after writing. * * @default false */ validate?: boolean; }; type HiddenInputProps = { /** * Input name */ name: string; /** * Input value */ value?: any; /** * Default value */ defaultValue?: any; }; type FormSubmitOptions = { /** * Form instance */ form: FormInterface; /** * Form submit event * Will be undefined if the form is submitted programmatically */ event?: React.FormEvent; /** * Form values. * * When a `schema` is passed to the form, this is typed as the schema's * inferred **output** shape; otherwise it is a loose record. */ values: FormValues; /** * Get form values as FormData */ formData: FormData; }; type FormProps = Omit, "onSubmit" | "onError" | "defaultValue" | "values"> & { /** * Triggered when form validation results to error */ onError?: (invalidInputs: FormControl[]) => void; /** * Triggered when form validation is passed and now its in the submit process. * * If the handler returns a Promise, the form keeps its submitting state until * the promise settles and then auto-clears it (success or failure) — you no * longer need to call `form.submitting(false)` manually in that case. */ onSubmit?: (options: FormSubmitOptions) => void | Promise; /** * Form element * * @default form */ component?: React.ComponentType; /** * Default value that will be passed to all form controls. * * This is the **reset baseline** — `form.reset()` restores controls to these * values. For data that arrives after mount (edit forms) prefer the reactive * `values` prop or `form.fill()`. */ defaultValue?: Record | undefined; /** * Reactive current values. Unlike `defaultValue`, changing the identity of * this object **re-hydrates** already-mounted controls (and seeds controls * that mount later). Ideal for edit forms whose record loads asynchronously. */ values?: Record | undefined; /** * Whole-form Standard Schema validator (`@warlock.js/seal`, `zod`, * `valibot`, …). Runs against the collected values on submit; each issue is * mapped back to its control by `path`. Also drives `onSubmit` value typing. */ schema?: Schema; /** * Default validation trigger for every control in this form. A per-control * `validateOn` prop overrides it. * * @default "change" */ validateOn?: ValidateOn; /** * When validation fails, move focus to the first invalid control. * * @default false */ focusFirstError?: boolean; /** * Whether to ignore empty values * * @default false */ ignoreEmptyValues?: boolean; }; type FormControlChangeOptions = { /** * Set current checked value * It's recommended to use `setChecked` method instead */ checked?: boolean; /** * Whether to update the state or not * * @default true */ updateState?: boolean; /** * Whether to perform form control validation or not * * @default true */ validate?: boolean; /** * Whether this change should mark the control as dirty. * Internal callers (e.g. `reset()`) pass `false` so the value * write does not flip the dirty flag back on. * * @default true */ dirty?: boolean; [key: string]: any; }; type FormControlChange = FormControlChangeOptions & { formControl: FormControl; }; type FormControl = { /** * Form input name, it must be unique */ name: string; /** * Form control type */ type: string; /** * default value */ defaultValue?: any; /** * Check if form control's value is changed */ isDirty: boolean; /** * Check if form control is touched * Touched means that the user has focused on the input */ isTouched: boolean; /** * Whether an async validation rule is currently in-flight for this control. */ isValidating: boolean; /** * Form input id, used as a form input flag determiner */ id: string; /** * Form input value */ value: any; /** * Input Initial value */ initialValue: any; /** * Triggered when form starts validation. * * Returns the rendered error (or `null` when valid) **synchronously** when * every rule is synchronous, and a `Promise` of it only when a rule returns * one (the sync-fast-path). The form `await`s this either way, so async * validation genuinely gates submission. */ validate: () => ReactNode | Promise; /** * Set form input error */ setError: (error: React.ReactNode) => void; /** * Determine if current control is visible in the browser */ isVisible: () => boolean; /** * Determine whether the form input is valid, this is checked after calling the validate method * if the form control is not validated yet, then it will return null */ isValid: boolean | null; /** * List of errors caused by rules */ errorsList: { [rule: string]: React.ReactNode; }; /** * Focus on the element */ focus: () => void; /** * Trigger blur event on the element */ blur: () => void; /** * Clear form control value */ clear: () => void; /** * Abandon any in-flight async validation for this control: discards pending * results and clears `isValidating`. Called by `reset()` / `clear()`. */ cancelValidation: () => void; /** * Triggered when form resets its values */ reset: () => void; /** * Form Input Error */ error: React.ReactNode; /** * Unregister form control */ unregister: () => void; /** * Props list to this component */ props: any; /** * Check if the input's value is marked as checked */ checked: boolean; /** * Set checked value */ setChecked: (checked: boolean) => void; /** * Initial checked value */ initialChecked: boolean; /** * Determine if form control is multiple */ multiple?: boolean; /** * Collect form control value */ collectValue: () => any; /** * Check if input is collectable */ isCollectable: () => boolean; /** * Determine if form control is controlled */ isControlled: boolean; /** * Change form control value and any other related values */ change: (value: any, changeOptions?: FormControlChangeOptions) => void; /** * Determine if form control is rendered */ rendered: boolean; /** * Input Ref */ inputRef: any; /** * Visible element ref */ visibleElementRef: any; /** * Listen when form control value is changed */ onChange: (callback: (value: FormControlChange) => void) => EventSubscription; /** * Listen when form control is destroyed */ onDestroy: (callback: () => void) => EventSubscription; /** * Listen to form control when value is reset */ onReset: (callback: () => void) => EventSubscription; /** * Listen to form control when it is cleared (via `clear()`). */ onClear: (callback: () => void) => EventSubscription; /** * Disable/Enable form control */ disable: (disable: boolean) => void; /** * Determine if form control is disabled */ disabled: boolean; /** * Whether unchecked value should be collected * * Works only if type is `checkbox` or `radio` * @default false */ collectUnchecked?: boolean; /** * Define the value if control checked state is false, If collectUnchecked is true */ uncheckedValue?: any; /** * Any other data to be used by the form control */ data?: any; }; /** * Form control events that can be subscribed to by the form control */ type FormControlEvent = "change" | "reset" | "resetting" | "disabled" | "unregister" | "validation.start" | "validation.success" | "validation.error" | "validation.end"; /** * Returns when calling form.values() or form.toObject() to list all form inputs with its values */ type FormControlValues = { [name: string]: any; }; /** * Form events types */ type FormEventType = /** * Triggered before form starts validation */ "validating" /** * Triggered when an invalid control is added to invalid controls */ | "invalidControl" /** * Triggered when invalid controls has at least one invalid control */ | "invalidControls" /** * Triggered when an invalid control becomes valid control */ | "validControl" /** * Triggered when all invalid controls become valid controls */ | "validControls" /** * Triggered after form validation */ | "validation" /** * Triggered before form starts submitting and after form validation passes */ | "submitting" /** * Triggered after form submission */ | "submit" /** * Triggered before disabling/enabling form */ | "disabling" /** * Triggered after disabling/enabling form */ | "disable" /** * Triggered when at least one form inputs value has been changed */ | "dirty" /** * Triggered before form resetting function */ | "resetting" /** * Triggered after form resetting */ | "reset" /** * Triggered before form registering form input */ | "registering" /** * Triggered after form registering form input */ | "register" /** * Triggered before form unregistering form input */ | "unregistering" /** * Triggered after form unregistering form input */ | "unregister" /** * Triggered when form control's value is changed */ | "change" /** * Triggered before form values are collected */ | "collecting" /** * Triggered after form values are collected */ | "collected" /** * Triggered after form is initialized */ | "init"; type ReactComponent = React.FC | React.ComponentClass; interface FormInterface { /** * Form element. * * On web this is the rendered `HTMLFormElement`. On React Native (or * other non-DOM platforms) it is the ref of whatever `component` was * passed to the form (e.g. a `View`), or `null` when no component is * provided. */ formElement: any; /** * Form dirty state */ isDirty: boolean; /** * Form dirty controls */ dirtyControls: FormControl[]; /** * Trigger form submission */ submitting: (submitting: boolean) => void; /** * Validate the form. Pass a subset of control names (or `FormControl` * objects) to validate only those. Resolves with the validated controls. */ validate: (controls?: FormControl[] | string[]) => Promise; /** * Validate only the controls currently visible in the DOM. */ validateVisible: () => Promise; /** * Disable (or, with `false`, enable) every control in the form. */ disable: (isDisabled: boolean) => this; /** * Enable every control in the form (shorthand for `disable(false)`). */ enable: () => this; /** * Whether the whole form is currently disabled. */ isDisabled: () => boolean; /** * Form-level error messages with no owning control (whole-form schema issues * whose path maps to no control). Populated by {@link validate}. */ formErrors: React.ReactNode[]; /** * Determine whether the form is being submitted */ isSubmitting: () => boolean; /** * Determine whether the form is valid, can be called after form validation */ isValid: () => boolean; /** * Change form input value using its name */ change: (name: string, value: any) => void; /** * Manually submit form */ submit: () => void; /** * Form events method */ on: (event: FormEventType, callback: (form: FormInterface) => void) => EventSubscription; /** * Register new form input */ register: (formInput: FormControl) => void; /** * Unregister form input from the form */ unregister: (formInput: FormControl) => void; /** * Reset form values and validation state. Pass `values` to reset to a new * baseline (merged into `defaultValue`) instead of the original one. */ reset: (values?: Record) => this; /** * Reset form errors */ resetErrors: () => this; /** * Check and trigger form validation state */ checkIfIsValid: () => void; /** * Get all form values * If formControlNames is passed, then it will be operated only on these names. */ values: (formControlNames?: string[]) => FormControlValues; /** * Get value for the given control * */ value: (FormControlName: string) => any; /** * Get form id */ get id(): string; /** * Get input by input value * * @defaults getBy id */ control: (value: string, getBy?: "name" | "id") => FormControl | null; /** * Get form controls list or only the given names */ controls: (formControlNames?: string[]) => FormControl[]; /** * Mark the given form control as invalid control */ invalidControl: (formControl: FormControl) => void; /** * Mark the given form control as valid control */ validControl: (formControl: FormControl) => void; /** * Default value that will be passed to all form controls (reset baseline). */ defaultValue?: Record; /** * Reactive hydration snapshot. Read by controls that mount *after* a * `fill()` / reactive `values` update so they seed from the latest data. */ hydrationValues?: Record; /** * Whole-form Standard Schema validator, if one was provided. */ schema?: StandardSchemaV1; /** * Form-level default validation trigger. Per-control `validateOn` overrides. */ validateOn?: ValidateOn; /** * Whether the form has attempted submission at least once. Drives * `validateOn: "submit"` revalidation behavior. */ wasSubmitted: boolean; /** * Bulk-write values onto already-mounted controls and seed later-mounting * controls. Use for edit-form hydration when the record loads asynchronously. * `defaultValue` remains the reset baseline; `fill()` does not change it. */ fill: (values: Record, options?: FillOptions) => this; /** * Alias of {@link fill}. */ setValues: (values: Record, options?: FillOptions) => this; /** * Bulk-assign errors keyed by dot-notation control name — for mapping a * server validation response (e.g. HTTP 422) back onto controls. * Names with no matching control are ignored. */ setErrors: (errors: Record) => this; /** * Resolve the seed value for a control name from the reactive hydration * snapshot then the reset baseline. Returns `undefined` when neither has it. */ getInitialValue: (name: string) => any; /** * Resolve the reset baseline for a control name from `defaultValue` only * (never the hydration snapshot). Returns `undefined` when absent. */ getResetBaseline: (name: string) => any; } type InputRuleOptions = { /** * Current value */ value: any; /** * Form input name */ name: string; /** * Form Control */ formControl: FormControl; /** * Form instance */ form: FormInterface | null; [key: string]: any; }; type FormContextData = FormInterface | null; type InputRuleResult = React.ReactNode | undefined; type InitOptions = { formControl: FormControl; form: FormInterface; [key: string]: any; }; type InputRule = { validate: (options: InputRuleOptions) => InputRuleResult | Promise; /** * Validation rule name */ name?: string; /** * Preserved props will be used to prevent these props to be passed to `otherProps` object */ preservedProps?: string[]; /** * Whether it requires a value to be called or not * * @default true */ requiresValue?: boolean; /** * Determine what input type to run this input against */ requiresType?: string; /** * Called when form control is initialized */ onInit?: (options: InitOptions) => EventSubscription | undefined; }; type ErrorMessages = { [errorName: string]: string; }; type ErrorKeys = ErrorMessages; type ValidateOn = "change" | "blur" | "submit"; type FormControlOptions = { /** * Whether to run all validation rules even if one of them fails * * @default false */ validateAll?: boolean; /** * Determine if form input value is multiple */ multiple?: boolean; /** * Callback used to determine if input's value should be collected when calling form.values() */ isCollectable?: (formControl: FormControl) => boolean; /** * Manually return the value that should be collected */ collectValue?: (formControl: FormControl) => any; /** * Set unchecked value to be sent * If not set and input is not checked, then it will not be sent */ uncheckedValue?: any; /** * Determine whether to collect unchecked value */ collectUnchecked?: boolean; /** * Transform input value before setting it */ transformValue?: (value: any, formControl?: FormControl) => any; /** * Per-field Standard Schema validator. Equivalent to passing `schema` in the * control props; useful when authoring a reusable input wrapper. */ schema?: StandardSchemaV1; }; type FormControlProps = { /** * Input name attribute, allows dot notation syntax * i.e user.name is valid, will be transformed into user[name] */ name: string; /** * Input id attribute */ id?: string; /** * Override error messages */ errors?: ErrorMessages; /** * Error keys * Used only when errorMessages is not set * Error key is the key that will be replaced on the validation error message. * Each rule can have its own error key. * But they all have `name` as default error key. */ errorKeys?: ErrorKeys; /** * Input value, used with onChange */ value?: any; /** * Input default value */ defaultValue?: any; /** * Determine if the input is disabled */ disabled?: boolean; /** * Determine if the input is read only */ readOnly?: boolean; /** * Input type */ type?: string; /** * Determine if the input is required */ required?: boolean; /** * Input placeholder */ placeholder?: string; /** * Input label */ label?: React.ReactNode; /** * Triggered when input validation has an error */ onError?: (error: React.ReactNode) => any; /** * Add manual validation */ validate?: InputRule["validate"]; /** * Per-field Standard Schema validator (`@warlock.js/seal`, `zod`, …). Wrapped * as a rule and run inside this control's pipeline. */ schema?: StandardSchemaV1; /** * Input validation rules list */ rules?: InputRule[]; /** * A callback function triggered on input value changes */ onChange?: (value: any, options?: FormControlChangeOptions) => void; /** * Validate the input based on type of change * * @default change */ validateOn?: ValidateOn; /** * Any other props */ [key: string]: any; }; type FormControlHook = { /** * Input id */ id: string; /** * Input name */ name: string; /** * Input type */ type: string; /** * Input value */ value: any; /** * Input error */ error: ReactNode; /** * Set input error */ setError: (error: React.ReactNode) => void; /** * Input Ref */ inputRef: any; /** * Visible element ref */ visibleElementRef: any; /** * Form input handler */ formControl: FormControl; /** * Manually validate the input. Returns the rendered error (or `null`) * synchronously, or a `Promise` of it when an async rule is involved. */ validate: () => ReactNode | Promise; /** * Determine if input is checked */ checked: boolean; /** * Update checked state */ setChecked: (checked: boolean) => void; /** * Other props passed to the input */ otherProps: any; /** * Change value */ changeValue: (value: any, otherOptions?: FormControlChangeOptions) => void; /** * Determine if form control is disabled */ disabled: boolean; /** * Disable form control */ disable: () => void; /** * Enable form control */ enable: () => void; /** * Errors list */ errorsList: FormControl["errorsList"]; /** * Determine if current form control is not valid * * An invalid control is a control that is touched and has at least one error */ isInvalid: boolean; /** * Whether an async validation rule is currently in-flight for this control. */ isValidating: boolean; /** * Stable id for the error element — wire it as the error node's `id` and the * input's `aria-describedby` (already done for you by `getInputProps`). */ errorId: string; /** * Blur handler — triggers validation when `validateOn` is `"blur"`. Spread via * `getInputProps` or wire manually. */ onBlur: () => void; /** * Accessibility-complete prop bag for the host input. Spread onto your * `` to get `id`, `name`, `value`/`checked`, `onChange`, `onBlur`, * `ref`, `disabled`, `aria-invalid`, `aria-required`, and `aria-describedby`. * Pass `overrides` to merge/replace any of them. */ getInputProps: (overrides?: Record) => Record; /** * Prop bag for the error message element — `{ id, role, "aria-live" }`. */ getErrorProps: () => { id: string; role: "alert"; "aria-live": "polite"; }; }; /** * A single row managed by {@link FieldArrayHelpers}. `key` is a stable React * key that survives reordering/removal; `name` is the dot-notation prefix for * the row's inputs (e.g. `addresses.0`). */ type FieldArrayItem = { /** * Stable, unique key for this row — use as the React `key`. */ key: string; /** * Current index of this row in the array. */ index: number; /** * Dot-notation name prefix for inputs in this row, e.g. `addresses.0`. * Compose child input names as `` `${item.name}.city` ``. */ name: string; }; /** * Return shape of `useFieldArray(name)` — helpers to manage a dynamic list of * repeated field rows with stable keys. */ type FieldArrayHelpers = { /** * The current rows. Map over these to render; use `item.key` as the React key * and `item.name` as the input name prefix. */ fields: FieldArrayItem[]; /** * Append one or more rows to the end. */ append: (count?: number) => void; /** * Prepend one or more rows to the start. */ prepend: (count?: number) => void; /** * Remove the row at `index` (or the last row when omitted). */ remove: (index?: number) => void; /** * Insert a row at `index`. */ insert: (index: number) => void; /** * Move a row from one index to another. */ move: (from: number, to: number) => void; /** * Swap two rows. */ swap: (a: number, b: number) => void; /** * Replace all rows with `count` fresh rows. */ replace: (count: number) => void; }; type FormConfigurations = { /** * Whether to ignore empty values when calling form.values() * * @default false */ ignoreEmptyValues?: boolean; /** * Set form component * * @default `form` */ formComponent?: ReactComponent; /** * Global default validation trigger for all controls. A form-level or * per-control `validateOn` overrides this. * * @default "change" */ validateOn?: ValidateOn; }; //#endregion export { ActiveForms, ErrorKeys, ErrorMessages, FieldArrayHelpers, FieldArrayItem, FillOptions, FormConfigurations, FormContextData, FormControl, FormControlChange, FormControlChangeOptions, FormControlEvent, FormControlHook, FormControlOptions, FormControlProps, FormControlValues, FormEventType, FormInterface, FormProps, FormSubmitOptions, FormValues, HiddenInputProps, InputRule, InputRuleOptions, InputRuleResult, ReactComponent, ValidateOn }; //# sourceMappingURL=types.d.mts.map