You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
103 lines
2.4 KiB
103 lines
2.4 KiB
import { MoreVert as MoreVertIcon } from '@mui/icons-material'; |
|
import { Box } from '@mui/material'; |
|
import { FC, MouseEventHandler, useCallback, useMemo, useState } from 'react'; |
|
|
|
import ContainedButton from './ContainedButton'; |
|
import IconButton from './IconButton/IconButton'; |
|
import Menu from './Menu'; |
|
|
|
const ButtonWithMenu: FC<ButtonWithMenuProps> = (props) => { |
|
const { |
|
children, |
|
containedButtonProps, |
|
iconButtonProps, |
|
muiMenuProps, |
|
onButtonClick, |
|
onItemClick, |
|
variant = 'icon', |
|
...menuProps |
|
} = props; |
|
|
|
const [anchorEl, setAnchorEl] = useState<HTMLElement | null>(null); |
|
|
|
const open = useMemo(() => Boolean(anchorEl), [anchorEl]); |
|
|
|
const buttonContent = useMemo(() => { |
|
if (children) { |
|
return children; |
|
} |
|
|
|
if (variant === 'icon') { |
|
return <MoreVertIcon fontSize={iconButtonProps?.size} />; |
|
} |
|
|
|
return 'Options'; |
|
}, [children, iconButtonProps?.size, variant]); |
|
|
|
const buttonClickHandler = useCallback<MouseEventHandler<HTMLButtonElement>>( |
|
(...args) => { |
|
const { |
|
0: { currentTarget }, |
|
} = args; |
|
|
|
setAnchorEl(currentTarget); |
|
|
|
return onButtonClick?.call(null, ...args); |
|
}, |
|
[onButtonClick], |
|
); |
|
|
|
const buttonElement = useMemo(() => { |
|
if (variant === 'contained') { |
|
return ( |
|
<ContainedButton onClick={buttonClickHandler} {...containedButtonProps}> |
|
{buttonContent} |
|
</ContainedButton> |
|
); |
|
} |
|
|
|
return ( |
|
<IconButton onClick={buttonClickHandler} {...iconButtonProps}> |
|
{buttonContent} |
|
</IconButton> |
|
); |
|
}, [ |
|
buttonClickHandler, |
|
buttonContent, |
|
containedButtonProps, |
|
iconButtonProps, |
|
variant, |
|
]); |
|
|
|
const itemClickHandler = useCallback< |
|
Exclude<MenuProps['onItemClick'], undefined> |
|
>( |
|
(key, value, ...rest) => { |
|
setAnchorEl(null); |
|
|
|
return onItemClick?.call(null, key, value, ...rest); |
|
}, |
|
[onItemClick], |
|
); |
|
|
|
return ( |
|
<Box> |
|
{buttonElement} |
|
<Menu |
|
muiMenuProps={{ |
|
anchorEl, |
|
keepMounted: true, |
|
onClose: () => setAnchorEl(null), |
|
...muiMenuProps, |
|
}} |
|
onItemClick={itemClickHandler} |
|
open={open} |
|
{...menuProps} |
|
/> |
|
</Box> |
|
); |
|
}; |
|
|
|
export default ButtonWithMenu as <T>( |
|
...args: Parameters<FC<ButtonWithMenuProps<T>>> |
|
) => ReturnType<FC<ButtonWithMenuProps<T>>>;
|
|
|