@inspirare/design-system 0.0.22 → 0.0.24

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 +98 -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 +42 -41
  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 +14 -0
  216. package/src/components/ui/select.tsx +145 -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,56 @@
1
+ import { cn } from "../../../lib/utils";
2
+
3
+ const LogoWithText = ({
4
+ className,
5
+ width = 24,
6
+ height = 24,
7
+ }: {
8
+ className?: string;
9
+ width?: number;
10
+ height?: number;
11
+ }) => {
12
+ return (
13
+ <div
14
+ className={cn("flex items-center gap-3", className)}
15
+ aria-label="Inspirare"
16
+ role="img"
17
+ >
18
+ <img
19
+ src="/book-logo-filled.svg"
20
+ alt=""
21
+ aria-hidden="true"
22
+ width={width}
23
+ height={height}
24
+ className="shrink-0"
25
+ />
26
+ <span
27
+ aria-hidden="true"
28
+ className="hidden sm:block font-heading font-bold text-xl text-primary leading-none tracking-wide translate-no translate-y-2"
29
+ >
30
+ Inspirare
31
+ </span>
32
+ </div>
33
+ );
34
+ };
35
+
36
+ const Logo = ({
37
+ className,
38
+ width = 32,
39
+ height = 32,
40
+ }: {
41
+ className?: string;
42
+ width?: number;
43
+ height?: number;
44
+ }) => {
45
+ return (
46
+ <img
47
+ src="/book-logo-filled.svg"
48
+ alt="Inspirare, hub criativo para escritores"
49
+ width={width}
50
+ height={height}
51
+ className={className}
52
+ />
53
+ );
54
+ };
55
+
56
+ export { Logo, LogoWithText };
@@ -0,0 +1,18 @@
1
+ import type { Meta, StoryObj } from '@storybook/react-vite';
2
+
3
+ const meta = {
4
+ title: 'Design System/AccessibilityImprovements',
5
+ parameters: { layout: 'centered' },
6
+ tags: ['autodocs'],
7
+ } satisfies Meta;
8
+
9
+ export default meta;
10
+ type Story = StoryObj<typeof meta>;
11
+
12
+ export const Default: Story = {
13
+ render: () => (
14
+ <div className="p-4 w-full h-full flex items-center justify-center">
15
+ <div className="p-4 border rounded bg-muted/50 text-muted-foreground text-sm">AccessibilityImprovements — needs manual template</div>
16
+ </div>
17
+ )
18
+ };
@@ -0,0 +1,13 @@
1
+ import { render } from '@testing-library/react';
2
+ import { axe } from 'jest-axe';
3
+
4
+ describe('AccessibilityImprovements Accessibility', () => {
5
+ it('should have no accessibility violations in basic render', async () => {
6
+ const Wrapper = () => (
7
+ <div className="p-4 border rounded bg-muted/50 text-muted-foreground text-sm">AccessibilityImprovements — needs manual template</div>
8
+ );
9
+ const { container } = render(<Wrapper />);
10
+ const results = await axe(container);
11
+ expect(results).toHaveNoViolations();
12
+ });
13
+ });
@@ -3,8 +3,12 @@
3
3
  import { useEffect } from "react";
4
4
 
5
5
  /**
6
- * Hook para melhorar a acessibilidade dos modais
7
- * Gerencia foco, escape key e aria-labels
6
+ * Hook para melhorar a acessibilidade dos modais customizados.
7
+ * Gerencia foco, escape key e aria-labels.
8
+ *
9
+ * @deprecated Se estiver usando os componentes do shadcn (Dialog, Sheet, Drawer)
10
+ * com o preset `base-nova`, este hook NÃO é necessário. O React Aria / Base UI
11
+ * já gerencia Focus Traps e Escape keys nativamente.
8
12
  */
