Keyboard shortcuts and accessibility

This commit is contained in:
Scott Nonnenberg 2019-11-07 13:36:16 -08:00
parent 8590a047c7
commit 20a892247f
87 changed files with 3652 additions and 711 deletions

View file

@ -33,7 +33,7 @@ export type OwnProps = {
export type Props = OwnProps & Pick<React.HTMLProps<HTMLDivElement>, 'style'>;
function focusRef(el: HTMLElement | null) {
function focusOnRender(el: HTMLElement | null) {
if (el) {
el.focus();
}
@ -69,6 +69,7 @@ export const EmojiPicker = React.memo(
}: Props,
ref
) => {
const focusRef = React.useRef<HTMLButtonElement>(null);
// Per design: memoize the initial recent emojis so the grid only updates after re-opening the picker.
const firstRecent = React.useMemo(() => {
return recentEmojis;
@ -140,11 +141,14 @@ export const EmojiPicker = React.memo(
// Handle escape key
React.useEffect(
() => {
const handler = (e: KeyboardEvent) => {
if (searchMode && e.key === 'Escape') {
const handler = (event: KeyboardEvent) => {
if (searchMode && event.key === 'Escape') {
setSearchText('');
setSearchMode(false);
setScrollToRow(0);
event.preventDefault();
event.stopPropagation();
} else if (
!searchMode &&
![
@ -155,21 +159,38 @@ export const EmojiPicker = React.memo(
'Shift',
'Tab',
' ', // Space
].includes(e.key)
].includes(event.key)
) {
onClose();
event.preventDefault();
event.stopPropagation();
}
};
document.addEventListener('keyup', handler);
document.addEventListener('keydown', handler);
return () => {
document.removeEventListener('keyup', handler);
document.removeEventListener('keydown', handler);
};
},
[onClose, searchMode]
);
// Restore focus on teardown
React.useEffect(() => {
const lastFocused = document.activeElement as any;
if (focusRef.current) {
focusRef.current.focus();
}
return () => {
if (lastFocused && lastFocused.focus) {
lastFocused.focus();
}
};
}, []);
const emojiGrid = React.useMemo(
() => {
if (searchText) {
@ -287,6 +308,7 @@ export const EmojiPicker = React.memo(
<div className="module-emoji-picker" ref={ref} style={style}>
<header className="module-emoji-picker__header">
<button
ref={focusRef}
onClick={handleToggleSearch}
title={i18n('EmojiPicker--search-placeholder')}
className={classNames(
@ -300,7 +322,7 @@ export const EmojiPicker = React.memo(
{searchMode ? (
<div className="module-emoji-picker__header__search-field">
<input
ref={focusRef}
ref={focusOnRender}
className="module-emoji-picker__header__search-field__input"
placeholder={i18n('EmojiPicker--search-placeholder')}
onChange={handleSearchChange}