@neeloong/form 0.8.0 → 0.9.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 +6 -1
- package/index.d.mts +85 -34
- package/index.js +670 -322
- package/index.min.js +4 -4
- package/index.min.mjs +4 -4
- package/index.mjs +670 -322
- package/package.json +1 -1
package/index.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/*!
|
|
2
|
-
* @neeloong/form v0.
|
|
2
|
+
* @neeloong/form v0.9.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 = v => {
|
|
76
|
+
const values$1 = 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; }
|
|
@@ -387,7 +387,7 @@ class Store {
|
|
|
387
387
|
validator, validators,
|
|
388
388
|
index, length, new: isNew, parent: parentNode,
|
|
389
389
|
hidden, clearable, required, disabled, readonly,
|
|
390
|
-
label, description, placeholder, min, max, step, minLength, maxLength, pattern, values
|
|
390
|
+
label, description, placeholder, min, max, step, minLength, maxLength, pattern, values
|
|
391
391
|
} = {}) {
|
|
392
392
|
this.schema = schema;
|
|
393
393
|
this.#state.set(typeof state === 'object' && state || {});
|
|
@@ -450,7 +450,7 @@ class Store {
|
|
|
450
450
|
[this.#selfMaxLength, this.#maxLength] = createState(this, number, maxLength, schema.maxLength);
|
|
451
451
|
[this.#selfPattern, this.#pattern] = createState(this, regex, pattern, schema.pattern);
|
|
452
452
|
// @ts-ignore
|
|
453
|
-
[this.#selfValues, this.#values] = createState(this, values, values
|
|
453
|
+
[this.#selfValues, this.#values] = createState(this, values$1, values, schema.values);
|
|
454
454
|
|
|
455
455
|
const validatorResult = createValidator(this, schema.validator, validator);
|
|
456
456
|
|
|
@@ -682,9 +682,9 @@ class Store {
|
|
|
682
682
|
/** @readonly @type {Signal.Computed<(Schema.Value.Group | Schema.Value)[] | null>} */
|
|
683
683
|
#values
|
|
684
684
|
get selfValues() { return this.#selfValues.get(); }
|
|
685
|
-
set selfValues(v) { this.#selfValues.set(values(v)); }
|
|
685
|
+
set selfValues(v) { this.#selfValues.set(values$1(v)); }
|
|
686
686
|
get values() { return this.#values.get(); }
|
|
687
|
-
set values(v) { this.#selfValues.set(values(v)); }
|
|
687
|
+
set values(v) { this.#selfValues.set(values$1(v)); }
|
|
688
688
|
|
|
689
689
|
|
|
690
690
|
/** @type {Signal.Computed<string[]>} */
|
|
@@ -1184,6 +1184,16 @@ class ArrayStore extends Store {
|
|
|
1184
1184
|
// @ts-ignore
|
|
1185
1185
|
setArrayStore(ArrayStore);
|
|
1186
1186
|
|
|
1187
|
+
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;
|
|
1188
|
+
/**
|
|
1189
|
+
*
|
|
1190
|
+
* @param {string} t
|
|
1191
|
+
* @returns
|
|
1192
|
+
*/
|
|
1193
|
+
function parseNumber(t) {
|
|
1194
|
+
return numRegex.test(t) ? Number(t.replaceAll('_', '')) : NaN;
|
|
1195
|
+
}
|
|
1196
|
+
|
|
1187
1197
|
const errors = {
|
|
1188
1198
|
CALC: 'no `createCalc` option, no expression parsing support',
|
|
1189
1199
|
EVENT: 'no `createEvent`, options, no event parsing support',
|
|
@@ -1231,64 +1241,137 @@ class ParseError extends Error {
|
|
|
1231
1241
|
/** @import * as Layout from './index.mjs' */
|
|
1232
1242
|
|
|
1233
1243
|
const attrPattern = /^(?<decorator>[:@!+*\.?]|style:|样式:)?(?<name>-?[\w\p{Unified_Ideograph}_][-\w\p{Unified_Ideograph}_:\d\.]*)$/u;
|
|
1244
|
+
const enhancementPattern = /^~(?<enhancement>[\w\p{Unified_Ideograph}_][-\w\p{Unified_Ideograph}_\d\.]*)(?:(?<decorator>[:@!])(?<name>-?[\w\p{Unified_Ideograph}_][-\w\p{Unified_Ideograph}_:\d\.]*))?$/u;
|
|
1234
1245
|
const nameRegex = /^(?<name>[a-zA-Z$\p{Unified_Ideograph}_][\da-zA-Z$\p{Unified_Ideograph}_]*)?$/u;
|
|
1246
|
+
|
|
1247
|
+
/**
|
|
1248
|
+
*
|
|
1249
|
+
* @param {Record<string, Layout.Enhancement>} enhancements
|
|
1250
|
+
* @param {string} name
|
|
1251
|
+
*/
|
|
1252
|
+
function getEnhancement(enhancements, name) {
|
|
1253
|
+
const enhancement = enhancements[name];
|
|
1254
|
+
if (enhancement) { return enhancement; }
|
|
1255
|
+
/** @type {Layout.Enhancement} */
|
|
1256
|
+
const e = {
|
|
1257
|
+
attrs: Object.create(null),
|
|
1258
|
+
events: Object.create(null),
|
|
1259
|
+
};
|
|
1260
|
+
enhancements[name] = e;
|
|
1261
|
+
return e;
|
|
1262
|
+
}
|
|
1263
|
+
/**
|
|
1264
|
+
*
|
|
1265
|
+
* @param {string} value
|
|
1266
|
+
* @param {Exclude<Layout.Options['createCalc'], undefined>} createCalc
|
|
1267
|
+
* @returns {Layout.Node.Name | Layout.Node.Calc | Layout.Node.Value}
|
|
1268
|
+
*/
|
|
1269
|
+
function parse$1(value, createCalc) {
|
|
1270
|
+
const text = value.replace(/$\s+|\s+$/gs,'');
|
|
1271
|
+
if (text === 'null') { return {value: null} }
|
|
1272
|
+
if (text === 'true') { return {value: true} }
|
|
1273
|
+
if (text === 'false') { return {value: false} }
|
|
1274
|
+
const t = parseNumber(text);
|
|
1275
|
+
if (!Number.isNaN(t)) { return {value: t}; }
|
|
1276
|
+
if (nameRegex.test(text)) { return {name: text} }
|
|
1277
|
+
return {calc: createCalc(value)};
|
|
1278
|
+
}
|
|
1279
|
+
|
|
1235
1280
|
/**
|
|
1236
1281
|
* @param {Layout.Node} node
|
|
1237
1282
|
* @param {Exclude<Layout.Options['createCalc'], undefined>} createCalc
|
|
1238
1283
|
* @param {Exclude<Layout.Options['createEvent'], undefined>} createEvent
|
|
1239
1284
|
*/
|
|
1240
1285
|
function createAttributeAdder(node, createCalc, createEvent) {
|
|
1241
|
-
const { attrs,
|
|
1286
|
+
const { attrs, events, classes, styles, vars, aliases, params, enhancements } = node;
|
|
1242
1287
|
/**
|
|
1243
1288
|
* @param {string} qName
|
|
1244
1289
|
* @param {string} value
|
|
1245
1290
|
*/
|
|
1246
1291
|
function addAttribute(qName, value) {
|
|
1247
|
-
const
|
|
1248
|
-
|
|
1249
|
-
|
|
1250
|
-
|
|
1251
|
-
|
|
1252
|
-
|
|
1253
|
-
|
|
1254
|
-
|
|
1292
|
+
const qn = qName
|
|
1293
|
+
.replace(/./g,'.')
|
|
1294
|
+
.replace(/:/g,':')
|
|
1295
|
+
.replace(/@/g,'@')
|
|
1296
|
+
.replace(/+/g,'+')
|
|
1297
|
+
.replace(/-/g,'-')
|
|
1298
|
+
.replace(/[*×]/g,'*')
|
|
1299
|
+
.replace(/!/g, '!');
|
|
1300
|
+
const attr = (attrPattern.exec(qn) || enhancementPattern.exec(qn))?.groups;
|
|
1255
1301
|
if (!attr) { throw new ParseError('ATTR', qName); }
|
|
1256
|
-
const { name } = attr;
|
|
1302
|
+
const { name, enhancement } = attr;
|
|
1257
1303
|
const decorator = attr.decorator?.toLowerCase();
|
|
1258
|
-
if (
|
|
1259
|
-
|
|
1260
|
-
|
|
1261
|
-
|
|
1262
|
-
|
|
1263
|
-
|
|
1264
|
-
|
|
1265
|
-
|
|
1266
|
-
|
|
1267
|
-
|
|
1268
|
-
|
|
1269
|
-
|
|
1270
|
-
|
|
1271
|
-
aliases[name] = nameRegex.test(value) ? value : createCalc(value);
|
|
1272
|
-
} else if (decorator === '?') {
|
|
1273
|
-
params[name] = nameRegex.test(value) ? value : createCalc(value);
|
|
1274
|
-
} else if (decorator === '!') {
|
|
1275
|
-
const key = name.toString();
|
|
1276
|
-
switch (key) {
|
|
1277
|
-
case 'fragment': directives.fragment = value || true; break;
|
|
1278
|
-
case 'else': directives.else = true; break;
|
|
1279
|
-
case 'enum':
|
|
1280
|
-
directives.enum = value ? nameRegex.test(value) ? value : createCalc(value) : true;
|
|
1281
|
-
break;
|
|
1282
|
-
case 'if':
|
|
1283
|
-
case 'text':
|
|
1284
|
-
case 'html':
|
|
1285
|
-
directives[key] = nameRegex.test(value) ? value : createCalc(value);
|
|
1286
|
-
break;
|
|
1287
|
-
case 'template': directives.template = value; break;
|
|
1288
|
-
case 'bind': directives.bind = value || true; break;
|
|
1289
|
-
case 'value': directives.value = value; break;
|
|
1290
|
-
case 'comment': directives.comment = value; break;
|
|
1304
|
+
if (enhancement) {
|
|
1305
|
+
if (decorator === ':') {
|
|
1306
|
+
getEnhancement(enhancements, enhancement).attrs[name] = value ? parse$1(value, createCalc) : {name};
|
|
1307
|
+
} else if (decorator === '@') {
|
|
1308
|
+
getEnhancement(enhancements, enhancement).events[name] = value ? nameRegex.test(value) ? {name: value} : {event: createEvent(value)} : {name};
|
|
1309
|
+
} else if (decorator === '!') {
|
|
1310
|
+
switch(name) {
|
|
1311
|
+
case 'bind':
|
|
1312
|
+
getEnhancement(enhancements, enhancement).bind = value || true;
|
|
1313
|
+
break;
|
|
1314
|
+
}
|
|
1315
|
+
} else {
|
|
1316
|
+
getEnhancement(enhancements, enhancement).value = parse$1(value, createCalc);
|
|
1291
1317
|
}
|
|
1318
|
+
return;
|
|
1319
|
+
}
|
|
1320
|
+
if (!decorator) {
|
|
1321
|
+
attrs[name] = {value};
|
|
1322
|
+
return;
|
|
1323
|
+
}
|
|
1324
|
+
if (decorator === ':') {
|
|
1325
|
+
attrs[name] = value ? parse$1(value, createCalc) : {name};
|
|
1326
|
+
return;
|
|
1327
|
+
}
|
|
1328
|
+
if (decorator === '.') {
|
|
1329
|
+
classes[name] = value ? parse$1(value, createCalc) : {name};
|
|
1330
|
+
return;
|
|
1331
|
+
}
|
|
1332
|
+
if (decorator === 'style:') {
|
|
1333
|
+
styles[name] = parse$1(value, createCalc);
|
|
1334
|
+
return;
|
|
1335
|
+
}
|
|
1336
|
+
if (decorator === '@') {
|
|
1337
|
+
events[name] = value ? nameRegex.test(value) ? {name: value} : {event: createEvent(value)} : {name};
|
|
1338
|
+
return;
|
|
1339
|
+
}
|
|
1340
|
+
if (decorator === '+') {
|
|
1341
|
+
vars[name] = !value ? {value: undefined} : parse$1(value, createCalc);
|
|
1342
|
+
return;
|
|
1343
|
+
}
|
|
1344
|
+
if (decorator === '*') {
|
|
1345
|
+
aliases[name] = parse$1(value, createCalc);
|
|
1346
|
+
return;
|
|
1347
|
+
}
|
|
1348
|
+
if (decorator === '?') {
|
|
1349
|
+
params[name] = parse$1(value, createCalc);
|
|
1350
|
+
return;
|
|
1351
|
+
}
|
|
1352
|
+
if (decorator !== '!') {
|
|
1353
|
+
return;
|
|
1354
|
+
}
|
|
1355
|
+
const key = name.toString();
|
|
1356
|
+
switch (key) {
|
|
1357
|
+
case 'fragment': node.fragment = value || true; break;
|
|
1358
|
+
case 'else': node.else = true; break;
|
|
1359
|
+
case 'enum':
|
|
1360
|
+
node.enum = value ? parse$1(value, createCalc) : {value: true};
|
|
1361
|
+
break;
|
|
1362
|
+
case 'if':
|
|
1363
|
+
node.if = parse$1(value, createCalc);
|
|
1364
|
+
break;
|
|
1365
|
+
case 'text':
|
|
1366
|
+
node.text = parse$1(value, createCalc);
|
|
1367
|
+
break;
|
|
1368
|
+
case 'html':
|
|
1369
|
+
node.html = parse$1(value, createCalc);
|
|
1370
|
+
break;
|
|
1371
|
+
case 'template': node.template = value; break;
|
|
1372
|
+
case 'bind': node.bind = value || true; break;
|
|
1373
|
+
case 'value': node.value = value; break;
|
|
1374
|
+
case 'comment': node.comment = value; break;
|
|
1292
1375
|
}
|
|
1293
1376
|
}
|
|
1294
1377
|
return addAttribute;
|
|
@@ -1309,12 +1392,12 @@ function createElement(name, is) {
|
|
|
1309
1392
|
children: [],
|
|
1310
1393
|
attrs: Object.create(null),
|
|
1311
1394
|
events: Object.create(null),
|
|
1312
|
-
directives: Object.create(null),
|
|
1313
1395
|
classes: Object.create(null),
|
|
1314
1396
|
styles: Object.create(null),
|
|
1315
1397
|
vars: Object.create(null),
|
|
1316
1398
|
aliases: Object.create(null),
|
|
1317
1399
|
params: Object.create(null),
|
|
1400
|
+
enhancements: Object.create(null),
|
|
1318
1401
|
};
|
|
1319
1402
|
}
|
|
1320
1403
|
|
|
@@ -1826,6 +1909,54 @@ function _xmlEncoder(c) {
|
|
|
1826
1909
|
'&#' + c.charCodeAt() + ';';
|
|
1827
1910
|
}
|
|
1828
1911
|
|
|
1912
|
+
/**
|
|
1913
|
+
* @param {Layout.Node.Name | Layout.Node.Calc | Layout.Node.Event | Layout.Node.Value} def
|
|
1914
|
+
*/
|
|
1915
|
+
function toValue({name, calc, event, value}) {
|
|
1916
|
+
if (value === true || value === undefined) { return ''; }
|
|
1917
|
+
const val = typeof value === 'string' ? JSON.stringify(value) : name || calc || event || value;
|
|
1918
|
+
return `="${toAttrValue$1(val)}"`;
|
|
1919
|
+
}
|
|
1920
|
+
/**
|
|
1921
|
+
* @param {string | Function | null} [value]
|
|
1922
|
+
*/
|
|
1923
|
+
function toAttrValue$1(value) {
|
|
1924
|
+
return String(value).replace(/[<&"]/g, _xmlEncoder);
|
|
1925
|
+
}
|
|
1926
|
+
|
|
1927
|
+
/**
|
|
1928
|
+
* @param {Record<string, Layout.Node.Name | Layout.Node.Calc | Layout.Node.Event | Layout.Node.Value>} values
|
|
1929
|
+
* @param {string} [prefix]
|
|
1930
|
+
* @param {boolean | null} [isName]
|
|
1931
|
+
*/
|
|
1932
|
+
function *values(values, prefix, isName = false) {
|
|
1933
|
+
if (prefix) {
|
|
1934
|
+
for (const [key, {name, calc, event, value}] of Object.entries(values)) {
|
|
1935
|
+
yield ` ${prefix}${key}`;
|
|
1936
|
+
if (isName && name === key) { continue; }
|
|
1937
|
+
const val = value && typeof value === 'string' ? JSON.stringify(value) : name || calc || event || value;
|
|
1938
|
+
if (val == null) { continue; }
|
|
1939
|
+
if (isName === false && val === true) { continue; }
|
|
1940
|
+
yield `="${toAttrValue$1(val)}"`;
|
|
1941
|
+
}
|
|
1942
|
+
return;
|
|
1943
|
+
}
|
|
1944
|
+
for (const [key, attr] of Object.entries(values)) {
|
|
1945
|
+
if (!attr) { continue; }
|
|
1946
|
+
const {name, value, calc} = attr;
|
|
1947
|
+
if (name === key) { yield ` :${key}`; continue; }
|
|
1948
|
+
if (name || calc || typeof value !== 'string') {
|
|
1949
|
+
yield ` :${key}="${toAttrValue$1(name || calc || value)}"`;
|
|
1950
|
+
continue;
|
|
1951
|
+
}
|
|
1952
|
+
yield ` ${key}`;
|
|
1953
|
+
if (value) {
|
|
1954
|
+
yield `="${toAttrValue$1(value)}"`;
|
|
1955
|
+
}
|
|
1956
|
+
}
|
|
1957
|
+
}
|
|
1958
|
+
|
|
1959
|
+
|
|
1829
1960
|
/**
|
|
1830
1961
|
*
|
|
1831
1962
|
* @param {Layout.Node} node
|
|
@@ -1833,81 +1964,37 @@ function _xmlEncoder(c) {
|
|
|
1833
1964
|
* @returns {Iterable<string>}
|
|
1834
1965
|
*/
|
|
1835
1966
|
function* nodeToString(node, level = 0) {
|
|
1836
|
-
const {
|
|
1967
|
+
const { children, is, name } = node;
|
|
1837
1968
|
const pad = level > 0 ? ''.padEnd(level, '\t') : '';
|
|
1838
1969
|
|
|
1839
1970
|
yield pad;
|
|
1840
1971
|
yield* ['<', name || '-'];
|
|
1841
1972
|
if (is) { yield* ['|', is]; }
|
|
1842
|
-
|
|
1843
|
-
|
|
1844
|
-
|
|
1845
|
-
const val = typeof value === 'function' ? String(value) : value;
|
|
1846
|
-
yield* [' ?', name];
|
|
1847
|
-
if (val && typeof val === 'string') {
|
|
1848
|
-
yield* ['="', val.replace(/[<&"]/g, _xmlEncoder), '"'];
|
|
1849
|
-
}
|
|
1850
|
-
}
|
|
1851
|
-
for (const [name, value] of Object.entries(directives)) {
|
|
1852
|
-
if (value === false || value == null) { continue; }
|
|
1853
|
-
const val = typeof value === 'function' ? String(value) : value;
|
|
1854
|
-
yield* [' !', name];
|
|
1855
|
-
if (val && typeof val === 'string') {
|
|
1856
|
-
yield* ['="', val.replace(/[<&"]/g, _xmlEncoder), '"'];
|
|
1857
|
-
}
|
|
1858
|
-
}
|
|
1859
|
-
for (const [name, value] of Object.entries(aliases)) {
|
|
1860
|
-
if (value == null) { continue; }
|
|
1861
|
-
const val = typeof value === 'function' ? String(value) : value;
|
|
1862
|
-
yield* [' *', name];
|
|
1863
|
-
if (val && typeof val === 'string') {
|
|
1864
|
-
yield* ['="', val.replace(/[<&"]/g, _xmlEncoder), '"'];
|
|
1865
|
-
}
|
|
1866
|
-
}
|
|
1867
|
-
for (const [name, value] of Object.entries(vars)) {
|
|
1868
|
-
if (value == null) { continue; }
|
|
1869
|
-
const val = typeof value === 'function' ? String(value) : value;
|
|
1870
|
-
yield* [' +', name];
|
|
1871
|
-
if (val && typeof val === 'string') {
|
|
1872
|
-
yield* ['="', val.replace(/[<&"]/g, _xmlEncoder), '"'];
|
|
1873
|
-
}
|
|
1874
|
-
}
|
|
1875
|
-
for (const [name, value] of Object.entries(attrs)) {
|
|
1876
|
-
if (value == null) { continue; }
|
|
1877
|
-
if (typeof value === 'string') {
|
|
1878
|
-
yield* [' ', name];
|
|
1879
|
-
if (value) {
|
|
1880
|
-
yield* ['="', value.replace(/[<&"]/g, _xmlEncoder), '"'];
|
|
1881
|
-
}
|
|
1882
|
-
continue;
|
|
1883
|
-
}
|
|
1884
|
-
const val = typeof value === 'function' ? String(value) : typeof value === 'object' ? value.name : value;
|
|
1885
|
-
if (val && typeof val === 'string') {
|
|
1886
|
-
yield* [' :', name, '="', val.replace(/[<&"]/g, _xmlEncoder) || '', '"'];
|
|
1887
|
-
}
|
|
1973
|
+
if (node.template) {
|
|
1974
|
+
yield ` !template="${toAttrValue$1(node.template)}"`;
|
|
1975
|
+
yield* values(node.params, '?', null);
|
|
1888
1976
|
}
|
|
1889
|
-
|
|
1890
|
-
|
|
1891
|
-
|
|
1892
|
-
|
|
1893
|
-
|
|
1894
|
-
|
|
1895
|
-
|
|
1896
|
-
|
|
1897
|
-
|
|
1898
|
-
|
|
1899
|
-
|
|
1900
|
-
|
|
1901
|
-
|
|
1902
|
-
}
|
|
1903
|
-
|
|
1904
|
-
|
|
1905
|
-
|
|
1906
|
-
const val = typeof value === 'function' ? String(value) : value;
|
|
1907
|
-
if (val && typeof val === 'string') {
|
|
1908
|
-
yield* [' style:', name, '="', val.replace(/[<&"]/g, _xmlEncoder), '"'];
|
|
1909
|
-
}
|
|
1977
|
+
if (node.fragment) { yield node.fragment === true ? ` !fragment` : ` !fragment="${toAttrValue$1(node.fragment)}"`; }
|
|
1978
|
+
if (node.else) { yield ` !else`; }
|
|
1979
|
+
if (node.if) { yield ` !if${toValue(node.if)}`; }
|
|
1980
|
+
if (node.value) { yield ` !value="${toAttrValue$1(node.value)}"`; }
|
|
1981
|
+
if (node.enum) { yield ` !enum${toValue(node.enum)}`; }
|
|
1982
|
+
yield* values(node.aliases, '*', null);
|
|
1983
|
+
yield* values(node.vars, '+', null);
|
|
1984
|
+
if (node.bind) { yield node.bind === true ? ` !bind` : ` !bind="${toAttrValue$1(node.bind)}"`; }
|
|
1985
|
+
yield* values(node.attrs);
|
|
1986
|
+
yield* values(node.events, '@', true);
|
|
1987
|
+
yield* values(node.classes, '.', true);
|
|
1988
|
+
yield* values(node.styles, 'style:');
|
|
1989
|
+
for (const [k, en] of Object.entries(node.enhancements)) {
|
|
1990
|
+
if (en.bind) { yield en.bind === true ? ` ~${k}!bind` : ` ~${k}!bind="${toAttrValue$1(en.bind)}"`; }
|
|
1991
|
+
if (en.value) { yield ` ~${k}${toValue(en.value)}`; }
|
|
1992
|
+
yield* values(en.attrs, `~${k}:`, true);
|
|
1993
|
+
yield* values(en.events, `~${k}@`, true);
|
|
1910
1994
|
}
|
|
1995
|
+
if (node.text) { yield ` !text${toValue(node.text)}`; }
|
|
1996
|
+
if (node.html) { yield ` !html${toValue(node.html)}`; }
|
|
1997
|
+
if (node.comment) { yield ` !comment="${toAttrValue$1(node.comment)}"`; }
|
|
1911
1998
|
if (!children.length) {
|
|
1912
1999
|
yield '/>';
|
|
1913
2000
|
if (level >= 0) { yield '\n'; }
|
|
@@ -1969,44 +2056,66 @@ function toString(value, formable) {
|
|
|
1969
2056
|
/**
|
|
1970
2057
|
* @typedef {object} Directives
|
|
1971
2058
|
*
|
|
1972
|
-
* @property {string} [template]
|
|
1973
|
-
*
|
|
1974
|
-
* @property {boolean | string} [fragment]
|
|
1975
|
-
*
|
|
1976
|
-
* @property {string | Calc} [if]
|
|
1977
|
-
* @property {boolean} [else]
|
|
1978
|
-
*
|
|
1979
|
-
* @property {string} [value] 值关联(关联为列表)
|
|
1980
|
-
* @property {boolean | string | Calc} [enum] 列表属性枚举
|
|
1981
|
-
*
|
|
1982
|
-
* @property {boolean | string} [bind]
|
|
1983
|
-
* @property {string | Calc} [text]
|
|
1984
|
-
* @property {string | Calc} [html]
|
|
1985
|
-
*
|
|
1986
|
-
* @property {string} [comment] 注释
|
|
1987
2059
|
*/
|
|
1988
2060
|
|
|
1989
2061
|
|
|
1990
2062
|
|
|
2063
|
+
/**
|
|
2064
|
+
* @typedef {object} Enhancement
|
|
2065
|
+
* @property {Record<string, Node.Name | Node.Event>} events
|
|
2066
|
+
* @property {Record<string, Node.Name | Node.Calc | Node.Value>} attrs
|
|
2067
|
+
* @property {Node.Name | Node.Calc | Node.Value} [value]
|
|
2068
|
+
* @property {boolean | string} [bind]
|
|
2069
|
+
*/
|
|
2070
|
+
|
|
1991
2071
|
/**
|
|
1992
2072
|
* @typedef {object} Options
|
|
1993
2073
|
* @property {(t: string) => Calc} [options.createCalc]
|
|
1994
2074
|
* @property {(t: string) => EventListener} [options.createEvent]
|
|
1995
2075
|
* @property {Set<string>} [options.simpleTag]
|
|
1996
2076
|
*/
|
|
2077
|
+
/**
|
|
2078
|
+
* @template [T=any]
|
|
2079
|
+
* @typedef {{value: T; name?: undefined; calc?: undefined; event?: undefined}} Node.Value
|
|
2080
|
+
*/
|
|
2081
|
+
/**
|
|
2082
|
+
* @typedef {{name: string; value?: undefined; calc?: undefined; event?: undefined}} Node.Name
|
|
2083
|
+
*/
|
|
2084
|
+
/**
|
|
2085
|
+
* @typedef {{event: EventListener; name?: undefined; calc?: undefined; value?: undefined}} Node.Event
|
|
2086
|
+
*/
|
|
2087
|
+
/**
|
|
2088
|
+
* @typedef {{calc: Calc; name?: undefined; value?: undefined; event?: undefined}} Node.Calc
|
|
2089
|
+
*/
|
|
1997
2090
|
/**
|
|
1998
2091
|
* @typedef {object} Node
|
|
1999
2092
|
* @property {string} name
|
|
2000
2093
|
* @property {string?} [is]
|
|
2001
2094
|
* @property {string} [id]
|
|
2002
|
-
* @property {Record<string,
|
|
2003
|
-
* @property {Record<string,
|
|
2004
|
-
* @property {Record<string,
|
|
2005
|
-
* @property {Record<string,
|
|
2006
|
-
* @property {Record<string,
|
|
2007
|
-
* @property {Record<string,
|
|
2008
|
-
* @property {Record<string,
|
|
2009
|
-
* @property {
|
|
2095
|
+
* @property {Record<string, Node.Name | Node.Calc | Node.Value>} attrs
|
|
2096
|
+
* @property {Record<string, Node.Name | Node.Calc | Node.Value>} params
|
|
2097
|
+
* @property {Record<string, Node.Name | Node.Calc | Node.Value>} classes
|
|
2098
|
+
* @property {Record<string, Node.Name | Node.Calc | Node.Value>} styles
|
|
2099
|
+
* @property {Record<string, Node.Name | Node.Event>} events
|
|
2100
|
+
* @property {Record<string, Node.Name | Node.Calc | Node.Value>} vars
|
|
2101
|
+
* @property {Record<string, Node.Name | Node.Calc | Node.Value>} aliases
|
|
2102
|
+
* @property {Record<string, Enhancement>} enhancements
|
|
2103
|
+
*
|
|
2104
|
+
* @property {string} [template]
|
|
2105
|
+
* @property {boolean | string} [fragment]
|
|
2106
|
+
*
|
|
2107
|
+
* @property {Node.Name | Node.Calc | Node.Value} [if]
|
|
2108
|
+
* @property {boolean} [else]
|
|
2109
|
+
*
|
|
2110
|
+
* @property {string} [value] 值关联
|
|
2111
|
+
* @property {Node.Name | Node.Calc | Node.Value} [enum] 列表属性枚举
|
|
2112
|
+
*
|
|
2113
|
+
* @property {boolean | string} [bind]
|
|
2114
|
+
* @property {Node.Name | Node.Value | Node.Calc} [text]
|
|
2115
|
+
* @property {Node.Name | Node.Value | Node.Calc} [html]
|
|
2116
|
+
*
|
|
2117
|
+
* @property {string} [comment] 注释
|
|
2118
|
+
*
|
|
2010
2119
|
* @property {(Node | string)[]} children
|
|
2011
2120
|
*/
|
|
2012
2121
|
|
|
@@ -2014,7 +2123,7 @@ function toString(value, formable) {
|
|
|
2014
2123
|
* @callback Calc
|
|
2015
2124
|
* @param {Record<string, any>} env
|
|
2016
2125
|
* @returns {any}
|
|
2017
|
-
*/
|
|
2126
|
+
*/
|
|
2018
2127
|
|
|
2019
2128
|
|
|
2020
2129
|
/**
|
|
@@ -2311,37 +2420,63 @@ function addStore(store, env) {
|
|
|
2311
2420
|
*/
|
|
2312
2421
|
class Environment {
|
|
2313
2422
|
/**
|
|
2314
|
-
* @param {
|
|
2423
|
+
* @param {Layout.Node.Name | Layout.Node.Calc | Layout.Node.Value} value
|
|
2315
2424
|
*/
|
|
2316
|
-
exec(value) {
|
|
2317
|
-
if (typeof
|
|
2318
|
-
const item = this.#items[
|
|
2425
|
+
exec({name, calc, value }) {
|
|
2426
|
+
if (typeof name === 'string') {
|
|
2427
|
+
const item = this.#items[name];
|
|
2319
2428
|
if (typeof item?.get !== 'function') { return }
|
|
2320
2429
|
return item.get();
|
|
2321
2430
|
}
|
|
2322
|
-
if (typeof
|
|
2323
|
-
return
|
|
2431
|
+
if (typeof calc === 'function') {
|
|
2432
|
+
return calc(this.getters);
|
|
2324
2433
|
}
|
|
2434
|
+
return value;
|
|
2325
2435
|
}
|
|
2326
2436
|
/**
|
|
2327
|
-
* @param {
|
|
2437
|
+
* @param {Layout.Node.Name | Layout.Node.Calc | Layout.Node.Value} value
|
|
2438
|
+
*/
|
|
2439
|
+
get({name, calc, value}) {
|
|
2440
|
+
if (typeof name === 'string') {
|
|
2441
|
+
const item = this.#items[name];
|
|
2442
|
+
if (typeof item?.get !== 'function') { return }
|
|
2443
|
+
const{get, set} = item;
|
|
2444
|
+
return {get, set};
|
|
2445
|
+
}
|
|
2446
|
+
if (typeof calc === 'function') {
|
|
2447
|
+
const c = new Signal.Computed(() => calc(this.getters));
|
|
2448
|
+
return {get: () => c.get() };
|
|
2449
|
+
}
|
|
2450
|
+
return {get: () => value };
|
|
2451
|
+
}
|
|
2452
|
+
/**
|
|
2453
|
+
* @param {Layout.Node.Name | Layout.Node.Calc | Layout.Node.Value} value
|
|
2328
2454
|
* @param {(value: any) => void} cb
|
|
2329
2455
|
*/
|
|
2330
2456
|
watch(value, cb) { return watch(() => this.exec(value), cb, true); }
|
|
2331
2457
|
|
|
2332
2458
|
/**
|
|
2333
|
-
* @param {
|
|
2459
|
+
* @param {Layout.Node.Name | Layout.Node.Calc | Layout.Node.Value | null} [en]
|
|
2334
2460
|
*/
|
|
2335
|
-
enum(
|
|
2336
|
-
if (!
|
|
2337
|
-
|
|
2338
|
-
if (typeof
|
|
2339
|
-
if (typeof name
|
|
2340
|
-
|
|
2341
|
-
|
|
2342
|
-
|
|
2343
|
-
|
|
2344
|
-
|
|
2461
|
+
enum(en) {
|
|
2462
|
+
if (!en) { return true; }
|
|
2463
|
+
const {name, calc} = en;
|
|
2464
|
+
if (typeof calc === 'function') { return () => calc(this.getters); }
|
|
2465
|
+
if (typeof name === 'string') {
|
|
2466
|
+
const item = this.#items[name];
|
|
2467
|
+
if (typeof item?.get !== 'function') { return null }
|
|
2468
|
+
const store = item.store;
|
|
2469
|
+
return store instanceof Store ? store : item.get;
|
|
2470
|
+
}
|
|
2471
|
+
return this.store;
|
|
2472
|
+
}
|
|
2473
|
+
/**
|
|
2474
|
+
* @param {string | boolean | null} [name]
|
|
2475
|
+
*/
|
|
2476
|
+
getStore(name) {
|
|
2477
|
+
if (!name) { return null; }
|
|
2478
|
+
const item = this.#items[name === true ? '' : name];
|
|
2479
|
+
return item?.get && item.store || null
|
|
2345
2480
|
}
|
|
2346
2481
|
|
|
2347
2482
|
/**
|
|
@@ -2384,6 +2519,29 @@ class Environment {
|
|
|
2384
2519
|
]));
|
|
2385
2520
|
return res;
|
|
2386
2521
|
}
|
|
2522
|
+
/**
|
|
2523
|
+
* @param {string | true} name
|
|
2524
|
+
* @returns {Record<string, {get(): any; set?(v: any): void}> | void}
|
|
2525
|
+
*/
|
|
2526
|
+
getBindAll(name) {
|
|
2527
|
+
const item = this.#items[name === true ? '' : name];
|
|
2528
|
+
if (!item?.get) { return {}; }
|
|
2529
|
+
const { store } = item;
|
|
2530
|
+
if (!store) {
|
|
2531
|
+
const { get, set } = item;
|
|
2532
|
+
return { '$value': {get,set} }
|
|
2533
|
+
}
|
|
2534
|
+
/** @type {Record<string, {get(): any; set?(v: any): void}> | void} */
|
|
2535
|
+
const res = Object.fromEntries([...bindableSet].map(v => [
|
|
2536
|
+
`$${v}`, v === 'value' || v === 'state' ? {
|
|
2537
|
+
get: () => store[v],
|
|
2538
|
+
set: (s)=>{store[v] = s;}
|
|
2539
|
+
} : {
|
|
2540
|
+
get: () => store[v],
|
|
2541
|
+
}
|
|
2542
|
+
]));
|
|
2543
|
+
return res;
|
|
2544
|
+
}
|
|
2387
2545
|
/**
|
|
2388
2546
|
* @param {string | true} name
|
|
2389
2547
|
* @param {string} type
|
|
@@ -2427,12 +2585,12 @@ class Environment {
|
|
|
2427
2585
|
}
|
|
2428
2586
|
|
|
2429
2587
|
/**
|
|
2430
|
-
* @param {
|
|
2588
|
+
* @param {Layout.Node.Name | Layout.Node.Event} event
|
|
2431
2589
|
* @returns {Layout.EventListener?}
|
|
2432
2590
|
*/
|
|
2433
|
-
getEvent(event) {
|
|
2591
|
+
getEvent({name, event}) {
|
|
2434
2592
|
if (typeof event === 'function') { return event }
|
|
2435
|
-
const item = this.#items[
|
|
2593
|
+
const item = this.#items[name];
|
|
2436
2594
|
if (!item) { return null }
|
|
2437
2595
|
const {exec, calc} = item;
|
|
2438
2596
|
if (typeof exec === 'function') { return exec }
|
|
@@ -2550,45 +2708,55 @@ class Environment {
|
|
|
2550
2708
|
const items = cloned.#items;
|
|
2551
2709
|
for (const [key, param] of Object.entries(params)) {
|
|
2552
2710
|
const attr = key in attrs ? attrs[key] : null;
|
|
2553
|
-
if (
|
|
2554
|
-
|
|
2555
|
-
|
|
2556
|
-
|
|
2557
|
-
|
|
2558
|
-
|
|
2559
|
-
|
|
2711
|
+
if (attr) {
|
|
2712
|
+
const {name, calc, value} = attr;
|
|
2713
|
+
if (name) {
|
|
2714
|
+
const item = sourceEnv.#items[name];
|
|
2715
|
+
if (!item?.get) { continue; }
|
|
2716
|
+
if (!item.store) {
|
|
2717
|
+
explicit[key] = items[key] = item;
|
|
2718
|
+
continue;
|
|
2719
|
+
}
|
|
2720
|
+
for (const [k, it] of toItem(item.store, key)) {
|
|
2721
|
+
explicit[k] = items[k] = it;
|
|
2722
|
+
}
|
|
2560
2723
|
continue;
|
|
2561
|
-
}
|
|
2562
|
-
|
|
2563
|
-
explicit[
|
|
2724
|
+
} else if (typeof calc === 'function') {
|
|
2725
|
+
const val = new Signal.Computed(() => calc(sourceEnv.getters));
|
|
2726
|
+
explicit[key] = items[key] = {
|
|
2727
|
+
get: () => { return val.get(); },
|
|
2728
|
+
};
|
|
2729
|
+
continue;
|
|
2730
|
+
} else {
|
|
2731
|
+
explicit[key] = items[key] = {get: () => value};
|
|
2564
2732
|
}
|
|
2565
2733
|
continue;
|
|
2566
|
-
|
|
2567
|
-
} else if (typeof attr === 'function') {
|
|
2568
|
-
const val = new Signal.Computed(() => attr(sourceEnv.getters));
|
|
2569
|
-
explicit[key] = items[key] = {
|
|
2570
|
-
get: () => { return val.get(); },
|
|
2571
|
-
};
|
|
2572
|
-
continue;
|
|
2573
|
-
} else if (typeof param === 'function') {
|
|
2574
|
-
const getters = cloned.getters;
|
|
2575
|
-
cloned.#getters = null;
|
|
2576
|
-
const val = new Signal.Computed(() => param(getters));
|
|
2577
|
-
explicit[key] = items[key] = {
|
|
2578
|
-
get: () => { return val.get(); },
|
|
2579
|
-
};
|
|
2580
|
-
continue;
|
|
2581
2734
|
} else {
|
|
2582
|
-
const
|
|
2583
|
-
if (
|
|
2584
|
-
|
|
2585
|
-
|
|
2735
|
+
const {name, calc, value} = param;
|
|
2736
|
+
if (typeof calc === 'function') {
|
|
2737
|
+
const getters = cloned.getters;
|
|
2738
|
+
cloned.#getters = null;
|
|
2739
|
+
const val = new Signal.Computed(() => calc(getters));
|
|
2740
|
+
explicit[key] = items[key] = {
|
|
2741
|
+
get: () => { return val.get(); },
|
|
2742
|
+
};
|
|
2586
2743
|
continue;
|
|
2744
|
+
} else if (name) {
|
|
2745
|
+
const item = items[name];
|
|
2746
|
+
if (!item?.get) { continue; }
|
|
2747
|
+
if (!item.store) {
|
|
2748
|
+
explicit[key] = items[key] = item;
|
|
2749
|
+
continue;
|
|
2750
|
+
}
|
|
2751
|
+
for (const [k, it] of toItem(item.store, key)) {
|
|
2752
|
+
explicit[k] = items[k] = it;
|
|
2753
|
+
}
|
|
2754
|
+
continue;
|
|
2755
|
+
} else {
|
|
2756
|
+
explicit[key] = items[key] = {get: () => value};
|
|
2757
|
+
continue;
|
|
2758
|
+
|
|
2587
2759
|
}
|
|
2588
|
-
for (const [k, it] of toItem(item.store, key)) {
|
|
2589
|
-
explicit[k] = items[k] = it;
|
|
2590
|
-
}
|
|
2591
|
-
continue;
|
|
2592
2760
|
}
|
|
2593
2761
|
}
|
|
2594
2762
|
return cloned;
|
|
@@ -2601,8 +2769,8 @@ class Environment {
|
|
|
2601
2769
|
}
|
|
2602
2770
|
/**
|
|
2603
2771
|
*
|
|
2604
|
-
* @param {Record<string,
|
|
2605
|
-
* @param {Record<string,
|
|
2772
|
+
* @param {Record<string, Layout.Node.Name | Layout.Node.Calc | Layout.Node.Value>} aliases
|
|
2773
|
+
* @param {Record<string, Layout.Node.Name | Layout.Node.Calc | Layout.Node.Value>} vars
|
|
2606
2774
|
*/
|
|
2607
2775
|
set(aliases, vars) {
|
|
2608
2776
|
if (Object.keys(aliases).length + Object.keys(vars).length === 0) { return this; }
|
|
@@ -2611,35 +2779,40 @@ class Environment {
|
|
|
2611
2779
|
cloned.#object = this.#object;
|
|
2612
2780
|
const explicit = cloned.#explicit;
|
|
2613
2781
|
const items = cloned.#items;
|
|
2614
|
-
for (const [key, name] of Object.entries(aliases)) {
|
|
2615
|
-
if (typeof
|
|
2782
|
+
for (const [key, {name, calc, value}] of Object.entries(aliases)) {
|
|
2783
|
+
if (typeof calc === 'function') {
|
|
2616
2784
|
const getters = cloned.getters;
|
|
2617
2785
|
cloned.#getters = null;
|
|
2618
|
-
const val = new Signal.Computed(() =>
|
|
2786
|
+
const val = new Signal.Computed(() => calc(getters));
|
|
2619
2787
|
explicit[key] = items[key] = {
|
|
2620
2788
|
get: () => { return val.get(); },
|
|
2621
2789
|
};
|
|
2622
2790
|
continue;
|
|
2623
2791
|
}
|
|
2624
|
-
|
|
2625
|
-
|
|
2626
|
-
|
|
2627
|
-
|
|
2792
|
+
if (name) {
|
|
2793
|
+
const item = items[name];
|
|
2794
|
+
if (!item) { continue; }
|
|
2795
|
+
if (!item.get || !item.store) {
|
|
2796
|
+
explicit[key] = items[key] = item;
|
|
2797
|
+
continue;
|
|
2798
|
+
}
|
|
2799
|
+
for (const [k, it] of toItem(item.store, key)) {
|
|
2800
|
+
explicit[k] = items[k] = it;
|
|
2801
|
+
}
|
|
2628
2802
|
continue;
|
|
2629
2803
|
}
|
|
2630
|
-
|
|
2631
|
-
|
|
2632
|
-
}
|
|
2804
|
+
explicit[key] = items[key] = { get: () => { return value; } };
|
|
2805
|
+
continue;
|
|
2633
2806
|
}
|
|
2634
|
-
for (const [k,
|
|
2807
|
+
for (const [k,{name, calc, value}] of Object.entries(vars)) {
|
|
2635
2808
|
|
|
2636
|
-
const val = new Signal.State(/** @type {any} */(
|
|
2637
|
-
if (typeof
|
|
2809
|
+
const val = new Signal.State(/** @type {any} */(value));
|
|
2810
|
+
if (typeof calc === 'function') {
|
|
2638
2811
|
const settable = cloned.settable;
|
|
2639
2812
|
cloned.#settable = null;
|
|
2640
|
-
val.set(
|
|
2641
|
-
} else if (
|
|
2642
|
-
const item = items[
|
|
2813
|
+
val.set(calc(settable));
|
|
2814
|
+
} else if (name) {
|
|
2815
|
+
const item = items[name];
|
|
2643
2816
|
if (!item?.get) { continue }
|
|
2644
2817
|
val.set(item.get());
|
|
2645
2818
|
}
|
|
@@ -2750,44 +2923,44 @@ class Environment {
|
|
|
2750
2923
|
/**
|
|
2751
2924
|
* @param {Component.Handler} handler
|
|
2752
2925
|
* @param {Environment} envs
|
|
2753
|
-
* @param {Record<string,
|
|
2926
|
+
* @param {Record<string, Layout.Node.Name | Layout.Node.Calc | Layout.Node.Value>} attrs
|
|
2754
2927
|
* @param {Record<string, Component.Attr>} componentAttrs
|
|
2755
2928
|
* @param {string | boolean | null} [bindValue]
|
|
2756
2929
|
*/
|
|
2757
2930
|
function bindAttrs(handler, envs, attrs, componentAttrs, bindValue) {
|
|
2758
2931
|
|
|
2759
2932
|
let bk = new Set();
|
|
2760
|
-
for (const [
|
|
2761
|
-
|
|
2762
|
-
if (
|
|
2763
|
-
|
|
2764
|
-
|
|
2933
|
+
for (const [key, attr] of Object.entries(componentAttrs)) {
|
|
2934
|
+
if (key === 'class' || key === 'style') { continue; }
|
|
2935
|
+
if (key in attrs) {
|
|
2936
|
+
const attrDefine = attrs[key];
|
|
2937
|
+
const { name, calc, value } = attrs[key];
|
|
2938
|
+
if (!name && !calc) {
|
|
2939
|
+
handler.set(key, value);
|
|
2765
2940
|
continue;
|
|
2766
2941
|
}
|
|
2767
|
-
const attrSchema = typeof attrValue === 'function' ? /** @type{Layout.Calc} */(attrValue) : attrValue.name;
|
|
2768
2942
|
if (attr.immutable) {
|
|
2769
|
-
handler.set(
|
|
2770
|
-
continue;
|
|
2943
|
+
handler.set(key, envs.exec(attrDefine));
|
|
2771
2944
|
}
|
|
2772
|
-
bk.add(envs.watch(
|
|
2945
|
+
bk.add(envs.watch(attrDefine, v => handler.set(key, v)));
|
|
2773
2946
|
continue;
|
|
2774
2947
|
}
|
|
2775
2948
|
const bind = attr.bind;
|
|
2776
2949
|
if (!bindValue || !bind) {
|
|
2777
|
-
handler.set(
|
|
2950
|
+
handler.set(key, attr.default);
|
|
2778
2951
|
continue;
|
|
2779
2952
|
}
|
|
2780
2953
|
if (typeof bind === 'string') {
|
|
2781
|
-
const r = envs.bind(bindValue, bind, v => handler.set(
|
|
2954
|
+
const r = envs.bind(bindValue, bind, v => handler.set(key, v));
|
|
2782
2955
|
if (r) {
|
|
2783
2956
|
bk.add(r);
|
|
2784
2957
|
} else {
|
|
2785
|
-
handler.set(
|
|
2958
|
+
handler.set(key, attr.default);
|
|
2786
2959
|
}
|
|
2787
2960
|
continue;
|
|
2788
2961
|
}
|
|
2789
2962
|
if (!Array.isArray(bind)) {
|
|
2790
|
-
handler.set(
|
|
2963
|
+
handler.set(key, attr.default);
|
|
2791
2964
|
continue;
|
|
2792
2965
|
}
|
|
2793
2966
|
const [event, set, isState] = bind;
|
|
@@ -2796,11 +2969,11 @@ function bindAttrs(handler, envs, attrs, componentAttrs, bindValue) {
|
|
|
2796
2969
|
}
|
|
2797
2970
|
if (!isState) {
|
|
2798
2971
|
const bindKey = bindValue === true ? '' : bindValue;
|
|
2799
|
-
bk.add(envs.watch(bindKey, v => handler.set(
|
|
2972
|
+
bk.add(envs.watch({name: bindKey}, v => handler.set(key, v)));
|
|
2800
2973
|
handler.addEvent(event, (...args) => { envs.all[bindKey] = set(...args);});
|
|
2801
2974
|
continue;
|
|
2802
2975
|
}
|
|
2803
|
-
const r = envs.bind(bindValue, 'state', v => handler.set(
|
|
2976
|
+
const r = envs.bind(bindValue, 'state', v => handler.set(key, v));
|
|
2804
2977
|
if (!r) { continue; }
|
|
2805
2978
|
bk.add(r);
|
|
2806
2979
|
const s = envs.bindSet(bindValue, 'state');
|
|
@@ -2824,23 +2997,24 @@ function bindAttrs(handler, envs, attrs, componentAttrs, bindValue) {
|
|
|
2824
2997
|
/**
|
|
2825
2998
|
* @param {Component.Handler} handler
|
|
2826
2999
|
* @param {Environment} envs
|
|
2827
|
-
* @param {Record<string,
|
|
3000
|
+
* @param {Record<string, Layout.Node.Name | Layout.Node.Calc | Layout.Node.Value>} attrs
|
|
2828
3001
|
*/
|
|
2829
3002
|
function bindBaseAttrs(handler, envs, attrs) {
|
|
2830
3003
|
const tag = handler.tag;
|
|
2831
3004
|
let bk = new Set();
|
|
2832
|
-
for (const [
|
|
2833
|
-
if (
|
|
2834
|
-
|
|
3005
|
+
for (const [key, attr] of Object.entries(attrs)) {
|
|
3006
|
+
if (key === 'class' || key === 'style') { continue; }
|
|
3007
|
+
const {name, calc, value} = attr;
|
|
3008
|
+
if (!name && !calc) {
|
|
3009
|
+
handler.set(key, value);
|
|
2835
3010
|
continue;
|
|
2836
3011
|
}
|
|
2837
|
-
|
|
2838
|
-
|
|
2839
|
-
|
|
2840
|
-
handler.set(name, value);
|
|
3012
|
+
if (typeof tag === 'string' && tag.toLocaleLowerCase() === 'input' && key.toLocaleLowerCase() === 'type') {
|
|
3013
|
+
const value = envs.exec(attr);
|
|
3014
|
+
handler.set(key, value);
|
|
2841
3015
|
continue;
|
|
2842
3016
|
}
|
|
2843
|
-
bk.add(envs.watch(
|
|
3017
|
+
bk.add(envs.watch(attr, val => handler.set(key, val)));
|
|
2844
3018
|
}
|
|
2845
3019
|
|
|
2846
3020
|
return ()=> {
|
|
@@ -2858,26 +3032,29 @@ function bindBaseAttrs(handler, envs, attrs) {
|
|
|
2858
3032
|
/**
|
|
2859
3033
|
* @param {Node} node
|
|
2860
3034
|
* @param {Environment} envs
|
|
2861
|
-
* @param {Record<string,
|
|
3035
|
+
* @param {Record<string, Layout.Node.Name | Layout.Node.Calc | Layout.Node.Value>} classes
|
|
3036
|
+
* @param {Layout.Node.Name | Layout.Node.Calc | Layout.Node.Value} [classAttr]
|
|
2862
3037
|
*/
|
|
2863
|
-
function bindClasses(node, classes,
|
|
3038
|
+
function bindClasses(node, envs, classes, classAttr) {
|
|
2864
3039
|
if (!(node instanceof Element)) {
|
|
2865
3040
|
return () => {};
|
|
2866
3041
|
}
|
|
3042
|
+
if (classAttr) {
|
|
3043
|
+
node.className += ' ' + envs.exec(classAttr);
|
|
3044
|
+
}
|
|
2867
3045
|
|
|
2868
3046
|
/** @type {Set<() => void>?} */
|
|
2869
3047
|
let bk = new Set();
|
|
2870
|
-
for (const [
|
|
2871
|
-
if (
|
|
2872
|
-
|
|
2873
|
-
node.classList.add(name);
|
|
3048
|
+
for (const [key, attr] of Object.entries(classes)) {
|
|
3049
|
+
if (attr.value) {
|
|
3050
|
+
node.classList.add(key);
|
|
2874
3051
|
continue;
|
|
2875
3052
|
}
|
|
2876
3053
|
bk.add(watch(() => Boolean(envs.exec(attr)), value => {
|
|
2877
3054
|
if (value) {
|
|
2878
|
-
node.classList.add(
|
|
3055
|
+
node.classList.add(key);
|
|
2879
3056
|
} else {
|
|
2880
|
-
node.classList.remove(
|
|
3057
|
+
node.classList.remove(key);
|
|
2881
3058
|
}
|
|
2882
3059
|
}, true));
|
|
2883
3060
|
}
|
|
@@ -2961,16 +3138,20 @@ function toStyle(name, value) {
|
|
|
2961
3138
|
/**
|
|
2962
3139
|
* @param {Element} node
|
|
2963
3140
|
* @param {Environment} envs
|
|
2964
|
-
* @param {Record<string,
|
|
3141
|
+
* @param {Record<string, Layout.Node.Name | Layout.Node.Calc | Layout.Node.Value>} styles
|
|
3142
|
+
* @param {Layout.Node.Name | Layout.Node.Calc | Layout.Node.Value} [styleAttr]
|
|
2965
3143
|
*/
|
|
2966
|
-
function bindStyles(node,
|
|
3144
|
+
function bindStyles(node, envs, styles, styleAttr) {
|
|
2967
3145
|
if (!(node instanceof HTMLElement) && !(node instanceof SVGElement)) {
|
|
2968
3146
|
return () => {};
|
|
2969
3147
|
}
|
|
3148
|
+
if (styleAttr) {
|
|
3149
|
+
node.setAttribute('style', node.getAttribute('style') + ';' + envs.exec(styleAttr));
|
|
3150
|
+
}
|
|
2970
3151
|
|
|
2971
3152
|
/** @type {Set<() => void>?} */
|
|
2972
3153
|
let bk = new Set();
|
|
2973
|
-
for (const [name, attr] of Object.entries(
|
|
3154
|
+
for (const [name, attr] of Object.entries(styles)) {
|
|
2974
3155
|
bk.add(watch(() => toStyle(name, envs.exec(attr)), value => {
|
|
2975
3156
|
if (value) {
|
|
2976
3157
|
node.style.setProperty(name, ...value);
|
|
@@ -3032,9 +3213,10 @@ class EventEmitter {
|
|
|
3032
3213
|
}
|
|
3033
3214
|
}
|
|
3034
3215
|
|
|
3035
|
-
/** @import { Component } from '../types.mjs' */
|
|
3216
|
+
/** @import { Component, Relatedness } from '../types.mjs' */
|
|
3036
3217
|
/** @import Store from '../Store/index.mjs' */
|
|
3037
3218
|
/** @import Environment from './Environment/index.mjs' */
|
|
3219
|
+
/** @import * as Layout from '../Layout/index.mjs' */
|
|
3038
3220
|
|
|
3039
3221
|
|
|
3040
3222
|
/** @type {Record<string, Component.Event.Filter>} */
|
|
@@ -3154,14 +3336,68 @@ const eventFilters = {
|
|
|
3154
3336
|
}
|
|
3155
3337
|
},
|
|
3156
3338
|
};
|
|
3339
|
+
/**
|
|
3340
|
+
*
|
|
3341
|
+
* @param {string[]} fs
|
|
3342
|
+
* @param {Record<string, string | Component.Event.Filter>} filters
|
|
3343
|
+
* @param {AddEventListenerOptions?} [options]
|
|
3344
|
+
* @returns
|
|
3345
|
+
*/
|
|
3346
|
+
function findFilters(fs, filters, options) {
|
|
3347
|
+
/** @type {[Component.Event.Filter, string[], boolean][]} */
|
|
3348
|
+
const filterFns = [];
|
|
3349
|
+
if (filters) for (let f = fs.shift(); f; f = fs.shift()) {
|
|
3350
|
+
const paramIndex = f.indexOf(':');
|
|
3351
|
+
const noParamName = paramIndex >= 0 ? f.slice(0, paramIndex) : f;
|
|
3352
|
+
const param = paramIndex >= 0 ? f.slice(paramIndex + 1).split(':') : [];
|
|
3353
|
+
const filterName = noParamName.replace(/^-+/, '');
|
|
3354
|
+
const sub = (noParamName.length - filterName.length) % 2 === 1;
|
|
3355
|
+
let filter = filters[filterName] || filterName;
|
|
3356
|
+
if (options) {
|
|
3357
|
+
switch (filter) {
|
|
3358
|
+
case 'once': case 'passive': case 'capture': options[filter] = !sub; continue;
|
|
3359
|
+
}
|
|
3360
|
+
}
|
|
3361
|
+
if (typeof filter === 'string') {
|
|
3362
|
+
filter = eventFilters[filter];
|
|
3363
|
+
}
|
|
3364
|
+
if (typeof filter !== 'function') { continue; }
|
|
3365
|
+
filterFns.push([filter, param, sub]);
|
|
3366
|
+
}
|
|
3367
|
+
return filterFns;
|
|
3368
|
+
}
|
|
3369
|
+
|
|
3370
|
+
/**
|
|
3371
|
+
*
|
|
3372
|
+
* @param {Environment} env
|
|
3373
|
+
* @param {Layout.EventListener} fn
|
|
3374
|
+
* @param {[Component.Event.Filter, string[], boolean][]} filterFns
|
|
3375
|
+
* @returns {($event: any) => void}
|
|
3376
|
+
*/
|
|
3377
|
+
function bindFilters(env, fn, filterFns) {
|
|
3378
|
+
return $event => {
|
|
3379
|
+
const global = env.all;
|
|
3380
|
+
for (const [filter, param, sub] of filterFns) {
|
|
3381
|
+
if (filter($event, param, global) === sub) { return; }
|
|
3382
|
+
}
|
|
3383
|
+
fn($event, global);
|
|
3384
|
+
}
|
|
3385
|
+
}
|
|
3386
|
+
|
|
3387
|
+
/** @import { Component, Relatedness } from '../types.mjs' */
|
|
3388
|
+
/** @import Store from '../Store/index.mjs' */
|
|
3389
|
+
/** @import Environment from './Environment/index.mjs' */
|
|
3390
|
+
|
|
3391
|
+
|
|
3157
3392
|
/**
|
|
3158
3393
|
*
|
|
3159
3394
|
* @param {Component | string} component
|
|
3160
3395
|
* @param {Environment} env
|
|
3161
|
-
* @param {
|
|
3396
|
+
* @param {Store?} store
|
|
3397
|
+
* @param {((store: Store, el: Element | Relatedness) => () => void)?} [relate]
|
|
3162
3398
|
* @returns
|
|
3163
3399
|
*/
|
|
3164
|
-
function createContext(component, env, relate) {
|
|
3400
|
+
function createContext(component, env, store, relate) {
|
|
3165
3401
|
const tag = typeof component === 'string' ? component : component.tag;
|
|
3166
3402
|
const { attrs, events } = typeof component !== 'string' && component || { attrs: null, events: null };
|
|
3167
3403
|
|
|
@@ -3202,9 +3438,9 @@ function createContext(component, env, relate) {
|
|
|
3202
3438
|
};
|
|
3203
3439
|
},
|
|
3204
3440
|
relate(el) {
|
|
3205
|
-
if (!relate || destroyed) { return () => { }; }
|
|
3441
|
+
if (!store || !relate || destroyed) { return () => { }; }
|
|
3206
3442
|
try {
|
|
3207
|
-
const w = relate(
|
|
3443
|
+
const w = relate(store, el);
|
|
3208
3444
|
if (typeof w !== 'function') { return () => { }; }
|
|
3209
3445
|
cancelFns.add(w);
|
|
3210
3446
|
return () => {
|
|
@@ -3245,40 +3481,8 @@ function createContext(component, env, relate) {
|
|
|
3245
3481
|
if (!filters) { return; }
|
|
3246
3482
|
/** @type {AddEventListenerOptions} */
|
|
3247
3483
|
const options = {};
|
|
3248
|
-
|
|
3249
|
-
|
|
3250
|
-
if (filters) for (let f = fs.shift(); f; f = fs.shift()) {
|
|
3251
|
-
const paramIndex = f.indexOf(':');
|
|
3252
|
-
const noParamName = paramIndex >= 0 ? f.slice(0, paramIndex) : f;
|
|
3253
|
-
const param = paramIndex >= 0 ? f.slice(paramIndex + 1).split(':') : [];
|
|
3254
|
-
const filterName = noParamName.replace(/^-+/, '');
|
|
3255
|
-
const sub = (noParamName.length - filterName.length) % 2 === 1;
|
|
3256
|
-
let filter = filters[filterName] || filterName;
|
|
3257
|
-
switch (filter) {
|
|
3258
|
-
case 'once':
|
|
3259
|
-
options.once = !sub;
|
|
3260
|
-
break;
|
|
3261
|
-
case 'passive':
|
|
3262
|
-
options.passive = !sub;
|
|
3263
|
-
break;
|
|
3264
|
-
case 'capture':
|
|
3265
|
-
options.capture = !sub;
|
|
3266
|
-
break;
|
|
3267
|
-
default:
|
|
3268
|
-
if (typeof filter === 'string') {
|
|
3269
|
-
filter = eventFilters[filter];
|
|
3270
|
-
}
|
|
3271
|
-
}
|
|
3272
|
-
if (typeof filter !== 'function') { continue; }
|
|
3273
|
-
filterFns.push([filter, param, sub]);
|
|
3274
|
-
}
|
|
3275
|
-
allEvents.push([e, $event => {
|
|
3276
|
-
const global = env.all;
|
|
3277
|
-
for (const [filter, param, sub] of filterFns) {
|
|
3278
|
-
if (filter($event, param, global) === sub) { return; }
|
|
3279
|
-
}
|
|
3280
|
-
fn($event, global);
|
|
3281
|
-
}, options]);
|
|
3484
|
+
const filterFns = findFilters(fs, filters, options);
|
|
3485
|
+
allEvents.push([e, bindFilters(env, fn, filterFns), options]);
|
|
3282
3486
|
},
|
|
3283
3487
|
destroy() {
|
|
3284
3488
|
if (destroyed) { return; }
|
|
@@ -3468,6 +3672,9 @@ const tagBindMap = {
|
|
|
3468
3672
|
function createTagComponent (context, name, is) {
|
|
3469
3673
|
const node = document.createElement(name, {is: is || undefined});
|
|
3470
3674
|
const { watchAttr, props } = context;
|
|
3675
|
+
if(['input', 'textarea', 'select'].includes(name.toLowerCase())) {
|
|
3676
|
+
context.relate(node);
|
|
3677
|
+
}
|
|
3471
3678
|
|
|
3472
3679
|
context.listen('init', ({events})=> {
|
|
3473
3680
|
const e = tagBindMap[name.toLowerCase()];
|
|
@@ -3646,7 +3853,7 @@ function toText(val) {
|
|
|
3646
3853
|
* @param {Element} parent
|
|
3647
3854
|
* @param {Node?} next
|
|
3648
3855
|
* @param {Environment} envs
|
|
3649
|
-
* @param {Layout.
|
|
3856
|
+
* @param {Layout.Node} layout
|
|
3650
3857
|
*/
|
|
3651
3858
|
function renderFillDirectives(parent, next, envs, { text, html }) {
|
|
3652
3859
|
if (text != null) {
|
|
@@ -3700,18 +3907,18 @@ function renderList(layouts, parent, next, envs, templates, renderItem) {
|
|
|
3700
3907
|
|
|
3701
3908
|
/** @type {Set<() => void>?} */
|
|
3702
3909
|
let bkList = new Set();
|
|
3703
|
-
/** @type {[
|
|
3910
|
+
/** @type {[Layout.Node.Name | Layout.Node.Calc | Layout.Node.Value | null, Layout.Node][]} */
|
|
3704
3911
|
let ifList = [];
|
|
3705
3912
|
/** @type {Record<string, [Layout.Node, Environment]>} */
|
|
3706
3913
|
let currentTemplates = Object.create(templates);
|
|
3707
3914
|
for (const layout of layouts) {
|
|
3708
3915
|
if (typeof layout === 'string') { continue; }
|
|
3709
|
-
const name = layout.
|
|
3916
|
+
const name = layout.template;
|
|
3710
3917
|
if (!name) { continue; }
|
|
3711
3918
|
currentTemplates[name] = [layout, envs];
|
|
3712
3919
|
}
|
|
3713
3920
|
|
|
3714
|
-
/** @param {[
|
|
3921
|
+
/** @param {[Layout.Node.Name | Layout.Node.Calc | Layout.Node.Value | null, Layout.Node][]} list */
|
|
3715
3922
|
function renderIf(list) {
|
|
3716
3923
|
if (!list.length || !bkList) { return; }
|
|
3717
3924
|
const end = parent.insertBefore(document.createComment(''), next);
|
|
@@ -3735,7 +3942,7 @@ function renderList(layouts, parent, next, envs, templates, renderItem) {
|
|
|
3735
3942
|
end.remove();
|
|
3736
3943
|
});
|
|
3737
3944
|
bkList.add(watch(
|
|
3738
|
-
() => list.findIndex(([ifv]) => ifv
|
|
3945
|
+
() => list.findIndex(([ifv]) => !ifv || envs.exec(ifv)),
|
|
3739
3946
|
index => {
|
|
3740
3947
|
if (index === lastIndex) { return; }
|
|
3741
3948
|
lastIndex = index;
|
|
@@ -3754,13 +3961,13 @@ function renderList(layouts, parent, next, envs, templates, renderItem) {
|
|
|
3754
3961
|
bkList.add(() => node.remove());
|
|
3755
3962
|
continue;
|
|
3756
3963
|
}
|
|
3757
|
-
if (layout.
|
|
3964
|
+
if (layout.template) {
|
|
3758
3965
|
renderIf(ifList);
|
|
3759
3966
|
ifList = [];
|
|
3760
3967
|
continue;
|
|
3761
3968
|
}
|
|
3762
|
-
if (ifList.length && layout.
|
|
3763
|
-
const ifv = layout.
|
|
3969
|
+
if (ifList.length && layout.else) {
|
|
3970
|
+
const ifv = layout.if || null;
|
|
3764
3971
|
ifList.push([ifv, layout]);
|
|
3765
3972
|
if (!ifv) {
|
|
3766
3973
|
renderIf(ifList);
|
|
@@ -3770,7 +3977,7 @@ function renderList(layouts, parent, next, envs, templates, renderItem) {
|
|
|
3770
3977
|
}
|
|
3771
3978
|
renderIf(ifList);
|
|
3772
3979
|
ifList = [];
|
|
3773
|
-
const ifv = layout.
|
|
3980
|
+
const ifv = layout.if;
|
|
3774
3981
|
if (ifv) {
|
|
3775
3982
|
ifList.push([ifv, layout]);
|
|
3776
3983
|
continue;
|
|
@@ -3779,6 +3986,7 @@ function renderList(layouts, parent, next, envs, templates, renderItem) {
|
|
|
3779
3986
|
renderItem(layout, currentTemplates)
|
|
3780
3987
|
);
|
|
3781
3988
|
}
|
|
3989
|
+
renderIf(ifList);
|
|
3782
3990
|
|
|
3783
3991
|
return () => {
|
|
3784
3992
|
if (!bkList) { return; }
|
|
@@ -3925,6 +4133,135 @@ function bindBase(handler, env, bind) {
|
|
|
3925
4133
|
}
|
|
3926
4134
|
}
|
|
3927
4135
|
|
|
4136
|
+
/** @import Environment from './Environment/index.mjs' */
|
|
4137
|
+
/** @import { Enhancement } from '../types.mjs' */
|
|
4138
|
+
/** @import * as Layout from '../Layout/index.mjs' */
|
|
4139
|
+
|
|
4140
|
+
/**
|
|
4141
|
+
*
|
|
4142
|
+
* @param {object} obj
|
|
4143
|
+
* @param {string} name
|
|
4144
|
+
* @returns
|
|
4145
|
+
*/
|
|
4146
|
+
const hasOwnProperty = (obj, name) => Object.prototype.hasOwnProperty.call(obj, name);
|
|
4147
|
+
/**
|
|
4148
|
+
* @param {any} tag
|
|
4149
|
+
* @param {Record<string, Layout.Enhancement>} enhancementDefine
|
|
4150
|
+
* @param {Environment} env
|
|
4151
|
+
* @param {Record<string, Enhancement>} enhancements
|
|
4152
|
+
* @param {Element} root
|
|
4153
|
+
* @param {Element?} [slot]
|
|
4154
|
+
*/
|
|
4155
|
+
function bindEnhancements(tag, enhancementDefine, env, enhancements, root, slot) {
|
|
4156
|
+
|
|
4157
|
+
let bk = new Set();
|
|
4158
|
+
for (const [name, { attrs: attrDefine, value, events: eventsDefine, bind }] of Object.entries(enhancementDefine)) {
|
|
4159
|
+
if (!hasOwnProperty(enhancements, name)) { continue; }
|
|
4160
|
+
const enhancement = enhancements[name];
|
|
4161
|
+
if (typeof enhancement !== 'function') { continue; }
|
|
4162
|
+
|
|
4163
|
+
|
|
4164
|
+
let destroyed = false;
|
|
4165
|
+
const destroyedState = new Signal.State(false);
|
|
4166
|
+
const events = /** @type {any} */(enhancement)?.events;
|
|
4167
|
+
/** @type {[string, ($event: any) => void, AddEventListenerOptions][]} */
|
|
4168
|
+
const allEvents = [];
|
|
4169
|
+
const attrs = Object.create(null);
|
|
4170
|
+
/** @type {Set<() => void>} */
|
|
4171
|
+
const cancelFns = new Set();
|
|
4172
|
+
const stateEmitter = new EventEmitter();
|
|
4173
|
+
|
|
4174
|
+
/**
|
|
4175
|
+
*
|
|
4176
|
+
* @param {string} name
|
|
4177
|
+
* @param {Layout.EventListener} fn
|
|
4178
|
+
* @returns
|
|
4179
|
+
*/
|
|
4180
|
+
function addEvent(name, fn) {
|
|
4181
|
+
if (typeof fn !== 'function') { return; }
|
|
4182
|
+
const [e, ...fs] = name.split('.').filter(Boolean);
|
|
4183
|
+
const filters = events ? events[e].filters : {};
|
|
4184
|
+
if (!filters) { return; }
|
|
4185
|
+
/** @type {AddEventListenerOptions} */
|
|
4186
|
+
const options = {};
|
|
4187
|
+
const filterFns = findFilters(fs, filters, options);
|
|
4188
|
+
allEvents.push([e, bindFilters(env, fn, filterFns), options]);
|
|
4189
|
+
}
|
|
4190
|
+
function destroy() {
|
|
4191
|
+
if (destroyed) { return; }
|
|
4192
|
+
destroyed = true;
|
|
4193
|
+
destroyedState.set(true);
|
|
4194
|
+
for (const w of cancelFns) {
|
|
4195
|
+
w();
|
|
4196
|
+
}
|
|
4197
|
+
stateEmitter.emit('destroy');
|
|
4198
|
+
}
|
|
4199
|
+
bk.add(destroy);
|
|
4200
|
+
|
|
4201
|
+
|
|
4202
|
+
|
|
4203
|
+
for (const [name, attr] of Object.entries(attrDefine)) {
|
|
4204
|
+
const s = env.get(attr);
|
|
4205
|
+
if (!s) { continue; }
|
|
4206
|
+
Object.defineProperty(attrs, name, { ...s, configurable: true, enumerable: true });
|
|
4207
|
+
}
|
|
4208
|
+
|
|
4209
|
+
for (const [name, event] of Object.entries(eventsDefine)) {
|
|
4210
|
+
const fn = env.getEvent(event);
|
|
4211
|
+
if (fn) { addEvent(name, fn); }
|
|
4212
|
+
}
|
|
4213
|
+
|
|
4214
|
+
if (bind) {
|
|
4215
|
+
for (const [key, effect] of Object.entries(env.getBindAll(bind) || {})) {
|
|
4216
|
+
Object.defineProperty(attrs, key, { ...effect, configurable: true, enumerable: true });
|
|
4217
|
+
}
|
|
4218
|
+
for (const [key, setter] of Object.entries(env.bindEvents(bind) || {})) {
|
|
4219
|
+
addEvent(key, $event => setter($event));
|
|
4220
|
+
}
|
|
4221
|
+
|
|
4222
|
+
}
|
|
4223
|
+
/**@type {Enhancement.Context} */
|
|
4224
|
+
const context = {
|
|
4225
|
+
get value() { return null; },
|
|
4226
|
+
events: allEvents,
|
|
4227
|
+
attrs: attrs,
|
|
4228
|
+
watchAttr(name, fn) {
|
|
4229
|
+
if (destroyed) { return () => { }; }
|
|
4230
|
+
let old = attrs[name];
|
|
4231
|
+
const w = watch(() => attrs[name], v => {
|
|
4232
|
+
const o = old;
|
|
4233
|
+
old = v;
|
|
4234
|
+
fn(v, o, name);
|
|
4235
|
+
}, true);
|
|
4236
|
+
cancelFns.add(w);
|
|
4237
|
+
|
|
4238
|
+
return () => {
|
|
4239
|
+
cancelFns.delete(w);
|
|
4240
|
+
w();
|
|
4241
|
+
};
|
|
4242
|
+
},
|
|
4243
|
+
get destroyed() { return destroyedState.get(); },
|
|
4244
|
+
listen(name, listener) { return stateEmitter.listen(name, listener); },
|
|
4245
|
+
root, slot,
|
|
4246
|
+
tag,
|
|
4247
|
+
};
|
|
4248
|
+
if (value) {
|
|
4249
|
+
const s = env.get(value);
|
|
4250
|
+
if (s) {
|
|
4251
|
+
Object.defineProperty(context, 'value', { ...s, configurable: true, enumerable: true });
|
|
4252
|
+
}
|
|
4253
|
+
}
|
|
4254
|
+
enhancement(context);
|
|
4255
|
+
}
|
|
4256
|
+
return () => {
|
|
4257
|
+
const list = bk;
|
|
4258
|
+
bk = new Set();
|
|
4259
|
+
for (const s of list) {
|
|
4260
|
+
s();
|
|
4261
|
+
}
|
|
4262
|
+
};
|
|
4263
|
+
}
|
|
4264
|
+
|
|
3928
4265
|
/** @import Store from '../Store/index.mjs' */
|
|
3929
4266
|
|
|
3930
4267
|
/**
|
|
@@ -3934,31 +4271,36 @@ function bindBase(handler, env, bind) {
|
|
|
3934
4271
|
* @param {Environment} env
|
|
3935
4272
|
* @param {Record<string, [Layout.Node, Environment]>} templates
|
|
3936
4273
|
* @param {string[]} componentPath
|
|
3937
|
-
* @param {
|
|
4274
|
+
* @param {Record<string, Enhancement>} enhancements
|
|
4275
|
+
* @param {((store: Store, el: Element | Relatedness) => () => void)?} [relate]
|
|
3938
4276
|
* @param {Component.Getter?} [getComponent]
|
|
3939
4277
|
*/
|
|
3940
|
-
function renderItem(layout, parent, next, env, templates, componentPath, relate, getComponent) {
|
|
4278
|
+
function renderItem(layout, parent, next, env, templates, componentPath, enhancements, relate, getComponent) {
|
|
3941
4279
|
env = env.set(layout.aliases, layout.vars);
|
|
3942
|
-
const bind = layout.
|
|
3943
|
-
const fragment = layout.
|
|
4280
|
+
const bind = layout.bind;
|
|
4281
|
+
const fragment = layout.fragment;
|
|
3944
4282
|
if (fragment && typeof fragment === 'string') {
|
|
3945
4283
|
const template = templates[fragment];
|
|
3946
4284
|
if (!template) { return () => {}; }
|
|
3947
4285
|
const [templateLayout, templateEnv] = template;
|
|
3948
4286
|
const newEnv = templateEnv.params(templateLayout, layout, env, bind);
|
|
3949
|
-
return render(templateLayout, parent, next, newEnv, templates, componentPath, relate, getComponent);
|
|
4287
|
+
return render(templateLayout, parent, next, newEnv, templates, componentPath, enhancements, relate, getComponent);
|
|
3950
4288
|
}
|
|
3951
|
-
if (!layout.name || layout.
|
|
3952
|
-
return renderFillDirectives(parent, next, env, layout
|
|
4289
|
+
if (!layout.name || layout.fragment) {
|
|
4290
|
+
return renderFillDirectives(parent, next, env, layout) ||
|
|
3953
4291
|
renderList(layout.children || [], parent, next, env, templates, (layout, templates) => {
|
|
3954
|
-
return render(layout, parent, next, env, templates, componentPath, relate, getComponent);
|
|
4292
|
+
return render(layout, parent, next, env, templates, componentPath, enhancements, relate, getComponent);
|
|
3955
4293
|
});
|
|
3956
4294
|
}
|
|
3957
4295
|
const path = [...componentPath, layout.name];
|
|
3958
4296
|
const component = getComponent?.(path);
|
|
3959
4297
|
if (getComponent && !component) { return () => { }; }
|
|
3960
|
-
const { context, handler } = createContext(
|
|
3961
|
-
|
|
4298
|
+
const { context, handler } = createContext(
|
|
4299
|
+
component ? component : layout.name,
|
|
4300
|
+
env,
|
|
4301
|
+
env.getStore(bind),
|
|
4302
|
+
relate
|
|
4303
|
+
);
|
|
3962
4304
|
|
|
3963
4305
|
const componentAttrs = component?.attrs;
|
|
3964
4306
|
const attrs = componentAttrs
|
|
@@ -3982,23 +4324,27 @@ function renderItem(layout, parent, next, env, templates, componentPath, relate,
|
|
|
3982
4324
|
const slot = Array.isArray(r) ? r[1] : root;
|
|
3983
4325
|
parent.insertBefore(root, next);
|
|
3984
4326
|
const children = slot ?
|
|
3985
|
-
renderFillDirectives(slot, null, env, layout
|
|
4327
|
+
renderFillDirectives(slot, null, env, layout)
|
|
3986
4328
|
|| renderList(layout.children || [], slot, null, env, templates, (layout, templates) => {
|
|
3987
|
-
return render(layout, slot, null, env, templates, componentPath, relate, getComponent);
|
|
4329
|
+
return render(layout, slot, null, env, templates, componentPath, enhancements, relate, getComponent);
|
|
3988
4330
|
}) : () => {};
|
|
3989
4331
|
|
|
3990
4332
|
|
|
3991
|
-
bindClasses(root, layout.classes,
|
|
3992
|
-
bindStyles(root, layout.styles,
|
|
4333
|
+
const classes = bindClasses(root, env, layout.classes, layout.attrs.class);
|
|
4334
|
+
const styles = bindStyles(root, env, layout.styles, layout.attrs.style);
|
|
3993
4335
|
|
|
3994
4336
|
handler.mount();
|
|
4337
|
+
const enhancement = bindEnhancements(handler.tag, layout.enhancements, env, enhancements, root, slot);
|
|
3995
4338
|
|
|
3996
4339
|
return () => {
|
|
3997
|
-
|
|
4340
|
+
enhancement();
|
|
3998
4341
|
handler.destroy();
|
|
4342
|
+
root.remove();
|
|
3999
4343
|
attrs();
|
|
4000
4344
|
children();
|
|
4001
4345
|
base();
|
|
4346
|
+
classes();
|
|
4347
|
+
styles();
|
|
4002
4348
|
};
|
|
4003
4349
|
}
|
|
4004
4350
|
/**
|
|
@@ -4009,17 +4355,17 @@ function renderItem(layout, parent, next, env, templates, componentPath, relate,
|
|
|
4009
4355
|
* @param {Environment} env
|
|
4010
4356
|
* @param {Record<string, [Layout.Node, Environment]>} templates
|
|
4011
4357
|
* @param {string[]} componentPath
|
|
4012
|
-
* @param {
|
|
4358
|
+
* @param {Record<string, Enhancement>} enhancements
|
|
4359
|
+
* @param {((store: Store, el: Element | Relatedness) => () => void)?} [relate]
|
|
4013
4360
|
* @param {Component.Getter?} [getComponent]
|
|
4014
4361
|
* @returns {() => void}
|
|
4015
4362
|
*/
|
|
4016
|
-
function render(layout, parent, next, env, templates, componentPath, relate, getComponent) {
|
|
4017
|
-
const
|
|
4018
|
-
const newEnv = env.child(directives.value);
|
|
4363
|
+
function render(layout, parent, next, env, templates, componentPath, enhancements, relate, getComponent) {
|
|
4364
|
+
const newEnv = env.child(layout.value);
|
|
4019
4365
|
if (!newEnv) { return () => {}; }
|
|
4020
|
-
const list = newEnv.enum(
|
|
4366
|
+
const list = newEnv.enum(layout.enum);
|
|
4021
4367
|
/** @type {(next: Node | null, env: any) => () => void} */
|
|
4022
|
-
const r = (next, env) => renderItem(layout, parent, next, env, templates, componentPath, relate, getComponent);
|
|
4368
|
+
const r = (next, env) => renderItem(layout, parent, next, env, templates, componentPath, enhancements, relate, getComponent);
|
|
4023
4369
|
if (list === true) {
|
|
4024
4370
|
return r(next, newEnv);
|
|
4025
4371
|
}
|
|
@@ -4042,15 +4388,17 @@ function render(layout, parent, next, env, templates, componentPath, relate, get
|
|
|
4042
4388
|
* @param {object} [options]
|
|
4043
4389
|
* @param {Record<string, Store | {get?(): any; set?(v: any): void; exec?(...p: any[]): any; calc?(...p: any[]): any }>} [options.global]
|
|
4044
4390
|
* @param {(path: string[]) => Component?} [options.component]
|
|
4045
|
-
* @param {(store: Store, el: Element) => () => void} [options.relate]
|
|
4391
|
+
* @param {(store: Store, el: Element | Relatedness) => () => void} [options.relate]
|
|
4392
|
+
* @param {Record<string, Enhancement>} [options.enhancements]
|
|
4046
4393
|
* @returns {() => void}
|
|
4047
4394
|
*/
|
|
4048
|
-
function index (store, layouts, parent, {component, global, relate} = {}) {
|
|
4395
|
+
function index (store, layouts, parent, {component, global, relate, enhancements} = {}) {
|
|
4049
4396
|
const env = new Environment(store, global);
|
|
4050
4397
|
const templates = Object.create(null);
|
|
4398
|
+
const allEnhancements = enhancements || {};
|
|
4051
4399
|
const relateFn = typeof relate === 'function' ? relate : null;
|
|
4052
4400
|
return renderList(layouts, parent, null, env, templates, (layout, templates) => {
|
|
4053
|
-
return render(layout, parent, null, env, templates, [], relateFn, component);
|
|
4401
|
+
return render(layout, parent, null, env, templates, [], allEnhancements, relateFn, component);
|
|
4054
4402
|
});
|
|
4055
4403
|
}
|
|
4056
4404
|
|