docusaurus-theme-openapi-docs 0.0.0-beta.647 → 0.0.0-beta.651

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 (78) hide show
  1. package/lib/theme/ApiDemoPanel/ApiCodeBlock/Content/_Content.scss +1 -0
  2. package/lib/theme/ApiDemoPanel/Body/index.d.ts +3 -1
  3. package/lib/theme/ApiDemoPanel/Body/index.js +30 -32
  4. package/lib/theme/ApiDemoPanel/CodeTabs/_CodeTabs.scss +18 -0
  5. package/lib/theme/ApiDemoPanel/CodeTabs/index.js +7 -1
  6. package/lib/theme/ApiDemoPanel/Curl/index.js +1 -0
  7. package/lib/theme/ApiDemoPanel/FormItem/_FormItem.scss +11 -2
  8. package/lib/theme/ApiDemoPanel/FormItem/index.d.ts +2 -1
  9. package/lib/theme/ApiDemoPanel/FormItem/index.js +9 -3
  10. package/lib/theme/ApiDemoPanel/FormMultiSelect/_FormMultiSelect.scss +8 -4
  11. package/lib/theme/ApiDemoPanel/FormMultiSelect/index.d.ts +2 -1
  12. package/lib/theme/ApiDemoPanel/FormMultiSelect/index.js +5 -2
  13. package/lib/theme/ApiDemoPanel/FormSelect/_FormSelect.scss +3 -3
  14. package/lib/theme/ApiDemoPanel/FormTextInput/_FormTextInput.scss +24 -5
  15. package/lib/theme/ApiDemoPanel/FormTextInput/index.d.ts +1 -1
  16. package/lib/theme/ApiDemoPanel/FormTextInput/index.js +56 -10
  17. package/lib/theme/ApiDemoPanel/LiveEditor/index.d.ts +5 -2
  18. package/lib/theme/ApiDemoPanel/LiveEditor/index.js +59 -14
  19. package/lib/theme/ApiDemoPanel/ParamOptions/ParamFormItems/ParamArrayFormItem.d.ts +6 -0
  20. package/lib/theme/ApiDemoPanel/ParamOptions/ParamFormItems/ParamArrayFormItem.js +194 -0
  21. package/lib/theme/ApiDemoPanel/ParamOptions/ParamFormItems/ParamBooleanFormItem.d.ts +6 -0
  22. package/lib/theme/ApiDemoPanel/ParamOptions/ParamFormItems/ParamBooleanFormItem.js +63 -0
  23. package/lib/theme/ApiDemoPanel/ParamOptions/ParamFormItems/ParamMultiSelectFormItem.d.ts +6 -0
  24. package/lib/theme/ApiDemoPanel/ParamOptions/ParamFormItems/ParamMultiSelectFormItem.js +89 -0
  25. package/lib/theme/ApiDemoPanel/ParamOptions/ParamFormItems/ParamSelectFormItem.d.ts +6 -0
  26. package/lib/theme/ApiDemoPanel/ParamOptions/ParamFormItems/ParamSelectFormItem.js +63 -0
  27. package/lib/theme/ApiDemoPanel/ParamOptions/ParamFormItems/ParamTextFormItem.d.ts +6 -0
  28. package/lib/theme/ApiDemoPanel/ParamOptions/ParamFormItems/ParamTextFormItem.js +38 -0
  29. package/lib/theme/ApiDemoPanel/ParamOptions/_ParamOptions.scss +9 -28
  30. package/lib/theme/ApiDemoPanel/ParamOptions/index.js +24 -176
  31. package/lib/theme/ApiDemoPanel/Request/_Request.scss +93 -20
  32. package/lib/theme/ApiDemoPanel/Request/index.d.ts +1 -1
  33. package/lib/theme/ApiDemoPanel/Request/index.js +316 -37
  34. package/lib/theme/ApiDemoPanel/Response/_Response.scss +54 -0
  35. package/lib/theme/ApiDemoPanel/Response/index.d.ts +4 -1
  36. package/lib/theme/ApiDemoPanel/Response/index.js +56 -31
  37. package/lib/theme/ApiDemoPanel/Server/_Server.scss +10 -0
  38. package/lib/theme/ApiDemoPanel/Server/index.js +10 -11
  39. package/lib/theme/ApiDemoPanel/index.js +1 -1
  40. package/lib/theme/SchemaTabs/_SchemaTabs.scss +0 -1
  41. package/lib/theme/styles.scss +6 -0
  42. package/package.json +7 -4
  43. package/src/theme/ApiDemoPanel/ApiCodeBlock/Content/_Content.scss +1 -0
  44. package/src/theme/ApiDemoPanel/Body/index.tsx +38 -29
  45. package/src/theme/ApiDemoPanel/CodeTabs/_CodeTabs.scss +18 -0
  46. package/src/theme/ApiDemoPanel/CodeTabs/index.js +7 -1
  47. package/src/theme/ApiDemoPanel/Curl/index.tsx +1 -0
  48. package/src/theme/ApiDemoPanel/FormItem/_FormItem.scss +11 -2
  49. package/src/theme/ApiDemoPanel/FormItem/index.tsx +8 -3
  50. package/src/theme/ApiDemoPanel/FormMultiSelect/_FormMultiSelect.scss +8 -4
  51. package/src/theme/ApiDemoPanel/FormMultiSelect/index.tsx +7 -2
  52. package/src/theme/ApiDemoPanel/FormSelect/_FormSelect.scss +3 -3
  53. package/src/theme/ApiDemoPanel/FormTextInput/_FormTextInput.scss +24 -5
  54. package/src/theme/ApiDemoPanel/FormTextInput/index.tsx +58 -10
  55. package/src/theme/ApiDemoPanel/LiveEditor/index.tsx +53 -14
  56. package/src/theme/ApiDemoPanel/ParamOptions/ParamFormItems/ParamArrayFormItem.tsx +153 -0
  57. package/src/theme/ApiDemoPanel/ParamOptions/ParamFormItems/ParamBooleanFormItem.tsx +64 -0
  58. package/src/theme/ApiDemoPanel/ParamOptions/ParamFormItems/ParamMultiSelectFormItem.tsx +86 -0
  59. package/src/theme/ApiDemoPanel/ParamOptions/ParamFormItems/ParamSelectFormItem.tsx +65 -0
  60. package/src/theme/ApiDemoPanel/ParamOptions/ParamFormItems/ParamTextFormItem.tsx +38 -0
  61. package/src/theme/ApiDemoPanel/ParamOptions/_ParamOptions.scss +9 -28
  62. package/src/theme/ApiDemoPanel/ParamOptions/index.tsx +8 -196
  63. package/src/theme/ApiDemoPanel/Request/_Request.scss +93 -20
  64. package/src/theme/ApiDemoPanel/Request/index.tsx +250 -28
  65. package/src/theme/ApiDemoPanel/Response/_Response.scss +54 -0
  66. package/src/theme/ApiDemoPanel/Response/index.tsx +44 -26
  67. package/src/theme/ApiDemoPanel/Server/_Server.scss +10 -0
  68. package/src/theme/ApiDemoPanel/Server/index.tsx +8 -11
  69. package/src/theme/ApiDemoPanel/index.tsx +1 -1
  70. package/src/theme/SchemaTabs/_SchemaTabs.scss +0 -1
  71. package/src/theme/styles.scss +6 -0
  72. package/src/theme-openapi.d.ts +40 -1
  73. package/lib/theme/ApiDemoPanel/Execute/index.d.ts +0 -8
  74. package/lib/theme/ApiDemoPanel/Execute/index.js +0 -213
  75. package/src/theme/ApiDemoPanel/Execute/index.tsx +0 -200
  76. /package/lib/theme/ApiDemoPanel/{Execute → Request}/makeRequest.d.ts +0 -0
  77. /package/lib/theme/ApiDemoPanel/{Execute → Request}/makeRequest.js +0 -0
  78. /package/src/theme/ApiDemoPanel/{Execute → Request}/makeRequest.ts +0 -0
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "docusaurus-theme-openapi-docs",
3
3
  "description": "OpenAPI theme for Docusaurus.",
