@bearmenu/ui 0.5.1 → 0.6.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 (225) hide show
  1. package/dist/{chunk-ERMIA7NP.js → chunk-7PPCH42H.js} +3 -3
  2. package/dist/{chunk-HLQ2IRE7.js → chunk-BAZFVSSG.js} +3 -3
  3. package/dist/chunk-D5QHEHXJ.js +26 -0
  4. package/dist/{chunk-UISA4CIG.js → chunk-N2KNBPAQ.js} +2 -2
  5. package/dist/{chunk-7H54PTVH.js → chunk-PSR7N36A.js} +38 -10
  6. package/dist/chunk-RIDXFY6M.js +38 -0
  7. package/dist/chunk-UUJVXN2O.js +82 -0
  8. package/dist/chunk-WKMLZDUT.js +122 -0
  9. package/dist/chunk-XK2ZDQVE.js +122 -0
  10. package/dist/{chunk-4KOMHDZD.js → chunk-Y5D5LP4A.js} +18 -3
  11. package/dist/chunk-YJ6OBKZJ.js +32 -0
  12. package/dist/{chunk-ESO2EM3L.js → chunk-ZBBUKXM5.js} +2 -2
  13. package/dist/chunk-ZFNOCP6W.js +106 -0
  14. package/dist/components/accordion.js +11 -5
  15. package/dist/components/alert-dialog.js +5 -3
  16. package/dist/components/alert.d.ts +5 -2
  17. package/dist/components/alert.js +25 -9
  18. package/dist/components/avatar.d.ts +17 -2
  19. package/dist/components/avatar.js +91 -12
  20. package/dist/components/badge.d.ts +1 -1
  21. package/dist/components/badge.js +1 -1
  22. package/dist/components/breadcrumb.js +5 -2
  23. package/dist/components/button-group.d.ts +14 -0
  24. package/dist/components/button-group.js +39 -0
  25. package/dist/components/button.d.ts +4 -2
  26. package/dist/components/button.js +1 -1
  27. package/dist/components/calendar.js +3 -3
  28. package/dist/components/card.d.ts +13 -5
  29. package/dist/components/card.js +2 -2
  30. package/dist/components/carousel.d.ts +20 -3
  31. package/dist/components/carousel.js +72 -12
  32. package/dist/components/checkbox.js +1 -1
  33. package/dist/components/circular-progress.d.ts +16 -0
  34. package/dist/components/circular-progress.js +105 -0
  35. package/dist/components/combobox.d.ts +27 -0
  36. package/dist/components/combobox.js +102 -0
  37. package/dist/components/command.d.ts +29 -16
  38. package/dist/components/command.js +2 -2
  39. package/dist/components/currency-input.d.ts +1 -0
  40. package/dist/components/currency-input.js +73 -52
  41. package/dist/components/date-input.d.ts +10 -0
  42. package/dist/components/date-input.js +40 -0
  43. package/dist/components/description-list.d.ts +15 -0
  44. package/dist/components/description-list.js +67 -0
  45. package/dist/components/dialog.d.ts +13 -2
  46. package/dist/components/dialog.js +1 -1
  47. package/dist/components/drawer.d.ts +5 -2
  48. package/dist/components/drawer.js +47 -9
  49. package/dist/components/dropdown-menu.d.ts +7 -2
  50. package/dist/components/dropdown-menu.js +22 -6
  51. package/dist/components/empty-state.js +2 -2
  52. package/dist/components/field.d.ts +22 -0
  53. package/dist/components/field.js +130 -0
  54. package/dist/components/form.d.ts +2 -1
  55. package/dist/components/form.js +11 -1
  56. package/dist/components/haptic-button.js +3 -3
  57. package/dist/components/input-group.d.ts +18 -0
  58. package/dist/components/input-group.js +92 -0
  59. package/dist/components/input.d.ts +8 -2
  60. package/dist/components/input.js +1 -1
  61. package/dist/components/item.d.ts +23 -0
  62. package/dist/components/item.js +120 -0
  63. package/dist/components/kbd.d.ts +13 -0
  64. package/dist/components/kbd.js +49 -0
  65. package/dist/components/lazy-markdown.d.ts +3 -1
  66. package/dist/components/lazy-markdown.js +7 -7
  67. package/dist/components/link-button.js +1 -1
  68. package/dist/components/multi-select-combobox.js +92 -83
  69. package/dist/components/multi-select-menu.d.ts +0 -4
  70. package/dist/components/multi-select-menu.js +28 -17
  71. package/dist/components/native-select.d.ts +12 -0
  72. package/dist/components/native-select.js +49 -0
  73. package/dist/components/pagination.d.ts +5 -2
  74. package/dist/components/pagination.js +66 -7
  75. package/dist/components/place-about-tab.js +4 -4
  76. package/dist/components/place-card.js +1 -1
  77. package/dist/components/place-details-mobile.js +4 -4
  78. package/dist/components/popover.d.ts +7 -1
  79. package/dist/components/popover.js +1 -1
  80. package/dist/components/progress.d.ts +5 -1
  81. package/dist/components/progress.js +17 -3
  82. package/dist/components/radio-group.js +12 -3
  83. package/dist/components/rating.d.ts +2 -0
  84. package/dist/components/rating.js +88 -70
  85. package/dist/components/search-bar.d.ts +1 -2
  86. package/dist/components/search-bar.js +37 -60
  87. package/dist/components/searchable-select.js +76 -72
  88. package/dist/components/select.d.ts +5 -1
  89. package/dist/components/select.js +30 -14
  90. package/dist/components/selection-bar.d.ts +11 -0
  91. package/dist/components/selection-bar.js +65 -0
  92. package/dist/components/separator.js +3 -2
  93. package/dist/components/sheet.d.ts +1 -1
  94. package/dist/components/sheet.js +1 -1
  95. package/dist/components/skeleton-card.js +1 -1
  96. package/dist/components/skeleton.js +1 -1
  97. package/dist/components/slider.js +21 -4
  98. package/dist/components/sliding-panels.js +15 -13
  99. package/dist/components/spinner.d.ts +17 -0
  100. package/dist/components/spinner.js +50 -0
  101. package/dist/components/stepper.d.ts +18 -0
  102. package/dist/components/stepper.js +199 -0
  103. package/dist/components/sticky-container.js +1 -0
  104. package/dist/components/switch.js +4 -3
  105. package/dist/components/table.d.ts +23 -5
  106. package/dist/components/table.js +121 -35
  107. package/dist/components/tabs.d.ts +3 -1
  108. package/dist/components/tabs.js +37 -9
  109. package/dist/components/tag-group.d.ts +9 -0
  110. package/dist/components/tag-group.js +26 -0
  111. package/dist/components/tag.d.ts +17 -0
  112. package/dist/components/tag.js +61 -0
  113. package/dist/components/text.d.ts +3 -3
  114. package/dist/components/text.js +1 -1
  115. package/dist/components/textarea.js +2 -1
  116. package/dist/components/toast.js +1 -1
  117. package/dist/components/toaster.js +1 -1
  118. package/dist/components/toggle-group.js +1 -1
  119. package/dist/components/toggle.js +1 -1
  120. package/dist/components/tooltip.d.ts +3 -2
  121. package/dist/components/tooltip.js +16 -2
  122. package/package.json +44 -26
  123. package/src/components/accordion.tsx +11 -6
  124. package/src/components/alert-dialog.tsx +4 -2
  125. package/src/components/alert.tsx +20 -8
  126. package/src/components/avatar.tsx +106 -13
  127. package/src/components/badge.tsx +12 -11
  128. package/src/components/breadcrumb.tsx +5 -2
  129. package/src/components/button-group.stories.tsx +52 -0
  130. package/src/components/button-group.tsx +40 -0
  131. package/src/components/button.test.tsx +174 -0
  132. package/src/components/button.tsx +42 -19
  133. package/src/components/calendar.tsx +2 -2
  134. package/src/components/card.tsx +55 -13
  135. package/src/components/carousel.tsx +85 -13
  136. package/src/components/checkbox.test.tsx +58 -0
  137. package/src/components/checkbox.tsx +8 -3
  138. package/src/components/circular-progress.stories.tsx +39 -0
  139. package/src/components/circular-progress.tsx +102 -0
  140. package/src/components/collapsible.stories.tsx +7 -3
  141. package/src/components/combobox.stories.tsx +82 -0
  142. package/src/components/combobox.test.tsx +118 -0
  143. package/src/components/combobox.tsx +136 -0
  144. package/src/components/command.test.tsx +91 -0
  145. package/src/components/command.tsx +38 -15
  146. package/src/components/currency-input.test.tsx +63 -0
  147. package/src/components/currency-input.tsx +84 -66
  148. package/src/components/date-input.stories.tsx +31 -0
  149. package/src/components/date-input.tsx +43 -0
  150. package/src/components/description-list.stories.tsx +62 -0
  151. package/src/components/description-list.tsx +68 -0
  152. package/src/components/dialog.test.tsx +84 -0
  153. package/src/components/dialog.tsx +64 -24
  154. package/src/components/drawer.tsx +72 -23
  155. package/src/components/dropdown-menu.test.tsx +180 -0
  156. package/src/components/dropdown-menu.tsx +31 -6
  157. package/src/components/field.stories.tsx +36 -0
  158. package/src/components/field.test.tsx +157 -0
  159. package/src/components/field.tsx +146 -0
  160. package/src/components/form.stories.tsx +3 -2
  161. package/src/components/form.test.tsx +95 -0
  162. package/src/components/form.tsx +9 -0
  163. package/src/components/haptic-button.tsx +1 -1
  164. package/src/components/input-group.stories.tsx +61 -0
  165. package/src/components/input-group.tsx +99 -0
  166. package/src/components/input.test.tsx +103 -0
  167. package/src/components/input.tsx +24 -7
  168. package/src/components/item.stories.tsx +52 -0
  169. package/src/components/item.tsx +115 -0
  170. package/src/components/kbd.stories.tsx +33 -0
  171. package/src/components/kbd.tsx +46 -0
  172. package/src/components/lazy-markdown.tsx +10 -7
  173. package/src/components/multi-select-combobox.test.tsx +101 -0
  174. package/src/components/multi-select-combobox.tsx +85 -82
  175. package/src/components/multi-select-menu.tsx +49 -41
  176. package/src/components/native-select.stories.tsx +52 -0
  177. package/src/components/native-select.tsx +45 -0
  178. package/src/components/pagination.tsx +64 -5
  179. package/src/components/popover.tsx +66 -3
  180. package/src/components/progress.tsx +27 -4
  181. package/src/components/radio-group.test.tsx +64 -0
  182. package/src/components/radio-group.tsx +11 -3
  183. package/src/components/rating.test.tsx +112 -0
  184. package/src/components/rating.tsx +97 -82
  185. package/src/components/search-bar.stories.tsx +1 -32
  186. package/src/components/search-bar.tsx +22 -59
  187. package/src/components/searchable-select.tsx +69 -73
  188. package/src/components/select.tsx +34 -19
  189. package/src/components/selection-bar.stories.tsx +37 -0
  190. package/src/components/selection-bar.tsx +65 -0
  191. package/src/components/separator.tsx +5 -2
  192. package/src/components/sheet.tsx +1 -1
  193. package/src/components/skeleton.tsx +2 -2
  194. package/src/components/slider.test.tsx +45 -0
  195. package/src/components/slider.tsx +31 -12
  196. package/src/components/sliding-panels.tsx +14 -12
  197. package/src/components/spinner.stories.tsx +35 -0
  198. package/src/components/spinner.tsx +50 -0
  199. package/src/components/stepper.stories.tsx +71 -0
  200. package/src/components/stepper.tsx +220 -0
  201. package/src/components/sticky-container.tsx +1 -0
  202. package/src/components/switch.test.tsx +52 -0
  203. package/src/components/switch.tsx +4 -3
  204. package/src/components/table.tsx +140 -35
  205. package/src/components/tabs.test.tsx +107 -0
  206. package/src/components/tabs.tsx +70 -23
  207. package/src/components/tag-group.stories.tsx +39 -0
  208. package/src/components/tag-group.tsx +28 -0
  209. package/src/components/tag.stories.tsx +50 -0
  210. package/src/components/tag.tsx +63 -0
  211. package/src/components/text.test.tsx +1 -1
  212. package/src/components/text.tsx +19 -3
  213. package/src/components/textarea.test.tsx +48 -0
  214. package/src/components/textarea.tsx +2 -1
  215. package/src/components/toast.tsx +4 -3
  216. package/src/components/toggle.tsx +2 -2
  217. package/src/components/tooltip.tsx +12 -2
  218. package/src/globals.css +142 -90
  219. package/dist/chunk-2BMJRXQX.js +0 -80
  220. package/dist/chunk-4AVS6CV4.js +0 -89
  221. package/dist/chunk-4UO73SKC.js +0 -26
  222. package/dist/chunk-CW24PLDW.js +0 -24
  223. package/dist/chunk-IQASCH2V.js +0 -25
  224. package/dist/chunk-NKHH23YK.js +0 -31
  225. package/dist/chunk-QJ54Z7TC.js +0 -83
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bearmenu/ui",
3
- "version": "0.5.1",
3
+ "version": "0.6.0",
4
4
  "description": "BearMenu design system — shared UI tokens, primitives, and components",
