infinity-ui-elements 1.8.45 → 1.8.47

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -2625,18 +2625,18 @@ const ListItem = React__namespace.forwardRef(({ className, type = "single", lead
2625
2625
  });
2626
2626
  ListItem.displayName = "ListItem";
2627
2627
 
2628
- const DropdownMenu = React__namespace.forwardRef(({ items = [], customContent, sectionHeading, isLoading = false, isEmpty = false, emptyTitle = "No Search Results Found", emptyDescription = "Add description of what the user can search for here.", emptyLinkText = "Link to support site", onEmptyLinkClick, primaryButtonText = "Primary", secondaryButtonText = "Secondary", onPrimaryClick, onSecondaryClick, showChevron = false, emptyIcon, disableFooter = false, showFooter, footerLayout = "horizontal", onClose, focusedIndex = -1, className, width = "auto", }, ref) => {
2628
+ const DropdownMenu = React__namespace.forwardRef(({ items = [], customContent, sectionHeading, isLoading = false, isEmpty = false, emptyTitle = "No Search Results Found", emptyDescription = "Add description of what the user can search for here.", emptyLinkText = "Link to support site", onEmptyLinkClick, primaryButtonText = "Primary", secondaryButtonText = "Secondary", onPrimaryClick, onSecondaryClick, showChevron = false, emptyIcon, disableFooter = false, showFooter, footerLayout = "horizontal", onClose, focusedIndex = -1, className, width = "auto", maxHeight = "400px", }, ref) => {
2629
2629
  const renderContent = () => {
2630
2630
  if (isLoading) {
2631
2631
  return (jsxRuntime.jsx("div", { className: "flex flex-col items-center justify-center py-12 px-6", children: jsxRuntime.jsx(lucideReact.Loader2, { className: "w-12 h-12 text-action-ink-primary-normal mb-4 animate-spin" }) }));
2632
2632
  }
2633
2633
  if (customContent) {
2634
- return (jsxRuntime.jsxs("div", { className: "py-3 px-3 max-h-[400px] overflow-y-auto", children: [sectionHeading && (jsxRuntime.jsx(Text, { as: "div", variant: "body", size: "small", weight: "medium", className: "text-body-small-medium text-surface-ink-neutral-muted px-3 py-2 mb-1", children: sectionHeading })), jsxRuntime.jsx("div", { className: "px-1", children: customContent })] }));
2634
+ return (jsxRuntime.jsxs("div", { className: "py-3 px-3 overflow-y-auto", style: { maxHeight }, children: [sectionHeading && (jsxRuntime.jsx(Text, { as: "div", variant: "body", size: "small", weight: "medium", className: "text-body-small-medium text-surface-ink-neutral-muted px-3 py-2 mb-1", children: sectionHeading })), jsxRuntime.jsx("div", { className: "px-1", children: customContent })] }));
2635
2635
  }
2636
2636
  if (isEmpty || items.length === 0) {
2637
2637
  return (jsxRuntime.jsxs("div", { className: "flex flex-col items-center justify-center py-8 px-6 text-center", children: [emptyIcon || (jsxRuntime.jsx(lucideReact.Search, { className: "w-12 h-12 text-surface-ink-neutral-muted mb-4" })), jsxRuntime.jsx(Text, { as: "h3", variant: "body", size: "small", weight: "semibold", className: "text-surface-ink-neutral-normal mb-2", children: emptyTitle }), jsxRuntime.jsx(Text, { as: "p", variant: "body", size: "small", weight: "regular", className: "text-surface-ink-neutral-muted mb-3", children: emptyDescription }), emptyLinkText && (jsxRuntime.jsx(Link, { type: "anchor", color: "primary", size: "small", onClick: onEmptyLinkClick, children: emptyLinkText }))] }));
2638
2638
  }
2639
- return (jsxRuntime.jsxs("div", { className: "py-3 px-3 max-h-[400px] overflow-y-auto", children: [sectionHeading && (jsxRuntime.jsx(Text, { as: "div", variant: "body", size: "small", weight: "medium", className: "text-surface-ink-neutral-muted px-3 py-2 mb-1", children: sectionHeading })), jsxRuntime.jsx("div", { className: "flex flex-col gap-1", children: items.map((item, index) => (jsxRuntime.jsx(ListItem, { title: item.label, description: item.description, leadingIcon: item.leadingIcon, trailingIcon: item.trailingIcon, showChevron: showChevron, isDisabled: item.isDisabled, isSelected: index === focusedIndex, variant: item.variant, onClick: () => {
2639
+ return (jsxRuntime.jsxs("div", { className: "py-3 px-3 overflow-y-auto", style: { maxHeight }, children: [sectionHeading && (jsxRuntime.jsx(Text, { as: "div", variant: "body", size: "small", weight: "medium", className: "text-surface-ink-neutral-muted px-3 py-2 mb-1", children: sectionHeading })), jsxRuntime.jsx("div", { className: "flex flex-col gap-1", children: items.map((item, index) => (jsxRuntime.jsx(ListItem, { title: item.label, description: item.description, leadingIcon: item.leadingIcon, trailingIcon: item.trailingIcon, showChevron: showChevron, isDisabled: item.isDisabled, isSelected: index === focusedIndex, variant: item.variant, onClick: () => {
2640
2640
  item.onClick?.();
2641
2641
  onClose?.();
2642
2642
  }, containerClassName: cn(index === focusedIndex && "bg-action-fill-primary-faded") }, item.value))) })] }));
@@ -2668,6 +2668,14 @@ const Dropdown = React__namespace.forwardRef(({ className, trigger, items = [],
2668
2668
  const [uncontrolledOpen, setUncontrolledOpen] = React__namespace.useState(defaultOpen);
2669
2669
  const isOpen = controlledOpen !== undefined ? controlledOpen : uncontrolledOpen;
2670
2670
  const dropdownRef = React__namespace.useRef(null);
2671
+ const menuRef = React__namespace.useRef(null);
2672
+ const [menuPosition, setMenuPosition] = React__namespace.useState({
2673
+ top: "100%",
2674
+ bottom: "auto",
2675
+ left: "0",
2676
+ right: "auto",
2677
+ maxHeight: "400px",
2678
+ });
2671
2679
  const handleOpenChange = (newOpen) => {
2672
2680
  if (controlledOpen === undefined) {
2673
2681
  setUncontrolledOpen(newOpen);
@@ -2706,12 +2714,92 @@ const Dropdown = React__namespace.forwardRef(({ className, trigger, items = [],
2706
2714
  };
2707
2715
  }
2708
2716
  }, [isOpen]);
2717
+ // Calculate and adjust dropdown position to keep it within viewport
2718
+ React__namespace.useEffect(() => {
2719
+ if (!isOpen || !dropdownRef.current || !menuRef.current)
2720
+ return;
2721
+ const calculatePosition = () => {
2722
+ const triggerRect = dropdownRef.current.getBoundingClientRect();
2723
+ const menuElement = menuRef.current;
2724
+ // Get menu dimensions (use a temporary measurement if needed)
2725
+ const menuRect = menuElement.getBoundingClientRect();
2726
+ const menuHeight = menuRect.height || 400; // fallback to max-height
2727
+ const menuWidth = menuRect.width;
2728
+ const viewportHeight = window.innerHeight;
2729
+ const viewportWidth = window.innerWidth;
2730
+ const spaceBelow = viewportHeight - triggerRect.bottom;
2731
+ const spaceAbove = triggerRect.top;
2732
+ const spaceRight = viewportWidth - triggerRect.left;
2733
+ const spaceLeft = triggerRect.right;
2734
+ const position = {
2735
+ top: "auto",
2736
+ bottom: "auto",
2737
+ left: "auto",
2738
+ right: "auto",
2739
+ maxHeight: "400px",
2740
+ };
2741
+ // Vertical positioning
2742
+ if (spaceBelow >= menuHeight || spaceBelow >= spaceAbove) {
2743
+ // Position below trigger
2744
+ position.top = "100%";
2745
+ position.bottom = "auto";
2746
+ position.maxHeight = `${Math.min(400, spaceBelow - 16)}px`;
2747
+ }
2748
+ else {
2749
+ // Position above trigger
2750
+ position.top = "auto";
2751
+ position.bottom = "100%";
2752
+ position.maxHeight = `${Math.min(400, spaceAbove - 16)}px`;
2753
+ }
2754
+ // Horizontal positioning
2755
+ if (spaceRight >= menuWidth) {
2756
+ // Align to left edge of trigger
2757
+ position.left = "0";
2758
+ position.right = "auto";
2759
+ }
2760
+ else if (spaceLeft >= menuWidth) {
2761
+ // Align to right edge of trigger
2762
+ position.left = "auto";
2763
+ position.right = "0";
2764
+ }
2765
+ else {
2766
+ // Not enough space on either side, try to center or align based on available space
2767
+ if (triggerRect.left + menuWidth > viewportWidth) {
2768
+ position.left = "auto";
2769
+ position.right = "0";
2770
+ }
2771
+ else {
2772
+ position.left = "0";
2773
+ position.right = "auto";
2774
+ }
2775
+ }
2776
+ setMenuPosition(position);
2777
+ };
2778
+ // Calculate position after menu is rendered
2779
+ calculatePosition();
2780
+ // Recalculate on window resize or scroll
2781
+ const handleResize = () => calculatePosition();
2782
+ const handleScroll = () => calculatePosition();
2783
+ window.addEventListener("resize", handleResize);
2784
+ window.addEventListener("scroll", handleScroll, true);
2785
+ return () => {
2786
+ window.removeEventListener("resize", handleResize);
2787
+ window.removeEventListener("scroll", handleScroll, true);
2788
+ };
2789
+ }, [isOpen]);
2709
2790
  const sizeMap = {
2710
2791
  small: "w-64",
2711
2792
  medium: "w-80",
2712
2793
  large: "w-96",
2713
2794
  };
2714
- return (jsxRuntime.jsxs("div", { ref: dropdownRef, className: cn("relative inline-block", containerClassName), ...props, children: [trigger && (jsxRuntime.jsx("div", { onClick: toggleOpen, className: "cursor-pointer", children: trigger })), isOpen && (jsxRuntime.jsx(DropdownMenu, { ref: ref, items: items, customContent: customContent, sectionHeading: sectionHeading, isLoading: isLoading, isEmpty: isEmpty, emptyTitle: emptyTitle, emptyDescription: emptyDescription, emptyLinkText: emptyLinkText, onEmptyLinkClick: onEmptyLinkClick, primaryButtonText: primaryButtonText, secondaryButtonText: secondaryButtonText, onPrimaryClick: onPrimaryClick, onSecondaryClick: onSecondaryClick, showChevron: showChevron, emptyIcon: emptyIcon, disableFooter: disableFooter, showFooter: showFooter, onClose: () => handleOpenChange(false), className: cn("absolute z-50 mt-2", menuClassName, className), width: sizeMap[size] }))] }));
2795
+ return (jsxRuntime.jsxs("div", { ref: dropdownRef, className: cn("relative inline-block", containerClassName), ...props, children: [trigger && (jsxRuntime.jsx("div", { onClick: toggleOpen, className: "cursor-pointer", children: trigger })), isOpen && (jsxRuntime.jsx("div", { ref: menuRef, className: cn("absolute z-50", menuClassName), style: {
2796
+ top: menuPosition.top,
2797
+ bottom: menuPosition.bottom,
2798
+ left: menuPosition.left,
2799
+ right: menuPosition.right,
2800
+ marginTop: menuPosition.top === "100%" ? "0.5rem" : "0",
2801
+ marginBottom: menuPosition.bottom === "100%" ? "0.5rem" : "0",
2802
+ }, children: jsxRuntime.jsx(DropdownMenu, { ref: ref, items: items, customContent: customContent, sectionHeading: sectionHeading, isLoading: isLoading, isEmpty: isEmpty, emptyTitle: emptyTitle, emptyDescription: emptyDescription, emptyLinkText: emptyLinkText, onEmptyLinkClick: onEmptyLinkClick, primaryButtonText: primaryButtonText, secondaryButtonText: secondaryButtonText, onPrimaryClick: onPrimaryClick, onSecondaryClick: onSecondaryClick, showChevron: showChevron, emptyIcon: emptyIcon, disableFooter: disableFooter, showFooter: showFooter, onClose: () => handleOpenChange(false), className: className, width: sizeMap[size], maxHeight: menuPosition.maxHeight }) }))] }));
2715
2803
  });
2716
2804
  Dropdown.displayName = "Dropdown";
2717
2805
 
@@ -3861,6 +3949,10 @@ const SidePanel = React__namespace.forwardRef(({ isOpen, onClose, title, titleIc
3861
3949
  container: "justify-end",
3862
3950
  panel: isVisible ? "animate-slide-in-right" : "animate-slide-out-right",
3863
3951
  },
3952
+ center: {
3953
+ container: "justify-center items-center",
3954
+ panel: isVisible ? "animate-scale-in" : "animate-scale-out",
3955
+ },
3864
3956
  };
3865
3957
  // Handle escape key
3866
3958
  React__namespace.useEffect(() => {
@@ -3899,7 +3991,7 @@ const SidePanel = React__namespace.forwardRef(({ isOpen, onClose, title, titleIc
3899
3991
  const widthClass = width in widthConfig
3900
3992
  ? widthConfig[width]
3901
3993
  : width;
3902
- return (jsxRuntime.jsxs("div", { className: cn("fixed inset-0 z-10000 flex p-4", positionClasses[position].container, className), role: "dialog", "aria-modal": "true", "aria-label": ariaLabel || title, "aria-describedby": ariaDescribedBy, children: [jsxRuntime.jsx("div", { className: cn("absolute inset-0 bg-black/50 backdrop-blur-sm transition-opacity duration-300", isVisible ? "opacity-100" : "opacity-0", overlayClassName), onClick: handleOverlayClick, "aria-hidden": "true" }), jsxRuntime.jsxs("div", { ref: contentRef, className: cn("relative bg-white shadow-2xl transition-transform duration-300 ease-out rounded-large", "flex flex-col max-w-full h-full overflow-hidden", widthClass, positionClasses[position].panel, contentClassName), children: [hasHeader && (jsxRuntime.jsxs("div", { className: cn("flex items-center justify-between gap-4 px-7 py-5 shrink-0 border-b border-surface-outline-neutral-subtle", headerClassName), children: [jsxRuntime.jsxs("div", { className: "flex items-center gap-3 flex-1 min-w-0", children: [titleIcon && (jsxRuntime.jsx("div", { className: "flex items-center justify-center shrink-0", children: typeof titleIcon === "string" ? (jsxRuntime.jsx(Icon, { name: titleIcon, size: 20 })) : (titleIcon) })), jsxRuntime.jsxs("div", { className: "flex flex-col flex-1 min-w-0", children: [title && (jsxRuntime.jsx(Text, { as: "h2", variant: "body", size: "large", weight: "semibold", color: "default", className: "truncate", children: title })), description && (jsxRuntime.jsx(Text, { as: "p", variant: "body", size: "small", weight: "regular", color: "subtle", className: "mt-0.5", children: description }))] })] }), jsxRuntime.jsxs("div", { className: "flex items-center gap-2 shrink-0", children: [headerActions, showCloseButton && onClose && (jsxRuntime.jsx(IconButton, { icon: "close", onClick: onClose, color: "neutral", size: "small", "aria-label": "Close side panel" }))] })] })), !hasHeader && showCloseButton && onClose && (jsxRuntime.jsx("div", { className: "absolute top-4 right-4 z-10", children: jsxRuntime.jsx(IconButton, { icon: "close", onClick: onClose, color: "neutral", size: "small", "aria-label": "Close side panel" }) })), jsxRuntime.jsx("div", { className: cn("flex-1 overflow-y-auto px-6", hasHeader ? "py-6" : "pt-6 pb-4", !footer && "pb-6", bodyClassName), children: children }), footer && (jsxRuntime.jsxs("div", { className: "flex flex-col shrink-0", children: [jsxRuntime.jsx(Divider, { thickness: "thin", variant: "muted" }), jsxRuntime.jsx("div", { className: cn("flex items-center justify-end gap-3 px-6 py-4", footerClassName), children: footer })] }))] })] }));
3994
+ return (jsxRuntime.jsxs("div", { className: cn("fixed inset-0 z-10000 flex p-4", positionClasses[position].container, className), role: "dialog", "aria-modal": "true", "aria-label": ariaLabel || title, "aria-describedby": ariaDescribedBy, children: [jsxRuntime.jsx("div", { className: cn("absolute inset-0 bg-black/50 backdrop-blur-sm transition-opacity duration-300", isVisible ? "opacity-100" : "opacity-0", overlayClassName), onClick: handleOverlayClick, "aria-hidden": "true" }), jsxRuntime.jsxs("div", { ref: contentRef, className: cn("relative bg-white shadow-2xl transition-transform duration-300 ease-out rounded-large", "flex flex-col max-w-full overflow-hidden", position === "center" ? "max-h-[90vh]" : "h-full", widthClass, positionClasses[position].panel, contentClassName), children: [hasHeader && (jsxRuntime.jsxs("div", { className: cn("flex items-center justify-between gap-4 px-7 py-5 shrink-0 border-b border-surface-outline-neutral-subtle", headerClassName), children: [jsxRuntime.jsxs("div", { className: "flex items-center gap-3 flex-1 min-w-0", children: [titleIcon && (jsxRuntime.jsx("div", { className: "flex items-center justify-center shrink-0", children: typeof titleIcon === "string" ? (jsxRuntime.jsx(Icon, { name: titleIcon, size: 20 })) : (titleIcon) })), jsxRuntime.jsxs("div", { className: "flex flex-col flex-1 min-w-0", children: [title && (jsxRuntime.jsx(Text, { as: "h2", variant: "body", size: "large", weight: "semibold", color: "default", className: "truncate", children: title })), description && (jsxRuntime.jsx(Text, { as: "p", variant: "body", size: "small", weight: "regular", color: "subtle", className: "mt-0.5", children: description }))] })] }), jsxRuntime.jsxs("div", { className: "flex items-center gap-2 shrink-0", children: [headerActions, showCloseButton && onClose && (jsxRuntime.jsx(IconButton, { icon: "close", onClick: onClose, color: "neutral", size: "small", "aria-label": "Close side panel" }))] })] })), !hasHeader && showCloseButton && onClose && (jsxRuntime.jsx("div", { className: "absolute top-4 right-4 z-10", children: jsxRuntime.jsx(IconButton, { icon: "close", onClick: onClose, color: "neutral", size: "small", "aria-label": "Close side panel" }) })), jsxRuntime.jsx("div", { className: cn("flex-1 overflow-y-auto px-6", hasHeader ? "py-6" : "pt-6 pb-4", !footer && "pb-6", bodyClassName), children: children }), footer && (jsxRuntime.jsxs("div", { className: "flex flex-col shrink-0", children: [jsxRuntime.jsx(Divider, { thickness: "thin", variant: "muted" }), jsxRuntime.jsx("div", { className: cn("flex items-center justify-end gap-3 px-6 py-4", footerClassName), children: footer })] }))] })] }));
3903
3995
  });
3904
3996
  SidePanel.displayName = "SidePanel";
3905
3997