@schemx/vue 0.1.20 → 0.1.21
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/README.md +3 -0
- package/dist/components/FormItem/index.d.ts.map +1 -1
- package/dist/hooks/useContext.d.ts.map +1 -1
- package/dist/hooks/useDictionary.d.ts +2 -2
- package/dist/hooks/useDictionary.d.ts.map +1 -1
- package/dist/hooks/useField.d.ts.map +1 -1
- package/dist/hooks/useFieldContext.d.ts.map +1 -1
- package/dist/index.cjs +1 -1
- package/dist/index.cjs.map +1 -1
- package/dist/index.mjs +4695 -31
- package/dist/index.mjs.map +1 -1
- package/dist/index.umd.js +1 -1
- package/dist/index.umd.js.map +1 -1
- package/dist/style.css +1 -1
- package/dist/utils/helpers.d.ts +26 -0
- package/dist/utils/helpers.d.ts.map +1 -0
- package/package.json +12 -4
package/dist/index.mjs
CHANGED
|
@@ -1,8 +1,4602 @@
|
|
|
1
|
-
import
|
|
1
|
+
import "./style.css";
|
|
2
|
+
import { computed, provide, onUnmounted, inject, shallowRef, ref, onMounted, watchEffect, onScopeDispose, defineComponent, createVNode, toRef, h as h$1, createTextVNode, watch, openBlock, createElementBlock, normalizeClass, Fragment, renderList, unref, createBlock, createSlots, withCtx, renderSlot, mergeProps } from "vue";
|
|
2
3
|
import classnames from "classnames";
|
|
3
4
|
import { omit } from "es-toolkit";
|
|
4
|
-
|
|
5
|
-
|
|
5
|
+
var __defProp = Object.defineProperty;
|
|
6
|
+
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
7
|
+
var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
|
|
8
|
+
var i = Symbol.for("preact-signals");
|
|
9
|
+
function t() {
|
|
10
|
+
if (!(s > 1)) {
|
|
11
|
+
var i2, t2 = false;
|
|
12
|
+
!function() {
|
|
13
|
+
var i3 = c;
|
|
14
|
+
c = void 0;
|
|
15
|
+
while (void 0 !== i3) {
|
|
16
|
+
if (i3.S.v === i3.v) i3.S.i = i3.i;
|
|
17
|
+
i3 = i3.o;
|
|
18
|
+
}
|
|
19
|
+
}();
|
|
20
|
+
while (void 0 !== h) {
|
|
21
|
+
var n2 = h;
|
|
22
|
+
h = void 0;
|
|
23
|
+
v++;
|
|
24
|
+
while (void 0 !== n2) {
|
|
25
|
+
var r2 = n2.u;
|
|
26
|
+
n2.u = void 0;
|
|
27
|
+
n2.f &= -3;
|
|
28
|
+
if (!(8 & n2.f) && w(n2)) try {
|
|
29
|
+
n2.c();
|
|
30
|
+
} catch (n3) {
|
|
31
|
+
if (!t2) {
|
|
32
|
+
i2 = n3;
|
|
33
|
+
t2 = true;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
n2 = r2;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
v = 0;
|
|
40
|
+
s--;
|
|
41
|
+
if (t2) throw i2;
|
|
42
|
+
} else s--;
|
|
43
|
+
}
|
|
44
|
+
function n(i2) {
|
|
45
|
+
if (s > 0) return i2();
|
|
46
|
+
e = ++u;
|
|
47
|
+
s++;
|
|
48
|
+
try {
|
|
49
|
+
return i2();
|
|
50
|
+
} finally {
|
|
51
|
+
t();
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
var r = void 0;
|
|
55
|
+
function o(i2) {
|
|
56
|
+
var t2 = r;
|
|
57
|
+
r = void 0;
|
|
58
|
+
try {
|
|
59
|
+
return i2();
|
|
60
|
+
} finally {
|
|
61
|
+
r = t2;
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
var h = void 0, s = 0, v = 0, u = 0, e = 0, c = void 0, d = 0;
|
|
65
|
+
function a(i2) {
|
|
66
|
+
if (void 0 !== r) {
|
|
67
|
+
var t2 = i2.n;
|
|
68
|
+
if (void 0 === t2 || t2.t !== r) {
|
|
69
|
+
t2 = { i: 0, S: i2, p: r.s, n: void 0, t: r, e: void 0, x: void 0, r: t2 };
|
|
70
|
+
if (void 0 !== r.s) r.s.n = t2;
|
|
71
|
+
r.s = t2;
|
|
72
|
+
i2.n = t2;
|
|
73
|
+
if (32 & r.f) i2.S(t2);
|
|
74
|
+
return t2;
|
|
75
|
+
} else if (-1 === t2.i) {
|
|
76
|
+
t2.i = 0;
|
|
77
|
+
if (void 0 !== t2.n) {
|
|
78
|
+
t2.n.p = t2.p;
|
|
79
|
+
if (void 0 !== t2.p) t2.p.n = t2.n;
|
|
80
|
+
t2.p = r.s;
|
|
81
|
+
t2.n = void 0;
|
|
82
|
+
r.s.n = t2;
|
|
83
|
+
r.s = t2;
|
|
84
|
+
}
|
|
85
|
+
return t2;
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
function l(i2, t2) {
|
|
90
|
+
this.v = i2;
|
|
91
|
+
this.i = 0;
|
|
92
|
+
this.n = void 0;
|
|
93
|
+
this.t = void 0;
|
|
94
|
+
this.l = 0;
|
|
95
|
+
this.W = null == t2 ? void 0 : t2.watched;
|
|
96
|
+
this.Z = null == t2 ? void 0 : t2.unwatched;
|
|
97
|
+
this.name = null == t2 ? void 0 : t2.name;
|
|
98
|
+
}
|
|
99
|
+
l.prototype.brand = i;
|
|
100
|
+
l.prototype.h = function() {
|
|
101
|
+
return true;
|
|
102
|
+
};
|
|
103
|
+
l.prototype.S = function(i2) {
|
|
104
|
+
var t2 = this, n2 = this.t;
|
|
105
|
+
if (n2 !== i2 && void 0 === i2.e) {
|
|
106
|
+
i2.x = n2;
|
|
107
|
+
this.t = i2;
|
|
108
|
+
if (void 0 !== n2) n2.e = i2;
|
|
109
|
+
else o(function() {
|
|
110
|
+
var i3;
|
|
111
|
+
null == (i3 = t2.W) || i3.call(t2);
|
|
112
|
+
});
|
|
113
|
+
}
|
|
114
|
+
};
|
|
115
|
+
l.prototype.U = function(i2) {
|
|
116
|
+
var t2 = this;
|
|
117
|
+
if (void 0 !== this.t) {
|
|
118
|
+
var n2 = i2.e, r2 = i2.x;
|
|
119
|
+
if (void 0 !== n2) {
|
|
120
|
+
n2.x = r2;
|
|
121
|
+
i2.e = void 0;
|
|
122
|
+
}
|
|
123
|
+
if (void 0 !== r2) {
|
|
124
|
+
r2.e = n2;
|
|
125
|
+
i2.x = void 0;
|
|
126
|
+
}
|
|
127
|
+
if (i2 === this.t) {
|
|
128
|
+
this.t = r2;
|
|
129
|
+
if (void 0 === r2) o(function() {
|
|
130
|
+
var i3;
|
|
131
|
+
null == (i3 = t2.Z) || i3.call(t2);
|
|
132
|
+
});
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
};
|
|
136
|
+
l.prototype.subscribe = function(i2) {
|
|
137
|
+
var t2 = this;
|
|
138
|
+
return j(function() {
|
|
139
|
+
var n2 = t2.value, o2 = r;
|
|
140
|
+
r = void 0;
|
|
141
|
+
try {
|
|
142
|
+
i2(n2);
|
|
143
|
+
} finally {
|
|
144
|
+
r = o2;
|
|
145
|
+
}
|
|
146
|
+
}, { name: "sub" });
|
|
147
|
+
};
|
|
148
|
+
l.prototype.valueOf = function() {
|
|
149
|
+
return this.value;
|
|
150
|
+
};
|
|
151
|
+
l.prototype.toString = function() {
|
|
152
|
+
return this.value + "";
|
|
153
|
+
};
|
|
154
|
+
l.prototype.toJSON = function() {
|
|
155
|
+
return this.value;
|
|
156
|
+
};
|
|
157
|
+
l.prototype.peek = function() {
|
|
158
|
+
var i2 = this;
|
|
159
|
+
return o(function() {
|
|
160
|
+
return i2.value;
|
|
161
|
+
});
|
|
162
|
+
};
|
|
163
|
+
Object.defineProperty(l.prototype, "value", { get: function() {
|
|
164
|
+
var i2 = a(this);
|
|
165
|
+
if (void 0 !== i2) i2.i = this.i;
|
|
166
|
+
return this.v;
|
|
167
|
+
}, set: function(i2) {
|
|
168
|
+
if (i2 !== this.v) {
|
|
169
|
+
if (v > 100) throw new Error("Cycle detected");
|
|
170
|
+
!function(i3) {
|
|
171
|
+
if (0 !== s && 0 === v) {
|
|
172
|
+
if (i3.l !== e) {
|
|
173
|
+
i3.l = e;
|
|
174
|
+
c = { S: i3, v: i3.v, i: i3.i, o: c };
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
}(this);
|
|
178
|
+
this.v = i2;
|
|
179
|
+
this.i++;
|
|
180
|
+
d++;
|
|
181
|
+
s++;
|
|
182
|
+
try {
|
|
183
|
+
for (var n2 = this.t; void 0 !== n2; n2 = n2.x) n2.t.N();
|
|
184
|
+
} finally {
|
|
185
|
+
t();
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
} });
|
|
189
|
+
function y(i2, t2) {
|
|
190
|
+
return new l(i2, t2);
|
|
191
|
+
}
|
|
192
|
+
function w(i2) {
|
|
193
|
+
for (var t2 = i2.s; void 0 !== t2; t2 = t2.n) if (t2.S.i !== t2.i || !t2.S.h() || t2.S.i !== t2.i) return true;
|
|
194
|
+
return false;
|
|
195
|
+
}
|
|
196
|
+
function _(i2) {
|
|
197
|
+
for (var t2 = i2.s; void 0 !== t2; t2 = t2.n) {
|
|
198
|
+
var n2 = t2.S.n;
|
|
199
|
+
if (void 0 !== n2) t2.r = n2;
|
|
200
|
+
t2.S.n = t2;
|
|
201
|
+
t2.i = -1;
|
|
202
|
+
if (void 0 === t2.n) {
|
|
203
|
+
i2.s = t2;
|
|
204
|
+
break;
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
function b(i2) {
|
|
209
|
+
var t2 = i2.s, n2 = void 0;
|
|
210
|
+
while (void 0 !== t2) {
|
|
211
|
+
var r2 = t2.p;
|
|
212
|
+
if (-1 === t2.i) {
|
|
213
|
+
t2.S.U(t2);
|
|
214
|
+
if (void 0 !== r2) r2.n = t2.n;
|
|
215
|
+
if (void 0 !== t2.n) t2.n.p = r2;
|
|
216
|
+
} else n2 = t2;
|
|
217
|
+
t2.S.n = t2.r;
|
|
218
|
+
if (void 0 !== t2.r) t2.r = void 0;
|
|
219
|
+
t2 = r2;
|
|
220
|
+
}
|
|
221
|
+
i2.s = n2;
|
|
222
|
+
}
|
|
223
|
+
function p(i2, t2) {
|
|
224
|
+
l.call(this, void 0);
|
|
225
|
+
this.x = i2;
|
|
226
|
+
this.s = void 0;
|
|
227
|
+
this.g = d - 1;
|
|
228
|
+
this.f = 4;
|
|
229
|
+
this.W = null == t2 ? void 0 : t2.watched;
|
|
230
|
+
this.Z = null == t2 ? void 0 : t2.unwatched;
|
|
231
|
+
this.name = null == t2 ? void 0 : t2.name;
|
|
232
|
+
}
|
|
233
|
+
p.prototype = new l();
|
|
234
|
+
p.prototype.h = function() {
|
|
235
|
+
this.f &= -3;
|
|
236
|
+
if (1 & this.f) return false;
|
|
237
|
+
if (32 == (36 & this.f)) return true;
|
|
238
|
+
this.f &= -5;
|
|
239
|
+
if (this.g === d) return true;
|
|
240
|
+
this.g = d;
|
|
241
|
+
this.f |= 1;
|
|
242
|
+
if (this.i > 0 && !w(this)) {
|
|
243
|
+
this.f &= -2;
|
|
244
|
+
return true;
|
|
245
|
+
}
|
|
246
|
+
var i2 = r;
|
|
247
|
+
try {
|
|
248
|
+
_(this);
|
|
249
|
+
r = this;
|
|
250
|
+
var t2 = this.x();
|
|
251
|
+
if (16 & this.f || this.v !== t2 || 0 === this.i) {
|
|
252
|
+
this.v = t2;
|
|
253
|
+
this.f &= -17;
|
|
254
|
+
this.i++;
|
|
255
|
+
}
|
|
256
|
+
} catch (i3) {
|
|
257
|
+
this.v = i3;
|
|
258
|
+
this.f |= 16;
|
|
259
|
+
this.i++;
|
|
260
|
+
}
|
|
261
|
+
r = i2;
|
|
262
|
+
b(this);
|
|
263
|
+
this.f &= -2;
|
|
264
|
+
return true;
|
|
265
|
+
};
|
|
266
|
+
p.prototype.S = function(i2) {
|
|
267
|
+
if (void 0 === this.t) {
|
|
268
|
+
this.f |= 36;
|
|
269
|
+
for (var t2 = this.s; void 0 !== t2; t2 = t2.n) t2.S.S(t2);
|
|
270
|
+
}
|
|
271
|
+
l.prototype.S.call(this, i2);
|
|
272
|
+
};
|
|
273
|
+
p.prototype.U = function(i2) {
|
|
274
|
+
if (void 0 !== this.t) {
|
|
275
|
+
l.prototype.U.call(this, i2);
|
|
276
|
+
if (void 0 === this.t) {
|
|
277
|
+
this.f &= -33;
|
|
278
|
+
for (var t2 = this.s; void 0 !== t2; t2 = t2.n) t2.S.U(t2);
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
};
|
|
282
|
+
p.prototype.N = function() {
|
|
283
|
+
if (!(2 & this.f)) {
|
|
284
|
+
this.f |= 6;
|
|
285
|
+
for (var i2 = this.t; void 0 !== i2; i2 = i2.x) i2.t.N();
|
|
286
|
+
}
|
|
287
|
+
};
|
|
288
|
+
Object.defineProperty(p.prototype, "value", { get: function() {
|
|
289
|
+
if (1 & this.f) throw new Error("Cycle detected");
|
|
290
|
+
var i2 = a(this);
|
|
291
|
+
this.h();
|
|
292
|
+
if (void 0 !== i2) i2.i = this.i;
|
|
293
|
+
if (16 & this.f) throw this.v;
|
|
294
|
+
return this.v;
|
|
295
|
+
} });
|
|
296
|
+
function S(i2) {
|
|
297
|
+
var n2 = i2.m;
|
|
298
|
+
i2.m = void 0;
|
|
299
|
+
if ("function" == typeof n2) {
|
|
300
|
+
s++;
|
|
301
|
+
var o2 = r;
|
|
302
|
+
r = void 0;
|
|
303
|
+
try {
|
|
304
|
+
n2();
|
|
305
|
+
} catch (t2) {
|
|
306
|
+
i2.f &= -2;
|
|
307
|
+
i2.f |= 8;
|
|
308
|
+
m(i2);
|
|
309
|
+
throw t2;
|
|
310
|
+
} finally {
|
|
311
|
+
r = o2;
|
|
312
|
+
t();
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
function m(i2) {
|
|
317
|
+
for (var t2 = i2.s; void 0 !== t2; t2 = t2.n) t2.S.U(t2);
|
|
318
|
+
i2.x = void 0;
|
|
319
|
+
i2.s = void 0;
|
|
320
|
+
S(i2);
|
|
321
|
+
}
|
|
322
|
+
function x(i2) {
|
|
323
|
+
if (r !== this) throw new Error("Out-of-order effect");
|
|
324
|
+
b(this);
|
|
325
|
+
r = i2;
|
|
326
|
+
this.f &= -2;
|
|
327
|
+
if (8 & this.f) m(this);
|
|
328
|
+
t();
|
|
329
|
+
}
|
|
330
|
+
function E(i2, t2) {
|
|
331
|
+
this.x = i2;
|
|
332
|
+
this.m = void 0;
|
|
333
|
+
this.s = void 0;
|
|
334
|
+
this.u = void 0;
|
|
335
|
+
this.f = 32;
|
|
336
|
+
this.name = null == t2 ? void 0 : t2.name;
|
|
337
|
+
}
|
|
338
|
+
E.prototype.c = function() {
|
|
339
|
+
var i2 = this.S();
|
|
340
|
+
try {
|
|
341
|
+
if (8 & this.f) return;
|
|
342
|
+
if (void 0 === this.x) return;
|
|
343
|
+
var t2 = this.x();
|
|
344
|
+
if ("function" == typeof t2) this.m = t2;
|
|
345
|
+
} finally {
|
|
346
|
+
i2();
|
|
347
|
+
}
|
|
348
|
+
};
|
|
349
|
+
E.prototype.S = function() {
|
|
350
|
+
if (1 & this.f) throw new Error("Cycle detected");
|
|
351
|
+
this.f |= 1;
|
|
352
|
+
this.f &= -9;
|
|
353
|
+
S(this);
|
|
354
|
+
_(this);
|
|
355
|
+
s++;
|
|
356
|
+
var i2 = r;
|
|
357
|
+
r = this;
|
|
358
|
+
return x.bind(this, i2);
|
|
359
|
+
};
|
|
360
|
+
E.prototype.N = function() {
|
|
361
|
+
if (!(2 & this.f)) {
|
|
362
|
+
this.f |= 2;
|
|
363
|
+
this.u = h;
|
|
364
|
+
h = this;
|
|
365
|
+
}
|
|
366
|
+
};
|
|
367
|
+
E.prototype.d = function() {
|
|
368
|
+
this.f |= 8;
|
|
369
|
+
if (!(1 & this.f)) m(this);
|
|
370
|
+
};
|
|
371
|
+
E.prototype.dispose = function() {
|
|
372
|
+
this.d();
|
|
373
|
+
};
|
|
374
|
+
function j(i2, t2) {
|
|
375
|
+
var n2 = new E(i2, t2);
|
|
376
|
+
try {
|
|
377
|
+
n2.c();
|
|
378
|
+
} catch (i3) {
|
|
379
|
+
n2.d();
|
|
380
|
+
throw i3;
|
|
381
|
+
}
|
|
382
|
+
var r2 = n2.d.bind(n2);
|
|
383
|
+
r2[Symbol.dispose] = r2;
|
|
384
|
+
return r2;
|
|
385
|
+
}
|
|
386
|
+
function createSignal(value, options) {
|
|
387
|
+
return y(value, options);
|
|
388
|
+
}
|
|
389
|
+
function isSymbol(value) {
|
|
390
|
+
return typeof value === "symbol" || value instanceof Symbol;
|
|
391
|
+
}
|
|
392
|
+
const globalThis_ = typeof globalThis === "object" && globalThis || typeof window === "object" && window || typeof self === "object" && self || typeof global === "object" && global || /* @__PURE__ */ function() {
|
|
393
|
+
return this;
|
|
394
|
+
}();
|
|
395
|
+
function debounce(func, debounceMs, { signal, edges } = {}) {
|
|
396
|
+
let pendingThis = void 0;
|
|
397
|
+
let pendingArgs = null;
|
|
398
|
+
const leading = edges != null && edges.includes("leading");
|
|
399
|
+
const trailing = edges == null || edges.includes("trailing");
|
|
400
|
+
const invoke = () => {
|
|
401
|
+
if (pendingArgs !== null) {
|
|
402
|
+
func.apply(pendingThis, pendingArgs);
|
|
403
|
+
pendingThis = void 0;
|
|
404
|
+
pendingArgs = null;
|
|
405
|
+
}
|
|
406
|
+
};
|
|
407
|
+
const onTimerEnd = () => {
|
|
408
|
+
if (trailing) invoke();
|
|
409
|
+
cancel();
|
|
410
|
+
};
|
|
411
|
+
let timeoutId = null;
|
|
412
|
+
const schedule = () => {
|
|
413
|
+
if (timeoutId != null) clearTimeout(timeoutId);
|
|
414
|
+
timeoutId = setTimeout(() => {
|
|
415
|
+
timeoutId = null;
|
|
416
|
+
onTimerEnd();
|
|
417
|
+
}, debounceMs);
|
|
418
|
+
};
|
|
419
|
+
const cancelTimer = () => {
|
|
420
|
+
if (timeoutId !== null) {
|
|
421
|
+
clearTimeout(timeoutId);
|
|
422
|
+
timeoutId = null;
|
|
423
|
+
}
|
|
424
|
+
};
|
|
425
|
+
const cancel = () => {
|
|
426
|
+
cancelTimer();
|
|
427
|
+
pendingThis = void 0;
|
|
428
|
+
pendingArgs = null;
|
|
429
|
+
};
|
|
430
|
+
const flush = () => {
|
|
431
|
+
invoke();
|
|
432
|
+
};
|
|
433
|
+
const debounced = function(...args) {
|
|
434
|
+
if (signal == null ? void 0 : signal.aborted) return;
|
|
435
|
+
pendingThis = this;
|
|
436
|
+
pendingArgs = args;
|
|
437
|
+
const isFirstCall = timeoutId == null;
|
|
438
|
+
schedule();
|
|
439
|
+
if (leading && isFirstCall) invoke();
|
|
440
|
+
};
|
|
441
|
+
debounced.schedule = schedule;
|
|
442
|
+
debounced.cancel = cancel;
|
|
443
|
+
debounced.flush = flush;
|
|
444
|
+
signal == null ? void 0 : signal.addEventListener("abort", cancel, { once: true });
|
|
445
|
+
return debounced;
|
|
446
|
+
}
|
|
447
|
+
function noop$1() {
|
|
448
|
+
}
|
|
449
|
+
function isPrimitive(value) {
|
|
450
|
+
return value == null || typeof value !== "object" && typeof value !== "function";
|
|
451
|
+
}
|
|
452
|
+
function isTypedArray(x2) {
|
|
453
|
+
return ArrayBuffer.isView(x2) && !(x2 instanceof DataView);
|
|
454
|
+
}
|
|
455
|
+
function isBuffer(x2) {
|
|
456
|
+
return typeof globalThis_.Buffer !== "undefined" && globalThis_.Buffer.isBuffer(x2);
|
|
457
|
+
}
|
|
458
|
+
function getSymbols(object) {
|
|
459
|
+
return Object.getOwnPropertySymbols(object).filter((symbol) => Object.prototype.propertyIsEnumerable.call(object, symbol));
|
|
460
|
+
}
|
|
461
|
+
function getTag(value) {
|
|
462
|
+
if (value == null) return value === void 0 ? "[object Undefined]" : "[object Null]";
|
|
463
|
+
return Object.prototype.toString.call(value);
|
|
464
|
+
}
|
|
465
|
+
const regexpTag = "[object RegExp]";
|
|
466
|
+
const stringTag = "[object String]";
|
|
467
|
+
const numberTag = "[object Number]";
|
|
468
|
+
const booleanTag = "[object Boolean]";
|
|
469
|
+
const argumentsTag = "[object Arguments]";
|
|
470
|
+
const symbolTag = "[object Symbol]";
|
|
471
|
+
const dateTag = "[object Date]";
|
|
472
|
+
const mapTag = "[object Map]";
|
|
473
|
+
const setTag = "[object Set]";
|
|
474
|
+
const arrayTag = "[object Array]";
|
|
475
|
+
const functionTag = "[object Function]";
|
|
476
|
+
const arrayBufferTag = "[object ArrayBuffer]";
|
|
477
|
+
const objectTag = "[object Object]";
|
|
478
|
+
const errorTag = "[object Error]";
|
|
479
|
+
const dataViewTag = "[object DataView]";
|
|
480
|
+
const uint8ArrayTag = "[object Uint8Array]";
|
|
481
|
+
const uint8ClampedArrayTag = "[object Uint8ClampedArray]";
|
|
482
|
+
const uint16ArrayTag = "[object Uint16Array]";
|
|
483
|
+
const uint32ArrayTag = "[object Uint32Array]";
|
|
484
|
+
const bigUint64ArrayTag = "[object BigUint64Array]";
|
|
485
|
+
const int8ArrayTag = "[object Int8Array]";
|
|
486
|
+
const int16ArrayTag = "[object Int16Array]";
|
|
487
|
+
const int32ArrayTag = "[object Int32Array]";
|
|
488
|
+
const bigInt64ArrayTag = "[object BigInt64Array]";
|
|
489
|
+
const float32ArrayTag = "[object Float32Array]";
|
|
490
|
+
const float64ArrayTag = "[object Float64Array]";
|
|
491
|
+
function cloneDeepWithImpl(valueToClone, keyToClone, objectToClone, stack = /* @__PURE__ */ new Map(), cloneValue = void 0) {
|
|
492
|
+
const cloned = cloneValue == null ? void 0 : cloneValue(valueToClone, keyToClone, objectToClone, stack);
|
|
493
|
+
if (cloned !== void 0) return cloned;
|
|
494
|
+
if (isPrimitive(valueToClone)) return valueToClone;
|
|
495
|
+
if (stack.has(valueToClone)) return stack.get(valueToClone);
|
|
496
|
+
if (Array.isArray(valueToClone)) {
|
|
497
|
+
const result = new Array(valueToClone.length);
|
|
498
|
+
stack.set(valueToClone, result);
|
|
499
|
+
for (let i2 = 0; i2 < valueToClone.length; i2++) result[i2] = cloneDeepWithImpl(valueToClone[i2], i2, objectToClone, stack, cloneValue);
|
|
500
|
+
if (Object.hasOwn(valueToClone, "index")) result.index = valueToClone.index;
|
|
501
|
+
if (Object.hasOwn(valueToClone, "input")) result.input = valueToClone.input;
|
|
502
|
+
return result;
|
|
503
|
+
}
|
|
504
|
+
if (valueToClone instanceof Date) return new Date(valueToClone.getTime());
|
|
505
|
+
if (valueToClone instanceof RegExp) {
|
|
506
|
+
const result = new RegExp(valueToClone.source, valueToClone.flags);
|
|
507
|
+
result.lastIndex = valueToClone.lastIndex;
|
|
508
|
+
return result;
|
|
509
|
+
}
|
|
510
|
+
if (valueToClone instanceof Map) {
|
|
511
|
+
const result = /* @__PURE__ */ new Map();
|
|
512
|
+
stack.set(valueToClone, result);
|
|
513
|
+
for (const [key, value] of valueToClone) result.set(key, cloneDeepWithImpl(value, key, objectToClone, stack, cloneValue));
|
|
514
|
+
return result;
|
|
515
|
+
}
|
|
516
|
+
if (valueToClone instanceof Set) {
|
|
517
|
+
const result = /* @__PURE__ */ new Set();
|
|
518
|
+
stack.set(valueToClone, result);
|
|
519
|
+
for (const value of valueToClone) result.add(cloneDeepWithImpl(value, void 0, objectToClone, stack, cloneValue));
|
|
520
|
+
return result;
|
|
521
|
+
}
|
|
522
|
+
if (isBuffer(valueToClone)) return valueToClone.subarray();
|
|
523
|
+
if (isTypedArray(valueToClone)) {
|
|
524
|
+
const result = new (Object.getPrototypeOf(valueToClone)).constructor(valueToClone.length);
|
|
525
|
+
stack.set(valueToClone, result);
|
|
526
|
+
for (let i2 = 0; i2 < valueToClone.length; i2++) result[i2] = cloneDeepWithImpl(valueToClone[i2], i2, objectToClone, stack, cloneValue);
|
|
527
|
+
return result;
|
|
528
|
+
}
|
|
529
|
+
if (valueToClone instanceof ArrayBuffer || typeof SharedArrayBuffer !== "undefined" && valueToClone instanceof SharedArrayBuffer) return valueToClone.slice(0);
|
|
530
|
+
if (valueToClone instanceof DataView) {
|
|
531
|
+
const result = new DataView(valueToClone.buffer.slice(0), valueToClone.byteOffset, valueToClone.byteLength);
|
|
532
|
+
stack.set(valueToClone, result);
|
|
533
|
+
copyProperties(result, valueToClone, objectToClone, stack, cloneValue);
|
|
534
|
+
return result;
|
|
535
|
+
}
|
|
536
|
+
if (typeof File !== "undefined" && valueToClone instanceof File) {
|
|
537
|
+
const result = new File([valueToClone], valueToClone.name, { type: valueToClone.type });
|
|
538
|
+
stack.set(valueToClone, result);
|
|
539
|
+
copyProperties(result, valueToClone, objectToClone, stack, cloneValue);
|
|
540
|
+
return result;
|
|
541
|
+
}
|
|
542
|
+
if (typeof Blob !== "undefined" && valueToClone instanceof Blob) {
|
|
543
|
+
const result = new Blob([valueToClone], { type: valueToClone.type });
|
|
544
|
+
stack.set(valueToClone, result);
|
|
545
|
+
copyProperties(result, valueToClone, objectToClone, stack, cloneValue);
|
|
546
|
+
return result;
|
|
547
|
+
}
|
|
548
|
+
if (valueToClone instanceof Error) {
|
|
549
|
+
const result = structuredClone(valueToClone);
|
|
550
|
+
stack.set(valueToClone, result);
|
|
551
|
+
result.message = valueToClone.message;
|
|
552
|
+
result.name = valueToClone.name;
|
|
553
|
+
result.stack = valueToClone.stack;
|
|
554
|
+
result.cause = valueToClone.cause;
|
|
555
|
+
result.constructor = valueToClone.constructor;
|
|
556
|
+
copyProperties(result, valueToClone, objectToClone, stack, cloneValue);
|
|
557
|
+
return result;
|
|
558
|
+
}
|
|
559
|
+
if (valueToClone instanceof Boolean) {
|
|
560
|
+
const result = new Boolean(valueToClone.valueOf());
|
|
561
|
+
stack.set(valueToClone, result);
|
|
562
|
+
copyProperties(result, valueToClone, objectToClone, stack, cloneValue);
|
|
563
|
+
return result;
|
|
564
|
+
}
|
|
565
|
+
if (valueToClone instanceof Number) {
|
|
566
|
+
const result = new Number(valueToClone.valueOf());
|
|
567
|
+
stack.set(valueToClone, result);
|
|
568
|
+
copyProperties(result, valueToClone, objectToClone, stack, cloneValue);
|
|
569
|
+
return result;
|
|
570
|
+
}
|
|
571
|
+
if (valueToClone instanceof String) {
|
|
572
|
+
const result = new String(valueToClone.valueOf());
|
|
573
|
+
stack.set(valueToClone, result);
|
|
574
|
+
copyProperties(result, valueToClone, objectToClone, stack, cloneValue);
|
|
575
|
+
return result;
|
|
576
|
+
}
|
|
577
|
+
if (typeof valueToClone === "object" && isCloneableObject(valueToClone)) {
|
|
578
|
+
const result = Object.create(Object.getPrototypeOf(valueToClone));
|
|
579
|
+
stack.set(valueToClone, result);
|
|
580
|
+
copyProperties(result, valueToClone, objectToClone, stack, cloneValue);
|
|
581
|
+
return result;
|
|
582
|
+
}
|
|
583
|
+
return valueToClone;
|
|
584
|
+
}
|
|
585
|
+
function copyProperties(target, source, objectToClone = target, stack, cloneValue) {
|
|
586
|
+
const keys = [...Object.keys(source), ...getSymbols(source)];
|
|
587
|
+
for (let i2 = 0; i2 < keys.length; i2++) {
|
|
588
|
+
const key = keys[i2];
|
|
589
|
+
const descriptor = Object.getOwnPropertyDescriptor(target, key);
|
|
590
|
+
if (descriptor == null || descriptor.writable) target[key] = cloneDeepWithImpl(source[key], key, objectToClone, stack, cloneValue);
|
|
591
|
+
}
|
|
592
|
+
}
|
|
593
|
+
function isCloneableObject(object) {
|
|
594
|
+
switch (getTag(object)) {
|
|
595
|
+
case argumentsTag:
|
|
596
|
+
case arrayTag:
|
|
597
|
+
case arrayBufferTag:
|
|
598
|
+
case dataViewTag:
|
|
599
|
+
case booleanTag:
|
|
600
|
+
case dateTag:
|
|
601
|
+
case float32ArrayTag:
|
|
602
|
+
case float64ArrayTag:
|
|
603
|
+
case int8ArrayTag:
|
|
604
|
+
case int16ArrayTag:
|
|
605
|
+
case int32ArrayTag:
|
|
606
|
+
case mapTag:
|
|
607
|
+
case numberTag:
|
|
608
|
+
case objectTag:
|
|
609
|
+
case regexpTag:
|
|
610
|
+
case setTag:
|
|
611
|
+
case stringTag:
|
|
612
|
+
case symbolTag:
|
|
613
|
+
case uint8ArrayTag:
|
|
614
|
+
case uint8ClampedArrayTag:
|
|
615
|
+
case uint16ArrayTag:
|
|
616
|
+
case uint32ArrayTag:
|
|
617
|
+
return true;
|
|
618
|
+
default:
|
|
619
|
+
return false;
|
|
620
|
+
}
|
|
621
|
+
}
|
|
622
|
+
function cloneDeep(obj) {
|
|
623
|
+
return cloneDeepWithImpl(obj, void 0, obj, /* @__PURE__ */ new Map(), void 0);
|
|
624
|
+
}
|
|
625
|
+
function isPlainObject(value) {
|
|
626
|
+
if (!value || typeof value !== "object") return false;
|
|
627
|
+
const proto = Object.getPrototypeOf(value);
|
|
628
|
+
if (!(proto === null || proto === Object.prototype || Object.getPrototypeOf(proto) === null)) return false;
|
|
629
|
+
return Object.prototype.toString.call(value) === "[object Object]";
|
|
630
|
+
}
|
|
631
|
+
function isUnsafeProperty(key) {
|
|
632
|
+
return key === "__proto__";
|
|
633
|
+
}
|
|
634
|
+
function pick(obj, keys) {
|
|
635
|
+
const result = {};
|
|
636
|
+
for (let i2 = 0; i2 < keys.length; i2++) {
|
|
637
|
+
const key = keys[i2];
|
|
638
|
+
if (Object.hasOwn(obj, key)) result[key] = obj[key];
|
|
639
|
+
}
|
|
640
|
+
return result;
|
|
641
|
+
}
|
|
642
|
+
function isEqualsSameValueZero(value, other) {
|
|
643
|
+
return value === other || Number.isNaN(value) && Number.isNaN(other);
|
|
644
|
+
}
|
|
645
|
+
function isEqualWith(a2, b2, areValuesEqual) {
|
|
646
|
+
return isEqualWithImpl(a2, b2, void 0, void 0, void 0, void 0, areValuesEqual);
|
|
647
|
+
}
|
|
648
|
+
function isEqualWithImpl(a2, b2, property, aParent, bParent, stack, areValuesEqual) {
|
|
649
|
+
const result = areValuesEqual(a2, b2, property, aParent, bParent, stack);
|
|
650
|
+
if (result !== void 0) return result;
|
|
651
|
+
if (typeof a2 === typeof b2) switch (typeof a2) {
|
|
652
|
+
case "bigint":
|
|
653
|
+
case "string":
|
|
654
|
+
case "boolean":
|
|
655
|
+
case "symbol":
|
|
656
|
+
case "undefined":
|
|
657
|
+
return a2 === b2;
|
|
658
|
+
case "number":
|
|
659
|
+
return a2 === b2 || Object.is(a2, b2);
|
|
660
|
+
case "function":
|
|
661
|
+
return a2 === b2;
|
|
662
|
+
case "object":
|
|
663
|
+
return areObjectsEqual(a2, b2, stack, areValuesEqual);
|
|
664
|
+
}
|
|
665
|
+
return areObjectsEqual(a2, b2, stack, areValuesEqual);
|
|
666
|
+
}
|
|
667
|
+
function areObjectsEqual(a2, b2, stack, areValuesEqual) {
|
|
668
|
+
if (Object.is(a2, b2)) return true;
|
|
669
|
+
let aTag = getTag(a2);
|
|
670
|
+
let bTag = getTag(b2);
|
|
671
|
+
if (aTag === "[object Arguments]") aTag = objectTag;
|
|
672
|
+
if (bTag === "[object Arguments]") bTag = objectTag;
|
|
673
|
+
if (aTag !== bTag) return false;
|
|
674
|
+
switch (aTag) {
|
|
675
|
+
case stringTag:
|
|
676
|
+
return a2.toString() === b2.toString();
|
|
677
|
+
case numberTag:
|
|
678
|
+
return isEqualsSameValueZero(a2.valueOf(), b2.valueOf());
|
|
679
|
+
case booleanTag:
|
|
680
|
+
case dateTag:
|
|
681
|
+
case symbolTag:
|
|
682
|
+
return Object.is(a2.valueOf(), b2.valueOf());
|
|
683
|
+
case regexpTag:
|
|
684
|
+
return a2.source === b2.source && a2.flags === b2.flags;
|
|
685
|
+
case functionTag:
|
|
686
|
+
return a2 === b2;
|
|
687
|
+
}
|
|
688
|
+
stack = stack ?? /* @__PURE__ */ new Map();
|
|
689
|
+
const aStack = stack.get(a2);
|
|
690
|
+
const bStack = stack.get(b2);
|
|
691
|
+
if (aStack != null && bStack != null) return aStack === b2;
|
|
692
|
+
stack.set(a2, b2);
|
|
693
|
+
stack.set(b2, a2);
|
|
694
|
+
try {
|
|
695
|
+
switch (aTag) {
|
|
696
|
+
case mapTag:
|
|
697
|
+
if (a2.size !== b2.size) return false;
|
|
698
|
+
for (const [key, value] of a2.entries()) if (!b2.has(key) || !isEqualWithImpl(value, b2.get(key), key, a2, b2, stack, areValuesEqual)) return false;
|
|
699
|
+
return true;
|
|
700
|
+
case setTag: {
|
|
701
|
+
if (a2.size !== b2.size) return false;
|
|
702
|
+
const aValues = Array.from(a2.values());
|
|
703
|
+
const bValues = Array.from(b2.values());
|
|
704
|
+
for (let i2 = 0; i2 < aValues.length; i2++) {
|
|
705
|
+
const aValue = aValues[i2];
|
|
706
|
+
const index = bValues.findIndex((bValue) => {
|
|
707
|
+
return isEqualWithImpl(aValue, bValue, void 0, a2, b2, stack, areValuesEqual);
|
|
708
|
+
});
|
|
709
|
+
if (index === -1) return false;
|
|
710
|
+
bValues.splice(index, 1);
|
|
711
|
+
}
|
|
712
|
+
return true;
|
|
713
|
+
}
|
|
714
|
+
case arrayTag:
|
|
715
|
+
case uint8ArrayTag:
|
|
716
|
+
case uint8ClampedArrayTag:
|
|
717
|
+
case uint16ArrayTag:
|
|
718
|
+
case uint32ArrayTag:
|
|
719
|
+
case bigUint64ArrayTag:
|
|
720
|
+
case int8ArrayTag:
|
|
721
|
+
case int16ArrayTag:
|
|
722
|
+
case int32ArrayTag:
|
|
723
|
+
case bigInt64ArrayTag:
|
|
724
|
+
case float32ArrayTag:
|
|
725
|
+
case float64ArrayTag:
|
|
726
|
+
if (isBuffer(a2) !== isBuffer(b2)) return false;
|
|
727
|
+
if (a2.length !== b2.length) return false;
|
|
728
|
+
for (let i2 = 0; i2 < a2.length; i2++) if (!isEqualWithImpl(a2[i2], b2[i2], i2, a2, b2, stack, areValuesEqual)) return false;
|
|
729
|
+
return true;
|
|
730
|
+
case arrayBufferTag:
|
|
731
|
+
if (a2.byteLength !== b2.byteLength) return false;
|
|
732
|
+
return areObjectsEqual(new Uint8Array(a2), new Uint8Array(b2), stack, areValuesEqual);
|
|
733
|
+
case dataViewTag:
|
|
734
|
+
if (a2.byteLength !== b2.byteLength || a2.byteOffset !== b2.byteOffset) return false;
|
|
735
|
+
return areObjectsEqual(new Uint8Array(a2), new Uint8Array(b2), stack, areValuesEqual);
|
|
736
|
+
case errorTag:
|
|
737
|
+
return a2.name === b2.name && a2.message === b2.message;
|
|
738
|
+
case objectTag: {
|
|
739
|
+
if (!(areObjectsEqual(a2.constructor, b2.constructor, stack, areValuesEqual) || isPlainObject(a2) && isPlainObject(b2))) return false;
|
|
740
|
+
const aKeys = [...Object.keys(a2), ...getSymbols(a2)];
|
|
741
|
+
const bKeys = [...Object.keys(b2), ...getSymbols(b2)];
|
|
742
|
+
if (aKeys.length !== bKeys.length) return false;
|
|
743
|
+
for (let i2 = 0; i2 < aKeys.length; i2++) {
|
|
744
|
+
const propKey = aKeys[i2];
|
|
745
|
+
const aProp = a2[propKey];
|
|
746
|
+
if (!Object.hasOwn(b2, propKey)) return false;
|
|
747
|
+
const bProp = b2[propKey];
|
|
748
|
+
if (!isEqualWithImpl(aProp, bProp, propKey, a2, b2, stack, areValuesEqual)) return false;
|
|
749
|
+
}
|
|
750
|
+
return true;
|
|
751
|
+
}
|
|
752
|
+
default:
|
|
753
|
+
return false;
|
|
754
|
+
}
|
|
755
|
+
} finally {
|
|
756
|
+
stack.delete(a2);
|
|
757
|
+
stack.delete(b2);
|
|
758
|
+
}
|
|
759
|
+
}
|
|
760
|
+
function isEqual(a2, b2) {
|
|
761
|
+
return isEqualWith(a2, b2, noop$1);
|
|
762
|
+
}
|
|
763
|
+
function createFieldSignal(options) {
|
|
764
|
+
const { value, initialValue, touched, pending } = options || {};
|
|
765
|
+
const valueSignal = createSignal(
|
|
766
|
+
value === void 0 ? void 0 : cloneDeep(value)
|
|
767
|
+
);
|
|
768
|
+
const initialSignal = createSignal(
|
|
769
|
+
initialValue === void 0 ? void 0 : cloneDeep(initialValue)
|
|
770
|
+
);
|
|
771
|
+
const touchedSignal = createSignal(touched ?? false);
|
|
772
|
+
const pendingSignal = createSignal(pending ?? false);
|
|
773
|
+
const pendingMessageSignal = createSignal([]);
|
|
774
|
+
const setValue = (next) => {
|
|
775
|
+
valueSignal.value = next;
|
|
776
|
+
};
|
|
777
|
+
const setInitialValue = (next) => {
|
|
778
|
+
initialSignal.value = next;
|
|
779
|
+
};
|
|
780
|
+
const setTouched = (next) => {
|
|
781
|
+
touchedSignal.value = next;
|
|
782
|
+
};
|
|
783
|
+
const setPending = (next, message) => {
|
|
784
|
+
pendingSignal.value = next;
|
|
785
|
+
if (next) {
|
|
786
|
+
if (message) {
|
|
787
|
+
pendingMessageSignal.value = Array.isArray(message) ? message : [message];
|
|
788
|
+
}
|
|
789
|
+
} else {
|
|
790
|
+
pendingMessageSignal.value = [];
|
|
791
|
+
}
|
|
792
|
+
};
|
|
793
|
+
const reset = (next = initialSignal.peek()) => {
|
|
794
|
+
valueSignal.value = cloneDeep(next);
|
|
795
|
+
touchedSignal.value = false;
|
|
796
|
+
pendingSignal.value = false;
|
|
797
|
+
};
|
|
798
|
+
const peek = () => {
|
|
799
|
+
return {
|
|
800
|
+
value: valueSignal.peek(),
|
|
801
|
+
initialValue: initialSignal.peek(),
|
|
802
|
+
touched: touchedSignal.peek(),
|
|
803
|
+
pending: pendingSignal.peek(),
|
|
804
|
+
pendingMessage: pendingMessageSignal.peek()
|
|
805
|
+
};
|
|
806
|
+
};
|
|
807
|
+
return {
|
|
808
|
+
value: valueSignal,
|
|
809
|
+
initialValue: initialSignal,
|
|
810
|
+
touched: touchedSignal,
|
|
811
|
+
pending: pendingSignal,
|
|
812
|
+
pendingMessage: pendingMessageSignal,
|
|
813
|
+
setValue,
|
|
814
|
+
setInitialValue,
|
|
815
|
+
setTouched,
|
|
816
|
+
setPending,
|
|
817
|
+
reset,
|
|
818
|
+
peek
|
|
819
|
+
};
|
|
820
|
+
}
|
|
821
|
+
class FieldSignalMapImpl {
|
|
822
|
+
constructor(options = {}) {
|
|
823
|
+
__publicField(this, "records", /* @__PURE__ */ new Map());
|
|
824
|
+
__publicField(this, "version", createSignal(0));
|
|
825
|
+
__publicField(this, "normalizeKey");
|
|
826
|
+
this.normalizeKey = options.normalizeKey ?? defaultNormalizeFieldKey;
|
|
827
|
+
}
|
|
828
|
+
/**
|
|
829
|
+
* 获取字段 key 的标准化字符串。
|
|
830
|
+
*/
|
|
831
|
+
getKey(key) {
|
|
832
|
+
return this.normalizeKey(key);
|
|
833
|
+
}
|
|
834
|
+
/**
|
|
835
|
+
* 获取字段 signal。
|
|
836
|
+
*
|
|
837
|
+
* 读取缺失 key 时会订阅结构版本;后续 set 同 key 会触发 effect 重跑。
|
|
838
|
+
*
|
|
839
|
+
* @param key - 字段路径。
|
|
840
|
+
* @returns 字段 signal;未创建时返回 undefined。
|
|
841
|
+
*/
|
|
842
|
+
get(key) {
|
|
843
|
+
const record = this.records.get(this.getKey(key));
|
|
844
|
+
if (record) {
|
|
845
|
+
return record.value;
|
|
846
|
+
}
|
|
847
|
+
void this.version.value;
|
|
848
|
+
return void 0;
|
|
849
|
+
}
|
|
850
|
+
/**
|
|
851
|
+
* 无依赖追踪地获取字段 signal。
|
|
852
|
+
*
|
|
853
|
+
* @param key - 字段路径。
|
|
854
|
+
* @returns 字段 signal;未创建时返回 undefined。
|
|
855
|
+
*/
|
|
856
|
+
peek(key) {
|
|
857
|
+
var _a;
|
|
858
|
+
return (_a = this.records.get(this.getKey(key))) == null ? void 0 : _a.value;
|
|
859
|
+
}
|
|
860
|
+
/**
|
|
861
|
+
* 设置字段 signal。
|
|
862
|
+
*
|
|
863
|
+
* @param key - 字段路径。
|
|
864
|
+
* @param value - 字段 signal。
|
|
865
|
+
* @returns 当前映射实例,便于链式调用。
|
|
866
|
+
*/
|
|
867
|
+
set(key, value) {
|
|
868
|
+
const normalizedKey = this.getKey(key);
|
|
869
|
+
const exists = this.records.has(normalizedKey);
|
|
870
|
+
this.records.set(normalizedKey, { key, value });
|
|
871
|
+
if (!exists) {
|
|
872
|
+
this.version.value++;
|
|
873
|
+
}
|
|
874
|
+
return this;
|
|
875
|
+
}
|
|
876
|
+
/**
|
|
877
|
+
* 判断字段是否存在。
|
|
878
|
+
*
|
|
879
|
+
* @param key - 字段路径。
|
|
880
|
+
* @returns 字段 signal 是否已存在。
|
|
881
|
+
*/
|
|
882
|
+
has(key) {
|
|
883
|
+
return this.records.has(this.getKey(key));
|
|
884
|
+
}
|
|
885
|
+
/**
|
|
886
|
+
* 删除字段 signal。
|
|
887
|
+
*
|
|
888
|
+
* @param key - 字段路径。
|
|
889
|
+
* @returns 是否删除了已存在的字段 signal。
|
|
890
|
+
*/
|
|
891
|
+
delete(key) {
|
|
892
|
+
const normalizedKey = this.getKey(key);
|
|
893
|
+
const record = this.records.get(normalizedKey);
|
|
894
|
+
if (!record) return false;
|
|
895
|
+
this.records.delete(normalizedKey);
|
|
896
|
+
disposeSignal(record.value);
|
|
897
|
+
this.version.value++;
|
|
898
|
+
return true;
|
|
899
|
+
}
|
|
900
|
+
/**
|
|
901
|
+
* 清空所有字段 signal。
|
|
902
|
+
*/
|
|
903
|
+
clear() {
|
|
904
|
+
if (this.records.size === 0) return;
|
|
905
|
+
for (const record of this.records.values()) {
|
|
906
|
+
disposeSignal(record.value);
|
|
907
|
+
}
|
|
908
|
+
this.records.clear();
|
|
909
|
+
this.version.value++;
|
|
910
|
+
}
|
|
911
|
+
/**
|
|
912
|
+
* 响应式遍历原始字段 key。
|
|
913
|
+
*
|
|
914
|
+
* @returns 原始字段 key 的迭代器。
|
|
915
|
+
*/
|
|
916
|
+
keys() {
|
|
917
|
+
void this.version.value;
|
|
918
|
+
return Array.from(this.records.values(), (record) => record.key).values();
|
|
919
|
+
}
|
|
920
|
+
/**
|
|
921
|
+
* 响应式遍历字段 signal。
|
|
922
|
+
*
|
|
923
|
+
* @returns 字段 signal 的迭代器。
|
|
924
|
+
*/
|
|
925
|
+
values() {
|
|
926
|
+
void this.version.value;
|
|
927
|
+
return Array.from(this.records.values(), (record) => record.value).values();
|
|
928
|
+
}
|
|
929
|
+
/**
|
|
930
|
+
* 响应式遍历 `[key, signal]`。
|
|
931
|
+
*
|
|
932
|
+
* @returns 原始字段 key 与字段 signal 的迭代器。
|
|
933
|
+
*/
|
|
934
|
+
entries() {
|
|
935
|
+
void this.version.value;
|
|
936
|
+
return Array.from(
|
|
937
|
+
this.records.values(),
|
|
938
|
+
(record) => [record.key, record.value]
|
|
939
|
+
).values();
|
|
940
|
+
}
|
|
941
|
+
}
|
|
942
|
+
function createFieldSignalMap(options = {}) {
|
|
943
|
+
return new FieldSignalMapImpl(options);
|
|
944
|
+
}
|
|
945
|
+
function disposeSignal(signal) {
|
|
946
|
+
signal.value.value = void 0;
|
|
947
|
+
signal.initialValue.value = void 0;
|
|
948
|
+
signal.touched.value = false;
|
|
949
|
+
signal.pending.value = false;
|
|
950
|
+
}
|
|
951
|
+
function defaultNormalizeFieldKey(key) {
|
|
952
|
+
if (Array.isArray(key)) {
|
|
953
|
+
return key.map((part) => String(part)).join(".");
|
|
954
|
+
}
|
|
955
|
+
return String(key);
|
|
956
|
+
}
|
|
957
|
+
function createSignalEffect(fn) {
|
|
958
|
+
return j(fn);
|
|
959
|
+
}
|
|
960
|
+
function createDebouncedSignalEffect(collect, run, wait = 16, options = {}) {
|
|
961
|
+
const debouncedRun = debounce(run, wait, { edges: options.edges });
|
|
962
|
+
let initialized = false;
|
|
963
|
+
const disposeEffect = createSignalEffect(() => {
|
|
964
|
+
const value = collect();
|
|
965
|
+
if (!initialized && options.immediate) {
|
|
966
|
+
initialized = true;
|
|
967
|
+
run(value);
|
|
968
|
+
return;
|
|
969
|
+
}
|
|
970
|
+
initialized = true;
|
|
971
|
+
debouncedRun(value);
|
|
972
|
+
});
|
|
973
|
+
return () => {
|
|
974
|
+
disposeEffect();
|
|
975
|
+
debouncedRun.cancel();
|
|
976
|
+
};
|
|
977
|
+
}
|
|
978
|
+
function batchUpdates(fn) {
|
|
979
|
+
n(fn);
|
|
980
|
+
}
|
|
981
|
+
class SignalMapImpl {
|
|
982
|
+
constructor() {
|
|
983
|
+
__publicField(this, "signals", /* @__PURE__ */ new Map());
|
|
984
|
+
__publicField(this, "version", createSignal(0));
|
|
985
|
+
}
|
|
986
|
+
/**
|
|
987
|
+
* 读取 key,并在 effect 内自动收集响应式依赖。
|
|
988
|
+
*
|
|
989
|
+
* @param key - 待读取的 key。
|
|
990
|
+
* @returns key 对应的值;不存在时返回 undefined。
|
|
991
|
+
*/
|
|
992
|
+
get(key) {
|
|
993
|
+
const s2 = this.signals.get(key);
|
|
994
|
+
if (s2) return s2.value;
|
|
995
|
+
void this.version.value;
|
|
996
|
+
return void 0;
|
|
997
|
+
}
|
|
998
|
+
/**
|
|
999
|
+
* 写入 key;如果 key 不存在,则创建新的 signal。
|
|
1000
|
+
*
|
|
1001
|
+
* @param key - 待写入的 key。
|
|
1002
|
+
* @param value - 新值。
|
|
1003
|
+
* @returns 当前 SignalMap 实例,便于链式调用。
|
|
1004
|
+
*/
|
|
1005
|
+
set(key, value) {
|
|
1006
|
+
const s2 = this.signals.get(key);
|
|
1007
|
+
if (s2) {
|
|
1008
|
+
s2.value = value;
|
|
1009
|
+
} else {
|
|
1010
|
+
this.signals.set(key, createSignal(value));
|
|
1011
|
+
this.version.value++;
|
|
1012
|
+
}
|
|
1013
|
+
return this;
|
|
1014
|
+
}
|
|
1015
|
+
/**
|
|
1016
|
+
* 无依赖追踪地读取 key。
|
|
1017
|
+
*
|
|
1018
|
+
* @param key - 待读取的 key。
|
|
1019
|
+
* @returns key 对应的值;不存在时返回 undefined。
|
|
1020
|
+
*/
|
|
1021
|
+
peek(key) {
|
|
1022
|
+
var _a;
|
|
1023
|
+
return (_a = this.signals.get(key)) == null ? void 0 : _a.peek();
|
|
1024
|
+
}
|
|
1025
|
+
/**
|
|
1026
|
+
* 判断 key 是否存在。
|
|
1027
|
+
*
|
|
1028
|
+
* @param key - 待检查的 key。
|
|
1029
|
+
* @returns key 已存在时返回 true。
|
|
1030
|
+
*/
|
|
1031
|
+
has(key) {
|
|
1032
|
+
return this.signals.has(key);
|
|
1033
|
+
}
|
|
1034
|
+
/**
|
|
1035
|
+
* 删除 key,并通知订阅旧 signal 或 map 结构的 effects。
|
|
1036
|
+
*
|
|
1037
|
+
* @param key - 待删除的 key。
|
|
1038
|
+
* @returns 成功删除时返回 true;key 不存在时返回 false。
|
|
1039
|
+
*/
|
|
1040
|
+
delete(key) {
|
|
1041
|
+
const s2 = this.signals.get(key);
|
|
1042
|
+
if (!s2) return false;
|
|
1043
|
+
this.signals.delete(key);
|
|
1044
|
+
batchUpdates(() => {
|
|
1045
|
+
s2.value = void 0;
|
|
1046
|
+
this.version.value++;
|
|
1047
|
+
});
|
|
1048
|
+
return true;
|
|
1049
|
+
}
|
|
1050
|
+
/**
|
|
1051
|
+
* 清空所有 key,并通知订阅任意被删除 signal 的 effects。
|
|
1052
|
+
*/
|
|
1053
|
+
clear() {
|
|
1054
|
+
if (this.signals.size === 0) return;
|
|
1055
|
+
const oldSignals = [...this.signals.values()];
|
|
1056
|
+
this.signals.clear();
|
|
1057
|
+
batchUpdates(() => {
|
|
1058
|
+
for (const s2 of oldSignals) {
|
|
1059
|
+
s2.value = void 0;
|
|
1060
|
+
}
|
|
1061
|
+
this.version.value++;
|
|
1062
|
+
});
|
|
1063
|
+
}
|
|
1064
|
+
/**
|
|
1065
|
+
* 遍历所有已注册 key。
|
|
1066
|
+
*
|
|
1067
|
+
* @returns key 迭代器。
|
|
1068
|
+
*/
|
|
1069
|
+
keys() {
|
|
1070
|
+
void this.version.value;
|
|
1071
|
+
return this.signals.keys();
|
|
1072
|
+
}
|
|
1073
|
+
/**
|
|
1074
|
+
* 遍历所有值。
|
|
1075
|
+
*
|
|
1076
|
+
* @returns value 迭代器。
|
|
1077
|
+
*/
|
|
1078
|
+
values() {
|
|
1079
|
+
void this.version.value;
|
|
1080
|
+
return Array.from(this.signals.values(), (signal) => signal.value).values();
|
|
1081
|
+
}
|
|
1082
|
+
/**
|
|
1083
|
+
* 遍历 key/value 对。
|
|
1084
|
+
*
|
|
1085
|
+
* @returns key/value entry 迭代器。
|
|
1086
|
+
*/
|
|
1087
|
+
entries() {
|
|
1088
|
+
void this.version.value;
|
|
1089
|
+
return Array.from(
|
|
1090
|
+
this.signals.entries(),
|
|
1091
|
+
([key, signal]) => [key, signal.value]
|
|
1092
|
+
).values();
|
|
1093
|
+
}
|
|
1094
|
+
}
|
|
1095
|
+
function createSignalMap() {
|
|
1096
|
+
return new SignalMapImpl();
|
|
1097
|
+
}
|
|
1098
|
+
function isBaseSchema(schema) {
|
|
1099
|
+
return !isGroupSchema(schema) && !isDependencySchema(schema);
|
|
1100
|
+
}
|
|
1101
|
+
function isGroupSchema(schema) {
|
|
1102
|
+
return schema.componentType === "group";
|
|
1103
|
+
}
|
|
1104
|
+
function isDependencySchema(schema) {
|
|
1105
|
+
return schema.componentType === "dependency";
|
|
1106
|
+
}
|
|
1107
|
+
function isBaseResolvedSchema(schema) {
|
|
1108
|
+
return !isGroupResolvedSchema(schema) && !isDependencyResolvedSchema(schema);
|
|
1109
|
+
}
|
|
1110
|
+
function isGroupResolvedSchema(schema) {
|
|
1111
|
+
return schema.componentType === "group";
|
|
1112
|
+
}
|
|
1113
|
+
function isDependencyResolvedSchema(schema) {
|
|
1114
|
+
return schema.componentType === "dependency";
|
|
1115
|
+
}
|
|
1116
|
+
const isLegalName = (schema) => Object.hasOwn(schema, "name") && [null, void 0, ""].every((i2) => i2 !== schema.name);
|
|
1117
|
+
const isLegalComponentType = (schema) => Object.hasOwn(schema, "componentType") && typeof schema.componentType === "string";
|
|
1118
|
+
function getBaseFieldMissing(schema) {
|
|
1119
|
+
const missing = [];
|
|
1120
|
+
if (!isLegalName(schema)) missing.push("name");
|
|
1121
|
+
if (!isLegalComponentType(schema)) missing.push("componentType");
|
|
1122
|
+
return missing;
|
|
1123
|
+
}
|
|
1124
|
+
function getGroupFieldMissing(schema) {
|
|
1125
|
+
const missing = [];
|
|
1126
|
+
if (!isLegalComponentType(schema)) missing.push("componentType");
|
|
1127
|
+
if (!Object.hasOwn(schema, "children") || !Array.isArray(schema.children))
|
|
1128
|
+
missing.push("children");
|
|
1129
|
+
return missing;
|
|
1130
|
+
}
|
|
1131
|
+
function getDependencyFieldMissing(schema) {
|
|
1132
|
+
const missing = [];
|
|
1133
|
+
if (!isLegalComponentType(schema)) missing.push("componentType");
|
|
1134
|
+
if (!Object.hasOwn(schema, "to") || !Array.isArray(schema.to)) missing.push("to");
|
|
1135
|
+
if (typeof schema.renderer !== "function") missing.push("renderer");
|
|
1136
|
+
return missing;
|
|
1137
|
+
}
|
|
1138
|
+
function buildWarnMessage(index, schema, missing) {
|
|
1139
|
+
const identifier = "name" in schema && schema.name || schema.componentType || "unknown";
|
|
1140
|
+
return `[schemx] schemas[${index}] (${String(identifier)}) 缺少必填项: ${missing.join(", ")},已被过滤`;
|
|
1141
|
+
}
|
|
1142
|
+
function normalizeSchemas(schemas) {
|
|
1143
|
+
const result = [];
|
|
1144
|
+
const missings = [];
|
|
1145
|
+
for (let i2 = 0; i2 < schemas.length; i2++) {
|
|
1146
|
+
const schema = schemas[i2];
|
|
1147
|
+
let missing = [];
|
|
1148
|
+
if (isGroupSchema(schema)) {
|
|
1149
|
+
missing = getGroupFieldMissing(schema);
|
|
1150
|
+
if (missing.length > 0) {
|
|
1151
|
+
missings.push(buildWarnMessage(i2, schema, missing));
|
|
1152
|
+
continue;
|
|
1153
|
+
}
|
|
1154
|
+
result.push({
|
|
1155
|
+
...schema,
|
|
1156
|
+
children: normalizeSchemas(schema.children)
|
|
1157
|
+
});
|
|
1158
|
+
} else if (isDependencySchema(schema)) {
|
|
1159
|
+
missing = getDependencyFieldMissing(schema);
|
|
1160
|
+
if (missing.length > 0) {
|
|
1161
|
+
missings.push(buildWarnMessage(i2, schema, missing));
|
|
1162
|
+
continue;
|
|
1163
|
+
}
|
|
1164
|
+
result.push(schema);
|
|
1165
|
+
} else if (isBaseSchema(schema)) {
|
|
1166
|
+
missing = getBaseFieldMissing(schema);
|
|
1167
|
+
if (missing.length > 0) {
|
|
1168
|
+
missings.push(buildWarnMessage(i2, schema, missing));
|
|
1169
|
+
continue;
|
|
1170
|
+
}
|
|
1171
|
+
result.push(schema);
|
|
1172
|
+
}
|
|
1173
|
+
}
|
|
1174
|
+
if (missings.length) console.warn(missings.join("\n"));
|
|
1175
|
+
return result;
|
|
1176
|
+
}
|
|
1177
|
+
function toString(value) {
|
|
1178
|
+
if (value == null) return "";
|
|
1179
|
+
if (typeof value === "string") return value;
|
|
1180
|
+
if (Array.isArray(value)) return value.map(toString).join(",");
|
|
1181
|
+
const result = String(value);
|
|
1182
|
+
if (result === "0" && Object.is(Number(value), -0)) return "-0";
|
|
1183
|
+
return result;
|
|
1184
|
+
}
|
|
1185
|
+
function toKey(value) {
|
|
1186
|
+
var _a;
|
|
1187
|
+
if (typeof value === "string" || typeof value === "symbol") return value;
|
|
1188
|
+
if (Object.is((_a = value == null ? void 0 : value.valueOf) == null ? void 0 : _a.call(value), -0)) return "-0";
|
|
1189
|
+
return String(value);
|
|
1190
|
+
}
|
|
1191
|
+
function toPath(deepKey) {
|
|
1192
|
+
if (Array.isArray(deepKey)) return deepKey.map(toKey);
|
|
1193
|
+
if (typeof deepKey === "symbol") return [deepKey];
|
|
1194
|
+
deepKey = toString(deepKey);
|
|
1195
|
+
const result = [];
|
|
1196
|
+
const length = deepKey.length;
|
|
1197
|
+
if (length === 0) return result;
|
|
1198
|
+
let index = 0;
|
|
1199
|
+
let key = "";
|
|
1200
|
+
let quoteChar = "";
|
|
1201
|
+
let bracket = false;
|
|
1202
|
+
if (deepKey.charCodeAt(0) === 46) {
|
|
1203
|
+
result.push("");
|
|
1204
|
+
index++;
|
|
1205
|
+
}
|
|
1206
|
+
while (index < length) {
|
|
1207
|
+
const char = deepKey[index];
|
|
1208
|
+
if (quoteChar) if (char === "\\" && index + 1 < length) {
|
|
1209
|
+
index++;
|
|
1210
|
+
key += deepKey[index];
|
|
1211
|
+
} else if (char === quoteChar) quoteChar = "";
|
|
1212
|
+
else key += char;
|
|
1213
|
+
else if (bracket) if (char === '"' || char === "'") quoteChar = char;
|
|
1214
|
+
else if (char === "]") {
|
|
1215
|
+
bracket = false;
|
|
1216
|
+
result.push(key);
|
|
1217
|
+
key = "";
|
|
1218
|
+
} else key += char;
|
|
1219
|
+
else if (char === "[") {
|
|
1220
|
+
bracket = true;
|
|
1221
|
+
if (key) {
|
|
1222
|
+
result.push(key);
|
|
1223
|
+
key = "";
|
|
1224
|
+
}
|
|
1225
|
+
} else if (char === ".") {
|
|
1226
|
+
if (key) {
|
|
1227
|
+
result.push(key);
|
|
1228
|
+
key = "";
|
|
1229
|
+
}
|
|
1230
|
+
} else key += char;
|
|
1231
|
+
index++;
|
|
1232
|
+
}
|
|
1233
|
+
if (key) result.push(key);
|
|
1234
|
+
return result;
|
|
1235
|
+
}
|
|
1236
|
+
function isDeepKey(key) {
|
|
1237
|
+
switch (typeof key) {
|
|
1238
|
+
case "number":
|
|
1239
|
+
case "symbol":
|
|
1240
|
+
return false;
|
|
1241
|
+
case "string":
|
|
1242
|
+
return key.includes(".") || key.includes("[") || key.includes("]");
|
|
1243
|
+
}
|
|
1244
|
+
}
|
|
1245
|
+
function get(object, path, defaultValue) {
|
|
1246
|
+
if (object == null) return defaultValue;
|
|
1247
|
+
switch (typeof path) {
|
|
1248
|
+
case "string": {
|
|
1249
|
+
if (isUnsafeProperty(path)) return defaultValue;
|
|
1250
|
+
const result = object[path];
|
|
1251
|
+
if (result === void 0) if (isDeepKey(path)) return get(object, toPath(path), defaultValue);
|
|
1252
|
+
else return defaultValue;
|
|
1253
|
+
return result;
|
|
1254
|
+
}
|
|
1255
|
+
case "number":
|
|
1256
|
+
case "symbol": {
|
|
1257
|
+
if (typeof path === "number") path = toKey(path);
|
|
1258
|
+
const result = object[path];
|
|
1259
|
+
if (result === void 0) return defaultValue;
|
|
1260
|
+
return result;
|
|
1261
|
+
}
|
|
1262
|
+
default: {
|
|
1263
|
+
if (Array.isArray(path)) return getWithPath(object, path, defaultValue);
|
|
1264
|
+
if (Object.is(path == null ? void 0 : path.valueOf(), -0)) path = "-0";
|
|
1265
|
+
else path = String(path);
|
|
1266
|
+
if (isUnsafeProperty(path)) return defaultValue;
|
|
1267
|
+
const result = object[path];
|
|
1268
|
+
if (result === void 0) return defaultValue;
|
|
1269
|
+
return result;
|
|
1270
|
+
}
|
|
1271
|
+
}
|
|
1272
|
+
}
|
|
1273
|
+
function getWithPath(object, path, defaultValue) {
|
|
1274
|
+
if (path.length === 0) return defaultValue;
|
|
1275
|
+
let current = object;
|
|
1276
|
+
for (let index = 0; index < path.length; index++) {
|
|
1277
|
+
if (current == null) return defaultValue;
|
|
1278
|
+
if (isUnsafeProperty(path[index])) return defaultValue;
|
|
1279
|
+
current = current[path[index]];
|
|
1280
|
+
}
|
|
1281
|
+
if (current === void 0) return defaultValue;
|
|
1282
|
+
return current;
|
|
1283
|
+
}
|
|
1284
|
+
function isObject(value) {
|
|
1285
|
+
return value !== null && (typeof value === "object" || typeof value === "function");
|
|
1286
|
+
}
|
|
1287
|
+
const IS_UNSIGNED_INTEGER = /^(?:0|[1-9]\d*)$/;
|
|
1288
|
+
function isIndex(value, length = Number.MAX_SAFE_INTEGER) {
|
|
1289
|
+
switch (typeof value) {
|
|
1290
|
+
case "number":
|
|
1291
|
+
return Number.isInteger(value) && value >= 0 && value < length;
|
|
1292
|
+
case "symbol":
|
|
1293
|
+
return false;
|
|
1294
|
+
case "string":
|
|
1295
|
+
return IS_UNSIGNED_INTEGER.test(value);
|
|
1296
|
+
}
|
|
1297
|
+
}
|
|
1298
|
+
const regexIsDeepProp = /\.|\[(?:[^[\]]*|(["'])(?:(?!\1)[^\\]|\\.)*?\1)\]/;
|
|
1299
|
+
const regexIsPlainProp = /^\w*$/;
|
|
1300
|
+
function isKey(value, object) {
|
|
1301
|
+
if (Array.isArray(value)) return false;
|
|
1302
|
+
if (typeof value === "number" || typeof value === "boolean" || value == null || isSymbol(value)) return true;
|
|
1303
|
+
return typeof value === "string" && (regexIsPlainProp.test(value) || !regexIsDeepProp.test(value)) || object != null && Object.hasOwn(object, value);
|
|
1304
|
+
}
|
|
1305
|
+
const assignValue = (object, key, value) => {
|
|
1306
|
+
const objValue = object[key];
|
|
1307
|
+
if (!(Object.hasOwn(object, key) && isEqualsSameValueZero(objValue, value)) || value === void 0 && !(key in object)) object[key] = value;
|
|
1308
|
+
};
|
|
1309
|
+
function updateWith(obj, path, updater, customizer) {
|
|
1310
|
+
if (obj == null && !isObject(obj)) return obj;
|
|
1311
|
+
let resolvedPath;
|
|
1312
|
+
if (isKey(path, obj)) resolvedPath = [path];
|
|
1313
|
+
else if (Array.isArray(path)) resolvedPath = path;
|
|
1314
|
+
else resolvedPath = toPath(path);
|
|
1315
|
+
const updateValue = updater(get(obj, resolvedPath));
|
|
1316
|
+
let current = obj;
|
|
1317
|
+
for (let i2 = 0; i2 < resolvedPath.length && current != null; i2++) {
|
|
1318
|
+
const key = toKey(resolvedPath[i2]);
|
|
1319
|
+
if (isUnsafeProperty(key)) continue;
|
|
1320
|
+
let newValue;
|
|
1321
|
+
if (i2 === resolvedPath.length - 1) newValue = updateValue;
|
|
1322
|
+
else {
|
|
1323
|
+
const objValue = current[key];
|
|
1324
|
+
const customizerResult = customizer == null ? void 0 : customizer(objValue, key, obj);
|
|
1325
|
+
newValue = customizerResult !== void 0 ? customizerResult : isObject(objValue) ? objValue : isIndex(resolvedPath[i2 + 1]) ? [] : {};
|
|
1326
|
+
}
|
|
1327
|
+
assignValue(current, key, newValue);
|
|
1328
|
+
current = current[key];
|
|
1329
|
+
}
|
|
1330
|
+
return obj;
|
|
1331
|
+
}
|
|
1332
|
+
function set(obj, path, value) {
|
|
1333
|
+
return updateWith(obj, path, () => value, () => void 0);
|
|
1334
|
+
}
|
|
1335
|
+
function getByPath(obj, path) {
|
|
1336
|
+
if (path === "" || Array.isArray(path) && path.length === 0) {
|
|
1337
|
+
return obj;
|
|
1338
|
+
}
|
|
1339
|
+
return get(obj, normalizeRuntimePath(path));
|
|
1340
|
+
}
|
|
1341
|
+
function setByPath(obj, path, value) {
|
|
1342
|
+
if (obj == null) return;
|
|
1343
|
+
set(obj, normalizeRuntimePath(path), value);
|
|
1344
|
+
}
|
|
1345
|
+
function collectObjectPathsByLeaf(obj, prefix = "") {
|
|
1346
|
+
const paths = [];
|
|
1347
|
+
for (const key of Object.keys(obj)) {
|
|
1348
|
+
const path = prefix ? `${prefix}.${key}` : key;
|
|
1349
|
+
const value = obj[key];
|
|
1350
|
+
if (Array.isArray(value)) {
|
|
1351
|
+
value.forEach((item, index) => {
|
|
1352
|
+
const itemPath = `${path}[${index}]`;
|
|
1353
|
+
if (item !== null && typeof item === "object") {
|
|
1354
|
+
paths.push(...collectObjectPathsByLeaf(item, itemPath));
|
|
1355
|
+
} else {
|
|
1356
|
+
paths.push(itemPath);
|
|
1357
|
+
}
|
|
1358
|
+
});
|
|
1359
|
+
} else if (value !== null && typeof value === "object") {
|
|
1360
|
+
paths.push(...collectObjectPathsByLeaf(value, path));
|
|
1361
|
+
} else {
|
|
1362
|
+
paths.push(path);
|
|
1363
|
+
}
|
|
1364
|
+
}
|
|
1365
|
+
return paths;
|
|
1366
|
+
}
|
|
1367
|
+
const normalizeRuntimePath = (path) => {
|
|
1368
|
+
if (Array.isArray(path)) {
|
|
1369
|
+
return path.map((part) => typeof part === "number" ? part : String(part));
|
|
1370
|
+
}
|
|
1371
|
+
return path;
|
|
1372
|
+
};
|
|
1373
|
+
function withLock(fn) {
|
|
1374
|
+
let pending = null;
|
|
1375
|
+
return (...args) => {
|
|
1376
|
+
if (pending) return pending;
|
|
1377
|
+
pending = fn(...args).finally(() => {
|
|
1378
|
+
pending = null;
|
|
1379
|
+
});
|
|
1380
|
+
return pending;
|
|
1381
|
+
};
|
|
1382
|
+
}
|
|
1383
|
+
function diff(current, prev) {
|
|
1384
|
+
const changedValues = {};
|
|
1385
|
+
for (const key of Object.keys(current)) {
|
|
1386
|
+
if (!isEqual(current[key], prev[key])) {
|
|
1387
|
+
changedValues[key] = current[key];
|
|
1388
|
+
}
|
|
1389
|
+
}
|
|
1390
|
+
return changedValues;
|
|
1391
|
+
}
|
|
1392
|
+
const defaultConfig = {
|
|
1393
|
+
/**
|
|
1394
|
+
* 是否展示必填的 * 号(静态默认值)
|
|
1395
|
+
*
|
|
1396
|
+
* 控制必填标记(红色星号)的显示。
|
|
1397
|
+
* 若未设置,会根据 `rules` 中的校验规则自动推断。
|
|
1398
|
+
*/
|
|
1399
|
+
required: false,
|
|
1400
|
+
/**
|
|
1401
|
+
* 是否只读(静态默认值)
|
|
1402
|
+
*
|
|
1403
|
+
* 未设置时继承 FormContext 的全局 `readonly` 配置。
|
|
1404
|
+
*/
|
|
1405
|
+
readonly: false,
|
|
1406
|
+
/**
|
|
1407
|
+
* 是否禁用(静态默认值)
|
|
1408
|
+
*
|
|
1409
|
+
* 未设置时继承 FormContext 的全局 `disabled` 配置。
|
|
1410
|
+
*/
|
|
1411
|
+
disabled: false,
|
|
1412
|
+
/**
|
|
1413
|
+
* 是否可见(静态默认值)
|
|
1414
|
+
*
|
|
1415
|
+
* 不可见时字段不渲染,同时会清除校验规则和错误信息。
|
|
1416
|
+
*/
|
|
1417
|
+
visible: true,
|
|
1418
|
+
/**
|
|
1419
|
+
* 标签图标
|
|
1420
|
+
*
|
|
1421
|
+
* 显示在 label 文本旁的图标标识。
|
|
1422
|
+
*/
|
|
1423
|
+
labelIcon: "",
|
|
1424
|
+
/**
|
|
1425
|
+
* 标签对齐方式
|
|
1426
|
+
*
|
|
1427
|
+
* 未设置时继承 FormContext 的全局 `labelAlign` 配置。
|
|
1428
|
+
*/
|
|
1429
|
+
labelAlign: "left",
|
|
1430
|
+
/**
|
|
1431
|
+
* 标签位置
|
|
1432
|
+
*
|
|
1433
|
+
* 未设置时继承 FormContext 的全局 `labelPosition` 配置。
|
|
1434
|
+
*/
|
|
1435
|
+
labelPosition: "left",
|
|
1436
|
+
/**
|
|
1437
|
+
* 标签宽度
|
|
1438
|
+
*
|
|
1439
|
+
* 未设置时继承 FormContext 的全局 `labelWidth` 配置。
|
|
1440
|
+
*/
|
|
1441
|
+
labelWidth: "auto",
|
|
1442
|
+
/**
|
|
1443
|
+
* 校验触发时机
|
|
1444
|
+
*
|
|
1445
|
+
* 支持单个或多个触发时机组合,如 `'change'`、`'blur'`、`['change', 'blur']`。
|
|
1446
|
+
* 未设置时继承 FormContext 的全局 `validationTrigger` 配置。
|
|
1447
|
+
*/
|
|
1448
|
+
validationTrigger: "blur",
|
|
1449
|
+
/**
|
|
1450
|
+
* 是否在标签后显示冒号
|
|
1451
|
+
*
|
|
1452
|
+
* 未设置时继承 FormContext 的全局 `colon` 配置。
|
|
1453
|
+
*/
|
|
1454
|
+
colon: true
|
|
1455
|
+
};
|
|
1456
|
+
const defaultConfigKey = Object.keys(defaultConfig);
|
|
1457
|
+
class ValidatorImpl {
|
|
1458
|
+
constructor() {
|
|
1459
|
+
__publicField(this, "rules", /* @__PURE__ */ new Map());
|
|
1460
|
+
__publicField(this, "errors", createSignalMap());
|
|
1461
|
+
}
|
|
1462
|
+
/**
|
|
1463
|
+
* 注册单个字段的校验规则。
|
|
1464
|
+
*
|
|
1465
|
+
* 支持传入单个 schema 或 schema 数组,多次调用会追加规则而非覆盖。
|
|
1466
|
+
*
|
|
1467
|
+
* @param path - 字段路径
|
|
1468
|
+
* @param rules - 单个或多个 StandardSchemaV1 校验 schema
|
|
1469
|
+
* @param defaultMessage - 可选,空值(undefined/null)时的默认错误提示
|
|
1470
|
+
*
|
|
1471
|
+
* @example
|
|
1472
|
+
* ```typescript
|
|
1473
|
+
* validator.register('email', emailSchema)
|
|
1474
|
+
* validator.register('name', [minLenSchema, maxLenSchema], '请输入姓名')
|
|
1475
|
+
* ```
|
|
1476
|
+
*/
|
|
1477
|
+
register(path, rules, defaultMessage) {
|
|
1478
|
+
const schemas = Array.isArray(rules) ? rules : [rules];
|
|
1479
|
+
const existing = this.rules.get(path);
|
|
1480
|
+
if (existing) {
|
|
1481
|
+
existing.schemas.push(...schemas);
|
|
1482
|
+
if (defaultMessage) {
|
|
1483
|
+
existing.defaultMessage = defaultMessage;
|
|
1484
|
+
}
|
|
1485
|
+
} else {
|
|
1486
|
+
this.rules.set(path, { schemas, defaultMessage });
|
|
1487
|
+
}
|
|
1488
|
+
}
|
|
1489
|
+
/**
|
|
1490
|
+
* 注销单个字段的校验规则,同时清除该字段的错误信息。
|
|
1491
|
+
*
|
|
1492
|
+
* @param path - 字段路径
|
|
1493
|
+
*
|
|
1494
|
+
* @example
|
|
1495
|
+
* ```typescript
|
|
1496
|
+
* validator.unregister('email')
|
|
1497
|
+
* ```
|
|
1498
|
+
*/
|
|
1499
|
+
unregister(path) {
|
|
1500
|
+
this.rules.delete(path);
|
|
1501
|
+
this.errors.delete(path);
|
|
1502
|
+
}
|
|
1503
|
+
/**
|
|
1504
|
+
* 获取指定字段的错误信息。
|
|
1505
|
+
*
|
|
1506
|
+
* @param path - 字段路径
|
|
1507
|
+
* @returns 错误信息数组,无错误时返回 undefined
|
|
1508
|
+
*
|
|
1509
|
+
* @example
|
|
1510
|
+
* ```typescript
|
|
1511
|
+
* validator.getFieldError('email') // => ['邮箱格式不正确']
|
|
1512
|
+
* ```
|
|
1513
|
+
*/
|
|
1514
|
+
getFieldError(path) {
|
|
1515
|
+
return this.errors.get(path);
|
|
1516
|
+
}
|
|
1517
|
+
/**
|
|
1518
|
+
* 手动设置指定字段的错误信息。
|
|
1519
|
+
*
|
|
1520
|
+
* @param path - 字段路径
|
|
1521
|
+
* @param errors - 错误信息数组
|
|
1522
|
+
*
|
|
1523
|
+
* @example
|
|
1524
|
+
* ```typescript
|
|
1525
|
+
* validator.setFieldError('email', ['该邮箱已被注册'])
|
|
1526
|
+
* ```
|
|
1527
|
+
*/
|
|
1528
|
+
setFieldError(path, errors) {
|
|
1529
|
+
this.errors.set(path, errors);
|
|
1530
|
+
}
|
|
1531
|
+
/**
|
|
1532
|
+
* 校验指定字段。
|
|
1533
|
+
*
|
|
1534
|
+
* 支持传入单个路径或路径数组,逐个校验后返回汇总结果。
|
|
1535
|
+
*
|
|
1536
|
+
* @param path - 字段路径或路径数组
|
|
1537
|
+
* @param latestValues - 当前表单全量值
|
|
1538
|
+
* @returns 校验结果
|
|
1539
|
+
*
|
|
1540
|
+
* @example
|
|
1541
|
+
* ```typescript
|
|
1542
|
+
* const result = await validator.validateField('email', formValues)
|
|
1543
|
+
* const result = await validator.validateField(['name', 'email'], formValues)
|
|
1544
|
+
*
|
|
1545
|
+
* if (!result.ok) console.log(result.error.errors)
|
|
1546
|
+
* ```
|
|
1547
|
+
*/
|
|
1548
|
+
async validateField(path, latestValues) {
|
|
1549
|
+
const paths = Array.isArray(path) ? path : [path];
|
|
1550
|
+
this.reset(paths);
|
|
1551
|
+
let allValid = true;
|
|
1552
|
+
for (const p2 of paths) {
|
|
1553
|
+
const result = await this.validateSingleRule(p2, latestValues);
|
|
1554
|
+
if (!result.ok) allValid = false;
|
|
1555
|
+
}
|
|
1556
|
+
return this.buildResult(allValid, latestValues);
|
|
1557
|
+
}
|
|
1558
|
+
/**
|
|
1559
|
+
* 校验所有已注册规则的字段。
|
|
1560
|
+
*
|
|
1561
|
+
* 校验前清空所有错误,逐个校验后返回汇总结果。
|
|
1562
|
+
*
|
|
1563
|
+
* @param latestValues - 当前表单全量值
|
|
1564
|
+
* @returns 校验结果
|
|
1565
|
+
*
|
|
1566
|
+
* @example
|
|
1567
|
+
* ```typescript
|
|
1568
|
+
* const result = await validator.validate(formValues)
|
|
1569
|
+
* if (result.ok) submit(result.values)
|
|
1570
|
+
* ```
|
|
1571
|
+
*/
|
|
1572
|
+
async validate(latestValues) {
|
|
1573
|
+
let allValid = true;
|
|
1574
|
+
this.reset();
|
|
1575
|
+
for (const path of this.rules.keys()) {
|
|
1576
|
+
const result = await this.validateSingleRule(path, latestValues);
|
|
1577
|
+
if (!result.ok) allValid = false;
|
|
1578
|
+
}
|
|
1579
|
+
return this.buildResult(allValid, latestValues);
|
|
1580
|
+
}
|
|
1581
|
+
/**
|
|
1582
|
+
* 重置所有字段的校验错误。
|
|
1583
|
+
*
|
|
1584
|
+
* 清空 errors 映射表,不影响已注册的校验规则。
|
|
1585
|
+
*
|
|
1586
|
+
* @param paths - 可选的字段路径数组;不传时重置所有已注册字段。
|
|
1587
|
+
*
|
|
1588
|
+
* @example
|
|
1589
|
+
* ```typescript
|
|
1590
|
+
* validator.resetErrors()
|
|
1591
|
+
* ```
|
|
1592
|
+
*/
|
|
1593
|
+
reset(paths) {
|
|
1594
|
+
if (paths) {
|
|
1595
|
+
batchUpdates(() => {
|
|
1596
|
+
for (const key of paths) {
|
|
1597
|
+
this.errors.set(key, []);
|
|
1598
|
+
}
|
|
1599
|
+
});
|
|
1600
|
+
return;
|
|
1601
|
+
}
|
|
1602
|
+
batchUpdates(() => {
|
|
1603
|
+
for (const key of this.rules.keys()) {
|
|
1604
|
+
this.errors.set(key, []);
|
|
1605
|
+
}
|
|
1606
|
+
for (const key of [...this.errors.keys()]) {
|
|
1607
|
+
if (!this.rules.has(key)) {
|
|
1608
|
+
this.errors.delete(key);
|
|
1609
|
+
}
|
|
1610
|
+
}
|
|
1611
|
+
});
|
|
1612
|
+
}
|
|
1613
|
+
/**
|
|
1614
|
+
* 根据校验结果构建 ValidateResult 返回值。
|
|
1615
|
+
*
|
|
1616
|
+
* @param ok - 校验是否全部通过
|
|
1617
|
+
* @param latestValues - 当前表单全量值
|
|
1618
|
+
* @returns 统一的校验结果对象
|
|
1619
|
+
*/
|
|
1620
|
+
buildResult(ok, latestValues) {
|
|
1621
|
+
if (ok) {
|
|
1622
|
+
return { ok: true, values: latestValues };
|
|
1623
|
+
}
|
|
1624
|
+
return {
|
|
1625
|
+
ok: false,
|
|
1626
|
+
error: {
|
|
1627
|
+
errors: Array.from(this.errors.keys()).map((field) => ({
|
|
1628
|
+
field,
|
|
1629
|
+
message: this.errors.peek(field) || []
|
|
1630
|
+
})),
|
|
1631
|
+
values: latestValues
|
|
1632
|
+
}
|
|
1633
|
+
};
|
|
1634
|
+
}
|
|
1635
|
+
/**
|
|
1636
|
+
* 记录字段错误并返回失败结果。
|
|
1637
|
+
*
|
|
1638
|
+
* @param path - 字段路径
|
|
1639
|
+
* @param messages - 错误信息数组
|
|
1640
|
+
* @param latestValues - 当前表单全量值
|
|
1641
|
+
* @returns 失败的校验结果
|
|
1642
|
+
*/
|
|
1643
|
+
failResult(path, messages, latestValues) {
|
|
1644
|
+
this.errors.set(path, messages);
|
|
1645
|
+
return {
|
|
1646
|
+
ok: false,
|
|
1647
|
+
error: {
|
|
1648
|
+
errors: [{ field: path, message: messages }],
|
|
1649
|
+
values: latestValues
|
|
1650
|
+
}
|
|
1651
|
+
};
|
|
1652
|
+
}
|
|
1653
|
+
/**
|
|
1654
|
+
* 校验单个字段的所有规则。
|
|
1655
|
+
*
|
|
1656
|
+
* 依次执行该字段注册的所有 schema,遇到第一个失败即返回错误。
|
|
1657
|
+
* 若值为 undefined/null 且配置了 defaultMessage,直接返回失败结果。
|
|
1658
|
+
*
|
|
1659
|
+
* @param path - 字段路径
|
|
1660
|
+
* @param latestValues - 当前表单全量值
|
|
1661
|
+
* @returns 校验结果
|
|
1662
|
+
*/
|
|
1663
|
+
async validateSingleRule(path, latestValues) {
|
|
1664
|
+
const entry = this.rules.get(path);
|
|
1665
|
+
if (!entry || entry.schemas.length === 0) {
|
|
1666
|
+
this.errors.delete(path);
|
|
1667
|
+
return { ok: true, values: latestValues };
|
|
1668
|
+
}
|
|
1669
|
+
const value = getByPath(latestValues, path);
|
|
1670
|
+
const allMessages = [];
|
|
1671
|
+
if ((value === void 0 || value === null) && entry.defaultMessage) {
|
|
1672
|
+
allMessages.push(entry.defaultMessage);
|
|
1673
|
+
}
|
|
1674
|
+
for (const schema of entry.schemas) {
|
|
1675
|
+
try {
|
|
1676
|
+
const result = await schema["~standard"].validate(value);
|
|
1677
|
+
if (result.issues) {
|
|
1678
|
+
allMessages.push(...result.issues.map((i2) => i2.message));
|
|
1679
|
+
}
|
|
1680
|
+
} catch (error) {
|
|
1681
|
+
console.warn(`[Validator] 校验字段 "${path}" 时发生错误:`, error);
|
|
1682
|
+
allMessages.push("校验失败");
|
|
1683
|
+
}
|
|
1684
|
+
}
|
|
1685
|
+
if (allMessages.length > 0) {
|
|
1686
|
+
return this.failResult(path, allMessages, latestValues);
|
|
1687
|
+
}
|
|
1688
|
+
this.errors.delete(path);
|
|
1689
|
+
return { ok: true, values: latestValues };
|
|
1690
|
+
}
|
|
1691
|
+
}
|
|
1692
|
+
function createValidator() {
|
|
1693
|
+
return new ValidatorImpl();
|
|
1694
|
+
}
|
|
1695
|
+
function createRequiredRule(schema) {
|
|
1696
|
+
const validate = (value) => {
|
|
1697
|
+
if (value === void 0 || value === null || value === "") {
|
|
1698
|
+
const label = (schema == null ? void 0 : schema.label) ?? "";
|
|
1699
|
+
return standardIssueResult(label ? `请输入${label}` : "此项为必填项");
|
|
1700
|
+
}
|
|
1701
|
+
return standardValueResult(value);
|
|
1702
|
+
};
|
|
1703
|
+
return buildStandardSchema(validate);
|
|
1704
|
+
}
|
|
1705
|
+
function createSelectRequiredRule(schema) {
|
|
1706
|
+
const validate = (value) => {
|
|
1707
|
+
if (value === void 0 || value === null || value === "" || Array.isArray(value) && value.length === 0) {
|
|
1708
|
+
const label = (schema == null ? void 0 : schema.label) ?? "";
|
|
1709
|
+
return standardIssueResult(label ? `请选择${label}` : "此项为必选项");
|
|
1710
|
+
}
|
|
1711
|
+
return standardValueResult(value);
|
|
1712
|
+
};
|
|
1713
|
+
return buildStandardSchema(validate);
|
|
1714
|
+
}
|
|
1715
|
+
function createUploadRequiredRule(schema) {
|
|
1716
|
+
const validate = (value) => {
|
|
1717
|
+
if (value === void 0 || value === null || Array.isArray(value) && value.length === 0) {
|
|
1718
|
+
const label = (schema == null ? void 0 : schema.label) ?? "";
|
|
1719
|
+
return standardIssueResult(label ? `请上传${label}` : "此项为必传项");
|
|
1720
|
+
}
|
|
1721
|
+
return standardValueResult(value);
|
|
1722
|
+
};
|
|
1723
|
+
return buildStandardSchema(validate);
|
|
1724
|
+
}
|
|
1725
|
+
const buildStandardSchema = (validate) => {
|
|
1726
|
+
return {
|
|
1727
|
+
"~standard": {
|
|
1728
|
+
version: 1,
|
|
1729
|
+
vendor: "schemx",
|
|
1730
|
+
validate
|
|
1731
|
+
}
|
|
1732
|
+
};
|
|
1733
|
+
};
|
|
1734
|
+
const standardIssueResult = (message) => {
|
|
1735
|
+
return {
|
|
1736
|
+
issues: [{ message }]
|
|
1737
|
+
};
|
|
1738
|
+
};
|
|
1739
|
+
const standardValueResult = (value) => {
|
|
1740
|
+
return { value };
|
|
1741
|
+
};
|
|
1742
|
+
class RendererRegistry {
|
|
1743
|
+
/**
|
|
1744
|
+
* 创建 Registry 实例。
|
|
1745
|
+
*
|
|
1746
|
+
* @param defaultType - 默认渲染器类型,未找到指定类型时回退使用
|
|
1747
|
+
*/
|
|
1748
|
+
constructor(defaultType) {
|
|
1749
|
+
__publicField(this, "renderers");
|
|
1750
|
+
__publicField(this, "defaultType");
|
|
1751
|
+
this.renderers = /* @__PURE__ */ new Map();
|
|
1752
|
+
this.defaultType = defaultType;
|
|
1753
|
+
}
|
|
1754
|
+
/**
|
|
1755
|
+
* 注册渲染器。
|
|
1756
|
+
*
|
|
1757
|
+
* 默认会覆盖已存在的同名渲染器,可通过 `options.override` 控制。
|
|
1758
|
+
*
|
|
1759
|
+
* @param type - 渲染器类型标识
|
|
1760
|
+
* @param renderer - 组件
|
|
1761
|
+
* @param options - 注册选项
|
|
1762
|
+
*
|
|
1763
|
+
* @example
|
|
1764
|
+
* ```typescript
|
|
1765
|
+
* renderer.register('text', TextRenderer)
|
|
1766
|
+
* renderer.register('text', NewTextRenderer, { override: true })
|
|
1767
|
+
* ```
|
|
1768
|
+
*/
|
|
1769
|
+
register(type, renderer, options) {
|
|
1770
|
+
if (this.renderers.has(type) && (options == null ? void 0 : options.override) === false) {
|
|
1771
|
+
console.warn(
|
|
1772
|
+
`[RendererRegistryType] RendererRegistry "${type}" already exists, skipping registration`
|
|
1773
|
+
);
|
|
1774
|
+
return;
|
|
1775
|
+
}
|
|
1776
|
+
this.renderers.set(type, renderer);
|
|
1777
|
+
}
|
|
1778
|
+
/**
|
|
1779
|
+
* 批量注册渲染器。
|
|
1780
|
+
*
|
|
1781
|
+
* 遍历映射对象逐个注册,已存在的同名渲染器会被直接覆盖。
|
|
1782
|
+
*
|
|
1783
|
+
* @param renderers - 类型到组件的映射对象
|
|
1784
|
+
*
|
|
1785
|
+
* @example
|
|
1786
|
+
* ```typescript
|
|
1787
|
+
* renderer.registerAll({
|
|
1788
|
+
* text: TextRenderer,
|
|
1789
|
+
* number: NumberRenderer,
|
|
1790
|
+
* date: DateRenderer,
|
|
1791
|
+
* })
|
|
1792
|
+
* ```
|
|
1793
|
+
*/
|
|
1794
|
+
registerAll(renderers) {
|
|
1795
|
+
Object.entries(renderers).forEach(([type, renderer]) => {
|
|
1796
|
+
this.renderers.set(type, renderer);
|
|
1797
|
+
});
|
|
1798
|
+
}
|
|
1799
|
+
/**
|
|
1800
|
+
* 获取指定类型的渲染器组件。
|
|
1801
|
+
*
|
|
1802
|
+
* 未找到时自动回退到默认类型,默认类型也不存在则返回 undefined。
|
|
1803
|
+
*
|
|
1804
|
+
* @param type - 渲染器类型标识
|
|
1805
|
+
* @returns 对应的组件,未找到且无默认时返回 undefined
|
|
1806
|
+
*
|
|
1807
|
+
* @example
|
|
1808
|
+
* ```typescript
|
|
1809
|
+
* const renderer = renderer.getRenderer('text')
|
|
1810
|
+
* const fallback = renderer.getRenderer('unknown') // => 默认渲染器
|
|
1811
|
+
* ```
|
|
1812
|
+
*/
|
|
1813
|
+
getRenderer(type) {
|
|
1814
|
+
let renderer = this.renderers.get(type);
|
|
1815
|
+
if (!renderer) {
|
|
1816
|
+
console.warn(
|
|
1817
|
+
`[RendererRegistryType] RendererRegistry "${type}" not found, falling back to default "${this.defaultType}"`
|
|
1818
|
+
);
|
|
1819
|
+
if (this.defaultType) renderer = this.renderers.get(this.defaultType);
|
|
1820
|
+
}
|
|
1821
|
+
return renderer;
|
|
1822
|
+
}
|
|
1823
|
+
/**
|
|
1824
|
+
* 检查渲染器是否已注册
|
|
1825
|
+
*
|
|
1826
|
+
* @param type - 渲染器类型标识
|
|
1827
|
+
* @returns 是否存在
|
|
1828
|
+
*
|
|
1829
|
+
* @example
|
|
1830
|
+
* ```typescript
|
|
1831
|
+
* renderer.hasRenderer('text') // => true
|
|
1832
|
+
* renderer.hasRenderer('custom') // => false
|
|
1833
|
+
* ```
|
|
1834
|
+
*/
|
|
1835
|
+
hasRenderer(type) {
|
|
1836
|
+
return this.renderers.has(type);
|
|
1837
|
+
}
|
|
1838
|
+
/**
|
|
1839
|
+
* 移除渲染器
|
|
1840
|
+
*
|
|
1841
|
+
* 如果移除的是当前默认类型,会从剩余渲染器中智能选取新默认类型。
|
|
1842
|
+
* 若无剩余渲染器则默认类型设为空字符串。
|
|
1843
|
+
*
|
|
1844
|
+
* @param type - 渲染器类型标识
|
|
1845
|
+
* @returns 是否成功移除
|
|
1846
|
+
*
|
|
1847
|
+
* @example
|
|
1848
|
+
* ```typescript
|
|
1849
|
+
* renderer.unregister('date') // => true
|
|
1850
|
+
* renderer.unregister('nonexistent') // => false
|
|
1851
|
+
* ```
|
|
1852
|
+
*/
|
|
1853
|
+
unregister(type) {
|
|
1854
|
+
const isDefault = type === this.defaultType;
|
|
1855
|
+
const deleted = this.renderers.delete(type);
|
|
1856
|
+
if (isDefault && deleted) {
|
|
1857
|
+
const firstKey = this.renderers.keys().next().value;
|
|
1858
|
+
if (firstKey) {
|
|
1859
|
+
console.warn(
|
|
1860
|
+
`[RendererRegistryType] Default renderer was removed, Please reset the default renderer.`
|
|
1861
|
+
);
|
|
1862
|
+
this.defaultType = firstKey;
|
|
1863
|
+
}
|
|
1864
|
+
}
|
|
1865
|
+
return deleted;
|
|
1866
|
+
}
|
|
1867
|
+
/**
|
|
1868
|
+
* 获取所有已注册的渲染器类型
|
|
1869
|
+
*
|
|
1870
|
+
* @returns 类型标识数组
|
|
1871
|
+
*
|
|
1872
|
+
* @example
|
|
1873
|
+
* ```typescript
|
|
1874
|
+
* renderer.getTypes() // => ['text', 'number', 'date']
|
|
1875
|
+
* ```
|
|
1876
|
+
*/
|
|
1877
|
+
getTypes() {
|
|
1878
|
+
return Array.from(this.renderers.keys());
|
|
1879
|
+
}
|
|
1880
|
+
/**
|
|
1881
|
+
* 设置默认渲染器类型
|
|
1882
|
+
*
|
|
1883
|
+
* 当 getRenderer 找不到指定类型时,会回退到默认类型。
|
|
1884
|
+
* 设置的类型必须已注册,否则操作无效。
|
|
1885
|
+
*
|
|
1886
|
+
* @param type - 渲染器类型标识
|
|
1887
|
+
*
|
|
1888
|
+
* @example
|
|
1889
|
+
* ```typescript
|
|
1890
|
+
* renderer.setDefault('number')
|
|
1891
|
+
* renderer.getDefault() // => 'number'
|
|
1892
|
+
* ```
|
|
1893
|
+
*/
|
|
1894
|
+
setDefault(type) {
|
|
1895
|
+
if (!this.renderers.has(type)) {
|
|
1896
|
+
console.warn(
|
|
1897
|
+
`[RendererRegistryType] Cannot set default to "${type}": renderer not registered`
|
|
1898
|
+
);
|
|
1899
|
+
return;
|
|
1900
|
+
}
|
|
1901
|
+
this.defaultType = type;
|
|
1902
|
+
}
|
|
1903
|
+
/**
|
|
1904
|
+
* 获取当前默认渲染器类型
|
|
1905
|
+
*
|
|
1906
|
+
* @returns 默认类型标识
|
|
1907
|
+
*
|
|
1908
|
+
* @example
|
|
1909
|
+
* ```typescript
|
|
1910
|
+
* renderer.getDefault() // => 'text'
|
|
1911
|
+
* ```
|
|
1912
|
+
*/
|
|
1913
|
+
getDefault() {
|
|
1914
|
+
return this.defaultType;
|
|
1915
|
+
}
|
|
1916
|
+
/**
|
|
1917
|
+
* 清除所有已注册的渲染器并重置默认类型为 'text'。
|
|
1918
|
+
*
|
|
1919
|
+
* @example
|
|
1920
|
+
* ```typescript
|
|
1921
|
+
* renderer.clear()
|
|
1922
|
+
* renderer.size() // => 0
|
|
1923
|
+
* ```
|
|
1924
|
+
*/
|
|
1925
|
+
clear() {
|
|
1926
|
+
this.renderers.clear();
|
|
1927
|
+
}
|
|
1928
|
+
/**
|
|
1929
|
+
* 获取已注册渲染器数量
|
|
1930
|
+
*
|
|
1931
|
+
* @returns 渲染器数量
|
|
1932
|
+
*
|
|
1933
|
+
* @example
|
|
1934
|
+
* ```typescript
|
|
1935
|
+
* renderer.size() // => 5
|
|
1936
|
+
* ```
|
|
1937
|
+
*/
|
|
1938
|
+
size() {
|
|
1939
|
+
return this.renderers.size;
|
|
1940
|
+
}
|
|
1941
|
+
}
|
|
1942
|
+
function createRendererRegistry(defaultType) {
|
|
1943
|
+
return new RendererRegistry(defaultType);
|
|
1944
|
+
}
|
|
1945
|
+
class ValidatorsRegistry {
|
|
1946
|
+
/**
|
|
1947
|
+
* 创建 ValidatorsRegistryType 实例。
|
|
1948
|
+
*
|
|
1949
|
+
* 创建空的规则注册中心。
|
|
1950
|
+
*/
|
|
1951
|
+
constructor() {
|
|
1952
|
+
__publicField(this, "validators");
|
|
1953
|
+
this.validators = /* @__PURE__ */ new Map();
|
|
1954
|
+
}
|
|
1955
|
+
/**
|
|
1956
|
+
* 注册校验规则。
|
|
1957
|
+
*
|
|
1958
|
+
* 支持 StandardSchemaV1 实例或工厂函数。
|
|
1959
|
+
* 默认覆盖已存在的同名规则,可通过 `options.override` 控制。
|
|
1960
|
+
*
|
|
1961
|
+
* @param name - validators 名称
|
|
1962
|
+
* @param validators - StandardSchemaV1 实例或工厂函数
|
|
1963
|
+
* @param options - 注册选项
|
|
1964
|
+
*
|
|
1965
|
+
* @example
|
|
1966
|
+
* ```typescript
|
|
1967
|
+
* // 注册固定 validators
|
|
1968
|
+
* validatorRegistry.register('phone', phoneValidators)
|
|
1969
|
+
*
|
|
1970
|
+
* // 注册工厂函数
|
|
1971
|
+
* validatorRegistry.register('required', (schema) => createRequiredValidators(schema))
|
|
1972
|
+
* ```
|
|
1973
|
+
*/
|
|
1974
|
+
register(name, validators, options) {
|
|
1975
|
+
if (this.validators.has(name) && (options == null ? void 0 : options.override) === false) {
|
|
1976
|
+
console.warn(`[ValidatorsRegistryType] Validators "${name}" 已存在,跳过注册`);
|
|
1977
|
+
return;
|
|
1978
|
+
}
|
|
1979
|
+
this.validators.set(name, validators);
|
|
1980
|
+
}
|
|
1981
|
+
/**
|
|
1982
|
+
* 批量注册校验规则。
|
|
1983
|
+
*
|
|
1984
|
+
* 遍历映射对象逐个注册,已存在的同名规则会被直接覆盖。
|
|
1985
|
+
*
|
|
1986
|
+
* @param validators - 名称到 validators/工厂的映射对象
|
|
1987
|
+
*
|
|
1988
|
+
* @example
|
|
1989
|
+
* ```typescript
|
|
1990
|
+
* validatorRegistry.registerAll({
|
|
1991
|
+
* phone: phoneValidators,
|
|
1992
|
+
* required: (schema) => createRequiredValidators(schema),
|
|
1993
|
+
* })
|
|
1994
|
+
* ```
|
|
1995
|
+
*/
|
|
1996
|
+
registerAll(validators) {
|
|
1997
|
+
Object.entries(validators).forEach(([name, validators2]) => {
|
|
1998
|
+
this.validators.set(name, validators2);
|
|
1999
|
+
});
|
|
2000
|
+
}
|
|
2001
|
+
/**
|
|
2002
|
+
* 获取指定名称的原始注册条目。
|
|
2003
|
+
*
|
|
2004
|
+
* 返回 StandardSchemaV1 实例或工厂函数,不做解析。
|
|
2005
|
+
* 如需按字段 schema 自动解析字符串规则和工厂,请使用 {@link resolveValidatorsBySchema}。
|
|
2006
|
+
*
|
|
2007
|
+
* @param name - validators 名称
|
|
2008
|
+
* @returns 对应的注册条目,未找到时返回 undefined
|
|
2009
|
+
*
|
|
2010
|
+
* @example
|
|
2011
|
+
* ```typescript
|
|
2012
|
+
* const entry = validatorRegistry.get('phone')
|
|
2013
|
+
* ```
|
|
2014
|
+
*/
|
|
2015
|
+
get(name) {
|
|
2016
|
+
return this.validators.get(name);
|
|
2017
|
+
}
|
|
2018
|
+
/**
|
|
2019
|
+
* 解析字段 schema 上声明的校验规则。
|
|
2020
|
+
*
|
|
2021
|
+
* 字符串规则会从注册表查找;若注册项是工厂函数,则传入完整字段 schema
|
|
2022
|
+
* 生成 StandardSchemaV1 实例。已经是 StandardSchemaV1 的规则会原样返回。
|
|
2023
|
+
*
|
|
2024
|
+
* @param schema - 含 validators 的字段 schema。
|
|
2025
|
+
* @returns 解析后的 StandardSchemaV1 实例数组。
|
|
2026
|
+
*
|
|
2027
|
+
* @example
|
|
2028
|
+
* ```typescript
|
|
2029
|
+
* // 固定 validators 直接返回
|
|
2030
|
+
* validatorRegistry.resolveValidatorsBySchema({
|
|
2031
|
+
* name: 'phone',
|
|
2032
|
+
* label: '手机号',
|
|
2033
|
+
* componentType: 'input',
|
|
2034
|
+
* validators: 'phone',
|
|
2035
|
+
* })
|
|
2036
|
+
*
|
|
2037
|
+
* // 工厂函数会被调用
|
|
2038
|
+
* validatorRegistry.resolveValidatorsBySchema({
|
|
2039
|
+
* name: 'username',
|
|
2040
|
+
* label: '用户名',
|
|
2041
|
+
* componentType: 'input',
|
|
2042
|
+
* validators: 'required',
|
|
2043
|
+
* })
|
|
2044
|
+
* ```
|
|
2045
|
+
*/
|
|
2046
|
+
resolveValidatorsBySchema(schema) {
|
|
2047
|
+
const validators = (schema == null ? void 0 : schema.rules) ?? [];
|
|
2048
|
+
const validatorsList = Array.isArray(validators) ? validators : [validators];
|
|
2049
|
+
const resolved = [];
|
|
2050
|
+
for (const validators2 of validatorsList) {
|
|
2051
|
+
if (typeof validators2 === "string") {
|
|
2052
|
+
if (this.validators.has(validators2)) {
|
|
2053
|
+
const entry = this.validators.get(validators2);
|
|
2054
|
+
if (entry) {
|
|
2055
|
+
resolved.push(typeof entry === "function" ? entry(schema) : entry);
|
|
2056
|
+
}
|
|
2057
|
+
} else {
|
|
2058
|
+
console.warn(`[schemx] 未找到名为 "${validators2}" 的校验规则`);
|
|
2059
|
+
}
|
|
2060
|
+
} else {
|
|
2061
|
+
if (validators2) resolved.push(validators2);
|
|
2062
|
+
}
|
|
2063
|
+
}
|
|
2064
|
+
return resolved;
|
|
2065
|
+
}
|
|
2066
|
+
/**
|
|
2067
|
+
* 检查 validators 是否已注册。
|
|
2068
|
+
*
|
|
2069
|
+
* @param name - validators 名称
|
|
2070
|
+
* @returns 是否存在
|
|
2071
|
+
*
|
|
2072
|
+
* @example
|
|
2073
|
+
* ```typescript
|
|
2074
|
+
* validatorRegistry.has('phone') // => true
|
|
2075
|
+
* validatorRegistry.has('custom') // => false
|
|
2076
|
+
* ```
|
|
2077
|
+
*/
|
|
2078
|
+
has(name) {
|
|
2079
|
+
return this.validators.has(name);
|
|
2080
|
+
}
|
|
2081
|
+
/**
|
|
2082
|
+
* 移除校验规则。
|
|
2083
|
+
*
|
|
2084
|
+
* @param name - validators 名称
|
|
2085
|
+
* @returns 是否成功移除
|
|
2086
|
+
*
|
|
2087
|
+
* @example
|
|
2088
|
+
* ```typescript
|
|
2089
|
+
* validatorRegistry.unregister('phone') // => true
|
|
2090
|
+
* ```
|
|
2091
|
+
*/
|
|
2092
|
+
unregister(name) {
|
|
2093
|
+
return this.validators.delete(name);
|
|
2094
|
+
}
|
|
2095
|
+
/**
|
|
2096
|
+
* 获取所有已注册的 validators 名称。
|
|
2097
|
+
*
|
|
2098
|
+
* @returns validators 名称数组
|
|
2099
|
+
*
|
|
2100
|
+
* @example
|
|
2101
|
+
* ```typescript
|
|
2102
|
+
* validatorRegistry.getNames() // => ['phone', 'email', 'idCard']
|
|
2103
|
+
* ```
|
|
2104
|
+
*/
|
|
2105
|
+
getNames() {
|
|
2106
|
+
return Array.from(this.validators.keys());
|
|
2107
|
+
}
|
|
2108
|
+
/**
|
|
2109
|
+
* 清除所有已注册的规则。
|
|
2110
|
+
*
|
|
2111
|
+
* @example
|
|
2112
|
+
* ```typescript
|
|
2113
|
+
* validatorRegistry.clear()
|
|
2114
|
+
* validatorRegistry.size() // => 0
|
|
2115
|
+
* ```
|
|
2116
|
+
*/
|
|
2117
|
+
clear() {
|
|
2118
|
+
this.validators.clear();
|
|
2119
|
+
}
|
|
2120
|
+
/**
|
|
2121
|
+
* 获取已注册 validators 数量。
|
|
2122
|
+
*
|
|
2123
|
+
* @returns validators 数量
|
|
2124
|
+
*
|
|
2125
|
+
* @example
|
|
2126
|
+
* ```typescript
|
|
2127
|
+
* validatorRegistry.size() // => 3
|
|
2128
|
+
* ```
|
|
2129
|
+
*/
|
|
2130
|
+
size() {
|
|
2131
|
+
return this.validators.size;
|
|
2132
|
+
}
|
|
2133
|
+
}
|
|
2134
|
+
function createValidatorsRegistry() {
|
|
2135
|
+
return new ValidatorsRegistry();
|
|
2136
|
+
}
|
|
2137
|
+
function createSchemas(schemas = []) {
|
|
2138
|
+
const source = createSignal(schemas);
|
|
2139
|
+
const getValue = () => {
|
|
2140
|
+
return source.value;
|
|
2141
|
+
};
|
|
2142
|
+
const peek = () => {
|
|
2143
|
+
return source.peek();
|
|
2144
|
+
};
|
|
2145
|
+
const set2 = (nextSchemas) => {
|
|
2146
|
+
source.value = nextSchemas;
|
|
2147
|
+
};
|
|
2148
|
+
const update = (updater) => {
|
|
2149
|
+
source.value = updater(source.peek());
|
|
2150
|
+
};
|
|
2151
|
+
const subscribe = (listener) => {
|
|
2152
|
+
let isInitialNotify = true;
|
|
2153
|
+
const unsubscribe = source.subscribe((value) => {
|
|
2154
|
+
if (isInitialNotify) {
|
|
2155
|
+
isInitialNotify = false;
|
|
2156
|
+
return;
|
|
2157
|
+
}
|
|
2158
|
+
listener(value);
|
|
2159
|
+
});
|
|
2160
|
+
return () => {
|
|
2161
|
+
unsubscribe();
|
|
2162
|
+
};
|
|
2163
|
+
};
|
|
2164
|
+
return {
|
|
2165
|
+
signal: source,
|
|
2166
|
+
get value() {
|
|
2167
|
+
return getValue();
|
|
2168
|
+
},
|
|
2169
|
+
peek,
|
|
2170
|
+
set: set2,
|
|
2171
|
+
update,
|
|
2172
|
+
subscribe
|
|
2173
|
+
};
|
|
2174
|
+
}
|
|
2175
|
+
function isSchemxSchemas(schemas) {
|
|
2176
|
+
if (!schemas || Array.isArray(schemas)) {
|
|
2177
|
+
return false;
|
|
2178
|
+
}
|
|
2179
|
+
const candidate = schemas;
|
|
2180
|
+
return typeof candidate.peek === "function" && typeof candidate.set === "function" && typeof candidate.update === "function" && typeof candidate.subscribe === "function";
|
|
2181
|
+
}
|
|
2182
|
+
class CompileErrorImpl extends Error {
|
|
2183
|
+
constructor(message, schema) {
|
|
2184
|
+
super(message);
|
|
2185
|
+
__publicField(this, "schemaKey");
|
|
2186
|
+
__publicField(this, "schemaName");
|
|
2187
|
+
this.name = "CompileError";
|
|
2188
|
+
if (schema && "name" in schema) {
|
|
2189
|
+
this.schemaName = schema.name;
|
|
2190
|
+
}
|
|
2191
|
+
if (schema && "key" in schema && schema.key) {
|
|
2192
|
+
this.schemaKey = schema.key;
|
|
2193
|
+
}
|
|
2194
|
+
}
|
|
2195
|
+
}
|
|
2196
|
+
const CompileError = CompileErrorImpl;
|
|
2197
|
+
function compileToDescriptors(schemas, options = {}, parentKey = "") {
|
|
2198
|
+
const descriptors = [];
|
|
2199
|
+
const normalized = normalizeSchemas(schemas);
|
|
2200
|
+
for (let i2 = 0; i2 < normalized.length; i2++) {
|
|
2201
|
+
const schema = normalized[i2];
|
|
2202
|
+
let descriptor = void 0;
|
|
2203
|
+
if (isGroupSchema(schema)) {
|
|
2204
|
+
descriptor = compileGroup(schema, i2, options, parentKey);
|
|
2205
|
+
} else if (isDependencySchema(schema)) {
|
|
2206
|
+
descriptor = compileDependencySlot(schema, i2, parentKey);
|
|
2207
|
+
} else {
|
|
2208
|
+
descriptor = compileField(schema, i2, options, parentKey);
|
|
2209
|
+
}
|
|
2210
|
+
descriptors.push(descriptor);
|
|
2211
|
+
}
|
|
2212
|
+
return descriptors;
|
|
2213
|
+
}
|
|
2214
|
+
function compileField(schema, index, options = {}, parentKey = "") {
|
|
2215
|
+
const key = schema.key ?? (parentKey ? `field:${parentKey}/${schema.name}` : `field:${schema.name}`);
|
|
2216
|
+
const normalizedSchema = buildNormalizedFieldSchema(schema, options);
|
|
2217
|
+
return {
|
|
2218
|
+
type: "field",
|
|
2219
|
+
key,
|
|
2220
|
+
name: schema.name,
|
|
2221
|
+
rendererType: schema.componentType,
|
|
2222
|
+
schema: normalizedSchema,
|
|
2223
|
+
dependencies: schema.dependencies
|
|
2224
|
+
};
|
|
2225
|
+
}
|
|
2226
|
+
function compileGroup(schema, index, options = {}, parentKey = "") {
|
|
2227
|
+
const key = schema.key ?? (parentKey ? `group:${parentKey}/${index}` : `group:${index}`);
|
|
2228
|
+
const { children: rawChildren, ...schemaWithoutChildren } = schema;
|
|
2229
|
+
const children = compileToDescriptors(rawChildren, options, key);
|
|
2230
|
+
return {
|
|
2231
|
+
type: "group",
|
|
2232
|
+
key,
|
|
2233
|
+
schema: {
|
|
2234
|
+
...schemaWithoutChildren,
|
|
2235
|
+
key
|
|
2236
|
+
},
|
|
2237
|
+
children
|
|
2238
|
+
};
|
|
2239
|
+
}
|
|
2240
|
+
function compileDependencySlot(schema, index, parentKey = "") {
|
|
2241
|
+
const key = schema.key ?? (parentKey ? `dependency:${parentKey}/${index}` : `dependency:${index}`);
|
|
2242
|
+
if (!schema.to || schema.to.length === 0) {
|
|
2243
|
+
throw new CompileError("Dependency schema must have non-empty trigger fields", schema);
|
|
2244
|
+
}
|
|
2245
|
+
const trigger = [...schema.to];
|
|
2246
|
+
const renderer = (formApi, abortSignal) => {
|
|
2247
|
+
const values = formApi.getValues();
|
|
2248
|
+
return schema.renderer(values, formApi, {
|
|
2249
|
+
abortSignal
|
|
2250
|
+
});
|
|
2251
|
+
};
|
|
2252
|
+
return {
|
|
2253
|
+
type: "dependency",
|
|
2254
|
+
key,
|
|
2255
|
+
trigger,
|
|
2256
|
+
renderer
|
|
2257
|
+
};
|
|
2258
|
+
}
|
|
2259
|
+
function buildNormalizedFieldSchema(schema, options = {}) {
|
|
2260
|
+
const {
|
|
2261
|
+
componentProps: cp,
|
|
2262
|
+
visible,
|
|
2263
|
+
readonly,
|
|
2264
|
+
disabled,
|
|
2265
|
+
required,
|
|
2266
|
+
placeholder,
|
|
2267
|
+
rules,
|
|
2268
|
+
validationTrigger,
|
|
2269
|
+
dependencies: _dependencies,
|
|
2270
|
+
...rest
|
|
2271
|
+
} = schema;
|
|
2272
|
+
const mergedVisible = visible ?? defaultConfig.visible;
|
|
2273
|
+
const mergedReadonly = readonly ?? options.readonly ?? defaultConfig.readonly;
|
|
2274
|
+
const mergedDisabled = disabled ?? options.disabled ?? defaultConfig.disabled;
|
|
2275
|
+
const mergedAlign = mergedReadonly ? "right" : (cp == null ? void 0 : cp.align) ?? rest.contentAlign;
|
|
2276
|
+
const mergedPlaceholder = getPlaceholder(schema);
|
|
2277
|
+
const componentProps = {
|
|
2278
|
+
...cp,
|
|
2279
|
+
readonly: mergedReadonly,
|
|
2280
|
+
disabled: mergedDisabled,
|
|
2281
|
+
placeholder: mergedPlaceholder,
|
|
2282
|
+
align: mergedAlign
|
|
2283
|
+
};
|
|
2284
|
+
const rulesArray = (Array.isArray(rules) ? rules : [rules]).filter(Boolean);
|
|
2285
|
+
const mergedRequired = required ?? (rulesArray.length > 0 || defaultConfig.required);
|
|
2286
|
+
const normalizedSchema = {
|
|
2287
|
+
...rest ?? {},
|
|
2288
|
+
key: rest.key,
|
|
2289
|
+
name: rest.name,
|
|
2290
|
+
label: rest.label,
|
|
2291
|
+
componentType: rest.componentType,
|
|
2292
|
+
visible: mergedVisible,
|
|
2293
|
+
readonly: mergedReadonly,
|
|
2294
|
+
disabled: mergedDisabled,
|
|
2295
|
+
required: mergedRequired,
|
|
2296
|
+
placeholder: mergedPlaceholder,
|
|
2297
|
+
componentProps,
|
|
2298
|
+
labelIcon: rest.labelIcon || defaultConfig.labelIcon,
|
|
2299
|
+
labelAlign: rest.labelAlign || defaultConfig.labelAlign,
|
|
2300
|
+
labelPosition: rest.labelPosition || defaultConfig.labelPosition,
|
|
2301
|
+
labelWidth: rest.labelWidth || defaultConfig.labelWidth,
|
|
2302
|
+
colon: rest.colon ?? defaultConfig.colon,
|
|
2303
|
+
rules,
|
|
2304
|
+
validationTrigger: validationTrigger || defaultConfig.validationTrigger
|
|
2305
|
+
};
|
|
2306
|
+
if (Object.hasOwn(schema, "initialValue")) {
|
|
2307
|
+
normalizedSchema.initialValue = rest.initialValue;
|
|
2308
|
+
}
|
|
2309
|
+
if (mergedReadonly) {
|
|
2310
|
+
normalizedSchema.contentAlign = "right";
|
|
2311
|
+
normalizedSchema.labelPosition = "left";
|
|
2312
|
+
}
|
|
2313
|
+
return normalizedSchema;
|
|
2314
|
+
}
|
|
2315
|
+
function getPlaceholder(schema) {
|
|
2316
|
+
var _a;
|
|
2317
|
+
const existingplaceholder = ((_a = schema.componentProps) == null ? void 0 : _a.placeholder) ?? schema.placeholder;
|
|
2318
|
+
if (existingplaceholder == null) {
|
|
2319
|
+
return ["input", "text", "textarea"].includes(schema.componentType) ? `请输入${schema.label || schema.name}` : `请选择${schema.label || schema.name}`;
|
|
2320
|
+
}
|
|
2321
|
+
return existingplaceholder;
|
|
2322
|
+
}
|
|
2323
|
+
const isFieldDescriptor = (descriptor) => {
|
|
2324
|
+
return descriptor.type === "field";
|
|
2325
|
+
};
|
|
2326
|
+
const isGroupDescriptor = (descriptor) => {
|
|
2327
|
+
return descriptor.type === "group";
|
|
2328
|
+
};
|
|
2329
|
+
const isDependencyDescriptor = (descriptor) => {
|
|
2330
|
+
return descriptor.type === "dependency";
|
|
2331
|
+
};
|
|
2332
|
+
function createFieldModel(descriptor) {
|
|
2333
|
+
return {
|
|
2334
|
+
snapshot: createSignal(createFieldModelSnapshot(descriptor))
|
|
2335
|
+
};
|
|
2336
|
+
}
|
|
2337
|
+
function updateFieldModel(model, descriptor, resolved) {
|
|
2338
|
+
const nextSnapshot = createFieldModelSnapshot(descriptor, resolved);
|
|
2339
|
+
if (isSameFieldModelSnapshot(model.snapshot.peek(), nextSnapshot)) {
|
|
2340
|
+
return;
|
|
2341
|
+
}
|
|
2342
|
+
model.snapshot.value = nextSnapshot;
|
|
2343
|
+
}
|
|
2344
|
+
function createFieldModelSnapshot(descriptor, resolved) {
|
|
2345
|
+
const schema = descriptor.schema;
|
|
2346
|
+
return {
|
|
2347
|
+
visible: (resolved == null ? void 0 : resolved.visible) ?? schema.visible ?? defaultConfig.visible,
|
|
2348
|
+
disabled: (resolved == null ? void 0 : resolved.disabled) ?? schema.disabled ?? defaultConfig.disabled,
|
|
2349
|
+
readonly: (resolved == null ? void 0 : resolved.readonly) ?? schema.readonly ?? defaultConfig.readonly,
|
|
2350
|
+
required: (resolved == null ? void 0 : resolved.required) ?? schema.required ?? defaultConfig.required,
|
|
2351
|
+
label: schema.label || "",
|
|
2352
|
+
rules: ((resolved == null ? void 0 : resolved.rules) ?? schema.rules) || [],
|
|
2353
|
+
placeholder: (resolved == null ? void 0 : resolved.placeholder) ?? schema.placeholder ?? getPlaceholder(schema),
|
|
2354
|
+
componentProps: ((resolved == null ? void 0 : resolved.componentProps) ?? schema.componentProps) || {}
|
|
2355
|
+
};
|
|
2356
|
+
}
|
|
2357
|
+
function isSameFieldModelSnapshot(current, next) {
|
|
2358
|
+
return current.visible === next.visible && current.disabled === next.disabled && current.readonly === next.readonly && current.required === next.required && current.label === next.label && isSameArrayOrValue(current.rules, next.rules) && current.placeholder === next.placeholder && isShallowEqualRecord(current.componentProps, next.componentProps);
|
|
2359
|
+
}
|
|
2360
|
+
function isSameArrayOrValue(current, next) {
|
|
2361
|
+
if (current === next) {
|
|
2362
|
+
return true;
|
|
2363
|
+
}
|
|
2364
|
+
if (!Array.isArray(current) || !Array.isArray(next)) {
|
|
2365
|
+
return false;
|
|
2366
|
+
}
|
|
2367
|
+
return current.length === next.length && current.every((value, index) => value === next[index]);
|
|
2368
|
+
}
|
|
2369
|
+
function isShallowEqualRecord(current, next) {
|
|
2370
|
+
if (current === next) {
|
|
2371
|
+
return true;
|
|
2372
|
+
}
|
|
2373
|
+
const currentKeys = Object.keys(current);
|
|
2374
|
+
const nextKeys = Object.keys(next);
|
|
2375
|
+
const currentRecord = current;
|
|
2376
|
+
const nextRecord = next;
|
|
2377
|
+
return currentKeys.length === nextKeys.length && currentKeys.every((key) => currentRecord[key] === nextRecord[key]);
|
|
2378
|
+
}
|
|
2379
|
+
function createDependenciesEffect(options) {
|
|
2380
|
+
const { descriptor, fieldModel, context, scope } = options;
|
|
2381
|
+
const base = descriptor.schema;
|
|
2382
|
+
const dependencies = descriptor.dependencies;
|
|
2383
|
+
if (dependencies == null || dependencies.triggerFields == null || dependencies.triggerFields.length === 0) {
|
|
2384
|
+
return;
|
|
2385
|
+
}
|
|
2386
|
+
let version = 0;
|
|
2387
|
+
const dispose = createSignalEffect(() => {
|
|
2388
|
+
const currentVersion = ++version;
|
|
2389
|
+
void context.formApi.getValues(dependencies.triggerFields);
|
|
2390
|
+
void context.scheduler.track(
|
|
2391
|
+
resolveDependencies(dependencies, base, context.formApi).then((resolvedProps) => {
|
|
2392
|
+
if (scope.disposed || currentVersion !== version) {
|
|
2393
|
+
return;
|
|
2394
|
+
}
|
|
2395
|
+
updateFieldModel(fieldModel, descriptor, resolvedProps);
|
|
2396
|
+
})
|
|
2397
|
+
);
|
|
2398
|
+
});
|
|
2399
|
+
scope.add(() => {
|
|
2400
|
+
version += 1;
|
|
2401
|
+
dispose();
|
|
2402
|
+
});
|
|
2403
|
+
}
|
|
2404
|
+
async function resolveDependencies(dependencies, base, formApi) {
|
|
2405
|
+
const values = formApi.getValues();
|
|
2406
|
+
const [resolvedProps] = await Promise.all([
|
|
2407
|
+
resolveDependenciesProps(dependencies, base, values, formApi),
|
|
2408
|
+
runDependenciesTrigger(dependencies, values, formApi)
|
|
2409
|
+
]);
|
|
2410
|
+
return resolvedProps;
|
|
2411
|
+
}
|
|
2412
|
+
async function runDependenciesTrigger(dependencies, values, formApi) {
|
|
2413
|
+
if (!dependencies.trigger) {
|
|
2414
|
+
return;
|
|
2415
|
+
}
|
|
2416
|
+
try {
|
|
2417
|
+
await dependencies.trigger(values, formApi);
|
|
2418
|
+
} catch (error) {
|
|
2419
|
+
console.error("[schemx] trigger 执行错误:", error);
|
|
2420
|
+
}
|
|
2421
|
+
}
|
|
2422
|
+
async function resolveDependenciesProps(dependencies, base, values, formApi) {
|
|
2423
|
+
const [componentProps, placeholder, required, readonly, disabled, visible, rules] = await Promise.all([
|
|
2424
|
+
resolveDependenciesProp({
|
|
2425
|
+
condition: dependencies.componentProps,
|
|
2426
|
+
values,
|
|
2427
|
+
formApi,
|
|
2428
|
+
defaultValue: base.componentProps
|
|
2429
|
+
}),
|
|
2430
|
+
resolveDependenciesProp({
|
|
2431
|
+
condition: dependencies.placeholder,
|
|
2432
|
+
values,
|
|
2433
|
+
formApi,
|
|
2434
|
+
defaultValue: base.placeholder
|
|
2435
|
+
}),
|
|
2436
|
+
resolveDependenciesProp({
|
|
2437
|
+
condition: dependencies.required,
|
|
2438
|
+
values,
|
|
2439
|
+
formApi,
|
|
2440
|
+
defaultValue: base.required
|
|
2441
|
+
}),
|
|
2442
|
+
resolveDependenciesProp({
|
|
2443
|
+
condition: dependencies.readonly,
|
|
2444
|
+
values,
|
|
2445
|
+
formApi,
|
|
2446
|
+
defaultValue: base.readonly
|
|
2447
|
+
}),
|
|
2448
|
+
resolveDependenciesProp({
|
|
2449
|
+
condition: dependencies.disabled,
|
|
2450
|
+
values,
|
|
2451
|
+
formApi,
|
|
2452
|
+
defaultValue: base.disabled
|
|
2453
|
+
}),
|
|
2454
|
+
resolveDependenciesProp({
|
|
2455
|
+
condition: dependencies.visible,
|
|
2456
|
+
values,
|
|
2457
|
+
formApi,
|
|
2458
|
+
defaultValue: base.visible
|
|
2459
|
+
}),
|
|
2460
|
+
resolveDependenciesProp({
|
|
2461
|
+
condition: dependencies.rules,
|
|
2462
|
+
values,
|
|
2463
|
+
formApi,
|
|
2464
|
+
defaultValue: base.rules
|
|
2465
|
+
})
|
|
2466
|
+
]);
|
|
2467
|
+
return {
|
|
2468
|
+
componentProps,
|
|
2469
|
+
placeholder,
|
|
2470
|
+
required,
|
|
2471
|
+
readonly,
|
|
2472
|
+
disabled,
|
|
2473
|
+
visible,
|
|
2474
|
+
rules
|
|
2475
|
+
};
|
|
2476
|
+
}
|
|
2477
|
+
async function resolveDependenciesProp(options) {
|
|
2478
|
+
const { condition, values, formApi, defaultValue } = options;
|
|
2479
|
+
if (condition == null) {
|
|
2480
|
+
return defaultValue;
|
|
2481
|
+
}
|
|
2482
|
+
return resolveCondition(formApi, condition, values, defaultValue);
|
|
2483
|
+
}
|
|
2484
|
+
async function resolveCondition(formApi, condition, formValues, defaultValue) {
|
|
2485
|
+
try {
|
|
2486
|
+
const result = await condition(formValues, formApi);
|
|
2487
|
+
return result ?? defaultValue;
|
|
2488
|
+
} catch (error) {
|
|
2489
|
+
console.error("[schemx] 解析动态属性时发生错误:", error);
|
|
2490
|
+
return defaultValue;
|
|
2491
|
+
}
|
|
2492
|
+
}
|
|
2493
|
+
function createDependencyEffect(options) {
|
|
2494
|
+
var _a;
|
|
2495
|
+
const { node, descriptor, context } = options;
|
|
2496
|
+
const resourceScope = options.scope ?? node.scope.child();
|
|
2497
|
+
(_a = node.dependencySlot) == null ? void 0 : _a.dispose();
|
|
2498
|
+
const slot = {
|
|
2499
|
+
loading: createSignal(false),
|
|
2500
|
+
error: createSignal(null),
|
|
2501
|
+
version: createSignal(0),
|
|
2502
|
+
abortController: createSignal(null),
|
|
2503
|
+
run: async () => void 0,
|
|
2504
|
+
dispose: () => void 0
|
|
2505
|
+
};
|
|
2506
|
+
node.dependencyResourceScope = resourceScope;
|
|
2507
|
+
slot.run = () => {
|
|
2508
|
+
var _a2;
|
|
2509
|
+
if (resourceScope.disposed) return Promise.resolve();
|
|
2510
|
+
const currentDescriptor = node.descriptor;
|
|
2511
|
+
const currentVersion = slot.version.value + 1;
|
|
2512
|
+
slot.version.value = currentVersion;
|
|
2513
|
+
(_a2 = slot.abortController.value) == null ? void 0 : _a2.abort();
|
|
2514
|
+
const controller = new AbortController();
|
|
2515
|
+
slot.abortController.value = controller;
|
|
2516
|
+
slot.loading.value = true;
|
|
2517
|
+
slot.error.value = null;
|
|
2518
|
+
return context.scheduler.track(
|
|
2519
|
+
(async () => {
|
|
2520
|
+
try {
|
|
2521
|
+
const childSchemas = await Promise.resolve(
|
|
2522
|
+
currentDescriptor.renderer(context.formApi, controller.signal)
|
|
2523
|
+
);
|
|
2524
|
+
if (resourceScope.disposed || controller.signal.aborted || currentVersion !== slot.version.value) {
|
|
2525
|
+
return;
|
|
2526
|
+
}
|
|
2527
|
+
const descriptors = compileToDescriptors(
|
|
2528
|
+
childSchemas,
|
|
2529
|
+
context.defaultProps
|
|
2530
|
+
);
|
|
2531
|
+
context.commitChildren(node, descriptors);
|
|
2532
|
+
} catch (cause) {
|
|
2533
|
+
if (resourceScope.disposed || controller.signal.aborted || currentVersion !== slot.version.value) {
|
|
2534
|
+
return;
|
|
2535
|
+
}
|
|
2536
|
+
slot.error.value = normalizeError$1(cause);
|
|
2537
|
+
} finally {
|
|
2538
|
+
if (!resourceScope.disposed && !controller.signal.aborted && currentVersion === slot.version.value) {
|
|
2539
|
+
slot.loading.value = false;
|
|
2540
|
+
}
|
|
2541
|
+
}
|
|
2542
|
+
})()
|
|
2543
|
+
);
|
|
2544
|
+
};
|
|
2545
|
+
slot.dispose = () => {
|
|
2546
|
+
var _a2;
|
|
2547
|
+
slot.version.value += 1;
|
|
2548
|
+
(_a2 = slot.abortController.value) == null ? void 0 : _a2.abort();
|
|
2549
|
+
resourceScope.dispose();
|
|
2550
|
+
};
|
|
2551
|
+
resourceScope.add(() => {
|
|
2552
|
+
var _a2;
|
|
2553
|
+
(_a2 = slot.abortController.value) == null ? void 0 : _a2.abort();
|
|
2554
|
+
slot.abortController.value = null;
|
|
2555
|
+
if (node.dependencySlot === slot) {
|
|
2556
|
+
node.dependencySlot = null;
|
|
2557
|
+
}
|
|
2558
|
+
if (node.dependencyResourceScope === resourceScope) {
|
|
2559
|
+
node.dependencyResourceScope = null;
|
|
2560
|
+
}
|
|
2561
|
+
});
|
|
2562
|
+
if (descriptor.trigger.length > 0) {
|
|
2563
|
+
setupTriggerSubscription(
|
|
2564
|
+
descriptor.trigger,
|
|
2565
|
+
context.formApi,
|
|
2566
|
+
() => slot.run(),
|
|
2567
|
+
resourceScope
|
|
2568
|
+
);
|
|
2569
|
+
}
|
|
2570
|
+
node.dependencySlot = slot;
|
|
2571
|
+
void slot.run().catch((runError) => {
|
|
2572
|
+
console.error("DependencyEffectSlot initial run error:", runError);
|
|
2573
|
+
});
|
|
2574
|
+
return slot;
|
|
2575
|
+
}
|
|
2576
|
+
function setupTriggerSubscription(triggers, formApi, run, scope) {
|
|
2577
|
+
let isFirstRun = true;
|
|
2578
|
+
let pendingRun = false;
|
|
2579
|
+
const disposeEffect = createSignalEffect(() => {
|
|
2580
|
+
void formApi.getValues(triggers);
|
|
2581
|
+
if (!isFirstRun && !pendingRun) {
|
|
2582
|
+
pendingRun = true;
|
|
2583
|
+
queueMicrotask(() => {
|
|
2584
|
+
pendingRun = false;
|
|
2585
|
+
if (scope.disposed) return;
|
|
2586
|
+
run().catch((runError) => {
|
|
2587
|
+
console.error("DependencyEffectSlot trigger run error:", runError);
|
|
2588
|
+
});
|
|
2589
|
+
});
|
|
2590
|
+
}
|
|
2591
|
+
isFirstRun = false;
|
|
2592
|
+
});
|
|
2593
|
+
scope.add(disposeEffect);
|
|
2594
|
+
}
|
|
2595
|
+
function normalizeError$1(cause) {
|
|
2596
|
+
return cause instanceof Error ? cause : new Error(String(cause));
|
|
2597
|
+
}
|
|
2598
|
+
class RuntimeFieldRegistry {
|
|
2599
|
+
constructor() {
|
|
2600
|
+
__publicField(this, "fields", /* @__PURE__ */ new Map());
|
|
2601
|
+
}
|
|
2602
|
+
register(entry) {
|
|
2603
|
+
const key = entry.name;
|
|
2604
|
+
this.fields.set(key, entry);
|
|
2605
|
+
}
|
|
2606
|
+
unregister(name, node) {
|
|
2607
|
+
const key = name;
|
|
2608
|
+
const current = this.fields.get(key);
|
|
2609
|
+
if (node && (current == null ? void 0 : current.node) !== node) {
|
|
2610
|
+
return;
|
|
2611
|
+
}
|
|
2612
|
+
this.fields.delete(key);
|
|
2613
|
+
}
|
|
2614
|
+
get(name) {
|
|
2615
|
+
const key = name;
|
|
2616
|
+
return this.fields.get(key);
|
|
2617
|
+
}
|
|
2618
|
+
list() {
|
|
2619
|
+
return Array.from(this.fields.values());
|
|
2620
|
+
}
|
|
2621
|
+
}
|
|
2622
|
+
function createFieldRegistry() {
|
|
2623
|
+
return new RuntimeFieldRegistry();
|
|
2624
|
+
}
|
|
2625
|
+
function createValidationEffect(options) {
|
|
2626
|
+
const { name, fieldModel, scope, context } = options;
|
|
2627
|
+
const taskScheduler = context.scheduler;
|
|
2628
|
+
const registered = createSignal(false);
|
|
2629
|
+
const validating = createSignal(false);
|
|
2630
|
+
let registrationVersion = 0;
|
|
2631
|
+
const readValidationProps = () => {
|
|
2632
|
+
const snapshot = fieldModel.snapshot.value;
|
|
2633
|
+
return {
|
|
2634
|
+
visible: snapshot.visible,
|
|
2635
|
+
readonly: snapshot.readonly,
|
|
2636
|
+
disabled: snapshot.disabled,
|
|
2637
|
+
label: snapshot.label,
|
|
2638
|
+
rules: snapshot.rules
|
|
2639
|
+
};
|
|
2640
|
+
};
|
|
2641
|
+
const applyRegistration = (snapshot) => {
|
|
2642
|
+
const { visible, readonly, disabled, label, rules } = snapshot;
|
|
2643
|
+
if (!visible || readonly || disabled || !rules) {
|
|
2644
|
+
context.instance.unregisterRules(name);
|
|
2645
|
+
context.instance.setFieldError(name, []);
|
|
2646
|
+
registered.value = false;
|
|
2647
|
+
return;
|
|
2648
|
+
}
|
|
2649
|
+
context.instance.registerRules(name, rules, `${label}为必填项`);
|
|
2650
|
+
registered.value = true;
|
|
2651
|
+
};
|
|
2652
|
+
const scheduleRegistration = (snapshot) => {
|
|
2653
|
+
const currentVersion = ++registrationVersion;
|
|
2654
|
+
taskScheduler.schedule({
|
|
2655
|
+
id: `validation:${String(name)}`,
|
|
2656
|
+
priority: "post",
|
|
2657
|
+
scope,
|
|
2658
|
+
run: () => {
|
|
2659
|
+
if (scope.disposed || currentVersion !== registrationVersion) {
|
|
2660
|
+
return;
|
|
2661
|
+
}
|
|
2662
|
+
applyRegistration(snapshot);
|
|
2663
|
+
}
|
|
2664
|
+
});
|
|
2665
|
+
};
|
|
2666
|
+
scope.add(() => {
|
|
2667
|
+
registrationVersion += 1;
|
|
2668
|
+
context.instance.unregisterRules(name);
|
|
2669
|
+
context.instance.setFieldError(name, []);
|
|
2670
|
+
registered.value = false;
|
|
2671
|
+
});
|
|
2672
|
+
const disposeEffect = createSignalEffect(() => {
|
|
2673
|
+
scheduleRegistration(readValidationProps());
|
|
2674
|
+
});
|
|
2675
|
+
scope.add(disposeEffect);
|
|
2676
|
+
const validate = async () => {
|
|
2677
|
+
validating.value = true;
|
|
2678
|
+
try {
|
|
2679
|
+
const result = await context.instance.validateField(name);
|
|
2680
|
+
return result;
|
|
2681
|
+
} finally {
|
|
2682
|
+
validating.value = false;
|
|
2683
|
+
}
|
|
2684
|
+
};
|
|
2685
|
+
const dispose = () => {
|
|
2686
|
+
scope.dispose();
|
|
2687
|
+
};
|
|
2688
|
+
return {
|
|
2689
|
+
registered,
|
|
2690
|
+
validating,
|
|
2691
|
+
validate,
|
|
2692
|
+
dispose
|
|
2693
|
+
};
|
|
2694
|
+
}
|
|
2695
|
+
function createLifecycleBus(initialListener) {
|
|
2696
|
+
const listeners = /* @__PURE__ */ new Set();
|
|
2697
|
+
if (initialListener) {
|
|
2698
|
+
listeners.add(initialListener);
|
|
2699
|
+
}
|
|
2700
|
+
const emit = (run, ...args) => {
|
|
2701
|
+
for (const listener of Array.from(listeners)) {
|
|
2702
|
+
run(listener, ...args);
|
|
2703
|
+
}
|
|
2704
|
+
};
|
|
2705
|
+
const on = (listener) => {
|
|
2706
|
+
listeners.add(listener);
|
|
2707
|
+
return () => {
|
|
2708
|
+
listeners.delete(listener);
|
|
2709
|
+
};
|
|
2710
|
+
};
|
|
2711
|
+
const emitMount = (node) => {
|
|
2712
|
+
emit((listener, currentNode) => {
|
|
2713
|
+
var _a, _b;
|
|
2714
|
+
(_a = listener.mount) == null ? void 0 : _a.call(listener, currentNode);
|
|
2715
|
+
(_b = listener.mounted) == null ? void 0 : _b.call(listener, currentNode);
|
|
2716
|
+
}, node);
|
|
2717
|
+
};
|
|
2718
|
+
const emitBeforeMount = (node) => {
|
|
2719
|
+
emit((listener, currentNode) => {
|
|
2720
|
+
var _a;
|
|
2721
|
+
(_a = listener.beforeMount) == null ? void 0 : _a.call(listener, currentNode);
|
|
2722
|
+
}, node);
|
|
2723
|
+
};
|
|
2724
|
+
const emitUpdate = (node, previousNode) => {
|
|
2725
|
+
emit(
|
|
2726
|
+
(listener, currentNode, currentPreviousNode) => {
|
|
2727
|
+
var _a;
|
|
2728
|
+
(_a = listener.update) == null ? void 0 : _a.call(listener, currentNode, currentPreviousNode);
|
|
2729
|
+
},
|
|
2730
|
+
node,
|
|
2731
|
+
previousNode
|
|
2732
|
+
);
|
|
2733
|
+
};
|
|
2734
|
+
const emitBeforeUpdate = (node, previousNode) => {
|
|
2735
|
+
emit(
|
|
2736
|
+
(listener, currentNode, currentPreviousNode) => {
|
|
2737
|
+
var _a;
|
|
2738
|
+
(_a = listener.beforeUpdate) == null ? void 0 : _a.call(listener, currentNode, currentPreviousNode);
|
|
2739
|
+
},
|
|
2740
|
+
node,
|
|
2741
|
+
previousNode
|
|
2742
|
+
);
|
|
2743
|
+
};
|
|
2744
|
+
const emitUpdated = (node, previousNode) => {
|
|
2745
|
+
emit(
|
|
2746
|
+
(listener, currentNode, currentPreviousNode) => {
|
|
2747
|
+
var _a;
|
|
2748
|
+
(_a = listener.updated) == null ? void 0 : _a.call(listener, currentNode, currentPreviousNode);
|
|
2749
|
+
},
|
|
2750
|
+
node,
|
|
2751
|
+
previousNode
|
|
2752
|
+
);
|
|
2753
|
+
};
|
|
2754
|
+
const emitBeforeUnmount = (node) => {
|
|
2755
|
+
emit((listener, currentNode) => {
|
|
2756
|
+
var _a;
|
|
2757
|
+
(_a = listener.beforeUnmount) == null ? void 0 : _a.call(listener, currentNode);
|
|
2758
|
+
}, node);
|
|
2759
|
+
};
|
|
2760
|
+
const emitUnmount = (node) => {
|
|
2761
|
+
emit((listener, currentNode) => {
|
|
2762
|
+
var _a, _b;
|
|
2763
|
+
(_a = listener.unmount) == null ? void 0 : _a.call(listener, currentNode);
|
|
2764
|
+
(_b = listener.unmounted) == null ? void 0 : _b.call(listener, currentNode);
|
|
2765
|
+
}, node);
|
|
2766
|
+
};
|
|
2767
|
+
const clear = () => {
|
|
2768
|
+
listeners.clear();
|
|
2769
|
+
};
|
|
2770
|
+
return {
|
|
2771
|
+
on,
|
|
2772
|
+
emitMount,
|
|
2773
|
+
emitBeforeMount,
|
|
2774
|
+
emitUpdate,
|
|
2775
|
+
emitBeforeUpdate,
|
|
2776
|
+
emitUpdated,
|
|
2777
|
+
emitBeforeUnmount,
|
|
2778
|
+
emitUnmount,
|
|
2779
|
+
clear
|
|
2780
|
+
};
|
|
2781
|
+
}
|
|
2782
|
+
const createLifecycle = createLifecycleBus;
|
|
2783
|
+
function defaultGetChildren(node) {
|
|
2784
|
+
return node.children;
|
|
2785
|
+
}
|
|
2786
|
+
function findNodeBFS(tree, predicate, options = {}) {
|
|
2787
|
+
const getChildren = options.getChildren ?? defaultGetChildren;
|
|
2788
|
+
const queue = Array.isArray(tree) ? [...tree] : [tree];
|
|
2789
|
+
let index = 0;
|
|
2790
|
+
while (index < queue.length) {
|
|
2791
|
+
const node = queue[index];
|
|
2792
|
+
index++;
|
|
2793
|
+
if (predicate(node)) {
|
|
2794
|
+
return node;
|
|
2795
|
+
}
|
|
2796
|
+
const children = getChildren(node);
|
|
2797
|
+
if (children == null ? void 0 : children.length) {
|
|
2798
|
+
queue.push(...children);
|
|
2799
|
+
}
|
|
2800
|
+
}
|
|
2801
|
+
return void 0;
|
|
2802
|
+
}
|
|
2803
|
+
function hasDescriptor(node) {
|
|
2804
|
+
return node.type !== "root";
|
|
2805
|
+
}
|
|
2806
|
+
function isRootRuntimeNode(node) {
|
|
2807
|
+
return node.type === "root";
|
|
2808
|
+
}
|
|
2809
|
+
function isFieldRuntimeNode(node) {
|
|
2810
|
+
return (node == null ? void 0 : node.type) === "field";
|
|
2811
|
+
}
|
|
2812
|
+
function isGroupRuntimeNode(node) {
|
|
2813
|
+
return (node == null ? void 0 : node.type) === "group";
|
|
2814
|
+
}
|
|
2815
|
+
function isDependencyRuntimeNode(node) {
|
|
2816
|
+
return (node == null ? void 0 : node.type) === "dependency";
|
|
2817
|
+
}
|
|
2818
|
+
function isContainerRuntimeNode(node) {
|
|
2819
|
+
return node.type === "root" || node.type === "group" || node.type === "dependency";
|
|
2820
|
+
}
|
|
2821
|
+
function getChildRuntimeNodes(node) {
|
|
2822
|
+
if (isRootRuntimeNode(node) || isGroupRuntimeNode(node)) {
|
|
2823
|
+
return node.childNodes;
|
|
2824
|
+
}
|
|
2825
|
+
if (isDependencyRuntimeNode(node)) {
|
|
2826
|
+
return node.dynamicChildNodes;
|
|
2827
|
+
}
|
|
2828
|
+
return [];
|
|
2829
|
+
}
|
|
2830
|
+
function setChildRuntimeNodes(node, children) {
|
|
2831
|
+
if (isRootRuntimeNode(node) || isGroupRuntimeNode(node)) {
|
|
2832
|
+
node.childNodes = children;
|
|
2833
|
+
return;
|
|
2834
|
+
}
|
|
2835
|
+
if (isDependencyRuntimeNode(node)) {
|
|
2836
|
+
node.dynamicChildNodes = children;
|
|
2837
|
+
return;
|
|
2838
|
+
}
|
|
2839
|
+
}
|
|
2840
|
+
function findFieldRuntimeNode(root, name) {
|
|
2841
|
+
return findNodeBFS(
|
|
2842
|
+
root,
|
|
2843
|
+
(node) => isFieldRuntimeNode(node) && node.descriptor.name === name,
|
|
2844
|
+
{
|
|
2845
|
+
getChildren: (node) => getChildRuntimeNodes(node)
|
|
2846
|
+
}
|
|
2847
|
+
);
|
|
2848
|
+
}
|
|
2849
|
+
class RuntimeReconciler {
|
|
2850
|
+
constructor(runtimeNodeManager) {
|
|
2851
|
+
__publicField(this, "runtimeNodeManager");
|
|
2852
|
+
this.runtimeNodeManager = runtimeNodeManager;
|
|
2853
|
+
}
|
|
2854
|
+
/**
|
|
2855
|
+
* 将容器 RuntimeNode 的子节点更新为目标 descriptor 列表。
|
|
2856
|
+
*
|
|
2857
|
+
* @param parentNode - 承载子节点的 RuntimeNode。
|
|
2858
|
+
* @param descriptors - 新一轮编译后的子节点描述符。
|
|
2859
|
+
* @returns 子节点结构是否发生可观测变化(新增、移除、类型变更或子树变动)。
|
|
2860
|
+
*
|
|
2861
|
+
* @remarks
|
|
2862
|
+
* 同 key 且同 type 的 RuntimeNode 会被复用;不同 type 即使 key 相同也会重建。
|
|
2863
|
+
* 新子节点会先提交到 parent,再销毁被移除的旧节点,避免 cleanup 或视图投影
|
|
2864
|
+
* 期间仍读取到过期结构。`viewRevision` 由外层 commit boundary 统一推进。
|
|
2865
|
+
*/
|
|
2866
|
+
reconcileChildren(parentNode, descriptors) {
|
|
2867
|
+
return this.reconcileChildrenTree(parentNode, descriptors);
|
|
2868
|
+
}
|
|
2869
|
+
reconcileChildrenTree(parentNode, descriptors) {
|
|
2870
|
+
const previousByKey = new Map(
|
|
2871
|
+
getChildRuntimeNodes(parentNode).map((node) => [node.key, node])
|
|
2872
|
+
);
|
|
2873
|
+
const next = [];
|
|
2874
|
+
const groups = [];
|
|
2875
|
+
let changed = false;
|
|
2876
|
+
for (const descriptor of descriptors) {
|
|
2877
|
+
const existingNode = previousByKey.get(descriptor.key);
|
|
2878
|
+
if (existingNode && existingNode.type === descriptor.type) {
|
|
2879
|
+
previousByKey.delete(descriptor.key);
|
|
2880
|
+
existingNode.parent = parentNode;
|
|
2881
|
+
this.runtimeNodeManager.update(existingNode, descriptor);
|
|
2882
|
+
next.push(existingNode);
|
|
2883
|
+
if (isGroupDescriptor(descriptor)) {
|
|
2884
|
+
groups.push({ node: existingNode, descriptor });
|
|
2885
|
+
}
|
|
2886
|
+
continue;
|
|
2887
|
+
}
|
|
2888
|
+
changed = true;
|
|
2889
|
+
const node = this.runtimeNodeManager.create(descriptor, parentNode);
|
|
2890
|
+
this.runtimeNodeManager.mount(node);
|
|
2891
|
+
next.push(node);
|
|
2892
|
+
if (isGroupDescriptor(descriptor)) {
|
|
2893
|
+
groups.push({ node, descriptor });
|
|
2894
|
+
}
|
|
2895
|
+
}
|
|
2896
|
+
setChildRuntimeNodes(parentNode, next);
|
|
2897
|
+
for (const { node, descriptor } of groups) {
|
|
2898
|
+
if (isGroupDescriptor(descriptor)) {
|
|
2899
|
+
if (this.reconcileChildrenTree(node, descriptor.children)) {
|
|
2900
|
+
changed = true;
|
|
2901
|
+
}
|
|
2902
|
+
}
|
|
2903
|
+
}
|
|
2904
|
+
if (previousByKey.size > 0) {
|
|
2905
|
+
changed = true;
|
|
2906
|
+
}
|
|
2907
|
+
for (const removed of previousByKey.values()) {
|
|
2908
|
+
this.runtimeNodeManager.disposeTree(removed);
|
|
2909
|
+
}
|
|
2910
|
+
return changed;
|
|
2911
|
+
}
|
|
2912
|
+
}
|
|
2913
|
+
function createReconciler(runtimeNodeManager) {
|
|
2914
|
+
return new RuntimeReconciler(runtimeNodeManager);
|
|
2915
|
+
}
|
|
2916
|
+
function createScope() {
|
|
2917
|
+
let disposed = false;
|
|
2918
|
+
const cleanupRecords = [];
|
|
2919
|
+
const childScopes = [];
|
|
2920
|
+
const add = (cleanup) => {
|
|
2921
|
+
if (disposed) {
|
|
2922
|
+
runCleanup(cleanup);
|
|
2923
|
+
return createDisposedHandle();
|
|
2924
|
+
}
|
|
2925
|
+
const record = {
|
|
2926
|
+
cleanup,
|
|
2927
|
+
disposed: false
|
|
2928
|
+
};
|
|
2929
|
+
cleanupRecords.push(record);
|
|
2930
|
+
const disposeCleanup = () => {
|
|
2931
|
+
if (record.disposed) {
|
|
2932
|
+
return;
|
|
2933
|
+
}
|
|
2934
|
+
record.disposed = true;
|
|
2935
|
+
removeItem(cleanupRecords, record);
|
|
2936
|
+
runCleanup(record.cleanup);
|
|
2937
|
+
};
|
|
2938
|
+
return {
|
|
2939
|
+
get disposed() {
|
|
2940
|
+
return record.disposed;
|
|
2941
|
+
},
|
|
2942
|
+
dispose: disposeCleanup
|
|
2943
|
+
};
|
|
2944
|
+
};
|
|
2945
|
+
const child = () => {
|
|
2946
|
+
const childScope = createScope();
|
|
2947
|
+
childScopes.push(childScope);
|
|
2948
|
+
childScope.add(() => {
|
|
2949
|
+
removeItem(childScopes, childScope);
|
|
2950
|
+
});
|
|
2951
|
+
return childScope;
|
|
2952
|
+
};
|
|
2953
|
+
const disposeScope = () => {
|
|
2954
|
+
if (disposed) {
|
|
2955
|
+
return;
|
|
2956
|
+
}
|
|
2957
|
+
disposed = true;
|
|
2958
|
+
for (const childScope of childScopes.slice().reverse()) {
|
|
2959
|
+
childScope.dispose();
|
|
2960
|
+
}
|
|
2961
|
+
childScopes.length = 0;
|
|
2962
|
+
for (const record of cleanupRecords.slice().reverse()) {
|
|
2963
|
+
if (!record.disposed) {
|
|
2964
|
+
record.disposed = true;
|
|
2965
|
+
runCleanup(record.cleanup);
|
|
2966
|
+
}
|
|
2967
|
+
}
|
|
2968
|
+
cleanupRecords.length = 0;
|
|
2969
|
+
};
|
|
2970
|
+
return {
|
|
2971
|
+
get disposed() {
|
|
2972
|
+
return disposed;
|
|
2973
|
+
},
|
|
2974
|
+
add,
|
|
2975
|
+
child,
|
|
2976
|
+
dispose: disposeScope
|
|
2977
|
+
};
|
|
2978
|
+
}
|
|
2979
|
+
const createDisposedHandle = () => {
|
|
2980
|
+
return {
|
|
2981
|
+
disposed: true,
|
|
2982
|
+
dispose: noop
|
|
2983
|
+
};
|
|
2984
|
+
};
|
|
2985
|
+
const noop = () => {
|
|
2986
|
+
};
|
|
2987
|
+
const removeItem = (items, item) => {
|
|
2988
|
+
const index = items.indexOf(item);
|
|
2989
|
+
if (index >= 0) {
|
|
2990
|
+
items.splice(index, 1);
|
|
2991
|
+
}
|
|
2992
|
+
};
|
|
2993
|
+
const runCleanup = (cleanup) => {
|
|
2994
|
+
try {
|
|
2995
|
+
cleanup();
|
|
2996
|
+
} catch (error) {
|
|
2997
|
+
reportRuntimeCleanupError(error);
|
|
2998
|
+
}
|
|
2999
|
+
};
|
|
3000
|
+
function reportRuntimeCleanupError(error) {
|
|
3001
|
+
console.error("[Scope] Cleanup error:", error);
|
|
3002
|
+
}
|
|
3003
|
+
class DefaultRuntimeNodeManager {
|
|
3004
|
+
constructor(context) {
|
|
3005
|
+
__publicField(this, "nextId", 1);
|
|
3006
|
+
__publicField(this, "context");
|
|
3007
|
+
__publicField(this, "instance");
|
|
3008
|
+
__publicField(this, "fieldRegistry");
|
|
3009
|
+
__publicField(this, "lifecycleBus");
|
|
3010
|
+
this.context = context;
|
|
3011
|
+
this.fieldRegistry = context.fieldRegistry;
|
|
3012
|
+
this.instance = context.instance;
|
|
3013
|
+
this.lifecycleBus = context.lifecycleBus;
|
|
3014
|
+
}
|
|
3015
|
+
/**
|
|
3016
|
+
* 创建透明根 RuntimeNode。
|
|
3017
|
+
*
|
|
3018
|
+
* @returns root RuntimeNode,不对应任何表单 descriptor。
|
|
3019
|
+
*/
|
|
3020
|
+
createRoot() {
|
|
3021
|
+
return {
|
|
3022
|
+
id: 0,
|
|
3023
|
+
key: "schemx:root",
|
|
3024
|
+
type: "root",
|
|
3025
|
+
parent: null,
|
|
3026
|
+
scope: createScope(),
|
|
3027
|
+
disposed: createSignal(false),
|
|
3028
|
+
mounted: createSignal(false),
|
|
3029
|
+
childNodes: []
|
|
3030
|
+
};
|
|
3031
|
+
}
|
|
3032
|
+
/**
|
|
3033
|
+
* 根据 descriptor 创建单个未挂载 RuntimeNode。
|
|
3034
|
+
*
|
|
3035
|
+
* @param descriptor - 编译后的表单节点描述符。
|
|
3036
|
+
* @param parent - 新 RuntimeNode 所属的容器 RuntimeNode。
|
|
3037
|
+
*/
|
|
3038
|
+
create(descriptor, parent) {
|
|
3039
|
+
if (descriptor.type === "field") {
|
|
3040
|
+
return this.createField(descriptor, parent);
|
|
3041
|
+
}
|
|
3042
|
+
if (descriptor.type === "group") {
|
|
3043
|
+
return this.createGroup(descriptor, parent);
|
|
3044
|
+
}
|
|
3045
|
+
if (descriptor.type === "dependency") {
|
|
3046
|
+
return this.createDependency(descriptor, parent);
|
|
3047
|
+
}
|
|
3048
|
+
throwUnknownDescriptor(descriptor);
|
|
3049
|
+
}
|
|
3050
|
+
/**
|
|
3051
|
+
* 挂载单个 RuntimeNode 的运行期资源。
|
|
3052
|
+
*
|
|
3053
|
+
* @param node - 要挂载的 RuntimeNode。
|
|
3054
|
+
*
|
|
3055
|
+
* @remarks
|
|
3056
|
+
* Group RuntimeNode 只表示结构,不会创建领域资源;Field 和 Dependency 会在这里
|
|
3057
|
+
* 创建各自的模型、effect 与资源 scope。
|
|
3058
|
+
*/
|
|
3059
|
+
mount(node) {
|
|
3060
|
+
if (!hasDescriptor(node)) {
|
|
3061
|
+
return;
|
|
3062
|
+
}
|
|
3063
|
+
this.lifecycleBus.emitBeforeMount(node);
|
|
3064
|
+
switch (node.type) {
|
|
3065
|
+
case "field":
|
|
3066
|
+
this.mountField(node);
|
|
3067
|
+
break;
|
|
3068
|
+
case "group":
|
|
3069
|
+
this.mountGroup(node);
|
|
3070
|
+
break;
|
|
3071
|
+
case "dependency":
|
|
3072
|
+
this.mountDependency(node);
|
|
3073
|
+
break;
|
|
3074
|
+
}
|
|
3075
|
+
node.mounted.value = true;
|
|
3076
|
+
this.lifecycleBus.emitMount(node);
|
|
3077
|
+
}
|
|
3078
|
+
/**
|
|
3079
|
+
* 更新单个 RuntimeNode 的 descriptor 快照和运行期资源。
|
|
3080
|
+
*
|
|
3081
|
+
* @param node - 要更新的 RuntimeNode。
|
|
3082
|
+
* @param next - 更新后的表单 descriptor。
|
|
3083
|
+
*
|
|
3084
|
+
* @remarks
|
|
3085
|
+
* descriptor 快照会先写入 RuntimeNode,再由具体 update 分支决定复用还是重启资源。
|
|
3086
|
+
* 结构层面的 children reconcile 不在这里处理。
|
|
3087
|
+
*/
|
|
3088
|
+
update(node, next) {
|
|
3089
|
+
if (!hasDescriptor(node)) {
|
|
3090
|
+
return;
|
|
3091
|
+
}
|
|
3092
|
+
switch (node.type) {
|
|
3093
|
+
case "field": {
|
|
3094
|
+
if (!isFieldDescriptor(next)) {
|
|
3095
|
+
throwUnexpectedDescriptor(node, next);
|
|
3096
|
+
}
|
|
3097
|
+
const previousNode = createPreviousRuntimeNodeSnapshot(node);
|
|
3098
|
+
this.lifecycleBus.emitBeforeUpdate(node, previousNode);
|
|
3099
|
+
node.descriptor = next;
|
|
3100
|
+
this.updateField(node, previousNode);
|
|
3101
|
+
this.lifecycleBus.emitUpdate(node, previousNode);
|
|
3102
|
+
this.lifecycleBus.emitUpdated(node, previousNode);
|
|
3103
|
+
break;
|
|
3104
|
+
}
|
|
3105
|
+
case "group": {
|
|
3106
|
+
if (!isGroupDescriptor(next)) {
|
|
3107
|
+
throwUnexpectedDescriptor(node, next);
|
|
3108
|
+
}
|
|
3109
|
+
const previousNode = createPreviousRuntimeNodeSnapshot(node);
|
|
3110
|
+
this.lifecycleBus.emitBeforeUpdate(node, previousNode);
|
|
3111
|
+
node.descriptor = next;
|
|
3112
|
+
this.updateGroup(node, next);
|
|
3113
|
+
this.lifecycleBus.emitUpdate(node, previousNode);
|
|
3114
|
+
this.lifecycleBus.emitUpdated(node, previousNode);
|
|
3115
|
+
break;
|
|
3116
|
+
}
|
|
3117
|
+
case "dependency": {
|
|
3118
|
+
if (!isDependencyDescriptor(next)) {
|
|
3119
|
+
throwUnexpectedDescriptor(node, next);
|
|
3120
|
+
}
|
|
3121
|
+
const previousNode = createPreviousRuntimeNodeSnapshot(node);
|
|
3122
|
+
this.lifecycleBus.emitBeforeUpdate(node, previousNode);
|
|
3123
|
+
node.descriptor = next;
|
|
3124
|
+
this.updateDependency(node, previousNode);
|
|
3125
|
+
this.lifecycleBus.emitUpdate(node, previousNode);
|
|
3126
|
+
this.lifecycleBus.emitUpdated(node, previousNode);
|
|
3127
|
+
break;
|
|
3128
|
+
}
|
|
3129
|
+
}
|
|
3130
|
+
}
|
|
3131
|
+
/**
|
|
3132
|
+
* 卸载单个 RuntimeNode 的运行期资源。
|
|
3133
|
+
*
|
|
3134
|
+
* @param node - 要卸载的 RuntimeNode。
|
|
3135
|
+
*
|
|
3136
|
+
* @remarks
|
|
3137
|
+
* 这个方法不递归销毁子节点;需要销毁整棵子树时使用 `disposeTree`。
|
|
3138
|
+
*/
|
|
3139
|
+
unmount(node) {
|
|
3140
|
+
if (!hasDescriptor(node)) {
|
|
3141
|
+
return;
|
|
3142
|
+
}
|
|
3143
|
+
switch (node.type) {
|
|
3144
|
+
case "field":
|
|
3145
|
+
this.unmountField(node);
|
|
3146
|
+
break;
|
|
3147
|
+
case "group":
|
|
3148
|
+
this.unmountGroup(node);
|
|
3149
|
+
break;
|
|
3150
|
+
case "dependency":
|
|
3151
|
+
this.unmountDependency(node);
|
|
3152
|
+
break;
|
|
3153
|
+
}
|
|
3154
|
+
node.mounted.value = false;
|
|
3155
|
+
}
|
|
3156
|
+
/**
|
|
3157
|
+
* 递归销毁 RuntimeNode 子树。
|
|
3158
|
+
*
|
|
3159
|
+
* @param node - 要销毁的子树根 RuntimeNode。
|
|
3160
|
+
*
|
|
3161
|
+
* @remarks
|
|
3162
|
+
* 销毁顺序是:标记 disposed、递归销毁 runtime 子节点、卸载自身领域资源、
|
|
3163
|
+
* 释放 RuntimeNode scope、断开 parent。这样可以确保子资源先于父资源释放。
|
|
3164
|
+
*/
|
|
3165
|
+
disposeTree(node) {
|
|
3166
|
+
if (node.disposed.value) {
|
|
3167
|
+
return;
|
|
3168
|
+
}
|
|
3169
|
+
if (node.type !== "root") {
|
|
3170
|
+
this.lifecycleBus.emitBeforeUnmount(node);
|
|
3171
|
+
}
|
|
3172
|
+
node.disposed.value = true;
|
|
3173
|
+
if (isContainerRuntimeNode(node)) {
|
|
3174
|
+
for (const child of getChildRuntimeNodes(node)) {
|
|
3175
|
+
this.disposeTree(child);
|
|
3176
|
+
}
|
|
3177
|
+
setChildRuntimeNodes(node, []);
|
|
3178
|
+
}
|
|
3179
|
+
this.unmount(node);
|
|
3180
|
+
node.scope.dispose();
|
|
3181
|
+
node.parent = null;
|
|
3182
|
+
if (node.type !== "root") {
|
|
3183
|
+
this.lifecycleBus.emitUnmount(node);
|
|
3184
|
+
}
|
|
3185
|
+
}
|
|
3186
|
+
createField(descriptor, parent) {
|
|
3187
|
+
const fieldModel = createFieldModel(descriptor);
|
|
3188
|
+
const node = {
|
|
3189
|
+
id: this.nextId++,
|
|
3190
|
+
key: descriptor.key,
|
|
3191
|
+
type: descriptor.type,
|
|
3192
|
+
parent,
|
|
3193
|
+
scope: parent.scope.child(),
|
|
3194
|
+
disposed: createSignal(false),
|
|
3195
|
+
mounted: createSignal(false),
|
|
3196
|
+
descriptor,
|
|
3197
|
+
fieldModel,
|
|
3198
|
+
fieldResourceScope: null,
|
|
3199
|
+
fieldDependenciesScope: null
|
|
3200
|
+
};
|
|
3201
|
+
return node;
|
|
3202
|
+
}
|
|
3203
|
+
createGroup(descriptor, parent) {
|
|
3204
|
+
const node = {
|
|
3205
|
+
id: this.nextId++,
|
|
3206
|
+
key: descriptor.key,
|
|
3207
|
+
type: descriptor.type,
|
|
3208
|
+
parent,
|
|
3209
|
+
scope: parent.scope.child(),
|
|
3210
|
+
disposed: createSignal(false),
|
|
3211
|
+
mounted: createSignal(false),
|
|
3212
|
+
descriptor,
|
|
3213
|
+
childNodes: []
|
|
3214
|
+
};
|
|
3215
|
+
return node;
|
|
3216
|
+
}
|
|
3217
|
+
createDependency(descriptor, parent) {
|
|
3218
|
+
const node = {
|
|
3219
|
+
id: this.nextId++,
|
|
3220
|
+
key: descriptor.key,
|
|
3221
|
+
type: descriptor.type,
|
|
3222
|
+
parent,
|
|
3223
|
+
scope: parent.scope.child(),
|
|
3224
|
+
disposed: createSignal(false),
|
|
3225
|
+
mounted: createSignal(false),
|
|
3226
|
+
descriptor,
|
|
3227
|
+
dependencySlot: null,
|
|
3228
|
+
dependencyResourceScope: null,
|
|
3229
|
+
dynamicChildNodes: []
|
|
3230
|
+
};
|
|
3231
|
+
return node;
|
|
3232
|
+
}
|
|
3233
|
+
mountField(node) {
|
|
3234
|
+
const resourceScope = node.scope.child();
|
|
3235
|
+
const model = node.fieldModel;
|
|
3236
|
+
if (!model) {
|
|
3237
|
+
return;
|
|
3238
|
+
}
|
|
3239
|
+
this.initializeFieldValue(node);
|
|
3240
|
+
node.fieldResourceScope = resourceScope;
|
|
3241
|
+
this.fieldRegistry.register({
|
|
3242
|
+
name: node.descriptor.name,
|
|
3243
|
+
node,
|
|
3244
|
+
model
|
|
3245
|
+
});
|
|
3246
|
+
resourceScope.add(() => {
|
|
3247
|
+
this.fieldRegistry.unregister(node.descriptor.name, node);
|
|
3248
|
+
if (node.fieldResourceScope === resourceScope) {
|
|
3249
|
+
node.fieldResourceScope = null;
|
|
3250
|
+
}
|
|
3251
|
+
});
|
|
3252
|
+
this.mountFieldValidation(node, model, resourceScope);
|
|
3253
|
+
this.mountOrRestartFieldDependencies(node, model);
|
|
3254
|
+
}
|
|
3255
|
+
initializeFieldValue(node) {
|
|
3256
|
+
const { name, schema } = node.descriptor;
|
|
3257
|
+
if (!Object.hasOwn(schema, "initialValue") || this.instance.getFieldSnapshot(name) !== void 0) {
|
|
3258
|
+
return;
|
|
3259
|
+
}
|
|
3260
|
+
const values = {};
|
|
3261
|
+
setByPath(values, name, schema.initialValue);
|
|
3262
|
+
this.instance.setInitialValues(values);
|
|
3263
|
+
this.instance.setFieldValue(name, schema.initialValue);
|
|
3264
|
+
}
|
|
3265
|
+
mountGroup(_node) {
|
|
3266
|
+
}
|
|
3267
|
+
mountDependency(node) {
|
|
3268
|
+
createDependencyEffect({
|
|
3269
|
+
node,
|
|
3270
|
+
descriptor: node.descriptor,
|
|
3271
|
+
context: this.context
|
|
3272
|
+
});
|
|
3273
|
+
}
|
|
3274
|
+
updateField(node, previousNode) {
|
|
3275
|
+
const model = node.fieldModel;
|
|
3276
|
+
if (model && previousNode && previousNode.descriptor.name === node.descriptor.name) {
|
|
3277
|
+
updateFieldModel(model, node.descriptor);
|
|
3278
|
+
this.fieldRegistry.register({
|
|
3279
|
+
name: node.descriptor.name,
|
|
3280
|
+
node,
|
|
3281
|
+
model
|
|
3282
|
+
});
|
|
3283
|
+
this.mountOrRestartFieldDependencies(node, model);
|
|
3284
|
+
return;
|
|
3285
|
+
}
|
|
3286
|
+
this.unmountField(node);
|
|
3287
|
+
this.mountField(node);
|
|
3288
|
+
}
|
|
3289
|
+
updateGroup(_node, _descriptor) {
|
|
3290
|
+
}
|
|
3291
|
+
updateDependency(node, previousNode) {
|
|
3292
|
+
if (!node.dependencySlot || !previousNode || !isSameNamePathList(node.descriptor.trigger, previousNode == null ? void 0 : previousNode.descriptor.trigger)) {
|
|
3293
|
+
this.unmountDependency(node);
|
|
3294
|
+
this.mountDependency(node);
|
|
3295
|
+
}
|
|
3296
|
+
}
|
|
3297
|
+
mountFieldValidation(node, model = node.fieldModel, scope = node.fieldResourceScope) {
|
|
3298
|
+
if (!model || !scope) {
|
|
3299
|
+
return;
|
|
3300
|
+
}
|
|
3301
|
+
createValidationEffect({
|
|
3302
|
+
name: node.descriptor.name,
|
|
3303
|
+
fieldModel: model,
|
|
3304
|
+
context: this.context,
|
|
3305
|
+
scope
|
|
3306
|
+
});
|
|
3307
|
+
}
|
|
3308
|
+
mountOrRestartFieldDependencies(node, model = node.fieldModel) {
|
|
3309
|
+
var _a;
|
|
3310
|
+
(_a = node.fieldDependenciesScope) == null ? void 0 : _a.dispose();
|
|
3311
|
+
if (!model || !node.descriptor.dependencies) {
|
|
3312
|
+
node.fieldDependenciesScope = null;
|
|
3313
|
+
return;
|
|
3314
|
+
}
|
|
3315
|
+
const dependenciesScope = node.scope.child();
|
|
3316
|
+
node.fieldDependenciesScope = dependenciesScope;
|
|
3317
|
+
dependenciesScope.add(() => {
|
|
3318
|
+
if (node.fieldDependenciesScope === dependenciesScope) {
|
|
3319
|
+
node.fieldDependenciesScope = null;
|
|
3320
|
+
}
|
|
3321
|
+
});
|
|
3322
|
+
createDependenciesEffect({
|
|
3323
|
+
descriptor: node.descriptor,
|
|
3324
|
+
fieldModel: model,
|
|
3325
|
+
context: this.context,
|
|
3326
|
+
scope: dependenciesScope
|
|
3327
|
+
});
|
|
3328
|
+
}
|
|
3329
|
+
unmountField(node) {
|
|
3330
|
+
var _a, _b;
|
|
3331
|
+
(_a = node.fieldDependenciesScope) == null ? void 0 : _a.dispose();
|
|
3332
|
+
node.fieldDependenciesScope = null;
|
|
3333
|
+
(_b = node.fieldResourceScope) == null ? void 0 : _b.dispose();
|
|
3334
|
+
node.fieldResourceScope = null;
|
|
3335
|
+
}
|
|
3336
|
+
unmountGroup(_node) {
|
|
3337
|
+
}
|
|
3338
|
+
unmountDependency(node) {
|
|
3339
|
+
var _a;
|
|
3340
|
+
(_a = node.dependencyResourceScope) == null ? void 0 : _a.dispose();
|
|
3341
|
+
node.dependencyResourceScope = null;
|
|
3342
|
+
node.dependencySlot = null;
|
|
3343
|
+
}
|
|
3344
|
+
}
|
|
3345
|
+
function createRuntimeNodeManager(context) {
|
|
3346
|
+
return new DefaultRuntimeNodeManager(context);
|
|
3347
|
+
}
|
|
3348
|
+
function isSameNamePathList(a2, b2) {
|
|
3349
|
+
if (a2.length !== b2.length) {
|
|
3350
|
+
return false;
|
|
3351
|
+
}
|
|
3352
|
+
return a2.every((name, index) => name === b2[index]);
|
|
3353
|
+
}
|
|
3354
|
+
function createPreviousRuntimeNodeSnapshot(node) {
|
|
3355
|
+
return { ...node };
|
|
3356
|
+
}
|
|
3357
|
+
function throwUnknownDescriptor(descriptor) {
|
|
3358
|
+
throw new Error(`unknown type: ${descriptor.type ?? "unknown"}`);
|
|
3359
|
+
}
|
|
3360
|
+
function throwUnexpectedDescriptor(node, descriptor) {
|
|
3361
|
+
throw new Error(
|
|
3362
|
+
`unexpected descriptor type: node ${node.type} cannot update with ${descriptor.type}`
|
|
3363
|
+
);
|
|
3364
|
+
}
|
|
3365
|
+
const PRIORITY_ORDER = ["sync", "pre", "normal", "post"];
|
|
3366
|
+
function createScheduler() {
|
|
3367
|
+
const queues = new Map(
|
|
3368
|
+
PRIORITY_ORDER.map((priority) => [priority, /* @__PURE__ */ new Map()])
|
|
3369
|
+
);
|
|
3370
|
+
const idleResolvers = /* @__PURE__ */ new Set();
|
|
3371
|
+
let pendingAsync = 0;
|
|
3372
|
+
let disposed = false;
|
|
3373
|
+
let currentFlush = null;
|
|
3374
|
+
const flush = async () => {
|
|
3375
|
+
if (disposed) {
|
|
3376
|
+
return;
|
|
3377
|
+
}
|
|
3378
|
+
if (currentFlush) {
|
|
3379
|
+
return currentFlush;
|
|
3380
|
+
}
|
|
3381
|
+
currentFlush = flushOnce().finally(() => {
|
|
3382
|
+
currentFlush = null;
|
|
3383
|
+
notifyIdleIfNeeded();
|
|
3384
|
+
});
|
|
3385
|
+
return currentFlush;
|
|
3386
|
+
};
|
|
3387
|
+
const flushOnce = async () => {
|
|
3388
|
+
var _a, _b;
|
|
3389
|
+
const batch = takeBatch();
|
|
3390
|
+
for (const task of batch) {
|
|
3391
|
+
if (disposed || ((_a = task.scope) == null ? void 0 : _a.disposed)) {
|
|
3392
|
+
continue;
|
|
3393
|
+
}
|
|
3394
|
+
try {
|
|
3395
|
+
const result = task.run();
|
|
3396
|
+
if (isPromiseLike(result)) {
|
|
3397
|
+
await track(result);
|
|
3398
|
+
}
|
|
3399
|
+
} catch (error) {
|
|
3400
|
+
(_b = task.onError) == null ? void 0 : _b.call(task, error);
|
|
3401
|
+
}
|
|
3402
|
+
}
|
|
3403
|
+
};
|
|
3404
|
+
const schedule = (task) => {
|
|
3405
|
+
var _a, _b;
|
|
3406
|
+
if (disposed || ((_a = task.scope) == null ? void 0 : _a.disposed)) {
|
|
3407
|
+
return;
|
|
3408
|
+
}
|
|
3409
|
+
(_b = queues.get(task.priority)) == null ? void 0 : _b.set(task.id, task);
|
|
3410
|
+
queueMicrotask(() => void flush());
|
|
3411
|
+
};
|
|
3412
|
+
const takeBatch = () => {
|
|
3413
|
+
const batch = [];
|
|
3414
|
+
for (const priority of PRIORITY_ORDER) {
|
|
3415
|
+
const queue = queues.get(priority);
|
|
3416
|
+
if (!queue) {
|
|
3417
|
+
continue;
|
|
3418
|
+
}
|
|
3419
|
+
batch.push(...queue.values());
|
|
3420
|
+
queue.clear();
|
|
3421
|
+
}
|
|
3422
|
+
return batch;
|
|
3423
|
+
};
|
|
3424
|
+
const track = async (promise) => {
|
|
3425
|
+
pendingAsync += 1;
|
|
3426
|
+
try {
|
|
3427
|
+
return await promise;
|
|
3428
|
+
} finally {
|
|
3429
|
+
pendingAsync -= 1;
|
|
3430
|
+
notifyIdleIfNeeded();
|
|
3431
|
+
}
|
|
3432
|
+
};
|
|
3433
|
+
const whenIdle = (timeout = 1e4) => {
|
|
3434
|
+
if (isIdle()) {
|
|
3435
|
+
return Promise.resolve(true);
|
|
3436
|
+
}
|
|
3437
|
+
return new Promise((resolve) => {
|
|
3438
|
+
const timeoutId = globalThis.setTimeout(() => {
|
|
3439
|
+
idleResolvers.delete(resolve);
|
|
3440
|
+
resolve(false);
|
|
3441
|
+
}, timeout);
|
|
3442
|
+
idleResolvers.add((idle) => {
|
|
3443
|
+
globalThis.clearTimeout(timeoutId);
|
|
3444
|
+
resolve(idle);
|
|
3445
|
+
});
|
|
3446
|
+
});
|
|
3447
|
+
};
|
|
3448
|
+
const isIdle = () => {
|
|
3449
|
+
return !currentFlush && pendingAsync === 0 && !hasQueuedTasks();
|
|
3450
|
+
};
|
|
3451
|
+
const hasQueuedTasks = () => {
|
|
3452
|
+
return Array.from(queues.values()).some((queue) => queue.size > 0);
|
|
3453
|
+
};
|
|
3454
|
+
const notifyIdleIfNeeded = () => {
|
|
3455
|
+
if (!isIdle()) {
|
|
3456
|
+
return;
|
|
3457
|
+
}
|
|
3458
|
+
const resolvers = Array.from(idleResolvers);
|
|
3459
|
+
idleResolvers.clear();
|
|
3460
|
+
resolvers.forEach((resolve) => resolve(true));
|
|
3461
|
+
};
|
|
3462
|
+
const dispose = () => {
|
|
3463
|
+
disposed = true;
|
|
3464
|
+
queues.forEach((queue) => queue.clear());
|
|
3465
|
+
notifyIdleIfNeeded();
|
|
3466
|
+
};
|
|
3467
|
+
return {
|
|
3468
|
+
schedule,
|
|
3469
|
+
flush,
|
|
3470
|
+
whenIdle,
|
|
3471
|
+
track,
|
|
3472
|
+
dispose
|
|
3473
|
+
};
|
|
3474
|
+
}
|
|
3475
|
+
const isPromiseLike = (value) => {
|
|
3476
|
+
return value !== null && typeof value === "object" && "then" in value && typeof value.then === "function";
|
|
3477
|
+
};
|
|
3478
|
+
class StoreImpl {
|
|
3479
|
+
/**
|
|
3480
|
+
* 创建 Store 实例。
|
|
3481
|
+
*
|
|
3482
|
+
* 对 initialValues 进行深拷贝,确保内部状态与外部引用隔离。
|
|
3483
|
+
* 为每个初始字段路径创建对应的 reactive value。
|
|
3484
|
+
*
|
|
3485
|
+
* @param options - 配置选项
|
|
3486
|
+
*/
|
|
3487
|
+
constructor(options = {}) {
|
|
3488
|
+
__publicField(this, "fieldSignals", createFieldSignalMap());
|
|
3489
|
+
__publicField(this, "initialValues");
|
|
3490
|
+
const initialValues = options.initialValues ?? {};
|
|
3491
|
+
this.initialValues = cloneDeep(initialValues);
|
|
3492
|
+
const paths = collectObjectPathsByLeaf(initialValues);
|
|
3493
|
+
for (const path of paths) {
|
|
3494
|
+
const value = getByPath(initialValues, path);
|
|
3495
|
+
this.fieldSignals.set(
|
|
3496
|
+
path,
|
|
3497
|
+
createFieldSignal({
|
|
3498
|
+
value,
|
|
3499
|
+
initialValue: value
|
|
3500
|
+
})
|
|
3501
|
+
);
|
|
3502
|
+
}
|
|
3503
|
+
}
|
|
3504
|
+
getOrCreateFieldSignal(path) {
|
|
3505
|
+
const initialValue = getByPath(this.initialValues, path);
|
|
3506
|
+
let signal = this.fieldSignals.peek(path);
|
|
3507
|
+
if (!signal) {
|
|
3508
|
+
signal = createFieldSignal({
|
|
3509
|
+
value: initialValue,
|
|
3510
|
+
initialValue
|
|
3511
|
+
});
|
|
3512
|
+
this.fieldSignals.set(path, signal);
|
|
3513
|
+
}
|
|
3514
|
+
return signal;
|
|
3515
|
+
}
|
|
3516
|
+
/**
|
|
3517
|
+
* 获取指定路径的字段值。
|
|
3518
|
+
*
|
|
3519
|
+
* 读取对应 reactive value,在 effect 中使用时自动收集依赖。
|
|
3520
|
+
*
|
|
3521
|
+
* @param path - 字段路径,支持嵌套路径如 'user.name'
|
|
3522
|
+
* @returns 字段当前值
|
|
3523
|
+
*
|
|
3524
|
+
* @example
|
|
3525
|
+
* ```typescript
|
|
3526
|
+
* store.getFieldValue('name') // => 'John'
|
|
3527
|
+
* store.getFieldValue('user.address') // => { city: 'Beijing', zip: '100000' }
|
|
3528
|
+
* ```
|
|
3529
|
+
*/
|
|
3530
|
+
getFieldValue(path) {
|
|
3531
|
+
const signal = this.fieldSignals.get(path);
|
|
3532
|
+
return signal == null ? void 0 : signal.value.value;
|
|
3533
|
+
}
|
|
3534
|
+
/**
|
|
3535
|
+
* 设置指定路径的字段值。
|
|
3536
|
+
*
|
|
3537
|
+
* 直接写入对应 reactive value,自动触发依赖它的 effect。
|
|
3538
|
+
*
|
|
3539
|
+
* @param path - 字段路径
|
|
3540
|
+
* @param value - 要设置的值
|
|
3541
|
+
*
|
|
3542
|
+
* @example
|
|
3543
|
+
* ```typescript
|
|
3544
|
+
* store.setFieldValue('name', 'Jane')
|
|
3545
|
+
* store.setFieldValue('user.age', 30)
|
|
3546
|
+
* ```
|
|
3547
|
+
*/
|
|
3548
|
+
setFieldValue(path, value) {
|
|
3549
|
+
const signal = this.getOrCreateFieldSignal(path);
|
|
3550
|
+
signal.setValue(value);
|
|
3551
|
+
signal.setTouched(!isEqual(value, signal.initialValue.peek()));
|
|
3552
|
+
}
|
|
3553
|
+
getFieldsValue(paths) {
|
|
3554
|
+
const result = {};
|
|
3555
|
+
const pathsArr = paths ?? this.fieldSignals.keys();
|
|
3556
|
+
for (const path of pathsArr) {
|
|
3557
|
+
setByPath(result, path, this.getFieldValue(path));
|
|
3558
|
+
}
|
|
3559
|
+
return result;
|
|
3560
|
+
}
|
|
3561
|
+
/**
|
|
3562
|
+
* 批量设置多个字段的值。
|
|
3563
|
+
*
|
|
3564
|
+
* 批量设置多个字段;每个字段写入都会更新对应 FieldSignal。
|
|
3565
|
+
*
|
|
3566
|
+
* @param values - 要设置的字段值对象
|
|
3567
|
+
*
|
|
3568
|
+
* @example
|
|
3569
|
+
* ```typescript
|
|
3570
|
+
* store.setFieldsValue({ name: 'Bob', age: 30 })
|
|
3571
|
+
* ```
|
|
3572
|
+
*/
|
|
3573
|
+
setFieldsValue(values) {
|
|
3574
|
+
const paths = collectObjectPathsByLeaf(values);
|
|
3575
|
+
batchUpdates(() => {
|
|
3576
|
+
for (const path of paths) {
|
|
3577
|
+
this.setFieldValue(path, getByPath(values, path));
|
|
3578
|
+
}
|
|
3579
|
+
});
|
|
3580
|
+
}
|
|
3581
|
+
/**
|
|
3582
|
+
* 获取单个字段值的快照。
|
|
3583
|
+
*
|
|
3584
|
+
* 使用 signal.peek() 避免收集依赖,返回深拷贝的值。
|
|
3585
|
+
*
|
|
3586
|
+
* @param path - 字段路径
|
|
3587
|
+
*
|
|
3588
|
+
* @returns 该字段当前值的深拷贝
|
|
3589
|
+
*
|
|
3590
|
+
* @example
|
|
3591
|
+
* ```typescript
|
|
3592
|
+
* const name = store.getFieldSnapshot('name') // => 'John'(深拷贝)
|
|
3593
|
+
* ```
|
|
3594
|
+
*/
|
|
3595
|
+
getFieldSnapshot(path) {
|
|
3596
|
+
const signal = this.fieldSignals.peek(path);
|
|
3597
|
+
return signal == null ? void 0 : signal.value.peek();
|
|
3598
|
+
}
|
|
3599
|
+
getFieldsSnapshot(paths) {
|
|
3600
|
+
const result = {};
|
|
3601
|
+
const pathsArr = paths ?? this.fieldSignals.keys();
|
|
3602
|
+
for (const path of pathsArr) {
|
|
3603
|
+
setByPath(result, path, this.getFieldSnapshot(path));
|
|
3604
|
+
}
|
|
3605
|
+
return result;
|
|
3606
|
+
}
|
|
3607
|
+
/**
|
|
3608
|
+
* 获取指定字段的初始值。
|
|
3609
|
+
*
|
|
3610
|
+
* @param path - 字段路径
|
|
3611
|
+
* @returns 字段初始值,不存在时返回 undefined
|
|
3612
|
+
*
|
|
3613
|
+
* @example
|
|
3614
|
+
* ```typescript
|
|
3615
|
+
* store.getInitialValue('name') // => 'John'
|
|
3616
|
+
* ```
|
|
3617
|
+
*/
|
|
3618
|
+
getInitialValue(path) {
|
|
3619
|
+
const signal = this.fieldSignals.peek(path);
|
|
3620
|
+
if (signal) {
|
|
3621
|
+
return signal.initialValue.peek();
|
|
3622
|
+
}
|
|
3623
|
+
return getByPath(this.initialValues, path);
|
|
3624
|
+
}
|
|
3625
|
+
getInitialValues(paths) {
|
|
3626
|
+
if (paths === void 0) {
|
|
3627
|
+
return cloneDeep(this.initialValues);
|
|
3628
|
+
}
|
|
3629
|
+
const result = {};
|
|
3630
|
+
for (const path of paths) {
|
|
3631
|
+
setByPath(result, path, getByPath(this.initialValues, path));
|
|
3632
|
+
}
|
|
3633
|
+
return result;
|
|
3634
|
+
}
|
|
3635
|
+
/**
|
|
3636
|
+
* 设置指定字段的初始值。
|
|
3637
|
+
*
|
|
3638
|
+
* @param path - 字段路径
|
|
3639
|
+
* @param value - 要设置的初始值
|
|
3640
|
+
*
|
|
3641
|
+
* @example
|
|
3642
|
+
* ```typescript
|
|
3643
|
+
* store.setInitialValue('name', 'Bob')
|
|
3644
|
+
* ```
|
|
3645
|
+
*/
|
|
3646
|
+
setInitialValue(path, value) {
|
|
3647
|
+
setByPath(this.initialValues, path, value);
|
|
3648
|
+
const signal = this.getOrCreateFieldSignal(path);
|
|
3649
|
+
signal.setInitialValue(value);
|
|
3650
|
+
signal.setTouched(!isEqual(signal.value.peek(), signal.initialValue.peek()));
|
|
3651
|
+
}
|
|
3652
|
+
/**
|
|
3653
|
+
* 批量设置多个字段的初始值。
|
|
3654
|
+
*
|
|
3655
|
+
* @param values - 要设置的字段值对象
|
|
3656
|
+
*
|
|
3657
|
+
* @example
|
|
3658
|
+
* ```typescript
|
|
3659
|
+
* store.setInitialValues({ name: 'Bob', age: 30 })
|
|
3660
|
+
* ```
|
|
3661
|
+
*/
|
|
3662
|
+
setInitialValues(values) {
|
|
3663
|
+
const paths = collectObjectPathsByLeaf(values);
|
|
3664
|
+
if (!paths.length) return;
|
|
3665
|
+
batchUpdates(() => {
|
|
3666
|
+
for (const path of paths) {
|
|
3667
|
+
const next = getByPath(values, path);
|
|
3668
|
+
setByPath(this.initialValues, path, next);
|
|
3669
|
+
const signal = this.getOrCreateFieldSignal(path);
|
|
3670
|
+
signal.setInitialValue(next);
|
|
3671
|
+
signal.setTouched(!isEqual(signal.value.peek(), signal.initialValue.peek()));
|
|
3672
|
+
}
|
|
3673
|
+
});
|
|
3674
|
+
}
|
|
3675
|
+
/**
|
|
3676
|
+
* 检查指定字段是否被修改过。
|
|
3677
|
+
*
|
|
3678
|
+
* 通过深比较当前值与初始值判断。
|
|
3679
|
+
*
|
|
3680
|
+
* @param path - 字段路径
|
|
3681
|
+
* @returns 是否与初始值不同
|
|
3682
|
+
*
|
|
3683
|
+
* @example
|
|
3684
|
+
* ```typescript
|
|
3685
|
+
* store.setFieldValue('name', 'Jane')
|
|
3686
|
+
* store.isFieldTouched('name') // => true
|
|
3687
|
+
* ```
|
|
3688
|
+
*/
|
|
3689
|
+
isFieldTouched(path) {
|
|
3690
|
+
var _a;
|
|
3691
|
+
return ((_a = this.fieldSignals.get(path)) == null ? void 0 : _a.touched.value) ?? false;
|
|
3692
|
+
}
|
|
3693
|
+
isFieldsTouched(paths) {
|
|
3694
|
+
const pathsArr = paths ?? [...this.fieldSignals.keys()];
|
|
3695
|
+
return paths === void 0 ? pathsArr.some((path) => this.isFieldTouched(path)) : pathsArr.every((path) => this.isFieldTouched(path));
|
|
3696
|
+
}
|
|
3697
|
+
/**
|
|
3698
|
+
* 获取所有被修改的字段路径。
|
|
3699
|
+
*
|
|
3700
|
+
* 遍历所有 reactive values,与初始值比较,收集不同的路径。
|
|
3701
|
+
*
|
|
3702
|
+
* @returns 被修改的字段路径数组
|
|
3703
|
+
*
|
|
3704
|
+
* @example
|
|
3705
|
+
* ```typescript
|
|
3706
|
+
* store.getTouchedFields() // => ['name', 'user.age']
|
|
3707
|
+
* ```
|
|
3708
|
+
*/
|
|
3709
|
+
getTouchedFields() {
|
|
3710
|
+
const touchedFields = [];
|
|
3711
|
+
for (const [path, signal] of this.fieldSignals.entries()) {
|
|
3712
|
+
if (signal.touched.value) {
|
|
3713
|
+
touchedFields.push(path);
|
|
3714
|
+
}
|
|
3715
|
+
}
|
|
3716
|
+
return touchedFields;
|
|
3717
|
+
}
|
|
3718
|
+
/**
|
|
3719
|
+
* 设置字段的修改状态。
|
|
3720
|
+
*
|
|
3721
|
+
* @param path - 字段路径
|
|
3722
|
+
* @param touched - 是否被修改
|
|
3723
|
+
*
|
|
3724
|
+
* @example
|
|
3725
|
+
* ```typescript
|
|
3726
|
+
* store.setFieldTouched('name', true)
|
|
3727
|
+
* ```
|
|
3728
|
+
*/
|
|
3729
|
+
setFieldTouched(path, touched) {
|
|
3730
|
+
this.getOrCreateFieldSignal(path).setTouched(touched);
|
|
3731
|
+
}
|
|
3732
|
+
/**
|
|
3733
|
+
* 批量设置字段的修改状态。
|
|
3734
|
+
*
|
|
3735
|
+
* @param paths - 要设置 touched 状态的字段路径数组
|
|
3736
|
+
* @param touched - 目标 touched 状态,默认 true
|
|
3737
|
+
*
|
|
3738
|
+
* @example
|
|
3739
|
+
* ```typescript
|
|
3740
|
+
* store.setFieldsTouched(['name', 'age'], true)
|
|
3741
|
+
* ```
|
|
3742
|
+
*/
|
|
3743
|
+
setFieldsTouched(paths, touched = true) {
|
|
3744
|
+
batchUpdates(() => {
|
|
3745
|
+
for (const path of paths) {
|
|
3746
|
+
this.setFieldTouched(path, touched);
|
|
3747
|
+
}
|
|
3748
|
+
});
|
|
3749
|
+
}
|
|
3750
|
+
/**
|
|
3751
|
+
* 检查单个字段是否处于操作中。
|
|
3752
|
+
*
|
|
3753
|
+
* 读取对应 reactive value,在 effect 中使用时自动收集依赖。
|
|
3754
|
+
*
|
|
3755
|
+
* @param path - 字段路径
|
|
3756
|
+
* @returns 是否处于操作中
|
|
3757
|
+
*
|
|
3758
|
+
* @example
|
|
3759
|
+
* ```typescript
|
|
3760
|
+
* store.isFieldPending('avatar') // => true
|
|
3761
|
+
* ```
|
|
3762
|
+
*/
|
|
3763
|
+
isFieldPending(path) {
|
|
3764
|
+
var _a;
|
|
3765
|
+
return ((_a = this.fieldSignals.get(path)) == null ? void 0 : _a.pending.value) ?? false;
|
|
3766
|
+
}
|
|
3767
|
+
isFieldsPending(paths) {
|
|
3768
|
+
const pathsArr = paths ?? [...this.fieldSignals.keys()];
|
|
3769
|
+
return pathsArr.every((path) => this.isFieldPending(path));
|
|
3770
|
+
}
|
|
3771
|
+
/**
|
|
3772
|
+
* 获取所有处于操作中的字段路径。
|
|
3773
|
+
*
|
|
3774
|
+
* 遍历字段 signal,收集 pending 为 true 的字段路径。
|
|
3775
|
+
* 无操作中字段时返回空数组。
|
|
3776
|
+
*
|
|
3777
|
+
* @returns 操作中的字段路径数组
|
|
3778
|
+
*
|
|
3779
|
+
* @example
|
|
3780
|
+
* ```typescript
|
|
3781
|
+
* store.getPendingFields() // => ['avatar', 'attachment']
|
|
3782
|
+
* ```
|
|
3783
|
+
*/
|
|
3784
|
+
getPendingFields() {
|
|
3785
|
+
const fields = [];
|
|
3786
|
+
for (const [field, signal] of this.fieldSignals.entries()) {
|
|
3787
|
+
if (signal.pending.value) {
|
|
3788
|
+
fields.push({ field, message: signal.pendingMessage.peek() });
|
|
3789
|
+
}
|
|
3790
|
+
}
|
|
3791
|
+
return fields;
|
|
3792
|
+
}
|
|
3793
|
+
/**
|
|
3794
|
+
* 设置字段的操作中状态。
|
|
3795
|
+
*
|
|
3796
|
+
* 标记字段正在进行异步操作(如文件上传),
|
|
3797
|
+
* 校验和提交时会检查是否有字段处于操作中状态。
|
|
3798
|
+
* 取消操作中状态时删除对应 key,保持 map 干净。
|
|
3799
|
+
*
|
|
3800
|
+
* @param path - 字段路径
|
|
3801
|
+
* @param pending - 是否处于操作中
|
|
3802
|
+
* @param message - 可选的操作中提示信息。
|
|
3803
|
+
*
|
|
3804
|
+
* @example
|
|
3805
|
+
* ```typescript
|
|
3806
|
+
* store.setFieldPending('avatar', true) // 上传开始
|
|
3807
|
+
* store.setFieldPending('avatar', false) // 上传结束
|
|
3808
|
+
* ```
|
|
3809
|
+
*/
|
|
3810
|
+
setFieldPending(path, pending, message) {
|
|
3811
|
+
this.getOrCreateFieldSignal(path).setPending(pending, message);
|
|
3812
|
+
}
|
|
3813
|
+
/**
|
|
3814
|
+
* 批量设置字段的操作中状态。
|
|
3815
|
+
*
|
|
3816
|
+
* @param paths - 要设置 pending 状态的字段路径数组
|
|
3817
|
+
* @param pending - 目标 pending 状态,默认 true
|
|
3818
|
+
* @param message - 可选的操作中提示信息。
|
|
3819
|
+
*
|
|
3820
|
+
* @example
|
|
3821
|
+
* ```typescript
|
|
3822
|
+
* store.setFieldsPending(['name', 'age'], true)
|
|
3823
|
+
* ```
|
|
3824
|
+
*/
|
|
3825
|
+
setFieldsPending(paths, pending = true, message) {
|
|
3826
|
+
batchUpdates(() => {
|
|
3827
|
+
for (const path of paths) {
|
|
3828
|
+
this.setFieldPending(path, pending, message);
|
|
3829
|
+
}
|
|
3830
|
+
});
|
|
3831
|
+
}
|
|
3832
|
+
/**
|
|
3833
|
+
* 重置单个字段到初始值。
|
|
3834
|
+
*
|
|
3835
|
+
* @param path - 要重置的字段路径。
|
|
3836
|
+
*
|
|
3837
|
+
* @example
|
|
3838
|
+
* ```typescript
|
|
3839
|
+
* store.resetField('name')
|
|
3840
|
+
* ```
|
|
3841
|
+
*/
|
|
3842
|
+
resetField(path) {
|
|
3843
|
+
this.getOrCreateFieldSignal(path).reset();
|
|
3844
|
+
}
|
|
3845
|
+
/**
|
|
3846
|
+
* 批量重置指定字段到初始值。
|
|
3847
|
+
*
|
|
3848
|
+
* @param paths - 要重置的字段路径数组。
|
|
3849
|
+
*
|
|
3850
|
+
* @example
|
|
3851
|
+
* ```typescript
|
|
3852
|
+
* store.resetFields(['name', 'age'])
|
|
3853
|
+
* ```
|
|
3854
|
+
*/
|
|
3855
|
+
resetFields(paths) {
|
|
3856
|
+
batchUpdates(() => {
|
|
3857
|
+
for (const path of paths) {
|
|
3858
|
+
this.getOrCreateFieldSignal(path).reset();
|
|
3859
|
+
}
|
|
3860
|
+
});
|
|
3861
|
+
}
|
|
3862
|
+
/**
|
|
3863
|
+
* 重置表单到初始状态(diff 式更新)。
|
|
3864
|
+
*
|
|
3865
|
+
* 不传参时恢复到构造时的初始值,传入 values 时同时更新初始值。
|
|
3866
|
+
* 对比新旧路径集合:复用已有字段 signal、删除多余字段 signal、
|
|
3867
|
+
* 创建新字段 signal。
|
|
3868
|
+
*
|
|
3869
|
+
* @param values - 可选的新初始值;传入后会同时更新 initialValues baseline。
|
|
3870
|
+
*
|
|
3871
|
+
* @example
|
|
3872
|
+
* ```typescript
|
|
3873
|
+
* store.reset() // 恢复到构造时的初始值
|
|
3874
|
+
* store.reset({ name: 'New', age: 0 }) // 重置并更新初始值
|
|
3875
|
+
* ```
|
|
3876
|
+
*/
|
|
3877
|
+
reset(values) {
|
|
3878
|
+
const resetValues = cloneDeep(values ?? this.initialValues);
|
|
3879
|
+
const nextPaths = collectObjectPathsByLeaf(resetValues);
|
|
3880
|
+
const nextPathSet = new Set(nextPaths);
|
|
3881
|
+
batchUpdates(() => {
|
|
3882
|
+
for (const path of this.fieldSignals.keys()) {
|
|
3883
|
+
if (!nextPathSet.has(path)) {
|
|
3884
|
+
this.fieldSignals.delete(path);
|
|
3885
|
+
}
|
|
3886
|
+
}
|
|
3887
|
+
for (const path of nextPaths) {
|
|
3888
|
+
const next = getByPath(resetValues, path);
|
|
3889
|
+
setByPath(this.initialValues, path, next);
|
|
3890
|
+
const signal = this.fieldSignals.peek(path);
|
|
3891
|
+
if (signal) {
|
|
3892
|
+
signal.setInitialValue(next);
|
|
3893
|
+
signal.reset(next);
|
|
3894
|
+
} else {
|
|
3895
|
+
this.fieldSignals.set(
|
|
3896
|
+
path,
|
|
3897
|
+
createFieldSignal({
|
|
3898
|
+
value: next,
|
|
3899
|
+
initialValue: next
|
|
3900
|
+
})
|
|
3901
|
+
);
|
|
3902
|
+
}
|
|
3903
|
+
}
|
|
3904
|
+
});
|
|
3905
|
+
}
|
|
3906
|
+
/**
|
|
3907
|
+
* 销毁 Store 实例。
|
|
3908
|
+
*
|
|
3909
|
+
* 清理所有字段 signal,释放资源。
|
|
3910
|
+
*
|
|
3911
|
+
* @example
|
|
3912
|
+
* ```typescript
|
|
3913
|
+
* store.destroy()
|
|
3914
|
+
* ```
|
|
3915
|
+
*/
|
|
3916
|
+
destroy() {
|
|
3917
|
+
this.fieldSignals.clear();
|
|
3918
|
+
}
|
|
3919
|
+
}
|
|
3920
|
+
function createStore(options = {}) {
|
|
3921
|
+
return new StoreImpl(options);
|
|
3922
|
+
}
|
|
3923
|
+
const MAX_DEPTH = 100;
|
|
3924
|
+
function buildViewSchemas(root) {
|
|
3925
|
+
if (!root) {
|
|
3926
|
+
return [];
|
|
3927
|
+
}
|
|
3928
|
+
return buildRuntimeNodeChildren(getChildRuntimeNodes(root), 1);
|
|
3929
|
+
}
|
|
3930
|
+
function buildRuntimeNodeChildren(nodes, depth) {
|
|
3931
|
+
if (depth > MAX_DEPTH) {
|
|
3932
|
+
throw new RangeError(
|
|
3933
|
+
`buildViewSchemas: max depth ${MAX_DEPTH} exceeded at depth ${depth}`
|
|
3934
|
+
);
|
|
3935
|
+
}
|
|
3936
|
+
const results = [];
|
|
3937
|
+
for (const node of nodes) {
|
|
3938
|
+
const schema = buildRuntimeNodeSchema(node, depth);
|
|
3939
|
+
if (schema === null) {
|
|
3940
|
+
continue;
|
|
3941
|
+
}
|
|
3942
|
+
if (Array.isArray(schema)) {
|
|
3943
|
+
for (const child of schema) {
|
|
3944
|
+
results.push(child);
|
|
3945
|
+
}
|
|
3946
|
+
continue;
|
|
3947
|
+
}
|
|
3948
|
+
results.push(schema);
|
|
3949
|
+
}
|
|
3950
|
+
return results;
|
|
3951
|
+
}
|
|
3952
|
+
function buildRuntimeNodeSchema(node, depth) {
|
|
3953
|
+
if (node.disposed.value) {
|
|
3954
|
+
return null;
|
|
3955
|
+
}
|
|
3956
|
+
if (isGroupRuntimeNode(node)) {
|
|
3957
|
+
return buildGroupViewSchema(node, depth);
|
|
3958
|
+
}
|
|
3959
|
+
if (isDependencyRuntimeNode(node)) {
|
|
3960
|
+
return buildDependencyRuntimeNode(node, depth);
|
|
3961
|
+
}
|
|
3962
|
+
if (isFieldRuntimeNode(node)) {
|
|
3963
|
+
return buildFieldViewSchema(node);
|
|
3964
|
+
}
|
|
3965
|
+
return null;
|
|
3966
|
+
}
|
|
3967
|
+
function buildFieldViewSchema(node) {
|
|
3968
|
+
const descriptor = node.descriptor;
|
|
3969
|
+
const model = node.fieldModel;
|
|
3970
|
+
if (!model) {
|
|
3971
|
+
console.warn(
|
|
3972
|
+
`[buildViewSchemas] skipping field node "${node.key}": no FieldModel resource`
|
|
3973
|
+
);
|
|
3974
|
+
return null;
|
|
3975
|
+
}
|
|
3976
|
+
if ((descriptor == null ? void 0 : descriptor.type) !== "field") {
|
|
3977
|
+
return null;
|
|
3978
|
+
}
|
|
3979
|
+
const schema = descriptor.schema;
|
|
3980
|
+
const snapshot = model.snapshot.value;
|
|
3981
|
+
return {
|
|
3982
|
+
...schema,
|
|
3983
|
+
key: node.key,
|
|
3984
|
+
visible: snapshot.visible,
|
|
3985
|
+
label: snapshot.label,
|
|
3986
|
+
readonly: snapshot.readonly,
|
|
3987
|
+
disabled: snapshot.disabled,
|
|
3988
|
+
required: snapshot.required,
|
|
3989
|
+
placeholder: sanitizePlaceholder(snapshot.placeholder),
|
|
3990
|
+
componentProps: sanitizeComponentProps(snapshot.componentProps ?? {}),
|
|
3991
|
+
rules: snapshot.rules,
|
|
3992
|
+
validationTrigger: schema.validationTrigger,
|
|
3993
|
+
debug: buildDebugMeta(node)
|
|
3994
|
+
};
|
|
3995
|
+
}
|
|
3996
|
+
function buildGroupViewSchema(node, depth) {
|
|
3997
|
+
const children = buildRuntimeNodeChildren(
|
|
3998
|
+
getChildRuntimeNodes(node),
|
|
3999
|
+
depth + 1
|
|
4000
|
+
);
|
|
4001
|
+
const descriptor = node.descriptor;
|
|
4002
|
+
return {
|
|
4003
|
+
...descriptor.schema,
|
|
4004
|
+
key: node.key,
|
|
4005
|
+
children,
|
|
4006
|
+
debug: buildDebugMeta(node)
|
|
4007
|
+
};
|
|
4008
|
+
}
|
|
4009
|
+
function buildDependencyRuntimeNode(node, depth) {
|
|
4010
|
+
return buildRuntimeNodeChildren(getChildRuntimeNodes(node), depth + 1);
|
|
4011
|
+
}
|
|
4012
|
+
function sanitizePlaceholder(value) {
|
|
4013
|
+
return value.length > 1e3 ? value.slice(0, 1e3) : value;
|
|
4014
|
+
}
|
|
4015
|
+
function sanitizeComponentProps(props, depth = 0) {
|
|
4016
|
+
if (depth > 10) {
|
|
4017
|
+
return {};
|
|
4018
|
+
}
|
|
4019
|
+
const result = {};
|
|
4020
|
+
for (const key of Object.keys(props)) {
|
|
4021
|
+
if (!isValidPropKey(key)) {
|
|
4022
|
+
continue;
|
|
4023
|
+
}
|
|
4024
|
+
const value = props[key];
|
|
4025
|
+
if (value !== null && typeof value === "object" && !Array.isArray(value)) {
|
|
4026
|
+
result[key] = sanitizeComponentProps(value, depth + 1);
|
|
4027
|
+
} else {
|
|
4028
|
+
result[key] = value;
|
|
4029
|
+
}
|
|
4030
|
+
}
|
|
4031
|
+
return result;
|
|
4032
|
+
}
|
|
4033
|
+
function isValidPropKey(key) {
|
|
4034
|
+
if (/^[a-zA-Z_$][a-zA-Z0-9_$]*$/.test(key)) {
|
|
4035
|
+
return true;
|
|
4036
|
+
}
|
|
4037
|
+
if (/^[a-zA-Z0-9_-]+$/.test(key)) {
|
|
4038
|
+
return true;
|
|
4039
|
+
}
|
|
4040
|
+
return false;
|
|
4041
|
+
}
|
|
4042
|
+
function buildDebugMeta(node) {
|
|
4043
|
+
return {
|
|
4044
|
+
runtimeNodeId: node.id,
|
|
4045
|
+
runtimeNodeType: node.type,
|
|
4046
|
+
hasFieldModel: node.type === "field" && node.fieldModel !== void 0,
|
|
4047
|
+
hasDependencySlot: node.type === "dependency" && node.dependencySlot !== void 0
|
|
4048
|
+
};
|
|
4049
|
+
}
|
|
4050
|
+
function subscribeViewSchemas(root, revision, onChange) {
|
|
4051
|
+
let rootDisposed = false;
|
|
4052
|
+
const rootScope = root.scope;
|
|
4053
|
+
const disposeHandle = rootScope.add(() => {
|
|
4054
|
+
rootDisposed = true;
|
|
4055
|
+
});
|
|
4056
|
+
const disposeEffect = createDebouncedSignalEffect(
|
|
4057
|
+
() => {
|
|
4058
|
+
void revision.revision.value;
|
|
4059
|
+
return rootDisposed ? [] : buildViewSchemas(root);
|
|
4060
|
+
},
|
|
4061
|
+
(viewSchemas) => {
|
|
4062
|
+
try {
|
|
4063
|
+
onChange(viewSchemas);
|
|
4064
|
+
} catch (error) {
|
|
4065
|
+
console.error("[subscribeViewSchemas] onChange error:", error);
|
|
4066
|
+
}
|
|
4067
|
+
},
|
|
4068
|
+
16,
|
|
4069
|
+
{ immediate: true, edges: ["leading", "trailing"] }
|
|
4070
|
+
);
|
|
4071
|
+
const unsubscribe = () => {
|
|
4072
|
+
disposeEffect();
|
|
4073
|
+
disposeHandle.dispose();
|
|
4074
|
+
rootDisposed = false;
|
|
4075
|
+
};
|
|
4076
|
+
return unsubscribe;
|
|
4077
|
+
}
|
|
4078
|
+
function createViewRevision() {
|
|
4079
|
+
const revision = createSignal(0);
|
|
4080
|
+
const bump = () => {
|
|
4081
|
+
revision.value += 1;
|
|
4082
|
+
};
|
|
4083
|
+
return {
|
|
4084
|
+
revision,
|
|
4085
|
+
bump
|
|
4086
|
+
};
|
|
4087
|
+
}
|
|
4088
|
+
class CreateForm {
|
|
4089
|
+
constructor(options = {}) {
|
|
4090
|
+
__publicField(this, "context");
|
|
4091
|
+
__publicField(this, "callbacks");
|
|
4092
|
+
__publicField(this, "store");
|
|
4093
|
+
__publicField(this, "rendererRegistry");
|
|
4094
|
+
__publicField(this, "validatorRegistry");
|
|
4095
|
+
__publicField(this, "validator");
|
|
4096
|
+
__publicField(this, "root");
|
|
4097
|
+
__publicField(this, "scheduler");
|
|
4098
|
+
__publicField(this, "viewRevision");
|
|
4099
|
+
__publicField(this, "reconciler");
|
|
4100
|
+
__publicField(this, "runtimeNodeManager");
|
|
4101
|
+
__publicField(this, "fieldRegistry");
|
|
4102
|
+
__publicField(this, "scope", createScope());
|
|
4103
|
+
__publicField(this, "schemas");
|
|
4104
|
+
__publicField(this, "disposed", false);
|
|
4105
|
+
__publicField(this, "lifecycleBus");
|
|
4106
|
+
__publicField(this, "getFormInstance", () => {
|
|
4107
|
+
return {
|
|
4108
|
+
setFieldValue: this.store.setFieldValue.bind(this.store),
|
|
4109
|
+
setFieldsValue: this.store.setFieldsValue.bind(this.store),
|
|
4110
|
+
getFieldValue: this.store.getFieldValue.bind(this.store),
|
|
4111
|
+
getFieldsValue: this.store.getFieldsValue.bind(this.store),
|
|
4112
|
+
getFieldSnapshot: this.store.getFieldSnapshot.bind(this.store),
|
|
4113
|
+
getFieldsSnapshot: this.store.getFieldsSnapshot.bind(this.store),
|
|
4114
|
+
getInitialValue: this.store.getInitialValue.bind(this.store),
|
|
4115
|
+
getInitialValues: this.store.getInitialValues.bind(this.store),
|
|
4116
|
+
setInitialValues: this.store.setInitialValues.bind(this.store),
|
|
4117
|
+
isFieldTouched: this.store.isFieldTouched.bind(this.store),
|
|
4118
|
+
setFieldTouched: this.store.setFieldTouched.bind(this.store),
|
|
4119
|
+
getTouchedFields: this.store.getTouchedFields.bind(this.store),
|
|
4120
|
+
setFieldPending: this.store.setFieldPending.bind(this.store),
|
|
4121
|
+
isFieldPending: this.store.isFieldPending.bind(this.store),
|
|
4122
|
+
getPendingFields: this.store.getPendingFields.bind(this.store),
|
|
4123
|
+
validateField: this.validateField.bind(this),
|
|
4124
|
+
validate: this.validate.bind(this),
|
|
4125
|
+
getFieldError: this.validator.getFieldError.bind(this.validator),
|
|
4126
|
+
setFieldError: this.validator.setFieldError.bind(this.validator),
|
|
4127
|
+
resetFields: this.store.resetFields.bind(this.store),
|
|
4128
|
+
reset: this.reset.bind(this),
|
|
4129
|
+
submit: this.submit.bind(this),
|
|
4130
|
+
registerRules: this.register.bind(this),
|
|
4131
|
+
unregisterRules: this.validator.unregister.bind(this.validator),
|
|
4132
|
+
effect: this.effect.bind(this),
|
|
4133
|
+
batch: this.batch.bind(this),
|
|
4134
|
+
setSchemas: this.setSchemas.bind(this),
|
|
4135
|
+
updateSchemas: this.updateSchemas.bind(this),
|
|
4136
|
+
updateDefaultProps: this.updateDefaultProps.bind(this),
|
|
4137
|
+
getViewRevision: () => this.viewRevision.revision.value,
|
|
4138
|
+
getViewSchemas: this.getViewSchemas.bind(this),
|
|
4139
|
+
subscribeViewSchemas: this.subscribeViewSchemas.bind(this),
|
|
4140
|
+
waitForDependencies: this.waitForIdle.bind(this),
|
|
4141
|
+
getRenderer: this.rendererRegistry.getRenderer.bind(this.rendererRegistry),
|
|
4142
|
+
registerRenderer: this.rendererRegistry.register.bind(this.rendererRegistry),
|
|
4143
|
+
hasRenderer: this.rendererRegistry.hasRenderer.bind(this.rendererRegistry),
|
|
4144
|
+
getValidator: this.validatorRegistry.get.bind(this.validatorRegistry),
|
|
4145
|
+
registerValidator: this.validatorRegistry.register.bind(this.validatorRegistry),
|
|
4146
|
+
hasValidator: this.validatorRegistry.has.bind(this.validatorRegistry),
|
|
4147
|
+
destroy: this.destroy.bind(this)
|
|
4148
|
+
};
|
|
4149
|
+
});
|
|
4150
|
+
__publicField(this, "getFormApi", () => {
|
|
4151
|
+
return {
|
|
4152
|
+
setValue: this.store.setFieldValue.bind(this.store),
|
|
4153
|
+
setValues: this.store.setFieldsValue.bind(this.store),
|
|
4154
|
+
getValue: this.store.getFieldValue.bind(this.store),
|
|
4155
|
+
getValues: this.store.getFieldsValue.bind(this.store),
|
|
4156
|
+
getSnapshots: this.store.getFieldsSnapshot.bind(this.store),
|
|
4157
|
+
setPending: this.store.setFieldPending.bind(this.store),
|
|
4158
|
+
isPending: this.store.isFieldPending.bind(this.store),
|
|
4159
|
+
setTouched: this.store.setFieldTouched.bind(this.store),
|
|
4160
|
+
isTouched: this.store.isFieldTouched.bind(this.store),
|
|
4161
|
+
getError: this.validator.getFieldError.bind(this.validator),
|
|
4162
|
+
setError: this.validator.setFieldError.bind(this.validator),
|
|
4163
|
+
resetFields: this.store.resetFields.bind(this.store),
|
|
4164
|
+
reset: this.reset.bind(this),
|
|
4165
|
+
validateField: this.validateField.bind(this),
|
|
4166
|
+
validate: this.validate.bind(this)
|
|
4167
|
+
};
|
|
4168
|
+
});
|
|
4169
|
+
__publicField(this, "validate", withLock(async () => {
|
|
4170
|
+
const pendingFields = this.store.getPendingFields();
|
|
4171
|
+
if (pendingFields.length > 0) {
|
|
4172
|
+
const defaultMessage = `存在正在操作中的字段: ${pendingFields.map((i2) => i2.field).join(", ")},请等待完成后再提交`;
|
|
4173
|
+
console.warn(`[schemx] ${defaultMessage}`);
|
|
4174
|
+
return {
|
|
4175
|
+
ok: false,
|
|
4176
|
+
error: {
|
|
4177
|
+
errors: pendingFields.map(({ field, message }) => {
|
|
4178
|
+
const _message = message.length ? message : ["字段正在处理中,请稍后重试"];
|
|
4179
|
+
this.validator.setFieldError(field, _message);
|
|
4180
|
+
return {
|
|
4181
|
+
field,
|
|
4182
|
+
message: _message
|
|
4183
|
+
};
|
|
4184
|
+
}),
|
|
4185
|
+
values: this.store.getFieldsSnapshot()
|
|
4186
|
+
}
|
|
4187
|
+
};
|
|
4188
|
+
}
|
|
4189
|
+
const result = await this.validator.validate(this.store.getFieldsValue());
|
|
4190
|
+
return result;
|
|
4191
|
+
}));
|
|
4192
|
+
__publicField(this, "submit", withLock(async () => {
|
|
4193
|
+
var _a2, _b2, _c, _d;
|
|
4194
|
+
const depsReady = await this.waitForIdle();
|
|
4195
|
+
if (!depsReady) {
|
|
4196
|
+
return;
|
|
4197
|
+
}
|
|
4198
|
+
const result = await this.validate();
|
|
4199
|
+
if (result.ok) {
|
|
4200
|
+
await ((_b2 = (_a2 = this.callbacks).onFinish) == null ? void 0 : _b2.call(_a2, result.values));
|
|
4201
|
+
} else {
|
|
4202
|
+
(_d = (_c = this.callbacks).onFinishFailed) == null ? void 0 : _d.call(_c, result.error);
|
|
4203
|
+
}
|
|
4204
|
+
}));
|
|
4205
|
+
__publicField(this, "commitChildren", (parentNode, descriptors) => {
|
|
4206
|
+
const changed = this.reconciler.reconcileChildren(parentNode, descriptors);
|
|
4207
|
+
if (changed) {
|
|
4208
|
+
this.viewRevision.bump();
|
|
4209
|
+
}
|
|
4210
|
+
});
|
|
4211
|
+
var _a, _b;
|
|
4212
|
+
const {
|
|
4213
|
+
schemas: schemasInput,
|
|
4214
|
+
initialValues = {},
|
|
4215
|
+
modelValue,
|
|
4216
|
+
rendererRegistry: rendererRegistry2,
|
|
4217
|
+
defaultRendererType,
|
|
4218
|
+
validatorRegistry: validatorRegistry2,
|
|
4219
|
+
...restOptions
|
|
4220
|
+
} = options;
|
|
4221
|
+
this.callbacks = {
|
|
4222
|
+
onValuesChange: options.onValuesChange,
|
|
4223
|
+
onFinish: options.onFinish,
|
|
4224
|
+
onFinishFailed: options.onFinishFailed,
|
|
4225
|
+
onFieldsChange: options.onFieldsChange
|
|
4226
|
+
};
|
|
4227
|
+
this.rendererRegistry = rendererRegistry2 ?? createRendererRegistry(defaultRendererType);
|
|
4228
|
+
this.validatorRegistry = validatorRegistry2 ?? createValidatorsRegistry();
|
|
4229
|
+
this.validator = createValidator();
|
|
4230
|
+
this.store = createStore({
|
|
4231
|
+
initialValues: { ...initialValues, ...modelValue ?? {} }
|
|
4232
|
+
});
|
|
4233
|
+
this.validatorRegistry.registerAll({
|
|
4234
|
+
required: createRequiredRule,
|
|
4235
|
+
selectRequired: createSelectRequiredRule,
|
|
4236
|
+
uploadRequired: createUploadRequiredRule
|
|
4237
|
+
});
|
|
4238
|
+
this.lifecycleBus = createLifecycleBus();
|
|
4239
|
+
this.scheduler = createScheduler();
|
|
4240
|
+
this.viewRevision = createViewRevision();
|
|
4241
|
+
this.fieldRegistry = createFieldRegistry();
|
|
4242
|
+
this.context = {
|
|
4243
|
+
defaultProps: pick(restOptions, defaultConfigKey),
|
|
4244
|
+
instance: this.getFormInstance(),
|
|
4245
|
+
formApi: this.getFormApi(),
|
|
4246
|
+
scheduler: this.scheduler,
|
|
4247
|
+
lifecycleBus: this.lifecycleBus,
|
|
4248
|
+
fieldRegistry: this.fieldRegistry,
|
|
4249
|
+
commitChildren: this.commitChildren
|
|
4250
|
+
};
|
|
4251
|
+
this.runtimeNodeManager = createRuntimeNodeManager(this.context);
|
|
4252
|
+
this.reconciler = createReconciler(this.runtimeNodeManager);
|
|
4253
|
+
this.root = this.runtimeNodeManager.createRoot();
|
|
4254
|
+
if (options.lifecycleHooks) {
|
|
4255
|
+
this.lifecycleBus.on(options.lifecycleHooks);
|
|
4256
|
+
}
|
|
4257
|
+
this.schemas = isSchemxSchemas(schemasInput) ? schemasInput : createSchemas(schemasInput ?? []);
|
|
4258
|
+
this.applySchemas(this.schemas.peek());
|
|
4259
|
+
const schemasDisposer = this.schemas.subscribe((nextSchemas) => {
|
|
4260
|
+
this.applySchemas(nextSchemas);
|
|
4261
|
+
});
|
|
4262
|
+
this.scope.add(schemasDisposer);
|
|
4263
|
+
if (((_a = this.callbacks) == null ? void 0 : _a.onValuesChange) || ((_b = this.callbacks) == null ? void 0 : _b.onFieldsChange)) {
|
|
4264
|
+
let prevSnapshot = this.store.getFieldsSnapshot();
|
|
4265
|
+
const valuesChangeDisposer = createSignalEffect(() => {
|
|
4266
|
+
var _a2, _b2, _c, _d;
|
|
4267
|
+
const latestValues = this.store.getFieldsValue();
|
|
4268
|
+
const latestSnapshot = this.store.getFieldsSnapshot();
|
|
4269
|
+
const changedValues = diff(latestSnapshot, prevSnapshot);
|
|
4270
|
+
const changedPaths = collectObjectPathsByLeaf(changedValues);
|
|
4271
|
+
if (changedPaths.length > 0) {
|
|
4272
|
+
(_b2 = (_a2 = this.callbacks).onValuesChange) == null ? void 0 : _b2.call(_a2, changedValues, latestSnapshot);
|
|
4273
|
+
(_d = (_c = this.callbacks).onFieldsChange) == null ? void 0 : _d.call(
|
|
4274
|
+
_c,
|
|
4275
|
+
changedPaths,
|
|
4276
|
+
collectObjectPathsByLeaf(latestValues)
|
|
4277
|
+
);
|
|
4278
|
+
}
|
|
4279
|
+
prevSnapshot = latestSnapshot;
|
|
4280
|
+
});
|
|
4281
|
+
this.scope.add(valuesChangeDisposer);
|
|
4282
|
+
}
|
|
4283
|
+
}
|
|
4284
|
+
/**
|
|
4285
|
+
* 注册字段校验规则
|
|
4286
|
+
*/
|
|
4287
|
+
register(path, rules, defaultMessage) {
|
|
4288
|
+
const resolvedRules = [];
|
|
4289
|
+
const node = findFieldRuntimeNode(this.root, path);
|
|
4290
|
+
const schema = node == null ? void 0 : node.descriptor.schema;
|
|
4291
|
+
this.validator.unregister(path);
|
|
4292
|
+
const schemaWithRules = {
|
|
4293
|
+
...schema,
|
|
4294
|
+
rules
|
|
4295
|
+
};
|
|
4296
|
+
resolvedRules.push(
|
|
4297
|
+
...this.validatorRegistry.resolveValidatorsBySchema(schemaWithRules)
|
|
4298
|
+
);
|
|
4299
|
+
if (resolvedRules.length > 0) {
|
|
4300
|
+
this.validator.register(path, resolvedRules, defaultMessage);
|
|
4301
|
+
}
|
|
4302
|
+
}
|
|
4303
|
+
/**
|
|
4304
|
+
* 校验指定字段
|
|
4305
|
+
*/
|
|
4306
|
+
async validateField(name) {
|
|
4307
|
+
const result = await this.validator.validateField(name, this.store.getFieldsValue());
|
|
4308
|
+
return result;
|
|
4309
|
+
}
|
|
4310
|
+
/**
|
|
4311
|
+
* 重置整个表单到初始值
|
|
4312
|
+
*/
|
|
4313
|
+
reset() {
|
|
4314
|
+
this.store.reset();
|
|
4315
|
+
this.validator.reset();
|
|
4316
|
+
}
|
|
4317
|
+
/**
|
|
4318
|
+
* 创建 reactive effect。
|
|
4319
|
+
*
|
|
4320
|
+
* 回调内调用 getFieldValue / getFieldError 时自动追踪依赖,
|
|
4321
|
+
* 跨越 store 和 validator 的 reactive maps。
|
|
4322
|
+
* dispose 函数由 createForm 层面统一管理,destroy 时清理。
|
|
4323
|
+
*/
|
|
4324
|
+
effect(fn) {
|
|
4325
|
+
const dispose = createSignalEffect(fn);
|
|
4326
|
+
const handle = this.scope.add(dispose);
|
|
4327
|
+
return () => {
|
|
4328
|
+
handle.dispose();
|
|
4329
|
+
};
|
|
4330
|
+
}
|
|
4331
|
+
/**
|
|
4332
|
+
* 批量更新,合并多次 reactive 写入。
|
|
4333
|
+
*
|
|
4334
|
+
* 将多次 reactive 写入合并为一次 effect 触发,
|
|
4335
|
+
* 跨越 store 和 validator 的 reactive maps。
|
|
4336
|
+
*/
|
|
4337
|
+
batch(fn) {
|
|
4338
|
+
batchUpdates(fn);
|
|
4339
|
+
}
|
|
4340
|
+
/**
|
|
4341
|
+
* 替换 root schemas。
|
|
4342
|
+
*/
|
|
4343
|
+
setSchemas(schemas) {
|
|
4344
|
+
if (this.disposed) {
|
|
4345
|
+
return;
|
|
4346
|
+
}
|
|
4347
|
+
this.schemas.set(schemas);
|
|
4348
|
+
}
|
|
4349
|
+
/**
|
|
4350
|
+
* 基于当前 root schemas 派生下一版 schemas。
|
|
4351
|
+
*/
|
|
4352
|
+
updateSchemas(updater) {
|
|
4353
|
+
if (this.disposed) {
|
|
4354
|
+
return;
|
|
4355
|
+
}
|
|
4356
|
+
this.schemas.update(updater);
|
|
4357
|
+
}
|
|
4358
|
+
/**
|
|
4359
|
+
* 更新表单默认配置。
|
|
4360
|
+
*
|
|
4361
|
+
* 合并传入属性到当前 defaultProps,然后重新编译根 schemas 并 reconcile。
|
|
4362
|
+
* 字段级属性未设置时会回退到这些默认值。
|
|
4363
|
+
*/
|
|
4364
|
+
updateDefaultProps(partial) {
|
|
4365
|
+
if (this.disposed) {
|
|
4366
|
+
return;
|
|
4367
|
+
}
|
|
4368
|
+
Object.assign(this.context.defaultProps, pick(partial, defaultConfigKey));
|
|
4369
|
+
this.applySchemas(this.schemas.peek());
|
|
4370
|
+
}
|
|
4371
|
+
/**
|
|
4372
|
+
* 将 schema source 的当前值提交到 runtime node。
|
|
4373
|
+
*/
|
|
4374
|
+
applySchemas(schemas) {
|
|
4375
|
+
if (this.disposed) {
|
|
4376
|
+
return;
|
|
4377
|
+
}
|
|
4378
|
+
const previousRevision = this.viewRevision.revision.value;
|
|
4379
|
+
const descriptors = compileToDescriptors([...schemas], this.context.defaultProps);
|
|
4380
|
+
this.commitChildren(this.root, descriptors);
|
|
4381
|
+
if (this.viewRevision.revision.value === previousRevision) {
|
|
4382
|
+
this.viewRevision.bump();
|
|
4383
|
+
}
|
|
4384
|
+
}
|
|
4385
|
+
/**
|
|
4386
|
+
* 销毁表单实例
|
|
4387
|
+
*
|
|
4388
|
+
* 清除所有订阅回调和 effect,释放资源。通常在组件卸载时调用。
|
|
4389
|
+
*/
|
|
4390
|
+
destroy() {
|
|
4391
|
+
if (this.disposed) {
|
|
4392
|
+
return;
|
|
4393
|
+
}
|
|
4394
|
+
this.disposed = true;
|
|
4395
|
+
this.scope.dispose();
|
|
4396
|
+
this.runtimeNodeManager.disposeTree(this.root);
|
|
4397
|
+
this.scheduler.dispose();
|
|
4398
|
+
this.store.destroy();
|
|
4399
|
+
}
|
|
4400
|
+
/**
|
|
4401
|
+
* 获取当前 ViewSchemas。
|
|
4402
|
+
*/
|
|
4403
|
+
getViewSchemas() {
|
|
4404
|
+
return buildViewSchemas(this.root);
|
|
4405
|
+
}
|
|
4406
|
+
/**
|
|
4407
|
+
* 订阅 ViewSchemas 变化。
|
|
4408
|
+
*/
|
|
4409
|
+
subscribeViewSchemas(callback) {
|
|
4410
|
+
return subscribeViewSchemas(this.root, this.viewRevision, callback);
|
|
4411
|
+
}
|
|
4412
|
+
/**
|
|
4413
|
+
* 等待内部异步任务完成。
|
|
4414
|
+
*/
|
|
4415
|
+
waitForIdle(timeout = 1e4) {
|
|
4416
|
+
return this.scheduler.whenIdle(timeout);
|
|
4417
|
+
}
|
|
4418
|
+
}
|
|
4419
|
+
function createForm(options = {}) {
|
|
4420
|
+
return new CreateForm(options).getFormInstance();
|
|
4421
|
+
}
|
|
4422
|
+
function createField(form, name) {
|
|
4423
|
+
const getValue = () => form.getFieldValue(name);
|
|
4424
|
+
const setValue = (value) => {
|
|
4425
|
+
form.setFieldValue(name, value);
|
|
4426
|
+
};
|
|
4427
|
+
const getInitialValue = () => {
|
|
4428
|
+
return form.getInitialValue(name);
|
|
4429
|
+
};
|
|
4430
|
+
const setInitialValue = (value) => {
|
|
4431
|
+
const result = {};
|
|
4432
|
+
setByPath(result, name, value);
|
|
4433
|
+
form.setInitialValues(result);
|
|
4434
|
+
};
|
|
4435
|
+
const getValues = () => form.getFieldsValue();
|
|
4436
|
+
const getSnapshot = () => form.getFieldsSnapshot();
|
|
4437
|
+
const validate = () => {
|
|
4438
|
+
return form.validateField(name);
|
|
4439
|
+
};
|
|
4440
|
+
const getError = () => form.getFieldError(name);
|
|
4441
|
+
const setError = (errors) => {
|
|
4442
|
+
form.setFieldError(name, errors);
|
|
4443
|
+
};
|
|
4444
|
+
const clearError = () => {
|
|
4445
|
+
form.setFieldError(name, []);
|
|
4446
|
+
};
|
|
4447
|
+
const registerRules = (rules, defaultMessage) => {
|
|
4448
|
+
form.registerRules(name, rules, defaultMessage);
|
|
4449
|
+
};
|
|
4450
|
+
const unregisterRules = () => {
|
|
4451
|
+
form.unregisterRules(name);
|
|
4452
|
+
};
|
|
4453
|
+
const isTouched = () => form.isFieldTouched(name) ?? false;
|
|
4454
|
+
const reset = () => {
|
|
4455
|
+
form.resetFields([name]);
|
|
4456
|
+
};
|
|
4457
|
+
const setPending = (pending, message) => {
|
|
4458
|
+
form.setFieldPending(name, pending, message);
|
|
4459
|
+
};
|
|
4460
|
+
const isPending = () => form.isFieldPending(name) ?? false;
|
|
4461
|
+
const effect = (fn) => {
|
|
4462
|
+
return form.effect(fn);
|
|
4463
|
+
};
|
|
4464
|
+
return {
|
|
4465
|
+
getValue,
|
|
4466
|
+
setValue,
|
|
4467
|
+
getInitialValue,
|
|
4468
|
+
setInitialValue,
|
|
4469
|
+
getValues,
|
|
4470
|
+
getSnapshot,
|
|
4471
|
+
validate,
|
|
4472
|
+
getError,
|
|
4473
|
+
setError,
|
|
4474
|
+
clearError,
|
|
4475
|
+
registerRules,
|
|
4476
|
+
unregisterRules,
|
|
4477
|
+
isTouched,
|
|
4478
|
+
reset,
|
|
4479
|
+
setPending,
|
|
4480
|
+
isPending,
|
|
4481
|
+
effect
|
|
4482
|
+
};
|
|
4483
|
+
}
|
|
4484
|
+
function createEffect(callback) {
|
|
4485
|
+
let cleanup;
|
|
4486
|
+
let disposed = false;
|
|
4487
|
+
const dispose = createSignalEffect(() => {
|
|
4488
|
+
cleanup == null ? void 0 : cleanup();
|
|
4489
|
+
cleanup = void 0;
|
|
4490
|
+
const result = callback();
|
|
4491
|
+
if (typeof result === "function") {
|
|
4492
|
+
cleanup = result;
|
|
4493
|
+
}
|
|
4494
|
+
});
|
|
4495
|
+
const api = () => {
|
|
4496
|
+
if (disposed) return;
|
|
4497
|
+
disposed = true;
|
|
4498
|
+
dispose();
|
|
4499
|
+
cleanup == null ? void 0 : cleanup();
|
|
4500
|
+
cleanup = void 0;
|
|
4501
|
+
};
|
|
4502
|
+
return api;
|
|
4503
|
+
}
|
|
4504
|
+
const createWatchField = (form, name, callback, options) => {
|
|
4505
|
+
let prev = form.getFieldSnapshot(name);
|
|
4506
|
+
let isFirst = true;
|
|
4507
|
+
const dispose = form.effect(() => {
|
|
4508
|
+
const current = form.getFieldValue(name);
|
|
4509
|
+
const latestSnapshot = form.getFieldsSnapshot();
|
|
4510
|
+
if (isFirst) {
|
|
4511
|
+
isFirst = false;
|
|
4512
|
+
if (options.immediate) {
|
|
4513
|
+
callback({ value: current, prevValue: void 0 }, latestSnapshot);
|
|
4514
|
+
}
|
|
4515
|
+
prev = current;
|
|
4516
|
+
return;
|
|
4517
|
+
}
|
|
4518
|
+
if (options.inequality && isEqual(current, prev)) return;
|
|
4519
|
+
callback({ value: current, prevValue: prev }, latestSnapshot);
|
|
4520
|
+
prev = current;
|
|
4521
|
+
});
|
|
4522
|
+
return dispose;
|
|
4523
|
+
};
|
|
4524
|
+
const createWatchFields = (form, names, callback, options) => {
|
|
4525
|
+
let prevValues = form.getFieldsSnapshot(names);
|
|
4526
|
+
let isFirst = true;
|
|
4527
|
+
const dispose = form.effect(() => {
|
|
4528
|
+
const currentValues = form.getFieldsValue(names);
|
|
4529
|
+
const latestSnapshot = form.getFieldsSnapshot();
|
|
4530
|
+
if (isFirst) {
|
|
4531
|
+
isFirst = false;
|
|
4532
|
+
if (options.immediate) {
|
|
4533
|
+
callback(
|
|
4534
|
+
{ changedPaths: names, changedValues: currentValues, prevValues: {} },
|
|
4535
|
+
latestSnapshot
|
|
4536
|
+
);
|
|
4537
|
+
}
|
|
4538
|
+
prevValues = { ...currentValues };
|
|
4539
|
+
return;
|
|
4540
|
+
}
|
|
4541
|
+
if (options.inequality && isEqual(currentValues, prevValues)) return;
|
|
4542
|
+
const changedValues = diff(currentValues, prevValues);
|
|
4543
|
+
const changedPaths = collectObjectPathsByLeaf(changedValues);
|
|
4544
|
+
callback({ changedPaths, changedValues, prevValues }, latestSnapshot);
|
|
4545
|
+
prevValues = { ...currentValues };
|
|
4546
|
+
});
|
|
4547
|
+
return dispose;
|
|
4548
|
+
};
|
|
4549
|
+
const createWatchAll = (form, callback, options) => {
|
|
4550
|
+
let isFirst = true;
|
|
4551
|
+
let prevValues = form.getFieldsSnapshot();
|
|
4552
|
+
const dispose = form.effect(() => {
|
|
4553
|
+
const latestSnapshot = form.getFieldsSnapshot();
|
|
4554
|
+
if (isFirst) {
|
|
4555
|
+
isFirst = false;
|
|
4556
|
+
if (options.immediate) {
|
|
4557
|
+
callback(
|
|
4558
|
+
{
|
|
4559
|
+
changedPaths: [],
|
|
4560
|
+
changedValues: latestSnapshot,
|
|
4561
|
+
prevValues: {}
|
|
4562
|
+
},
|
|
4563
|
+
latestSnapshot
|
|
4564
|
+
);
|
|
4565
|
+
}
|
|
4566
|
+
prevValues = { ...latestSnapshot };
|
|
4567
|
+
return;
|
|
4568
|
+
}
|
|
4569
|
+
if (options.inequality && isEqual(latestSnapshot, prevValues)) return;
|
|
4570
|
+
const changedValues = diff(latestSnapshot, prevValues);
|
|
4571
|
+
const changedPaths = collectObjectPathsByLeaf(changedValues);
|
|
4572
|
+
callback({ changedPaths, changedValues, prevValues }, latestSnapshot);
|
|
4573
|
+
prevValues = { ...latestSnapshot };
|
|
4574
|
+
});
|
|
4575
|
+
return dispose;
|
|
4576
|
+
};
|
|
4577
|
+
function createWatch(form, nameOrNamesOrCallback, callbackOrOptions, maybeOptions) {
|
|
4578
|
+
if (typeof nameOrNamesOrCallback === "function") {
|
|
4579
|
+
return createWatchAll(
|
|
4580
|
+
form,
|
|
4581
|
+
nameOrNamesOrCallback,
|
|
4582
|
+
callbackOrOptions || {}
|
|
4583
|
+
);
|
|
4584
|
+
}
|
|
4585
|
+
if (typeof nameOrNamesOrCallback === "string" || typeof nameOrNamesOrCallback === "number") {
|
|
4586
|
+
return createWatchField(
|
|
4587
|
+
form,
|
|
4588
|
+
nameOrNamesOrCallback,
|
|
4589
|
+
callbackOrOptions,
|
|
4590
|
+
maybeOptions || {}
|
|
4591
|
+
);
|
|
4592
|
+
}
|
|
4593
|
+
return createWatchFields(
|
|
4594
|
+
form,
|
|
4595
|
+
nameOrNamesOrCallback,
|
|
4596
|
+
callbackOrOptions,
|
|
4597
|
+
maybeOptions || {}
|
|
4598
|
+
);
|
|
4599
|
+
}
|
|
6
4600
|
const rendererRegistry = createRendererRegistry("input");
|
|
7
4601
|
const validatorRegistry = createValidatorsRegistry();
|
|
8
4602
|
const SCHEMX_INSTANCE_KEY = Symbol("SCHEMX_INSTANCE");
|
|
@@ -136,7 +4730,7 @@ const useDictionary = (options, fieldName) => {
|
|
|
136
4730
|
} catch (err) {
|
|
137
4731
|
lastError = normalizeError(err);
|
|
138
4732
|
if (attempt < maxRetries) {
|
|
139
|
-
await new Promise((
|
|
4733
|
+
await new Promise((r2) => setTimeout(r2, retryDelay));
|
|
140
4734
|
}
|
|
141
4735
|
}
|
|
142
4736
|
}
|
|
@@ -207,11 +4801,11 @@ function useContext() {
|
|
|
207
4801
|
}
|
|
208
4802
|
return context;
|
|
209
4803
|
}
|
|
210
|
-
const isShallowEqual = (
|
|
211
|
-
const keysA = Object.keys(
|
|
212
|
-
const keysB = Object.keys(
|
|
4804
|
+
const isShallowEqual = (a2, b2) => {
|
|
4805
|
+
const keysA = Object.keys(a2);
|
|
4806
|
+
const keysB = Object.keys(b2);
|
|
213
4807
|
if (keysA.length !== keysB.length) return false;
|
|
214
|
-
return keysA.every((key) =>
|
|
4808
|
+
return keysA.every((key) => a2[key] === b2[key]);
|
|
215
4809
|
};
|
|
216
4810
|
function useStableRef(factory) {
|
|
217
4811
|
const stableRef = shallowRef({});
|
|
@@ -242,9 +4836,9 @@ function useFieldContext() {
|
|
|
242
4836
|
}
|
|
243
4837
|
return field;
|
|
244
4838
|
}
|
|
245
|
-
function isValidTrigger(
|
|
246
|
-
if (
|
|
247
|
-
if (Array.isArray(
|
|
4839
|
+
function isValidTrigger(v2) {
|
|
4840
|
+
if (v2 === void 0) return false;
|
|
4841
|
+
if (Array.isArray(v2) && v2.length === 0) return false;
|
|
248
4842
|
return true;
|
|
249
4843
|
}
|
|
250
4844
|
function mergeTrigger(columnTrigger, contextTrigger, defaultTrigger) {
|
|
@@ -252,7 +4846,7 @@ function mergeTrigger(columnTrigger, contextTrigger, defaultTrigger) {
|
|
|
252
4846
|
if (isValidTrigger(contextTrigger)) return contextTrigger;
|
|
253
4847
|
return defaultTrigger;
|
|
254
4848
|
}
|
|
255
|
-
function normalizeTrigger(
|
|
4849
|
+
function normalizeTrigger(t2) {
|
|
256
4850
|
const map = {
|
|
257
4851
|
onBlur: "blur",
|
|
258
4852
|
onChange: "change",
|
|
@@ -261,12 +4855,12 @@ function normalizeTrigger(t) {
|
|
|
261
4855
|
change: "change",
|
|
262
4856
|
submit: "submit"
|
|
263
4857
|
};
|
|
264
|
-
return map[
|
|
4858
|
+
return map[t2] ?? "submit";
|
|
265
4859
|
}
|
|
266
4860
|
function shouldValidateOn(event, trigger) {
|
|
267
4861
|
if (!trigger) return false;
|
|
268
4862
|
const triggers = Array.isArray(trigger) ? trigger : [trigger];
|
|
269
|
-
return triggers.some((
|
|
4863
|
+
return triggers.some((t2) => normalizeTrigger(t2) === event);
|
|
270
4864
|
}
|
|
271
4865
|
const isCamelCase = (str) => /[A-Z]/.test(str);
|
|
272
4866
|
const isKebabCase = (str) => str.includes("-");
|
|
@@ -327,9 +4921,9 @@ const FormGroup = /* @__PURE__ */ defineComponent((props, {
|
|
|
327
4921
|
"schemx-group__header--clickable": collapsible
|
|
328
4922
|
}),
|
|
329
4923
|
"onClick": toggle,
|
|
330
|
-
"onKeydown": (
|
|
331
|
-
if (
|
|
332
|
-
|
|
4924
|
+
"onKeydown": (e2) => {
|
|
4925
|
+
if (e2.key === "Enter" || e2.key === " ") {
|
|
4926
|
+
e2.preventDefault();
|
|
333
4927
|
toggle();
|
|
334
4928
|
}
|
|
335
4929
|
}
|
|
@@ -361,7 +4955,7 @@ const FormItem = /* @__PURE__ */ defineComponent((props, {
|
|
|
361
4955
|
const schemaRef = toRef(props, "schema");
|
|
362
4956
|
if (isViewGroupSchema(schemaRef.value)) {
|
|
363
4957
|
return () => {
|
|
364
|
-
return h(FormGroup, {
|
|
4958
|
+
return h$1(FormGroup, {
|
|
365
4959
|
schema: schemaRef.value
|
|
366
4960
|
}, slots);
|
|
367
4961
|
};
|
|
@@ -378,10 +4972,10 @@ const FormItem = /* @__PURE__ */ defineComponent((props, {
|
|
|
378
4972
|
const hasRules = Array.isArray(rules) ? (rules == null ? void 0 : rules.length) > 0 : !!schema().rules;
|
|
379
4973
|
return isOperate && hasRules;
|
|
380
4974
|
});
|
|
381
|
-
const handleChange = (
|
|
4975
|
+
const handleChange = (v2) => {
|
|
382
4976
|
var _a, _b;
|
|
383
|
-
field.setValue(
|
|
384
|
-
(_b = (_a = schema().componentProps) == null ? void 0 : _a.onChange) == null ? void 0 : _b.call(_a,
|
|
4977
|
+
field.setValue(v2);
|
|
4978
|
+
(_b = (_a = schema().componentProps) == null ? void 0 : _a.onChange) == null ? void 0 : _b.call(_a, v2);
|
|
385
4979
|
if (canVerified.value && shouldValidateOn("change", trigger.value)) {
|
|
386
4980
|
field.validate();
|
|
387
4981
|
}
|
|
@@ -414,7 +5008,7 @@ const FormItem = /* @__PURE__ */ defineComponent((props, {
|
|
|
414
5008
|
placeholder: schema().placeholder,
|
|
415
5009
|
onChange: handleChange,
|
|
416
5010
|
onBlur: handleBlur,
|
|
417
|
-
"onUpdate:value": (
|
|
5011
|
+
"onUpdate:value": (v2) => field.setValue(v2)
|
|
418
5012
|
}));
|
|
419
5013
|
const renderRequired = () => {
|
|
420
5014
|
if (!schema().required || schema().disabled || schema().readonly) {
|
|
@@ -448,7 +5042,7 @@ const FormItem = /* @__PURE__ */ defineComponent((props, {
|
|
|
448
5042
|
throw new Error(`[schemx] Can not find component renderer of "${schema().componentType}".`);
|
|
449
5043
|
}
|
|
450
5044
|
const childSlots = extractChildSlots(normalizeNameKey(schema().name), slots);
|
|
451
|
-
const columnElement = h(component, componentProps.value, childSlots);
|
|
5045
|
+
const columnElement = h$1(component, componentProps.value, childSlots);
|
|
452
5046
|
const contentSlot = resolveSlot(slots, `${schema().name}Content`);
|
|
453
5047
|
if (contentSlot) {
|
|
454
5048
|
return contentSlot({
|
|
@@ -485,12 +5079,12 @@ const FormItem = /* @__PURE__ */ defineComponent((props, {
|
|
|
485
5079
|
}
|
|
486
5080
|
const labelPosition = schema().labelPosition || formContext.labelPosition;
|
|
487
5081
|
return createVNode("div", {
|
|
488
|
-
"class": classnames("schemx-item-wrapper"
|
|
5082
|
+
"class": classnames("schemx-item-wrapper")
|
|
5083
|
+
}, [createVNode("div", {
|
|
5084
|
+
"class": classnames("schemx-item", `schemx-item--label-${labelPosition}`, schema().class, {
|
|
489
5085
|
"is-readonly": schema().readonly,
|
|
490
5086
|
"is-disabled": schema().disabled
|
|
491
|
-
})
|
|
492
|
-
}, [createVNode("div", {
|
|
493
|
-
"class": classnames("schemx-item", `schemx-item--label-${labelPosition}`, schema().class),
|
|
5087
|
+
}),
|
|
494
5088
|
"style": {
|
|
495
5089
|
...schema().style ?? {}
|
|
496
5090
|
}
|
|
@@ -516,6 +5110,42 @@ const normalizeNameKey = (name) => {
|
|
|
516
5110
|
}
|
|
517
5111
|
return String(name);
|
|
518
5112
|
};
|
|
5113
|
+
function getSectionPosition(list, currentKey) {
|
|
5114
|
+
const currentIndex = list.findIndex((item) => item.key === currentKey);
|
|
5115
|
+
if (currentIndex === -1) {
|
|
5116
|
+
return {
|
|
5117
|
+
found: false,
|
|
5118
|
+
isFirst: false,
|
|
5119
|
+
isLast: false
|
|
5120
|
+
};
|
|
5121
|
+
}
|
|
5122
|
+
const currentItem = list[currentIndex];
|
|
5123
|
+
if (!isPositionItem(currentItem)) {
|
|
5124
|
+
return {
|
|
5125
|
+
found: true,
|
|
5126
|
+
isFirst: false,
|
|
5127
|
+
isLast: false
|
|
5128
|
+
};
|
|
5129
|
+
}
|
|
5130
|
+
const prevItem = findPositionItem(list, currentIndex, -1);
|
|
5131
|
+
const nextItem = findPositionItem(list, currentIndex, 1);
|
|
5132
|
+
return {
|
|
5133
|
+
found: true,
|
|
5134
|
+
isFirst: !prevItem,
|
|
5135
|
+
isLast: !nextItem
|
|
5136
|
+
};
|
|
5137
|
+
}
|
|
5138
|
+
function isPositionItem(item) {
|
|
5139
|
+
return !!item && item.componentType !== "group" && (!("visible" in item) || item.visible !== false);
|
|
5140
|
+
}
|
|
5141
|
+
function findPositionItem(list, startIndex, step) {
|
|
5142
|
+
for (let index = startIndex + step; index >= 0 && index < list.length; index += step) {
|
|
5143
|
+
if (isPositionItem(list[index])) {
|
|
5144
|
+
return list[index];
|
|
5145
|
+
}
|
|
5146
|
+
}
|
|
5147
|
+
return void 0;
|
|
5148
|
+
}
|
|
519
5149
|
const _sfc_main = /* @__PURE__ */ defineComponent({
|
|
520
5150
|
...{ name: "SchemxForm" },
|
|
521
5151
|
__name: "form",
|
|
@@ -596,6 +5226,16 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
|
|
|
596
5226
|
{ deep: false, immediate: !!props.form }
|
|
597
5227
|
);
|
|
598
5228
|
const viewSchemas = useViewSchemas(form);
|
|
5229
|
+
const getFormItemClass = (schema) => {
|
|
5230
|
+
const { isFirst, isLast } = getSectionPosition(
|
|
5231
|
+
viewSchemas.value,
|
|
5232
|
+
schema.key
|
|
5233
|
+
);
|
|
5234
|
+
return {
|
|
5235
|
+
"schemx-item-wrapper--first": isFirst,
|
|
5236
|
+
"schemx-item-wrapper--last": isLast
|
|
5237
|
+
};
|
|
5238
|
+
};
|
|
599
5239
|
watchEffect(() => {
|
|
600
5240
|
form.updateDefaultProps(props);
|
|
601
5241
|
});
|
|
@@ -609,9 +5249,10 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
|
|
|
609
5249
|
(openBlock(true), createElementBlock(Fragment, null, renderList(unref(viewSchemas), (schema) => {
|
|
610
5250
|
return openBlock(), createBlock(unref(FormItem), {
|
|
611
5251
|
key: schema.key,
|
|
612
|
-
schema
|
|
5252
|
+
schema,
|
|
5253
|
+
class: normalizeClass(getFormItemClass(schema))
|
|
613
5254
|
}, createSlots({ _: 2 }, [
|
|
614
|
-
renderList(_ctx.$slots, (
|
|
5255
|
+
renderList(_ctx.$slots, (_2, slotName) => {
|
|
615
5256
|
return {
|
|
616
5257
|
name: slotName,
|
|
617
5258
|
fn: withCtx((slotProps) => [
|
|
@@ -619,7 +5260,7 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
|
|
|
619
5260
|
])
|
|
620
5261
|
};
|
|
621
5262
|
})
|
|
622
|
-
]), 1032, ["schema"]);
|
|
5263
|
+
]), 1032, ["schema", "class"]);
|
|
623
5264
|
}), 128))
|
|
624
5265
|
], 2);
|
|
625
5266
|
};
|
|
@@ -660,7 +5301,7 @@ function WithRemoteOptions(WrappedComponent) {
|
|
|
660
5301
|
loading: props.dict ? dictResult == null ? void 0 : dictResult.loading.value : attrs.loading
|
|
661
5302
|
};
|
|
662
5303
|
});
|
|
663
|
-
return () => h(WrappedComponent, childrenProps.value, slots);
|
|
5304
|
+
return () => h$1(WrappedComponent, childrenProps.value, slots);
|
|
664
5305
|
}
|
|
665
5306
|
});
|
|
666
5307
|
}
|
|
@@ -668,9 +5309,32 @@ export {
|
|
|
668
5309
|
FormGroup,
|
|
669
5310
|
FormItem,
|
|
670
5311
|
WithRemoteOptions,
|
|
5312
|
+
collectObjectPathsByLeaf,
|
|
5313
|
+
createEffect,
|
|
5314
|
+
createField,
|
|
5315
|
+
createForm,
|
|
5316
|
+
createForm as createFormInstance,
|
|
5317
|
+
createLifecycle,
|
|
5318
|
+
createLifecycleBus,
|
|
5319
|
+
createRendererRegistry,
|
|
5320
|
+
createSchemas,
|
|
5321
|
+
createValidator,
|
|
5322
|
+
createValidatorsRegistry,
|
|
5323
|
+
createWatch,
|
|
5324
|
+
createWatchAll,
|
|
5325
|
+
createWatchField,
|
|
5326
|
+
createWatchFields,
|
|
671
5327
|
SchemxFormExport as default,
|
|
5328
|
+
getByPath,
|
|
5329
|
+
isBaseResolvedSchema,
|
|
5330
|
+
isBaseSchema,
|
|
5331
|
+
isDependencySchema,
|
|
5332
|
+
isGroupResolvedSchema,
|
|
5333
|
+
isGroupSchema,
|
|
5334
|
+
isSchemxSchemas,
|
|
672
5335
|
rendererRegistry,
|
|
673
5336
|
SchemxFormExport as schemxForm,
|
|
5337
|
+
setByPath,
|
|
674
5338
|
useContext,
|
|
675
5339
|
useDictionary,
|
|
676
5340
|
useEffect,
|