@fpkit/acss 0.5.13 → 0.6.0

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 (280) hide show
  1. package/libs/{chunk-PQ2K3BM6.cjs → chunk-2NRIP6RB.cjs} +3 -3
  2. package/libs/chunk-33PNJ4LO.cjs +15 -0
  3. package/libs/chunk-33PNJ4LO.cjs.map +1 -0
  4. package/libs/chunk-4BZKFPEC.cjs +17 -0
  5. package/libs/chunk-4BZKFPEC.cjs.map +1 -0
  6. package/libs/{chunk-772NRB75.js → chunk-5QD3DWFI.js} +2 -2
  7. package/libs/chunk-6SAHIYCZ.js +7 -0
  8. package/libs/chunk-6SAHIYCZ.js.map +1 -0
  9. package/libs/{chunk-3MKLDCKQ.cjs → chunk-6WTC4JXH.cjs} +3 -3
  10. package/libs/chunk-75QHTLFO.js +7 -0
  11. package/libs/chunk-75QHTLFO.js.map +1 -0
  12. package/libs/{chunk-ZANSFMTD.js → chunk-7XPFW7CB.js} +3 -3
  13. package/libs/chunk-BFK62VX5.js +5 -0
  14. package/libs/chunk-BFK62VX5.js.map +1 -0
  15. package/libs/{chunk-ROZI23GS.cjs → chunk-DKTHCQ5P.cjs} +4 -4
  16. package/libs/chunk-E2AJURUW.cjs +13 -0
  17. package/libs/chunk-E2AJURUW.cjs.map +1 -0
  18. package/libs/{chunk-L75OQKEI.cjs → chunk-ENTCUJ3A.cjs} +3 -3
  19. package/libs/chunk-ENTCUJ3A.cjs.map +1 -0
  20. package/libs/chunk-F5EYMVQM.js +10 -0
  21. package/libs/chunk-F5EYMVQM.js.map +1 -0
  22. package/libs/chunk-FVROL3V5.js +9 -0
  23. package/libs/chunk-FVROL3V5.js.map +1 -0
  24. package/libs/chunk-GT77BX4L.cjs +17 -0
  25. package/libs/chunk-GT77BX4L.cjs.map +1 -0
  26. package/libs/chunk-GUJSMQ3V.cjs +16 -0
  27. package/libs/chunk-GUJSMQ3V.cjs.map +1 -0
  28. package/libs/chunk-HHLNOC5T.js +7 -0
  29. package/libs/chunk-HHLNOC5T.js.map +1 -0
  30. package/libs/chunk-HRRHPLER.js +8 -0
  31. package/libs/chunk-HRRHPLER.js.map +1 -0
  32. package/libs/chunk-IEB64SWY.js +8 -0
  33. package/libs/chunk-IEB64SWY.js.map +1 -0
  34. package/libs/{chunk-NGTJDDFO.js → chunk-IQ76HGVP.js} +2 -2
  35. package/libs/chunk-IRLFZ3OL.js +9 -0
  36. package/libs/chunk-IRLFZ3OL.js.map +1 -0
  37. package/libs/{chunk-JJ43O4Y5.js → chunk-KK47SYZI.js} +2 -2
  38. package/libs/chunk-O3JIHC5M.cjs +15 -0
  39. package/libs/chunk-O3JIHC5M.cjs.map +1 -0
  40. package/libs/chunk-O5XAJ7BY.cjs +18 -0
  41. package/libs/chunk-O5XAJ7BY.cjs.map +1 -0
  42. package/libs/chunk-OVWLQYMK.js +10 -0
  43. package/libs/chunk-OVWLQYMK.js.map +1 -0
  44. package/libs/chunk-PNWIRCG3.cjs +7 -0
  45. package/libs/chunk-PNWIRCG3.cjs.map +1 -0
  46. package/libs/{chunk-D4YLRWAO.cjs → chunk-QVW6W76L.cjs} +6 -6
  47. package/libs/chunk-T4T6GWYQ.cjs +17 -0
  48. package/libs/chunk-T4T6GWYQ.cjs.map +1 -0
  49. package/libs/chunk-TON2YGMD.cjs +9 -0
  50. package/libs/chunk-TON2YGMD.cjs.map +1 -0
  51. package/libs/chunk-UEPAWMDF.js +8 -0
  52. package/libs/chunk-UEPAWMDF.js.map +1 -0
  53. package/libs/{chunk-LT5KZ2QW.cjs → chunk-US2I5GI7.cjs} +3 -3
  54. package/libs/{chunk-B7F5FS6D.cjs → chunk-W2UIN7EV.cjs} +3 -3
  55. package/libs/{chunk-P2DC76ZZ.cjs → chunk-W5TKWBFC.cjs} +3 -3
  56. package/libs/chunk-WXBFBWYF.cjs +16 -0
  57. package/libs/chunk-WXBFBWYF.cjs.map +1 -0
  58. package/libs/{chunk-VUH3FXGJ.js → chunk-X3JCTEPD.js} +5 -5
  59. package/libs/chunk-X5LGFCWG.js +9 -0
  60. package/libs/chunk-X5LGFCWG.js.map +1 -0
  61. package/libs/{chunk-5M57K4SW.js → chunk-Y2PFDELK.js} +2 -2
  62. package/libs/{chunk-ETFLFC2S.js → chunk-ZFJ4U45S.js} +2 -2
  63. package/libs/{component-props-a8a2f97e.d.ts → component-props-67d978a2.d.ts} +4 -4
  64. package/libs/components/alert/alert.css +1 -1
  65. package/libs/components/alert/alert.css.map +1 -1
  66. package/libs/components/alert/alert.min.css +2 -2
  67. package/libs/components/breadcrumbs/breadcrumb.cjs +6 -6
  68. package/libs/components/breadcrumbs/breadcrumb.d.cts +11 -11
  69. package/libs/components/breadcrumbs/breadcrumb.d.ts +11 -11
  70. package/libs/components/breadcrumbs/breadcrumb.js +3 -3
  71. package/libs/components/button.cjs +6 -4
  72. package/libs/components/button.d.cts +97 -4
  73. package/libs/components/button.d.ts +97 -4
  74. package/libs/components/button.js +4 -2
  75. package/libs/components/card.cjs +7 -7
  76. package/libs/components/card.d.cts +14 -14
  77. package/libs/components/card.d.ts +14 -14
  78. package/libs/components/card.js +2 -2
  79. package/libs/components/dialog/dialog.cjs +9 -7
  80. package/libs/components/dialog/dialog.d.cts +3 -3
  81. package/libs/components/dialog/dialog.d.ts +3 -3
  82. package/libs/components/dialog/dialog.js +7 -5
  83. package/libs/components/form/fields.cjs +4 -4
  84. package/libs/components/form/fields.d.cts +16 -7
  85. package/libs/components/form/fields.d.ts +16 -7
  86. package/libs/components/form/fields.js +2 -2
  87. package/libs/components/form/inputs.cjs +6 -4
  88. package/libs/components/form/inputs.d.cts +50 -2
  89. package/libs/components/form/inputs.d.ts +50 -2
  90. package/libs/components/form/inputs.js +4 -2
  91. package/libs/components/form/textarea.cjs +5 -4
  92. package/libs/components/form/textarea.d.cts +32 -23
  93. package/libs/components/form/textarea.d.ts +32 -23
  94. package/libs/components/form/textarea.js +3 -2
  95. package/libs/components/heading/heading.cjs +3 -3
  96. package/libs/components/heading/heading.d.cts +2 -2
  97. package/libs/components/heading/heading.d.ts +2 -2
  98. package/libs/components/heading/heading.js +2 -2
  99. package/libs/components/icons/icon.cjs +4 -4
  100. package/libs/components/icons/icon.d.cts +38 -38
  101. package/libs/components/icons/icon.d.ts +38 -38
  102. package/libs/components/icons/icon.js +2 -2
  103. package/libs/components/link/link.cjs +4 -4
  104. package/libs/components/link/link.css +1 -1
  105. package/libs/components/link/link.css.map +1 -1
  106. package/libs/components/link/link.d.cts +3 -19
  107. package/libs/components/link/link.d.ts +3 -19
  108. package/libs/components/link/link.js +2 -2
  109. package/libs/components/link/link.min.css +2 -2
  110. package/libs/components/list/list.cjs +5 -5
  111. package/libs/components/list/list.css +1 -0
  112. package/libs/components/list/list.css.map +1 -0
  113. package/libs/components/list/list.d.cts +120 -33
  114. package/libs/components/list/list.d.ts +120 -33
  115. package/libs/components/list/list.js +2 -2
  116. package/libs/components/list/list.min.css +3 -0
  117. package/libs/components/modal.cjs +6 -4
  118. package/libs/components/modal.d.cts +8 -8
  119. package/libs/components/modal.d.ts +8 -8
  120. package/libs/components/modal.js +5 -3
  121. package/libs/components/nav/nav.cjs +7 -7
  122. package/libs/components/nav/nav.css +1 -1
  123. package/libs/components/nav/nav.css.map +1 -1
  124. package/libs/components/nav/nav.d.cts +550 -34
  125. package/libs/components/nav/nav.d.ts +550 -34
  126. package/libs/components/nav/nav.js +3 -3
  127. package/libs/components/nav/nav.min.css +2 -2
  128. package/libs/components/popover/popover.d.cts +5 -5
  129. package/libs/components/popover/popover.d.ts +5 -5
  130. package/libs/components/tables/table.cjs +5 -5
  131. package/libs/components/tables/table.d.cts +8 -8
  132. package/libs/components/tables/table.d.ts +8 -8
  133. package/libs/components/tables/table.js +2 -2
  134. package/libs/components/tag/tag.css +1 -1
  135. package/libs/components/tag/tag.css.map +1 -1
  136. package/libs/components/tag/tag.min.css +2 -2
  137. package/libs/components/text/text.cjs +5 -5
  138. package/libs/components/text/text.d.cts +5 -5
  139. package/libs/components/text/text.d.ts +5 -5
  140. package/libs/components/text/text.js +2 -2
  141. package/libs/form.types-d25ebfac.d.ts +233 -0
  142. package/libs/{heading-3648c538.d.ts → heading-7446cb46.d.ts} +8 -8
  143. package/libs/hooks.cjs +9 -4
  144. package/libs/hooks.d.cts +137 -3
  145. package/libs/hooks.d.ts +137 -3
  146. package/libs/hooks.js +4 -3
  147. package/libs/icons.cjs +3 -3
  148. package/libs/icons.d.cts +2 -2
  149. package/libs/icons.d.ts +2 -2
  150. package/libs/icons.js +2 -2
  151. package/libs/index.cjs +53 -51
  152. package/libs/index.cjs.map +1 -1
  153. package/libs/index.css +1 -1
  154. package/libs/index.css.map +1 -1
  155. package/libs/index.d.cts +338 -49
  156. package/libs/index.d.ts +338 -49
  157. package/libs/index.js +24 -22
  158. package/libs/index.js.map +1 -1
  159. package/libs/link-5192f411.d.ts +323 -0
  160. package/libs/list.types-d26de310.d.ts +245 -0
  161. package/libs/{ui-645f95b5.d.ts → ui-d01b50d4.d.ts} +16 -12
  162. package/package.json +4 -6
  163. package/src/components/alert/alert.scss +1 -4
  164. package/src/components/breadcrumbs/breadcrumb.tsx +4 -1
  165. package/src/components/buttons/README.mdx +102 -1
  166. package/src/components/buttons/button.stories.tsx +106 -0
  167. package/src/components/buttons/button.tsx +82 -52
  168. package/src/components/dialog/dialog-a11y-review.md +653 -0
  169. package/src/components/form/README.mdx +725 -43
  170. package/src/components/form/WCAG-REVIEW.md +654 -0
  171. package/src/components/form/fields.tsx +10 -1
  172. package/src/components/form/form.stories.tsx +604 -23
  173. package/src/components/form/form.tsx +204 -63
  174. package/src/components/form/form.types.ts +378 -0
  175. package/src/components/form/input.stories.tsx +71 -3
  176. package/src/components/form/inputs.tsx +159 -67
  177. package/src/components/form/select.tsx +122 -66
  178. package/src/components/form/textarea.tsx +120 -73
  179. package/src/components/fp.tsx +86 -11
  180. package/src/components/link/README.mdx +923 -0
  181. package/src/components/link/link.scss +79 -26
  182. package/src/components/link/link.stories.tsx +383 -30
  183. package/src/components/link/link.test.tsx +677 -0
  184. package/src/components/link/link.tsx +163 -57
  185. package/src/components/link/link.types.ts +261 -0
  186. package/src/components/list/README.mdx +764 -0
  187. package/src/components/list/list.scss +285 -0
  188. package/src/components/list/list.stories.tsx +514 -27
  189. package/src/components/list/list.test.tsx +554 -0
  190. package/src/components/list/list.tsx +153 -51
  191. package/src/components/list/list.types.ts +255 -0
  192. package/src/components/nav/ACCESSIBILITY.md +649 -0
  193. package/src/components/nav/README.mdx +782 -0
  194. package/src/components/nav/nav.scss +32 -1
  195. package/src/components/nav/nav.stories.tsx +44 -6
  196. package/src/components/nav/nav.tsx +302 -51
  197. package/src/components/nav/nav.types.ts +308 -0
  198. package/src/components/tag/README.mdx +426 -0
  199. package/src/components/tag/tag.scss +101 -27
  200. package/src/components/tag/tag.stories.tsx +384 -10
  201. package/src/components/tag/tag.test.tsx +210 -0
  202. package/src/components/tag/tag.tsx +106 -9
  203. package/src/components/tag/tag.types.ts +107 -0
  204. package/src/components/ui.tsx +8 -3
  205. package/src/hooks/use-disabled-state.test.tsx +536 -0
  206. package/src/hooks/use-disabled-state.ts +246 -0
  207. package/src/hooks/useDisabledState.md +393 -0
  208. package/src/hooks.ts +6 -0
  209. package/src/index.scss +2 -0
  210. package/src/index.ts +2 -1
  211. package/src/sass/_globals.scss +2 -7
  212. package/src/styles/alert/alert.css +1 -3
  213. package/src/styles/alert/alert.css.map +1 -1
  214. package/src/styles/index.css +450 -76
  215. package/src/styles/index.css.map +1 -1
  216. package/src/styles/link/link.css +45 -28
  217. package/src/styles/link/link.css.map +1 -1
  218. package/src/styles/list/list.css +214 -0
  219. package/src/styles/list/list.css.map +1 -0
  220. package/src/styles/nav/nav.css +21 -1
  221. package/src/styles/nav/nav.css.map +1 -1
  222. package/src/styles/tag/tag.css +113 -35
  223. package/src/styles/tag/tag.css.map +1 -1
  224. package/src/styles/utilities/_disabled.scss +58 -0
  225. package/src/types/shared.ts +43 -6
  226. package/src/utils/accessibility.ts +109 -0
  227. package/libs/chunk-2LTJ7HHX.cjs +0 -18
  228. package/libs/chunk-2LTJ7HHX.cjs.map +0 -1
  229. package/libs/chunk-2Y7W75TT.js +0 -9
  230. package/libs/chunk-2Y7W75TT.js.map +0 -1
  231. package/libs/chunk-5S4ORA4C.cjs +0 -15
  232. package/libs/chunk-5S4ORA4C.cjs.map +0 -1
  233. package/libs/chunk-AHDJGCG5.cjs +0 -15
  234. package/libs/chunk-AHDJGCG5.cjs.map +0 -1
  235. package/libs/chunk-BHRQBJRY.js +0 -8
  236. package/libs/chunk-BHRQBJRY.js.map +0 -1
  237. package/libs/chunk-GZ4QFPRY.js +0 -9
  238. package/libs/chunk-GZ4QFPRY.js.map +0 -1
  239. package/libs/chunk-IYUN2EW3.cjs +0 -15
  240. package/libs/chunk-IYUN2EW3.cjs.map +0 -1
  241. package/libs/chunk-J32EZPYD.cjs +0 -15
  242. package/libs/chunk-J32EZPYD.cjs.map +0 -1
  243. package/libs/chunk-KUKIVRC2.js +0 -7
  244. package/libs/chunk-KUKIVRC2.js.map +0 -1
  245. package/libs/chunk-L75OQKEI.cjs.map +0 -1
  246. package/libs/chunk-M5RRNTVX.cjs +0 -15
  247. package/libs/chunk-M5RRNTVX.cjs.map +0 -1
  248. package/libs/chunk-OK5QEIMD.cjs +0 -17
  249. package/libs/chunk-OK5QEIMD.cjs.map +0 -1
  250. package/libs/chunk-P7TTEYCD.js +0 -7
  251. package/libs/chunk-P7TTEYCD.js.map +0 -1
  252. package/libs/chunk-QLZWHAMK.js +0 -8
  253. package/libs/chunk-QLZWHAMK.js.map +0 -1
  254. package/libs/chunk-RIVUMPOG.js +0 -8
  255. package/libs/chunk-RIVUMPOG.js.map +0 -1
  256. package/libs/chunk-S7BABR7Z.cjs +0 -13
  257. package/libs/chunk-S7BABR7Z.cjs.map +0 -1
  258. package/libs/chunk-SMYRLO3E.js +0 -8
  259. package/libs/chunk-SMYRLO3E.js.map +0 -1
  260. package/libs/chunk-TYRCEX2L.js +0 -8
  261. package/libs/chunk-TYRCEX2L.js.map +0 -1
  262. package/libs/chunk-XBA562WW.js +0 -8
  263. package/libs/chunk-XBA562WW.js.map +0 -1
  264. package/libs/chunk-XTQKWY7W.cjs +0 -32
  265. package/libs/chunk-XTQKWY7W.cjs.map +0 -1
  266. package/libs/inputs-f3a216db.d.ts +0 -45
  267. /package/libs/{chunk-PQ2K3BM6.cjs.map → chunk-2NRIP6RB.cjs.map} +0 -0
  268. /package/libs/{chunk-772NRB75.js.map → chunk-5QD3DWFI.js.map} +0 -0
  269. /package/libs/{chunk-3MKLDCKQ.cjs.map → chunk-6WTC4JXH.cjs.map} +0 -0
  270. /package/libs/{chunk-ZANSFMTD.js.map → chunk-7XPFW7CB.js.map} +0 -0
  271. /package/libs/{chunk-ROZI23GS.cjs.map → chunk-DKTHCQ5P.cjs.map} +0 -0
  272. /package/libs/{chunk-NGTJDDFO.js.map → chunk-IQ76HGVP.js.map} +0 -0
  273. /package/libs/{chunk-JJ43O4Y5.js.map → chunk-KK47SYZI.js.map} +0 -0
  274. /package/libs/{chunk-D4YLRWAO.cjs.map → chunk-QVW6W76L.cjs.map} +0 -0
  275. /package/libs/{chunk-LT5KZ2QW.cjs.map → chunk-US2I5GI7.cjs.map} +0 -0
  276. /package/libs/{chunk-B7F5FS6D.cjs.map → chunk-W2UIN7EV.cjs.map} +0 -0
  277. /package/libs/{chunk-P2DC76ZZ.cjs.map → chunk-W5TKWBFC.cjs.map} +0 -0
  278. /package/libs/{chunk-VUH3FXGJ.js.map → chunk-X3JCTEPD.js.map} +0 -0
  279. /package/libs/{chunk-5M57K4SW.js.map → chunk-Y2PFDELK.js.map} +0 -0
  280. /package/libs/{chunk-ETFLFC2S.js.map → chunk-ZFJ4U45S.js.map} +0 -0
