import React, {
type HTMLProps,
type ReactNode,
useEffect,
useRef,
useState,
} from 'react';
import type { GetPropsCommonOptions, GetMenuPropsOptions } from 'downshift';
import { DropdownMenuContentList } from './DropdownMenuContentList';
import { classNames, getStyleFromPlacement, type Placement } from '../../utils';
import usePrevious from '../../hooks/usePrevious';
import { useFormFieldContext } from '../FormField/FormFieldContext';
import styles from './DropdownMenuContent.module.css';
import commonStyles from '../../theme/common.module.css';
type OptionGroup = { key: string; label: string; options: T[] };
type Option = { key: string; label: string };
type Overwrite = Pick> & U;
export type Props = {
className?: string;
isOpen?: boolean;
isLoading?: boolean;
placement?: Placement;
maxHeight?: string;
options: (T | OptionGroup)[];
renderSearchBar?: () => ReactNode;
getItemProps(options: { item: T; index: number }): HTMLProps;
getMenuProps(
options?: GetMenuPropsOptions,
otherOptions?: GetPropsCommonOptions,
// eslint-disable-next-line @typescript-eslint/no-explicit-any
): Overwrite, { ref?: any }>;
renderOption(option: T, index: number): ReactNode; // should always return a DropdownItem component
renderOptionGroup?(optionGroup: OptionGroup): ReactNode;
renderNoOptions?(): ReactNode;
renderLoadingOptions?(): ReactNode;
};
export const DropdownMenuContent = ({
className,
isOpen = true,
isLoading = false,
maxHeight,
options,
placement = 'bottom-start',
getItemProps,
getMenuProps,
renderOption,
renderOptionGroup,
renderNoOptions,
renderLoadingOptions,
renderSearchBar,
}: Props) => {
const [visible, setVisible] = useState(isOpen);
const refTimeout = useRef>(undefined);
const previousOpenState = usePrevious(isOpen);
const context = useFormFieldContext();
useEffect(() => {
if (isOpen) {
clearTimeout(refTimeout.current);
setVisible(isOpen);
} else if (previousOpenState) {
refTimeout.current = setTimeout(() => {
if (!isOpen) {
setVisible(false);
}
}, 200);
}
}, [isOpen, previousOpenState]);
useEffect(() => {
return () => clearTimeout(refTimeout.current);
}, []);
return (
{
if (!isOpen) {
setVisible(false);
}
}}
>
{visible ? (
<>
{renderSearchBar && renderSearchBar()}
>
) : null}
);
};