@reformer/core 11.0.0-beta.2 → 11.0.0-beta.4

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 (115) hide show
  1. package/dist/behaviors.d.ts +1 -1
  2. package/dist/behaviors.js +37 -37
  3. package/dist/create-model-Dxh9cfLp.js +97 -0
  4. package/dist/form/behaviors/collections.d.ts +50 -0
  5. package/dist/form/behaviors/context.d.ts +23 -0
  6. package/dist/form/behaviors/index.d.ts +28 -0
  7. package/dist/form/behaviors/internals.d.ts +26 -0
  8. package/dist/form/{behaviors-node.d.ts → behaviors/node.d.ts} +3 -3
  9. package/dist/form/behaviors/operators.d.ts +51 -0
  10. package/dist/form/behaviors/types.d.ts +17 -0
  11. package/dist/form/create-core-form.d.ts +70 -0
  12. package/dist/form/create-form.d.ts +1 -1
  13. package/dist/form/index.d.ts +12 -12
  14. package/dist/form/nodes/model-array-node.d.ts +1 -1
  15. package/dist/form/types/contracts.d.ts +9 -6
  16. package/dist/form/types/validation-schema.d.ts +1 -1
  17. package/dist/form/validation/config.d.ts +73 -0
  18. package/dist/form/validation/context.d.ts +27 -0
  19. package/dist/form/{error-handler.d.ts → validation/error-handler.d.ts} +1 -1
  20. package/dist/form/validation/index.d.ts +23 -28
  21. package/dist/form/validation/operators.d.ts +42 -0
  22. package/dist/form/validation/run.d.ts +45 -0
  23. package/dist/form/{validation-strategy.d.ts → validation/strategy.d.ts} +10 -4
  24. package/dist/form/validation/types.d.ts +28 -0
  25. package/dist/form/{validation/validators → validators}/date-utils.d.ts +1 -1
  26. package/dist/form/{validation/validators → validators}/email.d.ts +1 -1
  27. package/dist/form/{validation/validators → validators}/file-type.d.ts +1 -1
  28. package/dist/form/{validation/validators → validators}/file-utils.d.ts +1 -1
  29. package/dist/form/{validation/validators → validators}/future-date.d.ts +1 -1
  30. package/dist/form/{validation/validators → validators}/index.d.ts +6 -4
  31. package/dist/form/{validation/validators → validators}/integer.d.ts +1 -1
  32. package/dist/form/{validation/validators → validators}/is-date.d.ts +1 -1
  33. package/dist/form/{validation/validators → validators}/is-number.d.ts +1 -1
  34. package/dist/form/{validation/validators → validators}/max-age.d.ts +1 -1
  35. package/dist/form/{validation/validators → validators}/max-date.d.ts +1 -1
  36. package/dist/form/{validation/validators → validators}/max-file-size.d.ts +1 -1
  37. package/dist/form/{validation/validators → validators}/max-files.d.ts +1 -1
  38. package/dist/form/{validation/validators → validators}/max-length.d.ts +1 -1
  39. package/dist/form/{validation/validators → validators}/max-total-file-size.d.ts +1 -1
  40. package/dist/form/{validation/validators → validators}/max.d.ts +1 -1
  41. package/dist/form/{validation/validators → validators}/min-age.d.ts +1 -1
  42. package/dist/form/{validation/validators → validators}/min-date.d.ts +1 -1
  43. package/dist/form/{validation/validators → validators}/min-file-size.d.ts +1 -1
  44. package/dist/form/{validation/validators → validators}/min-files.d.ts +1 -1
  45. package/dist/form/{validation/validators → validators}/min-length.d.ts +1 -1
  46. package/dist/form/{validation/validators → validators}/min.d.ts +1 -1
  47. package/dist/form/{validation/validators → validators}/multiple-of.d.ts +1 -1
  48. package/dist/form/{validation/validators → validators}/non-negative.d.ts +1 -1
  49. package/dist/form/{validation/validators → validators}/non-zero.d.ts +1 -1
  50. package/dist/form/{validation/validators → validators}/past-date.d.ts +1 -1
  51. package/dist/form/{validation/validators → validators}/pattern.d.ts +1 -1
  52. package/dist/form/{validation/validators → validators}/phone.d.ts +1 -1
  53. package/dist/form/{validation/validators → validators}/required.d.ts +1 -1
  54. package/dist/form/{validation/validators → validators}/url.d.ts +1 -1
  55. package/dist/index.d.ts +7 -4
  56. package/dist/index.js +708 -479
  57. package/dist/{state/form-model.d.ts → model/create-model.d.ts} +0 -14
  58. package/dist/{state → model}/index.d.ts +10 -11
  59. package/dist/model/model-nodes.d.ts +60 -0
  60. package/dist/model/model-signals-proxy.d.ts +32 -0
  61. package/dist/model/model-value-proxy.d.ts +3 -0
  62. package/dist/{state → model}/safe-effect.d.ts +1 -1
  63. package/dist/model-signals-proxy-mV3WGdlO.js +233 -0
  64. package/dist/model.d.ts +2 -0
  65. package/dist/model.js +21 -0
  66. package/dist/{form → platforms/react}/hooks/types.d.ts +1 -1
  67. package/dist/platforms/react/hooks/use-form-bundle.d.ts +26 -0
  68. package/dist/{form → platforms/react}/hooks/use-form-validation.d.ts +3 -3
  69. package/dist/{form → platforms/react}/hooks/useArrayLength.d.ts +1 -1
  70. package/dist/{form → platforms/react}/hooks/useFormControl.d.ts +3 -3
  71. package/dist/{form → platforms/react}/hooks/useFormControlValue.d.ts +2 -2
  72. package/dist/platforms/react/index.d.ts +23 -0
  73. package/dist/signals.d.ts +1 -1
  74. package/dist/strategy-DA3JwxsR.js +170 -0
  75. package/dist/validation.d.ts +1 -1
  76. package/dist/validation.js +10 -165
  77. package/dist/validators/email.d.ts +1 -1
  78. package/dist/validators/future-date.d.ts +1 -1
  79. package/dist/validators/integer.d.ts +1 -1
  80. package/dist/validators/is-date.d.ts +1 -1
  81. package/dist/validators/is-number.d.ts +1 -1
  82. package/dist/validators/max-age.d.ts +1 -1
  83. package/dist/validators/max-date.d.ts +1 -1
  84. package/dist/validators/max-length.d.ts +1 -1
  85. package/dist/validators/max.d.ts +1 -1
  86. package/dist/validators/min-age.d.ts +1 -1
  87. package/dist/validators/min-date.d.ts +1 -1
  88. package/dist/validators/min-length.d.ts +1 -1
  89. package/dist/validators/min.d.ts +1 -1
  90. package/dist/validators/multiple-of.d.ts +1 -1
  91. package/dist/validators/non-negative.d.ts +1 -1
  92. package/dist/validators/non-zero.d.ts +1 -1
  93. package/dist/validators/past-date.d.ts +1 -1
  94. package/dist/validators/pattern.d.ts +1 -1
  95. package/dist/validators/phone.d.ts +1 -1
  96. package/dist/validators/required.d.ts +1 -1
  97. package/dist/validators/url.d.ts +1 -1
  98. package/dist/validators.d.ts +1 -1
  99. package/docs/llms/02-quick-start.md +14 -7
  100. package/docs/llms/15-project-structure.md +12 -8
  101. package/llms.txt +329 -53
  102. package/package.json +4 -4
  103. package/dist/form/behaviors.d.ts +0 -133
  104. package/dist/form/validation-schema.d.ts +0 -106
  105. package/dist/form/validators.d.ts +0 -11
  106. package/dist/form-model-DhW2HZOB.js +0 -323
  107. package/dist/state.d.ts +0 -2
  108. package/dist/state.js +0 -21
  109. package/dist/subscription-manager-705bls97.js +0 -171
  110. /package/dist/{state → form/nodes}/subscription-manager.d.ts +0 -0
  111. /package/dist/{state → model}/behaviors-value.d.ts +0 -0
  112. /package/dist/{state → model}/derived-registry.d.ts +0 -0
  113. /package/dist/{state → model}/types.d.ts +0 -0
  114. /package/dist/{behaviors-node-DGEFMTQu.js → node-DGEFMTQu.js} +0 -0
  115. /package/dist/{form → platforms/react}/hooks/useSignalSubscription.d.ts +0 -0
