@fpkit/acss 0.5.11 → 0.5.13

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 (312) hide show
  1. package/README.md +514 -18
  2. package/libs/chunk-23ANBDCR.js +8 -0
  3. package/libs/chunk-23ANBDCR.js.map +1 -0
  4. package/libs/chunk-2LTJ7HHX.cjs +18 -0
  5. package/libs/chunk-2LTJ7HHX.cjs.map +1 -0
  6. package/libs/chunk-2Y7W75TT.js +9 -0
  7. package/libs/chunk-2Y7W75TT.js.map +1 -0
  8. package/libs/chunk-3MKLDCKQ.cjs +31 -0
  9. package/libs/chunk-3MKLDCKQ.cjs.map +1 -0
  10. package/libs/chunk-5M57K4SW.js +8 -0
  11. package/libs/chunk-5M57K4SW.js.map +1 -0
  12. package/libs/chunk-5S4ORA4C.cjs +15 -0
  13. package/libs/chunk-5S4ORA4C.cjs.map +1 -0
  14. package/libs/chunk-772NRB75.js +9 -0
  15. package/libs/chunk-772NRB75.js.map +1 -0
  16. package/libs/chunk-AHDJGCG5.cjs +15 -0
  17. package/libs/chunk-AHDJGCG5.cjs.map +1 -0
  18. package/libs/chunk-B7F5FS6D.cjs +16 -0
  19. package/libs/chunk-B7F5FS6D.cjs.map +1 -0
  20. package/libs/chunk-BHRQBJRY.js +8 -0
  21. package/libs/chunk-BHRQBJRY.js.map +1 -0
  22. package/libs/chunk-D4YLRWAO.cjs +18 -0
  23. package/libs/chunk-D4YLRWAO.cjs.map +1 -0
  24. package/libs/chunk-ETFLFC2S.js +10 -0
  25. package/libs/chunk-ETFLFC2S.js.map +1 -0
  26. package/libs/chunk-G55UJ53G.cjs +16 -0
  27. package/libs/chunk-G55UJ53G.cjs.map +1 -0
  28. package/libs/chunk-GZ4QFPRY.js +9 -0
  29. package/libs/chunk-GZ4QFPRY.js.map +1 -0
  30. package/libs/chunk-IYUN2EW3.cjs +15 -0
  31. package/libs/chunk-IYUN2EW3.cjs.map +1 -0
  32. package/libs/chunk-J32EZPYD.cjs +15 -0
  33. package/libs/chunk-J32EZPYD.cjs.map +1 -0
  34. package/libs/chunk-JJ43O4Y5.js +8 -0
  35. package/libs/chunk-JJ43O4Y5.js.map +1 -0
  36. package/libs/chunk-KUKIVRC2.js +7 -0
  37. package/libs/chunk-KUKIVRC2.js.map +1 -0
  38. package/libs/chunk-L75OQKEI.cjs +13 -0
  39. package/libs/chunk-L75OQKEI.cjs.map +1 -0
  40. package/libs/chunk-LT5KZ2QW.cjs +22 -0
  41. package/libs/chunk-LT5KZ2QW.cjs.map +1 -0
  42. package/libs/chunk-M5RRNTVX.cjs +15 -0
  43. package/libs/chunk-M5RRNTVX.cjs.map +1 -0
  44. package/libs/chunk-NGTJDDFO.js +8 -0
  45. package/libs/chunk-NGTJDDFO.js.map +1 -0
  46. package/libs/chunk-OK5QEIMD.cjs +17 -0
  47. package/libs/chunk-OK5QEIMD.cjs.map +1 -0
  48. package/libs/chunk-P2DC76ZZ.cjs +18 -0
  49. package/libs/chunk-P2DC76ZZ.cjs.map +1 -0
  50. package/libs/chunk-P7TTEYCD.js +7 -0
  51. package/libs/chunk-P7TTEYCD.js.map +1 -0
  52. package/libs/chunk-PQ2K3BM6.cjs +17 -0
  53. package/libs/chunk-PQ2K3BM6.cjs.map +1 -0
  54. package/libs/chunk-QLZWHAMK.js +8 -0
  55. package/libs/chunk-QLZWHAMK.js.map +1 -0
  56. package/libs/chunk-RIVUMPOG.js +8 -0
  57. package/libs/chunk-RIVUMPOG.js.map +1 -0
  58. package/libs/chunk-ROZI23GS.cjs +15 -0
  59. package/libs/chunk-ROZI23GS.cjs.map +1 -0
  60. package/libs/chunk-S7BABR7Z.cjs +13 -0
  61. package/libs/chunk-S7BABR7Z.cjs.map +1 -0
  62. package/libs/chunk-SMYRLO3E.js +8 -0
  63. package/libs/chunk-SMYRLO3E.js.map +1 -0
  64. package/libs/chunk-TYRCEX2L.js +8 -0
  65. package/libs/chunk-TYRCEX2L.js.map +1 -0
  66. package/libs/chunk-VUH3FXGJ.js +11 -0
  67. package/libs/chunk-VUH3FXGJ.js.map +1 -0
  68. package/libs/chunk-XBA562WW.js +8 -0
  69. package/libs/chunk-XBA562WW.js.map +1 -0
  70. package/libs/chunk-XTQKWY7W.cjs +32 -0
  71. package/libs/chunk-XTQKWY7W.cjs.map +1 -0
  72. package/libs/chunk-ZANSFMTD.js +9 -0
  73. package/libs/chunk-ZANSFMTD.js.map +1 -0
  74. package/libs/component-props-a8a2f97e.d.ts +38 -0
  75. package/libs/components/alert/alert.css +1 -1
  76. package/libs/components/alert/alert.css.map +1 -1
  77. package/libs/components/alert/alert.min.css +2 -2
  78. package/libs/components/badge/badge.css +1 -1
  79. package/libs/components/badge/badge.css.map +1 -1
  80. package/libs/components/badge/badge.min.css +2 -2
  81. package/libs/components/breadcrumbs/breadcrumb.cjs +24 -0
  82. package/libs/components/breadcrumbs/breadcrumb.cjs.map +1 -0
  83. package/libs/components/breadcrumbs/breadcrumb.d.cts +290 -0
  84. package/libs/components/breadcrumbs/breadcrumb.d.ts +290 -0
  85. package/libs/components/breadcrumbs/breadcrumb.js +5 -0
  86. package/libs/components/breadcrumbs/breadcrumb.js.map +1 -0
  87. package/libs/components/button.cjs +19 -0
  88. package/libs/components/button.cjs.map +1 -0
  89. package/libs/components/button.d.cts +16 -0
  90. package/libs/components/button.d.ts +16 -0
  91. package/libs/components/button.js +4 -0
  92. package/libs/components/button.js.map +1 -0
  93. package/libs/components/buttons/button.css +1 -1
  94. package/libs/components/buttons/button.css.map +1 -1
  95. package/libs/components/buttons/button.min.css +2 -2
  96. package/libs/components/card.cjs +31 -0
  97. package/libs/components/card.cjs.map +1 -0
  98. package/libs/components/card.d.cts +302 -0
  99. package/libs/components/card.d.ts +302 -0
  100. package/libs/components/card.js +4 -0
  101. package/libs/components/card.js.map +1 -0
  102. package/libs/components/cards/card.css +1 -1
  103. package/libs/components/cards/card.css.map +1 -1
  104. package/libs/components/cards/card.min.css +2 -2
  105. package/libs/components/details/details.css +1 -1
  106. package/libs/components/details/details.css.map +1 -1
  107. package/libs/components/details/details.min.css +2 -2
  108. package/libs/components/dialog/dialog.cjs +22 -0
  109. package/libs/components/dialog/dialog.cjs.map +1 -0
  110. package/libs/components/dialog/dialog.css +1 -1
  111. package/libs/components/dialog/dialog.css.map +1 -1
  112. package/libs/components/dialog/dialog.d.cts +105 -0
  113. package/libs/components/dialog/dialog.d.ts +105 -0
  114. package/libs/components/dialog/dialog.js +7 -0
  115. package/libs/components/dialog/dialog.js.map +1 -0
  116. package/libs/components/dialog/dialog.min.css +2 -2
  117. package/libs/components/form/fields.cjs +19 -0
  118. package/libs/components/form/fields.cjs.map +1 -0
  119. package/libs/components/form/fields.d.cts +24 -0
  120. package/libs/components/form/fields.d.ts +24 -0
  121. package/libs/components/form/fields.js +4 -0
  122. package/libs/components/form/fields.js.map +1 -0
  123. package/libs/components/form/inputs.cjs +19 -0
  124. package/libs/components/form/inputs.cjs.map +1 -0
  125. package/libs/components/form/inputs.d.cts +2 -0
  126. package/libs/components/form/inputs.d.ts +2 -0
  127. package/libs/components/form/inputs.js +4 -0
  128. package/libs/components/form/inputs.js.map +1 -0
  129. package/libs/components/form/textarea.cjs +19 -0
  130. package/libs/components/form/textarea.cjs.map +1 -0
  131. package/libs/components/form/textarea.d.cts +29 -0
  132. package/libs/components/form/textarea.d.ts +29 -0
  133. package/libs/components/form/textarea.js +4 -0
  134. package/libs/components/form/textarea.js.map +1 -0
  135. package/libs/components/heading/heading.cjs +10 -0
  136. package/libs/components/heading/heading.cjs.map +1 -0
  137. package/libs/components/heading/heading.d.cts +3 -0
  138. package/libs/components/heading/heading.d.ts +3 -0
  139. package/libs/components/heading/heading.js +4 -0
  140. package/libs/components/heading/heading.js.map +1 -0
  141. package/libs/components/icons/icon.cjs +19 -0
  142. package/libs/components/icons/icon.cjs.map +1 -0
  143. package/libs/{icons-31ace3de.d.ts → components/icons/icon.d.cts} +151 -61
  144. package/libs/components/icons/icon.d.ts +445 -0
  145. package/libs/components/icons/icon.js +4 -0
  146. package/libs/components/icons/icon.js.map +1 -0
  147. package/libs/components/images/img.css +1 -1
  148. package/libs/components/images/img.css.map +1 -1
  149. package/libs/components/images/img.min.css +2 -2
  150. package/libs/components/link/link.cjs +19 -0
  151. package/libs/components/link/link.cjs.map +1 -0
  152. package/libs/components/link/link.d.cts +19 -0
  153. package/libs/components/link/link.d.ts +19 -0
  154. package/libs/components/link/link.js +4 -0
  155. package/libs/components/link/link.js.map +1 -0
  156. package/libs/components/list/list.cjs +23 -0
  157. package/libs/components/list/list.cjs.map +1 -0
  158. package/libs/components/list/list.d.cts +39 -0
  159. package/libs/components/list/list.d.ts +39 -0
  160. package/libs/components/list/list.js +4 -0
  161. package/libs/components/list/list.js.map +1 -0
  162. package/libs/components/modal.cjs +14 -0
  163. package/libs/components/modal.cjs.map +1 -0
  164. package/libs/components/modal.d.cts +35 -0
  165. package/libs/components/modal.d.ts +35 -0
  166. package/libs/components/modal.js +5 -0
  167. package/libs/components/modal.js.map +1 -0
  168. package/libs/components/nav/nav.cjs +28 -0
  169. package/libs/components/nav/nav.cjs.map +1 -0
  170. package/libs/components/nav/nav.d.cts +44 -0
  171. package/libs/components/nav/nav.d.ts +44 -0
  172. package/libs/components/nav/nav.js +5 -0
  173. package/libs/components/nav/nav.js.map +1 -0
  174. package/libs/components/popover/popover.cjs +23 -0
  175. package/libs/components/popover/popover.cjs.map +1 -0
  176. package/libs/components/popover/popover.d.cts +40 -0
  177. package/libs/components/popover/popover.d.ts +40 -0
  178. package/libs/components/popover/popover.js +4 -0
  179. package/libs/components/popover/popover.js.map +1 -0
  180. package/libs/components/tables/table.cjs +21 -0
  181. package/libs/components/tables/table.cjs.map +1 -0
  182. package/libs/components/tables/table.d.cts +36 -0
  183. package/libs/components/tables/table.d.ts +36 -0
  184. package/libs/components/tables/table.js +4 -0
  185. package/libs/components/tables/table.js.map +1 -0
  186. package/libs/components/text/text.cjs +23 -0
  187. package/libs/components/text/text.cjs.map +1 -0
  188. package/libs/components/text/text.d.cts +30 -0
  189. package/libs/components/text/text.d.ts +30 -0
  190. package/libs/components/text/text.js +4 -0
  191. package/libs/components/text/text.js.map +1 -0
  192. package/libs/heading-3648c538.d.ts +250 -0
  193. package/libs/hooks.cjs +7 -0
  194. package/libs/hooks.d.cts +5 -0
  195. package/libs/hooks.d.ts +5 -0
  196. package/libs/hooks.js +3 -0
  197. package/libs/icons.cjs +3 -2
  198. package/libs/icons.d.cts +3 -1
  199. package/libs/icons.d.ts +3 -1
  200. package/libs/icons.js +2 -1
  201. package/libs/index.cjs +174 -62
  202. package/libs/index.cjs.map +1 -1
  203. package/libs/index.css +1 -1
  204. package/libs/index.css.map +1 -1
  205. package/libs/index.d.cts +529 -446
  206. package/libs/index.d.ts +529 -446
  207. package/libs/index.js +36 -7
  208. package/libs/index.js.map +1 -1
  209. package/libs/inputs-f3a216db.d.ts +45 -0
  210. package/libs/ui-645f95b5.d.ts +285 -0
  211. package/package.json +2 -2
  212. package/src/components/README-UI.mdx +416 -0
  213. package/src/components/alert/ACCESSIBILITY.md +319 -0
  214. package/src/components/alert/README.mdx +475 -19
  215. package/src/components/alert/alert.scss +113 -6
  216. package/src/components/alert/alert.stories.tsx +372 -0
  217. package/src/components/alert/alert.test.tsx +762 -0
  218. package/src/components/alert/alert.tsx +331 -66
  219. package/src/components/alert/views/alert-actions.tsx +13 -0
  220. package/src/components/alert/views/alert-content.tsx +17 -0
  221. package/src/components/alert/views/alert-icon.tsx +53 -0
  222. package/src/components/alert/views/alert-screen-reader-text.tsx +30 -0
  223. package/src/components/alert/views/alert-title.tsx +23 -0
  224. package/src/components/alert/views/alert-view.tsx +158 -0
  225. package/src/components/alert/views/index.ts +12 -0
  226. package/src/components/badge/badge.mdx +186 -49
  227. package/src/components/badge/badge.scss +20 -2
  228. package/src/components/badge/badge.stories.tsx +160 -14
  229. package/src/components/badge/badge.test.tsx +179 -0
  230. package/src/components/badge/badge.tsx +97 -4
  231. package/src/components/breadcrumbs/README.mdx +364 -45
  232. package/src/components/breadcrumbs/__snapshots__/breadcrumb.test.tsx.snap +152 -0
  233. package/src/components/breadcrumbs/breadcrumb.stories.tsx +7 -3
  234. package/src/components/breadcrumbs/breadcrumb.test.tsx +490 -0
  235. package/src/components/breadcrumbs/breadcrumb.tsx +427 -170
  236. package/src/components/button.ts +2 -0
  237. package/src/components/buttons/button.scss +34 -31
  238. package/src/components/buttons/button.stories.tsx +35 -0
  239. package/src/components/card.ts +2 -0
  240. package/src/components/cards/README.mdx +657 -0
  241. package/src/components/cards/card.scss +22 -0
  242. package/src/components/cards/card.stories.tsx +167 -5
  243. package/src/components/cards/card.test.tsx +360 -20
  244. package/src/components/cards/card.tsx +200 -79
  245. package/src/components/cards/card.types.ts +135 -0
  246. package/src/components/cards/card.utils.ts +79 -0
  247. package/src/components/details/ACCESSIBILITY-REVIEW-LIVE.md +1050 -0
  248. package/src/components/details/ACCESSIBILITY-REVIEW.md +502 -0
  249. package/src/components/details/README.mdx +437 -69
  250. package/src/components/details/details.scss +16 -0
  251. package/src/components/details/details.test.tsx +385 -0
  252. package/src/components/details/details.tsx +101 -69
  253. package/src/components/details/details.types.ts +76 -0
  254. package/src/components/dialog/README.mdx +513 -110
  255. package/src/components/dialog/dialog-modal.tsx +79 -56
  256. package/src/components/dialog/dialog.scss +53 -3
  257. package/src/components/dialog/dialog.stories.tsx +10 -7
  258. package/src/components/dialog/dialog.test.tsx +450 -0
  259. package/src/components/dialog/dialog.tsx +69 -59
  260. package/src/components/dialog/dialog.types.ts +133 -0
  261. package/src/components/dialog/views/dialog-footer.tsx +54 -11
  262. package/src/components/dialog/views/dialog-header.tsx +20 -15
  263. package/src/components/heading/heading.stories.tsx +44 -4
  264. package/src/components/heading/heading.tsx +89 -23
  265. package/src/components/icons/README.mdx +332 -0
  266. package/src/components/icons/icon.stories.tsx +74 -1
  267. package/src/components/icons/icon.tsx +89 -1
  268. package/src/components/icons/types.ts +47 -0
  269. package/src/components/images/README.mdx +340 -24
  270. package/src/components/images/img.scss +19 -3
  271. package/src/components/images/img.stories.tsx +424 -15
  272. package/src/components/images/img.test.tsx +354 -25
  273. package/src/components/images/img.tsx +186 -63
  274. package/src/components/images/img.types.ts +211 -0
  275. package/src/components/modal.ts +1 -0
  276. package/src/components/title/MIGRATION.md +199 -0
  277. package/src/components/title/README.md +326 -0
  278. package/src/components/title/README.mdx +452 -0
  279. package/src/components/title/title.stories.tsx +393 -0
  280. package/src/components/title/title.test.tsx +251 -0
  281. package/src/components/title/title.tsx +219 -0
  282. package/src/components/ui.stories.tsx +894 -0
  283. package/src/components/ui.test.tsx +559 -0
  284. package/src/components/ui.tsx +266 -15
  285. package/src/components/word-count/README.md +240 -0
  286. package/src/hooks.ts +1 -0
  287. package/src/index.ts +51 -19
  288. package/src/sass/_properties.scss +1 -0
  289. package/src/styles/alert/alert.css +94 -4
  290. package/src/styles/alert/alert.css.map +1 -1
  291. package/src/styles/badge/badge.css +20 -2
  292. package/src/styles/badge/badge.css.map +1 -1
  293. package/src/styles/buttons/button.css +31 -31
  294. package/src/styles/buttons/button.css.map +1 -1
  295. package/src/styles/cards/card.css +16 -0
  296. package/src/styles/cards/card.css.map +1 -1
  297. package/src/styles/details/details.css +19 -0
  298. package/src/styles/details/details.css.map +1 -1
  299. package/src/styles/dialog/dialog.css +43 -2
  300. package/src/styles/dialog/dialog.css.map +1 -1
  301. package/src/styles/images/img.css +15 -3
  302. package/src/styles/images/img.css.map +1 -1
  303. package/src/styles/index.css +240 -43
  304. package/src/styles/index.css.map +1 -1
  305. package/src/test/setup.d.ts +9 -0
  306. package/src/test/setup.ts +53 -1
  307. package/libs/chunk-PWVRDQ3R.js +0 -8
  308. package/libs/chunk-PWVRDQ3R.js.map +0 -1
  309. package/libs/chunk-SVS4MX3U.cjs +0 -31
  310. package/libs/chunk-SVS4MX3U.cjs.map +0 -1
  311. package/src/components/cards/README.md +0 -80
  312. package/src/components/dialog/hooks/useClickOutside.ts +0 -33
