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

feat(UI builder): Add ability to compute screen reader narration of focused element in … …use mode #15464

Merged
merged 40 commits into from
Oct 12, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
40 commits
Select commit Hold shift + click to select a range
37afedc
Integrated the message computation script by Adam into UI Builder
adamsamec Sep 4, 2020
b464da0
Rename and reformat changes
adamsamec Sep 10, 2020
9e8f8f2
Merge branch 'master' into narration-computation
adamsamec Sep 10, 2020
dd0fdfd
Fix type errors
adamsamec Sep 10, 2020
d6d371b
Implement suggestions from PR for better readability of the code
adamsamec Sep 11, 2020
b56ca8e
Refactorring of the code. Mainly rewritten the large computeMessage()…
adamsamec Sep 11, 2020
03de7e5
Fix narration computation for elements with checked DOM property as s…
adamsamec Sep 12, 2020
0e77c3f
Rename to screen reader narration computation
adamsamec Sep 16, 2020
63df501
Merge branch 'master' into narration-computation
adamsamec Sep 16, 2020
69b3abf
Refactor getDefinitionName() method in NarrationComputer.tsx for con…
adamsamec Sep 17, 2020
5228b78
Replace default exports with named exports.
adamsamec Sep 17, 2020
6d66188
Remove private modifier
adamsamec Sep 17, 2020
a495f92
Change to a more readable type
adamsamec Sep 17, 2020
20e58b8
Rewrite the code not to use label for the for-loop and refactoring
adamsamec Sep 18, 2020
dadfa36
Update packages/fluentui/react-builder/src/components/NarrationComput…
adamsamec Sep 18, 2020
a13abc7
Reverting the last commit,
adamsamec Sep 18, 2020
5a4ff5e
Merge branch 'narration-computation' of https://github.com/adamsamec/…
adamsamec Sep 18, 2020
cb47801
Comment change
adamsamec Sep 18, 2020
3cd647c
Replace for loop with Array.forEach().
adamsamec Sep 18, 2020
dae82f1
Resolve lint errors
adamsamec Sep 18, 2020
742ddff
Remove empty file northstar. Have no idea how it was created-
adamsamec Sep 19, 2020
9ec256d
Remove showNarration condition
adamsamec Sep 23, 2020
ae51ced
Replace condition with ternary operator.
adamsamec Sep 23, 2020
8b3a33f
Add missing quotes in a CSS definition.
adamsamec Sep 23, 2020
d9c23ee
Replace condition with ternary operator
adamsamec Sep 23, 2020
70149fa
Rename parameter and add type"
adamsamec Sep 23, 2020
146c5dd
Merge branch 'master' into narration-computation
adamsamec Oct 1, 2020
8a6d454
Integrate descendant element screen reader narration computation into…
adamsamec Oct 2, 2020
79b8d4a
Refactoring and handle the case where there are no elements for the s…
adamsamec Oct 2, 2020
d59e7e1
Refactoring, narration now computes for all focusable elements, and p…
adamsamec Oct 2, 2020
84a826d
Fix for duplicate narration of the text 'Narration: '
adamsamec Oct 4, 2020
f1dc8e9
Add a small comment
adamsamec Oct 4, 2020
298d267
Add a comment and parenthesis around a arrow function parameter
adamsamec Oct 4, 2020
4913cd5
Edit comment and try to add parenthesis again
adamsamec Oct 4, 2020
074daa1
Revert the change to config.ts and refactoring of a if statement
adamsamec Oct 7, 2020
03c9ea7
Refactor for loop into forEach loop
adamsamec Oct 7, 2020
17ebcc1
Merge master
adamsamec Oct 8, 2020
a5b5bfe
Screen reader now computes the narration immediately on every change …
adamsamec Oct 9, 2020
378ad9b
Merge master
adamsamec Oct 9, 2020
ffebdd1
Add ability to compute screen reader narration of focused element in …
adamsamec Oct 11, 2020
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
11 changes: 6 additions & 5 deletions packages/fluentui/react-builder/src/components/Canvas.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -332,11 +332,12 @@ export const Canvas: React.FunctionComponent<CanvasProps> = ({
)}
{inUseMode && <EventListener capture type="focus" listener={handleFocus} target={document} />}
{renderJSONTreeToJSXElement(jsonTree, renderJSONTreeElement)}
{selectedComponent && (
<div style={{ bottom: '0', position: 'absolute' }}>
<ReaderNarration selector={`[data-builder-id="${selectedComponent.uuid}"]`} />
</div>
)}
<div style={{ bottom: '0', position: 'absolute' }}>
<ReaderNarration
selector={selectedComponent ? `[data-builder-id="${selectedComponent.uuid}"]` : null}
inUseMode={inUseMode}
/>
</div>
</Provider>
</>
)}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,73 +3,104 @@ import { Alert, Ref, Dropdown, DropdownProps } from '@fluentui/react-northstar';
import { IAriaElement } from './../narration/NarrationComputer';
import { DescendantsNarrationsComputer } from './../narration/DescendantsNarrationsComputer';

