voodoojs 0.11.2 → 0.12.2

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 (41) hide show
  1. package/README.md +1 -1
  2. package/dist/{chunk-IGZSDZKU.js → chunk-7AKBELZA.js} +4 -4
  3. package/dist/{chunk-V3O3WOZH.js → chunk-AVXQPDQH.js} +4 -4
  4. package/dist/{chunk-AH2VXDZD.js → chunk-K2U3O36M.js} +193 -20
  5. package/dist/{chunk-IS3DR2KY.js → chunk-MEE2ZAKJ.js} +3 -3
  6. package/dist/{chunk-DJJB35SR.js → chunk-NVANUFWZ.js} +6 -6
  7. package/dist/{chunk-H2ZUEQWV.js → chunk-OWCQV42D.js} +112 -20
  8. package/dist/{chunk-KQYSJHZR.js → chunk-RTZEIVNA.js} +5 -5
  9. package/dist/{chunk-NFDXVIII.js → chunk-RXOLGHSU.js} +3 -3
  10. package/dist/{chunk-WJP3YGUI.js → chunk-S4BXAGAW.js} +4 -4
  11. package/dist/{chunk-DCE5WIGA.js → chunk-UGLD36KV.js} +5 -5
  12. package/dist/{chunk-UV5PMS7P.js → chunk-YV4I45SK.js} +4 -4
  13. package/dist/essential.cjs +297 -28
  14. package/dist/essential.d.cts +1 -1
  15. package/dist/essential.d.ts +1 -1
  16. package/dist/essential.js +10 -10
  17. package/dist/gpu.cjs +1 -1
  18. package/dist/gpu.js +10 -10
  19. package/dist/http.cjs +1 -1
  20. package/dist/http.js +5 -5
  21. package/dist/index.cjs +325 -34
  22. package/dist/index.d.cts +88 -4
  23. package/dist/index.d.ts +88 -4
  24. package/dist/index.js +38 -24
  25. package/dist/{query-DiQAS73Q.d.cts → query-D_BGQw8m.d.cts} +12 -1
  26. package/dist/{query-Cf-7iibE.d.ts → query-Dl6Urlwd.d.ts} +12 -1
  27. package/dist/reactivity.cjs +1 -1
  28. package/dist/reactivity.js +2 -2
  29. package/dist/socket.cjs +29 -2
  30. package/dist/socket.js +9 -9
  31. package/dist/style-GWGXWHB4.js +5 -0
  32. package/dist/utils.cjs +1 -1
  33. package/dist/utils.js +2 -2
  34. package/dist/voodoo.core.js +277 -27
  35. package/dist/voodoo.core.min.js +17 -17
  36. package/dist/voodoo.full.js +325 -36
  37. package/dist/voodoo.full.min.js +59 -55
  38. package/dist/voodoo.js +305 -30
  39. package/dist/voodoo.min.js +29 -25
  40. package/package.json +1 -1
  41. package/dist/style-4X62SABN.js +0 -5
package/README.md CHANGED
@@ -22,7 +22,7 @@ npm install voodoojs
22
22
  Or drop it into a page, with nothing else:
23
23
 
