@almadar/ui 5.76.7 → 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.
Files changed (62) hide show
  1. package/dist/avl/index.cjs +264 -443
  2. package/dist/avl/index.css +3 -3
  3. package/dist/avl/index.js +265 -444
  4. package/dist/components/core/atoms/FlipContainer.d.ts +1 -1
  5. package/dist/components/core/molecules/Card.d.ts +1 -1
  6. package/dist/components/core/molecules/DataGrid.d.ts +1 -1
  7. package/dist/components/core/molecules/DataList.d.ts +1 -1
  8. package/dist/components/core/molecules/DocPagination.d.ts +1 -8
  9. package/dist/components/core/molecules/DocSearch.d.ts +1 -8
  10. package/dist/components/core/molecules/FlipCard.d.ts +1 -1
  11. package/dist/components/core/molecules/MapView.d.ts +1 -18
  12. package/dist/components/core/molecules/SortableList.d.ts +1 -1
  13. package/dist/components/core/molecules/TableView.d.ts +1 -1
  14. package/dist/components/core/organisms/DataTable.d.ts +1 -1
  15. package/dist/components/core/organisms/debug/RuntimeDebugger.d.ts +1 -10
  16. package/dist/components/core/organisms/debug/tabs/EntitiesTab.d.ts +1 -2
  17. package/dist/components/core/organisms/debug/tabs/EventDispatcherTab.d.ts +1 -2
  18. package/dist/components/core/organisms/debug/tabs/EventFlowTab.d.ts +1 -6
  19. package/dist/components/core/organisms/debug/tabs/GuardsPanel.d.ts +1 -6
  20. package/dist/components/core/organisms/debug/tabs/ServerBridgeTab.d.ts +1 -12
  21. package/dist/components/core/organisms/debug/tabs/TicksTab.d.ts +1 -2
  22. package/dist/components/core/organisms/debug/tabs/TraitsTab.d.ts +1 -2
  23. package/dist/components/core/organisms/debug/tabs/TransitionTimeline.d.ts +1 -11
  24. package/dist/components/core/organisms/debug/tabs/VerificationTab.d.ts +1 -8
  25. package/dist/components/game/2d/atoms/ActionButton.d.ts +1 -2
  26. package/dist/components/game/2d/atoms/ChoiceButton.d.ts +1 -2
  27. package/dist/components/game/2d/atoms/ComboCounter.d.ts +1 -2
  28. package/dist/components/game/2d/atoms/ControlButton.d.ts +1 -2
  29. package/dist/components/game/2d/atoms/DamageNumber.d.ts +1 -2
  30. package/dist/components/game/2d/atoms/DialogueBubble.d.ts +1 -2
  31. package/dist/components/game/2d/atoms/GameIcon.d.ts +1 -2
  32. package/dist/components/game/2d/atoms/HealthBar.d.ts +1 -2
  33. package/dist/components/game/2d/atoms/ItemSlot.d.ts +1 -2
  34. package/dist/components/game/2d/atoms/MiniMap.d.ts +1 -2
  35. package/dist/components/game/2d/atoms/ResourceCounter.d.ts +1 -2
  36. package/dist/components/game/2d/atoms/ScoreDisplay.d.ts +1 -2
  37. package/dist/components/game/2d/atoms/StatusEffect.d.ts +1 -2
  38. package/dist/components/game/2d/atoms/TimerDisplay.d.ts +1 -2
  39. package/dist/components/game/2d/atoms/TurnIndicator.d.ts +1 -2
  40. package/dist/components/game/2d/atoms/WaypointMarker.d.ts +1 -2
  41. package/dist/components/game/2d/molecules/GameHud.d.ts +1 -2
  42. package/dist/components/game/2d/molecules/GameMenu.d.ts +1 -2
  43. package/dist/components/game/2d/molecules/InventoryGrid.d.ts +1 -2
  44. package/dist/components/game/2d/molecules/ResourceBar.d.ts +1 -2
  45. package/dist/components/game/2d/molecules/StatBadge.d.ts +1 -2
  46. package/dist/components/game/shared/lib/editorUtils.d.ts +8 -8
  47. package/dist/components/index.cjs +133 -134
  48. package/dist/components/index.css +3 -3
  49. package/dist/components/index.js +133 -134
  50. package/dist/hooks/useGitHub.d.ts +7 -7
  51. package/dist/marketing/index.cjs +2 -2
  52. package/dist/marketing/index.js +2 -2
  53. package/dist/providers/EventBusProvider.d.ts +1 -1
  54. package/dist/providers/SelectionProvider.d.ts +1 -1
  55. package/dist/providers/ServerBridge.d.ts +1 -1
  56. package/dist/providers/index.cjs +260 -439
  57. package/dist/providers/index.css +3 -3
  58. package/dist/providers/index.js +261 -440
  59. package/dist/runtime/index.cjs +260 -439
  60. package/dist/runtime/index.css +3 -3
  61. package/dist/runtime/index.js +261 -440
  62. package/package.json +2 -2
