Skip to content

Commit da55fac

Browse files
authored
Support GitBook blocks in OpenAPI operation description (#2868)
1 parent dc2dbc5 commit da55fac

File tree

8 files changed

+74
-15
lines changed

8 files changed

+74
-15
lines changed

.changeset/sharp-doors-itch.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
---
2+
'@gitbook/openapi-parser': patch
3+
'@gitbook/react-openapi': patch
4+
'gitbook': patch
5+
---
6+
7+
Render GitBook blocks in OpenAPI operation description

packages/gitbook/src/app/middleware/(space)/~gitbook/pdf/page.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -244,8 +244,8 @@ async function PDFPageDocument(props: {
244244
{document ? (
245245
<DocumentView
246246
document={document}
247-
style={'mt-6 space-y-6'}
248-
blockStyle={['max-w-full']}
247+
style="mt-6 space-y-6"
248+
blockStyle="max-w-full"
249249
context={{
250250
mode: 'print',
251251
content: {

packages/gitbook/src/components/DocumentView/OpenAPI/OpenAPI.tsx

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { DocumentBlockOpenAPI } from '@gitbook/api';
1+
import { DocumentBlockOpenAPI, JSONDocument } from '@gitbook/api';
22
import { Icon } from '@gitbook/icons';
33
import { OpenAPIOperation } from '@gitbook/react-openapi';
44
import React from 'react';
@@ -8,6 +8,7 @@ import { tcls } from '@/lib/tailwind';
88

99
import { BlockProps } from '../Block';
1010
import { PlainCodeBlock } from '../CodeBlock';
11+
import { DocumentView } from '../DocumentView';
1112
import { Heading } from '../Heading';
1213

1314
import './style.css';
@@ -57,7 +58,15 @@ async function OpenAPIBody(props: BlockProps<DocumentBlockOpenAPI>) {
5758
chevronRight: <Icon icon="chevron-right" />,
5859
plus: <Icon icon="plus" />,
5960
},
60-
CodeBlock: PlainCodeBlock,
61+
renderCodeBlock: (codeProps) => <PlainCodeBlock {...codeProps} />,
62+
renderDocument: (documentProps) => (
63+
<DocumentView
64+
document={documentProps.document as JSONDocument}
65+
context={props.context}
66+
style="space-y-6"
67+
blockStyle="max-w-full"
68+
/>
69+
),
6170
renderHeading: (headingProps) => (
6271
<Heading
6372
document={props.document}

packages/openapi-parser/src/types.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,11 @@ export interface OpenAPICustomOperationProperties {
4242
* Description in HTML format.
4343
*/
4444
'x-gitbook-description-html'?: string;
45+
46+
/**
47+
* Description in Document format.
48+
*/
49+
'x-gitbook-description-document'?: object;
4550
}
4651

4752
/**

packages/react-openapi/src/OpenAPICodeSample.tsx

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,10 @@ export function OpenAPICodeSample(props: {
7272
const autoCodeSamples = codeSampleGenerators.map((generator) => ({
7373
key: `default-${generator.id}`,
7474
label: generator.label,
75-
body: <context.CodeBlock code={generator.generate(input)} syntax={generator.syntax} />,
75+
body: context.renderCodeBlock({
76+
code: generator.generate(input),
77+
syntax: generator.syntax,
78+
}),
7679
}));
7780

7881
// Use custom samples if defined
@@ -95,7 +98,10 @@ export function OpenAPICodeSample(props: {
9598
.map((sample) => ({
9699
key: `redocly-${sample.lang}`,
97100
label: sample.label,
98-
body: <context.CodeBlock code={sample.source} syntax={sample.lang} />,
101+
body: context.renderCodeBlock({
102+
code: sample.source,
103+
syntax: sample.lang,
104+
}),
99105
}));
100106
}
101107
});

packages/react-openapi/src/OpenAPIOperation.tsx

Lines changed: 29 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import { OpenAPISpec } from './OpenAPISpec';
77
import type { OpenAPIClientContext, OpenAPIContextProps, OpenAPIOperationData } from './types';
88
import { OpenAPIPath } from './OpenAPIPath';
99
import { resolveDescription } from './utils';
10+
import { OpenAPICustomOperationProperties, OpenAPIV3 } from '@gitbook/openapi-parser';
1011

1112
/**
1213
* Display an interactive OpenAPI operation.
@@ -25,8 +26,6 @@ export function OpenAPIOperation(props: {
2526
blockKey: context.blockKey,
2627
};
2728

28-
const description = resolveDescription(operation);
29-
3029
return (
3130
<div className={clsx('openapi-operation', className)}>
3231
<div className="openapi-summary" id={operation.summary ? undefined : context.id}>
@@ -49,11 +48,7 @@ export function OpenAPIOperation(props: {
4948
{`.`}
5049
</div>
5150
) : null}
52-
{description ? (
53-
<div className="openapi-intro">
54-
<Markdown className="openapi-description" source={description} />
55-
</div>
56-
) : null}
51+
<OpenAPIOperationDescription operation={operation} context={context} />
5752
<OpenAPIPath data={data} context={context} />
5853
<OpenAPISpec data={data} context={clientContext} />
5954
</div>
@@ -67,3 +62,30 @@ export function OpenAPIOperation(props: {
6762
</div>
6863
);
6964
}
65+
66+
function OpenAPIOperationDescription(props: {
67+
operation: OpenAPIV3.OperationObject<OpenAPICustomOperationProperties>;
68+
context: OpenAPIContextProps;
69+
}) {
70+
const { operation } = props;
71+
if (operation['x-gitbook-description-document']) {
72+
return (
73+
<div className="openapi-intro">
74+
{props.context.renderDocument({
75+
document: operation['x-gitbook-description-document'],
76+
})}
77+
</div>
78+
);
79+
}
80+
81+
const description = resolveDescription(operation);
82+
if (!description) {
83+
return null;
84+
}
85+
86+
return (
87+
<div className="openapi-intro">
88+
<Markdown className="openapi-description" source={description} />
89+
</div>
90+
);
91+
}

packages/react-openapi/src/OpenAPIResponseExample.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -209,7 +209,7 @@ function OpenAPIExample(props: {
209209
return <OpenAPIEmptyResponseExample />;
210210
}
211211

212-
return <context.CodeBlock code={code} syntax={syntax} />;
212+
return context.renderCodeBlock({ code, syntax });
213213
}
214214

215215
function stringifyExample(args: { example: OpenAPIV3.ExampleObject; xml: boolean }): string | null {

packages/react-openapi/src/types.ts

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,18 @@ import type {
55
} from '@gitbook/openapi-parser';
66

77
export interface OpenAPIContextProps extends OpenAPIClientContext {
8-
CodeBlock: React.ComponentType<{ code: string; syntax: string }>;
8+
/**
9+
* Render a code block.
10+
*/
11+
renderCodeBlock: (props: { code: string; syntax: string }) => React.ReactNode;
12+
/**
13+
* Render the heading of the operation.
14+
*/
915
renderHeading: (props: { deprecated: boolean; title: string }) => React.ReactNode;
16+
/**
17+
* Render the document of the operation.
18+
*/
19+
renderDocument: (props: { document: object }) => React.ReactNode;
1020

1121
/** Spec url for the Scalar Api Client */
1222
specUrl: string;

0 commit comments

Comments
 (0)