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.
Files changed (137) hide show
  1. package/.turbo/turbo-build.log +15 -9
  2. package/README.md +1 -0
  3. package/browser/internal/logic/getRadioChecked.js +10 -0
  4. package/browser/internal/reset.d.ts +0 -0
  5. package/browser/internal/reset.js +0 -0
  6. package/browser/unreleased/formStateHooks.d.ts +0 -0
  7. package/browser/unreleased/formStateHooks.js +0 -0
  8. package/dist/remix-validated-form.cjs.js +1 -0
  9. package/dist/remix-validated-form.es.js +3535 -0
  10. package/dist/remix-validated-form.umd.js +1 -0
  11. package/{build → dist/types}/ValidatedForm.d.ts +0 -0
  12. package/{build → dist/types}/hooks.d.ts +0 -0
  13. package/{build → dist/types}/index.d.ts +0 -0
  14. package/{build → dist/types}/internal/MultiValueMap.d.ts +0 -0
  15. package/{build → dist/types}/internal/constants.d.ts +0 -0
  16. package/{build → dist/types}/internal/flatten.d.ts +0 -0
  17. package/{build → dist/types}/internal/formContext.d.ts +0 -0
  18. package/{build → dist/types}/internal/getInputProps.d.ts +0 -0
  19. package/{build → dist/types}/internal/hooks.d.ts +0 -0
  20. package/{build → dist/types}/internal/hydratable.d.ts +0 -0
  21. package/{build → dist/types}/internal/logic/getCheckboxChecked.d.ts +0 -0
  22. package/{build → dist/types}/internal/logic/getRadioChecked.d.ts +0 -0
  23. package/{build → dist/types}/internal/reset.d.ts +0 -0
  24. package/{build → dist/types}/internal/state/atomUtils.d.ts +0 -0
  25. package/{build → dist/types}/internal/state/controlledFields.d.ts +0 -0
  26. package/{build → dist/types}/internal/state.d.ts +0 -0
  27. package/{build → dist/types}/internal/submissionCallbacks.d.ts +0 -0
  28. package/{build → dist/types}/internal/util.d.ts +0 -0
  29. package/{build → dist/types}/server.d.ts +0 -0
  30. package/{build → dist/types}/unreleased/formStateHooks.d.ts +0 -0
  31. package/{build → dist/types}/userFacingFormContext.d.ts +0 -0
  32. package/{build → dist/types}/validation/createValidator.d.ts +0 -0
  33. package/{build → dist/types}/validation/types.d.ts +0 -0
  34. package/package.json +8 -7
  35. package/src/internal/getInputProps.test.ts +251 -0
  36. package/src/internal/logic/getRadioChecked.ts +11 -0
  37. package/src/validation/validation.test.ts +304 -0
  38. package/tsconfig.json +4 -1
  39. package/vite.config.ts +7 -0
  40. package/.turbo/turbo-test.log +0 -11
  41. package/browser/components.d.ts +0 -7
  42. package/browser/components.js +0 -10
  43. package/browser/internal/SingleTypeMultiValueMap.d.ts +0 -9
  44. package/browser/internal/SingleTypeMultiValueMap.js +0 -41
  45. package/browser/internal/customState.d.ts +0 -105
  46. package/browser/internal/customState.js +0 -46
  47. package/browser/internal/hooks-valtio.d.ts +0 -18
  48. package/browser/internal/hooks-valtio.js +0 -110
  49. package/browser/internal/hooks-zustand.d.ts +0 -16
  50. package/browser/internal/hooks-zustand.js +0 -100
  51. package/browser/internal/immerMiddleware.d.ts +0 -6
  52. package/browser/internal/immerMiddleware.js +0 -7
  53. package/browser/internal/logic/elementUtils.d.ts +0 -3
  54. package/browser/internal/logic/elementUtils.js +0 -3
  55. package/browser/internal/logic/getCheckboxChecked copy.d.ts +0 -1
  56. package/browser/internal/logic/getCheckboxChecked copy.js +0 -9
  57. package/browser/internal/logic/setFieldValue.d.ts +0 -1
  58. package/browser/internal/logic/setFieldValue.js +0 -40
  59. package/browser/internal/logic/setInputValueInForm.d.ts +0 -1
  60. package/browser/internal/logic/setInputValueInForm.js +0 -77
  61. package/browser/internal/setFieldValue.d.ts +0 -20
  62. package/browser/internal/setFieldValue.js +0 -83
  63. package/browser/internal/setFormValues.d.ts +0 -2
  64. package/browser/internal/setFormValues.js +0 -26
  65. package/browser/internal/state/setFieldValue.d.ts +0 -0
  66. package/browser/internal/state/setFieldValue.js +0 -1
  67. package/browser/internal/state-valtio.d.ts +0 -62
  68. package/browser/internal/state-valtio.js +0 -69
  69. package/browser/internal/state-zustand.d.ts +0 -47
  70. package/browser/internal/state-zustand.js +0 -85
  71. package/browser/internal/test.d.ts +0 -0
  72. package/browser/internal/test.js +0 -15
  73. package/browser/internal/useMultiValueMap.d.ts +0 -1
  74. package/browser/internal/useMultiValueMap.js +0 -11
  75. package/browser/internal/watch.d.ts +0 -18
  76. package/browser/internal/watch.js +0 -122
  77. package/browser/lowLevelHooks.d.ts +0 -0
  78. package/browser/lowLevelHooks.js +0 -1
  79. package/browser/test-data/testFormData.d.ts +0 -15
  80. package/browser/test-data/testFormData.js +0 -46
  81. package/browser/types.d.ts +0 -1
  82. package/browser/types.js +0 -1
  83. package/browser/validation/validation.test.d.ts +0 -1
  84. package/browser/validation/validation.test.js +0 -274
  85. package/browser/validation/withYup.d.ts +0 -6
  86. package/browser/validation/withYup.js +0 -40
  87. package/browser/validation/withZod.d.ts +0 -6
  88. package/browser/validation/withZod.js +0 -50
  89. package/build/ValidatedForm.js +0 -261
  90. package/build/hooks.js +0 -91
  91. package/build/index.js +0 -18
  92. package/build/internal/MultiValueMap.js +0 -48
  93. package/build/internal/SingleTypeMultiValueMap.d.ts +0 -8
  94. package/build/internal/SingleTypeMultiValueMap.js +0 -45
  95. package/build/internal/constants.js +0 -7
  96. package/build/internal/flatten.js +0 -14
  97. package/build/internal/formContext.js +0 -5
  98. package/build/internal/getInputProps.js +0 -58
  99. package/build/internal/hooks-valtio.d.ts +0 -18
  100. package/build/internal/hooks-valtio.js +0 -128
  101. package/build/internal/hooks-zustand.d.ts +0 -16
  102. package/build/internal/hooks-zustand.js +0 -117
  103. package/build/internal/hooks.js +0 -128
  104. package/build/internal/hydratable.js +0 -17
  105. package/build/internal/immerMiddleware.d.ts +0 -6
  106. package/build/internal/immerMiddleware.js +0 -14
  107. package/build/internal/logic/elementUtils.d.ts +0 -3
  108. package/build/internal/logic/elementUtils.js +0 -9
  109. package/build/internal/logic/getCheckboxChecked.js +0 -13
  110. package/build/internal/logic/getRadioChecked.js +0 -9
  111. package/build/internal/logic/setFieldValue.d.ts +0 -1
  112. package/build/internal/logic/setFieldValue.js +0 -47
  113. package/build/internal/logic/setInputValueInForm.d.ts +0 -1
  114. package/build/internal/logic/setInputValueInForm.js +0 -84
  115. package/build/internal/reset.js +0 -19
  116. package/build/internal/setFormValues.d.ts +0 -2
  117. package/build/internal/setFormValues.js +0 -33
  118. package/build/internal/state/atomUtils.js +0 -13
  119. package/build/internal/state/controlledFields.js +0 -103
  120. package/build/internal/state-valtio.d.ts +0 -62
  121. package/build/internal/state-valtio.js +0 -83
  122. package/build/internal/state-zustand.d.ts +0 -47
  123. package/build/internal/state-zustand.js +0 -91
  124. package/build/internal/state.js +0 -71
  125. package/build/internal/submissionCallbacks.js +0 -17
  126. package/build/internal/test.d.ts +0 -1
  127. package/build/internal/test.js +0 -12
  128. package/build/internal/util.js +0 -41
  129. package/build/internal/watch.d.ts +0 -20
  130. package/build/internal/watch.js +0 -126
  131. package/build/server.js +0 -32
  132. package/build/types.d.ts +0 -1
  133. package/build/types.js +0 -2
  134. package/build/unreleased/formStateHooks.js +0 -59
  135. package/build/userFacingFormContext.js +0 -30
  136. package/build/validation/createValidator.js +0 -45
  137. 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
