@reformer/core 2.0.0-beta.6 → 2.0.0-beta.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/behaviors/compute-from.d.ts +2 -0
- package/dist/behaviors/compute-from.js +31 -0
- package/dist/behaviors/copy-from.d.ts +2 -0
- package/dist/behaviors/copy-from.js +29 -0
- package/dist/behaviors/enable-when.d.ts +2 -0
- package/dist/behaviors/enable-when.js +25 -0
- package/dist/behaviors/reset-when.d.ts +2 -0
- package/dist/behaviors/reset-when.js +24 -0
- package/dist/behaviors/revalidate-when.d.ts +2 -0
- package/dist/behaviors/revalidate-when.js +18 -0
- package/dist/behaviors/sync-fields.d.ts +2 -0
- package/dist/behaviors/sync-fields.js +41 -0
- package/dist/behaviors/transform-value.d.ts +2 -0
- package/dist/behaviors/transform-value.js +45 -0
- package/dist/behaviors/watch-field.d.ts +2 -0
- package/dist/behaviors/watch-field.js +21 -0
- package/dist/behaviors.js +26 -19
- package/dist/core/behavior/behavior-context.d.ts +26 -12
- package/dist/core/behavior/behavior-registry.d.ts +15 -27
- package/dist/core/behavior/behaviors/compute-from.d.ts +50 -21
- package/dist/core/behavior/behaviors/copy-from.d.ts +39 -14
- package/dist/core/behavior/behaviors/enable-when.d.ts +88 -19
- package/dist/core/behavior/behaviors/reset-when.d.ts +31 -18
- package/dist/core/behavior/behaviors/revalidate-when.d.ts +40 -17
- package/dist/core/behavior/behaviors/sync-fields.d.ts +34 -14
- package/dist/core/behavior/behaviors/transform-value.d.ts +116 -44
- package/dist/core/behavior/behaviors/watch-field.d.ts +66 -21
- package/dist/core/behavior/compose-behavior.d.ts +2 -12
- package/dist/core/behavior/index.d.ts +0 -1
- package/dist/core/behavior/types.d.ts +2 -8
- package/dist/core/factories/node-factory.d.ts +6 -29
- package/dist/core/nodes/array-node.d.ts +39 -19
- package/dist/core/nodes/field-node.d.ts +43 -24
- package/dist/core/nodes/form-node.d.ts +18 -20
- package/dist/core/nodes/group-node.d.ts +25 -21
- package/dist/core/types/deep-schema.d.ts +2 -12
- package/dist/core/types/field-path.d.ts +1 -1
- package/dist/core/types/form-context.d.ts +26 -26
- package/dist/core/types/form-proxy.d.ts +2 -32
- package/dist/core/types/index.d.ts +16 -4
- package/dist/core/types/validation-schema.d.ts +3 -12
- package/dist/core/utils/abstract-registry.d.ts +74 -0
- package/dist/core/utils/aggregate-signals.d.ts +71 -0
- package/dist/core/utils/create-form.d.ts +1 -18
- package/dist/core/utils/error-handler.d.ts +1 -18
- package/dist/core/utils/field-path-navigator.d.ts +1 -1
- package/dist/core/utils/field-path.d.ts +23 -11
- package/dist/core/utils/form-observer.d.ts +176 -0
- package/dist/core/utils/form-proxy-builder.d.ts +25 -0
- package/dist/core/utils/form-submitter.d.ts +121 -0
- package/dist/core/utils/index.d.ts +9 -2
- package/dist/core/utils/registry-helpers.d.ts +0 -7
- package/dist/core/utils/safe-effect.d.ts +73 -0
- package/dist/core/utils/status-machine.d.ts +153 -0
- package/dist/core/utils/type-guards.d.ts +5 -23
- package/dist/core/utils/unique-id.d.ts +53 -0
- package/dist/core/validation/core/apply-when.d.ts +3 -9
- package/dist/core/validation/core/apply.d.ts +2 -13
- package/dist/core/validation/core/validate-async.d.ts +2 -8
- package/dist/core/validation/core/validate-tree.d.ts +0 -6
- package/dist/core/validation/core/validate.d.ts +1 -7
- package/dist/core/validation/index.d.ts +8 -2
- package/dist/core/validation/validate-form.d.ts +1 -38
- package/dist/core/validation/validation-applicator.d.ts +2 -21
- package/dist/core/validation/validation-context.d.ts +58 -42
- package/dist/core/validation/validation-registry.d.ts +11 -25
- package/dist/core/validation/validators/array-validators.d.ts +2 -12
- package/dist/core/validation/validators/date-utils.d.ts +26 -0
- package/dist/core/validation/validators/email.d.ts +2 -9
- package/dist/core/validation/validators/future-date.d.ts +35 -0
- package/dist/core/validation/validators/index.d.ts +7 -1
- package/dist/core/validation/validators/is-date.d.ts +36 -0
- package/dist/core/validation/validators/max-age.d.ts +36 -0
- package/dist/core/validation/validators/max-date.d.ts +36 -0
- package/dist/core/validation/validators/max-length.d.ts +3 -10
- package/dist/core/validation/validators/max.d.ts +3 -10
- package/dist/core/validation/validators/min-age.d.ts +36 -0
- package/dist/core/validation/validators/min-date.d.ts +36 -0
- package/dist/core/validation/validators/min-length.d.ts +3 -10
- package/dist/core/validation/validators/min.d.ts +3 -10
- package/dist/core/validation/validators/number.d.ts +2 -9
- package/dist/core/validation/validators/past-date.d.ts +35 -0
- package/dist/core/validation/validators/pattern.d.ts +2 -9
- package/dist/core/validation/validators/phone.d.ts +2 -9
- package/dist/core/validation/validators/required.d.ts +2 -9
- package/dist/core/validation/validators/url.d.ts +2 -9
- package/dist/date-utils-xUWFslTj.js +29 -0
- package/dist/field-path-DuKdGcIE.js +66 -0
- package/dist/hooks/types.d.ts +1 -1
- package/dist/hooks/useArrayLength.d.ts +31 -0
- package/dist/hooks/useFormControl.d.ts +4 -4
- package/dist/hooks/useFormControlValue.d.ts +2 -2
- package/dist/hooks/useHiddenCondition.d.ts +25 -0
- package/dist/hooks/useSignalSubscription.d.ts +1 -1
- package/dist/index-D25LsbRm.js +73 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +1100 -740
- package/dist/registry-helpers-Bv_BJ1s-.js +615 -0
- package/dist/safe-effect-Dh8uw81c.js +20 -0
- package/dist/validate-C3XiA_zf.js +10 -0
- package/dist/validators/email.d.ts +2 -0
- package/dist/validators/email.js +13 -0
- package/dist/validators/future-date.d.ts +2 -0
- package/dist/validators/future-date.js +20 -0
- package/dist/validators/is-date.d.ts +2 -0
- package/dist/validators/is-date.js +12 -0
- package/dist/validators/max-age.d.ts +2 -0
- package/dist/validators/max-age.js +20 -0
- package/dist/validators/max-date.d.ts +2 -0
- package/dist/validators/max-date.js +20 -0
- package/dist/validators/max-length.d.ts +2 -0
- package/dist/validators/max-length.js +11 -0
- package/dist/validators/max.d.ts +2 -0
- package/dist/validators/max.js +11 -0
- package/dist/validators/min-age.d.ts +2 -0
- package/dist/validators/min-age.js +20 -0
- package/dist/validators/min-date.d.ts +2 -0
- package/dist/validators/min-date.js +20 -0
- package/dist/validators/min-length.d.ts +2 -0
- package/dist/validators/min-length.js +11 -0
- package/dist/validators/min.d.ts +2 -0
- package/dist/validators/min.js +11 -0
- package/dist/validators/number.d.ts +2 -0
- package/dist/validators/number.js +35 -0
- package/dist/validators/past-date.d.ts +2 -0
- package/dist/validators/past-date.js +20 -0
- package/dist/validators/pattern.d.ts +2 -0
- package/dist/validators/pattern.js +11 -0
- package/dist/validators/phone.d.ts +2 -0
- package/dist/validators/phone.js +35 -0
- package/dist/validators/required.d.ts +2 -0
- package/dist/validators/required.js +15 -0
- package/dist/validators/url.d.ts +2 -0
- package/dist/validators/url.js +19 -0
- package/dist/validators-BGsNOgT1.js +207 -0
- package/dist/validators.js +54 -29
- package/llms.txt +7878 -311
- package/package.json +83 -9
- package/dist/behaviors-2HSqHPb4.js +0 -508
- package/dist/core/behavior/create-field-path.d.ts +0 -7
- package/dist/core/context/form-context-impl.d.ts +0 -29
- package/dist/core/utils/debounce.d.ts +0 -160
- package/dist/core/utils/resources.d.ts +0 -41
- package/dist/core/validation/field-path.d.ts +0 -7
- package/dist/core/validation/validators/date.d.ts +0 -38
- package/dist/registry-helpers-BRxAr6nG.js +0 -490
- package/dist/validators-gXoHPdqM.js +0 -418
|
@@ -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,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,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,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,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,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,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,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
|
|
2
|
-
import {
|
|
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
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
h as
|
|
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
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
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
|
-
*
|
|
6
|
+
* Реализация {@link FormContext} для behaviors. Создаётся фреймворком и передаётся
|
|
7
|
+
* в callback'и behaviors (`watchField`, `computeFrom`, …) — напрямую инстанцировать
|
|
8
|
+
* не нужно.
|
|
3
9
|
*
|
|
4
|
-
*
|
|
5
|
-
|
|
6
|
-
import
|
|
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
|
-
*
|
|
15
|
-
*
|
|
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
|
-
*
|
|
3
|
-
*
|
|
4
|
-
* Аналогично ValidationRegistry, но для реактивного поведения форм
|
|
6
|
+
* Зарегистрированный behavior с опциями
|
|
5
7
|
*/
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
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
|
-
*
|
|
16
|
-
* -
|
|
17
|
-
* -
|
|
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
|
-
*
|
|
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) =>
|
|
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
|
-
*
|
|
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: '
|
|
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;
|