@fpkit/acss 0.5.12 → 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 (264) hide show
  1. package/README.md +89 -0
  2. package/libs/{chunk-DV56L5YX.cjs → chunk-2LTJ7HHX.cjs} +4 -4
  3. package/libs/{chunk-EQ67LF46.js → chunk-2Y7W75TT.js} +3 -3
  4. package/libs/{chunk-KKLTUJFB.cjs → chunk-3MKLDCKQ.cjs} +5 -5
  5. package/libs/chunk-3MKLDCKQ.cjs.map +1 -0
  6. package/libs/{chunk-X3EVB7VS.cjs → chunk-5S4ORA4C.cjs} +3 -3
  7. package/libs/{chunk-O6QZBB6G.js → chunk-772NRB75.js} +5 -5
  8. package/libs/chunk-772NRB75.js.map +1 -0
  9. package/libs/{chunk-6BVXFW7U.cjs → chunk-AHDJGCG5.cjs} +3 -3
  10. package/libs/{chunk-E3XP6BEX.cjs → chunk-B7F5FS6D.cjs} +3 -3
  11. package/libs/chunk-D4YLRWAO.cjs +18 -0
  12. package/libs/chunk-D4YLRWAO.cjs.map +1 -0
  13. package/libs/chunk-ETFLFC2S.js +10 -0
  14. package/libs/chunk-ETFLFC2S.js.map +1 -0
  15. package/libs/chunk-GZ4QFPRY.js +9 -0
  16. package/libs/chunk-GZ4QFPRY.js.map +1 -0
  17. package/libs/{chunk-LHVJKDMA.cjs → chunk-J32EZPYD.cjs} +3 -3
  18. package/libs/chunk-JJ43O4Y5.js +8 -0
  19. package/libs/chunk-JJ43O4Y5.js.map +1 -0
  20. package/libs/chunk-KUKIVRC2.js +7 -0
  21. package/libs/chunk-KUKIVRC2.js.map +1 -0
  22. package/libs/chunk-L75OQKEI.cjs +13 -0
  23. package/libs/chunk-L75OQKEI.cjs.map +1 -0
  24. package/libs/{chunk-LL7HTLMS.cjs → chunk-M5RRNTVX.cjs} +3 -3
  25. package/libs/{chunk-LIQJ7ZZR.js → chunk-NGTJDDFO.js} +2 -2
  26. package/libs/chunk-OK5QEIMD.cjs +17 -0
  27. package/libs/chunk-OK5QEIMD.cjs.map +1 -0
  28. package/libs/chunk-P2DC76ZZ.cjs +18 -0
  29. package/libs/chunk-P2DC76ZZ.cjs.map +1 -0
  30. package/libs/chunk-PQ2K3BM6.cjs +17 -0
  31. package/libs/chunk-PQ2K3BM6.cjs.map +1 -0
  32. package/libs/{chunk-QCMV4VQZ.js → chunk-QLZWHAMK.js} +2 -2
  33. package/libs/{chunk-BIP2NY53.js → chunk-RIVUMPOG.js} +2 -2
  34. package/libs/{chunk-ICCKQ2GC.cjs → chunk-ROZI23GS.cjs} +4 -4
  35. package/libs/{chunk-NHYXGV3L.js → chunk-SMYRLO3E.js} +2 -2
  36. package/libs/{chunk-5ZM4XL44.js → chunk-TYRCEX2L.js} +2 -2
  37. package/libs/chunk-VUH3FXGJ.js +11 -0
  38. package/libs/chunk-VUH3FXGJ.js.map +1 -0
  39. package/libs/{chunk-PPOOBUOS.js → chunk-XBA562WW.js} +2 -2
  40. package/libs/{chunk-QVV34QEH.cjs → chunk-XTQKWY7W.cjs} +3 -3
  41. package/libs/{chunk-YWOYVRFT.js → chunk-ZANSFMTD.js} +3 -3
  42. package/libs/components/alert/alert.css +1 -1
  43. package/libs/components/alert/alert.css.map +1 -1
  44. package/libs/components/alert/alert.min.css +2 -2
  45. package/libs/components/badge/badge.css +1 -1
  46. package/libs/components/badge/badge.css.map +1 -1
  47. package/libs/components/badge/badge.min.css +2 -2
  48. package/libs/components/breadcrumbs/breadcrumb.cjs +9 -5
  49. package/libs/components/breadcrumbs/breadcrumb.d.cts +271 -32
  50. package/libs/components/breadcrumbs/breadcrumb.d.ts +271 -32
  51. package/libs/components/breadcrumbs/breadcrumb.js +3 -3
  52. package/libs/components/button.cjs +4 -4
  53. package/libs/components/button.d.cts +2 -2
  54. package/libs/components/button.d.ts +2 -2
  55. package/libs/components/button.js +2 -2
  56. package/libs/components/buttons/button.css +1 -1
  57. package/libs/components/buttons/button.css.map +1 -1
  58. package/libs/components/buttons/button.min.css +2 -2
  59. package/libs/components/card.cjs +7 -7
  60. package/libs/components/card.d.cts +277 -33
  61. package/libs/components/card.d.ts +277 -33
  62. package/libs/components/card.js +2 -2
  63. package/libs/components/cards/card.css +1 -1
  64. package/libs/components/cards/card.css.map +1 -1
  65. package/libs/components/cards/card.min.css +2 -2
  66. package/libs/components/details/details.css +1 -1
  67. package/libs/components/details/details.css.map +1 -1
  68. package/libs/components/details/details.min.css +2 -2
  69. package/libs/components/dialog/dialog.cjs +7 -7
  70. package/libs/components/dialog/dialog.css +1 -1
  71. package/libs/components/dialog/dialog.css.map +1 -1
  72. package/libs/components/dialog/dialog.d.cts +88 -34
  73. package/libs/components/dialog/dialog.d.ts +88 -34
  74. package/libs/components/dialog/dialog.js +5 -5
  75. package/libs/components/dialog/dialog.min.css +2 -2
  76. package/libs/components/form/fields.cjs +4 -4
  77. package/libs/components/form/fields.d.cts +2 -2
  78. package/libs/components/form/fields.d.ts +2 -2
  79. package/libs/components/form/fields.js +2 -2
  80. package/libs/components/form/textarea.cjs +4 -4
  81. package/libs/components/form/textarea.d.cts +2 -2
  82. package/libs/components/form/textarea.d.ts +2 -2
  83. package/libs/components/form/textarea.js +2 -2
  84. package/libs/components/heading/heading.cjs +3 -3
  85. package/libs/components/heading/heading.d.cts +3 -14
  86. package/libs/components/heading/heading.d.ts +3 -14
  87. package/libs/components/heading/heading.js +2 -2
  88. package/libs/components/icons/icon.cjs +4 -4
  89. package/libs/components/icons/icon.d.cts +148 -4
  90. package/libs/components/icons/icon.d.ts +148 -4
  91. package/libs/components/icons/icon.js +2 -2
  92. package/libs/components/images/img.css +1 -1
  93. package/libs/components/images/img.css.map +1 -1
  94. package/libs/components/images/img.min.css +2 -2
  95. package/libs/components/link/link.cjs +4 -4
  96. package/libs/components/link/link.d.cts +2 -2
  97. package/libs/components/link/link.d.ts +2 -2
  98. package/libs/components/link/link.js +2 -2
  99. package/libs/components/list/list.cjs +5 -5
  100. package/libs/components/list/list.d.cts +3 -3
  101. package/libs/components/list/list.d.ts +3 -3
  102. package/libs/components/list/list.js +2 -2
  103. package/libs/components/modal.cjs +4 -4
  104. package/libs/components/modal.js +3 -3
  105. package/libs/components/nav/nav.cjs +7 -7
  106. package/libs/components/nav/nav.d.cts +2 -2
  107. package/libs/components/nav/nav.d.ts +2 -2
  108. package/libs/components/nav/nav.js +3 -3
  109. package/libs/components/text/text.cjs +5 -5
  110. package/libs/components/text/text.d.cts +2 -2
  111. package/libs/components/text/text.d.ts +2 -2
  112. package/libs/components/text/text.js +2 -2
  113. package/libs/heading-3648c538.d.ts +250 -0
  114. package/libs/hooks.cjs +7 -0
  115. package/libs/hooks.d.cts +5 -0
  116. package/libs/hooks.d.ts +5 -0
  117. package/libs/hooks.js +3 -0
  118. package/libs/icons.cjs +3 -3
  119. package/libs/icons.d.cts +1 -1
  120. package/libs/icons.d.ts +1 -1
  121. package/libs/icons.js +2 -2
  122. package/libs/index.cjs +112 -91
  123. package/libs/index.cjs.map +1 -1
  124. package/libs/index.css +1 -1
  125. package/libs/index.css.map +1 -1
  126. package/libs/index.d.cts +515 -31
  127. package/libs/index.d.ts +515 -31
  128. package/libs/index.js +31 -19
  129. package/libs/index.js.map +1 -1
  130. package/libs/ui-645f95b5.d.ts +285 -0
  131. package/package.json +2 -83
  132. package/src/components/README-UI.mdx +416 -0
  133. package/src/components/alert/ACCESSIBILITY.md +319 -0
  134. package/src/components/alert/README.mdx +475 -19
  135. package/src/components/alert/alert.scss +113 -6
  136. package/src/components/alert/alert.stories.tsx +372 -0
  137. package/src/components/alert/alert.test.tsx +762 -0
  138. package/src/components/alert/alert.tsx +331 -66
  139. package/src/components/alert/views/alert-actions.tsx +13 -0
  140. package/src/components/alert/views/alert-content.tsx +17 -0
  141. package/src/components/alert/views/alert-icon.tsx +53 -0
  142. package/src/components/alert/views/alert-screen-reader-text.tsx +30 -0
  143. package/src/components/alert/views/alert-title.tsx +23 -0
  144. package/src/components/alert/views/alert-view.tsx +158 -0
  145. package/src/components/alert/views/index.ts +12 -0
  146. package/src/components/badge/badge.mdx +186 -49
  147. package/src/components/badge/badge.scss +20 -2
  148. package/src/components/badge/badge.stories.tsx +160 -14
  149. package/src/components/badge/badge.test.tsx +179 -0
  150. package/src/components/badge/badge.tsx +97 -4
  151. package/src/components/breadcrumbs/README.mdx +364 -45
  152. package/src/components/breadcrumbs/__snapshots__/breadcrumb.test.tsx.snap +152 -0
  153. package/src/components/breadcrumbs/breadcrumb.stories.tsx +7 -3
  154. package/src/components/breadcrumbs/breadcrumb.test.tsx +490 -0
  155. package/src/components/breadcrumbs/breadcrumb.tsx +427 -170
  156. package/src/components/buttons/button.scss +34 -31
  157. package/src/components/buttons/button.stories.tsx +35 -0
  158. package/src/components/cards/README.mdx +657 -0
  159. package/src/components/cards/card.scss +22 -0
  160. package/src/components/cards/card.stories.tsx +167 -5
  161. package/src/components/cards/card.test.tsx +360 -20
  162. package/src/components/cards/card.tsx +200 -79
  163. package/src/components/cards/card.types.ts +135 -0
  164. package/src/components/cards/card.utils.ts +79 -0
  165. package/src/components/details/ACCESSIBILITY-REVIEW-LIVE.md +1050 -0
  166. package/src/components/details/ACCESSIBILITY-REVIEW.md +502 -0
  167. package/src/components/details/README.mdx +437 -69
  168. package/src/components/details/details.scss +16 -7
  169. package/src/components/details/details.test.tsx +385 -0
  170. package/src/components/details/details.tsx +101 -69
  171. package/src/components/details/details.types.ts +76 -0
  172. package/src/components/dialog/README.mdx +513 -110
  173. package/src/components/dialog/dialog-modal.tsx +79 -56
  174. package/src/components/dialog/dialog.scss +53 -3
  175. package/src/components/dialog/dialog.stories.tsx +10 -7
  176. package/src/components/dialog/dialog.test.tsx +450 -0
  177. package/src/components/dialog/dialog.tsx +69 -59
  178. package/src/components/dialog/dialog.types.ts +133 -0
  179. package/src/components/dialog/views/dialog-footer.tsx +54 -11
  180. package/src/components/dialog/views/dialog-header.tsx +20 -15
  181. package/src/components/heading/heading.stories.tsx +44 -4
  182. package/src/components/heading/heading.tsx +89 -23
  183. package/src/components/icons/README.mdx +332 -0
  184. package/src/components/icons/icon.stories.tsx +74 -1
  185. package/src/components/icons/icon.tsx +89 -1
  186. package/src/components/icons/types.ts +47 -0
  187. package/src/components/images/README.mdx +340 -24
  188. package/src/components/images/img.scss +19 -3
  189. package/src/components/images/img.stories.tsx +424 -15
  190. package/src/components/images/img.test.tsx +354 -25
  191. package/src/components/images/img.tsx +186 -63
  192. package/src/components/images/img.types.ts +211 -0
  193. package/src/components/title/MIGRATION.md +199 -0
  194. package/src/components/title/README.md +326 -0
  195. package/src/components/title/README.mdx +452 -0
  196. package/src/components/title/title.stories.tsx +393 -0
  197. package/src/components/title/title.test.tsx +251 -0
  198. package/src/components/title/title.tsx +219 -0
  199. package/src/components/ui.stories.tsx +894 -0
  200. package/src/components/ui.test.tsx +559 -0
  201. package/src/components/ui.tsx +266 -15
  202. package/src/components/word-count/README.md +240 -0
  203. package/src/hooks.ts +1 -0
  204. package/src/index.ts +10 -2
  205. package/src/sass/_properties.scss +1 -0
  206. package/src/styles/alert/alert.css +94 -4
  207. package/src/styles/alert/alert.css.map +1 -1
  208. package/src/styles/badge/badge.css +20 -2
  209. package/src/styles/badge/badge.css.map +1 -1
  210. package/src/styles/buttons/button.css +31 -31
  211. package/src/styles/buttons/button.css.map +1 -1
  212. package/src/styles/cards/card.css +16 -0
  213. package/src/styles/cards/card.css.map +1 -1
  214. package/src/styles/details/details.css +19 -8
  215. package/src/styles/details/details.css.map +1 -1
  216. package/src/styles/dialog/dialog.css +43 -2
  217. package/src/styles/dialog/dialog.css.map +1 -1
  218. package/src/styles/images/img.css +15 -3
  219. package/src/styles/images/img.css.map +1 -1
  220. package/src/styles/index.css +240 -51
  221. package/src/styles/index.css.map +1 -1
  222. package/src/test/setup.d.ts +9 -0
  223. package/src/test/setup.ts +53 -1
  224. package/libs/chunk-6TE5QEVE.cjs +0 -13
  225. package/libs/chunk-6TE5QEVE.cjs.map +0 -1
  226. package/libs/chunk-7K76RW2A.cjs +0 -18
  227. package/libs/chunk-7K76RW2A.cjs.map +0 -1
  228. package/libs/chunk-BSPKFLO4.js +0 -8
  229. package/libs/chunk-BSPKFLO4.js.map +0 -1
  230. package/libs/chunk-BV5CLH44.cjs +0 -18
  231. package/libs/chunk-BV5CLH44.cjs.map +0 -1
  232. package/libs/chunk-DKGJHKGW.js +0 -9
  233. package/libs/chunk-DKGJHKGW.js.map +0 -1
  234. package/libs/chunk-ECLD37WN.cjs +0 -16
  235. package/libs/chunk-ECLD37WN.cjs.map +0 -1
  236. package/libs/chunk-HYBZBN4G.js +0 -8
  237. package/libs/chunk-HYBZBN4G.js.map +0 -1
  238. package/libs/chunk-KKLTUJFB.cjs.map +0 -1
  239. package/libs/chunk-M5QL5TAE.cjs +0 -14
  240. package/libs/chunk-M5QL5TAE.cjs.map +0 -1
  241. package/libs/chunk-NE6YXTMC.js +0 -7
  242. package/libs/chunk-NE6YXTMC.js.map +0 -1
  243. package/libs/chunk-O6QZBB6G.js.map +0 -1
  244. package/libs/chunk-SXVZSWX6.js +0 -11
  245. package/libs/chunk-SXVZSWX6.js.map +0 -1
  246. package/libs/ui-9a6f9f8d.d.ts +0 -24
  247. package/src/components/cards/README.md +0 -80
  248. package/src/components/dialog/hooks/useClickOutside.ts +0 -33
  249. /package/libs/{chunk-DV56L5YX.cjs.map → chunk-2LTJ7HHX.cjs.map} +0 -0
  250. /package/libs/{chunk-EQ67LF46.js.map → chunk-2Y7W75TT.js.map} +0 -0
  251. /package/libs/{chunk-X3EVB7VS.cjs.map → chunk-5S4ORA4C.cjs.map} +0 -0
  252. /package/libs/{chunk-6BVXFW7U.cjs.map → chunk-AHDJGCG5.cjs.map} +0 -0
  253. /package/libs/{chunk-E3XP6BEX.cjs.map → chunk-B7F5FS6D.cjs.map} +0 -0
  254. /package/libs/{chunk-LHVJKDMA.cjs.map → chunk-J32EZPYD.cjs.map} +0 -0
  255. /package/libs/{chunk-LL7HTLMS.cjs.map → chunk-M5RRNTVX.cjs.map} +0 -0
  256. /package/libs/{chunk-LIQJ7ZZR.js.map → chunk-NGTJDDFO.js.map} +0 -0
  257. /package/libs/{chunk-QCMV4VQZ.js.map → chunk-QLZWHAMK.js.map} +0 -0
  258. /package/libs/{chunk-BIP2NY53.js.map → chunk-RIVUMPOG.js.map} +0 -0
  259. /package/libs/{chunk-ICCKQ2GC.cjs.map → chunk-ROZI23GS.cjs.map} +0 -0
  260. /package/libs/{chunk-NHYXGV3L.js.map → chunk-SMYRLO3E.js.map} +0 -0
  261. /package/libs/{chunk-5ZM4XL44.js.map → chunk-TYRCEX2L.js.map} +0 -0
  262. /package/libs/{chunk-PPOOBUOS.js.map → chunk-XBA562WW.js.map} +0 -0
  263. /package/libs/{chunk-QVV34QEH.cjs.map → chunk-XTQKWY7W.cjs.map} +0 -0
  264. /package/libs/{chunk-YWOYVRFT.js.map → chunk-ZANSFMTD.js.map} +0 -0
