'use client'; import { useLayoutEffect, useEffect, useState, useRef, useCallback, createContext, useContext, forwardRef, useMemo } from 'react'; import { c } from 'react/compiler-runtime'; import { klona } from 'klona/full'; import isEqual from 'fast-deep-equal'; import { jsx } from 'react/jsx-runtime'; function dispatchEvent(type, detail) { window.dispatchEvent(new CustomEvent(type, { detail })); } function validateFormName(name) { if (!/^[0-9a-zA-Z-]+$/.test(name)) { throw new Error( `[@mantine/use-form] Form name "${name}" is invalid, it should contain only letters, numbers and dashes` ); } } const useIsomorphicEffect = typeof window !== "undefined" ? useLayoutEffect : useEffect; function createFormActions(name) { validateFormName(name); const setFieldValue = (path, value) => dispatchEvent(`mantine-form:${name}:set-field-value`, { path, value }); const setValues = (values) => dispatchEvent(`mantine-form:${name}:set-values`, values); const setInitialValues = (values) => dispatchEvent(`mantine-form:${name}:set-initial-values`, values); const setErrors = (errors) => dispatchEvent(`mantine-form:${name}:set-errors`, errors); const setFieldError = (path, error) => dispatchEvent(`mantine-form:${name}:set-field-error`, { path, error }); const clearFieldError = (path) => dispatchEvent(`mantine-form:${name}:clear-field-error`, path); const clearErrors = () => dispatchEvent(`mantine-form:${name}:clear-errors`); const reset = () => dispatchEvent(`mantine-form:${name}:reset`); const validate = () => dispatchEvent(`mantine-form:${name}:validate`); const validateField = (path) => dispatchEvent(`mantine-form:${name}:validate-field`, path); const reorderListItem = (path, payload) => dispatchEvent(`mantine-form:${name}:reorder-list-item`, { path, payload }); const removeListItem = (path, index) => dispatchEvent(`mantine-form:${name}:remove-list-item`, { path, index }); const insertListItem = (path, item, index) => dispatchEvent(`mantine-form:${name}:insert-list-item`, { path, index, item }); const setDirty = (value) => dispatchEvent(`mantine-form:${name}:set-dirty`, value); const setTouched = (value) => dispatchEvent(`mantine-form:${name}:set-touched`, value); const resetDirty = (values) => dispatchEvent(`mantine-form:${name}:reset-dirty`, values); const resetTouched = () => dispatchEvent(`mantine-form:${name}:reset-touched`); return { setFieldValue, setValues, setInitialValues, setErrors, setFieldError, clearFieldError, clearErrors, reset, validate, validateField, reorderListItem, removeListItem, insertListItem, setDirty, setTouched, resetDirty, resetTouched }; } function useFormEvent(eventKey, handler) { const $ = c(5); let t0; if ($[0] !== eventKey || $[1] !== handler) { t0 = () => { if (eventKey) { window.addEventListener(eventKey, handler); return () => window.removeEventListener(eventKey, handler); } }; $[0] = eventKey; $[1] = handler; $[2] = t0; } else { t0 = $[2]; } let t1; if ($[3] !== eventKey) { t1 = [eventKey]; $[3] = eventKey; $[4] = t1; } else { t1 = $[4]; } useIsomorphicEffect(t0, t1); } function useFormActions(name, form) { const $ = c(26); if (name) { validateFormName(name); } let t0; if ($[0] !== form) { t0 = (event) => form.setFieldValue(event.detail.path, event.detail.value); $[0] = form; $[1] = t0; } else { t0 = $[1]; } useFormEvent( `mantine-form:${name}:set-field-value`, t0 ); let t1; if ($[2] !== form) { t1 = (event_0) => form.setValues(event_0.detail); $[2] = form; $[3] = t1; } else { t1 = $[3]; } useFormEvent( `mantine-form:${name}:set-values`, t1 ); let t2; if ($[4] !== form) { t2 = (event_1) => form.setInitialValues(event_1.detail); $[4] = form; $[5] = t2; } else { t2 = $[5]; } useFormEvent( `mantine-form:${name}:set-initial-values`, t2 ); let t3; if ($[6] !== form) { t3 = (event_2) => form.setErrors(event_2.detail); $[6] = form; $[7] = t3; } else { t3 = $[7]; } useFormEvent( `mantine-form:${name}:set-errors`, t3 ); let t4; if ($[8] !== form) { t4 = (event_3) => form.setFieldError(event_3.detail.path, event_3.detail.error); $[8] = form; $[9] = t4; } else { t4 = $[9]; } useFormEvent( `mantine-form:${name}:set-field-error`, t4 ); let t5; if ($[10] !== form) { t5 = (event_4) => form.clearFieldError(event_4.detail); $[10] = form; $[11] = t5; } else { t5 = $[11]; } useFormEvent( `mantine-form:${name}:clear-field-error`, t5 ); useFormEvent(`mantine-form:${name}:clear-errors`, form.clearErrors); useFormEvent(`mantine-form:${name}:reset`, form.reset); useFormEvent(`mantine-form:${name}:validate`, form.validate); let t6; if ($[12] !== form) { t6 = (event_5) => form.validateField(event_5.detail); $[12] = form; $[13] = t6; } else { t6 = $[13]; } useFormEvent( `mantine-form:${name}:validate-field`, t6 ); let t7; if ($[14] !== form) { t7 = (event_6) => form.reorderListItem(event_6.detail.path, event_6.detail.payload); $[14] = form; $[15] = t7; } else { t7 = $[15]; } useFormEvent( `mantine-form:${name}:reorder-list-item`, t7 ); let t8; if ($[16] !== form) { t8 = (event_7) => form.removeListItem(event_7.detail.path, event_7.detail.index); $[16] = form; $[17] = t8; } else { t8 = $[17]; } useFormEvent( `mantine-form:${name}:remove-list-item`, t8 ); let t9; if ($[18] !== form) { t9 = (event_8) => form.insertListItem(event_8.detail.path, event_8.detail.item, event_8.detail.index); $[18] = form; $[19] = t9; } else { t9 = $[19]; } useFormEvent( `mantine-form:${name}:insert-list-item`, t9 ); let t10; if ($[20] !== form) { t10 = (event_9) => form.setDirty(event_9.detail); $[20] = form; $[21] = t10; } else { t10 = $[21]; } useFormEvent( `mantine-form:${name}:set-dirty`, t10 ); let t11; if ($[22] !== form) { t11 = (event_10) => form.setTouched(event_10.detail); $[22] = form; $[23] = t11; } else { t11 = $[23]; } useFormEvent( `mantine-form:${name}:set-touched`, t11 ); let t12; if ($[24] !== form) { t12 = (event_11) => form.resetDirty(event_11.detail); $[24] = form; $[25] = t12; } else { t12 = $[25]; } useFormEvent( `mantine-form:${name}:reset-dirty`, t12 ); useFormEvent(`mantine-form:${name}:reset-touched`, form.resetTouched); } function getInputOnChange(setValue) { return (val) => { if (!val) { setValue(val); } else if (typeof val === "function") { setValue(val); } else if (typeof val === "object" && "nativeEvent" in val) { const { currentTarget } = val; if (currentTarget instanceof HTMLInputElement) { if (currentTarget.type === "checkbox") { setValue(currentTarget.checked); } else { setValue(currentTarget.value); } } else if (currentTarget instanceof HTMLTextAreaElement || currentTarget instanceof HTMLSelectElement) { setValue(currentTarget.value); } } else { setValue(val); } }; } function filterErrors(errors) { if (errors === null || typeof errors !== "object") { return {}; } return Object.keys(errors).reduce((acc, key) => { const errorValue = errors[key]; if (errorValue !== void 0 && errorValue !== null && errorValue !== false) { acc[key] = errorValue; } return acc; }, {}); } function useFormErrors(initialErrors) { const [errorsState, setErrorsState] = useState(filterErrors(initialErrors)); const errorsRef = useRef(errorsState); const setErrors = useCallback((errors) => { setErrorsState((current) => { const newErrors = filterErrors(typeof errors === "function" ? errors(current) : errors); errorsRef.current = newErrors; return newErrors; }); }, []); const clearErrors = useCallback(() => setErrors({}), []); const clearFieldError = useCallback( (path) => { if (errorsRef.current[path] === void 0) { return; } setErrors((current_0) => { const errors_0 = { ...current_0 }; delete errors_0[path]; return errors_0; }); }, [errorsState] ); const setFieldError = useCallback( (path_0, error) => { if (error == null || error === false) { clearFieldError(path_0); } else if (errorsRef.current[path_0] !== error) { setErrors((current_1) => ({ ...current_1, [path_0]: error })); } }, [errorsState] ); return { errorsState, setErrors, clearErrors, setFieldError, clearFieldError }; } function clearListState(field, state) { if (state === null || typeof state !== "object") { return {}; } const clone = { ...state }; Object.keys(state).forEach((errorKey) => { if (errorKey.includes(`${String(field)}.`)) { delete clone[errorKey]; } }); return clone; } function getIndexFromKeyAfterPath(key, path) { const split = key.substring(path.length + 1).split(".")[0]; return parseInt(split, 10); } function changeErrorIndices(path, index, errors, change) { if (index === void 0) { return errors; } const pathString = `${String(path)}`; let clearedErrors = errors; if (change === -1) { clearedErrors = clearListState(`${pathString}.${index}`, clearedErrors); } const cloned = { ...clearedErrors }; const changedKeys = /* @__PURE__ */ new Set(); Object.entries(clearedErrors).filter(([key]) => { if (!key.startsWith(`${pathString}.`)) { return false; } const currIndex = getIndexFromKeyAfterPath(key, pathString); if (Number.isNaN(currIndex)) { return false; } return currIndex >= index; }).forEach(([key, value]) => { const currIndex = getIndexFromKeyAfterPath(key, pathString); const newKey = key.replace( `${pathString}.${currIndex}`, `${pathString}.${currIndex + change}` ); cloned[newKey] = value; changedKeys.add(newKey); if (!changedKeys.has(key)) { delete cloned[key]; } }); return cloned; } function reorderErrors(path, { from, to }, errors) { const oldKeyStart = `${path}.${from}`; const newKeyStart = `${path}.${to}`; const clone = { ...errors }; Object.keys(errors).every((key) => { let oldKey; let newKey; if (key.startsWith(oldKeyStart)) { oldKey = key; newKey = key.replace(oldKeyStart, newKeyStart); } if (key.startsWith(newKeyStart)) { oldKey = key.replace(newKeyStart, oldKeyStart); newKey = key; } if (oldKey && newKey) { const value1 = clone[oldKey]; const value2 = clone[newKey]; value2 === void 0 ? delete clone[oldKey] : clone[oldKey] = value2; value1 === void 0 ? delete clone[newKey] : clone[newKey] = value1; return false; } return true; }); return clone; } function getSplittedPath(path) { if (typeof path !== "string") { return []; } return path.split("."); } function getPath(path, values) { const splittedPath = getSplittedPath(path); if (splittedPath.length === 0 || typeof values !== "object" || values === null) { return void 0; } let value = values[splittedPath[0]]; for (let i = 1; i < splittedPath.length; i += 1) { if (value === void 0) { break; } value = value[splittedPath[i]]; } return value; } function setPath(path, value, values) { const splittedPath = getSplittedPath(path); if (splittedPath.length === 0) { return values; } const cloned = klona(values); if (splittedPath.length === 1) { cloned[splittedPath[0]] = value; return cloned; } let val = cloned[splittedPath[0]]; for (let i = 1; i < splittedPath.length - 1; i += 1) { if (val === void 0) { return cloned; } val = val[splittedPath[i]]; } val[splittedPath[splittedPath.length - 1]] = value; return cloned; } function reorderPath(path, { from, to }, values) { const currentValue = getPath(path, values); if (!Array.isArray(currentValue)) { return values; } const cloned = [...currentValue]; const item = currentValue[from]; cloned.splice(from, 1); cloned.splice(to, 0, item); return setPath(path, cloned, values); } function insertPath(path, value, index, values) { const currentValue = getPath(path, values); if (!Array.isArray(currentValue)) { return values; } const cloned = [...currentValue]; cloned.splice(typeof index === "number" ? index : cloned.length, 0, value); return setPath(path, cloned, values); } function removePath(path, index, values) { const currentValue = getPath(path, values); if (!Array.isArray(currentValue)) { return values; } return setPath( path, currentValue.filter((_, itemIndex) => itemIndex !== index), values ); } function getDataPath(formName, fieldPath) { return formName ? `${formName}-${fieldPath.toString()}` : fieldPath.toString(); } function useFormList({ $values, $errors, $status }) { const reorderListItem = useCallback((path, payload) => { $status.clearFieldDirty(path); $errors.setErrors((errs) => reorderErrors(path, payload, errs)); $values.setValues({ values: reorderPath(path, payload, $values.refValues.current), updateState: true }); }, []); const removeListItem = useCallback((path_0, index) => { $status.clearFieldDirty(path_0); $errors.setErrors((errs_0) => changeErrorIndices(path_0, index, errs_0, -1)); $values.setValues({ values: removePath(path_0, index, $values.refValues.current), updateState: true }); }, []); const insertListItem = useCallback((path_1, item, index_0) => { $status.clearFieldDirty(path_1); $errors.setErrors((errs_1) => changeErrorIndices(path_1, index_0, errs_1, 1)); $values.setValues({ values: insertPath(path_1, item, index_0, $values.refValues.current), updateState: true }); }, []); return { reorderListItem, removeListItem, insertListItem }; } function getStatus(status, path) { const paths = Object.keys(status); if (typeof path === "string") { const nestedPaths = paths.filter((statusPath) => statusPath.startsWith(`${path}.`)); return status[path] || nestedPaths.some((statusPath) => status[statusPath]) || false; } return paths.some((statusPath) => status[statusPath]); } function useFormStatus({ initialDirty, initialTouched, mode, $values }) { const [touchedState, setTouchedState] = useState(initialTouched); const [dirtyState, setDirtyState] = useState(initialDirty); const touchedRef = useRef(initialTouched); const dirtyRef = useRef(initialDirty); const setTouched = useCallback((values) => { const resolvedValues = typeof values === "function" ? values(touchedRef.current) : values; touchedRef.current = resolvedValues; if (mode === "controlled") { setTouchedState(resolvedValues); } }, []); const setDirty = useCallback((values_0) => { const resolvedValues_0 = typeof values_0 === "function" ? values_0(dirtyRef.current) : values_0; dirtyRef.current = resolvedValues_0; if (mode === "controlled") { setDirtyState(resolvedValues_0); } }, []); const resetTouched = useCallback(() => setTouched({}), []); const resetDirty = (values_1) => { const newSnapshot = values_1 ? { ...values_1, ...$values.refValues.current } : $values.refValues.current; $values.setValuesSnapshot(newSnapshot); setDirty({}); }; const setFieldTouched = useCallback((path, touched) => { setTouched((currentTouched) => { if (getStatus(currentTouched, path) === touched) { return currentTouched; } return { ...currentTouched, [path]: touched }; }); }, []); const setFieldDirty = useCallback((path_0, dirty) => { setDirty((currentDirty) => { if (getStatus(currentDirty, path_0) === dirty) { return currentDirty; } return { ...currentDirty, [path_0]: dirty }; }); }, []); const isTouched = useCallback( (path_1) => getStatus(touchedRef.current, path_1), [] ); const clearFieldDirty = useCallback( (path_2) => setDirty((current) => { if (typeof path_2 !== "string") { return current; } const result = clearListState(path_2, current); delete result[path_2]; if (isEqual(result, current)) { return current; } return result; }), [] ); const isDirty = useCallback((path_3) => { if (path_3) { const overriddenValue = getPath(path_3, dirtyRef.current); if (typeof overriddenValue === "boolean") { return overriddenValue; } const sliceOfValues = getPath(path_3, $values.refValues.current); const sliceOfInitialValues = getPath(path_3, $values.valuesSnapshot.current); return !isEqual(sliceOfValues, sliceOfInitialValues); } const isOverridden = Object.keys(dirtyRef.current).length > 0; if (isOverridden) { return getStatus(dirtyRef.current); } return !isEqual($values.refValues.current, $values.valuesSnapshot.current); }, []); const getDirty = useCallback(() => dirtyRef.current, []); const getTouched = useCallback(() => touchedRef.current, []); return { touchedState, dirtyState, touchedRef, dirtyRef, setTouched, setDirty, resetDirty, resetTouched, isTouched, setFieldTouched, setFieldDirty, setTouchedState, setDirtyState, clearFieldDirty, isDirty, getDirty, getTouched }; } function useFormValues({ initialValues, onValuesChange, mode }) { const initialized = useRef(false); const [stateValues, setStateValues] = useState(initialValues || {}); const refValues = useRef(stateValues); const valuesSnapshot = useRef(stateValues); const setValues = useCallback( ({ values, subscribers, updateState = true, mergeWithPreviousValues = true }) => { const previousValues = refValues.current; const resolvedValues = values instanceof Function ? values(refValues.current) : values; const updatedValues = mergeWithPreviousValues ? { ...previousValues, ...resolvedValues } : resolvedValues; refValues.current = updatedValues; updateState && setStateValues(updatedValues); onValuesChange?.(updatedValues, previousValues); subscribers?.filter(Boolean).forEach((subscriber) => subscriber({ updatedValues, previousValues })); }, [onValuesChange] ); const setFieldValue = useCallback( (payload) => { const currentValue = getPath(payload.path, refValues.current); const updatedValue = payload.value instanceof Function ? payload.value(currentValue) : payload.value; if (currentValue !== updatedValue) { const previousValues_0 = refValues.current; const updatedValues_0 = setPath(payload.path, updatedValue, refValues.current); setValues({ values: updatedValues_0, updateState: payload.updateState }); payload.subscribers?.filter(Boolean).forEach( (subscriber_0) => subscriber_0({ path: payload.path, updatedValues: updatedValues_0, previousValues: previousValues_0 }) ); } }, [setValues] ); const setValuesSnapshot = useCallback((payload_0) => { valuesSnapshot.current = payload_0; }, []); const initialize = useCallback( (values_0, onInitialize) => { if (!initialized.current) { initialized.current = true; setValues({ values: values_0, updateState: mode === "controlled" }); setValuesSnapshot(values_0); onInitialize(); } }, [setValues] ); const resetValues = useCallback(() => { setValues({ values: valuesSnapshot.current, updateState: true, mergeWithPreviousValues: false }); }, [setValues]); const getValues = useCallback(() => refValues.current, []); return { initialized, stateValues, refValues, valuesSnapshot, setValues, setFieldValue, resetValues, setValuesSnapshot, initialize, getValues }; } function useFormWatch({ $status }) { const subscribers = useRef( {} ); const watch = useCallback((path, callback) => { useEffect(() => { subscribers.current[path] = subscribers.current[path] || []; subscribers.current[path].push(callback); return () => { subscribers.current[path] = subscribers.current[path].filter((cb) => cb !== callback); }; }, [callback]); }, []); const getFieldSubscribers = useCallback((path_0) => { if (!subscribers.current[path_0]) { return []; } return subscribers.current[path_0].map( (callback_0) => (input) => callback_0({ previousValue: getPath(path_0, input.previousValues), value: getPath(path_0, input.updatedValues), touched: $status.isTouched(path_0), dirty: $status.isDirty(path_0) }) ); }, []); return { subscribers, watch, getFieldSubscribers }; } function getValidationResults(errors) { const filteredErrors = filterErrors(errors); return { hasErrors: Object.keys(filteredErrors).length > 0, errors: filteredErrors }; } function validateRulesRecord(rules, values, path = "", errors = {}) { if (typeof rules !== "object" || rules === null) { return errors; } return Object.keys(rules).reduce((acc, ruleKey) => { const rule = rules[ruleKey]; const rulePath = `${path === "" ? "" : `${path}.`}${ruleKey}`; const value = getPath(rulePath, values); let arrayValidation = false; if (typeof rule === "function") { acc[rulePath] = rule(value, values, rulePath); } if (typeof rule === "object" && Array.isArray(value)) { arrayValidation = true; value.forEach( (_item, index) => validateRulesRecord(rule, values, `${rulePath}.${index}`, acc) ); } if (typeof rule === "object" && typeof value === "object" && value !== null) { if (!arrayValidation) { validateRulesRecord(rule, values, rulePath, acc); } } return acc; }, errors); } function validateValues(validate, values) { if (typeof validate === "function") { return getValidationResults(validate(values)); } return getValidationResults(validateRulesRecord(validate, values)); } function validateFieldValue(path, rules, values) { if (typeof path !== "string") { return { hasError: false, error: null }; } const results = validateValues(rules, values); const pathInError = Object.keys(results.errors).find( (errorKey) => path.split(".").every((pathPart, i) => pathPart === errorKey.split(".")[i]) ); return { hasError: !!pathInError, error: pathInError ? results.errors[pathInError] : null }; } const FORM_INDEX = "__MANTINE_FORM_INDEX__"; function shouldValidateOnChange(path, validateInputOnChange) { if (!validateInputOnChange) { return false; } if (typeof validateInputOnChange === "boolean") { return validateInputOnChange; } if (Array.isArray(validateInputOnChange)) { return validateInputOnChange.includes(path.replace(/[.][0-9]/g, `.${FORM_INDEX}`)); } return false; } function useForm({ name, mode = "controlled", initialValues, initialErrors = {}, initialDirty = {}, initialTouched = {}, clearInputErrorOnChange = true, validateInputOnChange = false, validateInputOnBlur = false, onValuesChange, transformValues = (values) => values, enhanceGetInputProps, validate: rules } = {}) { const $errors = useFormErrors(initialErrors); const $values = useFormValues({ initialValues, onValuesChange, mode }); const $status = useFormStatus({ initialDirty, initialTouched, $values, mode }); const $list = useFormList({ $values, $errors, $status }); const $watch = useFormWatch({ $status }); const [formKey, setFormKey] = useState(0); const [fieldKeys, setFieldKeys] = useState({}); const reset = useCallback(() => { $values.resetValues(); $errors.clearErrors(); $status.resetDirty(); $status.resetTouched(); mode === "uncontrolled" && setFormKey((key) => key + 1); }, []); const initialize = useCallback((values_0) => { $values.initialize(values_0, () => mode === "uncontrolled" && setFormKey((key_0) => key_0 + 1)); }, []); const setFieldValue = useCallback( (path, value, options) => { const shouldValidate = shouldValidateOnChange(path, validateInputOnChange); $status.clearFieldDirty(path); $status.setFieldTouched(path, true); !shouldValidate && clearInputErrorOnChange && $errors.clearFieldError(path); $values.setFieldValue({ path, value, updateState: mode === "controlled", subscribers: [ ...$watch.getFieldSubscribers(path), shouldValidate ? (payload) => { const validationResults = validateFieldValue(path, rules, payload.updatedValues); validationResults.hasError ? $errors.setFieldError(path, validationResults.error) : $errors.clearFieldError(path); } : null, options?.forceUpdate !== false && mode !== "controlled" ? () => setFieldKeys((keys) => ({ ...keys, [path]: (keys[path] || 0) + 1 })) : null ] }); }, [onValuesChange, rules] ); const setValues = useCallback( (values_1) => { const previousValues = $values.refValues.current; $values.setValues({ values: values_1, updateState: mode === "controlled" }); clearInputErrorOnChange && $errors.clearErrors(); mode === "uncontrolled" && setFormKey((key_1) => key_1 + 1); Object.keys($watch.subscribers.current).forEach((path_0) => { const value_0 = getPath(path_0, $values.refValues.current); const previousValue = getPath(path_0, previousValues); if (value_0 !== previousValue) { $watch.getFieldSubscribers(path_0).forEach((cb) => cb({ previousValues, updatedValues: $values.refValues.current })); } }); }, [onValuesChange, clearInputErrorOnChange] ); const validate = useCallback(() => { const results = validateValues(rules, $values.refValues.current); $errors.setErrors(results.errors); return results; }, [rules]); const validateField = useCallback( (path_1) => { const results_0 = validateFieldValue(path_1, rules, $values.refValues.current); results_0.hasError ? $errors.setFieldError(path_1, results_0.error) : $errors.clearFieldError(path_1); return results_0; }, [rules] ); const getInputProps = (path_2, { type = "input", withError = true, withFocus = true, ...otherOptions } = {}) => { const onChange = getInputOnChange( (value_1) => setFieldValue(path_2, value_1, { forceUpdate: false }) ); const payload_0 = { onChange, "data-path": getDataPath(name, path_2) }; if (withError) { payload_0.error = $errors.errorsState[path_2]; } if (type === "checkbox") { payload_0[mode === "controlled" ? "checked" : "defaultChecked"] = getPath( path_2, $values.refValues.current ); } else { payload_0[mode === "controlled" ? "value" : "defaultValue"] = getPath( path_2, $values.refValues.current ); } if (withFocus) { payload_0.onFocus = () => $status.setFieldTouched(path_2, true); payload_0.onBlur = () => { if (shouldValidateOnChange(path_2, validateInputOnBlur)) { const validationResults_0 = validateFieldValue(path_2, rules, $values.refValues.current); validationResults_0.hasError ? $errors.setFieldError(path_2, validationResults_0.error) : $errors.clearFieldError(path_2); } }; } return Object.assign( payload_0, enhanceGetInputProps?.({ inputProps: payload_0, field: path_2, options: { type, withError, withFocus, ...otherOptions }, form }) ); }; const onSubmit = (handleSubmit, handleValidationFailure) => (event) => { event?.preventDefault(); const results_1 = validate(); if (results_1.hasErrors) { handleValidationFailure?.(results_1.errors, $values.refValues.current, event); } else { handleSubmit?.(transformValues($values.refValues.current), event); } }; const getTransformedValues = (input) => transformValues(input || $values.refValues.current); const onReset = useCallback((event_0) => { event_0.preventDefault(); reset(); }, []); const isValid = useCallback( (path_3) => path_3 ? !validateFieldValue(path_3, rules, $values.refValues.current).hasError : !validateValues(rules, $values.refValues.current).hasErrors, [rules] ); const key_2 = (path_4) => `${formKey}-${path_4}-${fieldKeys[path_4] || 0}`; const getInputNode = useCallback( (path_5) => document.querySelector(`[data-path="${getDataPath(name, path_5)}"]`), [] ); const form = { watch: $watch.watch, initialized: $values.initialized.current, values: $values.stateValues, getValues: $values.getValues, setInitialValues: $values.setValuesSnapshot, initialize, setValues, setFieldValue, errors: $errors.errorsState, setErrors: $errors.setErrors, setFieldError: $errors.setFieldError, clearFieldError: $errors.clearFieldError, clearErrors: $errors.clearErrors, resetDirty: $status.resetDirty, setTouched: $status.setTouched, setDirty: $status.setDirty, isTouched: $status.isTouched, resetTouched: $status.resetTouched, isDirty: $status.isDirty, getTouched: $status.getTouched, getDirty: $status.getDirty, reorderListItem: $list.reorderListItem, insertListItem: $list.insertListItem, removeListItem: $list.removeListItem, reset, validate, validateField, getInputProps, onSubmit, onReset, isValid, getTransformedValues, key: key_2, getInputNode }; useFormActions(name, form); return form; } function createFormContext() { const FormContext = createContext(null); function FormProvider(t0) { const $ = c(3); const { form, children } = t0; let t1; if ($[0] !== form || $[1] !== children) { t1 = /* @__PURE__ */ jsx(FormContext.Provider, { value: form, children }); $[0] = form; $[1] = children; $[2] = t1; } else { t1 = $[2]; } return t1; } function useFormContext() { const ctx = useContext(FormContext); if (!ctx) { throw new Error( "useFormContext was called outside of FormProvider context" ); } return ctx; } return [FormProvider, useFormContext, useForm]; } const Form = forwardRef( (t0, ref) => { const $ = c(16); let onSubmit; let form; let onReset; let others; if ($[0] !== t0) { ({ form, onSubmit, onReset, ...others } = t0); $[0] = t0; $[1] = onSubmit; $[2] = form; $[3] = onReset; $[4] = others; } else { onSubmit = $[1]; form = $[2]; onReset = $[3]; others = $[4]; } let t1; if ($[5] !== onSubmit || $[6] !== form) { t1 = form.onSubmit(typeof onSubmit === "function" ? onSubmit : _temp); $[5] = onSubmit; $[6] = form; $[7] = t1; } else { t1 = $[7]; } let t2; if ($[8] !== onReset || $[9] !== form) { t2 = (event) => { onReset?.(event); form.onReset(event); }; $[8] = onReset; $[9] = form; $[10] = t2; } else { t2 = $[10]; } let t3; if ($[11] !== others || $[12] !== t1 || $[13] !== t2 || $[14] !== ref) { t3 = /* @__PURE__ */ jsx( "form", { ...others, onSubmit: t1, onReset: t2, ref } ); $[11] = others; $[12] = t1; $[13] = t2; $[14] = ref; $[15] = t3; } else { t3 = $[15]; } return t3; } ); function _temp() { } function isNotEmpty(error) { const _error = error || true; return (value) => { if (typeof value === "string") { return value.trim().length > 0 ? null : _error; } if (Array.isArray(value)) { return value.length > 0 ? null : _error; } if (value === null || value === void 0) { return _error; } if (value === false) { return _error; } return null; }; } function matches(regexp, error) { const _error = error || true; return (value) => { if (typeof value !== "string") { return _error; } return regexp.test(value) ? null : _error; }; } function isEmail(error) { return matches(/^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/, error); } function isLengthValid(payload, value) { if (typeof payload === "number") { return value.length === payload; } const { max, min } = payload; let valid = true; if (typeof max === "number" && value.length > max) { valid = false; } if (typeof min === "number" && value.length < min) { valid = false; } return valid; } function hasLength(payload, error) { const _error = error || true; return (value) => { if (typeof value === "string") { return isLengthValid(payload, value.trim()) ? null : _error; } if (typeof value === "object" && value !== null && "length" in value) { return isLengthValid(payload, value) ? null : _error; } return _error; }; } function isInRange({ min, max }, error) { const _error = error || true; return (value) => { if (typeof value !== "number") { return _error; } let valid = true; if (typeof min === "number" && value < min) { valid = false; } if (typeof max === "number" && value > max) { valid = false; } return valid ? null : _error; }; } function matchesField(field, error) { const _error = error || true; return (value, values) => { if (!values || !(field in values)) { return _error; } return value === values[field] ? null : _error; }; } function useField({ mode = "controlled", clearErrorOnChange = true, initialValue, initialError = null, initialTouched = false, onValueChange, validateOnChange = false, validateOnBlur = false, validate, resolveValidationError, type = "input" }) { const [valueState, setValueState] = useState(initialValue); const valueRef = useRef(valueState); const [key, setKey] = useState(0); const [error, setError] = useState(initialError || null); const touchedRef = useRef(initialTouched || false); const [, setTouchedState] = useState(touchedRef.current); const [isValidating, setIsValidating] = useState(false); const errorResolver = useMemo( () => resolveValidationError || ((err) => err), [resolveValidationError] ); const setTouched = useCallback((val, { updateState = mode === "controlled" } = {}) => { touchedRef.current = val; updateState && setTouchedState(val); }, []); const setValue = useCallback( async (value, { updateKey = mode === "uncontrolled", updateState: updateState_0 = mode === "controlled" } = {}) => { if (valueRef.current === value) { return; } valueRef.current = value; onValueChange?.(value); if (clearErrorOnChange && error !== null) { setError(null); } if (updateState_0) { setValueState(value); } if (updateKey) { setKey((currentKey) => currentKey + 1); } if (validateOnChange) { _validate(); } }, [error, clearErrorOnChange] ); const reset = useCallback(() => { setValue(initialValue); setError(null); setTouched(false); }, [initialValue]); const getValue = useCallback(() => valueRef.current, []); const isTouched = useCallback(() => touchedRef.current, []); const isDirty = useCallback(() => valueRef.current !== initialValue, [initialValue]); const _validate = useCallback(async () => { const validationResult = validate?.(valueRef.current); if (validationResult instanceof Promise) { setIsValidating(true); try { const result = await validationResult; setIsValidating(false); setError(result); } catch (err_0) { setIsValidating(false); const resolvedError = errorResolver(err_0); setError(resolvedError); return resolvedError; } } else { setError(validationResult); return validationResult; } }, []); const getInputProps = ({ withError = true, withFocus = true } = {}) => { const onChange = getInputOnChange((val_0) => setValue(val_0, { updateKey: false })); const payload = { onChange }; if (withError) { payload.error = error; } if (type === "checkbox") { payload[mode === "controlled" ? "checked" : "defaultChecked"] = valueRef.current; } else { payload[mode === "controlled" ? "value" : "defaultValue"] = valueRef.current; } if (withFocus) { payload.onFocus = () => { setTouched(true); }; payload.onBlur = () => { if (shouldValidateOnChange("", !!validateOnBlur)) { _validate(); } }; } return payload; }; const resetTouched = useCallback(() => setTouched(false), []); return { key, getValue, setValue, reset, getInputProps, isValidating, validate: _validate, error, setError, isTouched, isDirty, resetTouched }; } function zodResolver(schema) { return (values) => { const parsed = schema.safeParse(values); if (parsed.success) { return {}; } const results = {}; parsed.error.errors.forEach((error) => { results[error.path.join(".")] = error.message; }); return results; }; } function superstructResolver(schema) { function structValidation(values) { const formErrors = {}; const [err] = schema.validate(values); if (!err) { return formErrors; } err.failures().forEach((fieldFailure) => { const fieldName = fieldFailure.path.join(" "); formErrors[fieldFailure.path.join(".")] = `${fieldName}: ${fieldFailure.message}`; }); return formErrors; } return structValidation; } function yupResolver(schema) { const _schema = schema; return (values) => { try { _schema.validateSync(values, { abortEarly: false }); return {}; } catch (_yupError) { const yupError = _yupError; const results = {}; yupError.inner.forEach((error) => { results[error.path.replaceAll("[", ".").replaceAll("]", "")] = error.message; }); return results; } }; } function joiResolver(schema, options) { const _schema = schema; return (values) => { const parsed = _schema.validate(values, { abortEarly: false, ...options }); if (!parsed.error) { return {}; } const results = {}; parsed.error.details.forEach((error) => { results[error.path.join(".")] = error.message; }); return results; }; } export { FORM_INDEX, Form, createFormActions, createFormContext, hasLength, isEmail, isInRange, isNotEmpty, joiResolver, matches, matchesField, superstructResolver, useField, useForm, yupResolver, zodResolver };