@@ -1,25 +1,122 @@
1
1
  import React from 'react'
2
2
  import UI from '#components/ui'
3
+ import type { TagProps, TagVariant } from './tag.types'
3
4
 
4
- export type TagProps = {
5
- /** HTML element to display the badge as span or p */
6
- elm?: 'span' | 'p'
7
- /** Aria role for the component - conditional */
8
- role: 'note' | 'status'
9
- } & React.ComponentProps<typeof UI>
10
-
5
+ /**
6
+ * Tag - A small inline label component for displaying status, versions, or environment indicators
7
+ *
8
+ * The Tag component is used to highlight supplementary information such as release stages
9
+ * (alpha, beta, stable), environment indicators (production), or version labels. It renders
10
+ * as either a `<span>` (inline) or `<p>` (block) element with semantic ARIA roles.
11
+ *
12
+ * ## Design Philosophy
13
+ *
14
+ * Tags serve as visual and semantic indicators that:
15
+ * - Communicate the state or stage of features, releases, or environments
16
+ * - Provide quick visual scanning through color-coded variants
17
+ * - Maintain accessibility through proper ARIA roles and labels
18
+ *
19
+ * ## Styling Architecture
20
+ *
21
+ * The Tag component uses CSS custom properties (CSS variables) for theming and styling,
22
+ * allowing for easy customization through the `data-tag` attribute. Each variant
23
+ * (alpha, beta, stable, production) applies predefined color schemes defined in SCSS.
24
+ *
25
+ * ## Accessibility Considerations (WCAG 2.1 AA Compliance)
26
+ *
27
+ * - **Semantic Roles**: Uses `role="note"` for static tags or `role="status"` for dynamic content
28
+ * - `role="note"`: Read once by screen readers, suitable for static labels (default)
29
+ * - `role="status"`: Announces updates to screen readers, use for changing status indicators
30
+ * - **Color Independence**: Don't rely solely on color to convey meaning - include text labels
31
+ * - **Text Alternatives**: For icon-only tags, provide `aria-label` for screen reader context
32
+ * - **Contrast Ratios**: All variants meet WCAG AA contrast requirements (4.5:1 for normal text)
33
+ * - **Live Regions**: When using `role="status"`, tag becomes a live region for accessibility
34
+ *
35
+ * ## When to Use Each Role
36
+ *
37
+ * **Use `role="note"` (default) when:**
38
+ * - Displaying static version numbers (e.g., "v2.1.0")
39
+ * - Showing fixed environment indicators (e.g., "Beta Feature")
40
+ * - Labeling unchanging content categories
41
+ *
42
+ * **Use `role="status"` when:**
43
+ * - Indicating real-time status that may change (e.g., "Processing" → "Complete")
44
+ * - Displaying live build/deployment states
45
+ * - Showing dynamic feature flags that toggle
46
+ *
47
+ * @param {TagProps} props - Component props
48
+ * @returns {React.ReactElement} A Tag component
49
+ *
50
+ * @example
51
+ * // Basic tag with beta variant (default inline span)
52
+ * <Tag variant="beta">Beta</Tag>
53
+ *
54
+ * @example
55
+ * // Production environment indicator as block element
56
+ * <Tag elm="p" variant="production">Production Environment</Tag>
57
+ *
58
+ * @example
59
+ * // Dynamic status tag with live updates
60
+ * <Tag role="status" variant="stable">
61
+ * {isDeployed ? 'Deployed' : 'Deploying...'}
62
+ * </Tag>
63
+ *
64
+ * @example
65
+ * // Tag with custom styling and accessibility label
66
+ * <Tag
67
+ * variant="alpha"
68
+ * aria-label="Alpha version - may contain bugs"
69
+ * styles={{ fontSize: '0.75rem' }}
70
+ * >
71
+ * Alpha
72
+ * </Tag>
73
+ *
74
+ * @example
75
+ * // ✅ GOOD: Clear text content with variant for visual enhancement
76
+ * <Tag variant="stable">v2.0 Stable</Tag>
77
+ *
78
+ * @example
79
+ * // ✅ GOOD: Dynamic status with proper role
80
+ * <Tag role="status" variant="production">{deploymentStatus}</Tag>
81
+ *
82
+ * @example
83
+ * // ✅ GOOD: Accessible tag with descriptive label
84
+ * <Tag variant="beta" aria-label="Beta feature - feedback welcome">
85
+ * Beta
86
+ * </Tag>
87
+ *
88
+ * @example
89
+ * // ❌ BAD: Relying only on color without text
90
+ * <Tag variant="production" aria-label="Production" />
91
+ *
92
+ * @example
93
+ * // ❌ BAD: Using status role for static content
94
+ * <Tag role="status" variant="stable">v1.0</Tag>
95
+ */
11
96
  export const Tag = ({
12
97
  elm = 'span',
13
98
  role = 'note',
99
+ variant,
14
100
  children,
15
101
  styles,
16
102
  ...props
17
103
  }: TagProps) => {
104
+ // Map variant to data-tag attribute for SCSS styling
105
+ const dataTag = variant ? variant : undefined
106
+
18
107
  return (
19
- <UI as={elm} role={role} styles={styles} {...props}>
108
+ <UI
109
+ as={elm}
110
+ role={role}
111
+ data-tag={dataTag}
112
+ styles={styles}
113
+ {...props}
114
+ >
20
115
  {children}
21
116
  </UI>
22
117
  )
23
118
  }
