diff --git a/src/components/ui/__tests__/tabs.test.tsx b/src/components/ui/__tests__/tabs.test.tsx new file mode 100644 index 000000000..1685e00df --- /dev/null +++ b/src/components/ui/__tests__/tabs.test.tsx @@ -0,0 +1,33 @@ +import { describe, expect, it } from "vitest"; +import { renderToStaticMarkup } from "react-dom/server"; + +import { Tabs, TabsList, TabsTrigger } from "../tabs"; + +describe("", () => { + it("clamps the y-axis so a fixed-height strip never paints a vertical scrollbar", () => { + // Marc reported a stray "mini scroll-button" on the right side of + // the feedback inbox tab strip (Open / Acknowledged / Resolved / + // Archived). Root cause: `overflow-x-auto` couples to `overflow-y` + // — once one axis is `auto`, the other can no longer be `visible`, + // so the browser silently flips it to `auto` too. Combined with + // the fixed `h-9` strip and the badges (`py-0.5` + text-xs) that + // ride 1-2 px taller than the strip on some glyph stacks, a + // tiny vertical scrollbar paints on the right edge. + // + // Locking `overflow-y-hidden` on the strip kills the painted bar + // without touching the horizontal swipe behaviour. + const html = renderToStaticMarkup( + + + A + B + + , + ); + const list = html.match(/]*data-slot="tabs-list"[^>]*>/); + expect(list).not.toBeNull(); + expect(list![0]).toMatch(/\boverflow-y-hidden\b/); + // Horizontal scroll behaviour is still intact for long strips. + expect(list![0]).toMatch(/\boverflow-x-auto\b/); + }); +}); diff --git a/src/components/ui/tabs.tsx b/src/components/ui/tabs.tsx index 70835b32f..16bef7550 100644 --- a/src/components/ui/tabs.tsx +++ b/src/components/ui/tabs.tsx @@ -34,8 +34,18 @@ function Tabs({ // `whitespace-nowrap` so labels never word-wrap mid-tab. Desktop // looks identical because the inline-flex shrink-wraps inside the // wider container. +// +// v1.4.19 A7 — `overflow-y-hidden` clamps the y-axis. Browsers couple +// the two overflow axes once one is `auto`: setting only +// `overflow-x: auto` silently flips `overflow-y` to `auto` as well. +// Combined with the fixed `h-9` strip and badge children that ride +// ~1 px taller than the strip on some glyph stacks, a tiny painted +// vertical scrollbar appeared on the right edge of short strips +// (e.g. the admin feedback `Open / Acknowledged / Resolved / +// Archived` tabs Marc reported in v1.4.19). Locking the y-axis hides +// that bar without affecting horizontal swipe behaviour. const tabsListVariants = cva( - "rounded-lg p-[3px] group-data-[orientation=horizontal]/tabs:h-9 data-[variant=line]:rounded-none group/tabs-list text-muted-foreground inline-flex w-fit max-w-full items-center justify-center overflow-x-auto touch-pan-x scrollbar-thin group-data-[orientation=vertical]/tabs:h-fit group-data-[orientation=vertical]/tabs:flex-col group-data-[orientation=vertical]/tabs:overflow-x-visible", + "rounded-lg p-[3px] group-data-[orientation=horizontal]/tabs:h-9 data-[variant=line]:rounded-none group/tabs-list text-muted-foreground inline-flex w-fit max-w-full items-center justify-center overflow-x-auto overflow-y-hidden touch-pan-x scrollbar-thin group-data-[orientation=vertical]/tabs:h-fit group-data-[orientation=vertical]/tabs:flex-col group-data-[orientation=vertical]/tabs:overflow-x-visible group-data-[orientation=vertical]/tabs:overflow-y-visible", { variants: { variant: {