@gitbook/react-openapi 1.2.0 → 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.
- package/CHANGELOG.md +26 -0
- package/dist/OpenAPIDisclosure.d.ts +1 -0
- package/dist/OpenAPIDisclosure.jsx +6 -3
- package/dist/OpenAPIDisclosureGroup.jsx +17 -16
- package/dist/OpenAPIResponse.jsx +18 -2
- package/dist/OpenAPIResponseExample.jsx +8 -3
- package/dist/OpenAPIResponses.jsx +7 -2
- package/dist/OpenAPISchema.d.ts +9 -2
- package/dist/OpenAPISchema.jsx +93 -59
- package/dist/OpenAPISchemaName.d.ts +1 -1
- package/dist/OpenAPISchemaName.jsx +1 -1
- package/dist/StaticSection.jsx +1 -1
- package/dist/code-samples.js +5 -2
- package/dist/generateSchemaExample.js +5 -0
- package/dist/getDisclosureLabel.d.ts +7 -0
- package/dist/getDisclosureLabel.js +18 -0
- package/dist/schemas/OpenAPISchemaItem.d.ts +7 -0
- package/dist/schemas/OpenAPISchemaItem.jsx +16 -0
- package/dist/schemas/OpenAPISchemas.jsx +3 -9
- package/dist/translations/de.d.ts +6 -1
- package/dist/translations/de.js +9 -4
- package/dist/translations/en.d.ts +6 -1
- package/dist/translations/en.js +8 -3
- package/dist/translations/es.d.ts +6 -1
- package/dist/translations/es.js +9 -4
- package/dist/translations/fr.d.ts +6 -1
- package/dist/translations/fr.js +10 -5
- package/dist/translations/index.d.ts +54 -9
- package/dist/translations/ja.d.ts +6 -1
- package/dist/translations/ja.js +8 -3
- package/dist/translations/nl.d.ts +6 -1
- package/dist/translations/nl.js +8 -3
- package/dist/translations/no.d.ts +6 -1
- package/dist/translations/no.js +9 -4
- package/dist/translations/pt-br.d.ts +6 -1
- package/dist/translations/pt-br.js +9 -4
- package/dist/translations/zh.d.ts +6 -1
- package/dist/translations/zh.js +9 -4
- package/dist/tsconfig.build.tsbuildinfo +1 -1
- package/package.json +1 -1
- package/src/OpenAPIDisclosure.tsx +7 -3
- package/src/OpenAPIDisclosureGroup.tsx +49 -47
- package/src/OpenAPIResponse.tsx +34 -2
- package/src/OpenAPIResponseExample.tsx +36 -34
- package/src/OpenAPIResponses.tsx +5 -4
- package/src/OpenAPISchema.tsx +167 -103
- package/src/OpenAPISchemaName.tsx +2 -2
- package/src/StaticSection.tsx +1 -1
- package/src/code-samples.test.ts +2 -1
- package/src/code-samples.ts +5 -2
- package/src/generateSchemaExample.ts +8 -0
- package/src/getDisclosureLabel.ts +25 -0
- package/src/schemas/OpenAPISchemaItem.tsx +34 -0
- package/src/schemas/OpenAPISchemas.tsx +7 -13
- package/src/translations/de.ts +9 -4
- package/src/translations/en.ts +8 -3
- package/src/translations/es.ts +9 -4
- package/src/translations/fr.ts +10 -5
- package/src/translations/ja.ts +8 -3
- package/src/translations/nl.ts +8 -3
- package/src/translations/no.ts +9 -4
- package/src/translations/pt-br.ts +9 -4
- package/src/translations/zh.ts +9 -4
package/package.json
CHANGED
|
@@ -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,
|
|
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
|
-
{
|
|
35
|
-
<
|
|
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<
|
|
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,54 +96,56 @@ function DisclosureItem(props: {
|
|
|
96
96
|
|
|
97
97
|
return (
|
|
98
98
|
<div className="openapi-disclosure-group" aria-expanded={state.isExpanded}>
|
|
99
|
-
<div
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
>
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
<
|
|
115
|
-
|
|
116
|
-
|
|
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
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
{tab.
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
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>
|
|
147
149
|
</div>
|
|
148
150
|
|
|
149
151
|
{state.isExpanded && selectedTab && (
|
package/src/OpenAPIResponse.tsx
CHANGED
|
@@ -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
|
|
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={[
|
|
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
|
|
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
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
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
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
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: <
|
|
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;
|
package/src/OpenAPIResponses.tsx
CHANGED
|
@@ -20,8 +20,9 @@ export function OpenAPIResponses(props: {
|
|
|
20
20
|
}) {
|
|
21
21
|
const { responses, context } = props;
|
|
22
22
|
|
|
23
|
-
const groups = Object.entries(responses)
|
|
24
|
-
([
|
|
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
|
|
|
@@ -98,6 +98,7 @@ export function OpenAPIResponses(props: {
|
|
|
98
98
|
state.setKey(key);
|
|
99
99
|
}}
|
|
100
100
|
groups={groups}
|
|
101
|
+
selectIcon={context.icons.chevronDown}
|
|
101
102
|
selectStateKey={createStateKey('response-media-types', context.blockKey)}
|
|
102
103
|
/>
|
|
103
104
|
</StaticSection>
|