mirror of
https://github.com/GitbookIO/gitbook.git
synced 2026-09-17 08:05:19 +00:00
139 lines
4.7 KiB
TypeScript
139 lines
4.7 KiB
TypeScript
'use client';
|
|
|
|
import { ApiClientModalProvider, useApiClientModal } from '@scalar/api-client-react';
|
|
import { Suspense, useEffect, useImperativeHandle, useMemo, useRef, useState } from 'react';
|
|
import { createPortal } from 'react-dom';
|
|
|
|
import type { OpenAPIV3_1 } from '@gitbook/openapi-parser';
|
|
import { useOpenAPIOperationContext } from './OpenAPIOperationContext';
|
|
import { useOpenAPIPrefillContext } from './OpenAPIPrefillContextProvider';
|
|
import type { OpenAPIClientContext } from './context';
|
|
import { t } from './translate';
|
|
import type { OpenAPIOperationData } from './types';
|
|
import { resolveTryItPrefillForOperation } from './util/tryit-prefill';
|
|
|
|
/**
|
|
* Button which launches the Scalar API Client
|
|
*/
|
|
export function ScalarApiButton(props: {
|
|
method: OpenAPIV3_1.HttpMethods;
|
|
path: string;
|
|
securities: OpenAPIOperationData['securities'];
|
|
servers: OpenAPIOperationData['servers'];
|
|
specUrl: string;
|
|
context: OpenAPIClientContext;
|
|
}) {
|
|
const { method, path, securities, servers, specUrl, context } = props;
|
|
const [isOpen, setIsOpen] = useState(false);
|
|
const controllerRef = useRef<ScalarModalControllerRef>(null);
|
|
|
|
return (
|
|
<div className="scalar scalar-activate">
|
|
<button
|
|
className="scalar-activate-button button"
|
|
onClick={() => {
|
|
controllerRef.current?.openClient?.();
|
|
setIsOpen(true);
|
|
}}
|
|
>
|
|
{t(context.translation, 'test_it')}
|
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 10 12" fill="currentColor">
|
|
<path
|
|
stroke="currentColor"
|
|
strokeWidth="1.5"
|
|
d="M1 10.05V1.43c0-.2.2-.31.37-.22l7.26 4.08c.17.1.17.33.01.43l-7.26 4.54a.25.25 0 0 1-.38-.21Z"
|
|
/>
|
|
</svg>
|
|
</button>
|
|
|
|
{isOpen &&
|
|
createPortal(
|
|
<Suspense fallback={null}>
|
|
<ScalarModal
|
|
controllerRef={controllerRef}
|
|
method={method}
|
|
path={path}
|
|
securities={securities}
|
|
servers={servers}
|
|
specUrl={specUrl}
|
|
/>
|
|
</Suspense>,
|
|
document.body
|
|
)}
|
|
</div>
|
|
);
|
|
}
|
|
|
|
function ScalarModal(props: {
|
|
method: OpenAPIV3_1.HttpMethods;
|
|
path: string;
|
|
securities: OpenAPIOperationData['securities'];
|
|
servers: OpenAPIOperationData['servers'];
|
|
specUrl: string;
|
|
controllerRef: React.Ref<ScalarModalControllerRef>;
|
|
}) {
|
|
const { method, path, securities, servers, specUrl, controllerRef } = props;
|
|
|
|
const getPrefillInputContextData = useOpenAPIPrefillContext();
|
|
const prefillInputContext = getPrefillInputContextData();
|
|
|
|
const prefillConfig = resolveTryItPrefillForOperation({
|
|
operation: { securities, servers },
|
|
prefillInputContext,
|
|
});
|
|
|
|
return (
|
|
<ApiClientModalProvider
|
|
configuration={{ url: specUrl, ...prefillConfig }}
|
|
initialRequest={
|
|
method !== 'connect' ? { method: toScalarHttpMethod(method), path } : undefined
|
|
}
|
|
>
|
|
<ScalarModalController method={method} path={path} controllerRef={controllerRef} />
|
|
</ApiClientModalProvider>
|
|
);
|
|
}
|
|
|
|
function toScalarHttpMethod<T extends OpenAPIV3_1.HttpMethods>(method: T): Uppercase<T> {
|
|
return method.toUpperCase() as Uppercase<T>;
|
|
}
|
|
|
|
type ScalarModalControllerRef = {
|
|
openClient: (() => void) | undefined;
|
|
};
|
|
|
|
function ScalarModalController(props: {
|
|
method: OpenAPIV3_1.HttpMethods;
|
|
path: string;
|
|
controllerRef: React.Ref<ScalarModalControllerRef>;
|
|
}) {
|
|
const { method, path, controllerRef } = props;
|
|
const client = useApiClientModal();
|
|
const openScalarClient = client?.open;
|
|
const { onOpenClient: trackClientOpening } = useOpenAPIOperationContext();
|
|
const openClient = useMemo(() => {
|
|
if (openScalarClient && method !== 'connect') {
|
|
return () => {
|
|
openScalarClient({
|
|
method: toScalarHttpMethod(method),
|
|
path,
|
|
_source: 'gitbook',
|
|
});
|
|
trackClientOpening({ method, path });
|
|
};
|
|
}
|
|
return null;
|
|
}, [openScalarClient, method, path, trackClientOpening]);
|
|
useImperativeHandle(
|
|
controllerRef,
|
|
() => ({ openClient: openClient ? () => openClient() : undefined }),
|
|
[openClient]
|
|
);
|
|
|
|
// Open at mount
|
|
useEffect(() => {
|
|
openClient?.();
|
|
}, [openClient]);
|
|
return null;
|
|
}
|