@almadar/ui 5.76.6 → 5.77.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.
package/dist/avl/index.js CHANGED
@@ -7,7 +7,7 @@ import ELK from 'elkjs/lib/elk.bundled.js';
7
7
  import { MarkerType, useReactFlow, Handle, Position, getBezierPath, EdgeLabelRenderer, useNodeId, ReactFlowProvider, BaseEdge, useNodesState, useEdgesState, ReactFlow, Controls, Background, BackgroundVariant } from '@xyflow/react';
8
8
  import { useTranslate } from '@almadar/ui/hooks';
9
9
  import * as LucideIcons2 from 'lucide-react';
10
- import { Loader2, X, Code, FileText, WrapText, Check, Copy, Lightbulb, CheckCircle, List, Printer, ChevronRight, ChevronLeft, GitBranch, Pencil, Eye, Plus, ArrowRight, Trash, RotateCcw, Play, Terminal, XCircle, AlertTriangle, Trash2, Link2, ZoomOut, ZoomIn, Download, Menu as Menu$1, Package, Calendar, MoreHorizontal, Image as Image$1, Upload, ArrowLeft, HelpCircle, PauseCircle, Search, Type, Heading1, Heading2, Heading3, ListOrdered, Quote, Minus, Eraser, TrendingUp, TrendingDown, AlertCircle, Circle, Clock, CheckCircle2, Bug, Send, ChevronUp, ChevronDown, Wrench, Tag, User, DollarSign } from 'lucide-react';
10
+ import { Loader2, X, Code, FileText, WrapText, Check, Copy, Lightbulb, CheckCircle, List, Printer, ChevronRight, ChevronLeft, GitBranch, Pencil, Eye, Plus, ArrowRight, Trash, RotateCcw, Play, Terminal, XCircle, AlertTriangle, Trash2, Link2, ZoomOut, ZoomIn, Download, ChevronDown, Menu as Menu$1, Package, Calendar, MoreHorizontal, Image as Image$1, Upload, ArrowLeft, HelpCircle, PauseCircle, Search, Type, Heading1, Heading2, Heading3, ListOrdered, Quote, Minus, Eraser, TrendingUp, TrendingDown, AlertCircle, Circle, Clock, CheckCircle2, Bug, Send, ChevronUp, Wrench, Tag, User, DollarSign } from 'lucide-react';
11
11
  import { createPortal } from 'react-dom';
12
12
  import { UISlotProvider, useUISlots, useTheme } from '@almadar/ui/context';
13
13
  import { evaluateGuard, evaluate, createMinimalContext } from '@almadar/evaluator';
