import { ButtonToolbar } from '@components/Buttons'; import MainNav from '@components/MainNav/MainNav'; import Spinner from '@components/Spinner/Spinner'; import dynamic from 'next/dynamic'; import { RefObject, useCallback, useEffect, useRef, useState } from 'react'; import styles from './Toolbar.module.scss'; const DynamicSearchForm = dynamic( () => import('@components/SearchForm/SearchForm'), { loading: () => , } ); const DynamicSettings = dynamic(() => import('@components/Settings/Settings'), { loading: () => , }); const Toolbar = () => { const [isNavOpened, setIsNavOpened] = useState(false); const [isSearchOpened, setIsSearchOpened] = useState(false); const [isSettingsOpened, setIsSettingsOpened] = useState(false); const mainNavRef = useRef(null); const searchBtnRef = useRef(null); const searchModalRef = useRef(null); const settingsBtnRef = useRef(null); const settingsModalRef = useRef(null); useEffect(() => { if (isNavOpened) { setIsSearchOpened(false); setIsSettingsOpened(false); } }, [isNavOpened]); useEffect(() => { if (isSearchOpened) { setIsNavOpened(false); setIsSettingsOpened(false); } }, [isSearchOpened]); useEffect(() => { if (isSettingsOpened) { setIsNavOpened(false); setIsSearchOpened(false); } }, [isSettingsOpened]); const isClickOutside = ( ref: RefObject, target: EventTarget ) => { return ref.current && !ref.current.contains(target as Node); }; const isToggleBtn = (ref: RefObject, target: EventTarget) => { return ( ref.current && ref.current.previousElementSibling && ref.current.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 | null = null; if (isNavOpened) ref = mainNavRef; 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 === 'main-nav' && !isSettingsBtn(e.target as HTMLElement) && !isSearchBtn(e.target as HTMLElement) ) { setIsNavOpened(false); } 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); }, [isNavOpened, 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'] }`; const settingsClasses = `${styles.menu} ${ isSettingsOpened ? styles['menu--opened'] : styles['menu--closed'] }`; return (
); }; export default Toolbar; f='#n24'>24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40
import { storageKey as ackeeStorageKey } from '@components/molecules/forms/ackee-toggle.fixture';
import { storageKey as motionStorageKey } from '@components/molecules/forms/motion-toggle.fixture';
import { render, screen } from '@tests/utils';
import SettingsModal from './settings-modal';

describe('SettingsModal', () => {
  it('renders the modal heading', () => {
    render(
      <SettingsModal
        ackeeStorageKey={ackeeStorageKey}
        motionStorageKey={motionStorageKey}
      />
    );
    expect(screen.getByText(/Settings/i)).toBeInTheDocument();
  });

  it('renders a settings form', () => {
    render(
      <SettingsModal
        ackeeStorageKey={ackeeStorageKey}
        motionStorageKey={motionStorageKey}
      />
    );
    expect(
      screen.getByRole('form', { name: /^Settings form/i })
    ).toBeInTheDocument();
    expect(
      screen.getByRole('radiogroup', { name: /^Theme:/i })
    ).toBeInTheDocument();
    expect(
      screen.getByRole('radiogroup', { name: /^Code blocks:/i })
    ).toBeInTheDocument();
    expect(
      screen.getByRole('radiogroup', { name: /^Animations:/i })
    ).toBeInTheDocument();
    expect(
      screen.getByRole('radiogroup', { name: /^Tracking:/i })
    ).toBeInTheDocument();
  });
});