import type {
HTMLAttributes,
MouseEventHandler,
ReactElement,
ReactNode,
SyntheticEvent
} from 'react';
import type { SortEndHandler } from 'react-sortable-hoc';
import type { VariableSizeListProps } from 'react-window';
import type { CheckboxProps as MuiCheckboxProps } from '@mui/material/Checkbox';
import type { IconButtonProps as MuiIconButtonProps } from '@mui/material/IconButton';
import type { MenuProps as MuiMenuProps } from '@mui/material/Menu';
import type { MenuItemProps as MuiMenuItemProps } from '@mui/material/MenuItem';
import type { PopperProps } from '@mui/material/Popper';
import type { ButtonProps } from '../button';
import type { CustomIconProps } from '../custom-icon';
import type { TooltipProps } from '../@popovers/tooltip';
import type { CreateClassesProps } from './styles';
import createClasses from './styles';
export interface DropDownMenuProps extends Omit {
/**
* A HTML element, or a function that returns it.
* It's used to set the position of the menu.
* @document
*/
anchorEl?: MuiMenuProps['anchorEl'] | PopperProps['anchorEl'];
/**
* Call back which will be fired on clicking a menu item.
*/
handleClick?: (
name: string | number,
value?: DropdownMenuItem['value']
) => MouseEventHandler;
/**
* The items which will be shown in the list.
*/
listItems: DropdownMenuItem[];
/**
* Changes an existing menu item. This function is used to specify the content, appearance, and behavior of the menu item.
* @param {MenuItemProps} props
* @returns {MenuItemProps}
*/
modifyMenuItem?: (props: MenuItemProps) => Partial;
/**
* Will be placed just before the list.
*/
InsertBeforeList?: () => ReactNode;
/**
* Will be placed right after the list.
*/
InsertAfterList?: () => ReactNode;
/**
* Allow multiple selection. Notice your selection logic should also support multiple selection.
*/
multiple?: boolean;
/**
* Specify top addition to place the menu correctly relative to the anchor component.
*/
anchorElTopAddition?: number;
/**
* The width of the menu.
*/
width?: number;
/**
* Whether or not to show selected icon on single selection.
*/
showSelectedIcon?: boolean;
/**
* Whether or not to show the sort icon for menu items, notice you must pass `onSortEnd` to make it work.
*/
sortable?: boolean;
/**
* Callback which is fired on sort end.
*/
onSortEnd?: SortEndHandler;
/**
* Whether or not to allow searching items inside the menu, notice you must pass `handleSearchChangeCallback` to make it work.
*/
search?: boolean;
/**
* Callback which is fired on search text change.
*/
handleSearchChangeCallback?: (value: string) => void;
/**
* Highlighting emphasizes the search term(s) matches in the results.
* @default false
*/
searchHighlight?: boolean;
/**
* Place holder for the search field.
*/
searchPlaceholder?: string;
/**
* List of fields to search by.
* @default ['name']
*/
searchBy?: Array;
/**
* Whether or not to show the delete icon for menu items, notice you must pass `handleDelete` to make it work.
*/
deletable?: boolean;
/**
* Call back which will be fired on click a delete icon.
*/
handleDelete?: (
name: string | number,
value?: DropdownMenuItem['value']
) => MouseEventHandler;
/**
* If passed, a button will appear in the bottom of the menu, pass `bottomButtonClickHandler` to make it work.
*/
bottomButtonText?: string;
/**
* Call back which will be fired on click the bottom button.
*/
bottomButtonClickHandler?: ButtonProps['onClick'];
/**
* On which side to show the menu arrow.
*/
arrowSide?: CreateClassesProps['arrowSide'];
/**
* Specify left addition to place the menu correctly relative to the anchor component.
*/
leftAddition?: number;
/**
* Defines a string value that labels the DropDownMenu element.
*/
ariaLabel?: HTMLAttributes['aria-label'];
/**
* Text to display when there are no items in the list.
*/
noOptionsText?: ReactNode;
/**
* Text to display when there are no search results.
*/
noResultsText?: ReactNode;
/**
* Text to display when there are items loading.
*/
loadingText?: ReactNode;
/**
* Virtualize large lists with react-window?
*/
variableSizeList?: boolean;
variableSizeListProps?: Omit<
VariableSizeListProps,
'children' | 'itemCount' | 'itemSize' | 'height' | 'width'
> & {
itemSize?: VariableSizeListProps['itemSize'];
height?: VariableSizeListProps['height'];
width?: VariableSizeListProps['width'];
};
/**
* Provide to override classes.
*/
classes?: Partial>;
}
export interface InfinityScrollProps {
fetchFunction: () => void;
allItemsCount: number;
threshold?: number;
}
export interface ListItemProps {
infinityScrollProps?: InfinityScrollProps;
listItems: DropDownMenuProps['listItems'];
modifyMenuItem?: DropDownMenuProps['modifyMenuItem'];
InsertBeforeList?: DropDownMenuProps['InsertBeforeList'];
InsertAfterList?: DropDownMenuProps['InsertAfterList'];
multiple?: DropDownMenuProps['multiple'];
handleClick?: DropDownMenuProps['handleClick'];
styles: ReturnType;
classes?: DropDownMenuProps['classes'];
sortable?: DropDownMenuProps['sortable'];
deletable?: DropDownMenuProps['deletable'];
handleDelete?: DropDownMenuProps['handleDelete'];
showSelectedIcon?: DropDownMenuProps['showSelectedIcon'];
ariaLabel?: DropDownMenuProps['ariaLabel'];
noOptionsText?: DropDownMenuProps['noOptionsText'];
noResultsText?: DropDownMenuProps['noResultsText'];
loadingText?: DropDownMenuProps['loadingText'];
variableSizeList?: DropDownMenuProps['variableSizeList'];
variableSizeListProps?: DropDownMenuProps['variableSizeListProps'];
}
export interface MenuContentProps {
infinityScrollProps?: InfinityScrollProps;
search?: DropDownMenuProps['search'];
handleTextChange?: (
value: string | SyntheticEvent
) => void;
/**
* Number of milliseconds for which the calls to handleTextChange is to be delayed.
*/
searchDebounceTime?: number;
searchHighlight?: DropDownMenuProps['searchHighlight'];
searchPlaceholder?: DropDownMenuProps['searchPlaceholder'];
searchBy?: DropDownMenuProps['searchBy'];
styles?: ReturnType;
classes?: DropDownMenuProps['classes'];
sortable?: DropDownMenuProps['sortable'];
handleClick?: DropDownMenuProps['handleClick'];
listItems: DropDownMenuProps['listItems'];
modifyMenuItem?: DropDownMenuProps['modifyMenuItem'];
InsertBeforeList?: DropDownMenuProps['InsertBeforeList'];
InsertAfterList?: DropDownMenuProps['InsertAfterList'];
multiple?: DropDownMenuProps['multiple'];
deletable?: DropDownMenuProps['deletable'];
handleDelete?: DropDownMenuProps['handleDelete'];
onSortEnd?: DropDownMenuProps['onSortEnd'];
showSelectedIcon?: DropDownMenuProps['showSelectedIcon'];
bottomButtonText?: DropDownMenuProps['bottomButtonText'];
bottomButtonClickHandler?: DropDownMenuProps['bottomButtonClickHandler'];
bottomButtonProps?: ButtonProps;
showSort?: boolean;
ariaLabel?: DropDownMenuProps['ariaLabel'];
noOptionsText?: DropDownMenuProps['noOptionsText'];
noResultsText?: DropDownMenuProps['noResultsText'];
loadingText?: DropDownMenuProps['loadingText'];
/**
* Used only when `search` in menuContentProps is enabled.
*/
defaultListItems?: DropDownMenuProps['listItems'];
clearSelectItems?: () => void;
variableSizeList?: DropDownMenuProps['variableSizeList'];
variableSizeListProps?: DropDownMenuProps['variableSizeListProps'];
/**
* Displays fixed content at the top of the menu.
*/
menuListHeader?: ReactNode;
/**
* Displays fixed content at the bottom of the menu.
*/
menuListFooter?: ReactNode;
/**
* If enabled, the menuListLoader is displayed.
*/
loading?: boolean;
/**
* Custom loader content.
* @default 'Loading...'
*/
menuListLoader?: ReactNode;
}
export interface SortableProps {
children: ReactElement;
}
/**
* Supported props for the "action icon" of the menu item.
*/
export interface MenuItemActionIconProps extends Omit {
'data-testid'?: string;
iconSrc: string;
customIconProps?: CustomIconProps;
handleClick?: (
name: MenuItemProps['name'],
value: MenuItemProps['value']
) => MouseEventHandler;
tooltipText?: TooltipProps['title'];
}
export interface MenuItemProps extends Omit {
handleClick?: DropDownMenuProps['handleClick'];
multiple?: DropDownMenuProps['multiple'];
styles?: ReturnType;
classes?: DropDownMenuProps['classes'];
sortable?: DropDownMenuProps['sortable'];
deletable?: DropDownMenuProps['deletable'];
handleDelete?: DropDownMenuProps['handleDelete'];
index?: number;
showSelectedIcon?: DropDownMenuProps['showSelectedIcon'];
/**
* Allows to render a grouping of options (HTML nested list).
* @link https://developer.mozilla.org/en-US/docs/Web/HTML/Element/ul#nesting_a_list
*/
nestedListItems?: ReactNode;
autoFocus?: MuiMenuItemProps['autoFocus'];
actionIcons?: MenuItemActionIconProps[];
modifyMenuItem?: DropDownMenuProps['modifyMenuItem'];
style?: MuiMenuItemProps['style'];
sx?: MuiMenuItemProps['sx'];
}
type Key = string | number;
export interface DropdownMenuItem {
/**
* The unique identifier to be used as the key.
*/
id?: Key | null;
/**
* Text that will be displayed in case `textNode` is not supplied.
* Also this name will be passed to the click handler.
*/
name: string | number;
/**
* Used to display instead of `name` to support partial text styling.
*/
textNode?: ReactNode;
/**
* If not passed, name should be used as value. If passed, this would be sent as the value/id.
*/
value?: string | ReadonlyArray | number;
/**
* Will render selected menu item.
*/
selected?: boolean;
/**
* Will render disabled menu item.
*/
disabled?: boolean;
/**
* Will render hidden menu item.
*/
hidden?: boolean;
/**
* If provider then the item will rendered with a checkbox.
*/
checkboxProps?: MuiCheckboxProps;
/**
* Creates a nested grouping of options, where `name` is used as a group label.
*/
options?: DropdownMenuItem[];
/**
* Identifies the element (or elements) that labels the MenuItem element.
*/
ariaLabelledby?: HTMLAttributes['aria-labelledby'];
style?: MuiMenuProps['style'];
/**
* The autocomplete input (to pass inside the rendered list item)
*/
searchQuery?: string;
indeterminate?: MuiCheckboxProps['indeterminate'];
/**
* An array containing the "action icons" of the menu item.
* @default []
*/
actionIcons?: MenuItemActionIconProps[];
}