@gitbook/react-openapi 1.2.1 → 1.3.0

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 (63) hide show
  1. package/CHANGELOG.md +19 -0
  2. package/dist/OpenAPIDisclosure.d.ts +1 -0
  3. package/dist/OpenAPIDisclosure.jsx +6 -3
  4. package/dist/OpenAPIDisclosureGroup.jsx +16 -15
  5. package/dist/OpenAPIResponse.jsx +18 -2
  6. package/dist/OpenAPIResponseExample.jsx +8 -3
  7. package/dist/OpenAPIResponses.jsx +6 -1
  8. package/dist/OpenAPISchema.d.ts +9 -2
  9. package/dist/OpenAPISchema.jsx +93 -59
  10. package/dist/OpenAPISchemaName.d.ts +1 -1
  11. package/dist/OpenAPISchemaName.jsx +1 -1
  12. package/dist/StaticSection.jsx +1 -1
  13. package/dist/code-samples.js +5 -2
  14. package/dist/generateSchemaExample.js +5 -0
  15. package/dist/getDisclosureLabel.d.ts +7 -0
  16. package/dist/getDisclosureLabel.js +18 -0
  17. package/dist/schemas/OpenAPISchemaItem.d.ts +7 -0
  18. package/dist/schemas/OpenAPISchemaItem.jsx +16 -0
  19. package/dist/schemas/OpenAPISchemas.jsx +3 -9
  20. package/dist/translations/de.d.ts +6 -1
  21. package/dist/translations/de.js +9 -4
  22. package/dist/translations/en.d.ts +6 -1
  23. package/dist/translations/en.js +8 -3
  24. package/dist/translations/es.d.ts +6 -1
  25. package/dist/translations/es.js +9 -4
  26. package/dist/translations/fr.d.ts +6 -1
  27. package/dist/translations/fr.js +10 -5
  28. package/dist/translations/index.d.ts +54 -9
  29. package/dist/translations/ja.d.ts +6 -1
  30. package/dist/translations/ja.js +8 -3
  31. package/dist/translations/nl.d.ts +6 -1
  32. package/dist/translations/nl.js +8 -3
  33. package/dist/translations/no.d.ts +6 -1
  34. package/dist/translations/no.js +9 -4
  35. package/dist/translations/pt-br.d.ts +6 -1
  36. package/dist/translations/pt-br.js +9 -4
  37. package/dist/translations/zh.d.ts +6 -1
  38. package/dist/translations/zh.js +9 -4
  39. package/dist/tsconfig.build.tsbuildinfo +1 -1
  40. package/package.json +1 -1
  41. package/src/OpenAPIDisclosure.tsx +7 -3
  42. package/src/OpenAPIDisclosureGroup.tsx +49 -48
  43. package/src/OpenAPIResponse.tsx +34 -2
  44. package/src/OpenAPIResponseExample.tsx +36 -34
  45. package/src/OpenAPIResponses.tsx +4 -4
  46. package/src/OpenAPISchema.tsx +167 -103
  47. package/src/OpenAPISchemaName.tsx +2 -2
  48. package/src/StaticSection.tsx +1 -1
  49. package/src/code-samples.test.ts +2 -1
  50. package/src/code-samples.ts +5 -2
  51. package/src/generateSchemaExample.ts +8 -0
  52. package/src/getDisclosureLabel.ts +25 -0
  53. package/src/schemas/OpenAPISchemaItem.tsx +34 -0
  54. package/src/schemas/OpenAPISchemas.tsx +7 -13
  55. package/src/translations/de.ts +9 -4
  56. package/src/translations/en.ts +8 -3
  57. package/src/translations/es.ts +9 -4
  58. package/src/translations/fr.ts +10 -5
  59. package/src/translations/ja.ts +8 -3
  60. package/src/translations/nl.ts +8 -3
  61. package/src/translations/no.ts +9 -4
  62. package/src/translations/pt-br.ts +9 -4
  63. package/src/translations/zh.ts +9 -4
package/package.json CHANGED
@@ -8,7 +8,7 @@
8
8
  "default": "./dist/index.js"
