voodoojs 0.11.1 → 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 +4 -3
  2. package/dist/{chunk-32J7GDLD.js → chunk-4M4ZXHNY.js} +94 -21
  3. package/dist/{chunk-TXWSOPF2.js → chunk-72PMUUMT.js} +4 -4
  4. package/dist/{chunk-OHSGDVPA.js → chunk-AFMCDNYS.js} +5 -5
  5. package/dist/{chunk-KE6WWJOB.js → chunk-D7675IJG.js} +6 -6
  6. package/dist/{chunk-BEQEBFQ2.js → chunk-GXPNWCGE.js} +3 -3
  7. package/dist/{chunk-FCJ2APGN.js → chunk-HNM3CTBD.js} +5 -5
  8. package/dist/{chunk-OJDW7KXT.js → chunk-KN7NAKBL.js} +4 -4
  9. package/dist/{chunk-FITEA237.js → chunk-LLNDLLKV.js} +4 -4
  10. package/dist/{chunk-J6RTM5P4.js → chunk-NP66JM2P.js} +4 -4
  11. package/dist/{chunk-XG2UDP4O.js → chunk-RDHYPGH6.js} +187 -18
  12. package/dist/{chunk-GC3BKNPT.js → chunk-T5ION5NG.js} +3 -3
  13. package/dist/essential.cjs +273 -27
  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 +283 -29
  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-p04Fl8VW.d.ts → query-DzHfm8Kg.d.ts} +12 -1
  26. package/dist/{query-CbHihkvO.d.cts → query-XooOh4vB.d.cts} +12 -1
  27. package/dist/reactivity.cjs +1 -1
  28. package/dist/reactivity.js +2 -2
  29. package/dist/socket.cjs +11 -3
  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 +252 -26
  35. package/dist/voodoo.core.min.js +17 -17
  36. package/dist/voodoo.full.js +276 -29
  37. package/dist/voodoo.full.min.js +57 -53
  38. package/dist/voodoo.js +274 -27
  39. package/dist/voodoo.min.js +29 -25
  40. package/package.json +1 -1
  41. package/dist/style-MX6ZATL4.js +0 -5
@@ -1,5 +1,5 @@
1
1
  /**
2
- * Voodoo.js v0.11.1
2
+ * Voodoo.js v0.12.1
3
3
  * JavaScript feels like magic.
4
4
  * (c) 2026 Voodoo.js contributors. MIT License.
5
5
  */
@@ -1649,9 +1649,17 @@ ${pointer}`);
1649
1649
  if (t.type === "punct") {
1650
1650
  if (t.value === "(") {
1651
1651
  this.next();
1652
- const expr = this.parseExpression();
1652
+ const body = [this.parseExpression()];
1653
+ while (this.isPunct(",")) {
1654
+ this.next();
1655
+ if (this.isPunct(")")) {
1656
+ const stray = this.peek();
1657
+ throw new VoodooSyntaxError("Trailing comma in a group", this.source, stray.start);
1658
+ }
1659
+ body.push(this.parseExpression());
1660
+ }
1653
1661
  this.expect(")");
1654
- return expr;
1662
+ return body.length === 1 ? body[0] : { t: "seq", body };
1655
1663
  }
1656
1664
  if (t.value === "[") return this.parseArrayLiteral();
1657
1665
  if (t.value === "{") return this.parseObjectLiteral();
@@ -2255,6 +2263,10 @@ Expression: ${expression}` : message);
2255
2263
  function magic(name, getter) {
2256
2264
  magics.set(name.startsWith("$") ? name : `$${name}`, getter);
2257
2265
  }
