Skip to content

Instantly share code, notes, and snippets.

@brandonkal
Created May 25, 2019 06:33
Show Gist options
  • Save brandonkal/088da2bf362cf23df58cb9e1f9c263ab to your computer and use it in GitHub Desktop.
Save brandonkal/088da2bf362cf23df58cb9e1f9c263ab to your computer and use it in GitHub Desktop.
useFocusTrap bug
import React from 'react'
import { storiesOf } from '@storybook/react'
// import '../../global.css'
// Mock out Button:
// import Button from '../Button'
import styled from '@emotion/styled'
const Button = styled.button``
import Drawer, { Directions } from './Drawer'
function Demo() {
const [isOpen, setOpen] = React.useState(false)
const [direction, setDirection] = React.useState<Directions>('e')
const toggleDirection = () => {
const directions: Directions[] = ['n', 's', 'e', 'w']
let index = directions.indexOf(direction)
index += 1
if (!directions[index]) index = 0
setDirection(directions[index])
}
const handleClick = () => {
return setOpen(!isOpen)
}
React.useEffect(() => {
function handleEsc(event: any) {
console.log('Checking for escape key in demo')
if (event.key === 'Escape') {
setOpen(!isOpen)
}
}
document.addEventListener('keydown', handleEsc)
return () => {
document.removeEventListener('keydown', handleEsc)
}
}, [isOpen])
return (
<>
<p>{isOpen ? 'Opened' : 'Closed'}</p>
<Button onClick={handleClick}>Open Drawer</Button>
<input />
<br />
<Button onClick={toggleDirection}>Toggle Direction</Button>
{direction.toUpperCase()}
<Drawer
isOpen={isOpen}
position={direction}
style={{
width: '50vw',
}}
>
<>
<input id="first" />
<input />
<p style={{ padding: '3rem' }}>
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed nonne
merninisti licere mihi ista probare, quae sunt a te dicta? Refert
tamen, quo modo.
</p>
</>
</Drawer>
</>
)
}
storiesOf('Drawer', module).add('Basic', () => <Demo />)
import React from 'react'
import { animated, useSpring, SpringConfig } from 'react-spring'
import { Portal } from '../Portal'
import useFocusTrap from '@charlietango/use-focus-trap'
import { RemoveScroll } from 'react-remove-scroll'
import { css } from '@emotion/core'
export type Directions = 'n' | 's' | 'e' | 'w'
interface DrawerProps {
style?: any
/** Whether the sheet is visible */
isOpen: boolean
/** A callback to handle closing the sheet */
onRequestClose?: () => void
role?: string
children: React.ReactNode
/**
* The compass position of the sheet.
* 'w' is typically used for navigation,
* 'e' for additional information,
* 's' for responsive modal popovers.
*/
position?: Directions
closeOnClick?: boolean
/** spring animation configuration */
animationConfig?: SpringConfig
}
export const Drawer = ({
isOpen,
children,
role = 'document',
closeOnClick = true,
animationConfig = { mass: 0.8, tension: 185, friction: 24 },
position = 'e',
onRequestClose,
...props
}: DrawerProps) => {
const ref = useFocusTrap(isOpen)
const isNegative = position === 'w' || position === 'n'
const isSide = position === 'e' || position === 'w'
const opacity = useSpring({
opacity: isOpen ? 1 : 0,
})
// A spring which animates the sheet position
const { percent } = useSpring({
percent: [isOpen ? 0 : isNegative ? -100 : 100],
config: animationConfig,
})
return (
<Portal>
<div
aria-hidden={!isOpen}
// onKeyDown={(e: React.KeyboardEvent) => {
// if (e.key === 'Escape') {
// e.stopPropagation()
// onRequestClose && onRequestClose()
// }
// }}
css={{
bottom: 0,
left: 0,
overflow: 'auto',
width: '100vw',
height: '100vh',
pointerEvents: isOpen ? 'auto' : 'none',
zIndex: 999,
position: 'fixed',
content: "''",
right: 0,
top: 0,
WebkitTapHighlightColor: 'transparent',
}}
>
<animated.div
css={{
touchAction: 'none',
position: 'absolute',
willChange: 'opacity',
top: 0,
left: 0,
pointerEvents: isOpen ? 'auto' : 'none',
right: 0,
bottom: 0,
background: 'rgba(33, 37, 41, 0.6) none repeat scroll 0% 0%',
}}
style={opacity}
/>
<animated.div
tabIndex={-1}
ref={ref}
className="Sheet"
onClick={e => {
e.stopPropagation()
}}
css={css`
will-change: transform;
outline: none;
z-index: 10;
opacity: 1;
/* max-width: 50vw; */
position: fixed;
top: ${position !== 's' && 0};
bottom: ${position !== 'n' && 0};
left: ${position === 'w' && 0};
right: ${position === 'e' && 0};
height: ${isSide ? '100vh' : 'auto'};
width: ${!isSide && '100%'};
`}
style={{
visibility: opacity.opacity.interpolate(o =>
o === 0 ? 'hidden' : 'visible'
),
transform: percent.interpolate(percent => {
return isSide
? `translate3d(${percent}%, 0, 0)`
: `translate3d(0, ${percent}%, 0)`
}),
}}
// {...props}
>
{/* <RequestCloseContext.Provider value={onRequestClose}> */}
<RemoveScroll enabled={isOpen} forwardProps>
<div
className="Sheet__container"
css={{
background: 'white none repeat scroll 0% 0%',
height: '100%',
}}
>
{children}
</div>
</RemoveScroll>
{/* </RequestCloseContext.Provider> */}
</animated.div>
</div>
</Portal>
)
}
export default Drawer
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment