@inspirare/design-system 0.0.23 → 0.0.25

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 (297) hide show
  1. package/README.md +82 -61
  2. package/dist/book-logo-filled.svg +55 -0
  3. package/dist/components/ui/accessibility-improvements.js +26 -23
  4. package/dist/components/ui/accordion.js +34 -24
  5. package/dist/components/ui/alert-dialog.js +91 -57
  6. package/dist/components/ui/alert.js +38 -26
  7. package/dist/components/ui/aspect-ratio.js +11 -3
  8. package/dist/components/ui/avatar.js +30 -8
  9. package/dist/components/ui/badge.js +20 -14
  10. package/dist/components/ui/breadcrumb.js +69 -56
  11. package/dist/components/ui/button-group.js +17 -13
  12. package/dist/components/ui/button.js +19 -15
  13. package/dist/components/ui/calendar.js +63 -59
  14. package/dist/components/ui/card.js +11 -9
  15. package/dist/components/ui/carousel.js +70 -75
  16. package/dist/components/ui/chart.js +75 -72
  17. package/dist/components/ui/checkbox.js +4 -5
  18. package/dist/components/ui/collapsible.js +12 -14
  19. package/dist/components/ui/color-picker.js +60 -80
  20. package/dist/components/ui/combobox.js +153 -33
  21. package/dist/components/ui/command.js +50 -48
  22. package/dist/components/ui/context-menu.js +129 -68
  23. package/dist/components/ui/dialog.js +65 -60
  24. package/dist/components/ui/drawer.js +81 -40
  25. package/dist/components/ui/dropdown-menu.js +100 -87
  26. package/dist/components/ui/empty.js +7 -6
  27. package/dist/components/ui/field.js +44 -47
  28. package/dist/components/ui/form.js +22 -23
  29. package/dist/components/ui/hover-card.js +14 -11
  30. package/dist/components/ui/input-group.js +16 -13
  31. package/dist/components/ui/input-otp.js +37 -32
  32. package/dist/components/ui/input.js +9 -7
  33. package/dist/components/ui/item.js +42 -36
  34. package/dist/components/ui/kbd.js +2 -1
  35. package/dist/components/ui/label.js +6 -7
  36. package/dist/components/ui/menubar.js +124 -93
  37. package/dist/components/ui/navigation-menu.js +79 -54
  38. package/dist/components/ui/pagination.js +78 -58
  39. package/dist/components/ui/popover.js +35 -16
  40. package/dist/components/ui/progress.js +37 -13
  41. package/dist/components/ui/radio-group.js +14 -14
  42. package/dist/components/ui/resizable.js +24 -15
  43. package/dist/components/ui/scroll-area.js +29 -11
  44. package/dist/components/ui/select.js +116 -56
  45. package/dist/components/ui/separator.js +5 -7
  46. package/dist/components/ui/sheet.js +47 -42
  47. package/dist/components/ui/sidebar.js +279 -248
  48. package/dist/components/ui/skeleton.js +4 -40
  49. package/dist/components/ui/slider.js +27 -29
  50. package/dist/components/ui/sonner.js +27 -10
  51. package/dist/components/ui/spinner.js +2 -0
  52. package/dist/components/ui/switch.js +3 -4
  53. package/dist/components/ui/table.js +6 -6
  54. package/dist/components/ui/tabs.js +45 -22
  55. package/dist/components/ui/textarea.js +3 -2
  56. package/dist/components/ui/theme-toggle.js +38 -41
  57. package/dist/components/ui/toggle-group.js +30 -21
  58. package/dist/components/ui/toggle.js +8 -9
  59. package/dist/components/ui/tooltip.js +28 -23
  60. package/dist/index.css +1 -1
  61. package/dist/index.d.ts +446 -468
  62. package/dist/index.js +58 -58
  63. package/package.json +38 -37
  64. package/src/App.tsx +28 -34
  65. package/src/components/branding/assets/book-logo-filled.svg +55 -0
  66. package/src/components/branding/logo/logo.tsx +56 -0
  67. package/src/components/ui/accessibility-improvements.stories.tsx +18 -0
  68. package/src/components/ui/accessibility-improvements.test.tsx +13 -0
  69. package/src/components/ui/accessibility-improvements.tsx +16 -6
  70. package/src/components/ui/accordion.stories.tsx +19 -0
  71. package/src/components/ui/accordion.test.tsx +14 -0
  72. package/src/components/ui/accordion.tsx +28 -20
  73. package/src/components/ui/alert-dialog.stories.tsx +19 -0
  74. package/src/components/ui/alert-dialog.test.tsx +14 -0
  75. package/src/components/ui/alert-dialog.tsx +159 -123
  76. package/src/components/ui/alert.stories.tsx +19 -0
  77. package/src/components/ui/alert.test.tsx +14 -0
  78. package/src/components/ui/alert.tsx +60 -41
  79. package/src/components/ui/aspect-ratio.stories.tsx +19 -0
  80. package/src/components/ui/aspect-ratio.test.tsx +14 -0
  81. package/src/components/ui/aspect-ratio.tsx +19 -2
  82. package/src/components/ui/attachment.stories.tsx +19 -0
  83. package/src/components/ui/attachment.test.tsx +14 -0
  84. package/src/components/ui/attachment.tsx +209 -0
  85. package/src/components/ui/avatar.stories.tsx +19 -0
  86. package/src/components/ui/avatar.test.tsx +14 -0
  87. package/src/components/ui/avatar.tsx +73 -17
  88. package/src/components/ui/badge.stories.tsx +19 -0
  89. package/src/components/ui/badge.test.tsx +14 -0
  90. package/src/components/ui/badge.tsx +33 -25
  91. package/src/components/ui/breadcrumb.stories.tsx +19 -0
  92. package/src/components/ui/breadcrumb.test.tsx +14 -0
  93. package/src/components/ui/breadcrumb.tsx +98 -86
  94. package/src/components/ui/bubble.stories.tsx +19 -0
  95. package/src/components/ui/bubble.test.tsx +14 -0
  96. package/src/components/ui/bubble.tsx +130 -0
  97. package/src/components/ui/button-group.stories.tsx +19 -0
  98. package/src/components/ui/button-group.test.tsx +14 -0
  99. package/src/components/ui/button-group.tsx +26 -20
  100. package/src/components/ui/button.stories.tsx +19 -0
  101. package/src/components/ui/button.test.tsx +14 -0
  102. package/src/components/ui/button.tsx +30 -31
  103. package/src/components/ui/calendar.stories.tsx +19 -0
  104. package/src/components/ui/calendar.test.tsx +14 -0
  105. package/src/components/ui/calendar.tsx +28 -26
  106. package/src/components/ui/card.stories.tsx +19 -0
  107. package/src/components/ui/card.test.tsx +14 -0
  108. package/src/components/ui/card.tsx +30 -17
  109. package/src/components/ui/carousel.stories.tsx +19 -0
  110. package/src/components/ui/carousel.test.tsx +14 -0
  111. package/src/components/ui/carousel.tsx +115 -135
  112. package/src/components/ui/chart.stories.tsx +18 -0
  113. package/src/components/ui/chart.test.tsx +13 -0
  114. package/src/components/ui/chart.tsx +220 -216
  115. package/src/components/ui/checkbox.stories.tsx +19 -0
  116. package/src/components/ui/checkbox.test.tsx +14 -0
  117. package/src/components/ui/checkbox.tsx +7 -10
  118. package/src/components/ui/collapsible.stories.tsx +19 -0
  119. package/src/components/ui/collapsible.test.tsx +14 -0
  120. package/src/components/ui/collapsible.tsx +11 -26
  121. package/src/components/ui/color-picker.stories.tsx +19 -0
  122. package/src/components/ui/color-picker.test.tsx +14 -0
  123. package/src/components/ui/color-picker.tsx +36 -26
  124. package/src/components/ui/combobox.stories.tsx +19 -0
  125. package/src/components/ui/combobox.test.tsx +14 -0
  126. package/src/components/ui/combobox.tsx +281 -96
  127. package/src/components/ui/command.stories.tsx +19 -0
  128. package/src/components/ui/command.test.tsx +14 -0
  129. package/src/components/ui/command.tsx +59 -47
  130. package/src/components/ui/context-menu.stories.tsx +19 -0
  131. package/src/components/ui/context-menu.test.tsx +14 -0
  132. package/src/components/ui/context-menu.tsx +231 -160
  133. package/src/components/ui/dialog.stories.tsx +19 -0
  134. package/src/components/ui/dialog.test.tsx +14 -0
  135. package/src/components/ui/dialog.tsx +81 -72
  136. package/src/components/ui/direction.stories.tsx +19 -0
  137. package/src/components/ui/direction.test.tsx +14 -0
  138. package/src/components/ui/direction.tsx +6 -0
  139. package/src/components/ui/drawer.stories.tsx +19 -0
  140. package/src/components/ui/drawer.test.tsx +14 -0
  141. package/src/components/ui/drawer.tsx +143 -64
  142. package/src/components/ui/dropdown-menu.stories.tsx +19 -0
  143. package/src/components/ui/dropdown-menu.test.tsx +14 -0
  144. package/src/components/ui/dropdown-menu.tsx +199 -153
  145. package/src/components/ui/empty.stories.tsx +18 -0
  146. package/src/components/ui/empty.test.tsx +13 -0
  147. package/src/components/ui/empty.tsx +11 -9
  148. package/src/components/ui/field.stories.tsx +18 -0
  149. package/src/components/ui/field.test.tsx +13 -0
  150. package/src/components/ui/field.tsx +26 -32
  151. package/src/components/ui/form.stories.tsx +22 -0
  152. package/src/components/ui/form.test.tsx +15 -0
  153. package/src/components/ui/form.tsx +1 -2
  154. package/src/components/ui/hover-card.stories.tsx +19 -0
  155. package/src/components/ui/hover-card.test.tsx +14 -0
  156. package/src/components/ui/hover-card.tsx +34 -32
  157. package/src/components/ui/input-group.stories.tsx +18 -0
  158. package/src/components/ui/input-group.test.tsx +13 -0
  159. package/src/components/ui/input-group.tsx +21 -28
  160. package/src/components/ui/input-otp.stories.tsx +19 -0
  161. package/src/components/ui/input-otp.test.tsx +14 -0
  162. package/src/components/ui/input-otp.tsx +58 -42
  163. package/src/components/ui/input.stories.tsx +19 -0
  164. package/src/components/ui/input.test.tsx +14 -0
  165. package/src/components/ui/input.tsx +9 -8
  166. package/src/components/ui/item.stories.tsx +18 -0
  167. package/src/components/ui/item.test.tsx +13 -0
  168. package/src/components/ui/item.tsx +38 -28
  169. package/src/components/ui/kbd.stories.tsx +18 -0
  170. package/src/components/ui/kbd.test.tsx +13 -0
  171. package/src/components/ui/kbd.tsx +3 -3
  172. package/src/components/ui/label.stories.tsx +18 -0
  173. package/src/components/ui/label.test.tsx +13 -0
  174. package/src/components/ui/label.tsx +7 -11
  175. package/src/components/ui/marker.stories.tsx +19 -0
  176. package/src/components/ui/marker.test.tsx +14 -0
  177. package/src/components/ui/marker.tsx +73 -0
  178. package/src/components/ui/menubar.stories.tsx +19 -0
  179. package/src/components/ui/menubar.test.tsx +14 -0
  180. package/src/components/ui/menubar.tsx +226 -202
  181. package/src/components/ui/message-scroller.stories.tsx +19 -0
  182. package/src/components/ui/message-scroller.test.tsx +14 -0
  183. package/src/components/ui/message-scroller.tsx +131 -0
  184. package/src/components/ui/message.stories.tsx +19 -0
  185. package/src/components/ui/message.test.tsx +14 -0
  186. package/src/components/ui/message.tsx +94 -0
  187. package/src/components/ui/native-select.stories.tsx +18 -0
  188. package/src/components/ui/native-select.test.tsx +13 -0
  189. package/src/components/ui/native-select.tsx +63 -0
  190. package/src/components/ui/navigation-menu.stories.tsx +19 -0
  191. package/src/components/ui/navigation-menu.test.tsx +14 -0
  192. package/src/components/ui/navigation-menu.tsx +145 -103
  193. package/src/components/ui/pagination.stories.tsx +19 -0
  194. package/src/components/ui/pagination.test.tsx +14 -0
  195. package/src/components/ui/pagination.tsx +114 -83
  196. package/src/components/ui/popover.stories.tsx +19 -0
  197. package/src/components/ui/popover.test.tsx +14 -0
  198. package/src/components/ui/popover.tsx +68 -33
  199. package/src/components/ui/progress.stories.tsx +19 -0
  200. package/src/components/ui/progress.test.tsx +14 -0
  201. package/src/components/ui/progress.tsx +67 -15
  202. package/src/components/ui/questionnaire.stories.tsx +19 -0
  203. package/src/components/ui/questionnaire.test.tsx +14 -0
  204. package/src/components/ui/questionnaire.tsx +324 -0
  205. package/src/components/ui/radio-group.stories.tsx +19 -0
  206. package/src/components/ui/radio-group.test.tsx +14 -0
  207. package/src/components/ui/radio-group.tsx +15 -20
  208. package/src/components/ui/resizable.stories.tsx +19 -0
  209. package/src/components/ui/resizable.test.tsx +14 -0
  210. package/src/components/ui/resizable.tsx +37 -30
  211. package/src/components/ui/scroll-area.stories.tsx +19 -0
  212. package/src/components/ui/scroll-area.test.tsx +14 -0
  213. package/src/components/ui/scroll-area.tsx +41 -19
  214. package/src/components/ui/select.stories.tsx +19 -0
  215. package/src/components/ui/select.test.tsx +32 -0
  216. package/src/components/ui/select.tsx +172 -78
  217. package/src/components/ui/separator.stories.tsx +19 -0
  218. package/src/components/ui/separator.test.tsx +14 -0
  219. package/src/components/ui/separator.tsx +8 -11
  220. package/src/components/ui/sheet.stories.tsx +19 -0
  221. package/src/components/ui/sheet.test.tsx +14 -0
  222. package/src/components/ui/sheet.tsx +56 -71
  223. package/src/components/ui/sidebar.stories.tsx +18 -0
  224. package/src/components/ui/sidebar.test.tsx +13 -0
  225. package/src/components/ui/sidebar.tsx +469 -513
  226. package/src/components/ui/skeleton.stories.tsx +19 -0
  227. package/src/components/ui/skeleton.test.tsx +14 -0
  228. package/src/components/ui/skeleton.tsx +8 -114
  229. package/src/components/ui/slider.stories.tsx +19 -0
  230. package/src/components/ui/slider.test.tsx +14 -0
  231. package/src/components/ui/slider.tsx +31 -40
  232. package/src/components/ui/sonner.stories.tsx +19 -0
  233. package/src/components/ui/sonner.test.tsx +14 -0
  234. package/src/components/ui/sonner.tsx +39 -7
  235. package/src/components/ui/spinner.stories.tsx +18 -0
  236. package/src/components/ui/spinner.test.tsx +13 -0
  237. package/src/components/ui/spinner.tsx +3 -7
  238. package/src/components/ui/switch.stories.tsx +19 -0
  239. package/src/components/ui/switch.test.tsx +14 -0
  240. package/src/components/ui/switch.tsx +4 -7
  241. package/src/components/ui/table.stories.tsx +19 -0
  242. package/src/components/ui/table.test.tsx +14 -0
  243. package/src/components/ui/table.tsx +17 -17
  244. package/src/components/ui/tabs.stories.tsx +19 -0
  245. package/src/components/ui/tabs.test.tsx +14 -0
  246. package/src/components/ui/tabs.tsx +71 -31
  247. package/src/components/ui/textarea.stories.tsx +19 -0
  248. package/src/components/ui/textarea.test.tsx +14 -0
  249. package/src/components/ui/textarea.tsx +7 -5
  250. package/src/components/ui/theme-toggle.stories.tsx +18 -0
  251. package/src/components/ui/theme-toggle.test.tsx +13 -0
  252. package/src/components/ui/theme-toggle.tsx +35 -37
  253. package/src/components/ui/toggle-group.stories.tsx +19 -0
  254. package/src/components/ui/toggle-group.test.tsx +14 -0
  255. package/src/components/ui/toggle-group.tsx +41 -25
  256. package/src/components/ui/toggle.stories.tsx +19 -0
  257. package/src/components/ui/toggle.test.tsx +14 -0
  258. package/src/components/ui/toggle.tsx +17 -19
  259. package/src/components/ui/tooltip.stories.tsx +19 -0
  260. package/src/components/ui/tooltip.test.tsx +14 -0
  261. package/src/components/ui/tooltip.tsx +53 -44
  262. package/src/demo/AIDemo.tsx +50 -0
  263. package/src/demo/ButtonsDemo.tsx +41 -18
  264. package/src/demo/CalendarDemo.tsx +1 -1
  265. package/src/demo/FeedbackDemo.tsx +4 -6
  266. package/src/demo/FormsDemo.tsx +34 -11
  267. package/src/demo/NavigationDemo.tsx +38 -13
  268. package/src/demo/OverlaysDemo.tsx +22 -36
  269. package/src/demo/update-demos.js +82 -0
  270. package/src/index.css +66 -46
  271. package/src/lib/utils.ts +3 -3
  272. package/src/stories/Button.stories.ts +54 -0
  273. package/src/stories/Button.tsx +36 -0
  274. package/src/stories/Configure.mdx +388 -0
  275. package/src/stories/Header.stories.ts +34 -0
  276. package/src/stories/Header.tsx +55 -0
  277. package/src/stories/Page.stories.ts +33 -0
  278. package/src/stories/Page.tsx +73 -0
  279. package/src/stories/assets/accessibility.png +0 -0
  280. package/src/stories/assets/accessibility.svg +1 -0
  281. package/src/stories/assets/addon-library.png +0 -0
  282. package/src/stories/assets/assets.png +0 -0
  283. package/src/stories/assets/avif-test-image.avif +0 -0
  284. package/src/stories/assets/context.png +0 -0
  285. package/src/stories/assets/discord.svg +1 -0
  286. package/src/stories/assets/docs.png +0 -0
  287. package/src/stories/assets/figma-plugin.png +0 -0
  288. package/src/stories/assets/github.svg +1 -0
  289. package/src/stories/assets/share.png +0 -0
  290. package/src/stories/assets/styling.png +0 -0
  291. package/src/stories/assets/testing.png +0 -0
  292. package/src/stories/assets/theming.png +0 -0
  293. package/src/stories/assets/tutorials.svg +1 -0
  294. package/src/stories/assets/youtube.svg +1 -0
  295. package/src/stories/button.css +30 -0
  296. package/src/stories/header.css +32 -0
  297. package/src/stories/page.css +68 -0
