"use client" import React, { Children, useCallback, useEffect, useMemo, useRef } from "react" import { Badge, BaseTabType, CodeBlockProps, CodeBlockStyle, useColorMode, useTabs, } from "../.." import clsx from "clsx" type CodeTab = BaseTabType & { codeProps: CodeBlockProps codeBlock: React.ReactNode } type CodeTabProps = { children: React.ReactNode className?: string group?: string title?: string blockStyle?: CodeBlockStyle } export const CodeTabs = ({ children, className, group = "client", blockStyle = "loud", }: CodeTabProps) => { const { colorMode } = useColorMode() const tabs: CodeTab[] = useMemo(() => { const tempTabs: CodeTab[] = [] Children.forEach(children, (child) => { if ( !React.isValidElement(child) || !child.props.label || !child.props.value || !React.isValidElement(child.props.children) ) { return } // extract child code block const codeBlock = child.props.children.type === "pre" && React.isValidElement(child.props.children.props.children) ? child.props.children.props.children : child.props.children tempTabs.push({ label: child.props.label, value: child.props.value, codeProps: codeBlock.props, codeBlock: { ...codeBlock, props: { ...codeBlock.props, badgeLabel: undefined, hasTabs: true, className: clsx("!my-0", codeBlock.props.className), }, }, }) }) return tempTabs }, [children]) const { selectedTab, changeSelectedTab } = useTabs({ tabs, group, }) const tabRefs: (HTMLButtonElement | null)[] = useMemo(() => [], []) const codeTabSelectorRef = useRef(null) const codeTabsWrapperRef = useRef(null) const bgColor = useMemo( () => clsx( blockStyle === "loud" && "bg-medusa-contrast-bg-base", blockStyle === "subtle" && [ colorMode === "light" && "bg-medusa-bg-component", colorMode === "dark" && "bg-medusa-code-bg-header", ] ), [blockStyle, colorMode] ) const boxShadow = useMemo( () => clsx( blockStyle === "loud" && "shadow-elevation-code-block dark:shadow-elevation-code-block-dark", blockStyle === "subtle" && "shadow-none" ), [blockStyle] ) const changeTabSelectorCoordinates = useCallback( (selectedTabElm: HTMLElement) => { if (!codeTabSelectorRef?.current || !codeTabsWrapperRef?.current) { return } const selectedTabsCoordinates = selectedTabElm.getBoundingClientRect() const tabsWrapperCoordinates = codeTabsWrapperRef.current.getBoundingClientRect() codeTabSelectorRef.current.style.left = `${ selectedTabsCoordinates.left - tabsWrapperCoordinates.left }px` codeTabSelectorRef.current.style.width = `${selectedTabsCoordinates.width}px` if (blockStyle !== "loud") { codeTabSelectorRef.current.style.height = `${selectedTabsCoordinates.height}px` } }, [blockStyle] ) useEffect(() => { if (codeTabSelectorRef?.current && tabRefs.length) { const selectedTabElm = tabRefs.find( (tab) => tab?.getAttribute("aria-selected") === "true" ) if (selectedTabElm) { changeTabSelectorCoordinates( selectedTabElm.parentElement || selectedTabElm ) } } }, [codeTabSelectorRef, tabRefs, changeTabSelectorCoordinates, selectedTab]) return (
    {Children.map(children, (child, index) => { if (!React.isValidElement(child)) { return <> } return ( tabRefs.push(tabButton) } blockStyle={blockStyle} isSelected={ !selectedTab ? index === 0 : selectedTab.value === child.props.value } /> ) })}
{selectedTab?.codeProps.badgeLabel && ( {selectedTab.codeProps.badgeLabel} )}
{selectedTab?.codeBlock}
) }