Skip to content

Commit 2a2c536

Browse files
OpeDadamulengawilfredmkumbobeaty
authored
refactor(web): improve ui components accessibility [VIZ-1522] (#1576)
Co-authored-by: mulengawilfred <m.wilfred@eukarya.io> Co-authored-by: Beatrice Mkumbo <charsbeaty@gmail.com>
1 parent be17555 commit 2a2c536

File tree

29 files changed

+357
-80
lines changed

29 files changed

+357
-80
lines changed

web/src/beta/lib/reearth-ui/components/Breadcrumb/index.tsx

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,17 +16,21 @@ export type BreadcrumbProp = {
1616
separator?: ReactNode;
1717
size?: "normal" | "large";
1818
onClick?: (id?: string) => void;
19+
ariaLabel?: string;
20+
dataTestid?: string;
1921
};
2022

2123
export const Breadcrumb: FC<BreadcrumbProp> = ({
2224
items = [],
2325
separator = " / ",
2426
size,
25-
onClick
27+
onClick,
28+
ariaLabel,
29+
dataTestid
2630
}) => {
2731
const theme = useTheme();
2832
return (
29-
<Wrapper>
33+
<Wrapper as="nav" aria-label={ariaLabel} data-testid={dataTestid}>
3034
{items.map((item, index) => (
3135
<ItemWrapper key={index}>
3236
<Item onClick={() => onClick?.(item.id)}>
@@ -37,6 +41,7 @@ export const Breadcrumb: FC<BreadcrumbProp> = ({
3741
icon={item.icon}
3842
size="small"
3943
color={theme.content.weak}
44+
aria-hidden="true"
4045
/>
4146
)}
4247
<Typography
@@ -51,7 +56,9 @@ export const Breadcrumb: FC<BreadcrumbProp> = ({
5156
item.title
5257
)}
5358
</Item>
54-
{index < items.length - 1 && <Separator>{separator}</Separator>}
59+
{index < items.length - 1 && (
60+
<Separator aria-hidden="true">{separator}</Separator>
61+
)}
5562
</ItemWrapper>
5663
))}
5764
</Wrapper>

web/src/beta/lib/reearth-ui/components/Button/index.tsx

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ export type ButtonProps = {
1919
onClick?: (e: MouseEvent<HTMLElement>) => void;
2020
onMouseEnter?: (e: MouseEvent<HTMLElement>) => void;
2121
onMouseLeave?: (e: MouseEvent<HTMLElement>) => void;
22+
ariaLabel?: string;
2223
"data-testid"?: string;
2324
} & Pick<IconProps, "placement" | "tooltipText">;
2425

@@ -40,6 +41,7 @@ export const Button: FC<ButtonProps> = ({
4041
onClick,
4142
onMouseEnter,
4243
onMouseLeave,
44+
ariaLabel,
4345
"data-testid": dataTestId
4446
}) => {
4547
return (
@@ -54,6 +56,7 @@ export const Button: FC<ButtonProps> = ({
5456
onClick={onClick}
5557
onMouseEnter={onMouseEnter}
5658
onMouseLeave={onMouseLeave}
59+
aria-label={iconButton || !title ? ariaLabel : undefined}
5760
data-testid={dataTestId}
5861
>
5962
{icon && (
@@ -62,6 +65,7 @@ export const Button: FC<ButtonProps> = ({
6265
color={iconColor}
6366
tooltipText={tooltipText}
6467
placement={placement}
68+
aria-hidden="true"
6569
/>
6670
)}
6771
{!iconButton && title}

web/src/beta/lib/reearth-ui/components/CheckBox/index.tsx

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,17 @@ export type CheckBoxProps = {
66
value?: boolean;
77
disabled?: boolean;
88
onChange?: (value: boolean) => void;
9+
ariaLabel?: string;
10+
dataTestid?: string;
911
};
1012

11-
export const CheckBox: FC<CheckBoxProps> = ({ value, disabled, onChange }) => {
13+
export const CheckBox: FC<CheckBoxProps> = ({
14+
value,
15+
disabled,
16+
onChange,
17+
ariaLabel,
18+
dataTestid
19+
}) => {
1220
const [isChecked, setIsChecked] = useState(value);
1321

1422
const theme = useTheme();
@@ -30,12 +38,15 @@ export const CheckBox: FC<CheckBoxProps> = ({ value, disabled, onChange }) => {
3038
disabled={disabled}
3139
role="checkbox"
3240
aria-checked={isChecked}
41+
aria-label={ariaLabel}
42+
data-testid={dataTestid}
3343
>
3444
{isChecked && (
3545
<Icon
3646
icon="check"
3747
size="large"
3848
color={disabled ? theme.content.weak : theme.content.main}
49+
aria-hidden="true"
3950
/>
4051
)}
4152
</BoxField>

web/src/beta/lib/reearth-ui/components/ClickAway/index.tsx

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,14 @@ import { FC, ReactNode, useEffect, useRef } from "react";
33
type ClickAwayProps = {
44
children: ReactNode;
55
onClickAway?: () => void;
6+
dataTestid?: string;
67
};
78

8-
export const ClickAway: FC<ClickAwayProps> = ({ children, onClickAway }) => {
9+
export const ClickAway: FC<ClickAwayProps> = ({
10+
children,
11+
onClickAway,
12+
dataTestid
13+
}) => {
914
const containerRef = useRef<HTMLDivElement>(null);
1015

1116
useEffect(() => {
@@ -33,5 +38,9 @@ export const ClickAway: FC<ClickAwayProps> = ({ children, onClickAway }) => {
3338
};
3439
}, [onClickAway]);
3540

36-
return <div ref={containerRef}>{children}</div>;
41+
return (
42+
<div ref={containerRef} data-testid={dataTestid}>
43+
{children}
44+
</div>
45+
);
3746
};

web/src/beta/lib/reearth-ui/components/CodeInput/index.tsx

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ export type CodeInputProps = {
1212
onChange?: (val: string | undefined) => void;
1313
onBlur?: (val: string | undefined) => void;
1414
onMount?: OnMount;
15+
dataTestid?: string;
1516
};
1617

1718
export const CodeInput: FC<CodeInputProps> = ({
@@ -22,7 +23,8 @@ export const CodeInput: FC<CodeInputProps> = ({
2223
height,
2324
onChange,
2425
onBlur,
25-
onMount
26+
onMount,
27+
dataTestid
2628
}) => {
2729
const theme = useTheme();
2830
const t = useT();
@@ -93,7 +95,11 @@ export const CodeInput: FC<CodeInputProps> = ({
9395
}, [value]);
9496

9597
return (
96-
<EditorWrapper isActive={isActive} disabled={disabled}>
98+
<EditorWrapper
99+
isActive={isActive}
100+
disabled={disabled}
101+
data-testid={dataTestid}
102+
>
97103
<MonacoEditor
98104
language={language}
99105
theme="vs-dark"

web/src/beta/lib/reearth-ui/components/Collapse/index.tsx

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@ export type CollapseProps = {
1919
actions?: ReactNode;
2020
children: ReactNode;
2121
onCollapse?: (collapsed: boolean) => void;
22+
dataTestid?: string;
23+
ariaControls?: string;
2224
};
2325

2426
export const Collapse: FC<CollapseProps> = ({
@@ -35,7 +37,9 @@ export const Collapse: FC<CollapseProps> = ({
3537
noShrink,
3638
actions,
3739
children,
38-
onCollapse
40+
onCollapse,
41+
dataTestid,
42+
ariaControls
3943
}) => {
4044
const [isCollapsed, setIsCollapsed] = useState<boolean>(collapsed ?? false);
4145

@@ -50,14 +54,20 @@ export const Collapse: FC<CollapseProps> = ({
5054
}, [disabled, isCollapsed, onCollapse]);
5155

5256
return (
53-
<StyledWrapper isCollapsed={isCollapsed} noShrink={noShrink}>
57+
<StyledWrapper
58+
isCollapsed={isCollapsed}
59+
noShrink={noShrink}
60+
data-testid={dataTestid}
61+
>
5462
<StyledHeader
5563
onClick={handleCollapse}
5664
isCollapsed={isCollapsed}
5765
size={size}
5866
headerBg={headerBg}
5967
iconPosition={iconPosition}
6068
disabled={disabled}
69+
aria-expanded={!isCollapsed}
70+
aria-controls={ariaControls}
6171
>
6272
<TitleWrapper>
6373
<Typography
@@ -75,7 +85,7 @@ export const Collapse: FC<CollapseProps> = ({
7585
{actions}
7686
{!disabled && (
7787
<IconWrapper isCollapsed={isCollapsed} iconPosition={iconPosition}>
78-
<Icon size="small" icon="triangle" />
88+
<Icon size="small" icon="triangle" aria-hidden="true" />
7989
</IconWrapper>
8090
)}
8191
</ActionsWrapper>

web/src/beta/lib/reearth-ui/components/ColorInput/index.tsx

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@ export type ColorInputProps = {
1919
alphaDisabled?: boolean;
2020
appearance?: "readonly" | undefined;
2121
onChange?: (text: string) => void;
22+
ariaLabel?: string;
23+
dataTestid?: string;
2224
};
2325

2426
const DEFAULT_PANEL_OFFSET = 4;
@@ -29,7 +31,9 @@ export const ColorInput: FC<ColorInputProps> = ({
2931
size = "normal",
3032
alphaDisabled,
3133
appearance,
32-
onChange
34+
onChange,
35+
ariaLabel,
36+
dataTestid
3337
}) => {
3438
const {
3539
open,
@@ -52,7 +56,7 @@ export const ColorInput: FC<ColorInputProps> = ({
5256
const t = useT();
5357

5458
return (
55-
<InputWrapper>
59+
<InputWrapper data-testid={dataTestid}>
5660
<Popup
5761
open={open}
5862
placement="bottom"
@@ -66,6 +70,8 @@ export const ColorInput: FC<ColorInputProps> = ({
6670
status={isSwatchFocused}
6771
size={size}
6872
disabled={disabled}
73+
aria-label={ariaLabel}
74+
aria-valuetext={colorValue}
6975
data-testid="color-input-swatch"
7076
/>
7177
}
@@ -91,7 +97,7 @@ export const ColorInput: FC<ColorInputProps> = ({
9197
</ActionsWrapper>
9298
}
9399
>
94-
<ColorPickerWrapper>
100+
<ColorPickerWrapper role="application">
95101
<ColorPicker
96102
className="colorPicker"
97103
alphaDisabled={alphaDisabled}

web/src/beta/lib/reearth-ui/components/DatePicker/index.tsx

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,19 @@ export type DatePickerProps = {
77
size?: "normal" | "small";
88
onChange?: (text: string) => void;
99
onBlur?: (text: string) => void;
10+
ariaLabel?: string;
11+
dataTestid?: string;
12+
title?: string;
1013
};
1114

1215
export const DatePicker: FC<DatePickerProps> = ({
1316
value,
1417
disabled,
1518
onChange,
16-
onBlur
19+
onBlur,
20+
ariaLabel,
21+
dataTestid,
22+
title
1723
}) => {
1824
const [currentValue, setCurrentValue] = useState(value ?? "");
1925
const [isFocused, setIsFocused] = useState(false);
@@ -41,14 +47,20 @@ export const DatePicker: FC<DatePickerProps> = ({
4147
}, []);
4248

4349
return (
44-
<Wrapper status={isFocused ? "active" : "default"}>
50+
<Wrapper
51+
status={isFocused ? "active" : "default"}
52+
role="application"
53+
data-testid={dataTestid}
54+
>
4555
<StyledInput
4656
value={currentValue}
4757
disabled={disabled}
4858
onChange={handleChange}
4959
onBlur={handleBlur}
5060
onFocus={handleFocus}
5161
type="date"
62+
aria-label={ariaLabel}
63+
title={title}
5264
data-testid="date-picker-input"
5365
/>
5466
</Wrapper>

web/src/beta/lib/reearth-ui/components/DragAndDropList/index.tsx

Lines changed: 31 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@ export interface DragAndDropListProps<T extends ItemInterface> {
2020
dragDisabled?: boolean;
2121
onMoveStart?: () => void;
2222
onMoveEnd?: (itemId?: string, newIndex?: number) => void;
23+
ariaLabel?: string;
24+
dataTestid?: string;
2325
}
2426

2527
const GHOST_CLASSNAME = "reearth-visualizer-dnd-ghost";
@@ -34,7 +36,9 @@ export const DragAndDropList = <T extends ItemInterface>({
3436
gap = "small",
3537
dragDisabled,
3638
onMoveStart,
37-
onMoveEnd
39+
onMoveEnd,
40+
ariaLabel,
41+
dataTestid
3842
}: DragAndDropListProps<T>) => {
3943
const handleSetList = (
4044
newState: ItemInterface[],
@@ -56,28 +60,32 @@ export const DragAndDropList = <T extends ItemInterface>({
5660
);
5761

5862
return (
59-
<StyledReactSortable
60-
list={items}
61-
setList={handleSetList}
62-
group={group}
63-
className={className}
64-
gap={gap}
65-
handle={handleClassName ? `.${handleClassName}` : undefined}
66-
animation={150}
67-
ghostClass={GHOST_CLASSNAME}
68-
filter={`.${NO_DRAG_CLASSNAME}`}
69-
onStart={handleStart}
70-
onEnd={handleEnd}
71-
>
72-
{items?.map((item) => (
73-
<ItemWrapper
74-
key={item.id}
75-
className={dragDisabled ? NO_DRAG_CLASSNAME : ""}
76-
>
77-
{item.content}
78-
</ItemWrapper>
79-
))}
80-
</StyledReactSortable>
63+
<div role="list" aria-label={ariaLabel} data-testid={dataTestid}>
64+
<StyledReactSortable
65+
list={items}
66+
setList={handleSetList}
67+
group={group}
68+
className={className}
69+
gap={gap}
70+
handle={handleClassName ? `.${handleClassName}` : undefined}
71+
animation={150}
72+
ghostClass={GHOST_CLASSNAME}
73+
filter={`.${NO_DRAG_CLASSNAME}`}
74+
onStart={handleStart}
75+
onEnd={handleEnd}
76+
>
77+
{items?.map((item, index) => (
78+
<ItemWrapper
79+
key={item.id}
80+
className={dragDisabled ? NO_DRAG_CLASSNAME : ""}
81+
role="listitem"
82+
data-testid={dataTestid && `${dataTestid}-${index}`}
83+
>
84+
{item.content}
85+
</ItemWrapper>
86+
))}
87+
</StyledReactSortable>
88+
</div>
8189
);
8290
};
8391

web/src/beta/lib/reearth-ui/components/Icon/index.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ export const Icon: FC<IconProps> = ({
5151
color={color}
5252
className={className}
5353
aria-label={ariaLabel}
54+
aria-hidden={!ariaLabel ? "true" : undefined}
5455
/>
5556
) : null;
5657

0 commit comments

Comments
 (0)