@@ -0,0 +1,32 @@
1
+ import { render } from '@testing-library/react';
2
+ import { axe } from 'jest-axe';
3
+ import { Select, SelectTrigger, SelectValue, SelectContent, SelectItem } from "./select";
4
+
5
+
6
+ describe('Select Accessibility', () => {
7
+ it('should have no accessibility violations in basic render', async () => {
8
+ const Wrapper = () => (
9
+ <Select><SelectTrigger aria-label="Select a theme" className="w-[180px]"><SelectValue placeholder="Theme" /></SelectTrigger><SelectContent><SelectItem value="light">Light</SelectItem><SelectItem value="dark">Dark</SelectItem><SelectItem value="system">System</SelectItem></SelectContent></Select>
10
+ );
11
+ const { container } = render(<Wrapper />);
12
+ const results = await axe(container);
13
+ expect(results).toHaveNoViolations();
14
+ });
15
+
16
+ it('should display the default label instead of the value on initial render', () => {
17
+ const Wrapper = () => (
18
+ <Select defaultValue="dark">
19
+ <SelectTrigger aria-label="Select a theme" className="w-[180px]">
20
+ <SelectValue placeholder="Theme" />
21
+ </SelectTrigger>
22
+ <SelectContent>
23
+ <SelectItem value="light">Light</SelectItem>
24
+ <SelectItem value="dark">Dark Theme</SelectItem>
25
+ <SelectItem value="system">System</SelectItem>
26
+ </SelectContent>
27
+ </Select>
28
+ );
29
+ const { container } = render(<Wrapper />);
30
+ expect(container.textContent).toContain('Dark Theme');
31
+ });
32
+ });
@@ -1,27 +1,95 @@
1
- "use client";
1
+ "use client"
2
2
 
