docusaurus-theme-openapi-docs 4.7.1 → 5.0.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 (127) hide show
  1. package/lib/index.js +2 -0
  2. package/lib/markdown/schema.js +63 -9
  3. package/lib/theme/ApiExplorer/Accept/index.js +2 -1
  4. package/lib/theme/ApiExplorer/Authorization/index.js +12 -18
  5. package/lib/theme/ApiExplorer/Body/FileArrayFormBodyItem/index.js +0 -4
  6. package/lib/theme/ApiExplorer/Body/FormBodyItem/index.d.ts +5 -1
  7. package/lib/theme/ApiExplorer/Body/FormBodyItem/index.js +190 -37
  8. package/lib/theme/ApiExplorer/Body/index.js +84 -13
  9. package/lib/theme/ApiExplorer/Body/slice.d.ts +136 -544
  10. package/lib/theme/ApiExplorer/CodeSnippets/index.d.ts +2 -1
  11. package/lib/theme/ApiExplorer/CodeSnippets/index.js +4 -0
  12. package/lib/theme/ApiExplorer/CodeTabs/index.js +15 -16
  13. package/lib/theme/ApiExplorer/ContentType/index.js +7 -2
  14. package/lib/theme/ApiExplorer/EncodingSelection/slice.d.ts +17 -0
  15. package/lib/theme/ApiExplorer/EncodingSelection/slice.js +29 -0
  16. package/lib/theme/ApiExplorer/EncodingSelection/useResolvedEncoding.d.ts +12 -0
  17. package/lib/theme/ApiExplorer/EncodingSelection/useResolvedEncoding.js +39 -0
  18. package/lib/theme/ApiExplorer/FormItem/_FormItem.scss +0 -5
  19. package/lib/theme/ApiExplorer/FormItem/index.d.ts +1 -4
  20. package/lib/theme/ApiExplorer/FormItem/index.js +2 -26
  21. package/lib/theme/ApiExplorer/FormLabel/_FormLabel.scss +4 -0
  22. package/lib/theme/ApiExplorer/FormLabel/index.d.ts +9 -0
  23. package/lib/theme/ApiExplorer/FormLabel/index.js +50 -0
  24. package/lib/theme/ApiExplorer/FormMultiSelect/index.d.ts +4 -1
  25. package/lib/theme/ApiExplorer/FormMultiSelect/index.js +97 -19
  26. package/lib/theme/ApiExplorer/FormSelect/index.d.ts +6 -1
  27. package/lib/theme/ApiExplorer/FormSelect/index.js +96 -15
  28. package/lib/theme/ApiExplorer/FormTextInput/index.d.ts +4 -1
  29. package/lib/theme/ApiExplorer/FormTextInput/index.js +71 -1
  30. package/lib/theme/ApiExplorer/MethodEndpoint/index.js +28 -0
  31. package/lib/theme/ApiExplorer/ParamOptions/ParamFormItems/ParamArrayFormItem.d.ts +4 -1
  32. package/lib/theme/ApiExplorer/ParamOptions/ParamFormItems/ParamArrayFormItem.js +11 -3
  33. package/lib/theme/ApiExplorer/ParamOptions/ParamFormItems/ParamBooleanFormItem.d.ts +4 -1
  34. package/lib/theme/ApiExplorer/ParamOptions/ParamFormItems/ParamBooleanFormItem.js +4 -1
  35. package/lib/theme/ApiExplorer/ParamOptions/ParamFormItems/ParamMultiSelectFormItem.d.ts +4 -1
  36. package/lib/theme/ApiExplorer/ParamOptions/ParamFormItems/ParamMultiSelectFormItem.js +6 -2
  37. package/lib/theme/ApiExplorer/ParamOptions/ParamFormItems/ParamSelectFormItem.d.ts +4 -1
  38. package/lib/theme/ApiExplorer/ParamOptions/ParamFormItems/ParamSelectFormItem.js +6 -2
  39. package/lib/theme/ApiExplorer/ParamOptions/ParamFormItems/ParamTextFormItem.d.ts +4 -1
  40. package/lib/theme/ApiExplorer/ParamOptions/ParamFormItems/ParamTextFormItem.js +8 -3
  41. package/lib/theme/ApiExplorer/ParamOptions/_ParamOptions.scss +0 -9
  42. package/lib/theme/ApiExplorer/ParamOptions/index.d.ts +10 -0
  43. package/lib/theme/ApiExplorer/ParamOptions/index.js +55 -5
  44. package/lib/theme/ApiExplorer/Request/_Request.scss +11 -0
  45. package/lib/theme/ApiExplorer/Request/index.js +19 -5
  46. package/lib/theme/ApiExplorer/Request/makeRequest.d.ts +3 -1
  47. package/lib/theme/ApiExplorer/Request/makeRequest.js +19 -3
  48. package/lib/theme/ApiExplorer/Response/_Response.scss +11 -0
  49. package/lib/theme/ApiExplorer/Response/index.js +98 -12
  50. package/lib/theme/ApiExplorer/Server/index.d.ts +4 -1
  51. package/lib/theme/ApiExplorer/Server/index.js +6 -3
  52. package/lib/theme/ApiExplorer/buildPostmanRequest.d.ts +4 -1
  53. package/lib/theme/ApiExplorer/buildPostmanRequest.js +46 -5
  54. package/lib/theme/ApiExplorer/index.js +1 -0
  55. package/lib/theme/ApiExplorer/persistenceMiddleware.d.ts +2 -0
  56. package/lib/theme/ApiItem/hooks.d.ts +1 -0
  57. package/lib/theme/ApiItem/index.js +2 -1
  58. package/lib/theme/ApiItem/store.d.ts +6 -0
  59. package/lib/theme/ApiItem/store.js +11 -7
  60. package/lib/theme/ApiTabs/index.js +10 -11
  61. package/lib/theme/DiscriminatorTabs/index.js +10 -11
  62. package/lib/theme/MimeTabs/index.js +10 -11
  63. package/lib/theme/OperationTabs/index.js +10 -11
  64. package/lib/theme/ParamsItem/index.js +27 -0
  65. package/lib/theme/RequestSchema/index.js +172 -109
  66. package/lib/theme/ResponseHeaders/index.js +0 -1
  67. package/lib/theme/Schema/index.d.ts +1 -1
  68. package/lib/theme/Schema/index.js +91 -23
  69. package/lib/theme/SchemaItem/index.js +6 -1
  70. package/lib/theme/SchemaTabs/index.d.ts +1 -1
  71. package/lib/theme/SchemaTabs/index.js +31 -12
  72. package/lib/theme/styles.scss +1 -0
  73. package/lib/theme/translationIds.d.ts +3 -0
  74. package/lib/theme/translationIds.js +3 -0
  75. package/package.json +9 -8
  76. package/src/index.ts +2 -0
  77. package/src/markdown/schema.ts +69 -13
  78. package/src/theme/ApiExplorer/Accept/index.tsx +2 -1
  79. package/src/theme/ApiExplorer/Authorization/index.tsx +27 -33
  80. package/src/theme/ApiExplorer/Body/FileArrayFormBodyItem/index.tsx +0 -5
  81. package/src/theme/ApiExplorer/Body/FormBodyItem/index.tsx +115 -37
  82. package/src/theme/ApiExplorer/Body/index.tsx +85 -17
  83. package/src/theme/ApiExplorer/CodeSnippets/index.tsx +9 -1
  84. package/src/theme/ApiExplorer/CodeTabs/index.tsx +19 -19
  85. package/src/theme/ApiExplorer/ContentType/index.tsx +7 -4
  86. package/src/theme/ApiExplorer/EncodingSelection/slice.ts +31 -0
  87. package/src/theme/ApiExplorer/EncodingSelection/useResolvedEncoding.ts +43 -0
  88. package/src/theme/ApiExplorer/FormItem/_FormItem.scss +0 -5
  89. package/src/theme/ApiExplorer/FormItem/index.tsx +2 -16
  90. package/src/theme/ApiExplorer/FormLabel/_FormLabel.scss +4 -0
  91. package/src/theme/ApiExplorer/FormLabel/index.tsx +43 -0
  92. package/src/theme/ApiExplorer/FormMultiSelect/index.tsx +40 -20
  93. package/src/theme/ApiExplorer/FormSelect/index.tsx +41 -15
  94. package/src/theme/ApiExplorer/FormTextInput/index.tsx +15 -1
  95. package/src/theme/ApiExplorer/MethodEndpoint/index.tsx +21 -0
  96. package/src/theme/ApiExplorer/ParamOptions/ParamFormItems/ParamArrayFormItem.tsx +13 -2
  97. package/src/theme/ApiExplorer/ParamOptions/ParamFormItems/ParamBooleanFormItem.tsx +12 -1
  98. package/src/theme/ApiExplorer/ParamOptions/ParamFormItems/ParamMultiSelectFormItem.tsx +14 -2
  99. package/src/theme/ApiExplorer/ParamOptions/ParamFormItems/ParamSelectFormItem.tsx +14 -2
  100. package/src/theme/ApiExplorer/ParamOptions/ParamFormItems/ParamTextFormItem.tsx +16 -3
  101. package/src/theme/ApiExplorer/ParamOptions/_ParamOptions.scss +0 -9
  102. package/src/theme/ApiExplorer/ParamOptions/index.tsx +97 -11
  103. package/src/theme/ApiExplorer/Request/_Request.scss +11 -0
  104. package/src/theme/ApiExplorer/Request/index.tsx +20 -8
  105. package/src/theme/ApiExplorer/Request/makeRequest.ts +19 -3
  106. package/src/theme/ApiExplorer/Response/_Response.scss +11 -0
  107. package/src/theme/ApiExplorer/Response/index.tsx +35 -14
  108. package/src/theme/ApiExplorer/Server/index.tsx +10 -3
  109. package/src/theme/ApiExplorer/buildPostmanRequest.ts +52 -5
  110. package/src/theme/ApiExplorer/index.tsx +1 -0
  111. package/src/theme/ApiItem/index.tsx +2 -1
  112. package/src/theme/ApiItem/store.ts +2 -0
  113. package/src/theme/ApiTabs/index.tsx +14 -19
  114. package/src/theme/DiscriminatorTabs/index.tsx +14 -19
  115. package/src/theme/MimeTabs/index.tsx +15 -19
  116. package/src/theme/OperationTabs/index.tsx +14 -19
  117. package/src/theme/ParamsItem/index.tsx +25 -0
  118. package/src/theme/RequestSchema/index.tsx +141 -83
  119. package/src/theme/ResponseHeaders/index.tsx +1 -2
  120. package/src/theme/Schema/index.tsx +112 -27
  121. package/src/theme/SchemaItem/index.tsx +6 -1
  122. package/src/theme/SchemaTabs/index.tsx +42 -21
  123. package/src/theme/styles.scss +1 -0
  124. package/src/theme/translationIds.ts +3 -0
  125. package/src/theme-classic.d.ts +25 -1
  126. package/src/types.d.ts +7 -0
  127. package/tsconfig.tsbuildinfo +1 -1
@@ -9,13 +9,13 @@ import React from "react";
9
9
 
10
10
  import { useDoc } from "@docusaurus/plugin-content-docs/client";
11
11
  import { usePrismTheme } from "@docusaurus/theme-common";
12
- import { translate } from "@docusaurus/Translate";
12
+ import Translate, { translate } from "@docusaurus/Translate";
13
13
  import useDocusaurusContext from "@docusaurus/useDocusaurusContext";
14
14
  import ApiCodeBlock from "@theme/ApiExplorer/ApiCodeBlock";
15
15
  import { useTypedDispatch, useTypedSelector } from "@theme/ApiItem/hooks";
16
16
  import SchemaTabs from "@theme/SchemaTabs";
17
17
  import TabItem from "@theme/TabItem";
18
- import { OPENAPI_RESPONSE } from "@theme/translationIds";
18
+ import { OPENAPI_REQUEST, OPENAPI_RESPONSE } from "@theme/translationIds";
19
19
  import clsx from "clsx";
20
20
  import type { ApiItem } from "docusaurus-plugin-openapi-docs/src/types";
21
21
  import type { ThemeConfig } from "docusaurus-theme-openapi-docs/src/types";
@@ -84,7 +84,8 @@ function Response({ item }: { item: ApiItem }) {
84
84
  <span className="openapi-explorer__response-title">
85
85
  {translate({ id: OPENAPI_RESPONSE.TITLE, message: "Response" })}
86
86
  </span>
87
- <span
87
+ <button
88
+ type="button"
88
89
  className="openapi-explorer__response-clear-btn"
89
90
  onClick={() => {
90
91
  dispatch(clearResponse());
@@ -93,7 +94,7 @@ function Response({ item }: { item: ApiItem }) {
93
94
  }}
94
95
  >
95
96
  {translate({ id: OPENAPI_RESPONSE.CLEAR, message: "Clear" })}
96
- </span>
97
+ </button>
97
98
  </div>
98
99
  <div
99
100
  style={{
@@ -126,11 +127,22 @@ function Response({ item }: { item: ApiItem }) {
126
127
  >
127
128
  {prettyResponse || (
128
129
  <p className="openapi-explorer__response-placeholder-message">
129
- {translate({
130
- id: OPENAPI_RESPONSE.PLACEHOLDER,
131
- message:
132
- "Click the <code>Send API Request</code> button above and see the response here!",
133
- })}
130
+ <Translate
131
+ id={OPENAPI_RESPONSE.PLACEHOLDER}
132
+ values={{
133
+ code: (
134
+ <code>
135
+ <Translate id={OPENAPI_REQUEST.SEND_BUTTON}>
136
+ Send API Request
137
+ </Translate>
138
+ </code>
139
+ ),
140
+ }}
141
+ >
142
+ {
143
+ "Click the {code} button above and see the response here!"
144
+ }
145
+ </Translate>
134
146
  </p>
135
147
  )}
136
148
  </ApiCodeBlock>
@@ -163,11 +175,20 @@ function Response({ item }: { item: ApiItem }) {
163
175
  </div>
164
176
  ) : (
165
177
  <p className="openapi-explorer__response-placeholder-message">
166
- {translate({
167
- id: OPENAPI_RESPONSE.PLACEHOLDER,
168
- message:
169
- "Click the <code>Send API Request</code> button above and see the response here!",
170
- })}
178
+ <Translate
179
+ id={OPENAPI_RESPONSE.PLACEHOLDER}
180
+ values={{
181
+ code: (
182
+ <code>
183
+ <Translate id={OPENAPI_REQUEST.SEND_BUTTON}>
184
+ Send API Request
185
+ </Translate>
186
+ </code>
187
+ ),
188
+ }}
189
+ >
190
+ {"Click the {code} button above and see the response here!"}
191
+ </Translate>
171
192
  </p>
172
193
  )}
173
194
  </div>
@@ -17,7 +17,11 @@ import { OPENAPI_SERVER } from "@theme/translationIds";
17
17
 
18
18
  import { setServer, setServerVariable } from "./slice";
19
19
 
20
- function Server() {
20
+ interface ServerProps {
21
+ labelId?: string;
22
+ }
23
+
24
+ function Server({ labelId }: ServerProps) {
21
25
  const [isEditing, setIsEditing] = useState(false);
22
26
  const value = useTypedSelector((state: any) => state.server.value);
23
27
  const options = useTypedSelector((state: any) => state.server.options);
@@ -79,6 +83,7 @@ function Server() {
79
83
  >
80
84
  <FormItem>
81
85
  <FormSelect
86
+ ariaLabelledBy={labelId}
82
87
  options={options.map((s: any) => s.url)}
83
88
  onChange={(e: React.ChangeEvent<HTMLSelectElement>) => {
84
89
  dispatch(
@@ -99,8 +104,9 @@ function Server() {
99
104
  Object.keys(value.variables).map((key) => {
100
105
  if (value.variables?.[key].enum !== undefined) {
101
106
  return (
102
- <FormItem label={key}>
107
+ <FormItem>
103
108
  <FormSelect
109
+ label={key}
104
110
  options={value.variables[key].enum}
105
111
  onChange={(e: React.ChangeEvent<HTMLSelectElement>) => {
106
112
  dispatch(
@@ -115,8 +121,9 @@ function Server() {
115
121
  );
116
122
  }
117
123
  return (
118
- <FormItem label={key}>
124
+ <FormItem>
119
125
  <FormTextInput
126
+ label={key}
120
127
  placeholder={value.variables?.[key].default}
121
128
  onChange={(e: React.ChangeEvent<HTMLInputElement>) => {
122
129
  dispatch(
@@ -293,12 +293,36 @@ function tryDecodeJsonParam(value: string): any {
293
293
  }
294
294
 
295
295
  // TODO: this is all a bit hacky
296
- function setBody(clonedPostman: sdk.Request, body: Body) {
296
+ function setBody(
297
+ clonedPostman: sdk.Request,
298
+ body: Body,
299
+ encoding?: Record<string, { contentType?: string }>
300
+ ) {
297
301
  if (clonedPostman.body === undefined) {
298
302
  return;
299
303
  }
300
304
 
301
305
  if (body.type === "empty") {
306
+ // When the original request has formdata and encoding is declared, keep the
307
+ // placeholder params so the code snippet reflects the selected encoding even
308
+ // before the user has uploaded a file.
309
+ if (
310
+ clonedPostman.body?.mode === "formdata" &&
311
+ encoding &&
312
+ Object.keys(encoding).length > 0
313
+ ) {
314
+ const members: any[] =
315
+ (clonedPostman.body.formdata as any)?.members ?? [];
316
+ members.forEach((param: any) => {
317
+ const partContentType = encoding[param.key]?.contentType
318
+ ?.split(",")[0]
319
+ .trim();
320
+ if (partContentType) {
321
+ param.contentType = partContentType;
322
+ }
323
+ });
324
+ return;
325
+ }
302
326
  clonedPostman.body = undefined;
303
327
  return;
304
328
  }
@@ -336,14 +360,35 @@ function setBody(clonedPostman: sdk.Request, body: Body) {
336
360
  Object.entries(body.content)
337
361
  .filter((entry): entry is [string, NonNullable<Content>] => !!entry[1])
338
362
  .forEach(([key, content]) => {
363
+ const partContentType = encoding?.[key]?.contentType
364
+ ?.split(",")[0]
365
+ .trim();
339
366
  if (content.type === "file") {
340
- params.push(new sdk.FormParam({ key: key, ...content }));
367
+ params.push(
368
+ new sdk.FormParam({
369
+ key: key,
370
+ ...content,
371
+ ...(partContentType && { contentType: partContentType }),
372
+ })
373
+ );
341
374
  } else if (content.type === "file[]") {
342
375
  content.value.forEach((file) =>
343
- params.push(new sdk.FormParam({ key, value: file }))
376
+ params.push(
377
+ new sdk.FormParam({
378
+ key,
379
+ value: file,
380
+ ...(partContentType && { contentType: partContentType }),
381
+ })
382
+ )
344
383
  );
345
384
  } else {
346
- params.push(new sdk.FormParam({ key: key, value: content.value }));
385
+ params.push(
386
+ new sdk.FormParam({
387
+ key: key,
388
+ value: content.value,
389
+ ...(partContentType && { contentType: partContentType }),
390
+ })
391
+ );
347
392
  }
348
393
  });
349
394
  params.forEach((param) => {
@@ -391,6 +436,7 @@ interface Options {
391
436
  accept: string;
392
437
  body: Body;
393
438
  auth: AuthState;
439
+ encoding?: Record<string, { contentType?: string }>;
394
440
  }
395
441
 
396
442
  function buildPostmanRequest(
@@ -405,6 +451,7 @@ function buildPostmanRequest(
405
451
  body,
406
452
  server,
407
453
  auth,
454
+ encoding,
408
455
  }: Options
409
456
  ) {
410
457
  const clonedPostman = cloneDeep(postman);
@@ -532,7 +579,7 @@ function buildPostmanRequest(
532
579
  otherHeaders
533
580
  );
534
581
 
535
- setBody(clonedPostman, body);
582
+ setBody(clonedPostman, body, encoding);
536
583
 
537
584
  return clonedPostman;
538
585
  }
@@ -41,6 +41,7 @@ function ApiExplorer({
41
41
  postman={postman}
42
42
  codeSamples={(item as any)["x-codeSamples"] ?? []}
43
43
  maskCredentials={mask_credentials}
44
+ requestBody={item.requestBody}
44
45
  />
45
46
  )}
46
47
  <Request item={item} />
@@ -122,7 +122,7 @@ export default function ApiItem(props: Props): JSX.Element {
122
122
  (param: { in: "path" | "query" | "header" | "cookie" }) => {
123
123
  const paramType = param.in;
124
124
  const paramsArray: ParameterObject[] = params[paramType];
125
- paramsArray.push(param as ParameterObject);
125
+ paramsArray?.push(param as ParameterObject);
126
126
  }
127
127
  );
128
128
  const auth = createAuth({
@@ -159,6 +159,7 @@ export default function ApiItem(props: Props): JSX.Element {
159
159
  params,
160
160
  auth,
161
161
  schemaSelection: { selections: {} },
162
+ encodingSelection: {},
162
163
  },
163
164
  [persistenceMiddleware]
164
165
  );
@@ -10,6 +10,7 @@ import accept from "@theme/ApiExplorer/Accept/slice";
10
10
  import auth from "@theme/ApiExplorer/Authorization/slice";
11
11
  import body from "@theme/ApiExplorer/Body/slice";
12
12
  import contentType from "@theme/ApiExplorer/ContentType/slice";
13
+ import encodingSelection from "@theme/ApiExplorer/EncodingSelection/slice";
13
14
  import params from "@theme/ApiExplorer/ParamOptions/slice";
14
15
  import response from "@theme/ApiExplorer/Response/slice";
15
16
  import schemaSelection from "@theme/ApiExplorer/SchemaSelection/slice";
@@ -18,6 +19,7 @@ import server from "@theme/ApiExplorer/Server/slice";
18
19
  const rootReducer = combineReducers({
19
20
  accept,
20
21
  contentType,
22
+ encodingSelection,
21
23
  response,
22
24
  server,
23
25
  body,
@@ -15,11 +15,12 @@ import React, {
15
15
 
16
16
  import {
17
17
  sanitizeTabsChildren,
18
+ type TabItemProps,
18
19
  TabProps,
20
+ TabsProvider,
19
21
  useScrollPositionBlocker,
20
- useTabs,
22
+ useTabsContextValue,
21
23
  } from "@docusaurus/theme-common/internal";
22
- import { TabItemProps } from "@docusaurus/theme-common/lib/utils/tabsUtils";
23
24
  import { translate } from "@docusaurus/Translate";
24
25
  import useIsBrowser from "@docusaurus/useIsBrowser";
25
26
  import Heading from "@theme/Heading";
@@ -42,7 +43,7 @@ function TabList({
42
43
  message: "Responses",
43
44
  }),
44
45
  id = "responses",
45
- }: TabListProps & ReturnType<typeof useTabs>) {
46
+ }: TabListProps & ReturnType<typeof useTabsContextValue>) {
46
47
  const tabRefs: (HTMLLIElement | null)[] = [];
47
48
  const { blockElementScrollPositionUntilNextRender } =
48
49
  useScrollPositionBlocker();
@@ -194,7 +195,8 @@ function TabContent({
194
195
  lazy,
195
196
  children,
196
197
  selectedValue,
197
- }: TabProps & ReturnType<typeof useTabs>): React.JSX.Element | null {
198
+ }: TabProps &
199
+ ReturnType<typeof useTabsContextValue>): React.JSX.Element | null {
198
200
  const childTabs = (Array.isArray(children) ? children : [children]).filter(
199
201
  Boolean
200
202
  ) as ReactElement<TabItemProps>[];
@@ -208,24 +210,17 @@ function TabContent({
208
210
  }
209
211
  return cloneElement(selectedTabItem, { className: "margin-top--md" });
210
212
  }
211
- return (
212
- <div className="margin-top--md">
213
- {childTabs.map((tabItem, i) =>
214
- cloneElement(tabItem, {
215
- key: i,
216
- hidden: tabItem.props.value !== selectedValue,
217
- })
218
- )}
219
- </div>
220
- );
213
+ return <div className="margin-top--md">{childTabs}</div>;
221
214
  }
222
215
  function TabsComponent(props: TabListProps): React.JSX.Element {
223
- const tabs = useTabs(props);
216
+ const tabs = useTabsContextValue(props);
224
217
  return (
225
- <div className="openapi-tabs__container">
226
- <TabList {...props} {...tabs} />
227
- <TabContent {...props} {...tabs} />
228
- </div>
218
+ <TabsProvider value={tabs}>
219
+ <div className="openapi-tabs__container">
220
+ <TabList {...props} {...tabs} />
221
+ <TabContent {...props} {...tabs} />
222
+ </div>
223
+ </TabsProvider>
229
224
  );
230
225
  }
231
226
  export default function ApiTabs(props: TabListProps): React.JSX.Element {
@@ -15,11 +15,12 @@ import React, {
15
15
 
16
16
  import {
17
17
  sanitizeTabsChildren,
18
+ type TabItemProps,
18
19
  TabProps,
20
+ TabsProvider,
19
21
  useScrollPositionBlocker,
20
- useTabs,
22
+ useTabsContextValue,
21
23
  } from "@docusaurus/theme-common/internal";
22
- import { TabItemProps } from "@docusaurus/theme-common/lib/utils/tabsUtils";
23
24
  import useIsBrowser from "@docusaurus/useIsBrowser";
24
25
  import clsx from "clsx";
25
26
  import flatten from "lodash/flatten";
@@ -30,7 +31,7 @@ function TabList({
30
31
  selectedValue,
31
32
  selectValue,
32
33
  tabValues,
33
- }: TabProps & ReturnType<typeof useTabs>) {
34
+ }: TabProps & ReturnType<typeof useTabsContextValue>) {
34
35
  const tabRefs: (HTMLLIElement | null)[] = [];
35
36
  const { blockElementScrollPositionUntilNextRender } =
36
37
  useScrollPositionBlocker();
@@ -172,7 +173,8 @@ function TabContent({
172
173
  lazy,
173
174
  children,
174
175
  selectedValue,
175
- }: TabProps & ReturnType<typeof useTabs>): React.JSX.Element | null {
176
+ }: TabProps &
177
+ ReturnType<typeof useTabsContextValue>): React.JSX.Element | null {
176
178
  const childTabs = (Array.isArray(children) ? children : [children]).filter(
177
179
  Boolean
178
180
  ) as ReactElement<TabItemProps>[];
@@ -187,24 +189,17 @@ function TabContent({
187
189
  }
188
190
  return cloneElement(selectedTabItem, { className: "margin-top--md" });
189
191
  }
190
- return (
191
- <div className="margin-top--md">
192
- {childTabs.map((tabItem, i) =>
193
- cloneElement(tabItem, {
194
- key: i,
195
- hidden: tabItem.props.value !== selectedValue,
196
- })
197
- )}
198
- </div>
199
- );
192
+ return <div className="margin-top--md">{childTabs}</div>;
200
193
  }
201
194
  function TabsComponent(props: TabProps): React.JSX.Element {
202
- const tabs = useTabs(props);
195
+ const tabs = useTabsContextValue(props);
203
196
  return (
204
- <div className="openapi-tabs__container">
205
- <TabList {...props} {...tabs} />
206
- <TabContent {...props} {...tabs} />
207
- </div>
197
+ <TabsProvider value={tabs}>
198
+ <div className="openapi-tabs__container">
199
+ <TabList {...props} {...tabs} />
200
+ <TabContent {...props} {...tabs} />
201
+ </div>
202
+ </TabsProvider>
208
203
  );
209
204
  }
210
205
  export default function DiscriminatorTabs(props: TabProps): React.JSX.Element {
@@ -15,11 +15,12 @@ import React, {
15
15
 
16
16
  import {
17
17
  sanitizeTabsChildren,
18
+ type TabItemProps,
18
19
  TabProps,
20
+ TabsProvider,
19
21
  useScrollPositionBlocker,
20
- useTabs,
22
+ useTabsContextValue,
21
23
  } from "@docusaurus/theme-common/internal";
22
- import { TabItemProps } from "@docusaurus/theme-common/lib/utils/tabsUtils";
23
24
  import useIsBrowser from "@docusaurus/useIsBrowser";
24
25
  import { setAccept } from "@theme/ApiExplorer/Accept/slice";
25
26
  import { setContentType } from "@theme/ApiExplorer/ContentType/slice";
@@ -38,7 +39,9 @@ function TabList({
38
39
  selectValue,
39
40
  tabValues,
40
41
  schemaType,
41
- }: Props & TabProps & ReturnType<typeof useTabs>): React.JSX.Element {
42
+ }: Props &
43
+ TabProps &
44
+ ReturnType<typeof useTabsContextValue>): React.JSX.Element {
42
45
  const tabRefs: (HTMLLIElement | null)[] = [];
43
46
  const { blockElementScrollPositionUntilNextRender } =
44
47
  useScrollPositionBlocker();
@@ -208,7 +211,7 @@ function TabContent({
208
211
  lazy,
209
212
  children,
210
213
  selectedValue,
211
- }: Props & TabProps & ReturnType<typeof useTabs>) {
214
+ }: Props & TabProps & ReturnType<typeof useTabsContextValue>) {
212
215
  const childTabs = (Array.isArray(children) ? children : [children]).filter(
213
216
  Boolean
214
217
  ) as ReactElement<TabItemProps>[];
@@ -222,24 +225,17 @@ function TabContent({
222
225
  }
223
226
  return cloneElement(selectedTabItem, { className: "margin-top--md" });
224
227
  }
225
- return (
226
- <div className="margin-top--md">
227
- {childTabs.map((tabItem, i) =>
228
- cloneElement(tabItem, {
229
- key: i,
230
- hidden: tabItem.props.value !== selectedValue,
231
- })
232
- )}
233
- </div>
234
- );
228
+ return <div className="margin-top--md">{childTabs}</div>;
235
229
  }
236
230
  function TabsComponent(props: Props & TabProps): React.JSX.Element {
237
- const tabs = useTabs(props);
231
+ const tabs = useTabsContextValue(props);
238
232
  return (
239
- <div className="tabs-container">
240
- <TabList {...props} {...tabs} />
241
- <TabContent {...props} {...tabs} />
242
- </div>
233
+ <TabsProvider value={tabs}>
234
+ <div className="tabs-container">
235
+ <TabList {...props} {...tabs} />
236
+ <TabContent {...props} {...tabs} />
237
+ </div>
238
+ </TabsProvider>
243
239
  );
244
240
  }
245
241
  export default function MimeTabs(props: Props & TabProps) {
@@ -15,11 +15,12 @@ import React, {
15
15
 
16
16
  import {
17
17
  sanitizeTabsChildren,
18
+ type TabItemProps,
18
19
  TabProps,
20
+ TabsProvider,
19
21
  useScrollPositionBlocker,
20
- useTabs,
22
+ useTabsContextValue,
21
23
  } from "@docusaurus/theme-common/internal";
22
- import { TabItemProps } from "@docusaurus/theme-common/lib/utils/tabsUtils";
23
24
  import useIsBrowser from "@docusaurus/useIsBrowser";
24
25
  import clsx from "clsx";
25
26
 
@@ -29,7 +30,7 @@ function TabList({
29
30
  selectedValue,
30
31
  selectValue,
31
32
  tabValues,
32
- }: TabProps & ReturnType<typeof useTabs>) {
33
+ }: TabProps & ReturnType<typeof useTabsContextValue>) {
33
34
  const tabRefs: (HTMLLIElement | null)[] = [];
34
35
  const { blockElementScrollPositionUntilNextRender } =
35
36
  useScrollPositionBlocker();
@@ -171,7 +172,8 @@ function TabContent({
171
172
  lazy,
172
173
  children,
173
174
  selectedValue,
174
- }: TabProps & ReturnType<typeof useTabs>): React.JSX.Element | null {
175
+ }: TabProps &
176
+ ReturnType<typeof useTabsContextValue>): React.JSX.Element | null {
175
177
  const childTabs = (Array.isArray(children) ? children : [children]).filter(
176
178
  Boolean
177
179
  ) as ReactElement<TabItemProps>[];
@@ -185,24 +187,17 @@ function TabContent({
185
187
  }
186
188
  return cloneElement(selectedTabItem, { className: "margin-top--md" });
187
189
  }
188
- return (
189
- <div className="margin-top--md">
190
- {childTabs.map((tabItem, i) =>
191
- cloneElement(tabItem, {
192
- key: i,
193
- hidden: tabItem.props.value !== selectedValue,
194
- })
195
- )}
196
- </div>
197
- );
190
+ return <div className="margin-top--md">{childTabs}</div>;
198
191
  }
199
192
  function TabsComponent(props: TabProps): React.JSX.Element {
200
- const tabs = useTabs(props);
193
+ const tabs = useTabsContextValue(props);
201
194
  return (
202
- <div className="tabs-container">
203
- <TabList {...props} {...tabs} />
204
- <TabContent {...props} {...tabs} />
205
- </div>
195
+ <TabsProvider value={tabs}>
196
+ <div className="tabs-container">
197
+ <TabList {...props} {...tabs} />
198
+ <TabContent {...props} {...tabs} />
199
+ </div>
200
+ </TabsProvider>
206
201
  );
207
202
  }
208
203
  export default function OperationTabs(props: TabProps): React.JSX.Element {
@@ -102,10 +102,34 @@ function ParamsItem({ param, ...rest }: Props) {
102
102
  </span>
103
103
  ));
104
104
 
105
+ const constValue = schema?.const;
106
+
105
107
  const renderQualifier = guard(getQualifierMessage(schema), (qualifier) => (
106
108
  <Markdown>{qualifier}</Markdown>
107
109
  ));
108
110
 
111
+ function renderConstValue() {
112
+ if (constValue === undefined) {
113
+ return undefined;
114
+ }
115
+ const label = translate({
116
+ id: OPENAPI_SCHEMA_ITEM.CONSTANT_VALUE,
117
+ message: "Constant value:",
118
+ });
119
+ return (
120
+ <div>
121
+ <strong>{label} </strong>
122
+ <span>
123
+ <code>
124
+ {typeof constValue === "string"
125
+ ? constValue
126
+ : JSON.stringify(constValue)}
127
+ </code>
128
+ </span>
129
+ </div>
130
+ );
131
+ }
132
+
109
133
  const renderDescription = guard(description, (description) => (
110
134
  <Markdown>{description}</Markdown>
111
135
  ));
@@ -173,6 +197,7 @@ function ParamsItem({ param, ...rest }: Props) {
173
197
  {renderDeprecated}
174
198
  </span>
175
199
  {renderQualifier}
200
+ {renderConstValue()}
176
201
  {renderDescription}
177
202
  {renderEnumDescriptions}
178
203
  {renderDefaultValue()}