mirror of
https://github.com/discourse/discourse.git
synced 2025-02-25 18:55:32 -06:00
UX: improves arrow support in chat emoji picker (#19038)
This commit is contained in:
parent
87b297e76c
commit
df7730d938
@ -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();
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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)}}
|
||||||
|
Loading…
Reference in New Issue
Block a user