aboutsummaryrefslogtreecommitdiff
path: root/src/console
diff options
context:
space:
mode:
authorShin'ya Ueoka <ueokande@i-beam.org>2020-08-16 16:39:57 +0900
committerShin'ya Ueoka <ueokande@i-beam.org>2020-09-21 12:48:18 +0900
commit264d69c933370b3321dfcd83d823222e730e3fe0 (patch)
tree9d70c4a6cc8c5eb8c8565098e31e8eda7f3ccf9c /src/console
parenta70122acd6595ba26f084d22185c40f6da65b5ac (diff)
Improve a11y in completion items
Diffstat (limited to 'src/console')
-rw-r--r--src/console/components/console/Completion.tsx48
-rw-r--r--src/console/components/console/CompletionItem.tsx18
-rw-r--r--src/console/components/console/CompletionTitle.tsx10
3 files changed, 54 insertions, 22 deletions
diff --git a/src/console/components/console/Completion.tsx b/src/console/components/console/Completion.tsx
index aefee32..56c5de3 100644
--- a/src/console/components/console/Completion.tsx
+++ b/src/console/components/console/Completion.tsx
@@ -63,29 +63,51 @@ class Completion extends React.Component<Props, State> {
}
render() {
- let eles = [];
- let index = 0;
+ let itemIndex = 0;
+ let viewIndex = 0;
+ const groups: Array<JSX.Element> = [];
+ const viewOffset = this.state.viewOffset;
+ const viewSize = this.props.size;
- for (const group of this.props.completions) {
- eles.push(<CompletionTitle key={`group-${index}`} title={group.name} />);
+ this.props.completions.forEach((group, groupIndex) => {
+ const items = [];
+ const title = (
+ <CompletionTitle
+ id={`title-${groupIndex}`}
+ key={`group-${groupIndex}`}
+ shown={viewOffset <= viewIndex && viewIndex < viewOffset + viewSize}
+ title={group.name}
+ />
+ );
+ ++viewIndex;
for (const item of group.items) {
- eles.push(
+ items.push(
<CompletionItem
- key={`item-${index}`}
+ shown={viewOffset <= viewIndex && viewIndex < viewOffset + viewSize}
+ key={`item-${itemIndex}`}
icon={item.icon}
caption={item.caption}
url={item.url}
- highlight={index === this.props.select}
+ highlight={itemIndex === this.props.select}
+ role="menuitem"
/>
);
- ++index;
+ ++viewIndex;
+ ++itemIndex;
}
- }
-
- const viewOffset = this.state.viewOffset;
- eles = eles.slice(viewOffset, viewOffset + this.props.size);
+ groups.push(
+ <div
+ key={`group-${groupIndex}`}
+ role="group"
+ aria-describedby={`title-${groupIndex}`}
+ >
+ {title}
+ <ul>{items}</ul>
+ </div>
+ );
+ });
- return <ul>{eles}</ul>;
+ return <div role="menu">{groups}</div>;
}
}
diff --git a/src/console/components/console/CompletionItem.tsx b/src/console/components/console/CompletionItem.tsx
index da07bf0..76db5b5 100644
--- a/src/console/components/console/CompletionItem.tsx
+++ b/src/console/components/console/CompletionItem.tsx
@@ -1,7 +1,11 @@
import React from "react";
import styled from "../Theme";
-const Container = styled.li<{ icon: string; highlight: boolean }>`
+const Container = styled.li<{
+ shown: boolean;
+ icon: string;
+ highlight: boolean;
+}>`
backgroundimage: ${({ icon }) => "url(" + icon + ")"};
background-color: ${({ highlight, theme }) =>
highlight
@@ -11,6 +15,7 @@ const Container = styled.li<{ icon: string; highlight: boolean }>`
highlight
? theme.completionSelectedForeground
: theme.completionItemForeground};
+ display: ${({ shown }) => (shown ? "display" : "none")};
padding-left: 1.5rem;
background-position: 0 center;
background-size: contain;
@@ -34,16 +39,19 @@ const Description = styled.span`
`;
interface Props {
+ shown: boolean;
highlight: boolean;
caption?: string;
url?: string;
icon?: string;
}
-const CompletionItem: React.FC<Props> = ({ highlight, caption, url, icon }) => (
- <Container icon={icon || ""} highlight={highlight}>
- <Caption>{caption}</Caption>
- <Description>{url}</Description>
+const CompletionItem: React.FC<React.HTMLAttributes<HTMLElement> & Props> = (
+ props
+) => (
+ <Container icon={props.icon || ""} {...props}>
+ <Caption>{props.caption}</Caption>
+ <Description>{props.url}</Description>
</Container>
);
diff --git a/src/console/components/console/CompletionTitle.tsx b/src/console/components/console/CompletionTitle.tsx
index 55c3c2e..ec2fc8b 100644
--- a/src/console/components/console/CompletionTitle.tsx
+++ b/src/console/components/console/CompletionTitle.tsx
@@ -1,7 +1,8 @@
import React from "react";
import styled from "../Theme";
-const Li = styled.li`
+const Li = styled.li<{ shown: boolean }>`
+ display: ${({ shown }) => (shown ? "display" : "none")};
background-color: ${({ theme }) => theme.completionTitleBackground};
color: ${({ theme }) => theme.completionTitleForeground};
font-weight: bold;
@@ -10,11 +11,12 @@ const Li = styled.li`
`;
interface Props {
+ shown: boolean;
title: string;
}
-const CompletionTitle: React.FC<Props> = ({ title }) => {
- return <Li>{title}</Li>;
-};
+const CompletionTitle: React.FC<React.HTMLAttributes<HTMLElement> & Props> = (
+ props
+) => <Li {...props}>{props.title}</Li>;
export default CompletionTitle;