import { forwardRef, useRef, useState, useEffect, useCallback } from 'react'
import * as RadixMenu from '@radix-ui/react-dropdown-menu'
import Block from '../../Primitives/Block/Block'
import PrimitiveText from '../../Primitives/PrimitiveText/PrimitiveText'
import { Tooltip, TooltipSide } from '../../Tooltip'
import { Checkbox } from '../../Checkbox'
import { Check } from 'lucide-react'
import { type SelectItemProps, SelectItemType } from './types'
import { checkIfTruncated, isItemSelected, getRightSlotConfig } from './utils'
import { useResponsiveTokens } from '../../../hooks/useResponsiveTokens'
import type { MultiSelectTokensType } from '../../MultiSelect/multiSelect.tokens'
import type { SingleSelectTokensType } from '../../SingleSelect/singleSelect.tokens'
const MenuItemSlot = ({ slot }: { slot: React.ReactNode }) => {
return (
{slot}
)
}
const SelectItem = forwardRef(
(
{
item,
onSelect,
selected,
type,
showCheckmark = true,
className,
selectedPosition = 'none',
index = 0,
focusIdentityValue,
},
ref
) => {
const textRef = useRef(null)
const subLabelRef = useRef(null)
const [showTooltip, setShowTooltip] = useState(false)
const [showSubLabelTooltip, setShowSubLabelTooltip] = useState(false)
const multiSelectTokens =
useResponsiveTokens('MULTI_SELECT')
const singleSelectTokens =
useResponsiveTokens('SINGLE_SELECT')
const tokens: MultiSelectTokensType | SingleSelectTokensType =
type === SelectItemType.MULTI
? multiSelectTokens
: singleSelectTokens
const isSelected = isItemSelected(item.value, selected, type)
const resizeObserverRef = useRef(null)
const rafRef = useRef(null)
const checkTruncation = useCallback(() => {
if (rafRef.current !== null) {
cancelAnimationFrame(rafRef.current)
}
resizeObserverRef.current?.disconnect()
rafRef.current = requestAnimationFrame(() => {
let nextShowTooltip = false
let nextShowSubLabelTooltip = false
if (textRef.current) {
nextShowTooltip = checkIfTruncated(textRef.current)
}
if (item.subLabel && subLabelRef.current) {
nextShowSubLabelTooltip = checkIfTruncated(
subLabelRef.current
)
}
setShowTooltip((prev) =>
prev !== nextShowTooltip ? nextShowTooltip : prev
)
setShowSubLabelTooltip((prev) =>
prev !== nextShowSubLabelTooltip
? nextShowSubLabelTooltip
: prev
)
requestAnimationFrame(() => {
if (!resizeObserverRef.current) return
if (textRef.current) {
resizeObserverRef.current.observe(textRef.current)
}
if (subLabelRef.current) {
resizeObserverRef.current.observe(subLabelRef.current)
}
})
rafRef.current = null
})
}, [item.subLabel])
useEffect(() => {
if (item.disableTruncation) return
resizeObserverRef.current = new ResizeObserver(() => {
checkTruncation()
})
checkTruncation()
return () => {
resizeObserverRef.current?.disconnect()
resizeObserverRef.current = null
if (rafRef.current !== null) {
cancelAnimationFrame(rafRef.current)
}
}
}, [item.label, item.subLabel, item.disableTruncation, checkTruncation])
const handleSelect = (e: Event) => {
if (item.disabled) {
e.preventDefault()
return
}
if (type === SelectItemType.MULTI) {
e.preventDefault()
}
onSelect(item.value)
}
const shouldShowAutoTooltip =
(showTooltip && item.label) ||
(showSubLabelTooltip && item.subLabel)
const customTooltip = item.tooltip
const hasTooltip = shouldShowAutoTooltip || customTooltip
const tooltipContent = customTooltip || (
<>
{showTooltip && item.label && {item.label}}
{showSubLabelTooltip && item.subLabel && (
{item.subLabel}
)}
>
)
const rightSlotConfig = getRightSlotConfig(isSelected, type, item)
const rightSlotContent = rightSlotConfig ? (
rightSlotConfig.type === 'checkbox' ? (
) : (
)
) : null
const getBorderRadius = () => {
const defaultRadius = tokens?.menu?.item?.borderRadius
if (!isSelected || selectedPosition === 'none') {
return defaultRadius
}
switch (selectedPosition) {
case 'first':
return `${defaultRadius} ${defaultRadius} 0 0`
case 'middle':
return '0'
case 'last':
return `0 0 ${defaultRadius} ${defaultRadius}`
case 'only':
return defaultRadius
default:
return defaultRadius
}
}
const itemContent = (
{item.slot1 && }
{item.label}
{item.slot2 && }
{item.slot3 && }
{item.slot4 && }
{showCheckmark && rightSlotContent && (
{rightSlotContent}
)}
{item.subLabel && (
{item.subLabel}
)}
)
if (hasTooltip) {
return (
{itemContent}
)
}
return itemContent
}
)
SelectItem.displayName = 'SelectItem'
export default SelectItem
export { SelectItemType } from './types'
export type { SelectItemProps, BaseSelectItemType } from './types'