mirror of
https://github.com/vercel/commerce.git
synced 2025-05-18 23:46:58 +00:00
60 lines
1.4 KiB
TypeScript
60 lines
1.4 KiB
TypeScript
import React, { useRef, useEffect, MouseEvent, ReactElement } from 'react'
|
|
import mergeRefs from 'react-merge-refs'
|
|
import hasParent from './has-parent'
|
|
|
|
interface ClickOutsideProps {
|
|
active: boolean
|
|
onClick: (e?: MouseEvent) => void
|
|
children: any
|
|
}
|
|
|
|
const ClickOutside = ({
|
|
active = true,
|
|
onClick,
|
|
children,
|
|
}: ClickOutsideProps) => {
|
|
const innerRef = useRef()
|
|
const child = children ? React.Children.only(children) : undefined
|
|
if (!child) {
|
|
throw new Error('A valid non Fragment React Children should be provided')
|
|
}
|
|
|
|
useEffect(() => {
|
|
if (active) {
|
|
document.addEventListener('mousedown', handleClick)
|
|
document.addEventListener('touchstart', handleClick)
|
|
}
|
|
|
|
return () => {
|
|
if (active) {
|
|
document.removeEventListener('mousedown', handleClick)
|
|
document.removeEventListener('touchstart', handleClick)
|
|
}
|
|
}
|
|
})
|
|
|
|
const handleClick = (event: any) => {
|
|
if (!hasParent(event.target, innerRef?.current)) {
|
|
if (typeof onClick === 'function') {
|
|
onClick(event)
|
|
}
|
|
}
|
|
}
|
|
|
|
const composedRefCallback = (element: ReactElement) => {
|
|
if (child) {
|
|
if (typeof child.ref === 'function') {
|
|
child.ref(element)
|
|
} else if (child.ref) {
|
|
child.ref.current = element
|
|
}
|
|
}
|
|
}
|
|
|
|
return React.cloneElement(child, {
|
|
ref: mergeRefs([composedRefCallback, innerRef]),
|
|
})
|
|
}
|
|
|
|
export default ClickOutside
|