sibujs 3.4.0 → 4.0.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.
Files changed (98) hide show
  1. package/LICENSE +21 -21
  2. package/README.md +118 -15
  3. package/dist/browser.cjs +410 -101
  4. package/dist/browser.d.cts +50 -5
  5. package/dist/browser.d.ts +50 -5
  6. package/dist/browser.js +8 -6
  7. package/dist/build.cjs +777 -385
  8. package/dist/build.js +15 -15
  9. package/dist/cdn.global.js +11 -7
  10. package/dist/{chunk-JCO7AHNU.js → chunk-3EKJK5FZ.js} +73 -34
  11. package/dist/chunk-4MFZMLUU.js +147 -0
  12. package/dist/chunk-52XFPGSN.js +123 -0
  13. package/dist/chunk-5INI7D2L.js +194 -0
  14. package/dist/{chunk-OAVXAFAY.js → chunk-6LG2T7LO.js} +5 -5
  15. package/dist/{chunk-OOUQUCNN.js → chunk-ACBT6UZS.js} +57 -22
  16. package/dist/{chunk-F7HW2NI5.js → chunk-AW6HPJ3L.js} +1 -1
  17. package/dist/chunk-DHDZ7IVN.js +109 -0
  18. package/dist/{chunk-JNGGM2XE.js → chunk-DQVUBVNX.js} +16 -25
  19. package/dist/{chunk-AXFWGY32.js → chunk-DR7H6UGM.js} +232 -67
  20. package/dist/{chunk-WSGLJYFI.js → chunk-E62UADKL.js} +9 -3
  21. package/dist/{chunk-3Z2NGWQI.js → chunk-ES2GERY2.js} +1 -1
  22. package/dist/{chunk-S3V6ZXPI.js → chunk-EWEE7NBF.js} +115 -41
  23. package/dist/{chunk-3DVGCW7O.js → chunk-F64ZPCFE.js} +8 -8
  24. package/dist/{chunk-APFRCIRI.js → chunk-GCSGGA3Q.js} +295 -198
  25. package/dist/{chunk-EX77FXTT.js → chunk-HYCCIYNS.js} +228 -51
  26. package/dist/{chunk-ELXMRSVN.js → chunk-NF3LYCQH.js} +259 -124
  27. package/dist/chunk-O3QQ3XOL.js +61 -0
  28. package/dist/{chunk-BUKYCWHX.js → chunk-PBQEW5VW.js} +14 -10
  29. package/dist/{chunk-H5FI5WDP.js → chunk-RRIDJQ5C.js} +3 -3
  30. package/dist/{chunk-S3NFJO6L.js → chunk-TIRZCERI.js} +36 -5
  31. package/dist/{chunk-ODXVQ3CS.js → chunk-VFHIVEPF.js} +309 -188
  32. package/dist/chunk-VPP2FONR.js +142 -0
  33. package/dist/{chunk-KZBEVFXZ.js → chunk-W55YHPEP.js} +5 -3
  34. package/dist/{chunk-FKQG7FTY.js → chunk-WN6WDFCB.js} +4 -4
  35. package/dist/{chunk-CEBWDD63.js → chunk-WOOMUJFT.js} +228 -86
  36. package/dist/{chunk-ITWCTZYH.js → chunk-Z2CE42DB.js} +19 -25
  37. package/dist/{contracts-ey_Qh8ef.d.cts → contracts-Hg6ITAEF.d.cts} +6 -6
  38. package/dist/{contracts-ey_Qh8ef.d.ts → contracts-Hg6ITAEF.d.ts} +6 -6
  39. package/dist/{customElement-CPfIrbvg.d.ts → customElement-CKLoO63w.d.cts} +73 -11
  40. package/dist/{customElement-CPfIrbvg.d.cts → customElement-CKLoO63w.d.ts} +73 -11
  41. package/dist/data.cjs +483 -205
  42. package/dist/data.d.cts +139 -7
  43. package/dist/data.d.ts +139 -7
  44. package/dist/data.js +9 -9
  45. package/dist/devtools.cjs +222 -87
  46. package/dist/devtools.js +8 -8
  47. package/dist/dispose-4FZ6OFXR.js +19 -0
  48. package/dist/ecosystem.cjs +419 -175
  49. package/dist/ecosystem.js +11 -11
  50. package/dist/extras.cjs +1981 -765
  51. package/dist/extras.d.cts +7 -7
  52. package/dist/extras.d.ts +7 -7
  53. package/dist/extras.js +29 -26
  54. package/dist/index.cjs +784 -385
  55. package/dist/index.d.cts +299 -28
  56. package/dist/index.d.ts +299 -28
  57. package/dist/index.js +33 -18
  58. package/dist/motion.cjs +180 -50
  59. package/dist/motion.d.cts +26 -0
  60. package/dist/motion.d.ts +26 -0
  61. package/dist/motion.js +5 -5
  62. package/dist/patterns.cjs +437 -170
  63. package/dist/patterns.d.cts +60 -13
  64. package/dist/patterns.d.ts +60 -13
  65. package/dist/patterns.js +7 -7
  66. package/dist/performance.cjs +333 -148
  67. package/dist/performance.d.cts +55 -7
  68. package/dist/performance.d.ts +55 -7
  69. package/dist/performance.js +9 -9
  70. package/dist/plugins.cjs +1374 -576
  71. package/dist/plugins.d.cts +227 -9
  72. package/dist/plugins.d.ts +227 -9
  73. package/dist/plugins.js +613 -321
  74. package/dist/{ssr-D62yFwuw.d.cts → ssr-BiPRdZ6n.d.cts} +44 -15
  75. package/dist/{ssr-D62yFwuw.d.ts → ssr-BiPRdZ6n.d.ts} +44 -15
  76. package/dist/{ssr-2PPULEK2.js → ssr-JFP5535P.js} +5 -4
  77. package/dist/ssr.cjs +1104 -443
  78. package/dist/ssr.d.cts +230 -20
  79. package/dist/ssr.d.ts +230 -20
  80. package/dist/ssr.js +15 -12
  81. package/dist/{startup-0Qv6aosO.d.cts → startup-BMpaiMhP.d.cts} +1 -1
  82. package/dist/{startup-0Qv6aosO.d.ts → startup-BMpaiMhP.d.ts} +1 -1
  83. package/dist/testing.cjs +205 -63
  84. package/dist/testing.d.cts +1 -1
  85. package/dist/testing.d.ts +1 -1
  86. package/dist/testing.js +8 -10
  87. package/dist/ui.cjs +640 -199
  88. package/dist/ui.d.cts +2 -2
  89. package/dist/ui.d.ts +2 -2
  90. package/dist/ui.js +10 -10
  91. package/dist/widgets.cjs +207 -82
  92. package/dist/widgets.js +9 -9
  93. package/package.json +12 -7
  94. package/dist/chunk-5VGSK6D2.js +0 -80
  95. package/dist/chunk-COY6PUD2.js +0 -34
  96. package/dist/chunk-K35BAR4P.js +0 -96
  97. package/dist/chunk-L3GAGWCC.js +0 -111
  98. package/dist/chunk-RT3IYFN2.js +0 -38
