@craftzbay/ui 0.8.1 → 0.10.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 (172) hide show
  1. package/README.md +72 -6
  2. package/dist-lib/components/ui/Accordion.js +60 -0
  3. package/dist-lib/components/ui/Accordion.js.map +1 -0
  4. package/dist-lib/components/ui/Alert.d.ts +1 -1
  5. package/dist-lib/components/ui/Alert.js +66 -0
  6. package/dist-lib/components/ui/Alert.js.map +1 -0
  7. package/dist-lib/components/ui/Avatar.d.ts +2 -2
  8. package/dist-lib/components/ui/Avatar.js +96 -0
  9. package/dist-lib/components/ui/Avatar.js.map +1 -0
  10. package/dist-lib/components/ui/Badge.d.ts +1 -1
  11. package/dist-lib/components/ui/Badge.js +67 -0
  12. package/dist-lib/components/ui/Badge.js.map +1 -0
  13. package/dist-lib/components/ui/Breadcrumbs.js +34 -0
  14. package/dist-lib/components/ui/Breadcrumbs.js.map +1 -0
  15. package/dist-lib/components/ui/Button.d.ts +1 -1
  16. package/dist-lib/components/ui/Button.js +117 -0
  17. package/dist-lib/components/ui/Button.js.map +1 -0
  18. package/dist-lib/components/ui/Calendar.d.ts +7 -1
  19. package/dist-lib/components/ui/Calendar.js +111 -0
  20. package/dist-lib/components/ui/Calendar.js.map +1 -0
  21. package/dist-lib/components/ui/Card.d.ts +1 -1
  22. package/dist-lib/components/ui/Card.js +116 -0
  23. package/dist-lib/components/ui/Card.js.map +1 -0
  24. package/dist-lib/components/ui/Carousel.d.ts +5 -1
  25. package/dist-lib/components/ui/Carousel.js +143 -0
  26. package/dist-lib/components/ui/Carousel.js.map +1 -0
  27. package/dist-lib/components/ui/Chart.d.ts +26 -4
  28. package/dist-lib/components/ui/Chart.js +253 -0
  29. package/dist-lib/components/ui/Chart.js.map +1 -0
  30. package/dist-lib/components/ui/Checkbox.js +56 -0
  31. package/dist-lib/components/ui/Checkbox.js.map +1 -0
  32. package/dist-lib/components/ui/Combobox.d.ts +7 -0
  33. package/dist-lib/components/ui/Combobox.js +164 -0
  34. package/dist-lib/components/ui/Combobox.js.map +1 -0
  35. package/dist-lib/components/ui/CommandPalette.d.ts +3 -3
  36. package/dist-lib/components/ui/CommandPalette.js +174 -0
  37. package/dist-lib/components/ui/CommandPalette.js.map +1 -0
  38. package/dist-lib/components/ui/ContextMenu.js +150 -0
  39. package/dist-lib/components/ui/ContextMenu.js.map +1 -0
  40. package/dist-lib/components/ui/DataGrid.js +84 -0
  41. package/dist-lib/components/ui/DataGrid.js.map +1 -0
  42. package/dist-lib/components/ui/DatePicker.d.ts +16 -13
  43. package/dist-lib/components/ui/DatePicker.js +174 -0
  44. package/dist-lib/components/ui/DatePicker.js.map +1 -0
  45. package/dist-lib/components/ui/DesignSystemProvider.d.ts +8 -1
  46. package/dist-lib/components/ui/DesignSystemProvider.js +79 -0
  47. package/dist-lib/components/ui/DesignSystemProvider.js.map +1 -0
  48. package/dist-lib/components/ui/Dialog.d.ts +1 -1
  49. package/dist-lib/components/ui/Dialog.js +140 -0
  50. package/dist-lib/components/ui/Dialog.js.map +1 -0
  51. package/dist-lib/components/ui/Drawer.d.ts +6 -0
  52. package/dist-lib/components/ui/Drawer.js +98 -0
  53. package/dist-lib/components/ui/Drawer.js.map +1 -0
  54. package/dist-lib/components/ui/DropdownMenu.js +164 -0
  55. package/dist-lib/components/ui/DropdownMenu.js.map +1 -0
  56. package/dist-lib/components/ui/EmptyState.js +32 -0
  57. package/dist-lib/components/ui/EmptyState.js.map +1 -0
  58. package/dist-lib/components/ui/ErrorState.js +48 -0
  59. package/dist-lib/components/ui/ErrorState.js.map +1 -0
  60. package/dist-lib/components/ui/FileUpload.d.ts +3 -0
  61. package/dist-lib/components/ui/FileUpload.js +108 -0
  62. package/dist-lib/components/ui/FileUpload.js.map +1 -0
  63. package/dist-lib/components/ui/Form.d.ts +1 -0
  64. package/dist-lib/components/ui/Form.js +105 -0
  65. package/dist-lib/components/ui/Form.js.map +1 -0
  66. package/dist-lib/components/ui/Icon.d.ts +34 -0
  67. package/dist-lib/components/ui/Icon.js +26 -0
  68. package/dist-lib/components/ui/Icon.js.map +1 -0
  69. package/dist-lib/components/ui/IconButton.d.ts +1 -1
  70. package/dist-lib/components/ui/IconButton.js +56 -0
  71. package/dist-lib/components/ui/IconButton.js.map +1 -0
  72. package/dist-lib/components/ui/Input.d.ts +6 -3
  73. package/dist-lib/components/ui/Input.js +135 -0
  74. package/dist-lib/components/ui/Input.js.map +1 -0
  75. package/dist-lib/components/ui/Kbd.js +24 -0
  76. package/dist-lib/components/ui/Kbd.js.map +1 -0
  77. package/dist-lib/components/ui/MultiSelect.d.ts +3 -1
  78. package/dist-lib/components/ui/MultiSelect.js +196 -0
  79. package/dist-lib/components/ui/MultiSelect.js.map +1 -0
  80. package/dist-lib/components/ui/Pagination.d.ts +23 -0
  81. package/dist-lib/components/ui/Pagination.js +148 -0
  82. package/dist-lib/components/ui/Pagination.js.map +1 -0
  83. package/dist-lib/components/ui/Popover.js +35 -0
  84. package/dist-lib/components/ui/Popover.js.map +1 -0
  85. package/dist-lib/components/ui/Progress.js +95 -0
  86. package/dist-lib/components/ui/Progress.js.map +1 -0
  87. package/dist-lib/components/ui/RadioGroup.js +64 -0
  88. package/dist-lib/components/ui/RadioGroup.js.map +1 -0
  89. package/dist-lib/components/ui/ScrollArea.js +44 -0
  90. package/dist-lib/components/ui/ScrollArea.js.map +1 -0
  91. package/dist-lib/components/ui/Select.js +131 -0
  92. package/dist-lib/components/ui/Select.js.map +1 -0
  93. package/dist-lib/components/ui/Separator.js +26 -0
  94. package/dist-lib/components/ui/Separator.js.map +1 -0
  95. package/dist-lib/components/ui/Sheet.d.ts +1 -1
  96. package/dist-lib/components/ui/Sheet.js +113 -0
  97. package/dist-lib/components/ui/Sheet.js.map +1 -0
  98. package/dist-lib/components/ui/Sidebar.d.ts +18 -6
  99. package/dist-lib/components/ui/Sidebar.js +169 -0
  100. package/dist-lib/components/ui/Sidebar.js.map +1 -0
  101. package/dist-lib/components/ui/Skeleton.js +28 -0
  102. package/dist-lib/components/ui/Skeleton.js.map +1 -0
  103. package/dist-lib/components/ui/Slider.js +52 -0
  104. package/dist-lib/components/ui/Slider.js.map +1 -0
  105. package/dist-lib/components/ui/Snackbar.d.ts +1 -1
  106. package/dist-lib/components/ui/Snackbar.js +56 -0
  107. package/dist-lib/components/ui/Snackbar.js.map +1 -0
  108. package/dist-lib/components/ui/Spinner.js +42 -0
  109. package/dist-lib/components/ui/Spinner.js.map +1 -0
  110. package/dist-lib/components/ui/Stepper.js +88 -0
  111. package/dist-lib/components/ui/Stepper.js.map +1 -0
  112. package/dist-lib/components/ui/Switch.js +77 -0
  113. package/dist-lib/components/ui/Switch.js.map +1 -0
  114. package/dist-lib/components/ui/Table.d.ts +9 -1
  115. package/dist-lib/components/ui/Table.js +157 -0
  116. package/dist-lib/components/ui/Table.js.map +1 -0
  117. package/dist-lib/components/ui/Tabs.d.ts +1 -1
  118. package/dist-lib/components/ui/Tabs.js +89 -0
  119. package/dist-lib/components/ui/Tabs.js.map +1 -0
  120. package/dist-lib/components/ui/TagInput.d.ts +17 -2
  121. package/dist-lib/components/ui/TagInput.js +111 -0
  122. package/dist-lib/components/ui/TagInput.js.map +1 -0
  123. package/dist-lib/components/ui/Textarea.js +77 -0
  124. package/dist-lib/components/ui/Textarea.js.map +1 -0
  125. package/dist-lib/components/ui/Timeline.d.ts +16 -6
  126. package/dist-lib/components/ui/Timeline.js +52 -0
  127. package/dist-lib/components/ui/Timeline.js.map +1 -0
  128. package/dist-lib/components/ui/Toast.d.ts +1 -1
  129. package/dist-lib/components/ui/Toast.js +171 -0
  130. package/dist-lib/components/ui/Toast.js.map +1 -0
  131. package/dist-lib/components/ui/Tooltip.js +58 -0
  132. package/dist-lib/components/ui/Tooltip.js.map +1 -0
  133. package/dist-lib/components/ui/TopNav.js +52 -0
  134. package/dist-lib/components/ui/TopNav.js.map +1 -0
  135. package/dist-lib/components/ui/Tree.d.ts +27 -5
  136. package/dist-lib/components/ui/Tree.js +167 -0
  137. package/dist-lib/components/ui/Tree.js.map +1 -0
  138. package/dist-lib/hooks/use-field-ids.d.ts +29 -0
  139. package/dist-lib/hooks/use-field-ids.js +18 -0
  140. package/dist-lib/hooks/use-field-ids.js.map +1 -0
  141. package/dist-lib/hooks/use-media-query.js +18 -0
  142. package/dist-lib/hooks/use-media-query.js.map +1 -0
  143. package/dist-lib/hooks/use-strings.d.ts +5 -0
  144. package/dist-lib/hooks/use-strings.js +12 -0
  145. package/dist-lib/hooks/use-strings.js.map +1 -0
  146. package/dist-lib/hooks/use-toast.js +36 -0
  147. package/dist-lib/hooks/use-toast.js.map +1 -0
  148. package/dist-lib/icon.d.ts +8 -0
  149. package/dist-lib/icon.js +7 -0
  150. package/dist-lib/icon.js.map +1 -0
  151. package/dist-lib/icons/index.d.ts +71 -11
  152. package/dist-lib/icons/index.js +145 -0
  153. package/dist-lib/icons/index.js.map +1 -0
  154. package/dist-lib/illustrations/index.js +105 -0
  155. package/dist-lib/illustrations/index.js.map +1 -0
  156. package/dist-lib/index.d.ts +62 -58
  157. package/dist-lib/index.js +268 -4386
  158. package/dist-lib/index.js.map +1 -1
  159. package/dist-lib/lib/strings.d.ts +129 -0
  160. package/dist-lib/lib/strings.js +85 -0
  161. package/dist-lib/lib/strings.js.map +1 -0
  162. package/dist-lib/lib/strings.mn.d.ts +3 -0
  163. package/dist-lib/lib/strings.mn.js +70 -0
  164. package/dist-lib/lib/strings.mn.js.map +1 -0
  165. package/dist-lib/lib/utils.d.ts +0 -1
  166. package/dist-lib/lib/utils.js +10 -0
  167. package/dist-lib/lib/utils.js.map +1 -0
  168. package/dist-lib/styles.css +1 -1
  169. package/dist-lib/theme.css +777 -0
  170. package/package.json +31 -8
  171. package/dist-lib/index.cjs +0 -8
  172. package/dist-lib/index.cjs.map +0 -1
