@railway-ts/use-form 0.1.1 → 0.1.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{index.js → index.mjs} +2 -2
- package/dist/index.mjs.map +1 -0
- package/package.json +1 -1
- package/dist/index.js.map +0 -1
|
@@ -985,5 +985,5 @@ var useFormAutoSubmission = (form, delay = 200) => {
|
|
|
985
985
|
};
|
|
986
986
|
|
|
987
987
|
export { useDebounce, useForm, useFormAutoSubmission };
|
|
988
|
-
//# sourceMappingURL=index.
|
|
989
|
-
//# sourceMappingURL=index.
|
|
988
|
+
//# sourceMappingURL=index.mjs.map
|
|
989
|
+
//# sourceMappingURL=index.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/utils.ts","../src/formReducer.ts","../src/arrayHelpersFactory.ts","../src/fieldPropsFactory.ts","../src/useForm.ts","../src/useDebounce.ts","../src/useAutoSubmitForm.ts"],"names":["errors","useRef","useEffect","useCallback"],"mappings":"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","file":"index.mjs","sourcesContent":["import type { FieldPath } from './types';\n\n/**\n * Retrieves a value from a nested object using a path string.\n * Supports both dot notation for object properties and bracket notation for array indices.\n * Returns undefined if any part of the path doesn't exist.\n *\n * Internally normalizes bracket notation to dot notation (e.g., \"arr[0]\" → \"arr.0\")\n * and traverses the object tree to find the value.\n *\n * @template TObj - The object type to extract from\n * @template TValue - The expected return value type\n *\n * @param obj - The object to extract value from\n * @param path - Path to the value using dot or bracket notation\n * @returns The value at the path, or undefined if not found\n *\n * @example\n * // Simple dot notation\n * const user = { name: \"John\", age: 30 };\n * getValueByPath(user, \"name\"); // \"John\"\n *\n * @example\n * // Nested dot notation\n * const user = { address: { city: \"NYC\", zip: \"10001\" } };\n * getValueByPath(user, \"address.city\"); // \"NYC\"\n *\n * @example\n * // Bracket notation for arrays\n * const user = { contacts: [\"email@example.com\", \"phone@example.com\"] };\n * getValueByPath(user, \"contacts[0]\"); // \"email@example.com\"\n *\n * @example\n * // Combined notation for deeply nested structures\n * const user = { teams: [{ name: \"Engineering\", members: [{ name: \"Alice\" }] }] };\n * getValueByPath(user, \"teams[0].members[0].name\"); // \"Alice\"\n *\n * @example\n * // Missing path returns undefined\n * const user = { name: \"John\" };\n * getValueByPath(user, \"address.city\"); // undefined\n */\nexport const getValueByPath = <\n TObj extends Record<string, unknown>,\n TValue = unknown,\n>(\n obj: TObj,\n path: FieldPath\n): TValue | undefined => {\n if (!path) return obj as unknown as TValue;\n\n const normalizedPath = path.replace(/\\[(\\d+)\\]/g, '.$1');\n const parts = normalizedPath.split('.').filter(Boolean);\n\n let current: unknown = obj;\n for (const part of parts) {\n if (current == null) return undefined;\n current = (current as Record<string, unknown>)[part];\n }\n\n return current as TValue | undefined;\n};\n\n/**\n * Sets a value in a nested object using a path string, returning a new object.\n * Creates intermediate objects and arrays as needed without mutating the original.\n * All updates are performed immutably using spreading.\n *\n * Internally normalizes bracket notation to dot notation and determines whether\n * to create objects or arrays based on whether the next path segment is numeric.\n *\n * @template TObj - The object type to update\n * @template TValue - The value type to set\n *\n * @param obj - The source object to set value in (not mutated)\n * @param path - Path to the value using dot or bracket notation\n * @param value - The value to set at the path\n * @returns A new object with the updated value\n *\n * @example\n * // Update existing nested property\n * const user = { name: \"John\", address: { city: \"NYC\" } };\n * const updated = setValueByPath(user, \"address.city\", \"San Francisco\");\n * // updated = { name: \"John\", address: { city: \"San Francisco\" } }\n * // user is unchanged (immutable)\n *\n * @example\n * // Create missing intermediate objects\n * const user = { name: \"John\" };\n * const updated = setValueByPath(user, \"address.city\", \"NYC\");\n * // updated = { name: \"John\", address: { city: \"NYC\" } }\n *\n * @example\n * // Update array element\n * const user = { contacts: [\"old@example.com\"] };\n * const updated = setValueByPath(user, \"contacts[0]\", \"new@example.com\");\n * // updated = { contacts: [\"new@example.com\"] }\n *\n * @example\n * // Create missing arrays and nested properties\n * const user = {};\n * const updated = setValueByPath(user, \"teams[0].name\", \"Engineering\");\n * // updated = { teams: [{ name: \"Engineering\" }] }\n *\n * @example\n * // Deep nested update\n * const form = { users: [{ address: { city: \"NYC\" } }] };\n * const updated = setValueByPath(form, \"users[0].address.zip\", \"10001\");\n * // updated = { users: [{ address: { city: \"NYC\", zip: \"10001\" } }] }\n */\nexport const setValueByPath = <TObj extends Record<string, unknown>, TValue>(\n obj: TObj,\n path: FieldPath,\n value: TValue\n): TObj => {\n if (!path) return value as unknown as TObj;\n\n const normalizedPath = path.replace(/\\[(\\d+)\\]/g, '.$1');\n const parts = normalizedPath.split('.').filter(Boolean);\n\n // Clone the root (array/object)\n const result: unknown = Array.isArray(obj)\n ? [...(obj as unknown[])]\n : { ...obj };\n let currNew: Record<string, unknown> | unknown[] = Array.isArray(result)\n ? (result as unknown[])\n : (result as Record<string, unknown>);\n let currOld: unknown = obj;\n\n for (let i = 0; i < parts.length; i++) {\n const keyStr = parts[i]!;\n const isIndex = /^\\d+$/.test(keyStr);\n const key: number | string = isIndex ? Number(keyStr) : keyStr;\n\n if (i === parts.length - 1) {\n // Final set\n if (Array.isArray(currNew) && typeof key === 'number') {\n currNew[key] = value as unknown;\n } else if (!Array.isArray(currNew) && typeof key === 'string') {\n currNew[key] = value as unknown;\n }\n break;\n }\n\n // Prepare next container\n let nextOld: unknown = undefined;\n if (currOld != null && typeof currOld === 'object') {\n if (Array.isArray(currOld) && typeof key === 'number') {\n nextOld = (currOld as unknown[])[key];\n } else if (!Array.isArray(currOld) && typeof key === 'string') {\n nextOld = (currOld as Record<string, unknown>)[key];\n }\n }\n let nextNew: Record<string, unknown> | unknown[];\n\n if (nextOld == null) {\n // Create missing container based on the next segment\n const nextIsIndex = /^\\d+$/.test(parts[i + 1] ?? '');\n nextNew = nextIsIndex ? [] : {};\n } else {\n nextNew = Array.isArray(nextOld)\n ? [...(nextOld as unknown[])]\n : { ...(nextOld as Record<string, unknown>) };\n }\n\n if (Array.isArray(currNew) && typeof key === 'number') {\n currNew[key] = nextNew;\n } else if (!Array.isArray(currNew) && typeof key === 'string') {\n currNew[key] = nextNew;\n }\n\n currNew = nextNew;\n currOld = nextOld ?? (Array.isArray(nextNew) ? [] : {});\n }\n\n return result as TObj;\n};\n\n/**\n * Checks if a field path is affected by changes to another path.\n * Used internally for determining which errors to clear when a field value changes.\n *\n * A path is considered affected if:\n * 1. It exactly matches the change path\n * 2. The change path is a parent of the path (e.g., \"address\" affects \"address.city\")\n *\n * Paths are normalized before comparison so bracket notation is handled correctly.\n *\n * @param path - The path to check if affected (e.g., error path)\n * @param changePath - The path that was changed (e.g., field that was updated)\n * @returns True if the path is affected by the change, false otherwise\n *\n * @example\n * // Exact match\n * isPathAffected(\"email\", \"email\"); // true\n *\n * @example\n * // Parent affects child\n * isPathAffected(\"address.city\", \"address\"); // true\n * isPathAffected(\"address.city\", \"address.city\"); // true\n *\n * @example\n * // Child does not affect parent\n * isPathAffected(\"address\", \"address.city\"); // false\n *\n * @example\n * // Unrelated paths\n * isPathAffected(\"address.city\", \"name\"); // false\n *\n * @example\n * // Array notation (normalized internally)\n * isPathAffected(\"contacts[0].email\", \"contacts\"); // true\n * isPathAffected(\"contacts[0].email\", \"contacts[0]\"); // true\n * isPathAffected(\"contacts[0].email\", \"contacts[1]\"); // false\n *\n * @example\n * // Practical use case: clearing server errors\n * const serverErrors = {\n * \"address.city\": \"City is required\",\n * \"address.zip\": \"Invalid ZIP\"\n * };\n * // When user updates \"address\", both errors should be cleared\n * Object.keys(serverErrors).filter(path => isPathAffected(path, \"address\"));\n * // Returns [\"address.city\", \"address.zip\"]\n */\nexport const isPathAffected = (\n path: FieldPath,\n changePath: FieldPath\n): boolean => {\n if (path === changePath) return true;\n\n const normalizedPath = path.replace(/\\[(\\d+)\\]/g, '.$1');\n const normalizedChangePath = changePath.replace(/\\[(\\d+)\\]/g, '.$1');\n\n // Parent affects child\n return (\n normalizedPath === normalizedChangePath ||\n normalizedPath.startsWith(`${normalizedChangePath}.`)\n );\n};\n\n/**\n * Recursively collects all field paths from a nested object structure.\n * Traverses the entire object tree and generates path strings for every field,\n * including intermediate parent paths, nested objects, and array elements.\n *\n * Useful for operations that need to touch all fields in a form, such as:\n * - Marking all fields as touched on form submission\n * - Collecting all error paths for validation\n * - Iterating over all form values\n *\n * Leaf values (primitives, Date, RegExp, null, undefined) are treated as terminal nodes.\n * Arrays are traversed with bracket notation, objects with dot notation.\n *\n * @param obj - The object to collect paths from (typically form values)\n * @param prefix - Internal parameter for recursion, starting path prefix (default: \"\")\n * @returns Array of all field paths found in the object\n *\n * @example\n * // Simple object\n * const user = { name: \"John\", age: 30 };\n * collectFieldPaths(user);\n * // Returns: [\"name\", \"age\"]\n *\n * @example\n * // Nested object\n * const user = { name: \"John\", address: { city: \"NYC\", zip: \"10001\" } };\n * collectFieldPaths(user);\n * // Returns: [\"name\", \"address\", \"address.city\", \"address.zip\"]\n * // Note: \"address\" is included as a parent path\n *\n * @example\n * // Arrays with objects\n * const form = { contacts: [{ email: \"a@example.com\" }, { email: \"b@example.com\" }] };\n * collectFieldPaths(form);\n * // Returns: [\"contacts\", \"contacts[0]\", \"contacts[0].email\", \"contacts[1]\", \"contacts[1].email\"]\n *\n * @example\n * // Mixed nesting\n * const form = {\n * user: { name: \"John\" },\n * tags: [\"react\", \"typescript\"]\n * };\n * collectFieldPaths(form);\n * // Returns: [\"user\", \"user.name\", \"tags\", \"tags[0]\", \"tags[1]\"]\n *\n * @example\n * // Practical use: marking all fields as touched on submit\n * const handleSubmit = () => {\n * const allPaths = collectFieldPaths(form.values);\n * allPaths.forEach(path => form.setFieldTouched(path, true));\n * // Now all validation errors will be visible\n * };\n *\n * @example\n * // Leaf values (Date, null) are treated as terminals\n * const form = { createdAt: new Date(), deletedAt: null };\n * collectFieldPaths(form);\n * // Returns: [\"createdAt\", \"deletedAt\"]\n * // Does not try to traverse into Date or null\n */\nexport const collectFieldPaths = (obj: unknown, prefix = ''): FieldPath[] => {\n const paths: FieldPath[] = [];\n\n const isLeaf = (v: unknown) =>\n v == null ||\n typeof v !== 'object' ||\n v instanceof Date ||\n v instanceof RegExp;\n\n const visit = (value: unknown, path: string) => {\n if (path) paths.push(path);\n\n if (isLeaf(value)) return;\n\n if (Array.isArray(value)) {\n value.forEach((item, i) => visit(item, `${path}[${i}]`));\n return;\n }\n\n const entries = Object.entries(value as Record<string, unknown>);\n for (const [k, v] of entries) {\n const childPath = path ? `${path}.${k}` : k;\n visit(v, childPath);\n }\n };\n\n visit(obj, prefix);\n return paths;\n};\n","import type { FieldPath, FormAction, FormState } from './types';\nimport { isPathAffected, setValueByPath } from './utils';\n\n/**\n * Reducer function for form state management using the Redux-style reducer pattern.\n * Handles all form state transitions in an immutable, predictable way.\n *\n * This reducer processes various actions that modify form state including:\n * - Field value updates (single or batch)\n * - Touch state tracking (marking fields as interacted with)\n * - Client-side validation errors\n * - Server-side validation errors\n * - Form submission state\n * - Form reset to initial values\n *\n * All state updates are performed immutably - the reducer always returns a new state object\n * rather than mutating the existing state. Server errors are automatically cleared when\n * related fields are modified to provide a smooth user experience.\n *\n * @template TValues - The type of form values being managed\n *\n * @param state - The current form state before the action is applied\n * @param action - The action to perform (e.g., SET_FIELD_VALUE, SET_CLIENT_ERRORS, RESET_FORM)\n * @param initialValues - Initial form values used when resetting the form\n * @returns A new form state object reflecting the changes from the action\n *\n * @example\n * // Used internally by useForm hook with useReducer\n * const reducerFn = useCallback(\n * (state: FormState<TValues>, action: FormAction<TValues>) =>\n * formReducer(state, action, initialValues),\n * [initialValues]\n * );\n * const [formState, dispatch] = useReducer(reducerFn, initialState);\n *\n * @example\n * // Dispatching a field value change\n * dispatch({\n * type: \"SET_FIELD_VALUE\",\n * field: \"email\",\n * value: \"user@example.com\"\n * });\n *\n * @example\n * // Dispatching validation errors\n * dispatch({\n * type: \"SET_CLIENT_ERRORS\",\n * errors: { email: \"Invalid email format\", password: \"Too short\" }\n * });\n *\n * @example\n * // Marking all fields as touched on submit\n * dispatch({\n * type: \"MARK_ALL_TOUCHED\",\n * fields: [\"name\", \"email\", \"password\"]\n * });\n */\nexport const formReducer = <TValues extends Record<string, unknown>>(\n state: FormState<TValues>,\n action: FormAction<TValues>,\n initialValues: Partial<TValues>\n): FormState<TValues> => {\n switch (action.type) {\n case 'SET_FIELD_VALUE': {\n const newValues = setValueByPath(\n state.values,\n action.field,\n action.value\n );\n\n const newServerErrors = { ...state.serverErrors };\n Object.keys(newServerErrors).forEach((errorPath) => {\n if (isPathAffected(errorPath, action.field)) {\n delete newServerErrors[errorPath];\n }\n });\n\n return {\n ...state,\n values: newValues,\n serverErrors: newServerErrors,\n isDirty: true,\n };\n }\n\n case 'SET_VALUES': {\n const newServerErrors = { ...state.serverErrors };\n Object.keys(action.values).forEach((field) => {\n Object.keys(newServerErrors).forEach((errorPath) => {\n if (isPathAffected(errorPath, field)) {\n delete newServerErrors[errorPath];\n }\n });\n });\n\n return {\n ...state,\n values: { ...state.values, ...action.values },\n serverErrors: newServerErrors,\n isDirty: true,\n };\n }\n\n case 'SET_FIELD_TOUCHED':\n return {\n ...state,\n touched: {\n ...state.touched,\n [action.field]: action.isTouched,\n },\n };\n\n case 'SET_CLIENT_ERRORS':\n return {\n ...state,\n clientErrors: action.errors,\n };\n\n case 'SET_SERVER_ERRORS':\n return {\n ...state,\n serverErrors: action.errors,\n };\n\n case 'CLEAR_SERVER_ERRORS':\n return {\n ...state,\n serverErrors: {},\n };\n\n case 'SET_SUBMITTING':\n return {\n ...state,\n isSubmitting: action.isSubmitting,\n };\n\n case 'RESET_FORM':\n return {\n values: initialValues,\n touched: {},\n clientErrors: {},\n serverErrors: {},\n isSubmitting: false,\n isDirty: false,\n };\n\n case 'MARK_ALL_TOUCHED': {\n const allTouched: Record<FieldPath, boolean> = {};\n action.fields.forEach((path) => {\n allTouched[path] = true;\n });\n\n return {\n ...state,\n touched: {\n ...state.touched,\n ...allTouched,\n },\n };\n }\n\n default:\n return state;\n }\n};\n","import type {\n ArrayHelpers,\n ExtractFieldPaths,\n FieldPath,\n NativeSelectProps,\n NativeSliderProps,\n NativeFieldProps,\n NativeCheckboxProps,\n NativeSwitchProps,\n NativeFileFieldProps,\n NativeRadioGroupOptionProps,\n} from './types';\n\n/**\n * Factory function that creates an ArrayHelpers object for managing array fields in forms.\n * Provides type-safe methods to add, remove, update, and reorder array items, as well as\n * bind native HTML elements to fields within array items.\n *\n * This is typically called internally by the useForm hook's arrayHelpers() method\n * and not used directly by consumers.\n *\n * @template TItem - The type of items stored in the array\n * @template TFieldPaths - Union of valid field paths for the item type\n *\n * @param field - The path to the array field in the form\n * @param arrayValue - The current array values\n * @param setFieldValue - Function to update a field value in the form\n * @param getFieldProps - Function to get props for native text inputs\n * @param getSelectFieldProps - Function to get props for native select elements\n * @param getSliderProps - Function to get props for native range inputs\n * @param getCheckboxProps - Function to get props for native checkboxes\n * @param getSwitchProps - Function to get props for native switches\n * @param getFileFieldProps - Function to get props for native file inputs\n * @param getRadioGroupOptionProps - Function to get props for radio group options\n * @returns An ArrayHelpers object with methods for array manipulation and field binding\n *\n * @example\n * // Used internally by useForm\n * const contactsHelpers = form.arrayHelpers(\"contacts\");\n * contactsHelpers.push({ name: \"\", email: \"\" });\n * contactsHelpers.remove(0);\n *\n * @example\n * // Accessing nested fields in array items\n * const helpers = form.arrayHelpers(\"addresses\");\n * return helpers.values.map((_, index) => (\n * <input {...helpers.getFieldProps(index, \"street\")} />\n * ));\n */\nexport const createArrayHelpers = <\n TItem = unknown,\n TFieldPaths extends string = ExtractFieldPaths<TItem>,\n>(\n field: FieldPath,\n arrayValue: TItem[],\n setFieldValue: (field: FieldPath, value: unknown) => void,\n getFieldProps: (field: string) => NativeFieldProps,\n getSelectFieldProps: (field: string) => NativeSelectProps,\n getSliderProps: (field: string) => NativeSliderProps,\n getCheckboxProps: (field: string) => NativeCheckboxProps,\n getSwitchProps: (field: string) => NativeSwitchProps,\n getFileFieldProps: (field: string) => NativeFileFieldProps,\n getRadioGroupOptionProps: (\n field: string,\n optionValue: string | number\n ) => NativeRadioGroupOptionProps\n): ArrayHelpers<TItem, TFieldPaths> => {\n return {\n /**\n * The current array of values for this field.\n * Use this to iterate over items when rendering the form.\n *\n * @example\n * // Render array items\n * helpers.values.map((contact, index) => (\n * <div key={index}>\n * <input {...helpers.getFieldProps(index, \"name\")} />\n * </div>\n * ))\n */\n values: arrayValue,\n\n /**\n * Adds a new item to the end of the array.\n * The form state is updated immutably and all subscribed components re-render.\n *\n * @param value - The item to add to the array\n *\n * @example\n * // Add a new contact\n * const helpers = form.arrayHelpers(\"contacts\");\n * helpers.push({ name: \"\", email: \"\", phone: \"\" });\n */\n push: (value: TItem) => {\n const newArray = [...arrayValue, value];\n setFieldValue(field, newArray);\n },\n\n /**\n * Removes an item at the specified index from the array.\n * If the index is out of bounds, no action is taken.\n * The form state is updated immutably.\n *\n * @param index - The zero-based index of the item to remove\n *\n * @example\n * // Remove the second contact\n * const helpers = form.arrayHelpers(\"contacts\");\n * helpers.remove(1);\n */\n remove: (index: number) => {\n if (index < 0 || index >= arrayValue.length) return;\n const newArray = [...arrayValue];\n newArray.splice(index, 1);\n setFieldValue(field, newArray);\n },\n\n /**\n * Inserts an item at the specified index in the array.\n * Items at and after the index are shifted to the right.\n * If the index is out of bounds, it's clamped to valid range [0, length].\n *\n * @param index - The zero-based insertion position\n * @param value - The item to insert\n *\n * @example\n * // Insert a contact at the beginning\n * const helpers = form.arrayHelpers(\"contacts\");\n * helpers.insert(0, { name: \"New Contact\", email: \"\", phone: \"\" });\n */\n insert: (index: number, value: TItem) => {\n const clamped = Math.max(0, Math.min(index, arrayValue.length));\n const newArray = [...arrayValue];\n newArray.splice(clamped, 0, value);\n setFieldValue(field, newArray);\n },\n\n /**\n * Swaps the positions of two items in the array.\n * If either index is out of bounds or they are equal, no action is taken.\n * Useful for drag-and-drop reordering interfaces.\n *\n * @param indexA - The zero-based index of the first item\n * @param indexB - The zero-based index of the second item\n *\n * @example\n * // Swap first and second contacts\n * const helpers = form.arrayHelpers(\"contacts\");\n * helpers.swap(0, 1);\n *\n * @example\n * // Move item up in list\n * const moveUp = (index: number) => {\n * if (index > 0) helpers.swap(index, index - 1);\n * };\n */\n swap: (indexA: number, indexB: number) => {\n if (\n indexA === indexB ||\n indexA < 0 ||\n indexB < 0 ||\n indexA >= arrayValue.length ||\n indexB >= arrayValue.length\n ) {\n return;\n }\n const newArray = [...arrayValue];\n\n const a = newArray[indexA];\n const b = newArray[indexB];\n if (a === undefined || b === undefined) {\n return;\n }\n\n newArray[indexA] = b;\n newArray[indexB] = a;\n setFieldValue(field, newArray);\n },\n\n /**\n * Replaces an entire item at the specified index with a new value.\n * If the index is out of bounds, no action is taken.\n *\n * @param index - The zero-based index of the item to replace\n * @param value - The new item value\n *\n * @example\n * // Replace a contact entirely\n * const helpers = form.arrayHelpers(\"contacts\");\n * helpers.replace(0, { name: \"John Doe\", email: \"john@example.com\", phone: \"555-0100\" });\n */\n replace: (index: number, value: TItem) => {\n if (index < 0 || index >= arrayValue.length) return;\n const newArray = [...arrayValue];\n newArray[index] = value;\n setFieldValue(field, newArray);\n },\n\n /**\n * Gets props for a native text input bound to a field within an array item.\n * Provides type-safe field path autocomplete for nested fields.\n * Works with: <input type=\"text\">, <input type=\"email\">, <textarea>, etc.\n *\n * @param index - The zero-based index of the array item\n * @param subField - The field path within the array item (type-safe and autocompleted)\n * @returns Props object to spread onto a native input element\n *\n * @example\n * // Text input for contact name\n * helpers.values.map((_, index) => (\n * <input type=\"text\" {...helpers.getFieldProps(index, \"name\")} />\n * ))\n */\n getFieldProps: (index: number, subField: TFieldPaths) => {\n const path = `${field}[${index}].${subField}`;\n return getFieldProps(path);\n },\n\n /**\n * Gets props for a native select element bound to a field within an array item.\n * Provides type-safe field path autocomplete for nested fields.\n * Works with: <select>\n *\n * @param index - The zero-based index of the array item\n * @param subField - The field path within the array item (type-safe and autocompleted)\n * @returns Props object to spread onto a native select element\n *\n * @example\n * // Select for contact type\n * <select {...helpers.getSelectFieldProps(index, \"type\")}>\n * <option value=\"work\">Work</option>\n * <option value=\"personal\">Personal</option>\n * </select>\n */\n getSelectFieldProps: (index: number, subField: TFieldPaths) => {\n const path = `${field}[${index}].${subField}`;\n return getSelectFieldProps(path);\n },\n\n /**\n * Gets props for a native range input bound to a field within an array item.\n * Provides type-safe field path autocomplete for nested fields.\n * Works with: <input type=\"range\">\n *\n * @param index - The zero-based index of the array item\n * @param subField - The field path within the array item (type-safe and autocompleted)\n * @returns Props object to spread onto a native range input element\n *\n * @example\n * // Range slider for priority\n * <input type=\"range\" min={0} max={10} {...helpers.getSliderProps(index, \"priority\")} />\n */\n getSliderProps: (index: number, subField: TFieldPaths) => {\n const path = `${field}[${index}].${subField}`;\n return getSliderProps(path);\n },\n\n /**\n * Gets props for a native checkbox bound to a field within an array item.\n * Provides type-safe field path autocomplete for nested fields.\n * Works with: <input type=\"checkbox\">\n *\n * @param index - The zero-based index of the array item\n * @param subField - The field path within the array item (type-safe and autocompleted)\n * @returns Props object to spread onto a native checkbox input\n *\n * @example\n * // Checkbox for marking contact as favorite\n * <input type=\"checkbox\" {...helpers.getCheckboxProps(index, \"isFavorite\")} />\n */\n getCheckboxProps: (index: number, subField: TFieldPaths) => {\n const path = `${field}[${index}].${subField}`;\n return getCheckboxProps(path);\n },\n\n /**\n * Gets props for a native switch (checkbox styled as switch) bound to a field within an array item.\n * Provides type-safe field path autocomplete for nested fields.\n * Works with: <input type=\"checkbox\"> (styled as switch via CSS)\n *\n * @param index - The zero-based index of the array item\n * @param subField - The field path within the array item (type-safe and autocompleted)\n * @returns Props object to spread onto a native checkbox input\n *\n * @example\n * // Switch for enabling/disabling a feature\n * <label className=\"switch\">\n * <input type=\"checkbox\" {...helpers.getSwitchProps(index, \"enabled\")} />\n * <span className=\"slider\"></span>\n * </label>\n */\n getSwitchProps: (index: number, subField: TFieldPaths) => {\n const path = `${field}[${index}].${subField}`;\n return getSwitchProps(path);\n },\n\n /**\n * Gets props for a native file input bound to a field within an array item.\n * Provides type-safe field path autocomplete for nested fields.\n * Works with: <input type=\"file\">\n *\n * @param index - The zero-based index of the array item\n * @param subField - The field path within the array item (type-safe and autocompleted)\n * @returns Props object to spread onto a native file input\n *\n * @example\n * // File input for contact avatar\n * <input type=\"file\" accept=\"image/*\" {...helpers.getFileFieldProps(index, \"avatar\")} />\n */\n getFileFieldProps: (index: number, subField: TFieldPaths) => {\n const path = `${field}[${index}].${subField}`;\n return getFileFieldProps(path);\n },\n\n /**\n * Gets props for a radio group option bound to a field within an array item.\n * Provides type-safe field path autocomplete for nested fields.\n * Works with: multiple <input type=\"radio\"> elements sharing the same name\n *\n * @param index - The zero-based index of the array item\n * @param subField - The field path within the array item (type-safe and autocompleted)\n * @param optionValue - The value this radio option represents\n * @returns Props object to spread onto a native radio input\n *\n * @example\n * // Radio group for contact method preference\n * <label>\n * <input type=\"radio\" {...helpers.getRadioGroupOptionProps(index, \"preferredMethod\", \"email\")} />\n * Email\n * </label>\n * <label>\n * <input type=\"radio\" {...helpers.getRadioGroupOptionProps(index, \"preferredMethod\", \"phone\")} />\n * Phone\n * </label>\n */\n getRadioGroupOptionProps: (\n index: number,\n subField: TFieldPaths,\n optionValue: string | number\n ) => {\n const path = `${field}[${index}].${subField}`;\n return getRadioGroupOptionProps(path, optionValue);\n },\n };\n};\n","import type { ChangeEvent } from 'react';\nimport type {\n FieldPath,\n NativeFieldProps,\n NativeSelectProps,\n NativeCheckboxProps,\n NativeSwitchProps,\n NativeSliderProps,\n NativeCheckboxGroupOptionProps,\n NativeFileFieldProps,\n NativeRadioGroupOptionProps,\n} from './types';\nimport { getValueByPath } from './utils';\n\n// =============================================================================\n// Native HTML Field Props Factories\n// =============================================================================\n\n/**\n * Creates props for a native text input element bound to a form field.\n * Automatically handles value normalization, change events, and blur tracking.\n * Works with: <input type=\"text\">, <input type=\"email\">, <input type=\"date\">, <textarea>, etc.\n *\n * The returned props include id, name, value, onChange, and onBlur handlers that\n * are pre-configured to work with the form state management system.\n *\n * @param field - The path to the field in form values (supports dot notation and bracket notation)\n * @param formValues - Current form values object\n * @param handleChange - Function to update the field value in form state\n * @param handleBlur - Function to mark the field as touched in form state\n * @returns Props object to spread onto native text input elements\n *\n * @example\n * // Native text input with placeholder\n * <input type=\"text\" {...form.getFieldProps(\"username\")} placeholder=\"Username\" />\n *\n * @example\n * // Native email input\n * <input type=\"email\" {...form.getFieldProps(\"email\")} />\n *\n * @example\n * // Native textarea\n * <textarea {...form.getFieldProps(\"bio\")} rows={4} />\n *\n * @example\n * // Nested field path\n * <input type=\"text\" {...form.getFieldProps(\"address.city\")} />\n *\n * @example\n * // Date input (values are auto-converted to/from ISO format)\n * <input type=\"date\" {...form.getFieldProps(\"birthDate\")} />\n */\nexport const createNativeFieldProps = (\n field: FieldPath,\n formValues: Record<string, unknown>,\n handleChange: (field: FieldPath, value: unknown) => void,\n handleBlur: (field: FieldPath, isTouched: boolean) => void\n): NativeFieldProps => {\n const raw = getValueByPath(formValues, field);\n\n // Normalize to string or number for native inputs\n const value = (\n raw == null\n ? ''\n : typeof raw === 'string' || typeof raw === 'number'\n ? raw\n : raw instanceof Date\n ? isNaN(raw.getTime())\n ? ''\n : raw.toISOString().split('T')[0]\n : JSON.stringify(raw)\n ) as string | number;\n\n return {\n id: `field-${field.replace(/[[\\].]/g, '-')}`,\n name: field,\n value,\n onChange: (e: ChangeEvent<HTMLInputElement | HTMLTextAreaElement>) => {\n // For date inputs, clearing sets value to '' until a valid date is chosen\n // We forward the raw string and let validation handle emptiness/format.\n handleChange(field, e.target.value);\n },\n onBlur: () => handleBlur(field, true),\n };\n};\n\n/**\n * Creates props for a native select element bound to a form field.\n * Automatically handles value normalization, change events, and blur tracking.\n * Works with: <select> (single selection only, not multiple)\n *\n * The returned props include id, name, value, onChange, and onBlur handlers that\n * are pre-configured to work with the form state management system.\n *\n * @param field - The path to the field in form values (supports dot notation and bracket notation)\n * @param formValues - Current form values object\n * @param handleChange - Function to update the field value in form state\n * @param handleBlur - Function to mark the field as touched in form state\n * @returns Props object to spread onto native select elements\n *\n * @example\n * // Native select with default option\n * <select {...form.getSelectFieldProps(\"role\")}>\n * <option value=\"\">Select a role…</option>\n * <option value=\"user\">User</option>\n * <option value=\"admin\">Admin</option>\n * </select>\n *\n * @example\n * // Select with nested field path\n * <select {...form.getSelectFieldProps(\"address.country\")}>\n * <option value=\"US\">United States</option>\n * <option value=\"CA\">Canada</option>\n * <option value=\"UK\">United Kingdom</option>\n * </select>\n *\n * @example\n * // Select with dynamic options\n * <select {...form.getSelectFieldProps(\"category\")}>\n * {categories.map(cat => (\n * <option key={cat.id} value={cat.id}>{cat.name}</option>\n * ))}\n * </select>\n */\nexport const createNativeSelectFieldProps = (\n field: FieldPath,\n formValues: Record<string, unknown>,\n handleChange: (field: FieldPath, value: unknown) => void,\n handleBlur: (field: FieldPath, isTouched: boolean) => void\n): NativeSelectProps => {\n const raw = getValueByPath(formValues, field);\n\n // Native select expects primitive value\n const value =\n raw == null\n ? ''\n : typeof raw === 'string' || typeof raw === 'number'\n ? raw\n : JSON.stringify(raw);\n\n return {\n id: `field-${field.replace(/[[\\].]/g, '-')}`,\n name: field,\n value,\n onChange: (e: ChangeEvent<HTMLSelectElement>) =>\n handleChange(field, e.target.value),\n onBlur: () => handleBlur(field, true),\n };\n};\n\n/**\n * Creates props for a native checkbox input bound to a boolean form field.\n * The checkbox is checked when the field value is truthy, unchecked when falsy.\n * Automatically handles checked state, change events, and blur tracking.\n * Works with: <input type=\"checkbox\">\n *\n * Note: For checkbox groups (multiple checkboxes bound to an array), use\n * getCheckboxGroupOptionProps instead.\n *\n * @param field - The path to the field in form values (supports dot notation and bracket notation)\n * @param formValues - Current form values object\n * @param handleChange - Function to update the field value (receives boolean) in form state\n * @param handleBlur - Function to mark the field as touched in form state\n * @returns Props object to spread onto native checkbox inputs\n *\n * @example\n * // Simple checkbox for boolean field\n * <label>\n * <input type=\"checkbox\" {...form.getCheckboxProps(\"acceptTerms\")} />\n * I accept the terms and conditions\n * </label>\n *\n * @example\n * // Nested field path\n * <label>\n * <input type=\"checkbox\" {...form.getCheckboxProps(\"preferences.newsletter\")} />\n * Subscribe to newsletter\n * </label>\n *\n * @example\n * // With accessible labeling\n * <div>\n * <input type=\"checkbox\" {...form.getCheckboxProps(\"agreeToPolicy\")} />\n * <label htmlFor={form.getCheckboxProps(\"agreeToPolicy\").id}>\n * I agree to the privacy policy\n * </label>\n * </div>\n */\nexport const createNativeCheckboxProps = (\n field: FieldPath,\n formValues: Record<string, unknown>,\n handleChange: (field: FieldPath, value: unknown) => void,\n handleBlur: (field: FieldPath, isTouched: boolean) => void\n): NativeCheckboxProps => {\n const value = getValueByPath(formValues, field);\n\n return {\n id: `field-${field.replace(/[[\\].]/g, '-')}`,\n name: field,\n checked: !!value,\n onChange: (e: ChangeEvent<HTMLInputElement>) =>\n handleChange(field, e.target.checked),\n onBlur: () => handleBlur(field, true),\n };\n};\n\n/**\n * Creates props for a native switch input bound to a boolean form field.\n * Semantically identical to checkbox, but typically styled as a toggle switch via CSS.\n * The switch is \"on\" when the field value is truthy, \"off\" when falsy.\n * Works with: <input type=\"checkbox\"> (styled as switch via CSS)\n *\n * This is functionally the same as createNativeCheckboxProps but exists as a separate\n * method to clarify the semantic intent when building toggle switch UIs.\n *\n * @param field - The path to the field in form values (supports dot notation and bracket notation)\n * @param formValues - Current form values object\n * @param handleChange - Function to update the field value (receives boolean) in form state\n * @param handleBlur - Function to mark the field as touched in form state\n * @returns Props object to spread onto native checkbox inputs styled as switches\n *\n * @example\n * // Native checkbox styled as switch\n * <label className=\"switch\">\n * <input type=\"checkbox\" {...form.getSwitchProps(\"settings.darkMode\")} />\n * <span className=\"slider\"></span>\n * </label>\n *\n * @example\n * // Switch with label\n * <div className=\"setting-row\">\n * <label htmlFor={form.getSwitchProps(\"notifications.enabled\").id}>\n * Enable Notifications\n * </label>\n * <input type=\"checkbox\" {...form.getSwitchProps(\"notifications.enabled\")} className=\"toggle-switch\" />\n * </div>\n *\n * @example\n * // Multiple switches for feature flags\n * <input type=\"checkbox\" {...form.getSwitchProps(\"features.experimentalUI\")} />\n * <input type=\"checkbox\" {...form.getSwitchProps(\"features.betaFeatures\")} />\n */\nexport const createNativeSwitchProps = (\n field: FieldPath,\n formValues: Record<string, unknown>,\n handleChange: (field: FieldPath, value: unknown) => void,\n handleBlur: (field: FieldPath, isTouched: boolean) => void\n): NativeSwitchProps => {\n const value = getValueByPath(formValues, field);\n\n return {\n id: `field-${field.replace(/[[\\].]/g, '-')}`,\n name: field,\n checked: !!value,\n onChange: (e: ChangeEvent<HTMLInputElement>) =>\n handleChange(field, e.target.checked),\n onBlur: () => handleBlur(field, true),\n };\n};\n\n/**\n * Creates props for a native range input bound to a numeric form field.\n * Automatically handles value normalization, change events, and blur tracking.\n * Works with: <input type=\"range\">\n *\n * Note: Native range inputs only support single numeric values, not arrays.\n * For multi-thumb sliders or more complex range inputs, use a UI library adapter.\n * If the field value is an array, only the first element is used.\n *\n * @param field - The path to the field in form values (supports dot notation and bracket notation)\n * @param formValues - Current form values object\n * @param handleChange - Function to update the field value (receives number) in form state\n * @param handleBlur - Function to mark the field as touched in form state\n * @returns Props object to spread onto native range input elements\n *\n * @example\n * // Basic range input with value display\n * <div>\n * <input\n * type=\"range\"\n * min={0}\n * max={100}\n * {...form.getSliderProps(\"settings.volume\")}\n * />\n * <span>{form.values.settings?.volume}%</span>\n * </div>\n *\n * @example\n * // Range with step for decimal values\n * <input\n * type=\"range\"\n * min={0}\n * max={1}\n * step={0.1}\n * {...form.getSliderProps(\"opacity\")}\n * />\n *\n * @example\n * // Age slider with min/max and labels\n * <label htmlFor={form.getSliderProps(\"age\").id}>Age: {form.values.age}</label>\n * <input type=\"range\" min={18} max={100} {...form.getSliderProps(\"age\")} />\n */\nexport const createNativeSliderProps = (\n field: FieldPath,\n formValues: Record<string, unknown>,\n handleChange: (field: FieldPath, value: unknown) => void,\n handleBlur: (field: FieldPath, isTouched: boolean) => void\n): NativeSliderProps => {\n const raw = getValueByPath(formValues, field);\n\n const toNumber = (v: unknown): number =>\n typeof v === 'string' ? Number(v || 0) : typeof v === 'number' ? v : 0;\n\n // Native range only supports single values, not arrays\n const value = Array.isArray(raw) ? toNumber(raw[0]) : toNumber(raw);\n\n return {\n id: `field-${field.replace(/[[\\].]/g, '-')}`,\n name: field,\n type: 'range',\n value,\n onChange: (e: ChangeEvent<HTMLInputElement>) =>\n handleChange(field, Number(e.target.value)),\n onBlur: () => handleBlur(field, true),\n };\n};\n\n/**\n * Creates props for a single checkbox option within a checkbox group bound to an array field.\n * Each checkbox toggles the presence of its value in the array field.\n * Checking adds the value to the array; unchecking removes it.\n * Works with: multiple <input type=\"checkbox\"> elements bound to the same array field\n *\n * This is different from createNativeCheckboxProps, which is for single boolean checkboxes.\n *\n * @param field - The path to the array field in form values\n * @param optionValue - The value this checkbox represents (added/removed from array)\n * @param formValues - Current form values object\n * @param handleChange - Function to update the array field value in form state\n * @param handleBlur - Function to mark the field as touched in form state\n * @returns Props object to spread onto a checkbox input in a group\n *\n * @example\n * // Multiple checkboxes for selecting interests (array field)\n * <label>\n * <input type=\"checkbox\" {...form.getCheckboxGroupOptionProps(\"interests\", \"sports\")} />\n * Sports\n * </label>\n * <label>\n * <input type=\"checkbox\" {...form.getCheckboxGroupOptionProps(\"interests\", \"music\")} />\n * Music\n * </label>\n * <label>\n * <input type=\"checkbox\" {...form.getCheckboxGroupOptionProps(\"interests\", \"travel\")} />\n * Travel\n * </label>\n * // form.values.interests = [\"sports\", \"music\"] when both are checked\n *\n * @example\n * // Dynamic checkbox group from data\n * {permissions.map(permission => (\n * <label key={permission.id}>\n * <input type=\"checkbox\" {...form.getCheckboxGroupOptionProps(\"userPermissions\", permission.id)} />\n * {permission.name}\n * </label>\n * ))}\n */\nexport const createCheckboxGroupOptionProps = (\n field: FieldPath,\n optionValue: string | number,\n formValues: Record<string, unknown>,\n handleChange: (field: FieldPath, value: unknown) => void,\n handleBlur: (field: FieldPath, isTouched: boolean) => void\n): NativeCheckboxGroupOptionProps => {\n const raw = getValueByPath(formValues, field);\n const current = Array.isArray(raw)\n ? (raw as (string | number)[])\n : ([] as (string | number)[]);\n const isChecked = current.some((v) => String(v) === String(optionValue));\n\n return {\n id: `field-${field.replace(/[[\\].]/g, '-')}-${String(optionValue)}`,\n name: field,\n value: optionValue,\n checked: isChecked,\n onChange: (e: ChangeEvent<HTMLInputElement>) => {\n if (e.target.checked) {\n if (!current.some((v) => String(v) === String(optionValue))) {\n handleChange(field, [...current, optionValue]);\n }\n } else {\n const next = current.filter((v) => String(v) !== String(optionValue));\n handleChange(field, next);\n }\n },\n onBlur: () => handleBlur(field, true),\n };\n};\n\n/**\n * Creates props for a native file input bound to a form field.\n * Automatically handles single or multiple file selection based on the input's `multiple` attribute.\n * Works with: <input type=\"file\">\n *\n * When a file is selected:\n * - For single file inputs: field value is set to the File object or null if cleared\n * - For multiple file inputs: field value is set to an array of File objects or empty array if cleared\n *\n * Note: File values are not displayed in the returned props (file inputs are controlled differently).\n * Access the current file(s) via form.values[field].\n *\n * @param field - The path to the field in form values (supports dot notation and bracket notation)\n * @param _formValues - Current form values object (not used for file inputs)\n * @param handleChange - Function to update the field value (receives File, File[], or null) in form state\n * @param handleBlur - Function to mark the field as touched in form state\n * @returns Props object to spread onto native file input elements\n *\n * @example\n * // Single file upload\n * <input type=\"file\" accept=\"image/*\" {...form.getFileFieldProps(\"avatar\")} />\n * {form.values.avatar && <p>Selected: {form.values.avatar.name}</p>}\n *\n * @example\n * // Multiple file upload\n * <input type=\"file\" multiple accept=\".pdf,.doc,.docx\" {...form.getFileFieldProps(\"documents\")} />\n * {form.values.documents?.length > 0 && (\n * <ul>\n * {form.values.documents.map((file, i) => (\n * <li key={i}>{file.name} ({file.size} bytes)</li>\n * ))}\n * </ul>\n * )}\n *\n * @example\n * // File input with preview\n * <div>\n * <input type=\"file\" accept=\"image/*\" {...form.getFileFieldProps(\"profilePic\")} />\n * {form.values.profilePic && (\n * <img src={URL.createObjectURL(form.values.profilePic)} alt=\"Preview\" />\n * )}\n * </div>\n */\nexport const createNativeFileFieldProps = (\n field: FieldPath,\n _formValues: Record<string, unknown>,\n handleChange: (field: FieldPath, value: unknown) => void,\n handleBlur: (field: FieldPath, isTouched: boolean) => void\n): NativeFileFieldProps => {\n return {\n id: `field-${field.replace(/[[\\].]/g, '-')}`,\n name: field,\n onChange: (e: ChangeEvent<HTMLInputElement>) => {\n const input = e.target;\n const files = input.files;\n if (!files || files.length === 0) {\n handleChange(field, input.multiple ? [] : null);\n return;\n }\n handleChange(field, input.multiple ? Array.from(files) : files[0]!);\n },\n onBlur: () => handleBlur(field, true),\n };\n};\n\n/**\n * Creates props for a single radio button option within a radio group bound to a scalar form field.\n * Multiple radio buttons with the same field name form a group where only one can be selected.\n * Selecting a radio button sets the field value to that option's value.\n * Works with: multiple <input type=\"radio\"> elements sharing the same name attribute\n *\n * This is used for mutually exclusive choices, unlike checkbox groups where multiple can be selected.\n *\n * @param field - The path to the field in form values (supports dot notation and bracket notation)\n * @param optionValue - The value this radio button represents\n * @param formValues - Current form values object\n * @param handleChange - Function to update the field value in form state\n * @param handleBlur - Function to mark the field as touched in form state\n * @returns Props object to spread onto a radio input in a group\n *\n * @example\n * // Radio group for selecting a contact method\n * <div>\n * <label>\n * <input type=\"radio\" {...form.getRadioGroupOptionProps(\"contactMethod\", \"email\")} />\n * Email\n * </label>\n * <label>\n * <input type=\"radio\" {...form.getRadioGroupOptionProps(\"contactMethod\", \"phone\")} />\n * Phone\n * </label>\n * <label>\n * <input type=\"radio\" {...form.getRadioGroupOptionProps(\"contactMethod\", \"mail\")} />\n * Mail\n * </label>\n * </div>\n * // form.values.contactMethod = \"email\" when email is selected\n *\n * @example\n * // Dynamic radio group from data\n * {sizes.map(size => (\n * <label key={size.value}>\n * <input type=\"radio\" {...form.getRadioGroupOptionProps(\"size\", size.value)} />\n * {size.label}\n * </label>\n * ))}\n *\n * @example\n * // Radio group with descriptions\n * <div className=\"radio-group\">\n * <label>\n * <input type=\"radio\" {...form.getRadioGroupOptionProps(\"plan\", \"free\")} />\n * <span>Free Plan</span>\n * <small>Basic features for personal use</small>\n * </label>\n * <label>\n * <input type=\"radio\" {...form.getRadioGroupOptionProps(\"plan\", \"pro\")} />\n * <span>Pro Plan</span>\n * <small>Advanced features for professionals</small>\n * </label>\n * </div>\n */\nexport const createRadioGroupOptionProps = (\n field: FieldPath,\n optionValue: string | number,\n formValues: Record<string, unknown>,\n handleChange: (field: FieldPath, value: unknown) => void,\n handleBlur: (field: FieldPath, isTouched: boolean) => void\n): NativeRadioGroupOptionProps => {\n const current = getValueByPath(formValues, field);\n const checked = String(current) === String(optionValue);\n\n return {\n id: `field-${field.replace(/[[\\].]/g, '-')}-${String(optionValue)}`,\n name: field,\n value: optionValue,\n checked,\n onChange: (e: ChangeEvent<HTMLInputElement>) => {\n if (e.target.checked) handleChange(field, optionValue);\n },\n onBlur: () => handleBlur(field, true),\n };\n};\n","import {\n useReducer,\n useCallback,\n useMemo,\n useEffect,\n useRef,\n type FormEvent,\n} from 'react';\nimport { isErr, match, type Result } from '@railway-ts/pipelines/result';\nimport {\n validate,\n formatErrors,\n type Validator,\n type ValidationError,\n} from '@railway-ts/pipelines/schema';\nimport { formReducer } from './formReducer';\nimport { getValueByPath, setValueByPath, collectFieldPaths } from './utils';\nimport type {\n ArrayHelpers,\n ExtractFieldPaths,\n FieldPath,\n FormAction,\n NativeCheckboxProps,\n FormOptions,\n NativeSelectProps,\n NativeSliderProps,\n FormState,\n NativeSwitchProps,\n NativeFieldProps,\n GetArrayItemType,\n NativeFileFieldProps,\n NativeRadioGroupOptionProps,\n} from './types';\nimport { createArrayHelpers } from './arrayHelpersFactory';\nimport {\n createNativeCheckboxProps,\n createNativeSelectFieldProps,\n createNativeSliderProps,\n createNativeSwitchProps,\n createNativeFieldProps,\n createCheckboxGroupOptionProps,\n createNativeFileFieldProps,\n createRadioGroupOptionProps,\n} from './fieldPropsFactory';\n\n// =============================================================================\n// Main Hook\n// =============================================================================\n\n/**\n * A powerful React form hook that combines Railway-oriented validation with native HTML support.\n * Provides type-safe form state management, automatic validation, error handling, and direct\n * integration with native HTML form elements.\n *\n * This hook integrates with @railway-ts/pipelines for functional validation, supports multiple\n * validation modes (live, blur, mount, submit), manages both client and server errors, and\n * provides helpers for working with nested objects and dynamic arrays.\n *\n * @template TValues - The shape of form values as a record with string keys\n *\n * @param validator - Railway-oriented validator from @railway-ts/pipelines that validates form values\n * @param options - Configuration options for form behavior\n * @param options.initialValues - Initial values for form fields (used on mount and reset)\n * @param options.onSubmit - Callback invoked when form is submitted with valid data\n * @param options.validationMode - Controls when validation occurs: \"live\" | \"blur\" | \"mount\" | \"submit\"\n *\n * @returns An object containing:\n * **Form State:**\n * - `values` - Current form field values (Partial<TValues>)\n * - `touched` - Record of which fields have been interacted with\n * - `errors` - Combined client and server errors (server takes precedence)\n * - `clientErrors` - Validation errors from the validator function\n * - `serverErrors` - Manually set errors from server responses\n * - `isValid` - Whether the form has no validation errors\n * - `isDirty` - Whether any values have changed from initial state\n * - `isSubmitting` - Whether the form is currently being submitted\n *\n * **Field Management:**\n * - `setFieldValue(field, value, shouldValidate?)` - Update a single field\n * - `setFieldTouched(field, isTouched?, shouldValidate?)` - Mark field as touched\n * - `setValues(values, shouldValidate?)` - Update multiple fields at once\n *\n * **Server Error Management:**\n * - `setServerErrors(errors)` - Set server-side validation errors\n * - `clearServerErrors()` - Clear all server-side errors\n *\n * **Form Actions:**\n * - `handleSubmit(e?)` - Validate and submit the form\n * - `resetForm()` - Reset form to initial values and clear errors\n * - `validateForm(values)` - Manually trigger validation\n *\n * **Native HTML Integration:**\n * - `getFieldProps(field)` - Props for text inputs, email, textarea, etc.\n * - `getSelectFieldProps(field)` - Props for select elements\n * - `getCheckboxProps(field)` - Props for boolean checkboxes\n * - `getSwitchProps(field)` - Props for toggle switches\n * - `getSliderProps(field)` - Props for range inputs\n * - `getCheckboxGroupOptionProps(field, value)` - Props for checkbox groups (arrays)\n * - `getFileFieldProps(field)` - Props for file inputs\n * - `getRadioGroupOptionProps(field, value)` - Props for radio groups\n *\n * **Array Field Helpers:**\n * - `arrayHelpers(field)` - Get helpers for managing array fields (push, remove, swap, etc.)\n *\n * @example\n * // Basic usage with validation\n * const form = useForm(userValidator, {\n * initialValues: { name: \"\", email: \"\", age: 0 },\n * onSubmit: async (values) => {\n * await api.createUser(values);\n * },\n * validationMode: \"live\"\n * });\n *\n * @example\n * // Render with native HTML elements\n * <form onSubmit={form.handleSubmit}>\n * <input type=\"text\" {...form.getFieldProps(\"name\")} />\n * {form.touched.name && form.errors.name && <span>{form.errors.name}</span>}\n *\n * <input type=\"email\" {...form.getFieldProps(\"email\")} />\n * {form.touched.email && form.errors.email && <span>{form.errors.email}</span>}\n *\n * <button type=\"submit\" disabled={!form.isValid || form.isSubmitting}>\n * {form.isSubmitting ? \"Submitting...\" : \"Submit\"}\n * </button>\n * </form>\n *\n * @example\n * // Handle server errors\n * const form = useForm(userValidator, {\n * onSubmit: async (values) => {\n * const response = await api.createUser(values);\n * if (!response.ok) {\n * const errors = await response.json();\n * form.setServerErrors(errors);\n * }\n * }\n * });\n *\n * @example\n * // Working with arrays\n * const form = useForm(contactsValidator, {\n * initialValues: { contacts: [] }\n * });\n *\n * const contactsHelpers = form.arrayHelpers(\"contacts\");\n * return (\n * <div>\n * {contactsHelpers.values.map((_, index) => (\n * <div key={index}>\n * <input {...contactsHelpers.getFieldProps(index, \"name\")} />\n * <input {...contactsHelpers.getFieldProps(index, \"email\")} />\n * <button onClick={() => contactsHelpers.remove(index)}>Remove</button>\n * </div>\n * ))}\n * <button onClick={() => contactsHelpers.push({ name: \"\", email: \"\" })}>\n * Add Contact\n * </button>\n * </div>\n * );\n */\nexport const useForm = <TValues extends Record<string, unknown>>(\n validator: Validator<unknown, TValues>,\n options: FormOptions<TValues> = {}\n) => {\n const {\n initialValues = {} as Partial<TValues>,\n onSubmit,\n validationMode,\n } = options;\n\n // Derive behavior flags from validationMode\n const mode = validationMode ?? 'live';\n const validateOnChange = mode === 'live';\n const validateOnBlur = mode === 'live' || mode === 'blur';\n const validateOnMount = mode === 'mount';\n const touchOnChange = mode === 'live';\n\n // ===========================================================================\n // Reducer Setup\n // ===========================================================================\n\n // Create a memoized reducer that captures initialValues\n const reducerFn = useCallback(\n (state: FormState<TValues>, action: FormAction<TValues>) =>\n formReducer(state, action, initialValues),\n [initialValues]\n );\n\n // Initial state\n const initialState: FormState<TValues> = {\n values: initialValues,\n touched: {},\n clientErrors: {},\n serverErrors: {},\n isSubmitting: false,\n isDirty: false,\n };\n\n // Initialize the reducer\n const [formState, dispatch] = useReducer(reducerFn, initialState);\n\n // ===========================================================================\n // Computed State\n // ===========================================================================\n\n // Combined errors from both client and server\n const errors = useMemo(() => {\n const combined: Record<FieldPath, string> = {};\n\n // Add all server errors\n Object.entries(formState.serverErrors).forEach(([path, message]) => {\n combined[path] = message;\n });\n\n // Add client errors only if there's no server error for the same path\n Object.entries(formState.clientErrors).forEach(([path, message]) => {\n if (!combined[path]) {\n combined[path] = message;\n }\n });\n\n return combined;\n }, [formState.clientErrors, formState.serverErrors]);\n\n // Form is valid when there are no errors of any kind\n const isValid = useMemo(() => Object.keys(errors).length === 0, [errors]);\n\n // ===========================================================================\n // Validation Functions\n // ===========================================================================\n\n /**\n * Validates the current form values using the Railway-oriented validator and updates error state.\n * Returns a Result type that can be pattern-matched for success or failure.\n *\n * @param values - The form values to validate (usually form.values)\n * @returns Railway Result<TValues, ValidationError[]> - Ok with validated data or Err with errors\n *\n * @example\n * // Manually trigger validation\n * const result = form.validateForm(form.values);\n * if (isOk(result)) {\n * console.log(\"Form is valid!\", result.value);\n * }\n *\n * @example\n * // Validate before a custom action\n * const handleCustomAction = () => {\n * const result = form.validateForm(form.values);\n * if (isErr(result)) {\n * alert(\"Please fix validation errors first\");\n * return;\n * }\n * // Proceed with custom action\n * };\n */\n const validateForm = useCallback(\n (values: Partial<TValues>): Result<TValues, ValidationError[]> => {\n const validationResult = validate(values, validator);\n\n if (isErr(validationResult)) {\n dispatch({\n type: 'SET_CLIENT_ERRORS',\n errors: formatErrors(validationResult.error),\n });\n } else {\n dispatch({\n type: 'SET_CLIENT_ERRORS',\n errors: {},\n });\n }\n\n return validationResult;\n },\n [validator]\n );\n\n // Validate on mount if enabled\n const didMountRef = useRef(false);\n useEffect(() => {\n if (validateOnMount && !didMountRef.current) {\n didMountRef.current = true;\n validateForm(initialValues);\n\n // Also mark all fields as touched (including nested and array items)\n const allFields = collectFieldPaths(\n initialValues as Record<string, unknown>\n );\n dispatch({\n type: 'MARK_ALL_TOUCHED',\n fields: allFields,\n });\n }\n }, [initialValues, validateForm, validateOnMount]);\n\n // ===========================================================================\n // Field Management Functions\n // ===========================================================================\n\n /**\n * Updates a single field value and optionally triggers validation.\n * Automatically marks the field as touched (in \"live\" mode) and clears related server errors.\n *\n * @template TValue - The type of the value being set\n * @param field - The field path (supports dot notation and bracket notation)\n * @param value - The new value for the field\n * @param shouldValidate - Whether to trigger validation after update (default: depends on validationMode)\n *\n * @example\n * // Update a field programmatically\n * form.setFieldValue(\"email\", \"user@example.com\");\n *\n * @example\n * // Update without triggering validation\n * form.setFieldValue(\"username\", \"newuser\", false);\n *\n * @example\n * // Update nested field\n * form.setFieldValue(\"address.city\", \"San Francisco\");\n *\n * @example\n * // Use in a custom input handler\n * const handleCustomChange = (value: string) => {\n * const formatted = value.toUpperCase();\n * form.setFieldValue(\"code\", formatted);\n * };\n */\n const setFieldValue = useCallback(\n <TValue>(\n field: FieldPath,\n value: TValue,\n shouldValidate = validateOnChange\n ): void => {\n // Calculate updated values first\n const updatedValues = setValueByPath<Partial<TValues>, TValue>(\n formState.values,\n field,\n value\n );\n\n // Dispatch state update\n dispatch({\n type: 'SET_FIELD_VALUE',\n field,\n value,\n });\n\n // Mark touched on first change for immediate error visibility\n if (touchOnChange && !formState.touched[field]) {\n dispatch({ type: 'SET_FIELD_TOUCHED', field, isTouched: true });\n }\n\n // Validate with calculated values if needed\n if (shouldValidate) {\n validateForm(updatedValues);\n }\n },\n [\n formState.values,\n formState.touched,\n validateOnChange,\n validateForm,\n touchOnChange,\n ]\n );\n\n /**\n * Updates multiple field values simultaneously and optionally triggers validation.\n * More efficient than calling setFieldValue multiple times when updating several fields.\n * Automatically clears server errors for affected fields.\n *\n * @param newValues - Partial object containing the fields to update\n * @param shouldValidate - Whether to trigger validation after update (default: depends on validationMode)\n *\n * @example\n * // Update multiple fields at once\n * form.setValues({\n * firstName: \"John\",\n * lastName: \"Doe\",\n * email: \"john@example.com\"\n * });\n *\n * @example\n * // Update without validation\n * form.setValues({ theme: \"dark\", language: \"en\" }, false);\n *\n * @example\n * // Populate form from API response\n * const loadUser = async (id: string) => {\n * const user = await api.getUser(id);\n * form.setValues(user);\n * };\n */\n const setValues = useCallback(\n (newValues: Partial<TValues>, shouldValidate = validateOnChange): void => {\n dispatch({\n type: 'SET_VALUES',\n values: newValues,\n });\n\n if (shouldValidate) {\n // Need to get latest state for validation\n const updatedValues = { ...formState.values, ...newValues };\n validateForm(updatedValues);\n }\n },\n [formState.values, validateOnChange, validateForm]\n );\n\n /**\n * Marks a field as touched or untouched and optionally triggers validation.\n * Touched fields typically display their validation errors to the user.\n *\n * @param field - The field path to mark\n * @param isTouched - Whether the field should be marked as touched (default: true)\n * @param shouldValidate - Whether to trigger validation after update (default: depends on validationMode)\n *\n * @example\n * // Mark a field as touched (will show validation errors)\n * form.setFieldTouched(\"email\");\n *\n * @example\n * // Mark as untouched (hide validation errors)\n * form.setFieldTouched(\"password\", false);\n *\n * @example\n * // Use in custom blur handler\n * const handleCustomBlur = () => {\n * form.setFieldTouched(\"username\", true);\n * // Additional custom logic\n * };\n */\n const setFieldTouched = useCallback(\n (\n field: FieldPath,\n isTouched = true,\n shouldValidate = validateOnBlur\n ): void => {\n dispatch({\n type: 'SET_FIELD_TOUCHED',\n field,\n isTouched,\n });\n\n if (shouldValidate) {\n validateForm(formState.values);\n }\n },\n [formState.values, validateOnBlur, validateForm]\n );\n\n // ===========================================================================\n // Server Error Management\n // ===========================================================================\n\n /**\n * Sets server-side validation errors received from API responses.\n * These errors take precedence over client-side errors in the merged `errors` object.\n * Server errors are automatically cleared when the related field value changes.\n *\n * @param serverErrors - Map of field paths to error messages from server\n *\n * @example\n * // Handle server validation errors\n * const form = useForm(userValidator, {\n * onSubmit: async (values) => {\n * const response = await fetch(\"/api/users\", {\n * method: \"POST\",\n * body: JSON.stringify(values)\n * });\n *\n * if (!response.ok) {\n * const errors = await response.json();\n * form.setServerErrors({\n * \"email\": \"Email already taken\",\n * \"username\": \"Username not available\"\n * });\n * return;\n * }\n * }\n * });\n *\n * @example\n * // Set a single server error\n * form.setServerErrors({ \"email\": \"This email is already registered\" });\n */\n const setServerErrors = useCallback(\n (serverErrors: Record<FieldPath, string>): void => {\n dispatch({\n type: 'SET_SERVER_ERRORS',\n errors: serverErrors,\n });\n },\n []\n );\n\n /**\n * Clears all server-side validation errors.\n * Client-side validation errors are not affected.\n * Server errors are also automatically cleared when field values change.\n *\n * @example\n * // Clear server errors when user starts editing\n * const handleRetry = () => {\n * form.clearServerErrors();\n * // User can now resubmit\n * };\n *\n * @example\n * // Clear before resubmitting\n * const handleResubmit = () => {\n * form.clearServerErrors();\n * form.handleSubmit();\n * };\n */\n const clearServerErrors = useCallback((): void => {\n dispatch({\n type: 'CLEAR_SERVER_ERRORS',\n });\n }, []);\n\n // ===========================================================================\n // Form Action Functions\n // ===========================================================================\n\n /**\n * Handles form submission using the Railway-oriented programming pattern.\n * Validates all fields, marks them as touched, and calls onSubmit if validation passes.\n * Returns a Promise that resolves to either the validated data or validation errors.\n *\n * @param e - Optional form event (will preventDefault if provided)\n * @returns Promise<TValues | ValidationError[]> - Validated data on success, errors on failure\n *\n * @example\n * // Use in form element\n * <form onSubmit={form.handleSubmit}>\n * <input {...form.getFieldProps(\"email\")} />\n * <button type=\"submit\">Submit</button>\n * </form>\n *\n * @example\n * // Use in button click handler\n * <button onClick={form.handleSubmit}>\n * Save Changes\n * </button>\n *\n * @example\n * // Handle result programmatically\n * const handleSave = async () => {\n * const result = await form.handleSubmit();\n * if (Array.isArray(result)) {\n * // Validation failed, result is ValidationError[]\n * console.error(\"Validation errors:\", result);\n * } else {\n * // Success, result is TValues\n * console.log(\"Form submitted:\", result);\n * navigate(\"/success\");\n * }\n * };\n *\n * @example\n * // With loading state\n * const [isLoading, setIsLoading] = useState(false);\n * const handleSubmitWithLoading = async () => {\n * setIsLoading(true);\n * await form.handleSubmit();\n * setIsLoading(false);\n * };\n */\n const handleSubmit = useCallback(\n async (e?: FormEvent): Promise<TValues | ValidationError[]> => {\n if (e) {\n e.preventDefault();\n }\n\n // Mark all fields and error paths as touched (deep)\n const valuePaths = collectFieldPaths(\n formState.values as Record<string, unknown>\n );\n const allPaths = Array.from(\n new Set([\n ...valuePaths,\n ...Object.keys(formState.clientErrors),\n ...Object.keys(formState.serverErrors),\n ])\n );\n\n dispatch({\n type: 'MARK_ALL_TOUCHED',\n fields: allPaths,\n });\n\n dispatch({\n type: 'SET_SUBMITTING',\n isSubmitting: true,\n });\n\n // Clear any existing server errors\n dispatch({\n type: 'CLEAR_SERVER_ERRORS',\n });\n\n // Validate the form\n const validationResult = validate(formState.values, validator);\n\n // Handle result using Railway pattern\n return match<\n TValues,\n ValidationError[],\n Promise<TValues | ValidationError[]>\n >(validationResult, {\n ok: async (validData) => {\n if (onSubmit) {\n try {\n await onSubmit(validData);\n } catch (error) {\n console.error('Form submission error:', error);\n }\n }\n\n dispatch({\n type: 'SET_SUBMITTING',\n isSubmitting: false,\n });\n\n return validData;\n },\n err: async (errors) => {\n dispatch({\n type: 'SET_CLIENT_ERRORS',\n errors: formatErrors(errors),\n });\n\n dispatch({\n type: 'SET_SUBMITTING',\n isSubmitting: false,\n });\n\n return Promise.resolve(errors);\n },\n });\n },\n [\n formState.values,\n formState.clientErrors,\n formState.serverErrors,\n validator,\n onSubmit,\n ]\n );\n\n /**\n * Resets the form to its initial state.\n * Clears all values (back to initialValues), errors, and touched state.\n * If validationMode is \"mount\", triggers validation after reset.\n *\n * @example\n * // Reset after successful submission\n * const form = useForm(userValidator, {\n * onSubmit: async (values) => {\n * await api.createUser(values);\n * form.resetForm(); // Clear form after success\n * }\n * });\n *\n * @example\n * // Cancel button\n * <button type=\"button\" onClick={form.resetForm}>\n * Cancel\n * </button>\n *\n * @example\n * // Reset with confirmation\n * const handleReset = () => {\n * if (form.isDirty && !confirm(\"Discard changes?\")) {\n * return;\n * }\n * form.resetForm();\n * };\n */\n const resetForm = useCallback((): void => {\n dispatch({\n type: 'RESET_FORM',\n });\n\n if (validateOnMount) {\n validateForm(initialValues);\n }\n }, [initialValues, validateForm, validateOnMount]);\n\n // ===========================================================================\n // Native HTML Integration\n // ===========================================================================\n\n /**\n * Returns props to bind a native text input, email input, or textarea to a form field.\n * Provides type-safe autocomplete for valid field paths.\n * The returned object can be spread directly onto native HTML elements.\n *\n * @template TField - The field path type (auto-inferred with autocomplete)\n * @param field - The field path (with type-safe autocomplete)\n * @returns NativeFieldProps - Object with id, name, value, onChange, onBlur\n *\n * @example\n * // Text input\n * <input type=\"text\" {...form.getFieldProps(\"username\")} placeholder=\"Username\" />\n *\n * @example\n * // Email input\n * <input type=\"email\" {...form.getFieldProps(\"email\")} required />\n *\n * @example\n * // Textarea\n * <textarea {...form.getFieldProps(\"bio\")} rows={4} />\n *\n * @example\n * // Nested field\n * <input type=\"text\" {...form.getFieldProps(\"address.city\")} />\n */\n const getFieldProps = useCallback(\n <TField extends ExtractFieldPaths<TValues>>(\n field: TField\n ): NativeFieldProps => {\n return createNativeFieldProps(\n field as FieldPath,\n formState.values,\n setFieldValue,\n setFieldTouched\n );\n },\n [formState.values, setFieldValue, setFieldTouched]\n );\n\n /**\n * Returns props to bind a native select element to a form field.\n * Provides type-safe autocomplete for valid field paths.\n *\n * @template TField - The field path type (auto-inferred with autocomplete)\n * @param field - The field path (with type-safe autocomplete)\n * @returns NativeSelectProps - Object with id, name, value, onChange, onBlur\n *\n * @example\n * <select {...form.getSelectFieldProps(\"country\")}>\n * <option value=\"\">Select a country</option>\n * <option value=\"US\">United States</option>\n * <option value=\"CA\">Canada</option>\n * </select>\n */\n const getSelectFieldProps = useCallback(\n <TField extends ExtractFieldPaths<TValues>>(\n field: TField\n ): NativeSelectProps => {\n return createNativeSelectFieldProps(\n field as FieldPath,\n formState.values,\n setFieldValue,\n setFieldTouched\n );\n },\n [formState.values, setFieldValue, setFieldTouched]\n );\n\n /**\n * Returns props to bind a native checkbox input to a boolean form field.\n * Provides type-safe autocomplete for valid field paths.\n *\n * @template TField - The field path type (auto-inferred with autocomplete)\n * @param field - The field path (with type-safe autocomplete)\n * @returns NativeCheckboxProps - Object with id, name, checked, onChange, onBlur\n *\n * @example\n * <label>\n * <input type=\"checkbox\" {...form.getCheckboxProps(\"acceptTerms\")} />\n * I accept the terms and conditions\n * </label>\n */\n const getCheckboxProps = useCallback(\n <TField extends ExtractFieldPaths<TValues>>(\n field: TField\n ): NativeCheckboxProps => {\n return createNativeCheckboxProps(\n field as FieldPath,\n formState.values,\n setFieldValue,\n setFieldTouched\n );\n },\n [formState.values, setFieldValue, setFieldTouched]\n );\n\n /**\n * Returns props to bind a native switch (checkbox styled as toggle) to a boolean form field.\n * Provides type-safe autocomplete for valid field paths.\n *\n * @template TField - The field path type (auto-inferred with autocomplete)\n * @param field - The field path (with type-safe autocomplete)\n * @returns NativeSwitchProps - Object with id, name, checked, onChange, onBlur\n *\n * @example\n * <label className=\"switch\">\n * <input type=\"checkbox\" {...form.getSwitchProps(\"settings.darkMode\")} />\n * <span className=\"slider\"></span>\n * </label>\n */\n const getSwitchProps = useCallback(\n <TField extends ExtractFieldPaths<TValues>>(\n field: TField\n ): NativeSwitchProps => {\n return createNativeSwitchProps(\n field as FieldPath,\n formState.values,\n setFieldValue,\n setFieldTouched\n );\n },\n [formState.values, setFieldValue, setFieldTouched]\n );\n\n /**\n * Returns props to bind a native range input to a numeric form field.\n * Provides type-safe autocomplete for valid field paths.\n * Note: Native range inputs only support single numeric values, not arrays.\n *\n * @template TField - The field path type (auto-inferred with autocomplete)\n * @param field - The field path (with type-safe autocomplete)\n * @returns NativeSliderProps - Object with id, name, type, value, onChange, onBlur\n *\n * @example\n * <div>\n * <label>Volume: {form.values.volume}%</label>\n * <input type=\"range\" min={0} max={100} {...form.getSliderProps(\"volume\")} />\n * </div>\n */\n const getSliderProps = useCallback(\n <TField extends ExtractFieldPaths<TValues>>(\n field: TField\n ): NativeSliderProps => {\n return createNativeSliderProps(\n field as FieldPath,\n formState.values,\n setFieldValue,\n setFieldTouched\n );\n },\n [formState.values, setFieldValue, setFieldTouched]\n );\n\n /**\n * Returns props for a single checkbox within a checkbox group bound to an array field.\n * Checking the box adds the value to the array; unchecking removes it.\n * Provides type-safe autocomplete for valid field paths.\n *\n * @template TField - The field path type (auto-inferred with autocomplete)\n * @param field - The field path (with type-safe autocomplete)\n * @param optionValue - The value this checkbox represents\n * @returns NativeCheckboxGroupOptionProps - Object with id, name, value, checked, onChange, onBlur\n *\n * @example\n * <label>\n * <input type=\"checkbox\" {...form.getCheckboxGroupOptionProps(\"interests\", \"sports\")} />\n * Sports\n * </label>\n * <label>\n * <input type=\"checkbox\" {...form.getCheckboxGroupOptionProps(\"interests\", \"music\")} />\n * Music\n * </label>\n */\n const getCheckboxGroupOptionProps = useCallback(\n <TField extends ExtractFieldPaths<TValues>>(\n field: TField,\n optionValue: string | number\n ) => {\n return createCheckboxGroupOptionProps(\n field as FieldPath,\n optionValue,\n formState.values,\n setFieldValue,\n setFieldTouched\n );\n },\n [formState.values, setFieldValue, setFieldTouched]\n );\n\n /**\n * Returns props to bind a native file input to a form field.\n * Provides type-safe autocomplete for valid field paths.\n * Supports both single and multiple file selection.\n *\n * @template TField - The field path type (auto-inferred with autocomplete)\n * @param field - The field path (with type-safe autocomplete)\n * @returns NativeFileFieldProps - Object with id, name, onChange, onBlur\n *\n * @example\n * // Single file\n * <input type=\"file\" accept=\"image/*\" {...form.getFileFieldProps(\"avatar\")} />\n *\n * @example\n * // Multiple files\n * <input type=\"file\" multiple {...form.getFileFieldProps(\"documents\")} />\n */\n const getFileFieldProps = useCallback(\n <TField extends ExtractFieldPaths<TValues>>(\n field: TField\n ): NativeFileFieldProps => {\n return createNativeFileFieldProps(\n field as FieldPath,\n formState.values,\n setFieldValue,\n setFieldTouched\n );\n },\n [formState.values, setFieldValue, setFieldTouched]\n );\n\n /**\n * Returns props for a single radio button within a radio group bound to a scalar field.\n * Only one radio button in the group can be selected at a time.\n * Provides type-safe autocomplete for valid field paths.\n *\n * @template TField - The field path type (auto-inferred with autocomplete)\n * @param field - The field path (with type-safe autocomplete)\n * @param optionValue - The value this radio button represents\n * @returns NativeRadioGroupOptionProps - Object with id, name, value, checked, onChange, onBlur\n *\n * @example\n * <label>\n * <input type=\"radio\" {...form.getRadioGroupOptionProps(\"contactMethod\", \"email\")} />\n * Email\n * </label>\n * <label>\n * <input type=\"radio\" {...form.getRadioGroupOptionProps(\"contactMethod\", \"phone\")} />\n * Phone\n * </label>\n */\n const getRadioGroupOptionProps = useCallback(\n <TField extends ExtractFieldPaths<TValues>>(\n field: TField,\n optionValue: string | number\n ): NativeRadioGroupOptionProps => {\n return createRadioGroupOptionProps(\n field as FieldPath,\n optionValue,\n formState.values,\n setFieldValue,\n setFieldTouched\n );\n },\n [formState.values, setFieldValue, setFieldTouched]\n );\n\n // ===========================================================================\n // Array Field Helpers\n // ===========================================================================\n\n /**\n * Returns helper functions for managing array fields with type-safe operations.\n * Provides methods to add, remove, reorder, and bind HTML elements to array items.\n * Automatically infers item types and provides autocomplete for nested field paths.\n *\n * @template TItem - The type of items in the array (auto-inferred from field)\n * @param field - The path to the array field\n * @returns ArrayHelpers<TItem> - Object with array manipulation methods and field binding helpers\n *\n * @example\n * // Basic array operations\n * const form = useForm(contactsValidator, {\n * initialValues: { contacts: [] }\n * });\n * const helpers = form.arrayHelpers(\"contacts\");\n *\n * // Add new item\n * <button onClick={() => helpers.push({ name: \"\", email: \"\" })}>\n * Add Contact\n * </button>\n *\n * @example\n * // Render array items with field binding\n * const helpers = form.arrayHelpers(\"addresses\");\n * return (\n * <div>\n * {helpers.values.map((address, index) => (\n * <div key={index}>\n * <input {...helpers.getFieldProps(index, \"street\")} placeholder=\"Street\" />\n * <input {...helpers.getFieldProps(index, \"city\")} placeholder=\"City\" />\n * <button onClick={() => helpers.remove(index)}>Remove</button>\n * </div>\n * ))}\n * <button onClick={() => helpers.push({ street: \"\", city: \"\" })}>\n * Add Address\n * </button>\n * </div>\n * );\n *\n * @example\n * // Reorder items (drag and drop)\n * const handleMoveUp = (index: number) => {\n * if (index > 0) {\n * helpers.swap(index, index - 1);\n * }\n * };\n *\n * @example\n * // Replace an entire item\n * const handleUpdate = (index: number) => {\n * helpers.replace(index, { name: \"Updated\", email: \"new@example.com\" });\n * };\n */\n const arrayHelpersImpl = useCallback(\n <TItem = unknown>(\n field: string\n ): ArrayHelpers<TItem, ExtractFieldPaths<TItem>> => {\n // Local path-based wrappers to avoid generic casts\n const getFieldPropsAtPath = (path: string) =>\n createNativeFieldProps(\n path,\n formState.values,\n setFieldValue,\n setFieldTouched\n );\n\n const getSelectFieldPropsAtPath = (path: string) =>\n createNativeSelectFieldProps(\n path,\n formState.values,\n setFieldValue,\n setFieldTouched\n );\n\n const getSliderPropsAtPath = (path: string) =>\n createNativeSliderProps(\n path,\n formState.values,\n setFieldValue,\n setFieldTouched\n );\n\n const getCheckboxPropsAtPath = (path: string) =>\n createNativeCheckboxProps(\n path,\n formState.values,\n setFieldValue,\n setFieldTouched\n );\n\n const getSwitchPropsAtPath = (path: string) =>\n createNativeSwitchProps(\n path,\n formState.values,\n setFieldValue,\n setFieldTouched\n );\n\n const getFileFieldPropsAtPath = (path: string) =>\n createNativeFileFieldProps(\n path,\n formState.values,\n setFieldValue,\n setFieldTouched\n );\n\n const getRadioGroupOptionPropsAtPath = (\n path: string,\n opt: string | number\n ) =>\n createRadioGroupOptionProps(\n path,\n opt,\n formState.values,\n setFieldValue,\n setFieldTouched\n );\n\n const arrayValue =\n getValueByPath<Partial<TValues>, TItem[]>(formState.values, field) ||\n [];\n\n return createArrayHelpers<TItem, ExtractFieldPaths<TItem>>(\n field,\n arrayValue,\n setFieldValue,\n getFieldPropsAtPath,\n getSelectFieldPropsAtPath,\n getSliderPropsAtPath,\n getCheckboxPropsAtPath,\n getSwitchPropsAtPath,\n getFileFieldPropsAtPath,\n getRadioGroupOptionPropsAtPath\n );\n },\n [formState.values, setFieldValue, setFieldTouched]\n );\n\n // Overloaded wrapper for better type inference\n const arrayHelpers = arrayHelpersImpl as {\n <TField extends keyof TValues & string>(\n field: TField\n ): ArrayHelpers<\n GetArrayItemType<TValues, TField>,\n ExtractFieldPaths<GetArrayItemType<TValues, TField>>\n >;\n <TField extends ExtractFieldPaths<TValues>, TItem = unknown>(\n field: TField\n ): ArrayHelpers<TItem, ExtractFieldPaths<TItem>>;\n };\n\n // ===========================================================================\n // Return\n // ===========================================================================\n\n return {\n // Form state\n values: formState.values,\n touched: formState.touched,\n errors,\n clientErrors: formState.clientErrors,\n serverErrors: formState.serverErrors,\n isSubmitting: formState.isSubmitting,\n isValid,\n isDirty: formState.isDirty,\n\n // Field management\n setFieldValue,\n setFieldTouched,\n setValues,\n\n // Server error management\n setServerErrors,\n clearServerErrors,\n\n // Form actions\n handleSubmit,\n resetForm,\n validateForm,\n\n // Native HTML field integration\n getFieldProps,\n getSelectFieldProps,\n getCheckboxProps,\n getSwitchProps,\n getSliderProps,\n getCheckboxGroupOptionProps,\n getFileFieldProps,\n getRadioGroupOptionProps,\n\n // Array field helpers\n arrayHelpers,\n };\n};\n","import { useRef, useCallback, useEffect } from 'react';\n\n/**\n * A React hook that debounces a callback function, delaying its execution until after\n * a specified delay period has elapsed since the last time it was invoked.\n *\n * Useful for optimizing performance by limiting the rate at which a function is called,\n * such as in response to rapid user input or scroll events.\n *\n * @template T - The callback function type\n * @template Params - The parameter types of the callback function\n * @template Return - The return type of the callback function\n *\n * @param callback - The function to debounce\n * @param delay - The number of milliseconds to delay execution\n * @returns A debounced version of the callback function that can be called with the same parameters\n *\n * @example\n * // Debounce a search function\n * const debouncedSearch = useDebounce((query: string) => {\n * fetchSearchResults(query);\n * }, 300);\n *\n * @example\n * // Use in an input handler\n * const handleInputChange = useDebounce((value: string) => {\n * form.setFieldValue('search', value);\n * }, 500);\n */\nexport function useDebounce<\n T extends (...args: Params) => Return,\n Params extends unknown[] = Parameters<T>,\n Return = ReturnType<T>,\n>(callback: T, delay: number): (...args: Params) => void {\n const timeoutRef = useRef<ReturnType<typeof setTimeout> | null>(null);\n const callbackRef = useRef(callback);\n\n // Keep callback ref up-to-date\n useEffect(() => {\n callbackRef.current = callback;\n }, [callback]);\n\n // Cleanup timeout on unmount\n useEffect(() => {\n return () => {\n if (timeoutRef.current) {\n clearTimeout(timeoutRef.current);\n }\n };\n }, []);\n\n return useCallback(\n (...args: Params) => {\n if (timeoutRef.current) {\n clearTimeout(timeoutRef.current);\n }\n\n timeoutRef.current = setTimeout(() => {\n callbackRef.current(...args);\n }, delay);\n },\n [delay]\n );\n}\n","import { useRef, useEffect } from 'react';\n\nimport { useDebounce } from './useDebounce';\n\n/**\n * Represents the subset of form methods needed for auto-submission\n * @template T - The type of form values\n */\ntype FormWithAutoSubmit<T> = {\n values: Partial<T>;\n isDirty: boolean;\n isValid: boolean;\n validateForm: (values: T) => void;\n handleSubmit: () => void;\n};\n\n/**\n * A React hook that automatically submits a form when it becomes valid and dirty.\n * Useful for creating auto-save or live-update form experiences.\n *\n * The hook monitors form values and automatically triggers submission when:\n * 1. The form is dirty (has been modified)\n * 2. The form is valid (passes all validation rules)\n * 3. The values have changed since the last validation\n *\n * Submission is debounced to avoid excessive API calls during rapid user input.\n *\n * @template T - The type of form values\n *\n * @param form - A form object containing values, validation state, and submission methods\n * @param delay - The debounce delay in milliseconds before auto-submitting (default: 200ms)\n * @returns null (this hook only produces side effects)\n *\n * @example\n * // Auto-submit a preferences form\n * const form = useForm(preferencesSchema, {\n * initialValues: { theme: 'light', notifications: true },\n * onSubmit: async (values) => {\n * await updateUserPreferences(values);\n * }\n * });\n *\n * useFormAutoSubmission(form, 500);\n *\n * @example\n * // Auto-save a draft\n * const form = useForm(draftSchema, {\n * initialValues: draft,\n * onSubmit: saveDraft,\n * validationMode: \"live\"\n * });\n *\n * useFormAutoSubmission(form);\n */\nexport const useFormAutoSubmission = <T>(\n form: FormWithAutoSubmit<T>,\n delay = 200\n) => {\n const lastValidatedRef = useRef('');\n\n const debouncedSubmit = useDebounce(() => {\n if (form.isValid) form.handleSubmit();\n }, delay);\n\n useEffect(() => {\n if (!form.isDirty) return;\n\n const valuesString = JSON.stringify(form.values);\n if (valuesString === lastValidatedRef.current) return;\n\n lastValidatedRef.current = valuesString;\n form.validateForm(form.values as T);\n\n if (form.isValid) debouncedSubmit();\n }, [form.values, form.isDirty, form.isValid, debouncedSubmit, form]);\n\n return null;\n};\n"]}
|
package/package.json
CHANGED
package/dist/index.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/utils.ts","../src/formReducer.ts","../src/arrayHelpersFactory.ts","../src/fieldPropsFactory.ts","../src/useForm.ts","../src/useDebounce.ts","../src/useAutoSubmitForm.ts"],"names":["errors","useRef","useEffect","useCallback"],"mappings":"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","file":"index.js","sourcesContent":["import type { FieldPath } from './types';\n\n/**\n * Retrieves a value from a nested object using a path string.\n * Supports both dot notation for object properties and bracket notation for array indices.\n * Returns undefined if any part of the path doesn't exist.\n *\n * Internally normalizes bracket notation to dot notation (e.g., \"arr[0]\" → \"arr.0\")\n * and traverses the object tree to find the value.\n *\n * @template TObj - The object type to extract from\n * @template TValue - The expected return value type\n *\n * @param obj - The object to extract value from\n * @param path - Path to the value using dot or bracket notation\n * @returns The value at the path, or undefined if not found\n *\n * @example\n * // Simple dot notation\n * const user = { name: \"John\", age: 30 };\n * getValueByPath(user, \"name\"); // \"John\"\n *\n * @example\n * // Nested dot notation\n * const user = { address: { city: \"NYC\", zip: \"10001\" } };\n * getValueByPath(user, \"address.city\"); // \"NYC\"\n *\n * @example\n * // Bracket notation for arrays\n * const user = { contacts: [\"email@example.com\", \"phone@example.com\"] };\n * getValueByPath(user, \"contacts[0]\"); // \"email@example.com\"\n *\n * @example\n * // Combined notation for deeply nested structures\n * const user = { teams: [{ name: \"Engineering\", members: [{ name: \"Alice\" }] }] };\n * getValueByPath(user, \"teams[0].members[0].name\"); // \"Alice\"\n *\n * @example\n * // Missing path returns undefined\n * const user = { name: \"John\" };\n * getValueByPath(user, \"address.city\"); // undefined\n */\nexport const getValueByPath = <\n TObj extends Record<string, unknown>,\n TValue = unknown,\n>(\n obj: TObj,\n path: FieldPath\n): TValue | undefined => {\n if (!path) return obj as unknown as TValue;\n\n const normalizedPath = path.replace(/\\[(\\d+)\\]/g, '.$1');\n const parts = normalizedPath.split('.').filter(Boolean);\n\n let current: unknown = obj;\n for (const part of parts) {\n if (current == null) return undefined;\n current = (current as Record<string, unknown>)[part];\n }\n\n return current as TValue | undefined;\n};\n\n/**\n * Sets a value in a nested object using a path string, returning a new object.\n * Creates intermediate objects and arrays as needed without mutating the original.\n * All updates are performed immutably using spreading.\n *\n * Internally normalizes bracket notation to dot notation and determines whether\n * to create objects or arrays based on whether the next path segment is numeric.\n *\n * @template TObj - The object type to update\n * @template TValue - The value type to set\n *\n * @param obj - The source object to set value in (not mutated)\n * @param path - Path to the value using dot or bracket notation\n * @param value - The value to set at the path\n * @returns A new object with the updated value\n *\n * @example\n * // Update existing nested property\n * const user = { name: \"John\", address: { city: \"NYC\" } };\n * const updated = setValueByPath(user, \"address.city\", \"San Francisco\");\n * // updated = { name: \"John\", address: { city: \"San Francisco\" } }\n * // user is unchanged (immutable)\n *\n * @example\n * // Create missing intermediate objects\n * const user = { name: \"John\" };\n * const updated = setValueByPath(user, \"address.city\", \"NYC\");\n * // updated = { name: \"John\", address: { city: \"NYC\" } }\n *\n * @example\n * // Update array element\n * const user = { contacts: [\"old@example.com\"] };\n * const updated = setValueByPath(user, \"contacts[0]\", \"new@example.com\");\n * // updated = { contacts: [\"new@example.com\"] }\n *\n * @example\n * // Create missing arrays and nested properties\n * const user = {};\n * const updated = setValueByPath(user, \"teams[0].name\", \"Engineering\");\n * // updated = { teams: [{ name: \"Engineering\" }] }\n *\n * @example\n * // Deep nested update\n * const form = { users: [{ address: { city: \"NYC\" } }] };\n * const updated = setValueByPath(form, \"users[0].address.zip\", \"10001\");\n * // updated = { users: [{ address: { city: \"NYC\", zip: \"10001\" } }] }\n */\nexport const setValueByPath = <TObj extends Record<string, unknown>, TValue>(\n obj: TObj,\n path: FieldPath,\n value: TValue\n): TObj => {\n if (!path) return value as unknown as TObj;\n\n const normalizedPath = path.replace(/\\[(\\d+)\\]/g, '.$1');\n const parts = normalizedPath.split('.').filter(Boolean);\n\n // Clone the root (array/object)\n const result: unknown = Array.isArray(obj)\n ? [...(obj as unknown[])]\n : { ...obj };\n let currNew: Record<string, unknown> | unknown[] = Array.isArray(result)\n ? (result as unknown[])\n : (result as Record<string, unknown>);\n let currOld: unknown = obj;\n\n for (let i = 0; i < parts.length; i++) {\n const keyStr = parts[i]!;\n const isIndex = /^\\d+$/.test(keyStr);\n const key: number | string = isIndex ? Number(keyStr) : keyStr;\n\n if (i === parts.length - 1) {\n // Final set\n if (Array.isArray(currNew) && typeof key === 'number') {\n currNew[key] = value as unknown;\n } else if (!Array.isArray(currNew) && typeof key === 'string') {\n currNew[key] = value as unknown;\n }\n break;\n }\n\n // Prepare next container\n let nextOld: unknown = undefined;\n if (currOld != null && typeof currOld === 'object') {\n if (Array.isArray(currOld) && typeof key === 'number') {\n nextOld = (currOld as unknown[])[key];\n } else if (!Array.isArray(currOld) && typeof key === 'string') {\n nextOld = (currOld as Record<string, unknown>)[key];\n }\n }\n let nextNew: Record<string, unknown> | unknown[];\n\n if (nextOld == null) {\n // Create missing container based on the next segment\n const nextIsIndex = /^\\d+$/.test(parts[i + 1] ?? '');\n nextNew = nextIsIndex ? [] : {};\n } else {\n nextNew = Array.isArray(nextOld)\n ? [...(nextOld as unknown[])]\n : { ...(nextOld as Record<string, unknown>) };\n }\n\n if (Array.isArray(currNew) && typeof key === 'number') {\n currNew[key] = nextNew;\n } else if (!Array.isArray(currNew) && typeof key === 'string') {\n currNew[key] = nextNew;\n }\n\n currNew = nextNew;\n currOld = nextOld ?? (Array.isArray(nextNew) ? [] : {});\n }\n\n return result as TObj;\n};\n\n/**\n * Checks if a field path is affected by changes to another path.\n * Used internally for determining which errors to clear when a field value changes.\n *\n * A path is considered affected if:\n * 1. It exactly matches the change path\n * 2. The change path is a parent of the path (e.g., \"address\" affects \"address.city\")\n *\n * Paths are normalized before comparison so bracket notation is handled correctly.\n *\n * @param path - The path to check if affected (e.g., error path)\n * @param changePath - The path that was changed (e.g., field that was updated)\n * @returns True if the path is affected by the change, false otherwise\n *\n * @example\n * // Exact match\n * isPathAffected(\"email\", \"email\"); // true\n *\n * @example\n * // Parent affects child\n * isPathAffected(\"address.city\", \"address\"); // true\n * isPathAffected(\"address.city\", \"address.city\"); // true\n *\n * @example\n * // Child does not affect parent\n * isPathAffected(\"address\", \"address.city\"); // false\n *\n * @example\n * // Unrelated paths\n * isPathAffected(\"address.city\", \"name\"); // false\n *\n * @example\n * // Array notation (normalized internally)\n * isPathAffected(\"contacts[0].email\", \"contacts\"); // true\n * isPathAffected(\"contacts[0].email\", \"contacts[0]\"); // true\n * isPathAffected(\"contacts[0].email\", \"contacts[1]\"); // false\n *\n * @example\n * // Practical use case: clearing server errors\n * const serverErrors = {\n * \"address.city\": \"City is required\",\n * \"address.zip\": \"Invalid ZIP\"\n * };\n * // When user updates \"address\", both errors should be cleared\n * Object.keys(serverErrors).filter(path => isPathAffected(path, \"address\"));\n * // Returns [\"address.city\", \"address.zip\"]\n */\nexport const isPathAffected = (\n path: FieldPath,\n changePath: FieldPath\n): boolean => {\n if (path === changePath) return true;\n\n const normalizedPath = path.replace(/\\[(\\d+)\\]/g, '.$1');\n const normalizedChangePath = changePath.replace(/\\[(\\d+)\\]/g, '.$1');\n\n // Parent affects child\n return (\n normalizedPath === normalizedChangePath ||\n normalizedPath.startsWith(`${normalizedChangePath}.`)\n );\n};\n\n/**\n * Recursively collects all field paths from a nested object structure.\n * Traverses the entire object tree and generates path strings for every field,\n * including intermediate parent paths, nested objects, and array elements.\n *\n * Useful for operations that need to touch all fields in a form, such as:\n * - Marking all fields as touched on form submission\n * - Collecting all error paths for validation\n * - Iterating over all form values\n *\n * Leaf values (primitives, Date, RegExp, null, undefined) are treated as terminal nodes.\n * Arrays are traversed with bracket notation, objects with dot notation.\n *\n * @param obj - The object to collect paths from (typically form values)\n * @param prefix - Internal parameter for recursion, starting path prefix (default: \"\")\n * @returns Array of all field paths found in the object\n *\n * @example\n * // Simple object\n * const user = { name: \"John\", age: 30 };\n * collectFieldPaths(user);\n * // Returns: [\"name\", \"age\"]\n *\n * @example\n * // Nested object\n * const user = { name: \"John\", address: { city: \"NYC\", zip: \"10001\" } };\n * collectFieldPaths(user);\n * // Returns: [\"name\", \"address\", \"address.city\", \"address.zip\"]\n * // Note: \"address\" is included as a parent path\n *\n * @example\n * // Arrays with objects\n * const form = { contacts: [{ email: \"a@example.com\" }, { email: \"b@example.com\" }] };\n * collectFieldPaths(form);\n * // Returns: [\"contacts\", \"contacts[0]\", \"contacts[0].email\", \"contacts[1]\", \"contacts[1].email\"]\n *\n * @example\n * // Mixed nesting\n * const form = {\n * user: { name: \"John\" },\n * tags: [\"react\", \"typescript\"]\n * };\n * collectFieldPaths(form);\n * // Returns: [\"user\", \"user.name\", \"tags\", \"tags[0]\", \"tags[1]\"]\n *\n * @example\n * // Practical use: marking all fields as touched on submit\n * const handleSubmit = () => {\n * const allPaths = collectFieldPaths(form.values);\n * allPaths.forEach(path => form.setFieldTouched(path, true));\n * // Now all validation errors will be visible\n * };\n *\n * @example\n * // Leaf values (Date, null) are treated as terminals\n * const form = { createdAt: new Date(), deletedAt: null };\n * collectFieldPaths(form);\n * // Returns: [\"createdAt\", \"deletedAt\"]\n * // Does not try to traverse into Date or null\n */\nexport const collectFieldPaths = (obj: unknown, prefix = ''): FieldPath[] => {\n const paths: FieldPath[] = [];\n\n const isLeaf = (v: unknown) =>\n v == null ||\n typeof v !== 'object' ||\n v instanceof Date ||\n v instanceof RegExp;\n\n const visit = (value: unknown, path: string) => {\n if (path) paths.push(path);\n\n if (isLeaf(value)) return;\n\n if (Array.isArray(value)) {\n value.forEach((item, i) => visit(item, `${path}[${i}]`));\n return;\n }\n\n const entries = Object.entries(value as Record<string, unknown>);\n for (const [k, v] of entries) {\n const childPath = path ? `${path}.${k}` : k;\n visit(v, childPath);\n }\n };\n\n visit(obj, prefix);\n return paths;\n};\n","import type { FieldPath, FormAction, FormState } from './types';\nimport { isPathAffected, setValueByPath } from './utils';\n\n/**\n * Reducer function for form state management using the Redux-style reducer pattern.\n * Handles all form state transitions in an immutable, predictable way.\n *\n * This reducer processes various actions that modify form state including:\n * - Field value updates (single or batch)\n * - Touch state tracking (marking fields as interacted with)\n * - Client-side validation errors\n * - Server-side validation errors\n * - Form submission state\n * - Form reset to initial values\n *\n * All state updates are performed immutably - the reducer always returns a new state object\n * rather than mutating the existing state. Server errors are automatically cleared when\n * related fields are modified to provide a smooth user experience.\n *\n * @template TValues - The type of form values being managed\n *\n * @param state - The current form state before the action is applied\n * @param action - The action to perform (e.g., SET_FIELD_VALUE, SET_CLIENT_ERRORS, RESET_FORM)\n * @param initialValues - Initial form values used when resetting the form\n * @returns A new form state object reflecting the changes from the action\n *\n * @example\n * // Used internally by useForm hook with useReducer\n * const reducerFn = useCallback(\n * (state: FormState<TValues>, action: FormAction<TValues>) =>\n * formReducer(state, action, initialValues),\n * [initialValues]\n * );\n * const [formState, dispatch] = useReducer(reducerFn, initialState);\n *\n * @example\n * // Dispatching a field value change\n * dispatch({\n * type: \"SET_FIELD_VALUE\",\n * field: \"email\",\n * value: \"user@example.com\"\n * });\n *\n * @example\n * // Dispatching validation errors\n * dispatch({\n * type: \"SET_CLIENT_ERRORS\",\n * errors: { email: \"Invalid email format\", password: \"Too short\" }\n * });\n *\n * @example\n * // Marking all fields as touched on submit\n * dispatch({\n * type: \"MARK_ALL_TOUCHED\",\n * fields: [\"name\", \"email\", \"password\"]\n * });\n */\nexport const formReducer = <TValues extends Record<string, unknown>>(\n state: FormState<TValues>,\n action: FormAction<TValues>,\n initialValues: Partial<TValues>\n): FormState<TValues> => {\n switch (action.type) {\n case 'SET_FIELD_VALUE': {\n const newValues = setValueByPath(\n state.values,\n action.field,\n action.value\n );\n\n const newServerErrors = { ...state.serverErrors };\n Object.keys(newServerErrors).forEach((errorPath) => {\n if (isPathAffected(errorPath, action.field)) {\n delete newServerErrors[errorPath];\n }\n });\n\n return {\n ...state,\n values: newValues,\n serverErrors: newServerErrors,\n isDirty: true,\n };\n }\n\n case 'SET_VALUES': {\n const newServerErrors = { ...state.serverErrors };\n Object.keys(action.values).forEach((field) => {\n Object.keys(newServerErrors).forEach((errorPath) => {\n if (isPathAffected(errorPath, field)) {\n delete newServerErrors[errorPath];\n }\n });\n });\n\n return {\n ...state,\n values: { ...state.values, ...action.values },\n serverErrors: newServerErrors,\n isDirty: true,\n };\n }\n\n case 'SET_FIELD_TOUCHED':\n return {\n ...state,\n touched: {\n ...state.touched,\n [action.field]: action.isTouched,\n },\n };\n\n case 'SET_CLIENT_ERRORS':\n return {\n ...state,\n clientErrors: action.errors,\n };\n\n case 'SET_SERVER_ERRORS':\n return {\n ...state,\n serverErrors: action.errors,\n };\n\n case 'CLEAR_SERVER_ERRORS':\n return {\n ...state,\n serverErrors: {},\n };\n\n case 'SET_SUBMITTING':\n return {\n ...state,\n isSubmitting: action.isSubmitting,\n };\n\n case 'RESET_FORM':\n return {\n values: initialValues,\n touched: {},\n clientErrors: {},\n serverErrors: {},\n isSubmitting: false,\n isDirty: false,\n };\n\n case 'MARK_ALL_TOUCHED': {\n const allTouched: Record<FieldPath, boolean> = {};\n action.fields.forEach((path) => {\n allTouched[path] = true;\n });\n\n return {\n ...state,\n touched: {\n ...state.touched,\n ...allTouched,\n },\n };\n }\n\n default:\n return state;\n }\n};\n","import type {\n ArrayHelpers,\n ExtractFieldPaths,\n FieldPath,\n NativeSelectProps,\n NativeSliderProps,\n NativeFieldProps,\n NativeCheckboxProps,\n NativeSwitchProps,\n NativeFileFieldProps,\n NativeRadioGroupOptionProps,\n} from './types';\n\n/**\n * Factory function that creates an ArrayHelpers object for managing array fields in forms.\n * Provides type-safe methods to add, remove, update, and reorder array items, as well as\n * bind native HTML elements to fields within array items.\n *\n * This is typically called internally by the useForm hook's arrayHelpers() method\n * and not used directly by consumers.\n *\n * @template TItem - The type of items stored in the array\n * @template TFieldPaths - Union of valid field paths for the item type\n *\n * @param field - The path to the array field in the form\n * @param arrayValue - The current array values\n * @param setFieldValue - Function to update a field value in the form\n * @param getFieldProps - Function to get props for native text inputs\n * @param getSelectFieldProps - Function to get props for native select elements\n * @param getSliderProps - Function to get props for native range inputs\n * @param getCheckboxProps - Function to get props for native checkboxes\n * @param getSwitchProps - Function to get props for native switches\n * @param getFileFieldProps - Function to get props for native file inputs\n * @param getRadioGroupOptionProps - Function to get props for radio group options\n * @returns An ArrayHelpers object with methods for array manipulation and field binding\n *\n * @example\n * // Used internally by useForm\n * const contactsHelpers = form.arrayHelpers(\"contacts\");\n * contactsHelpers.push({ name: \"\", email: \"\" });\n * contactsHelpers.remove(0);\n *\n * @example\n * // Accessing nested fields in array items\n * const helpers = form.arrayHelpers(\"addresses\");\n * return helpers.values.map((_, index) => (\n * <input {...helpers.getFieldProps(index, \"street\")} />\n * ));\n */\nexport const createArrayHelpers = <\n TItem = unknown,\n TFieldPaths extends string = ExtractFieldPaths<TItem>,\n>(\n field: FieldPath,\n arrayValue: TItem[],\n setFieldValue: (field: FieldPath, value: unknown) => void,\n getFieldProps: (field: string) => NativeFieldProps,\n getSelectFieldProps: (field: string) => NativeSelectProps,\n getSliderProps: (field: string) => NativeSliderProps,\n getCheckboxProps: (field: string) => NativeCheckboxProps,\n getSwitchProps: (field: string) => NativeSwitchProps,\n getFileFieldProps: (field: string) => NativeFileFieldProps,\n getRadioGroupOptionProps: (\n field: string,\n optionValue: string | number\n ) => NativeRadioGroupOptionProps\n): ArrayHelpers<TItem, TFieldPaths> => {\n return {\n /**\n * The current array of values for this field.\n * Use this to iterate over items when rendering the form.\n *\n * @example\n * // Render array items\n * helpers.values.map((contact, index) => (\n * <div key={index}>\n * <input {...helpers.getFieldProps(index, \"name\")} />\n * </div>\n * ))\n */\n values: arrayValue,\n\n /**\n * Adds a new item to the end of the array.\n * The form state is updated immutably and all subscribed components re-render.\n *\n * @param value - The item to add to the array\n *\n * @example\n * // Add a new contact\n * const helpers = form.arrayHelpers(\"contacts\");\n * helpers.push({ name: \"\", email: \"\", phone: \"\" });\n */\n push: (value: TItem) => {\n const newArray = [...arrayValue, value];\n setFieldValue(field, newArray);\n },\n\n /**\n * Removes an item at the specified index from the array.\n * If the index is out of bounds, no action is taken.\n * The form state is updated immutably.\n *\n * @param index - The zero-based index of the item to remove\n *\n * @example\n * // Remove the second contact\n * const helpers = form.arrayHelpers(\"contacts\");\n * helpers.remove(1);\n */\n remove: (index: number) => {\n if (index < 0 || index >= arrayValue.length) return;\n const newArray = [...arrayValue];\n newArray.splice(index, 1);\n setFieldValue(field, newArray);\n },\n\n /**\n * Inserts an item at the specified index in the array.\n * Items at and after the index are shifted to the right.\n * If the index is out of bounds, it's clamped to valid range [0, length].\n *\n * @param index - The zero-based insertion position\n * @param value - The item to insert\n *\n * @example\n * // Insert a contact at the beginning\n * const helpers = form.arrayHelpers(\"contacts\");\n * helpers.insert(0, { name: \"New Contact\", email: \"\", phone: \"\" });\n */\n insert: (index: number, value: TItem) => {\n const clamped = Math.max(0, Math.min(index, arrayValue.length));\n const newArray = [...arrayValue];\n newArray.splice(clamped, 0, value);\n setFieldValue(field, newArray);\n },\n\n /**\n * Swaps the positions of two items in the array.\n * If either index is out of bounds or they are equal, no action is taken.\n * Useful for drag-and-drop reordering interfaces.\n *\n * @param indexA - The zero-based index of the first item\n * @param indexB - The zero-based index of the second item\n *\n * @example\n * // Swap first and second contacts\n * const helpers = form.arrayHelpers(\"contacts\");\n * helpers.swap(0, 1);\n *\n * @example\n * // Move item up in list\n * const moveUp = (index: number) => {\n * if (index > 0) helpers.swap(index, index - 1);\n * };\n */\n swap: (indexA: number, indexB: number) => {\n if (\n indexA === indexB ||\n indexA < 0 ||\n indexB < 0 ||\n indexA >= arrayValue.length ||\n indexB >= arrayValue.length\n ) {\n return;\n }\n const newArray = [...arrayValue];\n\n const a = newArray[indexA];\n const b = newArray[indexB];\n if (a === undefined || b === undefined) {\n return;\n }\n\n newArray[indexA] = b;\n newArray[indexB] = a;\n setFieldValue(field, newArray);\n },\n\n /**\n * Replaces an entire item at the specified index with a new value.\n * If the index is out of bounds, no action is taken.\n *\n * @param index - The zero-based index of the item to replace\n * @param value - The new item value\n *\n * @example\n * // Replace a contact entirely\n * const helpers = form.arrayHelpers(\"contacts\");\n * helpers.replace(0, { name: \"John Doe\", email: \"john@example.com\", phone: \"555-0100\" });\n */\n replace: (index: number, value: TItem) => {\n if (index < 0 || index >= arrayValue.length) return;\n const newArray = [...arrayValue];\n newArray[index] = value;\n setFieldValue(field, newArray);\n },\n\n /**\n * Gets props for a native text input bound to a field within an array item.\n * Provides type-safe field path autocomplete for nested fields.\n * Works with: <input type=\"text\">, <input type=\"email\">, <textarea>, etc.\n *\n * @param index - The zero-based index of the array item\n * @param subField - The field path within the array item (type-safe and autocompleted)\n * @returns Props object to spread onto a native input element\n *\n * @example\n * // Text input for contact name\n * helpers.values.map((_, index) => (\n * <input type=\"text\" {...helpers.getFieldProps(index, \"name\")} />\n * ))\n */\n getFieldProps: (index: number, subField: TFieldPaths) => {\n const path = `${field}[${index}].${subField}`;\n return getFieldProps(path);\n },\n\n /**\n * Gets props for a native select element bound to a field within an array item.\n * Provides type-safe field path autocomplete for nested fields.\n * Works with: <select>\n *\n * @param index - The zero-based index of the array item\n * @param subField - The field path within the array item (type-safe and autocompleted)\n * @returns Props object to spread onto a native select element\n *\n * @example\n * // Select for contact type\n * <select {...helpers.getSelectFieldProps(index, \"type\")}>\n * <option value=\"work\">Work</option>\n * <option value=\"personal\">Personal</option>\n * </select>\n */\n getSelectFieldProps: (index: number, subField: TFieldPaths) => {\n const path = `${field}[${index}].${subField}`;\n return getSelectFieldProps(path);\n },\n\n /**\n * Gets props for a native range input bound to a field within an array item.\n * Provides type-safe field path autocomplete for nested fields.\n * Works with: <input type=\"range\">\n *\n * @param index - The zero-based index of the array item\n * @param subField - The field path within the array item (type-safe and autocompleted)\n * @returns Props object to spread onto a native range input element\n *\n * @example\n * // Range slider for priority\n * <input type=\"range\" min={0} max={10} {...helpers.getSliderProps(index, \"priority\")} />\n */\n getSliderProps: (index: number, subField: TFieldPaths) => {\n const path = `${field}[${index}].${subField}`;\n return getSliderProps(path);\n },\n\n /**\n * Gets props for a native checkbox bound to a field within an array item.\n * Provides type-safe field path autocomplete for nested fields.\n * Works with: <input type=\"checkbox\">\n *\n * @param index - The zero-based index of the array item\n * @param subField - The field path within the array item (type-safe and autocompleted)\n * @returns Props object to spread onto a native checkbox input\n *\n * @example\n * // Checkbox for marking contact as favorite\n * <input type=\"checkbox\" {...helpers.getCheckboxProps(index, \"isFavorite\")} />\n */\n getCheckboxProps: (index: number, subField: TFieldPaths) => {\n const path = `${field}[${index}].${subField}`;\n return getCheckboxProps(path);\n },\n\n /**\n * Gets props for a native switch (checkbox styled as switch) bound to a field within an array item.\n * Provides type-safe field path autocomplete for nested fields.\n * Works with: <input type=\"checkbox\"> (styled as switch via CSS)\n *\n * @param index - The zero-based index of the array item\n * @param subField - The field path within the array item (type-safe and autocompleted)\n * @returns Props object to spread onto a native checkbox input\n *\n * @example\n * // Switch for enabling/disabling a feature\n * <label className=\"switch\">\n * <input type=\"checkbox\" {...helpers.getSwitchProps(index, \"enabled\")} />\n * <span className=\"slider\"></span>\n * </label>\n */\n getSwitchProps: (index: number, subField: TFieldPaths) => {\n const path = `${field}[${index}].${subField}`;\n return getSwitchProps(path);\n },\n\n /**\n * Gets props for a native file input bound to a field within an array item.\n * Provides type-safe field path autocomplete for nested fields.\n * Works with: <input type=\"file\">\n *\n * @param index - The zero-based index of the array item\n * @param subField - The field path within the array item (type-safe and autocompleted)\n * @returns Props object to spread onto a native file input\n *\n * @example\n * // File input for contact avatar\n * <input type=\"file\" accept=\"image/*\" {...helpers.getFileFieldProps(index, \"avatar\")} />\n */\n getFileFieldProps: (index: number, subField: TFieldPaths) => {\n const path = `${field}[${index}].${subField}`;\n return getFileFieldProps(path);\n },\n\n /**\n * Gets props for a radio group option bound to a field within an array item.\n * Provides type-safe field path autocomplete for nested fields.\n * Works with: multiple <input type=\"radio\"> elements sharing the same name\n *\n * @param index - The zero-based index of the array item\n * @param subField - The field path within the array item (type-safe and autocompleted)\n * @param optionValue - The value this radio option represents\n * @returns Props object to spread onto a native radio input\n *\n * @example\n * // Radio group for contact method preference\n * <label>\n * <input type=\"radio\" {...helpers.getRadioGroupOptionProps(index, \"preferredMethod\", \"email\")} />\n * Email\n * </label>\n * <label>\n * <input type=\"radio\" {...helpers.getRadioGroupOptionProps(index, \"preferredMethod\", \"phone\")} />\n * Phone\n * </label>\n */\n getRadioGroupOptionProps: (\n index: number,\n subField: TFieldPaths,\n optionValue: string | number\n ) => {\n const path = `${field}[${index}].${subField}`;\n return getRadioGroupOptionProps(path, optionValue);\n },\n };\n};\n","import type { ChangeEvent } from 'react';\nimport type {\n FieldPath,\n NativeFieldProps,\n NativeSelectProps,\n NativeCheckboxProps,\n NativeSwitchProps,\n NativeSliderProps,\n NativeCheckboxGroupOptionProps,\n NativeFileFieldProps,\n NativeRadioGroupOptionProps,\n} from './types';\nimport { getValueByPath } from './utils';\n\n// =============================================================================\n// Native HTML Field Props Factories\n// =============================================================================\n\n/**\n * Creates props for a native text input element bound to a form field.\n * Automatically handles value normalization, change events, and blur tracking.\n * Works with: <input type=\"text\">, <input type=\"email\">, <input type=\"date\">, <textarea>, etc.\n *\n * The returned props include id, name, value, onChange, and onBlur handlers that\n * are pre-configured to work with the form state management system.\n *\n * @param field - The path to the field in form values (supports dot notation and bracket notation)\n * @param formValues - Current form values object\n * @param handleChange - Function to update the field value in form state\n * @param handleBlur - Function to mark the field as touched in form state\n * @returns Props object to spread onto native text input elements\n *\n * @example\n * // Native text input with placeholder\n * <input type=\"text\" {...form.getFieldProps(\"username\")} placeholder=\"Username\" />\n *\n * @example\n * // Native email input\n * <input type=\"email\" {...form.getFieldProps(\"email\")} />\n *\n * @example\n * // Native textarea\n * <textarea {...form.getFieldProps(\"bio\")} rows={4} />\n *\n * @example\n * // Nested field path\n * <input type=\"text\" {...form.getFieldProps(\"address.city\")} />\n *\n * @example\n * // Date input (values are auto-converted to/from ISO format)\n * <input type=\"date\" {...form.getFieldProps(\"birthDate\")} />\n */\nexport const createNativeFieldProps = (\n field: FieldPath,\n formValues: Record<string, unknown>,\n handleChange: (field: FieldPath, value: unknown) => void,\n handleBlur: (field: FieldPath, isTouched: boolean) => void\n): NativeFieldProps => {\n const raw = getValueByPath(formValues, field);\n\n // Normalize to string or number for native inputs\n const value = (\n raw == null\n ? ''\n : typeof raw === 'string' || typeof raw === 'number'\n ? raw\n : raw instanceof Date\n ? isNaN(raw.getTime())\n ? ''\n : raw.toISOString().split('T')[0]\n : JSON.stringify(raw)\n ) as string | number;\n\n return {\n id: `field-${field.replace(/[[\\].]/g, '-')}`,\n name: field,\n value,\n onChange: (e: ChangeEvent<HTMLInputElement | HTMLTextAreaElement>) => {\n // For date inputs, clearing sets value to '' until a valid date is chosen\n // We forward the raw string and let validation handle emptiness/format.\n handleChange(field, e.target.value);\n },\n onBlur: () => handleBlur(field, true),\n };\n};\n\n/**\n * Creates props for a native select element bound to a form field.\n * Automatically handles value normalization, change events, and blur tracking.\n * Works with: <select> (single selection only, not multiple)\n *\n * The returned props include id, name, value, onChange, and onBlur handlers that\n * are pre-configured to work with the form state management system.\n *\n * @param field - The path to the field in form values (supports dot notation and bracket notation)\n * @param formValues - Current form values object\n * @param handleChange - Function to update the field value in form state\n * @param handleBlur - Function to mark the field as touched in form state\n * @returns Props object to spread onto native select elements\n *\n * @example\n * // Native select with default option\n * <select {...form.getSelectFieldProps(\"role\")}>\n * <option value=\"\">Select a role…</option>\n * <option value=\"user\">User</option>\n * <option value=\"admin\">Admin</option>\n * </select>\n *\n * @example\n * // Select with nested field path\n * <select {...form.getSelectFieldProps(\"address.country\")}>\n * <option value=\"US\">United States</option>\n * <option value=\"CA\">Canada</option>\n * <option value=\"UK\">United Kingdom</option>\n * </select>\n *\n * @example\n * // Select with dynamic options\n * <select {...form.getSelectFieldProps(\"category\")}>\n * {categories.map(cat => (\n * <option key={cat.id} value={cat.id}>{cat.name}</option>\n * ))}\n * </select>\n */\nexport const createNativeSelectFieldProps = (\n field: FieldPath,\n formValues: Record<string, unknown>,\n handleChange: (field: FieldPath, value: unknown) => void,\n handleBlur: (field: FieldPath, isTouched: boolean) => void\n): NativeSelectProps => {\n const raw = getValueByPath(formValues, field);\n\n // Native select expects primitive value\n const value =\n raw == null\n ? ''\n : typeof raw === 'string' || typeof raw === 'number'\n ? raw\n : JSON.stringify(raw);\n\n return {\n id: `field-${field.replace(/[[\\].]/g, '-')}`,\n name: field,\n value,\n onChange: (e: ChangeEvent<HTMLSelectElement>) =>\n handleChange(field, e.target.value),\n onBlur: () => handleBlur(field, true),\n };\n};\n\n/**\n * Creates props for a native checkbox input bound to a boolean form field.\n * The checkbox is checked when the field value is truthy, unchecked when falsy.\n * Automatically handles checked state, change events, and blur tracking.\n * Works with: <input type=\"checkbox\">\n *\n * Note: For checkbox groups (multiple checkboxes bound to an array), use\n * getCheckboxGroupOptionProps instead.\n *\n * @param field - The path to the field in form values (supports dot notation and bracket notation)\n * @param formValues - Current form values object\n * @param handleChange - Function to update the field value (receives boolean) in form state\n * @param handleBlur - Function to mark the field as touched in form state\n * @returns Props object to spread onto native checkbox inputs\n *\n * @example\n * // Simple checkbox for boolean field\n * <label>\n * <input type=\"checkbox\" {...form.getCheckboxProps(\"acceptTerms\")} />\n * I accept the terms and conditions\n * </label>\n *\n * @example\n * // Nested field path\n * <label>\n * <input type=\"checkbox\" {...form.getCheckboxProps(\"preferences.newsletter\")} />\n * Subscribe to newsletter\n * </label>\n *\n * @example\n * // With accessible labeling\n * <div>\n * <input type=\"checkbox\" {...form.getCheckboxProps(\"agreeToPolicy\")} />\n * <label htmlFor={form.getCheckboxProps(\"agreeToPolicy\").id}>\n * I agree to the privacy policy\n * </label>\n * </div>\n */\nexport const createNativeCheckboxProps = (\n field: FieldPath,\n formValues: Record<string, unknown>,\n handleChange: (field: FieldPath, value: unknown) => void,\n handleBlur: (field: FieldPath, isTouched: boolean) => void\n): NativeCheckboxProps => {\n const value = getValueByPath(formValues, field);\n\n return {\n id: `field-${field.replace(/[[\\].]/g, '-')}`,\n name: field,\n checked: !!value,\n onChange: (e: ChangeEvent<HTMLInputElement>) =>\n handleChange(field, e.target.checked),\n onBlur: () => handleBlur(field, true),\n };\n};\n\n/**\n * Creates props for a native switch input bound to a boolean form field.\n * Semantically identical to checkbox, but typically styled as a toggle switch via CSS.\n * The switch is \"on\" when the field value is truthy, \"off\" when falsy.\n * Works with: <input type=\"checkbox\"> (styled as switch via CSS)\n *\n * This is functionally the same as createNativeCheckboxProps but exists as a separate\n * method to clarify the semantic intent when building toggle switch UIs.\n *\n * @param field - The path to the field in form values (supports dot notation and bracket notation)\n * @param formValues - Current form values object\n * @param handleChange - Function to update the field value (receives boolean) in form state\n * @param handleBlur - Function to mark the field as touched in form state\n * @returns Props object to spread onto native checkbox inputs styled as switches\n *\n * @example\n * // Native checkbox styled as switch\n * <label className=\"switch\">\n * <input type=\"checkbox\" {...form.getSwitchProps(\"settings.darkMode\")} />\n * <span className=\"slider\"></span>\n * </label>\n *\n * @example\n * // Switch with label\n * <div className=\"setting-row\">\n * <label htmlFor={form.getSwitchProps(\"notifications.enabled\").id}>\n * Enable Notifications\n * </label>\n * <input type=\"checkbox\" {...form.getSwitchProps(\"notifications.enabled\")} className=\"toggle-switch\" />\n * </div>\n *\n * @example\n * // Multiple switches for feature flags\n * <input type=\"checkbox\" {...form.getSwitchProps(\"features.experimentalUI\")} />\n * <input type=\"checkbox\" {...form.getSwitchProps(\"features.betaFeatures\")} />\n */\nexport const createNativeSwitchProps = (\n field: FieldPath,\n formValues: Record<string, unknown>,\n handleChange: (field: FieldPath, value: unknown) => void,\n handleBlur: (field: FieldPath, isTouched: boolean) => void\n): NativeSwitchProps => {\n const value = getValueByPath(formValues, field);\n\n return {\n id: `field-${field.replace(/[[\\].]/g, '-')}`,\n name: field,\n checked: !!value,\n onChange: (e: ChangeEvent<HTMLInputElement>) =>\n handleChange(field, e.target.checked),\n onBlur: () => handleBlur(field, true),\n };\n};\n\n/**\n * Creates props for a native range input bound to a numeric form field.\n * Automatically handles value normalization, change events, and blur tracking.\n * Works with: <input type=\"range\">\n *\n * Note: Native range inputs only support single numeric values, not arrays.\n * For multi-thumb sliders or more complex range inputs, use a UI library adapter.\n * If the field value is an array, only the first element is used.\n *\n * @param field - The path to the field in form values (supports dot notation and bracket notation)\n * @param formValues - Current form values object\n * @param handleChange - Function to update the field value (receives number) in form state\n * @param handleBlur - Function to mark the field as touched in form state\n * @returns Props object to spread onto native range input elements\n *\n * @example\n * // Basic range input with value display\n * <div>\n * <input\n * type=\"range\"\n * min={0}\n * max={100}\n * {...form.getSliderProps(\"settings.volume\")}\n * />\n * <span>{form.values.settings?.volume}%</span>\n * </div>\n *\n * @example\n * // Range with step for decimal values\n * <input\n * type=\"range\"\n * min={0}\n * max={1}\n * step={0.1}\n * {...form.getSliderProps(\"opacity\")}\n * />\n *\n * @example\n * // Age slider with min/max and labels\n * <label htmlFor={form.getSliderProps(\"age\").id}>Age: {form.values.age}</label>\n * <input type=\"range\" min={18} max={100} {...form.getSliderProps(\"age\")} />\n */\nexport const createNativeSliderProps = (\n field: FieldPath,\n formValues: Record<string, unknown>,\n handleChange: (field: FieldPath, value: unknown) => void,\n handleBlur: (field: FieldPath, isTouched: boolean) => void\n): NativeSliderProps => {\n const raw = getValueByPath(formValues, field);\n\n const toNumber = (v: unknown): number =>\n typeof v === 'string' ? Number(v || 0) : typeof v === 'number' ? v : 0;\n\n // Native range only supports single values, not arrays\n const value = Array.isArray(raw) ? toNumber(raw[0]) : toNumber(raw);\n\n return {\n id: `field-${field.replace(/[[\\].]/g, '-')}`,\n name: field,\n type: 'range',\n value,\n onChange: (e: ChangeEvent<HTMLInputElement>) =>\n handleChange(field, Number(e.target.value)),\n onBlur: () => handleBlur(field, true),\n };\n};\n\n/**\n * Creates props for a single checkbox option within a checkbox group bound to an array field.\n * Each checkbox toggles the presence of its value in the array field.\n * Checking adds the value to the array; unchecking removes it.\n * Works with: multiple <input type=\"checkbox\"> elements bound to the same array field\n *\n * This is different from createNativeCheckboxProps, which is for single boolean checkboxes.\n *\n * @param field - The path to the array field in form values\n * @param optionValue - The value this checkbox represents (added/removed from array)\n * @param formValues - Current form values object\n * @param handleChange - Function to update the array field value in form state\n * @param handleBlur - Function to mark the field as touched in form state\n * @returns Props object to spread onto a checkbox input in a group\n *\n * @example\n * // Multiple checkboxes for selecting interests (array field)\n * <label>\n * <input type=\"checkbox\" {...form.getCheckboxGroupOptionProps(\"interests\", \"sports\")} />\n * Sports\n * </label>\n * <label>\n * <input type=\"checkbox\" {...form.getCheckboxGroupOptionProps(\"interests\", \"music\")} />\n * Music\n * </label>\n * <label>\n * <input type=\"checkbox\" {...form.getCheckboxGroupOptionProps(\"interests\", \"travel\")} />\n * Travel\n * </label>\n * // form.values.interests = [\"sports\", \"music\"] when both are checked\n *\n * @example\n * // Dynamic checkbox group from data\n * {permissions.map(permission => (\n * <label key={permission.id}>\n * <input type=\"checkbox\" {...form.getCheckboxGroupOptionProps(\"userPermissions\", permission.id)} />\n * {permission.name}\n * </label>\n * ))}\n */\nexport const createCheckboxGroupOptionProps = (\n field: FieldPath,\n optionValue: string | number,\n formValues: Record<string, unknown>,\n handleChange: (field: FieldPath, value: unknown) => void,\n handleBlur: (field: FieldPath, isTouched: boolean) => void\n): NativeCheckboxGroupOptionProps => {\n const raw = getValueByPath(formValues, field);\n const current = Array.isArray(raw)\n ? (raw as (string | number)[])\n : ([] as (string | number)[]);\n const isChecked = current.some((v) => String(v) === String(optionValue));\n\n return {\n id: `field-${field.replace(/[[\\].]/g, '-')}-${String(optionValue)}`,\n name: field,\n value: optionValue,\n checked: isChecked,\n onChange: (e: ChangeEvent<HTMLInputElement>) => {\n if (e.target.checked) {\n if (!current.some((v) => String(v) === String(optionValue))) {\n handleChange(field, [...current, optionValue]);\n }\n } else {\n const next = current.filter((v) => String(v) !== String(optionValue));\n handleChange(field, next);\n }\n },\n onBlur: () => handleBlur(field, true),\n };\n};\n\n/**\n * Creates props for a native file input bound to a form field.\n * Automatically handles single or multiple file selection based on the input's `multiple` attribute.\n * Works with: <input type=\"file\">\n *\n * When a file is selected:\n * - For single file inputs: field value is set to the File object or null if cleared\n * - For multiple file inputs: field value is set to an array of File objects or empty array if cleared\n *\n * Note: File values are not displayed in the returned props (file inputs are controlled differently).\n * Access the current file(s) via form.values[field].\n *\n * @param field - The path to the field in form values (supports dot notation and bracket notation)\n * @param _formValues - Current form values object (not used for file inputs)\n * @param handleChange - Function to update the field value (receives File, File[], or null) in form state\n * @param handleBlur - Function to mark the field as touched in form state\n * @returns Props object to spread onto native file input elements\n *\n * @example\n * // Single file upload\n * <input type=\"file\" accept=\"image/*\" {...form.getFileFieldProps(\"avatar\")} />\n * {form.values.avatar && <p>Selected: {form.values.avatar.name}</p>}\n *\n * @example\n * // Multiple file upload\n * <input type=\"file\" multiple accept=\".pdf,.doc,.docx\" {...form.getFileFieldProps(\"documents\")} />\n * {form.values.documents?.length > 0 && (\n * <ul>\n * {form.values.documents.map((file, i) => (\n * <li key={i}>{file.name} ({file.size} bytes)</li>\n * ))}\n * </ul>\n * )}\n *\n * @example\n * // File input with preview\n * <div>\n * <input type=\"file\" accept=\"image/*\" {...form.getFileFieldProps(\"profilePic\")} />\n * {form.values.profilePic && (\n * <img src={URL.createObjectURL(form.values.profilePic)} alt=\"Preview\" />\n * )}\n * </div>\n */\nexport const createNativeFileFieldProps = (\n field: FieldPath,\n _formValues: Record<string, unknown>,\n handleChange: (field: FieldPath, value: unknown) => void,\n handleBlur: (field: FieldPath, isTouched: boolean) => void\n): NativeFileFieldProps => {\n return {\n id: `field-${field.replace(/[[\\].]/g, '-')}`,\n name: field,\n onChange: (e: ChangeEvent<HTMLInputElement>) => {\n const input = e.target;\n const files = input.files;\n if (!files || files.length === 0) {\n handleChange(field, input.multiple ? [] : null);\n return;\n }\n handleChange(field, input.multiple ? Array.from(files) : files[0]!);\n },\n onBlur: () => handleBlur(field, true),\n };\n};\n\n/**\n * Creates props for a single radio button option within a radio group bound to a scalar form field.\n * Multiple radio buttons with the same field name form a group where only one can be selected.\n * Selecting a radio button sets the field value to that option's value.\n * Works with: multiple <input type=\"radio\"> elements sharing the same name attribute\n *\n * This is used for mutually exclusive choices, unlike checkbox groups where multiple can be selected.\n *\n * @param field - The path to the field in form values (supports dot notation and bracket notation)\n * @param optionValue - The value this radio button represents\n * @param formValues - Current form values object\n * @param handleChange - Function to update the field value in form state\n * @param handleBlur - Function to mark the field as touched in form state\n * @returns Props object to spread onto a radio input in a group\n *\n * @example\n * // Radio group for selecting a contact method\n * <div>\n * <label>\n * <input type=\"radio\" {...form.getRadioGroupOptionProps(\"contactMethod\", \"email\")} />\n * Email\n * </label>\n * <label>\n * <input type=\"radio\" {...form.getRadioGroupOptionProps(\"contactMethod\", \"phone\")} />\n * Phone\n * </label>\n * <label>\n * <input type=\"radio\" {...form.getRadioGroupOptionProps(\"contactMethod\", \"mail\")} />\n * Mail\n * </label>\n * </div>\n * // form.values.contactMethod = \"email\" when email is selected\n *\n * @example\n * // Dynamic radio group from data\n * {sizes.map(size => (\n * <label key={size.value}>\n * <input type=\"radio\" {...form.getRadioGroupOptionProps(\"size\", size.value)} />\n * {size.label}\n * </label>\n * ))}\n *\n * @example\n * // Radio group with descriptions\n * <div className=\"radio-group\">\n * <label>\n * <input type=\"radio\" {...form.getRadioGroupOptionProps(\"plan\", \"free\")} />\n * <span>Free Plan</span>\n * <small>Basic features for personal use</small>\n * </label>\n * <label>\n * <input type=\"radio\" {...form.getRadioGroupOptionProps(\"plan\", \"pro\")} />\n * <span>Pro Plan</span>\n * <small>Advanced features for professionals</small>\n * </label>\n * </div>\n */\nexport const createRadioGroupOptionProps = (\n field: FieldPath,\n optionValue: string | number,\n formValues: Record<string, unknown>,\n handleChange: (field: FieldPath, value: unknown) => void,\n handleBlur: (field: FieldPath, isTouched: boolean) => void\n): NativeRadioGroupOptionProps => {\n const current = getValueByPath(formValues, field);\n const checked = String(current) === String(optionValue);\n\n return {\n id: `field-${field.replace(/[[\\].]/g, '-')}-${String(optionValue)}`,\n name: field,\n value: optionValue,\n checked,\n onChange: (e: ChangeEvent<HTMLInputElement>) => {\n if (e.target.checked) handleChange(field, optionValue);\n },\n onBlur: () => handleBlur(field, true),\n };\n};\n","import {\n useReducer,\n useCallback,\n useMemo,\n useEffect,\n useRef,\n type FormEvent,\n} from 'react';\nimport { isErr, match, type Result } from '@railway-ts/pipelines/result';\nimport {\n validate,\n formatErrors,\n type Validator,\n type ValidationError,\n} from '@railway-ts/pipelines/schema';\nimport { formReducer } from './formReducer';\nimport { getValueByPath, setValueByPath, collectFieldPaths } from './utils';\nimport type {\n ArrayHelpers,\n ExtractFieldPaths,\n FieldPath,\n FormAction,\n NativeCheckboxProps,\n FormOptions,\n NativeSelectProps,\n NativeSliderProps,\n FormState,\n NativeSwitchProps,\n NativeFieldProps,\n GetArrayItemType,\n NativeFileFieldProps,\n NativeRadioGroupOptionProps,\n} from './types';\nimport { createArrayHelpers } from './arrayHelpersFactory';\nimport {\n createNativeCheckboxProps,\n createNativeSelectFieldProps,\n createNativeSliderProps,\n createNativeSwitchProps,\n createNativeFieldProps,\n createCheckboxGroupOptionProps,\n createNativeFileFieldProps,\n createRadioGroupOptionProps,\n} from './fieldPropsFactory';\n\n// =============================================================================\n// Main Hook\n// =============================================================================\n\n/**\n * A powerful React form hook that combines Railway-oriented validation with native HTML support.\n * Provides type-safe form state management, automatic validation, error handling, and direct\n * integration with native HTML form elements.\n *\n * This hook integrates with @railway-ts/pipelines for functional validation, supports multiple\n * validation modes (live, blur, mount, submit), manages both client and server errors, and\n * provides helpers for working with nested objects and dynamic arrays.\n *\n * @template TValues - The shape of form values as a record with string keys\n *\n * @param validator - Railway-oriented validator from @railway-ts/pipelines that validates form values\n * @param options - Configuration options for form behavior\n * @param options.initialValues - Initial values for form fields (used on mount and reset)\n * @param options.onSubmit - Callback invoked when form is submitted with valid data\n * @param options.validationMode - Controls when validation occurs: \"live\" | \"blur\" | \"mount\" | \"submit\"\n *\n * @returns An object containing:\n * **Form State:**\n * - `values` - Current form field values (Partial<TValues>)\n * - `touched` - Record of which fields have been interacted with\n * - `errors` - Combined client and server errors (server takes precedence)\n * - `clientErrors` - Validation errors from the validator function\n * - `serverErrors` - Manually set errors from server responses\n * - `isValid` - Whether the form has no validation errors\n * - `isDirty` - Whether any values have changed from initial state\n * - `isSubmitting` - Whether the form is currently being submitted\n *\n * **Field Management:**\n * - `setFieldValue(field, value, shouldValidate?)` - Update a single field\n * - `setFieldTouched(field, isTouched?, shouldValidate?)` - Mark field as touched\n * - `setValues(values, shouldValidate?)` - Update multiple fields at once\n *\n * **Server Error Management:**\n * - `setServerErrors(errors)` - Set server-side validation errors\n * - `clearServerErrors()` - Clear all server-side errors\n *\n * **Form Actions:**\n * - `handleSubmit(e?)` - Validate and submit the form\n * - `resetForm()` - Reset form to initial values and clear errors\n * - `validateForm(values)` - Manually trigger validation\n *\n * **Native HTML Integration:**\n * - `getFieldProps(field)` - Props for text inputs, email, textarea, etc.\n * - `getSelectFieldProps(field)` - Props for select elements\n * - `getCheckboxProps(field)` - Props for boolean checkboxes\n * - `getSwitchProps(field)` - Props for toggle switches\n * - `getSliderProps(field)` - Props for range inputs\n * - `getCheckboxGroupOptionProps(field, value)` - Props for checkbox groups (arrays)\n * - `getFileFieldProps(field)` - Props for file inputs\n * - `getRadioGroupOptionProps(field, value)` - Props for radio groups\n *\n * **Array Field Helpers:**\n * - `arrayHelpers(field)` - Get helpers for managing array fields (push, remove, swap, etc.)\n *\n * @example\n * // Basic usage with validation\n * const form = useForm(userValidator, {\n * initialValues: { name: \"\", email: \"\", age: 0 },\n * onSubmit: async (values) => {\n * await api.createUser(values);\n * },\n * validationMode: \"live\"\n * });\n *\n * @example\n * // Render with native HTML elements\n * <form onSubmit={form.handleSubmit}>\n * <input type=\"text\" {...form.getFieldProps(\"name\")} />\n * {form.touched.name && form.errors.name && <span>{form.errors.name}</span>}\n *\n * <input type=\"email\" {...form.getFieldProps(\"email\")} />\n * {form.touched.email && form.errors.email && <span>{form.errors.email}</span>}\n *\n * <button type=\"submit\" disabled={!form.isValid || form.isSubmitting}>\n * {form.isSubmitting ? \"Submitting...\" : \"Submit\"}\n * </button>\n * </form>\n *\n * @example\n * // Handle server errors\n * const form = useForm(userValidator, {\n * onSubmit: async (values) => {\n * const response = await api.createUser(values);\n * if (!response.ok) {\n * const errors = await response.json();\n * form.setServerErrors(errors);\n * }\n * }\n * });\n *\n * @example\n * // Working with arrays\n * const form = useForm(contactsValidator, {\n * initialValues: { contacts: [] }\n * });\n *\n * const contactsHelpers = form.arrayHelpers(\"contacts\");\n * return (\n * <div>\n * {contactsHelpers.values.map((_, index) => (\n * <div key={index}>\n * <input {...contactsHelpers.getFieldProps(index, \"name\")} />\n * <input {...contactsHelpers.getFieldProps(index, \"email\")} />\n * <button onClick={() => contactsHelpers.remove(index)}>Remove</button>\n * </div>\n * ))}\n * <button onClick={() => contactsHelpers.push({ name: \"\", email: \"\" })}>\n * Add Contact\n * </button>\n * </div>\n * );\n */\nexport const useForm = <TValues extends Record<string, unknown>>(\n validator: Validator<unknown, TValues>,\n options: FormOptions<TValues> = {}\n) => {\n const {\n initialValues = {} as Partial<TValues>,\n onSubmit,\n validationMode,\n } = options;\n\n // Derive behavior flags from validationMode\n const mode = validationMode ?? 'live';\n const validateOnChange = mode === 'live';\n const validateOnBlur = mode === 'live' || mode === 'blur';\n const validateOnMount = mode === 'mount';\n const touchOnChange = mode === 'live';\n\n // ===========================================================================\n // Reducer Setup\n // ===========================================================================\n\n // Create a memoized reducer that captures initialValues\n const reducerFn = useCallback(\n (state: FormState<TValues>, action: FormAction<TValues>) =>\n formReducer(state, action, initialValues),\n [initialValues]\n );\n\n // Initial state\n const initialState: FormState<TValues> = {\n values: initialValues,\n touched: {},\n clientErrors: {},\n serverErrors: {},\n isSubmitting: false,\n isDirty: false,\n };\n\n // Initialize the reducer\n const [formState, dispatch] = useReducer(reducerFn, initialState);\n\n // ===========================================================================\n // Computed State\n // ===========================================================================\n\n // Combined errors from both client and server\n const errors = useMemo(() => {\n const combined: Record<FieldPath, string> = {};\n\n // Add all server errors\n Object.entries(formState.serverErrors).forEach(([path, message]) => {\n combined[path] = message;\n });\n\n // Add client errors only if there's no server error for the same path\n Object.entries(formState.clientErrors).forEach(([path, message]) => {\n if (!combined[path]) {\n combined[path] = message;\n }\n });\n\n return combined;\n }, [formState.clientErrors, formState.serverErrors]);\n\n // Form is valid when there are no errors of any kind\n const isValid = useMemo(() => Object.keys(errors).length === 0, [errors]);\n\n // ===========================================================================\n // Validation Functions\n // ===========================================================================\n\n /**\n * Validates the current form values using the Railway-oriented validator and updates error state.\n * Returns a Result type that can be pattern-matched for success or failure.\n *\n * @param values - The form values to validate (usually form.values)\n * @returns Railway Result<TValues, ValidationError[]> - Ok with validated data or Err with errors\n *\n * @example\n * // Manually trigger validation\n * const result = form.validateForm(form.values);\n * if (isOk(result)) {\n * console.log(\"Form is valid!\", result.value);\n * }\n *\n * @example\n * // Validate before a custom action\n * const handleCustomAction = () => {\n * const result = form.validateForm(form.values);\n * if (isErr(result)) {\n * alert(\"Please fix validation errors first\");\n * return;\n * }\n * // Proceed with custom action\n * };\n */\n const validateForm = useCallback(\n (values: Partial<TValues>): Result<TValues, ValidationError[]> => {\n const validationResult = validate(values, validator);\n\n if (isErr(validationResult)) {\n dispatch({\n type: 'SET_CLIENT_ERRORS',\n errors: formatErrors(validationResult.error),\n });\n } else {\n dispatch({\n type: 'SET_CLIENT_ERRORS',\n errors: {},\n });\n }\n\n return validationResult;\n },\n [validator]\n );\n\n // Validate on mount if enabled\n const didMountRef = useRef(false);\n useEffect(() => {\n if (validateOnMount && !didMountRef.current) {\n didMountRef.current = true;\n validateForm(initialValues);\n\n // Also mark all fields as touched (including nested and array items)\n const allFields = collectFieldPaths(\n initialValues as Record<string, unknown>\n );\n dispatch({\n type: 'MARK_ALL_TOUCHED',\n fields: allFields,\n });\n }\n }, [initialValues, validateForm, validateOnMount]);\n\n // ===========================================================================\n // Field Management Functions\n // ===========================================================================\n\n /**\n * Updates a single field value and optionally triggers validation.\n * Automatically marks the field as touched (in \"live\" mode) and clears related server errors.\n *\n * @template TValue - The type of the value being set\n * @param field - The field path (supports dot notation and bracket notation)\n * @param value - The new value for the field\n * @param shouldValidate - Whether to trigger validation after update (default: depends on validationMode)\n *\n * @example\n * // Update a field programmatically\n * form.setFieldValue(\"email\", \"user@example.com\");\n *\n * @example\n * // Update without triggering validation\n * form.setFieldValue(\"username\", \"newuser\", false);\n *\n * @example\n * // Update nested field\n * form.setFieldValue(\"address.city\", \"San Francisco\");\n *\n * @example\n * // Use in a custom input handler\n * const handleCustomChange = (value: string) => {\n * const formatted = value.toUpperCase();\n * form.setFieldValue(\"code\", formatted);\n * };\n */\n const setFieldValue = useCallback(\n <TValue>(\n field: FieldPath,\n value: TValue,\n shouldValidate = validateOnChange\n ): void => {\n // Calculate updated values first\n const updatedValues = setValueByPath<Partial<TValues>, TValue>(\n formState.values,\n field,\n value\n );\n\n // Dispatch state update\n dispatch({\n type: 'SET_FIELD_VALUE',\n field,\n value,\n });\n\n // Mark touched on first change for immediate error visibility\n if (touchOnChange && !formState.touched[field]) {\n dispatch({ type: 'SET_FIELD_TOUCHED', field, isTouched: true });\n }\n\n // Validate with calculated values if needed\n if (shouldValidate) {\n validateForm(updatedValues);\n }\n },\n [\n formState.values,\n formState.touched,\n validateOnChange,\n validateForm,\n touchOnChange,\n ]\n );\n\n /**\n * Updates multiple field values simultaneously and optionally triggers validation.\n * More efficient than calling setFieldValue multiple times when updating several fields.\n * Automatically clears server errors for affected fields.\n *\n * @param newValues - Partial object containing the fields to update\n * @param shouldValidate - Whether to trigger validation after update (default: depends on validationMode)\n *\n * @example\n * // Update multiple fields at once\n * form.setValues({\n * firstName: \"John\",\n * lastName: \"Doe\",\n * email: \"john@example.com\"\n * });\n *\n * @example\n * // Update without validation\n * form.setValues({ theme: \"dark\", language: \"en\" }, false);\n *\n * @example\n * // Populate form from API response\n * const loadUser = async (id: string) => {\n * const user = await api.getUser(id);\n * form.setValues(user);\n * };\n */\n const setValues = useCallback(\n (newValues: Partial<TValues>, shouldValidate = validateOnChange): void => {\n dispatch({\n type: 'SET_VALUES',\n values: newValues,\n });\n\n if (shouldValidate) {\n // Need to get latest state for validation\n const updatedValues = { ...formState.values, ...newValues };\n validateForm(updatedValues);\n }\n },\n [formState.values, validateOnChange, validateForm]\n );\n\n /**\n * Marks a field as touched or untouched and optionally triggers validation.\n * Touched fields typically display their validation errors to the user.\n *\n * @param field - The field path to mark\n * @param isTouched - Whether the field should be marked as touched (default: true)\n * @param shouldValidate - Whether to trigger validation after update (default: depends on validationMode)\n *\n * @example\n * // Mark a field as touched (will show validation errors)\n * form.setFieldTouched(\"email\");\n *\n * @example\n * // Mark as untouched (hide validation errors)\n * form.setFieldTouched(\"password\", false);\n *\n * @example\n * // Use in custom blur handler\n * const handleCustomBlur = () => {\n * form.setFieldTouched(\"username\", true);\n * // Additional custom logic\n * };\n */\n const setFieldTouched = useCallback(\n (\n field: FieldPath,\n isTouched = true,\n shouldValidate = validateOnBlur\n ): void => {\n dispatch({\n type: 'SET_FIELD_TOUCHED',\n field,\n isTouched,\n });\n\n if (shouldValidate) {\n validateForm(formState.values);\n }\n },\n [formState.values, validateOnBlur, validateForm]\n );\n\n // ===========================================================================\n // Server Error Management\n // ===========================================================================\n\n /**\n * Sets server-side validation errors received from API responses.\n * These errors take precedence over client-side errors in the merged `errors` object.\n * Server errors are automatically cleared when the related field value changes.\n *\n * @param serverErrors - Map of field paths to error messages from server\n *\n * @example\n * // Handle server validation errors\n * const form = useForm(userValidator, {\n * onSubmit: async (values) => {\n * const response = await fetch(\"/api/users\", {\n * method: \"POST\",\n * body: JSON.stringify(values)\n * });\n *\n * if (!response.ok) {\n * const errors = await response.json();\n * form.setServerErrors({\n * \"email\": \"Email already taken\",\n * \"username\": \"Username not available\"\n * });\n * return;\n * }\n * }\n * });\n *\n * @example\n * // Set a single server error\n * form.setServerErrors({ \"email\": \"This email is already registered\" });\n */\n const setServerErrors = useCallback(\n (serverErrors: Record<FieldPath, string>): void => {\n dispatch({\n type: 'SET_SERVER_ERRORS',\n errors: serverErrors,\n });\n },\n []\n );\n\n /**\n * Clears all server-side validation errors.\n * Client-side validation errors are not affected.\n * Server errors are also automatically cleared when field values change.\n *\n * @example\n * // Clear server errors when user starts editing\n * const handleRetry = () => {\n * form.clearServerErrors();\n * // User can now resubmit\n * };\n *\n * @example\n * // Clear before resubmitting\n * const handleResubmit = () => {\n * form.clearServerErrors();\n * form.handleSubmit();\n * };\n */\n const clearServerErrors = useCallback((): void => {\n dispatch({\n type: 'CLEAR_SERVER_ERRORS',\n });\n }, []);\n\n // ===========================================================================\n // Form Action Functions\n // ===========================================================================\n\n /**\n * Handles form submission using the Railway-oriented programming pattern.\n * Validates all fields, marks them as touched, and calls onSubmit if validation passes.\n * Returns a Promise that resolves to either the validated data or validation errors.\n *\n * @param e - Optional form event (will preventDefault if provided)\n * @returns Promise<TValues | ValidationError[]> - Validated data on success, errors on failure\n *\n * @example\n * // Use in form element\n * <form onSubmit={form.handleSubmit}>\n * <input {...form.getFieldProps(\"email\")} />\n * <button type=\"submit\">Submit</button>\n * </form>\n *\n * @example\n * // Use in button click handler\n * <button onClick={form.handleSubmit}>\n * Save Changes\n * </button>\n *\n * @example\n * // Handle result programmatically\n * const handleSave = async () => {\n * const result = await form.handleSubmit();\n * if (Array.isArray(result)) {\n * // Validation failed, result is ValidationError[]\n * console.error(\"Validation errors:\", result);\n * } else {\n * // Success, result is TValues\n * console.log(\"Form submitted:\", result);\n * navigate(\"/success\");\n * }\n * };\n *\n * @example\n * // With loading state\n * const [isLoading, setIsLoading] = useState(false);\n * const handleSubmitWithLoading = async () => {\n * setIsLoading(true);\n * await form.handleSubmit();\n * setIsLoading(false);\n * };\n */\n const handleSubmit = useCallback(\n async (e?: FormEvent): Promise<TValues | ValidationError[]> => {\n if (e) {\n e.preventDefault();\n }\n\n // Mark all fields and error paths as touched (deep)\n const valuePaths = collectFieldPaths(\n formState.values as Record<string, unknown>\n );\n const allPaths = Array.from(\n new Set([\n ...valuePaths,\n ...Object.keys(formState.clientErrors),\n ...Object.keys(formState.serverErrors),\n ])\n );\n\n dispatch({\n type: 'MARK_ALL_TOUCHED',\n fields: allPaths,\n });\n\n dispatch({\n type: 'SET_SUBMITTING',\n isSubmitting: true,\n });\n\n // Clear any existing server errors\n dispatch({\n type: 'CLEAR_SERVER_ERRORS',\n });\n\n // Validate the form\n const validationResult = validate(formState.values, validator);\n\n // Handle result using Railway pattern\n return match<\n TValues,\n ValidationError[],\n Promise<TValues | ValidationError[]>\n >(validationResult, {\n ok: async (validData) => {\n if (onSubmit) {\n try {\n await onSubmit(validData);\n } catch (error) {\n console.error('Form submission error:', error);\n }\n }\n\n dispatch({\n type: 'SET_SUBMITTING',\n isSubmitting: false,\n });\n\n return validData;\n },\n err: async (errors) => {\n dispatch({\n type: 'SET_CLIENT_ERRORS',\n errors: formatErrors(errors),\n });\n\n dispatch({\n type: 'SET_SUBMITTING',\n isSubmitting: false,\n });\n\n return Promise.resolve(errors);\n },\n });\n },\n [\n formState.values,\n formState.clientErrors,\n formState.serverErrors,\n validator,\n onSubmit,\n ]\n );\n\n /**\n * Resets the form to its initial state.\n * Clears all values (back to initialValues), errors, and touched state.\n * If validationMode is \"mount\", triggers validation after reset.\n *\n * @example\n * // Reset after successful submission\n * const form = useForm(userValidator, {\n * onSubmit: async (values) => {\n * await api.createUser(values);\n * form.resetForm(); // Clear form after success\n * }\n * });\n *\n * @example\n * // Cancel button\n * <button type=\"button\" onClick={form.resetForm}>\n * Cancel\n * </button>\n *\n * @example\n * // Reset with confirmation\n * const handleReset = () => {\n * if (form.isDirty && !confirm(\"Discard changes?\")) {\n * return;\n * }\n * form.resetForm();\n * };\n */\n const resetForm = useCallback((): void => {\n dispatch({\n type: 'RESET_FORM',\n });\n\n if (validateOnMount) {\n validateForm(initialValues);\n }\n }, [initialValues, validateForm, validateOnMount]);\n\n // ===========================================================================\n // Native HTML Integration\n // ===========================================================================\n\n /**\n * Returns props to bind a native text input, email input, or textarea to a form field.\n * Provides type-safe autocomplete for valid field paths.\n * The returned object can be spread directly onto native HTML elements.\n *\n * @template TField - The field path type (auto-inferred with autocomplete)\n * @param field - The field path (with type-safe autocomplete)\n * @returns NativeFieldProps - Object with id, name, value, onChange, onBlur\n *\n * @example\n * // Text input\n * <input type=\"text\" {...form.getFieldProps(\"username\")} placeholder=\"Username\" />\n *\n * @example\n * // Email input\n * <input type=\"email\" {...form.getFieldProps(\"email\")} required />\n *\n * @example\n * // Textarea\n * <textarea {...form.getFieldProps(\"bio\")} rows={4} />\n *\n * @example\n * // Nested field\n * <input type=\"text\" {...form.getFieldProps(\"address.city\")} />\n */\n const getFieldProps = useCallback(\n <TField extends ExtractFieldPaths<TValues>>(\n field: TField\n ): NativeFieldProps => {\n return createNativeFieldProps(\n field as FieldPath,\n formState.values,\n setFieldValue,\n setFieldTouched\n );\n },\n [formState.values, setFieldValue, setFieldTouched]\n );\n\n /**\n * Returns props to bind a native select element to a form field.\n * Provides type-safe autocomplete for valid field paths.\n *\n * @template TField - The field path type (auto-inferred with autocomplete)\n * @param field - The field path (with type-safe autocomplete)\n * @returns NativeSelectProps - Object with id, name, value, onChange, onBlur\n *\n * @example\n * <select {...form.getSelectFieldProps(\"country\")}>\n * <option value=\"\">Select a country</option>\n * <option value=\"US\">United States</option>\n * <option value=\"CA\">Canada</option>\n * </select>\n */\n const getSelectFieldProps = useCallback(\n <TField extends ExtractFieldPaths<TValues>>(\n field: TField\n ): NativeSelectProps => {\n return createNativeSelectFieldProps(\n field as FieldPath,\n formState.values,\n setFieldValue,\n setFieldTouched\n );\n },\n [formState.values, setFieldValue, setFieldTouched]\n );\n\n /**\n * Returns props to bind a native checkbox input to a boolean form field.\n * Provides type-safe autocomplete for valid field paths.\n *\n * @template TField - The field path type (auto-inferred with autocomplete)\n * @param field - The field path (with type-safe autocomplete)\n * @returns NativeCheckboxProps - Object with id, name, checked, onChange, onBlur\n *\n * @example\n * <label>\n * <input type=\"checkbox\" {...form.getCheckboxProps(\"acceptTerms\")} />\n * I accept the terms and conditions\n * </label>\n */\n const getCheckboxProps = useCallback(\n <TField extends ExtractFieldPaths<TValues>>(\n field: TField\n ): NativeCheckboxProps => {\n return createNativeCheckboxProps(\n field as FieldPath,\n formState.values,\n setFieldValue,\n setFieldTouched\n );\n },\n [formState.values, setFieldValue, setFieldTouched]\n );\n\n /**\n * Returns props to bind a native switch (checkbox styled as toggle) to a boolean form field.\n * Provides type-safe autocomplete for valid field paths.\n *\n * @template TField - The field path type (auto-inferred with autocomplete)\n * @param field - The field path (with type-safe autocomplete)\n * @returns NativeSwitchProps - Object with id, name, checked, onChange, onBlur\n *\n * @example\n * <label className=\"switch\">\n * <input type=\"checkbox\" {...form.getSwitchProps(\"settings.darkMode\")} />\n * <span className=\"slider\"></span>\n * </label>\n */\n const getSwitchProps = useCallback(\n <TField extends ExtractFieldPaths<TValues>>(\n field: TField\n ): NativeSwitchProps => {\n return createNativeSwitchProps(\n field as FieldPath,\n formState.values,\n setFieldValue,\n setFieldTouched\n );\n },\n [formState.values, setFieldValue, setFieldTouched]\n );\n\n /**\n * Returns props to bind a native range input to a numeric form field.\n * Provides type-safe autocomplete for valid field paths.\n * Note: Native range inputs only support single numeric values, not arrays.\n *\n * @template TField - The field path type (auto-inferred with autocomplete)\n * @param field - The field path (with type-safe autocomplete)\n * @returns NativeSliderProps - Object with id, name, type, value, onChange, onBlur\n *\n * @example\n * <div>\n * <label>Volume: {form.values.volume}%</label>\n * <input type=\"range\" min={0} max={100} {...form.getSliderProps(\"volume\")} />\n * </div>\n */\n const getSliderProps = useCallback(\n <TField extends ExtractFieldPaths<TValues>>(\n field: TField\n ): NativeSliderProps => {\n return createNativeSliderProps(\n field as FieldPath,\n formState.values,\n setFieldValue,\n setFieldTouched\n );\n },\n [formState.values, setFieldValue, setFieldTouched]\n );\n\n /**\n * Returns props for a single checkbox within a checkbox group bound to an array field.\n * Checking the box adds the value to the array; unchecking removes it.\n * Provides type-safe autocomplete for valid field paths.\n *\n * @template TField - The field path type (auto-inferred with autocomplete)\n * @param field - The field path (with type-safe autocomplete)\n * @param optionValue - The value this checkbox represents\n * @returns NativeCheckboxGroupOptionProps - Object with id, name, value, checked, onChange, onBlur\n *\n * @example\n * <label>\n * <input type=\"checkbox\" {...form.getCheckboxGroupOptionProps(\"interests\", \"sports\")} />\n * Sports\n * </label>\n * <label>\n * <input type=\"checkbox\" {...form.getCheckboxGroupOptionProps(\"interests\", \"music\")} />\n * Music\n * </label>\n */\n const getCheckboxGroupOptionProps = useCallback(\n <TField extends ExtractFieldPaths<TValues>>(\n field: TField,\n optionValue: string | number\n ) => {\n return createCheckboxGroupOptionProps(\n field as FieldPath,\n optionValue,\n formState.values,\n setFieldValue,\n setFieldTouched\n );\n },\n [formState.values, setFieldValue, setFieldTouched]\n );\n\n /**\n * Returns props to bind a native file input to a form field.\n * Provides type-safe autocomplete for valid field paths.\n * Supports both single and multiple file selection.\n *\n * @template TField - The field path type (auto-inferred with autocomplete)\n * @param field - The field path (with type-safe autocomplete)\n * @returns NativeFileFieldProps - Object with id, name, onChange, onBlur\n *\n * @example\n * // Single file\n * <input type=\"file\" accept=\"image/*\" {...form.getFileFieldProps(\"avatar\")} />\n *\n * @example\n * // Multiple files\n * <input type=\"file\" multiple {...form.getFileFieldProps(\"documents\")} />\n */\n const getFileFieldProps = useCallback(\n <TField extends ExtractFieldPaths<TValues>>(\n field: TField\n ): NativeFileFieldProps => {\n return createNativeFileFieldProps(\n field as FieldPath,\n formState.values,\n setFieldValue,\n setFieldTouched\n );\n },\n [formState.values, setFieldValue, setFieldTouched]\n );\n\n /**\n * Returns props for a single radio button within a radio group bound to a scalar field.\n * Only one radio button in the group can be selected at a time.\n * Provides type-safe autocomplete for valid field paths.\n *\n * @template TField - The field path type (auto-inferred with autocomplete)\n * @param field - The field path (with type-safe autocomplete)\n * @param optionValue - The value this radio button represents\n * @returns NativeRadioGroupOptionProps - Object with id, name, value, checked, onChange, onBlur\n *\n * @example\n * <label>\n * <input type=\"radio\" {...form.getRadioGroupOptionProps(\"contactMethod\", \"email\")} />\n * Email\n * </label>\n * <label>\n * <input type=\"radio\" {...form.getRadioGroupOptionProps(\"contactMethod\", \"phone\")} />\n * Phone\n * </label>\n */\n const getRadioGroupOptionProps = useCallback(\n <TField extends ExtractFieldPaths<TValues>>(\n field: TField,\n optionValue: string | number\n ): NativeRadioGroupOptionProps => {\n return createRadioGroupOptionProps(\n field as FieldPath,\n optionValue,\n formState.values,\n setFieldValue,\n setFieldTouched\n );\n },\n [formState.values, setFieldValue, setFieldTouched]\n );\n\n // ===========================================================================\n // Array Field Helpers\n // ===========================================================================\n\n /**\n * Returns helper functions for managing array fields with type-safe operations.\n * Provides methods to add, remove, reorder, and bind HTML elements to array items.\n * Automatically infers item types and provides autocomplete for nested field paths.\n *\n * @template TItem - The type of items in the array (auto-inferred from field)\n * @param field - The path to the array field\n * @returns ArrayHelpers<TItem> - Object with array manipulation methods and field binding helpers\n *\n * @example\n * // Basic array operations\n * const form = useForm(contactsValidator, {\n * initialValues: { contacts: [] }\n * });\n * const helpers = form.arrayHelpers(\"contacts\");\n *\n * // Add new item\n * <button onClick={() => helpers.push({ name: \"\", email: \"\" })}>\n * Add Contact\n * </button>\n *\n * @example\n * // Render array items with field binding\n * const helpers = form.arrayHelpers(\"addresses\");\n * return (\n * <div>\n * {helpers.values.map((address, index) => (\n * <div key={index}>\n * <input {...helpers.getFieldProps(index, \"street\")} placeholder=\"Street\" />\n * <input {...helpers.getFieldProps(index, \"city\")} placeholder=\"City\" />\n * <button onClick={() => helpers.remove(index)}>Remove</button>\n * </div>\n * ))}\n * <button onClick={() => helpers.push({ street: \"\", city: \"\" })}>\n * Add Address\n * </button>\n * </div>\n * );\n *\n * @example\n * // Reorder items (drag and drop)\n * const handleMoveUp = (index: number) => {\n * if (index > 0) {\n * helpers.swap(index, index - 1);\n * }\n * };\n *\n * @example\n * // Replace an entire item\n * const handleUpdate = (index: number) => {\n * helpers.replace(index, { name: \"Updated\", email: \"new@example.com\" });\n * };\n */\n const arrayHelpersImpl = useCallback(\n <TItem = unknown>(\n field: string\n ): ArrayHelpers<TItem, ExtractFieldPaths<TItem>> => {\n // Local path-based wrappers to avoid generic casts\n const getFieldPropsAtPath = (path: string) =>\n createNativeFieldProps(\n path,\n formState.values,\n setFieldValue,\n setFieldTouched\n );\n\n const getSelectFieldPropsAtPath = (path: string) =>\n createNativeSelectFieldProps(\n path,\n formState.values,\n setFieldValue,\n setFieldTouched\n );\n\n const getSliderPropsAtPath = (path: string) =>\n createNativeSliderProps(\n path,\n formState.values,\n setFieldValue,\n setFieldTouched\n );\n\n const getCheckboxPropsAtPath = (path: string) =>\n createNativeCheckboxProps(\n path,\n formState.values,\n setFieldValue,\n setFieldTouched\n );\n\n const getSwitchPropsAtPath = (path: string) =>\n createNativeSwitchProps(\n path,\n formState.values,\n setFieldValue,\n setFieldTouched\n );\n\n const getFileFieldPropsAtPath = (path: string) =>\n createNativeFileFieldProps(\n path,\n formState.values,\n setFieldValue,\n setFieldTouched\n );\n\n const getRadioGroupOptionPropsAtPath = (\n path: string,\n opt: string | number\n ) =>\n createRadioGroupOptionProps(\n path,\n opt,\n formState.values,\n setFieldValue,\n setFieldTouched\n );\n\n const arrayValue =\n getValueByPath<Partial<TValues>, TItem[]>(formState.values, field) ||\n [];\n\n return createArrayHelpers<TItem, ExtractFieldPaths<TItem>>(\n field,\n arrayValue,\n setFieldValue,\n getFieldPropsAtPath,\n getSelectFieldPropsAtPath,\n getSliderPropsAtPath,\n getCheckboxPropsAtPath,\n getSwitchPropsAtPath,\n getFileFieldPropsAtPath,\n getRadioGroupOptionPropsAtPath\n );\n },\n [formState.values, setFieldValue, setFieldTouched]\n );\n\n // Overloaded wrapper for better type inference\n const arrayHelpers = arrayHelpersImpl as {\n <TField extends keyof TValues & string>(\n field: TField\n ): ArrayHelpers<\n GetArrayItemType<TValues, TField>,\n ExtractFieldPaths<GetArrayItemType<TValues, TField>>\n >;\n <TField extends ExtractFieldPaths<TValues>, TItem = unknown>(\n field: TField\n ): ArrayHelpers<TItem, ExtractFieldPaths<TItem>>;\n };\n\n // ===========================================================================\n // Return\n // ===========================================================================\n\n return {\n // Form state\n values: formState.values,\n touched: formState.touched,\n errors,\n clientErrors: formState.clientErrors,\n serverErrors: formState.serverErrors,\n isSubmitting: formState.isSubmitting,\n isValid,\n isDirty: formState.isDirty,\n\n // Field management\n setFieldValue,\n setFieldTouched,\n setValues,\n\n // Server error management\n setServerErrors,\n clearServerErrors,\n\n // Form actions\n handleSubmit,\n resetForm,\n validateForm,\n\n // Native HTML field integration\n getFieldProps,\n getSelectFieldProps,\n getCheckboxProps,\n getSwitchProps,\n getSliderProps,\n getCheckboxGroupOptionProps,\n getFileFieldProps,\n getRadioGroupOptionProps,\n\n // Array field helpers\n arrayHelpers,\n };\n};\n","import { useRef, useCallback, useEffect } from 'react';\n\n/**\n * A React hook that debounces a callback function, delaying its execution until after\n * a specified delay period has elapsed since the last time it was invoked.\n *\n * Useful for optimizing performance by limiting the rate at which a function is called,\n * such as in response to rapid user input or scroll events.\n *\n * @template T - The callback function type\n * @template Params - The parameter types of the callback function\n * @template Return - The return type of the callback function\n *\n * @param callback - The function to debounce\n * @param delay - The number of milliseconds to delay execution\n * @returns A debounced version of the callback function that can be called with the same parameters\n *\n * @example\n * // Debounce a search function\n * const debouncedSearch = useDebounce((query: string) => {\n * fetchSearchResults(query);\n * }, 300);\n *\n * @example\n * // Use in an input handler\n * const handleInputChange = useDebounce((value: string) => {\n * form.setFieldValue('search', value);\n * }, 500);\n */\nexport function useDebounce<\n T extends (...args: Params) => Return,\n Params extends unknown[] = Parameters<T>,\n Return = ReturnType<T>,\n>(callback: T, delay: number): (...args: Params) => void {\n const timeoutRef = useRef<ReturnType<typeof setTimeout> | null>(null);\n const callbackRef = useRef(callback);\n\n // Keep callback ref up-to-date\n useEffect(() => {\n callbackRef.current = callback;\n }, [callback]);\n\n // Cleanup timeout on unmount\n useEffect(() => {\n return () => {\n if (timeoutRef.current) {\n clearTimeout(timeoutRef.current);\n }\n };\n }, []);\n\n return useCallback(\n (...args: Params) => {\n if (timeoutRef.current) {\n clearTimeout(timeoutRef.current);\n }\n\n timeoutRef.current = setTimeout(() => {\n callbackRef.current(...args);\n }, delay);\n },\n [delay]\n );\n}\n","import { useRef, useEffect } from 'react';\n\nimport { useDebounce } from './useDebounce';\n\n/**\n * Represents the subset of form methods needed for auto-submission\n * @template T - The type of form values\n */\ntype FormWithAutoSubmit<T> = {\n values: Partial<T>;\n isDirty: boolean;\n isValid: boolean;\n validateForm: (values: T) => void;\n handleSubmit: () => void;\n};\n\n/**\n * A React hook that automatically submits a form when it becomes valid and dirty.\n * Useful for creating auto-save or live-update form experiences.\n *\n * The hook monitors form values and automatically triggers submission when:\n * 1. The form is dirty (has been modified)\n * 2. The form is valid (passes all validation rules)\n * 3. The values have changed since the last validation\n *\n * Submission is debounced to avoid excessive API calls during rapid user input.\n *\n * @template T - The type of form values\n *\n * @param form - A form object containing values, validation state, and submission methods\n * @param delay - The debounce delay in milliseconds before auto-submitting (default: 200ms)\n * @returns null (this hook only produces side effects)\n *\n * @example\n * // Auto-submit a preferences form\n * const form = useForm(preferencesSchema, {\n * initialValues: { theme: 'light', notifications: true },\n * onSubmit: async (values) => {\n * await updateUserPreferences(values);\n * }\n * });\n *\n * useFormAutoSubmission(form, 500);\n *\n * @example\n * // Auto-save a draft\n * const form = useForm(draftSchema, {\n * initialValues: draft,\n * onSubmit: saveDraft,\n * validationMode: \"live\"\n * });\n *\n * useFormAutoSubmission(form);\n */\nexport const useFormAutoSubmission = <T>(\n form: FormWithAutoSubmit<T>,\n delay = 200\n) => {\n const lastValidatedRef = useRef('');\n\n const debouncedSubmit = useDebounce(() => {\n if (form.isValid) form.handleSubmit();\n }, delay);\n\n useEffect(() => {\n if (!form.isDirty) return;\n\n const valuesString = JSON.stringify(form.values);\n if (valuesString === lastValidatedRef.current) return;\n\n lastValidatedRef.current = valuesString;\n form.validateForm(form.values as T);\n\n if (form.isValid) debouncedSubmit();\n }, [form.values, form.isDirty, form.isValid, debouncedSubmit, form]);\n\n return null;\n};\n"]}
|