mirror of
https://github.com/GitbookIO/gitbook.git
synced 2026-09-12 05:48:57 +00:00
66 lines
2.2 KiB
TypeScript
66 lines
2.2 KiB
TypeScript
'use client';
|
|
import { Collapsible } from '@base-ui/react/collapsible';
|
|
import clsx from 'classnames';
|
|
import type React from 'react';
|
|
import { useEffect, useState } from 'react';
|
|
|
|
/**
|
|
* Display an interactive OpenAPI disclosure.
|
|
*/
|
|
export function OpenAPIDisclosure(props: {
|
|
icon: React.ReactNode;
|
|
header: React.ReactNode;
|
|
children: React.ReactNode;
|
|
label: string | ((isExpanded: boolean) => string);
|
|
className?: string;
|
|
defaultExpanded?: boolean;
|
|
/**
|
|
* Anchor id used as a deep-link target. When set, the disclosure expands and scrolls the
|
|
* element carrying this id into view once the URL hash matches it.
|
|
*/
|
|
id?: string;
|
|
}): React.JSX.Element {
|
|
const { icon, header, label, children, className, defaultExpanded = false, id } = props;
|
|
const [isExpanded, setIsExpanded] = useState(defaultExpanded);
|
|
|
|
// Expand and scroll into view when the URL hash points to this disclosure.
|
|
useEffect(() => {
|
|
if (!id) {
|
|
return;
|
|
}
|
|
|
|
const openFromHash = () => {
|
|
if (window.location.hash.slice(1) !== id) {
|
|
return;
|
|
}
|
|
setIsExpanded(true);
|
|
requestAnimationFrame(() => {
|
|
document.getElementById(id)?.scrollIntoView({ block: 'start' });
|
|
});
|
|
};
|
|
|
|
openFromHash();
|
|
window.addEventListener('hashchange', openFromHash);
|
|
return () => window.removeEventListener('hashchange', openFromHash);
|
|
}, [id]);
|
|
|
|
return (
|
|
<Collapsible.Root
|
|
className={clsx('openapi-disclosure', className)}
|
|
open={isExpanded}
|
|
onOpenChange={setIsExpanded}
|
|
>
|
|
<Collapsible.Trigger className="openapi-disclosure-trigger">
|
|
{header}
|
|
<div className="openapi-disclosure-trigger-label">
|
|
{label ? (
|
|
<span>{typeof label === 'function' ? label(isExpanded) : label}</span>
|
|
) : null}
|
|
{icon}
|
|
</div>
|
|
</Collapsible.Trigger>
|
|
<Collapsible.Panel className="openapi-disclosure-panel">{children}</Collapsible.Panel>
|
|
</Collapsible.Root>
|
|
);
|
|
}
|