24
- export default Tag
119
+
25
120
  Tag.displayName = 'Tag'
121
+ export default Tag
122
+ export type { TagProps, TagVariant }
@@ -0,0 +1,107 @@
1
+ import React from 'react'
2
+ import UI from '#components/ui'
3
+
4
+ /**
5
+ * Available visual variants for the Tag component
6
+ *
7
+ * Each variant applies predefined color schemes and styling through CSS custom properties:
8
+ * - `alpha`: Early development stage indicator (warning colors)
9
+ * - `beta`: Pre-release version indicator (warning colors)
10
+ * - `stable`: Production-ready release indicator (success colors)
11
+ * - `production`: Live production environment indicator (primary colors)
12
+ *
13
+ * @example
14
+ * ```tsx
15
+ * <Tag variant="beta">Beta Feature</Tag>
16
+ * <Tag variant="stable">v2.0</Tag>
17
+ * ```
18
+ */
19
+ export type TagVariant = 'alpha' | 'beta' | 'stable' | 'production'
20
+
21
+ /**
22
+ * Props for the Tag component
23
+ *
24
+ * @property {React.ReactNode} children - REQUIRED - Content to display inside the tag (typically short text or version numbers)
25
+ * @property {'span' | 'p'} [elm='span'] - HTML element to render the tag as. Use 'p' for block-level tags, 'span' for inline
26
+ * @property {'note' | 'status'} [role='note'] - ARIA role for semantic meaning and screen reader announcements
27
+ * @property {TagVariant} [variant] - Visual variant that applies predefined color schemes (alpha, beta, stable, production)
28
+ * @property {string} [id] - Optional HTML id attribute for the tag element
29
+ * @property {React.CSSProperties} [styles] - Inline styles to apply to the tag
30
+ * @property {string} [classes] - CSS class names to apply to the tag
31
+ * @property {string} [aria-label] - Accessible label for screen readers. Recommended when tag content needs additional context
32
+ * @property {string} [aria-labelledby] - Reference to element(s) that label the tag for additional context
33
+ * @property {string} [aria-describedby] - Reference to element(s) that describe the tag for additional context
34
+ * @property {'off' | 'polite' | 'assertive'} [aria-live] - ARIA live region politeness setting for dynamic content (use with role="status")
35
+ *
36
+ * @example
37
+ * ```tsx
38
+ * // Basic tag with variant
39
+ * <Tag variant="beta">Beta</Tag>
40
+ *
41
+ * // Tag with custom element and role
42
+ * <Tag elm="p" role="status" variant="stable">v1.0 Released</Tag>
43
+ *
44
+ * // Tag with accessibility label
45
+ * <Tag variant="production" aria-label="Currently in production environment">
46
+ * Production
47
+ * </Tag>
48
+ * ```
49
+ */
50
+ export type TagProps = {
51
+ /**
52
+ * HTML element to display the tag as
53
+ * - 'span': Inline tag (default) - use for inline placement within text flow
54
+ * - 'p': Block-level tag - use when tag should appear as a distinct block element
55
+ */
56
+ elm?: 'span' | 'p'
57
+ /**
58
+ * ARIA role for semantic meaning and screen reader behavior
59
+ * - 'note': For static, informational tags (default) - screen readers read once
60
+ * - 'status': For dynamic tags that update - screen readers announce changes to users
61
+ *
62
+ * Choose 'status' when tag content changes dynamically (e.g., real-time status updates).
63
+ * Choose 'note' for static tags that provide contextual information.
64
+ */
65
+ role?: 'note' | 'status'
66
+ /**
67
+ * Visual variant that applies predefined color schemes
68
+ * - 'alpha': Early development stage (amber background with warning symbol ⚠)
69
+ * - 'beta': Pre-release version (amber background with warning symbol ⚠)
70
+ * - 'stable': Production-ready release (green background with checkmark ✓)
71
+ * - 'production': Live production environment (blue background with live indicator ●)
72
+ *
73
+ * Each variant includes both color AND visual symbols for accessibility (WCAG 1.4.1).
74
+ */
75
+ variant?: TagVariant
76
+ /**
77
+ * Content to display inside the tag
78
+ * REQUIRED - Ensures tag has meaningful content for all users including screen reader users
79
+ * Typically short text, version numbers, or status labels
80
+ */
81
+ children: React.ReactNode
82
+ /**
83
+ * Accessible label for screen readers
84
+ * Provides additional context beyond visible text
85
+ */
86
+ 'aria-label'?: string
87
+ /**
88
+ * Reference to element(s) that label the tag
89
+ * Alternative to aria-label for programmatic labeling
90
+ */
91
+ 'aria-labelledby'?: string
92
+ /**
93
+ * Reference to element(s) that describe the tag
94
+ * Provides additional descriptive context
95
+ */
96
+ 'aria-describedby'?: string
97
+ /**
98
+ * ARIA live region politeness setting
99
+ * - 'off': Updates not announced (default)
100
+ * - 'polite': Announces when user is idle (recommended for role="status")
101
+ * - 'assertive': Announces immediately (use sparingly for critical updates)
102
+ */
103
+ 'aria-live'?: 'off' | 'polite' | 'assertive'
104
+ } & Omit<
105
+ React.ComponentProps<typeof UI>,
106
+ 'as' | 'aria-label' | 'aria-labelledby' | 'aria-describedby' | 'aria-live'
107
+ >
@@ -7,6 +7,7 @@ import React from "react";
7
7
  *
