UNPKG

react-tiniest-form

Version:
120 lines (119 loc) 5.13 kB
import { useRef, useState } from 'react'; import { createFormsStore, parseToInputValue } from '../../utils/formStore/createFormStore'; import { invariantOf } from '../../utils/@common/invariantOf'; const useFormStore = (options) => { const formStore = useRef(createFormsStore(options)).current; const [snapshot, setSnapshot] = useState(formStore.store); const [errors, setErrors] = useState({}); const setError = (name, info) => { setErrors(errors => (Object.assign(Object.assign({}, errors), { [name]: Object.assign(Object.assign({}, errors[name]), info) }))); }; const deleteError = (name) => { if (errors[name]) { setErrors(errors => { const clonedErrors = structuredClone(errors); delete clonedErrors[name]; return clonedErrors; }); } }; const takeSnapShot = (name, value) => { setSnapshot(prev => (Object.assign(Object.assign({}, prev), { [name]: Object.assign(Object.assign({}, prev[name]), { value }) }))); }; return { store: formStore, snapshot, errors, setError, takeSnapShot, deleteError, }; }; const useForm = (options) => { const { store: { store, errors, registerField, getFieldValue, updateFieldValue, watchField, isWatching, validateField, getFieldInfo, }, errors: errorsSnapshot, setError, deleteError, takeSnapShot, } = useFormStore(options); const watch = (fieldsNames) => { return fieldsNames.reduce((acc, name) => { watchField(name); return Object.assign(Object.assign({}, acc), { /**@todo snapshot or getFieldValue */ [name]: getFieldValue(name) }); }, {}); }; const handleValidation = (name) => { return validateField({ name, onValid: () => deleteError(name), onInvalid: ({ type, message }) => { var _a; return (!errors[name] || ((_a = errorsSnapshot[name]) === null || _a === void 0 ? void 0 : _a.type) !== type) && setError(name, { type, message }); }, }); }; const register = (name, options) => { const isControlledValue = (options === null || options === void 0 ? void 0 : options.value) !== undefined; const controlledValue = parseToInputValue(options === null || options === void 0 ? void 0 : options.value); const onChange = (e) => { var _a; const { target: { value }, } = e; updateFieldValue(name, { value }); handleValidation(name); if (isWatching(name)) takeSnapShot(name, value); (_a = options === null || options === void 0 ? void 0 : options.onChange) === null || _a === void 0 ? void 0 : _a.call(options, e); }; const onBlur = (e) => { var _a; handleValidation(name); (_a = options === null || options === void 0 ? void 0 : options.onBlur) === null || _a === void 0 ? void 0 : _a.call(options, e); }; const ref = instance => { var _a; if (!instance) return; if (!((_a = getFieldInfo(name)) === null || _a === void 0 ? void 0 : _a.registered)) { const defaultValue = getFieldValue(name); registerField(name, { value: controlledValue || defaultValue, validations: options === null || options === void 0 ? void 0 : options.validations, ref: instance, }); instance.value = getFieldValue(name); } }; return Object.assign({ name, onChange, onBlur, ref }, (isControlledValue ? { value: controlledValue } : {})); }; const handleSubmit = (onValid, onInvalid) => { const onSubmit = (e) => { e.preventDefault(); const formData = new FormData(e.currentTarget); const formFields = Object.fromEntries(formData); /**@todo schema check */ const isAllValid = Object.keys(invariantOf(formFields)).every(name => { var _a; const info = getFieldInfo(name); /**@todo use store errors */ const isValid = handleValidation(name); if (!isValid) (_a = info === null || info === void 0 ? void 0 : info.ref) === null || _a === void 0 ? void 0 : _a.focus(); return isValid; }); isAllValid ? onValid === null || onValid === void 0 ? void 0 : onValid(formFields, e) : onInvalid === null || onInvalid === void 0 ? void 0 : onInvalid(errors, e); }; return onSubmit; }; const getFieldState = (name) => { const info = getFieldInfo(name); return info ? { isValid: info.isValid, ref: info.ref } : undefined; }; return { store, errors, setError, register, watch, handleSubmit, getFieldValue, getFieldState, }; }; export { useForm };