@reformer/core 2.0.0-beta.7 → 2.0.0-beta.9

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/dist/behaviors/compute-from.d.ts +2 -0
  2. package/dist/behaviors/compute-from.js +31 -0
  3. package/dist/behaviors/copy-from.d.ts +2 -0
  4. package/dist/behaviors/copy-from.js +29 -0
  5. package/dist/behaviors/enable-when.d.ts +2 -0
  6. package/dist/behaviors/enable-when.js +25 -0
  7. package/dist/behaviors/reset-when.d.ts +2 -0
  8. package/dist/behaviors/reset-when.js +24 -0
  9. package/dist/behaviors/revalidate-when.d.ts +2 -0
  10. package/dist/behaviors/revalidate-when.js +18 -0
  11. package/dist/behaviors/sync-fields.d.ts +2 -0
  12. package/dist/behaviors/sync-fields.js +41 -0
  13. package/dist/behaviors/transform-value.d.ts +2 -0
  14. package/dist/behaviors/transform-value.js +45 -0
  15. package/dist/behaviors/watch-field.d.ts +2 -0
  16. package/dist/behaviors/watch-field.js +21 -0
  17. package/dist/behaviors.js +26 -19
  18. package/dist/core/behavior/behavior-context.d.ts +26 -12
  19. package/dist/core/behavior/behavior-registry.d.ts +15 -27
  20. package/dist/core/behavior/behaviors/compute-from.d.ts +50 -21
  21. package/dist/core/behavior/behaviors/copy-from.d.ts +39 -14
  22. package/dist/core/behavior/behaviors/enable-when.d.ts +88 -19
  23. package/dist/core/behavior/behaviors/reset-when.d.ts +31 -18
  24. package/dist/core/behavior/behaviors/revalidate-when.d.ts +40 -17
  25. package/dist/core/behavior/behaviors/sync-fields.d.ts +34 -14
  26. package/dist/core/behavior/behaviors/transform-value.d.ts +116 -44
  27. package/dist/core/behavior/behaviors/watch-field.d.ts +66 -21
  28. package/dist/core/behavior/compose-behavior.d.ts +2 -12
  29. package/dist/core/behavior/index.d.ts +0 -1
  30. package/dist/core/behavior/types.d.ts +2 -8
  31. package/dist/core/factories/node-factory.d.ts +6 -29
  32. package/dist/core/nodes/array-node.d.ts +11 -15
  33. package/dist/core/nodes/field-node.d.ts +43 -24
  34. package/dist/core/nodes/form-node.d.ts +18 -20
  35. package/dist/core/nodes/group-node.d.ts +25 -21
  36. package/dist/core/types/deep-schema.d.ts +2 -12
  37. package/dist/core/types/field-path.d.ts +1 -1
  38. package/dist/core/types/form-context.d.ts +26 -26
  39. package/dist/core/types/form-proxy.d.ts +1 -31
  40. package/dist/core/types/index.d.ts +16 -4
  41. package/dist/core/types/validation-schema.d.ts +3 -12
  42. package/dist/core/utils/abstract-registry.d.ts +74 -0
  43. package/dist/core/utils/aggregate-signals.d.ts +71 -0
  44. package/dist/core/utils/create-form.d.ts +1 -20
  45. package/dist/core/utils/error-handler.d.ts +1 -18
  46. package/dist/core/utils/field-path-navigator.d.ts +1 -1
  47. package/dist/core/utils/field-path.d.ts +23 -11
  48. package/dist/core/utils/form-observer.d.ts +176 -0
  49. package/dist/core/utils/form-proxy-builder.d.ts +25 -0
  50. package/dist/core/utils/form-submitter.d.ts +121 -0
  51. package/dist/core/utils/index.d.ts +8 -2
  52. package/dist/core/utils/registry-helpers.d.ts +0 -7
  53. package/dist/core/utils/safe-effect.d.ts +73 -0
  54. package/dist/core/utils/status-machine.d.ts +153 -0
  55. package/dist/core/utils/type-guards.d.ts +5 -23
  56. package/dist/core/utils/unique-id.d.ts +34 -7
  57. package/dist/core/validation/core/apply-when.d.ts +3 -9
  58. package/dist/core/validation/core/apply.d.ts +2 -13
  59. package/dist/core/validation/core/validate-async.d.ts +2 -8
  60. package/dist/core/validation/core/validate-tree.d.ts +0 -6
  61. package/dist/core/validation/core/validate.d.ts +1 -7
  62. package/dist/core/validation/index.d.ts +8 -2
  63. package/dist/core/validation/validate-form.d.ts +1 -38
  64. package/dist/core/validation/validation-applicator.d.ts +2 -21
  65. package/dist/core/validation/validation-context.d.ts +38 -14
  66. package/dist/core/validation/validation-registry.d.ts +11 -20
  67. package/dist/core/validation/validators/array-validators.d.ts +2 -12
  68. package/dist/core/validation/validators/date-utils.d.ts +26 -0
  69. package/dist/core/validation/validators/email.d.ts +2 -9
  70. package/dist/core/validation/validators/future-date.d.ts +35 -0
  71. package/dist/core/validation/validators/index.d.ts +7 -1
  72. package/dist/core/validation/validators/is-date.d.ts +36 -0
  73. package/dist/core/validation/validators/max-age.d.ts +36 -0
  74. package/dist/core/validation/validators/max-date.d.ts +36 -0
  75. package/dist/core/validation/validators/max-length.d.ts +3 -10
  76. package/dist/core/validation/validators/max.d.ts +3 -10
  77. package/dist/core/validation/validators/min-age.d.ts +36 -0
  78. package/dist/core/validation/validators/min-date.d.ts +36 -0
  79. package/dist/core/validation/validators/min-length.d.ts +3 -10
  80. package/dist/core/validation/validators/min.d.ts +3 -10
  81. package/dist/core/validation/validators/number.d.ts +2 -9
  82. package/dist/core/validation/validators/past-date.d.ts +35 -0
  83. package/dist/core/validation/validators/pattern.d.ts +2 -9
  84. package/dist/core/validation/validators/phone.d.ts +2 -9
  85. package/dist/core/validation/validators/required.d.ts +2 -9
  86. package/dist/core/validation/validators/url.d.ts +2 -9
  87. package/dist/date-utils-xUWFslTj.js +29 -0
  88. package/dist/field-path-DuKdGcIE.js +66 -0
  89. package/dist/hooks/types.d.ts +1 -1
  90. package/dist/hooks/useArrayLength.d.ts +31 -0
  91. package/dist/hooks/useFormControl.d.ts +4 -4
  92. package/dist/hooks/useFormControlValue.d.ts +2 -2
  93. package/dist/hooks/useHiddenCondition.d.ts +25 -0
  94. package/dist/hooks/useSignalSubscription.d.ts +1 -1
  95. package/dist/index-D25LsbRm.js +73 -0
  96. package/dist/index.d.ts +2 -0
  97. package/dist/index.js +1031 -714
  98. package/dist/registry-helpers-Bv_BJ1s-.js +615 -0
  99. package/dist/safe-effect-Dh8uw81c.js +20 -0
  100. package/dist/validate-C3XiA_zf.js +10 -0
  101. package/dist/validators/email.d.ts +2 -0
  102. package/dist/validators/email.js +13 -0
  103. package/dist/validators/future-date.d.ts +2 -0
  104. package/dist/validators/future-date.js +20 -0
  105. package/dist/validators/is-date.d.ts +2 -0
  106. package/dist/validators/is-date.js +12 -0
  107. package/dist/validators/max-age.d.ts +2 -0
  108. package/dist/validators/max-age.js +20 -0
  109. package/dist/validators/max-date.d.ts +2 -0
  110. package/dist/validators/max-date.js +20 -0
  111. package/dist/validators/max-length.d.ts +2 -0
  112. package/dist/validators/max-length.js +11 -0
  113. package/dist/validators/max.d.ts +2 -0
  114. package/dist/validators/max.js +11 -0
  115. package/dist/validators/min-age.d.ts +2 -0
  116. package/dist/validators/min-age.js +20 -0
  117. package/dist/validators/min-date.d.ts +2 -0
  118. package/dist/validators/min-date.js +20 -0
  119. package/dist/validators/min-length.d.ts +2 -0
  120. package/dist/validators/min-length.js +11 -0
  121. package/dist/validators/min.d.ts +2 -0
  122. package/dist/validators/min.js +11 -0
  123. package/dist/validators/number.d.ts +2 -0
  124. package/dist/validators/number.js +35 -0
  125. package/dist/validators/past-date.d.ts +2 -0
  126. package/dist/validators/past-date.js +20 -0
  127. package/dist/validators/pattern.d.ts +2 -0
  128. package/dist/validators/pattern.js +11 -0
  129. package/dist/validators/phone.d.ts +2 -0
  130. package/dist/validators/phone.js +35 -0
  131. package/dist/validators/required.d.ts +2 -0
  132. package/dist/validators/required.js +15 -0
  133. package/dist/validators/url.d.ts +2 -0
  134. package/dist/validators/url.js +19 -0
  135. package/dist/validators-BGsNOgT1.js +207 -0
  136. package/dist/validators.js +54 -29
  137. package/llms.txt +7878 -311
  138. package/package.json +83 -9
  139. package/dist/behaviors-DyPzh2-X.js +0 -508
  140. package/dist/core/behavior/create-field-path.d.ts +0 -7
  141. package/dist/core/context/form-context-impl.d.ts +0 -29
  142. package/dist/core/utils/debounce.d.ts +0 -160
  143. package/dist/core/utils/resources.d.ts +0 -41
  144. package/dist/core/validation/field-path.d.ts +0 -7
  145. package/dist/core/validation/validators/date.d.ts +0 -38
  146. package/dist/registry-helpers--8-OogF8.js +0 -477
  147. package/dist/validators-CWdzevnC.js +0 -397
