fix(#1029): use getBoundingClientRect for tab overflow cutoff
The old measurement used tabbar.clientWidth which includes horizontal padding (~2em / ~30px total), causing an over-allocation of the same amount. Flex gap between tabs (0.2em) was also not counted in the accumulated offsetWidth, adding another ~20px of error. Together these caused the algorithm to leave too many tabs visible, overflowing the bar and pushing the ⋮ button off the right edge of the screen. Replace the clientWidth + cumulative-offsetWidth approach with getBoundingClientRect: the cutoff is the tabbar's actual right edge minus its right padding, minus a reserve for the overflow wrapper. Individual tabs are overflowed once their right edge exceeds the cutoff; subsequent tabs are overflowed unconditionally to keep the visible set contiguous and left-anchored.
This commit is contained in:
parent
0f77fc3598
commit
0723737d89
1 changed files with 24 additions and 12 deletions
|
|
@ -3730,20 +3730,32 @@ window.marked = marked;
|
|||
// Step 1: un-overflow all dynamic tabs so we can measure natural widths.
|
||||
dynamic.forEach(t => t.classList.remove('tab-overflowed'));
|
||||
|
||||
// Step 2: measure available width (bar width minus overflow-btn width).
|
||||
// We must read layout AFTER restoring all dynamic tabs.
|
||||
// overflowBtn may be hidden (offsetWidth=0) on the very first call; fall
|
||||
// back to a 32px estimate so the first-pass measurement isn't off.
|
||||
const btnW = overflowBtn.offsetWidth || 32;
|
||||
const availWidth = tabbar.clientWidth - btnW - 8;
|
||||
// Step 2: compute the right boundary where visible tabs must end.
|
||||
// getBoundingClientRect is used instead of clientWidth because
|
||||
// clientWidth includes the tabbar's horizontal padding (~2em total),
|
||||
// causing an over-allocation of ~2em; flex gap between tabs is also
|
||||
// not captured by offsetWidth accumulation. Together these pushed
|
||||
// the ⋮ button off the right edge of the screen.
|
||||
const tabbarRect = tabbar.getBoundingClientRect();
|
||||
const padR = parseFloat(getComputedStyle(tabbar).paddingRight) || 0;
|
||||
// Right edge of the flex content area (inside right padding).
|
||||
// Fall back to clientWidth-based estimate when the rect is zero
|
||||
// (element not in layout, e.g. display:none ancestor).
|
||||
const contentRight = tabbarRect.width > 0
|
||||
? (tabbarRect.right - padR)
|
||||
: (tabbar.clientWidth - padR);
|
||||
// Space to reserve for the overflow wrapper. Use its actual offsetWidth
|
||||
// when available; fall back to 40px on the first call (button hidden).
|
||||
const btnReserve = (overflowWrap.offsetWidth || 40) + 4;
|
||||
const cutoffRight = contentRight - btnReserve;
|
||||
|
||||
// Step 3: walk dynamic tabs left-to-right, accumulating widths.
|
||||
// Any that go over the available width get overflowed.
|
||||
let cumWidth = 0;
|
||||
// Step 3: any tab whose right edge exceeds the cutoff is overflowed,
|
||||
// along with all subsequent tabs (keeps the visible set contiguous
|
||||
// and left-anchored). Once the first offending tab is found, all
|
||||
// following tabs are also overflowed without re-measuring.
|
||||
const dynamicOverflow = [];
|
||||
for (const tab of dynamic) {
|
||||
cumWidth += tab.offsetWidth;
|
||||
if (cumWidth > availWidth) {
|
||||
if (dynamicOverflow.length > 0 || tab.getBoundingClientRect().right > cutoffRight) {
|
||||
dynamicOverflow.push(tab);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue