@dashforge/tw 1.0.0 → 1.1.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 (396) hide show
  1. package/CHANGELOG.md +221 -0
  2. package/README.md +74 -15
  3. package/dashforge-tw-1.0.0.tgz +0 -0
  4. package/dist/index.d.ts +1 -146
  5. package/dist/index.esm.js +3127 -748
  6. package/dist/src/components/Alert/Alert.d.ts +65 -0
  7. package/dist/src/components/Alert/Alert.d.ts.map +1 -0
  8. package/dist/src/components/Alert/alert.types.d.ts +130 -0
  9. package/dist/src/components/Alert/alert.types.d.ts.map +1 -0
  10. package/dist/src/components/Alert/alert.variants.d.ts +85 -0
  11. package/dist/src/components/Alert/alert.variants.d.ts.map +1 -0
  12. package/dist/src/components/Avatar/Avatar.d.ts +48 -0
  13. package/dist/src/components/Avatar/Avatar.d.ts.map +1 -0
  14. package/dist/src/components/Avatar/avatar.types.d.ts +162 -0
  15. package/dist/src/components/Avatar/avatar.types.d.ts.map +1 -0
  16. package/dist/src/components/Avatar/avatar.variants.d.ts +208 -0
  17. package/dist/src/components/Avatar/avatar.variants.d.ts.map +1 -0
  18. package/dist/src/components/Badge/Badge.d.ts +63 -0
  19. package/dist/src/components/Badge/Badge.d.ts.map +1 -0
  20. package/dist/src/components/Badge/badge.types.d.ts +124 -0
  21. package/dist/src/components/Badge/badge.types.d.ts.map +1 -0
  22. package/dist/src/components/Badge/badge.variants.d.ts +262 -0
  23. package/dist/src/components/Badge/badge.variants.d.ts.map +1 -0
  24. package/dist/src/components/Box/Box.d.ts.map +1 -1
  25. package/dist/src/components/Box/box.types.d.ts +53 -0
  26. package/dist/src/components/Box/box.types.d.ts.map +1 -1
  27. package/dist/src/components/Button/Button.d.ts.map +1 -1
  28. package/dist/src/components/Button/button.types.d.ts +35 -0
  29. package/dist/src/components/Button/button.types.d.ts.map +1 -1
  30. package/dist/src/components/Card/Card.d.ts +107 -0
  31. package/dist/src/components/Card/Card.d.ts.map +1 -0
  32. package/dist/src/components/Card/card.types.d.ts +119 -0
  33. package/dist/src/components/Card/card.types.d.ts.map +1 -0
  34. package/dist/src/components/Chip/Chip.d.ts +67 -0
  35. package/dist/src/components/Chip/Chip.d.ts.map +1 -0
  36. package/dist/src/components/Chip/chip.types.d.ts +113 -0
  37. package/dist/src/components/Chip/chip.types.d.ts.map +1 -0
  38. package/dist/src/components/Chip/chip.variants.d.ts +155 -0
  39. package/dist/src/components/Chip/chip.variants.d.ts.map +1 -0
  40. package/dist/src/components/IconButton/IconButton.d.ts +57 -0
  41. package/dist/src/components/IconButton/IconButton.d.ts.map +1 -0
  42. package/dist/src/components/IconButton/iconButton.types.d.ts +96 -0
  43. package/dist/src/components/IconButton/iconButton.types.d.ts.map +1 -0
  44. package/dist/src/components/IconButton/iconButton.variants.d.ts +26 -0
  45. package/dist/src/components/IconButton/iconButton.variants.d.ts.map +1 -0
  46. package/dist/src/components/Menu/Menu.d.ts +118 -0
  47. package/dist/src/components/Menu/Menu.d.ts.map +1 -0
  48. package/dist/src/components/Menu/menu.types.d.ts +179 -0
  49. package/dist/src/components/Menu/menu.types.d.ts.map +1 -0
  50. package/dist/src/components/Menu/menu.variants.d.ts +129 -0
  51. package/dist/src/components/Menu/menu.variants.d.ts.map +1 -0
  52. package/dist/src/components/Snackbar/Snackbar.d.ts.map +1 -1
  53. package/dist/src/components/Snackbar/snackbar.types.d.ts +40 -3
  54. package/dist/src/components/Snackbar/snackbar.types.d.ts.map +1 -1
  55. package/dist/src/components/Snackbar/snackbar.variants.d.ts +12 -57
  56. package/dist/src/components/Snackbar/snackbar.variants.d.ts.map +1 -1
  57. package/dist/src/components/Spinner/Spinner.d.ts +44 -0
  58. package/dist/src/components/Spinner/Spinner.d.ts.map +1 -0
  59. package/dist/src/components/Spinner/spinner.types.d.ts +89 -0
  60. package/dist/src/components/Spinner/spinner.types.d.ts.map +1 -0
  61. package/dist/src/components/Spinner/spinner.variants.d.ts +111 -0
  62. package/dist/src/components/Spinner/spinner.variants.d.ts.map +1 -0
  63. package/dist/src/components/Table/cells/RenderChip.d.ts +15 -72
  64. package/dist/src/components/Table/cells/RenderChip.d.ts.map +1 -1
  65. package/dist/src/components/_shared/severity/index.d.ts +21 -0
  66. package/dist/src/components/_shared/severity/index.d.ts.map +1 -0
  67. package/dist/src/components/_shared/severity/severity.types.d.ts +48 -0
  68. package/dist/src/components/_shared/severity/severity.types.d.ts.map +1 -0
  69. package/dist/src/components/_shared/severity/severityIcons.d.ts +45 -0
  70. package/dist/src/components/_shared/severity/severityIcons.d.ts.map +1 -0
  71. package/dist/src/components/_shared/severity/severityVariants.d.ts +22 -0
  72. package/dist/src/components/_shared/severity/severityVariants.d.ts.map +1 -0
  73. package/dist/src/index.d.ts +27 -2
  74. package/dist/src/index.d.ts.map +1 -1
  75. package/package.json +2 -1
  76. package/src/components/Alert/Alert.test.tsx +302 -0
  77. package/src/components/Alert/Alert.tsx +186 -0
  78. package/src/components/Alert/alert.types.ts +144 -0
  79. package/src/components/Alert/alert.variants.ts +71 -0
  80. package/src/components/Autocomplete/autocomplete.variants.ts +1 -1
  81. package/src/components/Avatar/Avatar.test.tsx +287 -0
  82. package/src/components/Avatar/Avatar.tsx +304 -0
  83. package/src/components/Avatar/avatar.types.ts +205 -0
  84. package/src/components/Avatar/avatar.variants.ts +194 -0
  85. package/src/components/Badge/Badge.test.tsx +385 -0
  86. package/src/components/Badge/Badge.tsx +174 -0
  87. package/src/components/Badge/badge.types.ts +154 -0
  88. package/src/components/Badge/badge.variants.ts +161 -0
  89. package/src/components/Box/Box.test.tsx +21 -0
  90. package/src/components/Box/Box.tsx +32 -3
  91. package/src/components/Box/box.types.ts +55 -0
  92. package/src/components/Button/Button.test.tsx +21 -0
  93. package/src/components/Button/Button.tsx +28 -27
  94. package/src/components/Button/button.types.ts +36 -0
  95. package/src/components/Card/Card.test.tsx +291 -0
  96. package/src/components/Card/Card.tsx +241 -0
  97. package/src/components/Card/card.types.ts +132 -0
  98. package/src/components/Chip/Chip.test.tsx +316 -0
  99. package/src/components/Chip/Chip.tsx +224 -0
  100. package/src/components/Chip/chip.types.ts +128 -0
  101. package/src/components/Chip/chip.variants.ts +173 -0
  102. package/src/components/DataGrid/visibility/ColumnVisibilityMenu.tsx +1 -1
  103. package/src/components/IconButton/IconButton.test.tsx +367 -0
  104. package/src/components/IconButton/IconButton.tsx +159 -0
  105. package/src/components/IconButton/iconButton.types.ts +106 -0
  106. package/src/components/IconButton/iconButton.variants.ts +31 -0
  107. package/src/components/LeftNav/leftNav.variants.ts +2 -2
  108. package/src/components/Menu/Menu.test.tsx +408 -0
  109. package/src/components/Menu/Menu.tsx +335 -0
  110. package/src/components/Menu/menu.types.ts +221 -0
  111. package/src/components/Menu/menu.variants.ts +132 -0
  112. package/src/components/Pagination/pagination.variants.ts +1 -1
  113. package/src/components/Snackbar/Snackbar.tsx +46 -28
  114. package/src/components/Snackbar/snackbar.types.ts +47 -3
  115. package/src/components/Snackbar/snackbar.variants.ts +29 -22
  116. package/src/components/Spinner/Spinner.test.tsx +199 -0
  117. package/src/components/Spinner/Spinner.tsx +158 -0
  118. package/src/components/Spinner/spinner.types.ts +113 -0
  119. package/src/components/Spinner/spinner.variants.ts +83 -0
  120. package/src/components/Table/cells/RenderChip.tsx +24 -87
  121. package/src/components/Table/cells/RowActionsMenu.tsx +1 -1
  122. package/src/components/_shared/severity/index.ts +33 -0
  123. package/src/components/_shared/severity/severity.types.ts +50 -0
  124. package/src/components/_shared/severity/severityIcons.tsx +104 -0
  125. package/src/components/_shared/severity/severityVariants.test.ts +136 -0
  126. package/src/components/_shared/severity/severityVariants.ts +115 -0
  127. package/src/index.ts +163 -1
  128. package/LICENSE +0 -21
  129. package/dist/components/Accordion/Accordion.d.ts +0 -21
  130. package/dist/components/Accordion/Accordion.d.ts.map +0 -1
  131. package/dist/components/Accordion/accordion.types.d.ts +0 -74
  132. package/dist/components/Accordion/accordion.types.d.ts.map +0 -1
  133. package/dist/components/Accordion/accordion.variants.d.ts +0 -58
  134. package/dist/components/Accordion/accordion.variants.d.ts.map +0 -1
  135. package/dist/components/AppShell/AppShell.d.ts +0 -46
  136. package/dist/components/AppShell/AppShell.d.ts.map +0 -1
  137. package/dist/components/AppShell/appShell.types.d.ts +0 -62
  138. package/dist/components/AppShell/appShell.types.d.ts.map +0 -1
  139. package/dist/components/AppShell/appShell.variants.d.ts +0 -65
  140. package/dist/components/AppShell/appShell.variants.d.ts.map +0 -1
  141. package/dist/components/AspectRatio/AspectRatio.d.ts +0 -36
  142. package/dist/components/AspectRatio/AspectRatio.d.ts.map +0 -1
  143. package/dist/components/AspectRatio/aspectRatio.types.d.ts +0 -50
  144. package/dist/components/AspectRatio/aspectRatio.types.d.ts.map +0 -1
  145. package/dist/components/Autocomplete/Autocomplete.d.ts +0 -32
  146. package/dist/components/Autocomplete/Autocomplete.d.ts.map +0 -1
  147. package/dist/components/Autocomplete/autocomplete.types.d.ts +0 -214
  148. package/dist/components/Autocomplete/autocomplete.types.d.ts.map +0 -1
  149. package/dist/components/Autocomplete/autocomplete.variants.d.ts +0 -214
  150. package/dist/components/Autocomplete/autocomplete.variants.d.ts.map +0 -1
  151. package/dist/components/Box/Box.d.ts +0 -36
  152. package/dist/components/Box/Box.d.ts.map +0 -1
  153. package/dist/components/Box/box.types.d.ts +0 -54
  154. package/dist/components/Box/box.types.d.ts.map +0 -1
  155. package/dist/components/Box/box.variants.d.ts +0 -402
  156. package/dist/components/Box/box.variants.d.ts.map +0 -1
  157. package/dist/components/Breadcrumbs/Breadcrumbs.d.ts +0 -23
  158. package/dist/components/Breadcrumbs/Breadcrumbs.d.ts.map +0 -1
  159. package/dist/components/Breadcrumbs/breadcrumbs.types.d.ts +0 -98
  160. package/dist/components/Breadcrumbs/breadcrumbs.types.d.ts.map +0 -1
  161. package/dist/components/Breadcrumbs/breadcrumbs.variants.d.ts +0 -85
  162. package/dist/components/Breadcrumbs/breadcrumbs.variants.d.ts.map +0 -1
  163. package/dist/components/Button/Button.d.ts +0 -44
  164. package/dist/components/Button/Button.d.ts.map +0 -1
  165. package/dist/components/Button/button.types.d.ts +0 -66
  166. package/dist/components/Button/button.types.d.ts.map +0 -1
  167. package/dist/components/Button/button.variants.d.ts +0 -104
  168. package/dist/components/Button/button.variants.d.ts.map +0 -1
  169. package/dist/components/Calendar/Calendar.d.ts +0 -14
  170. package/dist/components/Calendar/Calendar.d.ts.map +0 -1
  171. package/dist/components/Calendar/calendar.types.d.ts +0 -72
  172. package/dist/components/Calendar/calendar.types.d.ts.map +0 -1
  173. package/dist/components/Calendar/calendar.variants.d.ts +0 -99
  174. package/dist/components/Calendar/calendar.variants.d.ts.map +0 -1
  175. package/dist/components/Checkbox/Checkbox.d.ts +0 -31
  176. package/dist/components/Checkbox/Checkbox.d.ts.map +0 -1
  177. package/dist/components/Checkbox/checkbox.types.d.ts +0 -86
  178. package/dist/components/Checkbox/checkbox.types.d.ts.map +0 -1
  179. package/dist/components/Checkbox/checkbox.variants.d.ts +0 -109
  180. package/dist/components/Checkbox/checkbox.variants.d.ts.map +0 -1
  181. package/dist/components/ConfirmDialog/ConfirmDialog.d.ts +0 -38
  182. package/dist/components/ConfirmDialog/ConfirmDialog.d.ts.map +0 -1
  183. package/dist/components/ConfirmDialog/confirmDialog.types.d.ts +0 -80
  184. package/dist/components/ConfirmDialog/confirmDialog.types.d.ts.map +0 -1
  185. package/dist/components/ConfirmDialog/confirmDialog.variants.d.ts +0 -90
  186. package/dist/components/ConfirmDialog/confirmDialog.variants.d.ts.map +0 -1
  187. package/dist/components/Container/Container.d.ts +0 -35
  188. package/dist/components/Container/Container.d.ts.map +0 -1
  189. package/dist/components/Container/container.types.d.ts +0 -41
  190. package/dist/components/Container/container.types.d.ts.map +0 -1
  191. package/dist/components/Container/container.variants.d.ts +0 -93
  192. package/dist/components/Container/container.variants.d.ts.map +0 -1
  193. package/dist/components/DataGrid/DataGrid.d.ts +0 -29
  194. package/dist/components/DataGrid/DataGrid.d.ts.map +0 -1
  195. package/dist/components/DataGrid/dataGrid.types.d.ts +0 -214
  196. package/dist/components/DataGrid/dataGrid.types.d.ts.map +0 -1
  197. package/dist/components/DataGrid/dataGrid.variants.d.ts +0 -222
  198. package/dist/components/DataGrid/dataGrid.variants.d.ts.map +0 -1
  199. package/dist/components/DataGrid/filters/ColumnFilters.d.ts +0 -23
  200. package/dist/components/DataGrid/filters/ColumnFilters.d.ts.map +0 -1
  201. package/dist/components/DataGrid/reorder/useColumnReorder.d.ts +0 -50
  202. package/dist/components/DataGrid/reorder/useColumnReorder.d.ts.map +0 -1
  203. package/dist/components/DataGrid/resize/useColumnResize.d.ts +0 -39
  204. package/dist/components/DataGrid/resize/useColumnResize.d.ts.map +0 -1
  205. package/dist/components/DataGrid/visibility/ColumnVisibilityMenu.d.ts +0 -44
  206. package/dist/components/DataGrid/visibility/ColumnVisibilityMenu.d.ts.map +0 -1
  207. package/dist/components/DatePicker/DatePicker.d.ts +0 -14
  208. package/dist/components/DatePicker/DatePicker.d.ts.map +0 -1
  209. package/dist/components/DatePicker/datePicker.types.d.ts +0 -88
  210. package/dist/components/DatePicker/datePicker.types.d.ts.map +0 -1
  211. package/dist/components/DatePicker/datePicker.variants.d.ts +0 -97
  212. package/dist/components/DatePicker/datePicker.variants.d.ts.map +0 -1
  213. package/dist/components/DateRangePicker/DateRangePicker.d.ts +0 -13
  214. package/dist/components/DateRangePicker/DateRangePicker.d.ts.map +0 -1
  215. package/dist/components/DateRangePicker/dateRangePicker.types.d.ts +0 -85
  216. package/dist/components/DateRangePicker/dateRangePicker.types.d.ts.map +0 -1
  217. package/dist/components/DateRangePicker/dateRangePicker.variants.d.ts +0 -183
  218. package/dist/components/DateRangePicker/dateRangePicker.variants.d.ts.map +0 -1
  219. package/dist/components/DateTimePicker/DateTimePicker.d.ts +0 -13
  220. package/dist/components/DateTimePicker/DateTimePicker.d.ts.map +0 -1
  221. package/dist/components/DateTimePicker/dateTimePicker.types.d.ts +0 -90
  222. package/dist/components/DateTimePicker/dateTimePicker.types.d.ts.map +0 -1
  223. package/dist/components/DateTimePicker/dateTimePicker.variants.d.ts +0 -107
  224. package/dist/components/DateTimePicker/dateTimePicker.variants.d.ts.map +0 -1
  225. package/dist/components/Dialog/Dialog.d.ts +0 -17
  226. package/dist/components/Dialog/Dialog.d.ts.map +0 -1
  227. package/dist/components/Dialog/dialog.types.d.ts +0 -75
  228. package/dist/components/Dialog/dialog.types.d.ts.map +0 -1
  229. package/dist/components/Dialog/dialog.variants.d.ts +0 -80
  230. package/dist/components/Dialog/dialog.variants.d.ts.map +0 -1
  231. package/dist/components/Divider/Divider.d.ts +0 -50
  232. package/dist/components/Divider/Divider.d.ts.map +0 -1
  233. package/dist/components/Divider/divider.types.d.ts +0 -47
  234. package/dist/components/Divider/divider.types.d.ts.map +0 -1
  235. package/dist/components/Divider/divider.variants.d.ts +0 -129
  236. package/dist/components/Divider/divider.variants.d.ts.map +0 -1
  237. package/dist/components/Grid/Grid.d.ts +0 -32
  238. package/dist/components/Grid/Grid.d.ts.map +0 -1
  239. package/dist/components/Grid/grid.types.d.ts +0 -103
  240. package/dist/components/Grid/grid.types.d.ts.map +0 -1
  241. package/dist/components/Grid/grid.variants.d.ts +0 -453
  242. package/dist/components/Grid/grid.variants.d.ts.map +0 -1
  243. package/dist/components/LeftNav/LeftNav.d.ts +0 -34
  244. package/dist/components/LeftNav/LeftNav.d.ts.map +0 -1
  245. package/dist/components/LeftNav/leftNav.types.d.ts +0 -136
  246. package/dist/components/LeftNav/leftNav.types.d.ts.map +0 -1
  247. package/dist/components/LeftNav/leftNav.variants.d.ts +0 -143
  248. package/dist/components/LeftNav/leftNav.variants.d.ts.map +0 -1
  249. package/dist/components/NumberField/NumberField.d.ts +0 -18
  250. package/dist/components/NumberField/NumberField.d.ts.map +0 -1
  251. package/dist/components/NumberField/numberField.types.d.ts +0 -79
  252. package/dist/components/NumberField/numberField.types.d.ts.map +0 -1
  253. package/dist/components/NumberField/numberField.variants.d.ts +0 -169
  254. package/dist/components/NumberField/numberField.variants.d.ts.map +0 -1
  255. package/dist/components/OTPField/OTPField.d.ts +0 -25
  256. package/dist/components/OTPField/OTPField.d.ts.map +0 -1
  257. package/dist/components/OTPField/otpField.types.d.ts +0 -74
  258. package/dist/components/OTPField/otpField.types.d.ts.map +0 -1
  259. package/dist/components/OTPField/otpField.variants.d.ts +0 -105
  260. package/dist/components/OTPField/otpField.variants.d.ts.map +0 -1
  261. package/dist/components/Pagination/Pagination.d.ts +0 -32
  262. package/dist/components/Pagination/Pagination.d.ts.map +0 -1
  263. package/dist/components/Pagination/pagination.helpers.d.ts +0 -23
  264. package/dist/components/Pagination/pagination.helpers.d.ts.map +0 -1
  265. package/dist/components/Pagination/pagination.types.d.ts +0 -120
  266. package/dist/components/Pagination/pagination.types.d.ts.map +0 -1
  267. package/dist/components/Pagination/pagination.variants.d.ts +0 -150
  268. package/dist/components/Pagination/pagination.variants.d.ts.map +0 -1
  269. package/dist/components/Popover/Popover.d.ts +0 -15
  270. package/dist/components/Popover/Popover.d.ts.map +0 -1
  271. package/dist/components/Popover/popover.types.d.ts +0 -45
  272. package/dist/components/Popover/popover.types.d.ts.map +0 -1
  273. package/dist/components/Popover/popover.variants.d.ts +0 -34
  274. package/dist/components/Popover/popover.variants.d.ts.map +0 -1
  275. package/dist/components/RadioGroup/RadioGroup.d.ts +0 -35
  276. package/dist/components/RadioGroup/RadioGroup.d.ts.map +0 -1
  277. package/dist/components/RadioGroup/radioGroup.types.d.ts +0 -103
  278. package/dist/components/RadioGroup/radioGroup.types.d.ts.map +0 -1
  279. package/dist/components/RadioGroup/radioGroup.variants.d.ts +0 -166
  280. package/dist/components/RadioGroup/radioGroup.variants.d.ts.map +0 -1
  281. package/dist/components/Skeleton/Skeleton.d.ts +0 -23
  282. package/dist/components/Skeleton/Skeleton.d.ts.map +0 -1
  283. package/dist/components/Skeleton/skeleton.types.d.ts +0 -56
  284. package/dist/components/Skeleton/skeleton.types.d.ts.map +0 -1
  285. package/dist/components/Skeleton/skeleton.variants.d.ts +0 -110
  286. package/dist/components/Skeleton/skeleton.variants.d.ts.map +0 -1
  287. package/dist/components/Snackbar/Snackbar.d.ts +0 -37
  288. package/dist/components/Snackbar/Snackbar.d.ts.map +0 -1
  289. package/dist/components/Snackbar/snackbar.types.d.ts +0 -86
  290. package/dist/components/Snackbar/snackbar.types.d.ts.map +0 -1
  291. package/dist/components/Snackbar/snackbar.variants.d.ts +0 -153
  292. package/dist/components/Snackbar/snackbar.variants.d.ts.map +0 -1
  293. package/dist/components/Stack/Stack.d.ts +0 -24
  294. package/dist/components/Stack/Stack.d.ts.map +0 -1
  295. package/dist/components/Stack/stack.types.d.ts +0 -61
  296. package/dist/components/Stack/stack.types.d.ts.map +0 -1
  297. package/dist/components/Stack/stack.variants.d.ts +0 -163
  298. package/dist/components/Stack/stack.variants.d.ts.map +0 -1
  299. package/dist/components/Switch/Switch.d.ts +0 -15
  300. package/dist/components/Switch/Switch.d.ts.map +0 -1
  301. package/dist/components/Switch/switch.types.d.ts +0 -47
  302. package/dist/components/Switch/switch.types.d.ts.map +0 -1
  303. package/dist/components/Switch/switch.variants.d.ts +0 -105
  304. package/dist/components/Switch/switch.variants.d.ts.map +0 -1
  305. package/dist/components/Table/Table.d.ts +0 -24
  306. package/dist/components/Table/Table.d.ts.map +0 -1
  307. package/dist/components/Table/cells/RenderButton.d.ts +0 -13
  308. package/dist/components/Table/cells/RenderButton.d.ts.map +0 -1
  309. package/dist/components/Table/cells/RenderChip.d.ts +0 -80
  310. package/dist/components/Table/cells/RenderChip.d.ts.map +0 -1
  311. package/dist/components/Table/cells/RenderText.d.ts +0 -21
  312. package/dist/components/Table/cells/RenderText.d.ts.map +0 -1
  313. package/dist/components/Table/cells/RenderTwoLine.d.ts +0 -20
  314. package/dist/components/Table/cells/RenderTwoLine.d.ts.map +0 -1
  315. package/dist/components/Table/cells/RowActionsMenu.d.ts +0 -36
  316. package/dist/components/Table/cells/RowActionsMenu.d.ts.map +0 -1
  317. package/dist/components/Table/cells/index.d.ts +0 -11
  318. package/dist/components/Table/cells/index.d.ts.map +0 -1
  319. package/dist/components/Table/table.types.d.ts +0 -399
  320. package/dist/components/Table/table.types.d.ts.map +0 -1
  321. package/dist/components/Table/table.variants.d.ts +0 -285
  322. package/dist/components/Table/table.variants.d.ts.map +0 -1
  323. package/dist/components/Tabs/Tabs.d.ts +0 -19
  324. package/dist/components/Tabs/Tabs.d.ts.map +0 -1
  325. package/dist/components/Tabs/tabs.types.d.ts +0 -61
  326. package/dist/components/Tabs/tabs.types.d.ts.map +0 -1
  327. package/dist/components/Tabs/tabs.variants.d.ts +0 -82
  328. package/dist/components/Tabs/tabs.variants.d.ts.map +0 -1
  329. package/dist/components/Tabs/useTabs.d.ts +0 -55
  330. package/dist/components/Tabs/useTabs.d.ts.map +0 -1
  331. package/dist/components/TextField/TextField.d.ts +0 -25
  332. package/dist/components/TextField/TextField.d.ts.map +0 -1
  333. package/dist/components/TextField/textField.types.d.ts +0 -98
  334. package/dist/components/TextField/textField.types.d.ts.map +0 -1
  335. package/dist/components/TextField/textField.variants.d.ts +0 -166
  336. package/dist/components/TextField/textField.variants.d.ts.map +0 -1
  337. package/dist/components/Textarea/Textarea.d.ts +0 -16
  338. package/dist/components/Textarea/Textarea.d.ts.map +0 -1
  339. package/dist/components/Textarea/textarea.types.d.ts +0 -63
  340. package/dist/components/Textarea/textarea.types.d.ts.map +0 -1
  341. package/dist/components/Textarea/textarea.variants.d.ts +0 -197
  342. package/dist/components/Textarea/textarea.variants.d.ts.map +0 -1
  343. package/dist/components/TimePicker/TimePicker.d.ts +0 -12
  344. package/dist/components/TimePicker/TimePicker.d.ts.map +0 -1
  345. package/dist/components/TimePicker/timePicker.types.d.ts +0 -80
  346. package/dist/components/TimePicker/timePicker.types.d.ts.map +0 -1
  347. package/dist/components/TimePicker/timePicker.variants.d.ts +0 -103
  348. package/dist/components/TimePicker/timePicker.variants.d.ts.map +0 -1
  349. package/dist/components/Tooltip/Tooltip.d.ts +0 -29
  350. package/dist/components/Tooltip/Tooltip.d.ts.map +0 -1
  351. package/dist/components/Tooltip/tooltip.types.d.ts +0 -47
  352. package/dist/components/Tooltip/tooltip.types.d.ts.map +0 -1
  353. package/dist/components/Tooltip/tooltip.variants.d.ts +0 -34
  354. package/dist/components/Tooltip/tooltip.variants.d.ts.map +0 -1
  355. package/dist/components/TopBar/TopBar.d.ts +0 -33
  356. package/dist/components/TopBar/TopBar.d.ts.map +0 -1
  357. package/dist/components/TopBar/topBar.types.d.ts +0 -49
  358. package/dist/components/TopBar/topBar.types.d.ts.map +0 -1
  359. package/dist/components/TopBar/topBar.variants.d.ts +0 -79
  360. package/dist/components/TopBar/topBar.variants.d.ts.map +0 -1
  361. package/dist/components/Typography/Typography.d.ts +0 -42
  362. package/dist/components/Typography/Typography.d.ts.map +0 -1
  363. package/dist/components/Typography/typography.types.d.ts +0 -61
  364. package/dist/components/Typography/typography.types.d.ts.map +0 -1
  365. package/dist/components/Typography/typography.variants.d.ts +0 -167
  366. package/dist/components/Typography/typography.variants.d.ts.map +0 -1
  367. package/dist/components/VisuallyHidden/VisuallyHidden.d.ts +0 -42
  368. package/dist/components/VisuallyHidden/VisuallyHidden.d.ts.map +0 -1
  369. package/dist/components/VisuallyHidden/visuallyHidden.types.d.ts +0 -42
  370. package/dist/components/VisuallyHidden/visuallyHidden.types.d.ts.map +0 -1
  371. package/dist/components/_shared/data/getNestedValue.d.ts +0 -20
  372. package/dist/components/_shared/data/getNestedValue.d.ts.map +0 -1
  373. package/dist/components/_shared/data/useColumnAutoDetect.d.ts +0 -45
  374. package/dist/components/_shared/data/useColumnAutoDetect.d.ts.map +0 -1
  375. package/dist/components/_shared/data/useControllableState.d.ts +0 -23
  376. package/dist/components/_shared/data/useControllableState.d.ts.map +0 -1
  377. package/dist/components/_shared/data/useDebouncedValue.d.ts +0 -10
  378. package/dist/components/_shared/data/useDebouncedValue.d.ts.map +0 -1
  379. package/dist/components/_shared/data/useTableFilter.d.ts +0 -36
  380. package/dist/components/_shared/data/useTableFilter.d.ts.map +0 -1
  381. package/dist/components/_shared/data/useTableSearch.d.ts +0 -23
  382. package/dist/components/_shared/data/useTableSearch.d.ts.map +0 -1
  383. package/dist/components/_shared/data/useTableSelection.d.ts +0 -25
  384. package/dist/components/_shared/data/useTableSelection.d.ts.map +0 -1
  385. package/dist/components/_shared/data/useTableSort.d.ts +0 -20
  386. package/dist/components/_shared/data/useTableSort.d.ts.map +0 -1
  387. package/dist/components/_shared/data/useVirtualizer.d.ts +0 -107
  388. package/dist/components/_shared/data/useVirtualizer.d.ts.map +0 -1
  389. package/dist/components/_shared/resolveValidationState.d.ts +0 -42
  390. package/dist/components/_shared/resolveValidationState.d.ts.map +0 -1
  391. package/dist/hooks/useAccessState.d.ts +0 -37
  392. package/dist/hooks/useAccessState.d.ts.map +0 -1
  393. package/dist/index.d.ts.map +0 -1
  394. package/dist/tsconfig.lib.tsbuildinfo +0 -1
  395. package/dist/utils/cn.d.ts +0 -26
  396. package/dist/utils/cn.d.ts.map +0 -1
