@gitbook/react-openapi 1.1.8 → 1.1.10

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 (65) hide show
  1. package/CHANGELOG.md +21 -0
  2. package/dist/InteractiveSection.jsx +7 -6
  3. package/dist/OpenAPICodeSample.d.ts +2 -2
  4. package/dist/OpenAPICodeSample.jsx +3 -8
  5. package/dist/OpenAPICodeSampleInteractive.jsx +31 -19
  6. package/dist/OpenAPICodeSampleSelector.d.ts +15 -0
  7. package/dist/OpenAPICodeSampleSelector.jsx +49 -0
  8. package/dist/OpenAPIExample.d.ts +34 -0
  9. package/dist/OpenAPIExample.jsx +103 -0
  10. package/dist/OpenAPIOperation.d.ts +2 -2
  11. package/dist/OpenAPIOperation.jsx +3 -7
  12. package/dist/OpenAPIPath.d.ts +10 -2
  13. package/dist/OpenAPIPath.jsx +9 -4
  14. package/dist/OpenAPIResponse.jsx +3 -3
  15. package/dist/OpenAPIResponseExample.d.ts +2 -2
  16. package/dist/OpenAPIResponseExample.jsx +4 -90
  17. package/dist/OpenAPIResponses.jsx +23 -10
  18. package/dist/OpenAPISchema.jsx +26 -15
  19. package/dist/OpenAPISchemaName.jsx +2 -7
  20. package/dist/OpenAPISecurities.jsx +6 -6
  21. package/dist/OpenAPISelect.d.ts +15 -0
  22. package/dist/OpenAPISelect.jsx +32 -0
  23. package/dist/OpenAPITabs.jsx +9 -9
  24. package/dist/context.d.ts +54 -0
  25. package/dist/context.js +11 -0
  26. package/dist/generateSchemaExample.d.ts +1 -1
  27. package/dist/generateSchemaExample.js +28 -26
  28. package/dist/getOrCreateStoreByKey.d.ts +10 -0
  29. package/dist/getOrCreateStoreByKey.js +20 -0
  30. package/dist/index.d.ts +1 -1
  31. package/dist/resolveOpenAPIOperation.js +10 -5
  32. package/dist/schemas/OpenAPISchemas.d.ts +5 -6
  33. package/dist/schemas/OpenAPISchemas.jsx +45 -38
  34. package/dist/schemas/resolveOpenAPISchemas.d.ts +4 -3
  35. package/dist/schemas/resolveOpenAPISchemas.js +0 -1
  36. package/dist/tsconfig.build.tsbuildinfo +1 -1
  37. package/dist/types.d.ts +32 -26
  38. package/package.json +1 -1
  39. package/src/InteractiveSection.tsx +10 -8
  40. package/src/OpenAPICodeSample.tsx +8 -15
  41. package/src/OpenAPICodeSampleInteractive.tsx +43 -26
  42. package/src/OpenAPICodeSampleSelector.tsx +87 -0
  43. package/src/OpenAPIExample.tsx +129 -0
  44. package/src/OpenAPIOperation.tsx +6 -10
  45. package/src/OpenAPIPath.tsx +23 -6
  46. package/src/OpenAPIResponse.tsx +9 -7
  47. package/src/OpenAPIResponseExample.tsx +13 -113
  48. package/src/OpenAPIResponses.tsx +37 -12
  49. package/src/OpenAPISchema.tsx +40 -25
  50. package/src/OpenAPISchemaName.tsx +2 -8
  51. package/src/OpenAPISecurities.tsx +22 -9
  52. package/src/OpenAPISelect.tsx +70 -0
  53. package/src/OpenAPITabs.tsx +9 -9
  54. package/src/context.ts +64 -0
  55. package/src/generateSchemaExample.test.ts +1020 -0
  56. package/src/generateSchemaExample.ts +103 -36
  57. package/src/getOrCreateStoreByKey.ts +35 -0
  58. package/src/index.ts +1 -1
  59. package/src/resolveOpenAPIOperation.ts +14 -3
  60. package/src/schemas/OpenAPISchemas.tsx +75 -70
  61. package/src/schemas/resolveOpenAPISchemas.ts +4 -5
  62. package/src/types.ts +36 -29
  63. package/dist/useSyncedTabsGlobalState.d.ts +0 -10
  64. package/dist/useSyncedTabsGlobalState.js +0 -20
  65. package/src/useSyncedTabsGlobalState.ts +0 -35
