[MM-61577]: Ensure all interactive functionality is operable with the keyboard in emoji picker (#29629)

Этот коммит содержится в:
Saurabh Sharma
2025-02-03 12:26:49 +05:30
коммит произвёл GitHub
родитель 316cde2569
Коммит e8e40c79f6
14 изменённых файлов: 64 добавлений и 36 удалений

Просмотреть файл

@@ -134,7 +134,9 @@ exports[`components/emoji_picker/EmojiPicker should match snapshot 1`] = `
style="height: 290px;"
>
<div
aria-labelledby="emojiPickerSearch"
class="emoji-picker__container"
role="grid"
>
<div
style="overflow: visible; height: 0px; width: 0px;"

Просмотреть файл

@@ -35,6 +35,7 @@ function EmojiPickerCategoryOrEmojiRow({index, style, data, cursorRowIndex, curs
<div
style={style}
className='emoji-picker__row'
role='row'
>
{row.items.map((emojiColumn) => {
const emoji = emojiColumn.item;

Просмотреть файл

@@ -17,6 +17,7 @@ function EmojiPickerCategoryRow({categoryName, style}: Props) {
<div
className='emoji-picker-items__container'
style={style}
role='row'
>
<div
className='emoji-picker__category-header'

Просмотреть файл

@@ -91,7 +91,11 @@ const EmojiPickerCurrentResults = forwardRef<InfiniteLoader, Props>(({categoryOr
className='emoji-picker__items'
style={{height: EMOJI_CONTAINER_HEIGHT}}
>
<div className='emoji-picker__container'>
<div
className='emoji-picker__container'
role='grid'
aria-labelledby='emojiPickerSearch'
>
<AutoSizer>
{({height, width}) => (
<InfiniteLoader

Просмотреть файл

@@ -55,32 +55,21 @@ function EmojiPickerItem({emoji, rowIndex, isSelected, onClick, onMouseOver}: Pr
let content;
if (isSystemEmoji(emoji)) {
const emojiName = emoji.short_name ? emoji.short_name : emoji.name;
const emojiUnified = emoji.unified ? emoji.unified.toLowerCase() : emoji.name.toLowerCase();
content = (
<img
alt={'emoji image'}
alt={`${emoji.name.toLocaleLowerCase()} emoji`}
data-testid={emoji.short_names}
src={imgTrans}
className={`emojisprite emoji-category-${emoji.category} emoji-${emojiUnified}`}
id={`emoji-${emojiUnified}`}
aria-label={formatMessage(
{
id: 'emoji_picker_item.emoji_aria_label',
defaultMessage: '{emojiName} emoji',
},
{
emojiName: (emojiName).replace(/_/g, ' '),
},
)}
role='button'
/>
);
} else {
content = (
<img
alt={'custom emoji image'}
alt={'custom emoji'}
data-testid={emoji.name}
src={getEmojiImageUrl(emoji)}
className={'emoji-category--custom'}
@@ -89,15 +78,26 @@ function EmojiPickerItem({emoji, rowIndex, isSelected, onClick, onMouseOver}: Pr
}
return (
<div
<button
className={itemClassName}
onClick={handleClick}
onMouseOver={throttledMouseOver}
data-testid='emojiItem'
tabIndex={-1}
type='button'
id={emoji.name.toLocaleLowerCase().replaceAll(' ', '_')}
aria-label={formatMessage(
{
id: 'emoji_picker_item.emoji_aria_label',
defaultMessage: '{emojiName} emoji',
},
{
emojiName: (isSystemEmoji(emoji) ? emoji.short_name : emoji.name).replace(/_/g, ' '),
},
)}
>
<div data-testid='emojiItem'>
{content}
</div>
</div>
{content}
</button>
);
}

Просмотреть файл

@@ -13,6 +13,8 @@ import {useIntl} from 'react-intl';
import {EMOJI_PER_ROW} from 'components/emoji_picker/constants';
import {NavigationDirection} from 'components/emoji_picker/types';
import Constants from 'utils/constants';
interface Props {
value: string;
cursorCategoryIndex: number;
@@ -24,6 +26,8 @@ interface Props {
resetCursorPosition: () => void;
}
const KeyCodes = Constants.KeyCodes;
const EmojiPickerSearch = forwardRef<HTMLInputElement, Props>(({value, cursorCategoryIndex, cursorEmojiIndex, onChange, resetCursorPosition, onKeyDown, focus, onEnter}: Props, ref) => {
const {formatMessage} = useIntl();
@@ -39,7 +43,7 @@ const EmojiPickerSearch = forwardRef<HTMLInputElement, Props>(({value, cursorCat
const handleKeyDown = (event: KeyboardEvent<HTMLInputElement>) => {
switch (event.key) {
case 'ArrowRight':
case KeyCodes.RIGHT[0]:
// If the cursor is at the end of the textbox and an emoji is currently selected, move it to the next emoji
if ((event.currentTarget?.selectionStart ?? 0) + 1 > value.length || (cursorCategoryIndex !== -1 || cursorEmojiIndex !== -1)) {
event.stopPropagation();
@@ -48,7 +52,7 @@ const EmojiPickerSearch = forwardRef<HTMLInputElement, Props>(({value, cursorCat
onKeyDown(NavigationDirection.NextEmoji);
}
break;
case 'ArrowLeft':
case KeyCodes.LEFT[0]:
if (cursorCategoryIndex > 0 || cursorEmojiIndex > 0) {
event.stopPropagation();
event.preventDefault();
@@ -65,7 +69,7 @@ const EmojiPickerSearch = forwardRef<HTMLInputElement, Props>(({value, cursorCat
focus();
}
break;
case 'ArrowUp':
case KeyCodes.UP[0]:
event.stopPropagation();
event.preventDefault();
@@ -88,7 +92,7 @@ const EmojiPickerSearch = forwardRef<HTMLInputElement, Props>(({value, cursorCat
onKeyDown(NavigationDirection.PreviousEmojiRow);
}
break;
case 'ArrowDown':
case KeyCodes.DOWN[0]:
event.stopPropagation();
event.preventDefault();
@@ -104,7 +108,14 @@ const EmojiPickerSearch = forwardRef<HTMLInputElement, Props>(({value, cursorCat
onKeyDown(NavigationDirection.NextEmojiRow);
}
break;
case 'Enter': {
case KeyCodes.SPACE[0]: {
event.stopPropagation();
event.preventDefault();
onEnter();
break;
}
case KeyCodes.ENTER[0]: {
event.stopPropagation();
event.preventDefault();

Просмотреть файл

@@ -340,6 +340,7 @@ const EmojiPicker = ({
return;
}
searchInputRef.current?.setAttribute('aria-activedescendant', newCursorEmoji.name.toLocaleLowerCase().replaceAll(' ', '_'));
setCursor({
rowIndex: newCursor.rowIndex,
emojiId: newCursor.emojiId,

Просмотреть файл

@@ -29,6 +29,7 @@ const PostEmoji = ({children, name, imageUrl}: Props) => {
className='emoticon'
data-testid={`postEmoji.${emojiText}`}
style={{backgroundImage: backgroundImageUrl}}
aria-label={emojiText}
>
{children}
</span>

Просмотреть файл

@@ -538,7 +538,9 @@ $emoji-footer-height: $emoji-footer-border-width + $emoji-half-height + $emoji-
height: 36px;
align-items: center;
justify-content: center;
border: none;
border-radius: 3px;
background-color: transparent;
cursor: pointer;
vertical-align: middle;