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}
) : (
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