9
9
  }
10
10
  },
11
- "version": "1.2.1",
11
+ "version": "1.3.0",
12
12
  "sideEffects": false,
13
13
  "dependencies": {
14
14
  "@gitbook/openapi-parser": "workspace:*",
@@ -9,11 +9,12 @@ import { Button, Disclosure, DisclosurePanel } from 'react-aria-components';
9
9
  */
10
10
  export function OpenAPIDisclosure(props: {
11
11
  icon: React.ReactNode;
12
+ header: React.ReactNode;
12
13
  children: React.ReactNode;
13
14
  label: string | ((isExpanded: boolean) => string);
14
15
  className?: string;
15
16
  }): React.JSX.Element {
16
- const { icon, children, label, className } = props;
17
+ const { icon, header, label, children, className } = props;
17
18
  const [isExpanded, setIsExpanded] = useState(false);
18
19
 
19
20
  return (
@@ -31,8 +32,11 @@ export function OpenAPIDisclosure(props: {
31
32
  : 'none',
32
33
  })}
33
34
  >
34
- {icon}
35
- <span>{typeof label === 'function' ? label(isExpanded) : label}</span>
35
+ {header}
36
+ <div className="openapi-disclosure-trigger-label">
37
+ <span>{typeof label === 'function' ? label(isExpanded) : label}</span>
38
+ {icon}
39
+ </div>
36
40
  </Button>
37
41
  <DisclosurePanel className="openapi-disclosure-panel">
38
42
  {isExpanded ? children : null}
@@ -76,7 +76,7 @@ function DisclosureItem(props: {
76
76
  });
77
77
 
78
78
  const panelRef = useRef<HTMLDivElement | null>(null);
79
- const triggerRef = useRef<HTMLButtonElement | null>(null);
79
+ const triggerRef = useRef<HTMLDivElement | null>(null);
80
80
  const isDisabled = groupState?.isDisabled || !group.tabs?.length || false;
81
81
  const { buttonProps: triggerProps, panelProps } = useDisclosure(
82
82
  {
@@ -96,55 +96,56 @@ function DisclosureItem(props: {
96
96
 
97
97
  return (
98
98
  <div className="openapi-disclosure-group" aria-expanded={state.isExpanded}>
99
- <div className="openapi-disclosure-group-header">
100
- <button
101
- slot="trigger"
102
- ref={triggerRef}
103
- {...mergeProps(buttonProps, focusProps)}
104
- disabled={isDisabled}
105
- style={{
106
- outline: isFocusVisible
107
- ? '2px solid rgb(var(--primary-color-500)/0.4)'
108
- : 'none',
109
- }}
110
- className="openapi-disclosure-group-trigger"
111
- >
112
- <div className="openapi-disclosure-group-icon">
113
- {icon || (
114
- <svg viewBox="0 0 24 24" className="openapi-disclosure-group-icon">
115
- <path d="m8.25 4.5 7.5 7.5-7.5 7.5" />
116
- </svg>
117
- )}
118
- </div>
99
+ <div
100
+ slot="trigger"
101
+ ref={triggerRef}
102
+ {...mergeProps(buttonProps, focusProps)}
103
+ aria-disabled={isDisabled}
104
+ style={{
105
+ outline: isFocusVisible
106
+ ? '2px solid rgb(var(--primary-color-500)/0.4)'
107
+ : 'none',
108
+ }}
109
+ className="openapi-disclosure-group-trigger"
110
+ >
111
+ <div className="openapi-disclosure-group-icon">
112
+ {icon || (
113
+ <svg viewBox="0 0 24 24" className="openapi-disclosure-group-icon">
114
+ <path d="m8.25 4.5 7.5 7.5-7.5 7.5" />
115
+ </svg>
116
+ )}
117
+ </div>
119
118
 
119
+ <div className="openapi-disclosure-group-label">
120
120
  {group.label}
121
- </button>
122
- {group.tabs ? (
123
- <div
124
- className="openapi-disclosure-group-mediatype"
125
- onClick={(e) => e.stopPropagation()}
126
- >
127
- {group.tabs?.length > 1 ? (
128
- <OpenAPISelect
129
- icon={selectIcon}
130
- stateKey={selectStateKey}
131
- onSelectionChange={() => {
132
- state.expand();
133
- }}
134
- items={group.tabs}
135
- placement="bottom end"
136
- >
137
- {group.tabs.map((tab) => (
138
- <OpenAPISelectItem key={tab.key} id={tab.key} value={tab}>
139
- {tab.label}
140
- </OpenAPISelectItem>
141
- ))}
142
- </OpenAPISelect>
143
- ) : group.tabs[0]?.label ? (
144
- <span>{group.tabs[0].label}</span>
145
- ) : null}
146
- </div>
147
- ) : null}
121
+
122
+ {group.tabs ? (
123
+ <div
124
+ className="openapi-disclosure-group-mediatype"
125
+ onClick={(e) => e.stopPropagation()}
126
+ >
127
+ {group.tabs?.length > 1 ? (
128
+ <OpenAPISelect
129
+ icon={selectIcon}
130
+ stateKey={selectStateKey}
131
+ onSelectionChange={() => {
132
+ state.expand();
133
+ }}
134
+ items={group.tabs}
135
+ placement="bottom end"
136
+ >
137
+ {group.tabs.map((tab) => (
138
+ <OpenAPISelectItem key={tab.key} id={tab.key} value={tab}>
139
+ {tab.label}
140
+ </OpenAPISelectItem>
141
+ ))}
142
+ </OpenAPISelect>
143
+ ) : group.tabs[0]?.label ? (
144
+ <span>{group.tabs[0].label}</span>
145
+ ) : null}
146
+ </div>
147
+ ) : null}
148
+ </div>
148
149
  </div>
149
150
 
150
151
  {state.isExpanded && selectedTab && (
@@ -1,7 +1,9 @@
1
1
  import type { OpenAPIV3 } from '@gitbook/openapi-parser';
2
2
  import { OpenAPIDisclosure } from './OpenAPIDisclosure';
3
+ import { OpenAPISchemaPresentation } from './OpenAPISchema';
3
4
  import { OpenAPISchemaProperties } from './OpenAPISchemaServer';
4
5
  import type { OpenAPIClientContext } from './context';
6
+ import { tString } from './translate';
5
7
  import { parameterToProperty, resolveDescription } from './utils';
6
8
 
7
9
  /**
@@ -27,7 +29,31 @@ export function OpenAPIResponse(props: {
27
29
  return (
28
30
  <div className="openapi-response-body">
29
31
  {headers.length > 0 ? (
30
- <OpenAPIDisclosure icon={context.icons.plus} label="Headers">
32
+ <OpenAPIDisclosure
33
+ header={
34
+ <OpenAPISchemaPresentation
35
+ context={context}
36
+ property={{
37
+ propertyName: tString(context.translation, 'headers'),
38
+ schema: {
39
+ type: 'object',
40
+ },
41
+ required: null,
42
+ }}
43
+ />
44
+ }
45
+ icon={context.icons.plus}
46
+ label={(isExpanded) =>
47
+ tString(
48
+ context.translation,
49
+ isExpanded ? 'hide' : 'show',
50
+ tString(
51
+ context.translation,
52
+ headers.length === 1 ? 'header' : 'headers'
53
+ )
54
+ )
55
+ }
56
+ >
31
57
  <OpenAPISchemaProperties
32
58
  properties={headers.map(([name, header]) =>
33
59
  parameterToProperty({ name, ...header })
@@ -40,7 +66,13 @@ export function OpenAPIResponse(props: {
40
66
  <div className="openapi-responsebody">
41
67
  <OpenAPISchemaProperties
42
68
  id={`response-${context.blockKey}`}
43
- properties={[{ schema: mediaType.schema }]}
69
+ properties={[
70
+ {
71
+ schema: mediaType.schema,
72
+ propertyName: tString(context.translation, 'response'),
73
+ required: null,
74
+ },
75
+ ]}
44
76
  context={context}
45
77
  />
46
78
  </div>
@@ -6,8 +6,8 @@ import { OpenAPIResponseExampleContent } from './OpenAPIResponseExampleContent';
6
6
  import { type OpenAPIContext, getOpenAPIClientContext } from './context';
7
7
  import type { OpenAPIOperationData, OpenAPIWebhookData } from './types';
8
8
  import { getExampleFromReference, getExamples } from './util/example';
9
- import { createStateKey, getStatusCodeDefaultLabel } from './utils';
10
- import { checkIsReference, resolveDescription } from './utils';
9
+ import { createStateKey, getStatusCodeDefaultLabel, resolveDescription } from './utils';
10
+ import { checkIsReference } from './utils';
11
11
 
12
12
  /**
13
13
  * Display an example of the response content.
@@ -41,45 +41,47 @@ export function OpenAPIResponseExample(props: {
41
41
  return Number(a) - Number(b);
42
42
  });
43
43
 
44
- const tabs = responses.map(([key, responseObject]) => {
45
- const description = resolveDescription(responseObject);
46
- const label = description ? (
47
- <Markdown source={description} />
48
- ) : (
49
- getStatusCodeDefaultLabel(key, context)
50
- );
44
+ const tabs = responses
45
+ .filter(([_, responseObject]) => responseObject && typeof responseObject === 'object')
46
+ .map(([key, responseObject]) => {
47
+ const description = resolveDescription(responseObject);
48
+ const label = description ? (
49
+ <Markdown source={description} />
50
+ ) : (
51
+ getStatusCodeDefaultLabel(key, context)
52
+ );
51
53
 
52
- if (checkIsReference(responseObject)) {
53
- return {
54
- key: key,
55
- label,
56
- statusCode: key,
57
- body: (
58
- <OpenAPIExample
59
- example={getExampleFromReference(responseObject, context)}
60
- context={context}
61
- syntax="json"
62
- />
63
- ),
64
- };
65
- }
54
+ if (checkIsReference(responseObject)) {
55
+ return {
56
+ key: key,
57
+ label,
58
+ statusCode: key,
59
+ body: (
60
+ <OpenAPIExample
61
+ example={getExampleFromReference(responseObject, context)}
62
+ context={context}
63
+ syntax="json"
64
+ />
65
+ ),
66
+ };
67
+ }
68
+
69
+ if (!responseObject.content || Object.keys(responseObject.content).length === 0) {
70
+ return {
71
+ key: key,
72
+ label,
73
+ statusCode: key,
74
+ body: <OpenAPIEmptyExample context={context} />,
75
+ };
76
+ }
66
77
 
67
- if (!responseObject.content || Object.keys(responseObject.content).length === 0) {
68
78
  return {
69
79
  key: key,
70
80
  label,
71
81
  statusCode: key,
72
- body: <OpenAPIEmptyExample context={context} />,
82
+ body: <OpenAPIResponse context={context} content={responseObject.content} />,
73
83
  };
74
- }
75
-
76
- return {
77
- key: key,
78
- label,
79
- statusCode: key,
80
- body: <OpenAPIResponse context={context} content={responseObject.content} />,
81
- };
82
- });
84
+ });
83
85
 
84
86
  if (tabs.length === 0) {
85
87
  return null;
@@ -20,8 +20,9 @@ export function OpenAPIResponses(props: {
20
20
  }) {
21
21
  const { responses, context } = props;
22
22
 
23
- const groups = Object.entries(responses).map(
24
- ([statusCode, response]: [string, OpenAPIV3.ResponseObject]) => {
23
+ const groups = Object.entries(responses)
24
+ .filter(([_, response]) => response && typeof response === 'object')
25
+ .map(([statusCode, response]: [string, OpenAPIV3.ResponseObject]) => {
25
26
  const tabs = (() => {
26
27
  // If there is no content, but there are headers, we need to show the headers
27
28
  if (
@@ -83,8 +84,7 @@ export function OpenAPIResponses(props: {
83
84
  ),
84
85
  tabs,
85
86
  };
86
- }
87
- );
87
+ });
88
88
 
89
89
  const state = useResponseExamplesState(context.blockKey, groups[0]?.key);
90
90