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