Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Keyboard accessibility improvements in Widgets and DS components #835

Merged
merged 19 commits into from
Feb 13, 2024
Merged
Show file tree
Hide file tree
Changes from 16 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

## Not released

- Keyboard accessibility improvements in Widgets and DS components [#835](https://github.com/CartoDB/carto-react/pull/835)

## 2.3

### 2.3.10 (2024-01-31)
Expand Down
4 changes: 4 additions & 0 deletions packages/react-ui/src/localization/en.js
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,10 @@ const locales = {
clear: 'Clear',
selectedItems: '{items, plural, one{# selected} other{# selected}}',
allSelected: 'All'
},
chartLegend: {
next: 'Next page',
prev: 'Previous page'
}
}
}
Expand Down
4 changes: 4 additions & 0 deletions packages/react-ui/src/localization/es.js
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,10 @@ const locales = {
clear: 'Limpiar',
selectedItems: '{items, plural, one {# seleccionado} other {# seleccionados}}',
allSelected: 'Todos seleccionados'
},
chartLegend: {
next: 'Página siguente',
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

typo

Suggested change
next: 'Página siguente',
next: 'Página siguiente',

prev: 'Página anterior'
}
}
}
Expand Down
4 changes: 4 additions & 0 deletions packages/react-ui/src/localization/id.js
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,10 @@ const locales = {
clear: 'Bersihkan',
selectedItems: '{items, plural, one{# terpilih} other{# terpilih}}',
allSelected: 'Semua terpilih'
},
chartLegend: {
next: 'Next page',
prev: 'Previous page'
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,12 @@ export const dataDisplayOverrides = {
}
}
}
},

'& .MuiListItemButton-root': {
'&:focus-visible': {
backgroundColor: 'transparent'
}
}
})
}
Expand Down
33 changes: 29 additions & 4 deletions packages/react-ui/src/theme/sections/components/forms.js
Original file line number Diff line number Diff line change
Expand Up @@ -194,6 +194,19 @@ export const formsOverrides = {
},
'&.Mui-disabled::placeholder': {
color: theme.palette.text.disabled
},
// Remove focus on keyboard navigation as the parent element has focus
'&:focus-visible': {
outline: 'none !important',
boxShadow: 'none !important'
}
},

'&.Mui-disabled': {
cursor: 'not-allowed',

'& .Mui-disabled': {
cursor: 'not-allowed'
}
},

Expand Down Expand Up @@ -332,6 +345,11 @@ export const formsOverrides = {
},
'&.Mui-disabled::placeholder': {
color: theme.palette.text.disabled
},
// Remove focus on keyboard navigation as the parent element has focus
'&:focus-visible': {
outline: 'none !important',
boxShadow: 'none !important'
}
},