3
- import * as React from "react";
4
- import * as SelectPrimitive from "@radix-ui/react-select";
5
- import { CheckIcon, ChevronDownIcon, ChevronUpIcon } from "lucide-react";
3
+ import * as React from "react"
4
+ import { Select as SelectPrimitive } from "@base-ui/react/select"
6
5
 
7
- import { cn } from "@/lib/utils";
6
+ import { cn } from "@/lib/utils"
7
+ import { ChevronDownIcon, CheckIcon, ChevronUpIcon } from "lucide-react"
8
8
 
9
- function Select({
10
- ...props
11
- }: React.ComponentProps<typeof SelectPrimitive.Root>) {
12
- return <SelectPrimitive.Root data-slot="select" {...props} />;
13
- }
9
+ const SelectContext = React.createContext<{
10
+ registerLabel: (val: any, label: string) => void;
11
+ getLabel: (val: any) => string | undefined;
12
+ } | null>(null);
14
13
 
15
- function SelectGroup({
16
- ...props
17
- }: React.ComponentProps<typeof SelectPrimitive.Group>) {
18
- return <SelectPrimitive.Group data-slot="select-group" {...props} />;
14
+ function Select({ children, ...props }: React.ComponentProps<typeof SelectPrimitive.Root>) {
15
+ const [dynamicLabels, setDynamicLabels] = React.useState<Record<string, string>>({});
16
+
17
+ const staticLabels = React.useMemo(() => {
18
+ const result: Record<string, string> = {};
19
+ const extract = (node: React.ReactNode) => {
20
+ React.Children.forEach(node, (child) => {
21
+ if (!React.isValidElement(child)) return;
22
+ if ((child as any).props && (child as any).props.value !== undefined) {
23
+ if ((child as any).props.children) {
24
+ let label = "";
25
+ React.Children.forEach((child as any).props.children, (grandChild) => {
26
+ if (typeof grandChild === "string" || typeof grandChild === "number") {
27
+ label += grandChild;
28
+ }
29
+ });
30
+ if (label) result[(child as any).props.value] = label;
31
+ }
32
+ }
33
+ if ((child as any).props && (child as any).props.children) {
34
+ extract((child as any).props.children);
35
+ }
36
+ });
37
+ };
38
+ extract(children);
39
+ return result;
40
+ }, [children]);
41
+
42
+ const labels = { ...staticLabels, ...dynamicLabels };
43
+
44
+ const registerLabel = React.useCallback((val: any, label: string) => {
45
+ setDynamicLabels((prev) => {
46
+ if (prev[val] === label) return prev;
47
+ return { ...prev, [val]: label };
48
+ });
49
+ }, []);
50
+
51
+ const getLabel = React.useCallback((val: any) => labels[val], [labels]);
52
+
53
+ return (
54
+ <SelectContext.Provider value={{ registerLabel, getLabel }}>
55
+ <SelectPrimitive.Root {...props}>
56
+ {children}
57
+ </SelectPrimitive.Root>
58
+ </SelectContext.Provider>
59
+ )
60
+ }
61
+ function SelectGroup({ className, ...props }: SelectPrimitive.Group.Props) {
62
+ return (
63
+ <SelectPrimitive.Group
64
+ data-slot="select-group"
65
+ className={cn("scroll-my-1 p-1", className)}
66
+ {...props}
67
+ />
68
+ )
19
69
  }
20
70
 
21
- function SelectValue({
22
- ...props
23
- }: React.ComponentProps<typeof SelectPrimitive.Value>) {
24
- return <SelectPrimitive.Value data-slot="select-value" {...props} />;
71
+ function SelectValue({ className, children, ...props }: SelectPrimitive.Value.Props) {
72
+ const ctx = React.useContext(SelectContext);
73
+
74
+ return (
75
+ <SelectPrimitive.Value
76
+ data-slot="select-value"
77
+ className={cn("flex flex-1 text-left", className)}
78
+ {...props}
79
+ >
80
+ {children ? children : (val: any) => {
81
+ if (!val) return null;
82
+ if (ctx) {
83
+ if (Array.isArray(val)) {
84
+ return val.map(v => ctx.getLabel(v) || v).join(', ');
85
+ }
86
+ const label = ctx.getLabel(val);
87
+ if (label) return label;
88
+ }
89
+ return val;
90
+ }}
91
+ </SelectPrimitive.Value>
92
+ )
25
93
  }
26
94
 
27
95
  function SelectTrigger({
@@ -29,146 +97,172 @@ function SelectTrigger({
29
97
  size = "default",
30
98
  children,
31
99
  ...props
32
- }: React.ComponentProps<typeof SelectPrimitive.Trigger> & {
33
- size?: "sm" | "default";
100
+ }: SelectPrimitive.Trigger.Props & {
101
+ size?: "sm" | "default"
34
102
  }) {
35
103
  return (
36
104
  <SelectPrimitive.Trigger
37
105
  data-slot="select-trigger"
38
106
  data-size={size}
39
107
  className={cn(
40
- "border-input data-[placeholder]:text-muted-foreground [&_svg:not([class*='text-'])]:text-muted-foreground focus-visible:border-ring focus-visible:ring-ring/50 aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive dark:bg-input/30 dark:hover:bg-input/50 flex w-fit cursor-pointer items-center justify-between gap-2 rounded-md border bg-transparent px-3 py-2 text-sm whitespace-nowrap shadow-xs transition-[color,box-shadow] outline-none focus-visible:ring-[3px] disabled:cursor-not-allowed disabled:opacity-50 data-[size=default]:h-9 data-[size=sm]:h-8 *:data-[slot=select-value]:line-clamp-1 *:data-[slot=select-value]:flex *:data-[slot=select-value]:items-center *:data-[slot=select-value]:gap-2 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
108
+ "flex w-fit items-center justify-between gap-1.5 rounded-lg border border-input bg-transparent py-2 pr-2 pl-2.5 text-sm whitespace-nowrap transition-colors outline-none select-none focus-visible:border-ring focus-visible:ring-3 focus-visible:ring-ring/50 disabled:cursor-not-allowed disabled:opacity-50 aria-invalid:border-destructive aria-invalid:ring-3 aria-invalid:ring-destructive/20 data-placeholder:text-muted-foreground data-[size=default]:h-8 data-[size=sm]:h-7 data-[size=sm]:rounded-[min(var(--radius-md),10px)] *:data-[slot=select-value]:line-clamp-1 *:data-[slot=select-value]:flex *:data-[slot=select-value]:items-center *:data-[slot=select-value]:gap-1.5 dark:bg-input/30 dark:hover:bg-input/50 dark:aria-invalid:border-destructive/50 dark:aria-invalid:ring-destructive/40 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
41
109
  className
42
110
  )}
43
111
  {...props}
44
112
  >
45
113
  {children}
46
- <SelectPrimitive.Icon asChild>
47
- <ChevronDownIcon className="size-4 opacity-50" />
48
- </SelectPrimitive.Icon>
114
+ <SelectPrimitive.Icon
115
+ render={
116
+ <ChevronDownIcon className="pointer-events-none size-4 text-muted-foreground" />
117
+ }
118
+ />
49
119
  </SelectPrimitive.Trigger>
50
- );
120
+ )
51
121
  }
52
122
 
53
123
  function SelectContent({
54
124
  className,
55
125
  children,
56
- position = "popper",
126
+ side = "bottom",
127
+ sideOffset = 4,
128
+ align = "center",
129
+ alignOffset = 0,
130
+ alignItemWithTrigger = true,
57
131
  ...props
58
- }: React.ComponentProps<typeof SelectPrimitive.Content>) {
132
+ }: SelectPrimitive.Popup.Props &
133
+ Pick<
134
+ SelectPrimitive.Positioner.Props,
135
+ "align" | "alignOffset" | "side" | "sideOffset" | "alignItemWithTrigger"
136
+ >) {
59
137
  return (
60
138
  <SelectPrimitive.Portal>
61
- <SelectPrimitive.Content
62
- data-slot="select-content"
63
- className={cn(
64
- "bg-popover text-popover-foreground 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-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 relative z-50 max-h-(--radix-select-content-available-height) min-w-[8rem] origin-(--radix-select-content-transform-origin) overflow-x-hidden overflow-y-auto rounded-md border shadow-md",
65
- position === "popper" &&
66
- "data-[side=bottom]:translate-y-1 data-[side=left]:-translate-x-1 data-[side=right]:translate-x-1 data-[side=top]:-translate-y-1",
67
- className
68
- )}
69
- position={position}
70
- {...props}
139
+ <SelectPrimitive.Positioner
140
+ side={side}
141
+ sideOffset={sideOffset}
142
+ align={align}
143
+ alignOffset={alignOffset}
144
+ alignItemWithTrigger={alignItemWithTrigger}
145
+ className="isolate z-50"
71
146
  >
72
- <SelectScrollUpButton />
73
- <SelectPrimitive.Viewport
74
- className={cn(
75
- "p-1",
76
- position === "popper" &&
77
- "h-[var(--radix-select-trigger-height)] w-full min-w-[var(--radix-select-trigger-width)] scroll-my-1"
78
- )}
147
+ <SelectPrimitive.Popup
148
+ data-slot="select-content"
149
+ data-align-trigger={alignItemWithTrigger}
150
+ className={cn("relative isolate z-50 max-h-(--available-height) w-(--anchor-width) min-w-36 origin-(--transform-origin) overflow-x-hidden overflow-y-auto rounded-lg bg-popover text-popover-foreground shadow-md ring-1 ring-foreground/10 duration-100 data-[align-trigger=true]:animate-none data-[side=bottom]:slide-in-from-top-2 data-[side=inline-end]:slide-in-from-left-2 data-[side=inline-start]:slide-in-from-right-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 data-open:animate-in data-open:fade-in-0 data-open:zoom-in-95 data-closed:animate-out data-closed:fade-out-0 data-closed:zoom-out-95", className )}
151
+ {...props}
79
152
  >
80
- {children}
81
- </SelectPrimitive.Viewport>
82
- <SelectScrollDownButton />
83
- </SelectPrimitive.Content>
153
+ <SelectScrollUpButton />
154
+ <SelectPrimitive.List>{children}</SelectPrimitive.List>
155
+ <SelectScrollDownButton />
156
+ </SelectPrimitive.Popup>
157
+ </SelectPrimitive.Positioner>
84
158
  </SelectPrimitive.Portal>
85
- );
159
+ )
86
160
  }
87
161
 
88
162
  function SelectLabel({
89
163
  className,
90
164
  ...props
91
- }: React.ComponentProps<typeof SelectPrimitive.Label>) {
165
+ }: SelectPrimitive.GroupLabel.Props) {
92
166
  return (
93
- <SelectPrimitive.Label
167
+ <SelectPrimitive.GroupLabel
94
168
  data-slot="select-label"
95
- className={cn("text-muted-foreground px-2 py-1.5 text-xs", className)}
169
+ className={cn("px-1.5 py-1 text-xs text-muted-foreground", className)}
96
170
  {...props}
97
171
  />
98
- );
172
+ )
99
173
  }
