Files
sk-react-toolkit/web/SwitcherMenu.tsx
T

60 lines
2.1 KiB
TypeScript

import ArrowDropDown from '@mui/icons-material/ArrowDropDown'
import { Button, ListItemIcon, ListItemText, Menu, MenuItem, Typography } from '@mui/material'
import { useState, type ReactNode } from 'react'
import { MONOSPACED } from './fonts.ts'
/**
* An item of a SwitcherMenu: its key, the label and icon of the button and the menu, and optionally a second line in
* the Monospaced font, a hint at the right end, such as the key that opens it, and whether it can be chosen.
*/
export type SwitcherItem<K> = {
key: K
label: string
icon: ReactNode
secondary?: string
hint?: string
disabled?: boolean
}
/**
* A button naming the item chosen, current, with its icon, whose menu chooses another with onChoose. title is the
* button's tooltip.
*/
export default function SwitcherMenu<K>(props: { items: SwitcherItem<K>[]; current: SwitcherItem<K>; title?: string; onChoose: (key: K) => void }) {
const { items, current } = props
const [anchor, setAnchor] = useState<HTMLElement | null>(null)
return (
<>
<Button
variant="text"
color="inherit"
startIcon={current.icon}
endIcon={<ArrowDropDown />}
aria-haspopup="menu"
aria-expanded={anchor !== null}
title={props.title}
onClick={(event) => setAnchor(event.currentTarget)}
>
{current.label}
</Button>
<Menu anchorEl={anchor} open={anchor !== null} onClose={() => setAnchor(null)}>
{items.map((item, index) => (
<MenuItem
key={index}
selected={item.key === current.key}
disabled={item.disabled}
onClick={() => {
setAnchor(null)
props.onChoose(item.key)
}}
>
<ListItemIcon>{item.icon}</ListItemIcon>
<ListItemText primary={item.label} secondary={item.secondary} slotProps={{ secondary: { sx: MONOSPACED } }} />
{item.hint !== undefined && <Typography variant="body2" color="text.secondary" sx={{ ml: 3 }}>{item.hint}</Typography>}
</MenuItem>
))}
</Menu>
</>
)
}