@@ -6,39 +6,165 @@ import { Meta } from "@storybook/addon-docs/blocks";
6
6
 
7
7
  ## Summary
8
8
 
9
- The `Alert` component is a customizable component for displaying status messages
10
- with different severity levels. It supports multiple severity types (default,
11
- info, success, warning, error) and can include optional titles and dismissal
12
- functionality.
9
+ The `Alert` component is a highly customizable and accessible component for displaying status messages with different severity levels. It supports multiple severity types (default, info, success, warning, error), visual variants, auto-dismiss functionality, exit animations, and optional action buttons. **Fully WCAG 2.1 Level AA compliant** with comprehensive accessibility features.
13
10
 
14
11
  ## Features
15
12
 
16
- - Multiple severity levels with matching visual indicators
17
- - Optional title and dismissible states
18
- - Accessible by default with appropriate ARIA attributes
19
- - Customizable icons through `iconProps`
13
+ - **Multiple Severity Levels** - Info, success, warning, error, and default states with matching visual indicators
14
+ - **Visual Variants** - Choose from outlined (default), filled, or soft styles
15
+ - **Flexible Content** - Simple text mode or complex layouts with the `contentType` prop
16
+ - **Exit Animations** - Smooth fade-out and slide-up transitions using CSS
17
+ - **Auto-Dismiss with Pause** - Automatic dismissal that pauses on hover/focus (WCAG 2.2.1)
18
+ - **Keyboard Support** - ESC key dismisses dismissible alerts
19
+ - **Custom Actions** - Add custom action buttons alongside the message
20
+ - **Icon Customization** - Adjust icon size or hide icons completely
21
+ - **Configurable Headings** - Maintain proper document hierarchy with `titleLevel` prop
22
+ - **Auto-Focus** - Automatically focus critical alerts for accessibility
23
+ - **Screen Reader Support** - Severity announcements and proper ARIA attributes
24
+ - **WCAG 2.1 Level AA Compliant** - Meets all accessibility standards including color contrast, touch targets, and focus indicators
20
25
 