100
174
 
101
175
  function SelectItem({
102
176
  className,
103
177
  children,
178
+ value,
104
179
  ...props
105
- }: React.ComponentProps<typeof SelectPrimitive.Item>) {
180
+ }: SelectPrimitive.Item.Props) {
181
+ const ctx = React.useContext(SelectContext);
182
+ const textRef = React.useRef<HTMLDivElement>(null);
183
+
184
+ React.useEffect(() => {
185
+ if (value !== undefined && textRef.current && ctx) {
186
+ const text = textRef.current.textContent;
187
+ if (text) {
188
+ ctx.registerLabel(value, text.trim());
189
+ }
190
+ }
191
+ }, [value, ctx, children]);
192
+
106
193
  return (
107
194
  <SelectPrimitive.Item
195
+ value={value}
108
196
  data-slot="select-item"
109
197
  className={cn(
110
- "focus:bg-accent focus:text-accent-foreground [&_svg:not([class*='text-'])]:text-muted-foreground relative flex w-full cursor-pointer items-center gap-2 rounded-sm py-1.5 pr-8 pl-2 text-sm outline-hidden select-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4 *:[span]:last:flex *:[span]:last:items-center *:[span]:last:gap-2",
198
+ "relative flex w-full cursor-pointer items-center gap-1.5 rounded-md py-1 pr-8 pl-1.5 text-sm outline-hidden select-none focus:bg-accent focus:text-accent-foreground not-data-[variant=destructive]:focus:**:text-accent-foreground data-disabled:pointer-events-none data-disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4 *:[span]:last:flex *:[span]:last:items-center *:[span]:last:gap-2",
111
199
  className
112
200
  )}
113
201
  {...props}
114
202
  >
115
- <span className="absolute right-2 flex size-3.5 items-center justify-center">
116
- <SelectPrimitive.ItemIndicator>
117
- <CheckIcon className="size-4" />
118
- </SelectPrimitive.ItemIndicator>
119
- </span>
120
- <SelectPrimitive.ItemText>{children}</SelectPrimitive.ItemText>
203
+ <SelectPrimitive.ItemText ref={textRef} className="flex flex-1 shrink-0 gap-2 whitespace-nowrap">
204
+ {children}
205
+ </SelectPrimitive.ItemText>
206
+ <SelectPrimitive.ItemIndicator
207
+ render={
208
+ <span className="pointer-events-none absolute right-2 flex size-4 items-center justify-center" />
209
+ }
210
+ >
211
+ <CheckIcon className="pointer-events-none" />
212
+ </SelectPrimitive.ItemIndicator>
121
213
  </SelectPrimitive.Item>
122
- );
214
+ )
123
215
  }
