@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.
@@ -5,7 +5,7 @@ import { createLogger, isLogLevelEnabled } from '@almadar/logger';
5
5
  import { clsx } from 'clsx';
6
6
  import { twMerge } from 'tailwind-merge';
7
7
  import * as LucideIcons2 from 'lucide-react';
8
- import { Loader2, X, Lightbulb, CheckCircle, List, Printer, ChevronRight, ChevronLeft, GitBranch, Pencil, Eye, Plus, ArrowRight, Trash, Code, FileText, WrapText, Check, Copy, 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';
8
+ import { Loader2, X, Lightbulb, CheckCircle, List, Printer, ChevronRight, ChevronLeft, GitBranch, Pencil, Eye, Plus, ArrowRight, Trash, Code, FileText, WrapText, Check, Copy, 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';
9
9
  import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
10
10
  import { createPortal } from 'react-dom';
11
11
  import { useTranslate } from '@almadar/ui/hooks';
@@ -4682,7 +4682,11 @@ var init_Switch = __esm({
4682
4682
  disabled,
4683
4683
  onClick: handleClick,
4684
4684
  className: cn(
4685
- "relative inline-flex h-6 w-11 shrink-0 cursor-pointer items-center rounded-full border-2 border-transparent transition-colors",
4685
+ // Fixed rem sizes instead of spacing tokens: themes like atelier
4686
+ // redefine --space-11 to 68px, which makes w-11 enormous and leaves
4687
+ // the thumb stuck near the left edge. The switch geometry must stay
4688
+ // proportional regardless of a theme's density scale.
4689
+ "relative inline-flex h-[1.5rem] w-[2.75rem] shrink-0 cursor-pointer items-center rounded-full border-2 border-transparent transition-colors",
4686
4690
  "focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background",
4687
4691
  isChecked ? "bg-primary" : "bg-muted",
4688
4692
  disabled && "cursor-not-allowed opacity-50"
@@ -4691,8 +4695,8 @@ var init_Switch = __esm({
4691
4695
  "span",
4692
4696
  {
4693
4697
  className: cn(
4694
- "pointer-events-none block h-5 w-5 rounded-full bg-background shadow-lg ring-0 transition-transform",
4695
- isChecked ? "translate-x-5" : "translate-x-0"
4698
+ "pointer-events-none block h-[1.25rem] w-[1.25rem] rounded-full bg-background shadow-lg ring-0 transition-transform",
4699
+ isChecked ? "translate-x-[1.25rem]" : "translate-x-0"
4696
4700
  )
4697
4701
  }
4698
4702
  )
@@ -12104,318 +12108,14 @@ var init_useCanvasEffects = __esm({
12104
12108
  "use client";
12105
12109
  }
12106
12110
  });
12107
- function pickPath(entry) {
12108
- if (Array.isArray(entry.path)) {
12109
- return entry.path[Math.floor(Math.random() * entry.path.length)];
12110
- }
12111
- return entry.path;
12112
- }
12113
- function useGameAudio({
12114
- manifest,
12115
- baseUrl = "",
12116
- initialMuted = false,
12117
- initialVolume = 1
12118
- }) {
12119
- const [muted, setMutedState] = useState(initialMuted);
12120
- const [masterVolume, setMasterVolumeState] = useState(initialVolume);
12121
- const mutedRef = useRef(muted);
12122
- const volumeRef = useRef(masterVolume);
12123
- const manifestRef = useRef(manifest);
12124
- mutedRef.current = muted;
12125
- volumeRef.current = masterVolume;
12126
- manifestRef.current = manifest;
12127
- const poolsRef = useRef(/* @__PURE__ */ new Map());
12128
- const getOrCreateElement = useCallback((key) => {
12129
- const entry = manifestRef.current[key];
12130
- if (!entry) return null;
12131
- let pool = poolsRef.current.get(key);
12132
- if (!pool) {
12133
- pool = [];
12134
- poolsRef.current.set(key, pool);
12135
- }
12136
- const maxSize = entry.poolSize ?? 1;
12137
- for (const audio of pool) {
12138
- if (audio.paused && (audio.ended || audio.currentTime === 0)) {
12139
- return audio;
12140
- }
12141
- }
12142
- if (pool.length < maxSize) {
12143
- const src = baseUrl + pickPath(entry);
12144
- const audio = new Audio(src);
12145
- audio.loop = entry.loop ?? false;
12146
- pool.push(audio);
12147
- return audio;
12148
- }
12149
- if (!entry.loop) {
12150
- let oldest = pool[0];
12151
- for (const audio of pool) {
12152
- if (audio.currentTime > oldest.currentTime) {
12153
- oldest = audio;
12154
- }
12155
- }
12156
- oldest.pause();
12157
- oldest.currentTime = 0;
12158
- return oldest;
12159
- }
12160
- return null;
12161
- }, [baseUrl]);
12162
- const play = useCallback((key) => {
12163
- if (mutedRef.current) return;
12164
- const entry = manifestRef.current[key];
12165
- if (!entry) return;
12166
- const audio = getOrCreateElement(key);
12167
- if (!audio) return;
12168
- audio.volume = Math.min(1, (entry.volume ?? 1) * volumeRef.current);
12169
- if (!entry.loop) {
12170
- audio.currentTime = 0;
12171
- }
12172
- const promise = audio.play();
12173
- if (promise) {
12174
- promise.catch(() => {
12175
- });
12176
- }
12177
- }, [getOrCreateElement]);
12178
- const stop = useCallback((key) => {
12179
- const pool = poolsRef.current.get(key);
12180
- if (!pool) return;
12181
- for (const audio of pool) {
12182
- audio.pause();
12183
- audio.currentTime = 0;
12184
- }
12185
- }, []);
12186
- const currentMusicKeyRef = useRef(null);
12187
- const currentMusicElRef = useRef(null);
12188
- const musicFadeRef = useRef(null);
12189
- const pendingMusicKeyRef = useRef(null);
12190
- const clearMusicFade = useCallback(() => {
12191
- if (musicFadeRef.current) {
12192
- clearInterval(musicFadeRef.current);
12193
- musicFadeRef.current = null;
12194
- }
12195
- }, []);
12196
- const playMusic = useCallback((key) => {
12197
- if (key === currentMusicKeyRef.current) return;
12198
- pendingMusicKeyRef.current = key;
12199
- const entry = manifestRef.current[key];
12200
- if (!entry) return;
12201
- const fadeDurationMs = entry.crossfadeDurationMs ?? 1500;
12202
- const stepMs = 50;
12203
- const totalSteps = Math.max(1, fadeDurationMs / stepMs);
12204
- const targetVolume = Math.min(1, (entry.volume ?? 1) * volumeRef.current);
12205
- clearMusicFade();
12206
- const src = baseUrl + (Array.isArray(entry.path) ? entry.path[0] : entry.path);
12207
- const incoming = new Audio(src);
12208
- incoming.loop = true;
12209
- incoming.volume = 0;
12210
- const outgoing = currentMusicElRef.current;
12211
- const outgoingStartVol = outgoing?.volume ?? 0;
12212
- currentMusicKeyRef.current = key;
12213
- currentMusicElRef.current = incoming;
12214
- if (!mutedRef.current) {
12215
- incoming.play().catch(() => {
12216
- currentMusicKeyRef.current = null;
12217
- currentMusicElRef.current = outgoing;
12218
- });
12219
- }
12220
- let step = 0;
12221
- musicFadeRef.current = setInterval(() => {
12222
- step++;
12223
- const progress = Math.min(step / totalSteps, 1);
12224
- incoming.volume = Math.min(1, targetVolume * progress);
12225
- if (outgoing) {
12226
- outgoing.volume = Math.max(0, outgoingStartVol * (1 - progress));
12227
- }
12228
- if (progress >= 1) {
12229
- clearMusicFade();
12230
- if (outgoing) {
12231
- outgoing.pause();
12232
- outgoing.src = "";
12233
- }
12234
- }
12235
- }, stepMs);
12236
- }, [baseUrl, clearMusicFade]);
12237
- const stopMusic = useCallback((fadeDurationMs = 1e3) => {
12238
- const outgoing = currentMusicElRef.current;
12239
- if (!outgoing) return;
12240
- currentMusicKeyRef.current = null;
12241
- currentMusicElRef.current = null;
12242
- pendingMusicKeyRef.current = null;
12243
- clearMusicFade();
12244
- const startVolume = outgoing.volume;
12245
- const stepMs = 50;
12246
- const totalSteps = Math.max(1, fadeDurationMs / stepMs);
12247
- let step = 0;
12248
- musicFadeRef.current = setInterval(() => {
12249
- step++;
12250
- const progress = step / totalSteps;
12251
- outgoing.volume = Math.max(0, startVolume * (1 - progress));
12252
- if (progress >= 1) {
12253
- clearMusicFade();
12254
- outgoing.pause();
12255
- outgoing.src = "";
12256
- }
12257
- }, stepMs);
12258
- }, [clearMusicFade]);
12259
- const stopAll = useCallback(() => {
12260
- for (const pool of poolsRef.current.values()) {
12261
- for (const audio of pool) {
12262
- audio.pause();
12263
- audio.currentTime = 0;
12264
- }
12265
- }
12266
- stopMusic(0);
12267
- }, [stopMusic]);
12268
- const setMuted = useCallback((value) => {
12269
- setMutedState(value);
12270
- if (value) {
12271
- for (const [key, pool] of poolsRef.current.entries()) {
12272
- if (manifestRef.current[key]?.loop) {
12273
- for (const audio of pool) {
12274
- if (!audio.paused) audio.pause();
12275
- }
12276
- }
12277
- }
12278
- currentMusicElRef.current?.pause();
12279
- } else {
12280
- for (const [key, pool] of poolsRef.current.entries()) {
12281
- const entry = manifestRef.current[key];
12282
- if (entry?.loop && entry?.autostart) {
12283
- for (const audio of pool) {
12284
- if (audio.paused) audio.play().catch(() => {
12285
- });
12286
- }
12287
- }
12288
- }
12289
- const musicEl = currentMusicElRef.current;
12290
- if (musicEl) {
12291
- musicEl.play().catch(() => {
12292
- });
12293
- }
12294
- }
12295
- }, []);
12296
- const setMasterVolume = useCallback((volume) => {
12297
- const clamped = Math.max(0, Math.min(1, volume));
12298
- setMasterVolumeState(clamped);
12299
- for (const [key, pool] of poolsRef.current.entries()) {
12300
- const entryVol = manifestRef.current[key]?.volume ?? 1;
12301
- for (const audio of pool) {
12302
- audio.volume = Math.min(1, entryVol * clamped);
12303
- }
12304
- }
12305
- if (!musicFadeRef.current && currentMusicElRef.current) {
12306
- const key = currentMusicKeyRef.current;
12307
- const entryVol = key ? manifestRef.current[key]?.volume ?? 1 : 1;
12308
- currentMusicElRef.current.volume = Math.min(1, entryVol * clamped);
12309
- }
12310
- }, []);
12311
- const unlockedRef = useRef(false);
12312
- useEffect(() => {
12313
- const autoKeys = Object.keys(manifest).filter((k) => manifest[k].autostart);
12314
- const hasPendingMusic = () => pendingMusicKeyRef.current !== null;
12315
- const hasAutoStart = autoKeys.length > 0;
12316
- if (!hasAutoStart && !hasPendingMusic()) return;
12317
- const unlock = () => {
12318
- if (unlockedRef.current) return;
12319
- unlockedRef.current = true;
12320
- if (!mutedRef.current) {
12321
- for (const key of autoKeys) {
12322
- play(key);
12323
- }
12324
- const pending = pendingMusicKeyRef.current;
12325
- if (pending && pending !== currentMusicKeyRef.current) {
12326
- playMusic(pending);
12327
- }
12328
- }
12329
- };
12330
- document.addEventListener("click", unlock, { once: true });
12331
- document.addEventListener("keydown", unlock, { once: true });
12332
- document.addEventListener("touchstart", unlock, { once: true });
12333
- return () => {
12334
- document.removeEventListener("click", unlock);
12335
- document.removeEventListener("keydown", unlock);
12336
- document.removeEventListener("touchstart", unlock);
12337
- };
12338
- }, [manifest, play, playMusic]);
12339
- useEffect(() => {
12340
- return () => {
12341
- clearMusicFade();
12342
- for (const pool of poolsRef.current.values()) {
12343
- for (const audio of pool) {
12344
- audio.pause();
12345
- audio.src = "";
12346
- }
12347
- }
12348
- poolsRef.current.clear();
12349
- if (currentMusicElRef.current) {
12350
- currentMusicElRef.current.pause();
12351
- currentMusicElRef.current.src = "";
12352
- currentMusicElRef.current = null;
12353
- }
12354
- };
12355
- }, [clearMusicFade]);
12356
- return {
12357
- play,
12358
- stop,
12359
- stopAll,
12360
- playMusic,
12361
- stopMusic,
12362
- muted,
12363
- setMuted,
12364
- masterVolume,
12365
- setMasterVolume
12366
- };
12367
- }
12368
12111
  var init_useGameAudio = __esm({
12369
12112
  "components/game/shared/hooks/useGameAudio.ts"() {
12370
12113
  "use client";
12371
- useGameAudio.displayName = "useGameAudio";
12372
12114
  }
12373
12115
  });
12374
12116
  function useGameAudioContextOptional() {
12375
12117
  return useContext(GameAudioContext);
12376
12118
  }
12377
- function GameAudioProvider({
12378
- manifest,
12379
- baseUrl = "",
12380
- children,
12381
- initialMuted = false
12382
- }) {
12383
- const eventBus = useEventBus();
12384
- const { play, stop, stopAll, playMusic, stopMusic, muted, setMuted, masterVolume, setMasterVolume } = useGameAudio({ manifest, baseUrl, initialMuted });
12385
- useEffect(() => {
12386
- const unsubPlay = eventBus.on("UI:PLAY_SOUND", (event) => {
12387
- const key = event.payload?.key;
12388
- if (key) play(key);
12389
- });
12390
- const unsubStop = eventBus.on("UI:STOP_SOUND", (event) => {
12391
- const key = event.payload?.key;
12392
- if (key) {
12393
- stop(key);
12394
- } else {
12395
- stopAll();
12396
- }
12397
- });
12398
- const unsubChangeMusic = eventBus.on("UI:CHANGE_MUSIC", (event) => {
12399
- const key = event.payload?.key;
12400
- if (key) {
12401
- playMusic(key);
12402
- } else {
12403
- stopMusic();
12404
- }
12405
- });
12406
- const unsubStopMusic = eventBus.on("UI:STOP_MUSIC", () => {
12407
- stopMusic();
12408
- });
12409
- return () => {
12410
- unsubPlay();
12411
- unsubStop();
12412
- unsubChangeMusic();
12413
- unsubStopMusic();
12414
- };
12415
- }, [eventBus, play, stop, stopAll, playMusic, stopMusic]);
12416
- const value = { muted, setMuted, masterVolume, setMasterVolume, play, playMusic, stopMusic };
12417
- return /* @__PURE__ */ jsx(GameAudioContext.Provider, { value, children });
12418
- }
12419
12119
  var GameAudioContext;
12420
12120
  var init_GameAudioProvider = __esm({
12421
12121
  "components/game/shared/providers/GameAudioProvider.tsx"() {
@@ -12424,7 +12124,6 @@ var init_GameAudioProvider = __esm({
12424
12124
  init_useGameAudio();
12425
12125
  GameAudioContext = createContext(null);
12426
12126
  GameAudioContext.displayName = "GameAudioContext";
12427
- GameAudioProvider.displayName = "GameAudioProvider";
12428
12127
  }
12429
12128
  });
12430
12129
  function GameAudioToggle({
@@ -27377,129 +27076,6 @@ var init_Breadcrumb = __esm({
27377
27076
  Breadcrumb.displayName = "Breadcrumb";
27378
27077
  }
27379
27078
  });
27380
- function useSafeEventBus2() {
27381
- try {
27382
- return useEventBus();
27383
- } catch {
27384
- return { emit: () => {
27385
- }, on: () => () => {
27386
- }, once: () => {
27387
- } };
27388
- }
27389
- }
27390
- var log8, lookStyles4, ButtonGroup;
27391
- var init_ButtonGroup = __esm({
27392
- "components/core/molecules/ButtonGroup.tsx"() {
27393
- "use client";
27394
- init_cn();
27395
- init_atoms();
27396
- init_useEventBus();
27397
- log8 = createLogger("almadar:ui:button-group");
27398
- lookStyles4 = {
27399
- "right-aligned-buttons": "",
27400
- "floating-bar": "fixed bottom-section left-1/2 -translate-x-1/2 shadow-elevation-toast bg-card p-card-sm rounded-container",
27401
- "inline-row": "gap-2 inline-flex",
27402
- "dropdown-menu": "[&>button:not(:first-child)]:hidden",
27403
- "command-palette-trigger": "[&>button:not(:first-child)]:hidden"
27404
- };
27405
- ButtonGroup = ({
27406
- children,
27407
- primary,
27408
- secondary,
27409
- variant = "default",
27410
- orientation = "horizontal",
27411
- className,
27412
- // Filter-group pattern props (entity and filters are used for schema-driven filtering)
27413
- entity: _entity,
27414
- filters,
27415
- look = "right-aligned-buttons"
27416
- }) => {
27417
- const eventBus = useSafeEventBus2();
27418
- const variantClasses2 = {
27419
- default: "gap-0",
27420
- 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",
27421
- 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"
27422
- };
27423
- const orientationClasses = {
27424
- horizontal: "flex-row",
27425
- 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"
27426
- };
27427
- const handleActionClick = (action) => {
27428
- if (action.event) {
27429
- eventBus.emit("UI:DISPATCH", { event: action.event });
27430
- }
27431
- if (action.navigatesTo) {
27432
- eventBus.emit("UI:NAVIGATE", { url: action.navigatesTo });
27433
- }
27434
- };
27435
- const renderFormActions = () => {
27436
- const buttons = [];
27437
- if (secondary) {
27438
- secondary.forEach((action, index) => {
27439
- buttons.push(
27440
- /* @__PURE__ */ jsx(
27441
- Button,
27442
- {
27443
- type: action.actionType === "submit" ? "submit" : "button",
27444
- variant: action.variant || "ghost",
27445
- onClick: () => handleActionClick(action),
27446
- children: action.label
27447
- },
27448
- `secondary-${index}`
27449
- )
27450
- );
27451
- });
27452
- }
27453
- if (primary) {
27454
- const isSubmit = primary.actionType === "submit";
27455
- buttons.push(
27456
- /* @__PURE__ */ jsx(
27457
- Button,
27458
- {
27459
- type: isSubmit ? "submit" : "button",
27460
- variant: primary.variant || "primary",
27461
- onClick: () => handleActionClick(primary),
27462
- "data-testid": isSubmit ? "form-submit" : void 0,
27463
- children: primary.label
27464
- },
27465
- "primary"
27466
- )
27467
- );
27468
- }
27469
- return buttons;
27470
- };
27471
- const renderFilters = () => {
27472
- if (!filters || filters.length === 0) return null;
27473
- return filters.map((filter, index) => /* @__PURE__ */ jsx(
27474
- Button,
27475
- {
27476
- variant: "ghost",
27477
- onClick: () => {
27478
- log8.debug("Filter clicked", { field: filter.field });
27479
- },
27480
- children: filter.label
27481
- },
27482
- `filter-${filter.field}-${index}`
27483
- ));
27484
- };
27485
- return /* @__PURE__ */ jsx(
27486
- "div",
27487
- {
27488
- className: cn(
27489
- "inline-flex gap-2",
27490
- variantClasses2[variant],
27491
- orientationClasses[orientation],
27492
- lookStyles4[look],
27493
- className
27494
- ),
27495
- role: "group",
27496
- children: children || renderFilters() || renderFormActions()
27497
- }
27498
- );
27499
- };
27500
- ButtonGroup.displayName = "ButtonGroup";
27501
- }
27502
- });
27503
27079
  function useSwipeGesture(callbacks, options = {}) {
27504
27080
  const { threshold = 50, velocityThreshold = 0.3, preventDefault = false } = options;
27505
27081
  const startX = useRef(0);
@@ -28309,7 +27885,7 @@ var init_CardGrid = __esm({
28309
27885
  CardGrid.displayName = "CardGrid";
28310
27886
  }
28311
27887
  });
28312
- function useSafeEventBus3() {
27888
+ function useSafeEventBus2() {
28313
27889
  try {
28314
27890
  return useEventBus();
28315
27891
  } catch {
@@ -28345,7 +27921,7 @@ var init_Carousel = __esm({
28345
27921
  const [activeIndex, setActiveIndex] = useState(0);
28346
27922
  const scrollRef = useRef(null);
28347
27923
  const autoPlayRef = useRef(null);
28348
- const eventBus = useSafeEventBus3();
27924
+ const eventBus = useSafeEventBus2();
28349
27925
  const { t } = useTranslate();
28350
27926
  const safeItems = items ?? [];
28351
27927
  const totalSlides = safeItems.length;
@@ -31681,7 +31257,7 @@ function DataGrid({
31681
31257
  /* @__PURE__ */ jsx(
31682
31258
  Box,
31683
31259
  {
31684
- className: cn("grid", gapStyles5[gap], scrollX ? "grid-flow-col overflow-x-auto" : colsClass, lookStyles5[look], className),
31260
+ className: cn("grid", gapStyles5[gap], scrollX ? "grid-flow-col overflow-x-auto" : colsClass, lookStyles4[look], className),
31685
31261
  style: scrollX ? { gridAutoFlow: "column", gridAutoColumns: `minmax(${minCardWidth}px, 1fr)` } : gridTemplateColumns ? { gridTemplateColumns } : void 0,
31686
31262
  children: data.map((item, index) => {
31687
31263
  const itemData = item;
@@ -31876,7 +31452,7 @@ function DataGrid({
31876
31452
  ] })
31877
31453
  );
31878
31454
  }
31879
- var dataGridLog, BADGE_VARIANTS, gapStyles5, lookStyles5;
31455
+ var dataGridLog, BADGE_VARIANTS, gapStyles5, lookStyles4;
31880
31456
  var init_DataGrid = __esm({
31881
31457
  "components/core/molecules/DataGrid.tsx"() {
31882
31458
  "use client";
@@ -31911,7 +31487,7 @@ var init_DataGrid = __esm({
31911
31487
  lg: "gap-6",
31912
31488
  xl: "gap-8"
31913
31489
  };
31914
- lookStyles5 = {
31490
+ lookStyles4 = {
31915
31491
  dense: "gap-2 [&>*]:p-card-sm",
31916
31492
  spacious: "gap-8 [&>*]:p-card-lg",
31917
31493
  striped: "[&>*:nth-child(even)]:bg-muted/30",
@@ -32338,6 +31914,133 @@ var init_DataList = __esm({
32338
31914
  DataList.displayName = "DataList";
32339
31915
  }
32340
31916
  });
31917
+ var FormSection, FormLayout, FormActions;
31918
+ var init_FormSection = __esm({
31919
+ "components/core/molecules/FormSection.tsx"() {
31920
+ "use client";
31921
+ init_cn();
31922
+ init_atoms();
31923
+ init_Box();
31924
+ init_Typography();
31925
+ init_Button();
31926
+ init_Stack();
31927
+ init_Icon();
31928
+ init_useEventBus();
31929
+ FormSection = ({
31930
+ title,
31931
+ description,
31932
+ children,
31933
+ collapsible = false,
31934
+ defaultCollapsed = false,
31935
+ card = false,
31936
+ columns = 1,
31937
+ className
31938
+ }) => {
31939
+ const [collapsed, setCollapsed] = React107__default.useState(defaultCollapsed);
31940
+ const { t } = useTranslate();
31941
+ const eventBus = useEventBus();
31942
+ const gridClass = {
31943
+ 1: "grid-cols-1",
31944
+ 2: "grid-cols-1 md:grid-cols-2",
31945
+ 3: "grid-cols-1 md:grid-cols-2 lg:grid-cols-3"
31946
+ }[columns];
31947
+ React107__default.useCallback(() => {
31948
+ if (collapsible) {
31949
+ setCollapsed((prev) => !prev);
31950
+ eventBus.emit("UI:TOGGLE_COLLAPSE", { collapsed: !collapsed });
31951
+ }
31952
+ }, [collapsible, collapsed, eventBus]);
31953
+ const content = /* @__PURE__ */ jsxs(Fragment, { children: [
31954
+ (title || description) && /* @__PURE__ */ jsxs(VStack, { gap: "xs", className: "mb-4", children: [
31955
+ title && /* @__PURE__ */ jsxs(
31956
+ HStack,
31957
+ {
31958
+ justify: "between",
31959
+ align: "center",
31960
+ className: cn(collapsible && "cursor-pointer"),
31961
+ action: collapsible ? "TOGGLE_COLLAPSE" : void 0,
31962
+ children: [
31963
+ /* @__PURE__ */ jsx(Typography, { variant: "h3", weight: "semibold", children: title }),
31964
+ collapsible && /* @__PURE__ */ jsx(
31965
+ Button,
31966
+ {
31967
+ variant: "ghost",
31968
+ size: "sm",
31969
+ action: "TOGGLE_COLLAPSE",
31970
+ children: /* @__PURE__ */ jsx(
31971
+ Icon,
31972
+ {
31973
+ icon: ChevronDown,
31974
+ size: "sm",
31975
+ className: cn(
31976
+ "text-muted-foreground transition-transform",
31977
+ collapsed && "rotate-180"
31978
+ )
31979
+ }
31980
+ )
31981
+ }
31982
+ )
31983
+ ]
31984
+ }
31985
+ ),
31986
+ description && /* @__PURE__ */ jsx(Typography, { variant: "small", color: "secondary", children: description })
31987
+ ] }),
31988
+ (!collapsible || !collapsed) && /* @__PURE__ */ jsx(Box, { className: cn("grid gap-4", gridClass), children })
31989
+ ] });
31990
+ if (card) {
31991
+ return /* @__PURE__ */ jsx(Card, { className: cn("p-6", className), children: content });
31992
+ }
31993
+ return /* @__PURE__ */ jsx(Box, { className, children: content });
31994
+ };
31995
+ FormSection.displayName = "FormSection";
31996
+ FormLayout = ({
31997
+ children,
31998
+ dividers = true,
31999
+ className
32000
+ }) => {
32001
+ return /* @__PURE__ */ jsx(
32002
+ VStack,
32003
+ {
32004
+ gap: "lg",
32005
+ className: cn(
32006
+ dividers && "[&>*+*]:pt-8 [&>*+*]:border-t [&>*+*]:border-border",
32007
+ className
32008
+ ),
32009
+ children
32010
+ }
32011
+ );
32012
+ };
32013
+ FormLayout.displayName = "FormLayout";
32014
+ FormActions = ({
32015
+ children,
32016
+ sticky = false,
32017
+ align = "right",
32018
+ className
32019
+ }) => {
32020
+ const alignClass2 = {
32021
+ left: "justify-start",
32022
+ right: "justify-end",
32023
+ between: "justify-between",
32024
+ center: "justify-center"
32025
+ }[align];
32026
+ return /* @__PURE__ */ jsx(
32027
+ HStack,
32028
+ {
32029
+ gap: "sm",
32030
+ align: "center",
32031
+ className: cn(
32032
+ "pt-6 border-t border-border",
32033
+ alignClass2,
32034
+ sticky && "sticky bottom-0 bg-card py-4 -mx-6 px-6 shadow-[0_-4px_6px_-1px_rgb(0,0,0,0.05)]",
32035
+ className
32036
+ ),
32037
+ children
32038
+ }
32039
+ );
32040
+ };
32041
+ FormActions.displayName = "FormActions";
32042
+ }
32043
+ });
32341
32044
  function fileIcon(name) {
32342
32045
  const ext = name.split(".").pop()?.toLowerCase() ?? "";
32343
32046
  switch (ext) {
@@ -32499,6 +32202,129 @@ var init_FormField = __esm({
32499
32202
  FormField.displayName = "FormField";
32500
32203
  }
32501
32204
  });
32205
+ function useSafeEventBus3() {
32206
+ try {
32207
+ return useEventBus();
32208
+ } catch {
32209
+ return { emit: () => {
32210
+ }, on: () => () => {
32211
+ }, once: () => {
32212
+ } };
32213
+ }
32214
+ }
32215
+ var log8, lookStyles5, ButtonGroup;
32216
+ var init_ButtonGroup = __esm({
32217
+ "components/core/molecules/ButtonGroup.tsx"() {
32218
+ "use client";
32219
+ init_cn();
32220
+ init_atoms();
32221
+ init_useEventBus();
32222
+ log8 = createLogger("almadar:ui:button-group");
32223
+ lookStyles5 = {
32224
+ "right-aligned-buttons": "",
32225
+ "floating-bar": "fixed bottom-section left-1/2 -translate-x-1/2 shadow-elevation-toast bg-card p-card-sm rounded-container",
32226
+ "inline-row": "gap-2 inline-flex",
32227
+ "dropdown-menu": "[&>button:not(:first-child)]:hidden",
32228
+ "command-palette-trigger": "[&>button:not(:first-child)]:hidden"
32229
+ };
32230
+ ButtonGroup = ({
32231
+ children,
32232
+ primary,
32233
+ secondary,
32234
+ variant = "default",
32235
+ orientation = "horizontal",
32236
+ className,
32237
+ // Filter-group pattern props (entity and filters are used for schema-driven filtering)
32238
+ entity: _entity,
32239
+ filters,
32240
+ look = "right-aligned-buttons"
32241
+ }) => {
32242
+ const eventBus = useSafeEventBus3();
32243
+ const variantClasses2 = {
32244
+ default: "gap-0",
32245
+ 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",
32246
+ 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"
32247
+ };
32248
+ const orientationClasses = {
32249
+ horizontal: "flex-row",
32250
+ 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"
32251
+ };
32252
+ const handleActionClick = (action) => {
32253
+ if (action.event) {
32254
+ eventBus.emit("UI:DISPATCH", { event: action.event });
32255
+ }
32256
+ if (action.navigatesTo) {
32257
+ eventBus.emit("UI:NAVIGATE", { url: action.navigatesTo });
32258
+ }
32259
+ };
32260
+ const renderFormActions = () => {
32261
+ const buttons = [];
32262
+ if (secondary) {
32263
+ secondary.forEach((action, index) => {
32264
+ buttons.push(
32265
+ /* @__PURE__ */ jsx(
32266
+ Button,
32267
+ {
32268
+ type: action.actionType === "submit" ? "submit" : "button",
32269
+ variant: action.variant || "ghost",
32270
+ onClick: () => handleActionClick(action),
32271
+ children: action.label
32272
+ },
32273
+ `secondary-${index}`
32274
+ )
32275
+ );
32276
+ });
32277
+ }
32278
+ if (primary) {
32279
+ const isSubmit = primary.actionType === "submit";
32280
+ buttons.push(
32281
+ /* @__PURE__ */ jsx(
32282
+ Button,
32283
+ {
32284
+ type: isSubmit ? "submit" : "button",
32285
+ variant: primary.variant || "primary",
32286
+ onClick: () => handleActionClick(primary),
32287
+ "data-testid": isSubmit ? "form-submit" : void 0,
32288
+ children: primary.label
32289
+ },
32290
+ "primary"
32291
+ )
32292
+ );
32293
+ }
32294
+ return buttons;
32295
+ };
32296
+ const renderFilters = () => {
32297
+ if (!filters || filters.length === 0) return null;
32298
+ return filters.map((filter, index) => /* @__PURE__ */ jsx(
32299
+ Button,
32300
+ {
32301
+ variant: "ghost",
32302
+ onClick: () => {
32303
+ log8.debug("Filter clicked", { field: filter.field });
32304
+ },
32305
+ children: filter.label
32306
+ },
32307
+ `filter-${filter.field}-${index}`
32308
+ ));
32309
+ };
32310
+ return /* @__PURE__ */ jsx(
32311
+ "div",
32312
+ {
32313
+ className: cn(
32314
+ "inline-flex gap-2",
32315
+ variantClasses2[variant],
32316
+ orientationClasses[orientation],
32317
+ lookStyles5[look],
32318
+ className
32319
+ ),
32320
+ role: "group",
32321
+ children: children || renderFilters() || renderFormActions()
32322
+ }
32323
+ );
32324
+ };
32325
+ ButtonGroup.displayName = "ButtonGroup";
32326
+ }
32327
+ });
32502
32328
  function getOrCreateStore(query) {
32503
32329
  if (!queryStores.has(query)) {
32504
32330
  queryStores.set(query, {
@@ -51059,7 +50885,6 @@ var init_component_registry_generated = __esm({
51059
50885
  init_BranchingLogicBuilder();
51060
50886
  init_Breadcrumb();
51061
50887
  init_BuilderBoard();
51062
- init_ButtonGroup();
51063
50888
  init_CTABanner();
51064
50889
  init_CalendarGrid();
51065
50890
  init_Canvas2D();
@@ -51136,9 +50961,9 @@ var init_component_registry_generated = __esm({
51136
50961
  init_FlipContainer();
51137
50962
  init_FloatingActionButton();
51138
50963
  init_Form();
50964
+ init_FormSection();
51139
50965
  init_FormField();
51140
50966
  init_FormSectionHeader();
51141
- init_GameAudioProvider();
51142
50967
  init_GameAudioToggle();
51143
50968
  init_GameCard();
51144
50969
  init_GameHud();
@@ -51387,7 +51212,6 @@ var init_component_registry_generated = __esm({
51387
51212
  "Breadcrumb": Breadcrumb,
51388
51213
  "BuilderBoard": BuilderBoard,
51389
51214
  "Button": ButtonPattern,
51390
- "ButtonGroup": ButtonGroup,
51391
51215
  "ButtonPattern": ButtonPattern,
51392
51216
  "CTABanner": CTABanner,
51393
51217
  "CalendarGrid": CalendarGrid,
@@ -51467,9 +51291,10 @@ var init_component_registry_generated = __esm({
51467
51291
  "FlipContainer": FlipContainer,
51468
51292
  "FloatingActionButton": FloatingActionButton,
51469
51293
  "Form": Form,
51294
+ "FormActions": FormActions,
51470
51295
  "FormField": FormField,
51296
+ "FormLayout": FormLayout,
51471
51297
  "FormSectionHeader": FormSectionHeader,
51472
- "GameAudioProvider": GameAudioProvider,
51473
51298
  "GameAudioToggle": GameAudioToggle,
51474
51299
  "GameBoard3D": GameBoard3D,
51475
51300
  "GameCanvas3D": GameCanvas3D,