@almadar/ui 6.59.0 → 6.62.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 (91) hide show
  1. package/dist/BehaviorValueFrame-3ORZHPWQ.css +1252 -0
  2. package/dist/BehaviorValueFrame-QYFJEMN5.js +18 -0
  3. package/dist/TraitValueFrame-2WMYJOA5.css +1252 -0
  4. package/dist/TraitValueFrame-X6IL3UST.js +17 -0
  5. package/dist/Typography-KBATMU2V.js +5 -0
  6. package/dist/{UISlotRenderer-YNY7V2UJ.js → UISlotRenderer-NZBV5BUI.js} +12 -10
  7. package/dist/avl/index.cjs +32263 -28103
  8. package/dist/avl/index.d.ts +36 -13
  9. package/dist/avl/index.js +298 -6130
  10. package/dist/{avl-3d-context-BpBKZIbc.d.ts → avl-3d-context-Dxun3-ri.d.ts} +2 -0
  11. package/dist/{chunk-YYYHH5BA.js → chunk-7JRWELUC.js} +4 -6
  12. package/dist/{chunk-723MJUU3.js → chunk-CXQENFO2.js} +1 -1
  13. package/dist/chunk-D4NAA2JW.js +49 -0
  14. package/dist/{chunk-I5QOYW2Z.js → chunk-DXPCAQJU.js} +205 -2
  15. package/dist/{chunk-J755QADM.js → chunk-EDPUQ2ZJ.js} +327 -18
  16. package/dist/{chunk-4ZGXIW3B.js → chunk-ERDYADVZ.js} +1 -1
  17. package/dist/{chunk-7CVXM2KS.js → chunk-EZ5FSNOE.js} +2 -2
  18. package/dist/{chunk-E6MWYQVZ.js → chunk-G6EFTACU.js} +9713 -786
  19. package/dist/{chunk-MZIDOJMD.js → chunk-GVQOTA7T.js} +2 -1
  20. package/dist/{chunk-Q47ZN2DW.js → chunk-N23SVGTH.js} +83 -1
  21. package/dist/{chunk-KJGVLXEN.js → chunk-N4IJS5DD.js} +50 -116
  22. package/dist/{chunk-LZRW6GXG.js → chunk-QOV3TUAA.js} +2 -3
  23. package/dist/chunk-WBWXBA5H.js +434 -0
  24. package/dist/{chunk-V3FGTQUE.js → chunk-ZR45FGW3.js} +7 -1
  25. package/dist/{cn-DIql5232.d.ts → cn-CDIhHCUC.d.ts} +40 -16
  26. package/dist/components/index.cjs +14779 -4354
  27. package/dist/components/index.d.ts +200 -180
  28. package/dist/components/index.js +16 -17
  29. package/dist/context/index.cjs +9 -1
  30. package/dist/context/index.js +3 -1
  31. package/dist/hooks/index.cjs +78 -9
  32. package/dist/hooks/index.d.ts +43 -2
  33. package/dist/hooks/index.js +6 -7
  34. package/dist/lib/drawable/three/index.cjs +361 -27
  35. package/dist/lib/drawable/three/index.d.ts +2 -2
  36. package/dist/lib/drawable/three/index.js +28 -7
  37. package/dist/lib/index.cjs +117 -5
  38. package/dist/lib/index.d.ts +2 -2
  39. package/dist/lib/index.js +99 -6
  40. package/dist/locales/index.cjs +6 -9
  41. package/dist/locales/index.js +2 -2
  42. package/dist/providers/index.cjs +14137 -1311
  43. package/dist/providers/index.d.ts +36 -4
  44. package/dist/providers/index.js +37 -17
  45. package/dist/runtime/index.cjs +28769 -18640
  46. package/dist/runtime/index.d.ts +70 -3
  47. package/dist/runtime/index.js +15 -381
  48. package/dist/ssr/index.cjs +508 -134
  49. package/dist/ssr/index.d.cts +56 -4
  50. package/dist/ssr/index.d.ts +56 -4
  51. package/dist/ssr/index.js +446 -72
  52. package/dist/{verificationRegistry-B3dj1Zl8.d.ts → verificationRegistry-B5aGl7WF.d.ts} +2 -1
  53. package/locales/ar.json +2 -3
  54. package/locales/en.json +2 -3
  55. package/locales/sl.json +2 -3
  56. package/package.json +8 -8
  57. package/tailwind-preset.cjs +78 -8
  58. package/themes/_base.css +27 -0
  59. package/themes/_contract.md +6 -0
  60. package/themes/_fonts.css +4 -4
  61. package/themes/_foundation.css +11 -0
  62. package/themes/_presets.css +2 -0
  63. package/themes/almadar-website.css +10 -0
  64. package/themes/almadar.css +10 -0
  65. package/themes/atelier.css +10 -0
  66. package/themes/bauhaus.css +10 -0
  67. package/themes/bloomberg-dense.css +10 -0
  68. package/themes/clay.css +10 -0
  69. package/themes/corporate.css +10 -0
  70. package/themes/gazette.css +10 -0
  71. package/themes/glass.css +10 -0
  72. package/themes/kflow.css +5 -0
  73. package/themes/kiosk.css +10 -0
  74. package/themes/linear-clean.css +10 -0
  75. package/themes/material.css +10 -0
  76. package/themes/minimalist.css +10 -0
  77. package/themes/nata.css +304 -0
  78. package/themes/neon.css +10 -0
  79. package/themes/notion-editorial.css +10 -0
  80. package/themes/orb.css +10 -0
  81. package/themes/prism.css +10 -0
  82. package/themes/rawi.css +304 -0
  83. package/themes/retro.css +10 -0
  84. package/themes/risograph.css +10 -0
  85. package/themes/scandi.css +10 -0
  86. package/themes/solarpunk.css +10 -0
  87. package/themes/terminal.css +138 -128
  88. package/dist/Typography-LZTP72Y4.js +0 -5
  89. package/dist/chunk-D2E44ODB.js +0 -350
  90. package/dist/chunk-N7JIG57B.js +0 -138
  91. package/dist/chunk-QJIAJ6EH.js +0 -2256
package/dist/ssr/index.js CHANGED
@@ -1,8 +1,8 @@
1
- import * as React17 from 'react';
2
- import React17__default, { createContext, useCallback, useState, useRef, useEffect, useContext, useMemo, useSyncExternalStore, useLayoutEffect, useId } from 'react';
1
+ import * as React18 from 'react';
2
+ import React18__default, { createContext, useRef, useCallback, useState, useEffect, useContext, useMemo, useSyncExternalStore, useLayoutEffect, useId } from 'react';
3
3
  import { createLogger } from '@almadar/logger';
4
- import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
5
- import { LOADING_STATE_MARKER, isSystemUiEvent } from '@almadar/core';
4
+ import { jsxs, Fragment, jsx } from 'react/jsx-runtime';
5
+ import { actionTestId, LOADING_STATE_MARKER, isSystemUiEvent } from '@almadar/core';
6
6
  import * as LucideIcons2 from 'lucide-react';
7
7
  import { Loader2, X } from 'lucide-react';
8
8
  import 'react-router-dom';
