commit 5a36124942f4affb61b7394e62d6461cf5d260fd
parent f35f40300ec3a0a8faa1f34ceddfcf5f6394820c
Author: Kelly Cochrane <kcochrane@mozilla.com>
Date: Thu, 30 Oct 2025 13:23:40 +0000
Bug 1992844 - Update styles for split views within tab groups r=tabbrowser-reviewers,sthompson
Differential Revision: https://phabricator.services.mozilla.com/D269229
Diffstat:
3 files changed, 119 insertions(+), 18 deletions(-)
diff --git a/browser/components/tabbrowser/content/tabbrowser.js b/browser/components/tabbrowser/content/tabbrowser.js
@@ -6331,6 +6331,15 @@
return !!element?.classList?.contains("tab-group-label");
}
+ /**
+ * @param {Element} element
+ * @returns {boolean}
+ * `true` if element is a `<tab-split-view-wrapper>`
+ */
+ isSplitViewWrapper(element) {
+ return !!(element?.tagName == "tab-split-view-wrapper");
+ }
+
_updateTabsAfterInsert() {
for (let i = 0; i < this.tabs.length; i++) {
this.tabs[i]._tPos = i;
@@ -6607,10 +6616,26 @@
if (aTab.group && aTab.group.id === aGroup.id) {
return;
}
-
- this.#handleTabMove(aTab, () => aGroup.appendChild(aTab), metricsContext);
- this.removeFromMultiSelectedTabs(aTab);
- this.tabContainer._notifyBackgroundTab(aTab);
+ if (aTab.splitview) {
+ let splitViewTabs = aTab.splitview.tabs;
+ this.#handleTabMove(
+ aTab.splitview,
+ () => aGroup.appendChild(aTab.splitview),
+ metricsContext
+ );
+ for (const splitViewTab of splitViewTabs) {
+ this.removeFromMultiSelectedTabs(splitViewTab);
+ this.tabContainer._notifyBackgroundTab(splitViewTab);
+ }
+ } else {
+ this.#handleTabMove(
+ aTab,
+ () => aGroup.appendChild(aTab),
+ metricsContext
+ );
+ this.removeFromMultiSelectedTabs(aTab);
+ this.tabContainer._notifyBackgroundTab(aTab);
+ }
}
/**
@@ -6685,8 +6710,12 @@
tabs = [element];
} else if (this.isTabGroup(element)) {
tabs = element.tabs;
+ } else if (this.isSplitViewWrapper(element)) {
+ tabs = element.tabs;
} else {
- throw new Error("Can only move a tab or tab group within the tab bar");
+ throw new Error(
+ "Can only move a tab, tab group, or split view within the tab bar"
+ );
}
let wasFocused = document.activeElement == this.selectedTab;
diff --git a/browser/components/tabbrowser/content/tabgroup.js b/browser/components/tabbrowser/content/tabgroup.js
@@ -187,6 +187,7 @@
});
this.hasActiveTab = hasActiveTab;
this.#updateOverflowLabel();
+ this.#updateLastTabOrSplitViewAttr();
}
for (const mutation of mutations) {
for (const addedNode of mutation.addedNodes) {
@@ -430,6 +431,22 @@
});
}
+ #updateLastTabOrSplitViewAttr() {
+ const LAST_ITEM_ATTRIBUTE = "last-tab-or-split-view";
+ let lastTab = this.tabs[this.tabs.length - 1];
+ let currentLastTabOrSplitView = lastTab.splitview
+ ? lastTab.splitview
+ : lastTab;
+
+ let prevLastTabOrSplitView = this.querySelector(
+ `[${LAST_ITEM_ATTRIBUTE}]`
+ );
+ if (prevLastTabOrSplitView !== currentLastTabOrSplitView) {
+ prevLastTabOrSplitView?.toggleAttribute(LAST_ITEM_ATTRIBUTE);
+ currentLastTabOrSplitView.toggleAttribute(LAST_ITEM_ATTRIBUTE);
+ }
+ }
+
/**
* @returns {MozTabbrowserTab[]}
*/
diff --git a/browser/themes/shared/tabbrowser/tabs.css b/browser/themes/shared/tabbrowser/tabs.css
@@ -1157,32 +1157,79 @@
/* Split View */
tab-group > tab-split-view-wrapper {
+ &[aria-hidden="true"] {
+ display: none;
+ }
#tabbrowser-tabs[orient="vertical"] & {
- margin-block: calc(var(--space-xsmall) * -1);
+ margin-inline-end: var(--space-medium);
+
+ #tabbrowser-tabs[expanded] & {
+ margin-inline-start: calc(var(--space-medium) + var(--tab-inner-inline-margin) - var(--space-xsmall));
+ }
- .tabbrowser-tab:last-child {
+ #tabbrowser:not([expanded]) & {
+ margin-inline-start: calc(var(--space-medium) - var(--space-xsmall));
+ }
+
+ #tabbrowser-tabs:not([expanded]) & {
.tab-group-line {
- display: none;
+ inset-inline-start: calc(((var(--space-medium)) * -1) + 2px) !important;
}
}
- }
- @container vertical-tabs-container (max-width: 210px) {
- #tabbrowser-tabs[orient="vertical"] & {
- margin-inline-start: 0;
+ &[last-tab-or-split-view] > .tabbrowser-tab .tab-group-line {
+ inset-block-start: calc(var(--space-xsmall) * -2);
+ }
+
+ > .tabbrowser-tab {
+ overflow: visible;
+
+ .tab-group-line {
+ inset-inline-start: calc(var(--space-medium) * -1) !important;
+ inset-block: calc(var(--space-xsmall) * -1);
+
+ @container vertical-tabs-container (max-width: 210px) {
+ inset-inline-start: calc(var(--space-large) * -1) !important;
+ }
+ }
- .tabbrowser-tab:last-child {
+ &:last-child {
.tab-group-line {
- display: flex;
+ display: none;
+
+ @container vertical-tabs-container (max-width: 210px) {
+ display: flex;
+ }
}
}
}
}
+}
+
+#tabbrowser-tabs[orient="horizontal"] tab-split-view-wrapper {
+ margin-block: var(--tab-block-margin);
+ margin-inline: 0;
+ align-items: flex-end;
+ padding: 2px 0;
+
+ &[last-tab-or-split-view] .tabbrowser-tab:last-child .tab-group-line {
+ inset-inline-end: calc(var(--tab-border-radius) / 2);
+ }
- #tabbrowser-tabs[orient="horizontal"] & {
- margin-inline: 0;
- padding-block-end: 0;
- padding-inline: 0;
+ .tabbrowser-tab {
+ padding-inline: 2px;
+ .tab-background {
+ --tab-min-height: 32px;
+
+ .tab-group-line {
+ inset-block-end: calc(((var(--tab-block-margin) / 2) + var(--space-xsmall)) * -1);
+ inset-inline-start: calc(var(--space-small) * -2);
+ }
+ }
+
+ tab-group & {
+ overflow: visible;
+ }
}
}
@@ -1263,6 +1310,7 @@ tab-group > tab-split-view-wrapper {
#tabbrowser-tabs[orient="vertical"] & {
border-radius: var(--tab-border-radius);
gap: var(--space-xsmall);
+ grid-template-columns: 49.5% 49.5%;
@container vertical-tabs-container (max-width: 210px) {
grid-template-columns: 1fr;
@@ -1279,6 +1327,13 @@ tab-group > tab-split-view-wrapper {
}
}
}
+
+ #tabbrowser-tabs[orient="vertical"]:not([expanded]) & {
+ .tab-close-button {
+ top: -5px;
+ inset-inline-start: -7px;
+ }
+ }
}
/* Tab Groups */