@neeloong/form 0.29.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 +31 -33
- package/index.full.js +190 -149
- package/index.full.min.js +2 -2
- package/index.full.min.mjs +4 -4
- package/index.min.mjs +2 -2
- package/index.mjs +190 -149
- 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
|
*/
|
|
@@ -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
251
|
}
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
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());
|
|
261
|
+
}
|
|
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' */
|
|
@@ -332,10 +380,25 @@ class Store {
|
|
|
332
380
|
/**
|
|
333
381
|
* 监听事件
|
|
334
382
|
* @template {keyof Schema.Events} K
|
|
383
|
+
* @overload
|
|
335
384
|
* @param {K} event
|
|
336
385
|
* @param {(this: this, p: Schema.Events[K], store: this) => void | boolean | null} listener
|
|
337
386
|
* @returns {() => void}
|
|
338
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
|
+
*/
|
|
339
402
|
listen(event, listener) {
|
|
340
403
|
const originStore = this.#originStore;
|
|
341
404
|
if (originStore) { return originStore.listen(event, p => listener.call(this, p, this)); }
|
|
@@ -385,73 +448,70 @@ class Store {
|
|
|
385
448
|
constructor(schema, options) {
|
|
386
449
|
if (schema instanceof Store) {
|
|
387
450
|
const store = schema.#originStore || schema;
|
|
388
|
-
this.#originStore= store;
|
|
389
|
-
this.#schema= store.#schema;
|
|
390
|
-
this.#null= store.#null;
|
|
391
|
-
this.#ref= store.#ref;
|
|
392
|
-
this.#states= store.#states;
|
|
393
|
-
this.#layout= store.#layout;
|
|
394
|
-
this.#createDefault= store.#createDefault;
|
|
395
|
-
this.#setValue= store.#setValue;
|
|
396
|
-
this.#convert= store.#convert;
|
|
397
|
-
this.#onUpdate= store.#onUpdate;
|
|
398
|
-
this.#parent= store.#parent;
|
|
399
|
-
this.#root= store.#root;
|
|
400
|
-
this.#type= store.#type;
|
|
401
|
-
this.#meta= store.#meta;
|
|
402
|
-
this.#component= store.#component;
|
|
403
|
-
this.#selfLoading= store.#selfLoading;
|
|
404
|
-
this.#loading= store.#loading;
|
|
405
|
-
this.#size= store.#size;
|
|
406
|
-
this.#index= store.#index;
|
|
407
|
-
this.#creatable= store.#creatable;
|
|
408
|
-
this.#immutable= store.#immutable;
|
|
409
|
-
this.#new= store.#new;
|
|
410
|
-
this.#selfNew= store.#selfNew;
|
|
411
|
-
this.#selfHidden= store.#selfHidden;
|
|
412
|
-
this.#hidden= store.#hidden;
|
|
413
|
-
this.#selfClearable= store.#selfClearable;
|
|
414
|
-
this.#clearable= store.#clearable;
|
|
415
|
-
this.#selfRequired= store.#selfRequired;
|
|
416
|
-
this.#required= store.#required;
|
|
417
|
-
this.#selfDisabled= store.#selfDisabled;
|
|
418
|
-
this.#disabled= store.#disabled;
|
|
419
|
-
this.#selfReadonly= store.#selfReadonly;
|
|
420
|
-
this.#readonly= store.#readonly;
|
|
421
|
-
this.#selfRemovable= store.#selfRemovable;
|
|
422
|
-
this.#removable= store.#removable;
|
|
423
|
-
this.#selfLabel= store.#selfLabel;
|
|
424
|
-
this.#label= store.#label;
|
|
425
|
-
this.#selfDescription= store.#selfDescription;
|
|
426
|
-
this.#description= store.#description;
|
|
427
|
-
this.#selfPlaceholder= store.#selfPlaceholder;
|
|
428
|
-
this.#placeholder= store.#placeholder;
|
|
429
|
-
this.#selfMin= store.#selfMin;
|
|
430
|
-
this.#min= store.#min;
|
|
431
|
-
this.#selfMax= store.#selfMax;
|
|
432
|
-
this.#max= store.#max;
|
|
433
|
-
this.#selfStep= store.#selfStep;
|
|
434
|
-
this.#step= store.#step;
|
|
435
|
-
this.#selfMinLength= store.#selfMinLength;
|
|
436
|
-
this.#minLength= store.#minLength;
|
|
437
|
-
this.#selfMaxLength= store.#selfMaxLength;
|
|
438
|
-
this.#maxLength= store.#maxLength;
|
|
439
|
-
this.#selfPattern= store.#selfPattern;
|
|
440
|
-
this.#pattern= store.#pattern;
|
|
441
|
-
this.#selfValues= store.#selfValues;
|
|
442
|
-
this.#values= store.#values;
|
|
443
|
-
this.#errors= store.#errors;
|
|
444
|
-
this.#
|
|
445
|
-
this.#
|
|
446
|
-
this.#
|
|
447
|
-
this.#
|
|
448
|
-
this.#
|
|
449
|
-
this.#set= store.#set;
|
|
450
|
-
this.#initValue= store.#initValue;
|
|
451
|
-
this.#value= store.#value;
|
|
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;
|
|
452
512
|
const signal = options instanceof AbortSignal ? options : null;
|
|
453
513
|
if (signal?.aborted) { return; }
|
|
454
|
-
const subBindStores= store.#subBindStores;
|
|
514
|
+
const subBindStores = store.#subBindStores;
|
|
455
515
|
subBindStores.add(this);
|
|
456
516
|
signal?.addEventListener('abort', () => subBindStores.delete(this));
|
|
457
517
|
store.#requestUpdate();
|
|
@@ -459,8 +519,7 @@ class Store {
|
|
|
459
519
|
}
|
|
460
520
|
const {
|
|
461
521
|
null: isNull, ref, default: defaultValue,
|
|
462
|
-
setValue, convert, onUpdate, states,
|
|
463
|
-
validator, validators,
|
|
522
|
+
setValue, convert, onUpdate, states, validator,
|
|
464
523
|
index, size, new: isNew, parent: parentNode,
|
|
465
524
|
hidden, clearable, required, disabled, readonly, removable,
|
|
466
525
|
label, description, placeholder, min, max, step, minLength, maxLength, pattern, values: values$1
|
|
@@ -535,9 +594,6 @@ class Store {
|
|
|
535
594
|
|
|
536
595
|
[this.#selfRemovable, this.#removable] = createBooleanStates(this, removable, schema.removable ?? true);
|
|
537
596
|
|
|
538
|
-
const validatorResult = createValidator(this, schema.validator, validator);
|
|
539
|
-
|
|
540
|
-
|
|
541
597
|
const schemaStates = schema.states;
|
|
542
598
|
this.#states = schemaStates ? Object.defineProperties(Object.create(null),
|
|
543
599
|
Object.fromEntries(
|
|
@@ -553,16 +609,13 @@ class Store {
|
|
|
553
609
|
})
|
|
554
610
|
)) : null;
|
|
555
611
|
|
|
556
|
-
const [
|
|
557
|
-
const [
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
this.#errors =
|
|
561
|
-
this.#
|
|
562
|
-
this.#
|
|
563
|
-
this.#blurred = blurred;
|
|
564
|
-
this.#cancelChange = cancelChange;
|
|
565
|
-
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;
|
|
566
619
|
|
|
567
620
|
if (size instanceof Signal.State || size instanceof Signal.Computed) {
|
|
568
621
|
this.#size = size;
|
|
@@ -847,16 +900,10 @@ class Store {
|
|
|
847
900
|
|
|
848
901
|
/** @type {Signal.Computed<string[]>} */
|
|
849
902
|
#errors;
|
|
850
|
-
/** @type {Signal.Computed<string[]>} */
|
|
851
|
-
#validatorResult;
|
|
852
903
|
/** @type {() => Promise<string[]>} */
|
|
853
|
-
#
|
|
854
|
-
/** @type {() => Promise<string[]>} */
|
|
855
|
-
#blurred;
|
|
856
|
-
/** @type {() => void} */
|
|
857
|
-
#cancelChange;
|
|
904
|
+
#execValidators;
|
|
858
905
|
/** @type {() => void} */
|
|
859
|
-
#
|
|
906
|
+
#cancelEventValidator;
|
|
860
907
|
/** 所有校验错误列表 */
|
|
861
908
|
get errors() { return this.#errors.get(); }
|
|
862
909
|
/** 字段校验错误信息 */
|
|
@@ -920,8 +967,7 @@ class Store {
|
|
|
920
967
|
this.#selfNew.set(isNew);
|
|
921
968
|
const newValue = this.#setValue?.(v);
|
|
922
969
|
const value = newValue === undefined ? v : newValue;
|
|
923
|
-
this.#
|
|
924
|
-
this.#cancelBlur();
|
|
970
|
+
this.#cancelEventValidator();
|
|
925
971
|
this.#set = true;
|
|
926
972
|
if (!value || typeof value !== 'object') {
|
|
927
973
|
for (const bind of [this, ...this.#subBindStores]) {
|
|
@@ -1017,11 +1063,7 @@ class Store {
|
|
|
1017
1063
|
validate(path) {
|
|
1018
1064
|
if (path === true) {
|
|
1019
1065
|
if (this.#originStore) { return Promise.resolve(null); }
|
|
1020
|
-
return
|
|
1021
|
-
.then(v => {
|
|
1022
|
-
const errors = v.flat();
|
|
1023
|
-
return errors.length ? errors : null;
|
|
1024
|
-
});
|
|
1066
|
+
return this.#execValidators().then(errors => errors.length ? errors : null);
|
|
1025
1067
|
}
|
|
1026
1068
|
const selfPath = Array.isArray(path) ? path : [];
|
|
1027
1069
|
if (!this.#originStore && this.#hidden.get()) { return Promise.resolve([]); }
|
|
@@ -1069,7 +1111,6 @@ class Store {
|
|
|
1069
1111
|
* @property {RegExp} [pattern]
|
|
1070
1112
|
* @property {(Schema.Value.Group | Schema.Value | string | number)[]} [values] 可选值
|
|
1071
1113
|
* @property {Schema.Validator | Schema.Validator[] | null} [validator]
|
|
1072
|
-
* @property {{[k in keyof Schema.Events]?: Schema.AsyncValidator | Schema.AsyncValidator[] | null}} [validators]
|
|
1073
1114
|
*
|
|
1074
1115
|
* @property {Ref?} [ref]
|
|
1075
1116
|
*
|