chore: improve a11y of traffic chart style selection

This commit is contained in:
Haishan 2020-11-21 23:31:14 +08:00
parent 71646e2881
commit 10f6e708e5
5 changed files with 52 additions and 30 deletions

View file

@ -12,7 +12,7 @@ import Button from './Button';
import s0 from './Config.module.css';
import ContentHeader from './ContentHeader';
import Input, { SelfControlledInput } from './Input';
import Selection from './Selection';
import { Selection2 } from './Selection';
import { connect, useStoreActions } from './StateProvider';
import Switch from './SwitchThemed';
import ToggleSwitch from './ToggleSwitch';
@ -243,7 +243,7 @@ function ConfigImpl({
<div className={s0.section}>
<div>
<div className={s0.label}>Chart Style</div>
<Selection
<Selection2
OptionComponent={TrafficChartSample}
optionPropsList={propsList}
selectedIndex={selectedChartStyleIndex}

View file

@ -156,10 +156,20 @@ body.light {
justify-content: center;
}
/* TODO remove fabgrp in component css files */
.fabgrp {
position: fixed;
z-index: 3;
right: 20px;
bottom: 20px;
}
.visually-hidden {
position: absolute;
overflow: hidden;
clip: rect(0 0 0 0);
width: 1px;
height: 1px;
margin: -1px;
border: 0;
padding: 0;
}

View file

@ -1,16 +1,23 @@
.root {
.fieldset {
margin: 0;
padding: 0;
border: 0;
display: flex;
flex-wrap: wrap;
}
.item {
flex-grow: 0;
margin-right: 10px;
margin-bottom: 10px;
.input + .cnt {
border: 1px solid transparent;
border-radius: 8px;
cursor: pointer;
border: 2px solid transparent;
margin-right: 5px;
margin-bottom: 5px;
}
.itemActive {
.input:focus + .cnt {
border-color: #387cec;
}
.input:checked + .cnt {
border-color: #387cec;
}

View file

@ -10,34 +10,37 @@ type SelectionProps = {
onChange?: (...args: any[]) => any;
};
export default function Selection({
export function Selection2({
OptionComponent,
optionPropsList,
selectedIndex,
onChange,
}: SelectionProps) {
const inputCx = cx('visually-hidden', s.input);
const onInputChange = (e: React.ChangeEvent<HTMLInputElement>) => {
onChange(e.target.value);
};
return (
<div className={s.root}>
<fieldset className={s.fieldset}>
{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}
tabIndex={0}
role="menuitem"
onKeyDown={doSelect}
onClick={doSelect}
>
<OptionComponent {...props} />
</div>
<label key={idx}>
<input
type="radio"
checked={selectedIndex === idx}
name="selection"
value={idx}
aria-labelledby={'traffic chart type ' + idx}
onChange={onInputChange}
className={inputCx}
/>
<div className={s.cnt}>
<OptionComponent {...props} />
</div>
</label>
);
})}
</div>
</fieldset>
);
}

View file

@ -123,10 +123,12 @@ export function switchTheme() {
};
}
export function selectChartStyleIndex(selectedChartStyleIndex: number) {
export function selectChartStyleIndex(
selectedChartStyleIndex: number | string
) {
return (dispatch: DispatchFn, getState: GetStateFn) => {
dispatch('appSelectChartStyleIndex', (s) => {
s.app.selectedChartStyleIndex = selectedChartStyleIndex;
s.app.selectedChartStyleIndex = Number(selectedChartStyleIndex);
});
// side effect
saveState(getState().app);