Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

chore: persist menu in DOM #969

Merged
35 changes: 29 additions & 6 deletions src/components/Menu/Menu.style.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
'use client';
import type {
AppBarProps,
BoxProps,
CSSObject,
LinkProps,
ListItemProps,
Expand All @@ -10,6 +11,7 @@ import type {
} from '@mui/material';
import {
AppBar,
Box,
Drawer,
Link,
ListItem,
Expand Down Expand Up @@ -46,13 +48,13 @@ export const MenuList = styled(MuiMenuList, {
justifyContent: cardsLayout ? 'center' : 'unset',
flexWrap: cardsLayout ? 'wrap' : 'inherit',
padding: cardsLayout ? theme.spacing(0, 3) : 0,
outline: 'unset',
gap: cardsLayout ? '12px' : 'inherit',
'& > :first-of-type': {
marginTop:
isOpenSubMenu || hasLabel || cardsLayout ? 'inherit' : theme.spacing(1.5),
paddingTop: isOpenSubMenu ? theme.spacing(1.5) : 'inherit',
},
'& > :last-child': {
'& > li:last-of-type': {
marginBottom: isOpenSubMenu ? 'inherit' : theme.spacing(3),
paddingBottom: isOpenSubMenu ? theme.spacing(1.5) : 'inherit',
paddingTop: hasLabel ? 0 : 'inherit',
Expand All @@ -68,7 +70,7 @@ export const MenuHeaderLabel = styled(Typography)(({ theme }) => ({
display: 'flex',
marginRight: theme.spacing(4.75),
flexWrap: 'nowrap',
[theme.breakpoints.up('sm' as Breakpoint)]: {
[theme.breakpoints.up('md' as Breakpoint)]: {
maxWidth: 174,
marginRight: 0,
marginLeft: theme.spacing(0.75),
Expand All @@ -78,14 +80,16 @@ export const MenuHeaderLabel = styled(Typography)(({ theme }) => ({
export interface MenuPaperProps
extends Omit<PaperProps, 'isDarkMode' | 'isWide' | 'component'> {
isMobile?: boolean;
show: boolean;
width?: string;
component?: ElementType<any>;
}

export const MenuPaper = styled(Paper, {
shouldForwardProp: (prop) =>
prop !== 'isMobile' && prop !== 'isWide' && prop !== 'isSubMenu',
})<MenuPaperProps>(({ theme, isMobile, width }) => ({
prop !== 'isMobile' && prop !== 'isWide' && prop !== 'show',
})<MenuPaperProps>(({ theme, isMobile, width, show }) => ({
display: !show ? 'none' : 'block',
background: theme.palette.surface1.main,
padding: 0,
marginTop: 0,
Expand All @@ -99,11 +103,13 @@ export const MenuPaper = styled(Paper, {
}8px 16px rgba(0, 0, 0, 0.16)`,
borderRadius: '12px 12px 0 0',
marginBottom: 0,

maxHeight: `calc( 100vh - ${MENU_LABEL_HEIGHT}px - 12px )`, // viewHeight - navbarHeight - offset
overflowY: 'auto',
overflowX: 'hidden',
width: '100%',
transformOrigin: 'bottom',
height: '100% !important',
transition:
'opacity 307ms cubic-bezier(0.4, 0, 0.2, 1) 0ms, transform 204ms cubic-bezier(0.4, 0, 0.2, 1) 0ms',

Expand All @@ -112,6 +118,8 @@ export const MenuPaper = styled(Paper, {
height: 32,
},

'.submenu': { paddingBottom: theme.spacing(1.5) },

[theme.breakpoints.up('sm' as Breakpoint)]: {
maxHeight: 'calc( 100vh - 72px - 12px )',
},
Expand All @@ -138,7 +146,6 @@ export const MenuItemLink = styled(Link, {
})<MenuItemLinkProps>(({ theme }) => ({
display: 'flex',
justifyContent: 'space-between',
padding: theme.spacing(0, 1.5),
height: 48,
textDecoration: 'none',
color: 'inherit',
Expand Down Expand Up @@ -193,3 +200,19 @@ export const MenuHeaderAppBar = styled(AppBar)<MenuHeaderAppBarProps>(
},
}),
);

export interface MenuClickAwayBoxProps extends Omit<BoxProps, 'component'> {
open: boolean;
}

export const MenuClickAwayBox = styled(Box)<MenuClickAwayBoxProps>(
({ open }) => ({
display: open ? 'block' : 'none',
position: 'absolute',
left: 0,
width: '100%',
top: 0,
zIndex: -1,
backgroundColor: 'transparent',
}),
);
5 changes: 4 additions & 1 deletion src/components/Menu/Menu.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ interface MenuProps {
setOpen: (open: boolean, anchorRef: any) => void;
cardsLayout?: boolean;
styles?: SxProps<Theme>;
keepMounted?: boolean;
open: boolean;
children: any;
width?: string;
Expand All @@ -19,6 +20,7 @@ export const Menu = ({
setOpen,
cardsLayout,
styles,
keepMounted,
width,
label,
isOpenSubMenu,
Expand All @@ -32,6 +34,7 @@ export const Menu = ({
label={label}
open={open}
styles={styles}
keepMounted={keepMounted}
width={width}
cardsLayout={cardsLayout}
setOpen={setOpen}
Expand All @@ -45,8 +48,8 @@ export const Menu = ({
label={label}
open={open}
styles={styles}
keepMounted={keepMounted}
cardsLayout={cardsLayout}
setOpen={setOpen}
isOpenSubMenu={isOpenSubMenu || false}
>
{children}
Expand Down
31 changes: 31 additions & 0 deletions src/components/Menu/MenuClickAwayListener.tsx
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is unfortunate, but I wasted too much time with the MUI clickawaylistener and decided to drop it in favor of a component which handles just that.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would prefer to remove the div to be able to keep the click on the widget and not the double click

Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import { useMenuStore } from '@/stores/menu/MenuStore';
import type { CSSObject } from '@mui/material';
import type { PropsWithChildren } from 'react';
import { MenuClickAwayBox } from './Menu.style';
interface MenuClickAwayListenerProps {
open: boolean;
styles?: CSSObject;
}

export const MenuClickAwayListener: React.FC<
PropsWithChildren<MenuClickAwayListenerProps>
> = ({ open, children, styles }) => {
const { closeAllMenus } = useMenuStore((state) => state);

return open ? (
<MenuClickAwayBox
open={open}
className="click-away"
sx={styles}
onClick={(event) => {
event.preventDefault();
event.stopPropagation();
closeAllMenus();
}}
>
{children}
</MenuClickAwayBox>
) : (
children
);
};
90 changes: 43 additions & 47 deletions src/components/Menu/MenuDesktop.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ import { MenuKeysEnum, MenuMain } from '@/const/menuKeys';
import { useMenuStore } from '@/stores/menu/MenuStore';
import type { SxProps, Theme } from '@mui/material';
import { Fade, Typography } from '@mui/material';
import ClickAwayListener from '@mui/material/ClickAwayListener';
import type { KeyboardEvent } from 'react';
import {
MenuHeaderAppBar,
Expand All @@ -11,12 +10,14 @@ import {
MenuPaper,
MenuPopper,
} from './Menu.style';
import { MenuClickAwayListener } from './MenuClickAwayListener';
interface MenuProps {
isOpenSubMenu: boolean;
label?: string;
transformOrigin?: string;
cardsLayout?: boolean;
styles?: SxProps<Theme>;
keepMounted?: boolean;
setOpen: (open: boolean, anchorRef: any) => void;
open: boolean;
children: any;
Expand All @@ -28,6 +29,7 @@ export const MenuDesktop = ({
isOpenSubMenu,
setOpen,
styles,
keepMounted,
transformOrigin,
cardsLayout,
width,
Expand All @@ -36,7 +38,7 @@ export const MenuDesktop = ({
children,
anchorEl,
}: MenuProps) => {
const { openSubMenu, closeAllMenus } = useMenuStore((state) => state);
const { openSubMenu } = useMenuStore((state) => state);

function handleListKeyDown(event: KeyboardEvent) {
if (event.key === 'Tab' || event.key === 'Escape') {
Expand All @@ -45,67 +47,61 @@ export const MenuDesktop = ({
}
}

return open ? (
<>
return (
<MenuClickAwayListener open={open} styles={{ height: '100vh' }}>
<MenuPopper
open={open}
anchorEl={anchorEl}
keepMounted={keepMounted}
transition
disablePortal
placement="bottom-end"
>
{({ TransitionProps }) => (
<Fade
{...TransitionProps}
in={open}
style={{
transformOrigin: transformOrigin || 'top',
}}
>
<MenuPaper width={width}>
<ClickAwayListener
onClickAway={(event) => {
event.preventDefault();
closeAllMenus();
}}
<MenuPaper show={open} width={width} className="menu-paper">
<MenuList
autoFocusItem={open}
id="main-burger-menu"
autoFocus={open}
isOpenSubMenu={openSubMenu !== MenuKeysEnum.None}
aria-labelledby="main-burger-menu"
onKeyDown={handleListKeyDown}
cardsLayout={cardsLayout}
hasLabel={!!label}
sx={styles}
component={
isOpenSubMenu && openSubMenu !== MenuMain.WalletSelect
? 'div'
: 'ul'
}
>
<MenuList
autoFocusItem={open}
id="main-burger-menu"
autoFocus={open}
isOpenSubMenu={openSubMenu !== MenuKeysEnum.None}
aria-labelledby="main-burger-menu"
onKeyDown={handleListKeyDown}
cardsLayout={cardsLayout}
hasLabel={!!label}
sx={styles}
component={
isOpenSubMenu && openSubMenu !== MenuMain.WalletSelect
? 'div'
: 'ul'
}
>
{!!label ? (
<MenuHeaderAppWrapper>
<MenuHeaderAppBar component="div" elevation={0}>
<Typography
variant={'lifiBodyMediumStrong'}
width={'100%'}
align={'center'}
flex={1}
noWrap
>
{label}
</Typography>
</MenuHeaderAppBar>
</MenuHeaderAppWrapper>
) : null}
{children}
</MenuList>
</ClickAwayListener>
{!!label ? (
<MenuHeaderAppWrapper>
<MenuHeaderAppBar component="div" elevation={0}>
<Typography
variant={'lifiBodyMediumStrong'}
width={'100%'}
align={'center'}
flex={1}
noWrap
>
{label}
</Typography>
</MenuHeaderAppBar>
</MenuHeaderAppWrapper>
) : null}
{children}
</MenuList>
</MenuPaper>
</Fade>
)}
</MenuPopper>
</>
) : null;
</MenuClickAwayListener>
);
};
1 change: 0 additions & 1 deletion src/components/Menu/MenuItem.style.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
'use client';
import type {
ListItemProps,
MenuItemProps as MUIMenuItemProps,
Expand Down
Loading
Loading