import { ArrowDropDown } from '@mui/icons-material' import clsx from 'clsx' import { MouseEventHandler, ReactNode, forwardRef, useEffect, useRef, useState, } from 'react' import { createPortal } from 'react-dom' import { useTranslation } from 'react-i18next' import { SegmentedControlsProps } from '@dao-dao/types' import { useTrackDropdown } from '../../hooks/useTrackDropdown' import { Button } from '../buttons' import { Tooltip } from '../tooltip' export const SegmentedControls = ({ tabs, selected, onSelect, loading, className, disabled, noWrap, moreTabs, }: SegmentedControlsProps) => { const { t } = useTranslation() const [hoveringIndex, setHoveringIndex] = useState() let selectedIndex = tabs.findIndex((tab) => tab.value === selected) const selectedMoreTabIndex = moreTabs?.findIndex((tab) => tab.value === selected) ?? -1 // If the selected tab is in the more tabs, then select the last tab, which is // the More dropdown. if (selectedIndex === -1 && selectedMoreTabIndex !== -1) { selectedIndex = tabs.length } const moreTabRef = useRef(null) const [moreOpen, setMoreOpen] = useState(false) // Listen for click not in dropdown bounds, and close if so. Adds listener // only when the dropdown is open. useEffect(() => { // Don't do anything if not on browser or dropdown is not open. // If open is switched off, the useEffect will remove the listener and then // not-readd it. if (typeof window === 'undefined' || !moreOpen) { return } const closeIfClickOutside = (event: MouseEvent) => { // If clicked on an element that is not a descendant of this Dropdown's // outermost container, close the dropdown. if ( event.target instanceof Node && !moreTabRef.current?.contains(event.target) ) { setMoreOpen(false) } } window.addEventListener('click', closeIfClickOutside) return () => window.removeEventListener('click', closeIfClickOutside) }, [moreOpen]) // Track button to position the dropdown. const { onDropdownRef, onTrackRef } = useTrackDropdown() return (
setHoveringIndex(undefined)} > {tabs.map(({ label, value, tooltip, disabled }, index) => ( onSelect(value, e)} onMouseOver={() => setHoveringIndex(index)} selectedIndex={selectedIndex} tooltip={tooltip} > {label} ))} {!!moreTabs?.length && ( <> loading === value)} noWrap={noWrap} onClick={() => setMoreOpen((o) => !o)} onMouseOver={() => setHoveringIndex(tabs.length)} ref={(ref) => { moreTabRef.current = ref onTrackRef(ref) }} selectedIndex={moreOpen ? tabs.length : selectedIndex} >

{selectedMoreTabIndex === -1 ? t('button.more') : moreTabs[selectedMoreTabIndex].label}

{/* Dropdown */} {createPortal(
{moreTabs.map(({ label, value, tooltip, disabled }, index) => ( ))}
, document.body )} )}
) } type TabProps = { children: ReactNode | ReactNode[] index: number hoveringIndex: number | undefined selectedIndex: number loading: boolean onClick: MouseEventHandler onMouseOver: () => void noWrap?: boolean buttonClassName?: string buttonContentContainerClassName?: string tooltip?: NonNullable disabled?: boolean } const Tab = forwardRef(function Tab( { children, index, hoveringIndex, selectedIndex, loading, onClick, onMouseOver, noWrap, buttonClassName, buttonContentContainerClassName, tooltip, disabled, }, ref ) { return (
{/* Don't render left border for the first element. */} {index > 0 && (
)}
{/* Sliding selection indicator. It matches the width of the first button and offsets based on the selection index. */} {index === 0 && selectedIndex > -1 && (
)}
) })