Add useClickOutside hook for Floating UI elements

environments/review-fix-dropdo-shg56a/deployments/2544
Alex Gleason 2 years ago
parent ec7f9b9950
commit dc597ac765
No known key found for this signature in database
GPG Key ID: 7211D1F99744FBB7

@ -8,7 +8,7 @@ import { Link } from 'react-router-dom';
import { fetchOwnAccounts, logOut, switchAccount } from 'soapbox/actions/auth';
import Account from 'soapbox/components/account';
import { MenuDivider } from 'soapbox/components/ui';
import { useAppDispatch, useAppSelector, useFeatures } from 'soapbox/hooks';
import { useAppDispatch, useAppSelector, useClickOutside, useFeatures } from 'soapbox/hooks';
import { makeGetAccount } from 'soapbox/selectors';
import ThemeToggle from './theme-toggle';
@ -102,29 +102,13 @@ const ProfileDropdown: React.FC<IProfileDropdown> = ({ account, children }) => {
const toggleVisible = () => setVisible(!visible);
const handleWindowClick = (e: MouseEvent) => {
if (e.target) {
const clickWithin = [
refs.floating.current?.contains(e.target as Node),
(refs.reference.current as HTMLButtonElement | undefined)?.contains(e.target as Node),
].some(Boolean);
if (!clickWithin) {
setVisible(false);
}
}
};
useEffect(() => {
fetchOwnAccountThrottled();
}, [account, authUsers]);
useEffect(() => {
window.addEventListener('click', handleWindowClick);
return () => {
window.removeEventListener('click', handleWindowClick);
};
}, []);
useClickOutside(refs, () => {
setVisible(false);
});
return (
<>

@ -2,6 +2,7 @@ export { useAccount } from './useAccount';
export { useApi } from './useApi';
export { useAppDispatch } from './useAppDispatch';
export { useAppSelector } from './useAppSelector';
export { useClickOutside } from './useClickOutside';
export { useCompose } from './useCompose';
export { useDebounce } from './useDebounce';
export { useDimensions } from './useDimensions';

@ -0,0 +1,29 @@
import { ExtendedRefs } from '@floating-ui/react';
import { useCallback, useEffect } from 'react';
/** Trigger `callback` when a Floating UI element is clicked outside from. */
export const useClickOutside = <T extends HTMLElement>(
refs: ExtendedRefs<T>,
callback: (e: MouseEvent) => void,
) => {
const handleWindowClick = useCallback((e: MouseEvent) => {
if (e.target) {
const target = e.target as Node;
const floating = refs.floating.current;
const reference = refs.reference.current as T | undefined;
if (!(floating?.contains(target) || reference?.contains(target))) {
callback(e);
}
}
}, [refs.floating.current, refs.reference.current]);
useEffect(() => {
window.addEventListener('click', handleWindowClick);
return () => {
window.removeEventListener('click', handleWindowClick);
};
}, []);
};
Loading…
Cancel
Save