import React, { useContext, useMemo } from 'react'; import isUndefined from 'lodash/isUndefined'; import { css, cx } from '@leafygreen-ui/emotion'; import { useAvailableSpace, useForwardedRef } from '@leafygreen-ui/hooks'; import Icon from '@leafygreen-ui/icon'; import { palette } from '@leafygreen-ui/palette'; import Popover from '@leafygreen-ui/popover'; import { ComboboxProps } from '../Combobox.types'; import { ComboboxContext } from '../ComboboxContext'; import { loadingIconStyle, menuBaseStyle, menuList, menuMessageBaseStyle, menuMessageSizeStyle, menuMessageThemeStyle, menuThemeStyle, popoverStyle, popoverThemeStyle, } from './Menu.styles'; type ComboboxMenuProps = { children?: React.ReactNode; refEl: React.RefObject; id: string; labelId: string; } & Pick< ComboboxProps, | 'searchLoadingMessage' | 'searchErrorMessage' | 'searchEmptyMessage' | 'usePortal' | 'portalClassName' | 'portalContainer' | 'scrollContainer' | 'popoverZIndex' | 'className' >; export const ComboboxMenu = React.forwardRef( ( { children, id, refEl, labelId, searchLoadingMessage, searchErrorMessage, searchEmptyMessage, className, ...popoverProps }: ComboboxMenuProps, forwardedRef ) => { const { disabled, darkMode, theme, size, isOpen, searchState } = useContext(ComboboxContext); const ref = useForwardedRef(forwardedRef, null); /** The max height of the menu element */ const availableSpace = useAvailableSpace(refEl); const maxHeightValue = !isUndefined(availableSpace) ? `${Math.min(availableSpace, 256)}px` : 'unset'; /** * The rendered menu JSX contents * Includes error, empty, search and default states */ const renderedMenuContents = useMemo((): JSX.Element => { const messageStyles = cx( menuMessageBaseStyle, menuMessageThemeStyle[theme], menuMessageSizeStyle[size] ); switch (searchState) { case 'loading': { return ( {searchLoadingMessage} ); } case 'error': { return ( {searchErrorMessage} ); } case 'unset': default: { if ( children && typeof children === 'object' && 'length' in children && children.length > 0 ) { return
    {children}
; } return {searchEmptyMessage}; } } }, [ theme, size, searchState, darkMode, searchLoadingMessage, searchErrorMessage, children, searchEmptyMessage, ]); return (
e.preventDefault()} > {renderedMenuContents}
); } ); ComboboxMenu.displayName = 'ComboboxMenu';