@brokenrubik/ui 0.0.0-stage → 0.1.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.
Files changed (190) hide show
  1. package/README.md +264 -2
  2. package/dist/components/accordion.d.ts +13 -0
  3. package/dist/components/accordion.d.ts.map +1 -0
  4. package/dist/components/accordion.js +25 -0
  5. package/dist/components/accordion.js.map +1 -0
  6. package/dist/components/alert-dialog.d.ts +21 -0
  7. package/dist/components/alert-dialog.d.ts.map +1 -0
  8. package/dist/components/alert-dialog.js +46 -0
  9. package/dist/components/alert-dialog.js.map +1 -0
  10. package/dist/components/alert.d.ts +24 -0
  11. package/dist/components/alert.d.ts.map +1 -0
  12. package/dist/components/alert.js +42 -0
  13. package/dist/components/alert.js.map +1 -0
  14. package/dist/components/avatar.d.ts +27 -0
  15. package/dist/components/avatar.d.ts.map +1 -0
  16. package/dist/components/avatar.js +53 -0
  17. package/dist/components/avatar.js.map +1 -0
  18. package/dist/components/badge.d.ts +21 -0
  19. package/dist/components/badge.d.ts.map +1 -0
  20. package/dist/components/badge.js +40 -0
  21. package/dist/components/badge.js.map +1 -0
  22. package/dist/components/button.d.ts +18 -0
  23. package/dist/components/button.d.ts.map +1 -0
  24. package/dist/components/button.js +39 -0
  25. package/dist/components/button.js.map +1 -0
  26. package/dist/components/calendar.d.ts +13 -0
  27. package/dist/components/calendar.d.ts.map +1 -0
  28. package/dist/components/calendar.js +68 -0
  29. package/dist/components/calendar.js.map +1 -0
  30. package/dist/components/card.d.ts +15 -0
  31. package/dist/components/card.d.ts.map +1 -0
  32. package/dist/components/card.js +31 -0
  33. package/dist/components/card.js.map +1 -0
  34. package/dist/components/checkbox.d.ts +6 -0
  35. package/dist/components/checkbox.d.ts.map +1 -0
  36. package/dist/components/checkbox.js +12 -0
  37. package/dist/components/checkbox.js.map +1 -0
  38. package/dist/components/command.d.ts +24 -0
  39. package/dist/components/command.d.ts.map +1 -0
  40. package/dist/components/command.js +41 -0
  41. package/dist/components/command.js.map +1 -0
  42. package/dist/components/date-picker.d.ts +24 -0
  43. package/dist/components/date-picker.d.ts.map +1 -0
  44. package/dist/components/date-picker.js +18 -0
  45. package/dist/components/date-picker.js.map +1 -0
  46. package/dist/components/dialog.d.ts +23 -0
  47. package/dist/components/dialog.d.ts.map +1 -0
  48. package/dist/components/dialog.js +45 -0
  49. package/dist/components/dialog.js.map +1 -0
  50. package/dist/components/dropdown-menu.d.ts +34 -0
  51. package/dist/components/dropdown-menu.d.ts.map +1 -0
  52. package/dist/components/dropdown-menu.js +61 -0
  53. package/dist/components/dropdown-menu.js.map +1 -0
  54. package/dist/components/empty-state.d.ts +13 -0
  55. package/dist/components/empty-state.d.ts.map +1 -0
  56. package/dist/components/empty-state.js +25 -0
  57. package/dist/components/empty-state.js.map +1 -0
  58. package/dist/components/field.d.ts +24 -0
  59. package/dist/components/field.d.ts.map +1 -0
  60. package/dist/components/field.js +34 -0
  61. package/dist/components/field.js.map +1 -0
  62. package/dist/components/input.d.ts +17 -0
  63. package/dist/components/input.d.ts.map +1 -0
  64. package/dist/components/input.js +18 -0
  65. package/dist/components/input.js.map +1 -0
  66. package/dist/components/kbd.d.ts +14 -0
  67. package/dist/components/kbd.d.ts.map +1 -0
  68. package/dist/components/kbd.js +31 -0
  69. package/dist/components/kbd.js.map +1 -0
  70. package/dist/components/label.d.ts +6 -0
  71. package/dist/components/label.d.ts.map +1 -0
  72. package/dist/components/label.js +11 -0
  73. package/dist/components/label.js.map +1 -0
  74. package/dist/components/pagination.d.ts +18 -0
  75. package/dist/components/pagination.d.ts.map +1 -0
  76. package/dist/components/pagination.js +33 -0
  77. package/dist/components/pagination.js.map +1 -0
  78. package/dist/components/popover.d.ts +12 -0
  79. package/dist/components/popover.d.ts.map +1 -0
  80. package/dist/components/popover.js +29 -0
  81. package/dist/components/popover.js.map +1 -0
  82. package/dist/components/progress.d.ts +17 -0
  83. package/dist/components/progress.d.ts.map +1 -0
  84. package/dist/components/progress.js +26 -0
  85. package/dist/components/progress.js.map +1 -0
  86. package/dist/components/radio-group.d.ts +7 -0
  87. package/dist/components/radio-group.d.ts.map +1 -0
  88. package/dist/components/radio-group.js +14 -0
  89. package/dist/components/radio-group.js.map +1 -0
  90. package/dist/components/select.d.ts +20 -0
  91. package/dist/components/select.d.ts.map +1 -0
  92. package/dist/components/select.js +46 -0
  93. package/dist/components/select.js.map +1 -0
  94. package/dist/components/separator.d.ts +6 -0
  95. package/dist/components/separator.d.ts.map +1 -0
  96. package/dist/components/separator.js +11 -0
  97. package/dist/components/separator.js.map +1 -0
  98. package/dist/components/sheet.d.ts +19 -0
  99. package/dist/components/sheet.d.ts.map +1 -0
  100. package/dist/components/sheet.js +47 -0
  101. package/dist/components/sheet.js.map +1 -0
  102. package/dist/components/skeleton.d.ts +5 -0
  103. package/dist/components/skeleton.d.ts.map +1 -0
  104. package/dist/components/skeleton.js +9 -0
  105. package/dist/components/skeleton.js.map +1 -0
  106. package/dist/components/sonner.d.ts +13 -0
  107. package/dist/components/sonner.d.ts.map +1 -0
  108. package/dist/components/sonner.js +40 -0
  109. package/dist/components/sonner.js.map +1 -0
  110. package/dist/components/switch.d.ts +6 -0
  111. package/dist/components/switch.d.ts.map +1 -0
  112. package/dist/components/switch.js +11 -0
  113. package/dist/components/switch.js.map +1 -0
  114. package/dist/components/tabs.d.ts +13 -0
  115. package/dist/components/tabs.d.ts.map +1 -0
  116. package/dist/components/tabs.js +24 -0
  117. package/dist/components/tabs.js.map +1 -0
  118. package/dist/components/textarea.d.ts +5 -0
  119. package/dist/components/textarea.d.ts.map +1 -0
  120. package/dist/components/textarea.js +10 -0
  121. package/dist/components/textarea.js.map +1 -0
  122. package/dist/components/toggle-group.d.ts +11 -0
  123. package/dist/components/toggle-group.d.ts.map +1 -0
  124. package/dist/components/toggle-group.js +18 -0
  125. package/dist/components/toggle-group.js.map +1 -0
  126. package/dist/components/tooltip.d.ts +13 -0
  127. package/dist/components/tooltip.d.ts.map +1 -0
  128. package/dist/components/tooltip.js +24 -0
  129. package/dist/components/tooltip.js.map +1 -0
  130. package/dist/index.d.ts +34 -0
  131. package/dist/index.d.ts.map +1 -0
  132. package/dist/index.js +36 -0
  133. package/dist/index.js.map +1 -0
  134. package/dist/lib/tone.d.ts +8 -0
  135. package/dist/lib/tone.d.ts.map +1 -0
  136. package/dist/lib/tone.js +14 -0
  137. package/dist/lib/tone.js.map +1 -0
  138. package/dist/lib/utils.d.ts +20 -0
  139. package/dist/lib/utils.d.ts.map +1 -0
  140. package/dist/lib/utils.js +40 -0
  141. package/dist/lib/utils.js.map +1 -0
  142. package/dist/styles/base.css +37 -0
  143. package/dist/styles/fonts.css +16 -0
  144. package/dist/styles/styles.css +14 -0
  145. package/dist/styles/theme.css +170 -0
  146. package/dist/styles/tokens.css +228 -0
  147. package/docs/design-handoff.md +112 -0
  148. package/docs/figma-vs-tailwind.md +135 -0
  149. package/docs/visual-testing.md +156 -0
  150. package/package.json +96 -4
  151. package/src/components/accordion.tsx +66 -0
  152. package/src/components/alert-dialog.tsx +139 -0
  153. package/src/components/alert.tsx +87 -0
  154. package/src/components/avatar.tsx +105 -0
  155. package/src/components/badge.tsx +63 -0
  156. package/src/components/button.tsx +70 -0
  157. package/src/components/calendar.tsx +131 -0
  158. package/src/components/card.tsx +72 -0
  159. package/src/components/checkbox.tsx +31 -0
  160. package/src/components/command.tsx +149 -0
  161. package/src/components/date-picker.tsx +86 -0
  162. package/src/components/dialog.tsx +126 -0
  163. package/src/components/dropdown-menu.tsx +225 -0
  164. package/src/components/empty-state.tsx +63 -0
  165. package/src/components/field.tsx +79 -0
  166. package/src/components/input.tsx +49 -0
  167. package/src/components/kbd.tsx +48 -0
  168. package/src/components/label.tsx +22 -0
  169. package/src/components/pagination.tsx +94 -0
  170. package/src/components/popover.tsx +65 -0
  171. package/src/components/progress.tsx +52 -0
  172. package/src/components/radio-group.tsx +42 -0
  173. package/src/components/select.tsx +167 -0
  174. package/src/components/separator.tsx +29 -0
  175. package/src/components/sheet.tsx +112 -0
  176. package/src/components/skeleton.tsx +16 -0
  177. package/src/components/sonner.tsx +58 -0
  178. package/src/components/switch.tsx +27 -0
  179. package/src/components/tabs.tsx +56 -0
  180. package/src/components/textarea.tsx +17 -0
  181. package/src/components/toggle-group.tsx +42 -0
  182. package/src/components/tooltip.tsx +55 -0
  183. package/src/index.ts +35 -0
  184. package/src/lib/tone.ts +16 -0
  185. package/src/lib/utils.ts +46 -0
  186. package/src/styles/base.css +37 -0
  187. package/src/styles/fonts.css +16 -0
  188. package/src/styles/styles.css +14 -0
  189. package/src/styles/theme.css +170 -0
  190. package/src/styles/tokens.css +228 -0
