From b50fed203315162d50a33583a1195d17d44b4844 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ver=C3=B3nica=20Mil=C3=A1n?= Date: Wed, 20 Mar 2024 17:11:45 +0100 Subject: [PATCH 01/11] fix keyboard navigation --- .../src/widgets/CategoryWidgetUI/CategoryWidgetUI.js | 6 +++--- .../src/widgets/CategoryWidgetUI/CategoryWidgetUI.styled.js | 5 ----- 2 files changed, 3 insertions(+), 8 deletions(-) diff --git a/packages/react-ui/src/widgets/CategoryWidgetUI/CategoryWidgetUI.js b/packages/react-ui/src/widgets/CategoryWidgetUI/CategoryWidgetUI.js index 6ccee369c..4a774d40c 100644 --- a/packages/react-ui/src/widgets/CategoryWidgetUI/CategoryWidgetUI.js +++ b/packages/react-ui/src/widgets/CategoryWidgetUI/CategoryWidgetUI.js @@ -323,7 +323,7 @@ function CategoryWidgetUI(props) { }; }, []); - const handleCategoryPress = (e) => { + const onCategoryPress = (e) => { if (e.key === 'Enter') { onCategoryClick(); } @@ -339,11 +339,11 @@ function CategoryWidgetUI(props) { direction='row' spacing={1} onClick={filterable ? onCategoryClick : () => {}} - onKeyDown={handleCategoryPress} + onKeyDown={filterable ? onCategoryPress : () => {}} selectable={filterable} unselected={unselected} name={data.name === REST_CATEGORY ? REST_CATEGORY : ''} - tabIndex={filterable && showAll ? 0 : -1} + tabIndex={filterable ? 0 : -1} > {filterable && showAll && ( diff --git a/packages/react-ui/src/widgets/CategoryWidgetUI/CategoryWidgetUI.styled.js b/packages/react-ui/src/widgets/CategoryWidgetUI/CategoryWidgetUI.styled.js index 68a01494a..25ce6f046 100644 --- a/packages/react-ui/src/widgets/CategoryWidgetUI/CategoryWidgetUI.styled.js +++ b/packages/react-ui/src/widgets/CategoryWidgetUI/CategoryWidgetUI.styled.js @@ -5,7 +5,6 @@ const REST_CATEGORY = '__rest__'; export const CategoriesWrapper = styled(Grid)(({ theme: { spacing } }) => ({ maxHeight: spacing(40), - overflow: 'auto', padding: spacing(0, 1, 1, 0) })); @@ -28,10 +27,6 @@ export const CategoryItemGroup = styled(Grid, { '&:hover .progressbar div': { backgroundColor: theme.palette.secondary.dark - }, - '&:focus-visible': { - outline: `none !important`, - boxShadow: `inset 0 0 0 2px ${theme.palette.primary.main} !important` } }), ...(name === REST_CATEGORY && { From 98e8ba9a8ec1245b0b7d1813d42cb9c0983bfc37 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ver=C3=B3nica=20Mil=C3=A1n?= Date: Wed, 20 Mar 2024 17:14:06 +0100 Subject: [PATCH 02/11] changelog --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9f660a40c..df99a9318 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,8 @@ ## Not released +- Category widget UI: increase keyboard accessibility [#856](https://github.com/CartoDB/carto-react/pull/856) + ## 2.4 ### 2.4.1 (2024-03-13) From 832bf1107cd2da70c7cc57008cb35470028871ff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ver=C3=B3nica=20Mil=C3=A1n?= Date: Wed, 20 Mar 2024 18:25:50 +0100 Subject: [PATCH 03/11] fix unrelated styling bug --- .../src/widgets/CategoryWidgetUI/CategoryWidgetUI.js | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/packages/react-ui/src/widgets/CategoryWidgetUI/CategoryWidgetUI.js b/packages/react-ui/src/widgets/CategoryWidgetUI/CategoryWidgetUI.js index 4a774d40c..b26e3e3d5 100644 --- a/packages/react-ui/src/widgets/CategoryWidgetUI/CategoryWidgetUI.js +++ b/packages/react-ui/src/widgets/CategoryWidgetUI/CategoryWidgetUI.js @@ -7,7 +7,8 @@ import { InputAdornment, Divider, TextField, - Tooltip + Tooltip, + Box } from '@mui/material'; import { useIntl } from 'react-intl'; @@ -477,17 +478,17 @@ function CategoryWidgetUI(props) { /> )) ) : ( - <> + {intlConfig.formatMessage({ id: 'c4r.widgets.category.noResults' })} - + {intlConfig.formatMessage( { id: 'c4r.widgets.category.noResultsMessage' }, { searchValue } )} - + )} {data.length > maxItems && searchable ? ( From 026480b570f59dcf6ff1f76373b533bc7ae3c3c9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ver=C3=B3nica=20Mil=C3=A1n?= Date: Thu, 21 Mar 2024 12:12:56 +0100 Subject: [PATCH 04/11] fix styles when the list is too large --- .../CategoryWidgetUI/CategoryWidgetUI.js | 34 +++++++++++-------- .../CategoryWidgetUI.styled.js | 21 +++++++++--- .../widgetsUI/CategoryWidgetUI.stories.js | 2 +- 3 files changed, 37 insertions(+), 20 deletions(-) diff --git a/packages/react-ui/src/widgets/CategoryWidgetUI/CategoryWidgetUI.js b/packages/react-ui/src/widgets/CategoryWidgetUI/CategoryWidgetUI.js index b26e3e3d5..f0adb15c3 100644 --- a/packages/react-ui/src/widgets/CategoryWidgetUI/CategoryWidgetUI.js +++ b/packages/react-ui/src/widgets/CategoryWidgetUI/CategoryWidgetUI.js @@ -347,7 +347,7 @@ function CategoryWidgetUI(props) { tabIndex={filterable ? 0 : -1} > {filterable && showAll && ( - + {data.length > maxItems && searchable ? ( showAll ? ( - + + + ) : ( - + + + ) ) : null} diff --git a/packages/react-ui/src/widgets/CategoryWidgetUI/CategoryWidgetUI.styled.js b/packages/react-ui/src/widgets/CategoryWidgetUI/CategoryWidgetUI.styled.js index 25ce6f046..624c9fa8b 100644 --- a/packages/react-ui/src/widgets/CategoryWidgetUI/CategoryWidgetUI.styled.js +++ b/packages/react-ui/src/widgets/CategoryWidgetUI/CategoryWidgetUI.styled.js @@ -3,9 +3,10 @@ import Typography from '../../components/atoms/Typography'; const REST_CATEGORY = '__rest__'; -export const CategoriesWrapper = styled(Grid)(({ theme: { spacing } }) => ({ - maxHeight: spacing(40), - padding: spacing(0, 1, 1, 0) +export const CategoriesWrapper = styled(Grid)(({ theme }) => ({ + maxHeight: theme.spacing(40), + overflow: 'auto', + padding: 0 })); export const CategoryItemGroup = styled(Grid, { @@ -13,6 +14,18 @@ export const CategoryItemGroup = styled(Grid, { })(({ theme, selectable, name, unselected }) => { return { flexDirection: 'row', + padding: theme.spacing(0.5, 0.25), + margin: 0, + + '> .MuiGrid-item': { + paddingTop: 0, + paddingLeft: 0 + }, + '&:focus-visible': { + outline: `none !important`, + boxShadow: `inset 0 0 0 2px ${theme.palette.primary.main} !important` + }, + ...(unselected && { color: theme.palette.text.disabled, @@ -54,7 +67,7 @@ export const OptionsSelectedBar = styled(Grid)(({ theme: { spacing, palette } }) export const ProgressBar = styled(Grid)(({ theme }) => ({ height: theme.spacing(0.5), width: '100%', - margin: theme.spacing(0.5, 0, 1, 0), + margin: theme.spacing(0.5, 0, 0.25, 0), borderRadius: theme.spacing(0.5), backgroundColor: theme.palette.action.disabledBackground, diff --git a/packages/react-ui/storybook/stories/widgetsUI/CategoryWidgetUI.stories.js b/packages/react-ui/storybook/stories/widgetsUI/CategoryWidgetUI.stories.js index ff8503dc4..5df265218 100644 --- a/packages/react-ui/storybook/stories/widgetsUI/CategoryWidgetUI.stories.js +++ b/packages/react-ui/storybook/stories/widgetsUI/CategoryWidgetUI.stories.js @@ -60,7 +60,7 @@ const LoadingTemplate = (args) => { ); }; -const data = [...Array(7)].map((_, idx) => ({ +const data = [...Array(30)].map((_, idx) => ({ name: `Category ${idx + 1}`, value: idx * 100 })); From 74bad64ab99b1d4f6c8a906332b27104848282ef Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ver=C3=B3nica=20Mil=C3=A1n?= Date: Thu, 21 Mar 2024 14:55:29 +0100 Subject: [PATCH 05/11] fix horizontal scrolling --- .../src/widgets/CategoryWidgetUI/CategoryWidgetUI.js | 7 ++++--- .../CategoryWidgetUI/CategoryWidgetUI.styled.js | 11 +++++++++++ 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/packages/react-ui/src/widgets/CategoryWidgetUI/CategoryWidgetUI.js b/packages/react-ui/src/widgets/CategoryWidgetUI/CategoryWidgetUI.js index f0adb15c3..40b485d1b 100644 --- a/packages/react-ui/src/widgets/CategoryWidgetUI/CategoryWidgetUI.js +++ b/packages/react-ui/src/widgets/CategoryWidgetUI/CategoryWidgetUI.js @@ -23,7 +23,8 @@ import { LinkAsButton, OptionsSelectedBar, ProgressBar, - CategoriesRoot + CategoriesRoot, + CategoryLabelWrapper } from './CategoryWidgetUI.styled'; import SearchIcon from '../../assets/icons/SearchIcon'; import useImperativeIntl from '../../hooks/useImperativeIntl'; @@ -354,7 +355,7 @@ function CategoryWidgetUI(props) { /> )} - +
-
+
); }; diff --git a/packages/react-ui/src/widgets/CategoryWidgetUI/CategoryWidgetUI.styled.js b/packages/react-ui/src/widgets/CategoryWidgetUI/CategoryWidgetUI.styled.js index 624c9fa8b..cd8b8a7d1 100644 --- a/packages/react-ui/src/widgets/CategoryWidgetUI/CategoryWidgetUI.styled.js +++ b/packages/react-ui/src/widgets/CategoryWidgetUI/CategoryWidgetUI.styled.js @@ -14,6 +14,7 @@ export const CategoryItemGroup = styled(Grid, { })(({ theme, selectable, name, unselected }) => { return { flexDirection: 'row', + maxWidth: '100%', padding: theme.spacing(0.5, 0.25), margin: 0, @@ -81,6 +82,16 @@ export const ProgressBar = styled(Grid)(({ theme }) => ({ } })); +export const CategoryLabelWrapper = styled(Grid, { + shouldForwardProp: (prop) => prop !== 'isSelectable' +})(({ theme, isSelectable }) => { + return { + ...(isSelectable && { + width: `calc(100% - ${theme.spacing(4)})` + }) + }; +}); + export const CategoryLabel = styled(Typography)(({ theme }) => ({ fontWeight: theme.typography.fontWeightBold, marginRight: theme.spacing(2) From 2b38c089ab1bca915c8c789592f604d1b89e9a35 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ver=C3=B3nica=20Mil=C3=A1n?= Date: Thu, 21 Mar 2024 15:50:15 +0100 Subject: [PATCH 06/11] fix horizontal scrolling --- .../react-ui/src/widgets/CategoryWidgetUI/CategoryWidgetUI.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/react-ui/src/widgets/CategoryWidgetUI/CategoryWidgetUI.js b/packages/react-ui/src/widgets/CategoryWidgetUI/CategoryWidgetUI.js index 40b485d1b..f5bbf38bb 100644 --- a/packages/react-ui/src/widgets/CategoryWidgetUI/CategoryWidgetUI.js +++ b/packages/react-ui/src/widgets/CategoryWidgetUI/CategoryWidgetUI.js @@ -355,7 +355,7 @@ function CategoryWidgetUI(props) { />
)} - + Date: Thu, 21 Mar 2024 17:08:48 +0100 Subject: [PATCH 07/11] fix order focus on searchField --- .../CategoryWidgetUI/CategoryWidgetUI.js | 17 +++++++++++++++-- .../CategoryWidgetUI.styled.js | 18 +++++++++++++++++- 2 files changed, 32 insertions(+), 3 deletions(-) diff --git a/packages/react-ui/src/widgets/CategoryWidgetUI/CategoryWidgetUI.js b/packages/react-ui/src/widgets/CategoryWidgetUI/CategoryWidgetUI.js index f5bbf38bb..6fc101f4c 100644 --- a/packages/react-ui/src/widgets/CategoryWidgetUI/CategoryWidgetUI.js +++ b/packages/react-ui/src/widgets/CategoryWidgetUI/CategoryWidgetUI.js @@ -24,7 +24,8 @@ import { OptionsSelectedBar, ProgressBar, CategoriesRoot, - CategoryLabelWrapper + CategoryLabelWrapper, + HiddenButton } from './CategoryWidgetUI.styled'; import SearchIcon from '../../assets/icons/SearchIcon'; import useImperativeIntl from '../../hooks/useImperativeIntl'; @@ -61,6 +62,7 @@ function CategoryWidgetUI(props) { const [tempBlockedCategories, setTempBlockedCategories] = useState(false); const [animValues, setAnimValues] = useState([]); const requestRef = useRef(); + const searchRef = useRef(); const prevAnimValues = usePrevious(animValues); const referencedPrevAnimValues = useRef(); const { showSkeleton } = useSkeleton(isLoading); @@ -304,6 +306,12 @@ function CategoryWidgetUI(props) { } }, [animation, sortedData]); + useEffect(() => { + if (showAll && searchRef.current) { + searchRef.current.focus(); + } + }, [showAll, searchRef]); + // Separated to simplify the widget layout but inside the main component to avoid passing all dependencies const CategoryItem = (props) => { const { data, onCategoryClick } = props; @@ -335,6 +343,7 @@ function CategoryWidgetUI(props) { !showAll && selectedCategories.length > 0 && selectedCategories.indexOf(data.name) === -1; + return ( + + {intlConfig.formatMessage({ id: 'c4r.widgets.category.cancel' })} + )} diff --git a/packages/react-ui/src/widgets/CategoryWidgetUI/CategoryWidgetUI.styled.js b/packages/react-ui/src/widgets/CategoryWidgetUI/CategoryWidgetUI.styled.js index cd8b8a7d1..31e04ac0c 100644 --- a/packages/react-ui/src/widgets/CategoryWidgetUI/CategoryWidgetUI.styled.js +++ b/packages/react-ui/src/widgets/CategoryWidgetUI/CategoryWidgetUI.styled.js @@ -1,4 +1,4 @@ -import { Box, Grid, Link, styled } from '@mui/material'; +import { Box, Button, Grid, Link, styled } from '@mui/material'; import Typography from '../../components/atoms/Typography'; const REST_CATEGORY = '__rest__'; @@ -109,3 +109,19 @@ export const LinkAsButton = styled(Link)(({ theme }) => ({ export const CategoriesRoot = styled(Box)(({ theme }) => ({ ...theme.typography.body2 })); + +export const HiddenButton = styled(Button)(({ theme }) => ({ + position: 'absolute', + left: '-999px', + top: '-1px', + width: '1px', + height: '1px', + display: 'inline-flex', + + '&:focus-visible': { + position: 'static', + width: 'auto', + height: 'auto', + marginTop: theme.spacing(2) + } +})); From b34e347786ddc991c14afe74eafd70b6cecec18f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ver=C3=B3nica=20Mil=C3=A1n?= Date: Thu, 21 Mar 2024 18:45:30 +0100 Subject: [PATCH 08/11] fix unit test --- .../__tests__/widgets/CategoryWidgetUI.test.js | 7 +++++-- .../src/widgets/CategoryWidgetUI/CategoryWidgetUI.js | 11 +++++++++-- 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/packages/react-ui/__tests__/widgets/CategoryWidgetUI.test.js b/packages/react-ui/__tests__/widgets/CategoryWidgetUI.test.js index 5e2382eff..c17330fee 100644 --- a/packages/react-ui/__tests__/widgets/CategoryWidgetUI.test.js +++ b/packages/react-ui/__tests__/widgets/CategoryWidgetUI.test.js @@ -62,6 +62,10 @@ describe('CategoryWidgetUI', () => { }); describe('events', () => { + beforeEach(() => { + HTMLElement.prototype.scrollIntoView = jest.fn(); + }); + test('category change', () => { const mockOnSelectedCategoriesChange = jest.fn(); render( @@ -138,7 +142,6 @@ describe('CategoryWidgetUI', () => { }); test('search category', () => { - HTMLElement.prototype.scrollIntoView = jest.fn(); const mockOnSelectedCategoriesChange = jest.fn(); render( { expect(screen.getByText(/Search in 4 elements/)).toBeInTheDocument(); fireEvent.click(screen.getByText(/Search in 4 elements/)); - fireEvent.click(screen.getByText(/Cancel/)); + fireEvent.click(screen.getByTestId('primaryCancelButton')); }); test('searchable prop', () => { diff --git a/packages/react-ui/src/widgets/CategoryWidgetUI/CategoryWidgetUI.js b/packages/react-ui/src/widgets/CategoryWidgetUI/CategoryWidgetUI.js index 6fc101f4c..c2769064c 100644 --- a/packages/react-ui/src/widgets/CategoryWidgetUI/CategoryWidgetUI.js +++ b/packages/react-ui/src/widgets/CategoryWidgetUI/CategoryWidgetUI.js @@ -460,7 +460,9 @@ function CategoryWidgetUI(props) { maxItems && searchable ? ( showAll ? ( - From 6585cf2d69398f643930403edb0890fb646ce236 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ver=C3=B3nica=20Mil=C3=A1n?= Date: Fri, 22 Mar 2024 10:07:24 +0100 Subject: [PATCH 09/11] improve accessibility on search flow --- .../react-ui/__tests__/widgets/CategoryWidgetUI.test.js | 4 ++-- .../src/widgets/CategoryWidgetUI/CategoryWidgetUI.js | 6 ++++++ 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/packages/react-ui/__tests__/widgets/CategoryWidgetUI.test.js b/packages/react-ui/__tests__/widgets/CategoryWidgetUI.test.js index c17330fee..3fcb28836 100644 --- a/packages/react-ui/__tests__/widgets/CategoryWidgetUI.test.js +++ b/packages/react-ui/__tests__/widgets/CategoryWidgetUI.test.js @@ -136,7 +136,7 @@ describe('CategoryWidgetUI', () => { fireEvent.click(screen.getByText(/Search in 4 elements/)); fireEvent.click(screen.getByText(/Category 1/)); - fireEvent.click(screen.getByText(/Apply/)); + fireEvent.click(screen.getByTestId('primaryApplyButton')); fireEvent.click(screen.getByText(/Unlock/)); expect(mockOnSelectedCategoriesChange).toHaveBeenCalledTimes(2); }); @@ -154,7 +154,7 @@ describe('CategoryWidgetUI', () => { fireEvent.click(screen.getByText(/Search in 4 elements/)); userEvent.type(screen.getByRole('textbox'), 'Category 1'); fireEvent.click(screen.getByText(/Category 1/)); - fireEvent.click(screen.getByText(/Apply/)); + fireEvent.click(screen.getByTestId('primaryApplyButton')); }); test('cancel search', () => { diff --git a/packages/react-ui/src/widgets/CategoryWidgetUI/CategoryWidgetUI.js b/packages/react-ui/src/widgets/CategoryWidgetUI/CategoryWidgetUI.js index c2769064c..31a90dfba 100644 --- a/packages/react-ui/src/widgets/CategoryWidgetUI/CategoryWidgetUI.js +++ b/packages/react-ui/src/widgets/CategoryWidgetUI/CategoryWidgetUI.js @@ -418,6 +418,7 @@ function CategoryWidgetUI(props) { onKeyDown={handleApplyPress} underline='hover' tabIndex={0} + data-testid='primaryApplyButton' > {intlConfig.formatMessage({ id: 'c4r.widgets.category.apply' })} @@ -507,6 +508,11 @@ function CategoryWidgetUI(props) { )} + {showAll && ( + + {intlConfig.formatMessage({ id: 'c4r.widgets.category.apply' })} + + )} {data.length > maxItems && searchable ? ( showAll ? ( From ff45c13c734eadebe1b7ca627dc6ec9a5b2bb11d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ver=C3=B3nica=20Mil=C3=A1n?= Date: Fri, 22 Mar 2024 10:10:48 +0100 Subject: [PATCH 10/11] improve accessibility on search flow --- .../react-ui/src/widgets/CategoryWidgetUI/CategoryWidgetUI.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/react-ui/src/widgets/CategoryWidgetUI/CategoryWidgetUI.js b/packages/react-ui/src/widgets/CategoryWidgetUI/CategoryWidgetUI.js index 31a90dfba..26fb79f57 100644 --- a/packages/react-ui/src/widgets/CategoryWidgetUI/CategoryWidgetUI.js +++ b/packages/react-ui/src/widgets/CategoryWidgetUI/CategoryWidgetUI.js @@ -478,7 +478,7 @@ function CategoryWidgetUI(props) { ref: searchRef }} /> - + {intlConfig.formatMessage({ id: 'c4r.widgets.category.cancel' })} @@ -509,7 +509,7 @@ function CategoryWidgetUI(props) { )} {showAll && ( - + {intlConfig.formatMessage({ id: 'c4r.widgets.category.apply' })} )} From 89a50b716d175f31e08e5914aba3d48ce101d4be Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ver=C3=B3nica=20Mil=C3=A1n?= Date: Fri, 22 Mar 2024 10:50:27 +0100 Subject: [PATCH 11/11] changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index df99a9318..aeef9de1b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,7 @@ ## Not released - Category widget UI: increase keyboard accessibility [#856](https://github.com/CartoDB/carto-react/pull/856) +- Category widget UI: change focus order to increase keyboard accessibility [#857](https://github.com/CartoDB/carto-react/pull/857) ## 2.4