@neeloong/form 0.12.0 → 0.13.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/README.md +11 -2
- package/index.d.mts +22 -6
- package/index.js +142 -38
- package/index.min.js +5 -5
- package/index.min.mjs +5 -5
- package/index.mjs +142 -38
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -175,6 +175,13 @@ render(store, layouts, app);
|
|
|
175
175
|
<li !enum="items" !text="$item"></li> <!-- items 是数组 -->
|
|
176
176
|
</ul>
|
|
177
177
|
```
|
|
178
|
+
#### 自定义排序
|
|
179
|
+
|
|
180
|
+
```html
|
|
181
|
+
<ul>
|
|
182
|
+
<li !enum="object" !sort="$key" !text="$item"></li> <!-- object 是对象,将按照其键排序,渲染其值 -->
|
|
183
|
+
</ul>
|
|
184
|
+
```
|
|
178
185
|
|
|
179
186
|
#### 嵌套循环
|
|
180
187
|
|
|
@@ -284,7 +291,7 @@ render(store, layouts, app);
|
|
|
284
291
|
1. 模板定义: `!template`
|
|
285
292
|
1. 条件: `!if` `!else`
|
|
286
293
|
1. 子属性: `!value`
|
|
287
|
-
1. 枚举: `!enum`
|
|
294
|
+
1. 枚举: `!enum` `!sort`
|
|
288
295
|
1. 别名、计算名与显式变量: `*别名` `*计算名` `+变量`
|
|
289
296
|
1. 片段与模板调用: `!fragment`
|
|
290
297
|
1. 属性与事件: `:绑定属性` `@事件` `普通属性` `!bind`
|
|
@@ -325,7 +332,9 @@ render(store, layouts, app);
|
|
|
325
332
|
- `$kind` 只读 字段类别
|
|
326
333
|
- `$error` 只读 字段校验错误信息
|
|
327
334
|
- `$errors` 只读 所有校验错误列表
|
|
328
|
-
|
|
335
|
+
- `$addable` 只读 是否可以为当前数组增加项目,非数组上下文总是为 `false`
|
|
336
|
+
- `$removable` 只读 是否可以将当前项从数组中移除,非数组成员上下文总是为 `false`
|
|
337
|
+
1. 字段扩展隐式函数(只在事件中可用)
|
|
329
338
|
- `$reset()` 重置数据
|
|
330
339
|
- `$validate()` 触发当前项的异步校验
|
|
331
340
|
- `$validate(true)` 触发当前项及其后代的异步校验
|
package/index.d.mts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/*!
|
|
2
|
-
* @neeloong/form v0.
|
|
2
|
+
* @neeloong/form v0.13.0
|
|
3
3
|
* (c) 2024-2025 Fierflame
|
|
4
4
|
* @license Apache-2.0
|
|
5
5
|
*/
|
|
@@ -253,6 +253,7 @@ type Enum = {
|
|
|
253
253
|
templates?: Record<string, Template> | undefined;
|
|
254
254
|
type: "enum";
|
|
255
255
|
value: Node.Name | Node.Calc | Node.Value;
|
|
256
|
+
sort?: Node.Name | Node.Calc | Node.Value<any> | undefined;
|
|
256
257
|
/**
|
|
257
258
|
* 子元素
|
|
258
259
|
*/
|
|
@@ -653,6 +654,14 @@ declare namespace Schema {
|
|
|
653
654
|
* 模式规则
|
|
654
655
|
*/
|
|
655
656
|
pattern?: RegExp | ((store: Store) => RegExp | null) | null | undefined;
|
|
657
|
+
/**
|
|
658
|
+
* 数组内是否可添加
|
|
659
|
+
*/
|
|
660
|
+
addable?: boolean | ((store: Store) => boolean) | null | undefined;
|
|
661
|
+
/**
|
|
662
|
+
* 数组内是否可移除
|
|
663
|
+
*/
|
|
664
|
+
removable?: boolean | ((store: Store) => boolean) | null | undefined;
|
|
656
665
|
/**
|
|
657
666
|
* 可选值
|
|
658
667
|
*/
|
|
@@ -804,7 +813,7 @@ declare class Store<T = any, M = any> {
|
|
|
804
813
|
/**
|
|
805
814
|
* @param {Schema.Field<M>} schema 字段的 Schema 定义
|
|
806
815
|
* @param {object} [options] 可选配置
|
|
807
|
-
* @param {
|
|
816
|
+
* @param {Store?} [options.parent]
|
|
808
817
|
* @param {*} [options.state]
|
|
809
818
|
* @param {number | string | null} [options.index]
|
|
810
819
|
* @param {number | Signal.State<number> | Signal.Computed<number>} [options.size]
|
|
@@ -813,8 +822,9 @@ declare class Store<T = any, M = any> {
|
|
|
813
822
|
* @param {boolean} [options.hidden]
|
|
814
823
|
* @param {boolean} [options.clearable]
|
|
815
824
|
* @param {boolean} [options.required]
|
|
816
|
-
* @param {boolean} [options.readonly]
|
|
817
825
|
* @param {boolean} [options.disabled]
|
|
826
|
+
* @param {boolean} [options.readonly]
|
|
827
|
+
* @param {boolean} [options.removable]
|
|
818
828
|
*
|
|
819
829
|
* @param {string} [options.label] 字段标签
|
|
820
830
|
* @param {string} [options.description] 字段描述
|
|
@@ -838,8 +848,8 @@ declare class Store<T = any, M = any> {
|
|
|
838
848
|
* @param {((value: T?, index: any, store: Store) => void)?} [options.onUpdate]
|
|
839
849
|
* @param {((value: T?, index: any, store: Store) => void)?} [options.onUpdateState]
|
|
840
850
|
*/
|
|
841
|
-
constructor(schema: Schema.Field<M>, { null: isNull, state, ref, setValue, setState, convert, onUpdate, onUpdateState, validator, validators, index, size, new: isNew, parent: parentNode, hidden, clearable, required, disabled, readonly, label, description, placeholder, min, max, step, minLength, maxLength, pattern, values }?: {
|
|
842
|
-
parent?: any;
|
|
851
|
+
constructor(schema: Schema.Field<M>, { null: isNull, state, ref, setValue, setState, convert, onUpdate, onUpdateState, validator, validators, index, size, new: isNew, parent: parentNode, hidden, clearable, required, disabled, readonly, removable, label, description, placeholder, min, max, step, minLength, maxLength, pattern, values }?: {
|
|
852
|
+
parent?: Store<any, any> | null | undefined;
|
|
843
853
|
state?: any;
|
|
844
854
|
index?: string | number | null | undefined;
|
|
845
855
|
size?: number | Signal.State<number> | Signal.Computed<number> | undefined;
|
|
@@ -848,8 +858,9 @@ declare class Store<T = any, M = any> {
|
|
|
848
858
|
hidden?: boolean | undefined;
|
|
849
859
|
clearable?: boolean | undefined;
|
|
850
860
|
required?: boolean | undefined;
|
|
851
|
-
readonly?: boolean | undefined;
|
|
852
861
|
disabled?: boolean | undefined;
|
|
862
|
+
readonly?: boolean | undefined;
|
|
863
|
+
removable?: boolean | undefined;
|
|
853
864
|
label?: string | undefined;
|
|
854
865
|
description?: string | undefined;
|
|
855
866
|
placeholder?: string | undefined;
|
|
@@ -964,6 +975,11 @@ declare class Store<T = any, M = any> {
|
|
|
964
975
|
set readonly(v: boolean);
|
|
965
976
|
/** 是否只读 */
|
|
966
977
|
get readonly(): boolean;
|
|
978
|
+
set selfRemovable(v: boolean | null);
|
|
979
|
+
get selfRemovable(): boolean | null;
|
|
980
|
+
set removable(v: boolean);
|
|
981
|
+
/** 是否只读 */
|
|
982
|
+
get removable(): boolean;
|
|
967
983
|
set selfLabel(v: string | null);
|
|
968
984
|
get selfLabel(): string | null;
|
|
969
985
|
set label(v: string | null);
|
package/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/*!
|
|
2
|
-
* @neeloong/form v0.
|
|
2
|
+
* @neeloong/form v0.13.0
|
|
3
3
|
* (c) 2024-2025 Fierflame
|
|
4
4
|
* @license Apache-2.0
|
|
5
5
|
*/
|
|
@@ -595,17 +595,12 @@
|
|
|
595
595
|
* @param {Signal.Computed<boolean>?} [parent]
|
|
596
596
|
* @returns {[Signal.State<boolean?>, Signal.Computed<boolean>]}
|
|
597
597
|
*/
|
|
598
|
-
|
|
598
|
+
function createBooleanStates(self, defState, fn, parent) {
|
|
599
599
|
|
|
600
600
|
const selfState = new exports.Signal.State(typeof defState === 'boolean' ? defState : null);
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
scriptState = new exports.Signal.Computed(() => Boolean(fn(self)));
|
|
605
|
-
} else {
|
|
606
|
-
const def = Boolean(fn);
|
|
607
|
-
scriptState = new exports.Signal.Computed(() => def);
|
|
608
|
-
}
|
|
601
|
+
const scriptState = typeof fn === 'function'
|
|
602
|
+
? new exports.Signal.Computed(() => Boolean(fn(self)))
|
|
603
|
+
: new exports.Signal.State(Boolean(fn));
|
|
609
604
|
|
|
610
605
|
const getState = () => {
|
|
611
606
|
const s = selfState.get();
|
|
@@ -617,7 +612,7 @@
|
|
|
617
612
|
|
|
618
613
|
return [selfState, state];
|
|
619
614
|
|
|
620
|
-
}
|
|
615
|
+
}
|
|
621
616
|
|
|
622
617
|
/** @import { Schema } from '../types.mjs' */
|
|
623
618
|
/** @param {*} v */
|
|
@@ -717,12 +712,13 @@
|
|
|
717
712
|
}
|
|
718
713
|
|
|
719
714
|
/** @import { Schema } from '../types.mjs' */
|
|
715
|
+
/** @import ArrayStore from './ArrayStore.mjs' */
|
|
720
716
|
|
|
721
717
|
|
|
722
718
|
/** @type {{new(...p: ConstructorParameters<typeof Store>): Store}?} */
|
|
723
719
|
let ObjectStore$1 = null;
|
|
724
|
-
/** @type {{new(...p: ConstructorParameters<typeof Store>):
|
|
725
|
-
let
|
|
720
|
+
/** @type {{new(...p: ConstructorParameters<typeof Store>): ArrayStore}?} */
|
|
721
|
+
let ArrayStoreClass = null;
|
|
726
722
|
/** @type {Record<string, {new(...p: ConstructorParameters<typeof Store>): Store}?>} */
|
|
727
723
|
let TypeStores = Object.create(null);
|
|
728
724
|
/**
|
|
@@ -739,8 +735,8 @@
|
|
|
739
735
|
const type = schema.type;
|
|
740
736
|
/** @type {{new(...p: ConstructorParameters<typeof Store>): Store}} */
|
|
741
737
|
let Class = Store;
|
|
742
|
-
if (schema.array && !(
|
|
743
|
-
if (
|
|
738
|
+
if (schema.array && !(ArrayStoreClass && options?.parent instanceof ArrayStoreClass)) {
|
|
739
|
+
if (ArrayStoreClass) { Class = ArrayStoreClass; }
|
|
744
740
|
} else if (typeof type === 'string') {
|
|
745
741
|
const C = TypeStores[type];
|
|
746
742
|
if (C) { Class = C; }
|
|
@@ -755,9 +751,9 @@
|
|
|
755
751
|
ObjectStore$1 = Class;
|
|
756
752
|
}
|
|
757
753
|
|
|
758
|
-
/** @param {{new(...p: ConstructorParameters<typeof Store>):
|
|
754
|
+
/** @param {{new(...p: ConstructorParameters<typeof Store>): ArrayStore}} Class */
|
|
759
755
|
function setArrayStore(Class) {
|
|
760
|
-
|
|
756
|
+
ArrayStoreClass = Class;
|
|
761
757
|
}
|
|
762
758
|
/**
|
|
763
759
|
* @param {string} type
|
|
@@ -933,7 +929,7 @@
|
|
|
933
929
|
/**
|
|
934
930
|
* @param {Schema.Field<M>} schema 字段的 Schema 定义
|
|
935
931
|
* @param {object} [options] 可选配置
|
|
936
|
-
* @param {
|
|
932
|
+
* @param {Store?} [options.parent]
|
|
937
933
|
* @param {*} [options.state]
|
|
938
934
|
* @param {number | string | null} [options.index]
|
|
939
935
|
* @param {number | Signal.State<number> | Signal.Computed<number>} [options.size]
|
|
@@ -942,8 +938,9 @@
|
|
|
942
938
|
* @param {boolean} [options.hidden]
|
|
943
939
|
* @param {boolean} [options.clearable]
|
|
944
940
|
* @param {boolean} [options.required]
|
|
945
|
-
* @param {boolean} [options.readonly]
|
|
946
941
|
* @param {boolean} [options.disabled]
|
|
942
|
+
* @param {boolean} [options.readonly]
|
|
943
|
+
* @param {boolean} [options.removable]
|
|
947
944
|
*
|
|
948
945
|
* @param {string} [options.label] 字段标签
|
|
949
946
|
* @param {string} [options.description] 字段描述
|
|
@@ -972,7 +969,7 @@
|
|
|
972
969
|
setValue, setState, convert, onUpdate, onUpdateState,
|
|
973
970
|
validator, validators,
|
|
974
971
|
index, size, new: isNew, parent: parentNode,
|
|
975
|
-
hidden, clearable, required, disabled, readonly,
|
|
972
|
+
hidden, clearable, required, disabled, readonly, removable,
|
|
976
973
|
label, description, placeholder, min, max, step, minLength, maxLength, pattern, values: values$1
|
|
977
974
|
} = {}) {
|
|
978
975
|
this.schema = schema;
|
|
@@ -1038,6 +1035,8 @@
|
|
|
1038
1035
|
// @ts-ignore
|
|
1039
1036
|
[this.#selfValues, this.#values] = createState(this, values, values$1, schema.values);
|
|
1040
1037
|
|
|
1038
|
+
[this.#selfRemovable, this.#removable] = createBooleanStates(this, removable, schema.removable ?? true);
|
|
1039
|
+
|
|
1041
1040
|
const validatorResult = createValidator(this, schema.validator, validator);
|
|
1042
1041
|
|
|
1043
1042
|
const [changed, changedResult, cancelChange] = createAsyncValidator(this, schema.validators?.change, validators?.change);
|
|
@@ -1192,6 +1191,15 @@
|
|
|
1192
1191
|
set readonly(v) { this.#selfReadonly.set(typeof v === 'boolean' ? v : null); }
|
|
1193
1192
|
|
|
1194
1193
|
|
|
1194
|
+
/** @readonly @type {Signal.State<boolean?>} */
|
|
1195
|
+
#selfRemovable
|
|
1196
|
+
/** @readonly @type {Signal.Computed<boolean>} */
|
|
1197
|
+
#removable
|
|
1198
|
+
get selfRemovable() { return this.#selfRemovable.get(); }
|
|
1199
|
+
set selfRemovable(v) { this.#selfRemovable.set(typeof v === 'boolean' ? v : null); }
|
|
1200
|
+
/** 是否只读 */
|
|
1201
|
+
get removable() { return this.#removable.get(); }
|
|
1202
|
+
set removable(v) { this.#selfRemovable.set(typeof v === 'boolean' ? v : null); }
|
|
1195
1203
|
|
|
1196
1204
|
|
|
1197
1205
|
/** @readonly @type {Signal.State<string?>} */
|
|
@@ -1397,6 +1405,7 @@
|
|
|
1397
1405
|
}
|
|
1398
1406
|
this.#value.set(newValues);
|
|
1399
1407
|
this.#initValue.set(newValues);
|
|
1408
|
+
this.#onUpdate?.(newValues, this.#index.get(), this);
|
|
1400
1409
|
return newValues;
|
|
1401
1410
|
}
|
|
1402
1411
|
|
|
@@ -1596,10 +1605,11 @@
|
|
|
1596
1605
|
* @param {Store?} [options.parent]
|
|
1597
1606
|
* @param {string | number | null} [options.index]
|
|
1598
1607
|
* @param {boolean} [options.new]
|
|
1608
|
+
* @param {boolean} [options.addable]
|
|
1599
1609
|
* @param {(value: any, index: any, store: Store) => void} [options.onUpdate]
|
|
1600
1610
|
* @param {(value: any, index: any, store: Store) => void} [options.onUpdateState]
|
|
1601
1611
|
*/
|
|
1602
|
-
constructor(schema, { parent, onUpdate, onUpdateState, index, new: isNew} = {}) {
|
|
1612
|
+
constructor(schema, { parent, onUpdate, onUpdateState, index, new: isNew, addable} = {}) {
|
|
1603
1613
|
const childrenState = new exports.Signal.State(/** @type {Store[]} */([]));
|
|
1604
1614
|
// @ts-ignore
|
|
1605
1615
|
const updateChildren = (list) => {
|
|
@@ -1635,6 +1645,9 @@
|
|
|
1635
1645
|
},
|
|
1636
1646
|
onUpdateState,
|
|
1637
1647
|
});
|
|
1648
|
+
|
|
1649
|
+
[this.#selfAddable, this.#addable] = createBooleanStates(this, addable, schema.addable ?? true);
|
|
1650
|
+
|
|
1638
1651
|
this.#children = childrenState;
|
|
1639
1652
|
const childCommonOptions = {
|
|
1640
1653
|
parent: this,
|
|
@@ -1665,6 +1678,20 @@
|
|
|
1665
1678
|
return child
|
|
1666
1679
|
};
|
|
1667
1680
|
}
|
|
1681
|
+
|
|
1682
|
+
|
|
1683
|
+
/** @readonly @type {Signal.State<boolean?>} */
|
|
1684
|
+
#selfAddable
|
|
1685
|
+
/** @readonly @type {Signal.Computed<boolean>} */
|
|
1686
|
+
#addable
|
|
1687
|
+
get selfAddable() { return this.#selfAddable.get(); }
|
|
1688
|
+
set selfAddable(v) { this.#selfAddable.set(typeof v === 'boolean' ? v : null); }
|
|
1689
|
+
/** 是否禁用字段 */
|
|
1690
|
+
get addable() { return this.#addable.get(); }
|
|
1691
|
+
set addable(v) { this.#selfAddable.set(typeof v === 'boolean' ? v : null); }
|
|
1692
|
+
|
|
1693
|
+
|
|
1694
|
+
|
|
1668
1695
|
/**
|
|
1669
1696
|
*
|
|
1670
1697
|
* @param {number} index
|
|
@@ -1673,6 +1700,7 @@
|
|
|
1673
1700
|
* @returns
|
|
1674
1701
|
*/
|
|
1675
1702
|
insert(index, value = null, isNew) {
|
|
1703
|
+
if (!this.addable) { return false; }
|
|
1676
1704
|
const data = this.value || [];
|
|
1677
1705
|
if (!Array.isArray(data)) { return false; }
|
|
1678
1706
|
const children = [...this.#children.get()];
|
|
@@ -1943,7 +1971,7 @@
|
|
|
1943
1971
|
}
|
|
1944
1972
|
const enumValue = layout.enum;
|
|
1945
1973
|
const name = layout.value;
|
|
1946
|
-
if (enumValue) { child = { type: 'enum', value: enumValue, vars, children: child ? [child] : [] }; vars = null; }
|
|
1974
|
+
if (enumValue) { child = { type: 'enum', value: enumValue, sort: layout.sort, vars, children: child ? [child] : [] }; vars = null; }
|
|
1947
1975
|
if (name) { child = { type: 'value', name, vars, children: child ? [child] : [] }; vars = null; }
|
|
1948
1976
|
if (vars?.length) {
|
|
1949
1977
|
child = { type: 'fragment', vars, children: child ? [child] : [] };
|
|
@@ -2137,6 +2165,9 @@
|
|
|
2137
2165
|
case 'enum':
|
|
2138
2166
|
node.enum = value ? parse$1(value, createCalc) : {value: true};
|
|
2139
2167
|
break;
|
|
2168
|
+
case 'sort':
|
|
2169
|
+
node.sort = value ? parse$1(value, createCalc) : {value: true};
|
|
2170
|
+
break;
|
|
2140
2171
|
case 'if':
|
|
2141
2172
|
node.if = parse$1(value, createCalc);
|
|
2142
2173
|
break;
|
|
@@ -2178,6 +2209,7 @@
|
|
|
2178
2209
|
*
|
|
2179
2210
|
* @property {string} [value] 值关联
|
|
2180
2211
|
* @property {Layout.Node.Name | Layout.Node.Calc | Layout.Node.Value} [enum] 列表属性枚举
|
|
2212
|
+
* @property {Layout.Node.Name | Layout.Node.Calc | Layout.Node.Value} [sort]
|
|
2181
2213
|
*
|
|
2182
2214
|
* @property {boolean | string} [bind] 绑定内容
|
|
2183
2215
|
* @property {Layout.Node.Name | Layout.Node.Value | Layout.Node.Calc} [text] 文本渲染
|
|
@@ -2804,6 +2836,7 @@
|
|
|
2804
2836
|
* @property {Record<string, Template>} [templates]
|
|
2805
2837
|
* @property {'enum'} type
|
|
2806
2838
|
* @property {Node.Name | Node.Calc | Node.Value} value
|
|
2839
|
+
* @property {Node.Name | Node.Calc | Node.Value} [sort]
|
|
2807
2840
|
* @property {Child[]} children 子元素
|
|
2808
2841
|
* @property {string} [comment] 注释
|
|
2809
2842
|
*/
|
|
@@ -3003,7 +3036,11 @@
|
|
|
3003
3036
|
yield [`${key}${sign}reset`, {exec: () => val.reset()}];
|
|
3004
3037
|
// @ts-ignore
|
|
3005
3038
|
yield [`${key}${sign}validate`, {exec: v => val.validate(v ? [] : null)}];
|
|
3006
|
-
if (!(val instanceof ArrayStore)) {
|
|
3039
|
+
if (!(val instanceof ArrayStore)) {
|
|
3040
|
+
yield [`${key}${sign}addable`, {get: () => false}];
|
|
3041
|
+
return;
|
|
3042
|
+
}
|
|
3043
|
+
yield [`${key}${sign}addable`, {get: () => val.addable}];
|
|
3007
3044
|
yield [`${key}${sign}insert`, {exec: (index, value) => val.insert(index, value)}];
|
|
3008
3045
|
yield [`${key}${sign}add`, {exec: (v) => val.add(v)}];
|
|
3009
3046
|
yield [`${key}${sign}remove`, {exec: (index) => val.remove(index)}];
|
|
@@ -3022,30 +3059,53 @@
|
|
|
3022
3059
|
*/
|
|
3023
3060
|
function *toParentItem(parent, val, key = '', sign = '$') {
|
|
3024
3061
|
if (!(parent instanceof ArrayStore)) {
|
|
3062
|
+
yield [`${key}${sign}removable`, {get: () => false}];
|
|
3025
3063
|
yield [`${key}${sign}upMovable`, {get: () => false}];
|
|
3026
3064
|
yield [`${key}${sign}downMovable`, {get: () => false}];
|
|
3065
|
+
yield [`${key}${sign}remove`, {exec: () => {}}];
|
|
3066
|
+
yield [`${key}${sign}upMove`, {exec: () => {}}];
|
|
3067
|
+
yield [`${key}${sign}downMove`, {exec: () => {}}];
|
|
3027
3068
|
return
|
|
3028
3069
|
}
|
|
3070
|
+
yield [`${key}${sign}removable`, {get: () => {
|
|
3071
|
+
if (parent.readonly) { return false; }
|
|
3072
|
+
if (parent.disabled) { return false; }
|
|
3073
|
+
if (!val.removable) { return false; }
|
|
3074
|
+
return true;
|
|
3075
|
+
}}];
|
|
3029
3076
|
yield [`${key}${sign}upMovable`, {get: () => {
|
|
3077
|
+
if (parent.readonly) { return false; }
|
|
3078
|
+
if (parent.disabled) { return false; }
|
|
3030
3079
|
const s = val.index;
|
|
3031
3080
|
if (typeof s !== 'number') { return false; }
|
|
3032
3081
|
if (s <= 0) { return false; }
|
|
3033
3082
|
return true;
|
|
3034
3083
|
}}];
|
|
3035
3084
|
yield [`${key}${sign}downMovable`, {get: () => {
|
|
3085
|
+
if (parent.readonly) { return false; }
|
|
3086
|
+
if (parent.disabled) { return false; }
|
|
3036
3087
|
const s = val.index;
|
|
3037
3088
|
if (typeof s !== 'number') { return false; }
|
|
3038
3089
|
if (s >= parent.size - 1) { return false; }
|
|
3039
3090
|
return true;
|
|
3040
3091
|
}}];
|
|
3041
|
-
yield [`${key}${sign}remove`, {exec: () =>
|
|
3092
|
+
yield [`${key}${sign}remove`, {exec: () => {
|
|
3093
|
+
if (parent.readonly) { return; }
|
|
3094
|
+
if (parent.disabled) { return; }
|
|
3095
|
+
if (!val.removable) { return; }
|
|
3096
|
+
parent.remove(Number(val.index));
|
|
3097
|
+
}}];
|
|
3042
3098
|
yield [`${key}${sign}upMove`, {exec: () => {
|
|
3099
|
+
if (parent.readonly) { return; }
|
|
3100
|
+
if (parent.disabled) { return; }
|
|
3043
3101
|
const s = val.index;
|
|
3044
3102
|
if (typeof s !== 'number') { return; }
|
|
3045
3103
|
if (s <= 0) { return; }
|
|
3046
3104
|
parent.move(s, s - 1);
|
|
3047
3105
|
}}];
|
|
3048
3106
|
yield [`${key}${sign}downMove`, {exec: () => {
|
|
3107
|
+
if (parent.readonly) { return; }
|
|
3108
|
+
if (parent.disabled) { return; }
|
|
3049
3109
|
const s = val.index;
|
|
3050
3110
|
if (typeof s !== 'number') { return; }
|
|
3051
3111
|
if (s >= parent.size - 1) { return; }
|
|
@@ -4524,6 +4584,7 @@
|
|
|
4524
4584
|
return node;
|
|
4525
4585
|
}
|
|
4526
4586
|
|
|
4587
|
+
/** @import * as Layout from '../Layout/index.mjs' */
|
|
4527
4588
|
/** @import Store, { ArrayStore } from '../Store/index.mjs' */
|
|
4528
4589
|
|
|
4529
4590
|
/**
|
|
@@ -4533,8 +4594,9 @@
|
|
|
4533
4594
|
* @param {ArrayStore} store
|
|
4534
4595
|
* @param {Environment} env
|
|
4535
4596
|
* @param {(next: Node | null, env: any) => () => void} renderItem
|
|
4597
|
+
* @param {Layout.Node.Name | Layout.Node.Calc | Layout.Node.Value} [sort]
|
|
4536
4598
|
*/
|
|
4537
|
-
function renderArray(parent, next, store, env, renderItem) {
|
|
4599
|
+
function renderArray(parent, next, store, env, renderItem, sort) {
|
|
4538
4600
|
const start = parent.insertBefore(document.createComment(''), next);
|
|
4539
4601
|
/** @type {Map<Store, [Comment, Comment, () => void]>} */
|
|
4540
4602
|
let seMap = new Map();
|
|
@@ -4650,7 +4712,26 @@
|
|
|
4650
4712
|
};
|
|
4651
4713
|
}
|
|
4652
4714
|
|
|
4715
|
+
/**
|
|
4716
|
+
*
|
|
4717
|
+
* @param {any} a
|
|
4718
|
+
* @param {any} b
|
|
4719
|
+
* @returns
|
|
4720
|
+
*/
|
|
4721
|
+
function compare(a, b) {
|
|
4722
|
+
if (typeof a === 'bigint' && typeof b === 'bigint') {
|
|
4723
|
+
return Number(a - b);
|
|
4724
|
+
}
|
|
4725
|
+
if ((typeof a === 'number' || typeof a === 'bigint') && (typeof b === 'number' || typeof b === 'bigint')) {
|
|
4726
|
+
return Number(a) - Number(b);
|
|
4727
|
+
}
|
|
4728
|
+
const sa = String(a);
|
|
4729
|
+
const sb = String(b);
|
|
4730
|
+
return sa > sb ? 1 : sa < sb ? -1 : 0;
|
|
4731
|
+
}
|
|
4732
|
+
|
|
4653
4733
|
/** @import { ObjectStore, Store } from '../Store/index.mjs' */
|
|
4734
|
+
/** @import * as Layout from '../Layout/index.mjs' */
|
|
4654
4735
|
|
|
4655
4736
|
/**
|
|
4656
4737
|
*
|
|
@@ -4659,14 +4740,21 @@
|
|
|
4659
4740
|
* @param {ObjectStore} store
|
|
4660
4741
|
* @param {Environment} env
|
|
4661
4742
|
* @param {(next: Node | null, env: any) => () => void} renderItem
|
|
4743
|
+
* @param {Layout.Node.Name | Layout.Node.Calc | Layout.Node.Value} [sort]
|
|
4662
4744
|
*/
|
|
4663
|
-
function renderObject(parent, next, store, env, renderItem) {
|
|
4745
|
+
function renderObject(parent, next, store, env, renderItem, sort) {
|
|
4664
4746
|
/** @type {(() => void)[]} */
|
|
4665
4747
|
const children = [];
|
|
4666
|
-
|
|
4667
|
-
const childStores = [...store].map(([k,v], i) => [k,v,i]);
|
|
4748
|
+
const childStores = [...store];
|
|
4668
4749
|
const count = childStores.length;
|
|
4669
|
-
|
|
4750
|
+
/** @type {[string, Store<any, any>, number][]} */
|
|
4751
|
+
const stores = sort
|
|
4752
|
+
? childStores
|
|
4753
|
+
.map(([k,v]) => [k,v,env.setStore(v, store).exec(sort)])
|
|
4754
|
+
.sort(([,,a], [,,b]) => compare(a, b))
|
|
4755
|
+
.map(([k,v], i) => [k,v,i])
|
|
4756
|
+
: childStores.map(([k,v], i) => [k,v,i]);
|
|
4757
|
+
for (const [key, child, index] of stores) {
|
|
4670
4758
|
children.push(renderItem(next, env.setStore(child, store, {
|
|
4671
4759
|
get count() { return count; },
|
|
4672
4760
|
get key() { return key; },
|
|
@@ -4682,6 +4770,8 @@
|
|
|
4682
4770
|
};
|
|
4683
4771
|
}
|
|
4684
4772
|
|
|
4773
|
+
/** @import * as Layout from '../Layout/index.mjs' */
|
|
4774
|
+
|
|
4685
4775
|
/**
|
|
4686
4776
|
*
|
|
4687
4777
|
* @param {Element} parent
|
|
@@ -4689,24 +4779,38 @@
|
|
|
4689
4779
|
* @param {() => any} getter
|
|
4690
4780
|
* @param {Environment} env
|
|
4691
4781
|
* @param {(next: Node | null, env: any) => () => void} renderItem
|
|
4782
|
+
* @param {Layout.Node.Name | Layout.Node.Calc | Layout.Node.Value} [sort]
|
|
4692
4783
|
*/
|
|
4693
|
-
function renderEnum(parent, next, getter, env, renderItem) {
|
|
4784
|
+
function renderEnum(parent, next, getter, env, renderItem, sort) {
|
|
4694
4785
|
|
|
4695
|
-
/** @type {Signal.Computed<[value: any,
|
|
4786
|
+
/** @type {Signal.Computed<[value: any, kKey: any][]>} */
|
|
4696
4787
|
const list = new exports.Signal.Computed(() => {
|
|
4697
4788
|
const values = getter();
|
|
4698
4789
|
if (typeof values === 'number') {
|
|
4699
4790
|
const n = Math.floor(values);
|
|
4700
4791
|
if (!n) { return []; }
|
|
4701
|
-
return Array(n).fill(0).map((_, i) => [i + 1, i
|
|
4792
|
+
return Array(n).fill(0).map((_, i) => [i + 1, i]);
|
|
4702
4793
|
}
|
|
4703
4794
|
if (!values || typeof values !== 'object') { return []; }
|
|
4704
4795
|
if (Array.isArray(values)) {
|
|
4705
|
-
return values.map((v, i) => [v, i
|
|
4796
|
+
return values.map((v, i) => [v, i]);
|
|
4706
4797
|
}
|
|
4707
4798
|
// TODO: 转列表
|
|
4708
|
-
return Object.entries(values).map(([k,v]
|
|
4799
|
+
return Object.entries(values).map(([k,v]) => [v, k]);
|
|
4709
4800
|
});
|
|
4801
|
+
/** @type {Signal.Computed<[value: any, index: number, kKey: any][]>} */
|
|
4802
|
+
const slotted = sort ? new exports.Signal.Computed(() => {
|
|
4803
|
+
const values = list.get();
|
|
4804
|
+
return values
|
|
4805
|
+
.map(([k,v], i) => [v, k, env.setObject({
|
|
4806
|
+
get count() { return values.length },
|
|
4807
|
+
get key() { return k; },
|
|
4808
|
+
get item() { return v; },
|
|
4809
|
+
get index() { return i; },
|
|
4810
|
+
}).exec(sort)])
|
|
4811
|
+
.sort(([,,a], [,,b]) => compare(a, b))
|
|
4812
|
+
.map(([k, v], i) => [v, i, k]);
|
|
4813
|
+
}) : new exports.Signal.Computed(() => list.get().map(([k,v], i) => [v, i, k]));
|
|
4710
4814
|
const start = parent.insertBefore(document.createComment(''), next);
|
|
4711
4815
|
/** @type {[Comment, Comment, () => void, key: any, Signal.State<any>, Signal.State<any>][]} */
|
|
4712
4816
|
let seMap = [];
|
|
@@ -4719,7 +4823,7 @@
|
|
|
4719
4823
|
}
|
|
4720
4824
|
}
|
|
4721
4825
|
const count = new exports.Signal.State(0);
|
|
4722
|
-
const childrenResult = watch(() =>
|
|
4826
|
+
const childrenResult = watch(() => slotted.get(), function render(children) {
|
|
4723
4827
|
if (!start.parentNode) { return; }
|
|
4724
4828
|
let nextNode = start.nextSibling;
|
|
4725
4829
|
const oldSeMap = seMap;
|
|
@@ -5090,13 +5194,13 @@
|
|
|
5090
5194
|
/** @type {(next: Node | null, env: any) => () => void} */
|
|
5091
5195
|
const r = (next, env) => renderChildren(layout.children, parent, next, env, templates, componentPath, enhancements, relate, getComponent);
|
|
5092
5196
|
if (list instanceof ArrayStore) {
|
|
5093
|
-
return renderArray(parent, next, list, env, r);
|
|
5197
|
+
return renderArray(parent, next, list, env, r, layout.sort);
|
|
5094
5198
|
}
|
|
5095
5199
|
if (list instanceof ObjectStore) {
|
|
5096
|
-
return renderObject(parent, next, list, env, r);
|
|
5200
|
+
return renderObject(parent, next, list, env, r, layout.sort);
|
|
5097
5201
|
}
|
|
5098
5202
|
if (typeof list === 'function') {
|
|
5099
|
-
return renderEnum(parent, next, list, env, r);
|
|
5203
|
+
return renderEnum(parent, next, list, env, r, layout.sort);
|
|
5100
5204
|
}
|
|
5101
5205
|
return () => { };
|
|
5102
5206
|
}
|