package/README.md CHANGED
@@ -1,3 +1,265 @@
1
- # Temporary Holding Version
1
+ # @brokenrubik/ui
2
2
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
3
+ The **BR Admin Library** (Figma) as a React component package: shadcn-style components and a
4
+ Tailwind CSS v4 theme with the exact Figma values. Every BrokenRubik app (Proma, Timma, Mara,
5
+ Folio, DocuBuilder and the next one) installs this package and gets the same look. Each app can
6
+ still change or extend it.
7
+
8
+ - **Docs site with live examples and code:** https://brokenrubik.github.io/ui/
9
+ - **Source of truth:** Figma file `ONZyUryZr526mtbex2HVPk` (BR Admin Library), pages
10
+ *Foundations* (`2004:2`) and *Components · Base* (`2004:3`).
11
+ - **What is different from Tailwind and shadcn:** [docs/figma-vs-tailwind.md](docs/figma-vs-tailwind.md)
12
+ - **Stack:** React 18 or 19, Tailwind CSS v4, Radix UI, class-variance-authority,
13
+ tailwind-merge, lucide-react, cmdk, sonner, react-day-picker, IBM Plex fonts (included). ESM only. Every component that
14
+ needs the browser has `'use client'`, so it works in the Next.js App Router.
15
+
16
+ Contents: [Install](#install) · [Set up](#set-up-once-per-app) ·
17
+ [How the Tailwind config works](#how-the-tailwind-config-works) · [Use](#use) ·
18
+ [Extend and override](#extend-and-override) · [Adopt in an existing app](#adopt-in-an-existing-app) ·
19
+ [Rules](#rules-that-prevent-bugs) · [Contribute](#contribute)
20
+
21
+ ## Install
22
+
23
+ ```bash
24
+ pnpm add @brokenrubik/ui # or: npm install @brokenrubik/ui
25
+ ```
26
+
27
+ Your app must already have `react`, `react-dom` and `tailwindcss` 4.x (peer dependencies). The
28
+ package installs all other libraries itself (Radix, sonner, cmdk, lucide-react…) and the IBM
29
+ Plex font files.
30
+
31
+ ## Set up (once per app)
32
+
33
+ ### 1. CSS
34
+
35
+ Put these two lines at the top of the app's main stylesheet (`globals.css`, `index.css`):
36
+
37
+ ```css
38
+ @import "tailwindcss";
39
+ @import "@brokenrubik/ui/styles.css";
40
+ ```
41
+
42
+ The order is important: `tailwindcss` first, then the package. Nothing else is necessary. The
43
+ next section tells what these two lines do.
44
+
45
+ ### 2. Fonts (IBM Plex Sans and IBM Plex Mono)
46
+
47
+ You do not need to do anything. `styles.css` loads IBM Plex Sans (400, 500, 600) and IBM Plex
48
+ Mono (400, 500) from the package. Your bundler (Next.js, Vite) copies the font files into the
49
+ build. The browser downloads only the weights and the character sets that the page uses.
50
+
51
+ If the app already loads the fonts, remove that code (`next/font` IBM Plex, `@fontsource`
52
+ imports, a Google Fonts `<link>`), so that the fonts do not load two times.
53
+
54
+ To load the fonts in a different way (for example `next/font`, to get self-hosting with
55
+ preload), set the CSS variables `--font-plex-sans` and `--font-plex-mono` to your font
56
+ families. The package fonts are then never downloaded:
57
+
58
+ ```tsx
59
+ // Next.js: app/layout.tsx (optional)
60
+ import { IBM_Plex_Sans, IBM_Plex_Mono } from 'next/font/google';
61
+
62
+ const sans = IBM_Plex_Sans({ subsets: ['latin'], weight: ['400', '500', '600'], variable: '--font-plex-sans' });
63
+ const mono = IBM_Plex_Mono({ subsets: ['latin'], weight: ['400', '500'], variable: '--font-plex-mono' });
64
+
65
+ <html lang="en" className={`${sans.variable} ${mono.variable}`}>
66
+ ```
67
+
68
+ ### 3. Dark mode and the light sidebar
69
+
70
+ - Dark theme: put the class `dark` on `<html>`. The `dark:` variant follows this class, not
71
+ the operating system setting.
72
+ - "Sidebar claro" (light sidebar, in the light and the dark theme): put the class
73
+ `sidebar-light` on `<html>`. With `dark` too, you get the Figma mode "Dark · Sidebar claro".
74
+ - On the sidebar element, put the class `sidebar-surface`. Then the components inside the
75
+ sidebar use the sidebar colors (light text on navy).
76
+
77
+ Set these classes before the first paint (an inline script in `<head>`), or the page flashes.
78
+
79
+ ### 4. Providers
80
+
81
+ Add these once, in the app root:
82
+
83
+ ```tsx
84
+ import { Toaster, TooltipProvider } from '@brokenrubik/ui';
85
+
86
+ <TooltipProvider>
87
+ {children}
88
+ <Toaster theme={isDark ? 'dark' : 'light'} />
89
+ </TooltipProvider>
90
+ ```
91
+
92
+ ## How the Tailwind config works
93
+
94
+ Tailwind v4 has **no `tailwind.config.js`**. The configuration is CSS, and
95
+ `@brokenrubik/ui/styles.css` is the shared configuration. When your app's Tailwind compiles
96
+ `globals.css`, it reads the package CSS as if you wrote it in your own file. There is one
97
+ CSS output for the app, with your classes and the package classes together.
98
+
99
+ `styles.css` contains five parts:
100
+
101
+ | Part | File | What it does |
102
+ | --- | --- | --- |
103
+ | Fonts | `fonts.css` | `@font-face` rules for IBM Plex Sans and IBM Plex Mono (files from the `@fontsource` packages, which the package installs). |
104
+ | Tokens | `tokens.css` | CSS variables with the Figma values: `--primary: #9547ff`, `--radius: .5rem`… for light (`:root`), dark (`.dark`), `.sidebar-light` and `.sidebar-surface`. Plain CSS, no Tailwind. |
105
+ | Theme | `theme.css` | Tells Tailwind about the tokens. `@theme` makes `bg-primary`, `text-muted-foreground`, `rounded-lg`, `shadow-md`, `text-body`… `@custom-variant dark` makes `dark:` follow the `.dark` class. `@source "../"` tells Tailwind to scan the package files for class names. |
106
+ | Base | `base.css` | Page defaults: IBM Plex Sans, 13 px body text (Figma Body/Default), border color. |
107
+ | Animations | `tw-animate-css` | Open and close animations for menus, dialogs and sheets. |
108
+
109
+ Three things follow from this:
110
+
111
+ 1. **Tailwind must see the package classes.** The `@source` line in `theme.css` does this
112
+ automatically. If the components show without styles, the import is missing or is above
113
+ `@import "tailwindcss"`.
114
+ 2. **Your CSS after the import wins.** A later declaration of the same variable replaces the
115
+ earlier one. This is how you extend and override (next section).
116
+ 3. **Your own classes and the package classes use the same scale.** `bg-primary` in your code is
117
+ the same violet as in the Button. `text-body` in your code is the same 13/20 text as in the
118
+ Input.
119
+
120
+ If an app needs less, import the parts:
121
+
122
+ ```css
123
+ @import "tailwindcss";
124
+ @import "@brokenrubik/ui/tokens.css"; /* variables only */
125
+ @import "@brokenrubik/ui/theme.css"; /* Tailwind mapping + @source */
126
+ @import "tw-animate-css"; /* needed by the overlays */
127
+ /* no base.css: the app keeps its own body styles */
128
+ ```
129
+
130
+ `tokens.css` alone works without Tailwind (for example in a plain CSS app or in app-shell).
131
+
132
+ Tailwind v3 apps cannot use this package.
133
+
134
+ ## Use
135
+
136
+ ```tsx
137
+ import { Badge, Button, Field, FieldDescription, FieldLabel, Input, toast } from '@brokenrubik/ui';
138
+ // or one file: import { Button } from '@brokenrubik/ui/components/button';
139
+
140
+ <Button onClick={() => toast.success('Saved')}>Save changes</Button>
141
+ <Button variant="outline" size="sm">Cancel</Button>
142
+ <Badge tone="success">Done</Badge>
143
+ <Field>
144
+ <FieldLabel htmlFor="name">Project name</FieldLabel>
145
+ <Input id="name" />
146
+ <FieldDescription>Shown on the sidebar and in links.</FieldDescription>
147
+ </Field>
148
+ ```
149
+
150
+ The components have the shadcn/ui API (the same parts, `asChild`, `data-slot`), so shadcn
151
+ examples work. The [docs site](https://brokenrubik.github.io/ui/) shows every
152
+ component with its code.
153
+
154
+ | Figma | Code |
155
+ | --- | --- |
156
+ | Button, Icon Button | `Button` — `variant`: default · secondary · outline · ghost · destructive · link; `size`: default · sm · icon · icon-sm |
157
+ | Badge | `Badge` — `tone` (or `variant`): neutral · primary · success · warning · destructive · highlight · info |
158
+ | Avatar | `Avatar` (`size` 20 · 28), `AvatarImage`, `AvatarFallback` (`tone`); `avatarToneFor(name)` |
159
+ | Key Chip | `Kbd` — `variant`: highlight · muted; `size` 20 · 24 |
160
+ | Input, Textarea, Select, Date Picker | `Input` (`startIcon`), `Textarea`, `Select*`, `DatePicker` |
161
+ | Form Field | `Field` (`invalid`, `disabled`), `FieldLabel`, `FieldDescription`, `FieldError` |
162
+ | Checkbox, Radio, Switch | `Checkbox`, `RadioGroup` + `RadioGroupItem`, `Switch` |
163
+ | Tab, Toggle Group | `Tabs*` (underline), `ToggleGroup` + `ToggleGroupItem` (segmented) |
164
+ | Menu Item, Dropdown Menu | `DropdownMenu*` (item `variant="destructive"`) |
165
+ | Tooltip, Popover | `Tooltip*`, `Popover*` (`PopoverHeader`, `PopoverTitle`, `PopoverDescription`) |
166
+ | Dialog (Default, Destructive) | `Dialog*`, `AlertDialog*` (`AlertDialogAction variant="destructive"`) |
167
+ | Sheet, Command | `Sheet*` (`side`), `Command*`, `CommandDialog` |
168
+ | Alert, Toast | `Alert` (`tone`, default icon per tone), `Toaster` + `toast()` |
169
+ | Card, Empty State | `Card*`, `EmptyState*` |
170
+ | Progress, Skeleton, Separator | `Progress` (`tone`), `Skeleton`, `Separator` |
171
+ | Calendar, Pagination, Accordion | `Calendar`, `Pagination*`, `Accordion*` |
172
+
173
+ **`tone` and `variant`.** Figma calls the color of Badge, Alert, Progress and Avatar "Tone";
174
+ shadcn calls it `variant`. These components accept both names. `variant` also accepts the
175
+ shadcn values: `<Badge variant="secondary">` is the neutral badge, and `<Alert variant="default">`
176
+ is the info alert. If you set both props, `tone` wins.
177
+
178
+ ## Extend and override
179
+
180
+ Put your changes **after** the package import. From the smallest change to the largest:
181
+
182
+ 1. **Change a token.** Every component follows.
183
+
184
+ ```css
185
+ @import "tailwindcss";
186
+ @import "@brokenrubik/ui/styles.css";
187
+
188
+ :root { --radius: 0.375rem; } /* all corners, from one value */
189
+ .dark { --primary: #a78bfa; }
190
+ ```
191
+
192
+ 2. **Add tokens and utilities** in your own `@theme` block.
193
+
194
+ ```css
195
+ @theme {
196
+ --color-brand-timma: #c2581c; /* gives bg-brand-timma, text-brand-timma, border-brand-timma… */
197
+ --text-hero: 40px; /* gives text-hero */
198
+ --text-hero--line-height: 48px;
199
+ }
200
+ ```
201
+
202
+ If you add a `text-*` size, also make a `cn` that knows it (see the rule about `cn` below):
203
+
204
+ ```ts
205
+ // lib/utils.ts
206
+ import { createCn } from '@brokenrubik/ui';
207
+ export const cn = createCn({ extend: { theme: { text: ['hero'] } } });
208
+ ```
209
+
210
+ 3. **Change one use** with `className`. The last class wins: `<Button className="h-9 px-4">`.
211
+
212
+ 4. **Use the styles on another element.** Each component exports its recipe
213
+ (`buttonVariants`, `badgeVariants`, `alertVariants`, `kbdVariants`…) and the shared class
214
+ strings (`controlClassName`, `menuItemClassName`, `menuContentClassName`, `overlayClassName`).
215
+
216
+ ```tsx
217
+ <Link className={buttonVariants({ variant: 'outline', size: 'sm' })} href="/">Home</Link>
218
+ ```
219
+
220
+ 5. **A new variant for one app.** Wrap the package component in the app:
221
+
222
+ ```tsx
223
+ // components/ui/button.tsx (in the app)
224
+ import { Button as BaseButton, cn, type ButtonProps } from '@brokenrubik/ui';
225
+
226
+ export function Button({ variant, className, ...props }: Omit<ButtonProps, 'variant'> & { variant?: ButtonProps['variant'] | 'brand' }) {
227
+ if (variant === 'brand') return <BaseButton className={cn('bg-brand-timma text-white hover:bg-brand-timma/90', className)} {...props} />;
228
+ return <BaseButton variant={variant} className={className} {...props} />;
229
+ }
230
+ ```
231
+
232
+ When a second app needs the same variant, add it to Figma and to this package.
233
+
234
+ ## Adopt in an existing app
235
+
236
+ 1. `pnpm add @brokenrubik/ui`.
237
+ 2. In `globals.css`, remove the token blocks (`:root`, `.dark`, `.sidebar-light`,
238
+ `.sidebar-surface`, `@theme inline`) and add `@import "@brokenrubik/ui/styles.css";` after
239
+ `@import "tailwindcss";`. Keep only the tokens that belong to the app, after the import.
240
+ 3. Remove the app's IBM Plex setup (`next/font` IBM Plex in `layout.tsx`, `@fontsource`
241
+ imports and packages, Google Fonts `<link>`). The package loads the fonts.
242
+ 4. Replace `cn` in `lib/utils.ts` with `export { cn } from '@brokenrubik/ui';`.
243
+ 5. Replace the `components/ui/*` imports with `@brokenrubik/ui`, one component at a time. Keep
244
+ an app file only for a real app variant (step 5 above).
245
+ 6. Replace `import { toast } from 'sonner'` with `import { toast } from '@brokenrubik/ui'`.
246
+ 7. Check light, dark, light sidebar and phone width against Figma.
247
+
248
+ The differences that each app has today: [docs/figma-vs-tailwind.md › Drift](docs/figma-vs-tailwind.md#7-drift-found-in-the-apps-2026-11-09).
249
+
250
+ ## Rules that prevent bugs
251
+
252
+ - **Use the package `cn`.** The Figma text styles are classes such as `text-body`. A plain
253
+ shadcn `cn` thinks that `text-body` is a color and removes it when you also write a color
254
+ (`cn('text-body', 'text-muted-foreground')`). The package `cn` knows the names.
255
+ - **Import `toast` from `@brokenrubik/ui`.** A `toast` from another copy of `sonner` does not
256
+ reach the package `<Toaster />`.
257
+ - **Never use `primary` for text.** Use `text-primary-strong`. `primary` is for fills.
258
+ - **Lime (`highlight`) means "you are here" only.** Do not use it for status.
259
+
260
+ ## Contribute
261
+
262
+ See [CONTRIBUTING.md](CONTRIBUTING.md): set up, add or change a component, the visual test
263
+ against Figma, and releases. AI agents: read [AGENTS.md](AGENTS.md).
264
+
265
+ Releases and their notes: [GitHub releases](https://github.com/BrokenRubik/ui/releases). Requests for the Figma file: [docs/design-handoff.md](docs/design-handoff.md).
@@ -0,0 +1,13 @@
1
+ import * as React from 'react';
2
+ import { Accordion as AccordionPrimitive } from 'radix-ui';
3
+ /**
4
+ * Figma: Components · Base › Accordion Item (2085:277). Bottom border; trigger 12 px
5
+ * vertical padding, Body/Default Medium, muted chevron; content Body/Default muted, 12 px
6
+ * bottom padding.
7
+ */
8
+ declare function Accordion(props: React.ComponentProps<typeof AccordionPrimitive.Root>): React.JSX.Element;
9
+ declare function AccordionItem({ className, ...props }: React.ComponentProps<typeof AccordionPrimitive.Item>): React.JSX.Element;
10
+ declare function AccordionTrigger({ className, children, ...props }: React.ComponentProps<typeof AccordionPrimitive.Trigger>): React.JSX.Element;
11
+ declare function AccordionContent({ className, children, ...props }: React.ComponentProps<typeof AccordionPrimitive.Content>): React.JSX.Element;
12
+ export { Accordion, AccordionItem, AccordionTrigger, AccordionContent };
13
+ //# sourceMappingURL=accordion.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"accordion.d.ts","sourceRoot":"","sources":["../../src/components/accordion.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAC/B,OAAO,EAAE,SAAS,IAAI,kBAAkB,EAAE,MAAM,UAAU,CAAC;AAK3D;;;;GAIG;AACH,iBAAS,SAAS,CAAC,KAAK,EAAE,KAAK,CAAC,cAAc,CAAC,OAAO,kBAAkB,CAAC,IAAI,CAAC,qBAE7E;AAED,iBAAS,aAAa,CAAC,EAAE,SAAS,EAAE,GAAG,KAAK,EAAE,EAAE,KAAK,CAAC,cAAc,CAAC,OAAO,kBAAkB,CAAC,IAAI,CAAC,qBAQnG;AAED,iBAAS,gBAAgB,CAAC,EACxB,SAAS,EACT,QAAQ,EACR,GAAG,KAAK,EACT,EAAE,KAAK,CAAC,cAAc,CAAC,OAAO,kBAAkB,CAAC,OAAO,CAAC,qBAgBzD;AAED,iBAAS,gBAAgB,CAAC,EACxB,SAAS,EACT,QAAQ,EACR,GAAG,KAAK,EACT,EAAE,KAAK,CAAC,cAAc,CAAC,OAAO,kBAAkB,CAAC,OAAO,CAAC,qBAUzD;AAED,OAAO,EAAE,SAAS,EAAE,aAAa,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,CAAC"}
@@ -0,0 +1,25 @@
1
+ 'use client';
2
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
+ import * as React from 'react';
4
+ import { Accordion as AccordionPrimitive } from 'radix-ui';
5
+ import { ChevronDownIcon } from 'lucide-react';
6
+ import { cn } from '../lib/utils.js';
7
+ /**
8
+ * Figma: Components · Base › Accordion Item (2085:277). Bottom border; trigger 12 px
9
+ * vertical padding, Body/Default Medium, muted chevron; content Body/Default muted, 12 px
10
+ * bottom padding.
11
+ */
12
+ function Accordion(props) {
13
+ return _jsx(AccordionPrimitive.Root, { "data-slot": "accordion", ...props });
14
+ }
15
+ function AccordionItem({ className, ...props }) {
16
+ return (_jsx(AccordionPrimitive.Item, { "data-slot": "accordion-item", className: cn('border-b border-border', className), ...props }));
17
+ }
18
+ function AccordionTrigger({ className, children, ...props }) {
19
+ return (_jsx(AccordionPrimitive.Header, { className: "flex", children: _jsxs(AccordionPrimitive.Trigger, { "data-slot": "accordion-trigger", className: cn('flex flex-1 items-center justify-between gap-4 py-3 text-left text-body font-medium text-foreground transition-all outline-none hover:underline focus-visible:ring-3 focus-visible:ring-ring/40 disabled:pointer-events-none disabled:opacity-50 [&[data-state=open]>svg]:rotate-180', className), ...props, children: [children, _jsx(ChevronDownIcon, { className: "pointer-events-none size-4 shrink-0 text-muted-foreground transition-transform duration-200" })] }) }));
20
+ }
21
+ function AccordionContent({ className, children, ...props }) {
22
+ return (_jsx(AccordionPrimitive.Content, { "data-slot": "accordion-content", className: "overflow-hidden text-body text-muted-foreground data-[state=closed]:animate-accordion-up data-[state=open]:animate-accordion-down", ...props, children: _jsx("div", { className: cn('pb-3', className), children: children }) }));
23
+ }
24
+ export { Accordion, AccordionItem, AccordionTrigger, AccordionContent };
25
+ //# sourceMappingURL=accordion.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"accordion.js","sourceRoot":"","sources":["../../src/components/accordion.tsx"],"names":[],"mappings":"AAAA,YAAY,CAAC;;AAEb,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAC/B,OAAO,EAAE,SAAS,IAAI,kBAAkB,EAAE,MAAM,UAAU,CAAC;AAC3D,OAAO,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAE/C,OAAO,EAAE,EAAE,EAAE,MAAM,iBAAiB,CAAC;AAErC;;;;GAIG;AACH,SAAS,SAAS,CAAC,KAA2D;IAC5E,OAAO,KAAC,kBAAkB,CAAC,IAAI,iBAAW,WAAW,KAAK,KAAK,GAAI,CAAC;AACtE,CAAC;AAED,SAAS,aAAa,CAAC,EAAE,SAAS,EAAE,GAAG,KAAK,EAAwD;IAClG,OAAO,CACL,KAAC,kBAAkB,CAAC,IAAI,iBACZ,gBAAgB,EAC1B,SAAS,EAAE,EAAE,CAAC,wBAAwB,EAAE,SAAS,CAAC,KAC9C,KAAK,GACT,CACH,CAAC;AACJ,CAAC;AAED,SAAS,gBAAgB,CAAC,EACxB,SAAS,EACT,QAAQ,EACR,GAAG,KAAK,EACgD;IACxD,OAAO,CACL,KAAC,kBAAkB,CAAC,MAAM,IAAC,SAAS,EAAC,MAAM,YACzC,MAAC,kBAAkB,CAAC,OAAO,iBACf,mBAAmB,EAC7B,SAAS,EAAE,EAAE,CACX,sRAAsR,EACtR,SAAS,CACV,KACG,KAAK,aAER,QAAQ,EACT,KAAC,eAAe,IAAC,SAAS,EAAC,6FAA6F,GAAG,IAChG,GACH,CAC7B,CAAC;AACJ,CAAC;AAED,SAAS,gBAAgB,CAAC,EACxB,SAAS,EACT,QAAQ,EACR,GAAG,KAAK,EACgD;IACxD,OAAO,CACL,KAAC,kBAAkB,CAAC,OAAO,iBACf,mBAAmB,EAC7B,SAAS,EAAC,mIAAmI,KACzI,KAAK,YAET,cAAK,SAAS,EAAE,EAAE,CAAC,MAAM,EAAE,SAAS,CAAC,YAAG,QAAQ,GAAO,GAC5B,CAC9B,CAAC;AACJ,CAAC;AAED,OAAO,EAAE,SAAS,EAAE,aAAa,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,CAAC"}
@@ -0,0 +1,21 @@
1
+ import * as React from 'react';
2
+ import { AlertDialog as AlertDialogPrimitive } from 'radix-ui';
3
+ import type { VariantProps } from 'class-variance-authority';
4
+ import { buttonVariants } from './button.js';
5
+ /**
6
+ * Figma: Components · Base › Dialog, Type=Destructive (2084:160): the confirm dialog.
7
+ * Same chrome as Dialog, no close button; Cancel (outline) + action (default or destructive).
8
+ */
9
+ declare function AlertDialog(props: React.ComponentProps<typeof AlertDialogPrimitive.Root>): React.JSX.Element;
10
+ declare function AlertDialogTrigger(props: React.ComponentProps<typeof AlertDialogPrimitive.Trigger>): React.JSX.Element;
11
+ declare function AlertDialogPortal(props: React.ComponentProps<typeof AlertDialogPrimitive.Portal>): React.JSX.Element;
12
+ declare function AlertDialogOverlay({ className, ...props }: React.ComponentProps<typeof AlertDialogPrimitive.Overlay>): React.JSX.Element;
13
+ declare function AlertDialogContent({ className, ...props }: React.ComponentProps<typeof AlertDialogPrimitive.Content>): React.JSX.Element;
14
+ declare function AlertDialogHeader({ className, ...props }: React.ComponentProps<'div'>): React.JSX.Element;
15
+ declare function AlertDialogFooter({ className, ...props }: React.ComponentProps<'div'>): React.JSX.Element;
16
+ declare function AlertDialogTitle({ className, ...props }: React.ComponentProps<typeof AlertDialogPrimitive.Title>): React.JSX.Element;
17
+ declare function AlertDialogDescription({ className, ...props }: React.ComponentProps<typeof AlertDialogPrimitive.Description>): React.JSX.Element;
18
+ declare function AlertDialogAction({ className, variant, ...props }: React.ComponentProps<typeof AlertDialogPrimitive.Action> & Pick<VariantProps<typeof buttonVariants>, 'variant'>): React.JSX.Element;
19
+ declare function AlertDialogCancel({ className, ...props }: React.ComponentProps<typeof AlertDialogPrimitive.Cancel>): React.JSX.Element;
20
+ export { AlertDialog, AlertDialogAction, AlertDialogCancel, AlertDialogContent, AlertDialogDescription, AlertDialogFooter, AlertDialogHeader, AlertDialogOverlay, AlertDialogPortal, AlertDialogTitle, AlertDialogTrigger, };
21
+ //# sourceMappingURL=alert-dialog.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"alert-dialog.d.ts","sourceRoot":"","sources":["../../src/components/alert-dialog.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAC/B,OAAO,EAAE,WAAW,IAAI,oBAAoB,EAAE,MAAM,UAAU,CAAC;AAC/D,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,0BAA0B,CAAC;AAG7D,OAAO,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAG7C;;;GAGG;AACH,iBAAS,WAAW,CAAC,KAAK,EAAE,KAAK,CAAC,cAAc,CAAC,OAAO,oBAAoB,CAAC,IAAI,CAAC,qBAEjF;AAED,iBAAS,kBAAkB,CAAC,KAAK,EAAE,KAAK,CAAC,cAAc,CAAC,OAAO,oBAAoB,CAAC,OAAO,CAAC,qBAE3F;AAED,iBAAS,iBAAiB,CAAC,KAAK,EAAE,KAAK,CAAC,cAAc,CAAC,OAAO,oBAAoB,CAAC,MAAM,CAAC,qBAEzF;AAED,iBAAS,kBAAkB,CAAC,EAC1B,SAAS,EACT,GAAG,KAAK,EACT,EAAE,KAAK,CAAC,cAAc,CAAC,OAAO,oBAAoB,CAAC,OAAO,CAAC,qBAQ3D;AAED,iBAAS,kBAAkB,CAAC,EAC1B,SAAS,EACT,GAAG,KAAK,EACT,EAAE,KAAK,CAAC,cAAc,CAAC,OAAO,oBAAoB,CAAC,OAAO,CAAC,qBAc3D;AAED,iBAAS,iBAAiB,CAAC,EAAE,SAAS,EAAE,GAAG,KAAK,EAAE,EAAE,KAAK,CAAC,cAAc,CAAC,KAAK,CAAC,qBAE9E;AAED,iBAAS,iBAAiB,CAAC,EAAE,SAAS,EAAE,GAAG,KAAK,EAAE,EAAE,KAAK,CAAC,cAAc,CAAC,KAAK,CAAC,qBAQ9E;AAED,iBAAS,gBAAgB,CAAC,EACxB,SAAS,EACT,GAAG,KAAK,EACT,EAAE,KAAK,CAAC,cAAc,CAAC,OAAO,oBAAoB,CAAC,KAAK,CAAC,qBAQzD;AAED,iBAAS,sBAAsB,CAAC,EAC9B,SAAS,EACT,GAAG,KAAK,EACT,EAAE,KAAK,CAAC,cAAc,CAAC,OAAO,oBAAoB,CAAC,WAAW,CAAC,qBAQ/D;AAED,iBAAS,iBAAiB,CAAC,EACzB,SAAS,EACT,OAAmB,EACnB,GAAG,KAAK,EACT,EAAE,KAAK,CAAC,cAAc,CAAC,OAAO,oBAAoB,CAAC,MAAM,CAAC,GACzD,IAAI,CAAC,YAAY,CAAC,OAAO,cAAc,CAAC,EAAE,SAAS,CAAC,qBAQrD;AAED,iBAAS,iBAAiB,CAAC,EACzB,SAAS,EACT,GAAG,KAAK,EACT,EAAE,KAAK,CAAC,cAAc,CAAC,OAAO,oBAAoB,CAAC,MAAM,CAAC,qBAQ1D;AAED,OAAO,EACL,WAAW,EACX,iBAAiB,EACjB,iBAAiB,EACjB,kBAAkB,EAClB,sBAAsB,EACtB,iBAAiB,EACjB,iBAAiB,EACjB,kBAAkB,EAClB,iBAAiB,EACjB,gBAAgB,EAChB,kBAAkB,GACnB,CAAC"}
@@ -0,0 +1,46 @@
1
+ 'use client';
2
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
+ import * as React from 'react';
4
+ import { AlertDialog as AlertDialogPrimitive } from 'radix-ui';
5
+ import { cn } from '../lib/utils.js';
6
+ import { buttonVariants } from './button.js';
7
+ import { overlayClassName } from './dialog.js';
8
+ /**
9
+ * Figma: Components · Base › Dialog, Type=Destructive (2084:160): the confirm dialog.
10
+ * Same chrome as Dialog, no close button; Cancel (outline) + action (default or destructive).
11
+ */
12
+ function AlertDialog(props) {
13
+ return _jsx(AlertDialogPrimitive.Root, { "data-slot": "alert-dialog", ...props });
14
+ }
15
+ function AlertDialogTrigger(props) {
16
+ return _jsx(AlertDialogPrimitive.Trigger, { "data-slot": "alert-dialog-trigger", ...props });
17
+ }
18
+ function AlertDialogPortal(props) {
19
+ return _jsx(AlertDialogPrimitive.Portal, { "data-slot": "alert-dialog-portal", ...props });
20
+ }
21
+ function AlertDialogOverlay({ className, ...props }) {
22
+ return (_jsx(AlertDialogPrimitive.Overlay, { "data-slot": "alert-dialog-overlay", className: cn(overlayClassName, className), ...props }));
23
+ }
24
+ function AlertDialogContent({ className, ...props }) {
25
+ return (_jsxs(AlertDialogPortal, { children: [_jsx(AlertDialogOverlay, {}), _jsx(AlertDialogPrimitive.Content, { "data-slot": "alert-dialog-content", className: cn('fixed top-1/2 left-1/2 z-50 flex w-[calc(100%-2rem)] max-w-[480px] -translate-x-1/2 -translate-y-1/2 flex-col gap-4 rounded-xl border border-border bg-background p-6 text-body text-foreground shadow-lg outline-none data-[state=open]:animate-in data-[state=open]:fade-in-0 data-[state=open]:zoom-in-95 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95', className), ...props })] }));
26
+ }
27
+ function AlertDialogHeader({ className, ...props }) {
28
+ return _jsx("div", { "data-slot": "alert-dialog-header", className: cn('flex flex-col gap-1.5', className), ...props });
29
+ }
30
+ function AlertDialogFooter({ className, ...props }) {
31
+ return (_jsx("div", { "data-slot": "alert-dialog-footer", className: cn('flex flex-col-reverse gap-2 sm:flex-row sm:justify-end', className), ...props }));
32
+ }
33
+ function AlertDialogTitle({ className, ...props }) {
34
+ return (_jsx(AlertDialogPrimitive.Title, { "data-slot": "alert-dialog-title", className: cn('text-page-title', className), ...props }));
35
+ }
36
+ function AlertDialogDescription({ className, ...props }) {
37
+ return (_jsx(AlertDialogPrimitive.Description, { "data-slot": "alert-dialog-description", className: cn('text-body text-muted-foreground', className), ...props }));
38
+ }
39
+ function AlertDialogAction({ className, variant = 'default', ...props }) {
40
+ return (_jsx(AlertDialogPrimitive.Action, { "data-slot": "alert-dialog-action", className: cn(buttonVariants({ variant }), className), ...props }));
41
+ }
42
+ function AlertDialogCancel({ className, ...props }) {
43
+ return (_jsx(AlertDialogPrimitive.Cancel, { "data-slot": "alert-dialog-cancel", className: cn(buttonVariants({ variant: 'outline' }), className), ...props }));
44
+ }
45
+ export { AlertDialog, AlertDialogAction, AlertDialogCancel, AlertDialogContent, AlertDialogDescription, AlertDialogFooter, AlertDialogHeader, AlertDialogOverlay, AlertDialogPortal, AlertDialogTitle, AlertDialogTrigger, };
46
+ //# sourceMappingURL=alert-dialog.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"alert-dialog.js","sourceRoot":"","sources":["../../src/components/alert-dialog.tsx"],"names":[],"mappings":"AAAA,YAAY,CAAC;;AAEb,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAC/B,OAAO,EAAE,WAAW,IAAI,oBAAoB,EAAE,MAAM,UAAU,CAAC;AAG/D,OAAO,EAAE,EAAE,EAAE,MAAM,iBAAiB,CAAC;AACrC,OAAO,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAC7C,OAAO,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAE/C;;;GAGG;AACH,SAAS,WAAW,CAAC,KAA6D;IAChF,OAAO,KAAC,oBAAoB,CAAC,IAAI,iBAAW,cAAc,KAAK,KAAK,GAAI,CAAC;AAC3E,CAAC;AAED,SAAS,kBAAkB,CAAC,KAAgE;IAC1F,OAAO,KAAC,oBAAoB,CAAC,OAAO,iBAAW,sBAAsB,KAAK,KAAK,GAAI,CAAC;AACtF,CAAC;AAED,SAAS,iBAAiB,CAAC,KAA+D;IACxF,OAAO,KAAC,oBAAoB,CAAC,MAAM,iBAAW,qBAAqB,KAAK,KAAK,GAAI,CAAC;AACpF,CAAC;AAED,SAAS,kBAAkB,CAAC,EAC1B,SAAS,EACT,GAAG,KAAK,EACkD;IAC1D,OAAO,CACL,KAAC,oBAAoB,CAAC,OAAO,iBACjB,sBAAsB,EAChC,SAAS,EAAE,EAAE,CAAC,gBAAgB,EAAE,SAAS,CAAC,KACtC,KAAK,GACT,CACH,CAAC;AACJ,CAAC;AAED,SAAS,kBAAkB,CAAC,EAC1B,SAAS,EACT,GAAG,KAAK,EACkD;IAC1D,OAAO,CACL,MAAC,iBAAiB,eAChB,KAAC,kBAAkB,KAAG,EACtB,KAAC,oBAAoB,CAAC,OAAO,iBACjB,sBAAsB,EAChC,SAAS,EAAE,EAAE,CACX,6YAA6Y,EAC7Y,SAAS,CACV,KACG,KAAK,GACT,IACgB,CACrB,CAAC;AACJ,CAAC;AAED,SAAS,iBAAiB,CAAC,EAAE,SAAS,EAAE,GAAG,KAAK,EAA+B;IAC7E,OAAO,2BAAe,qBAAqB,EAAC,SAAS,EAAE,EAAE,CAAC,uBAAuB,EAAE,SAAS,CAAC,KAAM,KAAK,GAAI,CAAC;AAC/G,CAAC;AAED,SAAS,iBAAiB,CAAC,EAAE,SAAS,EAAE,GAAG,KAAK,EAA+B;IAC7E,OAAO,CACL,2BACY,qBAAqB,EAC/B,SAAS,EAAE,EAAE,CAAC,wDAAwD,EAAE,SAAS,CAAC,KAC9E,KAAK,GACT,CACH,CAAC;AACJ,CAAC;AAED,SAAS,gBAAgB,CAAC,EACxB,SAAS,EACT,GAAG,KAAK,EACgD;IACxD,OAAO,CACL,KAAC,oBAAoB,CAAC,KAAK,iBACf,oBAAoB,EAC9B,SAAS,EAAE,EAAE,CAAC,iBAAiB,EAAE,SAAS,CAAC,KACvC,KAAK,GACT,CACH,CAAC;AACJ,CAAC;AAED,SAAS,sBAAsB,CAAC,EAC9B,SAAS,EACT,GAAG,KAAK,EACsD;IAC9D,OAAO,CACL,KAAC,oBAAoB,CAAC,WAAW,iBACrB,0BAA0B,EACpC,SAAS,EAAE,EAAE,CAAC,iCAAiC,EAAE,SAAS,CAAC,KACvD,KAAK,GACT,CACH,CAAC;AACJ,CAAC;AAED,SAAS,iBAAiB,CAAC,EACzB,SAAS,EACT,OAAO,GAAG,SAAS,EACnB,GAAG,KAAK,EAE4C;IACpD,OAAO,CACL,KAAC,oBAAoB,CAAC,MAAM,iBAChB,qBAAqB,EAC/B,SAAS,EAAE,EAAE,CAAC,cAAc,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE,SAAS,CAAC,KACjD,KAAK,GACT,CACH,CAAC;AACJ,CAAC;AAED,SAAS,iBAAiB,CAAC,EACzB,SAAS,EACT,GAAG,KAAK,EACiD;IACzD,OAAO,CACL,KAAC,oBAAoB,CAAC,MAAM,iBAChB,qBAAqB,EAC/B,SAAS,EAAE,EAAE,CAAC,cAAc,CAAC,EAAE,OAAO,EAAE,SAAS,EAAE,CAAC,EAAE,SAAS,CAAC,KAC5D,KAAK,GACT,CACH,CAAC;AACJ,CAAC;AAED,OAAO,EACL,WAAW,EACX,iBAAiB,EACjB,iBAAiB,EACjB,kBAAkB,EAClB,sBAAsB,EACtB,iBAAiB,EACjB,iBAAiB,EACjB,kBAAkB,EAClB,iBAAiB,EACjB,gBAAgB,EAChB,kBAAkB,GACnB,CAAC"}
@@ -0,0 +1,24 @@
1
+ import * as React from 'react';
2
+ import { type VariantProps } from 'class-variance-authority';
3
+ /**
4
+ * Figma: Components · Base › Alert (2085:172). 8 px radius, 12/16 px padding, 12 px gap,
5
+ * 16 px icon. info = bordered on background (violet icon, muted text); the states are a
6
+ * tint with the -strong shade for icon, title and text.
7
+ */
8
+ declare const alertVariants: (props?: ({
9
+ tone?: "destructive" | "info" | "success" | "warning" | null | undefined;
10
+ } & import("class-variance-authority/types").ClassProp) | undefined) => string;
11
+ type AlertTone = NonNullable<VariantProps<typeof alertVariants>['tone']>;
12
+ type AlertProps = React.ComponentProps<'div'> & {
13
+ /** Figma "Tone". Default `info`. */
14
+ tone?: AlertTone | null;
15
+ /** shadcn name for `tone`. Also accepts `default` (→ `info`). */
16
+ variant?: AlertTone | 'default' | null;
17
+ /** The icon. Default: the tone's lucide icon from Figma. `null` = no icon. */
18
+ icon?: React.ReactNode;
19
+ };
20
+ declare function Alert({ className, tone: toneProp, variant, icon, children, ...props }: AlertProps): React.JSX.Element;
21
+ declare function AlertTitle({ className, ...props }: React.ComponentProps<'div'>): React.JSX.Element;
22
+ declare function AlertDescription({ className, ...props }: React.ComponentProps<'div'>): React.JSX.Element;
23
+ export { Alert, AlertTitle, AlertDescription, alertVariants, type AlertProps, type AlertTone };
24
+ //# sourceMappingURL=alert.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"alert.d.ts","sourceRoot":"","sources":["../../src/components/alert.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAC/B,OAAO,EAAO,KAAK,YAAY,EAAE,MAAM,0BAA0B,CAAC;AAMlE;;;;GAIG;AACH,QAAA,MAAM,aAAa;;8EAalB,CAAC;AASF,KAAK,SAAS,GAAG,WAAW,CAAC,YAAY,CAAC,OAAO,aAAa,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC;AAEzE,KAAK,UAAU,GAAG,KAAK,CAAC,cAAc,CAAC,KAAK,CAAC,GAAG;IAC9C,oCAAoC;IACpC,IAAI,CAAC,EAAE,SAAS,GAAG,IAAI,CAAC;IACxB,iEAAiE;IACjE,OAAO,CAAC,EAAE,SAAS,GAAG,SAAS,GAAG,IAAI,CAAC;IACvC,8EAA8E;IAC9E,IAAI,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;CACxB,CAAC;AAEF,iBAAS,KAAK,CAAC,EAAE,SAAS,EAAE,IAAI,EAAE,QAAQ,EAAE,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,GAAG,KAAK,EAAE,EAAE,UAAU,qBAgB1F;AAED,iBAAS,UAAU,CAAC,EAAE,SAAS,EAAE,GAAG,KAAK,EAAE,EAAE,KAAK,CAAC,cAAc,CAAC,KAAK,CAAC,qBAQvE;AAED,iBAAS,gBAAgB,CAAC,EAAE,SAAS,EAAE,GAAG,KAAK,EAAE,EAAE,KAAK,CAAC,cAAc,CAAC,KAAK,CAAC,qBAW7E;AAED,OAAO,EAAE,KAAK,EAAE,UAAU,EAAE,gBAAgB,EAAE,aAAa,EAAE,KAAK,UAAU,EAAE,KAAK,SAAS,EAAE,CAAC"}
@@ -0,0 +1,42 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import * as React from 'react';
3
+ import { cva } from 'class-variance-authority';
4
+ import { CircleAlertIcon, CircleCheckIcon, InfoIcon, TriangleAlertIcon } from 'lucide-react';
5
+ import { resolveTone } from '../lib/tone.js';
6
+ import { cn } from '../lib/utils.js';
7
+ /**
8
+ * Figma: Components · Base › Alert (2085:172). 8 px radius, 12/16 px padding, 12 px gap,
9
+ * 16 px icon. info = bordered on background (violet icon, muted text); the states are a
10
+ * tint with the -strong shade for icon, title and text.
11
+ */
12
+ const alertVariants = cva("relative grid w-full grid-cols-[auto_1fr] items-start gap-x-3 gap-y-0.5 rounded-lg px-4 py-3 text-body [&>svg]:size-4", {
13
+ variants: {
14
+ tone: {
15
+ info: 'border border-border bg-background text-foreground [&>svg]:text-primary-strong *:data-[slot=alert-description]:text-muted-foreground',
16
+ success: 'bg-success-tint text-success-strong',
17
+ warning: 'bg-warning-tint text-warning-strong',
18
+ destructive: 'bg-destructive-tint text-destructive-strong',
19
+ },
20
+ },
21
+ defaultVariants: { tone: 'info' },
22
+ });
23
+ const defaultIcons = {
24
+ info: InfoIcon,
25
+ success: CircleCheckIcon,
26
+ warning: TriangleAlertIcon,
27
+ destructive: CircleAlertIcon,
28
+ };
29
+ function Alert({ className, tone: toneProp, variant, icon, children, ...props }) {
30
+ const tone = resolveTone(toneProp, variant, { default: 'info' }, 'info');
31
+ const DefaultIcon = defaultIcons[tone];
32
+ const shown = icon === undefined ? _jsx(DefaultIcon, { "aria-hidden": true }) : icon;
33
+ return (_jsxs("div", { "data-slot": "alert", "data-tone": tone, role: "alert", className: cn(alertVariants({ tone }), !shown && 'grid-cols-1', className), ...props, children: [shown, children] }));
34
+ }
35
+ function AlertTitle({ className, ...props }) {
36
+ return (_jsx("div", { "data-slot": "alert-title", className: cn('col-start-2 font-medium in-[[data-slot=alert].grid-cols-1]:col-start-1', className), ...props }));
37
+ }
38
+ function AlertDescription({ className, ...props }) {
39
+ return (_jsx("div", { "data-slot": "alert-description", className: cn('col-start-2 text-body-sm in-[[data-slot=alert].grid-cols-1]:col-start-1 [&_p]:leading-relaxed', className), ...props }));
40
+ }
41
+ export { Alert, AlertTitle, AlertDescription, alertVariants };
42
+ //# sourceMappingURL=alert.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"alert.js","sourceRoot":"","sources":["../../src/components/alert.tsx"],"names":[],"mappings":";AAAA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAC/B,OAAO,EAAE,GAAG,EAAqB,MAAM,0BAA0B,CAAC;AAClE,OAAO,EAAE,eAAe,EAAE,eAAe,EAAE,QAAQ,EAAE,iBAAiB,EAAE,MAAM,cAAc,CAAC;AAE7F,OAAO,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAC7C,OAAO,EAAE,EAAE,EAAE,MAAM,iBAAiB,CAAC;AAErC;;;;GAIG;AACH,MAAM,aAAa,GAAG,GAAG,CACvB,uHAAuH,EACvH;IACE,QAAQ,EAAE;QACR,IAAI,EAAE;YACJ,IAAI,EAAE,sIAAsI;YAC5I,OAAO,EAAE,qCAAqC;YAC9C,OAAO,EAAE,qCAAqC;YAC9C,WAAW,EAAE,6CAA6C;SAC3D;KACF;IACD,eAAe,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE;CAClC,CACF,CAAC;AAEF,MAAM,YAAY,GAAG;IACnB,IAAI,EAAE,QAAQ;IACd,OAAO,EAAE,eAAe;IACxB,OAAO,EAAE,iBAAiB;IAC1B,WAAW,EAAE,eAAe;CACpB,CAAC;AAaX,SAAS,KAAK,CAAC,EAAE,SAAS,EAAE,IAAI,EAAE,QAAQ,EAAE,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,GAAG,KAAK,EAAc;IACzF,MAAM,IAAI,GAAG,WAAW,CAAC,QAAQ,EAAE,OAAO,EAAE,EAAE,OAAO,EAAE,MAAM,EAAE,EAAE,MAAM,CAAC,CAAC;IACzE,MAAM,WAAW,GAAG,YAAY,CAAC,IAAI,CAAC,CAAC;IACvC,MAAM,KAAK,GAAG,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,KAAC,WAAW,0BAAe,CAAC,CAAC,CAAC,IAAI,CAAC;IACtE,OAAO,CACL,4BACY,OAAO,eACN,IAAI,EACf,IAAI,EAAC,OAAO,EACZ,SAAS,EAAE,EAAE,CAAC,aAAa,CAAC,EAAE,IAAI,EAAE,CAAC,EAAE,CAAC,KAAK,IAAI,aAAa,EAAE,SAAS,CAAC,KACtE,KAAK,aAER,KAAK,EACL,QAAQ,IACL,CACP,CAAC;AACJ,CAAC;AAED,SAAS,UAAU,CAAC,EAAE,SAAS,EAAE,GAAG,KAAK,EAA+B;IACtE,OAAO,CACL,2BACY,aAAa,EACvB,SAAS,EAAE,EAAE,CAAC,wEAAwE,EAAE,SAAS,CAAC,KAC9F,KAAK,GACT,CACH,CAAC;AACJ,CAAC;AAED,SAAS,gBAAgB,CAAC,EAAE,SAAS,EAAE,GAAG,KAAK,EAA+B;IAC5E,OAAO,CACL,2BACY,mBAAmB,EAC7B,SAAS,EAAE,EAAE,CACX,+FAA+F,EAC/F,SAAS,CACV,KACG,KAAK,GACT,CACH,CAAC;AACJ,CAAC;AAED,OAAO,EAAE,KAAK,EAAE,UAAU,EAAE,gBAAgB,EAAE,aAAa,EAAmC,CAAC"}
@@ -0,0 +1,27 @@
1
+ import * as React from 'react';
2
+ import { type VariantProps } from 'class-variance-authority';
3
+ import { Avatar as AvatarPrimitive } from 'radix-ui';
4
+ /**
5
+ * Figma: Components · Base › Avatar (2006:62). 20 or 28 px, full radius. Initials use a
6
+ * soft tint per person with the -strong shade, never a solid saturated fill.
7
+ */
8
+ declare const avatarVariants: (props?: ({
9
+ size?: 20 | 28 | null | undefined;
10
+ } & import("class-variance-authority/types").ClassProp) | undefined) => string;
11
+ declare const avatarFallbackVariants: (props?: ({
12
+ tone?: "amber" | "coral" | "emerald" | "purple" | "red" | "slate" | null | undefined;
13
+ } & import("class-variance-authority/types").ClassProp) | undefined) => string;
14
+ type AvatarTone = NonNullable<VariantProps<typeof avatarFallbackVariants>['tone']>;
15
+ /** A stable tone for a person (same name → same tint), for lists without a stored tone. */
16
+ declare function avatarToneFor(key: string): AvatarTone;
17
+ declare function Avatar({ className, size, ...props }: React.ComponentProps<typeof AvatarPrimitive.Root> & VariantProps<typeof avatarVariants>): React.JSX.Element;
18
+ declare function AvatarImage({ className, ...props }: React.ComponentProps<typeof AvatarPrimitive.Image>): React.JSX.Element;
19
+ type AvatarFallbackProps = React.ComponentProps<typeof AvatarPrimitive.Fallback> & {
20
+ /** Figma "Tone". Default `slate`. `avatarToneFor(name)` picks a stable one per person. */
21
+ tone?: AvatarTone | null;
22
+ /** Same as `tone` (shadcn-style name). */
23
+ variant?: AvatarTone | null;
24
+ };
25
+ declare function AvatarFallback({ className, tone: toneProp, variant, ...props }: AvatarFallbackProps): React.JSX.Element;
26
+ export { Avatar, AvatarImage, AvatarFallback, avatarVariants, avatarFallbackVariants, avatarToneFor, type AvatarTone, type AvatarFallbackProps, };
27
+ //# sourceMappingURL=avatar.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"avatar.d.ts","sourceRoot":"","sources":["../../src/components/avatar.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAC/B,OAAO,EAAO,KAAK,YAAY,EAAE,MAAM,0BAA0B,CAAC;AAClE,OAAO,EAAE,MAAM,IAAI,eAAe,EAAE,MAAM,UAAU,CAAC;AAKrD;;;GAGG;AACH,QAAA,MAAM,cAAc;;8EAQlB,CAAC;AAEH,QAAA,MAAM,sBAAsB;;8EAe3B,CAAC;AAEF,KAAK,UAAU,GAAG,WAAW,CAAC,YAAY,CAAC,OAAO,sBAAsB,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC;AAInF,2FAA2F;AAC3F,iBAAS,aAAa,CAAC,GAAG,EAAE,MAAM,GAAG,UAAU,CAI9C;AAED,iBAAS,MAAM,CAAC,EACd,SAAS,EACT,IAAS,EACT,GAAG,KAAK,EACT,EAAE,KAAK,CAAC,cAAc,CAAC,OAAO,eAAe,CAAC,IAAI,CAAC,GAAG,YAAY,CAAC,OAAO,cAAc,CAAC,qBASzF;AAED,iBAAS,WAAW,CAAC,EAAE,SAAS,EAAE,GAAG,KAAK,EAAE,EAAE,KAAK,CAAC,cAAc,CAAC,OAAO,eAAe,CAAC,KAAK,CAAC,qBAQ/F;AAED,KAAK,mBAAmB,GAAG,KAAK,CAAC,cAAc,CAAC,OAAO,eAAe,CAAC,QAAQ,CAAC,GAAG;IACjF,0FAA0F;IAC1F,IAAI,CAAC,EAAE,UAAU,GAAG,IAAI,CAAC;IACzB,0CAA0C;IAC1C,OAAO,CAAC,EAAE,UAAU,GAAG,IAAI,CAAC;CAC7B,CAAC;AAEF,iBAAS,cAAc,CAAC,EAAE,SAAS,EAAE,IAAI,EAAE,QAAQ,EAAE,OAAO,EAAE,GAAG,KAAK,EAAE,EAAE,mBAAmB,qBAU5F;AAED,OAAO,EACL,MAAM,EACN,WAAW,EACX,cAAc,EACd,cAAc,EACd,sBAAsB,EACtB,aAAa,EACb,KAAK,UAAU,EACf,KAAK,mBAAmB,GACzB,CAAC"}
@@ -0,0 +1,53 @@
1
+ 'use client';
2
+ import { jsx as _jsx } from "react/jsx-runtime";
3
+ import * as React from 'react';
4
+ import { cva } from 'class-variance-authority';
5
+ import { Avatar as AvatarPrimitive } from 'radix-ui';
6
+ import { resolveTone } from '../lib/tone.js';
7
+ import { cn } from '../lib/utils.js';
8
+ /**
9
+ * Figma: Components · Base › Avatar (2006:62). 20 or 28 px, full radius. Initials use a
10
+ * soft tint per person with the -strong shade, never a solid saturated fill.
11
+ */
12
+ const avatarVariants = cva('group/avatar relative flex shrink-0 overflow-hidden rounded-full', {
13
+ variants: {
14
+ size: {
15
+ 20: 'size-5',
16
+ 28: 'size-7',
17
+ },
18
+ },
19
+ defaultVariants: { size: 28 },
20
+ });
21
+ const avatarFallbackVariants = cva('flex size-full items-center justify-center rounded-full text-initials group-data-[size=20]/avatar:text-initials-sm', {
22
+ variants: {
23
+ tone: {
24
+ purple: 'bg-primary-tint text-primary-strong',
25
+ amber: 'bg-warning-tint text-warning-strong',
26
+ red: 'bg-destructive-tint text-destructive-strong',
27
+ emerald: 'bg-success-tint text-success-strong',
28
+ coral: 'bg-secondary text-secondary-foreground',
29
+ slate: 'bg-secondary text-secondary-foreground',
30
+ },
31
+ },
32
+ defaultVariants: { tone: 'slate' },
33
+ });
34
+ const avatarTones = ['purple', 'amber', 'red', 'emerald', 'coral', 'slate'];
35
+ /** A stable tone for a person (same name → same tint), for lists without a stored tone. */
36
+ function avatarToneFor(key) {
37
+ let hash = 0;
38
+ for (let i = 0; i < key.length; i++)
39
+ hash = (hash * 31 + key.charCodeAt(i)) | 0;
40
+ return avatarTones[Math.abs(hash) % avatarTones.length] ?? 'slate';
41
+ }
42
+ function Avatar({ className, size = 28, ...props }) {
43
+ return (_jsx(AvatarPrimitive.Root, { "data-slot": "avatar", "data-size": size, className: cn(avatarVariants({ size }), className), ...props }));
44
+ }
45
+ function AvatarImage({ className, ...props }) {
46
+ return (_jsx(AvatarPrimitive.Image, { "data-slot": "avatar-image", className: cn('aspect-square size-full object-cover', className), ...props }));
47
+ }
48
+ function AvatarFallback({ className, tone: toneProp, variant, ...props }) {
49
+ const tone = resolveTone(toneProp, variant, {}, 'slate');
50
+ return (_jsx(AvatarPrimitive.Fallback, { "data-slot": "avatar-fallback", "data-tone": tone, className: cn(avatarFallbackVariants({ tone }), className), ...props }));
51
+ }
52
+ export { Avatar, AvatarImage, AvatarFallback, avatarVariants, avatarFallbackVariants, avatarToneFor, };
53
+ //# sourceMappingURL=avatar.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"avatar.js","sourceRoot":"","sources":["../../src/components/avatar.tsx"],"names":[],"mappings":"AAAA,YAAY,CAAC;;AAEb,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAC/B,OAAO,EAAE,GAAG,EAAqB,MAAM,0BAA0B,CAAC;AAClE,OAAO,EAAE,MAAM,IAAI,eAAe,EAAE,MAAM,UAAU,CAAC;AAErD,OAAO,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAC7C,OAAO,EAAE,EAAE,EAAE,MAAM,iBAAiB,CAAC;AAErC;;;GAGG;AACH,MAAM,cAAc,GAAG,GAAG,CAAC,kEAAkE,EAAE;IAC7F,QAAQ,EAAE;QACR,IAAI,EAAE;YACJ,EAAE,EAAE,QAAQ;YACZ,EAAE,EAAE,QAAQ;SACb;KACF;IACD,eAAe,EAAE,EAAE,IAAI,EAAE,EAAE,EAAE;CAC9B,CAAC,CAAC;AAEH,MAAM,sBAAsB,GAAG,GAAG,CAChC,oHAAoH,EACpH;IACE,QAAQ,EAAE;QACR,IAAI,EAAE;YACJ,MAAM,EAAE,qCAAqC;YAC7C,KAAK,EAAE,qCAAqC;YAC5C,GAAG,EAAE,6CAA6C;YAClD,OAAO,EAAE,qCAAqC;YAC9C,KAAK,EAAE,wCAAwC;YAC/C,KAAK,EAAE,wCAAwC;SAChD;KACF;IACD,eAAe,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE;CACnC,CACF,CAAC;AAIF,MAAM,WAAW,GAA0B,CAAC,QAAQ,EAAE,OAAO,EAAE,KAAK,EAAE,SAAS,EAAE,OAAO,EAAE,OAAO,CAAC,CAAC;AAEnG,2FAA2F;AAC3F,SAAS,aAAa,CAAC,GAAW;IAChC,IAAI,IAAI,GAAG,CAAC,CAAC;IACb,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,GAAG,CAAC,MAAM,EAAE,CAAC,EAAE;QAAE,IAAI,GAAG,CAAC,IAAI,GAAG,EAAE,GAAG,GAAG,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;IAChF,OAAO,WAAW,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,WAAW,CAAC,MAAM,CAAC,IAAI,OAAO,CAAC;AACrE,CAAC;AAED,SAAS,MAAM,CAAC,EACd,SAAS,EACT,IAAI,GAAG,EAAE,EACT,GAAG,KAAK,EACgF;IACxF,OAAO,CACL,KAAC,eAAe,CAAC,IAAI,iBACT,QAAQ,eACP,IAAI,EACf,SAAS,EAAE,EAAE,CAAC,cAAc,CAAC,EAAE,IAAI,EAAE,CAAC,EAAE,SAAS,CAAC,KAC9C,KAAK,GACT,CACH,CAAC;AACJ,CAAC;AAED,SAAS,WAAW,CAAC,EAAE,SAAS,EAAE,GAAG,KAAK,EAAsD;IAC9F,OAAO,CACL,KAAC,eAAe,CAAC,KAAK,iBACV,cAAc,EACxB,SAAS,EAAE,EAAE,CAAC,sCAAsC,EAAE,SAAS,CAAC,KAC5D,KAAK,GACT,CACH,CAAC;AACJ,CAAC;AASD,SAAS,cAAc,CAAC,EAAE,SAAS,EAAE,IAAI,EAAE,QAAQ,EAAE,OAAO,EAAE,GAAG,KAAK,EAAuB;IAC3F,MAAM,IAAI,GAAG,WAAW,CAAC,QAAQ,EAAE,OAAO,EAAE,EAAE,EAAE,OAAO,CAAC,CAAC;IACzD,OAAO,CACL,KAAC,eAAe,CAAC,QAAQ,iBACb,iBAAiB,eAChB,IAAI,EACf,SAAS,EAAE,EAAE,CAAC,sBAAsB,CAAC,EAAE,IAAI,EAAE,CAAC,EAAE,SAAS,CAAC,KACtD,KAAK,GACT,CACH,CAAC;AACJ,CAAC;AAED,OAAO,EACL,MAAM,EACN,WAAW,EACX,cAAc,EACd,cAAc,EACd,sBAAsB,EACtB,aAAa,GAGd,CAAC"}
@@ -0,0 +1,21 @@
1
+ import * as React from 'react';
2
+ import { type VariantProps } from 'class-variance-authority';
3
+ /**
4
+ * Figma: Components · Base › Badge (2006:37). 20 px high, 6 px radius, Label/Caption
5
+ * Medium. Every tone is a soft tint with the -strong text shade ("one color, one job").
6
+ * Only status fields get a tone: categorical tags (country, owner…) stay neutral.
7
+ */
8
+ declare const badgeVariants: (props?: ({
9
+ tone?: "destructive" | "highlight" | "info" | "neutral" | "primary" | "success" | "warning" | null | undefined;
10
+ } & import("class-variance-authority/types").ClassProp) | undefined) => string;
11
+ type BadgeTone = NonNullable<VariantProps<typeof badgeVariants>['tone']>;
12
+ type BadgeProps = React.ComponentProps<'span'> & {
13
+ /** Figma "Tone". Default `neutral`. */
14
+ tone?: BadgeTone | null;
15
+ /** shadcn name for `tone`. Also accepts `default`, `secondary`, `outline` (→ `neutral`). */
16
+ variant?: BadgeTone | 'default' | 'secondary' | 'outline' | null;
17
+ asChild?: boolean;
18
+ };
19
+ declare function Badge({ className, tone, variant, asChild, ...props }: BadgeProps): React.JSX.Element;
20
+ export { Badge, badgeVariants, type BadgeProps, type BadgeTone };
21
+ //# sourceMappingURL=badge.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"badge.d.ts","sourceRoot":"","sources":["../../src/components/badge.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAC/B,OAAO,EAAO,KAAK,YAAY,EAAE,MAAM,0BAA0B,CAAC;AAMlE;;;;GAIG;AACH,QAAA,MAAM,aAAa;;8EAkBlB,CAAC;AAEF,KAAK,SAAS,GAAG,WAAW,CAAC,YAAY,CAAC,OAAO,aAAa,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC;AASzE,KAAK,UAAU,GAAG,KAAK,CAAC,cAAc,CAAC,MAAM,CAAC,GAAG;IAC/C,uCAAuC;IACvC,IAAI,CAAC,EAAE,SAAS,GAAG,IAAI,CAAC;IACxB,4FAA4F;IAC5F,OAAO,CAAC,EAAE,SAAS,GAAG,SAAS,GAAG,WAAW,GAAG,SAAS,GAAG,IAAI,CAAC;IACjE,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB,CAAC;AAEF,iBAAS,KAAK,CAAC,EAAE,SAAS,EAAE,IAAI,EAAE,OAAO,EAAE,OAAe,EAAE,GAAG,KAAK,EAAE,EAAE,UAAU,qBAWjF;AAED,OAAO,EAAE,KAAK,EAAE,aAAa,EAAE,KAAK,UAAU,EAAE,KAAK,SAAS,EAAE,CAAC"}