@@ -1,22 +1,24 @@
1
+ import {
2
+ sanitizeUrl
3
+ } from "./chunk-5INI7D2L.js";
1
4
  import {
2
5
  globalSingleton
3
6
  } from "./chunk-7ZHH77QA.js";
4
- import {
5
- sanitizeUrl
6
- } from "./chunk-L3GAGWCC.js";
7
7
  import {
8
8
  effect
9
- } from "./chunk-BUKYCWHX.js";
9
+ } from "./chunk-PBQEW5VW.js";
10
10
  import {
11
- dispose
12
- } from "./chunk-5VGSK6D2.js";
11
+ dispose,
12
+ replaceChildrenSafely
13
+ } from "./chunk-DHDZ7IVN.js";
13
14
  import {
14
15
  signal
15
- } from "./chunk-KZBEVFXZ.js";
16
+ } from "./chunk-W55YHPEP.js";
16
17
  import {
17
18
  devWarn,
18
- isDev
19
- } from "./chunk-COY6PUD2.js";
19
+ isDev,
20
+ reportError
21
+ } from "./chunk-VPP2FONR.js";
20
22
 
21
23
  // src/performance/scheduler.ts
22
24
  var Priority = {
@@ -265,7 +267,7 @@ var DOMPool = class {
265
267
  this.pools.set(tag, pool);
266
268
  }
267
269
  if (pool.length >= this.maxSize) return;
268
- element.innerHTML = "";
270
+ replaceChildrenSafely(element);
269
271
  element.className = "";
270
272
  element.removeAttribute("style");
271
273
  element.removeAttribute("id");
@@ -396,8 +398,9 @@ function normalizedStore(schema) {
396
398
  ids: [],
397
399
  entities: {}
398
400
  });
