fix(tabs): wrap case clusters box by box and never route a lineage line through a tab

With tabArrangement 'case' at 1440px (nine tabs in four cases), the lineage
routes ran horizontally through the middle of tabs, cluster labels and box
borders. #538's clusters are `max-width: 100%` boxes that may shrink, so in
the one-line strip every box squeezed and wrapped inside itself (a one-tab
case's swatch alone on a line above its tab). The strip then never
overflowed, so updateTabOverflowMode() never wrapped it, and #544's routing
room (`.lineage-tree.tabs-auto-wrap`: row gap and spine channel) never
applied. computeLineageRows grouped the squeezed tabs by top alone into rows
that overlap (10-40, 20-50, 42-74), and gapUnder put the first row's gap at
y 30, inside the tabs below it.

- On the desktop header strip a cluster keeps its width, so clusters that do
  not fit overflow and the strip wraps box by box; the boxes' own gaps read
  --lineage-row-gap, so the routes run between box rows and through the
  spine channel. A case wider than the whole strip still wraps inside its
  box, and now wraps the strip too (`_tabClustersWrapInside`, the new
  `innerWrap` input of shouldAutoWrapTabs), so its inner rows get the gap.
- computeLineageRows never returns overlapping rows: tabs whose spans
  overlap are one row. gapUnder returns null when there is no real gap, and
  a route with no gap is not drawn. A final pass drops any route with a
  segment inside a tab, so no arrangement can draw a line through a tab
  (a layout without the room loses lines instead). Pinned with the squeezed
  rects measured live.

At 1920px, where the clusters fit on one line, nothing changes.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
Codeman maintainer
2026-10-08 21:36:04 +02:00
parent 382d7dd406
commit e308e99f05
6 changed files with 230 additions and 11 deletions
+15
View File
@@ -20891,6 +20891,21 @@ html[data-session-list='sidebar'][data-sidebar='collapsed'] .session-sidebar .ta
padding-left: 3px;
}
/* Desktop: a cluster keeps its width, so clusters that do not fit on one line
overflow the strip and updateTabOverflowMode() wraps it box by box. Allowed
to shrink, every box squeezed and wrapped inside itself instead (a one-tab
case's swatch alone on a line above its tab), the strip never overflowed,
and the lineage routing room, which needs a wrapped strip, never applied:
the routes ran through tabs, labels and box borders. Only a case wider than
the whole strip still wraps inside its box (max-width: 100%), and the strip
wraps around it too (_tabClustersWrapInside). The narrower screens keep
their scrolling strip. */
@media (min-width: 768px) {
.session-tabs-host > .session-tabs.tabs-clusters > .tab-cluster {
flex-shrink: 0;
}
}
/* Side rail and sidebar: every case is a section with its label on top
(vertical space is cheap there, so a one-tab case is labelled too). The
label goes first by `order`, because a sorted rail orders the rows inside