Skip to content

Commit

Permalink
a11y: add linkBtn to tab-order (#2717)
Browse files Browse the repository at this point in the history
* add inline link to tab order

* refactor code

Co-authored-by: Ben Yackley <61990921+beyackle@users.noreply.github.com>
  • Loading branch information
alanlong9278 and beyackle committed Apr 23, 2020
1 parent b69b954 commit 3d94f1c
Show file tree
Hide file tree
Showing 4 changed files with 47 additions and 5 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,13 @@ export enum AttrNames {
NodeElement = 'data-is-node',
EdgeMenuElement = 'data-is-edge-menu',
FocusedId = 'data-focused-id',
InlineLinkElement = 'data-is-inline-link',
SelectedId = 'data-selected-id',
Tab = 'data-tab',

// attrs for multi selection
FocusableElement = 'data-is-focusable',
SelectionIndex = 'data-selection-index',
}

export const LinkTag = 'link';
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.

import { KeyboardCommandTypes } from '../../constants/KeyboardCommandTypes';

import { SelectorElement, Direction } from './type';
Expand Down Expand Up @@ -32,20 +33,35 @@ function findSelectableParent(element: SelectorElement, elementList: SelectorEle

export function handleTabMove(currentElement: SelectorElement, selectableElements: SelectorElement[], command: string) {
let nextElement: SelectorElement;
const selectableChildren = findSelectableChildren(currentElement, selectableElements);
const selectableParent = findSelectableParent(currentElement, selectableElements);
const findElementWithSuffix = suffix => {
return selectableElements.find(element => element.selectedId === `${selectableParent?.selectedId}${suffix}`);
};
if (command === KeyboardCommandTypes.Cursor.MoveNext) {
const selectableChildren = findSelectableChildren(currentElement, selectableElements);
if (selectableChildren.length > 0) {
// Tab to inner selectable element.
nextElement = selectableChildren[0];
} else {
// Perform like presssing down arrow key.
nextElement = locateNearestElement(currentElement, selectableElements, Direction.Down, ['isNode', 'isEdgeMenu']);
const hasInlineLinkElement = currentElement.selectedId.endsWith('dot') && findElementWithSuffix('link');
if (hasInlineLinkElement) {
nextElement = findElementWithSuffix('link') || currentElement;
} else {
// Perform like presssing down arrow key.
nextElement = locateNearestElement(currentElement, selectableElements, Direction.Down, [
'isNode',
'isEdgeMenu',
]);
}
}
} else if (command === KeyboardCommandTypes.Cursor.MovePrevious) {
const selectableParent = findSelectableParent(currentElement, selectableElements);
if (selectableParent) {
// Tab to parent.
nextElement = selectableParent;
if (currentElement.isInlineLinkElement) {
nextElement = findElementWithSuffix('dot') || selectableParent;
} else {
nextElement = selectableParent;
}
} else {
// Perform like pressing up arrow key.
nextElement = locateNearestElement(currentElement, selectableElements, Direction.Up, ['isNode', 'isEdgeMenu']);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ export class SelectorElement {
isSelectable: string | null;
isNode: string | null;
isEdgeMenu: string | null;
isInlineLinkElement: string | null;
focusedId: string | null;
selectedId: string;
tab: string | null;
Expand All @@ -15,6 +16,7 @@ export class SelectorElement {
this.isSelectable = element.getAttribute(AttrNames.SelectableElement);
this.isNode = element.getAttribute(AttrNames.NodeElement);
this.isEdgeMenu = element.getAttribute(AttrNames.EdgeMenuElement);
this.isInlineLinkElement = element.getAttribute(AttrNames.InlineLinkElement);
this.focusedId = element.getAttribute(AttrNames.FocusedId);
this.selectedId = element.getAttribute(AttrNames.SelectedId) as string;
this.tab = element.getAttribute(AttrNames.Tab);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,22 +6,43 @@ import { jsx } from '@emotion/core';
import get from 'lodash/get';
import { WidgetContainerProps, WidgetComponent } from '@bfc/extension';
import { LinkBtn } from '@bfc/ui-shared';
import { useEffect, useContext, useRef } from 'react';
import { ILink } from 'office-ui-fabric-react/lib/Link';

import { NodeEventTypes } from '../constants/NodeEventTypes';
import { AttrNames, LinkTag } from '../constants/ElementAttributes';
import { SelectionContext } from '../store/SelectionContext';

export interface DialogRefCardProps extends WidgetContainerProps {
dialog: string | object;
getRefContent?: (dialogRef: JSX.Element | null) => JSX.Element;
}

export const DialogRef: WidgetComponent<DialogRefCardProps> = ({ id, onEvent, dialog, getRefContent }) => {
const linkBtnRef = useRef<ILink>(null);
const { selectedIds } = useContext(SelectionContext);
const nodeSelected = selectedIds.includes(`${id}${LinkTag}`);
const declareElementAttributes = (id: string) => {
return {
[AttrNames.SelectableElement]: true,
[AttrNames.InlineLinkElement]: true,
[AttrNames.SelectedId]: `${id}${LinkTag}`,
};
};
useEffect(() => {
if (nodeSelected) {
linkBtnRef.current?.focus();
}
});
const calleeDialog = typeof dialog === 'object' ? get(dialog, '$ref') : dialog;
const dialogRef = calleeDialog ? (
<LinkBtn
componentRef={linkBtnRef}
onClick={e => {
e.stopPropagation();
onEvent(NodeEventTypes.OpenDialog, { caller: id, callee: calleeDialog });
}}
{...declareElementAttributes(id)}
>
{calleeDialog}
</LinkBtn>
Expand Down

0 comments on commit 3d94f1c

Please sign in to comment.