@@ -4,184 +4,587 @@ import { Meta } from "@storybook/addon-docs/blocks";
4
4
 
5
5
  # Dialog Components
6
6
 
7
- A flexible Dialog component system for building accessible modal dialogs in
8
- React applications. The component supports:
7
+ A modern, accessible dialog component system built with React and TypeScript, leveraging the native HTML `<dialog>` element for optimal performance and built-in accessibility features.
9
8
 
10
- - Controlled modal behavior with built-in state management
11
- - Full ARIA accessibility support out of the box
12
- - Customizable headers and content layout
13
- - Multiple variants including standard dialogs and alert dialogs
14
- - Event handling for open, close, and cancel actions
15
- - Responsive design with inline rendering option
16
- - Modal and non-modal dialog variants via `isAlertDialog`
17
- - Built-in header with close functionality
18
- - Configurable footer with confirm/cancel actions
19
- - Click-outside-to-close behavior
20
- - Focus management and keyboard navigation
9
+ ## Features
21
10
 
22
- Built with TypeScript and React, this component follows modern best practices
23
- and provides a developer-friendly API for implementing modal dialogs in your web
24
- applications.
11
+ **Controlled Component Pattern** - Full React state control with `isOpen`/`onOpenChange`
12
+ **WCAG 2.1 AA Compliant** - Proper ARIA attributes, focus management, keyboard navigation
13
+ ✅ **Native Dialog API** - Leverages browser's built-in focus trap and escape key handling
14
+ ✅ **TypeScript Support** - Comprehensive type definitions with full IntelliSense
15
+ ✅ **Two Modes** - Modal dialogs (overlay) and inline alert dialogs
16
+ ✅ **Focus Management** - Automatic focus restoration to trigger element
17
+ ✅ **Flexible API** - Controlled `Dialog` or uncontrolled `DialogModal` wrapper
18
+ ✅ **Customizable** - CSS custom properties for theming
19
+ ✅ **Keyboard Accessible** - `:focus-visible` styles, Escape key support
20
+ ✅ **High Contrast Mode** - Supports `prefers-contrast: high` media query
25
21
 
