/* ============================================================================ * Copyright (c) Palo Alto Networks * * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * ========================================================================== */ import React, { cloneElement, useRef, useState, useEffect, ReactElement, } from "react"; import { sanitizeTabsChildren, type TabItemProps, TabProps, TabsProvider, useScrollPositionBlocker, useTabsContextValue, } from "@docusaurus/theme-common/internal"; import { translate } from "@docusaurus/Translate"; import useIsBrowser from "@docusaurus/useIsBrowser"; import Heading from "@theme/Heading"; import { OPENAPI_TABS } from "@theme/translationIds"; import clsx from "clsx"; export interface TabListProps extends TabProps { label: string; id: string; } function TabList({ className, block, selectedValue, selectValue, tabValues, label = translate({ id: OPENAPI_TABS.RESPONSES_LABEL, message: "Responses", }), id = "responses", }: TabListProps & ReturnType) { const tabRefs: (HTMLLIElement | null)[] = []; const { blockElementScrollPositionUntilNextRender } = useScrollPositionBlocker(); const handleTabChange = ( event: | React.FocusEvent | React.MouseEvent | React.KeyboardEvent ) => { const newTab = event.currentTarget; const newTabIndex = tabRefs.indexOf(newTab); const newTabValue = tabValues[newTabIndex].value; if (newTabValue !== selectedValue) { blockElementScrollPositionUntilNextRender(newTab); selectValue(newTabValue); } }; const handleKeydown = (event: React.KeyboardEvent) => { let focusElement: HTMLLIElement | null = null; switch (event.key) { case "Enter": { handleTabChange(event); break; } case "ArrowRight": { const nextTab = tabRefs.indexOf(event.currentTarget) + 1; focusElement = tabRefs[nextTab] ?? tabRefs[0]!; break; } case "ArrowLeft": { const prevTab = tabRefs.indexOf(event.currentTarget) - 1; focusElement = tabRefs[prevTab] ?? tabRefs[tabRefs.length - 1]!; break; } default: break; } focusElement?.focus(); }; const tabItemListContainerRef = useRef(null); const [showTabArrows, setShowTabArrows] = useState(false); useEffect(() => { const resizeObserver = new ResizeObserver((entries) => { for (let entry of entries) { requestAnimationFrame(() => { if (entry.target.clientWidth < entry.target.scrollWidth) { setShowTabArrows(true); } else { setShowTabArrows(false); } }); } }); resizeObserver.observe(tabItemListContainerRef.current!); return () => { resizeObserver.disconnect(); }; }, []); const handleRightClick = () => { tabItemListContainerRef.current!.scrollLeft += 90; }; const handleLeftClick = () => { tabItemListContainerRef.current!.scrollLeft -= 90; }; return (
{label}
{showTabArrows && (
); } function TabContent({ lazy, children, selectedValue, }: TabProps & ReturnType): React.JSX.Element | null { const childTabs = (Array.isArray(children) ? children : [children]).filter( Boolean ) as ReactElement[]; if (lazy) { const selectedTabItem = childTabs.find( (tabItem) => tabItem.props.value === selectedValue ); if (!selectedTabItem) { // fail-safe or fail-fast? not sure what's best here return null; } return cloneElement(selectedTabItem, { className: "margin-top--md" }); } return
{childTabs}
; } function TabsComponent(props: TabListProps): React.JSX.Element { const tabs = useTabsContextValue(props); return (
); } export default function ApiTabs(props: TabListProps): React.JSX.Element { const isBrowser = useIsBrowser(); return ( {sanitizeTabsChildren(props.children)} ); }