5
5
  "license": "UNLICENSED",
6
6
  "repository": {
@@ -24,28 +24,38 @@
24
24
  "./components/avatar": "./src/components/avatar.tsx",
25
25
  "./components/badge": "./src/components/badge.tsx",
26
26
  "./components/breadcrumb": "./src/components/breadcrumb.tsx",
27
+ "./components/button-group": "./src/components/button-group.tsx",
27
28
  "./components/button": "./src/components/button.tsx",
28
29
  "./components/calendar": "./src/components/calendar.tsx",
29
30
  "./components/card": "./src/components/card.tsx",
30
31
  "./components/carousel": "./src/components/carousel.tsx",
31
32
  "./components/checkbox": "./src/components/checkbox.tsx",
33
+ "./components/circular-progress": "./src/components/circular-progress.tsx",
32
34
  "./components/collapsible": "./src/components/collapsible.tsx",
35
+ "./components/combobox": "./src/components/combobox.tsx",
33
36
  "./components/command": "./src/components/command.tsx",
34
37
  "./components/currency-input": "./src/components/currency-input.tsx",
38
+ "./components/date-input": "./src/components/date-input.tsx",
39
+ "./components/description-list": "./src/components/description-list.tsx",
35
40
  "./components/dialog": "./src/components/dialog.tsx",
36
41
  "./components/drawer": "./src/components/drawer.tsx",
37
42
  "./components/dropdown-menu": "./src/components/dropdown-menu.tsx",
38
43
  "./components/empty-state": "./src/components/empty-state.tsx",
44
+ "./components/field": "./src/components/field.tsx",
39
45
  "./components/form": "./src/components/form.tsx",
40
46
  "./components/haptic-button": "./src/components/haptic-button.tsx",
47
+ "./components/input-group": "./src/components/input-group.tsx",
41
48
  "./components/input-otp": "./src/components/input-otp.tsx",
42
49
  "./components/input": "./src/components/input.tsx",
50
+ "./components/item": "./src/components/item.tsx",
51
+ "./components/kbd": "./src/components/kbd.tsx",
43
52
  "./components/label": "./src/components/label.tsx",
44
53
  "./components/lazy-markdown": "./src/components/lazy-markdown.tsx",
45
54
  "./components/link-button": "./src/components/link-button.tsx",
46
55
  "./components/markdown-renderer": "./src/components/markdown-renderer.tsx",
47
56
  "./components/multi-select-combobox": "./src/components/multi-select-combobox.tsx",
48
57
  "./components/multi-select-menu": "./src/components/multi-select-menu.tsx",
58
+ "./components/native-select": "./src/components/native-select.tsx",
49
59
  "./components/pagination": "./src/components/pagination.tsx",
50
60
  "./components/phone-frame": "./src/components/phone-frame.tsx",
51
61
  "./components/place-about-tab": "./src/components/place-about-tab.tsx",
@@ -60,6 +70,7 @@
60
70
  "./components/search-bar": "./src/components/search-bar.tsx",
61
71
  "./components/searchable-select": "./src/components/searchable-select.tsx",
62
72
  "./components/select": "./src/components/select.tsx",
73
+ "./components/selection-bar": "./src/components/selection-bar.tsx",
63
74
  "./components/separator": "./src/components/separator.tsx",
64
75
  "./components/sheet": "./src/components/sheet.tsx",
65
76
  "./components/skeleton-card": "./src/components/skeleton-card.tsx",
@@ -67,10 +78,14 @@
67
78
  "./components/slider": "./src/components/slider.tsx",
68
79
  "./components/sliding-panels": "./src/components/sliding-panels.tsx",
69
80
  "./components/sonner": "./src/components/sonner.tsx",
81
+ "./components/spinner": "./src/components/spinner.tsx",
82
+ "./components/stepper": "./src/components/stepper.tsx",
70
83
  "./components/sticky-container": "./src/components/sticky-container.tsx",
71
84
  "./components/switch": "./src/components/switch.tsx",
72
85
  "./components/table": "./src/components/table.tsx",
73
86
  "./components/tabs": "./src/components/tabs.tsx",
87
+ "./components/tag-group": "./src/components/tag-group.tsx",
88
+ "./components/tag": "./src/components/tag.tsx",
74
89
  "./components/text": "./src/components/text.tsx",
75
90
  "./components/textarea": "./src/components/textarea.tsx",
76
91
  "./components/toast": "./src/components/toast.tsx",
@@ -109,6 +124,8 @@
109
124
  "build": "tsup",
110
125
  "dev": "tsup --watch",
111
126
  "typecheck": "tsc --noEmit",
127
+ "test": "vitest run",
128
+ "test:watch": "vitest",
112
129
  "clean": "rm -rf dist",
113
130
  "prepublishOnly": "pnpm run build"
114
131
  },