26
- ## Overview
22
+ ---
27
23
 
28
- The dialog component system consists of the following key parts:
29
-
30
- ### Dialog Component
24
+ ## Component Architecture
31
25
 
32
26
  The dialog system consists of:
33
27
 
34
- - `Dialog`: Main modal component
35
- - `DialogHeader`: Header with title and close button
36
- - `DialogFooter`: Footer with confirm/cancel actions
28
+ | Component | Purpose | Usage |
29
+ |-----------|---------|-------|
30
+ | **`Dialog`** | Controlled modal/alert dialog | When you need full state control |
31
+ | **`DialogModal`** | Uncontrolled wrapper with trigger button | For simple use cases |
32
+ | **`DialogHeader`** | Header with title and close button | Internal (auto-rendered) |
33
+ | **`DialogFooter`** | Footer with confirm/cancel actions | Internal (auto-rendered) |
34
+
35
+ ---
36
+
37
+ ## Quick Start
38
+
39
+ ### Option 1: Controlled Dialog (Recommended)
40
+
41
+ Use this when you need to control the dialog state from your component.
42
+
43
+ ```tsx
44
+ import { Dialog } from "@fpkit/acss";
45
+ import { useState } from "react";
46
+
47
+ function MyComponent() {
48
+ const [isOpen, setIsOpen] = useState(false);
49
+
50
+ return (
51
+ <>
52
+ <button onClick={() => setIsOpen(true)}>Open Dialog</button>
53
+
54
+ <Dialog
55
+ isOpen={isOpen}
56
+ onOpenChange={setIsOpen}
57
+ dialogTitle="Confirm Action"
58
+ >
59
+ <p>Are you sure you want to proceed?</p>
60
+ </Dialog>
61
+ </>
62
+ );
63
+ }
64
+ ```
65
+
66
+ ### Option 2: Uncontrolled DialogModal (Simple)
67
+
68
+ Use this when you want a dialog with a built-in trigger button and automatic state management.
69
+
70
+ ```tsx
71
+ import { DialogModal } from "@fpkit/acss";
72
+
73
+ function MyComponent() {
74
+ return (
75
+ <DialogModal
76
+ dialogTitle="Delete Item"
77
+ btnLabel="Delete"
78
+ btnSize="md"
79
+ onConfirm={async () => {
80
+ await deleteItem();
81
+ }}
82
+ confirmLabel="Delete"
83
+ cancelLabel="Cancel"
84
+ >
85
+ <p>This action cannot be undone. Are you sure?</p>
86
+ </DialogModal>
87
+ );
88
+ }
89
+ ```
37
90
 