package/README.md CHANGED
@@ -15,19 +15,77 @@ primitives — Button through DataGrid — plus composed patterns
15
15
  ## Install
16
16
 
17
17
  ```bash
18
- pnpm add @craftzbay/ui
18
+ pnpm add @craftzbay/ui # peers: react ^18 || ^19, react-dom ^18 || ^19
19
19
  ```
20
20
 
21
+ **1. Fonts** — Geist + Geist Mono are referenced by the tokens but not bundled. Add to `<head>`:
22
+
23
+ ```html
24
+ <link rel="preconnect" href="https://fonts.googleapis.com" />
25
+ <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
26
+ <link
27
+ href="https://fonts.googleapis.com/css2?family=Geist:wght@400;500;600&family=Geist+Mono:wght@400;500&display=swap"
28
+ rel="stylesheet"
29
+ />
30
+ ```
31
+
32
+ **2. CSS** — pick one:
33
+
34
+ ```css
35
+ /* a) No Tailwind in your app: one precompiled sheet (tokens + base + every utility the components use) */
36
+ @import '@craftzbay/ui/styles.css';
37
+
38
+ /* b) Your app already uses Tailwind v4: share the tokens and let Tailwind compile the library's classes */
39
+ @import 'tailwindcss';
40
+ @import '@craftzbay/ui/theme.css';
41
+ @source "../node_modules/@craftzbay/ui/dist-lib";
42
+ ```
43
+
44
+ **3. Dark mode** — toggle the `dark` class on `<html>`; every token flips. Set it before first paint to avoid a flash.
45
+
46
+ **4. Providers** — `<Toaster />` once near the root if you use `toast()`; wrap the app in `<TooltipProvider>` if you use `Tooltip`. Nothing else is required.
47
+
21
48
  ```tsx
22
- import { Button, Dialog, Toast } from '@craftzbay/ui';
23
- import '@craftzbay/ui/styles.css';
49
+ import { Button, Toaster, TooltipProvider, toast } from '@craftzbay/ui';
24
50
 
25
51
  export function App() {
26
- return <Button variant="primary">Save</Button>;
52
+ return (
53
+ <TooltipProvider>
54
+ <Button onClick={() => toast({ title: 'Saved' })}>Save</Button>
55
+ <Toaster />
56
+ </TooltipProvider>
57
+ );
27
58
  }
28
59
  ```
29
60
 
