/* eslint-disable react-hooks/exhaustive-deps */ import { useRef, useState, useCallback, useMemo } from 'react'; export interface UseTogglableTabInterface { toggleProperty: string; singleOpen?: boolean; toggleOpenClose?: boolean; toggleParentOpen?: boolean; onToggleProperty: string; initial?: Record; firstOpen?: boolean; ariaNavigation?: boolean; toggleHook?: (id: string) => void; } export interface UseTogglableTabReturn { register: (el: string) => any; registered: { current: Record }; opened: Record; toggle: (id: string) => void; setOpened: ( opened: | ((curOpened: Record) => Record) | Record ) => void; } export function useTogglableTab({ toggleProperty, singleOpen, onToggleProperty, initial, firstOpen, ariaNavigation, toggleHook, }: UseTogglableTabInterface): UseTogglableTabReturn { const [opened, setOpened] = useState(initial || {}); const registered = useRef>({}); const sectionsOrder = useRef([]); const registerRef = useCallback((el) => { if (!el) return; const key = el.getAttribute('aria-controls') as string; if (registered.current[key]) return; registered.current[key] = el; sectionsOrder.current.push(key); if (firstOpen && sectionsOrder.current.length === 1) { setOpened({ [key]: true, }); } }, []); const toggle = useCallback((e) => { const key = e.currentTarget.getAttribute('aria-controls') as string; if (toggleHook) { toggleHook(key); } e.preventDefault(); if (singleOpen) { setOpened({ [key]: true }); } else { setOpened((prev) => ({ ...prev, [key]: !prev[key] })); } }, []); const onKeyDown = useCallback((e) => { const key = e.target.getAttribute('aria-controls'); const currentIndex = sectionsOrder.current.findIndex((k) => k === key); const nextKey = sectionsOrder.current[currentIndex + 1]; const previousKey = sectionsOrder.current[currentIndex - 1]; switch (e.key) { case 'ArrowRight': case 'ArrowDown': if (nextKey) { registered.current[nextKey].focus(); } break; case 'ArrowLeft': case 'ArrowUp': if (previousKey) { registered.current[previousKey].focus(); } break; case ' ': case 'Enter': toggle(e); break; } }, []); const register = useCallback( (key) => { const isOpen = !!opened[key]; return { ref: registerRef, [toggleProperty]: isOpen, [onToggleProperty]: toggle, 'aria-controls': `${key}`, ...(ariaNavigation && { onKeyDown, tabIndex: opened[key] ? 0 : -1 }), }; }, [opened] ); return useMemo( () => ({ register, registered, opened, toggle, setOpened, }), [opened] ); }