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

Fixing a11y status messages PL-17 #1206

Merged
merged 3 commits into from
Nov 28, 2024
Merged
Show file tree
Hide file tree
Changes from all 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
34 changes: 25 additions & 9 deletions src/components/SettingsDropdowns/SettingsDropdowns.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,13 @@
/* eslint-disable react/jsx-props-no-spreading */
import styled from '@emotion/styled';
import { Checkbox, ListItem, TextField, Typography } from '@mui/material';
import {
Checkbox, ListItem, TextField, Typography,
} from '@mui/material';
import PropTypes from 'prop-types';
import React, { useRef, useState } from 'react';
import { useIntl } from 'react-intl';
import { useDispatch, useSelector } from 'react-redux';
import { visuallyHidden } from '@mui/utils';
import config from '../../../config';
import { resetMobilityTreeSelections } from '../../redux/actions/mobilityTree';
import { resetServiceTreeSelections } from '../../redux/actions/serviceTree';
Expand All @@ -29,14 +33,16 @@ import SMButton from '../ServiceMapButton';
import constants from '../SettingsComponent/constants';
import SMAutocomplete from '../SMAutocomplete';

const SettingsDropdowns = ({ variant = 'default'}) => {
function SettingsDropdowns({ variant }) {
const intl = useIntl();
const dispatch = useDispatch();
const getLocaleText = useLocaleText();
const settings = useSelector(selectSettings);
// Format settings from redux to easier structure
const settingsValues = constants.convertToSettingsValues(settings);
const [openSettings, setOpenSettings] = useState(null);
const [resetText, setResetText] = useState('');

const highlightedOption = useRef(null);
const themeMode = useSelector(selectThemeMode);
const ownSettingsVariant = variant === 'ownSettings';
Expand All @@ -61,7 +67,7 @@ const SettingsDropdowns = ({ variant = 'default'}) => {
{ id: organization.id, title: getLocaleText(organization.name) }
));

const toggleSettingsBox = (id) => {
const toggleSettingsBox = id => {
if (openSettings === id) setOpenSettings(null);
else setOpenSettings(id);
};
Expand All @@ -70,6 +76,9 @@ const SettingsDropdowns = ({ variant = 'default'}) => {
if (!id) {
return;
}

setResetText('');

if (category === 'mobility') {
dispatch(setMobility(id));
setOpenSettings(null);
Expand Down Expand Up @@ -122,6 +131,8 @@ const SettingsDropdowns = ({ variant = 'default'}) => {
dispatch(resetCustomPosition());
dispatch(changeTheme('default'));
dispatch(resetUserPosition());

setResetText(intl.formatMessage({ id: 'settings.reset_button.ariaLive' }));
};

const handleKeyboardSelect = (id, category, event) => {
Expand Down Expand Up @@ -171,8 +182,9 @@ const SettingsDropdowns = ({ variant = 'default'}) => {
ChipProps={{
clickable: true, onDelete: null, variant: ownSettingsVariant ? 'outlined' : 'filled',
}}
slotProps={{
popper:{ sx: { pb: 1 } } // This padding fixes the listBox position on small screens where the list is renderend to top of input
slotProps={{
// eslint-disable-next-line max-len
popper: { sx: { pb: 1 } }, // This padding fixes the listBox position on small screens where the list is renderend to top of input
}}
renderOption={(props, option) => (isSingleOption
? ( // Single option options box
Expand All @@ -188,12 +200,11 @@ const SettingsDropdowns = ({ variant = 'default'}) => {
/>
<Typography>{option.title}</Typography>
</ListItem>
))
}
))}
renderInput={({ inputProps, ...rest }) => (
<TextField
label={label}
onClick={(e) => {
onClick={e => {
e?.stopPropagation();
toggleSettingsBox(label);
}}
Expand Down Expand Up @@ -222,6 +233,7 @@ const SettingsDropdowns = ({ variant = 'default'}) => {
{renderSettingsElement(citySettingsList, intl.formatMessage({ id: 'settings.choose.cities' }), 'cities')}
{renderSettingsElement(organizationSettingsList, intl.formatMessage({ id: 'settings.choose.organization' }), 'organizations')}
<div>
<Typography aria-live="polite" style={visuallyHidden}>{resetText}</Typography>
<StyledButton
data-sm="reset-settings-button"
ownsettings={+ownSettingsVariant}
Expand All @@ -234,7 +246,7 @@ const SettingsDropdowns = ({ variant = 'default'}) => {
</div>
</>
);
};
}

const StyledButton = styled(SMButton)(() => ({ marginRight: 0 }));

Expand Down Expand Up @@ -280,6 +292,10 @@ const StyledAutocomplete = styled(SMAutocomplete)(({ theme, ownsettings, colormo
return { ...styles, ...ownSettingsStyles };
});

SettingsDropdowns.defaultProps = {
variant: 'default',
};

SettingsDropdowns.propTypes = {
variant: PropTypes.oneOf(['default', 'ownSettings']),
};
Expand Down
91 changes: 51 additions & 40 deletions src/components/TabLists/TabLists.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
/* eslint-disable react/forbid-prop-types */
/* eslint-disable react/no-multi-comp */
import React, { useState, useEffect, useRef } from 'react';
import PropTypes from 'prop-types';
Expand All @@ -16,14 +17,14 @@ import config from '../../../config';
import useMobileStatus from '../../utils/isMobile';
import PaginatedList from '../Lists/PaginatedList';

const TabLists = ({
function TabLists({
location,
data,
onTabChange = null,
focusClass = null,
focusText = null,
headerComponents = null,
}) => {
onTabChange,
focusClass,
focusText,
headerComponents,
}) {
const isMobile = useMobileStatus();
const theme = useTheme();
const navigator = useSelector(selectNavigator);
Expand Down Expand Up @@ -154,7 +155,7 @@ const TabLists = ({
const renderHeader = () => {
let fullData = [];

data.forEach((element) => {
data.forEach(element => {
if (element.data && !element.noOrderer) {
fullData = [...fullData, ...element.data];
}
Expand Down Expand Up @@ -216,16 +217,16 @@ const TabLists = ({
}
{
fullData.length > 0 && (
<>
<ResultOrderer disabled={disabled} />
</>
<ResultOrderer disabled={disabled} />
)
}
{
focusClass
&& focusText
&& (
<Typography style={visuallyHidden} className={focusClass} tabIndex={-1}>{focusText}</Typography>
<Typography style={visuallyHidden} className={focusClass} tabIndex={-1}>
{focusText}
</Typography>
)
}
<StyledTabs
Expand All @@ -237,62 +238,65 @@ const TabLists = ({
style={styles}
>
{
filteredData.map((item, index) => {
if (item.data && item.data.length > 0) {
const label = `${item.title} ${item.component ? '' : `(${item.data.length})`}`.trim();
const tabId = `${item.title}-${item.data.length}`;
return (
<StyledTab
id={tabId}
key={tabId}
aria-controls={`tab-content-${index}`}
aria-label={item.ariaLabel ? item.ariaLabel : null}
classes={{
root: tabRootClass,
selected: selectedClass,
}}
label={label}
onClick={item.onClick ? () => item.onClick(index) : null}
focusVisibleClassName={tabFocusClass}
/>
);
}
filteredData.map((item, index) => {
if (item.data && item.data.length > 0) {
const label = `${item.title} ${item.component ? '' : `(${item.data.length})`}`.trim();
const tabId = `${item.title}-${item.data.length}`;

return (
<Tab
id={`Tab${index}`}
key={`${item.title}`}
<StyledTab
id={tabId}
key={tabId}
ref={item.ref}
aria-controls={`tab-content-${index}`}
aria-label={item.ariaLabel ? item.ariaLabel : null}
classes={{
root: tabRootClass,
selected: selectedClass,
}}
label={`${item.title}`}
label={label}
onClick={item.onClick ? () => item.onClick(index) : null}
focusVisibleClassName={tabFocusClass}
/>
);
})
}
}
return (
<Tab
id={`Tab${index}`}
key={`${item.title}`}
ref={item.ref}
aria-controls={`tab-content-${index}`}
aria-label={item.ariaLabel ? item.ariaLabel : null}
classes={{
root: tabRootClass,
selected: selectedClass,
}}
label={`${item.title}`}
onClick={item.onClick ? () => item.onClick(index) : null}
focusVisibleClassName={tabFocusClass}
/>
);
})
}
</StyledTabs>
</>
);
};

useEffect(() => {
calculateHeaderStylings();
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [isMobile]);


useEffect(() => {
// Change tab if selected tab is changed on url
const tabFromUrl = getTabfromUrl();
if (tabFromUrl !== tabIndex) {
handleTabChange(null, tabFromUrl);
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [location]);


const render = () => (
<>
{
Expand Down Expand Up @@ -359,7 +363,7 @@ const TabLists = ({
);

return render();
};
}

const StyledTabs = styled(Tabs)(({ theme }) => ({
position: 'sticky',
Expand Down Expand Up @@ -404,4 +408,11 @@ TabLists.propTypes = {
focusText: PropTypes.string,
};

TabLists.defaultProps = {
onTabChange: null,
focusClass: null,
focusText: null,
headerComponents: null,
};

export default TabLists;
1 change: 1 addition & 0 deletions src/i18n/en.js
Original file line number Diff line number Diff line change
Expand Up @@ -724,6 +724,7 @@ export default {
'settings.choose.organization': 'Choose a service provider',
'settings.map.info': 'You can select the background map that best suits you in the map settings.',
'settings.reset_button.title': 'Clear all my selections',
'settings.reset_button.ariaLive': 'All selections were cleared.',

// Tools
'tool.download': 'Download data',
Expand Down
1 change: 1 addition & 0 deletions src/i18n/fi.js
Original file line number Diff line number Diff line change
Expand Up @@ -726,6 +726,7 @@ export default {
'settings.choose.organization': 'Valitse palveluntarjoaja',
'settings.map.info': 'Kartta-asetuksista voit valita sinulle parhaiten sopivan pohjakartan.',
'settings.reset_button.title': 'Tyhjennä kaikki valintani',
'settings.reset_button.ariaLive': 'Kaikki valinnat tyhjennettiin.',

// Tools
'tool.download': 'Lataa tiedot',
Expand Down
1 change: 1 addition & 0 deletions src/i18n/sv.js
Original file line number Diff line number Diff line change
Expand Up @@ -725,6 +725,7 @@ export default {
'settings.choose.organization': 'Välj tjänsteleverantör',
'settings.map.info': 'I kartinställningarna kan du välja det kartunderlag som passar dig bäst.',
'settings.reset_button.title': 'Rensa alla mina val',
'settings.reset_button.ariaLive': 'Alla val har rensats.',

// Tools
'tool.download': 'Exportera',
Expand Down
Loading