@@ -159,29 +176,29 @@
159
176
  },
160
177
  "devDependencies": {
161
178
  "@hookform/resolvers": "^3.10.0",
162
- "@radix-ui/react-accordion": "latest",
163
- "@radix-ui/react-alert-dialog": "latest",
164
- "@radix-ui/react-aspect-ratio": "latest",
165
- "@radix-ui/react-avatar": "latest",
166
- "@radix-ui/react-checkbox": "latest",
167
- "@radix-ui/react-collapsible": "latest",
168
- "@radix-ui/react-dialog": "latest",
169
- "@radix-ui/react-dropdown-menu": "latest",
170
- "@radix-ui/react-label": "latest",
171
- "@radix-ui/react-popover": "latest",
172
- "@radix-ui/react-progress": "latest",
173
- "@radix-ui/react-radio-group": "latest",
174
- "@radix-ui/react-scroll-area": "latest",
175
- "@radix-ui/react-select": "latest",
176
- "@radix-ui/react-separator": "latest",
177
- "@radix-ui/react-slider": "latest",
178
- "@radix-ui/react-slot": "latest",
179
- "@radix-ui/react-switch": "latest",
180
- "@radix-ui/react-tabs": "latest",
181
- "@radix-ui/react-toast": "latest",
182
- "@radix-ui/react-toggle": "latest",
183
- "@radix-ui/react-toggle-group": "latest",
184
- "@radix-ui/react-tooltip": "latest",
179
+ "@radix-ui/react-accordion": "^1.2.12",
180
+ "@radix-ui/react-alert-dialog": "^1.1.15",
181
+ "@radix-ui/react-aspect-ratio": "^1.1.8",
182
+ "@radix-ui/react-avatar": "^1.1.11",
183
+ "@radix-ui/react-checkbox": "^1.3.3",
184
+ "@radix-ui/react-collapsible": "^1.1.12",
185
+ "@radix-ui/react-dialog": "^1.1.15",
186
+ "@radix-ui/react-dropdown-menu": "^2.1.16",
187
+ "@radix-ui/react-label": "^2.1.8",
188
+ "@radix-ui/react-popover": "^1.1.15",
189
+ "@radix-ui/react-progress": "^1.1.8",
190
+ "@radix-ui/react-radio-group": "^1.3.8",
191
+ "@radix-ui/react-scroll-area": "^1.2.10",
192
+ "@radix-ui/react-select": "^2.2.6",
193
+ "@radix-ui/react-separator": "^1.1.8",
194
+ "@radix-ui/react-slider": "^1.3.6",
195
+ "@radix-ui/react-slot": "^1.2.4",
196
+ "@radix-ui/react-switch": "^1.2.6",
197
+ "@radix-ui/react-tabs": "^1.1.13",
198
+ "@radix-ui/react-toast": "^1.2.15",
199
+ "@radix-ui/react-toggle": "^1.1.10",
200
+ "@radix-ui/react-toggle-group": "^1.1.11",
201
+ "@radix-ui/react-tooltip": "^1.2.8",
185
202
  "@storybook/addon-a11y": "^10.3.5",
186
203
  "@storybook/addon-docs": "^10.3.5",
187
204
  "@storybook/react-vite": "^10.3.5",
@@ -189,12 +206,13 @@
189
206
  "@tailwindcss/vite": "^4.2.4",
190
207
  "@testing-library/jest-dom": "^6.9.1",
191
208
  "@testing-library/react": "^16.3.2",
209
+ "@testing-library/user-event": "^14.6.1",
192
210
  "@types/react": "^19",
193
211
  "@types/react-dom": "^19",
194
212
  "@vitejs/plugin-react": "^6.0.1",
195
213
  "class-variance-authority": "^0.7.1",
196
214
  "clsx": "^2.1.1",
197
- "cmdk": "latest",
215
+ "cmdk": "^1.1.1",
198
216
  "embla-carousel-react": "^8.6.0",
199
217
  "framer-motion": "^12.23.22",
200
218
  "input-otp": "^1.4.2",
@@ -203,7 +221,7 @@
203
221
  "next": "^16.1.7",
204
222
  "next-themes": "^0.4.6",
205
223
  "react": "19.2.4",
206
- "react-day-picker": "latest",
224
+ "react-day-picker": "^9.14.0",
207
225
  "react-dom": "19.2.4",
208
226
  "react-hook-form": "7.72.0",
209
227
  "react-markdown": "^10.1.0",
@@ -13,7 +13,8 @@ const AccordionItem = React.forwardRef<
13
13
  >(({ className, ...props }, ref) => (
14
14
  <AccordionPrimitive.Item
15
15
  ref={ref}
16
- className={cn("border-b border-border/50", className)}
16
+ data-slot="accordion-item"
17
+ className={cn("border-b border-border last:border-b-0", className)}
17
18
  {...props}
18
19
  />
19
20
  ));
@@ -26,14 +27,18 @@ const AccordionTrigger = React.forwardRef<
26
27
  <AccordionPrimitive.Header className="flex">
27
28
  <AccordionPrimitive.Trigger
28
29
  ref={ref}
30
+ data-slot="accordion-trigger"
29
31
  className={cn(
30
- "flex flex-1 items-center justify-between py-4 font-medium transition-all duration-300 hover:underline [&[data-state=open]>svg]:rotate-180 glass-hover rounded-xl px-4 hover:bg-accent/20",
32
+ "flex flex-1 cursor-pointer items-center justify-between py-4 text-sm font-medium text-foreground transition-colors hover:text-foreground/80",
33
+ "focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 rounded-sm",
34
+ "disabled:pointer-events-none disabled:cursor-not-allowed disabled:opacity-50",
35
+ "[&[data-state=open]>svg]:rotate-180",
31
36
  className
32
37
  )}
33
38
  {...props}
34
39
  >
35
40
  {children}
36
- <ChevronDown className="h-4 w-4 shrink-0 transition-transform duration-300" />
41
+ <ChevronDown className="size-4 shrink-0 text-muted-foreground transition-transform duration-200" />
37
42
  </AccordionPrimitive.Trigger>
38
43
  </AccordionPrimitive.Header>
39
44
  ));
