UNPKG

@drivy/cobalt

Version:

Opinionated design system for Drivy's projects.

56 lines (53 loc) 3.52 kB
import { jsxs, Fragment, jsx } from 'react/jsx-runtime'; import cx from 'classnames'; import React, { useState, useEffect } from 'react'; import ReactDOM from 'react-dom'; import { getA11yOnClick } from '../../helpers/index.js'; import useBreakpoint from '../../hooks/useBreakpoint.js'; import Button from '../Buttons/Button/index.js'; import '../Icon/index.js'; import { Fixed } from '../Layout/Surfaces/index.js'; import Modal from '../Modal/index.js'; import CloseIcon from '../Icon/__generated__/CloseIcon.js'; const SidepanelFooter = ({ children, className }) => { return (jsx("div", { className: cx("c-p-sm c-border-t c-border-outline", className), children: children })); }; // Memoized component to not render content when the panel is collapsing function _SidepanelContent({ title, close, children }) { return (jsxs(Fragment, { children: [title && (jsxs("div", { className: "c-flex c-gap-sm c-items-start c-px-sm c-py-md c-border-b c-border-outline", children: [jsx("div", { className: "c-text-title-md c-flex-1", children: title }), close && (jsx(Button, { className: "cobalt-sidepanel__close", icon: jsx(CloseIcon, {}), text: true, ...getA11yOnClick(close) }))] })), children] })); } function areSidepanelContentEqual(_prevProps, nextProps) { return !nextProps.isOpen; } const SidepanelContent = React.memo(_SidepanelContent, areSidepanelContentEqual); SidepanelContent.displayName = "SidepanelContent"; // Only for the API, render nothing const SidepanelFooterAPI = (_props) => null; const isSidepanelFooterAPIComponent = (component) => React.isValidElement(component) && component.type === SidepanelFooterAPI; const _Sidepanel = ({ isOpen, title, close, withDesktopOverlay, onPointerDownOutside, width = 420, children, }) => { const { isMobile } = useBreakpoint(); // To display box-shadow when visible. We can't rely on isOpen because it triggers the collapse animation and so the box shadow would not be set during the transition const [isPanelVisible, setIsPanelVisible] = useState(false); useEffect(() => { isOpen && setIsPanelVisible(true); }, [isOpen]); const sidepanelFooter = React.Children.toArray(children).find((c) => isSidepanelFooterAPIComponent(c)); let footer = null; if (React.isValidElement(sidepanelFooter)) { footer = isMobile ? (jsx(Modal.Footer, { ...sidepanelFooter.props })) : (jsx(SidepanelFooter, { ...sidepanelFooter.props })); } return isMobile ? (jsxs(Modal, { "aria-label": "Sidepanel", isOpen: isOpen, bodySpacing: false, close: close, title: title, fullScreen: true, children: [children, footer] })) : (ReactDOM.createPortal(jsxs(Fragment, { children: [jsx("div", { className: cx("cobalt-sidepanel", { "cobalt-sidepanel--show": isOpen, "cobalt-sidepanel--visible": isPanelVisible, }), onTransitionEnd: () => { !isOpen && setIsPanelVisible(false); }, children: jsx(Fixed, { width: width, isFullHeight: true, children: jsxs(SidepanelContent, { isOpen: isOpen, title: title, close: close, children: [children, footer] }) }) }), withDesktopOverlay && (jsx("div", { className: "cobalt-sidepanel-overlay", ...(onPointerDownOutside ? getA11yOnClick(onPointerDownOutside) : {}) }))] }), document.body)); }; _Sidepanel.displayName = "Sidepanel"; const Sidepanel = Object.assign(_Sidepanel, { Footer: SidepanelFooterAPI, }); export { Sidepanel }; //# sourceMappingURL=index.js.map