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
@@ -0,0 +1,218 @@
1
+ /* ============================================================================
2
+ * Copyright (c) Palo Alto Networks
3
+ *
4
+ * This source code is licensed under the MIT license found in the
5
+ * LICENSE file in the root directory of this source tree.
6
+ * ========================================================================== */
7
+
8
+ import React, {
9
+ cloneElement,
10
+ useEffect,
11
+ useState,
12
+ useRef,
13
+ ReactElement,
14
+ } from "react";
15
+
16
+ import {
17
+ sanitizeTabsChildren,
18
+ TabProps,
19
+ useScrollPositionBlocker,
20
+ useTabs,
21
+ } from "@docusaurus/theme-common/internal";
22
+ import { TabItemProps } from "@docusaurus/theme-common/lib/utils/tabsUtils";
23
+ import useIsBrowser from "@docusaurus/useIsBrowser";
24
+ import clsx from "clsx";
25
+
26
+ function TabList({
27
+ className,
28
+ block,
29
+ selectedValue,
30
+ selectValue,
31
+ tabValues,
32
+ }: TabProps & ReturnType<typeof useTabs>) {
33
+ const tabRefs: (HTMLLIElement | null)[] = [];
34
+ const { blockElementScrollPositionUntilNextRender } =
35
+ useScrollPositionBlocker();
36
+
37
+ const handleTabChange = (
38
+ event:
39
+ | React.FocusEvent<HTMLLIElement>
40
+ | React.MouseEvent<HTMLLIElement>
41
+ | React.KeyboardEvent<HTMLLIElement>
42
+ ) => {
43
+ const newTab = event.currentTarget;
44
+ const newTabIndex = tabRefs.indexOf(newTab);
45
+ const newTabValue = tabValues[newTabIndex].value;
46
+
47
+ if (newTabValue !== selectedValue) {
48
+ blockElementScrollPositionUntilNextRender(newTab);
49
+ selectValue(newTabValue);
50
+ }
51
+ };
52
+
53
+ const handleKeydown = (event: React.KeyboardEvent<HTMLLIElement>) => {
54
+ let focusElement: HTMLLIElement | null = null;
55
+
56
+ switch (event.key) {
57
+ case "Enter": {
58
+ handleTabChange(event);
59
+ break;
60
+ }
61
+ case "ArrowRight": {
62
+ const nextTab = tabRefs.indexOf(event.currentTarget) + 1;
63
+ focusElement = tabRefs[nextTab] ?? tabRefs[0]!;
64
+ break;
65
+ }
66
+ case "ArrowLeft": {
67
+ const prevTab = tabRefs.indexOf(event.currentTarget) - 1;
68
+ focusElement = tabRefs[prevTab] ?? tabRefs[tabRefs.length - 1]!;
69
+ break;
70
+ }
71
+ default:
72
+ break;
73
+ }
74
+
75
+ focusElement?.focus();
76
+ };
77
+
78
+ const tabItemListContainerRef = useRef<HTMLUListElement>(null);
79
+ const [showTabArrows, setShowTabArrows] = useState<boolean>(false);
80
+
81
+ useEffect(() => {
82
+ const resizeObserver = new ResizeObserver((entries) => {
83
+ for (let entry of entries) {
84
+ requestAnimationFrame(() => {
85
+ if (entry.target.clientWidth < entry.target.scrollWidth) {
86
+ setShowTabArrows(true);
87
+ } else {
88
+ setShowTabArrows(false);
89
+ }
90
+ });
91
+ }
92
+ });
93
+
94
+ resizeObserver.observe(tabItemListContainerRef.current!);
95
+
96
+ return () => {
97
+ resizeObserver.disconnect();
98
+ };
99
+ }, []);
100
+
101
+ const handleRightClick = () => {
102
+ tabItemListContainerRef.current!.scrollLeft += 90;
103
+ };
104
+
105
+ const handleLeftClick = () => {
106
+ tabItemListContainerRef.current!.scrollLeft -= 90;
107
+ };
108
+
109
+ return (
110
+ <div className="tabs__container">
111
+ <div className="openapi-tabs__operation-container">
112
+ {showTabArrows && (
113
+ <button
114
+ className={clsx("openapi-tabs__arrow", "left")}
115
+ onClick={handleLeftClick}
116
+ />
117
+ )}
118
+ <ul
119
+ ref={tabItemListContainerRef}
120
+ role="tablist"
121
+ aria-orientation="horizontal"
122
+ className={clsx(
123
+ "openapi-tabs__operation-list-container",
124
+ "tabs",
125
+ {
126
+ "tabs--block": block,
127
+ },
128
+ className
129
+ )}
130
+ >
131
+ {tabValues.map(({ value, label, attributes }) => {
132
+ return (
133
+ <li
134
+ // TODO extract TabListItem
135
+ role="tab"
136
+ tabIndex={selectedValue === value ? 0 : -1}
137
+ aria-selected={selectedValue === value}
138
+ key={value}
139
+ ref={(tabControl) => tabRefs.push(tabControl)}
140
+ onKeyDown={handleKeydown}
141
+ onFocus={handleTabChange}
142
+ onClick={(e) => handleTabChange(e)}
143
+ {...attributes}
144
+ className={clsx(
145
+ "tabs__item",
146
+ "openapi-tabs__operation-item",
147
+ attributes?.className as string,
148
+ {
149
+ active: selectedValue === value,
150
+ }
151
+ )}
152
+ >
153
+ {label ?? value}
154
+ </li>
155
+ );
156
+ })}
157
+ </ul>
158
+ {showTabArrows && (
159
+ <button
160
+ className={clsx("openapi-tabs__arrow", "right")}
161
+ onClick={handleRightClick}
162
+ />
163
+ )}
164
+ </div>
165
+ </div>
166
+ );
167
+ }
168
+ function TabContent({
169
+ lazy,
170
+ children,
171
+ selectedValue,
172
+ }: TabProps & ReturnType<typeof useTabs>): React.JSX.Element | null {
173
+ const childTabs = (Array.isArray(children) ? children : [children]).filter(
174
+ Boolean
175
+ ) as ReactElement<TabItemProps>[];
176
+ if (lazy) {
177
+ const selectedTabItem = childTabs.find(
178
+ (tabItem) => tabItem.props.value === selectedValue
179
+ );
180
+ if (!selectedTabItem) {
181
+ // fail-safe or fail-fast? not sure what's best here
182
+ return null;
183
+ }
184
+ return cloneElement(selectedTabItem, { className: "margin-top--md" });
185
+ }
186
+ return (
187
+ <div className="margin-top--md">
188
+ {childTabs.map((tabItem, i) =>
189
+ cloneElement(tabItem, {
190
+ key: i,
191
+ hidden: tabItem.props.value !== selectedValue,
192
+ })
193
+ )}
194
+ </div>
195
+ );
196
+ }
197
+ function TabsComponent(props: TabProps): React.JSX.Element {
198
+ const tabs = useTabs(props);
199
+ return (
200
+ <div className="tabs-container">
201
+ <TabList {...props} {...tabs} />
202
+ <TabContent {...props} {...tabs} />
203
+ </div>
204
+ );
205
+ }
206
+ export default function OperationTabs(props: TabProps): React.JSX.Element {
207
+ const isBrowser = useIsBrowser();
208
+ return (
209
+ <TabsComponent
210
+ // Remount tabs after hydration
211
+ // Temporary fix for https://github.com/facebook/docusaurus/issues/5653
212
+ key={String(isBrowser)}
213
+ {...props}
214
+ >
215
+ {sanitizeTabsChildren(props.children)}
216
+ </TabsComponent>
217
+ );
218
+ }
@@ -11,23 +11,40 @@ import CodeBlock from "@theme/CodeBlock";
11
11
  import SchemaTabs from "@theme/SchemaTabs";