38
- ### Props
91
+ ---
39
92
 
40
- The Dialog component accepts two types of props - required core props and
41
- optional configuration props.
93
+ ## API Reference
94
+
95
+ ### Dialog Props (Controlled)
42
96
 
43
97
  #### Required Props
44
98
 
45
- - `dialogTitle` (`string`): Title text displayed in dialog header
46
- - `children` (`React.ReactNode`): Content rendered inside dialog body
47
- - `showDialog` (`boolean`): Controls dialog visibility state
99
+ | Prop | Type | Description |
100
+ |------|------|-------------|
101
+ | `isOpen` | `boolean` | Controls whether the dialog is currently open |
102
+ | `onOpenChange` | `(open: boolean) => void` | Callback fired when dialog open state changes |
103
+ | `dialogTitle` | `string` | Title displayed in the dialog header |
104
+ | `children` | `ReactNode` | Content to display inside the dialog body |
48
105
 
49
106
  #### Optional Props
50
107
 
51
- - `isAlertDialog` (`boolean`, default: `false`): Renders as non-modal alert
52
- dialog
53
- - `onClose` (`() => void`): Callback when dialog closes
54
- - `onConfirm` (`() => void | Promise<void>`): Confirmation action callback
55
- - `confirmLabel` (`string`, default: "Confirm"): Custom confirm button text
56
- - `cancelLabel` (`string`, default: "Cancel"): Custom cancel button text
57
- - `className` (`string`, default: ""): Additional CSS classes
108
+ | Prop | Type | Default | Description |
109
+ |------|------|---------|-------------|
110
+ | `isAlertDialog` | `boolean` | `false` | If true, renders as non-modal inline alert using `dialog.show()` |
111
+ | `onClose` | `() => void` | - | **Deprecated:** Use `onOpenChange`. Called when dialog closes. |
112
+ | `onConfirm` | `() => void \| Promise<void>` | - | Callback fired when confirm button is clicked |
113
+ | `confirmLabel` | `string` | `"Confirm"` | Text label for the confirm button |
114
+ | `cancelLabel` | `string` | `"Cancel"` | Text label for the cancel button |
115
+ | `hideFooter` | `boolean` | `false` | If true, hides the footer with action buttons |
116
+ | `className` | `string` | `""` | Additional CSS classes to apply to the dialog |
117
+ | `dialogLabel` | `string` | - | Optional `aria-label` for the dialog |
118
+ | `styles` | `CSSProperties` | - | Inline styles to apply to the dialog element |
119
+
120
+ ---
121
+
122
+ ### DialogModal Props (Uncontrolled)
123
+
124
+ All `Dialog` props plus:
58
125
 
