Bug 1938249 - Disable expanded sidebar behaviour for horizontal tabs mode r=sidebar-reviewers,desktop-theme-reviewers,dao,jsudiaman,kcochrane

- disable expand behaviour for horizontal tabs mode
- remove expand/collapse option from customize panel when horizontal mode (follow up bug to land immediately after - bug 1939917)
- default horizontal mode to show/hide with the launcher visible initially
- default vertical mode to expand/collapse
- remove auto collapsing behviour when expanded and opening a panel

Differential Revision: https://phabricator.services.mozilla.com/D234592
This commit is contained in:
Nikki Sharpley
2025-01-24 21:34:33 +00:00
parent 7c97f38cc6
commit 463d047cea
11 changed files with 249 additions and 75 deletions

View File

@@ -6,6 +6,7 @@ import { AppConstants } from "resource://gre/modules/AppConstants.sys.mjs";
import { XPCOMUtils } from "resource://gre/modules/XPCOMUtils.sys.mjs";
const BACKUP_STATE_PREF = "sidebar.backupState";
const VISIBILITY_SETTING_PREF = "sidebar.visibility";
const lazy = {};
ChromeUtils.defineESModuleGetters(lazy, {
@@ -19,6 +20,12 @@ XPCOMUtils.defineLazyPreferenceGetter(
"sidebarBackupState",
BACKUP_STATE_PREF
);
XPCOMUtils.defineLazyPreferenceGetter(
lazy,
"verticalTabsEnabled",
"sidebar.verticalTabs",
false
);
export const SidebarManager = {
/**
@@ -66,6 +73,10 @@ export const SidebarManager = {
setPref(pref, lazy.NimbusFeatures[featureId].getVariable(pref))
);
});
if (!lazy.verticalTabsEnabled) {
Services.prefs.setStringPref(VISIBILITY_SETTING_PREF, "hide-sidebar");
}
},
/**

View File

@@ -2,6 +2,16 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
import { XPCOMUtils } from "resource://gre/modules/XPCOMUtils.sys.mjs";
const lazy = {};
XPCOMUtils.defineLazyPreferenceGetter(
lazy,
"verticalTabsEnabled",
"sidebar.verticalTabs"
);
/**
* The properties that make up a sidebar's UI state.
*
@@ -43,7 +53,6 @@ export class SidebarState {
launcherDragActive: false,
launcherHoverActive: false,
};
#previousExpandedState = false;
#previousLauncherVisible = undefined;
/**
@@ -103,11 +112,7 @@ export class SidebarState {
if (isPopup) {
// Don't show launcher if we're in a popup window.
this.launcherVisible = false;
} else if (this.revampVisibility === "hide-sidebar" && !this.panelOpen) {
// When using "Show and hide sidebar", launcher will start off hidden.
this.launcherVisible = false;
} else if (this.revampVisibility === "always-show") {
// When using "Expand and collapse sidebar", launcher must be visible.
} else {
this.launcherVisible = true;
}
// Ensure that tab container has the updated value of `launcherExpanded`.
@@ -188,19 +193,11 @@ export class SidebarState {
// Launcher must be visible to open a panel.
this.#previousLauncherVisible = this.launcherVisible;
this.launcherVisible = true;
// Whenever a panel is shown, the sidebar is collapsed. Upon hiding
// that panel afterwards, `expanded` reverts back to what it was prior
// to calling `show()`. Thus, we store the expanded state at this point.
this.#previousExpandedState = this.launcherExpanded;
this.launcherExpanded = false;
} else if (this.revampVisibility === "hide-sidebar") {
// When visibility is set to "Hide Sidebar", revert back to an expanded state except
// when a panel was opened via keyboard shortcut and the launcher was previously hidden.
this.launcherExpanded = this.#previousLauncherVisible;
this.launcherExpanded = lazy.verticalTabsEnabled
? this.#previousLauncherVisible
: false;
this.launcherVisible = this.#previousLauncherVisible;
} else {
this.launcherExpanded = this.#previousExpandedState;
}
}
@@ -229,7 +226,7 @@ export class SidebarState {
// If we are hiding the sidebar because we removed the toolbar button, close everything
this.#previousLauncherVisible = false;
this.launcherVisible = false;
this.launcherExpanded = true;
this.launcherExpanded = false;
if (this.panelOpen) {
this.#controller.hide();
@@ -241,8 +238,8 @@ export class SidebarState {
// customize panel, we don't want to close anything on them.
return;
}
// we need this set to true to ensure it has the correct state when toggling the sidebar button
this.launcherExpanded = true;
// we need this set to verticalTabsEnabled to ensure it has the correct state when toggling the sidebar button
this.launcherExpanded = lazy.verticalTabsEnabled;
if (!visible && this.panelOpen) {
// Hiding the launcher should also close out any open panels and resets panelOpen
@@ -302,6 +299,8 @@ export class SidebarState {
this.#props.launcherDragActive = active;
if (active) {
this.#launcherEl.toggleAttribute("customWidth", true);
} else if (!lazy.verticalTabsEnabled) {
this.launcherExpanded = false;
} else if (this.launcherWidth < LAUNCHER_MINIMUM_WIDTH) {
// Snap back to collapsed state when the new width is too narrow.
this.launcherExpanded = false;
@@ -327,7 +326,11 @@ export class SidebarState {
) {
this.#panelEl.style.maxWidth = `calc(${SIDEBAR_MAXIMUM_WIDTH} - ${width}px)`;
// Expand the launcher when it gets wide enough.
if (lazy.verticalTabsEnabled) {
this.launcherExpanded = width >= LAUNCHER_MINIMUM_WIDTH;
} else {
this.launcherExpanded = false;
}
}
}

View File

@@ -225,6 +225,7 @@ var SidebarController = {
POSITION_START_PREF: "sidebar.position_start",
DEFAULT_SIDEBAR_ID: "viewBookmarksSidebar",
TOOLS_PREF: "sidebar.main.tools",
VISIBILITY_PREF: "sidebar.visibility",
// lastOpenedId is set in show() but unlike currentID it's not cleared out on hide
// and isn't persisted across windows
@@ -1086,7 +1087,11 @@ var SidebarController = {
let sidebarToggleKey = document.getElementById("toggleSidebarKb");
const shortcut = ShortcutUtils.prettifyShortcut(sidebarToggleKey);
toolbarButton.dataset.l10nArgs = JSON.stringify({ shortcut });
if (this.sidebarVerticalTabsEnabled) {
toolbarButton.toggleAttribute("expanded", this.sidebarMain.expanded);
} else {
toolbarButton.toggleAttribute("expanded", false);
}
switch (this.sidebarRevampVisibility) {
case "always-show":
// Toolbar button controls expanded state.
@@ -1815,7 +1820,11 @@ XPCOMUtils.defineLazyPreferenceGetter(
SidebarController.updateToolbarButton();
SidebarController.recordVisibilitySetting(newValue);
SidebarController._state.revampVisibility = newValue;
SidebarController._state.updateVisibility(newValue != "hide-sidebar");
SidebarController._state.updateVisibility(
(newValue != "hide-sidebar" &&
SidebarController.sidebarVerticalTabsEnabled) ||
!SidebarController.sidebarVerticalTabsEnabled
);
}
}
);
@@ -1826,6 +1835,10 @@ XPCOMUtils.defineLazyPreferenceGetter(
false,
(_aPreference, _previousValue, newValue) => {
if (!SidebarController.uninitializing) {
Services.prefs.setStringPref(
SidebarController.VISIBILITY_PREF,
newValue ? "always-show" : "hide-sidebar"
);
SidebarController.recordTabsLayoutSetting(newValue);
}
}

View File

@@ -9,6 +9,12 @@ import { SidebarPage } from "./sidebar-page.mjs";
// eslint-disable-next-line import/no-unassigned-import
import "chrome://global/content/elements/moz-radio-group.mjs";
const lazy = {};
ChromeUtils.defineESModuleGetters(lazy, {
CustomizableUI: "resource:///modules/CustomizableUI.sys.mjs",
});
const l10nMap = new Map([
["viewGenaiChatSidebar", "sidebar-menu-genai-chat-label"],
["viewReviewCheckerSidebar", "sidebar-menu-review-checker-label"],
@@ -27,12 +33,14 @@ export class SidebarCustomize extends SidebarPage {
VISIBILITY_SETTING_PREF,
"always-show"
);
this.verticalTabsEnabled = lazy.CustomizableUI.verticalTabsEnabled;
this.boundObserve = (...args) => this.observe(...args);
}
static properties = {
activeExtIndex: { type: Number },
visibility: { type: String },
verticalTabsEnabled: { type: Boolean },
};
static queries = {
@@ -49,6 +57,7 @@ export class SidebarCustomize extends SidebarPage {
this.getWindow().addEventListener("SidebarItemChanged", this);
this.getWindow().addEventListener("SidebarItemRemoved", this);
Services.prefs.addObserver(VISIBILITY_SETTING_PREF, this.boundObserve);
Services.obs.addObserver(this.boundObserve, "tabstrip-orientation-change");
}
disconnectedCallback() {
@@ -56,6 +65,10 @@ export class SidebarCustomize extends SidebarPage {
this.getWindow().removeEventListener("SidebarItemAdded", this);
this.getWindow().removeEventListener("SidebarItemChanged", this);
this.getWindow().removeEventListener("SidebarItemRemoved", this);
Services.obs.removeObserver(
this.boundObserve,
"tabstrip-orientation-change"
);
Services.prefs.removeObserver(VISIBILITY_SETTING_PREF, this.boundObserve);
}
@@ -71,6 +84,9 @@ export class SidebarCustomize extends SidebarPage {
break;
}
break;
case "tabstrip-orientation-change":
this.verticalTabsEnabled = lazy.CustomizableUI.verticalTabsEnabled;
break;
}
}
@@ -246,7 +262,10 @@ export class SidebarCustomize extends SidebarPage {
</div>
</div>`
)}
<div class="customize-group">
${when(
this.verticalTabsEnabled,
() =>
html`<div class="customize-group">
<moz-radio-group
@change=${this.#handleVisibilityChange}
name="visibility"
@@ -267,7 +286,8 @@ export class SidebarCustomize extends SidebarPage {
data-l10n-id="sidebar-visibility-setting-hide-sidebar"
></moz-radio>
</moz-radio-group>
</div>
</div>`
)}
<div class="customize-group">
<moz-radio-group
@change=${this.reversePosition}

View File

@@ -205,6 +205,9 @@ add_task(async function test_customize_position_setting() {
});
add_task(async function test_customize_visibility_setting() {
await SpecialPowers.pushPrefEnv({
set: [[TAB_DIRECTION_PREF, true]],
});
const deferredPrefChange = Promise.withResolvers();
const prefObserver = () => deferredPrefChange.resolve();
Services.prefs.addObserver(SIDEBAR_VISIBILITY_PREF, prefObserver);
@@ -235,6 +238,7 @@ add_task(async function test_customize_visibility_setting() {
await BrowserTestUtils.closeWindow(newWin);
Services.prefs.clearUserPref(SIDEBAR_VISIBILITY_PREF);
await SpecialPowers.popPrefEnv();
});
add_task(async function test_vertical_tabs_setting() {

View File

@@ -6,6 +6,9 @@ const { DOMFullscreenTestUtils } = ChromeUtils.importESModule(
let win;
add_setup(async () => {
await SpecialPowers.pushPrefEnv({
set: [["sidebar.verticalTabs", true]],
});
DOMFullscreenTestUtils.init(this, window);
win = await BrowserTestUtils.openNewBrowserWindow();
await waitForBrowserWindowActive(win);

View File

@@ -7,6 +7,8 @@ requestLongerTimeout(10);
const lazy = {};
const TAB_DIRECTION_PREF = "sidebar.verticalTabs";
ChromeUtils.defineESModuleGetters(lazy, {
TabsSetupFlowManager:
"resource:///modules/firefox-view-tabs-setup-manager.sys.mjs",
@@ -41,6 +43,10 @@ add_task(async function test_metrics_initialized() {
});
add_task(async function test_sidebar_expand() {
await SpecialPowers.pushPrefEnv({
set: [[TAB_DIRECTION_PREF, true]],
});
// Vertical tabs are expanded by default
await SidebarController.initializeUIState({ launcherExpanded: false });
info("Expand the sidebar.");
@@ -58,7 +64,7 @@ add_task(async function test_sidebar_expand() {
);
const events = Glean.sidebar.expand.testGetValue();
Assert.equal(events?.length, 1, "One event was reported.");
Assert.equal(events?.length, 2, "Two events were reported.");
});
async function testSidebarToggle(commandID, gleanEvent, otherCommandID) {
@@ -91,6 +97,7 @@ async function testSidebarToggle(commandID, gleanEvent, otherCommandID) {
if (otherCommandID) {
SidebarController.hide();
}
await SpecialPowers.popPrefEnv();
}
add_task(async function test_history_sidebar_toggle() {
@@ -396,6 +403,9 @@ async function testCustomizeSetting(
}
add_task(async function test_customize_sidebar_display() {
await SpecialPowers.pushPrefEnv({
set: [[TAB_DIRECTION_PREF, true]],
});
await testCustomizeSetting(
"visibilityInputs",
Glean.sidebarCustomize.sidebarDisplay,
@@ -403,6 +413,7 @@ add_task(async function test_customize_sidebar_display() {
{ preference: "always" },
true
);
await SpecialPowers.popPrefEnv();
});
add_task(async function test_customize_sidebar_position() {
@@ -439,6 +450,9 @@ add_task(async function test_customize_firefox_settings_clicked() {
});
add_task(async function test_sidebar_resize() {
await SpecialPowers.pushPrefEnv({
set: [[TAB_DIRECTION_PREF, true]],
});
await SidebarController.show("viewHistorySidebar");
const originalWidth = SidebarController._box.style.width;
SidebarController._box.style.width = "500px";
@@ -461,9 +475,13 @@ add_task(async function test_sidebar_resize() {
SidebarController._box.style.width = originalWidth;
SidebarController.hide();
await SpecialPowers.popPrefEnv();
});
add_task(async function test_sidebar_display_settings() {
await SpecialPowers.pushPrefEnv({
set: [[TAB_DIRECTION_PREF, true]],
});
await testCustomizeSetting(
"visibilityInputs",
Glean.sidebar.displaySettings,
@@ -471,6 +489,7 @@ add_task(async function test_sidebar_display_settings() {
"always",
true
);
await SpecialPowers.popPrefEnv();
});
add_task(async function test_sidebar_position_settings() {
@@ -523,6 +542,7 @@ async function testIconClick(expanded) {
set: [
["browser.ml.chat.enabled", true],
["sidebar.main.tools", "aichat,syncedtabs,history,bookmarks"],
[TAB_DIRECTION_PREF, true],
],
});
@@ -539,6 +559,7 @@ async function testIconClick(expanded) {
info(`Click the icon for: ${button.getAttribute("view")}`);
EventUtils.synthesizeMouseAtCenter(button, {});
if (gleanEvents[i]) {
const events = gleanEvents[i].testGetValue();
Assert.equal(events?.length, 1, "One event was reported.");
Assert.deepEqual(
@@ -547,6 +568,7 @@ async function testIconClick(expanded) {
`Event indicates the sidebar was ${expanded ? "expanded" : "collapsed"}.`
);
}
}
info("Load an extension.");
const extension = ExtensionTestUtils.loadExtension({ ...extData });
@@ -556,7 +578,10 @@ async function testIconClick(expanded) {
await SidebarController.initializeUIState({ launcherExpanded: expanded });
info("Click the icon for the extension.");
const extensionButton = sidebarMain.extensionButtons[0];
const extensionButton = await TestUtils.waitForCondition(
() => sidebarMain.extensionButtons[0],
"Extension button is present"
);
EventUtils.synthesizeMouseAtCenter(extensionButton, {});
const events = Glean.sidebar.addonIconClick.testGetValue();

View File

@@ -8,6 +8,7 @@ add_setup(async () => {
set: [
["sidebar.visibility", "always-show"],
["sidebar.position_start", true],
["sidebar.verticalTabs", true],
],
});
await SidebarController.initializeUIState({
@@ -16,6 +17,10 @@ add_setup(async () => {
});
});
registerCleanupFunction(async () => {
await SpecialPowers.popPrefEnv();
});
async function dragLauncher(deltaX, shouldExpand) {
AccessibilityUtils.setEnv({ mustHaveAccessibleRule: false });
@@ -101,3 +106,14 @@ add_task(async function test_custom_width_persists() {
);
await BrowserTestUtils.closeWindow(win);
});
add_task(async function test_drag_show_and_hide_for_horizontal_tabs() {
await SidebarController.initializeUIState({
launcherExpanded: false,
launcherVisible: true,
});
await dragLauncher(-200, false);
ok(!SidebarController.sidebarContainer.hidden, "Sidebar is not hidden.");
ok(!SidebarController.sidebarContainer.expanded, "Sidebar is not expanded.");
});

View File

@@ -3,7 +3,12 @@
"use strict";
const TAB_DIRECTION_PREF = "sidebar.verticalTabs";
add_task(async function test_customize_sidebar_actions() {
SpecialPowers.pushPrefEnv({
set: [[TAB_DIRECTION_PREF, true]],
});
const win = await BrowserTestUtils.openNewBrowserWindow();
const { document } = win;
const sidebar = document.querySelector("sidebar-main");
@@ -54,5 +59,6 @@ add_task(async function test_customize_sidebar_actions() {
"The max-width of the sidebar is approximately 75% of the viewport width."
);
SpecialPowers.popPrefEnv();
await BrowserTestUtils.closeWindow(win);
});

View File

@@ -11,10 +11,13 @@ let gAreas = CustomizableUI.getTestOnlyInternalProp("gAreas");
const SIDEBAR_BUTTON_INTRODUCED_PREF =
"browser.toolbarbuttons.introduced.sidebar-button";
const SIDEBAR_VISIBILITY_PREF = "sidebar.visibility";
const SIDEBAR_TAB_DIRECTION_PREF = "sidebar.verticalTabs";
add_setup(async () => {
// Only vertical tabs mode has expanded state
await SpecialPowers.pushPrefEnv({
set: [
[SIDEBAR_TAB_DIRECTION_PREF, true],
[SIDEBAR_BUTTON_INTRODUCED_PREF, false],
[SIDEBAR_VISIBILITY_PREF, "always-show"],
],
@@ -142,15 +145,11 @@ add_task(async function test_expanded_state_for_always_show() {
EventUtils.synthesizeMouseAtCenter(toolbarButton, {}, win);
await checkExpandedState(false);
info("Collapse the sidebar by loading a tool.");
info("Don't collapse the sidebar by loading a tool.");
await SidebarController.initializeUIState({ launcherExpanded: true });
await sidebarMain.updateComplete;
const toolButton = sidebarMain.toolButtons[0];
EventUtils.synthesizeMouseAtCenter(toolButton, {}, win);
await checkExpandedState(false);
info("Restore the sidebar back to its previous state.");
EventUtils.synthesizeMouseAtCenter(toolButton, {}, win);
await checkExpandedState(true);
info("Load and unload a tool with the sidebar collapsed to begin with.");
@@ -178,7 +177,82 @@ add_task(async function test_expanded_state_for_always_show() {
add_task(async function test_states_for_hide_sidebar() {
await SpecialPowers.pushPrefEnv({
set: [[SIDEBAR_VISIBILITY_PREF, "hide-sidebar"]],
set: [[SIDEBAR_TAB_DIRECTION_PREF, false]],
});
const win = await BrowserTestUtils.openNewBrowserWindow();
const { SidebarController } = win;
const { sidebarContainer, sidebarMain, toolbarButton } = SidebarController;
const checkStates = async (
{ hidden },
container = sidebarContainer,
component = sidebarMain,
button = toolbarButton
) => {
await TestUtils.waitForCondition(
() => container.hidden == hidden,
"Hidden state is correct."
);
await TestUtils.waitForCondition(
() => !component.expanded,
"Expanded state is correct."
);
await TestUtils.waitForCondition(
() => button.checked == !hidden,
"Toolbar button state is correct."
);
Assert.deepEqual(
document.l10n.getAttributes(button),
{
id: hidden
? "sidebar-widget-show-sidebar2"
: "sidebar-widget-hide-sidebar2",
args:
AppConstants.platform === "macosx"
? { shortcut: "⌃Z" }
: { shortcut: "Alt+Ctrl+Z" },
},
"Toolbar button has the correct tooltip."
);
await TestUtils.waitForCondition(
() => !button.hasAttribute("expanded"),
"Toolbar button expanded attribute is absent."
);
};
// Hide the sidebar
info("Check default hidden state.");
await checkStates({ hidden: false });
info("Hide sidebar using the toolbar button.");
EventUtils.synthesizeMouseAtCenter(toolbarButton, {}, win);
await checkStates({ hidden: true });
info("Show sidebar using the toolbar button.");
EventUtils.synthesizeMouseAtCenter(toolbarButton, {}, win);
await checkStates({ hidden: false });
info("Check states on a new window.");
EventUtils.synthesizeMouseAtCenter(toolbarButton, {}, win);
await checkStates({ hidden: true });
const newWin = await BrowserTestUtils.openNewBrowserWindow();
await checkStates(
{ hidden: true },
newWin.SidebarController.sidebarContainer,
newWin.SidebarController.sidebarMain,
newWin.SidebarController.toolbarButton
);
await BrowserTestUtils.closeWindow(win);
await BrowserTestUtils.closeWindow(newWin);
await SpecialPowers.popPrefEnv();
});
add_task(async function test_states_for_hide_sidebar_vertical() {
await SpecialPowers.pushPrefEnv({
set: [
[SIDEBAR_TAB_DIRECTION_PREF, true],
[SIDEBAR_VISIBILITY_PREF, "hide-sidebar"],
],
});
const win = await BrowserTestUtils.openNewBrowserWindow();
const { SidebarController } = win;
@@ -224,29 +298,22 @@ add_task(async function test_states_for_hide_sidebar() {
};
// Hide the sidebar
EventUtils.synthesizeMouseAtCenter(toolbarButton, {}, win);
info("Check default hidden state.");
await checkStates({ hidden: true, expanded: false });
info("Show expanded sidebar using the toolbar button.");
EventUtils.synthesizeMouseAtCenter(toolbarButton, {}, win);
await checkStates({ hidden: false, expanded: true });
info("Collapse the sidebar by loading a tool.");
info("Don't collapse the sidebar by loading a tool.");
const toolButton = sidebarMain.toolButtons[0];
EventUtils.synthesizeMouseAtCenter(toolButton, {}, win);
await checkStates({ hidden: false, expanded: false });
info("Restore the sidebar back to its previous state.");
EventUtils.synthesizeMouseAtCenter(toolButton, {}, win);
ok(SidebarController.isOpen, "Panel is open.");
await checkStates({ hidden: false, expanded: true });
info("Close a panel using the toolbar button.");
EventUtils.synthesizeMouseAtCenter(toolButton, {}, win);
ok(SidebarController.isOpen, "Panel is open.");
EventUtils.synthesizeMouseAtCenter(toolbarButton, {}, win);
ok(!SidebarController.isOpen, "Panel is closed.");
await checkStates({ hidden: true, expanded: true });
await checkStates({ hidden: true, expanded: false });
info("Check states on a new window.");
EventUtils.synthesizeMouseAtCenter(toolbarButton, {}, win);
@@ -262,7 +329,7 @@ add_task(async function test_states_for_hide_sidebar() {
await BrowserTestUtils.closeWindow(win);
await BrowserTestUtils.closeWindow(newWin);
await SpecialPowers.popPrefEnv();
}).skip(); //bug 1896421
});
add_task(async function test_sidebar_button_runtime_pref_enabled() {
await SpecialPowers.pushPrefEnv({

View File

@@ -203,9 +203,12 @@
@media (-moz-bool-pref: "sidebar.revamp") {
list-style-image: url("chrome://browser/skin/sidebar-collapsed-right.svg");
/* stylelint-disable-next-line media-query-no-invalid */
@media (-moz-bool-pref: "sidebar.verticalTabs") {
&:hover {
list-style-image: url("chrome://browser/skin/sidebar-expanded-right.svg");
}
}
&[expanded] {
list-style-image: url("chrome://browser/skin/sidebar-expanded-right.svg");
@@ -219,9 +222,12 @@
&:-moz-locale-dir(rtl)[positionend] {
list-style-image: url("chrome://browser/skin/sidebar-collapsed.svg");
/* stylelint-disable-next-line media-query-no-invalid */
@media (-moz-bool-pref: "sidebar.verticalTabs") {
&:hover {
list-style-image: url("chrome://browser/skin/sidebar-expanded.svg");
}
}
&[expanded] {
list-style-image: url("chrome://browser/skin/sidebar-expanded.svg");