Bug 1913322 - Make arrowscrollbox use resizeobserver rather than overflow/underflow events. r=Gijs,dao,desktop-theme-reviewers,tabbrowser-reviewers,frontend-codestyle-reviewers
For that, make the <slot> have a box. Keep firing the overflow / underflow events, but only in cases relative to the arrowScrollbox. Remove unneeded scrollbox-clip box, and replace it by `overflow-clip-box-block: content-box` in the only place that we make the scrollbox grow. Differential Revision: https://phabricator.services.mozilla.com/D219249
This commit is contained in:
@@ -65,7 +65,14 @@ module.exports = {
|
||||
"property-no-unknown": [
|
||||
true,
|
||||
{
|
||||
ignoreProperties: ["overflow-clip-box"],
|
||||
ignoreProperties: [
|
||||
// overflow-clip-box is Gecko-specific and not exposed to web
|
||||
// content. Might be replaced with overflow-clip-margin, see:
|
||||
// https://github.com/w3c/csswg-drafts/issues/10745
|
||||
"overflow-clip-box",
|
||||
"overflow-clip-box-block",
|
||||
"overflow-clip-box-inline",
|
||||
],
|
||||
},
|
||||
],
|
||||
|
||||
|
||||
@@ -66,7 +66,7 @@
|
||||
tooltip="dynamic-shortcut-tooltip"
|
||||
data-l10n-id="tabs-toolbar-new-tab"/>
|
||||
</html:div>
|
||||
<arrowscrollbox id="tabbrowser-arrowscrollbox" orient="horizontal" flex="1" style="min-width: 1px;" clicktoscroll="true" scrolledtostart="true" scrolledtoend="true">
|
||||
<arrowscrollbox id="tabbrowser-arrowscrollbox" orient="horizontal" flex="1" style="min-width: 1px;" clicktoscroll="" scrolledtostart="" scrolledtoend="">
|
||||
<tab is="tabbrowser-tab" class="tabbrowser-tab" selected="true" visuallyselected="" fadein=""/>
|
||||
<hbox id="tabbrowser-arrowscrollbox-periphery">
|
||||
<toolbartabstop/>
|
||||
|
||||
@@ -30,12 +30,6 @@ let ignoreList = [
|
||||
errorMessage: /Unknown pseudo-class.*-moz-/i,
|
||||
isFromDevTools: false,
|
||||
},
|
||||
// Reserved to UA sheets unless layout.css.overflow-clip-box.enabled flipped to true.
|
||||
{
|
||||
sourceName: /(?:res|gre-resources)\/forms\.css$/i,
|
||||
errorMessage: /Unknown property.*overflow-clip-box/i,
|
||||
isFromDevTools: false,
|
||||
},
|
||||
// content: -moz-alt-content is UA-only.
|
||||
{
|
||||
sourceName: /\b(html)\.css$/i,
|
||||
|
||||
@@ -1243,16 +1243,14 @@
|
||||
_initializeArrowScrollbox() {
|
||||
let arrowScrollbox = this.arrowScrollbox;
|
||||
let previewElement = document.getElementById("tab-preview-panel");
|
||||
arrowScrollbox.shadowRoot.addEventListener(
|
||||
arrowScrollbox.addEventListener(
|
||||
"underflow",
|
||||
event => {
|
||||
// Ignore underflow events:
|
||||
// - from nested scrollable elements
|
||||
// - for vertical orientation
|
||||
// - corresponding to an overflow event that we ignored
|
||||
if (
|
||||
event.originalTarget != arrowScrollbox.scrollbox ||
|
||||
event.detail == 0 ||
|
||||
event.target != arrowScrollbox ||
|
||||
!this.hasAttribute("overflow")
|
||||
) {
|
||||
return;
|
||||
@@ -1275,13 +1273,12 @@
|
||||
true
|
||||
);
|
||||
|
||||
arrowScrollbox.shadowRoot.addEventListener("overflow", event => {
|
||||
arrowScrollbox.addEventListener("overflow", event => {
|
||||
// Ignore overflow events:
|
||||
// - from nested scrollable elements
|
||||
// - for vertical orientation
|
||||
if (
|
||||
event.originalTarget != arrowScrollbox.scrollbox ||
|
||||
event.detail == 0 ||
|
||||
event.target != arrowScrollbox ||
|
||||
event.originalTarget.getAttribute("orient") == "vertical"
|
||||
) {
|
||||
return;
|
||||
|
||||
@@ -736,9 +736,7 @@ tab-group {
|
||||
transition: opacity 150ms ease;
|
||||
}
|
||||
|
||||
&::part(scrollbox-clip) {
|
||||
/* Needed to prevent tabstrip from growing as wide as the sum of the tabs'
|
||||
page-title widths when emulating XUL with modern flexbox. */
|
||||
&::part(scrollbox) {
|
||||
contain: inline-size;
|
||||
}
|
||||
|
||||
@@ -763,14 +761,14 @@ tab-group {
|
||||
background-color: SelectedItem;
|
||||
}
|
||||
|
||||
&:not([scrolledtostart=true])::part(scrollbutton-up):hover,
|
||||
&:not([scrolledtoend=true])::part(scrollbutton-down):hover {
|
||||
&:not([scrolledtostart])::part(scrollbutton-up):hover,
|
||||
&:not([scrolledtoend])::part(scrollbutton-down):hover {
|
||||
background-color: var(--toolbarbutton-hover-background);
|
||||
color: inherit;
|
||||
}
|
||||
|
||||
&:not([scrolledtostart=true])::part(scrollbutton-up):hover:active,
|
||||
&:not([scrolledtoend=true])::part(scrollbutton-down):hover:active {
|
||||
&:not([scrolledtostart])::part(scrollbutton-up):hover:active,
|
||||
&:not([scrolledtoend])::part(scrollbutton-down):hover:active {
|
||||
background-color: var(--toolbarbutton-active-background);
|
||||
color: inherit;
|
||||
}
|
||||
@@ -791,12 +789,12 @@ tab-group {
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
&[overflowing="true"]:not([scrolledtoend="true"]) {
|
||||
&[overflowing]:not([scrolledtoend]) {
|
||||
mask-image: linear-gradient(to bottom, black 98%, transparent 100%);
|
||||
}
|
||||
}
|
||||
|
||||
#tabbrowser-tabs[orient="vertical"]:has(> #tabbrowser-arrowscrollbox[overflowing="true"]) {
|
||||
#tabbrowser-tabs[orient="vertical"]:has(> #tabbrowser-arrowscrollbox[overflowing]) {
|
||||
border-bottom: 1px solid color-mix(in srgb, currentColor 25%, transparent);
|
||||
}
|
||||
|
||||
|
||||
@@ -151,7 +151,7 @@ ${helpers.single_keyword(
|
||||
"OverflowClipBox",
|
||||
"computed::OverflowClipBox::PaddingBox",
|
||||
engines="gecko",
|
||||
enabled_in="ua",
|
||||
enabled_in="chrome",
|
||||
gecko_pref="layout.css.overflow-clip-box.enabled",
|
||||
animation_type="discrete",
|
||||
spec="Internal, may be standardized in the future: \
|
||||
|
||||
@@ -17,7 +17,7 @@ ${helpers.two_properties_shorthand(
|
||||
"overflow-clip-box-block",
|
||||
"overflow-clip-box-inline",
|
||||
engines="gecko",
|
||||
enabled_in="ua",
|
||||
enabled_in="chrome",
|
||||
gecko_pref="layout.css.overflow-clip-box.enabled",
|
||||
spec="Internal, may be standardized in the future "
|
||||
"(https://developer.mozilla.org/en-US/docs/Web/CSS/overflow-clip-box)",
|
||||
|
||||
@@ -14,7 +14,6 @@
|
||||
static get inheritedAttributes() {
|
||||
return {
|
||||
"#scrollbutton-up": "disabled=scrolledtostart",
|
||||
".scrollbox-clip": "orient",
|
||||
scrollbox: "orient,align,pack,dir,smoothscroll",
|
||||
"#scrollbutton-down": "disabled=scrolledtoend",
|
||||
};
|
||||
@@ -26,11 +25,9 @@
|
||||
<html:link rel="stylesheet" href="chrome://global/skin/arrowscrollbox.css"/>
|
||||
<toolbarbutton id="scrollbutton-up" part="scrollbutton-up" keyNav="false" data-l10n-id="overflow-scroll-button-backwards"/>
|
||||
<spacer part="overflow-start-indicator"/>
|
||||
<box class="scrollbox-clip" part="scrollbox-clip" flex="1">
|
||||
<scrollbox part="scrollbox" flex="1">
|
||||
<html:slot/>
|
||||
</scrollbox>
|
||||
</box>
|
||||
<scrollbox part="scrollbox" flex="1">
|
||||
<html:slot/>
|
||||
</scrollbox>
|
||||
<spacer part="overflow-end-indicator"/>
|
||||
<toolbarbutton id="scrollbutton-down" part="scrollbutton-down" keyNav="false" data-l10n-id="overflow-scroll-button-forwards"/>
|
||||
`;
|
||||
@@ -103,25 +100,25 @@
|
||||
this.shadowRoot.addEventListener("mouseup", this.on_mouseup.bind(this));
|
||||
this.shadowRoot.addEventListener("mouseout", this.on_mouseout.bind(this));
|
||||
|
||||
// These events don't get retargeted outside of the shadow root, but
|
||||
// some callers like tests wait for these events. So run handlers
|
||||
// and then retarget events from the scrollbox to the host.
|
||||
this.scrollbox.addEventListener(
|
||||
"underflow",
|
||||
event => {
|
||||
this.on_underflow(event);
|
||||
this.dispatchEvent(new Event("underflow"));
|
||||
},
|
||||
true
|
||||
);
|
||||
this.scrollbox.addEventListener(
|
||||
"overflow",
|
||||
event => {
|
||||
this.on_overflow(event);
|
||||
this.dispatchEvent(new Event("overflow"));
|
||||
},
|
||||
true
|
||||
);
|
||||
this._overflowObserver = new ResizeObserver(([entry]) => {
|
||||
let overflowing = false;
|
||||
if (this.getAttribute("orient") == "vertical") {
|
||||
overflowing = entry.contentRect.height > this.scrollbox.clientHeight;
|
||||
} else {
|
||||
overflowing = entry.contentRect.width > this.scrollbox.clientWidth;
|
||||
}
|
||||
if (overflowing == this.hasAttribute("overflowing")) {
|
||||
return;
|
||||
}
|
||||
window.requestAnimationFrame(() => {
|
||||
this.toggleAttribute("overflowing", overflowing);
|
||||
this._updateScrollButtonsDisabledState();
|
||||
this.dispatchEvent(
|
||||
new CustomEvent(overflowing ? "overflow" : "underflow")
|
||||
);
|
||||
});
|
||||
});
|
||||
this._overflowObserver.observe(this.shadowRoot.querySelector("slot"));
|
||||
this.scrollbox.addEventListener("scroll", event => {
|
||||
this.on_scroll(event);
|
||||
this.dispatchEvent(new Event("scroll"));
|
||||
@@ -624,17 +621,8 @@
|
||||
}
|
||||
}
|
||||
|
||||
if (scrolledToEnd) {
|
||||
this.setAttribute("scrolledtoend", "true");
|
||||
} else {
|
||||
this.removeAttribute("scrolledtoend");
|
||||
}
|
||||
|
||||
if (scrolledToStart) {
|
||||
this.setAttribute("scrolledtostart", "true");
|
||||
} else {
|
||||
this.removeAttribute("scrolledtostart");
|
||||
}
|
||||
this.toggleAttribute("scrolledtoend", scrolledToEnd);
|
||||
this.toggleAttribute("scrolledtostart", scrolledToStart);
|
||||
}, 0);
|
||||
});
|
||||
}
|
||||
@@ -763,57 +751,6 @@
|
||||
this._touchStart = -1;
|
||||
}
|
||||
|
||||
on_underflow(event) {
|
||||
// Ignore underflow events:
|
||||
// - from nested scrollable elements
|
||||
// - corresponding to an overflow event that we ignored
|
||||
if (event.target != this.scrollbox || !this.hasAttribute("overflowing")) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Ignore events that doesn't match our orientation.
|
||||
// Scrollport event orientation:
|
||||
// 0: vertical
|
||||
// 1: horizontal
|
||||
// 2: both
|
||||
if (this.getAttribute("orient") == "vertical") {
|
||||
if (event.detail == 1) {
|
||||
return;
|
||||
}
|
||||
} else if (event.detail == 0) {
|
||||
// horizontal scrollbox
|
||||
return;
|
||||
}
|
||||
|
||||
this.removeAttribute("overflowing");
|
||||
this._updateScrollButtonsDisabledState();
|
||||
}
|
||||
|
||||
on_overflow(event) {
|
||||
// Ignore overflow events:
|
||||
// - from nested scrollable elements
|
||||
if (event.target != this.scrollbox) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Ignore events that doesn't match our orientation.
|
||||
// Scrollport event orientation:
|
||||
// 0: vertical
|
||||
// 1: horizontal
|
||||
// 2: both
|
||||
if (this.getAttribute("orient") == "vertical") {
|
||||
if (event.detail == 1) {
|
||||
return;
|
||||
}
|
||||
} else if (event.detail == 0) {
|
||||
// horizontal scrollbox
|
||||
return;
|
||||
}
|
||||
|
||||
this.setAttribute("overflowing", "true");
|
||||
this._updateScrollButtonsDisabledState();
|
||||
}
|
||||
|
||||
on_scroll() {
|
||||
this._isScrolling = true;
|
||||
this._updateScrollButtonsDisabledState();
|
||||
|
||||
@@ -132,9 +132,6 @@
|
||||
overflow: auto;
|
||||
margin: 0;
|
||||
}
|
||||
:host(.in-menulist) arrowscrollbox::part(scrollbox-clip) {
|
||||
overflow: visible;
|
||||
}
|
||||
`;
|
||||
}
|
||||
|
||||
|
||||
@@ -2,14 +2,18 @@
|
||||
* 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/. */
|
||||
|
||||
@namespace url("http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul");
|
||||
|
||||
:host([scrolledtostart=true])::part(overflow-start-indicator),
|
||||
:host([scrolledtoend=true])::part(overflow-end-indicator),
|
||||
:host(:not([overflowing=true])) > toolbarbutton {
|
||||
:host([scrolledtostart])::part(overflow-start-indicator),
|
||||
:host([scrolledtoend])::part(overflow-end-indicator),
|
||||
:host(:not([overflowing])) > toolbarbutton {
|
||||
visibility: collapse;
|
||||
}
|
||||
|
||||
slot {
|
||||
display: flex;
|
||||
flex: 1 0 auto;
|
||||
flex-direction: inherit;
|
||||
}
|
||||
|
||||
/* Scroll arrows */
|
||||
|
||||
toolbarbutton {
|
||||
@@ -21,7 +25,7 @@ toolbarbutton {
|
||||
padding: 2px;
|
||||
}
|
||||
|
||||
toolbarbutton[disabled="true"] {
|
||||
toolbarbutton[disabled] {
|
||||
fill-opacity: var(--toolbarbutton-disabled-opacity);
|
||||
}
|
||||
|
||||
@@ -43,13 +47,12 @@ toolbarbutton > .toolbarbutton-text {
|
||||
}
|
||||
|
||||
@media not (-moz-platform: macos) {
|
||||
:host(:not([clicktoscroll="true"])) > toolbarbutton {
|
||||
:host(:not([clicktoscroll])) > toolbarbutton {
|
||||
appearance: none;
|
||||
}
|
||||
}
|
||||
|
||||
scrollbox,
|
||||
.scrollbox-clip {
|
||||
scrollbox {
|
||||
min-width: 0;
|
||||
min-height: 0;
|
||||
}
|
||||
|
||||
@@ -49,32 +49,31 @@ menuseparator::before {
|
||||
/* Scroll buttons */
|
||||
|
||||
/* Hide arrow buttons when there's nothing to scroll in that direction */
|
||||
.menupopup-arrowscrollbox[scrolledtostart="true"]::part(scrollbutton-up),
|
||||
.menupopup-arrowscrollbox[scrolledtoend="true"]::part(scrollbutton-down) {
|
||||
.menupopup-arrowscrollbox[scrolledtostart]::part(scrollbutton-up),
|
||||
.menupopup-arrowscrollbox[scrolledtoend]::part(scrollbutton-down) {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.menupopup-arrowscrollbox::part(scrollbox) {
|
||||
/* This makes the padding / margin trick below work */
|
||||
overflow-clip-box-block: content-box;
|
||||
}
|
||||
|
||||
/* Prevent the scrolled contents of the menupopup from jumping vertically when
|
||||
* the arrow buttons appear / disappear, by positioning ::part(scrollbox) in
|
||||
* such a way that its edges are at the same position as the edges of
|
||||
* arrowscrollbox regardless of scroll button visibility.
|
||||
*/
|
||||
.menupopup-arrowscrollbox:not([scrolledtostart="true"])::part(scrollbox) {
|
||||
.menupopup-arrowscrollbox:not([scrolledtostart])::part(scrollbox) {
|
||||
/* scrollbutton-up is visible; shift our top edge up by its height. */
|
||||
margin-top: -16px;
|
||||
padding-top: 16px;
|
||||
}
|
||||
|
||||
.menupopup-arrowscrollbox:not([scrolledtoend="true"])::part(scrollbox) {
|
||||
.menupopup-arrowscrollbox:not([scrolledtoend])::part(scrollbox) {
|
||||
/* scrollbutton-down is visible; shift our bottom edge down by its height. */
|
||||
margin-bottom: -16px;
|
||||
}
|
||||
|
||||
.menupopup-arrowscrollbox::part(scrollbox-clip) {
|
||||
/* In the space where the arrow buttons overlap the scrollbox, clip away the
|
||||
* scrollbox so that nothing is shown behind the arrow button even if the
|
||||
* button is transparent.
|
||||
*/
|
||||
overflow: clip;
|
||||
padding-bottom: 16px;
|
||||
}
|
||||
|
||||
@media (-moz-platform: windows) or (-moz-platform: linux) {
|
||||
|
||||
Reference in New Issue
Block a user