@neeloong/form 0.12.1 → 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 +141 -38
- package/index.min.js +5 -5
- package/index.min.mjs +5 -5
- package/index.mjs +141 -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?>} */
|
|
@@ -1597,10 +1605,11 @@
|
|
|
1597
1605
|
* @param {Store?} [options.parent]
|
|
1598
1606
|
* @param {string | number | null} [options.index]
|
|
1599
1607
|
* @param {boolean} [options.new]
|
|
1608
|
+
* @param {boolean} [options.addable]
|
|
1600
1609
|
* @param {(value: any, index: any, store: Store) => void} [options.onUpdate]
|
|
1601
1610
|
* @param {(value: any, index: any, store: Store) => void} [options.onUpdateState]
|
|
1602
1611
|
*/
|
|
1603
|
-
constructor(schema, { parent, onUpdate, onUpdateState, index, new: isNew} = {}) {
|
|
1612
|
+
constructor(schema, { parent, onUpdate, onUpdateState, index, new: isNew, addable} = {}) {
|
|
1604
1613
|
const childrenState = new exports.Signal.State(/** @type {Store[]} */([]));
|
|
1605
1614
|
// @ts-ignore
|
|
1606
1615
|
const updateChildren = (list) => {
|
|
@@ -1636,6 +1645,9 @@
|
|
|
1636
1645
|
},
|
|
1637
1646
|
onUpdateState,
|
|
1638
1647
|
});
|
|
1648
|
+
|
|
1649
|
+
[this.#selfAddable, this.#addable] = createBooleanStates(this, addable, schema.addable ?? true);
|
|
1650
|
+
|
|
1639
1651
|
this.#children = childrenState;
|
|
1640
1652
|
const childCommonOptions = {
|
|
1641
1653
|
parent: this,
|
|
@@ -1666,6 +1678,20 @@
|
|
|
1666
1678
|
return child
|
|
1667
1679
|
};
|
|
1668
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
|
+
|
|
1669
1695
|
/**
|
|
1670
1696
|
*
|
|
1671
1697
|
* @param {number} index
|
|
@@ -1674,6 +1700,7 @@
|
|
|
1674
1700
|
* @returns
|
|
1675
1701
|
*/
|
|
1676
1702
|
insert(index, value = null, isNew) {
|
|
1703
|
+
if (!this.addable) { return false; }
|
|
1677
1704
|
const data = this.value || [];
|
|
1678
1705
|
if (!Array.isArray(data)) { return false; }
|
|
1679
1706
|
const children = [...this.#children.get()];
|
|
@@ -1944,7 +1971,7 @@
|
|
|
1944
1971
|
}
|
|
1945
1972
|
const enumValue = layout.enum;
|
|
1946
1973
|
const name = layout.value;
|
|
1947
|
-
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; }
|
|
1948
1975
|
if (name) { child = { type: 'value', name, vars, children: child ? [child] : [] }; vars = null; }
|
|
1949
1976
|
if (vars?.length) {
|
|
1950
1977
|
child = { type: 'fragment', vars, children: child ? [child] : [] };
|
|
@@ -2138,6 +2165,9 @@
|
|
|
2138
2165
|
case 'enum':
|
|
2139
2166
|
node.enum = value ? parse$1(value, createCalc) : {value: true};
|
|
2140
2167
|
break;
|
|
2168
|
+
case 'sort':
|
|
2169
|
+
node.sort = value ? parse$1(value, createCalc) : {value: true};
|
|
2170
|
+
break;
|
|
2141
2171
|
case 'if':
|
|
2142
2172
|
node.if = parse$1(value, createCalc);
|
|
2143
2173
|
break;
|
|
@@ -2179,6 +2209,7 @@
|
|
|
2179
2209
|
*
|
|
2180
2210
|
* @property {string} [value] 值关联
|
|
2181
2211
|
* @property {Layout.Node.Name | Layout.Node.Calc | Layout.Node.Value} [enum] 列表属性枚举
|
|
2212
|
+
* @property {Layout.Node.Name | Layout.Node.Calc | Layout.Node.Value} [sort]
|
|
2182
2213
|
*
|
|
2183
2214
|
* @property {boolean | string} [bind] 绑定内容
|
|
2184
2215
|
* @property {Layout.Node.Name | Layout.Node.Value | Layout.Node.Calc} [text] 文本渲染
|
|
@@ -2805,6 +2836,7 @@
|
|
|
2805
2836
|
* @property {Record<string, Template>} [templates]
|
|
2806
2837
|
* @property {'enum'} type
|
|
2807
2838
|
* @property {Node.Name | Node.Calc | Node.Value} value
|
|
2839
|
+
* @property {Node.Name | Node.Calc | Node.Value} [sort]
|
|
2808
2840
|
* @property {Child[]} children 子元素
|
|
2809
2841
|
* @property {string} [comment] 注释
|
|
2810
2842
|
*/
|
|
@@ -3004,7 +3036,11 @@
|
|
|
3004
3036
|
yield [`${key}${sign}reset`, {exec: () => val.reset()}];
|
|
3005
3037
|
// @ts-ignore
|
|
3006
3038
|
yield [`${key}${sign}validate`, {exec: v => val.validate(v ? [] : null)}];
|
|
3007
|
-
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}];
|
|
3008
3044
|
yield [`${key}${sign}insert`, {exec: (index, value) => val.insert(index, value)}];
|
|
3009
3045
|
yield [`${key}${sign}add`, {exec: (v) => val.add(v)}];
|
|
3010
3046
|
yield [`${key}${sign}remove`, {exec: (index) => val.remove(index)}];
|
|
@@ -3023,30 +3059,53 @@
|
|
|
3023
3059
|
*/
|
|
3024
3060
|
function *toParentItem(parent, val, key = '', sign = '$') {
|
|
3025
3061
|
if (!(parent instanceof ArrayStore)) {
|
|
3062
|
+
yield [`${key}${sign}removable`, {get: () => false}];
|
|
3026
3063
|
yield [`${key}${sign}upMovable`, {get: () => false}];
|
|
3027
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: () => {}}];
|
|
3028
3068
|
return
|
|
3029
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
|
+
}}];
|
|
3030
3076
|
yield [`${key}${sign}upMovable`, {get: () => {
|
|
3077
|
+
if (parent.readonly) { return false; }
|
|
3078
|
+
if (parent.disabled) { return false; }
|
|
3031
3079
|
const s = val.index;
|
|
3032
3080
|
if (typeof s !== 'number') { return false; }
|
|
3033
3081
|
if (s <= 0) { return false; }
|
|
3034
3082
|
return true;
|
|
3035
3083
|
}}];
|
|
3036
3084
|
yield [`${key}${sign}downMovable`, {get: () => {
|
|
3085
|
+
if (parent.readonly) { return false; }
|
|
3086
|
+
if (parent.disabled) { return false; }
|
|
3037
3087
|
const s = val.index;
|
|
3038
3088
|
if (typeof s !== 'number') { return false; }
|
|
3039
3089
|
if (s >= parent.size - 1) { return false; }
|
|
3040
3090
|
return true;
|
|
3041
3091
|
}}];
|
|
3042
|
-
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
|
+
}}];
|
|
3043
3098
|
yield [`${key}${sign}upMove`, {exec: () => {
|
|
3099
|
+
if (parent.readonly) { return; }
|
|
3100
|
+
if (parent.disabled) { return; }
|
|
3044
3101
|
const s = val.index;
|
|
3045
3102
|
if (typeof s !== 'number') { return; }
|
|
3046
3103
|
if (s <= 0) { return; }
|
|
3047
3104
|
parent.move(s, s - 1);
|
|
3048
3105
|
}}];
|
|
3049
3106
|
yield [`${key}${sign}downMove`, {exec: () => {
|
|
3107
|
+
if (parent.readonly) { return; }
|
|
3108
|
+
if (parent.disabled) { return; }
|
|
3050
3109
|
const s = val.index;
|
|
3051
3110
|
if (typeof s !== 'number') { return; }
|
|
3052
3111
|
if (s >= parent.size - 1) { return; }
|
|
@@ -4525,6 +4584,7 @@
|
|
|
4525
4584
|
return node;
|
|
4526
4585
|
}
|
|
4527
4586
|
|
|
4587
|
+
/** @import * as Layout from '../Layout/index.mjs' */
|
|
4528
4588
|
/** @import Store, { ArrayStore } from '../Store/index.mjs' */
|
|
4529
4589
|
|
|
4530
4590
|
/**
|
|
@@ -4534,8 +4594,9 @@
|
|
|
4534
4594
|
* @param {ArrayStore} store
|
|
4535
4595
|
* @param {Environment} env
|
|
4536
4596
|
* @param {(next: Node | null, env: any) => () => void} renderItem
|
|
4597
|
+
* @param {Layout.Node.Name | Layout.Node.Calc | Layout.Node.Value} [sort]
|
|
4537
4598
|
*/
|
|
4538
|
-
function renderArray(parent, next, store, env, renderItem) {
|
|
4599
|
+
function renderArray(parent, next, store, env, renderItem, sort) {
|
|
4539
4600
|
const start = parent.insertBefore(document.createComment(''), next);
|
|
4540
4601
|
/** @type {Map<Store, [Comment, Comment, () => void]>} */
|
|
4541
4602
|
let seMap = new Map();
|
|
@@ -4651,7 +4712,26 @@
|
|
|
4651
4712
|
};
|
|
4652
4713
|
}
|
|
4653
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
|
+
|
|
4654
4733
|
/** @import { ObjectStore, Store } from '../Store/index.mjs' */
|
|
4734
|
+
/** @import * as Layout from '../Layout/index.mjs' */
|
|
4655
4735
|
|
|
4656
4736
|
/**
|
|
4657
4737
|
*
|
|
@@ -4660,14 +4740,21 @@
|
|
|
4660
4740
|
* @param {ObjectStore} store
|
|
4661
4741
|
* @param {Environment} env
|
|
4662
4742
|
* @param {(next: Node | null, env: any) => () => void} renderItem
|
|
4743
|
+
* @param {Layout.Node.Name | Layout.Node.Calc | Layout.Node.Value} [sort]
|
|
4663
4744
|
*/
|
|
4664
|
-
function renderObject(parent, next, store, env, renderItem) {
|
|
4745
|
+
function renderObject(parent, next, store, env, renderItem, sort) {
|
|
4665
4746
|
/** @type {(() => void)[]} */
|
|
4666
4747
|
const children = [];
|
|
4667
|
-
|
|
4668
|
-
const childStores = [...store].map(([k,v], i) => [k,v,i]);
|
|
4748
|
+
const childStores = [...store];
|
|
4669
4749
|
const count = childStores.length;
|
|
4670
|
-
|
|
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) {
|
|
4671
4758
|
children.push(renderItem(next, env.setStore(child, store, {
|
|
4672
4759
|
get count() { return count; },
|
|
4673
4760
|
get key() { return key; },
|
|
@@ -4683,6 +4770,8 @@
|
|
|
4683
4770
|
};
|
|
4684
4771
|
}
|
|
4685
4772
|
|
|
4773
|
+
/** @import * as Layout from '../Layout/index.mjs' */
|
|
4774
|
+
|
|
4686
4775
|
/**
|
|
4687
4776
|
*
|
|
4688
4777
|
* @param {Element} parent
|
|
@@ -4690,24 +4779,38 @@
|
|
|
4690
4779
|
* @param {() => any} getter
|
|
4691
4780
|
* @param {Environment} env
|
|
4692
4781
|
* @param {(next: Node | null, env: any) => () => void} renderItem
|
|
4782
|
+
* @param {Layout.Node.Name | Layout.Node.Calc | Layout.Node.Value} [sort]
|
|
4693
4783
|
*/
|
|
4694
|
-
function renderEnum(parent, next, getter, env, renderItem) {
|
|
4784
|
+
function renderEnum(parent, next, getter, env, renderItem, sort) {
|
|
4695
4785
|
|
|
4696
|
-
/** @type {Signal.Computed<[value: any,
|
|
4786
|
+
/** @type {Signal.Computed<[value: any, kKey: any][]>} */
|
|
4697
4787
|
const list = new exports.Signal.Computed(() => {
|
|
4698
4788
|
const values = getter();
|
|
4699
4789
|
if (typeof values === 'number') {
|
|
4700
4790
|
const n = Math.floor(values);
|
|
4701
4791
|
if (!n) { return []; }
|
|
4702
|
-
return Array(n).fill(0).map((_, i) => [i + 1, i
|
|
4792
|
+
return Array(n).fill(0).map((_, i) => [i + 1, i]);
|
|
4703
4793
|
}
|
|
4704
4794
|
if (!values || typeof values !== 'object') { return []; }
|
|
4705
4795
|
if (Array.isArray(values)) {
|
|
4706
|
-
return values.map((v, i) => [v, i
|
|
4796
|
+
return values.map((v, i) => [v, i]);
|
|
4707
4797
|
}
|
|
4708
4798
|
// TODO: 转列表
|
|
4709
|
-
return Object.entries(values).map(([k,v]
|
|
4799
|
+
return Object.entries(values).map(([k,v]) => [v, k]);
|
|
4710
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]));
|
|
4711
4814
|
const start = parent.insertBefore(document.createComment(''), next);
|
|
4712
4815
|
/** @type {[Comment, Comment, () => void, key: any, Signal.State<any>, Signal.State<any>][]} */
|
|
4713
4816
|
let seMap = [];
|
|
@@ -4720,7 +4823,7 @@
|
|
|
4720
4823
|
}
|
|
4721
4824
|
}
|
|
4722
4825
|
const count = new exports.Signal.State(0);
|
|
4723
|
-
const childrenResult = watch(() =>
|
|
4826
|
+
const childrenResult = watch(() => slotted.get(), function render(children) {
|
|
4724
4827
|
if (!start.parentNode) { return; }
|
|
4725
4828
|
let nextNode = start.nextSibling;
|
|
4726
4829
|
const oldSeMap = seMap;
|
|
@@ -5091,13 +5194,13 @@
|
|
|
5091
5194
|
/** @type {(next: Node | null, env: any) => () => void} */
|
|
5092
5195
|
const r = (next, env) => renderChildren(layout.children, parent, next, env, templates, componentPath, enhancements, relate, getComponent);
|
|
5093
5196
|
if (list instanceof ArrayStore) {
|
|
5094
|
-
return renderArray(parent, next, list, env, r);
|
|
5197
|
+
return renderArray(parent, next, list, env, r, layout.sort);
|
|
5095
5198
|
}
|
|
5096
5199
|
if (list instanceof ObjectStore) {
|
|
5097
|
-
return renderObject(parent, next, list, env, r);
|
|
5200
|
+
return renderObject(parent, next, list, env, r, layout.sort);
|
|
5098
5201
|
}
|
|
5099
5202
|
if (typeof list === 'function') {
|
|
5100
|
-
return renderEnum(parent, next, list, env, r);
|
|
5203
|
+
return renderEnum(parent, next, list, env, r, layout.sort);
|
|
5101
5204
|
}
|
|
5102
5205
|
return () => { };
|
|
5103
5206
|
}
|