'use client'; import '@scalar/api-client-react/style.css'; import { type ComponentType, type ReactNode, type Ref, useEffect, useImperativeHandle, useMemo, useRef, } from 'react'; import type { OpenAPIV3_1 } from '@gitbook/openapi-parser'; import type { OpenAPIClientContext } from './context'; import { useOpenAPIOperationContext } from './OpenAPIOperationContext'; import { useOpenAPIPrefillContext } from './OpenAPIPrefillContextProvider'; import type { OpenAPIOperationData } from './types'; import { resolveTryItPrefillForOperation } from './util/tryit-prefill'; export type ScalarModalControllerRef = { openClient: (() => void) | undefined; }; export type ScalarRuntime = { ApiClientModalProvider: ComponentType<{ configuration: object; initialRequest: { method: string; path: string }; children: ReactNode; }>; useApiClientModal: () => { open?: (request: { method: string; path: string; _source?: string }) => void; } | null; }; export type ScalarApiModalProps = { method: OpenAPIV3_1.HttpMethods; path: string; securities: OpenAPIOperationData['securities']; servers: OpenAPIOperationData['servers']; specUrl: string; withProxy: boolean; context: OpenAPIClientContext; runtime: ScalarRuntime; controllerRef: Ref; /** Called once the client is initialized and the modal is opening. */ onReady: () => void; }; /** Loaded only after a reader opens the Try it client. */ export function ScalarApiModal(props: ScalarApiModalProps) { const { method, path, securities, servers, specUrl, withProxy, context, controllerRef, runtime, onReady, } = props; const getPrefillInputContextData = useOpenAPIPrefillContext(); const prefillInputContext = getPrefillInputContextData(); const prefillConfig = resolveTryItPrefillForOperation({ operation: { securities, servers }, prefillInputContext, }); return ( ); } function ScalarModalController(props: { method: OpenAPIV3_1.HttpMethods; path: string; controllerRef: Ref; runtime: ScalarRuntime; onReady: () => void; }) { const { method, path, controllerRef, runtime, onReady } = props; const client = runtime.useApiClientModal(); const openScalarClient = client?.open; const { onOpenClient: trackClientOpening } = useOpenAPIOperationContext(); const openClient = useMemo(() => { if (openScalarClient) { return () => { openScalarClient({ method: toScalarHttpMethod(method), path, _source: 'gitbook', }); trackClientOpening({ method, path }); }; } return null; }, [openScalarClient, method, path, trackClientOpening]); useImperativeHandle( controllerRef, () => ({ openClient: openClient ? () => openClient() : undefined }), [openClient] ); // Through a ref, so an unstable callback doesn't re-open the client on every render. const onReadyRef = useRef(onReady); onReadyRef.current = onReady; useEffect(() => { if (openClient) { openClient(); onReadyRef.current(); } }, [openClient]); return null; } function toScalarHttpMethod(method: T): Uppercase { return method.toUpperCase() as Uppercase; }