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.
Files changed (80) hide show
  1. package/README.md +29 -1
  2. package/dist/browser.cjs +21 -22
  3. package/dist/browser.js +6 -6
  4. package/dist/build.cjs +363 -110
  5. package/dist/build.js +15 -15
  6. package/dist/cdn.dev.global.js +398 -0
  7. package/dist/cdn.global.js +10 -10
  8. package/dist/{chunk-AD5YSZAN.js → chunk-2LOYNGBY.js} +2 -2
  9. package/dist/{chunk-VPP2FONR.js → chunk-2WLZ6757.js} +17 -10
  10. package/dist/{chunk-UNAYBND2.js → chunk-3VTSPNC5.js} +2 -2
  11. package/dist/{chunk-TIRZCERI.js → chunk-5DXA2J44.js} +1 -1
  12. package/dist/{chunk-QD4I7ZGZ.js → chunk-6ZGI3RBE.js} +149 -33
  13. package/dist/{chunk-JYXQCELN.js → chunk-7ALC7KGE.js} +13 -7
  14. package/dist/{chunk-XDOMTQHM.js → chunk-7VEC3UD2.js} +3 -3
  15. package/dist/{chunk-PTLJ7NQX.js → chunk-BMYYZWHX.js} +3 -3
  16. package/dist/{chunk-PHB3MCK4.js → chunk-BNKV4REK.js} +7 -8
  17. package/dist/{chunk-XET2RUJF.js → chunk-FOWBJZDL.js} +7 -8
  18. package/dist/{chunk-5BVKQX2F.js → chunk-GDUNQCCW.js} +4 -4
  19. package/dist/{chunk-TVURNWDK.js → chunk-HECVW343.js} +20 -9
  20. package/dist/{chunk-PHRH66Y7.js → chunk-HJEPKZ2O.js} +7 -8
  21. package/dist/{chunk-PJDSI2K7.js → chunk-HZEBO22J.js} +125 -42
  22. package/dist/{chunk-5INI7D2L.js → chunk-IXKSNWV5.js} +74 -11
  23. package/dist/{chunk-IKVUUE7D.js → chunk-KE4KWRDY.js} +3 -3
  24. package/dist/{chunk-AW6HPJ3L.js → chunk-KKLW7YWL.js} +1 -1
  25. package/dist/{chunk-XZMCVZW6.js → chunk-NEYWS4EX.js} +6 -6
  26. package/dist/{chunk-HYCCIYNS.js → chunk-NIOYEGBQ.js} +13 -14
  27. package/dist/{chunk-YLV26GAJ.js → chunk-OUWAIXIK.js} +3 -3
  28. package/dist/{chunk-E72G5JSK.js → chunk-P3DHXBR6.js} +1 -1
  29. package/dist/{chunk-J4WZMCIW.js → chunk-QCFLDD7C.js} +5 -5
  30. package/dist/{chunk-DHDZ7IVN.js → chunk-QKRPLZ2V.js} +7 -8
  31. package/dist/{chunk-52ERIVFD.js → chunk-QL4UREZO.js} +6 -6
  32. package/dist/{chunk-TNEHT3NG.js → chunk-SF3TB4K6.js} +8 -8
  33. package/dist/{chunk-HPXTUPJD.js → chunk-XZ2N525U.js} +6 -6
  34. package/dist/{customElement-CKLoO63w.d.ts → customElement-CNZxEB9G.d.cts} +77 -0
  35. package/dist/{customElement-CKLoO63w.d.cts → customElement-CNZxEB9G.d.ts} +77 -0
  36. package/dist/data.cjs +23 -25
  37. package/dist/data.js +9 -9
  38. package/dist/devtools.cjs +26 -23
  39. package/dist/devtools.d.cts +1 -1
  40. package/dist/devtools.d.ts +1 -1
  41. package/dist/devtools.js +8 -8
  42. package/dist/{dispose-4FZ6OFXR.js → dispose-46BOMMQJ.js} +2 -2
  43. package/dist/ecosystem.cjs +230 -68
  44. package/dist/ecosystem.js +11 -11
  45. package/dist/extras.cjs +251 -87
  46. package/dist/extras.d.cts +2 -2
  47. package/dist/extras.d.ts +2 -2
  48. package/dist/extras.js +25 -25
  49. package/dist/index.cjs +358 -104
  50. package/dist/index.d.cts +287 -34
  51. package/dist/index.d.ts +287 -34
  52. package/dist/index.js +17 -15
  53. package/dist/{introspect-RjLfIFpL.d.cts → introspect-D5xF-0Es.d.cts} +7 -0
  54. package/dist/{introspect-DOZfmC-4.d.ts → introspect-rSBIxEQi.d.ts} +7 -0
  55. package/dist/motion.cjs +21 -23
  56. package/dist/motion.js +5 -5
  57. package/dist/patterns.cjs +24 -25
  58. package/dist/patterns.d.cts +8 -0
  59. package/dist/patterns.d.ts +8 -0
  60. package/dist/patterns.js +7 -7
  61. package/dist/performance.cjs +24 -28
  62. package/dist/performance.js +9 -9
  63. package/dist/plugins.cjs +268 -87
  64. package/dist/plugins.d.cts +92 -0
  65. package/dist/plugins.d.ts +92 -0
  66. package/dist/plugins.js +18 -17
  67. package/dist/{ssr-JFP5535P.js → ssr-Y7XOEPEN.js} +5 -5
  68. package/dist/ssr.cjs +241 -80
  69. package/dist/ssr.js +12 -12
  70. package/dist/testing.cjs +19 -20
  71. package/dist/testing.js +5 -5
  72. package/dist/ui.cjs +106 -44
  73. package/dist/ui.d.cts +7 -1
  74. package/dist/ui.d.ts +7 -1
  75. package/dist/ui.js +10 -10
  76. package/dist/widgets.cjs +21 -22
  77. package/dist/widgets.d.cts +8 -0
  78. package/dist/widgets.d.ts +8 -0
  79. package/dist/widgets.js +9 -9
  80. package/package.json +11 -2