@@ -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
+ };
package/dist/behaviors.js CHANGED
@@ -1,22 +1,29 @@
1
- import { a as s, b as r, g as t, c as o, m as l, i as h, f as n, e as i, k as m, j as p, s as c, t as d, l as f, n as F, h as y } from "./behaviors-DyPzh2-X.js";
2
- import { d as v, B, c as b } from "./registry-helpers--8-OogF8.js";
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";
3
11
  export {
4
- v as BehaviorContextImpl,
5
- B as BehaviorRegistry,
6
- s as apply,
7
- r as applyWhen,
8
- t as computeFrom,
9
- o as copyFrom,
10
- b as createFieldPath,
11
- l as createTransformer,
12
- h as default,
13
- n as disableWhen,
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,
14
21
  i as enableWhen,
15
- m as resetWhen,
16
- p as revalidateWhen,
17
- c as syncFields,
18
- d as toBehaviorFieldPath,
19
- f as transformValue,
20
- F as transformers,
21
- y as watchField
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
22
29
  };
@@ -1,18 +1,21 @@
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';
1
5
  /**
2
- * BehaviorContext - контекст для behavior callback функций
6
+ * Реализация {@link FormContext} для behaviors. Создаётся фреймворком и передаётся
7
+ * в callback'и behaviors (`watchField`, `computeFrom`, …) — напрямую инстанцировать
8
+ * не нужно.
3
9
  *
4
- * Реализует FormContext для behavior схем
5
- */
6
- import type { GroupNode } from '../nodes/group-node';
7
- import type { FormProxy } from '../types/form-proxy';
8
- import type { FormContext } from '../types/form-context';
9
- import type { FieldPathNode } from '../types/field-path';
10
- /**
11
- * Реализация BehaviorContext (FormContext)
10
+ * @example
11
+ * ```typescript
12
+ * import { watchField } from '@reformer/core/behaviors/watch-field';
12
13
  *
13
- * Предоставляет:
14
- * - `form` - прямой типизированный доступ к форме
15
- * - `setFieldValue` - безопасная установка значения (emitEvent: false)
14
+ * watchField(path.country, (value, ctx) => {
15
+ * // ctx экземпляр BehaviorContextImpl
16
+ * ctx.setFieldValue(path.city, '');
17
+ * });
18
+ * ```
16
19
  */
