46 lines
1.3 KiB
TypeScript
46 lines
1.3 KiB
TypeScript
import { useEffect, useRef, useState } from 'react';
|
|
import conditionalClass from '../../../lib/utils/conditional-class';
|
|
import styles from './Dropdown.module.scss';
|
|
|
|
export const Dropdown = ({
|
|
children,
|
|
opens = 'left',
|
|
}: {
|
|
children: React.ReactNode;
|
|
opens?: 'right' | 'left';
|
|
}) => {
|
|
const [visible, setVisible] = useState(false);
|
|
const ref = useRef<HTMLDivElement>(null);
|
|
|
|
// Off click listener
|
|
useEffect(() => {
|
|
if (!visible || !ref) return;
|
|
|
|
function handleClickOutside(event: MouseEvent | TouchEvent) {
|
|
if (ref.current && !ref.current.contains(event.target as HTMLElement)) {
|
|
setVisible(false);
|
|
}
|
|
}
|
|
|
|
document.addEventListener('mousedown', handleClickOutside);
|
|
document.addEventListener('touchstart', handleClickOutside);
|
|
return () => {
|
|
document.removeEventListener('mousedown', handleClickOutside);
|
|
document.removeEventListener('touchstart', handleClickOutside);
|
|
};
|
|
}, [ref, visible]);
|
|
|
|
return (
|
|
<div className={[styles.wrapper, styles[opens]].join(' ')} ref={ref}>
|
|
<button
|
|
className={[
|
|
styles.toggle,
|
|
conditionalClass(visible, styles.active),
|
|
].join(' ')}
|
|
onClick={() => setVisible(!visible)}
|
|
></button>
|
|
{visible && <div className={styles.dropdown}>{children}</div>}
|
|
</div>
|
|
);
|
|
};
|