@equinor/eds-core-react
Version:
The React implementation of the Equinor Design System
237 lines (233 loc) • 8.08 kB
JavaScript
import { forwardRef, useState, useMemo, Children } from 'react';
import styled, { css } from 'styled-components';
import { bordersTemplate, outlineTemplate, useId, mergeRefs } from '@equinor/eds-utils';
import { chevron_up, chevron_down, arrow_drop_down } from '@equinor/eds-icons';
import { useSideBar } from '../SideBar.context.js';
import { sidebar } from '../SideBar.tokens.js';
import { Icon } from '../../Icon/index.js';
import { Menu } from '../../Menu/index.js';
import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
import { Typography } from '../../Typography/Typography.js';
import { Tooltip as Tooltip$1 } from '../../Tooltip/Tooltip.js';
const {
minWidth,
entities: {
sidebarItem: {
minHeight,
border,
typography: {
color: typographyColor
},
states: {
active: {
background: menuActiveBackground,
typography: {
color: typographyActiveColor
}
},
hover: {
background: menuHoverBackground
},
focus,
disabled: {
background: menuDisabledBackground,
typography: {
color: menuDisabledText
}
}
}
}
}
} = sidebar;
const MenuItem = styled.div.withConfig({
displayName: "SideBarAccordion__MenuItem",
componentId: "sc-1ekwnbi-0"
})(({
$isExpanded
}) => {
return css(["display:grid;grid-template-columns:1fr;place-items:center;text-decoration:none;min-height:", ";", ";&:hover{cursor:pointer;background-color:", ";}&:focus-visible{", ";}"], minHeight, !$isExpanded && bordersTemplate(border), !$isExpanded ? menuHoverBackground : 'none', outlineTemplate(focus.outline));
});
const AccordionHeader = styled.h2.withConfig({
displayName: "SideBarAccordion__AccordionHeader",
componentId: "sc-1ekwnbi-1"
})(({
$active
}) => {
return css(["margin:0;width:100%;min-height:", ";background-color:", ";&:hover{cursor:pointer;background-color:", ";}"], minHeight, $active ? menuActiveBackground : 'none', $active ? menuActiveBackground : menuHoverBackground);
});
const Button = styled.button.withConfig({
displayName: "SideBarAccordion__Button",
componentId: "sc-1ekwnbi-2"
})(({
$active
}) => {
return css(["width:100%;min-height:", ";padding:0;border:none;background-color:", ";cursor:pointer;display:grid;place-items:center;&:focus-visible{", ";}&:disabled{background-color:", ";cursor:auto;}"], minHeight, $active ? menuActiveBackground : 'transparent', outlineTemplate(focus.outline), menuDisabledBackground);
});
const OpenSidebarButton = styled(Button).withConfig({
displayName: "SideBarAccordion__OpenSidebarButton",
componentId: "sc-1ekwnbi-3"
})(["grid-template-columns:", " 1fr 48px;"], minWidth);
const ClosedSidebarButton = styled(Button).withConfig({
displayName: "SideBarAccordion__ClosedSidebarButton",
componentId: "sc-1ekwnbi-4"
})(["grid-template-columns:", ";position:relative;overflow:hidden;"], minWidth);
const AccordionIcon = styled(Icon).withConfig({
displayName: "SideBarAccordion__AccordionIcon",
componentId: "sc-1ekwnbi-5"
})(["position:absolute;bottom:-10px;right:-10px;transform:rotate(-45deg);"]);
const Panel = styled.div.withConfig({
displayName: "SideBarAccordion__Panel",
componentId: "sc-1ekwnbi-6"
})(["width:100%;", ""], bordersTemplate(border));
const ItemText = styled(Typography).withConfig({
displayName: "SideBarAccordion__ItemText",
componentId: "sc-1ekwnbi-7"
})(({
$textColor
}) => {
return css(["justify-self:start;color:", ";&::first-letter{text-transform:capitalize;}"], $textColor);
});
const Tooltip = styled(Tooltip$1).withConfig({
displayName: "SideBarAccordion__Tooltip",
componentId: "sc-1ekwnbi-8"
})(["text-transform:capitalize;"]);
const SideBarAccordion = /*#__PURE__*/forwardRef(function SideBarAccordion({
icon,
label,
isExpanded,
id,
active,
toggleExpand,
onClick,
children,
disabled,
...rest
}, ref) {
const accordionId = useId(id, 'accordion');
const [menuIsOpen, setMenuIsOpen] = useState(false);
const [accordionIsOpen, setAccordionIsOpen] = useState(isExpanded);
const [anchorEl, setAnchorEl] = useState(null);
const {
isOpen
} = useSideBar();
const showPanel = toggleExpand !== undefined ? isExpanded : accordionIsOpen;
const showAsActive = useMemo(() => {
// Active-state is controlled
if (active !== undefined) {
return active;
}
let hasActiveChild = false;
Children.forEach(children, child => {
const item = child;
if (item.props.active) {
hasActiveChild = true;
}
});
// When Sidebar is expanded, we only show accordion header as active if the accordion is closed, to avoid showing two active items at the same time.
return isOpen ? !showPanel && hasActiveChild : hasActiveChild;
}, [active, children, showPanel, isOpen]);
const combinedRefs = useMemo(() => mergeRefs(setAnchorEl, ref), [ref]);
const closeMenu = () => {
setMenuIsOpen(false);
};
const onClickWhenSidePanelExpanded = () => {
if (toggleExpand === undefined) {
setAccordionIsOpen(!accordionIsOpen);
} else {
toggleExpand();
}
onClick && onClick();
};
const onClickWhenSidePanelClosed = () => {
setMenuIsOpen(!menuIsOpen);
onClick && onClick();
};
const getTextColor = () => {
if (showAsActive) {
return typographyActiveColor;
} else if (disabled) {
return menuDisabledText;
}
return typographyColor;
};
if (isOpen) {
return /*#__PURE__*/jsxs(MenuItem, {
$isExpanded: showPanel,
children: [/*#__PURE__*/jsx(AccordionHeader, {
$active: showAsActive,
children: /*#__PURE__*/jsxs(OpenSidebarButton, {
ref: ref,
id: `header_${accordionId}`,
"aria-expanded": showPanel,
"aria-controls": `panel_${accordionId}`,
onClick: onClickWhenSidePanelExpanded,
disabled: disabled,
...rest,
children: [icon && /*#__PURE__*/jsx(Icon, {
data: icon,
color: getTextColor()
}), /*#__PURE__*/jsx(ItemText, {
variant: "cell_text",
group: "table",
$textColor: getTextColor(),
children: label
}), /*#__PURE__*/jsx(Icon, {
data: showPanel ? chevron_up : chevron_down,
size: 24,
color: getTextColor()
})]
})
}), showPanel && /*#__PURE__*/jsx(Panel, {
id: `panel_${accordionId}`,
role: "region",
"aria-labelledby": `header_${accordionId}`,
children: children
})]
});
}
const tooltip = menuIsOpen ? '' : label;
return /*#__PURE__*/jsxs(Fragment, {
children: [/*#__PURE__*/jsx(Tooltip, {
title: tooltip,
placement: "right",
children: /*#__PURE__*/jsx(MenuItem, {
$isExpanded: showPanel,
children: /*#__PURE__*/jsx(AccordionHeader, {
$active: showAsActive,
children: /*#__PURE__*/jsxs(ClosedSidebarButton, {
ref: combinedRefs,
id: "anchor-default",
"aria-haspopup": "true",
"aria-expanded": menuIsOpen,
"aria-controls": "menu-default",
onClick: onClickWhenSidePanelClosed,
disabled: disabled,
...rest,
children: [icon && /*#__PURE__*/jsx(Icon, {
data: icon,
color: getTextColor()
}), /*#__PURE__*/jsx(AccordionIcon, {
data: arrow_drop_down,
size: 24,
color: getTextColor()
})]
})
})
})
}), /*#__PURE__*/jsx(Menu, {
open: menuIsOpen,
placement: 'right-start',
onClose: closeMenu,
anchorEl: anchorEl,
children: Children.map(children, child => {
const item = child;
return /*#__PURE__*/jsx(Menu.Item, {
...child.props,
children: item.props.label
});
})
})]
});
});
SideBarAccordion.displayName = 'SidebarAccordion';
export { SideBarAccordion };