@almadar/ui 6.53.1 → 6.55.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 (120) hide show
  1. package/dist/{AwaitingSkeletonContext-Bh399p1x.d.ts → AwaitingSkeletonContext-DPgW__WV.d.ts} +3 -1
  2. package/dist/{Canvas3DHost-B-y2TNij.d.ts → Canvas3DHost-DfAhg6EH.d.ts} +2 -0
  3. package/dist/Typography-7PDT62PG.js +5 -0
  4. package/dist/{UISlotRenderer-P7A4SZSK.js → UISlotRenderer-QTHFT6Z4.js} +8 -8
  5. package/dist/avl/index.cjs +3031 -1790
  6. package/dist/avl/index.js +57 -745
  7. package/dist/{avl-3d-context-MAt_NuU9.d.ts → avl-3d-context-BpBKZIbc.d.ts} +1 -0
  8. package/dist/{chunk-ERXIHZW3.js → chunk-D2E44ODB.js} +29 -15
  9. package/dist/{chunk-UOTYAPV5.js → chunk-F4ZTPKZL.js} +3 -3
  10. package/dist/{chunk-53VTY5CC.js → chunk-FQM37C56.js} +352 -162
  11. package/dist/{chunk-HB4C27KU.js → chunk-HCSJHRC4.js} +1 -1
  12. package/dist/{chunk-7KSLPY56.js → chunk-HRCR53OW.js} +11 -1
  13. package/dist/{chunk-O7OLVVBR.js → chunk-Q47ZN2DW.js} +24 -22
  14. package/dist/{chunk-DQTV6QVS.js → chunk-QGH4NAQO.js} +53 -2
  15. package/dist/{chunk-QVXLKFUQ.js → chunk-RNY5LJXJ.js} +1 -1
  16. package/dist/{chunk-FUQASYEW.js → chunk-SGJHVPHC.js} +2 -2
  17. package/dist/{chunk-6O37FCX4.js → chunk-V3FGTQUE.js} +37 -2
  18. package/dist/{chunk-HUG25TT3.js → chunk-XZKGRSIO.js} +2745 -1644
  19. package/dist/{chunk-7LM6I3NA.js → chunk-Y53Q55H5.js} +522 -24
  20. package/dist/components/index.cjs +4614 -2858
  21. package/dist/components/index.d.ts +122 -53
  22. package/dist/components/index.js +16 -17
  23. package/dist/context/index.cjs +38 -1
  24. package/dist/context/index.d.ts +1 -1
  25. package/dist/context/index.js +3 -1
  26. package/dist/design-classes/index.cjs +29 -15
  27. package/dist/design-classes/index.d.cts +1 -0
  28. package/dist/design-classes/index.d.ts +1 -0
  29. package/dist/design-classes/index.js +29 -15
  30. package/dist/hooks/index.cjs +16 -1
  31. package/dist/hooks/index.d.ts +10 -1
  32. package/dist/hooks/index.js +3 -4
  33. package/dist/lib/drawable/three/index.cjs +444 -82
  34. package/dist/lib/drawable/three/index.d.ts +4 -4
  35. package/dist/lib/drawable/three/index.js +28 -24
  36. package/dist/lib/index.cjs +53 -3
  37. package/dist/lib/index.d.ts +1 -1
  38. package/dist/lib/index.js +4 -4
  39. package/dist/locales/index.cjs +33 -3
  40. package/dist/locales/index.js +23 -3
  41. package/dist/providers/index.cjs +4987 -3183
  42. package/dist/providers/index.d.ts +2 -2
  43. package/dist/providers/index.js +14 -11
  44. package/dist/runtime/index.cjs +8973 -7000
  45. package/dist/runtime/index.d.ts +28 -6
  46. package/dist/runtime/index.js +16 -13
  47. package/dist/ssr/index.cjs +26 -9
  48. package/dist/ssr/index.js +26 -9
  49. package/dist/{themeTokens-Ccu7EmGY.d.ts → themeTokens-D6MFwKrC.d.ts} +6 -2
  50. package/locales/ar.json +11 -1
  51. package/locales/en.json +11 -1
  52. package/locales/sl.json +11 -1
  53. package/package.json +8 -7
  54. package/scripts/audit-tailwind-safelist.ts +21 -1
  55. package/scripts/theme-contrast-audit.mjs +20 -1
  56. package/tailwind-preset.cjs +5 -6
  57. package/themes/_base.css +61 -0
  58. package/themes/_contract.md +37 -0
  59. package/themes/_fonts.css +6 -4
  60. package/themes/_presets.css +2 -0
  61. package/themes/almadar-heritage.css +455 -0
  62. package/themes/almadar-website.css +82 -0
  63. package/themes/almadar.css +82 -0
  64. package/themes/aqua.css +82 -0
  65. package/themes/arabesque.css +82 -0
  66. package/themes/art-deco.css +82 -0
  67. package/themes/art-nouveau.css +82 -0
  68. package/themes/atelier.css +82 -0
  69. package/themes/bauhaus.css +82 -0
  70. package/themes/bloomberg-dense.css +83 -1
  71. package/themes/blueprint.css +84 -0
  72. package/themes/clay.css +82 -0
  73. package/themes/comic.css +82 -0
  74. package/themes/constructivist.css +82 -0
  75. package/themes/corporate.css +82 -0
  76. package/themes/cyberpunk.css +82 -0
  77. package/themes/frutiger-aero.css +83 -0
  78. package/themes/game-adventure.css +15 -0
  79. package/themes/game-rpg.css +16 -0
  80. package/themes/game-sci-fi.css +15 -0
  81. package/themes/game-ui-pack.css +15 -0
  82. package/themes/gazette.css +82 -0
  83. package/themes/glass.css +82 -0
  84. package/themes/gothic.css +82 -0
  85. package/themes/ink-wash.css +82 -0
  86. package/themes/kawaii.css +82 -0
  87. package/themes/kiosk.css +82 -0
  88. package/themes/linear-clean.css +82 -0
  89. package/themes/luxury.css +82 -0
  90. package/themes/mac-classic.css +90 -8
  91. package/themes/material.css +82 -0
  92. package/themes/memphis.css +82 -0
  93. package/themes/mid-century.css +82 -0
  94. package/themes/minimalist.css +82 -0
  95. package/themes/mudcloth.css +82 -0
  96. package/themes/neon.css +83 -0
  97. package/themes/neumorphic.css +82 -0
  98. package/themes/newsprint.css +82 -0
  99. package/themes/notion-editorial.css +82 -0
  100. package/themes/orb.css +455 -0
  101. package/themes/pixel.css +82 -0
  102. package/themes/prism.css +82 -0
  103. package/themes/retro.css +83 -0
  104. package/themes/risograph.css +82 -0
  105. package/themes/scandi.css +82 -0
  106. package/themes/sketch.css +82 -0
  107. package/themes/solarpunk.css +82 -0
  108. package/themes/steampunk.css +82 -0
  109. package/themes/swiss.css +82 -0
  110. package/themes/terminal.css +84 -1
  111. package/themes/trait-wars.css +82 -0
  112. package/themes/ukiyo-e.css +82 -0
  113. package/themes/vaporwave.css +82 -0
  114. package/themes/victorian.css +82 -0
  115. package/themes/wabi-sabi.css +82 -0
  116. package/themes/win95.css +84 -0
  117. package/themes/wireframe.css +82 -0
  118. package/themes/zine.css +82 -0
  119. package/dist/Typography-7QEWUTW3.js +0 -5
  120. package/dist/chunk-E37BYSXY.js +0 -51
