Skip to content

Commit

Permalink
fix: add accessible descriptions to the dropdowns (#7112)
Browse files Browse the repository at this point in the history
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
  • Loading branch information
thomasheartman committed May 22, 2024
1 parent 57f66f3 commit be4bb86
Show file tree
Hide file tree
Showing 3 changed files with 55 additions and 20 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -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) => {
Expand Down Expand Up @@ -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,
Expand All @@ -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,
Expand All @@ -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}
/>
Expand All @@ -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);
Expand All @@ -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}
/>
Expand All @@ -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) =>
Expand Down Expand Up @@ -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}
/>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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 }) => ({
Expand Down
Original file line number Diff line number Diff line change
@@ -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 {
Expand All @@ -8,6 +9,7 @@ import {
StyledPopover,
StyledDropdownSearch,
TableSearchInput,
HiddenDescription,
} from './SelectionButton.styles';
import { ChangeRequestTable } from './ChangeRequestTable';

Expand Down Expand Up @@ -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> = ({
Expand All @@ -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 = () => {
Expand Down Expand Up @@ -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'
Expand Down Expand Up @@ -186,6 +194,7 @@ const CombinedSelect: FC<CombinedSelectProps> = ({

return (
<StyledListItem
aria-describedby={labelId}
key={option.value}
dense
disablePadding
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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) => {
Expand All @@ -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;
Expand Down

0 comments on commit be4bb86

Please sign in to comment.