@@ -12500,318 +12500,14 @@ var init_useCanvasEffects = __esm({
12500
12500
  "use client";
12501
12501
  }
12502
12502
  });
12503
- function pickPath(entry) {
12504
- if (Array.isArray(entry.path)) {
12505
- return entry.path[Math.floor(Math.random() * entry.path.length)];
12506
- }
12507
- return entry.path;
12508
- }
12509
- function useGameAudio({
12510
- manifest,
12511
- baseUrl = "",
12512
- initialMuted = false,
12513
- initialVolume = 1
12514
- }) {
12515
- const [muted, setMutedState] = React105.useState(initialMuted);
12516
- const [masterVolume, setMasterVolumeState] = React105.useState(initialVolume);
12517
- const mutedRef = React105.useRef(muted);
12518
- const volumeRef = React105.useRef(masterVolume);
12519
- const manifestRef = React105.useRef(manifest);
12520
- mutedRef.current = muted;
12521
- volumeRef.current = masterVolume;
12522
- manifestRef.current = manifest;
12523
- const poolsRef = React105.useRef(/* @__PURE__ */ new Map());
12524
- const getOrCreateElement = React105.useCallback((key) => {
12525
- const entry = manifestRef.current[key];
12526
- if (!entry) return null;
12527
- let pool = poolsRef.current.get(key);
12528
- if (!pool) {
12529
- pool = [];
12530
- poolsRef.current.set(key, pool);
12531
- }
12532
- const maxSize = entry.poolSize ?? 1;
12533
- for (const audio of pool) {
12534
- if (audio.paused && (audio.ended || audio.currentTime === 0)) {
12535
- return audio;
12536
- }
12537
- }
12538
- if (pool.length < maxSize) {
12539
- const src = baseUrl + pickPath(entry);
12540
- const audio = new Audio(src);
12541
- audio.loop = entry.loop ?? false;
12542
- pool.push(audio);
12543
- return audio;
12544
- }
12545
- if (!entry.loop) {
12546
- let oldest = pool[0];
12547
- for (const audio of pool) {
12548
- if (audio.currentTime > oldest.currentTime) {
12549
- oldest = audio;
12550
- }
12551
- }
12552
- oldest.pause();
12553
- oldest.currentTime = 0;
12554
- return oldest;
12555
- }
12556
- return null;
12557
- }, [baseUrl]);
12558
- const play = React105.useCallback((key) => {
12559
- if (mutedRef.current) return;
12560
- const entry = manifestRef.current[key];
12561
- if (!entry) return;
12562
- const audio = getOrCreateElement(key);
12563
- if (!audio) return;
12564
- audio.volume = Math.min(1, (entry.volume ?? 1) * volumeRef.current);
12565
- if (!entry.loop) {
12566
- audio.currentTime = 0;
12567
- }
12568
- const promise = audio.play();
12569
- if (promise) {
12570
- promise.catch(() => {
12571
- });
12572
- }
12573
- }, [getOrCreateElement]);
12574
- const stop = React105.useCallback((key) => {
12575
- const pool = poolsRef.current.get(key);
12576
- if (!pool) return;
12577
- for (const audio of pool) {
12578
- audio.pause();
12579
- audio.currentTime = 0;
12580
- }
12581
- }, []);
12582
- const currentMusicKeyRef = React105.useRef(null);
12583
- const currentMusicElRef = React105.useRef(null);
12584
- const musicFadeRef = React105.useRef(null);
12585
- const pendingMusicKeyRef = React105.useRef(null);
12586
- const clearMusicFade = React105.useCallback(() => {
12587
- if (musicFadeRef.current) {
12588
- clearInterval(musicFadeRef.current);
12589
- musicFadeRef.current = null;
12590
- }
12591
- }, []);
12592
- const playMusic = React105.useCallback((key) => {
12593
- if (key === currentMusicKeyRef.current) return;
12594
- pendingMusicKeyRef.current = key;
12595
- const entry = manifestRef.current[key];
12596
- if (!entry) return;
12597
- const fadeDurationMs = entry.crossfadeDurationMs ?? 1500;
12598
- const stepMs = 50;
12599
- const totalSteps = Math.max(1, fadeDurationMs / stepMs);
12600
- const targetVolume = Math.min(1, (entry.volume ?? 1) * volumeRef.current);
12601
- clearMusicFade();
12602
- const src = baseUrl + (Array.isArray(entry.path) ? entry.path[0] : entry.path);
12603
- const incoming = new Audio(src);
12604
- incoming.loop = true;
12605
- incoming.volume = 0;
12606
- const outgoing = currentMusicElRef.current;
12607
- const outgoingStartVol = outgoing?.volume ?? 0;
12608
- currentMusicKeyRef.current = key;
12609
- currentMusicElRef.current = incoming;
12610
- if (!mutedRef.current) {
12611
- incoming.play().catch(() => {
12612
- currentMusicKeyRef.current = null;
12613
- currentMusicElRef.current = outgoing;
12614
- });
12615
- }
12616
- let step = 0;
12617
- musicFadeRef.current = setInterval(() => {
12618
- step++;
12619
- const progress = Math.min(step / totalSteps, 1);
12620
- incoming.volume = Math.min(1, targetVolume * progress);
12621
- if (outgoing) {
12622
- outgoing.volume = Math.max(0, outgoingStartVol * (1 - progress));
12623
- }
12624
- if (progress >= 1) {
12625
- clearMusicFade();
12626
- if (outgoing) {
12627
- outgoing.pause();
12628
- outgoing.src = "";
12629
- }
12630
- }
12631
- }, stepMs);
12632
- }, [baseUrl, clearMusicFade]);
12633
- const stopMusic = React105.useCallback((fadeDurationMs = 1e3) => {
12634
- const outgoing = currentMusicElRef.current;
12635
- if (!outgoing) return;
12636
- currentMusicKeyRef.current = null;
12637
- currentMusicElRef.current = null;
12638
- pendingMusicKeyRef.current = null;
12639
- clearMusicFade();
12640
- const startVolume = outgoing.volume;
12641
- const stepMs = 50;
12642
- const totalSteps = Math.max(1, fadeDurationMs / stepMs);
12643
- let step = 0;
12644
- musicFadeRef.current = setInterval(() => {
12645
- step++;
12646
- const progress = step / totalSteps;
12647
- outgoing.volume = Math.max(0, startVolume * (1 - progress));
12648
- if (progress >= 1) {
12649
- clearMusicFade();
12650
- outgoing.pause();
12651
- outgoing.src = "";
12652
- }
12653
- }, stepMs);
12654
- }, [clearMusicFade]);
12655
- const stopAll = React105.useCallback(() => {
12656
- for (const pool of poolsRef.current.values()) {
12657
- for (const audio of pool) {
12658
- audio.pause();
12659
- audio.currentTime = 0;
12660
- }
12661
- }
12662
- stopMusic(0);
12663
- }, [stopMusic]);
12664
- const setMuted = React105.useCallback((value) => {
12665
- setMutedState(value);
12666
- if (value) {
12667
- for (const [key, pool] of poolsRef.current.entries()) {
12668
- if (manifestRef.current[key]?.loop) {
12669
- for (const audio of pool) {
12670
- if (!audio.paused) audio.pause();
12671
- }
12672
- }
12673
- }
12674
- currentMusicElRef.current?.pause();
12675
- } else {
12676
- for (const [key, pool] of poolsRef.current.entries()) {
12677
- const entry = manifestRef.current[key];
12678
- if (entry?.loop && entry?.autostart) {
12679
- for (const audio of pool) {
12680
- if (audio.paused) audio.play().catch(() => {
12681
- });
12682
- }
12683
- }
12684
- }
12685
- const musicEl = currentMusicElRef.current;
12686
- if (musicEl) {
12687
- musicEl.play().catch(() => {
12688
- });
12689
- }
12690
- }
12691
- }, []);
12692
- const setMasterVolume = React105.useCallback((volume) => {
12693
- const clamped = Math.max(0, Math.min(1, volume));
12694
- setMasterVolumeState(clamped);
12695
- for (const [key, pool] of poolsRef.current.entries()) {
12696
- const entryVol = manifestRef.current[key]?.volume ?? 1;
12697
- for (const audio of pool) {
12698
- audio.volume = Math.min(1, entryVol * clamped);
12699
- }
12700
- }
12701
- if (!musicFadeRef.current && currentMusicElRef.current) {
12702
- const key = currentMusicKeyRef.current;
12703
- const entryVol = key ? manifestRef.current[key]?.volume ?? 1 : 1;
12704
- currentMusicElRef.current.volume = Math.min(1, entryVol * clamped);
12705
- }
12706
- }, []);
12707
- const unlockedRef = React105.useRef(false);
12708
- React105.useEffect(() => {
12709
- const autoKeys = Object.keys(manifest).filter((k) => manifest[k].autostart);
12710
- const hasPendingMusic = () => pendingMusicKeyRef.current !== null;
12711
- const hasAutoStart = autoKeys.length > 0;
12712
- if (!hasAutoStart && !hasPendingMusic()) return;
12713
- const unlock = () => {
12714
- if (unlockedRef.current) return;
12715
- unlockedRef.current = true;
12716
- if (!mutedRef.current) {
12717
- for (const key of autoKeys) {
12718
- play(key);
12719
- }
12720
- const pending = pendingMusicKeyRef.current;
12721
- if (pending && pending !== currentMusicKeyRef.current) {
12722
- playMusic(pending);
12723
- }
12724
- }
12725
- };
12726
- document.addEventListener("click", unlock, { once: true });
12727
- document.addEventListener("keydown", unlock, { once: true });
12728
- document.addEventListener("touchstart", unlock, { once: true });
12729
- return () => {
12730
- document.removeEventListener("click", unlock);
12731
- document.removeEventListener("keydown", unlock);
12732
- document.removeEventListener("touchstart", unlock);
12733
- };
12734
- }, [manifest, play, playMusic]);
12735
- React105.useEffect(() => {
12736
- return () => {
12737
- clearMusicFade();
12738
- for (const pool of poolsRef.current.values()) {
12739
- for (const audio of pool) {
12740
- audio.pause();
12741
- audio.src = "";
12742
- }
12743
- }
12744
- poolsRef.current.clear();
12745
- if (currentMusicElRef.current) {
12746
- currentMusicElRef.current.pause();
12747
- currentMusicElRef.current.src = "";
12748
- currentMusicElRef.current = null;
12749
- }
12750
- };
12751
- }, [clearMusicFade]);
12752
- return {
12753
- play,
12754
- stop,
12755
- stopAll,
12756
- playMusic,
12757
- stopMusic,
12758
- muted,
12759
- setMuted,
12760
- masterVolume,
12761
- setMasterVolume
12762
- };
12763
- }
12764
12503
  var init_useGameAudio = __esm({
12765
12504
  "components/game/shared/hooks/useGameAudio.ts"() {
12766
12505
  "use client";
12767
- useGameAudio.displayName = "useGameAudio";
12768
12506
  }
12769
12507
  });
