import {
Breadcrumb,
BreadcrumbEllipsis,
BreadcrumbItem,
BreadcrumbLink,
BreadcrumbList,
BreadcrumbPage,
BreadcrumbSeparator,
} from '@/components/breadcrumb';
import {
Pagination,
PaginationContent,
PaginationEllipsis,
PaginationItem,
PaginationLink,
PaginationNext,
PaginationPrevious,
} from '@/components/pagination';
import type { PaginationProps } from '@/components/pagination';
import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/tabs';
import type { TabsListProps } from '@/components/tabs';
import { CalendarIcon, ChevronRightIcon } from '@/icons';
import * as React from 'react';
import { PALETTES } from './axis-values';
import type { Entry } from './types';
export const breadcrumb: Entry = {
slug: 'breadcrumb',
name: 'Breadcrumb',
group: 'Navigation',
description:
'The path to the current page. Only the separator carries palette colour — CBAR draws it turquoise, which is why the default palette here is `secondary` rather than `primary`.',
imports: { subpath: 'breadcrumb', names: ['Breadcrumb', 'BreadcrumbList', 'BreadcrumbItem'] },
figma: { set: 'breadcrumb' },
axes: {
colorPalette: PALETTES,
size: ['xs', 'md'],
},
defaults: { colorPalette: 'secondary', size: 'md' },
/* Both axes live on BreadcrumbList, not on the nav wrapper — passing them to
Breadcrumb would spread them straight onto the DOM node. */
render: (props) => (
)}>
Home
Settings
),
matrices: [{ title: 'Size × colorPalette', rows: 'size', cols: 'colorPalette' }],
compositions: [
{
name: 'A deeper trail',
render: () => (
Home
Projects
Design system
),
},
{
name: 'With a collapsed middle',
description:
'Past three or four levels, collapse rather than wrap — `BreadcrumbEllipsis` carries its own accessible name, so the omission is announced instead of silently disappearing.',
render: () => (
Home
Components
Button
),
},
],
};
export const pagination: Entry = {
slug: 'pagination',
name: 'Pagination',
group: 'Navigation',
description:
'Page navigation, rendered as real anchors so pages stay linkable and open-in-new-tab works. CBAR draws every control in the strip at the same 32×32 rather than reusing its Button ladder.',
imports: { subpath: 'pagination', names: ['Pagination', 'PaginationContent', 'PaginationLink'] },
figma: { set: 'Pagination page', pin: { state: 'Default' } },
axes: { colorPalette: PALETTES },
defaults: { colorPalette: 'secondary' },
render: (props) => (
1
2
3
),
matrices: [
{
title: 'colorPalette',
description: 'Only the selected page takes the palette; the rest stay on the muted surface.',
rows: 'colorPalette',
},
],
compositions: [
{
name: 'Full strip',
render: () => (
1
2
3
24
),
},
],
};
export const tabs: Entry = {
slug: 'tabs',
name: 'Tabs',
group: 'Navigation',
description:
'Sibling views sharing one region. `variant`, `size` and `colorPalette` live on TabsList — the Tabs root only owns `orientation` and the selected value.',
imports: { subpath: 'tabs', names: ['Tabs', 'TabsList', 'TabsTrigger', 'TabsContent'] },
figma: { set: 'tabsList' },
axes: {
variant: ['line', 'subtle', 'outline', 'plain', 'default'],
colorPalette: PALETTES,
size: ['md', 'lg'],
},
defaults: { variant: 'line', colorPalette: 'secondary', size: 'md' },
render: (props) => (
One
Two
),
matrices: [
{
title: 'Variant × colorPalette',
description:
'The `--ctl-soft` role exists for this: CBAR paints hover and selected identically, which makes an unselected tab look selected. Hover lands one step below instead.',
rows: 'variant',
cols: 'colorPalette',
pin: { size: 'md' },
},
{ title: 'Variant × size', rows: 'variant', cols: 'size', pin: { colorPalette: 'secondary' } },
],
compositions: [
{
name: 'Icon slots',
description:
"CBAR's `tabs` set carries `.iconStart?` (on by default) and `.iconEnd?` (off) as independent booleans. A TabsTrigger takes any `svg` child on either side — `iconSizing` handles the rest.",
render: () => (
Leading
Trailing
Both
Neither
),
},
{
name: 'With panels',
render: () => (
Account
Security
Billing
Name, e-mail and locale.
Password and two-factor authentication.
Plan, invoices and payment method.
),
},
{
name: 'Vertical',
description:
'`orientation` is the one shape prop that lives on the Tabs root rather than on TabsList — it changes which arrow keys move the selection, not just the layout.',
render: () => (
Overview
Activity
Settings
Traffic, conversion and revenue for the last 30 days.
Everything that happened in this project recently.
Project name, visibility and danger zone.
),
},
{
name: 'With a disabled tab',
description:
'The arrow keys skip it and it keeps its place in the strip — which is the point: a tab nobody can open still says the section exists.',
render: () => (
Overview
Billing
Billing is only available on paid plans.
),
},
],
};