// This example is mostly a port to react-md from:// https://www.w3.org/TR/wai-aria-practices/examples/menubar/menubar-editor.htmlimporttype{ ReactElement }from"react";import{ useState }from"react";import{ AppBar }from"@react-md/app-bar";import{ Button }from"@react-md/button";import{
Dialog,
DialogContent,
DialogFooter,
DialogHeader,
DialogTitle,}from"@react-md/dialog";import{
Form,
MenuItemCheckbox,
MenuItemRadio,
TextFieldWithMessage,
useNumberField,}from"@react-md/form";import{
AddSVGIcon,
BuildSVGIcon,
RemoveSVGIcon,}from"@react-md/material-icons";import{
DropdownMenu,
MenuBar,
MenuItem,
MenuItemGroup,
MenuItemSeparator,}from"@react-md/menu";import scssVariables from"@react-md/theme/dist/scssVariables";import{ Typography }from"@react-md/typography";importtype{ CalculateFixedPositionOptions }from"@react-md/utils";import Code from"./Code";import styles from"./HoverableMenus.module.scss";import InfiniteDropdownMenu from"./InfiniteDropdownMenu";constFONT_FAMILIES=["Roboto","Sans-serif","Serif","Monospace","Fantasy",]asconst;typeFontFamily=typeofFONT_FAMILIES[number];constCOLORS=[{ label:"Current Color", value:""},{ label:"Blue", value: scssVariables["rmd-blue-500"]},{ label:"Red", value: scssVariables["rmd-red-500"]},{ label:"Green", value: scssVariables["rmd-green-500"]},]asconst;typeColor=typeofCOLORS[number]["value"];constTEXT_DECORATIONS=[{ label:"None", value:"none"},{ label:"Overline", value:"overline"},{ label:"Line-through", value:"line-through"},{ label:"Underline", value:"underline"},]asconst;typeTextDecoration=typeofTEXT_DECORATIONS[number]["value"];constTEXT_ALIGNS=[{ label:"Left", value:"left"},{ label:"Right", value:"right"},{ label:"Center", value:"center"},{ label:"Justify", value:"justify"},]asconst;typeTextAlign=typeofTEXT_ALIGNS[number]["value"];constFONT_SIZES=[{ label:"X-Small", value:"x-small"},{ label:"Small", value:"small"},{ label:"Medium", value:"medium"},{ label:"Large", value:"large"},{ label:"X-Large", value:"x-large"},]asconst;typeFontSize=typeofFONT_SIZES[number]["value"];const fixedPositionOptions: CalculateFixedPositionOptions ={
preventOverlap:true,
disableSwapping:true,};constEXAMPLE_TEXT="Lorem ipsum dolor sit amet, consectetur adipiscing elit. In dictum sodales sem, non molestie nunc mollis at. Morbi sed lobortis lorem. Vivamus nisi turpis, blandit eu dolor a, tincidunt eleifend odio. Integer id dui velit. Nulla nisi eros, porttitor id ligula id, hendrerit maximus mauris. Sed feugiat lacinia euismod. Mauris eros lectus, ultrices et arcu in, finibus ornare neque. Proin rhoncus molestie sagittis. Cras sit amet magna sed erat scelerisque auctor. Mauris iaculis erat non mi mollis, eget feugiat odio lacinia. Aliquam dapibus at velit quis posuere. Phasellus est sem, auctor in mattis ut, rhoncus eu metus. In turpis sem, fermentum a elementum eu, lobortis ut massa. Suspendisse a urna enim.";exportdefaultfunctionDemo(): ReactElement {const[fontFamily, setFontFamily]=useState<FontFamily>(FONT_FAMILIES[0]);const[color, setColor]=useState<Color>(COLORS[0].value);const[bold, setBold]=useState(false);const[italic, setItalic]=useState(false);const[textDecoration, setTextDecoration]=useState<TextDecoration>(TEXT_DECORATIONS[0].value
);const[textAlign, setTextAlign]=useState<TextAlign>(TEXT_ALIGNS[0].value);const[fontSize, setFontSize]=useState<FontSize>("medium");const updateFontSize =(increment:boolean):void=>{setFontSize((fontSize)=>{const i =FONT_SIZES.findIndex(({ value })=> value === fontSize);const amount = increment ?1:-1;const nextIndex = Math.max(0, Math.min(FONT_SIZES.length, i + amount));returnFONT_SIZES[nextIndex].value;});};const[visible, setVisible]=useState(false);const onRequestClose =():void=>setVisible(false);const[hoverTimeout, textFieldProps,{ reset }]=useNumberField({
id:"hoverable-menus-hover-timeout",
min:0,
max:3000,
step:100,
fixOnBlur:false,});return(<divclassName={styles.container}><AppBarcomponent="div"theme="default"className={styles.appbar}><MenuBararia-label="Text Formatting"// The default behavior is to require the user to click one of the// `DropdownMenu` below before enabling the "hover mode" behavior.// This can be overridden by setting the `hoverTimeout` prop which// will update the behavior so the "hover mode" behavior will be// active after the user has hovered over one of the `DropdownMenu`s// for that amount of time in millisecondshoverTimeout={hoverTimeout}><DropdownMenuid="menubar-item-1"buttonChildren="Font"fixedPositionOptions={fixedPositionOptions}>{FONT_FAMILIES.map((font, i)=>(<MenuItemRadioid={`menubar-item-font-${i +1}`}key={font}checked={font === fontFamily}onCheckedChange={()=>setFontFamily(font)}>{font}</MenuItemRadio>))}</DropdownMenu><DropdownMenuid="menubar-item-2"buttonChildren="Style/Color"fixedPositionOptions={fixedPositionOptions}><MenuItemCheckboxid="menubar-item-bold"checked={bold}onCheckedChange={(checked)=>setBold(checked)}>
Bold
</MenuItemCheckbox><MenuItemCheckboxid="menubar-item-italic"checked={italic}onCheckedChange={(checked)=>setItalic(checked)}>
Italic
</MenuItemCheckbox><MenuItemGrouparia-label="Color">{COLORS.map(({ label, value }, i)=>(<MenuItemRadioid={`menubar-item-color-${i +1}`}key={value}checked={color === value}onCheckedChange={()=>setColor(value)}>{label}</MenuItemRadio>))}</MenuItemGroup><MenuItemSeparator/><MenuItemGrouparia-label="Text Decoration">{TEXT_DECORATIONS.map(({ label, value }, i)=>(<MenuItemRadioid={`menubar-item-decoration-${i +1}`}key={value}checked={textDecoration === value}onCheckedChange={()=>setTextDecoration(value)}>{label}</MenuItemRadio>))}</MenuItemGroup></DropdownMenu><DropdownMenuid="menubar-item-3"buttonChildren="Text Align"fixedPositionOptions={fixedPositionOptions}><MenuItemGrouparia-label="Text Align">{TEXT_ALIGNS.map(({ label, value }, i)=>(<MenuItemRadioid={`menubar-item-3-align-${i +1}`}key={value}checked={value === textAlign}onCheckedChange={()=>setTextAlign(value)}>{label}</MenuItemRadio>))}</MenuItemGroup><MenuItemSeparator/><InfiniteDropdownMenuindex={3}depth={1}buttonChildren="Infinite Menu"/></DropdownMenu><DropdownMenuid="menubar-item-4"buttonChildren="Size"fixedPositionOptions={fixedPositionOptions}><MenuItemid="menubar-item-4-smaller"onClick={()=>updateFontSize(false)}leftAddon={<RemoveSVGIcon/>}disabled={fontSize ==="x-small"}disabledOpacity>
Smaller
</MenuItem><MenuItemid="menubar-item-4-bigger"onClick={()=>updateFontSize(true)}leftAddon={<AddSVGIcon/>}disabled={fontSize ==="x-large"}disabledOpacity>
Bigger
</MenuItem><MenuItemSeparator/><MenuItemGrouparia-label="Font Size">{FONT_SIZES.map(({ label, value }, i)=>(<MenuItemRadioid={`menubar-item-4-font-size-${i +1}`}key={value}checked={value === fontSize}onCheckedChange={()=>setFontSize(value)}>{label}</MenuItemRadio>))}</MenuItemGroup></DropdownMenu></MenuBar></AppBar><divclassName={styles.text}><Typographystyle={{
color: color ===""?undefined: color,
fontFamily,
fontSize,
fontStyle: italic ?"italic":undefined,
fontWeight: bold ?"bold":undefined,
textAlign,
textDecoration,}}>{EXAMPLE_TEXT}</Typography></div><Buttontheme="warning"floating="bottom-left"aria-label="Configure"onClick={()=>setVisible((prevVisible)=>!prevVisible)}><BuildSVGIcon/></Button><Dialogid="configure-dialog"aria-labelledby="configure-dialog-title"modalvisible={visible}onRequestClose={onRequestClose}className={styles.dialog}><DialogHeader><DialogTitleid="configure-dialog-title">
Configure Hover Timeout
</DialogTitle></DialogHeader><DialogContent><Formid="configure-form"onSubmit={onRequestClose}onReset={()=>{reset();onRequestClose();}}><TextFieldWithMessage{...textFieldProps}label="Hover Timeout"placeholder="0"/></Form><Typography>
The amount of time the user must over over a menu in milliseconds
before the hover mode behavior is enabled.
</Typography><Typography>
If this is <Code>undefined</Code>, the user must click one of the
dropdown buttons before the hover mode is enabled.
</Typography><Typography>
If this is set to <Code>0</Code>, the menus will become visible
immediately on hover.
</Typography></DialogContent><DialogFooter><Buttonform="configure-form"type="reset"theme="warning">
Reset
</Button><Buttonform="configure-form"type="submit"theme="primary"disabled={textFieldProps.error}>
Confirm
</Button></DialogFooter></Dialog></div>);}