Skip to content

Commit

Permalink
ADA Accessibility (#370)
Browse files Browse the repository at this point in the history
* Update segment control and layer toggles for ADA accessibility

* nits

* class table spacing nit

* revert classtable change

* Updates color contrast for light text, vertically justifies infor status

* Layer toggle spacing nit

* Adds aria labels, simplifies storybook library stories, adds ErrorStatus component, fixes z-index of dropdown

* Present simplebutton as single component, adds aria-labels and roles, reformats to eslint standards,

* Adjust status component formatting

* Update status formatting
  • Loading branch information
avmey authored Dec 6, 2024
1 parent 74a9813 commit cbbed01
Show file tree
Hide file tree
Showing 40 changed files with 465 additions and 371 deletions.
8 changes: 6 additions & 2 deletions packages/geoprocessing/src/components/Card.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -34,9 +34,13 @@ export const Card = ({
};

return (
<div style={{ position: "relative", ...styles.box, ...style }}>
<div
role="region"
aria-label={typeof title === "string" ? title : "Report"}
style={{ position: "relative", ...styles.box, ...style }}
>
{title && title !== "" && (
<div style={{ ...styles.title, ...titleStyle }}>{title}</div>
<h1 style={{ ...styles.title, ...titleStyle }}>{title}</h1>
)}
{children}
</div>
Expand Down
2 changes: 1 addition & 1 deletion packages/geoprocessing/src/components/Circle.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ const groupColorMap = {
low: "#F7A6B4",
};

export const simple = () => (
export const circle = () => (
<Card>
<div>
<Circle>S</Circle>
Expand Down
21 changes: 18 additions & 3 deletions packages/geoprocessing/src/components/Circle.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ interface StyledCircleProps {

/** Default style for Circle */
export const StyledCircle = styled.span<StyledCircleProps>`
background-color: ${(props) => (props.color ? props.color : "#DDD")};
background-color: ${(props) => props.color || "#DDD"};
padding: 3px 5px;
border-radius: ${(props) => (props.size ? `${props.size}px` : "17px")};
min-width: ${(props) => (props.size ? `${props.size}px` : "17px")};
Expand All @@ -23,16 +23,24 @@ export interface CircleProps {
children: ReactNode;
color?: string;
size?: number;
ariaLabel?: string;
}

/** Circle with user-defined component inside */
export const Circle: React.FunctionComponent<CircleProps> = ({
children,
color,
size,
ariaLabel,
}) => {
return (
<StyledCircle color={color} size={size}>
<StyledCircle
color={color}
size={size}
aria-label={
ariaLabel || `Circle highlighted with ${color || "#DDD"} color`
}
>
{children}
</StyledCircle>
);
Expand All @@ -57,5 +65,12 @@ export const GroupCircle: React.FunctionComponent<GroupCircleProps> = ({
group,
groupColorMap,
}) => {
return <Circle color={groupColorMap[group]}>{children}</Circle>;
return (
<Circle
color={groupColorMap[group]}
ariaLabel={`Circle highlighted with group ${group} color ${groupColorMap[group]}`}
>
{children}
</Circle>
);
};
2 changes: 1 addition & 1 deletion packages/geoprocessing/src/components/Collapse.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ export default {
decorators: [ReportDecorator],
};

export const text = () => (
export const collapse = () => (
<Card title="Card Title">
<Collapse title="Learn more">Help text here</Collapse>
</Card>
Expand Down
62 changes: 27 additions & 35 deletions packages/geoprocessing/src/components/Collapse.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { CaretDownFill, CaretRightFill } from "@styled-icons/bootstrap";
import React, { ReactNode } from "react";
import { styled } from "styled-components";

Expand All @@ -14,34 +15,17 @@ const StyledCollapse = styled.div`
height: 20px;
}
.collapse-icon-container {
margin-left: -3px;
}
.collapse-icon-button {
display: block;
border: 0;
margin-bottom: 10px;
padding-left: 0px;
background-color: transparent;
font-size: 15px;
height: 20px;
width: 25px;
color: #777;
cursor: pointer;
}
.collapse-text-button {
display: block;
.collapse-button {
display: flex;
align-items: center;
border: 0;
margin-bottom: 10px;
padding-left: 0px;
background-color: transparent;
font-size: 15px;
height: 20px;
font-weight: bold;
color: #777;
color: #767676;
cursor: pointer;
padding: 0;
margin-bottom: 10px;
}
.collapse-content {
Expand All @@ -56,7 +40,7 @@ const StyledCollapse = styled.div`
display: none;
}
.collapsed-content.expanded {
.collapse-content.expanded {
display: block;
}
`;
Expand All @@ -69,26 +53,34 @@ export const Collapse: React.FunctionComponent<CollapseProps> = ({
const [isCollapsed, setIsCollapsed] = React.useState(collapsed);

return (
<StyledCollapse>
<StyledCollapse
aria-label={isCollapsed ? `Expand ${title}` : `Collapse ${title}`}
aria-expanded={!isCollapsed}
role="button"
>
<div className="collapse-header">
<div className="collapse-icon-container">
<button
className="collapse-icon-button"
onClick={() => setIsCollapsed(!isCollapsed)}
>
{isCollapsed ? "▶" : "▼"}
</button>
</div>
<button
className="collapse-text-button"
className="collapse-button"
onClick={() => setIsCollapsed(!isCollapsed)}
>
{isCollapsed ? (
<CaretRightFill
size={15}
style={{ marginRight: "5px" }}
aria-hidden="true"
/>
) : (
<CaretDownFill
size={15}
style={{ marginRight: "5px" }}
aria-hidden="true"
/>
)}{" "}
{title}
</button>
</div>
<div
className={`collapse-content ${isCollapsed ? "collapsed" : "expanded"}`}
aria-expanded={isCollapsed}
>
{children}
</div>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
import React from "react";
import DataDownload from "./DataDownload.js";
import fixtures from "../testing/fixtures/index.js";
import { SimpleButton } from "./buttons/SimpleButton.js";
import { SimpleButton } from "./SimpleButton.js";
import ReportDecorator from "./storybook/ReportDecorator.js";

export default {
component: DataDownload,
title: "Components/DataDownload",
decorators: [],
decorators: [ReportDecorator],
};

export const simple = () => {
Expand Down
8 changes: 2 additions & 6 deletions packages/geoprocessing/src/components/DataDownload.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import React, { useEffect, useState } from "react";
import Dropdown, { DropdownProps } from "./Dropdown.js";
import { SimpleButtonStyled } from "./buttons/SimpleButton.js";
import { SimpleButtonStyled } from "./SimpleButton.js";
import { styled } from "styled-components";
import { Parser, transforms } from "json2csv";
import useSketchProperties from "../hooks/useSketchProperties.js";
Expand Down Expand Up @@ -139,11 +139,7 @@ export const DataDownload = ({
...dropdownProps,
};

return (
<>
<Dropdown {...dropdownPropsMerged}>{links}</Dropdown>
</>
);
return <Dropdown {...dropdownPropsMerged}>{links}</Dropdown>;
};

export default DataDownload;
18 changes: 11 additions & 7 deletions packages/geoprocessing/src/components/Dropdown.stories.tsx
Original file line number Diff line number Diff line change
@@ -1,19 +1,23 @@
import React from "react";
import Card from "./Card.js";
import { SimpleButton } from "./buttons/SimpleButton.js";
import { SimpleButton } from "./SimpleButton.js";
import Dropdown from "./Dropdown.js";
import ReportDecorator from "./storybook/ReportDecorator.js";
import { ThreeDotsVertical } from "@styled-icons/bootstrap";

export default {
component: Card,
component: Dropdown,
title: "Components/Dropdown",
decorators: [],
decorators: [ReportDecorator],
};

export const simpleButton = () => {
export const dropdown = () => {
return (
<Dropdown titleElement={<></>}>
<Dropdown titleElement={<ThreeDotsVertical size={18} color="#999" />}>
<a href="https://seasketch.org" target="_blank" rel="noreferrer">
<SimpleButton>➥ Seasketch</SimpleButton>
<SimpleButton>➥ Item 1</SimpleButton>
</a>
<a href="https://seasketch.org" target="_blank" rel="noreferrer">
<SimpleButton>➥ Item 2</SimpleButton>
</a>
</Dropdown>
);
Expand Down
34 changes: 21 additions & 13 deletions packages/geoprocessing/src/components/Dropdown.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -58,10 +58,11 @@ export const DropdownTrigger = styled.button`
border: none;
background: none;
font-family: sans-serif;
cursor: pointer;
`;

export const Dropdown = ({
titleElement: TitleElement = <></>,
titleElement = <></>,
placement = "auto",
offset = { horizontal: 0, vertical: 0 },
children,
Expand Down Expand Up @@ -101,25 +102,32 @@ export const Dropdown = ({
}

return (
<React.StrictMode>
<div ref={DropownRef}>
<DropdownTrigger
type="button"
ref={referenceRef}
onClick={handleDropdownClick}
<div ref={DropownRef} aria-label="Dropdown">
<DropdownTrigger
ref={referenceRef}
onClick={handleDropdownClick}
aria-label={`${open ? "Close" : "Open"} dropdown menu`}
aria-expanded={open}
>
{titleElement}
</DropdownTrigger>
<div
ref={popperRef}
style={{ zIndex: 1000, ...styles.popper }}
{...attributes.popper}
>
<DropdownContainer
style={styles.offset}
open={open}
aria-label="Dropdown Menu"
>
{TitleElement}
</DropdownTrigger>
</div>
<div ref={popperRef} style={styles.popper} {...attributes.popper}>
<DropdownContainer style={styles.offset} open={open}>
{children &&
React.Children.map(children, (child) => {
return <DropdownItem>{child}</DropdownItem>;
})}
</DropdownContainer>
</div>
</React.StrictMode>
</div>
);
};

Expand Down
19 changes: 19 additions & 0 deletions packages/geoprocessing/src/components/ErrorStatus.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import React from "react";
import Card from "./Card.js";
import { ErrorStatus } from "./ErrorStatus.js";
import ReportDecorator from "./storybook/ReportDecorator.js";

export default {
component: ErrorStatus,
title: "Components/ErrorStatus",
decorators: [ReportDecorator],
};

export const errorStatus = () => (
<Card>
<ErrorStatus
size={32}
msg={<>Your sketch falls outside of project boundaries</>}
/>
</Card>
);
29 changes: 29 additions & 0 deletions packages/geoprocessing/src/components/ErrorStatus.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import React from "react";
import { ExclamationCircleFill } from "@styled-icons/bootstrap";

export interface ErrorStatusProps {
msg: JSX.Element;
size?: number;
style?: React.HTMLAttributes<HTMLElement>["style"];
}

export const ErrorStatus: React.FunctionComponent<ErrorStatusProps> = ({
msg,
size = 36,
style = {},
}) => {
return (
<div
style={{ display: "flex", alignItems: "center" }}
aria-label="Error"
role="status"
>
<ExclamationCircleFill
size={size}
style={{ color: "#ea4848", paddingRight: 10, flexShrink: 0, ...style }}
aria-label="Error icon"
/>
<div aria-label="Error message">{msg}</div>
</div>
);
};
Loading

0 comments on commit cbbed01

Please sign in to comment.