@@ -1,5 +1,8 @@
1
1
  {
2
2
  "extends": "tsconfig/tsconfig.json",
3
+ "compilerOptions": {
4
+ "module": "esnext"
5
+ },
3
6
  "include": ["src/**/*.ts", "src/**/*.tsx"],
4
- "exclude": ["node_modules"]
7
+ "exclude": ["node_modules", "**/*.test.ts", "**/*.test.tsx"]
5
8
  }
package/vite.config.ts ADDED
@@ -0,0 +1,7 @@
1
+ import { makeConfig } from "vite-config";
2
+
3
+ export default makeConfig({
4
+ lib: "remix-validated-form",
5
+ external: ["react", "@remix-run/react", "@remix-run/server-runtime"],
6
+ dir: __dirname,
7
+ });
@@ -1,11 +0,0 @@
1
- $ jest src
2
- No tests found, exiting with code 1
3
- Run with `--passWithNoTests` to exit with code 0
4
- In /Users/aaronpettengill/dev/remix-validated-form/packages/remix-validated-form
5
- 68 files checked.
6
- testMatch: **/__tests__/**/*.[jt]s?(x), **/?(*.)+(spec|test).[tj]s?(x) - 2 matches
7
- testPathIgnorePatterns: /node_modules/ - 68 matches
8
- testRegex: - 0 matches
9
- Pattern: src - 0 matches
10
- info Visit https://yarnpkg.com/en/docs/cli/run for documentation about this command.
11
- error Command failed with exit code 1.
@@ -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 {};
@@ -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;