diff --git a/apps/desktop/src/components/ui/pane-tab.test.tsx b/apps/desktop/src/components/ui/pane-tab.test.tsx index bdd275497a..44b52294bf 100644 --- a/apps/desktop/src/components/ui/pane-tab.test.tsx +++ b/apps/desktop/src/components/ui/pane-tab.test.tsx @@ -124,6 +124,26 @@ describe('PaneTab hover close button', () => { expect(screen.queryByRole('button', { name: 'Close' })).toBeNull() }) + it('reserves a close-button runway only on closeable horizontal tabs', () => { + const onClose = vi.fn() + const { rerender } = render( + + BROWSER + + ) + + const horizontalTab = screen.getByText('BROWSER').parentElement?.parentElement + expect(horizontalTab?.className).toContain('pr-9') + + rerender( + + BROWSER + + ) + const verticalTab = screen.getByText('BROWSER').parentElement?.parentElement + expect(verticalTab?.className).not.toContain('pr-9') + }) + it('a closeable horizontal tab always shows its ✕ — the chip and the pointer gestures are one affordance', () => { const onClose = vi.fn() render( diff --git a/apps/desktop/src/components/ui/pane-tab.tsx b/apps/desktop/src/components/ui/pane-tab.tsx index dbf9fab10e..8b0703a9e2 100644 --- a/apps/desktop/src/components/ui/pane-tab.tsx +++ b/apps/desktop/src/components/ui/pane-tab.tsx @@ -102,6 +102,7 @@ export const PaneTab = React.forwardRef(function P className={cn( TAB, vertical ? TAB_VERTICAL : TAB_HORIZONTAL, + !vertical && onClose && 'pr-9', edge, active ? cn(TAB_ACTIVE, !vertical && TAB_ACTIVE_UNDERLINE) @@ -163,10 +164,9 @@ export const PaneTab = React.forwardRef(function P )} {onClose && !vertical && ( - // Hover ✕, painted OVER the label's right edge as an overlay (no - // layout shift, tab width never jumps on hover). The runway is a tiny - // transparent→`--tab-face` gradient, so the button melts into the - // tab's effective surface instead of hard-clipping the text under it. + // Hover ✕ stays absolutely positioned so hover never shifts the tab. + // The tab reserves a fixed right runway for this overlay, keeping the + // label clear of the gradient/button even for short labels like BROWSER. // Rendered after the dirty dot: on hover the ✕ takes the dot's spot, // VS Code-style.