@neeloong/form 0.24.0 → 0.26.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 +132 -46
- package/index.full.js +231 -141
- package/index.full.min.js +4 -4
- package/index.full.min.mjs +7 -7
- package/index.min.mjs +2 -2
- package/index.mjs +231 -141
- package/package.json +1 -1
package/index.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/*!
|
|
2
|
-
* @neeloong/form v0.
|
|
2
|
+
* @neeloong/form v0.26.0
|
|
3
3
|
* (c) 2024-2026 Fierflame
|
|
4
4
|
* @license Apache-2.0
|
|
5
5
|
*/
|
|
@@ -145,7 +145,8 @@ let ArrayStoreClass = null;
|
|
|
145
145
|
let TypeStores = Object.create(null);
|
|
146
146
|
/**
|
|
147
147
|
* @template [M=any]
|
|
148
|
-
* @
|
|
148
|
+
* @template {Object.<string, Schema.State>} [S=Object.<string, Schema.State>]
|
|
149
|
+
* @param {Schema.Field<M, S>} schema
|
|
149
150
|
* @param {object} [options]
|
|
150
151
|
* @param {Store?} [options.parent]
|
|
151
152
|
* @param {string | number | null} [options.index]
|
|
@@ -299,6 +300,7 @@ function makeDefault(store, def) {
|
|
|
299
300
|
* 管理单个表单字段的状态和行为
|
|
300
301
|
* @template [T=any]
|
|
301
302
|
* @template [M=any]
|
|
303
|
+
* @template {Object.<string, Schema.State>} [S=Object.<string, Schema.State>]
|
|
302
304
|
*/
|
|
303
305
|
class Store {
|
|
304
306
|
/** @type {Map<string, Set<(value: any, store: any) => void | boolean | null>>} */
|
|
@@ -341,7 +343,8 @@ class Store {
|
|
|
341
343
|
/**
|
|
342
344
|
* 从数据结构模式创建存储
|
|
343
345
|
* @template [M=any]
|
|
344
|
-
* @
|
|
346
|
+
* @template {Object.<string, Schema.State>} [S=Object.<string, Schema.State>]
|
|
347
|
+
* @param {Schema<M, S>} schema 数据结构模式
|
|
345
348
|
* @param {object} [options] 选项
|
|
346
349
|
* @param {boolean} [options.new] 是否为新建环境
|
|
347
350
|
*/
|
|
@@ -365,9 +368,10 @@ class Store {
|
|
|
365
368
|
#ref = null;
|
|
366
369
|
get ref() { return this.#ref || createRef(this); }
|
|
367
370
|
/**
|
|
368
|
-
* @param {Schema.Field<M>} schema 字段的 Schema 定义
|
|
371
|
+
* @param {Schema.Field<M, S>} schema 字段的 Schema 定义
|
|
369
372
|
* @param {object} [options] 可选配置
|
|
370
373
|
* @param {Store?} [options.parent]
|
|
374
|
+
* @param {Partial<S>?} [options.states]
|
|
371
375
|
* @param {((store: Store, value?: any) => any) | object | number | string | boolean | null | undefined} [options.default]
|
|
372
376
|
* @param {number | string | null} [options.index]
|
|
373
377
|
* @param {number | Signal.State<number> | Signal.Computed<number>} [options.size]
|
|
@@ -402,7 +406,7 @@ class Store {
|
|
|
402
406
|
*/
|
|
403
407
|
constructor(schema, {
|
|
404
408
|
null: isNull, ref, default: defaultValue,
|
|
405
|
-
setValue, convert, onUpdate,
|
|
409
|
+
setValue, convert, onUpdate, states,
|
|
406
410
|
validator, validators,
|
|
407
411
|
index, size, new: isNew, parent: parentNode,
|
|
408
412
|
hidden, clearable, required, disabled, readonly, removable,
|
|
@@ -480,6 +484,22 @@ class Store {
|
|
|
480
484
|
|
|
481
485
|
const validatorResult = createValidator(this, schema.validator, validator);
|
|
482
486
|
|
|
487
|
+
|
|
488
|
+
const schemaStates = schema.states;
|
|
489
|
+
this.#states = schemaStates ? Object.defineProperties(Object.create(null),
|
|
490
|
+
Object.fromEntries(
|
|
491
|
+
Object.entries(schemaStates).map(([k, { get, set, toState }]) => {
|
|
492
|
+
const state = new Signal.State(toState?.(states?.[k]));
|
|
493
|
+
const computed = new Signal.Computed(() => get(this, state));
|
|
494
|
+
return [k, {
|
|
495
|
+
configurable: true,
|
|
496
|
+
enumerable: true,
|
|
497
|
+
get() { return computed.get(); },
|
|
498
|
+
set(v) { return set?.(this, state, v); },
|
|
499
|
+
}];
|
|
500
|
+
})
|
|
501
|
+
)) : null;
|
|
502
|
+
|
|
483
503
|
const [changed, changedResult, cancelChange] = createAsyncValidator(this, schema.validators?.change, validators?.change);
|
|
484
504
|
const [blurred, blurredResult, cancelBlur] = createAsyncValidator(this, schema.validators?.blur, validators?.blur);
|
|
485
505
|
this.listen('change', () => { changed(); });
|
|
@@ -514,8 +534,11 @@ class Store {
|
|
|
514
534
|
this.listen(k, f);
|
|
515
535
|
}
|
|
516
536
|
}
|
|
537
|
+
/** @type {S?} */
|
|
538
|
+
#states;
|
|
539
|
+
get states() { return this.#states; }
|
|
517
540
|
/** @type {StoreLayout.Field<any>} */
|
|
518
|
-
#layout
|
|
541
|
+
#layout;
|
|
519
542
|
get layout() { return this.#layout; }
|
|
520
543
|
#createDefault;
|
|
521
544
|
/** @param {any} [value] @returns {any} */
|
|
@@ -691,9 +714,10 @@ class Store {
|
|
|
691
714
|
#selfMin;
|
|
692
715
|
/** @readonly @type {Signal.Computed<number?>} */
|
|
693
716
|
#min;
|
|
717
|
+
/** @deprecated */
|
|
694
718
|
get selfMin() { return this.#selfMin.get(); }
|
|
695
719
|
set selfMin(v) { this.#selfMin.set(number(v)); }
|
|
696
|
-
/** 数值字段的最小值限制 */
|
|
720
|
+
/** @deprecated 数值字段的最小值限制 */
|
|
697
721
|
get min() { return this.#min.get(); }
|
|
698
722
|
set min(v) { this.#selfMin.set(number(v)); }
|
|
699
723
|
|
|
@@ -702,9 +726,10 @@ class Store {
|
|
|
702
726
|
#selfMax;
|
|
703
727
|
/** @readonly @type {Signal.Computed<number?>} */
|
|
704
728
|
#max;
|
|
729
|
+
/** @deprecated */
|
|
705
730
|
get selfMax() { return this.#selfMax.get(); }
|
|
706
731
|
set selfMax(v) { this.#selfMax.set(number(v)); }
|
|
707
|
-
/** 数值字段的最大值限制 */
|
|
732
|
+
/** @deprecated 数值字段的最大值限制 */
|
|
708
733
|
get max() { return this.#max.get(); }
|
|
709
734
|
set max(v) { this.#selfMax.set(number(v)); }
|
|
710
735
|
|
|
@@ -713,9 +738,10 @@ class Store {
|
|
|
713
738
|
#selfStep;
|
|
714
739
|
/** @readonly @type {Signal.Computed<number?>} */
|
|
715
740
|
#step;
|
|
741
|
+
/** @deprecated */
|
|
716
742
|
get selfStep() { return this.#selfStep.get(); }
|
|
717
743
|
set selfStep(v) { this.#selfStep.set(number(v)); }
|
|
718
|
-
/** 数值字段的步长 */
|
|
744
|
+
/** @deprecated 数值字段的步长 */
|
|
719
745
|
get step() { return this.#step.get(); }
|
|
720
746
|
set step(v) { this.#selfStep.set(number(v)); }
|
|
721
747
|
|
|
@@ -723,9 +749,10 @@ class Store {
|
|
|
723
749
|
#selfMinLength;
|
|
724
750
|
/** @readonly @type {Signal.Computed<number?>} */
|
|
725
751
|
#minLength;
|
|
752
|
+
/** @deprecated */
|
|
726
753
|
get selfMinLength() { return this.#selfMinLength.get(); }
|
|
727
754
|
set selfMinLength(v) { this.#selfMinLength.set(number(v)); }
|
|
728
|
-
/** 最小长度 */
|
|
755
|
+
/** @deprecated 最小长度 */
|
|
729
756
|
get minLength() { return this.#minLength.get(); }
|
|
730
757
|
set minLength(v) { this.#selfMinLength.set(number(v)); }
|
|
731
758
|
|
|
@@ -733,9 +760,10 @@ class Store {
|
|
|
733
760
|
#selfMaxLength;
|
|
734
761
|
/** @readonly @type {Signal.Computed<number?>} */
|
|
735
762
|
#maxLength;
|
|
763
|
+
/** @deprecated */
|
|
736
764
|
get selfMaxLength() { return this.#selfMaxLength.get(); }
|
|
737
765
|
set selfMaxLength(v) { this.#selfMaxLength.set(number(v)); }
|
|
738
|
-
/** 最大长度 */
|
|
766
|
+
/** @deprecated 最大长度 */
|
|
739
767
|
get maxLength() { return this.#maxLength.get(); }
|
|
740
768
|
set maxLength(v) { this.#selfMaxLength.set(number(v)); }
|
|
741
769
|
|
|
@@ -743,9 +771,10 @@ class Store {
|
|
|
743
771
|
#selfPattern;
|
|
744
772
|
/** @readonly @type {Signal.Computed<RegExp?>} */
|
|
745
773
|
#pattern;
|
|
774
|
+
/** @deprecated */
|
|
746
775
|
get selfPattern() { return this.#selfPattern.get(); }
|
|
747
776
|
set selfPattern(v) { this.#selfPattern.set(regex(v)); }
|
|
748
|
-
/** 模式 */
|
|
777
|
+
/** @deprecated 模式 */
|
|
749
778
|
get pattern() { return this.#pattern.get(); }
|
|
750
779
|
set pattern(v) { this.#selfPattern.set(regex(v)); }
|
|
751
780
|
|
|
@@ -754,9 +783,10 @@ class Store {
|
|
|
754
783
|
#selfValues;
|
|
755
784
|
/** @readonly @type {Signal.Computed<(Schema.Value.Group | Schema.Value)[] | null>} */
|
|
756
785
|
#values;
|
|
786
|
+
/** @deprecated */
|
|
757
787
|
get selfValues() { return this.#selfValues.get(); }
|
|
758
788
|
set selfValues(v) { this.#selfValues.set(values(v)); }
|
|
759
|
-
/** 可选值列表 */
|
|
789
|
+
/** @deprecated 可选值列表 */
|
|
760
790
|
get values() { return this.#values.get(); }
|
|
761
791
|
set values(v) { this.#selfValues.set(values(v)); }
|
|
762
792
|
|
|
@@ -791,6 +821,40 @@ class Store {
|
|
|
791
821
|
#initValue = new Signal.State(/** @type {T?} */(null));
|
|
792
822
|
#value = new Signal.State(this.#initValue.get());
|
|
793
823
|
|
|
824
|
+
/**
|
|
825
|
+
* @template [M=any]
|
|
826
|
+
* @template {Object.<string, Schema.State>} [S=Object.<string, Schema.State>]
|
|
827
|
+
* @param {Schema<M, S>} schema 数据结构模式
|
|
828
|
+
*/
|
|
829
|
+
bindObject(schema) {
|
|
830
|
+
const bindStores = this.#bindStores;
|
|
831
|
+
/** @type {Store[]} */
|
|
832
|
+
const list = [];
|
|
833
|
+
for (const [index, field] of Object.entries(schema)) {
|
|
834
|
+
const bindStore = create(field, {
|
|
835
|
+
index, parent: this,
|
|
836
|
+
/** @param {*} value @param {*} currentIndex @param {Store} store */
|
|
837
|
+
onUpdate: (value, currentIndex, store) => {
|
|
838
|
+
if (index !== currentIndex) { return; }
|
|
839
|
+
if (bindStores.has(store)) { return; }
|
|
840
|
+
const val = this.#value ?? null;
|
|
841
|
+
if (typeof val !== 'object' || Array.isArray(val)) { return }
|
|
842
|
+
// @ts-ignore
|
|
843
|
+
this.value = { ...val, [currentIndex]: value };
|
|
844
|
+
},
|
|
845
|
+
});
|
|
846
|
+
list.push(bindStore);
|
|
847
|
+
bindStores.set(bindStore, index);
|
|
848
|
+
}
|
|
849
|
+
this.#requestUpdate();
|
|
850
|
+
return () => {
|
|
851
|
+
for (const bindStore of list) {
|
|
852
|
+
bindStores.delete(bindStore);
|
|
853
|
+
}
|
|
854
|
+
};
|
|
855
|
+
}
|
|
856
|
+
/** @type {Map<Store, string>} */
|
|
857
|
+
#bindStores = new Map();
|
|
794
858
|
|
|
795
859
|
/** 内容是否已改变 */
|
|
796
860
|
get changed() { return !Object.is(this.#value.get(), this.#initValue.get()); }
|
|
@@ -837,6 +901,9 @@ class Store {
|
|
|
837
901
|
for (const [, field] of this) {
|
|
838
902
|
field.#reset(null, false);
|
|
839
903
|
}
|
|
904
|
+
for (const [field] of this.#bindStores) {
|
|
905
|
+
field.#reset(null, false);
|
|
906
|
+
}
|
|
840
907
|
this.#value.set(value);
|
|
841
908
|
this.#initValue.set(value);
|
|
842
909
|
this.#onUpdate?.(value, this.#index.get(), this);
|
|
@@ -847,6 +914,9 @@ class Store {
|
|
|
847
914
|
for (const [key, field] of this) {
|
|
848
915
|
newValues[key] = field.#reset(Object.hasOwn(newValues, key) ? newValues[key] : undefined, false);
|
|
849
916
|
}
|
|
917
|
+
for (const [field, key] of this.#bindStores) {
|
|
918
|
+
newValues[key] = field.#reset(Object.hasOwn(newValues, key) ? newValues[key] : undefined, false);
|
|
919
|
+
}
|
|
850
920
|
this.#value.set(newValues);
|
|
851
921
|
this.#initValue.set(newValues);
|
|
852
922
|
this.#onUpdate?.(newValues, this.#index.get(), this);
|
|
@@ -888,6 +958,15 @@ class Store {
|
|
|
888
958
|
newValues[key] = newData;
|
|
889
959
|
updated = true;
|
|
890
960
|
}
|
|
961
|
+
for (const [field, key] of this.#bindStores) {
|
|
962
|
+
// @ts-ignore
|
|
963
|
+
const data = Object.hasOwn(val, key) ? val[key] : undefined;
|
|
964
|
+
const newData = field.#toUpdate(data);
|
|
965
|
+
if (Object.is(data, newData)) { continue; }
|
|
966
|
+
// @ts-ignore
|
|
967
|
+
newValues[key] = newData;
|
|
968
|
+
updated = true;
|
|
969
|
+
}
|
|
891
970
|
if (updated) {
|
|
892
971
|
val = newValues;
|
|
893
972
|
initValue = val;
|
|
@@ -904,7 +983,7 @@ class Store {
|
|
|
904
983
|
/**
|
|
905
984
|
* 异步校验
|
|
906
985
|
* @overload
|
|
907
|
-
* @param {true} [
|
|
986
|
+
* @param {true} [self]
|
|
908
987
|
* @returns {Promise<string[] | null>}
|
|
909
988
|
*/
|
|
910
989
|
/**
|
|
@@ -927,6 +1006,7 @@ class Store {
|
|
|
927
1006
|
});
|
|
928
1007
|
}
|
|
929
1008
|
const selfPath = Array.isArray(path) ? path : [];
|
|
1009
|
+
if (this.#hidden.get()) { return Promise.resolve([]); }
|
|
930
1010
|
const list = [this.validate(true).then(errors => {
|
|
931
1011
|
if (!errors?.length) { return []; }
|
|
932
1012
|
return [{ path: [...selfPath], store: /** @type {Store} */(this), errors }];
|
|
@@ -934,6 +1014,9 @@ class Store {
|
|
|
934
1014
|
for (const [key, field] of this) {
|
|
935
1015
|
list.push(field.validate([...selfPath, key]));
|
|
936
1016
|
}
|
|
1017
|
+
for (const [field, key] of this.#bindStores) {
|
|
1018
|
+
list.push(field.validate([...selfPath, key]));
|
|
1019
|
+
}
|
|
937
1020
|
return Promise.all(list).then(v => v.flat());
|
|
938
1021
|
}
|
|
939
1022
|
}
|
|
@@ -943,7 +1026,8 @@ class Store {
|
|
|
943
1026
|
/**
|
|
944
1027
|
* @template {Record<string, any>} [T=Record<string, any>]
|
|
945
1028
|
* @template [M=any]
|
|
946
|
-
* @
|
|
1029
|
+
* @template {Object.<string, Schema.State>} [S=Object.<string, Schema.State>]
|
|
1030
|
+
* @extends {Store<T, M, S>}
|
|
947
1031
|
*/
|
|
948
1032
|
class ObjectStore extends Store {
|
|
949
1033
|
get kind() { return 'object'; }
|
|
@@ -957,7 +1041,7 @@ class ObjectStore extends Store {
|
|
|
957
1041
|
*/
|
|
958
1042
|
child(key) { return this.#children[key] || null; }
|
|
959
1043
|
/**
|
|
960
|
-
* @param {Schema.Object<M> & Schema.Attr<M>} schema
|
|
1044
|
+
* @param {Schema.Object<M, S> & Schema.Attr<M, S>} schema
|
|
961
1045
|
* @param {object} [options]
|
|
962
1046
|
* @param {Store?} [options.parent]
|
|
963
1047
|
* @param {number | string | null} [options.index]
|
|
@@ -1009,7 +1093,8 @@ setObjectStore(ObjectStore);
|
|
|
1009
1093
|
/**
|
|
1010
1094
|
* @template [T=any]
|
|
1011
1095
|
* @template [M=any]
|
|
1012
|
-
* @
|
|
1096
|
+
* @template {Object.<string, Schema.State>} [S=Object.<string, Schema.State>]
|
|
1097
|
+
* @extends {Store<(T | null)[], M, S>}
|
|
1013
1098
|
*/
|
|
1014
1099
|
class ArrayStore extends Store {
|
|
1015
1100
|
/** @type {(index: number, isNew?: boolean) => Store} */
|
|
@@ -1032,7 +1117,7 @@ class ArrayStore extends Store {
|
|
|
1032
1117
|
}
|
|
1033
1118
|
get kind() { return 'array'; }
|
|
1034
1119
|
/**
|
|
1035
|
-
* @param {Schema.Field<M>} schema
|
|
1120
|
+
* @param {Schema.Field<M, S>} schema
|
|
1036
1121
|
* @param {object} [options]
|
|
1037
1122
|
* @param {Store?} [options.parent]
|
|
1038
1123
|
* @param {string | number | null} [options.index]
|
|
@@ -1101,6 +1186,8 @@ class ArrayStore extends Store {
|
|
|
1101
1186
|
return child;
|
|
1102
1187
|
};
|
|
1103
1188
|
}
|
|
1189
|
+
/** @returns {never} */
|
|
1190
|
+
bindObject() { throw new Error(`ArrayStore 不支持 bindObject()方法`); }
|
|
1104
1191
|
|
|
1105
1192
|
|
|
1106
1193
|
/** @readonly @type {Signal.State<boolean?>} */
|
|
@@ -4218,7 +4305,7 @@ function renderObject(parent, next, store, env, renderItem, sort) {
|
|
|
4218
4305
|
const children = [];
|
|
4219
4306
|
const childStores = [...store];
|
|
4220
4307
|
const count = childStores.length;
|
|
4221
|
-
/** @type {[string, Store<any, any>, number][]} */
|
|
4308
|
+
/** @type {[string, Store<any, any, any>, number][]} */
|
|
4222
4309
|
const stores = sort
|
|
4223
4310
|
? childStores
|
|
4224
4311
|
.map(([k,v]) => [k,v,env.setStore(v, store).exec(sort)])
|
|
@@ -4765,7 +4852,7 @@ function createFieldFilter(field) {
|
|
|
4765
4852
|
* @param {StoreLayout.Options?} options
|
|
4766
4853
|
* @param {StoreLayout<T>} layout
|
|
4767
4854
|
* @param {Node} [anchor]
|
|
4768
|
-
* @param {(child?: Store<any, any> | undefined) => void} [dragenter]
|
|
4855
|
+
* @param {(child?: Store<any, any, any> | undefined) => void} [dragenter]
|
|
4769
4856
|
* @returns {void}
|
|
4770
4857
|
*/
|
|
4771
4858
|
function renderHtml(store, fieldRenderer, node, options, layout, anchor, dragenter) {
|
|
@@ -4778,27 +4865,49 @@ function renderHtml(store, fieldRenderer, node, options, layout, anchor, dragent
|
|
|
4778
4865
|
const mode = node.getAttribute('mode') || '';
|
|
4779
4866
|
const fieldStore = field ? store.child(field) : store;
|
|
4780
4867
|
if (!fieldStore) { return; }
|
|
4781
|
-
|
|
4782
|
-
|
|
4783
|
-
: { ...layout, html: '' };
|
|
4868
|
+
/** @type {HTMLElement?} */
|
|
4869
|
+
let el = null;
|
|
4784
4870
|
switch (mode) {
|
|
4785
4871
|
case 'grid': {
|
|
4786
|
-
const
|
|
4787
|
-
|
|
4788
|
-
|
|
4872
|
+
const fieldLayout = field
|
|
4873
|
+
? layout?.fields?.find(createFieldFilter(field)) || fieldStore.layout
|
|
4874
|
+
: { ...layout, html: '' };
|
|
4875
|
+
el = Form(fieldStore, fieldRenderer, fieldLayout, options);
|
|
4876
|
+
break;
|
|
4877
|
+
}
|
|
4878
|
+
default: {
|
|
4879
|
+
el = fieldRenderer(fieldStore, layout.renderer, options);
|
|
4880
|
+
break;
|
|
4789
4881
|
}
|
|
4790
4882
|
}
|
|
4791
|
-
|
|
4792
|
-
|
|
4793
|
-
node.replaceWith(
|
|
4883
|
+
if (!el) {
|
|
4884
|
+
const value = node.getAttribute('placeholder') || '';
|
|
4885
|
+
node.replaceWith(document.createTextNode(value));
|
|
4794
4886
|
return;
|
|
4795
4887
|
}
|
|
4796
|
-
const
|
|
4797
|
-
|
|
4888
|
+
const className = node.getAttribute('class') || '';
|
|
4889
|
+
if (className) {
|
|
4890
|
+
el.setAttribute('class', [
|
|
4891
|
+
el.getAttribute('class') || '',
|
|
4892
|
+
className,
|
|
4893
|
+
].filter(Boolean).join(' '));
|
|
4894
|
+
}
|
|
4895
|
+
const style = node.getAttribute('style') || '';
|
|
4896
|
+
if (style) {
|
|
4897
|
+
el.setAttribute('style', [
|
|
4898
|
+
el.getAttribute('style') || '',
|
|
4899
|
+
style,
|
|
4900
|
+
].filter(Boolean).join(' '));
|
|
4901
|
+
}
|
|
4902
|
+
node.replaceWith(el);
|
|
4798
4903
|
return;
|
|
4799
4904
|
}
|
|
4800
4905
|
if (tagName === 'nl-form-button') {
|
|
4801
4906
|
const button = document.createElement('button');
|
|
4907
|
+
const className = node.getAttribute('class') || '';
|
|
4908
|
+
const style = node.getAttribute('style') || '';
|
|
4909
|
+
if (className) { button.setAttribute('class', className); }
|
|
4910
|
+
if (style) { button.setAttribute('style', style); }
|
|
4802
4911
|
button.classList.add('NeeloongForm-item-button');
|
|
4803
4912
|
const click = node.getAttribute('click') || '';
|
|
4804
4913
|
const call = options?.call;
|
|
@@ -4986,7 +5095,7 @@ function getHtmlContent(html) {
|
|
|
4986
5095
|
/**
|
|
4987
5096
|
*
|
|
4988
5097
|
* @template T
|
|
4989
|
-
* @param {Store<any, any>} store
|
|
5098
|
+
* @param {Store<any, any, any>} store
|
|
4990
5099
|
* @param {StoreLayout.Renderer<T>} fieldRenderer
|
|
4991
5100
|
* @param {StoreLayout<T>} layout
|
|
4992
5101
|
* @param {StoreLayout.Options?} options
|
|
@@ -5009,7 +5118,7 @@ function FormFieldInline(store, fieldRenderer, layout, options) {
|
|
|
5009
5118
|
/**
|
|
5010
5119
|
*
|
|
5011
5120
|
* @template T
|
|
5012
|
-
* @param {Store<any, any>} store
|
|
5121
|
+
* @param {Store<any, any, any>} store
|
|
5013
5122
|
* @param {StoreLayout.Renderer<T>} fieldRenderer
|
|
5014
5123
|
* @param {StoreLayout.Field<T>} layout
|
|
5015
5124
|
* @param {object} option
|
|
@@ -5048,6 +5157,7 @@ function Line(store, fieldRenderer, layout, {
|
|
|
5048
5157
|
const body = root.appendChild(document.createElement('tr'));
|
|
5049
5158
|
const main = body.appendChild(document.createElement('td'));
|
|
5050
5159
|
main.colSpan = columns.length;
|
|
5160
|
+
main.appendChild(form);
|
|
5051
5161
|
body.hidden = true;
|
|
5052
5162
|
trigger = () => {
|
|
5053
5163
|
if (body.hidden) {
|
|
@@ -5087,12 +5197,12 @@ function Line(store, fieldRenderer, layout, {
|
|
|
5087
5197
|
}
|
|
5088
5198
|
|
|
5089
5199
|
for (const column of columns) {
|
|
5090
|
-
const { actions, field, pattern } = column;
|
|
5200
|
+
const { actions, field, pattern, editable } = column;
|
|
5091
5201
|
if (!actions?.length) {
|
|
5092
5202
|
const td = head.appendChild(document.createElement('td'));
|
|
5093
5203
|
const child = field && store.child(field);
|
|
5094
5204
|
if (child) {
|
|
5095
|
-
const el = FormFieldInline(child, fieldRenderer, column, options);
|
|
5205
|
+
const el = FormFieldInline(child, fieldRenderer, column, {...options, editable: options?.editable && (editable !== false)});
|
|
5096
5206
|
if (el) { td.appendChild(el); }
|
|
5097
5207
|
}
|
|
5098
5208
|
continue;
|
|
@@ -5140,6 +5250,64 @@ function Line(store, fieldRenderer, layout, {
|
|
|
5140
5250
|
return root;
|
|
5141
5251
|
}
|
|
5142
5252
|
|
|
5253
|
+
/** @import { ArrayStore } from '../Store/index.mjs' */
|
|
5254
|
+
/** @import { StoreLayout } from '../StoreLayout.types.mjs' */
|
|
5255
|
+
|
|
5256
|
+
/**
|
|
5257
|
+
*
|
|
5258
|
+
* @template T
|
|
5259
|
+
* @param {ArrayStore} store
|
|
5260
|
+
* @param {StoreLayout.Field<T>} layout
|
|
5261
|
+
* @param {StoreLayout.Action[]} actionOptions
|
|
5262
|
+
* @param {(fields: { field: string; width: any; label: any; editable?: boolean? }[]) => StoreLayout.Column<T>[]} createDefault
|
|
5263
|
+
* @returns {StoreLayout.Column<T>[]}
|
|
5264
|
+
*/
|
|
5265
|
+
function getColumns(store, layout, actionOptions, createDefault) {
|
|
5266
|
+
const fieldList = Object.entries(store.type || {})
|
|
5267
|
+
.filter(([k, v]) => typeof v?.type !== 'object')
|
|
5268
|
+
.map(([field, { width, label }]) => ({ field, width, label }));
|
|
5269
|
+
const headerColumns = layout.columns;
|
|
5270
|
+
if (Array.isArray(headerColumns)) {
|
|
5271
|
+
const map = new Map(fieldList.map(v => [v.field, v]));
|
|
5272
|
+
/** @type {(StoreLayout.Column<T> | null)[]} */
|
|
5273
|
+
const allColumns = headerColumns.map(v => {
|
|
5274
|
+
if (!v) { return null; }
|
|
5275
|
+
if (typeof v === 'number') { return { placeholder: v }; }
|
|
5276
|
+
if (typeof v === 'string') { return map.get(v) || null; }
|
|
5277
|
+
if (typeof v !== 'object') { return null; }
|
|
5278
|
+
if (Array.isArray(v)) {
|
|
5279
|
+
/** @type {Set<StoreLayout.Action>} */
|
|
5280
|
+
const options = new Set(actionOptions);
|
|
5281
|
+
const actions = v.filter(v => options.delete(v));
|
|
5282
|
+
if (!actions) { return null; }
|
|
5283
|
+
return { actions };
|
|
5284
|
+
}
|
|
5285
|
+
const { action, actions, field, placeholder, pattern, width, label, editable } = v;
|
|
5286
|
+
if (field) {
|
|
5287
|
+
const define = map.get(field);
|
|
5288
|
+
if (define) {
|
|
5289
|
+
return { field, placeholder, width, label: label || define.label, editable };
|
|
5290
|
+
}
|
|
5291
|
+
}
|
|
5292
|
+
const options = new Set(actionOptions);
|
|
5293
|
+
const allActions = [action, actions].flat().filter(v => v && options.delete(v));
|
|
5294
|
+
if (allActions.length) {
|
|
5295
|
+
return { actions: /** @type {StoreLayout.Action[]} */(allActions), width, label, editable };
|
|
5296
|
+
}
|
|
5297
|
+
if (pattern) {
|
|
5298
|
+
return { pattern, placeholder, width, label, editable };
|
|
5299
|
+
}
|
|
5300
|
+
if (placeholder || width) {
|
|
5301
|
+
return { placeholder, width, label, editable };
|
|
5302
|
+
}
|
|
5303
|
+
return null;
|
|
5304
|
+
});
|
|
5305
|
+
const columns = /** @type {StoreLayout.Column<T>[]} */(allColumns.filter(Boolean));
|
|
5306
|
+
if (columns.length) { return columns; }
|
|
5307
|
+
}
|
|
5308
|
+
return createDefault(fieldList);
|
|
5309
|
+
}
|
|
5310
|
+
|
|
5143
5311
|
/** @import { Store, ArrayStore } from '../Store/index.mjs' */
|
|
5144
5312
|
/** @import { StoreLayout } from '../StoreLayout.types.mjs' */
|
|
5145
5313
|
|
|
@@ -5170,6 +5338,7 @@ function renderHead(signal, parent, columns, add, addable, editable) {
|
|
|
5170
5338
|
watch(() => !addable.get(), disabled => { button.disabled = disabled; }, true, signal);
|
|
5171
5339
|
}
|
|
5172
5340
|
}
|
|
5341
|
+
|
|
5173
5342
|
/**
|
|
5174
5343
|
*
|
|
5175
5344
|
* @template T
|
|
@@ -5181,54 +5350,15 @@ function renderHead(signal, parent, columns, add, addable, editable) {
|
|
|
5181
5350
|
*/
|
|
5182
5351
|
function Table(store, fieldRenderer, layout, options) {
|
|
5183
5352
|
if (options?.signal?.aborted) { return null; }
|
|
5184
|
-
const
|
|
5185
|
-
|
|
5186
|
-
|
|
5187
|
-
|
|
5188
|
-
|
|
5189
|
-
let columns = [];
|
|
5190
|
-
if (Array.isArray(headerColumns)) {
|
|
5191
|
-
const map = new Map(fieldList.map(v => [v.field, v]));
|
|
5192
|
-
|
|
5193
|
-
/** @type {(StoreLayout.Column<T> | null)[]} */
|
|
5194
|
-
const allColumns = headerColumns.map(v => {
|
|
5195
|
-
if (!v) { return null; }
|
|
5196
|
-
if (typeof v === 'number') { return { placeholder: v }; }
|
|
5197
|
-
if (typeof v === 'string') { return map.get(v) || null; }
|
|
5198
|
-
if (typeof v !== 'object') { return null; }
|
|
5199
|
-
if (Array.isArray(v)) {
|
|
5200
|
-
/** @type {Set<StoreLayout.Action>} */
|
|
5201
|
-
const options = new Set(['add', 'move', 'trigger', 'remove', 'serial', 'open', 'collapse']);
|
|
5202
|
-
const actions = v.filter(v => options.delete(v));
|
|
5203
|
-
if (!actions) { return null; }
|
|
5204
|
-
return { actions };
|
|
5205
|
-
}
|
|
5206
|
-
const { action, actions, field, placeholder, pattern, width, label } = v;
|
|
5207
|
-
if (field) {
|
|
5208
|
-
const define = map.get(field);
|
|
5209
|
-
if (define) {
|
|
5210
|
-
return { field, placeholder, width, label: label || define.label };
|
|
5211
|
-
}
|
|
5212
|
-
}
|
|
5213
|
-
const options = new Set(['add', 'move', 'trigger', 'remove', 'serial']);
|
|
5214
|
-
const allActions = [action, actions].flat().filter(v => v && options.delete(v));
|
|
5215
|
-
if (allActions.length) {
|
|
5216
|
-
return { actions: /** @type {StoreLayout.Action[]} */(allActions), width, label };
|
|
5217
|
-
}
|
|
5218
|
-
// if (pattern) {
|
|
5219
|
-
// return { pattern, placeholder, width, label };
|
|
5220
|
-
// }
|
|
5221
|
-
return null;
|
|
5222
|
-
});
|
|
5223
|
-
columns = /** @type {StoreLayout.Column<T>[]} */(allColumns.filter(Boolean));
|
|
5224
|
-
|
|
5225
|
-
}
|
|
5226
|
-
if (!columns.length) {
|
|
5227
|
-
columns = [
|
|
5353
|
+
const columns = getColumns(
|
|
5354
|
+
store,
|
|
5355
|
+
layout,
|
|
5356
|
+
['add', 'move', 'trigger', 'remove', 'serial'],
|
|
5357
|
+
fields => [
|
|
5228
5358
|
{ actions: ['add', 'trigger', 'move', 'remove', 'serial'] },
|
|
5229
|
-
...
|
|
5230
|
-
]
|
|
5231
|
-
|
|
5359
|
+
...fields.slice(0, 3),
|
|
5360
|
+
],
|
|
5361
|
+
);
|
|
5232
5362
|
|
|
5233
5363
|
const table = document.createElement('table');
|
|
5234
5364
|
table.classList.add('NeeloongForm-table');
|
|
@@ -5473,8 +5603,8 @@ function createCell(signal, layout, values, defCell, blockOnly) {
|
|
|
5473
5603
|
/**
|
|
5474
5604
|
*
|
|
5475
5605
|
* @template T
|
|
5476
|
-
* @param {Store<any, any>} store
|
|
5477
|
-
* @param {Signal.State<Store<any, any>?>} currentStore
|
|
5606
|
+
* @param {Store<any, any, any>} store
|
|
5607
|
+
* @param {Signal.State<Store<any, any, any>?>} currentStore
|
|
5478
5608
|
* @param {StoreLayout.Renderer<T>} fieldRenderer
|
|
5479
5609
|
* @param {StoreLayout.Field<T>} layout
|
|
5480
5610
|
* @param {Signal.State<State>} state
|
|
@@ -5488,7 +5618,7 @@ function createCell(signal, layout, values, defCell, blockOnly) {
|
|
|
5488
5618
|
* @param {() => void} option.dragend
|
|
5489
5619
|
* @param {{get(): boolean}} option.deletable
|
|
5490
5620
|
* @param {() => void} option.addNode
|
|
5491
|
-
* @param {(store: Store<any, any>) => () => void} option.createDetails
|
|
5621
|
+
* @param {(store: Store<any, any, any>) => () => void} option.createDetails
|
|
5492
5622
|
* @param {StoreLayout.Options?} options
|
|
5493
5623
|
* @returns {HTMLElement}
|
|
5494
5624
|
*/
|
|
@@ -5805,56 +5935,16 @@ function createState(store, states, drag, levelKey, index) {
|
|
|
5805
5935
|
*/
|
|
5806
5936
|
function Tree(store, fieldRenderer, layout, options) {
|
|
5807
5937
|
if (options?.signal?.aborted) { return null; }
|
|
5808
|
-
const
|
|
5809
|
-
|
|
5810
|
-
|
|
5811
|
-
|
|
5812
|
-
|
|
5813
|
-
let columns = [];
|
|
5814
|
-
if (Array.isArray(headerColumns)) {
|
|
5815
|
-
const map = new Map(fieldList.map(v => [v.field, v]));
|
|
5816
|
-
/** @type {(StoreLayout.Column<T> | null)[]} */
|
|
5817
|
-
const allColumns = headerColumns.map(v => {
|
|
5818
|
-
if (!v) { return null; }
|
|
5819
|
-
if (typeof v === 'number') { return { placeholder: v }; }
|
|
5820
|
-
if (typeof v === 'string') { return map.get(v) || null; }
|
|
5821
|
-
if (typeof v !== 'object') { return null; }
|
|
5822
|
-
if (Array.isArray(v)) {
|
|
5823
|
-
/** @type {Set<StoreLayout.Action>} */
|
|
5824
|
-
const options = new Set(['add', 'move', 'trigger', 'remove', 'serial', 'open', 'collapse']);
|
|
5825
|
-
const actions = v.filter(v => options.delete(v));
|
|
5826
|
-
if (!actions) { return null; }
|
|
5827
|
-
return { actions };
|
|
5828
|
-
}
|
|
5829
|
-
const { action, actions, field, placeholder, pattern, width, label } = v;
|
|
5830
|
-
if (field) {
|
|
5831
|
-
const define = map.get(field);
|
|
5832
|
-
if (define) {
|
|
5833
|
-
return { field, placeholder, width, label: label || define.label };
|
|
5834
|
-
}
|
|
5835
|
-
}
|
|
5836
|
-
const options = new Set(['add', 'move', 'trigger', 'remove', 'serial', 'open', 'collapse']);
|
|
5837
|
-
const allActions = [action, actions].flat().filter(v => v && options.delete(v));
|
|
5838
|
-
if (allActions.length) {
|
|
5839
|
-
return { actions: /** @type {StoreLayout.Action[]} */(allActions), width, label };
|
|
5840
|
-
}
|
|
5841
|
-
if (pattern) {
|
|
5842
|
-
return { pattern, placeholder, width, label };
|
|
5843
|
-
}
|
|
5844
|
-
if (placeholder || width) {
|
|
5845
|
-
return { placeholder, width, label };
|
|
5846
|
-
}
|
|
5847
|
-
return null;
|
|
5848
|
-
});
|
|
5849
|
-
columns = /** @type {StoreLayout.Column<T>[]} */(allColumns.filter(Boolean));
|
|
5850
|
-
}
|
|
5851
|
-
if (!columns.length) {
|
|
5852
|
-
columns = [
|
|
5938
|
+
const columns = getColumns(
|
|
5939
|
+
store,
|
|
5940
|
+
layout,
|
|
5941
|
+
['add', 'move', 'trigger', 'remove', 'serial', 'open', 'collapse'],
|
|
5942
|
+
fields => [
|
|
5853
5943
|
{ actions: ['collapse', 'move'] },
|
|
5854
|
-
|
|
5944
|
+
fields[0],
|
|
5855
5945
|
{ actions: ['add', 'remove'] },
|
|
5856
|
-
]
|
|
5857
|
-
|
|
5946
|
+
]
|
|
5947
|
+
);
|
|
5858
5948
|
|
|
5859
5949
|
|
|
5860
5950
|
const root = document.createElement('div');
|
|
@@ -5930,10 +6020,10 @@ function Tree(store, fieldRenderer, layout, options) {
|
|
|
5930
6020
|
|
|
5931
6021
|
/** @type {AbortController?} */
|
|
5932
6022
|
let detailAbortController = null;
|
|
5933
|
-
const detailsStore = new Signal.State(/** @type{Store<any, any>?}*/(null));
|
|
6023
|
+
const detailsStore = new Signal.State(/** @type{Store<any, any, any>?}*/(null));
|
|
5934
6024
|
/**
|
|
5935
6025
|
*
|
|
5936
|
-
* @param {Store<any, any>} store
|
|
6026
|
+
* @param {Store<any, any, any>} store
|
|
5937
6027
|
* @returns
|
|
5938
6028
|
*/
|
|
5939
6029
|
function createDetails(store) {
|
|
@@ -6185,7 +6275,7 @@ function Tree(store, fieldRenderer, layout, options) {
|
|
|
6185
6275
|
*
|
|
6186
6276
|
* @template T
|
|
6187
6277
|
* @param {string | ParentNode} html
|
|
6188
|
-
* @param {Store<any, any>} store
|
|
6278
|
+
* @param {Store<any, any, any>} store
|
|
6189
6279
|
* @param {StoreLayout.Renderer<T>} fieldRenderer
|
|
6190
6280
|
* @param {StoreLayout.Options?} options
|
|
6191
6281
|
* @param {StoreLayout.Field<T>} layout
|
|
@@ -6217,7 +6307,7 @@ function renderArrayCell(arrayStyle, store, fieldRenderer, layout, options) {
|
|
|
6217
6307
|
/**
|
|
6218
6308
|
*
|
|
6219
6309
|
* @template T
|
|
6220
|
-
* @param {Store<any, any>} store
|
|
6310
|
+
* @param {Store<any, any, any>} store
|
|
6221
6311
|
* @param {StoreLayout.Renderer<T>} fieldRenderer
|
|
6222
6312
|
* @param {StoreLayout.Field<T>} layout
|
|
6223
6313
|
* @param {StoreLayout.Options?} options
|
|
@@ -6251,7 +6341,7 @@ function FormField(store, fieldRenderer, layout, options) {
|
|
|
6251
6341
|
|
|
6252
6342
|
/**
|
|
6253
6343
|
*
|
|
6254
|
-
* @param {Store<any, any>} store
|
|
6344
|
+
* @param {Store<any, any, any>} store
|
|
6255
6345
|
* @param {StoreLayout.Button} layout
|
|
6256
6346
|
* @param {StoreLayout.Options?} options
|
|
6257
6347
|
* @returns {ParentNode}
|
|
@@ -6289,7 +6379,7 @@ function FormButton(store, layout, options) {
|
|
|
6289
6379
|
/**
|
|
6290
6380
|
*
|
|
6291
6381
|
* @template T
|
|
6292
|
-
* @param {Store<any, any>} store
|
|
6382
|
+
* @param {Store<any, any, any>} store
|
|
6293
6383
|
* @param {StoreLayout.Renderer<T>} fieldRenderer
|
|
6294
6384
|
* @param {StoreLayout.Html} layout
|
|
6295
6385
|
* @param {StoreLayout.Options?} options
|
|
@@ -6311,7 +6401,7 @@ function FormHtml(store, fieldRenderer, layout, options) {
|
|
|
6311
6401
|
/**
|
|
6312
6402
|
*
|
|
6313
6403
|
* @template T
|
|
6314
|
-
* @param {Store<any, any>} store
|
|
6404
|
+
* @param {Store<any, any, any>} store
|
|
6315
6405
|
* @param {StoreLayout.Renderer<T>} fieldRenderer
|
|
6316
6406
|
* @param {StoreLayout.Item<T>} item
|
|
6317
6407
|
* @param {StoreLayout.Options?} options
|
|
@@ -6336,7 +6426,7 @@ function FormItem(store, fieldRenderer, item, options) {
|
|
|
6336
6426
|
/**
|
|
6337
6427
|
*
|
|
6338
6428
|
* @template T
|
|
6339
|
-
* @param {Store<any, any>} store
|
|
6429
|
+
* @param {Store<any, any, any>} store
|
|
6340
6430
|
* @param {StoreLayout.Renderer<T>} fieldRenderer
|
|
6341
6431
|
* @param {StoreLayout<T>} layout
|
|
6342
6432
|
* @param {StoreLayout.Options?} options
|