401
+ const idOf = (entity) => String(entity[idKey]);
399
402
  function add(entity) {
400
- const id = String(entity[idKey]);
403
+ const id = idOf(entity);
401
404
  setState((prev) => {
402
405
  const ids = prev.ids.includes(id) ? prev.ids : [...prev.ids, id];
403
406
  return {
@@ -411,7 +414,7 @@ function normalizedStore(schema) {
411
414
  const nextIds = [...prev.ids];
412
415
  const nextEntities = { ...prev.entities };
413
416
  for (const entity of entities) {
414
- const id = String(entity[idKey]);
417
+ const id = idOf(entity);
415
418
  if (!nextIds.includes(id)) {
416
419
  nextIds.push(id);
417
420
  }
@@ -533,7 +536,14 @@ function createChunkRegistry(config = {}) {
533
536
  } = config;
534
537
  const cache = /* @__PURE__ */ new Map();
535
538
  const pending = /* @__PURE__ */ new Map();
536
- const preloaded = /* @__PURE__ */ new Set();
539
+ const preloaded = /* @__PURE__ */ new Map();
540
+ function notify(name, run) {
541
+ try {
542
+ run();
543
+ } catch (err) {
544
+ reportError(err, { phase: "async", name: `chunkRegistry(${name})` });
545
+ }
546
+ }
537
547
  function evict() {
538
548
  while (cache.size >= maxCacheSize) {
539
549
  let lru = null;
@@ -588,30 +598,47 @@ function createChunkRegistry(config = {}) {
588
598
  cached.lastAccess = Date.now();
589
599
  return cached.value;
590
600
  }
591
- const pendingLoad = pending.get(id);
592
- if (pendingLoad) return pendingLoad;
593
- onLoadStart?.(id);
594
- const loadPromise = loadWithRetry(id, loader).then((value) => {
595
- evict();
596
- const now = Date.now();
597
- cache.set(id, { value, timestamp: now, lastAccess: now, accessCount: 1 });
598
- pending.delete(id);
599
- onLoadEnd?.(id);
600
- return value;
601
- }).catch((err) => {
602
- pending.delete(id);
603
- const error = err instanceof Error ? err : new Error(String(err));
604
- onLoadError?.(id, error);
605
- throw error;
601
+ const existing = pending.get(id);
602
+ if (existing) return existing.promise;
603
+ let resolveOuter;
604
+ let rejectOuter;
605
+ const outcome = new Promise((resolve, reject) => {
606
+ resolveOuter = resolve;
607
+ rejectOuter = reject;
608
+ });
609
+ const entry = { promise: outcome };
610
+ pending.set(id, entry);
611
+ const owns = () => pending.get(id) === entry;
612
+ notify("onLoadStart", () => onLoadStart?.(id));
613
+ void loadWithRetry(id, loader).then(
614
+ (value) => {
615
+ if (owns()) {
616
+ pending.delete(id);
617
+ evict();
618
+ const now = Date.now();
619
+ cache.set(id, { value, timestamp: now, lastAccess: now, accessCount: 1 });
620
+ }
621
+ notify("onLoadEnd", () => onLoadEnd?.(id));
622
+ resolveOuter(value);
623
+ },
624
+ (err) => {
625
+ if (owns()) pending.delete(id);
626
+ const error = err instanceof Error ? err : new Error(String(err));
627
+ notify("onLoadError", () => onLoadError?.(id, error));
628
+ rejectOuter(error);
629
+ }
630
+ ).catch((internal) => {
631
+ reportError(internal, { phase: "async", name: "chunkRegistry(settlement)" });
632
+ rejectOuter(internal);
606
633
  });
607
- pending.set(id, loadPromise);
608
- return loadPromise;
634
+ return outcome;
609
635
  }
610
636
  function preloadFn(id, loader) {
611
637
  if (cache.has(id) || pending.has(id) || preloaded.has(id)) return;
612
- preloaded.add(id);
638
+ const marker = {};
639
+ preloaded.set(id, marker);
613
640
  loadFn(id, loader).catch(() => {
614
- preloaded.delete(id);
641
+ if (preloaded.get(id) === marker) preloaded.delete(id);
615
642
  });
616
643
  }
617
644
  return {
@@ -645,21 +672,33 @@ function createChunkRegistry(config = {}) {
645
672
  return void 0;
646
673
  },
647
674
  /**
648
- * Invalidate a cached chunk.
675
+ * Invalidate a cached chunk, and supersede any load still in flight for it.
676
+ *
677
+ * In-flight work is not cancelled — the loader API takes no abort signal, so
678
+ * claiming cancellation would be a lie. It is *superseded*: it still settles
679
+ * for whoever called `load()`, but it can no longer write to the cache, and
680
+ * a subsequent `load(id, …)` starts fresh work rather than adopting it.
649
681
  */
650
682
  invalidate(id) {
651
683
  cache.delete(id);
652
684
  preloaded.delete(id);
685
+ pending.delete(id);
653
686
  },
654
687
  /**
655
- * Clear all cached chunks.
688
+ * Clear all cached chunks, and supersede every load still in flight.
689
+ *
690
+ * Same barrier as `invalidate`, applied to every key at once.
656
691
  */
657
692
  clear() {
658
693
  cache.clear();
659
694
  preloaded.clear();
695
+ pending.clear();
660
696
  },
661
697
  /**
662
698
  * Get cache statistics.
699
+ *
700
+ * Describes currently OWNED state: superseded loads are already absent from
701
+ * `pending`, so the counts never include work whose result will be discarded.
663
702
  */
664
703
  stats() {
665
704
  return {
@@ -0,0 +1,147 @@
1
+ import {
2
+ isEventHandlerAttr,
3
+ isHtmlContentAttribute,
4
+ sanitizeAttributeString
5
+ } from "./chunk-5INI7D2L.js";
6
+ import {
7
+ reactiveBinding
8
+ } from "./chunk-ACBT6UZS.js";
9
+ import {
10
+ devWarn,
11
+ isDev,
12
+ reportError
13
+ } from "./chunk-VPP2FONR.js";
14
+
15
+ // src/utils/setSafeAttribute.ts
16
+ var _isDev = isDev();
17
+ var HTML_NS = "http://www.w3.org/1999/xhtml";
18
+ var SVG_NS = "http://www.w3.org/2000/svg";
19
+ var XLINK_NS = "http://www.w3.org/1999/xlink";
20
+ var XML_NS = "http://www.w3.org/XML/1998/namespace";
21
+ var BOOLEAN_IDL_ATTRS = /* @__PURE__ */ new Set(["checked", "disabled", "selected"]);
22
+ function isHtmlElement(el) {
23
+ return el.namespaceURI === null || el.namespaceURI === HTML_NS;
24
+ }
25
+ function setProp(el, key, val) {
26
+ el[key] = val;
27
+ }
28
+ function namespaceFor(el, name) {
29
+ if (el.namespaceURI !== SVG_NS) return null;
30
+ const lower = name.toLowerCase();
31
+ if (lower.startsWith("xlink:")) return XLINK_NS;
32
+ if (lower.startsWith("xml:")) return XML_NS;
33
+ return null;
34
+ }
35
+ function setSafeAttribute(el, name, value, options = {}) {
36
+ const ns = namespaceFor(el, name);
37
+ const localName = ns ? name.slice(name.indexOf(":") + 1) : name;
38
+ if (isEventHandlerAttr(name)) {
39
+ if (_isDev) {
40
+ devWarn(
41
+ `${options.label ?? "setSafeAttribute"}: refusing to set event-handler attribute "${name}". Its value would be evaluated as JavaScript. Use on:{ ${name.slice(2)}: fn } instead.`
42
+ );
43
+ }
44
+ if (ns) el.removeAttributeNS(ns, localName);
45
+ else el.removeAttribute(name);
46
+ return false;
47
+ }
48
+ if (value == null) {
49
+ if (ns) el.removeAttributeNS(ns, localName);
50
+ else el.removeAttribute(name);
51
+ return true;
52
+ }
53
+ if (isHtmlContentAttribute(name)) {
54
+ if (_isDev) {
55
+ devWarn(
56
+ `${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.`
57
+ );
58
+ }
59
+ if (ns) el.removeAttributeNS(ns, localName);
60
+ else el.removeAttribute(name);
61
+ return false;
62
+ }
63
+ const html = isHtmlElement(el);
64
+ const idlName = html ? name.toLowerCase() : name;
65
+ if (typeof value === "boolean") {
66
+ if (html && BOOLEAN_IDL_ATTRS.has(idlName) && idlName in el) {
67
+ setProp(el, idlName, value);
68
+ } else if (value) {
69
+ if (ns) el.setAttributeNS(ns, name, "");
70
+ else el.setAttribute(name, "");
71
+ } else if (ns) {
72
+ el.removeAttributeNS(ns, localName);
73
+ } else {
74
+ el.removeAttribute(name);
75
+ }
76
+ return true;
77
+ }
78
+ const str = String(value);
79
+ if (options.syncValueProperty !== false && html && (idlName === "value" || idlName === "checked") && idlName in el) {
80
+ setProp(el, idlName, idlName === "checked" ? Boolean(value) : str);
81
+ return true;
82
+ }
83
+ const safe = sanitizeAttributeString(name, str);
84
+ const current = ns ? el.getAttributeNS(ns, localName) : el.getAttribute(name);
85
+ if (current === safe) return true;
86
+ if (ns) el.setAttributeNS(ns, name, safe);
87
+ else el.setAttribute(name, safe);
88
+ return true;
89
+ }
90
+
91
+ // src/reactivity/bindAttribute.ts
92
+ function bindAttribute(el, attr, getter) {
93
+ if (isEventHandlerAttr(attr)) {
94
+ setSafeAttribute(el, attr, "", { label: `bindAttribute("${attr}")` });
95
+ return () => {
96
+ };
97
+ }
98
+ function commit() {
99
+ let value;
100
+ try {
101
+ value = getter();
102
+ } catch (err) {
103
+ reportError(err, { phase: "binding", name: `bindAttribute("${attr}")`, node: el });
104
+ return;
105
+ }
106
+ setSafeAttribute(el, attr, value, { label: `bindAttribute("${attr}")` });
107
+ }
108
+ return reactiveBinding(commit, el);
109
+ }
110
+ function bindDynamic(el, nameGetter, valueGetter) {
111
+ let prevName = null;
112
+ function commit() {
113
+ let name;
114
+ try {
115
+ name = typeof nameGetter === "function" ? nameGetter() : nameGetter;
116
+ } catch (err) {
117
+ reportError(err, { phase: "binding", name: "bindDynamic (name getter)", node: el });
118
+ return;
119
+ }
120
+ let value;
121
+ try {
122
+ value = typeof valueGetter === "function" ? valueGetter() : valueGetter;
123
+ } catch (err) {
124
+ reportError(err, { phase: "binding", name: "bindDynamic (value getter)", node: el });
125
+ return;
126
+ }
127
+ if (prevName !== null && prevName !== name) {
128
+ el.removeAttribute(prevName);
129
+ prevName = null;
130
+ }
131
+ if (!setSafeAttribute(el, name, value, { label: "bindDynamic" })) return;
132
+ prevName = name;
133
+ }
134
+ const teardown = reactiveBinding(commit, el);
135
+ return () => {
136
+ teardown();
137
+ if (prevName !== null) {
138
+ el.removeAttribute(prevName);
139
+ }
140
+ };
141
+ }
142
+
143
+ export {
144
+ setSafeAttribute,
145
+ bindAttribute,
146
+ bindDynamic
147
+ };
@@ -0,0 +1,123 @@
1
+ import {
2
+ globalSingleton
3
+ } from "./chunk-7ZHH77QA.js";
4
+
5
+ // src/utils/singletonResource.ts
6
+ function singletonResource(io) {
7
+ let original = null;
8
+ let captured = false;
9
+ const stack = [];
10
+ function apply() {
11
+ if (stack.length > 0) {
12
+ io.write(stack[stack.length - 1].value);
13
+ return;
14
+ }
15
+ if (captured) {
16
+ io.write(original);
17
+ captured = false;
18
+ original = null;
19
+ }
20
+ }
21
+ return {
22
+ acquire(value) {
23
+ if (!captured) {
24
+ original = io.read();
25
+ captured = true;
26
+ }
27
+ const entry = { value, released: false };
28
+ stack.push(entry);
29
+ apply();
30
+ return {
31
+ set(next) {
32
+ if (entry.released) return;
33
+ entry.value = next;
34
+ apply();
35
+ },
36
+ release() {
37
+ if (entry.released) return;
38
+ entry.released = true;
39
+ const index = stack.indexOf(entry);
40
+ if (index !== -1) stack.splice(index, 1);
41
+ apply();
42
+ }
43
+ };
44
+ },
45
+ ownerCount() {
46
+ return stack.length;
47
+ }
48
+ };
49
+ }
50
+
51
+ // src/utils/documentResources.ts
52
+ var INERT_LEASE = {
53
+ set() {
54
+ },
55
+ release() {
56
+ }
57
+ };
58
+ function inertLease() {
59
+ return INERT_LEASE;
60
+ }
61
+ var titleResource = globalSingleton(
62
+ /* @__PURE__ */ Symbol.for("sibujs.documentTitle.v1"),
63
+ () => singletonResource({
64
+ read: () => document.title,
65
+ write: (value) => {
66
+ document.title = value;
67
+ }
68
+ })
69
+ );
70
+ var baseResource = globalSingleton(
71
+ /* @__PURE__ */ Symbol.for("sibujs.documentBase.v1"),
72
+ () => singletonResource({
73
+ read: () => {
74
+ const el = document.head.querySelector("base");
75
+ if (!el) return null;
76
+ return {
77
+ href: el.getAttribute("href") ?? void 0,
78
+ target: el.getAttribute("target") ?? void 0
79
+ };
80
+ },
81
+ write: (spec) => {
82
+ const existing = document.head.querySelector("base");
83
+ if (spec === null) {
84
+ existing?.remove();
85
+ return;
86
+ }
87
+ const el = existing ?? document.head.appendChild(document.createElement("base"));
88
+ if (spec.href === void 0) el.removeAttribute("href");
89
+ else el.setAttribute("href", spec.href);
90
+ if (spec.target === void 0) el.removeAttribute("target");
91
+ else el.setAttribute("target", spec.target);
92
+ }
93
+ })
94
+ );
95
+ var scrollRestorationResource = globalSingleton(
96
+ /* @__PURE__ */ Symbol.for("sibujs.historyScrollRestoration.v1"),
97
+ () => singletonResource({
98
+ read: () => history.scrollRestoration,
99
+ write: (mode) => {
100
+ history.scrollRestoration = mode;
101
+ }
102
+ })
103
+ );
104
+ function acquireScrollRestorationMode(mode) {
105
+ if (typeof history === "undefined" || !("scrollRestoration" in history)) {
106
+ return inertLease();
107
+ }
108
+ return scrollRestorationResource.acquire(mode);
109
+ }
110
+ function acquireTitle(value) {
111
+ if (typeof document === "undefined") return inertLease();
112
+ return titleResource.acquire(value);
113
+ }
114
+ function acquireBase(spec) {
115
+ if (typeof document === "undefined") return inertLease();
116
+ return baseResource.acquire(spec);
117
+ }
118
+
119
+ export {
120
+ acquireScrollRestorationMode,
121
+ acquireTitle,
122
+ acquireBase
123
+ };
@@ -0,0 +1,194 @@
1
+ // src/utils/sanitize.ts
2
+ function stripControlChars(value) {
3
+ return value.replace(/[\x00-\x20\x7f-\x9f]+/g, "");
4
+ }
5
+ function canonicalAttrName(name) {
6
+ return name.replace(/[A-Z]/g, (ch) => String.fromCharCode(ch.charCodeAt(0) + 32));
7
+ }
8
+ function isEventHandlerAttr(name) {
9
+ if (name.length < 3) return false;
10
+ const lower = name.toLowerCase();
11
+ return lower[0] === "o" && lower[1] === "n" && lower.charCodeAt(2) >= 97 && lower.charCodeAt(2) <= 122;
12
+ }
13
+ var SAFE_URL_PROTOCOLS = ["http:", "https:", "mailto:", "tel:", "ftp:"];
14
+ var OUTER_TRIM = /^[\x00-\x20\x7f-\x9f]+|[\x00-\x20\x7f-\x9f]+$/g;
15
+ function sanitizeUrl(url) {
16
+ const probe = stripControlChars(url).trim();
17
+ if (!probe) return "";
18
+ const output = url.replace(OUTER_TRIM, "");
19
+ const lower = probe.toLowerCase();
20
+ let schemeEnd = -1;
21
+ for (let i = 0; i < lower.length; i++) {
22
+ const ch = lower.charCodeAt(i);
23
+ if (ch === 58) {
24
+ schemeEnd = i;
25
+ break;
26
+ }
27
+ if (ch === 47 || ch === 63 || ch === 35) break;
28
+ }
29
+ if (schemeEnd === -1) return output;
30
+ const scheme = lower.slice(0, schemeEnd + 1);
31
+ if (!/^[a-z][a-z0-9+.-]*:$/.test(scheme)) return output;
32
+ if (SAFE_URL_PROTOCOLS.indexOf(scheme) === -1) return "";
33
+ return output;
34
+ }
35
+ var SRCSET_DESCRIPTOR = /^\s+\d+(\.\d+)?[wx]$/;
36
+ function sanitizeSrcset(value) {
37
+ const parts = value.split(",");
38
+ const out = [];
39
+ for (let i = 0; i < parts.length; i++) {
40
+ const part = parts[i].trim();
41
+ if (!part) continue;
42
+ const m = part.match(/^(\S+)(\s+.+)?$/);
43
+ if (!m) continue;
44
+ if (m[2] !== void 0 && !SRCSET_DESCRIPTOR.test(m[2])) continue;
45
+ const safe = sanitizeUrl(m[1]);
46
+ if (!safe) continue;
47
+ out.push(m[2] ? `${safe}${m[2]}` : safe);
48
+ }
49
+ return out.join(", ");
50
+ }
51
+ var CSS_DANGER_GATE = /[(:@\\]/;
52
+ function isCssWhitespace(ch) {
53
+ return ch === " " || ch === " " || ch === "\n" || ch === "\r" || ch === "\f";
54
+ }
55
+ function isHexDigit(ch) {
56
+ return ch >= "0" && ch <= "9" || ch >= "a" && ch <= "f" || ch >= "A" && ch <= "F";
57
+ }
58
+ function decodeCssEscapes(value) {
59
+ let out = "";
60
+ for (let i = 0; i < value.length; i++) {
61
+ const ch = value[i];
62
+ if (ch !== "\\") {
63
+ out += ch;
64
+ continue;
65
+ }
66
+ if (i + 1 >= value.length) break;
67
+ const next = value[i + 1];
68
+ if (next === "\n" || next === "\f") {
69
+ i += 1;
70
+ continue;
71
+ }
72
+ if (next === "\r") {
73
+ i += value[i + 2] === "\n" ? 2 : 1;
74
+ continue;
75
+ }
76
+ if (isHexDigit(next)) {
77
+ let hex = "";
78
+ let j = i + 1;
79
+ while (j < value.length && hex.length < 6 && isHexDigit(value[j])) {
80
+ hex += value[j];
81
+ j++;
82
+ }
83
+ if (j < value.length && isCssWhitespace(value[j])) {
84
+ j += value[j] === "\r" && value[j + 1] === "\n" ? 2 : 1;
85
+ }
86
+ const code = Number.parseInt(hex, 16);
87
+ const invalid = code === 0 || code > 1114111 || code >= 55296 && code <= 57343;
88
+ out += invalid ? "\uFFFD" : String.fromCodePoint(code);
89
+ i = j - 1;
90
+ continue;
91
+ }
92
+ out += next;
93
+ i += 1;
94
+ }
95
+ return out;
96
+ }
97
+ function sanitizeCSSValue(value) {
98
+ if (!CSS_DANGER_GATE.test(value)) return value;
99
+ const normalized = value.includes("\\") ? decodeCssEscapes(value) : value;
100
+ const lower = normalized.toLowerCase().replace(/\s+/g, "");
101
+ if (lower.includes("url(") || lower.includes("expression(") || lower.includes("javascript:") || lower.includes("vbscript:") || lower.includes("-moz-binding") || lower.includes("behavior:") || lower.includes("@import") || lower.includes("image-set(") || lower.includes("filter:progid")) {
102
+ return "";
103
+ }
104
+ return value;
105
+ }
106
+ function sanitizeStyleAttribute(cssText) {
107
+ const input = String(cssText);
108
+ if (input.trim() === "") return "";
109
+ if (typeof document === "undefined") {
110
+ return sanitizeCSSValue(input) === "" ? "" : input;
111
+ }
112
+ const probe = document.createElement("div");
113
+ try {
114
+ probe.style.cssText = input;
115
+ } catch {
116
+ return "";
117
+ }
118
+ const declarations = [];
119
+ for (let i = 0; i < probe.style.length; i++) {
120
+ const property = probe.style[i];
121
+ const value = probe.style.getPropertyValue(property);
122
+ if (sanitizeCSSValue(value) === "") continue;
123
+ if (sanitizeCSSValue(`${property}:${value}`) === "") continue;
124
+ const priority = probe.style.getPropertyPriority(property);
125
+ declarations.push(`${property}: ${value}${priority ? ` !${priority}` : ""}`);
126
+ }
127
+ return declarations.join("; ");
128
+ }
129
+ function stripHtml(html) {
130
+ const input = String(html);
131
+ if (typeof DOMParser !== "undefined") {
132
+ try {
133
+ return new DOMParser().parseFromString(input, "text/html").body.textContent ?? "";
134
+ } catch {
135
+ }
136
+ }
137
+ let prev;
138
+ let out = input;
139
+ do {
140
+ prev = out;
141
+ out = out.replace(/<[^>]*>/g, "");
142
+ } while (out !== prev);
143
+ return out.replace(/<[^>]*$/, "");
144
+ }
145
+ var URL_ATTRIBUTES = /* @__PURE__ */ new Set([
146
+ "href",
147
+ "xlink:href",
148
+ "src",
149
+ "action",
150
+ "formaction",
151
+ "formtarget",
152
+ "cite",
153
+ "poster",
154
+ "background",
155
+ "srcset",
156
+ "ping",
157
+ "data",
158
+ // `<html manifest>` is a URL sink too. It was carried only by the SSR
159
+ // serializers' private copy of this set; folding that copy into this one would
160
+ // otherwise have silently dropped its coverage.
161
+ "manifest"
162
+ ]);
163
+ var HTML_CONTENT_ATTRIBUTES = /* @__PURE__ */ new Set(["srcdoc"]);
164
+ function isHtmlContentAttribute(name) {
165
+ return HTML_CONTENT_ATTRIBUTES.has(name.toLowerCase());
166
+ }
167
+ function isUrlAttribute(attr) {
168
+ return URL_ATTRIBUTES.has(attr.toLowerCase());
169
+ }
170
+ function isPolicyAttribute(name) {
171
+ const lower = name.toLowerCase();
172
+ return lower === "style" || URL_ATTRIBUTES.has(lower);
173
+ }
174
+ function sanitizeAttributeString(attr, value) {
175
+ const lower = attr.toLowerCase();
176
+ if (lower === "srcset") return sanitizeSrcset(value);
177
+ if (URL_ATTRIBUTES.has(lower)) return sanitizeUrl(value);
178
+ if (lower === "style") return sanitizeStyleAttribute(value);
179
+ return value;
180
+ }
181
+
182
+ export {
183
+ stripControlChars,
184
+ canonicalAttrName,
185
+ isEventHandlerAttr,
186
+ sanitizeUrl,
187
+ sanitizeCSSValue,
188
+ sanitizeStyleAttribute,
189
+ stripHtml,
190
+ isHtmlContentAttribute,
191
+ isUrlAttribute,
192
+ isPolicyAttribute,
193
+ sanitizeAttributeString
194
+ };
@@ -1,22 +1,22 @@
1
1
  import {
2
2
  watch
3
- } from "./chunk-H5FI5WDP.js";
3
+ } from "./chunk-RRIDJQ5C.js";
4
4
  import {
5
5
  createId
6
6
  } from "./chunk-CCSJMTRN.js";
7
7
  import {
8
8
  derived
9
- } from "./chunk-ITWCTZYH.js";
9
+ } from "./chunk-Z2CE42DB.js";
10
10
  import {
11
11
  stripHtml
12
- } from "./chunk-L3GAGWCC.js";
12
+ } from "./chunk-5INI7D2L.js";
13
13
  import {
14
14
  effect
15
- } from "./chunk-BUKYCWHX.js";
15
+ } from "./chunk-PBQEW5VW.js";
16
16
  import {
17
17
  batch,
18
18
  signal
19
- } from "./chunk-KZBEVFXZ.js";
19
+ } from "./chunk-W55YHPEP.js";
20
20
 
21
21
  // src/widgets/Combobox.ts
22
22
  var boundComboboxes = /* @__PURE__ */ new WeakMap();