diff --git a/app/assets/javascripts/discourse/app/components/search-menu-panel.hbs b/app/assets/javascripts/discourse/app/components/search-menu-panel.hbs index 51d562c165e..e5009a35c21 100644 --- a/app/assets/javascripts/discourse/app/components/search-menu-panel.hbs +++ b/app/assets/javascripts/discourse/app/components/search-menu-panel.hbs @@ -1,6 +1,6 @@ diff --git a/app/assets/javascripts/discourse/app/components/search-menu.js b/app/assets/javascripts/discourse/app/components/search-menu.js index 4987b2980a3..91df1cbb19c 100644 --- a/app/assets/javascripts/discourse/app/components/search-menu.js +++ b/app/assets/javascripts/discourse/app/components/search-menu.js @@ -51,24 +51,30 @@ export default class SearchMenu extends Component { @bind setupEventListeners() { - document.addEventListener("mousedown", this.onDocumentPress, true); - document.addEventListener("touchend", this.onDocumentPress, { - capture: true, - passive: true, - }); + // We only need to register click events when the search menu is rendered outside of the header. + // The header handles clicking outside. + if (!this.args.inlineResults) { + document.addEventListener("mousedown", this.onDocumentPress); + document.addEventListener("touchend", this.onDocumentPress); + } } willDestroy() { - document.removeEventListener("mousedown", this.onDocumentPress); - document.removeEventListener("touchend", this.onDocumentPress); - + if (!this.args.inlineResults) { + document.removeEventListener("mousedown", this.onDocumentPress); + document.removeEventListener("touchend", this.onDocumentPress); + } super.willDestroy(...arguments); } @bind onDocumentPress(event) { + if (!this.menuPanelOpen) { + return; + } + if (!event.target.closest(".search-menu-container.menu-panel-results")) { - this.menuPanelOpen = false; + this.close(); } } @@ -100,13 +106,13 @@ export default class SearchMenu extends Component { @action close() { - if (this.args?.closeSearchMenu) { - return this.args.closeSearchMenu(); + if (this.args?.onClose) { + return this.args.onClose(); } - // We want to blur the active element (search input) when in stand-alone mode + // We want to blur the search input when in stand-alone mode // so that when we focus on the search input again, the menu panel pops up - document.activeElement.blur(); + document.getElementById(SEARCH_INPUT_ID)?.blur(); this.menuPanelOpen = false; } diff --git a/app/assets/javascripts/discourse/tests/integration/components/search-menu-test.gjs b/app/assets/javascripts/discourse/tests/integration/components/search-menu-test.gjs index 1a953b3d05b..e477ddc946f 100644 --- a/app/assets/javascripts/discourse/tests/integration/components/search-menu-test.gjs +++ b/app/assets/javascripts/discourse/tests/integration/components/search-menu-test.gjs @@ -55,4 +55,27 @@ module("Integration | Component | search-menu", function (hooks) { "Clicking the term brought back search results" ); }); + + test("clicking outside results hides and blurs input", async function (assert) { + await render(); + await click("#search-term"); + + assert.strictEqual( + document.activeElement, + query("#search-term"), + "Clicking the search term input focuses it" + ); + + await click("#click-me"); + + assert.strictEqual( + document.activeElement, + document.body, + "Clicking outside blurs focus and closes panel" + ); + assert.notOk( + exists(".menu-panel .search-menu-initial-options"), + "Menu panel is hidden" + ); + }); });