import { useSelect , UseSelectState } from 'downshift' ; import React , { cloneElement , isValidElement , memo , useCallback , useMemo , useRef } from 'react' ; import { usePopper } from 'react-popper' ; import { useUniqueId } from '../../hooks' ; import { Box } from '../Box' ; import { List } from '../List' ; import { StyledBox } from './styled' ; import { DropdownItem , DropdownItemGroup , DropdownLinkItem , DropdownProps } from './types' ; export const Dropdown = memo ( ( { autoWidth = false , className , disabled = false , maxHeight , id , items , placement = 'bottom-start' as const , positionFixed = false , toggle , style , ... props } ) => { const dropdownUniqueId = useUniqueId ( 'dropdown' ) ; const flattenItems = useCallback ( ( items ) => { const isGroups = ( items ) : items is Array < DropdownItemGroup > => items . every ( ( items ) => 'items' in items && ! ( 'content' in items ) ) ; return isGroups ( items ) ? items . map ( ( group ) => group . items ) . reduce ( ( acum , curr ) => acum . concat ( curr ) , [ ] ) : items ; } , [ ] ) ; const flattenedItems = useMemo ( ( ) => flattenItems ( items ) , [ flattenItems , items ] ) ; const handleOnSelectedItemChange = useCallback ( ( { selectedItem } ) => { if ( selectedItem && selectedItem . type !== 'link' && typeof selectedItem . onItemClick === 'function' ) { selectedItem . onItemClick ( selectedItem ) ; } } , [ ] ) ; const { getItemProps , getMenuProps , getToggleButtonProps , highlightedIndex , isOpen } = useSelect ( { circularNavigation : true , defaultHighlightedIndex : 0 , id : dropdownUniqueId , itemToString : ( item ) => ( item ? item . content : '' ) , items : flattenedItems , menuId : id , onSelectedItemChange : handleOnSelectedItemChange , selectedItem : null , toggleButtonId : toggle . props . id } ) ; const referenceRef = useRef ( null ) ; const popperRef = useRef ( null ) ; const { attributes , styles , update } = usePopper ( referenceRef . current , popperRef . current , { modifiers : [ { name : 'eventListeners' , options : { scroll : isOpen , resize : isOpen } } , { name : 'offset' , options : { offset : [ 0 , 4 ] } } , ] , placement , strategy : positionFixed ? 'fixed' : 'absolute' } ) ; const renderToggle = useMemo ( ( ) => { return ( isValidElement ( toggle ) && cloneElement ( toggle , { ... getToggleButtonProps ( { 'aria-expanded' : isOpen , disabled , ref : referenceRef } ) } ) ) ; } , [ disabled , getToggleButtonProps , isOpen , toggle ] ) ; return ( < StyledBox > { renderToggle } < Box ref = { popperRef } style = { styles . popper } { ... attributes . poppper } zIndex = "popover" > < List { ... props } autoWidth = { autoWidth } getItemProps = { getItemProps } getMenuProps = { getMenuProps } highlightedIndex = { highlightedIndex } isDropdown = { true } isOpen = { isOpen } items = { items } maxHeight = { maxHeight } update = { update } / > < /Box> < /StyledBox>); } ) ;