@@ -135,40 +135,42 @@ import {
135
135
  use,
136
136
  var_,
137
137
  video
138
- } from "./chunk-E72G5JSK.js";
138
+ } from "./chunk-P3DHXBR6.js";
139
139
  import {
140
140
  trustHTML
141
- } from "./chunk-HYCCIYNS.js";
141
+ } from "./chunk-NIOYEGBQ.js";
142
142
  import {
143
143
  watch
144
- } from "./chunk-PTLJ7NQX.js";
144
+ } from "./chunk-BMYYZWHX.js";
145
145
  import {
146
146
  __resetIdCounter,
147
147
  createId
148
148
  } from "./chunk-CCSJMTRN.js";
149
149
  import {
150
150
  context
151
- } from "./chunk-XET2RUJF.js";
151
+ } from "./chunk-FOWBJZDL.js";
152
152
  import {
153
153
  SVG_NS,
154
154
  bindChildNode,
155
+ captureFocusWithin,
156
+ restoreFocusWithin,
155
157
  tagFactory
156
- } from "./chunk-QD4I7ZGZ.js";
158
+ } from "./chunk-6ZGI3RBE.js";
157
159
  import {
158
160
  bindAttribute,
159
161
  bindDynamic,
160
162
  setSafeAttribute
161
- } from "./chunk-PHRH66Y7.js";
163
+ } from "./chunk-HJEPKZ2O.js";
162
164
  import {
163
165
  derived
164
- } from "./chunk-AD5YSZAN.js";
166
+ } from "./chunk-2LOYNGBY.js";
165
167
  import {
166
168
  globalSingleton
167
169
  } from "./chunk-7ZHH77QA.js";
168
170
  import {
169
171
  effect,
170
172
  on
171
- } from "./chunk-XDOMTQHM.js";
173
+ } from "./chunk-7VEC3UD2.js";
172
174
  import {
173
175
  disableSSR,
174
176
  enableSSR,
@@ -177,7 +179,7 @@ import {
177
179
  isSSR,
178
180
  runInSSRContext,
179
181
  withSSR
180
- } from "./chunk-TIRZCERI.js";
182
+ } from "./chunk-5DXA2J44.js";
181
183
  import {
182
184
  MAX_DRAIN_TEARDOWNS,
183
185
  checkLeaks,
@@ -186,15 +188,17 @@ import {
186
188
  replaceChildrenSafely,
187
189
  reportDrainRunaway,
188
190
  unregisterDisposer
189
- } from "./chunk-DHDZ7IVN.js";
191
+ } from "./chunk-QKRPLZ2V.js";
190
192
  import {
191
193
  batch,
192
194
  enqueueBatchedSignal,
195
+ external,
193
196
  isBatching,
194
197
  signal
195
- } from "./chunk-TVURNWDK.js";
198
+ } from "./chunk-HECVW343.js";
196
199
  import {
197
200
  notifySubscribers,
201
+ reactiveBinding,
198
202
  recordDependency,
199
203
  resumeTracking,
200
204
  retrack,
@@ -202,17 +206,19 @@ import {
202
206
  suspendTracking,
203
207
  track,
204
208
  untracked
205
- } from "./chunk-JYXQCELN.js";
209
+ } from "./chunk-7ALC7KGE.js";
206
210
  import {
211
+ DEV,
207
212
  __export,
208
213
  devAssert,
209
214
  devWarn,
215
+ devWarnLazy,
210
216
  getRuntimeErrorHandler,
211
217
  isDev,
212
218
  normalizeError,
213
219
  reportError,
214
220
  setRuntimeErrorHandler
215
- } from "./chunk-VPP2FONR.js";
221
+ } from "./chunk-2WLZ6757.js";
216
222
 
