refactor: improve a11y
This commit is contained in:
parent
941224c13b
commit
2c9ee574dd
12 changed files with 111 additions and 45 deletions
|
@ -4,14 +4,16 @@ parserOptions:
|
|||
project: tsconfig.json
|
||||
sourceType: module
|
||||
|
||||
plugins:
|
||||
- simple-import-sort
|
||||
- jsx-a11y
|
||||
|
||||
extends:
|
||||
- 'plugin:@typescript-eslint/recommended'
|
||||
- 'prettier'
|
||||
- prettier/@typescript-eslint
|
||||
- react-app
|
||||
|
||||
plugins:
|
||||
- simple-import-sort
|
||||
- 'plugin:jsx-a11y/recommended'
|
||||
|
||||
env:
|
||||
node: true
|
||||
|
|
|
@ -78,6 +78,7 @@ function APIConfig({ apiConfig, dispatch }) {
|
|||
);
|
||||
|
||||
return (
|
||||
// eslint-disable-next-line jsx-a11y/no-static-element-interactions
|
||||
<div className={s0.root} ref={contentEl} onKeyDown={handleContentOnKeyDown}>
|
||||
<div className={s0.header}>
|
||||
<div className={s0.icon}>
|
||||
|
|
|
@ -2,10 +2,15 @@
|
|||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
&:focus {
|
||||
outline: none;
|
||||
}
|
||||
|
||||
.arrow {
|
||||
display: inline-flex;
|
||||
transform: rotate(0deg);
|
||||
transition: transform 0.3s;
|
||||
|
||||
&.isOpen {
|
||||
transform: rotate(180deg);
|
||||
}
|
||||
|
|
|
@ -1,23 +1,40 @@
|
|||
import cx from 'clsx';
|
||||
import React from 'react';
|
||||
import * as React from 'react';
|
||||
import { ChevronDown } from 'react-feather';
|
||||
|
||||
import { keyCodes } from '../misc/keycode';
|
||||
import Button from './Button';
|
||||
import s from './CollapsibleSectionHeader.module.css';
|
||||
import { SectionNameType } from './shared/Basic';
|
||||
|
||||
type Props = {
|
||||
name: string,
|
||||
type: string,
|
||||
qty?: number,
|
||||
toggle?: () => void,
|
||||
isOpen?: boolean,
|
||||
name: string;
|
||||
type: string;
|
||||
qty?: number;
|
||||
toggle?: () => void;
|
||||
isOpen?: boolean;
|
||||
};
|
||||
|
||||
export default function Header({ name, type, toggle, isOpen, qty }: Props) {
|
||||
const handleKeyDown = React.useCallback(
|
||||
(e: React.KeyboardEvent) => {
|
||||
e.preventDefault();
|
||||
if (e.keyCode === keyCodes.Enter || e.keyCode === keyCodes.Space) {
|
||||
toggle();
|
||||
}
|
||||
},
|
||||
[toggle]
|
||||
);
|
||||
return (
|
||||
<div className={s.header}>
|
||||
<div onClick={toggle} style={{ cursor: 'pointer' }}>
|
||||
<div
|
||||
className={s.header}
|
||||
onClick={toggle}
|
||||
style={{ cursor: 'pointer' }}
|
||||
tabIndex={0}
|
||||
onKeyDown={handleKeyDown}
|
||||
role="button"
|
||||
>
|
||||
<div>
|
||||
<SectionNameType name={name} type={type} />
|
||||
</div>
|
||||
|
|
@ -11,21 +11,21 @@ export default function Selection({
|
|||
onChange,
|
||||
}) {
|
||||
return (
|
||||
// TODO a11y
|
||||
// tabIndex="0"
|
||||
<div className={s.root}>
|
||||
{optionPropsList.map((props, idx) => {
|
||||
const className = cx(s.item, { [s.itemActive]: idx === selectedIndex });
|
||||
const doSelect = (ev) => {
|
||||
ev.preventDefault();
|
||||
if (idx !== selectedIndex) onChange(idx);
|
||||
};
|
||||
return (
|
||||
<div
|
||||
key={idx}
|
||||
className={className}
|
||||
onClick={(ev) => {
|
||||
ev.preventDefault();
|
||||
if (idx !== selectedIndex) {
|
||||
onChange(idx);
|
||||
}
|
||||
}}
|
||||
tabIndex={0}
|
||||
role="menuitem"
|
||||
onKeyDown={doSelect}
|
||||
onClick={doSelect}
|
||||
>
|
||||
<OptionComponent {...props} />
|
||||
</div>
|
||||
|
|
|
@ -90,6 +90,7 @@
|
|||
justify-content: center;
|
||||
align-items: center;
|
||||
|
||||
outline: none;
|
||||
padding: 5px;
|
||||
color: var(--color-text);
|
||||
border-radius: 100%;
|
||||
|
@ -104,7 +105,6 @@
|
|||
|
||||
.themeSwitchContainer {
|
||||
appearance: none;
|
||||
outline: none;
|
||||
user-select: none;
|
||||
background: none;
|
||||
cursor: pointer;
|
||||
|
|
|
@ -29,6 +29,7 @@ export function ClosePrevConns({
|
|||
};
|
||||
|
||||
return (
|
||||
// eslint-disable-next-line jsx-a11y/no-static-element-interactions
|
||||
<div onKeyDown={handleKeyDown}>
|
||||
<h2>Close Connections?</h2>
|
||||
<p>
|
||||
|
|
|
@ -9,6 +9,12 @@
|
|||
flex-direction: column;
|
||||
justify-content: space-between;
|
||||
|
||||
outline: none;
|
||||
border: 1px solid transparent;
|
||||
&:focus {
|
||||
border: 1px solid var(--color-focus-blue);
|
||||
}
|
||||
|
||||
max-width: 280px;
|
||||
@media (--breakpoint-not-small) {
|
||||
min-width: 200px;
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
import cx from 'clsx';
|
||||
import * as React from 'react';
|
||||
import { keyCodes } from 'src/misc/keycode';
|
||||
|
||||
import { getDelay, getProxies, NonProxyTypes } from '../../store/proxies';
|
||||
import { connect } from '../StateProvider';
|
||||
|
@ -76,17 +77,35 @@ function ProxySmallImpl({
|
|||
}
|
||||
return ret;
|
||||
}, [name, latency]);
|
||||
|
||||
const doSelect = React.useCallback(() => {
|
||||
isSelectable && onClick && onClick(name);
|
||||
}, [name, onClick, isSelectable]);
|
||||
|
||||
const className = useMemo(() => {
|
||||
return cx(s0.proxySmall, {
|
||||
[s0.now]: now,
|
||||
[s0.selectable]: isSelectable,
|
||||
});
|
||||
}, [isSelectable, now]);
|
||||
|
||||
const handleKeyDown = React.useCallback(
|
||||
(e: React.KeyboardEvent) => {
|
||||
if (e.keyCode === keyCodes.Enter) {
|
||||
doSelect();
|
||||
}
|
||||
},
|
||||
[doSelect]
|
||||
);
|
||||
|
||||
return (
|
||||
<div
|
||||
title={title}
|
||||
className={cx(s0.proxySmall, {
|
||||
[s0.now]: now,
|
||||
[s0.selectable]: isSelectable,
|
||||
})}
|
||||
className={className}
|
||||
style={{ background: color }}
|
||||
onClick={() => {
|
||||
isSelectable && onClick && onClick(name);
|
||||
}}
|
||||
onClick={doSelect}
|
||||
onKeyDown={handleKeyDown}
|
||||
role={isSelectable ? 'menuitem' : ''}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
@ -100,16 +119,32 @@ function ProxyImpl({
|
|||
onClick,
|
||||
}: ProxyProps) {
|
||||
const color = useMemo(() => getLabelColor(latency), [latency]);
|
||||
const doSelect = React.useCallback(() => {
|
||||
isSelectable && onClick && onClick(name);
|
||||
}, [name, onClick, isSelectable]);
|
||||
const handleKeyDown = React.useCallback(
|
||||
(e: React.KeyboardEvent) => {
|
||||
if (e.keyCode === keyCodes.Enter) {
|
||||
doSelect();
|
||||
}
|
||||
},
|
||||
[doSelect]
|
||||
);
|
||||
const className = useMemo(() => {
|
||||
return cx(s0.proxy, {
|
||||
[s0.now]: now,
|
||||
[s0.error]: latency && latency.error,
|
||||
[s0.selectable]: isSelectable,
|
||||
});
|
||||
}, [isSelectable, now, latency]);
|
||||
|
||||
return (
|
||||
<div
|
||||
className={cx(s0.proxy, {
|
||||
[s0.now]: now,
|
||||
[s0.error]: latency && latency.error,
|
||||
[s0.selectable]: isSelectable,
|
||||
})}
|
||||
onClick={() => {
|
||||
isSelectable && onClick && onClick(name);
|
||||
}}
|
||||
tabIndex={0}
|
||||
className={className}
|
||||
onClick={doSelect}
|
||||
onKeyDown={handleKeyDown}
|
||||
role={isSelectable ? 'menuitem' : ''}
|
||||
>
|
||||
<div className={s0.proxyName}>{name}</div>
|
||||
<div className={s0.row}>
|
||||
|
|
|
@ -10,6 +10,7 @@ type Props = {
|
|||
|
||||
export default function Select({ options, selected, onChange }: Props) {
|
||||
return (
|
||||
// eslint-disable-next-line jsx-a11y/no-onchange
|
||||
<select className={s.select} value={selected} onChange={onChange}>
|
||||
{options.map(([value, name]) => (
|
||||
<option key={value} value={value}>
|
||||
|
|
6
src/misc/keycode.ts
Normal file
6
src/misc/keycode.ts
Normal file
|
@ -0,0 +1,6 @@
|
|||
export const keyCodes = {
|
||||
Right: 39,
|
||||
Left: 37,
|
||||
Enter: 13,
|
||||
Space: 32,
|
||||
};
|
|
@ -102,14 +102,6 @@ module.exports = {
|
|||
},
|
||||
module: {
|
||||
rules: [
|
||||
// {
|
||||
// test: /\.tsx?$/,
|
||||
// loader: 'ts-loader',
|
||||
// options: {
|
||||
// // disable type checker - we will use it in fork plugin
|
||||
// transpileOnly: true,
|
||||
// },
|
||||
// },
|
||||
{
|
||||
test: /\.[tj]sx?$/,
|
||||
exclude: /node_modules/,
|
||||
|
@ -126,7 +118,7 @@ module.exports = {
|
|||
isDev ? { loader: 'style-loader' } : MiniCssExtractPlugin.loader,
|
||||
{ loader: 'css-loader' },
|
||||
{ loader: 'postcss-loader', options: { plugins: postcssPlugins } },
|
||||
].filter(Boolean),
|
||||
],
|
||||
},
|
||||
{
|
||||
test: /\.module\.css$/,
|
||||
|
@ -146,7 +138,7 @@ module.exports = {
|
|||
loader: 'postcss-loader',
|
||||
options: { plugins: postcssPlugins },
|
||||
},
|
||||
].filter(Boolean),
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
|
|
Loading…
Reference in a new issue