@jxsuite/runtime 3.1.0 → 4.0.1
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/dist/runtime.js +1460 -516
- package/dist/runtime.js.map +8 -8
- package/package.json +3 -3
- package/src/css.ts +767 -3
- package/src/expression.ts +34 -2
- package/src/runtime.ts +1917 -330
- package/src/statements.ts +42 -5
- package/src/types.ts +73 -1
package/dist/runtime.js
CHANGED
|
@@ -177,6 +177,13 @@ class EffectScope {
|
|
|
177
177
|
function effectScope(detached) {
|
|
178
178
|
return new EffectScope(detached);
|
|
179
179
|
}
|
|
180
|
+
function onScopeDispose(fn, failSilently = false) {
|
|
181
|
+
if (activeEffectScope) {
|
|
182
|
+
activeEffectScope.cleanups.push(fn);
|
|
183
|
+
} else if (!failSilently) {
|
|
184
|
+
warn(`onScopeDispose() is called when there is no active effect scope to be associated with.`);
|
|
185
|
+
}
|
|
186
|
+
}
|
|
180
187
|
var activeSub;
|
|
181
188
|
var pausedQueueEffects = /* @__PURE__ */ new WeakSet;
|
|
182
189
|
|
|
@@ -1012,6 +1019,7 @@ class ReadonlyReactiveHandler extends BaseReactiveHandler {
|
|
|
1012
1019
|
}
|
|
1013
1020
|
var mutableHandlers = /* @__PURE__ */ new MutableReactiveHandler;
|
|
1014
1021
|
var readonlyHandlers = /* @__PURE__ */ new ReadonlyReactiveHandler;
|
|
1022
|
+
var shallowReactiveHandlers = /* @__PURE__ */ new MutableReactiveHandler(true);
|
|
1015
1023
|
var toShallow = (value) => value;
|
|
1016
1024
|
var getProto = (v) => Reflect.getPrototypeOf(v);
|
|
1017
1025
|
function createIterableMethod(method, isReadonly2, isShallow2) {
|
|
@@ -1189,6 +1197,9 @@ function createInstrumentationGetter(isReadonly2, shallow) {
|
|
|
1189
1197
|
var mutableCollectionHandlers = {
|
|
1190
1198
|
get: /* @__PURE__ */ createInstrumentationGetter(false, false)
|
|
1191
1199
|
};
|
|
1200
|
+
var shallowCollectionHandlers = {
|
|
1201
|
+
get: /* @__PURE__ */ createInstrumentationGetter(false, true)
|
|
1202
|
+
};
|
|
1192
1203
|
var readonlyCollectionHandlers = {
|
|
1193
1204
|
get: /* @__PURE__ */ createInstrumentationGetter(true, false)
|
|
1194
1205
|
};
|
|
@@ -1223,6 +1234,9 @@ function reactive(target) {
|
|
|
1223
1234
|
}
|
|
1224
1235
|
return createReactiveObject(target, false, mutableHandlers, mutableCollectionHandlers, reactiveMap);
|
|
1225
1236
|
}
|
|
1237
|
+
function shallowReactive(target) {
|
|
1238
|
+
return createReactiveObject(target, false, shallowReactiveHandlers, shallowCollectionHandlers, shallowReactiveMap);
|
|
1239
|
+
}
|
|
1226
1240
|
function readonly(target) {
|
|
1227
1241
|
return createReactiveObject(target, true, readonlyHandlers, readonlyCollectionHandlers, readonlyMap);
|
|
1228
1242
|
}
|
|
@@ -1384,6 +1398,79 @@ function computed(getterOrOptions, debugOptions, isSSR = false) {
|
|
|
1384
1398
|
return cRef;
|
|
1385
1399
|
}
|
|
1386
1400
|
|
|
1401
|
+
// ../schema/src/guards.ts
|
|
1402
|
+
function isJsonObject(value) {
|
|
1403
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
1404
|
+
}
|
|
1405
|
+
function isRef2(value) {
|
|
1406
|
+
return isJsonObject(value) && typeof value.$ref === "string";
|
|
1407
|
+
}
|
|
1408
|
+
function isFunctionDef(value) {
|
|
1409
|
+
return isJsonObject(value) && value.$prototype === "Function";
|
|
1410
|
+
}
|
|
1411
|
+
function isExpressionDef(value) {
|
|
1412
|
+
return isJsonObject(value) && isJsonObject(value.$expression);
|
|
1413
|
+
}
|
|
1414
|
+
function isNamedFormulaDef(value) {
|
|
1415
|
+
return isExpressionDef(value) && Array.isArray(value.parameters) && value.parameters.length > 0;
|
|
1416
|
+
}
|
|
1417
|
+
function hasStructuredBody(value) {
|
|
1418
|
+
return isFunctionDef(value) && Array.isArray(value.body);
|
|
1419
|
+
}
|
|
1420
|
+
function isPrototypeDef(value) {
|
|
1421
|
+
return isJsonObject(value) && typeof value.$prototype === "string" && value.$prototype !== "Function";
|
|
1422
|
+
}
|
|
1423
|
+
function isServerFnDef(value) {
|
|
1424
|
+
return isJsonObject(value) && value.timing === "server" && typeof value.$src === "string" && typeof value.$export === "string" && !value.$prototype;
|
|
1425
|
+
}
|
|
1426
|
+
var SCHEMA_KEYWORDS = new Set([
|
|
1427
|
+
"type",
|
|
1428
|
+
"enum",
|
|
1429
|
+
"minimum",
|
|
1430
|
+
"maximum",
|
|
1431
|
+
"minLength",
|
|
1432
|
+
"maxLength",
|
|
1433
|
+
"pattern",
|
|
1434
|
+
"format",
|
|
1435
|
+
"items",
|
|
1436
|
+
"properties",
|
|
1437
|
+
"required",
|
|
1438
|
+
"description",
|
|
1439
|
+
"title",
|
|
1440
|
+
"$comment"
|
|
1441
|
+
]);
|
|
1442
|
+
function isMappedArray(value) {
|
|
1443
|
+
return isJsonObject(value) && value.$prototype === "Array";
|
|
1444
|
+
}
|
|
1445
|
+
function isTemplateString(value) {
|
|
1446
|
+
return typeof value === "string" && value.includes("${");
|
|
1447
|
+
}
|
|
1448
|
+
function bodyReturnsValue(body) {
|
|
1449
|
+
return /\breturn\b[^\S\n]*(?![;}\s]|$)/.test(body);
|
|
1450
|
+
}
|
|
1451
|
+
function paramNames(parameters) {
|
|
1452
|
+
if (!parameters) {
|
|
1453
|
+
return [];
|
|
1454
|
+
}
|
|
1455
|
+
return parameters.map((p) => typeof p === "string" ? p : p.name);
|
|
1456
|
+
}
|
|
1457
|
+
function isTagExpression(tagName) {
|
|
1458
|
+
if (!isJsonObject(tagName) || !isJsonObject(tagName.$expression)) {
|
|
1459
|
+
return false;
|
|
1460
|
+
}
|
|
1461
|
+
const expression = tagName.$expression;
|
|
1462
|
+
if (expression.operator === "?:") {
|
|
1463
|
+
return typeof expression.value === "string" && typeof expression.initial === "string";
|
|
1464
|
+
}
|
|
1465
|
+
if (expression.operator === "switch") {
|
|
1466
|
+
return isJsonObject(expression.cases) && Object.values(expression.cases).every((tag) => typeof tag === "string") && typeof expression.default === "string";
|
|
1467
|
+
}
|
|
1468
|
+
return false;
|
|
1469
|
+
}
|
|
1470
|
+
function isPrivateStateKey(key) {
|
|
1471
|
+
return key.startsWith("#");
|
|
1472
|
+
}
|
|
1473
|
+
|
|
1387
1474
|
// src/css.ts
|
|
1388
1475
|
function camelToKebab(s) {
|
|
1389
1476
|
return s.replaceAll(/[A-Z]/g, (c) => `-${c.toLowerCase()}`);
|
|
@@ -1399,6 +1486,90 @@ function resolveAtQuery(atKey, mediaQueries) {
|
|
|
1399
1486
|
}
|
|
1400
1487
|
return null;
|
|
1401
1488
|
}
|
|
1489
|
+
function isDeclarationAtRule(atKey) {
|
|
1490
|
+
return atKey.startsWith("@position-try") || atKey.startsWith("@property") || atKey.startsWith("@font-face") || atKey.startsWith("@counter-style");
|
|
1491
|
+
}
|
|
1492
|
+
function isKeyframesAtRule(atKey) {
|
|
1493
|
+
return atKey.startsWith("@keyframes");
|
|
1494
|
+
}
|
|
1495
|
+
function resolveNestedSelector(scope, key) {
|
|
1496
|
+
const resolved = [];
|
|
1497
|
+
for (const scopePart of splitSelectorList(scope)) {
|
|
1498
|
+
for (const keyPart of splitSelectorList(key)) {
|
|
1499
|
+
resolved.push(resolveOneNestedSelector(scopePart, keyPart));
|
|
1500
|
+
}
|
|
1501
|
+
}
|
|
1502
|
+
return resolved.join(", ");
|
|
1503
|
+
}
|
|
1504
|
+
function resolveOneNestedSelector(scope, key) {
|
|
1505
|
+
if (key.startsWith("&")) {
|
|
1506
|
+
return key.replaceAll("&", scope);
|
|
1507
|
+
}
|
|
1508
|
+
if (key.startsWith("[") || key.startsWith(":") || key.startsWith(".")) {
|
|
1509
|
+
return `${scope}${key}`;
|
|
1510
|
+
}
|
|
1511
|
+
return `${scope} ${key}`;
|
|
1512
|
+
}
|
|
1513
|
+
function splitSelectorList(selector) {
|
|
1514
|
+
const members = [];
|
|
1515
|
+
let depth = 0;
|
|
1516
|
+
let quote = null;
|
|
1517
|
+
let start = 0;
|
|
1518
|
+
for (let i = 0;i < selector.length; i += 1) {
|
|
1519
|
+
const ch = selector[i];
|
|
1520
|
+
if (quote) {
|
|
1521
|
+
if (ch === "\\") {
|
|
1522
|
+
i += 1;
|
|
1523
|
+
} else if (ch === quote) {
|
|
1524
|
+
quote = null;
|
|
1525
|
+
}
|
|
1526
|
+
continue;
|
|
1527
|
+
}
|
|
1528
|
+
if (ch === '"' || ch === "'") {
|
|
1529
|
+
quote = ch;
|
|
1530
|
+
} else if (ch === "(" || ch === "[") {
|
|
1531
|
+
depth += 1;
|
|
1532
|
+
} else if (ch === ")" || ch === "]") {
|
|
1533
|
+
depth = Math.max(0, depth - 1);
|
|
1534
|
+
} else if (ch === "," && depth === 0) {
|
|
1535
|
+
members.push(selector.slice(start, i));
|
|
1536
|
+
start = i + 1;
|
|
1537
|
+
}
|
|
1538
|
+
}
|
|
1539
|
+
members.push(selector.slice(start));
|
|
1540
|
+
const trimmed = members.map((member) => member.trim()).filter((member) => member !== "");
|
|
1541
|
+
return trimmed.length > 0 ? trimmed : [selector];
|
|
1542
|
+
}
|
|
1543
|
+
function transposeCanvasPopoverSelector(selector) {
|
|
1544
|
+
return transposeCanvasOverlaySelector(selector);
|
|
1545
|
+
}
|
|
1546
|
+
var COMPOUND_BREAK = /[\s>+~,()]/;
|
|
1547
|
+
var LEADING_TYPE = /^[A-Za-z_\u{00A0}-\u{FFFF}][\w\u{00A0}-\u{FFFF}-]*/u;
|
|
1548
|
+
function transposeOpenAttribute(selector, options) {
|
|
1549
|
+
let out = "";
|
|
1550
|
+
let from = 0;
|
|
1551
|
+
for (;; ) {
|
|
1552
|
+
const at = selector.indexOf("[open]", from);
|
|
1553
|
+
if (at === -1) {
|
|
1554
|
+
return out + selector.slice(from);
|
|
1555
|
+
}
|
|
1556
|
+
let start = at;
|
|
1557
|
+
while (start > 0 && !COMPOUND_BREAK.test(selector[start - 1])) {
|
|
1558
|
+
start -= 1;
|
|
1559
|
+
}
|
|
1560
|
+
const type = LEADING_TYPE.exec(selector.slice(start, at))?.[0]?.toLowerCase();
|
|
1561
|
+
const dialog = type === undefined ? options.dialog === true : type === "dialog";
|
|
1562
|
+
out += selector.slice(from, at) + (dialog ? "[data-jx-dialog-open]" : "[open]");
|
|
1563
|
+
from = at + "[open]".length;
|
|
1564
|
+
}
|
|
1565
|
+
}
|
|
1566
|
+
function transposeCanvasOverlaySelector(selector, options = {}) {
|
|
1567
|
+
if (selector.includes("::backdrop")) {
|
|
1568
|
+
return null;
|
|
1569
|
+
}
|
|
1570
|
+
const transposed = selector.replaceAll(":popover-open", "[data-jx-popover-open]").replaceAll(":modal", "[data-jx-dialog-open]").replaceAll("[inert]", "[data-jx-inert]");
|
|
1571
|
+
return transposeOpenAttribute(transposed, options);
|
|
1572
|
+
}
|
|
1402
1573
|
var COLOR_SCHEME_ATTR = "data-color-scheme";
|
|
1403
1574
|
var COLOR_SCHEME_STORAGE_KEY = "jx-color-scheme";
|
|
1404
1575
|
function pureSchemeOf(query) {
|
|
@@ -1417,6 +1588,195 @@ function schemeSelectors(selector, scheme) {
|
|
|
1417
1588
|
forced: `:where(:root[${COLOR_SCHEME_ATTR}="${scheme}"]) ${selector}`
|
|
1418
1589
|
};
|
|
1419
1590
|
}
|
|
1591
|
+
function isNestedSelectorKey(key) {
|
|
1592
|
+
return key.startsWith(":") || key.startsWith(".") || key.startsWith("&") || key.startsWith("[");
|
|
1593
|
+
}
|
|
1594
|
+
function cssPropertyName(property) {
|
|
1595
|
+
return property.startsWith("--") ? property : camelToKebab(property);
|
|
1596
|
+
}
|
|
1597
|
+
function hashCss(text) {
|
|
1598
|
+
let h = 2166136261;
|
|
1599
|
+
for (let i = 0;i < text.length; i += 1) {
|
|
1600
|
+
h ^= text.charCodeAt(i);
|
|
1601
|
+
h = Math.imul(h, 16777619);
|
|
1602
|
+
}
|
|
1603
|
+
return (h >>> 0).toString(36);
|
|
1604
|
+
}
|
|
1605
|
+
function cssRuleText(conditions, selector, declarations) {
|
|
1606
|
+
const body = declarations.map(([property, value]) => `${property}: ${value}`).join("; ");
|
|
1607
|
+
let text = selector === null ? body : `${selector} { ${body} }`;
|
|
1608
|
+
for (let i = conditions.length - 1;i >= 0; i -= 1) {
|
|
1609
|
+
text = `${conditions[i]} { ${text} }`;
|
|
1610
|
+
}
|
|
1611
|
+
return text;
|
|
1612
|
+
}
|
|
1613
|
+
function cssKeyframesText(conditions, name, blocks) {
|
|
1614
|
+
const body = blocks.map(({ selector, declarations }) => `${selector} { ${declarations.map(([property, value]) => `${property}: ${value}`).join("; ")} }`).join(" ");
|
|
1615
|
+
let text = `@keyframes ${name} { ${body} }`;
|
|
1616
|
+
for (let i = conditions.length - 1;i >= 0; i -= 1) {
|
|
1617
|
+
text = `${conditions[i]} { ${text} }`;
|
|
1618
|
+
}
|
|
1619
|
+
return text;
|
|
1620
|
+
}
|
|
1621
|
+
function withoutKeyframes(block) {
|
|
1622
|
+
const keyframeKeys = Object.keys(block).filter((key) => isKeyframesAtRule(key));
|
|
1623
|
+
if (keyframeKeys.length === 0) {
|
|
1624
|
+
return block;
|
|
1625
|
+
}
|
|
1626
|
+
const rest = { ...block };
|
|
1627
|
+
for (const key of keyframeKeys) {
|
|
1628
|
+
delete rest[key];
|
|
1629
|
+
}
|
|
1630
|
+
return rest;
|
|
1631
|
+
}
|
|
1632
|
+
function compoundsOntoScope(key) {
|
|
1633
|
+
const rest = key.startsWith("&") ? key.slice(1) : key;
|
|
1634
|
+
return rest === "" || rest.startsWith(":") || rest.startsWith(".") || rest.startsWith("[");
|
|
1635
|
+
}
|
|
1636
|
+
function buildStyleRules(style, options = {}) {
|
|
1637
|
+
const {
|
|
1638
|
+
scope = null,
|
|
1639
|
+
mediaQueries = {},
|
|
1640
|
+
transposeValue = (value) => value,
|
|
1641
|
+
transposeSelector = (selector) => selector,
|
|
1642
|
+
resolveValue
|
|
1643
|
+
} = options;
|
|
1644
|
+
const rules = [];
|
|
1645
|
+
const isBlock = (value) => value !== null && typeof value === "object" && !Array.isArray(value) && !isRef2(value);
|
|
1646
|
+
const blocksOf = (key, value) => {
|
|
1647
|
+
if (isBlock(value)) {
|
|
1648
|
+
return [value];
|
|
1649
|
+
}
|
|
1650
|
+
if (!isDeclarationAtRule(key) || !Array.isArray(value) || value.length === 0) {
|
|
1651
|
+
return [];
|
|
1652
|
+
}
|
|
1653
|
+
return value.every((entry) => isBlock(entry)) ? value : [];
|
|
1654
|
+
};
|
|
1655
|
+
const declarationValue = (property, value, reactive, target) => {
|
|
1656
|
+
if (value === undefined || value === null) {
|
|
1657
|
+
return null;
|
|
1658
|
+
}
|
|
1659
|
+
if (isRef2(value)) {
|
|
1660
|
+
return reactive ? resolveValue?.(property, value, target) ?? null : null;
|
|
1661
|
+
}
|
|
1662
|
+
if (typeof value === "object") {
|
|
1663
|
+
return null;
|
|
1664
|
+
}
|
|
1665
|
+
const raw = String(value);
|
|
1666
|
+
if (isTemplateString(raw)) {
|
|
1667
|
+
return reactive ? resolveValue?.(property, raw, target) ?? null : null;
|
|
1668
|
+
}
|
|
1669
|
+
return transposeValue(raw);
|
|
1670
|
+
};
|
|
1671
|
+
const declarationsOf = (node, skipSelectorKeys, reactive = true, target = "self") => {
|
|
1672
|
+
const declarations = [];
|
|
1673
|
+
for (const [key, value] of Object.entries(node)) {
|
|
1674
|
+
if (blocksOf(key, value).length > 0) {
|
|
1675
|
+
continue;
|
|
1676
|
+
}
|
|
1677
|
+
if (skipSelectorKeys && (key.startsWith("@") || isNestedSelectorKey(key))) {
|
|
1678
|
+
continue;
|
|
1679
|
+
}
|
|
1680
|
+
if (key.startsWith("$")) {
|
|
1681
|
+
continue;
|
|
1682
|
+
}
|
|
1683
|
+
const resolved = declarationValue(key, value, reactive, target);
|
|
1684
|
+
if (resolved !== null) {
|
|
1685
|
+
declarations.push([cssPropertyName(key), resolved]);
|
|
1686
|
+
}
|
|
1687
|
+
}
|
|
1688
|
+
return declarations;
|
|
1689
|
+
};
|
|
1690
|
+
const emit = (conditions, selector, declarations, target, description) => {
|
|
1691
|
+
if (declarations.length === 0) {
|
|
1692
|
+
return;
|
|
1693
|
+
}
|
|
1694
|
+
let resolved = selector;
|
|
1695
|
+
if (resolved !== null) {
|
|
1696
|
+
const transposed = transposeSelector(resolved);
|
|
1697
|
+
if (transposed === null) {
|
|
1698
|
+
return;
|
|
1699
|
+
}
|
|
1700
|
+
resolved = transposed;
|
|
1701
|
+
}
|
|
1702
|
+
const text = cssRuleText(conditions, resolved, declarations);
|
|
1703
|
+
rules.push({
|
|
1704
|
+
text,
|
|
1705
|
+
conditions: [...conditions],
|
|
1706
|
+
selector: resolved,
|
|
1707
|
+
declarations,
|
|
1708
|
+
target,
|
|
1709
|
+
key: hashCss(text),
|
|
1710
|
+
...typeof description === "string" && description !== "" ? { description } : {}
|
|
1711
|
+
});
|
|
1712
|
+
};
|
|
1713
|
+
const emitKeyframes = (atKey, block, conditions) => {
|
|
1714
|
+
const name = atKey.slice("@keyframes".length).trim();
|
|
1715
|
+
if (name === "") {
|
|
1716
|
+
return;
|
|
1717
|
+
}
|
|
1718
|
+
const blocks = [];
|
|
1719
|
+
for (const [key, value] of Object.entries(block)) {
|
|
1720
|
+
if (!isBlock(value)) {
|
|
1721
|
+
continue;
|
|
1722
|
+
}
|
|
1723
|
+
const declarations = declarationsOf(value, true, false, "unscoped");
|
|
1724
|
+
if (declarations.length > 0) {
|
|
1725
|
+
blocks.push({ declarations, selector: key.trim() });
|
|
1726
|
+
}
|
|
1727
|
+
}
|
|
1728
|
+
if (blocks.length === 0) {
|
|
1729
|
+
return;
|
|
1730
|
+
}
|
|
1731
|
+
const text = cssKeyframesText(conditions, name, blocks);
|
|
1732
|
+
rules.push({
|
|
1733
|
+
blocks,
|
|
1734
|
+
conditions: [...conditions],
|
|
1735
|
+
declarations: [],
|
|
1736
|
+
key: hashCss(text),
|
|
1737
|
+
selector: null,
|
|
1738
|
+
target: "unscoped",
|
|
1739
|
+
text
|
|
1740
|
+
});
|
|
1741
|
+
};
|
|
1742
|
+
const walkAt = (atKey, block, selector, conditions, target) => {
|
|
1743
|
+
if (atKey === "@--") {
|
|
1744
|
+
return;
|
|
1745
|
+
}
|
|
1746
|
+
if (isDeclarationAtRule(atKey)) {
|
|
1747
|
+
emit([...conditions, atKey], null, declarationsOf(block, false, true, "unscoped"), "unscoped", block["$description"]);
|
|
1748
|
+
return;
|
|
1749
|
+
}
|
|
1750
|
+
if (isKeyframesAtRule(atKey)) {
|
|
1751
|
+
emitKeyframes(atKey, block, conditions);
|
|
1752
|
+
return;
|
|
1753
|
+
}
|
|
1754
|
+
const query = resolveAtQuery(atKey, mediaQueries);
|
|
1755
|
+
const atRule = query === null ? atKey : `@media ${query}`;
|
|
1756
|
+
const scheme = query === null ? null : pureSchemeOf(query);
|
|
1757
|
+
if (scheme !== null && selector !== null) {
|
|
1758
|
+
const { auto, forced } = schemeSelectors(selector, scheme);
|
|
1759
|
+
walk(block, auto, [...conditions, atRule], target);
|
|
1760
|
+
walk(withoutKeyframes(block), forced, conditions, target);
|
|
1761
|
+
return;
|
|
1762
|
+
}
|
|
1763
|
+
walk(block, selector, [...conditions, atRule], target);
|
|
1764
|
+
};
|
|
1765
|
+
function walk(node, selector, conditions, target) {
|
|
1766
|
+
emit(conditions, selector, declarationsOf(node, true, true, target), target, node["$description"]);
|
|
1767
|
+
for (const [key, value] of Object.entries(node)) {
|
|
1768
|
+
for (const block of blocksOf(key, value)) {
|
|
1769
|
+
if (key.startsWith("@")) {
|
|
1770
|
+
walkAt(key, block, selector, conditions, target);
|
|
1771
|
+
} else if (selector !== null) {
|
|
1772
|
+
walk(block, resolveNestedSelector(selector, key), conditions, compoundsOntoScope(key) ? target : "descendant");
|
|
1773
|
+
}
|
|
1774
|
+
}
|
|
1775
|
+
}
|
|
1776
|
+
}
|
|
1777
|
+
walk(style, scope, [], "self");
|
|
1778
|
+
return rules;
|
|
1779
|
+
}
|
|
1420
1780
|
|
|
1421
1781
|
// ../schema/src/intl.ts
|
|
1422
1782
|
var DEFAULT_FORMAT_LOCALE = "en-US";
|
|
@@ -1648,8 +2008,8 @@ function withPageLocale(path, args, state) {
|
|
|
1648
2008
|
filled[index] = locale;
|
|
1649
2009
|
return filled;
|
|
1650
2010
|
}
|
|
1651
|
-
function isBlessedGlobal(
|
|
1652
|
-
return
|
|
2011
|
+
function isBlessedGlobal(ref) {
|
|
2012
|
+
return ref.startsWith("window#/") && BLESSED_GLOBALS.has(ref.slice("window#/".length));
|
|
1653
2013
|
}
|
|
1654
2014
|
function isMutating(op) {
|
|
1655
2015
|
return MUTATING_OPS.has(op);
|
|
@@ -1688,24 +2048,43 @@ function resolveOperand(operand, state, event, iterCtx, trace) {
|
|
|
1688
2048
|
trace?.report(trace.path ?? [], operand);
|
|
1689
2049
|
return operand;
|
|
1690
2050
|
}
|
|
1691
|
-
function
|
|
1692
|
-
|
|
2051
|
+
function calleeOwner(ref, state, event, iterCtx) {
|
|
2052
|
+
const parentRef = (prefix) => {
|
|
2053
|
+
const rest = ref.slice(prefix.length);
|
|
2054
|
+
if (!rest.includes("/")) {
|
|
2055
|
+
return state;
|
|
2056
|
+
}
|
|
2057
|
+
return resolveExprRef(ref.slice(0, ref.lastIndexOf("/")), state, event, iterCtx);
|
|
2058
|
+
};
|
|
2059
|
+
if (ref.startsWith("#/state/")) {
|
|
2060
|
+
return parentRef("#/state/");
|
|
2061
|
+
}
|
|
2062
|
+
if (ref.startsWith("parent#/")) {
|
|
2063
|
+
return parentRef("parent#/");
|
|
2064
|
+
}
|
|
2065
|
+
if (ref.startsWith("$map/") || ref.startsWith("$args/")) {
|
|
2066
|
+
return ref.split("/").length > 2 ? resolveExprRef(ref.slice(0, ref.lastIndexOf("/")), state, event, iterCtx) : undefined;
|
|
2067
|
+
}
|
|
2068
|
+
return;
|
|
2069
|
+
}
|
|
2070
|
+
function resolveExprRef(ref, state, event, iterCtx) {
|
|
2071
|
+
if (ref === "$reduce/acc") {
|
|
1693
2072
|
return iterCtx?.acc;
|
|
1694
2073
|
}
|
|
1695
|
-
if (
|
|
2074
|
+
if (ref.startsWith("$reduce/")) {
|
|
1696
2075
|
return iterCtx?.acc;
|
|
1697
2076
|
}
|
|
1698
|
-
if (
|
|
1699
|
-
const parts =
|
|
2077
|
+
if (ref.startsWith("$args/")) {
|
|
2078
|
+
const parts = ref.slice("$args/".length).split("/");
|
|
1700
2079
|
const base = iterCtx?.args?.[parts[0]];
|
|
1701
2080
|
return parts.length > 1 ? getPath(base, parts.slice(1).join("/")) : base;
|
|
1702
2081
|
}
|
|
1703
|
-
if (
|
|
1704
|
-
const path =
|
|
2082
|
+
if (ref.startsWith("event#/")) {
|
|
2083
|
+
const path = ref.slice("event#/".length);
|
|
1705
2084
|
return getPath(event, path);
|
|
1706
2085
|
}
|
|
1707
|
-
if (
|
|
1708
|
-
const parts =
|
|
2086
|
+
if (ref.startsWith("$map/")) {
|
|
2087
|
+
const parts = ref.split("/");
|
|
1709
2088
|
const [, key] = parts;
|
|
1710
2089
|
let base;
|
|
1711
2090
|
const map = scopeMap(state);
|
|
@@ -1718,23 +2097,23 @@ function resolveExprRef(ref2, state, event, iterCtx) {
|
|
|
1718
2097
|
}
|
|
1719
2098
|
return parts.length > 2 ? getPath(base, parts.slice(2).join("/")) : base;
|
|
1720
2099
|
}
|
|
1721
|
-
if (
|
|
1722
|
-
return readPath(state,
|
|
2100
|
+
if (ref.startsWith("#/state/")) {
|
|
2101
|
+
return readPath(state, ref.slice("#/state/".length));
|
|
1723
2102
|
}
|
|
1724
|
-
if (
|
|
1725
|
-
return readPath(state,
|
|
2103
|
+
if (ref.startsWith("parent#/")) {
|
|
2104
|
+
return readPath(state, ref.slice("parent#/".length));
|
|
1726
2105
|
}
|
|
1727
|
-
if (
|
|
1728
|
-
return getPath(globalThis.window,
|
|
2106
|
+
if (ref.startsWith("window#/")) {
|
|
2107
|
+
return getPath(globalThis.window, ref.slice("window#/".length));
|
|
1729
2108
|
}
|
|
1730
|
-
if (
|
|
1731
|
-
return getPath(globalThis.document,
|
|
2109
|
+
if (ref.startsWith("document#/")) {
|
|
2110
|
+
return getPath(globalThis.document, ref.slice("document#/".length));
|
|
1732
2111
|
}
|
|
1733
|
-
return readPath(state,
|
|
2112
|
+
return readPath(state, ref) ?? null;
|
|
1734
2113
|
}
|
|
1735
|
-
function resolveWritableRef(
|
|
1736
|
-
if (
|
|
1737
|
-
const parts =
|
|
2114
|
+
function resolveWritableRef(ref, state, _event, iterCtx) {
|
|
2115
|
+
if (ref.startsWith("$map/")) {
|
|
2116
|
+
const parts = ref.split("/");
|
|
1738
2117
|
const [, key] = parts;
|
|
1739
2118
|
let base;
|
|
1740
2119
|
const map = scopeMap(state);
|
|
@@ -1756,8 +2135,8 @@ function resolveWritableRef(ref2, state, _event, iterCtx) {
|
|
|
1756
2135
|
obj: scopeMap(state) ?? state
|
|
1757
2136
|
};
|
|
1758
2137
|
}
|
|
1759
|
-
if (
|
|
1760
|
-
const sub =
|
|
2138
|
+
if (ref.startsWith("#/state/")) {
|
|
2139
|
+
const sub = ref.slice("#/state/".length);
|
|
1761
2140
|
const slash = sub.indexOf("/");
|
|
1762
2141
|
if (slash === -1) {
|
|
1763
2142
|
return { key: sub, obj: state };
|
|
@@ -1770,7 +2149,7 @@ function resolveWritableRef(ref2, state, _event, iterCtx) {
|
|
|
1770
2149
|
}
|
|
1771
2150
|
return { key: lastKey, obj };
|
|
1772
2151
|
}
|
|
1773
|
-
return { key:
|
|
2152
|
+
return { key: ref, obj: state };
|
|
1774
2153
|
}
|
|
1775
2154
|
function evaluateExpression(node, state, event, iterCtx, trace) {
|
|
1776
2155
|
const result = evaluateNode(node, state, event, iterCtx, trace);
|
|
@@ -1817,19 +2196,19 @@ function evaluateNode(node, state, event, iterCtx, trace) {
|
|
|
1817
2196
|
}
|
|
1818
2197
|
const callee = resolveExprRef(calleeRef, state, event, iterCtx);
|
|
1819
2198
|
if (typeof callee === "function") {
|
|
1820
|
-
return callee(
|
|
2199
|
+
return callee.apply(calleeOwner(calleeRef, state, event, iterCtx), argValues);
|
|
1821
2200
|
}
|
|
1822
2201
|
if (callee && typeof callee === "object" && "$expression" in callee) {
|
|
1823
|
-
const
|
|
2202
|
+
const def = callee;
|
|
1824
2203
|
const args = {};
|
|
1825
|
-
for (const [i, p] of (
|
|
2204
|
+
for (const [i, p] of (def.parameters ?? []).entries()) {
|
|
1826
2205
|
const name = typeof p === "string" ? p : p?.name ?? "";
|
|
1827
2206
|
if (!name) {
|
|
1828
2207
|
continue;
|
|
1829
2208
|
}
|
|
1830
2209
|
args[name] = argValues[i] === undefined && typeof p === "object" && p !== null && "default" in p ? p.default : argValues[i];
|
|
1831
2210
|
}
|
|
1832
|
-
return evaluateExpression(
|
|
2211
|
+
return evaluateExpression(def.$expression, state, event, { args, callDepth });
|
|
1833
2212
|
}
|
|
1834
2213
|
throw new TypeError(`$expression: call target "${calleeRef}" is not callable`);
|
|
1835
2214
|
}
|
|
@@ -2003,69 +2382,6 @@ function evaluateOperand(operand, state, event, iterCtx) {
|
|
|
2003
2382
|
return resolveOperand(operand, state, event, iterCtx);
|
|
2004
2383
|
}
|
|
2005
2384
|
|
|
2006
|
-
// ../schema/src/guards.ts
|
|
2007
|
-
function isJsonObject(value) {
|
|
2008
|
-
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
2009
|
-
}
|
|
2010
|
-
function isRef2(value) {
|
|
2011
|
-
return isJsonObject(value) && typeof value.$ref === "string";
|
|
2012
|
-
}
|
|
2013
|
-
function isFunctionDef(value) {
|
|
2014
|
-
return isJsonObject(value) && value.$prototype === "Function";
|
|
2015
|
-
}
|
|
2016
|
-
function isExpressionDef(value) {
|
|
2017
|
-
return isJsonObject(value) && isJsonObject(value.$expression);
|
|
2018
|
-
}
|
|
2019
|
-
function isNamedFormulaDef(value) {
|
|
2020
|
-
return isExpressionDef(value) && Array.isArray(value.parameters) && value.parameters.length > 0;
|
|
2021
|
-
}
|
|
2022
|
-
function hasStructuredBody(value) {
|
|
2023
|
-
return isFunctionDef(value) && Array.isArray(value.body);
|
|
2024
|
-
}
|
|
2025
|
-
function isPrototypeDef(value) {
|
|
2026
|
-
return isJsonObject(value) && typeof value.$prototype === "string" && value.$prototype !== "Function";
|
|
2027
|
-
}
|
|
2028
|
-
function isServerFnDef(value) {
|
|
2029
|
-
return isJsonObject(value) && value.timing === "server" && typeof value.$src === "string" && typeof value.$export === "string" && !value.$prototype;
|
|
2030
|
-
}
|
|
2031
|
-
var SCHEMA_KEYWORDS = new Set([
|
|
2032
|
-
"type",
|
|
2033
|
-
"enum",
|
|
2034
|
-
"minimum",
|
|
2035
|
-
"maximum",
|
|
2036
|
-
"minLength",
|
|
2037
|
-
"maxLength",
|
|
2038
|
-
"pattern",
|
|
2039
|
-
"format",
|
|
2040
|
-
"items",
|
|
2041
|
-
"properties",
|
|
2042
|
-
"required",
|
|
2043
|
-
"description",
|
|
2044
|
-
"title",
|
|
2045
|
-
"$comment"
|
|
2046
|
-
]);
|
|
2047
|
-
function isMappedArray(value) {
|
|
2048
|
-
return isJsonObject(value) && value.$prototype === "Array";
|
|
2049
|
-
}
|
|
2050
|
-
function isTemplateString(value) {
|
|
2051
|
-
return typeof value === "string" && value.includes("${");
|
|
2052
|
-
}
|
|
2053
|
-
function bodyReturnsValue(body) {
|
|
2054
|
-
return /\breturn\b[^\S\n]*(?![;}\s]|$)/.test(body);
|
|
2055
|
-
}
|
|
2056
|
-
function paramNames(parameters) {
|
|
2057
|
-
if (!parameters) {
|
|
2058
|
-
return [];
|
|
2059
|
-
}
|
|
2060
|
-
return parameters.map((p) => typeof p === "string" ? p : p.name);
|
|
2061
|
-
}
|
|
2062
|
-
function isTagExpression(tagName) {
|
|
2063
|
-
return isJsonObject(tagName) && isJsonObject(tagName.$expression);
|
|
2064
|
-
}
|
|
2065
|
-
function isPrivateStateKey(key) {
|
|
2066
|
-
return key.startsWith("#");
|
|
2067
|
-
}
|
|
2068
|
-
|
|
2069
2385
|
// ../schema/src/asset-paths.ts
|
|
2070
2386
|
var URL_TERMINATOR = String.raw`"'\s<>()\\`;
|
|
2071
2387
|
function parseSrcset(value) {
|
|
@@ -2118,6 +2434,12 @@ function statementKind(statement) {
|
|
|
2118
2434
|
if ("$switch" in statement) {
|
|
2119
2435
|
return "switch";
|
|
2120
2436
|
}
|
|
2437
|
+
if ("stopPropagation" in statement) {
|
|
2438
|
+
return "stopPropagation";
|
|
2439
|
+
}
|
|
2440
|
+
if ("preventDefault" in statement) {
|
|
2441
|
+
return "preventDefault";
|
|
2442
|
+
}
|
|
2121
2443
|
return "dispatch";
|
|
2122
2444
|
}
|
|
2123
2445
|
async function runStatements(statements, state, event, opts = {}) {
|
|
@@ -2151,7 +2473,8 @@ async function runStatements(statements, state, event, opts = {}) {
|
|
|
2151
2473
|
}
|
|
2152
2474
|
case "dispatch": {
|
|
2153
2475
|
const dispatch = statement;
|
|
2154
|
-
const
|
|
2476
|
+
const fallback = typeof opts.target === "function" ? opts.target() : opts.target;
|
|
2477
|
+
const target = event?.currentTarget ?? fallback;
|
|
2155
2478
|
if (!target) {
|
|
2156
2479
|
break;
|
|
2157
2480
|
}
|
|
@@ -2168,6 +2491,14 @@ async function runStatements(statements, state, event, opts = {}) {
|
|
|
2168
2491
|
target.dispatchEvent(new CustomEvent(dispatch.dispatchEvent, init));
|
|
2169
2492
|
break;
|
|
2170
2493
|
}
|
|
2494
|
+
case "stopPropagation": {
|
|
2495
|
+
event?.stopPropagation();
|
|
2496
|
+
break;
|
|
2497
|
+
}
|
|
2498
|
+
case "preventDefault": {
|
|
2499
|
+
event?.preventDefault();
|
|
2500
|
+
break;
|
|
2501
|
+
}
|
|
2171
2502
|
default: {
|
|
2172
2503
|
break;
|
|
2173
2504
|
}
|
|
@@ -2230,28 +2561,99 @@ function checkSchemaVersion($schema) {
|
|
|
2230
2561
|
async function Jx(source, target = document.body, options) {
|
|
2231
2562
|
const base = options?.base ? new URL(options.base, location.href).href : typeof source === "string" ? new URL(source, location.href).href : location.href;
|
|
2232
2563
|
const doc = await resolve(source);
|
|
2564
|
+
if (doc.$media) {
|
|
2565
|
+
_rootMedia = doc.$media;
|
|
2566
|
+
}
|
|
2567
|
+
const mounted = await mount(doc, target, {
|
|
2568
|
+
base,
|
|
2569
|
+
...options?.onNodeCreated ? { onNodeCreated: options.onNodeCreated } : {},
|
|
2570
|
+
...options?.signal ? { signal: options.signal } : {}
|
|
2571
|
+
});
|
|
2572
|
+
return mounted.scope;
|
|
2573
|
+
}
|
|
2574
|
+
var HOST_SCOPE_RESERVED = /^[$#]/;
|
|
2575
|
+
function assertHostScope(scope) {
|
|
2576
|
+
for (const key of Object.keys(scope)) {
|
|
2577
|
+
if (HOST_SCOPE_RESERVED.test(key)) {
|
|
2578
|
+
throw new TypeError(`Jx mount: host scope key "${key}" is reserved — names beginning with "$" or "#" are ` + `runtime vocabulary`);
|
|
2579
|
+
}
|
|
2580
|
+
}
|
|
2581
|
+
}
|
|
2582
|
+
async function mount(doc, target, options = {}) {
|
|
2583
|
+
const hostScope = options.scope ?? {};
|
|
2584
|
+
assertHostScope(hostScope);
|
|
2585
|
+
const base = options.base ? new URL(options.base, location.href).href : location.href;
|
|
2586
|
+
const ctx = {
|
|
2587
|
+
base,
|
|
2588
|
+
media: options.media ?? doc.$media ?? null,
|
|
2589
|
+
root: null,
|
|
2590
|
+
...options.resolver ? { resolver: options.resolver } : {},
|
|
2591
|
+
...options.skipServerFunctions === undefined ? {} : { skipServerFunctions: options.skipServerFunctions },
|
|
2592
|
+
...options.skipAutoRequests === undefined ? {} : { skipAutoRequests: options.skipAutoRequests }
|
|
2593
|
+
};
|
|
2233
2594
|
checkSchemaVersion(doc.$schema);
|
|
2234
2595
|
if (doc.$elements) {
|
|
2235
|
-
await registerElements(doc.$elements, base);
|
|
2596
|
+
await registerElements(doc.$elements, base, ctx);
|
|
2236
2597
|
}
|
|
2237
2598
|
if (doc.$head) {
|
|
2238
2599
|
injectHead(doc.$head, base);
|
|
2239
2600
|
}
|
|
2240
|
-
|
|
2241
|
-
|
|
2242
|
-
|
|
2243
|
-
|
|
2244
|
-
|
|
2245
|
-
|
|
2246
|
-
|
|
2601
|
+
const scope = await buildScope(doc, hostScope, base, ctx);
|
|
2602
|
+
const elements = new Set;
|
|
2603
|
+
const renderOptions = {
|
|
2604
|
+
_ctx: ctx,
|
|
2605
|
+
onNodeCreated: (el, path, def, state) => {
|
|
2606
|
+
if (el instanceof Element && el.tagName.includes("-")) {
|
|
2607
|
+
elements.add(el.tagName.toLowerCase());
|
|
2608
|
+
}
|
|
2609
|
+
options.onNodeCreated?.(el, path, def, state);
|
|
2610
|
+
},
|
|
2611
|
+
...options.onNodeMoved ? { onNodeMoved: options.onNodeMoved } : {}
|
|
2612
|
+
};
|
|
2613
|
+
const { result: root, stop } = runScoped(() => renderNode(doc, scope, renderOptions));
|
|
2614
|
+
ctx.root = root;
|
|
2615
|
+
let mounted = false;
|
|
2616
|
+
let disposed = false;
|
|
2617
|
+
const dispose = () => {
|
|
2618
|
+
if (disposed) {
|
|
2619
|
+
return;
|
|
2620
|
+
}
|
|
2621
|
+
disposed = true;
|
|
2622
|
+
options.signal?.removeEventListener("abort", dispose);
|
|
2623
|
+
stop();
|
|
2624
|
+
if (mounted && typeof scope.onUnmount === "function") {
|
|
2625
|
+
scope.onUnmount(scope);
|
|
2626
|
+
}
|
|
2627
|
+
root.remove();
|
|
2628
|
+
};
|
|
2629
|
+
if (options.signal?.aborted) {
|
|
2630
|
+
dispose();
|
|
2631
|
+
} else {
|
|
2632
|
+
options.signal?.addEventListener("abort", dispose, { once: true });
|
|
2633
|
+
target.append(root);
|
|
2634
|
+
mounted = true;
|
|
2635
|
+
if (typeof scope.onMount === "function") {
|
|
2636
|
+
scope.onMount(scope);
|
|
2637
|
+
}
|
|
2247
2638
|
}
|
|
2248
|
-
return
|
|
2639
|
+
return { scope, root, elements, dispose };
|
|
2249
2640
|
}
|
|
2250
2641
|
var _resolveCache = new Map;
|
|
2251
|
-
|
|
2642
|
+
function preloadDocument(url, doc) {
|
|
2643
|
+
const settled = Promise.resolve(doc);
|
|
2644
|
+
_resolveCache.set(url, settled);
|
|
2645
|
+
try {
|
|
2646
|
+
_resolveCache.set(new URL(url, location.href).href, settled);
|
|
2647
|
+
} catch {}
|
|
2648
|
+
}
|
|
2649
|
+
async function resolve(source, ctx) {
|
|
2252
2650
|
if (typeof source !== "string") {
|
|
2253
2651
|
return source;
|
|
2254
2652
|
}
|
|
2653
|
+
const served = ctx?.resolver?.(source);
|
|
2654
|
+
if (served) {
|
|
2655
|
+
return served;
|
|
2656
|
+
}
|
|
2255
2657
|
if (_resolveCache.has(source)) {
|
|
2256
2658
|
return _resolveCache.get(source);
|
|
2257
2659
|
}
|
|
@@ -2337,10 +2739,36 @@ var _canvasDelinkAnchors = false;
|
|
|
2337
2739
|
function setCanvasDelinkAnchors(on) {
|
|
2338
2740
|
_canvasDelinkAnchors = on;
|
|
2339
2741
|
}
|
|
2742
|
+
var _canvasDelinkPopovers = false;
|
|
2743
|
+
function setCanvasDelinkPopovers(on) {
|
|
2744
|
+
_canvasDelinkPopovers = on;
|
|
2745
|
+
}
|
|
2746
|
+
var _canvasDelinkCommands = false;
|
|
2747
|
+
function setCanvasDelinkCommands(on) {
|
|
2748
|
+
_canvasDelinkCommands = on;
|
|
2749
|
+
}
|
|
2750
|
+
var _canvasInsideStampedHost = false;
|
|
2751
|
+
function canvasStamped(el) {
|
|
2752
|
+
return _canvasInsideStampedHost || el.dataset.jxPath !== undefined;
|
|
2753
|
+
}
|
|
2340
2754
|
function canvasAttrName(el, key) {
|
|
2341
2755
|
if (_canvasDelinkAnchors && key === "href" && (el.tagName === "A" || el.tagName === "AREA")) {
|
|
2342
2756
|
return "data-jx-href";
|
|
2343
2757
|
}
|
|
2758
|
+
if (_canvasDelinkPopovers && key === "popover" && canvasStamped(el)) {
|
|
2759
|
+
return "data-jx-popover";
|
|
2760
|
+
}
|
|
2761
|
+
if (_canvasDelinkCommands && canvasStamped(el)) {
|
|
2762
|
+
if (key === "commandfor") {
|
|
2763
|
+
return "data-jx-commandfor";
|
|
2764
|
+
}
|
|
2765
|
+
if (key === "inert") {
|
|
2766
|
+
return "data-jx-inert";
|
|
2767
|
+
}
|
|
2768
|
+
if (key === "open" && el.tagName === "DIALOG") {
|
|
2769
|
+
return "data-jx-open";
|
|
2770
|
+
}
|
|
2771
|
+
}
|
|
2344
2772
|
return key;
|
|
2345
2773
|
}
|
|
2346
2774
|
var _canvasAssetResolver = null;
|
|
@@ -2420,71 +2848,84 @@ function boundPropKey(key, val, state) {
|
|
|
2420
2848
|
}
|
|
2421
2849
|
return sub;
|
|
2422
2850
|
}
|
|
2423
|
-
async function buildScope(doc, parentScope = {}, base = location.href) {
|
|
2851
|
+
async function buildScope(doc, parentScope = {}, base = location.href, ctx) {
|
|
2852
|
+
const dispatchRoot = () => ctx?.root ?? null;
|
|
2424
2853
|
const raw = {};
|
|
2425
|
-
for (const [key, val] of Object.entries(parentScope)) {
|
|
2426
|
-
raw[key] = val;
|
|
2427
|
-
}
|
|
2428
2854
|
const defs = doc.state ?? {};
|
|
2855
|
+
const linked = isReactive(parentScope);
|
|
2856
|
+
for (const key of Object.keys(parentScope)) {
|
|
2857
|
+
if (linked && !(key in defs)) {
|
|
2858
|
+
Object.defineProperty(raw, key, {
|
|
2859
|
+
configurable: true,
|
|
2860
|
+
enumerable: true,
|
|
2861
|
+
get: () => parentScope[key],
|
|
2862
|
+
set: (value) => {
|
|
2863
|
+
parentScope[key] = value;
|
|
2864
|
+
}
|
|
2865
|
+
});
|
|
2866
|
+
} else {
|
|
2867
|
+
raw[key] = parentScope[key];
|
|
2868
|
+
}
|
|
2869
|
+
}
|
|
2429
2870
|
const imports = doc.imports ?? {};
|
|
2430
|
-
for (const [,
|
|
2431
|
-
if (isPrototypeDef(
|
|
2432
|
-
const mapped = imports[
|
|
2871
|
+
for (const [, def] of Object.entries(defs)) {
|
|
2872
|
+
if (isPrototypeDef(def) && !def.$src) {
|
|
2873
|
+
const mapped = imports[def.$prototype];
|
|
2433
2874
|
if (mapped) {
|
|
2434
2875
|
if (!mapped.endsWith(".class.json")) {
|
|
2435
|
-
console.warn(`Jx: import "${
|
|
2876
|
+
console.warn(`Jx: import "${def.$prototype}" must map to a .class.json path, got "${mapped}"`);
|
|
2436
2877
|
continue;
|
|
2437
2878
|
}
|
|
2438
|
-
|
|
2879
|
+
def.$src = mapped;
|
|
2439
2880
|
}
|
|
2440
2881
|
}
|
|
2441
2882
|
}
|
|
2442
|
-
for (const [key,
|
|
2443
|
-
if (typeof
|
|
2444
|
-
if (!
|
|
2445
|
-
raw[key] =
|
|
2883
|
+
for (const [key, def] of Object.entries(defs)) {
|
|
2884
|
+
if (typeof def === "string") {
|
|
2885
|
+
if (!def.includes("${")) {
|
|
2886
|
+
raw[key] = def;
|
|
2446
2887
|
}
|
|
2447
2888
|
continue;
|
|
2448
2889
|
}
|
|
2449
|
-
if (typeof
|
|
2450
|
-
raw[key] =
|
|
2890
|
+
if (typeof def === "number" || typeof def === "boolean" || def === null) {
|
|
2891
|
+
raw[key] = def;
|
|
2451
2892
|
continue;
|
|
2452
2893
|
}
|
|
2453
|
-
if (Array.isArray(
|
|
2454
|
-
raw[key] =
|
|
2894
|
+
if (Array.isArray(def)) {
|
|
2895
|
+
raw[key] = def;
|
|
2455
2896
|
continue;
|
|
2456
2897
|
}
|
|
2457
|
-
if (typeof
|
|
2458
|
-
if (
|
|
2898
|
+
if (typeof def === "object") {
|
|
2899
|
+
if (def.$prototype) {
|
|
2459
2900
|
continue;
|
|
2460
2901
|
}
|
|
2461
|
-
if (isExpressionDef(
|
|
2902
|
+
if (isExpressionDef(def)) {
|
|
2462
2903
|
continue;
|
|
2463
2904
|
}
|
|
2464
|
-
if (isServerFnDef(
|
|
2905
|
+
if (isServerFnDef(def)) {
|
|
2465
2906
|
continue;
|
|
2466
2907
|
}
|
|
2467
|
-
if ("default" in
|
|
2468
|
-
raw[key] =
|
|
2908
|
+
if ("default" in def) {
|
|
2909
|
+
raw[key] = def.default;
|
|
2469
2910
|
continue;
|
|
2470
2911
|
}
|
|
2471
|
-
if (hasSchemaKeywords(
|
|
2912
|
+
if (hasSchemaKeywords(def)) {
|
|
2472
2913
|
continue;
|
|
2473
2914
|
}
|
|
2474
|
-
raw[key] =
|
|
2915
|
+
raw[key] = def;
|
|
2475
2916
|
}
|
|
2476
2917
|
}
|
|
2477
2918
|
const state = reactive(raw);
|
|
2478
|
-
for (const [key,
|
|
2479
|
-
if (typeof
|
|
2480
|
-
state[key] = computed(() => evaluateTemplate(
|
|
2919
|
+
for (const [key, def] of Object.entries(defs)) {
|
|
2920
|
+
if (typeof def === "string" && def.includes("${")) {
|
|
2921
|
+
state[key] = computed(() => evaluateTemplate(def, state));
|
|
2481
2922
|
}
|
|
2482
2923
|
}
|
|
2483
|
-
for (const [key,
|
|
2484
|
-
if (isExpressionDef(
|
|
2485
|
-
const node =
|
|
2486
|
-
if (isNamedFormulaDef(
|
|
2487
|
-
const params =
|
|
2924
|
+
for (const [key, def] of Object.entries(defs)) {
|
|
2925
|
+
if (isExpressionDef(def)) {
|
|
2926
|
+
const node = def.$expression;
|
|
2927
|
+
if (isNamedFormulaDef(def)) {
|
|
2928
|
+
const params = def.parameters;
|
|
2488
2929
|
state[key] = (...argValues) => {
|
|
2489
2930
|
const args = {};
|
|
2490
2931
|
for (const [i, p] of params.entries()) {
|
|
@@ -2504,11 +2945,11 @@ async function buildScope(doc, parentScope = {}, base = location.href) {
|
|
|
2504
2945
|
}
|
|
2505
2946
|
}
|
|
2506
2947
|
}
|
|
2507
|
-
for (const [key,
|
|
2508
|
-
if (hasStructuredBody(
|
|
2509
|
-
const { body } =
|
|
2510
|
-
if (Array.isArray(
|
|
2511
|
-
const params =
|
|
2948
|
+
for (const [key, def] of Object.entries(defs)) {
|
|
2949
|
+
if (hasStructuredBody(def)) {
|
|
2950
|
+
const { body } = def;
|
|
2951
|
+
if (Array.isArray(def.parameters) && def.parameters.length > 0) {
|
|
2952
|
+
const params = def.parameters;
|
|
2512
2953
|
state[key] = (...argValues) => {
|
|
2513
2954
|
const args = {};
|
|
2514
2955
|
for (const [i, p] of params.entries()) {
|
|
@@ -2518,34 +2959,35 @@ async function buildScope(doc, parentScope = {}, base = location.href) {
|
|
|
2518
2959
|
}
|
|
2519
2960
|
args[name] = argValues[i] === undefined && typeof p === "object" && p !== null && "default" in p ? p.default : argValues[i];
|
|
2520
2961
|
}
|
|
2521
|
-
return runStatements(body, state, null, { args });
|
|
2962
|
+
return runStatements(body, state, null, { args, target: dispatchRoot });
|
|
2522
2963
|
};
|
|
2523
2964
|
} else {
|
|
2524
2965
|
const handler = (s, event) => {
|
|
2525
|
-
runStatements(body, s, event ?? null);
|
|
2966
|
+
runStatements(body, s, event ?? null, { target: dispatchRoot });
|
|
2526
2967
|
};
|
|
2527
2968
|
state[key] = handler;
|
|
2528
2969
|
}
|
|
2529
|
-
} else if (isFunctionDef(
|
|
2530
|
-
state[key] = await resolveFunction(
|
|
2970
|
+
} else if (isFunctionDef(def)) {
|
|
2971
|
+
state[key] = await resolveFunction(def, state, key, base);
|
|
2531
2972
|
}
|
|
2532
2973
|
}
|
|
2533
|
-
for (const [key,
|
|
2534
|
-
if (isPrototypeDef(
|
|
2535
|
-
state[key] = await resolvePrototype(
|
|
2974
|
+
for (const [key, def] of Object.entries(defs)) {
|
|
2975
|
+
if (isPrototypeDef(def)) {
|
|
2976
|
+
state[key] = await resolvePrototype(def, state, key, base, ctx);
|
|
2536
2977
|
}
|
|
2537
2978
|
}
|
|
2538
|
-
if (!_serverFnConfig.skip) {
|
|
2539
|
-
for (const [key,
|
|
2540
|
-
if (isServerFnDef(
|
|
2541
|
-
state[key] = await resolveServerFunction(
|
|
2979
|
+
if (!(ctx?.skipServerFunctions ?? _serverFnConfig.skip)) {
|
|
2980
|
+
for (const [key, def] of Object.entries(defs)) {
|
|
2981
|
+
if (isServerFnDef(def)) {
|
|
2982
|
+
state[key] = await resolveServerFunction(def, state, key, base);
|
|
2542
2983
|
}
|
|
2543
2984
|
}
|
|
2544
2985
|
}
|
|
2986
|
+
const rootMedia = ctx?.media ?? _rootMedia;
|
|
2545
2987
|
if (doc.$media) {
|
|
2546
2988
|
state["$media"] = doc.$media;
|
|
2547
|
-
} else if (!state["$media"] && Object.keys(
|
|
2548
|
-
state["$media"] =
|
|
2989
|
+
} else if (!state["$media"] && Object.keys(rootMedia).length > 0) {
|
|
2990
|
+
state["$media"] = rootMedia;
|
|
2549
2991
|
}
|
|
2550
2992
|
return state;
|
|
2551
2993
|
}
|
|
@@ -2589,36 +3031,72 @@ function evaluateAttrTemplate(str, state) {
|
|
|
2589
3031
|
return fn(state, $map, $map?.item, $map?.index);
|
|
2590
3032
|
}
|
|
2591
3033
|
var _moduleCache = new Map;
|
|
2592
|
-
|
|
2593
|
-
|
|
2594
|
-
|
|
3034
|
+
var _moduleLoaders = new Map;
|
|
3035
|
+
function preloadModule(specifier, mod) {
|
|
3036
|
+
if (typeof mod === "function") {
|
|
3037
|
+
_moduleCache.delete(specifier);
|
|
3038
|
+
_moduleLoaders.set(specifier, mod);
|
|
3039
|
+
return;
|
|
2595
3040
|
}
|
|
2596
|
-
|
|
2597
|
-
|
|
2598
|
-
|
|
2599
|
-
|
|
2600
|
-
|
|
2601
|
-
|
|
2602
|
-
|
|
2603
|
-
|
|
3041
|
+
_moduleLoaders.delete(specifier);
|
|
3042
|
+
_moduleCache.set(specifier, mod);
|
|
3043
|
+
}
|
|
3044
|
+
function seededModule(src) {
|
|
3045
|
+
const cached = _moduleCache.get(src);
|
|
3046
|
+
if (cached) {
|
|
3047
|
+
return cached;
|
|
3048
|
+
}
|
|
3049
|
+
const pending = _moduleLoaders.get(src);
|
|
3050
|
+
if (!pending) {
|
|
3051
|
+
return;
|
|
3052
|
+
}
|
|
3053
|
+
if (typeof pending !== "function") {
|
|
3054
|
+
return pending;
|
|
3055
|
+
}
|
|
3056
|
+
const load = Promise.resolve(pending()).then((mod) => {
|
|
3057
|
+
_moduleCache.set(src, mod);
|
|
3058
|
+
_moduleLoaders.delete(src);
|
|
3059
|
+
return mod;
|
|
3060
|
+
}, (error) => {
|
|
3061
|
+
_moduleLoaders.set(src, pending);
|
|
3062
|
+
throw error;
|
|
3063
|
+
});
|
|
3064
|
+
_moduleLoaders.set(src, load);
|
|
3065
|
+
return load;
|
|
3066
|
+
}
|
|
3067
|
+
async function resolveFunction(def, state, key, base) {
|
|
3068
|
+
if (def.body && def.$src) {
|
|
3069
|
+
throw new Error(`Jx: '${key}' declares both body and $src — these are mutually exclusive`);
|
|
3070
|
+
}
|
|
3071
|
+
if (!def.body && !def.$src) {
|
|
3072
|
+
const params = resolveParamNames(def);
|
|
3073
|
+
const noop = new Function(...params, "");
|
|
3074
|
+
Object.defineProperty(noop, "name", {
|
|
3075
|
+
configurable: true,
|
|
3076
|
+
value: def.name ?? key
|
|
3077
|
+
});
|
|
3078
|
+
return noop;
|
|
2604
3079
|
}
|
|
2605
3080
|
let fn;
|
|
2606
|
-
if (typeof
|
|
2607
|
-
const params = resolveParamNames(
|
|
2608
|
-
fn = new Function(...params,
|
|
3081
|
+
if (typeof def.body === "string") {
|
|
3082
|
+
const params = resolveParamNames(def);
|
|
3083
|
+
fn = new Function(...params, def.body);
|
|
2609
3084
|
Object.defineProperty(fn, "name", {
|
|
2610
3085
|
configurable: true,
|
|
2611
|
-
value:
|
|
3086
|
+
value: def.name ?? key
|
|
2612
3087
|
});
|
|
2613
3088
|
} else {
|
|
2614
|
-
const src =
|
|
3089
|
+
const src = def.$src;
|
|
2615
3090
|
if (!src) {
|
|
2616
3091
|
throw new Error(`Jx: '${key}' has neither body nor $src`);
|
|
2617
3092
|
}
|
|
2618
|
-
const exportName =
|
|
3093
|
+
const exportName = def.$export ?? key;
|
|
2619
3094
|
let mod;
|
|
2620
|
-
|
|
2621
|
-
|
|
3095
|
+
const seeded = seededModule(src);
|
|
3096
|
+
if (seeded instanceof Promise) {
|
|
3097
|
+
mod = await seeded;
|
|
3098
|
+
} else if (seeded) {
|
|
3099
|
+
mod = seeded;
|
|
2622
3100
|
} else {
|
|
2623
3101
|
if (base) {
|
|
2624
3102
|
const resolvedSrc = new URL(src, base).href;
|
|
@@ -2638,11 +3116,11 @@ async function resolveFunction(def2, state, key, base) {
|
|
|
2638
3116
|
}
|
|
2639
3117
|
fn = candidate;
|
|
2640
3118
|
}
|
|
2641
|
-
const hasParams = (
|
|
3119
|
+
const hasParams = (def.parameters ?? def.arguments ?? []).length > 0;
|
|
2642
3120
|
let isComputed = false;
|
|
2643
3121
|
if (!hasParams) {
|
|
2644
|
-
if (typeof
|
|
2645
|
-
isComputed = bodyReturnsValue(
|
|
3122
|
+
if (typeof def.body === "string") {
|
|
3123
|
+
isComputed = bodyReturnsValue(def.body);
|
|
2646
3124
|
} else if (fn) {
|
|
2647
3125
|
isComputed = fn.length <= 1 && bodyReturnsValue(fn.toString());
|
|
2648
3126
|
}
|
|
@@ -2652,8 +3130,8 @@ async function resolveFunction(def2, state, key, base) {
|
|
|
2652
3130
|
}
|
|
2653
3131
|
return fn;
|
|
2654
3132
|
}
|
|
2655
|
-
function resolveParamNames(
|
|
2656
|
-
const names =
|
|
3133
|
+
function resolveParamNames(def) {
|
|
3134
|
+
const names = def.parameters ? paramNames(def.parameters) : def.arguments ?? [];
|
|
2657
3135
|
return names.length > 0 && names[0] === "state" ? names : ["state", ...names];
|
|
2658
3136
|
}
|
|
2659
3137
|
var RESERVED_KEYS = new Set([
|
|
@@ -2702,19 +3180,19 @@ function elementNamespace(tagName, inherited) {
|
|
|
2702
3180
|
}
|
|
2703
3181
|
return inherited ?? null;
|
|
2704
3182
|
}
|
|
2705
|
-
function renderNode(
|
|
3183
|
+
function renderNode(def, state, options) {
|
|
2706
3184
|
const path = options?._path ?? [];
|
|
2707
|
-
if (typeof
|
|
2708
|
-
const textNode = document.createTextNode(String(
|
|
2709
|
-
if (typeof
|
|
3185
|
+
if (typeof def === "string" || typeof def === "number" || typeof def === "boolean") {
|
|
3186
|
+
const textNode = document.createTextNode(String(def));
|
|
3187
|
+
if (typeof def === "string" && isTemplateString(def)) {
|
|
2710
3188
|
effect(() => {
|
|
2711
|
-
textNode.textContent = evaluateTemplate(
|
|
3189
|
+
textNode.textContent = evaluateTemplate(def, state);
|
|
2712
3190
|
});
|
|
2713
3191
|
}
|
|
2714
3192
|
return textNode;
|
|
2715
3193
|
}
|
|
2716
3194
|
let localState = state;
|
|
2717
|
-
for (const [key, val] of Object.entries(
|
|
3195
|
+
for (const [key, val] of Object.entries(def)) {
|
|
2718
3196
|
if (key.startsWith("$") && !RESERVED_KEYS.has(key)) {
|
|
2719
3197
|
if (localState === state) {
|
|
2720
3198
|
localState = Object.create(state);
|
|
@@ -2722,38 +3200,41 @@ function renderNode(def2, state, options) {
|
|
|
2722
3200
|
localState[key] = isRefObj(val) ? resolveRef(val.$ref, state) : val;
|
|
2723
3201
|
}
|
|
2724
3202
|
}
|
|
2725
|
-
if ("$ref" in
|
|
2726
|
-
const refTarget = String(
|
|
3203
|
+
if ("$ref" in def && !def.tagName) {
|
|
3204
|
+
const refTarget = String(def.$ref ?? "");
|
|
2727
3205
|
if (!warnedRefChildren.has(refTarget)) {
|
|
2728
3206
|
warnedRefChildren.add(refTarget);
|
|
2729
3207
|
console.warn(`Jx: a $ref child ("${refTarget}") is not a supported component instance; register the ` + `component in $elements and use its custom-element tag instead (spec §13).`);
|
|
2730
3208
|
}
|
|
2731
3209
|
}
|
|
2732
|
-
const tagName = resolveTagName(
|
|
3210
|
+
const tagName = resolveTagName(def.tagName, localState);
|
|
2733
3211
|
const isCustomEl = tagName.includes("-") && customElements.get(tagName);
|
|
2734
|
-
if (
|
|
2735
|
-
return renderCustomElementWithProps(
|
|
3212
|
+
if (def.$props && isCustomEl) {
|
|
3213
|
+
return renderCustomElementWithProps(def, localState, options, path);
|
|
2736
3214
|
}
|
|
2737
|
-
if (
|
|
3215
|
+
if (def.$props) {
|
|
2738
3216
|
if (tagName.includes("-")) {
|
|
2739
|
-
return renderCustomElementWithProps(
|
|
3217
|
+
return renderCustomElementWithProps(def, localState, options, path);
|
|
2740
3218
|
}
|
|
2741
|
-
const { $props: _$props, ...rest } =
|
|
2742
|
-
return renderNode(rest, mergeProps(
|
|
3219
|
+
const { $props: _$props, ...rest } = def;
|
|
3220
|
+
return renderNode(rest, mergeProps(def, localState), options);
|
|
2743
3221
|
}
|
|
2744
|
-
if (
|
|
2745
|
-
return renderSwitch(
|
|
3222
|
+
if (def.$switch) {
|
|
3223
|
+
return renderSwitch(def, localState, options);
|
|
2746
3224
|
}
|
|
2747
3225
|
const ns = elementNamespace(tagName, options?._ns);
|
|
2748
3226
|
const childNs = tagName === "foreignObject" ? null : ns;
|
|
2749
3227
|
const el = ns ? document.createElementNS(ns, tagName) : document.createElement(tagName);
|
|
2750
3228
|
if (options?.onNodeCreated) {
|
|
2751
|
-
options.onNodeCreated(el, path,
|
|
3229
|
+
options.onNodeCreated(el, path, def, localState);
|
|
3230
|
+
}
|
|
3231
|
+
applyProperties(el, def, localState);
|
|
3232
|
+
if (def.style && tagName.includes("-")) {
|
|
3233
|
+
callSiteStyles.set(el, def.style);
|
|
2752
3234
|
}
|
|
2753
|
-
|
|
2754
|
-
|
|
2755
|
-
|
|
2756
|
-
const kids = def2.children;
|
|
3235
|
+
applyStyle(el, def.style ?? {}, localState["$media"] ?? {}, localState);
|
|
3236
|
+
applyAttributes(el, def.attributes ?? {}, localState);
|
|
3237
|
+
const kids = def.children;
|
|
2757
3238
|
if (isMappedArray(kids)) {
|
|
2758
3239
|
const arrOpts = options || childNs ? { ...options, _ns: childNs, _path: [...path, "children"] } : undefined;
|
|
2759
3240
|
renderMappedArrayInto(el, kids, localState, arrOpts);
|
|
@@ -2770,49 +3251,58 @@ function renderNode(def2, state, options) {
|
|
|
2770
3251
|
}
|
|
2771
3252
|
return el;
|
|
2772
3253
|
}
|
|
2773
|
-
function applyProperties(el,
|
|
2774
|
-
for (const [key, val] of Object.entries(
|
|
3254
|
+
function applyProperties(el, def, state) {
|
|
3255
|
+
for (const [key, val] of Object.entries(def)) {
|
|
2775
3256
|
if (RESERVED_KEYS.has(key)) {
|
|
2776
3257
|
continue;
|
|
2777
3258
|
}
|
|
2778
3259
|
if (key.startsWith("$")) {
|
|
2779
3260
|
continue;
|
|
2780
3261
|
}
|
|
2781
|
-
if (key.startsWith("on")) {
|
|
2782
|
-
|
|
2783
|
-
const handler = resolveRef(val.$ref, state);
|
|
2784
|
-
if (typeof handler === "function") {
|
|
2785
|
-
const scope = state;
|
|
2786
|
-
const handlerFn = handler;
|
|
2787
|
-
el.addEventListener(key.slice(2), (e) => handlerFn(scope, e));
|
|
2788
|
-
}
|
|
2789
|
-
continue;
|
|
2790
|
-
}
|
|
2791
|
-
if (hasStructuredBody(val)) {
|
|
2792
|
-
const { body } = val;
|
|
2793
|
-
const scope = state;
|
|
2794
|
-
el.addEventListener(key.slice(2), (e) => {
|
|
2795
|
-
runStatements(body, scope, e);
|
|
2796
|
-
});
|
|
2797
|
-
continue;
|
|
2798
|
-
}
|
|
2799
|
-
if (isFunctionDef(val) && typeof val.body === "string") {
|
|
2800
|
-
const params = resolveParamNames(val);
|
|
2801
|
-
const fn = new Function(...params, val.body);
|
|
2802
|
-
const scope = state;
|
|
2803
|
-
el.addEventListener(key.slice(2), (e) => fn(scope, e));
|
|
2804
|
-
continue;
|
|
2805
|
-
}
|
|
2806
|
-
if (isExpressionDef(val)) {
|
|
2807
|
-
const node = val.$expression;
|
|
2808
|
-
const scope = state;
|
|
2809
|
-
el.addEventListener(key.slice(2), (e) => evaluateExpression(node, scope, e));
|
|
2810
|
-
continue;
|
|
2811
|
-
}
|
|
3262
|
+
if (key.startsWith("on") && bindHandler(el, key, val, state)) {
|
|
3263
|
+
continue;
|
|
2812
3264
|
}
|
|
2813
3265
|
bindProperty(el, key, val, state);
|
|
2814
3266
|
}
|
|
2815
3267
|
}
|
|
3268
|
+
function bindHandler(el, key, val, state) {
|
|
3269
|
+
const type = key.slice(2);
|
|
3270
|
+
const scope = state;
|
|
3271
|
+
if (isRefObj(val)) {
|
|
3272
|
+
const handler = resolveRef(val.$ref, state);
|
|
3273
|
+
if (typeof handler === "function") {
|
|
3274
|
+
const handlerFn = handler;
|
|
3275
|
+
el.addEventListener(type, (e) => handlerFn(scope, e));
|
|
3276
|
+
}
|
|
3277
|
+
return true;
|
|
3278
|
+
}
|
|
3279
|
+
if (hasStructuredBody(val)) {
|
|
3280
|
+
const { body } = val;
|
|
3281
|
+
el.addEventListener(type, (e) => {
|
|
3282
|
+
runStatements(body, scope, e);
|
|
3283
|
+
});
|
|
3284
|
+
return true;
|
|
3285
|
+
}
|
|
3286
|
+
if (isFunctionDef(val) && typeof val.body === "string") {
|
|
3287
|
+
const params = resolveParamNames(val);
|
|
3288
|
+
const fn = new Function(...params, val.body);
|
|
3289
|
+
el.addEventListener(type, (e) => fn(scope, e));
|
|
3290
|
+
return true;
|
|
3291
|
+
}
|
|
3292
|
+
if (isExpressionDef(val)) {
|
|
3293
|
+
const node = val.$expression;
|
|
3294
|
+
el.addEventListener(type, (e) => evaluateExpression(node, scope, e));
|
|
3295
|
+
return true;
|
|
3296
|
+
}
|
|
3297
|
+
return false;
|
|
3298
|
+
}
|
|
3299
|
+
function bindDefinitionHandlers(host, def, state) {
|
|
3300
|
+
for (const [key, val] of Object.entries(def)) {
|
|
3301
|
+
if (key.startsWith("on") && !RESERVED_KEYS.has(key)) {
|
|
3302
|
+
bindHandler(host, key, val, state);
|
|
3303
|
+
}
|
|
3304
|
+
}
|
|
3305
|
+
}
|
|
2816
3306
|
function bindProperty(el, key, val, state) {
|
|
2817
3307
|
const target = el;
|
|
2818
3308
|
const boundProp = boundPropKey(key, val, state);
|
|
@@ -2826,6 +3316,9 @@ function bindProperty(el, key, val, state) {
|
|
|
2826
3316
|
node.setAttribute("class", resolved == null ? "" : String(resolved));
|
|
2827
3317
|
return;
|
|
2828
3318
|
}
|
|
3319
|
+
if (target[key] === resolved) {
|
|
3320
|
+
return;
|
|
3321
|
+
}
|
|
2829
3322
|
target[key] = resolved;
|
|
2830
3323
|
};
|
|
2831
3324
|
if (isRefObj(val)) {
|
|
@@ -2847,144 +3340,300 @@ function bindProperty(el, key, val, state) {
|
|
|
2847
3340
|
}
|
|
2848
3341
|
write(asAsset(val));
|
|
2849
3342
|
}
|
|
2850
|
-
function
|
|
2851
|
-
const
|
|
2852
|
-
|
|
2853
|
-
|
|
2854
|
-
|
|
2855
|
-
|
|
2856
|
-
|
|
2857
|
-
|
|
2858
|
-
|
|
2859
|
-
|
|
3343
|
+
function cssomSink(sheet, detach) {
|
|
3344
|
+
const entries = [];
|
|
3345
|
+
return {
|
|
3346
|
+
detach,
|
|
3347
|
+
insert(texts) {
|
|
3348
|
+
const rules = [];
|
|
3349
|
+
for (const text of texts) {
|
|
3350
|
+
const index = sheet.cssRules.length;
|
|
3351
|
+
try {
|
|
3352
|
+
sheet.insertRule(text, index);
|
|
3353
|
+
} catch {
|
|
3354
|
+
continue;
|
|
3355
|
+
}
|
|
3356
|
+
const rule = sheet.cssRules[index];
|
|
3357
|
+
if (rule) {
|
|
3358
|
+
rules.push(rule);
|
|
2860
3359
|
}
|
|
2861
3360
|
}
|
|
2862
|
-
|
|
2863
|
-
|
|
2864
|
-
|
|
2865
|
-
|
|
2866
|
-
|
|
2867
|
-
|
|
2868
|
-
|
|
2869
|
-
|
|
3361
|
+
const inserted = { rules, texts };
|
|
3362
|
+
entries.push(inserted);
|
|
3363
|
+
return inserted;
|
|
3364
|
+
},
|
|
3365
|
+
remove(inserted) {
|
|
3366
|
+
const at = entries.indexOf(inserted);
|
|
3367
|
+
if (at !== -1) {
|
|
3368
|
+
entries.splice(at, 1);
|
|
2870
3369
|
}
|
|
2871
|
-
|
|
2872
|
-
|
|
2873
|
-
|
|
2874
|
-
|
|
2875
|
-
|
|
2876
|
-
|
|
2877
|
-
|
|
3370
|
+
if (inserted.rules.length === 0) {
|
|
3371
|
+
return;
|
|
3372
|
+
}
|
|
3373
|
+
const list = [...sheet.cssRules];
|
|
3374
|
+
const indices = inserted.rules.map((rule) => list.indexOf(rule)).filter((index) => index >= 0).toSorted((a, b) => b - a);
|
|
3375
|
+
for (const index of indices) {
|
|
3376
|
+
sheet.deleteRule(index);
|
|
3377
|
+
}
|
|
3378
|
+
inserted.rules.length = 0;
|
|
3379
|
+
},
|
|
3380
|
+
replaceAll(texts) {
|
|
3381
|
+
entries.length = 0;
|
|
3382
|
+
entries.push({ rules: [], texts });
|
|
3383
|
+
sheet.replaceSync(texts.join(`
|
|
3384
|
+
`));
|
|
3385
|
+
},
|
|
3386
|
+
text() {
|
|
3387
|
+
return entries.flatMap((entry) => entry.texts.join(`
|
|
3388
|
+
`)).join(`
|
|
3389
|
+
`);
|
|
2878
3390
|
}
|
|
2879
|
-
|
|
2880
|
-
|
|
2881
|
-
|
|
2882
|
-
|
|
2883
|
-
|
|
2884
|
-
|
|
2885
|
-
|
|
2886
|
-
|
|
3391
|
+
};
|
|
3392
|
+
}
|
|
3393
|
+
function textSink(tag) {
|
|
3394
|
+
const entries = [];
|
|
3395
|
+
const write = () => {
|
|
3396
|
+
tag.textContent = entries.map((entry) => entry.texts.join(`
|
|
3397
|
+
`)).join(`
|
|
3398
|
+
`);
|
|
3399
|
+
};
|
|
3400
|
+
return {
|
|
3401
|
+
detach() {
|
|
3402
|
+
tag.remove();
|
|
3403
|
+
},
|
|
3404
|
+
insert(texts) {
|
|
3405
|
+
const inserted = { rules: [], texts };
|
|
3406
|
+
entries.push(inserted);
|
|
3407
|
+
write();
|
|
3408
|
+
return inserted;
|
|
3409
|
+
},
|
|
3410
|
+
remove(inserted) {
|
|
3411
|
+
const index = entries.indexOf(inserted);
|
|
3412
|
+
if (index !== -1) {
|
|
3413
|
+
entries.splice(index, 1);
|
|
3414
|
+
write();
|
|
2887
3415
|
}
|
|
2888
|
-
}
|
|
2889
|
-
|
|
2890
|
-
|
|
2891
|
-
});
|
|
2892
|
-
|
|
2893
|
-
|
|
2894
|
-
|
|
2895
|
-
|
|
3416
|
+
},
|
|
3417
|
+
replaceAll(texts) {
|
|
3418
|
+
entries.length = 0;
|
|
3419
|
+
entries.push({ rules: [], texts });
|
|
3420
|
+
write();
|
|
3421
|
+
},
|
|
3422
|
+
text() {
|
|
3423
|
+
return tag.textContent ?? "";
|
|
2896
3424
|
}
|
|
3425
|
+
};
|
|
3426
|
+
}
|
|
3427
|
+
function openSink(doc) {
|
|
3428
|
+
const view = doc.defaultView;
|
|
3429
|
+
const SheetConstructor = view?.CSSStyleSheet;
|
|
3430
|
+
if (typeof SheetConstructor === "function" && Array.isArray(doc.adoptedStyleSheets)) {
|
|
3431
|
+
try {
|
|
3432
|
+
const sheet = new SheetConstructor;
|
|
3433
|
+
doc.adoptedStyleSheets = [...doc.adoptedStyleSheets, sheet];
|
|
3434
|
+
return cssomSink(sheet, () => {
|
|
3435
|
+
doc.adoptedStyleSheets = doc.adoptedStyleSheets.filter((s) => s !== sheet);
|
|
3436
|
+
});
|
|
3437
|
+
} catch {}
|
|
3438
|
+
}
|
|
3439
|
+
const tag = doc.createElement("style");
|
|
3440
|
+
tag.dataset.jxSheet = "";
|
|
3441
|
+
(doc.head ?? doc.documentElement).append(tag);
|
|
3442
|
+
return tag.sheet ? cssomSink(tag.sheet, () => tag.remove()) : textSink(tag);
|
|
3443
|
+
}
|
|
3444
|
+
var sheetStates = new WeakMap;
|
|
3445
|
+
function sheetStateFor(doc) {
|
|
3446
|
+
const existing = sheetStates.get(doc);
|
|
3447
|
+
if (existing) {
|
|
3448
|
+
return existing;
|
|
3449
|
+
}
|
|
3450
|
+
const created = {
|
|
3451
|
+
hoisted: new Map,
|
|
3452
|
+
interned: new Map,
|
|
3453
|
+
scratch: null,
|
|
3454
|
+
scratchOwners: new Map,
|
|
3455
|
+
serial: 0,
|
|
3456
|
+
shared: openSink(doc)
|
|
3457
|
+
};
|
|
3458
|
+
sheetStates.set(doc, created);
|
|
3459
|
+
return created;
|
|
3460
|
+
}
|
|
3461
|
+
var elementStyles = new WeakMap;
|
|
3462
|
+
var SCOPE_TOKEN = "\x01jx-scope\x01";
|
|
3463
|
+
function rewriteScratch(state) {
|
|
3464
|
+
if (!state.scratch) {
|
|
3465
|
+
return;
|
|
2897
3466
|
}
|
|
2898
|
-
|
|
2899
|
-
|
|
2900
|
-
|
|
2901
|
-
|
|
3467
|
+
state.scratch.replaceAll([...state.scratchOwners.values()].flat());
|
|
3468
|
+
}
|
|
3469
|
+
function releaseInterned(state, table, key) {
|
|
3470
|
+
const entry = table.get(key);
|
|
3471
|
+
if (!entry) {
|
|
2902
3472
|
return;
|
|
2903
3473
|
}
|
|
2904
|
-
|
|
2905
|
-
|
|
2906
|
-
|
|
2907
|
-
|
|
2908
|
-
if (baseCSS) {
|
|
2909
|
-
css += `[data-jx="${uid}"] { ${baseCSS} }
|
|
2910
|
-
`;
|
|
2911
|
-
}
|
|
2912
|
-
function emitNested(scope, rules) {
|
|
2913
|
-
const props = toCSSText(rules);
|
|
2914
|
-
if (props) {
|
|
2915
|
-
css += `${scope} { ${props} }
|
|
2916
|
-
`;
|
|
2917
|
-
}
|
|
2918
|
-
for (const [sel, sub] of Object.entries(rules)) {
|
|
2919
|
-
if (sub === null || typeof sub !== "object" || Array.isArray(sub)) {
|
|
2920
|
-
continue;
|
|
2921
|
-
}
|
|
2922
|
-
if (sel.startsWith("@")) {
|
|
2923
|
-
continue;
|
|
2924
|
-
}
|
|
2925
|
-
const resolved = sel.startsWith("&") ? sel.replace("&", scope) : sel.startsWith("[") ? `${scope}${sel}` : sel.startsWith(":") || sel.startsWith(".") ? `${scope}${sel}` : `${scope} ${sel}`;
|
|
2926
|
-
emitNested(resolved, sub);
|
|
2927
|
-
}
|
|
3474
|
+
entry.refs -= 1;
|
|
3475
|
+
if (entry.refs <= 0) {
|
|
3476
|
+
table.delete(key);
|
|
3477
|
+
state.shared.remove(entry.inserted);
|
|
2928
3478
|
}
|
|
2929
|
-
|
|
2930
|
-
|
|
2931
|
-
|
|
3479
|
+
}
|
|
3480
|
+
function retainInterned(state, table, key, texts) {
|
|
3481
|
+
const existing = table.get(key);
|
|
3482
|
+
if (existing) {
|
|
3483
|
+
existing.refs += 1;
|
|
3484
|
+
return;
|
|
2932
3485
|
}
|
|
2933
|
-
|
|
2934
|
-
|
|
2935
|
-
|
|
2936
|
-
|
|
2937
|
-
|
|
2938
|
-
|
|
2939
|
-
continue;
|
|
2940
|
-
}
|
|
2941
|
-
const resolved = sel.startsWith("&") ? sel.replace("&", parentSel) : sel.startsWith("[") ? `${parentSel}${sel}` : sel.startsWith(":") || sel.startsWith(".") ? `${parentSel}${sel}` : `${parentSel} ${sel}`;
|
|
2942
|
-
const props = toCSSText(sub);
|
|
2943
|
-
if (props) {
|
|
2944
|
-
css += `${atRule} { ${resolved} { ${props} } }
|
|
2945
|
-
`;
|
|
2946
|
-
}
|
|
2947
|
-
emitMediaNested(atRule, resolved, sub);
|
|
2948
|
-
}
|
|
3486
|
+
table.set(key, { inserted: state.shared.insert(texts), refs: 1 });
|
|
3487
|
+
}
|
|
3488
|
+
function releaseElementStyles(el, only) {
|
|
3489
|
+
const entry = elementStyles.get(el);
|
|
3490
|
+
if (!entry || only !== undefined && entry !== only) {
|
|
3491
|
+
return;
|
|
2949
3492
|
}
|
|
2950
|
-
|
|
2951
|
-
|
|
2952
|
-
|
|
2953
|
-
|
|
2954
|
-
|
|
2955
|
-
|
|
2956
|
-
|
|
2957
|
-
|
|
2958
|
-
|
|
2959
|
-
|
|
2960
|
-
|
|
2961
|
-
|
|
2962
|
-
|
|
2963
|
-
emitNested(forced, rules);
|
|
2964
|
-
} else {
|
|
2965
|
-
css += `${atRule} { ${scope} { ${toCSSText(rules)} } }
|
|
2966
|
-
`;
|
|
2967
|
-
emitMediaNested(atRule, scope, rules);
|
|
3493
|
+
elementStyles.delete(el);
|
|
3494
|
+
entry.stop?.();
|
|
3495
|
+
for (const name of entry.vars) {
|
|
3496
|
+
el.style.removeProperty(name);
|
|
3497
|
+
}
|
|
3498
|
+
delete el.dataset.jx;
|
|
3499
|
+
if (sheetStates.get(entry.doc) !== entry.state) {
|
|
3500
|
+
return;
|
|
3501
|
+
}
|
|
3502
|
+
const { state } = entry;
|
|
3503
|
+
if (entry.interned === null) {
|
|
3504
|
+
if (state.scratchOwners.delete(el)) {
|
|
3505
|
+
rewriteScratch(state);
|
|
2968
3506
|
}
|
|
3507
|
+
} else {
|
|
3508
|
+
releaseInterned(state, state.interned, entry.interned);
|
|
3509
|
+
}
|
|
3510
|
+
for (const key of entry.hoisted) {
|
|
3511
|
+
releaseInterned(state, state.hoisted, key);
|
|
3512
|
+
}
|
|
3513
|
+
}
|
|
3514
|
+
function resetDocumentStyles(doc = document) {
|
|
3515
|
+
const state = sheetStates.get(doc);
|
|
3516
|
+
if (!state) {
|
|
3517
|
+
return;
|
|
2969
3518
|
}
|
|
2970
|
-
|
|
2971
|
-
|
|
2972
|
-
|
|
2973
|
-
|
|
2974
|
-
|
|
3519
|
+
sheetStates.delete(doc);
|
|
3520
|
+
for (const el of state.scratchOwners.keys()) {
|
|
3521
|
+
elementStyles.delete(el);
|
|
3522
|
+
delete el.dataset.jx;
|
|
3523
|
+
}
|
|
3524
|
+
state.scratchOwners.clear();
|
|
3525
|
+
state.interned.clear();
|
|
3526
|
+
state.hoisted.clear();
|
|
3527
|
+
state.shared.detach();
|
|
3528
|
+
state.scratch?.detach();
|
|
3529
|
+
}
|
|
3530
|
+
function documentStyleText(doc = document) {
|
|
3531
|
+
const state = sheetStates.get(doc);
|
|
3532
|
+
if (!state) {
|
|
3533
|
+
return "";
|
|
3534
|
+
}
|
|
3535
|
+
return [state.shared.text(), state.scratch?.text() ?? ""].filter(Boolean).join(`
|
|
3536
|
+
`);
|
|
3537
|
+
}
|
|
3538
|
+
function declaresDisplay(style) {
|
|
3539
|
+
return Boolean(style) && typeof style === "object" && "display" in style;
|
|
3540
|
+
}
|
|
3541
|
+
var callSiteStyles = new WeakMap;
|
|
3542
|
+
function mergeStyle(base, over) {
|
|
3543
|
+
if (!over) {
|
|
3544
|
+
return base;
|
|
3545
|
+
}
|
|
3546
|
+
const out = { ...base };
|
|
3547
|
+
for (const [key, value] of Object.entries(over)) {
|
|
3548
|
+
const prior = out[key];
|
|
3549
|
+
out[key] = prior !== null && typeof prior === "object" && value !== null && typeof value === "object" && !Array.isArray(value) ? mergeStyle(prior, value) : value;
|
|
3550
|
+
}
|
|
3551
|
+
return out;
|
|
3552
|
+
}
|
|
3553
|
+
function applyStyle(el, styleDef, mediaQueries = {}, state = {}) {
|
|
3554
|
+
applyStyleInto(el, styleDef, mediaQueries, state, false);
|
|
2975
3555
|
}
|
|
2976
|
-
var elementStyleTags = new WeakMap;
|
|
2977
3556
|
function reapplyStyle(el, styleDef, mediaQueries = {}, state = {}) {
|
|
2978
|
-
|
|
2979
|
-
|
|
2980
|
-
|
|
2981
|
-
|
|
3557
|
+
applyStyleInto(el, styleDef ?? {}, mediaQueries, state, true);
|
|
3558
|
+
}
|
|
3559
|
+
function applyStyleInto(el, styleDef, mediaQueries, state, live) {
|
|
3560
|
+
releaseElementStyles(el);
|
|
3561
|
+
const doc = el.ownerDocument ?? document;
|
|
3562
|
+
const sheetState = sheetStateFor(doc);
|
|
3563
|
+
const transposeSelector = (_canvasDelinkPopovers || _canvasDelinkCommands) && canvasStamped(el) ? (selector) => transposeCanvasOverlaySelector(selector, {
|
|
3564
|
+
dialog: el.tagName === "DIALOG"
|
|
3565
|
+
}) : (selector) => selector;
|
|
3566
|
+
let serial = -1;
|
|
3567
|
+
let indirect = 0;
|
|
3568
|
+
const sources = [];
|
|
3569
|
+
const rules = buildStyleRules(styleDef, {
|
|
3570
|
+
mediaQueries,
|
|
3571
|
+
resolveValue: (property, value, target) => {
|
|
3572
|
+
if (target === "self" && property.startsWith("--")) {
|
|
3573
|
+
sources.push({ name: property, value });
|
|
3574
|
+
return null;
|
|
3575
|
+
}
|
|
3576
|
+
if (serial < 0) {
|
|
3577
|
+
({ serial } = sheetState);
|
|
3578
|
+
sheetState.serial += 1;
|
|
3579
|
+
}
|
|
3580
|
+
const name = `--jx-r${serial}-${indirect}`;
|
|
3581
|
+
indirect += 1;
|
|
3582
|
+
sources.push({ name, value });
|
|
3583
|
+
return `var(${name})`;
|
|
3584
|
+
},
|
|
3585
|
+
scope: SCOPE_TOKEN,
|
|
3586
|
+
transposeSelector,
|
|
3587
|
+
transposeValue: canvasStyleValue
|
|
3588
|
+
});
|
|
3589
|
+
if (rules.length === 0 && sources.length === 0) {
|
|
3590
|
+
return;
|
|
2982
3591
|
}
|
|
2983
|
-
|
|
2984
|
-
|
|
2985
|
-
|
|
3592
|
+
const scoped = rules.filter((rule) => rule.target !== "unscoped");
|
|
3593
|
+
const unscoped = rules.filter((rule) => rule.target === "unscoped");
|
|
3594
|
+
for (const rule of unscoped) {
|
|
3595
|
+
retainInterned(sheetState, sheetState.hoisted, rule.text, [rule.text]);
|
|
3596
|
+
}
|
|
3597
|
+
const uid = `jx-${hashCss(scoped.map((rule) => rule.key).join("|"))}`;
|
|
3598
|
+
const texts = scoped.map((rule) => rule.text.replaceAll(SCOPE_TOKEN, `[data-jx="${uid}"]`));
|
|
3599
|
+
if (texts.length > 0) {
|
|
3600
|
+
el.dataset.jx = uid;
|
|
3601
|
+
if (live) {
|
|
3602
|
+
sheetState.scratch ??= openSink(doc);
|
|
3603
|
+
sheetState.scratchOwners.set(el, texts);
|
|
3604
|
+
rewriteScratch(sheetState);
|
|
3605
|
+
} else {
|
|
3606
|
+
retainInterned(sheetState, sheetState.interned, uid, texts);
|
|
3607
|
+
}
|
|
3608
|
+
}
|
|
3609
|
+
const entry = {
|
|
3610
|
+
doc,
|
|
3611
|
+
hoisted: unscoped.map((rule) => rule.text),
|
|
3612
|
+
interned: texts.length > 0 && !live ? uid : null,
|
|
3613
|
+
state: sheetState,
|
|
3614
|
+
stop: null,
|
|
3615
|
+
uid,
|
|
3616
|
+
vars: sources.map((source) => source.name)
|
|
3617
|
+
};
|
|
3618
|
+
if (sources.length > 0) {
|
|
3619
|
+
const scope = effectScope();
|
|
3620
|
+
scope.run(() => {
|
|
3621
|
+
for (const { name, value } of sources) {
|
|
3622
|
+
effect(() => {
|
|
3623
|
+
const resolved = isRefObj(value) ? resolveRef(value.$ref, state) : evaluateTemplate(value, state);
|
|
3624
|
+
el.style.setProperty(name, canvasStyleValue(String(resolved ?? "")));
|
|
3625
|
+
});
|
|
3626
|
+
}
|
|
3627
|
+
});
|
|
3628
|
+
entry.stop = () => scope.stop();
|
|
3629
|
+
}
|
|
3630
|
+
elementStyles.set(el, entry);
|
|
3631
|
+
onScopeDispose(() => releaseElementStyles(el, entry), true);
|
|
2986
3632
|
}
|
|
2987
3633
|
var ENUMERATED_ATTRS = new Set(["contenteditable", "draggable", "spellcheck"]);
|
|
3634
|
+
function enumeratedAttrNames() {
|
|
3635
|
+
return [...ENUMERATED_ATTRS].toSorted();
|
|
3636
|
+
}
|
|
2988
3637
|
function booleanAttrValue(name, value) {
|
|
2989
3638
|
const lower = name.toLowerCase();
|
|
2990
3639
|
if (lower.startsWith("aria-") || ENUMERATED_ATTRS.has(lower)) {
|
|
@@ -2996,6 +3645,10 @@ function applyAttributes(el, attrs, state) {
|
|
|
2996
3645
|
for (const [k, v] of Object.entries(attrs)) {
|
|
2997
3646
|
const attr = canvasAttrName(el, k);
|
|
2998
3647
|
const write = (resolved) => {
|
|
3648
|
+
if (resolved === null || resolved === undefined) {
|
|
3649
|
+
el.removeAttribute(attr);
|
|
3650
|
+
return;
|
|
3651
|
+
}
|
|
2999
3652
|
if (typeof resolved === "boolean") {
|
|
3000
3653
|
const text = booleanAttrValue(attr, resolved);
|
|
3001
3654
|
if (text === null) {
|
|
@@ -3005,7 +3658,7 @@ function applyAttributes(el, attrs, state) {
|
|
|
3005
3658
|
}
|
|
3006
3659
|
return;
|
|
3007
3660
|
}
|
|
3008
|
-
el.setAttribute(attr, canvasAssetValue(el.tagName, k, String(resolved
|
|
3661
|
+
el.setAttribute(attr, canvasAssetValue(el.tagName, k, String(resolved)));
|
|
3009
3662
|
};
|
|
3010
3663
|
if (isRefObj(v)) {
|
|
3011
3664
|
effect(() => write(resolveRef(v.$ref, state)));
|
|
@@ -3020,8 +3673,70 @@ function renderMappedArrayInto(parentEl, arrayDef, state, options) {
|
|
|
3020
3673
|
const path = options?._path ?? [];
|
|
3021
3674
|
const anchor = document.createComment("jx-array");
|
|
3022
3675
|
parentEl.append(anchor);
|
|
3023
|
-
const { items: itemsSrc, map: mapDef, filter: filterRef, sort: sortRef } = arrayDef;
|
|
3024
|
-
|
|
3676
|
+
const { items: itemsSrc, map: mapDef, filter: filterRef, sort: sortRef, key: keyRef } = arrayDef;
|
|
3677
|
+
const keyPointer = isRefObj(keyRef) ? keyRef.$ref : null;
|
|
3678
|
+
const instancePath = _instancePath;
|
|
3679
|
+
let warned = false;
|
|
3680
|
+
const warnOnce = (message) => {
|
|
3681
|
+
if (!warned) {
|
|
3682
|
+
warned = true;
|
|
3683
|
+
console.warn(`Jx $map: ${message}`);
|
|
3684
|
+
}
|
|
3685
|
+
};
|
|
3686
|
+
let rows = [];
|
|
3687
|
+
const teardown = (row) => {
|
|
3688
|
+
row.scope.stop();
|
|
3689
|
+
row.node.remove();
|
|
3690
|
+
};
|
|
3691
|
+
const createRow = (key, item, index) => {
|
|
3692
|
+
const map = shallowReactive({ index, item });
|
|
3693
|
+
const child = Object.create(state);
|
|
3694
|
+
child.$map = map;
|
|
3695
|
+
Object.defineProperty(child, "$map/item", { enumerable: true, get: () => map.item });
|
|
3696
|
+
Object.defineProperty(child, "$map/index", { enumerable: true, get: () => map.index });
|
|
3697
|
+
const scope = effectScope(true);
|
|
3698
|
+
const childOpts = options ? { ...options, _path: [...path, "map", index] } : undefined;
|
|
3699
|
+
const node = scope.run(() => renderNode(mapDef, child, childOpts));
|
|
3700
|
+
return { key, map, node, scope };
|
|
3701
|
+
};
|
|
3702
|
+
const reconcile = (list, keys) => {
|
|
3703
|
+
const previous = new Map;
|
|
3704
|
+
for (const row of rows) {
|
|
3705
|
+
previous.set(row.key, row);
|
|
3706
|
+
}
|
|
3707
|
+
const next = [];
|
|
3708
|
+
for (let index = 0;index < list.length; index++) {
|
|
3709
|
+
const key = keys[index];
|
|
3710
|
+
const item = list[index];
|
|
3711
|
+
const existing = previous.get(key);
|
|
3712
|
+
if (existing) {
|
|
3713
|
+
previous.delete(key);
|
|
3714
|
+
if (existing.map.item !== item) {
|
|
3715
|
+
existing.map.item = item;
|
|
3716
|
+
}
|
|
3717
|
+
if (existing.map.index !== index) {
|
|
3718
|
+
existing.map.index = index;
|
|
3719
|
+
options?.onNodeMoved?.(existing.node, [...path, "map", index]);
|
|
3720
|
+
}
|
|
3721
|
+
next.push(existing);
|
|
3722
|
+
} else {
|
|
3723
|
+
next.push(createRow(key, item, index));
|
|
3724
|
+
}
|
|
3725
|
+
}
|
|
3726
|
+
for (const row of previous.values()) {
|
|
3727
|
+
teardown(row);
|
|
3728
|
+
}
|
|
3729
|
+
let cursor = rows.find((row) => !previous.has(row.key))?.node ?? anchor;
|
|
3730
|
+
for (const row of next) {
|
|
3731
|
+
if (row.node === cursor) {
|
|
3732
|
+
cursor = cursor.nextSibling ?? anchor;
|
|
3733
|
+
continue;
|
|
3734
|
+
}
|
|
3735
|
+
cursor.before(row.node);
|
|
3736
|
+
}
|
|
3737
|
+
rows = next;
|
|
3738
|
+
};
|
|
3739
|
+
const update = () => {
|
|
3025
3740
|
let items = isRefObj(itemsSrc) ? resolveRef(itemsSrc.$ref, state) : itemsSrc;
|
|
3026
3741
|
if (Array.isArray(items) && isRefObj(filterRef)) {
|
|
3027
3742
|
const fn = resolveRef(filterRef.$ref, state);
|
|
@@ -3035,30 +3750,65 @@ function renderMappedArrayInto(parentEl, arrayDef, state, options) {
|
|
|
3035
3750
|
items = [...items].toSorted(fn);
|
|
3036
3751
|
}
|
|
3037
3752
|
}
|
|
3038
|
-
|
|
3039
|
-
|
|
3040
|
-
|
|
3041
|
-
|
|
3042
|
-
|
|
3043
|
-
|
|
3044
|
-
|
|
3045
|
-
|
|
3046
|
-
|
|
3047
|
-
child["$map/item"] = item;
|
|
3048
|
-
child["$map/index"] = index;
|
|
3049
|
-
const childOpts = options ? { ...options, _path: [...path, "map", index] } : undefined;
|
|
3050
|
-
const node = renderNode(mapDef, child, childOpts);
|
|
3051
|
-
anchor.before(node);
|
|
3052
|
-
nodes.push(node);
|
|
3753
|
+
const list = Array.isArray(items) && mapDef ? items : [];
|
|
3754
|
+
const keys = list.map((item, index) => mappedRowKey(keyPointer, item, index, warnOnce));
|
|
3755
|
+
const seen = new Set;
|
|
3756
|
+
for (let i = 0;i < keys.length; i++) {
|
|
3757
|
+
if (seen.has(keys[i])) {
|
|
3758
|
+
warnOnce(`duplicate key ${String(keys[i])} — every occurrence after the first is rebuilt on each change`);
|
|
3759
|
+
keys[i] = { duplicate: i };
|
|
3760
|
+
} else {
|
|
3761
|
+
seen.add(keys[i]);
|
|
3053
3762
|
}
|
|
3054
|
-
}
|
|
3055
|
-
|
|
3056
|
-
|
|
3057
|
-
|
|
3058
|
-
|
|
3763
|
+
}
|
|
3764
|
+
pauseTracking();
|
|
3765
|
+
try {
|
|
3766
|
+
underInstancePath(reexpand(instancePath), () => reconcile(list, keys));
|
|
3767
|
+
} finally {
|
|
3768
|
+
resetTracking();
|
|
3769
|
+
}
|
|
3770
|
+
};
|
|
3771
|
+
let queued = false;
|
|
3772
|
+
let stopped = false;
|
|
3773
|
+
const runner = effect(update, {
|
|
3774
|
+
scheduler: () => {
|
|
3775
|
+
if (queued) {
|
|
3776
|
+
return;
|
|
3059
3777
|
}
|
|
3060
|
-
|
|
3778
|
+
queued = true;
|
|
3779
|
+
queueMicrotask(() => {
|
|
3780
|
+
queued = false;
|
|
3781
|
+
if (!stopped) {
|
|
3782
|
+
runner();
|
|
3783
|
+
}
|
|
3784
|
+
});
|
|
3785
|
+
}
|
|
3061
3786
|
});
|
|
3787
|
+
onScopeDispose(() => {
|
|
3788
|
+
stopped = true;
|
|
3789
|
+
for (const row of rows) {
|
|
3790
|
+
teardown(row);
|
|
3791
|
+
}
|
|
3792
|
+
rows = [];
|
|
3793
|
+
}, true);
|
|
3794
|
+
}
|
|
3795
|
+
function mappedRowKey(pointer, item, index, warnOnce) {
|
|
3796
|
+
if (pointer === null) {
|
|
3797
|
+
return index;
|
|
3798
|
+
}
|
|
3799
|
+
if (pointer === "$map/item") {
|
|
3800
|
+
return item;
|
|
3801
|
+
}
|
|
3802
|
+
if (pointer.startsWith("$map/item/")) {
|
|
3803
|
+
const key = readPath(item, pointer.slice("$map/item/".length));
|
|
3804
|
+
if (key === undefined || key === null) {
|
|
3805
|
+
warnOnce(`key "${pointer}" is empty for some items — those rows fall back to their index`);
|
|
3806
|
+
return index;
|
|
3807
|
+
}
|
|
3808
|
+
return key;
|
|
3809
|
+
}
|
|
3810
|
+
warnOnce(`key "${pointer}" is not a $map/item pointer — rows fall back to their index`);
|
|
3811
|
+
return index;
|
|
3062
3812
|
}
|
|
3063
3813
|
function resolveTagName(tagName, scope) {
|
|
3064
3814
|
if (typeof tagName === "string") {
|
|
@@ -3074,65 +3824,87 @@ function resolveTagName(tagName, scope) {
|
|
|
3074
3824
|
const key = evaluateOperand(expression.target, scope, null);
|
|
3075
3825
|
return expression.cases[String(key)] ?? expression.default;
|
|
3076
3826
|
}
|
|
3077
|
-
function renderSwitch(
|
|
3827
|
+
function renderSwitch(def, state, options) {
|
|
3078
3828
|
const path = options?._path ?? [];
|
|
3079
|
-
const container = document.createElement(resolveTagName(
|
|
3829
|
+
const container = document.createElement(resolveTagName(def.tagName, state));
|
|
3830
|
+
const instancePath = _instancePath;
|
|
3080
3831
|
if (options?.onNodeCreated) {
|
|
3081
|
-
options.onNodeCreated(container, path,
|
|
3832
|
+
options.onNodeCreated(container, path, def, state);
|
|
3082
3833
|
}
|
|
3083
|
-
applyProperties(container,
|
|
3084
|
-
applyStyle(container,
|
|
3085
|
-
applyAttributes(container,
|
|
3834
|
+
applyProperties(container, def, state);
|
|
3835
|
+
applyStyle(container, def.style ?? {}, state["$media"] ?? {}, state);
|
|
3836
|
+
applyAttributes(container, def.attributes ?? {}, state);
|
|
3086
3837
|
let generation = 0;
|
|
3838
|
+
let live = null;
|
|
3839
|
+
let renderedKey = null;
|
|
3840
|
+
const retire = () => {
|
|
3841
|
+
live?.stop();
|
|
3842
|
+
live = null;
|
|
3843
|
+
};
|
|
3087
3844
|
effect(() => {
|
|
3088
|
-
|
|
3089
|
-
|
|
3845
|
+
if (!isRefObj(def.$switch)) {
|
|
3846
|
+
retire();
|
|
3847
|
+
container.replaceChildren();
|
|
3848
|
+
generation += 1;
|
|
3090
3849
|
return;
|
|
3091
3850
|
}
|
|
3092
|
-
const key = resolveRef(
|
|
3093
|
-
|
|
3851
|
+
const key = String(resolveRef(def.$switch.$ref, state));
|
|
3852
|
+
if (key === renderedKey) {
|
|
3853
|
+
return;
|
|
3854
|
+
}
|
|
3855
|
+
renderedKey = key;
|
|
3856
|
+
retire();
|
|
3857
|
+
container.replaceChildren();
|
|
3858
|
+
generation += 1;
|
|
3859
|
+
const caseDef = def.cases?.[key];
|
|
3094
3860
|
if (!caseDef) {
|
|
3095
3861
|
return;
|
|
3096
3862
|
}
|
|
3863
|
+
const gen = generation;
|
|
3864
|
+
const scope = effectScope(true);
|
|
3865
|
+
live = scope;
|
|
3866
|
+
const childOpts = options ? { ...options, _path: [...path, "cases", key] } : undefined;
|
|
3097
3867
|
if (isRefObj(caseDef)) {
|
|
3098
|
-
|
|
3099
|
-
|
|
3100
|
-
const { href } = new URL(caseDef.$ref, location.href);
|
|
3101
|
-
resolve(href).then(async (doc) => {
|
|
3868
|
+
const { href } = new URL(caseDef.$ref, options?._ctx?.base ?? location.href);
|
|
3869
|
+
resolve(href, options?._ctx).then(async (doc) => {
|
|
3102
3870
|
if (gen !== generation) {
|
|
3103
3871
|
return;
|
|
3104
3872
|
}
|
|
3105
|
-
const childScope = await buildScope(doc, {}, href);
|
|
3873
|
+
const childScope = await buildScope(doc, {}, href, options?._ctx);
|
|
3106
3874
|
if (gen !== generation) {
|
|
3107
3875
|
return;
|
|
3108
3876
|
}
|
|
3109
3877
|
container.replaceChildren();
|
|
3110
|
-
|
|
3111
|
-
container.append(renderNode(doc, childScope, childOpts2));
|
|
3878
|
+
underInstancePath(reexpand(instancePath), () => scope.run(() => container.append(renderNode(doc, childScope, childOpts))));
|
|
3112
3879
|
}).catch((error) => console.error("Jx $switch: failed to load external case", caseDef.$ref, error));
|
|
3113
3880
|
return;
|
|
3114
3881
|
}
|
|
3115
|
-
|
|
3116
|
-
|
|
3882
|
+
pauseTracking();
|
|
3883
|
+
try {
|
|
3884
|
+
underInstancePath(reexpand(instancePath), () => scope.run(() => container.append(renderNode(caseDef, state, childOpts))));
|
|
3885
|
+
} finally {
|
|
3886
|
+
resetTracking();
|
|
3887
|
+
}
|
|
3117
3888
|
});
|
|
3889
|
+
onScopeDispose(retire, true);
|
|
3118
3890
|
return container;
|
|
3119
3891
|
}
|
|
3120
|
-
async function resolvePrototype(
|
|
3121
|
-
if (
|
|
3122
|
-
return resolveExternalPrototype(
|
|
3892
|
+
async function resolvePrototype(def, state, key, base, ctx) {
|
|
3893
|
+
if (def.$src) {
|
|
3894
|
+
return resolveExternalPrototype(def, state, key, base);
|
|
3123
3895
|
}
|
|
3124
|
-
switch (
|
|
3896
|
+
switch (def.$prototype) {
|
|
3125
3897
|
case "Request": {
|
|
3126
3898
|
const s = ref(null);
|
|
3127
|
-
const debounceMs =
|
|
3899
|
+
const debounceMs = def.debounce ?? 0;
|
|
3128
3900
|
let debounceTimer = null;
|
|
3129
|
-
if (!
|
|
3901
|
+
if (!def.manual && !(ctx?.skipAutoRequests ?? _autoRequestConfig.skip)) {
|
|
3130
3902
|
effect(() => {
|
|
3131
3903
|
let url;
|
|
3132
|
-
if (isTemplateString(
|
|
3133
|
-
url = evaluateTemplate(
|
|
3904
|
+
if (isTemplateString(def.url)) {
|
|
3905
|
+
url = evaluateTemplate(def.url, state);
|
|
3134
3906
|
} else {
|
|
3135
|
-
({ url } =
|
|
3907
|
+
({ url } = def);
|
|
3136
3908
|
}
|
|
3137
3909
|
if (!url || url === "undefined" || url.includes("undefined")) {
|
|
3138
3910
|
return;
|
|
@@ -3145,11 +3917,11 @@ async function resolvePrototype(def2, state, key, base) {
|
|
|
3145
3917
|
}
|
|
3146
3918
|
});
|
|
3147
3919
|
const doFetch = () => fetch(url, {
|
|
3148
|
-
method:
|
|
3920
|
+
method: def.method ?? "GET",
|
|
3149
3921
|
signal: controller.signal,
|
|
3150
|
-
...
|
|
3151
|
-
...
|
|
3152
|
-
body: typeof
|
|
3922
|
+
...def.headers && { headers: def.headers },
|
|
3923
|
+
...def.body && {
|
|
3924
|
+
body: typeof def.body === "object" ? JSON.stringify(def.body) : def.body
|
|
3153
3925
|
}
|
|
3154
3926
|
}).then((r) => r.ok ? r.json() : Promise.reject(r.statusText)).then((d) => {
|
|
3155
3927
|
s.value = d;
|
|
@@ -3170,7 +3942,7 @@ async function resolvePrototype(def2, state, key, base) {
|
|
|
3170
3942
|
case "URLSearchParams": {
|
|
3171
3943
|
return computed(() => {
|
|
3172
3944
|
const p = {};
|
|
3173
|
-
for (const [k, v] of Object.entries(
|
|
3945
|
+
for (const [k, v] of Object.entries(def)) {
|
|
3174
3946
|
if (k !== "$prototype") {
|
|
3175
3947
|
p[k] = isRefObj(v) ? resolveRef(v.$ref, state) : isTemplateString(v) ? evaluateTemplate(v, state) : v;
|
|
3176
3948
|
}
|
|
@@ -3180,14 +3952,14 @@ async function resolvePrototype(def2, state, key, base) {
|
|
|
3180
3952
|
}
|
|
3181
3953
|
case "LocalStorage":
|
|
3182
3954
|
case "SessionStorage": {
|
|
3183
|
-
const store =
|
|
3184
|
-
const k =
|
|
3955
|
+
const store = def.$prototype === "LocalStorage" ? localStorage : sessionStorage;
|
|
3956
|
+
const k = def.key ?? key;
|
|
3185
3957
|
let init;
|
|
3186
3958
|
try {
|
|
3187
3959
|
const s = store.getItem(k);
|
|
3188
|
-
init = s !== null ? JSON.parse(s) :
|
|
3960
|
+
init = s !== null ? JSON.parse(s) : def.default ?? null;
|
|
3189
3961
|
} catch {
|
|
3190
|
-
init =
|
|
3962
|
+
init = def.default ?? null;
|
|
3191
3963
|
}
|
|
3192
3964
|
const storageState = ref(init);
|
|
3193
3965
|
effect(() => {
|
|
@@ -3205,7 +3977,7 @@ async function resolvePrototype(def2, state, key, base) {
|
|
|
3205
3977
|
return storageState;
|
|
3206
3978
|
}
|
|
3207
3979
|
case "Cookie": {
|
|
3208
|
-
const name =
|
|
3980
|
+
const name = def.name ?? key;
|
|
3209
3981
|
const read = () => {
|
|
3210
3982
|
const raw = readCookie(document.cookie, name);
|
|
3211
3983
|
if (raw === null) {
|
|
@@ -3217,9 +3989,9 @@ async function resolvePrototype(def2, state, key, base) {
|
|
|
3217
3989
|
return raw;
|
|
3218
3990
|
}
|
|
3219
3991
|
};
|
|
3220
|
-
const cookieState = ref(read() ??
|
|
3992
|
+
const cookieState = ref(read() ?? def.default ?? null);
|
|
3221
3993
|
effect(() => {
|
|
3222
|
-
document.cookie = serializeCookie(name, cookieState.value,
|
|
3994
|
+
document.cookie = serializeCookie(name, cookieState.value, def);
|
|
3223
3995
|
});
|
|
3224
3996
|
return cookieState;
|
|
3225
3997
|
}
|
|
@@ -3232,7 +4004,7 @@ async function resolvePrototype(def2, state, key, base) {
|
|
|
3232
4004
|
keyPath = "id",
|
|
3233
4005
|
autoIncrement = true,
|
|
3234
4006
|
indexes = []
|
|
3235
|
-
} =
|
|
4007
|
+
} = def;
|
|
3236
4008
|
if (!database || !store) {
|
|
3237
4009
|
throw new Error(`Jx: IndexedDB entry '${key}' requires database and store`);
|
|
3238
4010
|
}
|
|
@@ -3262,28 +4034,28 @@ async function resolvePrototype(def2, state, key, base) {
|
|
|
3262
4034
|
return idbState;
|
|
3263
4035
|
}
|
|
3264
4036
|
case "Set": {
|
|
3265
|
-
return new Set(Array.isArray(
|
|
4037
|
+
return new Set(Array.isArray(def.default) ? def.default : []);
|
|
3266
4038
|
}
|
|
3267
4039
|
case "Map": {
|
|
3268
|
-
return new Map(Object.entries(isJsonObject(
|
|
4040
|
+
return new Map(Object.entries(isJsonObject(def.default) ? def.default : {}));
|
|
3269
4041
|
}
|
|
3270
4042
|
case "FormData": {
|
|
3271
4043
|
const fd = new FormData;
|
|
3272
|
-
for (const [k, v] of Object.entries(
|
|
4044
|
+
for (const [k, v] of Object.entries(def.fields ?? {})) {
|
|
3273
4045
|
fd.append(k, v);
|
|
3274
4046
|
}
|
|
3275
4047
|
return fd;
|
|
3276
4048
|
}
|
|
3277
4049
|
case "Blob": {
|
|
3278
|
-
return new Blob(
|
|
3279
|
-
type: typeof
|
|
4050
|
+
return new Blob(def.parts ?? [], {
|
|
4051
|
+
type: typeof def.type === "string" ? def.type : "text/plain"
|
|
3280
4052
|
});
|
|
3281
4053
|
}
|
|
3282
4054
|
case "ReadableStream": {
|
|
3283
4055
|
return null;
|
|
3284
4056
|
}
|
|
3285
4057
|
default: {
|
|
3286
|
-
console.warn(`Jx: unknown $prototype "${
|
|
4058
|
+
console.warn(`Jx: unknown $prototype "${def.$prototype}" for "${key}". Did you mean to add '$src'?`);
|
|
3287
4059
|
return ref(null);
|
|
3288
4060
|
}
|
|
3289
4061
|
}
|
|
@@ -3300,17 +4072,20 @@ var EXTERNAL_RESERVED = new Set([
|
|
|
3300
4072
|
"arguments",
|
|
3301
4073
|
"name"
|
|
3302
4074
|
]);
|
|
3303
|
-
async function resolveExternalPrototype(
|
|
3304
|
-
const src =
|
|
4075
|
+
async function resolveExternalPrototype(def, state, key, base) {
|
|
4076
|
+
const src = def.$src;
|
|
3305
4077
|
if (!src || !src.endsWith(".class.json")) {
|
|
3306
|
-
throw new Error(`Jx: $prototype "${
|
|
4078
|
+
throw new Error(`Jx: $prototype "${def.$prototype}" requires a .class.json $src, got "${src}". Wrap the class in a .class.json schema with $implementation.`);
|
|
3307
4079
|
}
|
|
3308
|
-
return resolveClassJson(
|
|
4080
|
+
return resolveClassJson(def, state, key, base);
|
|
3309
4081
|
}
|
|
3310
|
-
async function importAndInstantiate(
|
|
4082
|
+
async function importAndInstantiate(def, src, exportName, base) {
|
|
3311
4083
|
let mod;
|
|
3312
|
-
|
|
3313
|
-
|
|
4084
|
+
const seeded = seededModule(src);
|
|
4085
|
+
if (seeded instanceof Promise) {
|
|
4086
|
+
mod = await seeded;
|
|
4087
|
+
} else if (seeded) {
|
|
4088
|
+
mod = seeded;
|
|
3314
4089
|
} else {
|
|
3315
4090
|
try {
|
|
3316
4091
|
mod = await import(src);
|
|
@@ -3332,7 +4107,7 @@ async function importAndInstantiate(def2, src, exportName, base) {
|
|
|
3332
4107
|
throw new TypeError(`Jx: "${exportName}" from "${src}" is not a class`);
|
|
3333
4108
|
}
|
|
3334
4109
|
const config = {};
|
|
3335
|
-
for (const [k, v] of Object.entries(
|
|
4110
|
+
for (const [k, v] of Object.entries(def)) {
|
|
3336
4111
|
if (!EXTERNAL_RESERVED.has(k)) {
|
|
3337
4112
|
config[k] = v;
|
|
3338
4113
|
}
|
|
@@ -3355,15 +4130,15 @@ async function importAndInstantiate(def2, src, exportName, base) {
|
|
|
3355
4130
|
}
|
|
3356
4131
|
return s;
|
|
3357
4132
|
}
|
|
3358
|
-
async function resolveClassJson(
|
|
3359
|
-
const src =
|
|
4133
|
+
async function resolveClassJson(def, state, key, base) {
|
|
4134
|
+
const src = def.$src;
|
|
3360
4135
|
if (!src) {
|
|
3361
4136
|
throw new Error(`Jx: class entry '${key}' has no $src`);
|
|
3362
4137
|
}
|
|
3363
4138
|
let classDef;
|
|
3364
4139
|
const isBareSpecifier = !src.startsWith(".") && !src.startsWith("/") && !src.startsWith("http") && !src.startsWith("file:");
|
|
3365
4140
|
if (isBareSpecifier) {
|
|
3366
|
-
return resolveViaDevProxy(
|
|
4141
|
+
return resolveViaDevProxy(def, state, key, base);
|
|
3367
4142
|
}
|
|
3368
4143
|
try {
|
|
3369
4144
|
const url = base ? new URL(src, base).href : src;
|
|
@@ -3373,25 +4148,25 @@ async function resolveClassJson(def2, state, key, base) {
|
|
|
3373
4148
|
}
|
|
3374
4149
|
classDef = await res.json();
|
|
3375
4150
|
} catch {
|
|
3376
|
-
return resolveViaDevProxy(
|
|
4151
|
+
return resolveViaDevProxy(def, state, key, base);
|
|
3377
4152
|
}
|
|
3378
4153
|
if (classDef.$implementation) {
|
|
3379
4154
|
const schemaStr = JSON.stringify(classDef);
|
|
3380
4155
|
if (schemaStr.includes('"#/$context/')) {
|
|
3381
|
-
return resolveViaDevProxy(
|
|
4156
|
+
return resolveViaDevProxy(def, state, key, base);
|
|
3382
4157
|
}
|
|
3383
4158
|
const schemaUrl = base ? new URL(src, base).href : new URL(src, location.href).href;
|
|
3384
4159
|
const implSrc = new URL(classDef.$implementation, schemaUrl).href;
|
|
3385
|
-
const exportName =
|
|
4160
|
+
const exportName = def.$export ?? classDef.title ?? def.$prototype;
|
|
3386
4161
|
try {
|
|
3387
|
-
return await importAndInstantiate(
|
|
4162
|
+
return await importAndInstantiate(def, implSrc, exportName, base);
|
|
3388
4163
|
} catch {
|
|
3389
|
-
return resolveViaDevProxy(
|
|
4164
|
+
return resolveViaDevProxy(def, state, key, base);
|
|
3390
4165
|
}
|
|
3391
4166
|
}
|
|
3392
4167
|
const DynClass = classFromSchema(classDef);
|
|
3393
4168
|
const config = {};
|
|
3394
|
-
for (const [k, v] of Object.entries(
|
|
4169
|
+
for (const [k, v] of Object.entries(def)) {
|
|
3395
4170
|
if (!EXTERNAL_RESERVED.has(k)) {
|
|
3396
4171
|
config[k] = v;
|
|
3397
4172
|
}
|
|
@@ -3478,9 +4253,9 @@ function classFromSchema(classDef) {
|
|
|
3478
4253
|
const dynCtor = DynClass;
|
|
3479
4254
|
return dynCtor;
|
|
3480
4255
|
}
|
|
3481
|
-
async function resolveViaDevProxy(
|
|
4256
|
+
async function resolveViaDevProxy(def, state, key, base) {
|
|
3482
4257
|
const config = {};
|
|
3483
|
-
for (const [k, v] of Object.entries(
|
|
4258
|
+
for (const [k, v] of Object.entries(def)) {
|
|
3484
4259
|
if (!EXTERNAL_RESERVED.has(k)) {
|
|
3485
4260
|
config[k] = v;
|
|
3486
4261
|
}
|
|
@@ -3489,9 +4264,9 @@ async function resolveViaDevProxy(def2, state, key, base) {
|
|
|
3489
4264
|
const doResolve = (resolvedConfig) => fetch(resolveProxyPath("/__jx_resolve__"), {
|
|
3490
4265
|
body: JSON.stringify({
|
|
3491
4266
|
$base: base,
|
|
3492
|
-
$export:
|
|
3493
|
-
$prototype:
|
|
3494
|
-
$src:
|
|
4267
|
+
$export: def.$export,
|
|
4268
|
+
$prototype: def.$prototype,
|
|
4269
|
+
$src: def.$src,
|
|
3495
4270
|
...resolvedConfig
|
|
3496
4271
|
}),
|
|
3497
4272
|
headers: { "Content-Type": "application/json" },
|
|
@@ -3520,12 +4295,15 @@ async function resolveViaDevProxy(def2, state, key, base) {
|
|
|
3520
4295
|
}
|
|
3521
4296
|
return s;
|
|
3522
4297
|
}
|
|
3523
|
-
async function resolveServerFunction(
|
|
3524
|
-
const src =
|
|
3525
|
-
const exportName =
|
|
4298
|
+
async function resolveServerFunction(def, state, key, base) {
|
|
4299
|
+
const src = def.$src;
|
|
4300
|
+
const exportName = def.$export;
|
|
3526
4301
|
let mod;
|
|
3527
|
-
|
|
3528
|
-
|
|
4302
|
+
const seeded = seededModule(src);
|
|
4303
|
+
if (seeded instanceof Promise) {
|
|
4304
|
+
mod = await seeded;
|
|
4305
|
+
} else if (seeded) {
|
|
4306
|
+
mod = seeded;
|
|
3529
4307
|
} else {
|
|
3530
4308
|
try {
|
|
3531
4309
|
mod = await import(src);
|
|
@@ -3535,10 +4313,10 @@ async function resolveServerFunction(def2, state, key, base) {
|
|
|
3535
4313
|
const resolvedSrc = new URL(src, base).href;
|
|
3536
4314
|
mod = await import(resolvedSrc);
|
|
3537
4315
|
} catch {
|
|
3538
|
-
return resolveServerFunctionViaProxy(
|
|
4316
|
+
return resolveServerFunctionViaProxy(def, state, key, base);
|
|
3539
4317
|
}
|
|
3540
4318
|
} else {
|
|
3541
|
-
return resolveServerFunctionViaProxy(
|
|
4319
|
+
return resolveServerFunctionViaProxy(def, state, key, base);
|
|
3542
4320
|
}
|
|
3543
4321
|
}
|
|
3544
4322
|
_moduleCache.set(src, mod);
|
|
@@ -3551,7 +4329,7 @@ async function resolveServerFunction(def2, state, key, base) {
|
|
|
3551
4329
|
throw new TypeError(`Jx: "${exportName}" from "${src}" is not a function`);
|
|
3552
4330
|
}
|
|
3553
4331
|
const fn = candidate;
|
|
3554
|
-
const rawArgs =
|
|
4332
|
+
const rawArgs = def.arguments ?? {};
|
|
3555
4333
|
const hasReactiveArg = Object.values(rawArgs).some((v) => isRefObj(v));
|
|
3556
4334
|
const resolveArgs = () => {
|
|
3557
4335
|
const args = {};
|
|
@@ -3574,8 +4352,8 @@ async function resolveServerFunction(def2, state, key, base) {
|
|
|
3574
4352
|
}
|
|
3575
4353
|
return s;
|
|
3576
4354
|
}
|
|
3577
|
-
async function resolveServerFunctionViaProxy(
|
|
3578
|
-
const rawArgs =
|
|
4355
|
+
async function resolveServerFunctionViaProxy(def, state, key, base) {
|
|
4356
|
+
const rawArgs = def.arguments ?? {};
|
|
3579
4357
|
const hasReactiveArg = Object.values(rawArgs).some((v) => isRefObj(v));
|
|
3580
4358
|
const resolveArgs = () => {
|
|
3581
4359
|
const args = {};
|
|
@@ -3587,8 +4365,8 @@ async function resolveServerFunctionViaProxy(def2, state, key, base) {
|
|
|
3587
4365
|
const doResolve = (args) => fetch(resolveProxyPath("/__jx_server__"), {
|
|
3588
4366
|
body: JSON.stringify({
|
|
3589
4367
|
$base: base,
|
|
3590
|
-
$export:
|
|
3591
|
-
$src:
|
|
4368
|
+
$export: def.$export,
|
|
4369
|
+
$src: def.$src,
|
|
3592
4370
|
arguments: args
|
|
3593
4371
|
}),
|
|
3594
4372
|
headers: { "Content-Type": "application/json" },
|
|
@@ -3619,8 +4397,8 @@ function resolveRef(refPath, state) {
|
|
|
3619
4397
|
if (typeof refPath !== "string") {
|
|
3620
4398
|
return refPath;
|
|
3621
4399
|
}
|
|
3622
|
-
if (refPath.startsWith("$map/")) {
|
|
3623
|
-
const parts = refPath.split("/");
|
|
4400
|
+
if (refPath.startsWith("$map/") || refPath.startsWith("#/$map/")) {
|
|
4401
|
+
const parts = (refPath.startsWith("#/") ? refPath.slice(2) : refPath).split("/");
|
|
3624
4402
|
const [, key] = parts;
|
|
3625
4403
|
const map = state.$map;
|
|
3626
4404
|
const base = map?.[key] ?? state[`$map/${key}`];
|
|
@@ -3646,12 +4424,41 @@ function isSignal(v) {
|
|
|
3646
4424
|
function isRefObj(v) {
|
|
3647
4425
|
return isRef2(v);
|
|
3648
4426
|
}
|
|
3649
|
-
function isNestedSelector(k) {
|
|
3650
|
-
return k.startsWith(":") || k.startsWith(".") || k.startsWith("&") || k.startsWith("[");
|
|
3651
|
-
}
|
|
3652
4427
|
function getPath2(obj, path) {
|
|
3653
4428
|
return readPath(obj, path);
|
|
3654
4429
|
}
|
|
4430
|
+
function absorbAttribute(state, name, value, defaults) {
|
|
4431
|
+
const camelKey = name.replaceAll(/-([a-z])/g, (_, c) => c.toUpperCase());
|
|
4432
|
+
const current = state[camelKey];
|
|
4433
|
+
if (typeof current === "boolean") {
|
|
4434
|
+
state[camelKey] = value !== null && value !== "false";
|
|
4435
|
+
return;
|
|
4436
|
+
}
|
|
4437
|
+
if (value === null) {
|
|
4438
|
+
const declared = defaults?.get(camelKey);
|
|
4439
|
+
state[camelKey] = declared === undefined ? typeof current === "number" ? 0 : "" : declared;
|
|
4440
|
+
return;
|
|
4441
|
+
}
|
|
4442
|
+
state[camelKey] = typeof current === "number" ? Number(value) : value;
|
|
4443
|
+
}
|
|
4444
|
+
function declaredDefaults(def) {
|
|
4445
|
+
const out = new Map;
|
|
4446
|
+
for (const [key, entry] of Object.entries(def.state ?? {})) {
|
|
4447
|
+
if (entry !== null && typeof entry === "object") {
|
|
4448
|
+
const obj = entry;
|
|
4449
|
+
if ("default" in obj) {
|
|
4450
|
+
out.set(key, obj["default"]);
|
|
4451
|
+
continue;
|
|
4452
|
+
}
|
|
4453
|
+
if (COMPUTED_STATE_KEYS.some((marker) => (marker in obj))) {
|
|
4454
|
+
continue;
|
|
4455
|
+
}
|
|
4456
|
+
}
|
|
4457
|
+
out.set(key, entry);
|
|
4458
|
+
}
|
|
4459
|
+
return out;
|
|
4460
|
+
}
|
|
4461
|
+
var COMPUTED_STATE_KEYS = ["$expression", "$prototype", "$ref", "$src"];
|
|
3655
4462
|
var _privatePropWarned = new Set;
|
|
3656
4463
|
function instanceSupplies(el, key) {
|
|
3657
4464
|
if (Object.hasOwn(el, key)) {
|
|
@@ -3677,9 +4484,9 @@ function refusePrivateProp(key, where) {
|
|
|
3677
4484
|
function _resetPrivatePropWarnings() {
|
|
3678
4485
|
_privatePropWarned.clear();
|
|
3679
4486
|
}
|
|
3680
|
-
function mergeProps(
|
|
4487
|
+
function mergeProps(def, parentState) {
|
|
3681
4488
|
const child = Object.create(parentState);
|
|
3682
|
-
for (const [k, v] of Object.entries(
|
|
4489
|
+
for (const [k, v] of Object.entries(def.$props ?? {})) {
|
|
3683
4490
|
if (refusePrivateProp(k, "$props")) {
|
|
3684
4491
|
continue;
|
|
3685
4492
|
}
|
|
@@ -3688,14 +4495,37 @@ function mergeProps(def2, parentState) {
|
|
|
3688
4495
|
return child;
|
|
3689
4496
|
}
|
|
3690
4497
|
function toCSSText(rules) {
|
|
3691
|
-
return Object.entries(rules).filter(([k, v]) => !
|
|
4498
|
+
return Object.entries(rules).filter(([k, v]) => !isNestedSelectorKey(k) && (v === null || typeof v !== "object")).map(([p, v]) => `${cssPropertyName(p)}: ${canvasStyleValue(String(v))}`).join("; ");
|
|
3692
4499
|
}
|
|
3693
4500
|
var _rootMedia = {};
|
|
3694
4501
|
var _elementDefs = new Map;
|
|
4502
|
+
function elementDefinition(tagName) {
|
|
4503
|
+
return _elementDefs.get(tagName);
|
|
4504
|
+
}
|
|
4505
|
+
async function redefineElement(doc, baseUrl) {
|
|
4506
|
+
const base = baseUrl ?? location.href;
|
|
4507
|
+
const { tagName } = doc;
|
|
4508
|
+
if (!tagName || !tagName.includes("-")) {
|
|
4509
|
+
throw new Error(`Jx redefineElement: tagName "${tagName}" must contain a hyphen`);
|
|
4510
|
+
}
|
|
4511
|
+
if (!customElements.get(tagName)) {
|
|
4512
|
+
await defineElement(doc, base);
|
|
4513
|
+
return;
|
|
4514
|
+
}
|
|
4515
|
+
if (doc.$elements) {
|
|
4516
|
+
await registerElements(doc.$elements, base);
|
|
4517
|
+
}
|
|
4518
|
+
const before = _elementDefs.get(tagName)?.doc.observedAttributes ?? [];
|
|
4519
|
+
const after = doc.observedAttributes ?? [];
|
|
4520
|
+
if (JSON.stringify(before) !== JSON.stringify(after)) {
|
|
4521
|
+
console.warn(`Jx redefineElement: <${tagName}> keeps observedAttributes [${before.join(", ")}] as first defined; [${after.join(", ")}] takes effect only in a fresh realm`);
|
|
4522
|
+
}
|
|
4523
|
+
_elementDefs.set(tagName, { base, doc });
|
|
4524
|
+
}
|
|
3695
4525
|
function setRootMedia(map) {
|
|
3696
4526
|
_rootMedia = map ?? {};
|
|
3697
4527
|
}
|
|
3698
|
-
async function registerElements(elements, base) {
|
|
4528
|
+
async function registerElements(elements, base, ctx) {
|
|
3699
4529
|
for (const entry of elements) {
|
|
3700
4530
|
if (typeof entry === "string") {
|
|
3701
4531
|
try {
|
|
@@ -3710,7 +4540,7 @@ async function registerElements(elements, base) {
|
|
|
3710
4540
|
continue;
|
|
3711
4541
|
}
|
|
3712
4542
|
const { href } = new URL(entry.$ref, base);
|
|
3713
|
-
const doc = await resolve(href);
|
|
4543
|
+
const doc = await resolve(href, ctx);
|
|
3714
4544
|
if (!doc.tagName || !doc.tagName.includes("-")) {
|
|
3715
4545
|
continue;
|
|
3716
4546
|
}
|
|
@@ -3718,7 +4548,7 @@ async function registerElements(elements, base) {
|
|
|
3718
4548
|
continue;
|
|
3719
4549
|
}
|
|
3720
4550
|
if (doc.$elements) {
|
|
3721
|
-
await registerElements(doc.$elements, href);
|
|
4551
|
+
await registerElements(doc.$elements, href, ctx);
|
|
3722
4552
|
}
|
|
3723
4553
|
await defineElement(doc, href);
|
|
3724
4554
|
}
|
|
@@ -3755,6 +4585,65 @@ function injectHead(entries, _base) {
|
|
|
3755
4585
|
document.head.append(el);
|
|
3756
4586
|
}
|
|
3757
4587
|
}
|
|
4588
|
+
var MAX_COMPONENT_NESTING = 32;
|
|
4589
|
+
var ROOT_INSTANCE_PATH = { expansion: 0, frames: [] };
|
|
4590
|
+
var _instancePath = ROOT_INSTANCE_PATH;
|
|
4591
|
+
function underInstancePath(path, fn) {
|
|
4592
|
+
const was = _instancePath;
|
|
4593
|
+
_instancePath = path;
|
|
4594
|
+
try {
|
|
4595
|
+
return fn();
|
|
4596
|
+
} finally {
|
|
4597
|
+
_instancePath = was;
|
|
4598
|
+
}
|
|
4599
|
+
}
|
|
4600
|
+
function reexpand(path) {
|
|
4601
|
+
return { expansion: path.frames.length, frames: path.frames };
|
|
4602
|
+
}
|
|
4603
|
+
function samePropValue(a, b) {
|
|
4604
|
+
if (Object.is(a, b)) {
|
|
4605
|
+
return true;
|
|
4606
|
+
}
|
|
4607
|
+
if (!isPlainData(a) || !isPlainData(b)) {
|
|
4608
|
+
return false;
|
|
4609
|
+
}
|
|
4610
|
+
try {
|
|
4611
|
+
return JSON.stringify(a) === JSON.stringify(b);
|
|
4612
|
+
} catch {
|
|
4613
|
+
return false;
|
|
4614
|
+
}
|
|
4615
|
+
}
|
|
4616
|
+
function isPlainData(value) {
|
|
4617
|
+
if (typeof value !== "object" || value === null) {
|
|
4618
|
+
return false;
|
|
4619
|
+
}
|
|
4620
|
+
const raw = toRaw(value);
|
|
4621
|
+
if (Array.isArray(raw)) {
|
|
4622
|
+
return true;
|
|
4623
|
+
}
|
|
4624
|
+
const proto = Object.getPrototypeOf(raw);
|
|
4625
|
+
return proto === Object.prototype || proto === null;
|
|
4626
|
+
}
|
|
4627
|
+
function sameFrame(a, b) {
|
|
4628
|
+
if (a.tag !== b.tag) {
|
|
4629
|
+
return false;
|
|
4630
|
+
}
|
|
4631
|
+
const keys = Object.keys(a.props);
|
|
4632
|
+
if (keys.length !== Object.keys(b.props).length) {
|
|
4633
|
+
return false;
|
|
4634
|
+
}
|
|
4635
|
+
return keys.every((key) => Object.hasOwn(b.props, key) && samePropValue(a.props[key], b.props[key]));
|
|
4636
|
+
}
|
|
4637
|
+
function extendInstancePath(path, frame) {
|
|
4638
|
+
const chain = [...path.frames.map((f) => f.tag), frame.tag].join(" → ");
|
|
4639
|
+
if (path.frames.slice(path.expansion).some((f) => sameFrame(f, frame))) {
|
|
4640
|
+
throw new Error(`Component <${frame.tag}> renders itself: ${chain}. A component cannot appear inside its own ` + `definition with the same props — the expansion would never end.`);
|
|
4641
|
+
}
|
|
4642
|
+
if (path.frames.length >= MAX_COMPONENT_NESTING) {
|
|
4643
|
+
throw new Error(`Component nesting exceeds ${MAX_COMPONENT_NESTING} levels: ${chain}. A component that renders itself with changing props needs a case that stops.`);
|
|
4644
|
+
}
|
|
4645
|
+
return { expansion: path.expansion, frames: [...path.frames, frame] };
|
|
4646
|
+
}
|
|
3758
4647
|
var _definedSources = new Set;
|
|
3759
4648
|
async function defineElement(source, baseUrl) {
|
|
3760
4649
|
let base = baseUrl;
|
|
@@ -3780,8 +4669,9 @@ async function defineElement(source, baseUrl) {
|
|
|
3780
4669
|
await registerElements(source_.$elements, base);
|
|
3781
4670
|
}
|
|
3782
4671
|
_elementDefs.set(tagName, { base, doc: source_ });
|
|
3783
|
-
const
|
|
3784
|
-
const
|
|
4672
|
+
const initialDef = source_;
|
|
4673
|
+
const initialBase = base;
|
|
4674
|
+
const observedAttrs = initialDef.observedAttributes ?? [];
|
|
3785
4675
|
const ElementClass = class extends HTMLElement {
|
|
3786
4676
|
_jxInitialized = false;
|
|
3787
4677
|
_state = null;
|
|
@@ -3796,7 +4686,18 @@ async function defineElement(source, baseUrl) {
|
|
|
3796
4686
|
return;
|
|
3797
4687
|
}
|
|
3798
4688
|
this._jxInitialized = true;
|
|
3799
|
-
const
|
|
4689
|
+
const enclosingPath = _instancePath;
|
|
4690
|
+
const supplied = {};
|
|
4691
|
+
const live = _elementDefs.get(tagName) ?? { base: initialBase, doc: initialDef };
|
|
4692
|
+
const def = live.doc;
|
|
4693
|
+
const defBase = live.base;
|
|
4694
|
+
const state = await buildScope(def, {}, defBase, { base: defBase, media: null, root: this });
|
|
4695
|
+
for (const attr of observedAttrs) {
|
|
4696
|
+
if (this.hasAttribute(attr)) {
|
|
4697
|
+
absorbAttribute(state, attr, this.getAttribute(attr));
|
|
4698
|
+
supplied[attr] = this.getAttribute(attr);
|
|
4699
|
+
}
|
|
4700
|
+
}
|
|
3800
4701
|
const propsAttr = this.dataset.jxProps;
|
|
3801
4702
|
if (propsAttr) {
|
|
3802
4703
|
try {
|
|
@@ -3805,8 +4706,9 @@ async function defineElement(source, baseUrl) {
|
|
|
3805
4706
|
if (refusePrivateProp(key, "data-jx-props")) {
|
|
3806
4707
|
continue;
|
|
3807
4708
|
}
|
|
3808
|
-
if (key in (
|
|
4709
|
+
if (key in (def.state ?? {})) {
|
|
3809
4710
|
state[key] = val;
|
|
4711
|
+
supplied[key] = val;
|
|
3810
4712
|
}
|
|
3811
4713
|
}
|
|
3812
4714
|
} catch {}
|
|
@@ -3819,20 +4721,39 @@ async function defineElement(source, baseUrl) {
|
|
|
3819
4721
|
this.removeAttribute(name);
|
|
3820
4722
|
continue;
|
|
3821
4723
|
}
|
|
3822
|
-
if (key in (
|
|
4724
|
+
if (key in (def.state ?? {})) {
|
|
3823
4725
|
state[key] = this.getAttribute(name);
|
|
4726
|
+
supplied[key] = this.getAttribute(name);
|
|
3824
4727
|
this.removeAttribute(name);
|
|
3825
4728
|
}
|
|
3826
4729
|
}
|
|
3827
|
-
for (const key of Object.keys(
|
|
4730
|
+
for (const key of Object.keys(def.state ?? {})) {
|
|
3828
4731
|
if (isPrivateStateKey(key)) {
|
|
3829
4732
|
continue;
|
|
3830
4733
|
}
|
|
3831
4734
|
if (key in this && this[key] !== undefined && instanceSupplies(this, key)) {
|
|
3832
4735
|
state[key] = this[key];
|
|
4736
|
+
supplied[key] = this[key];
|
|
3833
4737
|
}
|
|
3834
4738
|
}
|
|
3835
|
-
|
|
4739
|
+
let ownPath;
|
|
4740
|
+
try {
|
|
4741
|
+
ownPath = extendInstancePath(enclosingPath, { props: supplied, tag: tagName });
|
|
4742
|
+
} catch (error) {
|
|
4743
|
+
this.replaceChildren();
|
|
4744
|
+
if (!this.isConnected) {
|
|
4745
|
+
return;
|
|
4746
|
+
}
|
|
4747
|
+
console.error(`Jx: <${tagName}> was not rendered:`, error);
|
|
4748
|
+
this.dispatchEvent(new ErrorEvent("jx-error", {
|
|
4749
|
+
bubbles: true,
|
|
4750
|
+
composed: true,
|
|
4751
|
+
error,
|
|
4752
|
+
message: error instanceof Error ? error.message : String(error)
|
|
4753
|
+
}));
|
|
4754
|
+
return;
|
|
4755
|
+
}
|
|
4756
|
+
for (const key of Object.keys(def.state ?? {})) {
|
|
3836
4757
|
if (isPrivateStateKey(key)) {
|
|
3837
4758
|
continue;
|
|
3838
4759
|
}
|
|
@@ -3849,22 +4770,30 @@ async function defineElement(source, baseUrl) {
|
|
|
3849
4770
|
this._state = state;
|
|
3850
4771
|
const slottedChildren = [...this.childNodes];
|
|
3851
4772
|
this.replaceChildren();
|
|
3852
|
-
|
|
3853
|
-
|
|
3854
|
-
}
|
|
3855
|
-
|
|
3856
|
-
|
|
3857
|
-
if (!Array.isArray(
|
|
3858
|
-
bindProperty(this, "textContent",
|
|
3859
|
-
}
|
|
3860
|
-
const children = Array.isArray(
|
|
3861
|
-
|
|
3862
|
-
|
|
4773
|
+
const defStyle = declaresDisplay(def.style) ? def.style : { display: "block", ...def.style };
|
|
4774
|
+
const hostStyle = mergeStyle(defStyle, callSiteStyles.get(this));
|
|
4775
|
+
applyStyle(this, hostStyle, state["$media"] ?? {}, state);
|
|
4776
|
+
applyAttributes(this, def.attributes ?? {}, state);
|
|
4777
|
+
bindDefinitionHandlers(this, def, state);
|
|
4778
|
+
if (!Array.isArray(def.children) && def.textContent !== undefined) {
|
|
4779
|
+
bindProperty(this, "textContent", def.textContent, state);
|
|
4780
|
+
}
|
|
4781
|
+
const children = Array.isArray(def.children) ? def.children : [];
|
|
4782
|
+
const wasInside = _canvasInsideStampedHost;
|
|
4783
|
+
_canvasInsideStampedHost ||= this.dataset.jxPath !== undefined;
|
|
4784
|
+
try {
|
|
4785
|
+
underInstancePath(ownPath, () => {
|
|
4786
|
+
for (const childDef of children) {
|
|
4787
|
+
this.append(renderNode(childDef, state));
|
|
4788
|
+
}
|
|
4789
|
+
});
|
|
4790
|
+
} finally {
|
|
4791
|
+
_canvasInsideStampedHost = wasInside;
|
|
3863
4792
|
}
|
|
3864
4793
|
distributeSlots(this, slottedChildren);
|
|
3865
4794
|
const { onMount } = state;
|
|
3866
4795
|
if (typeof onMount === "function") {
|
|
3867
|
-
queueMicrotask(() => onMount(state));
|
|
4796
|
+
queueMicrotask(() => onMount(state, this));
|
|
3868
4797
|
}
|
|
3869
4798
|
}
|
|
3870
4799
|
disconnectedCallback() {
|
|
@@ -3881,25 +4810,17 @@ async function defineElement(source, baseUrl) {
|
|
|
3881
4810
|
if (!this._state || oldVal === newVal) {
|
|
3882
4811
|
return;
|
|
3883
4812
|
}
|
|
3884
|
-
|
|
3885
|
-
const current = this._state[camelKey];
|
|
3886
|
-
if (typeof current === "number") {
|
|
3887
|
-
this._state[camelKey] = Number(newVal);
|
|
3888
|
-
} else if (typeof current === "boolean") {
|
|
3889
|
-
this._state[camelKey] = newVal !== null && newVal !== "false";
|
|
3890
|
-
} else {
|
|
3891
|
-
this._state[camelKey] = newVal;
|
|
3892
|
-
}
|
|
4813
|
+
absorbAttribute(this._state, name, newVal, declaredDefaults(_elementDefs.get(tagName)?.doc ?? initialDef));
|
|
3893
4814
|
}
|
|
3894
4815
|
};
|
|
3895
4816
|
customElements.define(tagName, ElementClass);
|
|
3896
4817
|
}
|
|
3897
|
-
function renderCustomElementWithProps(
|
|
3898
|
-
const el = document.createElement(resolveTagName(
|
|
4818
|
+
function renderCustomElementWithProps(def, state, options, path) {
|
|
4819
|
+
const el = document.createElement(resolveTagName(def.tagName, state));
|
|
3899
4820
|
if (options?.onNodeCreated) {
|
|
3900
|
-
options.onNodeCreated(el, path ?? [],
|
|
4821
|
+
options.onNodeCreated(el, path ?? [], def, state);
|
|
3901
4822
|
}
|
|
3902
|
-
for (const [key, val] of Object.entries(
|
|
4823
|
+
for (const [key, val] of Object.entries(def.$props ?? {})) {
|
|
3903
4824
|
if (refusePrivateProp(key, "$props")) {
|
|
3904
4825
|
continue;
|
|
3905
4826
|
}
|
|
@@ -3920,19 +4841,25 @@ function renderCustomElementWithProps(def2, state, options, path) {
|
|
|
3920
4841
|
write(val);
|
|
3921
4842
|
}
|
|
3922
4843
|
}
|
|
3923
|
-
|
|
3924
|
-
|
|
3925
|
-
|
|
4844
|
+
if (def.style) {
|
|
4845
|
+
callSiteStyles.set(el, def.style);
|
|
4846
|
+
}
|
|
4847
|
+
applyStyle(el, def.style ?? {}, state["$media"] ?? {}, state);
|
|
4848
|
+
applyAttributes(el, def.attributes ?? {}, state);
|
|
4849
|
+
applyProperties(el, def, state);
|
|
4850
|
+
const children = Array.isArray(def.children) ? def.children : [];
|
|
3926
4851
|
for (let i = 0;i < children.length; i++) {
|
|
4852
|
+
const child = children[i];
|
|
3927
4853
|
const childOpts = options && path ? { ...options, _path: [...path, "children", i] } : undefined;
|
|
3928
|
-
|
|
4854
|
+
if (isMappedArray(child)) {
|
|
4855
|
+
renderMappedArrayInto(el, child, state, childOpts);
|
|
4856
|
+
} else {
|
|
4857
|
+
el.append(renderNode(child, state, childOpts));
|
|
4858
|
+
}
|
|
3929
4859
|
}
|
|
3930
4860
|
return el;
|
|
3931
4861
|
}
|
|
3932
4862
|
function distributeSlots(host, slottedChildren) {
|
|
3933
|
-
if (slottedChildren.length === 0) {
|
|
3934
|
-
return;
|
|
3935
|
-
}
|
|
3936
4863
|
const slots = host.querySelectorAll("slot");
|
|
3937
4864
|
if (slots.length === 0) {
|
|
3938
4865
|
return;
|
|
@@ -3953,37 +4880,49 @@ function distributeSlots(host, slottedChildren) {
|
|
|
3953
4880
|
for (const slot of slots) {
|
|
3954
4881
|
const name = slot.getAttribute("name");
|
|
3955
4882
|
const matches = name ? named.get(name) ?? [] : unnamed;
|
|
3956
|
-
|
|
3957
|
-
slot.replaceChildren();
|
|
3958
|
-
for (const child of matches) {
|
|
3959
|
-
slot.append(child);
|
|
3960
|
-
}
|
|
3961
|
-
}
|
|
4883
|
+
slot.replaceWith(...matches.length > 0 ? matches : [...slot.childNodes]);
|
|
3962
4884
|
}
|
|
3963
4885
|
}
|
|
3964
4886
|
export {
|
|
3965
4887
|
COLOR_SCHEME_ATTR,
|
|
3966
4888
|
COLOR_SCHEME_STORAGE_KEY,
|
|
3967
4889
|
Jx,
|
|
4890
|
+
MAX_COMPONENT_NESTING,
|
|
3968
4891
|
RESERVED_KEYS,
|
|
3969
4892
|
SUPPORTED_SCHEMA_VERSION,
|
|
3970
4893
|
_resetPrivatePropWarnings,
|
|
3971
4894
|
applyStyle,
|
|
3972
4895
|
booleanAttrValue,
|
|
3973
4896
|
buildScope,
|
|
4897
|
+
buildStyleRules,
|
|
3974
4898
|
camelToKebab,
|
|
3975
4899
|
canvasStyleValue,
|
|
4900
|
+
cssPropertyName,
|
|
4901
|
+
cssRuleText,
|
|
3976
4902
|
defineElement,
|
|
3977
|
-
|
|
4903
|
+
documentStyleText,
|
|
4904
|
+
elementDefinition,
|
|
4905
|
+
enumeratedAttrNames,
|
|
3978
4906
|
hasSchemaKeywords,
|
|
4907
|
+
hashCss,
|
|
4908
|
+
isDeclarationAtRule,
|
|
4909
|
+
isKeyframesAtRule,
|
|
4910
|
+
isNestedSelectorKey,
|
|
3979
4911
|
isSignal,
|
|
3980
4912
|
isSingleExpression,
|
|
4913
|
+
mount,
|
|
3981
4914
|
observeScope,
|
|
4915
|
+
preloadDocument,
|
|
4916
|
+
preloadModule,
|
|
3982
4917
|
pureSchemeOf,
|
|
3983
4918
|
reapplyStyle,
|
|
4919
|
+
redefineElement,
|
|
4920
|
+
releaseElementStyles,
|
|
3984
4921
|
renderNode,
|
|
4922
|
+
resetDocumentStyles,
|
|
3985
4923
|
resolve,
|
|
3986
4924
|
resolveAtQuery,
|
|
4925
|
+
resolveNestedSelector,
|
|
3987
4926
|
resolvePrototype,
|
|
3988
4927
|
resolveRef,
|
|
3989
4928
|
resolveTagName,
|
|
@@ -3991,6 +4930,8 @@ export {
|
|
|
3991
4930
|
schemeSelectors,
|
|
3992
4931
|
setCanvasAssetResolver,
|
|
3993
4932
|
setCanvasDelinkAnchors,
|
|
4933
|
+
setCanvasDelinkCommands,
|
|
4934
|
+
setCanvasDelinkPopovers,
|
|
3994
4935
|
setCanvasViewportTranspose,
|
|
3995
4936
|
setResolveToken,
|
|
3996
4937
|
setRootMedia,
|
|
@@ -3998,9 +4939,12 @@ export {
|
|
|
3998
4939
|
setSkipContentResolution,
|
|
3999
4940
|
setSkipServerFunctions,
|
|
4000
4941
|
setStampPropBindings,
|
|
4942
|
+
splitSelectorList,
|
|
4001
4943
|
toCSSText,
|
|
4944
|
+
transposeCanvasOverlaySelector,
|
|
4945
|
+
transposeCanvasPopoverSelector,
|
|
4002
4946
|
transposeCanvasUnits
|
|
4003
4947
|
};
|
|
4004
4948
|
|
|
4005
|
-
//# debugId=
|
|
4949
|
+
//# debugId=52C255A4DA099CA964756E2164756E21
|
|
4006
4950
|
//# sourceMappingURL=runtime.js.map
|