60 lines
2.1 KiB
TypeScript
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>
|
|
</>
|
|
)
|
|
}
|