4
- "version": "0.0.0-beta.647",
4
+ "version": "0.0.0-beta.651",
5
5
  "license": "MIT",
6
6
  "keywords": [
7
7
  "openapi",
@@ -41,7 +41,9 @@
41
41
  },
42
42
  "dependencies": {
43
43
  "@docusaurus/theme-common": "^2.3.0",
44
+ "@hookform/error-message": "^2.0.1",
44
45
  "@mdx-js/react": "^1.6.21",
46
+ "@nextui-org/react": "^1.0.0-beta.12",
45
47
  "@paloaltonetworks/postman-code-generators": "1.1.15-patch.2",
46
48
  "@paloaltonetworks/postman-collection": "^4.1.0",
47
49
  "@reduxjs/toolkit": "^1.7.1",
@@ -49,7 +51,7 @@
49
51
  "clsx": "^1.1.1",
50
52
  "copy-text-to-clipboard": "^3.1.0",
51
53
  "crypto-js": "^4.1.1",
52
- "docusaurus-plugin-openapi-docs": "0.0.0-beta.647",
54
+ "docusaurus-plugin-openapi-docs": "0.0.0-beta.651",
53
55
  "docusaurus-plugin-sass": "^0.2.3",
54
56
  "file-saver": "^2.0.5",
55
57
  "immer": "^9.0.7",
@@ -57,7 +59,8 @@
57
59
  "node-polyfill-webpack-plugin": "^2.0.1",
58
60
  "prism-react-renderer": "^1.3.5",
59
61
  "process": "^0.11.10",
60
- "react-live": "^3.1.1",
62
+ "react-hook-form": "^7.43.8",
63
+ "react-live": "^4.0.0",
61
64
  "react-magic-dropzone": "^1.0.1",
62
65
  "react-markdown": "^8.0.1",
63
66
  "react-modal": "^3.15.1",
@@ -75,5 +78,5 @@
75
78
  "engines": {
76
79
  "node": ">=14"
77
80
  },
78
- "gitHead": "358ce5cd595fdd63d86b95dbc0f58569d9a15eaf"
81
+ "gitHead": "481c6eff7a5fff6fba2ef52e877ebb27a875259e"
79
82
  }
