Bug 1930201 - Add option to expand sidebar on hover r=desktop-theme-reviewers,sidebar-reviewers,emilio,tabbrowser-reviewers,flod,sclements,dao
Differential Revision: https://phabricator.services.mozilla.com/D233098
This commit is contained in:
@@ -2076,6 +2076,7 @@ pref("sidebar.revamp.round-content-area", false);
|
||||
#endif
|
||||
pref("sidebar.animation.enabled", true);
|
||||
pref("sidebar.animation.duration-ms", 200);
|
||||
pref("sidebar.animation.expand-on-hover.duration-ms", 400);
|
||||
pref("sidebar.main.tools", "aichat,syncedtabs,history");
|
||||
pref("sidebar.verticalTabs", false);
|
||||
pref("sidebar.visibility", "always-show");
|
||||
@@ -2083,6 +2084,7 @@ pref("sidebar.visibility", "always-show");
|
||||
// as a backup to restore the sidebar UI state when a user has PPB mode on
|
||||
// or has history cleared on browser close.
|
||||
pref("sidebar.backupState", "{}");
|
||||
pref("sidebar.expandOnHover", false);
|
||||
|
||||
pref("browser.ml.chat.enabled", true);
|
||||
pref("browser.ml.chat.hideLocalhost", true);
|
||||
|
||||
@@ -3,26 +3,29 @@
|
||||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
<hbox flex="1" id="browser">
|
||||
<box context="sidebar-context-menu" id="sidebar-main" hidden="true">
|
||||
<html:sidebar-main flex="1">
|
||||
<box id="vertical-tabs" slot="tabstrip" customizable="true" contextmenu="toolbar-context-menu"></box>
|
||||
</html:sidebar-main>
|
||||
</box>
|
||||
<splitter id="sidebar-launcher-splitter" class="chromeclass-extrachrome sidebar-splitter" resizebefore="sibling" resizeafter="none" hidden="true"/>
|
||||
<vbox id="sidebar-box" hidden="true" class="chromeclass-extrachrome">
|
||||
<box id="sidebar-header" align="center">
|
||||
<toolbarbutton id="sidebar-switcher-target" class="tabbable" aria-expanded="false">
|
||||
<image id="sidebar-icon" consumeanchor="sidebar-switcher-target"/>
|
||||
<label id="sidebar-title" crop="end" control="sidebar"/>
|
||||
<image id="sidebar-switcher-arrow"/>
|
||||
</toolbarbutton>
|
||||
<image id="sidebar-throbber"/>
|
||||
<spacer id="sidebar-spacer"/>
|
||||
<toolbarbutton id="sidebar-close" class="close-icon tabbable" data-l10n-id="sidebar-close-button"/>
|
||||
<div id="sidebar-wrapper">
|
||||
<box context="sidebar-context-menu" id="sidebar-main" hidden="true">
|
||||
<html:sidebar-main flex="1">
|
||||
<box id="vertical-tabs" slot="tabstrip" customizable="true" contextmenu="toolbar-context-menu"></box>
|
||||
</html:sidebar-main>
|
||||
</box>
|
||||
<browser id="sidebar" autoscroll="false" disablehistory="true" disablefullscreen="true" tooltip="aHTMLTooltip"/>
|
||||
</vbox>
|
||||
<splitter id="sidebar-splitter" class="chromeclass-extrachrome sidebar-splitter" resizebefore="sibling" resizeafter="none" hidden="true"/>
|
||||
<splitter id="sidebar-launcher-splitter" class="chromeclass-extrachrome sidebar-splitter" resizebefore="sibling" resizeafter="none" hidden="true"/>
|
||||
<vbox id="sidebar-box" hidden="true" class="chromeclass-extrachrome">
|
||||
<box id="sidebar-header" align="center">
|
||||
<toolbarbutton id="sidebar-switcher-target" class="tabbable" aria-expanded="false">
|
||||
<image id="sidebar-icon" consumeanchor="sidebar-switcher-target"/>
|
||||
<label id="sidebar-title" crop="end" control="sidebar"/>
|
||||
<image id="sidebar-switcher-arrow"/>
|
||||
</toolbarbutton>
|
||||
<image id="sidebar-throbber"/>
|
||||
<spacer id="sidebar-spacer"/>
|
||||
<toolbarbutton id="sidebar-close" class="close-icon tabbable" data-l10n-id="sidebar-close-button"/>
|
||||
</box>
|
||||
<browser id="sidebar" autoscroll="false" disablehistory="true" disablefullscreen="true" tooltip="aHTMLTooltip"/>
|
||||
</vbox>
|
||||
<splitter id="sidebar-splitter" class="chromeclass-extrachrome sidebar-splitter" resizebefore="sibling" resizeafter="none" hidden="true"/>
|
||||
<box id="after-splitter"></box>
|
||||
</div>
|
||||
<tabbox id="tabbrowser-tabbox" flex="1" tabcontainer="tabbrowser-tabs">
|
||||
<tabpanels id="tabbrowser-tabpanels" flex="1" selectedIndex="0"/>
|
||||
</tabbox>
|
||||
|
||||
@@ -33,6 +33,8 @@ XPCOMUtils.defineLazyPreferenceGetter(
|
||||
* Current width of the sidebar launcher.
|
||||
* @property {number} expandedLauncherWidth
|
||||
* Width that the sidebar launcher should expand to.
|
||||
* @property {number} collapsedLauncherWidth
|
||||
* Width that the sidebar launcher should collapse to.
|
||||
*/
|
||||
|
||||
const LAUNCHER_MINIMUM_WIDTH = 100;
|
||||
@@ -52,6 +54,7 @@ export class SidebarState {
|
||||
launcherExpanded: false,
|
||||
launcherDragActive: false,
|
||||
launcherHoverActive: false,
|
||||
collapsedLauncherWidth: undefined,
|
||||
};
|
||||
#previousLauncherVisible = undefined;
|
||||
|
||||
@@ -180,6 +183,10 @@ export class SidebarState {
|
||||
expandedLauncherWidth: convertToInt(this.expandedLauncherWidth),
|
||||
launcherExpanded: this.launcherExpanded,
|
||||
launcherVisible: this.launcherVisible,
|
||||
collapsedLauncherWidth:
|
||||
typeof this.collapsedLauncherWidth === "number"
|
||||
? Math.round(this.collapsedLauncherWidth)
|
||||
: this.collapsedLauncherWidth,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -218,7 +225,8 @@ export class SidebarState {
|
||||
updateVisibility(
|
||||
visible,
|
||||
openedByToolbarButton = false,
|
||||
onToolbarButtonRemoval = false
|
||||
onToolbarButtonRemoval = false,
|
||||
forceExpandValue = null
|
||||
) {
|
||||
switch (this.revampVisibility) {
|
||||
case "hide-sidebar":
|
||||
@@ -248,8 +256,10 @@ export class SidebarState {
|
||||
this.launcherVisible = visible;
|
||||
break;
|
||||
case "always-show":
|
||||
case "expand-on-hover":
|
||||
this.launcherVisible = true;
|
||||
this.launcherExpanded = !this.launcherExpanded;
|
||||
this.launcherExpanded =
|
||||
forceExpandValue !== null ? forceExpandValue : !this.launcherExpanded;
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -299,8 +309,6 @@ 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;
|
||||
@@ -313,6 +321,14 @@ export class SidebarState {
|
||||
}
|
||||
}
|
||||
|
||||
get launcherHoverActive() {
|
||||
return this.#props.launcherHoverActive;
|
||||
}
|
||||
|
||||
set launcherHoverActive(active) {
|
||||
this.#props.launcherHoverActive = active;
|
||||
}
|
||||
|
||||
get launcherWidth() {
|
||||
return this.#props.launcherWidth;
|
||||
}
|
||||
@@ -343,6 +359,14 @@ export class SidebarState {
|
||||
this.#updateLauncherWidth();
|
||||
}
|
||||
|
||||
get collapsedLauncherWidth() {
|
||||
return this.#props.collapsedLauncherWidth;
|
||||
}
|
||||
|
||||
set collapsedLauncherWidth(width) {
|
||||
this.#props.collapsedLauncherWidth = width;
|
||||
}
|
||||
|
||||
/**
|
||||
* If the sidebar is expanded, resize the launcher to the user-preferred
|
||||
* width (if available). If it is collapsed, reset the launcher width.
|
||||
|
||||
@@ -293,6 +293,20 @@ var SidebarController = {
|
||||
return this._sidebarMain;
|
||||
},
|
||||
|
||||
get sidebarWrapper() {
|
||||
if (!this._sidebarWrapper) {
|
||||
this._sidebarWrapper = document.getElementById("sidebar-wrapper");
|
||||
}
|
||||
return this._sidebarWrapper;
|
||||
},
|
||||
|
||||
get contentArea() {
|
||||
if (!this._contentArea) {
|
||||
this._contentArea = document.getElementById("tabbrowser-tabbox");
|
||||
}
|
||||
return this._contentArea;
|
||||
},
|
||||
|
||||
get toolbarButton() {
|
||||
if (!this._toolbarButton) {
|
||||
this._toolbarButton = document.getElementById("sidebar-button");
|
||||
@@ -494,6 +508,9 @@ var SidebarController = {
|
||||
if (this.isLauncherDragging) {
|
||||
this._state.launcherDragActive = true;
|
||||
}
|
||||
if (this._state.visibilitySetting === "expand-on-hover") {
|
||||
this.setLauncherInlineMargin();
|
||||
}
|
||||
},
|
||||
|
||||
getUIState() {
|
||||
@@ -667,6 +684,9 @@ var SidebarController = {
|
||||
*/
|
||||
reversePosition() {
|
||||
Services.prefs.setBoolPref(this.POSITION_START_PREF, !this._positionStart);
|
||||
if (this.sidebarRevampVisibility === "expand-on-hover") {
|
||||
this.setLauncherInlineMargin();
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
@@ -675,37 +695,51 @@ var SidebarController = {
|
||||
*/
|
||||
setPosition() {
|
||||
// First reset all ordinals to match DOM ordering.
|
||||
let contentArea = document.getElementById("tabbrowser-tabbox");
|
||||
let browser = document.getElementById("browser");
|
||||
[...browser.children].forEach((node, i) => {
|
||||
node.style.order = i + 1;
|
||||
});
|
||||
[...this.sidebarWrapper.children].forEach((node, i) => {
|
||||
node.style.order = i + 1;
|
||||
});
|
||||
let sidebarContainer = document.getElementById("sidebar-main");
|
||||
let sidebarMain = document.querySelector("sidebar-main");
|
||||
if (!this._positionStart) {
|
||||
// DOM ordering is: sidebar-main | launcher-splitter | sidebar-box | splitter | tabbrowser-tabbox |
|
||||
// Want to display as: | tabbrowser-tabbox | splitter | sidebar-box | launcher-splitter | sidebar-main
|
||||
// So we just swap box and tabbrowser-tabbox ordering and move sidebar-main to the end
|
||||
let tabbox = document.getElementById("tabbrowser-tabbox");
|
||||
let boxOrdinal = this._box.style.order;
|
||||
this._box.style.order = tabbox.style.order;
|
||||
// First switch order of sidebar-wrapper and tabbrowser-tabbox
|
||||
let wrapperOrdinal = this.sidebarWrapper.style.order;
|
||||
this.sidebarWrapper.style.order = contentArea.style.order;
|
||||
contentArea.style.order = wrapperOrdinal;
|
||||
|
||||
tabbox.style.order = boxOrdinal;
|
||||
// DOM ordering is: sidebar-main | launcher-splitter | sidebar-box | splitter | after-splitter |
|
||||
// Want to display as: after-splitter | splitter | sidebar-box | launcher-splitter | sidebar-main
|
||||
// First swap sidebar-box and after-splitter
|
||||
let afterSplitter = document.getElementById("after-splitter");
|
||||
let boxOrdinal = this._box.style.order;
|
||||
this._box.style.order = afterSplitter.style.order;
|
||||
afterSplitter.style.order = boxOrdinal;
|
||||
|
||||
// Then move the launcher-splitter to the right of sidebar-box
|
||||
const launcherSplitterOrdinal = parseInt(this._box.style.order) + 1;
|
||||
this._launcherSplitter.style.order = launcherSplitterOrdinal;
|
||||
// the launcher should be on the right of the launcher-splitter
|
||||
sidebarContainer.style.order = launcherSplitterOrdinal + 1;
|
||||
|
||||
// Finally move the launcher to the right of the launcher-splitter
|
||||
sidebarContainer.style.order = parseInt(launcherSplitterOrdinal) + 1;
|
||||
|
||||
// Indicate we've switched ordering to the box
|
||||
this._box.toggleAttribute("positionend", true);
|
||||
sidebarMain.toggleAttribute("positionend", true);
|
||||
sidebarContainer.toggleAttribute("positionend", true);
|
||||
this.toolbarButton &&
|
||||
this.toolbarButton.toggleAttribute("positionend", true);
|
||||
this.sidebarWrapper.toggleAttribute("positionend", true);
|
||||
} else {
|
||||
this._box.toggleAttribute("positionend", false);
|
||||
sidebarMain.toggleAttribute("positionend", false);
|
||||
sidebarContainer.toggleAttribute("positionend", false);
|
||||
this.toolbarButton &&
|
||||
this.toolbarButton.toggleAttribute("positionend", false);
|
||||
this.sidebarWrapper.toggleAttribute("positionend", false);
|
||||
}
|
||||
|
||||
this.hideSwitcherPanel();
|
||||
@@ -954,14 +988,19 @@ var SidebarController = {
|
||||
return this.show(commandID, triggerNode);
|
||||
},
|
||||
|
||||
_getRects(animatingElements) {
|
||||
return animatingElements.map(e => [
|
||||
e.hidden,
|
||||
e.getBoundingClientRect().toJSON(),
|
||||
]);
|
||||
},
|
||||
|
||||
async _animateSidebarMain() {
|
||||
let tabbox = document.getElementById("tabbrowser-tabbox");
|
||||
let animatingElements = [
|
||||
this.sidebarContainer,
|
||||
this._box,
|
||||
this._splitter,
|
||||
tabbox,
|
||||
];
|
||||
let animatingElements = [this.sidebarContainer, this._box, this._splitter];
|
||||
if (!this.sidebarRevampVisibility === "expand-on-hover") {
|
||||
animatingElements.push(tabbox);
|
||||
}
|
||||
let resetElements = () => {
|
||||
for (let el of animatingElements) {
|
||||
el.style.minWidth =
|
||||
@@ -971,30 +1010,29 @@ var SidebarController = {
|
||||
el.style.display =
|
||||
"";
|
||||
}
|
||||
this.sidebarWrapper.classList.remove("ongoing-animations");
|
||||
};
|
||||
if (this._ongoingAnimations.length) {
|
||||
this._ongoingAnimations.forEach(a => a.cancel());
|
||||
this._ongoingAnimations = [];
|
||||
resetElements();
|
||||
}
|
||||
let getRects = () => {
|
||||
return animatingElements.map(e => [
|
||||
e.hidden,
|
||||
e.getBoundingClientRect().toJSON(),
|
||||
]);
|
||||
};
|
||||
let fromRects = getRects();
|
||||
|
||||
let fromRects = this._getRects(animatingElements);
|
||||
|
||||
// We need to wait for rAF for lit to re-render, and us to get the final
|
||||
// width. This is a bit unfortunate but alas...
|
||||
let toRects = await new Promise(resolve => {
|
||||
requestAnimationFrame(() => {
|
||||
resolve(getRects());
|
||||
resolve(this._getRects(animatingElements));
|
||||
});
|
||||
});
|
||||
|
||||
const options = {
|
||||
duration: this._animationDurationMs,
|
||||
duration:
|
||||
this.sidebarRevampVisibility === "expand-on-hover"
|
||||
? this._animationExpandOnHoverDurationMs
|
||||
: this._animationDurationMs,
|
||||
easing: "ease-in-out",
|
||||
};
|
||||
let animations = [];
|
||||
@@ -1038,6 +1076,7 @@ var SidebarController = {
|
||||
if (isHidden && !wasHidden) {
|
||||
el.style.display = "flex";
|
||||
}
|
||||
|
||||
if (widthGrowth < 0) {
|
||||
el.style.minWidth = el.style.maxWidth = from.width + "px";
|
||||
el.style["margin-" + (sidebarOnLeft ? "right" : "left")] =
|
||||
@@ -1057,6 +1096,7 @@ var SidebarController = {
|
||||
} else if (isSidebar && !this._positionStart) {
|
||||
fromTranslate += sidebarOnLeft ? -widthGrowth : widthGrowth;
|
||||
}
|
||||
|
||||
animations.push(
|
||||
el.animate(
|
||||
[
|
||||
@@ -1079,6 +1119,7 @@ var SidebarController = {
|
||||
);
|
||||
}
|
||||
this._ongoingAnimations = animations;
|
||||
this.sidebarWrapper.classList.add("ongoing-animations");
|
||||
await Promise.allSettled(animations.map(a => a.finished));
|
||||
if (this._ongoingAnimations === animations) {
|
||||
this._ongoingAnimations = [];
|
||||
@@ -1117,6 +1158,7 @@ var SidebarController = {
|
||||
}
|
||||
switch (this.sidebarRevampVisibility) {
|
||||
case "always-show":
|
||||
case "expand-on-hover":
|
||||
// Toolbar button controls expanded state.
|
||||
toolbarButton.checked = this.sidebarMain.expanded;
|
||||
toolbarButton.dataset.l10nId = toolbarButton.checked
|
||||
@@ -1761,15 +1803,102 @@ var SidebarController = {
|
||||
this.sidebarMain.requestUpdate();
|
||||
},
|
||||
|
||||
onMouseOver() {
|
||||
SidebarController._state.launcherHoverActive = true;
|
||||
SidebarController.sidebarMain.addEventListener(
|
||||
"mouseout",
|
||||
SidebarController.onMouseOut,
|
||||
{ once: true }
|
||||
);
|
||||
if (SidebarController._animationEnabled && !window.gReduceMotion) {
|
||||
SidebarController._animateSidebarMain();
|
||||
}
|
||||
SidebarController._state.updateVisibility(true, false, false, true);
|
||||
SidebarController.sidebarMain.removeEventListener(
|
||||
"mouseover",
|
||||
SidebarController.onMouseOver
|
||||
);
|
||||
},
|
||||
|
||||
onMouseOut() {
|
||||
SidebarController._state.launcherHoverActive = false;
|
||||
SidebarController.sidebarMain.addEventListener(
|
||||
"mouseover",
|
||||
SidebarController.onMouseOver,
|
||||
{ once: true }
|
||||
);
|
||||
if (SidebarController._animationEnabled && !window.gReduceMotion) {
|
||||
SidebarController._animateSidebarMain();
|
||||
}
|
||||
SidebarController._state.updateVisibility(true, false, false, false);
|
||||
SidebarController.sidebarMain.removeEventListener(
|
||||
"mouseout",
|
||||
SidebarController.onMouseOut
|
||||
);
|
||||
},
|
||||
|
||||
async setLauncherInlineMargin() {
|
||||
let collapsedWidth;
|
||||
if (this._state.launcherExpanded) {
|
||||
this._state.launcherExpanded = false;
|
||||
await this.sidebarMain.updateComplete;
|
||||
collapsedWidth = await new Promise(resolve => {
|
||||
requestAnimationFrame(() => {
|
||||
resolve(this._getRects([this.sidebarMain])[0][1].width);
|
||||
});
|
||||
});
|
||||
} else {
|
||||
collapsedWidth = this._getRects([this.sidebarMain])[0][1].width;
|
||||
}
|
||||
|
||||
this._state.collapsedLauncherWidth = collapsedWidth;
|
||||
|
||||
// Make sure sidebar doesn't overlay content area outline
|
||||
const CONTENT_AREA_OUTLINE_WIDTH = 1;
|
||||
|
||||
if (this._positionStart) {
|
||||
this.contentArea.style.marginInlineStart = `${this._state.collapsedLauncherWidth + CONTENT_AREA_OUTLINE_WIDTH}px`;
|
||||
this.contentArea.style.marginInlineEnd = "";
|
||||
} else {
|
||||
this.contentArea.style.marginInlineEnd = `${this._state.collapsedLauncherWidth + CONTENT_AREA_OUTLINE_WIDTH}px`;
|
||||
this.contentArea.style.marginInlineStart = "";
|
||||
}
|
||||
},
|
||||
|
||||
async toggleExpandOnHover(isEnabled) {
|
||||
if (isEnabled) {
|
||||
this.sidebarWrapper.classList.add("expandOnHover");
|
||||
|
||||
if (!this._state) {
|
||||
this._state = new this.SidebarState(this);
|
||||
}
|
||||
|
||||
await this.setLauncherInlineMargin();
|
||||
|
||||
this.sidebarMain.addEventListener("mouseover", this.onMouseOver, {
|
||||
once: true,
|
||||
});
|
||||
} else {
|
||||
this.sidebarWrapper.classList.remove("expandOnHover");
|
||||
this.sidebarMain.removeEventListener("mouseover", this.onMouseOver);
|
||||
this.contentArea.style.marginInlineStart = "";
|
||||
this.contentArea.style.marginInlineEnd = "";
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Report visibility preference to Glean.
|
||||
*
|
||||
* @param {string} [value] - The preference value.
|
||||
*/
|
||||
recordVisibilitySetting(value = this.sidebarRevampVisibility) {
|
||||
Glean.sidebar.displaySettings.set(
|
||||
value === "always-show" ? "always" : "hide"
|
||||
);
|
||||
let visibilitySetting = "hide";
|
||||
if (value === "always-show") {
|
||||
visibilitySetting = "always";
|
||||
} else if (value === "expand-on-hover") {
|
||||
visibilitySetting = "expand-on-hover";
|
||||
}
|
||||
Glean.sidebar.displaySettings.set(visibilitySetting);
|
||||
},
|
||||
|
||||
/**
|
||||
@@ -1822,6 +1951,12 @@ XPCOMUtils.defineLazyPreferenceGetter(
|
||||
"sidebar.animation.duration-ms",
|
||||
200
|
||||
);
|
||||
XPCOMUtils.defineLazyPreferenceGetter(
|
||||
SidebarController,
|
||||
"_animationExpandOnHoverDurationMs",
|
||||
"sidebar.animation.expand-on-hover.duration-ms",
|
||||
400
|
||||
);
|
||||
XPCOMUtils.defineLazyPreferenceGetter(
|
||||
SidebarController,
|
||||
"sidebarRevampEnabled",
|
||||
@@ -1852,12 +1987,16 @@ XPCOMUtils.defineLazyPreferenceGetter(
|
||||
"always-show",
|
||||
(_aPreference, _previousValue, newValue) => {
|
||||
if (!SidebarController.inPopup && !SidebarController.uninitializing) {
|
||||
SidebarController.toggleExpandOnHover(newValue === "expand-on-hover");
|
||||
SidebarController.recordVisibilitySetting(newValue);
|
||||
SidebarController._state.revampVisibility = newValue;
|
||||
SidebarController._state.updateVisibility(
|
||||
(newValue != "hide-sidebar" &&
|
||||
SidebarController.sidebarVerticalTabsEnabled) ||
|
||||
!SidebarController.sidebarVerticalTabsEnabled
|
||||
!SidebarController.sidebarVerticalTabsEnabled,
|
||||
false,
|
||||
false,
|
||||
newValue !== "expand-on-hover"
|
||||
);
|
||||
SidebarController.updateToolbarButton();
|
||||
}
|
||||
|
||||
@@ -55,7 +55,7 @@ sidebar:
|
||||
type: string
|
||||
lifetime: application
|
||||
description: >
|
||||
Setting for sidebar display (either "always" or "hide").
|
||||
Setting for sidebar display (either "always", "expand-on-hover", or "hide").
|
||||
bugs:
|
||||
- https://bugzilla.mozilla.org/show_bug.cgi?id=1898250
|
||||
data_reviews:
|
||||
@@ -627,3 +627,22 @@ sidebar.customize:
|
||||
- vsabino@mozilla.com
|
||||
send_in_pings:
|
||||
- events
|
||||
expand_on_hover_enabled:
|
||||
type: event
|
||||
description: >
|
||||
User clicked on the checkbox corresponding to expand on hover on sidebar customization settings.
|
||||
bugs:
|
||||
- https://bugzilla.mozilla.org/show_bug.cgi?id=1930201
|
||||
data_reviews:
|
||||
- https://phabricator.services.mozilla.com/D233098
|
||||
data_sensitivity:
|
||||
- interaction
|
||||
expires: never
|
||||
notification_emails:
|
||||
- vsabino@mozilla.com
|
||||
send_in_pings:
|
||||
- events
|
||||
extra_keys:
|
||||
checked:
|
||||
type: boolean
|
||||
description: Whether the box was checked.
|
||||
|
||||
@@ -88,6 +88,10 @@ moz-checkbox {
|
||||
> moz-checkbox:last-of-type {
|
||||
padding-block: 0;
|
||||
}
|
||||
|
||||
&[disabled]::part(label) {
|
||||
opacity: 0.5;
|
||||
}
|
||||
}
|
||||
|
||||
.no-label::part(label) {
|
||||
|
||||
@@ -18,6 +18,7 @@ const l10nMap = new Map([
|
||||
["viewBookmarksSidebar", "sidebar-menu-bookmarks-label"],
|
||||
]);
|
||||
const VISIBILITY_SETTING_PREF = "sidebar.visibility";
|
||||
const EXPAND_ON_HOVER_PREF = "sidebar.expandOnHover";
|
||||
const POSITION_SETTING_PREF = "sidebar.position_start";
|
||||
const TAB_DIRECTION_SETTING_PREF = "sidebar.verticalTabs";
|
||||
|
||||
@@ -52,9 +53,19 @@ export class SidebarCustomize extends SidebarPage {
|
||||
this.verticalTabsEnabled = newValue;
|
||||
}
|
||||
);
|
||||
XPCOMUtils.defineLazyPreferenceGetter(
|
||||
this.#prefValues,
|
||||
"expandOnHoverEnabled",
|
||||
EXPAND_ON_HOVER_PREF,
|
||||
false,
|
||||
(_aPreference, _previousValue, newValue) => {
|
||||
this.expandOnHoverEnabled = newValue;
|
||||
}
|
||||
);
|
||||
this.visibility = this.#prefValues.visibility;
|
||||
this.isPositionStart = this.#prefValues.isPositionStart;
|
||||
this.verticalTabsEnabled = this.#prefValues.verticalTabsEnabled;
|
||||
this.expandOnHoverEnabled = this.#prefValues.expandOnHoverEnabled;
|
||||
this.boundObserve = (...args) => this.observe(...args);
|
||||
}
|
||||
|
||||
@@ -65,6 +76,7 @@ export class SidebarCustomize extends SidebarPage {
|
||||
visibility: { type: String },
|
||||
isPositionStart: { type: Boolean },
|
||||
verticalTabsEnabled: { type: Boolean },
|
||||
expandOnHoverEnabled: { type: Boolean },
|
||||
};
|
||||
|
||||
static queries = {
|
||||
@@ -110,7 +122,7 @@ export class SidebarCustomize extends SidebarPage {
|
||||
}
|
||||
}
|
||||
|
||||
async onToggleInput(e) {
|
||||
async onToggleToolInput(e) {
|
||||
e.preventDefault();
|
||||
this.getWindow().SidebarController.toggleTool(e.target.id);
|
||||
switch (e.target.id) {
|
||||
@@ -154,7 +166,7 @@ export class SidebarCustomize extends SidebarPage {
|
||||
}
|
||||
}
|
||||
|
||||
inputTemplate(tool) {
|
||||
toolInputTemplate(tool) {
|
||||
if (tool.hidden) {
|
||||
return null;
|
||||
}
|
||||
@@ -166,7 +178,7 @@ export class SidebarCustomize extends SidebarPage {
|
||||
name=${tool.view}
|
||||
iconsrc=${tool.iconUrl}
|
||||
data-l10n-id=${this.getInputL10nId(tool.view)}
|
||||
@change=${this.onToggleInput}
|
||||
@change=${this.onToggleToolInput}
|
||||
?checked=${!tool.disabled}
|
||||
/>
|
||||
`;
|
||||
@@ -253,20 +265,38 @@ export class SidebarCustomize extends SidebarPage {
|
||||
@change=${this.#handleTabDirectionChange}
|
||||
?checked=${this.verticalTabsEnabled}
|
||||
>
|
||||
${when(
|
||||
this.verticalTabsEnabled,
|
||||
() => html`
|
||||
<moz-checkbox
|
||||
slot="nested"
|
||||
type="checkbox"
|
||||
id="hide-sidebar"
|
||||
name="hideSidebar"
|
||||
data-l10n-id="sidebar-hide-tabs-and-sidebar"
|
||||
@change=${this.#handleVisibilityChange}
|
||||
?checked=${this.visibility == "hide-sidebar"}
|
||||
></moz-checkbox>
|
||||
`
|
||||
)}
|
||||
${when(
|
||||
this.verticalTabsEnabled,
|
||||
() => html`
|
||||
${when(
|
||||
this.expandOnHoverEnabled,
|
||||
() => html`
|
||||
<moz-checkbox
|
||||
slot="nested"
|
||||
type="checkbox"
|
||||
id="expand-on-hover"
|
||||
name="expand-on-hover"
|
||||
data-l10n-id="expand-sidebar-on-hover"
|
||||
@change=${this.#toggleExpandOnHover}
|
||||
?checked=${this.getWindow().SidebarController._state
|
||||
.revampVisibility === "expand-on-hover"}
|
||||
?disabled=${this.visibility == "hide-sidebar"}
|
||||
/>
|
||||
`
|
||||
)}
|
||||
<moz-checkbox
|
||||
slot="nested"
|
||||
type="checkbox"
|
||||
id="hide-sidebar"
|
||||
name="hideSidebar"
|
||||
data-l10n-id="sidebar-hide-tabs-and-sidebar"
|
||||
@change=${this.#handleVisibilityChange}
|
||||
?checked=${this.visibility == "hide-sidebar"}
|
||||
?disabled=${this.getWindow().SidebarController._state
|
||||
.revampVisibility === "expand-on-hover"}
|
||||
></moz-checkbox>
|
||||
`
|
||||
)}
|
||||
</moz-checkbox>
|
||||
</moz-fieldset>
|
||||
<moz-fieldset class="customize-group medium-top-margin no-label">
|
||||
@@ -282,7 +312,7 @@ export class SidebarCustomize extends SidebarPage {
|
||||
<moz-fieldset class="customize-group" data-l10n-id="sidebar-customize-firefox-tools-header">
|
||||
${this.getWindow()
|
||||
.SidebarController.getTools()
|
||||
.map(tool => this.inputTemplate(tool))}
|
||||
.map(tool => this.toolInputTemplate(tool))}
|
||||
</moz-fieldset>
|
||||
${when(
|
||||
extensions.length,
|
||||
@@ -325,6 +355,18 @@ export class SidebarCustomize extends SidebarPage {
|
||||
});
|
||||
}
|
||||
|
||||
#toggleExpandOnHover(e) {
|
||||
e.stopPropagation();
|
||||
if (e.target.checked) {
|
||||
Services.prefs.setStringPref("sidebar.visibility", "expand-on-hover");
|
||||
Glean.sidebarCustomize.expandOnHoverEnabled.record({
|
||||
checked: true,
|
||||
});
|
||||
} else {
|
||||
Services.prefs.setStringPref("sidebar.visibility", "always-show");
|
||||
}
|
||||
}
|
||||
|
||||
#handleTabDirectionChange({ target: { checked } }) {
|
||||
const verticalTabsEnabled = checked;
|
||||
Services.prefs.setBoolPref(TAB_DIRECTION_SETTING_PREF, verticalTabsEnabled);
|
||||
|
||||
@@ -2197,6 +2197,18 @@
|
||||
browserSidebarContainer.className = "browserSidebarContainer";
|
||||
browserSidebarContainer.appendChild(browserContainer);
|
||||
|
||||
let visibility = Services.prefs.getStringPref(
|
||||
"sidebar.visibility",
|
||||
"always-show"
|
||||
);
|
||||
let expandOnHover = Services.prefs.getBoolPref(
|
||||
"sidebar.expandOnHover",
|
||||
false
|
||||
);
|
||||
if (visibility === "expand-on-hover" && expandOnHover) {
|
||||
SidebarController.toggleExpandOnHover(true);
|
||||
}
|
||||
|
||||
// Prevent the superfluous initial load of a blank document
|
||||
// if we're going to load something other than about:blank.
|
||||
if (!uriIsAboutBlank || skipLoad) {
|
||||
|
||||
@@ -58,6 +58,10 @@ sidebar-show-on-the-right =
|
||||
.label = Move sidebar to the right
|
||||
sidebar-show-on-the-left =
|
||||
.label = Move sidebar to the left
|
||||
# Option to automatically expand the collapsed sidebar when the mouse pointer
|
||||
# hovers over it.
|
||||
expand-sidebar-on-hover =
|
||||
.label = Expand sidebar on hover
|
||||
|
||||
## Labels for sidebar context menu items
|
||||
|
||||
|
||||
@@ -70,7 +70,7 @@ body {
|
||||
--browser-area-z-index-toolbox: 0;
|
||||
--browser-area-z-index-sidebar: 1;
|
||||
--browser-area-z-index-tabbox: 2;
|
||||
--browser-area-z-index-sidebar-splitter: 3;
|
||||
--browser-area-z-index-sidebar-wrapper: 3;
|
||||
|
||||
/* on macOS the animation of the toolbox in fullscreen needs the toolbox to be higher */
|
||||
--browser-area-z-index-toolbox-while-animating: 4;
|
||||
|
||||
@@ -21,11 +21,10 @@
|
||||
padding-block-end: var(--space-small);
|
||||
padding-inline-end: var(--space-small);
|
||||
position: relative;
|
||||
z-index: var(--browser-area-z-index-sidebar);
|
||||
|
||||
&[positionend] {
|
||||
padding-inline-end: 0;
|
||||
padding-inline-start: var(--space-small);
|
||||
padding-inline: 0;
|
||||
margin-inline-start: var(--space-small);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -76,9 +75,6 @@
|
||||
|
||||
.sidebar-splitter {
|
||||
--splitter-width: 4px;
|
||||
/* Ensure the splitter is painted on top of the sidebar box it overlaps.
|
||||
Otherwise, the user may be unable to drag the splitter to resize the sidebar. */
|
||||
z-index: var(--browser-area-z-index-sidebar-splitter);
|
||||
|
||||
/* stylelint-disable-next-line media-query-no-invalid */
|
||||
@media (-moz-bool-pref: "sidebar.revamp") or (not (-moz-platform: linux)) {
|
||||
@@ -224,3 +220,60 @@ sidebar-main,
|
||||
/* Prevent overflow during sidebar animation when the sidebar is reordered */
|
||||
overflow: clip;
|
||||
}
|
||||
|
||||
/* Expand on hover */
|
||||
|
||||
#sidebar-wrapper {
|
||||
position: relative;
|
||||
z-index: var(--browser-area-z-index-sidebar-wrapper);
|
||||
|
||||
&.expandOnHover {
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
inset-inline-end: unset;
|
||||
|
||||
&:not([positionend]):hover {
|
||||
border-start-end-radius: var(--border-radius-medium);
|
||||
border-end-end-radius: var(--border-radius-medium);
|
||||
border-inline-end: 0.01px solid var(--chrome-content-separator-color);
|
||||
}
|
||||
|
||||
&[positionend]:hover {
|
||||
border-start-start-radius: var(--border-radius-medium);
|
||||
border-start-end-radius: var(--border-radius-medium);
|
||||
border-inline-start: 0.01px solid var(--chrome-content-separator-color);
|
||||
}
|
||||
|
||||
:root[lwtheme] & {
|
||||
border-radius: unset;
|
||||
border-inline: unset;
|
||||
color: var(--toolbox-textcolor);
|
||||
background-color: var(--toolbox-bgcolor);
|
||||
|
||||
&:-moz-window-inactive {
|
||||
color: var(--toolbox-textcolor-inactive);
|
||||
background-color: var(--toolbox-bgcolor-inactive);
|
||||
}
|
||||
}
|
||||
|
||||
&:hover,
|
||||
&.ongoing-animations {
|
||||
color: var(--toolbox-textcolor);
|
||||
background-color: var(--toolbox-bgcolor);
|
||||
}
|
||||
|
||||
#sidebar-main {
|
||||
border-radius: inherit;
|
||||
background-color: inherit;
|
||||
|
||||
&:hover {
|
||||
box-shadow: var(--content-area-shadow);
|
||||
}
|
||||
}
|
||||
|
||||
&[positionend] {
|
||||
inset-inline-start: unset;
|
||||
inset-inline-end: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -40,6 +40,11 @@
|
||||
}
|
||||
}
|
||||
|
||||
/* Needed to ensure #sidebar-wrapper is full height when vertical tabs are not enabled */
|
||||
#browser {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
#browser,
|
||||
#tabbrowser-tabbox,
|
||||
#tabbrowser-tabpanels,
|
||||
|
||||
@@ -1382,6 +1382,16 @@
|
||||
.tabbrowser-tab:not([pinned]):hover & {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
/* stylelint-disable-next-line media-query-no-invalid */
|
||||
@media (-moz-bool-pref: "sidebar.expandOnHover") {
|
||||
/* Tab close button when the sidebar is collapsed should
|
||||
not be shown when expand on hover is enabled because once
|
||||
you hover over the launcher to use the button, the launcher
|
||||
starts to expand and the button is no longer shown. Users can
|
||||
rely on the close button within the tab once expanded. */
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user