124
216
 
125
217
  function SelectSeparator({
126
218
  className,
127
219
  ...props
128
- }: React.ComponentProps<typeof SelectPrimitive.Separator>) {
220
+ }: SelectPrimitive.Separator.Props) {
129
221
  return (
130
222
  <SelectPrimitive.Separator
131
223
  data-slot="select-separator"
132
- className={cn("bg-border pointer-events-none -mx-1 my-1 h-px", className)}
224
+ className={cn("pointer-events-none -mx-1 my-1 h-px bg-border", className)}
133
225
  {...props}
134
226
  />
135
- );
227
+ )
136
228
  }
137
229
 
138
230
  function SelectScrollUpButton({
139
231
  className,
140
232
  ...props
141
- }: React.ComponentProps<typeof SelectPrimitive.ScrollUpButton>) {
233
+ }: React.ComponentProps<typeof SelectPrimitive.ScrollUpArrow>) {
142
234
  return (
143
- <SelectPrimitive.ScrollUpButton
235
+ <SelectPrimitive.ScrollUpArrow
144
236
  data-slot="select-scroll-up-button"
145
237
  className={cn(
146
- "flex cursor-pointer items-center justify-center py-1",
238
+ "top-0 z-10 flex w-full cursor-pointer items-center justify-center bg-popover py-1 [&_svg:not([class*='size-'])]:size-4",
147
239
  className
148
240
  )}
149
241
  {...props}
150
242
  >
151
- <ChevronUpIcon className="size-4" />
152
- </SelectPrimitive.ScrollUpButton>
153
- );
243
+ <ChevronUpIcon
244
+ />
245
+ </SelectPrimitive.ScrollUpArrow>
246
+ )
154
247
  }
