infinity-ui-elements 1.8.44 → 1.8.46
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/components/Dropdown/Dropdown.d.ts.map +1 -1
- package/dist/components/Dropdown/Dropdown.stories.d.ts +8 -0
- package/dist/components/Dropdown/Dropdown.stories.d.ts.map +1 -1
- package/dist/components/Dropdown/DropdownMenu.d.ts +4 -0
- package/dist/components/Dropdown/DropdownMenu.d.ts.map +1 -1
- package/dist/components/SidePanel/SidePanel.d.ts.map +1 -1
- package/dist/index.css +1 -1
- package/dist/index.esm.js +117 -9
- package/dist/index.esm.js.map +1 -1
- package/dist/index.js +117 -9
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
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
|
|
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
|
|
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(
|
|
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
|
|
|
@@ -3824,6 +3912,8 @@ SearchableDropdown.displayName = "SearchableDropdown";
|
|
|
3824
3912
|
const SidePanel = React__namespace.forwardRef(({ isOpen, onClose, title, titleIcon, description, footer, children, position = "right", width = "medium", showCloseButton = true, headerActions, closeOnOverlayClick = true, closeOnEscape = true, className, contentClassName, headerClassName, bodyClassName, footerClassName, overlayClassName, ariaLabel, ariaDescribedBy, }, ref) => {
|
|
3825
3913
|
const panelRef = React__namespace.useRef(null);
|
|
3826
3914
|
const contentRef = ref || panelRef;
|
|
3915
|
+
const [isVisible, setIsVisible] = React__namespace.useState(false);
|
|
3916
|
+
const [shouldRender, setShouldRender] = React__namespace.useState(false);
|
|
3827
3917
|
// Width configurations
|
|
3828
3918
|
const widthConfig = {
|
|
3829
3919
|
small: "w-80",
|
|
@@ -3831,15 +3921,33 @@ const SidePanel = React__namespace.forwardRef(({ isOpen, onClose, title, titleIc
|
|
|
3831
3921
|
large: "w-[32rem]",
|
|
3832
3922
|
xlarge: "w-[40rem]",
|
|
3833
3923
|
};
|
|
3924
|
+
// Handle mounting and unmounting with animation
|
|
3925
|
+
React__namespace.useEffect(() => {
|
|
3926
|
+
if (isOpen) {
|
|
3927
|
+
setShouldRender(true);
|
|
3928
|
+
// Small delay to trigger animation
|
|
3929
|
+
requestAnimationFrame(() => {
|
|
3930
|
+
setIsVisible(true);
|
|
3931
|
+
});
|
|
3932
|
+
}
|
|
3933
|
+
else {
|
|
3934
|
+
setIsVisible(false);
|
|
3935
|
+
// Wait for animation to complete before unmounting
|
|
3936
|
+
const timer = setTimeout(() => {
|
|
3937
|
+
setShouldRender(false);
|
|
3938
|
+
}, 300); // Match animation duration
|
|
3939
|
+
return () => clearTimeout(timer);
|
|
3940
|
+
}
|
|
3941
|
+
}, [isOpen]);
|
|
3834
3942
|
// Position-based classes
|
|
3835
3943
|
const positionClasses = {
|
|
3836
3944
|
left: {
|
|
3837
3945
|
container: "justify-start",
|
|
3838
|
-
panel:
|
|
3946
|
+
panel: isVisible ? "animate-slide-in-left" : "animate-slide-out-left",
|
|
3839
3947
|
},
|
|
3840
3948
|
right: {
|
|
3841
3949
|
container: "justify-end",
|
|
3842
|
-
panel:
|
|
3950
|
+
panel: isVisible ? "animate-slide-in-right" : "animate-slide-out-right",
|
|
3843
3951
|
},
|
|
3844
3952
|
};
|
|
3845
3953
|
// Handle escape key
|
|
@@ -3872,14 +3980,14 @@ const SidePanel = React__namespace.forwardRef(({ isOpen, onClose, title, titleIc
|
|
|
3872
3980
|
onClose();
|
|
3873
3981
|
}
|
|
3874
3982
|
};
|
|
3875
|
-
// Don't render if not open
|
|
3876
|
-
if (!
|
|
3983
|
+
// Don't render if not open and animation is complete
|
|
3984
|
+
if (!shouldRender)
|
|
3877
3985
|
return null;
|
|
3878
3986
|
const hasHeader = title || description;
|
|
3879
3987
|
const widthClass = width in widthConfig
|
|
3880
3988
|
? widthConfig[width]
|
|
3881
3989
|
: width;
|
|
3882
|
-
return (jsxRuntime.jsxs("div", { className: cn("fixed inset-0 z-10000 flex
|
|
3990
|
+
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 })] }))] })] }));
|
|
3883
3991
|
});
|
|
3884
3992
|
SidePanel.displayName = "SidePanel";
|
|
3885
3993
|
|