24
24
  ```html
25
- <script src="https://cdn.jsdelivr.net/npm/voodoojs@0.11.2/dist/voodoo.full.min.js" defer></script>
25
+ <script src="https://cdn.jsdelivr.net/npm/voodoojs@0.12.2/dist/voodoo.full.min.js" defer></script>
26
26
 
27
27
  <div v-data="{ count: 0 }">
28
28
  <button @click="count++">Clicked { count } times</button>
@@ -1,7 +1,7 @@
1
- import { __export } from './chunk-IS3DR2KY.js';
1
+ import { __export } from './chunk-MEE2ZAKJ.js';
2
2
 
3
3
  /**
4
- * Voodoo.js v0.11.2
4
+ * Voodoo.js v0.12.2
5
5
  * JavaScript feels like magic.
6
6
  * (c) 2026 Voodoo.js contributors. MIT License.
7
7
  */
@@ -397,5 +397,5 @@ var device = {
397
397
  };
398
398
 
399
399
  export { capitalize, chunk, clone, debounce, device, escapeHtml, formatCurrency, formatDate, formatFileSize, formatNumber, formatPercent, get, groupBy, isBrowser, matchesMedia, memoize, merge, once, parseDuration, random, relativeTime, sample, set, setFormatDefaults, sleep, slugify, sortBy, stripTags, throttle, titleCase, truncate, uid, unique, utils_exports, uuid };
400
- //# sourceMappingURL=chunk-IGZSDZKU.js.map
401
- //# sourceMappingURL=chunk-IGZSDZKU.js.map
400
+ //# sourceMappingURL=chunk-7AKBELZA.js.map
401
+ //# sourceMappingURL=chunk-7AKBELZA.js.map
@@ -1,7 +1,7 @@
1
- import { config } from './chunk-NFDXVIII.js';
1
+ import { config } from './chunk-RXOLGHSU.js';
2
2
 
3
3
  /**
4
- * Voodoo.js v0.11.2
4
+ * Voodoo.js v0.12.2
5
5
  * JavaScript feels like magic.
6
6
  * (c) 2026 Voodoo.js contributors. MIT License.
7
7
  */
@@ -68,5 +68,5 @@ function ensureTokens() {
68
68
  }
69
69
 
70
70
  export { BASE_TOKENS, ensureTokens, injectStyle };
71
- //# sourceMappingURL=chunk-V3O3WOZH.js.map
72
- //# sourceMappingURL=chunk-V3O3WOZH.js.map
71
+ //# sourceMappingURL=chunk-AVXQPDQH.js.map
72
+ //# sourceMappingURL=chunk-AVXQPDQH.js.map
@@ -1,14 +1,14 @@
1
- import { http, HttpError, request } from './chunk-DJJB35SR.js';
2
- import { stringify, markInitialized, markSkipChildren, destroy, walk, removeQuietly, evaluateIn, addCleanup, markNodeScope, setComponentMounter, closestDirective, magic, readAttr, hasAttr, componentAliases, Scope, queryDirective, parse, evaluate, parseAttribute, originalAttributes, hasDirective, findScope, VoodooRuntimeError, VoodooSyntaxError, allowedGlobals, clearParseCache, tokenize, getScope, stopObserving, refresh, start, magics, rootScope, isInitialized, restoreAttributes, hasDirectives } from './chunk-H2ZUEQWV.js';
3
- import { ref, reactive, handleError, nextTick, queuePostFlush, warn, watch, EffectScope, computed, effect, toRaw, flushSync, effectScope, stop, unref, markRaw, watchEffect, shallowRef, setErrorHandler } from './chunk-WJP3YGUI.js';
4
- import { warnDuplicateKey, warn as warn$1, describeElement, warnUnknownComponent, warnAlias, warnRequiredProp } from './chunk-UV5PMS7P.js';
5
- import { parseDuration, debounce, utils_exports, throttle, uid, device, escapeHtml } from './chunk-IGZSDZKU.js';
6
- import { injectStyle, ensureTokens } from './chunk-V3O3WOZH.js';
7
- import { defineDirective, config, PRIORITY, directives, normalizeComponentName, components, usePlugin } from './chunk-NFDXVIII.js';
8
- import { __publicField } from './chunk-IS3DR2KY.js';
1
+ import { http, HttpError, request } from './chunk-NVANUFWZ.js';
2
+ import { stringify, markInitialized, markSkipChildren, destroy, walk, removeQuietly, evaluateIn, addCleanup, markNodeScope, setComponentMounter, closestDirective, magic, readAttr, hasAttr, componentAliases, Scope, hook, queryDirective, parse, evaluate, parseAttribute, originalAttributes, hasDirective, currentHookHost, findScope, VoodooRuntimeError, VoodooSyntaxError, allowedGlobals, clearParseCache, tokenize, getScope, stopObserving, refresh, start, magics, rootScope, isInitialized, restoreAttributes, hasDirectives } from './chunk-OWCQV42D.js';
3
+ import { ref, reactive, handleError, nextTick, queuePostFlush, warn, watch, EffectScope, computed, effect, toRaw, markRaw, stop, flushSync, effectScope, unref, watchEffect, shallowRef, setErrorHandler } from './chunk-S4BXAGAW.js';
4
+ import { warnDuplicateKey, warn as warn$1, describeElement, warnUnknownComponent, warnAlias, warnRequiredProp } from './chunk-YV4I45SK.js';
5
+ import { parseDuration, debounce, utils_exports, throttle, uid, device, escapeHtml } from './chunk-7AKBELZA.js';
6
+ import { injectStyle, ensureTokens } from './chunk-AVXQPDQH.js';
7
+ import { defineDirective, config, PRIORITY, directives, normalizeComponentName, components, usePlugin } from './chunk-RXOLGHSU.js';
8
+ import { __publicField } from './chunk-MEE2ZAKJ.js';
9
9
 
10
10
  /**
11
- * Voodoo.js v0.11.2
11
+ * Voodoo.js v0.12.2
12
12
  * JavaScript feels like magic.
13
13
  * (c) 2026 Voodoo.js contributors. MIT License.
14
14
  */
@@ -338,10 +338,10 @@ var LIFECYCLE = /* @__PURE__ */ new Set([
338
338
  "destroyed"
339
339
  ]);
340
340
  function callHook(def, instance, name) {
341
- const hook = def[name];
342
- if (typeof hook !== "function") return;
341
+ const hook2 = def[name];
342
+ if (typeof hook2 !== "function") return;
343
343
  try {
344
- hook.call(instance);
344
+ hook2.call(instance);
345
345
  } catch (err) {
346
346
  handleError(err, `hook ${name}`);
347
347
  }
@@ -1116,21 +1116,28 @@ var cache = {
1116
1116
  };
1117
1117
  var THEME_KEY = "voodoo:theme";
1118
1118
  var picked = null;
1119
+ var revision = ref(0);
1119
1120
  var theme = {
1120
1121
  /** Theme chosen by the user, or `system` when never set. */
1121
1122
  get current() {
1123
+ void revision.value;
1122
1124
  return storage.get(THEME_KEY) ?? picked ?? "system";
1123
1125
  },
1124
1126
  /** Theme effectively applied, resolving `system`. */
1125
1127
  get resolved() {
1126
1128
  const value = this.current;
1127
1129
  if (value !== "system") return value;
1130
+ if (typeof document !== "undefined") {
1131
+ const authored = document.documentElement.getAttribute("data-theme");
1132
+ if (authored === "light" || authored === "dark") return authored;
1133
+ }
1128
1134
  if (typeof matchMedia === "undefined") return "light";
1129
1135
  return matchMedia("(prefers-color-scheme: dark)").matches ? "dark" : "light";
1130
1136
  },
1131
1137
  set(value) {
1132
1138
  picked = value;
1133
1139
  storage.set(THEME_KEY, value);
1140
+ revision.value++;
1134
1141
  this.apply();
1135
1142
  },
1136
1143
  toggle() {
@@ -1164,8 +1171,17 @@ var theme = {
1164
1171
  init() {
1165
1172
  if (typeof document === "undefined") return;
1166
1173
  this.apply();
1174
+ if (typeof MutationObserver !== "undefined") {
1175
+ new MutationObserver(() => {
1176
+ revision.value++;
1177
+ }).observe(document.documentElement, {
1178
+ attributes: true,
1179
+ attributeFilter: ["data-theme"]
1180
+ });
1181
+ }
1167
1182
  if (typeof matchMedia === "undefined") return;
1168
1183
  matchMedia("(prefers-color-scheme: dark)").addEventListener("change", () => {
1184
+ revision.value++;
1169
1185
  if (this.current === "system") this.apply();
1170
1186
  });
1171
1187
  }
@@ -1298,6 +1314,139 @@ function installMagics() {
1298
1314
  );
1299
1315
  }
1300
1316
 
1317
+ // src/hooks/index.ts
1318
+ var tables = /* @__PURE__ */ new WeakMap();
1319
+ function tableFor(scope) {
1320
+ const host = currentHookHost() ?? scope.el ?? scope;
1321
+ let table = tables.get(host);
1322
+ if (!table) {
1323
+ table = { slots: [], index: 0, scheduled: false, bound: false };
1324
+ tables.set(host, table);
1325
+ }
1326
+ const el = currentHookHost() ?? scope.el;
1327
+ if (!table.bound && el) {
1328
+ table.bound = true;
1329
+ const owned = table;
1330
+ addCleanup(el, () => {
1331
+ for (const slot of owned.slots) {
1332
+ if (slot.dispose) slot.dispose();
1333
+ if (slot.runner) stop(slot.runner);
1334
+ }
1335
+ owned.slots.length = 0;
1336
+ });
1337
+ }
1338
+ if (!table.scheduled) {
1339
+ table.scheduled = true;
1340
+ const pending = table;
1341
+ queueMicrotask(() => {
1342
+ pending.index = 0;
1343
+ pending.scheduled = false;
1344
+ });
1345
+ }
1346
+ return table;
1347
+ }
1348
+ function nextSlot(scope, kind) {
1349
+ const table = tableFor(scope);
1350
+ const at = table.index++;
1351
+ let slot = table.slots[at];
1352
+ if (!slot || slot.kind !== kind) {
1353
+ if (slot) {
1354
+ if (slot.dispose) slot.dispose();
1355
+ if (slot.runner) stop(slot.runner);
1356
+ }
1357
+ slot = { kind, deps: null, value: void 0 };
1358
+ table.slots[at] = slot;
1359
+ }
1360
+ return slot;
1361
+ }
1362
+ function depsChanged(previous, next) {
1363
+ if (!previous || !next) return true;
1364
+ if (previous.length !== next.length) return true;
1365
+ for (let i = 0; i < next.length; i++) {
1366
+ if (!Object.is(previous[i], next[i])) return true;
1367
+ }
1368
+ return false;
1369
+ }
1370
+ function normalizeDeps(deps) {
1371
+ return Array.isArray(deps) ? deps.slice() : null;
1372
+ }
1373
+ function useState(scope, initial) {
1374
+ const slot = nextSlot(scope, "state");
1375
+ if (slot.value === void 0) slot.value = ref(initial);
1376
+ return slot.value;
1377
+ }
1378
+ function useEffect(scope, fn, deps) {
1379
+ const slot = nextSlot(scope, "effect");
1380
+ const next = normalizeDeps(deps);
1381
+ const runCleanup = () => {
1382
+ if (slot.dispose) {
1383
+ const dispose = slot.dispose;
1384
+ slot.dispose = void 0;
1385
+ dispose();
1386
+ }
1387
+ };
1388
+ if (next) {
1389
+ const first = slot.deps === null && !slot.runner;
1390
+ if (first || depsChanged(slot.deps, next)) {
1391
+ slot.deps = next;
1392
+ runCleanup();
1393
+ const result = fn();
1394
+ if (typeof result === "function") slot.dispose = result;
1395
+ }
1396
+ return;
1397
+ }
1398
+ if (slot.runner) return;
1399
+ slot.deps = null;
1400
+ slot.runner = effect(() => {
1401
+ runCleanup();
1402
+ const result = fn();
1403
+ if (typeof result === "function") slot.dispose = result;
1404
+ });
1405
+ }
1406
+ function useMemo(scope, fn, deps) {
1407
+ const slot = nextSlot(scope, "memo");
1408
+ const next = normalizeDeps(deps);
1409
+ if (!next) {
1410
+ if (!slot.value) slot.value = computed(fn);
1411
+ return slot.value;
1412
+ }
1413
+ if (!slot.value) {
1414
+ slot.value = ref(fn());
1415
+ slot.deps = next;
1416
+ } else if (depsChanged(slot.deps, next)) {
1417
+ slot.deps = next;
1418
+ slot.value.value = fn();
1419
+ }
1420
+ return slot.value;
1421
+ }
1422
+ function useRef(scope, initial) {
1423
+ const slot = nextSlot(scope, "ref");
1424
+ if (!slot.value) slot.value = markRaw({ current: initial });
1425
+ return slot.value;
1426
+ }
1427
+ function useContext(name, initial) {
1428
+ if (initial !== void 0 && !(name in allStores)) {
1429
+ store(name, initial);
1430
+ }
1431
+ return allStores[name];
1432
+ }
1433
+ function installHooks() {
1434
+ hook("useState", (scope) => (initial) => useState(scope, initial));
1435
+ hook(
1436
+ "useEffect",
1437
+ (scope) => (fn, deps) => useEffect(scope, fn, deps)
1438
+ );
1439
+ hook(
1440
+ "useMemo",
1441
+ (scope) => (fn, deps) => useMemo(scope, fn, deps)
1442
+ );
1443
+ hook("useRef", (scope) => (initial) => useRef(scope, initial));
1444
+ hook(
1445
+ "useContext",
1446
+ () => (name, initial) => useContext(name, initial)
1447
+ );
1448
+ }
1449
+
1301
1450
  // src/http/resource.ts
1302
1451
  function pick(value, path) {
1303
1452
  if (!path) return value;
@@ -2662,7 +2811,7 @@ var jsonStylesInjected = false;
2662
2811
  function injectJSONStyles() {
2663
2812
  if (jsonStylesInjected) return;
2664
2813
  jsonStylesInjected = true;
2665
- void import('./style-4X62SABN.js').then(({ injectStyle: injectStyle2 }) => {
2814
+ void import('./style-GWGXWHB4.js').then(({ injectStyle: injectStyle2 }) => {
2666
2815
  injectStyle2(
2667
2816
  "json-render",
2668
2817
  `
