Files
gitbook/packages/react-openapi/src/InteractiveSection.tsx
T
Samy Pessé 85ec1884e6 OpenAPI blocks (#74)
* Start methods to resolve refs

* bun

* Start package

* Add code to resolve ref

* Continue

* Deref

* Start monorepo

* Continue

* Fix ref resolver

* Style a bit more

* Start toggling section

* Continue

* Start displaying query/path/headers params

* Hide respo se if empty

* Fix recursive refs

* Simplify interactive and styling

* Display enums

* Format

* Improve type name being displayed

* Improve naming

* Render oneOf/anyOf/allOf

* Handle circular references

* Start variable in server url

* Use client component for the spec part

* Improve CSS sizing

* Display open api blocks in aside

* Make aside an overlay

* Improve stickiness of openapi

* Align document on the left when api page

* Improve general layout

* Better align

* Fix padding in aside

* Use syntax highlighting

* Show sample of response

* Improve code generation

* Improve code generated

* Format

* Format

* Rename to OpenAPI

* Skip deprecated properties and handle additionalProperties

* Use discriminator for naming

* Better name enum

* Make entire header toggeable

* Format and lint

* Add curl example

* Improve curl

* style pass

* Start securities

* Bun

* Fix TS

* Improve label

* Start markdown

* Improve code samples

* Test

* Use custom skeleton for api block

* Format

* Add support for redocly code samples

* Fix api blocks in aside

* Use typography for markdown

* Format

* Fix spacing in markdown

* Render headers

* Format

* Format

---------

Co-authored-by: Sebastian Graz <graz@live.se>
2024-01-30 10:15:58 +01:00

126 lines
4.2 KiB
TypeScript

'use client';
import classNames from 'classnames';
import React from 'react';
/**
* 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;
/** Icons to display for the toggle */
toggleOpenIcon?: React.ReactNode;
toggleCloseIcon?: React.ReactNode;
/** Tabs of content to display */
tabs?: Array<{
key: string;
label: string;
body: React.ReactNode;
}>;
/** Default tab to have opened */
defaultTab?: string;
/** Content of the header */
header: React.ReactNode;
/** Body of the section */
children?: React.ReactNode;
}) {
const {
id,
className,
toggeable = false,
defaultOpened = true,
tabs = [],
defaultTab = tabs[0]?.key,
header,
children,
toggleOpenIcon = '▶',
toggleCloseIcon = '▼',
} = props;
const [opened, setOpened] = React.useState(defaultOpened);
const [selectedTab, setSelectedTab] = React.useState(defaultTab);
const tabBody = tabs.find((tab) => tab.key === selectedTab)?.body;
return (
<div
id={id}
className={classNames(
'openapi-section',
toggeable ? 'openapi-section-toggeable' : null,
className,
toggeable ? `${className}-${opened ? 'opened' : 'closed'}` : null,
)}
>
<div
onClick={() => {
if (toggeable) {
setOpened(!opened);
}
}}
className={classNames('openapi-section-header', `${className}-header`)}
>
<div
className={classNames(
'openapi-section-header-content',
`${className}-header-content`,
)}
>
{header}
</div>
<div
className={classNames(
'openapi-section-header-controls',
`${className}-header-controls`,
)}
onClick={(event) => {
event.stopPropagation();
}}
>
{tabs.length ? (
<select
className={classNames(
'openapi-section-select',
'openapi-select',
`${className}-tabs-select`,
)}
value={selectedTab}
onChange={(event) => {
setSelectedTab(event.target.value);
setOpened(true);
}}
>
{tabs.map((tab) => (
<option key={tab.key} value={tab.key}>
{tab.label}
</option>
))}
</select>
) : null}
{(children || tabBody) && toggeable ? (
<button
className={classNames('openapi-section-toggle', `${className}-toggle`)}
onClick={() => setOpened(!opened)}
>
{opened ? toggleCloseIcon : toggleOpenIcon}
</button>
) : null}
</div>
</div>
{(!toggeable || opened) && (children || tabBody) ? (
<div className={classNames('openapi-section-body', `${className}-body`)}>
{children}
{tabBody}
</div>
) : null}
</div>
);
}