@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
@@ -0,0 +1,211 @@
1
+ import React from 'react'
2
+
3
+ /**
4
+ * Props for the Img component.
5
+ *
6
+ * Extends native HTML img element attributes with additional functionality
7
+ * for responsive images, loading states, and error handling.
8
+ *
9
+ * ## Accessibility Guidelines (WCAG 2.1 AA)
10
+ *
11
+ * **Decorative Images:**
12
+ * Images that are purely visual decoration should have an empty alt attribute.
13
+ *
14
+ * @example
15
+ * ```tsx
16
+ * // ✅ Decorative image (border, background pattern, visual separator)
17
+ * <Img src="/decorative-border.png" alt="" />
18
+ * ```
19
+ *
20
+ * **Semantic Images:**
21
+ * Images that convey information or meaning must have descriptive alt text.
22
+ *
23
+ * @example
24
+ * ```tsx
25
+ * // ✅ Semantic image (charts, diagrams, photos with meaning)
26
+ * <Img
27
+ * src="/sales-chart.png"
28
+ * alt="Sales chart showing 30% growth in Q4 2024"
29
+ * />
30
+ * ```
31
+ *
32
+ * **Responsive Images:**
33
+ * Use srcset and sizes for responsive images to optimize performance.
34
+ *
35
+ * @example
36
+ * ```tsx
37
+ * // ✅ Responsive image with srcset
38
+ * <Img
39
+ * src="/photo.jpg"
40
+ * srcSet="/photo-320w.jpg 320w, /photo-640w.jpg 640w, /photo-1024w.jpg 1024w"
41
+ * sizes="(max-width: 640px) 100vw, (max-width: 1024px) 50vw, 33vw"
42
+ * alt="Team photo from annual conference"
43
+ * />
44
+ * ```
45
+ *
46
+ * @see https://www.w3.org/WAI/WCAG21/Understanding/non-text-content.html
47
+ */
48
+ export interface ImgProps
49
+ extends Omit<React.ImgHTMLAttributes<HTMLImageElement>, 'placeholder'> {
50
+ /**
51
+ * The image source URL.
52
+ * @default '//'
53
+ */
54
+ src?: string
55
+
56
+ /**
57
+ * Alternative text for the image.
58
+ * - **Empty string (`""`)** for decorative images
59
+ * - **Descriptive text** for semantic images that convey meaning
60
+ *
61
+ * @example
62
+ * ```tsx
63
+ * // Decorative
64
+ * <Img src="/border.png" alt="" />
65
+ *
66
+ * // Semantic
67
+ * <Img src="/logo.png" alt="Company logo" />
68
+ * ```
69
+ */
70
+ alt?: string
71
+
72
+ /**
73
+ * Width of the image in pixels.
74
+ * @default 480
75
+ */
76
+ width?: number | string
77
+
78
+ /**
79
+ * Height of the image in pixels.
80
+ * When not provided, defaults to 'auto'.
81
+ */
82
+ height?: number | string
83
+
84
+ /**
85
+ * Inline styles to apply to the image.
86
+ */
87
+ styles?: React.CSSProperties
88
+
89
+ /**
90
+ * Loading behavior for the image.
91
+ * - `"lazy"` (default): Defers loading until near viewport
92
+ * - `"eager"`: Loads immediately
93
+ *
94
+ * @default "lazy"
95
+ * @see https://developer.mozilla.org/en-US/docs/Web/HTML/Element/img#loading
96
+ */
97
+ loading?: 'eager' | 'lazy'
98
+
99
+ /**
100
+ * Fallback placeholder image URL to display on error.
101
+ * If not provided and image fails to load, a default placeholder is used.
102
+ *
103
+ * @example
104
+ * ```tsx
105
+ * <Img
106
+ * src="/photo.jpg"
107
+ * placeholder="/fallback.png"
108
+ * alt="User profile photo"
109
+ * />
110
+ * ```
111
+ */
112
+ placeholder?: string
113
+
114
+ /**
115
+ * Hint for the browser to prioritize image fetching.
116
+ * - `"high"`: High priority (above-the-fold images)
117
+ * - `"low"` (default): Low priority
118
+ * - `"auto"`: Browser decides
119
+ *
120
+ * @default "low"
121
+ * @see https://developer.mozilla.org/en-US/docs/Web/HTML/Element/img#fetchpriority
122
+ */
123
+ fetchpriority?: 'high' | 'low' | 'auto'
124
+
125
+ /**
126
+ * Decoding hint for the browser.
127
+ * - `"async"`: Decode asynchronously (don't block rendering)
128
+ * - `"sync"`: Decode synchronously
129
+ * - `"auto"` (default): Browser decides
130
+ *
131
+ * @default "auto"
132
+ * @see https://developer.mozilla.org/en-US/docs/Web/HTML/Element/img#decoding
133
+ */
134
+ decoding?: 'sync' | 'async' | 'auto'
135
+
136
+ /**
137
+ * Responsive image sources with width descriptors.
138
+ * Allows browser to choose appropriate image based on viewport.
139
+ *
140
+ * @example
141
+ * ```tsx
142
+ * <Img
143
+ * src="/photo.jpg"
144
+ * srcSet="/photo-320w.jpg 320w, /photo-640w.jpg 640w"
145
+ * sizes="(max-width: 640px) 100vw, 640px"
146
+ * alt="Responsive image"
147
+ * />
148
+ * ```
149
+ *
150
+ * @see https://developer.mozilla.org/en-US/docs/Web/HTML/Element/img#srcset
151
+ */
152
+ srcSet?: string
153
+
154
+ /**
155
+ * Media conditions for responsive image sizing.
156
+ * Works with srcSet to determine which image to load.
157
+ *
158
+ * @example
159
+ * ```tsx
160
+ * sizes="(max-width: 640px) 100vw, (max-width: 1024px) 50vw, 800px"
161
+ * ```
162
+ *
163
+ * @see https://developer.mozilla.org/en-US/docs/Web/HTML/Element/img#sizes
164
+ */
165
+ sizes?: string
166
+
167
+ /**
168
+ * Callback fired when the image fails to load.
169
+ * The default SVG placeholder is still applied after calling this handler.
170
+ * Call `event.preventDefault()` to prevent the default fallback behavior.
171
+ *
172
+ * @param event - The error event
173
+ *
174
+ * @example
175
+ * ```tsx
176
+ * // Log error and show default placeholder
177
+ * <Img
178
+ * src="/photo.jpg"
179
+ * onError={(e) => console.error('Image failed to load', e)}
180
+ * alt="Photo"
181
+ * />
182
+ *
183
+ * // Prevent default and use custom fallback
184
+ * <Img
185
+ * src="/photo.jpg"
186
+ * onError={(e) => {
187
+ * e.preventDefault()
188
+ * e.currentTarget.src = '/custom-fallback.jpg'
189
+ * }}
190
+ * alt="Photo"
191
+ * />
192
+ * ```
193
+ */
194
+ onError?: (event: React.SyntheticEvent<HTMLImageElement, Event>) => void
195
+
196
+ /**
197
+ * Callback fired when the image successfully loads.
198
+ *
199
+ * @param event - The load event
200
+ *
201
+ * @example
202
+ * ```tsx
203
+ * <Img
204
+ * src="/photo.jpg"
205
+ * onLoad={(e) => console.log('Image loaded successfully')}
206
+ * alt="Photo"
207
+ * />
208
+ * ```
209
+ */
210
+ onLoad?: (event: React.SyntheticEvent<HTMLImageElement, Event>) => void
211
+ }
@@ -0,0 +1,199 @@
1
+ # Migration Guide: Heading → Title
2
+
3
+ ## Summary of Changes
4
+
5
+ The `Heading` component has been refactored and renamed to `Title` with improved API design, better accessibility, and enhanced developer experience.
6
+
7
+ ## What Changed?
8
+
9
+ ### 1. Component Name
10
+ - **Old**: `Heading`
11
+ - **New**: `Title`
12
+
13
+ ### 2. Prop Names
14
+ - **Old**: `type` prop
15
+ - **New**: `level` prop (more semantic)
16
+
17
+ ### 3. Default Behavior
18
+ - **Old**: Default heading level was `h3`
19
+ - **New**: Default heading level is `h2`
20
+
21
+ ### 4. Improvements Added
22
+ - ✅ **Memoization**: Component wrapped with `React.memo` for performance
23
+ - ✅ **Ref Forwarding**: Properly typed refs for DOM access
24
+ - ✅ **Better TypeScript**: Comprehensive JSDoc comments for IDE support
25
+ - ✅ **Enhanced Accessibility**: Better WCAG 2.1 AA compliance documentation
26
+ - ✅ **Comprehensive Tests**: 31 test cases covering all functionality
27
+ - ✅ **Storybook Stories**: Interactive examples with accessibility checks
28
+
29
+ ## Quick Migration
30
+
31
+ ### Before (Deprecated)
32
+ ```tsx
33
+ import { Heading } from '@fpkit/acss';
34
+
35
+ <Heading type="h2">Section Title</Heading>
36
+ <Heading type="h3" id="subsection">Subsection</Heading>
37
+ <Heading>Default (renders as h3)</Heading>
38
+ ```
39
+
40
+ ### After (Recommended)
41
+ ```tsx
42
+ import { Title } from '@fpkit/acss';
43
+
44
+ <Title level="h2">Section Title</Title>
45
+ <Title level="h3" id="subsection">Subsection</Title>
46
+ <Title>Default (renders as h2)</Title>
47
+ ```
48
+
49
+ ## Backwards Compatibility
50
+
51
+ The `Heading` component **still works** and provides 100% backwards compatibility:
52
+
53
+ - ✅ All existing code continues to function
54
+ - ⚠️ Console warnings in development mode
55
+ - 📅 Will be removed in **v3.0.0**
56
+
57
+ ### Deprecation Warnings
58
+
59
+ In development mode, you'll see:
60
+
61
+ ```
62
+ [@fpkit/acss] Heading component is deprecated and will be removed in v3.0.0.
63
+ Please use the Title component instead.
64
+ Migration: <Heading type="h2"> → <Title level="h2">
65
+ See documentation: https://fpkit.dev/components/title
66
+ ```
67
+
68
+ ## Migration Steps
69
+
70
+ ### Step 1: Find All Usages
71
+
72
+ ```bash
73
+ # Search for all Heading imports
74
+ grep -r "import.*Heading" src/
75
+
76
+ # Search for all Heading components in JSX
77
+ grep -r "<Heading" src/
78
+ ```
79
+
80
+ ### Step 2: Update Imports
81
+
82
+ ```tsx
83
+ // Before:
84
+ import { Heading } from '@fpkit/acss';
85
+
86
+ // After:
87
+ import { Title } from '@fpkit/acss';
88
+ ```
89
+
90
+ ### Step 3: Update Component Names and Props
91
+
92
+ ```tsx
93
+ // Before:
94
+ <Heading type="h1">Page Title</Heading>
95
+ <Heading type="h2">Section</Heading>
96
+
97
+ // After:
98
+ <Title level="h1">Page Title</Title>
99
+ <Title level="h2">Section</Title>
100
+ ```
101
+
102
+ ### Step 4: Handle Default Behavior
103
+
104
+ If you relied on the default `h3` behavior:
105
+
106
+ ```tsx
107
+ // Before (default was h3):
108
+ <Heading>Title</Heading>
109
+
110
+ // After (default is now h2):
111
+ // Option 1: Accept new default
112
+ <Title>Title</Title>
113
+
114
+ // Option 2: Explicitly use h3
115
+ <Title level="h3">Title</Title>
116
+ ```
117
+
118
+ ### Step 5: Test Your Changes
119
+
120
+ ```bash
121
+ # Run your tests
122
+ npm test
123
+
124
+ # Check your app visually
125
+ npm start
126
+ ```
127
+
128
+ ## Automated Migration (Optional)
129
+
130
+ You can use find-and-replace, but **review changes carefully**:
131
+
132
+ ```bash
133
+ # Replace component name (dry run first!)
134
+ find src/ -type f \( -name "*.tsx" -o -name "*.ts" \) \
135
+ -exec sed -i '' 's/<Heading/<Title/g' {} +
136
+
137
+ # Replace prop name
138
+ find src/ -type f \( -name "*.tsx" -o -name "*.ts" \) \
139
+ -exec sed -i '' 's/type="/level="/g' {} +
140
+
141
+ # Update imports
142
+ find src/ -type f \( -name "*.tsx" -o -name "*.ts" \) \
143
+ -exec sed -i '' 's/import { Heading }/import { Title }/g' {} +
144
+ ```
145
+
146
+ ⚠️ **Warning**: The `type=` replacement may affect other components. Review all changes!
147
+
148
+ ## Type Safety
149
+
150
+ Both components are fully typed:
151
+
152
+ ```tsx
153
+ import { Title, type TitleProps, type HeadingLevel } from '@fpkit/acss';
154
+
155
+ // Custom wrapper
156
+ interface SectionTitleProps extends TitleProps {
157
+ emphasized?: boolean;
158
+ }
159
+
160
+ const SectionTitle = ({ emphasized, ...props }: SectionTitleProps) => (
161
+ <Title
162
+ {...props}
163
+ className={emphasized ? 'font-bold' : ''}
164
+ />
165
+ );
166
+ ```
167
+
168
+ ## Benefits of Migrating
169
+
170
+ ### Better API
171
+ - `level` is more semantic than `type`
172
+ - Clearer intent in code
173
+
174
+ ### Performance
175
+ - Memoization reduces unnecessary re-renders
176
+ - Better for large component trees
177
+
178
+ ### Developer Experience
179
+ - Comprehensive JSDoc comments
180
+ - Better IDE autocomplete
181
+ - Improved error messages
182
+
183
+ ### Accessibility
184
+ - Enhanced WCAG 2.1 documentation
185
+ - Better examples for screen reader support
186
+ - Improved heading hierarchy guidance
187
+
188
+ ## Need Help?
189
+
190
+ - 📚 [Full Documentation](README.md)
191
+ - 📖 [Storybook Examples](?path=/docs/fp-react-components-title--docs)
192
+ - 🐛 [Report Issues](https://github.com/fpkit/acss/issues)
193
+
194
+ ## Timeline
195
+
196
+ - **v2.x**: Both components available, `Heading` deprecated
197
+ - **v3.0.0**: `Heading` component removed (breaking change)
198
+
199
+ Migrate before v3.0.0 to avoid breaking changes!