21
26
  ## Props
22
27
 
23
28
  ```tsx
24
29
  export type AlertProps = {
30
+ /**
31
+ * Whether the alert is open.
32
+ */
25
33
  open: boolean;
34
+
35
+ /**
36
+ * The severity level of the alert.
37
+ * @default "default"
38
+ */
26
39
  severity?: "default" | "info" | "success" | "warning" | "error";
40
+
41
+ /**
42
+ * The main message content.
43
+ */
27
44
  children: React.ReactNode;
45
+
46
+ /**
47
+ * Optional title for the alert.
48
+ */
28
49
  title?: string;
50
+
51
+ /**
52
+ * Whether the alert can be dismissed.
53
+ * @default false
54
+ */
29
55
  dismissible?: boolean;
56
+
57
+ /**
58
+ * Callback when alert is dismissed.
59
+ */
30
60
  onDismiss?: () => void;
61
+
62
+ /**
63
+ * Size of the icon in pixels.
64
+ * @default 24
65
+ */
66
+ iconSize?: number;
67
+
68
+ /**
69
+ * Whether to hide the icon.
70
+ */
71
+ hideIcon?: boolean;
72
+
73
+ /**
74
+ * Additional props to pass to the Icon component.
75
+ */
31
76
  iconProps?: IconProps;
77
+
78
+ /**
79
+ * Duration in milliseconds before the alert automatically dismisses.
80
+ * Set to 0 or undefined to disable auto-dismiss.
81
+ * @default undefined
82
+ */
83
+ autoHideDuration?: number;
84
+
85
+ /**
86
+ * Whether to pause auto-dismiss when hovered or focused.
87
+ * Complies with WCAG 2.2.1 (Timing Adjustable).
88
+ * @default true
89
+ */
90
+ pauseOnHover?: boolean;
91
+
92
+ /**
93
+ * Semantic heading level for the title (2-6).
94
+ * When undefined, uses default heading level.
95
+ * Use this to maintain proper document hierarchy.
96
+ * @default 3
97
+ */
98
+ titleLevel?: 2 | 3 | 4 | 5 | 6;
99
+
100
+ /**
101
+ * Custom action buttons to display in the alert.
102
+ */
103
+ actions?: React.ReactNode;
104
+
105
+ /**
106
+ * Whether to automatically focus the alert when it becomes visible.
107
+ * Useful for critical alerts that require immediate attention.
108
+ * @default false
109
+ */
110
+ autoFocus?: boolean;
111
+
112
+ /**
113
+ * Visual variant of the alert.
114
+ * - outlined: Border with lighter background (default)
115
+ * - filled: Solid colored background
116
+ * - soft: No border, subtle background
117
+ * @default "outlined"
118
+ */
119
+ variant?: "outlined" | "filled" | "soft";
120
+
121
+ /**
122
+ * Content rendering mode for alert children.
123
+ * - "text": Wraps children in paragraph tag (default, for simple text)
124
+ * - "node": Renders children directly (for complex layouts, lists, or custom components)
125
+ * @default "text"
126
+ */
127
+ contentType?: "text" | "node";
32
128
  } & React.ComponentProps<typeof UI>;
33
129
  ```
