diff --git a/app/assets/javascripts/discourse/app/components/emoji-picker.js b/app/assets/javascripts/discourse/app/components/emoji-picker.js index 48dde62dcee..3598b0575ea 100644 --- a/app/assets/javascripts/discourse/app/components/emoji-picker.js +++ b/app/assets/javascripts/discourse/app/components/emoji-picker.js @@ -38,6 +38,7 @@ export default Component.extend({ hoveredEmoji: null, isActive: false, usePopper: true, + placement: "auto", // one of popper.js' placements, see https://popper.js.org/docs/v2/constructors/#options initialFilter: "", init() { @@ -96,11 +97,9 @@ export default Component.extend({ return; } - const textareaWrapper = document.querySelector( - ".d-editor-textarea-wrapper" - ); + const popperAnchor = this._getPopperAnchor(); - if (!this.site.isMobileDevice && this.usePopper && textareaWrapper) { + if (!this.site.isMobileDevice && this.usePopper && popperAnchor) { const modifiers = [ { name: "preventOverflow", @@ -113,7 +112,10 @@ export default Component.extend({ }, ]; - if (window.innerWidth < textareaWrapper.clientWidth * 2) { + if ( + this.placement === "auto" && + window.innerWidth < popperAnchor.clientWidth * 2 + ) { modifiers.push({ name: "computeStyles", enabled: true, @@ -131,9 +133,8 @@ export default Component.extend({ }); } - this._popper = createPopper(textareaWrapper, emojiPicker, { - placement: "auto", - modifiers, + this._popper = createPopper(popperAnchor, emojiPicker, { + placement: this.placement, }); } @@ -338,6 +339,15 @@ export default Component.extend({ ); }, + _getPopperAnchor() { + // .d-editor-textarea-wrapper is only for backward compatibility here + // in new code use .emoji-picker-anchor + return ( + document.querySelector(".emoji-picker-anchor") ?? + document.querySelector(".d-editor-textarea-wrapper") + ); + }, + @bind handleOutsideClick(event) { const emojiPicker = document.querySelector(".emoji-picker"); diff --git a/app/assets/javascripts/discourse/tests/integration/components/emoji-picker-test.js b/app/assets/javascripts/discourse/tests/integration/components/emoji-picker-test.js new file mode 100644 index 00000000000..6f530a82377 --- /dev/null +++ b/app/assets/javascripts/discourse/tests/integration/components/emoji-picker-test.js @@ -0,0 +1,52 @@ +import componentTest, { + setupRenderingTest, +} from "discourse/tests/helpers/component-test"; +import { discourseModule, query } from "discourse/tests/helpers/qunit-helpers"; +import hbs from "htmlbars-inline-precompile"; +import { click } from "@ember/test-helpers"; + +discourseModule("Integration | Component | emoji-picker", function (hooks) { + setupRenderingTest(hooks); + + componentTest("when placement == bottom, places the picker on the bottom", { + template: hbs` + {{d-button class="emoji-picker-anchor" action=showEmojiPicker}} + {{emoji-picker isActive=pickerIsActive placement="bottom"}} + `, + + beforeEach() { + this.set("showEmojiPicker", () => { + this.set("pickerIsActive", true); + }); + }, + + async test(assert) { + await click(".emoji-picker-anchor"); + assert.equal( + query(".emoji-picker.opened").getAttribute("data-popper-placement"), + "bottom" + ); + }, + }); + + componentTest("when placement == right, places the picker on the right", { + template: hbs` + {{d-button class="emoji-picker-anchor" action=showEmojiPicker}} + {{emoji-picker isActive=pickerIsActive placement="right"}} + `, + + beforeEach() { + this.set("showEmojiPicker", () => { + this.set("pickerIsActive", true); + }); + }, + + async test(assert) { + await click(".emoji-picker-anchor"); + assert.equal( + query(".emoji-picker.opened").getAttribute("data-popper-placement"), + "right" + ); + }, + }); +});