@gitbook/react-openapi 1.0.2 → 1.0.3

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 (41) hide show
  1. package/CHANGELOG.md +16 -0
  2. package/dist/OpenAPICodeSample.jsx +11 -9
  3. package/dist/OpenAPIOperation.jsx +19 -5
  4. package/dist/OpenAPIResponseExample.jsx +3 -2
  5. package/dist/OpenAPISchema.jsx +47 -45
  6. package/dist/OpenAPISchemaName.d.ts +2 -1
  7. package/dist/OpenAPISchemaName.jsx +25 -4
  8. package/dist/OpenAPITabs.jsx +6 -2
  9. package/dist/code-samples.js +232 -10
  10. package/dist/contentTypeChecks.d.ts +9 -0
  11. package/dist/contentTypeChecks.js +27 -0
  12. package/dist/generateSchemaExample.js +1 -1
  13. package/dist/stringifyOpenAPI.d.ts +1 -1
  14. package/dist/stringifyOpenAPI.js +8 -2
  15. package/dist/tsconfig.build.tsbuildinfo +1 -1
  16. package/dist/types.d.ts +14 -2
  17. package/dist/util/server.d.ts +9 -0
  18. package/dist/{OpenAPIServerURL.jsx → util/server.js} +7 -28
  19. package/dist/utils.d.ts +1 -1
  20. package/dist/utils.js +3 -0
  21. package/package.json +2 -2
  22. package/src/OpenAPICodeSample.tsx +11 -9
  23. package/src/OpenAPIOperation.tsx +30 -8
  24. package/src/OpenAPIResponseExample.tsx +3 -2
  25. package/src/OpenAPISchema.tsx +73 -62
  26. package/src/OpenAPISchemaName.tsx +37 -5
  27. package/src/OpenAPITabs.tsx +8 -2
  28. package/src/code-samples.test.ts +594 -2
  29. package/src/code-samples.ts +231 -10
  30. package/src/contentTypeChecks.ts +35 -0
  31. package/src/generateSchemaExample.ts +20 -16
  32. package/src/stringifyOpenAPI.ts +13 -2
  33. package/src/types.ts +11 -1
  34. package/src/util/server.test.ts +58 -0
  35. package/src/util/server.ts +48 -0
  36. package/src/utils.ts +5 -1
  37. package/dist/OpenAPIServerURL.d.ts +0 -11
  38. package/dist/OpenAPIServerURLVariable.d.ts +0 -8
  39. package/dist/OpenAPIServerURLVariable.jsx +0 -8
  40. package/src/OpenAPIServerURL.tsx +0 -73
  41. package/src/OpenAPIServerURLVariable.tsx +0 -14
package/dist/types.d.ts CHANGED
@@ -1,13 +1,25 @@
1
1
  import type { OpenAPICustomOperationProperties, OpenAPICustomSpecProperties, OpenAPIV3 } from '@gitbook/openapi-parser';
2
2
  export interface OpenAPIContextProps extends OpenAPIClientContext {
3
- CodeBlock: React.ComponentType<{
3
+ /**
4
+ * Render a code block.
5
+ */
6
+ renderCodeBlock: (props: {
4
7
  code: string;
5
8
  syntax: string;
6
- }>;
9
+ }) => React.ReactNode;
10
+ /**
11
+ * Render the heading of the operation.
12
+ */
7
13
  renderHeading: (props: {
8
14
  deprecated: boolean;
9
15
  title: string;
10
16
  }) => React.ReactNode;
17
+ /**
18
+ * Render the document of the operation.
19
+ */
20
+ renderDocument: (props: {
21
+ document: object;
22
+ }) => React.ReactNode;
11
23
  /** Spec url for the Scalar Api Client */
12
24
  specUrl: string;
13
25
  }
@@ -0,0 +1,9 @@
1
+ import { OpenAPIV3 } from '@gitbook/openapi-parser';
2
+ /**
3
+ * Get the default URL for the server.
4
+ */
5
+ export declare function getDefaultServerURL(servers: OpenAPIV3.ServerObject[]): string;
6
+ /**
7
+ * Interpolate the server URL with the default values of the variables.
8
+ */
9
+ export declare function interpolateServerURL(server: OpenAPIV3.ServerObject): string;
@@ -1,40 +1,19 @@
1
- import { OpenAPIServerURLVariable } from './OpenAPIServerURLVariable';
2
1
  /**
3
- * Show the url of the server with variables replaced by their default values.
2
+ * Get the default URL for the server.
4
3
  */
