From 44df5ee7c84cb6591dfccbf1f3d26bb723690b4b Mon Sep 17 00:00:00 2001 From: Jan Cernik <66427541+jancernik@users.noreply.github.com> Date: Fri, 3 Feb 2023 11:36:45 -0300 Subject: [PATCH] FIX: Allow keyboard navigation when searching emojis in chat (#20157) --- .../components/chat-emoji-picker.hbs | 53 ++++++------- .../discourse/components/chat-emoji-picker.js | 11 ++- .../stylesheets/common/chat-emoji-picker.scss | 8 +- .../components/chat-emoji-picker-test.js | 76 +++++++++++++++++-- 4 files changed, 115 insertions(+), 33 deletions(-) diff --git a/plugins/chat/assets/javascripts/discourse/components/chat-emoji-picker.hbs b/plugins/chat/assets/javascripts/discourse/components/chat-emoji-picker.hbs index e274c58f932..f4066e0e824 100644 --- a/plugins/chat/assets/javascripts/discourse/components/chat-emoji-picker.hbs +++ b/plugins/chat/assets/javascripts/discourse/components/chat-emoji-picker.hbs @@ -116,34 +116,36 @@
{{#if (gte this.filteredEmojis.length 0)}} - {{#each this.filteredEmojis as |emoji|}} - {{emoji.name}} - {{else}} -

- {{i18n "chat.emoji_picker.no_results"}} -

- {{/each}} +
+ {{#each this.filteredEmojis as |emoji|}} + {{emoji.name}} + {{else}} +

+ {{i18n "chat.emoji_picker.no_results"}} +

+ {{/each}} +
{{/if}} {{#each-in this.groups as |section emojis|}} @@ -158,7 +160,6 @@ (concat "chat.emoji_picker." section) translatedFallback=section }} - {{on "keydown" this.didNavigateSection}} >

{{i18n diff --git a/plugins/chat/assets/javascripts/discourse/components/chat-emoji-picker.js b/plugins/chat/assets/javascripts/discourse/components/chat-emoji-picker.js index 97ac5cd5b67..2c678e9d4bc 100644 --- a/plugins/chat/assets/javascripts/discourse/components/chat-emoji-picker.js +++ b/plugins/chat/assets/javascripts/discourse/components/chat-emoji-picker.js @@ -231,6 +231,15 @@ export default class ChatEmojiPicker extends Component { }); } + @action + onSectionsKeyDown(event) { + if (event.key === "Enter") { + this.didSelectEmoji(event); + } else { + this.didNavigateSection(event); + } + } + @action didNavigateSection(event) { const sectionsEmojis = (section) => [...section.querySelectorAll(".emoji")]; @@ -247,7 +256,7 @@ export default class ChatEmojiPicker extends Component { }; const allEmojis = () => [ ...document.querySelectorAll( - ".chat-emoji-picker__scrollable-content .emoji" + ".chat-emoji-picker__section:not(.hidden) .emoji" ), ]; diff --git a/plugins/chat/assets/stylesheets/common/chat-emoji-picker.scss b/plugins/chat/assets/stylesheets/common/chat-emoji-picker.scss index bc61941f3a4..45866b708ed 100644 --- a/plugins/chat/assets/stylesheets/common/chat-emoji-picker.scss +++ b/plugins/chat/assets/stylesheets/common/chat-emoji-picker.scss @@ -98,7 +98,8 @@ } } - &__section-emojis { + &__section-emojis, + &__section.filtered { padding: 0.5rem; } @@ -164,18 +165,23 @@ &.t1 { background: #ffcc4d; } + &.t2 { background: #f7dece; } + &.t3 { background: #f3d2a2; } + &.t4 { background: #d5ab88; } + &.t5 { background: #af7e57; } + &.t6 { background: #7c533e; } diff --git a/plugins/chat/test/javascripts/components/chat-emoji-picker-test.js b/plugins/chat/test/javascripts/components/chat-emoji-picker-test.js index 134fdf8f147..6856da9c522 100644 --- a/plugins/chat/test/javascripts/components/chat-emoji-picker-test.js +++ b/plugins/chat/test/javascripts/components/chat-emoji-picker-test.js @@ -3,7 +3,7 @@ import { exists, query, queryAll } from "discourse/tests/helpers/qunit-helpers"; import hbs from "htmlbars-inline-precompile"; import { module, test } from "qunit"; import pretender from "discourse/tests/helpers/create-pretender"; -import { click, fillIn, render } from "@ember/test-helpers"; +import { click, fillIn, render, triggerKeyEvent } from "@ember/test-helpers"; function emojisResponse() { return { @@ -138,26 +138,26 @@ module("Discourse Chat | Component | chat-emoji-picker", function (hooks) { await fillIn(".dc-filter-input", "grinning"); assert.strictEqual( - queryAll(".chat-emoji-picker__sections > img").length, + queryAll(".chat-emoji-picker__section.filtered > img").length, 1, "it filters the emojis list" ); assert.true( - exists('.chat-emoji-picker__sections > img[alt="grinning"]'), + exists('.chat-emoji-picker__section.filtered > img[alt="grinning"]'), "it filters the correct emoji" ); await fillIn(".dc-filter-input", "Grinning"); assert.true( - exists('.chat-emoji-picker__sections > img[alt="grinning"]'), + exists('.chat-emoji-picker__section.filtered > img[alt="grinning"]'), "it is case insensitive" ); await fillIn(".dc-filter-input", "smiley_cat"); assert.true( - exists('.chat-emoji-picker__sections > img[alt="grinning"]'), + exists('.chat-emoji-picker__section.filtered > img[alt="grinning"]'), "it filters the correct emoji using search alias" ); }); @@ -173,6 +173,72 @@ module("Discourse Chat | Component | chat-emoji-picker", function (hooks) { assert.strictEqual(selection, "grinning"); }); + test("When navigating sections", async function (assert) { + await render(hbs``); + + await triggerKeyEvent(document.activeElement, "keydown", "ArrowDown"); + assert.strictEqual( + document.activeElement.dataset.emoji, + "grinning", + "ArrowDown focuses on the first favorite emoji" + ); + + await triggerKeyEvent(document.activeElement, "keydown", "ArrowDown"); + await triggerKeyEvent(document.activeElement, "keydown", "ArrowDown"); + assert.strictEqual( + document.activeElement.dataset.emoji, + "raised_hands", + "ArrowDown focuses on the first emoji form the third section" + ); + + await triggerKeyEvent(document.activeElement, "keydown", "ArrowRight"); + assert.strictEqual( + document.activeElement.dataset.emoji, + "man_rowing_boat", + "ArrowRight focuses on the emoji at the right" + ); + + await triggerKeyEvent(document.activeElement, "keydown", "ArrowLeft"); + assert.strictEqual( + document.activeElement.dataset.emoji, + "raised_hands", + "ArrowLeft focuses on the emoji at the left" + ); + + await triggerKeyEvent(document.activeElement, "keydown", "ArrowUp"); + assert.strictEqual( + document.activeElement.dataset.emoji, + "grinning", + "ArrowUp focuses on the first emoji form the second section" + ); + }); + + test("When navigating filtered emojis", async function (assert) { + await render(hbs``); + await fillIn(".dc-filter-input", "man"); + + await triggerKeyEvent(document.activeElement, "keydown", "ArrowDown"); + assert.strictEqual( + document.activeElement.dataset.emoji, + "man_rowing_boat", + "ArrowDown focuses on the first filtered emoji" + ); + + await triggerKeyEvent(document.activeElement, "keydown", "ArrowRight"); + assert.strictEqual( + document.activeElement.dataset.emoji, + "womans_clothes", + "ArrowRight focuses on the emoji at the right" + ); + + await triggerKeyEvent(document.activeElement, "keydown", "ArrowLeft"); + assert.strictEqual( + document.activeElement.dataset.emoji, + "man_rowing_boat", + "ArrowLeft focuses on the emoji at the left" + ); + }); + test("When selecting a toned an emoji", async function (assert) { let selection; this.chatEmojiPickerManager.didSelectEmoji = (emoji) => {