/* ============================================================================ * 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, useEffect, useState, useRef, ReactElement, } from "react"; import { sanitizeTabsChildren, type TabItemProps, TabProps, TabsProvider, useScrollPositionBlocker, useTabsContextValue, } from "@docusaurus/theme-common/internal"; import useIsBrowser from "@docusaurus/useIsBrowser"; import { setAccept } from "@theme/ApiExplorer/Accept/slice"; import { setContentType } from "@theme/ApiExplorer/ContentType/slice"; import { useTypedDispatch, useTypedSelector } from "@theme/ApiItem/hooks"; import { RootState } from "@theme/ApiItem/store"; import clsx from "clsx"; export interface Props { schemaType: any; } function TabList({ className, block, selectedValue: selectedValueProp, selectValue, tabValues, schemaType, }: Props & TabProps & ReturnType): React.JSX.Element { const tabRefs: (HTMLLIElement | null)[] = []; const { blockElementScrollPositionUntilNextRender } = useScrollPositionBlocker(); // custom const dispatch = useTypedDispatch(); const isRequestSchema = schemaType?.toLowerCase() === "request"; const [selectedValue, setSelectedValue] = useState(selectedValueProp); const contentTypeVal = useTypedSelector( (state: RootState) => state.contentType.value ); const acceptTypeVal = useTypedSelector( (state: RootState) => state.accept.value ); useEffect(() => { if (tabRefs.length > 1) { if (isRequestSchema) { setSelectedValue(contentTypeVal); } else { setSelectedValue(acceptTypeVal); } } // eslint-disable-next-line react-hooks/exhaustive-deps }, [contentTypeVal, acceptTypeVal]); const handleTabChange = ( event: | React.FocusEvent | React.MouseEvent | React.KeyboardEvent ) => { event.preventDefault(); const newTab = event.currentTarget; const newTabIndex = tabRefs.indexOf(newTab); const newTabValue = tabValues[newTabIndex].value; // custom if (newTabValue !== selectedValue) { if (isRequestSchema) { dispatch(setContentType(newTabValue)); } else { dispatch(setAccept(newTabValue)); } 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 (
{showTabArrows && (
); } function TabContent({ lazy, children, selectedValue, }: Props & TabProps & ReturnType) { 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: Props & TabProps): React.JSX.Element { const tabs = useTabsContextValue(props); return (
); } export default function MimeTabs(props: Props & TabProps) { const isBrowser = useIsBrowser(); return ( {sanitizeTabsChildren(props.children)} ); }