@gitbook/react-openapi 1.1.5 → 1.1.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (59) hide show
  1. package/CHANGELOG.md +34 -0
  2. package/dist/InteractiveSection.d.ts +0 -2
  3. package/dist/InteractiveSection.jsx +3 -4
  4. package/dist/OpenAPICodeSample.d.ts +9 -0
  5. package/dist/OpenAPICodeSample.jsx +117 -58
  6. package/dist/OpenAPICodeSampleInteractive.d.ts +11 -0
  7. package/dist/OpenAPICodeSampleInteractive.jsx +85 -0
  8. package/dist/OpenAPICopyButton.d.ts +7 -0
  9. package/dist/OpenAPICopyButton.jsx +6 -6
  10. package/dist/OpenAPIOperation.jsx +21 -1
  11. package/dist/OpenAPIPath.jsx +2 -2
  12. package/dist/OpenAPIRequestBody.jsx +1 -1
  13. package/dist/OpenAPIResponse.jsx +1 -1
  14. package/dist/OpenAPIResponses.jsx +2 -2
  15. package/dist/OpenAPISchema.d.ts +5 -14
  16. package/dist/OpenAPISchema.jsx +79 -28
  17. package/dist/OpenAPISchemaName.jsx +8 -6
  18. package/dist/OpenAPISchemaServer.d.ts +12 -0
  19. package/dist/OpenAPISchemaServer.jsx +8 -0
  20. package/dist/OpenAPISpec.d.ts +0 -6
  21. package/dist/OpenAPISpec.jsx +5 -11
  22. package/dist/OpenAPITabs.jsx +3 -11
  23. package/dist/code-samples.d.ts +1 -2
  24. package/dist/code-samples.js +46 -11
  25. package/dist/decycle.d.ts +2 -0
  26. package/dist/decycle.js +70 -0
  27. package/dist/generateSchemaExample.d.ts +31 -2
  28. package/dist/generateSchemaExample.js +307 -24
  29. package/dist/schemas/OpenAPISchemas.jsx +1 -1
  30. package/dist/schemas/resolveOpenAPISchemas.d.ts +2 -6
  31. package/dist/schemas/resolveOpenAPISchemas.js +1 -21
  32. package/dist/tsconfig.build.tsbuildinfo +1 -1
  33. package/dist/types.d.ts +2 -5
  34. package/dist/utils.d.ts +1 -1
  35. package/dist/utils.js +11 -7
  36. package/package.json +3 -3
  37. package/src/InteractiveSection.tsx +2 -6
  38. package/src/OpenAPICodeSample.tsx +187 -78
  39. package/src/OpenAPICodeSampleInteractive.tsx +139 -0
  40. package/src/OpenAPICopyButton.tsx +17 -4
  41. package/src/OpenAPIOperation.tsx +39 -2
  42. package/src/OpenAPIPath.tsx +2 -2
  43. package/src/OpenAPIRequestBody.tsx +1 -1
  44. package/src/OpenAPIResponse.tsx +4 -4
  45. package/src/OpenAPIResponses.tsx +1 -5
  46. package/src/OpenAPISchema.tsx +152 -58
  47. package/src/OpenAPISchemaName.tsx +14 -6
  48. package/src/OpenAPISchemaServer.tsx +34 -0
  49. package/src/OpenAPISpec.tsx +13 -11
  50. package/src/OpenAPITabs.tsx +3 -13
  51. package/src/code-samples.test.ts +69 -1
  52. package/src/code-samples.ts +48 -12
  53. package/src/decycle.ts +68 -0
  54. package/src/generateSchemaExample.ts +412 -25
  55. package/src/resolveOpenAPIOperation.test.ts +6 -6
  56. package/src/schemas/OpenAPISchemas.tsx +1 -1
  57. package/src/schemas/resolveOpenAPISchemas.ts +3 -31
  58. package/src/types.ts +6 -6
  59. package/src/utils.ts +13 -10
@@ -1,6 +1,10 @@
1
1
  import clsx from 'clsx';
2
2
 
