docusaurus-theme-openapi-docs 1.0.4 → 1.1.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 (103) hide show
  1. package/lib/theme/ApiDemoPanel/Body/index.js +11 -9
  2. package/lib/theme/ApiDemoPanel/Body/json2xml.js +43 -0
  3. package/lib/theme/ApiDemoPanel/CodeTabs/index.js +193 -0
  4. package/lib/theme/ApiDemoPanel/CodeTabs/styles.module.css +11 -0
  5. package/lib/theme/ApiDemoPanel/Curl/index.js +41 -110
  6. package/lib/theme/ApiDemoPanel/FloatingButton/index.js +4 -2
  7. package/lib/theme/ApiDemoPanel/FloatingButton/styles.module.css +3 -2
  8. package/lib/theme/ApiDemoPanel/LiveEditor/index.js +74 -0
  9. package/lib/theme/ApiDemoPanel/LiveEditor/styles.module.css +35 -0
  10. package/lib/theme/ApiDemoPanel/ParamOptions/styles.module.css +0 -4
  11. package/lib/theme/ApiDemoPanel/Server/index.js +1 -1
  12. package/lib/theme/ApiDemoPanel/Server/styles.module.css +0 -4
  13. package/lib/theme/ApiItem/Content/index.js +65 -0
  14. package/lib/theme/ApiItem/Footer/index.js +78 -0
  15. package/lib/theme/ApiItem/Footer/styles.module.css +18 -0
  16. package/lib/theme/ApiItem/Layout/icons/bash-original.svg +1 -0
  17. package/lib/theme/ApiItem/Layout/icons/go-original-wordmark.svg +1 -0
  18. package/lib/theme/ApiItem/Layout/icons/javascript-original.svg +1 -0
  19. package/lib/theme/ApiItem/Layout/icons/linux-original.svg +1 -0
  20. package/lib/theme/ApiItem/Layout/icons/python-original.svg +1 -0
  21. package/lib/theme/ApiItem/Layout/index.js +93 -0
  22. package/lib/theme/ApiItem/{styles.module.css → Layout/styles.module.css} +114 -4
  23. package/lib/theme/ApiItem/Metadata/index.js +32 -0
  24. package/lib/theme/ApiItem/Paginator/index.js +33 -0
  25. package/lib/theme/ApiItem/TOC/Desktop/index.js +31 -0
  26. package/lib/theme/ApiItem/TOC/Mobile/index.js +35 -0
  27. package/lib/theme/ApiItem/TOC/Mobile/styles.module.css +19 -0
  28. package/lib/theme/ApiItem/index.js +37 -126
  29. package/lib/theme/ApiTabs/index.js +17 -6
  30. package/lib/theme/ApiTabs/styles.module.css +0 -1
  31. package/lib/theme/SchemaTabs/index.js +258 -0
  32. package/lib/theme/SchemaTabs/styles.module.css +110 -0
  33. package/lib-next/theme/ApiDemoPanel/Body/index.js +11 -15
  34. package/lib-next/theme/ApiDemoPanel/Body/json2xml.js +43 -0
  35. package/lib-next/theme/ApiDemoPanel/CodeTabs/index.js +215 -0
  36. package/lib-next/theme/ApiDemoPanel/CodeTabs/styles.module.css +11 -0
  37. package/lib-next/theme/ApiDemoPanel/Curl/index.js +46 -135
  38. package/lib-next/theme/ApiDemoPanel/FloatingButton/index.js +6 -2
  39. package/lib-next/theme/ApiDemoPanel/FloatingButton/styles.module.css +3 -2
  40. package/lib-next/theme/ApiDemoPanel/LiveEditor/index.js +60 -0
  41. package/lib-next/theme/ApiDemoPanel/LiveEditor/styles.module.css +35 -0
  42. package/lib-next/theme/ApiDemoPanel/ParamOptions/styles.module.css +0 -4
  43. package/lib-next/theme/ApiDemoPanel/Server/index.js +1 -0
  44. package/lib-next/theme/ApiDemoPanel/Server/styles.module.css +0 -4
  45. package/lib-next/theme/ApiItem/Content/index.js +55 -0
  46. package/lib-next/theme/ApiItem/Footer/index.js +88 -0
  47. package/lib-next/theme/ApiItem/Footer/styles.module.css +18 -0
  48. package/lib-next/theme/ApiItem/Layout/icons/bash-original.svg +1 -0
  49. package/lib-next/theme/ApiItem/Layout/icons/go-original-wordmark.svg +1 -0
  50. package/lib-next/theme/ApiItem/Layout/icons/javascript-original.svg +1 -0
  51. package/lib-next/theme/ApiItem/Layout/icons/linux-original.svg +1 -0
  52. package/lib-next/theme/ApiItem/Layout/icons/python-original.svg +1 -0
  53. package/lib-next/theme/ApiItem/Layout/index.js +69 -0
  54. package/{src/theme/ApiItem → lib-next/theme/ApiItem/Layout}/styles.module.css +114 -4
  55. package/lib-next/theme/ApiItem/Metadata/index.js +21 -0
  56. package/lib-next/theme/ApiItem/Paginator/index.js +19 -0
  57. package/lib-next/theme/ApiItem/TOC/Desktop/index.js +22 -0
  58. package/lib-next/theme/ApiItem/TOC/Mobile/index.js +24 -0
  59. package/lib-next/theme/ApiItem/TOC/Mobile/styles.module.css +19 -0
  60. package/lib-next/theme/ApiItem/index.js +31 -133
  61. package/lib-next/theme/ApiTabs/index.js +17 -6
  62. package/lib-next/theme/ApiTabs/styles.module.css +0 -1
  63. package/lib-next/theme/SchemaTabs/index.js +258 -0
  64. package/lib-next/theme/SchemaTabs/styles.module.css +110 -0
  65. package/package.json +7 -9
  66. package/src/theme/ApiDemoPanel/Body/index.tsx +9 -13
  67. package/src/theme/ApiDemoPanel/Body/json2xml.js +43 -0
  68. package/src/theme/ApiDemoPanel/CodeTabs/index.tsx +238 -0
  69. package/src/theme/ApiDemoPanel/CodeTabs/styles.module.css +11 -0
  70. package/src/theme/ApiDemoPanel/Curl/index.tsx +45 -124
  71. package/src/theme/ApiDemoPanel/FloatingButton/index.tsx +6 -2
  72. package/src/theme/ApiDemoPanel/FloatingButton/styles.module.css +3 -2
  73. package/src/theme/ApiDemoPanel/LiveEditor/index.tsx +71 -0
  74. package/src/theme/ApiDemoPanel/LiveEditor/styles.module.css +35 -0
  75. package/src/theme/ApiDemoPanel/ParamOptions/styles.module.css +0 -4
  76. package/src/theme/ApiDemoPanel/Server/index.tsx +1 -0
  77. package/src/theme/ApiDemoPanel/Server/styles.module.css +0 -4
  78. package/src/theme/ApiItem/Content/index.tsx +57 -0
  79. package/src/theme/ApiItem/Footer/index.tsx +101 -0
  80. package/src/theme/ApiItem/Footer/styles.module.css +18 -0
  81. package/src/theme/ApiItem/Layout/icons/bash-original.svg +1 -0
  82. package/src/theme/ApiItem/Layout/icons/go-original-wordmark.svg +1 -0
  83. package/src/theme/ApiItem/Layout/icons/javascript-original.svg +1 -0
  84. package/src/theme/ApiItem/Layout/icons/linux-original.svg +1 -0
  85. package/src/theme/ApiItem/Layout/icons/python-original.svg +1 -0
  86. package/src/theme/ApiItem/Layout/index.tsx +78 -0
  87. package/{lib-next/theme/ApiItem → src/theme/ApiItem/Layout}/styles.module.css +114 -4
  88. package/src/theme/ApiItem/Metadata/index.tsx +24 -0
  89. package/src/theme/ApiItem/Paginator/index.tsx +21 -0
  90. package/src/theme/ApiItem/TOC/Desktop/index.tsx +25 -0
  91. package/src/theme/ApiItem/TOC/Mobile/index.tsx +28 -0
  92. package/src/theme/ApiItem/TOC/Mobile/styles.module.css +19 -0
  93. package/src/theme/ApiItem/index.tsx +31 -130
  94. package/src/theme/ApiTabs/index.js +17 -6
  95. package/src/theme/ApiTabs/styles.module.css +0 -1
  96. package/src/theme/SchemaTabs/index.js +258 -0
  97. package/src/theme/SchemaTabs/styles.module.css +110 -0
  98. package/lib/theme/ApiDemoPanel/VSCode/index.js +0 -252
  99. package/lib/theme/ApiDemoPanel/VSCode/styles.module.css +0 -19
  100. package/lib-next/theme/ApiDemoPanel/VSCode/index.js +0 -265
  101. package/lib-next/theme/ApiDemoPanel/VSCode/styles.module.css +0 -19
  102. package/src/theme/ApiDemoPanel/VSCode/index.tsx +0 -205
  103. package/src/theme/ApiDemoPanel/VSCode/styles.module.css +0 -19