34
130
 
35
131
  ## Technical Details
36
132
 
37
- The `Alert` component uses the `UI` component for rendering and supports various
38
- severity levels with corresponding ARIA attributes for accessibility. It also
39
- allows for custom icons through the `iconProps` prop.
133
+ ### Component Architecture
134
+
135
+ The `Alert` component uses the `UI` component for rendering and includes:
136
+
137
+ - **Animation State Management** - Separate `isVisible` and `shouldRender` states for smooth exit animations
138
+ - **Auto-Dismiss Timer** - Automatic cleanup of setTimeout when component unmounts or alert is dismissed
139
+ - **Keyboard Event Handler** - ESC key support with proper cleanup
140
+ - **Memoized Icons** - Performance-optimized icon rendering using `useMemo`
141
+ - **ARIA Attributes** - Proper `role="alert"`, `aria-live`, and `aria-atomic` for screen readers
142
+
143
+ ### Accessibility Features (WCAG 2.1 Level AA Compliant)
144
+
145
+ - **ARIA Roles** - Uses `role="alert"` for proper screen reader announcements
146
+ - **Live Regions** - `aria-live="polite"` for info/success/warning, `aria-live="assertive"` for errors
147
+ - **Screen Reader Announcements** - Visually hidden severity text ("Error:", "Warning:", etc.) for context
148
+ - **Keyboard Navigation** - ESC key dismisses alerts when `dismissible` is true
149
+ - **Focus Management** - Optional auto-focus for critical alerts via `autoFocus` prop with visible focus indicators
150
+ - **Semantic HTML** - Configurable heading levels (h2-h6) via `titleLevel` prop for proper document hierarchy
151
+ - **Flexible Content Structure** - `contentType` prop enables semantic HTML for complex content (lists, multiple paragraphs)
152
+ - **Touch Target Compliance** - Dismiss button meets 44×44px minimum size (WCAG 2.5.5)
153
+ - **Pause on Interaction** - Auto-dismiss pauses when alert is hovered or focused (WCAG 2.2.1)
154
+ - **Color Contrast** - All text meets 4.5:1 minimum contrast ratio (WCAG 1.4.3)
155
+ - **Focus Indicators** - 2px visible outline for keyboard navigation (WCAG 2.4.7)
156
+ - **Reduced Motion Support** - Respects `prefers-reduced-motion` user preference
157
+
158
+ ### Animation Behavior
159
+
160
+ Exit animations use CSS transitions (300ms duration) for smooth fade-out and slide-up effects. The component:
40
161
 
