import { ReactNode, memo, useCallback, useMemo } from 'react'; import { rgba } from 'polished'; import { Item, Root, Content, TriggerItem } from '@radix-ui/react-dropdown-menu'; import { ChevronRight } from '@air/icons'; import { useTheme } from 'styled-components'; import { Box, BoxProps } from '../../Box'; import { Text } from '../../Text'; import { MenuItemDescription } from '../../Menus/components/MenuItemDescription'; import { MenuItemLabel } from '../../Menus/components/MenuItemLabel'; import { MenuSize } from '../../Menus/components/Menu'; import { MenuVariantName } from '../../theme/variants/menus'; import { TXProp } from '../../theme'; import { RadixMenuItemDivider } from './RadixMenuItemDivider'; export type RadixMenuItemRenderProps = | { children: ReactNode } | { label: ReactNode; description?: ReactNode } | { title: string } | { divider: boolean }; export type RadixMenuItemProps = Pick & { /** * Renders `` below the menu item. */ hasDividerBottom?: boolean; /** * Renders `` above the menu item. */ hasDividerTop?: boolean; /** * Displays an element on the left of `children` or `label. */ leftAdornment?: ReactNode; /** * Displays an element on the right of `children` or `label. */ rightAdornment?: ReactNode; /** * The `shortcut` prop will append the keys used to trigger the shortcut. */ shortcut?: string[]; /** * The `size` prop determines the height of the menu item and the spacing of the adornments. */ size?: MenuSize; /** * Event handler called when the user selects an item (via mouse of keyboard). * Calling event.preventDefault in this handler will prevent the dropdown menu from closing when selecting that item. */ onClick?: (event: Event) => void; onSelect?: () => void; /** * Prevents item selection. */ disabled?: boolean; /** * Defaults to value of `id` */ ['data-testid']?: string; variant?: MenuVariantName; subOptions?: (RadixMenuItemProps & RadixMenuItemRenderProps & { id?: string })[]; subOptionsTx?: TXProp; } & RadixMenuItemRenderProps; export const RadixMenuItem = memo( ({ hasDividerBottom, hasDividerTop, leftAdornment, rightAdornment, shortcut, size = 'small', onClick, onSelect, tx, disabled, subOptions, variant, id, 'data-testid': testId, subOptionsTx, ...renderProps }: RadixMenuItemProps) => { const hasDescription = 'description' in renderProps; const isSmallSize = size === 'small'; const numberOfShortcutKeys = shortcut?.length ?? 0; const theme = useTheme(); const menuItemStyle = useMemo( () => ({ mb: hasDividerBottom ? 0 : 8, '&:last-child': { mb: 0, }, ['.radix-menu-item']: { display: 'flex', alignItems: hasDescription ? 'flex-start' : 'center', justifyContent: 'space-between', backgroundColor: 'transparent', height: hasDescription ? 'auto' : isSmallSize ? 32 : 36, px: 6, py: hasDescription ? 6 : 0, border: 0, borderRadius: 4, color: variant === 'dark' ? 'pigeon100' : 'pigeon700', textAlign: 'left', cursor: 'pointer', '&[data-selected], &:active': { backgroundColor: variant === 'dark' ? 'pigeon800' : 'pigeon050', color: variant === 'dark' ? 'pigeon100' : 'pigeon700', }, '&:hover': { backgroundColor: variant === 'dark' ? 'pigeon800' : 'pigeon050', color: variant === 'dark' ? 'white' : undefined, }, '&:focus': { outline: 'none', backgroundColor: variant === 'dark' ? 'pigeon700' : 'pigeon050', }, ...tx, }, }), [hasDescription, hasDividerBottom, isSmallSize, tx, variant], ); const renderChildren = useCallback(() => { if ('children' in renderProps) { return renderProps.children; } if ('label' in renderProps) { return ( {renderProps.label} {renderProps.description} ); } return null; }, [isSmallSize, renderProps, variant]); const menuItemContent = useMemo( () => ( <> {leftAdornment && ( {leftAdornment} )} {renderChildren()} {rightAdornment || (!!subOptions && subOptions.length && ( {rightAdornment ? rightAdornment : } ))} {shortcut && ( {shortcut.map((key, index) => { const isLastKey = numberOfShortcutKeys - 1 === index; return ( <> {key} {!isLastKey && (  +  )} ); })} )} ), [ subOptions, hasDescription, isSmallSize, leftAdornment, numberOfShortcutKeys, renderChildren, rightAdornment, shortcut, ], ); if ('title' in renderProps) { return ( {renderProps.title} ); } if ('divider' in renderProps) return ; if (!!subOptions && subOptions.length) { return ( {hasDividerTop && } {menuItemContent} {hasDividerBottom && } {subOptions.map((option, index) => ( event.stopPropagation()} key={index} size={size} variant={variant} {...option} /> ))} ); } return ( {hasDividerTop && } {menuItemContent} {hasDividerBottom && } ); }, ); RadixMenuItem.displayName = 'RadixMenuItem';