9
13
  export function useModalAccessibility(isOpen: boolean, onClose: () => void) {
10
14
  useEffect(() => {
@@ -38,14 +42,20 @@ export function useModalAccessibility(isOpen: boolean, onClose: () => void) {
38
42
  }
39
43
 
40
44
  /**
41
- * Hook para gerenciar navegação por teclado em tabs
45
+ * Hook para gerenciar navegação por teclado em tabs customizadas.
46
+ *
47
+ * @deprecated Se estiver usando o componente `<Tabs>` do shadcn (Base UI),
48
+ * o React Aria já cuida dessa navegação (Setas, Home, End) automaticamente.
42
49
  */
43
50
  export function useTabKeyboardNavigation(
51
+ containerRef: React.RefObject<HTMLElement | null>,
44
52
  activeTab: string,
45
53
  tabs: Array<{ id: string }>,
46
54
  onTabChange: (tabId: string) => void
47
55
  ) {
48
56
  useEffect(() => {
57
+ const container = containerRef.current;
58
+ if (!container) return;
49
59
  const handleKeyDown = (event: KeyboardEvent) => {
50
60
  if (
51
61
  event.target &&
@@ -79,9 +89,9 @@ export function useTabKeyboardNavigation(
79
89
  }
80
90
  };
81
91
 
82
- document.addEventListener("keydown", handleKeyDown);
83
- return () => document.removeEventListener("keydown", handleKeyDown);
84
- }, [activeTab, tabs, onTabChange]);
92
+ container.addEventListener("keydown", handleKeyDown);
93
+ return () => container.removeEventListener("keydown", handleKeyDown);
94
+ }, [containerRef, activeTab, tabs, onTabChange]);
85
95
  }
86
96
 
87
97
  /**
@@ -0,0 +1,19 @@
1
+ import type { Meta, StoryObj } from '@storybook/react-vite';
2
+ import { Accordion, AccordionItem, AccordionTrigger, AccordionContent } from "./accordion";
3
+
4
+ const meta = {
5
+ title: 'Design System/Accordion',
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
+ <Accordion className="w-full max-w-sm"><AccordionItem value="item-1"><AccordionTrigger>Is it accessible?</AccordionTrigger><AccordionContent>Yes. It adheres to the WAI-ARIA design pattern.</AccordionContent></AccordionItem></Accordion>
17
+ </div>
18
+ )
19
+ };
@@ -0,0 +1,14 @@
1
+ import { render } from '@testing-library/react';
2
+ import { axe } from 'jest-axe';
3
+ import { Accordion, AccordionItem, AccordionTrigger, AccordionContent } from "./accordion";
4
+
5
+ describe('Accordion Accessibility', () => {
6
+ it('should have no accessibility violations in basic render', async () => {
7
+ const Wrapper = () => (
8
+ <Accordion className="w-full max-w-sm"><AccordionItem value="item-1"><AccordionTrigger>Is it accessible?</AccordionTrigger><AccordionContent>Yes. It adheres to the WAI-ARIA design pattern.</AccordionContent></AccordionItem></Accordion>
9
+ );
10
+ const { container } = render(<Wrapper />);
11
+ const results = await axe(container);
12
+ expect(results).toHaveNoViolations();
13
+ });
14
+ });
@@ -1,25 +1,25 @@
1
1
  "use client"
2
2
 
3
- import * as React from "react"
4
- import * as AccordionPrimitive from "@radix-ui/react-accordion"
5
- import { ChevronDownIcon } from "lucide-react"
3
+ import { Accordion as AccordionPrimitive } from "@base-ui/react/accordion"
6
4
 
7
5
  import { cn } from "@/lib/utils"
6
+ import { ChevronDownIcon, ChevronUpIcon } from "lucide-react"
8
7
 
9
- function Accordion({
10
- ...props
11
- }: React.ComponentProps<typeof AccordionPrimitive.Root>) {
12
- return <AccordionPrimitive.Root data-slot="accordion" {...props} />
8
+ function Accordion({ className, ...props }: AccordionPrimitive.Root.Props) {
9
+ return (
10
+ <AccordionPrimitive.Root
11
+ data-slot="accordion"
12
+ className={cn("flex w-full flex-col", className)}
13
+ {...props}
14
+ />
15
+ )
13
16
  }
14
17
 
15
- function AccordionItem({
16
- className,
17
- ...props
18
- }: React.ComponentProps<typeof AccordionPrimitive.Item>) {
18
+ function AccordionItem({ className, ...props }: AccordionPrimitive.Item.Props) {
19
19
  return (
20
20
  <AccordionPrimitive.Item
21
21
  data-slot="accordion-item"
22
- className={cn("border-b last:border-b-0", className)}
22
+ className={cn("not-last:border-b", className)}
23
23
  {...props}
24
24
  />
25
25
  )
@@ -29,19 +29,20 @@ function AccordionTrigger({
29
29
  className,
30
30
  children,
31
31
  ...props
32
- }: React.ComponentProps<typeof AccordionPrimitive.Trigger>) {
32
+ }: AccordionPrimitive.Trigger.Props) {
33
33
  return (
34
34
  <AccordionPrimitive.Header className="flex">
35
35
  <AccordionPrimitive.Trigger
36
36
  data-slot="accordion-trigger"
37
37
  className={cn(
38
- "focus-visible:border-ring focus-visible:ring-ring/50 flex flex-1 cursor-pointer items-start justify-between gap-4 rounded-md py-4 text-left text-sm font-medium transition-all outline-none hover:underline focus-visible:ring-[3px] disabled:pointer-events-none disabled:opacity-50 [&[data-state=open]>svg]:rotate-180",
38
+ "group/accordion-trigger relative flex flex-1 items-start justify-between rounded-lg border border-transparent py-2.5 text-left text-sm font-medium transition-all outline-none cursor-pointer hover:underline focus-visible:border-ring focus-visible:ring-3 focus-visible:ring-ring/50 focus-visible:after:border-ring aria-disabled:pointer-events-none aria-disabled:opacity-50 **:data-[slot=accordion-trigger-icon]:ml-auto **:data-[slot=accordion-trigger-icon]:size-4 **:data-[slot=accordion-trigger-icon]:text-muted-foreground",
39
39
  className
40
40
  )}
41
41
  {...props}
42
42
  >
43
43
  {children}
44
- <ChevronDownIcon className="text-muted-foreground pointer-events-none size-4 shrink-0 translate-y-0.5 transition-transform duration-200" />
44
+ <ChevronDownIcon data-slot="accordion-trigger-icon" className="pointer-events-none shrink-0 group-aria-expanded/accordion-trigger:hidden" />
45
+ <ChevronUpIcon data-slot="accordion-trigger-icon" className="pointer-events-none hidden shrink-0 group-aria-expanded/accordion-trigger:inline" />
45
46
  </AccordionPrimitive.Trigger>
46
47
  </AccordionPrimitive.Header>
47
48
  )
@@ -51,15 +52,22 @@ function AccordionContent({
51
52
  className,
52
53
  children,
53
54
  ...props
54
- }: React.ComponentProps<typeof AccordionPrimitive.Content>) {
55
+ }: AccordionPrimitive.Panel.Props) {
55
56
  return (
56
- <AccordionPrimitive.Content
57
+ <AccordionPrimitive.Panel
57
58
  data-slot="accordion-content"
58
- className="data-[state=closed]:animate-accordion-up data-[state=open]:animate-accordion-down overflow-hidden text-sm"
59
+ className="overflow-hidden text-sm data-open:animate-accordion-down data-closed:animate-accordion-up"
59
60
  {...props}
60
61
  >
61
- <div className={cn("pt-0 pb-4", className)}>{children}</div>
62
- </AccordionPrimitive.Content>
62
+ <div
63
+ className={cn(
64
+ "h-(--accordion-panel-height) pt-0 pb-2.5 data-ending-style:h-0 data-starting-style:h-0 [&_a]:underline [&_a]:underline-offset-3 [&_a]:hover:text-foreground [&_p:not(:last-child)]:mb-4",
65
+ className
66
+ )}
67
+ >
68
+ {children}
69
+ </div>
70
+ </AccordionPrimitive.Panel>
63
71
  )
64
72
  }
65
73
 
@@ -0,0 +1,19 @@
1
+ import type { Meta, StoryObj } from '@storybook/react-vite';
2
+ import { AlertDialog, AlertDialogTrigger, AlertDialogContent, AlertDialogHeader, AlertDialogTitle, AlertDialogDescription, AlertDialogFooter, AlertDialogCancel, AlertDialogAction } from "./alert-dialog";
3
+
4
+ const meta = {
5
+ title: 'Design System/AlertDialog',
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
+ <AlertDialog><AlertDialogTrigger className="px-4 py-2 border rounded">Show Dialog</AlertDialogTrigger><AlertDialogContent><AlertDialogHeader><AlertDialogTitle>Are you absolutely sure?</AlertDialogTitle><AlertDialogDescription>This action cannot be undone.</AlertDialogDescription></AlertDialogHeader><AlertDialogFooter><AlertDialogCancel>Cancel</AlertDialogCancel><AlertDialogAction>Continue</AlertDialogAction></AlertDialogFooter></AlertDialogContent></AlertDialog>
17
+ </div>
18
+ )
19
+ };
@@ -0,0 +1,14 @@
1
+ import { render } from '@testing-library/react';
2
+ import { axe } from 'jest-axe';
3
+ import { AlertDialog, AlertDialogTrigger, AlertDialogContent, AlertDialogHeader, AlertDialogTitle, AlertDialogDescription, AlertDialogFooter, AlertDialogCancel, AlertDialogAction } from "./alert-dialog";
4
+
5
+ describe('AlertDialog Accessibility', () => {
6
+ it('should have no accessibility violations in basic render', async () => {
7
+ const Wrapper = () => (
8
+ <AlertDialog><AlertDialogTrigger className="px-4 py-2 border rounded">Show Dialog</AlertDialogTrigger><AlertDialogContent><AlertDialogHeader><AlertDialogTitle>Are you absolutely sure?</AlertDialogTitle><AlertDialogDescription>This action cannot be undone.</AlertDialogDescription></AlertDialogHeader><AlertDialogFooter><AlertDialogCancel>Cancel</AlertDialogCancel><AlertDialogAction>Continue</AlertDialogAction></AlertDialogFooter></AlertDialogContent></AlertDialog>
9
+ );
10
+ const { container } = render(<Wrapper />);
11
+ const results = await axe(container);
12
+ expect(results).toHaveNoViolations();
13
+ });
14
+ });
@@ -1,151 +1,187 @@
1
- "use client";
1
+ "use client"
2
2
 
3
- import * as AlertDialogPrimitive from "@radix-ui/react-alert-dialog";
4
- import * as React from "react";
3
+ import * as React from "react"
4
+ import { AlertDialog as AlertDialogPrimitive } from "@base-ui/react/alert-dialog"
5
5
 
6
- import { cn } from "@/lib/utils";
7
- import { buttonVariants } from "./button";
6
+ import { cn } from "@/lib/utils"
7
+ import { Button } from "@/components/ui/button"
8
8
 
9
- const AlertDialog = AlertDialogPrimitive.Root;
9
+ function AlertDialog({ ...props }: AlertDialogPrimitive.Root.Props) {
10
+ return <AlertDialogPrimitive.Root data-slot="alert-dialog" {...props} />
11
+ }
10
12
 
11
- const AlertDialogTrigger = React.forwardRef<
12
- React.ElementRef<typeof AlertDialogPrimitive.Trigger>,
13
- React.ComponentPropsWithoutRef<typeof AlertDialogPrimitive.Trigger>
14
- >(({ className, ...props }, ref) => (
15
- <AlertDialogPrimitive.Trigger
16
- className={cn("cursor-pointer", className)}
17
- {...props}
18
- ref={ref}
19
- />
20
- ));
21
- AlertDialogTrigger.displayName = AlertDialogPrimitive.Trigger.displayName;
13
+ function AlertDialogTrigger({ ...props }: AlertDialogPrimitive.Trigger.Props) {
14
+ return (
15
+ <AlertDialogPrimitive.Trigger data-slot="alert-dialog-trigger" {...props} />
16
+ )
17
+ }
22
18
 
23
- const AlertDialogPortal = AlertDialogPrimitive.Portal;
19
+ function AlertDialogPortal({ ...props }: AlertDialogPrimitive.Portal.Props) {
20
+ return (
21
+ <AlertDialogPrimitive.Portal data-slot="alert-dialog-portal" {...props} />
22
+ )
23
+ }
24
24
 
25
- const AlertDialogOverlay = React.forwardRef<
26
- React.ElementRef<typeof AlertDialogPrimitive.Overlay>,
27
- React.ComponentPropsWithoutRef<typeof AlertDialogPrimitive.Overlay>
28
- >(({ className, ...props }, ref) => (
29
- <AlertDialogPrimitive.Overlay
30
- className={cn(
31
- "fixed inset-0 z-50 bg-black/50 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0",
32
- className
33
- )}
34
- {...props}
35
- ref={ref}
36
- />
37
- ));
38
- AlertDialogOverlay.displayName = AlertDialogPrimitive.Overlay.displayName;
25
+ function AlertDialogOverlay({
26
+ className,
27
+ ...props
28
+ }: AlertDialogPrimitive.Backdrop.Props) {
29
+ return (
30
+ <AlertDialogPrimitive.Backdrop
31
+ data-slot="alert-dialog-overlay"
32
+ className={cn(
33
+ "fixed inset-0 isolate z-50 bg-black/10 duration-100 supports-backdrop-filter:backdrop-blur-xs data-open:animate-in data-open:fade-in-0 data-closed:animate-out data-closed:fade-out-0",
34
+ className
35
+ )}
36
+ {...props}
37
+ />
38
+ )
39
+ }
39
40
 
40
- const AlertDialogContent = React.forwardRef<
41
- React.ElementRef<typeof AlertDialogPrimitive.Content>,
42
- React.ComponentPropsWithoutRef<typeof AlertDialogPrimitive.Content>
43
- >(({ className, ...props }, ref) => (
44
- <AlertDialogPortal>
45
- <AlertDialogOverlay />
46
- <AlertDialogPrimitive.Content
47
- ref={ref}
41
+ function AlertDialogContent({
42
+ className,
43
+ size = "default",
44
+ ...props
45
+ }: AlertDialogPrimitive.Popup.Props & {
46
+ size?: "default" | "sm"
47
+ }) {
48
+ return (
49
+ <AlertDialogPortal>
50
+ <AlertDialogOverlay />
51
+ <AlertDialogPrimitive.Popup
52
+ data-slot="alert-dialog-content"
53
+ data-size={size}
54
+ className={cn(
55
+ "group/alert-dialog-content fixed top-1/2 left-1/2 z-50 grid w-full -translate-x-1/2 -translate-y-1/2 gap-4 rounded-xl bg-popover p-4 text-popover-foreground ring-1 ring-foreground/10 duration-100 outline-none data-[size=default]:max-w-xs data-[size=sm]:max-w-xs data-[size=default]:sm:max-w-sm 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",
56
+ className
57
+ )}
58
+ {...props}
59
+ />
60
+ </AlertDialogPortal>
61
+ )
62
+ }
63
+
64
+ function AlertDialogHeader({
65
+ className,
66
+ ...props
67
+ }: React.ComponentProps<"div">) {
68
+ return (
69
+ <div
70
+ data-slot="alert-dialog-header"
48
71
  className={cn(
49
- "fixed left-[50%] top-[50%] z-50 grid w-full max-w-lg translate-x-[-50%] translate-y-[-50%] gap-4 border bg-background p-6 shadow-lg 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 sm:rounded-lg",
72
+ "grid grid-rows-[auto_1fr] place-items-center gap-1.5 text-center has-data-[slot=alert-dialog-media]:grid-rows-[auto_auto_1fr] has-data-[slot=alert-dialog-media]:gap-x-4 sm:group-data-[size=default]/alert-dialog-content:place-items-start sm:group-data-[size=default]/alert-dialog-content:text-left sm:group-data-[size=default]/alert-dialog-content:has-data-[slot=alert-dialog-media]:grid-rows-[auto_1fr]",
50
73
  className
51
74
  )}
52
75
  {...props}
53
76
  />
54
- </AlertDialogPortal>
55
- ));
56
- AlertDialogContent.displayName = AlertDialogPrimitive.Content.displayName;
77
+ )
78
+ }
57
79
 
58
- const AlertDialogHeader = ({
80
+ function AlertDialogFooter({
59
81
  className,
60
82
  ...props
61
- }: React.HTMLAttributes<HTMLDivElement>) => (
62
- <div
63
- className={cn(
64
- "flex flex-col space-y-2 text-center sm:text-left",
65
- className
66
- )}
67
- {...props}
68
- />
69
- );
70
- AlertDialogHeader.displayName = "AlertDialogHeader";
83
+ }: React.ComponentProps<"div">) {
84
+ return (
85
+ <div
86
+ data-slot="alert-dialog-footer"
87
+ className={cn(
88
+ "-mx-4 -mb-4 flex flex-col-reverse gap-2 rounded-b-xl border-t bg-muted/50 p-4 group-data-[size=sm]/alert-dialog-content:grid group-data-[size=sm]/alert-dialog-content:grid-cols-2 sm:flex-row sm:justify-end",
89
+ className
90
+ )}
91
+ {...props}
92
+ />
93
+ )
94
+ }
71
95
 
72
- const AlertDialogFooter = ({
96
+ function AlertDialogMedia({
73
97
  className,
74
98
  ...props
75
- }: React.HTMLAttributes<HTMLDivElement>) => (
76
- <div
77
- className={cn(
78
- "flex flex-col-reverse sm:flex-row sm:justify-end sm:space-x-2",
79
- className
80
- )}
81
- {...props}
82
- />
83
- );
84
- AlertDialogFooter.displayName = "AlertDialogFooter";
99
+ }: React.ComponentProps<"div">) {
100
+ return (
101
+ <div
102
+ data-slot="alert-dialog-media"
103
+ className={cn(
104
+ "mb-2 inline-flex size-10 items-center justify-center rounded-md bg-muted sm:group-data-[size=default]/alert-dialog-content:row-span-2 *:[svg:not([class*='size-'])]:size-6",
105
+ className
106
+ )}
107
+ {...props}
108
+ />
109
+ )
110
+ }
85
111
 
86
- const AlertDialogTitle = React.forwardRef<
87
- React.ElementRef<typeof AlertDialogPrimitive.Title>,
88
- React.ComponentPropsWithoutRef<typeof AlertDialogPrimitive.Title>
89
- >(({ className, ...props }, ref) => (
90
- <AlertDialogPrimitive.Title
91
- ref={ref}
92
- className={cn("text-lg font-semibold", className)}
93
- {...props}
94
- />
95
- ));
96
- AlertDialogTitle.displayName = AlertDialogPrimitive.Title.displayName;
112
+ function AlertDialogTitle({
113
+ className,
114
+ ...props
115
+ }: React.ComponentProps<typeof AlertDialogPrimitive.Title>) {
116
+ return (
117
+ <AlertDialogPrimitive.Title
118
+ data-slot="alert-dialog-title"
119
+ className={cn(
120
+ "font-heading text-base font-medium sm:group-data-[size=default]/alert-dialog-content:group-has-data-[slot=alert-dialog-media]/alert-dialog-content:col-start-2",
121
+ className
122
+ )}
123
+ {...props}
124
+ />
125
+ )
126
+ }
97
127
 
98
- const AlertDialogDescription = React.forwardRef<
99
- React.ElementRef<typeof AlertDialogPrimitive.Description>,
100
- React.ComponentPropsWithoutRef<typeof AlertDialogPrimitive.Description>
101
- >(({ className, ...props }, ref) => (
102
- <AlertDialogPrimitive.Description
103
- ref={ref}
104
- className={cn("text-sm text-muted-foreground", className)}
105
- {...props}
106
- />
107
- ));
108
- AlertDialogDescription.displayName =
109
- AlertDialogPrimitive.Description.displayName;
128
+ function AlertDialogDescription({
129
+ className,
130
+ ...props
131
+ }: React.ComponentProps<typeof AlertDialogPrimitive.Description>) {
132
+ return (
133
+ <AlertDialogPrimitive.Description
134
+ data-slot="alert-dialog-description"
135
+ className={cn(
136
+ "text-sm text-balance text-muted-foreground md:text-pretty *:[a]:underline *:[a]:underline-offset-3 *:[a]:hover:text-foreground",
137
+ className
138
+ )}
139
+ {...props}
140
+ />
141
+ )
142
+ }
110
143
 
111
- const AlertDialogAction = React.forwardRef<
112
- React.ElementRef<typeof AlertDialogPrimitive.Action>,
113
- React.ComponentPropsWithoutRef<typeof AlertDialogPrimitive.Action>
114
- >(({ className, ...props }, ref) => (
115
- <AlertDialogPrimitive.Action
116
- ref={ref}
117
- className={cn(buttonVariants(), className)}
118
- {...props}
119
- />
120
- ));
121
- AlertDialogAction.displayName = AlertDialogPrimitive.Action.displayName;
144
+ function AlertDialogAction({
145
+ className,
146
+ ...props
147
+ }: React.ComponentProps<typeof Button>) {
148
+ return (
149
+ <Button
150
+ data-slot="alert-dialog-action"
151
+ className={cn(className)}
152
+ {...props}
153
+ />
154
+ )
155
+ }
122
156
 
123
- const AlertDialogCancel = React.forwardRef<
124
- React.ElementRef<typeof AlertDialogPrimitive.Cancel>,
125
- React.ComponentPropsWithoutRef<typeof AlertDialogPrimitive.Cancel>
126
- >(({ className, ...props }, ref) => (
127
- <AlertDialogPrimitive.Cancel
128
- ref={ref}
129
- className={cn(
130
- buttonVariants({ variant: "outline" }),
131
- "mt-2 sm:mt-0",
132
- className
133
- )}
134
- {...props}
135
- />
136
- ));
137
- AlertDialogCancel.displayName = AlertDialogPrimitive.Cancel.displayName;
157
+ function AlertDialogCancel({
158
+ className,
159
+ variant = "outline",
160
+ size = "default",
161
+ ...props
162
+ }: AlertDialogPrimitive.Close.Props &
163
+ Pick<React.ComponentProps<typeof Button>, "variant" | "size">) {
164
+ return (
165
+ <AlertDialogPrimitive.Close
166
+ data-slot="alert-dialog-cancel"
167
+ className={cn(className)}
168
+ render={<Button variant={variant} size={size} />}
169
+ {...props}
170
+ />
171
+ )
172
+ }
138
173
 
139
174
  export {
140
175
  AlertDialog,
141
- AlertDialogPortal,
142
- AlertDialogOverlay,
143
- AlertDialogTrigger,
176
+ AlertDialogAction,
177
+ AlertDialogCancel,
144
178
  AlertDialogContent,
145
- AlertDialogHeader,
179
+ AlertDialogDescription,
146
180
  AlertDialogFooter,
181
+ AlertDialogHeader,
182
+ AlertDialogMedia,
183
+ AlertDialogOverlay,
184
+ AlertDialogPortal,
147
185
  AlertDialogTitle,
148
- AlertDialogDescription,
149
- AlertDialogAction,
150
- AlertDialogCancel,
151
- };
186
+ AlertDialogTrigger,
187
+ }
@@ -0,0 +1,19 @@
1
+ import type { Meta, StoryObj } from '@storybook/react-vite';
2
+ import { Alert, AlertTitle, AlertDescription } from "./alert";
3
+
4
+ const meta = {
5
+ title: 'Design System/Alert',
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
+ <Alert><AlertTitle>Heads up!</AlertTitle><AlertDescription>You can add components to your app using the cli.</AlertDescription></Alert>
17
+ </div>
18
+ )
19
+ };
@@ -0,0 +1,14 @@
1
+ import { render } from '@testing-library/react';
2
+ import { axe } from 'jest-axe';
3
+ import { Alert, AlertTitle, AlertDescription } from "./alert";
4
+
5
+ describe('Alert Accessibility', () => {
6
+ it('should have no accessibility violations in basic render', async () => {
7
+ const Wrapper = () => (
8
+ <Alert><AlertTitle>Heads up!</AlertTitle><AlertDescription>You can add components to your app using the cli.</AlertDescription></Alert>
9
+ );
10
+ const { container } = render(<Wrapper />);
11
+ const results = await axe(container);
12
+ expect(results).toHaveNoViolations();
13
+ });
14
+ });