import { isValidElement, useCallback, useId, useMemo, useState } from 'react' import type { AriaAttributes } from 'react' import InputFooter from '../Inputs/utils/InputFooter/InputFooter' import InputLabels from '../Inputs/utils/InputLabels/InputLabels' import Block from '../Primitives/Block/Block' import { SingleSelectV2Size, SingleSelectV2Variant, type SingleSelectV2Props, } from './singleSelectV2.types' import SingleSelectV2Menu from './SingleSelectV2Menu' import SingleSelectV2Trigger from './SingleSelectV2Trigger' import type { SingleSelectV2TokensType } from './singleSelectV2.tokens' import { useResponsiveTokens } from '../../hooks/useResponsiveTokens' import { useBreakpoints } from '../../hooks/useBreakPoints' import { BREAKPOINTS } from '../../breakpoints/breakPoints' import MobileSingleSelectV2 from './MobileSingleSelectV2' import { getSingleSelectV2BorderRadius, getSingleSelectV2ValueLabelMap, setupAccessibility, } from './utils' import { useDropdownInteractionLock } from '../../hooks' const SingleSelectV2 = ({ label, subLabel, hintText, required, helpIconText, placeholder, error = {}, size = SingleSelectV2Size.MD, items = [], variant = SingleSelectV2Variant.CONTAINER, open: controlledOpen, onOpenChange: onControlledOpenChange, selected, onSelect, search, slot, customTrigger, usePanelOnMobile = true, menuPosition, menuDimensions, triggerDimensions = { width: 'auto', minWidth: 'auto', maxWidth: 'auto', }, inline = false, enableVirtualization, virtualListItemHeight, virtualListOverscan, onEndReached, endReachedThreshold, hasMore, loadingComponent, skeleton = { count: 3, show: false, variant: 'pulse', }, allowCustomValue = false, customValueLabel = 'Specify', singleSelectGroupPosition, menuFooter, ...rest }: SingleSelectV2Props) => { const { disabled, name, ...buttonRest } = rest as { disabled?: boolean name?: string [key: string]: unknown } const breakpoints = useBreakpoints(BREAKPOINTS) const isSmallScreen = breakpoints.breakPointLabel === 'sm' const isContainer = variant === SingleSelectV2Variant.CONTAINER const singleSelectTokens = useResponsiveTokens('SINGLE_SELECT_V2') if (customTrigger !== undefined && !isValidElement(customTrigger)) { throw new Error( 'SingleSelectV2: customTrigger must be a valid React element.' ) } const [internalOpen, setInternalOpen] = useState(false) const open = controlledOpen !== undefined ? Boolean(controlledOpen) : internalOpen const handleOpenChange = useCallback( (nextOpen: boolean) => { if (controlledOpen === undefined) setInternalOpen(nextOpen) onControlledOpenChange?.(nextOpen) }, [controlledOpen, onControlledOpenChange] ) const valueLabelMap = useMemo( () => getSingleSelectV2ValueLabelMap(items), [items] ) const safeItems = items ?? [] const isItemSelected = Boolean(selected) const isSmallScreenWithLargeSize = isSmallScreen && size === SingleSelectV2Size.LG const generatedId = useId() const { uniqueName, hintTextId, errorMessageId, menuId, ariaAttributes } = setupAccessibility({ name, generatedId, label, hintText, error: error.show, errorMessage: error.message, rest: buttonRest, prefix: 'singleselectv2', needsMenuId: true, }) const triggerAriaAttributes: Pick< AriaAttributes, 'aria-describedby' | 'aria-labelledby' | 'aria-label' | 'aria-invalid' > = { 'aria-describedby': ariaAttributes['aria-describedby'] as | string | undefined, 'aria-labelledby': ariaAttributes['aria-labelledby'] as | string | undefined, 'aria-label': ariaAttributes['aria-label'] as string | undefined, 'aria-invalid': ariaAttributes['aria-invalid'] as boolean | undefined, } const borderConfig = getSingleSelectV2BorderRadius( size, variant, singleSelectGroupPosition, singleSelectTokens ) const handleSelect = useCallback( (value: string) => { onSelect(value) handleOpenChange(false) }, [onSelect, handleOpenChange] ) const shouldEnableVirtualization = enableVirtualization ?? safeItems.length > 20 useDropdownInteractionLock(!isSmallScreen && open) if (isSmallScreen && usePanelOnMobile) { return ( ) } return ( {isContainer && (!isSmallScreen || size !== SingleSelectV2Size.LG) && ( )} ) } /> {isContainer && ( )} ) } SingleSelectV2.displayName = 'SingleSelectV2' export default SingleSelectV2