/** * TabBar — a floating-pill bar of page-level navigation tabs. * * Each tab is an icon + label (+ optional count badge); the active tab is * marked with `aria-current="page"` and an `--accent` underline. The bar is a * glassy `--card` pill that floats on whatever canvas the consumer provides * (the strip area itself is transparent, so it blends with the surrounding * surface). * * Two layouts: * - default (`fill` off): content-width tabs that **centre** when they fit and * scroll from the inline-start (`safe center`) when they overflow, with a * gutter preserved at both ends. The label stacks under the icon below `sm`. * Use this when the tab set is open-ended (e.g. a marketplace app's routes). * - `fill`: equal-width tabs that fill the bar and always stack the label under * the icon — a fixed, always-visible set that fits any column width without * scrolling (e.g. a patient portal's handful of sections). * * Tabs render as links when given an `href` (real navigation) or as buttons * otherwise (in-app view switching via `onSelect`). Use it as a header (top, * default) for section navigation; `position="bottom"` floats it from the * bottom edge for a footer. * * With `collapseToMenu`, the strip folds into a single DropdownMenu whenever the * tabs don't fit — below the `sm` breakpoint OR when they overflow their * container at any width (a narrow column on a wide screen, e.g. a page squeezed * between two sidebars, clips the tabs just the same as a small viewport). * * SPA / consumer-router links: pass `renderLink` and TabBar hands each `href` * tab off to your router's `` instead of rendering its own `` — the * embedded MarketplaceAppShell strip uses this so a tab click is a client-side * route change, not a full page navigation. The kit forwards the same * `className` + `aria-current` so the accent-underline active styling and the * `aria-current="page"` marker survive in both modes. With `renderLink` * omitted the output is the plain `` exactly as before. */ import { type MouseEvent, type ReactNode } from 'react'; export interface TabBarItem { /** Stable id; also the value handed to `onSelect` for button tabs. */ id: string; /** Pre-translated label — consumers localise their own nav copy. */ label: string; /** Optional leading icon (a lucide-react element or equivalent), tinted with `--accent`. */ icon?: ReactNode; /** Optional unseen-item count rendered as a pill badge. */ badgeCount?: number; /** Mark the tab as the current page (`aria-current='page'` + accent underline). */ isActive?: boolean; /** When set, the tab renders as a link to this href; otherwise it's a button. */ href?: string; /** * Optional click handler threaded onto the link tab's `` (or, when * `renderLink` is supplied, available to the consumer's router element). Use * it to intercept a same-origin click and route client-side without a full * navigation. Only applies to `href` (link) tabs — button tabs use `onSelect`. */ onClick?: (event: MouseEvent) => void; } /** * Props the kit hands to `renderLink` for each `href` tab. The consumer returns * their router's `` carrying the same `className` (the active * accent-underline styling) and `aria-current` (`'page'` on the active tab). */ export interface TabBarRenderLinkProps { /** The tab's destination — feed it to your router's `to` / `href`. */ href: string; /** The kit's tab classes (CVA output) — apply verbatim to the link element. */ className: string; /** Icon + label + badge — render as the link's children. */ children: ReactNode; /** `'page'` on the active tab, otherwise omitted — forward to the link. */ 'aria-current'?: 'page'; /** * The tab's stable `TabBarItem.id`, as the agent / automation DOM hook. * Spread it onto your router link (`{...rest}`) so the tab stays addressable * by `[data-tab-id]` the same way the kit's own `` / `