import React, { Component, createRef, MouseEvent, ReactNode, StatelessComponent, } from 'react' import Link from 'react-router/lib/Link' import styled, { css } from 'styled-components' import { array, isEmpty } from 'fp-ts/lib/Array' import { none, some } from 'fp-ts/lib/Option' import { Colors, ellipsis, flexFlow, FontSizes, getColor, Sizes, typography, } from '@monorail/helpers/exports' import { PopOverChildProps } from '@monorail/metaComponents/popOver/PopOver' import { isNil } from '@monorail/sharedHelpers/typeGuards' import { CommonComponentType, LinkProps } from '@monorail/types' import { IconType } from '@monorail/visualComponents/icon/IconType' import { Search } from '@monorail/visualComponents/inputs/Search' import { SearchController } from '@monorail/visualComponents/inputs/SearchController' import { ScrollAnimation } from '@monorail/visualComponents/layout/ScrollAnimation' import { ListContainer, ListItem, ListItemGraphic, ListItemPrimaryText, ListItemSecondaryText, ListItemText, } from '@monorail/visualComponents/list/List' import { SidebarDropDown } from '@monorail/visualComponents/sidebar/SidebarDropDown' const SearchContainer = styled.div` ${flexFlow('row')}; align-items: center; flex-shrink: 0; ` const MenuHeader = styled.span( ({ cssOverrides }) => css` ${typography(500, FontSizes.Title5, '12px')}; ${ellipsis}; color: ${getColor(Colors.Black62a)}; flex-shrink: 0; ${cssOverrides}; `, ) const MenuItemIconRow = styled.div` ${flexFlow('row')}; flex: 1 1 100%; margin: 8px 6px 12px; ` type SimpleListItemProps = CommonComponentType & LinkProps & { dense?: boolean disabled?: boolean leftIcon?: IconType onClick?: (event: MouseEvent) => void primaryText?: ReactNode rightIcon?: IconType secondaryText?: ReactNode size?: Sizes meta?: ReactNode } const ContextMenuItem: StatelessComponent = ({ leftIcon, rightIcon, primaryText, secondaryText, children, dense, meta, size, cssOverrides, ...otherProps }) => ( {!isNil(leftIcon) && ( )} {isNil(secondaryText) && isNil(meta) ? ( {primaryText} ) : ( {primaryText} {isNil(secondaryText) ? null : ( {secondaryText} )} {meta} )} {!isNil(rightIcon) && } {children} ) export type ContextMenuItemProps = { description: string icons?: ReactNode isLabelActive?: boolean key: number | string link: string title: string } export type ContextMenuItems = Array<{ title: string items: Array }> type Props = PopOverChildProps & { onItemClick?: (item: ContextMenuItemProps) => void contextItems: ContextMenuItems icon: IconType renderFilter: () => ReactNode width?: number } export class ContextMenu extends Component { static defaultProps = { renderFilter: () => null, } searchRef = createRef() componentDidUpdate(prevProps: Readonly) { const searchRef = this.searchRef.current if (!isNil(searchRef) && !prevProps.isOpen && this.props.isOpen) { window.setTimeout(() => searchRef.focus(), 50) } } renderContextMenuItems = ( compareSearch: (stringToCompare: string) => boolean, ) => { const { contextItems, icon, onClick, onItemClick } = this.props return contextItems.map(event => { const groupHeader = ( {event.title} ) const items = event.items .filter( item => compareSearch(item.title) || compareSearch(item.description) || compareSearch(event.title), ) .map(item => ( ( )} // tslint:enable key={item.key} leftIcon={icon} primaryText={item.title} secondaryText={item.description} size={Sizes.DP40} to={item.link} onClick={(e: MouseEvent) => { onClick(e) if (onItemClick) { onItemClick(item) } }} tabIndex={1} meta={ isNil(item.icons) ? null : ( {item.icons} ) } /> )) return items.length > 0 ? some([groupHeader, items]) : none }) } render() { const { closingAnimationCompleted, isOpen, onClick, position, renderFilter, togglePopOver, width, } = this.props return ( {({ compareSearch, value, onChange }) => { const contextMenuItems = array.compact( this.renderContextMenuItems(compareSearch), ) return ( <> {renderFilter()} {isEmpty(contextMenuItems) ? ( ) : ( contextMenuItems )} ) }} ) } }