@@ -2555,6 +2555,44 @@ var twMerge = extendTailwindMerge({
2555
2555
  function cn(...inputs) {
2556
2556
  return twMerge(clsx(inputs));
2557
2557
  }
2558
+
2559
+ // lib/bandShapes.ts
2560
+ var shape = (d) => `url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 1440 100' preserveAspectRatio='none'><path d='${d}'/></svg>")`;
2561
+ var BAND_SHAPES = {
2562
+ wave: shape("M0 60 C240 100 480 100 720 60 C960 20 1200 20 1440 60 V100 H0 Z"),
2563
+ arc: shape("M0 100 Q720 0 1440 100 Z"),
2564
+ tilt: shape("M0 100 L1440 0 V100 Z"),
2565
+ step: shape("M0 100 V75 H360 V50 H720 V25 H1080 V0 H1440 V100 Z"),
2566
+ scallop: shape("M0 100 V40 a60 40 0 0 1 120 0 a60 40 0 0 1 120 0 a60 40 0 0 1 120 0 a60 40 0 0 1 120 0 a60 40 0 0 1 120 0 a60 40 0 0 1 120 0 a60 40 0 0 1 120 0 a60 40 0 0 1 120 0 a60 40 0 0 1 120 0 a60 40 0 0 1 120 0 a60 40 0 0 1 120 0 a60 40 0 0 1 120 0 V100 Z")
2567
+ };
2568
+ var BAND_EDGE_HEIGHT = "clamp(24px, 6vw, 96px)";
2569
+ var BAND_ACCENT_FALLBACK = "linear-gradient(180deg, color-mix(in oklab, var(--color-primary) 12%, var(--color-background)), var(--color-background))";
2570
+ var BAND_EDGE_FILL = {
2571
+ background: "var(--surface-page-image, none), var(--color-background)",
2572
+ muted: "var(--color-muted)",
2573
+ surface: "var(--color-card)",
2574
+ gradient: `var(--surface-accent-image, ${BAND_ACCENT_FALLBACK}), var(--color-muted)`,
2575
+ inverse: "var(--color-foreground)"
2576
+ };
2577
+ function bandEdgeMask(edge) {
2578
+ return edge === "curve" ? "var(--surface-edge-mask, none)" : BAND_SHAPES[edge];
2579
+ }
2580
+ function bandEdgeHeight(edge) {
2581
+ return edge === "curve" ? `var(--surface-edge-height, ${BAND_EDGE_HEIGHT})` : BAND_EDGE_HEIGHT;
2582
+ }
2583
+ function bandEdgeLayerStyle(edge, side, flip, color) {
2584
+ const mask = bandEdgeMask(edge);
2585
+ const turn = side === "top" ? flip ? "scaleY(-1)" : "rotate(180deg)" : flip ? "scaleX(-1)" : void 0;
2586
+ const style = { height: bandEdgeHeight(edge), background: BAND_EDGE_FILL[color], maskImage: mask, WebkitMaskImage: mask, transform: turn };
2587
+ if (color === "background") {
2588
+ style.backgroundSize = "var(--surface-page-image-size, auto), auto";
2589
+ style.backgroundAttachment = "fixed";
2590
+ }
2591
+ return style;
2592
+ }
2593
+ function bandPadding(basePad, edge) {
2594
+ return edge === "none" ? void 0 : `calc(${basePad} + ${bandEdgeHeight(edge)})`;
2595
+ }
2558
2596
  createLogger("almadar:eventbus");
2559
2597
  createLogger("almadar:eventbus:subscribe");
2560
2598
  var EventBusContext = globalThis.__almadarUiEventBusContext ?? (globalThis.__almadarUiEventBusContext = createContext(null));
@@ -2759,7 +2797,237 @@ function pressableProps(onPress, options = {}) {
2759
2797
  };
2760
2798
  }
2761
2799
 
2762
- // components/core/atoms/Box.tsx
2800
+ // lib/domPassthrough.ts
2801
+ var GLOBAL_ATTRIBUTES = /* @__PURE__ */ new Set(["role", "id", "lang", "dir", "tabIndex"]);
2802
+ function domPassthrough(props) {
2803
+ const out = {};
2804
+ for (const [key, value] of Object.entries(props)) {
2805
+ if (key.startsWith("aria-") || key.startsWith("data-") || GLOBAL_ATTRIBUTES.has(key)) {
2806
+ if (typeof value === "string" || typeof value === "number" || typeof value === "boolean" || value === void 0) {
2807
+ out[key] = value;
2808
+ }
2809
+ }
2810
+ }
2811
+ return out;
2812
+ }
2813
+ var motionEnabledCache = null;
2814
+ function isMotionEnabled() {
2815
+ if (typeof document === "undefined") return true;
2816
+ if (motionEnabledCache !== null) return motionEnabledCache;
2817
+ const v = getComputedStyle(document.documentElement).getPropertyValue("--motion-enable").trim().toLowerCase();
2818
+ motionEnabledCache = v !== "off";
2819
+ return motionEnabledCache;
2820
+ }
2821
+
2822
+ // lib/motion-tokens.ts
2823
+ function cssTimeMs(value) {
2824
+ const v = value.trim();
2825
+ if (v.endsWith("ms")) return Number.parseFloat(v);
2826
+ if (v.endsWith("s")) return Number.parseFloat(v) * 1e3;
2827
+ return Number.NaN;
2828
+ }
2829
+ function tokenAt(el, name) {
2830
+ for (let at = el; at !== null; at = at.parentElement) {
2831
+ const value = getComputedStyle(at).getPropertyValue(name).trim();
2832
+ if (value !== "") return value;
2833
+ }
2834
+ return "";
2835
+ }
2836
+ function motionTiming(durationToken, easingToken, scope) {
2837
+ const duration = cssTimeMs(tokenAt(scope ?? document.documentElement, durationToken));
2838
+ const easing = tokenAt(scope ?? document.documentElement, easingToken);
2839
+ const reduced = typeof window.matchMedia === "function" && window.matchMedia("(prefers-reduced-motion: reduce)").matches;
2840
+ if (!isMotionEnabled() || reduced || !Number.isFinite(duration) || easing === "") return void 0;
2841
+ return { duration, easing };
2842
+ }
2843
+ function layoutScale(el) {
2844
+ const layoutWidth = el instanceof HTMLElement ? el.offsetWidth : 0;
2845
+ const screenWidth = el.getBoundingClientRect().width;
2846
+ return layoutWidth > 0 && screenWidth > 0 ? screenWidth / layoutWidth : 1;
2847
+ }
2848
+
2849
+ // lib/animate-changes.ts
2850
+ function ownMotion(el) {
2851
+ return el.closest("[data-item-move]") !== null || /\balmadar-enter-/.test(el.getAttribute("class") ?? "");
2852
+ }
2853
+ function boxesOf(el) {
2854
+ return getComputedStyle(el).display === "contents" ? boxedChildren(el) : [el];
2855
+ }
2856
+ function boxedChildren(el) {
2857
+ return [...el.children].flatMap(boxesOf);
2858
+ }
2859
+ var GHOST_STYLE = ["font", "letterSpacing", "lineHeight", "color", "textAlign", "whiteSpace", "textTransform"];
2860
+ function roll(el, oldText, timing) {
2861
+ const box = el.getBoundingClientRect();
2862
+ const scale2 = layoutScale(el);
2863
+ const computed = getComputedStyle(el);
2864
+ const holder = document.createElement("span");
2865
+ holder.setAttribute("aria-hidden", "true");
2866
+ Object.assign(holder.style, {
2867
+ position: "fixed",
2868
+ left: `${box.left}px`,
2869
+ top: `${box.top}px`,
2870
+ width: `${box.width / scale2}px`,
2871
+ height: `${box.height / scale2}px`,
2872
+ transform: scale2 === 1 ? "" : `scale(${scale2})`,
2873
+ transformOrigin: "top left",
2874
+ pointerEvents: "none",
2875
+ zIndex: "2147483647"
2876
+ });
2877
+ const ghost = document.createElement("span");
2878
+ ghost.setAttribute("data-change-ghost", "");
2879
+ ghost.setAttribute("aria-hidden", "true");
2880
+ ghost.textContent = oldText;
2881
+ for (const prop of GHOST_STYLE) ghost.style[prop] = computed[prop];
2882
+ Object.assign(ghost.style, { display: "block", width: "100%", height: "100%", overflow: "visible" });
2883
+ holder.appendChild(ghost);
2884
+ document.body.appendChild(holder);
2885
+ const out = ghost.animate(
2886
+ [{ opacity: 1, transform: "none" }, { opacity: 0, transform: "translateY(-40%)", offset: 0.5 }, { opacity: 0, transform: "translateY(-40%)" }],
2887
+ timing
2888
+ );
2889
+ if (out === void 0) holder.remove();
2890
+ else {
2891
+ out.addEventListener("finish", () => holder.remove());
2892
+ out.addEventListener("cancel", () => holder.remove());
2893
+ }
2894
+ el.animate(
2895
+ [{ opacity: 0, transform: "translateY(40%)" }, { opacity: 0, transform: "translateY(40%)", offset: 0.4 }, { opacity: 1, transform: "none" }],
2896
+ timing
2897
+ );
2898
+ }
2899
+ var textOnly = (el) => el instanceof HTMLElement && el.childNodes.length > 0 && [...el.childNodes].every((n) => n.nodeType === Node.TEXT_NODE);
2900
+ function settle(root, added, changed) {
2901
+ const timing = motionTiming("--duration-normal", "--easing-emphasized", root);
2902
+ if (timing === void 0) return;
2903
+ for (const el of added) {
2904
+ if (ownMotion(el) || el.parentElement !== null && [...added].some((other) => other !== el && other.contains(el))) continue;
2905
+ for (const box of boxesOf(el)) {
2906
+ if (ownMotion(box)) continue;
2907
+ box.animate([{ opacity: 0, transform: "translateY(6px)" }, { opacity: 1, transform: "none" }], timing);
2908
+ }
2909
+ }
2910
+ for (const [el, oldText] of changed) {
2911
+ if (ownMotion(el) || [...added].some((a) => a.contains(el))) continue;
2912
+ if (oldText !== void 0 && oldText !== el.textContent && textOnly(el)) roll(el, oldText, timing);
2913
+ else el.animate([{ opacity: 0.25 }, { opacity: 1 }], timing);
2914
+ }
2915
+ }
2916
+ function blocks(root) {
2917
+ const seen = /* @__PURE__ */ new Set();
2918
+ for (const wrapper of root.querySelectorAll("[data-pattern]")) {
2919
+ for (const box of boxesOf(wrapper)) if (!ownMotion(box)) seen.add(box);
2920
+ }
2921
+ return [...seen];
2922
+ }
2923
+ function glidePushed(root, places) {
2924
+ const timing = motionTiming("--duration-normal", "--easing-emphasized", root);
2925
+ const origin = root.getBoundingClientRect();
2926
+ const applied = /* @__PURE__ */ new Map();
2927
+ const present = /* @__PURE__ */ new Set();
2928
+ for (const el of blocks(root)) {
2929
+ present.add(el);
2930
+ if ((el.getAnimations?.() ?? []).length > 0) {
2931
+ places.delete(el);
2932
+ continue;
2933
+ }
2934
+ const box = el.getBoundingClientRect();
2935
+ const now = { x: box.left - origin.left, y: box.top - origin.top };
2936
+ const was = places.get(el);
2937
+ places.set(el, now);
2938
+ if (was === void 0 || timing === void 0) continue;
2939
+ let inherited = { x: 0, y: 0 };
2940
+ for (let up = el.parentElement; up !== null && up !== root; up = up.parentElement) {
2941
+ const a = applied.get(up);
2942
+ if (a !== void 0) {
2943
+ inherited = a;
2944
+ break;
2945
+ }
2946
+ }
2947
+ const dx = was.x - now.x - inherited.x;
2948
+ const dy = was.y - now.y - inherited.y;
2949
+ if (Math.abs(dx) < 0.5 && Math.abs(dy) < 0.5) {
2950
+ if (inherited.x !== 0 || inherited.y !== 0) applied.set(el, inherited);
2951
+ continue;
2952
+ }
2953
+ const scale2 = layoutScale(el);
2954
+ el.animate([{ transform: `translate(${dx / scale2}px, ${dy / scale2}px)` }, { transform: "none" }], { ...timing, composite: "add" });
2955
+ applied.set(el, { x: inherited.x + dx, y: inherited.y + dy });
2956
+ }
2957
+ for (const el of places.keys()) if (!present.has(el)) places.delete(el);
2958
+ }
2959
+ function easeHeight(root) {
2960
+ if (typeof ResizeObserver === "undefined") return () => void 0;
2961
+ let rest;
2962
+ let glide;
2963
+ const sizes = new ResizeObserver(() => {
2964
+ const scale2 = layoutScale(root);
2965
+ const shown = root.getBoundingClientRect().height / scale2;
2966
+ const gliding = glide !== void 0 && glide.playState === "running";
2967
+ glide?.cancel();
2968
+ glide = void 0;
2969
+ const height = root.getBoundingClientRect().height / scale2;
2970
+ const from = gliding ? shown : rest;
2971
+ rest = height;
2972
+ const timing = motionTiming("--duration-normal", "--easing-emphasized", root);
2973
+ if (from === void 0 || timing === void 0 || Math.abs(from - height) < 1) return;
2974
+ glide = root.animate(
2975
+ [{ height: `${from}px`, overflow: "clip" }, { height: `${height}px`, overflow: "clip" }],
2976
+ timing
2977
+ ) ?? void 0;
2978
+ });
2979
+ let watched = [];
2980
+ const watch = () => {
2981
+ const next = boxedChildren(root);
2982
+ if (next.length === watched.length && next.every((el, i) => el === watched[i])) return;
2983
+ watched = next;
2984
+ sizes.disconnect();
2985
+ for (const el of next) sizes.observe(el);
2986
+ };
2987
+ watch();
2988
+ const children = new MutationObserver(watch);
2989
+ children.observe(root, { childList: true, subtree: true });
2990
+ return () => {
2991
+ children.disconnect();
2992
+ sizes.disconnect();
2993
+ };
2994
+ }
2995
+ function useAnimateChanges(ref, enabled) {
2996
+ useEffect(() => {
2997
+ const root = ref.current;
2998
+ if (!enabled || root === null) return;
2999
+ return easeHeight(root);
3000
+ }, [ref, enabled]);
3001
+ useEffect(() => {
3002
+ const root = ref.current;
3003
+ if (!enabled || root === null || typeof MutationObserver === "undefined") return;
3004
+ const observer2 = new MutationObserver((records) => {
3005
+ const added = /* @__PURE__ */ new Set();
3006
+ const changed = /* @__PURE__ */ new Map();
3007
+ for (const record of records) {
3008
+ if (record.type === "childList") {
3009
+ for (const node of record.addedNodes) {
3010
+ if (node instanceof Element) added.add(node);
3011
+ else if (node.nodeType === Node.TEXT_NODE && node.parentElement !== null && changed.get(node.parentElement) === void 0) {
3012
+ const removed = [...record.removedNodes].filter((n) => n.nodeType === Node.TEXT_NODE);
3013
+ changed.set(node.parentElement, removed.length > 0 ? removed.map((n) => n.textContent ?? "").join("") : void 0);
3014
+ }
3015
+ }
3016
+ } else if (record.type === "characterData") {
3017
+ const el = record.target.parentElement;
3018
+ if (el === null || changed.get(el) !== void 0) continue;
3019
+ changed.set(el, [...el.childNodes].map((n) => n === record.target ? record.oldValue ?? "" : n.textContent ?? "").join(""));
3020
+ }
3021
+ }
3022
+ glidePushed(root, places);
3023
+ settle(root, added, changed);
3024
+ });
3025
+ const places = /* @__PURE__ */ new Map();
3026
+ glidePushed(root, places);
3027
+ observer2.observe(root, { subtree: true, childList: true, characterData: true, characterDataOldValue: true });
3028
+ return () => observer2.disconnect();
3029
+ }, [ref, enabled]);
3030
+ }
2763
3031
  var paddingStyles = {
2764
3032
  none: "p-0",
2765
3033
  xs: "p-1",
@@ -2824,7 +3092,18 @@ var bgStyles = {
2824
3092
  muted: "bg-muted text-foreground",
2825
3093
  accent: "bg-accent text-accent-foreground",
2826
3094
  surface: "bg-card",
2827
- overlay: "bg-card/80 backdrop-blur-sm"
3095
+ overlay: "bg-card/80 backdrop-blur-sm",
3096
+ gradient: "band-gradient",
3097
+ inverse: "band-inverse"
3098
+ };
3099
+ var paddingRem = {
3100
+ none: "0rem",
3101
+ xs: "0.25rem",
3102
+ sm: "0.5rem",
3103
+ md: "1rem",
3104
+ lg: "1.5rem",
3105
+ xl: "2rem",
3106
+ "2xl": "3rem"
2828
3107
  };
2829
3108
  var roundedStyles = {
2830
3109
  none: "rounded-none",
@@ -2862,7 +3141,7 @@ var positionStyles = {
2862
3141
  fixed: "fixed",
2863
3142
  sticky: "sticky"
2864
3143
  };
2865
- var Box = React17__default.forwardRef(
3144
+ var Box = React18__default.forwardRef(
2866
3145
  ({
2867
3146
  padding,
2868
3147
  paddingX,
@@ -2887,6 +3166,13 @@ var Box = React17__default.forwardRef(
2887
3166
  hoverEvent,
2888
3167
  tapReveal = true,
2889
3168
  maxWidth,
3169
+ edgeTop = "none",
3170
+ edgeBottom = "none",
3171
+ edgeColor = "background",
3172
+ edgeFlip = false,
3173
+ texture = false,
3174
+ animateChanges = false,
3175
+ backdrop,
2890
3176
  onClick,
2891
3177
  onMouseEnter,
2892
3178
  onMouseLeave,
@@ -2894,6 +3180,13 @@ var Box = React17__default.forwardRef(
2894
3180
  ...rest
2895
3181
  }, ref) => {
2896
3182
  const eventBus = useEventBus();
3183
+ const ownRef = useRef(null);
3184
+ useAnimateChanges(ownRef, animateChanges);
3185
+ const setRef = useCallback((node) => {
3186
+ ownRef.current = node;
3187
+ if (typeof ref === "function") ref(node);
3188
+ else if (ref !== null) ref.current = node;
3189
+ }, [ref]);
2897
3190
  const { override: themeOverride } = useThemeScope();
2898
3191
  const declaredTheme = rest["data-theme"];
2899
3192
  const dataTheme = declaredTheme !== void 0 && themeOverride ? themeOverride : declaredTheme;
@@ -2929,12 +3222,25 @@ var Box = React17__default.forwardRef(
2929
3222
  if (hoverEvent && tapReveal) triggerProps.onPointerDown(e);
2930
3223
  onPointerDown?.(e);
2931
3224
  }, [hoverEvent, tapReveal, triggerProps, onPointerDown]);
3225
+ const isBand = backdrop != null || texture || edgeTop !== "none" || edgeBottom !== "none";
3226
+ const padKey = paddingY ?? padding;
3227
+ const bandStyle = {};
3228
+ const padTop = padKey ? bandPadding(paddingRem[padKey], edgeTop) : void 0;
3229
+ const padBottom = padKey ? bandPadding(paddingRem[padKey], edgeBottom) : void 0;
3230
+ if (padTop) bandStyle.paddingTop = padTop;
3231
+ if (padBottom) bandStyle.paddingBottom = padBottom;
3232
+ const bandLayers = isBand ? /* @__PURE__ */ jsxs(Fragment, { children: [
3233
+ backdrop != null && /* @__PURE__ */ jsx(Box, { as: "span", "data-band-layer": "", "aria-hidden": true, className: "band-backdrop", children: backdrop }),
3234
+ texture && /* @__PURE__ */ jsx(Box, { as: "span", "data-band-layer": "", "aria-hidden": true, className: "band-texture" }),
3235
+ edgeTop !== "none" && /* @__PURE__ */ jsx(Box, { as: "span", "data-band-layer": "", "aria-hidden": true, className: "band-edge band-edge-top", style: bandEdgeLayerStyle(edgeTop, "top", edgeFlip, edgeColor) }),
3236
+ edgeBottom !== "none" && /* @__PURE__ */ jsx(Box, { as: "span", "data-band-layer": "", "aria-hidden": true, className: "band-edge band-edge-bottom", style: bandEdgeLayerStyle(edgeBottom, "bottom", edgeFlip, edgeColor) })
3237
+ ] }) : null;
2932
3238
  const isClickable = action || onClick;
2933
3239
  const actionControl = action && rest.role === void 0 && rest.tabIndex === void 0 ? pressableProps(handleClick) : {};
2934
- return React17__default.createElement(
3240
+ return React18__default.createElement(
2935
3241
  Component,
2936
3242
  {
2937
- ref,
3243
+ ref: setRef,
2938
3244
  className: cn(
2939
3245
  padding && paddingStyles[padding],
2940
3246
  paddingX && paddingXStyles[paddingX],
@@ -2952,6 +3258,7 @@ var Box = React17__default.forwardRef(
2952
3258
  overflow && overflowStyles[overflow],
2953
3259
  position && positionStyles[position],
2954
3260
  isClickable && "cursor-pointer",
3261
+ isBand && "band",
2955
3262
  className
2956
3263
  ),
2957
3264
  onClick: isClickable ? handleClick : void 0,
@@ -2959,29 +3266,19 @@ var Box = React17__default.forwardRef(
2959
3266
  onMouseEnter: hoverEvent || onMouseEnter ? handleMouseEnter : void 0,
2960
3267
  onMouseLeave: hoverEvent || onMouseLeave ? handleMouseLeave : void 0,
2961
3268
  onPointerDown: hoverEvent && tapReveal || onPointerDown ? handlePointerDown : void 0,
2962
- style: maxWidth ? { maxWidth, ...rest.style } : rest.style,
3269
+ style: maxWidth || isBand ? { ...maxWidth ? { maxWidth } : {}, ...bandStyle, ...rest.style } : rest.style,
2963
3270
  ...rest,
2964
- "data-theme": dataTheme
3271
+ "data-theme": dataTheme,
3272
+ "data-motion": animateChanges ? "presentation" : void 0
2965
3273
  },
2966
- children
3274
+ isBand ? /* @__PURE__ */ jsxs(Fragment, { children: [
3275
+ bandLayers,
3276
+ children
3277
+ ] }) : children
2967
3278
  );
2968
3279
  }
2969
3280
  );
2970
3281
  Box.displayName = "Box";
2971
-
2972
- // lib/domPassthrough.ts
2973
- var GLOBAL_ATTRIBUTES = /* @__PURE__ */ new Set(["role", "id", "lang", "dir", "tabIndex"]);
2974
- function domPassthrough(props) {
2975
- const out = {};
2976
- for (const [key, value] of Object.entries(props)) {
2977
- if (key.startsWith("aria-") || key.startsWith("data-") || GLOBAL_ATTRIBUTES.has(key)) {
2978
- if (typeof value === "string" || typeof value === "number" || typeof value === "boolean" || value === void 0) {
2979
- out[key] = value;
2980
- }
2981
- }
2982
- }
2983
- return out;
2984
- }
2985
3282
  var gapStyles = {
2986
3283
  none: "gap-0",
2987
3284
  xs: "gap-1",
@@ -3036,7 +3333,7 @@ var Stack = ({
3036
3333
  };
3037
3334
  const isHorizontal = direction === "horizontal";
3038
3335
  const directionClass = responsive && isHorizontal ? reverse ? "flex-col-reverse md:flex-row-reverse" : "flex-col md:flex-row" : isHorizontal ? reverse ? "flex-row-reverse" : "flex-row" : reverse ? "flex-col-reverse" : "flex-col";
3039
- return React17__default.createElement(
3336
+ return React18__default.createElement(
3040
3337
  Component,
3041
3338
  {
3042
3339
  ...domPassthrough(rest),
@@ -3198,7 +3495,6 @@ var en_default = {
3198
3495
  "aria.upvote": "Upvote",
3199
3496
  "aria.downvote": "Downvote",
3200
3497
  "aria.qrScanner": "QR scanner",
3201
- "aria.mockScanDev": "Mock scan (dev)",
3202
3498
  "aria.openMenu": "Open menu",
3203
3499
  "aria.closeMenu": "Close menu",
3204
3500
  "aria.openSidebar": "Open sidebar",
@@ -3396,7 +3692,6 @@ var en_default = {
3396
3692
  "qrScanner.pauseScanning": "Pause scanning",
3397
3693
  "qrScanner.switchToFrontCamera": "Switch to front camera",
3398
3694
  "qrScanner.switchToRearCamera": "Switch to rear camera",
3399
- "qrScanner.mockScan": "Mock Scan",
3400
3695
  "docSearch.placeholder": "Search documentation...",
3401
3696
  "stateMachine.loading": "Loading state machine\u2026",
3402
3697
  "stateMachine.noStateMachine": "No state machine to visualize",
@@ -4318,7 +4613,8 @@ var en_default = {
4318
4613
  "avl.stateInitial": "start",
4319
4614
  "avl.stateTerminal": "end",
4320
4615
  "avl.guardCaption": "The transition only fires when this check is true.",
4321
- "avl.effectsCaption": "What runs, in order, when the transition fires."
4616
+ "avl.effectsCaption": "What runs, in order, when the transition fires.",
4617
+ "aria.carousel": "carousel"
4322
4618
  };
4323
4619
 
4324
4620
  // lib/format.ts
@@ -4509,7 +4805,7 @@ var Typography = ({
4509
4805
  if (format !== void 0 && format !== "none" && (typeof body === "string" || typeof body === "number" || body instanceof Date)) {
4510
4806
  body = formatValue(body, format, fmt);
4511
4807
  }
4512
- return React17__default.createElement(
4808
+ return React18__default.createElement(
4513
4809
  Component,
4514
4810
  {
4515
4811
  ...domPassthrough(rest),
@@ -4721,7 +5017,7 @@ function resolveLucide(name) {
4721
5017
  }
4722
5018
  function makeLucideAdapter(name) {
4723
5019
  const LucideComp = resolveLucide(name);
4724
- const Adapter = React17__default.forwardRef((props, ref) => /* @__PURE__ */ jsx(
5020
+ const Adapter = React18__default.forwardRef((props, ref) => /* @__PURE__ */ jsx(
4725
5021
  LucideComp,
4726
5022
  {
4727
5023
  ref,
@@ -4809,9 +5105,9 @@ var Icon = ({
4809
5105
  const effectiveName = typeof icon === "string" && icon !== "" ? icon : name;
4810
5106
  const effectiveStrokeWidth = strokeWidth != null && strokeWidth > 0 ? strokeWidth : void 0;
4811
5107
  const family = useIconFamily();
4812
- const svgRef = React17__default.useRef(null);
5108
+ const svgRef = React18__default.useRef(null);
4813
5109
  const themeStroke = useThemeIconStrokeApplies(svgRef);
4814
- const RenderedComponent = React17__default.useMemo(() => {
5110
+ const RenderedComponent = React18__default.useMemo(() => {
4815
5111
  if (directIcon) return null;
4816
5112
  return effectiveName ? resolveIconForFamily(effectiveName) : null;
4817
5113
  }, [directIcon, effectiveName, family]);
@@ -4953,13 +5249,13 @@ function AtlasImage({
4953
5249
  "aria-hidden": ariaHidden,
4954
5250
  ...rest
4955
5251
  }) {
4956
- const [, bump] = React17.useReducer((x) => x + 1, 0);
4957
- const canvasRef = React17.useRef(null);
5252
+ const [, bump] = React18.useReducer((x) => x + 1, 0);
5253
+ const canvasRef = React18.useRef(null);
4958
5254
  const sliced = isAtlasAsset(asset);
4959
5255
  const atlas = sliced ? getAtlas(asset.atlas, bump) : void 0;
4960
5256
  const img = sliced && asset?.url ? getSheetImage(asset.url, bump) : null;
4961
5257
  const rect = sliced && atlas ? subRectFor(atlas, asset.sprite) : null;
4962
- React17.useEffect(() => {
5258
+ React18.useEffect(() => {
4963
5259
  const canvas = canvasRef.current;
4964
5260
  if (!canvas || !img || !rect) return;
4965
5261
  canvas.width = rect.sw;
@@ -5125,7 +5421,7 @@ function resolveIconProp(value, sizeClass) {
5125
5421
  const IconComp = value;
5126
5422
  return /* @__PURE__ */ jsx(IconComp, { className: sizeClass });
5127
5423
  }
5128
- if (React17__default.isValidElement(value)) {
5424
+ if (React18__default.isValidElement(value)) {
5129
5425
  return value;
5130
5426
  }
5131
5427
  if (typeof value === "object" && value !== null && isIconLike(value)) {
@@ -5134,7 +5430,7 @@ function resolveIconProp(value, sizeClass) {
5134
5430
  }
5135
5431
  return value;
5136
5432
  }
5137
- var Button = React17__default.forwardRef(
5433
+ var Button = React18__default.forwardRef(
5138
5434
  ({
5139
5435
  className,
5140
5436
  variant = "primary",
@@ -5161,7 +5457,7 @@ var Button = React17__default.forwardRef(
5161
5457
  const navStack = useNavStack();
5162
5458
  const { pending, activate } = usePendingAction();
5163
5459
  const busy = isLoading || pending;
5164
- const [focused, setFocused] = React17__default.useState(false);
5460
+ const [focused, setFocused] = React18__default.useState(false);
5165
5461
  const inert = Boolean(disabled) || busy;
5166
5462
  const emitAction = () => {
5167
5463
  if (!action) return;
@@ -5203,7 +5499,7 @@ var Button = React17__default.forwardRef(
5203
5499
  disabled && focused && "opacity-50 cursor-not-allowed",
5204
5500
  className
5205
5501
  );
5206
- const testId = dataTestId ?? (action ? `action-${action}` : void 0);
5502
+ const testId = dataTestId ?? (action ? actionTestId(action) : void 0);
5207
5503
  const content = /* @__PURE__ */ jsxs(Fragment, { children: [
5208
5504
  busy && /* @__PURE__ */ jsx("span", { className: "almadar-busy-indicator absolute inset-0 flex items-center justify-center", "aria-hidden": "true", children: /* @__PURE__ */ jsx(Loader2, { className: "h-icon-default w-icon-default animate-spin" }) }),
5209
5505
  /* @__PURE__ */ jsxs("span", { className: cn("inline-flex flex-1 min-w-0 items-center [justify-content:inherit] gap-2", busy && "almadar-busy-content"), children: [
@@ -5219,6 +5515,8 @@ var Button = React17__default.forwardRef(
5219
5515
  return;
5220
5516
  }
5221
5517
  emitAction();
5518
+ onClick?.(e);
5519
+ if (e.defaultPrevented) return;
5222
5520
  if (e.metaKey || e.ctrlKey || e.shiftKey || e.altKey || e.button !== 0) return;
5223
5521
  if (!href.startsWith("#") && isInertNavStack(navStack)) return;
5224
5522
  e.preventDefault();
@@ -5299,7 +5597,7 @@ var sizeStyles2 = {
5299
5597
  md: "px-2.5 py-1 text-sm",
5300
5598
  lg: "px-3 py-1.5 text-base"
5301
5599
  };
5302
- var Badge = React17__default.forwardRef(
5600
+ var Badge = React18__default.forwardRef(
5303
5601
  ({ className, variant = "default", size = "sm", amount, label, icon, iconAsset, children, onRemove, removeLabel, onClick, ...props }, ref) => {
5304
5602
  const { t } = useTranslate();
5305
5603
  const iconSizes = {
@@ -5363,12 +5661,12 @@ var Badge = React17__default.forwardRef(
5363
5661
  }
5364
5662
  );
5365
5663
  Badge.displayName = "Badge";
5366
- var SurfaceContext = React17__default.createContext(false);
5664
+ var SurfaceContext = React18__default.createContext(false);
5367
5665
  function SurfaceBoundary({ children }) {
5368
5666
  return /* @__PURE__ */ jsx(SurfaceContext.Provider, { value: true, children });
5369
5667
  }
5370
5668
  function useContentSurface(surface = "auto") {
5371
- const onSurface = React17__default.useContext(SurfaceContext);
5669
+ const onSurface = React18__default.useContext(SurfaceContext);
5372
5670
  const paints = surface === "auto" && !onSurface;
5373
5671
  return {
5374
5672
  className: paints ? "surface-content" : void 0,
@@ -5381,7 +5679,7 @@ var sizeStyles3 = {
5381
5679
  md: "h-6 w-6",
5382
5680
  lg: "h-8 w-8"
5383
5681
  };
5384
- var Spinner = React17__default.forwardRef(
5682
+ var Spinner = React18__default.forwardRef(
5385
5683
  ({ className, size = "md", overlay, ...props }, ref) => {
5386
5684
  const { t } = useTranslate();
5387
5685
  if (overlay) {
@@ -5466,7 +5764,7 @@ var lookStyles = {
5466
5764
  chip: "shadow-none rounded-pill border-[length:var(--border-width)] border-border",
5467
5765
  "tile-image-first": "p-0 overflow-hidden"
5468
5766
  };
5469
- var Card = React17__default.forwardRef(
5767
+ var Card = React18__default.forwardRef(
5470
5768
  ({
5471
5769
  className,
5472
5770
  variant = "bordered",
@@ -5516,9 +5814,9 @@ var Card = React17__default.forwardRef(
5516
5814
  }
5517
5815
  );
5518
5816
  Card.displayName = "Card";
5519
- var CardHeader = React17__default.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx("div", { ref, className: cn("mb-4", className), ...props }));
5817
+ var CardHeader = React18__default.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx("div", { ref, className: cn("mb-4", className), ...props }));
5520
5818
  CardHeader.displayName = "CardHeader";
5521
- var CardTitle = React17__default.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
5819
+ var CardTitle = React18__default.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
5522
5820
  "h3",
5523
5821
  {
5524
5822
  ref,
@@ -5531,11 +5829,11 @@ var CardTitle = React17__default.forwardRef(({ className, ...props }, ref) => /*
5531
5829
  }
5532
5830
  ));
5533
5831
  CardTitle.displayName = "CardTitle";
5534
- var CardContent = React17__default.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx("div", { ref, className: cn("", className), ...props }));
5832
+ var CardContent = React18__default.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx("div", { ref, className: cn("", className), ...props }));
5535
5833
  CardContent.displayName = "CardContent";
5536
5834
  var CardBody = CardContent;
5537
5835
  CardBody.displayName = "CardBody";
5538
- var CardFooter = React17__default.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
5836
+ var CardFooter = React18__default.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
5539
5837
  "div",
5540
5838
  {
5541
5839
  ref,
@@ -5632,7 +5930,7 @@ var Center = ({
5632
5930
  ...rest
5633
5931
  }) => {
5634
5932
  const mergedStyle = minHeight ? { minHeight, ...style } : style;
5635
- return React17__default.createElement(Component, {
5933
+ return React18__default.createElement(Component, {
5636
5934
  ...domPassthrough(rest),
5637
5935
  className: cn(
5638
5936
  inline ? "inline-flex" : "flex",
@@ -5739,8 +6037,8 @@ var Avatar = ({
5739
6037
  }) => {
5740
6038
  const eventBus = useEventBus();
5741
6039
  const { t } = useTranslate();
5742
- const [imgFailed, setImgFailed] = React17__default.useState(false);
5743
- React17__default.useEffect(() => {
6040
+ const [imgFailed, setImgFailed] = React18__default.useState(false);
6041
+ React18__default.useEffect(() => {
5744
6042
  setImgFailed(false);
5745
6043
  }, [src]);
5746
6044
  const initials = providedInitials ?? (name ? generateInitials(name) : void 0);
@@ -5858,6 +6156,13 @@ var roundedClass = {
5858
6156
  "2xl": "rounded-[calc(var(--radius-xl)*1.5)]",
5859
6157
  full: "rounded-full"
5860
6158
  };
6159
+ var positionClass = {
6160
+ center: "object-center",
6161
+ top: "object-top",
6162
+ bottom: "object-bottom",
6163
+ left: "object-left",
6164
+ right: "object-right"
6165
+ };
5861
6166
  var Image2 = ({
5862
6167
  src,
5863
6168
  alt,
@@ -5866,6 +6171,10 @@ var Image2 = ({
5866
6171
  rounded = "md",
5867
6172
  bordered = false,
5868
6173
  loading = "lazy",
6174
+ position = "center",
6175
+ srcSet,
6176
+ sizes,
6177
+ priority = false,
5869
6178
  className,
5870
6179
  ...rest
5871
6180
  }) => {
@@ -5874,14 +6183,18 @@ var Image2 = ({
5874
6183
  "img",
5875
6184
  {
5876
6185
  src,
6186
+ srcSet,
6187
+ sizes,
6188
+ fetchPriority: priority ? "high" : void 0,
5877
6189
  alt,
5878
6190
  ...domPassthrough(rest),
5879
6191
  role: alt === "" ? "presentation" : rest.role,
5880
- loading,
6192
+ loading: priority ? "eager" : loading,
5881
6193
  decoding: "async",
5882
6194
  className: cn(
5883
6195
  "block w-full h-auto max-w-full",
5884
6196
  fitClass[fit],
6197
+ positionClass[position],
5885
6198
  aspectClass[aspect],
5886
6199
  roundedClass[rounded],
5887
6200
  bordered && "border border-border",
@@ -6097,7 +6410,7 @@ var Container = ({
6097
6410
  ...rest
6098
6411
  }) => {
6099
6412
  const resolvedSize = maxWidth ?? size ?? "lg";
6100
- return React17__default.createElement(
6413
+ return React18__default.createElement(
6101
6414
  Component,
6102
6415
  {
6103
6416
  ...domPassthrough(rest),
@@ -6208,10 +6521,10 @@ function ListSkeleton({ rows = 5, className }) {
6208
6521
  ] }, i)) });
6209
6522
  }
6210
6523
  function GridSkeleton({ rows = 6, className }) {
6211
- return /* @__PURE__ */ jsx(SimpleGrid, { minChildWidth: "260px", gap: "md", className, children: Array.from({ length: rows }).map((_, i) => /* @__PURE__ */ jsx(CardSkeleton, {}, i)) });
6524
+ return /* @__PURE__ */ jsx(SimpleGrid, { minChildWidth: "256px", gap: "md", className, children: Array.from({ length: rows }).map((_, i) => /* @__PURE__ */ jsx(CardSkeleton, {}, i)) });
6212
6525
  }
6213
6526
  function StatsSkeleton({ columns = 4, className }) {
6214
- return /* @__PURE__ */ jsx(SimpleGrid, { minChildWidth: "180px", gap: "md", className, children: Array.from({ length: columns }).map((_, i) => /* @__PURE__ */ jsxs(VStack, { gap: "sm", className: "p-4 border border-border rounded-container", children: [
6527
+ return /* @__PURE__ */ jsx(SimpleGrid, { minChildWidth: "176px", gap: "md", className, children: Array.from({ length: columns }).map((_, i) => /* @__PURE__ */ jsxs(VStack, { gap: "sm", className: "p-4 border border-border rounded-container", children: [
6215
6528
  /* @__PURE__ */ jsx(SkeletonLine, { className: "w-1/2 h-3" }),
6216
6529
  /* @__PURE__ */ jsx(SkeletonBlock, { className: "h-7 w-2/3" })
6217
6530
  ] }, i)) });
@@ -6233,7 +6546,7 @@ function DetailSkeleton({ rows = 6, className }) {
6233
6546
  /* @__PURE__ */ jsx(SkeletonBlock, { className: "h-20 flex-1" }),
6234
6547
  /* @__PURE__ */ jsx(SkeletonBlock, { className: "h-20 flex-1" })
6235
6548
  ] }),
6236
- /* @__PURE__ */ jsx(SimpleGrid, { minChildWidth: "200px", maxCols: 3, gap: "md", children: Array.from({ length: rows }).map((_, i) => /* @__PURE__ */ jsxs(VStack, { gap: "xs", children: [
6549
+ /* @__PURE__ */ jsx(SimpleGrid, { minChildWidth: "192px", maxCols: 3, gap: "md", children: Array.from({ length: rows }).map((_, i) => /* @__PURE__ */ jsxs(VStack, { gap: "xs", children: [
6237
6550
  /* @__PURE__ */ jsx(SkeletonLine, { className: "w-1/3 h-3" }),
6238
6551
  /* @__PURE__ */ jsx(SkeletonBlock, { className: "h-5 w-2/3" })
6239
6552
  ] }, i)) }),
@@ -6250,8 +6563,8 @@ function Skeleton({
6250
6563
  ...rest
6251
6564
  }) {
6252
6565
  const { t } = useTranslate();
6253
- const shape = spec !== void 0 ? shapeOfSpec(spec) : { variant, rows, columns, fields };
6254
- if (shape === null) return null;
6566
+ const shape2 = spec !== void 0 ? shapeOfSpec(spec) : { variant, rows, columns, fields };
6567
+ if (shape2 === null) return null;
6255
6568
  return /* @__PURE__ */ jsx(
6256
6569
  Box,
6257
6570
  {
@@ -6259,10 +6572,10 @@ function Skeleton({
6259
6572
  role: "status",
6260
6573
  "aria-busy": "true",
6261
6574
  "aria-label": rest["aria-label"] ?? t("common.loading"),
6262
- "data-skeleton": shape.variant,
6575
+ "data-skeleton": shape2.variant,
6263
6576
  ...{ [LOADING_STATE_MARKER]: "" },
6264
6577
  className: "w-full",
6265
- children: renderVariant(shape.variant, shape.rows, shape.columns, shape.fields, className)
6578
+ children: renderVariant(shape2.variant, shape2.rows, shape2.columns, shape2.fields, className)
6266
6579
  }
6267
6580
  );
6268
6581
  }
@@ -6609,6 +6922,35 @@ var AnimatedCounter = ({
6609
6922
  ] });
6610
6923
  };
6611
6924
  AnimatedCounter.displayName = "AnimatedCounter";
6925
+ function useMediaQuery(query) {
6926
+ const subscribe = useCallback(
6927
+ (onChange) => {
6928
+ if (!hasMatchMedia()) return () => void 0;
6929
+ const mql = window.matchMedia(query);
6930
+ mql.addEventListener("change", onChange);
6931
+ return () => mql.removeEventListener("change", onChange);
6932
+ },
6933
+ [query]
6934
+ );
6935
+ return useSyncExternalStore(
6936
+ subscribe,
6937
+ () => hasMatchMedia() && window.matchMedia(query).matches,
6938
+ () => false
6939
+ );
6940
+ }
6941
+ function hasMatchMedia() {
6942
+ return typeof window !== "undefined" && typeof window.matchMedia === "function";
6943
+ }
6944
+
6945
+ // hooks/usePrefersReducedMotion.ts
6946
+ function usePrefersReducedMotion() {
6947
+ return useMediaQuery("(prefers-reduced-motion: reduce)");
6948
+ }
6949
+ var revealLog = createLogger("almadar:ui:animated-reveal");
6950
+ function revealThresholds(threshold) {
6951
+ const steps = Array.from({ length: 20 }, (_, i) => i * threshold / 20);
6952
+ return [...steps, threshold];
6953
+ }
6612
6954
  var initialStyles = {
6613
6955
  "fade-up": { opacity: 0, transform: "translateY(24px)" },
6614
6956
  "fade-down": { opacity: 0, transform: "translateY(-24px)" },
@@ -6629,7 +6971,7 @@ var animatedStyles = {
6629
6971
  "scale-up": { opacity: 1, transform: "scale(1) translateY(0)" },
6630
6972
  "none": {}
6631
6973
  };
6632
- var AnimatedReveal = React17__default.forwardRef(
6974
+ var AnimatedReveal = React18__default.forwardRef(
6633
6975
  ({
6634
6976
  trigger = "scroll",
6635
6977
  animation = "fade-up",
@@ -6637,6 +6979,9 @@ var AnimatedReveal = React17__default.forwardRef(
6637
6979
  delay = 0,
6638
6980
  threshold = 0.15,
6639
6981
  once = true,
6982
+ revealEvent,
6983
+ enterEvent,
6984
+ leaveEvent,
6640
6985
  animate: manualAnimate,
6641
6986
  easing = "cubic-bezier(0.16, 1, 0.3, 1)",
6642
6987
  children,
@@ -6645,8 +6990,12 @@ var AnimatedReveal = React17__default.forwardRef(
6645
6990
  ...props
6646
6991
  }, forwardedRef) => {
6647
6992
  const [isAnimated, setIsAnimated] = useState(false);
6993
+ const reducedMotion = usePrefersReducedMotion();
6994
+ const eventBus = useEventBus();
6995
+ const revealEmitted = useRef(false);
6648
6996
  const internalRef = useRef(null);
6649
6997
  const hasAnimated = useRef(false);
6998
+ const inView = useRef(false);
6650
6999
  const setRef = useCallback(
6651
7000
  (node) => {
6652
7001
  internalRef.current = node;
@@ -6661,19 +7010,42 @@ var AnimatedReveal = React17__default.forwardRef(
6661
7010
  if (!el) return;
6662
7011
  const observer2 = new IntersectionObserver(
6663
7012
  ([entry]) => {
6664
- if (entry.isIntersecting) {
7013
+ if (entry.isIntersecting !== inView.current) {
7014
+ const event = entry.isIntersecting ? enterEvent : leaveEvent;
7015
+ inView.current = entry.isIntersecting;
7016
+ if (event) eventBus.emit(`UI:${event}`, {});
7017
+ }
7018
+ const seenEnough = entry.isIntersecting && (entry.intersectionRatio >= threshold || entry.rootBounds !== null && entry.intersectionRect.height >= threshold * entry.rootBounds.height);
7019
+ if (seenEnough) {
7020
+ if (revealEvent && !reducedMotion && !revealEmitted.current) {
7021
+ revealEmitted.current = true;
7022
+ revealLog.debug("reveal event", { event: revealEvent });
7023
+ eventBus.emit(`UI:${revealEvent}`, {});
7024
+ }
6665
7025
  if (once && hasAnimated.current) return;
6666
7026
  hasAnimated.current = true;
6667
7027
  setIsAnimated(true);
6668
- } else if (!once) {
7028
+ } else if (!entry.isIntersecting && !once) {
6669
7029
  setIsAnimated(false);
6670
7030
  }
6671
7031
  },
6672
- { threshold }
7032
+ { threshold: revealThresholds(threshold) }
7033
+ );
7034
+ observer2.observe(el);
7035
+ return () => observer2.disconnect();
7036
+ }, [trigger, threshold, once, revealEvent, enterEvent, leaveEvent, reducedMotion, eventBus]);
7037
+ useEffect(() => {
7038
+ const el = internalRef.current;
7039
+ if (!el || typeof IntersectionObserver === "undefined") return;
7040
+ const observer2 = new IntersectionObserver(
7041
+ ([entry]) => {
7042
+ el.dataset.onScreen = entry.isIntersecting ? "true" : "false";
7043
+ },
7044
+ { rootMargin: "200px" }
6673
7045
  );
6674
7046
  observer2.observe(el);
6675
7047
  return () => observer2.disconnect();
6676
- }, [trigger, threshold, once]);
7048
+ }, []);
6677
7049
  const handleMouseEnter = trigger === "hover" ? () => setIsAnimated(true) : void 0;
6678
7050
  const handleMouseLeave = trigger === "hover" ? () => {
6679
7051
  if (!once || !hasAnimated.current) {
@@ -6686,17 +7058,19 @@ var AnimatedReveal = React17__default.forwardRef(
6686
7058
  setIsAnimated(manualAnimate);
6687
7059
  }
6688
7060
  }, [trigger, manualAnimate]);
6689
- const active = isAnimated;
7061
+ const active = isAnimated || reducedMotion;
6690
7062
  const currentStyle = active ? animatedStyles[animation] : initialStyles[animation];
6691
7063
  return /* @__PURE__ */ jsx(
6692
7064
  "div",
6693
7065
  {
6694
7066
  ref: setRef,
6695
- className: cn("will-change-[opacity,transform]", className),
7067
+ className: cn(className),
6696
7068
  style: {
6697
7069
  ...currentStyle,
7070
+ // A revealed band is page-sized: keeping the layer hint after the reveal holds a huge GPU layer.
7071
+ willChange: active ? "auto" : "opacity, transform",
6698
7072
  transitionProperty: "opacity, transform",
6699
- transitionDuration: `${duration}ms`,
7073
+ transitionDuration: reducedMotion ? "0ms" : `${duration}ms`,
6700
7074
  transitionDelay: `${delay}ms`,
6701
7075
  transitionTimingFunction: easing,
6702
7076
  ...style
@@ -6782,7 +7156,7 @@ function applyMorphAnimation(container, animate, duration, delay, easing) {
6782
7156
  el.style.opacity = animate ? "1" : "0";
6783
7157
  });
6784
7158
  }
6785
- var AnimatedGraphic = React17__default.forwardRef(
7159
+ var AnimatedGraphic = React18__default.forwardRef(
6786
7160
  ({
6787
7161
  src,
6788
7162
  svgContent,
@@ -6805,7 +7179,7 @@ var AnimatedGraphic = React17__default.forwardRef(
6805
7179
  const fetchedSvg = useFetchedSvg(svgContent ? void 0 : src);
6806
7180
  const resolvedSvg = svgContent ?? fetchedSvg;
6807
7181
  const prevAnimateRef = useRef(animate);
6808
- const setRef = React17__default.useCallback(
7182
+ const setRef = React18__default.useCallback(
6809
7183
  (node) => {
6810
7184
  containerRef.current = node;
6811
7185
  if (typeof ref === "function") ref(node);