mirror of
https://github.com/vercel/commerce.git
synced 2025-03-14 14:42:31 +00:00
Adding Click Outside
This commit is contained in:
parent
c37ed3d418
commit
6020d5cfd2
@ -1,9 +1,10 @@
|
||||
import cn from 'classnames'
|
||||
import Link from 'next/link'
|
||||
import { FC, useState } from 'react'
|
||||
import { useRef, FC, useState } from 'react'
|
||||
import { useRouter } from 'next/router'
|
||||
import s from './I18nWidget.module.css'
|
||||
import { Cross, ChevronUp } from '@components/icons'
|
||||
import ClickOutside from '@lib/click-outside'
|
||||
interface LOCALE_DATA {
|
||||
name: string
|
||||
img: {
|
||||
@ -37,55 +38,62 @@ const I18nWidget: FC = () => {
|
||||
defaultLocale = 'en-US',
|
||||
asPath: currentPath,
|
||||
} = useRouter()
|
||||
|
||||
const options = locales?.filter((val) => val !== locale)
|
||||
const currentLocale = locale || defaultLocale
|
||||
const ref = useRef<HTMLDivElement | null>(null)
|
||||
|
||||
return (
|
||||
<nav className={s.root}>
|
||||
<div className="flex items-center relative">
|
||||
<button className={s.button} aria-label="Language selector">
|
||||
<img
|
||||
className="block mr-2 w-5"
|
||||
src={`/${LOCALES_MAP[currentLocale].img.filename}`}
|
||||
alt={LOCALES_MAP[currentLocale].img.alt}
|
||||
/>
|
||||
{options && (
|
||||
<span
|
||||
className="cursor-pointer"
|
||||
onClick={() => setDisplay(!display)}
|
||||
>
|
||||
<ChevronUp className={cn({ [s.icon]: display })} />
|
||||
</span>
|
||||
)}
|
||||
</button>
|
||||
</div>
|
||||
<div className="absolute top-0 right-0">
|
||||
{options?.length && display ? (
|
||||
<div className={s.dropdownMenu}>
|
||||
<div className="flex flex-row justify-end px-6">
|
||||
<button
|
||||
onClick={() => setDisplay(false)}
|
||||
aria-label="Close panel"
|
||||
className={s.closeButton}
|
||||
>
|
||||
<Cross className="h-6 w-6" />
|
||||
</button>
|
||||
<ClickOutside active={display} onClick={() => setDisplay(false)} ref={ref}>
|
||||
<nav className={s.root}>
|
||||
<div
|
||||
className="flex items-center relative"
|
||||
onClick={() => setDisplay(!display)}
|
||||
>
|
||||
<button className={s.button} aria-label="Language selector">
|
||||
<img
|
||||
className="block mr-2 w-5"
|
||||
src={`/${LOCALES_MAP[currentLocale].img.filename}`}
|
||||
alt={LOCALES_MAP[currentLocale].img.alt}
|
||||
/>
|
||||
{options && (
|
||||
<span className="cursor-pointer">
|
||||
<ChevronUp className={cn({ [s.icon]: display })} />
|
||||
</span>
|
||||
)}
|
||||
</button>
|
||||
</div>
|
||||
<div className="absolute top-0 right-0">
|
||||
{options?.length && display ? (
|
||||
<div className={s.dropdownMenu}>
|
||||
<div className="flex flex-row justify-end px-6">
|
||||
<button
|
||||
onClick={() => setDisplay(false)}
|
||||
aria-label="Close panel"
|
||||
className={s.closeButton}
|
||||
>
|
||||
<Cross className="h-6 w-6" />
|
||||
</button>
|
||||
</div>
|
||||
<ul>
|
||||
{options.map((locale) => (
|
||||
<li key={locale}>
|
||||
<Link href={currentPath} locale={locale}>
|
||||
<a
|
||||
className={cn(s.item)}
|
||||
onClick={() => setDisplay(false)}
|
||||
>
|
||||
{LOCALES_MAP[locale].name}
|
||||
</a>
|
||||
</Link>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
</div>
|
||||
<ul>
|
||||
{options.map((locale) => (
|
||||
<li key={locale}>
|
||||
<Link href={currentPath} locale={locale}>
|
||||
<a className={cn(s.item)} onClick={() => setDisplay(false)}>
|
||||
{LOCALES_MAP[locale].name}
|
||||
</a>
|
||||
</Link>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
</div>
|
||||
) : null}
|
||||
</div>
|
||||
</nav>
|
||||
) : null}
|
||||
</div>
|
||||
</nav>
|
||||
</ClickOutside>
|
||||
)
|
||||
}
|
||||
|
||||
|
45
lib/click-outside/click-outside.tsx
Normal file
45
lib/click-outside/click-outside.tsx
Normal file
@ -0,0 +1,45 @@
|
||||
import React, { forwardRef, useEffect, Ref, MouseEvent } from 'react'
|
||||
import hasParent from './has-parent'
|
||||
|
||||
interface ClickOutsideProps {
|
||||
active: boolean
|
||||
onClick: (e?: MouseEvent) => void
|
||||
children: any
|
||||
}
|
||||
|
||||
const ClickOutside = (
|
||||
{ active = true, onClick, children }: ClickOutsideProps,
|
||||
ref: Ref<HTMLDivElement> | null | any = {}
|
||||
) => {
|
||||
console.log('--------', active, '-----------')
|
||||
const innerRef = ref?.current
|
||||
|
||||
const handleClick = (event: any) => {
|
||||
console.log(innerRef, event.target)
|
||||
if (!hasParent(event.target, innerRef)) {
|
||||
if (typeof onClick === 'function') {
|
||||
event.preventDefault()
|
||||
event.stopImmediatePropagation()
|
||||
onClick(event)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
if (active) {
|
||||
document.addEventListener('mousedown', handleClick)
|
||||
document.addEventListener('touchstart', handleClick)
|
||||
}
|
||||
|
||||
return () => {
|
||||
if (active) {
|
||||
document.removeEventListener('mousedown', handleClick)
|
||||
document.removeEventListener('touchstart', handleClick)
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
return React.cloneElement(children, { ref })
|
||||
}
|
||||
|
||||
export default forwardRef(ClickOutside)
|
5
lib/click-outside/has-parent.js
Normal file
5
lib/click-outside/has-parent.js
Normal file
@ -0,0 +1,5 @@
|
||||
import isInDOM from './is-in-dom'
|
||||
|
||||
export default function hasParent(element, root) {
|
||||
return root && root.contains(element) && isInDOM(element)
|
||||
}
|
1
lib/click-outside/index.ts
Normal file
1
lib/click-outside/index.ts
Normal file
@ -0,0 +1 @@
|
||||
export { default } from './click-outside'
|
3
lib/click-outside/is-in-dom.js
Normal file
3
lib/click-outside/is-in-dom.js
Normal file
@ -0,0 +1,3 @@
|
||||
export default function isInDom(obj) {
|
||||
return Boolean(obj.closest('body'))
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user