@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 +8 -0
- package/llms-full.txt +1 -1
- package/make-kit/Guidelines.md +71 -0
- package/make-kit/components/badge.md +162 -0
- package/make-kit/components/button.md +125 -0
- package/make-kit/components/card.md +147 -0
- package/make-kit/components/dialog.md +167 -0
- package/make-kit/components/dropdown-menu.md +205 -0
- package/make-kit/components/form.md +189 -0
- package/make-kit/components/icon.md +152 -0
- package/make-kit/components/input.md +154 -0
- package/make-kit/components/overview.md +308 -0
- package/make-kit/components/popover.md +201 -0
- package/make-kit/components/select.md +148 -0
- package/make-kit/components/stack.md +165 -0
- package/make-kit/components/table.md +215 -0
- package/make-kit/components/tabs.md +162 -0
- package/make-kit/components/text.md +139 -0
- package/make-kit/components/toast.md +193 -0
- package/make-kit/foundations/color.md +128 -0
- package/make-kit/foundations/dark-mode.md +81 -0
- package/make-kit/foundations/icons.md +107 -0
- package/make-kit/foundations/motion.md +134 -0
- package/make-kit/foundations/radius.md +78 -0
- package/make-kit/foundations/spacing.md +110 -0
- package/make-kit/foundations/surfaces.md +121 -0
- package/make-kit/foundations/typography.md +120 -0
- package/make-kit/setup.md +130 -0
- package/package.json +5 -2
- package/skill/SKILL.md +1 -1
- package/skill/references/components-full.md +1 -1
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.
|
|
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.
|