59
- The component also inherits props from:
126
+ | Prop | Type | Default | Description |
127
+ |------|------|---------|-------------|
128
+ | `btnLabel` | `string` | `"Open Dialog"` | Text label for the trigger button |
129
+ | `btnSize` | `"sm" \| "md" \| "lg"` | `"sm"` | Size variant for the trigger button |
130
+ | `btnOnClick` | `() => void` | - | Callback fired when trigger button is clicked (before opening) |
131
+ | `btnProps` | `Record<string, unknown>` | - | Additional props to pass to the trigger button |
60
132
 
61
- - `React.ComponentProps<typeof UI>`
62
- - `React.ComponentProps<dialog>`
133
+ **Note:** `DialogModal` manages its own state internally, so you don't need `isOpen`/`onOpenChange`.
63
134
 
64
- ### Usage Examples
135
+ ---
136
+
137
+ ## Usage Examples
138
+
139
+ ### Basic Modal Dialog
65
140
 
66
141
  ```tsx
67
- // Basic usage
68
- import { Dialog } from "./dialog";
142
+ import { Dialog } from "@fpkit/acss";
143
+ import { useState } from "react";
69
144
 
70
- function MyComponent() {
71
- const [isOpen, setIsOpen] = React.useState(false);
145
+ function BasicExample() {
146
+ const [open, setOpen] = useState(false);
72
147
 
73
148
  return (
74
149
  <>
75
- <button onClick={() => setIsOpen(true)}>Open Dialog</button>
150
+ <button onClick={() => setOpen(true)}>Show Info</button>
151
+
76
152
  <Dialog
77
- isOpen={isOpen}
78
- onClose={() => setIsOpen(false)}
79
- dialogTitle="My Dialog"
80
- dialogId="example-dialog"
153
+ isOpen={open}
154
+ onOpenChange={setOpen}
155
+ dialogTitle="Information"
156
+ hideFooter
81
157
  >
82
- <div>Dialog content goes here</div>
158
+ <p>This is a simple informational dialog.</p>
159
+ <p>Click the X or press Escape to close.</p>
83
160
  </Dialog>
84
161
  </>
85
162
  );
86
163
  }
87
164
  ```
88
165
 
