sibujs 4.0.1 → 4.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +29 -1
- package/dist/browser.cjs +21 -22
- package/dist/browser.js +6 -6
- package/dist/build.cjs +363 -110
- package/dist/build.js +15 -15
- package/dist/cdn.dev.global.js +398 -0
- package/dist/cdn.global.js +10 -10
- package/dist/{chunk-AD5YSZAN.js → chunk-2LOYNGBY.js} +2 -2
- package/dist/{chunk-VPP2FONR.js → chunk-2WLZ6757.js} +17 -10
- package/dist/{chunk-UNAYBND2.js → chunk-3VTSPNC5.js} +2 -2
- package/dist/{chunk-TIRZCERI.js → chunk-5DXA2J44.js} +1 -1
- package/dist/{chunk-QD4I7ZGZ.js → chunk-6ZGI3RBE.js} +149 -33
- package/dist/{chunk-JYXQCELN.js → chunk-7ALC7KGE.js} +13 -7
- package/dist/{chunk-XDOMTQHM.js → chunk-7VEC3UD2.js} +3 -3
- package/dist/{chunk-PTLJ7NQX.js → chunk-BMYYZWHX.js} +3 -3
- package/dist/{chunk-PHB3MCK4.js → chunk-BNKV4REK.js} +7 -8
- package/dist/{chunk-XET2RUJF.js → chunk-FOWBJZDL.js} +7 -8
- package/dist/{chunk-5BVKQX2F.js → chunk-GDUNQCCW.js} +4 -4
- package/dist/{chunk-TVURNWDK.js → chunk-HECVW343.js} +20 -9
- package/dist/{chunk-PHRH66Y7.js → chunk-HJEPKZ2O.js} +7 -8
- package/dist/{chunk-PJDSI2K7.js → chunk-HZEBO22J.js} +125 -42
- package/dist/{chunk-5INI7D2L.js → chunk-IXKSNWV5.js} +74 -11
- package/dist/{chunk-IKVUUE7D.js → chunk-KE4KWRDY.js} +3 -3
- package/dist/{chunk-AW6HPJ3L.js → chunk-KKLW7YWL.js} +1 -1
- package/dist/{chunk-XZMCVZW6.js → chunk-NEYWS4EX.js} +6 -6
- package/dist/{chunk-HYCCIYNS.js → chunk-NIOYEGBQ.js} +13 -14
- package/dist/{chunk-YLV26GAJ.js → chunk-OUWAIXIK.js} +3 -3
- package/dist/{chunk-E72G5JSK.js → chunk-P3DHXBR6.js} +1 -1
- package/dist/{chunk-J4WZMCIW.js → chunk-QCFLDD7C.js} +5 -5
- package/dist/{chunk-DHDZ7IVN.js → chunk-QKRPLZ2V.js} +7 -8
- package/dist/{chunk-52ERIVFD.js → chunk-QL4UREZO.js} +6 -6
- package/dist/{chunk-TNEHT3NG.js → chunk-SF3TB4K6.js} +8 -8
- package/dist/{chunk-HPXTUPJD.js → chunk-XZ2N525U.js} +6 -6
- package/dist/{customElement-CKLoO63w.d.ts → customElement-CNZxEB9G.d.cts} +77 -0
- package/dist/{customElement-CKLoO63w.d.cts → customElement-CNZxEB9G.d.ts} +77 -0
- package/dist/data.cjs +23 -25
- package/dist/data.js +9 -9
- package/dist/devtools.cjs +26 -23
- package/dist/devtools.d.cts +1 -1
- package/dist/devtools.d.ts +1 -1
- package/dist/devtools.js +8 -8
- package/dist/{dispose-4FZ6OFXR.js → dispose-46BOMMQJ.js} +2 -2
- package/dist/ecosystem.cjs +230 -68
- package/dist/ecosystem.js +11 -11
- package/dist/extras.cjs +251 -87
- package/dist/extras.d.cts +2 -2
- package/dist/extras.d.ts +2 -2
- package/dist/extras.js +25 -25
- package/dist/index.cjs +358 -104
- package/dist/index.d.cts +287 -34
- package/dist/index.d.ts +287 -34
- package/dist/index.js +17 -15
- package/dist/{introspect-RjLfIFpL.d.cts → introspect-D5xF-0Es.d.cts} +7 -0
- package/dist/{introspect-DOZfmC-4.d.ts → introspect-rSBIxEQi.d.ts} +7 -0
- package/dist/motion.cjs +21 -23
- package/dist/motion.js +5 -5
- package/dist/patterns.cjs +24 -25
- package/dist/patterns.d.cts +8 -0
- package/dist/patterns.d.ts +8 -0
- package/dist/patterns.js +7 -7
- package/dist/performance.cjs +24 -28
- package/dist/performance.js +9 -9
- package/dist/plugins.cjs +268 -87
- package/dist/plugins.d.cts +92 -0
- package/dist/plugins.d.ts +92 -0
- package/dist/plugins.js +18 -17
- package/dist/{ssr-JFP5535P.js → ssr-Y7XOEPEN.js} +5 -5
- package/dist/ssr.cjs +241 -80
- package/dist/ssr.js +12 -12
- package/dist/testing.cjs +19 -20
- package/dist/testing.js +5 -5
- package/dist/ui.cjs +106 -44
- package/dist/ui.d.cts +7 -1
- package/dist/ui.d.ts +7 -1
- package/dist/ui.js +10 -10
- package/dist/widgets.cjs +21 -22
- package/dist/widgets.d.cts +8 -0
- package/dist/widgets.d.ts +8 -0
- package/dist/widgets.js +9 -9
- package/package.json +11 -2
package/dist/build.cjs
CHANGED
|
@@ -161,15 +161,15 @@ function parseTemplateLiteral(code2, openBacktick) {
|
|
|
161
161
|
return null;
|
|
162
162
|
}
|
|
163
163
|
function skipString(code2, start) {
|
|
164
|
-
const
|
|
164
|
+
const quote2 = code2[start];
|
|
165
165
|
let pos = start + 1;
|
|
166
166
|
while (pos < code2.length) {
|
|
167
167
|
if (code2[pos] === "\\") {
|
|
168
168
|
pos += 2;
|
|
169
169
|
continue;
|
|
170
170
|
}
|
|
171
|
-
if (code2[pos] ===
|
|
172
|
-
if (
|
|
171
|
+
if (code2[pos] === quote2) return pos + 1;
|
|
172
|
+
if (quote2 === "`" && code2[pos] === "$" && code2[pos + 1] === "{") {
|
|
173
173
|
pos += 2;
|
|
174
174
|
let depth = 1;
|
|
175
175
|
while (pos < code2.length && depth > 0) {
|
|
@@ -225,12 +225,12 @@ function parseTemplateToAST(strings) {
|
|
|
225
225
|
skipWs();
|
|
226
226
|
const exprIdx = tryExprIdx();
|
|
227
227
|
if (exprIdx >= 0) return { kind: "expr", index: exprIdx };
|
|
228
|
-
const
|
|
229
|
-
if (
|
|
228
|
+
const quote2 = template2[pos];
|
|
229
|
+
if (quote2 === '"' || quote2 === "'") {
|
|
230
230
|
pos++;
|
|
231
231
|
const parts = [];
|
|
232
232
|
let current = "";
|
|
233
|
-
while (pos < len && template2[pos] !==
|
|
233
|
+
while (pos < len && template2[pos] !== quote2) {
|
|
234
234
|
const innerIdx = tryExprIdx();
|
|
235
235
|
if (innerIdx >= 0) {
|
|
236
236
|
if (current) parts.push({ kind: "static", value: current });
|
|
@@ -1132,6 +1132,7 @@ __export(index_exports, {
|
|
|
1132
1132
|
enhance: () => enhance,
|
|
1133
1133
|
enhanceAll: () => enhanceAll,
|
|
1134
1134
|
enqueueBatchedSignal: () => enqueueBatchedSignal,
|
|
1135
|
+
external: () => external,
|
|
1135
1136
|
fieldset: () => fieldset,
|
|
1136
1137
|
figcaption: () => figcaption,
|
|
1137
1138
|
figure: () => figure,
|
|
@@ -1381,23 +1382,28 @@ function reportError(error, context2) {
|
|
|
1381
1382
|
}
|
|
1382
1383
|
|
|
1383
1384
|
// src/core/dev.ts
|
|
1385
|
+
var DEV = typeof __SIBU_DEV__ !== "undefined" ? !!__SIBU_DEV__ : typeof globalThis.__SIBU_DEV__ !== "undefined" ? !!globalThis.__SIBU_DEV__ : (
|
|
1386
|
+
// safe default: off in browser, on in test/dev Node
|
|
1387
|
+
typeof process !== "undefined" && process.env?.NODE_ENV !== "production"
|
|
1388
|
+
);
|
|
1384
1389
|
function isDev() {
|
|
1385
|
-
|
|
1386
|
-
|
|
1387
|
-
|
|
1388
|
-
// this branch is unreachable here.
|
|
1389
|
-
/* v8 ignore next 2 */
|
|
1390
|
-
typeof __SIBU_DEV__ !== "undefined" ? __SIBU_DEV__ : typeof process !== "undefined" && process.env?.NODE_ENV !== "production"
|
|
1391
|
-
);
|
|
1390
|
+
if (typeof globalThis.__SIBU_DEV__ !== "undefined") return !!globalThis.__SIBU_DEV__;
|
|
1391
|
+
if (typeof __SIBU_DEV__ !== "undefined") return !!__SIBU_DEV__;
|
|
1392
|
+
return typeof process !== "undefined" && process.env?.NODE_ENV !== "production";
|
|
1392
1393
|
}
|
|
1393
|
-
var _isDev = isDev();
|
|
1394
1394
|
function devAssert(condition, message) {
|
|
1395
|
-
if (
|
|
1395
|
+
if ((typeof __SIBU_DEV__ !== "undefined" ? __SIBU_DEV__ : DEV) && !condition) {
|
|
1396
1396
|
throw new Error(`[SibuJS] ${message}`);
|
|
1397
1397
|
}
|
|
1398
1398
|
}
|
|
1399
|
+
function devWarnLazy(build) {
|
|
1400
|
+
if (typeof __SIBU_DEV__ !== "undefined" ? __SIBU_DEV__ : DEV) {
|
|
1401
|
+
const message = build();
|
|
1402
|
+
if (message) console.warn(`[SibuJS] ${message}`);
|
|
1403
|
+
}
|
|
1404
|
+
}
|
|
1399
1405
|
function devWarn(message) {
|
|
1400
|
-
if (
|
|
1406
|
+
if (typeof __SIBU_DEV__ !== "undefined" ? __SIBU_DEV__ : DEV) {
|
|
1401
1407
|
console.warn(`[SibuJS] ${message}`);
|
|
1402
1408
|
}
|
|
1403
1409
|
}
|
|
@@ -1412,7 +1418,6 @@ function reportDrainRunaway(label2, executed, remaining) {
|
|
|
1412
1418
|
{ executed, remaining }
|
|
1413
1419
|
);
|
|
1414
1420
|
}
|
|
1415
|
-
var _isDev2 = isDev();
|
|
1416
1421
|
var activeBindingCount = 0;
|
|
1417
1422
|
function registerDisposer(node, teardown) {
|
|
1418
1423
|
let disposers = elementDisposers.get(node);
|
|
@@ -1421,7 +1426,7 @@ function registerDisposer(node, teardown) {
|
|
|
1421
1426
|
elementDisposers.set(node, disposers);
|
|
1422
1427
|
}
|
|
1423
1428
|
disposers.push(teardown);
|
|
1424
|
-
if (
|
|
1429
|
+
if (DEV) activeBindingCount++;
|
|
1425
1430
|
}
|
|
1426
1431
|
function unregisterDisposer(node, teardown) {
|
|
1427
1432
|
const disposers = elementDisposers.get(node);
|
|
@@ -1429,7 +1434,7 @@ function unregisterDisposer(node, teardown) {
|
|
|
1429
1434
|
const index = disposers.indexOf(teardown);
|
|
1430
1435
|
if (index === -1) return;
|
|
1431
1436
|
disposers.splice(index, 1);
|
|
1432
|
-
if (
|
|
1437
|
+
if (DEV) activeBindingCount--;
|
|
1433
1438
|
if (disposers.length === 0) elementDisposers.delete(node);
|
|
1434
1439
|
}
|
|
1435
1440
|
function dispose(node) {
|
|
@@ -1453,13 +1458,13 @@ function dispose(node) {
|
|
|
1453
1458
|
if (!pending || pending.length === 0) break;
|
|
1454
1459
|
const snapshot = pending.slice();
|
|
1455
1460
|
elementDisposers.delete(current);
|
|
1456
|
-
if (
|
|
1461
|
+
if (DEV) activeBindingCount -= snapshot.length;
|
|
1457
1462
|
for (let i3 = 0; i3 < snapshot.length; i3++) {
|
|
1458
1463
|
if (executed >= MAX_DRAIN_TEARDOWNS) {
|
|
1459
1464
|
const rest = snapshot.slice(i3);
|
|
1460
1465
|
const added = elementDisposers.get(current);
|
|
1461
1466
|
elementDisposers.set(current, added ? rest.concat(added) : rest);
|
|
1462
|
-
if (
|
|
1467
|
+
if (DEV) activeBindingCount += rest.length;
|
|
1463
1468
|
reportDrainRunaway("dispose", executed, rest.length + (added?.length ?? 0));
|
|
1464
1469
|
runaway = true;
|
|
1465
1470
|
break;
|
|
@@ -1487,7 +1492,7 @@ function replaceChildrenSafely(parent, ...next) {
|
|
|
1487
1492
|
parent.replaceChildren(...next);
|
|
1488
1493
|
}
|
|
1489
1494
|
function checkLeaks(warnThreshold = 0) {
|
|
1490
|
-
if (!
|
|
1495
|
+
if (!DEV) return 0;
|
|
1491
1496
|
if (warnThreshold > 0 && activeBindingCount > warnThreshold) {
|
|
1492
1497
|
devWarn(
|
|
1493
1498
|
`checkLeaks: ${activeBindingCount} active DOM bindings detected. Expected \u2264${warnThreshold}. This may indicate a component was removed from the DOM without calling dispose().`
|
|
@@ -1589,20 +1594,75 @@ function decodeCssEscapes(value) {
|
|
|
1589
1594
|
}
|
|
1590
1595
|
return out;
|
|
1591
1596
|
}
|
|
1592
|
-
|
|
1593
|
-
|
|
1597
|
+
var BLOCKED_CSS_NEEDLES = [
|
|
1598
|
+
"url(",
|
|
1599
|
+
"expression(",
|
|
1600
|
+
"javascript:",
|
|
1601
|
+
"vbscript:",
|
|
1602
|
+
"-moz-binding",
|
|
1603
|
+
"behavior:",
|
|
1604
|
+
"@import",
|
|
1605
|
+
"image-set(",
|
|
1606
|
+
"filter:progid"
|
|
1607
|
+
];
|
|
1608
|
+
function describeElement(el) {
|
|
1609
|
+
if (!el) return "an element";
|
|
1610
|
+
let out = el.tagName.toLowerCase();
|
|
1611
|
+
const id = el.getAttribute("id");
|
|
1612
|
+
if (id) out += `#${id}`;
|
|
1613
|
+
const cls = el.getAttribute("class");
|
|
1614
|
+
if (cls) out += `.${cls.trim().split(/\s+/).slice(0, 3).join(".")}`;
|
|
1615
|
+
return `<${out}>`;
|
|
1616
|
+
}
|
|
1617
|
+
var warnedDeclarations = /* @__PURE__ */ new Set();
|
|
1618
|
+
var MAX_WARNED_DECLARATIONS = 100;
|
|
1619
|
+
var declarationCapAnnounced = false;
|
|
1620
|
+
function warnDroppedDeclaration(value, reason, ctx) {
|
|
1621
|
+
devWarnLazy(() => {
|
|
1622
|
+
const reasons = [
|
|
1623
|
+
"url() in an inline style is an exfiltration channel: the browser fetches it immediately and the URL's path or query can carry page data off-origin",
|
|
1624
|
+
"expression() executes arbitrary script in legacy engines",
|
|
1625
|
+
"the javascript: scheme executes script",
|
|
1626
|
+
"the vbscript: scheme executes script",
|
|
1627
|
+
"-moz-binding loads and runs remote XBL",
|
|
1628
|
+
"behavior: loads and runs a remote HTC script",
|
|
1629
|
+
"@import pulls in a remote stylesheet",
|
|
1630
|
+
"image-set() fetches remote images, the same exfiltration channel as url()",
|
|
1631
|
+
"filter:progid activates legacy scriptable filters"
|
|
1632
|
+
];
|
|
1633
|
+
const declaration = ctx?.property ? `${ctx.property}: ${value}` : value;
|
|
1634
|
+
const where = describeElement(ctx?.element);
|
|
1635
|
+
const key = `${where}|${declaration}`;
|
|
1636
|
+
if (warnedDeclarations.has(key)) return "";
|
|
1637
|
+
if (warnedDeclarations.size >= MAX_WARNED_DECLARATIONS) {
|
|
1638
|
+
if (declarationCapAnnounced) return "";
|
|
1639
|
+
declarationCapAnnounced = true;
|
|
1640
|
+
return `${MAX_WARNED_DECLARATIONS} distinct dropped style declarations have been reported; suppressing further ones for the rest of this session so they cannot flood the console. The declarations are still dropped \u2014 only the reporting stops. Fix the reported ones and reload to see any that remain.`;
|
|
1641
|
+
}
|
|
1642
|
+
warnedDeclarations.add(key);
|
|
1643
|
+
return `style declaration "${declaration}" was dropped by the style sanitizer on ${where} \u2014 ${reasons[reason]}. The element renders without it, which usually looks like a missing image rather than an error. Sanctioned alternatives: for a content image use an <img> element (or a <picture>); for decoration, put the rule in a stylesheet and set a class instead \u2014 stylesheet CSS is not sanitized, only inline style attributes are. If this declaration is not yours, it came from untrusted data and the drop just prevented an exfiltration.`;
|
|
1644
|
+
});
|
|
1645
|
+
}
|
|
1646
|
+
function blockedCssReason(value) {
|
|
1647
|
+
if (!CSS_DANGER_GATE.test(value)) return -1;
|
|
1594
1648
|
const normalized = value.includes("\\") ? decodeCssEscapes(value) : value;
|
|
1595
1649
|
const lower = normalized.toLowerCase().replace(/\s+/g, "");
|
|
1596
|
-
|
|
1597
|
-
return
|
|
1650
|
+
for (let i2 = 0; i2 < BLOCKED_CSS_NEEDLES.length; i2++) {
|
|
1651
|
+
if (lower.includes(BLOCKED_CSS_NEEDLES[i2])) return i2;
|
|
1598
1652
|
}
|
|
1599
|
-
return
|
|
1653
|
+
return -1;
|
|
1600
1654
|
}
|
|
1601
|
-
function
|
|
1655
|
+
function sanitizeCSSValue(value, context2) {
|
|
1656
|
+
const reason = blockedCssReason(value);
|
|
1657
|
+
if (reason === -1) return value;
|
|
1658
|
+
warnDroppedDeclaration(value, reason, context2);
|
|
1659
|
+
return "";
|
|
1660
|
+
}
|
|
1661
|
+
function sanitizeStyleAttribute(cssText, context2) {
|
|
1602
1662
|
const input2 = String(cssText);
|
|
1603
1663
|
if (input2.trim() === "") return "";
|
|
1604
1664
|
if (typeof document === "undefined") {
|
|
1605
|
-
return sanitizeCSSValue(input2) === "" ? "" : input2;
|
|
1665
|
+
return sanitizeCSSValue(input2, context2) === "" ? "" : input2;
|
|
1606
1666
|
}
|
|
1607
1667
|
const probe = document.createElement("div");
|
|
1608
1668
|
try {
|
|
@@ -1614,8 +1674,12 @@ function sanitizeStyleAttribute(cssText) {
|
|
|
1614
1674
|
for (let i2 = 0; i2 < probe.style.length; i2++) {
|
|
1615
1675
|
const property = probe.style[i2];
|
|
1616
1676
|
const value = probe.style.getPropertyValue(property);
|
|
1617
|
-
|
|
1618
|
-
if (
|
|
1677
|
+
let reason = blockedCssReason(value);
|
|
1678
|
+
if (reason === -1) reason = blockedCssReason(`${property}:${value}`);
|
|
1679
|
+
if (reason !== -1) {
|
|
1680
|
+
warnDroppedDeclaration(value, reason, { property, element: context2?.element });
|
|
1681
|
+
continue;
|
|
1682
|
+
}
|
|
1619
1683
|
const priority = probe.style.getPropertyPriority(property);
|
|
1620
1684
|
declarations.push(`${property}: ${value}${priority ? ` !${priority}` : ""}`);
|
|
1621
1685
|
}
|
|
@@ -1643,16 +1707,15 @@ var HTML_CONTENT_ATTRIBUTES = /* @__PURE__ */ new Set(["srcdoc"]);
|
|
|
1643
1707
|
function isHtmlContentAttribute(name) {
|
|
1644
1708
|
return HTML_CONTENT_ATTRIBUTES.has(name.toLowerCase());
|
|
1645
1709
|
}
|
|
1646
|
-
function sanitizeAttributeString(attr, value) {
|
|
1710
|
+
function sanitizeAttributeString(attr, value, context2) {
|
|
1647
1711
|
const lower = attr.toLowerCase();
|
|
1648
1712
|
if (lower === "srcset") return sanitizeSrcset(value);
|
|
1649
1713
|
if (URL_ATTRIBUTES.has(lower)) return sanitizeUrl(value);
|
|
1650
|
-
if (lower === "style") return sanitizeStyleAttribute(value);
|
|
1714
|
+
if (lower === "style") return sanitizeStyleAttribute(value, context2);
|
|
1651
1715
|
return value;
|
|
1652
1716
|
}
|
|
1653
1717
|
|
|
1654
1718
|
// src/utils/setSafeAttribute.ts
|
|
1655
|
-
var _isDev3 = isDev();
|
|
1656
1719
|
var HTML_NS = "http://www.w3.org/1999/xhtml";
|
|
1657
1720
|
var SVG_NS = "http://www.w3.org/2000/svg";
|
|
1658
1721
|
var XLINK_NS = "http://www.w3.org/1999/xlink";
|
|
@@ -1675,7 +1738,7 @@ function setSafeAttribute(el, name, value, options = {}) {
|
|
|
1675
1738
|
const ns = namespaceFor(el, name);
|
|
1676
1739
|
const localName = ns ? name.slice(name.indexOf(":") + 1) : name;
|
|
1677
1740
|
if (isEventHandlerAttr(name)) {
|
|
1678
|
-
if (
|
|
1741
|
+
if (DEV) {
|
|
1679
1742
|
devWarn(
|
|
1680
1743
|
`${options.label ?? "setSafeAttribute"}: refusing to set event-handler attribute "${name}". Its value would be evaluated as JavaScript. Use on:{ ${name.slice(2)}: fn } instead.`
|
|
1681
1744
|
);
|
|
@@ -1690,7 +1753,7 @@ function setSafeAttribute(el, name, value, options = {}) {
|
|
|
1690
1753
|
return true;
|
|
1691
1754
|
}
|
|
1692
1755
|
if (isHtmlContentAttribute(name)) {
|
|
1693
|
-
if (
|
|
1756
|
+
if (DEV) {
|
|
1694
1757
|
devWarn(
|
|
1695
1758
|
`${options.label ?? "setSafeAttribute"}: refusing to set "${name}". The browser parses this attribute as a nested HTML document, so a generic string value cannot be made safe \u2014 attribute escaping is undone before the parse. Build the frame's content another way.`
|
|
1696
1759
|
);
|
|
@@ -1719,7 +1782,7 @@ function setSafeAttribute(el, name, value, options = {}) {
|
|
|
1719
1782
|
setProp(el, idlName, idlName === "checked" ? Boolean(value) : str);
|
|
1720
1783
|
return true;
|
|
1721
1784
|
}
|
|
1722
|
-
const safe = sanitizeAttributeString(name, str);
|
|
1785
|
+
const safe = sanitizeAttributeString(name, str, { element: el });
|
|
1723
1786
|
const current = ns ? el.getAttributeNS(ns, localName) : el.getAttribute(name);
|
|
1724
1787
|
if (current === safe) return true;
|
|
1725
1788
|
if (ns) el.setAttributeNS(ns, name, safe);
|
|
@@ -1945,7 +2008,14 @@ function reactiveBinding(commit, ownerNode) {
|
|
|
1945
2008
|
subscriber._disposed = false;
|
|
1946
2009
|
subscriber._errorPhase = "binding";
|
|
1947
2010
|
subscriber._errorNode = ownerNode;
|
|
1948
|
-
|
|
2011
|
+
try {
|
|
2012
|
+
run();
|
|
2013
|
+
} catch (err) {
|
|
2014
|
+
subscriber._disposed = true;
|
|
2015
|
+
subscriber._errorNode = void 0;
|
|
2016
|
+
cleanup(subscriber);
|
|
2017
|
+
throw err;
|
|
2018
|
+
}
|
|
1949
2019
|
return subscriber._dispose ?? (subscriber._dispose = () => {
|
|
1950
2020
|
subscriber._disposed = true;
|
|
1951
2021
|
subscriber._errorNode = void 0;
|
|
@@ -2176,17 +2246,16 @@ function forEachSubscriber(signal2, visit) {
|
|
|
2176
2246
|
}
|
|
2177
2247
|
|
|
2178
2248
|
// src/reactivity/track.ts
|
|
2179
|
-
var
|
|
2180
|
-
var _runtimeVersion = true ? "4.0.1" : "dev";
|
|
2249
|
+
var _runtimeVersion = true ? "4.2.0" : "dev";
|
|
2181
2250
|
var REGISTRY_KEY = /* @__PURE__ */ Symbol.for("sibujs.reactive.v1");
|
|
2182
2251
|
function resolveReactiveApi() {
|
|
2183
2252
|
const g2 = globalThis;
|
|
2184
2253
|
const existing = g2[REGISTRY_KEY];
|
|
2185
2254
|
if (existing) {
|
|
2186
|
-
if (
|
|
2255
|
+
if (DEV && !existing.__dupWarned) {
|
|
2187
2256
|
existing.__dupWarned = true;
|
|
2188
2257
|
devWarn(
|
|
2189
|
-
`Multiple instances of the reactive runtime detected on this page (active: ${existing.version}, duplicate: ${_runtimeVersion}). Reactivity
|
|
2258
|
+
`Multiple instances of the reactive runtime detected on this page (active: ${existing.version}, duplicate: ${_runtimeVersion}). Reactivity is NOT broken and no bundler configuration is required: every copy routes through the first one via a global registry, so signal writes still reach subscribers registered by any copy. This is only a SIZE issue \u2014 the duplicate copy's bytes are downloaded and parsed for nothing. If you want them back, de-duplicate sibujs in your bundler (Vite: resolve.dedupe: ['sibujs']). Mismatched VERSIONS above are worth fixing regardless, since only the first one loaded is used.`
|
|
2190
2259
|
);
|
|
2191
2260
|
}
|
|
2192
2261
|
return existing;
|
|
@@ -2285,8 +2354,101 @@ function bindDynamic(el, nameGetter, valueGetter) {
|
|
|
2285
2354
|
};
|
|
2286
2355
|
}
|
|
2287
2356
|
|
|
2357
|
+
// src/core/rendering/focusPreservation.ts
|
|
2358
|
+
var IDENTITY_ATTRS = ["data-focus-key", "id", "name"];
|
|
2359
|
+
var SELECTABLE_TYPES = /* @__PURE__ */ new Set(["text", "search", "url", "tel", "password", ""]);
|
|
2360
|
+
function selectionOf(el) {
|
|
2361
|
+
const tag = el.tagName;
|
|
2362
|
+
const selectable = tag === "TEXTAREA" || tag === "INPUT" && SELECTABLE_TYPES.has(el.type.toLowerCase());
|
|
2363
|
+
if (!selectable) return { start: null, end: null, direction: null };
|
|
2364
|
+
const field = el;
|
|
2365
|
+
return { start: field.selectionStart, end: field.selectionEnd, direction: field.selectionDirection };
|
|
2366
|
+
}
|
|
2367
|
+
function captureFocusWithin(nodes) {
|
|
2368
|
+
if (nodes.length === 0 || typeof document === "undefined") return null;
|
|
2369
|
+
const active = document.activeElement;
|
|
2370
|
+
if (!active || active === document.body) return null;
|
|
2371
|
+
let inside = false;
|
|
2372
|
+
for (let i2 = 0; i2 < nodes.length; i2++) {
|
|
2373
|
+
const n = nodes[i2];
|
|
2374
|
+
if (n === active || n.nodeType === 1 && n.contains(active)) {
|
|
2375
|
+
inside = true;
|
|
2376
|
+
break;
|
|
2377
|
+
}
|
|
2378
|
+
}
|
|
2379
|
+
if (!inside) return null;
|
|
2380
|
+
let attr = null;
|
|
2381
|
+
let value = null;
|
|
2382
|
+
for (let i2 = 0; i2 < IDENTITY_ATTRS.length; i2++) {
|
|
2383
|
+
const candidate = active.getAttribute(IDENTITY_ATTRS[i2]);
|
|
2384
|
+
if (candidate) {
|
|
2385
|
+
attr = IDENTITY_ATTRS[i2];
|
|
2386
|
+
value = candidate;
|
|
2387
|
+
break;
|
|
2388
|
+
}
|
|
2389
|
+
}
|
|
2390
|
+
return { el: active, attr, value, tag: active.tagName, ...selectionOf(active) };
|
|
2391
|
+
}
|
|
2392
|
+
function quote(value) {
|
|
2393
|
+
return `"${value.replace(/\\/g, "\\\\").replace(/"/g, '\\"')}"`;
|
|
2394
|
+
}
|
|
2395
|
+
function findUniqueByIdentity(nodes, selector) {
|
|
2396
|
+
let el = null;
|
|
2397
|
+
let count = 0;
|
|
2398
|
+
for (let i2 = 0; i2 < nodes.length; i2++) {
|
|
2399
|
+
const n = nodes[i2];
|
|
2400
|
+
if (n.nodeType !== 1) continue;
|
|
2401
|
+
const root = n;
|
|
2402
|
+
if (root.matches(selector)) {
|
|
2403
|
+
count++;
|
|
2404
|
+
el ?? (el = root);
|
|
2405
|
+
}
|
|
2406
|
+
const inner = root.querySelectorAll(selector);
|
|
2407
|
+
for (let j = 0; j < inner.length; j++) {
|
|
2408
|
+
count++;
|
|
2409
|
+
el ?? (el = inner[j]);
|
|
2410
|
+
}
|
|
2411
|
+
if (count > 1) return { el: null, count };
|
|
2412
|
+
}
|
|
2413
|
+
return count === 1 ? { el, count } : { el: null, count };
|
|
2414
|
+
}
|
|
2415
|
+
function refocus(el, snapshot) {
|
|
2416
|
+
el.focus();
|
|
2417
|
+
if (snapshot.start !== null && typeof el.setSelectionRange === "function") {
|
|
2418
|
+
const field = el;
|
|
2419
|
+
const max = field.value.length;
|
|
2420
|
+
const start = Math.min(snapshot.start, max);
|
|
2421
|
+
const end = Math.min(snapshot.end ?? start, max);
|
|
2422
|
+
field.setSelectionRange(start, end, snapshot.direction ?? "none");
|
|
2423
|
+
}
|
|
2424
|
+
}
|
|
2425
|
+
function restoreFocusWithin(snapshot, nodes, where) {
|
|
2426
|
+
if (!snapshot) return;
|
|
2427
|
+
if (typeof document === "undefined") return;
|
|
2428
|
+
const active = document.activeElement;
|
|
2429
|
+
if (active === snapshot.el) return;
|
|
2430
|
+
if (active && active !== document.body && active !== document.documentElement) return;
|
|
2431
|
+
if (snapshot.el.isConnected) {
|
|
2432
|
+
refocus(snapshot.el, snapshot);
|
|
2433
|
+
return;
|
|
2434
|
+
}
|
|
2435
|
+
let ambiguous = false;
|
|
2436
|
+
if (snapshot.attr && snapshot.value) {
|
|
2437
|
+
const { el: replacement, count } = findUniqueByIdentity(nodes, `[${snapshot.attr}=${quote(snapshot.value)}]`);
|
|
2438
|
+
if (replacement && replacement.tagName === snapshot.tag) {
|
|
2439
|
+
refocus(replacement, snapshot);
|
|
2440
|
+
return;
|
|
2441
|
+
}
|
|
2442
|
+
ambiguous = count > 1;
|
|
2443
|
+
}
|
|
2444
|
+
devWarnLazy(() => {
|
|
2445
|
+
const id = snapshot.attr ? ` (${snapshot.attr}="${snapshot.value}")` : "";
|
|
2446
|
+
const why = ambiguous ? `several elements in the rebuilt subtree share ${snapshot.attr}="${snapshot.value}", so there is no way to tell which one the user was in \u2014 a shared name (a radio group) identifies a GROUP, not a control. Add a unique id or data-focus-key to each` : "no element in the rebuilt subtree carries the same identity. Give it a stable id, name, or data-focus-key that the rebuild reproduces";
|
|
2447
|
+
return `${where}: a reactive rebuild discarded the focused element <${snapshot.tag.toLowerCase()}>${id} and could not re-establish it, so focus fell back to <body>. An in-progress edit ends here, and an in-progress IME composition is lost outright \u2014 a composition belongs to the DOM node, so it cannot survive the node being destroyed. ${why}, or stop the rebuild from happening: key the subtree with match(() => shapeKey(), { \u2026 }) so it is re-created only when the shape actually changes, and drive the rest with reactive attributes and text children, which mutate nodes in place instead of replacing them.`;
|
|
2448
|
+
});
|
|
2449
|
+
}
|
|
2450
|
+
|
|
2288
2451
|
// src/reactivity/bindChildNode.ts
|
|
2289
|
-
var _isDev5 = isDev();
|
|
2290
2452
|
function bindChildNode(placeholder, getter) {
|
|
2291
2453
|
let lastNodes = [];
|
|
2292
2454
|
function commit() {
|
|
@@ -2297,6 +2459,7 @@ function bindChildNode(placeholder, getter) {
|
|
|
2297
2459
|
reportError(err, { phase: "binding", name: "bindChildNode", node: placeholder });
|
|
2298
2460
|
return;
|
|
2299
2461
|
}
|
|
2462
|
+
const focused = captureFocusWithin(lastNodes);
|
|
2300
2463
|
if (result == null || typeof result === "boolean") {
|
|
2301
2464
|
for (let i2 = 0; i2 < lastNodes.length; i2++) {
|
|
2302
2465
|
const node = lastNodes[i2];
|
|
@@ -2304,6 +2467,7 @@ function bindChildNode(placeholder, getter) {
|
|
|
2304
2467
|
if (node.parentNode) node.parentNode.removeChild(node);
|
|
2305
2468
|
}
|
|
2306
2469
|
lastNodes.length = 0;
|
|
2470
|
+
restoreFocusWithin(focused, lastNodes, "bindChildNode");
|
|
2307
2471
|
return;
|
|
2308
2472
|
}
|
|
2309
2473
|
const parent = placeholder.parentNode;
|
|
@@ -2320,8 +2484,7 @@ function bindChildNode(placeholder, getter) {
|
|
|
2320
2484
|
if (item == null || typeof item === "boolean") continue;
|
|
2321
2485
|
const node = item instanceof Node ? item : document.createTextNode(String(item));
|
|
2322
2486
|
if (seen.has(node)) {
|
|
2323
|
-
if (
|
|
2324
|
-
devWarn("bindChildNode: duplicate node reference in array \u2014 only the first occurrence is rendered.");
|
|
2487
|
+
if (DEV) devWarn("bindChildNode: duplicate node reference in array \u2014 only the first occurrence is rendered.");
|
|
2325
2488
|
continue;
|
|
2326
2489
|
}
|
|
2327
2490
|
seen.add(node);
|
|
@@ -2354,13 +2517,13 @@ function bindChildNode(placeholder, getter) {
|
|
|
2354
2517
|
prev = node;
|
|
2355
2518
|
}
|
|
2356
2519
|
lastNodes = newNodes;
|
|
2520
|
+
restoreFocusWithin(focused, newNodes, "bindChildNode");
|
|
2357
2521
|
}
|
|
2358
2522
|
return reactiveBinding2(commit, placeholder);
|
|
2359
2523
|
}
|
|
2360
2524
|
|
|
2361
2525
|
// src/core/rendering/tagFactory.ts
|
|
2362
2526
|
var SVG_NS2 = "http://www.w3.org/2000/svg";
|
|
2363
|
-
var _isDev6 = isDev();
|
|
2364
2527
|
var BLOCKED_TAGS = /* @__PURE__ */ new Set(["script", "iframe", "object", "embed", "frame", "frameset"]);
|
|
2365
2528
|
function isBlockedTag(tag) {
|
|
2366
2529
|
return BLOCKED_TAGS.has(tag.toLowerCase());
|
|
@@ -2378,18 +2541,9 @@ var CLOBBER_RISKY_IDS = /* @__PURE__ */ new Set([
|
|
|
2378
2541
|
"self",
|
|
2379
2542
|
"frames"
|
|
2380
2543
|
]);
|
|
2381
|
-
|
|
2382
|
-
|
|
2383
|
-
|
|
2384
|
-
const tokens = t.split(/\s+/);
|
|
2385
|
-
let sawClassish = false;
|
|
2386
|
-
for (let i2 = 0; i2 < tokens.length; i2++) {
|
|
2387
|
-
const tok = tokens[i2];
|
|
2388
|
-
if (!/^-?[A-Za-z_][A-Za-z0-9_:/.-]*$/.test(tok)) return false;
|
|
2389
|
-
if (/[-:/0-9]/.test(tok)) sawClassish = true;
|
|
2390
|
-
}
|
|
2391
|
-
return sawClassish;
|
|
2392
|
-
}
|
|
2544
|
+
var warnedLoneStrings = /* @__PURE__ */ new Set();
|
|
2545
|
+
var MAX_WARNED_LONE_STRINGS = 100;
|
|
2546
|
+
var loneStringCapAnnounced = false;
|
|
2393
2547
|
var kebabCache = /* @__PURE__ */ new Map();
|
|
2394
2548
|
function toKebab(prop) {
|
|
2395
2549
|
let cached = kebabCache.get(prop);
|
|
@@ -2401,13 +2555,13 @@ function toKebab(prop) {
|
|
|
2401
2555
|
function applyStyle(el, style2) {
|
|
2402
2556
|
if (typeof style2 === "function") {
|
|
2403
2557
|
const teardown = reactiveBinding2(() => {
|
|
2404
|
-
el.setAttribute("style", sanitizeStyleAttribute(String(style2())));
|
|
2558
|
+
el.setAttribute("style", sanitizeStyleAttribute(String(style2()), { element: el }));
|
|
2405
2559
|
}, el);
|
|
2406
2560
|
registerDisposer(el, teardown);
|
|
2407
2561
|
return;
|
|
2408
2562
|
}
|
|
2409
2563
|
if (typeof style2 === "string") {
|
|
2410
|
-
el.setAttribute("style", sanitizeStyleAttribute(style2));
|
|
2564
|
+
el.setAttribute("style", sanitizeStyleAttribute(style2, { element: el }));
|
|
2411
2565
|
return;
|
|
2412
2566
|
}
|
|
2413
2567
|
const htmlEl = el;
|
|
@@ -2417,11 +2571,11 @@ function applyStyle(el, style2) {
|
|
|
2417
2571
|
if (typeof val === "function") {
|
|
2418
2572
|
const getter = val;
|
|
2419
2573
|
const teardown = reactiveBinding2(() => {
|
|
2420
|
-
htmlEl.style.setProperty(name, sanitizeCSSValue(String(getter())));
|
|
2574
|
+
htmlEl.style.setProperty(name, sanitizeCSSValue(String(getter()), { property: name, element: el }));
|
|
2421
2575
|
}, el);
|
|
2422
2576
|
registerDisposer(el, teardown);
|
|
2423
2577
|
} else {
|
|
2424
|
-
htmlEl.style.setProperty(name, sanitizeCSSValue(String(val)));
|
|
2578
|
+
htmlEl.style.setProperty(name, sanitizeCSSValue(String(val), { property: name, element: el }));
|
|
2425
2579
|
}
|
|
2426
2580
|
}
|
|
2427
2581
|
}
|
|
@@ -2528,11 +2682,26 @@ var tagFactory = (tag, ns) => {
|
|
|
2528
2682
|
appendChildren(el, second);
|
|
2529
2683
|
return el;
|
|
2530
2684
|
}
|
|
2531
|
-
|
|
2532
|
-
|
|
2533
|
-
|
|
2534
|
-
|
|
2535
|
-
|
|
2685
|
+
devWarnLazy(() => {
|
|
2686
|
+
const tokens = first.trim().split(/\s+/);
|
|
2687
|
+
if (tokens.length < 2) return "";
|
|
2688
|
+
let utilityTokens = 0;
|
|
2689
|
+
for (let i2 = 0; i2 < tokens.length; i2++) {
|
|
2690
|
+
const tok = tokens[i2];
|
|
2691
|
+
if (!/^-?[A-Za-z_][A-Za-z0-9_:/.-]*$/.test(tok)) return "";
|
|
2692
|
+
if (/[-:/0-9]/.test(tok)) utilityTokens++;
|
|
2693
|
+
}
|
|
2694
|
+
if (utilityTokens < 2) return "";
|
|
2695
|
+
const key = `${tag}|${first}`;
|
|
2696
|
+
if (warnedLoneStrings.has(key)) return "";
|
|
2697
|
+
if (warnedLoneStrings.size >= MAX_WARNED_LONE_STRINGS) {
|
|
2698
|
+
if (loneStringCapAnnounced) return "";
|
|
2699
|
+
loneStringCapAnnounced = true;
|
|
2700
|
+
return `tagFactory: ${MAX_WARNED_LONE_STRINGS} distinct lone-string class warnings have been reported; suppressing further ones for the rest of this session so they cannot flood the console. Fix the reported ones and reload to see any that remain.`;
|
|
2701
|
+
}
|
|
2702
|
+
warnedLoneStrings.add(key);
|
|
2703
|
+
return `tagFactory: lone string "${first}" looks like a class list but is being rendered as TEXT. For a class, use ${tag}({ class: "${first}" }) \u2014 or ${tag}("${first}", children) to set the class AND add children.`;
|
|
2704
|
+
});
|
|
2536
2705
|
el.textContent = first;
|
|
2537
2706
|
return el;
|
|
2538
2707
|
}
|
|
@@ -2549,7 +2718,7 @@ var tagFactory = (tag, ns) => {
|
|
|
2549
2718
|
if (pClass != null) applyClass(el, pClass);
|
|
2550
2719
|
const pId = props.id;
|
|
2551
2720
|
if (pId != null) {
|
|
2552
|
-
if (
|
|
2721
|
+
if (DEV && typeof pId === "string" && CLOBBER_RISKY_IDS.has(pId.toLowerCase())) {
|
|
2553
2722
|
devWarn(
|
|
2554
2723
|
`tagFactory: element id="${pId}" matches a common global and may cause DOM clobbering. Avoid setting ids from untrusted input.`
|
|
2555
2724
|
);
|
|
@@ -2564,7 +2733,7 @@ var tagFactory = (tag, ns) => {
|
|
|
2564
2733
|
const handler = pOn[ev];
|
|
2565
2734
|
if (typeof handler === "function") {
|
|
2566
2735
|
el.addEventListener(ev, handler);
|
|
2567
|
-
} else if (
|
|
2736
|
+
} else if (DEV) {
|
|
2568
2737
|
devWarn(
|
|
2569
2738
|
`tagFactory: on.${ev} handler is not a function (got ${typeof handler}). Event listener was not attached.`
|
|
2570
2739
|
);
|
|
@@ -3363,7 +3532,6 @@ var isBatching = API2.isBatching;
|
|
|
3363
3532
|
|
|
3364
3533
|
// src/core/signals/signal.ts
|
|
3365
3534
|
var _g2 = globalThis;
|
|
3366
|
-
var _isDev7 = isDev();
|
|
3367
3535
|
function signal(initial, options) {
|
|
3368
3536
|
const state2 = {
|
|
3369
3537
|
value: initial,
|
|
@@ -3376,7 +3544,7 @@ function signal(initial, options) {
|
|
|
3376
3544
|
_d: false,
|
|
3377
3545
|
_validate: void 0
|
|
3378
3546
|
};
|
|
3379
|
-
const debugName =
|
|
3547
|
+
const debugName = DEV ? options?.name : void 0;
|
|
3380
3548
|
const equalsFn = options?.equals;
|
|
3381
3549
|
if (debugName) state2.__name = debugName;
|
|
3382
3550
|
function get() {
|
|
@@ -3393,7 +3561,7 @@ function signal(initial, options) {
|
|
|
3393
3561
|
if (equalsFn(prev, newValue)) return;
|
|
3394
3562
|
state2.value = newValue;
|
|
3395
3563
|
state2.__v++;
|
|
3396
|
-
if (
|
|
3564
|
+
if (DEV) {
|
|
3397
3565
|
const hook = _g2.__SIBU_DEVTOOLS_GLOBAL_HOOK__;
|
|
3398
3566
|
if (hook) hook.emit("signal:update", { signal: state2, name: debugName, oldValue: prev, newValue });
|
|
3399
3567
|
}
|
|
@@ -3401,7 +3569,7 @@ function signal(initial, options) {
|
|
|
3401
3569
|
notifySubscribers2(state2);
|
|
3402
3570
|
}
|
|
3403
3571
|
};
|
|
3404
|
-
} else if (
|
|
3572
|
+
} else if (DEV) {
|
|
3405
3573
|
set = (next) => {
|
|
3406
3574
|
const prev = state2.value;
|
|
3407
3575
|
const newValue = typeof next === "function" ? next(prev) : next;
|
|
@@ -3426,12 +3594,23 @@ function signal(initial, options) {
|
|
|
3426
3594
|
}
|
|
3427
3595
|
};
|
|
3428
3596
|
}
|
|
3429
|
-
if (
|
|
3597
|
+
if (DEV) {
|
|
3430
3598
|
const hook = _g2.__SIBU_DEVTOOLS_GLOBAL_HOOK__;
|
|
3431
3599
|
if (hook) hook.emit("signal:create", { signal: state2, name: debugName, getter: get, initial });
|
|
3432
3600
|
}
|
|
3433
3601
|
return [get, set];
|
|
3434
3602
|
}
|
|
3603
|
+
function external(options) {
|
|
3604
|
+
const [version, bump] = signal(0, options?.name ? { name: options.name } : void 0);
|
|
3605
|
+
return {
|
|
3606
|
+
track() {
|
|
3607
|
+
version();
|
|
3608
|
+
},
|
|
3609
|
+
invalidate() {
|
|
3610
|
+
bump((n) => n + 1);
|
|
3611
|
+
}
|
|
3612
|
+
};
|
|
3613
|
+
}
|
|
3435
3614
|
|
|
3436
3615
|
// src/components/ErrorDisplay.ts
|
|
3437
3616
|
var STYLES = `
|
|
@@ -4407,11 +4586,10 @@ function setGlobalErrorHandler(handler) {
|
|
|
4407
4586
|
}
|
|
4408
4587
|
|
|
4409
4588
|
// src/core/rendering/context.ts
|
|
4410
|
-
var _isDev8 = isDev();
|
|
4411
4589
|
function context(defaultValue) {
|
|
4412
4590
|
const [getValue, setValue] = signal(defaultValue);
|
|
4413
4591
|
const warnIfSSR = (method) => {
|
|
4414
|
-
if (!
|
|
4592
|
+
if (!DEV || !isSSR()) return;
|
|
4415
4593
|
devWarn(
|
|
4416
4594
|
`context.${method}() called during SSR. SibuJS context() is application-global \u2014 it is NOT isolated per request, so a concurrent request can observe this value. Do not use context() for request-specific SSR data; pass it explicitly or use request-scoped storage instead.`
|
|
4417
4595
|
);
|
|
@@ -4439,7 +4617,7 @@ function context(defaultValue) {
|
|
|
4439
4617
|
setValue(value);
|
|
4440
4618
|
try {
|
|
4441
4619
|
const result = fn();
|
|
4442
|
-
if (
|
|
4620
|
+
if (DEV && result !== null && typeof result?.then === "function") {
|
|
4443
4621
|
devWarn(
|
|
4444
4622
|
"context.withContext() received an async callback. Scoping is synchronous only \u2014 the previous value is restored as soon as the callback returns its promise, so anything after an `await` runs outside the scope."
|
|
4445
4623
|
);
|
|
@@ -4466,34 +4644,53 @@ function __resetIdCounter() {
|
|
|
4466
4644
|
|
|
4467
4645
|
// src/core/rendering/directives.ts
|
|
4468
4646
|
function show(condition, element) {
|
|
4647
|
+
const resolved = typeof element === "function" ? element() : element;
|
|
4469
4648
|
const update = () => {
|
|
4470
|
-
|
|
4649
|
+
resolved.style.display = condition() ? "" : "none";
|
|
4471
4650
|
};
|
|
4472
|
-
registerDisposer(
|
|
4473
|
-
return
|
|
4651
|
+
registerDisposer(resolved, track2(update));
|
|
4652
|
+
return resolved;
|
|
4653
|
+
}
|
|
4654
|
+
function attachBranch(parent, anchor, branch, attachedOnce, where) {
|
|
4655
|
+
const result = typeof branch === "function" ? branch() : branch;
|
|
4656
|
+
if (result == null || typeof result === "boolean") return { node: null, owned: false };
|
|
4657
|
+
const node = result instanceof Node ? result : document.createTextNode(String(result));
|
|
4658
|
+
const handedIn = node === branch;
|
|
4659
|
+
const seenBefore = attachedOnce.has(node);
|
|
4660
|
+
const owned = !handedIn && !seenBefore;
|
|
4661
|
+
attachedOnce.add(node);
|
|
4662
|
+
if (seenBefore) {
|
|
4663
|
+
devWarnLazy(
|
|
4664
|
+
() => `${where}: ${handedIn ? "a branch was given as an element rather than a function" : "a branch factory returned a node it had already returned"}, so the SAME node is being re-attached \u2014 any state it accumulated while detached (input value, scroll position, classes set imperatively) comes back with it. Its reactive bindings are left intact rather than disposed, because the node is not this directive's to tear down. Return a FRESH node per call (\`() => div(\u2026)\`) for rebuild semantics, or keep this form deliberately when the reuse is what you want.`
|
|
4665
|
+
);
|
|
4666
|
+
}
|
|
4667
|
+
parent.insertBefore(node, anchor.nextSibling);
|
|
4668
|
+
return { node, owned };
|
|
4474
4669
|
}
|
|
4475
4670
|
function when(condition, thenBranch, elseBranch) {
|
|
4476
4671
|
const anchor = document.createComment("when");
|
|
4477
4672
|
let currentNode = null;
|
|
4478
4673
|
let lastCondition;
|
|
4479
4674
|
let initialized = false;
|
|
4675
|
+
const attachedOnce = /* @__PURE__ */ new WeakSet();
|
|
4676
|
+
let currentNodeOwned = false;
|
|
4480
4677
|
const update = () => {
|
|
4481
4678
|
const show2 = condition();
|
|
4482
4679
|
const parent = anchor.parentNode;
|
|
4483
4680
|
if (!parent) return;
|
|
4484
4681
|
if (initialized && show2 === lastCondition) return;
|
|
4485
4682
|
lastCondition = show2;
|
|
4683
|
+
const focused = currentNode ? captureFocusWithin([currentNode]) : null;
|
|
4486
4684
|
if (currentNode?.parentNode) {
|
|
4487
|
-
dispose(currentNode);
|
|
4685
|
+
if (currentNodeOwned) dispose(currentNode);
|
|
4488
4686
|
currentNode.parentNode.removeChild(currentNode);
|
|
4489
4687
|
currentNode = null;
|
|
4490
4688
|
}
|
|
4491
|
-
const
|
|
4492
|
-
|
|
4493
|
-
|
|
4494
|
-
|
|
4495
|
-
|
|
4496
|
-
}
|
|
4689
|
+
const branch = show2 ? thenBranch : elseBranch !== void 0 ? elseBranch : null;
|
|
4690
|
+
const attached = attachBranch(parent, anchor, branch, attachedOnce, "when");
|
|
4691
|
+
currentNode = attached.node;
|
|
4692
|
+
currentNodeOwned = attached.owned;
|
|
4693
|
+
restoreFocusWithin(focused, currentNode ? [currentNode] : [], "when");
|
|
4497
4694
|
initialized = true;
|
|
4498
4695
|
};
|
|
4499
4696
|
registerDisposer(anchor, track2(update));
|
|
@@ -4509,26 +4706,25 @@ function match(value, cases, fallback) {
|
|
|
4509
4706
|
let currentNode = null;
|
|
4510
4707
|
let lastKey;
|
|
4511
4708
|
let initialized = false;
|
|
4709
|
+
const attachedOnce = /* @__PURE__ */ new WeakSet();
|
|
4710
|
+
let currentNodeOwned = false;
|
|
4512
4711
|
const update = () => {
|
|
4513
4712
|
const key = String(value());
|
|
4514
4713
|
const parent = anchor.parentNode;
|
|
4515
4714
|
if (!parent) return;
|
|
4516
4715
|
if (initialized && key === lastKey) return;
|
|
4517
4716
|
lastKey = key;
|
|
4717
|
+
const focused = currentNode ? captureFocusWithin([currentNode]) : null;
|
|
4518
4718
|
if (currentNode?.parentNode) {
|
|
4519
|
-
dispose(currentNode);
|
|
4719
|
+
if (currentNodeOwned) dispose(currentNode);
|
|
4520
4720
|
currentNode.parentNode.removeChild(currentNode);
|
|
4521
4721
|
currentNode = null;
|
|
4522
4722
|
}
|
|
4523
|
-
const
|
|
4524
|
-
|
|
4525
|
-
|
|
4526
|
-
|
|
4527
|
-
|
|
4528
|
-
parent.insertBefore(node, anchor.nextSibling);
|
|
4529
|
-
currentNode = node;
|
|
4530
|
-
}
|
|
4531
|
-
}
|
|
4723
|
+
const branch = Object.hasOwn(cases, key) ? cases[key] : fallback;
|
|
4724
|
+
const attached = attachBranch(parent, anchor, branch ?? null, attachedOnce, "match");
|
|
4725
|
+
currentNode = attached.node;
|
|
4726
|
+
currentNodeOwned = attached.owned;
|
|
4727
|
+
restoreFocusWithin(focused, currentNode ? [currentNode] : [], "match");
|
|
4532
4728
|
initialized = true;
|
|
4533
4729
|
};
|
|
4534
4730
|
registerDisposer(anchor, track2(update));
|
|
@@ -4573,7 +4769,6 @@ function DynamicComponent(is) {
|
|
|
4573
4769
|
}
|
|
4574
4770
|
|
|
4575
4771
|
// src/core/rendering/each.ts
|
|
4576
|
-
var _isDev9 = isDev();
|
|
4577
4772
|
function resolveNodeChild(child) {
|
|
4578
4773
|
if (typeof child === "function") {
|
|
4579
4774
|
return resolveNodeChild(child());
|
|
@@ -4664,7 +4859,7 @@ function each(getArray, render, options) {
|
|
|
4664
4859
|
workMap.clear();
|
|
4665
4860
|
keyIndexMap.clear();
|
|
4666
4861
|
for (let i2 = 0; i2 < newLen; i2++) {
|
|
4667
|
-
if (
|
|
4862
|
+
if (DEV && keyIndexMap.has(newKeys[i2])) {
|
|
4668
4863
|
devWarn(
|
|
4669
4864
|
`each: duplicate key "${String(newKeys[i2])}" at index ${i2} (first seen at ${keyIndexMap.get(newKeys[i2])}). Keys must be unique \u2014 duplicates cause rows to be dropped or mis-ordered.`
|
|
4670
4865
|
);
|
|
@@ -4848,7 +5043,6 @@ function resolveChild(child) {
|
|
|
4848
5043
|
}
|
|
4849
5044
|
|
|
4850
5045
|
// src/core/rendering/htm.ts
|
|
4851
|
-
var _isDev10 = isDev();
|
|
4852
5046
|
var RAW_TEXT_TAGS = /* @__PURE__ */ new Set(["script", "style"]);
|
|
4853
5047
|
var VOID_ELEMENTS3 = /* @__PURE__ */ new Set([
|
|
4854
5048
|
"area",
|
|
@@ -4935,13 +5129,13 @@ function parseTemplate(strings) {
|
|
|
4935
5129
|
skipWs();
|
|
4936
5130
|
const exprIdx = tryExprIdx();
|
|
4937
5131
|
if (exprIdx >= 0) return { kind: "expr", idx: exprIdx };
|
|
4938
|
-
const
|
|
4939
|
-
if (
|
|
5132
|
+
const quote2 = template2[pos];
|
|
5133
|
+
if (quote2 === '"' || quote2 === "'") {
|
|
4940
5134
|
pos++;
|
|
4941
5135
|
const statics = [];
|
|
4942
5136
|
const exprs = [];
|
|
4943
5137
|
let current = "";
|
|
4944
|
-
while (pos < len && template2[pos] !==
|
|
5138
|
+
while (pos < len && template2[pos] !== quote2) {
|
|
4945
5139
|
const innerIdx = tryExprIdx();
|
|
4946
5140
|
if (innerIdx >= 0) {
|
|
4947
5141
|
statics.push(current);
|
|
@@ -5128,7 +5322,7 @@ function executeElement(tmpl, values) {
|
|
|
5128
5322
|
const fn = values[attr.idx];
|
|
5129
5323
|
if (typeof fn === "function") {
|
|
5130
5324
|
el.addEventListener(attr.name, fn);
|
|
5131
|
-
} else if (
|
|
5325
|
+
} else if (DEV) {
|
|
5132
5326
|
devWarn(
|
|
5133
5327
|
`html: on:${attr.name} handler is not a function (got ${typeof fn}). Event listener was not attached.`
|
|
5134
5328
|
);
|
|
@@ -5996,6 +6190,7 @@ function drainTeardowns(teardowns, label2) {
|
|
|
5996
6190
|
}
|
|
5997
6191
|
}
|
|
5998
6192
|
}
|
|
6193
|
+
var EACH_KEYS = ["text", "attr", "class", "show", "on", "cleanup"];
|
|
5999
6194
|
function resolveTarget(root, target) {
|
|
6000
6195
|
if (target == null) return root;
|
|
6001
6196
|
if (typeof target !== "string") return target;
|
|
@@ -6006,6 +6201,11 @@ function resolveTarget(root, target) {
|
|
|
6006
6201
|
return null;
|
|
6007
6202
|
}
|
|
6008
6203
|
}
|
|
6204
|
+
function bindNode(el, commit) {
|
|
6205
|
+
if (isSSR()) return () => {
|
|
6206
|
+
};
|
|
6207
|
+
return reactiveBinding2(commit, el);
|
|
6208
|
+
}
|
|
6009
6209
|
function readControlValue(el) {
|
|
6010
6210
|
if (el instanceof HTMLInputElement) {
|
|
6011
6211
|
if (el.type === "checkbox") return el.checked;
|
|
@@ -6029,6 +6229,50 @@ function writeControlValue(el, value) {
|
|
|
6029
6229
|
const next = value == null ? "" : String(value);
|
|
6030
6230
|
if (el.value !== next) el.value = next;
|
|
6031
6231
|
}
|
|
6232
|
+
function applyEachBindings(ctx, el, spec, index) {
|
|
6233
|
+
const where = `ctx.each[${index}]`;
|
|
6234
|
+
if (isDev()) {
|
|
6235
|
+
for (const key of Object.keys(spec)) {
|
|
6236
|
+
devAssert(
|
|
6237
|
+
EACH_KEYS.includes(key),
|
|
6238
|
+
`${where}: unknown binding "${key}". Expected one of: ${EACH_KEYS.join(", ")}.`
|
|
6239
|
+
);
|
|
6240
|
+
}
|
|
6241
|
+
}
|
|
6242
|
+
if (spec.text !== void 0) {
|
|
6243
|
+
devAssert(typeof spec.text === "function", `${where}: "text" must be a function returning the value.`);
|
|
6244
|
+
ctx.text(el, spec.text);
|
|
6245
|
+
}
|
|
6246
|
+
if (spec.attr !== void 0) {
|
|
6247
|
+
for (const name of Object.keys(spec.attr)) {
|
|
6248
|
+
const value = spec.attr[name];
|
|
6249
|
+
devAssert(typeof value === "function", `${where}: attr["${name}"] must be a function returning the value.`);
|
|
6250
|
+
ctx.attr(el, name, value);
|
|
6251
|
+
}
|
|
6252
|
+
}
|
|
6253
|
+
if (spec.class !== void 0) {
|
|
6254
|
+
for (const name of Object.keys(spec.class)) {
|
|
6255
|
+
const on2 = spec.class[name];
|
|
6256
|
+
devAssert(typeof on2 === "function", `${where}: class["${name}"] must be a function returning a boolean.`);
|
|
6257
|
+
ctx.classed(el, name, on2);
|
|
6258
|
+
}
|
|
6259
|
+
}
|
|
6260
|
+
if (spec.show !== void 0) {
|
|
6261
|
+
devAssert(typeof spec.show === "function", `${where}: "show" must be a function returning a boolean.`);
|
|
6262
|
+
ctx.show(el, spec.show);
|
|
6263
|
+
}
|
|
6264
|
+
if (spec.on !== void 0) {
|
|
6265
|
+
for (const event of Object.keys(spec.on)) {
|
|
6266
|
+
const handler = spec.on[event];
|
|
6267
|
+
devAssert(typeof handler === "function", `${where}: on["${String(event)}"] must be a function.`);
|
|
6268
|
+
ctx.on(el, event, handler);
|
|
6269
|
+
}
|
|
6270
|
+
}
|
|
6271
|
+
if (spec.cleanup !== void 0) {
|
|
6272
|
+
devAssert(typeof spec.cleanup === "function", `${where}: "cleanup" must be a function.`);
|
|
6273
|
+
ctx.cleanup(spec.cleanup);
|
|
6274
|
+
}
|
|
6275
|
+
}
|
|
6032
6276
|
function enhance(target, setup) {
|
|
6033
6277
|
const root = typeof target === "string" ? typeof document !== "undefined" ? document.querySelector(target) : null : target;
|
|
6034
6278
|
if (!root) {
|
|
@@ -6079,7 +6323,7 @@ function enhance(target, setup) {
|
|
|
6079
6323
|
text: (t, value) => {
|
|
6080
6324
|
bind(t, (el) => {
|
|
6081
6325
|
teardowns.push(
|
|
6082
|
-
|
|
6326
|
+
bindNode(el, () => {
|
|
6083
6327
|
const v = value();
|
|
6084
6328
|
const next = v == null ? "" : String(v);
|
|
6085
6329
|
if (el.textContent !== next) el.textContent = next;
|
|
@@ -6090,7 +6334,7 @@ function enhance(target, setup) {
|
|
|
6090
6334
|
attr: (t, name, value) => {
|
|
6091
6335
|
bind(t, (el) => {
|
|
6092
6336
|
teardowns.push(
|
|
6093
|
-
|
|
6337
|
+
bindNode(el, () => {
|
|
6094
6338
|
const v = value();
|
|
6095
6339
|
const next = v == null ? null : String(v);
|
|
6096
6340
|
setSafeAttribute(el, name, next, { syncValueProperty: false, label: "enhance attr()" });
|
|
@@ -6101,7 +6345,7 @@ function enhance(target, setup) {
|
|
|
6101
6345
|
classed: (t, name, on2) => {
|
|
6102
6346
|
bind(t, (el) => {
|
|
6103
6347
|
teardowns.push(
|
|
6104
|
-
|
|
6348
|
+
bindNode(el, () => {
|
|
6105
6349
|
el.classList.toggle(name, Boolean(on2()));
|
|
6106
6350
|
})
|
|
6107
6351
|
);
|
|
@@ -6111,7 +6355,7 @@ function enhance(target, setup) {
|
|
|
6111
6355
|
bind(t, (el) => {
|
|
6112
6356
|
const prevHidden = el.hidden;
|
|
6113
6357
|
teardowns.push(
|
|
6114
|
-
|
|
6358
|
+
bindNode(el, () => {
|
|
6115
6359
|
el.hidden = !when2();
|
|
6116
6360
|
})
|
|
6117
6361
|
);
|
|
@@ -6126,7 +6370,7 @@ function enhance(target, setup) {
|
|
|
6126
6370
|
const [get, set] = state2;
|
|
6127
6371
|
const evt = options?.event ?? (control instanceof HTMLSelectElement || control instanceof HTMLInputElement && (control.type === "checkbox" || control.type === "radio") ? "change" : "input");
|
|
6128
6372
|
teardowns.push(
|
|
6129
|
-
|
|
6373
|
+
bindNode(el, () => {
|
|
6130
6374
|
writeControlValue(control, get());
|
|
6131
6375
|
})
|
|
6132
6376
|
);
|
|
@@ -6135,6 +6379,16 @@ function enhance(target, setup) {
|
|
|
6135
6379
|
teardowns.push(() => control.removeEventListener(evt, onInput));
|
|
6136
6380
|
});
|
|
6137
6381
|
},
|
|
6382
|
+
each: (target_, describe2) => {
|
|
6383
|
+
devAssert(typeof describe2 === "function", "ctx.each: second argument must be a function.");
|
|
6384
|
+
const elements = typeof target_ === "string" ? ctx.refs(target_) : Array.from(target_);
|
|
6385
|
+
for (let i2 = 0; i2 < elements.length; i2++) {
|
|
6386
|
+
const el = elements[i2];
|
|
6387
|
+
const spec = describe2(el, i2);
|
|
6388
|
+
if (spec == null) continue;
|
|
6389
|
+
applyEachBindings(ctx, el, spec, i2);
|
|
6390
|
+
}
|
|
6391
|
+
},
|
|
6138
6392
|
cleanup: (fn) => {
|
|
6139
6393
|
teardowns.push(fn);
|
|
6140
6394
|
}
|
|
@@ -6343,7 +6597,6 @@ function schedule(strategy, el, activate, options) {
|
|
|
6343
6597
|
}
|
|
6344
6598
|
|
|
6345
6599
|
// src/platform/ssr.ts
|
|
6346
|
-
var _isDev11 = isDev();
|
|
6347
6600
|
function trustHTML(html3) {
|
|
6348
6601
|
return html3;
|
|
6349
6602
|
}
|