17
20
  export declare class BehaviorContextImpl<TForm> implements FormContext<TForm> {
18
21
  /**
@@ -30,4 +33,15 @@ export declare class BehaviorContextImpl<TForm> implements FormContext<TForm> {
30
33
  * @param value - Новое значение
31
34
  */
32
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;
33
47
  }
@@ -1,21 +1,25 @@
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';
1
5
  /**
2
- * BehaviorRegistry - регистрация и управление behavior схемами
3
- *
4
- * Аналогично ValidationRegistry, но для реактивного поведения форм
6
+ * Зарегистрированный behavior с опциями
5
7
  */
6
- import type { GroupNode } from '../nodes/group-node';
7
- import type { BehaviorHandlerFn, BehaviorOptions } from './types';
8
- import { FormFields } from '../types';
8
+ export interface RegisteredBehavior {
9
+ /** Handler функция behavior */
10
+ handler: BehaviorHandlerFn<FormFields>;
11
+ /** Debounce в миллисекундах */
12
+ debounce?: number;
13
+ }
9
14
  /**
10
15
  * Реестр behaviors для формы
11
16
  *
12
17
  * Каждый экземпляр GroupNode создает собственный реестр (композиция).
13
18
  * Устраняет race conditions и изолирует формы друг от друга.
14
19
  *
15
- * Context stack используется для tracking текущего активного реестра:
16
- * - beginRegistration() помещает this в stack
17
- * - endRegistration() извлекает из stack
18
- * - getCurrent() возвращает текущий активный реестр
20
+ * Наследует AbstractRegistry для унификации:
21
+ * - Управления global stack
22
+ * - Template methods begin/end registration
19
23
  *
20
24
  * @example
21
25
  * ```typescript
@@ -30,14 +34,7 @@ import { FormFields } from '../types';
30
34
  * }
31
35
  * ```
32
36
  */