5
- export function OpenAPIServerURL(props) {
6
- var _a;
7
- var servers = props.servers;
4
+ export function getDefaultServerURL(servers) {
8
5
  var server = servers[0];
9
6
  if (!server) {
10
- return null;
7
+ // Return empty string if no server is found to display nothing
8
+ return '';
11
9
  }
12
- var parts = parseServerURL((_a = server === null || server === void 0 ? void 0 : server.url) !== null && _a !== void 0 ? _a : '');
13
- return (<span>
14
- {parts.map(function (part, i) {
15
- var _a;
16
- if (part.kind === 'text') {
17
- return <span key={i}>{part.text}</span>;
18
- }
19
- else {
20
- var variable = (_a = server.variables) === null || _a === void 0 ? void 0 : _a[part.name];
21
- if (!variable) {
22
- return <span key={i}>{"{".concat(part.name, "}")}</span>;
23
- }
24
- return (<OpenAPIServerURLVariable key={i} name={part.name} variable={variable}/>);
25
- }
26
- })}
27
- </span>);
10
+ return interpolateServerURL(server);
28
11
  }
29
12
  /**
30
- * Get the default URL for the server.
13
+ * Interpolate the server URL with the default values of the variables.
31
14
  */
32
- export function getServersURL(servers) {
15
+ export function interpolateServerURL(server) {
33
16
  var _a;
34
- var server = servers[0];
35
- if (!server) {
36
- return '';
37
- }
38
17
  var parts = parseServerURL((_a = server === null || server === void 0 ? void 0 : server.url) !== null && _a !== void 0 ? _a : '');
39
18
  return parts
40
19
  .map(function (part) {
package/dist/utils.d.ts CHANGED
@@ -4,7 +4,7 @@ export declare function createStateKey(key: string, scope?: string): string;
4
4
  /**
5
5
  * Resolve the description of an object.
6
6
  */
7
- export declare function resolveDescription(object: AnyObject): string | undefined;
7
+ export declare function resolveDescription(object: OpenAPIV3.SchemaObject | AnyObject): string | undefined;
8
8
  /**
9
9
  * Extract descriptions from an object.
10
10
  */
package/dist/utils.js CHANGED
@@ -19,6 +19,9 @@ export function createStateKey(key, scope) {
19
19
  * Resolve the description of an object.
20
20
  */
21
21
  export function resolveDescription(object) {
22
+ if ('items' in object && object.items) {
23
+ return resolveDescription(object.items);
24
+ }
22
25
  return 'x-gitbook-description-html' in object &&
23
26
  typeof object['x-gitbook-description-html'] === 'string'
24
27
  ? object['x-gitbook-description-html'].trim()
package/package.json CHANGED
@@ -8,7 +8,7 @@
8
8
  "default": "./dist/index.js"
9
9
  }
10
10
  },
11
- "version": "1.0.2",
11
+ "version": "1.0.3",
12
12
  "sideEffects": false,
13
13
  "dependencies": {
14
14
  "@gitbook/openapi-parser": "workspace:*",
@@ -30,7 +30,7 @@
30
30
  "react": "*"
31
31
  },
32
32
  "scripts": {
33
- "build": "tsc --project tsconfig.build.json",
33
+ "build": "rm -rf ./dist && tsc --project tsconfig.build.json",
34
34
  "typecheck": "tsc --noEmit",
35
35
  "unit": "bun test",
36
36
  "dev": "bun run build -- --watch",
@@ -1,12 +1,12 @@
1
1
  import { CodeSampleInput, codeSampleGenerators } from './code-samples';
2
2
  import { generateMediaTypeExample, generateSchemaExample } from './generateSchemaExample';
3
3
  import { InteractiveSection } from './InteractiveSection';
4
- import { getServersURL } from './OpenAPIServerURL';
5
4
  import type { OpenAPIContextProps, OpenAPIOperationData } from './types';
6
5
  import { createStateKey } from './utils';
7
6
  import { stringifyOpenAPI } from './stringifyOpenAPI';
8
7
  import { OpenAPITabs, OpenAPITabsList, OpenAPITabsPanels } from './OpenAPITabs';
9
8
  import { checkIsReference } from './utils';
9
+ import { getDefaultServerURL } from './util/server';
10
10
 
11
11
  /**
12
12
  * Display code samples to execute the operation.
@@ -53,15 +53,11 @@ export function OpenAPICodeSample(props: {
53
53
 
54
54
  const input: CodeSampleInput = {
55
55
  url:
56
- getServersURL(data.servers) +
56
+ getDefaultServerURL(data.servers) +
57
57
  data.path +
58
58
  (searchParams.size ? `?${searchParams.toString()}` : ''),
59
59
  method: data.method,
60
- body: requestBodyContent
61
- ? generateMediaTypeExample(requestBodyContent[1], {
62
- omitEmptyAndOptionalProperties: true,
63
- })
64
- : undefined,
60
+ body: requestBodyContent ? generateMediaTypeExample(requestBodyContent[1]) : undefined,
65
61
  headers: {
66
62
  ...getSecurityHeaders(data.securities),
67
63
  ...headersObject,
@@ -76,7 +72,10 @@ export function OpenAPICodeSample(props: {
76
72
  const autoCodeSamples = codeSampleGenerators.map((generator) => ({
77
73
  key: `default-${generator.id}`,
78
74
  label: generator.label,
79
- body: <context.CodeBlock code={generator.generate(input)} syntax={generator.syntax} />,
75
+ body: context.renderCodeBlock({
76
+ code: generator.generate(input),
77
+ syntax: generator.syntax,
78
+ }),
80
79
  }));
81
80
 
82
81
  // Use custom samples if defined
@@ -99,7 +98,10 @@ export function OpenAPICodeSample(props: {
99
98
  .map((sample) => ({
100
99
  key: `redocly-${sample.lang}`,
101
100
  label: sample.label,
102
- body: <context.CodeBlock code={sample.source} syntax={sample.lang} />,
101
+ body: context.renderCodeBlock({
102
+ code: sample.source,
103
+ syntax: sample.lang,
104
+ }),
103
105
  }));
104
106
  }
105
107
  });
@@ -7,6 +7,7 @@ import { OpenAPISpec } from './OpenAPISpec';
7
7
  import type { OpenAPIClientContext, OpenAPIContextProps, OpenAPIOperationData } from './types';
8
8
  import { OpenAPIPath } from './OpenAPIPath';
9
9
  import { resolveDescription } from './utils';
10
+ import { OpenAPICustomOperationProperties, OpenAPIV3 } from '@gitbook/openapi-parser';
10
11
 
11
12
  /**
12
13
  * Display an interactive OpenAPI operation.
@@ -25,11 +26,9 @@ export function OpenAPIOperation(props: {
25
26
  blockKey: context.blockKey,
26
27
  };
27
28
 
28
- const description = resolveDescription(operation);
29
-
30
29
  return (
31
30
  <div className={clsx('openapi-operation', className)}>
32
- <div className="openapi-summary">
31
+ <div className="openapi-summary" id={operation.summary ? undefined : context.id}>
33
32
  {operation.summary
34
33
  ? context.renderHeading({
35
34
  deprecated: operation.deprecated ?? false,
@@ -49,11 +48,7 @@ export function OpenAPIOperation(props: {
49
48
  {`.`}
50
49
  </div>
51
50
  ) : 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} />
57
52
  <OpenAPIPath data={data} context={context} />
58
53
  <OpenAPISpec data={data} context={clientContext} />
59
54
  </div>
@@ -67,3 +62,30 @@ export function OpenAPIOperation(props: {
67
62
  </div>
68
63
  );
69
64
  }
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
+ }
@@ -5,6 +5,7 @@ import { checkIsReference, createStateKey, resolveDescription } from './utils';
5
5
  import { OpenAPITabs, OpenAPITabsList, OpenAPITabsPanels } from './OpenAPITabs';
6
6
  import { InteractiveSection } from './InteractiveSection';
7
7
  import { json2xml } from './json2xml';
8
+ import { stringifyOpenAPI } from './stringifyOpenAPI';
8
9
 
9
10
  /**
10
11
  * Display an example of the response content.
@@ -208,7 +209,7 @@ function OpenAPIExample(props: {
208
209
  return <OpenAPIEmptyResponseExample />;
209
210
  }
210
211
 
211
- return <context.CodeBlock code={code} syntax={syntax} />;
212
+ return context.renderCodeBlock({ code, syntax });
212
213
  }
213
214
 
214
215
  function stringifyExample(args: { example: OpenAPIV3.ExampleObject; xml: boolean }): string | null {
@@ -226,7 +227,7 @@ function stringifyExample(args: { example: OpenAPIV3.ExampleObject; xml: boolean
226
227
  return json2xml(example.value);
227
228
  }
228
229
 
229
- return JSON.stringify(example.value, null, 2);
230
+ return stringifyOpenAPI(example.value, null, 2);
230
231
  }
231
232
 
232
233
  /**
@@ -47,23 +47,6 @@ export function OpenAPISchemaProperty(
47
47
  ? null
48
48
  : getSchemaAlternatives(schema, new Set(circularRefs.keys()));
49
49
 
50
- if ((properties && properties.length > 0) || schema.type === 'object') {
51
- return (
52
- <InteractiveSection id={id} className={clsx('openapi-schema', className)}>
53
- <OpenAPISchemaPresentation {...props} />
54
- {properties && properties.length > 0 ? (
55
- <OpenAPIDisclosure context={context}>
56
- <OpenAPISchemaProperties
57
- properties={properties}
58
- circularRefs={circularRefs}
59
- context={context}
60
- />
61
- </OpenAPIDisclosure>
62
- ) : null}
63
- </InteractiveSection>
64
- );
65
- }
66
-
67
50
  if (alternatives?.[0]?.length) {
68
51
  return (
69
52
  <InteractiveSection id={id} className={clsx('openapi-schema', className)}>
@@ -76,6 +59,29 @@ export function OpenAPISchemaProperty(
76
59
  context={context}
77
60
  />
78
61
  ))}
62
+ {parentCircularRef ? (
63
+ <OpenAPISchemaCircularRef id={parentCircularRef} schema={schema} />
64
+ ) : null}
65
+ </InteractiveSection>
66
+ );
67
+ }
68
+
69
+ if ((properties && properties.length > 0) || schema.type === 'object') {
70
+ return (
71
+ <InteractiveSection id={id} className={clsx('openapi-schema', className)}>
72
+ <OpenAPISchemaPresentation {...props} />
73
+ {properties && properties.length > 0 ? (
74
+ <OpenAPIDisclosure context={context} label={getDisclosureLabel(schema)}>
75
+ <OpenAPISchemaProperties
76
+ properties={properties}
77
+ circularRefs={circularRefs}
78
+ context={context}
79
+ />
80
+ </OpenAPIDisclosure>
81
+ ) : null}
82
+ {parentCircularRef ? (
83
+ <OpenAPISchemaCircularRef id={parentCircularRef} schema={schema} />
84
+ ) : null}
79
85
  </InteractiveSection>
80
86
  );
81
87
  }
@@ -166,16 +172,24 @@ function OpenAPISchemaAlternative(props: {
166
172
  const { schema, circularRefs, context } = props;
167
173
  const id = useId();
168
174
  const subProperties = getSchemaProperties(schema);
175
+ const description = resolveDescription(schema);
169
176
 
170
177
  return (
171
- <OpenAPIDisclosure context={context}>
172
- <OpenAPISchemaProperties
173
- id={id}
174
- properties={subProperties ?? [{ schema }]}
175
- circularRefs={subProperties ? new Map(circularRefs).set(schema, id) : circularRefs}
176
- context={context}
177
- />
178
- </OpenAPIDisclosure>
178
+ <>
179
+ {description ? (
180
+ <Markdown source={description} className="openapi-schema-description" />
181
+ ) : null}
182
+ <OpenAPIDisclosure context={context} label={getDisclosureLabel(schema)}>
183
+ <OpenAPISchemaProperties
184
+ id={id}
185
+ properties={subProperties ?? [{ schema }]}
186
+ circularRefs={
187
+ subProperties ? new Map(circularRefs).set(schema, id) : circularRefs
188
+ }
189
+ context={context}
190
+ />
191
+ </OpenAPIDisclosure>
192
+ </>
179
193
  );
180
194
  }
181
195
 
@@ -219,7 +233,7 @@ export function OpenAPISchemaPresentation(props: OpenAPISchemaPropertyEntry) {
219
233
 
220
234
  const shouldDisplayExample = (schema: OpenAPIV3.SchemaObject): boolean => {
221
235
  return (
222
- typeof schema.example === 'string' ||
236
+ (typeof schema.example === 'string' && !!schema.example) ||
223
237
  typeof schema.example === 'number' ||
224
238
  typeof schema.example === 'boolean' ||
225
239
  (Array.isArray(schema.example) && schema.example.length > 0) ||
@@ -234,10 +248,10 @@ export function OpenAPISchemaPresentation(props: OpenAPISchemaPropertyEntry) {
234
248
  return (
235
249
  <div className="openapi-schema-presentation">
236
250
  <OpenAPISchemaName
251
+ schema={schema}
237
252
  type={getSchemaTitle(schema)}
238
253
  propertyName={propertyName}
239
254
  required={required}
240
- deprecated={schema.deprecated}
241
255
  />
242
256
  {schema['x-deprecated-sunset'] ? (
243
257
  <div className="openapi-deprecated-sunset openapi-schema-description openapi-markdown">
@@ -252,12 +266,7 @@ export function OpenAPISchemaPresentation(props: OpenAPISchemaPropertyEntry) {
252
266
  ) : null}
253
267
  {shouldDisplayExample(schema) ? (
254
268
  <div className="openapi-schema-example">
255
- Example:{' '}
256
- <code>
257
- {typeof schema.example === 'string'
258
- ? schema.example
259
- : stringifyOpenAPI(schema.example)}
260
- </code>
269
+ Example: <code>{formatExample(schema.example)}</code>
261
270
  </div>
262
271
  ) : null}
263
272
  {schema.pattern ? (
@@ -276,17 +285,6 @@ export function OpenAPISchemaPresentation(props: OpenAPISchemaPropertyEntry) {
276
285
  * Get the sub-properties of a schema.
277
286
  */
278
287
  function getSchemaProperties(schema: OpenAPIV3.SchemaObject): null | OpenAPISchemaPropertyEntry[] {
279
- if (schema.allOf) {
280
- return schema.allOf.reduce((acc, subSchema) => {
281
- const properties = getSchemaProperties(subSchema) ?? [
282
- {
283
- schema: subSchema,
284
- },
285
- ];
286
- return [...acc, ...properties];
287
- }, [] as OpenAPISchemaPropertyEntry[]);
288
- }
289
-
290
288
  // check array AND schema.items as this is sometimes null despite what the type indicates
291
289
  if (schema.type === 'array' && !!schema.items) {
292
290
  const items = schema.items;
@@ -295,6 +293,11 @@ function getSchemaProperties(schema: OpenAPIV3.SchemaObject): null | OpenAPISche
295
293
  return itemProperties;
296
294
  }
297
295
 
296
+ // If the items are a primitive type, we don't need to display them
297
+ if (['string', 'number', 'boolean', 'integer'].includes(items.type) && !items.enum) {
298
+ return null;
299
+ }
300
+
298
301
  return [
299
302
  {
300
303
  propertyName: 'items',
@@ -351,8 +354,7 @@ export function getSchemaAlternatives(
351
354
  }
352
355
 
353
356
  if (schema.allOf) {
354
- // allOf is managed in `getSchemaProperties`
355
- return null;
357
+ return [flattenAlternatives('allOf', schema.allOf, downAncestors), schema.discriminator];
356
358
  }
357
359
 
358
360
  return null;
@@ -378,11 +380,6 @@ export function getSchemaTitle(
378
380
  /** If the title is inferred in a oneOf with discriminator, we can use it to optimize the title */
379
381
  discriminator?: OpenAPIV3.DiscriminatorObject,
380
382
  ): string {
381
- if (schema.title) {
382
- // If the schema has a title, use it
383
- return schema.title;
384
- }
385
-
386
383
  // Try using the discriminator
387
384
  if (discriminator?.propertyName && schema.properties) {
388
385
  const discriminatorProperty = schema.properties[discriminator.propertyName];
@@ -419,21 +416,35 @@ export function getSchemaTitle(
419
416
  type = 'not';
420
417
  }
421
418
 
422
- if (schema.minimum || schema.minLength) {
423
- type += ` · min: ${schema.minimum || schema.minLength}`;
424
- }
419
+ return type;
420
+ }
425
421
 
426
- if (schema.maximum || schema.maxLength) {
427
- type += ` · max: ${schema.maximum || schema.maxLength}`;
428
- }
422
+ function getDisclosureLabel(schema: OpenAPIV3.SchemaObject): string | undefined {
423
+ if (schema.type === 'array' && !!schema.items) {
424
+ if (schema.items.oneOf) {
425
+ return 'available items';
426
+ }
427
+
428
+ // Fallback to "child attributes" for enums and objects
429
+ if (schema.items.enum || schema.items.type === 'object') {
430
+ return;
431
+ }
429
432
 
430
- if (schema.default) {
431
- type += ` · default: ${schema.default}`;
433
+ return schema.items.title ?? schema.title ?? getSchemaTitle(schema.items);
432
434
  }
433
435
 
434
- if (schema.nullable) {
435
- type = `${type} | nullable`;
436
+ return schema.title;
437
+ }
438
+
439
+ function formatExample(example: any): string {
440
+ if (typeof example === 'string') {
441
+ return example
442
+ .replace(/\n/g, ' ') // Replace newlines with spaces
443
+ .replace(/\s+/g, ' ') // Collapse multiple spaces/newlines into a single space
444
+ .replace(/([\{\}:,])\s+/g, '$1 ') // Ensure a space after {, }, :, and ,
445
+ .replace(/\s+([\{\}:,])/g, ' $1') // Ensure a space before {, }, :, and ,
446
+ .trim();
436
447
  }
437
448
 
438
- return type;
449
+ return stringifyOpenAPI(example);
439
450
  }
@@ -1,8 +1,10 @@
1
+ import { OpenAPIV3 } from '@gitbook/openapi-parser';
2
+
1
3
  interface OpenAPISchemaNameProps {
4
+ schema?: OpenAPIV3.SchemaObject;
2
5
  propertyName?: string | JSX.Element;
3
6
  required?: boolean;
4
7
  type?: string;
5
- deprecated?: boolean;
6
8
  }
7
9
 
8
10
  /**
@@ -10,18 +12,48 @@ interface OpenAPISchemaNameProps {
10
12
  * It includes the property name, type, required and deprecated status.
11
13
  */
12
14
  export function OpenAPISchemaName(props: OpenAPISchemaNameProps): JSX.Element {
13
- const { type, propertyName, required, deprecated } = props;
15
+ const { schema, type, propertyName, required } = props;
16
+
17
+ const additionalItems = schema && getAdditionalItems(schema);
14
18
 
15
19
  return (
16
20
  <div className="openapi-schema-name">
17
21
  {propertyName ? (
18
- <span data-deprecated={deprecated} className="openapi-schema-propertyname">
22
+ <span data-deprecated={schema?.deprecated} className="openapi-schema-propertyname">
19
23
  {propertyName}
20
24
  </span>
21
25
  ) : null}
22
- {type ? <span className="openapi-schema-type">{type}</span> : null}
26
+ <span>
27
+ {type ? <span className="openapi-schema-type">{type}</span> : null}
28
+ {additionalItems ? (
29
+ <span className="openapi-schema-type">{additionalItems}</span>
30
+ ) : null}
31
+ </span>
23
32
  {required ? <span className="openapi-schema-required">required</span> : null}
24
- {deprecated ? <span className="openapi-deprecated">Deprecated</span> : null}
33
+ {schema?.deprecated ? <span className="openapi-deprecated">Deprecated</span> : null}
25
34
  </div>
26
35
  );
27
36
  }
37
+
38
+ function getAdditionalItems(schema: OpenAPIV3.SchemaObject): string {
39
+ let additionalItems = '';
40
+
41
+ if (schema.minimum || schema.minLength) {
42
+ additionalItems += ` · min: ${schema.minimum || schema.minLength}`;
43
+ }
44
+
45
+ if (schema.maximum || schema.maxLength) {
46
+ additionalItems += ` · max: ${schema.maximum || schema.maxLength}`;
47
+ }
48
+
49
+ // If the schema has a default value, we display it
50
+ if (typeof schema.default !== 'undefined') {
51
+ additionalItems += ` · default: ${schema.default}`;
52
+ }
53
+
54
+ if (schema.nullable) {
55
+ additionalItems = ` | nullable`;
56
+ }
57
+
58
+ return additionalItems;
59
+ }
@@ -74,11 +74,17 @@ export function OpenAPITabs(
74
74
  const tabFromState = syncedTabs.get(stateKey);
75
75
 
76
76
  if (!items.some((item) => item.key === tabFromState?.key)) {
77
- return;
77
+ return setSelectedTab(defaultTab);
78
78
  }
79
79
 
80
80
  if (tabFromState && tabFromState?.key !== selectedTab?.key) {
81
- setSelectedTab(tabFromState);
81
+ const tabFromItems = items.find((item) => item.key === tabFromState.key);
82
+
83
+ if (!tabFromItems) {
84
+ return;
85
+ }
86
+
87
+ setSelectedTab(tabFromItems);
82
88
  }
83
89
  }
84
90
  }, [isVisible, stateKey, syncedTabs, selectedTabKey]);