41
- ## Usage Example
162
+ 1. Sets `isVisible` to `false` when dismissed
163
+ 2. Waits for CSS transition to complete (300ms)
164
+ 3. Removes component from DOM by setting `shouldRender` to `false`
165
+ 4. Calls `onDismiss` callback after animation completes
166
+
167
+ ## Usage Examples
42
168
 
43
169
  ### Basic Usage
44
170
 
@@ -50,7 +176,7 @@ import Alert from "#components/alert";
50
176
  </Alert>;
51
177
  ```
52
178
 
53
- ### Advanced Usage
179
+ ### With Title and Dismissal
54
180
 
55
181
  ```tsx
56
182
  import Alert from "#components/alert";
@@ -61,14 +187,344 @@ import Alert from "#components/alert";
61
187
  title="Error"
62
188
  dismissible={true}
63
189
  onDismiss={() => console.log("Alert dismissed")}
64
- iconProps={{ fill: "#000", size: 24 }}
65
190
  >
66
- This is an error alert with a custom icon.
191
+ This is an error alert with a title and dismiss button.
192
+ </Alert>;
193
+ ```
194
+
195
+ ### Auto-Dismiss Alert
196
+
197
+ Automatically dismiss the alert after 5 seconds:
198
+
199
+ ```tsx
200
+ import Alert from "#components/alert";
201
+
202
+ <Alert
203
+ open={true}
204
+ severity="success"
205
+ title="Success"
206
+ autoHideDuration={5000}
207
+ onDismiss={() => console.log("Auto-dismissed after 5 seconds")}
208
+ >
209
+ Your changes have been saved successfully!
210
+ </Alert>;
211
+ ```
212
+
213
+ ### Alert with Custom Actions
214
+
215
+ Add custom action buttons for user interactions:
216
+
217
+ ```tsx
218
+ import Alert from "#components/alert";
219
+ import Button from "#components/buttons/button";
220
+
221
+ <Alert
222
+ open={true}
223
+ severity="warning"
224
+ title="Unsaved Changes"
225
+ actions={
226
+ <>
227
+ <Button size="sm" onClick={handleSave}>
228
+ Save
229
+ </Button>
230
+ <Button size="sm" onClick={handleDiscard}>
231
+ Discard
232
+ </Button>
233
+ </>
234
+ }
235
+ >
236
+ You have unsaved changes that will be lost.
237
+ </Alert>;
238
+ ```
239
+
240
+ ### Visual Variants
241
+
242
+ Use different visual styles for the alert:
243
+
244
+ ```tsx
245
+ import Alert from "#components/alert";
246
+
247
+ // Outlined (default) - border with lighter background
248
+ <Alert open={true} variant="outlined" severity="info">
249
+ Outlined variant with border
250
+ </Alert>;
251
+
252
+ // Filled - solid colored background
253
+ <Alert open={true} variant="filled" severity="success">
254
+ Filled variant with solid background
255
+ </Alert>;
256
+
257
+ // Soft - no border, subtle background
258
+ <Alert open={true} variant="soft" severity="warning">
259
+ Soft variant with subtle styling
260
+ </Alert>;
261
+ ```
262
+
263
+ ### Hidden Icon
264
+
265
+ Hide the severity icon when needed:
266
+
267
+ ```tsx
268
+ import Alert from "#components/alert";
269
+
270
+ <Alert open={true} hideIcon severity="info">
271
+ This alert has no icon.
272
+ </Alert>;
273
+ ```
274
+
275
+ ### Custom Icon Size
276
+
277
+ Adjust the icon size:
278
+
279
+ ```tsx
280
+ import Alert from "#components/alert";
281
+
282
+ <Alert open={true} iconSize={48} severity="error">
283
+ This alert has a larger icon (48px).
284
+ </Alert>;
285
+ ```
286
+
287
+ ### Critical Alert with Auto-Focus
288
+
289
+ Automatically focus critical alerts for accessibility:
290
+
291
+ ```tsx
292
+ import Alert from "#components/alert";
293
+
294
+ <Alert
295
+ open={true}
296
+ severity="error"
297
+ title="Critical Error"
298
+ autoFocus={true}
299
+ dismissible={true}
300
+ >
301
+ A critical error occurred. Please contact support.
302
+ </Alert>;
303
+ ```
304
+
305
+ ### Complex Content with Lists
306
+
307
+ Use `contentType="node"` for complex layouts with lists:
308
+
309
+ ```tsx
310
+ import Alert from "#components/alert";
311
+
312
+ <Alert
313
+ open={true}
314
+ severity="warning"
315
+ title="Action Required"
316
+ contentType="node"
317
+ dismissible={true}
318
+ >
319
+ <p>Please complete the following security steps:</p>
320
+ <ul>
321
+ <li>Review your recent login activity</li>
322
+ <li>Update your password</li>
323
+ <li>Enable two-factor authentication</li>
324
+ </ul>
325
+ </Alert>;
326
+ ```
327
+
328
+ ### Multiple Paragraphs
329
+
330
+ Render multiple paragraphs for detailed messages:
331
+
332
+ ```tsx
333
+ import Alert from "#components/alert";
334
+
335
+ <Alert
336
+ open={true}
337
+ severity="info"
338
+ title="Privacy Policy Update"
339
+ contentType="node"
340
+ dismissible={true}
341
+ >
342
+ <p>
343
+ We've made significant improvements to our privacy policy to better
344
+ protect your data and give you more control.
345
+ </p>
346
+ <p>
347
+ Please review the changes. The new policy takes effect January 1, 2026.
348
+ </p>
349
+ </Alert>;
350
+ ```
351
+
352
+ ### Custom Layout with contentType
353
+
354
+ Create custom layouts for rich alert content:
355
+
356
+ ```tsx
357
+ import Alert from "#components/alert";
358
+
359
+ <Alert
360
+ open={true}
361
+ severity="success"
362
+ title="Deployment Complete"
363
+ contentType="node"
364
+ dismissible={true}
365
+ >
366
+ <p>Your application has been deployed successfully!</p>
367
+ <div style={{ display: 'flex', gap: '1rem', marginTop: '0.5rem' }}>
368
+ <div><strong>Build #:</strong> 1234</div>
369
+ <div><strong>Duration:</strong> 2m 34s</div>
370
+ <div><strong>Status:</strong> Live</div>
371
+ </div>
372
+ </Alert>;
373
+ ```
374
+
375
+ ### Configurable Heading Hierarchy
376
+
377
+ Maintain proper document structure with `titleLevel`:
378
+
379
+ ```tsx
380
+ import Alert from "#components/alert";
381
+
382
+ // In a section with h2 heading
383
+ <section>
384
+ <h2>Account Settings</h2>
385
+ <Alert
386
+ open={true}
387
+ severity="info"
388
+ title="Email Verification Required"
389
+ titleLevel={3}
390
+ dismissible={true}
391
+ >
392
+ Please verify your email address to continue.
393
+ </Alert>
394
+ </section>;
395
+ ```
396
+
397
+ ### Advanced Example
398
+
399
+ Combine multiple features:
400
+
401
+ ```tsx
402
+ import Alert from "#components/alert";
403
+ import Button from "#components/buttons/button";
404
+
405
+ <Alert
406
+ open={true}
407
+ severity="warning"
408
+ title="Session Expiring Soon"
409
+ variant="filled"
410
+ autoFocus={true}
411
+ dismissible={true}
412
+ autoHideDuration={30000}
413
+ onDismiss={() => console.log("Alert dismissed")}
414
+ iconSize={40}
415
+ actions={
416
+ <Button size="sm" onClick={handleExtendSession}>
417
+ Extend Session
418
+ </Button>
419
+ }
420
+ >
421
+ Your session will expire in 5 minutes. Save your work or extend your session.
67
422
  </Alert>;
