@reformer/core 1.0.0-beta.1

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 (147) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +143 -0
  3. package/dist/behaviors/compute-from.d.ts +2 -0
  4. package/dist/behaviors/compute-from.js +31 -0
  5. package/dist/behaviors/copy-from.d.ts +2 -0
  6. package/dist/behaviors/copy-from.js +29 -0
  7. package/dist/behaviors/enable-when.d.ts +2 -0
  8. package/dist/behaviors/enable-when.js +25 -0
  9. package/dist/behaviors/reset-when.d.ts +2 -0
  10. package/dist/behaviors/reset-when.js +24 -0
  11. package/dist/behaviors/revalidate-when.d.ts +2 -0
  12. package/dist/behaviors/revalidate-when.js +18 -0
  13. package/dist/behaviors/sync-fields.d.ts +2 -0
  14. package/dist/behaviors/sync-fields.js +41 -0
  15. package/dist/behaviors/transform-value.d.ts +2 -0
  16. package/dist/behaviors/transform-value.js +45 -0
  17. package/dist/behaviors/watch-field.d.ts +2 -0
  18. package/dist/behaviors/watch-field.js +21 -0
  19. package/dist/behaviors.d.ts +6 -0
  20. package/dist/behaviors.js +29 -0
  21. package/dist/core/behavior/behavior-context.d.ts +47 -0
  22. package/dist/core/behavior/behavior-registry.d.ts +85 -0
  23. package/dist/core/behavior/behaviors/compute-from.d.ts +70 -0
  24. package/dist/core/behavior/behaviors/copy-from.d.ts +56 -0
  25. package/dist/core/behavior/behaviors/enable-when.d.ts +118 -0
  26. package/dist/core/behavior/behaviors/index.d.ts +11 -0
  27. package/dist/core/behavior/behaviors/reset-when.d.ts +64 -0
  28. package/dist/core/behavior/behaviors/revalidate-when.d.ts +53 -0
  29. package/dist/core/behavior/behaviors/sync-fields.d.ts +48 -0
  30. package/dist/core/behavior/behaviors/transform-value.d.ts +192 -0
  31. package/dist/core/behavior/behaviors/watch-field.d.ts +80 -0
  32. package/dist/core/behavior/compose-behavior.d.ts +96 -0
  33. package/dist/core/behavior/index.d.ts +11 -0
  34. package/dist/core/behavior/types.d.ts +146 -0
  35. package/dist/core/factories/index.d.ts +6 -0
  36. package/dist/core/factories/node-factory.d.ts +186 -0
  37. package/dist/core/nodes/array-node.d.ts +328 -0
  38. package/dist/core/nodes/field-node.d.ts +294 -0
  39. package/dist/core/nodes/form-node.d.ts +340 -0
  40. package/dist/core/nodes/group-node.d.ts +319 -0
  41. package/dist/core/types/deep-schema.d.ts +68 -0
  42. package/dist/core/types/field-path.d.ts +42 -0
  43. package/dist/core/types/form-context.d.ts +89 -0
  44. package/dist/core/types/form-proxy.d.ts +105 -0
  45. package/dist/core/types/index.d.ts +209 -0
  46. package/dist/core/types/validation-schema.d.ts +95 -0
  47. package/dist/core/utils/abstract-registry.d.ts +74 -0
  48. package/dist/core/utils/aggregate-signals.d.ts +71 -0
  49. package/dist/core/utils/create-form.d.ts +44 -0
  50. package/dist/core/utils/error-handler.d.ts +163 -0
  51. package/dist/core/utils/field-path-navigator.d.ts +240 -0
  52. package/dist/core/utils/field-path.d.ts +60 -0
  53. package/dist/core/utils/form-observer.d.ts +176 -0
  54. package/dist/core/utils/form-proxy-builder.d.ts +25 -0
  55. package/dist/core/utils/form-submitter.d.ts +121 -0
  56. package/dist/core/utils/index.d.ts +22 -0
  57. package/dist/core/utils/registry-helpers.d.ts +43 -0
  58. package/dist/core/utils/registry-stack.d.ts +69 -0
  59. package/dist/core/utils/safe-effect.d.ts +73 -0
  60. package/dist/core/utils/status-machine.d.ts +153 -0
  61. package/dist/core/utils/subscription-manager.d.ts +180 -0
  62. package/dist/core/utils/type-guards.d.ts +98 -0
  63. package/dist/core/utils/unique-id.d.ts +53 -0
  64. package/dist/core/validation/core/apply-when.d.ts +22 -0
  65. package/dist/core/validation/core/apply.d.ts +52 -0
  66. package/dist/core/validation/core/index.d.ts +8 -0
  67. package/dist/core/validation/core/validate-async.d.ts +36 -0
  68. package/dist/core/validation/core/validate-tree.d.ts +35 -0
  69. package/dist/core/validation/core/validate.d.ts +26 -0
  70. package/dist/core/validation/index.d.ts +27 -0
  71. package/dist/core/validation/validate-form.d.ts +48 -0
  72. package/dist/core/validation/validation-applicator.d.ts +70 -0
  73. package/dist/core/validation/validation-context.d.ts +86 -0
  74. package/dist/core/validation/validation-registry.d.ts +142 -0
  75. package/dist/core/validation/validators/array-validators.d.ts +53 -0
  76. package/dist/core/validation/validators/date-utils.d.ts +26 -0
  77. package/dist/core/validation/validators/email.d.ts +37 -0
  78. package/dist/core/validation/validators/future-date.d.ts +35 -0
  79. package/dist/core/validation/validators/index.d.ts +20 -0
  80. package/dist/core/validation/validators/is-date.d.ts +36 -0
  81. package/dist/core/validation/validators/max-age.d.ts +36 -0
  82. package/dist/core/validation/validators/max-date.d.ts +36 -0
  83. package/dist/core/validation/validators/max-length.d.ts +38 -0
  84. package/dist/core/validation/validators/max.d.ts +38 -0
  85. package/dist/core/validation/validators/min-age.d.ts +36 -0
  86. package/dist/core/validation/validators/min-date.d.ts +36 -0
  87. package/dist/core/validation/validators/min-length.d.ts +38 -0
  88. package/dist/core/validation/validators/min.d.ts +38 -0
  89. package/dist/core/validation/validators/number.d.ts +31 -0
  90. package/dist/core/validation/validators/past-date.d.ts +35 -0
  91. package/dist/core/validation/validators/pattern.d.ts +40 -0
  92. package/dist/core/validation/validators/phone.d.ts +27 -0
  93. package/dist/core/validation/validators/required.d.ts +41 -0
  94. package/dist/core/validation/validators/url.d.ts +22 -0
  95. package/dist/date-utils-xUWFslTj.js +29 -0
  96. package/dist/field-path-DuKdGcIE.js +66 -0
  97. package/dist/hooks/types.d.ts +328 -0
  98. package/dist/hooks/useArrayLength.d.ts +31 -0
  99. package/dist/hooks/useFormControl.d.ts +24 -0
  100. package/dist/hooks/useFormControlValue.d.ts +167 -0
  101. package/dist/hooks/useHiddenCondition.d.ts +25 -0
  102. package/dist/hooks/useSignalSubscription.d.ts +17 -0
  103. package/dist/index-D25LsbRm.js +73 -0
  104. package/dist/index.d.ts +17 -0
  105. package/dist/index.js +3271 -0
  106. package/dist/registry-helpers-Bv_BJ1s-.js +615 -0
  107. package/dist/safe-effect-Dh8uw81c.js +20 -0
  108. package/dist/validate-C3XiA_zf.js +10 -0
  109. package/dist/validators/email.d.ts +2 -0
  110. package/dist/validators/email.js +13 -0
  111. package/dist/validators/future-date.d.ts +2 -0
  112. package/dist/validators/future-date.js +20 -0
  113. package/dist/validators/is-date.d.ts +2 -0
  114. package/dist/validators/is-date.js +12 -0
  115. package/dist/validators/max-age.d.ts +2 -0
  116. package/dist/validators/max-age.js +20 -0
  117. package/dist/validators/max-date.d.ts +2 -0
  118. package/dist/validators/max-date.js +20 -0
  119. package/dist/validators/max-length.d.ts +2 -0
  120. package/dist/validators/max-length.js +11 -0
  121. package/dist/validators/max.d.ts +2 -0
  122. package/dist/validators/max.js +11 -0
  123. package/dist/validators/min-age.d.ts +2 -0
  124. package/dist/validators/min-age.js +20 -0
  125. package/dist/validators/min-date.d.ts +2 -0
  126. package/dist/validators/min-date.js +20 -0
  127. package/dist/validators/min-length.d.ts +2 -0
  128. package/dist/validators/min-length.js +11 -0
  129. package/dist/validators/min.d.ts +2 -0
  130. package/dist/validators/min.js +11 -0
  131. package/dist/validators/number.d.ts +2 -0
  132. package/dist/validators/number.js +35 -0
  133. package/dist/validators/past-date.d.ts +2 -0
  134. package/dist/validators/past-date.js +20 -0
  135. package/dist/validators/pattern.d.ts +2 -0
  136. package/dist/validators/pattern.js +11 -0
  137. package/dist/validators/phone.d.ts +2 -0
  138. package/dist/validators/phone.js +35 -0
  139. package/dist/validators/required.d.ts +2 -0
  140. package/dist/validators/required.js +15 -0
  141. package/dist/validators/url.d.ts +2 -0
  142. package/dist/validators/url.js +19 -0
  143. package/dist/validators-BGsNOgT1.js +207 -0
  144. package/dist/validators.d.ts +6 -0
  145. package/dist/validators.js +56 -0
  146. package/llms.txt +9351 -0
  147. package/package.json +166 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2024 Alexandr Bukhtatyy
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,143 @@
1
+ # @reformer/core
2
+
3
+ [![npm version](https://img.shields.io/npm/v/@reformer/core.svg)](https://www.npmjs.com/package/@reformer/core)
4
+ [![npm downloads](https://img.shields.io/npm/dm/@reformer/core.svg)](https://www.npmjs.com/package/@reformer/core)
5
+ [![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](https://opensource.org/licenses/MIT)
6
+
7
+ Reactive form state management library for React with signals-based architecture.
8
+
9
+ ## Playground
10
+
11
+ [![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz_small.svg)](https://stackblitz.com/~/github.com/AlexandrBukhtatyy/ReFormer/tree/main/projects/react-playground?file=projects/react-playground/src/App.tsx)
12
+
13
+ ## Documentation
14
+
15
+ Full documentation is available at [https://alexandrbukhtatyy.github.io/ReFormer/](https://alexandrbukhtatyy.github.io/ReFormer/)
16
+
17
+ ## Features
18
+
19
+ - Signals-based reactive state management
20
+ - Declarative form validation
21
+ - Dynamic form behaviors
22
+ - TypeScript support
23
+ - Tree-shakeable exports
24
+
25
+ ## Installation
26
+
27
+ ```bash
28
+ npm install @reformer/core@beta # Active development is underway, so you can try beta
29
+ ```
30
+
31
+ ## Quick Start
32
+
33
+ ```tsx
34
+ import { useMemo } from 'react';
35
+ import {
36
+ createForm,
37
+ useFormControl,
38
+ required,
39
+ email,
40
+ validate,
41
+ watchField,
42
+ FieldNode,
43
+ } from '@reformer/core';
44
+
45
+ // 0. Simple FormField component
46
+ function FormField({ label, control }: { label: string; control: FieldNode<string> }) {
47
+ const { value, errors } = useFormControl(control);
48
+
49
+ return (
50
+ <div>
51
+ <label>{label}</label>
52
+ <input
53
+ value={value}
54
+ onChange={(e) => control.setValue(e.target.value)}
55
+ onBlur={() => control.markAsTouched()}
56
+ />
57
+ {errors.length > 0 && <span className="error">{errors[0].message}</span>}
58
+ </div>
59
+ );
60
+ }
61
+
62
+ // 1. Define form interface
63
+ interface RegistrationForm {
64
+ username: string;
65
+ email: string;
66
+ password: string;
67
+ confirmPassword: string;
68
+ }
69
+
70
+ // 2. Form schema
71
+ const formSchema = {
72
+ username: { value: '' },
73
+ email: { value: '' },
74
+ password: { value: '' },
75
+ confirmPassword: { value: '' },
76
+ };
77
+
78
+ // 3. Validation schema
79
+ validationSchema = (path) => {
80
+ required(path.username);
81
+
82
+ required(path.email);
83
+ email(path.email);
84
+
85
+ required(path.password);
86
+ required(path.confirmPassword);
87
+
88
+ // Cross-field validation: passwords must match
89
+ validate(path.confirmPassword, (value, ctx) => {
90
+ const password = ctx.form.password.value.value;
91
+ if (value && password && value !== password) {
92
+ return { code: 'mismatch', message: 'Passwords do not match' };
93
+ }
94
+ return null;
95
+ });
96
+ };
97
+
98
+ // 4. Behavior schema
99
+ behavior = (path) => {
100
+ // Clear confirmPassword when password changes (if not empty)
101
+ watchField(path.password, (_, ctx) => {
102
+ const confirmValue = ctx.form.confirmPassword.value.value;
103
+ if (confirmValue) {
104
+ ctx.form.confirmPassword.setValue('', { emitEvent: false });
105
+ }
106
+ });
107
+ };
108
+
109
+ // 5. Registration form component
110
+ function RegistrationFormExample() {
111
+ const form = useMemo(
112
+ () =>
113
+ createForm<RegistrationForm>({
114
+ form: formSchema,
115
+ validation: validationSchema,
116
+ behavior: behaviorSchema,
117
+ }),
118
+ []
119
+ );
120
+
121
+ const handleSubmit = async (e: React.FormEvent) => {
122
+ e.preventDefault();
123
+ await form.validate();
124
+ if (form.valid.value) {
125
+ console.log('Form data:', form.value.value);
126
+ }
127
+ };
128
+
129
+ return (
130
+ <form onSubmit={handleSubmit}>
131
+ <FormField label="Username" control={form.username} />
132
+ <FormField label="Email" control={form.email} />
133
+ <FormField label="Password" control={form.password} />
134
+ <FormField label="Confirm Password" control={form.confirmPassword} />
135
+ <button type="submit">Register</button>
136
+ </form>
137
+ );
138
+ }
139
+ ```
140
+
141
+ ## License
142
+
143
+ MIT
@@ -0,0 +1,2 @@
1
+ export * from '../core/behavior/behaviors/compute-from'
2
+ export {}
@@ -0,0 +1,31 @@
1
+ import { effect as _ } from "@preact/signals-core";
2
+ import { b as v } from "../registry-helpers-Bv_BJ1s-.js";
3
+ import { r as V } from "../safe-effect-Dh8uw81c.js";
4
+ function N(n, i, s, f) {
5
+ const { debounce: p, condition: u } = f || {}, h = (r, E, m) => {
6
+ const a = r.getFieldByPath(i.__path);
7
+ if (!a) return null;
8
+ const o = n.map((e) => r.getFieldByPath(e.__path)).filter((e) => e !== void 0);
9
+ return o.length === 0 ? null : _(() => {
10
+ o.forEach((e) => e.value.value), m(() => {
11
+ if (u) {
12
+ const t = r.getValue();
13
+ if (!u(t)) return;
14
+ }
15
+ const e = o.map((t) => t.value.value), l = {};
16
+ n.forEach((t, d) => {
17
+ const g = t.__path.split(".").pop() || t.__path;
18
+ l[g] = e[d];
19
+ });
20
+ const c = s(l);
21
+ a.value.peek() !== c && V(() => {
22
+ a.setValue(c, { emitEvent: !1 });
23
+ });
24
+ });
25
+ });
26
+ };
27
+ v().register(h, { debounce: p });
28
+ }
29
+ export {
30
+ N as computeFrom
31
+ };
@@ -0,0 +1,2 @@
1
+ export * from '../core/behavior/behaviors/copy-from'
2
+ export {}
@@ -0,0 +1,29 @@
1
+ import { r as s } from "../safe-effect-Dh8uw81c.js";
2
+ import { watchField as d } from "./watch-field.js";
3
+ function E(l, c, m) {
4
+ const { when: a, fields: o = "all", transform: i, debounce: p } = m || {};
5
+ d(
6
+ l,
7
+ (t, n) => {
8
+ if (a) {
9
+ const f = n.form.getValue();
10
+ if (!a(f)) return;
11
+ }
12
+ const h = i ? i(t) : t, e = n.form.getFieldByPath(c.__path);
13
+ e && s(() => {
14
+ if (o === "all" || !o)
15
+ e.setValue(h, { emitEvent: !1 });
16
+ else {
17
+ const f = {};
18
+ o.forEach((r) => {
19
+ t && typeof t == "object" && (f[r] = t[r]);
20
+ }), "patchValue" in e && e.patchValue(f);
21
+ }
22
+ });
23
+ },
24
+ { debounce: p }
25
+ );
26
+ }
27
+ export {
28
+ E as copyFrom
29
+ };
@@ -0,0 +1,2 @@
1
+ export * from '../core/behavior/behaviors/enable-when'
2
+ export {}
@@ -0,0 +1,25 @@
1
+ import { effect as c } from "@preact/signals-core";
2
+ import { b } from "../registry-helpers-Bv_BJ1s-.js";
3
+ import { r as d } from "../safe-effect-Dh8uw81c.js";
4
+ function h(t, n, r) {
5
+ const { debounce: o, resetOnDisable: a = !1 } = r || {}, i = (s, m, l) => {
6
+ const e = s.getFieldByPath(t.__path);
7
+ return e ? c(() => {
8
+ const f = s.value.value;
9
+ l(() => {
10
+ const u = n(f);
11
+ d(() => {
12
+ u ? e.enable() : (e.disable(), a && e.reset());
13
+ });
14
+ });
15
+ }) : null;
16
+ };
17
+ b().register(i, { debounce: o });
18
+ }
19
+ function _(t, n, r) {
20
+ h(t, (o) => !n(o), r);
21
+ }
22
+ export {
23
+ _ as disableWhen,
24
+ h as enableWhen
25
+ };
@@ -0,0 +1,2 @@
1
+ export * from '../core/behavior/behaviors/reset-when'
2
+ export {}
@@ -0,0 +1,24 @@
1
+ import { effect as c } from "@preact/signals-core";
2
+ import { b as d } from "../registry-helpers-Bv_BJ1s-.js";
3
+ import { r as h } from "../safe-effect-Dh8uw81c.js";
4
+ function R(r, n, o) {
5
+ const { debounce: s, resetValue: u = null, onlyIfDirty: a = !1 } = o || {}, i = (t, m, l) => {
6
+ const e = t.getFieldByPath(r.__path);
7
+ return e ? c(() => {
8
+ const f = t.value.value;
9
+ l(() => {
10
+ if (n(f)) {
11
+ if (a && !e.dirty.value)
12
+ return;
13
+ h(() => {
14
+ e.setValue(u), e.markAsPristine(), e.markAsUntouched();
15
+ });
16
+ }
17
+ });
18
+ }) : null;
19
+ };
20
+ d().register(i, { debounce: s });
21
+ }
22
+ export {
23
+ R as resetWhen
24
+ };
@@ -0,0 +1,2 @@
1
+ export * from '../core/behavior/behaviors/revalidate-when'
2
+ export {}
@@ -0,0 +1,18 @@
1
+ import { effect as d } from "@preact/signals-core";
2
+ import { b as h } from "../registry-helpers-Bv_BJ1s-.js";
3
+ function p(o, a, i) {
4
+ const { debounce: l } = i || {}, u = (t, s, c) => {
5
+ const r = t.getFieldByPath(o.__path);
6
+ if (!r) return null;
7
+ const n = a.map((e) => t.getFieldByPath(e.__path)).filter((e) => e !== void 0);
8
+ return n.length === 0 ? null : d(() => {
9
+ n.forEach((e) => e.value.value), c(() => {
10
+ r.validate();
11
+ });
12
+ });
13
+ };
14
+ h().register(u, { debounce: l });
15
+ }
16
+ export {
17
+ p as revalidateWhen
18
+ };
@@ -0,0 +1,2 @@
1
+ export * from '../core/behavior/behaviors/sync-fields'
2
+ export {}
@@ -0,0 +1,41 @@
1
+ import { effect as o } from "@preact/signals-core";
2
+ import { b as v } from "../registry-helpers-Bv_BJ1s-.js";
3
+ import { r as i } from "../safe-effect-Dh8uw81c.js";
4
+ function E(u, f, c) {
5
+ const { debounce: d, transform: a } = c || {}, p = (n, h, l) => {
6
+ const r = n.getFieldByPath(u.__path), s = n.getFieldByPath(f.__path);
7
+ if (!r || !s) return null;
8
+ let e = !1;
9
+ const g = o(() => {
10
+ const t = r.value.value;
11
+ e || l(() => {
12
+ e = !0, i(() => {
13
+ try {
14
+ const y = a ? a(t) : t;
15
+ s.setValue(y, { emitEvent: !1 });
16
+ } finally {
17
+ e = !1;
18
+ }
19
+ });
20
+ });
21
+ }), m = o(() => {
22
+ const t = s.value.value;
23
+ e || l(() => {
24
+ e = !0, i(() => {
25
+ try {
26
+ r.setValue(t, { emitEvent: !1 });
27
+ } finally {
28
+ e = !1;
29
+ }
30
+ });
31
+ });
32
+ });
33
+ return () => {
34
+ g(), m();
35
+ };
36
+ };
37
+ v().register(p, { debounce: d });
38
+ }
39
+ export {
40
+ E as syncFields
41
+ };
@@ -0,0 +1,2 @@
1
+ export * from '../core/behavior/behaviors/transform-value'
2
+ export {}
@@ -0,0 +1,45 @@
1
+ import { watchField as p } from "./watch-field.js";
2
+ function u(e, t, o) {
3
+ const { onUserChangeOnly: n = !1, emitEvent: m = !0, debounce: c } = o || {};
4
+ p(
5
+ e,
6
+ (s, i) => {
7
+ const a = i.form.getFieldByPath(e.__path);
8
+ if (!a || n && !a.touched.value)
9
+ return;
10
+ const f = t(s);
11
+ f !== s && a.setValue(f, { emitEvent: m });
12
+ },
13
+ { debounce: c }
14
+ );
15
+ }
16
+ function r(e, t) {
17
+ return (o, n) => {
18
+ u(o, e, { ...t, ...n });
19
+ };
20
+ }
21
+ const h = {
22
+ /** Перевести в верхний регистр */
23
+ toUpperCase: r((e) => e?.toUpperCase()),
24
+ /** Перевести в нижний регистр */
25
+ toLowerCase: r((e) => e?.toLowerCase()),
26
+ /** Удалить пробелы с краев */
27
+ trim: r((e) => e?.trim()),
28
+ /** Удалить все пробелы */
29
+ removeSpaces: r((e) => e?.replace(/\s/g, "")),
30
+ /** Оставить только цифры */
31
+ digitsOnly: r((e) => e?.replace(/\D/g, "")),
32
+ /** Округлить число */
33
+ round: r(
34
+ (e) => typeof e == "number" ? Math.round(e) : e
35
+ ),
36
+ /** Округлить до 2 знаков после запятой */
37
+ roundTo2: r(
38
+ (e) => typeof e == "number" ? Math.round(e * 100) / 100 : e
39
+ )
40
+ };
41
+ export {
42
+ r as createTransformer,
43
+ u as transformValue,
44
+ h as transformers
45
+ };
@@ -0,0 +1,2 @@
1
+ export * from '../core/behavior/behaviors/watch-field'
2
+ export {}
@@ -0,0 +1,21 @@
1
+ import { effect as c } from "@preact/signals-core";
2
+ import { b as d } from "../registry-helpers-Bv_BJ1s-.js";
3
+ import { r as i } from "../safe-effect-Dh8uw81c.js";
4
+ function g(n, r, u) {
5
+ const { debounce: a, immediate: f = !1 } = u || {}, s = (l, o, m) => {
6
+ const e = l.getFieldByPath(n.__path);
7
+ return e ? (f && i(() => {
8
+ const t = e.value.value;
9
+ r(t, o);
10
+ }), c(() => {
11
+ const t = e.value.value;
12
+ m(() => {
13
+ i(() => r(t, o));
14
+ });
15
+ })) : null;
16
+ };
17
+ d().register(s, { debounce: a });
18
+ }
19
+ export {
20
+ g as watchField
21
+ };
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Re-export behaviors from the main index to ensure single module instance.
3
+ * This prevents static registry isolation issues when consuming the library.
4
+ */
5
+ export { behaviors as default } from './index';
6
+ export * from './core/behavior';
@@ -0,0 +1,29 @@
1
+ import { a as o, b as a, i as t, t as m } from "./index-D25LsbRm.js";
2
+ import { a as s, B as f } from "./registry-helpers-Bv_BJ1s-.js";
3
+ import { copyFrom as n } from "./behaviors/copy-from.js";
4
+ import { disableWhen as h, enableWhen as i } from "./behaviors/enable-when.js";
5
+ import { computeFrom as c } from "./behaviors/compute-from.js";
6
+ import { watchField as F } from "./behaviors/watch-field.js";
7
+ import { revalidateWhen as v } from "./behaviors/revalidate-when.js";
8
+ import { syncFields as b } from "./behaviors/sync-fields.js";
9
+ import { resetWhen as g } from "./behaviors/reset-when.js";
10
+ import { createTransformer as C, transformValue as I, transformers as P } from "./behaviors/transform-value.js";
11
+ export {
12
+ s as BehaviorContextImpl,
13
+ f as BehaviorRegistry,
14
+ o as apply,
15
+ a as applyWhen,
16
+ c as computeFrom,
17
+ n as copyFrom,
18
+ C as createTransformer,
19
+ t as default,
20
+ h as disableWhen,
21
+ i as enableWhen,
22
+ g as resetWhen,
23
+ v as revalidateWhen,
24
+ b as syncFields,
25
+ m as toBehaviorFieldPath,
26
+ I as transformValue,
27
+ P as transformers,
28
+ F as watchField
29
+ };
@@ -0,0 +1,47 @@
1
+ import { GroupNode } from '../nodes/group-node';
2
+ import { FormProxy } from '../types/form-proxy';
3
+ import { FormContext } from '../types/form-context';
4
+ import { FieldPathNode } from '../types/field-path';
5
+ /**
6
+ * Реализация {@link FormContext} для behaviors. Создаётся фреймворком и передаётся
7
+ * в callback'и behaviors (`watchField`, `computeFrom`, …) — напрямую инстанцировать
8
+ * не нужно.
9
+ *
10
+ * @example
11
+ * ```typescript
12
+ * import { watchField } from '@reformer/core/behaviors/watch-field';
13
+ *
14
+ * watchField(path.country, (value, ctx) => {
15
+ * // ctx — экземпляр BehaviorContextImpl
16
+ * ctx.setFieldValue(path.city, '');
17
+ * });
18
+ * ```
19
+ */
20
+ export declare class BehaviorContextImpl<TForm> implements FormContext<TForm> {
21
+ /**
22
+ * Форма с типизированным Proxy-доступом к полям
23
+ */
24
+ readonly form: FormProxy<TForm>;
25
+ private _form;
26
+ constructor(form: GroupNode<TForm>);
27
+ /**
28
+ * Безопасно установить значение поля по строковому пути или FieldPath
29
+ *
30
+ * Автоматически использует emitEvent: false для предотвращения циклов
31
+ *
32
+ * @param path - Строковый путь к полю или FieldPath объект
33
+ * @param value - Новое значение
34
+ */
35
+ setFieldValue(path: string | FieldPathNode<TForm, unknown>, value: unknown): void;
36
+ /**
37
+ * Получить поле формы по строковому пути
38
+ *
39
+ * Используется для динамического доступа к вложенным полям, например:
40
+ * - `ctx.getFieldByPath('address.city')` -> FieldNode
41
+ * - `ctx.getFieldByPath(path.city.__path)` -> FieldNode (для nested behaviors)
42
+ *
43
+ * @param path - Строковый путь к полю (например "address.city")
44
+ * @returns FieldNode или undefined если поле не найдено
45
+ */
46
+ getFieldByPath(path: string): import('../..').FormNode<import('../types').FormValue> | undefined;
47
+ }
@@ -0,0 +1,85 @@
1
+ import { GroupNode } from '../nodes/group-node';
2
+ import { BehaviorHandlerFn, BehaviorOptions } from './types';
3
+ import { AbstractRegistry } from '../utils/abstract-registry';
4
+ import { FormFields } from '../types';
5
+ /**
6
+ * Зарегистрированный behavior с опциями
7
+ */
8
+ export interface RegisteredBehavior {
9
+ /** Handler функция behavior */
10
+ handler: BehaviorHandlerFn<FormFields>;
11
+ /** Debounce в миллисекундах */
12
+ debounce?: number;
13
+ }
14
+ /**
15
+ * Реестр behaviors для формы
16
+ *
17
+ * Каждый экземпляр GroupNode создает собственный реестр (композиция).
18
+ * Устраняет race conditions и изолирует формы друг от друга.
19
+ *
20
+ * Наследует AbstractRegistry для унификации:
21
+ * - Управления global stack
22
+ * - Template methods begin/end registration
23
+ *
24
+ * @example
25
+ * ```typescript
26
+ * class GroupNode {
27
+ * private readonly behaviorRegistry = new BehaviorRegistry();
28
+ *
29
+ * applyBehaviorSchema(schemaFn) {
30
+ * this.behaviorRegistry.beginRegistration(); // Pushes this to stack
31
+ * schemaFn(createBehaviorFieldPath(this)); // Uses getCurrent()
32
+ * return this.behaviorRegistry.endRegistration(this); // Pops from stack
33
+ * }
34
+ * }
35
+ * ```
36
+ */
37
+ export declare class BehaviorRegistry extends AbstractRegistry<RegisteredBehavior> {
38
+ /**
39
+ * Получить текущий активный реестр из context stack
40
+ *
41
+ * @returns Текущий активный реестр или null
42
+ *
43
+ * @example
44
+ * ```typescript
45
+ * // В schema-behaviors.ts
46
+ * export function copyFrom(...) {
47
+ * const registry = BehaviorRegistry.getCurrent();
48
+ * if (registry) {
49
+ * registry.register({ ... });
50
+ * }
51
+ * }
52
+ * ```
53
+ */
54
+ static getCurrent(): BehaviorRegistry | null;
55
+ /**
56
+ * Зарегистрировать behavior handler
57
+ * Вызывается функциями из schema-behaviors.ts
58
+ *
59
+ * @param handler - BehaviorHandlerFn функция
60
+ * @param options - Опции behavior (debounce)
61
+ *
62
+ * @example
63
+ * ```typescript
64
+ * const handler = createCopyBehavior(target, source, { when: ... });
65
+ * registry.register(handler, { debounce: 300 });
66
+ * ```
67
+ */
68
+ register<T extends FormFields>(handler: BehaviorHandlerFn<T>, options?: BehaviorOptions): void;
69
+ /**
70
+ * Завершить регистрацию и применить behaviors к форме
71
+ * Создает effect подписки для всех зарегистрированных behaviors
72
+ *
73
+ * @param form - GroupNode формы
74
+ * @returns Количество зарегистрированных behaviors и функция cleanup
75
+ */
76
+ endRegistration<T extends FormFields>(form: GroupNode<T>): {
77
+ count: number;
78
+ cleanup: () => void;
79
+ };
80
+ /**
81
+ * Создать effect подписку для behavior
82
+ * @private
83
+ */
84
+ private createEffect;
85
+ }