@@ -0,0 +1,238 @@
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
+ useState,
10
+ cloneElement,
11
+ isValidElement,
12
+ type ReactElement,
13
+ } from "react";
14
+
15
+ import { duplicates } from "@docusaurus/theme-common";
16
+ import useIsBrowser from "@docusaurus/useIsBrowser";
17
+ import type { Props as TabItemProps } from "@theme/TabItem";
18
+ import clsx from "clsx";
19
+
20
+ import { languageSet } from "../Curl";
21
+ import styles from "./styles.module.css";
22
+
23
+ const {
24
+ useScrollPositionBlocker,
25
+ useTabGroupChoice,
26
+ } = require("@docusaurus/theme-common/internal");
27
+
28
+ // A very rough duck type, but good enough to guard against mistakes while
29
+ // allowing customization
30
+ function isTabItem(
31
+ comp: ReactElement<object>
32
+ ): comp is ReactElement<TabItemProps> {
33
+ return "value" in comp.props;
34
+ }
35
+
36
+ export interface Props {
37
+ readonly lazy?: boolean;
38
+ readonly block?: boolean;
39
+ readonly children: readonly ReactElement<TabItemProps>[];
40
+ readonly defaultValue?: string | null;
41
+ readonly values?: readonly {
42
+ value: string;
43
+ label?: string;
44
+ attributes?: { [key: string]: unknown };
45
+ }[];
46
+ readonly groupId?: string;
47
+ readonly className?: string;
48
+ readonly action?: any;
49
+ }
50
+
51
+ function TabsComponent(props: Props): JSX.Element {
52
+ const {
53
+ lazy,
54
+ block,
55
+ defaultValue: defaultValueProp,
56
+ values: valuesProp,
57
+ groupId,
58
+ className,
59
+ action,
60
+ } = props;
61
+ const children = React.Children.map(props.children, (child) => {
62
+ if (isValidElement(child) && isTabItem(child)) {
63
+ return child;
64
+ }
65
+ // child.type.name will give non-sensical values in prod because of
66
+ // minification, but we assume it won't throw in prod.
67
+ throw new Error(
68
+ `Docusaurus error: Bad <Tabs> child <${
69
+ // @ts-expect-error: guarding against unexpected cases
70
+ typeof child.type === "string" ? child.type : child.type.name
71
+ }>: all children of the <Tabs> component should be <TabItem>, and every <TabItem> should have a unique "value" prop.`
72
+ );
73
+ });
74
+ const values =
75
+ valuesProp ??
76
+ // Only pick keys that we recognize. MDX would inject some keys by default
77
+ children.map(({ props: { value, label, attributes } }) => ({
78
+ value,
79
+ label,
80
+ attributes,
81
+ }));
82
+ const dup = duplicates(values, (a, b) => a.value === b.value);
83
+ if (dup.length > 0) {
84
+ throw new Error(
85
+ `Docusaurus error: Duplicate values "${dup
86
+ .map((a) => a.value)
87
+ .join(", ")}" found in <Tabs>. Every value needs to be unique.`
88
+ );
89
+ }
90
+ // When defaultValueProp is null, don't show a default tab
91
+ const defaultValue =
92
+ defaultValueProp === null
93
+ ? defaultValueProp
94
+ : defaultValueProp ??
95
+ children.find((child) => child.props.default)?.props.value ??
96
+ children[0]!.props.value;
97
+ if (defaultValue !== null && !values.some((a) => a.value === defaultValue)) {
98
+ throw new Error(
99
+ `Docusaurus error: The <Tabs> has a defaultValue "${defaultValue}" but none of its children has the corresponding value. Available values are: ${values
100
+ .map((a) => a.value)
101
+ .join(
102
+ ", "
103
+ )}. If you intend to show no default tab, use defaultValue={null} instead.`
104
+ );
105
+ }
106
+
107
+ const { tabGroupChoices, setTabGroupChoices } = useTabGroupChoice();
108
+ const [selectedValue, setSelectedValue] = useState(defaultValue);
109
+ const tabRefs: (HTMLLIElement | null)[] = [];
110
+ const { blockElementScrollPositionUntilNextRender } =
111
+ useScrollPositionBlocker();
112
+
113
+ if (groupId != null) {
114
+ const relevantTabGroupChoice = tabGroupChoices[groupId];
115
+ if (
116
+ relevantTabGroupChoice != null &&
117
+ relevantTabGroupChoice !== selectedValue &&
118
+ values.some((value) => value.value === relevantTabGroupChoice)
119
+ ) {
120
+ setSelectedValue(relevantTabGroupChoice);
121
+ }
122
+ }
123
+
124
+ const handleTabChange = (
125
+ event: React.FocusEvent<HTMLLIElement> | React.MouseEvent<HTMLLIElement>
126
+ ) => {
127
+ const newTab = event.currentTarget;
128
+ const newTabIndex = tabRefs.indexOf(newTab);
129
+ const newTabValue = values[newTabIndex]!.value;
130
+
131
+ if (newTabValue !== selectedValue) {
132
+ blockElementScrollPositionUntilNextRender(newTab);
133
+ setSelectedValue(newTabValue);
134
+ if (action) {
135
+ const newLanguage = languageSet.filter(
136
+ (lang) => lang.language === newTabValue
137
+ );
138
+ action(newLanguage[0]);
139
+ }
140
+
141
+ if (groupId != null) {
142
+ setTabGroupChoices(groupId, String(newTabValue));
143
+ }
144
+ }
145
+ };
146
+
147
+ const handleKeydown = (event: React.KeyboardEvent<HTMLLIElement>) => {
148
+ let focusElement: HTMLLIElement | null = null;
149
+
150
+ switch (event.key) {
151
+ case "ArrowRight": {
152
+ const nextTab = tabRefs.indexOf(event.currentTarget) + 1;
153
+ focusElement = tabRefs[nextTab] ?? tabRefs[0]!;
154
+ break;
155
+ }
156
+ case "ArrowLeft": {
157
+ const prevTab = tabRefs.indexOf(event.currentTarget) - 1;
158
+ focusElement = tabRefs[prevTab] ?? tabRefs[tabRefs.length - 1]!;
159
+ break;
160
+ }
161
+ default:
162
+ break;
163
+ }
164
+
165
+ focusElement?.focus();
166
+ };
167
+
168
+ return (
169
+ <div className={clsx("tabs-container", styles.tabList)}>
170
+ <ul
171
+ role="tablist"
172
+ aria-orientation="horizontal"
173
+ className={clsx(
174
+ "tabs",
175
+ {
176
+ "tabs--block": block,
177
+ },
178
+ styles.code__tabs,
179
+ className
180
+ )}
181
+ >
182
+ {values.map(({ value, label, attributes }) => (
183
+ <li
184
+ role="tab"
185
+ tabIndex={selectedValue === value ? 0 : -1}
186
+ aria-selected={selectedValue === value}
187
+ key={value}
188
+ ref={(tabControl) => tabRefs.push(tabControl)}
189
+ onKeyDown={handleKeydown}
190
+ onFocus={handleTabChange}
191
+ onClick={handleTabChange}
192
+ {...attributes}
193
+ className={clsx(
194
+ "tabs__item",
195
+ styles.tabItem,
196
+ attributes?.className as string,
197
+ {
198
+ "tabs__item--active": selectedValue === value,
199
+ }
200
+ )}
201
+ >
202
+ {label ?? value}
203
+ </li>
204
+ ))}
205
+ </ul>
206
+
207
+ {lazy ? (
208
+ cloneElement(
209
+ children.filter(
210
+ (tabItem) => tabItem.props.value === selectedValue
211
+ )[0]!,
212
+ { className: "margin-top--md" }
213
+ )
214
+ ) : (
215
+ <div className="margin-top--md">
216
+ {children.map((tabItem, i) =>
217
+ cloneElement(tabItem, {
218
+ key: i,
219
+ hidden: tabItem.props.value !== selectedValue,
220
+ })
221
+ )}
222
+ </div>
223
+ )}
224
+ </div>
225
+ );
226
+ }
227
+
228
+ export default function CodeTabs(props: Props): JSX.Element {
229
+ const isBrowser = useIsBrowser();
230
+ return (
231
+ <TabsComponent
232
+ // Remount tabs after hydration
233
+ // Temporary fix for https://github.com/facebook/docusaurus/issues/5653
234
+ key={String(isBrowser)}
235
+ {...props}
236
+ />
237
+ );
238
+ }
@@ -0,0 +1,11 @@
1
+ .tabList {
2
+ margin-bottom: var(--ifm-leading);
3
+ }
4
+
5
+ .tabItem {
6
+ margin-top: 0 !important;
7
+ }
8
+
9
+ .code__tabs {
10
+ justify-content: space-around;
11
+ }
@@ -5,32 +5,35 @@
5
5
  * LICENSE file in the root directory of this source tree.
