import * as React from 'react' ; import classnames from 'classnames' ; import { MDCMenuFoundation } from '@material/menu/foundation' ; import { MDCMenuAdapter } from '@material/menu/adapter' ; import MenuSurface , { MenuSurfaceProps } from '@material/react-menu-surface' ; import MenuList , { MenuListProps } from './MenuList' ; import MenuListItem from './MenuListItem' ; const { cssClasses } = MDCMenuFoundation ; export interface MenuProps extends MenuSurfaceProps { children : React . ReactElement < MenuList > ; onSelected ? : ( index : number , item : Element ) => void ; ref ? : React . Ref < any > ; } export interface MenuState { open : boolean ; foundation ? : MDCMenuFoundation ; } class Menu extends React . Component < MenuProps , MenuState > { menuListElement = React . createRef < MenuList > ( ) ; state : MenuState = { foundation : undefined , open : this . props . open || false , } ; static defaultProps : Partial < MenuProps > = { className : '' , open : false , onKeyDown : ( ) => { } , onSelected : ( ) => { } , } ; componentDidMount ( ) { const foundation = new MDCMenuFoundation ( this . adapter ) ; foundation . init ( ) ; this . setState ( { foundation } ) ; } componentDidUpdate ( prevProps ) { if ( this . props . open !== prevProps . open ) { this . setState ( { open : this . props . open ! } ) ; } } componentWillUnmount ( ) { if ( this . state . foundation ) { this . state . foundation . destroy ( ) ; } } get listElements ( ) : Element [ ] { if ( ! ( this . menuListElement . current && this . menuListElement . current . listElements && this . menuListElement . current . listElements . length >= 0 ) ) { return [ ] ; } return this . menuListElement . current . listElements ; } get adapter ( ) : MDCMenuAdapter { return { addClassToElementAtIndex : ( index , className ) => { const list = this . listElements ; list [ index ] . classList . add ( className ) ; } , removeClassFromElementAtIndex : ( index , className ) => { const list = this . listElements ; list [ index ] . classList . remove ( className ) ; } , addAttributeToElementAtIndex : ( index , attr , value ) => { const list = this . listElements ; list [ index ] . setAttribute ( attr , value ) ; } , removeAttributeFromElementAtIndex : ( index , attr ) => { const list = this . listElements ; list [ index ] . removeAttribute ( attr ) ; } , elementContainsClass : ( element , className ) => element . classList . contains ( className ) , closeSurface : ( ) => this . setState ( { open : false } ) , getElementIndex : ( element ) => this . listElements . indexOf ( element ) , getParentElement : ( element ) => element . parentElement , getSelectedElementIndex : ( selectionGroup ) => { const selectedListItem = selectionGroup . querySelector ( `.${ cssClasses . MENU_SELECTED_LIST_ITEM }` ) ; return selectedListItem ? this . listElements . indexOf ( selectedListItem ) : - 1 ; } , notifySelected : ( evtData ) => this . props . onSelected ! ( evtData . index , this . listElements [ evtData . index ] ) , } ; } handleKeyDown : React . KeyboardEventHandler < HTMLDivElement > = ( evt ) => { const { onKeyDown } = this . props ; if ( onKeyDown ) { onKeyDown ( evt ) ; } this . state . foundation && this . state . foundation . handleKeydown ( evt . nativeEvent ) ; } ; handleOpen : MenuSurfaceProps [ 'onOpen' ] = ( ) => { const { onOpen } = this . props ; onOpen && onOpen ( ) ; } ; render ( ) { const { className , open , onKeyDown , onOpen , children , onSelected , ... otherProps } = this . props ; return ( < MenuSurface tabIndex = { - 1 } open = { this . state . open } className = { classnames ( 'mdc-menu' , className ) } onKeyDown = { this . handleKeyDown } onOpen = { this . handleOpen } { ... otherProps } > { this . renderChild ( ) } < /MenuSurface>); } renderChild ( ) { const { children } = this . props ; const { foundation } = this . state ; if ( ! children ) return ; let handleItemAction = ( ) => { } ; if ( foundation ) { handleItemAction = foundation . handleItemAction . bind ( foundation ) ; } const updatedProps = { ... children . props , handleItemAction , ref : this . menuListElement , wrapFocus : true , } ; return React . cloneElement ( children , updatedProps ) ; } } export default Menu ; export { MenuList , MenuListItem } ; export { ListDivider as MenuListDivider , ListGroup as MenuListGroup , ListGroupSubheader as MenuListGroupSubheader , ListItemGraphic as MenuListItemGraphic , ListItemMeta as MenuListItemMeta , ListItemText as MenuListItemText , } from '@material/react-list' ; export { MenuListProps } from './MenuList' ; export { MenuListItemProps } from './MenuListItem' ;