fix(tabs): keep the plain wrap when the strip scrolls, add a browser test

Review follow-up for the L-shaped header strip:

- _syncTabStripCorner() keeps the plain wrap when the plain strip is
  already past --tab-strip-max-height, checked before .tabs-corner goes
  on: the float scrolled with the tabs while the toolbar stayed put, so a
  scrolled strip put tabs under #headerRight, and a re-render of a
  scrolled two-rows strip sized the float from the scrolled frame. The
  "- scrollTop" in contentTop is gone (always 0 now).
- A strip just under its max-height that passes it once the float is in
  falls back to the plain wrap as well.
- test/tab-strip-corner.browser.test.ts (real Chromium, real header and
  styles.css), listed in BROWSER_TEST_GLOBS.
- src/web/CLAUDE.md Tab layouts entry describes the L-shaped classic strip.
This commit is contained in:
timkjr committed 2026-10-26 21:35:04 -05:00
1 parent 3dafc89095
commit 285aa0b2b2
5 files changed
+244 -6

No files matched your search

+12 -3
View File
@@ -6996,7 +6996,12 @@ class CodemanApp {
container.style.removeProperty('--tab-corner-width');
container.style.removeProperty('--tab-corner-height');
};
if (!on) {
// A strip past its max-height scrolls, and the float would scroll its tabs
// under the toolbar, which stays put: keep the plain wrap. The plain strip
// is measured here (updateTabOverflowMode took .tabs-corner off), before
// the class goes on; toggling it on a scrolled strip lets scroll anchoring
// move the strip.
if (!on || container.scrollHeight > container.clientHeight + 1) {
off();
return;
}
@@ -7021,8 +7026,9 @@ class CodemanApp {
const style = getComputedStyle(container);
const strip = container.getBoundingClientRect();
const box = right.getBoundingClientRect();
// The float sits in the strip's scrolled content, at its padding edge.
const contentTop = strip.top + parseFloat(style.paddingTop) - container.scrollTop;
// The float sits at the strip's content padding edge (the plain strip did
// not scroll, so scrollTop is 0).
const contentTop = strip.top + parseFloat(style.paddingTop);
const contentLeft = strip.left + container.clientLeft + parseFloat(style.paddingLeft);
const contentRight = strip.left + container.clientLeft + container.clientWidth - parseFloat(style.paddingRight);
// A first tab that cannot fit beside the toolbar would drop the whole first
@@ -7040,6 +7046,9 @@ class CodemanApp {
if (container.style.getPropertyValue('--tab-corner-height') !== height) {
container.style.setProperty('--tab-corner-height', height);
}
// A plain strip just under its max-height can pass it once the float is in:
// fall back to the plain strip, which fit.
if (container.scrollHeight > container.clientHeight + 1) off();
}
/**
+3 -2
View File
@@ -621,8 +621,9 @@ body {
and only the rows beside the toolbar stop short of it. A flex line cannot
be shortened on its own, so the strip lays its tabs out inline, around a
float the size of the toolbar's box (measured into --tab-corner-width and
--tab-corner-height). The strip scrolls, so it contains the float and is
never shorter than the toolbar it now holds up. Inline tabs space their
--tab-corner-height). The strip is a scroll container, so it contains the
float and is never shorter than the toolbar it now holds up; a strip that
would actually scroll keeps the plain wrap instead. Inline tabs space their
rows with a bottom margin (the old row-gap, lineage's included); the strip
carries no font size of its own, so the whitespace between tabs is 0 wide. */
.header:has(> .session-tabs-host > .session-tabs.tabs-corner) > .header-right {