@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.js
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
|
*/
|
|
@@ -651,7 +651,7 @@
|
|
|
651
651
|
|
|
652
652
|
}
|
|
653
653
|
/** @param {*} v */
|
|
654
|
-
const values = v => {
|
|
654
|
+
const values$1 = v => {
|
|
655
655
|
if (!v || !Array.isArray(v)) { return null;}
|
|
656
656
|
const list = v.map(toValueItem).filter(valueFilter);
|
|
657
657
|
if (!list.length) { return null; }
|
|
@@ -965,7 +965,7 @@
|
|
|
965
965
|
validator, validators,
|
|
966
966
|
index, length, new: isNew, parent: parentNode,
|
|
967
967
|
hidden, clearable, required, disabled, readonly,
|
|
968
|
-
label, description, placeholder, min, max, step, minLength, maxLength, pattern, values
|
|
968
|
+
label, description, placeholder, min, max, step, minLength, maxLength, pattern, values
|
|
969
969
|
} = {}) {
|
|
970
970
|
this.schema = schema;
|
|
971
971
|
this.#state.set(typeof state === 'object' && state || {});
|
|
@@ -1028,7 +1028,7 @@
|
|
|
1028
1028
|
[this.#selfMaxLength, this.#maxLength] = createState(this, number, maxLength, schema.maxLength);
|
|
1029
1029
|
[this.#selfPattern, this.#pattern] = createState(this, regex, pattern, schema.pattern);
|
|
1030
1030
|
// @ts-ignore
|
|
1031
|
-
[this.#selfValues, this.#values] = createState(this, values, values
|
|
1031
|
+
[this.#selfValues, this.#values] = createState(this, values$1, values, schema.values);
|
|
1032
1032
|
|
|
1033
1033
|
const validatorResult = createValidator(this, schema.validator, validator);
|
|
1034
1034
|
|
|
@@ -1260,9 +1260,9 @@
|
|
|
1260
1260
|
/** @readonly @type {Signal.Computed<(Schema.Value.Group | Schema.Value)[] | null>} */
|
|
1261
1261
|
#values
|
|
1262
1262
|
get selfValues() { return this.#selfValues.get(); }
|
|
1263
|
-
set selfValues(v) { this.#selfValues.set(values(v)); }
|
|
1263
|
+
set selfValues(v) { this.#selfValues.set(values$1(v)); }
|
|
1264
1264
|
get values() { return this.#values.get(); }
|
|
1265
|
-
set values(v) { this.#selfValues.set(values(v)); }
|
|
1265
|
+
set values(v) { this.#selfValues.set(values$1(v)); }
|
|
1266
1266
|
|
|
1267
1267
|
|
|
1268
1268
|
/** @type {Signal.Computed<string[]>} */
|
|
@@ -1762,6 +1762,16 @@
|
|
|
1762
1762
|
// @ts-ignore
|
|
1763
1763
|
setArrayStore(ArrayStore);
|
|
1764
1764
|
|
|
1765
|
+
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;
|
|
1766
|
+
/**
|
|
1767
|
+
*
|
|
1768
|
+
* @param {string} t
|
|
1769
|
+
* @returns
|
|
1770
|
+
*/
|
|
1771
|
+
function parseNumber(t) {
|
|
1772
|
+
return numRegex.test(t) ? Number(t.replaceAll('_', '')) : NaN;
|
|
1773
|
+
}
|
|
1774
|
+
|
|
1765
1775
|
const errors = {
|
|
1766
1776
|
CALC: 'no `createCalc` option, no expression parsing support',
|
|
1767
1777
|
EVENT: 'no `createEvent`, options, no event parsing support',
|
|
@@ -1809,64 +1819,137 @@
|
|
|
1809
1819
|
/** @import * as Layout from './index.mjs' */
|
|
1810
1820
|
|
|
1811
1821
|
const attrPattern = /^(?<decorator>[:@!+*\.?]|style:|样式:)?(?<name>-?[\w\p{Unified_Ideograph}_][-\w\p{Unified_Ideograph}_:\d\.]*)$/u;
|
|
1822
|
+
const enhancementPattern = /^~(?<enhancement>[\w\p{Unified_Ideograph}_][-\w\p{Unified_Ideograph}_\d\.]*)(?:(?<decorator>[:@!])(?<name>-?[\w\p{Unified_Ideograph}_][-\w\p{Unified_Ideograph}_:\d\.]*))?$/u;
|
|
1812
1823
|
const nameRegex = /^(?<name>[a-zA-Z$\p{Unified_Ideograph}_][\da-zA-Z$\p{Unified_Ideograph}_]*)?$/u;
|
|
1824
|
+
|
|
1825
|
+
/**
|
|
1826
|
+
*
|
|
1827
|
+
* @param {Record<string, Layout.Enhancement>} enhancements
|
|
1828
|
+
* @param {string} name
|
|
1829
|
+
*/
|
|
1830
|
+
function getEnhancement(enhancements, name) {
|
|
1831
|
+
const enhancement = enhancements[name];
|
|
1832
|
+
if (enhancement) { return enhancement; }
|
|
1833
|
+
/** @type {Layout.Enhancement} */
|
|
1834
|
+
const e = {
|
|
1835
|
+
attrs: Object.create(null),
|
|
1836
|
+
events: Object.create(null),
|
|
1837
|
+
};
|
|
1838
|
+
enhancements[name] = e;
|
|
1839
|
+
return e;
|
|
1840
|
+
}
|
|
1841
|
+
/**
|
|
1842
|
+
*
|
|
1843
|
+
* @param {string} value
|
|
1844
|
+
* @param {Exclude<Layout.Options['createCalc'], undefined>} createCalc
|
|
1845
|
+
* @returns {Layout.Node.Name | Layout.Node.Calc | Layout.Node.Value}
|
|
1846
|
+
*/
|
|
1847
|
+
function parse$1(value, createCalc) {
|
|
1848
|
+
const text = value.replace(/$\s+|\s+$/gs,'');
|
|
1849
|
+
if (text === 'null') { return {value: null} }
|
|
1850
|
+
if (text === 'true') { return {value: true} }
|
|
1851
|
+
if (text === 'false') { return {value: false} }
|
|
1852
|
+
const t = parseNumber(text);
|
|
1853
|
+
if (!Number.isNaN(t)) { return {value: t}; }
|
|
1854
|
+
if (nameRegex.test(text)) { return {name: text} }
|
|
1855
|
+
return {calc: createCalc(value)};
|
|
1856
|
+
}
|
|
1857
|
+
|
|
1813
1858
|
/**
|
|
1814
1859
|
* @param {Layout.Node} node
|
|
1815
1860
|
* @param {Exclude<Layout.Options['createCalc'], undefined>} createCalc
|
|
1816
1861
|
* @param {Exclude<Layout.Options['createEvent'], undefined>} createEvent
|
|
1817
1862
|
*/
|
|
1818
1863
|
function createAttributeAdder(node, createCalc, createEvent) {
|
|
1819
|
-
const { attrs,
|
|
1864
|
+
const { attrs, events, classes, styles, vars, aliases, params, enhancements } = node;
|
|
1820
1865
|
/**
|
|
1821
1866
|
* @param {string} qName
|
|
1822
1867
|
* @param {string} value
|
|
1823
1868
|
*/
|
|
1824
1869
|
function addAttribute(qName, value) {
|
|
1825
|
-
const
|
|
1826
|
-
|
|
1827
|
-
|
|
1828
|
-
|
|
1829
|
-
|
|
1830
|
-
|
|
1831
|
-
|
|
1832
|
-
|
|
1870
|
+
const qn = qName
|
|
1871
|
+
.replace(/./g,'.')
|
|
1872
|
+
.replace(/:/g,':')
|
|
1873
|
+
.replace(/@/g,'@')
|
|
1874
|
+
.replace(/+/g,'+')
|
|
1875
|
+
.replace(/-/g,'-')
|
|
1876
|
+
.replace(/[*×]/g,'*')
|
|
1877
|
+
.replace(/!/g, '!');
|
|
1878
|
+
const attr = (attrPattern.exec(qn) || enhancementPattern.exec(qn))?.groups;
|
|
1833
1879
|
if (!attr) { throw new ParseError('ATTR', qName); }
|
|
1834
|
-
const { name } = attr;
|
|
1880
|
+
const { name, enhancement } = attr;
|
|
1835
1881
|
const decorator = attr.decorator?.toLowerCase();
|
|
1836
|
-
if (
|
|
1837
|
-
|
|
1838
|
-
|
|
1839
|
-
|
|
1840
|
-
|
|
1841
|
-
|
|
1842
|
-
|
|
1843
|
-
|
|
1844
|
-
|
|
1845
|
-
|
|
1846
|
-
|
|
1847
|
-
|
|
1848
|
-
|
|
1849
|
-
aliases[name] = nameRegex.test(value) ? value : createCalc(value);
|
|
1850
|
-
} else if (decorator === '?') {
|
|
1851
|
-
params[name] = nameRegex.test(value) ? value : createCalc(value);
|
|
1852
|
-
} else if (decorator === '!') {
|
|
1853
|
-
const key = name.toString();
|
|
1854
|
-
switch (key) {
|
|
1855
|
-
case 'fragment': directives.fragment = value || true; break;
|
|
1856
|
-
case 'else': directives.else = true; break;
|
|
1857
|
-
case 'enum':
|
|
1858
|
-
directives.enum = value ? nameRegex.test(value) ? value : createCalc(value) : true;
|
|
1859
|
-
break;
|
|
1860
|
-
case 'if':
|
|
1861
|
-
case 'text':
|
|
1862
|
-
case 'html':
|
|
1863
|
-
directives[key] = nameRegex.test(value) ? value : createCalc(value);
|
|
1864
|
-
break;
|
|
1865
|
-
case 'template': directives.template = value; break;
|
|
1866
|
-
case 'bind': directives.bind = value || true; break;
|
|
1867
|
-
case 'value': directives.value = value; break;
|
|
1868
|
-
case 'comment': directives.comment = value; break;
|
|
1882
|
+
if (enhancement) {
|
|
1883
|
+
if (decorator === ':') {
|
|
1884
|
+
getEnhancement(enhancements, enhancement).attrs[name] = value ? parse$1(value, createCalc) : {name};
|
|
1885
|
+
} else if (decorator === '@') {
|
|
1886
|
+
getEnhancement(enhancements, enhancement).events[name] = value ? nameRegex.test(value) ? {name: value} : {event: createEvent(value)} : {name};
|
|
1887
|
+
} else if (decorator === '!') {
|
|
1888
|
+
switch(name) {
|
|
1889
|
+
case 'bind':
|
|
1890
|
+
getEnhancement(enhancements, enhancement).bind = value || true;
|
|
1891
|
+
break;
|
|
1892
|
+
}
|
|
1893
|
+
} else {
|
|
1894
|
+
getEnhancement(enhancements, enhancement).value = parse$1(value, createCalc);
|
|
1869
1895
|
}
|
|
1896
|
+
return;
|
|
1897
|
+
}
|
|
1898
|
+
if (!decorator) {
|
|
1899
|
+
attrs[name] = {value};
|
|
1900
|
+
return;
|
|
1901
|
+
}
|
|
1902
|
+
if (decorator === ':') {
|
|
1903
|
+
attrs[name] = value ? parse$1(value, createCalc) : {name};
|
|
1904
|
+
return;
|
|
1905
|
+
}
|
|
1906
|
+
if (decorator === '.') {
|
|
1907
|
+
classes[name] = value ? parse$1(value, createCalc) : {name};
|
|
1908
|
+
return;
|
|
1909
|
+
}
|
|
1910
|
+
if (decorator === 'style:') {
|
|
1911
|
+
styles[name] = parse$1(value, createCalc);
|
|
1912
|
+
return;
|
|
1913
|
+
}
|
|
1914
|
+
if (decorator === '@') {
|
|
1915
|
+
events[name] = value ? nameRegex.test(value) ? {name: value} : {event: createEvent(value)} : {name};
|
|
1916
|
+
return;
|
|
1917
|
+
}
|
|
1918
|
+
if (decorator === '+') {
|
|
1919
|
+
vars[name] = !value ? {value: undefined} : parse$1(value, createCalc);
|
|
1920
|
+
return;
|
|
1921
|
+
}
|
|
1922
|
+
if (decorator === '*') {
|
|
1923
|
+
aliases[name] = parse$1(value, createCalc);
|
|
1924
|
+
return;
|
|
1925
|
+
}
|
|
1926
|
+
if (decorator === '?') {
|
|
1927
|
+
params[name] = parse$1(value, createCalc);
|
|
1928
|
+
return;
|
|
1929
|
+
}
|
|
1930
|
+
if (decorator !== '!') {
|
|
1931
|
+
return;
|
|
1932
|
+
}
|
|
1933
|
+
const key = name.toString();
|
|
1934
|
+
switch (key) {
|
|
1935
|
+
case 'fragment': node.fragment = value || true; break;
|
|
1936
|
+
case 'else': node.else = true; break;
|
|
1937
|
+
case 'enum':
|
|
1938
|
+
node.enum = value ? parse$1(value, createCalc) : {value: true};
|
|
1939
|
+
break;
|
|
1940
|
+
case 'if':
|
|
1941
|
+
node.if = parse$1(value, createCalc);
|
|
1942
|
+
break;
|
|
1943
|
+
case 'text':
|
|
1944
|
+
node.text = parse$1(value, createCalc);
|
|
1945
|
+
break;
|
|
1946
|
+
case 'html':
|
|
1947
|
+
node.html = parse$1(value, createCalc);
|
|
1948
|
+
break;
|
|
1949
|
+
case 'template': node.template = value; break;
|
|
1950
|
+
case 'bind': node.bind = value || true; break;
|
|
1951
|
+
case 'value': node.value = value; break;
|
|
1952
|
+
case 'comment': node.comment = value; break;
|
|
1870
1953
|
}
|
|
1871
1954
|
}
|
|
1872
1955
|
return addAttribute;
|
|
@@ -1887,12 +1970,12 @@
|
|
|
1887
1970
|
children: [],
|
|
1888
1971
|
attrs: Object.create(null),
|
|
1889
1972
|
events: Object.create(null),
|
|
1890
|
-
directives: Object.create(null),
|
|
1891
1973
|
classes: Object.create(null),
|
|
1892
1974
|
styles: Object.create(null),
|
|
1893
1975
|
vars: Object.create(null),
|
|
1894
1976
|
aliases: Object.create(null),
|
|
1895
1977
|
params: Object.create(null),
|
|
1978
|
+
enhancements: Object.create(null),
|
|
1896
1979
|
};
|
|
1897
1980
|
}
|
|
1898
1981
|
|
|
@@ -2404,6 +2487,54 @@
|
|
|
2404
2487
|
'&#' + c.charCodeAt() + ';';
|
|
2405
2488
|
}
|
|
2406
2489
|
|
|
2490
|
+
/**
|
|
2491
|
+
* @param {Layout.Node.Name | Layout.Node.Calc | Layout.Node.Event | Layout.Node.Value} def
|
|
2492
|
+
*/
|
|
2493
|
+
function toValue({name, calc, event, value}) {
|
|
2494
|
+
if (value === true || value === undefined) { return ''; }
|
|
2495
|
+
const val = typeof value === 'string' ? JSON.stringify(value) : name || calc || event || value;
|
|
2496
|
+
return `="${toAttrValue$1(val)}"`;
|
|
2497
|
+
}
|
|
2498
|
+
/**
|
|
2499
|
+
* @param {string | Function | null} [value]
|
|
2500
|
+
*/
|
|
2501
|
+
function toAttrValue$1(value) {
|
|
2502
|
+
return String(value).replace(/[<&"]/g, _xmlEncoder);
|
|
2503
|
+
}
|
|
2504
|
+
|
|
2505
|
+
/**
|
|
2506
|
+
* @param {Record<string, Layout.Node.Name | Layout.Node.Calc | Layout.Node.Event | Layout.Node.Value>} values
|
|
2507
|
+
* @param {string} [prefix]
|
|
2508
|
+
* @param {boolean | null} [isName]
|
|
2509
|
+
*/
|
|
2510
|
+
function *values(values, prefix, isName = false) {
|
|
2511
|
+
if (prefix) {
|
|
2512
|
+
for (const [key, {name, calc, event, value}] of Object.entries(values)) {
|
|
2513
|
+
yield ` ${prefix}${key}`;
|
|
2514
|
+
if (isName && name === key) { continue; }
|
|
2515
|
+
const val = value && typeof value === 'string' ? JSON.stringify(value) : name || calc || event || value;
|
|
2516
|
+
if (val == null) { continue; }
|
|
2517
|
+
if (isName === false && val === true) { continue; }
|
|
2518
|
+
yield `="${toAttrValue$1(val)}"`;
|
|
2519
|
+
}
|
|
2520
|
+
return;
|
|
2521
|
+
}
|
|
2522
|
+
for (const [key, attr] of Object.entries(values)) {
|
|
2523
|
+
if (!attr) { continue; }
|
|
2524
|
+
const {name, value, calc} = attr;
|
|
2525
|
+
if (name === key) { yield ` :${key}`; continue; }
|
|
2526
|
+
if (name || calc || typeof value !== 'string') {
|
|
2527
|
+
yield ` :${key}="${toAttrValue$1(name || calc || value)}"`;
|
|
2528
|
+
continue;
|
|
2529
|
+
}
|
|
2530
|
+
yield ` ${key}`;
|
|
2531
|
+
if (value) {
|
|
2532
|
+
yield `="${toAttrValue$1(value)}"`;
|
|
2533
|
+
}
|
|
2534
|
+
}
|
|
2535
|
+
}
|
|
2536
|
+
|
|
2537
|
+
|
|
2407
2538
|
/**
|
|
2408
2539
|
*
|
|
2409
2540
|
* @param {Layout.Node} node
|
|
@@ -2411,81 +2542,37 @@
|
|
|
2411
2542
|
* @returns {Iterable<string>}
|
|
2412
2543
|
*/
|
|
2413
2544
|
function* nodeToString(node, level = 0) {
|
|
2414
|
-
const {
|
|
2545
|
+
const { children, is, name } = node;
|
|
2415
2546
|
const pad = level > 0 ? ''.padEnd(level, '\t') : '';
|
|
2416
2547
|
|
|
2417
2548
|
yield pad;
|
|
2418
2549
|
yield* ['<', name || '-'];
|
|
2419
2550
|
if (is) { yield* ['|', is]; }
|
|
2420
|
-
|
|
2421
|
-
|
|
2422
|
-
|
|
2423
|
-
const val = typeof value === 'function' ? String(value) : value;
|
|
2424
|
-
yield* [' ?', name];
|
|
2425
|
-
if (val && typeof val === 'string') {
|
|
2426
|
-
yield* ['="', val.replace(/[<&"]/g, _xmlEncoder), '"'];
|
|
2427
|
-
}
|
|
2428
|
-
}
|
|
2429
|
-
for (const [name, value] of Object.entries(directives)) {
|
|
2430
|
-
if (value === false || value == null) { continue; }
|
|
2431
|
-
const val = typeof value === 'function' ? String(value) : value;
|
|
2432
|
-
yield* [' !', name];
|
|
2433
|
-
if (val && typeof val === 'string') {
|
|
2434
|
-
yield* ['="', val.replace(/[<&"]/g, _xmlEncoder), '"'];
|
|
2435
|
-
}
|
|
2436
|
-
}
|
|
2437
|
-
for (const [name, value] of Object.entries(aliases)) {
|
|
2438
|
-
if (value == null) { continue; }
|
|
2439
|
-
const val = typeof value === 'function' ? String(value) : value;
|
|
2440
|
-
yield* [' *', name];
|
|
2441
|
-
if (val && typeof val === 'string') {
|
|
2442
|
-
yield* ['="', val.replace(/[<&"]/g, _xmlEncoder), '"'];
|
|
2443
|
-
}
|
|
2444
|
-
}
|
|
2445
|
-
for (const [name, value] of Object.entries(vars)) {
|
|
2446
|
-
if (value == null) { continue; }
|
|
2447
|
-
const val = typeof value === 'function' ? String(value) : value;
|
|
2448
|
-
yield* [' +', name];
|
|
2449
|
-
if (val && typeof val === 'string') {
|
|
2450
|
-
yield* ['="', val.replace(/[<&"]/g, _xmlEncoder), '"'];
|
|
2451
|
-
}
|
|
2452
|
-
}
|
|
2453
|
-
for (const [name, value] of Object.entries(attrs)) {
|
|
2454
|
-
if (value == null) { continue; }
|
|
2455
|
-
if (typeof value === 'string') {
|
|
2456
|
-
yield* [' ', name];
|
|
2457
|
-
if (value) {
|
|
2458
|
-
yield* ['="', value.replace(/[<&"]/g, _xmlEncoder), '"'];
|
|
2459
|
-
}
|
|
2460
|
-
continue;
|
|
2461
|
-
}
|
|
2462
|
-
const val = typeof value === 'function' ? String(value) : typeof value === 'object' ? value.name : value;
|
|
2463
|
-
if (val && typeof val === 'string') {
|
|
2464
|
-
yield* [' :', name, '="', val.replace(/[<&"]/g, _xmlEncoder) || '', '"'];
|
|
2465
|
-
}
|
|
2551
|
+
if (node.template) {
|
|
2552
|
+
yield ` !template="${toAttrValue$1(node.template)}"`;
|
|
2553
|
+
yield* values(node.params, '?', null);
|
|
2466
2554
|
}
|
|
2467
|
-
|
|
2468
|
-
|
|
2469
|
-
|
|
2470
|
-
|
|
2471
|
-
|
|
2472
|
-
|
|
2473
|
-
|
|
2474
|
-
|
|
2475
|
-
|
|
2476
|
-
|
|
2477
|
-
|
|
2478
|
-
|
|
2479
|
-
|
|
2480
|
-
}
|
|
2481
|
-
|
|
2482
|
-
|
|
2483
|
-
|
|
2484
|
-
const val = typeof value === 'function' ? String(value) : value;
|
|
2485
|
-
if (val && typeof val === 'string') {
|
|
2486
|
-
yield* [' style:', name, '="', val.replace(/[<&"]/g, _xmlEncoder), '"'];
|
|
2487
|
-
}
|
|
2555
|
+
if (node.fragment) { yield node.fragment === true ? ` !fragment` : ` !fragment="${toAttrValue$1(node.fragment)}"`; }
|
|
2556
|
+
if (node.else) { yield ` !else`; }
|
|
2557
|
+
if (node.if) { yield ` !if${toValue(node.if)}`; }
|
|
2558
|
+
if (node.value) { yield ` !value="${toAttrValue$1(node.value)}"`; }
|
|
2559
|
+
if (node.enum) { yield ` !enum${toValue(node.enum)}`; }
|
|
2560
|
+
yield* values(node.aliases, '*', null);
|
|
2561
|
+
yield* values(node.vars, '+', null);
|
|
2562
|
+
if (node.bind) { yield node.bind === true ? ` !bind` : ` !bind="${toAttrValue$1(node.bind)}"`; }
|
|
2563
|
+
yield* values(node.attrs);
|
|
2564
|
+
yield* values(node.events, '@', true);
|
|
2565
|
+
yield* values(node.classes, '.', true);
|
|
2566
|
+
yield* values(node.styles, 'style:');
|
|
2567
|
+
for (const [k, en] of Object.entries(node.enhancements)) {
|
|
2568
|
+
if (en.bind) { yield en.bind === true ? ` ~${k}!bind` : ` ~${k}!bind="${toAttrValue$1(en.bind)}"`; }
|
|
2569
|
+
if (en.value) { yield ` ~${k}${toValue(en.value)}`; }
|
|
2570
|
+
yield* values(en.attrs, `~${k}:`, true);
|
|
2571
|
+
yield* values(en.events, `~${k}@`, true);
|
|
2488
2572
|
}
|
|
2573
|
+
if (node.text) { yield ` !text${toValue(node.text)}`; }
|
|
2574
|
+
if (node.html) { yield ` !html${toValue(node.html)}`; }
|
|
2575
|
+
if (node.comment) { yield ` !comment="${toAttrValue$1(node.comment)}"`; }
|
|
2489
2576
|
if (!children.length) {
|
|
2490
2577
|
yield '/>';
|
|
2491
2578
|
if (level >= 0) { yield '\n'; }
|
|
@@ -2547,44 +2634,66 @@
|
|
|
2547
2634
|
/**
|
|
2548
2635
|
* @typedef {object} Directives
|
|
2549
2636
|
*
|
|
2550
|
-
* @property {string} [template]
|
|
2551
|
-
*
|
|
2552
|
-
* @property {boolean | string} [fragment]
|
|
2553
|
-
*
|
|
2554
|
-
* @property {string | Calc} [if]
|
|
2555
|
-
* @property {boolean} [else]
|
|
2556
|
-
*
|
|
2557
|
-
* @property {string} [value] 值关联(关联为列表)
|
|
2558
|
-
* @property {boolean | string | Calc} [enum] 列表属性枚举
|
|
2559
|
-
*
|
|
2560
|
-
* @property {boolean | string} [bind]
|
|
2561
|
-
* @property {string | Calc} [text]
|
|
2562
|
-
* @property {string | Calc} [html]
|
|
2563
|
-
*
|
|
2564
|
-
* @property {string} [comment] 注释
|
|
2565
2637
|
*/
|
|
2566
2638
|
|
|
2567
2639
|
|
|
2568
2640
|
|
|
2641
|
+
/**
|
|
2642
|
+
* @typedef {object} Enhancement
|
|
2643
|
+
* @property {Record<string, Node.Name | Node.Event>} events
|
|
2644
|
+
* @property {Record<string, Node.Name | Node.Calc | Node.Value>} attrs
|
|
2645
|
+
* @property {Node.Name | Node.Calc | Node.Value} [value]
|
|
2646
|
+
* @property {boolean | string} [bind]
|
|
2647
|
+
*/
|
|
2648
|
+
|
|
2569
2649
|
/**
|
|
2570
2650
|
* @typedef {object} Options
|
|
2571
2651
|
* @property {(t: string) => Calc} [options.createCalc]
|
|
2572
2652
|
* @property {(t: string) => EventListener} [options.createEvent]
|
|
2573
2653
|
* @property {Set<string>} [options.simpleTag]
|
|
2574
2654
|
*/
|
|
2655
|
+
/**
|
|
2656
|
+
* @template [T=any]
|
|
2657
|
+
* @typedef {{value: T; name?: undefined; calc?: undefined; event?: undefined}} Node.Value
|
|
2658
|
+
*/
|
|
2659
|
+
/**
|
|
2660
|
+
* @typedef {{name: string; value?: undefined; calc?: undefined; event?: undefined}} Node.Name
|
|
2661
|
+
*/
|
|
2662
|
+
/**
|
|
2663
|
+
* @typedef {{event: EventListener; name?: undefined; calc?: undefined; value?: undefined}} Node.Event
|
|
2664
|
+
*/
|
|
2665
|
+
/**
|
|
2666
|
+
* @typedef {{calc: Calc; name?: undefined; value?: undefined; event?: undefined}} Node.Calc
|
|
2667
|
+
*/
|
|
2575
2668
|
/**
|
|
2576
2669
|
* @typedef {object} Node
|
|
2577
2670
|
* @property {string} name
|
|
2578
2671
|
* @property {string?} [is]
|
|
2579
2672
|
* @property {string} [id]
|
|
2580
|
-
* @property {Record<string,
|
|
2581
|
-
* @property {Record<string,
|
|
2582
|
-
* @property {Record<string,
|
|
2583
|
-
* @property {Record<string,
|
|
2584
|
-
* @property {Record<string,
|
|
2585
|
-
* @property {Record<string,
|
|
2586
|
-
* @property {Record<string,
|
|
2587
|
-
* @property {
|
|
2673
|
+
* @property {Record<string, Node.Name | Node.Calc | Node.Value>} attrs
|
|
2674
|
+
* @property {Record<string, Node.Name | Node.Calc | Node.Value>} params
|
|
2675
|
+
* @property {Record<string, Node.Name | Node.Calc | Node.Value>} classes
|
|
2676
|
+
* @property {Record<string, Node.Name | Node.Calc | Node.Value>} styles
|
|
2677
|
+
* @property {Record<string, Node.Name | Node.Event>} events
|
|
2678
|
+
* @property {Record<string, Node.Name | Node.Calc | Node.Value>} vars
|
|
2679
|
+
* @property {Record<string, Node.Name | Node.Calc | Node.Value>} aliases
|
|
2680
|
+
* @property {Record<string, Enhancement>} enhancements
|
|
2681
|
+
*
|
|
2682
|
+
* @property {string} [template]
|
|
2683
|
+
* @property {boolean | string} [fragment]
|
|
2684
|
+
*
|
|
2685
|
+
* @property {Node.Name | Node.Calc | Node.Value} [if]
|
|
2686
|
+
* @property {boolean} [else]
|
|
2687
|
+
*
|
|
2688
|
+
* @property {string} [value] 值关联
|
|
2689
|
+
* @property {Node.Name | Node.Calc | Node.Value} [enum] 列表属性枚举
|
|
2690
|
+
*
|
|
2691
|
+
* @property {boolean | string} [bind]
|
|
2692
|
+
* @property {Node.Name | Node.Value | Node.Calc} [text]
|
|
2693
|
+
* @property {Node.Name | Node.Value | Node.Calc} [html]
|
|
2694
|
+
*
|
|
2695
|
+
* @property {string} [comment] 注释
|
|
2696
|
+
*
|
|
2588
2697
|
* @property {(Node | string)[]} children
|
|
2589
2698
|
*/
|
|
2590
2699
|
|
|
@@ -2592,7 +2701,7 @@
|
|
|
2592
2701
|
* @callback Calc
|
|
2593
2702
|
* @param {Record<string, any>} env
|
|
2594
2703
|
* @returns {any}
|
|
2595
|
-
|
|
2704
|
+
*/
|
|
2596
2705
|
|
|
2597
2706
|
|
|
2598
2707
|
/**
|
|
@@ -2889,37 +2998,63 @@
|
|
|
2889
2998
|
*/
|
|
2890
2999
|
class Environment {
|
|
2891
3000
|
/**
|
|
2892
|
-
* @param {
|
|
3001
|
+
* @param {Layout.Node.Name | Layout.Node.Calc | Layout.Node.Value} value
|
|
2893
3002
|
*/
|
|
2894
|
-
exec(value) {
|
|
2895
|
-
if (typeof
|
|
2896
|
-
const item = this.#items[
|
|
3003
|
+
exec({name, calc, value }) {
|
|
3004
|
+
if (typeof name === 'string') {
|
|
3005
|
+
const item = this.#items[name];
|
|
2897
3006
|
if (typeof item?.get !== 'function') { return }
|
|
2898
3007
|
return item.get();
|
|
2899
3008
|
}
|
|
2900
|
-
if (typeof
|
|
2901
|
-
return
|
|
3009
|
+
if (typeof calc === 'function') {
|
|
3010
|
+
return calc(this.getters);
|
|
2902
3011
|
}
|
|
3012
|
+
return value;
|
|
2903
3013
|
}
|
|
2904
3014
|
/**
|
|
2905
|
-
* @param {
|
|
3015
|
+
* @param {Layout.Node.Name | Layout.Node.Calc | Layout.Node.Value} value
|
|
3016
|
+
*/
|
|
3017
|
+
get({name, calc, value}) {
|
|
3018
|
+
if (typeof name === 'string') {
|
|
3019
|
+
const item = this.#items[name];
|
|
3020
|
+
if (typeof item?.get !== 'function') { return }
|
|
3021
|
+
const{get, set} = item;
|
|
3022
|
+
return {get, set};
|
|
3023
|
+
}
|
|
3024
|
+
if (typeof calc === 'function') {
|
|
3025
|
+
const c = new exports.Signal.Computed(() => calc(this.getters));
|
|
3026
|
+
return {get: () => c.get() };
|
|
3027
|
+
}
|
|
3028
|
+
return {get: () => value };
|
|
3029
|
+
}
|
|
3030
|
+
/**
|
|
3031
|
+
* @param {Layout.Node.Name | Layout.Node.Calc | Layout.Node.Value} value
|
|
2906
3032
|
* @param {(value: any) => void} cb
|
|
2907
3033
|
*/
|
|
2908
3034
|
watch(value, cb) { return watch(() => this.exec(value), cb, true); }
|
|
2909
3035
|
|
|
2910
3036
|
/**
|
|
2911
|
-
* @param {
|
|
3037
|
+
* @param {Layout.Node.Name | Layout.Node.Calc | Layout.Node.Value | null} [en]
|
|
2912
3038
|
*/
|
|
2913
|
-
enum(
|
|
2914
|
-
if (!
|
|
2915
|
-
|
|
2916
|
-
if (typeof
|
|
2917
|
-
if (typeof name
|
|
2918
|
-
|
|
2919
|
-
|
|
2920
|
-
|
|
2921
|
-
|
|
2922
|
-
|
|
3039
|
+
enum(en) {
|
|
3040
|
+
if (!en) { return true; }
|
|
3041
|
+
const {name, calc} = en;
|
|
3042
|
+
if (typeof calc === 'function') { return () => calc(this.getters); }
|
|
3043
|
+
if (typeof name === 'string') {
|
|
3044
|
+
const item = this.#items[name];
|
|
3045
|
+
if (typeof item?.get !== 'function') { return null }
|
|
3046
|
+
const store = item.store;
|
|
3047
|
+
return store instanceof Store ? store : item.get;
|
|
3048
|
+
}
|
|
3049
|
+
return this.store;
|
|
3050
|
+
}
|
|
3051
|
+
/**
|
|
3052
|
+
* @param {string | boolean | null} [name]
|
|
3053
|
+
*/
|
|
3054
|
+
getStore(name) {
|
|
3055
|
+
if (!name) { return null; }
|
|
3056
|
+
const item = this.#items[name === true ? '' : name];
|
|
3057
|
+
return item?.get && item.store || null
|
|
2923
3058
|
}
|
|
2924
3059
|
|
|
2925
3060
|
/**
|
|
@@ -2962,6 +3097,29 @@
|
|
|
2962
3097
|
]));
|
|
2963
3098
|
return res;
|
|
2964
3099
|
}
|
|
3100
|
+
/**
|
|
3101
|
+
* @param {string | true} name
|
|
3102
|
+
* @returns {Record<string, {get(): any; set?(v: any): void}> | void}
|
|
3103
|
+
*/
|
|
3104
|
+
getBindAll(name) {
|
|
3105
|
+
const item = this.#items[name === true ? '' : name];
|
|
3106
|
+
if (!item?.get) { return {}; }
|
|
3107
|
+
const { store } = item;
|
|
3108
|
+
if (!store) {
|
|
3109
|
+
const { get, set } = item;
|
|
3110
|
+
return { '$value': {get,set} }
|
|
3111
|
+
}
|
|
3112
|
+
/** @type {Record<string, {get(): any; set?(v: any): void}> | void} */
|
|
3113
|
+
const res = Object.fromEntries([...bindableSet].map(v => [
|
|
3114
|
+
`$${v}`, v === 'value' || v === 'state' ? {
|
|
3115
|
+
get: () => store[v],
|
|
3116
|
+
set: (s)=>{store[v] = s;}
|
|
3117
|
+
} : {
|
|
3118
|
+
get: () => store[v],
|
|
3119
|
+
}
|
|
3120
|
+
]));
|
|
3121
|
+
return res;
|
|
3122
|
+
}
|
|
2965
3123
|
/**
|
|
2966
3124
|
* @param {string | true} name
|
|
2967
3125
|
* @param {string} type
|
|
@@ -3005,12 +3163,12 @@
|
|
|
3005
3163
|
}
|
|
3006
3164
|
|
|
3007
3165
|
/**
|
|
3008
|
-
* @param {
|
|
3166
|
+
* @param {Layout.Node.Name | Layout.Node.Event} event
|
|
3009
3167
|
* @returns {Layout.EventListener?}
|
|
3010
3168
|
*/
|
|
3011
|
-
getEvent(event) {
|
|
3169
|
+
getEvent({name, event}) {
|
|
3012
3170
|
if (typeof event === 'function') { return event }
|
|
3013
|
-
const item = this.#items[
|
|
3171
|
+
const item = this.#items[name];
|
|
3014
3172
|
if (!item) { return null }
|
|
3015
3173
|
const {exec, calc} = item;
|
|
3016
3174
|
if (typeof exec === 'function') { return exec }
|
|
@@ -3128,45 +3286,55 @@
|
|
|
3128
3286
|
const items = cloned.#items;
|
|
3129
3287
|
for (const [key, param] of Object.entries(params)) {
|
|
3130
3288
|
const attr = key in attrs ? attrs[key] : null;
|
|
3131
|
-
if (
|
|
3132
|
-
|
|
3133
|
-
|
|
3134
|
-
|
|
3135
|
-
|
|
3136
|
-
|
|
3137
|
-
|
|
3289
|
+
if (attr) {
|
|
3290
|
+
const {name, calc, value} = attr;
|
|
3291
|
+
if (name) {
|
|
3292
|
+
const item = sourceEnv.#items[name];
|
|
3293
|
+
if (!item?.get) { continue; }
|
|
3294
|
+
if (!item.store) {
|
|
3295
|
+
explicit[key] = items[key] = item;
|
|
3296
|
+
continue;
|
|
3297
|
+
}
|
|
3298
|
+
for (const [k, it] of toItem(item.store, key)) {
|
|
3299
|
+
explicit[k] = items[k] = it;
|
|
3300
|
+
}
|
|
3138
3301
|
continue;
|
|
3139
|
-
}
|
|
3140
|
-
|
|
3141
|
-
explicit[
|
|
3302
|
+
} else if (typeof calc === 'function') {
|
|
3303
|
+
const val = new exports.Signal.Computed(() => calc(sourceEnv.getters));
|
|
3304
|
+
explicit[key] = items[key] = {
|
|
3305
|
+
get: () => { return val.get(); },
|
|
3306
|
+
};
|
|
3307
|
+
continue;
|
|
3308
|
+
} else {
|
|
3309
|
+
explicit[key] = items[key] = {get: () => value};
|
|
3142
3310
|
}
|
|
3143
3311
|
continue;
|
|
3144
|
-
|
|
3145
|
-
} else if (typeof attr === 'function') {
|
|
3146
|
-
const val = new exports.Signal.Computed(() => attr(sourceEnv.getters));
|
|
3147
|
-
explicit[key] = items[key] = {
|
|
3148
|
-
get: () => { return val.get(); },
|
|
3149
|
-
};
|
|
3150
|
-
continue;
|
|
3151
|
-
} else if (typeof param === 'function') {
|
|
3152
|
-
const getters = cloned.getters;
|
|
3153
|
-
cloned.#getters = null;
|
|
3154
|
-
const val = new exports.Signal.Computed(() => param(getters));
|
|
3155
|
-
explicit[key] = items[key] = {
|
|
3156
|
-
get: () => { return val.get(); },
|
|
3157
|
-
};
|
|
3158
|
-
continue;
|
|
3159
3312
|
} else {
|
|
3160
|
-
const
|
|
3161
|
-
if (
|
|
3162
|
-
|
|
3163
|
-
|
|
3313
|
+
const {name, calc, value} = param;
|
|
3314
|
+
if (typeof calc === 'function') {
|
|
3315
|
+
const getters = cloned.getters;
|
|
3316
|
+
cloned.#getters = null;
|
|
3317
|
+
const val = new exports.Signal.Computed(() => calc(getters));
|
|
3318
|
+
explicit[key] = items[key] = {
|
|
3319
|
+
get: () => { return val.get(); },
|
|
3320
|
+
};
|
|
3164
3321
|
continue;
|
|
3322
|
+
} else if (name) {
|
|
3323
|
+
const item = items[name];
|
|
3324
|
+
if (!item?.get) { continue; }
|
|
3325
|
+
if (!item.store) {
|
|
3326
|
+
explicit[key] = items[key] = item;
|
|
3327
|
+
continue;
|
|
3328
|
+
}
|
|
3329
|
+
for (const [k, it] of toItem(item.store, key)) {
|
|
3330
|
+
explicit[k] = items[k] = it;
|
|
3331
|
+
}
|
|
3332
|
+
continue;
|
|
3333
|
+
} else {
|
|
3334
|
+
explicit[key] = items[key] = {get: () => value};
|
|
3335
|
+
continue;
|
|
3336
|
+
|
|
3165
3337
|
}
|
|
3166
|
-
for (const [k, it] of toItem(item.store, key)) {
|
|
3167
|
-
explicit[k] = items[k] = it;
|
|
3168
|
-
}
|
|
3169
|
-
continue;
|
|
3170
3338
|
}
|
|
3171
3339
|
}
|
|
3172
3340
|
return cloned;
|
|
@@ -3179,8 +3347,8 @@
|
|
|
3179
3347
|
}
|
|
3180
3348
|
/**
|
|
3181
3349
|
*
|
|
3182
|
-
* @param {Record<string,
|
|
3183
|
-
* @param {Record<string,
|
|
3350
|
+
* @param {Record<string, Layout.Node.Name | Layout.Node.Calc | Layout.Node.Value>} aliases
|
|
3351
|
+
* @param {Record<string, Layout.Node.Name | Layout.Node.Calc | Layout.Node.Value>} vars
|
|
3184
3352
|
*/
|
|
3185
3353
|
set(aliases, vars) {
|
|
3186
3354
|
if (Object.keys(aliases).length + Object.keys(vars).length === 0) { return this; }
|
|
@@ -3189,35 +3357,40 @@
|
|
|
3189
3357
|
cloned.#object = this.#object;
|
|
3190
3358
|
const explicit = cloned.#explicit;
|
|
3191
3359
|
const items = cloned.#items;
|
|
3192
|
-
for (const [key, name] of Object.entries(aliases)) {
|
|
3193
|
-
if (typeof
|
|
3360
|
+
for (const [key, {name, calc, value}] of Object.entries(aliases)) {
|
|
3361
|
+
if (typeof calc === 'function') {
|
|
3194
3362
|
const getters = cloned.getters;
|
|
3195
3363
|
cloned.#getters = null;
|
|
3196
|
-
const val = new exports.Signal.Computed(() =>
|
|
3364
|
+
const val = new exports.Signal.Computed(() => calc(getters));
|
|
3197
3365
|
explicit[key] = items[key] = {
|
|
3198
3366
|
get: () => { return val.get(); },
|
|
3199
3367
|
};
|
|
3200
3368
|
continue;
|
|
3201
3369
|
}
|
|
3202
|
-
|
|
3203
|
-
|
|
3204
|
-
|
|
3205
|
-
|
|
3370
|
+
if (name) {
|
|
3371
|
+
const item = items[name];
|
|
3372
|
+
if (!item) { continue; }
|
|
3373
|
+
if (!item.get || !item.store) {
|
|
3374
|
+
explicit[key] = items[key] = item;
|
|
3375
|
+
continue;
|
|
3376
|
+
}
|
|
3377
|
+
for (const [k, it] of toItem(item.store, key)) {
|
|
3378
|
+
explicit[k] = items[k] = it;
|
|
3379
|
+
}
|
|
3206
3380
|
continue;
|
|
3207
3381
|
}
|
|
3208
|
-
|
|
3209
|
-
|
|
3210
|
-
}
|
|
3382
|
+
explicit[key] = items[key] = { get: () => { return value; } };
|
|
3383
|
+
continue;
|
|
3211
3384
|
}
|
|
3212
|
-
for (const [k,
|
|
3385
|
+
for (const [k,{name, calc, value}] of Object.entries(vars)) {
|
|
3213
3386
|
|
|
3214
|
-
const val = new exports.Signal.State(/** @type {any} */(
|
|
3215
|
-
if (typeof
|
|
3387
|
+
const val = new exports.Signal.State(/** @type {any} */(value));
|
|
3388
|
+
if (typeof calc === 'function') {
|
|
3216
3389
|
const settable = cloned.settable;
|
|
3217
3390
|
cloned.#settable = null;
|
|
3218
|
-
val.set(
|
|
3219
|
-
} else if (
|
|
3220
|
-
const item = items[
|
|
3391
|
+
val.set(calc(settable));
|
|
3392
|
+
} else if (name) {
|
|
3393
|
+
const item = items[name];
|
|
3221
3394
|
if (!item?.get) { continue }
|
|
3222
3395
|
val.set(item.get());
|
|
3223
3396
|
}
|
|
@@ -3328,44 +3501,44 @@
|
|
|
3328
3501
|
/**
|
|
3329
3502
|
* @param {Component.Handler} handler
|
|
3330
3503
|
* @param {Environment} envs
|
|
3331
|
-
* @param {Record<string,
|
|
3504
|
+
* @param {Record<string, Layout.Node.Name | Layout.Node.Calc | Layout.Node.Value>} attrs
|
|
3332
3505
|
* @param {Record<string, Component.Attr>} componentAttrs
|
|
3333
3506
|
* @param {string | boolean | null} [bindValue]
|
|
3334
3507
|
*/
|
|
3335
3508
|
function bindAttrs(handler, envs, attrs, componentAttrs, bindValue) {
|
|
3336
3509
|
|
|
3337
3510
|
let bk = new Set();
|
|
3338
|
-
for (const [
|
|
3339
|
-
|
|
3340
|
-
if (
|
|
3341
|
-
|
|
3342
|
-
|
|
3511
|
+
for (const [key, attr] of Object.entries(componentAttrs)) {
|
|
3512
|
+
if (key === 'class' || key === 'style') { continue; }
|
|
3513
|
+
if (key in attrs) {
|
|
3514
|
+
const attrDefine = attrs[key];
|
|
3515
|
+
const { name, calc, value } = attrs[key];
|
|
3516
|
+
if (!name && !calc) {
|
|
3517
|
+
handler.set(key, value);
|
|
3343
3518
|
continue;
|
|
3344
3519
|
}
|
|
3345
|
-
const attrSchema = typeof attrValue === 'function' ? /** @type{Layout.Calc} */(attrValue) : attrValue.name;
|
|
3346
3520
|
if (attr.immutable) {
|
|
3347
|
-
handler.set(
|
|
3348
|
-
continue;
|
|
3521
|
+
handler.set(key, envs.exec(attrDefine));
|
|
3349
3522
|
}
|
|
3350
|
-
bk.add(envs.watch(
|
|
3523
|
+
bk.add(envs.watch(attrDefine, v => handler.set(key, v)));
|
|
3351
3524
|
continue;
|
|
3352
3525
|
}
|
|
3353
3526
|
const bind = attr.bind;
|
|
3354
3527
|
if (!bindValue || !bind) {
|
|
3355
|
-
handler.set(
|
|
3528
|
+
handler.set(key, attr.default);
|
|
3356
3529
|
continue;
|
|
3357
3530
|
}
|
|
3358
3531
|
if (typeof bind === 'string') {
|
|
3359
|
-
const r = envs.bind(bindValue, bind, v => handler.set(
|
|
3532
|
+
const r = envs.bind(bindValue, bind, v => handler.set(key, v));
|
|
3360
3533
|
if (r) {
|
|
3361
3534
|
bk.add(r);
|
|
3362
3535
|
} else {
|
|
3363
|
-
handler.set(
|
|
3536
|
+
handler.set(key, attr.default);
|
|
3364
3537
|
}
|
|
3365
3538
|
continue;
|
|
3366
3539
|
}
|
|
3367
3540
|
if (!Array.isArray(bind)) {
|
|
3368
|
-
handler.set(
|
|
3541
|
+
handler.set(key, attr.default);
|
|
3369
3542
|
continue;
|
|
3370
3543
|
}
|
|
3371
3544
|
const [event, set, isState] = bind;
|
|
@@ -3374,11 +3547,11 @@
|
|
|
3374
3547
|
}
|
|
3375
3548
|
if (!isState) {
|
|
3376
3549
|
const bindKey = bindValue === true ? '' : bindValue;
|
|
3377
|
-
bk.add(envs.watch(bindKey, v => handler.set(
|
|
3550
|
+
bk.add(envs.watch({name: bindKey}, v => handler.set(key, v)));
|
|
3378
3551
|
handler.addEvent(event, (...args) => { envs.all[bindKey] = set(...args);});
|
|
3379
3552
|
continue;
|
|
3380
3553
|
}
|
|
3381
|
-
const r = envs.bind(bindValue, 'state', v => handler.set(
|
|
3554
|
+
const r = envs.bind(bindValue, 'state', v => handler.set(key, v));
|
|
3382
3555
|
if (!r) { continue; }
|
|
3383
3556
|
bk.add(r);
|
|
3384
3557
|
const s = envs.bindSet(bindValue, 'state');
|
|
@@ -3402,23 +3575,24 @@
|
|
|
3402
3575
|
/**
|
|
3403
3576
|
* @param {Component.Handler} handler
|
|
3404
3577
|
* @param {Environment} envs
|
|
3405
|
-
* @param {Record<string,
|
|
3578
|
+
* @param {Record<string, Layout.Node.Name | Layout.Node.Calc | Layout.Node.Value>} attrs
|
|
3406
3579
|
*/
|
|
3407
3580
|
function bindBaseAttrs(handler, envs, attrs) {
|
|
3408
3581
|
const tag = handler.tag;
|
|
3409
3582
|
let bk = new Set();
|
|
3410
|
-
for (const [
|
|
3411
|
-
if (
|
|
3412
|
-
|
|
3583
|
+
for (const [key, attr] of Object.entries(attrs)) {
|
|
3584
|
+
if (key === 'class' || key === 'style') { continue; }
|
|
3585
|
+
const {name, calc, value} = attr;
|
|
3586
|
+
if (!name && !calc) {
|
|
3587
|
+
handler.set(key, value);
|
|
3413
3588
|
continue;
|
|
3414
3589
|
}
|
|
3415
|
-
|
|
3416
|
-
|
|
3417
|
-
|
|
3418
|
-
handler.set(name, value);
|
|
3590
|
+
if (typeof tag === 'string' && tag.toLocaleLowerCase() === 'input' && key.toLocaleLowerCase() === 'type') {
|
|
3591
|
+
const value = envs.exec(attr);
|
|
3592
|
+
handler.set(key, value);
|
|
3419
3593
|
continue;
|
|
3420
3594
|
}
|
|
3421
|
-
bk.add(envs.watch(
|
|
3595
|
+
bk.add(envs.watch(attr, val => handler.set(key, val)));
|
|
3422
3596
|
}
|
|
3423
3597
|
|
|
3424
3598
|
return ()=> {
|
|
@@ -3436,26 +3610,29 @@
|
|
|
3436
3610
|
/**
|
|
3437
3611
|
* @param {Node} node
|
|
3438
3612
|
* @param {Environment} envs
|
|
3439
|
-
* @param {Record<string,
|
|
3613
|
+
* @param {Record<string, Layout.Node.Name | Layout.Node.Calc | Layout.Node.Value>} classes
|
|
3614
|
+
* @param {Layout.Node.Name | Layout.Node.Calc | Layout.Node.Value} [classAttr]
|
|
3440
3615
|
*/
|
|
3441
|
-
function bindClasses(node, classes,
|
|
3616
|
+
function bindClasses(node, envs, classes, classAttr) {
|
|
3442
3617
|
if (!(node instanceof Element)) {
|
|
3443
3618
|
return () => {};
|
|
3444
3619
|
}
|
|
3620
|
+
if (classAttr) {
|
|
3621
|
+
node.className += ' ' + envs.exec(classAttr);
|
|
3622
|
+
}
|
|
3445
3623
|
|
|
3446
3624
|
/** @type {Set<() => void>?} */
|
|
3447
3625
|
let bk = new Set();
|
|
3448
|
-
for (const [
|
|
3449
|
-
if (
|
|
3450
|
-
|
|
3451
|
-
node.classList.add(name);
|
|
3626
|
+
for (const [key, attr] of Object.entries(classes)) {
|
|
3627
|
+
if (attr.value) {
|
|
3628
|
+
node.classList.add(key);
|
|
3452
3629
|
continue;
|
|
3453
3630
|
}
|
|
3454
3631
|
bk.add(watch(() => Boolean(envs.exec(attr)), value => {
|
|
3455
3632
|
if (value) {
|
|
3456
|
-
node.classList.add(
|
|
3633
|
+
node.classList.add(key);
|
|
3457
3634
|
} else {
|
|
3458
|
-
node.classList.remove(
|
|
3635
|
+
node.classList.remove(key);
|
|
3459
3636
|
}
|
|
3460
3637
|
}, true));
|
|
3461
3638
|
}
|
|
@@ -3539,16 +3716,20 @@
|
|
|
3539
3716
|
/**
|
|
3540
3717
|
* @param {Element} node
|
|
3541
3718
|
* @param {Environment} envs
|
|
3542
|
-
* @param {Record<string,
|
|
3719
|
+
* @param {Record<string, Layout.Node.Name | Layout.Node.Calc | Layout.Node.Value>} styles
|
|
3720
|
+
* @param {Layout.Node.Name | Layout.Node.Calc | Layout.Node.Value} [styleAttr]
|
|
3543
3721
|
*/
|
|
3544
|
-
function bindStyles(node,
|
|
3722
|
+
function bindStyles(node, envs, styles, styleAttr) {
|
|
3545
3723
|
if (!(node instanceof HTMLElement) && !(node instanceof SVGElement)) {
|
|
3546
3724
|
return () => {};
|
|
3547
3725
|
}
|
|
3726
|
+
if (styleAttr) {
|
|
3727
|
+
node.setAttribute('style', node.getAttribute('style') + ';' + envs.exec(styleAttr));
|
|
3728
|
+
}
|
|
3548
3729
|
|
|
3549
3730
|
/** @type {Set<() => void>?} */
|
|
3550
3731
|
let bk = new Set();
|
|
3551
|
-
for (const [name, attr] of Object.entries(
|
|
3732
|
+
for (const [name, attr] of Object.entries(styles)) {
|
|
3552
3733
|
bk.add(watch(() => toStyle(name, envs.exec(attr)), value => {
|
|
3553
3734
|
if (value) {
|
|
3554
3735
|
node.style.setProperty(name, ...value);
|
|
@@ -3610,9 +3791,10 @@
|
|
|
3610
3791
|
}
|
|
3611
3792
|
}
|
|
3612
3793
|
|
|
3613
|
-
/** @import { Component } from '../types.mjs' */
|
|
3794
|
+
/** @import { Component, Relatedness } from '../types.mjs' */
|
|
3614
3795
|
/** @import Store from '../Store/index.mjs' */
|
|
3615
3796
|
/** @import Environment from './Environment/index.mjs' */
|
|
3797
|
+
/** @import * as Layout from '../Layout/index.mjs' */
|
|
3616
3798
|
|
|
3617
3799
|
|
|
3618
3800
|
/** @type {Record<string, Component.Event.Filter>} */
|
|
@@ -3732,14 +3914,68 @@
|
|
|
3732
3914
|
}
|
|
3733
3915
|
},
|
|
3734
3916
|
};
|
|
3917
|
+
/**
|
|
3918
|
+
*
|
|
3919
|
+
* @param {string[]} fs
|
|
3920
|
+
* @param {Record<string, string | Component.Event.Filter>} filters
|
|
3921
|
+
* @param {AddEventListenerOptions?} [options]
|
|
3922
|
+
* @returns
|
|
3923
|
+
*/
|
|
3924
|
+
function findFilters(fs, filters, options) {
|
|
3925
|
+
/** @type {[Component.Event.Filter, string[], boolean][]} */
|
|
3926
|
+
const filterFns = [];
|
|
3927
|
+
if (filters) for (let f = fs.shift(); f; f = fs.shift()) {
|
|
3928
|
+
const paramIndex = f.indexOf(':');
|
|
3929
|
+
const noParamName = paramIndex >= 0 ? f.slice(0, paramIndex) : f;
|
|
3930
|
+
const param = paramIndex >= 0 ? f.slice(paramIndex + 1).split(':') : [];
|
|
3931
|
+
const filterName = noParamName.replace(/^-+/, '');
|
|
3932
|
+
const sub = (noParamName.length - filterName.length) % 2 === 1;
|
|
3933
|
+
let filter = filters[filterName] || filterName;
|
|
3934
|
+
if (options) {
|
|
3935
|
+
switch (filter) {
|
|
3936
|
+
case 'once': case 'passive': case 'capture': options[filter] = !sub; continue;
|
|
3937
|
+
}
|
|
3938
|
+
}
|
|
3939
|
+
if (typeof filter === 'string') {
|
|
3940
|
+
filter = eventFilters[filter];
|
|
3941
|
+
}
|
|
3942
|
+
if (typeof filter !== 'function') { continue; }
|
|
3943
|
+
filterFns.push([filter, param, sub]);
|
|
3944
|
+
}
|
|
3945
|
+
return filterFns;
|
|
3946
|
+
}
|
|
3947
|
+
|
|
3948
|
+
/**
|
|
3949
|
+
*
|
|
3950
|
+
* @param {Environment} env
|
|
3951
|
+
* @param {Layout.EventListener} fn
|
|
3952
|
+
* @param {[Component.Event.Filter, string[], boolean][]} filterFns
|
|
3953
|
+
* @returns {($event: any) => void}
|
|
3954
|
+
*/
|
|
3955
|
+
function bindFilters(env, fn, filterFns) {
|
|
3956
|
+
return $event => {
|
|
3957
|
+
const global = env.all;
|
|
3958
|
+
for (const [filter, param, sub] of filterFns) {
|
|
3959
|
+
if (filter($event, param, global) === sub) { return; }
|
|
3960
|
+
}
|
|
3961
|
+
fn($event, global);
|
|
3962
|
+
}
|
|
3963
|
+
}
|
|
3964
|
+
|
|
3965
|
+
/** @import { Component, Relatedness } from '../types.mjs' */
|
|
3966
|
+
/** @import Store from '../Store/index.mjs' */
|
|
3967
|
+
/** @import Environment from './Environment/index.mjs' */
|
|
3968
|
+
|
|
3969
|
+
|
|
3735
3970
|
/**
|
|
3736
3971
|
*
|
|
3737
3972
|
* @param {Component | string} component
|
|
3738
3973
|
* @param {Environment} env
|
|
3739
|
-
* @param {
|
|
3974
|
+
* @param {Store?} store
|
|
3975
|
+
* @param {((store: Store, el: Element | Relatedness) => () => void)?} [relate]
|
|
3740
3976
|
* @returns
|
|
3741
3977
|
*/
|
|
3742
|
-
function createContext(component, env, relate) {
|
|
3978
|
+
function createContext(component, env, store, relate) {
|
|
3743
3979
|
const tag = typeof component === 'string' ? component : component.tag;
|
|
3744
3980
|
const { attrs, events } = typeof component !== 'string' && component || { attrs: null, events: null };
|
|
3745
3981
|
|
|
@@ -3780,9 +4016,9 @@
|
|
|
3780
4016
|
};
|
|
3781
4017
|
},
|
|
3782
4018
|
relate(el) {
|
|
3783
|
-
if (!relate || destroyed) { return () => { }; }
|
|
4019
|
+
if (!store || !relate || destroyed) { return () => { }; }
|
|
3784
4020
|
try {
|
|
3785
|
-
const w = relate(
|
|
4021
|
+
const w = relate(store, el);
|
|
3786
4022
|
if (typeof w !== 'function') { return () => { }; }
|
|
3787
4023
|
cancelFns.add(w);
|
|
3788
4024
|
return () => {
|
|
@@ -3823,40 +4059,8 @@
|
|
|
3823
4059
|
if (!filters) { return; }
|
|
3824
4060
|
/** @type {AddEventListenerOptions} */
|
|
3825
4061
|
const options = {};
|
|
3826
|
-
|
|
3827
|
-
|
|
3828
|
-
if (filters) for (let f = fs.shift(); f; f = fs.shift()) {
|
|
3829
|
-
const paramIndex = f.indexOf(':');
|
|
3830
|
-
const noParamName = paramIndex >= 0 ? f.slice(0, paramIndex) : f;
|
|
3831
|
-
const param = paramIndex >= 0 ? f.slice(paramIndex + 1).split(':') : [];
|
|
3832
|
-
const filterName = noParamName.replace(/^-+/, '');
|
|
3833
|
-
const sub = (noParamName.length - filterName.length) % 2 === 1;
|
|
3834
|
-
let filter = filters[filterName] || filterName;
|
|
3835
|
-
switch (filter) {
|
|
3836
|
-
case 'once':
|
|
3837
|
-
options.once = !sub;
|
|
3838
|
-
break;
|
|
3839
|
-
case 'passive':
|
|
3840
|
-
options.passive = !sub;
|
|
3841
|
-
break;
|
|
3842
|
-
case 'capture':
|
|
3843
|
-
options.capture = !sub;
|
|
3844
|
-
break;
|
|
3845
|
-
default:
|
|
3846
|
-
if (typeof filter === 'string') {
|
|
3847
|
-
filter = eventFilters[filter];
|
|
3848
|
-
}
|
|
3849
|
-
}
|
|
3850
|
-
if (typeof filter !== 'function') { continue; }
|
|
3851
|
-
filterFns.push([filter, param, sub]);
|
|
3852
|
-
}
|
|
3853
|
-
allEvents.push([e, $event => {
|
|
3854
|
-
const global = env.all;
|
|
3855
|
-
for (const [filter, param, sub] of filterFns) {
|
|
3856
|
-
if (filter($event, param, global) === sub) { return; }
|
|
3857
|
-
}
|
|
3858
|
-
fn($event, global);
|
|
3859
|
-
}, options]);
|
|
4062
|
+
const filterFns = findFilters(fs, filters, options);
|
|
4063
|
+
allEvents.push([e, bindFilters(env, fn, filterFns), options]);
|
|
3860
4064
|
},
|
|
3861
4065
|
destroy() {
|
|
3862
4066
|
if (destroyed) { return; }
|
|
@@ -4046,6 +4250,9 @@
|
|
|
4046
4250
|
function createTagComponent (context, name, is) {
|
|
4047
4251
|
const node = document.createElement(name, {is: is || undefined});
|
|
4048
4252
|
const { watchAttr, props } = context;
|
|
4253
|
+
if(['input', 'textarea', 'select'].includes(name.toLowerCase())) {
|
|
4254
|
+
context.relate(node);
|
|
4255
|
+
}
|
|
4049
4256
|
|
|
4050
4257
|
context.listen('init', ({events})=> {
|
|
4051
4258
|
const e = tagBindMap[name.toLowerCase()];
|
|
@@ -4224,7 +4431,7 @@
|
|
|
4224
4431
|
* @param {Element} parent
|
|
4225
4432
|
* @param {Node?} next
|
|
4226
4433
|
* @param {Environment} envs
|
|
4227
|
-
* @param {Layout.
|
|
4434
|
+
* @param {Layout.Node} layout
|
|
4228
4435
|
*/
|
|
4229
4436
|
function renderFillDirectives(parent, next, envs, { text, html }) {
|
|
4230
4437
|
if (text != null) {
|
|
@@ -4278,18 +4485,18 @@
|
|
|
4278
4485
|
|
|
4279
4486
|
/** @type {Set<() => void>?} */
|
|
4280
4487
|
let bkList = new Set();
|
|
4281
|
-
/** @type {[
|
|
4488
|
+
/** @type {[Layout.Node.Name | Layout.Node.Calc | Layout.Node.Value | null, Layout.Node][]} */
|
|
4282
4489
|
let ifList = [];
|
|
4283
4490
|
/** @type {Record<string, [Layout.Node, Environment]>} */
|
|
4284
4491
|
let currentTemplates = Object.create(templates);
|
|
4285
4492
|
for (const layout of layouts) {
|
|
4286
4493
|
if (typeof layout === 'string') { continue; }
|
|
4287
|
-
const name = layout.
|
|
4494
|
+
const name = layout.template;
|
|
4288
4495
|
if (!name) { continue; }
|
|
4289
4496
|
currentTemplates[name] = [layout, envs];
|
|
4290
4497
|
}
|
|
4291
4498
|
|
|
4292
|
-
/** @param {[
|
|
4499
|
+
/** @param {[Layout.Node.Name | Layout.Node.Calc | Layout.Node.Value | null, Layout.Node][]} list */
|
|
4293
4500
|
function renderIf(list) {
|
|
4294
4501
|
if (!list.length || !bkList) { return; }
|
|
4295
4502
|
const end = parent.insertBefore(document.createComment(''), next);
|
|
@@ -4313,7 +4520,7 @@
|
|
|
4313
4520
|
end.remove();
|
|
4314
4521
|
});
|
|
4315
4522
|
bkList.add(watch(
|
|
4316
|
-
() => list.findIndex(([ifv]) => ifv
|
|
4523
|
+
() => list.findIndex(([ifv]) => !ifv || envs.exec(ifv)),
|
|
4317
4524
|
index => {
|
|
4318
4525
|
if (index === lastIndex) { return; }
|
|
4319
4526
|
lastIndex = index;
|
|
@@ -4332,13 +4539,13 @@
|
|
|
4332
4539
|
bkList.add(() => node.remove());
|
|
4333
4540
|
continue;
|
|
4334
4541
|
}
|
|
4335
|
-
if (layout.
|
|
4542
|
+
if (layout.template) {
|
|
4336
4543
|
renderIf(ifList);
|
|
4337
4544
|
ifList = [];
|
|
4338
4545
|
continue;
|
|
4339
4546
|
}
|
|
4340
|
-
if (ifList.length && layout.
|
|
4341
|
-
const ifv = layout.
|
|
4547
|
+
if (ifList.length && layout.else) {
|
|
4548
|
+
const ifv = layout.if || null;
|
|
4342
4549
|
ifList.push([ifv, layout]);
|
|
4343
4550
|
if (!ifv) {
|
|
4344
4551
|
renderIf(ifList);
|
|
@@ -4348,7 +4555,7 @@
|
|
|
4348
4555
|
}
|
|
4349
4556
|
renderIf(ifList);
|
|
4350
4557
|
ifList = [];
|
|
4351
|
-
const ifv = layout.
|
|
4558
|
+
const ifv = layout.if;
|
|
4352
4559
|
if (ifv) {
|
|
4353
4560
|
ifList.push([ifv, layout]);
|
|
4354
4561
|
continue;
|
|
@@ -4357,6 +4564,7 @@
|
|
|
4357
4564
|
renderItem(layout, currentTemplates)
|
|
4358
4565
|
);
|
|
4359
4566
|
}
|
|
4567
|
+
renderIf(ifList);
|
|
4360
4568
|
|
|
4361
4569
|
return () => {
|
|
4362
4570
|
if (!bkList) { return; }
|
|
@@ -4503,6 +4711,135 @@
|
|
|
4503
4711
|
}
|
|
4504
4712
|
}
|
|
4505
4713
|
|
|
4714
|
+
/** @import Environment from './Environment/index.mjs' */
|
|
4715
|
+
/** @import { Enhancement } from '../types.mjs' */
|
|
4716
|
+
/** @import * as Layout from '../Layout/index.mjs' */
|
|
4717
|
+
|
|
4718
|
+
/**
|
|
4719
|
+
*
|
|
4720
|
+
* @param {object} obj
|
|
4721
|
+
* @param {string} name
|
|
4722
|
+
* @returns
|
|
4723
|
+
*/
|
|
4724
|
+
const hasOwnProperty = (obj, name) => Object.prototype.hasOwnProperty.call(obj, name);
|
|
4725
|
+
/**
|
|
4726
|
+
* @param {any} tag
|
|
4727
|
+
* @param {Record<string, Layout.Enhancement>} enhancementDefine
|
|
4728
|
+
* @param {Environment} env
|
|
4729
|
+
* @param {Record<string, Enhancement>} enhancements
|
|
4730
|
+
* @param {Element} root
|
|
4731
|
+
* @param {Element?} [slot]
|
|
4732
|
+
*/
|
|
4733
|
+
function bindEnhancements(tag, enhancementDefine, env, enhancements, root, slot) {
|
|
4734
|
+
|
|
4735
|
+
let bk = new Set();
|
|
4736
|
+
for (const [name, { attrs: attrDefine, value, events: eventsDefine, bind }] of Object.entries(enhancementDefine)) {
|
|
4737
|
+
if (!hasOwnProperty(enhancements, name)) { continue; }
|
|
4738
|
+
const enhancement = enhancements[name];
|
|
4739
|
+
if (typeof enhancement !== 'function') { continue; }
|
|
4740
|
+
|
|
4741
|
+
|
|
4742
|
+
let destroyed = false;
|
|
4743
|
+
const destroyedState = new exports.Signal.State(false);
|
|
4744
|
+
const events = /** @type {any} */(enhancement)?.events;
|
|
4745
|
+
/** @type {[string, ($event: any) => void, AddEventListenerOptions][]} */
|
|
4746
|
+
const allEvents = [];
|
|
4747
|
+
const attrs = Object.create(null);
|
|
4748
|
+
/** @type {Set<() => void>} */
|
|
4749
|
+
const cancelFns = new Set();
|
|
4750
|
+
const stateEmitter = new EventEmitter();
|
|
4751
|
+
|
|
4752
|
+
/**
|
|
4753
|
+
*
|
|
4754
|
+
* @param {string} name
|
|
4755
|
+
* @param {Layout.EventListener} fn
|
|
4756
|
+
* @returns
|
|
4757
|
+
*/
|
|
4758
|
+
function addEvent(name, fn) {
|
|
4759
|
+
if (typeof fn !== 'function') { return; }
|
|
4760
|
+
const [e, ...fs] = name.split('.').filter(Boolean);
|
|
4761
|
+
const filters = events ? events[e].filters : {};
|
|
4762
|
+
if (!filters) { return; }
|
|
4763
|
+
/** @type {AddEventListenerOptions} */
|
|
4764
|
+
const options = {};
|
|
4765
|
+
const filterFns = findFilters(fs, filters, options);
|
|
4766
|
+
allEvents.push([e, bindFilters(env, fn, filterFns), options]);
|
|
4767
|
+
}
|
|
4768
|
+
function destroy() {
|
|
4769
|
+
if (destroyed) { return; }
|
|
4770
|
+
destroyed = true;
|
|
4771
|
+
destroyedState.set(true);
|
|
4772
|
+
for (const w of cancelFns) {
|
|
4773
|
+
w();
|
|
4774
|
+
}
|
|
4775
|
+
stateEmitter.emit('destroy');
|
|
4776
|
+
}
|
|
4777
|
+
bk.add(destroy);
|
|
4778
|
+
|
|
4779
|
+
|
|
4780
|
+
|
|
4781
|
+
for (const [name, attr] of Object.entries(attrDefine)) {
|
|
4782
|
+
const s = env.get(attr);
|
|
4783
|
+
if (!s) { continue; }
|
|
4784
|
+
Object.defineProperty(attrs, name, { ...s, configurable: true, enumerable: true });
|
|
4785
|
+
}
|
|
4786
|
+
|
|
4787
|
+
for (const [name, event] of Object.entries(eventsDefine)) {
|
|
4788
|
+
const fn = env.getEvent(event);
|
|
4789
|
+
if (fn) { addEvent(name, fn); }
|
|
4790
|
+
}
|
|
4791
|
+
|
|
4792
|
+
if (bind) {
|
|
4793
|
+
for (const [key, effect] of Object.entries(env.getBindAll(bind) || {})) {
|
|
4794
|
+
Object.defineProperty(attrs, key, { ...effect, configurable: true, enumerable: true });
|
|
4795
|
+
}
|
|
4796
|
+
for (const [key, setter] of Object.entries(env.bindEvents(bind) || {})) {
|
|
4797
|
+
addEvent(key, $event => setter($event));
|
|
4798
|
+
}
|
|
4799
|
+
|
|
4800
|
+
}
|
|
4801
|
+
/**@type {Enhancement.Context} */
|
|
4802
|
+
const context = {
|
|
4803
|
+
get value() { return null; },
|
|
4804
|
+
events: allEvents,
|
|
4805
|
+
attrs: attrs,
|
|
4806
|
+
watchAttr(name, fn) {
|
|
4807
|
+
if (destroyed) { return () => { }; }
|
|
4808
|
+
let old = attrs[name];
|
|
4809
|
+
const w = watch(() => attrs[name], v => {
|
|
4810
|
+
const o = old;
|
|
4811
|
+
old = v;
|
|
4812
|
+
fn(v, o, name);
|
|
4813
|
+
}, true);
|
|
4814
|
+
cancelFns.add(w);
|
|
4815
|
+
|
|
4816
|
+
return () => {
|
|
4817
|
+
cancelFns.delete(w);
|
|
4818
|
+
w();
|
|
4819
|
+
};
|
|
4820
|
+
},
|
|
4821
|
+
get destroyed() { return destroyedState.get(); },
|
|
4822
|
+
listen(name, listener) { return stateEmitter.listen(name, listener); },
|
|
4823
|
+
root, slot,
|
|
4824
|
+
tag,
|
|
4825
|
+
};
|
|
4826
|
+
if (value) {
|
|
4827
|
+
const s = env.get(value);
|
|
4828
|
+
if (s) {
|
|
4829
|
+
Object.defineProperty(context, 'value', { ...s, configurable: true, enumerable: true });
|
|
4830
|
+
}
|
|
4831
|
+
}
|
|
4832
|
+
enhancement(context);
|
|
4833
|
+
}
|
|
4834
|
+
return () => {
|
|
4835
|
+
const list = bk;
|
|
4836
|
+
bk = new Set();
|
|
4837
|
+
for (const s of list) {
|
|
4838
|
+
s();
|
|
4839
|
+
}
|
|
4840
|
+
};
|
|
4841
|
+
}
|
|
4842
|
+
|
|
4506
4843
|
/** @import Store from '../Store/index.mjs' */
|
|
4507
4844
|
|
|
4508
4845
|
/**
|
|
@@ -4512,31 +4849,36 @@
|
|
|
4512
4849
|
* @param {Environment} env
|
|
4513
4850
|
* @param {Record<string, [Layout.Node, Environment]>} templates
|
|
4514
4851
|
* @param {string[]} componentPath
|
|
4515
|
-
* @param {
|
|
4852
|
+
* @param {Record<string, Enhancement>} enhancements
|
|
4853
|
+
* @param {((store: Store, el: Element | Relatedness) => () => void)?} [relate]
|
|
4516
4854
|
* @param {Component.Getter?} [getComponent]
|
|
4517
4855
|
*/
|
|
4518
|
-
function renderItem(layout, parent, next, env, templates, componentPath, relate, getComponent) {
|
|
4856
|
+
function renderItem(layout, parent, next, env, templates, componentPath, enhancements, relate, getComponent) {
|
|
4519
4857
|
env = env.set(layout.aliases, layout.vars);
|
|
4520
|
-
const bind = layout.
|
|
4521
|
-
const fragment = layout.
|
|
4858
|
+
const bind = layout.bind;
|
|
4859
|
+
const fragment = layout.fragment;
|
|
4522
4860
|
if (fragment && typeof fragment === 'string') {
|
|
4523
4861
|
const template = templates[fragment];
|
|
4524
4862
|
if (!template) { return () => {}; }
|
|
4525
4863
|
const [templateLayout, templateEnv] = template;
|
|
4526
4864
|
const newEnv = templateEnv.params(templateLayout, layout, env, bind);
|
|
4527
|
-
return render(templateLayout, parent, next, newEnv, templates, componentPath, relate, getComponent);
|
|
4865
|
+
return render(templateLayout, parent, next, newEnv, templates, componentPath, enhancements, relate, getComponent);
|
|
4528
4866
|
}
|
|
4529
|
-
if (!layout.name || layout.
|
|
4530
|
-
return renderFillDirectives(parent, next, env, layout
|
|
4867
|
+
if (!layout.name || layout.fragment) {
|
|
4868
|
+
return renderFillDirectives(parent, next, env, layout) ||
|
|
4531
4869
|
renderList(layout.children || [], parent, next, env, templates, (layout, templates) => {
|
|
4532
|
-
return render(layout, parent, next, env, templates, componentPath, relate, getComponent);
|
|
4870
|
+
return render(layout, parent, next, env, templates, componentPath, enhancements, relate, getComponent);
|
|
4533
4871
|
});
|
|
4534
4872
|
}
|
|
4535
4873
|
const path = [...componentPath, layout.name];
|
|
4536
4874
|
const component = getComponent?.(path);
|
|
4537
4875
|
if (getComponent && !component) { return () => { }; }
|
|
4538
|
-
const { context, handler } = createContext(
|
|
4539
|
-
|
|
4876
|
+
const { context, handler } = createContext(
|
|
4877
|
+
component ? component : layout.name,
|
|
4878
|
+
env,
|
|
4879
|
+
env.getStore(bind),
|
|
4880
|
+
relate
|
|
4881
|
+
);
|
|
4540
4882
|
|
|
4541
4883
|
const componentAttrs = component?.attrs;
|
|
4542
4884
|
const attrs = componentAttrs
|
|
@@ -4560,23 +4902,27 @@
|
|
|
4560
4902
|
const slot = Array.isArray(r) ? r[1] : root;
|
|
4561
4903
|
parent.insertBefore(root, next);
|
|
4562
4904
|
const children = slot ?
|
|
4563
|
-
renderFillDirectives(slot, null, env, layout
|
|
4905
|
+
renderFillDirectives(slot, null, env, layout)
|
|
4564
4906
|
|| renderList(layout.children || [], slot, null, env, templates, (layout, templates) => {
|
|
4565
|
-
return render(layout, slot, null, env, templates, componentPath, relate, getComponent);
|
|
4907
|
+
return render(layout, slot, null, env, templates, componentPath, enhancements, relate, getComponent);
|
|
4566
4908
|
}) : () => {};
|
|
4567
4909
|
|
|
4568
4910
|
|
|
4569
|
-
bindClasses(root, layout.classes,
|
|
4570
|
-
bindStyles(root, layout.styles,
|
|
4911
|
+
const classes = bindClasses(root, env, layout.classes, layout.attrs.class);
|
|
4912
|
+
const styles = bindStyles(root, env, layout.styles, layout.attrs.style);
|
|
4571
4913
|
|
|
4572
4914
|
handler.mount();
|
|
4915
|
+
const enhancement = bindEnhancements(handler.tag, layout.enhancements, env, enhancements, root, slot);
|
|
4573
4916
|
|
|
4574
4917
|
return () => {
|
|
4575
|
-
|
|
4918
|
+
enhancement();
|
|
4576
4919
|
handler.destroy();
|
|
4920
|
+
root.remove();
|
|
4577
4921
|
attrs();
|
|
4578
4922
|
children();
|
|
4579
4923
|
base();
|
|
4924
|
+
classes();
|
|
4925
|
+
styles();
|
|
4580
4926
|
};
|
|
4581
4927
|
}
|
|
4582
4928
|
/**
|
|
@@ -4587,17 +4933,17 @@
|
|
|
4587
4933
|
* @param {Environment} env
|
|
4588
4934
|
* @param {Record<string, [Layout.Node, Environment]>} templates
|
|
4589
4935
|
* @param {string[]} componentPath
|
|
4590
|
-
* @param {
|
|
4936
|
+
* @param {Record<string, Enhancement>} enhancements
|
|
4937
|
+
* @param {((store: Store, el: Element | Relatedness) => () => void)?} [relate]
|
|
4591
4938
|
* @param {Component.Getter?} [getComponent]
|
|
4592
4939
|
* @returns {() => void}
|
|
4593
4940
|
*/
|
|
4594
|
-
function render(layout, parent, next, env, templates, componentPath, relate, getComponent) {
|
|
4595
|
-
const
|
|
4596
|
-
const newEnv = env.child(directives.value);
|
|
4941
|
+
function render(layout, parent, next, env, templates, componentPath, enhancements, relate, getComponent) {
|
|
4942
|
+
const newEnv = env.child(layout.value);
|
|
4597
4943
|
if (!newEnv) { return () => {}; }
|
|
4598
|
-
const list = newEnv.enum(
|
|
4944
|
+
const list = newEnv.enum(layout.enum);
|
|
4599
4945
|
/** @type {(next: Node | null, env: any) => () => void} */
|
|
4600
|
-
const r = (next, env) => renderItem(layout, parent, next, env, templates, componentPath, relate, getComponent);
|
|
4946
|
+
const r = (next, env) => renderItem(layout, parent, next, env, templates, componentPath, enhancements, relate, getComponent);
|
|
4601
4947
|
if (list === true) {
|
|
4602
4948
|
return r(next, newEnv);
|
|
4603
4949
|
}
|
|
@@ -4620,15 +4966,17 @@
|
|
|
4620
4966
|
* @param {object} [options]
|
|
4621
4967
|
* @param {Record<string, Store | {get?(): any; set?(v: any): void; exec?(...p: any[]): any; calc?(...p: any[]): any }>} [options.global]
|
|
4622
4968
|
* @param {(path: string[]) => Component?} [options.component]
|
|
4623
|
-
* @param {(store: Store, el: Element) => () => void} [options.relate]
|
|
4969
|
+
* @param {(store: Store, el: Element | Relatedness) => () => void} [options.relate]
|
|
4970
|
+
* @param {Record<string, Enhancement>} [options.enhancements]
|
|
4624
4971
|
* @returns {() => void}
|
|
4625
4972
|
*/
|
|
4626
|
-
function index (store, layouts, parent, {component, global, relate} = {}) {
|
|
4973
|
+
function index (store, layouts, parent, {component, global, relate, enhancements} = {}) {
|
|
4627
4974
|
const env = new Environment(store, global);
|
|
4628
4975
|
const templates = Object.create(null);
|
|
4976
|
+
const allEnhancements = enhancements || {};
|
|
4629
4977
|
const relateFn = typeof relate === 'function' ? relate : null;
|
|
4630
4978
|
return renderList(layouts, parent, null, env, templates, (layout, templates) => {
|
|
4631
|
-
return render(layout, parent, null, env, templates, [], relateFn, component);
|
|
4979
|
+
return render(layout, parent, null, env, templates, [], allEnhancements, relateFn, component);
|
|
4632
4980
|
});
|
|
4633
4981
|
}
|
|
4634
4982
|
|