@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.full.js CHANGED
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * @neeloong/form v0.28.0
2
+ * @neeloong/form v0.30.0
3
3
  * (c) 2024-2026 Fierflame
4
4
  * @license Apache-2.0
5
5
  */
@@ -716,7 +716,7 @@
716
716
 
717
717
 
718
718
  /** @type {{new(...p: ConstructorParameters<typeof Store>): Store}?} */
719
- let ObjectStore$2 = null;
719
+ let ObjectStore$1 = null;
720
720
  /** @type {{new(...p: ConstructorParameters<typeof Store>): ArrayStore}?} */
721
721
  let ArrayStoreClass = null;
722
722
  /** @type {Record<string, {new(...p: ConstructorParameters<typeof Store>): Store}?>} */
@@ -741,14 +741,14 @@
741
741
  const C = TypeStores[type];
742
742
  if (C) { Class = C; }
743
743
  } else if (type && typeof type === 'object') {
744
- if (ObjectStore$2) { Class = ObjectStore$2; }
744
+ if (ObjectStore$1) { Class = ObjectStore$1; }
745
745
  }
746
746
  return new Class(schema, options);
747
747
  }
748
748
 
749
749
  /** @param {{new(...p: ConstructorParameters<typeof Store>): Store}} Class */
750
750
  function setObjectStore(Class) {
751
- ObjectStore$2 = Class;
751
+ ObjectStore$1 = Class;
752
752
  }
753
753
 
754
754
  /** @param {{new(...p: ConstructorParameters<typeof Store>): ArrayStore}} Class */
@@ -779,79 +779,127 @@
779
779
  /**
780
780
  *
781
781
  * @param {Store} store
782
- * @param {...Schema.Validator | undefined | null | (Schema.Validator | undefined | null)[]} validators
782
+ * @param {Schema.SyncValidator[]} syncValidators
783
783
  * @returns
784
784
  */
785
- function createValidator(store, ...validators) {
786
- const allValidators = validators.flat().filter(v => typeof v === 'function');
787
- if (!allValidators.length) {
788
- return new exports.Signal.Computed(() => /** @type {string[]} */([]));
789
- }
785
+ function createSyncValidator(store, syncValidators) {
790
786
  return new exports.Signal.Computed(() => {
791
787
  const results = [];
792
- for (const validator of allValidators) {
788
+ for (const item of syncValidators) {
793
789
  try {
794
- results.push(validator(store));
795
- } catch (e){
790
+ results.push(item(store));
791
+ } catch (e) {
796
792
  results.push(e);
797
793
  }
798
794
  }
799
795
  return results.flat().map(toResult).filter(Boolean);
800
- })
796
+ });
801
797
  }
798
+
802
799
  /**
803
800
  *
804
801
  * @param {Store} store
805
- * @param {...Schema.AsyncValidator | undefined | null | (Schema.AsyncValidator | undefined | null)[]} validators
806
- * @returns {[exec: () => Promise<string[]>, state: Signal.Computed<string[]>, stop: () => void]}
802
+ * @param {Map<string, Schema.AsyncValidator[]>} eventsValidators
803
+ * @returns {[Record<string, () => Promise<string[]>>, results: Signal.State<string[]>[], stop: () => void]}
807
804
  */