const computer: DescendantsNarrationsComputer = new DescendantsNarrationsComputer();
let narrationTexts: Record<string, string> = {};
const computer = new DescendantsNarrationsComputer();
let narrationPath = null;
let narrationPaths = [];
let narrationTexts = {};
const aomMissing = !(window as any).getComputedAccessibleNode;

export type ReaderNarrationProps = {
selector: string;
inUseMode: boolean;
};

export const ReaderNarration: React.FunctionComponent<ReaderNarrationProps> = ({ selector }) => {
export const ReaderNarration: React.FunctionComponent<ReaderNarrationProps> = ({ selector, inUseMode }) => {
const ref = React.useRef<HTMLElement>();
const [selectedNarrationPath, setSelectedNarrationPath] = React.useState(null);
const [narrationText, setNarrationText] = React.useState('');
const [narrationPath, setNarrationPath] = React.useState('');
const [narrationPaths, setNarrationPaths] = React.useState([]);

React.useEffect(() => {
if (!ref.current) {
return;
}

if (aomMissing) {
return;
}

const element = ref.current.ownerDocument.querySelector(selector) as IAriaElement;

// Compute and store the narrations for the element and its focusable descendants
// Computes and saves the narration paths and texts for the given parent element and its focusable descendants
const computeAndSave = React.useCallback(element => {
computer.compute(element, 'Win/JAWS').then(narrations => {
const paths: string[] = [];
narrationPaths = [];
narrationTexts = {};
narrations.forEach(narration => {
// Begin forEach 1
const path = narration.path.join(' > ');
paths.push(path);
narrationPaths.push(path);
narrationTexts[path] = narration.text;
}); // End forEach 1

// Update the narration paths dropdown values
setNarrationPaths(paths);
// If narration path has not been selected by user, preselect the first path and its associated narration as defaults
const text = narrationPath == null ? narrations[0]?.text || null : narrationTexts[narrationPath];
if (narrationPath == null && narrationPaths.length > 1) {
// Begin if 1
setSelectedNarrationPath(narrationPaths[0]);
} // End if 1

// If some narration has been retrieved, choose the first one as the narration to be displayed
const text = narrations[0]?.text || null;
setCompleteText(text);
}); // End compute
});
}, []); // End computeAndSave

// Composes and sets the complete screen reader narration text to be displayed
// Sets the complete screen reader narration text to be displayed.
const setCompleteText = text => {
setNarrationText(`Narration: ${text}`);
setNarrationText(text !== null ? `Narration: ${text}` : null);
}; // End setCompleteText

// Handles the "focusin" event by computing and saving the narration paths and texts.
const handleFocusIn = React.useCallback(
event => {
computeAndSave(event.target as IAriaElement);
},
[computeAndSave],
); // End handleFocusIn

// Handles the narration path dropdown change event by saving the narration path.
const handleNarrationPathChange = (event: any, props: DropdownProps) => {
setNarrationPath(props.value as string);
const text = narrationTexts[props.value as string];
narrationPath = props.value as string;
setSelectedNarrationPath(narrationPath);
const text = narrationTexts[narrationPath];
setCompleteText(text);
}; // End handleNarrationPathChange

if (!selector) {
// Recomputes the narration paths and texts upon every render.
React.useEffect(() => {
if (inUseMode || !ref.current || aomMissing) {
return;
}

// Compute and save the narration paths and texts for the selected component's parent element and its focusable descendants
const element = ref.current.ownerDocument.querySelector(selector) as IAriaElement;
computeAndSave(element);
}); // End useEffect

// Resets the narration path to its defaults if selector changes.
React.useEffect(() => {
narrationPath = null;
}, [selector]); // End useEffect

// If in the use mode, sets up the "focusin" event listener.
React.useEffect(() => {
const alert = ref.current;
if (!inUseMode || !alert) {
return null;
}
alert.ownerDocument.addEventListener('focusin', handleFocusIn);
return () => {
alert.ownerDocument.removeEventListener('focusin', handleFocusIn);
}; // End return
}, [inUseMode, handleFocusIn]); // End useEffect

if (selector == null && !inUseMode) {
return null;
}

return (
<>
{narrationPaths.length > 1 && (
<Dropdown
items={narrationPaths}
defaultValue={narrationPath}
value={narrationPath}
defaultValue={selectedNarrationPath}
value={selectedNarrationPath}
onChange={handleNarrationPathChange}
getA11ySelectionMessage={{
onAdd: item => `${item} has been selected.`,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,9 +28,9 @@ export class DescendantsNarrationsComputer {
// Begin if 1
parents.push(element);
} // End if 1
Array.from(element.children).forEach((child: IAriaElement) => {
Array.from(element.children).forEach(child => {
// Begin foreach 1
this.findActiveDescendantsParents(child, parents);
this.findActiveDescendantsParents(child as IAriaElement, parents);
}); // End foreach 1
} // End findActiveDescendantsParents

Expand Down