import { Button } from '@/components/button'; import type { ButtonProps } from '@/components/button'; import { CheckIcon, ChevronRightIcon, SearchIcon } from '@/icons'; import { CONTROL_SIZES, PALETTES, VARIANTS } from './axis-values'; import type { Entry } from './types'; export const button: Entry = { slug: 'button', name: 'Button', group: 'Actions', description: "The kit's primary interactive control. Treatment and hue are separate props, the way CBAR models them: `variant` says how filled in the button is, `colorPalette` says which colour it wears — any of the five treatments combines with any of the seven palettes.", imports: { subpath: 'button', names: ['Button'] }, figma: { set: 'Button', /* CBAR draws the four interaction states as separate variants; the kit draws all but `disabled` in CSS, so that axis is fed by the one prop that does exist. `third` is CBAR's own name for the tertiary ramp. */ axisMap: { state: 'disabled' }, valueMap: { state: { true: 'disabled', false: 'default' }, colorPalette: { tertiary: 'third' }, }, }, axes: { variant: VARIANTS, colorPalette: PALETTES, size: CONTROL_SIZES, disabled: [false, true], }, defaults: { variant: 'solid', colorPalette: 'primary', size: 'md', disabled: false }, render: (props) => , matrices: [ { title: 'Variant × colorPalette', description: 'The two axes that compose. Five treatments against seven palettes — 35 combinations that cost 12 cva entries, because a variant reads the --ctl-* roles the palette class sets rather than naming a colour.', rows: 'variant', cols: 'colorPalette', pin: { size: 'md' }, }, { title: 'Variant × size', description: 'Heights come from CBAR: 32 / 36 / 40 / 48 / 56px. Note the horizontal padding is not monotonic — lg is roomier than xl — which holds across all 35 Figma variants and is reproduced rather than smoothed.', rows: 'variant', cols: 'size', pin: { colorPalette: 'primary' }, }, { title: 'Disabled', description: 'Every treatment at 50% opacity with pointer events off.', rows: 'variant', cols: 'colorPalette', pin: { size: 'md', disabled: true }, }, ], compositions: [ { name: 'Shorthands', description: 'Three one-word variants for the combinations that come up constantly. They paint from the semantic roles in theme.css, so they pin their own colour and ignore `colorPalette` instead of racing it on specificity.', render: () => (
), }, { name: 'Icon slots', description: "CBAR's Button set carries `iconLeft?` and `iconRight?` as two independent booleans — both default to on — so all four combinations are drawn. There is no prop for it here: any `svg` child is sized by the button's own rung and spaced by its `gap`, so position is decided by where you put the element.", render: () => (
), }, { name: 'Icon slots across sizes', description: 'Both the gap and the icon itself come from the size, not from the icon element. CBAR draws a 16px glyph on `xs` and 24px from `md` up, so the jump is visible between the second and third button here — `sm` sits on the small side because CBAR has no `sm` Button to copy. Pass your own `size-*` on the icon to opt out.', render: () => (
{(['xs', 'sm', 'md', 'lg', 'xl'] as const).map((size) => ( ))}
), }, { name: 'Icon only', description: 'Square sizes for a lone icon. Always pair one with `aria-label`.', render: () => (
), }, { name: 'asChild', description: 'Forwards every class to the child, so a router link can look like a button without an anchor nested inside one.', render: () => ( ), }, ], /* * Only what the docgen cannot see. * * `variant`, `colorPalette`, `size` and `asChild` used to be restated here in * full; they are now generated from the types by `scripts/gen-props.mjs`, * including their defaults and their prose — the descriptions moved into * JSDoc on the cva keys in `button.tsx`, where they also reach a consumer's * editor rather than only this page. * * `disabled` is React's, declared in `@types/react`, and the generator emits * only what the kit declares itself. So it is added here, which is exactly * what `Entry.props` is for — see `registry/props.ts`. */ props: [ { name: 'disabled', type: 'boolean', default: 'false', description: 'Standard button attribute. Also honoured as aria-disabled.', }, ], spec: { caption: 'Straight from CBAR\'s Button component set. Note the icon steps 16 → 24px at `md`: CBAR draws a small glyph only on `xs`. `sm` is the one rung CBAR does not draw for Button — it jumps xs → md — so it is filled in at the height CBAR\'s IconButton uses, keeping a small button and a small icon button aligned, and it keeps the 16px icon that is all a 36px box has room for.', head: ['Size', 'Height', 'Padding X', 'Gap', 'Text', 'Icon', 'Radius'], rows: [ ['xs', '32px', '10px', '4px', '12px', '16px', '4px'], ['sm', '36px', '12px', '6px', '14px', '16px', '4px'], ['md', '40px', '16px', '8px', '14px', '24px', '4px'], ['lg', '48px', '20px', '10px', '16px', '24px', '4px'], ['xl', '56px', '16px', '10px', '18px', '24px', '4px'], ], }, };