808
- function createAsyncValidator(store, ...validators) {
809
- const allValidators = validators.flat().filter(v => typeof v === 'function');
810
- if (!allValidators.length) {
811
- return [
812
- ()=>Promise.resolve([]),
813
- new exports.Signal.Computed(() => /** @type {string[]} */([])),
814
- () => {}
815
- ];
816
- }
817
- const st = new exports.Signal.State(/** @type {string[]} */([]));
818
- /**
819
- *
820
- * @param {Schema.AsyncValidator} validator
821
- * @param {AbortSignal} signal
822
- */
823
- async function run(validator, signal) {
824
- let results = [];
825
- try {
826
- results.push(await validator(store, signal));
827
- } catch (e){
828
- results.push(e);
805
+ function createEventsValidator(store, eventsValidators) {
806
+ /** @type {Record<string, () => Promise<string[]>>} */
807
+ const eventExecMap = {};
808
+ /** @type {(() => void)[]} */
809
+ const allCancels = [];
810
+ /** @type {Signal.State<string[]>[]} */
811
+ const results = [];
812
+ for (const [name, validators] of eventsValidators) {
813
+ const st = new exports.Signal.State(/** @type {string[]} */([]));
814
+ /**
815
+ *
816
+ * @param {Schema.AsyncValidator} validator
817
+ * @param {AbortSignal} signal
818
+ */
819
+ async function run(validator, signal) {
820
+ let results = [];
821
+ try {
822
+ results.push(await validator(store, signal));
823
+ } catch (e) {
824
+ results.push(e);
825
+ }
826
+ const list = results.flat().map(toResult).filter(Boolean);
827
+ if (!signal.aborted && list.length) { st.set([...st.get(), ...list]); }
828
+ return list;
829
+ }
830
+ /** @type {AbortController?} */
831
+ let ac = null;
832
+ function exec() {
833
+ ac?.abort();
834
+ ac = new AbortController();
835
+ const signal = ac.signal;
836
+ st.set([]);
837
+
838
+ return Promise.all(validators.map(f => run(f, signal))).then(v => v.flat());
829
839
  }
830
- const list = results.flat().map(toResult).filter(Boolean);
831
- if (!signal.aborted && list.length) { st.set([...st.get(), ...list]); }
832
- return list;
840
+ eventExecMap[name] = exec;
841
+ allCancels.push(() => { ac?.abort(); st.set([]); });
842
+ results.push(st);
833
843
  }
834
- /** @type {AbortController?} */
835
- let ac = null;
836
- function exec() {
837
- ac?.abort();
838
- ac = new AbortController();
839
- const signal = ac.signal;
840
- st.set([]);
841
-
842
- return Promise.all(allValidators.map(f => run(f, signal))).then(v => v.flat());
843
- }
844
- return [exec, new exports.Signal.Computed(() => st.get()), () => {ac?.abort(); st.set([]);}]
844
+
845
+ function stop() {
846
+ for (const c of allCancels) {
847
+ c();
848
+ }
849
+
850
+ }
851
+
852
+ return [eventExecMap, results, stop];
845
853
  }
846
854
 
847
855
  /**
848
856
  *
849
- * @param {...Signal.Computed<string[]>} v
850
- * @returns
857
+ * @param {Store} store
858
+ * @param {...Schema.Validator | undefined | null | (Schema.Validator | undefined | null)[]} validators
859
+ * @returns {[exec: () => Promise<string[]>, Record<string, () => Promise<string[]>>, state: Signal.Computed<string[]>, stop: () => void]}
851
860
  */
852
- function merge(...v) {
853
- const list = /** @type {Signal.Computed<string[]>[]} */(v.filter(Boolean));
854
- return new exports.Signal.Computed(() => list.flatMap(v => v.get()));
861
+ function createValidator(store, ...validators) {
862
+
863
+ /** @type {Schema.SyncValidator[]} */
864
+ const syncValidators = [];
865
+ /** @type {Map<string, Schema.AsyncValidator[]>} */
866
+ const eventsValidators = new Map();
867
+ for (const v of validators.flat()) {
868
+ if (!v) { continue; }
869
+ if (typeof v === 'function') {
870
+ syncValidators.push(v);
871
+ continue;
872
+ }
873
+ const { event, validator } = v;
874
+ if (typeof validator !== 'function') { continue; }
875
+ if (typeof event !== 'string') {
876
+ syncValidators.push(validator);
877
+ continue;
878
+ }
879
+ const list = eventsValidators.get(event);
880
+ if (list) {
881
+ list.push(validator);
882
+ } else {
883
+ eventsValidators.set(event, [validator]);
884
+ }
885
+ }
886
+
887
+
888
+ const validatorResult = syncValidators.length
889
+ ? createSyncValidator(store, syncValidators)
890
+ : new exports.Signal.Computed(() => /** @type {string[]} */([]));
891
+ if (!eventsValidators.size) {
892
+ return [() => Promise.resolve(validatorResult.get()), {}, validatorResult, () => {}];
893
+ }
894
+
895
+ const [eventExecMap, results, stop] = createEventsValidator(store, eventsValidators);
896
+
897
+ const errors = new exports.Signal.Computed(() => [validatorResult, ...results].flatMap(v => v.get()));
898
+ const execAll = () => Promise.all([
899
+ validatorResult.get(),
900
+ ...Object.values(eventExecMap).map(exec => exec()),
901
+ ]).then(v => v.flat());
902
+ return [execAll, eventExecMap, errors, stop];
855
903
  }
856
904
 
857
905
  /** @import Store from './Store.mjs' */
@@ -870,52 +918,6 @@
870
918
  return (value) => structuredClone(def(store, value));
871
919
  }
872
920
 
873
- /** @import { Schema } from '../Schema.types.mjs' */
874
-
875
- /**
876
- * @template [T=any]
877
- * @template [M=any]
878
- * @template {Object.<string, Schema.State>} [S=Object.<string, Schema.State>]
879
- * @extends {Store<T, M, S>}
880
- */
881
- class BindObjectStore extends Store {
882
-
883
- get kind() { return 'object'; }
884
- /** @type {Record<string, Store>} */
885
- #children = Object.create(null);
886
- *[Symbol.iterator]() { yield* Object.entries(this.#children); }
887
- /**
888
- *
889
- * @param {string | number} key
890
- * @returns {Store?}
891
- */
892
- child(key) { return this.#children[key] || null; }
893
- /**
894
- * @param {Schema<any, Object.<string, Schema.State>>} schema 数据结构模式
895
- * @param {Store<T, M, S>} store
896
- */
897
- constructor(schema, store) {
898
- super(store);
899
- const children = this.#children;
900
- for (const [index, field] of Object.entries(schema)) {
901
- const bindStore = create(field, {
902
- index, parent: this,
903
- /** @param {*} value @param {*} index @param {Store} store */
904
- onUpdate: (value, index, store) => {
905
- if (store !== children[index]) { return; }
906
- const val = this.value ?? null;
907
- if (typeof val !== 'object' || Array.isArray(val)) { return; }
908
- // @ts-ignore
909
- this.value = { ...val, [index]: value };
910
- },
911
- });
912
- children[index] = bindStore;
913
- }
914
- }
915
- }
916
- // @ts-ignore
917
- setObjectStore(ObjectStore);
918
-
919
921
  /** @import { Ref } from './ref.mjs' */
920
922
  /** @import { Schema } from '../Schema.types.mjs' */
921
923
  /** @import { StoreLayout } from '../StoreLayout.types.mjs' */
@@ -956,10 +958,25 @@
956
958
  /**
957
959
  * 监听事件
958
960
  * @template {keyof Schema.Events} K
961
+ * @overload
959
962
  * @param {K} event
960
963
  * @param {(this: this, p: Schema.Events[K], store: this) => void | boolean | null} listener
961
964
  * @returns {() => void}
962
965
  */
966
+ /**
967
+ * 监听事件
968
+ * @template {keyof Schema.Events} K
969
+ * @overload
970
+ * @param {string} event
971
+ * @param {(this: this, p: unknown, store: this) => void | boolean | null} listener
972
+ * @returns {() => void}
973
+ */
974
+ /**
975
+ * 监听事件
976
+ * @param {string} event
977
+ * @param {(this: this, p: unknown, store: this) => void | boolean | null} listener
978
+ * @returns {() => void}
979
+ */
963
980
  listen(event, listener) {
964
981
  const originStore = this.#originStore;
965
982
  if (originStore) { return originStore.listen(event, p => listener.call(this, p, this)); }
@@ -1004,116 +1021,87 @@
1004
1021
  get ref() { return this.#ref || createRef(this); }
1005
1022
  /**
1006
1023
  * @param {Schema.Field<M, S> | Store<T,M,S>} schema 字段的 Schema 定义
1007
- * @param {object} [options] 可选配置
1008
- * @param {Store?} [options.parent]
1009
- * @param {Partial<S>?} [options.states]
1010
- * @param {((store: Store, value?: any) => any) | object | number | string | boolean | null | undefined} [options.default]
1011
- * @param {number | string | null} [options.index]
1012
- * @param {number | Signal.State<number> | Signal.Computed<number>} [options.size]
1013
- * @param {boolean} [options.null]
1014
- * @param {boolean} [options.new]
1015
- * @param {boolean} [options.hidden]
1016
- * @param {boolean} [options.clearable]
1017
- * @param {boolean} [options.required]
1018
- * @param {boolean} [options.disabled]
1019
- * @param {boolean} [options.readonly]
1020
- * @param {boolean} [options.removable]
1021
- *
1022
- * @param {string} [options.label] 字段标签
1023
- * @param {string} [options.description] 字段描述
1024
- * @param {string} [options.placeholder] 占位符
1025
- * @param {number} [options.min] 日期、时间、数字的最小值
1026
- * @param {number} [options.max] 日期、时间、数字的最大值
1027
- * @param {number} [options.step] 日期、时间、数字的步长
1028
- * @param {number} [options.minLength]
1029
- * @param {number} [options.maxLength]
1030
- * @param {RegExp} [options.pattern]
1031
- * @param {(Schema.Value.Group | Schema.Value | string | number)[]} [options.values] 可选值
1032
- * @param {Schema.Validator | Schema.Validator[] | null} [options.validator]
1033
- * @param {{[k in keyof Schema.Events]?: Schema.AsyncValidator | Schema.AsyncValidator[] | null}} [options.validators]
1034
- *
1035
- * @param {Ref?} [options.ref]
1036
- *
1037
- * @param {((value: any) => any)?} [options.setValue]
1038
- * @param {((value: any) => any)?} [options.convert]
1039
- *
1040
- * @param {((value: T?, index: any, store: Store) => void)?} [options.onUpdate]
1024
+ * @param {StoreOptions | AbortSignal | null} [options] 可选配置
1041
1025
  */
1042
- constructor(schema, {
1043
- null: isNull, ref, default: defaultValue,
1044
- setValue, convert, onUpdate, states,
1045
- validator, validators,
1046
- index, size, new: isNew, parent: parentNode,
1047
- hidden, clearable, required, disabled, readonly, removable,
1048
- label, description, placeholder, min, max, step, minLength, maxLength, pattern, values: values$1
1049
- } = {}) {
1026
+ constructor(schema, options) {
1050
1027
  if (schema instanceof Store) {
1051
- this.#originStore = schema;
1052
- this.#schema = schema.#schema;
1053
- this.#null = schema.#null;
1054
- this.#ref = schema.#ref;
1055
- this.#states = schema.#states;
1056
- this.#layout = schema.#layout;
1057
- this.#createDefault = schema.#createDefault;
1058
- this.#setValue = schema.#setValue;
1059
- this.#convert = schema.#convert;
1060
- this.#onUpdate = schema.#onUpdate;
1061
- this.#parent = schema.#parent;
1062
- this.#root = schema.#root;
1063
- this.#type = schema.#type;
1064
- this.#meta = schema.#meta;
1065
- this.#component = schema.#component;
1066
- this.#selfLoading = schema.#selfLoading;
1067
- this.#loading = schema.#loading;
1068
- this.#size = schema.#size;
1069
- this.#index = schema.#index;
1070
- this.#creatable = schema.#creatable;
1071
- this.#immutable = schema.#immutable;
1072
- this.#new = schema.#new;
1073
- this.#selfNew = schema.#selfNew;
1074
- this.#selfHidden = schema.#selfHidden;
1075
- this.#hidden = schema.#hidden;
1076
- this.#selfClearable = schema.#selfClearable;
1077
- this.#clearable = schema.#clearable;
1078
- this.#selfRequired = schema.#selfRequired;
1079
- this.#required = schema.#required;
1080
- this.#selfDisabled = schema.#selfDisabled;
1081
- this.#disabled = schema.#disabled;
1082
- this.#selfReadonly = schema.#selfReadonly;
1083
- this.#readonly = schema.#readonly;
1084
- this.#selfRemovable = schema.#selfRemovable;
1085
- this.#removable = schema.#removable;
1086
- this.#selfLabel = schema.#selfLabel;
1087
- this.#label = schema.#label;
1088
- this.#selfDescription = schema.#selfDescription;
1089
- this.#description = schema.#description;
1090
- this.#selfPlaceholder = schema.#selfPlaceholder;
1091
- this.#placeholder = schema.#placeholder;
1092
- this.#selfMin = schema.#selfMin;
1093
- this.#min = schema.#min;
1094
- this.#selfMax = schema.#selfMax;
1095
- this.#max = schema.#max;
1096
- this.#selfStep = schema.#selfStep;
1097
- this.#step = schema.#step;
1098
- this.#selfMinLength = schema.#selfMinLength;
1099
- this.#minLength = schema.#minLength;
1100
- this.#selfMaxLength = schema.#selfMaxLength;
1101
- this.#maxLength = schema.#maxLength;
1102
- this.#selfPattern = schema.#selfPattern;
1103
- this.#pattern = schema.#pattern;
1104
- this.#selfValues = schema.#selfValues;
1105
- this.#values = schema.#values;
1106
- this.#errors = schema.#errors;
1107
- this.#validatorResult = schema.#validatorResult;
1108
- this.#changed = schema.#changed;
1109
- this.#blurred = schema.#blurred;
1110
- this.#cancelChange = schema.#cancelChange;
1111
- this.#cancelBlur = schema.#cancelBlur;
1112
- this.#set = schema.#set;
1113
- this.#initValue = schema.#initValue;
1114
- this.#value = schema.#value;
1028
+ const store = schema.#originStore || schema;
1029
+ this.#originStore = store;
1030
+ this.#schema = store.#schema;
1031
+ this.#null = store.#null;
1032
+ this.#ref = store.#ref;
1033
+ this.#states = store.#states;
1034
+ this.#layout = store.#layout;
1035
+ this.#createDefault = store.#createDefault;
1036
+ this.#setValue = store.#setValue;
1037
+ this.#convert = store.#convert;
1038
+ this.#onUpdate = store.#onUpdate;
1039
+ this.#parent = store.#parent;
1040
+ this.#root = store.#root;
1041
+ this.#type = store.#type;
1042
+ this.#meta = store.#meta;
1043
+ this.#component = store.#component;
1044
+ this.#selfLoading = store.#selfLoading;
1045
+ this.#loading = store.#loading;
1046
+ this.#size = store.#size;
1047
+ this.#index = store.#index;
1048
+ this.#creatable = store.#creatable;
1049
+ this.#immutable = store.#immutable;
1050
+ this.#new = store.#new;
1051
+ this.#selfNew = store.#selfNew;
1052
+ this.#selfHidden = store.#selfHidden;
1053
+ this.#hidden = store.#hidden;
1054
+ this.#selfClearable = store.#selfClearable;
1055
+ this.#clearable = store.#clearable;
1056
+ this.#selfRequired = store.#selfRequired;
1057
+ this.#required = store.#required;
1058
+ this.#selfDisabled = store.#selfDisabled;
1059
+ this.#disabled = store.#disabled;
1060
+ this.#selfReadonly = store.#selfReadonly;
1061
+ this.#readonly = store.#readonly;
1062
+ this.#selfRemovable = store.#selfRemovable;
1063
+ this.#removable = store.#removable;
1064
+ this.#selfLabel = store.#selfLabel;
1065
+ this.#label = store.#label;
1066
+ this.#selfDescription = store.#selfDescription;
1067
+ this.#description = store.#description;
1068
+ this.#selfPlaceholder = store.#selfPlaceholder;
1069
+ this.#placeholder = store.#placeholder;
1070
+ this.#selfMin = store.#selfMin;
1071
+ this.#min = store.#min;
1072
+ this.#selfMax = store.#selfMax;
1073
+ this.#max = store.#max;
1074
+ this.#selfStep = store.#selfStep;
1075
+ this.#step = store.#step;
1076
+ this.#selfMinLength = store.#selfMinLength;
1077
+ this.#minLength = store.#minLength;
1078
+ this.#selfMaxLength = store.#selfMaxLength;
1079
+ this.#maxLength = store.#maxLength;
1080
+ this.#selfPattern = store.#selfPattern;
1081
+ this.#pattern = store.#pattern;
1082
+ this.#selfValues = store.#selfValues;
1083
+ this.#values = store.#values;
1084
+ this.#errors = store.#errors;
1085
+ this.#execValidators = store.#execValidators;
1086
+ this.#cancelEventValidator = store.#cancelEventValidator;
1087
+ this.#set = store.#set;
1088
+ this.#initValue = store.#initValue;
1089
+ this.#value = store.#value;
1090
+ const signal = options instanceof AbortSignal ? options : null;
1091
+ if (signal?.aborted) { return; }
1092
+ const subBindStores = store.#subBindStores;
1093
+ subBindStores.add(this);
1094
+ signal?.addEventListener('abort', () => subBindStores.delete(this));
1095
+ store.#requestUpdate();
1115
1096
  return;
1116
1097
  }
1098
+ const {
1099
+ null: isNull, ref, default: defaultValue,
1100
+ setValue, convert, onUpdate, states, validator,
1101
+ index, size, new: isNew, parent: parentNode,
1102
+ hidden, clearable, required, disabled, readonly, removable,
1103
+ label, description, placeholder, min, max, step, minLength, maxLength, pattern, values: values$1
1104
+ } = !(options instanceof AbortSignal) && options || {};
1117
1105
  this.#schema = schema;
1118
1106
  const parent = parentNode instanceof Store ? parentNode : null;
1119
1107
  if (parent) {
@@ -1184,9 +1172,6 @@
1184
1172
 
1185
1173
  [this.#selfRemovable, this.#removable] = createBooleanStates(this, removable, schema.removable ?? true);
1186
1174
 
1187
- const validatorResult = createValidator(this, schema.validator, validator);
1188
-
1189
-
1190
1175
  const schemaStates = schema.states;
1191
1176
  this.#states = schemaStates ? Object.defineProperties(Object.create(null),
1192
1177
  Object.fromEntries(
@@ -1202,16 +1187,13 @@
1202
1187
  })
1203
1188
  )) : null;
1204
1189
 
1205
- const [changed, changedResult, cancelChange] = createAsyncValidator(this, schema.validators?.change, validators?.change);
1206
- const [blurred, blurredResult, cancelBlur] = createAsyncValidator(this, schema.validators?.blur, validators?.blur);
1207
- this.listen('change', () => { changed(); });
1208
- this.listen('blur', () => { blurred(); });
1209
- this.#errors = merge(validatorResult, changedResult, blurredResult);
1210
- this.#validatorResult = validatorResult;
1211
- this.#changed = changed;
1212
- this.#blurred = blurred;
1213
- this.#cancelChange = cancelChange;
1214
- this.#cancelBlur = cancelBlur;
1190
+ const [execValidators, eventExecMap, errors, cancelEventValidator] = createValidator(this, schema.validator, validator);
1191
+ for (const [name, exec] of Object.entries(eventExecMap)) {
1192
+ this.listen(name, () => { exec(); });
1193
+ }
1194
+ this.#errors = errors;
1195
+ this.#execValidators = execValidators;
1196
+ this.#cancelEventValidator = cancelEventValidator;
1215
1197
 
1216
1198
  if (size instanceof exports.Signal.State || size instanceof exports.Signal.Computed) {
1217
1199
  this.#size = size;
@@ -1496,16 +1478,10 @@
1496
1478
 
1497
1479
  /** @type {Signal.Computed<string[]>} */
1498
1480
  #errors;
1499
- /** @type {Signal.Computed<string[]>} */
1500
- #validatorResult;
1501
- /** @type {() => Promise<string[]>} */
1502
- #changed;
1503
1481
  /** @type {() => Promise<string[]>} */
1504
- #blurred;
1482
+ #execValidators;
1505
1483
  /** @type {() => void} */
1506
- #cancelChange;
1507
- /** @type {() => void} */
1508
- #cancelBlur;
1484
+ #cancelEventValidator;
1509
1485
  /** 所有校验错误列表 */
1510
1486
  get errors() { return this.#errors.get(); }
1511
1487
  /** 字段校验错误信息 */
@@ -1526,24 +1502,6 @@
1526
1502
 
1527
1503
  /** @type {Set<Store>} */
1528
1504
  #subBindStores = new Set();
1529
- /**
1530
- * @template [M=any]
1531
- * @template {Object.<string, Schema.State>} [S=Object.<string, Schema.State>]
1532
- * @param {Schema<M, S>} schema 数据结构模式
1533
- * @param {AbortSignal} [signal]
1534
- * @returns {BindObjectStore}
1535
- */
1536
- bindObject(schema, signal) {
1537
- const originStore = this.#originStore;
1538
- if (originStore) { return originStore.bindObject(schema, signal); }
1539
- const store = new BindObjectStore(schema, this);
1540
- if (signal?.aborted) { return store; }
1541
- const subBindStores = this.#subBindStores;
1542
- subBindStores.add(store);
1543
- signal?.addEventListener('abort', () => subBindStores.delete(store));
1544
- this.#requestUpdate();
1545
- return store;
1546
- }
1547
1505
 
1548
1506
  /** 内容是否已改变 */
1549
1507
  get changed() { return !Object.is(this.#value.get(), this.#initValue.get()); }
@@ -1587,8 +1545,7 @@
1587
1545
  this.#selfNew.set(isNew);
1588
1546
  const newValue = this.#setValue?.(v);
1589
1547
  const value = newValue === undefined ? v : newValue;
1590
- this.#cancelChange();
1591
- this.#cancelBlur();
1548
+ this.#cancelEventValidator();
1592
1549
  this.#set = true;
1593
1550
  if (!value || typeof value !== 'object') {
1594
1551
  for (const bind of [this, ...this.#subBindStores]) {
@@ -1640,7 +1597,7 @@
1640
1597
  // @ts-ignore
1641
1598
  let newValues = Array.isArray(val) ? [...val] : { ...val };
1642
1599
  let updated = false;
1643
- for (const bind of [this,...this.#subBindStores]) {
1600
+ for (const bind of [this, ...this.#subBindStores]) {
1644
1601
  for (const [key, field] of bind) {
1645
1602
  // @ts-ignore
1646
1603
  const data = Object.hasOwn(val, key) ? val[key] : undefined;
@@ -1684,11 +1641,7 @@
1684
1641
  validate(path) {
1685
1642
  if (path === true) {
1686
1643
  if (this.#originStore) { return Promise.resolve(null); }
1687
- return Promise.all([this.#validatorResult.get(), this.#changed(), this.#blurred()])
1688
- .then(v => {
1689
- const errors = v.flat();
1690
- return errors.length ? errors : null;
1691
- });
1644
+ return this.#execValidators().then(errors => errors.length ? errors : null);
1692
1645
  }
1693
1646
  const selfPath = Array.isArray(path) ? path : [];
1694
1647
  if (!this.#originStore && this.#hidden.get()) { return Promise.resolve([]); }
@@ -1706,6 +1659,45 @@
1706
1659
  }
1707
1660
  }
1708
1661
 
1662
+ /**
1663
+ * @template [T=any]
1664
+ * @template [M=any]
1665
+ * @template {Object.<string, Schema.State>} [S=Object.<string, Schema.State>]
1666
+ * @typedef {object} StoreOptions
1667
+ * @property {Store?} [parent]
1668
+ * @property {Partial<S>?} [states]
1669
+ * @property {((store: Store, value?: any) => any) | object | number | string | boolean | null | undefined} [default]
1670
+ * @property {number | string | null} [index]
1671
+ * @property {number | Signal.State<number> | Signal.Computed<number>} [size]
1672
+ * @property {boolean} [null]
1673
+ * @property {boolean} [new]
1674
+ * @property {boolean} [hidden]
1675
+ * @property {boolean} [clearable]
1676
+ * @property {boolean} [required]
1677
+ * @property {boolean} [disabled]
1678
+ * @property {boolean} [readonly]
1679
+ * @property {boolean} [removable]
1680
+ *
1681
+ * @property {string} [label] 字段标签
1682
+ * @property {string} [description] 字段描述
1683
+ * @property {string} [placeholder] 占位符
1684
+ * @property {number} [min] 日期、时间、数字的最小值
1685
+ * @property {number} [max] 日期、时间、数字的最大值
1686
+ * @property {number} [step] 日期、时间、数字的步长
1687
+ * @property {number} [minLength]
1688
+ * @property {number} [maxLength]
1689
+ * @property {RegExp} [pattern]
1690
+ * @property {(Schema.Value.Group | Schema.Value | string | number)[]} [values] 可选值
1691
+ * @property {Schema.Validator | Schema.Validator[] | null} [validator]
1692
+ *
1693
+ * @property {Ref?} [ref]
1694
+ *
1695
+ * @property {((value: any) => any)?} [setValue]
1696
+ * @property {((value: any) => any)?} [convert]
1697
+ *
1698
+ * @property {((value: T?, index: any, store: Store) => void)?} [onUpdate]
1699
+ */
1700
+
1709
1701
  /** @import { Schema } from '../Schema.types.mjs' */
1710
1702
 
1711
1703
  /**
@@ -1714,7 +1706,7 @@
1714
1706
  * @template {Object.<string, Schema.State>} [S=Object.<string, Schema.State>]
1715
1707
  * @extends {Store<T, M, S>}
1716
1708
  */
1717
- let ObjectStore$1 = class ObjectStore extends Store {
1709
+ class ObjectStore extends Store {
1718
1710
  get kind() { return 'object'; }
1719
1711
  /** @type {Record<string, Store>} */
1720
1712
  #children;
@@ -1767,9 +1759,9 @@
1767
1759
  }
1768
1760
  this.#children = children;
1769
1761
  }
1770
- };
1762
+ }
1771
1763
  // @ts-ignore
1772
- setObjectStore(ObjectStore$1);
1764
+ setObjectStore(ObjectStore);
1773
1765
 
1774
1766
  /** @import { Schema } from '../Schema.types.mjs' */
1775
1767
 
@@ -2011,6 +2003,51 @@
2011
2003
  // @ts-ignore
2012
2004
  setArrayStore(ArrayStore);
2013
2005
 
2006
+ /** @import { Schema } from '../Schema.types.mjs' */
2007
+
2008
+ /**
2009
+ * @template [T=any]
2010
+ * @template [M=any]
2011
+ * @template {Object.<string, Schema.State>} [S=Object.<string, Schema.State>]
2012
+ * @extends {Store<T, M, S>}
2013
+ */
2014
+ class BindObjectStore extends Store {
2015
+
2016
+ get kind() { return 'object'; }
2017
+ /** @type {Record<string, Store>} */
2018
+ #children = Object.create(null);
2019
+ *[Symbol.iterator]() { yield* Object.entries(this.#children); }
2020
+ /**
2021
+ *
2022
+ * @param {string | number} key
2023
+ * @returns {Store?}
2024
+ */
2025
+ child(key) { return this.#children[key] || null; }
2026
+ /**
2027
+ * @param {Schema<any, Object.<string, Schema.State>>} schema 数据结构模式
2028
+ * @param {Store<T, M, S>} store
2029
+ * @param {AbortSignal} [signal]
2030
+ */
2031
+ constructor(schema, store, signal) {
2032
+ super(store, signal);
2033
+ const children = this.#children;
2034
+ for (const [index, field] of Object.entries(schema)) {
2035
+ const bindStore = create(field, {
2036
+ index, parent: this,
2037
+ /** @param {*} value @param {*} index @param {Store} store */
2038
+ onUpdate: (value, index, store) => {
2039
+ if (store !== children[index]) { return; }
2040
+ const val = this.value ?? null;
2041
+ if (typeof val !== 'object' || Array.isArray(val)) { return; }
2042
+ // @ts-ignore
2043
+ this.value = { ...val, [index]: value };
2044
+ },
2045
+ });
2046
+ children[index] = bindStore;
2047
+ }
2048
+ }
2049
+ }
2050
+
2014
2051
  /** @import * as Layout from './index.mjs' */
2015
2052
 
2016
2053
  /** @import { OldNode } from './createElement.mjs' */
@@ -5439,7 +5476,7 @@
5439
5476
  if (list instanceof ArrayStore) {
5440
5477
  return renderArray(parent, next, list, env, r, layout.sort);
5441
5478
  }
5442
- if (list instanceof ObjectStore$1) {
5479
+ if (list instanceof ObjectStore) {
5443
5480
  return renderObject(parent, next, list, env, r, layout.sort);
5444
5481
  }
5445
5482
  if (typeof list === 'function') {
@@ -7172,8 +7209,9 @@
7172
7209
  }
7173
7210
 
7174
7211
  exports.ArrayStore = ArrayStore;
7212
+ exports.BindObjectStore = BindObjectStore;
7175
7213
  exports.Layout = index;
7176
- exports.ObjectStore = ObjectStore$1;
7214
+ exports.ObjectStore = ObjectStore;
7177
7215
  exports.Store = Store;
7178
7216
  exports.effect = effect;
7179
7217
  exports.render = render;