@@ -45,13 +50,13 @@ const AccordionContent = React.forwardRef<
45
50
  >(({ className, children, ...props }, ref) => (
46
51
  <AccordionPrimitive.Content
47
52
  ref={ref}
48
- className="overflow-hidden text-sm transition-all data-[state=closed]:animate-accordion-up data-[state=open]:animate-accordion-down"
53
+ data-slot="accordion-content"
54
+ className="overflow-hidden text-sm data-[state=closed]:animate-accordion-up data-[state=open]:animate-accordion-down"
49
55
  {...props}
50
56
  >
51
- <div className={cn("pb-4 pt-0 px-4", className)}>{children}</div>
57
+ <div className={cn("pb-4 pt-0", className)}>{children}</div>
52
58
  </AccordionPrimitive.Content>
53
59
  ));
54
-
55
60
  AccordionContent.displayName = AccordionPrimitive.Content.displayName;
56
61
 
57
62
  export { Accordion, AccordionItem, AccordionTrigger, AccordionContent };
@@ -16,8 +16,9 @@ const AlertDialogOverlay = React.forwardRef<
16
16
  React.ComponentPropsWithoutRef<typeof AlertDialogPrimitive.Overlay>
17
17
  >(({ className, ...props }, ref) => (
18
18
  <AlertDialogPrimitive.Overlay
19
+ data-slot="alert-dialog-overlay"
19
20
  className={cn(
20
- "fixed inset-0 z-50 bg-black/50 backdrop-blur-sm data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0",
21
+ "fixed inset-0 z-[1000] bg-black/50 backdrop-blur-sm data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0",
21
22
  className
22
23
  )}
23
24
  {...props}
@@ -34,8 +35,9 @@ const AlertDialogContent = React.forwardRef<
34
35
  <AlertDialogOverlay />
35
36
  <AlertDialogPrimitive.Content
36
37
  ref={ref}
38
+ data-slot="alert-dialog-content"
37
39
  className={cn(
38
- "fixed left-[50%] top-[50%] z-50 grid w-full max-w-lg translate-x-[-50%] translate-y-[-50%] gap-4 glass p-6 shadow-2xl duration-200 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[state=closed]:slide-out-to-left-1/2 data-[state=closed]:slide-out-to-top-[48%] data-[state=open]:slide-in-from-left-1/2 data-[state=open]:slide-in-from-top-[48%] rounded-2xl border border-border/50",
40
+ "fixed left-[50%] top-[50%] z-[1000] grid w-full max-w-lg translate-x-[-50%] translate-y-[-50%] gap-4 rounded-2xl border border-border bg-card p-6 shadow-2xl duration-200 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95",
39
41
  className
40
42
  )}
41
43
  {...props}
@@ -4,17 +4,17 @@ import { cn } from "../lib/utils";
4
4
  import { textVariants } from "./text";
5
5
 
6
6
  const alertVariants = cva(
7
- "relative w-full rounded-xl border border-border/50 px-4 py-3 text-sm glass transition-all duration-300 [&>svg+div]:translate-y-[-3px] [&>svg]:absolute [&>svg]:left-4 [&>svg]:top-4 [&>svg]:text-foreground [&>svg~*]:pl-7",
7
+ "relative w-full rounded-xl border px-4 py-3 text-sm transition-colors [&>svg+div]:translate-y-[-3px] [&>svg]:absolute [&>svg]:left-4 [&>svg]:top-4 [&>svg~*]:pl-7",
8
8
  {
9
9
  variants: {
10
10
  variant: {
11
- default: "bg-background text-foreground",
11
+ default: "bg-card text-card-foreground border-border [&>svg]:text-foreground",
12
12
  destructive:
13
- "border-destructive/50 text-destructive dark:border-destructive [&>svg]:text-destructive bg-destructive/10",
13
+ "border-destructive/40 bg-destructive/10 text-destructive [&>svg]:text-destructive",
14
14
  warning:
15
- "border-yellow-500/50 text-yellow-600 dark:border-yellow-500 [&>svg]:text-yellow-600 bg-yellow-500/10",
15
+ "border-warning/40 bg-warning/10 text-warning [&>svg]:text-warning",
16
16
  success:
17
- "border-green-500/50 text-green-600 dark:border-green-500 [&>svg]:text-green-600 bg-green-500/10",
17
+ "border-success/40 bg-success/10 text-success [&>svg]:text-success",
18
18
  },
19
19
  },
20
20
  defaultVariants: {
@@ -27,7 +27,13 @@ const Alert = React.forwardRef<
27
27
  HTMLDivElement,
28
28
  React.HTMLAttributes<HTMLDivElement> & VariantProps<typeof alertVariants>
29
29
  >(({ className, variant, ...props }, ref) => (
30
- <div ref={ref} role="alert" className={cn(alertVariants({ variant }), className)} {...props} />
30
+ <div
31
+ ref={ref}
32
+ role="alert"
33
+ data-slot="alert"
34
+ className={cn(alertVariants({ variant }), className)}
35
+ {...props}
36
+ />
31
37
  ));
32
38
  Alert.displayName = "Alert";
33
39
 
@@ -35,6 +41,7 @@ const AlertTitle = React.forwardRef<HTMLParagraphElement, React.HTMLAttributes<H
35
41
  ({ className, ...props }, ref) => (
36
42
  <h5
37
43
  ref={ref}
44
+ data-slot="alert-title"
38
45
  className={cn(
39
46
  "mb-1",
40
47
  textVariants({ weight: "medium", leading: "none", tracking: "tight" }),
@@ -50,8 +57,13 @@ const AlertDescription = React.forwardRef<
50
57
  HTMLParagraphElement,
51
58
  React.HTMLAttributes<HTMLParagraphElement>
52
59
  >(({ className, ...props }, ref) => (
53
- <div ref={ref} className={cn("text-sm [&_p]:leading-relaxed", className)} {...props} />
60
+ <div
61
+ ref={ref}
62
+ data-slot="alert-description"
63
+ className={cn("text-sm [&_p]:leading-relaxed", className)}
64
+ {...props}
65
+ />
54
66
  ));
55
67
  AlertDescription.displayName = "AlertDescription";
56
68
 
57
- export { Alert, AlertTitle, AlertDescription };
69
+ export { Alert, AlertTitle, AlertDescription, alertVariants };
@@ -2,20 +2,42 @@
2
2
 
3
3
  import * as React from "react";
4
4
  import * as AvatarPrimitive from "@radix-ui/react-avatar";
5
+ import { cva, type VariantProps } from "class-variance-authority";
5
6
  import { cn } from "../lib/utils";
6
7
 
8
+ const avatarVariants = cva(
9
+ "relative flex shrink-0 overflow-hidden rounded-full bg-muted",
10
+ {
11
+ variants: {
12
+ size: {
13
+ xs: "size-6 text-[10px]",
14
+ sm: "size-8 text-xs",
15
+ default: "size-10 text-sm",
16
+ lg: "size-12 text-base",
17
+ xl: "size-16 text-lg",
18
+ },
19
+ },
20
+ defaultVariants: {
21
+ size: "default",
22
+ },
23
+ }
24
+ );
25
+
26
+ const AvatarContext = React.createContext<VariantProps<typeof avatarVariants>["size"]>("default");
27
+
7
28
  const Avatar = React.forwardRef<
8
29
  React.ElementRef<typeof AvatarPrimitive.Root>,
9
- React.ComponentPropsWithoutRef<typeof AvatarPrimitive.Root>
10
- >(({ className, ...props }, ref) => (
11
- <AvatarPrimitive.Root
12
- ref={ref}
13
- className={cn(
14
- "relative flex h-10 w-10 shrink-0 overflow-hidden rounded-full border border-border/50 shadow-lg backdrop-blur-md bg-card/50 transition-all duration-300 hover:shadow-xl hover:shadow-black/20 hover:border-accent/30",
15
- className
16
- )}
17
- {...props}
18
- />
30
+ React.ComponentPropsWithoutRef<typeof AvatarPrimitive.Root> &
31
+ VariantProps<typeof avatarVariants>
32
+ >(({ className, size = "default", ...props }, ref) => (
33
+ <AvatarContext.Provider value={size}>
34
+ <AvatarPrimitive.Root
35
+ ref={ref}
36
+ data-slot="avatar"
37
+ className={cn(avatarVariants({ size }), className)}
38
+ {...props}
39
+ />
40
+ </AvatarContext.Provider>
19
41
  ));
20
42
  Avatar.displayName = AvatarPrimitive.Root.displayName;
21
43
 
@@ -25,7 +47,8 @@ const AvatarImage = React.forwardRef<
25
47
  >(({ className, ...props }, ref) => (
26
48
  <AvatarPrimitive.Image
27
49
  ref={ref}
28
- className={cn("aspect-square h-full w-full object-cover", className)}
50
+ data-slot="avatar-image"
51
+ className={cn("aspect-square size-full object-cover", className)}
29
52
  {...props}
30
53
  />
31
54
  ));
@@ -37,8 +60,9 @@ const AvatarFallback = React.forwardRef<
37
60
  >(({ className, ...props }, ref) => (
38
61
  <AvatarPrimitive.Fallback
39
62
  ref={ref}
63
+ data-slot="avatar-fallback"
40
64
  className={cn(
41
- "flex h-full w-full items-center justify-center rounded-full bg-muted text-muted-foreground text-sm font-medium backdrop-blur-md",
65
+ "flex size-full items-center justify-center rounded-full bg-muted font-medium text-muted-foreground",
42
66
  className
43
67
  )}
44
68
  {...props}
@@ -46,4 +70,73 @@ const AvatarFallback = React.forwardRef<
46
70
  ));
47
71
  AvatarFallback.displayName = AvatarPrimitive.Fallback.displayName;
48
72
 
49
- export { Avatar, AvatarImage, AvatarFallback };
73
+ const badgeOffset = {
74
+ xs: "size-2 ring-1",
75
+ sm: "size-2.5 ring-2",
76
+ default: "size-3 ring-2",
77
+ lg: "size-3.5 ring-2",
78
+ xl: "size-4 ring-2",
79
+ } as const;
80
+
81
+ const AvatarBadge = React.forwardRef<
82
+ HTMLSpanElement,
83
+ React.HTMLAttributes<HTMLSpanElement> & {
84
+ placement?: "top-right" | "bottom-right";
85
+ tone?: "success" | "warning" | "destructive" | "muted";
86
+ }
87
+ >(({ className, placement = "bottom-right", tone = "success", ...props }, ref) => {
88
+ const size = React.useContext(AvatarContext) ?? "default";
89
+ return (
90
+ <span
91
+ ref={ref}
92
+ data-slot="avatar-badge"
93
+ className={cn(
94
+ "absolute block rounded-full ring-background",
95
+ badgeOffset[size as keyof typeof badgeOffset],
96
+ placement === "top-right" ? "right-0 top-0" : "bottom-0 right-0",
97
+ tone === "success" && "bg-success",
98
+ tone === "warning" && "bg-warning",
99
+ tone === "destructive" && "bg-destructive",
100
+ tone === "muted" && "bg-muted-foreground",
101
+ className
102
+ )}
103
+ {...props}
104
+ />
105
+ );
106
+ });
107
+ AvatarBadge.displayName = "AvatarBadge";
108
+
109
+ const AvatarGroup = React.forwardRef<
110
+ HTMLDivElement,
111
+ React.HTMLAttributes<HTMLDivElement> & { max?: number; spacing?: "tight" | "default" | "loose" }
112
+ >(({ className, children, max, spacing = "default", ...props }, ref) => {
113
+ const items = React.Children.toArray(children);
114
+ const visible = max ? items.slice(0, max) : items;
115
+ const overflow = max ? items.length - max : 0;
116
+
117
+ return (
118
+ <div
119
+ ref={ref}
120
+ data-slot="avatar-group"
121
+ className={cn(
122
+ "flex items-center",
123
+ spacing === "tight" && "-space-x-3",
124
+ spacing === "default" && "-space-x-2",
125
+ spacing === "loose" && "-space-x-1",
126
+ "[&>*]:ring-2 [&>*]:ring-background",
127
+ className
128
+ )}
129
+ {...props}
130
+ >
131
+ {visible}
132
+ {overflow > 0 && (
133
+ <span className="relative inline-flex size-10 items-center justify-center rounded-full bg-muted text-xs font-medium text-muted-foreground ring-2 ring-background">
134
+ +{overflow}
135
+ </span>
136
+ )}
137
+ </div>
138
+ );
139
+ });
140
+ AvatarGroup.displayName = "AvatarGroup";
141
+
142
+ export { Avatar, AvatarImage, AvatarFallback, AvatarBadge, AvatarGroup, avatarVariants };
@@ -3,23 +3,24 @@ import { cva, type VariantProps } from "class-variance-authority";
3
3
  import { cn } from "../lib/utils";
4
4
 
5
5
  const badgeVariants = cva(
6
- "inline-flex items-center rounded-lg border px-2.5 py-0.5 text-xs font-semibold transition-[background-color,color,box-shadow,border-color] duration-300 focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 backdrop-blur-md",
6
+ "inline-flex items-center rounded-lg border px-2.5 py-0.5 text-xs font-semibold transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2",
7
7
  {
8
8
  variants: {
9
9
  variant: {
10
- default:
11
- "border-transparent bg-primary/80 text-primary-foreground shadow-lg hover:bg-primary hover:shadow-xl hover:shadow-primary/20",
10
+ default: "border-transparent bg-primary text-primary-foreground",
12
11
  secondary:
13
- "border-transparent bg-secondary/80 text-secondary-foreground shadow-lg hover:bg-secondary hover:shadow-xl hover:shadow-secondary/20",
12
+ "border-transparent bg-secondary text-secondary-foreground",
14
13
  destructive:
15
- "border-transparent bg-destructive/80 text-destructive-foreground shadow-lg hover:bg-destructive hover:shadow-xl hover:shadow-destructive/20",
16
- outline: "text-foreground glass glass-hover",
17
- overlay: "border-transparent bg-black/50 text-white backdrop-blur-sm shadow-lg",
18
- glass: "glass glass-hover text-foreground border-border/50",
14
+ "border-transparent bg-destructive text-destructive-foreground",
15
+ outline: "text-foreground border-border",
16
+ overlay:
17
+ "border-transparent bg-foreground/70 text-background backdrop-blur-sm",
18
+ glass: "glass text-foreground border-border/50",
19
19
  success:
20
- "border-transparent bg-green-500/80 text-primary shadow-lg hover:bg-green-500 hover:shadow-xl hover:shadow-green-500/20",
20
+ "border-transparent bg-success text-success-foreground",
21
21
  warning:
22
- "border-transparent bg-yellow-500/80 text-primary shadow-lg hover:bg-yellow-500 hover:shadow-xl hover:shadow-yellow-500/20",
22
+ "border-transparent bg-warning text-warning-foreground",
23
+ brown: "border-transparent bg-brown text-brown-foreground",
23
24
  },
24
25
  },
25
26
  defaultVariants: {
@@ -32,7 +33,7 @@ export interface BadgeProps
32
33
  extends React.HTMLAttributes<HTMLDivElement>, VariantProps<typeof badgeVariants> {}
33
34
 
34
35
  function Badge({ className, variant, ...props }: BadgeProps) {
35
- return <div className={cn(badgeVariants({ variant }), className)} {...props} />;
36
+ return <div data-slot="badge" className={cn(badgeVariants({ variant }), className)} {...props} />;
36
37
  }
37
38
 
38
39
  export { Badge, badgeVariants };
@@ -43,7 +43,10 @@ function BreadcrumbLink({
43
43
  return (
44
44
  <Comp
45
45
  data-slot="breadcrumb-link"
46
- className={cn("hover:text-foreground transition-colors", className)}
46
+ className={cn(
47
+ "rounded-sm text-muted-foreground transition-colors hover:text-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2",
48
+ className
49
+ )}
47
50
  {...props}
48
51
  />
49
52
  );
@@ -56,7 +59,7 @@ function BreadcrumbPage({ className, ...props }: React.ComponentProps<"span">) {
56
59
  role="link"
57
60
  aria-disabled="true"
58
61
  aria-current="page"
59
- className={cn("text-foreground font-normal", className)}
62
+ className={cn("font-medium text-foreground", className)}
60
63
  {...props}
61
64
  />
62
65
  );
@@ -0,0 +1,52 @@
1
+ import type { Meta, StoryObj } from "@storybook/react";
2
+ import { ButtonGroup } from "./button-group";
3
+ import { Button } from "./button";
4
+ import { AlignLeft, AlignCenter, AlignRight } from "lucide-react";
5
+
6
+ const meta = {
7
+ title: "Components/ButtonGroup",
8
+ component: ButtonGroup,
9
+ tags: ["autodocs"],
10
+ } satisfies Meta<typeof ButtonGroup>;
11
+
12
+ export default meta;
13
+ type Story = StoryObj<typeof meta>;
14
+
15
+ export const Default: Story = {
16
+ render: () => (
17
+ <ButtonGroup>
18
+ <Button variant="outline">One</Button>
19
+ <Button variant="outline">Two</Button>
20
+ <Button variant="outline">Three</Button>
21
+ </ButtonGroup>
22
+ ),
23
+ };
24
+
25
+ export const Icons: Story = {
26
+ render: () => (
27
+ <ButtonGroup>
28
+ <Button variant="outline" size="icon" aria-label="Align left"><AlignLeft className="size-4" /></Button>
29
+ <Button variant="outline" size="icon" aria-label="Align center"><AlignCenter className="size-4" /></Button>
30
+ <Button variant="outline" size="icon" aria-label="Align right"><AlignRight className="size-4" /></Button>
31
+ </ButtonGroup>
32
+ ),
33
+ };
34
+
35
+ export const Vertical: Story = {
36
+ render: () => (
37
+ <ButtonGroup orientation="vertical">
38
+ <Button variant="outline">Top</Button>
39
+ <Button variant="outline">Middle</Button>
40
+ <Button variant="outline">Bottom</Button>
41
+ </ButtonGroup>
42
+ ),
43
+ };
44
+
45
+ export const Detached: Story = {
46
+ render: () => (
47
+ <ButtonGroup attached={false}>
48
+ <Button>Save</Button>
49
+ <Button variant="outline">Cancel</Button>
50
+ </ButtonGroup>
51
+ ),
52
+ };
@@ -0,0 +1,40 @@
1
+ import * as React from "react";
2
+ import { cva, type VariantProps } from "class-variance-authority";
3
+ import { cn } from "../lib/utils";
4
+
5
+ const buttonGroupVariants = cva("inline-flex", {
6
+ variants: {
7
+ orientation: {
8
+ horizontal:
9
+ "flex-row [&>[data-slot=button]]:rounded-none [&>[data-slot=button]:first-child]:rounded-l-xl [&>[data-slot=button]:last-child]:rounded-r-xl [&>[data-slot=button]:not(:first-child)]:-ml-px",
10
+ vertical:
11
+ "flex-col [&>[data-slot=button]]:rounded-none [&>[data-slot=button]:first-child]:rounded-t-xl [&>[data-slot=button]:last-child]:rounded-b-xl [&>[data-slot=button]:not(:first-child)]:-mt-px",
12
+ },
13
+ attached: {
14
+ true: "",
15
+ false: "gap-1",
16
+ },
17
+ },
18
+ defaultVariants: {
19
+ orientation: "horizontal",
20
+ attached: true,
21
+ },
22
+ });
23
+
24
+ type ButtonGroupProps = React.HTMLAttributes<HTMLDivElement> &
25
+ VariantProps<typeof buttonGroupVariants>;
26
+
27
+ const ButtonGroup = React.forwardRef<HTMLDivElement, ButtonGroupProps>(
28
+ ({ className, orientation, attached, ...props }, ref) => (
29
+ <div
30
+ ref={ref}
31
+ role="group"
32
+ data-slot="button-group"
33
+ className={cn(buttonGroupVariants({ orientation, attached }), className)}
34
+ {...props}
35
+ />
36
+ )
37
+ );
38
+ ButtonGroup.displayName = "ButtonGroup";
39
+
40
+ export { ButtonGroup, buttonGroupVariants };