remix-validated-form 4.1.4-beta.0 → 4.1.6
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.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.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 +14 -53
@@ -5,27 +5,19 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
6
6
|
exports.createGetInputProps = void 0;
|
7
7
|
const omitBy_1 = __importDefault(require("lodash/omitBy"));
|
8
|
+
const getCheckboxChecked_1 = require("./logic/getCheckboxChecked");
|
9
|
+
const getRadioChecked_1 = require("./logic/getRadioChecked");
|
8
10
|
const defaultValidationBehavior = {
|
9
11
|
initial: "onBlur",
|
10
12
|
whenTouched: "onChange",
|
11
13
|
whenSubmitted: "onChange",
|
12
14
|
};
|
13
|
-
const getCheckboxDefaultChecked = (value, defaultValue) => {
|
14
|
-
if (Array.isArray(defaultValue))
|
15
|
-
return defaultValue.includes(value);
|
16
|
-
if (typeof defaultValue === "boolean")
|
17
|
-
return defaultValue;
|
18
|
-
if (typeof defaultValue === "string")
|
19
|
-
return defaultValue === value;
|
20
|
-
return undefined;
|
21
|
-
};
|
22
15
|
const createGetInputProps = ({ clearError, validate, defaultValue, touched, setTouched, hasBeenSubmitted, validationBehavior, name, }) => {
|
23
16
|
const validationBehaviors = {
|
24
17
|
...defaultValidationBehavior,
|
25
18
|
...validationBehavior,
|
26
19
|
};
|
27
20
|
return (props = {}) => {
|
28
|
-
var _a, _b;
|
29
21
|
const behavior = hasBeenSubmitted
|
30
22
|
? validationBehaviors.whenSubmitted
|
31
23
|
: touched
|
@@ -51,12 +43,10 @@ const createGetInputProps = ({ clearError, validate, defaultValue, touched, setT
|
|
51
43
|
name,
|
52
44
|
};
|
53
45
|
if (props.type === "checkbox") {
|
54
|
-
|
55
|
-
inputProps.defaultChecked = getCheckboxDefaultChecked(value, defaultValue);
|
46
|
+
inputProps.defaultChecked = (0, getCheckboxChecked_1.getCheckboxChecked)(props.value, defaultValue);
|
56
47
|
}
|
57
48
|
else if (props.type === "radio") {
|
58
|
-
|
59
|
-
inputProps.defaultChecked = defaultValue === value;
|
49
|
+
inputProps.defaultChecked = (0, getRadioChecked_1.getRadioChecked)(props.value, defaultValue);
|
60
50
|
}
|
61
51
|
else {
|
62
52
|
inputProps.defaultValue = defaultValue;
|
@@ -1,22 +1,21 @@
|
|
1
|
-
import { Atom } from "jotai";
|
1
|
+
import { Atom, WritableAtom } from "jotai";
|
2
2
|
import { useUpdateAtom } from "jotai/utils";
|
3
|
-
import { ValidationErrorResponseData } from "..";
|
3
|
+
import { FieldErrors, ValidationErrorResponseData } from "..";
|
4
4
|
import { InternalFormContextValue } from "./formContext";
|
5
|
-
import {
|
6
|
-
declare
|
7
|
-
declare const
|
5
|
+
import { Hydratable } from "./hydratable";
|
6
|
+
export declare const useFormUpdateAtom: typeof useUpdateAtom;
|
7
|
+
export declare const useFormAtom: <Value, Update, Result extends void | Promise<void>>(anAtom: WritableAtom<Value, Update, Result>) => [Value extends Promise<infer V> ? V : Value, import("jotai/core/atom").SetAtom<Update, Result>];
|
8
|
+
export declare const useFormAtomValue: <Value>(anAtom: Atom<Value>) => Value extends Promise<infer V> ? V : Value;
|
8
9
|
export declare const useInternalFormContext: (formId?: string | symbol | undefined, hookName?: string | undefined) => InternalFormContextValue;
|
9
|
-
export declare const useContextSelectAtom: <T>(formId: string | symbol, selectorAtomCreator: FormSelectorAtomCreator<T>) => T extends Promise<infer V> ? V : T;
|
10
|
-
export declare const useHydratableSelector: <T, U>({ formId }: InternalFormContextValue, atomCreator: FormSelectorAtomCreator<T>, dataToUse: U | typeof USE_HYDRATED_STATE, selector?: (data: U) => T) => T | (T extends Promise<infer V> ? V : T);
|
11
10
|
export declare function useErrorResponseForForm({ fetcher, subaction, formId, }: InternalFormContextValue): ValidationErrorResponseData | null;
|
12
|
-
export declare const useFieldErrorsForForm: (context: InternalFormContextValue) =>
|
11
|
+
export declare const useFieldErrorsForForm: (context: InternalFormContextValue) => Hydratable<FieldErrors | undefined>;
|
13
12
|
export declare const useDefaultValuesFromLoader: ({ formId, }: InternalFormContextValue) => any;
|
14
|
-
export declare const useDefaultValuesForForm: (context: InternalFormContextValue) =>
|
13
|
+
export declare const useDefaultValuesForForm: (context: InternalFormContextValue) => Hydratable<{
|
14
|
+
[fieldName: string]: any;
|
15
|
+
}>;
|
15
16
|
export declare const useHasActiveFormSubmit: ({ fetcher, }: InternalFormContextValue) => boolean;
|
16
|
-
export declare const useFieldTouched: (
|
17
|
-
export declare const useFieldError: (name: string, context: InternalFormContextValue) => string | undefined;
|
17
|
+
export declare const useFieldTouched: (field: string, { formId }: InternalFormContextValue) => [boolean, (update: boolean) => void];
|
18
|
+
export declare const useFieldError: (name: string, context: InternalFormContextValue) => readonly [string | undefined, (update?: string | undefined) => void];
|
18
19
|
export declare const useFieldDefaultValue: (name: string, context: InternalFormContextValue) => any;
|
19
|
-
export declare const
|
20
|
-
export declare const
|
21
|
-
export declare const useSetTouched: (context: InternalFormContextValue) => (name: string, touched: boolean) => void;
|
22
|
-
export {};
|
20
|
+
export declare const useClearError: ({ formId }: InternalFormContextValue) => (name: string) => void;
|
21
|
+
export declare const useSetTouched: ({ formId }: InternalFormContextValue) => (name: string, touched: boolean) => void;
|
package/build/internal/hooks.js
CHANGED
@@ -3,36 +3,32 @@ 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.useSetTouched = exports.useClearError = exports.
|
6
|
+
exports.useSetTouched = exports.useClearError = exports.useFieldDefaultValue = exports.useFieldError = exports.useFieldTouched = exports.useHasActiveFormSubmit = exports.useDefaultValuesForForm = exports.useDefaultValuesFromLoader = exports.useFieldErrorsForForm = exports.useErrorResponseForForm = exports.useInternalFormContext = exports.useFormAtomValue = exports.useFormAtom = exports.useFormUpdateAtom = void 0;
|
7
7
|
const react_1 = require("@remix-run/react");
|
8
|
+
const jotai_1 = require("jotai");
|
8
9
|
const utils_1 = require("jotai/utils");
|
9
10
|
const get_1 = __importDefault(require("lodash/get"));
|
10
|
-
const identity_1 = __importDefault(require("lodash/identity"));
|
11
11
|
const react_2 = require("react");
|
12
|
+
const tiny_invariant_1 = __importDefault(require("tiny-invariant"));
|
12
13
|
const constants_1 = require("./constants");
|
13
14
|
const formContext_1 = require("./formContext");
|
15
|
+
const hydratable_1 = require("./hydratable");
|
14
16
|
const state_1 = require("./state");
|
15
|
-
const
|
17
|
+
const useFormUpdateAtom = (atom) => (0, utils_1.useUpdateAtom)(atom, state_1.ATOM_SCOPE);
|
18
|
+
exports.useFormUpdateAtom = useFormUpdateAtom;
|
19
|
+
const useFormAtom = (anAtom) => (0, jotai_1.useAtom)(anAtom, state_1.ATOM_SCOPE);
|
20
|
+
exports.useFormAtom = useFormAtom;
|
21
|
+
const useFormAtomValue = (anAtom) => (0, utils_1.useAtomValue)(anAtom, state_1.ATOM_SCOPE);
|
22
|
+
exports.useFormAtomValue = useFormAtomValue;
|
16
23
|
const useInternalFormContext = (formId, hookName) => {
|
17
24
|
const formContext = (0, react_2.useContext)(formContext_1.InternalFormContext);
|
18
25
|
if (formId)
|
19
26
|
return { formId };
|
20
27
|
if (formContext)
|
21
28
|
return formContext;
|
22
|
-
throw new Error(`Unable to determine form for ${hookName}. Please use it inside a
|
29
|
+
throw new Error(`Unable to determine form for ${hookName}. Please use it inside a ValidatedForm or pass a 'formId'.`);
|
23
30
|
};
|
24
31
|
exports.useInternalFormContext = useInternalFormContext;
|
25
|
-
const useContextSelectAtom = (formId, selectorAtomCreator) => {
|
26
|
-
const formAtom = (0, state_1.formRegistry)(formId);
|
27
|
-
const selectorAtom = (0, react_2.useMemo)(() => selectorAtomCreator(formAtom), [formAtom, selectorAtomCreator]);
|
28
|
-
return (0, utils_1.useAtomValue)(selectorAtom, state_1.ATOM_SCOPE);
|
29
|
-
};
|
30
|
-
exports.useContextSelectAtom = useContextSelectAtom;
|
31
|
-
const useHydratableSelector = ({ formId }, atomCreator, dataToUse, selector = identity_1.default) => {
|
32
|
-
const dataFromState = (0, exports.useContextSelectAtom)(formId, atomCreator);
|
33
|
-
return dataToUse === USE_HYDRATED_STATE ? dataFromState : selector(dataToUse);
|
34
|
-
};
|
35
|
-
exports.useHydratableSelector = useHydratableSelector;
|
36
32
|
function useErrorResponseForForm({ fetcher, subaction, formId, }) {
|
37
33
|
var _a;
|
38
34
|
const actionData = (0, react_1.useActionData)();
|
@@ -54,8 +50,8 @@ function useErrorResponseForForm({ fetcher, subaction, formId, }) {
|
|
54
50
|
exports.useErrorResponseForForm = useErrorResponseForForm;
|
55
51
|
const useFieldErrorsForForm = (context) => {
|
56
52
|
const response = useErrorResponseForForm(context);
|
57
|
-
const hydrated = (0, exports.
|
58
|
-
return
|
53
|
+
const hydrated = (0, exports.useFormAtomValue)((0, state_1.isHydratedAtom)(context.formId));
|
54
|
+
return hydratable_1.hydratable.from(response === null || response === void 0 ? void 0 : response.fieldErrors, hydrated);
|
59
55
|
};
|
60
56
|
exports.useFieldErrorsForForm = useFieldErrorsForForm;
|
61
57
|
const useDefaultValuesFromLoader = ({ formId, }) => {
|
@@ -74,7 +70,7 @@ const useDefaultValuesFromLoader = ({ formId, }) => {
|
|
74
70
|
exports.useDefaultValuesFromLoader = useDefaultValuesFromLoader;
|
75
71
|
const useDefaultValuesForForm = (context) => {
|
76
72
|
const { formId, defaultValuesProp } = context;
|
77
|
-
const hydrated = (0, exports.
|
73
|
+
const hydrated = (0, exports.useFormAtomValue)((0, state_1.isHydratedAtom)(formId));
|
78
74
|
const errorResponse = useErrorResponseForForm(context);
|
79
75
|
const defaultValuesFromLoader = (0, exports.useDefaultValuesFromLoader)(context);
|
80
76
|
// Typical flow is:
|
@@ -83,12 +79,14 @@ const useDefaultValuesForForm = (context) => {
|
|
83
79
|
// - State gets hydrated with default values
|
84
80
|
// - After submit, we may need to use values from the error
|
85
81
|
if (hydrated)
|
86
|
-
return
|
87
|
-
if (errorResponse === null || errorResponse === void 0 ? void 0 : errorResponse.repopulateFields)
|
88
|
-
|
82
|
+
return hydratable_1.hydratable.hydratedData();
|
83
|
+
if (errorResponse === null || errorResponse === void 0 ? void 0 : errorResponse.repopulateFields) {
|
84
|
+
(0, tiny_invariant_1.default)(typeof errorResponse.repopulateFields === "object", "repopulateFields returned something other than an object");
|
85
|
+
return hydratable_1.hydratable.serverData(errorResponse.repopulateFields);
|
86
|
+
}
|
89
87
|
if (defaultValuesProp)
|
90
|
-
return defaultValuesProp;
|
91
|
-
return defaultValuesFromLoader;
|
88
|
+
return hydratable_1.hydratable.serverData(defaultValuesProp);
|
89
|
+
return hydratable_1.hydratable.serverData(defaultValuesFromLoader);
|
92
90
|
};
|
93
91
|
exports.useDefaultValuesForForm = useDefaultValuesForForm;
|
94
92
|
const useHasActiveFormSubmit = ({ fetcher, }) => {
|
@@ -99,32 +97,32 @@ const useHasActiveFormSubmit = ({ fetcher, }) => {
|
|
99
97
|
return hasActiveSubmission;
|
100
98
|
};
|
101
99
|
exports.useHasActiveFormSubmit = useHasActiveFormSubmit;
|
102
|
-
const useFieldTouched = (
|
103
|
-
const atomCreator = (0, react_2.useMemo)(() => (0, state_1.fieldTouchedAtom)(name), [name]);
|
104
|
-
return (0, exports.useContextSelectAtom)(formId, atomCreator);
|
105
|
-
};
|
100
|
+
const useFieldTouched = (field, { formId }) => (0, exports.useFormAtom)((0, state_1.fieldTouchedAtom)({ formId, field }));
|
106
101
|
exports.useFieldTouched = useFieldTouched;
|
107
102
|
const useFieldError = (name, context) => {
|
108
|
-
|
103
|
+
const fieldErrors = (0, exports.useFieldErrorsForForm)(context);
|
104
|
+
const [state, set] = (0, exports.useFormAtom)((0, state_1.fieldErrorAtom)({ formId: context.formId, field: name }));
|
105
|
+
return [
|
106
|
+
fieldErrors.map((fieldErrors) => fieldErrors === null || fieldErrors === void 0 ? void 0 : fieldErrors[name]).hydrateTo(state),
|
107
|
+
set,
|
108
|
+
];
|
109
109
|
};
|
110
110
|
exports.useFieldError = useFieldError;
|
111
111
|
const useFieldDefaultValue = (name, context) => {
|
112
|
-
|
112
|
+
const defaultValues = (0, exports.useDefaultValuesForForm)(context);
|
113
|
+
const { defaultValues: state } = (0, exports.useFormAtomValue)((0, state_1.formPropsAtom)(context.formId));
|
114
|
+
return defaultValues
|
115
|
+
.map((val) => (0, get_1.default)(val, name))
|
116
|
+
.hydrateTo(state[name]);
|
113
117
|
};
|
114
118
|
exports.useFieldDefaultValue = useFieldDefaultValue;
|
115
|
-
const
|
116
|
-
exports.useFormUpdateAtom
|
117
|
-
|
118
|
-
const clearError = (0, exports.useFormUpdateAtom)(state_1.clearErrorAtom);
|
119
|
-
return (0, react_2.useCallback)((name) => {
|
120
|
-
clearError({ name, formAtom: (0, state_1.formRegistry)(context.formId) });
|
121
|
-
}, [clearError, context.formId]);
|
119
|
+
const useClearError = ({ formId }) => {
|
120
|
+
const updateError = (0, exports.useFormUpdateAtom)((0, state_1.setFieldErrorAtom)(formId));
|
121
|
+
return (0, react_2.useCallback)((name) => updateError({ field: name, error: undefined }), [updateError]);
|
122
122
|
};
|
123
123
|
exports.useClearError = useClearError;
|
124
|
-
const useSetTouched = (
|
125
|
-
const setTouched = (0, exports.useFormUpdateAtom)(state_1.setTouchedAtom);
|
126
|
-
return (0, react_2.useCallback)((name, touched) => {
|
127
|
-
setTouched({ name, formAtom: (0, state_1.formRegistry)(context.formId), touched });
|
128
|
-
}, [setTouched, context.formId]);
|
124
|
+
const useSetTouched = ({ formId }) => {
|
125
|
+
const setTouched = (0, exports.useFormUpdateAtom)((0, state_1.setTouchedAtom)(formId));
|
126
|
+
return (0, react_2.useCallback)((name, touched) => setTouched({ field: name, touched }), [setTouched]);
|
129
127
|
};
|
130
128
|
exports.useSetTouched = useSetTouched;
|
@@ -0,0 +1,9 @@
|
|
1
|
+
"use strict";
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
3
|
+
exports.isRadio = exports.isCheckbox = exports.isMultiselect = void 0;
|
4
|
+
const isMultiselect = (node) => node instanceof HTMLSelectElement && node.multiple;
|
5
|
+
exports.isMultiselect = isMultiselect;
|
6
|
+
const isCheckbox = (node) => node instanceof HTMLInputElement && node.type === "checkbox";
|
7
|
+
exports.isCheckbox = isCheckbox;
|
8
|
+
const isRadio = (node) => node instanceof HTMLInputElement && node.type === "radio";
|
9
|
+
exports.isRadio = isRadio;
|
@@ -5,24 +5,23 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
6
6
|
exports.setInputValueInForm = void 0;
|
7
7
|
const tiny_invariant_1 = __importDefault(require("tiny-invariant"));
|
8
|
+
const elementUtils_1 = require("./elementUtils");
|
8
9
|
const getCheckboxChecked_1 = require("./getCheckboxChecked");
|
9
10
|
/**
|
10
11
|
* Helper class to track the values being set on uncontrolled fields.
|
11
12
|
* HTML is super permissive with inputs that all share the same `name`.
|
12
|
-
*
|
13
|
-
* This class is strict in the sense that, if the user provides an array value,
|
14
|
-
* the values inside the array must be in the same order as the elements in the DOM.
|
15
|
-
* Doing this allows us to be flexible with what types of form controls the user is using.
|
16
|
-
*
|
17
|
-
* This is how HTML tracks inputs of the same name as well.
|
18
|
-
* `new FormData(formElement).getAll('myField')` will return values in DOM order.
|
19
13
|
*/
|
20
14
|
class Values {
|
21
15
|
constructor(values) {
|
22
16
|
this.hasSetRadioValue = false;
|
17
|
+
this.remove = (value) => {
|
18
|
+
const index = this.values.indexOf(value);
|
19
|
+
const deleted = this.values.splice(index, 1);
|
20
|
+
return deleted.length > 0;
|
21
|
+
};
|
23
22
|
this.bool = (value) => {
|
24
|
-
if ((0, getCheckboxChecked_1.getCheckboxChecked)(value, this.values
|
25
|
-
this.
|
23
|
+
if ((0, getCheckboxChecked_1.getCheckboxChecked)(value, this.values)) {
|
24
|
+
this.remove(value) || this.remove(true);
|
26
25
|
return true;
|
27
26
|
}
|
28
27
|
return false;
|
@@ -47,44 +46,18 @@ class Values {
|
|
47
46
|
this.values = unknownValues;
|
48
47
|
}
|
49
48
|
}
|
50
|
-
/**
|
51
|
-
* This subclass is order-permissive, meaning the user doesn't have to worry about
|
52
|
-
* the order in which the inputs occur in the DOM.
|
53
|
-
* This is useful for multiselects and checkbox groups and provides a better DX than
|
54
|
-
* the order-strict version.
|
55
|
-
*/
|
56
|
-
class PermissiveValues extends Values {
|
57
|
-
constructor() {
|
58
|
-
super(...arguments);
|
59
|
-
this.remove = (value) => {
|
60
|
-
const index = this.values.indexOf(value);
|
61
|
-
const deleted = this.values.splice(index, 1);
|
62
|
-
return deleted.length > 0;
|
63
|
-
};
|
64
|
-
this.bool = (value) => {
|
65
|
-
if ((0, getCheckboxChecked_1.getCheckboxChecked)(value, this.values)) {
|
66
|
-
this.remove(value) || this.remove(true);
|
67
|
-
return true;
|
68
|
-
}
|
69
|
-
return false;
|
70
|
-
};
|
71
|
-
}
|
72
|
-
}
|
73
|
-
const isMultiselect = (node) => node instanceof HTMLSelectElement && node.multiple;
|
74
|
-
const isCheckbox = (node) => node instanceof HTMLInputElement && node.type === "checkbox";
|
75
|
-
const isRadio = (node) => node instanceof HTMLInputElement && node.type === "radio";
|
76
49
|
const setElementValue = (element, values, field) => {
|
77
|
-
if (isMultiselect(element)) {
|
50
|
+
if ((0, elementUtils_1.isMultiselect)(element)) {
|
78
51
|
for (const option of element.options) {
|
79
52
|
option.selected = values.bool(option.value);
|
80
53
|
}
|
81
54
|
return;
|
82
55
|
}
|
83
|
-
if (isCheckbox(element)) {
|
56
|
+
if ((0, elementUtils_1.isCheckbox)(element)) {
|
84
57
|
element.checked = values.bool(element.value);
|
85
58
|
return;
|
86
59
|
}
|
87
|
-
if (isRadio(element)) {
|
60
|
+
if ((0, elementUtils_1.isRadio)(element)) {
|
88
61
|
element.checked = values.radio(element.value);
|
89
62
|
return;
|
90
63
|
}
|
@@ -92,34 +65,18 @@ const setElementValue = (element, values, field) => {
|
|
92
65
|
(0, tiny_invariant_1.default)(input.type !== "hidden", `Cannot set value on hidden input if it is not a controlled field. Field being updated was ${field}.`);
|
93
66
|
input.value = values.str();
|
94
67
|
};
|
95
|
-
const areElementsTheSameType = (nodes) => {
|
96
|
-
const getType = (node) => {
|
97
|
-
if (node instanceof HTMLInputElement)
|
98
|
-
return node.type;
|
99
|
-
if (node instanceof HTMLSelectElement)
|
100
|
-
return node.multiple ? "select" : "multiselect";
|
101
|
-
return null;
|
102
|
-
};
|
103
|
-
const firstElementInstance = nodes[0].constructor;
|
104
|
-
const firstElementType = getType(nodes[0]);
|
105
|
-
return nodes.every((element) => element.constructor === firstElementInstance &&
|
106
|
-
getType(element) === firstElementType);
|
107
|
-
};
|
108
68
|
const setInputValueInForm = (formElement, name, value) => {
|
109
69
|
const controlElement = formElement.elements.namedItem(name);
|
110
70
|
if (!controlElement)
|
111
71
|
return;
|
72
|
+
const values = new Values(value);
|
112
73
|
if (controlElement instanceof RadioNodeList) {
|
113
|
-
const values = areElementsTheSameType([...controlElement])
|
114
|
-
? new PermissiveValues(value)
|
115
|
-
: new Values(value);
|
116
74
|
for (const element of controlElement) {
|
117
75
|
setElementValue(element, values, name);
|
118
76
|
}
|
119
77
|
values.warnIfLeftovers(name);
|
120
78
|
}
|
121
79
|
else {
|
122
|
-
const values = new PermissiveValues(value);
|
123
80
|
setElementValue(controlElement, values, name);
|
124
81
|
values.warnIfLeftovers(name);
|
125
82
|
}
|
File without changes
|
File without changes
|
@@ -15,10 +15,18 @@ const refCountAtom = (0, atomUtils_1.fieldAtomFamily)(() => (0, jotai_1.atom)(0)
|
|
15
15
|
const fieldValueAtom = (0, atomUtils_1.fieldAtomFamily)(() => (0, jotai_1.atom)(undefined));
|
16
16
|
const fieldValueHydratedAtom = (0, atomUtils_1.fieldAtomFamily)(() => (0, jotai_1.atom)(false));
|
17
17
|
const pendingValidateAtom = (0, atomUtils_1.fieldAtomFamily)(() => (0, jotai_1.atom)(undefined));
|
18
|
-
const valueSerializerAtom = (0, atomUtils_1.fieldAtomFamily)(() => (0, jotai_1.atom)({
|
18
|
+
const valueSerializerAtom = (0, atomUtils_1.fieldAtomFamily)(() => (0, jotai_1.atom)({
|
19
|
+
serializer: (value) => {
|
20
|
+
if (value === undefined)
|
21
|
+
return "";
|
22
|
+
return JSON.stringify(value);
|
23
|
+
},
|
24
|
+
}));
|
19
25
|
const registerAtom = (0, jotai_1.atom)(null, (get, set, { formId, field }) => {
|
20
26
|
set(refCountAtom({ formId, field }), (prev) => prev + 1);
|
21
27
|
const newRefCount = get(refCountAtom({ formId, field }));
|
28
|
+
// We don't set hydrated here because it gets set when we know
|
29
|
+
// we have the right default values
|
22
30
|
if (newRefCount === 1) {
|
23
31
|
set((0, exports.controlledFieldsAtom)(formId), (prev) => ({
|
24
32
|
...prev,
|
@@ -33,6 +41,7 @@ const unregisterAtom = (0, jotai_1.atom)(null, (get, set, { formId, field }) =>
|
|
33
41
|
set((0, exports.controlledFieldsAtom)(formId), (prev) => (0, omit_1.default)(prev, field));
|
34
42
|
fieldValueAtom.remove({ formId, field });
|
35
43
|
pendingValidateAtom.remove({ formId, field });
|
44
|
+
fieldValueHydratedAtom.remove({ formId, field });
|
36
45
|
}
|
37
46
|
});
|
38
47
|
exports.setControlledFieldValueAtom = (0, jotai_1.atom)(null, async (_get, set, { formId, field, value, }) => {
|
@@ -51,7 +60,7 @@ const useControlledFieldValue = (formId, field) => {
|
|
51
60
|
const [isFieldHydrated, setIsFieldHydrated] = (0, hooks_1.useFormAtom)(fieldValueHydratedAtom({ formId, field }));
|
52
61
|
(0, react_1.useEffect)(() => {
|
53
62
|
if (isHydrated && !isFieldHydrated) {
|
54
|
-
setValue(
|
63
|
+
setValue(defaultValue);
|
55
64
|
setIsFieldHydrated(true);
|
56
65
|
}
|
57
66
|
}, [
|