'use client'; import clsx from 'clsx'; import { useRef, useState } from 'react'; import { mergeProps, useButton, useDisclosure, useFocusRing } from 'react-aria'; import { useDisclosureState } from 'react-stately'; interface InteractiveSectionTab { key: string; label: string; body: React.ReactNode; } /** * To optimize rendering, most of the components are server-components, * and the interactiveness is mainly handled by a few key components like this one. */ export function InteractiveSection(props: { id?: string; /** Class name to be set on the section, sub-elements will use it as prefix */ className: string; /** If true, the content can be toggeable */ toggeable?: boolean; /** Default state of the toggle */ defaultOpened?: boolean; /** Icon to display for the toggle */ toggleIcon?: React.ReactNode; /** Tabs of content to display */ tabs?: Array; /** Default tab to have opened */ defaultTab?: string; /** Content of the header */ header?: React.ReactNode; /** Body of the section */ children?: React.ReactNode; /** Children to display within the container */ overlay?: React.ReactNode; }) { const { id, className, toggeable = false, defaultOpened = true, tabs = [], defaultTab = tabs[0]?.key, header, children, overlay, toggleIcon = '▶', } = props; const [selectedTabKey, setSelectedTab] = useState(defaultTab); const selectedTab: InteractiveSectionTab | undefined = tabs.find((tab) => tab.key === selectedTabKey) ?? tabs[0]; const state = useDisclosureState({ defaultExpanded: defaultOpened, }); const panelRef = useRef(null); const triggerRef = useRef(null); const { buttonProps: triggerProps, panelProps } = useDisclosure({}, state, panelRef); const { buttonProps } = useButton(triggerProps, triggerRef); const { isFocusVisible, focusProps } = useFocusRing(); return (
{header ? (
{ if (toggeable) { state.toggle(); } }} className={clsx('openapi-section-header', `${className}-header`)} >
{(children || selectedTab?.body) && toggeable ? ( ) : null} {header}
{ event.stopPropagation(); }} > {tabs.length > 1 ? ( ) : null}
) : null} {(!toggeable || state.isExpanded) && (children || selectedTab?.body) ? (
{children} {selectedTab?.body}
) : null} {overlay ? (
{overlay}
) : null}
); }