From 7ae0972c2871a2d5d73682da88bef10875768879 Mon Sep 17 00:00:00 2001 From: evykassirer Date: Thu, 20 Jun 2024 14:31:18 -0700 Subject: [PATCH] typeahead: Hide by default and show container on `show()`. This avoids a bug (currently only for search) where the page can be loaded with an empty but visible (half-loaded) search typeahead. --- web/src/bootstrap_typeahead.ts | 92 +++++++++++---------- web/third/bootstrap-typeahead/typeahead.css | 1 + 2 files changed, 48 insertions(+), 45 deletions(-) diff --git a/web/src/bootstrap_typeahead.ts b/web/src/bootstrap_typeahead.ts index 201cd20bbd..8feeba8c87 100644 --- a/web/src/bootstrap_typeahead.ts +++ b/web/src/bootstrap_typeahead.ts @@ -335,53 +335,55 @@ export class Typeahead { } this.mouse_moved_since_typeahead = false; - if (this.non_tippy_parent_element) { - this.$container.show(); - // We don't need tippy to position typeaheads which already know where they should be. - return this; + if (!this.non_tippy_parent_element) { + this.instance = tippy.default(this.input_element.$element[0]!, { + // Lets typeahead take the width needed to fit the content + // and wraps it if it overflows the visible container. + maxWidth: "none", + delay: [0, 0], + theme: "popover-menu", + placement: this.dropup ? "top-start" : "bottom-start", + popperOptions: { + strategy: "fixed", + modifiers: [ + { + // This will only work if there is enough space on the fallback + // placement, otherwise `preventOverflow` will be used to position + // it in the visible space. + name: "flip", + options: { + fallbackPlacements: ["top-start", "bottom-start"], + }, + }, + { + name: "preventOverflow", + options: { + // This seems required to prevent overflow, maybe because our + // placements are not the usual top, bottom, left, right. + // https://popper.js.org/docs/v2/modifiers/prevent-overflow/#altaxis + altAxis: true, + }, + }, + ], + }, + interactive: true, + appendTo: () => document.body, + showOnCreate: true, + content: this.$container[0]!, + // We expect the typeahead creator to handle when to hide / show the typeahead. + trigger: "manual", + arrow: false, + offset: [0, 0], + // We have event handlers to hide the typeahead, so we + // don't want tippy to hide it for us. + hideOnClick: false, + }); } - this.instance = tippy.default(this.input_element.$element[0]!, { - // Lets typeahead take the width needed to fit the content - // and wraps it if it overflows the visible container. - maxWidth: "none", - delay: [0, 0], - theme: "popover-menu", - placement: this.dropup ? "top-start" : "bottom-start", - popperOptions: { - strategy: "fixed", - modifiers: [ - { - // This will only work if there is enough space on the fallback placement, otherwise - // `preventOverflow` will be used to position it in the visible space. - name: "flip", - options: { - fallbackPlacements: ["top-start", "bottom-start"], - }, - }, - { - name: "preventOverflow", - options: { - // This seems required to prevent overflow, maybe because our placements are - // not the usual top, bottom, left, right. - // https://popper.js.org/docs/v2/modifiers/prevent-overflow/#altaxis - altAxis: true, - }, - }, - ], - }, - interactive: true, - appendTo: () => document.body, - showOnCreate: true, - content: this.$container[0]!, - // We expect the typeahead creator to handle when to hide / show the typeahead. - trigger: "manual", - arrow: false, - offset: [0, 0], - // We have event handlers to hide the typeahead, so we - // don't want tippy to hide it for us. - hideOnClick: false, - }); + // The container has `display: none` as a default style. We make sure to display + // it. For tippy elements, this must happen after we insert the typeahead into + // the DOM. + this.$container.show(); return this; } diff --git a/web/third/bootstrap-typeahead/typeahead.css b/web/third/bootstrap-typeahead/typeahead.css index dfdb035a83..e22e174bdf 100644 --- a/web/third/bootstrap-typeahead/typeahead.css +++ b/web/third/bootstrap-typeahead/typeahead.css @@ -1,6 +1,7 @@ /* CSS for Bootstrap typeahead */ .dropdown-menu { + display: none; padding: 5px 0; min-width: 160px; list-style: none;