Expand Down Expand Up @@ -513,6 +531,12 @@ export const formsOverrides = {
'&:focus': {
background: 'transparent'
},
// Remove focus on keyboard navigation as the parent element has focus
'&:focus-visible': {
outline: 'none !important',
boxShadow: 'none !important'
},

'& .MuiTypography-root': {
whiteSpace: 'nowrap',
overflow: 'hidden',
Expand All @@ -532,13 +556,10 @@ export const formsOverrides = {
size: 'small',
fullWidth: true,
popupIcon: <ArrowDropIcon />,
clearIcon: <CancelIcon />,
clearIcon: <CancelIcon date-testid='cancel-icon-autocomplete' />,
ChipProps: { color: 'default' },
limitTags: 1,
componentsProps: {
popupIndicator: {
disabled: true
},
paper: {
elevation: 8
}
Expand Down Expand Up @@ -631,7 +652,11 @@ export const formsOverrides = {
popupIndicator: ({ theme }) => ({
width: ICON_SIZE_MEDIUM,
height: ICON_SIZE_MEDIUM,
cursor: 'text',

'&:hover': {
backgroundColor: 'transparent'
},
'&.MuiButtonBase-root': {
color: theme.palette.text.secondary
},
Expand Down
10 changes: 9 additions & 1 deletion packages/react-ui/src/theme/sections/components/navigation.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { ICON_SIZE_MEDIUM } from '../../themeConstants';

export const navigationOverrides = {
// Menu
// Menu Item
MuiMenuItem: {
styleOverrides: {
root: ({ theme }) => ({
Expand All @@ -19,6 +19,9 @@ export const navigationOverrides = {
'&:focus-visible': {
// Solves a known Mui issue: https://github.com/mui/material-ui/issues/23747
backgroundColor: 'transparent',
outline: `none !important`,
boxShadow: ` inset 0 0 0 2px ${theme.palette.primary.main} !important`,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why an empty space at the beginning? Is it required?

borderRadius: theme.shape.borderRadius,

'&:hover': {
backgroundColor: theme.palette.action.hover
Expand Down Expand Up @@ -107,6 +110,11 @@ export const navigationOverrides = {
'&:hover': {
borderBottomColor: theme.palette.text.primary
},
'&:focus-visible': {
outline: `none !important`,
boxShadow: ` inset 0 0 0 2px ${theme.palette.primary.main} !important`,
borderRadius: `${theme.shape.borderRadius}px ${theme.shape.borderRadius}px 0 0`
},
'&.Mui-selected': {
pointerEvents: 'none',

Expand Down
4 changes: 4 additions & 0 deletions packages/react-ui/src/theme/sections/components/surfaces.js
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,10 @@ export const surfacesOverrides = {
'&.Mui-disabled': {
opacity: 1,
color: theme.palette.text.disabled
},
'&.Mui-focusVisible': {
backgroundColor: 'transparent',
borderRadius: theme.shape.borderRadius
}
}),
expandIconWrapper: ({ theme }) => ({
Expand Down
7 changes: 7 additions & 0 deletions packages/react-ui/src/theme/sections/cssBaseline.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,13 @@ import { commonPalette } from './palette';
import { themeTypography } from './typography';

export const CssBaseline = {
// Accessibility focus (keyboard only)
'*:focus-visible': {
outline: `2px solid ${commonPalette.primary.main} !important`,
boxShadow: `0 0 0 4px ${commonPalette.primary.background} !important`,
borderRadius: '4px'
},

// Custom scrollbars
'*::-webkit-scrollbar': {
position: 'fixed'
Expand Down
12 changes: 11 additions & 1 deletion packages/react-ui/src/widgets/BarWidgetUI/BarWidgetUI.js
Original file line number Diff line number Diff line change
Expand Up @@ -248,6 +248,11 @@ function BarWidgetUI(props) {
onSelectedBarsChange([], []);
}
};
const handleClearPress = (e) => {
if (e.key === 'Enter') {
clearBars();
}
};

const clickEvent = useCallback(
(params) => {
Expand Down Expand Up @@ -311,7 +316,12 @@ function BarWidgetUI(props) {
: intlConfig.formatMessage({ id: 'c4r.widgets.bar.all' })}
</Typography>
{selectedBars && selectedBars.length > 0 && (
<SelectAllButton onClick={() => clearBars()} underline='hover'>
<SelectAllButton
onClick={() => clearBars()}
onKeyDown={handleClearPress}
underline='hover'
tabIndex={0}
>
{intlConfig.formatMessage({ id: 'c4r.widgets.bar.clear' })}
</SelectAllButton>
)}
Expand Down
64 changes: 59 additions & 5 deletions packages/react-ui/src/widgets/CategoryWidgetUI/CategoryWidgetUI.js
Original file line number Diff line number Diff line change
Expand Up @@ -92,15 +92,30 @@ function CategoryWidgetUI(props) {
const handleClearClicked = () => {
props.onSelectedCategoriesChange([]);
};
const handleClearPress = (e) => {
if (e.key === 'Enter') {
handleClearClicked();
}
};

const handleUnblockClicked = () => {
props.onSelectedCategoriesChange([]);
setBlockedCategories([]);
};
const handleUnblockPress = (e) => {
if (e.key === 'Enter') {
handleUnblockClicked();
}
};

const handleBlockClicked = () => {
setBlockedCategories(sortBlockedSameAsData(selectedCategories));
};
const handleBlockPress = (e) => {
if (e.key === 'Enter') {
handleBlockClicked();
}
};

const handleApplyClicked = () => {
const blockedCategoriesOrdered = sortBlockedSameAsData(tempBlockedCategories);
Expand All @@ -111,6 +126,11 @@ function CategoryWidgetUI(props) {
setShowAll(false);
setSearchValue('');
};
const handleApplyPress = (e) => {
if (e.key === 'Enter') {
handleApplyClicked();
}
};

const handleCancelClicked = () => {
setSearchValue('');
Expand Down Expand Up @@ -303,6 +323,12 @@ function CategoryWidgetUI(props) {
};
}, []);

const handleCategoryPress = (e) => {
if (e.key === 'Enter') {
onCategoryClick();
}
};

const unselected =
!showAll &&
selectedCategories.length > 0 &&
Expand All @@ -313,13 +339,18 @@ function CategoryWidgetUI(props) {
direction='row'
spacing={1}
onClick={filterable ? onCategoryClick : () => {}}
onKeyDown={handleCategoryPress}
selectable={filterable}
unselected={unselected}
name={data.name === REST_CATEGORY ? REST_CATEGORY : ''}
tabIndex={filterable && showAll ? 0 : -1}
>
{filterable && showAll && (
<Grid item>
<Checkbox checked={tempBlockedCategories.indexOf(data.name) !== -1} />
<Checkbox
checked={tempBlockedCategories.indexOf(data.name) !== -1}
tabIndex={-1}
/>
</Grid>
)}
<Grid container item xs>
Expand Down Expand Up @@ -371,21 +402,41 @@ function CategoryWidgetUI(props) {
: intlConfig.formatMessage({ id: 'c4r.widgets.category.all' })}
</Typography>
{showAll ? (
<LinkAsButton onClick={handleApplyClicked} underline='hover'>
<LinkAsButton
onClick={handleApplyClicked}
onKeyDown={handleApplyPress}
underline='hover'
tabIndex={0}
>
{intlConfig.formatMessage({ id: 'c4r.widgets.category.apply' })}
</LinkAsButton>
) : blockedCategories.length > 0 ? (
<LinkAsButton onClick={handleUnblockClicked} underline='hover'>
<LinkAsButton
onClick={handleUnblockClicked}
onKeyDown={handleUnblockPress}
underline='hover'
tabIndex={0}
>
{intlConfig.formatMessage({ id: 'c4r.widgets.category.unlock' })}
</LinkAsButton>
) : (
selectedCategories.length > 0 && (
<Grid container direction='row' justifyContent='flex-end' item xs>
<LinkAsButton onClick={handleBlockClicked} underline='hover'>
<LinkAsButton
onClick={handleBlockClicked}
onKeyDown={handleBlockPress}
underline='hover'
tabIndex={0}
>
{intlConfig.formatMessage({ id: 'c4r.widgets.category.lock' })}
</LinkAsButton>
<Divider orientation='vertical' flexItem />
<LinkAsButton onClick={handleClearClicked} underline='hover'>
<LinkAsButton
onClick={handleClearClicked}
onKeyDown={handleClearPress}
underline='hover'
tabIndex={0}
>
{intlConfig.formatMessage({ id: 'c4r.widgets.category.clear' })}
</LinkAsButton>
</Grid>
Expand All @@ -408,6 +459,9 @@ function CategoryWidgetUI(props) {
</InputAdornment>
)
}}
inputProps={{
tabIndex: 0
}}
/>
</OptionsSelectedBar>
)}
Expand Down
Loading
Loading