@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.cjs.js CHANGED
@@ -15,7 +15,6 @@ var reactSlot = require('@radix-ui/react-slot');
15
15
  var isEqual = require('lodash/isEqual');
16
16
  var reactRouter = require('@tanstack/react-router');
17
17
  var usehooksTs = require('usehooks-ts');
18
- var reactSwipeable = require('react-swipeable');
19
18
  var react = require('@floating-ui/react');
20
19
  var omit = require('lodash/omit');
21
20
  var tailwindMerge = require('tailwind-merge');
@@ -1881,331 +1880,6 @@ const CopyableText = ({ text, alternativeText, dataTestId, className }) => {
1881
1880
  return (jsxRuntime.jsx("span", { className: cvaCopyableText({ animating, className }), "data-testid": dataTestId, onAnimationEnd: () => setAnimating(false), onClick: handleOnClick, title: value, children: text }));
1882
1881
  };
1883
1882
 
1884
- const cvaDialog = cssClassVarianceUtilities.cvaMerge([
1885
- "z-toast",
1886
- "pointer-events-auto",
1887
- "absolute",
1888
- "transform",
1889
- "flex-col",
1890
- "bg-neutral-50",
1891
- "transition-transform",
1892
- "duration-300",
1893
- "ease-in-out",
1894
- "shadow-lg",
1895
- ], {
1896
- variants: {
1897
- position: {
1898
- left: "left-0 top-0 h-full w-fit rounded-r-lg",
1899
- right: "right-0 top-0 h-full w-fit rounded-l-lg",
1900
- top: "left-0 top-0 h-fit w-full rounded-b-lg",
1901
- bottom: "bottom-0 left-0 right-0 h-fit w-full rounded-t-lg",
1902
- },
1903
- sidebarMode: {
1904
- "semi-closed": "translate-y-[calc(100%-2.2rem)]",
1905
- "1/3": "translate-y-2/3",
1906
- "2/3": "translate-y-1/3",
1907
- full: "translate-y-0",
1908
- "semi-full": "translate-y-5",
1909
- closed: "translate-y-full",
1910
- },
1911
- isLargeScreen: {
1912
- true: "",
1913
- false: "bottom-0 left-0 right-0 h-full w-full rounded-t-lg",
1914
- },
1915
- open: {
1916
- true: "",
1917
- false: "",
1918
- },
1919
- },
1920
- compoundVariants: [
1921
- {
1922
- isLargeScreen: false,
1923
- open: false,
1924
- className: "translate-y-full",
1925
- },
1926
- {
1927
- isLargeScreen: true,
1928
- open: true,
1929
- position: "left",
1930
- className: "translate-x-0",
1931
- },
1932
- {
1933
- isLargeScreen: true,
1934
- open: false,
1935
- position: "left",
1936
- className: "-translate-x-full",
1937
- },
1938
- {
1939
- isLargeScreen: true,
1940
- open: true,
1941
- position: "right",
1942
- className: "translate-x-0",
1943
- },
1944
- {
1945
- isLargeScreen: true,
1946
- open: false,
1947
- position: "right",
1948
- className: "translate-x-full",
1949
- },
1950
- {
1951
- isLargeScreen: true,
1952
- open: true,
1953
- position: "top",
1954
- className: "translate-y-0",
1955
- },
1956
- {
1957
- isLargeScreen: true,
1958
- open: false,
1959
- position: "top",
1960
- className: "-translate-y-full",
1961
- },
1962
- {
1963
- isLargeScreen: true,
1964
- open: true,
1965
- position: "bottom",
1966
- className: "translate-y-0",
1967
- },
1968
- {
1969
- isLargeScreen: true,
1970
- open: false,
1971
- position: "bottom",
1972
- className: "translate-y-full",
1973
- },
1974
- ],
1975
- });
1976
- const cvaDialogContainer = cssClassVarianceUtilities.cvaMerge(["flex", "flex-col", "overflow-hidden", "rounded-[inherit]"], {
1977
- variants: {
1978
- sidebarMode: {
1979
- "semi-closed": "h-auto",
1980
- "1/3": "h-[34%]",
1981
- "2/3": "h-[67%]",
1982
- "semi-full": "h-[calc(100%-1.25rem)]",
1983
- full: "h-full",
1984
- closed: "h-auto",
1985
- },
1986
- },
1987
- });
1988
- const cvaSwipeContainer = cssClassVarianceUtilities.cvaMerge(["my-4", "flex", "items-center", "justify-center", "lg:hidden"]);
1989
- const cvaSwipeIcon = cssClassVarianceUtilities.cvaMerge(["block", "h-1", "w-10", "rounded-full", "bg-gray-400"]);
1990
- const cvaToogleContainer = cssClassVarianceUtilities.cvaMerge(["z-8", "absolute"], {
1991
- variants: {
1992
- position: {
1993
- left: "right-[-24px] top-[calc(50%-24px)]",
1994
- right: "left-[-24px] top-[calc(50%-24px)]",
1995
- top: "bottom-[-24px] left-[calc(50%-24px)]",
1996
- bottom: "left-[calc(50%-24px)] top-[-24px]",
1997
- },
1998
- },
1999
- defaultVariants: {
2000
- position: "left",
2001
- },
2002
- });
2003
- const cvaToogleButton = cssClassVarianceUtilities.cvaMerge([
2004
- "flex",
2005
- "cursor-pointer",
2006
- "items-center",
2007
- "justify-center",
2008
- "border-gray-300",
2009
- "bg-neutral-50",
2010
- "bg-center",
2011
- "bg-no-repeat",
2012
- "shadow-md",
2013
- ], {
2014
- variants: {
2015
- position: {
2016
- left: "h-12 w-6 rounded-r-lg",
2017
- right: "h-12 w-6 rounded-l-lg",
2018
- top: "h-6 w-12 rounded-b-lg",
2019
- bottom: "h-6 w-12 rounded-t-lg",
2020
- },
2021
- },
2022
- defaultVariants: {
2023
- position: "left",
2024
- },
2025
- });
2026
- const cvaOverlayContainer = cssClassVarianceUtilities.cvaMerge([
2027
- "absolute",
2028
- "flex",
2029
- "items-center",
2030
- "justify-center",
2031
- "inset-0",
2032
- "bg-black/30",
2033
- "bg-opacity-50",
2034
- "transition-opacity",
2035
- "duration-200",
2036
- "ease-in-out",
2037
- "opacity-100",
2038
- ], {
2039
- variants: {
2040
- open: {
2041
- true: "opacity-1 z-popover",
2042
- false: "z-[-1] opacity-0",
2043
- },
2044
- },
2045
- });
2046
-
2047
- /**
2048
- * Overlay Component
2049
- *
2050
- * @param {object} props - The Overlay component properties
2051
- * @param {boolean} props.open - Open status of the Overlay
2052
- * @param {Function} props.onClose - Callback function when Overlay is closed
2053
- * @returns {JSX.Element|null} The Overlay component
2054
- */
2055
- const Overlay = ({ open, onClose }) => {
2056
- React.useEffect(() => {
2057
- if (!onClose) {
2058
- return;
2059
- }
2060
- const handleEscape = (event) => {
2061
- if (event.key === "Escape") {
2062
- onClose(event);
2063
- }
2064
- };
2065
- if (open) {
2066
- window.addEventListener("keyup", handleEscape);
2067
- }
2068
- return () => {
2069
- window.removeEventListener("keyup", handleEscape);
2070
- };
2071
- }, [open, onClose]);
2072
- const handleClick = (event) => {
2073
- if (onClose) {
2074
- onClose(event);
2075
- }
2076
- };
2077
- return (jsxRuntime.jsx("div", { "aria-hidden": open, className: cvaOverlayContainer({ open }), "data-testid": "sidebar-overlay", onClick: handleClick }));
2078
- };
2079
-
2080
- const getIconName = (open, position) => {
2081
- switch (position) {
2082
- case "left":
2083
- return open ? "ChevronLeft" : "ChevronRight";
2084
- case "right":
2085
- return open ? "ChevronRight" : "ChevronLeft";
2086
- case "top":
2087
- return open ? "ChevronUp" : "ChevronDown";
2088
- case "bottom":
2089
- return open ? "ChevronDown" : "ChevronUp";
2090
- default:
2091
- return open ? "ChevronLeft" : "ChevronRight";
2092
- }
2093
- };
2094
- /**
2095
- * ToggleButton is a React functional component that returns a button with a chevron icon.
2096
- * The direction of the chevron changes depending on the state of the 'open' prop and
2097
- * the side the button is positioned ('position' prop).
2098
- * The button might be disabled based on the 'disableButton' prop.
2099
- *
2100
- * @param {object} props - The properties passed to the component
2101
- * @param {boolean} props.open - Indicates if the button is in "open" state
2102
- * @param {Function} [props.onToggle] - Optional callback function for when the button is clicked
2103
- * @param {Position} props.position - The position of the button relative to its container
2104
- */
2105
- const ToogleButton = ({ open, position, onToggle }) => {
2106
- const name = getIconName(open, position);
2107
- return (jsxRuntime.jsx("div", { className: cvaToogleContainer({ position }), children: jsxRuntime.jsx("button", { className: cvaToogleButton({ position }), "data-testid": "toggle-button", onClick: onToggle, children: jsxRuntime.jsx(Icon, { name: name }) }) }));
2108
- };
2109
-
2110
- /**
2111
- * MapSidebar is a sidebar component used with Maps.
2112
- * It provides a slide over sidebar drawer which can be used for displaying map related information or controls.
2113
- *
2114
- * @param {DrawerProps} props - The props for the MapSidebar component
2115
- * @returns {JSX.Element | null} Drawer component
2116
- */
2117
- const Drawer = ({ open = true, onToggle, onClose, disableOverlay, position = "left", children, dataTestId, className, dialogClassName, }) => {
2118
- const { width } = useResize();
2119
- const isLargeScreen = width >= 1024;
2120
- const initialSidebarMode = () => {
2121
- if (!open) {
2122
- return "closed";
2123
- }
2124
- return isLargeScreen ? "full" : "2/3";
2125
- };
2126
- const [sidebarMode, setSidebarMode] = React.useState(initialSidebarMode);
2127
- const [isVisible, setIsVisible] = React.useState(open);
2128
- const [isAnimationStart, setStartAnimation] = React.useState(open);
2129
- React.useEffect(() => {
2130
- if (!isLargeScreen && open) {
2131
- setSidebarMode("2/3");
2132
- }
2133
- if (onToggle) {
2134
- setStartAnimation(open);
2135
- return;
2136
- }
2137
- manageVisibilityAndAnimation(open);
2138
- }, [onToggle, isLargeScreen, open]);
2139
- const manageVisibilityAndAnimation = (isOpen) => {
2140
- if (!isOpen) {
2141
- setStartAnimation(false);
2142
- return;
2143
- }
2144
- setIsVisible(true);
2145
- setTimeout(() => {
2146
- setStartAnimation(true);
2147
- }, 150);
2148
- };
2149
- const handlers = reactSwipeable.useSwipeable({
2150
- onSwipedUp: () => !isLargeScreen && handleSwipedUp(),
2151
- onSwipedDown: () => !isLargeScreen && handleSwipedDown(),
2152
- trackMouse: true,
2153
- });
2154
- const handleSwipedUp = () => {
2155
- setSidebarMode(prev => {
2156
- switch (prev) {
2157
- case "semi-closed":
2158
- return "1/3";
2159
- case "1/3":
2160
- return "2/3";
2161
- case "2/3":
2162
- return "semi-full";
2163
- default:
2164
- return prev;
2165
- }
2166
- });
2167
- };
2168
- const handleSwipedDown = () => {
2169
- setSidebarMode(prev => {
2170
- switch (prev) {
2171
- case "semi-full":
2172
- return "2/3";
2173
- case "2/3":
2174
- return "1/3";
2175
- case "1/3":
2176
- return onClose ? "closed" : "semi-closed";
2177
- default:
2178
- return prev;
2179
- }
2180
- });
2181
- /*
2182
- * Within a mobile device context, when swiping down,
2183
- * if the Drawer is open a third and no onToggle function is provided,
2184
- * the Drawer will automatically be closed using the onClose function.
2185
- */
2186
- if (sidebarMode === "1/3" && !onToggle && onClose) {
2187
- onClose();
2188
- }
2189
- };
2190
- const handleAnimationEnd = () => {
2191
- if (!open && !onToggle) {
2192
- setIsVisible(false);
2193
- }
2194
- };
2195
- if (!isVisible && !onToggle) {
2196
- return null;
2197
- }
2198
- return (jsxRuntime.jsxs("div", { className: className, "data-testid": dataTestId, children: [!disableOverlay ? jsxRuntime.jsx(Overlay, { onClose: onClose, open: isAnimationStart }) : null, jsxRuntime.jsxs("div", { ...handlers, className: cvaDialog({
2199
- sidebarMode: isLargeScreen ? null : sidebarMode,
2200
- isLargeScreen,
2201
- open: isAnimationStart,
2202
- position: isLargeScreen ? position : undefined,
2203
- className: dialogClassName,
2204
- }), "data-testid": dataTestId ? `${dataTestId}-container` : undefined, onTransitionEnd: handleAnimationEnd, children: [isLargeScreen && onToggle ? jsxRuntime.jsx(ToogleButton, { onToggle: onToggle, open: open, position: position }) : null, jsxRuntime.jsxs("div", { className: cvaDialogContainer({
2205
- sidebarMode: isLargeScreen ? "full" : sidebarMode,
2206
- }), children: [jsxRuntime.jsx("div", { className: cvaSwipeContainer(), children: jsxRuntime.jsx("div", { className: cvaSwipeIcon() }) }), children] })] })] }));
2207
- };
2208
-
2209
1883
  const cvaSkeletonLine = cssClassVarianceUtilities.cvaMerge([
2210
1884
  "rounded-md",
2211
1885
  "h-3",
@@ -3739,7 +3413,7 @@ const PopoverContent = React.forwardRef(function PopoverContent({ className, dat
3739
3413
  var _a;
3740
3414
  const { context: floatingContext, customProps, ...context } = usePopoverContext();
3741
3415
  const ref = react.useMergeRefs([context.refs.setFloating, propRef]);
3742
- return (jsxRuntime.jsx(react.FloatingPortal, { id: portalId !== null && portalId !== void 0 ? portalId : "tu-floating-ui", children: context.isOpen ? (jsxRuntime.jsx(react.FloatingFocusManager, { closeOnFocusOut: false, context: floatingContext, guards: false, modal: context.isModal, order: ["reference", "content"], returnFocus: false, children: jsxRuntime.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: {
3416
+ return (jsxRuntime.jsx(react.FloatingPortal, { id: portalId !== null && portalId !== void 0 ? portalId : "tu-floating-ui", children: context.isOpen ? (jsxRuntime.jsx(react.FloatingFocusManager, { closeOnFocusOut: false, context: floatingContext, guards: true, modal: context.isModal, order: ["reference", "content"], returnFocus: true, children: jsxRuntime.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: {
3743
3417
  position: context.strategy,
3744
3418
  top: context.y,
3745
3419
  left: context.x,
@@ -4036,6 +3710,36 @@ const KPICard = ({ asChild = false, title, value, loading, unit, iconName, iconB
4036
3710
  return (jsxRuntime.jsxs(Comp, { className: cvaKPICardContainer({ className, isClickable: Boolean(asChild || onClick) }), "data-testid": `${dataTestId}-comp`, onClick: onClick, ...rest, children: [tooltipLabel ? (jsxRuntime.jsx(Tooltip, { className: "w-full", label: tooltipLabel, placement: "bottom", children: jsxRuntime.jsx(CardContent, {}) })) : (jsxRuntime.jsx(CardContent, {})), !loading && jsxRuntime.jsx(reactSlot.Slottable, { children: rest.children })] }));
4037
3711
  };
4038
3712
 
3713
+ const cvaMenuList = cssClassVarianceUtilities.cvaMerge([
3714
+ "shadow",
3715
+ "rounded-lg",
3716
+ "z-popover",
3717
+ "bg-white",
3718
+ "border",
3719
+ "border-slate-300",
3720
+ "grid",
3721
+ "min-w-[200px]",
3722
+ "max-w-[300px]",
3723
+ "p-1",
3724
+ ], {
3725
+ variants: {
3726
+ stickyHeader: {
3727
+ true: "grid-rows-min-fr grid overflow-y-hidden",
3728
+ false: "",
3729
+ },
3730
+ },
3731
+ });
3732
+ const cvaMenuListDivider = cssClassVarianceUtilities.cvaMerge(["mx-[-4px]", "my-1", "min-h-px", "bg-slate-300"]);
3733
+ const cvaMenuListMultiSelect = cssClassVarianceUtilities.cvaMerge("hover:!bg-blue-200");
3734
+ const cvaMenuListItem = cssClassVarianceUtilities.cvaMerge("max-w-[290px]");
3735
+
3736
+ /**
3737
+ * The MenuDivider component is used to separate items in a menu list.
3738
+ */
3739
+ const MenuDivider = () => {
3740
+ return jsxRuntime.jsx("div", { className: cvaMenuListDivider(), "data-testid": "menu-divider" });
3741
+ };
3742
+
4039
3743
  /**
4040
3744
  * Applies standardized interaction-related styles to an element.
4041
3745
  *
@@ -4088,45 +3792,108 @@ const cvaInteractableItem = cssClassVarianceUtilities.cvaMerge("", {
4088
3792
  },
4089
3793
  });
4090
3794
 
4091
- const cvaMenuItemStyle = cssClassVarianceUtilities.cvaMerge(["py-2", "px-2", "w-full", "h-auto", "flex", "flex-row", "items-center", "gap-x-2", "select-none", "rounded"], {
3795
+ /**
3796
+ * Extends the cvaInteractableItem variant in order to set the padding, width, height, cursor, and other styles particular to the MenuItem component.
3797
+ * The cvaInteractableItem variant is used to set the standardized styles that change through interaction with the element (background color, hover, focus, and disabled).
3798
+ */
3799
+ const cvaMenuItem = (props) => {
3800
+ const { size, selected, disabled, focused, className, variant } = props !== null && props !== void 0 ? props : {};
3801
+ return tailwindMerge.twMerge(cvaMenuItemStyle({ size, variant, selected, disabled }), cvaInteractableItem({ selected, disabled, cursor: "pointer", focused }), className);
3802
+ };
3803
+ const cvaMenuItemStyle = cssClassVarianceUtilities.cvaMerge(["py-2", "px-2", "h-auto", "flex", "flex-row", "items-center", "gap-x-2", "select-none", "rounded", "text-sm"], {
4092
3804
  variants: {
4093
3805
  size: {
4094
3806
  small: "py-1",
4095
3807
  medium: "py-2",
4096
3808
  },
3809
+ variant: {
3810
+ primary: [],
3811
+ danger: [
3812
+ "text-danger-600",
3813
+ "hover:!bg-danger-100",
3814
+ "focus:!bg-danger-200",
3815
+ "hover:!text-danger-700",
3816
+ "focus:!text-danger-800",
3817
+ ],
3818
+ },
3819
+ selected: {
3820
+ true: "",
3821
+ false: "",
3822
+ },
3823
+ disabled: {
3824
+ true: "text-black opacity-50",
3825
+ false: "",
3826
+ },
3827
+ },
3828
+ compoundVariants: [
3829
+ {
3830
+ /* danger not multi-select enabled */
3831
+ selected: true,
3832
+ variant: "danger",
3833
+ className: ["!bg-white"],
3834
+ },
3835
+ ],
3836
+ defaultVariants: {
3837
+ variant: "primary",
3838
+ selected: false,
3839
+ disabled: false,
4097
3840
  },
4098
3841
  });
4099
- /**
4100
- * Extends the cvaInteractableItem variant in order to set the padding, width, height, cursor, and other styles particular to the MenuItem component.
4101
- * The cvaInteractableItem variant is used to set the standardized styles that change through interaction with the element (background color, hover, focus, and disabled).
4102
- */
4103
- const cvaMenuItem = (props) => {
4104
- const { size, selected, disabled, focused, className } = props !== null && props !== void 0 ? props : {};
4105
- return tailwindMerge.twMerge(cvaMenuItemStyle({ size }), cvaInteractableItem({ selected, disabled, cursor: "pointer", focused }), className);
4106
- };
4107
- const cvaMenuItemLabel = cssClassVarianceUtilities.cvaMerge([
4108
- "flex-grow",
4109
- "text-gray-700",
4110
- "text-ellipsis",
4111
- "truncate",
4112
- "group-hover:text-gray-900",
4113
- "group-active:text-gray-700",
4114
- ]);
4115
- const cvaMenuItemSuffix = cssClassVarianceUtilities.cvaMerge(["self-center", "flex-grow-0", "text-slate-400", "text-sm"], {
3842
+ const cvaMenuItemLabel = cssClassVarianceUtilities.cvaMerge(["flex-grow", "truncate", "text-black", "font-normal"], {
3843
+ variants: {
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-black opacity-50",
3850
+ false: "",
3851
+ },
3852
+ },
3853
+ defaultVariants: {
3854
+ variant: "primary",
3855
+ disabled: false,
3856
+ },
3857
+ });
3858
+ const cvaMenuItemPrefix = cssClassVarianceUtilities.cvaMerge(["text-secondary-400", "hover:text-secondary-500", "focus:text-secondary-500", "h-min", "leading-[0]"], {
4116
3859
  variants: {
4117
3860
  selected: {
4118
- true: "text-primary-600 hover:text-primary-700",
3861
+ true: "text-secondary-600",
4119
3862
  false: "",
4120
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",
3870
+ false: "",
3871
+ },
3872
+ },
3873
+ defaultVariants: {
3874
+ variant: "primary",
3875
+ disabled: false,
4121
3876
  },
4122
3877
  });
4123
- const cvaMenuItemPrefix = cssClassVarianceUtilities.cvaMerge(["self-center", "flex-grow-0", "text-slate-400", "group-hover:text-slate-600", "h-min", "leading-[0]", "text-sm"], {
3878
+ const cvaMenuItemSuffix = cssClassVarianceUtilities.cvaMerge(["text-secondary-400", "text-sm"], {
4124
3879
  variants: {
4125
3880
  selected: {
4126
- true: "text-primary-600 hover:text-primary-700",
3881
+ true: "text-secondary-600",
3882
+ false: "",
3883
+ },
3884
+ variant: {
3885
+ primary: [],
3886
+ danger: ["text-danger-600", "hover:text-danger-700", "focus:bg-danger-200", "focus:text-danger-800"],
3887
+ },
3888
+ disabled: {
3889
+ true: "text-secondary opacity-50",
4127
3890
  false: "",
4128
3891
  },
4129
3892
  },
3893
+ defaultVariants: {
3894
+ variant: "primary",
3895
+ disabled: false,
3896
+ },
4130
3897
  });
4131
3898
 
4132
3899
  /**
@@ -4135,46 +3902,81 @@ const cvaMenuItemPrefix = cssClassVarianceUtilities.cvaMerge(["self-center", "fl
4135
3902
  * @param {MenuItemProps} props - The props for the MenuItem component
4136
3903
  * @returns {JSX.Element} MenuItem component
4137
3904
  */
4138
- const MenuItem = ({ className, dataTestId, label, size, children, selected, prefix, suffix, disabled, onClick, stopPropagation = true, id, tabIndex, }) => {
4139
- return (jsxRuntime.jsxs("div", { className: cvaMenuItem({
3905
+ const MenuItem = ({ className, dataTestId, label, size, children, selected, prefix, suffix, disabled, onClick, stopPropagation = true, id, tabIndex, variant = "primary", }) => {
3906
+ /* Handle tab navigation */
3907
+ const handleKeyDown = (e) => {
3908
+ if (e.key === "Enter" && onClick && !disabled) {
3909
+ stopPropagation && e.stopPropagation();
3910
+ // eslint-disable-next-line local-rules/no-typescript-assertion
3911
+ onClick(e);
3912
+ }
3913
+ };
3914
+ return (jsxRuntime.jsxs("div", { "aria-disabled": disabled, className: cvaMenuItem({
4140
3915
  selected,
4141
3916
  disabled,
4142
3917
  size,
4143
3918
  className,
4144
- }), "data-testid": dataTestId !== null && dataTestId !== void 0 ? dataTestId : "menu-item", id: id, onClick: e => {
3919
+ variant,
3920
+ }), "data-testid": dataTestId ? `${dataTestId}-menu-item` : "menu-item", id: id, onClick: e => {
4145
3921
  stopPropagation && e.stopPropagation();
4146
3922
  onClick === null || onClick === void 0 ? void 0 : onClick(e);
4147
- }, role: "menuitem", tabIndex: tabIndex !== null && tabIndex !== void 0 ? tabIndex : 0, children: [prefix ? (jsxRuntime.jsx("div", { className: cvaMenuItemPrefix({ selected }), "data-testid": dataTestId ? `${dataTestId}-prefix` : null, children: prefix })) : null, children && typeof children !== "string" ? (children) : (jsxRuntime.jsx("div", { className: cvaMenuItemLabel(), "data-testid": dataTestId ? `${dataTestId}-label` : null, children: children !== null && children !== void 0 ? children : label })), suffix ? (jsxRuntime.jsx("div", { className: cvaMenuItemSuffix({ selected }), "data-testid": dataTestId ? `${dataTestId}-suffix` : null, children: suffix })) : null] }));
3923
+ }, onKeyDown: handleKeyDown, role: "menuitem", tabIndex: disabled ? -1 : tabIndex !== null && tabIndex !== void 0 ? tabIndex : 0, children: [prefix ? (jsxRuntime.jsx("div", { className: cvaMenuItemPrefix({ selected, variant, disabled }), "data-testid": dataTestId ? `${dataTestId}-prefix` : "menu-item-prefix", children: prefix })) : null, children && typeof children !== "string" ? (children) : (jsxRuntime.jsx("div", { className: cvaMenuItemLabel({ variant, disabled }), "data-testid": dataTestId ? `${dataTestId}-label` : "menu-item-label", children: children !== null && children !== void 0 ? children : label })), suffix ? (jsxRuntime.jsx("div", { className: cvaMenuItemSuffix({ selected, variant, disabled }), "data-testid": dataTestId ? `${dataTestId}-suffix` : "menu-item-suffix", children: suffix })) : null] }));
4148
3924
  };
4149
3925
 
4150
- const cvaMenuList = cssClassVarianceUtilities.cvaMerge(["shadow-md", "rounded-lg", "z-popover", "bg-white", "border", "border-slate-300", "grid"], {
4151
- variants: {
4152
- stickyHeader: {
4153
- true: "grid-rows-min-fr grid overflow-y-hidden",
4154
- false: "",
4155
- },
4156
- },
4157
- });
4158
- const cvaMenuListDivider = cssClassVarianceUtilities.cvaMerge([
4159
- "file:w-full",
4160
- "selection:col-span-full",
4161
- "selection:h-px",
4162
- "selection:bg-slate-200",
4163
- ]);
4164
-
4165
3926
  /**
4166
- * The MenuList component is used for menus and selects.
4167
-
3927
+ * 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.
3928
+ *
3929
+ * **When to use**
3930
+ * - Use the MenuList if you have limited space and need to display overflow actions in a list.
3931
+ * - Use the MenuList for actions that are not essential to completing workflows.
3932
+ * - 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).
3933
+ *
4168
3934
  * @param {MenuListProps} props - The props for the MenuList component
4169
3935
  * @returns {JSX.Element} MenuList component
4170
3936
  */
4171
- const MenuList = ({ dataTestId, className, children, withStickyHeader = false, showDivider = false, ...args }) => {
3937
+ const MenuList = ({ dataTestId, className, children, withStickyHeader = false, isMulti = false, selectedItems: controlledSelectedItems, onSelectionChange, ...args }) => {
4172
3938
  const childrenArr = React.Children.toArray(children);
4173
- const isLastItem = (index) => index === childrenArr.length - 1;
4174
- return (jsxRuntime.jsx("div", { className: cvaMenuList({ stickyHeader: withStickyHeader, className }), "data-testid": dataTestId, onClick: args.onClick, role: "list", tabIndex: 0, children: React.Children.map(childrenArr, (menuItem, index) => (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [menuItem, showDivider && !isLastItem(index) ? jsxRuntime.jsx("hr", { className: cvaMenuListDivider() }) : null] }))) }));
3939
+ const [internalSelectedItems, setInternalSelectedItems] = React.useState(controlledSelectedItems !== null && controlledSelectedItems !== void 0 ? controlledSelectedItems : []);
3940
+ const selectedItems = controlledSelectedItems !== null && controlledSelectedItems !== void 0 ? controlledSelectedItems : internalSelectedItems;
3941
+ const handleItemClick = React.useCallback((id, disabled) => {
3942
+ if (disabled) {
3943
+ return;
3944
+ }
3945
+ const newSelectedItems = isMulti
3946
+ ? selectedItems.includes(id)
3947
+ ? selectedItems.filter(item => item !== id)
3948
+ : [...selectedItems, id]
3949
+ : [id];
3950
+ if (onSelectionChange) {
3951
+ onSelectionChange(newSelectedItems);
3952
+ }
3953
+ else {
3954
+ setInternalSelectedItems(newSelectedItems);
3955
+ }
3956
+ }, [isMulti, selectedItems, onSelectionChange]);
3957
+ return (jsxRuntime.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) => {
3958
+ var _a;
3959
+ if (React.isValidElement(menuItem)) {
3960
+ const isSelected = selectedItems.includes((_a = menuItem.props.id) !== null && _a !== void 0 ? _a : `${index}`) || menuItem.props.selected;
3961
+ return (jsxRuntime.jsx("div", { children: React.cloneElement(menuItem, {
3962
+ ...menuItem.props,
3963
+ onClick: (event) => {
3964
+ var _a, _b, _c;
3965
+ (_b = (_a = menuItem.props).onClick) === null || _b === void 0 ? void 0 : _b.call(_a, event);
3966
+ handleItemClick((_c = menuItem.props.id) !== null && _c !== void 0 ? _c : `${index}`, menuItem.props.disabled);
3967
+ },
3968
+ className: isMulti && isSelected
3969
+ ? cvaMenuListMultiSelect({ className: menuItem.props.className })
3970
+ : cvaMenuListItem({ className: menuItem.props.className }),
3971
+ selected: isSelected,
3972
+ suffix: isMulti && isSelected ? (jsxRuntime.jsx(Icon, { className: "h-5 text-blue-600", name: "Check", size: "medium", type: "solid" })) : null,
3973
+ }) }, index));
3974
+ }
3975
+ return null;
3976
+ }) }));
4175
3977
  };
4176
3978
 
4177
- const cvaMoreMenu = cssClassVarianceUtilities.cvaMerge(["p-4"]);
3979
+ const cvaMoreMenu = cssClassVarianceUtilities.cvaMerge(["p-0"]);
4178
3980
 
4179
3981
  /**
4180
3982
  * A kebab menu component.
@@ -4192,7 +3994,7 @@ const MoreMenu = ({ className, dataTestId, popoverProps, iconProps = {
4192
3994
  variant: "secondary",
4193
3995
  }, customButton, customPortalId, children, }) => {
4194
3996
  const actionMenuRef = React.useRef(null);
4195
- return (jsxRuntime.jsx("div", { className: cvaMoreMenu({ className }), "data-testid": dataTestId, ref: actionMenuRef, children: jsxRuntime.jsxs(Popover, { ...popoverProps, children: [jsxRuntime.jsx(PopoverTrigger, { children: customButton !== null && customButton !== void 0 ? customButton : jsxRuntime.jsx(IconButton, { ...iconButtonProps, icon: jsxRuntime.jsx(Icon, { name: "EllipsisHorizontal", ...iconProps }) }) }), jsxRuntime.jsx(PopoverContent, { portalId: customPortalId, children: close => (typeof children === "function" ? children(close) : children) })] }) }));
3997
+ return (jsxRuntime.jsx("div", { className: cvaMoreMenu({ className }), "data-testid": dataTestId, ref: actionMenuRef, children: jsxRuntime.jsxs(Popover, { placement: "bottom-end", ...popoverProps, children: [jsxRuntime.jsx(PopoverTrigger, { children: customButton !== null && customButton !== void 0 ? customButton : (jsxRuntime.jsx(IconButton, { dataTestId: "more-menu-icon", ...iconButtonProps, icon: jsxRuntime.jsx(Icon, { name: "EllipsisHorizontal", ...iconProps }) })) }), jsxRuntime.jsx(PopoverContent, { portalId: customPortalId, children: close => (typeof children === "function" ? children(close) : children) })] }) }));
4196
3998
  };
4197
3999
 
4198
4000
  const cvaNotice = cssClassVarianceUtilities.cvaMerge(["flex", "items-center"]);
@@ -4608,7 +4410,7 @@ const Sidebar = ({ childContainerClassName, children, breakpoint = "lg", classNa
4608
4410
  }) }), overflowItemCount > 0 ? (jsxRuntime.jsx(MoreMenu, { iconButtonProps: {
4609
4411
  circular: false,
4610
4412
  variant: "ghost-neutral",
4611
- }, popoverProps: { placement: "bottom-end" }, ...moreMenuProps, className: tailwindMerge.twMerge(moreMenuProps === null || moreMenuProps === void 0 ? void 0 : moreMenuProps.className, "!p-0"), dataTestId: dataTestId ? `${dataTestId}-more-menu` : undefined, children: close => (jsxRuntime.jsx(MenuList, { ...menuListProps, dataTestId: dataTestId ? `${dataTestId}-menu-list` : undefined, children: React.Children.map(children, child => {
4413
+ }, ...moreMenuProps, className: moreMenuProps === null || moreMenuProps === void 0 ? void 0 : moreMenuProps.className, dataTestId: dataTestId ? `${dataTestId}-more-menu` : undefined, children: close => (jsxRuntime.jsx(MenuList, { ...menuListProps, dataTestId: dataTestId, children: React.Children.map(children, child => {
4612
4414
  return itemOverflowMap[child.props.id]
4613
4415
  ? React.cloneElement(child, {
4614
4416
  onClick: () => {
@@ -4616,6 +4418,7 @@ const Sidebar = ({ childContainerClassName, children, breakpoint = "lg", classNa
4616
4418
  (_b = (_a = child.props).onClick) === null || _b === void 0 ? void 0 : _b.call(_a);
4617
4419
  close();
4618
4420
  },
4421
+ className: "w-full",
4619
4422
  })
4620
4423
  : null;
4621
4424
  }) })) })) : null] }));
@@ -5035,7 +4838,6 @@ exports.CardHeader = CardHeader;
5035
4838
  exports.Collapse = Collapse;
5036
4839
  exports.CompletionStatusIndicator = CompletionStatusIndicator;
5037
4840
  exports.CopyableText = CopyableText;
5038
- exports.Drawer = Drawer;
5039
4841
  exports.EmptyState = EmptyState;
5040
4842
  exports.EmptyValue = EmptyValue;
5041
4843
  exports.ExternalLink = ExternalLink;
@@ -5044,6 +4846,7 @@ exports.Icon = Icon;
5044
4846
  exports.IconButton = IconButton;
5045
4847
  exports.Indicator = Indicator;
5046
4848
  exports.KPICard = KPICard;
4849
+ exports.MenuDivider = MenuDivider;
5047
4850
  exports.MenuItem = MenuItem;
5048
4851
  exports.MenuList = MenuList;
5049
4852
  exports.MoreMenu = MoreMenu;