@@ -8509,7 +8509,11 @@ var init_Switch = __esm({
8509
8509
  disabled,
8510
8510
  onClick: handleClick,
8511
8511
  className: cn(
8512
- "relative inline-flex h-6 w-11 shrink-0 cursor-pointer items-center rounded-full border-2 border-transparent transition-colors",
8512
+ // Fixed rem sizes instead of spacing tokens: themes like atelier
8513
+ // redefine --space-11 to 68px, which makes w-11 enormous and leaves
8514
+ // the thumb stuck near the left edge. The switch geometry must stay
8515
+ // proportional regardless of a theme's density scale.
8516
+ "relative inline-flex h-[1.5rem] w-[2.75rem] shrink-0 cursor-pointer items-center rounded-full border-2 border-transparent transition-colors",
8513
8517
  "focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background",
8514
8518
  isChecked ? "bg-primary" : "bg-muted",
8515
8519
  disabled && "cursor-not-allowed opacity-50"
@@ -8518,8 +8522,8 @@ var init_Switch = __esm({
8518
8522
  "span",
8519
8523
  {
8520
8524
  className: cn(
8521
- "pointer-events-none block h-5 w-5 rounded-full bg-background shadow-lg ring-0 transition-transform",
8522
- isChecked ? "translate-x-5" : "translate-x-0"
8525
+ "pointer-events-none block h-[1.25rem] w-[1.25rem] rounded-full bg-background shadow-lg ring-0 transition-transform",
8526
+ isChecked ? "translate-x-[1.25rem]" : "translate-x-0"
8523
8527
  )
8524
8528
  }
8525
8529
  )
@@ -15858,318 +15862,14 @@ var init_useCanvasEffects = __esm({
15858
15862
  "use client";
15859
15863
  }
15860
15864
  });
15861
- function pickPath(entry) {
15862
- if (Array.isArray(entry.path)) {
15863
- return entry.path[Math.floor(Math.random() * entry.path.length)];
15864
- }
15865
- return entry.path;
15866
- }
15867
- function useGameAudio({
15868
- manifest,
15869
- baseUrl = "",
15870
- initialMuted = false,
15871
- initialVolume = 1
15872
- }) {
15873
- const [muted, setMutedState] = useState(initialMuted);
15874
- const [masterVolume, setMasterVolumeState] = useState(initialVolume);
15875
- const mutedRef = useRef(muted);
15876
- const volumeRef = useRef(masterVolume);
15877
- const manifestRef = useRef(manifest);
15878
- mutedRef.current = muted;
15879
- volumeRef.current = masterVolume;
15880
- manifestRef.current = manifest;
15881
- const poolsRef = useRef(/* @__PURE__ */ new Map());
15882
- const getOrCreateElement = useCallback((key) => {
15883
- const entry = manifestRef.current[key];
15884
- if (!entry) return null;
15885
- let pool = poolsRef.current.get(key);
15886
- if (!pool) {
15887
- pool = [];
15888
- poolsRef.current.set(key, pool);
15889
- }
15890
- const maxSize = entry.poolSize ?? 1;
15891
- for (const audio of pool) {
15892
- if (audio.paused && (audio.ended || audio.currentTime === 0)) {
15893
- return audio;
15894
- }
15895
- }
15896
- if (pool.length < maxSize) {
15897
- const src = baseUrl + pickPath(entry);
15898
- const audio = new Audio(src);
15899
- audio.loop = entry.loop ?? false;
15900
- pool.push(audio);
15901
- return audio;
15902
- }
15903
- if (!entry.loop) {
15904
- let oldest = pool[0];
15905
- for (const audio of pool) {
15906
- if (audio.currentTime > oldest.currentTime) {
15907
- oldest = audio;
15908
- }
15909
- }
15910
- oldest.pause();
15911
- oldest.currentTime = 0;
15912
- return oldest;
15913
- }
15914
- return null;
15915
- }, [baseUrl]);
15916
- const play = useCallback((key) => {
15917
- if (mutedRef.current) return;
15918
- const entry = manifestRef.current[key];
15919
- if (!entry) return;
15920
- const audio = getOrCreateElement(key);
15921
- if (!audio) return;
15922
- audio.volume = Math.min(1, (entry.volume ?? 1) * volumeRef.current);
15923
- if (!entry.loop) {
15924
- audio.currentTime = 0;
15925
- }
15926
- const promise = audio.play();
15927
- if (promise) {
15928
- promise.catch(() => {
15929
- });
15930
- }
15931
- }, [getOrCreateElement]);
15932
- const stop = useCallback((key) => {
15933
- const pool = poolsRef.current.get(key);
15934
- if (!pool) return;
15935
- for (const audio of pool) {
15936
- audio.pause();
15937
- audio.currentTime = 0;
15938
- }
15939
- }, []);
15940
- const currentMusicKeyRef = useRef(null);
15941
- const currentMusicElRef = useRef(null);
15942
- const musicFadeRef = useRef(null);
15943
- const pendingMusicKeyRef = useRef(null);
15944
- const clearMusicFade = useCallback(() => {
15945
- if (musicFadeRef.current) {
15946
- clearInterval(musicFadeRef.current);
15947
- musicFadeRef.current = null;
15948
- }
15949
- }, []);
15950
- const playMusic = useCallback((key) => {
15951
- if (key === currentMusicKeyRef.current) return;
15952
- pendingMusicKeyRef.current = key;
15953
- const entry = manifestRef.current[key];
15954
- if (!entry) return;
15955
- const fadeDurationMs = entry.crossfadeDurationMs ?? 1500;
15956
- const stepMs = 50;
15957
- const totalSteps = Math.max(1, fadeDurationMs / stepMs);
15958
- const targetVolume = Math.min(1, (entry.volume ?? 1) * volumeRef.current);
15959
- clearMusicFade();
15960
- const src = baseUrl + (Array.isArray(entry.path) ? entry.path[0] : entry.path);
15961
- const incoming = new Audio(src);
15962
- incoming.loop = true;
15963
- incoming.volume = 0;
15964
- const outgoing = currentMusicElRef.current;
15965
- const outgoingStartVol = outgoing?.volume ?? 0;
15966
- currentMusicKeyRef.current = key;
15967
- currentMusicElRef.current = incoming;
15968
- if (!mutedRef.current) {
15969
- incoming.play().catch(() => {
15970
- currentMusicKeyRef.current = null;
15971
- currentMusicElRef.current = outgoing;
15972
- });
15973
- }
15974
- let step = 0;
15975
- musicFadeRef.current = setInterval(() => {
15976
- step++;
15977
- const progress = Math.min(step / totalSteps, 1);
15978
- incoming.volume = Math.min(1, targetVolume * progress);
15979
- if (outgoing) {
15980
- outgoing.volume = Math.max(0, outgoingStartVol * (1 - progress));
15981
- }
15982
- if (progress >= 1) {
15983
- clearMusicFade();
15984
- if (outgoing) {
15985
- outgoing.pause();
15986
- outgoing.src = "";
15987
- }
15988
- }
15989
- }, stepMs);
15990
- }, [baseUrl, clearMusicFade]);
15991
- const stopMusic = useCallback((fadeDurationMs = 1e3) => {
15992
- const outgoing = currentMusicElRef.current;
15993
- if (!outgoing) return;
15994
- currentMusicKeyRef.current = null;
15995
- currentMusicElRef.current = null;
15996
- pendingMusicKeyRef.current = null;
15997
- clearMusicFade();
15998
- const startVolume = outgoing.volume;
15999
- const stepMs = 50;
16000
- const totalSteps = Math.max(1, fadeDurationMs / stepMs);
16001
- let step = 0;
16002
- musicFadeRef.current = setInterval(() => {
16003
- step++;
16004
- const progress = step / totalSteps;
16005
- outgoing.volume = Math.max(0, startVolume * (1 - progress));
16006
- if (progress >= 1) {
16007
- clearMusicFade();
16008
- outgoing.pause();
16009
- outgoing.src = "";
16010
- }
16011
- }, stepMs);
16012
- }, [clearMusicFade]);
16013
- const stopAll = useCallback(() => {
16014
- for (const pool of poolsRef.current.values()) {
16015
- for (const audio of pool) {
16016
- audio.pause();
16017
- audio.currentTime = 0;
16018
- }
16019
- }
16020
- stopMusic(0);
16021
- }, [stopMusic]);
16022
- const setMuted = useCallback((value) => {
16023
- setMutedState(value);
16024
- if (value) {
16025
- for (const [key, pool] of poolsRef.current.entries()) {
16026
- if (manifestRef.current[key]?.loop) {
16027
- for (const audio of pool) {
16028
- if (!audio.paused) audio.pause();
16029
- }
16030
- }
16031
- }
16032
- currentMusicElRef.current?.pause();
16033
- } else {
16034
- for (const [key, pool] of poolsRef.current.entries()) {
16035
- const entry = manifestRef.current[key];
16036
- if (entry?.loop && entry?.autostart) {
16037
- for (const audio of pool) {
16038
- if (audio.paused) audio.play().catch(() => {
16039
- });
16040
- }
16041
- }
16042
- }
16043
- const musicEl = currentMusicElRef.current;
16044
- if (musicEl) {
16045
- musicEl.play().catch(() => {
16046
- });
16047
- }
16048
- }
16049
- }, []);
16050
- const setMasterVolume = useCallback((volume) => {
16051
- const clamped = Math.max(0, Math.min(1, volume));
16052
- setMasterVolumeState(clamped);
16053
- for (const [key, pool] of poolsRef.current.entries()) {
16054
- const entryVol = manifestRef.current[key]?.volume ?? 1;
16055
- for (const audio of pool) {
16056
- audio.volume = Math.min(1, entryVol * clamped);
16057
- }
16058
- }
16059
- if (!musicFadeRef.current && currentMusicElRef.current) {
16060
- const key = currentMusicKeyRef.current;
16061
- const entryVol = key ? manifestRef.current[key]?.volume ?? 1 : 1;
16062
- currentMusicElRef.current.volume = Math.min(1, entryVol * clamped);
16063
- }
16064
- }, []);
16065
- const unlockedRef = useRef(false);
16066
- useEffect(() => {
16067
- const autoKeys = Object.keys(manifest).filter((k) => manifest[k].autostart);
16068
- const hasPendingMusic = () => pendingMusicKeyRef.current !== null;
16069
- const hasAutoStart = autoKeys.length > 0;
16070
- if (!hasAutoStart && !hasPendingMusic()) return;
16071
- const unlock = () => {
16072
- if (unlockedRef.current) return;
16073
- unlockedRef.current = true;
16074
- if (!mutedRef.current) {
16075
- for (const key of autoKeys) {
16076
- play(key);
16077
- }
16078
- const pending = pendingMusicKeyRef.current;
16079
- if (pending && pending !== currentMusicKeyRef.current) {
16080
- playMusic(pending);
16081
- }
16082
- }
16083
- };
16084
- document.addEventListener("click", unlock, { once: true });
16085
- document.addEventListener("keydown", unlock, { once: true });
16086
- document.addEventListener("touchstart", unlock, { once: true });
16087
- return () => {
16088
- document.removeEventListener("click", unlock);
16089
- document.removeEventListener("keydown", unlock);
16090
- document.removeEventListener("touchstart", unlock);
16091
- };
16092
- }, [manifest, play, playMusic]);
16093
- useEffect(() => {
16094
- return () => {
16095
- clearMusicFade();
16096
- for (const pool of poolsRef.current.values()) {
16097
- for (const audio of pool) {
16098
- audio.pause();
16099
- audio.src = "";
16100
- }
16101
- }
16102
- poolsRef.current.clear();
16103
- if (currentMusicElRef.current) {
16104
- currentMusicElRef.current.pause();
16105
- currentMusicElRef.current.src = "";
16106
- currentMusicElRef.current = null;
16107
- }
16108
- };
16109
- }, [clearMusicFade]);
16110
- return {
16111
- play,
16112
- stop,
16113
- stopAll,
16114
- playMusic,
16115
- stopMusic,
16116
- muted,
16117
- setMuted,
16118
- masterVolume,
16119
- setMasterVolume
16120
- };
16121
- }
16122
15865
  var init_useGameAudio = __esm({
16123
15866
  "components/game/shared/hooks/useGameAudio.ts"() {
16124
15867
  "use client";
16125
- useGameAudio.displayName = "useGameAudio";
16126
15868
  }
16127
15869
  });
16128
15870
  function useGameAudioContextOptional() {
16129
15871
  return useContext(GameAudioContext);
16130
15872
  }
16131
- function GameAudioProvider({
16132
- manifest,
16133
- baseUrl = "",
16134
- children,
16135
- initialMuted = false
16136
- }) {
16137
- const eventBus = useEventBus();
16138
- const { play, stop, stopAll, playMusic, stopMusic, muted, setMuted, masterVolume, setMasterVolume } = useGameAudio({ manifest, baseUrl, initialMuted });
16139
- useEffect(() => {
16140
- const unsubPlay = eventBus.on("UI:PLAY_SOUND", (event) => {
16141
- const key = event.payload?.key;
16142
- if (key) play(key);
16143
- });
16144
- const unsubStop = eventBus.on("UI:STOP_SOUND", (event) => {
16145
- const key = event.payload?.key;
16146
- if (key) {
16147
- stop(key);
16148
- } else {
16149
- stopAll();
16150
- }
16151
- });
16152
- const unsubChangeMusic = eventBus.on("UI:CHANGE_MUSIC", (event) => {
16153
- const key = event.payload?.key;
16154
- if (key) {
16155
- playMusic(key);
16156
- } else {
16157
- stopMusic();
16158
- }
16159
- });
16160
- const unsubStopMusic = eventBus.on("UI:STOP_MUSIC", () => {
16161
- stopMusic();
16162
- });
16163
- return () => {
16164
- unsubPlay();
16165
- unsubStop();
16166
- unsubChangeMusic();
16167
- unsubStopMusic();
16168
- };
16169
- }, [eventBus, play, stop, stopAll, playMusic, stopMusic]);
16170
- const value = { muted, setMuted, masterVolume, setMasterVolume, play, playMusic, stopMusic };
16171
- return /* @__PURE__ */ jsx(GameAudioContext.Provider, { value, children });
16172
- }
16173
15873
  var GameAudioContext;
16174
15874
  var init_GameAudioProvider = __esm({
16175
15875
  "components/game/shared/providers/GameAudioProvider.tsx"() {
@@ -16178,7 +15878,6 @@ var init_GameAudioProvider = __esm({
16178
15878
  init_useGameAudio();
16179
15879
  GameAudioContext = createContext(null);
16180
15880
  GameAudioContext.displayName = "GameAudioContext";
16181
- GameAudioProvider.displayName = "GameAudioProvider";
16182
15881
  }
16183
15882
  });
16184
15883
  function GameAudioToggle({
@@ -29921,129 +29620,6 @@ var init_Breadcrumb = __esm({
29921
29620
  Breadcrumb.displayName = "Breadcrumb";
29922
29621
  }
29923
29622
  });
29924
- function useSafeEventBus2() {
29925
- try {
29926
- return useEventBus();
29927
- } catch {
29928
- return { emit: () => {
29929
- }, on: () => () => {
29930
- }, once: () => {
29931
- } };
29932
- }
29933
- }
29934
- var log5, lookStyles4, ButtonGroup;
29935
- var init_ButtonGroup = __esm({
29936
- "components/core/molecules/ButtonGroup.tsx"() {
29937
- "use client";
29938
- init_cn();
29939
- init_atoms();
29940
- init_useEventBus();
29941
- log5 = createLogger("almadar:ui:button-group");
29942
- lookStyles4 = {
29943
- "right-aligned-buttons": "",
29944
- "floating-bar": "fixed bottom-section left-1/2 -translate-x-1/2 shadow-elevation-toast bg-card p-card-sm rounded-container",
29945
- "inline-row": "gap-2 inline-flex",
29946
- "dropdown-menu": "[&>button:not(:first-child)]:hidden",
29947
- "command-palette-trigger": "[&>button:not(:first-child)]:hidden"
29948
- };
29949
- ButtonGroup = ({
29950
- children,
29951
- primary,
29952
- secondary,
29953
- variant = "default",
29954
- orientation = "horizontal",
29955
- className,
29956
- // Filter-group pattern props (entity and filters are used for schema-driven filtering)
29957
- entity: _entity,
29958
- filters,
29959
- look = "right-aligned-buttons"
29960
- }) => {
29961
- const eventBus = useSafeEventBus2();
29962
- const variantClasses2 = {
29963
- default: "gap-0",
29964
- segmented: "gap-0 [&>button]:rounded-none [&>button:first-child]:rounded-l-lg [&>button:last-child]:rounded-r-lg [&>button:not(:first-child)]:border-l-0",
29965
- toggle: "gap-0 [&>button]:rounded-none [&>button:first-child]:rounded-l-lg [&>button:last-child]:rounded-r-lg [&>button:not(:first-child)]:border-l-0"
29966
- };
29967
- const orientationClasses = {
29968
- horizontal: "flex-row",
29969
- vertical: "flex-col [&>button:first-child]:rounded-t-lg [&>button:last-child]:rounded-b-lg [&>button:not(:first-child)]:border-t-0 [&>button:not(:first-child)]:border-l"
29970
- };
29971
- const handleActionClick = (action) => {
29972
- if (action.event) {
29973
- eventBus.emit("UI:DISPATCH", { event: action.event });
29974
- }
29975
- if (action.navigatesTo) {
29976
- eventBus.emit("UI:NAVIGATE", { url: action.navigatesTo });
29977
- }
29978
- };
29979
- const renderFormActions = () => {
29980
- const buttons = [];
29981
- if (secondary) {
29982
- secondary.forEach((action, index) => {
29983
- buttons.push(
29984
- /* @__PURE__ */ jsx(
29985
- Button,
29986
- {
29987
- type: action.actionType === "submit" ? "submit" : "button",
29988
- variant: action.variant || "ghost",
29989
- onClick: () => handleActionClick(action),
29990
- children: action.label
29991
- },
29992
- `secondary-${index}`
29993
- )
29994
- );
29995
- });
29996
- }
29997
- if (primary) {
29998
- const isSubmit = primary.actionType === "submit";
29999
- buttons.push(
30000
- /* @__PURE__ */ jsx(
30001
- Button,
30002
- {
30003
- type: isSubmit ? "submit" : "button",
30004
- variant: primary.variant || "primary",
30005
- onClick: () => handleActionClick(primary),
30006
- "data-testid": isSubmit ? "form-submit" : void 0,
30007
- children: primary.label
30008
- },
30009
- "primary"
30010
- )
30011
- );
30012
- }
30013
- return buttons;
30014
- };
30015
- const renderFilters = () => {
30016
- if (!filters || filters.length === 0) return null;
30017
- return filters.map((filter, index) => /* @__PURE__ */ jsx(
30018
- Button,
30019
- {
30020
- variant: "ghost",
30021
- onClick: () => {
30022
- log5.debug("Filter clicked", { field: filter.field });
30023
- },
30024
- children: filter.label
30025
- },
30026
- `filter-${filter.field}-${index}`
30027
- ));
30028
- };
30029
- return /* @__PURE__ */ jsx(
30030
- "div",
30031
- {
30032
- className: cn(
30033
- "inline-flex gap-2",
30034
- variantClasses2[variant],
30035
- orientationClasses[orientation],
30036
- lookStyles4[look],
30037
- className
30038
- ),
30039
- role: "group",
30040
- children: children || renderFilters() || renderFormActions()
30041
- }
30042
- );
30043
- };
30044
- ButtonGroup.displayName = "ButtonGroup";
30045
- }
30046
- });
30047
29623
  function useSwipeGesture(callbacks, options = {}) {
30048
29624
  const { threshold = 50, velocityThreshold = 0.3, preventDefault = false } = options;
30049
29625
  const startX = useRef(0);
@@ -30853,7 +30429,7 @@ var init_CardGrid = __esm({
30853
30429
  CardGrid.displayName = "CardGrid";
30854
30430
  }
30855
30431
  });
30856
- function useSafeEventBus3() {
30432
+ function useSafeEventBus2() {
30857
30433
  try {
30858
30434
  return useEventBus();
30859
30435
  } catch {
@@ -30889,7 +30465,7 @@ var init_Carousel = __esm({
30889
30465
  const [activeIndex, setActiveIndex] = useState(0);
30890
30466
  const scrollRef = useRef(null);
30891
30467
  const autoPlayRef = useRef(null);
30892
- const eventBus = useSafeEventBus3();
30468
+ const eventBus = useSafeEventBus2();
30893
30469
  const { t } = useTranslate();
30894
30470
  const safeItems = items ?? [];
30895
30471
  const totalSlides = safeItems.length;
@@ -34225,7 +33801,7 @@ function DataGrid({
34225
33801
  /* @__PURE__ */ jsx(
34226
33802
  Box,
34227
33803
  {
34228
- className: cn("grid", gapStyles5[gap], scrollX ? "grid-flow-col overflow-x-auto" : colsClass, lookStyles5[look], className),
33804
+ className: cn("grid", gapStyles5[gap], scrollX ? "grid-flow-col overflow-x-auto" : colsClass, lookStyles4[look], className),
34229
33805
  style: scrollX ? { gridAutoFlow: "column", gridAutoColumns: `minmax(${minCardWidth}px, 1fr)` } : gridTemplateColumns ? { gridTemplateColumns } : void 0,
34230
33806
  children: data.map((item, index) => {
34231
33807
  const itemData = item;
@@ -34420,7 +33996,7 @@ function DataGrid({
34420
33996
  ] })
34421
33997
  );
34422
33998
  }
34423
- var dataGridLog, BADGE_VARIANTS, gapStyles5, lookStyles5;
33999
+ var dataGridLog, BADGE_VARIANTS, gapStyles5, lookStyles4;
34424
34000
  var init_DataGrid = __esm({
34425
34001
  "components/core/molecules/DataGrid.tsx"() {
34426
34002
  "use client";
@@ -34455,7 +34031,7 @@ var init_DataGrid = __esm({
34455
34031
  lg: "gap-6",
34456
34032
  xl: "gap-8"
34457
34033
  };
34458
- lookStyles5 = {
34034
+ lookStyles4 = {
34459
34035
  dense: "gap-2 [&>*]:p-card-sm",
34460
34036
  spacious: "gap-8 [&>*]:p-card-lg",
34461
34037
  striped: "[&>*:nth-child(even)]:bg-muted/30",
@@ -34882,6 +34458,133 @@ var init_DataList = __esm({
34882
34458
  DataList.displayName = "DataList";
34883
34459
  }
34884
34460
  });
34461
+ var FormSection, FormLayout, FormActions;
34462
+ var init_FormSection = __esm({
34463
+ "components/core/molecules/FormSection.tsx"() {
34464
+ "use client";
34465
+ init_cn();
34466
+ init_atoms();
34467
+ init_Box();
34468
+ init_Typography();
34469
+ init_Button();
34470
+ init_Stack();
34471
+ init_Icon();
34472
+ init_useEventBus();
34473
+ FormSection = ({
34474
+ title,
34475
+ description,
34476
+ children,
34477
+ collapsible = false,
34478
+ defaultCollapsed = false,
34479
+ card = false,
34480
+ columns = 1,
34481
+ className
34482
+ }) => {
34483
+ const [collapsed, setCollapsed] = React114__default.useState(defaultCollapsed);
34484
+ const { t } = useTranslate();
34485
+ const eventBus = useEventBus();
34486
+ const gridClass = {
34487
+ 1: "grid-cols-1",
34488
+ 2: "grid-cols-1 md:grid-cols-2",
34489
+ 3: "grid-cols-1 md:grid-cols-2 lg:grid-cols-3"
34490
+ }[columns];
34491
+ React114__default.useCallback(() => {
34492
+ if (collapsible) {
34493
+ setCollapsed((prev) => !prev);
34494
+ eventBus.emit("UI:TOGGLE_COLLAPSE", { collapsed: !collapsed });
34495
+ }
34496
+ }, [collapsible, collapsed, eventBus]);
34497
+ const content = /* @__PURE__ */ jsxs(Fragment, { children: [
34498
+ (title || description) && /* @__PURE__ */ jsxs(VStack, { gap: "xs", className: "mb-4", children: [
34499
+ title && /* @__PURE__ */ jsxs(
34500
+ HStack,
34501
+ {
34502
+ justify: "between",
34503
+ align: "center",
34504
+ className: cn(collapsible && "cursor-pointer"),
34505
+ action: collapsible ? "TOGGLE_COLLAPSE" : void 0,
34506
+ children: [
34507
+ /* @__PURE__ */ jsx(Typography, { variant: "h3", weight: "semibold", children: title }),
34508
+ collapsible && /* @__PURE__ */ jsx(
34509
+ Button,
34510
+ {
34511
+ variant: "ghost",
34512
+ size: "sm",
34513
+ action: "TOGGLE_COLLAPSE",
34514
+ children: /* @__PURE__ */ jsx(
34515
+ Icon,
34516
+ {
34517
+ icon: ChevronDown,
34518
+ size: "sm",
34519
+ className: cn(
34520
+ "text-muted-foreground transition-transform",
34521
+ collapsed && "rotate-180"
34522
+ )
34523
+ }
34524
+ )
34525
+ }
34526
+ )
34527
+ ]
34528
+ }
34529
+ ),
34530
+ description && /* @__PURE__ */ jsx(Typography, { variant: "small", color: "secondary", children: description })
34531
+ ] }),
34532
+ (!collapsible || !collapsed) && /* @__PURE__ */ jsx(Box, { className: cn("grid gap-4", gridClass), children })
34533
+ ] });
34534
+ if (card) {
34535
+ return /* @__PURE__ */ jsx(Card, { className: cn("p-6", className), children: content });
34536
+ }
34537
+ return /* @__PURE__ */ jsx(Box, { className, children: content });
34538
+ };
34539
+ FormSection.displayName = "FormSection";
34540
+ FormLayout = ({
34541
+ children,
34542
+ dividers = true,
34543
+ className
34544
+ }) => {
34545
+ return /* @__PURE__ */ jsx(
34546
+ VStack,
34547
+ {
34548
+ gap: "lg",
34549
+ className: cn(
34550
+ dividers && "[&>*+*]:pt-8 [&>*+*]:border-t [&>*+*]:border-border",
34551
+ className
34552
+ ),
34553
+ children
34554
+ }
34555
+ );
34556
+ };
34557
+ FormLayout.displayName = "FormLayout";
34558
+ FormActions = ({
34559
+ children,
34560
+ sticky = false,
34561
+ align = "right",
34562
+ className
34563
+ }) => {
34564
+ const alignClass2 = {
34565
+ left: "justify-start",
34566
+ right: "justify-end",
34567
+ between: "justify-between",
34568
+ center: "justify-center"
34569
+ }[align];
34570
+ return /* @__PURE__ */ jsx(
34571
+ HStack,
34572
+ {
34573
+ gap: "sm",
34574
+ align: "center",
34575
+ className: cn(
34576
+ "pt-6 border-t border-border",
34577
+ alignClass2,
34578
+ sticky && "sticky bottom-0 bg-card py-4 -mx-6 px-6 shadow-[0_-4px_6px_-1px_rgb(0,0,0,0.05)]",
34579
+ className
34580
+ ),
34581
+ children
34582
+ }
34583
+ );
34584
+ };
34585
+ FormActions.displayName = "FormActions";
34586
+ }
34587
+ });
34885
34588
  function fileIcon(name) {
34886
34589
  const ext = name.split(".").pop()?.toLowerCase() ?? "";
34887
34590
  switch (ext) {
@@ -35043,6 +34746,129 @@ var init_FormField = __esm({
35043
34746
  FormField.displayName = "FormField";
35044
34747
  }
35045
34748
  });
34749
+ function useSafeEventBus3() {
34750
+ try {
34751
+ return useEventBus();
34752
+ } catch {
34753
+ return { emit: () => {
34754
+ }, on: () => () => {
34755
+ }, once: () => {
34756
+ } };
34757
+ }
34758
+ }
34759
+ var log5, lookStyles5, ButtonGroup;
34760
+ var init_ButtonGroup = __esm({
34761
+ "components/core/molecules/ButtonGroup.tsx"() {
34762
+ "use client";
34763
+ init_cn();
34764
+ init_atoms();
34765
+ init_useEventBus();
34766
+ log5 = createLogger("almadar:ui:button-group");
34767
+ lookStyles5 = {
34768
+ "right-aligned-buttons": "",
34769
+ "floating-bar": "fixed bottom-section left-1/2 -translate-x-1/2 shadow-elevation-toast bg-card p-card-sm rounded-container",
34770
+ "inline-row": "gap-2 inline-flex",
34771
+ "dropdown-menu": "[&>button:not(:first-child)]:hidden",
34772
+ "command-palette-trigger": "[&>button:not(:first-child)]:hidden"
34773
+ };
34774
+ ButtonGroup = ({
34775
+ children,
34776
+ primary,
34777
+ secondary,
34778
+ variant = "default",
34779
+ orientation = "horizontal",
34780
+ className,
34781
+ // Filter-group pattern props (entity and filters are used for schema-driven filtering)
34782
+ entity: _entity,
34783
+ filters,
34784
+ look = "right-aligned-buttons"
34785
+ }) => {
34786
+ const eventBus = useSafeEventBus3();
34787
+ const variantClasses2 = {
34788
+ default: "gap-0",
34789
+ segmented: "gap-0 [&>button]:rounded-none [&>button:first-child]:rounded-l-lg [&>button:last-child]:rounded-r-lg [&>button:not(:first-child)]:border-l-0",
34790
+ toggle: "gap-0 [&>button]:rounded-none [&>button:first-child]:rounded-l-lg [&>button:last-child]:rounded-r-lg [&>button:not(:first-child)]:border-l-0"
34791
+ };
34792
+ const orientationClasses = {
34793
+ horizontal: "flex-row",
34794
+ vertical: "flex-col [&>button:first-child]:rounded-t-lg [&>button:last-child]:rounded-b-lg [&>button:not(:first-child)]:border-t-0 [&>button:not(:first-child)]:border-l"
34795
+ };
34796
+ const handleActionClick = (action) => {
34797
+ if (action.event) {
34798
+ eventBus.emit("UI:DISPATCH", { event: action.event });
34799
+ }
34800
+ if (action.navigatesTo) {
34801
+ eventBus.emit("UI:NAVIGATE", { url: action.navigatesTo });
34802
+ }
34803
+ };
34804
+ const renderFormActions = () => {
34805
+ const buttons = [];
34806
+ if (secondary) {
34807
+ secondary.forEach((action, index) => {
34808
+ buttons.push(
34809
+ /* @__PURE__ */ jsx(
34810
+ Button,
34811
+ {
34812
+ type: action.actionType === "submit" ? "submit" : "button",
34813
+ variant: action.variant || "ghost",
34814
+ onClick: () => handleActionClick(action),
34815
+ children: action.label
34816
+ },
34817
+ `secondary-${index}`
34818
+ )
34819
+ );
34820
+ });
34821
+ }
34822
+ if (primary) {
34823
+ const isSubmit = primary.actionType === "submit";
34824
+ buttons.push(
34825
+ /* @__PURE__ */ jsx(
34826
+ Button,
34827
+ {
34828
+ type: isSubmit ? "submit" : "button",
34829
+ variant: primary.variant || "primary",
34830
+ onClick: () => handleActionClick(primary),
34831
+ "data-testid": isSubmit ? "form-submit" : void 0,
34832
+ children: primary.label
34833
+ },
34834
+ "primary"
34835
+ )
34836
+ );
34837
+ }
34838
+ return buttons;
34839
+ };
34840
+ const renderFilters = () => {
34841
+ if (!filters || filters.length === 0) return null;
34842
+ return filters.map((filter, index) => /* @__PURE__ */ jsx(
34843
+ Button,
34844
+ {
34845
+ variant: "ghost",
34846
+ onClick: () => {
34847
+ log5.debug("Filter clicked", { field: filter.field });
34848
+ },
34849
+ children: filter.label
34850
+ },
34851
+ `filter-${filter.field}-${index}`
34852
+ ));
34853
+ };
34854
+ return /* @__PURE__ */ jsx(
34855
+ "div",
34856
+ {
34857
+ className: cn(
34858
+ "inline-flex gap-2",
34859
+ variantClasses2[variant],
34860
+ orientationClasses[orientation],
34861
+ lookStyles5[look],
34862
+ className
34863
+ ),
34864
+ role: "group",
34865
+ children: children || renderFilters() || renderFormActions()
34866
+ }
34867
+ );
34868
+ };
34869
+ ButtonGroup.displayName = "ButtonGroup";
34870
+ }
34871
+ });
35046
34872
  function getOrCreateStore(query) {
35047
34873
  if (!queryStores.has(query)) {
35048
34874
  queryStores.set(query, {
@@ -53213,7 +53039,6 @@ var init_component_registry_generated = __esm({
53213
53039
  init_BranchingLogicBuilder();
53214
53040
  init_Breadcrumb();
53215
53041
  init_BuilderBoard();
53216
- init_ButtonGroup();
53217
53042
  init_CTABanner();
53218
53043
  init_CalendarGrid();
53219
53044
  init_Canvas2D();
@@ -53290,9 +53115,9 @@ var init_component_registry_generated = __esm({
53290
53115
  init_FlipContainer();
53291
53116
  init_FloatingActionButton();
53292
53117
  init_Form();
53118
+ init_FormSection();
53293
53119
  init_FormField();
53294
53120
  init_FormSectionHeader();
53295
- init_GameAudioProvider();
53296
53121
  init_GameAudioToggle();
53297
53122
  init_GameCard();
53298
53123
  init_GameHud();
@@ -53541,7 +53366,6 @@ var init_component_registry_generated = __esm({
53541
53366
  "Breadcrumb": Breadcrumb,
53542
53367
  "BuilderBoard": BuilderBoard,
53543
53368
  "Button": ButtonPattern,
53544
- "ButtonGroup": ButtonGroup,
53545
53369
  "ButtonPattern": ButtonPattern,
53546
53370
  "CTABanner": CTABanner,
53547
53371
  "CalendarGrid": CalendarGrid,
@@ -53621,9 +53445,10 @@ var init_component_registry_generated = __esm({
53621
53445
  "FlipContainer": FlipContainer,
53622
53446
  "FloatingActionButton": FloatingActionButton,
53623
53447
  "Form": Form,
53448
+ "FormActions": FormActions,
53624
53449
  "FormField": FormField,
53450
+ "FormLayout": FormLayout,
53625
53451
  "FormSectionHeader": FormSectionHeader,
53626
- "GameAudioProvider": GameAudioProvider,
53627
53452
  "GameAudioToggle": GameAudioToggle,
53628
53453
  "GameBoard3D": GameBoard3D,
53629
53454
  "GameCanvas3D": GameCanvas3D,