remix-validated-form 4.1.4 → 4.1.7
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/.turbo/turbo-build.log +2 -2
- package/browser/ValidatedForm.js +31 -36
- package/browser/hooks.js +13 -16
- package/browser/internal/customState.d.ts +105 -0
- package/browser/internal/customState.js +46 -0
- package/browser/internal/getInputProps.js +4 -14
- package/browser/internal/hooks.d.ts +14 -15
- package/browser/internal/hooks.js +37 -39
- package/browser/internal/logic/elementUtils.d.ts +3 -0
- package/browser/internal/logic/elementUtils.js +3 -0
- package/browser/internal/logic/setInputValueInForm.js +9 -52
- package/browser/internal/setFieldValue.d.ts +0 -0
- package/browser/internal/setFieldValue.js +0 -0
- package/browser/internal/setFormValues.d.ts +0 -0
- package/browser/internal/setFormValues.js +0 -0
- package/browser/internal/state.d.ts +339 -238
- package/browser/internal/state.js +59 -72
- package/browser/internal/watch.d.ts +18 -0
- package/browser/internal/watch.js +122 -0
- package/browser/unreleased/formStateHooks.d.ts +39 -0
- package/browser/unreleased/formStateHooks.js +54 -0
- package/browser/userFacingFormContext.d.ts +4 -0
- package/browser/userFacingFormContext.js +9 -23
- package/build/ValidatedForm.js +30 -35
- package/build/hooks.js +11 -14
- package/build/internal/getInputProps.js +4 -14
- package/build/internal/hooks.d.ts +14 -15
- package/build/internal/hooks.js +39 -41
- package/build/internal/logic/elementUtils.d.ts +3 -0
- package/build/internal/logic/elementUtils.js +9 -0
- package/build/internal/logic/setInputValueInForm.js +12 -55
- package/build/internal/setFormValues.d.ts +0 -0
- package/build/internal/setFormValues.js +0 -0
- package/build/internal/state/controlledFields.js +11 -2
- package/build/internal/state.d.ts +339 -238
- package/build/internal/state.js +61 -77
- package/build/internal/watch.d.ts +20 -0
- package/build/internal/watch.js +126 -0
- package/build/unreleased/formStateHooks.d.ts +39 -0
- package/build/unreleased/formStateHooks.js +59 -0
- package/build/userFacingFormContext.d.ts +4 -0
- package/build/userFacingFormContext.js +9 -23
- package/package.json +1 -2
- package/src/ValidatedForm.tsx +48 -52
- package/src/hooks.ts +15 -26
- package/src/internal/getInputProps.ts +4 -14
- package/src/internal/hooks.ts +60 -72
- package/src/internal/hydratable.ts +28 -0
- package/src/internal/logic/getCheckboxChecked.ts +10 -0
- package/src/internal/logic/getRadioChecked.ts +7 -0
- package/src/internal/state/atomUtils.ts +13 -0
- package/src/internal/state.ts +99 -177
- package/src/unreleased/formStateHooks.ts +113 -0
- package/src/userFacingFormContext.ts +18 -53
package/build/internal/state.js
CHANGED
@@ -3,90 +3,74 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
3
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
4
4
|
};
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
6
|
-
exports.
|
6
|
+
exports.fieldDefaultValueAtom = exports.fieldErrorAtom = exports.fieldTouchedAtom = exports.setFieldErrorAtom = exports.setTouchedAtom = exports.endSubmitAtom = exports.startSubmitAtom = exports.resetAtom = exports.isValidAtom = exports.cleanupFormState = exports.formElementAtom = exports.formPropsAtom = exports.touchedFieldsAtom = exports.fieldErrorsAtom = exports.hasBeenSubmittedAtom = exports.isSubmittingAtom = exports.isHydratedAtom = exports.ATOM_SCOPE = void 0;
|
7
7
|
const jotai_1 = require("jotai");
|
8
|
-
const immer_1 = require("jotai/immer");
|
9
8
|
const utils_1 = require("jotai/utils");
|
10
|
-
const
|
9
|
+
const omit_1 = __importDefault(require("lodash/omit"));
|
10
|
+
const atomUtils_1 = require("./state/atomUtils");
|
11
11
|
exports.ATOM_SCOPE = Symbol("remix-validated-form-scope");
|
12
|
-
exports.
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
formId: typeof formId === "string" ? formId : undefined,
|
19
|
-
// Will change upon hydration -- these will never actually be used
|
12
|
+
exports.isHydratedAtom = (0, atomUtils_1.formAtomFamily)(false);
|
13
|
+
exports.isSubmittingAtom = (0, atomUtils_1.formAtomFamily)(false);
|
14
|
+
exports.hasBeenSubmittedAtom = (0, atomUtils_1.formAtomFamily)(false);
|
15
|
+
exports.fieldErrorsAtom = (0, atomUtils_1.formAtomFamily)({});
|
16
|
+
exports.touchedFieldsAtom = (0, atomUtils_1.formAtomFamily)({});
|
17
|
+
exports.formPropsAtom = (0, atomUtils_1.formAtomFamily)({
|
20
18
|
validateField: () => Promise.resolve(null),
|
21
19
|
registerReceiveFocus: () => () => { },
|
20
|
+
defaultValues: {},
|
21
|
+
});
|
22
|
+
exports.formElementAtom = (0, atomUtils_1.formAtomFamily)(null);
|
23
|
+
//// Everything below is derived from the above
|
24
|
+
const cleanupFormState = (formId) => {
|
25
|
+
[
|
26
|
+
exports.isHydratedAtom,
|
27
|
+
exports.isSubmittingAtom,
|
28
|
+
exports.hasBeenSubmittedAtom,
|
29
|
+
exports.fieldErrorsAtom,
|
30
|
+
exports.touchedFieldsAtom,
|
31
|
+
exports.formPropsAtom,
|
32
|
+
].forEach((formAtom) => formAtom.remove(formId));
|
33
|
+
};
|
34
|
+
exports.cleanupFormState = cleanupFormState;
|
35
|
+
exports.isValidAtom = (0, utils_1.atomFamily)((formId) => (0, jotai_1.atom)((get) => Object.keys(get((0, exports.fieldErrorsAtom)(formId))).length === 0));
|
36
|
+
exports.resetAtom = (0, utils_1.atomFamily)((formId) => (0, jotai_1.atom)(null, (_get, set) => {
|
37
|
+
set((0, exports.fieldErrorsAtom)(formId), {});
|
38
|
+
set((0, exports.touchedFieldsAtom)(formId), {});
|
39
|
+
set((0, exports.hasBeenSubmittedAtom)(formId), false);
|
22
40
|
}));
|
23
|
-
|
24
|
-
exports.
|
25
|
-
|
26
|
-
exports.fieldTouchedAtom = fieldTouchedAtom;
|
27
|
-
const fieldDefaultValueAtom = (name) => (formAtom) => (0, utils_1.selectAtom)(formAtom, (formState) => formState.defaultValues && (0, get_1.default)(formState.defaultValues, name));
|
28
|
-
exports.fieldDefaultValueAtom = fieldDefaultValueAtom;
|
29
|
-
// Selector atoms
|
30
|
-
const formSelectorAtom = (selector) => (formAtom) => (0, utils_1.selectAtom)(formAtom, selector);
|
31
|
-
exports.formSelectorAtom = formSelectorAtom;
|
32
|
-
exports.fieldErrorsAtom = (0, exports.formSelectorAtom)((state) => state.fieldErrors);
|
33
|
-
exports.touchedFieldsAtom = (0, exports.formSelectorAtom)((state) => state.touchedFields);
|
34
|
-
exports.actionAtom = (0, exports.formSelectorAtom)((state) => state.action);
|
35
|
-
exports.hasBeenSubmittedAtom = (0, exports.formSelectorAtom)((state) => state.hasBeenSubmitted);
|
36
|
-
exports.validateFieldAtom = (0, exports.formSelectorAtom)((state) => state.validateField);
|
37
|
-
exports.registerReceiveFocusAtom = (0, exports.formSelectorAtom)((state) => state.registerReceiveFocus);
|
38
|
-
exports.isSubmittingAtom = (0, exports.formSelectorAtom)((state) => state.isSubmitting);
|
39
|
-
exports.defaultValuesAtom = (0, exports.formSelectorAtom)((state) => state.defaultValues);
|
40
|
-
exports.isValidAtom = (0, exports.formSelectorAtom)((state) => { var _a; return Object.keys((_a = state.fieldErrors) !== null && _a !== void 0 ? _a : {}).length === 0; });
|
41
|
-
exports.isHydratedAtom = (0, exports.formSelectorAtom)((state) => state.hydrated);
|
42
|
-
exports.clearErrorAtom = (0, jotai_1.atom)(null, (get, set, { name, formAtom }) => set(formAtom, (state) => {
|
43
|
-
var _a;
|
44
|
-
(_a = state.fieldErrors) === null || _a === void 0 ? true : delete _a[name];
|
45
|
-
return state;
|
41
|
+
exports.startSubmitAtom = (0, utils_1.atomFamily)((formId) => (0, jotai_1.atom)(null, (_get, set) => {
|
42
|
+
set((0, exports.isSubmittingAtom)(formId), true);
|
43
|
+
set((0, exports.hasBeenSubmittedAtom)(formId), true);
|
46
44
|
}));
|
47
|
-
exports.
|
48
|
-
|
49
|
-
state.fieldErrors = {};
|
50
|
-
state.fieldErrors[name] = error;
|
51
|
-
return state;
|
45
|
+
exports.endSubmitAtom = (0, utils_1.atomFamily)((formId) => (0, jotai_1.atom)(null, (_get, set) => {
|
46
|
+
set((0, exports.isSubmittingAtom)(formId), false);
|
52
47
|
}));
|
53
|
-
exports.
|
54
|
-
|
55
|
-
|
48
|
+
exports.setTouchedAtom = (0, utils_1.atomFamily)((formId) => (0, jotai_1.atom)(null, (get, set, { field, touched }) => {
|
49
|
+
const prev = get((0, exports.touchedFieldsAtom)(formId));
|
50
|
+
if (prev[field] !== touched) {
|
51
|
+
set((0, exports.touchedFieldsAtom)(formId), {
|
52
|
+
...prev,
|
53
|
+
[field]: touched,
|
54
|
+
});
|
55
|
+
}
|
56
56
|
}));
|
57
|
-
exports.
|
58
|
-
|
59
|
-
|
57
|
+
exports.setFieldErrorAtom = (0, utils_1.atomFamily)((formId) => (0, jotai_1.atom)(null, (get, set, { field, error }) => {
|
58
|
+
const prev = get((0, exports.fieldErrorsAtom)(formId));
|
59
|
+
if (error === undefined && field in prev) {
|
60
|
+
set((0, exports.fieldErrorsAtom)(formId), (0, omit_1.default)(prev, field));
|
61
|
+
}
|
62
|
+
if (error !== undefined && prev[field] !== error) {
|
63
|
+
set((0, exports.fieldErrorsAtom)(formId), {
|
64
|
+
...get((0, exports.fieldErrorsAtom)(formId)),
|
65
|
+
[field]: error,
|
66
|
+
});
|
67
|
+
}
|
60
68
|
}));
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
});
|
69
|
-
exports.startSubmitAtom = (0, jotai_1.atom)(null, (get, set, { formAtom }) => {
|
70
|
-
set(formAtom, (state) => {
|
71
|
-
state.hasBeenSubmitted = true;
|
72
|
-
state.isSubmitting = true;
|
73
|
-
return state;
|
74
|
-
});
|
75
|
-
});
|
76
|
-
exports.endSubmitAtom = (0, jotai_1.atom)(null, (get, set, { formAtom }) => {
|
77
|
-
set(formAtom, (state) => {
|
78
|
-
state.isSubmitting = false;
|
79
|
-
return state;
|
80
|
-
});
|
81
|
-
});
|
82
|
-
exports.syncFormContextAtom = (0, jotai_1.atom)(null, (get, set, { defaultValues, action, subaction, formAtom, validateField, registerReceiveFocus, }) => {
|
83
|
-
set(formAtom, (state) => {
|
84
|
-
state.defaultValues = defaultValues;
|
85
|
-
state.action = action;
|
86
|
-
state.subaction = subaction;
|
87
|
-
state.registerReceiveFocus = registerReceiveFocus;
|
88
|
-
state.validateField = validateField;
|
89
|
-
state.hydrated = true;
|
90
|
-
return state;
|
91
|
-
});
|
92
|
-
});
|
69
|
+
//// Field specific
|
70
|
+
exports.fieldTouchedAtom = (0, atomUtils_1.fieldAtomFamily)(({ formId, field }) => (0, jotai_1.atom)((get) => get((0, exports.touchedFieldsAtom)(formId))[field], (_get, set, touched) => {
|
71
|
+
set((0, exports.setTouchedAtom)(formId), { field, touched });
|
72
|
+
}));
|
73
|
+
exports.fieldErrorAtom = (0, atomUtils_1.fieldAtomFamily)(({ formId, field }) => (0, jotai_1.atom)((get) => get((0, exports.fieldErrorsAtom)(formId))[field], (_get, set, error) => {
|
74
|
+
set((0, exports.setFieldErrorAtom)(formId), { field, error });
|
75
|
+
}));
|
76
|
+
exports.fieldDefaultValueAtom = (0, atomUtils_1.fieldAtomFamily)(({ formId, field }) => (0, utils_1.selectAtom)((0, exports.formPropsAtom)(formId), (state) => state.defaultValues[field]));
|
@@ -0,0 +1,20 @@
|
|
1
|
+
declare type ParseInfo = {
|
2
|
+
value: unknown;
|
3
|
+
type: string;
|
4
|
+
isRepeated: boolean;
|
5
|
+
checked?: boolean;
|
6
|
+
};
|
7
|
+
declare type BaseWatchOptions<T> = {
|
8
|
+
formId?: string;
|
9
|
+
parse?: (info: ParseInfo) => T;
|
10
|
+
};
|
11
|
+
declare type UseWatchType = {
|
12
|
+
<T>(name: string, options?: BaseWatchOptions<T> & {
|
13
|
+
repeatable?: false;
|
14
|
+
}): T;
|
15
|
+
<T>(name: string, options?: BaseWatchOptions<T> & {
|
16
|
+
repeatable: true;
|
17
|
+
}): T[];
|
18
|
+
};
|
19
|
+
export declare const useWatch: UseWatchType;
|
20
|
+
export {};
|
@@ -0,0 +1,126 @@
|
|
1
|
+
"use strict";
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
4
|
+
};
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
6
|
+
exports.useWatch = void 0;
|
7
|
+
const jotai_1 = require("jotai");
|
8
|
+
const utils_1 = require("jotai/utils");
|
9
|
+
const isNaN_1 = __importDefault(require("lodash/isNaN"));
|
10
|
+
const react_1 = require("react");
|
11
|
+
const tiny_invariant_1 = __importDefault(require("tiny-invariant"));
|
12
|
+
const hooks_1 = require("./hooks");
|
13
|
+
const elementUtils_1 = require("./logic/elementUtils");
|
14
|
+
const state_1 = require("./state");
|
15
|
+
const atomUtils_1 = require("./state/atomUtils");
|
16
|
+
const controlledFields_1 = require("./state/controlledFields");
|
17
|
+
const emptyAtom = (0, jotai_1.atom)(undefined); // Always empty -- just used as a default value
|
18
|
+
const watchControlledFieldAtom = (0, atomUtils_1.fieldAtomFamily)(({ field, formId }) => (0, utils_1.selectAtom)((0, controlledFields_1.controlledFieldsAtom)(formId), (fields) => {
|
19
|
+
var _a;
|
20
|
+
return ({
|
21
|
+
present: field in fields,
|
22
|
+
valueAtom: (_a = fields[field]) !== null && _a !== void 0 ? _a : emptyAtom,
|
23
|
+
});
|
24
|
+
}));
|
25
|
+
const defaultParse = ({ value, type, isRepeated, checked, }) => {
|
26
|
+
if (type === "number") {
|
27
|
+
const result = Number(value);
|
28
|
+
if ((0, isNaN_1.default)(result))
|
29
|
+
throw new Error("Value is not a number");
|
30
|
+
return result;
|
31
|
+
}
|
32
|
+
if (type === "checkbox" && !isRepeated) {
|
33
|
+
return checked;
|
34
|
+
}
|
35
|
+
return value;
|
36
|
+
};
|
37
|
+
const getInputValues = (node, multipleInputs = false) => {
|
38
|
+
if (!node)
|
39
|
+
return [];
|
40
|
+
if (node instanceof RadioNodeList) {
|
41
|
+
return [...node].flatMap((el) => getInputValues(el, true));
|
42
|
+
}
|
43
|
+
if ((0, elementUtils_1.isMultiselect)(node)) {
|
44
|
+
return [
|
45
|
+
{
|
46
|
+
type: "select",
|
47
|
+
value: [...node.options]
|
48
|
+
.filter((opt) => opt.selected)
|
49
|
+
.map((opt) => opt.value),
|
50
|
+
},
|
51
|
+
];
|
52
|
+
}
|
53
|
+
if ((0, elementUtils_1.isCheckbox)(node)) {
|
54
|
+
if (node.checked || !multipleInputs)
|
55
|
+
return [{ type: "checkbox", value: node.value, checked: node.checked }];
|
56
|
+
return [];
|
57
|
+
}
|
58
|
+
if ((0, elementUtils_1.isRadio)(node)) {
|
59
|
+
if (node.checked)
|
60
|
+
return [{ type: "radio", value: node.value, checked: node.checked }];
|
61
|
+
return [];
|
62
|
+
}
|
63
|
+
const input = node;
|
64
|
+
return [{ type: input.type, value: input.value, checked: input.checked }];
|
65
|
+
};
|
66
|
+
const useWatch = (field, { formId, parse = defaultParse, repeatable = false, } = {}) => {
|
67
|
+
const context = (0, hooks_1.useInternalFormContext)(formId, "useWatch");
|
68
|
+
const defaultValue = (0, hooks_1.useFieldDefaultValue)(field, context);
|
69
|
+
const hasSynced = (0, react_1.useRef)(false);
|
70
|
+
const [inputValues, setValue] = (0, react_1.useState)([]);
|
71
|
+
const formElement = (0, hooks_1.useFormAtomValue)((0, state_1.formElementAtom)(context.formId));
|
72
|
+
const controlledField = (0, hooks_1.useFormAtomValue)(watchControlledFieldAtom({ formId: context.formId, field }));
|
73
|
+
const controlledValue = (0, hooks_1.useFormAtomValue)(controlledField.valueAtom);
|
74
|
+
const shouldSyncNativeInputValue = !controlledField.present && formElement;
|
75
|
+
const syncFieldValue = (0, react_1.useCallback)(() => {
|
76
|
+
(0, tiny_invariant_1.default)(formElement, `Unable to find form element for form. Watching field ${field}`);
|
77
|
+
hasSynced.current = true;
|
78
|
+
// We pull the values out using `form.elements` instead of `FormData`
|
79
|
+
// so that we can access the `type` of the input.
|
80
|
+
setValue(getInputValues(formElement.elements.namedItem(field)));
|
81
|
+
}, [field, formElement]);
|
82
|
+
// Should set the field values after the initial render
|
83
|
+
(0, react_1.useEffect)(() => {
|
84
|
+
if (shouldSyncNativeInputValue)
|
85
|
+
syncFieldValue();
|
86
|
+
}, [
|
87
|
+
controlledField.present,
|
88
|
+
formElement,
|
89
|
+
shouldSyncNativeInputValue,
|
90
|
+
syncFieldValue,
|
91
|
+
]);
|
92
|
+
(0, react_1.useEffect)(() => {
|
93
|
+
if (shouldSyncNativeInputValue) {
|
94
|
+
const listener = async (event) => {
|
95
|
+
if (!(event.target instanceof HTMLElement))
|
96
|
+
return;
|
97
|
+
const target = event.target;
|
98
|
+
const { form: targetForm, name: targetName } = target;
|
99
|
+
if (targetForm === formElement && targetName === field) {
|
100
|
+
syncFieldValue();
|
101
|
+
}
|
102
|
+
};
|
103
|
+
window.addEventListener("change", listener);
|
104
|
+
window.addEventListener("input", listener);
|
105
|
+
return () => {
|
106
|
+
window.removeEventListener("change", listener);
|
107
|
+
window.removeEventListener("input", listener);
|
108
|
+
};
|
109
|
+
}
|
110
|
+
}, [field, formElement, shouldSyncNativeInputValue, syncFieldValue]);
|
111
|
+
const parsedValue = (0, react_1.useMemo)(() => {
|
112
|
+
const parsed = inputValues.map(({ type, value, checked }) => parse({
|
113
|
+
value,
|
114
|
+
type,
|
115
|
+
isRepeated: inputValues.length > 1 || repeatable,
|
116
|
+
checked,
|
117
|
+
}));
|
118
|
+
return parsed.length > 1 || repeatable ? parsed : parsed[0];
|
119
|
+
}, [parse, repeatable, inputValues]);
|
120
|
+
if (controlledField.present)
|
121
|
+
return controlledValue;
|
122
|
+
if (!hasSynced.current)
|
123
|
+
return defaultValue !== null && defaultValue !== void 0 ? defaultValue : (repeatable ? [] : undefined);
|
124
|
+
return parsedValue;
|
125
|
+
};
|
126
|
+
exports.useWatch = useWatch;
|
@@ -0,0 +1,39 @@
|
|
1
|
+
import { FieldErrors, TouchedFields } from "../validation/types";
|
2
|
+
export declare type FormState = {
|
3
|
+
fieldErrors: FieldErrors;
|
4
|
+
isSubmitting: boolean;
|
5
|
+
hasBeenSubmitted: boolean;
|
6
|
+
touchedFields: TouchedFields;
|
7
|
+
defaultValues: {
|
8
|
+
[fieldName: string]: any;
|
9
|
+
};
|
10
|
+
action?: string;
|
11
|
+
subaction?: string;
|
12
|
+
isValid: boolean;
|
13
|
+
};
|
14
|
+
/**
|
15
|
+
* Returns information about the form.
|
16
|
+
*
|
17
|
+
* @param formId the id of the form. Only necessary if being used outside a ValidatedForm.
|
18
|
+
*/
|
19
|
+
export declare const useFormState: (formId?: string | undefined) => FormState;
|
20
|
+
export declare type FormHelpers = {
|
21
|
+
/**
|
22
|
+
* Clear the error of the specified field.
|
23
|
+
*/
|
24
|
+
clearError: (fieldName: string) => void;
|
25
|
+
/**
|
26
|
+
* Validate the specified field.
|
27
|
+
*/
|
28
|
+
validateField: (fieldName: string) => Promise<string | null>;
|
29
|
+
/**
|
30
|
+
* Change the touched state of the specified field.
|
31
|
+
*/
|
32
|
+
setTouched: (fieldName: string, touched: boolean) => void;
|
33
|
+
};
|
34
|
+
/**
|
35
|
+
* Returns helpers that can be used to update the form state.
|
36
|
+
*
|
37
|
+
* @param formId the id of the form. Only necessary if being used outside a ValidatedForm.
|
38
|
+
*/
|
39
|
+
export declare const useFormHelpers: (formId?: string | undefined) => FormHelpers;
|
@@ -0,0 +1,59 @@
|
|
1
|
+
"use strict";
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
3
|
+
exports.useFormHelpers = exports.useFormState = void 0;
|
4
|
+
const react_1 = require("react");
|
5
|
+
const hooks_1 = require("../internal/hooks");
|
6
|
+
const state_1 = require("../internal/state");
|
7
|
+
/**
|
8
|
+
* Returns information about the form.
|
9
|
+
*
|
10
|
+
* @param formId the id of the form. Only necessary if being used outside a ValidatedForm.
|
11
|
+
*/
|
12
|
+
const useFormState = (formId) => {
|
13
|
+
const formContext = (0, hooks_1.useInternalFormContext)(formId, "useIsValid");
|
14
|
+
const formProps = (0, hooks_1.useFormAtomValue)((0, state_1.formPropsAtom)(formContext.formId));
|
15
|
+
const isSubmitting = (0, hooks_1.useFormAtomValue)((0, state_1.isSubmittingAtom)(formContext.formId));
|
16
|
+
const hasBeenSubmitted = (0, hooks_1.useFormAtomValue)((0, state_1.hasBeenSubmittedAtom)(formContext.formId));
|
17
|
+
const touchedFields = (0, hooks_1.useFormAtomValue)((0, state_1.touchedFieldsAtom)(formContext.formId));
|
18
|
+
const isValid = (0, hooks_1.useFormAtomValue)((0, state_1.isValidAtom)(formContext.formId));
|
19
|
+
const defaultValuesToUse = (0, hooks_1.useDefaultValuesForForm)(formContext);
|
20
|
+
const hydratedDefaultValues = defaultValuesToUse.hydrateTo(formProps.defaultValues);
|
21
|
+
const fieldErrorsFromState = (0, hooks_1.useFormAtomValue)((0, state_1.fieldErrorsAtom)(formContext.formId));
|
22
|
+
const fieldErrorsToUse = (0, hooks_1.useFieldErrorsForForm)(formContext);
|
23
|
+
const hydratedFieldErrors = fieldErrorsToUse.hydrateTo(fieldErrorsFromState);
|
24
|
+
return (0, react_1.useMemo)(() => ({
|
25
|
+
...formProps,
|
26
|
+
defaultValues: hydratedDefaultValues,
|
27
|
+
fieldErrors: hydratedFieldErrors !== null && hydratedFieldErrors !== void 0 ? hydratedFieldErrors : {},
|
28
|
+
hasBeenSubmitted,
|
29
|
+
isSubmitting,
|
30
|
+
touchedFields,
|
31
|
+
isValid,
|
32
|
+
}), [
|
33
|
+
formProps,
|
34
|
+
hasBeenSubmitted,
|
35
|
+
hydratedDefaultValues,
|
36
|
+
hydratedFieldErrors,
|
37
|
+
isSubmitting,
|
38
|
+
isValid,
|
39
|
+
touchedFields,
|
40
|
+
]);
|
41
|
+
};
|
42
|
+
exports.useFormState = useFormState;
|
43
|
+
/**
|
44
|
+
* Returns helpers that can be used to update the form state.
|
45
|
+
*
|
46
|
+
* @param formId the id of the form. Only necessary if being used outside a ValidatedForm.
|
47
|
+
*/
|
48
|
+
const useFormHelpers = (formId) => {
|
49
|
+
const formContext = (0, hooks_1.useInternalFormContext)(formId, "useFormHelpers");
|
50
|
+
const setTouched = (0, hooks_1.useSetTouched)(formContext);
|
51
|
+
const { validateField } = (0, hooks_1.useFormAtomValue)((0, state_1.formPropsAtom)(formContext.formId));
|
52
|
+
const clearError = (0, hooks_1.useClearError)(formContext);
|
53
|
+
return (0, react_1.useMemo)(() => ({
|
54
|
+
setTouched,
|
55
|
+
validateField,
|
56
|
+
clearError,
|
57
|
+
}), [clearError, setTouched, validateField]);
|
58
|
+
};
|
59
|
+
exports.useFormHelpers = useFormHelpers;
|
@@ -2,42 +2,28 @@
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
3
3
|
exports.useFormContext = void 0;
|
4
4
|
const react_1 = require("react");
|
5
|
-
const hooks_1 = require("./hooks");
|
6
|
-
const hooks_2 = require("./internal/hooks");
|
5
|
+
const hooks_1 = require("./internal/hooks");
|
7
6
|
const state_1 = require("./internal/state");
|
7
|
+
const formStateHooks_1 = require("./unreleased/formStateHooks");
|
8
8
|
/**
|
9
9
|
* Provides access to some of the internal state of the form.
|
10
10
|
*/
|
11
11
|
const useFormContext = (formId) => {
|
12
12
|
// Try to access context so we get our error specific to this hook if it's not there
|
13
|
-
const context = (0,
|
14
|
-
const
|
15
|
-
const
|
16
|
-
const
|
17
|
-
const isValid = (0, hooks_1.useIsValid)(formId);
|
18
|
-
const defaultValues = (0, hooks_2.useHydratableSelector)(context, state_1.defaultValuesAtom, (0, hooks_2.useDefaultValuesForForm)(context));
|
19
|
-
const fieldErrors = (0, hooks_2.useHydratableSelector)(context, state_1.fieldErrorsAtom, (0, hooks_2.useFieldErrorsForForm)(context));
|
20
|
-
const setFieldTouched = (0, hooks_2.useSetTouched)(context);
|
21
|
-
const touchedFields = (0, hooks_2.useContextSelectAtom)(context.formId, state_1.touchedFieldsAtom);
|
22
|
-
const validateField = (0, hooks_2.useContextSelectAtom)(context.formId, state_1.validateFieldAtom);
|
23
|
-
const registerReceiveFocus = (0, hooks_2.useContextSelectAtom)(context.formId, state_1.registerReceiveFocusAtom);
|
24
|
-
const internalClearError = (0, hooks_2.useClearError)(context);
|
13
|
+
const context = (0, hooks_1.useInternalFormContext)(formId, "useFormContext");
|
14
|
+
const state = (0, formStateHooks_1.useFormState)(formId);
|
15
|
+
const { clearError: internalClearError, setTouched, validateField, } = (0, formStateHooks_1.useFormHelpers)(formId);
|
16
|
+
const { registerReceiveFocus } = (0, hooks_1.useFormAtomValue)((0, state_1.formPropsAtom)(context.formId));
|
25
17
|
const clearError = (0, react_1.useCallback)((...names) => {
|
26
18
|
names.forEach((name) => {
|
27
19
|
internalClearError(name);
|
28
20
|
});
|
29
21
|
}, [internalClearError]);
|
30
22
|
return {
|
31
|
-
|
32
|
-
|
33
|
-
isValid,
|
34
|
-
defaultValues,
|
35
|
-
clearError,
|
36
|
-
fieldErrors: fieldErrors !== null && fieldErrors !== void 0 ? fieldErrors : {},
|
37
|
-
action,
|
38
|
-
setFieldTouched,
|
39
|
-
touchedFields,
|
23
|
+
...state,
|
24
|
+
setFieldTouched: setTouched,
|
40
25
|
validateField,
|
26
|
+
clearError,
|
41
27
|
registerReceiveFocus,
|
42
28
|
};
|
43
29
|
};
|
package/package.json
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
{
|
2
2
|
"name": "remix-validated-form",
|
3
|
-
"version": "4.1.
|
3
|
+
"version": "4.1.7",
|
4
4
|
"description": "Form component and utils for easy form validation in remix",
|
5
5
|
"browser": "./browser/index.js",
|
6
6
|
"main": "./build/index.js",
|
@@ -48,7 +48,6 @@
|
|
48
48
|
"typescript": "^4.5.3"
|
49
49
|
},
|
50
50
|
"dependencies": {
|
51
|
-
"immer": "^9.0.12",
|
52
51
|
"jotai": "^1.5.3",
|
53
52
|
"lodash": "^4.17.21",
|
54
53
|
"tiny-invariant": "^1.2.0"
|