package/dist/types.d.ts CHANGED
@@ -1,5 +1,28 @@
1
- import type { OpenAPICustomOperationProperties, OpenAPICustomSpecProperties, OpenAPISchema, OpenAPIV3 } from '@gitbook/openapi-parser';
2
- export interface OpenAPIContextProps extends OpenAPIClientContext {
1
+ import type { OpenAPICustomOperationProperties, OpenAPICustomSpecProperties, OpenAPIV3 } from '@gitbook/openapi-parser';
2
+ export interface OpenAPIClientContext {
3
+ /**
4
+ * Icons used in the block.
5
+ */
6
+ icons: {
7
+ chevronDown: React.ReactNode;
8
+ chevronRight: React.ReactNode;
9
+ plus: React.ReactNode;
10
+ };
11
+ /**
12
+ * Force all sections to be opened by default.
13
+ * @default false
14
+ */
15
+ defaultInteractiveOpened?: boolean;
16
+ /**
17
+ * The key of the block
18
+ */
19
+ blockKey?: string;
20
+ /**
21
+ * Optional id attached to the heading and used as an anchor.
22
+ */
23
+ id?: string;
24
+ }
25
+ export interface OpenAPIContext extends OpenAPIClientContext {
3
26
  /**
4
27
  * Render a code block.
5
28
  */
@@ -11,7 +34,7 @@ export interface OpenAPIContextProps extends OpenAPIClientContext {
11
34
  * Render the heading of the operation.
12
35
  */
13
36
  renderHeading: (props: {
14
- deprecated: boolean;
37
+ deprecated?: boolean;
15
38
  title: string;
16
39
  stability?: string;
17
40
  }) => React.ReactNode;
@@ -21,27 +44,14 @@ export interface OpenAPIContextProps extends OpenAPIClientContext {
21
44
  renderDocument: (props: {
22
45
  document: object;
23
46
  }) => React.ReactNode;
24
- /** Spec url for the Scalar Api Client */
25
- specUrl: string;
26
- }
27
- export interface OpenAPIClientContext {
28
- icons: {
29
- chevronDown: React.ReactNode;
30
- chevronRight: React.ReactNode;
31
- plus: React.ReactNode;
32
- };
33
47
  /**
34
- * Force all sections to be opened by default.
35
- * @default false
36
- */
37
- defaultInteractiveOpened?: boolean;
38
- /**
39
- * The key of the block
48
+ * Specification URL.
40
49
  */
41
- blockKey?: string;
42
- /** Optional id attached to the OpenAPI Operation heading and used as an anchor */
43
- id?: string;
50
+ specUrl: string;
44
51
  }
52
+ export type OpenAPISecurityWithRequired = OpenAPIV3.SecuritySchemeObject & {
53
+ required?: boolean;
54
+ };
45
55
  export interface OpenAPIOperationData extends OpenAPICustomSpecProperties {
46
56
  path: string;
47
57
  method: string;
@@ -50,9 +60,5 @@ export interface OpenAPIOperationData extends OpenAPICustomSpecProperties {
50
60
  /** Spec of the operation */
51
61
  operation: OpenAPIV3.OperationObject<OpenAPICustomOperationProperties>;
52
62
  /** Securities that should be used for this operation */
53
- securities: [string, OpenAPIV3.SecuritySchemeObject][];
54
- }
55
- export interface OpenAPISchemasData {
56
- /** Components schemas to be used for schemas */
57
- schemas: OpenAPISchema[];
63
+ securities: [string, OpenAPISecurityWithRequired][];
58
64
  }
package/package.json CHANGED
@@ -8,7 +8,7 @@
8
8
  "default": "./dist/index.js"
9
9
  }
10
10
  },
11
- "version": "1.1.8",
11
+ "version": "1.1.10",
12
12
  "sideEffects": false,
13
13
  "dependencies": {
14
14
  "@gitbook/openapi-parser": "workspace:*",
@@ -4,6 +4,7 @@ import clsx from 'clsx';
4
4
  import { useRef, useState } from 'react';
5
5
  import { mergeProps, useButton, useDisclosure, useFocusRing } from 'react-aria';
6
6
  import { useDisclosureState } from 'react-stately';
7
+ import { OpenAPISelect, OpenAPISelectItem } from './OpenAPISelect';
7
8
  import { Section, SectionBody, SectionHeader, SectionHeaderContent } from './StaticSection';
8
9
 
9
10
  interface InteractiveSectionTab {
@@ -106,24 +107,25 @@ export function InteractiveSection(props: {
106
107
  }}
107
108
  >
108
109
  {tabs.length > 1 ? (
109
- <select
110
+ <OpenAPISelect
110
111
  className={clsx(
111
112
  'openapi-section-select',
112
- 'openapi-select',
113
113
  `${className}-tabs-select`
114
114
  )}
115
- value={selectedTab?.key ?? ''}
116
- onChange={(event) => {
117
- setSelectedTab(event.target.value);
115
+ items={tabs}
116
+ selectedKey={selectedTab?.key ?? ''}
117
+ onSelectionChange={(key) => {
118
+ setSelectedTab(String(key));
118
119
  state.expand();
119
120
  }}
121
+ placement="bottom end"
120
122
  >
121
123
  {tabs.map((tab) => (
122
- <option key={tab.key} value={tab.key}>
124
+ <OpenAPISelectItem key={tab.key} id={tab.key} value={tab}>
123
125
  {tab.label}
124
- </option>
126
+ </OpenAPISelectItem>
125
127
  ))}
126
- </select>
128
+ </OpenAPISelect>
127
129
  ) : null}
128
130
  </div>
129
131
  </SectionHeader>
@@ -3,15 +3,14 @@ import {
3
3
  OpenAPIMediaTypeExamplesBody,
4
4
  OpenAPIMediaTypeExamplesSelector,
5
5
  } from './OpenAPICodeSampleInteractive';
6
- import { OpenAPITabs, OpenAPITabsList, OpenAPITabsPanels } from './OpenAPITabs';
6
+ import { OpenAPICodeSampleBody } from './OpenAPICodeSampleSelector';
7
7
  import { ScalarApiButton } from './ScalarApiButton';
8
- import { StaticSection } from './StaticSection';
9
8
  import { type CodeSampleGenerator, codeSampleGenerators } from './code-samples';
10
9
  import { generateMediaTypeExamples, generateSchemaExample } from './generateSchemaExample';
11
10
  import { stringifyOpenAPI } from './stringifyOpenAPI';
12
- import type { OpenAPIContextProps, OpenAPIOperationData } from './types';
11
+ import type { OpenAPIContext, OpenAPIOperationData } from './types';
13
12
  import { getDefaultServerURL } from './util/server';
14
- import { checkIsReference, createStateKey } from './utils';
13
+ import { checkIsReference } from './utils';
15
14
 
16
15
  const CUSTOM_CODE_SAMPLES_KEYS = ['x-custom-examples', 'x-code-samples', 'x-codeSamples'] as const;
17
16
 
@@ -21,7 +20,7 @@ const CUSTOM_CODE_SAMPLES_KEYS = ['x-custom-examples', 'x-code-samples', 'x-code
21
20
  */
22
21
  export function OpenAPICodeSample(props: {
23
22
  data: OpenAPIOperationData;
24
- context: OpenAPIContextProps;
23
+ context: OpenAPIContext;
25
24
  }) {
26
25
  const { data } = props;
27
26
 
@@ -44,13 +43,7 @@ export function OpenAPICodeSample(props: {
44
43
  return null;
45
44
  }
46
45
 
47
- return (
48
- <OpenAPITabs stateKey={createStateKey('codesample')} items={samples}>
49
- <StaticSection header={<OpenAPITabsList />} className="openapi-codesample">
50
- <OpenAPITabsPanels />
51
- </StaticSection>
52
- </OpenAPITabs>
53
- );
46
+ return <OpenAPICodeSampleBody data={data} items={samples} />;
54
47
  }
55
48
 
56
49
  /**
@@ -58,7 +51,7 @@ export function OpenAPICodeSample(props: {
58
51
  */
59
52
  function generateCodeSamples(props: {
60
53
  data: OpenAPIOperationData;
61
- context: OpenAPIContextProps;
54
+ context: OpenAPIContext;
62
55
  }) {
63
56
  const { data, context } = props;
64
57
 
@@ -189,7 +182,7 @@ export interface MediaTypeRenderer {
189
182
  function OpenAPICodeSampleFooter(props: {
190
183
  data: OpenAPIOperationData;
191
184
  renderers: MediaTypeRenderer[];
192
- context: OpenAPIContextProps;
185
+ context: OpenAPIContext;
193
186
  }) {
194
187
  const { data, context, renderers } = props;
195
188
  const { method, path } = data;
@@ -227,7 +220,7 @@ function OpenAPICodeSampleFooter(props: {
227
220
  */
228
221
  function getCustomCodeSamples(props: {
229
222
  data: OpenAPIOperationData;
230
- context: OpenAPIContextProps;
223
+ context: OpenAPIContext;
231
224
  }) {
232
225
  const { data, context } = props;
233
226
 
@@ -3,7 +3,8 @@ import clsx from 'clsx';
3
3
  import { useCallback } from 'react';
4
4
  import { useStore } from 'zustand';
5
5
  import type { MediaTypeRenderer } from './OpenAPICodeSample';
6
- import { getOrCreateTabStoreByKey } from './useSyncedTabsGlobalState';
6
+ import { OpenAPISelect, OpenAPISelectItem } from './OpenAPISelect';
7
+ import { getOrCreateStoreByKey } from './getOrCreateStoreByKey';
7
8
 
8
9
  type MediaTypeState = {
9
10
  mediaType: string;
@@ -15,27 +16,27 @@ function useMediaTypeState(
15
16
  defaultKey: string
16
17
  ): MediaTypeState {
17
18
  const { method, path } = data;
18
- const store = useStore(getOrCreateTabStoreByKey(`media-type-${method}-${path}`, defaultKey));
19
- if (typeof store.tabKey !== 'string') {
19
+ const store = useStore(getOrCreateStoreByKey(`media-type-${method}-${path}`, defaultKey));
20
+ if (typeof store.key !== 'string') {
20
21
  throw new Error('Media type key is not a string');
21
22
  }
22
23
  return {
23
- mediaType: store.tabKey,
24
- setMediaType: useCallback((index: string) => store.setTabKey(index), [store.setTabKey]),
24
+ mediaType: store.key,
25
+ setMediaType: useCallback((index: string) => store.setKey(index), [store.setKey]),
25
26
  };
26
27
  }
27
28
 
28
29
  function useMediaTypeSampleIndexState(data: { method: string; path: string }, mediaType: string) {
29
30
  const { method, path } = data;
30
31
  const store = useStore(
31
- getOrCreateTabStoreByKey(`media-type-sample-${mediaType}-${method}-${path}`, 0)
32
+ getOrCreateStoreByKey(`media-type-sample-${mediaType}-${method}-${path}`, 0)
32
33
  );
33
- if (typeof store.tabKey !== 'number') {
34
+ if (typeof store.key !== 'number') {
34
35
  throw new Error('Example key is not a number');
35
36
  }
36
37
  return {
37
- index: store.tabKey,
38
- setIndex: useCallback((index: number) => store.setTabKey(index), [store.setTabKey]),
38
+ index: store.key,
39
+ setIndex: useCallback((index: number) => store.setKey(index), [store.setKey]),
39
40
  };
40
41
  }
41
42
 
@@ -69,18 +70,28 @@ function MediaTypeSelector(props: {
69
70
  return null;
70
71
  }
71
72
 
73
+ const items = renderers.map((renderer) => ({
74
+ key: renderer.mediaType,
75
+ label: renderer.mediaType,
76
+ }));
77
+
72
78
  return (
73
- <select
79
+ <OpenAPISelect
74
80
  className={clsx('openapi-select')}
75
- value={state.mediaType}
76
- onChange={(e) => state.setMediaType(e.target.value)}
81
+ selectedKey={state.mediaType}
82
+ items={renderers.map((renderer) => ({
83
+ key: renderer.mediaType,
84
+ label: renderer.mediaType,
85
+ }))}
86
+ onSelectionChange={(e) => state.setMediaType(String(e))}
87
+ placement="bottom start"
77
88
  >
78
- {renderers.map((renderer) => (
79
- <option key={renderer.mediaType} value={renderer.mediaType}>
80
- {renderer.mediaType}
81
- </option>
89
+ {items.map((item) => (
90
+ <OpenAPISelectItem key={item.key} id={item.key} value={item}>
91
+ {item.label}
92
+ </OpenAPISelectItem>
82
93
  ))}
83
- </select>
94
+ </OpenAPISelect>
84
95
  );
85
96
  }
86
97
 
@@ -95,18 +106,24 @@ function ExamplesSelector(props: {
95
106
  return null;
96
107
  }
97
108
 
109
+ const items = renderer.examples.map((example, index) => ({
110
+ key: index,
111
+ label: example.example.summary || `Example ${index + 1}`,
112
+ }));
113
+
98
114
  return (
99
- <select
100
- className={clsx('openapi-select')}
101
- value={String(state.index)}
102
- onChange={(e) => state.setIndex(Number(e.target.value))}
115
+ <OpenAPISelect
116
+ items={items}
117
+ selectedKey={state.index}
118
+ onSelectionChange={(e) => state.setIndex(Number(e))}
119
+ placement="bottom start"
103
120
  >
104
- {renderer.examples.map((example, index) => (
105
- <option key={index} value={index}>
106
- {example.example.summary || `Example ${index + 1}`}
107
- </option>
121
+ {items.map((item) => (
122
+ <OpenAPISelectItem key={item.key} id={item.key} value={item}>
123
+ {item.label}
124
+ </OpenAPISelectItem>
108
125
  ))}
109
- </select>
126
+ </OpenAPISelect>
110
127
  );
111
128
  }
112
129
 
@@ -0,0 +1,87 @@
1
+ 'use client';
2
+
3
+ import { useCallback } from 'react';
4
+ import type { Key } from 'react-aria';
5
+ import { useStore } from 'zustand';
6
+ import { OpenAPIPath } from './OpenAPIPath';
7
+ import { OpenAPISelect, OpenAPISelectItem } from './OpenAPISelect';
8
+ import { StaticSection } from './StaticSection';
9
+ import { getOrCreateStoreByKey } from './getOrCreateStoreByKey';
10
+ import type { OpenAPIOperationData } from './types';
11
+
12
+ function useCodeSampleState(initialKey: Key = 'default') {
13
+ const store = useStore(getOrCreateStoreByKey('codesample', initialKey));
14
+ return {
15
+ key: store.key,
16
+ setKey: useCallback((key: Key) => store.setKey(key), [store.setKey]),
17
+ };
18
+ }
19
+
20
+ type CodeSampleItem = OpenAPISelectItem & {
21
+ body: React.ReactNode;
22
+ footer?: React.ReactNode;
23
+ };
24
+
25
+ export function OpenAPICodeSampleHeader(props: {
26
+ items: CodeSampleItem[];
27
+ data: OpenAPIOperationData;
28
+ }) {
29
+ const { data, items } = props;
30
+
31
+ const state = useCodeSampleState(items[0]?.key ?? '');
32
+ const selected = items.find((item) => item.key === state.key) || items[0];
33
+
34
+ return (
35
+ <>
36
+ <OpenAPIPath canCopy={false} withServer={false} data={data} />
37
+ {items.length > 1 ? (
38
+ <OpenAPISelect
39
+ selectedKey={selected?.key}
40
+ onSelectionChange={(key) => {
41
+ state.setKey(key);
42
+ }}
43
+ items={items}
44
+ placement="bottom end"
45
+ >
46
+ {items.map((item) => (
47
+ <OpenAPISelectItem key={item.key} id={item.key} value={item}>
48
+ {item.label}
49
+ </OpenAPISelectItem>
50
+ ))}
51
+ </OpenAPISelect>
52
+ ) : items[0] ? (
53
+ <span className="openapi-codesample-label">{items[0].label}</span>
54
+ ) : null}
55
+ </>
56
+ );
57
+ }
58
+
59
+ export function OpenAPICodeSampleBody(props: {
60
+ items: CodeSampleItem[];
61
+ data: OpenAPIOperationData;
62
+ }) {
63
+ const { items, data } = props;
64
+ if (!items[0]) {
65
+ throw new Error('No items provided');
66
+ }
67
+
68
+ const state = useCodeSampleState(items[0]?.key);
69
+
70
+ const selected = items.find((item) => item.key === state.key) || items[0];
71
+
72
+ if (!selected) {
73
+ return null;
74
+ }
75
+
76
+ return (
77
+ <StaticSection
78
+ header={<OpenAPICodeSampleHeader data={data} items={items} />}
79
+ className="openapi-codesample"
80
+ >
81
+ <div id={selected.key as string} className="openapi-codesample-panel">
82
+ {selected.body ? selected.body : null}
83
+ {selected.footer ? selected.footer : null}
84
+ </div>
85
+ </StaticSection>
86
+ );
87
+ }
@@ -0,0 +1,129 @@
1
+ import type { OpenAPIV3 } from '@gitbook/openapi-parser';
2
+ import { generateSchemaExample } from './generateSchemaExample';
3
+ import { json2xml } from './json2xml';
4
+ import { stringifyOpenAPI } from './stringifyOpenAPI';
5
+ import type { OpenAPIContext } from './types';
6
+ import { checkIsReference } from './utils';
7
+
8
+ /**
9
+ * Display an example.
10
+ */
11
+ export function OpenAPIExample(props: {
12
+ example: OpenAPIV3.ExampleObject;
13
+ context: OpenAPIContext;
14
+ syntax: string;
15
+ }) {
16
+ const { example, context, syntax } = props;
17
+ const code = stringifyExample({ example, xml: syntax === 'xml' });
18
+
19
+ if (code === null) {
20
+ return <OpenAPIEmptyExample />;
21
+ }
22
+
23
+ return context.renderCodeBlock({ code, syntax });
24
+ }
25
+
26
+ function stringifyExample(args: { example: OpenAPIV3.ExampleObject; xml: boolean }): string | null {
27
+ const { example, xml } = args;
28
+
29
+ if (!example.value) {
30
+ return null;
31
+ }
32
+
33
+ if (typeof example.value === 'string') {
34
+ return example.value;
35
+ }
36
+
37
+ if (xml) {
38
+ return json2xml(example.value);
39
+ }
40
+
41
+ return stringifyOpenAPI(example.value, null, 2);
42
+ }
43
+
44
+ /**
45
+ * Empty response example.
46
+ */
47
+ export function OpenAPIEmptyExample() {
48
+ return (
49
+ <pre className="openapi-example-empty">
50
+ <p>No Content</p>
51
+ </pre>
52
+ );
53
+ }
54
+
55
+ /**
56
+ * Generate an example from a reference object.
57
+ */
58
+ export function getExampleFromReference(ref: OpenAPIV3.ReferenceObject): OpenAPIV3.ExampleObject {
59
+ return { summary: 'Unresolved reference', value: { $ref: ref.$ref } };
60
+ }
61
+
62
+ /**
63
+ * Get examples from a media type object.
64
+ */
65
+ export function getExamplesFromMediaTypeObject(args: {
66
+ mediaType: string;
67
+ mediaTypeObject: OpenAPIV3.MediaTypeObject;
68
+ }): { key: string; example: OpenAPIV3.ExampleObject }[] {
69
+ const { mediaTypeObject, mediaType } = args;
70
+ if (mediaTypeObject.examples) {
71
+ return Object.entries(mediaTypeObject.examples).map(([key, example]) => {
72
+ return {
73
+ key,
74
+ example: checkIsReference(example) ? getExampleFromReference(example) : example,
75
+ };
76
+ });
77
+ }
78
+
79
+ if (mediaTypeObject.example) {
80
+ return [{ key: 'default', example: { value: mediaTypeObject.example } }];
81
+ }
82
+
83
+ if (mediaTypeObject.schema) {
84
+ if (mediaType === 'application/xml') {
85
+ // @TODO normally we should use the name of the schema but we don't have it
86
+ // fix it when we got the reference name
87
+ const root = mediaTypeObject.schema.xml?.name ?? 'object';
88
+ return [
89
+ {
90
+ key: 'default',
91
+ example: {
92
+ value: {
93
+ [root]: generateSchemaExample(mediaTypeObject.schema, {
94
+ xml: mediaType === 'application/xml',
95
+ mode: 'read',
96
+ }),
97
+ },
98
+ },
99
+ },
100
+ ];
101
+ }
102
+ return [
103
+ {
104
+ key: 'default',
105
+ example: {
106
+ value: generateSchemaExample(mediaTypeObject.schema, {
107
+ mode: 'read',
108
+ }),
109
+ },
110
+ },
111
+ ];
112
+ }
113
+ return [];
114
+ }
115
+
116
+ /**
117
+ * Get example from a schema object.
118
+ */
119
+ export function getExampleFromSchema(args: {
120
+ schema: OpenAPIV3.SchemaObject;
121
+ }): OpenAPIV3.ExampleObject {
122
+ const { schema } = args;
123
+
124
+ if (schema.example) {
125
+ return { value: schema.example };
126
+ }
127
+
128
+ return { value: generateSchemaExample(schema, { mode: 'read' }) };
129
+ }
@@ -10,7 +10,8 @@ import { OpenAPICodeSample } from './OpenAPICodeSample';
10
10
  import { OpenAPIPath } from './OpenAPIPath';
11
11
  import { OpenAPIResponseExample } from './OpenAPIResponseExample';
12
12
  import { OpenAPISpec } from './OpenAPISpec';
13
- import type { OpenAPIClientContext, OpenAPIContextProps, OpenAPIOperationData } from './types';
13
+ import { getOpenAPIClientContext } from './context';
14
+ import type { OpenAPIContext, OpenAPIOperationData } from './types';
14
15
  import { resolveDescription } from './utils';
15
16
 
16
17
  /**
@@ -19,16 +20,12 @@ import { resolveDescription } from './utils';
19
20
  export function OpenAPIOperation(props: {
20
21
  className?: string;
21
22
  data: OpenAPIOperationData;
22
- context: OpenAPIContextProps;
23
+ context: OpenAPIContext;
23
24
  }) {
24
25
  const { className, data, context } = props;
25
26
  const { operation } = data;
26
27
 
27
- const clientContext: OpenAPIClientContext = {
28
- defaultInteractiveOpened: context.defaultInteractiveOpened,
29
- icons: context.icons,
30
- blockKey: context.blockKey,
31
- };
28
+ const clientContext = getOpenAPIClientContext(context);
32
29
 
33
30
  return (
34
31
  <div className={clsx('openapi-operation', className)}>
@@ -50,7 +47,7 @@ export function OpenAPIOperation(props: {
50
47
  title: operation.summary,
51
48
  })
52
49
  : null}
53
- <OpenAPIPath data={data} context={context} />
50
+ <OpenAPIPath data={data} />
54
51
  </div>
55
52
  <div className="openapi-columns">
56
53
  <div className="openapi-column-spec">
@@ -79,7 +76,7 @@ export function OpenAPIOperation(props: {
79
76
 
80
77
  function OpenAPIOperationDescription(props: {
81
78
  operation: OpenAPIV3.OperationObject<OpenAPICustomOperationProperties>;
82
- context: OpenAPIContextProps;
79
+ context: OpenAPIContext;
83
80
  }) {
84
81
  const { operation } = props;
85
82
  if (operation['x-gitbook-description-document']) {
@@ -108,7 +105,6 @@ const stabilityEnum = {
108
105
  experimental: 'Experimental',
109
106
  alpha: 'Alpha',
110
107
  beta: 'Beta',
111
- stable: 'Stable',
112
108
  } as const;
113
109
 
114
110
  function OpenAPIOperationStability(props: { stability: OpenAPIStability }) {
@@ -1,5 +1,5 @@
1
1
  import { OpenAPICopyButton } from './OpenAPICopyButton';
2
- import type { OpenAPIContextProps, OpenAPIOperationData } from './types';
2
+ import type { OpenAPIOperationData } from './types';
3
3
  import { getDefaultServerURL } from './util/server';
4
4
 
5
5
  /**
@@ -7,25 +7,42 @@ import { getDefaultServerURL } from './util/server';
7
7
  */
8
8
  export function OpenAPIPath(props: {
9
9
  data: OpenAPIOperationData;
10
- context: OpenAPIContextProps;
10
+ /** Whether to show the server URL.
11
+ * @default true
12
+ */
13
+ withServer?: boolean;
14
+ /**
15
+ * Whether the path is copyable.
16
+ * @default true
17
+ */
18
+ canCopy?: boolean;
11
19
  }) {
12
- const { data } = props;
20
+ const { data, withServer = true, canCopy = true } = props;
13
21
  const { method, path, operation } = data;
14
22
 
15
23
  const server = getDefaultServerURL(data.servers);
16
24
  const formattedPath = formatPath(path);
17
25
 
26
+ const element = (() => {
27
+ return (
28
+ <>
29
+ {withServer ? <span className="openapi-path-server">{server}</span> : null}
30
+ {formattedPath}
31
+ </>
32
+ );
33
+ })();
34
+
18
35
  return (
19
36
  <div className="openapi-path">
20
37
  <div className={`openapi-method openapi-method-${method}`}>{method}</div>
21
38
 
22
39
  <OpenAPICopyButton
23
- value={server + path}
40
+ value={`${withServer ? server : ''}${path}`}
24
41
  className="openapi-path-title"
25
42
  data-deprecated={operation.deprecated}
43
+ isDisabled={!canCopy}
26
44
  >
27
- <span className="openapi-path-server">{server}</span>
28
- {formattedPath}
45
+ {element}
29
46
  </OpenAPICopyButton>
30
47
  </div>
31
48
  );
@@ -36,13 +36,15 @@ export function OpenAPIResponse(props: {
36
36
  />
37
37
  </OpenAPIDisclosure>
38
38
  ) : null}
39
- <div className="openapi-responsebody">
40
- <OpenAPISchemaProperties
41
- id={`response-${context.blockKey}`}
42
- properties={mediaType.schema ? [{ schema: mediaType.schema }] : []}
43
- context={context}
44
- />
45
- </div>
39
+ {mediaType.schema && (
40
+ <div className="openapi-responsebody">
41
+ <OpenAPISchemaProperties
42
+ id={`response-${context.blockKey}`}
43
+ properties={[{ schema: mediaType.schema }]}
44
+ context={context}
45
+ />
46
+ </div>
47
+ )}
46
48
  </div>
47
49
  );
48
50
  }