155
248
 
156
249
  function SelectScrollDownButton({
157
250
  className,
158
251
  ...props
159
- }: React.ComponentProps<typeof SelectPrimitive.ScrollDownButton>) {
252
+ }: React.ComponentProps<typeof SelectPrimitive.ScrollDownArrow>) {
160
253
  return (
161
- <SelectPrimitive.ScrollDownButton
254
+ <SelectPrimitive.ScrollDownArrow
162
255
  data-slot="select-scroll-down-button"
163
256
  className={cn(
164
- "flex cursor-pointer items-center justify-center py-1",
257
+ "bottom-0 z-10 flex w-full cursor-pointer items-center justify-center bg-popover py-1 [&_svg:not([class*='size-'])]:size-4",
165
258
  className
166
259
  )}
167
260
  {...props}
168
261
  >
169
- <ChevronDownIcon className="size-4" />
170
- </SelectPrimitive.ScrollDownButton>
171
- );
262
+ <ChevronDownIcon
263
+ />
264
+ </SelectPrimitive.ScrollDownArrow>
265
+ )
172
266
  }
173
267
 
174
268
  export {
@@ -182,4 +276,4 @@ export {
182
276
  SelectSeparator,
183
277
  SelectTrigger,
184
278
  SelectValue,
185
- };
279
+ }
@@ -0,0 +1,19 @@
1
+ import type { Meta, StoryObj } from '@storybook/react-vite';
2
+ import { Separator } from "./separator";
3
+
4
+ const meta = {
5
+ title: 'Design System/Separator',
6
+ parameters: { layout: 'centered' },
7
+ tags: ['autodocs'],
8
+ } satisfies Meta;
9
+
10
+ export default meta;
11
+ type Story = StoryObj<typeof meta>;
12
+
13
+ export const Default: Story = {
14
+ render: () => (
15
+ <div className="p-4 w-full h-full flex items-center justify-center">
16
+ <div><div className="space-y-1"><h4 className="text-sm font-medium leading-none">Radix Primitives</h4><p className="text-sm text-muted-foreground">An open-source UI component library.</p></div><Separator className="my-4" /><div className="flex h-5 items-center space-x-4 text-sm"><div>Blog</div><Separator orientation="vertical" /><div>Docs</div></div></div>
17
+ </div>
18
+ )
19
+ };
@@ -0,0 +1,14 @@
1
+ import { render } from '@testing-library/react';
2
+ import { axe } from 'jest-axe';
3
+ import { Separator } from "./separator";
4
+
5
+ describe('Separator Accessibility', () => {
6
+ it('should have no accessibility violations in basic render', async () => {
7
+ const Wrapper = () => (
8
+ <div><div className="space-y-1"><h4 className="text-sm font-medium leading-none">Radix Primitives</h4><p className="text-sm text-muted-foreground">An open-source UI component library.</p></div><Separator className="my-4" /><div className="flex h-5 items-center space-x-4 text-sm"><div>Blog</div><Separator orientation="vertical" /><div>Docs</div></div></div>
9
+ );
10
+ const { container } = render(<Wrapper />);
11
+ const results = await axe(container);
12
+ expect(results).toHaveNoViolations();
13
+ });
14
+ });
@@ -1,28 +1,25 @@
1
- "use client";
1
+ "use client"
2
2
 
