summaryrefslogtreecommitdiffstats
path: root/src/components/Toolbar/Toolbar.tsx
diff options
context:
space:
mode:
authorArmand Philippot <git@armandphilippot.com>2022-01-14 11:42:34 +0100
committerArmand Philippot <git@armandphilippot.com>2022-01-14 11:42:34 +0100
commit88478d6b991de50582a6ef85781eed5f56d68dbb (patch)
tree0c00c3ad9b1ad1ecad0fbda1740e37dce360735b /src/components/Toolbar/Toolbar.tsx
parent010e2e68568b3894fcaefc1f7c735b810a29a5c4 (diff)
chore(toolbar): close modals on click/focus outside
Diffstat (limited to 'src/components/Toolbar/Toolbar.tsx')
-rw-r--r--src/components/Toolbar/Toolbar.tsx80
1 files changed, 77 insertions, 3 deletions
diff --git a/src/components/Toolbar/Toolbar.tsx b/src/components/Toolbar/Toolbar.tsx
index 771efa1..25418b1 100644
--- a/src/components/Toolbar/Toolbar.tsx
+++ b/src/components/Toolbar/Toolbar.tsx
@@ -2,13 +2,17 @@ import { ButtonToolbar } from '@components/Buttons';
import MainNav from '@components/MainNav/MainNav';
import SearchForm from '@components/SearchForm/SearchForm';
import Settings from '@components/Settings/Settings';
-import { useEffect, useState } from 'react';
+import { RefObject, useCallback, useEffect, useRef, useState } from 'react';
import styles from './Toolbar.module.scss';
const Toolbar = () => {
const [isNavOpened, setIsNavOpened] = useState<boolean>(false);
const [isSearchOpened, setIsSearchOpened] = useState<boolean>(false);
const [isSettingsOpened, setIsSettingsOpened] = useState<boolean>(false);
+ const searchBtnRef = useRef<HTMLButtonElement>(null);
+ const searchModalRef = useRef<HTMLDivElement>(null);
+ const settingsBtnRef = useRef<HTMLButtonElement>(null);
+ const settingsModalRef = useRef<HTMLDivElement>(null);
useEffect(() => {
if (isNavOpened) {
@@ -31,6 +35,70 @@ const Toolbar = () => {
}
}, [isSettingsOpened]);
+ const isClickOutside = (
+ ref: RefObject<HTMLDivElement>,
+ target: EventTarget
+ ) => {
+ const currentRef = ref.current;
+ return currentRef && !currentRef.contains(target as Node);
+ };
+
+ const isToggleBtn = (ref: RefObject<HTMLDivElement>, target: EventTarget) => {
+ const currentRef = ref.current;
+ return (
+ currentRef &&
+ currentRef.previousElementSibling &&
+ currentRef.previousElementSibling.contains(target as Node)
+ );
+ };
+
+ const isSearchBtn = useCallback((target: HTMLElement) => {
+ return (
+ target === searchBtnRef.current || searchBtnRef.current?.contains(target)
+ );
+ }, []);
+
+ const isSettingsBtn = useCallback((target: HTMLElement) => {
+ return (
+ target === settingsBtnRef.current ||
+ settingsBtnRef.current?.contains(target)
+ );
+ }, []);
+
+ const handleVisibility = useCallback(
+ (e: MouseEvent | FocusEvent) => {
+ let ref: RefObject<HTMLDivElement> | null = null;
+ if (isSearchOpened) ref = searchModalRef;
+ if (isSettingsOpened) ref = settingsModalRef;
+
+ if (!ref || !ref.current || !ref.current.id) return;
+ if (!isClickOutside(ref, e.target as Node)) return;
+ if (isToggleBtn(ref, e.target as Node)) return;
+
+ if (
+ ref.current.id === 'search-modal' &&
+ !isSettingsBtn(e.target as HTMLElement)
+ )
+ setIsSearchOpened(false);
+ if (
+ ref.current.id === 'settings-modal' &&
+ !isSearchBtn(e.target as HTMLElement)
+ )
+ setIsSettingsOpened(false);
+ },
+ [isSearchOpened, isSettingsOpened, isSearchBtn, isSettingsBtn]
+ );
+
+ useEffect(() => {
+ document.addEventListener('mousedown', handleVisibility);
+ document.addEventListener('focusin', handleVisibility);
+
+ return () => {
+ document.removeEventListener('mousedown', handleVisibility);
+ document.removeEventListener('focusin', handleVisibility);
+ };
+ }, [handleVisibility]);
+
const searchClasses = `${styles.menu} ${
isSearchOpened ? styles['menu--opened'] : styles['menu--closed']
}`;
@@ -43,19 +111,25 @@ const Toolbar = () => {
<div className={styles.wrapper}>
<MainNav isOpened={isNavOpened} setIsOpened={setIsNavOpened} />
<ButtonToolbar
+ ref={searchBtnRef}
type="search"
isActivated={isSearchOpened}
setIsActivated={setIsSearchOpened}
/>
- <div className={searchClasses}>
+ <div id="search-modal" className={searchClasses} ref={searchModalRef}>
<SearchForm isOpened={isSearchOpened} />
</div>
<ButtonToolbar
+ ref={settingsBtnRef}
type="settings"
isActivated={isSettingsOpened}
setIsActivated={setIsSettingsOpened}
/>
- <div className={settingsClasses}>
+ <div
+ id="settings-modal"
+ className={settingsClasses}
+ ref={settingsModalRef}
+ >
<Settings />
</div>
</div>