Skip to content

Commit 6afcd7a

Browse files
committed
Less janky mobile search animations
1 parent 586dc10 commit 6afcd7a

File tree

1 file changed

+126
-84
lines changed

1 file changed

+126
-84
lines changed

src/components/mobile-search.js

Lines changed: 126 additions & 84 deletions
Original file line numberDiff line numberDiff line change
@@ -9,114 +9,156 @@ import useSiteMetadata from '../hooks/use-site-metadata'
99
import {HEADER_BAR, HEADER_HEIGHT} from '../constants'
1010
import {LightTheme} from '../theme'
1111

12-
function MobileSearch({onDismiss, ...props}) {
12+
function MobileSearch({open, setOpen, ...props}) {
1313
const siteMetadata = useSiteMetadata()
14-
const {reset, results, isOpen, getInputProps, getItemProps, getMenuProps, highlightedIndex} = props
14+
const {reset, results, isOpen: resultsOpen, getInputProps, getItemProps, getMenuProps, highlightedIndex} = props
1515

1616
const handleDismiss = () => {
1717
reset()
18-
onDismiss()
18+
setOpen(false)
1919
}
2020

2121
return (
22-
<FocusOn returnFocus={true} onEscapeKey={handleDismiss}>
23-
<Box
24-
sx={{
25-
position: 'fixed',
26-
top: `${HEADER_BAR}px`,
27-
left: 0,
28-
right: 0,
29-
bottom: 0,
30-
zIndex: 1,
31-
}}
32-
>
33-
<Box
34-
sx={{
35-
position: 'absolute',
36-
top: 0,
37-
left: 0,
38-
right: 0,
39-
bottom: 0,
40-
bg: 'canvas.backdrop',
41-
zIndex: -1,
42-
}}
43-
as={motion.div}
44-
initial={{opacity: 0}}
45-
animate={{opacity: 1}}
46-
exit={{opacity: 0}}
47-
onClick={handleDismiss}
48-
/>
49-
<Box sx={{display: 'flex', flexDirection: 'column', height: isOpen ? '100%' : 'auto'}}>
22+
<AnimatePresence>
23+
{open ? (
24+
<FocusOn returnFocus={true} onEscapeKey={handleDismiss}>
5025
<Box
5126
sx={{
52-
display: 'flex',
53-
bg: 'canvas.default',
54-
color: 'fg.default',
55-
height: `${HEADER_HEIGHT}px`,
56-
flex: '0 0 auto',
57-
px: 3,
58-
alignItems: 'center',
59-
border: '1px solid',
60-
borderTopWidth: 0,
61-
borderLeftWidth: 0,
62-
borderRightWidth: 0,
63-
borderColor: 'border.muted',
27+
position: 'fixed',
28+
top: `${HEADER_BAR}px`,
29+
left: 0,
30+
right: 0,
31+
bottom: 0,
32+
zIndex: 1,
6433
}}
6534
>
66-
<motion.div
67-
initial={{scaleX: 0.1}}
68-
animate={{scaleX: 1}}
69-
exit={{scaleX: 0.1, transition: {duration: 0.1}}}
70-
transition={{type: 'tween', duration: 0.2}}
71-
style={{width: '100%', originX: '100%'}}
72-
>
73-
<TextInput
74-
leadingVisual={SearchIcon}
75-
placeholder={`Search ${siteMetadata.title}`}
76-
aria-label={`Search ${siteMetadata.title}`}
77-
sx={{width: '100%'}}
78-
{...getInputProps()}
79-
/>
80-
</motion.div>
81-
<Button sx={{ml: 3}} aria-label="Cancel" onClick={handleDismiss}>
82-
<XIcon />
83-
</Button>
84-
</Box>
85-
<LightTheme>
8635
<Box
8736
sx={{
88-
display: 'flex',
89-
bg: 'canvas.default',
90-
py: isOpen ? 1 : 0,
91-
flexDirection: 'column',
92-
flex: '1 1 auto',
93-
overflow: 'auto',
94-
}}
95-
style={{
96-
WebkitOverflowScrolling: 'touch',
37+
position: 'absolute',
38+
top: 0,
39+
left: 0,
40+
right: 0,
41+
bottom: 0,
42+
bg: 'overlay.backdrop',
43+
zIndex: -1,
9744
}}
98-
{...getMenuProps()}
99-
>
100-
{isOpen ? <SearchResults {...{results, getItemProps, highlightedIndex}} /> : null}
45+
key="search-backdrop"
46+
as={motion.div}
47+
initial={{opacity: 0}}
48+
animate={{opacity: 1}}
49+
exit={{opacity: 0}}
50+
transition={{type: 'tween'}}
51+
onClick={handleDismiss}
52+
/>
53+
<Box sx={{display: 'flex', flexDirection: 'column', height: resultsOpen ? '100%' : 'auto'}}>
54+
<Box
55+
sx={{
56+
display: 'flex',
57+
color: 'fg.default',
58+
height: `${HEADER_HEIGHT}px`,
59+
flex: '0 0 auto',
60+
px: 3,
61+
alignItems: 'center',
62+
border: '1px solid',
63+
borderTopWidth: 0,
64+
borderLeftWidth: 0,
65+
borderRightWidth: 0,
66+
borderColor: 'border.muted',
67+
position: 'relative',
68+
}}
69+
>
70+
<motion.div
71+
key="search-box"
72+
initial={{scaleX: 0}}
73+
animate={{scaleX: 1}}
74+
exit={{scaleX: 0}}
75+
transition={{type: 'tween', ease: 'easeOut', duration: 0.2}}
76+
style={{width: '100%', originX: '100%'}}
77+
>
78+
<Box
79+
sx={{
80+
position: 'absolute',
81+
top: 0,
82+
bottom: 0,
83+
left: 0,
84+
width: '70px',
85+
bg: 'canvas.default',
86+
zIndex: '-1',
87+
}}
88+
/>
89+
<TextInput
90+
leadingVisual={SearchIcon}
91+
placeholder={`Search ${siteMetadata.title}`}
92+
aria-label={`Search ${siteMetadata.title}`}
93+
sx={{width: '100%'}}
94+
{...getInputProps()}
95+
/>
96+
</motion.div>
97+
<Box
98+
key="button-blocker"
99+
as={motion.div}
100+
initial={{opacity: 0}}
101+
animate={{opacity: 1}}
102+
exit={{opacity: 0}}
103+
transition={{type: 'tween', ease: 'easeOut', duration: 0.2}}
104+
sx={{
105+
position: 'absolute',
106+
top: 0,
107+
bottom: 0,
108+
right: 0,
109+
width: '70px',
110+
bg: 'canvas.default',
111+
zIndex: '-1',
112+
}}
113+
/>
114+
<Box
115+
key="button"
116+
as={motion.div}
117+
initial={{opacity: 0}}
118+
animate={{opacity: 1}}
119+
exit={{opacity: 0}}
120+
transition={{type: 'tween', ease: 'easeOut', duration: 0.2}}
121+
>
122+
<Button sx={{ml: 3}} aria-label="Cancel" onClick={handleDismiss}>
123+
<XIcon />
124+
</Button>
125+
</Box>
126+
</Box>
127+
<LightTheme>
128+
<Box
129+
sx={{
130+
display: 'flex',
131+
bg: 'canvas.default',
132+
py: resultsOpen ? 1 : 0,
133+
flexDirection: 'column',
134+
flex: '1 1 auto',
135+
overflow: 'auto',
136+
}}
137+
style={{
138+
WebkitOverflowScrolling: 'touch',
139+
}}
140+
{...getMenuProps()}
141+
>
142+
{resultsOpen ? <SearchResults {...{results, getItemProps, highlightedIndex}} /> : null}
143+
</Box>
144+
</LightTheme>
101145
</Box>
102-
</LightTheme>
103-
</Box>
104-
</Box>
105-
</FocusOn>
146+
</Box>
147+
</FocusOn>
148+
) : null}
149+
</AnimatePresence>
106150
)
107151
}
108152

109153
function MobileSearchWrapper(props) {
110-
const [isOpen, setIsOpen] = React.useState(false)
154+
const [open, setOpen] = React.useState(false)
111155

112156
return (
113157
<>
114-
<Button aria-label="Search" aria-expanded={isOpen} onClick={() => setIsOpen(true)}>
158+
<Button aria-label="Search" aria-expanded={open} onClick={() => setOpen(true)}>
115159
<SearchIcon />
116160
</Button>
117-
<AnimatePresence>
118-
{isOpen ? <MobileSearch onDismiss={() => setIsOpen(false)} {...props} /> : null}
119-
</AnimatePresence>
161+
<MobileSearch open={open} setOpen={setOpen} {...props} />
120162
</>
121163
)
122164
}

0 commit comments

Comments
 (0)