3
- import * as React from "react";
4
- import * as SeparatorPrimitive from "@radix-ui/react-separator";
3
+ import { Separator as SeparatorPrimitive } from "@base-ui/react/separator"
5
4
 
6
- import { cn } from "@/lib/utils";
5
+ import { cn } from "@/lib/utils"
7
6
 
8
7
  function Separator({
9
8
  className,
10
9
  orientation = "horizontal",
11
- decorative = true,
12
10
  ...props
13
- }: React.ComponentProps<typeof SeparatorPrimitive.Root>) {
11
+ }: SeparatorPrimitive.Props) {
14
12
  return (
15
- <SeparatorPrimitive.Root
13
+ <SeparatorPrimitive
16
14
  data-slot="separator"
17
- decorative={decorative}
18
15
  orientation={orientation}
19
16
  className={cn(
20
- "bg-border shrink-0 data-[orientation=horizontal]:h-px data-[orientation=horizontal]:w-full data-[orientation=vertical]:h-full data-[orientation=vertical]:w-px",
17
+ "shrink-0 bg-border data-horizontal:h-px data-horizontal:w-full data-vertical:w-px data-vertical:self-stretch",
21
18
  className
22
19
  )}
23
20
  {...props}
24
21
  />
25
- );
22
+ )
26
23
  }
