@trackunit/react-components 0.4.33 → 0.5.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.
package/index.esm.js CHANGED
@@ -14,7 +14,6 @@ import { Slottable, Slot } from '@radix-ui/react-slot';
14
14
  import isEqual from 'lodash/isEqual';
15
15
  import { Link, useBlocker } from '@tanstack/react-router';
16
16
  import { useCopyToClipboard } from 'usehooks-ts';
17
- import { useSwipeable } from 'react-swipeable';
18
17
  import { useFloating, autoUpdate, offset, flip, shift, size, useClick, useDismiss, useHover as useHover$1, useRole, useInteractions, useMergeRefs, FloatingPortal, FloatingFocusManager, arrow, useTransitionStatus, FloatingArrow } from '@floating-ui/react';
19
18
  import omit from 'lodash/omit';
20
19
  import { twMerge } from 'tailwind-merge';
@@ -1861,331 +1860,6 @@ const CopyableText = ({ text, alternativeText, dataTestId, className }) => {
1861
1860
  return (jsx("span", { className: cvaCopyableText({ animating, className }), "data-testid": dataTestId, onAnimationEnd: () => setAnimating(false), onClick: handleOnClick, title: value, children: text }));
1862
1861
  };
1863
1862
 
1864
- const cvaDialog = cvaMerge([
1865
- "z-toast",
1866
- "pointer-events-auto",
1867
- "absolute",
1868
- "transform",
1869
- "flex-col",
1870
- "bg-neutral-50",
1871
- "transition-transform",
1872
- "duration-300",
1873
- "ease-in-out",
1874
- "shadow-lg",
1875
- ], {
1876
- variants: {
1877
- position: {
1878
- left: "left-0 top-0 h-full w-fit rounded-r-lg",
1879
- right: "right-0 top-0 h-full w-fit rounded-l-lg",
1880
- top: "left-0 top-0 h-fit w-full rounded-b-lg",
1881
- bottom: "bottom-0 left-0 right-0 h-fit w-full rounded-t-lg",
1882
- },
1883
- sidebarMode: {
1884
- "semi-closed": "translate-y-[calc(100%-2.2rem)]",
1885
- "1/3": "translate-y-2/3",
1886
- "2/3": "translate-y-1/3",
1887
- full: "translate-y-0",
1888
- "semi-full": "translate-y-5",
1889
- closed: "translate-y-full",
1890
- },
1891
- isLargeScreen: {
1892
- true: "",
1893
- false: "bottom-0 left-0 right-0 h-full w-full rounded-t-lg",
1894
- },
1895
- open: {
1896
- true: "",
1897
- false: "",
1898
- },
1899
- },
1900
- compoundVariants: [
1901
- {
1902
- isLargeScreen: false,
1903
- open: false,
1904
- className: "translate-y-full",
1905
- },
1906
- {
1907
- isLargeScreen: true,
1908
- open: true,
1909
- position: "left",
1910
- className: "translate-x-0",
1911
- },
1912
- {
1913
- isLargeScreen: true,
1914
- open: false,
1915
- position: "left",
1916
- className: "-translate-x-full",
1917
- },
1918
- {
1919
- isLargeScreen: true,
1920
- open: true,
1921
- position: "right",
1922
- className: "translate-x-0",
1923
- },
1924
- {
1925
- isLargeScreen: true,
1926
- open: false,
1927
- position: "right",
1928
- className: "translate-x-full",
1929
- },
1930
- {
1931
- isLargeScreen: true,
1932
- open: true,
1933
- position: "top",
1934
- className: "translate-y-0",
1935
- },
1936
- {
1937
- isLargeScreen: true,
1938
- open: false,
1939
- position: "top",
1940
- className: "-translate-y-full",
1941
- },
1942
- {
1943
- isLargeScreen: true,
1944
- open: true,
1945
- position: "bottom",
1946
- className: "translate-y-0",
1947
- },
1948
- {
1949
- isLargeScreen: true,
1950
- open: false,
1951
- position: "bottom",
1952
- className: "translate-y-full",
1953
- },
1954
- ],
1955
- });
1956
- const cvaDialogContainer = cvaMerge(["flex", "flex-col", "overflow-hidden", "rounded-[inherit]"], {
1957
- variants: {
1958
- sidebarMode: {
1959
- "semi-closed": "h-auto",
1960
- "1/3": "h-[34%]",
1961
- "2/3": "h-[67%]",
1962
- "semi-full": "h-[calc(100%-1.25rem)]",
1963
- full: "h-full",
1964
- closed: "h-auto",
1965
- },
1966
- },
1967
- });
1968
- const cvaSwipeContainer = cvaMerge(["my-4", "flex", "items-center", "justify-center", "lg:hidden"]);
1969
- const cvaSwipeIcon = cvaMerge(["block", "h-1", "w-10", "rounded-full", "bg-gray-400"]);
1970
- const cvaToogleContainer = cvaMerge(["z-8", "absolute"], {
1971
- variants: {
1972
- position: {
1973
- left: "right-[-24px] top-[calc(50%-24px)]",
1974
- right: "left-[-24px] top-[calc(50%-24px)]",
1975
- top: "bottom-[-24px] left-[calc(50%-24px)]",
1976
- bottom: "left-[calc(50%-24px)] top-[-24px]",
1977
- },
1978
- },
1979
- defaultVariants: {
1980
- position: "left",
1981
- },
1982
- });
1983
- const cvaToogleButton = cvaMerge([
1984
- "flex",
1985
- "cursor-pointer",
1986
- "items-center",
1987
- "justify-center",
1988
- "border-gray-300",
1989
- "bg-neutral-50",
1990
- "bg-center",
1991
- "bg-no-repeat",
1992
- "shadow-md",
1993
- ], {
1994
- variants: {
1995
- position: {
1996
- left: "h-12 w-6 rounded-r-lg",
1997
- right: "h-12 w-6 rounded-l-lg",
1998
- top: "h-6 w-12 rounded-b-lg",
1999
- bottom: "h-6 w-12 rounded-t-lg",
2000
- },
2001
- },
2002
- defaultVariants: {
2003
- position: "left",
2004
- },
2005
- });
2006
- const cvaOverlayContainer = cvaMerge([
2007
- "absolute",
2008
- "flex",
2009
- "items-center",
2010
- "justify-center",
2011
- "inset-0",
2012
- "bg-black/30",
2013
- "bg-opacity-50",
2014
- "transition-opacity",
2015
- "duration-200",
2016
- "ease-in-out",
2017
- "opacity-100",
2018
- ], {
2019
- variants: {
2020
- open: {
2021
- true: "opacity-1 z-popover",
2022
- false: "z-[-1] opacity-0",
2023
- },
2024
- },
2025
- });
2026
-
2027
- /**
2028
- * Overlay Component
2029
- *
2030
- * @param {object} props - The Overlay component properties
2031
- * @param {boolean} props.open - Open status of the Overlay
2032
- * @param {Function} props.onClose - Callback function when Overlay is closed
2033
- * @returns {JSX.Element|null} The Overlay component
2034
- */
2035
- const Overlay = ({ open, onClose }) => {
2036
- useEffect(() => {
2037
- if (!onClose) {
2038
- return;
2039
- }
2040
- const handleEscape = (event) => {
2041
- if (event.key === "Escape") {
2042
- onClose(event);
2043
- }
2044
- };
2045
- if (open) {
2046
- window.addEventListener("keyup", handleEscape);
2047
- }
2048
- return () => {
2049
- window.removeEventListener("keyup", handleEscape);
2050
- };
2051
- }, [open, onClose]);
2052
- const handleClick = (event) => {
2053
- if (onClose) {
2054
- onClose(event);
2055
- }
2056
- };
2057
- return (jsx("div", { "aria-hidden": open, className: cvaOverlayContainer({ open }), "data-testid": "sidebar-overlay", onClick: handleClick }));
2058
- };
2059
-
2060
- const getIconName = (open, position) => {
2061
- switch (position) {
2062
- case "left":
2063
- return open ? "ChevronLeft" : "ChevronRight";
2064
- case "right":
2065
- return open ? "ChevronRight" : "ChevronLeft";
2066
- case "top":
2067
- return open ? "ChevronUp" : "ChevronDown";
2068
- case "bottom":
2069
- return open ? "ChevronDown" : "ChevronUp";
2070
- default:
2071
- return open ? "ChevronLeft" : "ChevronRight";
2072
- }
2073
- };
2074
- /**
2075
- * ToggleButton is a React functional component that returns a button with a chevron icon.
2076
- * The direction of the chevron changes depending on the state of the 'open' prop and
2077
- * the side the button is positioned ('position' prop).
2078
- * The button might be disabled based on the 'disableButton' prop.
2079
- *
2080
- * @param {object} props - The properties passed to the component
2081
- * @param {boolean} props.open - Indicates if the button is in "open" state
2082
- * @param {Function} [props.onToggle] - Optional callback function for when the button is clicked
2083
- * @param {Position} props.position - The position of the button relative to its container
2084
- */
2085
- const ToogleButton = ({ open, position, onToggle }) => {
2086
- const name = getIconName(open, position);
2087
- return (jsx("div", { className: cvaToogleContainer({ position }), children: jsx("button", { className: cvaToogleButton({ position }), "data-testid": "toggle-button", onClick: onToggle, children: jsx(Icon, { name: name }) }) }));
2088
- };
2089
-
2090
- /**
2091
- * MapSidebar is a sidebar component used with Maps.
2092
- * It provides a slide over sidebar drawer which can be used for displaying map related information or controls.
2093
- *
2094
- * @param {DrawerProps} props - The props for the MapSidebar component
2095
- * @returns {JSX.Element | null} Drawer component
2096
- */
2097
- const Drawer = ({ open = true, onToggle, onClose, disableOverlay, position = "left", children, dataTestId, className, dialogClassName, }) => {
2098
- const { width } = useResize();
2099
- const isLargeScreen = width >= 1024;
2100
- const initialSidebarMode = () => {
2101
- if (!open) {
2102
- return "closed";
2103
- }
2104
- return isLargeScreen ? "full" : "2/3";
2105
- };
2106
- const [sidebarMode, setSidebarMode] = useState(initialSidebarMode);
2107
- const [isVisible, setIsVisible] = useState(open);
2108
- const [isAnimationStart, setStartAnimation] = useState(open);
2109
- useEffect(() => {
2110
- if (!isLargeScreen && open) {
2111
- setSidebarMode("2/3");
2112
- }
2113
- if (onToggle) {
2114
- setStartAnimation(open);
2115
- return;
2116
- }
2117
- manageVisibilityAndAnimation(open);
2118
- }, [onToggle, isLargeScreen, open]);
2119
- const manageVisibilityAndAnimation = (isOpen) => {
2120
- if (!isOpen) {
2121
- setStartAnimation(false);
2122
- return;
2123
- }
2124
- setIsVisible(true);
2125
- setTimeout(() => {
2126
- setStartAnimation(true);
2127
- }, 150);
2128
- };
2129
- const handlers = useSwipeable({
2130
- onSwipedUp: () => !isLargeScreen && handleSwipedUp(),
2131
- onSwipedDown: () => !isLargeScreen && handleSwipedDown(),
2132
- trackMouse: true,
2133
- });
2134
- const handleSwipedUp = () => {
2135
- setSidebarMode(prev => {
2136
- switch (prev) {
2137
- case "semi-closed":
2138
- return "1/3";
2139
- case "1/3":
2140
- return "2/3";
2141
- case "2/3":
2142
- return "semi-full";
2143
- default:
2144
- return prev;
2145
- }
2146
- });
2147
- };
2148
- const handleSwipedDown = () => {
2149
- setSidebarMode(prev => {
2150
- switch (prev) {
2151
- case "semi-full":
2152
- return "2/3";
2153
- case "2/3":
2154
- return "1/3";
2155
- case "1/3":
2156
- return onClose ? "closed" : "semi-closed";
2157
- default:
2158
- return prev;
2159
- }
2160
- });
2161
- /*
2162
- * Within a mobile device context, when swiping down,
2163
- * if the Drawer is open a third and no onToggle function is provided,
2164
- * the Drawer will automatically be closed using the onClose function.
2165
- */
2166
- if (sidebarMode === "1/3" && !onToggle && onClose) {
2167
- onClose();
2168
- }
2169
- };
2170
- const handleAnimationEnd = () => {
2171
- if (!open && !onToggle) {
2172
- setIsVisible(false);
2173
- }
2174
- };
2175
- if (!isVisible && !onToggle) {
2176
- return null;
2177
- }
2178
- return (jsxs("div", { className: className, "data-testid": dataTestId, children: [!disableOverlay ? jsx(Overlay, { onClose: onClose, open: isAnimationStart }) : null, jsxs("div", { ...handlers, className: cvaDialog({
2179
- sidebarMode: isLargeScreen ? null : sidebarMode,
2180
- isLargeScreen,
2181
- open: isAnimationStart,
2182
- position: isLargeScreen ? position : undefined,
2183
- className: dialogClassName,
2184
- }), "data-testid": dataTestId ? `${dataTestId}-container` : undefined, onTransitionEnd: handleAnimationEnd, children: [isLargeScreen && onToggle ? jsx(ToogleButton, { onToggle: onToggle, open: open, position: position }) : null, jsxs("div", { className: cvaDialogContainer({
2185
- sidebarMode: isLargeScreen ? "full" : sidebarMode,
2186
- }), children: [jsx("div", { className: cvaSwipeContainer(), children: jsx("div", { className: cvaSwipeIcon() }) }), children] })] })] }));
2187
- };
2188
-
2189
1863
  const cvaSkeletonLine = cvaMerge([
2190
1864
  "rounded-md",
2191
1865
  "h-3",
@@ -3719,7 +3393,7 @@ const PopoverContent = React__default.forwardRef(function PopoverContent({ class
3719
3393
  var _a;
3720
3394
  const { context: floatingContext, customProps, ...context } = usePopoverContext();
3721
3395
  const ref = useMergeRefs([context.refs.setFloating, propRef]);
3722
- return (jsx(FloatingPortal, { id: portalId !== null && portalId !== void 0 ? portalId : "tu-floating-ui", children: context.isOpen ? (jsx(FloatingFocusManager, { closeOnFocusOut: false, context: floatingContext, guards: false, modal: context.isModal, order: ["reference", "content"], returnFocus: false, children: jsx("div", { "aria-describedby": context.descriptionId, "aria-labelledby": context.labelId, className: cvaPopoverContainer({ className: className !== null && className !== void 0 ? className : customProps.className }), "data-testid": (_a = dataTestId !== null && dataTestId !== void 0 ? dataTestId : customProps.dataTestId) !== null && _a !== void 0 ? _a : "popover-content", ref: ref, style: {
3396
+ return (jsx(FloatingPortal, { id: portalId !== null && portalId !== void 0 ? portalId : "tu-floating-ui", children: context.isOpen ? (jsx(FloatingFocusManager, { closeOnFocusOut: false, context: floatingContext, guards: true, modal: context.isModal, order: ["reference", "content"], returnFocus: true, children: jsx("div", { "aria-describedby": context.descriptionId, "aria-labelledby": context.labelId, className: cvaPopoverContainer({ className: className !== null && className !== void 0 ? className : customProps.className }), "data-testid": (_a = dataTestId !== null && dataTestId !== void 0 ? dataTestId : customProps.dataTestId) !== null && _a !== void 0 ? _a : "popover-content", ref: ref, style: {
3723
3397
  position: context.strategy,
3724
3398
  top: context.y,
3725
3399
  left: context.x,
@@ -4016,6 +3690,36 @@ const KPICard = ({ asChild = false, title, value, loading, unit, iconName, iconB
4016
3690
  return (jsxs(Comp, { className: cvaKPICardContainer({ className, isClickable: Boolean(asChild || onClick) }), "data-testid": `${dataTestId}-comp`, onClick: onClick, ...rest, children: [tooltipLabel ? (jsx(Tooltip, { className: "w-full", label: tooltipLabel, placement: "bottom", children: jsx(CardContent, {}) })) : (jsx(CardContent, {})), !loading && jsx(Slottable, { children: rest.children })] }));
4017
3691
  };
4018
3692
 
3693
+ const cvaMenuList = cvaMerge([
3694
+ "shadow",
3695
+ "rounded-lg",
3696
+ "z-popover",
3697
+ "bg-white",
3698
+ "border",
3699
+ "border-slate-300",
3700
+ "grid",
3701
+ "min-w-[200px]",
3702
+ "max-w-[300px]",
3703
+ "p-1",
3704
+ ], {
3705
+ variants: {
3706
+ stickyHeader: {
3707
+ true: "grid-rows-min-fr grid overflow-y-hidden",
3708
+ false: "",
3709
+ },
3710
+ },
3711
+ });
3712
+ const cvaMenuListDivider = cvaMerge(["mx-[-4px]", "my-1", "min-h-px", "bg-slate-300"]);
3713
+ const cvaMenuListMultiSelect = cvaMerge("hover:!bg-blue-200");
3714
+ const cvaMenuListItem = cvaMerge("max-w-[290px]");
3715
+
3716
+ /**
3717
+ * The MenuDivider component is used to separate items in a menu list.
3718
+ */
3719
+ const MenuDivider = () => {
3720
+ return jsx("div", { className: cvaMenuListDivider(), "data-testid": "menu-divider" });
3721
+ };
3722
+
4019
3723
  /**
4020
3724
  * Applies standardized interaction-related styles to an element.
4021
3725
  *
@@ -4068,45 +3772,108 @@ const cvaInteractableItem = cvaMerge("", {
4068
3772
  },
4069
3773
  });
4070
3774
 
4071
- const cvaMenuItemStyle = cvaMerge(["py-2", "px-2", "w-full", "h-auto", "flex", "flex-row", "items-center", "gap-x-2", "select-none", "rounded"], {
3775
+ /**
3776
+ * Extends the cvaInteractableItem variant in order to set the padding, width, height, cursor, and other styles particular to the MenuItem component.
3777
+ * The cvaInteractableItem variant is used to set the standardized styles that change through interaction with the element (background color, hover, focus, and disabled).
3778
+ */
3779
+ const cvaMenuItem = (props) => {
3780
+ const { size, selected, disabled, focused, className, variant } = props !== null && props !== void 0 ? props : {};
3781
+ return twMerge(cvaMenuItemStyle({ size, variant, selected, disabled }), cvaInteractableItem({ selected, disabled, cursor: "pointer", focused }), className);
3782
+ };
3783
+ const cvaMenuItemStyle = cvaMerge(["py-2", "px-2", "h-auto", "flex", "flex-row", "items-center", "gap-x-2", "select-none", "rounded", "text-sm"], {
4072
3784
  variants: {
4073
3785
  size: {
4074
3786
  small: "py-1",
4075
3787
  medium: "py-2",
4076
3788
  },
3789
+ variant: {
3790
+ primary: [],
3791
+ danger: [
3792
+ "text-danger-600",
3793
+ "hover:!bg-danger-100",
3794
+ "focus:!bg-danger-200",
3795
+ "hover:!text-danger-700",
3796
+ "focus:!text-danger-800",
3797
+ ],
3798
+ },
3799
+ selected: {
3800
+ true: "",
3801
+ false: "",
3802
+ },
3803
+ disabled: {
3804
+ true: "text-black opacity-50",
3805
+ false: "",
3806
+ },
3807
+ },
3808
+ compoundVariants: [
3809
+ {
3810
+ /* danger not multi-select enabled */
3811
+ selected: true,
3812
+ variant: "danger",
3813
+ className: ["!bg-white"],
3814
+ },
3815
+ ],
3816
+ defaultVariants: {
3817
+ variant: "primary",
3818
+ selected: false,
3819
+ disabled: false,
4077
3820
  },
4078
3821
  });
4079
- /**
4080
- * Extends the cvaInteractableItem variant in order to set the padding, width, height, cursor, and other styles particular to the MenuItem component.
4081
- * The cvaInteractableItem variant is used to set the standardized styles that change through interaction with the element (background color, hover, focus, and disabled).
4082
- */
4083
- const cvaMenuItem = (props) => {
4084
- const { size, selected, disabled, focused, className } = props !== null && props !== void 0 ? props : {};
4085
- return twMerge(cvaMenuItemStyle({ size }), cvaInteractableItem({ selected, disabled, cursor: "pointer", focused }), className);
4086
- };
4087
- const cvaMenuItemLabel = cvaMerge([
4088
- "flex-grow",
4089
- "text-gray-700",
4090
- "text-ellipsis",
4091
- "truncate",
4092
- "group-hover:text-gray-900",
4093
- "group-active:text-gray-700",
4094
- ]);
4095
- const cvaMenuItemSuffix = cvaMerge(["self-center", "flex-grow-0", "text-slate-400", "text-sm"], {
3822
+ const cvaMenuItemLabel = cvaMerge(["flex-grow", "truncate", "text-black", "font-normal"], {
3823
+ variants: {
3824
+ variant: {
3825
+ primary: [],
3826
+ danger: ["text-danger-600", "hover:text-danger-700", "focus:bg-danger-200", "focus:text-danger-800"],
3827
+ },
3828
+ disabled: {
3829
+ true: "text-black opacity-50",
3830
+ false: "",
3831
+ },
3832
+ },
3833
+ defaultVariants: {
3834
+ variant: "primary",
3835
+ disabled: false,
3836
+ },
3837
+ });
3838
+ const cvaMenuItemPrefix = cvaMerge(["text-secondary-400", "hover:text-secondary-500", "focus:text-secondary-500", "h-min", "leading-[0]"], {
4096
3839
  variants: {
4097
3840
  selected: {
4098
- true: "text-primary-600 hover:text-primary-700",
3841
+ true: "text-secondary-600",
4099
3842
  false: "",
4100
3843
  },
3844
+ variant: {
3845
+ primary: [],
3846
+ danger: ["text-danger-600", "hover:text-danger-700", "focus:bg-danger-200", "focus:text-danger-800"],
3847
+ },
3848
+ disabled: {
3849
+ true: "text-secondary opacity-50",
3850
+ false: "",
3851
+ },
3852
+ },
3853
+ defaultVariants: {
3854
+ variant: "primary",
3855
+ disabled: false,
4101
3856
  },
4102
3857
  });
4103
- const cvaMenuItemPrefix = cvaMerge(["self-center", "flex-grow-0", "text-slate-400", "group-hover:text-slate-600", "h-min", "leading-[0]", "text-sm"], {
3858
+ const cvaMenuItemSuffix = cvaMerge(["text-secondary-400", "text-sm"], {
4104
3859
  variants: {
4105
3860
  selected: {
4106
- true: "text-primary-600 hover:text-primary-700",
3861
+ true: "text-secondary-600",
3862
+ false: "",
3863
+ },
3864
+ variant: {
3865
+ primary: [],
3866
+ danger: ["text-danger-600", "hover:text-danger-700", "focus:bg-danger-200", "focus:text-danger-800"],
3867
+ },
3868
+ disabled: {
3869
+ true: "text-secondary opacity-50",
4107
3870
  false: "",
4108
3871
  },
4109
3872
  },
3873
+ defaultVariants: {
3874
+ variant: "primary",
3875
+ disabled: false,
3876
+ },
4110
3877
  });
4111
3878
 
4112
3879
  /**
@@ -4115,46 +3882,81 @@ const cvaMenuItemPrefix = cvaMerge(["self-center", "flex-grow-0", "text-slate-40
4115
3882
  * @param {MenuItemProps} props - The props for the MenuItem component
4116
3883
  * @returns {JSX.Element} MenuItem component
4117
3884
  */
4118
- const MenuItem = ({ className, dataTestId, label, size, children, selected, prefix, suffix, disabled, onClick, stopPropagation = true, id, tabIndex, }) => {
4119
- return (jsxs("div", { className: cvaMenuItem({
3885
+ const MenuItem = ({ className, dataTestId, label, size, children, selected, prefix, suffix, disabled, onClick, stopPropagation = true, id, tabIndex, variant = "primary", }) => {
3886
+ /* Handle tab navigation */
3887
+ const handleKeyDown = (e) => {
3888
+ if (e.key === "Enter" && onClick && !disabled) {
3889
+ stopPropagation && e.stopPropagation();
3890
+ // eslint-disable-next-line local-rules/no-typescript-assertion
3891
+ onClick(e);
3892
+ }
3893
+ };
3894
+ return (jsxs("div", { "aria-disabled": disabled, className: cvaMenuItem({
4120
3895
  selected,
4121
3896
  disabled,
4122
3897
  size,
4123
3898
  className,
4124
- }), "data-testid": dataTestId !== null && dataTestId !== void 0 ? dataTestId : "menu-item", id: id, onClick: e => {
3899
+ variant,
3900
+ }), "data-testid": dataTestId ? `${dataTestId}-menu-item` : "menu-item", id: id, onClick: e => {
4125
3901
  stopPropagation && e.stopPropagation();
4126
3902
  onClick === null || onClick === void 0 ? void 0 : onClick(e);
4127
- }, role: "menuitem", tabIndex: tabIndex !== null && tabIndex !== void 0 ? tabIndex : 0, children: [prefix ? (jsx("div", { className: cvaMenuItemPrefix({ selected }), "data-testid": dataTestId ? `${dataTestId}-prefix` : null, children: prefix })) : null, children && typeof children !== "string" ? (children) : (jsx("div", { className: cvaMenuItemLabel(), "data-testid": dataTestId ? `${dataTestId}-label` : null, children: children !== null && children !== void 0 ? children : label })), suffix ? (jsx("div", { className: cvaMenuItemSuffix({ selected }), "data-testid": dataTestId ? `${dataTestId}-suffix` : null, children: suffix })) : null] }));
3903
+ }, onKeyDown: handleKeyDown, role: "menuitem", tabIndex: disabled ? -1 : tabIndex !== null && tabIndex !== void 0 ? tabIndex : 0, children: [prefix ? (jsx("div", { className: cvaMenuItemPrefix({ selected, variant, disabled }), "data-testid": dataTestId ? `${dataTestId}-prefix` : "menu-item-prefix", children: prefix })) : null, children && typeof children !== "string" ? (children) : (jsx("div", { className: cvaMenuItemLabel({ variant, disabled }), "data-testid": dataTestId ? `${dataTestId}-label` : "menu-item-label", children: children !== null && children !== void 0 ? children : label })), suffix ? (jsx("div", { className: cvaMenuItemSuffix({ selected, variant, disabled }), "data-testid": dataTestId ? `${dataTestId}-suffix` : "menu-item-suffix", children: suffix })) : null] }));
4128
3904
  };
4129
3905
 
4130
- const cvaMenuList = cvaMerge(["shadow-md", "rounded-lg", "z-popover", "bg-white", "border", "border-slate-300", "grid"], {
4131
- variants: {
4132
- stickyHeader: {
4133
- true: "grid-rows-min-fr grid overflow-y-hidden",
4134
- false: "",
4135
- },
4136
- },
4137
- });
4138
- const cvaMenuListDivider = cvaMerge([
4139
- "file:w-full",
4140
- "selection:col-span-full",
4141
- "selection:h-px",
4142
- "selection:bg-slate-200",
4143
- ]);
4144
-
4145
3906
  /**
4146
- * The MenuList component is used for menus and selects.
4147
-
3907
+ * The MenuList is a popover menu that appears above all other content on the page. The menu offers a list of actions or functions that a user can access by clicking on a trigger.
3908
+ *
3909
+ * **When to use**
3910
+ * - Use the MenuList if you have limited space and need to display overflow actions in a list.
3911
+ * - Use the MenuList for actions that are not essential to completing workflows.
3912
+ * - Don’t use the MenuList to display single or multi-select items within form components. For dropdowns within select components, use SelectDropdown (component not available yet).
3913
+ *
4148
3914
  * @param {MenuListProps} props - The props for the MenuList component
4149
3915
  * @returns {JSX.Element} MenuList component
4150
3916
  */
4151
- const MenuList = ({ dataTestId, className, children, withStickyHeader = false, showDivider = false, ...args }) => {
3917
+ const MenuList = ({ dataTestId, className, children, withStickyHeader = false, isMulti = false, selectedItems: controlledSelectedItems, onSelectionChange, ...args }) => {
4152
3918
  const childrenArr = Children.toArray(children);
4153
- const isLastItem = (index) => index === childrenArr.length - 1;
4154
- return (jsx("div", { className: cvaMenuList({ stickyHeader: withStickyHeader, className }), "data-testid": dataTestId, onClick: args.onClick, role: "list", tabIndex: 0, children: Children.map(childrenArr, (menuItem, index) => (jsxs(Fragment, { children: [menuItem, showDivider && !isLastItem(index) ? jsx("hr", { className: cvaMenuListDivider() }) : null] }))) }));
3919
+ const [internalSelectedItems, setInternalSelectedItems] = useState(controlledSelectedItems !== null && controlledSelectedItems !== void 0 ? controlledSelectedItems : []);
3920
+ const selectedItems = controlledSelectedItems !== null && controlledSelectedItems !== void 0 ? controlledSelectedItems : internalSelectedItems;
3921
+ const handleItemClick = useCallback((id, disabled) => {
3922
+ if (disabled) {
3923
+ return;
3924
+ }
3925
+ const newSelectedItems = isMulti
3926
+ ? selectedItems.includes(id)
3927
+ ? selectedItems.filter(item => item !== id)
3928
+ : [...selectedItems, id]
3929
+ : [id];
3930
+ if (onSelectionChange) {
3931
+ onSelectionChange(newSelectedItems);
3932
+ }
3933
+ else {
3934
+ setInternalSelectedItems(newSelectedItems);
3935
+ }
3936
+ }, [isMulti, selectedItems, onSelectionChange]);
3937
+ return (jsx("div", { className: cvaMenuList({ stickyHeader: withStickyHeader, className }), "data-testid": dataTestId ? `${dataTestId}-menu-list` : "menu-list", onClick: args.onClick, role: "list", tabIndex: 0, children: childrenArr.map((menuItem, index) => {
3938
+ var _a;
3939
+ if (isValidElement(menuItem)) {
3940
+ const isSelected = selectedItems.includes((_a = menuItem.props.id) !== null && _a !== void 0 ? _a : `${index}`) || menuItem.props.selected;
3941
+ return (jsx("div", { children: cloneElement(menuItem, {
3942
+ ...menuItem.props,
3943
+ onClick: (event) => {
3944
+ var _a, _b, _c;
3945
+ (_b = (_a = menuItem.props).onClick) === null || _b === void 0 ? void 0 : _b.call(_a, event);
3946
+ handleItemClick((_c = menuItem.props.id) !== null && _c !== void 0 ? _c : `${index}`, menuItem.props.disabled);
3947
+ },
3948
+ className: isMulti && isSelected
3949
+ ? cvaMenuListMultiSelect({ className: menuItem.props.className })
3950
+ : cvaMenuListItem({ className: menuItem.props.className }),
3951
+ selected: isSelected,
3952
+ suffix: isMulti && isSelected ? (jsx(Icon, { className: "h-5 text-blue-600", name: "Check", size: "medium", type: "solid" })) : null,
3953
+ }) }, index));
3954
+ }
3955
+ return null;
3956
+ }) }));
4155
3957
  };
4156
3958
 
4157
- const cvaMoreMenu = cvaMerge(["p-4"]);
3959
+ const cvaMoreMenu = cvaMerge(["p-0"]);
4158
3960
 
4159
3961
  /**
4160
3962
  * A kebab menu component.
@@ -4172,7 +3974,7 @@ const MoreMenu = ({ className, dataTestId, popoverProps, iconProps = {
4172
3974
  variant: "secondary",
4173
3975
  }, customButton, customPortalId, children, }) => {
4174
3976
  const actionMenuRef = useRef(null);
4175
- return (jsx("div", { className: cvaMoreMenu({ className }), "data-testid": dataTestId, ref: actionMenuRef, children: jsxs(Popover, { ...popoverProps, children: [jsx(PopoverTrigger, { children: customButton !== null && customButton !== void 0 ? customButton : jsx(IconButton, { ...iconButtonProps, icon: jsx(Icon, { name: "EllipsisHorizontal", ...iconProps }) }) }), jsx(PopoverContent, { portalId: customPortalId, children: close => (typeof children === "function" ? children(close) : children) })] }) }));
3977
+ return (jsx("div", { className: cvaMoreMenu({ className }), "data-testid": dataTestId, ref: actionMenuRef, children: jsxs(Popover, { placement: "bottom-end", ...popoverProps, children: [jsx(PopoverTrigger, { children: customButton !== null && customButton !== void 0 ? customButton : (jsx(IconButton, { dataTestId: "more-menu-icon", ...iconButtonProps, icon: jsx(Icon, { name: "EllipsisHorizontal", ...iconProps }) })) }), jsx(PopoverContent, { portalId: customPortalId, children: close => (typeof children === "function" ? children(close) : children) })] }) }));
4176
3978
  };
4177
3979
 
4178
3980
  const cvaNotice = cvaMerge(["flex", "items-center"]);
@@ -4588,7 +4390,7 @@ const Sidebar = ({ childContainerClassName, children, breakpoint = "lg", classNa
4588
4390
  }) }), overflowItemCount > 0 ? (jsx(MoreMenu, { iconButtonProps: {
4589
4391
  circular: false,
4590
4392
  variant: "ghost-neutral",
4591
- }, popoverProps: { placement: "bottom-end" }, ...moreMenuProps, className: twMerge(moreMenuProps === null || moreMenuProps === void 0 ? void 0 : moreMenuProps.className, "!p-0"), dataTestId: dataTestId ? `${dataTestId}-more-menu` : undefined, children: close => (jsx(MenuList, { ...menuListProps, dataTestId: dataTestId ? `${dataTestId}-menu-list` : undefined, children: React__default.Children.map(children, child => {
4393
+ }, ...moreMenuProps, className: moreMenuProps === null || moreMenuProps === void 0 ? void 0 : moreMenuProps.className, dataTestId: dataTestId ? `${dataTestId}-more-menu` : undefined, children: close => (jsx(MenuList, { ...menuListProps, dataTestId: dataTestId, children: React__default.Children.map(children, child => {
4592
4394
  return itemOverflowMap[child.props.id]
4593
4395
  ? React__default.cloneElement(child, {
4594
4396
  onClick: () => {
@@ -4596,6 +4398,7 @@ const Sidebar = ({ childContainerClassName, children, breakpoint = "lg", classNa
4596
4398
  (_b = (_a = child.props).onClick) === null || _b === void 0 ? void 0 : _b.call(_a);
4597
4399
  close();
4598
4400
  },
4401
+ className: "w-full",
4599
4402
  })
4600
4403
  : null;
4601
4404
  }) })) })) : null] }));
@@ -5003,4 +4806,4 @@ const cvaClickable = cvaMerge([
5003
4806
  },
5004
4807
  });
5005
4808
 
5006
- export { Alert, Badge, Breadcrumb, BreadcrumbContainer, Button, Card, CardBody, CardFooter, CardHeader, Collapse, CompletionStatusIndicator, CopyableText, Drawer, EmptyState, EmptyValue, ExternalLink, Heading, Icon, IconButton, Indicator, KPICard, MenuItem, MenuList, MoreMenu, Notice, PackageNameStoryComponent, Page, PageContent, PageHeader, Pagination, Polygon, Popover, PopoverContent, PopoverTitle, PopoverTrigger, Prompt, ROLE_CARD, SectionHeader, Sidebar, SkeletonLines, Spacer, Spinner, StarButton, Tab, TabContent, TabList, Tabs, Tag, Text, Timeline, TimelineElement, ToggleGroup, ToggleItem, Tooltip, ValueBar, VirtualizedList, WidgetBody, cvaButton, cvaButtonPrefixSuffix, cvaButtonSpinner, cvaButtonSpinnerContainer, cvaClickable, cvaIconButton, cvaIndicator, cvaIndicatorIcon, cvaIndicatorIconBackground, cvaIndicatorLabel, cvaIndicatorPing, cvaInteractableItem, cvaMenuItem, cvaMenuItemLabel, cvaMenuItemPrefix, cvaMenuItemStyle, cvaMenuItemSuffix, docs, getDevicePixelRatio, getValueBarColorByValue, iconColorNames, iconPalette, setLocalStorage, useClickOutside, useContinuousTimeout, useDebounce, useDevicePixelRatio, useGeometry, useHover, useIsFirstRender, useIsFullscreen, useIsTextCutOff, useLocalStorage, useLocalStorageReducer, useOptionallyElevatedState, useOverflowItems, usePopoverContext, usePrevious, usePrompt, useResize, useSelfUpdatingRef, useTimeout, useViewportSize, useWindowActivity };
4809
+ export { Alert, Badge, Breadcrumb, BreadcrumbContainer, Button, Card, CardBody, CardFooter, CardHeader, Collapse, CompletionStatusIndicator, CopyableText, EmptyState, EmptyValue, ExternalLink, Heading, Icon, IconButton, Indicator, KPICard, MenuDivider, MenuItem, MenuList, MoreMenu, Notice, PackageNameStoryComponent, Page, PageContent, PageHeader, Pagination, Polygon, Popover, PopoverContent, PopoverTitle, PopoverTrigger, Prompt, ROLE_CARD, SectionHeader, Sidebar, SkeletonLines, Spacer, Spinner, StarButton, Tab, TabContent, TabList, Tabs, Tag, Text, Timeline, TimelineElement, ToggleGroup, ToggleItem, Tooltip, ValueBar, VirtualizedList, WidgetBody, cvaButton, cvaButtonPrefixSuffix, cvaButtonSpinner, cvaButtonSpinnerContainer, cvaClickable, cvaIconButton, cvaIndicator, cvaIndicatorIcon, cvaIndicatorIconBackground, cvaIndicatorLabel, cvaIndicatorPing, cvaInteractableItem, cvaMenuItem, cvaMenuItemLabel, cvaMenuItemPrefix, cvaMenuItemStyle, cvaMenuItemSuffix, docs, getDevicePixelRatio, getValueBarColorByValue, iconColorNames, iconPalette, setLocalStorage, useClickOutside, useContinuousTimeout, useDebounce, useDevicePixelRatio, useGeometry, useHover, useIsFirstRender, useIsFullscreen, useIsTextCutOff, useLocalStorage, useLocalStorageReducer, useOptionallyElevatedState, useOverflowItems, usePopoverContext, usePrevious, usePrompt, useResize, useSelfUpdatingRef, useTimeout, useViewportSize, useWindowActivity };