Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions apps/web/src/components/BranchToolbar.logic.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { describe, expect, it } from "vite-plus/test";
import {
dedupeRemoteBranchesWithLocalMatches,
deriveLocalBranchNameFromRemoteRef,
measureContextStripLabelWidth,
resolveEnvironmentOptionLabel,
resolveBranchSelectionTarget,
resolveCurrentWorkspaceLabel,
Expand All @@ -25,6 +26,21 @@ import {
const localEnvironmentId = EnvironmentId.make("environment-local");
const remoteEnvironmentId = EnvironmentId.make("environment-remote");

it.each([200, 100, 0])("measures the full branch-name width when rendered at %ipx", (width) => {
const head = { scrollWidth: 120, dataset: {} };
const tail = { scrollWidth: 80, dataset: {} };
const text = {
scrollWidth: Math.max(width, tail.scrollWidth),
dataset: { slot: "middle-truncate" },
children: [head, tail],
};
const label = {
scrollWidth: width,
querySelectorAll: () => [text, head, tail],
} as unknown as HTMLElement;
expect(measureContextStripLabelWidth(label)).toBe(200);
});

describe("resolvePreviousWorktreeSeed", () => {
it("picks the most recently updated worktree thread", () => {
expect(
Expand Down
11 changes: 11 additions & 0 deletions apps/web/src/components/BranchToolbar.logic.ts
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,17 @@ export function shouldShowComposerContextStrip(input: {
// hysteresis on the way back out keeps the boundary from flapping.
const CONTEXT_STRIP_COMPACT_EXPAND_HYSTERESIS_PX = 16;

export function measureContextStripLabelWidth(label: HTMLElement): number {
return Array.from(label.querySelectorAll<HTMLElement>("*")).reduce((width, inner) => {
// Sum both halves of middle-truncated text, even when collapsed.
const innerWidth =
inner.dataset.slot === "middle-truncate"
? Array.from(inner.children).reduce((total, child) => total + child.scrollWidth, 0)
: inner.scrollWidth;
return Math.max(width, innerWidth);
}, label.scrollWidth);
}

export function resolveContextStripLabelsCompact(input: {
compact: boolean;
neededWidth: number;
Expand Down
9 changes: 2 additions & 7 deletions apps/web/src/components/BranchToolbar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ import { useProject, useThreadShell, useThreadShellsForProjectRefs } from "../st
import {
type EnvMode,
type EnvironmentOption,
measureContextStripLabelWidth,
resolveContextStripLabelsCompact,
resolveCurrentWorkspaceLabel,
resolveEnvModeLabel,
Expand Down Expand Up @@ -381,13 +382,7 @@ function useLabelsOverflow(element: HTMLDivElement | null): boolean {
}
needed += stripGap * Math.max(0, groups - 1);
for (const label of current.querySelectorAll<HTMLElement>("[data-composer-label]")) {
// The clipping can happen below the marker (SelectValue truncates
// internally), where the outer span's scrollWidth matches its clipped
// box. The text's real width is the largest scrollWidth in the subtree.
let textWidth = label.scrollWidth;
for (const inner of label.querySelectorAll<HTMLElement>("*")) {
textWidth = Math.max(textWidth, inner.scrollWidth);
}
const textWidth = measureContextStripLabelWidth(label);
// Subtract the visible width even during an animation. The content
// sum already includes it; only the hidden text needs reserving.
needed += Math.max(0, textWidth - label.getBoundingClientRect().width);
Expand Down
1 change: 1 addition & 0 deletions apps/web/src/components/ui/middle-truncate.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ export function MiddleTruncate({
const split = splitForMiddleTruncate(value, tail);
return (
<span
data-slot="middle-truncate"
{...(showTitle ? { title: value } : {})}
className={cn("inline-flex min-w-0 max-w-full overflow-hidden whitespace-nowrap", className)}
{...props}
Expand Down
Loading