12
12
  import TabItem from "@theme/TabItem";
13
13
  /* eslint-disable import/no-extraneous-dependencies*/
14
- import { createDescription } from "docusaurus-theme-openapi-docs/lib/markdown/createDescription";
15
- /* eslint-disable import/no-extraneous-dependencies*/
16
- import {
17
- getQualifierMessage,
18
- getSchemaName,
19
- } from "docusaurus-theme-openapi-docs/lib/markdown/schema";
20
- /* eslint-disable import/no-extraneous-dependencies*/
21
- import {
22
- guard,
23
- toString,
24
- } from "docusaurus-theme-openapi-docs/lib/markdown/utils";
14
+ import clsx from "clsx";
25
15
  import ReactMarkdown from "react-markdown";
26
16
  import rehypeRaw from "rehype-raw";
27
17
 
18
+ import { createDescription } from "../../markdown/createDescription";
19
+ import { getQualifierMessage, getSchemaName } from "../../markdown/schema";
20
+ import { guard, toString } from "../../markdown/utils";
21
+
22
+ interface Map<T> {
23
+ [key: string]: T;
24
+ }
25
+
26
+ export interface ExampleObject {
27
+ summary?: string;
28
+ description?: string;
29
+ value?: any;
30
+ externalValue?: string;
31
+ }
32
+
33
+ export interface Props {
34
+ param: {
35
+ description: string;
36
+ example: any;
37
+ examples: Map<ExampleObject>;
38
+ name: string;
39
+ required: boolean;
40
+ deprecated: boolean;
41
+ schema: any;
42
+ };
43
+ }
44
+
28
45
  function ParamsItem({
29
- param: { description, example, examples, name, required, schema },
30
- }) {
46
+ param: { description, example, examples, name, required, schema, deprecated },
47
+ }: Props) {
31
48
  if (!schema || !schema?.type) {
32
49
  schema = { type: "any" };
33
50
  }
@@ -40,6 +57,10 @@ function ParamsItem({
40
57
  <span className="openapi-schema__required">required</span>
41
58
  ));
42
59
 
60
+ const renderDeprecated = guard(deprecated, () => (
61
+ <span className="openapi-schema__deprecated">deprecated</span>
62
+ ));
63
+
43
64
  const renderSchema = guard(getQualifierMessage(schema), (message) => (
44
65
  <div>
45
66
  <ReactMarkdown
@@ -74,8 +95,8 @@ function ParamsItem({
74
95
  schema && schema.items
75
96
  ? schema.items.default
76
97
  : schema
77
- ? schema.default
78
- : undefined,
98
+ ? schema.default
99
+ : undefined,
79
100
  (value) => (
80
101
  <div>
81
102
  <ReactMarkdown children={`**Default value:** \`${value}\``} />
@@ -97,6 +118,7 @@ function ParamsItem({
97
118
  <strong>Examples:</strong>
98
119
  <SchemaTabs>
99
120
  {exampleEntries.map(([exampleName, exampleProperties]) => (
121
+ // @ts-ignore
100
122
  <TabItem value={exampleName} label={exampleName}>
101
123
  {exampleProperties.summary && <p>{exampleProperties.summary}</p>}
102
124
  {exampleProperties.description && (
@@ -119,10 +141,19 @@ function ParamsItem({
119
141
  return (
120
142
  <div className="openapi-params__list-item">
121
143
  <span className="openapi-schema__container">
122
- <strong className="openapi-schema__property">{name}</strong>
144
+ <strong
145
+ className={clsx("openapi-schema__property", {
146
+ "openapi-schema__strikethrough": deprecated,
147
+ })}
148
+ >
149
+ {name}
150
+ </strong>
123
151
  {renderSchemaName}
124
- {required && <span className="openapi-schema__divider"></span>}
152
+ {(required || deprecated) && (
153
+ <span className="openapi-schema__divider"></span>
154
+ )}
125
155
  {renderSchemaRequired}
156
+ {renderDeprecated}
126
157
  </span>
127
158
  {renderSchema}
128
159
  {renderDefaultValue}
@@ -8,8 +8,17 @@
8
8
  import React from "react";
9
9
 
10
10
  import CodeBlock from "@theme/CodeBlock";
11
+ import { Language } from "prism-react-renderer";
11
12
 
12
- function ResponseSamples({ responseExample, language }) {
13
+ export interface Props {
14
+ readonly responseExample: string;
15
+ readonly language: Language;
16
+ }
17
+
18
+ function ResponseSamples({
19
+ responseExample,
20
+ language,
21
+ }: Props): React.JSX.Element {
13
22
  return (
14
23
  <div className="openapi-code__response-samples-container">
15
24
  <CodeBlock language={language ? language : "json"}>
@@ -5,18 +5,29 @@
5
5
  * LICENSE file in the root directory of this source tree.
6
6
  * ========================================================================== */
7
7
 
8
- import React from "react";
8
+ import React, { ReactNode } from "react";
9
9
 
10
10
  import CodeBlock from "@theme/CodeBlock";
11
- /* eslint-disable import/no-extraneous-dependencies*/
12
11
  import clsx from "clsx";
13
- import { createDescription } from "docusaurus-theme-openapi-docs/lib/markdown/createDescription";
14
- /* eslint-disable import/no-extraneous-dependencies*/
15
- import { guard } from "docusaurus-theme-openapi-docs/lib/markdown/utils";
16
12
  import ReactMarkdown from "react-markdown";
17
13
  import rehypeRaw from "rehype-raw";
18
14
 
19
- function SchemaItem({
15
+ import { createDescription } from "../../markdown/createDescription";
16
+ import { guard } from "../../markdown/utils";
17
+
18
+ export interface Props {
19
+ children: ReactNode;
20
+ collapsible: boolean;
21
+ name: string;
22
+ qualifierMessage: string | undefined;
23
+ required: boolean;
24
+ schemaName: string;
25
+ // TODO should probably be typed
26
+ schema: any;
27
+ discriminator: boolean;
28
+ }
29
+
30
+ export default function SchemaItem({
20
31
  children: collapsibleSchemaContent,
21
32
  collapsible,
22
33
  name,
@@ -24,7 +35,7 @@ function SchemaItem({
24
35
  required,
25
36
  schemaName,
26
37
  schema,
27
- }) {
38
+ }: Props) {
28
39
  let deprecated;
29
40
  let schemaDescription;
30
41
  let defaultValue;
@@ -79,14 +90,11 @@ function SchemaItem({
79
90
  </div>
80
91
  ));
81
92
 
82
- const renderDefaultValue = guard(
83
- typeof defaultValue === "boolean" ? defaultValue.toString() : defaultValue,
84
- (value) => (
85
- <div className="">
86
- <ReactMarkdown children={`**Default value:** \`${value}\``} />
87
- </div>
88
- )
89
- );
93
+ const renderDefaultValue = guard(defaultValue, (value) => (
94
+ <div className="">
95
+ <ReactMarkdown children={`**Default value:** \`${value}\``} />
96
+ </div>
97
+ ));
90
98
 
91
99
  const schemaContent = (
92
100
  <div>
@@ -103,7 +111,7 @@ function SchemaItem({
103
111
  <span className="openapi-schema__divider"></span>
104
112
  )}
105
113
  {renderNullable}
106
- {!deprecated && renderRequired}
114
+ {renderRequired}
107
115
  {renderDeprecated}
108
116
  </span>
109
117
  {renderQualifierMessage}
@@ -119,5 +127,3 @@ function SchemaItem({
119
127
  </div>
120
128
  );
121
129
  }
122
-
123
- export default SchemaItem;
@@ -5,10 +5,6 @@
5
5
  * LICENSE file in the root directory of this source tree.
6
6
  */
7
7
 
8
- .openapi-tabs__schema-container {
9
- margin-top: 1rem;
10
- }
11
-
12
8
  .openapi-tabs__schema-item {
13
9
  display: flex;
14
10
  align-items: center;
@@ -5,31 +5,55 @@
5
5
  * LICENSE file in the root directory of this source tree.
6
6
  * ========================================================================== */
7
7
 
8
- import React, { cloneElement, useRef, useEffect, useState } from "react";
8
+ import React, {
9
+ cloneElement,
10
+ useRef,
11
+ useEffect,
12
+ useState,
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 clsx from "clsx";
16
25
  import flatten from "lodash/flatten";
17
26
 
18
- function TabList({ className, block, selectedValue, selectValue, tabValues }) {
19
- const tabRefs = [];
27
+ function TabList({
28
+ className,
29
+ block,
30
+ selectedValue,
31
+ selectValue,
32
+ tabValues,
33
+ }: TabProps & ReturnType<typeof useTabs>) {
34
+ const tabRefs: (HTMLLIElement | null)[] = [];
20
35
  const { blockElementScrollPositionUntilNextRender } =
21
36
  useScrollPositionBlocker();
22
- const handleTabChange = (event) => {
37
+
38
+ const handleTabChange = (
39
+ event:
40
+ | React.FocusEvent<HTMLLIElement>
41
+ | React.MouseEvent<HTMLLIElement>
42
+ | React.KeyboardEvent<HTMLLIElement>
43
+ ) => {
23
44
  const newTab = event.currentTarget;
24
45
  const newTabIndex = tabRefs.indexOf(newTab);
25
46
  const newTabValue = tabValues[newTabIndex].value;
47
+
26
48
  if (newTabValue !== selectedValue) {
27
49
  blockElementScrollPositionUntilNextRender(newTab);
28
50
  selectValue(newTabValue);
29
51
  }
30
52
  };
31
- const handleKeydown = (event) => {
32
- let focusElement = null;
53
+
54
+ const handleKeydown = (event: React.KeyboardEvent<HTMLLIElement>) => {
55
+ let focusElement: HTMLLIElement | null = null;
56
+
33
57
  switch (event.key) {
34
58
  case "Enter": {
35
59
  handleTabChange(event);
@@ -37,35 +61,38 @@ function TabList({ className, block, selectedValue, selectValue, tabValues }) {
37
61
  }
38
62
  case "ArrowRight": {
39
63
  const nextTab = tabRefs.indexOf(event.currentTarget) + 1;
40
- focusElement = tabRefs[nextTab] ?? tabRefs[0];
64
+ focusElement = tabRefs[nextTab] ?? tabRefs[0]!;
41
65
  break;
42
66
  }
43
67
  case "ArrowLeft": {
44
68
  const prevTab = tabRefs.indexOf(event.currentTarget) - 1;
45
- focusElement = tabRefs[prevTab] ?? tabRefs[tabRefs.length - 1];
69
+ focusElement = tabRefs[prevTab] ?? tabRefs[tabRefs.length - 1]!;
46
70
  break;
47
71
  }
48
72
  default:
49
73
  break;
50
74
  }
75
+
51
76
  focusElement?.focus();
52
77
  };
53
78
 
54
- const tabItemListContainerRef = useRef(null);
55
- const [showTabArrows, setShowTabArrows] = useState(false);
79
+ const tabItemListContainerRef = useRef<HTMLUListElement>(null);
80
+ const [showTabArrows, setShowTabArrows] = useState<boolean>(false);
56
81
 
57
82
  useEffect(() => {
58
83
  const resizeObserver = new ResizeObserver((entries) => {
59
84
  for (let entry of entries) {
60
- if (entry.target.offsetWidth < entry.target.scrollWidth) {
61
- setShowTabArrows(true);
62
- } else {
63
- setShowTabArrows(false);
64
- }
85
+ requestAnimationFrame(() => {
86
+ if (entry.target.clientWidth < entry.target.scrollWidth) {
87
+ setShowTabArrows(true);
88
+ } else {
89
+ setShowTabArrows(false);
90
+ }
91
+ });
65
92
  }
66
93
  });
67
94
 
68
- resizeObserver.observe(tabItemListContainerRef.current);
95
+ resizeObserver.observe(tabItemListContainerRef.current!);
69
96
 
70
97
  return () => {
71
98
  resizeObserver.disconnect();
@@ -73,11 +100,11 @@ function TabList({ className, block, selectedValue, selectValue, tabValues }) {
73
100
  }, []);
74
101
 
75
102
  const handleRightClick = () => {
76
- tabItemListContainerRef.current.scrollLeft += 90;
103
+ tabItemListContainerRef.current!.scrollLeft += 90;
77
104
  };
78
105
 
79
106
  const handleLeftClick = () => {
80
- tabItemListContainerRef.current.scrollLeft -= 90;
107
+ tabItemListContainerRef.current!.scrollLeft -= 90;
81
108
  };
82
109
 
83
110
  return (
@@ -115,7 +142,7 @@ function TabList({ className, block, selectedValue, selectValue, tabValues }) {
115
142
  className={clsx(
116
143
  "tabs__item",
117
144
  "openapi-tabs__schema-item",
118
- attributes?.className,
145
+ attributes?.className as string,
119
146
  {
120
147
  active: selectedValue === value,
121
148
  }
@@ -134,13 +161,17 @@ function TabList({ className, block, selectedValue, selectValue, tabValues }) {
134
161
  </div>
135
162
  );
136
163
  }
137
- function TabContent({ lazy, children, selectedValue }) {
138
- // eslint-disable-next-line no-param-reassign
139
- children = Array.isArray(children) ? children : [children];
140
- const flattenedChildren = flatten(children);
141
-
164
+ function TabContent({
165
+ lazy,
166
+ children,
167
+ selectedValue,
168
+ }: TabProps & ReturnType<typeof useTabs>) {
169
+ const childTabs = (Array.isArray(children) ? children : [children]).filter(
170
+ Boolean
171
+ ) as ReactElement<TabItemProps>[];
172
+ const flattenedChildTabs = flatten(childTabs);
142
173
  if (lazy) {
143
- const selectedTabItem = flattenedChildren.find(
174
+ const selectedTabItem = flattenedChildTabs.find(
144
175
  (tabItem) => tabItem.props.value === selectedValue
145
176
  );
146
177
  if (!selectedTabItem) {
@@ -151,7 +182,7 @@ function TabContent({ lazy, children, selectedValue }) {
151
182
  }
152
183
  return (
153
184
  <div className="margin-top--md">
154
- {children.map((tabItem, i) =>
185
+ {childTabs.map((tabItem, i) =>
155
186
  cloneElement(tabItem, {
156
187
  key: i,
157
188
  hidden: tabItem.props.value !== selectedValue,
@@ -160,7 +191,7 @@ function TabContent({ lazy, children, selectedValue }) {
160
191
  </div>
161
192
  );
162
193
  }
163
- function TabsComponent(props) {
194
+ function TabsComponent(props: TabProps): React.JSX.Element {
164
195
  const tabs = useTabs(props);
165
196
  return (
166
197
  <div className="openapi-tabs__schema-container">
@@ -169,7 +200,7 @@ function TabsComponent(props) {
169
200
  </div>
170
201
  );
171
202
  }
172
- export default function SchemaTabs(props) {
203
+ export default function SchemaTabs(props: TabProps): React.JSX.Element {
173
204
  const isBrowser = useIsBrowser();
174
205
  return (
175
206
  <TabsComponent
@@ -177,6 +208,8 @@ export default function SchemaTabs(props) {
177
208
  // Temporary fix for https://github.com/facebook/docusaurus/issues/5653
178
209
  key={String(isBrowser)}
179
210
  {...props}
180
- />
211
+ >
212
+ {sanitizeTabsChildren(props.children)}
213
+ </TabsComponent>
181
214
  );
182
215
  }
@@ -36,6 +36,7 @@
36
36
  @use "./DiscriminatorTabs/DiscriminatorTabs";
37
37
  @use "./MimeTabs/MimeTabs";
38
38
  @use "./SchemaTabs/SchemaTabs";
39
+ @use "./OperationTabs/OperationTabs";
39
40
  /* Code Samples */
40
41
  @use "./ResponseSamples/ResponseSamples";
41
42
  /* Markdown Styling */
@@ -158,3 +159,7 @@
158
159
  .openapi-left-panel__container {
159
160
  border-right: thin solid var(--ifm-toc-border-color);
160
161
  }
162
+
163
+ .openapi-tabs__heading {
164
+ margin-bottom: 1rem;
165
+ }