8
8
  * This utility type ensures that refs are properly typed based on the element
9
9
  * being rendered. For example, a button element receives HTMLButtonElement ref.
10
+ * Excludes legacy string refs (deprecated since React 16.3).
10
11
  *
11
12
  * @typeParam C - The HTML element type (e.g., 'button', 'div', 'a')
12
13
  * @example
@@ -15,8 +16,9 @@ import React from "react";
15
16
  * type DivRef = PolymorphicRef<'div'>; // React.Ref<HTMLDivElement>
16
17
  * ```
17
18
  */
18
- type PolymorphicRef<C extends React.ElementType> =
19
- React.ComponentPropsWithRef<C>["ref"];
19
+ type PolymorphicRef<C extends React.ElementType> = React.Ref<
20
+ React.ElementRef<C>
21
+ >;
20
22
 
21
23
  /**
22
24
  * Defines the 'as' prop that determines which HTML element to render.
@@ -74,6 +76,9 @@ type PolymorphicComponentProp<
74
76
  * to match the element being rendered, enabling focus management and direct
75
77
  * DOM access for accessibility features like programmatic focus control.
76
78
  *
79
+ * Supports both PolymorphicRef and ForwardedRef for compatibility with
80
+ * React.forwardRef components.
81
+ *
77
82
  * @typeParam C - The HTML element type
78
83
  * @typeParam Props - The custom props to add
79
84
  *
@@ -93,7 +98,7 @@ type PolymorphicComponentPropWithRef<
93
98
  C extends React.ElementType,
94
99
  Props = {},
95
100
  > = PolymorphicComponentProp<C, Props> & {
96
- ref?: PolymorphicRef<C>;
101
+ ref?: PolymorphicRef<C> | React.ForwardedRef<React.ElementRef<C>>;
97
102
  };
98
103
 
99
104
  /**