remix-validated-form 4.2.0 → 4.4.0
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 +15 -9
- package/README.md +1 -0
- package/browser/ValidatedForm.js +16 -26
- package/browser/hooks.d.ts +2 -0
- package/browser/hooks.js +20 -9
- package/browser/internal/MultiValueMap.d.ts +2 -0
- package/browser/internal/MultiValueMap.js +4 -0
- package/browser/internal/getInputProps.js +2 -1
- package/browser/internal/hooks.d.ts +20 -9
- package/browser/internal/hooks.js +32 -23
- package/browser/internal/logic/getRadioChecked.js +10 -0
- package/browser/internal/reset.d.ts +28 -0
- package/browser/internal/reset.js +13 -0
- package/browser/internal/state/cleanup.d.ts +2 -0
- package/browser/internal/state/cleanup.js +6 -0
- package/browser/internal/state/controlledFieldStore.d.ts +24 -0
- package/browser/internal/state/controlledFieldStore.js +57 -0
- package/browser/internal/state/controlledFields.d.ts +6 -62
- package/browser/internal/state/controlledFields.js +36 -63
- package/browser/internal/state/createFormStore.d.ts +40 -0
- package/browser/internal/state/createFormStore.js +83 -0
- package/browser/internal/state/storeFamily.d.ts +9 -0
- package/browser/internal/state/storeFamily.js +18 -0
- package/browser/internal/state/storeHooks.d.ts +5 -0
- package/browser/internal/state/storeHooks.js +10 -0
- package/browser/internal/state.d.ts +0 -27
- package/browser/internal/state.js +0 -5
- package/browser/unreleased/formStateHooks.d.ts +15 -0
- package/browser/unreleased/formStateHooks.js +23 -14
- package/browser/userFacingFormContext.d.ts +8 -0
- package/browser/userFacingFormContext.js +5 -4
- package/dist/remix-validated-form.cjs.js +17 -0
- package/dist/remix-validated-form.es.js +2844 -0
- package/dist/remix-validated-form.umd.js +17 -0
- package/{build → dist/types}/ValidatedForm.d.ts +0 -0
- package/{build → dist/types}/hooks.d.ts +2 -0
- package/{build → dist/types}/index.d.ts +0 -0
- package/{build → dist/types}/internal/MultiValueMap.d.ts +2 -0
- package/{build → dist/types}/internal/constants.d.ts +0 -0
- package/{build → dist/types}/internal/flatten.d.ts +0 -0
- package/{build → dist/types}/internal/formContext.d.ts +0 -0
- package/{build → dist/types}/internal/getInputProps.d.ts +0 -0
- package/dist/types/internal/hooks.d.ts +32 -0
- package/{build → dist/types}/internal/hydratable.d.ts +0 -0
- package/{build → dist/types}/internal/logic/getCheckboxChecked.d.ts +0 -0
- package/{build → dist/types}/internal/logic/getRadioChecked.d.ts +0 -0
- package/dist/types/internal/state/cleanup.d.ts +2 -0
- package/dist/types/internal/state/controlledFieldStore.d.ts +24 -0
- package/dist/types/internal/state/controlledFields.d.ts +6 -0
- package/dist/types/internal/state/createFormStore.d.ts +40 -0
- package/dist/types/internal/state/storeFamily.d.ts +9 -0
- package/dist/types/internal/state/storeHooks.d.ts +5 -0
- package/{build → dist/types}/internal/submissionCallbacks.d.ts +0 -0
- package/{build → dist/types}/internal/util.d.ts +0 -0
- package/{build → dist/types}/server.d.ts +0 -0
- package/{build → dist/types}/unreleased/formStateHooks.d.ts +15 -0
- package/{build → dist/types}/userFacingFormContext.d.ts +8 -0
- package/{build → dist/types}/validation/createValidator.d.ts +0 -0
- package/{build → dist/types}/validation/types.d.ts +0 -0
- package/package.json +11 -9
- package/src/ValidatedForm.tsx +25 -43
- package/src/hooks.ts +29 -17
- package/src/internal/MultiValueMap.ts +6 -0
- package/src/internal/getInputProps.test.ts +251 -0
- package/src/internal/getInputProps.ts +2 -1
- package/src/internal/hooks.ts +69 -45
- package/src/internal/logic/getRadioChecked.ts +11 -0
- package/src/internal/state/cleanup.ts +8 -0
- package/src/internal/state/controlledFieldStore.ts +91 -0
- package/src/internal/state/controlledFields.ts +78 -0
- package/src/internal/state/createFormStore.ts +152 -0
- package/src/internal/state/storeFamily.ts +24 -0
- package/src/internal/state/storeHooks.ts +22 -0
- package/src/unreleased/formStateHooks.ts +50 -27
- package/src/userFacingFormContext.ts +17 -5
- package/src/validation/validation.test.ts +304 -0
- package/tsconfig.json +4 -1
- package/vite.config.ts +7 -0
- package/.turbo/turbo-test.log +0 -11
- package/browser/components.d.ts +0 -7
- package/browser/components.js +0 -10
- package/browser/internal/SingleTypeMultiValueMap.d.ts +0 -9
- package/browser/internal/SingleTypeMultiValueMap.js +0 -41
- package/browser/internal/customState.d.ts +0 -105
- package/browser/internal/customState.js +0 -46
- package/browser/internal/hooks-valtio.d.ts +0 -18
- package/browser/internal/hooks-valtio.js +0 -110
- package/browser/internal/hooks-zustand.d.ts +0 -16
- package/browser/internal/hooks-zustand.js +0 -100
- package/browser/internal/immerMiddleware.d.ts +0 -6
- package/browser/internal/immerMiddleware.js +0 -7
- package/browser/internal/logic/elementUtils.d.ts +0 -3
- package/browser/internal/logic/elementUtils.js +0 -3
- package/browser/internal/logic/getCheckboxChecked copy.d.ts +0 -1
- package/browser/internal/logic/getCheckboxChecked copy.js +0 -9
- package/browser/internal/logic/setFieldValue.d.ts +0 -1
- package/browser/internal/logic/setFieldValue.js +0 -40
- package/browser/internal/logic/setInputValueInForm.d.ts +0 -1
- package/browser/internal/logic/setInputValueInForm.js +0 -77
- package/browser/internal/setFieldValue.d.ts +0 -20
- package/browser/internal/setFieldValue.js +0 -83
- package/browser/internal/setFormValues.d.ts +0 -2
- package/browser/internal/setFormValues.js +0 -26
- package/browser/internal/state/setFieldValue.d.ts +0 -0
- package/browser/internal/state/setFieldValue.js +0 -1
- package/browser/internal/state-valtio.d.ts +0 -62
- package/browser/internal/state-valtio.js +0 -69
- package/browser/internal/state-zustand.d.ts +0 -47
- package/browser/internal/state-zustand.js +0 -85
- package/browser/internal/test.d.ts +0 -0
- package/browser/internal/test.js +0 -15
- package/browser/internal/useMultiValueMap.d.ts +0 -1
- package/browser/internal/useMultiValueMap.js +0 -11
- package/browser/internal/watch.d.ts +0 -18
- package/browser/internal/watch.js +0 -122
- package/browser/lowLevelHooks.d.ts +0 -0
- package/browser/lowLevelHooks.js +0 -1
- package/browser/test-data/testFormData.d.ts +0 -15
- package/browser/test-data/testFormData.js +0 -46
- package/browser/types.d.ts +0 -1
- package/browser/types.js +0 -1
- package/browser/validation/validation.test.d.ts +0 -1
- package/browser/validation/validation.test.js +0 -274
- package/browser/validation/withYup.d.ts +0 -6
- package/browser/validation/withYup.js +0 -40
- package/browser/validation/withZod.d.ts +0 -6
- package/browser/validation/withZod.js +0 -50
- package/build/ValidatedForm.js +0 -257
- package/build/hooks.js +0 -79
- package/build/index.js +0 -18
- package/build/internal/MultiValueMap.js +0 -44
- package/build/internal/SingleTypeMultiValueMap.d.ts +0 -8
- package/build/internal/SingleTypeMultiValueMap.js +0 -45
- package/build/internal/constants.js +0 -7
- package/build/internal/flatten.js +0 -14
- package/build/internal/formContext.js +0 -5
- package/build/internal/getInputProps.js +0 -57
- package/build/internal/hooks-valtio.d.ts +0 -18
- package/build/internal/hooks-valtio.js +0 -128
- package/build/internal/hooks-zustand.d.ts +0 -16
- package/build/internal/hooks-zustand.js +0 -117
- package/build/internal/hooks.d.ts +0 -21
- package/build/internal/hooks.js +0 -128
- package/build/internal/hydratable.js +0 -17
- package/build/internal/immerMiddleware.d.ts +0 -6
- package/build/internal/immerMiddleware.js +0 -14
- package/build/internal/logic/elementUtils.d.ts +0 -3
- package/build/internal/logic/elementUtils.js +0 -9
- package/build/internal/logic/getCheckboxChecked.js +0 -13
- package/build/internal/logic/getRadioChecked.js +0 -9
- package/build/internal/logic/setFieldValue.d.ts +0 -1
- package/build/internal/logic/setFieldValue.js +0 -47
- package/build/internal/logic/setInputValueInForm.d.ts +0 -1
- package/build/internal/logic/setInputValueInForm.js +0 -84
- package/build/internal/setFormValues.d.ts +0 -2
- package/build/internal/setFormValues.js +0 -33
- package/build/internal/state/atomUtils.d.ts +0 -38
- package/build/internal/state/atomUtils.js +0 -13
- package/build/internal/state/controlledFields.d.ts +0 -62
- package/build/internal/state/controlledFields.js +0 -85
- package/build/internal/state-valtio.d.ts +0 -62
- package/build/internal/state-valtio.js +0 -83
- package/build/internal/state-zustand.d.ts +0 -47
- package/build/internal/state-zustand.js +0 -91
- package/build/internal/state.d.ts +0 -370
- package/build/internal/state.js +0 -76
- package/build/internal/submissionCallbacks.js +0 -17
- package/build/internal/test.d.ts +0 -1
- package/build/internal/test.js +0 -12
- package/build/internal/util.js +0 -41
- package/build/internal/watch.d.ts +0 -20
- package/build/internal/watch.js +0 -126
- package/build/server.js +0 -32
- package/build/types.d.ts +0 -1
- package/build/types.js +0 -2
- package/build/unreleased/formStateHooks.js +0 -59
- package/build/userFacingFormContext.js +0 -30
- package/build/validation/createValidator.js +0 -45
- package/build/validation/types.js +0 -2
- package/src/internal/state/atomUtils.ts +0 -13
- package/src/internal/state.ts +0 -132
@@ -1,20 +0,0 @@
|
|
1
|
-
import { InternalFormId } from "./state/atomUtils";
|
2
|
-
declare type ControlledDataItem = Record<string, unknown[]>;
|
3
|
-
declare class ValidatedFormData {
|
4
|
-
#private;
|
5
|
-
constructor(formData: FormData, customData: ControlledDataItem);
|
6
|
-
get: (fieldName: string) => any;
|
7
|
-
getAll: (fieldName: string) => any[];
|
8
|
-
has: (fieldName: string) => boolean;
|
9
|
-
append: (fieldName: string, value: any) => void;
|
10
|
-
delete: (fieldName: string) => void;
|
11
|
-
set: (fieldName: string, value: any) => void;
|
12
|
-
entries: () => IterableIterator<[string, any[]]>;
|
13
|
-
values: () => IterableIterator<any[]>;
|
14
|
-
[Symbol.iterator]: () => IterableIterator<[string, any[]]>;
|
15
|
-
setRepeated: (fieldName: string, value: any[]) => void;
|
16
|
-
changedFields(): Generator<readonly [string, any[]], void, unknown>;
|
17
|
-
}
|
18
|
-
export declare type FormValuesUpdater = (formData: ValidatedFormData) => void;
|
19
|
-
export declare const useSetFormValues: (formId: InternalFormId) => (arg: FormValuesUpdater) => Promise<void>;
|
20
|
-
export {};
|
@@ -1,83 +0,0 @@
|
|
1
|
-
var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) {
|
2
|
-
if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
|
3
|
-
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
|
4
|
-
return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
|
5
|
-
};
|
6
|
-
var _ValidatedFormData_data, _ValidatedFormData_updates, _a;
|
7
|
-
import { useAtomCallback } from "jotai/utils";
|
8
|
-
import groupBy from "lodash/groupBy";
|
9
|
-
import mapValues from "lodash/mapValues";
|
10
|
-
import invariant from "tiny-invariant";
|
11
|
-
import { setInputValueInForm } from "./logic/setInputValueInForm";
|
12
|
-
import { MultiValueMap } from "./MultiValueMap";
|
13
|
-
import { ATOM_SCOPE, formElementAtom } from "./state";
|
14
|
-
import { controlledFieldsAtom, setControlledFieldValueAtom, } from "./state/controlledFields";
|
15
|
-
class ValidatedFormData {
|
16
|
-
constructor(formData, customData) {
|
17
|
-
_ValidatedFormData_data.set(this, new MultiValueMap());
|
18
|
-
_ValidatedFormData_updates.set(this, new Map());
|
19
|
-
// API to mimic form data
|
20
|
-
this.get = (fieldName) => __classPrivateFieldGet(this, _ValidatedFormData_data, "f").getAll(fieldName)[0];
|
21
|
-
this.getAll = (fieldName) => __classPrivateFieldGet(this, _ValidatedFormData_data, "f").getAll(fieldName);
|
22
|
-
this.has = (fieldName) => __classPrivateFieldGet(this, _ValidatedFormData_data, "f").has(fieldName);
|
23
|
-
this.append = (fieldName, value) => {
|
24
|
-
__classPrivateFieldGet(this, _ValidatedFormData_data, "f").add(fieldName, value);
|
25
|
-
};
|
26
|
-
this.delete = (fieldName) => {
|
27
|
-
__classPrivateFieldGet(this, _ValidatedFormData_data, "f").delete(fieldName);
|
28
|
-
__classPrivateFieldGet(this, _ValidatedFormData_updates, "f").set(fieldName, true);
|
29
|
-
};
|
30
|
-
this.set = (fieldName, value) => {
|
31
|
-
__classPrivateFieldGet(this, _ValidatedFormData_data, "f").delete(fieldName);
|
32
|
-
__classPrivateFieldGet(this, _ValidatedFormData_data, "f").add(fieldName, value);
|
33
|
-
__classPrivateFieldGet(this, _ValidatedFormData_updates, "f").set(fieldName, true);
|
34
|
-
};
|
35
|
-
this.entries = () => __classPrivateFieldGet(this, _ValidatedFormData_data, "f").entries();
|
36
|
-
this.values = () => __classPrivateFieldGet(this, _ValidatedFormData_data, "f").values();
|
37
|
-
this[_a] = () => __classPrivateFieldGet(this, _ValidatedFormData_data, "f").entries();
|
38
|
-
// Custom APIs
|
39
|
-
this.setRepeated = (fieldName, value) => {
|
40
|
-
__classPrivateFieldGet(this, _ValidatedFormData_data, "f").delete(fieldName);
|
41
|
-
value.forEach((val) => __classPrivateFieldGet(this, _ValidatedFormData_data, "f").add(fieldName, val));
|
42
|
-
__classPrivateFieldGet(this, _ValidatedFormData_updates, "f").set(fieldName, true);
|
43
|
-
};
|
44
|
-
for (const [key, value] of formData.entries()) {
|
45
|
-
__classPrivateFieldGet(this, _ValidatedFormData_data, "f").add(key, value);
|
46
|
-
}
|
47
|
-
Object.entries(customData).forEach(([name, values]) => {
|
48
|
-
__classPrivateFieldGet(this, _ValidatedFormData_data, "f").delete(name);
|
49
|
-
values.forEach((value) => __classPrivateFieldGet(this, _ValidatedFormData_data, "f").add(name, value));
|
50
|
-
});
|
51
|
-
}
|
52
|
-
*changedFields() {
|
53
|
-
for (const updatedField of __classPrivateFieldGet(this, _ValidatedFormData_updates, "f").keys()) {
|
54
|
-
const value = this.getAll(updatedField);
|
55
|
-
yield [updatedField, value];
|
56
|
-
}
|
57
|
-
}
|
58
|
-
}
|
59
|
-
_ValidatedFormData_data = new WeakMap(), _ValidatedFormData_updates = new WeakMap(), _a = Symbol.iterator;
|
60
|
-
export const useSetFormValues = (formId) => useAtomCallback(async (get, set, update) => {
|
61
|
-
var _b;
|
62
|
-
const form = get(formElementAtom(formId));
|
63
|
-
invariant(form, "Unable to access form element when setting field value. This is likely a bug in remix-validated-form.");
|
64
|
-
const formData = new FormData(form);
|
65
|
-
const controlledFields = get(controlledFieldsAtom(formId));
|
66
|
-
const controlledData = mapValues(groupBy(controlledFields, (field) => field.name), (val) => val.map((field) => get(field.valueAtom)));
|
67
|
-
const validatedFormData = new ValidatedFormData(formData, controlledData);
|
68
|
-
update(validatedFormData);
|
69
|
-
for (const [field, value] of validatedFormData.changedFields()) {
|
70
|
-
const relevantFields = controlledFields.filter(({ name }) => name === field);
|
71
|
-
if (relevantFields.length === 0) {
|
72
|
-
setInputValueInForm(form, field, value);
|
73
|
-
return;
|
74
|
-
}
|
75
|
-
for (const [index, field] of relevantFields.entries()) {
|
76
|
-
const itemValue = (_b = value[index]) !== null && _b !== void 0 ? _b : "";
|
77
|
-
await set(setControlledFieldValueAtom, {
|
78
|
-
internalFieldId: field.internalId,
|
79
|
-
value: itemValue,
|
80
|
-
});
|
81
|
-
}
|
82
|
-
}
|
83
|
-
}, ATOM_SCOPE);
|
@@ -1,26 +0,0 @@
|
|
1
|
-
import { useAtomCallback } from "jotai/utils";
|
2
|
-
import { useCallback } from "react";
|
3
|
-
import invariant from "tiny-invariant";
|
4
|
-
import { setInputValueInForm } from "./logic/setInputValueInForm";
|
5
|
-
import { ATOM_SCOPE, formElementAtom } from "./state";
|
6
|
-
import { controlledFieldsAtom, setControlledFieldValueAtom, } from "./state/controlledFields";
|
7
|
-
export const useSetFormValues = (formId) => useAtomCallback(useCallback(async (get, set, updatedValues) => {
|
8
|
-
const form = get(formElementAtom(formId));
|
9
|
-
invariant(form, "Unable to access form element when setting field value. This is likely a bug in remix-validated-form.");
|
10
|
-
const controlledFields = get(controlledFieldsAtom(formId));
|
11
|
-
const updatePromises = [];
|
12
|
-
for (const [field, value] of Object.entries(updatedValues)) {
|
13
|
-
const isControlled = !!controlledFields[field];
|
14
|
-
if (isControlled) {
|
15
|
-
updatePromises.push(set(setControlledFieldValueAtom, {
|
16
|
-
field,
|
17
|
-
formId,
|
18
|
-
value,
|
19
|
-
}));
|
20
|
-
}
|
21
|
-
else {
|
22
|
-
setInputValueInForm(form, field, Array.isArray(value) ? value : [value]);
|
23
|
-
}
|
24
|
-
}
|
25
|
-
await Promise.all(updatePromises);
|
26
|
-
}, [formId]), ATOM_SCOPE);
|
File without changes
|
@@ -1 +0,0 @@
|
|
1
|
-
"use strict";
|
@@ -1,62 +0,0 @@
|
|
1
|
-
import { FieldErrors, TouchedFields } from "..";
|
2
|
-
export declare type InternalFormState = {
|
3
|
-
hydrated: boolean;
|
4
|
-
fieldErrors: FieldErrors;
|
5
|
-
isSubmitting: boolean;
|
6
|
-
hasBeenSubmitted: boolean;
|
7
|
-
touchedFields: TouchedFields;
|
8
|
-
action?: string;
|
9
|
-
subaction?: string;
|
10
|
-
defaultValues: {
|
11
|
-
[fieldName: string]: any;
|
12
|
-
};
|
13
|
-
validateField: (fieldName: string) => Promise<string | null>;
|
14
|
-
registerReceiveFocus: (fieldName: string, handler: () => void) => () => void;
|
15
|
-
setFieldValue: (fieldName: string, value: unknown) => void;
|
16
|
-
};
|
17
|
-
declare type SyncFormArgs = {
|
18
|
-
defaultValues?: {
|
19
|
-
[fieldName: string]: any;
|
20
|
-
};
|
21
|
-
action?: string;
|
22
|
-
subaction?: string;
|
23
|
-
validateField: InternalFormState["validateField"];
|
24
|
-
registerReceiveFocus: InternalFormState["registerReceiveFocus"];
|
25
|
-
setFieldValueForForm: InternalFormState["setFieldValue"];
|
26
|
-
};
|
27
|
-
declare type StoreState = {
|
28
|
-
forms: {
|
29
|
-
[formId: string | symbol]: InternalFormState;
|
30
|
-
};
|
31
|
-
};
|
32
|
-
export declare const state: StoreState;
|
33
|
-
export declare const registerFormSlice: (formId: string | symbol, { registerReceiveFocus, setFieldValueForForm, validateField, action, defaultValues, subaction, }: SyncFormArgs) => void;
|
34
|
-
export declare const unregisterFormSlice: (formId: string | symbol) => void;
|
35
|
-
export declare const useFormData: (formId: string | symbol) => {
|
36
|
-
readonly hydrated: boolean;
|
37
|
-
readonly fieldErrors: {
|
38
|
-
readonly [x: string]: string;
|
39
|
-
};
|
40
|
-
readonly isSubmitting: boolean;
|
41
|
-
readonly hasBeenSubmitted: boolean;
|
42
|
-
readonly touchedFields: {
|
43
|
-
readonly [x: string]: boolean;
|
44
|
-
};
|
45
|
-
readonly action?: string | undefined;
|
46
|
-
readonly subaction?: string | undefined;
|
47
|
-
readonly defaultValues: {
|
48
|
-
readonly [x: string]: any;
|
49
|
-
};
|
50
|
-
readonly validateField: (fieldName: string) => Promise<string | null>;
|
51
|
-
readonly registerReceiveFocus: (fieldName: string, handler: () => void) => () => void;
|
52
|
-
readonly setFieldValue: (fieldName: string, value: unknown) => void;
|
53
|
-
};
|
54
|
-
export declare const startSubmit: (formId: string | symbol) => void;
|
55
|
-
export declare const endSubmit: (formId: string | symbol) => void;
|
56
|
-
export declare const sync: (formId: string | symbol, { defaultValues, action, subaction, registerReceiveFocus, validateField, setFieldValueForForm, }: SyncFormArgs) => void;
|
57
|
-
export declare const clearError: (formId: string | symbol, fieldName: string) => void;
|
58
|
-
export declare const addError: (formId: string | symbol, fieldName: string, error: string) => void;
|
59
|
-
export declare const setTouched: (formId: string | symbol, fieldName: string, touched: boolean) => void;
|
60
|
-
export declare const reset: (formId: string | symbol) => void;
|
61
|
-
export declare const setFieldErrors: (formId: string | symbol, fieldErrors: FieldErrors) => void;
|
62
|
-
export {};
|
@@ -1,69 +0,0 @@
|
|
1
|
-
import { proxy, useSnapshot } from "valtio";
|
2
|
-
export const state = proxy({ forms: {} });
|
3
|
-
export const registerFormSlice = (formId, { registerReceiveFocus, setFieldValueForForm, validateField, action, defaultValues, subaction, }) => {
|
4
|
-
state.forms[formId] = {
|
5
|
-
hydrated: true,
|
6
|
-
defaultValues: defaultValues !== null && defaultValues !== void 0 ? defaultValues : {},
|
7
|
-
fieldErrors: {},
|
8
|
-
hasBeenSubmitted: false,
|
9
|
-
isSubmitting: false,
|
10
|
-
touchedFields: {},
|
11
|
-
registerReceiveFocus,
|
12
|
-
setFieldValue: setFieldValueForForm,
|
13
|
-
validateField,
|
14
|
-
action,
|
15
|
-
subaction,
|
16
|
-
};
|
17
|
-
};
|
18
|
-
export const unregisterFormSlice = (formId) => {
|
19
|
-
delete state.forms[formId];
|
20
|
-
};
|
21
|
-
const unhydratedFormState = {
|
22
|
-
hydrated: false,
|
23
|
-
fieldErrors: {},
|
24
|
-
isSubmitting: false,
|
25
|
-
hasBeenSubmitted: false,
|
26
|
-
touchedFields: {},
|
27
|
-
defaultValues: {},
|
28
|
-
validateField: () => Promise.resolve(null),
|
29
|
-
registerReceiveFocus: () => () => { },
|
30
|
-
setFieldValue: () => { },
|
31
|
-
};
|
32
|
-
export const useFormData = (formId) => {
|
33
|
-
var _a;
|
34
|
-
const snapshot = useSnapshot(state);
|
35
|
-
return (_a = snapshot.forms[formId]) !== null && _a !== void 0 ? _a : unhydratedFormState;
|
36
|
-
};
|
37
|
-
export const startSubmit = (formId) => {
|
38
|
-
state.forms[formId].isSubmitting = true;
|
39
|
-
state.forms[formId].hasBeenSubmitted = true;
|
40
|
-
};
|
41
|
-
export const endSubmit = (formId) => {
|
42
|
-
state.forms[formId].isSubmitting = false;
|
43
|
-
};
|
44
|
-
export const sync = (formId, { defaultValues, action, subaction, registerReceiveFocus, validateField, setFieldValueForForm, }) => {
|
45
|
-
state.forms[formId].defaultValues = defaultValues !== null && defaultValues !== void 0 ? defaultValues : {};
|
46
|
-
state.forms[formId].action = action;
|
47
|
-
state.forms[formId].subaction = subaction;
|
48
|
-
state.forms[formId].registerReceiveFocus = registerReceiveFocus;
|
49
|
-
state.forms[formId].validateField = validateField;
|
50
|
-
state.forms[formId].hydrated = true;
|
51
|
-
state.forms[formId].setFieldValue = setFieldValueForForm;
|
52
|
-
};
|
53
|
-
export const clearError = (formId, fieldName) => {
|
54
|
-
delete state.forms[formId].fieldErrors[fieldName];
|
55
|
-
};
|
56
|
-
export const addError = (formId, fieldName, error) => {
|
57
|
-
state.forms[formId].fieldErrors[fieldName] = error;
|
58
|
-
};
|
59
|
-
export const setTouched = (formId, fieldName, touched) => {
|
60
|
-
state.forms[formId].touchedFields[fieldName] = touched;
|
61
|
-
};
|
62
|
-
export const reset = (formId) => {
|
63
|
-
state.forms[formId].fieldErrors = {};
|
64
|
-
state.forms[formId].touchedFields = {};
|
65
|
-
state.forms[formId].hasBeenSubmitted = false;
|
66
|
-
};
|
67
|
-
export const setFieldErrors = (formId, fieldErrors) => {
|
68
|
-
state.forms[formId].fieldErrors = fieldErrors;
|
69
|
-
};
|
@@ -1,47 +0,0 @@
|
|
1
|
-
import { FieldErrors, TouchedFields } from "..";
|
2
|
-
export declare type InternalFormState = {
|
3
|
-
hydrated: boolean;
|
4
|
-
fieldErrors: FieldErrors;
|
5
|
-
isSubmitting: boolean;
|
6
|
-
hasBeenSubmitted: boolean;
|
7
|
-
touchedFields: TouchedFields;
|
8
|
-
action?: string;
|
9
|
-
subaction?: string;
|
10
|
-
defaultValues: {
|
11
|
-
[fieldName: string]: any;
|
12
|
-
};
|
13
|
-
validateField: (fieldName: string) => Promise<string | null>;
|
14
|
-
registerReceiveFocus: (fieldName: string, handler: () => void) => () => void;
|
15
|
-
setFieldValue: (fieldName: string, value: unknown) => void;
|
16
|
-
};
|
17
|
-
declare type Helpers = {
|
18
|
-
startSubmit: () => void;
|
19
|
-
endSubmit: () => void;
|
20
|
-
sync: (args: SyncFormArgs) => void;
|
21
|
-
clearError: (name: string) => void;
|
22
|
-
addError: (name: string, error: string) => void;
|
23
|
-
setTouched: (name: string, touched: boolean) => void;
|
24
|
-
reset: () => void;
|
25
|
-
setFieldErrors: (fieldErrors: FieldErrors) => void;
|
26
|
-
register: (init: SyncFormArgs) => void;
|
27
|
-
unregister: () => void;
|
28
|
-
};
|
29
|
-
declare type SyncFormArgs = {
|
30
|
-
defaultValues?: {
|
31
|
-
[fieldName: string]: any;
|
32
|
-
};
|
33
|
-
action?: string;
|
34
|
-
subaction?: string;
|
35
|
-
validateField: InternalFormState["validateField"];
|
36
|
-
registerReceiveFocus: InternalFormState["registerReceiveFocus"];
|
37
|
-
setFieldValueForForm: InternalFormState["setFieldValue"];
|
38
|
-
};
|
39
|
-
declare type StoreState = {
|
40
|
-
forms: {
|
41
|
-
[formId: string | symbol]: InternalFormState;
|
42
|
-
};
|
43
|
-
form: (formId: string | symbol) => InternalFormState;
|
44
|
-
helpers: (formId: string | symbol) => Helpers;
|
45
|
-
};
|
46
|
-
export declare const useStore: import("zustand").UseBoundStore<StoreState, import("zustand").StoreApi<StoreState>>;
|
47
|
-
export {};
|
@@ -1,85 +0,0 @@
|
|
1
|
-
import create from "zustand";
|
2
|
-
import { immer } from "./immerMiddleware";
|
3
|
-
const unhydratedFormState = {
|
4
|
-
hydrated: false,
|
5
|
-
fieldErrors: {},
|
6
|
-
isSubmitting: false,
|
7
|
-
hasBeenSubmitted: false,
|
8
|
-
touchedFields: {},
|
9
|
-
defaultValues: {},
|
10
|
-
validateField: () => Promise.resolve(null),
|
11
|
-
registerReceiveFocus: () => () => { },
|
12
|
-
setFieldValue: () => { },
|
13
|
-
// clearError: () => {},
|
14
|
-
// addError: () => {},
|
15
|
-
// setTouched: () => {},
|
16
|
-
// reset: () => {},
|
17
|
-
// startSubmit: () => {},
|
18
|
-
// endSubmit: () => {},
|
19
|
-
// sync: () => {},
|
20
|
-
// setFieldErrors: () => {},
|
21
|
-
};
|
22
|
-
export const useStore = create(immer((set, get) => ({
|
23
|
-
forms: {},
|
24
|
-
form: (formId) => { var _a; return (_a = get().forms[formId]) !== null && _a !== void 0 ? _a : unhydratedFormState; },
|
25
|
-
helpers: (formId) => ({
|
26
|
-
clearError: (name) => set((state) => {
|
27
|
-
delete state.forms[formId].fieldErrors[name];
|
28
|
-
}),
|
29
|
-
addError: (name, error) => set((state) => {
|
30
|
-
state.forms[formId].fieldErrors[name] = error;
|
31
|
-
}),
|
32
|
-
setTouched: (name, touched) => set((state) => {
|
33
|
-
state.forms[formId].touchedFields[name] = touched;
|
34
|
-
}),
|
35
|
-
reset: () => set((state) => {
|
36
|
-
state.forms[formId].fieldErrors = {};
|
37
|
-
state.forms[formId].touchedFields = {};
|
38
|
-
state.forms[formId].hasBeenSubmitted = false;
|
39
|
-
}),
|
40
|
-
startSubmit: () => set((state) => {
|
41
|
-
state.forms[formId].hasBeenSubmitted = true;
|
42
|
-
state.forms[formId].isSubmitting = true;
|
43
|
-
}),
|
44
|
-
endSubmit: () => set((state) => {
|
45
|
-
state.forms[formId].isSubmitting = false;
|
46
|
-
}),
|
47
|
-
setFieldErrors: (fieldErrors) => {
|
48
|
-
set((state) => {
|
49
|
-
state.forms[formId].fieldErrors = fieldErrors;
|
50
|
-
});
|
51
|
-
},
|
52
|
-
sync: ({ defaultValues, action, subaction, validateField, registerReceiveFocus, setFieldValueForForm, }) => set((state) => {
|
53
|
-
state.forms[formId].defaultValues = defaultValues !== null && defaultValues !== void 0 ? defaultValues : {};
|
54
|
-
state.forms[formId].action = action;
|
55
|
-
state.forms[formId].subaction = subaction;
|
56
|
-
state.forms[formId].registerReceiveFocus = registerReceiveFocus;
|
57
|
-
state.forms[formId].validateField = validateField;
|
58
|
-
state.forms[formId].hydrated = true;
|
59
|
-
state.forms[formId].setFieldValue = setFieldValueForForm;
|
60
|
-
}),
|
61
|
-
unregister: () => {
|
62
|
-
set((state) => {
|
63
|
-
delete state.forms[formId];
|
64
|
-
});
|
65
|
-
},
|
66
|
-
register: ({ defaultValues, action, subaction, validateField, registerReceiveFocus, setFieldValueForForm, }) => {
|
67
|
-
set((state) => {
|
68
|
-
state.forms[formId] = {
|
69
|
-
defaultValues: defaultValues !== null && defaultValues !== void 0 ? defaultValues : {},
|
70
|
-
setFieldValue: setFieldValueForForm,
|
71
|
-
registerReceiveFocus,
|
72
|
-
validateField,
|
73
|
-
action,
|
74
|
-
subaction,
|
75
|
-
hydrated: true,
|
76
|
-
fieldErrors: {},
|
77
|
-
isSubmitting: false,
|
78
|
-
hasBeenSubmitted: false,
|
79
|
-
touchedFields: {},
|
80
|
-
// helpers
|
81
|
-
};
|
82
|
-
});
|
83
|
-
},
|
84
|
-
}),
|
85
|
-
})));
|
File without changes
|
package/browser/internal/test.js
DELETED
@@ -1,15 +0,0 @@
|
|
1
|
-
"use strict";
|
2
|
-
z.preprocess((val) => {
|
3
|
-
// Somewhat awkward -- this gets processed per item in the form,
|
4
|
-
// but as a whole array in the backend
|
5
|
-
if (Array.isArray(val)) {
|
6
|
-
return val;
|
7
|
-
}
|
8
|
-
else {
|
9
|
-
return [val];
|
10
|
-
}
|
11
|
-
}, z.array(z.preprocess((val) => {
|
12
|
-
return typeof val !== "string" || val === ""
|
13
|
-
? undefined
|
14
|
-
: Number.parseInt(val);
|
15
|
-
}, z.number())));
|
@@ -1 +0,0 @@
|
|
1
|
-
export declare const useMultiValueMap: <Key, Value>() => () => any;
|
@@ -1,11 +0,0 @@
|
|
1
|
-
import { MultiValueMap } from "multi-value-map";
|
2
|
-
import { useRef } from "react";
|
3
|
-
export const useMultiValueMap = () => {
|
4
|
-
const ref = useRef(null);
|
5
|
-
return () => {
|
6
|
-
if (ref.current)
|
7
|
-
return ref.current;
|
8
|
-
ref.current = new MultiValueMap();
|
9
|
-
return ref.current;
|
10
|
-
};
|
11
|
-
};
|
@@ -1,18 +0,0 @@
|
|
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, U extends boolean | undefined>(name: string, options?: BaseWatchOptions<T> & {
|
13
|
-
repeatable: U | undefined;
|
14
|
-
}): U extends true ? T[] : T;
|
15
|
-
<T>(name: string, options?: BaseWatchOptions<T>): T;
|
16
|
-
};
|
17
|
-
export declare const useWatch: UseWatchType;
|
18
|
-
export {};
|
@@ -1,122 +0,0 @@
|
|
1
|
-
import { atom } from "jotai";
|
2
|
-
import { selectAtom } from "jotai/utils";
|
3
|
-
import isNaN from "lodash/isNaN";
|
4
|
-
import { useCallback, useEffect, useMemo, useRef, useState } from "react";
|
5
|
-
import invariant from "tiny-invariant";
|
6
|
-
import { useInternalFormContext, useFieldDefaultValue, useFormAtomValue, } from "./hooks";
|
7
|
-
import { isCheckbox, isMultiselect, isRadio } from "./logic/elementUtils";
|
8
|
-
import { formElementAtom } from "./state";
|
9
|
-
import { fieldAtomFamily } from "./state/atomUtils";
|
10
|
-
import { controlledFieldsAtom } from "./state/controlledFields";
|
11
|
-
const emptyAtom = atom(undefined); // Always empty -- just used as a default value
|
12
|
-
const watchControlledFieldAtom = fieldAtomFamily(({ field, formId }) => selectAtom(controlledFieldsAtom(formId), (fields) => {
|
13
|
-
var _a;
|
14
|
-
return ({
|
15
|
-
present: field in fields,
|
16
|
-
valueAtom: (_a = fields[field]) !== null && _a !== void 0 ? _a : emptyAtom,
|
17
|
-
});
|
18
|
-
}, (a, b) => a.present === b.present && a.valueAtom === b.valueAtom));
|
19
|
-
const defaultParse = ({ value, type, isRepeated, checked, }) => {
|
20
|
-
if (type === "number") {
|
21
|
-
if (value === "")
|
22
|
-
return undefined;
|
23
|
-
const result = Number(value);
|
24
|
-
if (isNaN(result))
|
25
|
-
throw new Error("Value is not a number");
|
26
|
-
return result;
|
27
|
-
}
|
28
|
-
if (type === "checkbox" && !isRepeated) {
|
29
|
-
return checked;
|
30
|
-
}
|
31
|
-
return value;
|
32
|
-
};
|
33
|
-
const getInputValues = (node, multipleInputs = false) => {
|
34
|
-
if (!node)
|
35
|
-
return [];
|
36
|
-
if (node instanceof RadioNodeList) {
|
37
|
-
return [...node].flatMap((el) => getInputValues(el, true));
|
38
|
-
}
|
39
|
-
if (isMultiselect(node)) {
|
40
|
-
return [
|
41
|
-
{
|
42
|
-
type: "select",
|
43
|
-
value: [...node.options]
|
44
|
-
.filter((opt) => opt.selected)
|
45
|
-
.map((opt) => opt.value),
|
46
|
-
},
|
47
|
-
];
|
48
|
-
}
|
49
|
-
if (isCheckbox(node)) {
|
50
|
-
if (node.checked || !multipleInputs)
|
51
|
-
return [{ type: "checkbox", value: node.value, checked: node.checked }];
|
52
|
-
return [];
|
53
|
-
}
|
54
|
-
if (isRadio(node)) {
|
55
|
-
if (node.checked)
|
56
|
-
return [{ type: "radio", value: node.value, checked: node.checked }];
|
57
|
-
return [];
|
58
|
-
}
|
59
|
-
const input = node;
|
60
|
-
return [{ type: input.type, value: input.value, checked: input.checked }];
|
61
|
-
};
|
62
|
-
export const useWatch = (field, options) => {
|
63
|
-
const { formId, parse = defaultParse, repeatable = false, } = options !== null && options !== void 0 ? options : {};
|
64
|
-
const context = useInternalFormContext(formId, "useWatch");
|
65
|
-
const defaultValue = useFieldDefaultValue(field, context);
|
66
|
-
const hasSynced = useRef(false);
|
67
|
-
const [inputValues, setValue] = useState([]);
|
68
|
-
const formElement = useFormAtomValue(formElementAtom(context.formId));
|
69
|
-
const controlledField = useFormAtomValue(watchControlledFieldAtom({ formId: context.formId, field }));
|
70
|
-
const controlledValue = useFormAtomValue(controlledField.valueAtom);
|
71
|
-
const shouldSyncNativeInputValue = !controlledField.present && formElement;
|
72
|
-
const syncFieldValue = useCallback(() => {
|
73
|
-
invariant(formElement, `Unable to find form element for form. Watching field ${field}`);
|
74
|
-
hasSynced.current = true;
|
75
|
-
// We pull the values out using `form.elements` instead of `FormData`
|
76
|
-
// so that we can access the `type` of the input.
|
77
|
-
setValue(getInputValues(formElement.elements.namedItem(field)));
|
78
|
-
}, [field, formElement]);
|
79
|
-
// Should set the field values after the initial render
|
80
|
-
useEffect(() => {
|
81
|
-
if (shouldSyncNativeInputValue)
|
82
|
-
syncFieldValue();
|
83
|
-
}, [
|
84
|
-
controlledField.present,
|
85
|
-
formElement,
|
86
|
-
shouldSyncNativeInputValue,
|
87
|
-
syncFieldValue,
|
88
|
-
]);
|
89
|
-
useEffect(() => {
|
90
|
-
if (shouldSyncNativeInputValue) {
|
91
|
-
const listener = async (event) => {
|
92
|
-
if (!(event.target instanceof HTMLElement))
|
93
|
-
return;
|
94
|
-
const target = event.target;
|
95
|
-
const { form: targetForm, name: targetName } = target;
|
96
|
-
if (targetForm === formElement && targetName === field) {
|
97
|
-
syncFieldValue();
|
98
|
-
}
|
99
|
-
};
|
100
|
-
window.addEventListener("change", listener);
|
101
|
-
window.addEventListener("input", listener);
|
102
|
-
return () => {
|
103
|
-
window.removeEventListener("change", listener);
|
104
|
-
window.removeEventListener("input", listener);
|
105
|
-
};
|
106
|
-
}
|
107
|
-
}, [field, formElement, shouldSyncNativeInputValue, syncFieldValue]);
|
108
|
-
const parsedValue = useMemo(() => {
|
109
|
-
const parsed = inputValues.map(({ type, value, checked }) => parse({
|
110
|
-
value,
|
111
|
-
type,
|
112
|
-
isRepeated: inputValues.length > 1 || repeatable,
|
113
|
-
checked,
|
114
|
-
}));
|
115
|
-
return parsed.length > 1 || repeatable ? parsed : parsed[0];
|
116
|
-
}, [parse, repeatable, inputValues]);
|
117
|
-
if (controlledField.present)
|
118
|
-
return controlledValue;
|
119
|
-
if (!hasSynced.current)
|
120
|
-
return defaultValue !== null && defaultValue !== void 0 ? defaultValue : (repeatable ? [] : undefined);
|
121
|
-
return parsedValue;
|
122
|
-
};
|
File without changes
|
package/browser/lowLevelHooks.js
DELETED
@@ -1 +0,0 @@
|
|
1
|
-
"use strict";
|
@@ -1,15 +0,0 @@
|
|
1
|
-
export declare class TestFormData implements FormData {
|
2
|
-
private _params;
|
3
|
-
constructor(body?: string);
|
4
|
-
append(name: string, value: string | Blob, fileName?: string): void;
|
5
|
-
delete(name: string): void;
|
6
|
-
get(name: string): FormDataEntryValue | null;
|
7
|
-
getAll(name: string): FormDataEntryValue[];
|
8
|
-
has(name: string): boolean;
|
9
|
-
set(name: string, value: string | Blob, fileName?: string): void;
|
10
|
-
forEach(callbackfn: (value: FormDataEntryValue, key: string, parent: FormData) => void, thisArg?: any): void;
|
11
|
-
entries(): IterableIterator<[string, FormDataEntryValue]>;
|
12
|
-
keys(): IterableIterator<string>;
|
13
|
-
values(): IterableIterator<FormDataEntryValue>;
|
14
|
-
[Symbol.iterator](): IterableIterator<[string, FormDataEntryValue]>;
|
15
|
-
}
|
@@ -1,46 +0,0 @@
|
|
1
|
-
// Copied from remix to use in tests
|
2
|
-
// https://github.com/remix-run/remix/blob/a69a631cb5add72d5fb24211ab2a0be367b6f2fd/packages/remix-node/form-data.ts
|
3
|
-
export class TestFormData {
|
4
|
-
constructor(body) {
|
5
|
-
this._params = new URLSearchParams(body);
|
6
|
-
}
|
7
|
-
append(name, value, fileName) {
|
8
|
-
if (typeof value !== "string") {
|
9
|
-
throw new Error("formData.append can only accept a string");
|
10
|
-
}
|
11
|
-
this._params.append(name, value);
|
12
|
-
}
|
13
|
-
delete(name) {
|
14
|
-
this._params.delete(name);
|
15
|
-
}
|
16
|
-
get(name) {
|
17
|
-
return this._params.get(name);
|
18
|
-
}
|
19
|
-
getAll(name) {
|
20
|
-
return this._params.getAll(name);
|
21
|
-
}
|
22
|
-
has(name) {
|
23
|
-
return this._params.has(name);
|
24
|
-
}
|
25
|
-
set(name, value, fileName) {
|
26
|
-
if (typeof value !== "string") {
|
27
|
-
throw new Error("formData.set can only accept a string");
|
28
|
-
}
|
29
|
-
this._params.set(name, value);
|
30
|
-
}
|
31
|
-
forEach(callbackfn, thisArg) {
|
32
|
-
this._params.forEach(callbackfn, thisArg);
|
33
|
-
}
|
34
|
-
entries() {
|
35
|
-
return this._params.entries();
|
36
|
-
}
|
37
|
-
keys() {
|
38
|
-
return this._params.keys();
|
39
|
-
}
|
40
|
-
values() {
|
41
|
-
return this._params.values();
|
42
|
-
}
|
43
|
-
*[Symbol.iterator]() {
|
44
|
-
yield* this._params;
|
45
|
-
}
|
46
|
-
}
|
package/browser/types.d.ts
DELETED
@@ -1 +0,0 @@
|
|
1
|
-
export declare type ValidationState = "idle" | "validating" | "valid" | "invalid";
|
package/browser/types.js
DELETED
@@ -1 +0,0 @@
|
|
1
|
-
export {};
|
@@ -1 +0,0 @@
|
|
1
|
-
export {};
|