217
223
  // index.ts
218
224
  var index_exports = {};
@@ -292,6 +298,7 @@ __export(index_exports, {
292
298
  enhance: () => enhance,
293
299
  enhanceAll: () => enhanceAll,
294
300
  enqueueBatchedSignal: () => enqueueBatchedSignal,
301
+ external: () => external,
295
302
  fieldset: () => fieldset,
296
303
  figcaption: () => figcaption,
297
304
  figure: () => figure,
@@ -1746,34 +1753,53 @@ function setGlobalErrorHandler(handler) {
1746
1753
 
1747
1754
  // src/core/rendering/directives.ts
1748
1755
  function show(condition, element) {
1756
+ const resolved = typeof element === "function" ? element() : element;
1749
1757
  const update = () => {
1750
- element.style.display = condition() ? "" : "none";
1758
+ resolved.style.display = condition() ? "" : "none";
1751
1759
  };
1752
- registerDisposer(element, track(update));
1753
- return element;
1760
+ registerDisposer(resolved, track(update));
1761
+ return resolved;
1762
+ }
1763
+ function attachBranch(parent, anchor, branch, attachedOnce, where) {
1764
+ const result = typeof branch === "function" ? branch() : branch;
1765
+ if (result == null || typeof result === "boolean") return { node: null, owned: false };
1766
+ const node = result instanceof Node ? result : document.createTextNode(String(result));
1767
+ const handedIn = node === branch;
1768
+ const seenBefore = attachedOnce.has(node);
1769
+ const owned = !handedIn && !seenBefore;
1770
+ attachedOnce.add(node);
1771
+ if (seenBefore) {
1772
+ devWarnLazy(
1773
+ () => `${where}: ${handedIn ? "a branch was given as an element rather than a function" : "a branch factory returned a node it had already returned"}, so the SAME node is being re-attached \u2014 any state it accumulated while detached (input value, scroll position, classes set imperatively) comes back with it. Its reactive bindings are left intact rather than disposed, because the node is not this directive's to tear down. Return a FRESH node per call (\`() => div(\u2026)\`) for rebuild semantics, or keep this form deliberately when the reuse is what you want.`
1774
+ );
1775
+ }
1776
+ parent.insertBefore(node, anchor.nextSibling);
1777
+ return { node, owned };
1754
1778
  }
1755
1779
  function when(condition, thenBranch, elseBranch) {
1756
1780
  const anchor = document.createComment("when");
1757
1781
  let currentNode = null;
1758
1782
  let lastCondition;
1759
1783
  let initialized = false;
1784
+ const attachedOnce = /* @__PURE__ */ new WeakSet();
1785
+ let currentNodeOwned = false;
1760
1786
  const update = () => {
1761
1787
  const show2 = condition();
1762
1788
  const parent = anchor.parentNode;
1763
1789
  if (!parent) return;
1764
1790
  if (initialized && show2 === lastCondition) return;
1765
1791
  lastCondition = show2;
1792
+ const focused = currentNode ? captureFocusWithin([currentNode]) : null;
1766
1793
  if (currentNode?.parentNode) {
1767
- dispose(currentNode);
1794
+ if (currentNodeOwned) dispose(currentNode);
1768
1795
  currentNode.parentNode.removeChild(currentNode);
1769
1796
  currentNode = null;
1770
1797
  }
1771
- const result = show2 ? thenBranch() : elseBranch ? elseBranch() : null;
1772
- if (result != null) {
1773
- const node = result instanceof Node ? result : document.createTextNode(String(result));
1774
- parent.insertBefore(node, anchor.nextSibling);
1775
- currentNode = node;
1776
- }
1798
+ const branch = show2 ? thenBranch : elseBranch !== void 0 ? elseBranch : null;
1799
+ const attached = attachBranch(parent, anchor, branch, attachedOnce, "when");
1800
+ currentNode = attached.node;
1801
+ currentNodeOwned = attached.owned;
1802
+ restoreFocusWithin(focused, currentNode ? [currentNode] : [], "when");
1777
1803
  initialized = true;
1778
1804
  };
1779
1805
  registerDisposer(anchor, track(update));
@@ -1789,26 +1815,25 @@ function match(value, cases, fallback) {
1789
1815
  let currentNode = null;
1790
1816
  let lastKey;
1791
1817
  let initialized = false;
1818
+ const attachedOnce = /* @__PURE__ */ new WeakSet();
1819
+ let currentNodeOwned = false;
1792
1820
  const update = () => {
1793
1821
  const key = String(value());
1794
1822
  const parent = anchor.parentNode;
1795
1823
  if (!parent) return;
1796
1824
  if (initialized && key === lastKey) return;
1797
1825
  lastKey = key;
1826
+ const focused = currentNode ? captureFocusWithin([currentNode]) : null;
1798
1827
  if (currentNode?.parentNode) {
1799
- dispose(currentNode);
1828
+ if (currentNodeOwned) dispose(currentNode);
1800
1829
  currentNode.parentNode.removeChild(currentNode);
1801
1830
  currentNode = null;
1802
1831
  }
1803
- const renderFn = cases[key] || fallback;
1804
- if (renderFn) {
1805
- const result = renderFn();
1806
- if (result != null) {
1807
- const node = result instanceof Node ? result : document.createTextNode(String(result));
1808
- parent.insertBefore(node, anchor.nextSibling);
1809
- currentNode = node;
1810
- }
1811
- }
1832
+ const branch = Object.hasOwn(cases, key) ? cases[key] : fallback;
1833
+ const attached = attachBranch(parent, anchor, branch ?? null, attachedOnce, "match");
1834
+ currentNode = attached.node;
1835
+ currentNodeOwned = attached.owned;
1836
+ restoreFocusWithin(focused, currentNode ? [currentNode] : [], "match");
1812
1837
  initialized = true;
1813
1838
  };
1814
1839
  registerDisposer(anchor, track(update));
@@ -1853,7 +1878,6 @@ function DynamicComponent(is) {
1853
1878
  }
1854
1879
 
1855
1880
  // src/core/rendering/each.ts
1856
- var _isDev = isDev();
1857
1881
  function resolveNodeChild(child) {
1858
1882
  if (typeof child === "function") {
1859
1883
  return resolveNodeChild(child());
@@ -1944,7 +1968,7 @@ function each(getArray, render, options) {
1944
1968
  workMap.clear();
1945
1969
  keyIndexMap.clear();
1946
1970
  for (let i2 = 0; i2 < newLen; i2++) {
1947
- if (_isDev && keyIndexMap.has(newKeys[i2])) {
1971
+ if (DEV && keyIndexMap.has(newKeys[i2])) {
1948
1972
  devWarn(
1949
1973
  `each: duplicate key "${String(newKeys[i2])}" at index ${i2} (first seen at ${keyIndexMap.get(newKeys[i2])}). Keys must be unique \u2014 duplicates cause rows to be dropped or mis-ordered.`
1950
1974
  );
@@ -2128,7 +2152,6 @@ function resolveChild(child) {
2128
2152
  }
2129
2153
 
2130
2154
  // src/core/rendering/htm.ts
2131
- var _isDev2 = isDev();
2132
2155
  var RAW_TEXT_TAGS = /* @__PURE__ */ new Set(["script", "style"]);
2133
2156
  var VOID_ELEMENTS = /* @__PURE__ */ new Set([
2134
2157
  "area",
@@ -2408,7 +2431,7 @@ function executeElement(tmpl, values) {
2408
2431
  const fn = values[attr.idx];
2409
2432
  if (typeof fn === "function") {
2410
2433
  el.addEventListener(attr.name, fn);
2411
- } else if (_isDev2) {
2434
+ } else if (DEV) {
2412
2435
  devWarn(
2413
2436
  `html: on:${attr.name} handler is not a function (got ${typeof fn}). Event listener was not attached.`
2414
2437
  );
@@ -3173,6 +3196,7 @@ function drainTeardowns(teardowns, label2) {
3173
3196
  }
3174
3197
  }
3175
3198
  }
3199
+ var EACH_KEYS = ["text", "attr", "class", "show", "on", "cleanup"];
3176
3200
  function resolveTarget(root, target) {
3177
3201
  if (target == null) return root;
3178
3202
  if (typeof target !== "string") return target;
@@ -3183,6 +3207,11 @@ function resolveTarget(root, target) {
3183
3207
  return null;
3184
3208
  }
3185
3209
  }
3210
+ function bindNode(el, commit) {
3211
+ if (isSSR()) return () => {
3212
+ };
3213
+ return reactiveBinding(commit, el);
3214
+ }
3186
3215
  function readControlValue(el) {
3187
3216
  if (el instanceof HTMLInputElement) {
3188
3217
  if (el.type === "checkbox") return el.checked;
@@ -3206,6 +3235,50 @@ function writeControlValue(el, value) {
3206
3235
  const next = value == null ? "" : String(value);
3207
3236
  if (el.value !== next) el.value = next;
3208
3237
  }
3238
+ function applyEachBindings(ctx, el, spec, index) {
3239
+ const where = `ctx.each[${index}]`;
3240
+ if (isDev()) {
3241
+ for (const key of Object.keys(spec)) {
3242
+ devAssert(
3243
+ EACH_KEYS.includes(key),
3244
+ `${where}: unknown binding "${key}". Expected one of: ${EACH_KEYS.join(", ")}.`
3245
+ );
3246
+ }
3247
+ }
3248
+ if (spec.text !== void 0) {
3249
+ devAssert(typeof spec.text === "function", `${where}: "text" must be a function returning the value.`);
3250
+ ctx.text(el, spec.text);
3251
+ }
3252
+ if (spec.attr !== void 0) {
3253
+ for (const name of Object.keys(spec.attr)) {
3254
+ const value = spec.attr[name];
3255
+ devAssert(typeof value === "function", `${where}: attr["${name}"] must be a function returning the value.`);
3256
+ ctx.attr(el, name, value);
3257
+ }
3258
+ }
3259
+ if (spec.class !== void 0) {
3260
+ for (const name of Object.keys(spec.class)) {
3261
+ const on2 = spec.class[name];
3262
+ devAssert(typeof on2 === "function", `${where}: class["${name}"] must be a function returning a boolean.`);
3263
+ ctx.classed(el, name, on2);
3264
+ }
3265
+ }
3266
+ if (spec.show !== void 0) {
3267
+ devAssert(typeof spec.show === "function", `${where}: "show" must be a function returning a boolean.`);
3268
+ ctx.show(el, spec.show);
3269
+ }
3270
+ if (spec.on !== void 0) {
3271
+ for (const event of Object.keys(spec.on)) {
3272
+ const handler = spec.on[event];
3273
+ devAssert(typeof handler === "function", `${where}: on["${String(event)}"] must be a function.`);
3274
+ ctx.on(el, event, handler);
3275
+ }
3276
+ }
3277
+ if (spec.cleanup !== void 0) {
3278
+ devAssert(typeof spec.cleanup === "function", `${where}: "cleanup" must be a function.`);
3279
+ ctx.cleanup(spec.cleanup);
3280
+ }
3281
+ }
3209
3282
  function enhance(target, setup) {
3210
3283
  const root = typeof target === "string" ? typeof document !== "undefined" ? document.querySelector(target) : null : target;
3211
3284
  if (!root) {
@@ -3256,7 +3329,7 @@ function enhance(target, setup) {
3256
3329
  text: (t, value) => {
3257
3330
  bind(t, (el) => {
3258
3331
  teardowns.push(
3259
- effect(() => {
3332
+ bindNode(el, () => {
3260
3333
  const v = value();
3261
3334
  const next = v == null ? "" : String(v);
3262
3335
  if (el.textContent !== next) el.textContent = next;
@@ -3267,7 +3340,7 @@ function enhance(target, setup) {
3267
3340
  attr: (t, name, value) => {
3268
3341
  bind(t, (el) => {
3269
3342
  teardowns.push(
3270
- effect(() => {
3343
+ bindNode(el, () => {
3271
3344
  const v = value();
3272
3345
  const next = v == null ? null : String(v);
3273
3346
  setSafeAttribute(el, name, next, { syncValueProperty: false, label: "enhance attr()" });
@@ -3278,7 +3351,7 @@ function enhance(target, setup) {
3278
3351
  classed: (t, name, on2) => {
3279
3352
  bind(t, (el) => {
3280
3353
  teardowns.push(
3281
- effect(() => {
3354
+ bindNode(el, () => {
3282
3355
  el.classList.toggle(name, Boolean(on2()));
3283
3356
  })
3284
3357
  );
@@ -3288,7 +3361,7 @@ function enhance(target, setup) {
3288
3361
  bind(t, (el) => {
3289
3362
  const prevHidden = el.hidden;
3290
3363
  teardowns.push(
3291
- effect(() => {
3364
+ bindNode(el, () => {
3292
3365
  el.hidden = !when2();
3293
3366
  })
3294
3367
  );
@@ -3303,7 +3376,7 @@ function enhance(target, setup) {
3303
3376
  const [get, set] = state;
3304
3377
  const evt = options?.event ?? (control instanceof HTMLSelectElement || control instanceof HTMLInputElement && (control.type === "checkbox" || control.type === "radio") ? "change" : "input");
3305
3378
  teardowns.push(
3306
- effect(() => {
3379
+ bindNode(el, () => {
3307
3380
  writeControlValue(control, get());
3308
3381
  })
3309
3382
  );
@@ -3312,6 +3385,16 @@ function enhance(target, setup) {
3312
3385
  teardowns.push(() => control.removeEventListener(evt, onInput));
3313
3386
  });
3314
3387
  },
3388
+ each: (target_, describe) => {
3389
+ devAssert(typeof describe === "function", "ctx.each: second argument must be a function.");
3390
+ const elements = typeof target_ === "string" ? ctx.refs(target_) : Array.from(target_);
3391
+ for (let i2 = 0; i2 < elements.length; i2++) {
3392
+ const el = elements[i2];
3393
+ const spec = describe(el, i2);
3394
+ if (spec == null) continue;
3395
+ applyEachBindings(ctx, el, spec, i2);
3396
+ }
3397
+ },
3315
3398
  cleanup: (fn) => {
3316
3399
  teardowns.push(fn);
3317
3400
  }
@@ -1,3 +1,7 @@
1
+ import {
2
+ devWarnLazy
3
+ } from "./chunk-2WLZ6757.js";
4
+
1
5
  // src/utils/sanitize.ts
2
6
  function stripControlChars(value) {
3
7
  return value.replace(/[\x00-\x20\x7f-\x9f]+/g, "");
@@ -94,20 +98,75 @@ function decodeCssEscapes(value) {
94
98
  }
95
99
  return out;
96
100
  }
97
- function sanitizeCSSValue(value) {
98
- if (!CSS_DANGER_GATE.test(value)) return value;
101
+ var BLOCKED_CSS_NEEDLES = [
102
+ "url(",
103
+ "expression(",
104
+ "javascript:",
105
+ "vbscript:",
106
+ "-moz-binding",
107
+ "behavior:",
108
+ "@import",
109
+ "image-set(",
110
+ "filter:progid"
111
+ ];
112
+ function describeElement(el) {
113
+ if (!el) return "an element";
114
+ let out = el.tagName.toLowerCase();
115
+ const id = el.getAttribute("id");
116
+ if (id) out += `#${id}`;
117
+ const cls = el.getAttribute("class");
118
+ if (cls) out += `.${cls.trim().split(/\s+/).slice(0, 3).join(".")}`;
119
+ return `<${out}>`;
120
+ }
121
+ var warnedDeclarations = /* @__PURE__ */ new Set();
122
+ var MAX_WARNED_DECLARATIONS = 100;
123
+ var declarationCapAnnounced = false;
124
+ function warnDroppedDeclaration(value, reason, ctx) {
125
+ devWarnLazy(() => {
126
+ const reasons = [
127
+ "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",
128
+ "expression() executes arbitrary script in legacy engines",
129
+ "the javascript: scheme executes script",
130
+ "the vbscript: scheme executes script",
131
+ "-moz-binding loads and runs remote XBL",
132
+ "behavior: loads and runs a remote HTC script",
133
+ "@import pulls in a remote stylesheet",
134
+ "image-set() fetches remote images, the same exfiltration channel as url()",
135
+ "filter:progid activates legacy scriptable filters"
136
+ ];
137
+ const declaration = ctx?.property ? `${ctx.property}: ${value}` : value;
138
+ const where = describeElement(ctx?.element);
139
+ const key = `${where}|${declaration}`;
140
+ if (warnedDeclarations.has(key)) return "";
141
+ if (warnedDeclarations.size >= MAX_WARNED_DECLARATIONS) {
142
+ if (declarationCapAnnounced) return "";
143
+ declarationCapAnnounced = true;
144
+ 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.`;
145
+ }
146
+ warnedDeclarations.add(key);
147
+ 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.`;
148
+ });
149
+ }
150
+ function blockedCssReason(value) {
151
+ if (!CSS_DANGER_GATE.test(value)) return -1;
99
152
  const normalized = value.includes("\\") ? decodeCssEscapes(value) : value;
100
153
  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 "";
154
+ for (let i = 0; i < BLOCKED_CSS_NEEDLES.length; i++) {
155
+ if (lower.includes(BLOCKED_CSS_NEEDLES[i])) return i;
103
156
  }
104
- return value;
157
+ return -1;
158
+ }
159
+ function sanitizeCSSValue(value, context) {
160
+ const reason = blockedCssReason(value);
161
+ if (reason === -1) return value;
162
+ warnDroppedDeclaration(value, reason, context);
163
+ return "";
105
164
  }
106
- function sanitizeStyleAttribute(cssText) {
165
+ function sanitizeStyleAttribute(cssText, context) {
107
166
  const input = String(cssText);
108
167
  if (input.trim() === "") return "";
109
168
  if (typeof document === "undefined") {
110
- return sanitizeCSSValue(input) === "" ? "" : input;
169
+ return sanitizeCSSValue(input, context) === "" ? "" : input;
111
170
  }
112
171
  const probe = document.createElement("div");
113
172
  try {
@@ -119,8 +178,12 @@ function sanitizeStyleAttribute(cssText) {
119
178
  for (let i = 0; i < probe.style.length; i++) {
120
179
  const property = probe.style[i];
121
180
  const value = probe.style.getPropertyValue(property);
122
- if (sanitizeCSSValue(value) === "") continue;
123
- if (sanitizeCSSValue(`${property}:${value}`) === "") continue;
181
+ let reason = blockedCssReason(value);
182
+ if (reason === -1) reason = blockedCssReason(`${property}:${value}`);
183
+ if (reason !== -1) {
184
+ warnDroppedDeclaration(value, reason, { property, element: context?.element });
185
+ continue;
186
+ }
124
187
  const priority = probe.style.getPropertyPriority(property);
125
188
  declarations.push(`${property}: ${value}${priority ? ` !${priority}` : ""}`);
126
189
  }
@@ -171,11 +234,11 @@ function isPolicyAttribute(name) {
171
234
  const lower = name.toLowerCase();
172
235
  return lower === "style" || URL_ATTRIBUTES.has(lower);
173
236
  }
174
- function sanitizeAttributeString(attr, value) {
237
+ function sanitizeAttributeString(attr, value, context) {
175
238
  const lower = attr.toLowerCase();
176
239
  if (lower === "srcset") return sanitizeSrcset(value);
177
240
  if (URL_ATTRIBUTES.has(lower)) return sanitizeUrl(value);
178
- if (lower === "style") return sanitizeStyleAttribute(value);
241
+ if (lower === "style") return sanitizeStyleAttribute(value, context);
179
242
  return value;
180
243
  }
181
244
 
@@ -6,14 +6,14 @@ import {
6
6
  } from "./chunk-52XFPGSN.js";
7
7
  import {
8
8
  effect
9
- } from "./chunk-XDOMTQHM.js";
9
+ } from "./chunk-7VEC3UD2.js";
10
10
  import {
11
11
  batch,
12
12
  signal
13
- } from "./chunk-TVURNWDK.js";
13
+ } from "./chunk-HECVW343.js";
14
14
  import {
15
15
  reportError
16
- } from "./chunk-VPP2FONR.js";
16
+ } from "./chunk-2WLZ6757.js";
17
17
 
18
18
  // src/browser/media.ts
19
19
  function media(query) {
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  renderToString
3
- } from "./chunk-HYCCIYNS.js";
3
+ } from "./chunk-NIOYEGBQ.js";
4
4
 
5
5
  // src/plugins/modular.ts
6
6
  function createModuleRegistry() {
@@ -6,29 +6,29 @@ import {
6
6
  import {
7
7
  div,
8
8
  span
9
- } from "./chunk-E72G5JSK.js";
9
+ } from "./chunk-P3DHXBR6.js";
10
10
  import {
11
11
  STATIC_VALUE_RESOLVER,
12
12
  planHeadElementEntry,
13
13
  planMetaEntry
14
- } from "./chunk-HYCCIYNS.js";
14
+ } from "./chunk-NIOYEGBQ.js";
15
15
  import {
16
16
  sanitizeUrl
17
- } from "./chunk-5INI7D2L.js";
17
+ } from "./chunk-IXKSNWV5.js";
18
18
  import {
19
19
  globalSingleton
20
20
  } from "./chunk-7ZHH77QA.js";
21
21
  import {
22
22
  effect
23
- } from "./chunk-XDOMTQHM.js";
23
+ } from "./chunk-7VEC3UD2.js";
24
24
  import {
25
25
  registerDisposer,
26
26
  replaceChildrenSafely
27
- } from "./chunk-DHDZ7IVN.js";
27
+ } from "./chunk-QKRPLZ2V.js";
28
28
  import {
29
29
  batch,
30
30
  signal
31
- } from "./chunk-TVURNWDK.js";
31
+ } from "./chunk-HECVW343.js";
32
32
 
33
33
  // src/platform/head.ts
34
34
  function escapeScriptJsonLocal(json) {
@@ -6,17 +6,17 @@ import {
6
6
  sanitizeAttributeString,
7
7
  sanitizeUrl,
8
8
  stripControlChars
9
- } from "./chunk-5INI7D2L.js";
9
+ } from "./chunk-IXKSNWV5.js";
10
10
  import {
11
11
  getSSRStore
12
- } from "./chunk-TIRZCERI.js";
12
+ } from "./chunk-5DXA2J44.js";
13
13
  import {
14
14
  dispose,
15
15
  replaceChildrenSafely
16
- } from "./chunk-DHDZ7IVN.js";
16
+ } from "./chunk-QKRPLZ2V.js";
17
17
  import {
18
- isDev
19
- } from "./chunk-VPP2FONR.js";
18
+ DEV
19
+ } from "./chunk-2WLZ6757.js";
20
20
 
21
21
  // src/utils/metaRefresh.ts
22
22
  function isAsciiWhitespace(ch) {
@@ -185,13 +185,12 @@ function isForbiddenSsrAttr(lowerName) {
185
185
  function sanitizeSsrAttributeValue(lowerName, value) {
186
186
  return sanitizeAttributeString(lowerName, value);
187
187
  }
188
- var _isDev = isDev();
189
188
  var SAFE_ATTR_NAME = /^[A-Za-z_:][-A-Za-z0-9_.:]*$/;
190
189
  function isSafeAttrName(name) {
191
190
  return SAFE_ATTR_NAME.test(name);
192
191
  }
193
192
  function ssrErrorComment(err) {
194
- if (_isDev) {
193
+ if (DEV) {
195
194
  const msg = escapeHtml(err instanceof Error ? err.message : String(err));
196
195
  return `<!--SSR error: ${safeCommentText(msg)}-->`;
197
196
  }
@@ -237,10 +236,10 @@ function renderToString(element) {
237
236
  }
238
237
  const tag = element.tagName.toLowerCase();
239
238
  if (tag === "script" || tag === "style") {
240
- return _isDev ? `<!--ssr:${tag}-stripped-->` : "";
239
+ return DEV ? `<!--ssr:${tag}-stripped-->` : "";
241
240
  }
242
241
  if (!/^[a-z][a-z0-9-]*$/i.test(tag)) {
243
- return _isDev ? "<!--ssr:invalid-tag-->" : "";
242
+ return DEV ? "<!--ssr:invalid-tag-->" : "";
244
243
  }
245
244
  let html = `<${tag}`;
246
245
  for (const attr of Array.from(element.attributes)) {
@@ -282,7 +281,7 @@ function hydrate(component, container, options = {}) {
282
281
  const first = mismatches[0];
283
282
  if (options.onMismatch) {
284
283
  options.onMismatch(first);
285
- } else if (_isDev) {
284
+ } else if (DEV) {
286
285
  console.warn(
287
286
  `[SibuJS hydration] ${first.message}
288
287
  at ${first.path}
@@ -483,11 +482,11 @@ async function* renderToStream(element) {
483
482
  }
484
483
  const tag = element.tagName.toLowerCase();
485
484
  if (tag === "script" || tag === "style") {
486
- if (_isDev) yield `<!--ssr:${tag}-stripped-->`;
485
+ if (DEV) yield `<!--ssr:${tag}-stripped-->`;
487
486
  return;
488
487
  }
489
488
  if (!/^[a-z][a-z0-9-]*$/i.test(tag)) {
490
- if (_isDev) yield "<!--ssr:invalid-tag-->";
489
+ if (DEV) yield "<!--ssr:invalid-tag-->";
491
490
  return;
492
491
  }
493
492
  let openTag = `<${tag}`;
@@ -630,7 +629,7 @@ function ssrSuspense(props) {
630
629
  },
631
630
  (err) => {
632
631
  if (timer) clearTimeout(timer);
633
- if (_isDev) console.warn("[SibuJS SSR] ssrSuspense rejected:", err);
632
+ if (DEV) console.warn("[SibuJS SSR] ssrSuspense rejected:", err);
634
633
  return { id, html: fallbackHtml };
635
634
  }
636
635
  );
@@ -676,7 +675,7 @@ function serializeState(state, nonce, options) {
676
675
  }
677
676
  function deserializeState(validate) {
678
677
  if (typeof window === "undefined") return void 0;
679
- if (_isDev && !validate) {
678
+ if (DEV && !validate) {
680
679
  console.warn(
681
680
  "[SibuJS SSR] deserializeState() called without a validate guard \u2014 tampered SSR payloads will not be detected."
682
681
  );
@@ -4,14 +4,14 @@ import {
4
4
  } from "./chunk-H3SRKIYX.js";
5
5
  import {
6
6
  derived
7
- } from "./chunk-AD5YSZAN.js";
7
+ } from "./chunk-2LOYNGBY.js";
8
8
  import {
9
9
  effect
10
- } from "./chunk-XDOMTQHM.js";
10
+ } from "./chunk-7VEC3UD2.js";
11
11
  import {
12
12
  batch,
13
13
  signal
14
- } from "./chunk-TVURNWDK.js";
14
+ } from "./chunk-HECVW343.js";
15
15
 
16
16
  // src/patterns/machine.ts
17
17
  function machine(config) {
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  SVG_NS,
3
3
  tagFactory
4
- } from "./chunk-QD4I7ZGZ.js";
4
+ } from "./chunk-6ZGI3RBE.js";
5
5
 
6
6
  // src/core/rendering/html.ts
7
7
  var html = tagFactory("html");