Skip to content

Commit 77cf40a

Browse files
authored
feat: APP-374 header navigation toggle (#2581)
1 parent 8c5378b commit 77cf40a

17 files changed

+180
-119
lines changed

tailwind.common.js

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -408,6 +408,36 @@ module.exports = {
408408
},
409409
},
410410
},
411+
keyframes: {
412+
menuOpen: {
413+
'0%': {
414+
opacity: '0',
415+
transform: 'scale(0.60)',
416+
transformOrigin: 'top right',
417+
},
418+
'100%': {
419+
opacity: '1',
420+
transform: 'scale(1)',
421+
transformOrigin: 'top right',
422+
},
423+
},
424+
menuClose: {
425+
'0%': {
426+
opacity: '1',
427+
transform: 'scale(1)',
428+
transformOrigin: 'top right',
429+
},
430+
'100%': {
431+
opacity: '0',
432+
transform: 'scale(0.60)',
433+
transformOrigin: 'top right',
434+
},
435+
},
436+
},
437+
animation: {
438+
menuOpen: 'menuOpen 300ms ease-in-out',
439+
menuClose: 'menuClose 225ms ease-in-out',
440+
},
411441
},
412442
},
413443
plugins: [],

web-components/src/components/header/Header.styles.ts

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -102,14 +102,6 @@ export const useHeaderStyles = makeStyles<StyleProps>()(
102102
// BEGIN HACK setting jss styles (duplicated from mui components built-in emotion styles)
103103
// so it's initially rendered on gatsby build
104104
// Remove once migrations from mui jss to emotion and to latest gatsby done
105-
desktop: {
106-
[theme.breakpoints.down('md')]: {
107-
display: 'none',
108-
},
109-
[theme.breakpoints.up('md')]: {
110-
display: 'block',
111-
},
112-
},
113105
mobile: {
114106
[theme.breakpoints.down('md')]: {
115107
display: 'block',

web-components/src/components/header/components/HeaderDropdown/HeaderDropdown.Item.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@ export const HeaderDropdownItem: React.FC<
5656
alignItems="center"
5757
className={cn(styles.item, className)}
5858
onMouseEnter={onHover}
59+
component="li"
5960
>
6061
{SVG && (
6162
<Box className="mr-[18px] flex items-center">

web-components/src/components/header/components/HeaderDropdown/HeaderDropdown.tsx

Lines changed: 15 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -16,25 +16,32 @@ const HeaderDropdown: React.FC<
1616
items: HeaderDropdownItemProps[];
1717
linkComponent: React.FC<React.PropsWithChildren<NavLinkProps>>;
1818
title?: string;
19+
isUserMenu?: boolean;
1920
}>
2021
> = props => {
2122
const { classes: styles } = useStyles();
2223
return (
23-
<Box display="flex" flexDirection="column">
24+
<Box
25+
display="flex"
26+
flexDirection="column"
27+
className={`${props.isUserMenu ? 'pt-10' : 'p-25'}`}
28+
>
2429
{props.title && (
2530
<Box mb={2}>
2631
<Title variant="h4" className={styles.label}>
2732
{ReactHtmlParser(props.title)}
2833
</Title>
2934
</Box>
3035
)}
31-
{props.items.map((link, i) => (
32-
<HeaderDropdownItem
33-
key={i}
34-
{...link}
35-
linkComponent={props.linkComponent}
36-
/>
37-
))}
36+
<Box component="ul" className="p-0">
37+
{props.items.map((link, i) => (
38+
<HeaderDropdownItem
39+
key={i}
40+
{...link}
41+
linkComponent={props.linkComponent}
42+
/>
43+
))}
44+
</Box>
3845
</Box>
3946
);
4047
};

web-components/src/components/header/components/HeaderMenuItem/HeaderMenuItem.Content.tsx

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,13 +13,15 @@ type Props = {
1313
classes?: {
1414
paper?: string;
1515
};
16+
isUserMenu?: boolean;
1617
};
1718

1819
export const HeaderMenuItemContent = ({
1920
item,
2021
linkComponent: LinkComponent,
2122
pathname,
2223
classes,
24+
isUserMenu,
2325
}: Props): JSX.Element => {
2426
const theme = useTheme();
2527
const { classes: styles } = useHeaderMenuHoverStyles();
@@ -41,12 +43,14 @@ export const HeaderMenuItemContent = ({
4143
title={item.title}
4244
renderTitle={item.renderTitle}
4345
classes={{ title: styles.title, paper: classes?.paper }}
46+
isUserMenu={isUserMenu}
4447
>
4548
{/* `render` overrides default dropdown */}
4649
{item.dropdownItems && !item.renderDropdownItems && (
4750
<HeaderDropdown
4851
items={item.dropdownItems}
4952
linkComponent={LinkComponent}
53+
isUserMenu={isUserMenu}
5054
/>
5155
)}
5256
{item.renderDropdownItems && item.renderDropdownItems()}

web-components/src/components/header/components/HeaderMenuItem/HeaderMenuItem.Hover.styles.ts

Lines changed: 1 addition & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -2,18 +2,11 @@ import { Theme } from '@mui/material/styles';
22
import { makeStyles } from 'tss-react/mui';
33

44
export const useMenuHoverStyles = makeStyles()((theme: Theme) => ({
5-
popover: {
6-
pointerEvents: 'none',
7-
},
8-
popoverContent: {
9-
pointerEvents: 'auto',
10-
marginTop: theme.spacing(4),
11-
},
125
text: {
136
'& li.MuiMenuItem-root:hover': {
147
backgroundColor: 'transparent',
158
},
16-
'& li > a': {
9+
'& ul > li > a': {
1710
fontFamily: 'lato',
1811
color: '#000',
1912
textDecoration: 'none',
@@ -29,11 +22,6 @@ export const useMenuHoverStyles = makeStyles()((theme: Theme) => ({
2922
outline: 'none',
3023
},
3124
},
32-
paper: {
33-
borderRadius: '2px',
34-
border: `1px solid ${theme.palette.grey[400]}`,
35-
padding: theme.spacing(6.25),
36-
},
3725
icon: {
3826
marginLeft: theme.spacing(1),
3927
},

web-components/src/components/header/components/HeaderMenuItem/HeaderMenuItem.Hover.tsx

Lines changed: 42 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,8 @@
1-
import React, { useRef } from 'react';
2-
import { MenuList, Paper, Popover } from '@mui/material';
3-
import cx from 'clsx';
1+
import { MenuList } from '@mui/material';
42

53
import DropdownIcon from '../../../icons/DropdownIcon';
64
import { useMenuHoverStyles } from './HeaderMenuItem.Hover.styles';
5+
import { useMenuState } from './hooks/useMenuState';
76

87
export interface MenuTitle {
98
title?: string;
@@ -18,6 +17,7 @@ interface Props extends MenuTitle {
1817
children: React.ReactNode;
1918
textColor?: string;
2019
dropdownColor?: string;
20+
isUserMenu?: boolean;
2121
}
2222

2323
/**
@@ -30,31 +30,30 @@ const HeaderMenuItemHover = ({
3030
classes,
3131
dropdownColor,
3232
children,
33+
isUserMenu,
3334
}: Props): JSX.Element => {
3435
const { classes: styles } = useMenuHoverStyles();
3536

36-
const popoverAnchor = useRef(null);
37-
const [anchorEl, setAnchorEl] = React.useState<HTMLElement | null>(null);
38-
39-
const handlePopoverOpen = () => {
40-
setAnchorEl(popoverAnchor.current);
41-
};
42-
43-
const handlePopoverClose = () => {
44-
setAnchorEl(null);
45-
};
46-
47-
const open = Boolean(anchorEl);
37+
const {
38+
isMenuOpen,
39+
hasInteracted,
40+
isTouchScreen,
41+
openMenu,
42+
closeMenu,
43+
toggleMenu,
44+
} = useMenuState();
4845

4946
return (
50-
<div>
47+
<div
48+
className="relative p-10"
49+
onMouseEnter={isTouchScreen ? undefined : openMenu}
50+
onMouseLeave={closeMenu}
51+
>
5152
<span
52-
ref={popoverAnchor}
53-
aria-owns={open ? 'mouse-over-popover' : undefined}
53+
className="relative"
54+
aria-owns={isMenuOpen ? 'mouse-over-menu' : undefined}
5455
aria-haspopup="true"
55-
onMouseEnter={handlePopoverOpen}
56-
onMouseLeave={handlePopoverClose}
57-
onClick={handlePopoverOpen}
56+
onClick={isTouchScreen ? toggleMenu : undefined}
5857
>
5958
{title && (
6059
<span className={classes?.title}>
@@ -64,40 +63,29 @@ const HeaderMenuItemHover = ({
6463
)}
6564
{renderTitle && renderTitle()}
6665
</span>
67-
<Popover
68-
disableRestoreFocus
69-
id="mouse-over-popover"
70-
className={styles.popover}
71-
classes={{
72-
paper: styles.popoverContent,
73-
}}
74-
open={open}
75-
anchorEl={anchorEl}
76-
anchorOrigin={{
77-
vertical: 'bottom',
78-
horizontal: 'right',
79-
}}
80-
transformOrigin={{
81-
vertical: 'top',
82-
horizontal: 'right',
83-
}}
84-
PaperProps={{
85-
onMouseEnter: handlePopoverOpen,
86-
onMouseLeave: handlePopoverClose,
87-
}}
88-
onClose={handlePopoverClose}
89-
disableScrollLock={true}
90-
sx={{ position: 'absolute' }}
66+
<nav
67+
id="mouse-over-menu"
68+
className={`absolute top-15 ${
69+
isUserMenu ? 'pt-35' : 'top-full'
70+
} right-0 z-50 ${
71+
isMenuOpen
72+
? 'block opacity-100' + (hasInteracted ? ' animate-menuOpen' : '')
73+
: 'opacity-0' +
74+
(hasInteracted
75+
? ' animate-menuClose pointer-events-none'
76+
: ' hidden')
77+
}`}
78+
onClick={isTouchScreen ? closeMenu : undefined}
9179
>
92-
<Paper className={cx(classes?.paper, styles.paper)} elevation={5}>
93-
<MenuList
94-
classes={{ root: styles.text, padding: styles.noOutline }}
95-
disablePadding
96-
>
97-
{children}
98-
</MenuList>
99-
</Paper>
100-
</Popover>
80+
<MenuList
81+
className="bg-grey-0 rounded-[4px] border border-solid border-grey-300 shadow-[0px_5px_5px_-3px_rgba(0,0,0,0.2),_0px_8px_10px_1px_rgba(0,0,0,0.14),_0px_3px_14px_2px_rgba(0,0,0,0.12)]"
82+
classes={{ root: styles.text, padding: styles.noOutline }}
83+
disablePadding
84+
component="div"
85+
>
86+
{children}
87+
</MenuList>
88+
</nav>
10189
</div>
10290
);
10391
};

web-components/src/components/header/components/HeaderMenuItem/HeaderMenuItem.styles.ts

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,6 @@ export const useHeaderMenuHoverStyles = makeStyles()(theme => ({
55
boxSizing: 'border-box',
66
height: '100%',
77
lineHeight: theme.spacing(6),
8-
paddingRight: theme.spacing(7.375),
9-
paddingLeft: theme.spacing(7.375),
108
backgroundColor: 'inherit',
119
'& > a': {
1210
borderBottom: '2px solid transparent',

web-components/src/components/header/components/HeaderMenuItem/HeaderMenuItem.tsx

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,10 @@
1-
import React from 'react';
2-
import { BoxProps, MenuItem, SxProps } from '@mui/material';
1+
import {
2+
BoxProps,
3+
MenuItem,
4+
SxProps,
5+
useMediaQuery,
6+
useTheme,
7+
} from '@mui/material';
38
import cx from 'clsx';
49

510
import { Theme } from '../../../../theme/muiTheme';
@@ -30,6 +35,7 @@ export interface HeaderMenuItemBase {
3035

3136
export interface MenuItemProps extends HeaderMenuItemBase {
3237
item: Item;
38+
isUserMenu?: boolean;
3339
}
3440

3541
const HeaderMenuItem: React.FC<MenuItemProps> = ({
@@ -39,15 +45,18 @@ const HeaderMenuItem: React.FC<MenuItemProps> = ({
3945
classes,
4046
sx,
4147
component = 'li',
48+
isUserMenu,
4249
}) => {
4350
const { classes: styles } = useHeaderMenuHoverStyles();
44-
51+
const theme = useTheme();
52+
const isTablet = useMediaQuery(theme.breakpoints.down('md'));
4553
return (
4654
<MenuItem
4755
className={cx(
4856
classes?.root,
4957
styles.menuItem,
5058
pathname === item.href && styles.currentMenuItem,
59+
isTablet && !isUserMenu ? '!hidden' : '',
5160
)}
5261
sx={[...sxToArray(sx)]}
5362
component={component}
@@ -57,6 +66,7 @@ const HeaderMenuItem: React.FC<MenuItemProps> = ({
5766
linkComponent={linkComponent}
5867
pathname={pathname}
5968
classes={{ paper: classes?.paper }}
69+
isUserMenu={isUserMenu}
6070
/>
6171
</MenuItem>
6272
);

0 commit comments

Comments
 (0)