Keyboard shortcuts and accessibility
This commit is contained in:
parent
8590a047c7
commit
20a892247f
87 changed files with 3652 additions and 711 deletions
|
@ -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}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue