diff options
Diffstat (limited to 'src/components/Toolbar/Toolbar.tsx')
| -rw-r--r-- | src/components/Toolbar/Toolbar.tsx | 80 |
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> |
