import { Fragment, useContext, useEffect, useRef, useState } from 'react'; import styles from '@patternfly/react-styles/css/components/Tabs/tabs'; import { css } from '@patternfly/react-styles'; import RhMicronsCaretDownIcon from '@patternfly/react-icons/dist/esm/icons/rh-microns-caret-down-icon'; import { Popper, PopperOptions } from '../../helpers'; import { Menu, MenuContent, MenuList, MenuItem } from '../Menu'; import { TabsContext } from './TabsContext'; import { TabProps } from './Tab'; import { TabTitleText } from './TabTitleText'; /** @deprecated Use PopperOptions instead */ export type HorizontalOverflowPopperProps = PopperOptions; export interface OverflowTabProps extends React.HTMLProps { /** Additional classes added to the overflow tab */ className?: string; /** The tabs that should be displayed in the menu */ overflowingTabs?: TabProps[]; /** Flag which shows the count of overflowing tabs when enabled */ showTabCount?: boolean; /** The text which displays when an overflowing tab isn't selected */ defaultTitleText?: string; /** The aria label applied to the button which toggles the tab overflow menu */ toggleAriaLabel?: string; /** z-index of the overflow tab */ zIndex?: number; /** Flag indicating if scroll on focus of the first menu item should occur. */ shouldPreventScrollOnItemFocus?: boolean; /** Time in ms to wait before firing the toggles' focus event. Defaults to 0 */ focusTimeoutDelay?: number; /** Additional props to spread to the popper menu. */ popperProps?: PopperOptions; } export const OverflowTab: React.FunctionComponent = ({ className, overflowingTabs = [], showTabCount, defaultTitleText = 'More', toggleAriaLabel, zIndex = 9999, shouldPreventScrollOnItemFocus = true, focusTimeoutDelay = 0, popperProps, ...props }: OverflowTabProps) => { const menuRef = useRef(undefined); const overflowTabRef = useRef(undefined); const overflowLIRef = useRef(undefined); const [isExpanded, setIsExpanded] = useState(false); const { localActiveKey, handleTabClick } = useContext(TabsContext); const closeMenu = () => { setIsExpanded(false); overflowTabRef.current.focus(); }; const handleMenuKeys = (ev: KeyboardEvent) => { const menuContainsEventTarget = menuRef?.current?.contains(ev.target as Node); if (isExpanded && menuContainsEventTarget && ev.key === 'Escape') { closeMenu(); } }; const handleClick = (ev: MouseEvent) => { const clickIsOutsideMenu = !menuRef?.current?.contains(ev.target as Node); const clickIsOutsideOverflowTab = !overflowTabRef?.current?.contains(ev.target as Node); if (isExpanded && clickIsOutsideMenu && clickIsOutsideOverflowTab) { closeMenu(); } }; useEffect(() => { window.addEventListener('click', handleClick); window.addEventListener('keydown', handleMenuKeys); return () => { window.removeEventListener('click', handleClick); window.removeEventListener('keydown', handleMenuKeys); }; }, [isExpanded, menuRef, overflowTabRef]); const selectedTab = overflowingTabs.find((tab) => tab.eventKey === localActiveKey); const tabTitle = selectedTab?.title ? selectedTab.title : defaultTitleText; const toggleMenu = () => { setIsExpanded((prevIsExpanded) => !prevIsExpanded); setTimeout(() => { if (menuRef?.current) { const firstElement = menuRef.current.querySelector('li > button,input:not(:disabled)'); firstElement && (firstElement as HTMLElement).focus({ preventScroll: shouldPreventScrollOnItemFocus }); } }, focusTimeoutDelay); }; const overflowTab = (
  • ); const tabs = overflowingTabs.map((tab) => ( {tab.title} )); const onTabSelect = (event: React.MouseEvent, key: number | string) => { closeMenu(); const selectedTabRef = overflowingTabs.find((tab) => tab.eventKey === key).tabContentRef; handleTabClick(event, key, selectedTabRef); }; const overflowMenu = ( onTabSelect(ev as React.MouseEvent, itemId)}> {tabs} ); return ( {overflowTab} ); }; OverflowTab.displayName = 'OverflowTab';