@neeloong/form 0.10.0 → 0.12.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 +15 -13
- package/index.d.mts +228 -82
- package/index.js +546 -423
- package/index.min.js +6 -6
- package/index.min.mjs +6 -6
- package/index.mjs +545 -422
- package/package.json +1 -1
package/index.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/*!
|
|
2
|
-
* @neeloong/form v0.
|
|
2
|
+
* @neeloong/form v0.12.0
|
|
3
3
|
* (c) 2024-2025 Fierflame
|
|
4
4
|
* @license Apache-2.0
|
|
5
5
|
*/
|
|
@@ -73,7 +73,7 @@ function toValueItem(v) {
|
|
|
73
73
|
|
|
74
74
|
}
|
|
75
75
|
/** @param {*} v */
|
|
76
|
-
const values
|
|
76
|
+
const values = v => {
|
|
77
77
|
if (!v || !Array.isArray(v)) { return null;}
|
|
78
78
|
const list = v.map(toValueItem).filter(valueFilter);
|
|
79
79
|
if (!list.length) { return null; }
|
|
@@ -148,7 +148,8 @@ let ArrayStore$1 = null;
|
|
|
148
148
|
/** @type {Record<string, {new(...p: ConstructorParameters<typeof Store>): Store}?>} */
|
|
149
149
|
let TypeStores = Object.create(null);
|
|
150
150
|
/**
|
|
151
|
-
* @
|
|
151
|
+
* @template [M=any]
|
|
152
|
+
* @param {Schema.Field<M>} schema
|
|
152
153
|
* @param {object} [options]
|
|
153
154
|
* @param {Store?} [options.parent]
|
|
154
155
|
* @param {string | number | null} [options.index]
|
|
@@ -285,6 +286,7 @@ function merge(...v) {
|
|
|
285
286
|
/**
|
|
286
287
|
* 管理单个表单字段的状态和行为
|
|
287
288
|
* @template [T=any]
|
|
289
|
+
* @template [M=any]
|
|
288
290
|
*/
|
|
289
291
|
class Store {
|
|
290
292
|
/** @type {Map<string, Set<(value: any, store: any) => void | boolean | null>>} */
|
|
@@ -326,7 +328,8 @@ class Store {
|
|
|
326
328
|
}
|
|
327
329
|
/**
|
|
328
330
|
* 从数据结构模式创建存储
|
|
329
|
-
* @
|
|
331
|
+
* @template [M=any]
|
|
332
|
+
* @param {Schema<M>} schema 数据结构模式
|
|
330
333
|
* @param {object} [options] 选项
|
|
331
334
|
* @param {boolean} [options.new] 是否为新建环境
|
|
332
335
|
*/
|
|
@@ -350,12 +353,12 @@ class Store {
|
|
|
350
353
|
#ref = null;
|
|
351
354
|
get ref() { return this.#ref || createRef(this); }
|
|
352
355
|
/**
|
|
353
|
-
* @param {Schema.Field} schema 字段的 Schema 定义
|
|
356
|
+
* @param {Schema.Field<M>} schema 字段的 Schema 定义
|
|
354
357
|
* @param {object} [options] 可选配置
|
|
355
358
|
* @param {*} [options.parent]
|
|
356
359
|
* @param {*} [options.state]
|
|
357
360
|
* @param {number | string | null} [options.index]
|
|
358
|
-
* @param {number | Signal.State<number> | Signal.Computed<number>} [options.
|
|
361
|
+
* @param {number | Signal.State<number> | Signal.Computed<number>} [options.size]
|
|
359
362
|
* @param {boolean} [options.null]
|
|
360
363
|
* @param {boolean} [options.new]
|
|
361
364
|
* @param {boolean} [options.hidden]
|
|
@@ -390,9 +393,9 @@ class Store {
|
|
|
390
393
|
null: isNull, state, ref,
|
|
391
394
|
setValue, setState, convert, onUpdate, onUpdateState,
|
|
392
395
|
validator, validators,
|
|
393
|
-
index,
|
|
396
|
+
index, size, new: isNew, parent: parentNode,
|
|
394
397
|
hidden, clearable, required, disabled, readonly,
|
|
395
|
-
label, description, placeholder, min, max, step, minLength, maxLength, pattern, values
|
|
398
|
+
label, description, placeholder, min, max, step, minLength, maxLength, pattern, values: values$1
|
|
396
399
|
} = {}) {
|
|
397
400
|
this.schema = schema;
|
|
398
401
|
this.#state.set(typeof state === 'object' && state || {});
|
|
@@ -455,7 +458,7 @@ class Store {
|
|
|
455
458
|
[this.#selfMaxLength, this.#maxLength] = createState(this, number, maxLength, schema.maxLength);
|
|
456
459
|
[this.#selfPattern, this.#pattern] = createState(this, regex, pattern, schema.pattern);
|
|
457
460
|
// @ts-ignore
|
|
458
|
-
[this.#selfValues, this.#values] = createState(this, values
|
|
461
|
+
[this.#selfValues, this.#values] = createState(this, values, values$1, schema.values);
|
|
459
462
|
|
|
460
463
|
const validatorResult = createValidator(this, schema.validator, validator);
|
|
461
464
|
|
|
@@ -470,10 +473,10 @@ class Store {
|
|
|
470
473
|
this.#cancelChange = cancelChange;
|
|
471
474
|
this.#cancelBlur = cancelBlur;
|
|
472
475
|
|
|
473
|
-
if (
|
|
474
|
-
this.#
|
|
476
|
+
if (size instanceof Signal.State || size instanceof Signal.Computed) {
|
|
477
|
+
this.#size = size;
|
|
475
478
|
} else {
|
|
476
|
-
this.#
|
|
479
|
+
this.#size = new Signal.State(size || 0);
|
|
477
480
|
}
|
|
478
481
|
|
|
479
482
|
if (isNull) {
|
|
@@ -511,7 +514,7 @@ class Store {
|
|
|
511
514
|
#root = this;
|
|
512
515
|
/** @readonly @type {any} */
|
|
513
516
|
#type;
|
|
514
|
-
/** @readonly @type {
|
|
517
|
+
/** @readonly @type {M | void} */
|
|
515
518
|
#meta;
|
|
516
519
|
/** @readonly @type {any} */
|
|
517
520
|
#component;
|
|
@@ -529,9 +532,9 @@ class Store {
|
|
|
529
532
|
get component() { return this.#component; }
|
|
530
533
|
|
|
531
534
|
/** @type {Signal.State<number> | Signal.Computed<number>} */
|
|
532
|
-
#
|
|
535
|
+
#size;
|
|
533
536
|
/** 长度信息 */
|
|
534
|
-
get
|
|
537
|
+
get size() { return this.#size.get(); }
|
|
535
538
|
#index = new Signal.State(/** @type {string | number} */(''));
|
|
536
539
|
/** 索引信息 */
|
|
537
540
|
get index() { return this.#index.get(); }
|
|
@@ -713,10 +716,10 @@ class Store {
|
|
|
713
716
|
/** @readonly @type {Signal.Computed<(Schema.Value.Group | Schema.Value)[] | null>} */
|
|
714
717
|
#values
|
|
715
718
|
get selfValues() { return this.#selfValues.get(); }
|
|
716
|
-
set selfValues(v) { this.#selfValues.set(values
|
|
719
|
+
set selfValues(v) { this.#selfValues.set(values(v)); }
|
|
717
720
|
/** 可选值列表 */
|
|
718
721
|
get values() { return this.#values.get(); }
|
|
719
|
-
set values(v) { this.#selfValues.set(values
|
|
722
|
+
set values(v) { this.#selfValues.set(values(v)); }
|
|
720
723
|
|
|
721
724
|
|
|
722
725
|
/** @type {Signal.Computed<string[]>} */
|
|
@@ -918,7 +921,8 @@ class Store {
|
|
|
918
921
|
|
|
919
922
|
/**
|
|
920
923
|
* @template {Record<string, any>} [T=Record<string, any>]
|
|
921
|
-
* @
|
|
924
|
+
* @template [M=any]
|
|
925
|
+
* @extends {Store<T, M>}
|
|
922
926
|
*/
|
|
923
927
|
class ObjectStore extends Store {
|
|
924
928
|
get kind() { return 'object'; }
|
|
@@ -932,7 +936,7 @@ class ObjectStore extends Store {
|
|
|
932
936
|
*/
|
|
933
937
|
child(key) { return this.#children[key] || null; }
|
|
934
938
|
/**
|
|
935
|
-
* @param {Schema.Object & Schema.Attr} schema
|
|
939
|
+
* @param {Schema.Object<M> & Schema.Attr<M>} schema
|
|
936
940
|
* @param {object} [options]
|
|
937
941
|
* @param {Store?} [options.parent]
|
|
938
942
|
* @param {number | string | null} [options.index]
|
|
@@ -944,7 +948,7 @@ class ObjectStore extends Store {
|
|
|
944
948
|
const childrenTypes = Object.entries(schema.type);
|
|
945
949
|
super(schema, {
|
|
946
950
|
parent, index, new: isNew, onUpdate, onUpdateState,
|
|
947
|
-
|
|
951
|
+
size: childrenTypes.length,
|
|
948
952
|
setValue(v) { return typeof v === 'object' ? v : null; },
|
|
949
953
|
setState(v) { return typeof v === 'object' ? v : null; },
|
|
950
954
|
convert(v, state) {
|
|
@@ -985,7 +989,8 @@ setObjectStore(ObjectStore);
|
|
|
985
989
|
|
|
986
990
|
/**
|
|
987
991
|
* @template [T=any]
|
|
988
|
-
* @
|
|
992
|
+
* @template [M=any]
|
|
993
|
+
* @extends {Store<(T | null)[], M>}
|
|
989
994
|
*/
|
|
990
995
|
class ArrayStore extends Store {
|
|
991
996
|
/** @type {(index: number, isNew?: boolean) => Store} */
|
|
@@ -1008,7 +1013,7 @@ class ArrayStore extends Store {
|
|
|
1008
1013
|
}
|
|
1009
1014
|
get kind() { return 'array'; }
|
|
1010
1015
|
/**
|
|
1011
|
-
* @param {Schema.Field} schema
|
|
1016
|
+
* @param {Schema.Field<M>} schema
|
|
1012
1017
|
* @param {object} [options]
|
|
1013
1018
|
* @param {Store?} [options.parent]
|
|
1014
1019
|
* @param {string | number | null} [options.index]
|
|
@@ -1026,6 +1031,7 @@ class ArrayStore extends Store {
|
|
|
1026
1031
|
for (let i = children.length; i < length; i++) {
|
|
1027
1032
|
children.push(this.#create(i));
|
|
1028
1033
|
}
|
|
1034
|
+
children.length = length;
|
|
1029
1035
|
if (oldLength !== length) {
|
|
1030
1036
|
childrenState.set(children);
|
|
1031
1037
|
}
|
|
@@ -1033,7 +1039,7 @@ class ArrayStore extends Store {
|
|
|
1033
1039
|
};
|
|
1034
1040
|
super(schema, {
|
|
1035
1041
|
index, new: isNew, parent,
|
|
1036
|
-
|
|
1042
|
+
size: new Signal.Computed(() => childrenState.get().length),
|
|
1037
1043
|
state: [],
|
|
1038
1044
|
setValue(v) { return Array.isArray(v) ? v : v == null ? null : [v] },
|
|
1039
1045
|
setState(v) { return Array.isArray(v) ? v : v == null ? null : [v] },
|
|
@@ -1223,6 +1229,158 @@ class ArrayStore extends Store {
|
|
|
1223
1229
|
// @ts-ignore
|
|
1224
1230
|
setArrayStore(ArrayStore);
|
|
1225
1231
|
|
|
1232
|
+
/** @import * as Layout from './index.mjs' */
|
|
1233
|
+
|
|
1234
|
+
/** @import { OldNode } from './createElement.mjs' */
|
|
1235
|
+
|
|
1236
|
+
/**
|
|
1237
|
+
* @param {(OldNode | string)[]} [layouts]
|
|
1238
|
+
* @returns {Layout.Child[]}
|
|
1239
|
+
*/
|
|
1240
|
+
function renderList(layouts) {
|
|
1241
|
+
if (!layouts?.length) { return []; }
|
|
1242
|
+
/** @type {Layout.Child[]} */
|
|
1243
|
+
const children = [];
|
|
1244
|
+
/** @type {[Layout.Node.Name | Layout.Node.Calc | Layout.Node.Value | null, OldNode][]} */
|
|
1245
|
+
let ifList = [];
|
|
1246
|
+
/** @type {Record<string, Layout.Template>} */
|
|
1247
|
+
let templates = Object.create(null);
|
|
1248
|
+
let hasTemplate = false;
|
|
1249
|
+
for (const layout of layouts) {
|
|
1250
|
+
if (typeof layout === 'string') { continue; }
|
|
1251
|
+
const name = layout.template;
|
|
1252
|
+
if (!name) { continue; }
|
|
1253
|
+
hasTemplate = true;
|
|
1254
|
+
const children = convertItem(layout);
|
|
1255
|
+
templates[name] = { params: layout.params, children: children ? [children] : [] };
|
|
1256
|
+
}
|
|
1257
|
+
|
|
1258
|
+
/** @param {[Layout.Node.Name | Layout.Node.Calc | Layout.Node.Value | null, OldNode][]} list */
|
|
1259
|
+
function renderIf(list) {
|
|
1260
|
+
if (!list.length) { return; }
|
|
1261
|
+
children.push({
|
|
1262
|
+
type: 'divergent',
|
|
1263
|
+
children: list.map(([a, b]) => {
|
|
1264
|
+
const child = convertItem(b);
|
|
1265
|
+
if (!child) { return [{ children: [] }, a]; }
|
|
1266
|
+
if (typeof child !== 'string' && child.type === 'fragment') {
|
|
1267
|
+
return [child, a];
|
|
1268
|
+
}
|
|
1269
|
+
return [{ children: [child] }, a];
|
|
1270
|
+
}),
|
|
1271
|
+
});
|
|
1272
|
+
}
|
|
1273
|
+
for (const layout of layouts) {
|
|
1274
|
+
if (typeof layout === 'string') {
|
|
1275
|
+
renderIf(ifList);
|
|
1276
|
+
ifList = [];
|
|
1277
|
+
children.push(layout);
|
|
1278
|
+
continue;
|
|
1279
|
+
}
|
|
1280
|
+
if (layout.template) {
|
|
1281
|
+
renderIf(ifList);
|
|
1282
|
+
ifList = [];
|
|
1283
|
+
continue;
|
|
1284
|
+
}
|
|
1285
|
+
if (ifList.length && layout.else) {
|
|
1286
|
+
const ifv = layout.if || null;
|
|
1287
|
+
ifList.push([ifv, layout]);
|
|
1288
|
+
if (!ifv) {
|
|
1289
|
+
renderIf(ifList);
|
|
1290
|
+
ifList = [];
|
|
1291
|
+
}
|
|
1292
|
+
continue;
|
|
1293
|
+
}
|
|
1294
|
+
renderIf(ifList);
|
|
1295
|
+
ifList = [];
|
|
1296
|
+
const ifv = layout.if;
|
|
1297
|
+
if (ifv) {
|
|
1298
|
+
ifList.push([ifv, layout]);
|
|
1299
|
+
continue;
|
|
1300
|
+
}
|
|
1301
|
+
const s = convertItem(layout);
|
|
1302
|
+
if (s)
|
|
1303
|
+
children.push(s);
|
|
1304
|
+
}
|
|
1305
|
+
renderIf(ifList);
|
|
1306
|
+
if (hasTemplate) {
|
|
1307
|
+
return [{ type: 'fragment', templates, children }];
|
|
1308
|
+
}
|
|
1309
|
+
return children;
|
|
1310
|
+
}
|
|
1311
|
+
|
|
1312
|
+
|
|
1313
|
+
/**
|
|
1314
|
+
* @param {OldNode} layout
|
|
1315
|
+
* @returns {Layout.Child | undefined}
|
|
1316
|
+
*/
|
|
1317
|
+
function renderFillDirectives$1({ text, html }) {
|
|
1318
|
+
if (text != null) { return { type: 'content', value: text }; }
|
|
1319
|
+
if (html != null) { return { type: 'content', value: html, html: true }; }
|
|
1320
|
+
}
|
|
1321
|
+
|
|
1322
|
+
/**
|
|
1323
|
+
* @param {OldNode} layout
|
|
1324
|
+
* @returns {Layout.Child?}
|
|
1325
|
+
*/
|
|
1326
|
+
function convertNode(layout) {
|
|
1327
|
+
const fragment = layout.fragment;
|
|
1328
|
+
if (fragment && typeof fragment === 'string') {
|
|
1329
|
+
return { type: 'template', template: fragment, attrs: layout.attrs, children: [] };
|
|
1330
|
+
}
|
|
1331
|
+
const child = renderFillDirectives$1(layout);
|
|
1332
|
+
const children = child ? [child] : renderList(layout.children);
|
|
1333
|
+
if (!layout.name || fragment) { return child || { type: 'fragment', children }; }
|
|
1334
|
+
return {
|
|
1335
|
+
name: layout.name,
|
|
1336
|
+
is: layout.is,
|
|
1337
|
+
attrs: layout.attrs,
|
|
1338
|
+
events: layout.events,
|
|
1339
|
+
classes: layout.classes,
|
|
1340
|
+
styles: layout.styles,
|
|
1341
|
+
enhancements: layout.enhancements,
|
|
1342
|
+
bind: layout.bind,
|
|
1343
|
+
comment: layout.comment,
|
|
1344
|
+
children,
|
|
1345
|
+
};
|
|
1346
|
+
}
|
|
1347
|
+
/**
|
|
1348
|
+
*
|
|
1349
|
+
* @param {OldNode} layout
|
|
1350
|
+
* @returns {Layout.Child?}
|
|
1351
|
+
*/
|
|
1352
|
+
function convertItem(layout) {
|
|
1353
|
+
let child = convertNode(layout);
|
|
1354
|
+
/** @type {Layout.Variable[]?} */
|
|
1355
|
+
let vars = layout.vars;
|
|
1356
|
+
if (vars.length && child && typeof child !== 'string') {
|
|
1357
|
+
if (child.vars) {
|
|
1358
|
+
child.vars = [...vars, ...child.vars];
|
|
1359
|
+
} else if (child) {
|
|
1360
|
+
child.vars = vars;
|
|
1361
|
+
} else {
|
|
1362
|
+
child = { type: 'fragment', vars, children: [] };
|
|
1363
|
+
}
|
|
1364
|
+
vars = null;
|
|
1365
|
+
}
|
|
1366
|
+
const enumValue = layout.enum;
|
|
1367
|
+
const name = layout.value;
|
|
1368
|
+
if (enumValue) { child = { type: 'enum', value: enumValue, vars, children: child ? [child] : [] }; vars = null; }
|
|
1369
|
+
if (name) { child = { type: 'value', name, vars, children: child ? [child] : [] }; vars = null; }
|
|
1370
|
+
if (vars?.length) {
|
|
1371
|
+
child = { type: 'fragment', vars, children: child ? [child] : [] };
|
|
1372
|
+
}
|
|
1373
|
+
return child;
|
|
1374
|
+
}
|
|
1375
|
+
|
|
1376
|
+
/**
|
|
1377
|
+
* @param {(OldNode | string)[]} layouts 布局信息
|
|
1378
|
+
* @returns {Layout.Child[]}
|
|
1379
|
+
*/
|
|
1380
|
+
function convert(layouts) {
|
|
1381
|
+
return renderList(layouts);
|
|
1382
|
+
}
|
|
1383
|
+
|
|
1226
1384
|
const numRegex = /^([+-]?(\d(_?\d)*(\.(\d(_?\d)*)?)?|\.\d(_?\d)*)(?:e[+-]?\d(_?\d)*)|0(b[01](?:_?[01])*|o[0-7](?:_?[0-7])*|x[\dA-F](?:_?[\dA-F])*))$/is;
|
|
1227
1385
|
/**
|
|
1228
1386
|
*
|
|
@@ -1278,6 +1436,7 @@ class ParseError extends Error {
|
|
|
1278
1436
|
}
|
|
1279
1437
|
|
|
1280
1438
|
/** @import * as Layout from './index.mjs' */
|
|
1439
|
+
/** @import { OldNode } from './createElement.mjs' */
|
|
1281
1440
|
|
|
1282
1441
|
const attrPattern = /^(?<decorator>[:@!+*\.?]|style:|样式:)?(?<name>-?[\w\p{Unified_Ideograph}_][-\w\p{Unified_Ideograph}_:\d\.]*)$/u;
|
|
1283
1442
|
const enhancementPattern = /^~(?<enhancement>[\w\p{Unified_Ideograph}_][-\w\p{Unified_Ideograph}_\d\.]*)(?:(?<decorator>[:@!])(?<name>-?[\w\p{Unified_Ideograph}_][-\w\p{Unified_Ideograph}_:\d\.]*))?$/u;
|
|
@@ -1317,14 +1476,14 @@ function parse$1(value, createCalc) {
|
|
|
1317
1476
|
}
|
|
1318
1477
|
|
|
1319
1478
|
/**
|
|
1320
|
-
* @param {
|
|
1479
|
+
* @param {OldNode} node
|
|
1321
1480
|
* @param {Exclude<Layout.Options['createCalc'], undefined>} createCalc
|
|
1322
1481
|
* @param {Exclude<Layout.Options['createInit'], undefined>} createInit
|
|
1323
1482
|
* @param {Exclude<Layout.Options['createEvent'], undefined>} createEvent
|
|
1324
1483
|
* @param {boolean} enableHTML
|
|
1325
1484
|
*/
|
|
1326
1485
|
function createAttributeAdder(node, createCalc, createInit, createEvent, enableHTML) {
|
|
1327
|
-
const { attrs, events, classes, styles, vars,
|
|
1486
|
+
const { attrs, events, classes, styles, vars, params, enhancements } = node;
|
|
1328
1487
|
/**
|
|
1329
1488
|
* @param {string} qName
|
|
1330
1489
|
* @param {string} value
|
|
@@ -1379,11 +1538,11 @@ function createAttributeAdder(node, createCalc, createInit, createEvent, enableH
|
|
|
1379
1538
|
return;
|
|
1380
1539
|
}
|
|
1381
1540
|
if (decorator === '+') {
|
|
1382
|
-
vars
|
|
1541
|
+
vars.push({...value ? parse$1(value, createInit) : {value: undefined}, variable: name, init: true});
|
|
1383
1542
|
return;
|
|
1384
1543
|
}
|
|
1385
1544
|
if (decorator === '*') {
|
|
1386
|
-
|
|
1545
|
+
vars.push({...parse$1(value, createCalc), variable: name, init: false });
|
|
1387
1546
|
return;
|
|
1388
1547
|
}
|
|
1389
1548
|
if (decorator === '?') {
|
|
@@ -1420,10 +1579,40 @@ function createAttributeAdder(node, createCalc, createInit, createEvent, enableH
|
|
|
1420
1579
|
|
|
1421
1580
|
/** @import * as Layout from './index.mjs' */
|
|
1422
1581
|
|
|
1582
|
+
/**
|
|
1583
|
+
* @typedef {object} OldNode 布局节点
|
|
1584
|
+
* @property {string} name 标签名
|
|
1585
|
+
* @property {string?} [is]
|
|
1586
|
+
* @property {string} [id]
|
|
1587
|
+
* @property {Record<string, Layout.Node.Name | Layout.Node.Calc | Layout.Node.Value>} attrs 属性
|
|
1588
|
+
* @property {Record<string, Layout.Node.Name | Layout.Node.Calc | Layout.Node.Value>} params 模板参数定义
|
|
1589
|
+
* @property {Record<string, Layout.Node.Name | Layout.Node.Calc | Layout.Node.Value>} classes 类名
|
|
1590
|
+
* @property {Record<string, Layout.Node.Name | Layout.Node.Calc | Layout.Node.Value>} styles 样式
|
|
1591
|
+
* @property {Record<string, Layout.Node.Name | Layout.Node.Event>} events 事件
|
|
1592
|
+
* @property {Layout.Variable[]} vars 局部变量/别名/计算名
|
|
1593
|
+
* @property {Record<string, Layout.Enhancement>} enhancements 增强
|
|
1594
|
+
*
|
|
1595
|
+
* @property {string} [template] 模板定义的名称
|
|
1596
|
+
* @property {boolean | string} [fragment] 是否为片段或模板调用
|
|
1597
|
+
*
|
|
1598
|
+
* @property {Layout.Node.Name | Layout.Node.Calc | Layout.Node.Value} [if] 分歧条件
|
|
1599
|
+
* @property {boolean} [else] 否定
|
|
1600
|
+
*
|
|
1601
|
+
* @property {string} [value] 值关联
|
|
1602
|
+
* @property {Layout.Node.Name | Layout.Node.Calc | Layout.Node.Value} [enum] 列表属性枚举
|
|
1603
|
+
*
|
|
1604
|
+
* @property {boolean | string} [bind] 绑定内容
|
|
1605
|
+
* @property {Layout.Node.Name | Layout.Node.Value | Layout.Node.Calc} [text] 文本渲染
|
|
1606
|
+
* @property {Layout.Node.Name | Layout.Node.Value | Layout.Node.Calc} [html] HTML 渲染
|
|
1607
|
+
*
|
|
1608
|
+
* @property {string} [comment] 注释
|
|
1609
|
+
*
|
|
1610
|
+
* @property {(OldNode | string)[]} children 子元素
|
|
1611
|
+
*/
|
|
1423
1612
|
/**
|
|
1424
1613
|
* @param {string} name
|
|
1425
1614
|
* @param {string?} [is]
|
|
1426
|
-
* @returns {
|
|
1615
|
+
* @returns {OldNode}
|
|
1427
1616
|
*
|
|
1428
1617
|
*/
|
|
1429
1618
|
function createElement(name, is) {
|
|
@@ -1435,8 +1624,7 @@ function createElement(name, is) {
|
|
|
1435
1624
|
events: Object.create(null),
|
|
1436
1625
|
classes: Object.create(null),
|
|
1437
1626
|
styles: Object.create(null),
|
|
1438
|
-
vars:
|
|
1439
|
-
aliases: Object.create(null),
|
|
1627
|
+
vars: [],
|
|
1440
1628
|
params: Object.create(null),
|
|
1441
1629
|
enhancements: Object.create(null),
|
|
1442
1630
|
};
|
|
@@ -1689,6 +1877,7 @@ var entityMap = {
|
|
|
1689
1877
|
};
|
|
1690
1878
|
|
|
1691
1879
|
/** @import * as Layout from './index.mjs' */
|
|
1880
|
+
/** @import { OldNode } from './createElement.mjs' */
|
|
1692
1881
|
|
|
1693
1882
|
const tagNamePattern = /^(?<name>[\w\p{Unified_Ideograph}_][-\.\|:|d\w\p{Unified_Ideograph}_:]*)(?:|(?<is>[\w\p{Unified_Ideograph}_][-\.\|:|d\w\p{Unified_Ideograph}_]*))?$/u;
|
|
1694
1883
|
|
|
@@ -1754,7 +1943,7 @@ function entityReplacer(a) {
|
|
|
1754
1943
|
* 解析模板内容
|
|
1755
1944
|
* @param {string} source 输入源字符串
|
|
1756
1945
|
* @param {Layout.Options} [options] 解析选项
|
|
1757
|
-
* @returns {
|
|
1946
|
+
* @returns {Layout.Child[]}
|
|
1758
1947
|
*/
|
|
1759
1948
|
function parse(source, {
|
|
1760
1949
|
createCalc = () => { throw new ParseError('CALC'); },
|
|
@@ -1763,15 +1952,15 @@ function parse(source, {
|
|
|
1763
1952
|
simpleTag = new Set,
|
|
1764
1953
|
enableHTML = false,
|
|
1765
1954
|
} = {}) {
|
|
1766
|
-
/** @type {(
|
|
1955
|
+
/** @type {(OldNode | string)[]} */
|
|
1767
1956
|
const children = [];
|
|
1768
1957
|
|
|
1769
1958
|
const doc = { children };
|
|
1770
|
-
/** @type {(
|
|
1959
|
+
/** @type {(OldNode | null)[]} */
|
|
1771
1960
|
const stack = [];
|
|
1772
|
-
/** @type {
|
|
1961
|
+
/** @type {OldNode?} */
|
|
1773
1962
|
let currentNode = null;
|
|
1774
|
-
/** @type {typeof doc |
|
|
1963
|
+
/** @type {typeof doc | OldNode} */
|
|
1775
1964
|
let current = doc;
|
|
1776
1965
|
function endElement() {
|
|
1777
1966
|
currentNode = stack.pop() || null;
|
|
@@ -1947,229 +2136,156 @@ function parse(source, {
|
|
|
1947
2136
|
endElement();
|
|
1948
2137
|
}
|
|
1949
2138
|
}
|
|
1950
|
-
return children;
|
|
2139
|
+
return convert(children);
|
|
1951
2140
|
}
|
|
1952
2141
|
|
|
1953
|
-
/** @import * as Layout from './index.mjs' */
|
|
1954
|
-
|
|
1955
2142
|
/**
|
|
1956
|
-
*
|
|
1957
|
-
* @
|
|
1958
|
-
* @
|
|
2143
|
+
* @typedef {object} Enhancement 增强信息
|
|
2144
|
+
* @property {Record<string, Node.Name | Node.Event>} events 事件
|
|
2145
|
+
* @property {Record<string, Node.Name | Node.Calc | Node.Value>} attrs 属性
|
|
2146
|
+
* @property {Node.Name | Node.Calc | Node.Value} [value] 主值
|
|
2147
|
+
* @property {boolean | string} [bind] 绑定信息
|
|
1959
2148
|
*/
|
|
1960
|
-
function _xmlEncoder(c) {
|
|
1961
|
-
return c == '<' && '<' ||
|
|
1962
|
-
c == '>' && '>' ||
|
|
1963
|
-
c == '&' && '&' ||
|
|
1964
|
-
c == '"' && '"' ||
|
|
1965
|
-
'&#' + c.charCodeAt() + ';';
|
|
1966
|
-
}
|
|
1967
2149
|
|
|
1968
2150
|
/**
|
|
1969
|
-
* @
|
|
2151
|
+
* @typedef {object} Options 解析选项
|
|
2152
|
+
* @property {boolean} [enableHTML] 启用 `!html` 指令
|
|
2153
|
+
* @property {(t: string) => Calc} [createCalc] 创建计算属性的工厂函数
|
|
2154
|
+
* @property {(t: string) => Calc} [createInit] 创建变量初始化的工厂函数
|
|
2155
|
+
* @property {(t: string) => EventListener} [createEvent] 创建事件监听器的工厂函数
|
|
2156
|
+
* @property {Set<string>} [simpleTag] 简单标签的集合
|
|
2157
|
+
*/
|
|
2158
|
+
/**
|
|
2159
|
+
* @template [T=any]
|
|
2160
|
+
* @typedef {{value: T; name?: undefined; calc?: undefined; event?: undefined}} Node.Value 基础值
|
|
1970
2161
|
*/
|
|
1971
|
-
function toValue({name, calc, event, value}) {
|
|
1972
|
-
if (value === true || value === undefined) { return ''; }
|
|
1973
|
-
const val = typeof value === 'string' ? JSON.stringify(value) : name || calc || event || value;
|
|
1974
|
-
return `="${toAttrValue$1(val)}"`;
|
|
1975
|
-
}
|
|
1976
2162
|
/**
|
|
1977
|
-
* @
|
|
2163
|
+
* @typedef {{name: string; value?: undefined; calc?: undefined; event?: undefined}} Node.Name 名称
|
|
2164
|
+
*/
|
|
2165
|
+
/**
|
|
2166
|
+
* @typedef {{event: EventListener; name?: undefined; calc?: undefined; value?: undefined}} Node.Event 事件
|
|
1978
2167
|
*/
|
|
1979
|
-
function toAttrValue$1(value) {
|
|
1980
|
-
return String(value).replace(/[<&"]/g, _xmlEncoder);
|
|
1981
|
-
}
|
|
1982
|
-
|
|
1983
2168
|
/**
|
|
1984
|
-
* @
|
|
1985
|
-
* @param {string} [prefix]
|
|
1986
|
-
* @param {boolean | null} [isName]
|
|
2169
|
+
* @typedef {{calc: Calc; name?: undefined; value?: undefined; event?: undefined}} Node.Calc 计算
|
|
1987
2170
|
*/
|
|
1988
|
-
function *values(values, prefix, isName = false) {
|
|
1989
|
-
if (prefix) {
|
|
1990
|
-
for (const [key, {name, calc, event, value}] of Object.entries(values)) {
|
|
1991
|
-
yield ` ${prefix}${key}`;
|
|
1992
|
-
if (isName && name === key) { continue; }
|
|
1993
|
-
const val = value && typeof value === 'string' ? JSON.stringify(value) : name || calc || event || value;
|
|
1994
|
-
if (val == null) { continue; }
|
|
1995
|
-
if (isName === false && val === true) { continue; }
|
|
1996
|
-
yield `="${toAttrValue$1(val)}"`;
|
|
1997
|
-
}
|
|
1998
|
-
return;
|
|
1999
|
-
}
|
|
2000
|
-
for (const [key, attr] of Object.entries(values)) {
|
|
2001
|
-
if (!attr) { continue; }
|
|
2002
|
-
const {name, value, calc} = attr;
|
|
2003
|
-
if (name === key) { yield ` :${key}`; continue; }
|
|
2004
|
-
if (name || calc || typeof value !== 'string') {
|
|
2005
|
-
yield ` :${key}="${toAttrValue$1(name || calc || value)}"`;
|
|
2006
|
-
continue;
|
|
2007
|
-
}
|
|
2008
|
-
yield ` ${key}`;
|
|
2009
|
-
if (value) {
|
|
2010
|
-
yield `="${toAttrValue$1(value)}"`;
|
|
2011
|
-
}
|
|
2012
|
-
}
|
|
2013
|
-
}
|
|
2014
|
-
|
|
2015
2171
|
|
|
2016
2172
|
/**
|
|
2017
2173
|
*
|
|
2018
|
-
* @
|
|
2019
|
-
* @param {number} [level]
|
|
2020
|
-
* @returns {Iterable<string>}
|
|
2174
|
+
* @typedef {Divergent | Select | Enum | Content | CallTemplate | Fragment | Node | string} Child 分歧
|
|
2021
2175
|
*/
|
|
2022
|
-
function* nodeToString(node, level = 0) {
|
|
2023
|
-
const { children, is, name } = node;
|
|
2024
|
-
const pad = level > 0 ? ''.padEnd(level, '\t') : '';
|
|
2025
|
-
|
|
2026
|
-
yield pad;
|
|
2027
|
-
yield* ['<', name || '-'];
|
|
2028
|
-
if (is) { yield* ['|', is]; }
|
|
2029
|
-
if (node.template) {
|
|
2030
|
-
yield ` !template="${toAttrValue$1(node.template)}"`;
|
|
2031
|
-
yield* values(node.params, '?', null);
|
|
2032
|
-
}
|
|
2033
|
-
if (node.fragment) { yield node.fragment === true ? ` !fragment` : ` !fragment="${toAttrValue$1(node.fragment)}"`; }
|
|
2034
|
-
if (node.else) { yield ` !else`; }
|
|
2035
|
-
if (node.if) { yield ` !if${toValue(node.if)}`; }
|
|
2036
|
-
if (node.value) { yield ` !value="${toAttrValue$1(node.value)}"`; }
|
|
2037
|
-
if (node.enum) { yield ` !enum${toValue(node.enum)}`; }
|
|
2038
|
-
yield* values(node.aliases, '*', null);
|
|
2039
|
-
yield* values(node.vars, '+', null);
|
|
2040
|
-
if (node.bind) { yield node.bind === true ? ` !bind` : ` !bind="${toAttrValue$1(node.bind)}"`; }
|
|
2041
|
-
yield* values(node.attrs);
|
|
2042
|
-
yield* values(node.events, '@', true);
|
|
2043
|
-
yield* values(node.classes, '.', true);
|
|
2044
|
-
yield* values(node.styles, 'style:');
|
|
2045
|
-
for (const [k, en] of Object.entries(node.enhancements)) {
|
|
2046
|
-
if (en.bind) { yield en.bind === true ? ` ~${k}!bind` : ` ~${k}!bind="${toAttrValue$1(en.bind)}"`; }
|
|
2047
|
-
if (en.value) { yield ` ~${k}${toValue(en.value)}`; }
|
|
2048
|
-
yield* values(en.attrs, `~${k}:`, true);
|
|
2049
|
-
yield* values(en.events, `~${k}@`, true);
|
|
2050
|
-
}
|
|
2051
|
-
if (node.text) { yield ` !text${toValue(node.text)}`; }
|
|
2052
|
-
if (node.html) { yield ` !html${toValue(node.html)}`; }
|
|
2053
|
-
if (node.comment) { yield ` !comment="${toAttrValue$1(node.comment)}"`; }
|
|
2054
|
-
if (!children.length) {
|
|
2055
|
-
yield '/>';
|
|
2056
|
-
if (level >= 0) { yield '\n'; }
|
|
2057
|
-
return;
|
|
2058
|
-
}
|
|
2059
|
-
if (children.length === 1) {
|
|
2060
|
-
const [child] = children;
|
|
2061
|
-
if (typeof child === 'string' && child.length < 80 && !child.includes('\n')) {
|
|
2062
|
-
yield '>';
|
|
2063
|
-
yield* [child.replace(/[<&\t]/g, _xmlEncoder).replace(/]]>/g, ']]>')];
|
|
2064
|
-
yield* ['</', name, '>'];
|
|
2065
|
-
if (level >= 0) { yield '\n'; }
|
|
2066
|
-
return;
|
|
2067
|
-
}
|
|
2068
|
-
}
|
|
2069
|
-
yield '>';
|
|
2070
|
-
if (level >= 0) { yield '\n'; }
|
|
2071
|
-
yield* listToString(children, level >= 0 ? level + 1 : -1);
|
|
2072
|
-
yield* [pad, '</', name, '>'];
|
|
2073
|
-
if (level >= 0) { yield '\n'; }
|
|
2074
|
-
|
|
2075
|
-
}
|
|
2076
2176
|
/**
|
|
2077
2177
|
*
|
|
2078
|
-
* @
|
|
2079
|
-
* @
|
|
2080
|
-
* @
|
|
2178
|
+
* @template [T=unknown]
|
|
2179
|
+
* @typedef {object} Variable 变量定义
|
|
2180
|
+
* @property {string} variable
|
|
2181
|
+
* @property {string} [name]
|
|
2182
|
+
* @property {Calc} [calc]
|
|
2183
|
+
* @property {T} [value]
|
|
2184
|
+
* @property {boolean} [init] 是否普通变量
|
|
2185
|
+
* @property {string} [comment] 注释
|
|
2081
2186
|
*/
|
|
2082
|
-
function* listToString(nodes, level = 0) {
|
|
2083
|
-
if (!nodes.length) { return ''; }
|
|
2084
|
-
|
|
2085
|
-
const pad = level > 0 ? ''.padEnd(level, '\t') : '';
|
|
2086
|
-
for (const child of nodes) {
|
|
2087
|
-
if (typeof child === 'string') {
|
|
2088
|
-
let text = child.replace(/[<&\t]/g, _xmlEncoder).replace(/]]>/g, ']]>');
|
|
2089
|
-
if (pad) {
|
|
2090
|
-
text = text.replace(/(?<=^|\n)/g, pad);
|
|
2091
|
-
}
|
|
2092
|
-
yield text;
|
|
2093
|
-
if (level >= 0) { yield '\n'; }
|
|
2094
|
-
} else {
|
|
2095
|
-
yield* nodeToString(child, level);
|
|
2096
|
-
}
|
|
2097
|
-
}
|
|
2098
|
-
}
|
|
2099
2187
|
/**
|
|
2100
|
-
*
|
|
2101
|
-
* @
|
|
2102
|
-
* @
|
|
2103
|
-
* @
|
|
2188
|
+
* @typedef {object} Template
|
|
2189
|
+
* @property {Variable[]?} [vars] 局部变量/别名/计算名
|
|
2190
|
+
* @property {Record<string, Template>} [templates]
|
|
2191
|
+
* @property {Record<string, Node.Name | Node.Calc | Node.Value>} params 模板参数定义
|
|
2192
|
+
* @property {Child[]} children 子元素
|
|
2193
|
+
* @property {string} [comment] 注释
|
|
2104
2194
|
*/
|
|
2105
|
-
function stringify(value, formable) {
|
|
2106
|
-
const level = formable ? 0 : -1;
|
|
2107
|
-
if (Array.isArray(value)) { return [...listToString(value, level)].join(''); }
|
|
2108
|
-
return [nodeToString(value, level)].join();
|
|
2109
|
-
|
|
2110
|
-
}
|
|
2111
|
-
|
|
2112
2195
|
/**
|
|
2113
|
-
*
|
|
2114
|
-
* @
|
|
2115
|
-
* @property {
|
|
2116
|
-
* @property {
|
|
2117
|
-
* @property {
|
|
2196
|
+
*
|
|
2197
|
+
* @typedef {object} DivergentChildren 分歧项
|
|
2198
|
+
* @property {Variable[]?} [vars] 局部变量/别名/计算名
|
|
2199
|
+
* @property {Record<string, Template>} [templates]
|
|
2200
|
+
* @property {Child[]} children 子元素
|
|
2201
|
+
* @property {string} [comment] 注释
|
|
2118
2202
|
*/
|
|
2119
|
-
|
|
2120
2203
|
/**
|
|
2121
|
-
*
|
|
2122
|
-
* @
|
|
2123
|
-
* @property {
|
|
2124
|
-
* @property {
|
|
2125
|
-
* @property {
|
|
2126
|
-
* @property {
|
|
2204
|
+
*
|
|
2205
|
+
* @typedef {object} Divergent 分歧
|
|
2206
|
+
* @property {Variable[]?} [vars] 局部变量/别名/计算名
|
|
2207
|
+
* @property {Record<string, Template>} [templates]
|
|
2208
|
+
* @property {'divergent'} type
|
|
2209
|
+
* @property {[children: DivergentChildren, condition?: Node.Name | Node.Calc | Node.Value | null][]} children
|
|
2210
|
+
* @property {string} [comment] 注释
|
|
2127
2211
|
*/
|
|
2128
2212
|
/**
|
|
2129
|
-
*
|
|
2130
|
-
* @typedef {
|
|
2213
|
+
*
|
|
2214
|
+
* @typedef {object} Select 选值
|
|
2215
|
+
* @property {Variable[]?} [vars] 局部变量/别名/计算名
|
|
2216
|
+
* @property {Record<string, Template>} [templates]
|
|
2217
|
+
* @property {'value'} type
|
|
2218
|
+
* @property {string} name
|
|
2219
|
+
* @property {Child[]} children 子元素
|
|
2220
|
+
* @property {string} [comment] 注释
|
|
2131
2221
|
*/
|
|
2132
2222
|
/**
|
|
2133
|
-
*
|
|
2223
|
+
*
|
|
2224
|
+
* @typedef {object} Enum 枚举
|
|
2225
|
+
* @property {Variable[]?} [vars] 局部变量/别名/计算名
|
|
2226
|
+
* @property {Record<string, Template>} [templates]
|
|
2227
|
+
* @property {'enum'} type
|
|
2228
|
+
* @property {Node.Name | Node.Calc | Node.Value} value
|
|
2229
|
+
* @property {Child[]} children 子元素
|
|
2230
|
+
* @property {string} [comment] 注释
|
|
2134
2231
|
*/
|
|
2135
2232
|
/**
|
|
2136
|
-
*
|
|
2233
|
+
*
|
|
2234
|
+
* @typedef {object} Content 内容填充
|
|
2235
|
+
* @property {Variable[]?} [vars] 局部变量/别名/计算名
|
|
2236
|
+
* @property {Record<string, Template>} [templates]
|
|
2237
|
+
* @property {'content'} type
|
|
2238
|
+
* @property {Node.Name | Node.Calc | Node.Value} value
|
|
2239
|
+
* @property {boolean} [html]
|
|
2240
|
+
* @property {string} [comment] 注释
|
|
2137
2241
|
*/
|
|
2138
2242
|
/**
|
|
2139
|
-
*
|
|
2243
|
+
*
|
|
2244
|
+
* @typedef {object} CallTemplate 模板调用
|
|
2245
|
+
* @property {Variable[]?} [vars] 局部变量/别名/计算名
|
|
2246
|
+
* @property {Record<string, Template>} [templates]
|
|
2247
|
+
* @property {'template'} type
|
|
2248
|
+
* @property {string} template 模板名
|
|
2249
|
+
* @property {Record<string, Node.Name | Node.Calc | Node.Value>} attrs 属性
|
|
2250
|
+
* @property {boolean | string} [bind] 绑定内容
|
|
2251
|
+
* @property {Child[]} children 子元素
|
|
2252
|
+
* @property {string} [comment] 注释
|
|
2253
|
+
*/
|
|
2254
|
+
|
|
2255
|
+
/**
|
|
2256
|
+
* @typedef {object} Fragment 片段
|
|
2257
|
+
* @property {Variable[]?} [vars] 局部变量/别名/计算名
|
|
2258
|
+
* @property {Record<string, Template>} [templates]
|
|
2259
|
+
* @property {'fragment'} type
|
|
2260
|
+
* @property {Child[]} children 子元素
|
|
2261
|
+
* @property {string} [comment] 注释
|
|
2140
2262
|
*/
|
|
2263
|
+
|
|
2264
|
+
|
|
2141
2265
|
/**
|
|
2142
2266
|
* @typedef {object} Node 布局节点
|
|
2267
|
+
* @property {Variable[]?} [vars] 局部变量/别名/计算名
|
|
2268
|
+
* @property {Record<string, Template>} [templates]
|
|
2269
|
+
* @property {null} [type]
|
|
2270
|
+
*
|
|
2143
2271
|
* @property {string} name 标签名
|
|
2144
2272
|
* @property {string?} [is]
|
|
2145
2273
|
* @property {string} [id]
|
|
2146
2274
|
* @property {Record<string, Node.Name | Node.Calc | Node.Value>} attrs 属性
|
|
2147
|
-
* @property {Record<string, Node.Name | Node.Calc | Node.Value>} params 模板参数定义
|
|
2148
2275
|
* @property {Record<string, Node.Name | Node.Calc | Node.Value>} classes 类名
|
|
2149
2276
|
* @property {Record<string, Node.Name | Node.Calc | Node.Value>} styles 样式
|
|
2150
2277
|
* @property {Record<string, Node.Name | Node.Event>} events 事件
|
|
2151
|
-
* @property {Record<string, Node.Name | Node.Calc | Node.Value>} vars 局部变量
|
|
2152
|
-
* @property {Record<string, Node.Name | Node.Calc | Node.Value>} aliases 别名/计算名
|
|
2153
2278
|
* @property {Record<string, Enhancement>} enhancements 增强
|
|
2154
2279
|
*
|
|
2155
|
-
* @property {string} [template] 模板定义的名称
|
|
2156
|
-
* @property {boolean | string} [fragment] 是否为片段或模板调用
|
|
2157
|
-
*
|
|
2158
|
-
* @property {Node.Name | Node.Calc | Node.Value} [if] 分歧条件
|
|
2159
|
-
* @property {boolean} [else] 否定
|
|
2160
|
-
*
|
|
2161
|
-
* @property {string} [value] 值关联
|
|
2162
|
-
* @property {Node.Name | Node.Calc | Node.Value} [enum] 列表属性枚举
|
|
2163
2280
|
*
|
|
2164
2281
|
* @property {boolean | string} [bind] 绑定内容
|
|
2165
|
-
* @property {Node.Name | Node.Value | Node.Calc} [text] 文本渲染
|
|
2166
|
-
* @property {Node.Name | Node.Value | Node.Calc} [html] HTML 渲染
|
|
2167
2282
|
*
|
|
2168
2283
|
* @property {string} [comment] 注释
|
|
2169
2284
|
*
|
|
2170
|
-
* @property {
|
|
2285
|
+
* @property {Child[]} children 子元素
|
|
2171
2286
|
*/
|
|
2172
2287
|
|
|
2288
|
+
|
|
2173
2289
|
/**
|
|
2174
2290
|
* @callback Calc 计算函数
|
|
2175
2291
|
* @param {Record<string, any>} env 上下文环境
|
|
@@ -2184,10 +2300,9 @@ function stringify(value, formable) {
|
|
|
2184
2300
|
* @returns {void}
|
|
2185
2301
|
*/
|
|
2186
2302
|
|
|
2187
|
-
var index
|
|
2303
|
+
var index = /*#__PURE__*/Object.freeze({
|
|
2188
2304
|
__proto__: null,
|
|
2189
|
-
parse: parse
|
|
2190
|
-
stringify: stringify
|
|
2305
|
+
parse: parse
|
|
2191
2306
|
});
|
|
2192
2307
|
|
|
2193
2308
|
/**
|
|
@@ -2283,7 +2398,7 @@ const bindable = {
|
|
|
2283
2398
|
null: true,
|
|
2284
2399
|
index: true,
|
|
2285
2400
|
no: true,
|
|
2286
|
-
|
|
2401
|
+
size: true,
|
|
2287
2402
|
|
|
2288
2403
|
error: true,
|
|
2289
2404
|
errors: true,
|
|
@@ -2342,7 +2457,7 @@ function *toParentItem(parent, val, key = '', sign = '$') {
|
|
|
2342
2457
|
yield [`${key}${sign}downMovable`, {get: () => {
|
|
2343
2458
|
const s = val.index;
|
|
2344
2459
|
if (typeof s !== 'number') { return false; }
|
|
2345
|
-
if (s >= parent.
|
|
2460
|
+
if (s >= parent.size - 1) { return false; }
|
|
2346
2461
|
return true;
|
|
2347
2462
|
}}];
|
|
2348
2463
|
yield [`${key}${sign}remove`, {exec: () => parent.remove(Number(val.index))}];
|
|
@@ -2355,7 +2470,7 @@ function *toParentItem(parent, val, key = '', sign = '$') {
|
|
|
2355
2470
|
yield [`${key}${sign}downMove`, {exec: () => {
|
|
2356
2471
|
const s = val.index;
|
|
2357
2472
|
if (typeof s !== 'number') { return; }
|
|
2358
|
-
if (s >= parent.
|
|
2473
|
+
if (s >= parent.size - 1) { return; }
|
|
2359
2474
|
parent.move(s, s + 1);
|
|
2360
2475
|
}}];
|
|
2361
2476
|
}
|
|
@@ -2507,10 +2622,9 @@ class Environment {
|
|
|
2507
2622
|
watch(value, cb) { return watch(() => this.exec(value), cb, true); }
|
|
2508
2623
|
|
|
2509
2624
|
/**
|
|
2510
|
-
* @param {Layout.Node.Name | Layout.Node.Calc | Layout.Node.Value
|
|
2625
|
+
* @param {Layout.Node.Name | Layout.Node.Calc | Layout.Node.Value} en
|
|
2511
2626
|
*/
|
|
2512
2627
|
enum(en) {
|
|
2513
|
-
if (!en) { return true; }
|
|
2514
2628
|
const {name, calc} = en;
|
|
2515
2629
|
if (typeof calc === 'function') { return () => calc(this.getters); }
|
|
2516
2630
|
if (typeof name === 'string') {
|
|
@@ -2696,17 +2810,16 @@ class Environment {
|
|
|
2696
2810
|
const store = this.store;
|
|
2697
2811
|
const parent = this.#parent;
|
|
2698
2812
|
const object = this.#object;
|
|
2813
|
+
for (const [key, item] of toItem(store)) {
|
|
2814
|
+
ais[key] = item;
|
|
2815
|
+
}
|
|
2816
|
+
for (const [key, item] of toParentItem(parent, store)) {
|
|
2817
|
+
ais[key] = item;
|
|
2818
|
+
}
|
|
2699
2819
|
if (object) {
|
|
2700
2820
|
for (const k of Object.keys(object)) {
|
|
2701
2821
|
ais[`$${k}`] = {get: () => object[k]};
|
|
2702
2822
|
}
|
|
2703
|
-
} else {
|
|
2704
|
-
for (const [key, item] of toItem(store)) {
|
|
2705
|
-
ais[key] = item;
|
|
2706
|
-
}
|
|
2707
|
-
for (const [key, item] of toParentItem(parent, store)) {
|
|
2708
|
-
ais[key] = item;
|
|
2709
|
-
}
|
|
2710
2823
|
}
|
|
2711
2824
|
this.#allItems = ais;
|
|
2712
2825
|
return ais;
|
|
@@ -2715,11 +2828,13 @@ class Environment {
|
|
|
2715
2828
|
*
|
|
2716
2829
|
* @param {Store} store
|
|
2717
2830
|
* @param {Store} parent
|
|
2831
|
+
* @param {Record<string, any>} [object]
|
|
2718
2832
|
*/
|
|
2719
|
-
setStore(store, parent) {
|
|
2833
|
+
setStore(store, parent, object) {
|
|
2720
2834
|
const cloned = new Environment(store, this);
|
|
2721
2835
|
if (parent) { cloned.#parent = parent; }
|
|
2722
2836
|
setStore(cloned.#schemaItems, store);
|
|
2837
|
+
if (object) { cloned.#object = object; }
|
|
2723
2838
|
return cloned;
|
|
2724
2839
|
}
|
|
2725
2840
|
/**
|
|
@@ -2736,12 +2851,12 @@ class Environment {
|
|
|
2736
2851
|
}
|
|
2737
2852
|
/**
|
|
2738
2853
|
*
|
|
2739
|
-
* @param {Layout.Node}
|
|
2740
|
-
* @param {Layout.Node}
|
|
2854
|
+
* @param {Record<string, Layout.Node.Name | Layout.Node.Calc | Layout.Node.Value<any>>} params
|
|
2855
|
+
* @param {Record<string, Layout.Node.Name | Layout.Node.Calc | Layout.Node.Value<any>>} attrs
|
|
2741
2856
|
* @param {Environment} sourceEnv
|
|
2742
2857
|
* @param {string | null | boolean} [bind]
|
|
2743
2858
|
*/
|
|
2744
|
-
params(
|
|
2859
|
+
params(params, attrs, sourceEnv, bind) {
|
|
2745
2860
|
/** @type {Store} */
|
|
2746
2861
|
let store = this.store;
|
|
2747
2862
|
if (bind === true) {
|
|
@@ -2820,22 +2935,39 @@ class Environment {
|
|
|
2820
2935
|
}
|
|
2821
2936
|
/**
|
|
2822
2937
|
*
|
|
2823
|
-
* @param {
|
|
2824
|
-
* @
|
|
2938
|
+
* @param {Layout.Variable[]?} [vars]
|
|
2939
|
+
* @returns
|
|
2825
2940
|
*/
|
|
2826
|
-
set(
|
|
2827
|
-
if (
|
|
2941
|
+
set(vars) {
|
|
2942
|
+
if (!vars?.length) { return this; }
|
|
2828
2943
|
const cloned = new Environment(this.store, this);
|
|
2829
2944
|
cloned.#parent = this.#parent;
|
|
2830
2945
|
cloned.#object = this.#object;
|
|
2831
2946
|
const explicit = cloned.#explicit;
|
|
2832
2947
|
const items = cloned.#items;
|
|
2833
|
-
for (const
|
|
2948
|
+
for (const { variable, name, calc, value, init } of vars) {
|
|
2949
|
+
if (init) {
|
|
2950
|
+
const val = new Signal.State(/** @type {any} */(value));
|
|
2951
|
+
if (typeof calc === 'function') {
|
|
2952
|
+
const settable = cloned.settable;
|
|
2953
|
+
cloned.#settable = null;
|
|
2954
|
+
val.set(calc(settable));
|
|
2955
|
+
} else if (name) {
|
|
2956
|
+
const item = items[name];
|
|
2957
|
+
if (!item?.get) { continue; }
|
|
2958
|
+
val.set(item.get());
|
|
2959
|
+
}
|
|
2960
|
+
explicit[variable] = items[variable] = {
|
|
2961
|
+
get: () => { return val.get(); },
|
|
2962
|
+
set: (v) => { val.set(v); },
|
|
2963
|
+
};
|
|
2964
|
+
continue;
|
|
2965
|
+
}
|
|
2834
2966
|
if (typeof calc === 'function') {
|
|
2835
2967
|
const getters = cloned.getters;
|
|
2836
2968
|
cloned.#getters = null;
|
|
2837
2969
|
const val = new Signal.Computed(() => calc(getters));
|
|
2838
|
-
explicit[
|
|
2970
|
+
explicit[variable] = items[variable] = {
|
|
2839
2971
|
get: () => { return val.get(); },
|
|
2840
2972
|
};
|
|
2841
2973
|
continue;
|
|
@@ -2844,34 +2976,17 @@ class Environment {
|
|
|
2844
2976
|
const item = items[name];
|
|
2845
2977
|
if (!item) { continue; }
|
|
2846
2978
|
if (!item.get || !item.store) {
|
|
2847
|
-
explicit[
|
|
2979
|
+
explicit[variable] = items[variable] = item;
|
|
2848
2980
|
continue;
|
|
2849
2981
|
}
|
|
2850
|
-
for (const [k, it] of toItem(item.store,
|
|
2982
|
+
for (const [k, it] of toItem(item.store, variable)) {
|
|
2851
2983
|
explicit[k] = items[k] = it;
|
|
2852
2984
|
}
|
|
2853
2985
|
continue;
|
|
2854
2986
|
}
|
|
2855
|
-
explicit[
|
|
2987
|
+
explicit[variable] = items[variable] = { get: () => { return value; } };
|
|
2856
2988
|
continue;
|
|
2857
2989
|
}
|
|
2858
|
-
for (const [k,{name, calc, value}] of Object.entries(vars)) {
|
|
2859
|
-
|
|
2860
|
-
const val = new Signal.State(/** @type {any} */(value));
|
|
2861
|
-
if (typeof calc === 'function') {
|
|
2862
|
-
const settable = cloned.settable;
|
|
2863
|
-
cloned.#settable = null;
|
|
2864
|
-
val.set(calc(settable));
|
|
2865
|
-
} else if (name) {
|
|
2866
|
-
const item = items[name];
|
|
2867
|
-
if (!item?.get) { continue }
|
|
2868
|
-
val.set(item.get());
|
|
2869
|
-
}
|
|
2870
|
-
explicit[k] = items[k] = {
|
|
2871
|
-
get: () => { return val.get(); },
|
|
2872
|
-
set: (v) => { val.set(v); },
|
|
2873
|
-
};
|
|
2874
|
-
}
|
|
2875
2990
|
return cloned;
|
|
2876
2991
|
}
|
|
2877
2992
|
|
|
@@ -3854,17 +3969,24 @@ function renderArray(parent, next, store, env, renderItem) {
|
|
|
3854
3969
|
}
|
|
3855
3970
|
|
|
3856
3971
|
}
|
|
3972
|
+
const count = new Signal.State(0);
|
|
3857
3973
|
const childrenResult = watch(() => store.children, function render(children) {
|
|
3858
3974
|
if (!start.parentNode) { return; }
|
|
3859
3975
|
let nextNode = start.nextSibling;
|
|
3860
3976
|
const oldSeMap = seMap;
|
|
3861
3977
|
seMap = new Map();
|
|
3978
|
+
count.set(children.length);
|
|
3862
3979
|
for (let child of children) {
|
|
3863
3980
|
const old = oldSeMap.get(child);
|
|
3864
3981
|
if (!old) {
|
|
3865
3982
|
const ItemStart = parent.insertBefore(document.createComment(''), nextNode);
|
|
3866
3983
|
const itemEnd = parent.insertBefore(document.createComment(''), nextNode);
|
|
3867
|
-
const d = renderItem(itemEnd, env.setStore(child, store
|
|
3984
|
+
const d = renderItem(itemEnd, env.setStore(child, store, {
|
|
3985
|
+
get count() { return count.get() },
|
|
3986
|
+
get key() { return child.index; },
|
|
3987
|
+
get index() { return child.index; },
|
|
3988
|
+
get item() { return child.value; },
|
|
3989
|
+
}));
|
|
3868
3990
|
seMap.set(child, [ItemStart, itemEnd, d]);
|
|
3869
3991
|
continue;
|
|
3870
3992
|
}
|
|
@@ -3911,18 +4033,18 @@ function toText(val) {
|
|
|
3911
4033
|
* @param {Element} parent
|
|
3912
4034
|
* @param {Node?} next
|
|
3913
4035
|
* @param {Environment} envs
|
|
3914
|
-
* @param {Layout.Node}
|
|
4036
|
+
* @param {Layout.Node.Name | Layout.Node.Calc | Layout.Node.Value} value
|
|
4037
|
+
* @param {boolean} [isHtml]
|
|
3915
4038
|
*/
|
|
3916
|
-
function renderFillDirectives(parent, next, envs,
|
|
3917
|
-
if (
|
|
4039
|
+
function renderFillDirectives(parent, next, envs, value, isHtml) {
|
|
4040
|
+
if (!isHtml) {
|
|
3918
4041
|
const node = parent.insertBefore(document.createTextNode(''), next);
|
|
3919
|
-
const stop = envs.watch(
|
|
4042
|
+
const stop = envs.watch(value, val => node.textContent = toText(val));
|
|
3920
4043
|
return () => {
|
|
3921
4044
|
node.remove();
|
|
3922
4045
|
stop();
|
|
3923
4046
|
};
|
|
3924
4047
|
}
|
|
3925
|
-
if (html == null) { return; }
|
|
3926
4048
|
const start = parent.insertBefore(document.createComment(''), next);
|
|
3927
4049
|
const end = parent.insertBefore(document.createComment(''), next);
|
|
3928
4050
|
const div = document.createElement('div');
|
|
@@ -3938,7 +4060,7 @@ function renderFillDirectives(parent, next, envs, { text, html }) {
|
|
|
3938
4060
|
node.remove();
|
|
3939
4061
|
}
|
|
3940
4062
|
}
|
|
3941
|
-
const result = envs.watch(
|
|
4063
|
+
const result = envs.watch(value, val => {
|
|
3942
4064
|
remove();
|
|
3943
4065
|
add(toText(val));
|
|
3944
4066
|
});
|
|
@@ -3950,113 +4072,7 @@ function renderFillDirectives(parent, next, envs, { text, html }) {
|
|
|
3950
4072
|
};
|
|
3951
4073
|
}
|
|
3952
4074
|
|
|
3953
|
-
/** @import
|
|
3954
|
-
|
|
3955
|
-
/**
|
|
3956
|
-
* @param {(Layout.Node | string)[]} layouts
|
|
3957
|
-
* @param {Element} parent
|
|
3958
|
-
* @param {Node?} next
|
|
3959
|
-
* @param {Environment} envs
|
|
3960
|
-
* @param {Record<string, [Layout.Node, Environment]>} templates
|
|
3961
|
-
* @param {(layout: Layout.Node, templates: Record<string, any>) => () => void} renderItem
|
|
3962
|
-
* @returns {() => void}
|
|
3963
|
-
*/
|
|
3964
|
-
function renderList(layouts, parent, next, envs, templates, renderItem) {
|
|
3965
|
-
|
|
3966
|
-
/** @type {Set<() => void>?} */
|
|
3967
|
-
let bkList = new Set();
|
|
3968
|
-
/** @type {[Layout.Node.Name | Layout.Node.Calc | Layout.Node.Value | null, Layout.Node][]} */
|
|
3969
|
-
let ifList = [];
|
|
3970
|
-
/** @type {Record<string, [Layout.Node, Environment]>} */
|
|
3971
|
-
let currentTemplates = Object.create(templates);
|
|
3972
|
-
for (const layout of layouts) {
|
|
3973
|
-
if (typeof layout === 'string') { continue; }
|
|
3974
|
-
const name = layout.template;
|
|
3975
|
-
if (!name) { continue; }
|
|
3976
|
-
currentTemplates[name] = [layout, envs];
|
|
3977
|
-
}
|
|
3978
|
-
|
|
3979
|
-
/** @param {[Layout.Node.Name | Layout.Node.Calc | Layout.Node.Value | null, Layout.Node][]} list */
|
|
3980
|
-
function renderIf(list) {
|
|
3981
|
-
if (!list.length || !bkList) { return; }
|
|
3982
|
-
const end = parent.insertBefore(document.createComment(''), next);
|
|
3983
|
-
|
|
3984
|
-
|
|
3985
|
-
let lastIndex = -1;
|
|
3986
|
-
let destroy = () => { };
|
|
3987
|
-
/**
|
|
3988
|
-
*
|
|
3989
|
-
* @param {number} index
|
|
3990
|
-
* @returns
|
|
3991
|
-
*/
|
|
3992
|
-
function renderIndex(index) {
|
|
3993
|
-
const layout = list[index]?.[1];
|
|
3994
|
-
if (!layout) { return; }
|
|
3995
|
-
destroy = renderItem(layout, currentTemplates);
|
|
3996
|
-
}
|
|
3997
|
-
bkList.add(() => {
|
|
3998
|
-
destroy();
|
|
3999
|
-
destroy = () => { };
|
|
4000
|
-
end.remove();
|
|
4001
|
-
});
|
|
4002
|
-
bkList.add(watch(
|
|
4003
|
-
() => list.findIndex(([ifv]) => !ifv || envs.exec(ifv)),
|
|
4004
|
-
index => {
|
|
4005
|
-
if (index === lastIndex) { return; }
|
|
4006
|
-
lastIndex = index;
|
|
4007
|
-
destroy();
|
|
4008
|
-
destroy = () => { };
|
|
4009
|
-
renderIndex(lastIndex);
|
|
4010
|
-
}, true,
|
|
4011
|
-
));
|
|
4012
|
-
}
|
|
4013
|
-
for (const layout of layouts) {
|
|
4014
|
-
if (typeof layout === 'string') {
|
|
4015
|
-
renderIf(ifList);
|
|
4016
|
-
ifList = [];
|
|
4017
|
-
const node = document.createTextNode(layout);
|
|
4018
|
-
parent.insertBefore(node, next);
|
|
4019
|
-
bkList.add(() => node.remove());
|
|
4020
|
-
continue;
|
|
4021
|
-
}
|
|
4022
|
-
if (layout.template) {
|
|
4023
|
-
renderIf(ifList);
|
|
4024
|
-
ifList = [];
|
|
4025
|
-
continue;
|
|
4026
|
-
}
|
|
4027
|
-
if (ifList.length && layout.else) {
|
|
4028
|
-
const ifv = layout.if || null;
|
|
4029
|
-
ifList.push([ifv, layout]);
|
|
4030
|
-
if (!ifv) {
|
|
4031
|
-
renderIf(ifList);
|
|
4032
|
-
ifList = [];
|
|
4033
|
-
}
|
|
4034
|
-
continue;
|
|
4035
|
-
}
|
|
4036
|
-
renderIf(ifList);
|
|
4037
|
-
ifList = [];
|
|
4038
|
-
const ifv = layout.if;
|
|
4039
|
-
if (ifv) {
|
|
4040
|
-
ifList.push([ifv, layout]);
|
|
4041
|
-
continue;
|
|
4042
|
-
}
|
|
4043
|
-
bkList.add(
|
|
4044
|
-
renderItem(layout, currentTemplates)
|
|
4045
|
-
);
|
|
4046
|
-
}
|
|
4047
|
-
renderIf(ifList);
|
|
4048
|
-
|
|
4049
|
-
return () => {
|
|
4050
|
-
if (!bkList) { return; }
|
|
4051
|
-
const list = bkList;
|
|
4052
|
-
bkList = null;
|
|
4053
|
-
for (const s of list) {
|
|
4054
|
-
s();
|
|
4055
|
-
}
|
|
4056
|
-
};
|
|
4057
|
-
}
|
|
4058
|
-
|
|
4059
|
-
/** @import { ObjectStore } from '../Store/index.mjs' */
|
|
4075
|
+
/** @import { ObjectStore, Store } from '../Store/index.mjs' */
|
|
4060
4076
|
|
|
4061
4077
|
/**
|
|
4062
4078
|
*
|
|
@@ -4069,8 +4085,16 @@ function renderList(layouts, parent, next, envs, templates, renderItem) {
|
|
|
4069
4085
|
function renderObject(parent, next, store, env, renderItem) {
|
|
4070
4086
|
/** @type {(() => void)[]} */
|
|
4071
4087
|
const children = [];
|
|
4072
|
-
|
|
4073
|
-
|
|
4088
|
+
/** @type {[string, Store<any, any>, number][]} */
|
|
4089
|
+
const childStores = [...store].map(([k,v], i) => [k,v,i]);
|
|
4090
|
+
const count = childStores.length;
|
|
4091
|
+
for (const [key, child, index] of childStores) {
|
|
4092
|
+
children.push(renderItem(next, env.setStore(child, store, {
|
|
4093
|
+
get count() { return count; },
|
|
4094
|
+
get key() { return key; },
|
|
4095
|
+
get index() { return index; },
|
|
4096
|
+
get item() { return child.value; },
|
|
4097
|
+
})));
|
|
4074
4098
|
}
|
|
4075
4099
|
|
|
4076
4100
|
return () => {
|
|
@@ -4116,11 +4140,13 @@ function renderEnum(parent, next, getter, env, renderItem) {
|
|
|
4116
4140
|
e.remove();
|
|
4117
4141
|
}
|
|
4118
4142
|
}
|
|
4143
|
+
const count = new Signal.State(0);
|
|
4119
4144
|
const childrenResult = watch(() => list.get(), function render(children) {
|
|
4120
4145
|
if (!start.parentNode) { return; }
|
|
4121
4146
|
let nextNode = start.nextSibling;
|
|
4122
4147
|
const oldSeMap = seMap;
|
|
4123
4148
|
seMap = [];
|
|
4149
|
+
count.set(children.length);
|
|
4124
4150
|
for (const [value, index, key] of children) {
|
|
4125
4151
|
const index2 = oldSeMap.findIndex((v) => v[3] === key);
|
|
4126
4152
|
const [old] = index2 >= 0 ? oldSeMap.splice(index2, 1) : [];
|
|
@@ -4130,8 +4156,9 @@ function renderEnum(parent, next, getter, env, renderItem) {
|
|
|
4130
4156
|
const valueState = new Signal.State(value);
|
|
4131
4157
|
const indexState = new Signal.State(index);
|
|
4132
4158
|
const d = renderItem(itemEnd, env.setObject({
|
|
4159
|
+
get count() { return count.get() },
|
|
4133
4160
|
get key() { return key; },
|
|
4134
|
-
get
|
|
4161
|
+
get item() { return valueState.get(); },
|
|
4135
4162
|
get index() { return indexState.get(); },
|
|
4136
4163
|
}));
|
|
4137
4164
|
seMap.push([ItemStart, itemEnd, d, key, valueState, indexState]);
|
|
@@ -4320,6 +4347,50 @@ function bindEnhancements(tag, enhancementDefine, env, enhancements, root, slot)
|
|
|
4320
4347
|
};
|
|
4321
4348
|
}
|
|
4322
4349
|
|
|
4350
|
+
/** @import * as Layout from '../Layout/index.mjs' */
|
|
4351
|
+
|
|
4352
|
+
/**
|
|
4353
|
+
* @param {Layout.Divergent} layout
|
|
4354
|
+
* @param {Element} parent
|
|
4355
|
+
* @param {Node?} next
|
|
4356
|
+
* @param {Environment} env
|
|
4357
|
+
* @param {(layout: Layout.Child[], vars?: Layout.Variable[]?, templates?: Record<string, any>) => () => void} renderItem
|
|
4358
|
+
* @returns {() => void}
|
|
4359
|
+
*/
|
|
4360
|
+
function divergent(layout, parent, next, env, renderItem) {
|
|
4361
|
+
const children = layout.children;
|
|
4362
|
+
if (!children.length) { return () => { }; }
|
|
4363
|
+
const end = parent.insertBefore(document.createComment(''), next);
|
|
4364
|
+
/** @type {typeof children[0]?} */
|
|
4365
|
+
let last = null;
|
|
4366
|
+
let destroy = () => { };
|
|
4367
|
+
const stop = () => {
|
|
4368
|
+
destroy();
|
|
4369
|
+
destroy = () => { };
|
|
4370
|
+
end.remove();
|
|
4371
|
+
};
|
|
4372
|
+
const unwatch = watch(
|
|
4373
|
+
() => children.find(([, ifv]) => !ifv || env.exec(ifv)) || null,
|
|
4374
|
+
item => {
|
|
4375
|
+
if (item === last) { return; }
|
|
4376
|
+
last = item;
|
|
4377
|
+
destroy();
|
|
4378
|
+
destroy = () => { };
|
|
4379
|
+
const layout = item?.[0];
|
|
4380
|
+
if (!layout) { return; }
|
|
4381
|
+
destroy = renderItem(layout.children, layout.vars, layout.templates);
|
|
4382
|
+
}, true,
|
|
4383
|
+
);
|
|
4384
|
+
|
|
4385
|
+
let destroyed = false;
|
|
4386
|
+
return () => {
|
|
4387
|
+
if (destroyed) { return; }
|
|
4388
|
+
destroyed = true;
|
|
4389
|
+
unwatch();
|
|
4390
|
+
stop();
|
|
4391
|
+
};
|
|
4392
|
+
}
|
|
4393
|
+
|
|
4323
4394
|
/** @import Store from '../Store/index.mjs' */
|
|
4324
4395
|
|
|
4325
4396
|
/**
|
|
@@ -4327,37 +4398,19 @@ function bindEnhancements(tag, enhancementDefine, env, enhancements, root, slot)
|
|
|
4327
4398
|
* @param {Element} parent
|
|
4328
4399
|
* @param {Node?} next
|
|
4329
4400
|
* @param {Environment} env
|
|
4330
|
-
* @param {Record<string, [Layout.
|
|
4401
|
+
* @param {Record<string, [Layout.Template, Environment]>} templates
|
|
4331
4402
|
* @param {string[]} componentPath
|
|
4332
4403
|
* @param {Record<string, Enhancement>} enhancements
|
|
4333
4404
|
* @param {((store: Store, el: Element | Relatedness) => () => void)?} [relate]
|
|
4334
4405
|
* @param {Component.Getter?} [getComponent]
|
|
4335
4406
|
*/
|
|
4336
|
-
function
|
|
4337
|
-
env = env.set(layout.aliases, layout.vars);
|
|
4407
|
+
function renderNode(layout, parent, next, env, templates, componentPath, enhancements, relate, getComponent) {
|
|
4338
4408
|
const bind = layout.bind;
|
|
4339
|
-
const fragment = layout.fragment;
|
|
4340
|
-
if (fragment && typeof fragment === 'string') {
|
|
4341
|
-
const template = templates[fragment];
|
|
4342
|
-
if (!template) { return () => {}; }
|
|
4343
|
-
const [templateLayout, templateEnv] = template;
|
|
4344
|
-
const newEnv = templateEnv.params(templateLayout, layout, env, bind);
|
|
4345
|
-
return render(templateLayout, parent, next, newEnv, templates, componentPath, enhancements, relate, getComponent);
|
|
4346
|
-
}
|
|
4347
|
-
if (!layout.name || layout.fragment) {
|
|
4348
|
-
return renderFillDirectives(parent, next, env, layout) ||
|
|
4349
|
-
renderList(layout.children || [], parent, next, env, templates, (layout, templates) => {
|
|
4350
|
-
return render(layout, parent, next, env, templates, componentPath, enhancements, relate, getComponent);
|
|
4351
|
-
});
|
|
4352
|
-
}
|
|
4353
4409
|
const path = [...componentPath, layout.name];
|
|
4354
4410
|
const component = getComponent?.(path);
|
|
4355
4411
|
if (getComponent && !component) { return () => { }; }
|
|
4356
4412
|
const { context, handler } = createContext(
|
|
4357
|
-
component ? component : layout.name,
|
|
4358
|
-
env,
|
|
4359
|
-
env.getStore(bind),
|
|
4360
|
-
relate
|
|
4413
|
+
component ? component : layout.name, env, env.getStore(bind), relate
|
|
4361
4414
|
);
|
|
4362
4415
|
|
|
4363
4416
|
const componentAttrs = component?.attrs;
|
|
@@ -4381,11 +4434,9 @@ function renderItem(layout, parent, next, env, templates, componentPath, enhance
|
|
|
4381
4434
|
const root = Array.isArray(r) ? r[0] : r;
|
|
4382
4435
|
const slot = Array.isArray(r) ? r[1] : root;
|
|
4383
4436
|
parent.insertBefore(root, next);
|
|
4384
|
-
const children = slot ?
|
|
4385
|
-
|
|
4386
|
-
|
|
4387
|
-
return render(layout, slot, null, env, templates, componentPath, enhancements, relate, getComponent);
|
|
4388
|
-
}) : () => {};
|
|
4437
|
+
const children = slot ?
|
|
4438
|
+
renderChildren(layout.children || [], slot, null, env, templates, componentPath, enhancements, relate, getComponent)
|
|
4439
|
+
: () => { };
|
|
4389
4440
|
|
|
4390
4441
|
|
|
4391
4442
|
const classes = bindClasses(root, env, layout.classes, layout.attrs.class);
|
|
@@ -4393,7 +4444,7 @@ function renderItem(layout, parent, next, env, templates, componentPath, enhance
|
|
|
4393
4444
|
|
|
4394
4445
|
handler.mount();
|
|
4395
4446
|
const enhancement = bindEnhancements(handler.tag, layout.enhancements, env, enhancements, root, slot);
|
|
4396
|
-
|
|
4447
|
+
|
|
4397
4448
|
return () => {
|
|
4398
4449
|
enhancement();
|
|
4399
4450
|
handler.destroy();
|
|
@@ -4405,43 +4456,117 @@ function renderItem(layout, parent, next, env, templates, componentPath, enhance
|
|
|
4405
4456
|
styles();
|
|
4406
4457
|
};
|
|
4407
4458
|
}
|
|
4459
|
+
|
|
4408
4460
|
/**
|
|
4409
4461
|
*
|
|
4410
|
-
* @param {
|
|
4462
|
+
* @param {Environment} env
|
|
4463
|
+
* @param {Record<string, [Layout.Template, Environment]>} parentTemplates
|
|
4464
|
+
* @param {Record<string, Layout.Template>} [newTemplates]
|
|
4465
|
+
* @returns {Record<string, [Layout.Template, Environment]>}
|
|
4466
|
+
*/
|
|
4467
|
+
function createTemplates(env, parentTemplates, newTemplates) {
|
|
4468
|
+
if (!newTemplates) { return parentTemplates; } const layOutTemplates = Object.entries(newTemplates);
|
|
4469
|
+
if (!layOutTemplates.length) { return parentTemplates; }
|
|
4470
|
+
/** @type {Record<string, [Layout.Template, Environment]>} */
|
|
4471
|
+
const templates = Object.create(parentTemplates);
|
|
4472
|
+
for (const [name, template] of layOutTemplates) {
|
|
4473
|
+
templates[name] = [template, env];
|
|
4474
|
+
}
|
|
4475
|
+
return templates;
|
|
4476
|
+
}
|
|
4477
|
+
/**
|
|
4478
|
+
*
|
|
4479
|
+
* @param {Layout.Child} layout
|
|
4411
4480
|
* @param {Element} parent
|
|
4412
4481
|
* @param {Node?} next
|
|
4413
|
-
* @param {Environment}
|
|
4414
|
-
* @param {Record<string, [Layout.
|
|
4482
|
+
* @param {Environment} parentEnv
|
|
4483
|
+
* @param {Record<string, [Layout.Template, Environment]>} parentTemplates
|
|
4415
4484
|
* @param {string[]} componentPath
|
|
4416
4485
|
* @param {Record<string, Enhancement>} enhancements
|
|
4417
4486
|
* @param {((store: Store, el: Element | Relatedness) => () => void)?} [relate]
|
|
4418
4487
|
* @param {Component.Getter?} [getComponent]
|
|
4419
4488
|
* @returns {() => void}
|
|
4420
4489
|
*/
|
|
4421
|
-
function
|
|
4422
|
-
|
|
4423
|
-
|
|
4424
|
-
|
|
4425
|
-
|
|
4426
|
-
const r = (next, env) => renderItem(layout, parent, next, env, templates, componentPath, enhancements, relate, getComponent);
|
|
4427
|
-
if (list === true) {
|
|
4428
|
-
return r(next, newEnv);
|
|
4490
|
+
function renderChild(layout, parent, next, parentEnv, parentTemplates, componentPath, enhancements, relate, getComponent) {
|
|
4491
|
+
if (typeof layout === 'string') {
|
|
4492
|
+
const node = document.createTextNode(layout);
|
|
4493
|
+
parent.insertBefore(node, next);
|
|
4494
|
+
return () => node.remove();
|
|
4429
4495
|
}
|
|
4430
|
-
|
|
4431
|
-
|
|
4496
|
+
const env = parentEnv.set(layout.vars);
|
|
4497
|
+
const templates = createTemplates(env, parentTemplates, layout.templates);
|
|
4498
|
+
if (layout.type === 'divergent') {
|
|
4499
|
+
return divergent(layout, parent, next, env, (list, vars, templates2) => {
|
|
4500
|
+
const listEnv = env.set(vars);
|
|
4501
|
+
const templates = createTemplates(listEnv, parentTemplates, templates2);
|
|
4502
|
+
return renderChildren(list, parent, next, listEnv, templates, componentPath, enhancements, relate, getComponent);
|
|
4503
|
+
});
|
|
4432
4504
|
}
|
|
4433
|
-
if (
|
|
4434
|
-
|
|
4505
|
+
if (layout.type === 'value') {
|
|
4506
|
+
const newEnv = env.child(layout.name);
|
|
4507
|
+
if (!newEnv) { return () => { }; }
|
|
4508
|
+
return renderChildren(layout.children, parent, next, newEnv, templates, componentPath, enhancements, relate, getComponent);
|
|
4435
4509
|
}
|
|
4436
|
-
if (
|
|
4437
|
-
|
|
4510
|
+
if (layout.type === 'enum') {
|
|
4511
|
+
const list = env.enum(layout.value);
|
|
4512
|
+
/** @type {(next: Node | null, env: any) => () => void} */
|
|
4513
|
+
const r = (next, env) => renderChildren(layout.children, parent, next, env, templates, componentPath, enhancements, relate, getComponent);
|
|
4514
|
+
if (list instanceof ArrayStore) {
|
|
4515
|
+
return renderArray(parent, next, list, env, r);
|
|
4516
|
+
}
|
|
4517
|
+
if (list instanceof ObjectStore) {
|
|
4518
|
+
return renderObject(parent, next, list, env, r);
|
|
4519
|
+
}
|
|
4520
|
+
if (typeof list === 'function') {
|
|
4521
|
+
return renderEnum(parent, next, list, env, r);
|
|
4522
|
+
}
|
|
4523
|
+
return () => { };
|
|
4438
4524
|
}
|
|
4439
|
-
|
|
4525
|
+
if (layout.type === 'content') {
|
|
4526
|
+
return renderFillDirectives(parent, next, env, layout.value, layout.html);
|
|
4527
|
+
}
|
|
4528
|
+
if (layout.type === 'template') {
|
|
4529
|
+
const template = templates[layout.template];
|
|
4530
|
+
if (!template) { return () => { }; }
|
|
4531
|
+
const [templateLayout, templateEnv] = template;
|
|
4532
|
+
const newEnv = templateEnv.params(templateLayout.params, layout.attrs, env, layout.bind);
|
|
4533
|
+
const subTemplates = createTemplates(newEnv, parentTemplates, templateLayout.templates);
|
|
4534
|
+
return renderChildren(templateLayout.children, parent, next, newEnv, subTemplates, componentPath, enhancements, relate, getComponent);
|
|
4535
|
+
}
|
|
4536
|
+
if (layout.type === 'fragment') {
|
|
4537
|
+
return renderChildren(layout.children, parent, next, env, templates, componentPath, enhancements, relate, getComponent);
|
|
4538
|
+
}
|
|
4539
|
+
return renderNode(layout, parent, next, env, templates, componentPath, enhancements, relate, getComponent);
|
|
4540
|
+
}
|
|
4541
|
+
|
|
4542
|
+
/**
|
|
4543
|
+
*
|
|
4544
|
+
* @param {Layout.Child[]} layouts
|
|
4545
|
+
* @param {Element} parent
|
|
4546
|
+
* @param {Node?} next
|
|
4547
|
+
* @param {Environment} env
|
|
4548
|
+
* @param {Record<string, [Layout.Template, Environment]>} templates
|
|
4549
|
+
* @param {string[]} componentPath
|
|
4550
|
+
* @param {Record<string, Enhancement>} enhancements
|
|
4551
|
+
* @param {((store: Store, el: Element | Relatedness) => () => void)?} [relate]
|
|
4552
|
+
* @param {Component.Getter?} [getComponent]
|
|
4553
|
+
* @returns {() => void}
|
|
4554
|
+
*/
|
|
4555
|
+
function renderChildren(layouts, parent, next, env, templates, componentPath, enhancements, relate, getComponent) {
|
|
4556
|
+
const list = layouts.map(v => renderChild(v, parent, next, env, templates, componentPath, enhancements, relate, getComponent));
|
|
4557
|
+
let removed = false;
|
|
4558
|
+
return () => {
|
|
4559
|
+
if (removed) { return; }
|
|
4560
|
+
removed = true;
|
|
4561
|
+
for (const k of list) {
|
|
4562
|
+
k();
|
|
4563
|
+
}
|
|
4564
|
+
};
|
|
4440
4565
|
}
|
|
4441
4566
|
|
|
4442
4567
|
/**
|
|
4443
4568
|
* @param {Store} store 存储实例
|
|
4444
|
-
* @param {
|
|
4569
|
+
* @param {Layout.Child[]} layouts 布局信息
|
|
4445
4570
|
* @param {Element} parent 渲染节点
|
|
4446
4571
|
* @param {object} [options] 选项
|
|
4447
4572
|
* @param {Record<string, Store | {get?(): any; set?(v: any): void; exec?(...p: any[]): any; calc?(...p: any[]): any }>} [options.global] 全局数据
|
|
@@ -4450,14 +4575,12 @@ function render(layout, parent, next, env, templates, componentPath, enhancement
|
|
|
4450
4575
|
* @param {Record<string, Enhancement>} [options.enhancements] 增强信息
|
|
4451
4576
|
* @returns {() => void}
|
|
4452
4577
|
*/
|
|
4453
|
-
function
|
|
4578
|
+
function render(store, layouts, parent, { component, global, relate, enhancements } = {}) {
|
|
4454
4579
|
const env = new Environment(store, global);
|
|
4455
4580
|
const templates = Object.create(null);
|
|
4456
4581
|
const allEnhancements = enhancements || {};
|
|
4457
|
-
const relateFn = typeof relate
|
|
4458
|
-
return
|
|
4459
|
-
return render(layout, parent, null, env, templates, [], allEnhancements, relateFn, component);
|
|
4460
|
-
});
|
|
4582
|
+
const relateFn = typeof relate === 'function' ? relate : null;
|
|
4583
|
+
return renderChildren(layouts, parent, null, env, templates, [], allEnhancements, relateFn, component);
|
|
4461
4584
|
}
|
|
4462
4585
|
|
|
4463
|
-
export { index
|
|
4586
|
+
export { index as Layout, Store, effect, render, watch };
|