27
24
 
28
- export { Separator };
25
+ export { Separator }
@@ -0,0 +1,19 @@
1
+ import type { Meta, StoryObj } from '@storybook/react-vite';
2
+ import { Sheet, SheetTrigger, SheetContent, SheetHeader, SheetTitle, SheetDescription } from "./sheet";
3
+
4
+ const meta = {
5
+ title: 'Design System/Sheet',
6
+ parameters: { layout: 'centered' },
7
+ tags: ['autodocs'],
8
+ } satisfies Meta;
9
+
10
+ export default meta;
11
+ type Story = StoryObj<typeof meta>;
12
+
13
+ export const Default: Story = {
14
+ render: () => (
15
+ <div className="p-4 w-full h-full flex items-center justify-center">
16
+ <Sheet><SheetTrigger className="px-4 py-2 border rounded">Open</SheetTrigger><SheetContent><SheetHeader><SheetTitle>Are you sure?</SheetTitle><SheetDescription>This action cannot be undone.</SheetDescription></SheetHeader></SheetContent></Sheet>
17
+ </div>
18
+ )
19
+ };
@@ -0,0 +1,14 @@
1
+ import { render } from '@testing-library/react';
2
+ import { axe } from 'jest-axe';
3
+ import { Sheet, SheetTrigger, SheetContent, SheetHeader, SheetTitle, SheetDescription } from "./sheet";
4
+
5
+ describe('Sheet Accessibility', () => {
6
+ it('should have no accessibility violations in basic render', async () => {
7
+ const Wrapper = () => (
8
+ <Sheet><SheetTrigger className="px-4 py-2 border rounded">Open</SheetTrigger><SheetContent><SheetHeader><SheetTitle>Are you sure?</SheetTitle><SheetDescription>This action cannot be undone.</SheetDescription></SheetHeader></SheetContent></Sheet>
9
+ );
10
+ const { container } = render(<Wrapper />);
11
+ const results = await axe(container);
12
+ expect(results).toHaveNoViolations();
13
+ });
14
+ });