@@ -0,0 +1,170 @@
1
+ import { signal as A, effect as M } from "@preact/signals-core";
2
+ import { e as W } from "./create-model-Dxh9cfLp.js";
3
+ import { g as v } from "./signal-node-registry-tiwel-TV.js";
4
+ let g = null;
5
+ function E(e, n) {
6
+ const t = g;
7
+ g = e;
8
+ try {
9
+ return n();
10
+ } finally {
11
+ g = t;
12
+ }
13
+ }
14
+ function u(e) {
15
+ if (!g)
16
+ throw new Error(
17
+ `[@reformer/core/validation] "${e}" вызван вне схемы валидации — операторы валидации можно вызывать только внутри прогона validateModel(...) (напрямую или через apply/each).`
18
+ );
19
+ return g;
20
+ }
21
+ function m(e, n) {
22
+ let t = e.errors.get(n);
23
+ return t || e.errors.set(n, t = []), t;
24
+ }
25
+ const b = (e) => e.whenStack.every((n) => n());
26
+ function D(e, n) {
27
+ const t = u("validate"), r = m(t, e);
28
+ if (!b(t)) return;
29
+ const o = e.peek();
30
+ for (const a of n) {
31
+ const i = a(o, t.model, t.model);
32
+ i && r.push(i);
33
+ }
34
+ }
35
+ function N(e, n) {
36
+ const t = u("validateAsync"), r = m(t, e);
37
+ if (!b(t)) return;
38
+ const o = e.peek(), a = t.signal;
39
+ for (const i of n)
40
+ t.pending.push(
41
+ i(o, { signal: a }).then(
42
+ (s) => {
43
+ s && !a.aborted && r.push(s);
44
+ },
45
+ () => {
46
+ }
47
+ )
48
+ );
49
+ }
50
+ function R(e, n) {
51
+ const t = u("validateWhen");
52
+ t.whenStack.push(e);
53
+ try {
54
+ n();
55
+ } finally {
56
+ t.whenStack.pop();
57
+ }
58
+ }
59
+ function _(e, n) {
60
+ const t = u("cross"), r = m(t, e);
61
+ if (!b(t)) return;
62
+ const o = n(t.model.get());
63
+ o && r.push(o);
64
+ }
65
+ function $(e, n) {
66
+ u("each");
67
+ const t = e.length;
68
+ for (let r = 0; r < t; r++) n(e.at(r));
69
+ }
70
+ function j(...e) {
71
+ const t = u("apply").model;
72
+ for (const r of e) r({ model: t });
73
+ }
74
+ function z(e) {
75
+ return e;
76
+ }
77
+ const x = /* @__PURE__ */ new WeakMap();
78
+ function L(e, n) {
79
+ let t = x.get(e);
80
+ t || x.set(e, t = /* @__PURE__ */ new WeakMap());
81
+ let r = t.get(n);
82
+ return r || t.set(n, r = { fields: /* @__PURE__ */ new Set(), ac: null }), r;
83
+ }
84
+ const P = (e) => {
85
+ for (const n of e.values()) for (const t of n) if (t.severity !== "warning") return !0;
86
+ return !1;
87
+ };
88
+ function T(e) {
89
+ return e.aborted ? Promise.resolve() : new Promise((n) => {
90
+ e.addEventListener("abort", () => n(), { once: !0 });
91
+ });
92
+ }
93
+ async function C(e, n, t) {
94
+ const r = L(e, n);
95
+ r.ac?.abort();
96
+ const o = new AbortController();
97
+ r.ac = o;
98
+ const a = {
99
+ model: e,
100
+ errors: /* @__PURE__ */ new Map(),
101
+ pending: [],
102
+ whenStack: [],
103
+ signal: o.signal
104
+ };
105
+ if (E(a, () => n({ model: e })), a.pending.length && await Promise.race([Promise.all(a.pending), T(o.signal)]), o.signal.aborted) return !1;
106
+ const i = new Set(a.errors.keys());
107
+ for (const s of r.fields) i.has(s) || v(s)?.setErrors([]);
108
+ for (const s of i) v(s)?.setErrors(a.errors.get(s) ?? []);
109
+ if (t?.touch) for (const s of i) v(s)?.markAsTouched();
110
+ return r.fields = i, !P(a.errors);
111
+ }
112
+ function G(e, n, t = {}) {
113
+ const { strategy: r = "submit", debounce: o = 0, liveAfterSubmit: a = "change" } = t, i = A(!1);
114
+ let s = 0, y = !1, f, c;
115
+ const w = async (l) => {
116
+ s++, i.value = !0;
117
+ try {
118
+ return await C(e, n, { touch: l });
119
+ } finally {
120
+ --s === 0 && (i.value = !1);
121
+ }
122
+ }, p = () => {
123
+ w(!1);
124
+ }, F = () => {
125
+ if (!o) {
126
+ p();
127
+ return;
128
+ }
129
+ c && clearTimeout(c), c = setTimeout(p, o);
130
+ }, k = (l, d) => {
131
+ let S = !0;
132
+ return M(() => {
133
+ if (W(e, l), S) {
134
+ S = !1;
135
+ return;
136
+ }
137
+ r === "afterFirstSubmit" && !y || d();
138
+ });
139
+ }, h = {
140
+ async validate() {
141
+ return y = !0, w(!0);
142
+ },
143
+ start() {
144
+ if (f) return () => h.dispose();
145
+ const l = r === "afterFirstSubmit" ? a : r;
146
+ return l === "change" ? f = k((d) => void d.value, F) : l === "blur" && (f = k((d) => void v(d)?.touched.value, p)), () => h.dispose();
147
+ },
148
+ dispose() {
149
+ c && (clearTimeout(c), c = void 0), f?.(), f = void 0;
150
+ },
151
+ get isValidating() {
152
+ return i.value;
153
+ },
154
+ get validating() {
155
+ return i;
156
+ }
157
+ };
158
+ return h;
159
+ }
160
+ export {
161
+ N as a,
162
+ R as b,
163
+ _ as c,
164
+ j as d,
165
+ $ as e,
166
+ z as f,
167
+ C as g,
168
+ G as h,
169
+ D as v
170
+ };
@@ -1,2 +1,2 @@
1
- export * from './form/validation-schema'
1
+ export * from './form/validation/index'
2
2
  export {}