89
- ## Alert Dialog Example
166
+ ### Confirmation Dialog with Actions
167
+
168
+ ```tsx
169
+ import { Dialog } from "@fpkit/acss";
170
+ import { useState } from "react";
171
+
172
+ function ConfirmationExample() {
173
+ const [open, setOpen] = useState(false);
90
174
 
91
- A basic example of an Alert Dialog component implementation. Alert dialogs are
92
- used to show important messages that require user acknowledgment or
93
- confirmation.
175
+ const handleDelete = async () => {
176
+ await deleteItem();
177
+ setOpen(false);
178
+ };
94
179
 
95
- ### Features
180
+ return (
181
+ <>
182
+ <button onClick={() => setOpen(true)}>Delete Item</button>
96
183
 
97
- - Uses the `Dialog` component with `isAlertDialog` prop set to true
98
- - Displays a warning message with a confirmation button
99
- - Custom dialog title "Warning"
100
- - Unique dialog identifier "alert-dialog"
184
+ <Dialog
185
+ isOpen={open}
186
+ onOpenChange={setOpen}
187
+ dialogTitle="Confirm Deletion"
188
+ onConfirm={handleDelete}
189
+ confirmLabel="Delete"
190
+ cancelLabel="Keep"
191
+ >
192
+ <p>Are you sure you want to delete this item?</p>
193
+ <p>This action cannot be undone.</p>
194
+ </Dialog>
195
+ </>
196
+ );
197
+ }
198
+ ```
101
199
 
102
- ### Usage
200
+ ### Inline Alert Dialog (Non-Modal)
103
201
 
104
202
  ```tsx
203
+ import { Dialog } from "@fpkit/acss";
204
+ import { useState } from "react";
205
+
105
206
  function AlertExample() {
207
+ const [showAlert, setShowAlert] = useState(false);
208
+
106
209
  return (
107
- <Dialog isAlertDialog dialogTitle="Warning" dialogId="alert-dialog">
108
- <p>This action cannot be undone. Continue?</p>
109
- <button onClick={() => {}}>Confirm</button>
110
- </Dialog>
210
+ <div>
211
+ <button onClick={() => setShowAlert(true)}>Show Alert</button>
212
+
213
+ {/* Non-modal: page remains interactive */}
214
+ <Dialog
215
+ isOpen={showAlert}
216
+ onOpenChange={setShowAlert}
217
+ dialogTitle="Warning"
218
+ isAlertDialog={true}
219
+ hideFooter
220
+ >
221
+ <p>⚠️ Your session will expire in 5 minutes.</p>
222
+ </Dialog>
223
+
224
+ <p>This content remains interactive even when alert is shown.</p>
225
+ </div>
111
226
  );
112
227
  }
113
228
  ```
114
229
 
115
- ### Custom header dialog example
230
+ ### DialogModal with Simple API
116
231
 
117
232
  ```tsx
118
- // Custom header dialog
119
- function CustomDialog() {
233
+ import { DialogModal } from "@fpkit/acss";
234
+
235
+ function SimpleExample() {
120
236
  return (
121
- <Dialog hideDialogHeader dialogId="custom-dialog">
122
- <h2>Custom Header</h2>
123
- <div>Content with custom header</div>
237
+ <DialogModal
238
+ dialogTitle="Subscribe to Newsletter"
239
+ btnLabel="Subscribe"
240
+ btnSize="lg"
241
+ onConfirm={async () => {
242
+ await subscribe();
243
+ }}
244
+ confirmLabel="Sign Up"
245
+ cancelLabel="Maybe Later"
246
+ >
247
+ <p>Get weekly updates and exclusive content!</p>
248
+ <input type="email" placeholder="your@email.com" />
249
+ </DialogModal>
250
+ );
251
+ }
252
+ ```
253
+
254
+ ### Custom Styling
255
+
256
+ ```tsx
257
+ import { Dialog } from "@fpkit/acss";
258
+ import { useState } from "react";
259
+
260
+ function StyledExample() {
261
+ const [open, setOpen] = useState(false);
262
+
263
+ return (
264
+ <Dialog
265
+ isOpen={open}
266
+ onOpenChange={setOpen}
267
+ dialogTitle="Custom Styled Dialog"
268
+ className="my-custom-dialog"
269
+ styles={{ maxWidth: "600px", borderRadius: "1rem" }}
270
+ >
271
+ <p>This dialog has custom styles applied.</p>
124
272
  </Dialog>
125
273
  );
126
274
  }
127
275
  ```
128
276
 
