remix-validated-form
Version:
Form component and utils for easy form validation in remix
75 lines (74 loc) • 3.11 kB
JavaScript
import { Fragment as _Fragment, jsx as _jsx } from "react/jsx-runtime";
import { useMemo } from "react";
import { useCallback } from "react";
import invariant from "tiny-invariant";
import { useFieldDefaultValue, useFieldError, useInternalFormContext, useInternalHasBeenSubmitted, useValidateField, } from "../hooks";
import { useRegisterControlledField } from "./controlledFields";
import { useFormStore } from "./storeHooks";
const useInternalFieldArray = (context, field, validationBehavior) => {
const value = useFieldDefaultValue(field, context);
useRegisterControlledField(context, field);
const hasBeenSubmitted = useInternalHasBeenSubmitted(context.formId);
const validateField = useValidateField(context.formId);
const error = useFieldError(field, context);
const resolvedValidationBehavior = {
initial: "onSubmit",
whenSubmitted: "onChange",
...validationBehavior,
};
const behavior = hasBeenSubmitted
? resolvedValidationBehavior.whenSubmitted
: resolvedValidationBehavior.initial;
const maybeValidate = useCallback(() => {
if (behavior === "onChange") {
validateField(field);
}
}, [behavior, field, validateField]);
invariant(value === undefined || value === null || Array.isArray(value), `FieldArray: defaultValue value for ${field} must be an array, null, or undefined`);
const arr = useFormStore(context.formId, (state) => state.controlledFields.array);
const helpers = useMemo(() => ({
push: (item) => {
arr.push(field, item);
maybeValidate();
},
swap: (indexA, indexB) => {
arr.swap(field, indexA, indexB);
maybeValidate();
},
move: (from, to) => {
arr.move(field, from, to);
maybeValidate();
},
insert: (index, value) => {
arr.insert(field, index, value);
maybeValidate();
},
unshift: (value) => {
arr.unshift(field, value);
maybeValidate();
},
remove: (index) => {
arr.remove(field, index);
maybeValidate();
},
pop: () => {
arr.pop(field);
maybeValidate();
},
replace: (index, value) => {
arr.replace(field, index, value);
maybeValidate();
},
}), [arr, field, maybeValidate]);
const arrayValue = useMemo(() => value !== null && value !== void 0 ? value : [], [value]);
return [arrayValue, helpers, error];
};
export function useFieldArray(name, { formId, validationBehavior } = {}) {
const context = useInternalFormContext(formId, "FieldArray");
return useInternalFieldArray(context, name, validationBehavior);
}
export const FieldArray = ({ name, children, formId, validationBehavior, }) => {
const context = useInternalFormContext(formId, "FieldArray");
const [value, helpers, error] = useInternalFieldArray(context, name, validationBehavior);
return _jsx(_Fragment, { children: children(value, helpers, error) });
};