tembro 2.0.6 → 2.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 (341) hide show
  1. package/dist/components/calendar/calendar.cjs +1 -1
  2. package/dist/components/calendar/calendar.d.ts +2 -1
  3. package/dist/components/calendar/calendar.js +126 -122
  4. package/dist/components/calendar/date-range-picker.cjs +1 -1
  5. package/dist/components/calendar/date-range-picker.d.ts +2 -1
  6. package/dist/components/calendar/date-range-picker.js +39 -39
  7. package/dist/components/charts/charts.cjs +1 -1
  8. package/dist/components/charts/charts.d.ts +13 -4
  9. package/dist/components/charts/charts.js +76 -46
  10. package/dist/components/charts/progress-ring.cjs +1 -1
  11. package/dist/components/charts/progress-ring.d.ts +3 -1
  12. package/dist/components/charts/progress-ring.js +11 -10
  13. package/dist/components/data-table/data-table-column-visibility-menu.cjs +1 -1
  14. package/dist/components/data-table/data-table-column-visibility-menu.d.ts +4 -1
  15. package/dist/components/data-table/data-table-column-visibility-menu.js +36 -8
  16. package/dist/components/data-table/data-table-toolbar.cjs +1 -1
  17. package/dist/components/data-table/data-table-toolbar.js +12 -13
  18. package/dist/components/display/carousel.cjs +1 -1
  19. package/dist/components/display/carousel.d.ts +9 -1
  20. package/dist/components/display/carousel.js +123 -81
  21. package/dist/components/display/code-block.cjs +2 -2
  22. package/dist/components/display/code-block.d.ts +2 -1
  23. package/dist/components/display/code-block.js +17 -12
  24. package/dist/components/display/delta-badge.cjs +1 -1
  25. package/dist/components/display/delta-badge.d.ts +2 -1
  26. package/dist/components/display/delta-badge.js +11 -7
  27. package/dist/components/display/kanban.cjs +1 -1
  28. package/dist/components/display/kanban.d.ts +4 -1
  29. package/dist/components/display/kanban.js +60 -33
  30. package/dist/components/display/metric-grid.cjs +1 -1
  31. package/dist/components/display/metric-grid.d.ts +1 -0
  32. package/dist/components/display/metric-grid.js +1 -1
  33. package/dist/components/display/qr-code.cjs +1 -1
  34. package/dist/components/display/qr-code.d.ts +2 -1
  35. package/dist/components/display/qr-code.js +19 -16
  36. package/dist/components/display/tag.cjs +1 -1
  37. package/dist/components/display/tag.d.ts +2 -1
  38. package/dist/components/display/tag.js +28 -22
  39. package/dist/components/display/tree-view.cjs +1 -1
  40. package/dist/components/display/tree-view.d.ts +9 -1
  41. package/dist/components/display/tree-view.js +104 -40
  42. package/dist/components/display/trend-card.cjs +1 -1
  43. package/dist/components/display/trend-card.js +27 -41
  44. package/dist/components/feedback/alert.cjs +1 -1
  45. package/dist/components/feedback/alert.d.ts +2 -1
  46. package/dist/components/feedback/alert.js +6 -6
  47. package/dist/components/feedback/loading-state.cjs +1 -1
  48. package/dist/components/feedback/loading-state.d.ts +3 -1
  49. package/dist/components/feedback/loading-state.js +23 -10
  50. package/dist/components/feedback/page-state.cjs +1 -1
  51. package/dist/components/feedback/page-state.d.ts +2 -1
  52. package/dist/components/feedback/page-state.js +7 -4
  53. package/dist/components/form/form-field-shell.cjs +1 -1
  54. package/dist/components/form/form-field-shell.d.ts +4 -2
  55. package/dist/components/form/form-field-shell.js +57 -41
  56. package/dist/components/form/form-input.cjs +1 -1
  57. package/dist/components/form/form-input.js +2 -0
  58. package/dist/components/form/form-select.cjs +1 -1
  59. package/dist/components/form/form-select.js +2 -0
  60. package/dist/components/form/form-switch.cjs +1 -1
  61. package/dist/components/form/form-switch.d.ts +1 -1
  62. package/dist/components/form/form-switch.js +58 -54
  63. package/dist/components/form/form-textarea.cjs +1 -1
  64. package/dist/components/form/form-textarea.d.ts +1 -1
  65. package/dist/components/form/form-textarea.js +29 -27
  66. package/dist/components/layout/app-sidebar.cjs +1 -1
  67. package/dist/components/layout/app-sidebar.d.ts +1 -0
  68. package/dist/components/layout/app-sidebar.js +36 -36
  69. package/dist/components/layout/breadcrumbs.cjs +1 -1
  70. package/dist/components/layout/breadcrumbs.d.ts +2 -1
  71. package/dist/components/layout/breadcrumbs.js +7 -7
  72. package/dist/components/modern/calendar-scheduler.cjs +1 -1
  73. package/dist/components/modern/calendar-scheduler.d.ts +5 -1
  74. package/dist/components/modern/calendar-scheduler.js +47 -28
  75. package/dist/components/modern/dual-list-picker.cjs +1 -1
  76. package/dist/components/modern/dual-list-picker.d.ts +5 -1
  77. package/dist/components/modern/dual-list-picker.js +81 -23
  78. package/dist/components/modern/rich-text-editor.cjs +1 -1
  79. package/dist/components/modern/rich-text-editor.d.ts +3 -1
  80. package/dist/components/modern/rich-text-editor.js +12 -9
  81. package/dist/components/modern/tour.cjs +1 -1
  82. package/dist/components/modern/tour.d.ts +5 -1
  83. package/dist/components/modern/tour.js +57 -35
  84. package/dist/components/navigation/command-bar.cjs +1 -1
  85. package/dist/components/navigation/command-bar.d.ts +3 -1
  86. package/dist/components/navigation/command-bar.js +10 -7
  87. package/dist/components/navigation/demo.cjs +1 -1
  88. package/dist/components/navigation/demo.js +0 -1
  89. package/dist/components/navigation/nav-tabs.cjs +1 -1
  90. package/dist/components/navigation/nav-tabs.js +39 -27
  91. package/dist/components/navigation/page-tabs.cjs +1 -1
  92. package/dist/components/navigation/page-tabs.js +41 -30
  93. package/dist/components/navigation/pagination.cjs +1 -1
  94. package/dist/components/navigation/pagination.d.ts +7 -1
  95. package/dist/components/navigation/pagination.js +48 -25
  96. package/dist/components/notifications/notification-center.cjs +1 -1
  97. package/dist/components/notifications/notification-center.d.ts +3 -1
  98. package/dist/components/notifications/notification-center.js +56 -38
  99. package/dist/components/notifications/toast.cjs +1 -1
  100. package/dist/components/notifications/toast.d.ts +1 -0
  101. package/dist/components/notifications/toast.js +4 -0
  102. package/dist/components/overlay/alert-dialog.cjs +1 -1
  103. package/dist/components/overlay/alert-dialog.js +1 -1
  104. package/dist/components/overlay/confirm-dialog.cjs +1 -1
  105. package/dist/components/overlay/confirm-dialog.d.ts +4 -2
  106. package/dist/components/overlay/confirm-dialog.js +31 -22
  107. package/dist/components/overlay/drawer.cjs +1 -1
  108. package/dist/components/overlay/drawer.d.ts +3 -1
  109. package/dist/components/overlay/drawer.js +24 -16
  110. package/dist/components/ui/accordion/index.d.ts +4 -0
  111. package/dist/components/ui/badge/index.cjs +1 -1
  112. package/dist/components/ui/badge/index.d.ts +1 -1
  113. package/dist/components/ui/badge/index.js +2 -1
  114. package/dist/components/ui/button/index.cjs +1 -1
  115. package/dist/components/ui/button/index.d.ts +2 -1
  116. package/dist/components/ui/button/index.js +13 -10
  117. package/dist/components/ui/dialog/index.cjs +1 -1
  118. package/dist/components/ui/dialog/index.js +2 -1
  119. package/dist/components/ui/hover-card.cjs +1 -1
  120. package/dist/components/ui/hover-card.d.ts +11 -3
  121. package/dist/components/ui/hover-card.js +29 -24
  122. package/dist/components/ui/input/index.d.ts +1 -1
  123. package/dist/components/ui/popover/index.cjs +1 -1
  124. package/dist/components/ui/popover/index.d.ts +2 -2
  125. package/dist/components/ui/popover/index.js +6 -5
  126. package/dist/components/ui/radio-group/index.cjs +1 -1
  127. package/dist/components/ui/radio-group/index.d.ts +5 -1
  128. package/dist/components/ui/radio-group/index.js +50 -16
  129. package/dist/components/ui/right-click-menu/index.cjs +1 -1
  130. package/dist/components/ui/right-click-menu/index.d.ts +5 -1
  131. package/dist/components/ui/right-click-menu/index.js +77 -23
  132. package/dist/components/ui/segmented-control/index.cjs +1 -1
  133. package/dist/components/ui/segmented-control/index.d.ts +2 -1
  134. package/dist/components/ui/segmented-control/index.js +23 -11
  135. package/dist/components/ui/select/index.cjs +1 -1
  136. package/dist/components/ui/select/index.d.ts +8 -1
  137. package/dist/components/ui/select/index.js +40 -35
  138. package/dist/components/ui/switch/index.cjs +1 -1
  139. package/dist/components/ui/switch/index.d.ts +18 -0
  140. package/dist/components/ui/switch/index.js +47 -17
  141. package/dist/components/ui/tabs/index.cjs +1 -1
  142. package/dist/components/ui/tabs/index.d.ts +14 -4
  143. package/dist/components/ui/tabs/index.js +11 -8
  144. package/dist/components/ui/textarea/index.cjs +1 -1
  145. package/dist/components/ui/textarea/index.d.ts +10 -2
  146. package/dist/components/ui/textarea/index.js +37 -8
  147. package/dist/components/ui/textarea.cjs +1 -0
  148. package/dist/components/ui/textarea.d.ts +1 -0
  149. package/dist/components/ui/textarea.js +2 -0
  150. package/dist/components/ui/tooltip/index.cjs +1 -1
  151. package/dist/components/ui/tooltip/index.d.ts +11 -3
  152. package/dist/components/ui/tooltip/index.js +41 -20
  153. package/dist/components/upload/file-upload.cjs +1 -1
  154. package/dist/components/upload/file-upload.d.ts +8 -1
  155. package/dist/components/upload/file-upload.js +132 -100
  156. package/dist/components/upload/image-upload.cjs +1 -1
  157. package/dist/components/upload/image-upload.d.ts +5 -1
  158. package/dist/components/upload/image-upload.js +34 -9
  159. package/dist/index.cjs +1 -1
  160. package/dist/index.js +31 -31
  161. package/dist/public-component-surface.cjs +1 -1
  162. package/dist/public-component-surface.js +15 -0
  163. package/dist/showcase/component-api-schema.cjs +1 -1
  164. package/dist/showcase/component-api-schema.js +187 -10
  165. package/dist/showcase/fallback.cjs +3 -3
  166. package/dist/showcase/fallback.js +221 -243
  167. package/dist/showcase/premium/alert/showcase.cjs +1 -1
  168. package/dist/showcase/premium/alert/showcase.js +1 -0
  169. package/dist/showcase/premium/app-sidebar/showcase.cjs +1 -1
  170. package/dist/showcase/premium/app-sidebar/showcase.js +1 -0
  171. package/dist/showcase/premium/badge/showcase.cjs +1 -1
  172. package/dist/showcase/premium/badge/showcase.js +7 -0
  173. package/dist/showcase/premium/badge/types.d.ts +1 -1
  174. package/dist/showcase/premium/breadcrumbs/showcase.cjs +1 -1
  175. package/dist/showcase/premium/breadcrumbs/showcase.js +12 -1
  176. package/dist/showcase/premium/button/mock.cjs +1 -4
  177. package/dist/showcase/premium/button/mock.js +1 -1
  178. package/dist/showcase/premium/button/showcase.cjs +1 -1
  179. package/dist/showcase/premium/button/showcase.js +2 -2
  180. package/dist/showcase/premium/card/showcase.cjs +1 -1
  181. package/dist/showcase/premium/card/showcase.js +96 -47
  182. package/dist/showcase/premium/carousel/showcase.cjs +1 -1
  183. package/dist/showcase/premium/carousel/showcase.js +76 -49
  184. package/dist/showcase/premium/command-bar/showcase.cjs +1 -1
  185. package/dist/showcase/premium/command-bar/showcase.js +2 -0
  186. package/dist/showcase/premium/data-table/mock.cjs +12 -11
  187. package/dist/showcase/premium/data-table/mock.js +1 -1
  188. package/dist/showcase/premium/file-upload/showcase.cjs +1 -1
  189. package/dist/showcase/premium/file-upload/showcase.js +25 -4
  190. package/dist/showcase/premium/image-upload/showcase.cjs +1 -1
  191. package/dist/showcase/premium/image-upload/showcase.js +4 -1
  192. package/dist/showcase/premium/index.cjs +1 -1
  193. package/dist/showcase/premium/index.js +396 -402
  194. package/dist/showcase/premium/loading-state/showcase.cjs +1 -1
  195. package/dist/showcase/premium/loading-state/showcase.js +3 -1
  196. package/dist/showcase/premium/metric-grid/showcase.cjs +1 -1
  197. package/dist/showcase/premium/metric-grid/showcase.js +96 -28
  198. package/dist/showcase/premium/notification-center/showcase.cjs +1 -1
  199. package/dist/showcase/premium/notification-center/showcase.js +7 -3
  200. package/dist/showcase/premium/page-state/showcase.cjs +1 -1
  201. package/dist/showcase/premium/page-state/showcase.js +5 -1
  202. package/dist/showcase/premium/pagination/showcase.cjs +1 -1
  203. package/dist/showcase/premium/pagination/showcase.js +15 -2
  204. package/dist/showcase/premium/popover/showcase.cjs +1 -1
  205. package/dist/showcase/premium/popover/showcase.js +85 -50
  206. package/dist/showcase/premium/radio-group/showcase.cjs +1 -1
  207. package/dist/showcase/premium/radio-group/showcase.js +27 -4
  208. package/dist/showcase/premium/right-click-menu/showcase.cjs +1 -1
  209. package/dist/showcase/premium/right-click-menu/showcase.js +56 -43
  210. package/dist/showcase/premium/segmented-control/showcase.cjs +1 -1
  211. package/dist/showcase/premium/segmented-control/showcase.js +1 -0
  212. package/dist/showcase/premium/select/data.cjs +1 -1
  213. package/dist/showcase/premium/select/data.js +69 -34
  214. package/dist/showcase/premium/select/mock.cjs +19 -6
  215. package/dist/showcase/premium/select/mock.js +3 -2
  216. package/dist/showcase/premium/select/showcase.cjs +1 -1
  217. package/dist/showcase/premium/select/showcase.js +43 -18
  218. package/dist/showcase/premium/select/types.d.ts +3 -0
  219. package/dist/showcase/premium/statistic/showcase.cjs +1 -1
  220. package/dist/showcase/premium/statistic/showcase.js +57 -25
  221. package/dist/showcase/premium/switch/showcase.cjs +1 -1
  222. package/dist/showcase/premium/switch/showcase.js +25 -14
  223. package/dist/showcase/premium/tabs/showcase.cjs +1 -1
  224. package/dist/showcase/premium/tabs/showcase.js +171 -48
  225. package/dist/showcase/premium/textarea/mock.cjs +12 -4
  226. package/dist/showcase/premium/textarea/mock.js +1 -1
  227. package/dist/showcase/premium/textarea/showcase.cjs +1 -1
  228. package/dist/showcase/premium/textarea/showcase.js +8 -3
  229. package/dist/showcase/premium/toast/showcase.cjs +1 -1
  230. package/dist/showcase/premium/toast/showcase.js +32 -6
  231. package/dist/showcase/premium/types.d.ts +1 -1
  232. package/dist/showcase/registry-quality.cjs +1 -1
  233. package/dist/showcase/registry-quality.js +1 -0
  234. package/dist/showcase/render-registry-preview.cjs +1 -1
  235. package/dist/showcase/render-registry-preview.js +57 -79
  236. package/dist/showcase/site-data.cjs +1 -1
  237. package/dist/showcase/site-data.js +60 -21
  238. package/dist/showcase/tembro-registry.json.cjs +1 -1
  239. package/dist/showcase/tembro-registry.json.js +34 -20
  240. package/dist/showcase/types.d.ts +1 -1
  241. package/package.json +1 -1
  242. package/packages/cli/dist/index.cjs +31 -31
  243. package/packages/cli/vendor/src/components/calendar/calendar.tsx +59 -50
  244. package/packages/cli/vendor/src/components/calendar/date-range-picker.tsx +7 -4
  245. package/packages/cli/vendor/src/components/charts/charts.tsx +109 -66
  246. package/packages/cli/vendor/src/components/charts/progress-ring.tsx +37 -26
  247. package/packages/cli/vendor/src/components/data-table/data-table-column-visibility-menu.tsx +41 -22
  248. package/packages/cli/vendor/src/components/data-table/data-table-toolbar.tsx +8 -6
  249. package/packages/cli/vendor/src/components/display/carousel.tsx +84 -3
  250. package/packages/cli/vendor/src/components/display/code-block.tsx +22 -2
  251. package/packages/cli/vendor/src/components/display/delta-badge.tsx +11 -11
  252. package/packages/cli/vendor/src/components/display/kanban.tsx +103 -57
  253. package/packages/cli/vendor/src/components/display/metric-grid.tsx +16 -13
  254. package/packages/cli/vendor/src/components/display/qr-code.tsx +17 -15
  255. package/packages/cli/vendor/src/components/display/tag.tsx +39 -21
  256. package/packages/cli/vendor/src/components/display/tree-view.tsx +221 -84
  257. package/packages/cli/vendor/src/components/display/trend-card.tsx +6 -40
  258. package/packages/cli/vendor/src/components/feedback/alert.tsx +3 -1
  259. package/packages/cli/vendor/src/components/feedback/loading-state.tsx +33 -17
  260. package/packages/cli/vendor/src/components/feedback/page-state.tsx +8 -7
  261. package/packages/cli/vendor/src/components/form/form-field-shell.tsx +37 -8
  262. package/packages/cli/vendor/src/components/form/form-input.tsx +2 -0
  263. package/packages/cli/vendor/src/components/form/form-select.tsx +2 -0
  264. package/packages/cli/vendor/src/components/form/form-switch.tsx +9 -3
  265. package/packages/cli/vendor/src/components/form/form-textarea.tsx +6 -2
  266. package/packages/cli/vendor/src/components/layout/app-sidebar.tsx +3 -1
  267. package/packages/cli/vendor/src/components/layout/breadcrumbs.tsx +3 -1
  268. package/packages/cli/vendor/src/components/modern/calendar-scheduler.tsx +28 -13
  269. package/packages/cli/vendor/src/components/modern/dual-list-picker.tsx +103 -35
  270. package/packages/cli/vendor/src/components/modern/rich-text-editor.tsx +25 -22
  271. package/packages/cli/vendor/src/components/modern/tour.tsx +47 -29
  272. package/packages/cli/vendor/src/components/navigation/command-bar.tsx +6 -0
  273. package/packages/cli/vendor/src/components/navigation/demo.tsx +0 -1
  274. package/packages/cli/vendor/src/components/navigation/nav-tabs.tsx +38 -29
  275. package/packages/cli/vendor/src/components/navigation/page-tabs.tsx +35 -23
  276. package/packages/cli/vendor/src/components/navigation/pagination.tsx +65 -31
  277. package/packages/cli/vendor/src/components/notifications/notification-center.tsx +64 -39
  278. package/packages/cli/vendor/src/components/notifications/toast.tsx +23 -21
  279. package/packages/cli/vendor/src/components/overlay/alert-dialog.tsx +1 -1
  280. package/packages/cli/vendor/src/components/overlay/confirm-dialog.tsx +45 -22
  281. package/packages/cli/vendor/src/components/overlay/drawer.tsx +18 -5
  282. package/packages/cli/vendor/src/components/ui/accordion/index.tsx +4 -0
  283. package/packages/cli/vendor/src/components/ui/badge/index.tsx +2 -1
  284. package/packages/cli/vendor/src/components/ui/button/index.tsx +11 -5
  285. package/packages/cli/vendor/src/components/ui/dialog/index.tsx +2 -1
  286. package/packages/cli/vendor/src/components/ui/hover-card.tsx +54 -28
  287. package/packages/cli/vendor/src/components/ui/popover/index.tsx +10 -8
  288. package/packages/cli/vendor/src/components/ui/radio-group/index.tsx +55 -6
  289. package/packages/cli/vendor/src/components/ui/right-click-menu/index.tsx +120 -9
  290. package/packages/cli/vendor/src/components/ui/segmented-control/index.tsx +29 -3
  291. package/packages/cli/vendor/src/components/ui/select/index.tsx +64 -31
  292. package/packages/cli/vendor/src/components/ui/switch/index.tsx +71 -6
  293. package/packages/cli/vendor/src/components/ui/tabs/index.tsx +22 -6
  294. package/packages/cli/vendor/src/components/ui/textarea/index.tsx +105 -15
  295. package/packages/cli/vendor/src/components/ui/textarea.tsx +2 -0
  296. package/packages/cli/vendor/src/components/ui/tooltip/index.tsx +67 -22
  297. package/packages/cli/vendor/src/components/upload/file-upload.tsx +120 -57
  298. package/packages/cli/vendor/src/components/upload/image-upload.tsx +71 -24
  299. package/packages/cli/vendor/src/public-component-surface.ts +3 -0
  300. package/packages/cli/vendor/src/showcase/component-api-schema.ts +79 -41
  301. package/packages/cli/vendor/src/showcase/fallback.tsx +4 -19
  302. package/packages/cli/vendor/src/showcase/premium/alert/showcase.tsx +1 -0
  303. package/packages/cli/vendor/src/showcase/premium/app-sidebar/showcase.tsx +1 -0
  304. package/packages/cli/vendor/src/showcase/premium/badge/showcase.tsx +4 -2
  305. package/packages/cli/vendor/src/showcase/premium/badge/types.ts +1 -1
  306. package/packages/cli/vendor/src/showcase/premium/breadcrumbs/showcase.tsx +3 -1
  307. package/packages/cli/vendor/src/showcase/premium/button/mock.ts +2 -5
  308. package/packages/cli/vendor/src/showcase/premium/button/showcase.tsx +2 -2
  309. package/packages/cli/vendor/src/showcase/premium/card/showcase.tsx +26 -1
  310. package/packages/cli/vendor/src/showcase/premium/carousel/showcase.tsx +19 -3
  311. package/packages/cli/vendor/src/showcase/premium/command-bar/showcase.tsx +1 -1
  312. package/packages/cli/vendor/src/showcase/premium/data-table/mock.ts +26 -25
  313. package/packages/cli/vendor/src/showcase/premium/file-upload/showcase.tsx +21 -1
  314. package/packages/cli/vendor/src/showcase/premium/image-upload/showcase.tsx +4 -1
  315. package/packages/cli/vendor/src/showcase/premium/index.ts +0 -2
  316. package/packages/cli/vendor/src/showcase/premium/loading-state/showcase.tsx +1 -1
  317. package/packages/cli/vendor/src/showcase/premium/metric-grid/showcase.tsx +36 -4
  318. package/packages/cli/vendor/src/showcase/premium/notification-center/showcase.tsx +4 -3
  319. package/packages/cli/vendor/src/showcase/premium/page-state/showcase.tsx +1 -0
  320. package/packages/cli/vendor/src/showcase/premium/pagination/showcase.tsx +13 -1
  321. package/packages/cli/vendor/src/showcase/premium/popover/showcase.tsx +27 -11
  322. package/packages/cli/vendor/src/showcase/premium/radio-group/showcase.tsx +13 -1
  323. package/packages/cli/vendor/src/showcase/premium/right-click-menu/showcase.tsx +8 -5
  324. package/packages/cli/vendor/src/showcase/premium/segmented-control/showcase.tsx +1 -0
  325. package/packages/cli/vendor/src/showcase/premium/select/data.ts +12 -3
  326. package/packages/cli/vendor/src/showcase/premium/select/mock.ts +4 -4
  327. package/packages/cli/vendor/src/showcase/premium/select/showcase.tsx +22 -1
  328. package/packages/cli/vendor/src/showcase/premium/select/types.ts +3 -0
  329. package/packages/cli/vendor/src/showcase/premium/statistic/showcase.tsx +10 -1
  330. package/packages/cli/vendor/src/showcase/premium/switch/showcase.tsx +15 -6
  331. package/packages/cli/vendor/src/showcase/premium/tabs/showcase.tsx +48 -1
  332. package/packages/cli/vendor/src/showcase/premium/textarea/mock.ts +12 -4
  333. package/packages/cli/vendor/src/showcase/premium/textarea/showcase.tsx +5 -0
  334. package/packages/cli/vendor/src/showcase/premium/toast/showcase.tsx +17 -1
  335. package/packages/cli/vendor/src/showcase/premium/types.ts +1 -1
  336. package/packages/cli/vendor/src/showcase/registry-quality.ts +3 -2
  337. package/packages/cli/vendor/src/showcase/render-registry-preview.tsx +0 -15
  338. package/packages/cli/vendor/src/showcase/site-data.tsx +21 -15
  339. package/packages/cli/vendor/src/showcase/tembro-registry.json +42 -20
  340. package/packages/cli/vendor/src/showcase/types.ts +1 -1
  341. package/registry.json +18 -6
