UNPKG

@equinor/eds-core-react

Version:

The React implementation of the Equinor Design System

237 lines (233 loc) 8.08 kB
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 };