2266
+ var hooks = /* @__PURE__ */ new Map();
2267
+ function hook(name, getter) {
2268
+ hooks.set(name, getter);
2269
+ }
2258
2270
  var Scope = class _Scope {
2259
2271
  // Assignment order matches the order the fields were declared in before, so
2260
2272
  // the properties are created in the same sequence they always were.
@@ -2310,7 +2322,10 @@ Expression: ${expression}` : message);
2310
2322
  s = s.parent;
2311
2323
  }
2312
2324
  if (name.charCodeAt(0) === 36 && magics.has(name)) {
2313
- return this.magicContainer(name);
2325
+ return this.magicContainer(name, magics);
2326
+ }
2327
+ if (hooks.has(name)) {
2328
+ return this.magicContainer(name, hooks);
2314
2329
  }
2315
2330
  return void 0;
2316
2331
  }
@@ -2339,11 +2354,11 @@ Expression: ${expression}` : message);
2339
2354
  reactiveChild(vars, el = null) {
2340
2355
  return new _Scope(reactive(vars), this, el != null ? el : this.el);
2341
2356
  }
2342
- magicContainer(name) {
2357
+ magicContainer(name, registry) {
2343
2358
  if (!this.magicCache) this.magicCache = /* @__PURE__ */ new Map();
2344
2359
  const cached = this.magicCache.get(name);
2345
2360
  if (cached) return cached;
2346
- const getter = magics.get(name);
2361
+ const getter = registry.get(name);
2347
2362
  const scope = this;
2348
2363
  const container2 = {};
2349
2364
  Object.defineProperty(container2, name, {
@@ -2690,7 +2705,16 @@ Suggestion: attribute expressions accept a single value. If the logic spans more
2690
2705
  },
2691
2706
  effect(fn) {
2692
2707
  const owner = ownerScope();
2693
- owner.run(() => effect(fn, { scope: owner }));
2708
+ const hosted = () => {
2709
+ const previous = hookHost;
2710
+ hookHost = el;
2711
+ try {
2712
+ fn();
2713
+ } finally {
2714
+ hookHost = previous;
2715
+ }
2716
+ };
2717
+ owner.run(() => effect(hosted, { scope: owner }));
2694
2718
  },
2695
2719
  cleanup(fn) {
2696
2720
  addCleanup(el, fn);
@@ -2738,6 +2762,56 @@ Suggestion: attribute expressions accept a single value. If the logic spans more
2738
2762
  return;
2739
2763
  }
2740
2764
  initialized.add(el);
2765
+ const previousHost = hookHost;
2766
+ hookHost = el;
2767
+ try {
2768
+ walkElementDirectives(el, attrs, tagComponent, current2);
2769
+ } finally {
2770
+ hookHost = previousHost;
2771
+ }
2772
+ }
2773
+ var hookHost = null;
2774
+ function currentHookHost() {
2775
+ return hookHost;
2776
+ }
2777
+ function createDataScope(expression, parent, el) {
2778
+ let ast = null;
2779
+ try {
2780
+ ast = parse(expression);
2781
+ } catch (e) {
2782
+ ast = null;
2783
+ }
2784
+ const plain = ast && ast.t === "obj" && ast.props.every(
2785
+ (p2) => !p2.spread && !p2.keyExpr
2786
+ );
2787
+ if (!plain) {
2788
+ const raw = evaluateIn(expression, parent, "v-data");
2789
+ return parent.reactiveChild(raw && typeof raw === "object" ? raw : {}, el);
2790
+ }
2791
+ const scope = parent.reactiveChild({}, el);
2792
+ const props = ast.props;
2793
+ for (const prop of props) {
2794
+ if (prop.key === null) continue;
2795
+ try {
2796
+ if (prop.getter) {
2797
+ const compute = evaluate(prop.value, scope);
2798
+ Object.defineProperty(scope.data, prop.key, {
2799
+ enumerable: true,
2800
+ configurable: true,
2801
+ get: () => compute.call(scope.data)
2802
+ });
2803
+ } else {
2804
+ scope.data[prop.key] = evaluate(prop.value, scope);
2805
+ }
2806
+ } catch (err) {
2807
+ if (inDevelopment()) warnInvalidExpression(el, expression, expression, err);
2808
+ else handleError(err, "v-data");
2809
+ }
2810
+ }
2811
+ return scope;
2812
+ }
2813
+ function walkElementDirectives(el, attrs, tagComponent, scope) {
2814
+ let current2 = scope;
2741
2815
  for (const attr2 of attrs) {
2742
2816
  const def = directives.get(attr2.name);
2743
2817
  if (def == null ? void 0 : def.terminal) {
@@ -2757,11 +2831,10 @@ Suggestion: attribute expressions accept a single value. If the logic spans more
2757
2831
  nodeScopes.set(el, current2);
2758
2832
  }
2759
2833
  } else if (dataAttr || componentAttr) {
2760
- const raw = dataAttr ? evaluateIn(dataAttr.expression || "{}", current2, "v-data") : {};
2761
- current2 = current2.reactiveChild(raw && typeof raw === "object" ? raw : {}, el);
2834
+ current2 = createDataScope(dataAttr ? dataAttr.expression || "{}" : "{}", current2, el);
2762
2835
  nodeScopes.set(el, current2);
2763
2836
  }
2764
- const attributeScope = mountedComponent ? activeScope2 : current2;
2837
+ const attributeScope = mountedComponent ? scope : current2;
2765
2838
  for (const attr2 of attrs) {
2766
2839
  if (attr2.name === "data" || attr2.name === "component") continue;
2767
2840
  runDirective(el, attr2, attributeScope);
@@ -2918,9 +2991,9 @@ Suggestion: attribute expressions accept a single value. If the logic spans more
2918
2991
  var observer = null;
2919
2992
  var startHooks = [];
2920
2993
  function runPhase(target, after) {
2921
- for (const hook of startHooks) {
2994
+ for (const hook2 of startHooks) {
2922
2995
  try {
2923
- hook(target, after);
2996
+ hook2(target, after);
2924
2997
  } catch (error) {
2925
2998
  console.error("[Voodoo] a start hook failed", error);
2926
2999
  }
@@ -3304,10 +3377,10 @@ Suggestion: attribute expressions accept a single value. If the logic spans more
3304
3377
  "destroyed"
3305
3378
  ]);
3306
3379
  function callHook(def, instance, name) {
3307
- const hook = def[name];
3308
- if (typeof hook !== "function") return;
3380
+ const hook2 = def[name];
3381
+ if (typeof hook2 !== "function") return;
3309
3382
  try {
3310
- hook.call(instance);
3383
+ hook2.call(instance);
3311
3384
  } catch (err) {
3312
3385
  handleError(err, `hook ${name}`);
3313
3386
  }
@@ -4766,6 +4839,7 @@ Suggestion: attribute expressions accept a single value. If the logic spans more
4766
4839
  );
4767
4840
 
4768
4841
  // src/storage/index.ts
4842
+ init_reactivity();
4769
4843
  function createStorage(getStore, prefix = "") {
4770
4844
  const full = (key) => prefix + key;
4771
4845
  return {
@@ -4941,22 +5015,29 @@ Suggestion: attribute expressions accept a single value. If the logic spans more
4941
5015
  };
4942
5016
  var THEME_KEY = "voodoo:theme";
4943
5017
  var picked = null;
5018
+ var revision = ref(0);
4944
5019
  var theme = {
4945
5020
  /** Theme chosen by the user, or `system` when never set. */
4946
5021
  get current() {
4947
5022
  var _a2, _b;
5023
+ void revision.value;
4948
5024
  return (_b = (_a2 = storage.get(THEME_KEY)) != null ? _a2 : picked) != null ? _b : "system";
4949
5025
  },
4950
5026
  /** Theme effectively applied, resolving `system`. */
4951
5027
  get resolved() {
4952
5028
  const value = this.current;
4953
5029
  if (value !== "system") return value;
5030
+ if (typeof document !== "undefined") {
5031
+ const authored = document.documentElement.getAttribute("data-theme");
5032
+ if (authored === "light" || authored === "dark") return authored;
5033
+ }
4954
5034
  if (typeof matchMedia === "undefined") return "light";
4955
5035
  return matchMedia("(prefers-color-scheme: dark)").matches ? "dark" : "light";
4956
5036
  },
4957
5037
  set(value) {
4958
5038
  picked = value;
4959
5039
  storage.set(THEME_KEY, value);
5040
+ revision.value++;
4960
5041
  this.apply();
4961
5042
  },
4962
5043
  toggle() {
@@ -4990,8 +5071,17 @@ Suggestion: attribute expressions accept a single value. If the logic spans more
4990
5071
  init() {
4991
5072
  if (typeof document === "undefined") return;
4992
5073
  this.apply();
5074
+ if (typeof MutationObserver !== "undefined") {
5075
+ new MutationObserver(() => {
5076
+ revision.value++;
5077
+ }).observe(document.documentElement, {
5078
+ attributes: true,
5079
+ attributeFilter: ["data-theme"]
5080
+ });
5081
+ }
4993
5082
  if (typeof matchMedia === "undefined") return;
4994
5083
  matchMedia("(prefers-color-scheme: dark)").addEventListener("change", () => {
5084
+ revision.value++;
4995
5085
  if (this.current === "system") this.apply();
4996
5086
  });
4997
5087
  }
@@ -5135,6 +5225,141 @@ Suggestion: attribute expressions accept a single value. If the logic spans more
5135
5225
  );
5136
5226
  }
5137
5227
 
5228
+ // src/hooks/index.ts
5229
+ init_reactivity();
5230
+ var tables = /* @__PURE__ */ new WeakMap();
5231
+ function tableFor(scope) {
5232
+ var _a2, _b, _c;
5233
+ const host = (_b = (_a2 = currentHookHost()) != null ? _a2 : scope.el) != null ? _b : scope;
5234
+ let table = tables.get(host);
5235
+ if (!table) {
5236
+ table = { slots: [], index: 0, scheduled: false, bound: false };
5237
+ tables.set(host, table);
5238
+ }
5239
+ const el = (_c = currentHookHost()) != null ? _c : scope.el;
5240
+ if (!table.bound && el) {
5241
+ table.bound = true;
5242
+ const owned = table;
5243
+ addCleanup(el, () => {
5244
+ for (const slot of owned.slots) {
5245
+ if (slot.dispose) slot.dispose();
5246
+ if (slot.runner) stop(slot.runner);
5247
+ }
5248
+ owned.slots.length = 0;
5249
+ });
5250
+ }
5251
+ if (!table.scheduled) {
5252
+ table.scheduled = true;
5253
+ const pending = table;
5254
+ queueMicrotask(() => {
5255
+ pending.index = 0;
5256
+ pending.scheduled = false;
5257
+ });
5258
+ }
5259
+ return table;
5260
+ }
5261
+ function nextSlot(scope, kind) {
5262
+ const table = tableFor(scope);
5263
+ const at = table.index++;
5264
+ let slot = table.slots[at];
5265
+ if (!slot || slot.kind !== kind) {
5266
+ if (slot) {
5267
+ if (slot.dispose) slot.dispose();
5268
+ if (slot.runner) stop(slot.runner);
5269
+ }
5270
+ slot = { kind, deps: null, value: void 0 };
5271
+ table.slots[at] = slot;
5272
+ }
5273
+ return slot;
5274
+ }
5275
+ function depsChanged(previous, next) {
5276
+ if (!previous || !next) return true;
5277
+ if (previous.length !== next.length) return true;
5278
+ for (let i = 0; i < next.length; i++) {
5279
+ if (!Object.is(previous[i], next[i])) return true;
5280
+ }
5281
+ return false;
5282
+ }
5283
+ function normalizeDeps(deps) {
5284
+ return Array.isArray(deps) ? deps.slice() : null;
5285
+ }
5286
+ function useState(scope, initial) {
5287
+ const slot = nextSlot(scope, "state");
5288
+ if (slot.value === void 0) slot.value = ref(initial);
5289
+ return slot.value;
5290
+ }
5291
+ function useEffect(scope, fn, deps) {
5292
+ const slot = nextSlot(scope, "effect");
5293
+ const next = normalizeDeps(deps);
5294
+ const runCleanup = () => {
5295
+ if (slot.dispose) {
5296
+ const dispose = slot.dispose;
5297
+ slot.dispose = void 0;
5298
+ dispose();
5299
+ }
5300
+ };
5301
+ if (next) {
5302
+ const first = slot.deps === null && !slot.runner;
5303
+ if (first || depsChanged(slot.deps, next)) {
5304
+ slot.deps = next;
5305
+ runCleanup();
5306
+ const result = fn();
5307
+ if (typeof result === "function") slot.dispose = result;
5308
+ }
5309
+ return;
5310
+ }
5311
+ if (slot.runner) return;
5312
+ slot.deps = null;
5313
+ slot.runner = effect(() => {
5314
+ runCleanup();
5315
+ const result = fn();
5316
+ if (typeof result === "function") slot.dispose = result;
5317
+ });
5318
+ }
5319
+ function useMemo(scope, fn, deps) {
5320
+ const slot = nextSlot(scope, "memo");
5321
+ const next = normalizeDeps(deps);
5322
+ if (!next) {
5323
+ if (!slot.value) slot.value = computed(fn);
5324
+ return slot.value;
5325
+ }
5326
+ if (!slot.value) {
5327
+ slot.value = ref(fn());
5328
+ slot.deps = next;
5329
+ } else if (depsChanged(slot.deps, next)) {
5330
+ slot.deps = next;
5331
+ slot.value.value = fn();
5332
+ }
5333
+ return slot.value;
5334
+ }
5335
+ function useRef(scope, initial) {
5336
+ const slot = nextSlot(scope, "ref");
5337
+ if (!slot.value) slot.value = markRaw({ current: initial });
5338
+ return slot.value;
5339
+ }
5340
+ function useContext(name, initial) {
5341
+ if (initial !== void 0 && !(name in allStores)) {
5342
+ store(name, initial);
5343
+ }
5344
+ return allStores[name];
5345
+ }
5346
+ function installHooks() {
5347
+ hook("useState", (scope) => (initial) => useState(scope, initial));
5348
+ hook(
5349
+ "useEffect",
5350
+ (scope) => (fn, deps) => useEffect(scope, fn, deps)
5351
+ );
5352
+ hook(
5353
+ "useMemo",
5354
+ (scope) => (fn, deps) => useMemo(scope, fn, deps)
5355
+ );
5356
+ hook("useRef", (scope) => (initial) => useRef(scope, initial));
5357
+ hook(
5358
+ "useContext",
5359
+ () => (name, initial) => useContext(name, initial)
5360
+ );
5361
+ }
5362
+
5138
5363
  // src/http/resource.ts
5139
5364
  init_reactivity();
5140
5365
  function pick(value, path) {
@@ -6739,6 +6964,7 @@ Suggestion: attribute expressions accept a single value. If the logic spans more
6739
6964
  setScopeMarker(markNodeScope);
6740
6965
  setDirectiveRegistrar(directive);
6741
6966
  installMagics();
6967
+ installHooks();
6742
6968
  var eventBus = /* @__PURE__ */ new Map();
6743
6969
  function on(name, handler) {
6744
6970
  let set2 = eventBus.get(name);
@@ -6774,7 +7000,7 @@ Suggestion: attribute expressions accept a single value. If the logic spans more
6774
7000
  }
6775
7001
  function directive(name, definition) {
6776
7002
  var _a2, _b;
6777
- const hooks = typeof definition === "function" ? { mounted: definition, updated: definition } : definition;
7003
+ const hooks2 = typeof definition === "function" ? { mounted: definition, updated: definition } : definition;
6778
7004
  defineDirective(
6779
7005
  name,
6780
7006
  (ctx) => {
@@ -6794,38 +7020,38 @@ Suggestion: attribute expressions accept a single value. If the logic spans more
6794
7020
  instance: (_b3 = (_a4 = ctx.scope.owner) == null ? void 0 : _a4.component) != null ? _b3 : null
6795
7021
  };
6796
7022
  };
6797
- const initial = hooks.raw ? ctx.expression : ctx.evaluate();
6798
- (_a3 = hooks.created) == null ? void 0 : _a3.call(hooks, ctx.el, makeBinding(initial));
6799
- (_b2 = hooks.beforeMount) == null ? void 0 : _b2.call(hooks, ctx.el, makeBinding(initial));
7023
+ const initial = hooks2.raw ? ctx.expression : ctx.evaluate();
7024
+ (_a3 = hooks2.created) == null ? void 0 : _a3.call(hooks2, ctx.el, makeBinding(initial));
7025
+ (_b2 = hooks2.beforeMount) == null ? void 0 : _b2.call(hooks2, ctx.el, makeBinding(initial));
6800
7026
  ctx.effect(() => {
6801
7027
  var _a4, _b3;
6802
- const value = hooks.raw ? ctx.expression : ctx.evaluate();
7028
+ const value = hooks2.raw ? ctx.expression : ctx.evaluate();
6803
7029
  if (!mounted) {
6804
7030
  mounted = true;
6805
7031
  oldValue = value;
6806
- (_a4 = hooks.mounted) == null ? void 0 : _a4.call(hooks, ctx.el, makeBinding(value));
7032
+ (_a4 = hooks2.mounted) == null ? void 0 : _a4.call(hooks2, ctx.el, makeBinding(value));
6807
7033
  return;
6808
7034
  }
6809
7035
  if (value === oldValue) return;
6810
7036
  const binding = makeBinding(value);
6811
- (_b3 = hooks.updated) == null ? void 0 : _b3.call(hooks, ctx.el, binding);
7037
+ (_b3 = hooks2.updated) == null ? void 0 : _b3.call(hooks2, ctx.el, binding);
6812
7038
  oldValue = value;
6813
7039
  });
6814
7040
  ctx.cleanup(() => {
6815
7041
  var _a4, _b3;
6816
7042
  const binding = makeBinding(oldValue);
6817
- (_a4 = hooks.beforeUnmount) == null ? void 0 : _a4.call(hooks, ctx.el, binding);
6818
- (_b3 = hooks.unmounted) == null ? void 0 : _b3.call(hooks, ctx.el, binding);
7043
+ (_a4 = hooks2.beforeUnmount) == null ? void 0 : _a4.call(hooks2, ctx.el, binding);
7044
+ (_b3 = hooks2.unmounted) == null ? void 0 : _b3.call(hooks2, ctx.el, binding);
6819
7045
  });
6820
7046
  },
6821
- { priority: (_a2 = hooks.priority) != null ? _a2 : PRIORITY.DEFAULT, terminal: (_b = hooks.terminal) != null ? _b : false }
7047
+ { priority: (_a2 = hooks2.priority) != null ? _a2 : PRIORITY.DEFAULT, terminal: (_b = hooks2.terminal) != null ? _b : false }
6822
7048
  );
6823
7049
  }
6824
7050
  function data(values) {
6825
7051
  Object.defineProperties(rootScope.data, Object.getOwnPropertyDescriptors(values));
6826
7052
  return rootScope.data;
6827
7053
  }
6828
- var version2 = "0.11.1";
7054
+ var version2 = "0.12.1";
6829
7055
  var core = {
6830
7056
  // Utilities first: Voodoo's own names can override.
6831
7057
  ...utils_exports,