@devalok/shilp-sutra 0.41.0 → 0.42.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/MIGRATION.md CHANGED
@@ -4,6 +4,14 @@ This page indexes all breaking changes across `@devalok/shilp-sutra` versions. F
4
4
 
5
5
  > **Upgrading from < 0.36?** Start here, then read each intermediate version section. Breaking changes stack — skipping versions means stacking migrations.
6
6
 
7
+ ## v0.42.0 — Figma Make kit guidelines (no migration needed)
8
+
9
+ **Non-breaking minor.** No consumer code changes required.
10
+
11
+ - **New:** `packages/core/make-kit/` ships in the tarball — 26 guideline files Figma Make consumes when registering this package as a Make kit. Includes `Guidelines.md`, `setup.md`, 8 `foundations/*.md`, `components/overview.md`, and 15 per-component deep guides. Reachable at `node_modules/@devalok/shilp-sutra/make-kit/` after install, or via subpath exports `@devalok/shilp-sutra/make-kit` and `/make-kit/*`. Adds ~140 KB to tarball.
12
+ - No source code changes. No runtime impact. Existing consumers see a slightly larger install footprint and nothing else.
13
+ - See https://developers.figma.com/docs/code/bring-your-design-system-package/ for the Figma Make kit registration flow.
14
+
7
15
  ## v0.41.0 — `BREAKING.json` manifest + recipe polish (no migration needed)
8
16
 
9
17
  **Non-breaking minor.** No consumer code changes required.
package/llms-full.txt CHANGED
@@ -5,7 +5,7 @@
5
5
  > All variant values and props verified from source CVA definitions.
6
6
  >
7
7
  > Package: @devalok/shilp-sutra
8
- > Version: 0.41.0
8
+ > Version: 0.42.0
9
9
  >
10
10
  > **If you are an AI agent reading this file top-to-bottom:** the Setup
11
11
  > section below is authoritative. If any later per-component doc or a