33
- export declare class BehaviorRegistry {
34
- /**
35
- * Stack активных контекстов регистрации
36
- * Используется для изоляции форм друг от друга
37
- */
38
- private static contextStack;
39
- private registrations;
40
- private isRegistering;
37
+ export declare class BehaviorRegistry extends AbstractRegistry<RegisteredBehavior> {
41
38
  /**
42
39
  * Получить текущий активный реестр из context stack
43
40
  *
@@ -55,13 +52,6 @@ export declare class BehaviorRegistry {
55
52
  * ```
56
53
  */
57
54
  static getCurrent(): BehaviorRegistry | null;
58
- /**
59
- * Начать регистрацию behaviors
60
- * Вызывается перед применением схемы
61
- *
62
- * Помещает this в context stack для изоляции форм
63
- */
64
- beginRegistration(): void;
65
55
  /**
66
56
  * Зарегистрировать behavior handler
67
57
  * Вызывается функциями из schema-behaviors.ts
@@ -80,8 +70,6 @@ export declare class BehaviorRegistry {
80
70
  * Завершить регистрацию и применить behaviors к форме
81
71
  * Создает effect подписки для всех зарегистрированных behaviors
82
72
  *
83
- * Извлекает this из context stack
84
- *
85
73
  * @param form - GroupNode формы
86
74
  * @returns Количество зарегистрированных behaviors и функция cleanup
87
75
  */
@@ -1,12 +1,5 @@
1
- /**
2
- * Вычисляемые поля
3
- *
4
- * @group Behaviors
5
- * @category Behavior Rules
6
- * @module behaviors/computeFrom
7
- */
8
- import type { FieldPathNode } from '../../types';
9
- import type { ComputeFromOptions } from '../types';
1
+ import { FieldPathNode } from '../../types';
2
+ import { ComputeFromOptions } from '../types';
10
3
  /**
11
4
  * Автоматически вычисляет значение поля на основе других полей
12
5
  *
@@ -16,26 +9,62 @@ import type { ComputeFromOptions } from '../types';
16
9
  * @param sources - Массив полей-зависимостей
17
10
  * @param target - Поле для записи результата
18
11
  * @param computeFn - Функция вычисления (принимает объект с именами полей)
19
- * @param options - Опции
12
+ * @param options - Опции (`debounce`, `condition`, `trigger`)
20
13
  *
21
- * @example
14
+ * @example Многополевой расчёт — total = price × quantity
22
15
  * ```typescript
23
- * const schema: BehaviorSchemaFn<MyForm> = (path) => {
24
- * // Автоматический расчет минимального взноса
25
- * computeFrom(
26
- * [path.propertyValue],
27
- * path.initialPayment,
28
- * (values) => values.propertyValue ? values.propertyValue * 0.2 : null,
29
- * { debounce: 300 }
30
- * );
16
+ * import { computeFrom, type BehaviorSchemaFn } from '@reformer/core/behaviors';
31
17
  *
32
- * // Общая стоимость = цена * количество
18
+ * interface OrderForm {
19
+ * price: number;
20
+ * quantity: number;
21
+ * total: number;
22
+ * }
23
+ *
24
+ * export const orderBehavior: BehaviorSchemaFn<OrderForm> = (path) => {
33
25
  * computeFrom(
34
26
  * [path.price, path.quantity],
35
27
  * path.total,
36
- * (values) => values.price * values.quantity
28
+ * (values) =>
29
+ * (typeof values.price === 'number' ? values.price : 0) *
30
+ * (typeof values.quantity === 'number' ? values.quantity : 0),
31
+ * );
32
+ * };
33
+ * ```
34
+ *
35
+ * @example Edge case — async-like дорогие вычисления с `debounce` и условием
36
+ * ```typescript
37
+ * import { computeFrom, type BehaviorSchemaFn } from '@reformer/core/behaviors';
38
+ *
39
+ * interface MortgageForm {
40
+ * loanType: 'mortgage' | 'consumer';
41
+ * loanAmount: number;
42
+ * loanTerm: number;
43
+ * interestRate: number;
44
+ * monthlyPayment: number;
45
+ * }
46
+ *
47
+ * function annuity(values: MortgageForm): number {
48
+ * const { loanAmount, loanTerm, interestRate } = values;
49
+ * if (!loanAmount || !loanTerm || !interestRate) return 0;
50
+ * const r = interestRate / 100 / 12;
51
+ * const n = loanTerm;
52
+ * return Math.round((loanAmount * r * Math.pow(1 + r, n)) / (Math.pow(1 + r, n) - 1));
53
+ * }
54
+ *
55
+ * export const mortgageBehavior: BehaviorSchemaFn<MortgageForm> = (path) => {
56
+ * computeFrom(
57
+ * [path.loanAmount, path.loanTerm, path.interestRate],
58
+ * path.monthlyPayment,
59
+ * annuity,
60
+ * {
61
+ * debounce: 300, // не пересчитываем на каждый keystroke
62
+ * condition: (form) => form.loanType === 'mortgage', // считаем только для ипотеки
63
+ * },
37
64
  * );
38
65
  * };
39
66
  * ```
67
+ *
68
+ * @see [docs/llms/20-compute-vs-watch.md](../../../../docs/llms/20-compute-vs-watch.md)
40
69
  */
41
70
  export declare function computeFrom<TForm, TTarget>(sources: FieldPathNode<TForm, any>[], target: FieldPathNode<TForm, TTarget>, computeFn: (values: TForm) => TTarget, options?: ComputeFromOptions<TForm>): void;
@@ -1,12 +1,5 @@
1
- /**
2
- * Копирование значений между полями
3
- *
4
- * @group Behaviors
5
- * @category Behavior Rules
6
- * @module behaviors/copyFrom
7
- */
8
- import type { FieldPathNode } from '../../types';
9
- import type { CopyFromOptions } from '../types';
1
+ import { FieldPathNode } from '../../types';
2
+ import { CopyFromOptions } from '../types';
10
3
  /**
11
4
  * Копирует значения из одного поля/группы в другое при выполнении условия
12
5
  *
@@ -15,17 +8,49 @@ import type { CopyFromOptions } from '../types';
15
8
  *
16
9
  * @param source - Откуда копировать
17
10
  * @param target - Куда копировать
18
- * @param options - Опции копирования
11
+ * @param options - Опции копирования (`when`, `fields`, `transform`, `debounce`)
19
12
  *
20
- * @example
13
+ * @example Скаляр → скаляр с условием
21
14
  * ```typescript
22
- * const schema: BehaviorSchemaFn<MyForm> = (path) => {
23
- * // Копировать адрес регистрации в адрес проживания
15
+ * import { copyFrom, type BehaviorSchemaFn } from '@reformer/core/behaviors';
16
+ *
17
+ * interface ContactForm {
18
+ * sameEmail: boolean;
19
+ * email: string;
20
+ * emailAdditional: string;
21
+ * }
22
+ *
23
+ * export const contactBehavior: BehaviorSchemaFn<ContactForm> = (path) => {
24
+ * copyFrom(path.email, path.emailAdditional, {
25
+ * when: (form) => form.sameEmail === true,
26
+ * });
27
+ * };
28
+ * ```
29
+ *
30
+ * @example Копирование группы с подмножеством полей и `transform`
31
+ * ```typescript
32
+ * import { copyFrom, type BehaviorSchemaFn } from '@reformer/core/behaviors';
33
+ *
34
+ * interface Address { country: string; region: string; city: string; street: string }
35
+ * interface ProfileForm {
36
+ * sameAsRegistration: boolean;
37
+ * registrationAddress: Address;
38
+ * residenceAddress: Address;
39
+ * }
40
+ *
41
+ * export const profileBehavior: BehaviorSchemaFn<ProfileForm> = (path) => {
24
42
  * copyFrom(path.registrationAddress, path.residenceAddress, {
25
43
  * when: (form) => form.sameAsRegistration === true,
26
- * fields: 'all'
44
+ * fields: ['country', 'region', 'city'], // street НЕ копируем
45
+ * transform: (addr) => ({
46
+ * ...addr,
47
+ * country: addr.country.toUpperCase(), // нормализация при копировании
48
+ * }),
49
+ * debounce: 200,
27
50
  * });
28
51
  * };
29
52
  * ```
53
+ *
54
+ * @see [docs/llms/23-copy-from.md](../../../../docs/llms/23-copy-from.md)
30
55
  */
31
56
  export declare function copyFrom<TForm, TSource, TTarget>(source: FieldPathNode<TForm, TSource>, target: FieldPathNode<TForm, TTarget>, options?: CopyFromOptions<TSource, TForm>): void;