@@ -1,23 +1,26 @@
1
1
  import { useTapReveal } from './chunk-XJTHMW4G.js';
2
2
  import { useEventBus } from './chunk-6EV3OEBQ.js';
3
- import { updateAssetStatus } from './chunk-O7OLVVBR.js';
3
+ import { updateAssetStatus } from './chunk-Q47ZN2DW.js';
4
4
  import { cn, domPassthrough } from './chunk-64WACXM7.js';
5
+ import { __publicField } from './chunk-QPXIAUJD.js';
5
6
  import { createLogger } from '@almadar/logger';
6
- import React, { useCallback, createContext, useContext } from 'react';
7
- import { useThemeScope } from '@almadar/ui/context';
7
+ import React, { useCallback, createContext, useContext, useState, useLayoutEffect } from 'react';
8
+ import { useThemeScope, useTheme } from '@almadar/ui/context';
8
9
  import { jsx } from 'react/jsx-runtime';
9
10
  import { renderUiEntriesOf } from '@almadar/core/patterns';
10
- import { isInlineTrait } from '@almadar/core';
11
+ import { DIAGRAM_TONES, isInlineTrait, DIAGRAM_TONE_COLOR_KEYS, DIAGRAM_TEXT_SIZES } from '@almadar/core';
11
12
  import { parseListenSource } from '@almadar/runtime';
12
13
 
13
14
  var log = createLogger("almadar:ui:theme-color");
14
15
  var THEME_SERIES = [
15
- "var(--color-primary)",
16
- "var(--color-success)",
17
- "var(--color-warning)",
18
- "var(--color-error)",
19
- "var(--color-info)",
20
- "var(--color-accent)"
16
+ "var(--color-series-1)",
17
+ "var(--color-series-2)",
18
+ "var(--color-series-3)",
19
+ "var(--color-series-4)",
20
+ "var(--color-series-5)",
21
+ "var(--color-series-6)",
22
+ "var(--color-series-7)",
23
+ "var(--color-series-8)"
21
24
  ];
