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/plugins.cjs
CHANGED
|
@@ -22,29 +22,34 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
22
22
|
|
|
23
23
|
// src/core/dev.ts
|
|
24
24
|
function isDev() {
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
// this branch is unreachable here.
|
|
29
|
-
/* v8 ignore next 2 */
|
|
30
|
-
typeof __SIBU_DEV__ !== "undefined" ? __SIBU_DEV__ : typeof process !== "undefined" && process.env?.NODE_ENV !== "production"
|
|
31
|
-
);
|
|
25
|
+
if (typeof globalThis.__SIBU_DEV__ !== "undefined") return !!globalThis.__SIBU_DEV__;
|
|
26
|
+
if (typeof __SIBU_DEV__ !== "undefined") return !!__SIBU_DEV__;
|
|
27
|
+
return typeof process !== "undefined" && process.env?.NODE_ENV !== "production";
|
|
32
28
|
}
|
|
33
29
|
function devAssert(condition, message) {
|
|
34
|
-
if (
|
|
30
|
+
if ((typeof __SIBU_DEV__ !== "undefined" ? __SIBU_DEV__ : DEV) && !condition) {
|
|
35
31
|
throw new Error(`[SibuJS] ${message}`);
|
|
36
32
|
}
|
|
37
33
|
}
|
|
34
|
+
function devWarnLazy(build) {
|
|
35
|
+
if (typeof __SIBU_DEV__ !== "undefined" ? __SIBU_DEV__ : DEV) {
|
|
36
|
+
const message = build();
|
|
37
|
+
if (message) console.warn(`[SibuJS] ${message}`);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
38
40
|
function devWarn(message) {
|
|
39
|
-
if (
|
|
41
|
+
if (typeof __SIBU_DEV__ !== "undefined" ? __SIBU_DEV__ : DEV) {
|
|
40
42
|
console.warn(`[SibuJS] ${message}`);
|
|
41
43
|
}
|
|
42
44
|
}
|
|
43
|
-
var
|
|
45
|
+
var DEV;
|
|
44
46
|
var init_dev = __esm({
|
|
45
47
|
"src/core/dev.ts"() {
|
|
46
48
|
"use strict";
|
|
47
|
-
|
|
49
|
+
DEV = typeof __SIBU_DEV__ !== "undefined" ? !!__SIBU_DEV__ : typeof globalThis.__SIBU_DEV__ !== "undefined" ? !!globalThis.__SIBU_DEV__ : (
|
|
50
|
+
// safe default: off in browser, on in test/dev Node
|
|
51
|
+
typeof process !== "undefined" && process.env?.NODE_ENV !== "production"
|
|
52
|
+
);
|
|
48
53
|
}
|
|
49
54
|
});
|
|
50
55
|
|
|
@@ -234,20 +239,61 @@ function decodeCssEscapes(value) {
|
|
|
234
239
|
}
|
|
235
240
|
return out;
|
|
236
241
|
}
|
|
237
|
-
function
|
|
238
|
-
if (!
|
|
242
|
+
function describeElement(el) {
|
|
243
|
+
if (!el) return "an element";
|
|
244
|
+
let out = el.tagName.toLowerCase();
|
|
245
|
+
const id = el.getAttribute("id");
|
|
246
|
+
if (id) out += `#${id}`;
|
|
247
|
+
const cls = el.getAttribute("class");
|
|
248
|
+
if (cls) out += `.${cls.trim().split(/\s+/).slice(0, 3).join(".")}`;
|
|
249
|
+
return `<${out}>`;
|
|
250
|
+
}
|
|
251
|
+
function warnDroppedDeclaration(value, reason, ctx) {
|
|
252
|
+
devWarnLazy(() => {
|
|
253
|
+
const reasons = [
|
|
254
|
+
"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",
|
|
255
|
+
"expression() executes arbitrary script in legacy engines",
|
|
256
|
+
"the javascript: scheme executes script",
|
|
257
|
+
"the vbscript: scheme executes script",
|
|
258
|
+
"-moz-binding loads and runs remote XBL",
|
|
259
|
+
"behavior: loads and runs a remote HTC script",
|
|
260
|
+
"@import pulls in a remote stylesheet",
|
|
261
|
+
"image-set() fetches remote images, the same exfiltration channel as url()",
|
|
262
|
+
"filter:progid activates legacy scriptable filters"
|
|
263
|
+
];
|
|
264
|
+
const declaration = ctx?.property ? `${ctx.property}: ${value}` : value;
|
|
265
|
+
const where = describeElement(ctx?.element);
|
|
266
|
+
const key = `${where}|${declaration}`;
|
|
267
|
+
if (warnedDeclarations.has(key)) return "";
|
|
268
|
+
if (warnedDeclarations.size >= MAX_WARNED_DECLARATIONS) {
|
|
269
|
+
if (declarationCapAnnounced) return "";
|
|
270
|
+
declarationCapAnnounced = true;
|
|
271
|
+
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.`;
|
|
272
|
+
}
|
|
273
|
+
warnedDeclarations.add(key);
|
|
274
|
+
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.`;
|
|
275
|
+
});
|
|
276
|
+
}
|
|
277
|
+
function blockedCssReason(value) {
|
|
278
|
+
if (!CSS_DANGER_GATE.test(value)) return -1;
|
|
239
279
|
const normalized = value.includes("\\") ? decodeCssEscapes(value) : value;
|
|
240
280
|
const lower = normalized.toLowerCase().replace(/\s+/g, "");
|
|
241
|
-
|
|
242
|
-
return
|
|
281
|
+
for (let i2 = 0; i2 < BLOCKED_CSS_NEEDLES.length; i2++) {
|
|
282
|
+
if (lower.includes(BLOCKED_CSS_NEEDLES[i2])) return i2;
|
|
243
283
|
}
|
|
244
|
-
return
|
|
284
|
+
return -1;
|
|
285
|
+
}
|
|
286
|
+
function sanitizeCSSValue(value, context) {
|
|
287
|
+
const reason = blockedCssReason(value);
|
|
288
|
+
if (reason === -1) return value;
|
|
289
|
+
warnDroppedDeclaration(value, reason, context);
|
|
290
|
+
return "";
|
|
245
291
|
}
|
|
246
|
-
function sanitizeStyleAttribute(cssText) {
|
|
292
|
+
function sanitizeStyleAttribute(cssText, context) {
|
|
247
293
|
const input2 = String(cssText);
|
|
248
294
|
if (input2.trim() === "") return "";
|
|
249
295
|
if (typeof document === "undefined") {
|
|
250
|
-
return sanitizeCSSValue(input2) === "" ? "" : input2;
|
|
296
|
+
return sanitizeCSSValue(input2, context) === "" ? "" : input2;
|
|
251
297
|
}
|
|
252
298
|
const probe = document.createElement("div");
|
|
253
299
|
try {
|
|
@@ -259,8 +305,12 @@ function sanitizeStyleAttribute(cssText) {
|
|
|
259
305
|
for (let i2 = 0; i2 < probe.style.length; i2++) {
|
|
260
306
|
const property = probe.style[i2];
|
|
261
307
|
const value = probe.style.getPropertyValue(property);
|
|
262
|
-
|
|
263
|
-
if (
|
|
308
|
+
let reason = blockedCssReason(value);
|
|
309
|
+
if (reason === -1) reason = blockedCssReason(`${property}:${value}`);
|
|
310
|
+
if (reason !== -1) {
|
|
311
|
+
warnDroppedDeclaration(value, reason, { property, element: context?.element });
|
|
312
|
+
continue;
|
|
313
|
+
}
|
|
264
314
|
const priority = probe.style.getPropertyPriority(property);
|
|
265
315
|
declarations.push(`${property}: ${value}${priority ? ` !${priority}` : ""}`);
|
|
266
316
|
}
|
|
@@ -276,21 +326,36 @@ function isPolicyAttribute(name) {
|
|
|
276
326
|
const lower = name.toLowerCase();
|
|
277
327
|
return lower === "style" || URL_ATTRIBUTES.has(lower);
|
|
278
328
|
}
|
|
279
|
-
function sanitizeAttributeString(attr, value) {
|
|
329
|
+
function sanitizeAttributeString(attr, value, context) {
|
|
280
330
|
const lower = attr.toLowerCase();
|
|
281
331
|
if (lower === "srcset") return sanitizeSrcset(value);
|
|
282
332
|
if (URL_ATTRIBUTES.has(lower)) return sanitizeUrl(value);
|
|
283
|
-
if (lower === "style") return sanitizeStyleAttribute(value);
|
|
333
|
+
if (lower === "style") return sanitizeStyleAttribute(value, context);
|
|
284
334
|
return value;
|
|
285
335
|
}
|
|
286
|
-
var SAFE_URL_PROTOCOLS, OUTER_TRIM, SRCSET_DESCRIPTOR, CSS_DANGER_GATE, URL_ATTRIBUTES, HTML_CONTENT_ATTRIBUTES;
|
|
336
|
+
var SAFE_URL_PROTOCOLS, OUTER_TRIM, SRCSET_DESCRIPTOR, CSS_DANGER_GATE, BLOCKED_CSS_NEEDLES, warnedDeclarations, MAX_WARNED_DECLARATIONS, declarationCapAnnounced, URL_ATTRIBUTES, HTML_CONTENT_ATTRIBUTES;
|
|
287
337
|
var init_sanitize = __esm({
|
|
288
338
|
"src/utils/sanitize.ts"() {
|
|
289
339
|
"use strict";
|
|
340
|
+
init_dev();
|
|
290
341
|
SAFE_URL_PROTOCOLS = ["http:", "https:", "mailto:", "tel:", "ftp:"];
|
|
291
342
|
OUTER_TRIM = /^[\x00-\x20\x7f-\x9f]+|[\x00-\x20\x7f-\x9f]+$/g;
|
|
292
343
|
SRCSET_DESCRIPTOR = /^\s+\d+(\.\d+)?[wx]$/;
|
|
293
344
|
CSS_DANGER_GATE = /[(:@\\]/;
|
|
345
|
+
BLOCKED_CSS_NEEDLES = [
|
|
346
|
+
"url(",
|
|
347
|
+
"expression(",
|
|
348
|
+
"javascript:",
|
|
349
|
+
"vbscript:",
|
|
350
|
+
"-moz-binding",
|
|
351
|
+
"behavior:",
|
|
352
|
+
"@import",
|
|
353
|
+
"image-set(",
|
|
354
|
+
"filter:progid"
|
|
355
|
+
];
|
|
356
|
+
warnedDeclarations = /* @__PURE__ */ new Set();
|
|
357
|
+
MAX_WARNED_DECLARATIONS = 100;
|
|
358
|
+
declarationCapAnnounced = false;
|
|
294
359
|
URL_ATTRIBUTES = /* @__PURE__ */ new Set([
|
|
295
360
|
"href",
|
|
296
361
|
"xlink:href",
|
|
@@ -338,7 +403,7 @@ function registerDisposer(node, teardown) {
|
|
|
338
403
|
elementDisposers.set(node, disposers);
|
|
339
404
|
}
|
|
340
405
|
disposers.push(teardown);
|
|
341
|
-
if (
|
|
406
|
+
if (DEV) activeBindingCount++;
|
|
342
407
|
}
|
|
343
408
|
function unregisterDisposer(node, teardown) {
|
|
344
409
|
const disposers = elementDisposers.get(node);
|
|
@@ -346,7 +411,7 @@ function unregisterDisposer(node, teardown) {
|
|
|
346
411
|
const index = disposers.indexOf(teardown);
|
|
347
412
|
if (index === -1) return;
|
|
348
413
|
disposers.splice(index, 1);
|
|
349
|
-
if (
|
|
414
|
+
if (DEV) activeBindingCount--;
|
|
350
415
|
if (disposers.length === 0) elementDisposers.delete(node);
|
|
351
416
|
}
|
|
352
417
|
function dispose(node) {
|
|
@@ -370,13 +435,13 @@ function dispose(node) {
|
|
|
370
435
|
if (!pending || pending.length === 0) break;
|
|
371
436
|
const snapshot = pending.slice();
|
|
372
437
|
elementDisposers.delete(current);
|
|
373
|
-
if (
|
|
438
|
+
if (DEV) activeBindingCount -= snapshot.length;
|
|
374
439
|
for (let i3 = 0; i3 < snapshot.length; i3++) {
|
|
375
440
|
if (executed >= MAX_DRAIN_TEARDOWNS) {
|
|
376
441
|
const rest = snapshot.slice(i3);
|
|
377
442
|
const added = elementDisposers.get(current);
|
|
378
443
|
elementDisposers.set(current, added ? rest.concat(added) : rest);
|
|
379
|
-
if (
|
|
444
|
+
if (DEV) activeBindingCount += rest.length;
|
|
380
445
|
reportDrainRunaway("dispose", executed, rest.length + (added?.length ?? 0));
|
|
381
446
|
runaway = true;
|
|
382
447
|
break;
|
|
@@ -404,7 +469,7 @@ function replaceChildrenSafely(parent, ...next) {
|
|
|
404
469
|
parent.replaceChildren(...next);
|
|
405
470
|
}
|
|
406
471
|
function checkLeaks(warnThreshold = 0) {
|
|
407
|
-
if (!
|
|
472
|
+
if (!DEV) return 0;
|
|
408
473
|
if (warnThreshold > 0 && activeBindingCount > warnThreshold) {
|
|
409
474
|
devWarn(
|
|
410
475
|
`checkLeaks: ${activeBindingCount} active DOM bindings detected. Expected \u2264${warnThreshold}. This may indicate a component was removed from the DOM without calling dispose().`
|
|
@@ -412,7 +477,7 @@ function checkLeaks(warnThreshold = 0) {
|
|
|
412
477
|
}
|
|
413
478
|
return activeBindingCount;
|
|
414
479
|
}
|
|
415
|
-
var elementDisposers, MAX_DRAIN_TEARDOWNS,
|
|
480
|
+
var elementDisposers, MAX_DRAIN_TEARDOWNS, activeBindingCount;
|
|
416
481
|
var init_dispose = __esm({
|
|
417
482
|
"src/core/rendering/dispose.ts"() {
|
|
418
483
|
"use strict";
|
|
@@ -420,7 +485,6 @@ var init_dispose = __esm({
|
|
|
420
485
|
init_errors();
|
|
421
486
|
elementDisposers = /* @__PURE__ */ new WeakMap();
|
|
422
487
|
MAX_DRAIN_TEARDOWNS = 1e4;
|
|
423
|
-
_isDev4 = isDev();
|
|
424
488
|
activeBindingCount = 0;
|
|
425
489
|
}
|
|
426
490
|
});
|
|
@@ -507,9 +571,9 @@ function parseMetaRefreshContent(content) {
|
|
|
507
571
|
i2++;
|
|
508
572
|
while (i2 < raw.length && isAsciiWhitespace(raw[i2])) i2++;
|
|
509
573
|
let destination;
|
|
510
|
-
const
|
|
511
|
-
if (
|
|
512
|
-
const close = raw.indexOf(
|
|
574
|
+
const quote2 = raw[i2];
|
|
575
|
+
if (quote2 === '"' || quote2 === "'") {
|
|
576
|
+
const close = raw.indexOf(quote2, i2 + 1);
|
|
513
577
|
if (close === -1) return forbidden("unterminated quoted destination");
|
|
514
578
|
destination = raw.slice(i2 + 1, close);
|
|
515
579
|
const rest = trimAsciiWhitespace(raw.slice(close + 1));
|
|
@@ -681,7 +745,7 @@ function isSafeAttrName(name) {
|
|
|
681
745
|
return SAFE_ATTR_NAME.test(name);
|
|
682
746
|
}
|
|
683
747
|
function ssrErrorComment(err) {
|
|
684
|
-
if (
|
|
748
|
+
if (DEV) {
|
|
685
749
|
const msg = escapeHtml(err instanceof Error ? err.message : String(err));
|
|
686
750
|
return `<!--SSR error: ${safeCommentText(msg)}-->`;
|
|
687
751
|
}
|
|
@@ -711,10 +775,10 @@ function renderToString(element) {
|
|
|
711
775
|
}
|
|
712
776
|
const tag = element.tagName.toLowerCase();
|
|
713
777
|
if (tag === "script" || tag === "style") {
|
|
714
|
-
return
|
|
778
|
+
return DEV ? `<!--ssr:${tag}-stripped-->` : "";
|
|
715
779
|
}
|
|
716
780
|
if (!/^[a-z][a-z0-9-]*$/i.test(tag)) {
|
|
717
|
-
return
|
|
781
|
+
return DEV ? "<!--ssr:invalid-tag-->" : "";
|
|
718
782
|
}
|
|
719
783
|
let html2 = `<${tag}`;
|
|
720
784
|
for (const attr of Array.from(element.attributes)) {
|
|
@@ -756,7 +820,7 @@ function hydrate(component, container, options = {}) {
|
|
|
756
820
|
const first = mismatches[0];
|
|
757
821
|
if (options.onMismatch) {
|
|
758
822
|
options.onMismatch(first);
|
|
759
|
-
} else if (
|
|
823
|
+
} else if (DEV) {
|
|
760
824
|
console.warn(
|
|
761
825
|
`[SibuJS hydration] ${first.message}
|
|
762
826
|
at ${first.path}
|
|
@@ -957,11 +1021,11 @@ async function* renderToStream(element) {
|
|
|
957
1021
|
}
|
|
958
1022
|
const tag = element.tagName.toLowerCase();
|
|
959
1023
|
if (tag === "script" || tag === "style") {
|
|
960
|
-
if (
|
|
1024
|
+
if (DEV) yield `<!--ssr:${tag}-stripped-->`;
|
|
961
1025
|
return;
|
|
962
1026
|
}
|
|
963
1027
|
if (!/^[a-z][a-z0-9-]*$/i.test(tag)) {
|
|
964
|
-
if (
|
|
1028
|
+
if (DEV) yield "<!--ssr:invalid-tag-->";
|
|
965
1029
|
return;
|
|
966
1030
|
}
|
|
967
1031
|
let openTag = `<${tag}`;
|
|
@@ -1103,7 +1167,7 @@ function ssrSuspense(props) {
|
|
|
1103
1167
|
},
|
|
1104
1168
|
(err) => {
|
|
1105
1169
|
if (timer) clearTimeout(timer);
|
|
1106
|
-
if (
|
|
1170
|
+
if (DEV) console.warn("[SibuJS SSR] ssrSuspense rejected:", err);
|
|
1107
1171
|
return { id, html: fallbackHtml };
|
|
1108
1172
|
}
|
|
1109
1173
|
);
|
|
@@ -1146,7 +1210,7 @@ function serializeState(state2, nonce, options) {
|
|
|
1146
1210
|
}
|
|
1147
1211
|
function deserializeState(validate) {
|
|
1148
1212
|
if (typeof window === "undefined") return void 0;
|
|
1149
|
-
if (
|
|
1213
|
+
if (DEV && !validate) {
|
|
1150
1214
|
console.warn(
|
|
1151
1215
|
"[SibuJS SSR] deserializeState() called without a validate guard \u2014 tampered SSR payloads will not be detected."
|
|
1152
1216
|
);
|
|
@@ -1163,7 +1227,7 @@ function escapeHtml(str) {
|
|
|
1163
1227
|
function escapeAttr(str) {
|
|
1164
1228
|
return str.replace(/&/g, "&").replace(/"/g, """).replace(/'/g, "'").replace(/</g, "<").replace(/>/g, ">");
|
|
1165
1229
|
}
|
|
1166
|
-
var
|
|
1230
|
+
var SAFE_ATTR_NAME, VOID_ELEMENTS, SAFE_ID, SAFE_SUSPENSE_ID, SSR_DATA_ATTR, DEFAULT_MAX_SSR_BYTES;
|
|
1167
1231
|
var init_ssr = __esm({
|
|
1168
1232
|
"src/platform/ssr.ts"() {
|
|
1169
1233
|
"use strict";
|
|
@@ -1173,7 +1237,6 @@ var init_ssr = __esm({
|
|
|
1173
1237
|
init_headEntry();
|
|
1174
1238
|
init_metaRefresh();
|
|
1175
1239
|
init_sanitize();
|
|
1176
|
-
_isDev8 = isDev();
|
|
1177
1240
|
SAFE_ATTR_NAME = /^[A-Za-z_:][-A-Za-z0-9_.:]*$/;
|
|
1178
1241
|
VOID_ELEMENTS = /* @__PURE__ */ new Set([
|
|
1179
1242
|
"area",
|
|
@@ -1290,7 +1353,6 @@ init_sanitize();
|
|
|
1290
1353
|
// src/utils/setSafeAttribute.ts
|
|
1291
1354
|
init_dev();
|
|
1292
1355
|
init_sanitize();
|
|
1293
|
-
var _isDev2 = isDev();
|
|
1294
1356
|
var HTML_NS = "http://www.w3.org/1999/xhtml";
|
|
1295
1357
|
var SVG_NS = "http://www.w3.org/2000/svg";
|
|
1296
1358
|
var XLINK_NS = "http://www.w3.org/1999/xlink";
|
|
@@ -1313,7 +1375,7 @@ function setSafeAttribute(el, name, value, options = {}) {
|
|
|
1313
1375
|
const ns = namespaceFor(el, name);
|
|
1314
1376
|
const localName = ns ? name.slice(name.indexOf(":") + 1) : name;
|
|
1315
1377
|
if (isEventHandlerAttr(name)) {
|
|
1316
|
-
if (
|
|
1378
|
+
if (DEV) {
|
|
1317
1379
|
devWarn(
|
|
1318
1380
|
`${options.label ?? "setSafeAttribute"}: refusing to set event-handler attribute "${name}". Its value would be evaluated as JavaScript. Use on:{ ${name.slice(2)}: fn } instead.`
|
|
1319
1381
|
);
|
|
@@ -1328,7 +1390,7 @@ function setSafeAttribute(el, name, value, options = {}) {
|
|
|
1328
1390
|
return true;
|
|
1329
1391
|
}
|
|
1330
1392
|
if (isHtmlContentAttribute(name)) {
|
|
1331
|
-
if (
|
|
1393
|
+
if (DEV) {
|
|
1332
1394
|
devWarn(
|
|
1333
1395
|
`${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.`
|
|
1334
1396
|
);
|
|
@@ -1357,7 +1419,7 @@ function setSafeAttribute(el, name, value, options = {}) {
|
|
|
1357
1419
|
setProp(el, idlName, idlName === "checked" ? Boolean(value) : str);
|
|
1358
1420
|
return true;
|
|
1359
1421
|
}
|
|
1360
|
-
const safe = sanitizeAttributeString(name, str);
|
|
1422
|
+
const safe = sanitizeAttributeString(name, str, { element: el });
|
|
1361
1423
|
const current = ns ? el.getAttributeNS(ns, localName) : el.getAttribute(name);
|
|
1362
1424
|
if (current === safe) return true;
|
|
1363
1425
|
if (ns) el.setAttributeNS(ns, name, safe);
|
|
@@ -1587,7 +1649,14 @@ function reactiveBinding(commit, ownerNode) {
|
|
|
1587
1649
|
subscriber._disposed = false;
|
|
1588
1650
|
subscriber._errorPhase = "binding";
|
|
1589
1651
|
subscriber._errorNode = ownerNode;
|
|
1590
|
-
|
|
1652
|
+
try {
|
|
1653
|
+
run();
|
|
1654
|
+
} catch (err) {
|
|
1655
|
+
subscriber._disposed = true;
|
|
1656
|
+
subscriber._errorNode = void 0;
|
|
1657
|
+
cleanup(subscriber);
|
|
1658
|
+
throw err;
|
|
1659
|
+
}
|
|
1591
1660
|
return subscriber._dispose ?? (subscriber._dispose = () => {
|
|
1592
1661
|
subscriber._disposed = true;
|
|
1593
1662
|
subscriber._errorNode = void 0;
|
|
@@ -1818,17 +1887,16 @@ function forEachSubscriber(signal2, visit) {
|
|
|
1818
1887
|
}
|
|
1819
1888
|
|
|
1820
1889
|
// src/reactivity/track.ts
|
|
1821
|
-
var
|
|
1822
|
-
var _runtimeVersion = true ? "4.0.1" : "dev";
|
|
1890
|
+
var _runtimeVersion = true ? "4.2.0" : "dev";
|
|
1823
1891
|
var REGISTRY_KEY = /* @__PURE__ */ Symbol.for("sibujs.reactive.v1");
|
|
1824
1892
|
function resolveReactiveApi() {
|
|
1825
1893
|
const g2 = globalThis;
|
|
1826
1894
|
const existing = g2[REGISTRY_KEY];
|
|
1827
1895
|
if (existing) {
|
|
1828
|
-
if (
|
|
1896
|
+
if (DEV && !existing.__dupWarned) {
|
|
1829
1897
|
existing.__dupWarned = true;
|
|
1830
1898
|
devWarn(
|
|
1831
|
-
`Multiple instances of the reactive runtime detected on this page (active: ${existing.version}, duplicate: ${_runtimeVersion}). Reactivity
|
|
1899
|
+
`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.`
|
|
1832
1900
|
);
|
|
1833
1901
|
}
|
|
1834
1902
|
return existing;
|
|
@@ -1899,7 +1967,103 @@ function bindAttribute(el, attr, getter) {
|
|
|
1899
1967
|
init_dev();
|
|
1900
1968
|
init_errors();
|
|
1901
1969
|
init_dispose();
|
|
1902
|
-
|
|
1970
|
+
|
|
1971
|
+
// src/core/rendering/focusPreservation.ts
|
|
1972
|
+
init_dev();
|
|
1973
|
+
var IDENTITY_ATTRS = ["data-focus-key", "id", "name"];
|
|
1974
|
+
var SELECTABLE_TYPES = /* @__PURE__ */ new Set(["text", "search", "url", "tel", "password", ""]);
|
|
1975
|
+
function selectionOf(el) {
|
|
1976
|
+
const tag = el.tagName;
|
|
1977
|
+
const selectable = tag === "TEXTAREA" || tag === "INPUT" && SELECTABLE_TYPES.has(el.type.toLowerCase());
|
|
1978
|
+
if (!selectable) return { start: null, end: null, direction: null };
|
|
1979
|
+
const field = el;
|
|
1980
|
+
return { start: field.selectionStart, end: field.selectionEnd, direction: field.selectionDirection };
|
|
1981
|
+
}
|
|
1982
|
+
function captureFocusWithin(nodes) {
|
|
1983
|
+
if (nodes.length === 0 || typeof document === "undefined") return null;
|
|
1984
|
+
const active = document.activeElement;
|
|
1985
|
+
if (!active || active === document.body) return null;
|
|
1986
|
+
let inside = false;
|
|
1987
|
+
for (let i2 = 0; i2 < nodes.length; i2++) {
|
|
1988
|
+
const n = nodes[i2];
|
|
1989
|
+
if (n === active || n.nodeType === 1 && n.contains(active)) {
|
|
1990
|
+
inside = true;
|
|
1991
|
+
break;
|
|
1992
|
+
}
|
|
1993
|
+
}
|
|
1994
|
+
if (!inside) return null;
|
|
1995
|
+
let attr = null;
|
|
1996
|
+
let value = null;
|
|
1997
|
+
for (let i2 = 0; i2 < IDENTITY_ATTRS.length; i2++) {
|
|
1998
|
+
const candidate = active.getAttribute(IDENTITY_ATTRS[i2]);
|
|
1999
|
+
if (candidate) {
|
|
2000
|
+
attr = IDENTITY_ATTRS[i2];
|
|
2001
|
+
value = candidate;
|
|
2002
|
+
break;
|
|
2003
|
+
}
|
|
2004
|
+
}
|
|
2005
|
+
return { el: active, attr, value, tag: active.tagName, ...selectionOf(active) };
|
|
2006
|
+
}
|
|
2007
|
+
function quote(value) {
|
|
2008
|
+
return `"${value.replace(/\\/g, "\\\\").replace(/"/g, '\\"')}"`;
|
|
2009
|
+
}
|
|
2010
|
+
function findUniqueByIdentity(nodes, selector) {
|
|
2011
|
+
let el = null;
|
|
2012
|
+
let count = 0;
|
|
2013
|
+
for (let i2 = 0; i2 < nodes.length; i2++) {
|
|
2014
|
+
const n = nodes[i2];
|
|
2015
|
+
if (n.nodeType !== 1) continue;
|
|
2016
|
+
const root = n;
|
|
2017
|
+
if (root.matches(selector)) {
|
|
2018
|
+
count++;
|
|
2019
|
+
el ?? (el = root);
|
|
2020
|
+
}
|
|
2021
|
+
const inner = root.querySelectorAll(selector);
|
|
2022
|
+
for (let j = 0; j < inner.length; j++) {
|
|
2023
|
+
count++;
|
|
2024
|
+
el ?? (el = inner[j]);
|
|
2025
|
+
}
|
|
2026
|
+
if (count > 1) return { el: null, count };
|
|
2027
|
+
}
|
|
2028
|
+
return count === 1 ? { el, count } : { el: null, count };
|
|
2029
|
+
}
|
|
2030
|
+
function refocus(el, snapshot) {
|
|
2031
|
+
el.focus();
|
|
2032
|
+
if (snapshot.start !== null && typeof el.setSelectionRange === "function") {
|
|
2033
|
+
const field = el;
|
|
2034
|
+
const max = field.value.length;
|
|
2035
|
+
const start = Math.min(snapshot.start, max);
|
|
2036
|
+
const end = Math.min(snapshot.end ?? start, max);
|
|
2037
|
+
field.setSelectionRange(start, end, snapshot.direction ?? "none");
|
|
2038
|
+
}
|
|
2039
|
+
}
|
|
2040
|
+
function restoreFocusWithin(snapshot, nodes, where) {
|
|
2041
|
+
if (!snapshot) return;
|
|
2042
|
+
if (typeof document === "undefined") return;
|
|
2043
|
+
const active = document.activeElement;
|
|
2044
|
+
if (active === snapshot.el) return;
|
|
2045
|
+
if (active && active !== document.body && active !== document.documentElement) return;
|
|
2046
|
+
if (snapshot.el.isConnected) {
|
|
2047
|
+
refocus(snapshot.el, snapshot);
|
|
2048
|
+
return;
|
|
2049
|
+
}
|
|
2050
|
+
let ambiguous = false;
|
|
2051
|
+
if (snapshot.attr && snapshot.value) {
|
|
2052
|
+
const { el: replacement, count } = findUniqueByIdentity(nodes, `[${snapshot.attr}=${quote(snapshot.value)}]`);
|
|
2053
|
+
if (replacement && replacement.tagName === snapshot.tag) {
|
|
2054
|
+
refocus(replacement, snapshot);
|
|
2055
|
+
return;
|
|
2056
|
+
}
|
|
2057
|
+
ambiguous = count > 1;
|
|
2058
|
+
}
|
|
2059
|
+
devWarnLazy(() => {
|
|
2060
|
+
const id = snapshot.attr ? ` (${snapshot.attr}="${snapshot.value}")` : "";
|
|
2061
|
+
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";
|
|
2062
|
+
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.`;
|
|
2063
|
+
});
|
|
2064
|
+
}
|
|
2065
|
+
|
|
2066
|
+
// src/reactivity/bindChildNode.ts
|
|
1903
2067
|
function bindChildNode(placeholder, getter) {
|
|
1904
2068
|
let lastNodes = [];
|
|
1905
2069
|
function commit() {
|
|
@@ -1910,6 +2074,7 @@ function bindChildNode(placeholder, getter) {
|
|
|
1910
2074
|
reportError(err, { phase: "binding", name: "bindChildNode", node: placeholder });
|
|
1911
2075
|
return;
|
|
1912
2076
|
}
|
|
2077
|
+
const focused = captureFocusWithin(lastNodes);
|
|
1913
2078
|
if (result == null || typeof result === "boolean") {
|
|
1914
2079
|
for (let i2 = 0; i2 < lastNodes.length; i2++) {
|
|
1915
2080
|
const node = lastNodes[i2];
|
|
@@ -1917,6 +2082,7 @@ function bindChildNode(placeholder, getter) {
|
|
|
1917
2082
|
if (node.parentNode) node.parentNode.removeChild(node);
|
|
1918
2083
|
}
|
|
1919
2084
|
lastNodes.length = 0;
|
|
2085
|
+
restoreFocusWithin(focused, lastNodes, "bindChildNode");
|
|
1920
2086
|
return;
|
|
1921
2087
|
}
|
|
1922
2088
|
const parent = placeholder.parentNode;
|
|
@@ -1933,8 +2099,7 @@ function bindChildNode(placeholder, getter) {
|
|
|
1933
2099
|
if (item == null || typeof item === "boolean") continue;
|
|
1934
2100
|
const node = item instanceof Node ? item : document.createTextNode(String(item));
|
|
1935
2101
|
if (seen.has(node)) {
|
|
1936
|
-
if (
|
|
1937
|
-
devWarn("bindChildNode: duplicate node reference in array \u2014 only the first occurrence is rendered.");
|
|
2102
|
+
if (DEV) devWarn("bindChildNode: duplicate node reference in array \u2014 only the first occurrence is rendered.");
|
|
1938
2103
|
continue;
|
|
1939
2104
|
}
|
|
1940
2105
|
seen.add(node);
|
|
@@ -1967,6 +2132,7 @@ function bindChildNode(placeholder, getter) {
|
|
|
1967
2132
|
prev = node;
|
|
1968
2133
|
}
|
|
1969
2134
|
lastNodes = newNodes;
|
|
2135
|
+
restoreFocusWithin(focused, newNodes, "bindChildNode");
|
|
1970
2136
|
}
|
|
1971
2137
|
return reactiveBinding2(commit, placeholder);
|
|
1972
2138
|
}
|
|
@@ -1975,7 +2141,6 @@ function bindChildNode(placeholder, getter) {
|
|
|
1975
2141
|
init_sanitize();
|
|
1976
2142
|
init_dispose();
|
|
1977
2143
|
var SVG_NS2 = "http://www.w3.org/2000/svg";
|
|
1978
|
-
var _isDev6 = isDev();
|
|
1979
2144
|
var BLOCKED_TAGS = /* @__PURE__ */ new Set(["script", "iframe", "object", "embed", "frame", "frameset"]);
|
|
1980
2145
|
function isBlockedTag(tag) {
|
|
1981
2146
|
return BLOCKED_TAGS.has(tag.toLowerCase());
|
|
@@ -1993,18 +2158,9 @@ var CLOBBER_RISKY_IDS = /* @__PURE__ */ new Set([
|
|
|
1993
2158
|
"self",
|
|
1994
2159
|
"frames"
|
|
1995
2160
|
]);
|
|
1996
|
-
|
|
1997
|
-
|
|
1998
|
-
|
|
1999
|
-
const tokens = t2.split(/\s+/);
|
|
2000
|
-
let sawClassish = false;
|
|
2001
|
-
for (let i2 = 0; i2 < tokens.length; i2++) {
|
|
2002
|
-
const tok = tokens[i2];
|
|
2003
|
-
if (!/^-?[A-Za-z_][A-Za-z0-9_:/.-]*$/.test(tok)) return false;
|
|
2004
|
-
if (/[-:/0-9]/.test(tok)) sawClassish = true;
|
|
2005
|
-
}
|
|
2006
|
-
return sawClassish;
|
|
2007
|
-
}
|
|
2161
|
+
var warnedLoneStrings = /* @__PURE__ */ new Set();
|
|
2162
|
+
var MAX_WARNED_LONE_STRINGS = 100;
|
|
2163
|
+
var loneStringCapAnnounced = false;
|
|
2008
2164
|
var kebabCache = /* @__PURE__ */ new Map();
|
|
2009
2165
|
function toKebab(prop) {
|
|
2010
2166
|
let cached = kebabCache.get(prop);
|
|
@@ -2016,13 +2172,13 @@ function toKebab(prop) {
|
|
|
2016
2172
|
function applyStyle(el, style2) {
|
|
2017
2173
|
if (typeof style2 === "function") {
|
|
2018
2174
|
const teardown = reactiveBinding2(() => {
|
|
2019
|
-
el.setAttribute("style", sanitizeStyleAttribute(String(style2())));
|
|
2175
|
+
el.setAttribute("style", sanitizeStyleAttribute(String(style2()), { element: el }));
|
|
2020
2176
|
}, el);
|
|
2021
2177
|
registerDisposer(el, teardown);
|
|
2022
2178
|
return;
|
|
2023
2179
|
}
|
|
2024
2180
|
if (typeof style2 === "string") {
|
|
2025
|
-
el.setAttribute("style", sanitizeStyleAttribute(style2));
|
|
2181
|
+
el.setAttribute("style", sanitizeStyleAttribute(style2, { element: el }));
|
|
2026
2182
|
return;
|
|
2027
2183
|
}
|
|
2028
2184
|
const htmlEl = el;
|
|
@@ -2032,14 +2188,26 @@ function applyStyle(el, style2) {
|
|
|
2032
2188
|
if (typeof val === "function") {
|
|
2033
2189
|
const getter = val;
|
|
2034
2190
|
const teardown = reactiveBinding2(() => {
|
|
2035
|
-
htmlEl.style.setProperty(name, sanitizeCSSValue(String(getter())));
|
|
2191
|
+
htmlEl.style.setProperty(name, sanitizeCSSValue(String(getter()), { property: name, element: el }));
|
|
2036
2192
|
}, el);
|
|
2037
2193
|
registerDisposer(el, teardown);
|
|
2038
2194
|
} else {
|
|
2039
|
-
htmlEl.style.setProperty(name, sanitizeCSSValue(String(val)));
|
|
2195
|
+
htmlEl.style.setProperty(name, sanitizeCSSValue(String(val), { property: name, element: el }));
|
|
2040
2196
|
}
|
|
2041
2197
|
}
|
|
2042
2198
|
}
|
|
2199
|
+
function resolveClassValue(cls) {
|
|
2200
|
+
if (typeof cls === "string") return cls;
|
|
2201
|
+
if (typeof cls === "function") return cls();
|
|
2202
|
+
if (!cls) return "";
|
|
2203
|
+
let out = "";
|
|
2204
|
+
for (const name in cls) {
|
|
2205
|
+
const val = cls[name];
|
|
2206
|
+
const active = typeof val === "function" ? val() : val;
|
|
2207
|
+
if (active) out = out ? `${out} ${name}` : name;
|
|
2208
|
+
}
|
|
2209
|
+
return out;
|
|
2210
|
+
}
|
|
2043
2211
|
function applyClass(el, cls) {
|
|
2044
2212
|
if (typeof cls === "string") {
|
|
2045
2213
|
el.setAttribute("class", cls);
|
|
@@ -2143,11 +2311,26 @@ var tagFactory = (tag, ns) => {
|
|
|
2143
2311
|
appendChildren(el, second);
|
|
2144
2312
|
return el;
|
|
2145
2313
|
}
|
|
2146
|
-
|
|
2147
|
-
|
|
2148
|
-
|
|
2149
|
-
|
|
2150
|
-
|
|
2314
|
+
devWarnLazy(() => {
|
|
2315
|
+
const tokens = first.trim().split(/\s+/);
|
|
2316
|
+
if (tokens.length < 2) return "";
|
|
2317
|
+
let utilityTokens = 0;
|
|
2318
|
+
for (let i2 = 0; i2 < tokens.length; i2++) {
|
|
2319
|
+
const tok = tokens[i2];
|
|
2320
|
+
if (!/^-?[A-Za-z_][A-Za-z0-9_:/.-]*$/.test(tok)) return "";
|
|
2321
|
+
if (/[-:/0-9]/.test(tok)) utilityTokens++;
|
|
2322
|
+
}
|
|
2323
|
+
if (utilityTokens < 2) return "";
|
|
2324
|
+
const key = `${tag}|${first}`;
|
|
2325
|
+
if (warnedLoneStrings.has(key)) return "";
|
|
2326
|
+
if (warnedLoneStrings.size >= MAX_WARNED_LONE_STRINGS) {
|
|
2327
|
+
if (loneStringCapAnnounced) return "";
|
|
2328
|
+
loneStringCapAnnounced = true;
|
|
2329
|
+
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.`;
|
|
2330
|
+
}
|
|
2331
|
+
warnedLoneStrings.add(key);
|
|
2332
|
+
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.`;
|
|
2333
|
+
});
|
|
2151
2334
|
el.textContent = first;
|
|
2152
2335
|
return el;
|
|
2153
2336
|
}
|
|
@@ -2164,7 +2347,7 @@ var tagFactory = (tag, ns) => {
|
|
|
2164
2347
|
if (pClass != null) applyClass(el, pClass);
|
|
2165
2348
|
const pId = props.id;
|
|
2166
2349
|
if (pId != null) {
|
|
2167
|
-
if (
|
|
2350
|
+
if (DEV && typeof pId === "string" && CLOBBER_RISKY_IDS.has(pId.toLowerCase())) {
|
|
2168
2351
|
devWarn(
|
|
2169
2352
|
`tagFactory: element id="${pId}" matches a common global and may cause DOM clobbering. Avoid setting ids from untrusted input.`
|
|
2170
2353
|
);
|
|
@@ -2179,7 +2362,7 @@ var tagFactory = (tag, ns) => {
|
|
|
2179
2362
|
const handler = pOn[ev];
|
|
2180
2363
|
if (typeof handler === "function") {
|
|
2181
2364
|
el.addEventListener(ev, handler);
|
|
2182
|
-
} else if (
|
|
2365
|
+
} else if (DEV) {
|
|
2183
2366
|
devWarn(
|
|
2184
2367
|
`tagFactory: on.${ev} handler is not a function (got ${typeof handler}). Event listener was not attached.`
|
|
2185
2368
|
);
|
|
@@ -2411,7 +2594,6 @@ var isBatching = API2.isBatching;
|
|
|
2411
2594
|
// src/core/signals/signal.ts
|
|
2412
2595
|
init_dev();
|
|
2413
2596
|
var _g = globalThis;
|
|
2414
|
-
var _isDev7 = isDev();
|
|
2415
2597
|
function signal(initial, options) {
|
|
2416
2598
|
const state2 = {
|
|
2417
2599
|
value: initial,
|
|
@@ -2424,7 +2606,7 @@ function signal(initial, options) {
|
|
|
2424
2606
|
_d: false,
|
|
2425
2607
|
_validate: void 0
|
|
2426
2608
|
};
|
|
2427
|
-
const debugName =
|
|
2609
|
+
const debugName = DEV ? options?.name : void 0;
|
|
2428
2610
|
const equalsFn = options?.equals;
|
|
2429
2611
|
if (debugName) state2.__name = debugName;
|
|
2430
2612
|
function get() {
|
|
@@ -2441,7 +2623,7 @@ function signal(initial, options) {
|
|
|
2441
2623
|
if (equalsFn(prev, newValue)) return;
|
|
2442
2624
|
state2.value = newValue;
|
|
2443
2625
|
state2.__v++;
|
|
2444
|
-
if (
|
|
2626
|
+
if (DEV) {
|
|
2445
2627
|
const hook = _g.__SIBU_DEVTOOLS_GLOBAL_HOOK__;
|
|
2446
2628
|
if (hook) hook.emit("signal:update", { signal: state2, name: debugName, oldValue: prev, newValue });
|
|
2447
2629
|
}
|
|
@@ -2449,7 +2631,7 @@ function signal(initial, options) {
|
|
|
2449
2631
|
notifySubscribers2(state2);
|
|
2450
2632
|
}
|
|
2451
2633
|
};
|
|
2452
|
-
} else if (
|
|
2634
|
+
} else if (DEV) {
|
|
2453
2635
|
set = (next) => {
|
|
2454
2636
|
const prev = state2.value;
|
|
2455
2637
|
const newValue = typeof next === "function" ? next(prev) : next;
|
|
@@ -2474,7 +2656,7 @@ function signal(initial, options) {
|
|
|
2474
2656
|
}
|
|
2475
2657
|
};
|
|
2476
2658
|
}
|
|
2477
|
-
if (
|
|
2659
|
+
if (DEV) {
|
|
2478
2660
|
const hook = _g.__SIBU_DEVTOOLS_GLOBAL_HOOK__;
|
|
2479
2661
|
if (hook) hook.emit("signal:create", { signal: state2, name: debugName, getter: get, initial });
|
|
2480
2662
|
}
|
|
@@ -4140,7 +4322,6 @@ function RouterLink(props, children) {
|
|
|
4140
4322
|
if (!_routerRef.current) throw new Error("Router not initialized. Call createRouter() first.");
|
|
4141
4323
|
const { to, replace: replace2 = false, activeClass, exactActiveClass, nodes, target, rel, class: classAttr, ...attrs } = props;
|
|
4142
4324
|
const content = children !== void 0 ? children : nodes;
|
|
4143
|
-
const baseClass = typeof classAttr === "string" ? classAttr : "";
|
|
4144
4325
|
const routeGetter = _routerRef.current.routeGetter;
|
|
4145
4326
|
const rawHref = _routerRef.current["resolvePath"](to);
|
|
4146
4327
|
const kind = classifyNavigationTarget(rawHref);
|
|
@@ -4176,7 +4357,7 @@ function RouterLink(props, children) {
|
|
|
4176
4357
|
if (exactActiveClass) classes.push(exactActiveClass);
|
|
4177
4358
|
else if (options.linkExactActiveClass) classes.push(options.linkExactActiveClass);
|
|
4178
4359
|
}
|
|
4179
|
-
link2.className = [
|
|
4360
|
+
link2.className = [resolveClassValue(classAttr), ...classes].filter(Boolean).join(" ");
|
|
4180
4361
|
});
|
|
4181
4362
|
registerDisposer(link2, effectCleanup);
|
|
4182
4363
|
Object.entries(attrs).forEach(([key, value]) => {
|
|
@@ -4188,7 +4369,7 @@ function RouterLink(props, children) {
|
|
|
4188
4369
|
const safe = sanitizeUrl(str);
|
|
4189
4370
|
if (safe) link2.setAttribute(key, safe);
|
|
4190
4371
|
} else if (lkey === "style") {
|
|
4191
|
-
link2.setAttribute(key, sanitizeStyleAttribute(str));
|
|
4372
|
+
link2.setAttribute(key, sanitizeStyleAttribute(str, { element: link2 }));
|
|
4192
4373
|
} else {
|
|
4193
4374
|
link2.setAttribute(key, str);
|
|
4194
4375
|
}
|