3
- import type { OpenAPICustomOperationProperties, OpenAPIV3 } from '@gitbook/openapi-parser';
3
+ import type {
4
+ OpenAPICustomOperationProperties,
5
+ OpenAPIStability,
6
+ OpenAPIV3,
7
+ } from '@gitbook/openapi-parser';
4
8
  import { Markdown } from './Markdown';
5
9
  import { OpenAPICodeSample } from './OpenAPICodeSample';
6
10
  import { OpenAPIPath } from './OpenAPIPath';
@@ -29,14 +33,24 @@ export function OpenAPIOperation(props: {
29
33
  return (
30
34
  <div className={clsx('openapi-operation', className)}>
31
35
  <div className="openapi-summary" id={operation.summary ? undefined : context.id}>
36
+ {(operation.deprecated || operation['x-stability']) && (
37
+ <div className="openapi-summary-tags">
38
+ {operation.deprecated && (
39
+ <div className="openapi-deprecated">Deprecated</div>
40
+ )}
41
+ {operation['x-stability'] && (
42
+ <OpenAPIOperationStability stability={operation['x-stability']} />
43
+ )}
44
+ </div>
45
+ )}
32
46
  {operation.summary
33
47
  ? context.renderHeading({
34
48
  deprecated: operation.deprecated ?? false,
49
+ stability: operation['x-stability'],
35
50
  title: operation.summary,
36
51
  })
37
52
  : null}
38
53
  <OpenAPIPath data={data} context={context} />
39
- {operation.deprecated && <div className="openapi-deprecated">Deprecated</div>}
40
54
  </div>
41
55
  <div className="openapi-columns">
42
56
  <div className="openapi-column-spec">
@@ -89,3 +103,26 @@ function OpenAPIOperationDescription(props: {
89
103
  </div>
90
104
  );
91
105
  }
106
+
107
+ const stabilityEnum = {
108
+ experimental: 'Experimental',
109
+ alpha: 'Alpha',
110
+ beta: 'Beta',
111
+ stable: 'Stable',
112
+ } as const;
113
+
114
+ function OpenAPIOperationStability(props: { stability: OpenAPIStability }) {
115
+ const { stability } = props;
116
+
117
+ const foundStability = stabilityEnum[stability];
118
+
119
+ if (!foundStability) {
120
+ return null;
121
+ }
122
+
123
+ return (
124
+ <div className={`openapi-stability openapi-stability-${foundStability.toLowerCase()}`}>
125
+ {foundStability}
126
+ </div>
127
+ );
128
+ }
@@ -47,7 +47,7 @@ function formatPath(path: string) {
47
47
  parts.push(path.slice(lastIndex, offset));
48
48
  }
49
49
  parts.push(
50
- <span key={offset} className="openapi-path-variable">
50
+ <span key={`offset-${offset}`} className="openapi-path-variable">
51
51
  {match}
52
52
  </span>
53
53
  );
@@ -61,7 +61,7 @@ function formatPath(path: string) {
61
61
 
62
62
  const formattedPath = parts.map((part, index) => {
63
63
  if (typeof part === 'string') {
64
- return <span key={index}>{part}</span>;
64
+ return <span key={`part-${index}`}>{part}</span>;
65
65
  }
66
66
  return part;
67
67
  });
@@ -1,6 +1,6 @@
1
1
  import type { OpenAPIV3 } from '@gitbook/openapi-parser';
2
2
  import { InteractiveSection } from './InteractiveSection';
3
- import { OpenAPIRootSchema } from './OpenAPISchema';
3
+ import { OpenAPIRootSchema } from './OpenAPISchemaServer';
4
4
  import type { OpenAPIClientContext } from './types';
5
5
  import { checkIsReference } from './utils';
6
6
 
@@ -1,6 +1,6 @@
1
1
  import type { OpenAPIV3 } from '@gitbook/openapi-parser';
2
2
  import { OpenAPIDisclosure } from './OpenAPIDisclosure';
3
- import { OpenAPISchemaProperties } from './OpenAPISchema';
3
+ import { OpenAPISchemaProperties } from './OpenAPISchemaServer';
4
4
  import type { OpenAPIClientContext } from './types';
5
5
  import { parameterToProperty, resolveDescription } from './utils';
6
6
 
@@ -29,9 +29,9 @@ export function OpenAPIResponse(props: {
29
29
  {headers.length > 0 ? (
30
30
  <OpenAPIDisclosure context={context} label="Headers">
31
31
  <OpenAPISchemaProperties
32
- properties={headers.map(([name, header]) => {
33
- return parameterToProperty({ name, ...header });
34
- })}
32
+ properties={headers.map(([name, header]) =>
33
+ parameterToProperty({ name, ...header })
34
+ )}
35
35
  context={context}
36
36
  />
37
37
  </OpenAPIDisclosure>
@@ -27,10 +27,7 @@ export function OpenAPIResponses(props: {
27
27
  return {
28
28
  id: statusCode,
29
29
  label: (
30
- <div
31
- className="openapi-response-tab-content"
32
- key={`response-${statusCode}`}
33
- >
30
+ <div className="openapi-response-tab-content">
34
31
  <span className="openapi-response-statuscode">
35
32
  {statusCode}
36
33
  </span>
@@ -47,7 +44,6 @@ export function OpenAPIResponses(props: {
47
44
  label: contentType,
48
45
  body: (
49
46
  <OpenAPIResponse
50
- key={`$response-${statusCode}-${contentType}`}
51
47
  response={response}
52
48
  mediaType={mediaType}
53
49
  context={context}
@@ -1,16 +1,22 @@
1
- import type { OpenAPIV3 } from '@gitbook/openapi-parser';
1
+ 'use client';
2
+ // This component does not use any client feature but we don't want to
3
+ // render it server-side because it has recursion.
4
+
5
+ import type { OpenAPICustomOperationProperties, OpenAPIV3 } from '@gitbook/openapi-parser';
2
6
  import { useId } from 'react';
3
7
 
4
8
  import clsx from 'clsx';
5
9
  import { Markdown } from './Markdown';
10
+ import { OpenAPICopyButton } from './OpenAPICopyButton';
6
11
  import { OpenAPIDisclosure } from './OpenAPIDisclosure';
7
12
  import { OpenAPISchemaName } from './OpenAPISchemaName';
13
+ import { retrocycle } from './decycle';
8
14
  import type { OpenAPIClientContext } from './types';
9
15
  import { checkIsReference, resolveDescription, resolveFirstExample } from './utils';
10
16
 
11
17
  type CircularRefsIds = Map<OpenAPIV3.SchemaObject, string>;
12
18
 
13
- interface OpenAPISchemaPropertyEntry {
19
+ export interface OpenAPISchemaPropertyEntry {
14
20
  propertyName?: string | undefined;
15
21
  required?: boolean | undefined;
16
22
  schema: OpenAPIV3.SchemaObject;
@@ -22,15 +28,10 @@ interface OpenAPISchemaPropertyEntry {
22
28
  function OpenAPISchemaProperty(props: {
23
29
  property: OpenAPISchemaPropertyEntry;
24
30
  context: OpenAPIClientContext;
25
- circularRefs?: CircularRefsIds;
31
+ circularRefs: CircularRefsIds;
26
32
  className?: string;
27
33
  }) {
28
- const {
29
- property,
30
- circularRefs: parentCircularRefs = new Map<OpenAPIV3.SchemaObject, string>(),
31
- context,
32
- className,
33
- } = props;
34
+ const { circularRefs: parentCircularRefs, context, className, property } = props;
34
35
 
35
36
  const { schema } = property;
36
37
 
@@ -40,37 +41,43 @@ function OpenAPISchemaProperty(props: {
40
41
  <div id={id} className={clsx('openapi-schema', className)}>
41
42
  <OpenAPISchemaPresentation property={property} />
42
43
  {(() => {
43
- const parentCircularRef = parentCircularRefs.get(schema);
44
-
44
+ const circularRefId = parentCircularRefs.get(schema);
45
45
  // Avoid recursing infinitely, and instead render a link to the parent schema
46
- if (parentCircularRef) {
47
- return <OpenAPISchemaCircularRef id={parentCircularRef} schema={schema} />;
46
+ if (circularRefId) {
47
+ return <OpenAPISchemaCircularRef id={circularRefId} schema={schema} />;
48
48
  }
49
49
 
50
- const circularRefs = parentCircularRefs.set(schema, id);
50
+ const circularRefs = new Map(parentCircularRefs);
51
+ circularRefs.set(schema, id);
52
+
51
53
  const properties = getSchemaProperties(schema);
52
- const alternatives = getSchemaAlternatives(schema, new Set(circularRefs.keys()));
53
- return (
54
- <>
55
- {alternatives?.map((schema, index) => (
56
- <OpenAPISchemaAlternative
57
- key={index}
58
- schema={schema}
54
+ if (properties?.length) {
55
+ return (
56
+ <OpenAPIDisclosure context={context} label={getDisclosureLabel(schema)}>
57
+ <OpenAPISchemaProperties
58
+ properties={properties}
59
59
  circularRefs={circularRefs}
60
60
  context={context}
61
61
  />
62
- ))}
63
- {properties?.length ? (
64
- <OpenAPIDisclosure context={context} label={getDisclosureLabel(schema)}>
65
- <OpenAPISchemaProperties
66
- properties={properties}
67
- circularRefs={circularRefs}
68
- context={context}
69
- />
70
- </OpenAPIDisclosure>
71
- ) : null}
72
- </>
73
- );
62
+ </OpenAPIDisclosure>
63
+ );
64
+ }
65
+
66
+ const ancestors = new Set(circularRefs.keys());
67
+ const alternatives = getSchemaAlternatives(schema, ancestors);
68
+
69
+ if (alternatives) {
70
+ return alternatives.map((schema, index) => (
71
+ <OpenAPISchemaAlternative
72
+ key={index}
73
+ schema={schema}
74
+ circularRefs={circularRefs}
75
+ context={context}
76
+ />
77
+ ));
78
+ }
79
+
80
+ return null;
74
81
  })()}
75
82
  </div>
76
83
  );
@@ -79,41 +86,77 @@ function OpenAPISchemaProperty(props: {
79
86
  /**
80
87
  * Render a set of properties of an OpenAPI schema.
81
88
  */
82
- export function OpenAPISchemaProperties(props: {
89
+ function OpenAPISchemaProperties(props: {
83
90
  id?: string;
84
91
  properties: OpenAPISchemaPropertyEntry[];
85
92
  circularRefs?: CircularRefsIds;
86
93
  context: OpenAPIClientContext;
87
94
  }) {
88
- const { id, properties, circularRefs, context } = props;
95
+ const {
96
+ id,
97
+ properties,
98
+ circularRefs = new Map<OpenAPIV3.SchemaObject, string>(),
99
+ context,
100
+ } = props;
89
101
 
90
102
  return (
91
103
  <div id={id} className="openapi-schema-properties">
92
- {properties.map((property, index) => (
93
- <OpenAPISchemaProperty
94
- key={index}
95
- circularRefs={circularRefs}
96
- property={property}
97
- context={context}
98
- />
99
- ))}
104
+ {properties.map((property, index) => {
105
+ return (
106
+ <OpenAPISchemaProperty
107
+ key={index}
108
+ circularRefs={circularRefs}
109
+ property={property}
110
+ context={context}
111
+ />
112
+ );
113
+ })}
100
114
  </div>
101
115
  );
102
116
  }
103
117
 
118
+ export function OpenAPISchemaPropertiesFromServer(props: {
119
+ id?: string;
120
+ properties: string;
121
+ context: OpenAPIClientContext;
122
+ }) {
123
+ return (
124
+ <OpenAPISchemaProperties
125
+ id={props.id}
126
+ properties={JSON.parse(props.properties, retrocycle())}
127
+ context={props.context}
128
+ />
129
+ );
130
+ }
131
+
104
132
  /**
105
133
  * Render a root schema (such as the request body or response body).
106
134
  */
107
- export function OpenAPIRootSchema(props: {
135
+ function OpenAPIRootSchema(props: {
108
136
  schema: OpenAPIV3.SchemaObject;
109
137
  context: OpenAPIClientContext;
138
+ circularRefs?: CircularRefsIds;
110
139
  }) {
111
- const { schema, context } = props;
140
+ const {
141
+ schema,
142
+ context,
143
+ circularRefs: parentCircularRefs = new Map<OpenAPIV3.SchemaObject, string>(),
144
+ } = props;
112
145
 
146
+ const id = useId();
113
147
  const properties = getSchemaProperties(schema);
114
148
 
115
149
  if (properties?.length) {
116
- return <OpenAPISchemaProperties properties={properties} context={context} />;
150
+ const circularRefs = new Map(parentCircularRefs);
151
+ circularRefs.set(schema, id);
152
+
153
+ return (
154
+ <OpenAPISchemaProperties
155
+ properties={properties}
156
+ circularRefs={circularRefs}
157
+ context={context}
158
+ />
159
+ );
117
160
  }
118
161
 
119
162
  return (
@@ -121,6 +164,19 @@ export function OpenAPIRootSchema(props: {
121
164
  className="openapi-schema-root"
122
165
  property={{ schema }}
123
166
  context={context}
167
+ circularRefs={parentCircularRefs}
168
+ />
169
+ );
170
+ }
171
+
172
+ export function OpenAPIRootSchemaFromServer(props: {
173
+ schema: string;
174
+ context: OpenAPIClientContext;
175
+ }) {
176
+ return (
177
+ <OpenAPIRootSchema
178
+ schema={JSON.parse(props.schema, retrocycle())}
179
+ context={props.context}
124
180
  />
125
181
  );
126
182
  }
@@ -136,6 +192,7 @@ function OpenAPISchemaAlternative(props: {
136
192
  context: OpenAPIClientContext;
137
193
  }) {
138
194
  const { schema, circularRefs, context } = props;
195
+
139
196
  const description = resolveDescription(schema);
140
197
  const properties = getSchemaProperties(schema);
141
198
 
@@ -180,20 +237,59 @@ function OpenAPISchemaCircularRef(props: { id: string; schema: OpenAPIV3.SchemaO
180
237
  /**
181
238
  * Render the enum value for a schema.
182
239
  */
183
- function OpenAPISchemaEnum(props: { enumValues: any[] }) {
184
- const { enumValues } = props;
240
+ function OpenAPISchemaEnum(props: {
241
+ schema: OpenAPIV3.SchemaObject & OpenAPICustomOperationProperties;
242
+ }) {
243
+ const { schema } = props;
244
+
245
+ const enumValues = (() => {
246
+ // Render x-gitbook-enum first, as it has a different format
247
+ if (schema['x-gitbook-enum']) {
248
+ return Object.entries(schema['x-gitbook-enum']).map(([name, { description }]) => {
249
+ return {
250
+ value: name,
251
+ description,
252
+ };
253
+ });
254
+ }
255
+
256
+ if (schema['x-enumDescriptions']) {
257
+ return Object.entries(schema['x-enumDescriptions']).map(([value, description]) => {
258
+ return {
259
+ value,
260
+ description,
261
+ };
262
+ });
263
+ }
264
+
265
+ return schema.enum?.map((value) => {
266
+ return {
267
+ value,
268
+ description: undefined,
269
+ };
270
+ });
271
+ })();
272
+
273
+ if (!enumValues?.length) {
274
+ return null;
275
+ }
185
276
 
186
277
  return (
187
278
  <div className="openapi-schema-enum">
188
- <span>
189
- Options:{' '}
190
- {enumValues.map((value, index) => (
279
+ <span>Available options:</span>
280
+ <div className="openapi-schema-enum-list">
281
+ {enumValues.map((item, index) => (
191
282
  <span key={index} className="openapi-schema-enum-value">
192
- <code>{`${value}`}</code>
193
- {index < enumValues.length - 1 ? ', ' : ''}
283
+ <OpenAPICopyButton
284
+ value={item.value}
285
+ label={item.description}
286
+ withTooltip={!!item.description}
287
+ >
288
+ <code>{`${item.value}`}</code>
289
+ </OpenAPICopyButton>
194
290
  </span>
195
291
  ))}
196
- </span>
292
+ </div>
197
293
  </div>
198
294
  );
199
295
  }
@@ -238,9 +334,7 @@ function OpenAPISchemaPresentation(props: { property: OpenAPISchemaPropertyEntry
238
334
  Pattern: <code>{schema.pattern}</code>
239
335
  </div>
240
336
  ) : null}
241
- {schema.enum && schema.enum.length > 0 ? (
242
- <OpenAPISchemaEnum enumValues={schema.enum} />
243
- ) : null}
337
+ <OpenAPISchemaEnum schema={schema} />
244
338
  </div>
245
339
  );
246
340
  }
@@ -365,7 +459,7 @@ function getSchemaTitle(schema: OpenAPIV3.SchemaObject): string {
365
459
  // Otherwise try to infer a nice title
366
460
  let type = 'any';
367
461
 
368
- if (schema.enum) {
462
+ if (schema.enum || schema['x-enumDescriptions'] || schema['x-gitbook-enum']) {
369
463
  type = `${schema.type} · enum`;
370
464
  // check array AND schema.items as this is sometimes null despite what the type indicates
371
465
  } else if (schema.type === 'array' && !!schema.items) {
@@ -1,5 +1,6 @@
1
1
  import type { OpenAPIV3 } from '@gitbook/openapi-parser';
2
2
  import type React from 'react';
3
+ import { stringifyOpenAPI } from './stringifyOpenAPI';
3
4
 
4
5
  interface OpenAPISchemaNameProps {
5
6
  schema?: OpenAPIV3.SchemaObject;
@@ -31,7 +32,14 @@ export function OpenAPISchemaName(props: OpenAPISchemaNameProps) {
31
32
  ) : null}
32
33
  </span>
33
34
  {schema?.readOnly ? <span className="openapi-schema-readonly">read-only</span> : null}
34
- {required ? <span className="openapi-schema-required">required</span> : null}
35
+ {schema?.writeOnly ? (
36
+ <span className="openapi-schema-writeonly">write-only</span>
37
+ ) : null}
38
+ {required ? (
39
+ <span className="openapi-schema-required">required</span>
40
+ ) : (
41
+ <span className="openapi-schema-optional">optional</span>
42
+ )}
35
43
  {schema?.deprecated ? <span className="openapi-deprecated">Deprecated</span> : null}
36
44
  </div>
37
45
  );
@@ -40,17 +48,17 @@ export function OpenAPISchemaName(props: OpenAPISchemaNameProps) {
40
48
  function getAdditionalItems(schema: OpenAPIV3.SchemaObject): string {
41
49
  let additionalItems = '';
42
50
 
43
- if (schema.minimum || schema.minLength) {
44
- additionalItems += ` · min: ${schema.minimum || schema.minLength}`;
51
+ if (schema.minimum || schema.minLength || schema.minItems) {
52
+ additionalItems += ` · min: ${schema.minimum || schema.minLength || schema.minItems}`;
45
53
  }
46
54
 
47
- if (schema.maximum || schema.maxLength) {
48
- additionalItems += ` · max: ${schema.maximum || schema.maxLength}`;
55
+ if (schema.maximum || schema.maxLength || schema.maxItems) {
56
+ additionalItems += ` · max: ${schema.maximum || schema.maxLength || schema.maxItems}`;
49
57
  }
50
58
 
51
59
  // If the schema has a default value, we display it
52
60
  if (typeof schema.default !== 'undefined') {
53
- additionalItems += ` · default: ${schema.default}`;
61
+ additionalItems += ` · default: ${stringifyOpenAPI(schema.default)}`;
54
62
  }
55
63
 
56
64
  if (schema.nullable) {
@@ -0,0 +1,34 @@
1
+ import type { OpenAPIV3 } from '@gitbook/openapi-parser';
2
+ import {
3
+ OpenAPIRootSchemaFromServer,
4
+ OpenAPISchemaPropertiesFromServer,
5
+ type OpenAPISchemaPropertyEntry,
6
+ } from './OpenAPISchema';
7
+ import { decycle } from './decycle';
8
+ import type { OpenAPIClientContext } from './types';
9
+
10
+ export function OpenAPISchemaProperties(props: {
11
+ id?: string;
12
+ properties: OpenAPISchemaPropertyEntry[];
13
+ context: OpenAPIClientContext;
14
+ }) {
15
+ return (
16
+ <OpenAPISchemaPropertiesFromServer
17
+ id={props.id}
18
+ properties={JSON.stringify(props.properties, decycle())}
19
+ context={props.context}
20
+ />
21
+ );
22
+ }
23
+
24
+ export function OpenAPIRootSchema(props: {
25
+ schema: OpenAPIV3.SchemaObject;
26
+ context: OpenAPIClientContext;
27
+ }) {
28
+ return (
29
+ <OpenAPIRootSchemaFromServer
30
+ schema={JSON.stringify(props.schema, decycle())}
31
+ context={props.context}
32
+ />
33
+ );
34
+ }
@@ -2,18 +2,12 @@ import type { OpenAPI } from '@gitbook/openapi-parser';
2
2
 
3
3
  import { OpenAPIRequestBody } from './OpenAPIRequestBody';
4
4
  import { OpenAPIResponses } from './OpenAPIResponses';
5
- import { OpenAPISchemaProperties } from './OpenAPISchema';
5
+ import { OpenAPISchemaProperties } from './OpenAPISchemaServer';
6
6
  import { OpenAPISecurities } from './OpenAPISecurities';
7
7
  import { StaticSection } from './StaticSection';
8
8
  import type { OpenAPIClientContext, OpenAPIOperationData } from './types';
9
9
  import { parameterToProperty } from './utils';
10
10
 
11
- /**
12
- * Client component to render the spec for the request and response.
13
- *
14
- * We use a client component as rendering recursive JSON schema in the server is expensive
15
- * (the entire schema is rendered at once, while the client component only renders the visible part)
16
- */
17
11
  export function OpenAPISpec(props: { data: OpenAPIOperationData; context: OpenAPIClientContext }) {
18
12
  const { data, context } = props;
19
13
 
@@ -25,13 +19,13 @@ export function OpenAPISpec(props: { data: OpenAPIOperationData; context: OpenAP
25
19
  return (
26
20
  <>
27
21
  {securities.length > 0 ? (
28
- <OpenAPISecurities securities={securities} context={context} />
22
+ <OpenAPISecurities key="securities" securities={securities} context={context} />
29
23
  ) : null}
30
24
 
31
25
  {parameterGroups.map((group) => {
32
26
  return (
33
27
  <StaticSection
34
- key={group.key}
28
+ key={`parameter-${group.key}`}
35
29
  className="openapi-parameters"
36
30
  header={group.label}
37
31
  >
@@ -44,10 +38,18 @@ export function OpenAPISpec(props: { data: OpenAPIOperationData; context: OpenAP
44
38
  })}
45
39
 
46
40
  {operation.requestBody ? (
47
- <OpenAPIRequestBody requestBody={operation.requestBody} context={context} />
41
+ <OpenAPIRequestBody
42
+ key="body"
43
+ requestBody={operation.requestBody}
44
+ context={context}
45
+ />
48
46
  ) : null}
49
47
  {operation.responses ? (
50
- <OpenAPIResponses responses={operation.responses} context={context} />
48
+ <OpenAPIResponses
49
+ key="responses"
50
+ responses={operation.responses}
51
+ context={context}
52
+ />
51
53
  ) : null}
52
54
  </>
53
55
  );
@@ -137,21 +137,11 @@ export function OpenAPITabsPanels() {
137
137
  const key = selectedTab.key.toString();
138
138
 
139
139
  return (
140
- <TabPanel key={key} id={key} className="openapi-tabs-panel">
141
- {selectedTab.body}
140
+ <TabPanel id={key} className="openapi-tabs-panel">
141
+ <div className="openapi-tabs-body">{selectedTab.body}</div>
142
142
  {selectedTab.footer ? (
143
- <OpenAPITabsPanelFooter>{selectedTab.footer}</OpenAPITabsPanelFooter>
143
+ <div className="openapi-tabs-footer">{selectedTab.footer}</div>
144
144
  ) : null}
145
145
  </TabPanel>
146
146
  );
147
147
  }
148
-
149
- /**
150
- * The OpenAPI Tabs panel footer component.
151
- * This component should be used as a child of the OpenAPITabs component.
152
- */
153
- function OpenAPITabsPanelFooter(props: { children: React.ReactNode }) {
154
- const { children } = props;
155
-
156
- return <div className="openapi-tabs-footer">{children}</div>;
157
- }