Skip to content

Commit dd7920f

Browse files
authored
add open transition to menu (codesandbox#3670)
1 parent 3027be4 commit dd7920f

File tree

3 files changed

+85
-42
lines changed

3 files changed

+85
-42
lines changed

packages/components/src/components/IconButton/index.tsx

Lines changed: 16 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
// @ts-nocheck
22
import React from 'react';
3+
import deepmerge from 'deepmerge';
34
import { Button } from '../Button';
45
import { Icon, IconNames } from '../Icon';
56

@@ -16,24 +17,28 @@ export const IconButton: React.FC<IconButtonProps> = ({
1617
name,
1718
title,
1819
size,
20+
css = {},
1921
...props
2022
}) => (
2123
// @ts-ignore
2224
<Button
2325
title={title}
2426
variant="link"
25-
css={{
26-
width: '26px', // same width as (height of the button)
27-
padding: 0,
28-
borderRadius: '50%',
29-
':hover:not(:disabled)': {
30-
backgroundColor: 'secondaryButton.background',
27+
css={deepmerge(
28+
{
29+
width: '26px', // same width as (height of the button)
30+
padding: 0,
31+
borderRadius: '50%',
32+
':hover:not(:disabled)': {
33+
backgroundColor: 'secondaryButton.background',
34+
},
35+
':focus:not(:disabled)': {
36+
outline: 'none',
37+
backgroundColor: 'secondaryButton.background',
38+
},
3139
},
32-
':focus:not(:disabled)': {
33-
outline: 'none',
34-
backgroundColor: 'secondaryButton.background',
35-
},
36-
}}
40+
css
41+
)}
3742
// @ts-ignore
3843
{...props}
3944
>

packages/components/src/components/Menu/index.tsx

Lines changed: 62 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,30 @@ import React from 'react';
22
import deepmerge from 'deepmerge';
33
import css from '@styled-system/css';
44
import * as ReachMenu from '@reach/menu-button';
5-
import { createGlobalStyle } from 'styled-components';
5+
import {
6+
createGlobalStyle,
7+
css as styledcss,
8+
keyframes,
9+
} from 'styled-components';
610
import { Element, Button, IconButton, List } from '../..';
711

12+
const transitions = {
13+
slide: keyframes({
14+
from: {
15+
opacity: 0,
16+
transform: 'translateY(-4px)',
17+
},
18+
}),
19+
scale: keyframes({
20+
from: {
21+
opacity: 0,
22+
transform: 'scale(0.7)',
23+
},
24+
}),
25+
};
26+
27+
const MenuContext = React.createContext({ trigger: null });
28+
829
const Menu = ({ ...props }) => {
930
const PortalStyles = createGlobalStyle(
1031
css({
@@ -20,6 +41,7 @@ const Menu = ({ ...props }) => {
2041
border: '1px solid',
2142
borderColor: 'menuList.border',
2243
':focus': { outline: 'none' },
44+
transform: 'translateY(4px)',
2345
// override reach ui styles
2446
padding: 0,
2547
},
@@ -38,13 +60,27 @@ const Menu = ({ ...props }) => {
3860
// override reach ui styles
3961
font: 'ineherit',
4062
},
41-
})
63+
}),
64+
styledcss`
65+
[data-reach-menu-list][data-trigger=MenuButton] {
66+
animation: ${transitions.slide} 150ms ease-out;
67+
transform-origin: top;
68+
}
69+
[data-reach-menu-list][data-trigger=MenuIconButton] {
70+
animation: ${transitions.scale} 150ms ease-out;
71+
transform-origin: top left;
72+
}
73+
`
4274
);
4375

76+
const trigger = props.children[0].type.name;
77+
4478
return (
45-
<Element as={ReachMenu.Menu} data-component="Menu" {...props}>
79+
<Element as={ReachMenu.Menu} {...props}>
4680
<PortalStyles />
47-
{props.children}
81+
<MenuContext.Provider value={{ trigger }}>
82+
{props.children}
83+
</MenuContext.Provider>
4884
</Element>
4985
);
5086
};
@@ -54,7 +90,15 @@ const MenuButton = props => (
5490
as={ReachMenu.MenuButton}
5591
variant="link"
5692
{...props}
57-
css={deepmerge({ width: 'auto' }, props.css || {})}
93+
css={deepmerge(
94+
{
95+
width: 'auto',
96+
// disable scale feedback of buttons in menu
97+
// to make the menu feel less jumpy
98+
':active:not(:disabled)': { transform: 'scale(1)' },
99+
},
100+
props.css || {}
101+
)}
58102
>
59103
{props.children}
60104
</Button>
@@ -64,11 +108,19 @@ const MenuIconButton = props => (
64108
<IconButton as={ReachMenu.MenuButton} {...props} />
65109
);
66110

67-
const MenuList = props => (
68-
<List as={ReachMenu.MenuList} data-component="MenuList" {...props}>
69-
{props.children}
70-
</List>
71-
);
111+
const MenuList = props => {
112+
const { trigger } = React.useContext(MenuContext);
113+
return (
114+
<List
115+
as={ReachMenu.MenuList}
116+
data-component="MenuList"
117+
data-trigger={trigger}
118+
{...props}
119+
>
120+
{props.children}
121+
</List>
122+
);
123+
};
72124

73125
const MenuItem = props => (
74126
<Element as={ReachMenu.MenuItem} data-component="MenuItem" {...props} />

packages/components/src/components/Menu/menu.stories.tsx

Lines changed: 7 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -16,10 +16,10 @@ export const Access = () => {
1616

1717
return (
1818
<Stack justify="flex-end" align="center" css={{ '> *': { lineHeight: 1 } }}>
19+
<Text size={2} variant="muted">
20+
Everyone with link
21+
</Text>{' '}
1922
<Menu>
20-
<Text size={2} variant="muted">
21-
Everyone with link
22-
</Text>{' '}
2323
<Menu.Button css={{ color: 'white' }}>
2424
{selected}{' '}
2525
<Element
@@ -54,28 +54,14 @@ export const IconButton = () => {
5454
const [selected, select] = React.useState(options[0]);
5555

5656
return (
57-
<Stack justify="flex-end" align="center" css={{ '> *': { lineHeight: 1 } }}>
57+
<Stack align="center" css={{ '> *': { lineHeight: 1 } }}>
5858
<Menu>
59-
<Menu.Button
59+
<Menu.IconButton
60+
name="filter"
6061
css={{
6162
[selected !== options[0] && 'color']: 'blues.500',
6263
}}
63-
>
64-
<svg
65-
width="14"
66-
height="10"
67-
viewBox="0 0 14 10"
68-
fill="none"
69-
xmlns="http://www.w3.org/2000/svg"
70-
>
71-
<path
72-
fillRule="evenodd"
73-
clipRule="evenodd"
74-
d="M0 1C0 0.447715 0.447715 0 1 0H13C13.5523 0 14 0.447715 14 1C14 1.55228 13.5523 2 13 2H1C0.447716 2 0 1.55228 0 1ZM2 5C2 4.44772 2.44772 4 3 4H11C11.5523 4 12 4.44772 12 5C12 5.55228 11.5523 6 11 6H3C2.44772 6 2 5.55228 2 5ZM5 8C4.44772 8 4 8.44771 4 9C4 9.55229 4.44772 10 5 10H9C9.55228 10 10 9.55229 10 9C10 8.44771 9.55228 8 9 8H5Z"
75-
fill="currentColor"
76-
/>
77-
</svg>
78-
</Menu.Button>
64+
/>
7965
<Menu.List>
8066
{options.map(option => (
8167
<Menu.Item onSelect={() => select(option)}>{option}</Menu.Item>

0 commit comments

Comments
 (0)