129
- ## Styles
277
+ ---
278
+
279
+ ## Modal vs Non-Modal Behavior
280
+
281
+ ### Modal Dialog (Default)
282
+
283
+ Uses `dialog.showModal()` which provides:
284
+ - ✅ Full-page overlay with backdrop
285
+ - ✅ Automatic focus trap (Tab cycles within dialog)
286
+ - ✅ Escape key closes dialog (native behavior)
287
+ - ✅ Backdrop click closes dialog
288
+ - ✅ Background becomes inert (non-interactive)
289
+
290
+ ```tsx
291
+ <Dialog
292
+ isOpen={open}
293
+ onOpenChange={setOpen}
294
+ dialogTitle="Modal Dialog"
295
+ >
296
+ Content here - page is blocked
297
+ </Dialog>
298
+ ```
299
+
300
+ ### Inline Alert Dialog (`isAlertDialog={true}`)
301
+
302
+ Uses `dialog.show()` for non-modal inline alerts:
303
+ - ✅ Positioned inline in page flow
304
+ - ❌ No focus trap (page remains interactive)
305
+ - ❌ No escape key behavior
306
+ - ❌ No backdrop
307
+ - ✅ User can interact with page content
308
+
309
+ ```tsx
310
+ <Dialog
311
+ isOpen={showAlert}
312
+ onOpenChange={setShowAlert}
313
+ dialogTitle="Alert"
314
+ isAlertDialog={true}
315
+ >
316
+ Warning message - page stays interactive
317
+ </Dialog>
318
+ ```
319
+
320
+ ---
321
+
322
+ ## Accessibility Features
323
+
324
+ ### WCAG 2.1 AA Compliance
325
+
326
+ #### ARIA Attributes
327
+ - `aria-labelledby` - Links dialog to title using unique ID
328
+ - `aria-describedby` - Links dialog to content description
329
+ - `aria-modal="true"` - Indicates modal dialogs
330
+ - `aria-label` - Custom accessible label support
331
+ - `role="dialog"` or `role="alertdialog"` - Semantic roles
332
+
333
+ #### Keyboard Navigation
334
+ - **Escape key** - Closes modal dialogs (native `<dialog>` behavior)
335
+ - **Tab** - Cycles through focusable elements within dialog (focus trap)
336
+ - **Enter/Space** - Activates buttons
337
+ - `:focus-visible` styles for keyboard users
338
+
339
+ #### Focus Management
340
+ - **Auto-focus** - Dialog close button receives focus when opened
341
+ - **Focus restoration** - Focus returns to trigger button when closed
342
+ - **Focus trap** - Tab navigation stays within modal dialog
343
+
344
+ #### Screen Reader Support
345
+ - Semantic HTML structure
346
+ - Proper heading hierarchy
347
+ - Clear button labels
348
+ - Accessible close button ("Close dialog")
349
+
350
+ ### High Contrast Mode
351
+
352
+ ```scss
353
+ @media (prefers-contrast: high) {
354
+ dialog {
355
+ --dialog-border-color: currentColor;
356
+ --dialog-border-width: 0.125rem;
357
+ --dialog-focus-width: 0.1875rem;
358
+ }
359
+ }
360
+ ```
361
+
362
+ ---
363
+
364
+ ## Styling & Customization
365
+
366
+ ### CSS Custom Properties
367
+
368
+ Override these variables to customize the dialog appearance:
369
+
370
+ ```css
371
+ :root {
372
+ /* Dimensions */
373
+ --dialog-min-w: max(20rem, 80%);
374
+ --dialog-gap: 0.625rem;
375
+ --dialog-padding: 1.5rem;
376
+ --dialog-padding-inline: 1rem;
377
+
378
+ /* Borders */
379
+ --dialog-border-color: lightgray;
380
+ --dialog-border-width: thin;
381
+ --dialog-border-radius: var(--border-radius);
382
+
383
+ /* Buttons */
384
+ --dialog-button-bg: transparent;
385
+ --dialog-button-hover-bg: whitesmoke;
386
+ --dialog-close-color: gray;
387
+
388
+ /* Focus (Accessibility) */
389
+ --dialog-focus-color: #0066cc;
390
+ --dialog-focus-width: 0.125rem;
391
+ --dialog-focus-offset: 0.125rem;
392
+
393
+ /* Layout */
394
+ --dialog-display: flex;
395
+ --dialog-flex-direction: column;
396
+ }
397
+ ```
398
+
399
+ ### Example: Custom Theme
400
+
401
+ ```scss
402
+ // Dark theme dialog
403
+ .dark-theme-dialog {
404
+ --dialog-border-color: #444;
405
+ --dialog-button-hover-bg: #333;
406
+ --dialog-close-color: #ccc;
407
+ background: #1a1a1a;
408
+ color: #fff;
409
+ }
410
+ ```
411
+
412
+ ---
413
+
414
+ ## TypeScript Support
415
+
416
+ ### Import Types
417
+
418
+ ```tsx
419
+ import type {
420
+ DialogProps,
421
+ DialogModalProps,
422
+ DialogHeaderProps,
423
+ DialogFooterProps,
424
+ } from "@fpkit/acss";
425
+ ```
426
+
427
+ ### Type Definitions
428
+
429
+ All components are fully typed with comprehensive JSDoc comments:
430
+
431
+ ```tsx
432
+ interface DialogProps extends BaseDialogProps {
433
+ isOpen: boolean;
434
+ onOpenChange: (open: boolean) => void;
435
+ isAlertDialog?: boolean;
436
+ onClose?: () => void; // Deprecated
437
+ onConfirm?: () => void | Promise<void>;
438
+ confirmLabel?: string;
439
+ cancelLabel?: string;
440
+ hideFooter?: boolean;
441
+ }
442
+ ```
443
+
444
+ ---
445
+
446
+ ## Migration Guide
130
447
 
131
- This `dialog.scss` file defines the styling for a dialog component with
132
- customizable properties using CSS variables.
448
+ ### Upgrading from Old API
133
449
 
134
- ## CSS Custom Properties
450
+ **Before (Old API):**
451
+ ```tsx
452
+ <Dialog
453
+ showDialog={isOpen}
454
+ onClose={() => setIsOpen(false)}
455
+ dialogTitle="Old API"
456
+ >
457
+ Content
458
+ </Dialog>
459
+ ```
135
460
 
136
- ### Dialog Dimensions and Spacing
461
+ **After (New API):**
462
+ ```tsx
463
+ <Dialog
464
+ isOpen={isOpen}
465
+ onOpenChange={setIsOpen}
466
+ dialogTitle="New API"
467
+ >
468
+ Content
469
+ </Dialog>
470
+ ```
137
471
 
138
- - `--dialog-min-w`: Minimum width of the dialog (320px)
139
- - `--dialog-gap`: Spacing between dialog elements (0.75rem)
140
- - `--dialog-padding`: General padding inside dialog (0.75rem)
141
- - `--dialog-padding-inline`: Horizontal padding inside dialog (1rem)
472
+ **Backward Compatible (Temporary):**
473
+ ```tsx
474
+ <Dialog
475
+ isOpen={isOpen}
476
+ onOpenChange={setIsOpen}
477
+ onClose={() => console.log('Still works!')} // Deprecated but functional
478
+ dialogTitle="Hybrid"
479
+ >
480
+ Content
481
+ </Dialog>
482
+ ```
483
+
484
+ ### Breaking Changes
142
485
 
