UNPKG

@momentum-ui/react

Version:

Cisco Momentum UI framework for ReactJs applications

131 lines (112 loc) 3.4 kB
/** @component menu */ import React from 'react'; import { findDOMNode } from 'react-dom'; import PropTypes from 'prop-types'; import omit from 'lodash/omit'; import { UIDReset } from 'react-uid'; import { EventOverlay } from '@momentum-ui/react'; import MenuContext from '../MenuContext'; class MenuOverlay extends React.Component { state = { isOpen: this.props.isOpen || false } componentDidMount() { this.props.isOpen && this.forceUpdate(); } componentDidUpdate(prevProps, prevState) { const { focusFirstQuery } = this.props; const { isOpen } = this.state; if(!prevState.isOpen && prevState !== isOpen && focusFirstQuery) { const overlay = findDOMNode(this.menuOverlay); const focusElement = overlay && overlay.querySelector(focusFirstQuery); focusElement && focusElement.focus(); } } onSelect = (e, opts) => { const { onSelect } = this.props; const { eventKey, element } = opts; const { keepMenuOpen } = element.props; onSelect && onSelect(e, {eventKey, element}); element.constructor.displayName !== 'SubMenu' && !keepMenuOpen && this.handleClose(); }; handleClose = () => { this.setState({ isOpen: false }); }; render() { const { children, className, menuTrigger, showArrow, ...props } = this.props; const { isOpen } = this.state; const otherProps = omit({...props}, [ 'isOpen', 'focusFirstQuery', 'onSelect' ]); const setMenuTrigger = () => React.cloneElement(menuTrigger, { onClick: () => this.setState({ isOpen: !isOpen }), ref: ref => this.anchorNode = ref, }); return ( <div className={ 'md-menu-overlay-wrapper' + `${(className && ` ${className}`) || ''}` } > {setMenuTrigger()} { isOpen && <EventOverlay allowClickAway anchorNode={this.anchorNode} className='md-menu-overlay' close={this.handleClose} isOpen={isOpen} ref={ref => this.menuOverlay = ref} showArrow={showArrow} {...otherProps} > <MenuContext.Provider value={{ parentOnSelect: this.onSelect }}> <UIDReset> {children} </UIDReset> </MenuContext.Provider> </EventOverlay> } </div> ); } } MenuOverlay.propTypes = { /** @prop Children nodes to render inside MenuOverlay | null */ children: PropTypes.node, /** @prop Optional css class name | '' */ className: PropTypes.string, /** @prop Queries children to find matching item to have focus | '' */ focusFirstQuery: PropTypes.string, /** @prop Prop to initalize state as open | false */ isOpen: PropTypes.bool, /** @prop HTML element that provides control to MenuOverlay user */ menuTrigger: PropTypes.element.isRequired, /** @prop Callback function invoked when user selects MenuOverlay | null */ onSelect: PropTypes.func, /** @prop Determines if the MenuOverlay should show the open/close arrow | true */ showArrow: PropTypes.bool, }; MenuOverlay.defaultProps = { children: null, className: '', focusFirstQuery: '', isOpen: false, onSelect: null, showArrow: true, }; MenuOverlay.displayName = 'MenuOverlay'; export default MenuOverlay;