import classNames from 'classnames' import { type MouseEventHandler, useCallback, useEffect, useLayoutEffect, useState, } from 'react' interface TabSetProps { tabs: TabType[] tabTitles: Record activeTab: TabType onTabChange: (tab: TabType) => void } interface HighlightStyle { left: number width: number } export function TabSet({ tabs, tabTitles, activeTab, onTabChange, }: TabSetProps): JSX.Element { const [highlightStyle, setHighlightStyle] = useState({ left: 0, width: 140, }) const calculateHighlightStyle = useCallback(() => { const tabButton: HTMLButtonElement | null = globalThis.document?.querySelector( `.seam-tab-button:nth-of-type(${tabs.indexOf(activeTab) + 1})` ) setHighlightStyle({ left: tabButton?.offsetLeft ?? 0, width: tabButton?.offsetWidth ?? 140, }) }, [activeTab, tabs]) useLayoutEffect(() => { calculateHighlightStyle() }, [activeTab, calculateHighlightStyle]) useEffect(() => { globalThis.addEventListener?.('resize', calculateHighlightStyle) return () => { globalThis.removeEventListener?.('resize', calculateHighlightStyle) } }, [calculateHighlightStyle]) return (
{tabs.map((tab) => ( key={tab} tab={tab} title={tabTitles[tab]} isActive={activeTab === tab} onTabChange={onTabChange} setHighlightStyle={setHighlightStyle} /> ))}
) } interface TabButtonProps { tab: TabType title: string isActive: boolean onTabChange: (tab: TabType) => void setHighlightStyle: (style: HighlightStyle) => void } function TabButton({ tab, title, isActive, onTabChange, setHighlightStyle, }: TabButtonProps): JSX.Element { const handleClick: MouseEventHandler = (ev) => { onTabChange(tab) setHighlightStyle({ left: ev.currentTarget.offsetLeft, width: ev.currentTarget.offsetWidth, }) } return ( ) }