import * as React from 'react'; /** * Shared chassis for every icon in the kit. * * The geometry is drawn on a 24×24 grid and paints in `currentColor`, so an * icon inherits its colour from the surrounding text and lines up with the rest * of the set at any size. Controls size their own icons through the * `iconSizing` preset (`src/lib/cva-presets.ts`), which is why callers inside * the kit pass `className="size-4"` rather than the `size` prop. * * Two painting modes, because CBAR's set uses both: most of its outline icons * ship as closed filled paths (the stroke was expanded to an outline in Figma), * while a few are genuine strokes. `filled` picks between them, and the shell * sets the matching pair of `fill`/`stroke` so the geometry itself stays bare. */ export interface IconProps extends React.SVGProps { /** * Pixel size applied to both dimensions. A `size-*` utility on `className` * overrides it, since a class beats the presentational attribute. */ size?: number | string; } /** CBAR draws every icon twice. Which of the two families to paint. */ export type IconVariant = 'outline' | 'solid'; /** * Props of a generated CBAR icon. `variant` picks the family; a handful of * icons (arrows, carets) are drawn once and ignore it — `iconManifest` records * which ones with its `shared` flag. */ export interface CbarIconProps extends IconProps { variant?: IconVariant; } /** * An icon is decorative unless the caller says otherwise: next to a visible * label it would otherwise be announced twice. Passing `aria-label`, `role` or * `title` marks it as meaningful and opts it back into the accessibility tree. */ const isDecorative = (props: Record) => !Object.keys(props).some( (prop) => prop.startsWith('aria-') || prop === 'role' || prop === 'title' ); export interface IconBaseProps extends IconProps { children: React.ReactNode; /** * Paint the geometry as solid shapes rather than strokes. Set by the icon * itself, not by callers — it describes how that icon was drawn. */ filled?: boolean; /** Stroke weight for stroked icons. CBAR draws at 1.5 on a 24×24 grid. */ strokeWidth?: number | string; } export function Icon({ size = 24, className, children, filled = false, strokeWidth = 1.5, ...props }: IconBaseProps) { // A filled icon carries no stroke and vice versa; setting both would paint a // 1.5px outline around every solid shape. const paint = filled ? { fill: 'currentColor', stroke: 'none' as const } : { fill: 'none' as const, stroke: 'currentColor', strokeWidth, strokeLinecap: 'round' as const, strokeLinejoin: 'round' as const, }; return ( {children} ); }