6
6
  * ========================================================================== */
7
7
 
8
- import React, { useRef, useState, useEffect } from "react";
8
+ import React, { useState, useEffect } from "react";
9
9
 
10
10
  import useDocusaurusContext from "@docusaurus/useDocusaurusContext";
11
11
  import codegen from "@paloaltonetworks/postman-code-generators";
12
12
  import sdk from "@paloaltonetworks/postman-collection";
13
+ import CodeBlock from "@theme/CodeBlock";
13
14
  import clsx from "clsx";
14
- import Highlight, { defaultProps } from "prism-react-renderer";
15
15
 
16
+ import CodeTabs from "../CodeTabs";
16
17
  import { useTypedSelector } from "../hooks";
17
18
  import buildPostmanRequest from "./../buildPostmanRequest";
18
- import FloatingButton from "./../FloatingButton";
19
19
  import styles from "./styles.module.css";
20
20
 
21
21
  interface Language {
22
22
  tabName: string;
23
23
  highlight: string;
24
24
  language: string;
25
+ codeLanguage?: string;
25
26
  variant: string;
26
27
  options: { [key: string]: boolean };
28
+ source?: string;
27
29
  }
28
30
 
29
- const languageSet: Language[] = [
31
+ export const languageSet: Language[] = [
30
32
  {
31
33
  tabName: "cURL",
32
34
  highlight: "bash",
33
35
  language: "curl",
36
+ codeLanguage: "bash",
34
37
  variant: "curl",
35
38
  options: {
36
39
  longFormat: false,
@@ -39,12 +42,12 @@ const languageSet: Language[] = [
39
42
  },
40
43
  },
41
44
  {
42
- tabName: "Node",
43
- highlight: "javascript",
44
- language: "nodejs",
45
- variant: "axios",
45
+ tabName: "Python",
46
+ highlight: "python",
47
+ language: "python",
48
+ codeLanguage: "python",
49
+ variant: "requests",
46
50
  options: {
47
- ES6_enabled: true,
48
51
  followRedirect: true,
49
52
  trimRequestBody: true,
50
53
  },
@@ -53,6 +56,7 @@ const languageSet: Language[] = [
53
56
  tabName: "Go",
54
57
  highlight: "go",
55
58
  language: "go",
59
+ codeLanguage: "go",
56
60
  variant: "native",
57
61
  options: {
58
62
  followRedirect: true,
@@ -60,79 +64,41 @@ const languageSet: Language[] = [
60
64
  },
61
65
  },
62
66
  {
63
- tabName: "Python",
64
- highlight: "python",
65
- language: "python",
66
- variant: "requests",
67
+ tabName: "Node",
68
+ highlight: "javascript",
69
+ language: "nodejs",
70
+ codeLanguage: "javascript",
71
+ variant: "axios",
67
72
  options: {
73
+ ES6_enabled: true,
68
74
  followRedirect: true,
69
75
  trimRequestBody: true,
70
76
  },
71
77
  },
72
78
  ];
73
79
 
74
- const languageTheme = {
75
- plain: {
76
- color: "var(--ifm-code-color)",
77
- },
78
- styles: [
79
- {
80
- types: ["inserted", "attr-name"],
81
- style: {
82
- color: "var(--openapi-code-green)",
83
- },
84
- },
85
- {
86
- types: ["string", "url"],
87
- style: {
88
- color: "var(--openapi-code-green)",
89
- },
90
- },
91
- {
92
- types: ["builtin", "char", "constant", "function"],
93
- style: {
94
- color: "var(--openapi-code-blue)",
95
- },
96
- },
97
- {
98
- types: ["punctuation", "operator"],
99
- style: {
100
- color: "var(--openapi-code-dim)",
101
- },
102
- },
103
- {
104
- types: ["class-name"],
105
- style: {
106
- color: "var(--openapi-code-orange)",
107
- },
108
- },
109
- {
110
- types: ["tag", "arrow", "keyword"],
111
- style: {
112
- color: "var(--openapi-code-purple)",
113
- },
114
- },
115
- {
116
- types: ["boolean"],
117
- style: {
118
- color: "var(--openapi-code-red)",
119
- },
120
- },
121
- ],
122
- };
123
-
124
80
  interface Props {
125
81
  postman: sdk.Request;
126
82
  codeSamples: any; // TODO: Type this...
127
83
  }
128
84
 
85
+ function CodeTab({ children, hidden, className, onClick }: any): JSX.Element {
86
+ return (
87
+ <div
88
+ role="tabpanel"
89
+ className={clsx(styles.tabItem, className)}
90
+ {...{ hidden }}
91
+ >
92
+ {children}
93
+ </div>
94
+ );
95
+ }
96
+
129
97
  function Curl({ postman, codeSamples }: Props) {
130
98
  // TODO: match theme for vscode.
131
99
 
132
100
  const { siteConfig } = useDocusaurusContext();
133
101
 
134
- const [copyText, setCopyText] = useState("Copy");
135
-
136
102
  const contentType = useTypedSelector((state) => state.contentType.value);
137
103
  const accept = useTypedSelector((state) => state.accept.value);
138
104
  const server = useTypedSelector((state) => state.server.value);
@@ -152,7 +118,12 @@ function Curl({ postman, codeSamples }: Props) {
152
118
  ...codeSamples,
153
119
  ];
154
120
 
155
- const [language, setLanguage] = useState(langs[0]);
121
+ const defaultLang: Language[] = languageSet.filter(
122
+ (lang) =>
123
+ lang.codeLanguage === localStorage.getItem("docusaurus.tab.code-samples")
124
+ );
125
+
126
+ const [language, setLanguage] = useState(defaultLang[0] ?? langs[0]);
156
127
 
157
128
  const [codeText, setCodeText] = useState("");
158
129
 
@@ -201,76 +172,26 @@ function Curl({ postman, codeSamples }: Props) {
201
172
  auth,
202
173
  ]);
203
174
 
204
- const ref = useRef<HTMLDivElement>(null);
205
-
206
- const handleCurlCopy = () => {
207
- setCopyText("Copied");
208
- setTimeout(() => {
209
- setCopyText("Copy");
210
- }, 2000);
211
- if (ref.current?.innerText) {
212
- navigator.clipboard.writeText(ref.current.innerText);
213
- }
214
- };
215
-
216
175
  if (language === undefined) {
217
176
  return null;
218
177
  }
219
178
 
220
179
  return (
221
180
  <>
222
- <div className={clsx(styles.buttonGroup, "api-code-tab-group")}>
181
+ <CodeTabs groupId="code-samples" action={setLanguage}>
223
182
  {langs.map((lang) => {
224
183
  return (
225
- <button
184
+ <CodeTab
185
+ value={lang.language}
186
+ label={""}
226
187
  key={lang.tabName || lang.label}
227
- className={clsx(
228
- language === lang ? styles.selected : undefined,
229
- language === lang ? "api-code-tab--active" : undefined,
230
- "api-code-tab"
231
- )}
232
- onClick={() => setLanguage(lang)}
188
+ attributes={{ className: `code__tab--${lang.codeLanguage}` }}
233
189
  >
234
- {lang.tabName || lang.label}
235
- </button>
190
+ <CodeBlock language={lang.codeLanguage}>{codeText}</CodeBlock>
191
+ </CodeTab>
236
192
  );
237
193
  })}
238
- </div>
239
-
240
- <Highlight
241
- {...defaultProps}
242
- theme={languageTheme}
243
- code={codeText}
244
- language={language.highlight || language.lang}
245
- >
246
- {({ className, tokens, getLineProps, getTokenProps }) => (
247
- <FloatingButton onClick={handleCurlCopy} label={copyText}>
248
- <pre
249
- className={className}
250
- style={{
251
- background: "var(--openapi-card-background-color)",
252
- paddingRight: "60px",
253
- borderRadius:
254
- "2px 2px var(--openapi-card-border-radius) var(--openapi-card-border-radius)",
255
- }}
256
- >
257
- <code ref={ref}>
258
- {tokens.map((line, i) => (
259
- <span {...getLineProps({ line, key: i })}>
260
- {line.map((token, key) => {
261
- if (token.types.includes("arrow")) {
262
- token.types = ["arrow"];
263
- }
264
- return <span {...getTokenProps({ token, key })} />;
265
- })}
266
- {"\n"}
267
- </span>
268
- ))}
269
- </code>
270
- </pre>
271
- </FloatingButton>
272
- )}
273
- </Highlight>
194
+ </CodeTabs>
274
195
  </>
275
196
  );
276
197
  }
@@ -17,8 +17,12 @@ interface Props {
17
17
 
18
18
  function FloatingButton({ label, onClick, children }: Props) {
19
19
  return (
20
- <div className={styles.floatingButton}>
21
- {label && <button onClick={onClick}>{label}</button>}
20
+ <div tabIndex={0} className={styles.floatingButton}>
21
+ {label && (
22
+ <button tabIndex={0} onClick={onClick}>
23
+ {label}
24
+ </button>
25
+ )}
22
26
  {children}
23
27
  </div>
24
28
  );
@@ -9,7 +9,6 @@
9
9
  border-radius: var(--ifm-global-radius);
10
10
  color: var(--ifm-color-white);
11
11
  cursor: pointer;
12
- outline: none;
13
12
  padding: 0.4rem 0.5rem;
14
13
  opacity: 0;
15
14
  visibility: hidden;
@@ -20,7 +19,9 @@
20
19
  right: calc(var(--ifm-pre-padding) / 2);
21
20
  }
22
21
 
23
- .floatingButton:hover button {
22
+ .floatingButton:hover button,
23
+ .floatingButton:focus-visible button,
24
+ .floatingButton button:focus-visible {
24
25
  visibility: visible;
25
26
  opacity: 1;
26
27
  }
@@ -0,0 +1,71 @@
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, { useState } from "react";
9
+
10
+ import { usePrismTheme } from "@docusaurus/theme-common";
11
+ import useIsBrowser from "@docusaurus/useIsBrowser";
12
+ import { LiveProvider, LiveEditor, withLive } from "react-live";
13
+
14
+ import { setStringRawBody } from "../Body/slice";
15
+ import styles from "./styles.module.css";
16
+
17
+ function Live({ onEdit }: any) {
18
+ const isBrowser = useIsBrowser();
19
+ const [editorDisabled, setEditorDisabled] = useState(false);
20
+
21
+ // TODO: Temporary solution for disabling tab key
22
+ const handleKeydown = (event: React.KeyboardEvent) => {
23
+ if (event.key === "Tab") {
24
+ event.preventDefault();
25
+ setEditorDisabled(true);
26
+ }
27
+ };
28
+
29
+ return (
30
+ <div onClick={() => setEditorDisabled(false)}>
31
+ <LiveEditor
32
+ key={String(isBrowser)}
33
+ className={styles.playgroundEditor}
34
+ onChange={onEdit}
35
+ disabled={editorDisabled}
36
+ onKeyDown={handleKeydown}
37
+ />
38
+ </div>
39
+ );
40
+ }
41
+
42
+ const LiveComponent = withLive(Live);
43
+
44
+ function App({
45
+ children,
46
+ transformCode,
47
+ value,
48
+ language,
49
+ action,
50
+ ...props
51
+ }: any): JSX.Element {
52
+ const prismTheme = usePrismTheme();
53
+ const [code, setCode] = React.useState(children);
54
+ action(setStringRawBody(code));
55
+ return (
56
+ <div className={styles.playgroundContainer}>
57
+ <LiveProvider
58
+ code={children.replace(/\n$/, "")}
59
+ transformCode={transformCode ?? ((code) => `${code};`)}
60
+ theme={prismTheme}
61
+ language={language}
62
+ {...props}
63
+ >
64
+ <LiveComponent onEdit={setCode} />
65
+ </LiveProvider>
66
+ </div>
67
+ );
68
+ }
69
+
70
+ const LiveApp = withLive(App);
71
+ export default LiveApp;
@@ -0,0 +1,35 @@
1
+ .playgroundContainer {
2
+ margin-top: 1rem;
3
+ margin-bottom: var(--ifm-leading);
4
+ border-radius: var(--ifm-global-radius);
5
+ box-shadow: var(--ifm-global-shadow-lw);
6
+ overflow: auto;
7
+ max-height: 500px;
8
+ }
9
+
10
+ .playgroundHeader {
11
+ letter-spacing: 0.08rem;
12
+ padding: 0.75rem;
13
+ text-transform: uppercase;
14
+ font-weight: bold;
15
+ background: var(--ifm-color-emphasis-200);
16
+ color: var(--ifm-color-content);
17
+ font-size: var(--ifm-code-font-size);
18
+ }
19
+
20
+ .playgroundHeader:first-of-type {
21
+ background: var(--ifm-color-emphasis-600);
22
+ color: var(--ifm-color-content-inverse);
23
+ }
24
+
25
+ .playgroundEditor {
26
+ font: var(--ifm-code-font-size) / var(--ifm-pre-line-height)
27
+ var(--ifm-font-family-monospace) !important;
28
+ /* rtl:ignore */
29
+ direction: ltr;
30
+ }
31
+
32
+ .playgroundPreview {
33
+ padding: 1rem;
34
+ background-color: var(--ifm-pre-background);
35
+ }
@@ -41,10 +41,6 @@
41
41
  display: block;
42
42
  }
43
43
 
44
- .showMoreButton:focus {
45
- outline: 0;
46
- }
47
-
48
44
  .showMoreButton:hover {
49
45
  /* text-decoration: underline; */
50
46
  /* background-color: red; */
@@ -62,6 +62,7 @@ function Server() {
62
62
  <button
63
63
  className={styles.showMoreButton}
64
64
  onClick={() => setIsEditing(false)}
65
+ tabIndex={0}
65
66
  >
66
67
  Hide
67
68
  </button>
@@ -28,10 +28,6 @@
28
28
  display: block;
29
29
  }
30
30
 
31
- .showMoreButton:focus {
32
- outline: 0;
33
- }
34
-
35
31
  .showMoreButton:hover {
36
32
  /* text-decoration: underline; */
37
33
  /* background-color: red; */