@@ -1,167 +1,12 @@
1
- import { signal as M, effect as E } from "@preact/signals-core";
2
- import { e as L } from "./form-model-DhW2HZOB.js";
3
- import { g as p } from "./signal-node-registry-tiwel-TV.js";
4
- let v = null;
5
- function f(e) {
6
- if (!v)
7
- throw new Error(
8
- `[@reformer/core/validation] "${e}" вызван вне схемы валидации — операторы валидации можно вызывать только внутри прогона validateModel(...) (напрямую или через apply/each).`
9
- );
10
- return v;
11
- }
12
- function b(e, r) {
13
- let t = e.errors.get(r);
14
- return t || e.errors.set(r, t = []), t;
15
- }
16
- const y = (e) => e.whenStack.every((r) => r());
17
- function D(e, r) {
18
- const t = f("validate"), n = b(t, e);
19
- if (!y(t)) return;
20
- const o = e.peek();
21
- for (const i of r) {
22
- const s = i(o, t.model, t.model);
23
- s && n.push(s);
24
- }
25
- }
26
- function N(e, r) {
27
- const t = f("validateAsync"), n = b(t, e);
28
- if (!y(t)) return;
29
- const o = e.peek(), i = t.signal;
30
- for (const s of r)
31
- t.pending.push(
32
- s(o, { signal: i }).then(
33
- (a) => {
34
- a && !i.aborted && n.push(a);
35
- },
36
- () => {
37
- }
38
- )
39
- );
40
- }
41
- function R(e, r) {
42
- const t = f("validateWhen");
43
- t.whenStack.push(e);
44
- try {
45
- r();
46
- } finally {
47
- t.whenStack.pop();
48
- }
49
- }
50
- function _(e, r) {
51
- const t = f("cross"), n = b(t, e);
52
- if (!y(t)) return;
53
- const o = r(t.model.get());
54
- o && n.push(o);
55
- }
56
- function $(e, r) {
57
- f("each");
58
- const t = e.length;
59
- for (let n = 0; n < t; n++) r(e.at(n));
60
- }
61
- function j(...e) {
62
- const t = f("apply").model;
63
- for (const n of e) n({ model: t });
64
- }
65
- function z(e) {
66
- return e;
67
- }
68
- const F = /* @__PURE__ */ new WeakMap();
69
- function P(e, r) {
70
- let t = F.get(e);
71
- t || F.set(e, t = /* @__PURE__ */ new WeakMap());
72
- let n = t.get(r);
73
- return n || t.set(r, n = { fields: /* @__PURE__ */ new Set(), ac: null }), n;
74
- }
75
- const T = (e) => {
76
- for (const r of e.values()) for (const t of r) if (t.severity !== "warning") return !0;
77
- return !1;
78
- };
79
- function W(e) {
80
- return e.aborted ? Promise.resolve() : new Promise((r) => {
81
- e.addEventListener("abort", () => r(), { once: !0 });
82
- });
83
- }
84
- async function V(e, r, t) {
85
- const n = P(e, r);
86
- n.ac?.abort();
87
- const o = new AbortController();
88
- n.ac = o;
89
- const i = {
90
- model: e,
91
- errors: /* @__PURE__ */ new Map(),
92
- pending: [],
93
- whenStack: [],
94
- signal: o.signal
95
- }, s = v;
96
- v = i;
97
- try {
98
- r({ model: e });
99
- } finally {
100
- v = s;
101
- }
102
- if (i.pending.length && await Promise.race([Promise.all(i.pending), W(o.signal)]), o.signal.aborted) return !1;
103
- const a = new Set(i.errors.keys());
104
- for (const c of n.fields) a.has(c) || p(c)?.setErrors([]);
105
- for (const c of a) p(c)?.setErrors(i.errors.get(c) ?? []);
106
- if (t?.touch) for (const c of a) p(c)?.markAsTouched();
107
- return n.fields = a, !T(i.errors);
108
- }
109
- function G(e, r, t = {}) {
110
- const { strategy: n = "submit", debounce: o = 0, liveAfterSubmit: i = "change" } = t, s = M(!1);
111
- let a = 0, c = !1, w = !1, d, l;
112
- const k = async (u) => {
113
- a++, s.value = !0;
114
- try {
115
- return await V(e, r, { touch: u });
116
- } finally {
117
- --a === 0 && (s.value = !1);
118
- }
119
- }, h = () => {
120
- k(!1);
121
- }, A = () => {
122
- if (!o) {
123
- h();
124
- return;
125
- }
126
- l && clearTimeout(l), l = setTimeout(h, o);
127
- }, S = (u, g) => {
128
- let x = !0;
129
- return E(() => {
130
- if (L(e, u), x) {
131
- x = !1;
132
- return;
133
- }
134
- n === "afterFirstSubmit" && !c || g();
135
- });
136
- }, m = {
137
- async validate() {
138
- return c = !0, k(!0);
139
- },
140
- start() {
141
- if (w || d) return () => m.dispose();
142
- const u = n === "afterFirstSubmit" ? i : n;
143
- return u === "change" ? d = S((g) => void g.value, A) : u === "blur" && (d = S((g) => void p(g)?.touched.value, h)), () => m.dispose();
144
- },
145
- dispose() {
146
- w = !0, l && (clearTimeout(l), l = void 0), d?.(), d = void 0;
147
- },
148
- get isValidating() {
149
- return s.value;
150
- },
151
- get validating() {
152
- return s;
153
- }
154
- };
155
- return m;
156
- }
1
+ import { d as s, h as d, c as i, f as l, e as t, v as o, a as c, g as n, b as r } from "./strategy-DA3JwxsR.js";
157
2
  export {
158
- j as apply,
159
- G as createFormValidation,
160
- _ as cross,
161
- z as defineValidationSchema,
162
- $ as each,
163
- D as validate,
164
- N as validateAsync,
165
- V as validateModel,
166
- R as validateWhen
3
+ s as apply,
4
+ d as createFormValidation,
5
+ i as cross,
6
+ l as defineValidationSchema,
7
+ t as each,
8
+ o as validate,
9
+ c as validateAsync,
10
+ n as validateModel,
11
+ r as validateWhen
167
12
  };