12770
12508
  function useGameAudioContextOptional() {
12771
12509
  return React105.useContext(GameAudioContext);
12772
12510
  }
12773
- function GameAudioProvider({
12774
- manifest,
12775
- baseUrl = "",
12776
- children,
12777
- initialMuted = false
12778
- }) {
12779
- const eventBus = useEventBus();
12780
- const { play, stop, stopAll, playMusic, stopMusic, muted, setMuted, masterVolume, setMasterVolume } = useGameAudio({ manifest, baseUrl, initialMuted });
12781
- React105.useEffect(() => {
12782
- const unsubPlay = eventBus.on("UI:PLAY_SOUND", (event) => {
12783
- const key = event.payload?.key;
12784
- if (key) play(key);
12785
- });
12786
- const unsubStop = eventBus.on("UI:STOP_SOUND", (event) => {
12787
- const key = event.payload?.key;
12788
- if (key) {
12789
- stop(key);
12790
- } else {
12791
- stopAll();
12792
- }
12793
- });
12794
- const unsubChangeMusic = eventBus.on("UI:CHANGE_MUSIC", (event) => {
12795
- const key = event.payload?.key;
12796
- if (key) {
12797
- playMusic(key);
12798
- } else {
12799
- stopMusic();
12800
- }
12801
- });
12802
- const unsubStopMusic = eventBus.on("UI:STOP_MUSIC", () => {
12803
- stopMusic();
12804
- });
12805
- return () => {
12806
- unsubPlay();
12807
- unsubStop();
12808
- unsubChangeMusic();
12809
- unsubStopMusic();
12810
- };
12811
- }, [eventBus, play, stop, stopAll, playMusic, stopMusic]);
12812
- const value = { muted, setMuted, masterVolume, setMasterVolume, play, playMusic, stopMusic };
12813
- return /* @__PURE__ */ jsxRuntime.jsx(GameAudioContext.Provider, { value, children });
12814
- }
12815
12511
  var GameAudioContext;
