UNPKG

mdc-react

Version:

Material Components for the web implemented in React

134 lines (113 loc) 3.92 kB
import { forwardRef, useRef, useImperativeHandle, useEffect } from 'react'; import PropTypes from 'prop-types'; import classnames from 'classnames'; import Layer from '../layer'; import { numbers, cssClasses } from './constants'; import SideSheetHeader from './SideSheetHeader'; import SideSheetContent from './SideSheetContent'; const SideSheet = forwardRef(({ title, content, open = false, appear = false, dismissible = false, modal = false, closeIcon = dismissible && 'close', appContentSelector, onClose = Function.prototype, element = 'aside', component: Element = element, className, children, ...props }, ref) => { const rootRef = useRef(); useImperativeHandle(ref, () => rootRef.current); useEffect(() => { if (!dismissible) return; const appContentElement = appContentSelector ? document.querySelector(appContentSelector) : rootRef.current.nextElementSibling; appContentElement?.classList.add(cssClasses.APP_CONTENT); return () => { appContentElement?.classList.remove(cssClasses.APP_CONTENT); }; }, [dismissible, appContentSelector]); useEffect(() => { if (!modal) return; function handleDocumentKeyDown(event) { if (event.key && event.key === 'Escape' || event.keyCode === 27) { onClose(); } } document.addEventListener('keydown', handleDocumentKeyDown); return () => document.removeEventListener('keydown', handleDocumentKeyDown); }, [modal, onClose]); const classNames = classnames(cssClasses.ROOT, { [cssClasses.DISMISSIBLE]: dismissible, [cssClasses.MODAL]: modal }, className); return ( <Layer in={open} appear={appear} modal={modal} fixed={modal} timeout={{ enter: numbers.ANIMATION_ENTER_TIME_MS, exit: numbers.ANIMATION_EXIT_TIME_MS }} classNames={{ appear: cssClasses.OPEN, enter: `${cssClasses.OPEN} ${cssClasses.ANIMATE}`, enterActive: `${cssClasses.OPEN} ${cssClasses.OPENING}`, enterDone: cssClasses.OPEN, exit: `${cssClasses.OPEN} ${cssClasses.CLOSING}`, exitActive: cssClasses.CLOSING }} mountOnEnter={modal} unmountOnExit={modal} > <> <Element ref={rootRef} className={classNames} {...props} > {(title || dismissible) && <SideSheetHeader title={title} onClose={onClose} closeIcon={closeIcon} /> } {content && <SideSheetContent> {content} </SideSheetContent> } {children} </Element> {modal && <div className={cssClasses.SCRIM} onClick={onClose} /> } </> </Layer> ); }); SideSheet.displayName = 'MDCSideSheet'; SideSheet.propTypes = { title: PropTypes.string, content: PropTypes.node, closeIcon: PropTypes.node, open: PropTypes.bool, appear: PropTypes.bool, dismissible: PropTypes.bool, modal: PropTypes.bool, appContentSelector: PropTypes.string, onClose: PropTypes.func }; export default SideSheet;