143
- ### Border Properties
486
+ | Old Prop | New Prop | Migration |
487
+ |----------|----------|-----------|
488
+ | `showDialog` | `isOpen` | Rename prop |
489
+ | `onClose` | `onOpenChange` | Change signature from `() => void` to `(open: boolean) => void` |
490
+ | `dialogId` | *(removed)* | Use auto-generated IDs via `useId()` |
144
491
 
145
- - `--dialog-border-color`: Color of dialog border (lightgray)
146
- - `--dialog-border-width`: Width of dialog border (thin)
147
- - `--dialog-border-style`: Style of dialog border (solid)
148
- - `--dialog-border-radius`: Border radius of dialog corners (0.5rem)
492
+ ---
149
493
 
150
- ### Dialog Button Styles
494
+ ## Best Practices
151
495
 
152
- - `--dialog-button-bg`: Background color for dialog buttons (transparent)
153
- - `--dialog-button-border`: Border style for dialog buttons (transparent thin
154
- solid)
155
- - `--dialog-button-hover-bg`: Background color for button hover state
156
- (whitesmoke)
157
- - `--dialog-close-color`: Color for close button (gray)
496
+ ### Do
497
+
498
+ ```tsx
499
+ // Use controlled pattern for complex flows
500
+ const [step, setStep] = useState(1);
501
+ <Dialog isOpen={step === 2} onOpenChange={(open) => !open && setStep(1)}>
502
+ Multi-step content
503
+ </Dialog>
158
504
 
159
- ### Layout Properties
505
+ // Provide clear button labels
506
+ <Dialog confirmLabel="Delete Forever" cancelLabel="Keep Item">
160
507
 
161
- - `--dialog-display`: Display property for dialog (flex)
162
- - `--dialog-flex-direction`: Flex direction for dialog layout (column)
508
+ // Use DialogModal for simple cases
509
+ <DialogModal dialogTitle="Quick Action" btnLabel="Go">
510
+ ```
511
+
512
+ ### ❌ Don't
513
+
514
+ ```tsx
515
+ // Don't manage state twice
516
+ const [open, setOpen] = useState(false);
517
+ <Dialog isOpen={open} onOpenChange={setOpen} onClose={() => setOpen(false)}>
518
+ // onClose is redundant with onOpenChange
519
+
520
+ // Don't use inline alerts for critical actions
521
+ <Dialog isAlertDialog={true} onConfirm={deleteAllData}>
522
+ // Use modal for destructive actions!
523
+
524
+ // Don't skip ARIA labels for custom content
525
+ <Dialog hideFooter>
526
+ <button>Close</button> {/* Missing aria-label */}
527
+ </Dialog>
528
+ ```
529
+
530
+ ---
531
+
532
+ ## Performance Considerations
533
+
534
+ The dialog component is optimized with:
535
+ - ✅ `React.memo` on subcomponents (DialogHeader, DialogFooter)
536
+ - ✅ `useCallback` for event handlers
537
+ - ✅ Minimal re-renders via proper dependency arrays
538
+ - ✅ Native `<dialog>` API (no JavaScript focus trap)
539
+
540
+ ---
541
+
542
+ ## Browser Support
543
+
544
+ Requires browsers with native `<dialog>` element support:
545
+ - ✅ Chrome 37+
546
+ - ✅ Edge 79+
547
+ - ✅ Firefox 98+
548
+ - ✅ Safari 15.4+
549
+
550
+ For older browsers, consider using a polyfill like [`dialog-polyfill`](https://github.com/GoogleChrome/dialog-polyfill).
551
+
552
+ ---
553
+
554
+ ## Testing
555
+
556
+ The dialog component has comprehensive test coverage:
557
+ - ✓ 24 tests covering all scenarios
558
+ - ✓ Controlled vs uncontrolled behavior
559
+ - ✓ Modal vs non-modal rendering
560
+ - ✓ ARIA attributes validation
561
+ - ✓ Focus restoration
562
+ - ✓ Keyboard interactions
563
+
564
+ Run tests:
565
+ ```bash
566
+ npm test -- dialog.test.tsx
567
+ ```
163
568
 
164
- ## Component Structure
569
+ ---
165
570
 
166
- ### Base Dialog
571
+ ## Related Components
167
572
 
168
- - Sets minimum width and spacing
169
- - Applies border and padding styles
170
- - Implements flex layout when dialog is open
573
+ - **DialogHeader** - Header with title and close button (internal)
574
+ - **DialogFooter** - Footer with confirm/cancel buttons (internal)
575
+ - **Button** - Used for trigger and action buttons
576
+ - **Icon** - Used for close button icon
171
577
 
172
- ### Dialog Header
578
+ ---
173
579
 
174
- - Implements a flex layout with space-between alignment
175
- - Contains title (h3) and close button
176
- - Custom button styling with hover states
580
+ ## Resources
177
581
 
178
- ### Alert Dialog Actions
582
+ - [MDN: `<dialog>` Element](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/dialog)
583
+ - [ARIA: Dialog Role](https://www.w3.org/WAI/ARIA/apg/patterns/dialog-modal/)
584
+ - [WCAG 2.1 Guidelines](https://www.w3.org/WAI/WCAG21/quickref/)
179
585
 
180
- - Container for dialog action buttons
181
- - Uses flex layout with left alignment
182
- - Includes gap spacing between buttons
586
+ ---
183
587
 
184
- ## Usage
588
+ ## License
185
589
 
186
- To customize the dialog appearance, override the CSS custom properties in your
187
- stylesheet.
590
+ Part of the `@fpkit/acss` component library.