@@ -1,2 +1,2 @@
1
- export * from '../form/validation/validators/email'
1
+ export * from '../form/validators/email'
2
2
  export {}
@@ -1,2 +1,2 @@
1
- export * from '../form/validation/validators/future-date'
1
+ export * from '../form/validators/future-date'
2
2
  export {}
@@ -1,2 +1,2 @@
1
- export * from '../form/validation/validators/integer'
1
+ export * from '../form/validators/integer'
2
2
  export {}
@@ -1,2 +1,2 @@
1
- export * from '../form/validation/validators/is-date'
1
+ export * from '../form/validators/is-date'
2
2
  export {}
@@ -1,2 +1,2 @@
1
- export * from '../form/validation/validators/is-number'
1
+ export * from '../form/validators/is-number'
2
2
  export {}
@@ -1,2 +1,2 @@
1
- export * from '../form/validation/validators/max-age'
1
+ export * from '../form/validators/max-age'
2
2
  export {}
@@ -1,2 +1,2 @@
1
- export * from '../form/validation/validators/max-date'
1
+ export * from '../form/validators/max-date'
2
2
  export {}
@@ -1,2 +1,2 @@
1
- export * from '../form/validation/validators/max-length'
1
+ export * from '../form/validators/max-length'
2
2
  export {}
