import { forwardRef, isValidElement } from 'react' import * as RadixMenu from '@radix-ui/react-dropdown-menu' import { Check } from 'lucide-react' import Block from '../Primitives/Block/Block' import PrimitiveText from '../Primitives/PrimitiveText/PrimitiveText' import { Tooltip } from '../Tooltip' import type { MenuV2ItemType, MenuV2SelectionMode, MenuV2SelectionStyle, } from './menuV2.types' import { getMenuItemBackgroundColor, getMenuItemOptionColor, getMenuItemDescriptionColor, getItemSlots, } from './menuV2.utils' import type { MenuV2TokensType } from './menuV2.tokens' import { addPxToValue } from '../../global-utils/GlobalUtils' import { useMenuV2Selection } from './MenuV2SelectionContext' import { resolveMenuSelection } from '../Menu/selection' type MenuV2ItemProps = { item: MenuV2ItemType index: number itemTokens: MenuV2TokensType['group']['item'] /** Group-level override for selection style. */ selectionStyle?: MenuV2SelectionStyle /** Group-level override for selection cardinality. */ selectionMode?: MenuV2SelectionMode } const SlotWrapper = ({ slot, itemTokens, decorative = true, }: { slot: React.ReactNode decorative?: boolean itemTokens: MenuV2TokensType['group']['item'] }) => { const content = decorative && isValidElement(slot) ? ( slot ) : decorative ? ( ) : ( slot ) return ( {content} ) } const CheckmarkIndicator = ({ itemTokens, disabled, }: { itemTokens: MenuV2TokensType['group']['item'] disabled?: boolean }) => { const size = typeof itemTokens.text.leftSlot.maxWidth === 'number' ? itemTokens.text.leftSlot.maxWidth : 16 const checkmark = itemTokens.text.checkmark const position = checkmark?.position ?? 'trailing' const color = checkmark?.color const width = checkmark?.width ?? size return ( ) } const MenuV2Item = forwardRef( ( { item, index, itemTokens, selectionStyle: groupSelectionStyle, selectionMode: groupSelectionMode, }, ref ) => { const { selectionStyle: menuSelectionStyle, selectionMode: menuSelectionMode, closeOnSelect, } = useMenuV2Selection() const { isSelectable, isSelected, selectionStyle: effectiveSelectionStyle, selectionMode: effectiveSelectionMode, selectionRole, } = resolveMenuSelection({ selected: item.selected, groupSelectionStyle, groupSelectionMode, menuSelectionStyle, menuSelectionMode, }) const useHighlight = effectiveSelectionStyle === 'highlight' && isSelected const showCheckmark = effectiveSelectionStyle === 'checkmark' && isSelected const checkmarkPosition = itemTokens.text.checkmark?.position ?? 'trailing' const showLeadingCheck = showCheckmark && checkmarkPosition === 'leading' const showTrailingCheck = showCheckmark && checkmarkPosition === 'trailing' const [slot] = getItemSlots(item) const itemStyle = { paddingTop: itemTokens.paddingTop, paddingRight: itemTokens.paddingRight, paddingBottom: itemTokens.paddingBottom, paddingLeft: itemTokens.paddingLeft, marginTop: itemTokens.marginTop, marginRight: itemTokens.marginRight, marginBottom: itemTokens.marginBottom, marginLeft: itemTokens.marginLeft, border: 'none', outline: 'none', } const bgDefault = getMenuItemBackgroundColor( useHighlight ? 'selected' : 'default', itemTokens, item ) const bgHover = getMenuItemBackgroundColor('hover', itemTokens, item) const bgFocus = getMenuItemBackgroundColor('focus', itemTokens, item) const bgActive = getMenuItemBackgroundColor('active', itemTokens, item) const bgFocusVisible = getMenuItemBackgroundColor( 'focusVisible', itemTokens, item ) const colorDefault = getMenuItemOptionColor( useHighlight ? 'selected' : 'default', itemTokens, item ) const descColor = getMenuItemDescriptionColor( useHighlight ? 'selected' : 'default', itemTokens, item ) const handleSelect = (event: Event) => { if (item.disabled) return if (!closeOnSelect) { event.preventDefault() } item.onClick?.() } const content = ( {showLeadingCheck && ( )} {slot != null && ( )} {item.label.text} {showTrailingCheck && ( )} {item.subLabel && ( {item.subLabel} )} ) if (item.tooltip) { return ( {content} ) } return content } ) MenuV2Item.displayName = 'MenuV2Item' export default MenuV2Item