1
0
mirror of https://github.com/Unleash/unleash.git synced 2024-12-22 19:07:54 +01:00

fix: add accessible descriptions to the dropdowns (#7112)

This PR adds accessible descriptions to the dropdown widgets in the new
project creation form. The description is the same as we show in the
background
This commit is contained in:
Thomas Heartman 2024-05-22 14:02:05 +02:00 committed by GitHub
parent 57f66f3b55
commit be4bb86b92
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 55 additions and 20 deletions

View File

@ -154,6 +154,25 @@ export const NewProjectForm: React.FC<FormProps> = ({
const stickinessOptions = useStickinessOptions(projectStickiness);
const selectionButtonData = {
environments: {
icon: <EnvironmentsIcon />,
text: `Each feature flag can have a separate configuration per environment. This setting configures which environments your project should start with.`,
},
stickiness: {
icon: <StickinessIcon />,
text: 'Stickiness is used to guarantee that your users see the same result when using a gradual rollout. Default stickiness allows you to choose which field is used by default in this project.',
},
mode: {
icon: <ProjectModeIcon />,
text: 'Mode defines who should be allowed to interact and see your project. Private mode hides the project from anyone except the project owner and members.',
},
changeRequests: {
icon: <ChangeRequestIcon />,
text: 'Change requests can be configured per environment and require changes to go through an approval process before being applied.',
},
};
return (
<StyledForm
onSubmit={(submitEvent) => {
@ -207,6 +226,7 @@ export const NewProjectForm: React.FC<FormProps> = ({
<OptionButtons>
<MultiselectList
description={selectionButtonData.environments.text}
selectedOptions={projectEnvironments}
options={activeEnvironments.map((env) => ({
label: env.name,
@ -225,15 +245,13 @@ export const NewProjectForm: React.FC<FormProps> = ({
placeholder: 'Select project environments',
}}
onOpen={() =>
overrideDocumentation({
icon: <EnvironmentsIcon />,
text: `Each feature flag can have a separate configuration per environment. This setting configures which environments your project should start with.`,
})
overrideDocumentation(selectionButtonData.environments)
}
onClose={clearDocumentationOverride}
/>
<SingleSelectList
description={selectionButtonData.stickiness.text}
options={stickinessOptions.map(({ key, ...rest }) => ({
value: key,
...rest,
@ -250,10 +268,7 @@ export const NewProjectForm: React.FC<FormProps> = ({
placeholder: 'Select default stickiness',
}}
onOpen={() =>
overrideDocumentation({
icon: <StickinessIcon />,
text: 'Stickiness is used to guarantee that your users see the same result when using a gradual rollout. Default stickiness allows you to choose which field is used by default in this project.',
})
overrideDocumentation(selectionButtonData.stickiness)
}
onClose={clearDocumentationOverride}
/>
@ -262,6 +277,7 @@ export const NewProjectForm: React.FC<FormProps> = ({
condition={isEnterprise()}
show={
<SingleSelectList
description={selectionButtonData.mode.text}
options={projectModeOptions}
onChange={(value: any) => {
setProjectMode(value);
@ -275,10 +291,7 @@ export const NewProjectForm: React.FC<FormProps> = ({
placeholder: 'Select project mode',
}}
onOpen={() =>
overrideDocumentation({
icon: <ProjectModeIcon />,
text: 'Mode defines who should be allowed to interact and see your project. Private mode hides the project from anyone except the project owner and members.',
})
overrideDocumentation(selectionButtonData.mode)
}
onClose={clearDocumentationOverride}
/>
@ -288,6 +301,9 @@ export const NewProjectForm: React.FC<FormProps> = ({
condition={isEnterprise()}
show={
<TableSelect
description={
selectionButtonData.changeRequests.text
}
disabled={projectEnvironments.size === 0}
activeEnvironments={activeEnvironments
.filter((env) =>
@ -321,10 +337,9 @@ export const NewProjectForm: React.FC<FormProps> = ({
projectChangeRequestConfiguration
}
onOpen={() =>
overrideDocumentation({
icon: <ChangeRequestIcon />,
text: 'Change requests can be configured per environment and require changes to go through an approval process before being applied.',
})
overrideDocumentation(
selectionButtonData.changeRequests,
)
}
onClose={clearDocumentationOverride}
/>

View File

@ -40,6 +40,11 @@ const visuallyHiddenStyles = {
whiteSpace: 'nowrap',
};
export const HiddenDescription = styled('p')(() => ({
...visuallyHiddenStyles,
position: 'absolute',
}));
export const StyledDropdownSearch = styled(TextField, {
shouldForwardProp: (prop) => prop !== 'hideLabel',
})<{ hideLabel?: boolean }>(({ theme, hideLabel }) => ({

View File

@ -1,4 +1,5 @@
import Search from '@mui/icons-material/Search';
import { v4 as uuidv4 } from 'uuid';
import { Box, Button, InputAdornment, List, ListItemText } from '@mui/material';
import { type FC, type ReactNode, useRef, useState, useMemo } from 'react';
import {
@ -8,6 +9,7 @@ import {
StyledPopover,
StyledDropdownSearch,
TableSearchInput,
HiddenDescription,
} from './SelectionButton.styles';
import { ChangeRequestTable } from './ChangeRequestTable';
@ -81,6 +83,7 @@ type CombinedSelectProps = {
multiselect?: { selectedOptions: Set<string> };
onOpen?: () => void;
onClose?: () => void;
description: string; // visually hidden, for assistive tech
};
const CombinedSelect: FC<CombinedSelectProps> = ({
@ -91,10 +94,12 @@ const CombinedSelect: FC<CombinedSelectProps> = ({
multiselect,
onOpen = () => {},
onClose = () => {},
description,
}) => {
const ref = useRef<HTMLDivElement>(null);
const [anchorEl, setAnchorEl] = useState<HTMLDivElement | null>();
const [searchText, setSearchText] = useState('');
const descriptionId = uuidv4();
const [recentlyClosed, setRecentlyClosed] = useState(false);
const open = () => {
@ -156,7 +161,10 @@ const CombinedSelect: FC<CombinedSelectProps> = ({
horizontal: 'left',
}}
>
<StyledDropdown>
<HiddenDescription id={descriptionId}>
{description}
</HiddenDescription>
<StyledDropdown aria-describedby={descriptionId}>
<StyledDropdownSearch
variant='outlined'
size='small'
@ -186,6 +194,7 @@ const CombinedSelect: FC<CombinedSelectProps> = ({
return (
<StyledListItem
aria-describedby={labelId}
key={option.value}
dense
disablePadding
@ -234,7 +243,7 @@ const CombinedSelect: FC<CombinedSelectProps> = ({
type MultiselectListProps = Pick<
CombinedSelectProps,
'options' | 'button' | 'search' | 'onOpen' | 'onClose'
'options' | 'button' | 'search' | 'onOpen' | 'onClose' | 'description'
> & {
selectedOptions: Set<string>;
onChange: (values: Set<string>) => void;
@ -270,7 +279,13 @@ export const MultiselectList: FC<MultiselectListProps> = ({
type SingleSelectListProps = Pick<
CombinedSelectProps,
'options' | 'button' | 'search' | 'onChange' | 'onOpen' | 'onClose'
| 'options'
| 'button'
| 'search'
| 'onChange'
| 'onOpen'
| 'onClose'
| 'description'
>;
export const SingleSelectList: FC<SingleSelectListProps> = (props) => {
@ -279,7 +294,7 @@ export const SingleSelectList: FC<SingleSelectListProps> = (props) => {
type TableSelectProps = Pick<
CombinedSelectProps,
'button' | 'search' | 'onOpen' | 'onClose'
'button' | 'search' | 'onOpen' | 'onClose' | 'description'
> & {
updateProjectChangeRequestConfiguration: {
disableChangeRequests: (env: string) => void;