/** * Copyright 2020 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ import * as React from 'react'; import { withStyles, IconButton, Menu, MenuItem } from '@material-ui/core'; import { MoreVert } from '@material-ui/icons'; export type MenuCloseHandler = () => void; interface Props { menuItems: (closeHandler: MenuCloseHandler) => React.ReactNode; icon?: React.ReactNode; } interface State { anchorEl: null | HTMLElement; } /** Button with no padding. */ export const SmallButton = withStyles({ root: { padding: 0 } })(IconButton); /** Menu item with smaller padding and fontSize */ export const SmallMenuItem = withStyles({ root: { fontSize: '13px', padding: '4px', }, })(MenuItem); /** Component for rendering a menu triggered by an icon button. */ export class IconButtonMenu extends React.Component<Props, State> { constructor(props: Props) { super(props); this.state = { anchorEl: null }; this._onMenuClose = this._onMenuClose.bind(this); } render() { const { icon, menuItems } = this.props; const { anchorEl } = this.state; const iconElement = icon || <MoreVert />; return ( <span> <IconButton onClick={e => this._onOpenMenu(e)}> {iconElement} </IconButton> <Menu anchorEl={anchorEl} open={Boolean(anchorEl)} keepMounted onClose={this._onMenuClose} > {menuItems(this._onMenuClose)} </Menu> </span> ); } private _onOpenMenu(event: React.MouseEvent<HTMLButtonElement>) { this.setState({ anchorEl: event.currentTarget }); } private _onMenuClose() { this.setState({ anchorEl: null }); } }