diff --git a/docs/data/base/components/menu/UseMenu.js b/docs/data/base/components/menu/UseMenu.js index f2c4d8f28f2596..d495d627a0b845 100644 --- a/docs/data/base/components/menu/UseMenu.js +++ b/docs/data/base/components/menu/UseMenu.js @@ -2,6 +2,7 @@ import * as React from 'react'; import PropTypes from 'prop-types'; import { useMenu, MenuUnstyledContext } from '@mui/base/MenuUnstyled'; import { useMenuItem } from '@mui/base/MenuItemUnstyled'; +import PopperUnstyled from '@mui/base/PopperUnstyled'; import { GlobalStyles } from '@mui/system'; import clsx from 'clsx'; @@ -18,6 +19,15 @@ const grey = { 900: '#24292f', }; +const blue = { + 100: '#DAECFF', + 200: '#99CCF3', + 400: '#3399FF', + 500: '#007FFF', + 600: '#0072E5', + 900: '#003A75', +}; + const styles = ` .menu-root { font-family: IBM Plex Sans, sans-serif; @@ -80,10 +90,53 @@ const styles = ` background-color: ${grey[800]}; color: ${grey[300]}; } + + .button { + font-family: IBM Plex Sans, sans-serif; + font-size: 0.875rem; + box-sizing: border-box; + min-height: calc(1.5em + 22px); + border-radius: 12px; + padding: 12px 16px; + line-height: 1.5; + background: #fff; + border: 1px solid ${grey[200]}; + color: ${grey[900]}; + cursor: pointer; + + transition-property: all; + transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1); + transition-duration: 120ms; + + &:hover { + background: ${grey[50]}; + border-color: ${grey[300]}; + } + + &:focus { + border-color: ${blue[400]}; + outline: 3px solid ${blue[200]}; + } + } + + .mode-dark .button { + background: ${grey[900]}; + border: 1px solid ${grey[700]}; + color: ${grey[300]}; + + &:hover { + background: ${grey[800]}; + border-color: ${grey[600]}; + } + + &:focus { + outline: 3px solid ${blue[500]} + } + } `; const Menu = React.forwardRef(function Menu(props, ref) { - const { children, ...other } = props; + const { children, onClose, open, ...other } = props; const { registerItem, @@ -93,6 +146,8 @@ const Menu = React.forwardRef(function Menu(props, ref) { getItemState, } = useMenu({ listboxRef: ref, + onClose, + open, }); const contextValue = { @@ -114,6 +169,8 @@ const Menu = React.forwardRef(function Menu(props, ref) { Menu.propTypes = { children: PropTypes.node, + onClose: PropTypes.func.isRequired, + open: PropTypes.bool.isRequired, }; const MenuItem = React.forwardRef(function MenuItem(props, ref) { @@ -139,14 +196,54 @@ MenuItem.propTypes = { }; export default function UseMenu() { + const [anchorEl, setAnchorEl] = React.useState(null); + const preventReopen = React.useRef(false); + const buttonRef = React.useRef(null); + + const handleOnClick = (event) => { + if (preventReopen.current) { + event.preventDefault(); + preventReopen.current = false; + return; + } + + setAnchorEl(anchorEl ? null : event.currentTarget); + }; + + const handleOnClose = () => { + setAnchorEl(null); + buttonRef.current.focus(); + }; + + const open = Boolean(anchorEl); + + const handleButtonMouseDown = () => { + if (open) { + // Prevents the menu from reopening right after closing + // when clicking the button. + preventReopen.current = true; + } + }; + return ( - - Cut - Copy - Paste - + + + + Cut + Copy + Paste + + ); } diff --git a/docs/data/base/components/menu/UseMenu.tsx b/docs/data/base/components/menu/UseMenu.tsx index bae50a70c799e6..62021d9b0835a1 100644 --- a/docs/data/base/components/menu/UseMenu.tsx +++ b/docs/data/base/components/menu/UseMenu.tsx @@ -5,6 +5,7 @@ import { MenuUnstyledContextType, } from '@mui/base/MenuUnstyled'; import { useMenuItem } from '@mui/base/MenuItemUnstyled'; +import PopperUnstyled from '@mui/base/PopperUnstyled'; import { GlobalStyles } from '@mui/system'; import clsx from 'clsx'; @@ -20,6 +21,16 @@ const grey = { 800: '#32383f', 900: '#24292f', }; + +const blue = { + 100: '#DAECFF', + 200: '#99CCF3', + 400: '#3399FF', + 500: '#007FFF', + 600: '#0072E5', + 900: '#003A75', +}; + const styles = ` .menu-root { font-family: IBM Plex Sans, sans-serif; @@ -82,13 +93,59 @@ const styles = ` background-color: ${grey[800]}; color: ${grey[300]}; } + + .button { + font-family: IBM Plex Sans, sans-serif; + font-size: 0.875rem; + box-sizing: border-box; + min-height: calc(1.5em + 22px); + border-radius: 12px; + padding: 12px 16px; + line-height: 1.5; + background: #fff; + border: 1px solid ${grey[200]}; + color: ${grey[900]}; + cursor: pointer; + + transition-property: all; + transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1); + transition-duration: 120ms; + + &:hover { + background: ${grey[50]}; + border-color: ${grey[300]}; + } + + &:focus { + border-color: ${blue[400]}; + outline: 3px solid ${blue[200]}; + } + } + + .mode-dark .button { + background: ${grey[900]}; + border: 1px solid ${grey[700]}; + color: ${grey[300]}; + + &:hover { + background: ${grey[800]}; + border-color: ${grey[600]}; + } + + &:focus { + outline: 3px solid ${blue[500]} + } + } `; const Menu = React.forwardRef(function Menu( - props: React.ComponentPropsWithoutRef<'ul'>, + props: React.ComponentPropsWithoutRef<'ul'> & { + onClose: () => void; + open: boolean; + }, ref: React.Ref, ) { - const { children, ...other } = props; + const { children, onClose, open, ...other } = props; const { registerItem, @@ -98,6 +155,8 @@ const Menu = React.forwardRef(function Menu( getItemState, } = useMenu({ listboxRef: ref, + onClose, + open, }); const contextValue: MenuUnstyledContextType = { @@ -139,14 +198,54 @@ const MenuItem = React.forwardRef(function MenuItem( }); export default function UseMenu() { + const [anchorEl, setAnchorEl] = React.useState(null); + const preventReopen = React.useRef(false); + const buttonRef = React.useRef(null); + + const handleOnClick = (event: React.MouseEvent) => { + if (preventReopen.current) { + event.preventDefault(); + preventReopen.current = false; + return; + } + + setAnchorEl(anchorEl ? null : event.currentTarget); + }; + + const handleOnClose = () => { + setAnchorEl(null); + buttonRef.current!.focus(); + }; + + const open = Boolean(anchorEl); + + const handleButtonMouseDown = () => { + if (open) { + // Prevents the menu from reopening right after closing + // when clicking the button. + preventReopen.current = true; + } + }; + return ( - - Cut - Copy - Paste - + + + + Cut + Copy + Paste + + ); } diff --git a/docs/data/base/components/menu/UseMenu.tsx.preview b/docs/data/base/components/menu/UseMenu.tsx.preview deleted file mode 100644 index eaf8ac1dfb8966..00000000000000 --- a/docs/data/base/components/menu/UseMenu.tsx.preview +++ /dev/null @@ -1,8 +0,0 @@ - - - - Cut - Copy - Paste - - \ No newline at end of file