@neeloong/form 0.28.0 → 0.30.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/index.d.mts +116 -136
- package/index.full.js +298 -260
- package/index.full.min.js +2 -2
- package/index.full.min.mjs +2 -2
- package/index.min.mjs +2 -2
- package/index.mjs +297 -260
- package/package.json +1 -1
package/index.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/*!
|
|
2
|
-
* @neeloong/form v0.
|
|
2
|
+
* @neeloong/form v0.30.0
|
|
3
3
|
* (c) 2024-2026 Fierflame
|
|
4
4
|
* @license Apache-2.0
|
|
5
5
|
*/
|
|
@@ -138,7 +138,7 @@ function createRef(store) {
|
|
|
138
138
|
|
|
139
139
|
|
|
140
140
|
/** @type {{new(...p: ConstructorParameters<typeof Store>): Store}?} */
|
|
141
|
-
let ObjectStore$
|
|
141
|
+
let ObjectStore$1 = null;
|
|
142
142
|
/** @type {{new(...p: ConstructorParameters<typeof Store>): ArrayStore}?} */
|
|
143
143
|
let ArrayStoreClass = null;
|
|
144
144
|
/** @type {Record<string, {new(...p: ConstructorParameters<typeof Store>): Store}?>} */
|
|
@@ -163,14 +163,14 @@ function create(schema, options) {
|
|
|
163
163
|
const C = TypeStores[type];
|
|
164
164
|
if (C) { Class = C; }
|
|
165
165
|
} else if (type && typeof type === 'object') {
|
|
166
|
-
if (ObjectStore$
|
|
166
|
+
if (ObjectStore$1) { Class = ObjectStore$1; }
|
|
167
167
|
}
|
|
168
168
|
return new Class(schema, options);
|
|
169
169
|
}
|
|
170
170
|
|
|
171
171
|
/** @param {{new(...p: ConstructorParameters<typeof Store>): Store}} Class */
|
|
172
172
|
function setObjectStore(Class) {
|
|
173
|
-
ObjectStore$
|
|
173
|
+
ObjectStore$1 = Class;
|
|
174
174
|
}
|
|
175
175
|
|
|
176
176
|
/** @param {{new(...p: ConstructorParameters<typeof Store>): ArrayStore}} Class */
|
|
@@ -201,79 +201,127 @@ function toResult(v) {
|
|
|
201
201
|
/**
|
|
202
202
|
*
|
|
203
203
|
* @param {Store} store
|
|
204
|
-
* @param
|
|
204
|
+
* @param {Schema.SyncValidator[]} syncValidators
|
|
205
205
|
* @returns
|
|
206
206
|
*/
|
|
207
|
-
function
|
|
208
|
-
const allValidators = validators.flat().filter(v => typeof v === 'function');
|
|
209
|
-
if (!allValidators.length) {
|
|
210
|
-
return new Signal.Computed(() => /** @type {string[]} */([]));
|
|
211
|
-
}
|
|
207
|
+
function createSyncValidator(store, syncValidators) {
|
|
212
208
|
return new Signal.Computed(() => {
|
|
213
209
|
const results = [];
|
|
214
|
-
for (const
|
|
210
|
+
for (const item of syncValidators) {
|
|
215
211
|
try {
|
|
216
|
-
results.push(
|
|
217
|
-
} catch (e){
|
|
212
|
+
results.push(item(store));
|
|
213
|
+
} catch (e) {
|
|
218
214
|
results.push(e);
|
|
219
215
|
}
|
|
220
216
|
}
|
|
221
217
|
return results.flat().map(toResult).filter(Boolean);
|
|
222
|
-
})
|
|
218
|
+
});
|
|
223
219
|
}
|
|
220
|
+
|
|
224
221
|
/**
|
|
225
222
|
*
|
|
226
223
|
* @param {Store} store
|
|
227
|
-
* @param
|
|
228
|
-
* @returns {[
|
|
224
|
+
* @param {Map<string, Schema.AsyncValidator[]>} eventsValidators
|
|
225
|
+
* @returns {[Record<string, () => Promise<string[]>>, results: Signal.State<string[]>[], stop: () => void]}
|
|
229
226
|
*/
|
|
230
|
-
function
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
227
|
+
function createEventsValidator(store, eventsValidators) {
|
|
228
|
+
/** @type {Record<string, () => Promise<string[]>>} */
|
|
229
|
+
const eventExecMap = {};
|
|
230
|
+
/** @type {(() => void)[]} */
|
|
231
|
+
const allCancels = [];
|
|
232
|
+
/** @type {Signal.State<string[]>[]} */
|
|
233
|
+
const results = [];
|
|
234
|
+
for (const [name, validators] of eventsValidators) {
|
|
235
|
+
const st = new Signal.State(/** @type {string[]} */([]));
|
|
236
|
+
/**
|
|
237
|
+
*
|
|
238
|
+
* @param {Schema.AsyncValidator} validator
|
|
239
|
+
* @param {AbortSignal} signal
|
|
240
|
+
*/
|
|
241
|
+
async function run(validator, signal) {
|
|
242
|
+
let results = [];
|
|
243
|
+
try {
|
|
244
|
+
results.push(await validator(store, signal));
|
|
245
|
+
} catch (e) {
|
|
246
|
+
results.push(e);
|
|
247
|
+
}
|
|
248
|
+
const list = results.flat().map(toResult).filter(Boolean);
|
|
249
|
+
if (!signal.aborted && list.length) { st.set([...st.get(), ...list]); }
|
|
250
|
+
return list;
|
|
251
|
+
}
|
|
252
|
+
/** @type {AbortController?} */
|
|
253
|
+
let ac = null;
|
|
254
|
+
function exec() {
|
|
255
|
+
ac?.abort();
|
|
256
|
+
ac = new AbortController();
|
|
257
|
+
const signal = ac.signal;
|
|
258
|
+
st.set([]);
|
|
259
|
+
|
|
260
|
+
return Promise.all(validators.map(f => run(f, signal))).then(v => v.flat());
|
|
251
261
|
}
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
262
|
+
eventExecMap[name] = exec;
|
|
263
|
+
allCancels.push(() => { ac?.abort(); st.set([]); });
|
|
264
|
+
results.push(st);
|
|
255
265
|
}
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
}
|
|
266
|
-
return [exec, new Signal.Computed(() => st.get()), () => {ac?.abort(); st.set([]);}]
|
|
266
|
+
|
|
267
|
+
function stop() {
|
|
268
|
+
for (const c of allCancels) {
|
|
269
|
+
c();
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
return [eventExecMap, results, stop];
|
|
267
275
|
}
|
|
268
276
|
|
|
269
277
|
/**
|
|
270
278
|
*
|
|
271
|
-
* @param
|
|
272
|
-
* @
|
|
279
|
+
* @param {Store} store
|
|
280
|
+
* @param {...Schema.Validator | undefined | null | (Schema.Validator | undefined | null)[]} validators
|
|
281
|
+
* @returns {[exec: () => Promise<string[]>, Record<string, () => Promise<string[]>>, state: Signal.Computed<string[]>, stop: () => void]}
|
|
273
282
|
*/
|
|
274
|
-
function
|
|
275
|
-
|
|
276
|
-
|
|
283
|
+
function createValidator(store, ...validators) {
|
|
284
|
+
|
|
285
|
+
/** @type {Schema.SyncValidator[]} */
|
|
286
|
+
const syncValidators = [];
|
|
287
|
+
/** @type {Map<string, Schema.AsyncValidator[]>} */
|
|
288
|
+
const eventsValidators = new Map();
|
|
289
|
+
for (const v of validators.flat()) {
|
|
290
|
+
if (!v) { continue; }
|
|
291
|
+
if (typeof v === 'function') {
|
|
292
|
+
syncValidators.push(v);
|
|
293
|
+
continue;
|
|
294
|
+
}
|
|
295
|
+
const { event, validator } = v;
|
|
296
|
+
if (typeof validator !== 'function') { continue; }
|
|
297
|
+
if (typeof event !== 'string') {
|
|
298
|
+
syncValidators.push(validator);
|
|
299
|
+
continue;
|
|
300
|
+
}
|
|
301
|
+
const list = eventsValidators.get(event);
|
|
302
|
+
if (list) {
|
|
303
|
+
list.push(validator);
|
|
304
|
+
} else {
|
|
305
|
+
eventsValidators.set(event, [validator]);
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
|
|
310
|
+
const validatorResult = syncValidators.length
|
|
311
|
+
? createSyncValidator(store, syncValidators)
|
|
312
|
+
: new Signal.Computed(() => /** @type {string[]} */([]));
|
|
313
|
+
if (!eventsValidators.size) {
|
|
314
|
+
return [() => Promise.resolve(validatorResult.get()), {}, validatorResult, () => {}];
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
const [eventExecMap, results, stop] = createEventsValidator(store, eventsValidators);
|
|
318
|
+
|
|
319
|
+
const errors = new Signal.Computed(() => [validatorResult, ...results].flatMap(v => v.get()));
|
|
320
|
+
const execAll = () => Promise.all([
|
|
321
|
+
validatorResult.get(),
|
|
322
|
+
...Object.values(eventExecMap).map(exec => exec()),
|
|
323
|
+
]).then(v => v.flat());
|
|
324
|
+
return [execAll, eventExecMap, errors, stop];
|
|
277
325
|
}
|
|
278
326
|
|
|
279
327
|
/** @import Store from './Store.mjs' */
|
|
@@ -292,52 +340,6 @@ function makeDefault(store, def) {
|
|
|
292
340
|
return (value) => structuredClone(def(store, value));
|
|
293
341
|
}
|
|
294
342
|
|
|
295
|
-
/** @import { Schema } from '../Schema.types.mjs' */
|
|
296
|
-
|
|
297
|
-
/**
|
|
298
|
-
* @template [T=any]
|
|
299
|
-
* @template [M=any]
|
|
300
|
-
* @template {Object.<string, Schema.State>} [S=Object.<string, Schema.State>]
|
|
301
|
-
* @extends {Store<T, M, S>}
|
|
302
|
-
*/
|
|
303
|
-
class BindObjectStore extends Store {
|
|
304
|
-
|
|
305
|
-
get kind() { return 'object'; }
|
|
306
|
-
/** @type {Record<string, Store>} */
|
|
307
|
-
#children = Object.create(null);
|
|
308
|
-
*[Symbol.iterator]() { yield* Object.entries(this.#children); }
|
|
309
|
-
/**
|
|
310
|
-
*
|
|
311
|
-
* @param {string | number} key
|
|
312
|
-
* @returns {Store?}
|
|
313
|
-
*/
|
|
314
|
-
child(key) { return this.#children[key] || null; }
|
|
315
|
-
/**
|
|
316
|
-
* @param {Schema<any, Object.<string, Schema.State>>} schema 数据结构模式
|
|
317
|
-
* @param {Store<T, M, S>} store
|
|
318
|
-
*/
|
|
319
|
-
constructor(schema, store) {
|
|
320
|
-
super(store);
|
|
321
|
-
const children = this.#children;
|
|
322
|
-
for (const [index, field] of Object.entries(schema)) {
|
|
323
|
-
const bindStore = create(field, {
|
|
324
|
-
index, parent: this,
|
|
325
|
-
/** @param {*} value @param {*} index @param {Store} store */
|
|
326
|
-
onUpdate: (value, index, store) => {
|
|
327
|
-
if (store !== children[index]) { return; }
|
|
328
|
-
const val = this.value ?? null;
|
|
329
|
-
if (typeof val !== 'object' || Array.isArray(val)) { return; }
|
|
330
|
-
// @ts-ignore
|
|
331
|
-
this.value = { ...val, [index]: value };
|
|
332
|
-
},
|
|
333
|
-
});
|
|
334
|
-
children[index] = bindStore;
|
|
335
|
-
}
|
|
336
|
-
}
|
|
337
|
-
}
|
|
338
|
-
// @ts-ignore
|
|
339
|
-
setObjectStore(ObjectStore);
|
|
340
|
-
|
|
341
343
|
/** @import { Ref } from './ref.mjs' */
|
|
342
344
|
/** @import { Schema } from '../Schema.types.mjs' */
|
|
343
345
|
/** @import { StoreLayout } from '../StoreLayout.types.mjs' */
|
|
@@ -378,10 +380,25 @@ class Store {
|
|
|
378
380
|
/**
|
|
379
381
|
* 监听事件
|
|
380
382
|
* @template {keyof Schema.Events} K
|
|
383
|
+
* @overload
|
|
381
384
|
* @param {K} event
|
|
382
385
|
* @param {(this: this, p: Schema.Events[K], store: this) => void | boolean | null} listener
|
|
383
386
|
* @returns {() => void}
|
|
384
387
|
*/
|
|
388
|
+
/**
|
|
389
|
+
* 监听事件
|
|
390
|
+
* @template {keyof Schema.Events} K
|
|
391
|
+
* @overload
|
|
392
|
+
* @param {string} event
|
|
393
|
+
* @param {(this: this, p: unknown, store: this) => void | boolean | null} listener
|
|
394
|
+
* @returns {() => void}
|
|
395
|
+
*/
|
|
396
|
+
/**
|
|
397
|
+
* 监听事件
|
|
398
|
+
* @param {string} event
|
|
399
|
+
* @param {(this: this, p: unknown, store: this) => void | boolean | null} listener
|
|
400
|
+
* @returns {() => void}
|
|
401
|
+
*/
|
|
385
402
|
listen(event, listener) {
|
|
386
403
|
const originStore = this.#originStore;
|
|
387
404
|
if (originStore) { return originStore.listen(event, p => listener.call(this, p, this)); }
|
|
@@ -426,116 +443,87 @@ class Store {
|
|
|
426
443
|
get ref() { return this.#ref || createRef(this); }
|
|
427
444
|
/**
|
|
428
445
|
* @param {Schema.Field<M, S> | Store<T,M,S>} schema 字段的 Schema 定义
|
|
429
|
-
* @param {
|
|
430
|
-
* @param {Store?} [options.parent]
|
|
431
|
-
* @param {Partial<S>?} [options.states]
|
|
432
|
-
* @param {((store: Store, value?: any) => any) | object | number | string | boolean | null | undefined} [options.default]
|
|
433
|
-
* @param {number | string | null} [options.index]
|
|
434
|
-
* @param {number | Signal.State<number> | Signal.Computed<number>} [options.size]
|
|
435
|
-
* @param {boolean} [options.null]
|
|
436
|
-
* @param {boolean} [options.new]
|
|
437
|
-
* @param {boolean} [options.hidden]
|
|
438
|
-
* @param {boolean} [options.clearable]
|
|
439
|
-
* @param {boolean} [options.required]
|
|
440
|
-
* @param {boolean} [options.disabled]
|
|
441
|
-
* @param {boolean} [options.readonly]
|
|
442
|
-
* @param {boolean} [options.removable]
|
|
443
|
-
*
|
|
444
|
-
* @param {string} [options.label] 字段标签
|
|
445
|
-
* @param {string} [options.description] 字段描述
|
|
446
|
-
* @param {string} [options.placeholder] 占位符
|
|
447
|
-
* @param {number} [options.min] 日期、时间、数字的最小值
|
|
448
|
-
* @param {number} [options.max] 日期、时间、数字的最大值
|
|
449
|
-
* @param {number} [options.step] 日期、时间、数字的步长
|
|
450
|
-
* @param {number} [options.minLength]
|
|
451
|
-
* @param {number} [options.maxLength]
|
|
452
|
-
* @param {RegExp} [options.pattern]
|
|
453
|
-
* @param {(Schema.Value.Group | Schema.Value | string | number)[]} [options.values] 可选值
|
|
454
|
-
* @param {Schema.Validator | Schema.Validator[] | null} [options.validator]
|
|
455
|
-
* @param {{[k in keyof Schema.Events]?: Schema.AsyncValidator | Schema.AsyncValidator[] | null}} [options.validators]
|
|
456
|
-
*
|
|
457
|
-
* @param {Ref?} [options.ref]
|
|
458
|
-
*
|
|
459
|
-
* @param {((value: any) => any)?} [options.setValue]
|
|
460
|
-
* @param {((value: any) => any)?} [options.convert]
|
|
461
|
-
*
|
|
462
|
-
* @param {((value: T?, index: any, store: Store) => void)?} [options.onUpdate]
|
|
446
|
+
* @param {StoreOptions | AbortSignal | null} [options] 可选配置
|
|
463
447
|
*/
|
|
464
|
-
constructor(schema, {
|
|
465
|
-
null: isNull, ref, default: defaultValue,
|
|
466
|
-
setValue, convert, onUpdate, states,
|
|
467
|
-
validator, validators,
|
|
468
|
-
index, size, new: isNew, parent: parentNode,
|
|
469
|
-
hidden, clearable, required, disabled, readonly, removable,
|
|
470
|
-
label, description, placeholder, min, max, step, minLength, maxLength, pattern, values: values$1
|
|
471
|
-
} = {}) {
|
|
448
|
+
constructor(schema, options) {
|
|
472
449
|
if (schema instanceof Store) {
|
|
473
|
-
|
|
474
|
-
this.#
|
|
475
|
-
this.#
|
|
476
|
-
this.#
|
|
477
|
-
this.#
|
|
478
|
-
this.#
|
|
479
|
-
this.#
|
|
480
|
-
this.#
|
|
481
|
-
this.#
|
|
482
|
-
this.#
|
|
483
|
-
this.#
|
|
484
|
-
this.#
|
|
485
|
-
this.#
|
|
486
|
-
this.#
|
|
487
|
-
this.#
|
|
488
|
-
this.#
|
|
489
|
-
this.#
|
|
490
|
-
this.#
|
|
491
|
-
this.#
|
|
492
|
-
this.#
|
|
493
|
-
this.#
|
|
494
|
-
this.#
|
|
495
|
-
this.#
|
|
496
|
-
this.#
|
|
497
|
-
this.#
|
|
498
|
-
this.#
|
|
499
|
-
this.#
|
|
500
|
-
this.#
|
|
501
|
-
this.#
|
|
502
|
-
this.#
|
|
503
|
-
this.#
|
|
504
|
-
this.#
|
|
505
|
-
this.#
|
|
506
|
-
this.#
|
|
507
|
-
this.#
|
|
508
|
-
this.#
|
|
509
|
-
this.#
|
|
510
|
-
this.#
|
|
511
|
-
this.#
|
|
512
|
-
this.#
|
|
513
|
-
this.#
|
|
514
|
-
this.#
|
|
515
|
-
this.#
|
|
516
|
-
this.#
|
|
517
|
-
this.#
|
|
518
|
-
this.#
|
|
519
|
-
this.#
|
|
520
|
-
this.#
|
|
521
|
-
this.#
|
|
522
|
-
this.#
|
|
523
|
-
this.#
|
|
524
|
-
this.#
|
|
525
|
-
this.#
|
|
526
|
-
this.#
|
|
527
|
-
this.#
|
|
528
|
-
this.#
|
|
529
|
-
this.#
|
|
530
|
-
this.#
|
|
531
|
-
this.#
|
|
532
|
-
this.#
|
|
533
|
-
this.#
|
|
534
|
-
this.#
|
|
535
|
-
|
|
536
|
-
|
|
450
|
+
const store = schema.#originStore || schema;
|
|
451
|
+
this.#originStore = store;
|
|
452
|
+
this.#schema = store.#schema;
|
|
453
|
+
this.#null = store.#null;
|
|
454
|
+
this.#ref = store.#ref;
|
|
455
|
+
this.#states = store.#states;
|
|
456
|
+
this.#layout = store.#layout;
|
|
457
|
+
this.#createDefault = store.#createDefault;
|
|
458
|
+
this.#setValue = store.#setValue;
|
|
459
|
+
this.#convert = store.#convert;
|
|
460
|
+
this.#onUpdate = store.#onUpdate;
|
|
461
|
+
this.#parent = store.#parent;
|
|
462
|
+
this.#root = store.#root;
|
|
463
|
+
this.#type = store.#type;
|
|
464
|
+
this.#meta = store.#meta;
|
|
465
|
+
this.#component = store.#component;
|
|
466
|
+
this.#selfLoading = store.#selfLoading;
|
|
467
|
+
this.#loading = store.#loading;
|
|
468
|
+
this.#size = store.#size;
|
|
469
|
+
this.#index = store.#index;
|
|
470
|
+
this.#creatable = store.#creatable;
|
|
471
|
+
this.#immutable = store.#immutable;
|
|
472
|
+
this.#new = store.#new;
|
|
473
|
+
this.#selfNew = store.#selfNew;
|
|
474
|
+
this.#selfHidden = store.#selfHidden;
|
|
475
|
+
this.#hidden = store.#hidden;
|
|
476
|
+
this.#selfClearable = store.#selfClearable;
|
|
477
|
+
this.#clearable = store.#clearable;
|
|
478
|
+
this.#selfRequired = store.#selfRequired;
|
|
479
|
+
this.#required = store.#required;
|
|
480
|
+
this.#selfDisabled = store.#selfDisabled;
|
|
481
|
+
this.#disabled = store.#disabled;
|
|
482
|
+
this.#selfReadonly = store.#selfReadonly;
|
|
483
|
+
this.#readonly = store.#readonly;
|
|
484
|
+
this.#selfRemovable = store.#selfRemovable;
|
|
485
|
+
this.#removable = store.#removable;
|
|
486
|
+
this.#selfLabel = store.#selfLabel;
|
|
487
|
+
this.#label = store.#label;
|
|
488
|
+
this.#selfDescription = store.#selfDescription;
|
|
489
|
+
this.#description = store.#description;
|
|
490
|
+
this.#selfPlaceholder = store.#selfPlaceholder;
|
|
491
|
+
this.#placeholder = store.#placeholder;
|
|
492
|
+
this.#selfMin = store.#selfMin;
|
|
493
|
+
this.#min = store.#min;
|
|
494
|
+
this.#selfMax = store.#selfMax;
|
|
495
|
+
this.#max = store.#max;
|
|
496
|
+
this.#selfStep = store.#selfStep;
|
|
497
|
+
this.#step = store.#step;
|
|
498
|
+
this.#selfMinLength = store.#selfMinLength;
|
|
499
|
+
this.#minLength = store.#minLength;
|
|
500
|
+
this.#selfMaxLength = store.#selfMaxLength;
|
|
501
|
+
this.#maxLength = store.#maxLength;
|
|
502
|
+
this.#selfPattern = store.#selfPattern;
|
|
503
|
+
this.#pattern = store.#pattern;
|
|
504
|
+
this.#selfValues = store.#selfValues;
|
|
505
|
+
this.#values = store.#values;
|
|
506
|
+
this.#errors = store.#errors;
|
|
507
|
+
this.#execValidators = store.#execValidators;
|
|
508
|
+
this.#cancelEventValidator = store.#cancelEventValidator;
|
|
509
|
+
this.#set = store.#set;
|
|
510
|
+
this.#initValue = store.#initValue;
|
|
511
|
+
this.#value = store.#value;
|
|
512
|
+
const signal = options instanceof AbortSignal ? options : null;
|
|
513
|
+
if (signal?.aborted) { return; }
|
|
514
|
+
const subBindStores = store.#subBindStores;
|
|
515
|
+
subBindStores.add(this);
|
|
516
|
+
signal?.addEventListener('abort', () => subBindStores.delete(this));
|
|
517
|
+
store.#requestUpdate();
|
|
537
518
|
return;
|
|
538
519
|
}
|
|
520
|
+
const {
|
|
521
|
+
null: isNull, ref, default: defaultValue,
|
|
522
|
+
setValue, convert, onUpdate, states, validator,
|
|
523
|
+
index, size, new: isNew, parent: parentNode,
|
|
524
|
+
hidden, clearable, required, disabled, readonly, removable,
|
|
525
|
+
label, description, placeholder, min, max, step, minLength, maxLength, pattern, values: values$1
|
|
526
|
+
} = !(options instanceof AbortSignal) && options || {};
|
|
539
527
|
this.#schema = schema;
|
|
540
528
|
const parent = parentNode instanceof Store ? parentNode : null;
|
|
541
529
|
if (parent) {
|
|
@@ -606,9 +594,6 @@ class Store {
|
|
|
606
594
|
|
|
607
595
|
[this.#selfRemovable, this.#removable] = createBooleanStates(this, removable, schema.removable ?? true);
|
|
608
596
|
|
|
609
|
-
const validatorResult = createValidator(this, schema.validator, validator);
|
|
610
|
-
|
|
611
|
-
|
|
612
597
|
const schemaStates = schema.states;
|
|
613
598
|
this.#states = schemaStates ? Object.defineProperties(Object.create(null),
|
|
614
599
|
Object.fromEntries(
|
|
@@ -624,16 +609,13 @@ class Store {
|
|
|
624
609
|
})
|
|
625
610
|
)) : null;
|
|
626
611
|
|
|
627
|
-
const [
|
|
628
|
-
const [
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
this.#errors =
|
|
632
|
-
this.#
|
|
633
|
-
this.#
|
|
634
|
-
this.#blurred = blurred;
|
|
635
|
-
this.#cancelChange = cancelChange;
|
|
636
|
-
this.#cancelBlur = cancelBlur;
|
|
612
|
+
const [execValidators, eventExecMap, errors, cancelEventValidator] = createValidator(this, schema.validator, validator);
|
|
613
|
+
for (const [name, exec] of Object.entries(eventExecMap)) {
|
|
614
|
+
this.listen(name, () => { exec(); });
|
|
615
|
+
}
|
|
616
|
+
this.#errors = errors;
|
|
617
|
+
this.#execValidators = execValidators;
|
|
618
|
+
this.#cancelEventValidator = cancelEventValidator;
|
|
637
619
|
|
|
638
620
|
if (size instanceof Signal.State || size instanceof Signal.Computed) {
|
|
639
621
|
this.#size = size;
|
|
@@ -918,16 +900,10 @@ class Store {
|
|
|
918
900
|
|
|
919
901
|
/** @type {Signal.Computed<string[]>} */
|
|
920
902
|
#errors;
|
|
921
|
-
/** @type {Signal.Computed<string[]>} */
|
|
922
|
-
#validatorResult;
|
|
923
|
-
/** @type {() => Promise<string[]>} */
|
|
924
|
-
#changed;
|
|
925
903
|
/** @type {() => Promise<string[]>} */
|
|
926
|
-
#
|
|
904
|
+
#execValidators;
|
|
927
905
|
/** @type {() => void} */
|
|
928
|
-
#
|
|
929
|
-
/** @type {() => void} */
|
|
930
|
-
#cancelBlur;
|
|
906
|
+
#cancelEventValidator;
|
|
931
907
|
/** 所有校验错误列表 */
|
|
932
908
|
get errors() { return this.#errors.get(); }
|
|
933
909
|
/** 字段校验错误信息 */
|
|
@@ -948,24 +924,6 @@ class Store {
|
|
|
948
924
|
|
|
949
925
|
/** @type {Set<Store>} */
|
|
950
926
|
#subBindStores = new Set();
|
|
951
|
-
/**
|
|
952
|
-
* @template [M=any]
|
|
953
|
-
* @template {Object.<string, Schema.State>} [S=Object.<string, Schema.State>]
|
|
954
|
-
* @param {Schema<M, S>} schema 数据结构模式
|
|
955
|
-
* @param {AbortSignal} [signal]
|
|
956
|
-
* @returns {BindObjectStore}
|
|
957
|
-
*/
|
|
958
|
-
bindObject(schema, signal) {
|
|
959
|
-
const originStore = this.#originStore;
|
|
960
|
-
if (originStore) { return originStore.bindObject(schema, signal); }
|
|
961
|
-
const store = new BindObjectStore(schema, this);
|
|
962
|
-
if (signal?.aborted) { return store; }
|
|
963
|
-
const subBindStores = this.#subBindStores;
|
|
964
|
-
subBindStores.add(store);
|
|
965
|
-
signal?.addEventListener('abort', () => subBindStores.delete(store));
|
|
966
|
-
this.#requestUpdate();
|
|
967
|
-
return store;
|
|
968
|
-
}
|
|
969
927
|
|
|
970
928
|
/** 内容是否已改变 */
|
|
971
929
|
get changed() { return !Object.is(this.#value.get(), this.#initValue.get()); }
|
|
@@ -1009,8 +967,7 @@ class Store {
|
|
|
1009
967
|
this.#selfNew.set(isNew);
|
|
1010
968
|
const newValue = this.#setValue?.(v);
|
|
1011
969
|
const value = newValue === undefined ? v : newValue;
|
|
1012
|
-
this.#
|
|
1013
|
-
this.#cancelBlur();
|
|
970
|
+
this.#cancelEventValidator();
|
|
1014
971
|
this.#set = true;
|
|
1015
972
|
if (!value || typeof value !== 'object') {
|
|
1016
973
|
for (const bind of [this, ...this.#subBindStores]) {
|
|
@@ -1062,7 +1019,7 @@ class Store {
|
|
|
1062
1019
|
// @ts-ignore
|
|
1063
1020
|
let newValues = Array.isArray(val) ? [...val] : { ...val };
|
|
1064
1021
|
let updated = false;
|
|
1065
|
-
for (const bind of [this
|
|
1022
|
+
for (const bind of [this, ...this.#subBindStores]) {
|
|
1066
1023
|
for (const [key, field] of bind) {
|
|
1067
1024
|
// @ts-ignore
|
|
1068
1025
|
const data = Object.hasOwn(val, key) ? val[key] : undefined;
|
|
@@ -1106,11 +1063,7 @@ class Store {
|
|
|
1106
1063
|
validate(path) {
|
|
1107
1064
|
if (path === true) {
|
|
1108
1065
|
if (this.#originStore) { return Promise.resolve(null); }
|
|
1109
|
-
return
|
|
1110
|
-
.then(v => {
|
|
1111
|
-
const errors = v.flat();
|
|
1112
|
-
return errors.length ? errors : null;
|
|
1113
|
-
});
|
|
1066
|
+
return this.#execValidators().then(errors => errors.length ? errors : null);
|
|
1114
1067
|
}
|
|
1115
1068
|
const selfPath = Array.isArray(path) ? path : [];
|
|
1116
1069
|
if (!this.#originStore && this.#hidden.get()) { return Promise.resolve([]); }
|
|
@@ -1128,6 +1081,45 @@ class Store {
|
|
|
1128
1081
|
}
|
|
1129
1082
|
}
|
|
1130
1083
|
|
|
1084
|
+
/**
|
|
1085
|
+
* @template [T=any]
|
|
1086
|
+
* @template [M=any]
|
|
1087
|
+
* @template {Object.<string, Schema.State>} [S=Object.<string, Schema.State>]
|
|
1088
|
+
* @typedef {object} StoreOptions
|
|
1089
|
+
* @property {Store?} [parent]
|
|
1090
|
+
* @property {Partial<S>?} [states]
|
|
1091
|
+
* @property {((store: Store, value?: any) => any) | object | number | string | boolean | null | undefined} [default]
|
|
1092
|
+
* @property {number | string | null} [index]
|
|
1093
|
+
* @property {number | Signal.State<number> | Signal.Computed<number>} [size]
|
|
1094
|
+
* @property {boolean} [null]
|
|
1095
|
+
* @property {boolean} [new]
|
|
1096
|
+
* @property {boolean} [hidden]
|
|
1097
|
+
* @property {boolean} [clearable]
|
|
1098
|
+
* @property {boolean} [required]
|
|
1099
|
+
* @property {boolean} [disabled]
|
|
1100
|
+
* @property {boolean} [readonly]
|
|
1101
|
+
* @property {boolean} [removable]
|
|
1102
|
+
*
|
|
1103
|
+
* @property {string} [label] 字段标签
|
|
1104
|
+
* @property {string} [description] 字段描述
|
|
1105
|
+
* @property {string} [placeholder] 占位符
|
|
1106
|
+
* @property {number} [min] 日期、时间、数字的最小值
|
|
1107
|
+
* @property {number} [max] 日期、时间、数字的最大值
|
|
1108
|
+
* @property {number} [step] 日期、时间、数字的步长
|
|
1109
|
+
* @property {number} [minLength]
|
|
1110
|
+
* @property {number} [maxLength]
|
|
1111
|
+
* @property {RegExp} [pattern]
|
|
1112
|
+
* @property {(Schema.Value.Group | Schema.Value | string | number)[]} [values] 可选值
|
|
1113
|
+
* @property {Schema.Validator | Schema.Validator[] | null} [validator]
|
|
1114
|
+
*
|
|
1115
|
+
* @property {Ref?} [ref]
|
|
1116
|
+
*
|
|
1117
|
+
* @property {((value: any) => any)?} [setValue]
|
|
1118
|
+
* @property {((value: any) => any)?} [convert]
|
|
1119
|
+
*
|
|
1120
|
+
* @property {((value: T?, index: any, store: Store) => void)?} [onUpdate]
|
|
1121
|
+
*/
|
|
1122
|
+
|
|
1131
1123
|
/** @import { Schema } from '../Schema.types.mjs' */
|
|
1132
1124
|
|
|
1133
1125
|
/**
|
|
@@ -1136,7 +1128,7 @@ class Store {
|
|
|
1136
1128
|
* @template {Object.<string, Schema.State>} [S=Object.<string, Schema.State>]
|
|
1137
1129
|
* @extends {Store<T, M, S>}
|
|
1138
1130
|
*/
|
|
1139
|
-
|
|
1131
|
+
class ObjectStore extends Store {
|
|
1140
1132
|
get kind() { return 'object'; }
|
|
1141
1133
|
/** @type {Record<string, Store>} */
|
|
1142
1134
|
#children;
|
|
@@ -1189,9 +1181,9 @@ let ObjectStore$1 = class ObjectStore extends Store {
|
|
|
1189
1181
|
}
|
|
1190
1182
|
this.#children = children;
|
|
1191
1183
|
}
|
|
1192
|
-
}
|
|
1184
|
+
}
|
|
1193
1185
|
// @ts-ignore
|
|
1194
|
-
setObjectStore(ObjectStore
|
|
1186
|
+
setObjectStore(ObjectStore);
|
|
1195
1187
|
|
|
1196
1188
|
/** @import { Schema } from '../Schema.types.mjs' */
|
|
1197
1189
|
|
|
@@ -1433,6 +1425,51 @@ class ArrayStore extends Store {
|
|
|
1433
1425
|
// @ts-ignore
|
|
1434
1426
|
setArrayStore(ArrayStore);
|
|
1435
1427
|
|
|
1428
|
+
/** @import { Schema } from '../Schema.types.mjs' */
|
|
1429
|
+
|
|
1430
|
+
/**
|
|
1431
|
+
* @template [T=any]
|
|
1432
|
+
* @template [M=any]
|
|
1433
|
+
* @template {Object.<string, Schema.State>} [S=Object.<string, Schema.State>]
|
|
1434
|
+
* @extends {Store<T, M, S>}
|
|
1435
|
+
*/
|
|
1436
|
+
class BindObjectStore extends Store {
|
|
1437
|
+
|
|
1438
|
+
get kind() { return 'object'; }
|
|
1439
|
+
/** @type {Record<string, Store>} */
|
|
1440
|
+
#children = Object.create(null);
|
|
1441
|
+
*[Symbol.iterator]() { yield* Object.entries(this.#children); }
|
|
1442
|
+
/**
|
|
1443
|
+
*
|
|
1444
|
+
* @param {string | number} key
|
|
1445
|
+
* @returns {Store?}
|
|
1446
|
+
*/
|
|
1447
|
+
child(key) { return this.#children[key] || null; }
|
|
1448
|
+
/**
|
|
1449
|
+
* @param {Schema<any, Object.<string, Schema.State>>} schema 数据结构模式
|
|
1450
|
+
* @param {Store<T, M, S>} store
|
|
1451
|
+
* @param {AbortSignal} [signal]
|
|
1452
|
+
*/
|
|
1453
|
+
constructor(schema, store, signal) {
|
|
1454
|
+
super(store, signal);
|
|
1455
|
+
const children = this.#children;
|
|
1456
|
+
for (const [index, field] of Object.entries(schema)) {
|
|
1457
|
+
const bindStore = create(field, {
|
|
1458
|
+
index, parent: this,
|
|
1459
|
+
/** @param {*} value @param {*} index @param {Store} store */
|
|
1460
|
+
onUpdate: (value, index, store) => {
|
|
1461
|
+
if (store !== children[index]) { return; }
|
|
1462
|
+
const val = this.value ?? null;
|
|
1463
|
+
if (typeof val !== 'object' || Array.isArray(val)) { return; }
|
|
1464
|
+
// @ts-ignore
|
|
1465
|
+
this.value = { ...val, [index]: value };
|
|
1466
|
+
},
|
|
1467
|
+
});
|
|
1468
|
+
children[index] = bindStore;
|
|
1469
|
+
}
|
|
1470
|
+
}
|
|
1471
|
+
}
|
|
1472
|
+
|
|
1436
1473
|
/** @import * as Layout from './index.mjs' */
|
|
1437
1474
|
|
|
1438
1475
|
/** @import { OldNode } from './createElement.mjs' */
|
|
@@ -4861,7 +4898,7 @@ function renderChild(layout, parent, next, parentEnv, parentTemplates, component
|
|
|
4861
4898
|
if (list instanceof ArrayStore) {
|
|
4862
4899
|
return renderArray(parent, next, list, env, r, layout.sort);
|
|
4863
4900
|
}
|
|
4864
|
-
if (list instanceof ObjectStore
|
|
4901
|
+
if (list instanceof ObjectStore) {
|
|
4865
4902
|
return renderObject(parent, next, list, env, r, layout.sort);
|
|
4866
4903
|
}
|
|
4867
4904
|
if (typeof list === 'function') {
|
|
@@ -6593,4 +6630,4 @@ function renderStore(store, fieldRenderer, root, layout, options) {
|
|
|
6593
6630
|
}, { once: true });
|
|
6594
6631
|
}
|
|
6595
6632
|
|
|
6596
|
-
export { ArrayStore, index as Layout, ObjectStore
|
|
6633
|
+
export { ArrayStore, BindObjectStore, index as Layout, ObjectStore, Store, effect, render, renderStore, watch };
|