import { Badge } from '@/components/badge'; import type { BadgeProps } from '@/components/badge'; import { CheckIcon, XIcon } from '@/icons'; import { PALETTES } from './axis-values'; import type { Entry } from './types'; /** * Badge's own axes, exported so `pages/badges.tsx` and `pages/badges-figma.tsx` * read one list rather than a second hand-copy — the rule `registry/alert.tsx` * and `registry/avatar.tsx` already follow. * * The split matters: {@link BADGE_VARIANTS} compose with `colorPalette` because * they paint from the `--ctl-*` roles, while {@link BADGE_SHORTHANDS} pin their * colour from the semantic roles and ignore `colorPalette` entirely. A grid that * crossed the two would have five columns doing nothing. */ export const BADGE_VARIANTS = ['solid', 'subtle', 'surface', 'outline', 'ghost'] as const; export const BADGE_SHORTHANDS = [ 'default', 'secondary', 'destructive', 'success', 'warning', ] as const; export const BADGE_SIZES = ['xs', 'sm', 'md', 'lg'] as const; export const badge: Entry = { slug: 'badge', name: 'Badge', group: 'Data display', description: 'A small status label. Same two-axis model as Button — five treatments against seven palettes — plus five one-word shorthands that pin their own colour.', imports: { subpath: 'badge', names: ['Badge'] }, figma: { set: 'Badge', axisMap: { color: 'colorPalette' }, /* * CBAR names Badge's colours by what they mean rather than by ramp, so the * four it draws are the four listed here; the rest of the kit's palettes * have no counterpart on that canvas. * * `default` pairs with `secondary`, not `primary`. The pairing is read off * the fills rather than off the axis name — the same correction * `pages/alerts-figma.tsx` records for its own band table. Measured through * the bridge, `color=default` is `#4BC7B5` solid / `#CFF3EC` surface / * `#A6E8DA` border, which is `secondary-500 / -100 / -200` exactly. Calling * it `primary` matched a role name against a navy ramp and reported the * turquoise column as a gap. */ valueMap: { color: { green: 'success', red: 'removed', secondary: 'default' } }, }, axes: { variant: BADGE_VARIANTS, colorPalette: PALETTES, size: BADGE_SIZES, }, defaults: { variant: 'subtle', colorPalette: 'primary', size: 'md' }, render: (props) => Badge, matrices: [ { title: 'Variant × colorPalette', rows: 'variant', cols: 'colorPalette', pin: { size: 'md' } }, { title: 'Variant × size', description: 'CBAR draws the badge at 16 / 20 / 24 / 28px.', rows: 'variant', cols: 'size', pin: { colorPalette: 'primary' }, }, ], compositions: [ { name: 'Shorthands', description: 'Fixed-colour variants for the statuses that recur across an app.', render: () => (
Default Secondary Destructive Success Warning
), }, { name: 'Icon slots', description: "CBAR's Badge set has `.iconStart?` and `.iconEnd?` as independent booleans, both on by default. Here it is just child order — the size variant sizes any direct `svg` child (10 → 16px) and sets the gap.", render: () => (
Neither Leading Trailing Both
), }, { name: 'Icon slots across sizes', render: () => (
{BADGE_SIZES.map((size) => ( {size} ))}
), }, ], spec: { caption: "Measured off CBAR's Badge component set (`2456:5146`) through the Figma bridge — the box, the padding and the corner from the variant frames, the type from `figma_text`, the glyph from the `Outline/Interface/Plus` instance each variant carries. Every rung matches what the kit draws, down to the icon ladder, which is why there is no note here about a compromise. The corner is a flat 4px at all four sizes rather than a scaling one.", head: ['Size', 'Height', 'Padding X', 'Gap', 'Text', 'Icon', 'Radius'], rows: [ ['xs', '16px', '4px', '4px', '10px', '10px', '4px'], ['sm', '20px', '6px', '4px', '12px', '12px', '4px'], ['md', '24px', '8px', '6px', '14px', '14px', '4px'], ['lg', '28px', '10px', '8px', '14px', '16px', '4px'], ], }, };