import { LocationDescriptor } from "history"; import { CheckmarkIcon } from "outline-icons"; import { ellipsis } from "polished"; import * as React from "react"; import { mergeRefs } from "react-merge-refs"; import { MenuItem as BaseMenuItem } from "reakit/Menu"; import styled, { css } from "styled-components"; import breakpoint from "styled-components-breakpoint"; import MenuIconWrapper from "./MenuIconWrapper"; type Props = { id?: string; onClick?: (event: React.SyntheticEvent) => void | Promise; active?: boolean; selected?: boolean; disabled?: boolean; dangerous?: boolean; to?: LocationDescriptor; href?: string; target?: "_blank"; as?: string | React.ComponentType; hide?: () => void; level?: number; icon?: React.ReactElement; children?: React.ReactNode; ref?: React.LegacyRef | undefined; }; const MenuItem = ( { onClick, children, active, selected, disabled, as, hide, icon, ...rest }: Props, ref: React.Ref ) => { const content = React.useCallback( (props) => { const handleClick = async (ev: React.MouseEvent) => { hide?.(); if (onClick) { ev.preventDefault(); await onClick(ev); } }; // Preventing default mousedown otherwise menu items do not work in Firefox, // which triggers the hideOnClickOutside handler first via mousedown – hiding // and un-rendering the menu contents. const handleMouseDown = (ev: React.MouseEvent) => { ev.preventDefault(); ev.stopPropagation(); }; return ( , ])} > {selected !== undefined && ( {selected ? : } )} {icon && {icon}} {children} ); }, [active, as, hide, icon, onClick, ref, children, selected] ); return ( {content} ); }; const Spacer = styled.svg` width: 24px; height: 24px; flex-shrink: 0; `; const Title = styled.div` ${ellipsis()} flex-grow: 1; display: flex; `; type MenuAnchorProps = { level?: number; disabled?: boolean; dangerous?: boolean; disclosure?: boolean; $active?: boolean; }; export const MenuAnchorCSS = css` display: flex; margin: 0; border: 0; padding: 12px; border-radius: 4px; padding-left: ${(props) => 12 + (props.level || 0) * 10}px; width: 100%; min-height: 32px; background: none; color: ${(props) => props.disabled ? props.theme.textTertiary : props.theme.textSecondary}; justify-content: left; align-items: center; font-size: 16px; cursor: default; user-select: none; white-space: nowrap; position: relative; svg { flex-shrink: 0; opacity: ${(props) => (props.disabled ? ".5" : 1)}; } ${(props) => props.disabled && "pointer-events: none;"} ${(props) => props.$active === undefined && !props.disabled && ` @media (hover: hover) { &:hover, &:focus, &.focus-visible { color: ${props.theme.accentText}; background: ${props.dangerous ? props.theme.danger : props.theme.accent}; box-shadow: none; cursor: var(--pointer); svg { color: ${props.theme.accentText}; fill: ${props.theme.accentText}; } } } `} ${(props) => props.$active && !props.disabled && ` color: ${props.theme.accentText}; background: ${props.dangerous ? props.theme.danger : props.theme.accent}; box-shadow: none; cursor: var(--pointer); svg { fill: ${props.theme.accentText}; } `} ${breakpoint("tablet")` padding: 4px 12px; padding-right: ${(props: MenuAnchorProps) => props.disclosure ? 32 : 12}px; font-size: 14px; `} `; export const MenuAnchor = styled.a` ${MenuAnchorCSS} `; export default React.forwardRef(MenuItem);