voodoojs 0.11.2 → 0.12.1

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-H2ZUEQWV.js → chunk-4M4ZXHNY.js} +84 -19
  3. package/dist/{chunk-UV5PMS7P.js → chunk-72PMUUMT.js} +4 -4
  4. package/dist/{chunk-KQYSJHZR.js → chunk-AFMCDNYS.js} +5 -5
  5. package/dist/{chunk-DJJB35SR.js → chunk-D7675IJG.js} +6 -6
  6. package/dist/{chunk-IS3DR2KY.js → chunk-GXPNWCGE.js} +3 -3
  7. package/dist/{chunk-DCE5WIGA.js → chunk-HNM3CTBD.js} +5 -5
  8. package/dist/{chunk-IGZSDZKU.js → chunk-KN7NAKBL.js} +4 -4
  9. package/dist/{chunk-WJP3YGUI.js → chunk-LLNDLLKV.js} +4 -4
  10. package/dist/{chunk-V3O3WOZH.js → chunk-NP66JM2P.js} +4 -4
  11. package/dist/{chunk-AH2VXDZD.js → chunk-RDHYPGH6.js} +187 -18
  12. package/dist/{chunk-NFDXVIII.js → chunk-T5ION5NG.js} +3 -3
  13. package/dist/essential.cjs +263 -25
  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 +273 -27
  22. package/dist/index.d.cts +88 -4
  23. package/dist/index.d.ts +88 -4
  24. package/dist/index.js +20 -20
  25. package/dist/{query-Cf-7iibE.d.ts → query-DzHfm8Kg.d.ts} +40 -29
  26. package/dist/{query-DiQAS73Q.d.cts → query-XooOh4vB.d.cts} +40 -29
  27. package/dist/reactivity.cjs +1 -1
  28. package/dist/reactivity.js +2 -2
  29. package/dist/socket.cjs +1 -1
  30. package/dist/socket.js +9 -9
  31. package/dist/style-GR4X6O7I.js +5 -0
  32. package/dist/utils.cjs +1 -1
  33. package/dist/utils.js +2 -2
  34. package/dist/voodoo.core.js +242 -24
  35. package/dist/voodoo.core.min.js +17 -17
  36. package/dist/voodoo.full.js +266 -27
  37. package/dist/voodoo.full.min.js +57 -53
  38. package/dist/voodoo.js +264 -25
  39. package/dist/voodoo.min.js +29 -25
  40. package/package.json +1 -1
  41. package/dist/style-4X62SABN.js +0 -5
package/dist/index.cjs CHANGED
@@ -3,7 +3,7 @@
3
3
  Object.defineProperty(exports, '__esModule', { value: true });
4
4
 
5
5
  /**
6
- * Voodoo.js v0.11.2
6
+ * Voodoo.js v0.12.1
7
7
  * JavaScript feels like magic.
8
8
  * (c) 2026 Voodoo.js contributors. MIT License.
9
9
  */
@@ -2237,6 +2237,10 @@ var magics = /* @__PURE__ */ new Map();
2237
2237
  function magic(name, getter) {
2238
2238
  magics.set(name.startsWith("$") ? name : `$${name}`, getter);
2239
2239
  }
2240
+ var hooks = /* @__PURE__ */ new Map();
2241
+ function hook(name, getter) {
2242
+ hooks.set(name, getter);
2243
+ }
2240
2244
  var Scope = class _Scope {
2241
2245
  // Assignment order matches the order the fields were declared in before, so
2242
2246
  // the properties are created in the same sequence they always were.
@@ -2292,7 +2296,10 @@ var Scope = class _Scope {
2292
2296
  s = s.parent;
2293
2297
  }
2294
2298
  if (name.charCodeAt(0) === 36 && magics.has(name)) {
2295
- return this.magicContainer(name);
2299
+ return this.magicContainer(name, magics);
2300
+ }
2301
+ if (hooks.has(name)) {
2302
+ return this.magicContainer(name, hooks);
2296
2303
  }
2297
2304
  return void 0;
2298
2305
  }