@@ -0,0 +1,173 @@
1
+ import { tv, type VariantProps } from 'tailwind-variants';
2
+
3
+ /**
4
+ * Tailwind-variants recipe for `<Chip>` — promoted from the internal
5
+ * `Table/cells/RenderChip` (Sprint 4.4). The visual treatment is
6
+ * preserved byte-identical: the same 3 × 7 compound matrix
7
+ * (variant × color) emitted by RenderChip is now the single source
8
+ * of truth, consumed by both the public `<Chip>` and (via thin
9
+ * wrapper) the legacy `RenderChip` internal.
10
+ *
11
+ * Slots (only `root` slot used by the public Chip; sub-slots
12
+ * surfaced via separate inline classes in `Chip.tsx`):
13
+ * - `root` — outer chip surface
14
+ *
15
+ * Variants axis (3 × 7, plus orthogonal `size`):
16
+ * - `color`: 7 intents (`neutral / primary / secondary / success /
17
+ * warning / danger / info`)
18
+ * - `variant`: `soft` (default) / `solid` / `outline`
19
+ * - `size`: `sm` (default) / `md`
20
+ *
21
+ * Token-driven: every Tailwind utility resolves through
22
+ * `dashforgePreset()` → CSS variables. No hardcoded hex.
23
+ *
24
+ * `dark:` variants on color palettes (lines 49-77 of legacy
25
+ * RenderChip, preserved here) are INTENTIONAL — color palettes do not
26
+ * auto-invert via the CSS-var swap (only the `neutral` palette does),
27
+ * so the `dark:` shift is a deliberate design choice (darker bg +
28
+ * lighter text in dark mode for visual cohesion). `dark:` on the
29
+ * `neutral` row is AVOIDED — that would double-invert.
30
+ */
31
+ export const chipVariants = tv({
32
+ base: [
33
+ 'inline-flex items-center gap-1 rounded-full font-medium',
34
+ 'whitespace-nowrap',
35
+ // Smooth transitions for clickable / selected state changes.
36
+ 'transition-colors',
37
+ 'motion-reduce:transition-none',
38
+ ],
39
+ variants: {
40
+ color: {
41
+ neutral: '',
42
+ primary: '',
43
+ secondary: '',
44
+ success: '',
45
+ warning: '',
46
+ danger: '',
47
+ info: '',
48
+ },
49
+ variant: {
50
+ soft: '',
51
+ solid: '',
52
+ outline: '',
53
+ },
54
+ size: {
55
+ sm: 'h-5 px-2 text-xs',
56
+ md: 'h-6 px-2.5 text-xs',
57
+ },
58
+ /**
59
+ * Clickable state — adds focus ring + hover transition. Applied
60
+ * when the chip renders as `<button>` (i.e. `onClick` or
61
+ * explicit `clickable` is set).
62
+ */
63
+ clickable: {
64
+ true: [
65
+ 'cursor-pointer select-none',
66
+ 'outline-none focus-visible:ring-2 focus-visible:ring-offset-1',
67
+ ],
68
+ },
69
+ /**
70
+ * Selected state — used on filter chips to indicate active
71
+ * selection. Visually shifts the chip to a heavier emphasis
72
+ * (one step up the elevation ladder of its current variant).
73
+ * Compound rules below apply the actual shift per (variant, color)
74
+ * cell.
75
+ */
76
+ selected: {
77
+ true: 'ring-2 ring-offset-1',
78
+ },
79
+ /** Disabled state for clickable chips. */
80
+ disabled: {
81
+ true: 'opacity-50 cursor-not-allowed pointer-events-none',
82
+ },
83
+ },
84
+ compoundVariants: [
85
+ // ─── soft × color ──────────────────────────────────────────────
86
+ // Subtle bg + readable text. Neutral row uses NO `dark:` (auto-
87
+ // inverts via the dashforgePreset CSS-var swap). Color rows KEEP
88
+ // `dark:` (color palettes don't auto-invert).
89
+ { variant: 'soft', color: 'neutral', class: 'bg-neutral-100 text-neutral-700' },
90
+ { variant: 'soft', color: 'primary', class: 'bg-primary-100 dark:bg-primary-950 text-primary-700 dark:text-primary-300' },
91
+ { variant: 'soft', color: 'secondary', class: 'bg-secondary-100 dark:bg-secondary-950 text-secondary-700 dark:text-secondary-300' },
92
+ { variant: 'soft', color: 'success', class: 'bg-success-100 dark:bg-success-950 text-success-700 dark:text-success-300' },
93
+ { variant: 'soft', color: 'warning', class: 'bg-warning-100 dark:bg-warning-950 text-warning-700 dark:text-warning-300' },
94
+ { variant: 'soft', color: 'danger', class: 'bg-danger-100 dark:bg-danger-950 text-danger-700 dark:text-danger-300' },
95
+ { variant: 'soft', color: 'info', class: 'bg-info-100 dark:bg-info-950 text-info-700 dark:text-info-300' },
96
+ // ─── solid × color ─────────────────────────────────────────────
97
+ // Full bg + contrasting text. Solid neutral uses neutral-700/50
98
+ // (both on neutral palette → auto-invert together).
99
+ // `text-white` is deliberately NOT used: white does not auto-invert,
100
+ // which would flip the contrast in dark mode for the neutral row.
101
+ { variant: 'solid', color: 'neutral', class: 'bg-neutral-700 text-neutral-50' },
102
+ { variant: 'solid', color: 'primary', class: 'bg-primary-500 text-white' },
103
+ { variant: 'solid', color: 'secondary', class: 'bg-secondary-500 text-white' },
104
+ { variant: 'solid', color: 'success', class: 'bg-success-500 text-white' },
105
+ { variant: 'solid', color: 'warning', class: 'bg-warning-500 text-white' },
106
+ { variant: 'solid', color: 'danger', class: 'bg-danger-500 text-white' },
107
+ { variant: 'solid', color: 'info', class: 'bg-info-500 text-white' },
108
+ // ─── outline × color ───────────────────────────────────────────
109
+ // Border + colored text. Outline neutral: both auto-invert via
110
+ // CSS-var swap. Color rows: `dark:text-*-300` for legibility in
111
+ // dark mode on a transparent background.
112
+ { variant: 'outline', color: 'neutral', class: 'border border-neutral-300 text-neutral-700' },
113
+ { variant: 'outline', color: 'primary', class: 'border border-primary-500 text-primary-700 dark:text-primary-300' },
114
+ { variant: 'outline', color: 'secondary', class: 'border border-secondary-500 text-secondary-700 dark:text-secondary-300' },
115
+ { variant: 'outline', color: 'success', class: 'border border-success-500 text-success-700 dark:text-success-300' },
116
+ { variant: 'outline', color: 'warning', class: 'border border-warning-500 text-warning-700 dark:text-warning-300' },
117
+ { variant: 'outline', color: 'danger', class: 'border border-danger-500 text-danger-700 dark:text-danger-300' },
118
+ { variant: 'outline', color: 'info', class: 'border border-info-500 text-info-700 dark:text-info-300' },
119
+ // ─── clickable × color hover (subtle bg shift) ─────────────────
120
+ // Hover state on clickable chips. Each (variant, color) hover
121
+ // emits a one-tier deeper bg tint, working across both modes via
122
+ // the same auto-invert logic as the base compound.
123
+ { clickable: true, variant: 'soft', color: 'neutral', class: 'hover:bg-neutral-200' },
124
+ { clickable: true, variant: 'soft', color: 'primary', class: 'hover:bg-primary-200 dark:hover:bg-primary-900' },
125
+ { clickable: true, variant: 'soft', color: 'secondary', class: 'hover:bg-secondary-200 dark:hover:bg-secondary-900' },
126
+ { clickable: true, variant: 'soft', color: 'success', class: 'hover:bg-success-200 dark:hover:bg-success-900' },
127
+ { clickable: true, variant: 'soft', color: 'warning', class: 'hover:bg-warning-200 dark:hover:bg-warning-900' },
128
+ { clickable: true, variant: 'soft', color: 'danger', class: 'hover:bg-danger-200 dark:hover:bg-danger-900' },
129
+ { clickable: true, variant: 'soft', color: 'info', class: 'hover:bg-info-200 dark:hover:bg-info-900' },
130
+ // Solid hover → one tone darker
131
+ { clickable: true, variant: 'solid', color: 'neutral', class: 'hover:bg-neutral-800' },
132
+ { clickable: true, variant: 'solid', color: 'primary', class: 'hover:bg-primary-600' },
133
+ { clickable: true, variant: 'solid', color: 'secondary', class: 'hover:bg-secondary-600' },
134
+ { clickable: true, variant: 'solid', color: 'success', class: 'hover:bg-success-600' },
135
+ { clickable: true, variant: 'solid', color: 'warning', class: 'hover:bg-warning-600' },
136
+ { clickable: true, variant: 'solid', color: 'danger', class: 'hover:bg-danger-600' },
137
+ { clickable: true, variant: 'solid', color: 'info', class: 'hover:bg-info-600' },
138
+ // Outline hover → tinted bg appears (transparent → light tint)
139
+ { clickable: true, variant: 'outline', color: 'neutral', class: 'hover:bg-neutral-100' },
140
+ { clickable: true, variant: 'outline', color: 'primary', class: 'hover:bg-primary-50 dark:hover:bg-primary-950' },
141
+ { clickable: true, variant: 'outline', color: 'secondary', class: 'hover:bg-secondary-50 dark:hover:bg-secondary-950' },
142
+ { clickable: true, variant: 'outline', color: 'success', class: 'hover:bg-success-50 dark:hover:bg-success-950' },
143
+ { clickable: true, variant: 'outline', color: 'warning', class: 'hover:bg-warning-50 dark:hover:bg-warning-950' },
144
+ { clickable: true, variant: 'outline', color: 'danger', class: 'hover:bg-danger-50 dark:hover:bg-danger-950' },
145
+ { clickable: true, variant: 'outline', color: 'info', class: 'hover:bg-info-50 dark:hover:bg-info-950' },
146
+ // ─── selected × color (focus ring tone) ────────────────────────
147
+ // When selected, the ring color matches the chip's intent.
148
+ { selected: true, color: 'neutral', class: 'ring-neutral-400' },
149
+ { selected: true, color: 'primary', class: 'ring-primary-500' },
150
+ { selected: true, color: 'secondary', class: 'ring-secondary-500' },
151
+ { selected: true, color: 'success', class: 'ring-success-500' },
152
+ { selected: true, color: 'warning', class: 'ring-warning-500' },
153
+ { selected: true, color: 'danger', class: 'ring-danger-500' },
154
+ { selected: true, color: 'info', class: 'ring-info-500' },
155
+ // ─── clickable × color (focus ring tone) ───────────────────────
156
+ // Tab-focused ring tone matches the chip color (same intent as
157
+ // selected but only when keyboard-focused, via focus-visible).
158
+ { clickable: true, color: 'neutral', class: 'focus-visible:ring-neutral-400' },
159
+ { clickable: true, color: 'primary', class: 'focus-visible:ring-primary-500' },
160
+ { clickable: true, color: 'secondary', class: 'focus-visible:ring-secondary-500' },
161
+ { clickable: true, color: 'success', class: 'focus-visible:ring-success-500' },
162
+ { clickable: true, color: 'warning', class: 'focus-visible:ring-warning-500' },
163
+ { clickable: true, color: 'danger', class: 'focus-visible:ring-danger-500' },
164
+ { clickable: true, color: 'info', class: 'focus-visible:ring-info-500' },
165
+ ],
166
+ defaultVariants: {
167
+ color: 'neutral',
168
+ variant: 'soft',
169
+ size: 'sm',
170
+ },
171
+ });
172
+
173
+ export type ChipVariants = VariantProps<typeof chipVariants>;
@@ -120,7 +120,7 @@ export function ColumnVisibilityTrigger<T extends object>(
120
120
  {labels.columnsTitle}
121
121
  </span>
122
122
  </div>
123
- <ul className="flex flex-col gap-0.5 max-h-72 overflow-auto">
123
+ <ul className="flex flex-col gap-0.5 max-h-72 overflow-auto list-none pl-0 m-0">
124
124
  {hideableCols.map((col) => {
125
125
  const field = col.field as string;
126
126
  const hidden = hiddenColumns.includes(field);
@@ -0,0 +1,367 @@
1
+ // @vitest-environment jsdom
2
+ import * as React from 'react';
3
+ import { describe, it, expect, vi, afterEach } from 'vitest';
4
+ import { render, screen, fireEvent, cleanup } from '@testing-library/react';
5
+ import { RbacProvider } from '@dashforge/rbac';
6
+ import type { RbacPolicy, Subject } from '@dashforge/rbac';
7
+ import { IconButton } from './IconButton.js';
8
+
9
+ void React;
10
+ afterEach(() => cleanup());
11
+
12
+ /**
13
+ * `<IconButton>` unit tests. Covers:
14
+ * - icon rendering, required aria-label, base layout primitives
15
+ * - variant × color × size matrix (5 variants × 5 colors × 3 sizes)
16
+ * — sampled, not exhaustive (the full matrix is covered by
17
+ * `<Button>`'s tests since IconButton reuses `buttonVariants`)
18
+ * - square geometry via SIZE_OVERRIDES + aspect-square
19
+ * - asChild polymorphism via Radix Slot
20
+ * - loading state (spinner + aria-busy + disabled)
21
+ * - disabled state (explicit + access.disabled + access.readonly)
22
+ * - access RBAC: hide / disable
23
+ * - click handler firing semantics
24
+ */
25
+
26
+ const TestIcon = () => (
27
+ <svg data-testid="test-icon" width={20} height={20} viewBox="0 0 20 20">
28
+ <circle cx="10" cy="10" r="8" />
29
+ </svg>
30
+ );
31
+
32
+ const FULL_ACCESS_POLICY: RbacPolicy = {
33
+ roles: [
34
+ {
35
+ name: 'admin',
36
+ permissions: [{ resource: '*', action: '*', effect: 'allow' }],
37
+ },
38
+ ],
39
+ };
40
+ const NO_ACCESS_POLICY: RbacPolicy = {
41
+ roles: [
42
+ { name: 'guest', permissions: [] },
43
+ ],
44
+ };
45
+ const adminSubject: Subject = { id: 'a', roles: ['admin'] };
46
+ const guestSubject: Subject = { id: 'g', roles: ['guest'] };
47
+
48
+ describe('<IconButton>', () => {
49
+ describe('rendering', () => {
50
+ it('renders the icon child', () => {
51
+ render(
52
+ <IconButton aria-label="x">
53
+ <TestIcon />
54
+ </IconButton>
55
+ );
56
+ expect(screen.getByTestId('test-icon')).toBeTruthy();
57
+ });
58
+
59
+ it('applies the aria-label to the button element', () => {
60
+ render(
61
+ <IconButton aria-label="Open settings">
62
+ <TestIcon />
63
+ </IconButton>
64
+ );
65
+ expect(screen.getByRole('button', { name: /open settings/i })).toBeTruthy();
66
+ });
67
+
68
+ it('renders as type="button" by default', () => {
69
+ render(
70
+ <IconButton aria-label="x">
71
+ <TestIcon />
72
+ </IconButton>
73
+ );
74
+ const btn = screen.getByRole('button') as HTMLButtonElement;
75
+ expect(btn.type).toBe('button');
76
+ });
77
+
78
+ it('respects an explicit type prop', () => {
79
+ render(
80
+ <IconButton aria-label="x" type="submit">
81
+ <TestIcon />
82
+ </IconButton>
83
+ );
84
+ const btn = screen.getByRole('button') as HTMLButtonElement;
85
+ expect(btn.type).toBe('submit');
86
+ });
87
+ });
88
+
89
+ describe('layout primitives — square geometry', () => {
90
+ it('always applies aspect-square + inline-flex (layout base)', () => {
91
+ const { container } = render(
92
+ <IconButton aria-label="x">
93
+ <TestIcon />
94
+ </IconButton>
95
+ );
96
+ const btn = container.querySelector('button')!;
97
+ expect(btn.className).toContain('aspect-square');
98
+ expect(btn.className).toContain('inline-flex');
99
+ expect(btn.className).toContain('items-center');
100
+ expect(btn.className).toContain('justify-center');
101
+ });
102
+
103
+ it('applies SIZE_OVERRIDES (w-N + px-0) for sm', () => {
104
+ const { container } = render(
105
+ <IconButton aria-label="x" size="sm">
106
+ <TestIcon />
107
+ </IconButton>
108
+ );
109
+ const btn = container.querySelector('button')!;
110
+ expect(btn.className).toContain('w-8');
111
+ expect(btn.className).toContain('px-0');
112
+ });
113
+
114
+ it('applies SIZE_OVERRIDES for md (default)', () => {
115
+ const { container } = render(
116
+ <IconButton aria-label="x">
117
+ <TestIcon />
118
+ </IconButton>
119
+ );
120
+ const btn = container.querySelector('button')!;
121
+ expect(btn.className).toContain('w-10');
122
+ });
123
+
124
+ it('applies SIZE_OVERRIDES for lg', () => {
125
+ const { container } = render(
126
+ <IconButton aria-label="x" size="lg">
127
+ <TestIcon />
128
+ </IconButton>
129
+ );
130
+ const btn = container.querySelector('button')!;
131
+ expect(btn.className).toContain('w-12');
132
+ });
133
+ });
134
+
135
+ describe('variant × color (inherits buttonVariants)', () => {
136
+ it('renders solid + primary (token-driven, no hardcoded hex)', () => {
137
+ const { container } = render(
138
+ <IconButton aria-label="x" variant="solid" color="primary">
139
+ <TestIcon />
140
+ </IconButton>
141
+ );
142
+ const btn = container.querySelector('button')!;
143
+ expect(btn.className).toContain('bg-primary-500');
144
+ expect(btn.className).not.toMatch(/#[0-9a-fA-F]{3,8}/);
145
+ expect(btn.className).not.toMatch(/\bdark:/);
146
+ });
147
+
148
+ it('renders outline + danger (border color comes through)', () => {
149
+ const { container } = render(
150
+ <IconButton aria-label="x" variant="outline" color="danger">
151
+ <TestIcon />
152
+ </IconButton>
153
+ );
154
+ const btn = container.querySelector('button')!;
155
+ expect(btn.className).toContain('border');
156
+ expect(btn.className).toContain('danger');
157
+ });
158
+
159
+ it('ghost variant uses bg-transparent', () => {
160
+ const { container } = render(
161
+ <IconButton aria-label="x" variant="ghost">
162
+ <TestIcon />
163
+ </IconButton>
164
+ );
165
+ const btn = container.querySelector('button')!;
166
+ expect(btn.className).toContain('bg-transparent');
167
+ });
168
+ });
169
+
170
+ describe('asChild polymorphism', () => {
171
+ it('renders the child via Radix Slot when asChild=true', () => {
172
+ const { container } = render(
173
+ <IconButton asChild aria-label="Open">
174
+ <a href="/open" data-testid="anchor-child">
175
+ <TestIcon />
176
+ </a>
177
+ </IconButton>
178
+ );
179
+ // Should be an <a>, not a <button>
180
+ const anchor = container.querySelector('a[data-testid="anchor-child"]');
181
+ expect(anchor).toBeTruthy();
182
+ expect(container.querySelector('button')).toBeNull();
183
+ // Anchor carries the IconButton className
184
+ expect(anchor!.className).toContain('aspect-square');
185
+ });
186
+ });
187
+
188
+ describe('loading state', () => {
189
+ it('swaps the icon with a spinner', () => {
190
+ const { container } = render(
191
+ <IconButton aria-label="x" loading>
192
+ <TestIcon />
193
+ </IconButton>
194
+ );
195
+ // Icon child gone, replaced by Spinner (animate-spin is on the
196
+ // Spinner's outer <span> wrapper now, since Sprint 4.4 refactor
197
+ // delegated to the public <Spinner> component).
198
+ expect(screen.queryByTestId('test-icon')).toBeNull();
199
+ const spinner = container.querySelector('[class*="animate-spin"]');
200
+ expect(spinner).toBeTruthy();
201
+ });
202
+
203
+ it('sets aria-busy=true while loading', () => {
204
+ render(
205
+ <IconButton aria-label="x" loading>
206
+ <TestIcon />
207
+ </IconButton>
208
+ );
209
+ const btn = screen.getByRole('button');
210
+ expect(btn.getAttribute('aria-busy')).toBe('true');
211
+ });
212
+
213
+ it('is disabled while loading', () => {
214
+ render(
215
+ <IconButton aria-label="x" loading>
216
+ <TestIcon />
217
+ </IconButton>
218
+ );
219
+ const btn = screen.getByRole('button') as HTMLButtonElement;
220
+ expect(btn.disabled).toBe(true);
221
+ });
222
+ });
223
+
224
+ describe('disabled state', () => {
225
+ it('respects the explicit disabled prop', () => {
226
+ render(
227
+ <IconButton aria-label="x" disabled>
228
+ <TestIcon />
229
+ </IconButton>
230
+ );
231
+ const btn = screen.getByRole('button') as HTMLButtonElement;
232
+ expect(btn.disabled).toBe(true);
233
+ });
234
+
235
+ it('does not fire onClick when disabled', () => {
236
+ const onClick = vi.fn();
237
+ render(
238
+ <IconButton aria-label="x" disabled onClick={onClick}>
239
+ <TestIcon />
240
+ </IconButton>
241
+ );
242
+ fireEvent.click(screen.getByRole('button'));
243
+ expect(onClick).not.toHaveBeenCalled();
244
+ });
245
+ });
246
+
247
+ describe('access RBAC integration', () => {
248
+ it('hides the button when access.onUnauthorized=hide and subject lacks permission', () => {
249
+ const { container } = render(
250
+ <RbacProvider policy={NO_ACCESS_POLICY} subject={guestSubject}>
251
+ <IconButton
252
+ aria-label="x"
253
+ access={{
254
+ resource: 'article',
255
+ action: 'publish',
256
+ onUnauthorized: 'hide',
257
+ }}
258
+ >
259
+ <TestIcon />
260
+ </IconButton>
261
+ </RbacProvider>
262
+ );
263
+ expect(container.querySelector('button')).toBeNull();
264
+ });
265
+
266
+ it('disables the button when access.onUnauthorized=disable and subject lacks permission', () => {
267
+ render(
268
+ <RbacProvider policy={NO_ACCESS_POLICY} subject={guestSubject}>
269
+ <IconButton
270
+ aria-label="x"
271
+ access={{
272
+ resource: 'article',
273
+ action: 'publish',
274
+ onUnauthorized: 'disable',
275
+ }}
276
+ >
277
+ <TestIcon />
278
+ </IconButton>
279
+ </RbacProvider>
280
+ );
281
+ const btn = screen.getByRole('button') as HTMLButtonElement;
282
+ expect(btn.disabled).toBe(true);
283
+ });
284
+
285
+ it('renders normally for an admin subject', () => {
286
+ render(
287
+ <RbacProvider policy={FULL_ACCESS_POLICY} subject={adminSubject}>
288
+ <IconButton
289
+ aria-label="x"
290
+ access={{
291
+ resource: 'article',
292
+ action: 'publish',
293
+ onUnauthorized: 'hide',
294
+ }}
295
+ >
296
+ <TestIcon />
297
+ </IconButton>
298
+ </RbacProvider>
299
+ );
300
+ expect(screen.getByRole('button')).toBeTruthy();
301
+ });
302
+ });
303
+
304
+ describe('click handler', () => {
305
+ it('fires onClick when clicked', () => {
306
+ const onClick = vi.fn();
307
+ render(
308
+ <IconButton aria-label="x" onClick={onClick}>
309
+ <TestIcon />
310
+ </IconButton>
311
+ );
312
+ fireEvent.click(screen.getByRole('button'));
313
+ expect(onClick).toHaveBeenCalledTimes(1);
314
+ });
315
+ });
316
+
317
+ describe('visibleWhen (engine-reactive, Sprint 4.4)', () => {
318
+ it('renders when visibleWhen returns true', () => {
319
+ const { container } = render(
320
+ <IconButton aria-label="x" visibleWhen={() => true}>
321
+ <TestIcon />
322
+ </IconButton>
323
+ );
324
+ expect(container.firstChild).toBeTruthy();
325
+ });
326
+
327
+ it('returns null when visibleWhen returns false', () => {
328
+ const { container } = render(
329
+ <IconButton aria-label="x" visibleWhen={() => false}>
330
+ <TestIcon />
331
+ </IconButton>
332
+ );
333
+ expect(container.firstChild).toBeNull();
334
+ });
335
+
336
+ it('renders normally when visibleWhen is omitted', () => {
337
+ const { container } = render(
338
+ <IconButton aria-label="x">
339
+ <TestIcon />
340
+ </IconButton>
341
+ );
342
+ expect(container.firstChild).toBeTruthy();
343
+ });
344
+ });
345
+
346
+ describe('overrides — sx + className', () => {
347
+ it('appends sx to the root className', () => {
348
+ const { container } = render(
349
+ <IconButton aria-label="x" sx="ring-2 ring-purple-500">
350
+ <TestIcon />
351
+ </IconButton>
352
+ );
353
+ const btn = container.querySelector('button')!;
354
+ expect(btn.className).toContain('ring-purple-500');
355
+ });
356
+
357
+ it('appends className to the root', () => {
358
+ const { container } = render(
359
+ <IconButton aria-label="x" className="my-custom-icon-btn">
360
+ <TestIcon />
361
+ </IconButton>
362
+ );
363
+ const btn = container.querySelector('button')!;
364
+ expect(btn.className).toContain('my-custom-icon-btn');
365
+ });
366
+ });
367
+ });