@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.
@@ -6,7 +6,7 @@ import { createLogger, isLogLevelEnabled } from '@almadar/logger';
6
6
  import { clsx } from 'clsx';
7
7
  import { twMerge } from 'tailwind-merge';
8
8
  import * as LucideIcons2 from 'lucide-react';
9
- 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';
9
+ 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';
10
10
  import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
11
11
  import { createPortal } from 'react-dom';
12
12
  import { useTranslate } from '@almadar/ui/hooks';
@@ -5231,7 +5231,11 @@ var init_Switch = __esm({
5231
5231
  disabled,
5232
5232
  onClick: handleClick,
5233
5233
  className: cn(
5234
- "relative inline-flex h-6 w-11 shrink-0 cursor-pointer items-center rounded-full border-2 border-transparent transition-colors",
5234
+ // Fixed rem sizes instead of spacing tokens: themes like atelier
5235
+ // redefine --space-11 to 68px, which makes w-11 enormous and leaves
5236
+ // the thumb stuck near the left edge. The switch geometry must stay
5237
+ // proportional regardless of a theme's density scale.
5238
+ "relative inline-flex h-[1.5rem] w-[2.75rem] shrink-0 cursor-pointer items-center rounded-full border-2 border-transparent transition-colors",
5235
5239
  "focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background",
5236
5240
  isChecked ? "bg-primary" : "bg-muted",
5237
5241
  disabled && "cursor-not-allowed opacity-50"
@@ -5240,8 +5244,8 @@ var init_Switch = __esm({
5240
5244
  "span",
5241
5245
  {
5242
5246
  className: cn(
5243
- "pointer-events-none block h-5 w-5 rounded-full bg-background shadow-lg ring-0 transition-transform",
5244
- isChecked ? "translate-x-5" : "translate-x-0"
5247
+ "pointer-events-none block h-[1.25rem] w-[1.25rem] rounded-full bg-background shadow-lg ring-0 transition-transform",
5248
+ isChecked ? "translate-x-[1.25rem]" : "translate-x-0"
5245
5249
  )
5246
5250
  }
5247
5251
  )
@@ -12451,318 +12455,14 @@ var init_useCanvasEffects = __esm({
12451
12455
  "use client";
12452
12456
  }
12453
12457
  });
12454
- function pickPath(entry) {
12455
- if (Array.isArray(entry.path)) {
12456
- return entry.path[Math.floor(Math.random() * entry.path.length)];
12457
- }
12458
- return entry.path;
12459
- }
12460
- function useGameAudio({
12461
- manifest,
12462
- baseUrl = "",
12463
- initialMuted = false,
12464
- initialVolume = 1
12465
- }) {
12466
- const [muted, setMutedState] = useState(initialMuted);
12467
- const [masterVolume, setMasterVolumeState] = useState(initialVolume);
12468
- const mutedRef = useRef(muted);
12469
- const volumeRef = useRef(masterVolume);
12470
- const manifestRef = useRef(manifest);
12471
- mutedRef.current = muted;
12472
- volumeRef.current = masterVolume;
12473
- manifestRef.current = manifest;
12474
- const poolsRef = useRef(/* @__PURE__ */ new Map());
12475
- const getOrCreateElement = useCallback((key) => {
12476
- const entry = manifestRef.current[key];
12477
- if (!entry) return null;
12478
- let pool = poolsRef.current.get(key);
12479
- if (!pool) {
12480
- pool = [];
12481
- poolsRef.current.set(key, pool);
12482
- }
12483
- const maxSize = entry.poolSize ?? 1;
12484
- for (const audio of pool) {
12485
- if (audio.paused && (audio.ended || audio.currentTime === 0)) {
12486
- return audio;
12487
- }
12488
- }
12489
- if (pool.length < maxSize) {
12490
- const src = baseUrl + pickPath(entry);
12491
- const audio = new Audio(src);
12492
- audio.loop = entry.loop ?? false;
12493
- pool.push(audio);
12494
- return audio;
12495
- }
12496
- if (!entry.loop) {
12497
- let oldest = pool[0];
12498
- for (const audio of pool) {
12499
- if (audio.currentTime > oldest.currentTime) {
12500
- oldest = audio;
12501
- }
12502
- }
12503
- oldest.pause();
12504
- oldest.currentTime = 0;
12505
- return oldest;
12506
- }
12507
- return null;
12508
- }, [baseUrl]);
12509
- const play = useCallback((key) => {
12510
- if (mutedRef.current) return;
12511
- const entry = manifestRef.current[key];
12512
- if (!entry) return;
12513
- const audio = getOrCreateElement(key);
12514
- if (!audio) return;
12515
- audio.volume = Math.min(1, (entry.volume ?? 1) * volumeRef.current);
12516
- if (!entry.loop) {
12517
- audio.currentTime = 0;
12518
- }
12519
- const promise = audio.play();
12520
- if (promise) {
12521
- promise.catch(() => {
12522
- });
12523
- }
12524
- }, [getOrCreateElement]);
12525
- const stop = useCallback((key) => {
12526
- const pool = poolsRef.current.get(key);
12527
- if (!pool) return;
12528
- for (const audio of pool) {
12529
- audio.pause();
12530
- audio.currentTime = 0;
12531
- }
12532
- }, []);
12533
- const currentMusicKeyRef = useRef(null);
12534
- const currentMusicElRef = useRef(null);
12535
- const musicFadeRef = useRef(null);
12536
- const pendingMusicKeyRef = useRef(null);
12537
- const clearMusicFade = useCallback(() => {
12538
- if (musicFadeRef.current) {
12539
- clearInterval(musicFadeRef.current);
12540
- musicFadeRef.current = null;
12541
- }
12542
- }, []);
12543
- const playMusic = useCallback((key) => {
12544
- if (key === currentMusicKeyRef.current) return;
12545
- pendingMusicKeyRef.current = key;
12546
- const entry = manifestRef.current[key];
12547
- if (!entry) return;
12548
- const fadeDurationMs = entry.crossfadeDurationMs ?? 1500;
12549
- const stepMs = 50;
12550
- const totalSteps = Math.max(1, fadeDurationMs / stepMs);
12551
- const targetVolume = Math.min(1, (entry.volume ?? 1) * volumeRef.current);
12552
- clearMusicFade();
12553
- const src = baseUrl + (Array.isArray(entry.path) ? entry.path[0] : entry.path);
12554
- const incoming = new Audio(src);
12555
- incoming.loop = true;
12556
- incoming.volume = 0;
12557
- const outgoing = currentMusicElRef.current;
12558
- const outgoingStartVol = outgoing?.volume ?? 0;
12559
- currentMusicKeyRef.current = key;
12560
- currentMusicElRef.current = incoming;
12561
- if (!mutedRef.current) {
12562
- incoming.play().catch(() => {
12563
- currentMusicKeyRef.current = null;
12564
- currentMusicElRef.current = outgoing;
12565
- });
12566
- }
12567
- let step = 0;
12568
- musicFadeRef.current = setInterval(() => {
12569
- step++;
12570
- const progress = Math.min(step / totalSteps, 1);
12571
- incoming.volume = Math.min(1, targetVolume * progress);
12572
- if (outgoing) {
12573
- outgoing.volume = Math.max(0, outgoingStartVol * (1 - progress));
12574
- }
12575
- if (progress >= 1) {
12576
- clearMusicFade();
12577
- if (outgoing) {
12578
- outgoing.pause();
12579
- outgoing.src = "";
12580
- }
12581
- }
12582
- }, stepMs);
12583
- }, [baseUrl, clearMusicFade]);
12584
- const stopMusic = useCallback((fadeDurationMs = 1e3) => {
12585
- const outgoing = currentMusicElRef.current;
12586
- if (!outgoing) return;
12587
- currentMusicKeyRef.current = null;
12588
- currentMusicElRef.current = null;
12589
- pendingMusicKeyRef.current = null;
12590
- clearMusicFade();
12591
- const startVolume = outgoing.volume;
12592
- const stepMs = 50;
12593
- const totalSteps = Math.max(1, fadeDurationMs / stepMs);
12594
- let step = 0;
12595
- musicFadeRef.current = setInterval(() => {
12596
- step++;
12597
- const progress = step / totalSteps;
12598
- outgoing.volume = Math.max(0, startVolume * (1 - progress));
12599
- if (progress >= 1) {
12600
- clearMusicFade();
12601
- outgoing.pause();
12602
- outgoing.src = "";
12603
- }
12604
- }, stepMs);
12605
- }, [clearMusicFade]);
12606
- const stopAll = useCallback(() => {
12607
- for (const pool of poolsRef.current.values()) {
12608
- for (const audio of pool) {
12609
- audio.pause();
12610
- audio.currentTime = 0;
12611
- }
12612
- }
12613
- stopMusic(0);
12614
- }, [stopMusic]);
12615
- const setMuted = useCallback((value) => {
12616
- setMutedState(value);
12617
- if (value) {
12618
- for (const [key, pool] of poolsRef.current.entries()) {
12619
- if (manifestRef.current[key]?.loop) {
12620
- for (const audio of pool) {
12621
- if (!audio.paused) audio.pause();
12622
- }
12623
- }
12624
- }
12625
- currentMusicElRef.current?.pause();
12626
- } else {
12627
- for (const [key, pool] of poolsRef.current.entries()) {
12628
- const entry = manifestRef.current[key];
12629
- if (entry?.loop && entry?.autostart) {
12630
- for (const audio of pool) {
12631
- if (audio.paused) audio.play().catch(() => {
12632
- });
12633
- }
12634
- }
12635
- }
12636
- const musicEl = currentMusicElRef.current;
12637
- if (musicEl) {
12638
- musicEl.play().catch(() => {
12639
- });
12640
- }
12641
- }
12642
- }, []);
12643
- const setMasterVolume = useCallback((volume) => {
12644
- const clamped = Math.max(0, Math.min(1, volume));
12645
- setMasterVolumeState(clamped);
12646
- for (const [key, pool] of poolsRef.current.entries()) {
12647
- const entryVol = manifestRef.current[key]?.volume ?? 1;
12648
- for (const audio of pool) {
12649
- audio.volume = Math.min(1, entryVol * clamped);
12650
- }
12651
- }
12652
- if (!musicFadeRef.current && currentMusicElRef.current) {
12653
- const key = currentMusicKeyRef.current;
12654
- const entryVol = key ? manifestRef.current[key]?.volume ?? 1 : 1;
12655
- currentMusicElRef.current.volume = Math.min(1, entryVol * clamped);
12656
- }
12657
- }, []);
12658
- const unlockedRef = useRef(false);
12659
- useEffect(() => {
12660
- const autoKeys = Object.keys(manifest).filter((k) => manifest[k].autostart);
12661
- const hasPendingMusic = () => pendingMusicKeyRef.current !== null;
12662
- const hasAutoStart = autoKeys.length > 0;
12663
- if (!hasAutoStart && !hasPendingMusic()) return;
12664
- const unlock = () => {
12665
- if (unlockedRef.current) return;
12666
- unlockedRef.current = true;
12667
- if (!mutedRef.current) {
12668
- for (const key of autoKeys) {
12669
- play(key);
12670
- }
12671
- const pending = pendingMusicKeyRef.current;
12672
- if (pending && pending !== currentMusicKeyRef.current) {
12673
- playMusic(pending);
12674
- }
12675
- }
12676
- };
12677
- document.addEventListener("click", unlock, { once: true });
12678
- document.addEventListener("keydown", unlock, { once: true });
12679
- document.addEventListener("touchstart", unlock, { once: true });
12680
- return () => {
12681
- document.removeEventListener("click", unlock);
12682
- document.removeEventListener("keydown", unlock);
12683
- document.removeEventListener("touchstart", unlock);
12684
- };
12685
- }, [manifest, play, playMusic]);
12686
- useEffect(() => {
12687
- return () => {
12688
- clearMusicFade();
12689
- for (const pool of poolsRef.current.values()) {
12690
- for (const audio of pool) {
12691
- audio.pause();
12692
- audio.src = "";
12693
- }
12694
- }
12695
- poolsRef.current.clear();
12696
- if (currentMusicElRef.current) {
12697
- currentMusicElRef.current.pause();
12698
- currentMusicElRef.current.src = "";
12699
- currentMusicElRef.current = null;
12700
- }
12701
- };
12702
- }, [clearMusicFade]);
12703
- return {
12704
- play,
12705
- stop,
12706
- stopAll,
12707
- playMusic,
12708
- stopMusic,
12709
- muted,
12710
- setMuted,
12711
- masterVolume,
12712
- setMasterVolume
12713
- };
12714
- }
12715
12458
  var init_useGameAudio = __esm({
12716
12459
  "components/game/shared/hooks/useGameAudio.ts"() {
12717
12460
  "use client";
12718
- useGameAudio.displayName = "useGameAudio";
12719
12461
  }
12720
12462
  });
12721
12463
  function useGameAudioContextOptional() {
12722
12464
  return useContext(GameAudioContext);
12723
12465
  }
12724
- function GameAudioProvider({
12725
- manifest,
12726
- baseUrl = "",
12727
- children,
12728
- initialMuted = false
12729
- }) {
12730
- const eventBus = useEventBus();
12731
- const { play, stop, stopAll, playMusic, stopMusic, muted, setMuted, masterVolume, setMasterVolume } = useGameAudio({ manifest, baseUrl, initialMuted });
12732
- useEffect(() => {
12733
- const unsubPlay = eventBus.on("UI:PLAY_SOUND", (event) => {
12734
- const key = event.payload?.key;
12735
- if (key) play(key);
12736
- });
12737
- const unsubStop = eventBus.on("UI:STOP_SOUND", (event) => {
12738
- const key = event.payload?.key;
12739
- if (key) {
12740
- stop(key);
12741
- } else {
12742
- stopAll();
12743
- }
12744
- });
12745
- const unsubChangeMusic = eventBus.on("UI:CHANGE_MUSIC", (event) => {
12746
- const key = event.payload?.key;
12747
- if (key) {
12748
- playMusic(key);
12749
- } else {
12750
- stopMusic();
12751
- }
12752
- });
12753
- const unsubStopMusic = eventBus.on("UI:STOP_MUSIC", () => {
12754
- stopMusic();
12755
- });
12756
- return () => {
12757
- unsubPlay();
12758
- unsubStop();
12759
- unsubChangeMusic();
12760
- unsubStopMusic();
12761
- };
12762
- }, [eventBus, play, stop, stopAll, playMusic, stopMusic]);
12763
- const value = { muted, setMuted, masterVolume, setMasterVolume, play, playMusic, stopMusic };
12764
- return /* @__PURE__ */ jsx(GameAudioContext.Provider, { value, children });
12765
- }
12766
12466
  var GameAudioContext;
12767
12467
  var init_GameAudioProvider = __esm({
12768
12468
  "components/game/shared/providers/GameAudioProvider.tsx"() {
@@ -12771,7 +12471,6 @@ var init_GameAudioProvider = __esm({
12771
12471
  init_useGameAudio();
12772
12472
  GameAudioContext = createContext(null);
12773
12473
  GameAudioContext.displayName = "GameAudioContext";
12774
- GameAudioProvider.displayName = "GameAudioProvider";
12775
12474
  }
12776
12475
  });
12777
12476
  function GameAudioToggle({
@@ -27291,129 +26990,6 @@ var init_Breadcrumb = __esm({
27291
26990
  Breadcrumb.displayName = "Breadcrumb";
27292
26991
  }
27293
26992
  });
27294
- function useSafeEventBus2() {
27295
- try {
27296
- return useEventBus();
27297
- } catch {
27298
- return { emit: () => {
27299
- }, on: () => () => {
27300
- }, once: () => {
27301
- } };
27302
- }
27303
- }
27304
- var log6, lookStyles4, ButtonGroup;
27305
- var init_ButtonGroup = __esm({
27306
- "components/core/molecules/ButtonGroup.tsx"() {
27307
- "use client";
27308
- init_cn();
27309
- init_atoms();
27310
- init_useEventBus();
27311
- log6 = createLogger("almadar:ui:button-group");
27312
- lookStyles4 = {
27313
- "right-aligned-buttons": "",
27314
- "floating-bar": "fixed bottom-section left-1/2 -translate-x-1/2 shadow-elevation-toast bg-card p-card-sm rounded-container",
27315
- "inline-row": "gap-2 inline-flex",
27316
- "dropdown-menu": "[&>button:not(:first-child)]:hidden",
27317
- "command-palette-trigger": "[&>button:not(:first-child)]:hidden"
27318
- };
27319
- ButtonGroup = ({
27320
- children,
27321
- primary,
27322
- secondary,
27323
- variant = "default",
27324
- orientation = "horizontal",
27325
- className,
27326
- // Filter-group pattern props (entity and filters are used for schema-driven filtering)
27327
- entity: _entity,
27328
- filters,
27329
- look = "right-aligned-buttons"
27330
- }) => {
27331
- const eventBus = useSafeEventBus2();
27332
- const variantClasses2 = {
27333
- default: "gap-0",
27334
- 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",
27335
- 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"
27336
- };
27337
- const orientationClasses = {
27338
- horizontal: "flex-row",
27339
- 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"
27340
- };
27341
- const handleActionClick = (action) => {
27342
- if (action.event) {
27343
- eventBus.emit("UI:DISPATCH", { event: action.event });
27344
- }
27345
- if (action.navigatesTo) {
27346
- eventBus.emit("UI:NAVIGATE", { url: action.navigatesTo });
27347
- }
27348
- };
27349
- const renderFormActions = () => {
27350
- const buttons = [];
27351
- if (secondary) {
27352
- secondary.forEach((action, index) => {
27353
- buttons.push(
27354
- /* @__PURE__ */ jsx(
27355
- Button,
27356
- {
27357
- type: action.actionType === "submit" ? "submit" : "button",
27358
- variant: action.variant || "ghost",
27359
- onClick: () => handleActionClick(action),
27360
- children: action.label
27361
- },
27362
- `secondary-${index}`
27363
- )
27364
- );
27365
- });
27366
- }
27367
- if (primary) {
27368
- const isSubmit = primary.actionType === "submit";
27369
- buttons.push(
27370
- /* @__PURE__ */ jsx(
27371
- Button,
27372
- {
27373
- type: isSubmit ? "submit" : "button",
27374
- variant: primary.variant || "primary",
27375
- onClick: () => handleActionClick(primary),
27376
- "data-testid": isSubmit ? "form-submit" : void 0,
27377
- children: primary.label
27378
- },
27379
- "primary"
27380
- )
27381
- );
27382
- }
27383
- return buttons;
27384
- };
27385
- const renderFilters = () => {
27386
- if (!filters || filters.length === 0) return null;
27387
- return filters.map((filter, index) => /* @__PURE__ */ jsx(
27388
- Button,
27389
- {
27390
- variant: "ghost",
27391
- onClick: () => {
27392
- log6.debug("Filter clicked", { field: filter.field });
27393
- },
27394
- children: filter.label
27395
- },
27396
- `filter-${filter.field}-${index}`
27397
- ));
27398
- };
27399
- return /* @__PURE__ */ jsx(
27400
- "div",
27401
- {
27402
- className: cn(
27403
- "inline-flex gap-2",
27404
- variantClasses2[variant],
27405
- orientationClasses[orientation],
27406
- lookStyles4[look],
27407
- className
27408
- ),
27409
- role: "group",
27410
- children: children || renderFilters() || renderFormActions()
27411
- }
27412
- );
27413
- };
27414
- ButtonGroup.displayName = "ButtonGroup";
27415
- }
27416
- });
27417
26993
  function dayWindowForViewport(width) {
27418
26994
  if (width <= 640) return 1;
27419
26995
  if (width <= 1024) return 3;
@@ -28156,7 +27732,7 @@ var init_CardGrid = __esm({
28156
27732
  CardGrid.displayName = "CardGrid";
28157
27733
  }
28158
27734
  });
28159
- function useSafeEventBus3() {
27735
+ function useSafeEventBus2() {
28160
27736
  try {
28161
27737
  return useEventBus();
28162
27738
  } catch {
@@ -28192,7 +27768,7 @@ var init_Carousel = __esm({
28192
27768
  const [activeIndex, setActiveIndex] = useState(0);
28193
27769
  const scrollRef = useRef(null);
28194
27770
  const autoPlayRef = useRef(null);
28195
- const eventBus = useSafeEventBus3();
27771
+ const eventBus = useSafeEventBus2();
28196
27772
  const { t } = useTranslate();
28197
27773
  const safeItems = items ?? [];
28198
27774
  const totalSlides = safeItems.length;
@@ -31514,7 +31090,7 @@ function DataGrid({
31514
31090
  /* @__PURE__ */ jsx(
31515
31091
  Box,
31516
31092
  {
31517
- className: cn("grid", gapStyles5[gap], scrollX ? "grid-flow-col overflow-x-auto" : colsClass, lookStyles5[look], className),
31093
+ className: cn("grid", gapStyles5[gap], scrollX ? "grid-flow-col overflow-x-auto" : colsClass, lookStyles4[look], className),
31518
31094
  style: scrollX ? { gridAutoFlow: "column", gridAutoColumns: `minmax(${minCardWidth}px, 1fr)` } : gridTemplateColumns ? { gridTemplateColumns } : void 0,
31519
31095
  children: data.map((item, index) => {
31520
31096
  const itemData = item;
@@ -31709,7 +31285,7 @@ function DataGrid({
31709
31285
  ] })
31710
31286
  );
31711
31287
  }
31712
- var dataGridLog, BADGE_VARIANTS, gapStyles5, lookStyles5;
31288
+ var dataGridLog, BADGE_VARIANTS, gapStyles5, lookStyles4;
31713
31289
  var init_DataGrid = __esm({
31714
31290
  "components/core/molecules/DataGrid.tsx"() {
31715
31291
  "use client";
@@ -31744,7 +31320,7 @@ var init_DataGrid = __esm({
31744
31320
  lg: "gap-6",
31745
31321
  xl: "gap-8"
31746
31322
  };
31747
- lookStyles5 = {
31323
+ lookStyles4 = {
31748
31324
  dense: "gap-2 [&>*]:p-card-sm",
31749
31325
  spacious: "gap-8 [&>*]:p-card-lg",
31750
31326
  striped: "[&>*:nth-child(even)]:bg-muted/30",
@@ -32171,6 +31747,133 @@ var init_DataList = __esm({
32171
31747
  DataList.displayName = "DataList";
32172
31748
  }
32173
31749
  });
31750
+ var FormSection, FormLayout, FormActions;
31751
+ var init_FormSection = __esm({
31752
+ "components/core/molecules/FormSection.tsx"() {
31753
+ "use client";
31754
+ init_cn();
31755
+ init_atoms();
31756
+ init_Box();
31757
+ init_Typography();
31758
+ init_Button();
31759
+ init_Stack();
31760
+ init_Icon();
31761
+ init_useEventBus();
31762
+ FormSection = ({
31763
+ title,
31764
+ description,
31765
+ children,
31766
+ collapsible = false,
31767
+ defaultCollapsed = false,
31768
+ card = false,
31769
+ columns = 1,
31770
+ className
31771
+ }) => {
31772
+ const [collapsed, setCollapsed] = React105__default.useState(defaultCollapsed);
31773
+ const { t } = useTranslate();
31774
+ const eventBus = useEventBus();
31775
+ const gridClass = {
31776
+ 1: "grid-cols-1",
31777
+ 2: "grid-cols-1 md:grid-cols-2",
31778
+ 3: "grid-cols-1 md:grid-cols-2 lg:grid-cols-3"
31779
+ }[columns];
31780
+ React105__default.useCallback(() => {
31781
+ if (collapsible) {
31782
+ setCollapsed((prev) => !prev);
31783
+ eventBus.emit("UI:TOGGLE_COLLAPSE", { collapsed: !collapsed });
31784
+ }
31785
+ }, [collapsible, collapsed, eventBus]);
31786
+ const content = /* @__PURE__ */ jsxs(Fragment, { children: [
31787
+ (title || description) && /* @__PURE__ */ jsxs(VStack, { gap: "xs", className: "mb-4", children: [
31788
+ title && /* @__PURE__ */ jsxs(
31789
+ HStack,
31790
+ {
31791
+ justify: "between",
31792
+ align: "center",
31793
+ className: cn(collapsible && "cursor-pointer"),
31794
+ action: collapsible ? "TOGGLE_COLLAPSE" : void 0,
31795
+ children: [
31796
+ /* @__PURE__ */ jsx(Typography, { variant: "h3", weight: "semibold", children: title }),
31797
+ collapsible && /* @__PURE__ */ jsx(
31798
+ Button,
31799
+ {
31800
+ variant: "ghost",
31801
+ size: "sm",
31802
+ action: "TOGGLE_COLLAPSE",
31803
+ children: /* @__PURE__ */ jsx(
31804
+ Icon,
31805
+ {
31806
+ icon: ChevronDown,
31807
+ size: "sm",
31808
+ className: cn(
31809
+ "text-muted-foreground transition-transform",
31810
+ collapsed && "rotate-180"
31811
+ )
31812
+ }
31813
+ )
31814
+ }
31815
+ )
31816
+ ]
31817
+ }
31818
+ ),
31819
+ description && /* @__PURE__ */ jsx(Typography, { variant: "small", color: "secondary", children: description })
31820
+ ] }),
31821
+ (!collapsible || !collapsed) && /* @__PURE__ */ jsx(Box, { className: cn("grid gap-4", gridClass), children })
31822
+ ] });
31823
+ if (card) {
31824
+ return /* @__PURE__ */ jsx(Card, { className: cn("p-6", className), children: content });
31825
+ }
31826
+ return /* @__PURE__ */ jsx(Box, { className, children: content });
31827
+ };
31828
+ FormSection.displayName = "FormSection";
31829
+ FormLayout = ({
31830
+ children,
31831
+ dividers = true,
31832
+ className
31833
+ }) => {
31834
+ return /* @__PURE__ */ jsx(
31835
+ VStack,
31836
+ {
31837
+ gap: "lg",
31838
+ className: cn(
31839
+ dividers && "[&>*+*]:pt-8 [&>*+*]:border-t [&>*+*]:border-border",
31840
+ className
31841
+ ),
31842
+ children
31843
+ }
31844
+ );
31845
+ };
31846
+ FormLayout.displayName = "FormLayout";
31847
+ FormActions = ({
31848
+ children,
31849
+ sticky = false,
31850
+ align = "right",
31851
+ className
31852
+ }) => {
31853
+ const alignClass2 = {
31854
+ left: "justify-start",
31855
+ right: "justify-end",
31856
+ between: "justify-between",
31857
+ center: "justify-center"
31858
+ }[align];
31859
+ return /* @__PURE__ */ jsx(
31860
+ HStack,
31861
+ {
31862
+ gap: "sm",
31863
+ align: "center",
31864
+ className: cn(
31865
+ "pt-6 border-t border-border",
31866
+ alignClass2,
31867
+ sticky && "sticky bottom-0 bg-card py-4 -mx-6 px-6 shadow-[0_-4px_6px_-1px_rgb(0,0,0,0.05)]",
31868
+ className
31869
+ ),
31870
+ children
31871
+ }
31872
+ );
31873
+ };
31874
+ FormActions.displayName = "FormActions";
31875
+ }
31876
+ });
32174
31877
  function fileIcon(name) {
32175
31878
  const ext = name.split(".").pop()?.toLowerCase() ?? "";
32176
31879
  switch (ext) {
@@ -32332,6 +32035,129 @@ var init_FormField = __esm({
32332
32035
  FormField.displayName = "FormField";
32333
32036
  }
32334
32037
  });
32038
+ function useSafeEventBus3() {
32039
+ try {
32040
+ return useEventBus();
32041
+ } catch {
32042
+ return { emit: () => {
32043
+ }, on: () => () => {
32044
+ }, once: () => {
32045
+ } };
32046
+ }
32047
+ }
32048
+ var log6, lookStyles5, ButtonGroup;
32049
+ var init_ButtonGroup = __esm({
32050
+ "components/core/molecules/ButtonGroup.tsx"() {
32051
+ "use client";
32052
+ init_cn();
32053
+ init_atoms();
32054
+ init_useEventBus();
32055
+ log6 = createLogger("almadar:ui:button-group");
32056
+ lookStyles5 = {
32057
+ "right-aligned-buttons": "",
32058
+ "floating-bar": "fixed bottom-section left-1/2 -translate-x-1/2 shadow-elevation-toast bg-card p-card-sm rounded-container",
32059
+ "inline-row": "gap-2 inline-flex",
32060
+ "dropdown-menu": "[&>button:not(:first-child)]:hidden",
32061
+ "command-palette-trigger": "[&>button:not(:first-child)]:hidden"
32062
+ };
32063
+ ButtonGroup = ({
32064
+ children,
32065
+ primary,
32066
+ secondary,
32067
+ variant = "default",
32068
+ orientation = "horizontal",
32069
+ className,
32070
+ // Filter-group pattern props (entity and filters are used for schema-driven filtering)
32071
+ entity: _entity,
32072
+ filters,
32073
+ look = "right-aligned-buttons"
32074
+ }) => {
32075
+ const eventBus = useSafeEventBus3();
32076
+ const variantClasses2 = {
32077
+ default: "gap-0",
32078
+ 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",
32079
+ 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"
32080
+ };
32081
+ const orientationClasses = {
32082
+ horizontal: "flex-row",
32083
+ 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"
32084
+ };
32085
+ const handleActionClick = (action) => {
32086
+ if (action.event) {
32087
+ eventBus.emit("UI:DISPATCH", { event: action.event });
32088
+ }
32089
+ if (action.navigatesTo) {
32090
+ eventBus.emit("UI:NAVIGATE", { url: action.navigatesTo });
32091
+ }
32092
+ };
32093
+ const renderFormActions = () => {
32094
+ const buttons = [];
32095
+ if (secondary) {
32096
+ secondary.forEach((action, index) => {
32097
+ buttons.push(
32098
+ /* @__PURE__ */ jsx(
32099
+ Button,
32100
+ {
32101
+ type: action.actionType === "submit" ? "submit" : "button",
32102
+ variant: action.variant || "ghost",
32103
+ onClick: () => handleActionClick(action),
32104
+ children: action.label
32105
+ },
32106
+ `secondary-${index}`
32107
+ )
32108
+ );
32109
+ });
32110
+ }
32111
+ if (primary) {
32112
+ const isSubmit = primary.actionType === "submit";
32113
+ buttons.push(
32114
+ /* @__PURE__ */ jsx(
32115
+ Button,
32116
+ {
32117
+ type: isSubmit ? "submit" : "button",
32118
+ variant: primary.variant || "primary",
32119
+ onClick: () => handleActionClick(primary),
32120
+ "data-testid": isSubmit ? "form-submit" : void 0,
32121
+ children: primary.label
32122
+ },
32123
+ "primary"
32124
+ )
32125
+ );
32126
+ }
32127
+ return buttons;
32128
+ };
32129
+ const renderFilters = () => {
32130
+ if (!filters || filters.length === 0) return null;
32131
+ return filters.map((filter, index) => /* @__PURE__ */ jsx(
32132
+ Button,
32133
+ {
32134
+ variant: "ghost",
32135
+ onClick: () => {
32136
+ log6.debug("Filter clicked", { field: filter.field });
32137
+ },
32138
+ children: filter.label
32139
+ },
32140
+ `filter-${filter.field}-${index}`
32141
+ ));
32142
+ };
32143
+ return /* @__PURE__ */ jsx(
32144
+ "div",
32145
+ {
32146
+ className: cn(
32147
+ "inline-flex gap-2",
32148
+ variantClasses2[variant],
32149
+ orientationClasses[orientation],
32150
+ lookStyles5[look],
32151
+ className
32152
+ ),
32153
+ role: "group",
32154
+ children: children || renderFilters() || renderFormActions()
32155
+ }
32156
+ );
32157
+ };
32158
+ ButtonGroup.displayName = "ButtonGroup";
32159
+ }
32160
+ });
32335
32161
  var resolveFilterType, lookStyles6, FilterGroup;
32336
32162
  var init_FilterGroup = __esm({
32337
32163
  "components/core/molecules/FilterGroup.tsx"() {
@@ -50709,7 +50535,6 @@ var init_component_registry_generated = __esm({
50709
50535
  init_BranchingLogicBuilder();
50710
50536
  init_Breadcrumb();
50711
50537
  init_BuilderBoard();
50712
- init_ButtonGroup();
50713
50538
  init_CTABanner();
50714
50539
  init_CalendarGrid();
50715
50540
  init_Canvas2D();
@@ -50786,9 +50611,9 @@ var init_component_registry_generated = __esm({
50786
50611
  init_FlipContainer();
50787
50612
  init_FloatingActionButton();
50788
50613
  init_Form();
50614
+ init_FormSection();
50789
50615
  init_FormField();
50790
50616
  init_FormSectionHeader();
50791
- init_GameAudioProvider();
50792
50617
  init_GameAudioToggle();
50793
50618
  init_GameCard();
50794
50619
  init_GameHud();
@@ -51037,7 +50862,6 @@ var init_component_registry_generated = __esm({
51037
50862
  "Breadcrumb": Breadcrumb,
51038
50863
  "BuilderBoard": BuilderBoard,
51039
50864
  "Button": ButtonPattern,
51040
- "ButtonGroup": ButtonGroup,
51041
50865
  "ButtonPattern": ButtonPattern,
51042
50866
  "CTABanner": CTABanner,
51043
50867
  "CalendarGrid": CalendarGrid,
@@ -51117,9 +50941,10 @@ var init_component_registry_generated = __esm({
51117
50941
  "FlipContainer": FlipContainer,
51118
50942
  "FloatingActionButton": FloatingActionButton,
51119
50943
  "Form": Form,
50944
+ "FormActions": FormActions,
51120
50945
  "FormField": FormField,
50946
+ "FormLayout": FormLayout,
51121
50947
  "FormSectionHeader": FormSectionHeader,
51122
- "GameAudioProvider": GameAudioProvider,
51123
50948
  "GameAudioToggle": GameAudioToggle,
51124
50949
  "GameBoard3D": GameBoard3D,
51125
50950
  "GameCanvas3D": GameCanvas3D,