From 35f2ed4446fa16d11ca081ce08017f7eadd46626 Mon Sep 17 00:00:00 2001 From: Eugene Olonov Date: Thu, 3 Feb 2022 15:00:44 -0800 Subject: [PATCH 1/2] a11y: improve tree filtering keyboard and announcement This fixes the following issues: - Unable to go through filtered tree items via keyboard as the filter immediately gets closed after a blur event - Narrator doesn't announce search results and related instructions for filter The former issue is fixed by preserving the search query in case the query is not empty. If the query is empty blur causes the filter to close. I'd like to note that the filtered state is preserved until a user explicitly clears the search query. To me, this should be the desired behavior. The later issue has more to note about: - Refactored announcement to use `Announced` component from FluentUI built-ins. - Since Narrator still has issues with announcing status/alert roles used by the Announced component, added an explicit `aria-labeledby` link to the announced text, so it can be announced using Narrator shortcuts while navigating through the searchbox or the tree itself. - Improved announcement message to include the region label and more information regarding the current search query the result is provided for. --- .../components/ProjectTree/ProjectTree.tsx | 25 +++++++++++++------ .../ProjectTree/ProjectTreeHeader.tsx | 14 +++++------ 2 files changed, 24 insertions(+), 15 deletions(-) diff --git a/Composer/packages/client/src/components/ProjectTree/ProjectTree.tsx b/Composer/packages/client/src/components/ProjectTree/ProjectTree.tsx index c7a8949107..1e6ce5722c 100644 --- a/Composer/packages/client/src/components/ProjectTree/ProjectTree.tsx +++ b/Composer/packages/client/src/components/ProjectTree/ProjectTree.tsx @@ -13,6 +13,8 @@ import throttle from 'lodash/throttle'; import { useRecoilValue } from 'recoil'; import { extractSchemaProperties, groupTriggersByPropertyReference, NoGroupingTriggerGroupName } from '@bfc/indexers'; import isEqual from 'lodash/isEqual'; +import { Announced } from 'office-ui-fabric-react/lib/Announced'; +import { useId } from '@uifabric/react-hooks'; import { dispatcherState, @@ -175,6 +177,8 @@ export const ProjectTree: React.FC = ({ const projectCollection: TreeDataPerProject[] = useRecoilValue(projectTreeSelectorFamily); const jsonSchemaFilesByProjectId = useRecoilValue(jsonSchemaFilesByProjectIdSelector); + const projectTreeNavLabelId = useId('project-tree-nav-label'); + // TODO Refactor to make sure tree is not generated until a new trigger/dialog is added. #5462 const createSubtree = useCallback(() => { return projectCollection.map(createBotSubtree); @@ -773,24 +777,30 @@ export const ProjectTree: React.FC = ({ return (
-
= ({ 0 {} other {Press down arrow key to navigate the search results} }`, - { dialogNum: projectCollection.length } + { dialogNum: projectCollection.length, filter: filter, hasFilter: !!filter } )} - aria-live={'polite'} />
{projectTree}
diff --git a/Composer/packages/client/src/components/ProjectTree/ProjectTreeHeader.tsx b/Composer/packages/client/src/components/ProjectTree/ProjectTreeHeader.tsx index 05785b0767..70ac44ec9d 100644 --- a/Composer/packages/client/src/components/ProjectTree/ProjectTreeHeader.tsx +++ b/Composer/packages/client/src/components/ProjectTree/ProjectTreeHeader.tsx @@ -60,10 +60,12 @@ export interface ProjectTreeHeaderProps { placeholder?: string; ariaLabel?: string; onFilter?: (newValue?: string) => void; + filterValue: string; } export const ProjectTreeHeader: React.FC = ({ menu, + filterValue, onFilter = () => {}, placeholder = '', ariaLabel = '', @@ -94,8 +96,10 @@ export const ProjectTreeHeader: React.FC = ({ }) as IOverflowSetItemProps[]; const handleSearchBoxBlur = () => { - onFilter(''); - setShowFilter(false); + if (!filterValue) { + onFilter(''); + setShowFilter(false); + } }; // Move focus back to the filter button after the filter search box gets closed @@ -141,11 +145,7 @@ export const ProjectTreeHeader: React.FC = ({ styles={searchBox} onBlur={handleSearchBoxBlur} onChange={(_e, value) => onFilter(value)} - onClear={(ev) => { - if (!ev.target.value) { - handleSearchBoxBlur(); - } - }} + onClear={handleSearchBoxBlur} /> ) : (
From 599fa64f128e4df48a3e59e7a871805b010239f9 Mon Sep 17 00:00:00 2001 From: Eugene Olonov Date: Thu, 3 Feb 2022 16:03:47 -0800 Subject: [PATCH 2/2] Trigger rebuild