@@ -2321,11 +2328,11 @@ var Scope = class _Scope {
2321
2328
  reactiveChild(vars, el = null) {
2322
2329
  return new _Scope(reactive(vars), this, el ?? this.el);
2323
2330
  }
2324
- magicContainer(name) {
2331
+ magicContainer(name, registry) {
2325
2332
  if (!this.magicCache) this.magicCache = /* @__PURE__ */ new Map();
2326
2333
  const cached = this.magicCache.get(name);
2327
2334
  if (cached) return cached;
2328
- const getter = magics.get(name);
2335
+ const getter = registry.get(name);
2329
2336
  const scope = this;
2330
2337
  const container2 = {};
2331
2338
  Object.defineProperty(container2, name, {
@@ -2722,7 +2729,16 @@ function runDirective(el, attr2, scope) {
2722
2729
  },
2723
2730
  effect(fn) {
2724
2731
  const owner = ownerScope();
2725
- owner.run(() => effect(fn, { scope: owner }));
2732
+ const hosted = () => {
2733
+ const previous = hookHost;
2734
+ hookHost = el;
2735
+ try {
2736
+ fn();
2737
+ } finally {
2738
+ hookHost = previous;
2739
+ }
2740
+ };
2741
+ owner.run(() => effect(hosted, { scope: owner }));
2726
2742
  },
2727
2743
  cleanup(fn) {
2728
2744
  addCleanup(el, fn);
@@ -2770,6 +2786,56 @@ function walk(node, scope) {
2770
2786
  return;
2771
2787
  }
2772
2788
  initialized.add(el);
2789
+ const previousHost = hookHost;
2790
+ hookHost = el;
2791
+ try {
2792
+ walkElementDirectives(el, attrs, tagComponent, current2);
2793
+ } finally {
2794
+ hookHost = previousHost;
2795
+ }
2796
+ }
2797
+ var hookHost = null;
2798
+ function currentHookHost() {
2799
+ return hookHost;
2800
+ }
2801
+ function createDataScope(expression, parent, el) {
2802
+ let ast = null;
2803
+ try {
2804
+ ast = parse(expression);
2805
+ } catch {
2806
+ ast = null;
2807
+ }
2808
+ const plain = ast && ast.t === "obj" && ast.props.every(
2809
+ (p2) => !p2.spread && !p2.keyExpr
2810
+ );
2811
+ if (!plain) {
2812
+ const raw = evaluateIn(expression, parent, "v-data");
2813
+ return parent.reactiveChild(raw && typeof raw === "object" ? raw : {}, el);
2814
+ }
2815
+ const scope = parent.reactiveChild({}, el);
2816
+ const props = ast.props;
2817
+ for (const prop of props) {
2818
+ if (prop.key === null) continue;
2819
+ try {
2820
+ if (prop.getter) {
2821
+ const compute2 = evaluate(prop.value, scope);
2822
+ Object.defineProperty(scope.data, prop.key, {
2823
+ enumerable: true,
2824
+ configurable: true,
2825
+ get: () => compute2.call(scope.data)
2826
+ });
2827
+ } else {
2828
+ scope.data[prop.key] = evaluate(prop.value, scope);
2829
+ }
2830
+ } catch (err) {
2831
+ if (inDevelopment()) warnInvalidExpression(el, expression, expression, err);
2832
+ else handleError(err, "v-data");
2833
+ }
2834
+ }
2835
+ return scope;
2836
+ }
2837
+ function walkElementDirectives(el, attrs, tagComponent, scope) {
2838
+ let current2 = scope;
2773
2839
  for (const attr2 of attrs) {
2774
2840
  const def = directives.get(attr2.name);
2775
2841
  if (def?.terminal) {
@@ -2789,11 +2855,10 @@ function walk(node, scope) {
2789
2855
  nodeScopes.set(el, current2);
2790
2856
  }
2791
2857
  } else if (dataAttr || componentAttr) {
2792
- const raw = dataAttr ? evaluateIn(dataAttr.expression || "{}", current2, "v-data") : {};
2793
- current2 = current2.reactiveChild(raw && typeof raw === "object" ? raw : {}, el);
2858
+ current2 = createDataScope(dataAttr ? dataAttr.expression || "{}" : "{}", current2, el);
2794
2859
  nodeScopes.set(el, current2);
2795
2860
  }
2796
- const attributeScope = mountedComponent ? activeScope2 : current2;
2861
+ const attributeScope = mountedComponent ? scope : current2;
2797
2862
  for (const attr2 of attrs) {
2798
2863
  if (attr2.name === "data" || attr2.name === "component") continue;
2799
2864
  runDirective(el, attr2, attributeScope);
@@ -2948,13 +3013,13 @@ var componentAliases = /* @__PURE__ */ new Map();
2948
3013
  var started = false;
2949
3014
  var observer = null;
2950
3015
  var startHooks = [];
2951
- function onStart(hook) {
2952
- startHooks.push(hook);
3016
+ function onStart(hook2) {
3017
+ startHooks.push(hook2);
2953
3018
  }
2954
3019
  function runPhase(target2, after) {
2955
- for (const hook of startHooks) {
3020
+ for (const hook2 of startHooks) {
2956
3021
  try {
2957
- hook(target2, after);
3022
+ hook2(target2, after);
2958
3023
  } catch (error) {
2959
3024
  console.error("[Voodoo] a start hook failed", error);
2960
3025
  }
@@ -3332,10 +3397,10 @@ var LIFECYCLE = /* @__PURE__ */ new Set([
3332
3397
  "destroyed"
3333
3398
  ]);
3334
3399
  function callHook(def, instance, name) {
3335
- const hook = def[name];
3336
- if (typeof hook !== "function") return;
3400
+ const hook2 = def[name];
3401
+ if (typeof hook2 !== "function") return;
3337
3402
  try {
3338
- hook.call(instance);
3403
+ hook2.call(instance);
3339
3404
  } catch (err) {
3340
3405
  handleError(err, `hook ${name}`);
3341
3406
  }
@@ -4775,6 +4840,7 @@ var toast = Object.assign(
4775
4840
  );
4776
4841
 
4777
4842
  // src/storage/index.ts
4843
+ init_reactivity();
4778
4844
  function createStorage(getStore, prefix = "") {
4779
4845
  const full = (key) => prefix + key;
4780
4846
  return {
@@ -4944,21 +5010,28 @@ var cache2 = {
4944
5010
  };
4945
5011
  var THEME_KEY = "voodoo:theme";
4946
5012
  var picked = null;
5013
+ var revision = ref(0);
4947
5014
  var theme = {
4948
5015
  /** Theme chosen by the user, or `system` when never set. */
4949
5016
  get current() {
5017
+ void revision.value;
4950
5018
  return storage.get(THEME_KEY) ?? picked ?? "system";
4951
5019
  },
4952
5020
  /** Theme effectively applied, resolving `system`. */
4953
5021
  get resolved() {
4954
5022
  const value = this.current;
4955
5023
  if (value !== "system") return value;
5024
+ if (typeof document !== "undefined") {
5025
+ const authored = document.documentElement.getAttribute("data-theme");
5026
+ if (authored === "light" || authored === "dark") return authored;
5027
+ }
4956
5028
  if (typeof matchMedia === "undefined") return "light";
4957
5029
  return matchMedia("(prefers-color-scheme: dark)").matches ? "dark" : "light";
4958
5030
  },
4959
5031
  set(value) {
4960
5032
  picked = value;
4961
5033
  storage.set(THEME_KEY, value);
5034
+ revision.value++;
4962
5035
  this.apply();
4963
5036
  },
4964
5037
  toggle() {
@@ -4992,8 +5065,17 @@ var theme = {
4992
5065
  init() {
4993
5066
  if (typeof document === "undefined") return;
4994
5067
  this.apply();
5068
+ if (typeof MutationObserver !== "undefined") {
5069
+ new MutationObserver(() => {
5070
+ revision.value++;
5071
+ }).observe(document.documentElement, {
5072
+ attributes: true,
5073
+ attributeFilter: ["data-theme"]
5074
+ });
5075
+ }
4995
5076
  if (typeof matchMedia === "undefined") return;
4996
5077
  matchMedia("(prefers-color-scheme: dark)").addEventListener("change", () => {
5078
+ revision.value++;
4997
5079
  if (this.current === "system") this.apply();
4998
5080
  });
4999
5081
  }
@@ -5126,6 +5208,140 @@ function installMagics() {
5126
5208
  );
5127
5209
  }
5128
5210
 
5211
+ // src/hooks/index.ts
5212
+ init_reactivity();
5213
+ var tables = /* @__PURE__ */ new WeakMap();
5214
+ function tableFor(scope) {
5215
+ const host = currentHookHost() ?? scope.el ?? scope;
5216
+ let table = tables.get(host);
5217
+ if (!table) {
5218
+ table = { slots: [], index: 0, scheduled: false, bound: false };
5219
+ tables.set(host, table);
5220
+ }
5221
+ const el = currentHookHost() ?? scope.el;
5222
+ if (!table.bound && el) {
5223
+ table.bound = true;
5224
+ const owned = table;
5225
+ addCleanup(el, () => {
5226
+ for (const slot of owned.slots) {
5227
+ if (slot.dispose) slot.dispose();
5228
+ if (slot.runner) stop(slot.runner);
5229
+ }
5230
+ owned.slots.length = 0;
5231
+ });
5232
+ }
5233
+ if (!table.scheduled) {
5234
+ table.scheduled = true;
5235
+ const pending2 = table;
5236
+ queueMicrotask(() => {
5237
+ pending2.index = 0;
5238
+ pending2.scheduled = false;
5239
+ });
5240
+ }
5241
+ return table;
5242
+ }
5243
+ function nextSlot(scope, kind) {
5244
+ const table = tableFor(scope);
5245
+ const at = table.index++;
5246
+ let slot = table.slots[at];
5247
+ if (!slot || slot.kind !== kind) {
5248
+ if (slot) {
5249
+ if (slot.dispose) slot.dispose();
5250
+ if (slot.runner) stop(slot.runner);
5251
+ }
5252
+ slot = { kind, deps: null, value: void 0 };
5253
+ table.slots[at] = slot;
5254
+ }
5255
+ return slot;
5256
+ }
5257
+ function depsChanged(previous, next) {
5258
+ if (!previous || !next) return true;
5259
+ if (previous.length !== next.length) return true;
5260
+ for (let i = 0; i < next.length; i++) {
5261
+ if (!Object.is(previous[i], next[i])) return true;
5262
+ }
5263
+ return false;
5264
+ }
5265
+ function normalizeDeps(deps) {
5266
+ return Array.isArray(deps) ? deps.slice() : null;
5267
+ }
5268
+ function useState(scope, initial) {
5269
+ const slot = nextSlot(scope, "state");
5270
+ if (slot.value === void 0) slot.value = ref(initial);
5271
+ return slot.value;
5272
+ }
5273
+ function useEffect(scope, fn, deps) {
5274
+ const slot = nextSlot(scope, "effect");
5275
+ const next = normalizeDeps(deps);
5276
+ const runCleanup = () => {
5277
+ if (slot.dispose) {
5278
+ const dispose = slot.dispose;
5279
+ slot.dispose = void 0;
5280
+ dispose();
5281
+ }
5282
+ };
5283
+ if (next) {
5284
+ const first = slot.deps === null && !slot.runner;
5285
+ if (first || depsChanged(slot.deps, next)) {
5286
+ slot.deps = next;
5287
+ runCleanup();
5288
+ const result = fn();
5289
+ if (typeof result === "function") slot.dispose = result;
5290
+ }
5291
+ return;
5292
+ }
5293
+ if (slot.runner) return;
5294
+ slot.deps = null;
5295
+ slot.runner = effect(() => {
5296
+ runCleanup();
5297
+ const result = fn();
5298
+ if (typeof result === "function") slot.dispose = result;
5299
+ });
5300
+ }
5301
+ function useMemo(scope, fn, deps) {
5302
+ const slot = nextSlot(scope, "memo");
5303
+ const next = normalizeDeps(deps);
5304
+ if (!next) {
5305
+ if (!slot.value) slot.value = computed(fn);
5306
+ return slot.value;
5307
+ }
5308
+ if (!slot.value) {
5309
+ slot.value = ref(fn());
5310
+ slot.deps = next;
5311
+ } else if (depsChanged(slot.deps, next)) {
5312
+ slot.deps = next;
5313
+ slot.value.value = fn();
5314
+ }
5315
+ return slot.value;
5316
+ }
5317
+ function useRef(scope, initial) {
5318
+ const slot = nextSlot(scope, "ref");
5319
+ if (!slot.value) slot.value = markRaw({ current: initial });
5320
+ return slot.value;
5321
+ }
5322
+ function useContext(name, initial) {
5323
+ if (initial !== void 0 && !(name in allStores)) {
5324
+ store(name, initial);
5325
+ }
5326
+ return allStores[name];
5327
+ }
5328
+ function installHooks() {
5329
+ hook("useState", (scope) => (initial) => useState(scope, initial));
5330
+ hook(
5331
+ "useEffect",
5332
+ (scope) => (fn, deps) => useEffect(scope, fn, deps)
5333
+ );
5334
+ hook(
5335
+ "useMemo",
5336
+ (scope) => (fn, deps) => useMemo(scope, fn, deps)
5337
+ );
5338
+ hook("useRef", (scope) => (initial) => useRef(scope, initial));
5339
+ hook(
5340
+ "useContext",
5341
+ () => (name, initial) => useContext(name, initial)
5342
+ );
5343
+ }
5344
+
5129
5345
  // src/http/resource.ts
5130
5346
  init_reactivity();
5131
5347
  function pick(value, path) {
@@ -6708,6 +6924,7 @@ setComponentMounter(mountComponent);
6708
6924
  setScopeMarker(markNodeScope);
6709
6925
  setDirectiveRegistrar(directive);
6710
6926
  installMagics();
6927
+ installHooks();
6711
6928
  var eventBus = /* @__PURE__ */ new Map();
6712
6929
  function on(name, handler) {
6713
6930
  let set2 = eventBus.get(name);
@@ -6741,7 +6958,7 @@ function off(name, handler) {
6741
6958
  eventBus.get(name)?.delete(handler);
6742
6959
  }
6743
6960
  function directive(name, definition) {
6744
- const hooks = typeof definition === "function" ? { mounted: definition, updated: definition } : definition;
6961
+ const hooks2 = typeof definition === "function" ? { mounted: definition, updated: definition } : definition;
6745
6962
  defineDirective(
6746
6963
  name,
6747
6964
  (ctx) => {
@@ -6757,36 +6974,36 @@ function directive(name, definition) {
6757
6974
  scope: ctx.scope,
6758
6975
  instance: ctx.scope.owner?.component ?? null
6759
6976
  });
6760
- const initial = hooks.raw ? ctx.expression : ctx.evaluate();
6761
- hooks.created?.(ctx.el, makeBinding(initial));
6762
- hooks.beforeMount?.(ctx.el, makeBinding(initial));
6977
+ const initial = hooks2.raw ? ctx.expression : ctx.evaluate();
6978
+ hooks2.created?.(ctx.el, makeBinding(initial));
6979
+ hooks2.beforeMount?.(ctx.el, makeBinding(initial));
6763
6980
  ctx.effect(() => {
6764
- const value = hooks.raw ? ctx.expression : ctx.evaluate();
6981
+ const value = hooks2.raw ? ctx.expression : ctx.evaluate();
6765
6982
  if (!mounted2) {
6766
6983
  mounted2 = true;
6767
6984
  oldValue = value;
6768
- hooks.mounted?.(ctx.el, makeBinding(value));
6985
+ hooks2.mounted?.(ctx.el, makeBinding(value));
6769
6986
  return;
6770
6987
  }
6771
6988
  if (value === oldValue) return;
6772
6989
  const binding = makeBinding(value);
6773
- hooks.updated?.(ctx.el, binding);
6990
+ hooks2.updated?.(ctx.el, binding);
6774
6991
  oldValue = value;
6775
6992
  });
6776
6993
  ctx.cleanup(() => {
6777
6994
  const binding = makeBinding(oldValue);
6778
- hooks.beforeUnmount?.(ctx.el, binding);
6779
- hooks.unmounted?.(ctx.el, binding);
6995
+ hooks2.beforeUnmount?.(ctx.el, binding);
6996
+ hooks2.unmounted?.(ctx.el, binding);
6780
6997
  });
6781
6998
  },
6782
- { priority: hooks.priority ?? exports.PRIORITY.DEFAULT, terminal: hooks.terminal ?? false }
6999
+ { priority: hooks2.priority ?? exports.PRIORITY.DEFAULT, terminal: hooks2.terminal ?? false }
6783
7000
  );
6784
7001
  }
6785
7002
  function data(values) {
6786
7003
  Object.defineProperties(rootScope.data, Object.getOwnPropertyDescriptors(values));
6787
7004
  return rootScope.data;
6788
7005
  }
6789
- var version2 = "0.11.2";
7006
+ var version2 = "0.12.1";
6790
7007
  var core = {
6791
7008
  // Utilities first: Voodoo's own names can override.
6792
7009
  ...utils_exports,
@@ -13148,12 +13365,15 @@ magic("$history", (scope) => scope.el ? findController(scope.el) : null);
13148
13365
 
13149
13366
  // src/sound/index.ts
13150
13367
  init_registry();
13368
+ init_reactivity();
13369
+ init_style();
13151
13370
  var audioContext = null;
13152
13371
  var masterVolume = 0.35;
13153
13372
  var isMuted = false;
13154
13373
  var hasLoadedPreference = false;
13155
13374
  var VOLUME_KEY = "voodoo:sound:volume";
13156
13375
  var MUTE_KEY = "voodoo:sound:muted";
13376
+ var muteRevision = ref(0);
13157
13377
  function loadPreference() {
13158
13378
  if (hasLoadedPreference) return;
13159
13379
  hasLoadedPreference = true;
@@ -13465,6 +13685,7 @@ var sound = {
13465
13685
  loadPreference();
13466
13686
  isMuted = value;
13467
13687
  storage.set(MUTE_KEY, isMuted);
13688
+ muteRevision.value++;
13468
13689
  },
13469
13690
  /** Unmutes sound. */
13470
13691
  unmute() {
@@ -13476,8 +13697,18 @@ var sound = {
13476
13697
  this.mute(!isMuted);
13477
13698
  return isMuted;
13478
13699
  },
13479
- /** `true` when muted. */
13700
+ /**
13701
+ * `true` when muted.
13702
+ *
13703
+ * Reads a revision ref first, so that an expression asking whether sound is
13704
+ * muted actually re-runs when it changes. The state lives in a module
13705
+ * variable and in localStorage, both invisible to the Proxy, so
13706
+ * `v-show="$sound.muted"` used to render once and then never move: a page had
13707
+ * no way to show whether it was muted, which made the mute button look like
13708
+ * it did nothing at all.
13709
+ */
13480
13710
  get muted() {
13711
+ void muteRevision.value;
13481
13712
  loadPreference();
13482
13713
  return isMuted;
13483
13714
  },
@@ -13527,11 +13758,18 @@ defineDirective("sound", ({ el, arg, expression, modifiers, scope, cleanup, eval
13527
13758
  el.addEventListener(event, play);
13528
13759
  cleanup(() => el.removeEventListener(event, play));
13529
13760
  });
13761
+ var MUTE_CSS = `
13762
+ .v-muted{opacity:.55}
13763
+ .v-muted::after{content:" \\1F507";font-size:.9em}
13764
+ .v-mute-on::after{content:" \\1F50A";font-size:.9em}
13765
+ `;
13530
13766
  defineDirective("mute", ({ el, cleanup }) => {
13767
+ injectStyle("mute", MUTE_CSS);
13531
13768
  const sync = () => {
13532
13769
  const isMuted2 = sound.muted;
13533
13770
  el.setAttribute("aria-pressed", String(isMuted2));
13534
13771
  el.classList.toggle("v-muted", isMuted2);
13772
+ el.classList.toggle("v-mute-on", !isMuted2);
13535
13773
  };
13536
13774
  const toggle = () => {
13537
13775
  sound.toggle();
@@ -23569,11 +23807,14 @@ exports.getLocale = getLocale;
23569
23807
  exports.getScope = getScope;
23570
23808
  exports.gpu = gpu;
23571
23809
  exports.groupBy = groupBy;
23810
+ exports.hook = hook;
23811
+ exports.hooks = hooks;
23572
23812
  exports.hotkey = hotkey;
23573
23813
  exports.http = http;
23574
23814
  exports.i18n = i18n;
23575
23815
  exports.inView = inView;
23576
23816
  exports.injectStyle = injectStyle;
23817
+ exports.installHooks = installHooks;
23577
23818
  exports.instances = instances;
23578
23819
  exports.isBrowser = isBrowser;
23579
23820
  exports.isDevtoolsWidgetMounted = isDevtoolsWidgetMounted;
@@ -23660,6 +23901,11 @@ exports.unmask = unmask;
23660
23901
  exports.unmountDevtoolsWidget = unmountDevtoolsWidget;
23661
23902
  exports.unref = unref;
23662
23903
  exports.url = url;
23904
+ exports.useContext = useContext;
23905
+ exports.useEffect = useEffect;
23906
+ exports.useMemo = useMemo;
23907
+ exports.useRef = useRef;
23908
+ exports.useState = useState;
23663
23909
  exports.uuid = uuid;
23664
23910
  exports.validate = validate;
23665
23911
  exports.validator = validator;
package/dist/index.d.cts CHANGED
@@ -1,5 +1,6 @@
1
- import { S as Scope, c as core, V as VoodooCollection } from './query-DiQAS73Q.cjs';
2
- export { A as App, a as AppOptions, C as ComponentDefinition, D as DirectiveBinding, b as DirectiveHooks, P as PRIORITY, R as Resource, d as ResourceOptions, e as VoodooConfig, f as VoodooPlugin, g as VoodooRuntimeError, h as VoodooSyntaxError, i as addCleanup, j as allStores, k as allowedGlobals, l as cache, m as clearParseCache, n as config, o as cookie, p as createApp, q as createResource, r as defineComponent, s as defineDirective, t as destroy, u as documentReady, v as ensureTokens, w as enter, x as evaluate, y as fadeIn, z as fadeOut, B as findScope, E as fromHtml, F as getScope, G as injectStyle, H as instances, I as leave, J as magic, K as magics, L as mountComponent, M as parse, N as query, O as ready, Q as refresh, T as removeStore, q as resource, U as rootScope, W as session, X as slideDown, Y as slideUp, Z as start, _ as storage, $ as store, a0 as storeNames, a1 as stringify, a2 as theme, a3 as toast, a4 as tokenize, a5 as url, a6 as viewTransition, a7 as walk, a8 as whenElement, a9 as whenReady } from './query-DiQAS73Q.cjs';
1
+ import { S as Scope, c as core, V as VoodooCollection } from './query-XooOh4vB.cjs';
2
+ export { A as App, a as AppOptions, C as ComponentDefinition, D as DirectiveBinding, b as DirectiveHooks, P as PRIORITY, R as Resource, d as ResourceOptions, e as VoodooConfig, f as VoodooPlugin, g as VoodooRuntimeError, h as VoodooSyntaxError, i as addCleanup, j as allStores, k as allowedGlobals, l as cache, m as clearParseCache, n as config, o as cookie, p as createApp, q as createResource, r as defineComponent, s as defineDirective, t as destroy, u as documentReady, v as ensureTokens, w as enter, x as evaluate, y as fadeIn, z as fadeOut, B as findScope, E as fromHtml, F as getScope, G as hook, H as hooks, I as injectStyle, J as instances, K as leave, L as magic, M as magics, N as mountComponent, O as parse, Q as query, T as ready, U as refresh, W as removeStore, q as resource, X as rootScope, Y as session, Z as slideDown, _ as slideUp, $ as start, a0 as storage, a1 as store, a2 as storeNames, a3 as stringify, a4 as theme, a5 as toast, a6 as tokenize, a7 as url, a8 as viewTransition, a9 as walk, aa as whenElement, ab as whenReady } from './query-XooOh4vB.cjs';
3
+ import { Ref } from './reactivity.cjs';
3
4
  export { EffectScope, computed, effect, effectScope, flushSync, isReactive, markRaw, nextTick, reactive, ref, shallowRef, stop, toRaw, unref, watch, watchEffect } from './reactivity.cjs';
4
5
  export { HttpError, HttpMethod, HttpResponse, RequestConfig, http, request } from './http.cjs';
5
6
  export { R as RoomOptions, a as RoomState, S as SocketMessage, b as SocketOptions, c as SocketRoom, d as SocketState, e as SocketTransport, V as VoodooSocket, f as createSocket, s as socket, g as socketSupported } from './index-DTllqUtj.cjs';
@@ -171,7 +172,16 @@ declare const sound: {
171
172
  unmute(): void;
172
173
  /** Toggles between muted and unmuted, and returns the new state. */
173
174
  toggle(): boolean;
174
- /** `true` when muted. */
175
+ /**
176
+ * `true` when muted.
177
+ *
178
+ * Reads a revision ref first, so that an expression asking whether sound is
179
+ * muted actually re-runs when it changes. The state lives in a module
180
+ * variable and in localStorage, both invisible to the Proxy, so
181
+ * `v-show="$sound.muted"` used to render once and then never move: a page had
182
+ * no way to show whether it was muted, which made the mute button look like
183
+ * it did nothing at all.
184
+ */
175
185
  readonly muted: boolean;
176
186
  /** Names of all available effects. */
177
187
  readonly names: string[];
@@ -481,6 +491,80 @@ declare const charts: {
481
491
  colors: string[];
482
492
  };
483
493
 
494
+ /**
495
+ * @module hooks
496
+ *
497
+ * React-style hooks, reachable by bare name inside any expression.
498
+ *
499
+ * These are a thin surface over primitives the library already had — `effect`,
500
+ * `computed`, `ref` and `store`. The value is not new machinery, it is that
501
+ * someone arriving from React can write what they already know and have it mean
502
+ * the right thing here.
503
+ *
504
+ * Two differences from React are deliberate, and both are improvements rather
505
+ * than gaps:
506
+ *
507
+ * 1. `deps` is optional everywhere. Voodoo tracks reads through a Proxy, so a
508
+ * hook with no dependency array re-runs exactly when something it actually
509
+ * read changes. The array is there for when you want to narrow that, not
510
+ * because the library cannot work it out.
511
+ *
512
+ * 2. There is no rule against calling a hook in a branch. Slots are keyed per
513
+ * scope in call order within one evaluation, and `v-data` and `v-init` each
514
+ * evaluate once per scope, so the order is stable without a rule asking you
515
+ * to keep it stable.
516
+ *
517
+ * `useState` and `useMemo` return refs, and `reactive()` unwraps refs on read,
518
+ * so inside `v-data` they read as plain values with no `.value` anywhere.
519
+ * `useRef` deliberately does not: it returns a raw `{ current }` box that no
520
+ * effect subscribes to, which is the whole point of it.
521
+ */
522
+
523
+ /**
524
+ * A value that survives re-evaluation and re-renders whatever reads it.
525
+ *
526
+ * Returns a ref. Written into `v-data` it reads and assigns as a plain value,
527
+ * because reactive objects unwrap refs, so `count++` works with no `.value`.
528
+ */
529
+ declare function useState<T>(scope: Scope, initial: T): Ref<T>;
530
+ /**
531
+ * Runs a side effect, and re-runs it when what it depends on changes.
532
+ *
533
+ * With no dependency array it tracks its own reads and re-runs when any of them
534
+ * change. With `[]` it runs once. With `[a, b]` it re-runs only when one of
535
+ * those differs from last time. Returning a function from `fn` registers
536
+ * cleanup, called before the next run and again when the element is removed.
537
+ */
538
+ declare function useEffect(scope: Scope, fn: () => void | (() => void), deps?: unknown): void;
539
+ /**
540
+ * Caches a computation.
541
+ *
542
+ * With no dependency array it becomes a `computed`: lazy, cached, and
543
+ * recomputed only when something it read actually changed. With an array it
544
+ * recomputes when that array changes. Returns a ref, so inside `v-data` it
545
+ * reads as the value itself.
546
+ */
547
+ declare function useMemo<T>(scope: Scope, fn: () => T, deps?: unknown): Ref<T>;
548
+ /**
549
+ * A box that survives re-evaluation and that nothing subscribes to.
550
+ *
551
+ * Use it for a DOM element, a timer id, or a previous value — anything you want
552
+ * to keep without the page reacting when it changes. Deliberately not a ref, so
553
+ * reading `.current` inside an effect does not make that effect depend on it.
554
+ */
555
+ declare function useRef<T>(scope: Scope, initial: T): {
556
+ current: T;
557
+ };
558
+ /**
559
+ * Shared state, reachable from any component without threading it through the
560
+ * markup by hand.
561
+ *
562
+ * Backed by the store registry, so `useContext('user')` and `$store.user` are
563
+ * the same object. Passing a second argument creates the store on first use.
564
+ */
565
+ declare function useContext<T extends Record<string, any>>(name: string, initial?: T): T;
566
+ declare function installHooks(): void;
567
+
484
568
  /**
485
569
  * @module runtime/magics
486
570
  *
@@ -1714,4 +1798,4 @@ interface Voodoo extends Omit<typeof core, never> {
1714
1798
  }
1715
1799
  declare const V: Voodoo;
1716
1800
 
1717
- export { Scope, V, type Voodoo, VoodooCollection, activateJsx, alert, animate, applyMask, applyRegions, charts, clearErrors, clipboard, confirm, V as default, devtoolsBus, devtoolsWidget, dialog, disableXray, easings, enableXray, extractJsx, getLocale, hotkey, i18n, inView, isDevtoolsWidgetMounted, isXrayEnabled, jsx, mask, masks, modal, motionPresets, mountDevtoolsWidget, navigate, network, palette, prompt, readDeclarationBlock, registerMask, renderChart, route, router, screen, scrollProgress, serializeForm, setLocale, showFormErrors, sound, efeitos as soundEffects, spring, stagger, t, unmask, unmountDevtoolsWidget, validate, validator, xray };
1801
+ export { Scope, V, type Voodoo, VoodooCollection, activateJsx, alert, animate, applyMask, applyRegions, charts, clearErrors, clipboard, confirm, V as default, devtoolsBus, devtoolsWidget, dialog, disableXray, easings, enableXray, extractJsx, getLocale, hotkey, i18n, inView, installHooks, isDevtoolsWidgetMounted, isXrayEnabled, jsx, mask, masks, modal, motionPresets, mountDevtoolsWidget, navigate, network, palette, prompt, readDeclarationBlock, registerMask, renderChart, route, router, screen, scrollProgress, serializeForm, setLocale, showFormErrors, sound, efeitos as soundEffects, spring, stagger, t, unmask, unmountDevtoolsWidget, useContext, useEffect, useMemo, useRef, useState, validate, validator, xray };