remix-validated-form 4.3.0 → 4.3.1-beta.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/internal/logic/getRadioChecked.js +10 -0
- package/browser/internal/reset.d.ts +0 -0
- package/browser/internal/reset.js +0 -0
- package/browser/unreleased/formStateHooks.d.ts +0 -0
- package/browser/unreleased/formStateHooks.js +0 -0
- package/dist/remix-validated-form.cjs.js +1 -0
- package/dist/remix-validated-form.es.js +3535 -0
- package/dist/remix-validated-form.umd.js +1 -0
- package/{build → dist/types}/ValidatedForm.d.ts +0 -0
- package/{build → dist/types}/hooks.d.ts +0 -0
- package/{build → dist/types}/index.d.ts +0 -0
- package/{build → dist/types}/internal/MultiValueMap.d.ts +0 -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/{build → dist/types}/internal/hooks.d.ts +0 -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/{build → dist/types}/internal/reset.d.ts +0 -0
- package/{build → dist/types}/internal/state/atomUtils.d.ts +0 -0
- package/{build → dist/types}/internal/state/controlledFields.d.ts +0 -0
- package/{build → dist/types}/internal/state.d.ts +0 -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 +0 -0
- package/{build → dist/types}/userFacingFormContext.d.ts +0 -0
- package/{build → dist/types}/validation/createValidator.d.ts +0 -0
- package/{build → dist/types}/validation/types.d.ts +0 -0
- package/package.json +8 -7
- package/src/internal/getInputProps.test.ts +251 -0
- package/src/internal/logic/getRadioChecked.ts +11 -0
- 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 -261
- package/build/hooks.js +0 -91
- package/build/index.js +0 -18
- package/build/internal/MultiValueMap.js +0 -48
- 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 -58
- 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.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/reset.js +0 -19
- package/build/internal/setFormValues.d.ts +0 -2
- package/build/internal/setFormValues.js +0 -33
- package/build/internal/state/atomUtils.js +0 -13
- package/build/internal/state/controlledFields.js +0 -103
- 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.js +0 -71
- 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
@@ -0,0 +1,304 @@
|
|
1
|
+
import { anyString, TestFormData } from "@remix-validated-form/test-utils";
|
2
|
+
import { withYup } from "@remix-validated-form/with-yup/src";
|
3
|
+
import { withZod } from "@remix-validated-form/with-zod";
|
4
|
+
import { Validator } from "remix-validated-form/src";
|
5
|
+
import { objectFromPathEntries } from "remix-validated-form/src/internal/flatten";
|
6
|
+
import { describe, it, expect } from "vitest";
|
7
|
+
import * as yup from "yup";
|
8
|
+
import { z } from "zod";
|
9
|
+
|
10
|
+
// If adding an adapter, write a validator that validates this shape
|
11
|
+
type Person = {
|
12
|
+
firstName: string;
|
13
|
+
lastName: string;
|
14
|
+
age?: number;
|
15
|
+
address: {
|
16
|
+
streetAddress: string;
|
17
|
+
city: string;
|
18
|
+
country: string;
|
19
|
+
};
|
20
|
+
pets?: {
|
21
|
+
animal: string;
|
22
|
+
name: string;
|
23
|
+
}[];
|
24
|
+
};
|
25
|
+
|
26
|
+
type ValidationTestCase = {
|
27
|
+
name: string;
|
28
|
+
validator: Validator<Person>;
|
29
|
+
};
|
30
|
+
|
31
|
+
const validationTestCases: ValidationTestCase[] = [
|
32
|
+
{
|
33
|
+
name: "yup",
|
34
|
+
validator: withYup(
|
35
|
+
yup.object({
|
36
|
+
firstName: yup.string().required(),
|
37
|
+
lastName: yup.string().required(),
|
38
|
+
age: yup.number(),
|
39
|
+
address: yup
|
40
|
+
.object({
|
41
|
+
streetAddress: yup.string().required(),
|
42
|
+
city: yup.string().required(),
|
43
|
+
country: yup.string().required(),
|
44
|
+
})
|
45
|
+
.required(),
|
46
|
+
pets: yup.array().of(
|
47
|
+
yup.object({
|
48
|
+
animal: yup.string().required(),
|
49
|
+
name: yup.string().required(),
|
50
|
+
})
|
51
|
+
),
|
52
|
+
})
|
53
|
+
),
|
54
|
+
},
|
55
|
+
{
|
56
|
+
name: "zod",
|
57
|
+
validator: withZod(
|
58
|
+
z.object({
|
59
|
+
firstName: z.string().nonempty(),
|
60
|
+
lastName: z.string().nonempty(),
|
61
|
+
age: z.optional(z.number()),
|
62
|
+
address: z.preprocess(
|
63
|
+
(value) => (value == null ? {} : value),
|
64
|
+
z.object({
|
65
|
+
streetAddress: z.string().nonempty(),
|
66
|
+
city: z.string().nonempty(),
|
67
|
+
country: z.string().nonempty(),
|
68
|
+
})
|
69
|
+
),
|
70
|
+
pets: z
|
71
|
+
.object({
|
72
|
+
animal: z.string().nonempty(),
|
73
|
+
name: z.string().nonempty(),
|
74
|
+
})
|
75
|
+
.array()
|
76
|
+
.optional(),
|
77
|
+
})
|
78
|
+
),
|
79
|
+
},
|
80
|
+
];
|
81
|
+
|
82
|
+
describe("Validation", () => {
|
83
|
+
describe.each(validationTestCases)("Adapter for $name", ({ validator }) => {
|
84
|
+
describe("validate", () => {
|
85
|
+
it("should return the data when valid", async () => {
|
86
|
+
const person: Person = {
|
87
|
+
firstName: "John",
|
88
|
+
lastName: "Doe",
|
89
|
+
age: 30,
|
90
|
+
address: {
|
91
|
+
streetAddress: "123 Main St",
|
92
|
+
city: "Anytown",
|
93
|
+
country: "USA",
|
94
|
+
},
|
95
|
+
pets: [{ animal: "dog", name: "Fido" }],
|
96
|
+
};
|
97
|
+
expect(await validator.validate(person)).toEqual({
|
98
|
+
data: person,
|
99
|
+
error: undefined,
|
100
|
+
submittedData: person,
|
101
|
+
});
|
102
|
+
});
|
103
|
+
|
104
|
+
it("should return field errors when invalid", async () => {
|
105
|
+
const obj = { age: "hi!", pets: [{ animal: "dog" }] };
|
106
|
+
expect(await validator.validate(obj)).toEqual({
|
107
|
+
data: undefined,
|
108
|
+
error: {
|
109
|
+
fieldErrors: {
|
110
|
+
firstName: anyString,
|
111
|
+
lastName: anyString,
|
112
|
+
age: anyString,
|
113
|
+
"address.city": anyString,
|
114
|
+
"address.country": anyString,
|
115
|
+
"address.streetAddress": anyString,
|
116
|
+
"pets[0].name": anyString,
|
117
|
+
},
|
118
|
+
subaction: undefined,
|
119
|
+
},
|
120
|
+
submittedData: obj,
|
121
|
+
});
|
122
|
+
});
|
123
|
+
|
124
|
+
it("should unflatten data when validating", async () => {
|
125
|
+
const data = {
|
126
|
+
firstName: "John",
|
127
|
+
lastName: "Doe",
|
128
|
+
age: 30,
|
129
|
+
"address.streetAddress": "123 Main St",
|
130
|
+
"address.city": "Anytown",
|
131
|
+
"address.country": "USA",
|
132
|
+
"pets[0].animal": "dog",
|
133
|
+
"pets[0].name": "Fido",
|
134
|
+
};
|
135
|
+
expect(await validator.validate(data)).toEqual({
|
136
|
+
data: {
|
137
|
+
firstName: "John",
|
138
|
+
lastName: "Doe",
|
139
|
+
age: 30,
|
140
|
+
address: {
|
141
|
+
streetAddress: "123 Main St",
|
142
|
+
city: "Anytown",
|
143
|
+
country: "USA",
|
144
|
+
},
|
145
|
+
pets: [{ animal: "dog", name: "Fido" }],
|
146
|
+
},
|
147
|
+
error: undefined,
|
148
|
+
submittedData: objectFromPathEntries(Object.entries(data)),
|
149
|
+
});
|
150
|
+
});
|
151
|
+
|
152
|
+
it("should accept FormData directly and return errors", async () => {
|
153
|
+
const formData = new TestFormData();
|
154
|
+
formData.set("firstName", "John");
|
155
|
+
formData.set("lastName", "Doe");
|
156
|
+
formData.set("address.streetAddress", "123 Main St");
|
157
|
+
formData.set("address.country", "USA");
|
158
|
+
formData.set("pets[0].animal", "dog");
|
159
|
+
|
160
|
+
expect(await validator.validate(formData)).toEqual({
|
161
|
+
data: undefined,
|
162
|
+
error: {
|
163
|
+
fieldErrors: {
|
164
|
+
"address.city": anyString,
|
165
|
+
"pets[0].name": anyString,
|
166
|
+
},
|
167
|
+
subaction: undefined,
|
168
|
+
},
|
169
|
+
submittedData: objectFromPathEntries([...formData.entries()]),
|
170
|
+
});
|
171
|
+
});
|
172
|
+
|
173
|
+
it("should accept FormData directly and return valid data", async () => {
|
174
|
+
const formData = new TestFormData();
|
175
|
+
formData.set("firstName", "John");
|
176
|
+
formData.set("lastName", "Doe");
|
177
|
+
formData.set("address.streetAddress", "123 Main St");
|
178
|
+
formData.set("address.country", "USA");
|
179
|
+
formData.set("address.city", "Anytown");
|
180
|
+
formData.set("pets[0].animal", "dog");
|
181
|
+
formData.set("pets[0].name", "Fido");
|
182
|
+
|
183
|
+
expect(await validator.validate(formData)).toEqual({
|
184
|
+
data: {
|
185
|
+
firstName: "John",
|
186
|
+
lastName: "Doe",
|
187
|
+
address: {
|
188
|
+
streetAddress: "123 Main St",
|
189
|
+
country: "USA",
|
190
|
+
city: "Anytown",
|
191
|
+
},
|
192
|
+
pets: [{ animal: "dog", name: "Fido" }],
|
193
|
+
},
|
194
|
+
error: undefined,
|
195
|
+
subaction: undefined,
|
196
|
+
submittedData: objectFromPathEntries([...formData.entries()]),
|
197
|
+
});
|
198
|
+
});
|
199
|
+
|
200
|
+
it("should return the subaction in the ValidatorError if there is one", async () => {
|
201
|
+
const person = {
|
202
|
+
lastName: "Doe",
|
203
|
+
age: 20,
|
204
|
+
address: {
|
205
|
+
streetAddress: "123 Main St",
|
206
|
+
city: "Anytown",
|
207
|
+
country: "USA",
|
208
|
+
},
|
209
|
+
pets: [{ animal: "dog", name: "Fido" }],
|
210
|
+
subaction: "updatePerson",
|
211
|
+
};
|
212
|
+
expect(await validator.validate(person)).toEqual({
|
213
|
+
error: {
|
214
|
+
fieldErrors: {
|
215
|
+
firstName: anyString,
|
216
|
+
},
|
217
|
+
subaction: "updatePerson",
|
218
|
+
},
|
219
|
+
data: undefined,
|
220
|
+
submittedData: person,
|
221
|
+
});
|
222
|
+
});
|
223
|
+
});
|
224
|
+
|
225
|
+
describe("validateField", () => {
|
226
|
+
it("should not return an error if field is valid", async () => {
|
227
|
+
const person = {
|
228
|
+
firstName: "John",
|
229
|
+
lastName: {}, // invalid, but we should only be validating firstName
|
230
|
+
};
|
231
|
+
expect(await validator.validateField(person, "firstName")).toEqual({
|
232
|
+
error: undefined,
|
233
|
+
});
|
234
|
+
});
|
235
|
+
it("should not return an error if a nested field is valid", async () => {
|
236
|
+
const person = {
|
237
|
+
firstName: "John",
|
238
|
+
lastName: {}, // invalid, but we should only be validating firstName
|
239
|
+
address: {
|
240
|
+
streetAddress: "123 Main St",
|
241
|
+
city: "Anytown",
|
242
|
+
country: "USA",
|
243
|
+
},
|
244
|
+
pets: [{ animal: "dog", name: "Fido" }],
|
245
|
+
};
|
246
|
+
expect(
|
247
|
+
await validator.validateField(person, "address.streetAddress")
|
248
|
+
).toEqual({
|
249
|
+
error: undefined,
|
250
|
+
});
|
251
|
+
expect(await validator.validateField(person, "address.city")).toEqual({
|
252
|
+
error: undefined,
|
253
|
+
});
|
254
|
+
expect(
|
255
|
+
await validator.validateField(person, "address.country")
|
256
|
+
).toEqual({
|
257
|
+
error: undefined,
|
258
|
+
});
|
259
|
+
expect(await validator.validateField(person, "pets[0].animal")).toEqual(
|
260
|
+
{
|
261
|
+
error: undefined,
|
262
|
+
}
|
263
|
+
);
|
264
|
+
expect(await validator.validateField(person, "pets[0].name")).toEqual({
|
265
|
+
error: undefined,
|
266
|
+
});
|
267
|
+
});
|
268
|
+
|
269
|
+
it("should return an error if field is invalid", async () => {
|
270
|
+
const person = {
|
271
|
+
firstName: "John",
|
272
|
+
lastName: {},
|
273
|
+
address: {
|
274
|
+
streetAddress: "123 Main St",
|
275
|
+
city: 1234,
|
276
|
+
},
|
277
|
+
};
|
278
|
+
expect(await validator.validateField(person, "lastName")).toEqual({
|
279
|
+
error: anyString,
|
280
|
+
});
|
281
|
+
});
|
282
|
+
|
283
|
+
it("should return an error if a nested field is invalid", async () => {
|
284
|
+
const person = {
|
285
|
+
firstName: "John",
|
286
|
+
lastName: {},
|
287
|
+
address: {
|
288
|
+
streetAddress: "123 Main St",
|
289
|
+
city: 1234,
|
290
|
+
},
|
291
|
+
pets: [{ animal: "dog" }],
|
292
|
+
};
|
293
|
+
expect(
|
294
|
+
await validator.validateField(person, "address.country")
|
295
|
+
).toEqual({
|
296
|
+
error: anyString,
|
297
|
+
});
|
298
|
+
expect(await validator.validateField(person, "pets[0].name")).toEqual({
|
299
|
+
error: anyString,
|
300
|
+
});
|
301
|
+
});
|
302
|
+
});
|
303
|
+
});
|
304
|
+
});
|
package/tsconfig.json
CHANGED
package/vite.config.ts
ADDED
package/.turbo/turbo-test.log
DELETED
@@ -1,11 +0,0 @@
|
|
1
|
-
[2K[1G[2m$ jest src[22m
|
2
|
-
[1mNo tests found, exiting with code 1[22m
|
3
|
-
Run with `--passWithNoTests` to exit with code 0
|
4
|
-
In [1m/Users/aaronpettengill/dev/remix-validated-form/packages/remix-validated-form[22m
|
5
|
-
68 files checked.
|
6
|
-
testMatch: [33m**/__tests__/**/*.[jt]s?(x), **/?(*.)+(spec|test).[tj]s?(x)[39m - 2 matches
|
7
|
-
testPathIgnorePatterns: [33m/node_modules/[39m - 68 matches
|
8
|
-
testRegex: - 0 matches
|
9
|
-
Pattern: [33msrc[39m - 0 matches
|
10
|
-
[2K[1G[34minfo[39m Visit [1mhttps://yarnpkg.com/en/docs/cli/run[22m for documentation about this command.
|
11
|
-
[2K[1G[31merror[39m Command failed with exit code 1.
|
package/browser/components.d.ts
DELETED
@@ -1,7 +0,0 @@
|
|
1
|
-
import { HTMLProps } from "react";
|
2
|
-
declare type WithRequiredName<T extends {
|
3
|
-
name?: string;
|
4
|
-
}> = T & Required<Pick<T, "name">>;
|
5
|
-
export declare const ValidatedInput: ({ name, form, ...rest }: WithRequiredName<HTMLProps<HTMLInputElement>>) => JSX.Element;
|
6
|
-
export declare const ValidatedTextarea: ({ name, form, ...rest }: WithRequiredName<HTMLProps<HTMLTextAreaElement>>) => JSX.Element;
|
7
|
-
export {};
|
package/browser/components.js
DELETED
@@ -1,10 +0,0 @@
|
|
1
|
-
import { jsx as _jsx } from "react/jsx-runtime";
|
2
|
-
import { useField } from ".";
|
3
|
-
export const ValidatedInput = ({ name, form, ...rest }) => {
|
4
|
-
const { getInputProps } = useField(name, { formId: form });
|
5
|
-
return _jsx("input", { ...getInputProps(rest) }, void 0);
|
6
|
-
};
|
7
|
-
export const ValidatedTextarea = ({ name, form, ...rest }) => {
|
8
|
-
const { getInputProps } = useField(name, { formId: form });
|
9
|
-
return _jsx("textarea", { ...getInputProps(rest) }, void 0);
|
10
|
-
};
|
@@ -1,9 +0,0 @@
|
|
1
|
-
export declare class MultiValueMap<Key, Value> {
|
2
|
-
private dict;
|
3
|
-
add: (key: Key, value: Value) => void;
|
4
|
-
remove: (key: Key, value: Value) => void;
|
5
|
-
getAll: (key: Key) => Value[];
|
6
|
-
entries: () => IterableIterator<[Key, Value[]]>;
|
7
|
-
has: (key: Key) => boolean;
|
8
|
-
}
|
9
|
-
export declare const useMultiValueMap: <Key, Value>() => () => MultiValueMap<Key, Value>;
|
@@ -1,41 +0,0 @@
|
|
1
|
-
import { useRef } from "react";
|
2
|
-
export class MultiValueMap {
|
3
|
-
constructor() {
|
4
|
-
this.dict = new Map();
|
5
|
-
this.add = (key, value) => {
|
6
|
-
var _a;
|
7
|
-
this.dict.set(key, [...((_a = this.dict.get(key)) !== null && _a !== void 0 ? _a : []), value]);
|
8
|
-
if (this.dict.has(key)) {
|
9
|
-
this.dict.get(key).push(value);
|
10
|
-
}
|
11
|
-
else {
|
12
|
-
this.dict.set(key, [value]);
|
13
|
-
}
|
14
|
-
};
|
15
|
-
this.remove = (key, value) => {
|
16
|
-
if (!this.dict.has(key))
|
17
|
-
return;
|
18
|
-
const array = this.dict.get(key);
|
19
|
-
const index = array.indexOf(value);
|
20
|
-
if (index !== -1)
|
21
|
-
array.splice(index, 1);
|
22
|
-
if (array.length === 0)
|
23
|
-
this.dict.delete(key);
|
24
|
-
};
|
25
|
-
this.getAll = (key) => {
|
26
|
-
var _a;
|
27
|
-
return (_a = this.dict.get(key)) !== null && _a !== void 0 ? _a : [];
|
28
|
-
};
|
29
|
-
this.entries = () => this.dict.entries();
|
30
|
-
this.has = (key) => this.dict.has(key);
|
31
|
-
}
|
32
|
-
}
|
33
|
-
export const useMultiValueMap = () => {
|
34
|
-
const ref = useRef(null);
|
35
|
-
return () => {
|
36
|
-
if (ref.current)
|
37
|
-
return ref.current;
|
38
|
-
ref.current = new MultiValueMap();
|
39
|
-
return ref.current;
|
40
|
-
};
|
41
|
-
};
|
@@ -1,105 +0,0 @@
|
|
1
|
-
import { Atom } from "jotai";
|
2
|
-
import { InternalFormId } from "./state/atomUtils";
|
3
|
-
export declare const unregisterAtomsFamily: {
|
4
|
-
(param: InternalFormId): Atom<Atom<any>[]> & {
|
5
|
-
write: (get: {
|
6
|
-
<Value>(atom: Atom<Value | Promise<Value>>): Value;
|
7
|
-
<Value_1>(atom: Atom<Promise<Value_1>>): Value_1;
|
8
|
-
<Value_2>(atom: Atom<Value_2>): Value_2 extends Promise<infer V> ? V : Value_2;
|
9
|
-
} & {
|
10
|
-
<Value_3>(atom: Atom<Value_3 | Promise<Value_3>>, options: {
|
11
|
-
unstable_promise: true;
|
12
|
-
}): Value_3 | Promise<Value_3>;
|
13
|
-
<Value_4>(atom: Atom<Promise<Value_4>>, options: {
|
14
|
-
unstable_promise: true;
|
15
|
-
}): Value_4 | Promise<Value_4>;
|
16
|
-
<Value_5>(atom: Atom<Value_5>, options: {
|
17
|
-
unstable_promise: true;
|
18
|
-
}): (Value_5 extends Promise<infer V> ? V : Value_5) | Promise<Value_5 extends Promise<infer V> ? V : Value_5>;
|
19
|
-
}, set: {
|
20
|
-
<Value_6, Result extends void | Promise<void>>(atom: import("jotai").WritableAtom<Value_6, undefined, Result>): Result;
|
21
|
-
<Value_7, Update, Result_1 extends void | Promise<void>>(atom: import("jotai").WritableAtom<Value_7, Update, Result_1>, update: Update): Result_1;
|
22
|
-
}, update: Atom<any>[] | ((prev: Atom<any>[]) => Atom<any>[])) => void;
|
23
|
-
onMount?: (<S extends (update: Atom<any>[] | ((prev: Atom<any>[]) => Atom<any>[])) => void>(setAtom: S) => void | (() => void)) | undefined;
|
24
|
-
} & {
|
25
|
-
init: Atom<any>[];
|
26
|
-
};
|
27
|
-
remove(param: InternalFormId): void;
|
28
|
-
setShouldRemove(shouldRemove: ((createdAt: number, param: InternalFormId) => boolean) | null): void;
|
29
|
-
};
|
30
|
-
export declare const createCustomFormState: <T>(defaultValue: T) => {
|
31
|
-
__atomFamily: {
|
32
|
-
(param: InternalFormId): Atom<T> & {
|
33
|
-
write: (get: {
|
34
|
-
<Value>(atom: Atom<Value | Promise<Value>>): Value;
|
35
|
-
<Value_1>(atom: Atom<Promise<Value_1>>): Value_1;
|
36
|
-
<Value_2>(atom: Atom<Value_2>): Value_2 extends Promise<infer V> ? V : Value_2;
|
37
|
-
} & {
|
38
|
-
<Value_3>(atom: Atom<Value_3 | Promise<Value_3>>, options: {
|
39
|
-
unstable_promise: true;
|
40
|
-
}): Value_3 | Promise<Value_3>;
|
41
|
-
<Value_4>(atom: Atom<Promise<Value_4>>, options: {
|
42
|
-
unstable_promise: true;
|
43
|
-
}): Value_4 | Promise<Value_4>;
|
44
|
-
<Value_5>(atom: Atom<Value_5>, options: {
|
45
|
-
unstable_promise: true;
|
46
|
-
}): (Value_5 extends Promise<infer V> ? V : Value_5) | Promise<Value_5 extends Promise<infer V> ? V : Value_5>;
|
47
|
-
}, set: {
|
48
|
-
<Value_6, Result extends void | Promise<void>>(atom: import("jotai").WritableAtom<Value_6, undefined, Result>): Result;
|
49
|
-
<Value_7, Update, Result_1 extends void | Promise<void>>(atom: import("jotai").WritableAtom<Value_7, Update, Result_1>, update: Update): Result_1;
|
50
|
-
}, update: T | ((prev: T) => T)) => void;
|
51
|
-
onMount?: (<S extends import("jotai/core/atom").SetAtom<T | ((prev: T) => T), void>>(setAtom: S) => void | (() => void)) | undefined;
|
52
|
-
} & {
|
53
|
-
init: T;
|
54
|
-
};
|
55
|
-
remove(param: InternalFormId): void;
|
56
|
-
setShouldRemove(shouldRemove: ((createdAt: number, param: InternalFormId) => boolean) | null): void;
|
57
|
-
};
|
58
|
-
__registerAtom: Atom<null> & {
|
59
|
-
write: (get: {
|
60
|
-
<Value>(atom: Atom<Value | Promise<Value>>): Value;
|
61
|
-
<Value_1>(atom: Atom<Promise<Value_1>>): Value_1;
|
62
|
-
<Value_2>(atom: Atom<Value_2>): Value_2 extends Promise<infer V> ? V : Value_2;
|
63
|
-
} & {
|
64
|
-
<Value_3>(atom: Atom<Value_3 | Promise<Value_3>>, options: {
|
65
|
-
unstable_promise: true;
|
66
|
-
}): Value_3 | Promise<Value_3>;
|
67
|
-
<Value_4>(atom: Atom<Promise<Value_4>>, options: {
|
68
|
-
unstable_promise: true;
|
69
|
-
}): Value_4 | Promise<Value_4>;
|
70
|
-
<Value_5>(atom: Atom<Value_5>, options: {
|
71
|
-
unstable_promise: true;
|
72
|
-
}): (Value_5 extends Promise<infer V> ? V : Value_5) | Promise<Value_5 extends Promise<infer V> ? V : Value_5>;
|
73
|
-
}, set: {
|
74
|
-
<Value_6, Result extends void | Promise<void>>(atom: import("jotai").WritableAtom<Value_6, undefined, Result>): Result;
|
75
|
-
<Value_7, Update, Result_1 extends void | Promise<void>>(atom: import("jotai").WritableAtom<Value_7, Update, Result_1>, update: Update): Result_1;
|
76
|
-
}, update: InternalFormId) => void;
|
77
|
-
onMount?: (<S_1 extends (update: InternalFormId) => void>(setAtom: S_1) => void | (() => void)) | undefined;
|
78
|
-
} & {
|
79
|
-
init: null;
|
80
|
-
};
|
81
|
-
__unregisterAtom: Atom<null> & {
|
82
|
-
write: (get: {
|
83
|
-
<Value>(atom: Atom<Value | Promise<Value>>): Value;
|
84
|
-
<Value_1>(atom: Atom<Promise<Value_1>>): Value_1;
|
85
|
-
<Value_2>(atom: Atom<Value_2>): Value_2 extends Promise<infer V> ? V : Value_2;
|
86
|
-
} & {
|
87
|
-
<Value_3>(atom: Atom<Value_3 | Promise<Value_3>>, options: {
|
88
|
-
unstable_promise: true;
|
89
|
-
}): Value_3 | Promise<Value_3>;
|
90
|
-
<Value_4>(atom: Atom<Promise<Value_4>>, options: {
|
91
|
-
unstable_promise: true;
|
92
|
-
}): Value_4 | Promise<Value_4>;
|
93
|
-
<Value_5>(atom: Atom<Value_5>, options: {
|
94
|
-
unstable_promise: true;
|
95
|
-
}): (Value_5 extends Promise<infer V> ? V : Value_5) | Promise<Value_5 extends Promise<infer V> ? V : Value_5>;
|
96
|
-
}, set: {
|
97
|
-
<Value_6, Result extends void | Promise<void>>(atom: import("jotai").WritableAtom<Value_6, undefined, Result>): Result;
|
98
|
-
<Value_7, Update, Result_1 extends void | Promise<void>>(atom: import("jotai").WritableAtom<Value_7, Update, Result_1>, update: Update): Result_1;
|
99
|
-
}, update: InternalFormId) => void;
|
100
|
-
onMount?: (<S_1 extends (update: InternalFormId) => void>(setAtom: S_1) => void | (() => void)) | undefined;
|
101
|
-
} & {
|
102
|
-
init: null;
|
103
|
-
};
|
104
|
-
};
|
105
|
-
export declare const useCustomFormState: <T>(state: ReturnType<typeof createCustomFormState>, formId: InternalFormId) => readonly [T, (value: T) => void];
|
@@ -1,46 +0,0 @@
|
|
1
|
-
import { atom } from "jotai";
|
2
|
-
import { useAtomCallback } from "jotai/utils";
|
3
|
-
import { useCallback, useEffect } from "react";
|
4
|
-
import { useFormAtom } from "./hooks";
|
5
|
-
import { formAtomFamily } from "./state/atomUtils";
|
6
|
-
export const unregisterAtomsFamily = formAtomFamily([]);
|
7
|
-
export const createCustomFormState = (defaultValue) => {
|
8
|
-
const atomFamily = formAtomFamily(defaultValue);
|
9
|
-
const refCountFamily = formAtomFamily(0);
|
10
|
-
const registerAtom = atom(null, (get, set, formId) => {
|
11
|
-
const refCountAtom = refCountFamily(formId);
|
12
|
-
set(refCountAtom, (prev) => prev + 1);
|
13
|
-
const newRefCount = get(refCountAtom);
|
14
|
-
if (newRefCount === 1) {
|
15
|
-
set(unregisterAtomsFamily(formId), (prev) => [...prev, unregisterAtom]);
|
16
|
-
}
|
17
|
-
});
|
18
|
-
const unregisterAtom = atom(null, (get, set, formId) => {
|
19
|
-
const refCountAtom = refCountFamily(formId);
|
20
|
-
set(refCountAtom, (prev) => prev - 1);
|
21
|
-
const newRefCount = get(refCountAtom);
|
22
|
-
if (newRefCount === 0) {
|
23
|
-
set(unregisterAtomsFamily(formId), (prev) => prev.filter((item) => item !== unregisterAtom));
|
24
|
-
atomFamily.remove(formId);
|
25
|
-
refCountFamily.remove(formId);
|
26
|
-
}
|
27
|
-
});
|
28
|
-
return {
|
29
|
-
__atomFamily: atomFamily,
|
30
|
-
__registerAtom: registerAtom,
|
31
|
-
__unregisterAtom: unregisterAtom,
|
32
|
-
};
|
33
|
-
};
|
34
|
-
export const useCustomFormState = (state, formId) => {
|
35
|
-
const atom = state.__atomFamily(formId);
|
36
|
-
const [value, setValue] = useFormAtom(atom);
|
37
|
-
const register = useAtomCallback(useCallback((_get, set) => set(state.__registerAtom, formId), [formId, state.__registerAtom]));
|
38
|
-
const unregister = useAtomCallback(useCallback((_get, set) => set(state.__unregisterAtom, formId), [formId, state.__unregisterAtom]));
|
39
|
-
useEffect(() => {
|
40
|
-
register();
|
41
|
-
return () => {
|
42
|
-
unregister();
|
43
|
-
};
|
44
|
-
}, [register, unregister]);
|
45
|
-
return [value, setValue];
|
46
|
-
};
|
@@ -1,18 +0,0 @@
|
|
1
|
-
import { useUpdateAtom } from "jotai/utils";
|
2
|
-
import { FieldErrors, ValidationErrorResponseData } from "..";
|
3
|
-
import { InternalFormContextValue } from "./formContext";
|
4
|
-
import { Hydratable } from "./hydratable";
|
5
|
-
export declare const useInternalFormContext: (formId?: string | symbol | undefined, hookName?: string | undefined) => InternalFormContextValue;
|
6
|
-
export declare function useErrorResponseForForm({ fetcher, subaction, formId, }: InternalFormContextValue): ValidationErrorResponseData | null;
|
7
|
-
export declare const useFieldErrorsForForm: (context: InternalFormContextValue) => Hydratable<FieldErrors | undefined>;
|
8
|
-
export declare const useDefaultValuesFromLoader: ({ formId, }: InternalFormContextValue) => any;
|
9
|
-
export declare const useDefaultValuesForForm: (context: InternalFormContextValue) => Hydratable<{
|
10
|
-
[fieldName: string]: any;
|
11
|
-
}>;
|
12
|
-
export declare const useHasActiveFormSubmit: ({ fetcher, }: InternalFormContextValue) => boolean;
|
13
|
-
export declare const useFieldTouched: (name: string, { formId }: InternalFormContextValue) => boolean;
|
14
|
-
export declare const useFieldError: (name: string, context: InternalFormContextValue) => string | undefined;
|
15
|
-
export declare const useFieldDefaultValue: (name: string, context: InternalFormContextValue) => any;
|
16
|
-
export declare const useFormUpdateAtom: typeof useUpdateAtom;
|
17
|
-
export declare const useClearError: (context: InternalFormContextValue) => (name: string) => void;
|
18
|
-
export declare const useSetTouched: (context: InternalFormContextValue) => (name: string, touched: boolean) => void;
|