@neeloong/form 0.27.0 → 0.29.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.full.js CHANGED
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * @neeloong/form v0.27.0
2
+ * @neeloong/form v0.29.0
3
3
  * (c) 2024-2026 Fierflame
4
4
  * @license Apache-2.0
5
5
  */
@@ -881,6 +881,12 @@
881
881
  * @template {Object.<string, Schema.State>} [S=Object.<string, Schema.State>]
882
882
  */
883
883
  class Store {
884
+ /** @type {Store<T, M, S>?} */
885
+ #originStore = null;
886
+
887
+ /** @type {Schema.Field<M, S>} 字段的 Schema 定义 */
888
+ #schema;
889
+ get schema() { return this.#schema; }
884
890
  /** @type {Map<string, Set<(value: any, store: any) => void | boolean | null>>} */
885
891
  #events = new Map();
886
892
  /**
@@ -888,8 +894,11 @@
888
894
  * @template {keyof Schema.Events} K
889
895
  * @param {K} event
890
896
  * @param {Schema.Events[K]} value
897
+ * @returns {boolean}
891
898
  */
892
899
  emit(event, value) {
900
+ const originStore = this.#originStore;
901
+ if (originStore) { return originStore.emit(event, value); }
893
902
  const key = typeof event === 'number' ? String(event) : event;
894
903
  const events = this.#events;
895
904
  let canceled = false;
@@ -906,6 +915,8 @@
906
915
  * @returns {() => void}
907
916
  */
908
917
  listen(event, listener) {
918
+ const originStore = this.#originStore;
919
+ if (originStore) { return originStore.listen(event, p => listener.call(this, p, this)); }
909
920
  const fn = listener.bind(this);
910
921
  const events = this.#events;
911
922
  const key = typeof event === 'number' ? String(event) : event;
@@ -946,51 +957,93 @@
946
957
  #ref = null;
947
958
  get ref() { return this.#ref || createRef(this); }
948
959
  /**
949
- * @param {Schema.Field<M, S>} schema 字段的 Schema 定义
950
- * @param {object} [options] 可选配置
951
- * @param {Store?} [options.parent]
952
- * @param {Partial<S>?} [options.states]
953
- * @param {((store: Store, value?: any) => any) | object | number | string | boolean | null | undefined} [options.default]
954
- * @param {number | string | null} [options.index]
955
- * @param {number | Signal.State<number> | Signal.Computed<number>} [options.size]
956
- * @param {boolean} [options.null]
957
- * @param {boolean} [options.new]
958
- * @param {boolean} [options.hidden]
959
- * @param {boolean} [options.clearable]
960
- * @param {boolean} [options.required]
961
- * @param {boolean} [options.disabled]
962
- * @param {boolean} [options.readonly]
963
- * @param {boolean} [options.removable]
964
- *
965
- * @param {string} [options.label] 字段标签
966
- * @param {string} [options.description] 字段描述
967
- * @param {string} [options.placeholder] 占位符
968
- * @param {number} [options.min] 日期、时间、数字的最小值
969
- * @param {number} [options.max] 日期、时间、数字的最大值
970
- * @param {number} [options.step] 日期、时间、数字的步长
971
- * @param {number} [options.minLength]
972
- * @param {number} [options.maxLength]
973
- * @param {RegExp} [options.pattern]
974
- * @param {(Schema.Value.Group | Schema.Value | string | number)[]} [options.values] 可选值
975
- * @param {Schema.Validator | Schema.Validator[] | null} [options.validator]
976
- * @param {{[k in keyof Schema.Events]?: Schema.AsyncValidator | Schema.AsyncValidator[] | null}} [options.validators]
977
- *
978
- * @param {Ref?} [options.ref]
979
- *
980
- * @param {((value: any) => any)?} [options.setValue]
981
- * @param {((value: any) => any)?} [options.convert]
982
- *
983
- * @param {((value: T?, index: any, store: Store) => void)?} [options.onUpdate]
960
+ * @param {Schema.Field<M, S> | Store<T,M,S>} schema 字段的 Schema 定义
961
+ * @param {StoreOptions | AbortSignal | null} [options] 可选配置
984
962
  */
985
- constructor(schema, {
986
- null: isNull, ref, default: defaultValue,
987
- setValue, convert, onUpdate, states,
988
- validator, validators,
989
- index, size, new: isNew, parent: parentNode,
990
- hidden, clearable, required, disabled, readonly, removable,
991
- label, description, placeholder, min, max, step, minLength, maxLength, pattern, values: values$1
992
- } = {}) {
993
- this.schema = schema;
963
+ constructor(schema, options) {
964
+ if (schema instanceof Store) {
965
+ const store = schema.#originStore || schema;
966
+ this.#originStore= store;
967
+ this.#schema= store.#schema;
968
+ this.#null= store.#null;
969
+ this.#ref= store.#ref;
970
+ this.#states= store.#states;
971
+ this.#layout= store.#layout;
972
+ this.#createDefault= store.#createDefault;
973
+ this.#setValue= store.#setValue;
974
+ this.#convert= store.#convert;
975
+ this.#onUpdate= store.#onUpdate;
976
+ this.#parent= store.#parent;
977
+ this.#root= store.#root;
978
+ this.#type= store.#type;
979
+ this.#meta= store.#meta;
980
+ this.#component= store.#component;
981
+ this.#selfLoading= store.#selfLoading;
982
+ this.#loading= store.#loading;
983
+ this.#size= store.#size;
984
+ this.#index= store.#index;
985
+ this.#creatable= store.#creatable;
986
+ this.#immutable= store.#immutable;
987
+ this.#new= store.#new;
988
+ this.#selfNew= store.#selfNew;
989
+ this.#selfHidden= store.#selfHidden;
990
+ this.#hidden= store.#hidden;
991
+ this.#selfClearable= store.#selfClearable;
992
+ this.#clearable= store.#clearable;
993
+ this.#selfRequired= store.#selfRequired;
994
+ this.#required= store.#required;
995
+ this.#selfDisabled= store.#selfDisabled;
996
+ this.#disabled= store.#disabled;
997
+ this.#selfReadonly= store.#selfReadonly;
998
+ this.#readonly= store.#readonly;
999
+ this.#selfRemovable= store.#selfRemovable;
1000
+ this.#removable= store.#removable;
1001
+ this.#selfLabel= store.#selfLabel;
1002
+ this.#label= store.#label;
1003
+ this.#selfDescription= store.#selfDescription;
1004
+ this.#description= store.#description;
1005
+ this.#selfPlaceholder= store.#selfPlaceholder;
1006
+ this.#placeholder= store.#placeholder;
1007
+ this.#selfMin= store.#selfMin;
1008
+ this.#min= store.#min;
1009
+ this.#selfMax= store.#selfMax;
1010
+ this.#max= store.#max;
1011
+ this.#selfStep= store.#selfStep;
1012
+ this.#step= store.#step;
1013
+ this.#selfMinLength= store.#selfMinLength;
1014
+ this.#minLength= store.#minLength;
1015
+ this.#selfMaxLength= store.#selfMaxLength;
1016
+ this.#maxLength= store.#maxLength;
1017
+ this.#selfPattern= store.#selfPattern;
1018
+ this.#pattern= store.#pattern;
1019
+ this.#selfValues= store.#selfValues;
1020
+ this.#values= store.#values;
1021
+ this.#errors= store.#errors;
1022
+ this.#validatorResult= store.#validatorResult;
1023
+ this.#changed= store.#changed;
1024
+ this.#blurred= store.#blurred;
1025
+ this.#cancelChange= store.#cancelChange;
1026
+ this.#cancelBlur= store.#cancelBlur;
1027
+ this.#set= store.#set;
1028
+ this.#initValue= store.#initValue;
1029
+ this.#value= store.#value;
1030
+ const signal = options instanceof AbortSignal ? options : null;
1031
+ if (signal?.aborted) { return; }
1032
+ const subBindStores= store.#subBindStores;
1033
+ subBindStores.add(this);
1034
+ signal?.addEventListener('abort', () => subBindStores.delete(this));
1035
+ store.#requestUpdate();
1036
+ return;
1037
+ }
1038
+ const {
1039
+ null: isNull, ref, default: defaultValue,
1040
+ setValue, convert, onUpdate, states,
1041
+ validator, validators,
1042
+ index, size, new: isNew, parent: parentNode,
1043
+ hidden, clearable, required, disabled, readonly, removable,
1044
+ label, description, placeholder, min, max, step, minLength, maxLength, pattern, values: values$1
1045
+ } = !(options instanceof AbortSignal) && options || {};
1046
+ this.#schema = schema;
994
1047
  const parent = parentNode instanceof Store ? parentNode : null;
995
1048
  if (parent) {
996
1049
  this.#parent = parent;
@@ -1118,6 +1171,7 @@
1118
1171
  /** @type {StoreLayout.Field<any>} */
1119
1172
  #layout;
1120
1173
  get layout() { return this.#layout; }
1174
+ /** @type {(value?: any) => unknown} */
1121
1175
  #createDefault;
1122
1176
  /** @param {any} [value] @returns {any} */
1123
1177
  createDefault(value) { return this.#createDefault(value); }
@@ -1399,40 +1453,8 @@
1399
1453
  #initValue = new exports.Signal.State(/** @type {T?} */(null));
1400
1454
  #value = new exports.Signal.State(this.#initValue.get());
1401
1455
 
1402
- /**
1403
- * @template [M=any]
1404
- * @template {Object.<string, Schema.State>} [S=Object.<string, Schema.State>]
1405
- * @param {Schema<M, S>} schema 数据结构模式
1406
- */
1407
- bindObject(schema) {
1408
- const bindStores = this.#bindStores;
1409
- /** @type {Store[]} */
1410
- const list = [];
1411
- for (const [index, field] of Object.entries(schema)) {
1412
- const bindStore = create(field, {
1413
- index, parent: this,
1414
- /** @param {*} value @param {*} currentIndex @param {Store} store */
1415
- onUpdate: (value, currentIndex, store) => {
1416
- if (index !== currentIndex) { return; }
1417
- if (bindStores.has(store)) { return; }
1418
- const val = this.#value ?? null;
1419
- if (typeof val !== 'object' || Array.isArray(val)) { return }
1420
- // @ts-ignore
1421
- this.value = { ...val, [currentIndex]: value };
1422
- },
1423
- });
1424
- list.push(bindStore);
1425
- bindStores.set(bindStore, index);
1426
- }
1427
- this.#requestUpdate();
1428
- return () => {
1429
- for (const bindStore of list) {
1430
- bindStores.delete(bindStore);
1431
- }
1432
- };
1433
- }
1434
- /** @type {Map<Store, string>} */
1435
- #bindStores = new Map();
1456
+ /** @type {Set<Store>} */
1457
+ #subBindStores = new Set();
1436
1458
 
1437
1459
  /** 内容是否已改变 */
1438
1460
  get changed() { return !Object.is(this.#value.get(), this.#initValue.get()); }
@@ -1440,6 +1462,8 @@
1440
1462
  /** 字段当前值 */
1441
1463
  get value() { return this.#value.get(); }
1442
1464
  set value(v) {
1465
+ const originStore = this.#originStore;
1466
+ if (originStore) { originStore.value = v; return; }
1443
1467
  const newValue = this.#setValue?.(v);
1444
1468
  const val = newValue === undefined ? v : newValue;
1445
1469
  this.#value.set(val);
@@ -1460,6 +1484,8 @@
1460
1484
  }
1461
1485
  /** 重置数据 */
1462
1486
  reset(value = this.#set ? this.#initValue.get() : this.#createDefault(), isNew = this.#selfNew.get()) {
1487
+ const originStore = this.#originStore;
1488
+ if (originStore) { originStore.reset(value, isNew); return; }
1463
1489
  this.#reset(value, Boolean(isNew));
1464
1490
  }
1465
1491
  /**
@@ -1476,11 +1502,10 @@
1476
1502
  this.#cancelBlur();
1477
1503
  this.#set = true;
1478
1504
  if (!value || typeof value !== 'object') {
1479
- for (const [, field] of this) {
1480
- field.#reset(null, false);
1481
- }
1482
- for (const [field] of this.#bindStores) {
1483
- field.#reset(null, false);
1505
+ for (const bind of [this, ...this.#subBindStores]) {
1506
+ for (const [, field] of bind) {
1507
+ field.#reset(null, false);
1508
+ }
1484
1509
  }
1485
1510
  this.#value.set(value);
1486
1511
  this.#initValue.set(value);
@@ -1489,11 +1514,10 @@
1489
1514
  }
1490
1515
  /** @type {*} */
1491
1516
  const newValues = Array.isArray(value) ? [...value] : { ...value };
1492
- for (const [key, field] of this) {
1493
- newValues[key] = field.#reset(Object.hasOwn(newValues, key) ? newValues[key] : undefined, false);
1494
- }
1495
- for (const [field, key] of this.#bindStores) {
1496
- newValues[key] = field.#reset(Object.hasOwn(newValues, key) ? newValues[key] : undefined, false);
1517
+ for (const bind of [this, ...this.#subBindStores]) {
1518
+ for (const [key, field] of bind) {
1519
+ newValues[key] = field.#reset(Object.hasOwn(newValues, key) ? newValues[key] : undefined, false);
1520
+ }
1497
1521
  }
1498
1522
  this.#value.set(newValues);
1499
1523
  this.#initValue.set(newValues);
@@ -1527,23 +1551,16 @@
1527
1551
  // @ts-ignore
1528
1552
  let newValues = Array.isArray(val) ? [...val] : { ...val };
1529
1553
  let updated = false;
1530
- for (const [key, field] of this) {
1531
- // @ts-ignore
1532
- const data = Object.hasOwn(val, key) ? val[key] : undefined;
1533
- const newData = field.#toUpdate(data);
1534
- if (Object.is(data, newData)) { continue; }
1535
- // @ts-ignore
1536
- newValues[key] = newData;
1537
- updated = true;
1538
- }
1539
- for (const [field, key] of this.#bindStores) {
1540
- // @ts-ignore
1541
- const data = Object.hasOwn(val, key) ? val[key] : undefined;
1542
- const newData = field.#toUpdate(data);
1543
- if (Object.is(data, newData)) { continue; }
1544
- // @ts-ignore
1545
- newValues[key] = newData;
1546
- updated = true;
1554
+ for (const bind of [this, ...this.#subBindStores]) {
1555
+ for (const [key, field] of bind) {
1556
+ // @ts-ignore
1557
+ const data = Object.hasOwn(val, key) ? val[key] : undefined;
1558
+ const newData = field.#toUpdate(data);
1559
+ if (Object.is(data, newData)) { continue; }
1560
+ // @ts-ignore
1561
+ newValues[key] = newData;
1562
+ updated = true;
1563
+ }
1547
1564
  }
1548
1565
  if (updated) {
1549
1566
  val = newValues;
@@ -1577,6 +1594,7 @@
1577
1594
  */
1578
1595
  validate(path) {
1579
1596
  if (path === true) {
1597
+ if (this.#originStore) { return Promise.resolve(null); }
1580
1598
  return Promise.all([this.#validatorResult.get(), this.#changed(), this.#blurred()])
1581
1599
  .then(v => {
1582
1600
  const errors = v.flat();
@@ -1584,7 +1602,7 @@
1584
1602
  });
1585
1603
  }
1586
1604
  const selfPath = Array.isArray(path) ? path : [];
1587
- if (this.#hidden.get()) { return Promise.resolve([]); }
1605
+ if (!this.#originStore && this.#hidden.get()) { return Promise.resolve([]); }
1588
1606
  const list = [this.validate(true).then(errors => {
1589
1607
  if (!errors?.length) { return []; }
1590
1608
  return [{ path: [...selfPath], store: /** @type {Store} */(this), errors }];
@@ -1592,13 +1610,53 @@
1592
1610
  for (const [key, field] of this) {
1593
1611
  list.push(field.validate([...selfPath, key]));
1594
1612
  }
1595
- for (const [field, key] of this.#bindStores) {
1596
- list.push(field.validate([...selfPath, key]));
1613
+ for (const sub of this.#subBindStores) {
1614
+ list.push(sub.validate(selfPath));
1597
1615
  }
1598
1616
  return Promise.all(list).then(v => v.flat());
1599
1617
  }
1600
1618
  }
1601
1619
 
1620
+ /**
1621
+ * @template [T=any]
1622
+ * @template [M=any]
1623
+ * @template {Object.<string, Schema.State>} [S=Object.<string, Schema.State>]
1624
+ * @typedef {object} StoreOptions
1625
+ * @property {Store?} [parent]
1626
+ * @property {Partial<S>?} [states]
1627
+ * @property {((store: Store, value?: any) => any) | object | number | string | boolean | null | undefined} [default]
1628
+ * @property {number | string | null} [index]
1629
+ * @property {number | Signal.State<number> | Signal.Computed<number>} [size]
1630
+ * @property {boolean} [null]
1631
+ * @property {boolean} [new]
1632
+ * @property {boolean} [hidden]
1633
+ * @property {boolean} [clearable]
1634
+ * @property {boolean} [required]
1635
+ * @property {boolean} [disabled]
1636
+ * @property {boolean} [readonly]
1637
+ * @property {boolean} [removable]
1638
+ *
1639
+ * @property {string} [label] 字段标签
1640
+ * @property {string} [description] 字段描述
1641
+ * @property {string} [placeholder] 占位符
1642
+ * @property {number} [min] 日期、时间、数字的最小值
1643
+ * @property {number} [max] 日期、时间、数字的最大值
1644
+ * @property {number} [step] 日期、时间、数字的步长
1645
+ * @property {number} [minLength]
1646
+ * @property {number} [maxLength]
1647
+ * @property {RegExp} [pattern]
1648
+ * @property {(Schema.Value.Group | Schema.Value | string | number)[]} [values] 可选值
1649
+ * @property {Schema.Validator | Schema.Validator[] | null} [validator]
1650
+ * @property {{[k in keyof Schema.Events]?: Schema.AsyncValidator | Schema.AsyncValidator[] | null}} [validators]
1651
+ *
1652
+ * @property {Ref?} [ref]
1653
+ *
1654
+ * @property {((value: any) => any)?} [setValue]
1655
+ * @property {((value: any) => any)?} [convert]
1656
+ *
1657
+ * @property {((value: T?, index: any, store: Store) => void)?} [onUpdate]
1658
+ */
1659
+
1602
1660
  /** @import { Schema } from '../Schema.types.mjs' */
1603
1661
 
1604
1662
  /**
@@ -1904,6 +1962,51 @@
1904
1962
  // @ts-ignore
1905
1963
  setArrayStore(ArrayStore);
1906
1964
 
1965
+ /** @import { Schema } from '../Schema.types.mjs' */
1966
+
1967
+ /**
1968
+ * @template [T=any]
1969
+ * @template [M=any]
1970
+ * @template {Object.<string, Schema.State>} [S=Object.<string, Schema.State>]
1971
+ * @extends {Store<T, M, S>}
1972
+ */
1973
+ class BindObjectStore extends Store {
1974
+
1975
+ get kind() { return 'object'; }
1976
+ /** @type {Record<string, Store>} */
1977
+ #children = Object.create(null);
1978
+ *[Symbol.iterator]() { yield* Object.entries(this.#children); }
1979
+ /**
1980
+ *
1981
+ * @param {string | number} key
1982
+ * @returns {Store?}
1983
+ */
1984
+ child(key) { return this.#children[key] || null; }
1985
+ /**
1986
+ * @param {Schema<any, Object.<string, Schema.State>>} schema 数据结构模式
1987
+ * @param {Store<T, M, S>} store
1988
+ * @param {AbortSignal} [signal]
1989
+ */
1990
+ constructor(schema, store, signal) {
1991
+ super(store, signal);
1992
+ const children = this.#children;
1993
+ for (const [index, field] of Object.entries(schema)) {
1994
+ const bindStore = create(field, {
1995
+ index, parent: this,
1996
+ /** @param {*} value @param {*} index @param {Store} store */
1997
+ onUpdate: (value, index, store) => {
1998
+ if (store !== children[index]) { return; }
1999
+ const val = this.value ?? null;
2000
+ if (typeof val !== 'object' || Array.isArray(val)) { return; }
2001
+ // @ts-ignore
2002
+ this.value = { ...val, [index]: value };
2003
+ },
2004
+ });
2005
+ children[index] = bindStore;
2006
+ }
2007
+ }
2008
+ }
2009
+
1907
2010
  /** @import * as Layout from './index.mjs' */
1908
2011
 
1909
2012
  /** @import { OldNode } from './createElement.mjs' */
@@ -7065,6 +7168,7 @@
7065
7168
  }
7066
7169
 
7067
7170
  exports.ArrayStore = ArrayStore;
7171
+ exports.BindObjectStore = BindObjectStore;
7068
7172
  exports.Layout = index;
7069
7173
  exports.ObjectStore = ObjectStore;
7070
7174
  exports.Store = Store;