@@ -15,6 +15,7 @@
15
15
  }
16
16
 
17
17
  .openapi-demo__code-block {
18
+ border-radius: var(--ifm-global-radius);
18
19
  --ifm-pre-background: var(--prism-background-color);
19
20
  margin: 0;
20
21
  padding: 0;
@@ -8,7 +8,6 @@
8
8
  import React from "react";
9
9
 
10
10
  import json2xml from "@theme/ApiDemoPanel/Body/json2xml";
11
- import ContentType from "@theme/ApiDemoPanel/ContentType";
12
11
  import FormFileUpload from "@theme/ApiDemoPanel/FormFileUpload";
13
12
  import FormItem from "@theme/ApiDemoPanel/FormItem";
14
13
  import FormSelect from "@theme/ApiDemoPanel/FormSelect";
@@ -31,9 +30,16 @@ import {
31
30
  export interface Props {
32
31
  jsonRequestBodyExample: string;
33
32
  requestBodyMetadata?: RequestBodyObject;
33
+ methods?: any;
34
+ required?: boolean;
34
35
  }
35
36
 
36
- function BodyWrap({ requestBodyMetadata, jsonRequestBodyExample }: Props) {
37
+ function BodyWrap({
38
+ requestBodyMetadata,
39
+ jsonRequestBodyExample,
40
+ methods,
41
+ required,
42
+ }: Props) {
37
43
  const contentType = useTypedSelector((state: any) => state.contentType.value);
38
44
 
39
45
  // NOTE: We used to check if body was required, but opted to always show the request body
@@ -45,20 +51,21 @@ function BodyWrap({ requestBodyMetadata, jsonRequestBodyExample }: Props) {
45
51
  }
46
52
 
47
53
  return (
48
- <>
49
- <ContentType />
50
- <Body
51
- requestBodyMetadata={requestBodyMetadata}
52
- jsonRequestBodyExample={jsonRequestBodyExample}
53
- />
54
- </>
54
+ <Body
55
+ requestBodyMetadata={requestBodyMetadata}
56
+ jsonRequestBodyExample={jsonRequestBodyExample}
57
+ required={required}
58
+ />
55
59
  );
56
60
  }
57
61
 
58
- function Body({ requestBodyMetadata, jsonRequestBodyExample }: Props) {
62
+ function Body({
63
+ requestBodyMetadata,
64
+ jsonRequestBodyExample,
65
+ methods,
66
+ required,
67
+ }: Props) {
59
68
  const contentType = useTypedSelector((state: any) => state.contentType.value);
60
- const required = requestBodyMetadata?.required;
61
-
62
69
  const dispatch = useTypedDispatch();
63
70
 
64
71
  // Lot's of possible content-types:
@@ -88,7 +95,7 @@ function Body({ requestBodyMetadata, jsonRequestBodyExample }: Props) {
88
95
 
89
96
  if (schema?.format === "binary") {
90
97
  return (
91
- <FormItem label="Body" required={required}>
98
+ <FormItem>
92
99
  <FormFileUpload
93
100
  placeholder={schema.description || "Body"}
94
101
  onChange={(file: any) => {
@@ -114,15 +121,8 @@ function Body({ requestBodyMetadata, jsonRequestBodyExample }: Props) {
114
121
  schema?.type === "object"
115
122
  ) {
116
123
  return (
117
- <FormItem label="Body" required={required}>
118
- <div
119
- style={{
120
- marginTop: "calc(var(--ifm-pre-padding) / 2)",
121
- borderRadius: "4px",
122
- padding: "var(--ifm-pre-padding)",
123
- border: "1px solid var(--openapi-monaco-border-color)",
124
- }}
125
- >
124
+ <FormItem className="openapi-demo__form-item-body-container">
125
+ <div>
126
126
  {Object.entries(schema.properties ?? {}).map(([key, val]: any) => {
127
127
  if (val.format === "binary") {
128
128
  return (
@@ -196,6 +196,11 @@ function Body({ requestBodyMetadata, jsonRequestBodyExample }: Props) {
196
196
  }
197
197
  >
198
198
  <FormTextInput
199
+ paramName={key}
200
+ isRequired={
201
+ Array.isArray(schema.required) &&
202
+ schema.required.includes(key)
203
+ }
199
204
  placeholder={val.description || key}
200
205
  onChange={(e: React.ChangeEvent<HTMLInputElement>) => {
201
206
  dispatch(
@@ -282,18 +287,22 @@ function Body({ requestBodyMetadata, jsonRequestBodyExample }: Props) {
282
287
 
283
288
  if (exampleBody) {
284
289
  return (
285
- <FormItem label="Body" required={required}>
290
+ <FormItem>
286
291
  <SchemaTabs className="openapi-tabs__schema" lazy>
287
292
  {/* @ts-ignore */}
288
293
  <TabItem label="Default" value="default" default>
289
- <LiveApp action={dispatch} language={language}>
294
+ <LiveApp action={dispatch} language={language} required={required}>
290
295
  {defaultBody}
291
296
  </LiveApp>
292
297
  </TabItem>
293
298
  {/* @ts-ignore */}
294
299
  <TabItem label="Example" value="example">
295
300
  {exampleBody && (
296
- <LiveApp action={dispatch} language={language}>
301
+ <LiveApp
302
+ action={dispatch}
303
+ language={language}
304
+ required={required}
305
+ >
297
306
  {exampleBody}
298
307
  </LiveApp>
299
308
  )}
@@ -305,11 +314,11 @@ function Body({ requestBodyMetadata, jsonRequestBodyExample }: Props) {
305
314
 
306
315
  if (examplesBodies && examplesBodies.length > 0) {
307
316
  return (
308
- <FormItem label="Body" required={required}>
317
+ <FormItem className="openapi-demo__form-item-body-container">
309
318
  <SchemaTabs className="openapi-tabs__schema" lazy>
310
319
  {/* @ts-ignore */}
311
320
  <TabItem label="Default" value="default" default>
312
- <LiveApp action={dispatch} language={language}>
321
+ <LiveApp action={dispatch} language={language} required={required}>
313
322
  {defaultBody}
314
323
  </LiveApp>
315
324
  </TabItem>
@@ -336,8 +345,8 @@ function Body({ requestBodyMetadata, jsonRequestBodyExample }: Props) {
336
345
  }
337
346
 
338
347
  return (
339
- <FormItem label="Body" required={required}>
340
- <LiveApp action={dispatch} language={language}>
348
+ <FormItem>
349
+ <LiveApp action={dispatch} language={language} required={required}>
341
350
  {defaultBody}
342
351
  </LiveApp>
343
352
  </FormItem>
@@ -13,6 +13,22 @@
13
13
  .openapi-tabs__code-container {
14
14
  margin-bottom: 1rem;
15
15
 
16
+ &:not(.openapi-tabs__code-container-inner) {
17
+ padding: 1rem;
18
+ background-color: var(--ifm-pre-background);
19
+ border-radius: var(--ifm-global-radius);
20
+ border: 1px solid var(--openapi-demo-border-color);
21
+ box-shadow: 0 2px 3px hsla(222, 8%, 43%, 0.1),
22
+ 0 8px 16px -10px hsla(222, 8%, 43%, 0.2);
23
+ transition: 300ms;
24
+
25
+ &:hover {
26
+ box-shadow: 0 0 0 2px rgba(38, 53, 61, 0.15),
27
+ 0 2px 3px hsla(222, 8%, 43%, 0.15),
28
+ 0 16px 16px -10px hsla(222, 8%, 43%, 0.2);
29
+ }
30
+ }
31
+
16
32
  .openapi-tabs__code-item {
17
33
  display: flex;
18
34
  flex-direction: column-reverse;
@@ -54,6 +70,8 @@
54
70
 
55
71
  .openapi-demo__code-block code {
56
72
  max-height: 200px;
73
+ font-size: var(--openapi-demo-font-size-code);
74
+ padding-top: var(--ifm-pre-padding);
57
75
  }
58
76
 
59
77
  body[class="ReactModal__Body--open"] {
@@ -147,8 +147,14 @@ function TabContent({ lazy, children, selectedValue }) {
147
147
 
148
148
  function TabsComponent(props) {
149
149
  const tabs = useTabs(props);
150
+ const { className } = props;
151
+
150
152
  return (
151
- <div className="tabs-container openapi-tabs__code-container">
153
+ <div
154
+ className={clsx("tabs-container openapi-tabs__code-container", {
155
+ [className]: className,
156
+ })}
157
+ >
152
158
  <TabList {...props} {...tabs} />
153
159
  <TabContent {...props} {...tabs} />
154
160
  </div>
@@ -325,6 +325,7 @@ function Curl({ postman, codeSamples }: Props) {
325
325
  }}
326
326
  >
327
327
  <CodeTabs
328
+ className="openapi-tabs__code-container-inner"
328
329
  action={{
329
330
  setLanguage: setLanguage,
330
331
  setSelectedVariant: setSelectedVariant,
@@ -1,12 +1,21 @@
1
1
  .openapi-demo__form-item {
2
- margin-top: var(--ifm-pre-padding);
2
+ padding: var(--openapi-demo-padding-input);
3
+ font-size: var(--openapi-demo-font-size-input);
3
4
 
4
5
  &:first-child {
5
6
  margin-top: 0;
6
7
  }
7
8
 
8
9
  .required {
9
- font-size: var(--ifm-code-font-size);
10
10
  color: var(--openapi-required);
11
11
  }
12
12
  }
13
+
14
+ .openapi-demo__form-item-body-container {
15
+ padding: 0;
16
+ }
17
+
18
+ .openapi-demo__form-item-label {
19
+ font-family: var(--ifm-font-family-monospace);
20
+ font-weight: bold;
21
+ }
@@ -7,17 +7,22 @@
7
7
 
8
8
  import React from "react";
9
9
 
10
+ import clsx from "clsx";
11
+
10
12
  export interface Props {
11
13
  label?: string;
12
14
  type?: string;
13
15
  required?: boolean | undefined;
14
16
  children?: React.ReactNode;
17
+ className?: string;
15
18
  }
16
19
 
17
- function FormItem({ label, type, required, children }: Props) {
20
+ function FormItem({ label, type, required, children, className }: Props) {
18
21
  return (
19
- <div className="openapi-demo__form-item">
20
- <code>{label}</code>
22
+ <div className={clsx("openapi-demo__form-item", className)}>
23
+ {label && (
24
+ <label className="openapi-demo__form-item-label">{label}</label>
25
+ )}
21
26
  {type && <span style={{ opacity: 0.6 }}> — {type}</span>}
22
27
  {required && (
23
28
  <span>
@@ -1,19 +1,23 @@
1
1
  .openapi-demo__multi-select-input {
2
2
  width: 100%;
3
3
  margin-top: calc(var(--ifm-pre-padding) / 2);
4
- padding: 12px var(--ifm-pre-padding);
4
+ padding: 1rem;
5
5
  border-radius: 4px;
6
- border: 2px solid transparent;
6
+ border: 1px solid transparent;
7
7
  background-color: var(--openapi-input-background);
8
8
  outline: none;
9
- font-size: var(--ifm-code-font-size);
9
+ font-size: var(--openapi-demo-font-size-input);
10
10
  color: var(--ifm-pre-color);
11
11
  -moz-appearance: none;
12
12
  -webkit-appearance: none;
13
13
  appearance: none;
14
14
 
15
15
  &:focus {
16
- border: 2px solid var(--openapi-input-border);
16
+ border: 1px solid var(--openapi-input-border);
17
+ }
18
+
19
+ &.error {
20
+ border: 1px solid var(--ifm-color-danger);
17
21
  }
18
22
 
19
23
  option {
@@ -7,13 +7,16 @@
7
7
 
8
8
  import React from "react";
9
9
 
10
+ import clsx from "clsx";
11
+
10
12
  export interface Props {
11
13
  value?: string;
12
14
  options: string[];
13
15
  onChange?: React.ChangeEventHandler<HTMLSelectElement>;
16
+ showErrors?: boolean;
14
17
  }
15
18
 
16
- function FormMultiSelect({ value, options, onChange }: Props) {
19
+ function FormMultiSelect({ value, options, onChange, showErrors }: Props) {
17
20
  if (options.length === 0) {
18
21
  return null;
19
22
  }
@@ -32,7 +35,9 @@ function FormMultiSelect({ value, options, onChange }: Props) {
32
35
  return (
33
36
  <select
34
37
  style={{ height: height }}
35
- className="openapi-demo__multi-select-input"
38
+ className={clsx("openapi-demo__multi-select-input", {
39
+ error: showErrors,
40
+ })}
36
41
  value={value}
37
42
  onChange={onChange}
38
43
  size={Math.min(6, options.length + 1)}
@@ -4,7 +4,6 @@ html[data-theme="dark"] .openapi-demo__select-input {
4
4
  border: none;
5
5
  outline: none;
6
6
  width: 100%;
7
- font-size: var(--ifm-code-font-size);
8
7
  color: var(--ifm-pre-color);
9
8
 
10
9
  border-radius: 4px;
@@ -21,12 +20,13 @@ html[data-theme="dark"] .openapi-demo__select-input {
21
20
  .openapi-demo__select-input {
22
21
  width: 100%;
23
22
  margin-top: calc(var(--ifm-pre-padding) / 2);
24
- padding: 12px 48px 12px var(--ifm-pre-padding);
23
+ padding: var(--openapi-demo-padding-input);
25
24
  border: none;
26
25
  outline: none;
27
26
  border-radius: 4px;
28
27
  background-color: var(--openapi-input-background);
29
- font-size: var(--ifm-code-font-size);
28
+ font-size: var(--openapi-demo-font-size-input);
29
+ font-family: var(--ifm-font-family-monospace);
30
30
  color: var(--ifm-pre-color);
31
31
  -moz-appearance: none;
32
32
  -webkit-appearance: none;
@@ -1,15 +1,34 @@
1
- .openapi-demo__input {
1
+ .openapi-demo__form-item-input {
2
2
  margin-top: calc(var(--ifm-pre-padding) / 2);
3
3
  background-color: var(--openapi-input-background);
4
- border: none;
4
+ border: 1px solid transparent;
5
5
  outline: none;
6
6
  width: 100%;
7
- font-size: var(--ifm-code-font-size);
8
7
  color: var(--ifm-pre-color);
9
- padding: 12px var(--ifm-pre-padding);
8
+ padding: var(--openapi-demo-padding-input);
10
9
  border-radius: 4px;
11
10
 
11
+ &:hover {
12
+ border: 1px solid var(--ifm-toc-border-color);
13
+ }
14
+
12
15
  &:focus {
13
- box-shadow: inset 0px 0px 0px 2px var(--openapi-input-border);
16
+ border: 1px solid var(--ifm-color-primary);
17
+ box-shadow: none;
18
+ }
19
+
20
+ &.error {
21
+ border: 1px solid var(--openapi-required);
22
+ }
23
+ }
24
+
25
+ .openapi-demo__input-error {
26
+ font-size: var(--openapi-demo-font-size-input);
27
+ color: var(--openapi-required);
28
+ padding-top: var(--openapi-demo-padding-input);
29
+
30
+ &::before {
31
+ display: inline;
32
+ content: "⚠ ";
14
33
  }
15
34
  }
@@ -5,8 +5,13 @@
5
5
  * LICENSE file in the root directory of this source tree.
6
6
  * ========================================================================== */
7
7
 
8
+ // @ts-nocheck
8
9
  import React from "react";
9
10
 
11
+ import { ErrorMessage } from "@hookform/error-message";
12
+ import clsx from "clsx";
13
+ import { useFormContext } from "react-hook-form";
14
+
10
15
  export interface Props {
11
16
  value?: string;
12
17
  placeholder?: string;
@@ -14,18 +19,61 @@ export interface Props {
14
19
  onChange?: React.ChangeEventHandler<HTMLInputElement>;
15
20
  }
16
21
 
17
- function FormTextInput({ value, placeholder, password, onChange }: Props) {
22
+ function FormTextInput({
23
+ isRequired,
24
+ value,
25
+ placeholder,
26
+ password,
27
+ onChange,
28
+ paramName,
29
+ }: Props) {
18
30
  placeholder = placeholder?.split("\n")[0];
31
+
32
+ const {
33
+ register,
34
+ formState: { errors },
35
+ } = useFormContext();
36
+
37
+ const showErrorMessage = errors?.[paramName]?.message;
38
+
19
39
  return (
20
- <input
21
- className="openapi-demo__input"
22
- type={password ? "password" : "text"}
23
- placeholder={placeholder}
24
- title={placeholder}
25
- value={value}
26
- onChange={onChange}
27
- autoComplete="off"
28
- />
40
+ <>
41
+ {paramName ? (
42
+ <input
43
+ {...register(paramName, {
44
+ required: isRequired ? "This field is required" : false,
45
+ })}
46
+ className={clsx("openapi-demo__form-item-input", {
47
+ error: showErrorMessage,
48
+ })}
49
+ type={password ? "password" : "text"}
50
+ placeholder={placeholder}
51
+ title={placeholder}
52
+ value={value}
53
+ onChange={onChange}
54
+ autoComplete="off"
55
+ />
56
+ ) : (
57
+ <input
58
+ className="openapi-demo__form-item-input"
59
+ type={password ? "password" : "text"}
60
+ placeholder={placeholder}
61
+ title={placeholder}
62
+ value={value}
63
+ onChange={onChange}
64
+ autoComplete="off"
65
+ />
66
+ )}
67
+ {showErrorMessage && (
68
+ <ErrorMessage
69
+ errors={errors}
70
+ name={paramName}
71
+ render={({ message }) => (
72
+ <div className="openapi-demo__input-error">{message}</div>
73
+ )}
74
+ />
75
+ )}
76
+ </>
29
77
  );
30
78
  }
31
79
 
@@ -9,29 +9,31 @@ import React, { useEffect, useState } from "react";
9
9
 
10
10
  import { usePrismTheme } from "@docusaurus/theme-common";
11
11
  import useIsBrowser from "@docusaurus/useIsBrowser";
12
+ import { ErrorMessage } from "@hookform/error-message";
12
13
  import { setStringRawBody } from "@theme/ApiDemoPanel/Body/slice";
14
+ import clsx from "clsx";
15
+ import { Controller, useFormContext } from "react-hook-form";
13
16
  import { LiveProvider, LiveEditor, withLive } from "react-live";
14
17
 
15
- function Live({ onEdit }: any) {
18
+ function Live({ onEdit, showErrors }: any) {
16
19
  const isBrowser = useIsBrowser();
17
20
  const [editorDisabled, setEditorDisabled] = useState(false);
18
21
 
19
- // TODO: Temporary solution for disabling tab key
20
- const handleKeydown = (event: React.KeyboardEvent) => {
21
- if (event.key === "Tab") {
22
- event.preventDefault();
23
- setEditorDisabled(true);
24
- }
25
- };
26
-
27
22
  return (
28
- <div onClick={() => setEditorDisabled(false)}>
23
+ <div
24
+ onClick={() => setEditorDisabled(false)}
25
+ onBlur={() => setEditorDisabled(true)}
26
+ >
29
27
  <LiveEditor
30
28
  key={String(isBrowser)}
31
- className="openapi-demo__playground-editor"
29
+ className={clsx({
30
+ "openapi-demo__playground-editor": true,
31
+ "openapi-demo__form-item-input": showErrors,
32
+ error: showErrors,
33
+ })}
32
34
  onChange={onEdit}
33
35
  disabled={editorDisabled}
34
- onKeyDown={handleKeydown}
36
+ tabMode="focus"
35
37
  />
36
38
  </div>
37
39
  );
@@ -45,6 +47,7 @@ function App({
45
47
  value,
46
48
  language,
47
49
  action,
50
+ required: isRequired,
48
51
  ...props
49
52
  }: any): JSX.Element {
50
53
  const prismTheme = usePrismTheme();
@@ -54,8 +57,24 @@ function App({
54
57
  action(setStringRawBody(code));
55
58
  }, [action, code]);
56
59
 
60
+ const {
61
+ control,
62
+ formState: { errors },
63
+ } = useFormContext();
64
+
65
+ const showErrorMessage = errors?.requestBody;
66
+
67
+ const handleChange = (snippet: string, onChange: any) => {
68
+ setCode(snippet);
69
+ onChange(snippet);
70
+ };
71
+
57
72
  return (
58
- <div className="openapi-demo__playground-container">
73
+ <div
74
+ className={clsx({
75
+ "openapi-demo__playground-container": true,
76
+ })}
77
+ >
59
78
  <LiveProvider
60
79
  code={children.replace(/\n$/, "")}
61
80
  transformCode={transformCode ?? ((code) => `${code};`)}
@@ -63,7 +82,27 @@ function App({
63
82
  language={language}
64
83
  {...props}
65
84
  >
66
- <LiveComponent onEdit={setCode} />
85
+ <Controller
86
+ control={control}
87
+ rules={{ required: isRequired ? "This field is required" : false }}
88
+ name="requestBody"
89
+ render={({ field: { onChange, name } }) => (
90
+ <LiveComponent
91
+ onEdit={(e: any) => handleChange(e, onChange)}
92
+ name={name}
93
+ showErrors={showErrorMessage}
94
+ />
95
+ )}
96
+ />
97
+ {showErrorMessage && (
98
+ <ErrorMessage
99
+ errors={errors}
100
+ name="requestBody"
101
+ render={({ message }) => (
102
+ <div className="openapi-demo__input-error">{message}</div>
103
+ )}
104
+ />
105
+ )}
67
106
  </LiveProvider>
68
107
  </div>
69
108
  );