22
25
  function channel(value, unitScale) {
23
26
  return Math.round(Math.min(255, Math.max(0, Number(value) * unitScale)));
@@ -25,8 +28,40 @@ function channel(value, unitScale) {
25
28
  function make(r, g, b, a) {
26
29
  return { r, g, b, a, css: `rgb(${r}, ${g}, ${b})` };
27
30
  }
31
+ function gamma(linear) {
32
+ const c = Math.min(1, Math.max(0, linear));
33
+ return Math.round(255 * (c <= 31308e-7 ? 12.92 * c : 1.055 * Math.pow(c, 1 / 2.4) - 0.055));
34
+ }
35
+ function fromOklab(L, a, b, alpha) {
36
+ const l = (L + 0.3963377774 * a + 0.2158037573 * b) ** 3;
37
+ const m = (L - 0.1055613458 * a - 0.0638541728 * b) ** 3;
38
+ const s = (L - 0.0894841775 * a - 1.291485548 * b) ** 3;
39
+ return make(
40
+ gamma(4.0767416621 * l - 3.3077115913 * m + 0.2309699292 * s),
41
+ gamma(-1.2684380046 * l + 2.6097574011 * m - 0.3413193965 * s),
42
+ gamma(-0.0041960863 * l - 0.7034186147 * m + 1.707614701 * s),
43
+ alpha
44
+ );
45
+ }
46
+ function component(raw, percentOf) {
47
+ if (raw === "none") return 0;
48
+ return raw.endsWith("%") ? Number(raw.slice(0, -1)) / 100 * percentOf : Number(raw);
49
+ }
50
+ var NUM = "(none|-?[\\d.]+(?:e-?\\d+)?%?)";
51
+ var OKLCH = new RegExp(`^oklch\\(\\s*${NUM}\\s+${NUM}\\s+${NUM}(?:deg)?\\s*(?:\\/\\s*${NUM}\\s*)?\\)$`, "i");
52
+ var OKLAB = new RegExp(`^oklab\\(\\s*${NUM}\\s+${NUM}\\s+${NUM}\\s*(?:\\/\\s*${NUM}\\s*)?\\)$`, "i");
28
53
  function parseComputedColor(value) {
29
54
  const v = value.trim();
55
+ const lch = OKLCH.exec(v);
56
+ if (lch) {
57
+ const hue = component(lch[3], 360) * Math.PI / 180;
58
+ const chroma = component(lch[2], 0.4);
59
+ return fromOklab(component(lch[1], 1), chroma * Math.cos(hue), chroma * Math.sin(hue), lch[4] === void 0 ? 1 : component(lch[4], 1));
60
+ }
61
+ const lab = OKLAB.exec(v);
62
+ if (lab) {
63
+ return fromOklab(component(lab[1], 1), component(lab[2], 0.4), component(lab[3], 0.4), lab[4] === void 0 ? 1 : component(lab[4], 1));
64
+ }
30
65
  const hex = /^#([0-9a-f]{3}|[0-9a-f]{6})$/i.exec(v);
31
66
  if (hex) {
32
67
  const h = hex[1].length === 3 ? hex[1].split("").map((c) => c + c).join("") : hex[1];
@@ -306,6 +341,7 @@ var OPERATOR_CATEGORY_COLORS = {
306
341
  "std-json": avlBlend("var(--color-success)", 60, "var(--color-foreground)"),
307
342
  "std-time": avlBlend("var(--color-info)", 50, "var(--color-success)"),
308
343
  "std-format": avlBlend("var(--color-success)", 60, "var(--color-background)"),
344
+ "std-i18n": avlBlend("var(--color-info)", 60, "var(--color-background)"),
309
345
  "std-async": avlBlend("var(--color-accent)", 50, "var(--color-error)"),
310
346
  "std-nn": avlBlend("var(--color-primary)", 60, "var(--color-accent)"),
311
347
  "std-tensor": avlBlend("var(--color-primary)", 60, "var(--color-info)"),
@@ -677,30 +713,40 @@ function instanceOf(orbital, orbitalId, ref) {
677
713
  if (typeof ref === "object" && ref._resolved) return { ...at, name: ref.name ?? ref._resolved.name, trait: ref._resolved };
678
714
  return null;
679
715
  }
716
+ var wiresBySchema = /* @__PURE__ */ new WeakMap();
680
717
  function traitEventWires(schema) {
718
+ const cached = wiresBySchema.get(schema);
719
+ if (cached) return cached;
681
720
  const instances = (schema.orbitals ?? []).flatMap(
682
721
  (o) => (o.traits ?? []).map((ref) => instanceOf(o.name, o.id, ref)).filter((i) => i !== null)
683
722
  );
723
+ const listensByEvent = /* @__PURE__ */ new Map();
724
+ for (const listener of instances) {
725
+ for (const listen of listener.trait.listens ?? []) {
726
+ const { bareEvent, matcher } = parseListenSource(listen, listener.orbital);
727
+ const bucket = listensByEvent.get(bareEvent);
728
+ if (bucket) bucket.push({ listener, matcher });
729
+ else listensByEvent.set(bareEvent, [{ listener, matcher }]);
730
+ }
731
+ }
684
732
  const wires = [];
685
733
  for (const emitter of instances) {
734
+ const source = { orbital: emitter.orbital, trait: emitter.name, ...emitter.orbitalId ? { orbitalId: emitter.orbitalId } : {}, ...emitter.trait.id ? { traitId: emitter.trait.id } : {} };
686
735
  for (const emit of emitter.trait.emits ?? []) {
687
- for (const listener of instances) {
736
+ for (const { listener, matcher } of listensByEvent.get(emit.event) ?? []) {
688
737
  if (listener.orbital === emitter.orbital && listener.name === emitter.name) continue;
689
- for (const listen of listener.trait.listens ?? []) {
690
- const { bareEvent, matcher } = parseListenSource(listen, listener.orbital);
691
- const source = { orbital: emitter.orbital, trait: emitter.name, ...emitter.orbitalId ? { orbitalId: emitter.orbitalId } : {}, ...emitter.trait.id ? { traitId: emitter.trait.id } : {} };
692
- if (bareEvent !== emit.event || !matcher(source)) continue;
693
- wires.push({
694
- emitterOrbital: emitter.orbital,
695
- emitterTrait: emitter.name,
696
- listenerOrbital: listener.orbital,
697
- listenerTrait: listener.name,
698
- event: emit.event
699
- });
700
- }
738
+ if (!matcher(source)) continue;
739
+ wires.push({
740
+ emitterOrbital: emitter.orbital,
741
+ emitterTrait: emitter.name,
742
+ listenerOrbital: listener.orbital,
743
+ listenerTrait: listener.name,
744
+ event: emit.event
745
+ });
701
746
  }
702
747
  }
703
748
  }
749
+ wiresBySchema.set(schema, wires);
704
750
  return wires;
705
751
  }
706
752
 
@@ -1901,6 +1947,458 @@ function DrawFxLayer(_props) {
1901
1947
  return null;
1902
1948
  }
1903
1949
 
1950
+ // lib/drawable/themeDrawables.ts
1951
+ function opt(value, resolve) {
1952
+ return value === void 0 ? void 0 : resolve(value);
1953
+ }
1954
+ function themeShape(node, resolve) {
1955
+ return {
1956
+ ...node,
1957
+ ...node.fill !== void 0 ? { fill: resolve(node.fill) } : {},
1958
+ ...node.stroke !== void 0 ? { stroke: resolve(node.stroke) } : {},
1959
+ ...node.gradient ? { gradient: { ...node.gradient, stops: node.gradient.stops.map((s) => ({ ...s, color: resolve(s.color) })) } } : {},
1960
+ ...node.fillPattern?.color !== void 0 ? { fillPattern: { ...node.fillPattern, color: resolve(node.fillPattern.color) } } : {},
1961
+ ...node.shadow ? { shadow: { ...node.shadow, color: resolve(node.shadow.color) } } : {},
1962
+ ...node.animation ? {
1963
+ animation: {
1964
+ ...node.animation,
1965
+ keyframes: node.animation.keyframes.map((k) => ({
1966
+ ...k,
1967
+ ...k.fill !== void 0 ? { fill: resolve(k.fill) } : {},
1968
+ ...k.stroke !== void 0 ? { stroke: resolve(k.stroke) } : {}
1969
+ }))
1970
+ }
1971
+ } : {}
1972
+ };
1973
+ }
1974
+ function themeText(node, resolve) {
1975
+ return { ...node, color: resolve(node.color) };
1976
+ }
1977
+ function themeMaterial(material, resolve) {
1978
+ if (!material) return material;
1979
+ return {
1980
+ ...material,
1981
+ ...material.color !== void 0 ? { color: resolve(material.color) } : {},
1982
+ ...material.emissive !== void 0 ? { emissive: resolve(material.emissive) } : {}
1983
+ };
1984
+ }
1985
+ function resolveDrawableColors(nodes, resolve) {
1986
+ return nodes.map((node) => {
1987
+ switch (node.type) {
1988
+ case "draw-shape":
1989
+ return themeShape(node, resolve);
1990
+ case "draw-text":
1991
+ return themeText(node, resolve);
1992
+ case "draw-group":
1993
+ return { ...node, items: resolveDrawableColors(node.items, resolve) };
1994
+ case "draw-shape-layer":
1995
+ return { ...node, items: node.items.map((item) => themeShape(item, resolve)) };
1996
+ case "draw-text-layer":
1997
+ return { ...node, items: node.items.map((item) => themeText(item, resolve)) };
1998
+ case "draw-fx-layer":
1999
+ return {
2000
+ ...node,
2001
+ ...node.textColor !== void 0 ? { textColor: resolve(node.textColor) } : {},
2002
+ ...node.presets ? {
2003
+ presets: node.presets.map((p) => ({
2004
+ ...p,
2005
+ ...p.color !== void 0 ? { color: resolve(p.color) } : {},
2006
+ ...p.color2 !== void 0 ? { color2: resolve(p.color2) } : {}
2007
+ }))
2008
+ } : {}
2009
+ };
2010
+ case "draw-mesh":
2011
+ return {
2012
+ ...node,
2013
+ material: themeMaterial(node.material, resolve),
2014
+ ...node.outline ? { outline: { ...node.outline, ...node.outline.color !== void 0 ? { color: resolve(node.outline.color) } : {} } } : {},
2015
+ ...node.animation ? {
2016
+ animation: {
2017
+ ...node.animation,
2018
+ keyframes: node.animation.keyframes.map((k) => ({
2019
+ ...k,
2020
+ ...k.color !== void 0 ? { color: resolve(k.color) } : {},
2021
+ ...k.emissive !== void 0 ? { emissive: opt(k.emissive, resolve) } : {}
2022
+ }))
2023
+ }
2024
+ } : {}
2025
+ };
2026
+ default:
2027
+ return node;
2028
+ }
2029
+ });
2030
+ }
2031
+ function applySceneMaterials(nodes, theme) {
2032
+ return nodes.map((node) => {
2033
+ if (node.type === "draw-group") return { ...node, items: applySceneMaterials(node.items, theme) };
2034
+ if (node.type !== "draw-mesh") return node;
2035
+ const m = node.material ?? {};
2036
+ const pbr = (m.kind ?? "standard") === "standard" || m.kind === "physical";
2037
+ return {
2038
+ ...node,
2039
+ material: {
2040
+ ...m,
2041
+ ...pbr && m.roughness === void 0 ? { roughness: theme.scene.roughness } : {},
2042
+ ...pbr && m.metalness === void 0 ? { metalness: theme.scene.metalness } : {},
2043
+ ...m.flatShading === void 0 && theme.scene.flat ? { flatShading: true } : {}
2044
+ },
2045
+ ...node.outline === void 0 && theme.scene.outline > 0 ? { outline: { color: theme.tones.ink, width: theme.scene.outline * 0.02 } } : {}
2046
+ };
2047
+ });
2048
+ }
2049
+ var log2 = createLogger("almadar:ui:canvas-theme");
2050
+ var toneVar = (tone) => `--color-${DIAGRAM_TONE_COLOR_KEYS[tone]}`;
2051
+ var SERIES_TONES = ["series-1", "series-2", "series-3", "series-4", "series-5", "series-6", "series-7", "series-8"];
2052
+ var TONE_SET = new Set(DIAGRAM_TONES);
2053
+ function isDiagramTone(value) {
2054
+ return TONE_SET.has(value);
2055
+ }
2056
+ function colorCss(c) {
2057
+ return c.a >= 1 ? c.css : `rgba(${c.r}, ${c.g}, ${c.b}, ${c.a})`;
2058
+ }
2059
+ function oneOf(value, allowed, fallback, name) {
2060
+ const hit = allowed.find((a) => a === value);
2061
+ if (hit !== void 0) return hit;
2062
+ if (value !== "") log2.warn("invalid-theme-keyword", { var: name, value, allowed });
2063
+ return fallback;
2064
+ }
2065
+ var PLAIN_LENGTH = /^(-?[\d.]+)(px)?$/;
2066
+ var ScopeReader = class {
2067
+ constructor(scope) {
2068
+ __publicField(this, "scope", scope);
2069
+ __publicField(this, "style");
2070
+ __publicField(this, "probe");
2071
+ this.style = getComputedStyle(scope);
2072
+ const doc = scope.ownerDocument;
2073
+ this.probe = doc.createElement("span");
2074
+ this.probe.style.position = "absolute";
2075
+ this.probe.style.visibility = "hidden";
2076
+ this.probe.style.pointerEvents = "none";
2077
+ scope.appendChild(this.probe);
2078
+ }
2079
+ dispose() {
2080
+ this.probe.remove();
2081
+ }
2082
+ raw(name) {
2083
+ return this.style.getPropertyValue(name).trim();
2084
+ }
2085
+ /** A length var in px: a plain value parses directly, a derived one (`calc`, `var`) through the probe. */
2086
+ length(name, fallback) {
2087
+ const raw = this.raw(name);
2088
+ const plain = PLAIN_LENGTH.exec(raw);
2089
+ if (plain) return Number(plain[1]);
2090
+ if (raw === "") return fallback;
2091
+ this.probe.style.width = `var(${name})`;
2092
+ const computed = PLAIN_LENGTH.exec(getComputedStyle(this.probe).width.trim());
2093
+ this.probe.style.width = "";
2094
+ if (computed) return Number(computed[1]);
2095
+ log2.warn("unresolvable-theme-length", { var: name, raw });
2096
+ return fallback;
2097
+ }
2098
+ number(name, fallback) {
2099
+ const raw = this.raw(name);
2100
+ if (raw === "") return fallback;
2101
+ const n = Number(raw);
2102
+ if (Number.isFinite(n)) return n;
2103
+ log2.warn("unresolvable-theme-number", { var: name, raw });
2104
+ return fallback;
2105
+ }
2106
+ /** A duration var in ms (`250ms`, `0.25s`, or a `var()` alias resolved through the probe). */
2107
+ durationMs(name, fallback) {
2108
+ const parse = (v) => {
2109
+ const m = /^([\d.]+)(ms|s)$/.exec(v.trim());
2110
+ return m ? Number(m[1]) * (m[2] === "s" ? 1e3 : 1) : null;
2111
+ };
2112
+ const raw = this.raw(name);
2113
+ const direct = parse(raw);
2114
+ if (direct !== null) return direct;
2115
+ if (raw === "") return fallback;
2116
+ this.probe.style.transitionDuration = `var(${name})`;
2117
+ const computed = parse(getComputedStyle(this.probe).transitionDuration.split(",")[0] ?? "");
2118
+ this.probe.style.transitionDuration = "";
2119
+ return computed ?? fallback;
2120
+ }
2121
+ color(name) {
2122
+ const raw = this.raw(name);
2123
+ return parseComputedColor(raw) ?? resolveThemeColor(`var(${name})`, this.scope);
2124
+ }
2125
+ shadow(name) {
2126
+ const raw = this.raw(name);
2127
+ if (raw === "" || raw === "none") return null;
2128
+ this.probe.style.boxShadow = `var(${name})`;
2129
+ const computed = getComputedStyle(this.probe).boxShadow.trim() || raw;
2130
+ this.probe.style.boxShadow = "";
2131
+ const colorMatch = /(rgba?\([^)]*\)|#[0-9a-f]{3,8}|oklch\([^)]*\))/i.exec(computed);
2132
+ const lengths = computed.replace(colorMatch?.[0] ?? "", "").trim().split(/\s+/).map((t) => PLAIN_LENGTH.exec(t)).filter((m) => m !== null).map((m) => Number(m[1]));
2133
+ if (lengths.length < 2) return null;
2134
+ const color = colorMatch ? parseComputedColor(colorMatch[0]) : null;
2135
+ return { offsetX: lengths[0], offsetY: lengths[1], blur: lengths[2] ?? 0, color: color ? colorCss(color) : "rgba(0, 0, 0, 0.25)" };
2136
+ }
2137
+ family(name, fallback) {
2138
+ return this.raw(name) || fallback;
2139
+ }
2140
+ };
2141
+ function dashList(raw, fallback) {
2142
+ if (raw === "") return fallback;
2143
+ const parts = raw.split(/[\s,]+/).map(Number);
2144
+ return parts.every((n) => Number.isFinite(n) && n >= 0) ? parts : fallback;
2145
+ }
2146
+ function prefersReducedMotion(scope) {
2147
+ const view = scope.ownerDocument.defaultView;
2148
+ return typeof view?.matchMedia === "function" && view.matchMedia("(prefers-reduced-motion: reduce)").matches;
2149
+ }
2150
+ function resolveCanvasTheme(scope) {
2151
+ const r = new ScopeReader(scope);
2152
+ try {
2153
+ const tones = {};
2154
+ for (const tone of DIAGRAM_TONES) {
2155
+ const c = r.color(toneVar(tone));
2156
+ tones[tone] = c ? colorCss(c) : "currentColor";
2157
+ }
2158
+ const ground = r.color("--surface-diagram");
2159
+ const text = {};
2160
+ const TEXT_FALLBACK = { xs: 12, sm: 14, base: 16, lg: 18, xl: 20, "2xl": 24 };
2161
+ for (const size of DIAGRAM_TEXT_SIZES) text[size] = r.length(`--text-${size}`, TEXT_FALLBACK[size]);
2162
+ const body = r.family("--font-family-body", r.family("--font-family", "system-ui, sans-serif"));
2163
+ return {
2164
+ ground: ground ? colorCss(ground) : "transparent",
2165
+ tones,
2166
+ series: SERIES_TONES.map((t) => tones[t]),
2167
+ strokes: {
2168
+ thin: r.length("--diagram-stroke-thin", 1),
2169
+ normal: r.length("--diagram-stroke-normal", 1.5),
2170
+ bold: r.length("--diagram-stroke-bold", 3)
2171
+ },
2172
+ lineCap: oneOf(r.raw("--diagram-line-cap"), ["butt", "round", "square"], "round", "--diagram-line-cap"),
2173
+ lineJoin: oneOf(r.raw("--diagram-line-join"), ["miter", "round", "bevel"], "round", "--diagram-line-join"),
2174
+ dash: dashList(r.raw("--diagram-dash"), [6, 4]),
2175
+ dot: dashList(r.raw("--diagram-dot"), [1, 4]),
2176
+ fillStyle: oneOf(r.raw("--diagram-fill-style"), ["solid", "tint", "outline", "hatch"], "tint", "--diagram-fill-style"),
2177
+ fillOpacity: r.number("--diagram-fill-opacity", 0.18),
2178
+ roughness: r.number("--diagram-roughness", 0),
2179
+ glow: r.number("--diagram-glow", 0),
2180
+ shadow: r.shadow("--diagram-shadow"),
2181
+ marker: oneOf(r.raw("--diagram-marker"), ["triangle", "open", "line", "dot"], "triangle", "--diagram-marker"),
2182
+ faces: {
2183
+ body,
2184
+ display: r.family("--font-family-display", body),
2185
+ mono: r.family("--font-family-mono", "ui-monospace, monospace")
2186
+ },
2187
+ label: {
2188
+ font: oneOf(r.raw("--diagram-label-font"), ["body", "display", "mono"], "body", "--diagram-label-font"),
2189
+ size: oneOf(r.raw("--diagram-label-size"), DIAGRAM_TEXT_SIZES, "sm", "--diagram-label-size"),
2190
+ weight: r.raw("--diagram-label-weight") || "500",
2191
+ uppercase: oneOf(r.raw("--diagram-label-case"), ["none", "uppercase"], "none", "--diagram-label-case") === "uppercase"
2192
+ },
2193
+ text,
2194
+ corner: r.length("--diagram-corner", 4),
2195
+ motion: {
2196
+ enabled: r.raw("--motion-enable") !== "off" && !prefersReducedMotion(scope),
2197
+ fastMs: r.durationMs("--duration-fast", 150),
2198
+ normalMs: r.durationMs("--duration-normal", 250),
2199
+ slowMs: r.durationMs("--duration-slow", 400),
2200
+ easing: r.raw("--easing-standard") || "ease"
2201
+ },
2202
+ scene: {
2203
+ roughness: r.number("--material-roughness", 0.6),
2204
+ metalness: r.number("--material-metalness", 0),
2205
+ flat: r.number("--material-flat", 0) >= 1,
2206
+ outline: r.number("--material-outline", 0),
2207
+ ambient: r.number("--light-ambient", 0.55),
2208
+ key: r.number("--light-key", 1),
2209
+ keyColor: (() => {
2210
+ const c = r.color("--light-key-color");
2211
+ return c ? colorCss(c) : "#ffffff";
2212
+ })(),
2213
+ fog: r.number("--scene-fog", 0)
2214
+ }
2215
+ };
2216
+ } finally {
2217
+ r.dispose();
2218
+ }
2219
+ }
2220
+ function withSeries(theme, series, scope) {
2221
+ if (!theme || !series || series.length === 0 || !scope) return theme;
2222
+ const colors = series.map((c, i) => markColor(theme, c, scope, SERIES_TONES[i % SERIES_TONES.length]));
2223
+ const tones = { ...theme.tones };
2224
+ SERIES_TONES.forEach((tone, i) => {
2225
+ tones[tone] = colors[i % colors.length];
2226
+ });
2227
+ return { ...theme, tones, series: SERIES_TONES.map((t) => tones[t]) };
2228
+ }
2229
+ function markColor(theme, value, scope, fallback) {
2230
+ if (value === void 0 || value === "") return theme.tones[fallback];
2231
+ if (isDiagramTone(value)) return theme.tones[value];
2232
+ if (value.startsWith("var(") || value.startsWith("color-mix(")) {
2233
+ const resolved = resolveThemeColor(value, scope);
2234
+ return resolved ? colorCss(resolved) : theme.tones[fallback];
2235
+ }
2236
+ return value;
2237
+ }
2238
+ function markStrokeWidth(theme, literal, role, fallback = "normal") {
2239
+ return literal ?? theme.strokes[role ?? fallback];
2240
+ }
2241
+ function labelFont(theme, roles, literalPx, literalFamily) {
2242
+ const px = literalPx ?? theme.text[roles.textSize ?? theme.label.size];
2243
+ const family = literalFamily ?? theme.faces[roles.font ?? theme.label.font];
2244
+ return { font: `${theme.label.weight} ${px}px ${family}`, px };
2245
+ }
2246
+ function labelText(theme, text, textCase = "theme") {
2247
+ return theme.label.uppercase && textCase === "theme" ? text.toUpperCase() : text;
2248
+ }
2249
+ function fillLabel(ctx, theme, text, x, y) {
2250
+ if (!text) return;
2251
+ ctx.save();
2252
+ ctx.strokeStyle = theme.ground;
2253
+ ctx.lineWidth = Math.max(2, theme.text.xs * 0.3);
2254
+ ctx.lineJoin = "round";
2255
+ ctx.strokeText(text, x, y);
2256
+ ctx.restore();
2257
+ ctx.fillText(text, x, y);
2258
+ }
2259
+ function outlineStroke(stroke, fill, style, fillTone) {
2260
+ return outlineCarriesFill(fill, style, fillTone) && fill !== void 0 ? fill : stroke;
2261
+ }
2262
+ function outlineCarriesFill(fill, style, fillTone) {
2263
+ return style === "outline" && fill !== void 0 && fillTone !== "fill";
2264
+ }
2265
+ function applyLineCharacter(ctx, theme, strokeColor) {
2266
+ ctx.lineCap = theme.lineCap;
2267
+ ctx.lineJoin = theme.lineJoin;
2268
+ if (theme.glow > 0) {
2269
+ ctx.shadowColor = strokeColor;
2270
+ ctx.shadowBlur = theme.glow;
2271
+ ctx.shadowOffsetX = 0;
2272
+ ctx.shadowOffsetY = 0;
2273
+ }
2274
+ }
2275
+ function markDash(theme, dash) {
2276
+ if (dash === "dashed") return theme.dash;
2277
+ if (dash === "dotted") return theme.dot;
2278
+ return [];
2279
+ }
2280
+ function wobble(x, y, k) {
2281
+ const s = Math.sin(x * 12.9898 + y * 78.233 + k * 37.719) * 43758.5453;
2282
+ return (s - Math.floor(s)) * 2 - 1;
2283
+ }
2284
+ function tracePolyline(ctx, theme, points, closed) {
2285
+ ctx.beginPath();
2286
+ if (points.length === 0) return;
2287
+ const amp = theme.roughness;
2288
+ const pts = closed ? [...points, points[0]] : [...points];
2289
+ ctx.moveTo(pts[0].x + amp * wobble(pts[0].x, pts[0].y, 0), pts[0].y + amp * wobble(pts[0].y, pts[0].x, 1));
2290
+ for (let i = 1; i < pts.length; i++) {
2291
+ const a = pts[i - 1];
2292
+ const b = pts[i];
2293
+ if (amp === 0) {
2294
+ ctx.lineTo(b.x, b.y);
2295
+ continue;
2296
+ }
2297
+ const steps = Math.max(1, Math.round(Math.hypot(b.x - a.x, b.y - a.y) / 24));
2298
+ for (let s = 1; s <= steps; s++) {
2299
+ const t = s / steps;
2300
+ const x = a.x + (b.x - a.x) * t;
2301
+ const y = a.y + (b.y - a.y) * t;
2302
+ ctx.lineTo(x + amp * wobble(x, y, 2), y + amp * wobble(y, x, 3));
2303
+ }
2304
+ }
2305
+ if (closed) ctx.closePath();
2306
+ }
2307
+ function arcPoints(cx, cy, rx, ry, startRad = 0, endRad = Math.PI * 2) {
2308
+ const steps = Math.max(12, Math.round(Math.abs(endRad - startRad) * Math.max(rx, ry) / 8));
2309
+ const out = [];
2310
+ for (let i = 0; i <= steps; i++) {
2311
+ const t = startRad + (endRad - startRad) * i / steps;
2312
+ out.push({ x: cx + rx * Math.cos(t), y: cy + ry * Math.sin(t) });
2313
+ }
2314
+ return out;
2315
+ }
2316
+ function fillMark(ctx, theme, color, style = theme.fillStyle) {
2317
+ if (style === "outline") return;
2318
+ ctx.save();
2319
+ ctx.shadowBlur = 0;
2320
+ ctx.shadowColor = "transparent";
2321
+ if (theme.shadow) {
2322
+ ctx.shadowColor = theme.shadow.color;
2323
+ ctx.shadowOffsetX = theme.shadow.offsetX;
2324
+ ctx.shadowOffsetY = theme.shadow.offsetY;
2325
+ ctx.shadowBlur = theme.shadow.blur;
2326
+ }
2327
+ if (style === "hatch") {
2328
+ ctx.clip();
2329
+ const span = ctx.canvas.width + ctx.canvas.height;
2330
+ ctx.strokeStyle = color;
2331
+ ctx.lineWidth = theme.strokes.thin;
2332
+ ctx.setLineDash([]);
2333
+ ctx.beginPath();
2334
+ for (let d = -span; d < span; d += 6) {
2335
+ ctx.moveTo(d, 0);
2336
+ ctx.lineTo(d + span, span);
2337
+ }
2338
+ ctx.stroke();
2339
+ } else {
2340
+ ctx.globalAlpha *= style === "tint" ? theme.fillOpacity : 1;
2341
+ ctx.fillStyle = color;
2342
+ ctx.fill();
2343
+ }
2344
+ ctx.restore();
2345
+ }
2346
+ function drawMarker(ctx, theme, x1, y1, x2, y2, color, width) {
2347
+ const size = Math.max(8, width * 4);
2348
+ const angle = Math.atan2(y2 - y1, x2 - x1);
2349
+ const left = { x: x2 - size * Math.cos(angle - Math.PI / 6), y: y2 - size * Math.sin(angle - Math.PI / 6) };
2350
+ const right = { x: x2 - size * Math.cos(angle + Math.PI / 6), y: y2 - size * Math.sin(angle + Math.PI / 6) };
2351
+ ctx.save();
2352
+ ctx.strokeStyle = color;
2353
+ ctx.fillStyle = color;
2354
+ ctx.lineWidth = width;
2355
+ ctx.setLineDash([]);
2356
+ switch (theme.marker) {
2357
+ case "triangle": {
2358
+ ctx.beginPath();
2359
+ ctx.moveTo(x2, y2);
2360
+ ctx.lineTo(left.x, left.y);
2361
+ ctx.lineTo(right.x, right.y);
2362
+ ctx.closePath();
2363
+ ctx.fill();
2364
+ break;
2365
+ }
2366
+ case "open":
2367
+ case "line": {
2368
+ ctx.beginPath();
2369
+ ctx.moveTo(left.x, left.y);
2370
+ ctx.lineTo(x2, y2);
2371
+ ctx.lineTo(right.x, right.y);
2372
+ if (theme.marker === "open") ctx.stroke();
2373
+ else {
2374
+ ctx.moveTo(x2 - size * 0.5 * Math.cos(angle + Math.PI / 2), y2 - size * 0.5 * Math.sin(angle + Math.PI / 2));
2375
+ ctx.lineTo(x2 + size * 0.5 * Math.cos(angle + Math.PI / 2), y2 + size * 0.5 * Math.sin(angle + Math.PI / 2));
2376
+ ctx.stroke();
2377
+ }
2378
+ break;
2379
+ }
2380
+ case "dot": {
2381
+ ctx.beginPath();
2382
+ ctx.arc(x2, y2, Math.max(2.5, width * 1.5), 0, Math.PI * 2);
2383
+ ctx.fill();
2384
+ break;
2385
+ }
2386
+ }
2387
+ ctx.restore();
2388
+ }
2389
+ function useCanvasTheme(scopeRef) {
2390
+ const { appliedTheme } = useTheme();
2391
+ const scopeKey = JSON.stringify(useThemeScope());
2392
+ const [state, setState] = useState({ theme: null, version: 0 });
2393
+ useLayoutEffect(() => {
2394
+ const scope = scopeRef.current;
2395
+ if (!scope) return;
2396
+ const theme = resolveCanvasTheme(scope);
2397
+ setState((prev) => ({ theme, version: prev.version + 1 }));
2398
+ }, [appliedTheme, scopeKey, scopeRef]);
2399
+ return state;
2400
+ }
2401
+
1904
2402
  // lib/drawable/hitTest.ts
1905
2403
  function shapeDrawnItem(n) {
1906
2404
  if (n.shape !== "rect") return { pos: n.position, id: n.id };
@@ -1999,4 +2497,4 @@ function rotatePoint(p, center, radians) {
1999
2497
  return { x: center.x + dx * cos - dy * sin, y: center.y + dx * sin + dy * cos };
2000
2498
  }
2001
2499
 
2002
- export { AVL_FONT, AVL_INK, AVL_STROKE, Box, CONFETTI_BURST_KEYFRAMES, CONNECTION_COLORS, DrawFxLayer, DrawGroup, DrawMesh, DrawShape, DrawSkinnedMesh, DrawableRegistryContext, EFFECT_CATEGORY_COLORS, HStack, OPERATOR_CATEGORY_COLORS, SPRITE_FALLBACK_FILL, SPRITE_FALLBACK_STROKE, STATE_COLORS, STRETCHED_ABOVE, STRETCHED_CONTROL, Stack, THEME_SERIES, VStack, applyMeshAnimation, applyShapeAnimation, asEffectOperator, atlasFailed, atlasUrlOf, avlBlend, avlSeries, avlTint, blit, buildHitIndex, clampSegments, collectDrawnItems, createConfettiParticles, effectCategoryOf, effectZoneOf, expandFxLayer, fxHash01, getAtlas, getImageStatus, getOrLoadImage, getStateRole, hitTestSprites, isAnimatedGroup, isAnimatedMesh, isAnimatedShape, isAtlasAsset, isSpriteSheetAtlas, isValidScenePos, paintShape, paintSkinnedMesh, parseApplicationLevel, parseOrbitalLevel, parseTraitLevel, parseTransitionLevel, polyhedronBounds, pressableProps, resolveAssetSource, resolveThemeColor, rowOpenControlProps, spriteAssetState, spriteRect, subRectFor, traitEventWires, traitLevelFromTrait, traitTransitionRenderUi, withPreviewPosition };
2500
+ export { AVL_FONT, AVL_INK, AVL_STROKE, Box, CONFETTI_BURST_KEYFRAMES, CONNECTION_COLORS, DrawFxLayer, DrawGroup, DrawMesh, DrawShape, DrawSkinnedMesh, DrawableRegistryContext, EFFECT_CATEGORY_COLORS, HStack, OPERATOR_CATEGORY_COLORS, SPRITE_FALLBACK_FILL, SPRITE_FALLBACK_STROKE, STATE_COLORS, STRETCHED_ABOVE, STRETCHED_CONTROL, Stack, THEME_SERIES, VStack, applyLineCharacter, applyMeshAnimation, applySceneMaterials, applyShapeAnimation, arcPoints, asEffectOperator, atlasFailed, atlasUrlOf, avlBlend, avlSeries, avlTint, blit, buildHitIndex, clampSegments, collectDrawnItems, createConfettiParticles, drawMarker, effectCategoryOf, effectZoneOf, expandFxLayer, fillLabel, fillMark, fxHash01, getAtlas, getImageStatus, getOrLoadImage, getStateRole, hitTestSprites, isAnimatedGroup, isAnimatedMesh, isAnimatedShape, isAtlasAsset, isSpriteSheetAtlas, isValidScenePos, labelFont, labelText, markColor, markDash, markStrokeWidth, outlineCarriesFill, outlineStroke, paintShape, paintSkinnedMesh, parseApplicationLevel, parseOrbitalLevel, parseTraitLevel, parseTransitionLevel, polyhedronBounds, pressableProps, resolveAssetSource, resolveDrawableColors, resolveThemeColor, rowOpenControlProps, spriteAssetState, spriteRect, subRectFor, tracePolyline, traitEventWires, traitLevelFromTrait, traitTransitionRenderUi, useCanvasTheme, withPreviewPosition, withSeries };