@@ -1,2 +1,2 @@
1
- export * from '../form/validation/validators/max'
1
+ export * from '../form/validators/max'
2
2
  export {}
@@ -1,2 +1,2 @@
1
- export * from '../form/validation/validators/min-age'
1
+ export * from '../form/validators/min-age'
2
2
  export {}
@@ -1,2 +1,2 @@
1
- export * from '../form/validation/validators/min-date'
1
+ export * from '../form/validators/min-date'
2
2
  export {}
@@ -1,2 +1,2 @@
1
- export * from '../form/validation/validators/min-length'
1
+ export * from '../form/validators/min-length'
2
2
  export {}
@@ -1,2 +1,2 @@
1
- export * from '../form/validation/validators/min'
1
+ export * from '../form/validators/min'
2
2
  export {}
@@ -1,2 +1,2 @@
1
- export * from '../form/validation/validators/multiple-of'
1
+ export * from '../form/validators/multiple-of'
2
2
  export {}
@@ -1,2 +1,2 @@
1
- export * from '../form/validation/validators/non-negative'
1
+ export * from '../form/validators/non-negative'
2
2
  export {}
@@ -1,2 +1,2 @@
1
- export * from '../form/validation/validators/non-zero'
1
+ export * from '../form/validators/non-zero'
2
2
  export {}