@@ -11,25 +11,32 @@ type ConfirmDialogProps = Omit<ModalShellProps, "footer"> & {
11
11
  confirmVariant?: ConfirmVariant
12
12
  confirmDisabled?: boolean
13
13
  cancelDisabled?: boolean
14
- isLoading?: boolean
15
- onCancel?: () => void
16
- onConfirm?: () => void
17
- }
14
+ isLoading?: boolean
15
+ closeOnConfirm?: boolean
16
+ onConfirmError?: (error: unknown) => void
17
+ onCancel?: () => void
18
+ onConfirm?: () => void | Promise<void>
19
+ }
18
20
 
19
21
  function ConfirmDialog({
20
22
  cancelText = "Cancel",
21
23
  confirmText = "Confirm",
22
24
  confirmVariant = "default",
23
25
  confirmDisabled = false,
24
- cancelDisabled = false,
25
- isLoading = false,
26
- onCancel,
27
- onConfirm,
28
- onOpenChange,
29
- ...props
26
+ cancelDisabled = false,
27
+ isLoading = false,
28
+ closeOnConfirm = true,
29
+ onConfirmError,
30
+ onCancel,
31
+ onConfirm,
32
+ onOpenChange,
33
+ ...props
30
34
  }: ConfirmDialogProps) {
35
+ const [pending, setPending] = React.useState(false)
36
+ const resolvedLoading = isLoading || pending
37
+
31
38
  const handleOpenChange = (open: boolean) => {
32
- if (isLoading && open === false) {
39
+ if (resolvedLoading && open === false) {
33
40
  return
34
41
  }
35
42
 
@@ -38,31 +45,47 @@ function ConfirmDialog({
38
45
 
39
46
  const handleCancel = () => {
40
47
  onCancel?.()
41
- if (!isLoading) {
48
+ if (!resolvedLoading) {
42
49
  onOpenChange?.(false)
43
50
  }
44
51
  }
45
52
 
53
+ const handleConfirm = async () => {
54
+ if (confirmDisabled || resolvedLoading) return
55
+
56
+ try {
57
+ setPending(true)
58
+ await onConfirm?.()
59
+ if (closeOnConfirm) {
60
+ onOpenChange?.(false)
61
+ }
62
+ } catch (error) {
63
+ onConfirmError?.(error)
64
+ } finally {
65
+ setPending(false)
66
+ }
67
+ }
68
+
46
69
  return (
47
70
  <ModalShell
48
- showCloseButton={!isLoading}
71
+ showCloseButton={!resolvedLoading}
49
72
  onOpenChange={handleOpenChange}
50
73
  footer={
51
74
  <DialogActions>
52
75
  <DialogActionButton
53
- type="button"
54
- variant="outline"
55
- disabled={cancelDisabled || isLoading}
56
- onClick={handleCancel}
57
- >
58
- {cancelText}
76
+ type="button"
77
+ variant="outline"
78
+ disabled={cancelDisabled || resolvedLoading}
79
+ onClick={handleCancel}
80
+ >
81
+ {cancelText}
59
82
  </DialogActionButton>
60
83
  <DialogActionButton
61
84
  type="button"
62
85
  variant={confirmVariant}
63
- disabled={confirmDisabled || isLoading}
64
- isLoading={isLoading}
65
- onClick={onConfirm}
86
+ disabled={confirmDisabled || resolvedLoading}
87
+ isLoading={resolvedLoading}
88
+ onClick={() => void handleConfirm()}
66
89
  >
67
90
  {confirmText}
68
91
  </DialogActionButton>
@@ -12,13 +12,15 @@ import {
12
12
  } from "@/components/ui/dialog"
13
13
  import { cn } from "@/lib/utils"
14
14
 
15
- export type DrawerSide = "left" | "right" | "top" | "bottom"
15
+ export type DrawerSide = "left" | "right" | "top" | "bottom"
16
+ export type DrawerWidth = "sm" | "md" | "lg" | "xl" | "full"
16
17
 
17
18
  export type DrawerProps = Omit<React.ComponentProps<typeof Dialog>, "children"> & {
18
19
  trigger?: React.ReactNode
19
20
  title?: React.ReactNode
20
21
  description?: React.ReactNode
21
22
  side?: DrawerSide
23
+ width?: DrawerWidth
22
24
  footer?: React.ReactNode
23
25
  headerClassName?: string
24
26
  bodyClassName?: string
@@ -29,17 +31,26 @@ export type DrawerProps = Omit<React.ComponentProps<typeof Dialog>, "children">
29
31
  }
30
32
 
31
33
  const sideClassName: Record<DrawerSide, string> = {
32
- right: "left-auto right-0 top-0 h-dvh max-h-dvh w-full max-w-md translate-x-0 translate-y-0 rounded-none rounded-l-[var(--radius-3xl)] data-open:slide-in-from-right data-closed:slide-out-to-right sm:max-w-lg",
33
- left: "left-0 top-0 h-dvh max-h-dvh w-full max-w-md translate-x-0 translate-y-0 rounded-none rounded-r-[var(--radius-3xl)] data-open:slide-in-from-left data-closed:slide-out-to-left sm:max-w-lg",
34
+ right: "left-auto right-0 top-0 h-dvh max-h-dvh w-full translate-x-0 translate-y-0 rounded-none rounded-l-[var(--radius-3xl)] data-open:slide-in-from-right data-closed:slide-out-to-right",
35
+ left: "left-0 top-0 h-dvh max-h-dvh w-full translate-x-0 translate-y-0 rounded-none rounded-r-[var(--radius-3xl)] data-open:slide-in-from-left data-closed:slide-out-to-left",
34
36
  top: "left-0 top-0 h-auto max-h-[85dvh] w-full max-w-none translate-x-0 translate-y-0 rounded-none rounded-b-[var(--radius-3xl)] data-open:slide-in-from-top data-closed:slide-out-to-top",
35
37
  bottom: "bottom-0 left-0 top-auto h-auto max-h-[85dvh] w-full max-w-none translate-x-0 translate-y-0 rounded-none rounded-t-[var(--radius-3xl)] data-open:slide-in-from-bottom data-closed:slide-out-to-bottom",
36
38
  }
39
+
40
+ const widthClassName: Record<DrawerWidth, string> = {
41
+ sm: "sm:max-w-sm",
42
+ md: "sm:max-w-md",
43
+ lg: "sm:max-w-lg",
44
+ xl: "sm:max-w-2xl",
45
+ full: "max-w-none sm:max-w-[min(100vw,72rem)]",
46
+ }
37
47
 
38
48
  function Drawer({
39
49
  trigger,
40
- title,
50
+ title,
41
51
  description,
42
52
  side = "right",
53
+ width = "lg",
43
54
  footer,
44
55
  headerClassName,
45
56
  bodyClassName,
@@ -55,7 +66,9 @@ function Drawer({
55
66
  <DialogContent
56
67
  size="full"
57
68
  showCloseButton={showCloseButton}
58
- className={cn("fixed grid grid-rows-[auto_minmax(0,1fr)_auto] gap-0 p-0", sideClassName[side], contentClassName)}
69
+ data-side={side}
70
+ data-width={width}
71
+ className={cn("fixed grid grid-rows-[auto_minmax(0,1fr)_auto] gap-0 overscroll-contain p-0", sideClassName[side], (side === "left" || side === "right") && widthClassName[width], contentClassName)}
59
72
  >
60
73
  {(title || description) && (
61
74
  <DialogHeader className={cn("border-b border-border/70 p-6", headerClassName)}>
@@ -17,6 +17,10 @@ export type AccordionRootProps = CollapseProps
17
17
  export type AccordionTriggerProps = CollapseTriggerProps
18
18
  export type AccordionContentProps = React.ComponentProps<"div">
19
19
 
20
+ /**
21
+ * Accordion is the grouped disclosure API. Use CollapseRoot/CollapseTrigger/CollapseContent
22
+ * for a single standalone disclosure.
23
+ */
20
24
  function Accordion(props: AccordionProps) {
21
25
  return <CollapseGroup data-slot="accordion" {...props} />
22
26
  }
@@ -17,6 +17,7 @@ const badgeVariants = cva(
17
17
  "border-[color:color-mix(in_oklch,var(--border),var(--foreground)_10%)] bg-[color:color-mix(in_oklch,var(--muted),var(--background)_8%)] text-foreground",
18
18
  destructive:
19
19
  "border-[color:color-mix(in_oklch,var(--destructive),transparent_52%)] bg-[color:color-mix(in_oklch,var(--destructive),transparent_82%)] text-[color:color-mix(in_oklch,var(--destructive),black_16%)] dark:text-[color:color-mix(in_oklch,var(--destructive),white_38%)]",
20
+ soft: "border-transparent bg-[color:color-mix(in_oklch,var(--muted),transparent_38%)] text-foreground shadow-none",
20
21
  outline: "bg-[color:color-mix(in_oklch,var(--background),var(--muted)_6%)] text-foreground shadow-none",
21
22
  ghost: "border-transparent bg-[color:color-mix(in_oklch,var(--muted),transparent_76%)] text-muted-foreground shadow-none",
22
23
  link: "border-transparent bg-transparent p-0 text-primary shadow-none underline-offset-4",
@@ -115,7 +116,7 @@ function Badge({
115
116
  event.stopPropagation()
116
117
  onRemove?.()
117
118
  }}
118
- className="inline-flex size-4 shrink-0 items-center justify-center rounded-full bg-[color:color-mix(in_oklch,currentColor,transparent_90%)] opacity-80 transition hover:opacity-100"
119
+ className="inline-flex size-4 shrink-0 items-center justify-center rounded-full bg-[color:color-mix(in_oklch,currentColor,transparent_90%)] opacity-80 transition hover:opacity-100 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-current/35"
119
120
  >
120
121
  <XIcon className="size-3" />
121
122
  </button>
@@ -46,6 +46,7 @@ export type ButtonProps = ButtonPrimitive.Props &
46
46
  loadingLabel?: string
47
47
  leftIcon?: React.ReactNode
48
48
  rightIcon?: React.ReactNode
49
+ iconOnly?: boolean
49
50
  fullWidth?: boolean
50
51
  pressed?: boolean
51
52
  }
@@ -59,25 +60,30 @@ function Button({
59
60
  loadingLabel = "Loading",
60
61
  leftIcon,
61
62
  rightIcon,
63
+ iconOnly = false,
62
64
  fullWidth = false,
63
65
  pressed = false,
64
66
  children,
67
+ "aria-label": ariaLabel,
65
68
  ...props
66
69
  }: ButtonProps) {
67
- const isDisabled = disabled || loading
68
-
69
- return (
70
+ const isDisabled = disabled || loading
71
+ const resolvedSize = iconOnly && (size === "default" || size === "md") ? "icon" : size
72
+
73
+ return (
70
74
  <ButtonPrimitive
71
75
  data-slot="button"
72
76
  data-variant={variant ?? "default"}
73
- data-size={size ?? "default"}
77
+ data-size={resolvedSize ?? "default"}
78
+ data-icon-only={iconOnly || undefined}
74
79
  data-loading={loading || undefined}
75
80
  data-pressed={pressed || undefined}
76
81
  disabled={isDisabled}
77
82
  aria-busy={loading || undefined}
78
83
  aria-pressed={pressed || undefined}
84
+ aria-label={ariaLabel}
79
85
  className={cn(
80
- buttonVariants({ variant, size, className }),
86
+ buttonVariants({ variant, size: resolvedSize, className }),
81
87
  fullWidth && "w-full",
82
88
  pressed && "shadow-[var(--aui-control-shadow,0_1px_2px_rgba(15,23,42,0.04)),0_0_0_1px_var(--aui-focus-ring,var(--ring))]"
83
89
  )}
@@ -70,8 +70,9 @@ function DialogContent({
70
70
  data-size={size}
71
71
  data-surface={surface}
72
72
  role="dialog"
73
+ aria-modal="true"
73
74
  className={cn(
74
- "fixed top-1/2 left-1/2 z-50 grid w-full max-w-[calc(100%-2rem)] -translate-x-1/2 -translate-y-1/2 gap-5 overflow-hidden rounded-[var(--radius-3xl)] border border-[color:var(--aui-card-border,var(--border))] bg-[color:var(--aui-overlay-surface,var(--popover))] p-6 text-sm text-popover-foreground shadow-[var(--aui-control-panel-shadow,0_24px_70px_rgba(15,23,42,0.22))] backdrop-blur duration-100 outline-none data-[surface=plain]:overflow-visible data-[surface=plain]:border-transparent data-[surface=plain]:bg-transparent data-[surface=plain]:p-0 data-[surface=plain]:shadow-none data-[size=xs]:sm:max-w-sm data-[size=sm]:sm:max-w-md data-[size=md]:sm:max-w-lg data-[size=lg]:sm:max-w-2xl data-[size=xl]:sm:max-w-4xl data-[size=full]:h-[min(92vh,56rem)] data-[size=full]:max-w-[min(96vw,84rem)] data-[size=full]:grid-rows-[auto_minmax(0,1fr)] data-open:animate-in data-open:fade-in-0 data-open:zoom-in-95 data-closed:animate-out data-closed:fade-out-0 data-closed:zoom-out-95",
75
+ "fixed top-1/2 left-1/2 z-50 grid max-h-[min(92vh,calc(100dvh-2rem))] w-full max-w-[calc(100%-2rem)] -translate-x-1/2 -translate-y-1/2 gap-5 overflow-y-auto overscroll-contain rounded-[var(--radius-3xl)] border border-[color:var(--aui-card-border,var(--border))] bg-[color:var(--aui-overlay-surface,var(--popover))] p-6 text-sm text-popover-foreground shadow-[var(--aui-control-panel-shadow,0_24px_70px_rgba(15,23,42,0.22))] backdrop-blur duration-100 outline-none data-[surface=plain]:overflow-visible data-[surface=plain]:border-transparent data-[surface=plain]:bg-transparent data-[surface=plain]:p-0 data-[surface=plain]:shadow-none data-[size=xs]:sm:max-w-sm data-[size=sm]:sm:max-w-md data-[size=md]:sm:max-w-lg data-[size=lg]:sm:max-w-2xl data-[size=xl]:sm:max-w-4xl data-[size=full]:h-[min(92vh,56rem)] data-[size=full]:max-w-[min(96vw,84rem)] data-[size=full]:grid-rows-[auto_minmax(0,1fr)] data-open:animate-in data-open:fade-in-0 data-open:zoom-in-95 data-closed:animate-out data-closed:fade-out-0 data-closed:zoom-out-95",
75
76
  className
76
77
  )}
77
78
  {...props}
@@ -1,51 +1,77 @@
1
1
  import * as React from "react"
2
+ import { PreviewCard as PreviewCardPrimitive } from "@base-ui/react/preview-card"
2
3
 
3
4
  import { cn } from "@/lib/utils"
4
5
 
5
- export type HoverCardProps = Omit<React.ComponentProps<"div">, "content"> & {
6
+ export type HoverCardProps = Omit<PreviewCardPrimitive.Root.Props, "children"> &
7
+ Omit<React.ComponentProps<"span">, "content" | "children"> & {
6
8
  trigger: React.ReactNode
7
9
  content: React.ReactNode
8
- side?: "top" | "right" | "bottom" | "left"
10
+ side?: PreviewCardPrimitive.Positioner.Props["side"]
11
+ align?: PreviewCardPrimitive.Positioner.Props["align"]
12
+ sideOffset?: PreviewCardPrimitive.Positioner.Props["sideOffset"]
13
+ alignOffset?: PreviewCardPrimitive.Positioner.Props["alignOffset"]
14
+ collisionPadding?: PreviewCardPrimitive.Positioner.Props["collisionPadding"]
15
+ delay?: PreviewCardPrimitive.Trigger.Props["delay"]
16
+ closeDelay?: PreviewCardPrimitive.Trigger.Props["closeDelay"]
17
+ disabled?: boolean
9
18
  contentClassName?: string
10
19
  }
11
20
 
12
- const sideClassName = {
13
- top: "bottom-full left-1/2 mb-2.5 -translate-x-1/2",
14
- right: "left-full top-1/2 ml-2.5 -translate-y-1/2",
15
- bottom: "left-1/2 top-full mt-2.5 -translate-x-1/2",
16
- left: "right-full top-1/2 mr-2.5 -translate-y-1/2",
17
- } as const
18
-
19
21
  function HoverCard({
20
22
  trigger,
21
23
  content,
22
24
  side = "bottom",
25
+ align = "center",
26
+ sideOffset = 10,
27
+ alignOffset = 0,
28
+ collisionPadding = 12,
29
+ delay = 450,
30
+ closeDelay = 180,
31
+ disabled = false,
23
32
  contentClassName,
24
33
  className,
25
- children,
26
34
  ...props
27
35
  }: HoverCardProps) {
28
- return (
29
- <div
30
- data-slot="hover-card"
31
- className={cn("group/hover-card relative inline-flex", className)}
32
- {...props}
33
- >
34
- <span data-slot="hover-card-trigger" className="inline-flex">
36
+ if (disabled) {
37
+ return (
38
+ <span data-slot="hover-card" className={cn("inline-flex", className)} {...props}>
35
39
  {trigger}
36
40
  </span>
37
- <div
38
- data-slot="hover-card-content"
39
- className={cn(
40
- "pointer-events-none absolute z-50 min-w-60 rounded-[var(--radius-2xl)] border border-border/80 bg-popover/98 p-4 text-sm text-popover-foreground opacity-0 shadow-[0_18px_42px_color-mix(in_oklch,var(--foreground),transparent_86%)] ring-1 ring-foreground/8 backdrop-blur transition duration-150 group-hover/hover-card:pointer-events-auto group-hover/hover-card:opacity-100 group-focus-within/hover-card:pointer-events-auto group-focus-within/hover-card:opacity-100",
41
- sideClassName[side],
42
- contentClassName
43
- )}
41
+ )
42
+ }
43
+
44
+ return (
45
+ <PreviewCardPrimitive.Root>
46
+ <PreviewCardPrimitive.Trigger
47
+ data-slot="hover-card-trigger"
48
+ delay={delay}
49
+ closeDelay={closeDelay}
50
+ render={<span data-slot="hover-card" className={cn("inline-flex", className)} {...props} />}
44
51
  >
45
- {content}
46
- </div>
47
- {children}
48
- </div>
52
+ {trigger}
53
+ </PreviewCardPrimitive.Trigger>
54
+ <PreviewCardPrimitive.Portal>
55
+ <PreviewCardPrimitive.Positioner
56
+ className="isolate z-50"
57
+ side={side}
58
+ align={align}
59
+ sideOffset={sideOffset}
60
+ alignOffset={alignOffset}
61
+ collisionPadding={collisionPadding}
62
+ >
63
+ <PreviewCardPrimitive.Popup
64
+ data-slot="hover-card-content"
65
+ className={cn(
66
+ "z-50 min-w-60 max-w-[min(24rem,calc(100vw-1rem))] origin-(--transform-origin) rounded-[var(--aui-card-radius,var(--radius-xl))] border border-border/80 bg-popover/98 p-4 text-sm text-popover-foreground shadow-[0_18px_42px_color-mix(in_oklch,var(--foreground),transparent_86%)] ring-1 ring-foreground/8 outline-hidden backdrop-blur duration-150 data-open:animate-in data-open:fade-in-0 data-open:zoom-in-95 data-closed:animate-out data-closed:fade-out-0 data-closed:zoom-out-95",
67
+ contentClassName
68
+ )}
69
+ >
70
+ {content}
71
+ </PreviewCardPrimitive.Popup>
72
+ </PreviewCardPrimitive.Positioner>
73
+ </PreviewCardPrimitive.Portal>
74
+ </PreviewCardPrimitive.Root>
49
75
  )
50
76
  }
51
77
 
@@ -10,7 +10,7 @@ export type PopoverTriggerProps = PopoverPrimitive.Trigger.Props
10
10
  export type PopoverContentProps = PopoverPrimitive.Popup.Props &
11
11
  Pick<
12
12
  PopoverPrimitive.Positioner.Props,
13
- "align" | "alignOffset" | "side" | "sideOffset"
13
+ "align" | "alignOffset" | "collisionBoundary" | "collisionPadding" | "side" | "sideOffset"
14
14
  >
15
15
  export type PopoverHeaderProps = React.ComponentProps<"div">
16
16
  export type PopoverTitleProps = PopoverPrimitive.Title.Props
@@ -28,6 +28,7 @@ function PopoverContent({
28
28
  className,
29
29
  align = "center",
30
30
  alignOffset = 0,
31
+ collisionPadding = 12,
31
32
  side = "bottom",
32
33
  sideOffset = 4,
33
34
  ...props
@@ -35,16 +36,17 @@ function PopoverContent({
35
36
  return (
36
37
  <PopoverPrimitive.Portal>
37
38
  <PopoverPrimitive.Positioner
38
- align={align}
39
- alignOffset={alignOffset}
40
- side={side}
41
- sideOffset={sideOffset}
42
- className="isolate z-50"
43
- >
39
+ align={align}
40
+ alignOffset={alignOffset}
41
+ collisionPadding={collisionPadding}
42
+ side={side}
43
+ sideOffset={sideOffset}
44
+ className="isolate z-50"
45
+ >
44
46
  <PopoverPrimitive.Popup
45
47
  data-slot="popover-content"
46
48
  className={cn(
47
- "z-50 flex w-80 origin-(--transform-origin) flex-col gap-3 rounded-[var(--aui-card-radius,var(--radius-xl))] border border-[color:var(--aui-card-border,var(--border))] bg-[color:var(--aui-overlay-surface,var(--popover))] p-4 text-sm text-popover-foreground shadow-[var(--aui-popover-shadow,0_18px_42px_rgba(15,23,42,0.16))] outline-hidden duration-100 data-[side=bottom]:slide-in-from-top-2 data-[side=inline-end]:slide-in-from-left-2 data-[side=inline-start]:slide-in-from-right-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 data-open:animate-in data-open:fade-in-0 data-open:zoom-in-95 data-closed:animate-out data-closed:fade-out-0 data-closed:zoom-out-95",
49
+ "z-50 flex max-h-[min(var(--available-height),calc(100dvh-1rem))] w-[min(var(--anchor-width),20rem)] min-w-60 max-w-[calc(100vw-1rem)] origin-(--transform-origin) flex-col gap-3 overflow-y-auto rounded-[var(--aui-card-radius,var(--radius-xl))] border border-[color:var(--aui-card-border,var(--border))] bg-[color:var(--aui-overlay-surface,var(--popover))] p-4 text-sm text-popover-foreground shadow-[var(--aui-popover-shadow,0_18px_42px_rgba(15,23,42,0.16))] outline-hidden duration-100 data-[side=bottom]:slide-in-from-top-2 data-[side=inline-end]:slide-in-from-left-2 data-[side=inline-start]:slide-in-from-right-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 data-open:animate-in data-open:fade-in-0 data-open:zoom-in-95 data-closed:animate-out data-closed:fade-out-0 data-closed:zoom-out-95",
48
50
  className
49
51
  )}
50
52
  {...props}
@@ -17,7 +17,11 @@ export type RadioGroupProps = Omit<React.ComponentProps<"div">, "onChange"> & {
17
17
  options: RadioGroupOption[]
18
18
  orientation?: "vertical" | "horizontal"
19
19
  size?: "sm" | "default" | "lg"
20
+ invalid?: boolean
21
+ disabled?: boolean
20
22
  itemClassName?: string
23
+ itemLabelClassName?: string
24
+ itemDescriptionClassName?: string
21
25
  }
22
26
 
23
27
  const sizeClassName = {
@@ -34,8 +38,12 @@ function RadioGroup({
34
38
  options,
35
39
  orientation = "vertical",
36
40
  size = "default",
41
+ invalid = false,
42
+ disabled = false,
37
43
  className,
38
44
  itemClassName,
45
+ itemLabelClassName,
46
+ itemDescriptionClassName,
39
47
  ...props
40
48
  }: RadioGroupProps) {
41
49
  const generatedName = React.useId()
@@ -43,39 +51,80 @@ function RadioGroup({
43
51
  const [internalValue, setInternalValue] = React.useState(defaultValue ?? "")
44
52
  const isControlled = value !== undefined
45
53
  const currentValue = isControlled ? value : internalValue
54
+ const itemRefs = React.useRef<Array<HTMLInputElement | null>>([])
55
+ const enabledOptions = options.filter((option) => !option.disabled && !disabled)
46
56
 
47
57
  const setValue = (nextValue: string) => {
48
58
  if (!isControlled) setInternalValue(nextValue)
49
59
  onValueChange?.(nextValue)
50
60
  }
51
61
 
62
+ const focusOption = (nextIndex: number) => {
63
+ const option = enabledOptions[nextIndex]
64
+ if (!option) return
65
+ const optionIndex = options.findIndex((item) => item.value === option.value)
66
+ itemRefs.current[optionIndex]?.focus()
67
+ setValue(option.value)
68
+ }
69
+
70
+ const handleKeyDown: React.KeyboardEventHandler<HTMLDivElement> = (event) => {
71
+ if (!["ArrowDown", "ArrowRight", "ArrowUp", "ArrowLeft", "Home", "End"].includes(event.key)) return
72
+ if (enabledOptions.length === 0) return
73
+
74
+ event.preventDefault()
75
+ const currentEnabledIndex = Math.max(
76
+ 0,
77
+ enabledOptions.findIndex((option) => option.value === currentValue)
78
+ )
79
+ if (event.key === "Home") {
80
+ focusOption(0)
81
+ return
82
+ }
83
+ if (event.key === "End") {
84
+ focusOption(enabledOptions.length - 1)
85
+ return
86
+ }
87
+ const direction = event.key === "ArrowDown" || event.key === "ArrowRight" ? 1 : -1
88
+ focusOption((currentEnabledIndex + direction + enabledOptions.length) % enabledOptions.length)
89
+ }
90
+
52
91
  return (
53
92
  <div
54
93
  role="radiogroup"
94
+ aria-invalid={invalid || undefined}
95
+ aria-disabled={disabled || undefined}
55
96
  data-slot="radio-group"
56
97
  data-orientation={orientation}
98
+ data-invalid={invalid || undefined}
57
99
  className={cn("grid gap-2", orientation === "horizontal" && "sm:flex sm:flex-wrap sm:items-center", className)}
100
+ onKeyDown={handleKeyDown}
58
101
  {...props}
59
102
  >
60
- {options.map((option) => {
103
+ {options.map((option, index) => {
61
104
  const checked = option.value === currentValue
105
+ const optionDisabled = disabled || option.disabled
62
106
  return (
63
107
  <label
64
108
  key={option.value}
65
109
  data-slot="radio-group-item"
66
110
  data-checked={checked || undefined}
67
- data-disabled={option.disabled || undefined}
111
+ data-disabled={optionDisabled || undefined}
112
+ data-invalid={invalid || undefined}
68
113
  className={cn(
69
- "group flex cursor-pointer items-start gap-3 rounded-[min(var(--radius-xl),16px)] border border-border/80 bg-background/88 px-3 py-2.5 text-sm transition hover:border-ring/35 hover:bg-accent/60 data-[checked=true]:border-primary/35 data-[checked=true]:bg-primary/8 data-[disabled=true]:cursor-not-allowed data-[disabled=true]:opacity-55",
114
+ "group flex cursor-pointer items-start gap-3 rounded-[min(var(--radius-xl),16px)] border border-border/80 bg-background/88 px-3 py-2.5 text-sm transition hover:border-ring/35 hover:bg-accent/60 focus-within:border-ring focus-within:ring-3 focus-within:ring-ring/30 data-[checked=true]:border-primary/35 data-[checked=true]:bg-primary/8 data-[disabled=true]:cursor-not-allowed data-[disabled=true]:opacity-55 data-[invalid=true]:border-destructive/70 data-[invalid=true]:ring-3 data-[invalid=true]:ring-destructive/15",
70
115
  itemClassName
71
116
  )}
72
117
  >
73
118
  <input
119
+ ref={(node) => {
120
+ itemRefs.current[index] = node
121
+ }}
74
122
  type="radio"
75
123
  name={resolvedName}
76
124
  value={option.value}
77
125
  checked={checked}
78
- disabled={option.disabled}
126
+ disabled={optionDisabled}
127
+ aria-invalid={invalid || undefined}
79
128
  className="sr-only"
80
129
  onChange={() => setValue(option.value)}
81
130
  />
@@ -89,8 +138,8 @@ function RadioGroup({
89
138
  <span className="size-1.5 rounded-full bg-primary-foreground opacity-0 transition group-data-[checked=true]:opacity-100" />
90
139
  </span>
91
140
  <span className="min-w-0">
92
- <span className="block font-medium text-foreground">{option.label}</span>
93
- {option.description ? <span className="mt-1 block text-sm leading-6 text-muted-foreground">{option.description}</span> : null}
141
+ <span className={cn("block font-medium text-foreground", itemLabelClassName)}>{option.label}</span>
142
+ {option.description ? <span className={cn("mt-1 block text-sm leading-6 text-muted-foreground", itemDescriptionClassName)}>{option.description}</span> : null}
94
143
  </span>
95
144
  </label>
96
145
  )