@veracity/vui
Version:
Veracity UI is a React component library crafted for use within Veracity applications and pages. Based on Styled Components and @xstyled.
235 lines (233 loc) • 7.96 kB
JavaScript
import { generateMenuItemId } from "../utils/string.js";
import colors_default from "../theme/foundations/colors.js";
import { cs } from "../utils/styles.js";
import { omitThemingProps, th } from "../core/theme.js";
import styled from "../core/styled.js";
import vui from "../core/vui.js";
import { Box } from "../box/box.js";
import { Button } from "../button/button.js";
import Popover from "../popover/popover.js";
import { Tooltip } from "../tooltip/tooltip.js";
import SidemenuItemContent from "./SidemenuItemContent.js";
import useSidemenuItem from "./useSidemenuItem.js";
import { useCallback, useEffect, useMemo } from "react";
import { jsx, jsxs } from "react/jsx-runtime";
//#region src/sidemenuV2/sidemenuItemV2.tsx
const PopoverHovered = styled.div`
&:hover .vui-sidemenu-item-popover .vui-button.vui-button {
background: ${(p) => th.color(p.hoverColor)};
}
&:hover div:last-child .vui-sidemenu-item-content > .vui-box > .vui-button.vui-button {
background: ${(p) => th.color(p.hoverColor)};
}
`;
const SidemenuPopover = ({ isDark, className, buttonStyles, isExactlyActive, icon, title, isMenuExpanded, children }) => /* @__PURE__ */ jsx(Popover, {
offset: [0, 52 - 240 - 2],
placement: "right-start",
trigger: "mouseenter",
children: ({ isOpen }) => /* @__PURE__ */ jsxs(PopoverHovered, {
hoverColor: isDark ? colors_default.seaBlue.main : colors_default.skyBlue.selected,
children: [/* @__PURE__ */ jsx(Popover.Trigger, {
as: Box,
className: cs("vui-sidemenu-item-popover", className),
children: /* @__PURE__ */ jsx(Button, {
...buttonStyles,
borderLeft: `3px solid ${isDark ? "digiGreen.main" : "seaBlue.main"}`,
isActive: isExactlyActive,
className: cs("focusAsBorder"),
children: /* @__PURE__ */ jsx(SidemenuItemContent, {
icon,
iconSize: buttonStyles.iconSize,
title,
isMenuExpanded
})
})
}), /* @__PURE__ */ jsx(Popover.Content, {
elevation: "none",
className: cs("vui-sidemenu-item-content", className),
children: /* @__PURE__ */ jsxs(Box, {
flexDirection: "column",
justifyContent: "start",
w: "100%",
children: [/* @__PURE__ */ jsx(Button, {
...buttonStyles,
borderLeftColor: "transparent!important",
minW: "240px",
isActive: isOpen && isExactlyActive,
className: cs("focusAsBorder"),
children: /* @__PURE__ */ jsx(SidemenuItemContent, {
title,
isInPopover: true
})
}), children]
})
})]
})
});
/** A menu item. */
const SidemenuItemV2 = vui((props, ref) => {
const { children, className, disabled = false, icon, isActive = false, isExpanded = true, itemId, level = 0, onBottom = false, onClick, onCollapse, onExpand, title, ...rest } = omitThemingProps(props);
const computedItemId = itemId || generateMenuItemId(title, level) || `item-${Math.random().toString(36).substr(2, 9)}`;
const { isDark, isMenuExpanded, styles, size, isSubmenuOpen, toggleSubmenu } = useSidemenuItem(computedItemId);
const isExactlyActive = isActive;
useEffect(() => {
if (isMenuExpanded) {
if (isSubmenuOpen) onExpand?.();
if (!isSubmenuOpen) onCollapse?.();
}
}, [
isSubmenuOpen,
onExpand,
onCollapse,
isMenuExpanded
]);
const computedStates = useMemo(() => {
const hasChildren = !!children;
return {
hasChildren,
hasChildrenCollapsed: hasChildren && !isSubmenuOpen,
hasChildrenExpanded: hasChildren && isSubmenuOpen && isMenuExpanded,
shouldShowExpandButton: hasChildren && isMenuExpanded,
buttonSize: level < 1 ? "lg" : "md",
iconSize: level < 1 ? "sm" : "xs",
isDisabled: disabled,
shouldShowBorder: !hasChildren || isSubmenuOpen
};
}, [
children,
isSubmenuOpen,
isMenuExpanded,
disabled,
size,
level
]);
const themeValues = useMemo(() => ({ activeColor: isDark ? "digiGreen.main" : "seaBlue.main" }), [isDark]);
const handleClick = useCallback((event) => {
if (!computedStates.isDisabled) {
const targetTag = event.target;
if ((targetTag.classList.contains("vui-tagText") || targetTag.classList.contains("vui-tag")) && typeof window !== "undefined" && (targetTag.parentElement?.dataset.link || targetTag?.dataset.link)) {
const url = atob(targetTag.parentElement?.dataset.link ?? targetTag?.dataset.link ?? "");
window.open(url, "_blank", "noopener,noreferrer");
} else {
event?.stopPropagation?.();
onClick?.();
}
}
toggleSubmenu?.();
}, [onClick, computedStates.isDisabled]);
const buttonStyles = useMemo(() => ({
...styles && "item" in styles && styles.item ? styles.item : {},
...styles && "button" in styles && styles.button ? styles.button : {},
borderLeftColor: isExactlyActive ? themeValues.activeColor : "transparent",
transitionProperty: "background-color, border-color, color, transform, opacity",
size: computedStates.buttonSize,
h: computedStates.buttonSize === "lg" ? 40 : 36,
iconSize: computedStates.iconSize,
variant: "tertiaryBrand",
onClick: handleClick,
disabled: computedStates.isDisabled,
role: "button",
tabIndex: computedStates.isDisabled ? -1 : 0,
"aria-disabled": computedStates.isDisabled,
"aria-pressed": isExactlyActive,
...rest
}), [
styles,
computedStates,
isExactlyActive,
themeValues,
handleClick,
rest
]);
const expandButtonProps = useMemo(() => {
const isExpanded = isSubmenuOpen;
return {
"aria-label": isExpanded ? "Collapse" : "Expand",
className: "vui-sidemenu-item-expand",
variant: "tertiaryBrand",
icon: isExpanded ? "falChevronUp" : "falChevronDown",
size: "sm",
pl: "4px",
pr: "16px",
ml: "auto",
h: "100%",
border: "none",
bg: "transparent",
hoverBg: "transparent",
activeBg: "transparent"
};
}, [isSubmenuOpen]);
const renderPopover = () => /* @__PURE__ */ jsx(SidemenuPopover, {
isDark,
className,
buttonStyles,
isExactlyActive,
icon,
title,
isMenuExpanded,
children: children ? children : void 0
});
const renderButton = () => {
if (level === 0 && !isMenuExpanded) return /* @__PURE__ */ jsx(Tooltip, {
text: title,
placement: "right",
offset: [0, -200],
children: /* @__PURE__ */ jsxs(Button, {
className: cs("vui-sidemenu-item focusAsBorder", isExactlyActive && "vui-sidemenu-item--active", className),
...buttonStyles,
isActive: isExactlyActive,
children: [
/* @__PURE__ */ jsx(SidemenuItemContent, {
icon,
iconSize: buttonStyles.iconSize
}),
isMenuExpanded && computedStates.shouldShowExpandButton && /* @__PURE__ */ jsx(Button, { ...expandButtonProps }),
" "
]
})
});
return /* @__PURE__ */ jsxs(Button, {
className: cs("vui-sidemenu-item focusAsBorder", isExactlyActive && "vui-sidemenu-item--active", className),
...buttonStyles,
isActive: isExactlyActive,
title: !isMenuExpanded ? title : void 0,
children: [
/* @__PURE__ */ jsx(SidemenuItemContent, {
icon,
iconSize: buttonStyles.iconSize,
title,
isMenuExpanded,
badge: props.badge,
badgeLinkUrl: props.badgeLinkUrl
}),
isMenuExpanded && computedStates.shouldShowExpandButton && /* @__PURE__ */ jsx(Button, { ...expandButtonProps }),
" "
]
});
};
const renderChildren = () => /* @__PURE__ */ jsx(Box, {
flexDirection: "column",
justifyContent: "start",
w: "100%",
children
});
const shouldShowPopover = Boolean(!isMenuExpanded && level === 0 && !!children);
const shouldShowChildren = computedStates.hasChildrenExpanded;
return /* @__PURE__ */ jsxs(Box, {
flexDirection: "column",
ref,
w: "100%",
mt: onBottom ? "auto" : 0,
id: computedItemId,
children: [
shouldShowPopover && renderPopover(),
!shouldShowPopover && renderButton(),
shouldShowChildren && renderChildren()
]
});
});
SidemenuItemV2.displayName = "SidemenuItemV2";
//#endregion
export { PopoverHovered, SidemenuItemV2, SidemenuItemV2 as default };
globalThis.__vuiVersion__ = "5.3.1"
//# sourceMappingURL=sidemenuItemV2.js.map