@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
@@ -1,11 +1,14 @@
1
1
  import type { OpenAPIV3 } from '@gitbook/openapi-parser';
2
2
  import { Markdown } from './Markdown';
3
+ import {
4
+ OpenAPIEmptyExample,
5
+ OpenAPIExample,
6
+ getExampleFromReference,
7
+ getExamplesFromMediaTypeObject,
8
+ } from './OpenAPIExample';
3
9
  import { OpenAPITabs, OpenAPITabsList, OpenAPITabsPanels } from './OpenAPITabs';
4
10
  import { StaticSection } from './StaticSection';
5
- import { generateSchemaExample } from './generateSchemaExample';
6
- import { json2xml } from './json2xml';
7
- import { stringifyOpenAPI } from './stringifyOpenAPI';
8
- import type { OpenAPIContextProps, OpenAPIOperationData } from './types';
11
+ import type { OpenAPIContext, OpenAPIOperationData } from './types';
9
12
  import { checkIsReference, createStateKey, resolveDescription } from './utils';
10
13
 
11
14
  /**
@@ -13,7 +16,7 @@ import { checkIsReference, createStateKey, resolveDescription } from './utils';
13
16
  */
14
17
  export function OpenAPIResponseExample(props: {
15
18
  data: OpenAPIOperationData;
16
- context: OpenAPIContextProps;
19
+ context: OpenAPIContext;
17
20
  }) {
18
21
  const { data, context } = props;
19
22
 
@@ -62,7 +65,7 @@ export function OpenAPIResponseExample(props: {
62
65
  return {
63
66
  key: key,
64
67
  label: key,
65
- body: <OpenAPIEmptyResponseExample />,
68
+ body: <OpenAPIEmptyExample />,
66
69
  footer: description ? <Markdown source={description} /> : undefined,
67
70
  };
68
71
  }
@@ -81,7 +84,7 @@ export function OpenAPIResponseExample(props: {
81
84
 
82
85
  return (
83
86
  <OpenAPITabs stateKey={createStateKey('response-example')} items={tabs}>
84
- <StaticSection header={<OpenAPITabsList />} className="openapi-response-example">
87
+ <StaticSection header={<OpenAPITabsList />} className="openapi-panel">
85
88
  <OpenAPITabsPanels />
86
89
  </StaticSection>
87
90
  </OpenAPITabs>
@@ -89,7 +92,7 @@ export function OpenAPIResponseExample(props: {
89
92
  }
90
93
 
91
94
  function OpenAPIResponse(props: {
92
- context: OpenAPIContextProps;
95
+ context: OpenAPIContext;
93
96
  content: {
94
97
  [media: string]: OpenAPIV3.MediaTypeObject;
95
98
  };
@@ -141,7 +144,7 @@ function OpenAPIResponse(props: {
141
144
  function OpenAPIResponseMediaType(props: {
142
145
  mediaTypeObject: OpenAPIV3.MediaTypeObject;
143
146
  mediaType: string;
144
- context: OpenAPIContextProps;
147
+ context: OpenAPIContext;
145
148
  }) {
146
149
  const { mediaTypeObject, mediaType } = props;
147
150
  const examples = getExamplesFromMediaTypeObject({ mediaTypeObject, mediaType });
@@ -149,7 +152,7 @@ function OpenAPIResponseMediaType(props: {
149
152
  const firstExample = examples[0];
150
153
 
151
154
  if (!firstExample) {
152
- return <OpenAPIEmptyResponseExample />;
155
+ return <OpenAPIEmptyExample />;
153
156
  }
154
157
 
155
158
  if (examples.length === 1) {
@@ -184,42 +187,6 @@ function OpenAPIResponseMediaType(props: {
184
187
  );
185
188
  }
186
189
 
187
- /**
188
- * Display an example.
189
- */
190
- function OpenAPIExample(props: {
191
- example: OpenAPIV3.ExampleObject;
192
- context: OpenAPIContextProps;
193
- syntax: string;
194
- }) {
195
- const { example, context, syntax } = props;
196
- const code = stringifyExample({ example, xml: syntax === 'xml' });
197
-
198
- if (code === null) {
199
- return <OpenAPIEmptyResponseExample />;
200
- }
201
-
202
- return context.renderCodeBlock({ code, syntax });
203
- }
204
-
205
- function stringifyExample(args: { example: OpenAPIV3.ExampleObject; xml: boolean }): string | null {
206
- const { example, xml } = args;
207
-
208
- if (!example.value) {
209
- return null;
210
- }
211
-
212
- if (typeof example.value === 'string') {
213
- return example.value;
214
- }
215
-
216
- if (xml) {
217
- return json2xml(example.value);
218
- }
219
-
220
- return stringifyOpenAPI(example.value, null, 2);
221
- }
222
-
223
190
  /**
224
191
  * Get the syntax from a media type.
225
192
  */
@@ -234,70 +201,3 @@ function getSyntaxFromMediaType(mediaType: string): string {
234
201
 
235
202
  return 'text';
236
203
  }
237
-
238
- /**
239
- * Get examples from a media type object.
240
- */
241
- function getExamplesFromMediaTypeObject(args: {
242
- mediaType: string;
243
- mediaTypeObject: OpenAPIV3.MediaTypeObject;
244
- }): { key: string; example: OpenAPIV3.ExampleObject }[] {
245
- const { mediaTypeObject, mediaType } = args;
246
- if (mediaTypeObject.examples) {
247
- return Object.entries(mediaTypeObject.examples).map(([key, example]) => {
248
- return {
249
- key,
250
- example: checkIsReference(example) ? getExampleFromReference(example) : example,
251
- };
252
- });
253
- }
254
-
255
- if (mediaTypeObject.example) {
256
- return [{ key: 'default', example: { value: mediaTypeObject.example } }];
257
- }
258
-
259
- if (mediaTypeObject.schema) {
260
- if (mediaType === 'application/xml') {
261
- // @TODO normally we should use the name of the schema but we don't have it
262
- // fix it when we got the reference name
263
- const root = mediaTypeObject.schema.xml?.name ?? 'object';
264
- return [
265
- {
266
- key: 'default',
267
- example: {
268
- value: {
269
- [root]: generateSchemaExample(mediaTypeObject.schema, {
270
- xml: mediaType === 'application/xml',
271
- }),
272
- },
273
- },
274
- },
275
- ];
276
- }
277
- return [
278
- {
279
- key: 'default',
280
- example: { value: generateSchemaExample(mediaTypeObject.schema) },
281
- },
282
- ];
283
- }
284
- return [];
285
- }
286
-
287
- /**
288
- * Empty response example.
289
- */
290
- function OpenAPIEmptyResponseExample() {
291
- return (
292
- <pre className="openapi-response-example-empty">
293
- <p>No body</p>
294
- </pre>
295
- );
296
- }
297
-
298
- /**
299
- * Generate an example from a reference object.
300
- */
301
- function getExampleFromReference(ref: OpenAPIV3.ReferenceObject): OpenAPIV3.ExampleObject {
302
- return { summary: 'Unresolved reference', value: { $ref: ref.$ref } };
303
- }
@@ -21,7 +21,42 @@ export function OpenAPIResponses(props: {
21
21
  icon={context.icons.chevronRight}
22
22
  groups={Object.entries(responses).map(
23
23
  ([statusCode, response]: [string, OpenAPIV3.ResponseObject]) => {
24
- const content = Object.entries(response.content ?? {});
24
+ const tabs = (() => {
25
+ // If there is no content, but there are headers, we need to show the headers
26
+ if (
27
+ (!response.content || !Object.keys(response.content).length) &&
28
+ response.headers &&
29
+ Object.keys(response.headers).length
30
+ ) {
31
+ return [
32
+ {
33
+ id: 'default',
34
+ body: (
35
+ <OpenAPIResponse
36
+ response={response}
37
+ mediaType={{}}
38
+ context={context}
39
+ />
40
+ ),
41
+ },
42
+ ];
43
+ }
44
+
45
+ return Object.entries(response.content ?? {}).map(
46
+ ([contentType, mediaType]) => ({
47
+ id: contentType,
48
+ label: contentType,
49
+ body: (
50
+ <OpenAPIResponse
51
+ response={response}
52
+ mediaType={mediaType}
53
+ context={context}
54
+ />
55
+ ),
56
+ })
57
+ );
58
+ })();
59
+
25
60
  const description = response.description;
26
61
 
27
62
  return {
@@ -39,17 +74,7 @@ export function OpenAPIResponses(props: {
39
74
  ) : null}
40
75
  </div>
41
76
  ),
42
- tabs: content.map(([contentType, mediaType]) => ({
43
- id: contentType,
44
- label: contentType,
45
- body: (
46
- <OpenAPIResponse
47
- response={response}
48
- mediaType={mediaType}
49
- context={context}
50
- />
51
- ),
52
- })),
77
+ tabs,
53
78
  };
54
79
  }
55
80
  )}
@@ -11,6 +11,7 @@ import { OpenAPICopyButton } from './OpenAPICopyButton';
11
11
  import { OpenAPIDisclosure } from './OpenAPIDisclosure';
12
12
  import { OpenAPISchemaName } from './OpenAPISchemaName';
13
13
  import { retrocycle } from './decycle';
14
+ import { stringifyOpenAPI } from './stringifyOpenAPI';
14
15
  import type { OpenAPIClientContext } from './types';
15
16
  import { checkIsReference, resolveDescription, resolveFirstExample } from './utils';
16
17
 
@@ -145,17 +146,23 @@ function OpenAPIRootSchema(props: {
145
146
 
146
147
  const id = useId();
147
148
  const properties = getSchemaProperties(schema);
149
+ const description = resolveDescription(schema);
148
150
 
149
151
  if (properties?.length) {
150
152
  const circularRefs = new Map(parentCircularRefs);
151
153
  circularRefs.set(schema, id);
152
154
 
153
155
  return (
154
- <OpenAPISchemaProperties
155
- properties={properties}
156
- circularRefs={circularRefs}
157
- context={context}
158
- />
156
+ <>
157
+ {description ? (
158
+ <Markdown source={description} className="openapi-schema-root-description" />
159
+ ) : null}
160
+ <OpenAPISchemaProperties
161
+ properties={properties}
162
+ circularRefs={circularRefs}
163
+ context={context}
164
+ />
165
+ </>
159
166
  );
160
167
  }
161
168
 
@@ -275,22 +282,20 @@ function OpenAPISchemaEnum(props: {
275
282
  }
276
283
 
277
284
  return (
278
- <div className="openapi-schema-enum">
279
- <span>Available options:</span>
280
- <div className="openapi-schema-enum-list">
281
- {enumValues.map((item, index) => (
282
- <span key={index} className="openapi-schema-enum-value">
283
- <OpenAPICopyButton
284
- value={item.value}
285
- label={item.description}
286
- withTooltip={!!item.description}
287
- >
288
- <code>{`${item.value}`}</code>
289
- </OpenAPICopyButton>
290
- </span>
291
- ))}
292
- </div>
293
- </div>
285
+ <span className="openapi-schema-enum">
286
+ Available options:{' '}
287
+ {enumValues.map((item, index) => (
288
+ <span key={index} className="openapi-schema-enum-value">
289
+ <OpenAPICopyButton
290
+ value={item.value}
291
+ label={item.description}
292
+ withTooltip={!!item.description}
293
+ >
294
+ <code>{`${item.value}`}</code>
295
+ </OpenAPICopyButton>
296
+ </span>
297
+ ))}
298
+ </span>
294
299
  );
295
300
  }
296
301
 
@@ -324,15 +329,25 @@ function OpenAPISchemaPresentation(props: { property: OpenAPISchemaPropertyEntry
324
329
  {description ? (
325
330
  <Markdown source={description} className="openapi-schema-description" />
326
331
  ) : null}
332
+ {schema.default !== undefined ? (
333
+ <span className="openapi-schema-default">
334
+ Default:{' '}
335
+ <code>
336
+ {typeof schema.default === 'string' && schema.default
337
+ ? schema.default
338
+ : stringifyOpenAPI(schema.default)}
339
+ </code>
340
+ </span>
341
+ ) : null}
327
342
  {typeof example === 'string' ? (
328
- <div className="openapi-schema-example">
343
+ <span className="openapi-schema-example">
329
344
  Example: <code>{example}</code>
330
- </div>
345
+ </span>
331
346
  ) : null}
332
347
  {schema.pattern ? (
333
- <div className="openapi-schema-pattern">
348
+ <span className="openapi-schema-pattern">
334
349
  Pattern: <code>{schema.pattern}</code>
335
- </div>
350
+ </span>
336
351
  ) : null}
337
352
  <OpenAPISchemaEnum schema={schema} />
338
353
  </div>
@@ -1,6 +1,5 @@
1
1
  import type { OpenAPIV3 } from '@gitbook/openapi-parser';
2
2
  import type React from 'react';
3
- import { stringifyOpenAPI } from './stringifyOpenAPI';
4
3
 
5
4
  interface OpenAPISchemaNameProps {
6
5
  schema?: OpenAPIV3.SchemaObject;
@@ -19,7 +18,7 @@ export function OpenAPISchemaName(props: OpenAPISchemaNameProps) {
19
18
  const additionalItems = schema && getAdditionalItems(schema);
20
19
 
21
20
  return (
22
- <div className="openapi-schema-name">
21
+ <span className="openapi-schema-name">
23
22
  {propertyName ? (
24
23
  <span data-deprecated={schema?.deprecated} className="openapi-schema-propertyname">
25
24
  {propertyName}
@@ -41,7 +40,7 @@ export function OpenAPISchemaName(props: OpenAPISchemaNameProps) {
41
40
  <span className="openapi-schema-optional">optional</span>
42
41
  )}
43
42
  {schema?.deprecated ? <span className="openapi-deprecated">Deprecated</span> : null}
44
- </div>
43
+ </span>
45
44
  );
46
45
  }
47
46
 
@@ -56,11 +55,6 @@ function getAdditionalItems(schema: OpenAPIV3.SchemaObject): string {
56
55
  additionalItems += ` · max: ${schema.maximum || schema.maxLength || schema.maxItems}`;
57
56
  }
58
57
 
59
- // If the schema has a default value, we display it
60
- if (typeof schema.default !== 'undefined') {
61
- additionalItems += ` · default: ${stringifyOpenAPI(schema.default)}`;
62
- }
63
-
64
58
  if (schema.nullable) {
65
59
  additionalItems = ' | nullable';
66
60
  }
@@ -1,8 +1,11 @@
1
- import type { OpenAPIV3_1 } from '@gitbook/openapi-parser';
2
1
  import { InteractiveSection } from './InteractiveSection';
3
2
  import { Markdown } from './Markdown';
4
3
  import { OpenAPISchemaName } from './OpenAPISchemaName';
5
- import type { OpenAPIClientContext, OpenAPIOperationData } from './types';
4
+ import type {
5
+ OpenAPIClientContext,
6
+ OpenAPIOperationData,
7
+ OpenAPISecurityWithRequired,
8
+ } from './types';
6
9
  import { resolveDescription } from './utils';
7
10
 
8
11
  /**
@@ -50,26 +53,36 @@ export function OpenAPISecurities(props: {
50
53
  );
51
54
  }
52
55
 
53
- function getLabelForType(security: OpenAPIV3_1.SecuritySchemeObject) {
56
+ function getLabelForType(security: OpenAPISecurityWithRequired) {
54
57
  switch (security.type) {
55
58
  case 'apiKey':
56
59
  return (
57
60
  <OpenAPISchemaName
58
61
  propertyName={security.name ?? 'apiKey'}
59
62
  type="string"
60
- required
63
+ required={security.required}
61
64
  />
62
65
  );
63
66
  case 'http':
64
67
  if (security.scheme === 'basic') {
65
- return <OpenAPISchemaName propertyName="Authorization" type="string" required />;
68
+ return (
69
+ <OpenAPISchemaName
70
+ propertyName="Authorization"
71
+ type="string"
72
+ required={security.required}
73
+ />
74
+ );
66
75
  }
67
76
 
68
77
  if (security.scheme === 'bearer') {
69
78
  const description = resolveDescription(security);
70
79
  return (
71
80
  <>
72
- <OpenAPISchemaName propertyName="Authorization" type="string" required />
81
+ <OpenAPISchemaName
82
+ propertyName="Authorization"
83
+ type="string"
84
+ required={security.required}
85
+ />
73
86
  {/** Show a default description if none is provided */}
74
87
  {!description ? (
75
88
  <Markdown
@@ -81,11 +94,11 @@ function getLabelForType(security: OpenAPIV3_1.SecuritySchemeObject) {
81
94
  );
82
95
  }
83
96
 
84
- return <OpenAPISchemaName propertyName="HTTP" required />;
97
+ return <OpenAPISchemaName propertyName="HTTP" required={security.required} />;
85
98
  case 'oauth2':
86
- return <OpenAPISchemaName propertyName="OAuth2" required />;
99
+ return <OpenAPISchemaName propertyName="OAuth2" required={security.required} />;
87
100
  case 'openIdConnect':
88
- return <OpenAPISchemaName propertyName="OpenID Connect" required />;
101
+ return <OpenAPISchemaName propertyName="OpenID Connect" required={security.required} />;
89
102
  default:
90
103
  // @ts-ignore
91
104
  return security.type;
@@ -0,0 +1,70 @@
1
+ 'use client';
2
+
3
+ import clsx from 'clsx';
4
+ import {
5
+ Button,
6
+ type Key,
7
+ ListBox,
8
+ ListBoxItem,
9
+ type ListBoxItemProps,
10
+ Popover,
11
+ type PopoverProps,
12
+ Select,
13
+ type SelectProps,
14
+ SelectValue,
15
+ } from 'react-aria-components';
16
+
17
+ export type OpenAPISelectItem = {
18
+ key: Key;
19
+ label: string;
20
+ };
21
+
22
+ interface OpenAPISelectProps<T extends OpenAPISelectItem> extends Omit<SelectProps<T>, 'children'> {
23
+ items: T[];
24
+ children: React.ReactNode | ((item: T) => React.ReactNode);
25
+ selectedKey?: Key;
26
+ onChange?: (key: string | number) => void;
27
+ placement?: PopoverProps['placement'];
28
+ }
29
+
30
+ export function OpenAPISelect<T extends OpenAPISelectItem>(props: OpenAPISelectProps<T>) {
31
+ const { items, children, className, placement } = props;
32
+
33
+ return (
34
+ <Select {...props} className={clsx('openapi-select', className)}>
35
+ <Button>
36
+ <SelectValue />
37
+ <span aria-hidden="true">
38
+ <svg
39
+ className="gb-icon"
40
+ style={{
41
+ maskImage:
42
+ "url('https://ka-p.fontawesome.com/releases/v6.6.0/svgs/regular/chevron-down.svg?v=2&token=a463935e93')",
43
+ maskRepeat: 'no-repeat',
44
+ maskPosition: 'center center',
45
+ }}
46
+ />
47
+ </span>
48
+ </Button>
49
+ <Popover placement={placement} className="openapi-select-popover">
50
+ <ListBox className="openapi-select-listbox" items={items}>
51
+ {children}
52
+ </ListBox>
53
+ </Popover>
54
+ </Select>
55
+ );
56
+ }
57
+
58
+ export function OpenAPISelectItem(props: ListBoxItemProps) {
59
+ return (
60
+ <ListBoxItem
61
+ {...props}
62
+ className={({ isFocused, isSelected }) =>
63
+ clsx('openapi-select-item', {
64
+ 'openapi-select-item-focused': isFocused,
65
+ 'openapi-select-item-selected': isSelected,
66
+ })
67
+ }
68
+ />
69
+ );
70
+ }
@@ -3,7 +3,7 @@
3
3
  import { createContext, useContext, useEffect, useMemo, useRef, useState } from 'react';
4
4
  import { type Key, Tab, TabList, TabPanel, Tabs, type TabsProps } from 'react-aria-components';
5
5
  import { useEventCallback } from 'usehooks-ts';
6
- import { getOrCreateTabStoreByKey } from './useSyncedTabsGlobalState';
6
+ import { getOrCreateStoreByKey } from './getOrCreateStoreByKey';
7
7
 
8
8
  export type TabItem = {
9
9
  key: Key;
@@ -36,8 +36,8 @@ export function OpenAPITabs(
36
36
  const { children, items, stateKey } = props;
37
37
  const [tabKey, setTabKey] = useState<Key | null>(() => {
38
38
  if (stateKey && typeof window !== 'undefined') {
39
- const store = getOrCreateTabStoreByKey(stateKey);
40
- const tabKey = store.getState().tabKey;
39
+ const store = getOrCreateStoreByKey(stateKey);
40
+ const tabKey = store.getState().key;
41
41
  if (tabKey) {
42
42
  return tabKey;
43
43
  }
@@ -60,10 +60,10 @@ export function OpenAPITabs(
60
60
  if (!stateKey) {
61
61
  return undefined;
62
62
  }
63
- const store = getOrCreateTabStoreByKey(stateKey);
63
+ const store = getOrCreateStoreByKey(stateKey);
64
64
  return store.subscribe((state) => {
65
65
  cancelDeferRef.current?.();
66
- cancelDeferRef.current = defer(() => selectTab(state.tabKey));
66
+ cancelDeferRef.current = defer(() => selectTab(state.key));
67
67
  });
68
68
  }, [stateKey, selectTab]);
69
69
  useEffect(() => {
@@ -77,8 +77,8 @@ export function OpenAPITabs(
77
77
  onSelectionChange={(tabKey) => {
78
78
  selectTab(tabKey);
79
79
  if (stateKey) {
80
- const store = getOrCreateTabStoreByKey(stateKey);
81
- store.setState({ tabKey });
80
+ const store = getOrCreateStoreByKey(stateKey);
81
+ store.setState({ key: tabKey });
82
82
  }
83
83
  }}
84
84
  selectedKey={tabKey}
@@ -138,9 +138,9 @@ export function OpenAPITabsPanels() {
138
138
 
139
139
  return (
140
140
  <TabPanel id={key} className="openapi-tabs-panel">
141
- <div className="openapi-tabs-body">{selectedTab.body}</div>
141
+ <div className="openapi-panel-body">{selectedTab.body}</div>
142
142
  {selectedTab.footer ? (
143
- <div className="openapi-tabs-footer">{selectedTab.footer}</div>
143
+ <div className="openapi-panel-footer">{selectedTab.footer}</div>
144
144
  ) : null}
145
145
  </TabPanel>
146
146
  );
package/src/context.ts ADDED
@@ -0,0 +1,64 @@
1
+ export interface OpenAPIClientContext {
2
+ /**
3
+ * Icons used in the block.
4
+ */
5
+ icons: {
6
+ chevronDown: React.ReactNode;
7
+ chevronRight: React.ReactNode;
8
+ plus: React.ReactNode;
9
+ };
10
+
11
+ /**
12
+ * Force all sections to be opened by default.
13
+ * @default false
14
+ */
15
+ defaultInteractiveOpened?: boolean;
16
+
17
+ /**
18
+ * The key of the block
19
+ */
20
+ blockKey?: string;
21
+
22
+ /**
23
+ * Optional id attached to the heading and used as an anchor.
24
+ */
25
+ id?: string;
26
+ }
27
+
28
+ export interface OpenAPIContext extends OpenAPIClientContext {
29
+ /**
30
+ * Render a code block.
31
+ */
32
+ renderCodeBlock: (props: { code: string; syntax: string }) => React.ReactNode;
33
+
34
+ /**
35
+ * Render the heading of the operation.
36
+ */
37
+ renderHeading: (props: {
38
+ deprecated: boolean;
39
+ title: string;
40
+ stability?: string;
41
+ }) => React.ReactNode;
42
+
43
+ /**
44
+ * Render the document of the operation.
45
+ */
46
+ renderDocument: (props: { document: object }) => React.ReactNode;
47
+
48
+ /**
49
+ * Specification URL.
50
+ */
51
+ specUrl: string;
52
+ }
53
+
54
+ /**
55
+ * Get the client context from the OpenAPI context.
56
+ */
57
+ export function getOpenAPIClientContext(context: OpenAPIContext): OpenAPIClientContext {
58
+ return {
59
+ icons: context.icons,
60
+ defaultInteractiveOpened: context.defaultInteractiveOpened,
61
+ blockKey: context.blockKey,
62
+ id: context.id,
63
+ };
64
+ }