@fpkit/acss 0.5.13 → 0.6.1

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 +37 -4
  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 +461 -81
  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 +32 -6
  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,9 +1,10 @@
1
1
  body > nav,
2
- [aria-label~='navbar'], .navbar {
2
+ [aria-label~="navbar"],
3
+ .navbar {
3
4
  padding-inline: var(--nav-px, 1rem);
4
5
  min-height: var(--nav-h, fit-content);
5
6
 
6
- @media(max-width: 580px) {
7
+ @media (max-width: 580px) {
7
8
  flex-direction: column;
8
9
  height: fit-content;
9
10
  min-height: fit-content;
@@ -21,7 +22,7 @@ body > nav,
21
22
  padding-inline: var(--nav-px, 0.75rem);
22
23
 
23
24
  &:hover {
24
- background-color: var(--nav-hov-bg, whitesmoke);
25
+ background-color: var(--nav-hov-bg, #e8e8e8);
25
26
  }
26
27
  &:hover:where(img) {
27
28
  background-color: transparent;
@@ -31,6 +32,12 @@ body > nav,
31
32
  }
32
33
 
33
34
  nav {
35
+ // Focus Indicator Variables (WCAG 2.4.7 - 3:1 contrast minimum)
36
+ --nav-focus-color: currentColor;
37
+ --nav-focus-width: 0.125rem; // 2px
38
+ --nav-focus-offset: 0.125rem; // 2px
39
+ --nav-focus-style: solid;
40
+
34
41
  display: var(--nav-dsp, flex);
35
42
  flex-direction: var(--nav-direction, row);
36
43
  width: var(--nav-w, auto);
@@ -49,8 +56,9 @@ nav {
49
56
  align-items: var(--nav-align, center);
50
57
  padding-inline: var(--nav-px, 1rem);
51
58
  padding-block: var(--nav-py, 0);
59
+ margin-block-end: var(--nav-mb, 0);
52
60
  height: 100%;
53
- &[data-list~='block'] {
61
+ &[data-list~="block"] {
54
62
  --nav-direction: column;
55
63
  }
56
64
  }
@@ -87,4 +95,29 @@ nav {
87
95
  > div {
88
96
  margin-block-start: 0;
89
97
  }
98
+
99
+ // Focus indicators for links and buttons (WCAG 2.4.7)
100
+ a:focus {
101
+ outline: var(--nav-focus-width) var(--nav-focus-style)
102
+ var(--nav-focus-color);
103
+ outline-offset: var(--nav-focus-offset);
104
+ }
105
+
106
+ a:focus-visible {
107
+ outline: var(--nav-focus-width) var(--nav-focus-style)
108
+ var(--nav-focus-color);
109
+ outline-offset: var(--nav-focus-offset);
110
+ }
111
+
112
+ button:focus {
113
+ outline: var(--nav-focus-width) var(--nav-focus-style)
114
+ var(--nav-focus-color);
115
+ outline-offset: var(--nav-focus-offset);
116
+ }
117
+
118
+ button:focus-visible {
119
+ outline: var(--nav-focus-width) var(--nav-focus-style)
120
+ var(--nav-focus-color);
121
+ outline-offset: var(--nav-focus-offset);
122
+ }
90
123
  }
@@ -82,17 +82,55 @@ export const MultipleNavs: Story = {
82
82
  args: {
83
83
  ...NavSection.args,
84
84
  classes: "navbar",
85
+ "aria-label": "Main navigation",
85
86
  children: (
86
87
  <>
87
- <Nav.List>
88
- <Nav.Item>Link 1</Nav.Item>
89
- <Nav.Item>Link 2</Nav.Item>
88
+ <Nav.List aria-label="Primary menu">
89
+ <Nav.Item>
90
+ <Link href="/">Home</Link>
91
+ </Nav.Item>
92
+ <Nav.Item>
93
+ <Link href="/products">Products</Link>
94
+ </Nav.Item>
90
95
  </Nav.List>
91
- <Nav.List>
92
- <Nav.Item>Link 1</Nav.Item>
93
- <Nav.Item>Link 2</Nav.Item>
96
+ <Nav.List aria-label="User menu">
97
+ <Nav.Item>
98
+ <Link href="/login">Login</Link>
99
+ </Nav.Item>
100
+ <Nav.Item>
101
+ <Link href="/signup">Sign Up</Link>
102
+ </Nav.Item>
94
103
  </Nav.List>
95
104
  </>
96
105
  ),
97
106
  },
98
107
  } as Story;
108
+
109
+ export const WithCurrentPage: Story = {
110
+ args: {
111
+ "aria-label": "Main navigation",
112
+ children: (
113
+ <Nav.List>
114
+ <Nav.Item>
115
+ <Link href="/" aria-current="page">
116
+ Home
117
+ </Link>
118
+ </Nav.Item>
119
+ <Nav.Item>
120
+ <Link href="/about">About</Link>
121
+ </Nav.Item>
122
+ <Nav.Item>
123
+ <Link href="/products">Products</Link>
124
+ </Nav.Item>
125
+ <Nav.Item>
126
+ <Link href="/contact">Contact</Link>
127
+ </Nav.Item>
128
+ </Nav.List>
129
+ ),
130
+ },
131
+ play: async ({ canvasElement }) => {
132
+ const canvas = within(canvasElement);
133
+ const homeLink = canvas.getByText(/home/i);
134
+ expect(homeLink).toHaveAttribute("aria-current", "page");
135
+ },
136
+ } as Story;
@@ -1,76 +1,327 @@
1
- import UI from '../ui'
2
- import List from '../list/list'
3
- import React from 'react'
1
+ import UI from "../ui";
2
+ import List from "../list/list";
3
+ import React from "react";
4
+ import type { NavProps, NavListProps, NavItemProps } from "./nav.types";
4
5
 
5
- export type NavListProps = React.ComponentProps<typeof List> & {
6
- isBlock?: boolean
7
- }
8
- export type NavItemProps = React.ComponentProps<typeof List.ListItem>
9
-
10
- export type NavProps = React.ComponentProps<typeof UI>
6
+ // Re-export types for external use
7
+ export type { NavProps, NavListProps, NavItemProps };
11
8
 
12
9
  /**
13
- * Renders a NavList component.
14
- * @param {Object} props - The props for the component.
15
- * @param {ReactNode} props.children - The child elements.
16
- * @param {Object} props - Additional props to spread to the List component.
17
- * @returns {JSX.Element} The rendered NavList component.
10
+ * NavList - A navigation-specific list component for grouping navigation items.
11
+ *
12
+ * Extends the List component with navigation-specific layout options through
13
+ * the `isBlock` prop. Automatically renders as an unstyled list to maintain
14
+ * clean navigation aesthetics.
15
+ *
16
+ * ## Key Features:
17
+ * - **Flexible Layout**: Supports both horizontal (inline) and vertical (block) layouts
18
+ * - **Semantic HTML**: Uses `<ul>` element for proper document structure
19
+ * - **Unstyled by Default**: Removes default list markers for clean navigation
20
+ * - **Accessible**: Works naturally with screen readers
21
+ *
22
+ * ## Accessibility:
23
+ * - ✅ Uses semantic `<ul>` element
24
+ * - ✅ Screen readers announce as "list" with item count
25
+ * - ✅ Supports `aria-label` for multiple lists
26
+ * - ✅ Keyboard navigation works naturally with focusable children
27
+ *
28
+ * ## Layout Options:
29
+ * - **Inline (default)**: Horizontal navigation bars, top menus
30
+ * - **Block**: Vertical sidebars, mobile menus, footer navigation
31
+ *
32
+ * @example
33
+ * ```tsx
34
+ * // Horizontal navigation (default)
35
+ * <NavList>
36
+ * <NavItem><Link href="/">Home</Link></NavItem>
37
+ * <NavItem><Link href="/about">About</Link></NavItem>
38
+ * </NavList>
39
+ * ```
40
+ *
41
+ * @example
42
+ * ```tsx
43
+ * // Vertical sidebar navigation
44
+ * <NavList isBlock>
45
+ * <NavItem><Link href="/dashboard">Dashboard</Link></NavItem>
46
+ * <NavItem><Link href="/settings">Settings</Link></NavItem>
47
+ * </NavList>
48
+ * ```
49
+ *
50
+ * @example
51
+ * ```tsx
52
+ * // Multiple lists with labels
53
+ * <Nav>
54
+ * <NavList aria-label="Primary navigation">
55
+ * <NavItem><Link href="/">Home</Link></NavItem>
56
+ * </NavList>
57
+ * <NavList aria-label="User menu">
58
+ * <NavItem><Link href="/profile">Profile</Link></NavItem>
59
+ * </NavList>
60
+ * </Nav>
61
+ * ```
62
+ *
63
+ * @param {NavListProps} props - Component props
64
+ * @param {boolean} [props.isBlock=false] - Display items vertically (block layout)
65
+ * @param {React.ReactNode} props.children - Navigation items (typically NavItem components)
66
+ * @param {string} [props.aria-label] - Accessible label for the list
67
+ * @returns {React.ReactElement} A navigation list component
18
68
  */
19
- export const NavList = ({ isBlock, children, ...props }: NavListProps) => {
69
+ export const NavList = React.forwardRef<
70
+ HTMLUListElement,
71
+ NavListProps
72
+ >(({ isBlock, children, ...props }, ref) => {
20
73
  return (
21
- <List type="ul" {...props} data-list={`unstyled ${isBlock ? 'block' : ''}`}>
74
+ <List
75
+ type="ul"
76
+ {...props}
77
+ data-list={isBlock ? "unstyled block" : "unstyled"}
78
+ ref={ref}
79
+ >
22
80
  {children}
23
81
  </List>
24
- )
25
- }
82
+ );
83
+ });
84
+
85
+ NavList.displayName = "NavList";
26
86
 
27
87
  /**
28
- * Renders a NavItem component.
29
- * @param {Object} props - The props for the component.
30
- * @param {string} [props.id] - The id for the component.
31
- * @param {Object} [props.styles] - The styles for the component.
32
- * @param {string} [props.classes] - The classes for the component.
33
- * @param {ReactNode} props.children - The child elements.
34
- * @param {boolean} [props.inline=true] - Whether the item should display inline.
35
- * @param {Object} props - Additional props to spread to the ListItem component.
36
- * @returns {JSX.Element} The rendered NavItem component.
88
+ * NavItem - An individual navigation link container (list item).
89
+ *
90
+ * Wraps navigation content (typically Link components) in a semantic list item
91
+ * element with consistent styling and accessibility support.
92
+ *
93
+ * ## Key Features:
94
+ * - **Semantic HTML**: Uses `<li>` element for proper list structure
95
+ * - **Flexible Content**: Accepts any React content (links, buttons, text)
96
+ * - **Customizable**: Supports custom styles and CSS classes
97
+ * - **Ref Forwarding**: Enables direct DOM access for advanced use cases
98
+ *
99
+ * ## Accessibility:
100
+ * - ✅ Uses semantic `<li>` element
101
+ * - ✅ Works with screen readers out of the box
102
+ * - ✅ Supports keyboard navigation naturally
103
+ * - ✅ Ref forwarding for programmatic focus if needed
104
+ *
105
+ * ## Best Practices:
106
+ * - Always wrap with NavList/Nav for proper semantics
107
+ * - Use `aria-current="page"` on the link inside to indicate current page
108
+ * - Ensure link text is descriptive and meaningful
109
+ * - Maintain sufficient color contrast (WCAG 2.1: 4.5:1 for normal text)
110
+ *
111
+ * @example
112
+ * ```tsx
113
+ * // Basic navigation item
114
+ * <NavItem>
115
+ * <Link href="/about">About Us</Link>
116
+ * </NavItem>
117
+ * ```
118
+ *
119
+ * @example
120
+ * ```tsx
121
+ * // Current page with aria-current
122
+ * <NavItem>
123
+ * <Link href="/about" aria-current="page">
124
+ * About Us
125
+ * </Link>
126
+ * </NavItem>
127
+ * ```
128
+ *
129
+ * @example
130
+ * ```tsx
131
+ * // Custom styling
132
+ * <NavItem
133
+ * classes="nav-item-featured"
134
+ * styles={{ fontWeight: 'bold' }}
135
+ * >
136
+ * <Link href="/special">Special Offer</Link>
137
+ * </NavItem>
138
+ * ```
139
+ *
140
+ * @example
141
+ * ```tsx
142
+ * // With icon
143
+ * <NavItem>
144
+ * <Link href="/settings">
145
+ * <SettingsIcon aria-hidden="true" />
146
+ * Settings
147
+ * </Link>
148
+ * </NavItem>
149
+ * ```
150
+ *
151
+ * @param {NavItemProps} props - Component props
152
+ * @param {React.Ref} ref - Forwarded ref for DOM access
153
+ * @returns {React.ReactElement} A navigation item component
37
154
  */
38
- export const NavItem = ({
39
- id,
40
- styles,
41
- classes,
42
- children,
43
- ...props
44
- }: NavItemProps) => {
155
+ export const NavItem = React.forwardRef<
156
+ HTMLLIElement,
157
+ NavItemProps
158
+ >(({ id, styles, classes, children, ...props }, ref) => {
45
159
  return (
46
160
  <List.ListItem
47
161
  type="li"
48
162
  id={id}
49
163
  classes={classes}
50
164
  styles={styles}
165
+ ref={ref}
51
166
  {...props}
52
167
  >
53
168
  {children}
54
169
  </List.ListItem>
55
- )
56
- }
170
+ );
171
+ });
172
+
173
+ NavItem.displayName = "NavItem";
57
174
 
58
175
  /**
59
- * Renders a Nav component.
60
- * @param {Object} props - The props for the component.
61
- * @param {ReactNode} props.children - The child elements.
62
- * @param {Object} props - Additional props to spread to the UI component.
63
- * @returns {JSX.Element} The rendered Nav component.
176
+ * Nav - A semantic navigation container component for site navigation.
177
+ *
178
+ * The Nav component provides a semantic `<nav>` landmark element that helps
179
+ * users navigate your site. It meets WCAG 2.1 AA accessibility standards and
180
+ * follows modern React best practices with full TypeScript support.
181
+ *
182
+ * ## Key Features:
183
+ * - **Semantic HTML**: Uses native `<nav>` element for accessibility
184
+ * - **Landmark Role**: Automatically provides navigation landmark for screen readers
185
+ * - **Flexible Layout**: Supports multiple navigation patterns through CSS custom properties
186
+ * - **Compound Components**: Use Nav.List and Nav.Item for consistent structure
187
+ * - **Type-Safe**: Full TypeScript support with comprehensive JSDoc documentation
188
+ * - **Ref Forwarding**: Direct DOM access for scroll positioning and focus management
189
+ *
190
+ * ## Accessibility (WCAG 2.1 AA Compliant):
191
+ * - ✅ **4.1.2 Name, Role, Value**: Uses semantic `<nav>` element (landmark role)
192
+ * - ✅ **2.4.1 Bypass Blocks**: Navigation landmark helps skip repeated content
193
+ * - ✅ **1.3.1 Info and Relationships**: Proper list structure with ul > li
194
+ * - ✅ **2.4.8 Location**: Supports `aria-label` for multiple navigation regions
195
+ * - ✅ **4.1.3 Status Messages**: Use `aria-current="page"` on links for current page
196
+ *
197
+ * ## When to Use aria-label:
198
+ * - ✅ **Required**: When you have multiple `<nav>` elements on the same page
199
+ * - ✅ **Recommended**: To distinguish navigation purpose (e.g., "Footer navigation")
200
+ * - ❌ **Not needed**: For single navigation regions
201
+ *
202
+ * ## CSS Custom Properties:
203
+ * - `--nav-dsp`: Display mode (default: flex)
204
+ * - `--nav-direction`: Flex direction (default: row)
205
+ * - `--nav-bg`: Background color
206
+ * - `--nav-h`: Minimum height
207
+ * - `--nav-px`: Horizontal padding (default: 1rem)
208
+ * - `--nav-gap`: Gap between items
209
+ * - `--nav-fs`: Font size (default: 0.9rem)
210
+ *
211
+ * @example
212
+ * ```tsx
213
+ * // Simple navigation
214
+ * <Nav>
215
+ * <Nav.List>
216
+ * <Nav.Item><Link href="/">Home</Link></Nav.Item>
217
+ * <Nav.Item><Link href="/about">About</Link></Nav.Item>
218
+ * </Nav.List>
219
+ * </Nav>
220
+ * ```
221
+ *
222
+ * @example
223
+ * ```tsx
224
+ * // Multiple navigation regions (requires aria-label)
225
+ * <Nav aria-label="Main navigation">
226
+ * <Nav.List>
227
+ * <Nav.Item><Link href="/">Home</Link></Nav.Item>
228
+ * </Nav.List>
229
+ * </Nav>
230
+ *
231
+ * <Nav aria-label="Footer navigation">
232
+ * <Nav.List>
233
+ * <Nav.Item><Link href="/privacy">Privacy</Link></Nav.Item>
234
+ * </Nav.List>
235
+ * </Nav>
236
+ * ```
237
+ *
238
+ * @example
239
+ * ```tsx
240
+ * // Current page indication
241
+ * <Nav aria-label="Main navigation">
242
+ * <Nav.List>
243
+ * <Nav.Item>
244
+ * <Link href="/" aria-current="page">Home</Link>
245
+ * </Nav.Item>
246
+ * <Nav.Item>
247
+ * <Link href="/about">About</Link>
248
+ * </Nav.Item>
249
+ * </Nav.List>
250
+ * </Nav>
251
+ * ```
252
+ *
253
+ * @example
254
+ * ```tsx
255
+ * // Vertical sidebar navigation
256
+ * <Nav aria-label="Sidebar navigation">
257
+ * <Nav.List isBlock>
258
+ * <Nav.Item><Link href="/dashboard">Dashboard</Link></Nav.Item>
259
+ * <Nav.Item><Link href="/settings">Settings</Link></Nav.Item>
260
+ * </Nav.List>
261
+ * </Nav>
262
+ * ```
263
+ *
264
+ * @example
265
+ * ```tsx
266
+ * // Complex navbar with multiple sections
267
+ * <Nav classes="navbar" aria-label="Main navigation">
268
+ * <Nav.List aria-label="Primary menu">
269
+ * <Nav.Item><Link href="/">Home</Link></Nav.Item>
270
+ * <Nav.Item><Link href="/products">Products</Link></Nav.Item>
271
+ * </Nav.List>
272
+ * <Nav.List aria-label="User menu">
273
+ * <Nav.Item><Link href="/login">Login</Link></Nav.Item>
274
+ * <Nav.Item><Link href="/signup">Sign Up</Link></Nav.Item>
275
+ * </Nav.List>
276
+ * </Nav>
277
+ * ```
278
+ *
279
+ * @example
280
+ * ```tsx
281
+ * // Custom theming with CSS properties
282
+ * <Nav
283
+ * aria-label="Main navigation"
284
+ * styles={{
285
+ * '--nav-bg': '#1a1a1a',
286
+ * '--nav-h': '4rem',
287
+ * '--nav-px': '2rem',
288
+ * }}
289
+ * >
290
+ * <Nav.List>
291
+ * <Nav.Item><Link href="/">Home</Link></Nav.Item>
292
+ * </Nav.List>
293
+ * </Nav>
294
+ * ```
295
+ *
296
+ * @param {NavProps} props - Component props
297
+ * @param {React.Ref} ref - Forwarded ref for DOM access
298
+ * @returns {React.ReactElement} A navigation element
64
299
  */
65
- export const Nav = ({ children, ...props }: NavProps) => {
66
- return (
67
- <UI as="nav" {...props}>
68
- {children}
69
- </UI>
70
- )
300
+ export const Nav = React.forwardRef<HTMLElement, NavProps>(
301
+ ({ children, ...props }, ref) => {
302
+ return (
303
+ <UI as="nav" {...props} ref={ref}>
304
+ {children}
305
+ </UI>
306
+ );
307
+ }
308
+ );
309
+
310
+ Nav.displayName = "Nav";
311
+
312
+ // Compound component pattern - attach sub-components to Nav
313
+ export interface NavComponent
314
+ extends React.ForwardRefExoticComponent<
315
+ NavProps & React.RefAttributes<HTMLElement>
316
+ > {
317
+ List: typeof NavList;
318
+ Item: typeof NavItem;
71
319
  }
72
320
 
73
- export default Nav
74
- Nav.displayName = 'Nav'
75
- Nav.List = NavList
76
- Nav.Item = NavItem
321
+ // Attach sub-components using Object.assign for better type inference
322
+ const NavWithSubComponents = Object.assign(Nav, {
323
+ List: NavList,
324
+ Item: NavItem,
325
+ });
326
+
327
+ export default NavWithSubComponents as NavComponent;