adaptform 2.1.0 → 2.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +52 -4
- package/CHANGELOG.ru.md +52 -4
- package/README.md +43 -9
- package/README.ru.md +43 -9
- package/dist/{Form-kPYL4f-n.d.cts → Form-uHUaTUZS.d.cts} +81 -9
- package/dist/{Form-kPYL4f-n.d.ts → Form-uHUaTUZS.d.ts} +81 -9
- package/dist/index.cjs +735 -236
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/index.mjs +735 -236
- package/dist/index.mjs.map +1 -1
- package/dist/luxon.d.cts +1 -1
- package/dist/luxon.d.ts +1 -1
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -1,11 +1,332 @@
|
|
|
1
|
+
// src/core/state/value.ts
|
|
2
|
+
function copyValue(value, seen = /* @__PURE__ */ new WeakMap()) {
|
|
3
|
+
if (value === null || typeof value !== "object") return value;
|
|
4
|
+
if (seen.has(value)) return seen.get(value);
|
|
5
|
+
const remember = (copy) => {
|
|
6
|
+
seen.set(value, copy);
|
|
7
|
+
return copy;
|
|
8
|
+
};
|
|
9
|
+
if (value instanceof Date) return remember(new Date(value.getTime()));
|
|
10
|
+
if (value instanceof RegExp) return remember(new RegExp(value.source, value.flags));
|
|
11
|
+
if (value instanceof ArrayBuffer) return remember(value.slice(0));
|
|
12
|
+
if (ArrayBuffer.isView(value)) {
|
|
13
|
+
const bytes = value.buffer.slice(value.byteOffset, value.byteOffset + value.byteLength);
|
|
14
|
+
return remember(value instanceof DataView ? new DataView(bytes) : new value.constructor(bytes));
|
|
15
|
+
}
|
|
16
|
+
if (value instanceof Map) {
|
|
17
|
+
const result = /* @__PURE__ */ new Map();
|
|
18
|
+
seen.set(value, result);
|
|
19
|
+
for (const [key, item] of value) result.set(copyValue(key, seen), copyValue(item, seen));
|
|
20
|
+
return result;
|
|
21
|
+
}
|
|
22
|
+
if (value instanceof Set) {
|
|
23
|
+
const result = /* @__PURE__ */ new Set();
|
|
24
|
+
seen.set(value, result);
|
|
25
|
+
for (const item of value) result.add(copyValue(item, seen));
|
|
26
|
+
return result;
|
|
27
|
+
}
|
|
28
|
+
if (Array.isArray(value) || Object.getPrototypeOf(value) === Object.prototype || Object.getPrototypeOf(value) === null) {
|
|
29
|
+
const result = Array.isArray(value) ? new Array(value.length) : Object.create(Object.getPrototypeOf(value));
|
|
30
|
+
seen.set(value, result);
|
|
31
|
+
for (const key of Object.keys(value)) Object.defineProperty(result, key, {
|
|
32
|
+
value: copyValue(value[key], seen),
|
|
33
|
+
enumerable: true,
|
|
34
|
+
writable: true,
|
|
35
|
+
configurable: true
|
|
36
|
+
});
|
|
37
|
+
return result;
|
|
38
|
+
}
|
|
39
|
+
return value;
|
|
40
|
+
}
|
|
41
|
+
function equalValue(a, b, seen = /* @__PURE__ */ new WeakMap()) {
|
|
42
|
+
if (Object.is(a, b)) return true;
|
|
43
|
+
if (a === null || b === null || typeof a !== "object" || typeof b !== "object") return false;
|
|
44
|
+
if (Object.getPrototypeOf(a) !== Object.getPrototypeOf(b)) return false;
|
|
45
|
+
if (seen.get(a)?.has(b)) return true;
|
|
46
|
+
const matches = seen.get(a) ?? /* @__PURE__ */ new WeakSet();
|
|
47
|
+
matches.add(b);
|
|
48
|
+
seen.set(a, matches);
|
|
49
|
+
if (a instanceof Date && b instanceof Date) return Object.is(a.getTime(), b.getTime());
|
|
50
|
+
if (a instanceof RegExp && b instanceof RegExp) return a.source === b.source && a.flags === b.flags;
|
|
51
|
+
if (a instanceof ArrayBuffer && b instanceof ArrayBuffer) return equalValue(new Uint8Array(a), new Uint8Array(b), seen);
|
|
52
|
+
if (ArrayBuffer.isView(a) && ArrayBuffer.isView(b)) {
|
|
53
|
+
const av = new Uint8Array(a.buffer, a.byteOffset, a.byteLength);
|
|
54
|
+
const bv = new Uint8Array(b.buffer, b.byteOffset, b.byteLength);
|
|
55
|
+
return av.length === bv.length && av.every((byte, i) => byte === bv[i]);
|
|
56
|
+
}
|
|
57
|
+
if (a instanceof Map && b instanceof Map) return equalValue([...a], [...b], seen);
|
|
58
|
+
if (a instanceof Set && b instanceof Set) return equalValue([...a], [...b], seen);
|
|
59
|
+
if ("isLuxonDateTime" in a && a.isLuxonDateTime === true && "equals" in a && typeof a.equals === "function") {
|
|
60
|
+
return a.equals(b);
|
|
61
|
+
}
|
|
62
|
+
if (!Array.isArray(a) && Object.getPrototypeOf(a) !== Object.prototype && Object.getPrototypeOf(a) !== null) return false;
|
|
63
|
+
if (Array.isArray(a) && Array.isArray(b) && a.length !== b.length) return false;
|
|
64
|
+
const keys = Object.keys(a);
|
|
65
|
+
return keys.length === Object.keys(b).length && keys.every((key) => Object.prototype.hasOwnProperty.call(b, key) && equalValue(a[key], b[key], seen));
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
// src/core/state/snapshot.ts
|
|
69
|
+
function snapshotValue(value, seen = /* @__PURE__ */ new WeakMap()) {
|
|
70
|
+
if (value === null || value === void 0 || typeof value === "string" || typeof value === "number" || typeof value === "boolean" || typeof value === "bigint") return value;
|
|
71
|
+
if (typeof value !== "object") return Object.freeze({ kind: "Opaque", type: typeof value });
|
|
72
|
+
const previous = seen.get(value);
|
|
73
|
+
if (previous) return previous;
|
|
74
|
+
if (value instanceof Date) return Object.freeze({ kind: "Date", timestamp: value.getTime() });
|
|
75
|
+
if (value instanceof RegExp) return Object.freeze({ kind: "RegExp", source: value.source, flags: value.flags });
|
|
76
|
+
if (value instanceof ArrayBuffer || ArrayBuffer.isView(value)) {
|
|
77
|
+
const bytes = value instanceof ArrayBuffer ? new Uint8Array(value) : new Uint8Array(value.buffer, value.byteOffset, value.byteLength);
|
|
78
|
+
return Object.freeze({ kind: value.constructor.name, bytes: Object.freeze([...bytes]) });
|
|
79
|
+
}
|
|
80
|
+
if ("isLuxonDateTime" in value && value.isLuxonDateTime === true && "toISO" in value && typeof value.toISO === "function") {
|
|
81
|
+
return Object.freeze({ kind: "DateTime", iso: value.toISO() });
|
|
82
|
+
}
|
|
83
|
+
if (value instanceof Map || value instanceof Set) {
|
|
84
|
+
const result = { kind: value instanceof Map ? "Map" : "Set" };
|
|
85
|
+
seen.set(value, result);
|
|
86
|
+
result.entries = snapshotValue([...value], seen);
|
|
87
|
+
return Object.freeze(result);
|
|
88
|
+
}
|
|
89
|
+
if (Array.isArray(value)) {
|
|
90
|
+
const result = [];
|
|
91
|
+
seen.set(value, result);
|
|
92
|
+
for (const item of value) result.push(snapshotValue(item, seen));
|
|
93
|
+
return Object.freeze(result);
|
|
94
|
+
}
|
|
95
|
+
if (Object.getPrototypeOf(value) === Object.prototype || Object.getPrototypeOf(value) === null) {
|
|
96
|
+
const result = /* @__PURE__ */ Object.create(null);
|
|
97
|
+
seen.set(value, result);
|
|
98
|
+
for (const [key, item] of Object.entries(value)) result[key] = snapshotValue(item, seen);
|
|
99
|
+
return Object.freeze(result);
|
|
100
|
+
}
|
|
101
|
+
return Object.freeze({ kind: "Opaque", type: value.constructor?.name ?? "object" });
|
|
102
|
+
}
|
|
103
|
+
function freezeSnapshot(value, seen = /* @__PURE__ */ new WeakSet()) {
|
|
104
|
+
if (value === null || typeof value !== "object" || seen.has(value)) return value;
|
|
105
|
+
seen.add(value);
|
|
106
|
+
for (const item of Object.values(value)) freezeSnapshot(item, seen);
|
|
107
|
+
return Object.freeze(value);
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
// src/core/state/ObservableNode.ts
|
|
111
|
+
var mutationDepth = 0;
|
|
112
|
+
var flushing = false;
|
|
113
|
+
var publishing = false;
|
|
114
|
+
var batchDepth = 0;
|
|
115
|
+
var validations = /* @__PURE__ */ new Map();
|
|
116
|
+
var batchRoots = /* @__PURE__ */ new Map();
|
|
117
|
+
var pending = /* @__PURE__ */ new Set();
|
|
118
|
+
function flush() {
|
|
119
|
+
if (mutationDepth || flushing) return;
|
|
120
|
+
flushing = true;
|
|
121
|
+
let failure;
|
|
122
|
+
let failed = false;
|
|
123
|
+
try {
|
|
124
|
+
while (pending.size) {
|
|
125
|
+
const stores = [...pending];
|
|
126
|
+
const before = stores.map((store) => store.committed());
|
|
127
|
+
pending.clear();
|
|
128
|
+
for (const store of stores) store.refresh();
|
|
129
|
+
const changed = stores.filter((store, index) => !equalValue(before[index], store.committed()));
|
|
130
|
+
publishing = true;
|
|
131
|
+
try {
|
|
132
|
+
for (const store of changed) {
|
|
133
|
+
try {
|
|
134
|
+
store.notify();
|
|
135
|
+
} catch (error) {
|
|
136
|
+
if (!failed) {
|
|
137
|
+
failure = error;
|
|
138
|
+
failed = true;
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
} finally {
|
|
143
|
+
publishing = false;
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
} finally {
|
|
147
|
+
flushing = false;
|
|
148
|
+
}
|
|
149
|
+
if (failed) throw failure;
|
|
150
|
+
}
|
|
151
|
+
var SnapshotStore = class {
|
|
152
|
+
constructor(capture, getChildren) {
|
|
153
|
+
this.capture = capture;
|
|
154
|
+
this.getChildren = getChildren;
|
|
155
|
+
this.initialized = false;
|
|
156
|
+
this.listeners = /* @__PURE__ */ new Set();
|
|
157
|
+
this.parents = /* @__PURE__ */ new Set();
|
|
158
|
+
this.children = /* @__PURE__ */ new Set();
|
|
159
|
+
}
|
|
160
|
+
reconcile(seen = /* @__PURE__ */ new Set()) {
|
|
161
|
+
if (seen.has(this)) return;
|
|
162
|
+
seen.add(this);
|
|
163
|
+
const next = new Set(this.listeners.size || this.parents.size ? this.getChildren() : []);
|
|
164
|
+
for (const child of this.children) {
|
|
165
|
+
if (!next.has(child)) {
|
|
166
|
+
child.parents.delete(this);
|
|
167
|
+
child.reconcile(seen);
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
const previous = this.children;
|
|
171
|
+
this.children = next;
|
|
172
|
+
for (const child of next) {
|
|
173
|
+
if (!previous.has(child)) {
|
|
174
|
+
child.parents.add(this);
|
|
175
|
+
child.reconcile(seen);
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
read() {
|
|
180
|
+
if (!mutationDepth && !publishing) this.refresh();
|
|
181
|
+
else if (!this.initialized) this.refresh();
|
|
182
|
+
return this.snapshot;
|
|
183
|
+
}
|
|
184
|
+
committed() {
|
|
185
|
+
return this.snapshot;
|
|
186
|
+
}
|
|
187
|
+
refresh() {
|
|
188
|
+
this.reconcile();
|
|
189
|
+
const next = freezeSnapshot(this.capture());
|
|
190
|
+
if (this.initialized && equalValue(this.snapshot, next)) return false;
|
|
191
|
+
this.snapshot = next;
|
|
192
|
+
this.initialized = true;
|
|
193
|
+
return true;
|
|
194
|
+
}
|
|
195
|
+
subscribe(listener) {
|
|
196
|
+
this.read();
|
|
197
|
+
const registration = () => listener();
|
|
198
|
+
this.listeners.add(registration);
|
|
199
|
+
this.reconcile();
|
|
200
|
+
return () => {
|
|
201
|
+
this.listeners.delete(registration);
|
|
202
|
+
this.reconcile();
|
|
203
|
+
};
|
|
204
|
+
}
|
|
205
|
+
changed(seen = /* @__PURE__ */ new Set()) {
|
|
206
|
+
if (seen.has(this)) return;
|
|
207
|
+
seen.add(this);
|
|
208
|
+
this.reconcile();
|
|
209
|
+
if (this.listeners.size || this.parents.size || this.initialized) pending.add(this);
|
|
210
|
+
for (const parent of this.parents) parent.changed(seen);
|
|
211
|
+
}
|
|
212
|
+
notify() {
|
|
213
|
+
let failure;
|
|
214
|
+
let failed = false;
|
|
215
|
+
for (const listener of [...this.listeners]) {
|
|
216
|
+
if (!this.listeners.has(listener)) continue;
|
|
217
|
+
try {
|
|
218
|
+
listener();
|
|
219
|
+
} catch (error) {
|
|
220
|
+
if (!failed) {
|
|
221
|
+
failure = error;
|
|
222
|
+
failed = true;
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
if (failed) throw failure;
|
|
227
|
+
}
|
|
228
|
+
};
|
|
229
|
+
var ObservableNode = class {
|
|
230
|
+
constructor() {
|
|
231
|
+
this._stateStore = new SnapshotStore(
|
|
232
|
+
() => this.captureState(),
|
|
233
|
+
() => this.stateChildren().map((child) => child._stateStore)
|
|
234
|
+
);
|
|
235
|
+
}
|
|
236
|
+
stateChildren() {
|
|
237
|
+
return [];
|
|
238
|
+
}
|
|
239
|
+
contains(node, seen = /* @__PURE__ */ new Set()) {
|
|
240
|
+
if (this === node) return true;
|
|
241
|
+
if (seen.has(this)) return false;
|
|
242
|
+
seen.add(this);
|
|
243
|
+
return this.stateChildren().some((child) => child.contains(node, seen));
|
|
244
|
+
}
|
|
245
|
+
validateAfterMutation(callback) {
|
|
246
|
+
if (batchDepth) validations.set(this, callback);
|
|
247
|
+
else callback();
|
|
248
|
+
}
|
|
249
|
+
batchUpdate(callback, validate) {
|
|
250
|
+
this.getSnapshot();
|
|
251
|
+
return this.update(() => {
|
|
252
|
+
batchDepth++;
|
|
253
|
+
batchRoots.set(this, validate);
|
|
254
|
+
let failed = false;
|
|
255
|
+
let failure;
|
|
256
|
+
let result;
|
|
257
|
+
try {
|
|
258
|
+
result = callback();
|
|
259
|
+
if (result !== null && (typeof result === "object" || typeof result === "function") && "then" in result && typeof result.then === "function") {
|
|
260
|
+
throw new TypeError("batch callbacks must be synchronous");
|
|
261
|
+
}
|
|
262
|
+
} catch (error) {
|
|
263
|
+
failed = true;
|
|
264
|
+
failure = error;
|
|
265
|
+
} finally {
|
|
266
|
+
batchDepth--;
|
|
267
|
+
}
|
|
268
|
+
if (!batchDepth) {
|
|
269
|
+
const requested = [...validations];
|
|
270
|
+
const roots = [...batchRoots];
|
|
271
|
+
validations.clear();
|
|
272
|
+
batchRoots.clear();
|
|
273
|
+
const selected = roots.filter(([root]) => requested.some(([node]) => root.contains(node))).filter(([root], index, all) => !all.some(([other], otherIndex) => other !== root && other.contains(root) && (!root.contains(other) || otherIndex < index)));
|
|
274
|
+
const checks = [
|
|
275
|
+
...selected.map(([, check]) => check),
|
|
276
|
+
...requested.filter(([node]) => !selected.some(([root]) => root.contains(node))).map(([, check]) => check)
|
|
277
|
+
];
|
|
278
|
+
for (const check of checks) {
|
|
279
|
+
try {
|
|
280
|
+
check();
|
|
281
|
+
} catch (error) {
|
|
282
|
+
if (!failed) {
|
|
283
|
+
failed = true;
|
|
284
|
+
failure = error;
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
if (failed) throw failure;
|
|
290
|
+
return result;
|
|
291
|
+
});
|
|
292
|
+
}
|
|
293
|
+
subscribe(listener) {
|
|
294
|
+
return this._stateStore.subscribe(listener);
|
|
295
|
+
}
|
|
296
|
+
getSnapshot() {
|
|
297
|
+
return this._stateStore.read();
|
|
298
|
+
}
|
|
299
|
+
update(callback) {
|
|
300
|
+
mutationDepth++;
|
|
301
|
+
let failed = false;
|
|
302
|
+
try {
|
|
303
|
+
return callback();
|
|
304
|
+
} catch (error) {
|
|
305
|
+
failed = true;
|
|
306
|
+
throw error;
|
|
307
|
+
} finally {
|
|
308
|
+
this._stateStore.changed();
|
|
309
|
+
mutationDepth--;
|
|
310
|
+
if (failed) {
|
|
311
|
+
try {
|
|
312
|
+
flush();
|
|
313
|
+
} catch {
|
|
314
|
+
}
|
|
315
|
+
} else flush();
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
};
|
|
319
|
+
|
|
1
320
|
// src/core/fields/Field.ts
|
|
2
|
-
var Field = class {
|
|
321
|
+
var Field = class extends ObservableNode {
|
|
3
322
|
constructor(TypeConstructor, defaultValue, options) {
|
|
323
|
+
super();
|
|
4
324
|
this._rawValue = null;
|
|
5
325
|
this._valueClear = null;
|
|
326
|
+
this._baseline = null;
|
|
6
327
|
this._errors = [];
|
|
7
|
-
this.
|
|
8
|
-
this.
|
|
328
|
+
this._isValid = null;
|
|
329
|
+
this._isTouched = false;
|
|
9
330
|
this.fieldType = new TypeConstructor(options ?? {});
|
|
10
331
|
this.defaultValue = defaultValue ?? null;
|
|
11
332
|
for (const plugin of this.options.plugins ?? []) {
|
|
@@ -19,6 +340,33 @@ var Field = class {
|
|
|
19
340
|
this.isValid = null;
|
|
20
341
|
}
|
|
21
342
|
this.isTouched = false;
|
|
343
|
+
this.commitBaseline();
|
|
344
|
+
}
|
|
345
|
+
get isValid() {
|
|
346
|
+
return this._isValid;
|
|
347
|
+
}
|
|
348
|
+
set isValid(value) {
|
|
349
|
+
this.update(() => {
|
|
350
|
+
this._isValid = value;
|
|
351
|
+
});
|
|
352
|
+
}
|
|
353
|
+
get isTouched() {
|
|
354
|
+
return this._isTouched;
|
|
355
|
+
}
|
|
356
|
+
set isTouched(value) {
|
|
357
|
+
this.update(() => {
|
|
358
|
+
this._isTouched = value;
|
|
359
|
+
});
|
|
360
|
+
}
|
|
361
|
+
captureState() {
|
|
362
|
+
return {
|
|
363
|
+
rawValue: snapshotValue(this._rawValue),
|
|
364
|
+
valueClear: snapshotValue(this._valueClear),
|
|
365
|
+
errors: [...this._errors],
|
|
366
|
+
isValid: this.isValid,
|
|
367
|
+
isTouched: this.isTouched,
|
|
368
|
+
isDirty: this.isDirty
|
|
369
|
+
};
|
|
22
370
|
}
|
|
23
371
|
// ========== Getters and setters ==========
|
|
24
372
|
get plugins() {
|
|
@@ -30,8 +378,10 @@ var Field = class {
|
|
|
30
378
|
return this.fieldType.options;
|
|
31
379
|
}
|
|
32
380
|
set options(options) {
|
|
33
|
-
|
|
34
|
-
|
|
381
|
+
this.update(() => {
|
|
382
|
+
const currentOptions = this.fieldType.options;
|
|
383
|
+
this.fieldType.options = Object.assign(currentOptions, options);
|
|
384
|
+
});
|
|
35
385
|
}
|
|
36
386
|
get rawValue() {
|
|
37
387
|
return this._rawValue;
|
|
@@ -40,14 +390,16 @@ var Field = class {
|
|
|
40
390
|
this.setRawValue(input);
|
|
41
391
|
}
|
|
42
392
|
setRawValue(input, validate = true) {
|
|
43
|
-
this.
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
393
|
+
return this.update(() => {
|
|
394
|
+
this.assignRawValue(input);
|
|
395
|
+
this._errors = [];
|
|
396
|
+
this.isTouched = true;
|
|
397
|
+
if (validate) {
|
|
398
|
+
this.validateAfterMutation(() => this.checkAndSetValid());
|
|
399
|
+
} else {
|
|
400
|
+
this.isValid = null;
|
|
401
|
+
}
|
|
402
|
+
});
|
|
51
403
|
}
|
|
52
404
|
assignRawValue(input) {
|
|
53
405
|
let rawValue = input;
|
|
@@ -72,16 +424,26 @@ var Field = class {
|
|
|
72
424
|
return this._errors[0] ?? "";
|
|
73
425
|
}
|
|
74
426
|
set error(message) {
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
427
|
+
this.update(() => {
|
|
428
|
+
if (message) {
|
|
429
|
+
this._errors = [message];
|
|
430
|
+
} else {
|
|
431
|
+
this._errors = [];
|
|
432
|
+
}
|
|
433
|
+
this.isValid = message ? false : null;
|
|
434
|
+
});
|
|
81
435
|
}
|
|
82
436
|
get valueClear() {
|
|
83
437
|
return this._valueClear;
|
|
84
438
|
}
|
|
439
|
+
get isDirty() {
|
|
440
|
+
return !equalValue(this._valueClear, this._baseline);
|
|
441
|
+
}
|
|
442
|
+
commitBaseline() {
|
|
443
|
+
return this.update(() => {
|
|
444
|
+
this._baseline = copyValue(this._valueClear);
|
|
445
|
+
});
|
|
446
|
+
}
|
|
85
447
|
// ========== Validation ==========
|
|
86
448
|
isRequired(form) {
|
|
87
449
|
let isRequired;
|
|
@@ -93,41 +455,45 @@ var Field = class {
|
|
|
93
455
|
return isRequired;
|
|
94
456
|
}
|
|
95
457
|
checkValid(form) {
|
|
96
|
-
this.
|
|
97
|
-
|
|
98
|
-
if (this.
|
|
99
|
-
|
|
100
|
-
|
|
458
|
+
return this.update(() => {
|
|
459
|
+
this._errors = [];
|
|
460
|
+
if (this.isEmpty) {
|
|
461
|
+
if (this.isRequired(form)) {
|
|
462
|
+
this._errors.push(this.options.messages?.isRequired ?? "\u041F\u043E\u043B\u0435 \u043E\u0431\u044F\u0437\u0430\u0442\u0435\u043B\u044C\u043D\u043E \u0434\u043B\u044F \u0437\u0430\u043F\u043E\u043B\u043D\u0435\u043D\u0438\u044F");
|
|
463
|
+
return false;
|
|
464
|
+
}
|
|
465
|
+
return true;
|
|
101
466
|
}
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
this.options.messages?.type ?? `\u041E\u0436\u0438\u0434\u0430\u0435\u0442\u0441\u044F ${this.fieldType.getTypeName()}`
|
|
107
|
-
);
|
|
108
|
-
return false;
|
|
109
|
-
}
|
|
110
|
-
const typeErrors = this.fieldType.validate(this._valueClear, form);
|
|
111
|
-
if (typeErrors.length > 0) {
|
|
112
|
-
this._errors.push(...typeErrors);
|
|
113
|
-
return false;
|
|
114
|
-
}
|
|
115
|
-
if (this.options.validate) {
|
|
116
|
-
const result = this.options.validate(this._valueClear, form);
|
|
117
|
-
if (result === false) {
|
|
118
|
-
this._errors.push(this.options.messages?.validate ?? "\u0417\u043D\u0430\u0447\u0435\u043D\u0438\u0435 \u043D\u0435 \u043F\u0440\u043E\u0448\u043B\u043E \u0432\u0430\u043B\u0438\u0434\u0430\u0446\u0438\u044E");
|
|
467
|
+
if (this._valueClear === null) {
|
|
468
|
+
this._errors.push(
|
|
469
|
+
this.options.messages?.type ?? `\u041E\u0436\u0438\u0434\u0430\u0435\u0442\u0441\u044F ${this.fieldType.getTypeName()}`
|
|
470
|
+
);
|
|
119
471
|
return false;
|
|
120
472
|
}
|
|
121
|
-
|
|
122
|
-
|
|
473
|
+
const typeErrors = this.fieldType.validate(this._valueClear, form);
|
|
474
|
+
if (typeErrors.length > 0) {
|
|
475
|
+
this._errors.push(...typeErrors);
|
|
123
476
|
return false;
|
|
124
477
|
}
|
|
125
|
-
|
|
126
|
-
|
|
478
|
+
if (this.options.validate) {
|
|
479
|
+
const result = this.options.validate(this._valueClear, form);
|
|
480
|
+
if (result === false) {
|
|
481
|
+
this._errors.push(this.options.messages?.validate ?? "\u0417\u043D\u0430\u0447\u0435\u043D\u0438\u0435 \u043D\u0435 \u043F\u0440\u043E\u0448\u043B\u043E \u0432\u0430\u043B\u0438\u0434\u0430\u0446\u0438\u044E");
|
|
482
|
+
return false;
|
|
483
|
+
}
|
|
484
|
+
if (typeof result === "string") {
|
|
485
|
+
this._errors.push(result);
|
|
486
|
+
return false;
|
|
487
|
+
}
|
|
488
|
+
}
|
|
489
|
+
return true;
|
|
490
|
+
});
|
|
127
491
|
}
|
|
128
492
|
checkAndSetValid(form) {
|
|
129
|
-
|
|
130
|
-
|
|
493
|
+
return this.update(() => {
|
|
494
|
+
this.isValid = this.checkValid(form);
|
|
495
|
+
return this.isValid;
|
|
496
|
+
});
|
|
131
497
|
}
|
|
132
498
|
get isEmpty() {
|
|
133
499
|
let isEmpty = false;
|
|
@@ -138,15 +504,17 @@ var Field = class {
|
|
|
138
504
|
}
|
|
139
505
|
// ========== Helper methods ==========
|
|
140
506
|
reset() {
|
|
141
|
-
|
|
142
|
-
this.
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
507
|
+
return this.update(() => {
|
|
508
|
+
if (this.defaultValue !== null && this.defaultValue !== void 0) {
|
|
509
|
+
this.assignRawValue(this.defaultValue);
|
|
510
|
+
} else {
|
|
511
|
+
this._rawValue = null;
|
|
512
|
+
this._valueClear = null;
|
|
513
|
+
}
|
|
514
|
+
this._errors = [];
|
|
515
|
+
this.isValid = null;
|
|
516
|
+
this.isTouched = false;
|
|
517
|
+
});
|
|
150
518
|
}
|
|
151
519
|
};
|
|
152
520
|
|
|
@@ -156,28 +524,67 @@ function isValidArrayIndex(index, length) {
|
|
|
156
524
|
}
|
|
157
525
|
|
|
158
526
|
// src/core/fields/ArrayField.ts
|
|
159
|
-
var ArrayField = class {
|
|
527
|
+
var ArrayField = class extends ObservableNode {
|
|
160
528
|
constructor(factory, options = {}, initial = []) {
|
|
529
|
+
super();
|
|
161
530
|
this.factory = factory;
|
|
162
531
|
this._items = [];
|
|
163
532
|
this._errors = [];
|
|
533
|
+
this._baseline = [];
|
|
164
534
|
this._hasValidationResult = false;
|
|
165
|
-
this.
|
|
535
|
+
this._isTouched = false;
|
|
166
536
|
this.options = {
|
|
167
537
|
isRequired: true,
|
|
168
538
|
messages: {},
|
|
169
539
|
...options
|
|
170
540
|
};
|
|
171
541
|
this._items = initial.map((value) => this.factory(value));
|
|
172
|
-
this.checkValid();
|
|
542
|
+
this.validateAfterMutation(() => this.checkValid());
|
|
543
|
+
this.commitBaseline();
|
|
544
|
+
}
|
|
545
|
+
captureState() {
|
|
546
|
+
return {
|
|
547
|
+
itemsValue: snapshotValue(this.itemsValue),
|
|
548
|
+
items: this._items.map((item) => item.getSnapshot()),
|
|
549
|
+
errors: [...this._errors],
|
|
550
|
+
isValid: this.isValid,
|
|
551
|
+
isTouched: this.isTouched,
|
|
552
|
+
isDirty: this.isDirty
|
|
553
|
+
};
|
|
554
|
+
}
|
|
555
|
+
stateChildren() {
|
|
556
|
+
return this._items;
|
|
557
|
+
}
|
|
558
|
+
get isTouched() {
|
|
559
|
+
return this._isTouched;
|
|
560
|
+
}
|
|
561
|
+
set isTouched(value) {
|
|
562
|
+
this.update(() => {
|
|
563
|
+
this._isTouched = value;
|
|
564
|
+
});
|
|
565
|
+
}
|
|
566
|
+
get isDirty() {
|
|
567
|
+
return !equalValue(this.itemsValue, this._baseline) || this._items.some((child) => child.isDirty);
|
|
568
|
+
}
|
|
569
|
+
commitBaseline() {
|
|
570
|
+
return this.update(() => {
|
|
571
|
+
for (const child of this._items) child.commitBaseline();
|
|
572
|
+
this._baseline = copyValue(this.itemsValue);
|
|
573
|
+
});
|
|
173
574
|
}
|
|
174
575
|
// ===== value =====
|
|
175
576
|
set itemsValue(items) {
|
|
176
|
-
this.
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
577
|
+
this.setItemsValue(items);
|
|
578
|
+
}
|
|
579
|
+
setItemsValue(items, validate = true) {
|
|
580
|
+
return this.update(() => {
|
|
581
|
+
this._items = [];
|
|
582
|
+
this.error = null;
|
|
583
|
+
for (const item of items) {
|
|
584
|
+
this.add(item, false);
|
|
585
|
+
}
|
|
586
|
+
if (validate) this.validateAfterMutation(() => this.checkValid());
|
|
587
|
+
});
|
|
181
588
|
}
|
|
182
589
|
get itemsValue() {
|
|
183
590
|
return this._items.map((item) => item.valueClear);
|
|
@@ -187,20 +594,26 @@ var ArrayField = class {
|
|
|
187
594
|
}
|
|
188
595
|
// ===== actions =====
|
|
189
596
|
add(value, force_check = true) {
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
597
|
+
return this.update(() => {
|
|
598
|
+
const field = this.factory(value);
|
|
599
|
+
this.isTouched = true;
|
|
600
|
+
this._items.push(field);
|
|
601
|
+
if (force_check) this.validateAfterMutation(() => this.checkValid());
|
|
602
|
+
return field;
|
|
603
|
+
});
|
|
195
604
|
}
|
|
196
605
|
remove(index) {
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
606
|
+
return this.update(() => {
|
|
607
|
+
if (!isValidArrayIndex(index, this._items.length)) return;
|
|
608
|
+
this._items.splice(index, 1);
|
|
609
|
+
this.validateAfterMutation(() => this.checkValid());
|
|
610
|
+
});
|
|
200
611
|
}
|
|
201
612
|
clear() {
|
|
202
|
-
this.
|
|
203
|
-
|
|
613
|
+
return this.update(() => {
|
|
614
|
+
this._items = [];
|
|
615
|
+
this.validateAfterMutation(() => this.checkValid());
|
|
616
|
+
});
|
|
204
617
|
}
|
|
205
618
|
// ===== validation =====
|
|
206
619
|
isRequired(form) {
|
|
@@ -213,46 +626,48 @@ var ArrayField = class {
|
|
|
213
626
|
return isRequired;
|
|
214
627
|
}
|
|
215
628
|
checkValid(form) {
|
|
216
|
-
this.
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
this.
|
|
220
|
-
this.options.messages?.isRequired ?? "\u0414\u043E\u0431\u0430\u0432\u044C\u0442\u0435 \u0445\u043E\u0442\u044F \u0431\u044B \u043E\u0434\u0438\u043D \u044D\u043B\u0435\u043C\u0435\u043D\u0442"
|
|
221
|
-
);
|
|
222
|
-
return false;
|
|
223
|
-
}
|
|
224
|
-
if (this.options.minItems != null && this._items.length < this.options.minItems) {
|
|
225
|
-
this._errors.push(
|
|
226
|
-
this.options.messages?.minItems ?? `\u0417\u043D\u0430\u0447\u0435\u043D\u0438\u0439 \u0434\u043E\u043B\u0436\u043D\u043E \u0431\u044B\u0442\u044C \u043D\u0435 \u043C\u0435\u043D\u044C\u0448\u0435 ${this.options.minItems}`
|
|
227
|
-
);
|
|
228
|
-
return false;
|
|
229
|
-
}
|
|
230
|
-
if (this.options.maxItems != null && this._items.length > this.options.maxItems) {
|
|
231
|
-
this._errors.push(
|
|
232
|
-
this.options.messages?.maxItems ?? `\u0417\u043D\u0430\u0447\u0435\u043D\u0438\u0439 \u0434\u043E\u043B\u0436\u043D\u043E \u0431\u044B\u0442\u044C \u043D\u0435 \u0431\u043E\u043B\u044C\u0448\u0435 ${this.options.maxItems}`
|
|
233
|
-
);
|
|
234
|
-
return false;
|
|
235
|
-
}
|
|
236
|
-
let valid = true;
|
|
237
|
-
for (const field of this._items) {
|
|
238
|
-
const ok = field.checkAndSetValid(form);
|
|
239
|
-
if (!ok) valid = false;
|
|
240
|
-
}
|
|
241
|
-
if (this.options.validate) {
|
|
242
|
-
const values = this._items.map((item) => item.valueClear);
|
|
243
|
-
const result = this.options.validate(values, form);
|
|
244
|
-
if (result === false) {
|
|
629
|
+
return this.update(() => {
|
|
630
|
+
this._hasValidationResult = true;
|
|
631
|
+
this._errors = [];
|
|
632
|
+
if (this.isRequired(form) && this._items.length === 0) {
|
|
245
633
|
this._errors.push(
|
|
246
|
-
this.options.messages?.
|
|
634
|
+
this.options.messages?.isRequired ?? "\u0414\u043E\u0431\u0430\u0432\u044C\u0442\u0435 \u0445\u043E\u0442\u044F \u0431\u044B \u043E\u0434\u0438\u043D \u044D\u043B\u0435\u043C\u0435\u043D\u0442"
|
|
247
635
|
);
|
|
248
636
|
return false;
|
|
249
637
|
}
|
|
250
|
-
if (
|
|
251
|
-
this._errors.push(
|
|
638
|
+
if (this.options.minItems != null && this._items.length < this.options.minItems) {
|
|
639
|
+
this._errors.push(
|
|
640
|
+
this.options.messages?.minItems ?? `\u0417\u043D\u0430\u0447\u0435\u043D\u0438\u0439 \u0434\u043E\u043B\u0436\u043D\u043E \u0431\u044B\u0442\u044C \u043D\u0435 \u043C\u0435\u043D\u044C\u0448\u0435 ${this.options.minItems}`
|
|
641
|
+
);
|
|
252
642
|
return false;
|
|
253
643
|
}
|
|
254
|
-
|
|
255
|
-
|
|
644
|
+
if (this.options.maxItems != null && this._items.length > this.options.maxItems) {
|
|
645
|
+
this._errors.push(
|
|
646
|
+
this.options.messages?.maxItems ?? `\u0417\u043D\u0430\u0447\u0435\u043D\u0438\u0439 \u0434\u043E\u043B\u0436\u043D\u043E \u0431\u044B\u0442\u044C \u043D\u0435 \u0431\u043E\u043B\u044C\u0448\u0435 ${this.options.maxItems}`
|
|
647
|
+
);
|
|
648
|
+
return false;
|
|
649
|
+
}
|
|
650
|
+
let valid = true;
|
|
651
|
+
for (const field of this._items) {
|
|
652
|
+
const ok = field.checkAndSetValid(form);
|
|
653
|
+
if (!ok) valid = false;
|
|
654
|
+
}
|
|
655
|
+
if (this.options.validate) {
|
|
656
|
+
const values = this._items.map((item) => item.valueClear);
|
|
657
|
+
const result = this.options.validate(values, form);
|
|
658
|
+
if (result === false) {
|
|
659
|
+
this._errors.push(
|
|
660
|
+
this.options.messages?.validate ?? "\u041E\u0448\u0438\u0431\u043A\u0430 \u0432\u0430\u043B\u0438\u0434\u0430\u0446\u0438\u0438"
|
|
661
|
+
);
|
|
662
|
+
return false;
|
|
663
|
+
}
|
|
664
|
+
if (typeof result === "string") {
|
|
665
|
+
this._errors.push(result);
|
|
666
|
+
return false;
|
|
667
|
+
}
|
|
668
|
+
}
|
|
669
|
+
return valid && this._errors.length === 0;
|
|
670
|
+
});
|
|
256
671
|
}
|
|
257
672
|
checkAndSetValid(form) {
|
|
258
673
|
return this.checkValid(form);
|
|
@@ -266,51 +681,90 @@ var ArrayField = class {
|
|
|
266
681
|
return this._errors[0] ?? "";
|
|
267
682
|
}
|
|
268
683
|
set error(message) {
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
684
|
+
this.update(() => {
|
|
685
|
+
if (message) {
|
|
686
|
+
this._errors = [message];
|
|
687
|
+
this._hasValidationResult = true;
|
|
688
|
+
} else {
|
|
689
|
+
this._errors = [];
|
|
690
|
+
this._hasValidationResult = false;
|
|
691
|
+
}
|
|
692
|
+
});
|
|
276
693
|
}
|
|
277
694
|
get errors() {
|
|
278
695
|
return this._errors;
|
|
279
696
|
}
|
|
280
697
|
reset() {
|
|
281
|
-
this.
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
698
|
+
return this.update(() => {
|
|
699
|
+
this._items.forEach((item) => item.reset());
|
|
700
|
+
this._errors = [];
|
|
701
|
+
this._hasValidationResult = false;
|
|
702
|
+
this.isTouched = false;
|
|
703
|
+
});
|
|
285
704
|
}
|
|
286
705
|
};
|
|
287
706
|
|
|
288
707
|
// src/core/fields/ArrayFormField.ts
|
|
289
|
-
var ArrayFormField = class {
|
|
708
|
+
var ArrayFormField = class extends ObservableNode {
|
|
290
709
|
constructor(FormConstructor, options = {}, initial = []) {
|
|
710
|
+
super();
|
|
291
711
|
this.FormConstructor = FormConstructor;
|
|
292
712
|
this.options = options;
|
|
293
713
|
this._forms = [];
|
|
294
714
|
this._errors = [];
|
|
715
|
+
this._baseline = [];
|
|
295
716
|
this._hasValidationResult = false;
|
|
296
|
-
this.
|
|
717
|
+
this._isTouched = false;
|
|
297
718
|
this._forms = initial.map((data) => {
|
|
298
719
|
const form = new this.FormConstructor();
|
|
299
720
|
form.setFields(data, false);
|
|
300
721
|
return form;
|
|
301
722
|
});
|
|
302
|
-
this.checkValid();
|
|
723
|
+
this.validateAfterMutation(() => this.checkValid());
|
|
724
|
+
this.commitBaseline();
|
|
725
|
+
}
|
|
726
|
+
captureState() {
|
|
727
|
+
return {
|
|
728
|
+
formsFieldsValue: snapshotValue(this.formsFieldsValue),
|
|
729
|
+
forms: this._forms.map((form) => form.getSnapshot()),
|
|
730
|
+
errors: [...this._errors],
|
|
731
|
+
isValid: this.isValid,
|
|
732
|
+
isTouched: this.isTouched,
|
|
733
|
+
isDirty: this.isDirty
|
|
734
|
+
};
|
|
735
|
+
}
|
|
736
|
+
stateChildren() {
|
|
737
|
+
return this._forms;
|
|
738
|
+
}
|
|
739
|
+
get isTouched() {
|
|
740
|
+
return this._isTouched;
|
|
741
|
+
}
|
|
742
|
+
set isTouched(value) {
|
|
743
|
+
this.update(() => {
|
|
744
|
+
this._isTouched = value;
|
|
745
|
+
});
|
|
746
|
+
}
|
|
747
|
+
get isDirty() {
|
|
748
|
+
return !equalValue(this.formsFieldsValue, this._baseline) || this._forms.some((child) => child.isDirty);
|
|
749
|
+
}
|
|
750
|
+
commitBaseline() {
|
|
751
|
+
return this.update(() => {
|
|
752
|
+
for (const child of this._forms) child.commitBaseline();
|
|
753
|
+
this._baseline = copyValue(this.formsFieldsValue);
|
|
754
|
+
});
|
|
303
755
|
}
|
|
304
756
|
// ===== value =====
|
|
305
757
|
set forms(forms) {
|
|
306
758
|
this.setForms(forms);
|
|
307
759
|
}
|
|
308
760
|
setForms(forms, validate = true) {
|
|
309
|
-
this.
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
761
|
+
return this.update(() => {
|
|
762
|
+
this._forms = [];
|
|
763
|
+
for (const formData of forms) {
|
|
764
|
+
this.add(formData, false);
|
|
765
|
+
}
|
|
766
|
+
if (validate) this.validateAfterMutation(() => this.checkValid());
|
|
767
|
+
});
|
|
314
768
|
}
|
|
315
769
|
get forms() {
|
|
316
770
|
return this._forms;
|
|
@@ -320,29 +774,38 @@ var ArrayFormField = class {
|
|
|
320
774
|
}
|
|
321
775
|
// ===== actions =====
|
|
322
776
|
add(data, force_check = true) {
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
777
|
+
return this.update(() => {
|
|
778
|
+
const form = new this.FormConstructor();
|
|
779
|
+
if (data !== void 0 && data !== null) {
|
|
780
|
+
form.setFields(data, false);
|
|
781
|
+
}
|
|
782
|
+
form.commitBaseline();
|
|
783
|
+
this.isTouched = true;
|
|
784
|
+
this._forms.push(form);
|
|
785
|
+
if (force_check) this.validateAfterMutation(() => this.checkValid());
|
|
786
|
+
return form;
|
|
787
|
+
});
|
|
331
788
|
}
|
|
332
789
|
remove(index) {
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
790
|
+
return this.update(() => {
|
|
791
|
+
if (!isValidArrayIndex(index, this._forms.length)) return;
|
|
792
|
+
this._forms.splice(index, 1);
|
|
793
|
+
this.validateAfterMutation(() => this.checkValid());
|
|
794
|
+
});
|
|
336
795
|
}
|
|
337
796
|
clear() {
|
|
338
|
-
this.
|
|
339
|
-
|
|
797
|
+
return this.update(() => {
|
|
798
|
+
this._forms = [];
|
|
799
|
+
this.validateAfterMutation(() => this.checkValid());
|
|
800
|
+
});
|
|
340
801
|
}
|
|
341
802
|
reset() {
|
|
342
|
-
this.
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
803
|
+
return this.update(() => {
|
|
804
|
+
this._forms.forEach((form) => form.reset());
|
|
805
|
+
this._errors = [];
|
|
806
|
+
this._hasValidationResult = false;
|
|
807
|
+
this.isTouched = false;
|
|
808
|
+
});
|
|
346
809
|
}
|
|
347
810
|
// ===== validation =====
|
|
348
811
|
isRequired(form) {
|
|
@@ -355,45 +818,47 @@ var ArrayFormField = class {
|
|
|
355
818
|
return isRequired;
|
|
356
819
|
}
|
|
357
820
|
checkValid(form) {
|
|
358
|
-
this.
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
this.
|
|
362
|
-
this.options.messages?.isRequired ?? "\u0414\u043E\u0431\u0430\u0432\u044C\u0442\u0435 \u0445\u043E\u0442\u044F \u0431\u044B \u043E\u0434\u0438\u043D \u044D\u043B\u0435\u043C\u0435\u043D\u0442"
|
|
363
|
-
);
|
|
364
|
-
return false;
|
|
365
|
-
}
|
|
366
|
-
if (this.options.minForms != null && this._forms.length < this.options.minForms) {
|
|
367
|
-
this._errors.push(
|
|
368
|
-
this.options.messages?.minForms ?? `\u0417\u043D\u0430\u0447\u0435\u043D\u0438\u0439 \u0434\u043E\u043B\u0436\u043D\u043E \u0431\u044B\u0442\u044C \u043D\u0435 \u043C\u0435\u043D\u044C\u0448\u0435 ${this.options.minForms}`
|
|
369
|
-
);
|
|
370
|
-
return false;
|
|
371
|
-
}
|
|
372
|
-
if (this.options.maxForms != null && this._forms.length > this.options.maxForms) {
|
|
373
|
-
this._errors.push(
|
|
374
|
-
this.options.messages?.maxForms ?? `\u0417\u043D\u0430\u0447\u0435\u043D\u0438\u0439 \u0434\u043E\u043B\u0436\u043D\u043E \u0431\u044B\u0442\u044C \u043D\u0435 \u0431\u043E\u043B\u044C\u0448\u0435 ${this.options.maxForms}`
|
|
375
|
-
);
|
|
376
|
-
return false;
|
|
377
|
-
}
|
|
378
|
-
let valid = true;
|
|
379
|
-
for (const nestedForm of this._forms) {
|
|
380
|
-
const ok = nestedForm.checkValid(nestedForm);
|
|
381
|
-
if (!ok) valid = false;
|
|
382
|
-
}
|
|
383
|
-
if (this.options.validate) {
|
|
384
|
-
const result = this.options.validate(this._forms, form);
|
|
385
|
-
if (result === false) {
|
|
821
|
+
return this.update(() => {
|
|
822
|
+
this._hasValidationResult = true;
|
|
823
|
+
this._errors = [];
|
|
824
|
+
if (this.isRequired(form) && this._forms.length === 0) {
|
|
386
825
|
this._errors.push(
|
|
387
|
-
this.options.messages?.
|
|
826
|
+
this.options.messages?.isRequired ?? "\u0414\u043E\u0431\u0430\u0432\u044C\u0442\u0435 \u0445\u043E\u0442\u044F \u0431\u044B \u043E\u0434\u0438\u043D \u044D\u043B\u0435\u043C\u0435\u043D\u0442"
|
|
388
827
|
);
|
|
389
828
|
return false;
|
|
390
829
|
}
|
|
391
|
-
if (
|
|
392
|
-
this._errors.push(
|
|
830
|
+
if (this.options.minForms != null && this._forms.length < this.options.minForms) {
|
|
831
|
+
this._errors.push(
|
|
832
|
+
this.options.messages?.minForms ?? `\u0417\u043D\u0430\u0447\u0435\u043D\u0438\u0439 \u0434\u043E\u043B\u0436\u043D\u043E \u0431\u044B\u0442\u044C \u043D\u0435 \u043C\u0435\u043D\u044C\u0448\u0435 ${this.options.minForms}`
|
|
833
|
+
);
|
|
393
834
|
return false;
|
|
394
835
|
}
|
|
395
|
-
|
|
396
|
-
|
|
836
|
+
if (this.options.maxForms != null && this._forms.length > this.options.maxForms) {
|
|
837
|
+
this._errors.push(
|
|
838
|
+
this.options.messages?.maxForms ?? `\u0417\u043D\u0430\u0447\u0435\u043D\u0438\u0439 \u0434\u043E\u043B\u0436\u043D\u043E \u0431\u044B\u0442\u044C \u043D\u0435 \u0431\u043E\u043B\u044C\u0448\u0435 ${this.options.maxForms}`
|
|
839
|
+
);
|
|
840
|
+
return false;
|
|
841
|
+
}
|
|
842
|
+
let valid = true;
|
|
843
|
+
for (const nestedForm of this._forms) {
|
|
844
|
+
const ok = nestedForm.checkValid(nestedForm);
|
|
845
|
+
if (!ok) valid = false;
|
|
846
|
+
}
|
|
847
|
+
if (this.options.validate) {
|
|
848
|
+
const result = this.options.validate(this._forms, form);
|
|
849
|
+
if (result === false) {
|
|
850
|
+
this._errors.push(
|
|
851
|
+
this.options.messages?.validate ?? "\u041E\u0448\u0438\u0431\u043A\u0430 \u0432\u0430\u043B\u0438\u0434\u0430\u0446\u0438\u0438"
|
|
852
|
+
);
|
|
853
|
+
return false;
|
|
854
|
+
}
|
|
855
|
+
if (typeof result === "string") {
|
|
856
|
+
this._errors.push(result);
|
|
857
|
+
return false;
|
|
858
|
+
}
|
|
859
|
+
}
|
|
860
|
+
return valid && this._errors.length === 0;
|
|
861
|
+
});
|
|
397
862
|
}
|
|
398
863
|
checkAndSetValid(form) {
|
|
399
864
|
return this.checkValid(form);
|
|
@@ -410,13 +875,15 @@ var ArrayFormField = class {
|
|
|
410
875
|
return this._errors[0] ?? "";
|
|
411
876
|
}
|
|
412
877
|
set error(message) {
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
878
|
+
this.update(() => {
|
|
879
|
+
if (message) {
|
|
880
|
+
this._errors = [message];
|
|
881
|
+
this._hasValidationResult = true;
|
|
882
|
+
} else {
|
|
883
|
+
this._errors = [];
|
|
884
|
+
this._hasValidationResult = false;
|
|
885
|
+
}
|
|
886
|
+
});
|
|
420
887
|
}
|
|
421
888
|
};
|
|
422
889
|
|
|
@@ -671,11 +1138,29 @@ var ErrorsSchema = class _ErrorsSchema {
|
|
|
671
1138
|
var DefaultErrorsSchema = new ErrorsSchema().fallback((key) => key);
|
|
672
1139
|
|
|
673
1140
|
// src/core/Form.ts
|
|
674
|
-
var Form = class {
|
|
1141
|
+
var Form = class extends ObservableNode {
|
|
675
1142
|
constructor() {
|
|
1143
|
+
super(...arguments);
|
|
676
1144
|
this._globalErrors = {};
|
|
677
1145
|
this.errorsShema = DefaultErrorsSchema;
|
|
678
1146
|
}
|
|
1147
|
+
captureState() {
|
|
1148
|
+
return {
|
|
1149
|
+
fieldsValue: snapshotValue(this.fieldsValue),
|
|
1150
|
+
allErrors: this.allErrors,
|
|
1151
|
+
globalErrors: this.globalErrors,
|
|
1152
|
+
fields: Object.fromEntries(Object.entries(this._fields).map(([key, field]) => [key, field.getSnapshot()])),
|
|
1153
|
+
isValid: this.isValid,
|
|
1154
|
+
isTouched: this.isTouched,
|
|
1155
|
+
isDirty: this.isDirty
|
|
1156
|
+
};
|
|
1157
|
+
}
|
|
1158
|
+
stateChildren() {
|
|
1159
|
+
return Object.values(this._fields);
|
|
1160
|
+
}
|
|
1161
|
+
batch(callback) {
|
|
1162
|
+
return this.batchUpdate(callback, () => this.checkValid());
|
|
1163
|
+
}
|
|
679
1164
|
get _fields() {
|
|
680
1165
|
const fields = {};
|
|
681
1166
|
for (const key of Object.keys(this)) {
|
|
@@ -687,15 +1172,17 @@ var Form = class {
|
|
|
687
1172
|
return fields;
|
|
688
1173
|
}
|
|
689
1174
|
checkValid(form) {
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
const
|
|
694
|
-
|
|
695
|
-
|
|
1175
|
+
return this.update(() => {
|
|
1176
|
+
let isFormValid = true;
|
|
1177
|
+
const fields = this._fields;
|
|
1178
|
+
for (const key of Object.keys(fields)) {
|
|
1179
|
+
const field = fields[key];
|
|
1180
|
+
if (!field.checkAndSetValid(form ?? this)) {
|
|
1181
|
+
isFormValid = false;
|
|
1182
|
+
}
|
|
696
1183
|
}
|
|
697
|
-
|
|
698
|
-
|
|
1184
|
+
return isFormValid && Object.keys(this._globalErrors).length === 0;
|
|
1185
|
+
});
|
|
699
1186
|
}
|
|
700
1187
|
get fieldsValue() {
|
|
701
1188
|
const data = {};
|
|
@@ -715,17 +1202,19 @@ var Form = class {
|
|
|
715
1202
|
this.setFields(data);
|
|
716
1203
|
}
|
|
717
1204
|
setFields(data, validate = true) {
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
const
|
|
721
|
-
|
|
722
|
-
if (field
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
1205
|
+
return this.update(() => {
|
|
1206
|
+
const fields = this._fields;
|
|
1207
|
+
for (const key of Object.keys(data)) {
|
|
1208
|
+
const field = fields[key];
|
|
1209
|
+
if (field) {
|
|
1210
|
+
if (field instanceof Field) field.setRawValue(data[key], false);
|
|
1211
|
+
else if (field instanceof ArrayField) field.setItemsValue(data[key], false);
|
|
1212
|
+
else if (field instanceof ArrayFormField) field.setForms(data[key], false);
|
|
1213
|
+
else console.error(`Invalid field "${key}" type`);
|
|
1214
|
+
}
|
|
726
1215
|
}
|
|
727
|
-
|
|
728
|
-
|
|
1216
|
+
if (validate) this.validateAfterMutation(() => this.checkValid());
|
|
1217
|
+
});
|
|
729
1218
|
}
|
|
730
1219
|
get allErrors() {
|
|
731
1220
|
const errors = {};
|
|
@@ -740,7 +1229,7 @@ var Form = class {
|
|
|
740
1229
|
} else {
|
|
741
1230
|
const fieldErrors = field.errors;
|
|
742
1231
|
if (fieldErrors.length > 0) {
|
|
743
|
-
errors[key] = fieldErrors;
|
|
1232
|
+
errors[key] = [...fieldErrors];
|
|
744
1233
|
}
|
|
745
1234
|
}
|
|
746
1235
|
}
|
|
@@ -773,26 +1262,30 @@ var Form = class {
|
|
|
773
1262
|
return { ...this._globalErrors };
|
|
774
1263
|
}
|
|
775
1264
|
set errors(errors) {
|
|
776
|
-
this.
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
1265
|
+
this.update(() => {
|
|
1266
|
+
this.clearErrorsRecursively();
|
|
1267
|
+
const fields = this._fields;
|
|
1268
|
+
const parsedErrors = this.errorsShema.parseErrors(errors);
|
|
1269
|
+
for (const [fieldName, errorMessage] of Object.entries(parsedErrors)) {
|
|
1270
|
+
this.applyErrorToField(fieldName, errorMessage, fields, this);
|
|
1271
|
+
}
|
|
1272
|
+
});
|
|
782
1273
|
}
|
|
783
1274
|
clearErrorsRecursively() {
|
|
784
|
-
this.
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
field
|
|
788
|
-
|
|
789
|
-
field
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
field
|
|
793
|
-
|
|
1275
|
+
this.update(() => {
|
|
1276
|
+
this._globalErrors = {};
|
|
1277
|
+
for (const field of Object.values(this._fields)) {
|
|
1278
|
+
if (field instanceof Field) {
|
|
1279
|
+
field.error = null;
|
|
1280
|
+
} else if (field instanceof ArrayField) {
|
|
1281
|
+
field.error = null;
|
|
1282
|
+
for (const item of field.items) item.error = null;
|
|
1283
|
+
} else if (field instanceof ArrayFormField) {
|
|
1284
|
+
field.error = null;
|
|
1285
|
+
for (const nestedForm of field.forms) nestedForm.clearErrorsRecursively();
|
|
1286
|
+
}
|
|
794
1287
|
}
|
|
795
|
-
}
|
|
1288
|
+
});
|
|
796
1289
|
}
|
|
797
1290
|
/**
|
|
798
1291
|
* Apply an error to the corresponding field.
|
|
@@ -844,17 +1337,31 @@ var Form = class {
|
|
|
844
1337
|
}
|
|
845
1338
|
}
|
|
846
1339
|
setGlobalError(key, message) {
|
|
847
|
-
this.
|
|
1340
|
+
return this.update(() => {
|
|
1341
|
+
this._globalErrors[key] = message;
|
|
1342
|
+
});
|
|
848
1343
|
}
|
|
849
1344
|
clearGlobalErrors() {
|
|
850
|
-
this.
|
|
1345
|
+
return this.update(() => {
|
|
1346
|
+
this._globalErrors = {};
|
|
1347
|
+
});
|
|
851
1348
|
}
|
|
852
1349
|
reset() {
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
1350
|
+
return this.update(() => {
|
|
1351
|
+
const fields = this._fields;
|
|
1352
|
+
for (const key of Object.keys(fields)) {
|
|
1353
|
+
fields[key].reset();
|
|
1354
|
+
}
|
|
1355
|
+
this._globalErrors = {};
|
|
1356
|
+
});
|
|
1357
|
+
}
|
|
1358
|
+
get isDirty() {
|
|
1359
|
+
return Object.values(this._fields).some((field) => field.isDirty);
|
|
1360
|
+
}
|
|
1361
|
+
commitBaseline() {
|
|
1362
|
+
return this.update(() => {
|
|
1363
|
+
for (const field of Object.values(this._fields)) field.commitBaseline();
|
|
1364
|
+
});
|
|
858
1365
|
}
|
|
859
1366
|
get isTouched() {
|
|
860
1367
|
const fields = this._fields;
|
|
@@ -1245,14 +1752,6 @@ var DecimalType = class extends FieldType {
|
|
|
1245
1752
|
const parts = normalizedValue.split(".");
|
|
1246
1753
|
const intPart = parts[0];
|
|
1247
1754
|
const decPart = parts.length > 1 ? parts[1] : "";
|
|
1248
|
-
if (normalizedValue.endsWith(".")) {
|
|
1249
|
-
if (intPart.length > maxIntDigits) {
|
|
1250
|
-
errors.push(
|
|
1251
|
-
this.options.messages?.maxDigits ?? `\u041C\u0430\u043A\u0441\u0438\u043C\u0430\u043B\u044C\u043D\u043E\u0435 \u043A\u043E\u043B\u0438\u0447\u0435\u0441\u0442\u0432\u043E \u0437\u043D\u0430\u043A\u043E\u0432 \u043F\u0435\u0440\u0435\u0434 \u0437\u0430\u043F\u044F\u0442\u043E\u0439 ${maxIntDigits}`
|
|
1252
|
-
);
|
|
1253
|
-
}
|
|
1254
|
-
return errors;
|
|
1255
|
-
}
|
|
1256
1755
|
if (intPart.length === 0) {
|
|
1257
1756
|
errors.push(this.options.messages?.invalid ?? "\u041F\u0440\u0438\u043C\u0435\u0440: 1.00");
|
|
1258
1757
|
return errors;
|