68
423
  ```
69
424
 
70
- ### Additional Notes
425
+ ## Keyboard Interactions
426
+
427
+ | Key | Action |
428
+ | ----- | ---------------------------------------------- |
429
+ | `ESC` | Dismisses the alert (when `dismissible=true`) |
430
+ | `Tab` | Moves focus to dismiss button or action buttons|
431
+
432
+ ## Visual Variants
433
+
434
+ ### Outlined (Default)
435
+ - Border with background color
436
+ - Icon in severity color
437
+ - Default variant for most use cases
438
+
439
+ ### Filled
440
+ - Solid background in severity color
441
+ - White text and icon
442
+ - High visual emphasis
443
+ - Best for critical alerts
444
+
445
+ ### Soft
446
+ - No border
447
+ - Subtle background color
448
+ - Low visual weight
449
+ - Best for informational messages
450
+
451
+ ## Best Practices
452
+
453
+ ### When to Use Each Severity
454
+
455
+ - **Default** - Generic notifications without specific status
456
+ - **Info** - Informational messages that don't require action
457
+ - **Success** - Confirmation of successful actions
458
+ - **Warning** - Alerts requiring attention but not critical
459
+ - **Error** - Critical errors requiring immediate attention
460
+
461
+ ### Auto-Dismiss Guidelines
462
+
463
+ - Use for **success** and **info** alerts (non-critical)
464
+ - Avoid for **error** and **warning** alerts (user should explicitly dismiss)
465
+ - Recommended duration: 5000-7000ms for readable messages
466
+ - Always provide `onDismiss` callback for cleanup
467
+
468
+ ### Accessibility Guidelines
469
+
470
+ - Use `autoFocus` only for critical errors that require immediate attention
471
+ - Always provide meaningful titles for better screen reader experience
472
+ - Ensure action buttons have descriptive labels
473
+ - Test with keyboard-only navigation
474
+
475
+ ### Action Buttons
476
+
477
+ - Limit to 2-3 action buttons for clarity
478
+ - Use small button sizes (`size="sm"`)
479
+ - Primary action first, secondary actions after
480
+ - Always include dismiss option for dismissible alerts
481
+
482
+ ### Content Type Selection
483
+
484
+ Choose the appropriate `contentType` based on your content:
485
+
486
+ **Use `contentType="text"` (default) when:**
487
+ - Displaying simple, single-line or single-paragraph text
488
+ - Content is purely text without HTML structure
489
+ - You want automatic semantic paragraph wrapping
490
+
491
+ **Use `contentType="node"` when:**
492
+ - Including lists (ul, ol) in your alert
493
+ - Rendering multiple paragraphs with different styling
494
+ - Using custom components or complex layouts
495
+ - Need fine-grained control over HTML structure
496
+ - Content includes interactive elements
497
+
498
+ ### Heading Hierarchy
499
+
500
+ Maintain proper document structure with `titleLevel`:
501
+
502
+ - Always consider the parent heading level
503
+ - Use `titleLevel={2}` for alerts in main content areas
504
+ - Use `titleLevel={3}` for alerts within sections
505
+ - Use `titleLevel={4}` or higher for nested subsections
506
+ - Screen readers use heading levels for navigation
507
+
508
+ **Example:**
509
+ ```tsx
510
+ <h1>Dashboard</h1>
511
+ <h2>Notifications</h2>
512
+ <Alert titleLevel={3} title="New Message">...</Alert>
513
+ <h2>Settings</h2>
514
+ <Alert titleLevel={3} title="Update Available">...</Alert>
515
+ ```
516
+
517
+ ## Additional Notes
71
518
 
72
- - The `Alert` component is designed to be accessible by default.
73
- - The `dismissible` prop allows the alert to be dismissed by the user.
74
- - Custom icons can be provided through the `iconProps` prop.
519
+ - **WCAG 2.1 Level AA Compliant** - Meets all accessibility standards including color contrast, touch targets, focus indicators, and screen reader support
520
+ - **Flexible Content Rendering** - `contentType` prop supports both simple text and complex HTML structures while maintaining semantic correctness
521
+ - **Screen Reader Optimized** - Visually hidden severity text provides context ("Error:", "Warning:", etc.) for screen reader users
522
+ - **Pause on Interaction** - Auto-dismiss automatically pauses when users hover or focus the alert (WCAG 2.2.1)
523
+ - **Semantic Heading Levels** - `titleLevel` prop enables proper document hierarchy for accessibility and SEO
524
+ - **Exit Animations** - GPU-accelerated CSS transitions with automatic cleanup and reduced-motion support
525
+ - **Performance Optimized** - Severity icons are memoized, timers auto-cleanup on unmount
526
+ - **Keyboard Accessible** - ESC key dismissal with proper event listener cleanup
527
+ - **Touch-Friendly** - Dismiss button meets 44×44px minimum touch target size
528
+ - **Focus Management** - Visible 2px focus indicators for keyboard navigation
529
+ - **Custom Icons** - Fine-grained icon control through `iconProps` for advanced use cases
530
+ - **Backward Compatible** - All new features have sensible defaults and zero breaking changes
@@ -1,3 +1,16 @@
1
+ /* Screen reader only utility class */
2
+ .sr-only {
3
+ position: absolute;
4
+ width: 1px;
5
+ height: 1px;
6
+ padding: 0;
7
+ margin: -1px;
8
+ overflow: hidden;
9
+ clip: rect(0, 0, 0, 0);
10
+ white-space: nowrap;
11
+ border-width: 0;
12
+ }
13
+
1
14
  [role="alert"] {
2
15
  /* Success colors */
3
16
  --alert-success-bg: #e6f4ea;
@@ -19,6 +32,9 @@
19
32
  --alert-info-border: #0288d1;
20
33
  --alert-info-text: #084154;
21
34
 
35
+ /* Animation */
36
+ --alert-transition-duration: 0.3s;
37
+
22
38
  --alert-border: thin solid currentColor;
23
39
 
24
40
  background-color: var(--alert-bg, whitesmoke);
@@ -30,11 +46,37 @@
30
46
  line-height: 1.6;
31
47
  display: flex;
32
48
  flex-direction: row;
33
- // align-items: center;
34
49
  border-radius: var(--alert-border-radius, var(--border-radius));
35
- border: var(--alert-border);
36
50
  gap: var(--alert-gap, var(--spc-4));
37
- div {
51
+
52
+ /* Exit animations */
53
+ transition:
54
+ opacity var(--alert-transition-duration) ease,
55
+ transform var(--alert-transition-duration) ease;
56
+ opacity: 1;
57
+ transform: translateY(0);
58
+
59
+ &:not([data-visible="true"]) {
60
+ opacity: 0;
61
+ transform: translateY(-0.5rem);
62
+ }
63
+
64
+ @media (prefers-reduced-motion: reduce) {
65
+ transition-duration: 0.01ms;
66
+ }
67
+
68
+ /* Focus indicators for keyboard navigation (WCAG 2.4.7) */
69
+ &:focus {
70
+ outline: 2px solid currentColor;
71
+ outline-offset: 2px;
72
+ }
73
+
74
+ /* Hide focus outline for mouse clicks, keep for keyboard */
75
+ &:focus:not(:focus-visible) {
76
+ outline: none;
77
+ }
78
+
79
+ .alert-icon {
38
80
  margin-block-start: 0;
39
81
  align-items: center;
40
82
  }
@@ -42,8 +84,26 @@
42
84
  .alert-message {
43
85
  flex: 2;
44
86
  margin-block-start: 0;
45
- h3 {
46
- margin-block-end: 0;
87
+
88
+ /* Title styles for both heading and strong elements */
89
+ .alert-title {
90
+ margin-block-end: var(--spc-1, 0.25rem);
91
+ margin-block-start: 0;
92
+ font-weight: var(--alert-title-weight, 600);
93
+ font-size: var(--alert-title-size, inherit);
94
+ line-height: 1.4;
95
+ }
96
+
97
+ /* Reset heading-specific styles */
98
+ h2.alert-title,
99
+ h3.alert-title,
100
+ h4.alert-title,
101
+ h5.alert-title,
102
+ h6.alert-title {
103
+ margin: 0;
104
+ margin-block-end: var(--spc-1, 0.25rem);
105
+ font-size: inherit;
106
+ font-weight: var(--alert-title-weight, 600);
47
107
  }
48
108
  }
49
109
 
@@ -74,7 +134,54 @@
74
134
  button {
75
135
  &[data-btn~="icon"] {
76
136
  --btn-bg: transparent;
77
- // max-height: 1.5rem;
78
137
  }
79
138
  }
139
+
140
+ * + div {
141
+ margin-block-start: var(--spc-1);
142
+ }
143
+
144
+ /* Variant: Filled - Solid colored background */
145
+ &[data-variant="filled"] {
146
+ border: none;
147
+
148
+ &[data-alert~="info"] {
149
+ --alert-bg: var(--alert-info-border);
150
+ --alert-color: white;
151
+ }
152
+
153
+ &[data-alert~="warning"] {
154
+ --alert-bg: var(--alert-warning-border);
155
+ --alert-color: white;
156
+ }
157
+
158
+ &[data-alert~="error"] {
159
+ --alert-bg: var(--alert-error-border);
160
+ --alert-color: white;
161
+ }
162
+
163
+ &[data-alert~="success"] {
164
+ --alert-bg: var(--alert-success-border);
165
+ --alert-color: white;
166
+ }
167
+
168
+ &[data-alert~="default"] {
169
+ --alert-bg: #757575;
170
+ --alert-color: white;
171
+ }
172
+ }
173
+
174
+ /* Variant: Soft - No border, subtle background */
175
+ &[data-variant="soft"] {
176
+ border: none;
177
+ }
178
+
179
+ /* Variant: Outlined - Default with border (no additional styles needed) */
180
+ &[data-variant="outlined"] {
181
+ /* This is the default variant, styles already applied above */
182
+ }
183
+
184
+ p {
185
+ font-size: 0.875rem;
186
+ }
80
187
  }