@@ -1,2 +1,2 @@
1
- export * from '../form/validation/validators/past-date'
1
+ export * from '../form/validators/past-date'
2
2
  export {}
@@ -1,2 +1,2 @@
1
- export * from '../form/validation/validators/pattern'
1
+ export * from '../form/validators/pattern'
2
2
  export {}
@@ -1,2 +1,2 @@
1
- export * from '../form/validation/validators/phone'
1
+ export * from '../form/validators/phone'
2
2
  export {}
@@ -1,2 +1,2 @@
1
- export * from '../form/validation/validators/required'
1
+ export * from '../form/validators/required'
2
2
  export {}
@@ -1,2 +1,2 @@
1
- export * from '../form/validation/validators/url'
1
+ export * from '../form/validators/url'
2
2
  export {}
@@ -1,2 +1,2 @@
1
- export * from './form/validators'
1
+ export * from './form/validators/index'
2
2
  export {}
@@ -7,14 +7,15 @@
7
7
  > `Checkbox`-обёртки с `label`-prop'ами — это anti-pattern. См.
8
8
  > `find_recipe(package="@reformer/ui-kit", topic="form-field-integration")`.
9
9
 
10
- Архитектура M1: сначала создаётся **модель данных** (`createModel`), затем **форма**
11
- (`createForm({ model, schema })`), где схема привязывает поля к сигналам модели
12
- (`model.$.field`). Layout-схема НЕ несёт валидаторов — валидация живёт в отдельной
10
+ Архитектура M1: **модель данных** — источник истины, схема привязывает поля к её сигналам
11
+ (`model.$.field`), а сборка идёт ОДНИМ вызовом `createCoreForm` (для рендера ui-kit;
12
+ в рендерерах — `createReactForm` / `createJsonForm`), который создаёт модель, строит форму,
13
+ запускает поведение и собирает валидацию. Layout-схема НЕ несёт валидаторов — валидация живёт в отдельной
13
14
  схеме `defineValidationSchema` из `@reformer/core/validation` и запускается внешним
14
15
  раннером `validateModel(model, schema)`.
15
16
 
