docusaurus-theme-openapi-docs 3.0.0-beta.1 → 3.0.0-beta.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 (142) hide show
  1. package/lib/markdown/utils.d.ts +3 -2
  2. package/lib/markdown/utils.js +1 -1
  3. package/lib/markdown/utils.test.d.ts +1 -0
  4. package/lib/markdown/utils.test.js +43 -0
  5. package/lib/theme/ApiDemoPanel/ApiCodeBlock/ExpandButton/index.d.ts +13 -0
  6. package/lib/theme/ApiDemoPanel/ApiCodeBlock/ExpandButton/index.js +199 -124
  7. package/lib/theme/ApiExplorer/Accept/index.d.ts +2 -2
  8. package/lib/theme/ApiExplorer/ApiCodeBlock/Container/index.d.ts +4 -0
  9. package/lib/theme/ApiExplorer/ApiCodeBlock/Container/index.js +25 -19
  10. package/lib/theme/ApiExplorer/ApiCodeBlock/Content/Element.d.ts +4 -0
  11. package/lib/theme/ApiExplorer/ApiCodeBlock/Content/Element.js +27 -16
  12. package/lib/theme/ApiExplorer/ApiCodeBlock/Content/String.d.ts +4 -0
  13. package/lib/theme/ApiExplorer/ApiCodeBlock/Content/String.js +115 -96
  14. package/lib/theme/ApiExplorer/ApiCodeBlock/CopyButton/index.d.ts +3 -0
  15. package/lib/theme/ApiExplorer/ApiCodeBlock/CopyButton/index.js +115 -54
  16. package/lib/theme/ApiExplorer/ApiCodeBlock/ExitButton/index.d.ts +6 -0
  17. package/lib/theme/ApiExplorer/ApiCodeBlock/ExitButton/index.js +41 -30
  18. package/lib/theme/ApiExplorer/ApiCodeBlock/ExpandButton/index.d.ts +14 -0
  19. package/lib/theme/ApiExplorer/ApiCodeBlock/ExpandButton/index.js +200 -120
  20. package/lib/theme/ApiExplorer/ApiCodeBlock/Line/index.d.ts +3 -0
  21. package/lib/theme/ApiExplorer/ApiCodeBlock/Line/index.js +36 -24
  22. package/lib/theme/ApiExplorer/ApiCodeBlock/WordWrapButton/index.d.ts +7 -0
  23. package/lib/theme/ApiExplorer/ApiCodeBlock/WordWrapButton/index.js +35 -28
  24. package/lib/theme/ApiExplorer/ApiCodeBlock/index.d.ts +3 -0
  25. package/lib/theme/ApiExplorer/ApiCodeBlock/index.js +72 -14
  26. package/lib/theme/ApiExplorer/Authorization/index.d.ts +2 -2
  27. package/lib/theme/ApiExplorer/Authorization/slice.d.ts +1 -1
  28. package/lib/theme/ApiExplorer/Body/index.d.ts +2 -2
  29. package/lib/theme/ApiExplorer/Body/index.js +8 -1
  30. package/lib/theme/ApiExplorer/Body/slice.d.ts +3 -3
  31. package/lib/theme/ApiExplorer/CodeSnippets/code-snippets-types.d.ts +21 -0
  32. package/lib/theme/ApiExplorer/CodeSnippets/code-snippets-types.js +8 -0
  33. package/lib/theme/ApiExplorer/CodeSnippets/index.d.ts +4 -14
  34. package/lib/theme/ApiExplorer/CodeSnippets/index.js +86 -8
  35. package/lib/theme/ApiExplorer/CodeSnippets/languages.d.ts +3 -0
  36. package/lib/theme/ApiExplorer/CodeSnippets/languages.js +48 -0
  37. package/lib/theme/ApiExplorer/CodeSnippets/languages.json +0 -96
  38. package/lib/theme/ApiExplorer/CodeTabs/_CodeTabs.scss +18 -2
  39. package/lib/theme/ApiExplorer/CodeTabs/index.d.ts +15 -0
  40. package/lib/theme/ApiExplorer/CodeTabs/index.js +131 -76
  41. package/lib/theme/ApiExplorer/ContentType/index.d.ts +2 -2
  42. package/lib/theme/ApiExplorer/Export/index.d.ts +2 -2
  43. package/lib/theme/ApiExplorer/FloatingButton/_FloatingButton.scss +3 -1
  44. package/lib/theme/ApiExplorer/FloatingButton/index.d.ts +1 -1
  45. package/lib/theme/ApiExplorer/FormFileUpload/index.d.ts +2 -2
  46. package/lib/theme/ApiExplorer/FormItem/index.d.ts +1 -1
  47. package/lib/theme/ApiExplorer/FormMultiSelect/index.d.ts +1 -1
  48. package/lib/theme/ApiExplorer/FormSelect/index.d.ts +1 -1
  49. package/lib/theme/ApiExplorer/FormTextInput/index.d.ts +1 -1
  50. package/lib/theme/ApiExplorer/MethodEndpoint/index.d.ts +2 -2
  51. package/lib/theme/ApiExplorer/ParamOptions/ParamFormItems/ParamArrayFormItem.d.ts +2 -2
  52. package/lib/theme/ApiExplorer/ParamOptions/ParamFormItems/ParamBooleanFormItem.d.ts +2 -2
  53. package/lib/theme/ApiExplorer/ParamOptions/ParamFormItems/ParamMultiSelectFormItem.d.ts +2 -2
  54. package/lib/theme/ApiExplorer/ParamOptions/ParamFormItems/ParamMultiSelectFormItem.js +4 -4
  55. package/lib/theme/ApiExplorer/ParamOptions/ParamFormItems/ParamSelectFormItem.d.ts +2 -2
  56. package/lib/theme/ApiExplorer/ParamOptions/ParamFormItems/ParamTextFormItem.d.ts +2 -2
  57. package/lib/theme/ApiExplorer/ParamOptions/_ParamOptions.scss +2 -1
  58. package/lib/theme/ApiExplorer/ParamOptions/index.d.ts +2 -2
  59. package/lib/theme/ApiExplorer/ParamOptions/slice.d.ts +1 -1
  60. package/lib/theme/ApiExplorer/Request/_Request.scss +4 -2
  61. package/lib/theme/ApiExplorer/Request/index.d.ts +2 -2
  62. package/lib/theme/ApiExplorer/Request/makeRequest.js +50 -1
  63. package/lib/theme/ApiExplorer/Response/_Response.scss +4 -2
  64. package/lib/theme/ApiExplorer/Response/index.d.ts +2 -2
  65. package/lib/theme/ApiExplorer/Response/index.js +19 -19
  66. package/lib/theme/ApiExplorer/SecuritySchemes/index.d.ts +2 -2
  67. package/lib/theme/ApiExplorer/Server/index.d.ts +2 -2
  68. package/lib/theme/ApiExplorer/buildPostmanRequest.d.ts +1 -1
  69. package/lib/theme/ApiExplorer/index.d.ts +2 -2
  70. package/lib/theme/ApiExplorer/index.js +1 -1
  71. package/lib/theme/ApiExplorer/storage-utils.d.ts +1 -1
  72. package/lib/theme/ApiItem/index.js +28 -3
  73. package/lib/theme/ApiItem/store.d.ts +6 -6
  74. package/lib/theme/ApiLogo/index.d.ts +2 -2
  75. package/lib/theme/ApiTabs/_ApiTabs.scss +3 -1
  76. package/lib/theme/ApiTabs/index.d.ts +7 -0
  77. package/lib/theme/ApiTabs/index.js +167 -103
  78. package/lib/theme/DiscriminatorTabs/index.d.ts +3 -0
  79. package/lib/theme/DiscriminatorTabs/index.js +152 -98
  80. package/lib/theme/Markdown/index.js +37 -0
  81. package/lib/theme/MimeTabs/index.d.ts +6 -0
  82. package/lib/theme/MimeTabs/index.js +169 -118
  83. package/lib/theme/OperationTabs/_OperationTabs.scss +71 -0
  84. package/lib/theme/OperationTabs/index.d.ts +3 -0
  85. package/lib/theme/OperationTabs/index.js +234 -0
  86. package/lib/theme/ParamsItem/index.d.ts +23 -0
  87. package/lib/theme/ParamsItem/index.js +170 -111
  88. package/lib/theme/ResponseSamples/index.d.ts +8 -0
  89. package/lib/theme/ResponseSamples/index.js +18 -13
  90. package/lib/theme/SchemaItem/index.d.ts +12 -0
  91. package/lib/theme/SchemaItem/index.js +121 -89
  92. package/lib/theme/SchemaTabs/_SchemaTabs.scss +0 -4
  93. package/lib/theme/SchemaTabs/index.d.ts +3 -0
  94. package/lib/theme/SchemaTabs/index.js +148 -95
  95. package/lib/theme/styles.scss +5 -0
  96. package/lib/types.d.ts +4 -4
  97. package/package.json +8 -7
  98. package/src/markdown/utils.test.ts +49 -0
  99. package/src/markdown/utils.ts +5 -3
  100. package/src/theme/ApiDemoPanel/ApiCodeBlock/ExpandButton/{index.js → index.tsx} +21 -8
  101. package/src/theme/ApiExplorer/ApiCodeBlock/Container/{index.js → index.tsx} +6 -3
  102. package/src/theme/ApiExplorer/ApiCodeBlock/Content/{Element.js → Element.tsx} +5 -1
  103. package/src/theme/ApiExplorer/ApiCodeBlock/Content/{String.js → String.tsx} +4 -4
  104. package/src/theme/ApiExplorer/ApiCodeBlock/CopyButton/{index.js → index.tsx} +8 -3
  105. package/src/theme/ApiExplorer/ApiCodeBlock/ExitButton/{index.js → index.tsx} +9 -1
  106. package/src/theme/ApiExplorer/ApiCodeBlock/ExpandButton/{index.js → index.tsx} +12 -2
  107. package/src/theme/ApiExplorer/ApiCodeBlock/Line/{index.js → index.tsx} +2 -1
  108. package/src/theme/ApiExplorer/ApiCodeBlock/WordWrapButton/{index.js → index.tsx} +11 -1
  109. package/src/theme/ApiExplorer/ApiCodeBlock/{index.js → index.tsx} +10 -5
  110. package/src/theme/ApiExplorer/Body/index.tsx +3 -1
  111. package/src/theme/ApiExplorer/CodeSnippets/code-snippets-types.ts +55 -0
  112. package/src/theme/ApiExplorer/CodeSnippets/index.tsx +94 -21
  113. package/src/theme/ApiExplorer/CodeSnippets/languages.json +0 -96
  114. package/src/theme/ApiExplorer/CodeSnippets/languages.ts +53 -0
  115. package/src/theme/ApiExplorer/CodeTabs/_CodeTabs.scss +18 -2
  116. package/src/theme/ApiExplorer/CodeTabs/{index.js → index.tsx} +64 -25
  117. package/src/theme/ApiExplorer/FloatingButton/_FloatingButton.scss +3 -1
  118. package/src/theme/ApiExplorer/ParamOptions/ParamFormItems/ParamMultiSelectFormItem.tsx +4 -4
  119. package/src/theme/ApiExplorer/ParamOptions/_ParamOptions.scss +2 -1
  120. package/src/theme/ApiExplorer/Request/_Request.scss +4 -2
  121. package/src/theme/ApiExplorer/Request/makeRequest.ts +59 -4
  122. package/src/theme/ApiExplorer/Response/_Response.scss +4 -2
  123. package/src/theme/ApiExplorer/Response/index.tsx +2 -2
  124. package/src/theme/ApiExplorer/index.tsx +1 -1
  125. package/src/theme/ApiItem/index.tsx +22 -3
  126. package/src/theme/ApiLogo/index.tsx +1 -1
  127. package/src/theme/ApiTabs/_ApiTabs.scss +3 -1
  128. package/src/theme/ApiTabs/{index.js → index.tsx} +75 -31
  129. package/src/theme/DiscriminatorTabs/{index.js → index.tsx} +63 -28
  130. package/src/theme/Markdown/index.js +37 -0
  131. package/src/theme/MimeTabs/{index.js → index.tsx} +64 -30
  132. package/src/theme/OperationTabs/_OperationTabs.scss +71 -0
  133. package/src/theme/OperationTabs/index.tsx +218 -0
  134. package/src/theme/ParamsItem/{index.js → index.tsx} +48 -17
  135. package/src/theme/ResponseSamples/{index.js → index.tsx} +10 -1
  136. package/src/theme/SchemaItem/{index.js → index.tsx} +24 -18
  137. package/src/theme/SchemaTabs/_SchemaTabs.scss +0 -4
  138. package/src/theme/SchemaTabs/{index.js → index.tsx} +62 -29
  139. package/src/theme/styles.scss +5 -0
  140. package/src/theme-classic.d.ts +69 -2
  141. package/src/theme-openapi.d.ts +6 -0
  142. package/tsconfig.json +4 -1
