UX: improves arrow support in chat emoji picker (#19038)

This commit is contained in:
Joffrey JAFFEUX 2022-11-16 08:52:48 +01:00 committed by GitHub
parent 87b297e76c
commit df7730d938
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 72 additions and 28 deletions

View File

@ -86,7 +86,7 @@ export default class ChatEmojiPicker extends Component {
} }
@action @action
trapKeyUpEvents(event) { trapKeyDownEvents(event) {
if (event.key === "Escape") { if (event.key === "Escape") {
this.chatEmojiPickerManager.close(); this.chatEmojiPickerManager.close();
} }
@ -94,6 +94,20 @@ export default class ChatEmojiPicker extends Component {
if (event.key === "ArrowUp") { if (event.key === "ArrowUp") {
event.stopPropagation(); event.stopPropagation();
} }
if (
event.key === "ArrowDown" &&
event.target.classList.contains("dc-filter-input")
) {
event.stopPropagation();
event.preventDefault();
document
.querySelector(
`.chat-emoji-picker__scrollable-content .emoji[tabindex="0"]`
)
?.focus();
}
} }
@action @action
@ -224,29 +238,51 @@ export default class ChatEmojiPicker extends Component {
@action @action
didNavigateSection(event) { didNavigateSection(event) {
const sectionEmojis = [ const sectionsEmojis = (section) => [...section.querySelectorAll(".emoji")];
...event.target const focusSectionsLastEmoji = (section) => {
.closest(".chat-emoji-picker__section") const emojis = sectionsEmojis(section);
.querySelectorAll(".emoji"), return emojis[emojis.length - 1].focus();
};
const focusSectionsFirstEmoji = (section) => {
sectionsEmojis(section)[0].focus();
};
const currentSection = event.target.closest(".chat-emoji-picker__section");
const focusFilter = () => {
document.querySelector(".dc-filter-input")?.focus();
};
const allEmojis = () => [
...document.querySelectorAll(
".chat-emoji-picker__scrollable-content .emoji"
),
]; ];
if (event.key === "ArrowRight") { if (event.key === "ArrowRight") {
event.preventDefault(); event.preventDefault();
const nextEmoji = event.target.nextElementSibling;
if (event.target === sectionEmojis[sectionEmojis.length - 1]) { if (nextEmoji) {
sectionEmojis[0].focus(); nextEmoji.focus();
} else { } else {
event.target.nextElementSibling?.focus(); const nextSection = currentSection.nextElementSibling;
if (nextSection) {
focusSectionsFirstEmoji(nextSection);
}
} }
} }
if (event.key === "ArrowLeft") { if (event.key === "ArrowLeft") {
event.preventDefault(); event.preventDefault();
const prevEmoji = event.target.previousElementSibling;
if (event.target === sectionEmojis[0]) { if (prevEmoji) {
sectionEmojis[sectionEmojis.length - 1].focus(); prevEmoji.focus();
} else { } else {
event.target.previousElementSibling?.focus(); const prevSection = currentSection.previousElementSibling;
if (prevSection) {
focusSectionsLastEmoji(prevSection);
} else {
focusFilter();
}
} }
} }
@ -254,21 +290,36 @@ export default class ChatEmojiPicker extends Component {
event.preventDefault(); event.preventDefault();
event.stopPropagation(); event.stopPropagation();
sectionEmojis const nextEmoji = allEmojis()
.filter((c) => c.offsetTop > event.target.offsetTop) .filter((c) => c.offsetTop > event.target.offsetTop)
.find((c) => c.offsetLeft === event.target.offsetLeft) .findBy("offsetLeft", event.target.offsetLeft);
?.focus();
if (nextEmoji) {
nextEmoji.focus();
} else {
// for perf reason all emojis might not be loaded at this point
// but the first one will always be
const nextSection = currentSection.nextElementSibling;
if (nextSection) {
focusSectionsFirstEmoji(nextSection);
}
}
} }
if (event.key === "ArrowUp") { if (event.key === "ArrowUp") {
event.preventDefault(); event.preventDefault();
event.stopPropagation(); event.stopPropagation();
sectionEmojis const prevEmoji = allEmojis()
.reverse() .reverse()
.filter((c) => c.offsetTop < event.target.offsetTop) .filter((c) => c.offsetTop < event.target.offsetTop)
.find((c) => c.offsetLeft === event.target.offsetLeft) .findBy("offsetLeft", event.target.offsetLeft);
?.focus();
if (prevEmoji) {
prevEmoji.focus();
} else {
focusFilter();
}
} }
} }
@ -278,13 +329,9 @@ export default class ChatEmojiPicker extends Component {
return; return;
} }
if ( if (event.type === "click" || event.key === "Enter") {
event.type === "click" ||
(event.type === "keyup" && event.key === "Enter")
) {
event.preventDefault(); event.preventDefault();
event.stopPropagation(); event.stopPropagation();
const originalTarget = event.target;
let emoji = event.target.dataset.emoji; let emoji = event.target.dataset.emoji;
const tonable = event.target.dataset.tonable; const tonable = event.target.dataset.tonable;
const diversity = this.chatEmojiReactionStore.diversity; const diversity = this.chatEmojiReactionStore.diversity;
@ -293,10 +340,7 @@ export default class ChatEmojiPicker extends Component {
} }
this.chatEmojiPickerManager.didSelectEmoji(emoji); this.chatEmojiPickerManager.didSelectEmoji(emoji);
this.appEvents.trigger("chat:focus-composer");
schedule("afterRender", () => {
originalTarget.focus();
});
} }
} }

View File

@ -8,7 +8,7 @@
}} }}
{{did-insert this.addClickOutsideEventListener}} {{did-insert this.addClickOutsideEventListener}}
{{will-destroy this.removeClickOutsideEventListener}} {{will-destroy this.removeClickOutsideEventListener}}
{{on "keydown" this.trapKeyUpEvents}} {{on "keydown" this.trapKeyDownEvents}}
> >
<div class="chat-emoji-picker__filter-container"> <div class="chat-emoji-picker__filter-container">
<DcFilterInput <DcFilterInput
@ -109,7 +109,7 @@
<div <div
class="chat-emoji-picker__sections" class="chat-emoji-picker__sections"
{{on "click" this.didSelectEmoji}} {{on "click" this.didSelectEmoji}}
{{on "keyup" this.didSelectEmoji}} {{on "keydown" this.didSelectEmoji}}
role="button" role="button"
> >
{{#if (gte this.filteredEmojis.length 0)}} {{#if (gte this.filteredEmojis.length 0)}}