Skip to content

Commit 77b068a

Browse files
committed
fix(theme): improve accessibility of api explorer controls
1 parent 7a5535e commit 77b068a

File tree

25 files changed

+398
-161
lines changed

25 files changed

+398
-161
lines changed

packages/docusaurus-theme-openapi-docs/src/theme/ApiExplorer/Accept/index.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,9 @@ function Accept() {
2323
}
2424

2525
return (
26-
<FormItem label="Accept">
26+
<FormItem>
2727
<FormSelect
28+
label="Accept"
2829
value={value}
2930
options={options}
3031
onChange={(e: any) => dispatch(setAccept(e.target.value))}

packages/docusaurus-theme-openapi-docs/src/theme/ApiExplorer/Authorization/index.tsx

Lines changed: 27 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -34,13 +34,12 @@ function Authorization() {
3434
return (
3535
<div>
3636
{optionKeys.length > 1 && (
37-
<FormItem
38-
label={translate({
39-
id: OPENAPI_AUTH.SECURITY_SCHEME,
40-
message: "Security Scheme",
41-
})}
42-
>
37+
<FormItem>
4338
<FormSelect
39+
label={translate({
40+
id: OPENAPI_AUTH.SECURITY_SCHEME,
41+
message: "Security Scheme",
42+
})}
4443
options={optionKeys}
4544
value={selected}
4645
onChange={(e: React.ChangeEvent<HTMLSelectElement>) => {
@@ -52,14 +51,12 @@ function Authorization() {
5251
{selectedAuth.map((a: any) => {
5352
if (a.type === "http" && a.scheme === "bearer") {
5453
return (
55-
<FormItem
56-
label={translate({
57-
id: OPENAPI_AUTH.BEARER_TOKEN,
58-
message: "Bearer Token",
59-
})}
60-
key={a.key + "-bearer"}
61-
>
54+
<FormItem key={a.key + "-bearer"}>
6255
<FormTextInput
56+
label={translate({
57+
id: OPENAPI_AUTH.BEARER_TOKEN,
58+
message: "Bearer Token",
59+
})}
6360
placeholder={translate({
6461
id: OPENAPI_AUTH.BEARER_TOKEN,
6562
message: "Bearer Token",
@@ -83,14 +80,12 @@ function Authorization() {
8380

8481
if (a.type === "oauth2") {
8582
return (
86-
<FormItem
87-
label={translate({
88-
id: OPENAPI_AUTH.BEARER_TOKEN,
89-
message: "Bearer Token",
90-
})}
91-
key={a.key + "-oauth2"}
92-
>
83+
<FormItem key={a.key + "-oauth2"}>
9384
<FormTextInput
85+
label={translate({
86+
id: OPENAPI_AUTH.BEARER_TOKEN,
87+
message: "Bearer Token",
88+
})}
9489
placeholder={translate({
9590
id: OPENAPI_AUTH.BEARER_TOKEN,
9691
message: "Bearer Token",
@@ -115,13 +110,12 @@ function Authorization() {
115110
if (a.type === "http" && a.scheme === "basic") {
116111
return (
117112
<React.Fragment key={a.key + "-basic"}>
118-
<FormItem
119-
label={translate({
120-
id: OPENAPI_AUTH.USERNAME,
121-
message: "Username",
122-
})}
123-
>
113+
<FormItem>
124114
<FormTextInput
115+
label={translate({
116+
id: OPENAPI_AUTH.USERNAME,
117+
message: "Username",
118+
})}
125119
placeholder={translate({
126120
id: OPENAPI_AUTH.USERNAME,
127121
message: "Username",
@@ -139,13 +133,12 @@ function Authorization() {
139133
}}
140134
/>
141135
</FormItem>
142-
<FormItem
143-
label={translate({
144-
id: OPENAPI_AUTH.PASSWORD,
145-
message: "Password",
146-
})}
147-
>
136+
<FormItem>
148137
<FormTextInput
138+
label={translate({
139+
id: OPENAPI_AUTH.PASSWORD,
140+
message: "Password",
141+
})}
149142
placeholder={translate({
150143
id: OPENAPI_AUTH.PASSWORD,
151144
message: "Password",
@@ -170,8 +163,9 @@ function Authorization() {
170163

171164
if (a.type === "apiKey") {
172165
return (
173-
<FormItem label={`${a.key}`} key={a.key + "-apikey"}>
166+
<FormItem key={a.key + "-apikey"}>
174167
<FormTextInput
168+
label={`${a.key}`}
175169
placeholder={`${a.key}`}
176170
password
177171
value={data[a.key].apiKey ?? ""}

packages/docusaurus-theme-openapi-docs/src/theme/ApiExplorer/Body/FormBodyItem/index.tsx

Lines changed: 44 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
import React from "react";
99

1010
import FormFileUpload from "@theme/ApiExplorer/FormFileUpload";
11+
import FormLabel from "@theme/ApiExplorer/FormLabel";
1112
import FormSelect from "@theme/ApiExplorer/FormSelect";
1213
import FormTextInput from "@theme/ApiExplorer/FormTextInput";
1314
import LiveApp from "@theme/ApiExplorer/LiveEditor";
@@ -21,12 +22,16 @@ interface FormBodyItemProps {
2122
schemaObject: SchemaObject;
2223
id: string;
2324
schema: SchemaObject;
25+
label?: string;
26+
required?: boolean;
2427
}
2528

2629
export default function FormBodyItem({
2730
schemaObject,
2831
id,
2932
schema,
33+
label,
34+
required,
3035
}: FormBodyItemProps): React.JSX.Element {
3136
const dispatch = useTypedDispatch();
3237

@@ -35,30 +40,36 @@ export default function FormBodyItem({
3540
schemaObject.items?.format === "binary"
3641
) {
3742
return (
38-
<FileArrayFormBodyItem id={id} description={schemaObject.description} />
43+
<>
44+
{label && <FormLabel label={label} required={required} />}
45+
<FileArrayFormBodyItem id={id} description={schemaObject.description} />
46+
</>
3947
);
4048
}
4149

4250
if (schemaObject.format === "binary") {
4351
return (
44-
<FormFileUpload
45-
placeholder={schemaObject.description || id}
46-
onChange={(file: any) => {
47-
if (file === undefined) {
48-
dispatch(clearFormBodyKey(id));
49-
return;
50-
}
51-
dispatch(
52-
setFileFormBody({
53-
key: id,
54-
value: {
55-
src: `/path/to/${file.name}`,
56-
content: file,
57-
},
58-
})
59-
);
60-
}}
61-
/>
52+
<>
53+
{label && <FormLabel label={label} required={required} />}
54+
<FormFileUpload
55+
placeholder={schemaObject.description || id}
56+
onChange={(file: any) => {
57+
if (file === undefined) {
58+
dispatch(clearFormBodyKey(id));
59+
return;
60+
}
61+
dispatch(
62+
setFileFormBody({
63+
key: id,
64+
value: {
65+
src: `/path/to/${file.name}`,
66+
content: file,
67+
},
68+
})
69+
);
70+
}}
71+
/>
72+
</>
6273
);
6374
}
6475

@@ -73,13 +84,16 @@ export default function FormBodyItem({
7384
);
7485

7586
return (
76-
<LiveApp
77-
action={(code: string) =>
78-
dispatch(setStringFormBody({ key: id, value: code }))
79-
}
80-
>
81-
{objectExample}
82-
</LiveApp>
87+
<>
88+
{label && <FormLabel label={label} required={required} />}
89+
<LiveApp
90+
action={(code: string) =>
91+
dispatch(setStringFormBody({ key: id, value: code }))
92+
}
93+
>
94+
{objectExample}
95+
</LiveApp>
96+
</>
8397
);
8498
}
8599

@@ -89,6 +103,8 @@ export default function FormBodyItem({
89103
) {
90104
return (
91105
<FormSelect
106+
label={label}
107+
required={required}
92108
options={["---", ...schemaObject.enum]}
93109
onChange={(e: React.ChangeEvent<HTMLSelectElement>) => {
94110
const val = e.target.value;
@@ -109,6 +125,8 @@ export default function FormBodyItem({
109125
// TODO: support all the other types.
110126
return (
111127
<FormTextInput
128+
label={label}
129+
required={required}
112130
paramName={id}
113131
isRequired={
114132
Array.isArray(schema.required) && schema.required.includes(id)

packages/docusaurus-theme-openapi-docs/src/theme/ApiExplorer/Body/index.tsx

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -318,18 +318,17 @@ function Body({
318318
<FormItem className="openapi-explorer__form-item-body-container">
319319
{Object.entries(schema.properties ?? {}).map(([key, val]: any) => {
320320
return (
321-
<FormItem
322-
key={key}
323-
label={key}
324-
required={
325-
Array.isArray(schema.required) && schema.required.includes(key)
326-
}
327-
>
321+
<FormItem key={key}>
328322
<FormBodyItem
329323
schemaObject={val}
330324
id={key}
331325
schema={schema}
332-
></FormBodyItem>
326+
label={key}
327+
required={
328+
Array.isArray(schema.required) &&
329+
schema.required.includes(key)
330+
}
331+
/>
333332
</FormItem>
334333
);
335334
})}

packages/docusaurus-theme-openapi-docs/src/theme/ApiExplorer/ContentType/index.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,9 @@ function ContentType() {
2323
}
2424

2525
return (
26-
<FormItem label="Content-Type">
26+
<FormItem>
2727
<FormSelect
28+
label="Content-Type"
2829
value={value}
2930
options={options}
3031
onChange={(e: React.ChangeEvent<HTMLSelectElement>) =>

packages/docusaurus-theme-openapi-docs/src/theme/ApiExplorer/FormItem/_FormItem.scss

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,3 @@
1414
.openapi-explorer__form-item-body-container {
1515
padding: 0;
1616
}
17-
18-
.openapi-explorer__form-item-label {
19-
font-family: var(--ifm-font-family-monospace);
20-
font-weight: bold;
21-
}

packages/docusaurus-theme-openapi-docs/src/theme/ApiExplorer/FormItem/index.tsx

Lines changed: 2 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -7,31 +7,17 @@
77

88
import React from "react";
99

10-
import { translate } from "@docusaurus/Translate";
11-
import { OPENAPI_SCHEMA_ITEM } from "@theme/translationIds";
1210
import clsx from "clsx";
1311

1412
export interface Props {
15-
label?: string;
16-
type?: string;
17-
required?: boolean | undefined;
1813
children?: React.ReactNode;
1914
className?: string;
2015
}
2116

22-
function FormItem({ label, type, required, children, className }: Props) {
17+
function FormItem({ children, className }: Props) {
2318
return (
2419
<div className={clsx("openapi-explorer__form-item", className)}>
25-
{label && (
26-
<label className="openapi-explorer__form-item-label">{label}</label>
27-
)}
28-
{type && <span style={{ opacity: 0.6 }}>{type}</span>}
29-
{required && (
30-
<span className="openapi-schema__required">
31-
{translate({ id: OPENAPI_SCHEMA_ITEM.REQUIRED, message: "required" })}
32-
</span>
33-
)}
34-
<div>{children}</div>
20+
{children}
3521
</div>
3622
);
3723
}
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
.openapi-explorer__form-item-label {
2+
font-family: var(--ifm-font-family-monospace);
3+
font-weight: bold;
4+
}
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
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 from "react";
9+
10+
import { translate } from "@docusaurus/Translate";
11+
import { OPENAPI_SCHEMA_ITEM } from "@theme/translationIds";
12+
13+
export interface Props {
14+
htmlFor?: string;
15+
label: string;
16+
type?: string;
17+
required?: boolean;
18+
}
19+
20+
function FormLabel({ htmlFor, label, type, required }: Props) {
21+
const LabelTag = htmlFor ? "label" : "span";
22+
23+
return (
24+
<>
25+
<LabelTag className="openapi-explorer__form-item-label" htmlFor={htmlFor}>
26+
{label}
27+
</LabelTag>
28+
{type && <span style={{ opacity: 0.6 }}>{type}</span>}
29+
{required && (
30+
<span className="openapi-schema__required">
31+
{translate({
32+
id: OPENAPI_SCHEMA_ITEM.REQUIRED,
33+
message: "required",
34+
})}
35+
</span>
36+
)}
37+
</>
38+
);
39+
}
40+
41+
export default FormLabel;

0 commit comments

Comments
 (0)