@inl0re/blnk 1.0.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 (64) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +148 -0
  3. package/README.ru.md +476 -0
  4. package/dist/core/createFormControl.d.ts +3 -0
  5. package/dist/core/createFormControl.d.ts.map +1 -0
  6. package/dist/core/fieldArrayState.d.ts +23 -0
  7. package/dist/core/fieldArrayState.d.ts.map +1 -0
  8. package/dist/core/fieldRegistry.d.ts +9 -0
  9. package/dist/core/fieldRegistry.d.ts.map +1 -0
  10. package/dist/core/formState.d.ts +13 -0
  11. package/dist/core/formState.d.ts.map +1 -0
  12. package/dist/core/store.d.ts +4 -0
  13. package/dist/core/store.d.ts.map +1 -0
  14. package/dist/core/subscriptionManager.d.ts +8 -0
  15. package/dist/core/subscriptionManager.d.ts.map +1 -0
  16. package/dist/core/transactionManager.d.ts +11 -0
  17. package/dist/core/transactionManager.d.ts.map +1 -0
  18. package/dist/core/validationEngine.d.ts +5 -0
  19. package/dist/core/validationEngine.d.ts.map +1 -0
  20. package/dist/hooks/Controller.d.ts +8 -0
  21. package/dist/hooks/Controller.d.ts.map +1 -0
  22. package/dist/hooks/useController.d.ts +23 -0
  23. package/dist/hooks/useController.d.ts.map +1 -0
  24. package/dist/hooks/useField.d.ts +4 -0
  25. package/dist/hooks/useField.d.ts.map +1 -0
  26. package/dist/hooks/useFieldArray.d.ts +23 -0
  27. package/dist/hooks/useFieldArray.d.ts.map +1 -0
  28. package/dist/hooks/useForm.d.ts +3 -0
  29. package/dist/hooks/useForm.d.ts.map +1 -0
  30. package/dist/hooks/useFormState.d.ts +9 -0
  31. package/dist/hooks/useFormState.d.ts.map +1 -0
  32. package/dist/hooks/useWatch.d.ts +22 -0
  33. package/dist/hooks/useWatch.d.ts.map +1 -0
  34. package/dist/index.cjs +2 -0
  35. package/dist/index.cjs.map +1 -0
  36. package/dist/index.d.ts +23 -0
  37. package/dist/index.d.ts.map +1 -0
  38. package/dist/index.mjs +669 -0
  39. package/dist/index.mjs.map +1 -0
  40. package/dist/resolvers/yupResolver.d.ts +4 -0
  41. package/dist/resolvers/yupResolver.d.ts.map +1 -0
  42. package/dist/resolvers/zodResolver.d.ts +4 -0
  43. package/dist/resolvers/zodResolver.d.ts.map +1 -0
  44. package/dist/types/form.d.ts +94 -0
  45. package/dist/types/form.d.ts.map +1 -0
  46. package/dist/types/path.d.ts +9 -0
  47. package/dist/types/path.d.ts.map +1 -0
  48. package/dist/types/resolver.d.ts +7 -0
  49. package/dist/types/resolver.d.ts.map +1 -0
  50. package/dist/utils/clone.d.ts +2 -0
  51. package/dist/utils/clone.d.ts.map +1 -0
  52. package/dist/utils/get.d.ts +2 -0
  53. package/dist/utils/get.d.ts.map +1 -0
  54. package/dist/utils/getInputValue.d.ts +7 -0
  55. package/dist/utils/getInputValue.d.ts.map +1 -0
  56. package/dist/utils/isEqual.d.ts +2 -0
  57. package/dist/utils/isEqual.d.ts.map +1 -0
  58. package/dist/utils/path.d.ts +3 -0
  59. package/dist/utils/path.d.ts.map +1 -0
  60. package/dist/utils/set.d.ts +2 -0
  61. package/dist/utils/set.d.ts.map +1 -0
  62. package/dist/utils/unset.d.ts +2 -0
  63. package/dist/utils/unset.d.ts.map +1 -0
  64. package/package.json +86 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 blnk contributors
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,148 @@
1
+ # blnk
2
+
3
+ `blnk` is an MVP React 19 form library with React Hook Form-like DX and a subscription-based mutable store under the hood. Inputs stay uncontrolled, while fields and selected form state can subscribe to precise updates.
4
+
5
+ ## Docs
6
+
7
+ - [Subscriptions](./docs/concepts/subscriptions.md)
8
+ - [Uncontrolled inputs](./docs/concepts/uncontrolled-inputs.md)
9
+ - [Conditional fields](./docs/guides/conditional-fields.md)
10
+ - [Field arrays](./docs/guides/field-arrays.md)
11
+ - [Validation](./docs/guides/validation.md)
12
+ - [Transactions](./docs/guides/transactions.md)
13
+
14
+ ## Examples
15
+
16
+ - [LoginFormExample](./src/examples/LoginFormExample.tsx)
17
+ - [WizardFormExample](./src/examples/WizardFormExample.tsx)
18
+ - [ServerPatchTransactionExample](./src/examples/ServerPatchTransactionExample.tsx)
19
+ - [ControlledInputExample](./src/examples/ControlledInputExample.tsx)
20
+ - [CheckboxConditionalFieldExample](./src/examples/CheckboxConditionalFieldExample.tsx)
21
+ - [ComplexFormExample](./src/examples/ComplexFormExample.tsx)
22
+
23
+ ## Basic Usage
24
+
25
+ ```tsx
26
+ import { useForm } from "blnk";
27
+
28
+ type FormValues = {
29
+ user: {
30
+ email: string;
31
+ age: number;
32
+ };
33
+ };
34
+
35
+ const form = useForm<FormValues>({
36
+ defaultValues: {
37
+ user: { email: "", age: 18 },
38
+ },
39
+ });
40
+
41
+ <form onSubmit={form.handleSubmit((data) => console.log(data.user.email))}>
42
+ <input {...form.register("user.email")} />
43
+ <input type="number" {...form.register("user.age", { valueAsNumber: true })} />
44
+ </form>;
45
+ ```
46
+
47
+ ## Nested Fields
48
+
49
+ Dot paths support nested objects and arrays:
50
+
51
+ ```ts
52
+ form.setValue("user.age", 25);
53
+ form.setValue("addresses.0.city", "Minsk");
54
+ form.watch("user.email");
55
+ form.reset();
56
+ ```
57
+
58
+ `register`, `setValue`, `watch`, and `handleSubmit` are generic-aware through `Path<T>` and `PathValue<T, P>`.
59
+
60
+ ## Validation Resolver
61
+
62
+ Use a custom resolver:
63
+
64
+ ```ts
65
+ const form = useForm<FormValues>({
66
+ resolver: async (values) => ({
67
+ values,
68
+ errors: values.user.email ? {} : { user: { email: { type: "required", message: "Required" } } },
69
+ }),
70
+ });
71
+ ```
72
+
73
+ Zod-like and Yup-like schemas are supported through lightweight adapters:
74
+
75
+ ```ts
76
+ import { zodResolver } from "blnk";
77
+
78
+ const form = useForm<FormValues>({
79
+ schema: userSchema,
80
+ resolver: zodResolver(userSchema),
81
+ mode: "onBlur",
82
+ });
83
+ ```
84
+
85
+ ## Async Validation
86
+
87
+ Field-level validators can be sync or async. Async validators support debouncing and stale result protection.
88
+
89
+ ```ts
90
+ const form = useForm<FormValues>({
91
+ asyncValidatorDebounceMs: 250,
92
+ asyncValidators: {
93
+ "user.email": async (email) => {
94
+ const exists = await api.checkEmail(email);
95
+ return exists ? "Email already exists" : true;
96
+ },
97
+ },
98
+ });
99
+ ```
100
+
101
+ ## Field Arrays
102
+
103
+ `useFieldArray` keeps stable `id` values for React keys.
104
+
105
+ ```tsx
106
+ const skills = useFieldArray({ control: form.control, name: "skills" });
107
+
108
+ skills.append({ title: "", level: "junior" });
109
+ skills.remove(0);
110
+ skills.move(0, 1);
111
+ ```
112
+
113
+ ## Subscriptions
114
+
115
+ Use `useWatch` when React UI needs to rerender from form values, `useField` for field-level snapshots, and `useFormState` for selector-based form state subscriptions.
116
+
117
+ ```ts
118
+ const emailValue = useWatch({ control: form.control, name: "user.email" });
119
+ const email = useField(form.control, "user.email");
120
+
121
+ const state = useFormState({
122
+ control: form.control,
123
+ selector: (formState) => ({
124
+ error: formState.errors.user?.email,
125
+ isDirty: formState.isDirty,
126
+ }),
127
+ });
128
+ ```
129
+
130
+ `form.watch("user.email")` is an imperative read. `form.watch("user.email", callback)` is an imperative subscription. `useWatch` is the React hook for conditional UI.
131
+
132
+ ## Transactions
133
+
134
+ Transactions batch several mutations into one notification wave.
135
+
136
+ ```ts
137
+ form.transaction(() => {
138
+ form.setValue("user.name", "Gleb");
139
+ form.setValue("user.email", "gleb@example.com");
140
+ form.setValue("user.age", 25);
141
+ });
142
+ ```
143
+
144
+ ## MVP Limits
145
+
146
+ - Field array metadata cleanup is still newer than the core field path flow, so keep array-heavy forms covered by tests.
147
+ - Resolver adapters are duck-typed to keep Zod/Yup optional peer dependencies.
148
+ - Package publishing metadata is intentionally minimal.
package/README.ru.md ADDED
@@ -0,0 +1,476 @@
1
+ # blnk
2
+
3
+ ## Docs
4
+
5
+ - [Subscriptions](./docs/concepts/subscriptions.md)
6
+ - [Uncontrolled inputs](./docs/concepts/uncontrolled-inputs.md)
7
+ - [Conditional fields](./docs/guides/conditional-fields.md)
8
+ - [Field arrays](./docs/guides/field-arrays.md)
9
+ - [Validation](./docs/guides/validation.md)
10
+ - [Transactions](./docs/guides/transactions.md)
11
+
12
+ ## Examples
13
+
14
+ - [LoginFormExample](./src/examples/LoginFormExample.tsx)
15
+ - [WizardFormExample](./src/examples/WizardFormExample.tsx)
16
+ - [ServerPatchTransactionExample](./src/examples/ServerPatchTransactionExample.tsx)
17
+ - [ControlledInputExample](./src/examples/ControlledInputExample.tsx)
18
+ - [CheckboxConditionalFieldExample](./src/examples/CheckboxConditionalFieldExample.tsx)
19
+ - [ComplexFormExample](./src/examples/ComplexFormExample.tsx)
20
+
21
+ `blnk` β€” Π±ΠΈΠ±Π»ΠΈΠΎΡ‚Π΅ΠΊΠ° Ρ„ΠΎΡ€ΠΌ для React 19. Π‘Π½Π°Ρ€ΡƒΠΆΠΈ ΠΎΠ½Π° ΠΏΠΎΡ…ΠΎΠΆΠ° Π½Π° React Hook Form: Ρ‚Ρ‹ Π²Ρ‹Π·Ρ‹Π²Π°Π΅ΡˆΡŒ `useForm`, Ρ€Π΅Π³ΠΈΡΡ‚Ρ€ΠΈΡ€ΡƒΠ΅ΡˆΡŒ поля Ρ‡Π΅Ρ€Π΅Π· `register` ΠΈ ΠΎΡ‚ΠΏΡ€Π°Π²Π»ΡΠ΅ΡˆΡŒ Ρ„ΠΎΡ€ΠΌΡƒ Ρ‡Π΅Ρ€Π΅Π· `handleSubmit`. Π’Π½ΡƒΡ‚Ρ€ΠΈ ΠΎΠ½Π° Ρ€Π°Π±ΠΎΡ‚Π°Π΅Ρ‚ ΠΈΠ½Π°Ρ‡Π΅: значСния Π»Π΅ΠΆΠ°Ρ‚ Π² mutable store, Π° ΠΊΠΎΠΌΠΏΠΎΠ½Π΅Π½Ρ‚Ρ‹ ΠΏΠΎΠ΄ΠΏΠΈΡΡ‹Π²Π°ΡŽΡ‚ΡΡ Ρ‚ΠΎΠ»ΡŒΠΊΠΎ Π½Π° Π½ΡƒΠΆΠ½Ρ‹Π΅ поля.
22
+
23
+ Π­Ρ‚ΠΎ Π·Π½Π°Ρ‡ΠΈΡ‚, Ρ‡Ρ‚ΠΎ Π²Π²ΠΎΠ΄ Π² ΠΎΠ΄Π½ΠΎ ΠΏΠΎΠ»Π΅ Π½Π΅ Π΄ΠΎΠ»ΠΆΠ΅Π½ ΠΏΠ΅Ρ€Π΅Ρ€ΠΈΡΠΎΠ²Ρ‹Π²Π°Ρ‚ΡŒ всю Ρ„ΠΎΡ€ΠΌΡƒ.
24
+
25
+ ## Π‘Π°ΠΌΡ‹ΠΉ ΠΊΠΎΡ€ΠΎΡ‚ΠΊΠΈΠΉ ΠΏΡ€ΠΈΠΌΠ΅Ρ€
26
+
27
+ Π­Ρ‚ΠΎΡ‚ ΠΏΡ€ΠΈΠΌΠ΅Ρ€ ΠΏΠΎΠΊΠ°Π·Ρ‹Π²Π°Π΅Ρ‚ Π³Π»Π°Π²Π½Ρ‹ΠΉ сцСнарий: ΡΠΎΠ·Π΄Π°Ρ‚ΡŒ Ρ„ΠΎΡ€ΠΌΡƒ, ΠΏΠΎΠ΄ΠΊΠ»ΡŽΡ‡ΠΈΡ‚ΡŒ input ΠΈ ΠΏΠΎΠ»ΡƒΡ‡ΠΈΡ‚ΡŒ Ρ‚ΠΈΠΏΠΈΠ·ΠΈΡ€ΠΎΠ²Π°Π½Π½Ρ‹Π΅ Π΄Π°Π½Π½Ρ‹Π΅ ΠΏΡ€ΠΈ submit.
28
+
29
+ ```tsx
30
+ import { useForm } from "blnk";
31
+
32
+ type FormValues = {
33
+ user: {
34
+ email: string;
35
+ age: number;
36
+ };
37
+ };
38
+
39
+ const form = useForm<FormValues>({
40
+ defaultValues: {
41
+ user: { email: "", age: 18 },
42
+ },
43
+ });
44
+
45
+ return (
46
+ <form onSubmit={form.handleSubmit((data) => console.log(data.user.email))}>
47
+ <input {...form.register("user.email")} />
48
+ <input type="number" {...form.register("user.age", { valueAsNumber: true })} />
49
+ <button type="submit">Save</button>
50
+ </form>
51
+ );
52
+ ```
53
+
54
+ Π§Ρ‚ΠΎ здСсь Π²Π°ΠΆΠ½ΠΎ:
55
+
56
+ - `FormValues` описываСт Ρ„ΠΎΡ€ΠΌΡƒ Ρ†Π΅Π»ΠΈΠΊΠΎΠΌ
57
+ - `register("user.email")` Π·Π½Π°Π΅Ρ‚, Ρ‡Ρ‚ΠΎ Ρ‚Π°ΠΊΠΎΠ΅ ΠΏΠΎΠ»Π΅ сущСствуСт
58
+ - `data.user.email` Ρ‚ΠΈΠΏΠΈΠ·ΠΈΡ€ΠΎΠ²Π°Π½ Π²Π½ΡƒΡ‚Ρ€ΠΈ `handleSubmit`
59
+ - `valueAsNumber` ΠΏΡ€Π΅Π²Ρ€Π°Ρ‰Π°Π΅Ρ‚ строку ΠΈΠ· `<input type="number">` Π² число
60
+
61
+ ## Как устроСн state
62
+
63
+ `blnk` Π½Π΅ Ρ…Ρ€Π°Π½ΠΈΡ‚ ΠΊΠ°ΠΆΠ΄ΠΎΠ΅ Π·Π½Π°Ρ‡Π΅Π½ΠΈΠ΅ input Π² React state. ВмСсто этого Ρ„ΠΎΡ€ΠΌΠ° Ρ…Ρ€Π°Π½ΠΈΡ‚ значСния Π²ΠΎ Π²Π½ΡƒΡ‚Ρ€Π΅Π½Π½Π΅ΠΌ ΠΎΠ±ΡŠΠ΅ΠΊΡ‚Π΅.
64
+
65
+ Когда ΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚Π΅Π»ΡŒ ΠΏΠ΅Ρ‡Π°Ρ‚Π°Π΅Ρ‚:
66
+
67
+ 1. `register` ΠΏΠΎΠ»ΡƒΡ‡Π°Π΅Ρ‚ событиС ΠΈΠ· input
68
+ 2. Π±ΠΈΠ±Π»ΠΈΠΎΡ‚Π΅ΠΊΠ° достаСт Π·Π½Π°Ρ‡Π΅Π½ΠΈΠ΅ ΠΈΠ· события
69
+ 3. Π·Π½Π°Ρ‡Π΅Π½ΠΈΠ΅ записываСтся Π²ΠΎ Π²Π½ΡƒΡ‚Ρ€Π΅Π½Π½ΠΈΠΉ store
70
+ 4. ΠΎΠ±Π½ΠΎΠ²Π»ΡΡŽΡ‚ΡΡ `dirtyFields`, `touchedFields` ΠΈΠ»ΠΈ `errors`
71
+ 5. ΡƒΠ²Π΅Π΄ΠΎΠΌΠ»ΡΡŽΡ‚ΡΡ Ρ‚ΠΎΠ»ΡŒΠΊΠΎ подписчики этого поля
72
+
73
+ Π’Π°ΠΊΠΎΠΉ ΠΏΠΎΠ΄Ρ…ΠΎΠ΄ ΠΏΠΎΠ»Π΅Π·Π΅Π½ для Π±ΠΎΠ»ΡŒΡˆΠΈΡ… Ρ„ΠΎΡ€ΠΌ. Если измСнилось `user.email`, ΠΊΠΎΠΌΠΏΠΎΠ½Π΅Π½Ρ‚ с `user.age` Π½Π΅ обязан Ρ€Π΅Ρ€Π΅Π½Π΄Π΅Ρ€ΠΈΡ‚ΡŒΡΡ.
74
+
75
+ ## Π’Π»ΠΎΠΆΠ΅Π½Π½Ρ‹Π΅ поля
76
+
77
+ Поля Π·Π°ΠΏΠΈΡΡ‹Π²Π°ΡŽΡ‚ΡΡ строками Ρ‡Π΅Ρ€Π΅Π· Ρ‚ΠΎΡ‡ΠΊΡƒ.
78
+
79
+ ```ts
80
+ form.setValue("user.age", 25);
81
+ form.setValue("addresses.0.city", "Minsk");
82
+
83
+ const email = form.watch("user.email");
84
+ ```
85
+
86
+ ΠŸΡƒΡ‚ΡŒ `addresses.0.city` ΠΎΠ·Π½Π°Ρ‡Π°Π΅Ρ‚: массив `addresses`, ΠΏΠ΅Ρ€Π²Ρ‹ΠΉ элСмСнт, ΠΏΠΎΠ»Π΅ `city`.
87
+
88
+ Π’ΠΈΠΏΡ‹ Ρ‚ΠΎΠΆΠ΅ Ρ€Π°Π±ΠΎΡ‚Π°ΡŽΡ‚ Ρ‡Π΅Ρ€Π΅Π· эти ΠΏΡƒΡ‚ΠΈ:
89
+
90
+ ```ts
91
+ form.setValue("user.age", 25);
92
+ form.setValue("user.email", "gleb@example.com");
93
+ ```
94
+
95
+ Если ΠΏΠ΅Ρ€Π΅Π΄Π°Ρ‚ΡŒ Π½Π΅ΠΏΡ€Π°Π²ΠΈΠ»ΡŒΠ½Ρ‹ΠΉ Ρ‚ΠΈΠΏ значСния, TypeScript Π΄ΠΎΠ»ΠΆΠ΅Π½ ΠΏΠΎΠ΄ΡΠ²Π΅Ρ‚ΠΈΡ‚ΡŒ ΠΎΡˆΠΈΠ±ΠΊΡƒ.
96
+
97
+ ## register
98
+
99
+ `register` Π²ΠΎΠ·Π²Ρ€Π°Ρ‰Π°Π΅Ρ‚ props для input.
100
+
101
+ ```tsx
102
+ <input {...form.register("user.email")} />
103
+ ```
104
+
105
+ На ΠΏΡ€Π°ΠΊΡ‚ΠΈΠΊΠ΅ это ΠΎΠ±ΡŠΠ΅ΠΊΡ‚:
106
+
107
+ ```ts
108
+ {
109
+ name,
110
+ ref,
111
+ onChange,
112
+ onBlur,
113
+ }
114
+ ```
115
+
116
+ `onChange` ΠΏΠΈΡˆΠ΅Ρ‚ Π·Π½Π°Ρ‡Π΅Π½ΠΈΠ΅ Π² store. `onBlur` ΠΎΡ‚ΠΌΠ΅Ρ‡Π°Π΅Ρ‚ ΠΏΠΎΠ»Π΅ ΠΊΠ°ΠΊ touched ΠΈ ΠΌΠΎΠΆΠ΅Ρ‚ Π·Π°ΠΏΡƒΡΡ‚ΠΈΡ‚ΡŒ Π²Π°Π»ΠΈΠ΄Π°Ρ†ΠΈΡŽ, Ссли Ρ„ΠΎΡ€ΠΌΠ° настроСна Π½Π° `mode: "onBlur"`.
117
+
118
+ ΠŸΠΎΠ΄Π΄Π΅Ρ€ΠΆΠΈΠ²Π°ΡŽΡ‚ΡΡ ΠΎΠ±Ρ‹Ρ‡Π½Ρ‹Π΅ HTML-поля:
119
+
120
+ - text input
121
+ - number input
122
+ - checkbox
123
+ - radio
124
+ - select
125
+ - textarea
126
+ - file input
127
+
128
+ ## handleSubmit
129
+
130
+ `handleSubmit` ΠΎΠ±ΠΎΡ€Π°Ρ‡ΠΈΠ²Π°Π΅Ρ‚ Ρ‚Π²ΠΎΠΉ submit handler.
131
+
132
+ ```tsx
133
+ <form
134
+ onSubmit={form.handleSubmit(
135
+ (values) => {
136
+ console.log(values.user.email);
137
+ },
138
+ (errors) => {
139
+ console.log(errors);
140
+ },
141
+ )}
142
+ >
143
+ ```
144
+
145
+ ΠŸΡ€ΠΈ submit Π±ΠΈΠ±Π»ΠΈΠΎΡ‚Π΅ΠΊΠ°:
146
+
147
+ 1. Π²Ρ‹Π·Ρ‹Π²Π°Π΅Ρ‚ `event.preventDefault()`
148
+ 2. ставит `formState.isSubmitting`
149
+ 3. запускаСт Π²Π°Π»ΠΈΠ΄Π°Ρ†ΠΈΡŽ всСй Ρ„ΠΎΡ€ΠΌΡ‹
150
+ 4. Π²Ρ‹Π·Ρ‹Π²Π°Π΅Ρ‚ `onValid`, Ссли ошибок Π½Π΅Ρ‚
151
+ 5. Π²Ρ‹Π·Ρ‹Π²Π°Π΅Ρ‚ `onInvalid`, Ссли ошибки Π΅ΡΡ‚ΡŒ
152
+ 6. обновляСт `isSubmitted` ΠΈ `submitCount`
153
+ 7. снимаСт `isSubmitting`
154
+
155
+ Submit handler ΠΌΠΎΠΆΠ΅Ρ‚ Π±Ρ‹Ρ‚ΡŒ async.
156
+
157
+ ## watch
158
+
159
+ `watch` ΠΌΠΎΠΆΠ½ΠΎ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚ΡŒ двумя способами.
160
+
161
+ ΠŸΠΎΠ»ΡƒΡ‡ΠΈΡ‚ΡŒ Ρ‚Π΅ΠΊΡƒΡ‰Π΅Π΅ Π·Π½Π°Ρ‡Π΅Π½ΠΈΠ΅:
162
+
163
+ ```ts
164
+ const email = form.watch("user.email");
165
+ ```
166
+
167
+ ΠŸΠΎΠ΄ΠΏΠΈΡΠ°Ρ‚ΡŒΡΡ Π½Π° измСнСния:
168
+
169
+ ```ts
170
+ const unsubscribe = form.watch("user.email", (email) => {
171
+ console.log(email);
172
+ });
173
+ ```
174
+
175
+ Π’ΠΎ Π²Ρ‚ΠΎΡ€ΠΎΠΌ Π²Π°Ρ€ΠΈΠ°Π½Ρ‚Π΅ Ρ‚Ρ‹ сам Π²Ρ‹Π·Ρ‹Π²Π°Π΅ΡˆΡŒ `unsubscribe`, ΠΊΠΎΠ³Π΄Π° подписка большС Π½Π΅ Π½ΡƒΠΆΠ½Π°.
176
+
177
+ ## useWatch
178
+
179
+ `useWatch` Π½ΡƒΠΆΠ΅Π½, ΠΊΠΎΠ³Π΄Π° Π·Π½Π°Ρ‡Π΅Π½ΠΈΠ΅ поля Π΄ΠΎΠ»ΠΆΠ½ΠΎ ΡƒΠΏΡ€Π°Π²Π»ΡΡ‚ΡŒ React UI.
180
+
181
+ ```ts
182
+ const wantsDetails = useWatch({
183
+ control: form.control,
184
+ name: "wantsDetails",
185
+ });
186
+ ```
187
+
188
+ ΠŸΡ€ΠΈΠΌΠ΅Ρ€: чСкбокс ΠΏΠΎΠΊΠ°Π·Ρ‹Π²Π°Π΅Ρ‚ Π΄ΠΎΠΏΠΎΠ»Π½ΠΈΡ‚Π΅Π»ΡŒΠ½ΠΎΠ΅ ΠΏΠΎΠ»Π΅.
189
+
190
+ ```tsx
191
+ {
192
+ wantsDetails ? <input {...form.register("details")} /> : null;
193
+ }
194
+ ```
195
+
196
+ Π Π°Π·Π½ΠΈΡ†Π° простая:
197
+
198
+ - `form.watch("field")` Ρ‡ΠΈΡ‚Π°Π΅Ρ‚ Ρ‚Π΅ΠΊΡƒΡ‰Π΅Π΅ Π·Π½Π°Ρ‡Π΅Π½ΠΈΠ΅
199
+ - `form.watch("field", callback)` подписываСтся Π²Ρ€ΡƒΡ‡Π½ΡƒΡŽ
200
+ - `useWatch(...)` подписываСт React-ΠΊΠΎΠΌΠΏΠΎΠ½Π΅Π½Ρ‚ ΠΈ Π²Ρ‹Π·Ρ‹Π²Π°Π΅Ρ‚ Ρ€Π΅Ρ€Π΅Π½Π΄Π΅Ρ€
201
+
202
+ ## formState
203
+
204
+ `formState` Ρ…Ρ€Π°Π½ΠΈΡ‚ слуТСбноС состояниС Ρ„ΠΎΡ€ΠΌΡ‹.
205
+
206
+ ```ts
207
+ form.formState.isDirty;
208
+ form.formState.isSubmitting;
209
+ form.formState.errors.user?.email;
210
+ ```
211
+
212
+ Π“Π»Π°Π²Π½Ρ‹Π΅ поля:
213
+
214
+ - `errors`: ошибки Π²Π°Π»ΠΈΠ΄Π°Ρ†ΠΈΠΈ
215
+ - `touchedFields`: поля, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹Π΅ потСряли фокус
216
+ - `dirtyFields`: поля, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹Π΅ ΠΎΡ‚Π»ΠΈΡ‡Π°ΡŽΡ‚ΡΡ ΠΎΡ‚ `defaultValues`
217
+ - `isDirty`: Π² Ρ„ΠΎΡ€ΠΌΠ΅ Π΅ΡΡ‚ΡŒ ΠΈΠ·ΠΌΠ΅Π½Π΅Π½Π½Ρ‹Π΅ поля
218
+ - `isValid`: Π² Ρ„ΠΎΡ€ΠΌΠ΅ Π½Π΅Ρ‚ ошибок
219
+ - `isValidating`: ΠΈΠ΄Π΅Ρ‚ async validation
220
+ - `isSubmitting`: ΠΈΠ΄Π΅Ρ‚ submit
221
+ - `isSubmitted`: Ρ„ΠΎΡ€ΠΌΠ° ΡƒΠΆΠ΅ ΠΎΡ‚ΠΏΡ€Π°Π²Π»ΡΠ»Π°ΡΡŒ
222
+ - `submitCount`: количСство submit ΠΏΠΎΠΏΡ‹Ρ‚ΠΎΠΊ
223
+
224
+ ## useField
225
+
226
+ `useField` Π½ΡƒΠΆΠ΅Π½, ΠΊΠΎΠ³Π΄Π° ΠΊΠΎΠΌΠΏΠΎΠ½Π΅Π½Ρ‚ Π΄ΠΎΠ»ΠΆΠ΅Π½ ΡΠ»Π΅Π΄ΠΈΡ‚ΡŒ Ρ‚ΠΎΠ»ΡŒΠΊΠΎ Π·Π° ΠΎΠ΄Π½ΠΈΠΌ ΠΏΠΎΠ»Π΅ΠΌ.
227
+
228
+ ```ts
229
+ const email = useField(form.control, "user.email");
230
+ ```
231
+
232
+ Он Π²ΠΎΠ·Π²Ρ€Π°Ρ‰Π°Π΅Ρ‚:
233
+
234
+ ```ts
235
+ {
236
+ value,
237
+ error,
238
+ isDirty,
239
+ isTouched,
240
+ isValidating,
241
+ }
242
+ ```
243
+
244
+ Если измСнится Π΄Ρ€ΡƒΠ³ΠΎΠ΅ ΠΏΠΎΠ»Π΅, этот ΠΊΠΎΠΌΠΏΠΎΠ½Π΅Π½Ρ‚ Π½Π΅ Π΄ΠΎΠ»ΠΆΠ΅Π½ ΠΎΠ±Π½ΠΎΠ²Π»ΡΡ‚ΡŒΡΡ ΠΈΠ·-Π·Π° Π½Π΅Π³ΠΎ.
245
+
246
+ ## useFormState
247
+
248
+ `useFormState` Π½ΡƒΠΆΠ΅Π½, ΠΊΠΎΠ³Π΄Π° ΠΊΠΎΠΌΠΏΠΎΠ½Π΅Π½Ρ‚Ρƒ Π½ΡƒΠΆΠ½Π° Π½Π΅ вся Ρ„ΠΎΡ€ΠΌΠ°, Π° выбранная Ρ‡Π°ΡΡ‚ΡŒ `formState`.
249
+
250
+ ```ts
251
+ const state = useFormState({
252
+ control: form.control,
253
+ selector: (formState) => ({
254
+ error: formState.errors.user?.email,
255
+ isDirty: formState.isDirty,
256
+ }),
257
+ });
258
+ ```
259
+
260
+ Selector ΠΏΠΎΠΌΠΎΠ³Π°Π΅Ρ‚ Π½Π΅ ΠΏΠΎΠ΄ΠΏΠΈΡΡ‹Π²Π°Ρ‚ΡŒ ΠΊΠΎΠΌΠΏΠΎΠ½Π΅Π½Ρ‚ Π½Π° лишниС измСнСния.
261
+
262
+ ## Валидация Ρ‡Π΅Ρ€Π΅Π· resolver
263
+
264
+ Resolver β€” это функция, которая ΠΏΠΎΠ»ΡƒΡ‡Π°Π΅Ρ‚ всС значСния Ρ„ΠΎΡ€ΠΌΡ‹ ΠΈ Π²ΠΎΠ·Π²Ρ€Π°Ρ‰Π°Π΅Ρ‚ Π»ΠΈΠ±ΠΎ Π΄Π°Π½Π½Ρ‹Π΅, Π»ΠΈΠ±ΠΎ ошибки.
265
+
266
+ ```ts
267
+ const form = useForm<FormValues>({
268
+ resolver: async (values) => ({
269
+ values,
270
+ errors: values.user.email
271
+ ? {}
272
+ : { user: { email: { type: "required", message: "Email is required" } } },
273
+ }),
274
+ });
275
+ ```
276
+
277
+ Π€ΠΎΡ€ΠΌΠ°Ρ‚ ошибки:
278
+
279
+ ```ts
280
+ {
281
+ type: "required",
282
+ message: "Email is required",
283
+ }
284
+ ```
285
+
286
+ Π’Π°ΠΊΠΎΠΉ слой позволяСт ΠΏΠΎΠ΄ΠΊΠ»ΡŽΡ‡Π°Ρ‚ΡŒ Π»ΡŽΠ±ΡƒΡŽ схСму Π²Π°Π»ΠΈΠ΄Π°Ρ†ΠΈΠΈ.
287
+
288
+ ## Zod ΠΈ Yup
289
+
290
+ Π’ Π±ΠΈΠ±Π»ΠΈΠΎΡ‚Π΅ΠΊΠ΅ Π΅ΡΡ‚ΡŒ Π°Π΄Π°ΠΏΡ‚Π΅Ρ€Ρ‹:
291
+
292
+ ```ts
293
+ import { zodResolver, yupResolver } from "blnk";
294
+ ```
295
+
296
+ ΠŸΡ€ΠΈΠΌΠ΅Ρ€ с Zod-like схСмой:
297
+
298
+ ```ts
299
+ const form = useForm<FormValues>({
300
+ resolver: zodResolver(userSchema),
301
+ mode: "onBlur",
302
+ });
303
+ ```
304
+
305
+ Zod ΠΈ Yup Π½Π΅ установлСны ΠΊΠ°ΠΊ ΠΎΠ±ΡΠ·Π°Ρ‚Π΅Π»ΡŒΠ½Ρ‹Π΅ зависимости. Они ΡƒΠΊΠ°Π·Π°Π½Ρ‹ ΠΊΠ°ΠΊ optional peer dependencies, поэтому ΠΏΡ€ΠΎΠ΅ΠΊΡ‚ сам Ρ€Π΅ΡˆΠ°Π΅Ρ‚, Π½ΡƒΠΆΠ½Ρ‹ ΠΎΠ½ΠΈ Π΅ΠΌΡƒ ΠΈΠ»ΠΈ Π½Π΅Ρ‚.
306
+
307
+ ## Field-level validation
308
+
309
+ Π’Π°Π»ΠΈΠ΄Π°Ρ†ΠΈΡŽ ΠΌΠΎΠΆΠ½ΠΎ ΠΏΠΎΠ²Π΅ΡΠΈΡ‚ΡŒ Π½Π° ΠΊΠΎΠ½ΠΊΡ€Π΅Ρ‚Π½ΠΎΠ΅ ΠΏΠΎΠ»Π΅.
310
+
311
+ ```tsx
312
+ <input
313
+ {...form.register("user.email", {
314
+ required: "Email is required",
315
+ validate: (email) => email.includes("@") || "Email is invalid",
316
+ })}
317
+ />
318
+ ```
319
+
320
+ `validate` Π²ΠΎΠ·Π²Ρ€Π°Ρ‰Π°Π΅Ρ‚:
321
+
322
+ - `true`, Ссли Π·Π½Π°Ρ‡Π΅Π½ΠΈΠ΅ Π²Π°Π»ΠΈΠ΄Π½ΠΎ
323
+ - строку, Ссли Π½ΡƒΠΆΠ½ΠΎ ΠΏΠΎΠΊΠ°Π·Π°Ρ‚ΡŒ ΠΎΡˆΠΈΠ±ΠΊΡƒ
324
+ - ΠΎΠ±ΡŠΠ΅ΠΊΡ‚ ошибки, Ссли Π½ΡƒΠΆΠ΅Π½ свой `type`
325
+
326
+ ## Async validation
327
+
328
+ Асинхронная валидация ΠΏΠΎΠ»Π΅Π·Π½Π° для ΠΏΡ€ΠΎΠ²Π΅Ρ€ΠΎΠΊ Π½Π° сСрвСрС. НапримСр, ΠΏΡ€ΠΎΠ²Π΅Ρ€ΠΈΡ‚ΡŒ, занят Π»ΠΈ email.
329
+
330
+ ```ts
331
+ const form = useForm<FormValues>({
332
+ mode: "onBlur",
333
+ asyncValidatorDebounceMs: 250,
334
+ asyncValidators: {
335
+ "user.email": async (email) => {
336
+ const exists = await api.checkEmail(email);
337
+ return exists ? "Email already exists" : true;
338
+ },
339
+ },
340
+ });
341
+ ```
342
+
343
+ Π’Π°ΠΆΠ½Ρ‹Π΅ Π΄Π΅Ρ‚Π°Π»ΠΈ:
344
+
345
+ - debounce Π·Π°Π΄Π΅Ρ€ΠΆΠΈΠ²Π°Π΅Ρ‚ запрос, Ссли ΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚Π΅Π»ΡŒ ΠΏΡ€ΠΎΠ΄ΠΎΠ»ΠΆΠ°Π΅Ρ‚ Π²Π²ΠΎΠ΄
346
+ - stale result protection ΠΈΠ³Π½ΠΎΡ€ΠΈΡ€ΡƒΠ΅Ρ‚ старый ΠΎΡ‚Π²Π΅Ρ‚, Ссли ΡƒΠΆΠ΅ Π½Π°Ρ‡Π°Π»Π°ΡΡŒ новая ΠΏΡ€ΠΎΠ²Π΅Ρ€ΠΊΠ°
347
+ - `formState.isValidating` ΠΏΠΎΠΊΠ°Π·Ρ‹Π²Π°Π΅Ρ‚, Ρ‡Ρ‚ΠΎ ΠΈΠ΄Π΅Ρ‚ ΠΏΡ€ΠΎΠ²Π΅Ρ€ΠΊΠ°
348
+ - `formState.validatingFields` ΠΏΠΎΠΊΠ°Π·Ρ‹Π²Π°Π΅Ρ‚, ΠΊΠ°ΠΊΠΈΠ΅ поля ΠΏΡ€ΠΎΠ²Π΅Ρ€ΡΡŽΡ‚ΡΡ
349
+
350
+ ## Field arrays
351
+
352
+ `useFieldArray` управляСт массивами ΠΏΠΎΠ»Π΅ΠΉ.
353
+
354
+ ```tsx
355
+ const skills = useFieldArray({
356
+ control: form.control,
357
+ name: "skills",
358
+ });
359
+
360
+ skills.append({ title: "", level: "junior" });
361
+ skills.remove(0);
362
+ ```
363
+
364
+ `fields` содСрТит элСмСнты массива плюс ΡΡ‚Π°Π±ΠΈΠ»ΡŒΠ½Ρ‹ΠΉ `id`.
365
+
366
+ ```tsx
367
+ {
368
+ skills.fields.map((skill, index) => (
369
+ <div key={skill.id}>
370
+ <input {...form.register(`skills.${index}.title`)} />
371
+ </div>
372
+ ));
373
+ }
374
+ ```
375
+
376
+ Π˜ΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠΉ `skill.id` ΠΊΠ°ΠΊ React key. НС ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠΉ `index` ΠΊΠ°ΠΊ key, ΠΏΠΎΡ‚ΠΎΠΌΡƒ Ρ‡Ρ‚ΠΎ ΠΏΡ€ΠΈ ΡƒΠ΄Π°Π»Π΅Π½ΠΈΠΈ ΠΈΠ»ΠΈ ΠΏΠ΅Ρ€Π΅ΠΌΠ΅Ρ‰Π΅Π½ΠΈΠΈ элСмСнтов React ΠΌΠΎΠΆΠ΅Ρ‚ ΠΏΠ΅Ρ€Π΅ΠΏΡƒΡ‚Π°Ρ‚ΡŒ DOM.
377
+
378
+ ДоступныС ΠΎΠΏΠ΅Ρ€Π°Ρ†ΠΈΠΈ:
379
+
380
+ - `append`: Π΄ΠΎΠ±Π°Π²ΠΈΡ‚ΡŒ Π² ΠΊΠΎΠ½Π΅Ρ†
381
+ - `remove`: ΡƒΠ΄Π°Π»ΠΈΡ‚ΡŒ ΠΏΠΎ индСксу
382
+ - `insert`: Π²ΡΡ‚Π°Π²ΠΈΡ‚ΡŒ ΠΏΠΎ индСксу
383
+ - `move`: ΠΏΠ΅Ρ€Π΅ΠΌΠ΅ΡΡ‚ΠΈΡ‚ΡŒ
384
+ - `swap`: ΠΏΠΎΠΌΠ΅Π½ΡΡ‚ΡŒ мСстами
385
+ - `replace`: Π·Π°ΠΌΠ΅Π½ΠΈΡ‚ΡŒ вСсь массив
386
+
387
+ ## Transactions API
388
+
389
+ Transaction Π½ΡƒΠΆΠ½Π°, ΠΊΠΎΠ³Π΄Π° Ρ‚Ρ‹ мСняСшь сразу нСсколько ΠΏΠΎΠ»Π΅ΠΉ.
390
+
391
+ ```ts
392
+ form.transaction(() => {
393
+ form.setValue("user.name", "Gleb");
394
+ form.setValue("user.email", "gleb@example.com");
395
+ form.setValue("user.age", 25);
396
+ });
397
+ ```
398
+
399
+ Π‘Π΅Π· transaction ΠΊΠ°ΠΆΠ΄ΠΎΠ΅ ΠΈΠ·ΠΌΠ΅Π½Π΅Π½ΠΈΠ΅ увСдомляСт подписчиков ΠΎΡ‚Π΄Π΅Π»ΡŒΠ½ΠΎ. Π’Π½ΡƒΡ‚Ρ€ΠΈ transaction измСнСния ΠΏΡ€ΠΈΠΌΠ΅Π½ΡΡŽΡ‚ΡΡ сразу, Π½ΠΎ увСдомлСния ΠΎΡ‚ΠΏΡ€Π°Π²Π»ΡΡŽΡ‚ΡΡ ΠΎΠ΄Π½ΠΎΠΉ ΠΏΠ°Ρ‡ΠΊΠΎΠΉ послС `commitTransaction`.
400
+
401
+ Π­Ρ‚ΠΎ ΡƒΠ΄ΠΎΠ±Π½ΠΎ для:
402
+
403
+ - server patches
404
+ - wizard forms
405
+ - autosave
406
+ - заполнСния Ρ„ΠΎΡ€ΠΌΡ‹ ΠΈΠ· шаблона
407
+ - массового reset части Ρ„ΠΎΡ€ΠΌΡ‹
408
+
409
+ НизкоуровнСвый API Ρ‚ΠΎΠΆΠ΅ доступСн:
410
+
411
+ ```ts
412
+ form.beginTransaction();
413
+ form.setValue("user.name", "Gleb");
414
+ form.setValue("user.age", 25);
415
+ form.commitTransaction();
416
+ ```
417
+
418
+ Π’ Π±ΠΎΠ»ΡŒΡˆΠΈΠ½ΡΡ‚Π²Π΅ случаСв ΡƒΠ΄ΠΎΠ±Π½Π΅Π΅ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚ΡŒ `form.transaction`.
419
+
420
+ ## reset
421
+
422
+ `reset` Π²ΠΎΠ·Π²Ρ€Π°Ρ‰Π°Π΅Ρ‚ Ρ„ΠΎΡ€ΠΌΡƒ ΠΊ `defaultValues`.
423
+
424
+ ```ts
425
+ form.reset();
426
+ ```
427
+
428
+ МоТно ΠΏΠ΅Ρ€Π΅Π΄Π°Ρ‚ΡŒ Π½ΠΎΠ²Ρ‹Π΅ значСния:
429
+
430
+ ```ts
431
+ form.reset({
432
+ user: {
433
+ email: "new@example.com",
434
+ age: 30,
435
+ },
436
+ });
437
+ ```
438
+
439
+ ПослС reset ΠΎΡ‡ΠΈΡ‰Π°ΡŽΡ‚ΡΡ ошибки, touched, dirty ΠΈ submit state.
440
+
441
+ ## Π§Ρ‚ΠΎ ΡƒΠΆΠ΅ Π΅ΡΡ‚ΡŒ
442
+
443
+ - RHF-like API
444
+ - uncontrolled inputs
445
+ - mutable store
446
+ - подписки на поля
447
+ - selector-based подписки на `formState`
448
+ - `useWatch` для условного React UI
449
+ - nested paths
450
+ - arrays ΠΈ `useFieldArray`
451
+ - custom resolver
452
+ - Zod/Yup adapters
453
+ - field-level validation
454
+ - async validation с debounce
455
+ - Π·Π°Ρ‰ΠΈΡ‚Π° ΠΎΡ‚ race condition
456
+ - transactions
457
+ - TypeScript-Ρ‚ΠΈΠΏΡ‹ для основных сцСнариСв
458
+
459
+ ## ΠžΠ³Ρ€Π°Π½ΠΈΡ‡Π΅Π½ΠΈΡ MVP
460
+
461
+ - НСт adapter для controlled components
462
+ - React rendering tests ΠΏΠΎΠΊΠ° ΠΏΠΎΠΊΡ€Ρ‹Π²Π°ΡŽΡ‚ `useWatch` ΠΈ checkbox conditional-field example
463
+ - ΠžΡ‡ΠΈΡΡ‚ΠΊΠ° `errors`, `touched` ΠΈ `dirty` ΠΏΡ€ΠΈ слоТных пСрСстановках field arrays ΠΏΠΎΠΊΠ° базовая
464
+ - Zod/Yup adapters ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΡŽΡ‚ duck typing
465
+ - Package publishing metadata минимальная
466
+ - `Path<T>` ΠΎΠ³Ρ€Π°Π½ΠΈΡ‡Π΅Π½ Ρ€Π°Π·ΡƒΠΌΠ½ΠΎΠΉ Π³Π»ΡƒΠ±ΠΈΠ½ΠΎΠΉ, Ρ‡Ρ‚ΠΎΠ±Ρ‹ TypeScript Π½Π΅ ΡƒΡ…ΠΎΠ΄ΠΈΠ» Π² Π±Π΅ΡΠΊΠΎΠ½Π΅Ρ‡Π½ΡƒΡŽ Ρ€Π΅ΠΊΡƒΡ€ΡΠΈΡŽ
467
+
468
+ ## Как ΠΏΡ€ΠΎΠ²Π΅Ρ€ΠΈΡ‚ΡŒ ΠΏΡ€ΠΎΠ΅ΠΊΡ‚
469
+
470
+ ```bash
471
+ npm test
472
+ npm run typecheck
473
+ npm run build
474
+ ```
475
+
476
+ `lint`-скрипта сСйчас Π½Π΅Ρ‚.
@@ -0,0 +1,3 @@
1
+ import type { FieldValues, FormControl, UseFormOptions } from "../types/form";
2
+ export declare function createFormControl<T extends FieldValues>(options?: UseFormOptions<T>): FormControl<T>;
3
+ //# sourceMappingURL=createFormControl.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"createFormControl.d.ts","sourceRoot":"","sources":["../../src/core/createFormControl.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAEV,WAAW,EACX,WAAW,EAIX,cAAc,EAGf,MAAM,eAAe,CAAC;AA8DvB,wBAAgB,iBAAiB,CAAC,CAAC,SAAS,WAAW,EACrD,OAAO,GAAE,cAAc,CAAC,CAAC,CAAM,GAC9B,WAAW,CAAC,CAAC,CAAC,CAwYhB"}
@@ -0,0 +1,23 @@
1
+ export declare function getFieldArrayIds(control: object, name: string, length: number): string[];
2
+ export declare function setFieldArrayIds(control: object, name: string, ids: string[]): void;
3
+ export declare function createFieldArrayId(): string;
4
+ export type FieldArrayMetadataOperation = {
5
+ type: "append";
6
+ } | {
7
+ type: "remove";
8
+ index: number;
9
+ } | {
10
+ type: "insert";
11
+ index: number;
12
+ } | {
13
+ type: "move";
14
+ from: number;
15
+ to: number;
16
+ } | {
17
+ type: "swap";
18
+ left: number;
19
+ right: number;
20
+ } | {
21
+ type: "replace";
22
+ };
23
+ //# sourceMappingURL=fieldArrayState.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fieldArrayState.d.ts","sourceRoot":"","sources":["../../src/core/fieldArrayState.ts"],"names":[],"mappings":"AAiBA,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,CAWxF;AAED,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,IAAI,CAEnF;AAED,wBAAgB,kBAAkB,IAAI,MAAM,CAE3C;AAED,MAAM,MAAM,2BAA2B,GACnC;IAAE,IAAI,EAAE,QAAQ,CAAA;CAAE,GAClB;IAAE,IAAI,EAAE,QAAQ,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,GACjC;IAAE,IAAI,EAAE,QAAQ,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,GACjC;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,EAAE,EAAE,MAAM,CAAA;CAAE,GAC1C;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,GAC7C;IAAE,IAAI,EAAE,SAAS,CAAA;CAAE,CAAC"}
@@ -0,0 +1,9 @@
1
+ import type { FieldValues, RegisterOptions } from "../types/form";
2
+ import type { Path } from "../types/path";
3
+ export type RegisteredField<T extends FieldValues> = {
4
+ ref: unknown;
5
+ options?: RegisterOptions<T, any>;
6
+ };
7
+ export declare function setRegisteredField<T extends FieldValues>(fields: Map<string, RegisteredField<T>>, refs: Map<string, unknown>, name: Path<T>, ref: unknown, options?: RegisterOptions<T, any>): void;
8
+ export declare function unsetRegisteredField<T extends FieldValues>(fields: Map<string, RegisteredField<T>>, refs: Map<string, unknown>, name: Path<T>): void;
9
+ //# sourceMappingURL=fieldRegistry.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fieldRegistry.d.ts","sourceRoot":"","sources":["../../src/core/fieldRegistry.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAClE,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,eAAe,CAAC;AAE1C,MAAM,MAAM,eAAe,CAAC,CAAC,SAAS,WAAW,IAAI;IACnD,GAAG,EAAE,OAAO,CAAC;IACb,OAAO,CAAC,EAAE,eAAe,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC;CACnC,CAAC;AAEF,wBAAgB,kBAAkB,CAAC,CAAC,SAAS,WAAW,EACtD,MAAM,EAAE,GAAG,CAAC,MAAM,EAAE,eAAe,CAAC,CAAC,CAAC,CAAC,EACvC,IAAI,EAAE,GAAG,CAAC,MAAM,EAAE,OAAO,CAAC,EAC1B,IAAI,EAAE,IAAI,CAAC,CAAC,CAAC,EACb,GAAG,EAAE,OAAO,EACZ,OAAO,CAAC,EAAE,eAAe,CAAC,CAAC,EAAE,GAAG,CAAC,GAChC,IAAI,CAIN;AAED,wBAAgB,oBAAoB,CAAC,CAAC,SAAS,WAAW,EACxD,MAAM,EAAE,GAAG,CAAC,MAAM,EAAE,eAAe,CAAC,CAAC,CAAC,CAAC,EACvC,IAAI,EAAE,GAAG,CAAC,MAAM,EAAE,OAAO,CAAC,EAC1B,IAAI,EAAE,IAAI,CAAC,CAAC,CAAC,GACZ,IAAI,CAIN"}