Files
gitbook/packages/react-openapi/src/InteractiveSection.tsx
Marc Laventure 4f039ecb2b feat: add scalar api client (#180)
* wip

* feat: add scalar api client

* fix: pr feedback

* feat: add scalar react client package, remove vueary

* feat: add scalar proxy

* Move dependencies to package

* Format once

* Rename prop

* Use react context and simplify lazy loading

* Add loading state

* Format

* Move styles

* bun install

* bun

* fix: remove extraneous api-reference package

* feat: make operation functional with spec in client

* fix: column bug and http request type wrapping

* fix: add scalar api reference package

* Format

* bun install

* fix: scrolling in scalar modal

* Lazy load operations data in component

* fix: change dependency from api-reference to oas-utils to reduce size

* bun install

* Log error in the worker proxy

* Cleanup

* Comment "mode"

* Without credentials and referrerPolicy

---------

Co-authored-by: Samy Pessé <samypesse@gmail.com>
Co-authored-by: Amrit <amrit@hockey-community.com>
2024-03-19 15:32:54 +01:00

130 lines
4.3 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;
/** Children to display within the container */
overlay?: React.ReactNode;
}) {
const {
id,
className,
toggeable = false,
defaultOpened = true,
tabs = [],
defaultTab = tabs[0]?.key,
header,
children,
overlay,
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}
{overlay}
</div>
);
}