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

fix(backdrop): fix click events from content to close modal unexpectedly #265

Merged
merged 2 commits into from
Jun 9, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 25 additions & 0 deletions components/shared/__tests__/backdrop.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -74,4 +74,29 @@ describe('Backdrop', () => {
expect(wrapper.html()).toMatchSnapshot()
expect(notOffset).not.toEqual(wrapper.html())
})

it('backdrop handler should ignore click events from content', async () => {
const handler = jest.fn()
const wrapper = mount(
<Backdrop visible onClick={handler}>
<span>test-value</span>
</Backdrop>,
)

/**
* In simulation,`mousedown` and `mouseup`not directly triiger `click` event,
* the click event below is just for simulation.
*/
wrapper.find('.content').simulate('mousedown')
wrapper.find('.backdrop').simulate('click', nativeEvent)
wrapper.find('.backdrop').simulate('mouseup')
await updateWrapper(wrapper)
expect(handler).not.toHaveBeenCalled()

wrapper.find('.backdrop').simulate('mousedown')
wrapper.find('.backdrop').simulate('click', nativeEvent)
wrapper.find('.backdrop').simulate('mouseup')
await updateWrapper(wrapper)
expect(handler).toHaveBeenCalled()
})
})
21 changes: 17 additions & 4 deletions components/shared/backdrop.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import React, { MouseEvent, useCallback } from 'react'
import withDefaults from '../utils/with-defaults'
import useTheme from '../styles/use-theme'
import CSSTransition from './css-transition'
import useCurrentState from '../utils/use-current-state'

interface Props {
onClick?: (event: MouseEvent<HTMLElement>) => void
Expand All @@ -20,18 +21,30 @@ export type BackdropProps = Props & typeof defaultProps
const Backdrop: React.FC<React.PropsWithChildren<BackdropProps>> = React.memo(
({ children, onClick, visible, offsetY }) => {
const theme = useTheme()
const clickHandler = useCallback((event: MouseEvent<HTMLElement>) => {
const [, setIsContentMouseDown, IsContentMouseDownRef] = useCurrentState(false)
const clickHandler = (event: MouseEvent<HTMLElement>) => {
if (IsContentMouseDownRef.current) return
onClick && onClick(event)
}, [])
}
const childrenClickHandler = useCallback((event: MouseEvent<HTMLElement>) => {
event.stopPropagation()
}, [])
const mouseUpHandler = () => {
if (!IsContentMouseDownRef.current) return
const timer = setTimeout(() => {
setIsContentMouseDown(false)
clearTimeout(timer)
}, 0)
}

return (
<CSSTransition visible={visible} clearTime={300}>
<div className="backdrop" onClick={clickHandler}>
<div className="backdrop" onClick={clickHandler} onMouseUp={mouseUpHandler}>
<div className="layer" />
<div onClick={childrenClickHandler} className="content">
<div
onClick={childrenClickHandler}
className="content"
onMouseDown={() => setIsContentMouseDown(true)}>
{children}
</div>
<div onClick={childrenClickHandler} className="offset" />
Expand Down