@almadar/ui 5.29.0 → 5.30.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.
@@ -21544,7 +21544,84 @@ var init_DashboardLayout = __esm({
21544
21544
  NavLinkBottom.displayName = "NavLinkBottom";
21545
21545
  }
21546
21546
  });
21547
- var Menu;
21547
+ function computeMenuStyle(position, triggerRect) {
21548
+ const isTop = position.startsWith("top");
21549
+ const isRight = position.endsWith("right") || position.endsWith("end");
21550
+ if (isTop) {
21551
+ return {
21552
+ top: triggerRect.top - MENU_GAP,
21553
+ transform: "translateY(-100%)",
21554
+ ...isRight ? { right: window.innerWidth - triggerRect.right } : { left: triggerRect.left }
21555
+ };
21556
+ }
21557
+ return {
21558
+ top: triggerRect.bottom + MENU_GAP,
21559
+ ...isRight ? { right: window.innerWidth - triggerRect.right } : { left: triggerRect.left }
21560
+ };
21561
+ }
21562
+ function SubMenu({
21563
+ items,
21564
+ itemRef,
21565
+ direction,
21566
+ eventBus
21567
+ }) {
21568
+ const [rect, setRect] = React79.useState(null);
21569
+ React79.useEffect(() => {
21570
+ if (itemRef) {
21571
+ setRect(itemRef.getBoundingClientRect());
21572
+ }
21573
+ }, [itemRef]);
21574
+ if (!rect) return null;
21575
+ const isRtl = direction === "rtl";
21576
+ const style = {
21577
+ top: rect.top,
21578
+ ...isRtl ? { right: window.innerWidth - rect.left } : { left: rect.right }
21579
+ };
21580
+ const panel = /* @__PURE__ */ jsxRuntime.jsx(
21581
+ "div",
21582
+ {
21583
+ className: cn("fixed z-50", menuContainerStyles),
21584
+ style,
21585
+ children: items.map((item, index) => {
21586
+ const isDivider = item.id === "divider" || item.label === "divider";
21587
+ const itemId = item.id ?? `item-${item.label.toLowerCase().replace(/\s+/g, "-")}-${index}`;
21588
+ const isDanger = item.variant === "danger";
21589
+ if (isDivider) {
21590
+ return /* @__PURE__ */ jsxRuntime.jsx(Divider, { className: "my-1" }, `divider-${index}`);
21591
+ }
21592
+ return /* @__PURE__ */ jsxRuntime.jsxs(
21593
+ Box,
21594
+ {
21595
+ as: "button",
21596
+ onClick: () => {
21597
+ if (item.disabled) return;
21598
+ if (item.event) eventBus.emit(`UI:${item.event}`, { itemId, label: item.label });
21599
+ item.onClick?.();
21600
+ },
21601
+ "aria-disabled": item.disabled || void 0,
21602
+ "data-testid": item.event ? `action-${item.event}` : void 0,
21603
+ className: cn(
21604
+ "w-full flex items-center gap-3 px-4 py-2 text-start",
21605
+ "text-sm transition-colors",
21606
+ "hover:bg-muted focus:outline-none focus:bg-muted",
21607
+ "disabled:opacity-50 disabled:cursor-not-allowed",
21608
+ item.disabled && "cursor-not-allowed",
21609
+ isDanger && "text-error hover:bg-error/10"
21610
+ ),
21611
+ children: [
21612
+ item.icon && (typeof item.icon === "string" ? /* @__PURE__ */ jsxRuntime.jsx(Icon, { name: item.icon, size: "sm", className: "flex-shrink-0" }) : /* @__PURE__ */ jsxRuntime.jsx(Icon, { icon: item.icon, size: "sm", className: "flex-shrink-0" })),
21613
+ /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "small", className: cn("flex-1", isDanger && "text-red-600"), children: item.label }),
21614
+ item.badge !== void 0 && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "ml-auto text-xs font-medium", children: item.badge })
21615
+ ]
21616
+ },
21617
+ itemId
21618
+ );
21619
+ })
21620
+ }
21621
+ );
21622
+ return typeof document !== "undefined" ? reactDom.createPortal(panel, document.body) : panel;
21623
+ }
21624
+ var MENU_GAP, menuContainerStyles, Menu;
21548
21625
  var init_Menu = __esm({
21549
21626
  "components/core/molecules/Menu.tsx"() {
21550
21627
  "use client";
@@ -21555,6 +21632,14 @@ var init_Menu = __esm({
21555
21632
  init_Badge();
21556
21633
  init_cn();
21557
21634
  init_useEventBus();
21635
+ MENU_GAP = 4;
21636
+ menuContainerStyles = cn(
21637
+ "bg-card",
21638
+ "border-[length:var(--border-width)] border-border",
21639
+ "shadow-elevation-popover",
21640
+ "rounded-sm",
21641
+ "min-w-0 sm:min-w-[200px] max-w-[calc(100vw-1rem)] py-1"
21642
+ );
21558
21643
  Menu = ({
21559
21644
  trigger,
21560
21645
  items,
@@ -21562,9 +21647,10 @@ var init_Menu = __esm({
21562
21647
  className
21563
21648
  }) => {
21564
21649
  const eventBus = useEventBus();
21565
- const { t, direction } = hooks.useTranslate();
21650
+ const { direction } = hooks.useTranslate();
21566
21651
  const [isOpen, setIsOpen] = React79.useState(false);
21567
21652
  const [activeSubMenu, setActiveSubMenu] = React79.useState(null);
21653
+ const [activeSubMenuRef, setActiveSubMenuRef] = React79.useState(null);
21568
21654
  const [triggerRect, setTriggerRect] = React79.useState(null);
21569
21655
  const triggerRef = React79.useRef(null);
21570
21656
  const menuRef = React79.useRef(null);
@@ -21579,13 +21665,14 @@ var init_Menu = __esm({
21579
21665
  }
21580
21666
  setIsOpen(!isOpen);
21581
21667
  setActiveSubMenu(null);
21668
+ setActiveSubMenuRef(null);
21582
21669
  };
21583
- const handleItemClick = (item) => {
21670
+ const handleItemClick = (item, itemId) => {
21584
21671
  if (item.disabled) return;
21585
21672
  if (item.subMenu && item.subMenu.length > 0) {
21586
- setActiveSubMenu(item.id ?? null);
21673
+ setActiveSubMenu(itemId);
21587
21674
  } else {
21588
- if (item.event) eventBus.emit(`UI:${item.event}`, { itemId: item.id, label: item.label });
21675
+ if (item.event) eventBus.emit(`UI:${item.event}`, { itemId, label: item.label });
21589
21676
  item.onClick?.();
21590
21677
  setIsOpen(false);
21591
21678
  }
@@ -21600,22 +21687,12 @@ var init_Menu = __esm({
21600
21687
  if (isOpen && menuRef.current && !menuRef.current.contains(e.target) && triggerRef.current && !triggerRef.current.contains(e.target)) {
21601
21688
  setIsOpen(false);
21602
21689
  setActiveSubMenu(null);
21690
+ setActiveSubMenuRef(null);
21603
21691
  }
21604
21692
  };
21605
21693
  document.addEventListener("mousedown", handleClickOutside);
21606
21694
  return () => document.removeEventListener("mousedown", handleClickOutside);
21607
21695
  }, [isOpen]);
21608
- const positionClasses = {
21609
- "top-left": "bottom-full left-0 mb-2",
21610
- "top-right": "bottom-full right-0 mb-2",
21611
- "bottom-left": "top-full left-0 mt-2",
21612
- "bottom-right": "top-full right-0 mt-2",
21613
- // Aliases for pattern compatibility
21614
- "top-start": "bottom-full left-0 mb-2",
21615
- "top-end": "bottom-full right-0 mb-2",
21616
- "bottom-start": "top-full left-0 mt-2",
21617
- "bottom-end": "top-full right-0 mt-2"
21618
- };
21619
21696
  const rtlMirror = {
21620
21697
  "top-left": "top-right",
21621
21698
  "top-right": "top-left",
@@ -21627,7 +21704,6 @@ var init_Menu = __esm({
21627
21704
  "bottom-end": "bottom-start"
21628
21705
  };
21629
21706
  const effectivePosition = direction === "rtl" ? rtlMirror[position] ?? position : position;
21630
- const subMenuSideClass = direction === "rtl" ? "right-full mr-2" : "left-full ml-2";
21631
21707
  const triggerChild = React79__namespace.default.isValidElement(trigger) ? trigger : /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "small", as: "span", children: trigger });
21632
21708
  const triggerElement = React79__namespace.default.cloneElement(
21633
21709
  triggerChild,
@@ -21636,94 +21712,83 @@ var init_Menu = __esm({
21636
21712
  onClick: handleToggle
21637
21713
  }
21638
21714
  );
21639
- const menuContainerStyles = cn(
21640
- "bg-card",
21641
- "border-[length:var(--border-width)] border-border",
21642
- "shadow-elevation-popover",
21643
- "rounded-sm",
21644
- "min-w-0 sm:min-w-[200px] max-w-[calc(100vw-1rem)] py-1"
21645
- );
21646
- const renderMenuItem = (item, hasSubMenu, index) => {
21715
+ const renderMenuItems = (menuItems) => menuItems.map((item, index) => {
21716
+ const isDivider = item.id === "divider" || item.label === "divider";
21647
21717
  const itemId = item.id ?? `item-${item.label.toLowerCase().replace(/\s+/g, "-")}-${index}`;
21718
+ const hasSubMenu = !!(item.subMenu && item.subMenu.length > 0);
21648
21719
  const isDanger = item.variant === "danger";
21649
- return /* @__PURE__ */ jsxRuntime.jsx(
21650
- Box,
21651
- {
21652
- as: "button",
21653
- onClick: () => !item.disabled && handleItemClick({ ...item, id: itemId }),
21654
- "aria-disabled": item.disabled || void 0,
21655
- onMouseEnter: () => hasSubMenu && setActiveSubMenu(itemId),
21656
- "data-testid": item.event ? `action-${item.event}` : void 0,
21657
- className: cn(
21658
- "w-full flex items-center justify-between gap-3 px-4 py-2 text-start",
21659
- "text-sm transition-colors",
21660
- "hover:bg-muted",
21661
- "focus:outline-none focus:bg-muted",
21662
- "disabled:opacity-50 disabled:cursor-not-allowed",
21663
- item.disabled && "cursor-not-allowed",
21664
- isDanger && "text-error hover:bg-error/10"
21665
- ),
21666
- children: /* @__PURE__ */ jsxRuntime.jsxs(Box, { className: "flex items-center gap-3 flex-1 min-w-0", children: [
21667
- item.icon && (typeof item.icon === "string" ? /* @__PURE__ */ jsxRuntime.jsx(Icon, { name: item.icon, size: "sm", className: "flex-shrink-0" }) : /* @__PURE__ */ jsxRuntime.jsx(Icon, { icon: item.icon, size: "sm", className: "flex-shrink-0" })),
21668
- /* @__PURE__ */ jsxRuntime.jsx(
21669
- Typography,
21670
- {
21671
- variant: "small",
21672
- className: cn("flex-1", isDanger && "text-red-600"),
21673
- children: item.label
21720
+ if (isDivider) {
21721
+ return /* @__PURE__ */ jsxRuntime.jsx(Divider, { className: "my-1" }, `divider-${index}`);
21722
+ }
21723
+ return /* @__PURE__ */ jsxRuntime.jsxs(Box, { children: [
21724
+ /* @__PURE__ */ jsxRuntime.jsx(
21725
+ Box,
21726
+ {
21727
+ as: "button",
21728
+ onClick: () => handleItemClick({ ...item, id: itemId }, itemId),
21729
+ "aria-disabled": item.disabled || void 0,
21730
+ onMouseEnter: (e) => {
21731
+ if (hasSubMenu) {
21732
+ setActiveSubMenu(itemId);
21733
+ setActiveSubMenuRef(e.currentTarget);
21674
21734
  }
21735
+ },
21736
+ "data-testid": item.event ? `action-${item.event}` : void 0,
21737
+ className: cn(
21738
+ "w-full flex items-center justify-between gap-3 px-4 py-2 text-start",
21739
+ "text-sm transition-colors",
21740
+ "hover:bg-muted",
21741
+ "focus:outline-none focus:bg-muted",
21742
+ "disabled:opacity-50 disabled:cursor-not-allowed",
21743
+ item.disabled && "cursor-not-allowed",
21744
+ isDanger && "text-error hover:bg-error/10"
21675
21745
  ),
21676
- item.badge !== void 0 && /* @__PURE__ */ jsxRuntime.jsx(Badge, { variant: "default", size: "sm", children: item.badge }),
21677
- hasSubMenu && /* @__PURE__ */ jsxRuntime.jsx(Icon, { name: direction === "rtl" ? "chevron-left" : "chevron-right", size: "sm", className: "flex-shrink-0" })
21678
- ] })
21679
- },
21680
- itemId
21681
- );
21682
- };
21683
- const renderMenuItems = (menuItems) => {
21684
- return menuItems.map((item, index) => {
21685
- const hasSubMenu = item.subMenu && item.subMenu.length > 0;
21686
- const isDivider = item.id === "divider" || item.label === "divider";
21687
- const itemId = item.id ?? `item-${item.label.toLowerCase().replace(/\s+/g, "-")}-${index}`;
21688
- if (isDivider) {
21689
- return /* @__PURE__ */ jsxRuntime.jsx(Divider, { className: "my-1" }, `divider-${index}`);
21690
- }
21691
- return /* @__PURE__ */ jsxRuntime.jsxs(Box, { children: [
21692
- renderMenuItem(item, !!hasSubMenu, index),
21693
- hasSubMenu && activeSubMenu === itemId && item.subMenu && /* @__PURE__ */ jsxRuntime.jsx(
21694
- Box,
21695
- {
21696
- className: cn(
21697
- "absolute top-0 z-50",
21698
- subMenuSideClass,
21699
- menuContainerStyles
21746
+ children: /* @__PURE__ */ jsxRuntime.jsxs(Box, { className: "flex items-center gap-3 flex-1 min-w-0", children: [
21747
+ item.icon && (typeof item.icon === "string" ? /* @__PURE__ */ jsxRuntime.jsx(Icon, { name: item.icon, size: "sm", className: "flex-shrink-0" }) : /* @__PURE__ */ jsxRuntime.jsx(Icon, { icon: item.icon, size: "sm", className: "flex-shrink-0" })),
21748
+ /* @__PURE__ */ jsxRuntime.jsx(
21749
+ Typography,
21750
+ {
21751
+ variant: "small",
21752
+ className: cn("flex-1", isDanger && "text-red-600"),
21753
+ children: item.label
21754
+ }
21700
21755
  ),
21701
- children: renderMenuItems(item.subMenu)
21702
- }
21703
- )
21704
- ] }, itemId);
21705
- });
21706
- };
21707
- return /* @__PURE__ */ jsxRuntime.jsxs(Box, { className: "relative", children: [
21756
+ item.badge !== void 0 && /* @__PURE__ */ jsxRuntime.jsx(Badge, { variant: "default", size: "sm", children: item.badge }),
21757
+ hasSubMenu && /* @__PURE__ */ jsxRuntime.jsx(
21758
+ Icon,
21759
+ {
21760
+ name: direction === "rtl" ? "chevron-left" : "chevron-right",
21761
+ size: "sm",
21762
+ className: "flex-shrink-0"
21763
+ }
21764
+ )
21765
+ ] })
21766
+ }
21767
+ ),
21768
+ hasSubMenu && activeSubMenu === itemId && item.subMenu && /* @__PURE__ */ jsxRuntime.jsx(
21769
+ SubMenu,
21770
+ {
21771
+ items: item.subMenu,
21772
+ itemRef: activeSubMenuRef,
21773
+ direction,
21774
+ eventBus
21775
+ }
21776
+ )
21777
+ ] }, itemId);
21778
+ });
21779
+ const panel = isOpen && triggerRect ? /* @__PURE__ */ jsxRuntime.jsx(
21780
+ "div",
21781
+ {
21782
+ ref: menuRef,
21783
+ className: cn("fixed z-50", menuContainerStyles, className),
21784
+ style: computeMenuStyle(effectivePosition, triggerRect),
21785
+ role: "menu",
21786
+ children: renderMenuItems(items)
21787
+ }
21788
+ ) : null;
21789
+ return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
21708
21790
  triggerElement,
21709
- isOpen && triggerRect && /* @__PURE__ */ jsxRuntime.jsx(
21710
- Box,
21711
- {
21712
- ref: menuRef,
21713
- className: cn(
21714
- "absolute z-50",
21715
- menuContainerStyles,
21716
- positionClasses[effectivePosition],
21717
- className
21718
- ),
21719
- style: {
21720
- left: effectivePosition.includes("left") ? 0 : "auto",
21721
- right: effectivePosition.includes("right") ? 0 : "auto"
21722
- },
21723
- role: "menu",
21724
- children: renderMenuItems(items)
21725
- }
21726
- )
21791
+ panel && typeof document !== "undefined" ? reactDom.createPortal(panel, document.body) : panel
21727
21792
  ] });
21728
21793
  };
21729
21794
  Menu.displayName = "Menu";
@@ -36129,7 +36194,6 @@ var init_DocumentViewer = __esm({
36129
36194
  showPrint = false,
36130
36195
  actions,
36131
36196
  documents,
36132
- entity,
36133
36197
  isLoading = false,
36134
36198
  error,
36135
36199
  className
@@ -42944,7 +43008,7 @@ function TraitSlot({
42944
43008
  size = "md",
42945
43009
  showTooltip = true,
42946
43010
  categoryColors,
42947
- tooltipFrameUrl,
43011
+ tooltipFrameUrl = "",
42948
43012
  className,
42949
43013
  feedback,
42950
43014
  onItemDrop,