Fix accessibility regressions (#7336)

* Fix room list roving treeview

New TooltipTarget & TextWithTooltip were not roving-accessible

* Fix programmatic focus management in roving tab index not triggering onFocus handler

* Fix toolbar no longer handling left & right arrows

* Fix roving tab index focus tracking on interactive element like context menu trigger

* Fix thread list context menu roving

* add comment

* fix comment

* Fix handling vertical arrows in the wrong direction

* iterate PR

* delint

* tidy up
This commit is contained in:
Michael Telatynski 2021-12-14 14:27:35 +00:00 committed by GitHub
parent 60286f6170
commit a667677c57
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
8 changed files with 103 additions and 58 deletions

View file

@ -131,6 +131,8 @@ export const reducer = (state: IState, action: IAction) => {
}
case Type.SetFocus: {
// if the ref doesn't change just return the same object reference to skip a re-render
if (state.activeRef === action.payload.ref) return state;
// update active ref
state.activeRef = action.payload.ref;
return { ...state };
@ -194,6 +196,7 @@ export const RovingTabIndexProvider: React.FC<IProps> = ({
}
let handled = false;
let focusRef: RefObject<HTMLElement>;
// Don't interfere with input default keydown behaviour
if (ev.target.tagName !== "INPUT" && ev.target.tagName !== "TEXTAREA") {
// check if we actually have any items
@ -202,7 +205,7 @@ export const RovingTabIndexProvider: React.FC<IProps> = ({
if (handleHomeEnd) {
handled = true;
// move focus to first (visible) item
findSiblingElement(context.state.refs, 0)?.current?.focus();
focusRef = findSiblingElement(context.state.refs, 0);
}
break;
@ -210,28 +213,30 @@ export const RovingTabIndexProvider: React.FC<IProps> = ({
if (handleHomeEnd) {
handled = true;
// move focus to last (visible) item
findSiblingElement(context.state.refs, context.state.refs.length - 1, true)?.current?.focus();
}
break;
case Key.ARROW_UP:
case Key.ARROW_RIGHT:
if ((ev.key === Key.ARROW_UP && handleUpDown) || (ev.key === Key.ARROW_RIGHT && handleLeftRight)) {
handled = true;
if (context.state.refs.length > 0) {
const idx = context.state.refs.indexOf(context.state.activeRef);
findSiblingElement(context.state.refs, idx - 1)?.current?.focus();
}
focusRef = findSiblingElement(context.state.refs, context.state.refs.length - 1, true);
}
break;
case Key.ARROW_DOWN:
case Key.ARROW_LEFT:
if ((ev.key === Key.ARROW_DOWN && handleUpDown) || (ev.key === Key.ARROW_LEFT && handleLeftRight)) {
case Key.ARROW_RIGHT:
if ((ev.key === Key.ARROW_DOWN && handleUpDown) ||
(ev.key === Key.ARROW_RIGHT && handleLeftRight)
) {
handled = true;
if (context.state.refs.length > 0) {
const idx = context.state.refs.indexOf(context.state.activeRef);
findSiblingElement(context.state.refs, idx + 1, true)?.current?.focus();
focusRef = findSiblingElement(context.state.refs, idx + 1);
}
}
break;
case Key.ARROW_UP:
case Key.ARROW_LEFT:
if ((ev.key === Key.ARROW_UP && handleUpDown) || (ev.key === Key.ARROW_LEFT && handleLeftRight)) {
handled = true;
if (context.state.refs.length > 0) {
const idx = context.state.refs.indexOf(context.state.activeRef);
focusRef = findSiblingElement(context.state.refs, idx - 1, true);
}
}
break;
@ -242,7 +247,18 @@ export const RovingTabIndexProvider: React.FC<IProps> = ({
ev.preventDefault();
ev.stopPropagation();
}
}, [context.state, onKeyDown, handleHomeEnd, handleUpDown, handleLeftRight]);
if (focusRef) {
focusRef.current?.focus();
// programmatic focus doesn't fire the onFocus handler, so we must do the do ourselves
dispatch({
type: Type.SetFocus,
payload: {
ref: focusRef,
},
});
}
}, [context, onKeyDown, handleHomeEnd, handleUpDown, handleLeftRight]);
return <RovingTabIndexContext.Provider value={context}>
{ children({ onKeyDownHandler }) }
@ -283,7 +299,7 @@ export const useRovingTabIndex = (inputRef?: Ref): [FocusHandler, boolean, Ref]
type: Type.SetFocus,
payload: { ref },
});
}, [ref, context]);
}, []); // eslint-disable-line react-hooks/exhaustive-deps
const isActive = context.state.activeRef === ref;
return [onFocus, isActive, ref];

View file

@ -52,7 +52,7 @@ const Toolbar: React.FC<IProps> = ({ children, ...props }) => {
}
};
return <RovingTabIndexProvider handleHomeEnd={true} onKeyDown={onKeyDown}>
return <RovingTabIndexProvider handleHomeEnd handleLeftRight onKeyDown={onKeyDown}>
{ ({ onKeyDownHandler }) => <div {...props} onKeyDown={onKeyDownHandler} role="toolbar">
{ children }
</div> }