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/ecosystem.cjs
CHANGED
|
@@ -32,23 +32,23 @@ __export(ecosystem_exports, {
|
|
|
32
32
|
module.exports = __toCommonJS(ecosystem_exports);
|
|
33
33
|
|
|
34
34
|
// src/core/dev.ts
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
// this branch is unreachable here.
|
|
40
|
-
/* v8 ignore next 2 */
|
|
41
|
-
typeof __SIBU_DEV__ !== "undefined" ? __SIBU_DEV__ : typeof process !== "undefined" && process.env?.NODE_ENV !== "production"
|
|
42
|
-
);
|
|
43
|
-
}
|
|
44
|
-
var _isDev = isDev();
|
|
35
|
+
var DEV = typeof __SIBU_DEV__ !== "undefined" ? !!__SIBU_DEV__ : typeof globalThis.__SIBU_DEV__ !== "undefined" ? !!globalThis.__SIBU_DEV__ : (
|
|
36
|
+
// safe default: off in browser, on in test/dev Node
|
|
37
|
+
typeof process !== "undefined" && process.env?.NODE_ENV !== "production"
|
|
38
|
+
);
|
|
45
39
|
function devAssert(condition, message) {
|
|
46
|
-
if (
|
|
40
|
+
if ((typeof __SIBU_DEV__ !== "undefined" ? __SIBU_DEV__ : DEV) && !condition) {
|
|
47
41
|
throw new Error(`[SibuJS] ${message}`);
|
|
48
42
|
}
|
|
49
43
|
}
|
|
44
|
+
function devWarnLazy(build) {
|
|
45
|
+
if (typeof __SIBU_DEV__ !== "undefined" ? __SIBU_DEV__ : DEV) {
|
|
46
|
+
const message = build();
|
|
47
|
+
if (message) console.warn(`[SibuJS] ${message}`);
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
50
|
function devWarn(message) {
|
|
51
|
-
if (
|
|
51
|
+
if (typeof __SIBU_DEV__ !== "undefined" ? __SIBU_DEV__ : DEV) {
|
|
52
52
|
console.warn(`[SibuJS] ${message}`);
|
|
53
53
|
}
|
|
54
54
|
}
|
|
@@ -359,7 +359,14 @@ function reactiveBinding(commit, ownerNode) {
|
|
|
359
359
|
subscriber._disposed = false;
|
|
360
360
|
subscriber._errorPhase = "binding";
|
|
361
361
|
subscriber._errorNode = ownerNode;
|
|
362
|
-
|
|
362
|
+
try {
|
|
363
|
+
run();
|
|
364
|
+
} catch (err) {
|
|
365
|
+
subscriber._disposed = true;
|
|
366
|
+
subscriber._errorNode = void 0;
|
|
367
|
+
cleanup(subscriber);
|
|
368
|
+
throw err;
|
|
369
|
+
}
|
|
363
370
|
return subscriber._dispose ?? (subscriber._dispose = () => {
|
|
364
371
|
subscriber._disposed = true;
|
|
365
372
|
subscriber._errorNode = void 0;
|
|
@@ -590,17 +597,16 @@ function forEachSubscriber(signal2, visit) {
|
|
|
590
597
|
}
|
|
591
598
|
|
|
592
599
|
// src/reactivity/track.ts
|
|
593
|
-
var
|
|
594
|
-
var _runtimeVersion = true ? "4.0.1" : "dev";
|
|
600
|
+
var _runtimeVersion = true ? "4.2.0" : "dev";
|
|
595
601
|
var REGISTRY_KEY = /* @__PURE__ */ Symbol.for("sibujs.reactive.v1");
|
|
596
602
|
function resolveReactiveApi() {
|
|
597
603
|
const g = globalThis;
|
|
598
604
|
const existing = g[REGISTRY_KEY];
|
|
599
605
|
if (existing) {
|
|
600
|
-
if (
|
|
606
|
+
if (DEV && !existing.__dupWarned) {
|
|
601
607
|
existing.__dupWarned = true;
|
|
602
608
|
devWarn(
|
|
603
|
-
`Multiple instances of the reactive runtime detected on this page (active: ${existing.version}, duplicate: ${_runtimeVersion}). Reactivity
|
|
609
|
+
`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.`
|
|
604
610
|
);
|
|
605
611
|
}
|
|
606
612
|
return existing;
|
|
@@ -862,7 +868,6 @@ var isBatching = API2.isBatching;
|
|
|
862
868
|
|
|
863
869
|
// src/core/signals/signal.ts
|
|
864
870
|
var _g2 = globalThis;
|
|
865
|
-
var _isDev3 = isDev();
|
|
866
871
|
function signal(initial, options) {
|
|
867
872
|
const state2 = {
|
|
868
873
|
value: initial,
|
|
@@ -875,7 +880,7 @@ function signal(initial, options) {
|
|
|
875
880
|
_d: false,
|
|
876
881
|
_validate: void 0
|
|
877
882
|
};
|
|
878
|
-
const debugName =
|
|
883
|
+
const debugName = DEV ? options?.name : void 0;
|
|
879
884
|
const equalsFn = options?.equals;
|
|
880
885
|
if (debugName) state2.__name = debugName;
|
|
881
886
|
function get() {
|
|
@@ -892,7 +897,7 @@ function signal(initial, options) {
|
|
|
892
897
|
if (equalsFn(prev, newValue)) return;
|
|
893
898
|
state2.value = newValue;
|
|
894
899
|
state2.__v++;
|
|
895
|
-
if (
|
|
900
|
+
if (DEV) {
|
|
896
901
|
const hook = _g2.__SIBU_DEVTOOLS_GLOBAL_HOOK__;
|
|
897
902
|
if (hook) hook.emit("signal:update", { signal: state2, name: debugName, oldValue: prev, newValue });
|
|
898
903
|
}
|
|
@@ -900,7 +905,7 @@ function signal(initial, options) {
|
|
|
900
905
|
notifySubscribers2(state2);
|
|
901
906
|
}
|
|
902
907
|
};
|
|
903
|
-
} else if (
|
|
908
|
+
} else if (DEV) {
|
|
904
909
|
set = (next) => {
|
|
905
910
|
const prev = state2.value;
|
|
906
911
|
const newValue = typeof next === "function" ? next(prev) : next;
|
|
@@ -925,7 +930,7 @@ function signal(initial, options) {
|
|
|
925
930
|
}
|
|
926
931
|
};
|
|
927
932
|
}
|
|
928
|
-
if (
|
|
933
|
+
if (DEV) {
|
|
929
934
|
const hook = _g2.__SIBU_DEVTOOLS_GLOBAL_HOOK__;
|
|
930
935
|
if (hook) hook.emit("signal:create", { signal: state2, name: debugName, getter: get, initial });
|
|
931
936
|
}
|
|
@@ -1286,20 +1291,75 @@ function decodeCssEscapes(value) {
|
|
|
1286
1291
|
}
|
|
1287
1292
|
return out;
|
|
1288
1293
|
}
|
|
1289
|
-
|
|
1290
|
-
|
|
1294
|
+
var BLOCKED_CSS_NEEDLES = [
|
|
1295
|
+
"url(",
|
|
1296
|
+
"expression(",
|
|
1297
|
+
"javascript:",
|
|
1298
|
+
"vbscript:",
|
|
1299
|
+
"-moz-binding",
|
|
1300
|
+
"behavior:",
|
|
1301
|
+
"@import",
|
|
1302
|
+
"image-set(",
|
|
1303
|
+
"filter:progid"
|
|
1304
|
+
];
|
|
1305
|
+
function describeElement(el) {
|
|
1306
|
+
if (!el) return "an element";
|
|
1307
|
+
let out = el.tagName.toLowerCase();
|
|
1308
|
+
const id = el.getAttribute("id");
|
|
1309
|
+
if (id) out += `#${id}`;
|
|
1310
|
+
const cls = el.getAttribute("class");
|
|
1311
|
+
if (cls) out += `.${cls.trim().split(/\s+/).slice(0, 3).join(".")}`;
|
|
1312
|
+
return `<${out}>`;
|
|
1313
|
+
}
|
|
1314
|
+
var warnedDeclarations = /* @__PURE__ */ new Set();
|
|
1315
|
+
var MAX_WARNED_DECLARATIONS = 100;
|
|
1316
|
+
var declarationCapAnnounced = false;
|
|
1317
|
+
function warnDroppedDeclaration(value, reason, ctx) {
|
|
1318
|
+
devWarnLazy(() => {
|
|
1319
|
+
const reasons = [
|
|
1320
|
+
"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",
|
|
1321
|
+
"expression() executes arbitrary script in legacy engines",
|
|
1322
|
+
"the javascript: scheme executes script",
|
|
1323
|
+
"the vbscript: scheme executes script",
|
|
1324
|
+
"-moz-binding loads and runs remote XBL",
|
|
1325
|
+
"behavior: loads and runs a remote HTC script",
|
|
1326
|
+
"@import pulls in a remote stylesheet",
|
|
1327
|
+
"image-set() fetches remote images, the same exfiltration channel as url()",
|
|
1328
|
+
"filter:progid activates legacy scriptable filters"
|
|
1329
|
+
];
|
|
1330
|
+
const declaration = ctx?.property ? `${ctx.property}: ${value}` : value;
|
|
1331
|
+
const where = describeElement(ctx?.element);
|
|
1332
|
+
const key = `${where}|${declaration}`;
|
|
1333
|
+
if (warnedDeclarations.has(key)) return "";
|
|
1334
|
+
if (warnedDeclarations.size >= MAX_WARNED_DECLARATIONS) {
|
|
1335
|
+
if (declarationCapAnnounced) return "";
|
|
1336
|
+
declarationCapAnnounced = true;
|
|
1337
|
+
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.`;
|
|
1338
|
+
}
|
|
1339
|
+
warnedDeclarations.add(key);
|
|
1340
|
+
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.`;
|
|
1341
|
+
});
|
|
1342
|
+
}
|
|
1343
|
+
function blockedCssReason(value) {
|
|
1344
|
+
if (!CSS_DANGER_GATE.test(value)) return -1;
|
|
1291
1345
|
const normalized = value.includes("\\") ? decodeCssEscapes(value) : value;
|
|
1292
1346
|
const lower = normalized.toLowerCase().replace(/\s+/g, "");
|
|
1293
|
-
|
|
1294
|
-
return
|
|
1347
|
+
for (let i = 0; i < BLOCKED_CSS_NEEDLES.length; i++) {
|
|
1348
|
+
if (lower.includes(BLOCKED_CSS_NEEDLES[i])) return i;
|
|
1295
1349
|
}
|
|
1296
|
-
return
|
|
1350
|
+
return -1;
|
|
1351
|
+
}
|
|
1352
|
+
function sanitizeCSSValue(value, context) {
|
|
1353
|
+
const reason = blockedCssReason(value);
|
|
1354
|
+
if (reason === -1) return value;
|
|
1355
|
+
warnDroppedDeclaration(value, reason, context);
|
|
1356
|
+
return "";
|
|
1297
1357
|
}
|
|
1298
|
-
function sanitizeStyleAttribute(cssText) {
|
|
1358
|
+
function sanitizeStyleAttribute(cssText, context) {
|
|
1299
1359
|
const input = String(cssText);
|
|
1300
1360
|
if (input.trim() === "") return "";
|
|
1301
1361
|
if (typeof document === "undefined") {
|
|
1302
|
-
return sanitizeCSSValue(input) === "" ? "" : input;
|
|
1362
|
+
return sanitizeCSSValue(input, context) === "" ? "" : input;
|
|
1303
1363
|
}
|
|
1304
1364
|
const probe = document.createElement("div");
|
|
1305
1365
|
try {
|
|
@@ -1311,8 +1371,12 @@ function sanitizeStyleAttribute(cssText) {
|
|
|
1311
1371
|
for (let i = 0; i < probe.style.length; i++) {
|
|
1312
1372
|
const property = probe.style[i];
|
|
1313
1373
|
const value = probe.style.getPropertyValue(property);
|
|
1314
|
-
|
|
1315
|
-
if (
|
|
1374
|
+
let reason = blockedCssReason(value);
|
|
1375
|
+
if (reason === -1) reason = blockedCssReason(`${property}:${value}`);
|
|
1376
|
+
if (reason !== -1) {
|
|
1377
|
+
warnDroppedDeclaration(value, reason, { property, element: context?.element });
|
|
1378
|
+
continue;
|
|
1379
|
+
}
|
|
1316
1380
|
const priority = probe.style.getPropertyPriority(property);
|
|
1317
1381
|
declarations.push(`${property}: ${value}${priority ? ` !${priority}` : ""}`);
|
|
1318
1382
|
}
|
|
@@ -1340,16 +1404,15 @@ var HTML_CONTENT_ATTRIBUTES = /* @__PURE__ */ new Set(["srcdoc"]);
|
|
|
1340
1404
|
function isHtmlContentAttribute(name) {
|
|
1341
1405
|
return HTML_CONTENT_ATTRIBUTES.has(name.toLowerCase());
|
|
1342
1406
|
}
|
|
1343
|
-
function sanitizeAttributeString(attr, value) {
|
|
1407
|
+
function sanitizeAttributeString(attr, value, context) {
|
|
1344
1408
|
const lower = attr.toLowerCase();
|
|
1345
1409
|
if (lower === "srcset") return sanitizeSrcset(value);
|
|
1346
1410
|
if (URL_ATTRIBUTES.has(lower)) return sanitizeUrl(value);
|
|
1347
|
-
if (lower === "style") return sanitizeStyleAttribute(value);
|
|
1411
|
+
if (lower === "style") return sanitizeStyleAttribute(value, context);
|
|
1348
1412
|
return value;
|
|
1349
1413
|
}
|
|
1350
1414
|
|
|
1351
1415
|
// src/utils/setSafeAttribute.ts
|
|
1352
|
-
var _isDev4 = isDev();
|
|
1353
1416
|
var HTML_NS = "http://www.w3.org/1999/xhtml";
|
|
1354
1417
|
var SVG_NS = "http://www.w3.org/2000/svg";
|
|
1355
1418
|
var XLINK_NS = "http://www.w3.org/1999/xlink";
|
|
@@ -1372,7 +1435,7 @@ function setSafeAttribute(el, name, value, options = {}) {
|
|
|
1372
1435
|
const ns = namespaceFor(el, name);
|
|
1373
1436
|
const localName = ns ? name.slice(name.indexOf(":") + 1) : name;
|
|
1374
1437
|
if (isEventHandlerAttr(name)) {
|
|
1375
|
-
if (
|
|
1438
|
+
if (DEV) {
|
|
1376
1439
|
devWarn(
|
|
1377
1440
|
`${options.label ?? "setSafeAttribute"}: refusing to set event-handler attribute "${name}". Its value would be evaluated as JavaScript. Use on:{ ${name.slice(2)}: fn } instead.`
|
|
1378
1441
|
);
|
|
@@ -1387,7 +1450,7 @@ function setSafeAttribute(el, name, value, options = {}) {
|
|
|
1387
1450
|
return true;
|
|
1388
1451
|
}
|
|
1389
1452
|
if (isHtmlContentAttribute(name)) {
|
|
1390
|
-
if (
|
|
1453
|
+
if (DEV) {
|
|
1391
1454
|
devWarn(
|
|
1392
1455
|
`${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.`
|
|
1393
1456
|
);
|
|
@@ -1416,7 +1479,7 @@ function setSafeAttribute(el, name, value, options = {}) {
|
|
|
1416
1479
|
setProp(el, idlName, idlName === "checked" ? Boolean(value) : str);
|
|
1417
1480
|
return true;
|
|
1418
1481
|
}
|
|
1419
|
-
const safe = sanitizeAttributeString(name, str);
|
|
1482
|
+
const safe = sanitizeAttributeString(name, str, { element: el });
|
|
1420
1483
|
const current = ns ? el.getAttributeNS(ns, localName) : el.getAttribute(name);
|
|
1421
1484
|
if (current === safe) return true;
|
|
1422
1485
|
if (ns) el.setAttributeNS(ns, name, safe);
|
|
@@ -1454,7 +1517,6 @@ function reportDrainRunaway(label, executed, remaining) {
|
|
|
1454
1517
|
{ executed, remaining }
|
|
1455
1518
|
);
|
|
1456
1519
|
}
|
|
1457
|
-
var _isDev5 = isDev();
|
|
1458
1520
|
var activeBindingCount = 0;
|
|
1459
1521
|
function registerDisposer(node, teardown) {
|
|
1460
1522
|
let disposers = elementDisposers.get(node);
|
|
@@ -1463,7 +1525,7 @@ function registerDisposer(node, teardown) {
|
|
|
1463
1525
|
elementDisposers.set(node, disposers);
|
|
1464
1526
|
}
|
|
1465
1527
|
disposers.push(teardown);
|
|
1466
|
-
if (
|
|
1528
|
+
if (DEV) activeBindingCount++;
|
|
1467
1529
|
}
|
|
1468
1530
|
function dispose(node) {
|
|
1469
1531
|
const stack = [node];
|
|
@@ -1486,13 +1548,13 @@ function dispose(node) {
|
|
|
1486
1548
|
if (!pending || pending.length === 0) break;
|
|
1487
1549
|
const snapshot = pending.slice();
|
|
1488
1550
|
elementDisposers.delete(current);
|
|
1489
|
-
if (
|
|
1551
|
+
if (DEV) activeBindingCount -= snapshot.length;
|
|
1490
1552
|
for (let i2 = 0; i2 < snapshot.length; i2++) {
|
|
1491
1553
|
if (executed >= MAX_DRAIN_TEARDOWNS) {
|
|
1492
1554
|
const rest = snapshot.slice(i2);
|
|
1493
1555
|
const added = elementDisposers.get(current);
|
|
1494
1556
|
elementDisposers.set(current, added ? rest.concat(added) : rest);
|
|
1495
|
-
if (
|
|
1557
|
+
if (DEV) activeBindingCount += rest.length;
|
|
1496
1558
|
reportDrainRunaway("dispose", executed, rest.length + (added?.length ?? 0));
|
|
1497
1559
|
runaway = true;
|
|
1498
1560
|
break;
|
|
@@ -1509,8 +1571,101 @@ function dispose(node) {
|
|
|
1509
1571
|
}
|
|
1510
1572
|
}
|
|
1511
1573
|
|
|
1574
|
+
// src/core/rendering/focusPreservation.ts
|
|
1575
|
+
var IDENTITY_ATTRS = ["data-focus-key", "id", "name"];
|
|
1576
|
+
var SELECTABLE_TYPES = /* @__PURE__ */ new Set(["text", "search", "url", "tel", "password", ""]);
|
|
1577
|
+
function selectionOf(el) {
|
|
1578
|
+
const tag = el.tagName;
|
|
1579
|
+
const selectable = tag === "TEXTAREA" || tag === "INPUT" && SELECTABLE_TYPES.has(el.type.toLowerCase());
|
|
1580
|
+
if (!selectable) return { start: null, end: null, direction: null };
|
|
1581
|
+
const field = el;
|
|
1582
|
+
return { start: field.selectionStart, end: field.selectionEnd, direction: field.selectionDirection };
|
|
1583
|
+
}
|
|
1584
|
+
function captureFocusWithin(nodes) {
|
|
1585
|
+
if (nodes.length === 0 || typeof document === "undefined") return null;
|
|
1586
|
+
const active = document.activeElement;
|
|
1587
|
+
if (!active || active === document.body) return null;
|
|
1588
|
+
let inside = false;
|
|
1589
|
+
for (let i = 0; i < nodes.length; i++) {
|
|
1590
|
+
const n = nodes[i];
|
|
1591
|
+
if (n === active || n.nodeType === 1 && n.contains(active)) {
|
|
1592
|
+
inside = true;
|
|
1593
|
+
break;
|
|
1594
|
+
}
|
|
1595
|
+
}
|
|
1596
|
+
if (!inside) return null;
|
|
1597
|
+
let attr = null;
|
|
1598
|
+
let value = null;
|
|
1599
|
+
for (let i = 0; i < IDENTITY_ATTRS.length; i++) {
|
|
1600
|
+
const candidate = active.getAttribute(IDENTITY_ATTRS[i]);
|
|
1601
|
+
if (candidate) {
|
|
1602
|
+
attr = IDENTITY_ATTRS[i];
|
|
1603
|
+
value = candidate;
|
|
1604
|
+
break;
|
|
1605
|
+
}
|
|
1606
|
+
}
|
|
1607
|
+
return { el: active, attr, value, tag: active.tagName, ...selectionOf(active) };
|
|
1608
|
+
}
|
|
1609
|
+
function quote(value) {
|
|
1610
|
+
return `"${value.replace(/\\/g, "\\\\").replace(/"/g, '\\"')}"`;
|
|
1611
|
+
}
|
|
1612
|
+
function findUniqueByIdentity(nodes, selector) {
|
|
1613
|
+
let el = null;
|
|
1614
|
+
let count = 0;
|
|
1615
|
+
for (let i = 0; i < nodes.length; i++) {
|
|
1616
|
+
const n = nodes[i];
|
|
1617
|
+
if (n.nodeType !== 1) continue;
|
|
1618
|
+
const root = n;
|
|
1619
|
+
if (root.matches(selector)) {
|
|
1620
|
+
count++;
|
|
1621
|
+
el ?? (el = root);
|
|
1622
|
+
}
|
|
1623
|
+
const inner = root.querySelectorAll(selector);
|
|
1624
|
+
for (let j = 0; j < inner.length; j++) {
|
|
1625
|
+
count++;
|
|
1626
|
+
el ?? (el = inner[j]);
|
|
1627
|
+
}
|
|
1628
|
+
if (count > 1) return { el: null, count };
|
|
1629
|
+
}
|
|
1630
|
+
return count === 1 ? { el, count } : { el: null, count };
|
|
1631
|
+
}
|
|
1632
|
+
function refocus(el, snapshot) {
|
|
1633
|
+
el.focus();
|
|
1634
|
+
if (snapshot.start !== null && typeof el.setSelectionRange === "function") {
|
|
1635
|
+
const field = el;
|
|
1636
|
+
const max = field.value.length;
|
|
1637
|
+
const start = Math.min(snapshot.start, max);
|
|
1638
|
+
const end = Math.min(snapshot.end ?? start, max);
|
|
1639
|
+
field.setSelectionRange(start, end, snapshot.direction ?? "none");
|
|
1640
|
+
}
|
|
1641
|
+
}
|
|
1642
|
+
function restoreFocusWithin(snapshot, nodes, where) {
|
|
1643
|
+
if (!snapshot) return;
|
|
1644
|
+
if (typeof document === "undefined") return;
|
|
1645
|
+
const active = document.activeElement;
|
|
1646
|
+
if (active === snapshot.el) return;
|
|
1647
|
+
if (active && active !== document.body && active !== document.documentElement) return;
|
|
1648
|
+
if (snapshot.el.isConnected) {
|
|
1649
|
+
refocus(snapshot.el, snapshot);
|
|
1650
|
+
return;
|
|
1651
|
+
}
|
|
1652
|
+
let ambiguous = false;
|
|
1653
|
+
if (snapshot.attr && snapshot.value) {
|
|
1654
|
+
const { el: replacement, count } = findUniqueByIdentity(nodes, `[${snapshot.attr}=${quote(snapshot.value)}]`);
|
|
1655
|
+
if (replacement && replacement.tagName === snapshot.tag) {
|
|
1656
|
+
refocus(replacement, snapshot);
|
|
1657
|
+
return;
|
|
1658
|
+
}
|
|
1659
|
+
ambiguous = count > 1;
|
|
1660
|
+
}
|
|
1661
|
+
devWarnLazy(() => {
|
|
1662
|
+
const id = snapshot.attr ? ` (${snapshot.attr}="${snapshot.value}")` : "";
|
|
1663
|
+
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";
|
|
1664
|
+
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.`;
|
|
1665
|
+
});
|
|
1666
|
+
}
|
|
1667
|
+
|
|
1512
1668
|
// src/reactivity/bindChildNode.ts
|
|
1513
|
-
var _isDev6 = isDev();
|
|
1514
1669
|
function bindChildNode(placeholder, getter) {
|
|
1515
1670
|
let lastNodes = [];
|
|
1516
1671
|
function commit() {
|
|
@@ -1521,6 +1676,7 @@ function bindChildNode(placeholder, getter) {
|
|
|
1521
1676
|
reportError(err, { phase: "binding", name: "bindChildNode", node: placeholder });
|
|
1522
1677
|
return;
|
|
1523
1678
|
}
|
|
1679
|
+
const focused = captureFocusWithin(lastNodes);
|
|
1524
1680
|
if (result == null || typeof result === "boolean") {
|
|
1525
1681
|
for (let i = 0; i < lastNodes.length; i++) {
|
|
1526
1682
|
const node = lastNodes[i];
|
|
@@ -1528,6 +1684,7 @@ function bindChildNode(placeholder, getter) {
|
|
|
1528
1684
|
if (node.parentNode) node.parentNode.removeChild(node);
|
|
1529
1685
|
}
|
|
1530
1686
|
lastNodes.length = 0;
|
|
1687
|
+
restoreFocusWithin(focused, lastNodes, "bindChildNode");
|
|
1531
1688
|
return;
|
|
1532
1689
|
}
|
|
1533
1690
|
const parent = placeholder.parentNode;
|
|
@@ -1544,8 +1701,7 @@ function bindChildNode(placeholder, getter) {
|
|
|
1544
1701
|
if (item == null || typeof item === "boolean") continue;
|
|
1545
1702
|
const node = item instanceof Node ? item : document.createTextNode(String(item));
|
|
1546
1703
|
if (seen.has(node)) {
|
|
1547
|
-
if (
|
|
1548
|
-
devWarn("bindChildNode: duplicate node reference in array \u2014 only the first occurrence is rendered.");
|
|
1704
|
+
if (DEV) devWarn("bindChildNode: duplicate node reference in array \u2014 only the first occurrence is rendered.");
|
|
1549
1705
|
continue;
|
|
1550
1706
|
}
|
|
1551
1707
|
seen.add(node);
|
|
@@ -1578,12 +1734,12 @@ function bindChildNode(placeholder, getter) {
|
|
|
1578
1734
|
prev = node;
|
|
1579
1735
|
}
|
|
1580
1736
|
lastNodes = newNodes;
|
|
1737
|
+
restoreFocusWithin(focused, newNodes, "bindChildNode");
|
|
1581
1738
|
}
|
|
1582
1739
|
return reactiveBinding2(commit, placeholder);
|
|
1583
1740
|
}
|
|
1584
1741
|
|
|
1585
1742
|
// src/core/rendering/tagFactory.ts
|
|
1586
|
-
var _isDev7 = isDev();
|
|
1587
1743
|
var BLOCKED_TAGS = /* @__PURE__ */ new Set(["script", "iframe", "object", "embed", "frame", "frameset"]);
|
|
1588
1744
|
function isBlockedTag(tag) {
|
|
1589
1745
|
return BLOCKED_TAGS.has(tag.toLowerCase());
|
|
@@ -1601,18 +1757,9 @@ var CLOBBER_RISKY_IDS = /* @__PURE__ */ new Set([
|
|
|
1601
1757
|
"self",
|
|
1602
1758
|
"frames"
|
|
1603
1759
|
]);
|
|
1604
|
-
|
|
1605
|
-
|
|
1606
|
-
|
|
1607
|
-
const tokens = t.split(/\s+/);
|
|
1608
|
-
let sawClassish = false;
|
|
1609
|
-
for (let i = 0; i < tokens.length; i++) {
|
|
1610
|
-
const tok = tokens[i];
|
|
1611
|
-
if (!/^-?[A-Za-z_][A-Za-z0-9_:/.-]*$/.test(tok)) return false;
|
|
1612
|
-
if (/[-:/0-9]/.test(tok)) sawClassish = true;
|
|
1613
|
-
}
|
|
1614
|
-
return sawClassish;
|
|
1615
|
-
}
|
|
1760
|
+
var warnedLoneStrings = /* @__PURE__ */ new Set();
|
|
1761
|
+
var MAX_WARNED_LONE_STRINGS = 100;
|
|
1762
|
+
var loneStringCapAnnounced = false;
|
|
1616
1763
|
var kebabCache = /* @__PURE__ */ new Map();
|
|
1617
1764
|
function toKebab(prop) {
|
|
1618
1765
|
let cached = kebabCache.get(prop);
|
|
@@ -1624,13 +1771,13 @@ function toKebab(prop) {
|
|
|
1624
1771
|
function applyStyle(el, style) {
|
|
1625
1772
|
if (typeof style === "function") {
|
|
1626
1773
|
const teardown = reactiveBinding2(() => {
|
|
1627
|
-
el.setAttribute("style", sanitizeStyleAttribute(String(style())));
|
|
1774
|
+
el.setAttribute("style", sanitizeStyleAttribute(String(style()), { element: el }));
|
|
1628
1775
|
}, el);
|
|
1629
1776
|
registerDisposer(el, teardown);
|
|
1630
1777
|
return;
|
|
1631
1778
|
}
|
|
1632
1779
|
if (typeof style === "string") {
|
|
1633
|
-
el.setAttribute("style", sanitizeStyleAttribute(style));
|
|
1780
|
+
el.setAttribute("style", sanitizeStyleAttribute(style, { element: el }));
|
|
1634
1781
|
return;
|
|
1635
1782
|
}
|
|
1636
1783
|
const htmlEl = el;
|
|
@@ -1640,11 +1787,11 @@ function applyStyle(el, style) {
|
|
|
1640
1787
|
if (typeof val === "function") {
|
|
1641
1788
|
const getter = val;
|
|
1642
1789
|
const teardown = reactiveBinding2(() => {
|
|
1643
|
-
htmlEl.style.setProperty(name, sanitizeCSSValue(String(getter())));
|
|
1790
|
+
htmlEl.style.setProperty(name, sanitizeCSSValue(String(getter()), { property: name, element: el }));
|
|
1644
1791
|
}, el);
|
|
1645
1792
|
registerDisposer(el, teardown);
|
|
1646
1793
|
} else {
|
|
1647
|
-
htmlEl.style.setProperty(name, sanitizeCSSValue(String(val)));
|
|
1794
|
+
htmlEl.style.setProperty(name, sanitizeCSSValue(String(val), { property: name, element: el }));
|
|
1648
1795
|
}
|
|
1649
1796
|
}
|
|
1650
1797
|
}
|
|
@@ -1751,11 +1898,26 @@ var tagFactory = (tag, ns) => {
|
|
|
1751
1898
|
appendChildren(el, second);
|
|
1752
1899
|
return el;
|
|
1753
1900
|
}
|
|
1754
|
-
|
|
1755
|
-
|
|
1756
|
-
|
|
1757
|
-
|
|
1758
|
-
|
|
1901
|
+
devWarnLazy(() => {
|
|
1902
|
+
const tokens = first.trim().split(/\s+/);
|
|
1903
|
+
if (tokens.length < 2) return "";
|
|
1904
|
+
let utilityTokens = 0;
|
|
1905
|
+
for (let i = 0; i < tokens.length; i++) {
|
|
1906
|
+
const tok = tokens[i];
|
|
1907
|
+
if (!/^-?[A-Za-z_][A-Za-z0-9_:/.-]*$/.test(tok)) return "";
|
|
1908
|
+
if (/[-:/0-9]/.test(tok)) utilityTokens++;
|
|
1909
|
+
}
|
|
1910
|
+
if (utilityTokens < 2) return "";
|
|
1911
|
+
const key = `${tag}|${first}`;
|
|
1912
|
+
if (warnedLoneStrings.has(key)) return "";
|
|
1913
|
+
if (warnedLoneStrings.size >= MAX_WARNED_LONE_STRINGS) {
|
|
1914
|
+
if (loneStringCapAnnounced) return "";
|
|
1915
|
+
loneStringCapAnnounced = true;
|
|
1916
|
+
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.`;
|
|
1917
|
+
}
|
|
1918
|
+
warnedLoneStrings.add(key);
|
|
1919
|
+
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.`;
|
|
1920
|
+
});
|
|
1759
1921
|
el.textContent = first;
|
|
1760
1922
|
return el;
|
|
1761
1923
|
}
|
|
@@ -1772,7 +1934,7 @@ var tagFactory = (tag, ns) => {
|
|
|
1772
1934
|
if (pClass != null) applyClass(el, pClass);
|
|
1773
1935
|
const pId = props.id;
|
|
1774
1936
|
if (pId != null) {
|
|
1775
|
-
if (
|
|
1937
|
+
if (DEV && typeof pId === "string" && CLOBBER_RISKY_IDS.has(pId.toLowerCase())) {
|
|
1776
1938
|
devWarn(
|
|
1777
1939
|
`tagFactory: element id="${pId}" matches a common global and may cause DOM clobbering. Avoid setting ids from untrusted input.`
|
|
1778
1940
|
);
|
|
@@ -1787,7 +1949,7 @@ var tagFactory = (tag, ns) => {
|
|
|
1787
1949
|
const handler = pOn[ev];
|
|
1788
1950
|
if (typeof handler === "function") {
|
|
1789
1951
|
el.addEventListener(ev, handler);
|
|
1790
|
-
} else if (
|
|
1952
|
+
} else if (DEV) {
|
|
1791
1953
|
devWarn(
|
|
1792
1954
|
`tagFactory: on.${ev} handler is not a function (got ${typeof handler}). Event listener was not attached.`
|
|
1793
1955
|
);
|
package/dist/ecosystem.js
CHANGED
|
@@ -7,19 +7,19 @@ import {
|
|
|
7
7
|
mobXAdapter,
|
|
8
8
|
reduxAdapter,
|
|
9
9
|
zustandAdapter
|
|
10
|
-
} from "./chunk-
|
|
10
|
+
} from "./chunk-GDUNQCCW.js";
|
|
11
11
|
import "./chunk-WWV3SJ3L.js";
|
|
12
|
-
import "./chunk-
|
|
13
|
-
import "./chunk-
|
|
14
|
-
import "./chunk-
|
|
15
|
-
import "./chunk-
|
|
12
|
+
import "./chunk-6ZGI3RBE.js";
|
|
13
|
+
import "./chunk-HJEPKZ2O.js";
|
|
14
|
+
import "./chunk-2LOYNGBY.js";
|
|
15
|
+
import "./chunk-IXKSNWV5.js";
|
|
16
16
|
import "./chunk-7ZHH77QA.js";
|
|
17
|
-
import "./chunk-
|
|
18
|
-
import "./chunk-
|
|
19
|
-
import "./chunk-
|
|
20
|
-
import "./chunk-
|
|
21
|
-
import "./chunk-
|
|
22
|
-
import "./chunk-
|
|
17
|
+
import "./chunk-7VEC3UD2.js";
|
|
18
|
+
import "./chunk-5DXA2J44.js";
|
|
19
|
+
import "./chunk-QKRPLZ2V.js";
|
|
20
|
+
import "./chunk-HECVW343.js";
|
|
21
|
+
import "./chunk-7ALC7KGE.js";
|
|
22
|
+
import "./chunk-2WLZ6757.js";
|
|
23
23
|
export {
|
|
24
24
|
antdAdapter,
|
|
25
25
|
chakraAdapter,
|