12816
12512
  var init_GameAudioProvider = __esm({
12817
12513
  "components/game/shared/providers/GameAudioProvider.tsx"() {
@@ -12820,7 +12516,6 @@ var init_GameAudioProvider = __esm({
12820
12516
  init_useGameAudio();
12821
12517
  GameAudioContext = React105.createContext(null);
12822
12518
  GameAudioContext.displayName = "GameAudioContext";
12823
- GameAudioProvider.displayName = "GameAudioProvider";
12824
12519
  }
12825
12520
  });
12826
12521
  function GameAudioToggle({
@@ -22995,9 +22690,9 @@ var init_BehaviorView = __esm({
22995
22690
  }
22996
22691
  });
22997
22692
 
22998
- // node_modules/.pnpm/katex@0.16.47/node_modules/katex/dist/katex.min.css
22693
+ // node_modules/katex/dist/katex.min.css
22999
22694
  var init_katex_min = __esm({
23000
- "node_modules/.pnpm/katex@0.16.47/node_modules/katex/dist/katex.min.css"() {
22695
+ "node_modules/katex/dist/katex.min.css"() {
23001
22696
  }
23002
22697
  });
23003
22698
  var Tabs;
@@ -27340,129 +27035,6 @@ var init_Breadcrumb = __esm({
27340
27035
  Breadcrumb.displayName = "Breadcrumb";
27341
27036
  }
27342
27037
  });
27343
- function useSafeEventBus2() {
27344
- try {
27345
- return useEventBus();
27346
- } catch {
27347
- return { emit: () => {
27348
- }, on: () => () => {
27349
- }, once: () => {
27350
- } };
27351
- }
27352
- }
27353
- var log6, lookStyles4, ButtonGroup;
27354
- var init_ButtonGroup = __esm({
27355
- "components/core/molecules/ButtonGroup.tsx"() {
27356
- "use client";
27357
- init_cn();
27358
- init_atoms();
27359
- init_useEventBus();
27360
- log6 = logger.createLogger("almadar:ui:button-group");
27361
- lookStyles4 = {
27362
- "right-aligned-buttons": "",
27363
- "floating-bar": "fixed bottom-section left-1/2 -translate-x-1/2 shadow-elevation-toast bg-card p-card-sm rounded-container",
27364
- "inline-row": "gap-2 inline-flex",
27365
- "dropdown-menu": "[&>button:not(:first-child)]:hidden",
27366
- "command-palette-trigger": "[&>button:not(:first-child)]:hidden"
27367
- };
27368
- ButtonGroup = ({
27369
- children,
27370
- primary,
27371
- secondary,
27372
- variant = "default",
27373
- orientation = "horizontal",
27374
- className,
27375
- // Filter-group pattern props (entity and filters are used for schema-driven filtering)
27376
- entity: _entity,
27377
- filters,
27378
- look = "right-aligned-buttons"
27379
- }) => {
27380
- const eventBus = useSafeEventBus2();
27381
- const variantClasses2 = {
27382
- default: "gap-0",
27383
- 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",
27384
- 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"
27385
- };
27386
- const orientationClasses = {
27387
- horizontal: "flex-row",
27388
- 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"
27389
- };
27390
- const handleActionClick = (action) => {
27391
- if (action.event) {
27392
- eventBus.emit("UI:DISPATCH", { event: action.event });
27393
- }
27394
- if (action.navigatesTo) {
27395
- eventBus.emit("UI:NAVIGATE", { url: action.navigatesTo });
27396
- }
27397
- };
27398
- const renderFormActions = () => {
27399
- const buttons = [];
27400
- if (secondary) {
27401
- secondary.forEach((action, index) => {
27402
- buttons.push(
27403
- /* @__PURE__ */ jsxRuntime.jsx(
27404
- Button,
27405
- {
27406
- type: action.actionType === "submit" ? "submit" : "button",
27407
- variant: action.variant || "ghost",
27408
- onClick: () => handleActionClick(action),
27409
- children: action.label
27410
- },
27411
- `secondary-${index}`
27412
- )
27413
- );
27414
- });
27415
- }
27416
- if (primary) {
27417
- const isSubmit = primary.actionType === "submit";
27418
- buttons.push(
27419
- /* @__PURE__ */ jsxRuntime.jsx(
27420
- Button,
27421
- {
27422
- type: isSubmit ? "submit" : "button",
27423
- variant: primary.variant || "primary",
27424
- onClick: () => handleActionClick(primary),
27425
- "data-testid": isSubmit ? "form-submit" : void 0,
27426
- children: primary.label
27427
- },
27428
- "primary"
27429
- )
27430
- );
27431
- }
27432
- return buttons;
27433
- };
27434
- const renderFilters = () => {
27435
- if (!filters || filters.length === 0) return null;
27436
- return filters.map((filter, index) => /* @__PURE__ */ jsxRuntime.jsx(
27437
- Button,
27438
- {
27439
- variant: "ghost",
27440
- onClick: () => {
27441
- log6.debug("Filter clicked", { field: filter.field });
27442
- },
27443
- children: filter.label
27444
- },
27445
- `filter-${filter.field}-${index}`
27446
- ));
27447
- };
27448
- return /* @__PURE__ */ jsxRuntime.jsx(
27449
- "div",
27450
- {
27451
- className: cn(
27452
- "inline-flex gap-2",
27453
- variantClasses2[variant],
27454
- orientationClasses[orientation],
27455
- lookStyles4[look],
27456
- className
27457
- ),
27458
- role: "group",
27459
- children: children || renderFilters() || renderFormActions()
27460
- }
27461
- );
27462
- };
27463
- ButtonGroup.displayName = "ButtonGroup";
27464
- }
27465
- });
27466
27038
  function dayWindowForViewport(width) {
27467
27039
  if (width <= 640) return 1;
27468
27040
  if (width <= 1024) return 3;
@@ -28205,7 +27777,7 @@ var init_CardGrid = __esm({
28205
27777
  CardGrid.displayName = "CardGrid";
28206
27778
  }
28207
27779
  });
28208
- function useSafeEventBus3() {
27780
+ function useSafeEventBus2() {
28209
27781
  try {
28210
27782
  return useEventBus();
28211
27783
  } catch {
@@ -28241,7 +27813,7 @@ var init_Carousel = __esm({
28241
27813
  const [activeIndex, setActiveIndex] = React105.useState(0);
28242
27814
  const scrollRef = React105.useRef(null);
28243
27815
  const autoPlayRef = React105.useRef(null);
28244
- const eventBus = useSafeEventBus3();
27816
+ const eventBus = useSafeEventBus2();
28245
27817
  const { t } = hooks.useTranslate();
28246
27818
  const safeItems = items ?? [];
28247
27819
  const totalSlides = safeItems.length;
@@ -31563,7 +31135,7 @@ function DataGrid({
31563
31135
  /* @__PURE__ */ jsxRuntime.jsx(
31564
31136
  Box,
31565
31137
  {
31566
- className: cn("grid", gapStyles5[gap], scrollX ? "grid-flow-col overflow-x-auto" : colsClass, lookStyles5[look], className),
31138
+ className: cn("grid", gapStyles5[gap], scrollX ? "grid-flow-col overflow-x-auto" : colsClass, lookStyles4[look], className),
31567
31139
  style: scrollX ? { gridAutoFlow: "column", gridAutoColumns: `minmax(${minCardWidth}px, 1fr)` } : gridTemplateColumns ? { gridTemplateColumns } : void 0,
31568
31140
  children: data.map((item, index) => {
31569
31141
  const itemData = item;
@@ -31758,7 +31330,7 @@ function DataGrid({
31758
31330
  ] })
31759
31331
  );
31760
31332
  }
31761
- var dataGridLog, BADGE_VARIANTS, gapStyles5, lookStyles5;
31333
+ var dataGridLog, BADGE_VARIANTS, gapStyles5, lookStyles4;
31762
31334
  var init_DataGrid = __esm({
31763
31335
  "components/core/molecules/DataGrid.tsx"() {
31764
31336
  "use client";
@@ -31793,7 +31365,7 @@ var init_DataGrid = __esm({
31793
31365
  lg: "gap-6",
31794
31366
  xl: "gap-8"
31795
31367
  };
31796
- lookStyles5 = {
31368
+ lookStyles4 = {
31797
31369
  dense: "gap-2 [&>*]:p-card-sm",
31798
31370
  spacious: "gap-8 [&>*]:p-card-lg",
31799
31371
  striped: "[&>*:nth-child(even)]:bg-muted/30",
@@ -32220,6 +31792,133 @@ var init_DataList = __esm({
32220
31792
  DataList.displayName = "DataList";
32221
31793
  }
32222
31794
  });
31795
+ var FormSection, FormLayout, FormActions;
31796
+ var init_FormSection = __esm({
31797
+ "components/core/molecules/FormSection.tsx"() {
31798
+ "use client";
31799
+ init_cn();
31800
+ init_atoms();
31801
+ init_Box();
31802
+ init_Typography();
31803
+ init_Button();
31804
+ init_Stack();
31805
+ init_Icon();
31806
+ init_useEventBus();
31807
+ FormSection = ({
31808
+ title,
31809
+ description,
31810
+ children,
31811
+ collapsible = false,
31812
+ defaultCollapsed = false,
31813
+ card = false,
31814
+ columns = 1,
31815
+ className
31816
+ }) => {
31817
+ const [collapsed, setCollapsed] = React105__namespace.default.useState(defaultCollapsed);
31818
+ const { t } = hooks.useTranslate();
31819
+ const eventBus = useEventBus();
31820
+ const gridClass = {
31821
+ 1: "grid-cols-1",
31822
+ 2: "grid-cols-1 md:grid-cols-2",
31823
+ 3: "grid-cols-1 md:grid-cols-2 lg:grid-cols-3"
31824
+ }[columns];
31825
+ React105__namespace.default.useCallback(() => {
31826
+ if (collapsible) {
31827
+ setCollapsed((prev) => !prev);
31828
+ eventBus.emit("UI:TOGGLE_COLLAPSE", { collapsed: !collapsed });
31829
+ }
31830
+ }, [collapsible, collapsed, eventBus]);
31831
+ const content = /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
31832
+ (title || description) && /* @__PURE__ */ jsxRuntime.jsxs(VStack, { gap: "xs", className: "mb-4", children: [
31833
+ title && /* @__PURE__ */ jsxRuntime.jsxs(
31834
+ HStack,
31835
+ {
31836
+ justify: "between",
31837
+ align: "center",
31838
+ className: cn(collapsible && "cursor-pointer"),
31839
+ action: collapsible ? "TOGGLE_COLLAPSE" : void 0,
31840
+ children: [
31841
+ /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "h3", weight: "semibold", children: title }),
31842
+ collapsible && /* @__PURE__ */ jsxRuntime.jsx(
31843
+ Button,
31844
+ {
31845
+ variant: "ghost",
31846
+ size: "sm",
31847
+ action: "TOGGLE_COLLAPSE",
31848
+ children: /* @__PURE__ */ jsxRuntime.jsx(
31849
+ Icon,
31850
+ {
31851
+ icon: LucideIcons2.ChevronDown,
31852
+ size: "sm",
31853
+ className: cn(
31854
+ "text-muted-foreground transition-transform",
31855
+ collapsed && "rotate-180"
31856
+ )
31857
+ }
31858
+ )
31859
+ }
31860
+ )
31861
+ ]
31862
+ }
31863
+ ),
31864
+ description && /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "small", color: "secondary", children: description })
31865
+ ] }),
31866
+ (!collapsible || !collapsed) && /* @__PURE__ */ jsxRuntime.jsx(Box, { className: cn("grid gap-4", gridClass), children })
31867
+ ] });
31868
+ if (card) {
31869
+ return /* @__PURE__ */ jsxRuntime.jsx(Card, { className: cn("p-6", className), children: content });
31870
+ }
31871
+ return /* @__PURE__ */ jsxRuntime.jsx(Box, { className, children: content });
31872
+ };
31873
+ FormSection.displayName = "FormSection";
31874
+ FormLayout = ({
31875
+ children,
31876
+ dividers = true,
31877
+ className
31878
+ }) => {
31879
+ return /* @__PURE__ */ jsxRuntime.jsx(
31880
+ VStack,
31881
+ {
31882
+ gap: "lg",
31883
+ className: cn(
31884
+ dividers && "[&>*+*]:pt-8 [&>*+*]:border-t [&>*+*]:border-border",
31885
+ className
31886
+ ),
31887
+ children
31888
+ }
31889
+ );
31890
+ };
31891
+ FormLayout.displayName = "FormLayout";
31892
+ FormActions = ({
31893
+ children,
31894
+ sticky = false,
31895
+ align = "right",
31896
+ className
31897
+ }) => {
31898
+ const alignClass2 = {
31899
+ left: "justify-start",
31900
+ right: "justify-end",
31901
+ between: "justify-between",
31902
+ center: "justify-center"
31903
+ }[align];
31904
+ return /* @__PURE__ */ jsxRuntime.jsx(
31905
+ HStack,
31906
+ {
31907
+ gap: "sm",
31908
+ align: "center",
31909
+ className: cn(
31910
+ "pt-6 border-t border-border",
31911
+ alignClass2,
31912
+ sticky && "sticky bottom-0 bg-card py-4 -mx-6 px-6 shadow-[0_-4px_6px_-1px_rgb(0,0,0,0.05)]",
31913
+ className
31914
+ ),
31915
+ children
31916
+ }
31917
+ );
31918
+ };
31919
+ FormActions.displayName = "FormActions";
31920
+ }
31921
+ });
32223
31922
  function fileIcon(name) {
32224
31923
  const ext = name.split(".").pop()?.toLowerCase() ?? "";
32225
31924
  switch (ext) {
@@ -32381,6 +32080,129 @@ var init_FormField = __esm({
32381
32080
  FormField.displayName = "FormField";
32382
32081
  }
32383
32082
  });
32083
+ function useSafeEventBus3() {
32084
+ try {
32085
+ return useEventBus();
32086
+ } catch {
32087
+ return { emit: () => {
32088
+ }, on: () => () => {
32089
+ }, once: () => {
32090
+ } };
32091
+ }
32092
+ }
32093
+ var log6, lookStyles5, ButtonGroup;
32094
+ var init_ButtonGroup = __esm({
32095
+ "components/core/molecules/ButtonGroup.tsx"() {
32096
+ "use client";
32097
+ init_cn();
32098
+ init_atoms();
32099
+ init_useEventBus();
32100
+ log6 = logger.createLogger("almadar:ui:button-group");
32101
+ lookStyles5 = {
32102
+ "right-aligned-buttons": "",
32103
+ "floating-bar": "fixed bottom-section left-1/2 -translate-x-1/2 shadow-elevation-toast bg-card p-card-sm rounded-container",
32104
+ "inline-row": "gap-2 inline-flex",
32105
+ "dropdown-menu": "[&>button:not(:first-child)]:hidden",
32106
+ "command-palette-trigger": "[&>button:not(:first-child)]:hidden"
32107
+ };
32108
+ ButtonGroup = ({
32109
+ children,
32110
+ primary,
32111
+ secondary,
32112
+ variant = "default",
32113
+ orientation = "horizontal",
32114
+ className,
32115
+ // Filter-group pattern props (entity and filters are used for schema-driven filtering)
32116
+ entity: _entity,
32117
+ filters,
32118
+ look = "right-aligned-buttons"
32119
+ }) => {
32120
+ const eventBus = useSafeEventBus3();
32121
+ const variantClasses2 = {
32122
+ default: "gap-0",
32123
+ 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",
32124
+ 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"
32125
+ };
32126
+ const orientationClasses = {
32127
+ horizontal: "flex-row",
32128
+ 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"
32129
+ };
32130
+ const handleActionClick = (action) => {
32131
+ if (action.event) {
32132
+ eventBus.emit("UI:DISPATCH", { event: action.event });
32133
+ }
32134
+ if (action.navigatesTo) {
32135
+ eventBus.emit("UI:NAVIGATE", { url: action.navigatesTo });
32136
+ }
32137
+ };
32138
+ const renderFormActions = () => {
32139
+ const buttons = [];
32140
+ if (secondary) {
32141
+ secondary.forEach((action, index) => {
32142
+ buttons.push(
32143
+ /* @__PURE__ */ jsxRuntime.jsx(
32144
+ Button,
32145
+ {
32146
+ type: action.actionType === "submit" ? "submit" : "button",
32147
+ variant: action.variant || "ghost",
32148
+ onClick: () => handleActionClick(action),
32149
+ children: action.label
32150
+ },
32151
+ `secondary-${index}`
32152
+ )
32153
+ );
32154
+ });
32155
+ }
32156
+ if (primary) {
32157
+ const isSubmit = primary.actionType === "submit";
32158
+ buttons.push(
32159
+ /* @__PURE__ */ jsxRuntime.jsx(
32160
+ Button,
32161
+ {
32162
+ type: isSubmit ? "submit" : "button",
32163
+ variant: primary.variant || "primary",
32164
+ onClick: () => handleActionClick(primary),
32165
+ "data-testid": isSubmit ? "form-submit" : void 0,
32166
+ children: primary.label
32167
+ },
32168
+ "primary"
32169
+ )
32170
+ );
32171
+ }
32172
+ return buttons;
32173
+ };
32174
+ const renderFilters = () => {
32175
+ if (!filters || filters.length === 0) return null;
32176
+ return filters.map((filter, index) => /* @__PURE__ */ jsxRuntime.jsx(
32177
+ Button,
32178
+ {
32179
+ variant: "ghost",
32180
+ onClick: () => {
32181
+ log6.debug("Filter clicked", { field: filter.field });
32182
+ },
32183
+ children: filter.label
32184
+ },
32185
+ `filter-${filter.field}-${index}`
32186
+ ));
32187
+ };
32188
+ return /* @__PURE__ */ jsxRuntime.jsx(
32189
+ "div",
32190
+ {
32191
+ className: cn(
32192
+ "inline-flex gap-2",
32193
+ variantClasses2[variant],
32194
+ orientationClasses[orientation],
32195
+ lookStyles5[look],
32196
+ className
32197
+ ),
32198
+ role: "group",
32199
+ children: children || renderFilters() || renderFormActions()
32200
+ }
32201
+ );
32202
+ };
32203
+ ButtonGroup.displayName = "ButtonGroup";
32204
+ }
32205
+ });
32384
32206
  var resolveFilterType, lookStyles6, FilterGroup;
32385
32207
  var init_FilterGroup = __esm({
32386
32208
  "components/core/molecules/FilterGroup.tsx"() {
@@ -50758,7 +50580,6 @@ var init_component_registry_generated = __esm({
50758
50580
  init_BranchingLogicBuilder();
50759
50581
  init_Breadcrumb();
50760
50582
  init_BuilderBoard();
50761
- init_ButtonGroup();
50762
50583
  init_CTABanner();
50763
50584
  init_CalendarGrid();
50764
50585
  init_Canvas2D();
@@ -50835,9 +50656,9 @@ var init_component_registry_generated = __esm({
50835
50656
  init_FlipContainer();
50836
50657
  init_FloatingActionButton();
50837
50658
  init_Form();
50659
+ init_FormSection();
50838
50660
  init_FormField();
50839
50661
  init_FormSectionHeader();
50840
- init_GameAudioProvider();
50841
50662
  init_GameAudioToggle();
50842
50663
  init_GameCard();
50843
50664
  init_GameHud();
@@ -51086,7 +50907,6 @@ var init_component_registry_generated = __esm({
51086
50907
  "Breadcrumb": Breadcrumb,
51087
50908
  "BuilderBoard": BuilderBoard,
51088
50909
  "Button": ButtonPattern,
51089
- "ButtonGroup": ButtonGroup,
51090
50910
  "ButtonPattern": ButtonPattern,
51091
50911
  "CTABanner": CTABanner,
51092
50912
  "CalendarGrid": CalendarGrid,
@@ -51166,9 +50986,10 @@ var init_component_registry_generated = __esm({
51166
50986
  "FlipContainer": FlipContainer,
51167
50987
  "FloatingActionButton": FloatingActionButton,
51168
50988
  "Form": Form,
50989
+ "FormActions": FormActions,
51169
50990
  "FormField": FormField,
50991
+ "FormLayout": FormLayout,
51170
50992
  "FormSectionHeader": FormSectionHeader,
51171
- "GameAudioProvider": GameAudioProvider,
51172
50993
  "GameAudioToggle": GameAudioToggle,
51173
50994
  "GameBoard3D": GameBoard3D,
51174
50995
  "GameCanvas3D": GameCanvas3D,