@@ -0,0 +1,71 @@
1
+ # shilp-sutra — Figma Make Kit Guidelines
2
+
3
+ > **Read order.** This is the entry point. Read `setup.md` next, then `foundations/overview.md`, then `components/overview.md`. Branch into specific token / component files on demand.
4
+
5
+ ## What this is
6
+
7
+ `@devalok/shilp-sutra` is the Devalok design system: React 18/19 components built on vendored Radix primitives, OKLCH design tokens, CSS-first Tailwind 4. Generated apps must use these components instead of raw HTML elements wherever a matching component exists.
8
+
9
+ ## Product character
10
+
11
+ | Trait | Value |
12
+ |---|---|
13
+ | Density | Mid. Default `md` size on controls. Reach for `sm` only inside dense toolbars, tables, filter bars. |
14
+ | Color philosophy | ~90% neutral surfaces, accent color used sparingly for primary action + status. Brand accent is OKLCH magenta by default, but the kit is themable — never hardcode hex. |
15
+ | Corner radius | Semantic roles (`--radius-control`, `--radius-surface`, `--radius-overlay`). Default preset = "slightly-rounded" (6/10/16 px). Never hand-pick radii. |
16
+ | Elevation | Five surface tiers (`surface-base`, `raised`, `sunken`, `overlay`, `inverted`). Cards sit on `raised`, dialogs on `overlay`. Never combine an explicit `border-*` with a `shadow-*` token — shadow tokens already contain a hairline ring layer. |
17
+ | Motion | framer-motion is a required peer. Wrap apps in `<MotionProvider reducedMotion="user">` once. Use motion primitives (`MotionFade`, `MotionCollapse`, `MotionSlide`) instead of CSS keyframes. |
18
+ | Dark mode | `.dark` class on `<html>` or `<body>` flips every token. Algorithmically derived from OKLCH curves — surfaces lighten with elevation. |
19
+
20
+ ## Mandatory rules
21
+
22
+ These are not preferences. Generated code that violates them is wrong.
23
+
24
+ 1. **Use design system components, not raw HTML.** `<Button>` not `<button>`. `<Input>` not `<input>`. `<Text>` not `<span>`/`<p>` (when typographic semantics matter). `<Stack>` not bare flex divs.
25
+ 2. **Use semantic tokens, never hex / rgb / hsl.** `bg-surface-raised` not `bg-white`. `text-fg` not `text-zinc-900`. `bg-accent-9` not `bg-pink-500`.
26
+ 3. **Spacing uses `ds-*` cadence.** `p-ds-05`, `gap-ds-03`. Never `p-4` / `p-6`. Default cadence is `ds-03 / ds-05 / ds-07` (related items / grouped sections / page sections). Do not reach for every adjacent token (`ds-04`, `ds-06`) — three tiers, not five.
27
+ 4. **Prefer `variant="soft"` over `variant="outline"` for non-primary actions.** Soft (tinted bg, no visible border) reads better in data-dense UIs. Outline only when on a colored bg or paired with a primary for explicit hierarchy.
28
+ 5. **Surface layering is strict.** Page = `surface-base`. Cards/panels/widgets = `surface-raised`. Dialogs/popovers/dropdowns/inputs = `surface-overlay`. Shell chrome (sidebar, topbar) = `surface-sunken`. Tooltips = `surface-inverted`. If you're unsure, read `foundations/surfaces.md`.
29
+ 6. **Never combine `border-*` + `shadow-*` tokens.** Shadow tokens already include a 1px ring layer. Adding an explicit border creates a 2-px edge.
30
+ 7. **Icons use `<Icon icon={...} />` from `@tabler/icons-react`.** Do not import lucide, heroicons, mui-icons. The icon system auto-sizes via `IconProvider` context.
31
+ 8. **Toasts mount once at app root.** `<Toaster />` (singleton). All triggering is imperative: `toast.success("...")`, `toast.error("...")`.
32
+ 9. **Forms wire via `<FormField>`.** It auto-binds `<Label htmlFor>` ↔ `<Input id>` via context. Do not hand-generate ids.
33
+ 10. **Dialog is responsive by default.** It auto-fullScreens on mobile (<768px). Sheet auto-bottom-drawer. Popover auto-drawer. Opt out with `responsive={false}` only when explicitly needed.
34
+
35
+ ## Workflow — before generating any screen
36
+
37
+ 1. **Identify the layout shell.** AppSidebar + TopBar for product pages. Container + Stack for marketing. Dialog/Sheet for modal flows.
38
+ 2. **Pick the surface for each region.** Read `foundations/surfaces.md`. Default page bg is `surface-base`; everything else stacks up from there.
39
+ 3. **Pick components from `components/overview.md`.** That file has decision trees for the common confusions (Button variant, Input vs Combobox vs Autocomplete, Dialog vs Sheet vs Popover).
40
+ 4. **Lay things out with `<Stack>` + `<Container>`.** Use `gap-ds-03/05/07`. Don't reach for arbitrary flex divs.
41
+ 5. **Apply state via component props, not classnames.** Loading? `loading` prop on Button. Error state on Input? `state="error"`. Disabled? `disabled`. Don't simulate states with className overrides.
42
+
43
+ ## Workflow — before using a component
44
+
45
+ 1. Read its component guideline in `components/`. Each lists variants, props, and at least 3 correct examples.
46
+ 2. Check the "Don't" section at the bottom of the file. Most common mistakes are listed there.
47
+ 3. If a prop you want isn't documented, it probably doesn't exist — don't invent one.
48
+
49
+ ## Guidelines map
50
+
51
+ | File | When to read |
52
+ |---|---|
53
+ | `setup.md` | Always. Required imports + provider setup. |
54
+ | `foundations/color.md` | Choosing background / text / border color. Decision tree for status colors. |
55
+ | `foundations/typography.md` | Picking text size / weight. Heading vs body hierarchy. |
56
+ | `foundations/spacing.md` | Picking gap / padding. The three-tier cadence rule. |
57
+ | `foundations/surfaces.md` | Picking which surface tier a region sits on. Includes the surface decision matrix. |
58
+ | `foundations/radius.md` | When to override a radius role. Shape presets (`sharp` / `slightly-rounded` / `rounded`). |
59
+ | `foundations/motion.md` | Adding transitions, list stagger, drawer slides. framer-motion primitives. |
60
+ | `foundations/dark-mode.md` | Wiring the `.dark` toggle. How tokens behave in dark mode. |
61
+ | `foundations/icons.md` | Using Tabler icons, sizing via IconProvider. |
62
+ | `components/overview.md` | Catalog of all major components with decision trees. Read before picking a component. |
63
+ | `components/{name}.md` | Deep guide per component. Variants, props, examples, rules. |
64
+
65
+ ## What this kit excludes
66
+
67
+ - Raw HTML form elements (use `<Input>`, `<Select>`, `<Combobox>`, `<Textarea>`, etc.)
68
+ - Tailwind utility colors (`text-zinc-*`, `bg-blue-*`) — use semantic tokens
69
+ - Custom icon libraries — Tabler only
70
+ - CSS-in-JS at runtime — utilities + tokens cover styling
71
+ - React Router / Next.js Link primitives — use `<Link>` from the kit; consumers wire their router via `LinkProvider`
@@ -0,0 +1,162 @@
1
+ # Badge
2
+
3
+ Small inline status / label / chip. Counts, statuses, tags, filter chips.
4
+
5
+ ```tsx
6
+ import { Badge } from '@devalok/shilp-sutra/ui/badge'
7
+ ```
8
+
9
+ ## When to use
10
+
11
+ - Status pill on a row (Active / Pending / Failed).
12
+ - Filter chip with optional dismiss X.
13
+ - Selectable tag (multi-select chips).
14
+ - Count indicator on an Avatar / Icon / Button — use `<Badge.Indicator>`.
15
+ - A horizontal cluster of tags — wrap in `<Badge.Group>` with optional `max`.
16
+
17
+ Not for in-flow text emphasis — use `<Text variant="label-*">` or `<Code>`.
18
+
19
+ ## Variants
20
+
21
+ | Variant | When |
22
+ |---|---|
23
+ | `subtle` (default) | Tinted bg, colored border. Most common. |
24
+ | `solid` | Filled background, on-color text. Use for high-emphasis statuses (e.g. red error). |
25
+ | `outline` | Border-only, transparent bg. Use on already-tinted backgrounds. |
26
+ | `soft` | Tinted bg, no border. Lighter than `subtle`. Use in dense lists. |
27
+
28
+ ## Colors
29
+
30
+ | Color | Use |
31
+ |---|---|
32
+ | `default` (default) | Neutral / generic. |
33
+ | `accent` | Brand-aligned tag. |
34
+ | `error` | Failed / blocked / critical. |
35
+ | `success` | Active / completed / healthy. |
36
+ | `warning` | Caution / overdue. |
37
+ | `info` | Informational / new. |
38
+ | `neutral` | Brand-agnostic muted tag. |
39
+ | `teal`, `amber`, `slate`, `indigo`, `cyan`, `orange`, `emerald` | Categorical (Kanban columns, project labels). Pick distinct hues per category. |
40
+ | `custom` | Drives off `--badge-color` (and `--badge-fg-color` for solid) inline CSS vars. |
41
+
42
+ ## Sizes
43
+
44
+ | Size | When |
45
+ |---|---|
46
+ | `xs` | Inline next to a 14 px text run. |
47
+ | `sm` | Filter chips, dense tables. |
48
+ | `md` (default) | Standard row pills. |
49
+ | `lg` | Hero / marketing badges. |
50
+
51
+ ## Props
52
+
53
+ | Prop | Type | Notes |
54
+ |---|---|---|
55
+ | `variant` | `'subtle'\|'solid'\|'outline'\|'soft'` | Default `subtle`. |
56
+ | `color` | See colors table | Default `default`. |
57
+ | `size` | `'xs'\|'sm'\|'md'\|'lg'` | Default `md`. |
58
+ | `startIcon` | `ReactElement` | Use `<Icon icon={IconX} />` — auto-sized. |
59
+ | `endIcon` | `ReactElement` | Same. |
60
+ | `dot` | `boolean` | Animated leading status dot. Use for live-state badges. |
61
+ | `onClick` | `() => void` | Renders as `<button>` — interactive badge. |
62
+ | `selected` | `boolean` | Toggle state — shows a check icon. Pair with `onClick`. |
63
+ | `disabled` | `boolean` | Reduced opacity + pointer-events-none. |
64
+ | `onDismiss` | `() => void` | Inline X button for filter chips. |
65
+ | `maxWidth` | `number` | Triggers truncation with `title` tooltip. |
66
+ | `truncate` | `boolean` | Ellipsis overflow without explicit maxWidth. |
67
+ | `circle` | `boolean` | Square aspect-ratio (icon-only / count badges). |
68
+ | `asChild` | `boolean` | Merge with a child (router Link, etc.). |
69
+
70
+ ## Interactive modes
71
+
72
+ | Combo | Renders as | Use |
73
+ |---|---|---|
74
+ | `onClick` only | `<button>` | Selectable tag, filter chip. |
75
+ | `onDismiss` only | `<span>` with inner X button | Read-only chip with dismiss. |
76
+ | `onClick` + `onDismiss` | `<div role="button">` | Selectable + dismissible (avoids nested buttons). |
77
+
78
+ ## Examples
79
+
80
+ **Status pill:**
81
+ ```tsx
82
+ <Badge variant="solid" color="success">Active</Badge>
83
+ <Badge color="warning">Overdue</Badge>
84
+ <Badge color="error" dot>Failed</Badge>
85
+ ```
86
+
87
+ **Dismissible filter chip:**
88
+ ```tsx
89
+ <Badge color="accent" onDismiss={() => removeFilter('react')}>
90
+ React
91
+ </Badge>
92
+ ```
93
+
94
+ **Selectable tag (toggle):**
95
+ ```tsx
96
+ <Badge
97
+ onClick={() => toggleTag('design')}
98
+ selected={selectedTags.has('design')}
99
+ color="accent"
100
+ >
101
+ Design
102
+ </Badge>
103
+ ```
104
+
105
+ **Categorical chip with leading icon:**
106
+ ```tsx
107
+ <Badge color="teal" startIcon={<Icon icon={IconUsers} />}>
108
+ Engineering
109
+ </Badge>
110
+ ```
111
+
112
+ **Count indicator on an Avatar:**
113
+ ```tsx
114
+ <Badge.Indicator content={3} color="error">
115
+ <Avatar src={user.avatar} alt={user.name} />
116
+ </Badge.Indicator>
117
+ ```
118
+
119
+ **Tag cluster with overflow:**
120
+ ```tsx
121
+ <Badge.Group max={3} size="sm" onOverflowClick={() => setShowAll(true)}>
122
+ <Badge>React</Badge>
123
+ <Badge>TypeScript</Badge>
124
+ <Badge>Tailwind</Badge>
125
+ <Badge>Vite</Badge>
126
+ <Badge>Vitest</Badge>
127
+ </Badge.Group>
128
+ {/* Renders: React, TypeScript, Tailwind, +2 */}
129
+ ```
130
+
131
+ **As a router link:**
132
+ ```tsx
133
+ <Badge asChild>
134
+ <Link href="/tags/react">React</Link>
135
+ </Badge>
136
+ ```
137
+
138
+ **Custom color:**
139
+ ```tsx
140
+ <Badge color="custom" style={{ '--badge-color': '#8b5cf6' }}>
141
+ Beta
142
+ </Badge>
143
+ ```
144
+
145
+ ## Composability
146
+
147
+ - **Badge.Group** lays out badges with consistent gap and an optional overflow indicator. Doesn't style children — they keep their own variant / color / size.
148
+ - **Badge.Indicator** overlays a count or dot onto any child (Icon, Avatar, Button). Positioning-only.
149
+ - **IconProvider:** `startIcon` / `endIcon` auto-size to badge size. Don't set explicit size on the nested Icon.
150
+ - **asChild:** Compose with router Link for nav-style badges.
151
+
152
+ See `foundations/color.md` for the color step system, `foundations/icons.md` for IconProvider.
153
+
154
+ ## Rules
155
+
156
+ - For destructive / failed states, use `variant="solid" color="error"`. There is no `variant="destructive"`.
157
+ - Use `Badge.Group` for any tag list — manual gap-handling drifts from the spacing cadence.
158
+ - For toggle-style selectable tags, use `onClick` + `selected`. Don't roll your own with `<Toggle>` styled to look like a Badge.
159
+ - Don't nest a Badge inside a Button — it produces invalid nested buttons. Use `Badge.Indicator` over the Button instead.
160
+ - Icons in `startIcon` / `endIcon` go through `<Icon icon={...} />`. Don't pass `size` on the Icon.
161
+ - For truncated badges, set `truncate` AND a `maxWidth` or container width. Both work together.
162
+ - The deprecated `Chip` component was merged into Badge — use `Badge` with `onClick` for interactive tags.
@@ -0,0 +1,125 @@
1
+ # Button
2
+
3
+ Primary action element. Use instead of `<button>` everywhere.
4
+
5
+ ```tsx
6
+ import { Button } from '@devalok/shilp-sutra/ui/button'
7
+ ```
8
+
9
+ ## When to use
10
+
11
+ - Any user-triggered action: submit a form, open a dialog, navigate (with `asChild`), trigger a flow.
12
+ - Icon-only? Use `<IconButton>` instead.
13
+ - Action plus dropdown? Use `<SplitButton>`.
14
+ - Inline text link (no button affordance)? Use `<Link>` or `<Button variant="link">`.
15
+
16
+ ## Variants — and which to pick
17
+
18
+ | Variant | When |
19
+ |---|---|
20
+ | `solid` (default) | Primary CTA. One per region. Heavy visual weight. |
21
+ | `soft` | Secondary action. **Preferred default for any non-primary action.** Tinted bg, colored text, no visible border — warmer than outline, brand-consistent. |
22
+ | `outline` | Secondary action on a colored / `surface-raised` bg where soft's tint disappears. In toolbars / icon-dense rows. Paired adjacent to a primary that needs explicit hierarchy. |
23
+ | `ghost` | Tertiary / dismissive — close, cancel, skip. Minimal weight. |
24
+ | `link` | Inline action that should read as a link but behave as a button. Use sparingly. |
25
+
26
+ **Rule:** for non-primary actions, default to `soft`. Reach for `outline` only when the three above conditions hit.
27
+
28
+ ## Colors
29
+
30
+ | Color | Use |
31
+ |---|---|
32
+ | `accent` (default) | Primary brand action. |
33
+ | `error` | Destructive action. Pair with confirmation. |
34
+ | `success` | Confirmation / completion action. |
35
+ | `warning` | Caution action. |
36
+ | `neutral` | Brand-agnostic action. Filing/utility buttons. |
37
+
38
+ There is **no** `color="destructive"` — use `variant="solid" color="error"`.
39
+ There is **no** `variant="destructive"` — same.
40
+
41
+ ## Sizes
42
+
43
+ | Size | Pixel height | When |
44
+ |---|---|---|
45
+ | `xs` | 28 | Filter chips, dense toolbars. |
46
+ | `sm` | 32 | Secondary actions in dense rows. |
47
+ | `md` (default) | 40 | Standard. |
48
+ | `lg` | 48 | Marketing CTAs, primary in spacious layouts. |
49
+ | `compact-xs/sm/md` | inline (height-less) | Inline buttons that flow with text. |
50
+ | `icon`, `icon-xs/sm/md/lg` | square | Use `<IconButton>` instead, with the same sizes. |
51
+
52
+ ## Common props
53
+
54
+ | Prop | Type | Notes |
55
+ |---|---|---|
56
+ | `variant` | `'solid'\|'soft'\|'outline'\|'ghost'\|'link'` | See above. |
57
+ | `color` | `'accent'\|'error'\|'success'\|'warning'\|'neutral'` | See above. |
58
+ | `size` | `'xs'\|'sm'\|'md'\|'lg'` + compact + icon variants | Default `md`. |
59
+ | `startIcon`, `endIcon` | `IconInput` | Use `<Icon icon={IconX} />` or a Tabler ref. |
60
+ | `loading` | `boolean` | Disables click + shows spinner. |
61
+ | `loadingPosition` | `'start'\|'end'\|'center'` | Default `'start'`. |
62
+ | `fullWidth` | `boolean` | Stretch to parent width. |
63
+ | `shape` | `'default'\|'pill'` | Pill = fully rounded. |
64
+ | `weight` | `'semibold'\|'normal'` | Default `semibold`. Use `normal` for soft/ghost in dense areas. |
65
+ | `onClickAsync` | `(e) => Promise<void>` | Auto-runs idle → loading → success/error → idle state machine. |
66
+ | `asyncFeedbackDuration` | `number` (ms) | Default 1500. |
67
+ | `processing` | `boolean \| 'ambient' \| 'working' \| 'urgent'` | Marching-ants border for long ops. Forces `soft` variant. |
68
+ | `asChild` | `boolean` | Style transfers to child (use with router Links). |
69
+
70
+ ## Examples
71
+
72
+ **Primary action:**
73
+ ```tsx
74
+ <Button>Save</Button>
75
+ ```
76
+
77
+ **Primary + secondary, sensible default:**
78
+ ```tsx
79
+ <Stack direction="row" gap="ds-03">
80
+ <Button>Save</Button>
81
+ <Button variant="soft">Cancel</Button>
82
+ </Stack>
83
+ ```
84
+
85
+ **Destructive with confirmation pattern:**
86
+ ```tsx
87
+ <Button variant="solid" color="error" startIcon={IconTrash}>
88
+ Delete project
89
+ </Button>
90
+ ```
91
+
92
+ **Async with built-in feedback:**
93
+ ```tsx
94
+ <Button onClickAsync={async () => { await api.save(form) }}>
95
+ Save changes
96
+ </Button>
97
+ ```
98
+
99
+ **Inside a ButtonGroup (toolbar):**
100
+ ```tsx
101
+ <ButtonGroup variant="outline" size="sm">
102
+ <Button startIcon={IconBold} />
103
+ <Button startIcon={IconItalic} />
104
+ <Button startIcon={IconUnderline} />
105
+ </ButtonGroup>
106
+ ```
107
+
108
+ **With a router link (Next.js):**
109
+ ```tsx
110
+ <Button asChild>
111
+ <Link href="/dashboard">Dashboard</Link>
112
+ </Button>
113
+ ```
114
+
115
+ ## Rules
116
+
117
+ - **Default to `variant="soft"`** for any non-primary action.
118
+ - **Never** `variant="destructive"` / `variant="secondary"` / `color="danger"` / `color="default"` — these don't exist.
119
+ - **Never** size `default` — use `md`.
120
+ - **Never** color-override via className (`className="bg-red-500"`) — use `color` prop.
121
+ - **Don't pair** explicit `loading` + `onClickAsync` — `onClickAsync` manages loading itself.
122
+ - **`processing` forces `variant="soft"`** so the marching ants are visible. Don't fight it.
123
+ - **Inside `<ButtonGroup>`**, omit `variant`/`color`/`size` on children unless intentionally overriding — they inherit from context.
124
+ - Icons in `startIcon` / `endIcon` auto-size via `IconProvider`. Don't pass `size` on the icon.
125
+ - For multi-line button content, use `<Stack>` inside; default Button is single-line.
@@ -0,0 +1,147 @@
1
+ # Card
2
+
3
+ The default container for any panel-style content that sits **on** the page.
4
+
5
+ ```tsx
6
+ import {
7
+ Card,
8
+ CardHeader,
9
+ CardTitle,
10
+ CardDescription,
11
+ CardContent,
12
+ CardFooter,
13
+ } from '@devalok/shilp-sutra/ui/card'
14
+ ```
15
+
16
+ ## When to use
17
+
18
+ - Any rectangular region that reads as a discrete unit on the page: dashboards widgets, list items, marketing feature blocks.
19
+ - Need built-in header / actions / footer slots? Use `<ContentCard>` (composed wrapper).
20
+ - Need just a tinted region with no card affordance? Use a `<div className="bg-surface-raised">` (rare; usually Card is right).
21
+
22
+ Card renders on `surface-raised` with `shadow-raised`. **Never** override its background or border.
23
+
24
+ ## Variants
25
+
26
+ | Variant | Use |
27
+ |---|---|
28
+ | `default` (default) | `surface-raised` + `shadow-raised`. Standard card. |
29
+ | `elevated` | Slightly stronger shadow. Use for hero / hovered emphasis. |
30
+ | `outline` | `surface-raised` + border-only (no shadow). Dense lists where 12 cards stacked together would feel too lifted. |
31
+ | `flat` | `surface-raised` + no shadow, no border. For cards inside an already-elevated container. |
32
+
33
+ ## Colors
34
+
35
+ | Color | What it tints |
36
+ |---|---|
37
+ | `default` (default) | Standard border. |
38
+ | `accent`, `error`, `success`, `warning`, `info`, `neutral` | Border picks up the semantic color at step-7. Use to signal status without filling the whole card. |
39
+
40
+ ## Sizes (padding cascade)
41
+
42
+ `size` on Card propagates to `CardHeader`, `CardContent`, `CardFooter` via React context:
43
+
44
+ | Size | Default padding |
45
+ |---|---|
46
+ | `sm` | `ds-04` (12 px) |
47
+ | `md` (default) | `ds-05` (16 px) |
48
+ | `lg` | `ds-07` (32 px) |
49
+
50
+ Override on a sub-component via `className` only if absolutely necessary — it breaks the cascade.
51
+
52
+ ## Compound shape
53
+
54
+ ```
55
+ Card (root)
56
+ CardHeader ← inherits size from Card
57
+ CardTitle
58
+ CardDescription
59
+ CardContent ← inherits size from Card
60
+ CardFooter ← inherits size from Card
61
+ ```
62
+
63
+ ## Other props
64
+
65
+ | Prop | Type | Notes |
66
+ |---|---|---|
67
+ | `interactive` | `boolean` | Adds hover lift + `cursor-pointer`. Make the whole card clickable. Provide `onClick` and `aria-label`. |
68
+ | `accent` | `'left'\|'top'\|'right'\|'bottom'` | Decorative colored bar on the named edge. |
69
+ | `accentColor` | `'default'\|'accent'\|'error'\|'success'\|'warning'\|'info'` | Color of the accent bar. |
70
+
71
+ ## Examples
72
+
73
+ **Standard:**
74
+ ```tsx
75
+ <Card>
76
+ <CardHeader>
77
+ <CardTitle>Q4 revenue</CardTitle>
78
+ <CardDescription>Last updated 2h ago</CardDescription>
79
+ </CardHeader>
80
+ <CardContent>
81
+ <Text variant="heading-lg">$2.4M</Text>
82
+ <Text variant="body-sm" className="text-fg-muted">+18% YoY</Text>
83
+ </CardContent>
84
+ </Card>
85
+ ```
86
+
87
+ **Interactive (whole card clickable):**
88
+ ```tsx
89
+ <Card interactive onClick={() => navigate(`/projects/${id}`)} aria-label={`Open ${name}`}>
90
+ <CardHeader>
91
+ <CardTitle>{name}</CardTitle>
92
+ <CardDescription>{owner} · {memberCount} members</CardDescription>
93
+ </CardHeader>
94
+ </Card>
95
+ ```
96
+
97
+ **Status-tinted border (warning):**
98
+ ```tsx
99
+ <Card color="warning">
100
+ <CardHeader>
101
+ <CardTitle>Action required</CardTitle>
102
+ <CardDescription>2 invoices are overdue.</CardDescription>
103
+ </CardHeader>
104
+ <CardFooter>
105
+ <Button variant="soft" color="warning">Review</Button>
106
+ </CardFooter>
107
+ </Card>
108
+ ```
109
+
110
+ **Accent bar — pipeline state:**
111
+ ```tsx
112
+ <Card accent="left" accentColor="success">
113
+ <CardHeader>
114
+ <CardTitle>Deploy succeeded</CardTitle>
115
+ <CardDescription>main · 2 min ago</CardDescription>
116
+ </CardHeader>
117
+ </Card>
118
+ ```
119
+
120
+ **Dense list — outline variant, no shadow accumulation:**
121
+ ```tsx
122
+ <Stack gap="ds-03">
123
+ {items.map((item) => (
124
+ <Card key={item.id} variant="outline" size="sm">
125
+ <CardHeader>
126
+ <CardTitle>{item.title}</CardTitle>
127
+ </CardHeader>
128
+ </Card>
129
+ ))}
130
+ </Stack>
131
+ ```
132
+
133
+ **Inside a colored region (flat):**
134
+ ```tsx
135
+ <div className="bg-surface-sunken p-ds-07">
136
+ <Card variant="flat">…</Card> {/* nested-feel, no double shadow */}
137
+ </div>
138
+ ```
139
+
140
+ ## Rules
141
+
142
+ - **Never** `bg-surface-base` on a Card — cards sit on `surface-raised`. The pre-publish audit rejects this.
143
+ - **Never** combine `border-*` + `shadow-*` on a Card. Pick one (Card already does — don't override).
144
+ - **Use `interactive` + `onClick` + `aria-label`** for clickable cards. Don't wrap a Card in a `<button>` — broken nesting.
145
+ - **`size` on Card** drives sub-component padding. Don't set padding on `CardContent` directly.
146
+ - **Don't stack `default` cards inside another `default` card.** The nested one should be `flat` or `outline`.
147
+ - For row-style content (avatar + title + meta + actions), prefer `<ContentCard>` from `/composed/content-card` — it bundles the slots.