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:
Emilio Cobos Álvarez
2024-08-20 12:58:16 +00:00
parent bd8b1a3534
commit cb06f25a7a
11 changed files with 69 additions and 137 deletions

View File

@@ -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",
],
},
],

View File

@@ -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/>

View File

@@ -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,

View File

@@ -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;

View File

@@ -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);
}

View File

@@ -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: \

View File

@@ -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)",

View File

@@ -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();

View File

@@ -132,9 +132,6 @@
overflow: auto;
margin: 0;
}
:host(.in-menulist) arrowscrollbox::part(scrollbox-clip) {
overflow: visible;
}
`;
}

View File

@@ -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;
}

View File

@@ -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) {