16
17
  ```typescript
17
- import { createModel, createForm, type FormProxy } from '@reformer/core';
18
+ import { createCoreForm, createModel, useFormBundle, type FormProxy } from '@reformer/core';
18
19
  import { defineValidationSchema, validate, validateModel } from '@reformer/core/validation';
19
20
  import { required, email } from '@reformer/core/validators';
20
21
  import { FormField, Input, Button } from '@reformer/ui-kit';
@@ -49,8 +50,14 @@ const contactValidation = defineValidationSchema<ContactForm>(({ model }) => {
49
50
  validate(model.$.email, [required({ message: 'Email is required' }), email({ message: 'Invalid email' })]);
50
51
  });
51
52
 
52
- // 5. Form — ноды поверх сигналов модели
53
- const form = createForm<ContactForm>({ model, schema });
53
+ // 5. Сборка ОДНИМ вызовом: модель + ноды поверх её сигналов + валидация.
54
+ // В React оборачивают в useFormBundle — ленивый useState, фабрика зовётся один раз.
55
+ const contact = createCoreForm<ContactForm>({
56
+ model,
57
+ schema: buildSchema, // билдер (model) => tree
58
+ validation: contactValidation,
59
+ });
60
+ const form = contact.form;
54
61
 
55
62
  // 6. Use in React component — thin JSX, FormField does ALL heavy lifting
56
63
  function ContactFormComponent() {
@@ -121,7 +128,7 @@ const schema = {
121
128
  properties: { array: model.properties, item: propertyItem },
122
129
  };
123
130
 
124
- const form = createForm<MyForm>({ model, schema });
131
+ const { form } = createCoreForm<MyForm>({ model, schema: () => schema });
125
132
 
126
133
  // Операции над массивом — на модели:
127
134
  model.properties.push({ type: 'apartment', description: '', estimatedValue: 0 });
@@ -15,7 +15,7 @@ src/
15
15
  │
16
16
  ├── forms/
17
17
  │ └── [form-name]/ # Form module — flat, one file per concern
18
- │ ├── index.tsx # entry + whole form: createModel→createForm→<FormWizard> with all steps inline; arrays via FormArraySection
18
+ │ ├── index.tsx # entry + whole form: ONE createCoreForm call → <FormWizard> with all steps inline; arrays via FormArraySection
19
19
  │ ├── types.ts # form type + enums + { value, label } option type + constant dictionaries
20
20
  │ ├── model.ts # createModel + initial values + empty-array-element factories
21
21
  │ ├── form.schema.ts # FormSchema: { value: model.$.x, component, componentProps }
@@ -60,11 +60,15 @@ export const creditApplicationBehavior = defineFormBehavior<CreditApplicationFor
60
60
  });
61
61
 
62
62
  // forms/credit-application/index.tsx — entry: assembles the form, renders <FormWizard> with all steps inline
63
- import { createForm } from '@reformer/core';
64
- export const createCreditApplicationForm = () => {
65
- const model = createCreditApplicationModel();
66
- return createForm({ model, schema: creditApplicationSchema(model), behavior: creditApplicationBehavior });
67
- };
63
+ import { createCoreForm } from '@reformer/core';
64
+ // ONE call: model + form + behavior + validation. In the page: useFormBundle(createCreditApplicationForm).
65
+ export const createCreditApplicationForm = () =>
66
+ createCoreForm({
67
+ model: createCreditApplicationModel(),
68
+ schema: creditApplicationSchema, // builder (model) => tree
69
+ behavior: creditApplicationBehavior,
70
+ validation: creditApplicationValidation, // { steps, extras } → bundle.validation
71
+ });
68
72
  ```
69
73
 
70
74
  ### Scaling up: folders (large forms)
@@ -90,10 +94,10 @@ forms/
90
94
  │
91
95
  ├── schema/ # The form definition
92
96
  │ ├── model.ts # createModel factory + initial values + array-element factories
93
- │ ├── schema.ts # createForm schema tree ({ value: model.$.x, component })
97
+ │ ├── schema.ts # schema builder (model) => tree ({ value: model.$.x, component })
94
98
  │ ├── validation.ts # defineValidationSchema + validateModel config ({ validateStep, validateAll })
95
99
  │ ├── behavior.ts # defineFormBehavior(...)
96
- │ └── create-form.ts # Assembly: createForm({ model, schema, behavior })
100
+ │ └── create-form.ts # Assembly: createCoreForm({ model, schema, behavior, validation })
97
101
  │
98
102
  └── components/
99
103
  ├── steps/ # One component per wizard step