diff --git a/web/src/sidebar_ui.ts b/web/src/sidebar_ui.ts index 46535f8508..4742a99641 100644 --- a/web/src/sidebar_ui.ts +++ b/web/src/sidebar_ui.ts @@ -24,6 +24,7 @@ export function hide_userlist_sidebar(): void { export function show_userlist_sidebar(): void { $(".app-main .column-right").addClass("expanded"); + fix_invite_user_button_flicker(); resize.resize_page_components(); right_sidebar_expanded_as_overlay = true; } @@ -59,6 +60,18 @@ export function hide_all(): void { hide_userlist_sidebar(); } +function fix_invite_user_button_flicker(): void { + // Keep right sidebar hidden after browser renders it to avoid + // flickering of "Invite more users" button. Since the user list + // is a complex component browser takes time for it to render + // causing the invite button to render first. + $("body").addClass("hide-right-sidebar-by-visibility"); + // Show the right sidebar after the browser has completed the above render. + setTimeout(() => { + $("body").removeClass("hide-right-sidebar-by-visibility"); + }, 0); +} + export function initialize(): void { $("body").on("click", ".login_button", (e) => { e.preventDefault(); @@ -72,6 +85,9 @@ export function initialize(): void { if (window.innerWidth >= media_breakpoints_num.xl) { $("body").toggleClass("hide-right-sidebar"); + if (!$("body").hasClass("hide-right-sidebar")) { + fix_invite_user_button_flicker(); + } return; } diff --git a/web/src/user_search.ts b/web/src/user_search.ts index b959b59c1e..65ad7eb937 100644 --- a/web/src/user_search.ts +++ b/web/src/user_search.ts @@ -115,7 +115,10 @@ export class UserSearch { initiate_search(): void { this.expand_column(); this.show_widget(); - this.$input.trigger("focus"); + // Needs to be called when input is visible after fix_invite_user_button_flicker. + setTimeout(() => { + this.$input.trigger("focus"); + }, 0); } toggle_filter_displayed(): void { diff --git a/web/styles/zulip.css b/web/styles/zulip.css index 872df84deb..a53545fc2d 100644 --- a/web/styles/zulip.css +++ b/web/styles/zulip.css @@ -2430,6 +2430,10 @@ select.invite-as { @extend %hide-right-sidebar; } +.hide-right-sidebar-by-visibility .app-main .column-right { + visibility: hidden; +} + @media (width < $xl_min) { .default-sidebar-behaviour { @extend %hide-right-sidebar; diff --git a/web/tests/user_search.test.js b/web/tests/user_search.test.js index 25e118439f..5011b71e9d 100644 --- a/web/tests/user_search.test.js +++ b/web/tests/user_search.test.js @@ -2,7 +2,7 @@ const {strict: assert} = require("assert"); -const {mock_esm, zrequire} = require("./lib/namespace"); +const {set_global, mock_esm, zrequire} = require("./lib/namespace"); const {run_test, noop} = require("./lib/test"); const $ = require("./lib/zjquery"); const {realm} = require("./lib/zpage_params"); @@ -25,6 +25,18 @@ mock_esm("../src/buddy_list", { buddy_list: fake_buddy_list, }); +function mock_setTimeout() { + let set_timeout_function_called = false; + set_global("setTimeout", (func) => { + if (set_timeout_function_called) { + // This conditional is needed to avoid indefinite calls. + return; + } + set_timeout_function_called = true; + func(); + }); +} + const popovers = mock_esm("../src/popovers"); const presence = mock_esm("../src/presence"); const resize = mock_esm("../src/resize"); @@ -130,6 +142,7 @@ test("blur search right", ({override}) => { override(sidebar_ui, "show_userlist_sidebar", noop); override(popovers, "hide_all", noop); override(resize, "resize_sidebars", noop); + mock_setTimeout(); $("input.user-list-filter").closest = (selector) => { assert.equal(selector, ".app-main [class^='column-']"); @@ -146,6 +159,7 @@ test("blur search left", ({override}) => { override(sidebar_ui, "show_streamlist_sidebar", noop); override(popovers, "hide_all", noop); override(resize, "resize_sidebars", noop); + mock_setTimeout(); $("input.user-list-filter").closest = (selector) => { assert.equal(selector, ".app-main [class^='column-']");