30
- Peer dependencies: `react@>=18`, `react-dom@>=18`.
61
+ **Next.js App Router** — components use hooks/context, so import them from a file marked `'use client'` (or re-export the ones you need from a local `components/ui.ts` with that directive). Put the CSS import and fonts in `app/layout.tsx`.
62
+
63
+ **Name-addressed icons** — `Icons.*` (curated, tree-shaken) ships in the main entry. The lazy `<Icon name="…">` + `iconNames` list lives in a separate entry so its ~1500-icon import map never enters your bundle unless asked for:
64
+
65
+ ```tsx
66
+ import { Icon } from '@craftzbay/ui/icon';
67
+ <Icon name="calendar" className="size-4" />;
68
+ ```
69
+
70
+ The package is ESM-only, ships one module per component (`sideEffects` limited to CSS), so `import { Button }` pulls in about 8 KB gzipped — no calendar, drawer, or form dependencies.
71
+
72
+ ## Localisation (Mongolian built in)
73
+
74
+ Every built-in string (close/dismiss labels, placeholders, "No results.", pagination summary, error-state copy…) is typed in `UiStrings` and read through `useStrings()`. Defaults are English; a full Mongolian set ships as `mnStrings`.
75
+
76
+ ```tsx
77
+ import { DesignSystemProvider, mnStrings } from '@craftzbay/ui';
78
+ <DesignSystemProvider strings={mnStrings}>…</DesignSystemProvider>; // whole library in Mongolian
79
+ <DesignSystemProvider strings={{ dialog: { close: 'Schließen' } }}>…</DesignSystemProvider>; // partial override, deep-merged over defaults
80
+ ```
81
+
82
+ Precedence is per-component props (`placeholder`, `labels`, `aria-label`) → nearest provider → `defaultStrings`. Templates use `{name}` placeholders, e.g. `pagination.showing: '{from}–{to} / {total}'`.
83
+
84
+ ## Design rules
85
+
86
+ This library implements the [craftzbay design-research](https://github.com/craftzbay/design-research) guidelines
87
+ ([rendered site](https://craftzbay.github.io/design-research/)) — colour, type, spacing, components, accessibility, tokens.
88
+ The library-specific distillation is [`docs/PHILOSOPHY.md`](./docs/PHILOSOPHY.md).
31
89
 
32
90
  ## Local development
33
91
 
@@ -47,7 +105,7 @@ Inside `packages/ui` itself, `pnpm build` produces the distributable bundle and
47
105
  ## Tech stack
48
106
 
49
107
  - **Tailwind CSS v4** — tokens defined in `@theme` in `src/styles/globals.css`
50
- - **React 18** + **TypeScript 5.7**
108
+ - **React 18 / 19** + **TypeScript 5.7**
51
109
  - **Radix UI** primitives for accessibility-correct overlays
52
110
  - **class-variance-authority** + `cn()` (`clsx` + `tailwind-merge`)
53
111
  - **Lucide** icons (16 / 20px, 1.5 stroke)
@@ -78,6 +136,7 @@ docs/
78
136
  ## Component index
79
137
 
80
138
  ### Inputs
139
+
81
140
  - [Input](./src/components/ui/Input.tsx) — text / email / password / number / search with prefix, suffix, error
82
141
  - [Textarea](./src/components/ui/Textarea.tsx) — auto-resize multi-line input
83
142
  - [Select](./src/components/ui/Select.tsx) — single-choice menu (Radix)
@@ -91,11 +150,13 @@ docs/
91
150
  - [Form primitives](./src/components/ui/Form.tsx) — react-hook-form bindings
92
151
 
93
152
  ### Buttons
153
+
94
154
  - [Button](./src/components/ui/Button.tsx) — primary · secondary · outline · ghost · destructive · link
95
155
  - [IconButton](./src/components/ui/IconButton.tsx) — square icon-only variant
96
156
  - [Pagination](./src/components/ui/Pagination.tsx) — numbered + jumps + page-size
97
157
 
98
158
  ### Feedback
159
+
99
160
  - [Alert](./src/components/ui/Alert.tsx) — inline banner, dismissible
100
161
  - [Toast](./src/components/ui/Toast.tsx) + `useToast` hook
101
162
  - [Spinner](./src/components/ui/Spinner.tsx) — accent / neutral / on-accent tones
@@ -105,6 +166,7 @@ docs/
105
166
  - [ErrorState](./src/components/ui/ErrorState.tsx) — 404 / 500 / generic
106
167
 
107
168
  ### Navigation
169
+
108
170
  - [TopNav](./src/components/ui/TopNav.tsx) + `TopNavLink`
109
171
  - [Sidebar](./src/components/ui/Sidebar.tsx) + `SidebarSection` + `SidebarItem` + `SidebarGroup`
110
172
  - [Breadcrumbs](./src/components/ui/Breadcrumbs.tsx) — with overflow ellipsis
@@ -112,12 +174,14 @@ docs/
112
174
  - [Stepper](./src/components/ui/Stepper.tsx) — horizontal + vertical
113
175
 
114
176
  ### Layout
177
+
115
178
  - [Card](./src/components/ui/Card.tsx) + `CardHeader/Title/Description/Content/Footer`
116
179
  - [Separator](./src/components/ui/Separator.tsx)
117
180
  - [ScrollArea](./src/components/ui/ScrollArea.tsx) — Radix-backed styled scroll
118
181
  - [Accordion](./src/components/ui/Accordion.tsx) — single + multiple
119
182
 
120
183
  ### Overlays
184
+
121
185
  - [Dialog](./src/components/ui/Dialog.tsx) + `ConfirmationDialog`
122
186
  - [Sheet](./src/components/ui/Sheet.tsx) — left / right / top / bottom
123
187
  - [Popover](./src/components/ui/Popover.tsx)
@@ -127,12 +191,14 @@ docs/
127
191
  - [CommandPalette](./src/components/ui/CommandPalette.tsx) — ⌘K palette
128
192
 
129
193
  ### Data display
194
+
130
195
  - [Table](./src/components/ui/Table.tsx) + `TableSortHeader`
131
196
  - [DataGrid](./src/components/ui/DataGrid.tsx) — column visibility, filter, sortable
132
197
  - [Badge](./src/components/ui/Badge.tsx) — subtle + outline, 6 tones
133
198
  - [Avatar](./src/components/ui/Avatar.tsx) + `AvatarGroup`
134
199
 
135
200
  ### Typography
201
+
136
202
  - [Kbd](./src/components/ui/Kbd.tsx) — keyboard shortcut indicator
137
203
 
138
204
  ## Blocks (page templates)
@@ -0,0 +1,60 @@
1
+ "use client";
2
+ import { jsx as t, jsxs as d } from "react/jsx-runtime";
3
+ import { forwardRef as a } from "react";
4
+ import * as n from "@radix-ui/react-accordion";
5
+ import { ChevronDown as m } from "../../icons/index.js";
6
+ import { cn as i } from "../../lib/utils.js";
7
+ const v = n.Root, f = a(function({ className: o, ...e }, r) {
8
+ return /* @__PURE__ */ t(n.Item, { ref: r, className: i("border-b border-border", o), ...e });
9
+ });
10
+ f.displayName = "AccordionItem";
11
+ const l = a(function({ className: o, children: e, ...r }, c) {
12
+ return /* @__PURE__ */ t(n.Header, { className: "flex", children: /* @__PURE__ */ d(
13
+ n.Trigger,
14
+ {
15
+ ref: c,
16
+ className: i(
17
+ "flex flex-1 items-center justify-between gap-2 py-4 text-left text-sm font-medium text-foreground",
18
+ "outline-none transition-colors duration-[var(--duration-fast)]",
19
+ "hover:text-accent",
20
+ "focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background",
21
+ "[&[data-state=open]>svg]:rotate-180",
22
+ o
23
+ ),
24
+ ...r,
25
+ children: [
26
+ e,
27
+ /* @__PURE__ */ t(
28
+ m,
29
+ {
30
+ className: "size-4 shrink-0 text-foreground-subtle transition-transform duration-[var(--duration-base)]",
31
+ "aria-hidden": !0
32
+ }
33
+ )
34
+ ]
35
+ }
36
+ ) });
37
+ });
38
+ l.displayName = "AccordionTrigger";
39
+ const u = a(function({ className: o, children: e, ...r }, c) {
40
+ return /* @__PURE__ */ t(
41
+ n.Content,
42
+ {
43
+ ref: c,
44
+ className: i(
45
+ "overflow-hidden text-sm text-foreground-muted",
46
+ "data-[state=closed]:animate-accordion-up data-[state=open]:animate-accordion-down"
47
+ ),
48
+ ...r,
49
+ children: /* @__PURE__ */ t("div", { className: i("pb-4 pt-0", o), children: e })
50
+ }
51
+ );
52
+ });
53
+ u.displayName = "AccordionContent";
54
+ export {
55
+ v as Accordion,
56
+ u as AccordionContent,
57
+ f as AccordionItem,
58
+ l as AccordionTrigger
59
+ };
60
+ //# sourceMappingURL=Accordion.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Accordion.js","sources":["../../../src/components/ui/Accordion.tsx"],"sourcesContent":["'use client';\n\nimport {\n forwardRef,\n type ComponentPropsWithoutRef,\n type ElementRef,\n} from 'react';\nimport * as AccordionPrimitive from '@radix-ui/react-accordion';\nimport { ChevronDown } from '@/icons';\nimport { cn } from '@/lib/utils';\n\n/**\n * Accessible disclosure list. Supports single (`type=\"single\"`) and multiple\n * (`type=\"multiple\"`) open behaviour — both come from Radix.\n *\n * @example FAQ\n * <Accordion type=\"single\" collapsible>\n * <AccordionItem value=\"q1\">\n * <AccordionTrigger>Can I cancel anytime?</AccordionTrigger>\n * <AccordionContent>Yes — usage stops at the end of the billing period.</AccordionContent>\n * </AccordionItem>\n * …\n * </Accordion>\n *\n * @do Use for FAQs, settings groups, and progressive-disclosure forms.\n * @dont Nest accordions inside accordions — the focus order becomes opaque.\n */\nexport const Accordion = AccordionPrimitive.Root;\n\nexport const AccordionItem = forwardRef<\n ElementRef<typeof AccordionPrimitive.Item>,\n ComponentPropsWithoutRef<typeof AccordionPrimitive.Item>\n>(function AccordionItem({ className, ...props }, ref) {\n return (\n <AccordionPrimitive.Item ref={ref} className={cn('border-b border-border', className)} {...props} />\n );\n});\nAccordionItem.displayName = 'AccordionItem';\n\nexport const AccordionTrigger = forwardRef<\n ElementRef<typeof AccordionPrimitive.Trigger>,\n ComponentPropsWithoutRef<typeof AccordionPrimitive.Trigger>\n>(function AccordionTrigger({ className, children, ...props }, ref) {\n return (\n <AccordionPrimitive.Header className=\"flex\">\n <AccordionPrimitive.Trigger\n ref={ref}\n className={cn(\n 'flex flex-1 items-center justify-between gap-2 py-4 text-left text-sm font-medium text-foreground',\n 'outline-none transition-colors duration-[var(--duration-fast)]',\n 'hover:text-accent',\n 'focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background',\n '[&[data-state=open]>svg]:rotate-180',\n className,\n )}\n {...props}\n >\n {children}\n <ChevronDown\n className=\"size-4 shrink-0 text-foreground-subtle transition-transform duration-[var(--duration-base)]\"\n aria-hidden\n />\n </AccordionPrimitive.Trigger>\n </AccordionPrimitive.Header>\n );\n});\nAccordionTrigger.displayName = 'AccordionTrigger';\n\nexport const AccordionContent = forwardRef<\n ElementRef<typeof AccordionPrimitive.Content>,\n ComponentPropsWithoutRef<typeof AccordionPrimitive.Content>\n>(function AccordionContent({ className, children, ...props }, ref) {\n return (\n <AccordionPrimitive.Content\n ref={ref}\n className={cn(\n 'overflow-hidden text-sm text-foreground-muted',\n 'data-[state=closed]:animate-accordion-up data-[state=open]:animate-accordion-down',\n )}\n {...props}\n >\n <div className={cn('pb-4 pt-0', className)}>{children}</div>\n </AccordionPrimitive.Content>\n );\n});\nAccordionContent.displayName = 'AccordionContent';\n"],"names":["Accordion","AccordionPrimitive","AccordionItem","forwardRef","className","props","ref","jsx","cn","AccordionTrigger","children","jsxs","ChevronDown","AccordionContent"],"mappings":";;;;;;AA2BO,MAAMA,IAAYC,EAAmB,MAE/BC,IAAgBC,EAG3B,SAAuB,EAAE,WAAAC,GAAW,GAAGC,EAAA,GAASC,GAAK;AACrD,SACE,gBAAAC,EAACN,EAAmB,MAAnB,EAAwB,KAAAK,GAAU,WAAWE,EAAG,0BAA0BJ,CAAS,GAAI,GAAGC,EAAA,CAAO;AAEtG,CAAC;AACDH,EAAc,cAAc;AAErB,MAAMO,IAAmBN,EAG9B,SAA0B,EAAE,WAAAC,GAAW,UAAAM,GAAU,GAAGL,EAAA,GAASC,GAAK;AAClE,SACE,gBAAAC,EAACN,EAAmB,QAAnB,EAA0B,WAAU,QACnC,UAAA,gBAAAU;AAAA,IAACV,EAAmB;AAAA,IAAnB;AAAA,MACC,KAAAK;AAAA,MACA,WAAWE;AAAA,QACT;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACAJ;AAAA,MAAA;AAAA,MAED,GAAGC;AAAA,MAEH,UAAA;AAAA,QAAAK;AAAA,QACD,gBAAAH;AAAA,UAACK;AAAA,UAAA;AAAA,YACC,WAAU;AAAA,YACV,eAAW;AAAA,UAAA;AAAA,QAAA;AAAA,MACb;AAAA,IAAA;AAAA,EAAA,GAEJ;AAEJ,CAAC;AACDH,EAAiB,cAAc;AAExB,MAAMI,IAAmBV,EAG9B,SAA0B,EAAE,WAAAC,GAAW,UAAAM,GAAU,GAAGL,EAAA,GAASC,GAAK;AAClE,SACE,gBAAAC;AAAA,IAACN,EAAmB;AAAA,IAAnB;AAAA,MACC,KAAAK;AAAA,MACA,WAAWE;AAAA,QACT;AAAA,QACA;AAAA,MAAA;AAAA,MAED,GAAGH;AAAA,MAEJ,4BAAC,OAAA,EAAI,WAAWG,EAAG,aAAaJ,CAAS,GAAI,UAAAM,EAAA,CAAS;AAAA,IAAA;AAAA,EAAA;AAG5D,CAAC;AACDG,EAAiB,cAAc;"}
@@ -1,5 +1,5 @@
1
1
  import { HTMLAttributes, ReactNode } from 'react';
2
- import { VariantProps } from '../../lib/cva';
2
+ import { VariantProps } from '../../lib/cva.js';
3
3
  declare const alert: (props?: ({
4
4
  variant?: "default" | "success" | "warning" | "danger" | "info" | null | undefined;
5
5
  } & import('class-variance-authority/types').ClassProp) | undefined) => string;
@@ -0,0 +1,66 @@
1
+ "use client";
2
+ import { jsxs as a, jsx as e } from "react/jsx-runtime";
3
+ import { forwardRef as x, useState as p } from "react";
4
+ import { X as v, XCircle as N, AlertTriangle as k, CheckCircle2 as w, Info as z } from "../../icons/index.js";
5
+ import { cn as i } from "../../lib/utils.js";
6
+ import { useStrings as A } from "../../hooks/use-strings.js";
7
+ import { cva as C } from "class-variance-authority";
8
+ const j = C(["relative flex w-full gap-3 rounded-lg border p-4", "text-sm"], {
9
+ variants: {
10
+ variant: {
11
+ default: "border-border bg-background-subtle text-foreground",
12
+ info: "border-info-border-soft bg-info-soft text-info-text",
13
+ success: "border-success-border-soft bg-success-soft text-success-text",
14
+ warning: "border-warning-border-soft bg-warning-soft text-warning-text",
15
+ danger: "border-danger-border-soft bg-danger-soft text-danger-text"
16
+ }
17
+ },
18
+ defaultVariants: { variant: "default" }
19
+ }), y = {
20
+ default: null,
21
+ info: /* @__PURE__ */ e(z, { className: "mt-0.5 size-4 shrink-0", "aria-hidden": !0 }),
22
+ success: /* @__PURE__ */ e(w, { className: "mt-0.5 size-4 shrink-0", "aria-hidden": !0 }),
23
+ warning: /* @__PURE__ */ e(k, { className: "mt-0.5 size-4 shrink-0", "aria-hidden": !0 }),
24
+ danger: /* @__PURE__ */ e(N, { className: "mt-0.5 size-4 shrink-0", "aria-hidden": !0 })
25
+ }, I = x(function({ className: o, variant: r = "default", title: s, dismissible: l, onDismiss: t, icon: n, children: d, ...c }, f) {
26
+ const u = A(), [g, m] = p(!0);
27
+ if (!g) return null;
28
+ const b = () => {
29
+ m(!1), t == null || t();
30
+ }, h = n === !1 ? null : n ?? y[r ?? "default"];
31
+ return /* @__PURE__ */ a(
32
+ "div",
33
+ {
34
+ ref: f,
35
+ role: r === "danger" ? "alert" : "status",
36
+ className: i(j({ variant: r }), o),
37
+ ...c,
38
+ children: [
39
+ h,
40
+ /* @__PURE__ */ a("div", { className: "min-w-0 flex-1", children: [
41
+ s && /* @__PURE__ */ e("h5", { className: "mb-1 leading-tight font-medium", children: s }),
42
+ /* @__PURE__ */ e("div", { className: "text-sm leading-relaxed [&_p]:leading-relaxed", children: d })
43
+ ] }),
44
+ l && /* @__PURE__ */ e(
45
+ "button",
46
+ {
47
+ type: "button",
48
+ "aria-label": u.alert.dismiss,
49
+ onClick: b,
50
+ className: i(
51
+ "inline-flex size-6 shrink-0 items-center justify-center rounded-md",
52
+ "outline-none hover:bg-current/10",
53
+ "focus-visible:ring-ring focus-visible:ring-offset-background focus-visible:ring-2 focus-visible:ring-offset-2"
54
+ ),
55
+ children: /* @__PURE__ */ e(v, { className: "size-3.5", "aria-hidden": !0 })
56
+ }
57
+ )
58
+ ]
59
+ }
60
+ );
61
+ });
62
+ I.displayName = "Alert";
63
+ export {
64
+ I as Alert
65
+ };
66
+ //# sourceMappingURL=Alert.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Alert.js","sources":["../../../src/components/ui/Alert.tsx"],"sourcesContent":["'use client';\n\nimport { forwardRef, useState, type HTMLAttributes, type ReactNode } from 'react';\nimport { AlertTriangle, CheckCircle2, Info, X, XCircle } from '@/icons';\nimport { cn } from '@/lib/utils';\nimport { useStrings } from '@/hooks/use-strings';\nimport { cva, type VariantProps } from '@/lib/cva';\n\nconst alert = cva(['relative flex w-full gap-3 rounded-lg border p-4', 'text-sm'], {\n variants: {\n variant: {\n default: 'border-border bg-background-subtle text-foreground',\n info: 'border-info-border-soft bg-info-soft text-info-text',\n success: 'border-success-border-soft bg-success-soft text-success-text',\n warning: 'border-warning-border-soft bg-warning-soft text-warning-text',\n danger: 'border-danger-border-soft bg-danger-soft text-danger-text',\n },\n },\n defaultVariants: { variant: 'default' },\n});\n\nconst iconForVariant = {\n default: null,\n info: <Info className=\"mt-0.5 size-4 shrink-0\" aria-hidden />,\n success: <CheckCircle2 className=\"mt-0.5 size-4 shrink-0\" aria-hidden />,\n warning: <AlertTriangle className=\"mt-0.5 size-4 shrink-0\" aria-hidden />,\n danger: <XCircle className=\"mt-0.5 size-4 shrink-0\" aria-hidden />,\n};\n\nexport interface AlertProps\n extends Omit<HTMLAttributes<HTMLDivElement>, 'title'>, VariantProps<typeof alert> {\n /** Heading. Renders bold above the description. */\n title?: ReactNode;\n /** Show a dismiss (×) button. */\n dismissible?: boolean;\n /** Called when the user dismisses. */\n onDismiss?: () => void;\n /** Override the variant's default icon. Pass `false` to suppress the icon. */\n icon?: ReactNode | false;\n}\n\n/**\n * Inline banner for static page-level or section-level state. For transient\n * notifications use `Toast` instead.\n *\n * @example Inline error\n * <Alert variant=\"danger\" title=\"Payment failed\">\n * Your card was declined. Update your billing info to retry.\n * </Alert>\n *\n * @example Dismissible info\n * <Alert variant=\"info\" dismissible onDismiss={dismiss}>\n * We're improving search — give us feedback at #search-feedback.\n * </Alert>\n *\n * @do Use the closest semantic variant — `info` for neutral facts,\n * `warning` for \"watch out\", `danger` for \"this is broken\".\n * @dont Use Alert for one-time confirmations — that's Toast.\n */\nexport const Alert = forwardRef<HTMLDivElement, AlertProps>(function Alert(\n { className, variant = 'default', title, dismissible, onDismiss, icon, children, ...props },\n ref,\n) {\n const strings = useStrings();\n const [open, setOpen] = useState(true);\n if (!open) return null;\n\n const handleDismiss = () => {\n setOpen(false);\n onDismiss?.();\n };\n\n const renderedIcon = icon === false ? null : (icon ?? iconForVariant[variant ?? 'default']);\n\n return (\n <div\n ref={ref}\n // Only errors interrupt the screen reader; everything else is polite.\n role={variant === 'danger' ? 'alert' : 'status'}\n className={cn(alert({ variant }), className)}\n {...props}\n >\n {renderedIcon}\n <div className=\"min-w-0 flex-1\">\n {title && <h5 className=\"mb-1 leading-tight font-medium\">{title}</h5>}\n <div className=\"text-sm leading-relaxed [&_p]:leading-relaxed\">{children}</div>\n </div>\n {dismissible && (\n <button\n type=\"button\"\n aria-label={strings.alert.dismiss}\n onClick={handleDismiss}\n className={cn(\n 'inline-flex size-6 shrink-0 items-center justify-center rounded-md',\n 'outline-none hover:bg-current/10',\n 'focus-visible:ring-ring focus-visible:ring-offset-background focus-visible:ring-2 focus-visible:ring-offset-2',\n )}\n >\n <X className=\"size-3.5\" aria-hidden />\n </button>\n )}\n </div>\n );\n});\nAlert.displayName = 'Alert';\n"],"names":["alert","cva","iconForVariant","jsx","Info","CheckCircle2","AlertTriangle","XCircle","Alert","forwardRef","className","variant","title","dismissible","onDismiss","icon","children","props","ref","strings","useStrings","open","setOpen","useState","handleDismiss","renderedIcon","jsxs","cn","X"],"mappings":";;;;;;;AAQA,MAAMA,IAAQC,EAAI,CAAC,oDAAoD,SAAS,GAAG;AAAA,EACjF,UAAU;AAAA,IACR,SAAS;AAAA,MACP,SAAS;AAAA,MACT,MAAM;AAAA,MACN,SAAS;AAAA,MACT,SAAS;AAAA,MACT,QAAQ;AAAA,IAAA;AAAA,EACV;AAAA,EAEF,iBAAiB,EAAE,SAAS,UAAA;AAC9B,CAAC,GAEKC,IAAiB;AAAA,EACrB,SAAS;AAAA,EACT,MAAM,gBAAAC,EAACC,GAAA,EAAK,WAAU,0BAAyB,eAAW,IAAC;AAAA,EAC3D,SAAS,gBAAAD,EAACE,GAAA,EAAa,WAAU,0BAAyB,eAAW,IAAC;AAAA,EACtE,SAAS,gBAAAF,EAACG,GAAA,EAAc,WAAU,0BAAyB,eAAW,IAAC;AAAA,EACvE,QAAQ,gBAAAH,EAACI,GAAA,EAAQ,WAAU,0BAAyB,eAAW,GAAA,CAAC;AAClE,GAgCaC,IAAQC,EAAuC,SAC1D,EAAE,WAAAC,GAAW,SAAAC,IAAU,WAAW,OAAAC,GAAO,aAAAC,GAAa,WAAAC,GAAW,MAAAC,GAAM,UAAAC,GAAU,GAAGC,EAAA,GACpFC,GACA;AACA,QAAMC,IAAUC,EAAA,GACV,CAACC,GAAMC,CAAO,IAAIC,EAAS,EAAI;AACrC,MAAI,CAACF,EAAM,QAAO;AAElB,QAAMG,IAAgB,MAAM;AAC1B,IAAAF,EAAQ,EAAK,GACbR,KAAA,QAAAA;AAAA,EACF,GAEMW,IAAeV,MAAS,KAAQ,OAAQA,KAAQb,EAAeS,KAAW,SAAS;AAEzF,SACE,gBAAAe;AAAA,IAAC;AAAA,IAAA;AAAA,MACC,KAAAR;AAAA,MAEA,MAAMP,MAAY,WAAW,UAAU;AAAA,MACvC,WAAWgB,EAAG3B,EAAM,EAAE,SAAAW,EAAA,CAAS,GAAGD,CAAS;AAAA,MAC1C,GAAGO;AAAA,MAEH,UAAA;AAAA,QAAAQ;AAAA,QACD,gBAAAC,EAAC,OAAA,EAAI,WAAU,kBACZ,UAAA;AAAA,UAAAd,KAAS,gBAAAT,EAAC,MAAA,EAAG,WAAU,kCAAkC,UAAAS,GAAM;AAAA,UAChE,gBAAAT,EAAC,OAAA,EAAI,WAAU,iDAAiD,UAAAa,EAAA,CAAS;AAAA,QAAA,GAC3E;AAAA,QACCH,KACC,gBAAAV;AAAA,UAAC;AAAA,UAAA;AAAA,YACC,MAAK;AAAA,YACL,cAAYgB,EAAQ,MAAM;AAAA,YAC1B,SAASK;AAAA,YACT,WAAWG;AAAA,cACT;AAAA,cACA;AAAA,cACA;AAAA,YAAA;AAAA,YAGF,UAAA,gBAAAxB,EAACyB,GAAA,EAAE,WAAU,YAAW,eAAW,GAAA,CAAC;AAAA,UAAA;AAAA,QAAA;AAAA,MACtC;AAAA,IAAA;AAAA,EAAA;AAIR,CAAC;AACDpB,EAAM,cAAc;"}
@@ -1,8 +1,8 @@
1
1
  import { ComponentPropsWithoutRef, HTMLAttributes, ReactNode } from 'react';
2
- import { VariantProps } from '../../lib/cva';
2
+ import { VariantProps } from '../../lib/cva.js';
3
3
  import * as AvatarPrimitive from '@radix-ui/react-avatar';
4
4
  declare const sizeMap: {
5
- readonly xs: "size-5 text-[10px]";
5
+ readonly xs: "size-5 text-xs";
6
6
  readonly sm: "size-6 text-xs";
7
7
  readonly md: "size-8 text-xs";
8
8
  readonly lg: "size-10 text-sm";
@@ -0,0 +1,96 @@
1
+ "use client";
2
+ import { jsxs as n, jsx as i } from "react/jsx-runtime";
3
+ import { forwardRef as g } from "react";
4
+ import * as f from "@radix-ui/react-avatar";
5
+ import { cn as o } from "../../lib/utils.js";
6
+ import { useStrings as b } from "../../hooks/use-strings.js";
7
+ import { formatString as p } from "../../lib/strings.js";
8
+ import { cva as N } from "class-variance-authority";
9
+ const v = {
10
+ xs: "size-5 text-xs",
11
+ sm: "size-6 text-xs",
12
+ md: "size-8 text-xs",
13
+ lg: "size-10 text-sm",
14
+ xl: "size-12 text-base"
15
+ }, h = N("relative inline-flex shrink-0", {
16
+ variants: { size: v },
17
+ defaultVariants: { size: "md" }
18
+ }), y = {
19
+ online: "bg-success",
20
+ busy: "bg-danger",
21
+ away: "bg-warning",
22
+ offline: "bg-foreground-subtle"
23
+ }, A = g(
24
+ function({ className: l, size: m, src: e, alt: r, fallback: c, status: a, ...u }, t) {
25
+ const s = b();
26
+ return /* @__PURE__ */ n("span", { className: h({ size: m }), children: [
27
+ /* @__PURE__ */ n(
28
+ f.Root,
29
+ {
30
+ ref: t,
31
+ className: o(
32
+ "block size-full overflow-hidden rounded-full bg-background-muted text-foreground-muted",
33
+ l
34
+ ),
35
+ ...u,
36
+ children: [
37
+ e && /* @__PURE__ */ i(
38
+ f.Image,
39
+ {
40
+ src: e,
41
+ alt: r ?? "",
42
+ className: "aspect-square size-full object-cover"
43
+ }
44
+ ),
45
+ /* @__PURE__ */ i(
46
+ f.Fallback,
47
+ {
48
+ delayMs: e ? 200 : 0,
49
+ className: "flex size-full items-center justify-center bg-background-muted font-medium uppercase",
50
+ children: c ?? "?"
51
+ }
52
+ )
53
+ ]
54
+ }
55
+ ),
56
+ a && /* @__PURE__ */ i(
57
+ "span",
58
+ {
59
+ "aria-label": p(s.avatar.status, { status: a }),
60
+ className: o(
61
+ "absolute bottom-0 right-0 block size-[28%] rounded-full ring-2 ring-background",
62
+ y[a]
63
+ )
64
+ }
65
+ )
66
+ ] });
67
+ }
68
+ );
69
+ A.displayName = "Avatar";
70
+ const j = g(function({ max: l = 4, size: m = "md", className: e, children: r, ...c }, a) {
71
+ const u = b(), t = Array.isArray(r) ? r : [r], s = t.slice(0, l), d = t.length - s.length;
72
+ return /* @__PURE__ */ n("div", { ref: a, className: o("flex items-center -space-x-2", e), ...c, children: [
73
+ s.map((z, k) => /* @__PURE__ */ i("div", { className: "ring-2 ring-background rounded-full", children: z }, k)),
74
+ d > 0 && /* @__PURE__ */ n(
75
+ "div",
76
+ {
77
+ className: o(
78
+ "inline-flex items-center justify-center rounded-full bg-background-muted text-foreground-muted ring-2 ring-background",
79
+ v[m],
80
+ "font-medium"
81
+ ),
82
+ "aria-label": p(u.avatar.more, { n: d }),
83
+ children: [
84
+ "+",
85
+ d
86
+ ]
87
+ }
88
+ )
89
+ ] });
90
+ });
91
+ j.displayName = "AvatarGroup";
92
+ export {
93
+ A as Avatar,
94
+ j as AvatarGroup
95
+ };
96
+ //# sourceMappingURL=Avatar.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Avatar.js","sources":["../../../src/components/ui/Avatar.tsx"],"sourcesContent":["'use client';\n\nimport {\n forwardRef,\n type ComponentPropsWithoutRef,\n type ElementRef,\n type HTMLAttributes,\n type ReactNode,\n} from 'react';\nimport * as AvatarPrimitive from '@radix-ui/react-avatar';\nimport { cn } from '@/lib/utils';\nimport { useStrings } from '@/hooks/use-strings';\nimport { formatString } from '@/lib/strings';\nimport { cva, type VariantProps } from '@/lib/cva';\n\nconst sizeMap = {\n xs: 'size-5 text-xs',\n sm: 'size-6 text-xs',\n md: 'size-8 text-xs',\n lg: 'size-10 text-sm',\n xl: 'size-12 text-base',\n} as const;\n\n// The wrapper sets size — Root sits inside and clips image/fallback only.\nconst avatarWrapper = cva('relative inline-flex shrink-0', {\n variants: { size: sizeMap },\n defaultVariants: { size: 'md' },\n});\n\nexport interface AvatarProps\n extends ComponentPropsWithoutRef<typeof AvatarPrimitive.Root>,\n VariantProps<typeof avatarWrapper> {\n /** Image URL. If absent or fails to load, fallback initials are shown. */\n src?: string;\n /** Alt text for the image; falls back to fallback when there's no `src`. */\n alt?: string;\n /** Initials shown when image is missing or loading. Pass at most 2 characters. */\n fallback?: string;\n /** Status dot rendered on the bottom-right. */\n status?: 'online' | 'busy' | 'away' | 'offline';\n}\n\nconst statusColour: Record<NonNullable<AvatarProps['status']>, string> = {\n online: 'bg-success',\n busy: 'bg-danger',\n away: 'bg-warning',\n offline: 'bg-foreground-subtle',\n};\n\n/**\n * Avatar with image, initials fallback, and optional status dot.\n *\n * @example\n * <Avatar src={user.photo} alt={user.name} fallback={getInitials(user.name)} status=\"online\" />\n *\n * @example AvatarGroup\n * <AvatarGroup max={3}>\n * {users.map(u => <Avatar key={u.id} src={u.photo} fallback={getInitials(u.name)} />)}\n * </AvatarGroup>\n *\n * @do Provide `alt` for image avatars and meaningful initials for the\n * fallback so screen readers announce something useful.\n * @dont Use the status dot without a tooltip explaining what it means.\n */\nexport const Avatar = forwardRef<ElementRef<typeof AvatarPrimitive.Root>, AvatarProps>(\n function Avatar({ className, size, src, alt, fallback, status, ...props }, ref) {\n const strings = useStrings();\n return (\n <span className={avatarWrapper({ size })}>\n <AvatarPrimitive.Root\n ref={ref}\n className={cn(\n 'block size-full overflow-hidden rounded-full bg-background-muted text-foreground-muted',\n className,\n )}\n {...props}\n >\n {src && (\n <AvatarPrimitive.Image\n src={src}\n alt={alt ?? ''}\n className=\"aspect-square size-full object-cover\"\n />\n )}\n <AvatarPrimitive.Fallback\n delayMs={src ? 200 : 0}\n className=\"flex size-full items-center justify-center bg-background-muted font-medium uppercase\"\n >\n {fallback ?? '?'}\n </AvatarPrimitive.Fallback>\n </AvatarPrimitive.Root>\n {status && (\n <span\n aria-label={formatString(strings.avatar.status, { status })}\n className={cn(\n 'absolute bottom-0 right-0 block size-[28%] rounded-full ring-2 ring-background',\n statusColour[status],\n )}\n />\n )}\n </span>\n );\n },\n);\nAvatar.displayName = 'Avatar';\n\nexport interface AvatarGroupProps extends HTMLAttributes<HTMLDivElement> {\n /** Maximum visible avatars before showing a \"+N\" overflow chip. */\n max?: number;\n /** Avatar size applied to children + overflow. */\n size?: keyof typeof sizeMap;\n /** Children — Avatars. */\n children: ReactNode;\n}\n\n/**\n * Overlapping avatars with overflow indicator. Pass plain `<Avatar>` children.\n */\nexport const AvatarGroup = forwardRef<HTMLDivElement, AvatarGroupProps>(function AvatarGroup(\n { max = 4, size = 'md', className, children, ...props },\n ref,\n) {\n const strings = useStrings();\n const items = Array.isArray(children) ? children : [children];\n const visible = items.slice(0, max);\n const overflow = items.length - visible.length;\n\n return (\n <div ref={ref} className={cn('flex items-center -space-x-2', className)} {...props}>\n {visible.map((child, i) => (\n <div key={i} className=\"ring-2 ring-background rounded-full\">\n {child}\n </div>\n ))}\n {overflow > 0 && (\n <div\n className={cn(\n 'inline-flex items-center justify-center rounded-full bg-background-muted text-foreground-muted ring-2 ring-background',\n sizeMap[size],\n 'font-medium',\n )}\n aria-label={formatString(strings.avatar.more, { n: overflow })}\n >\n +{overflow}\n </div>\n )}\n </div>\n );\n});\nAvatarGroup.displayName = 'AvatarGroup';\n"],"names":["sizeMap","avatarWrapper","cva","statusColour","Avatar","forwardRef","className","size","src","alt","fallback","status","props","ref","strings","useStrings","jsxs","AvatarPrimitive","cn","jsx","formatString","AvatarGroup","max","children","items","visible","overflow","child","i"],"mappings":";;;;;;;;AAeA,MAAMA,IAAU;AAAA,EACd,IAAI;AAAA,EACJ,IAAI;AAAA,EACJ,IAAI;AAAA,EACJ,IAAI;AAAA,EACJ,IAAI;AACN,GAGMC,IAAgBC,EAAI,iCAAiC;AAAA,EACzD,UAAU,EAAE,MAAMF,EAAA;AAAA,EAClB,iBAAiB,EAAE,MAAM,KAAA;AAC3B,CAAC,GAeKG,IAAmE;AAAA,EACvE,QAAQ;AAAA,EACR,MAAM;AAAA,EACN,MAAM;AAAA,EACN,SAAS;AACX,GAiBaC,IAASC;AAAA,EACpB,SAAgB,EAAE,WAAAC,GAAW,MAAAC,GAAM,KAAAC,GAAK,KAAAC,GAAK,UAAAC,GAAU,QAAAC,GAAQ,GAAGC,EAAA,GAASC,GAAK;AAC9E,UAAMC,IAAUC,EAAA;AAChB,6BACG,QAAA,EAAK,WAAWd,EAAc,EAAE,MAAAM,EAAA,CAAM,GACrC,UAAA;AAAA,MAAA,gBAAAS;AAAA,QAACC,EAAgB;AAAA,QAAhB;AAAA,UACC,KAAAJ;AAAA,UACA,WAAWK;AAAA,YACT;AAAA,YACAZ;AAAA,UAAA;AAAA,UAED,GAAGM;AAAA,UAEH,UAAA;AAAA,YAAAJ,KACC,gBAAAW;AAAA,cAACF,EAAgB;AAAA,cAAhB;AAAA,gBACC,KAAAT;AAAA,gBACA,KAAKC,KAAO;AAAA,gBACZ,WAAU;AAAA,cAAA;AAAA,YAAA;AAAA,YAGd,gBAAAU;AAAA,cAACF,EAAgB;AAAA,cAAhB;AAAA,gBACC,SAAST,IAAM,MAAM;AAAA,gBACrB,WAAU;AAAA,gBAET,UAAAE,KAAY;AAAA,cAAA;AAAA,YAAA;AAAA,UACf;AAAA,QAAA;AAAA,MAAA;AAAA,MAEDC,KACC,gBAAAQ;AAAA,QAAC;AAAA,QAAA;AAAA,UACC,cAAYC,EAAaN,EAAQ,OAAO,QAAQ,EAAE,QAAAH,GAAQ;AAAA,UAC1D,WAAWO;AAAA,YACT;AAAA,YACAf,EAAaQ,CAAM;AAAA,UAAA;AAAA,QACrB;AAAA,MAAA;AAAA,IACF,GAEJ;AAAA,EAEJ;AACF;AACAP,EAAO,cAAc;AAcd,MAAMiB,IAAchB,EAA6C,SACtE,EAAE,KAAAiB,IAAM,GAAG,MAAAf,IAAO,MAAM,WAAAD,GAAW,UAAAiB,GAAU,GAAGX,EAAA,GAChDC,GACA;AACA,QAAMC,IAAUC,EAAA,GACVS,IAAQ,MAAM,QAAQD,CAAQ,IAAIA,IAAW,CAACA,CAAQ,GACtDE,IAAUD,EAAM,MAAM,GAAGF,CAAG,GAC5BI,IAAWF,EAAM,SAASC,EAAQ;AAExC,SACE,gBAAAT,EAAC,SAAI,KAAAH,GAAU,WAAWK,EAAG,gCAAgCZ,CAAS,GAAI,GAAGM,GAC1E,UAAA;AAAA,IAAAa,EAAQ,IAAI,CAACE,GAAOC,MACnB,gBAAAT,EAAC,SAAY,WAAU,uCACpB,UAAAQ,EAAA,GADOC,CAEV,CACD;AAAA,IACAF,IAAW,KACV,gBAAAV;AAAA,MAAC;AAAA,MAAA;AAAA,QACC,WAAWE;AAAA,UACT;AAAA,UACAlB,EAAQO,CAAI;AAAA,UACZ;AAAA,QAAA;AAAA,QAEF,cAAYa,EAAaN,EAAQ,OAAO,MAAM,EAAE,GAAGY,GAAU;AAAA,QAC9D,UAAA;AAAA,UAAA;AAAA,UACGA;AAAA,QAAA;AAAA,MAAA;AAAA,IAAA;AAAA,EACJ,GAEJ;AAEJ,CAAC;AACDL,EAAY,cAAc;"}
@@ -1,5 +1,5 @@
1
1
  import { HTMLAttributes } from 'react';
2
- import { VariantProps } from '../../lib/cva';
2
+ import { VariantProps } from '../../lib/cva.js';
3
3
  declare const badge: (props?: ({
4
4
  variant?: "subtle" | "outline" | null | undefined;
5
5
  tone?: "success" | "warning" | "danger" | "info" | "neutral" | "accent" | null | undefined;
@@ -0,0 +1,67 @@
1
+ "use client";
2
+ import { jsxs as i, jsx as u } from "react/jsx-runtime";
3
+ import { forwardRef as l } from "react";
4
+ import { cn as e } from "../../lib/utils.js";
5
+ import { cva as d } from "class-variance-authority";
6
+ const g = d(
7
+ [
8
+ "inline-flex items-center gap-1 rounded-full px-2 py-0.5",
9
+ "text-xs font-medium whitespace-nowrap"
10
+ ],
11
+ {
12
+ variants: {
13
+ variant: {
14
+ subtle: "",
15
+ outline: "border bg-transparent"
16
+ },
17
+ tone: {
18
+ neutral: "",
19
+ accent: "",
20
+ success: "",
21
+ warning: "",
22
+ danger: "",
23
+ info: ""
24
+ }
25
+ },
26
+ compoundVariants: [
27
+ // Subtle — coloured fill + matching text.
28
+ { variant: "subtle", tone: "neutral", class: "bg-background-muted text-foreground-muted" },
29
+ { variant: "subtle", tone: "accent", class: "bg-accent-soft text-on-accent-soft" },
30
+ { variant: "subtle", tone: "success", class: "bg-success-soft text-success-text" },
31
+ { variant: "subtle", tone: "warning", class: "bg-warning-soft text-warning-text" },
32
+ { variant: "subtle", tone: "danger", class: "bg-danger-soft text-danger-text" },
33
+ { variant: "subtle", tone: "info", class: "bg-info-soft text-info-text" },
34
+ // Outline — coloured border + text, transparent fill.
35
+ { variant: "outline", tone: "neutral", class: "border-border text-foreground-muted" },
36
+ { variant: "outline", tone: "accent", class: "border-accent text-accent" },
37
+ { variant: "outline", tone: "success", class: "border-success-border-soft text-success-text" },
38
+ { variant: "outline", tone: "warning", class: "border-warning-border-soft text-warning-text" },
39
+ { variant: "outline", tone: "danger", class: "border-danger-border-soft text-danger-text" },
40
+ { variant: "outline", tone: "info", class: "border-info-border-soft text-info-text" }
41
+ ],
42
+ defaultVariants: { variant: "subtle", tone: "neutral" }
43
+ }
44
+ ), b = {
45
+ neutral: "bg-foreground-subtle",
46
+ accent: "bg-accent",
47
+ success: "bg-success",
48
+ warning: "bg-warning",
49
+ danger: "bg-danger",
50
+ info: "bg-info"
51
+ }, f = l(function({ className: n, variant: a, tone: t = "neutral", dot: r, children: s, ...o }, c) {
52
+ return /* @__PURE__ */ i("span", { ref: c, className: e(g({ variant: a, tone: t }), n), ...o, children: [
53
+ r && /* @__PURE__ */ u(
54
+ "span",
55
+ {
56
+ "aria-hidden": !0,
57
+ className: e("inline-block size-1.5 rounded-full", b[t ?? "neutral"])
58
+ }
59
+ ),
60
+ s
61
+ ] });
62
+ });
63
+ f.displayName = "Badge";
64
+ export {
65
+ f as Badge
66
+ };
67
+ //# sourceMappingURL=Badge.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Badge.js","sources":["../../../src/components/ui/Badge.tsx"],"sourcesContent":["'use client';\n\nimport { forwardRef, type HTMLAttributes } from 'react';\nimport { cn } from '@/lib/utils';\nimport { cva, type VariantProps } from '@/lib/cva';\n\nconst badge = cva(\n [\n 'inline-flex items-center gap-1 rounded-full px-2 py-0.5',\n 'text-xs font-medium whitespace-nowrap',\n ],\n {\n variants: {\n variant: {\n subtle: '',\n outline: 'border bg-transparent',\n },\n tone: {\n neutral: '',\n accent: '',\n success: '',\n warning: '',\n danger: '',\n info: '',\n },\n },\n compoundVariants: [\n // Subtle — coloured fill + matching text.\n { variant: 'subtle', tone: 'neutral', class: 'bg-background-muted text-foreground-muted' },\n { variant: 'subtle', tone: 'accent', class: 'bg-accent-soft text-on-accent-soft' },\n { variant: 'subtle', tone: 'success', class: 'bg-success-soft text-success-text' },\n { variant: 'subtle', tone: 'warning', class: 'bg-warning-soft text-warning-text' },\n { variant: 'subtle', tone: 'danger', class: 'bg-danger-soft text-danger-text' },\n { variant: 'subtle', tone: 'info', class: 'bg-info-soft text-info-text' },\n // Outline — coloured border + text, transparent fill.\n { variant: 'outline', tone: 'neutral', class: 'border-border text-foreground-muted' },\n { variant: 'outline', tone: 'accent', class: 'border-accent text-accent' },\n { variant: 'outline', tone: 'success', class: 'border-success-border-soft text-success-text' },\n { variant: 'outline', tone: 'warning', class: 'border-warning-border-soft text-warning-text' },\n { variant: 'outline', tone: 'danger', class: 'border-danger-border-soft text-danger-text' },\n { variant: 'outline', tone: 'info', class: 'border-info-border-soft text-info-text' },\n ],\n defaultVariants: { variant: 'subtle', tone: 'neutral' },\n },\n);\n\nexport interface BadgeProps\n extends HTMLAttributes<HTMLSpanElement>,\n VariantProps<typeof badge> {\n /** Show a leading status dot in the same tone. */\n dot?: boolean;\n}\n\nconst dotColour = {\n neutral: 'bg-foreground-subtle',\n accent: 'bg-accent',\n success: 'bg-success',\n warning: 'bg-warning',\n danger: 'bg-danger',\n info: 'bg-info',\n} as const;\n\n/**\n * Status pill. Use `subtle` for high-volume contexts (table cells, lists);\n * `outline` when the badge sits on a busy or coloured background.\n *\n * @example\n * <Badge tone=\"success\" dot>Active</Badge>\n * <Badge tone=\"danger\" variant=\"outline\">Failed</Badge>\n *\n * @do Use badges to summarise state, not to label categories — for taxonomies\n * pick a tone palette and stick with it.\n * @dont Use a badge as a button. Wrap it in a Button or use a Toggle.\n */\nexport const Badge = forwardRef<HTMLSpanElement, BadgeProps>(function Badge(\n { className, variant, tone = 'neutral', dot, children, ...props },\n ref,\n) {\n return (\n <span ref={ref} className={cn(badge({ variant, tone }), className)} {...props}>\n {dot && (\n <span\n aria-hidden\n className={cn('inline-block size-1.5 rounded-full', dotColour[tone ?? 'neutral'])}\n />\n )}\n {children}\n </span>\n );\n});\nBadge.displayName = 'Badge';\n"],"names":["badge","cva","dotColour","Badge","forwardRef","className","variant","tone","dot","children","props","ref","jsxs","cn","jsx"],"mappings":";;;;;AAMA,MAAMA,IAAQC;AAAA,EACZ;AAAA,IACE;AAAA,IACA;AAAA,EAAA;AAAA,EAEF;AAAA,IACE,UAAU;AAAA,MACR,SAAS;AAAA,QACP,QAAQ;AAAA,QACR,SAAS;AAAA,MAAA;AAAA,MAEX,MAAM;AAAA,QACJ,SAAS;AAAA,QACT,QAAQ;AAAA,QACR,SAAS;AAAA,QACT,SAAS;AAAA,QACT,QAAQ;AAAA,QACR,MAAM;AAAA,MAAA;AAAA,IACR;AAAA,IAEF,kBAAkB;AAAA;AAAA,MAEhB,EAAE,SAAS,UAAU,MAAM,WAAW,OAAO,4CAAA;AAAA,MAC7C,EAAE,SAAS,UAAU,MAAM,UAAU,OAAO,qCAAA;AAAA,MAC5C,EAAE,SAAS,UAAU,MAAM,WAAW,OAAO,oCAAA;AAAA,MAC7C,EAAE,SAAS,UAAU,MAAM,WAAW,OAAO,oCAAA;AAAA,MAC7C,EAAE,SAAS,UAAU,MAAM,UAAU,OAAO,kCAAA;AAAA,MAC5C,EAAE,SAAS,UAAU,MAAM,QAAQ,OAAO,8BAAA;AAAA;AAAA,MAE1C,EAAE,SAAS,WAAW,MAAM,WAAW,OAAO,sCAAA;AAAA,MAC9C,EAAE,SAAS,WAAW,MAAM,UAAU,OAAO,4BAAA;AAAA,MAC7C,EAAE,SAAS,WAAW,MAAM,WAAW,OAAO,+CAAA;AAAA,MAC9C,EAAE,SAAS,WAAW,MAAM,WAAW,OAAO,+CAAA;AAAA,MAC9C,EAAE,SAAS,WAAW,MAAM,UAAU,OAAO,6CAAA;AAAA,MAC7C,EAAE,SAAS,WAAW,MAAM,QAAQ,OAAO,yCAAA;AAAA,IAAyC;AAAA,IAEtF,iBAAiB,EAAE,SAAS,UAAU,MAAM,UAAA;AAAA,EAAU;AAE1D,GASMC,IAAY;AAAA,EAChB,SAAS;AAAA,EACT,QAAQ;AAAA,EACR,SAAS;AAAA,EACT,SAAS;AAAA,EACT,QAAQ;AAAA,EACR,MAAM;AACR,GAcaC,IAAQC,EAAwC,SAC3D,EAAE,WAAAC,GAAW,SAAAC,GAAS,MAAAC,IAAO,WAAW,KAAAC,GAAK,UAAAC,GAAU,GAAGC,EAAA,GAC1DC,GACA;AACA,SACE,gBAAAC,EAAC,QAAA,EAAK,KAAAD,GAAU,WAAWE,EAAGb,EAAM,EAAE,SAAAM,GAAS,MAAAC,EAAA,CAAM,GAAGF,CAAS,GAAI,GAAGK,GACrE,UAAA;AAAA,IAAAF,KACC,gBAAAM;AAAA,MAAC;AAAA,MAAA;AAAA,QACC,eAAW;AAAA,QACX,WAAWD,EAAG,sCAAsCX,EAAUK,KAAQ,SAAS,CAAC;AAAA,MAAA;AAAA,IAAA;AAAA,IAGnFE;AAAA,EAAA,GACH;AAEJ,CAAC;AACDN,EAAM,cAAc;"}
@@ -0,0 +1,34 @@
1
+ "use client";
2
+ import { jsx as e, jsxs as c } from "react/jsx-runtime";
3
+ import { forwardRef as b } from "react";
4
+ import { MoreHorizontal as g, ChevronRight as d } from "../../icons/index.js";
5
+ import { cn as x } from "../../lib/utils.js";
6
+ import { useStrings as N } from "../../hooks/use-strings.js";
7
+ const v = b(function({ items: s, maxItems: m = 4, renderLink: l, className: u, ...i }, f) {
8
+ const h = N(), n = s.length > m ? [s[0], { collapsed: !0 }, ...s.slice(-2)] : s;
9
+ return /* @__PURE__ */ e("nav", { ref: f, "aria-label": i["aria-label"] ?? h.breadcrumbs.label, className: x("text-sm", u), ...i, children: /* @__PURE__ */ e("ol", { className: "flex flex-wrap items-center gap-1.5 text-foreground-subtle", children: n.map((o, a) => {
10
+ const t = a === n.length - 1;
11
+ if ("collapsed" in o)
12
+ return /* @__PURE__ */ c("li", { className: "flex items-center gap-1.5", children: [
13
+ /* @__PURE__ */ e(g, { className: "size-4", "aria-hidden": !0 }),
14
+ /* @__PURE__ */ e(d, { className: "size-3.5", "aria-hidden": !0 })
15
+ ] }, `ellipsis-${a}`);
16
+ const r = o, p = t ? /* @__PURE__ */ e("span", { "aria-current": "page", className: "font-medium text-foreground", children: r.label }) : r.href ? l ? l(r.href, r.label) : /* @__PURE__ */ e(
17
+ "a",
18
+ {
19
+ href: r.href,
20
+ className: "hover:text-foreground transition-colors duration-[var(--duration-fast)] outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 rounded-sm",
21
+ children: r.label
22
+ }
23
+ ) : /* @__PURE__ */ e("span", { children: r.label });
24
+ return /* @__PURE__ */ c("li", { className: "flex items-center gap-1.5", children: [
25
+ p,
26
+ !t && /* @__PURE__ */ e(d, { className: "size-3.5", "aria-hidden": !0 })
27
+ ] }, a);
28
+ }) }) });
29
+ });
30
+ v.displayName = "Breadcrumbs";
31
+ export {
32
+ v as Breadcrumbs
33
+ };
34
+ //# sourceMappingURL=Breadcrumbs.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Breadcrumbs.js","sources":["../../../src/components/ui/Breadcrumbs.tsx"],"sourcesContent":["'use client';\n\nimport { forwardRef, type HTMLAttributes, type ReactNode } from 'react';\nimport { ChevronRight, MoreHorizontal } from '@/icons';\nimport { cn } from '@/lib/utils';\nimport { useStrings } from '@/hooks/use-strings';\n\nexport interface BreadcrumbItem {\n /** Visible label. */\n label: ReactNode;\n /** Optional URL. Last item is treated as current page even if href is set. */\n href?: string;\n}\n\nexport interface BreadcrumbsProps extends HTMLAttributes<HTMLElement> {\n items: BreadcrumbItem[];\n /** Collapse to first + ellipsis + last `n` when items.length exceeds this. */\n maxItems?: number;\n /** Custom link renderer (for next/link, react-router, etc.). */\n renderLink?: (href: string, children: ReactNode) => ReactNode;\n}\n\n/**\n * Breadcrumb trail. Collapses with an ellipsis when there are too many crumbs.\n *\n * @example\n * <Breadcrumbs items={[\n * { label: 'Projects', href: '/projects' },\n * { label: 'Nova', href: '/projects/nova' },\n * { label: 'Settings' },\n * ]} />\n *\n * @example With react-router\n * <Breadcrumbs items={trail} renderLink={(href, c) => <Link to={href}>{c}</Link>} />\n *\n * @do Always omit `href` on the last item — it represents the current page.\n * @dont Use Breadcrumbs for flat navigation. Use TopNav links instead.\n */\nexport const Breadcrumbs = forwardRef<HTMLElement, BreadcrumbsProps>(function Breadcrumbs(\n { items, maxItems = 4, renderLink, className, ...props },\n ref,\n) {\n const strings = useStrings();\n const shouldCollapse = items.length > maxItems;\n const displayItems =\n !shouldCollapse\n ? items\n : [items[0], { collapsed: true } as const, ...items.slice(-2)];\n\n return (\n <nav ref={ref} aria-label={props['aria-label'] ?? strings.breadcrumbs.label} className={cn('text-sm', className)} {...props}>\n <ol className=\"flex flex-wrap items-center gap-1.5 text-foreground-subtle\">\n {displayItems.map((it, i) => {\n const isLast = i === displayItems.length - 1;\n if ('collapsed' in it) {\n return (\n <li key={`ellipsis-${i}`} className=\"flex items-center gap-1.5\">\n <MoreHorizontal className=\"size-4\" aria-hidden />\n <ChevronRight className=\"size-3.5\" aria-hidden />\n </li>\n );\n }\n const item = it as BreadcrumbItem;\n const labelNode = isLast ? (\n <span aria-current=\"page\" className=\"font-medium text-foreground\">\n {item.label}\n </span>\n ) : item.href ? (\n renderLink ? (\n renderLink(item.href, item.label)\n ) : (\n <a\n href={item.href}\n className=\"hover:text-foreground transition-colors duration-[var(--duration-fast)] outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 rounded-sm\"\n >\n {item.label}\n </a>\n )\n ) : (\n <span>{item.label}</span>\n );\n return (\n <li key={i} className=\"flex items-center gap-1.5\">\n {labelNode}\n {!isLast && <ChevronRight className=\"size-3.5\" aria-hidden />}\n </li>\n );\n })}\n </ol>\n </nav>\n );\n});\nBreadcrumbs.displayName = 'Breadcrumbs';\n"],"names":["Breadcrumbs","forwardRef","items","maxItems","renderLink","className","props","ref","strings","useStrings","displayItems","jsx","cn","it","i","isLast","jsxs","MoreHorizontal","ChevronRight","item","labelNode"],"mappings":";;;;;;AAsCO,MAAMA,IAAcC,EAA0C,SACnE,EAAE,OAAAC,GAAO,UAAAC,IAAW,GAAG,YAAAC,GAAY,WAAAC,GAAW,GAAGC,EAAA,GACjDC,GACA;AACA,QAAMC,IAAUC,EAAA,GAEVC,IADiBR,EAAM,SAASC,IAIhC,CAACD,EAAM,CAAC,GAAG,EAAE,WAAW,MAAiB,GAAGA,EAAM,MAAM,EAAE,CAAC,IAD3DA;AAGN,SACE,gBAAAS,EAAC,OAAA,EAAI,KAAAJ,GAAU,cAAYD,EAAM,YAAY,KAAKE,EAAQ,YAAY,OAAO,WAAWI,EAAG,WAAWP,CAAS,GAAI,GAAGC,GACpH,UAAA,gBAAAK,EAAC,MAAA,EAAG,WAAU,8DACX,UAAAD,EAAa,IAAI,CAACG,GAAIC,MAAM;AAC3B,UAAMC,IAASD,MAAMJ,EAAa,SAAS;AAC3C,QAAI,eAAeG;AACjB,aACE,gBAAAG,EAAC,MAAA,EAAyB,WAAU,6BAClC,UAAA;AAAA,QAAA,gBAAAL,EAACM,GAAA,EAAe,WAAU,UAAS,eAAW,IAAC;AAAA,QAC/C,gBAAAN,EAACO,GAAA,EAAa,WAAU,YAAW,eAAW,GAAA,CAAC;AAAA,MAAA,EAAA,GAFxC,YAAYJ,CAAC,EAGtB;AAGJ,UAAMK,IAAON,GACPO,IAAYL,IAChB,gBAAAJ,EAAC,UAAK,gBAAa,QAAO,WAAU,+BACjC,UAAAQ,EAAK,OACR,IACEA,EAAK,OACPf,IACEA,EAAWe,EAAK,MAAMA,EAAK,KAAK,IAEhC,gBAAAR;AAAA,MAAC;AAAA,MAAA;AAAA,QACC,MAAMQ,EAAK;AAAA,QACX,WAAU;AAAA,QAET,UAAAA,EAAK;AAAA,MAAA;AAAA,IAAA,IAIV,gBAAAR,EAAC,QAAA,EAAM,UAAAQ,EAAK,MAAA,CAAM;AAEpB,WACE,gBAAAH,EAAC,MAAA,EAAW,WAAU,6BACnB,UAAA;AAAA,MAAAI;AAAA,MACA,CAACL,KAAU,gBAAAJ,EAACO,KAAa,WAAU,YAAW,eAAW,GAAA,CAAC;AAAA,IAAA,EAAA,GAFpDJ,CAGT;AAAA,EAEJ,CAAC,GACH,GACF;AAEJ,CAAC;AACDd,EAAY,cAAc;"}
@@ -1,5 +1,5 @@
1
1
  import { ButtonHTMLAttributes, ReactNode } from 'react';
2
- import { VariantProps } from '../../lib/cva';
2
+ import { VariantProps } from '../../lib/cva.js';
3
3
  declare const button: (props?: ({
4
4
  variant?: "link" | "outline" | "primary" | "secondary" | "ghost" | "destructive" | null | undefined;
5
5
  size?: "icon" | "md" | "sm" | "lg" | null | undefined;