@@ -2871,6 +3020,7 @@ setComponentMounter(mountComponent);
2871
3020
  setScopeMarker(markNodeScope);
2872
3021
  setDirectiveRegistrar(directive);
2873
3022
  installMagics();
3023
+ installHooks();
2874
3024
  var eventBus = /* @__PURE__ */ new Map();
2875
3025
  function on(name, handler) {
2876
3026
  let set = eventBus.get(name);
@@ -2949,7 +3099,7 @@ function data(values) {
2949
3099
  Object.defineProperties(rootScope.data, Object.getOwnPropertyDescriptors(values));
2950
3100
  return rootScope.data;
2951
3101
  }
2952
- var version2 = "0.11.2";
3102
+ var version2 = "0.12.2";
2953
3103
  var core = {
2954
3104
  // Utilities first: Voodoo's own names can override.
2955
3105
  ...utils_exports,
@@ -5132,6 +5282,7 @@ defineDirective("collapse", ({ el }) => {
5132
5282
  ensureUi();
5133
5283
  collapseOf(el);
5134
5284
  });
5285
+ var selfToggling = /* @__PURE__ */ new WeakSet();
5135
5286
  defineDirective("collapse-toggle", ({ el, expression, cleanup }) => {
5136
5287
  ensureUi();
5137
5288
  const target = resolveTarget(el, expression);
@@ -5140,6 +5291,8 @@ defineDirective("collapse-toggle", ({ el, expression, cleanup }) => {
5140
5291
  controller.triggers.add(el);
5141
5292
  controller.sync();
5142
5293
  makeInteractive(el, cleanup);
5294
+ selfToggling.add(el);
5295
+ cleanup(() => selfToggling.delete(el));
5143
5296
  const onClick = (event) => {
5144
5297
  event.preventDefault();
5145
5298
  controller.toggle();
@@ -5550,10 +5703,11 @@ defineDirective("accordion", ({ el, cleanup }) => {
5550
5703
  if (index === -1) return;
5551
5704
  event.preventDefault();
5552
5705
  const controller = controllers2[index];
5553
- if (single && !controller.open) {
5706
+ const ownToggle = selfToggling.has(header);
5707
+ if (single && (ownToggle ? controller.open : !controller.open)) {
5554
5708
  for (const other of controllers2) if (other !== controller) other.hide();
5555
5709
  }
5556
- controller.toggle();
5710
+ if (!ownToggle) controller.toggle();
5557
5711
  };
5558
5712
  const onKeyDown = (event) => {
5559
5713
  const header = event.target?.closest(".v-accordion-header");
@@ -8367,6 +8521,7 @@ var isMuted = false;
8367
8521
  var hasLoadedPreference = false;
8368
8522
  var VOLUME_KEY = "voodoo:sound:volume";
8369
8523
  var MUTE_KEY = "voodoo:sound:muted";
8524
+ var muteRevision = ref(0);
8370
8525
  function loadPreference() {
8371
8526
  if (hasLoadedPreference) return;
8372
8527
  hasLoadedPreference = true;
@@ -8678,6 +8833,7 @@ var sound = {
8678
8833
  loadPreference();
8679
8834
  isMuted = value;
8680
8835
  storage.set(MUTE_KEY, isMuted);
8836
+ muteRevision.value++;
8681
8837
  },
8682
8838
  /** Unmutes sound. */
8683
8839
  unmute() {
@@ -8689,8 +8845,18 @@ var sound = {
8689
8845
  this.mute(!isMuted);
8690
8846
  return isMuted;
8691
8847
  },
8692
- /** `true` when muted. */
8848
+ /**
8849
+ * `true` when muted.
8850
+ *
8851
+ * Reads a revision ref first, so that an expression asking whether sound is
8852
+ * muted actually re-runs when it changes. The state lives in a module
8853
+ * variable and in localStorage, both invisible to the Proxy, so
8854
+ * `v-show="$sound.muted"` used to render once and then never move: a page had
8855
+ * no way to show whether it was muted, which made the mute button look like
8856
+ * it did nothing at all.
8857
+ */
8693
8858
  get muted() {
8859
+ void muteRevision.value;
8694
8860
  loadPreference();
8695
8861
  return isMuted;
8696
8862
  },
@@ -8740,11 +8906,18 @@ defineDirective("sound", ({ el, arg, expression, modifiers, scope, cleanup, eval
8740
8906
  el.addEventListener(event, play);
8741
8907
  cleanup(() => el.removeEventListener(event, play));
8742
8908
  });
8909
+ var MUTE_CSS = `
8910
+ .v-muted{opacity:.55}
8911
+ .v-muted::after{content:" \\1F507";font-size:.9em}
8912
+ .v-mute-on::after{content:" \\1F50A";font-size:.9em}
8913
+ `;
8743
8914
  defineDirective("mute", ({ el, cleanup }) => {
8915
+ injectStyle("mute", MUTE_CSS);
8744
8916
  const sync = () => {
8745
8917
  const isMuted2 = sound.muted;
8746
8918
  el.setAttribute("aria-pressed", String(isMuted2));
8747
8919
  el.classList.toggle("v-muted", isMuted2);
8920
+ el.classList.toggle("v-mute-on", !isMuted2);
8748
8921
  };
8749
8922
  const toggle = () => {
8750
8923
  sound.toggle();
@@ -10270,6 +10443,6 @@ defineDirective(
10270
10443
  { priority: PRIORITY.MODEL + 5 }
10271
10444
  );
10272
10445
 
10273
- export { VoodooCollection, alert, allStores, applyMask, cache, clearErrors, clipboard, confirm, cookie, core, createApp, createResource, defineComponent, dialog, efeitos, ensurePalette, enter, fadeIn, fadeOut, fromHtml, hotkey, instances, leave, mask, masks, messages, modal, mountComponent, network, palette, prompt, query, ready, ready2, registerMask, removeStore, screen, serializeForm, session, showFieldError, showFormErrors, slideDown, slideUp, sound, storage, store, storeNames, theme, toast, unmask, url, validate, validator, viewTransition, whenElement, whenReady };
10274
- //# sourceMappingURL=chunk-AH2VXDZD.js.map
10275
- //# sourceMappingURL=chunk-AH2VXDZD.js.map
10446
+ export { VoodooCollection, alert, allStores, applyMask, cache, clearErrors, clipboard, confirm, cookie, core, createApp, createResource, defineComponent, dialog, efeitos, ensurePalette, enter, fadeIn, fadeOut, fromHtml, hotkey, installHooks, instances, leave, mask, masks, messages, modal, mountComponent, network, palette, prompt, query, ready, ready2, registerMask, removeStore, screen, serializeForm, session, showFieldError, showFormErrors, slideDown, slideUp, sound, storage, store, storeNames, theme, toast, unmask, url, useContext, useEffect, useMemo, useRef, useState, validate, validator, viewTransition, whenElement, whenReady };
10447
+ //# sourceMappingURL=chunk-K2U3O36M.js.map
10448
+ //# sourceMappingURL=chunk-K2U3O36M.js.map
@@ -1,5 +1,5 @@
1
1
  /**
2
- * Voodoo.js v0.11.2
2
+ * Voodoo.js v0.12.2
3
3
  * JavaScript feels like magic.
4
4
  * (c) 2026 Voodoo.js contributors. MIT License.
5
5
  */
@@ -12,5 +12,5 @@ var __export = (target, all) => {
12
12
  var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
13
13
 
14
14
  export { __export, __publicField };
15
- //# sourceMappingURL=chunk-IS3DR2KY.js.map
16
- //# sourceMappingURL=chunk-IS3DR2KY.js.map
15
+ //# sourceMappingURL=chunk-MEE2ZAKJ.js.map
16
+ //# sourceMappingURL=chunk-MEE2ZAKJ.js.map
@@ -1,9 +1,9 @@
1
- import { warnOnce } from './chunk-UV5PMS7P.js';
2
- import { parseDuration } from './chunk-IGZSDZKU.js';
3
- import { __publicField } from './chunk-IS3DR2KY.js';
1
+ import { warnOnce } from './chunk-YV4I45SK.js';
2
+ import { parseDuration } from './chunk-7AKBELZA.js';
3
+ import { __publicField } from './chunk-MEE2ZAKJ.js';
4
4
 
5
5
  /**
6
- * Voodoo.js v0.11.2
6
+ * Voodoo.js v0.12.2
7
7
  * JavaScript feels like magic.
8
8
  * (c) 2026 Voodoo.js contributors. MIT License.
9
9
  */
@@ -444,5 +444,5 @@ var http = {
444
444
  };
445
445
 
446
446
  export { HttpError, clearCache, flushOfflineQueue, http, request };
447
- //# sourceMappingURL=chunk-DJJB35SR.js.map
448
- //# sourceMappingURL=chunk-DJJB35SR.js.map
447
+ //# sourceMappingURL=chunk-NVANUFWZ.js.map
448
+ //# sourceMappingURL=chunk-NVANUFWZ.js.map
@@ -1,10 +1,10 @@
1
- import { reactive, handleError, EffectScope, effect } from './chunk-WJP3YGUI.js';
2
- import { inDevelopment, warnInvalidExpression, warnUnknownDirective } from './chunk-UV5PMS7P.js';
3
- import { config, directives, components } from './chunk-NFDXVIII.js';
4
- import { __publicField } from './chunk-IS3DR2KY.js';
1
+ import { reactive, handleError, EffectScope, effect } from './chunk-S4BXAGAW.js';
2
+ import { inDevelopment, warnInvalidExpression, warnUnknownDirective } from './chunk-YV4I45SK.js';
3
+ import { config, directives, components } from './chunk-RXOLGHSU.js';
4
+ import { __publicField } from './chunk-MEE2ZAKJ.js';
5
5
 
6
6
  /**
7
- * Voodoo.js v0.11.2
7
+ * Voodoo.js v0.12.2
8
8
  * JavaScript feels like magic.
9
9
  * (c) 2026 Voodoo.js contributors. MIT License.
10
10
  */
@@ -957,6 +957,23 @@ var DELIBERATELY_WITHHELD = /* @__PURE__ */ new Set([
957
957
  "SharedWorker",
958
958
  "ServiceWorker"
959
959
  ]);
960
+ function guardedTimer(name) {
961
+ return function(handler, timeout, ...rest) {
962
+ if (typeof handler !== "function") {
963
+ throw new VoodooRuntimeError(
964
+ `${name} needs a function. Passing a string would compile it, which this library never does.`
965
+ );
966
+ }
967
+ const timer = globalThis[name];
968
+ return timer(handler, timeout, ...rest);
969
+ };
970
+ }
971
+ function forwardGlobal(name) {
972
+ return function(...args) {
973
+ const fn = globalThis[name];
974
+ return fn(...args);
975
+ };
976
+ }
960
977
  var allowedGlobals = {
961
978
  Math,
962
979
  JSON,
@@ -975,7 +992,17 @@ var allowedGlobals = {
975
992
  isFinite,
976
993
  encodeURIComponent,
977
994
  decodeURIComponent,
978
- console
995
+ console,
996
+ ...typeof setTimeout !== "undefined" ? {
997
+ setTimeout: guardedTimer("setTimeout"),
998
+ setInterval: guardedTimer("setInterval"),
999
+ clearTimeout: forwardGlobal("clearTimeout"),
1000
+ clearInterval: forwardGlobal("clearInterval")
1001
+ } : {},
1002
+ ...typeof requestAnimationFrame !== "undefined" ? {
1003
+ requestAnimationFrame: forwardGlobal("requestAnimationFrame"),
1004
+ cancelAnimationFrame: forwardGlobal("cancelAnimationFrame")
1005
+ } : {}
979
1006
  };
980
1007
  var VoodooRuntimeError = class extends Error {
981
1008
  constructor(message, expression) {
@@ -1417,6 +1444,10 @@ var magics = /* @__PURE__ */ new Map();
1417
1444
  function magic(name, getter) {
1418
1445
  magics.set(name.startsWith("$") ? name : `$${name}`, getter);
1419
1446
  }
1447
+ var hooks = /* @__PURE__ */ new Map();
1448
+ function hook(name, getter) {
1449
+ hooks.set(name, getter);
1450
+ }
1420
1451
  var Scope = class _Scope {
1421
1452
  // Assignment order matches the order the fields were declared in before, so
1422
1453
  // the properties are created in the same sequence they always were.
@@ -1472,7 +1503,10 @@ var Scope = class _Scope {
1472
1503
  s = s.parent;
1473
1504
  }
1474
1505
  if (name.charCodeAt(0) === 36 && magics.has(name)) {
1475
- return this.magicContainer(name);
1506
+ return this.magicContainer(name, magics);
1507
+ }
1508
+ if (hooks.has(name)) {
1509
+ return this.magicContainer(name, hooks);
1476
1510
  }
1477
1511
  return void 0;
1478
1512
  }
@@ -1501,11 +1535,11 @@ var Scope = class _Scope {
1501
1535
  reactiveChild(vars, el = null) {
1502
1536
  return new _Scope(reactive(vars), this, el ?? this.el);
1503
1537
  }
1504
- magicContainer(name) {
1538
+ magicContainer(name, registry) {
1505
1539
  if (!this.magicCache) this.magicCache = /* @__PURE__ */ new Map();
1506
1540
  const cached = this.magicCache.get(name);
1507
1541
  if (cached) return cached;
1508
- const getter = magics.get(name);
1542
+ const getter = registry.get(name);
1509
1543
  const scope = this;
1510
1544
  const container = {};
1511
1545
  Object.defineProperty(container, name, {
@@ -1826,7 +1860,16 @@ function runDirective(el, attr, scope) {
1826
1860
  },
1827
1861
  effect(fn) {
1828
1862
  const owner = ownerScope();
1829
- owner.run(() => effect(fn, { scope: owner }));
1863
+ const hosted = () => {
1864
+ const previous = hookHost;
1865
+ hookHost = el;
1866
+ try {
1867
+ fn();
1868
+ } finally {
1869
+ hookHost = previous;
1870
+ }
1871
+ };
1872
+ owner.run(() => effect(hosted, { scope: owner }));
1830
1873
  },
1831
1874
  cleanup(fn) {
1832
1875
  addCleanup(el, fn);
@@ -1874,6 +1917,56 @@ function walk(node, scope) {
1874
1917
  return;
1875
1918
  }
1876
1919
  initialized.add(el);
1920
+ const previousHost = hookHost;
1921
+ hookHost = el;
1922
+ try {
1923
+ walkElementDirectives(el, attrs, tagComponent, current);
1924
+ } finally {
1925
+ hookHost = previousHost;
1926
+ }
1927
+ }
1928
+ var hookHost = null;
1929
+ function currentHookHost() {
1930
+ return hookHost;
1931
+ }
1932
+ function createDataScope(expression, parent, el) {
1933
+ let ast = null;
1934
+ try {
1935
+ ast = parse(expression);
1936
+ } catch {
1937
+ ast = null;
1938
+ }
1939
+ const plain = ast && ast.t === "obj" && ast.props.every(
1940
+ (p) => !p.spread && !p.keyExpr
1941
+ );
1942
+ if (!plain) {
1943
+ const raw = evaluateIn(expression, parent, "v-data");
1944
+ return parent.reactiveChild(raw && typeof raw === "object" ? raw : {}, el);
1945
+ }
1946
+ const scope = parent.reactiveChild({}, el);
1947
+ const props = ast.props;
1948
+ for (const prop of props) {
1949
+ if (prop.key === null) continue;
1950
+ try {
1951
+ if (prop.getter) {
1952
+ const compute = evaluate(prop.value, scope);
1953
+ Object.defineProperty(scope.data, prop.key, {
1954
+ enumerable: true,
1955
+ configurable: true,
1956
+ get: () => compute.call(scope.data)
1957
+ });
1958
+ } else {
1959
+ scope.data[prop.key] = evaluate(prop.value, scope);
1960
+ }
1961
+ } catch (err) {
1962
+ if (inDevelopment()) warnInvalidExpression(el, expression, expression, err);
1963
+ else handleError(err, "v-data");
1964
+ }
1965
+ }
1966
+ return scope;
1967
+ }
1968
+ function walkElementDirectives(el, attrs, tagComponent, scope) {
1969
+ let current = scope;
1877
1970
  for (const attr of attrs) {
1878
1971
  const def = directives.get(attr.name);
1879
1972
  if (def?.terminal) {
@@ -1893,11 +1986,10 @@ function walk(node, scope) {
1893
1986
  nodeScopes.set(el, current);
1894
1987
  }
1895
1988
  } else if (dataAttr || componentAttr) {
1896
- const raw = dataAttr ? evaluateIn(dataAttr.expression || "{}", current, "v-data") : {};
1897
- current = current.reactiveChild(raw && typeof raw === "object" ? raw : {}, el);
1989
+ current = createDataScope(dataAttr ? dataAttr.expression || "{}" : "{}", current, el);
1898
1990
  nodeScopes.set(el, current);
1899
1991
  }
1900
- const attributeScope = mountedComponent ? activeScope : current;
1992
+ const attributeScope = mountedComponent ? scope : current;
1901
1993
  for (const attr of attrs) {
1902
1994
  if (attr.name === "data" || attr.name === "component") continue;
1903
1995
  runDirective(el, attr, attributeScope);
@@ -2052,13 +2144,13 @@ var componentAliases = /* @__PURE__ */ new Map();
2052
2144
  var started = false;
2053
2145
  var observer = null;
2054
2146
  var startHooks = [];
2055
- function onStart(hook) {
2056
- startHooks.push(hook);
2147
+ function onStart(hook2) {
2148
+ startHooks.push(hook2);
2057
2149
  }
2058
2150
  function runPhase(target, after) {
2059
- for (const hook of startHooks) {
2151
+ for (const hook2 of startHooks) {
2060
2152
  try {
2061
- hook(target, after);
2153
+ hook2(target, after);
2062
2154
  } catch (error) {
2063
2155
  console.error("[Voodoo] a start hook failed", error);
2064
2156
  }
@@ -2109,6 +2201,6 @@ function refresh(root) {
2109
2201
  walk(root ?? document.body, root ? findScope(root.parentNode) : rootScope);
2110
2202
  }
2111
2203
 
2112
- export { Scope, VoodooRuntimeError, VoodooSyntaxError, addCleanup, allowedGlobals, clearParseCache, closestDirective, collectDirectives, componentAliases, destroy, evaluate, evaluateIn, findScope, getEffectScopes, getScope, hadDirectives, hasAttr, hasDirective, hasDirectives, isInitialized, magic, magics, markInitialized, markNodeScope, markSkipChildren, onStart, originalAttributes, parse, parseAttribute, queryDirective, readAttr, refresh, removeQuietly, restoreAttributes, rootScope, setComponentMounter, start, stopObserving, stringify, tokenize, unwrap, walk };
2113
- //# sourceMappingURL=chunk-H2ZUEQWV.js.map
2114
- //# sourceMappingURL=chunk-H2ZUEQWV.js.map
2204
+ export { Scope, VoodooRuntimeError, VoodooSyntaxError, addCleanup, allowedGlobals, clearParseCache, closestDirective, collectDirectives, componentAliases, currentHookHost, destroy, evaluate, evaluateIn, findScope, getEffectScopes, getScope, hadDirectives, hasAttr, hasDirective, hasDirectives, hook, hooks, isInitialized, magic, magics, markInitialized, markNodeScope, markSkipChildren, onStart, originalAttributes, parse, parseAttribute, queryDirective, readAttr, refresh, removeQuietly, restoreAttributes, rootScope, setComponentMounter, start, stopObserving, stringify, tokenize, unwrap, walk };
2205
+ //# sourceMappingURL=chunk-OWCQV42D.js.map
2206
+ //# sourceMappingURL=chunk-OWCQV42D.js.map
@@ -1,8 +1,8 @@
1
- import { handleError } from './chunk-WJP3YGUI.js';
2
- import { warn } from './chunk-UV5PMS7P.js';
1
+ import { handleError } from './chunk-S4BXAGAW.js';
2
+ import { warn } from './chunk-YV4I45SK.js';
3
3
 
4
4
  /**
5
- * Voodoo.js v0.11.2
5
+ * Voodoo.js v0.12.2
6
6
  * JavaScript feels like magic.
7
7
  * (c) 2026 Voodoo.js contributors. MIT License.
8
8
  */
@@ -1192,5 +1192,5 @@ var gpu = {
1192
1192
  };
1193
1193
 
1194
1194
  export { clock, compute, describeWgslType, destroy, effect, findEntry, flattenValue, frame, frameLoop, gpu, inferStruct, init, packStruct, reflectBindings, reflectEntries, reflectStructs, reflectWgsl, resetShared, shared, splitTopLevel, stripWgslComments, supported, surface, target, uniforms, writeField, writeStruct };
1195
- //# sourceMappingURL=chunk-KQYSJHZR.js.map
1196
- //# sourceMappingURL=chunk-KQYSJHZR.js.map
1195
+ //# sourceMappingURL=chunk-RTZEIVNA.js.map
1196
+ //# sourceMappingURL=chunk-RTZEIVNA.js.map
@@ -1,5 +1,5 @@
1
1
  /**
2
- * Voodoo.js v0.11.2
2
+ * Voodoo.js v0.12.2
3
3
  * JavaScript feels like magic.
4
4
  * (c) 2026 Voodoo.js contributors. MIT License.
5
5
  */
@@ -61,5 +61,5 @@ function usePlugin(V, plugin, options) {
61
61
  }
62
62
 
63
63
  export { PRIORITY, components, config, defineDirective, directives, normalizeComponentName, usePlugin };
64
- //# sourceMappingURL=chunk-NFDXVIII.js.map
65
- //# sourceMappingURL=chunk-NFDXVIII.js.map
64
+ //# sourceMappingURL=chunk-RXOLGHSU.js.map
65
+ //# sourceMappingURL=chunk-RXOLGHSU.js.map