@@ -5,34 +5,57 @@
5
5
  * LICENSE file in the root directory of this source tree.
6
6
  * ========================================================================== */
7
7
 
8
- import React, { cloneElement } from "react";
8
+ import React, { cloneElement, ReactElement } from "react";
9
9
 
10
10
  import {
11
+ sanitizeTabsChildren,
12
+ type TabProps,
11
13
  useScrollPositionBlocker,
12
14
  useTabs,
13
15
  } from "@docusaurus/theme-common/internal";
16
+ import { TabItemProps } from "@docusaurus/theme-common/lib/utils/tabsUtils";
14
17
  import useIsBrowser from "@docusaurus/useIsBrowser";
15
- import { languageSet } from "@theme/ApiExplorer/CodeSnippets";
18
+ import { Language } from "@theme/ApiExplorer/CodeSnippets";
16
19
  import clsx from "clsx";
17
20
 
21
+ export interface Props {
22
+ action: {
23
+ [key: string]: React.Dispatch<any>;
24
+ };
25
+ currentLanguage: Language;
26
+ languageSet: Language[];
27
+ includeVariant: boolean;
28
+ }
29
+
30
+ export interface CodeTabsProps extends Props, TabProps {
31
+ includeSample?: boolean;
32
+ }
33
+
18
34
  function TabList({
19
35
  action,
20
36
  currentLanguage,
37
+ languageSet,
21
38
  includeVariant,
39
+ includeSample,
22
40
  className,
23
41
  block,
24
42
  selectedValue,
25
43
  selectValue,
26
44
  tabValues,
27
- }) {
28
- const tabRefs = [];
45
+ }: CodeTabsProps & ReturnType<typeof useTabs>) {
46
+ const tabRefs: (HTMLLIElement | null)[] = [];
29
47
  const { blockElementScrollPositionUntilNextRender } =
30
48
  useScrollPositionBlocker();
31
49
 
32
- const handleTabChange = (event) => {
50
+ const handleTabChange = (
51
+ event:
52
+ | React.FocusEvent<HTMLLIElement>
53
+ | React.MouseEvent<HTMLLIElement>
54
+ | React.KeyboardEvent<HTMLLIElement>
55
+ ) => {
33
56
  const newTab = event.currentTarget;
34
57
  const newTabIndex = tabRefs.indexOf(newTab);
35
- const newTabValue = tabValues[newTabIndex].value;
58
+ const newTabValue = tabValues[newTabIndex]!.value;
36
59
 
37
60
  if (newTabValue !== selectedValue) {
38
61
  blockElementScrollPositionUntilNextRender(newTab);
@@ -40,25 +63,33 @@ function TabList({
40
63
  }
41
64
 
42
65
  if (action) {
43
- let newLanguage;
66
+ let newLanguage: Language;
44
67
  if (currentLanguage && includeVariant) {
45
68
  newLanguage = languageSet.filter(
46
- (lang) => lang.language === currentLanguage
69
+ (lang: Language) => lang.language === currentLanguage
47
70
  )[0];
48
71
  newLanguage.variant = newTabValue;
49
72
  action.setSelectedVariant(newTabValue.toLowerCase());
73
+ } else if (currentLanguage && includeSample) {
74
+ newLanguage = languageSet.filter(
75
+ (lang: Language) => lang.language === currentLanguage
76
+ )[0];
77
+ newLanguage.sample = newTabValue;
78
+ action.setSelectedSample(newTabValue);
50
79
  } else {
51
80
  newLanguage = languageSet.filter(
52
- (lang) => lang.language === newTabValue
81
+ (lang: Language) => lang.language === newTabValue
53
82
  )[0];
54
83
  action.setSelectedVariant(newLanguage.variant.toLowerCase());
84
+ action.setSelectedSample(newLanguage.sample);
55
85
  }
56
86
  action.setLanguage(newLanguage);
57
87
  }
58
88
  };
59
89
 
60
- const handleKeydown = (event) => {
61
- let focusElement = null;
90
+ const handleKeydown = (event: React.KeyboardEvent<HTMLLIElement>) => {
91
+ let focusElement: HTMLLIElement | null = null;
92
+
62
93
  switch (event.key) {
63
94
  case "Enter": {
64
95
  handleTabChange(event);
@@ -66,17 +97,18 @@ function TabList({
66
97
  }
67
98
  case "ArrowRight": {
68
99
  const nextTab = tabRefs.indexOf(event.currentTarget) + 1;
69
- focusElement = tabRefs[nextTab] ?? tabRefs[0];
100
+ focusElement = tabRefs[nextTab] ?? tabRefs[0]!;
70
101
  break;
71
102
  }
72
103
  case "ArrowLeft": {
73
104
  const prevTab = tabRefs.indexOf(event.currentTarget) - 1;
74
- focusElement = tabRefs[prevTab] ?? tabRefs[tabRefs.length - 1];
105
+ focusElement = tabRefs[prevTab] ?? tabRefs[tabRefs.length - 1]!;
75
106
  break;
76
107
  }
77
108
  default:
78
109
  break;
79
110
  }
111
+
80
112
  focusElement?.focus();
81
113
  };
82
114
 
@@ -107,7 +139,7 @@ function TabList({
107
139
  className={clsx(
108
140
  "tabs__item",
109
141
  "openapi-tabs__code-item",
110
- attributes?.className,
142
+ attributes?.className as string,
111
143
  {
112
144
  active: selectedValue === value,
113
145
  }
@@ -120,11 +152,16 @@ function TabList({
120
152
  );
121
153
  }
122
154
 
123
- function TabContent({ lazy, children, selectedValue }) {
124
- // eslint-disable-next-line no-param-reassign
125
- children = Array.isArray(children) ? children : [children];
155
+ function TabContent({
156
+ lazy,
157
+ children,
158
+ selectedValue,
159
+ }: CodeTabsProps & ReturnType<typeof useTabs>): React.JSX.Element | null {
160
+ const childTabs = (Array.isArray(children) ? children : [children]).filter(
161
+ Boolean
162
+ ) as ReactElement<TabItemProps>[];
126
163
  if (lazy) {
127
- const selectedTabItem = children.find(
164
+ const selectedTabItem = childTabs.find(
128
165
  (tabItem) => tabItem.props.value === selectedValue
129
166
  );
130
167
  if (!selectedTabItem) {
@@ -135,7 +172,7 @@ function TabContent({ lazy, children, selectedValue }) {
135
172
  }
136
173
  return (
137
174
  <div className="margin-top--md openapi-tabs__code-content">
138
- {children.map((tabItem, i) =>
175
+ {childTabs.map((tabItem, i) =>
139
176
  cloneElement(tabItem, {
140
177
  key: i,
141
178
  hidden: tabItem.props.value !== selectedValue,
@@ -145,15 +182,13 @@ function TabContent({ lazy, children, selectedValue }) {
145
182
  );
146
183
  }
147
184
 
148
- function TabsComponent(props) {
185
+ function TabsComponent(props: CodeTabsProps & Props): React.JSX.Element {
149
186
  const tabs = useTabs(props);
150
187
  const { className } = props;
151
188
 
152
189
  return (
153
190
  <div
154
- className={clsx("tabs-container openapi-tabs__code-container", {
155
- [className]: className,
156
- })}
191
+ className={clsx("tabs-container openapi-tabs__code-container", className)}
157
192
  >
158
193
  <TabList {...props} {...tabs} />
159
194
  <TabContent {...props} {...tabs} />
@@ -161,7 +196,9 @@ function TabsComponent(props) {
161
196
  );
162
197
  }
163
198
 
164
- export default function CodeTabs(props) {
199
+ export default function CodeTabs(
200
+ props: CodeTabsProps & Props
201
+ ): React.JSX.Element {
165
202
  const isBrowser = useIsBrowser();
166
203
  return (
167
204
  <TabsComponent
@@ -169,6 +206,8 @@ export default function CodeTabs(props) {
169
206
  // Temporary fix for https://github.com/facebook/docusaurus/issues/5653
170
207
  key={String(isBrowser)}
171
208
  {...props}
172
- />
209
+ >
210
+ {sanitizeTabsChildren(props.children)}
211
+ </TabsComponent>
173
212
  );
174
213
  }
@@ -11,7 +11,9 @@
11
11
  padding: 0.4rem 0.5rem;
12
12
  opacity: 0;
13
13
  visibility: hidden;
14
- transition: opacity 0.2s ease-in-out, visibility 0.2s ease-in-out,
14
+ transition:
15
+ opacity 0.2s ease-in-out,
16
+ visibility 0.2s ease-in-out,
15
17
  bottom 0.2s ease-in-out;
16
18
  position: absolute;
17
19
  right: calc(var(--ifm-pre-padding) / 2);
@@ -37,10 +37,10 @@ export default function ParamMultiSelectFormItem({ param }: ParamProps) {
37
37
  const paramTypeToWatch = pathParams.length
38
38
  ? pathParams
39
39
  : queryParams.length
40
- ? queryParams
41
- : cookieParams.length
42
- ? cookieParams
43
- : headerParams;
40
+ ? queryParams
41
+ : cookieParams.length
42
+ ? cookieParams
43
+ : headerParams;
44
44
 
45
45
  const handleChange = (e: any, onChange: any) => {
46
46
  const values = Array.prototype.filter
@@ -107,7 +107,8 @@
107
107
  }
108
108
 
109
109
  &:active {
110
- box-shadow: inset 0 0 0 1px var(--openapi-input-border),
110
+ box-shadow:
111
+ inset 0 0 0 1px var(--openapi-input-border),
111
112
  inset 0 0 0 2px var(--openapi-inverse-color);
112
113
  }
113
114
  }
@@ -2,7 +2,8 @@
2
2
  background-color: var(--ifm-pre-background);
3
3
  border-radius: var(--openapi-card-border-radius);
4
4
  border: 1px solid var(--openapi-explorer-border-color);
5
- box-shadow: 0 2px 3px hsla(222, 8%, 43%, 0.1),
5
+ box-shadow:
6
+ 0 2px 3px hsla(222, 8%, 43%, 0.1),
6
7
  0 8px 16px -10px hsla(222, 8%, 43%, 0.2);
7
8
  color: var(--ifm-pre-color);
8
9
  line-height: var(--ifm-pre-line-height);
@@ -19,7 +20,8 @@
19
20
  }
20
21
 
21
22
  &:hover {
22
- box-shadow: 0 0 0 2px rgba(38, 53, 61, 0.15),
23
+ box-shadow:
24
+ 0 0 0 2px rgba(38, 53, 61, 0.15),
23
25
  0 2px 3px hsla(222, 8%, 43%, 0.15),
24
26
  0 16px 16px -10px hsla(222, 8%, 43%, 0.2);
25
27
  }
@@ -161,6 +161,10 @@ async function makeRequest(
161
161
  if (data.key && data.value.content) {
162
162
  myBody.append(data.key, data.value.content);
163
163
  }
164
+ // handle generic key-value payload
165
+ if (data.key && typeof data.value === "string") {
166
+ myBody.append(data.key, data.value);
167
+ }
164
168
  }
165
169
  }
166
170
  break;
@@ -189,11 +193,62 @@ async function makeRequest(
189
193
  finalUrl = normalizedProxy + request.url.toString();
190
194
  }
191
195
 
192
- return await fetchWithtimeout(finalUrl, requestOptions).then(
193
- (response: any) => {
194
- return response;
196
+ return fetchWithtimeout(finalUrl, requestOptions).then((response: any) => {
197
+ const contentType = response.headers.get("content-type");
198
+ let fileExtension = "";
199
+
200
+ if (contentType) {
201
+ if (contentType.includes("application/pdf")) {
202
+ fileExtension = ".pdf";
203
+ } else if (contentType.includes("image/jpeg")) {
204
+ fileExtension = ".jpg";
205
+ } else if (contentType.includes("image/png")) {
206
+ fileExtension = ".png";
207
+ } else if (contentType.includes("image/gif")) {
208
+ fileExtension = ".gif";
209
+ } else if (contentType.includes("image/webp")) {
210
+ fileExtension = ".webp";
211
+ } else if (contentType.includes("video/mpeg")) {
212
+ fileExtension = ".mpeg";
213
+ } else if (contentType.includes("video/mp4")) {
214
+ fileExtension = ".mp4";
215
+ } else if (contentType.includes("audio/mpeg")) {
216
+ fileExtension = ".mp3";
217
+ } else if (contentType.includes("audio/ogg")) {
218
+ fileExtension = ".ogg";
219
+ } else if (contentType.includes("application/octet-stream")) {
220
+ fileExtension = ".bin";
221
+ } else if (contentType.includes("application/zip")) {
222
+ fileExtension = ".zip";
223
+ }
224
+
225
+ if (fileExtension) {
226
+ return response.blob().then((blob: any) => {
227
+ const url = window.URL.createObjectURL(blob);
228
+
229
+ const link = document.createElement("a");
230
+ link.href = url;
231
+ // Now the file name includes the extension
232
+ link.setAttribute("download", `file${fileExtension}`);
233
+
234
+ // These two lines are necessary to make the link click in Firefox
235
+ link.style.display = "none";
236
+ document.body.appendChild(link);
237
+
238
+ link.click();
239
+
240
+ // After link is clicked, it's safe to remove it.
241
+ setTimeout(() => document.body.removeChild(link), 0);
242
+
243
+ return response;
244
+ });
245
+ } else {
246
+ return response;
247
+ }
195
248
  }
196
- );
249
+
250
+ return response;
251
+ });
197
252
  }
198
253
 
199
254
  export default makeRequest;
@@ -2,7 +2,8 @@
2
2
  background-color: var(--ifm-pre-background);
3
3
  border-radius: var(--openapi-card-border-radius);
4
4
  border: 1px solid var(--openapi-explorer-border-color);
5
- box-shadow: 0 2px 3px hsla(222, 8%, 43%, 0.1),
5
+ box-shadow:
6
+ 0 2px 3px hsla(222, 8%, 43%, 0.1),
6
7
  0 8px 16px -10px hsla(222, 8%, 43%, 0.2);
7
8
  color: var(--ifm-pre-color);
8
9
  line-height: var(--ifm-pre-line-height);
@@ -12,7 +13,8 @@
12
13
  transition: 300ms;
13
14
 
14
15
  &:hover {
15
- box-shadow: 0 0 0 2px rgba(38, 53, 61, 0.15),
16
+ box-shadow:
17
+ 0 0 0 2px rgba(38, 53, 61, 0.15),
16
18
  0 2px 3px hsla(222, 8%, 43%, 0.15),
17
19
  0 16px 16px -10px hsla(222, 8%, 43%, 0.2);
18
20
  }
@@ -52,8 +52,8 @@ function Response({ item }: { item: NonNullable<ApiItem> }) {
52
52
  (parseInt(code) >= 400
53
53
  ? "openapi-response__dot--danger"
54
54
  : parseInt(code) >= 200 && parseInt(code) < 300
55
- ? "openapi-response__dot--success"
56
- : "openapi-response__dot--info");
55
+ ? "openapi-response__dot--success"
56
+ : "openapi-response__dot--info");
57
57
 
58
58
  if (!item.servers || hideSendButton) {
59
59
  return null;
@@ -27,7 +27,7 @@ function ApiExplorer({
27
27
  {item.method !== "event" && (
28
28
  <CodeSnippets
29
29
  postman={postman}
30
- codeSamples={(item as any)["x-code-samples"] ?? []}
30
+ codeSamples={(item as any)["x-codeSamples"] ?? []}
31
31
  />
32
32
  )}
33
33
  <Request item={item} />
@@ -12,6 +12,7 @@ import React from "react";
12
12
  import BrowserOnly from "@docusaurus/BrowserOnly";
13
13
  import ExecutionEnvironment from "@docusaurus/ExecutionEnvironment";
14
14
  import { HtmlClassNameProvider } from "@docusaurus/theme-common";
15
+ import { DocProvider } from "@docusaurus/theme-common/internal";
15
16
  import useDocusaurusContext from "@docusaurus/useDocusaurusContext";
16
17
  import useIsBrowser from "@docusaurus/useIsBrowser";
17
18
  import { createAuth } from "@theme/ApiExplorer/Authorization/slice";
@@ -23,7 +24,6 @@ import clsx from "clsx";
23
24
  import { ServerObject } from "docusaurus-plugin-openapi-docs/src/openapi/types";
24
25
  import { ParameterObject } from "docusaurus-plugin-openapi-docs/src/openapi/types";
25
26
  import type { ApiItem as ApiItemType } from "docusaurus-plugin-openapi-docs/src/types";
26
- /* eslint-disable import/no-extraneous-dependencies*/
27
27
  import type {
28
28
  DocFrontMatter,
29
29
  ThemeConfig,
@@ -32,8 +32,6 @@ import { Provider } from "react-redux";
32
32
 
33
33
  import { createStoreWithoutState, createStoreWithState } from "./store";
34
34
 
35
- const { DocProvider } = require("@docusaurus/theme-common/internal");
36
-
37
35
  let ApiExplorer = (_: { item: any; infoPath: any }) => <div />;
38
36
 
39
37
  if (ExecutionEnvironment.canUseDOM) {
@@ -44,12 +42,18 @@ interface ApiFrontMatter extends DocFrontMatter {
44
42
  readonly api?: ApiItemType;
45
43
  }
46
44
 
45
+ interface SchemaFrontMatter extends DocFrontMatter {
46
+ readonly schema?: boolean;
47
+ }
48
+
49
+ // @ts-ignore
47
50
  export default function ApiItem(props: Props): JSX.Element {
48
51
  const docHtmlClassName = `docs-doc-id-${props.content.metadata.id}`;
49
52
  const MDXComponent = props.content;
50
53
  const { frontMatter } = MDXComponent;
51
54
  const { info_path: infoPath } = frontMatter as DocFrontMatter;
52
55
  let { api } = frontMatter as ApiFrontMatter;
56
+ const { schema } = frontMatter as SchemaFrontMatter;
53
57
  // decompress and parse
54
58
  if (api) {
55
59
  api = JSON.parse(
@@ -159,6 +163,21 @@ export default function ApiItem(props: Props): JSX.Element {
159
163
  </HtmlClassNameProvider>
160
164
  </DocProvider>
161
165
  );
166
+ } else if (schema) {
167
+ return (
168
+ <DocProvider content={props.content}>
169
+ <HtmlClassNameProvider className={docHtmlClassName}>
170
+ <DocItemMetadata />
171
+ <DocItemLayout>
172
+ <div className={clsx("row", "theme-api-markdown")}>
173
+ <div className="col col--12">
174
+ <MDXComponent />
175
+ </div>
176
+ </div>
177
+ </DocItemLayout>
178
+ </HtmlClassNameProvider>
179
+ </DocProvider>
180
+ );
162
181
  }
163
182
 
164
183
  // Non-API docs
@@ -11,7 +11,7 @@ import { useColorMode } from "@docusaurus/theme-common";
11
11
  import useBaseUrl from "@docusaurus/useBaseUrl";
12
12
  import ThemedImage from "@theme/ThemedImage";
13
13
 
14
- export default function ApiLogo(props: any): JSX.Element | undefined {
14
+ export default function ApiLogo(props: any): React.JSX.Element | undefined {
15
15
  const { colorMode } = useColorMode();
16
16
  const { logo, darkLogo } = props;
17
17
  const altText = () => {
@@ -10,7 +10,9 @@
10
10
  }
11
11
 
12
12
  .openapi-tabs__response-header {
13
- margin-bottom: 0;
13
+ &.openapi-tabs__heading {
14
+ margin-bottom: 0;
15
+ }
14
16
  }
15
17
 
16
18
  .openapi-tabs__response-code-item {
@@ -5,33 +5,62 @@
5
5
  * LICENSE file in the root directory of this source tree.
6
6
  * ========================================================================== */
7
7
 
8
- import React, { cloneElement, useRef, useState, useEffect } from "react";
8
+ import React, {
9
+ cloneElement,
10
+ useRef,
11
+ useState,
12
+ useEffect,
13
+ ReactElement,
14
+ } from "react";
9
15
 
10
16
  import {
17
+ sanitizeTabsChildren,
18
+ TabProps,
11
19
  useScrollPositionBlocker,
12
20
  useTabs,
13
21
  } from "@docusaurus/theme-common/internal";
22
+ import { TabItemProps } from "@docusaurus/theme-common/lib/utils/tabsUtils";
14
23
  import useIsBrowser from "@docusaurus/useIsBrowser";
15
24
  import Heading from "@theme/Heading";
16
25
  import clsx from "clsx";
17
26
 
18
- function TabList({ className, block, selectedValue, selectValue, tabValues }) {
19
- const tabRefs = [];
27
+ export interface TabListProps extends TabProps {
28
+ label: string;
29
+ id: string;
30
+ }
31
+
32
+ function TabList({
33
+ className,
34
+ block,
35
+ selectedValue,
36
+ selectValue,
37
+ tabValues,
38
+ label = "Responses",
39
+ id = "responses",
40
+ }: TabListProps & ReturnType<typeof useTabs>) {
41
+ const tabRefs: (HTMLLIElement | null)[] = [];
20
42
  const { blockElementScrollPositionUntilNextRender } =
21
43
  useScrollPositionBlocker();
22
44
 
23
- const handleTabChange = (event) => {
45
+ const handleTabChange = (
46
+ event:
47
+ | React.FocusEvent<HTMLLIElement>
48
+ | React.MouseEvent<HTMLLIElement>
49
+ | React.KeyboardEvent<HTMLLIElement>
50
+ ) => {
24
51
  const newTab = event.currentTarget;
25
52
  const newTabIndex = tabRefs.indexOf(newTab);
26
53
  const newTabValue = tabValues[newTabIndex].value;
54
+
27
55
  if (newTabValue !== selectedValue) {
28
56
  blockElementScrollPositionUntilNextRender(newTab);
29
57
  selectValue(newTabValue);
30
58
  }
31
59
  };
32
60
 
33
- const handleKeydown = (event) => {
34
- let focusElement = null;
61
+ const handleKeydown = (event: React.KeyboardEvent<HTMLLIElement>) => {
62
+ let focusElement: HTMLLIElement | null = null;
63
+
35
64
  switch (event.key) {
36
65
  case "Enter": {
37
66
  handleTabChange(event);
@@ -39,35 +68,38 @@ function TabList({ className, block, selectedValue, selectValue, tabValues }) {
39
68
  }
40
69
  case "ArrowRight": {
41
70
  const nextTab = tabRefs.indexOf(event.currentTarget) + 1;
42
- focusElement = tabRefs[nextTab] ?? tabRefs[0];
71
+ focusElement = tabRefs[nextTab] ?? tabRefs[0]!;
43
72
  break;
44
73
  }
45
74
  case "ArrowLeft": {
46
75
  const prevTab = tabRefs.indexOf(event.currentTarget) - 1;
47
- focusElement = tabRefs[prevTab] ?? tabRefs[tabRefs.length - 1];
76
+ focusElement = tabRefs[prevTab] ?? tabRefs[tabRefs.length - 1]!;
48
77
  break;
49
78
  }
50
79
  default:
51
80
  break;
52
81
  }
82
+
53
83
  focusElement?.focus();
54
84
  };
55
85
 
56
- const tabItemListContainerRef = useRef(null);
57
- const [showTabArrows, setShowTabArrows] = useState(false);
86
+ const tabItemListContainerRef = useRef<HTMLUListElement>(null);
87
+ const [showTabArrows, setShowTabArrows] = useState<boolean>(false);
58
88
 
59
89
  useEffect(() => {
60
90
  const resizeObserver = new ResizeObserver((entries) => {
61
91
  for (let entry of entries) {
62
- if (entry.target.offsetWidth < entry.target.scrollWidth) {
63
- setShowTabArrows(true);
64
- } else {
65
- setShowTabArrows(false);
66
- }
92
+ requestAnimationFrame(() => {
93
+ if (entry.target.clientWidth < entry.target.scrollWidth) {
94
+ setShowTabArrows(true);
95
+ } else {
96
+ setShowTabArrows(false);
97
+ }
98
+ });
67
99
  }
68
100
  });
69
101
 
70
- resizeObserver.observe(tabItemListContainerRef.current);
102
+ resizeObserver.observe(tabItemListContainerRef.current!);
71
103
 
72
104
  return () => {
73
105
  resizeObserver.disconnect();
@@ -75,17 +107,21 @@ function TabList({ className, block, selectedValue, selectValue, tabValues }) {
75
107
  }, []);
76
108
 
77
109
  const handleRightClick = () => {
78
- tabItemListContainerRef.current.scrollLeft += 90;
110
+ tabItemListContainerRef.current!.scrollLeft += 90;
79
111
  };
80
112
 
81
113
  const handleLeftClick = () => {
82
- tabItemListContainerRef.current.scrollLeft -= 90;
114
+ tabItemListContainerRef.current!.scrollLeft -= 90;
83
115
  };
84
116
 
85
117
  return (
86
118
  <div className="openapi-tabs__response-header-section">
87
- <Heading as="h2" id="responses" className="openapi-tabs__response-header">
88
- Responses
119
+ <Heading
120
+ as="h2"
121
+ id={id}
122
+ className="openapi-tabs__heading openapi-tabs__response-header"
123
+ >
124
+ {label}
89
125
  </Heading>
90
126
  <div className="openapi-tabs__response-container">
91
127
  {showTabArrows && (
@@ -121,12 +157,12 @@ function TabList({ className, block, selectedValue, selectValue, tabValues }) {
121
157
  className={clsx(
122
158
  "tabs__item",
123
159
  "openapi-tabs__response-code-item",
124
- attributes?.className,
160
+ attributes?.className as string,
125
161
  parseInt(value) >= 400
126
162
  ? "danger"
127
163
  : parseInt(value) >= 200 && parseInt(value) < 300
128
- ? "success"
129
- : "info",
164
+ ? "success"
165
+ : "info",
130
166
  {
131
167
  active: selectedValue === value,
132
168
  }
@@ -146,11 +182,17 @@ function TabList({ className, block, selectedValue, selectValue, tabValues }) {
146
182
  </div>
147
183
  );
148
184
  }
149
- function TabContent({ lazy, children, selectedValue }) {
150
- // eslint-disable-next-line no-param-reassign
151
- children = Array.isArray(children) ? children : [children];
185
+
186
+ function TabContent({
187
+ lazy,
188
+ children,
189
+ selectedValue,
190
+ }: TabProps & ReturnType<typeof useTabs>): React.JSX.Element | null {
191
+ const childTabs = (Array.isArray(children) ? children : [children]).filter(
192
+ Boolean
193
+ ) as ReactElement<TabItemProps>[];
152
194
  if (lazy) {
153
- const selectedTabItem = children.find(
195
+ const selectedTabItem = childTabs.find(
154
196
  (tabItem) => tabItem.props.value === selectedValue
155
197
  );
156
198
  if (!selectedTabItem) {
@@ -161,7 +203,7 @@ function TabContent({ lazy, children, selectedValue }) {
161
203
  }
162
204
  return (
163
205
  <div className="margin-top--md">
164
- {children.map((tabItem, i) =>
206
+ {childTabs.map((tabItem, i) =>
165
207
  cloneElement(tabItem, {
166
208
  key: i,
167
209
  hidden: tabItem.props.value !== selectedValue,
@@ -170,7 +212,7 @@ function TabContent({ lazy, children, selectedValue }) {
170
212
  </div>
171
213
  );
172
214
  }
173
- function TabsComponent(props) {
215
+ function TabsComponent(props: TabListProps): React.JSX.Element {
174
216
  const tabs = useTabs(props);
175
217
  return (
176
218
  <div className="openapi-tabs__container">
@@ -179,7 +221,7 @@ function TabsComponent(props) {
179
221
  </div>
180
222
  );
181
223
  }
182
- export default function ApiTabs(props) {
224
+ export default function ApiTabs(props: TabListProps): React.JSX.Element {
183
225
  const isBrowser = useIsBrowser();
184
226
  return (
185
227
  <TabsComponent
@@ -187,6 +229,8 @@ export default function ApiTabs(props) {
187
229
  // Temporary fix for https://github.com/facebook/docusaurus/issues/5653
188
230
  key={String(isBrowser)}
189
231
  {...props}
190
- />
232
+ >
233
+ {sanitizeTabsChildren(props.children)}
234
+ </TabsComponent>
191
235
  );
192
236
  }