tembro 2.0.6 → 2.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (344) 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/status-legend.cjs +1 -1
  37. package/dist/components/display/status-legend.js +6 -2
  38. package/dist/components/display/tag.cjs +1 -1
  39. package/dist/components/display/tag.d.ts +2 -1
  40. package/dist/components/display/tag.js +28 -22
  41. package/dist/components/display/tree-view.cjs +1 -1
  42. package/dist/components/display/tree-view.d.ts +9 -1
  43. package/dist/components/display/tree-view.js +104 -40
  44. package/dist/components/display/trend-card.cjs +1 -1
  45. package/dist/components/display/trend-card.js +27 -41
  46. package/dist/components/feedback/alert.cjs +1 -1
  47. package/dist/components/feedback/alert.d.ts +2 -1
  48. package/dist/components/feedback/alert.js +6 -6
  49. package/dist/components/feedback/loading-state.cjs +1 -1
  50. package/dist/components/feedback/loading-state.d.ts +3 -1
  51. package/dist/components/feedback/loading-state.js +23 -10
  52. package/dist/components/feedback/page-state.cjs +1 -1
  53. package/dist/components/feedback/page-state.d.ts +2 -1
  54. package/dist/components/feedback/page-state.js +7 -4
  55. package/dist/components/form/form-field-shell.cjs +1 -1
  56. package/dist/components/form/form-field-shell.d.ts +4 -2
  57. package/dist/components/form/form-field-shell.js +57 -41
  58. package/dist/components/form/form-input.cjs +1 -1
  59. package/dist/components/form/form-input.js +2 -0
  60. package/dist/components/form/form-select.cjs +1 -1
  61. package/dist/components/form/form-select.js +2 -0
  62. package/dist/components/form/form-switch.cjs +1 -1
  63. package/dist/components/form/form-switch.d.ts +1 -1
  64. package/dist/components/form/form-switch.js +58 -54
  65. package/dist/components/form/form-textarea.cjs +1 -1
  66. package/dist/components/form/form-textarea.d.ts +1 -1
  67. package/dist/components/form/form-textarea.js +29 -27
  68. package/dist/components/layout/app-sidebar.cjs +1 -1
  69. package/dist/components/layout/app-sidebar.d.ts +1 -0
  70. package/dist/components/layout/app-sidebar.js +36 -36
  71. package/dist/components/layout/breadcrumbs.cjs +1 -1
  72. package/dist/components/layout/breadcrumbs.d.ts +2 -1
  73. package/dist/components/layout/breadcrumbs.js +7 -7
  74. package/dist/components/modern/calendar-scheduler.cjs +1 -1
  75. package/dist/components/modern/calendar-scheduler.d.ts +5 -1
  76. package/dist/components/modern/calendar-scheduler.js +47 -28
  77. package/dist/components/modern/dual-list-picker.cjs +1 -1
  78. package/dist/components/modern/dual-list-picker.d.ts +5 -1
  79. package/dist/components/modern/dual-list-picker.js +81 -23
  80. package/dist/components/modern/rich-text-editor.cjs +1 -1
  81. package/dist/components/modern/rich-text-editor.d.ts +3 -1
  82. package/dist/components/modern/rich-text-editor.js +12 -9
  83. package/dist/components/modern/tour.cjs +1 -1
  84. package/dist/components/modern/tour.d.ts +5 -1
  85. package/dist/components/modern/tour.js +57 -35
  86. package/dist/components/navigation/command-bar.cjs +1 -1
  87. package/dist/components/navigation/command-bar.d.ts +3 -1
  88. package/dist/components/navigation/command-bar.js +10 -7
  89. package/dist/components/navigation/demo.cjs +1 -1
  90. package/dist/components/navigation/demo.js +0 -1
  91. package/dist/components/navigation/nav-tabs.cjs +1 -1
  92. package/dist/components/navigation/nav-tabs.js +39 -27
  93. package/dist/components/navigation/page-tabs.cjs +1 -1
  94. package/dist/components/navigation/page-tabs.js +41 -30
  95. package/dist/components/navigation/pagination.cjs +1 -1
  96. package/dist/components/navigation/pagination.d.ts +7 -1
  97. package/dist/components/navigation/pagination.js +48 -25
  98. package/dist/components/notifications/notification-center.cjs +1 -1
  99. package/dist/components/notifications/notification-center.d.ts +3 -1
  100. package/dist/components/notifications/notification-center.js +56 -38
  101. package/dist/components/notifications/toast.cjs +1 -1
  102. package/dist/components/notifications/toast.d.ts +1 -0
  103. package/dist/components/notifications/toast.js +4 -0
  104. package/dist/components/overlay/alert-dialog.cjs +1 -1
  105. package/dist/components/overlay/alert-dialog.js +1 -1
  106. package/dist/components/overlay/confirm-dialog.cjs +1 -1
  107. package/dist/components/overlay/confirm-dialog.d.ts +4 -2
  108. package/dist/components/overlay/confirm-dialog.js +31 -22
  109. package/dist/components/overlay/drawer.cjs +1 -1
  110. package/dist/components/overlay/drawer.d.ts +3 -1
  111. package/dist/components/overlay/drawer.js +24 -16
  112. package/dist/components/ui/accordion/index.d.ts +4 -0
  113. package/dist/components/ui/badge/index.cjs +1 -1
  114. package/dist/components/ui/badge/index.d.ts +1 -1
  115. package/dist/components/ui/badge/index.js +2 -1
  116. package/dist/components/ui/button/index.cjs +1 -1
  117. package/dist/components/ui/button/index.d.ts +2 -1
  118. package/dist/components/ui/button/index.js +13 -10
  119. package/dist/components/ui/dialog/index.cjs +1 -1
  120. package/dist/components/ui/dialog/index.js +2 -1
  121. package/dist/components/ui/hover-card.cjs +1 -1
  122. package/dist/components/ui/hover-card.d.ts +11 -3
  123. package/dist/components/ui/hover-card.js +29 -24
  124. package/dist/components/ui/input/index.d.ts +1 -1
  125. package/dist/components/ui/popover/index.cjs +1 -1
  126. package/dist/components/ui/popover/index.d.ts +2 -2
  127. package/dist/components/ui/popover/index.js +6 -5
  128. package/dist/components/ui/radio-group/index.cjs +1 -1
  129. package/dist/components/ui/radio-group/index.d.ts +5 -1
  130. package/dist/components/ui/radio-group/index.js +50 -16
  131. package/dist/components/ui/right-click-menu/index.cjs +1 -1
  132. package/dist/components/ui/right-click-menu/index.d.ts +5 -1
  133. package/dist/components/ui/right-click-menu/index.js +77 -23
  134. package/dist/components/ui/segmented-control/index.cjs +1 -1
  135. package/dist/components/ui/segmented-control/index.d.ts +2 -1
  136. package/dist/components/ui/segmented-control/index.js +23 -11
  137. package/dist/components/ui/select/index.cjs +1 -1
  138. package/dist/components/ui/select/index.d.ts +8 -1
  139. package/dist/components/ui/select/index.js +40 -35
  140. package/dist/components/ui/switch/index.cjs +1 -1
  141. package/dist/components/ui/switch/index.d.ts +18 -0
  142. package/dist/components/ui/switch/index.js +47 -17
  143. package/dist/components/ui/tabs/index.cjs +1 -1
  144. package/dist/components/ui/tabs/index.d.ts +14 -4
  145. package/dist/components/ui/tabs/index.js +11 -8
  146. package/dist/components/ui/textarea/index.cjs +1 -1
  147. package/dist/components/ui/textarea/index.d.ts +10 -2
  148. package/dist/components/ui/textarea/index.js +37 -8
  149. package/dist/components/ui/textarea.cjs +1 -0
  150. package/dist/components/ui/textarea.d.ts +1 -0
  151. package/dist/components/ui/textarea.js +2 -0
  152. package/dist/components/ui/tooltip/index.cjs +1 -1
  153. package/dist/components/ui/tooltip/index.d.ts +11 -3
  154. package/dist/components/ui/tooltip/index.js +41 -20
  155. package/dist/components/upload/file-upload.cjs +1 -1
  156. package/dist/components/upload/file-upload.d.ts +8 -1
  157. package/dist/components/upload/file-upload.js +132 -100
  158. package/dist/components/upload/image-upload.cjs +1 -1
  159. package/dist/components/upload/image-upload.d.ts +5 -1
  160. package/dist/components/upload/image-upload.js +34 -9
  161. package/dist/index.cjs +1 -1
  162. package/dist/index.js +31 -31
  163. package/dist/public-component-surface.cjs +1 -1
  164. package/dist/public-component-surface.js +15 -0
  165. package/dist/showcase/component-api-schema.cjs +1 -1
  166. package/dist/showcase/component-api-schema.js +187 -10
  167. package/dist/showcase/fallback.cjs +3 -3
  168. package/dist/showcase/fallback.js +221 -243
  169. package/dist/showcase/premium/alert/showcase.cjs +1 -1
  170. package/dist/showcase/premium/alert/showcase.js +1 -0
  171. package/dist/showcase/premium/app-sidebar/showcase.cjs +1 -1
  172. package/dist/showcase/premium/app-sidebar/showcase.js +1 -0
  173. package/dist/showcase/premium/badge/showcase.cjs +1 -1
  174. package/dist/showcase/premium/badge/showcase.js +7 -0
  175. package/dist/showcase/premium/badge/types.d.ts +1 -1
  176. package/dist/showcase/premium/breadcrumbs/showcase.cjs +1 -1
  177. package/dist/showcase/premium/breadcrumbs/showcase.js +12 -1
  178. package/dist/showcase/premium/button/mock.cjs +1 -4
  179. package/dist/showcase/premium/button/mock.js +1 -1
  180. package/dist/showcase/premium/button/showcase.cjs +1 -1
  181. package/dist/showcase/premium/button/showcase.js +2 -2
  182. package/dist/showcase/premium/card/showcase.cjs +1 -1
  183. package/dist/showcase/premium/card/showcase.js +96 -47
  184. package/dist/showcase/premium/carousel/showcase.cjs +1 -1
  185. package/dist/showcase/premium/carousel/showcase.js +76 -49
  186. package/dist/showcase/premium/command-bar/showcase.cjs +1 -1
  187. package/dist/showcase/premium/command-bar/showcase.js +2 -0
  188. package/dist/showcase/premium/data-table/mock.cjs +12 -11
  189. package/dist/showcase/premium/data-table/mock.js +1 -1
  190. package/dist/showcase/premium/file-upload/showcase.cjs +1 -1
  191. package/dist/showcase/premium/file-upload/showcase.js +25 -4
  192. package/dist/showcase/premium/image-upload/showcase.cjs +1 -1
  193. package/dist/showcase/premium/image-upload/showcase.js +4 -1
  194. package/dist/showcase/premium/index.cjs +1 -1
  195. package/dist/showcase/premium/index.js +396 -402
  196. package/dist/showcase/premium/loading-state/showcase.cjs +1 -1
  197. package/dist/showcase/premium/loading-state/showcase.js +3 -1
  198. package/dist/showcase/premium/metric-grid/showcase.cjs +1 -1
  199. package/dist/showcase/premium/metric-grid/showcase.js +96 -28
  200. package/dist/showcase/premium/notification-center/showcase.cjs +1 -1
  201. package/dist/showcase/premium/notification-center/showcase.js +7 -3
  202. package/dist/showcase/premium/page-state/showcase.cjs +1 -1
  203. package/dist/showcase/premium/page-state/showcase.js +5 -1
  204. package/dist/showcase/premium/pagination/showcase.cjs +1 -1
  205. package/dist/showcase/premium/pagination/showcase.js +15 -2
  206. package/dist/showcase/premium/popover/showcase.cjs +1 -1
  207. package/dist/showcase/premium/popover/showcase.js +85 -50
  208. package/dist/showcase/premium/radio-group/showcase.cjs +1 -1
  209. package/dist/showcase/premium/radio-group/showcase.js +27 -4
  210. package/dist/showcase/premium/right-click-menu/showcase.cjs +1 -1
  211. package/dist/showcase/premium/right-click-menu/showcase.js +56 -43
  212. package/dist/showcase/premium/segmented-control/showcase.cjs +1 -1
  213. package/dist/showcase/premium/segmented-control/showcase.js +1 -0
  214. package/dist/showcase/premium/select/data.cjs +1 -1
  215. package/dist/showcase/premium/select/data.js +69 -34
  216. package/dist/showcase/premium/select/mock.cjs +19 -6
  217. package/dist/showcase/premium/select/mock.js +3 -2
  218. package/dist/showcase/premium/select/showcase.cjs +1 -1
  219. package/dist/showcase/premium/select/showcase.js +43 -18
  220. package/dist/showcase/premium/select/types.d.ts +3 -0
  221. package/dist/showcase/premium/statistic/showcase.cjs +1 -1
  222. package/dist/showcase/premium/statistic/showcase.js +57 -25
  223. package/dist/showcase/premium/switch/showcase.cjs +1 -1
  224. package/dist/showcase/premium/switch/showcase.js +25 -14
  225. package/dist/showcase/premium/tabs/showcase.cjs +1 -1
  226. package/dist/showcase/premium/tabs/showcase.js +171 -48
  227. package/dist/showcase/premium/textarea/mock.cjs +12 -4
  228. package/dist/showcase/premium/textarea/mock.js +1 -1
  229. package/dist/showcase/premium/textarea/showcase.cjs +1 -1
  230. package/dist/showcase/premium/textarea/showcase.js +8 -3
  231. package/dist/showcase/premium/toast/showcase.cjs +1 -1
  232. package/dist/showcase/premium/toast/showcase.js +32 -6
  233. package/dist/showcase/premium/types.d.ts +1 -1
  234. package/dist/showcase/registry-quality.cjs +1 -1
  235. package/dist/showcase/registry-quality.js +1 -0
  236. package/dist/showcase/render-registry-preview.cjs +1 -1
  237. package/dist/showcase/render-registry-preview.js +57 -79
  238. package/dist/showcase/site-data.cjs +1 -1
  239. package/dist/showcase/site-data.js +60 -21
  240. package/dist/showcase/tembro-registry.json.cjs +1 -1
  241. package/dist/showcase/tembro-registry.json.js +34 -20
  242. package/dist/showcase/types.d.ts +1 -1
  243. package/package.json +1 -1
  244. package/packages/cli/dist/index.cjs +31 -31
  245. package/packages/cli/vendor/src/components/calendar/calendar.tsx +59 -50
  246. package/packages/cli/vendor/src/components/calendar/date-range-picker.tsx +7 -4
  247. package/packages/cli/vendor/src/components/charts/charts.tsx +109 -66
  248. package/packages/cli/vendor/src/components/charts/progress-ring.tsx +37 -26
  249. package/packages/cli/vendor/src/components/data-table/data-table-column-visibility-menu.tsx +41 -22
  250. package/packages/cli/vendor/src/components/data-table/data-table-toolbar.tsx +8 -6
  251. package/packages/cli/vendor/src/components/display/carousel.tsx +84 -3
  252. package/packages/cli/vendor/src/components/display/code-block.tsx +22 -2
  253. package/packages/cli/vendor/src/components/display/delta-badge.tsx +11 -11
  254. package/packages/cli/vendor/src/components/display/kanban.tsx +103 -57
  255. package/packages/cli/vendor/src/components/display/metric-grid.tsx +16 -13
  256. package/packages/cli/vendor/src/components/display/qr-code.tsx +17 -15
  257. package/packages/cli/vendor/src/components/display/status-legend.tsx +11 -8
  258. package/packages/cli/vendor/src/components/display/tag.tsx +39 -21
  259. package/packages/cli/vendor/src/components/display/tree-view.tsx +221 -84
  260. package/packages/cli/vendor/src/components/display/trend-card.tsx +6 -40
  261. package/packages/cli/vendor/src/components/feedback/alert.tsx +3 -1
  262. package/packages/cli/vendor/src/components/feedback/loading-state.tsx +33 -17
  263. package/packages/cli/vendor/src/components/feedback/page-state.tsx +8 -7
  264. package/packages/cli/vendor/src/components/form/form-field-shell.tsx +37 -8
  265. package/packages/cli/vendor/src/components/form/form-input.tsx +2 -0
  266. package/packages/cli/vendor/src/components/form/form-select.tsx +2 -0
  267. package/packages/cli/vendor/src/components/form/form-switch.tsx +9 -3
  268. package/packages/cli/vendor/src/components/form/form-textarea.tsx +6 -2
  269. package/packages/cli/vendor/src/components/layout/app-sidebar.tsx +3 -1
  270. package/packages/cli/vendor/src/components/layout/breadcrumbs.tsx +3 -1
  271. package/packages/cli/vendor/src/components/modern/calendar-scheduler.tsx +28 -13
  272. package/packages/cli/vendor/src/components/modern/dual-list-picker.tsx +103 -35
  273. package/packages/cli/vendor/src/components/modern/rich-text-editor.tsx +25 -22
  274. package/packages/cli/vendor/src/components/modern/tour.tsx +47 -29
  275. package/packages/cli/vendor/src/components/navigation/command-bar.tsx +6 -0
  276. package/packages/cli/vendor/src/components/navigation/demo.tsx +0 -1
  277. package/packages/cli/vendor/src/components/navigation/nav-tabs.tsx +38 -29
  278. package/packages/cli/vendor/src/components/navigation/page-tabs.tsx +35 -23
  279. package/packages/cli/vendor/src/components/navigation/pagination.tsx +65 -31
  280. package/packages/cli/vendor/src/components/notifications/notification-center.tsx +64 -39
  281. package/packages/cli/vendor/src/components/notifications/toast.tsx +23 -21
  282. package/packages/cli/vendor/src/components/overlay/alert-dialog.tsx +1 -1
  283. package/packages/cli/vendor/src/components/overlay/confirm-dialog.tsx +45 -22
  284. package/packages/cli/vendor/src/components/overlay/drawer.tsx +18 -5
  285. package/packages/cli/vendor/src/components/ui/accordion/index.tsx +4 -0
  286. package/packages/cli/vendor/src/components/ui/badge/index.tsx +2 -1
  287. package/packages/cli/vendor/src/components/ui/button/index.tsx +11 -5
  288. package/packages/cli/vendor/src/components/ui/dialog/index.tsx +2 -1
  289. package/packages/cli/vendor/src/components/ui/hover-card.tsx +54 -28
  290. package/packages/cli/vendor/src/components/ui/popover/index.tsx +10 -8
  291. package/packages/cli/vendor/src/components/ui/radio-group/index.tsx +55 -6
  292. package/packages/cli/vendor/src/components/ui/right-click-menu/index.tsx +120 -9
  293. package/packages/cli/vendor/src/components/ui/segmented-control/index.tsx +29 -3
  294. package/packages/cli/vendor/src/components/ui/select/index.tsx +64 -31
  295. package/packages/cli/vendor/src/components/ui/switch/index.tsx +71 -6
  296. package/packages/cli/vendor/src/components/ui/tabs/index.tsx +22 -6
  297. package/packages/cli/vendor/src/components/ui/textarea/index.tsx +105 -15
  298. package/packages/cli/vendor/src/components/ui/textarea.tsx +2 -0
  299. package/packages/cli/vendor/src/components/ui/tooltip/index.tsx +67 -22
  300. package/packages/cli/vendor/src/components/upload/file-upload.tsx +120 -57
  301. package/packages/cli/vendor/src/components/upload/image-upload.tsx +71 -24
  302. package/packages/cli/vendor/src/public-component-surface.ts +3 -0
  303. package/packages/cli/vendor/src/showcase/component-api-schema.ts +79 -41
  304. package/packages/cli/vendor/src/showcase/fallback.tsx +4 -19
  305. package/packages/cli/vendor/src/showcase/premium/alert/showcase.tsx +1 -0
  306. package/packages/cli/vendor/src/showcase/premium/app-sidebar/showcase.tsx +1 -0
  307. package/packages/cli/vendor/src/showcase/premium/badge/showcase.tsx +4 -2
  308. package/packages/cli/vendor/src/showcase/premium/badge/types.ts +1 -1
  309. package/packages/cli/vendor/src/showcase/premium/breadcrumbs/showcase.tsx +3 -1
  310. package/packages/cli/vendor/src/showcase/premium/button/mock.ts +2 -5
  311. package/packages/cli/vendor/src/showcase/premium/button/showcase.tsx +2 -2
  312. package/packages/cli/vendor/src/showcase/premium/card/showcase.tsx +26 -1
  313. package/packages/cli/vendor/src/showcase/premium/carousel/showcase.tsx +19 -3
  314. package/packages/cli/vendor/src/showcase/premium/command-bar/showcase.tsx +1 -1
  315. package/packages/cli/vendor/src/showcase/premium/data-table/mock.ts +26 -25
  316. package/packages/cli/vendor/src/showcase/premium/file-upload/showcase.tsx +21 -1
  317. package/packages/cli/vendor/src/showcase/premium/image-upload/showcase.tsx +4 -1
  318. package/packages/cli/vendor/src/showcase/premium/index.ts +0 -2
  319. package/packages/cli/vendor/src/showcase/premium/loading-state/showcase.tsx +1 -1
  320. package/packages/cli/vendor/src/showcase/premium/metric-grid/showcase.tsx +36 -4
  321. package/packages/cli/vendor/src/showcase/premium/notification-center/showcase.tsx +4 -3
  322. package/packages/cli/vendor/src/showcase/premium/page-state/showcase.tsx +1 -0
  323. package/packages/cli/vendor/src/showcase/premium/pagination/showcase.tsx +13 -1
  324. package/packages/cli/vendor/src/showcase/premium/popover/showcase.tsx +27 -11
  325. package/packages/cli/vendor/src/showcase/premium/radio-group/showcase.tsx +13 -1
  326. package/packages/cli/vendor/src/showcase/premium/right-click-menu/showcase.tsx +8 -5
  327. package/packages/cli/vendor/src/showcase/premium/segmented-control/showcase.tsx +1 -0
  328. package/packages/cli/vendor/src/showcase/premium/select/data.ts +12 -3
  329. package/packages/cli/vendor/src/showcase/premium/select/mock.ts +4 -4
  330. package/packages/cli/vendor/src/showcase/premium/select/showcase.tsx +22 -1
  331. package/packages/cli/vendor/src/showcase/premium/select/types.ts +3 -0
  332. package/packages/cli/vendor/src/showcase/premium/statistic/showcase.tsx +10 -1
  333. package/packages/cli/vendor/src/showcase/premium/switch/showcase.tsx +15 -6
  334. package/packages/cli/vendor/src/showcase/premium/tabs/showcase.tsx +48 -1
  335. package/packages/cli/vendor/src/showcase/premium/textarea/mock.ts +12 -4
  336. package/packages/cli/vendor/src/showcase/premium/textarea/showcase.tsx +5 -0
  337. package/packages/cli/vendor/src/showcase/premium/toast/showcase.tsx +17 -1
  338. package/packages/cli/vendor/src/showcase/premium/types.ts +1 -1
  339. package/packages/cli/vendor/src/showcase/registry-quality.ts +3 -2
  340. package/packages/cli/vendor/src/showcase/render-registry-preview.tsx +0 -15
  341. package/packages/cli/vendor/src/showcase/site-data.tsx +21 -15
  342. package/packages/cli/vendor/src/showcase/tembro-registry.json +42 -20
  343. package/packages/cli/vendor/src/showcase/types.ts +1 -1
  344. package/registry.json +18 -6
@@ -4,51 +4,162 @@ import { cn } from "@/lib/utils"
4
4
 
5
5
  export type RightClickMenuItem = {
6
6
  label: React.ReactNode
7
+ icon?: React.ReactNode
8
+ shortcut?: React.ReactNode
7
9
  onSelect?: () => void
8
10
  disabled?: boolean
11
+ variant?: "default" | "destructive"
9
12
  }
10
13
 
11
14
  export type RightClickMenuProps = React.ComponentProps<"div"> & {
12
15
  items: RightClickMenuItem[]
16
+ label?: string
13
17
  }
14
18
 
15
- function RightClickMenu({ items, children, className, ...props }: RightClickMenuProps) {
19
+ function getClampedPoint(x: number, y: number, width = 224, height: number) {
20
+ if (typeof window === "undefined") {
21
+ return { x, y }
22
+ }
23
+
24
+ const padding = 8
25
+ return {
26
+ x: Math.min(Math.max(padding, x), Math.max(padding, window.innerWidth - width - padding)),
27
+ y: Math.min(Math.max(padding, y), Math.max(padding, window.innerHeight - height - padding)),
28
+ }
29
+ }
30
+
31
+ function RightClickMenu({
32
+ items,
33
+ children,
34
+ className,
35
+ label = "Context menu",
36
+ ...props
37
+ }: RightClickMenuProps) {
16
38
  const [open, setOpen] = React.useState(false)
17
39
  const [point, setPoint] = React.useState({ x: 0, y: 0 })
40
+ const [activeIndex, setActiveIndex] = React.useState(0)
41
+ const rootRef = React.useRef<HTMLDivElement>(null)
42
+ const itemRefs = React.useRef<Array<HTMLButtonElement | null>>([])
43
+ const enabledItems = React.useMemo(
44
+ () => items.map((item, index) => ({ item, index })).filter(({ item }) => !item.disabled),
45
+ [items]
46
+ )
47
+
48
+ const openAt = React.useCallback(
49
+ (x: number, y: number) => {
50
+ const nextPoint = getClampedPoint(x, y, 224, Math.max(44, items.length * 42 + 12))
51
+ setPoint(nextPoint)
52
+ setActiveIndex(enabledItems[0]?.index ?? 0)
53
+ setOpen(true)
54
+ },
55
+ [enabledItems, items.length]
56
+ )
18
57
 
19
58
  React.useEffect(() => {
20
59
  if (!open) return
21
60
  const close = () => setOpen(false)
22
- window.addEventListener("click", close)
23
- return () => window.removeEventListener("click", close)
61
+ const onKeyDown = (event: KeyboardEvent) => {
62
+ if (event.key === "Escape") {
63
+ setOpen(false)
64
+ }
65
+ }
66
+
67
+ window.addEventListener("pointerdown", close)
68
+ window.addEventListener("resize", close)
69
+ window.addEventListener("scroll", close, true)
70
+ window.addEventListener("keydown", onKeyDown)
71
+ return () => {
72
+ window.removeEventListener("pointerdown", close)
73
+ window.removeEventListener("resize", close)
74
+ window.removeEventListener("scroll", close, true)
75
+ window.removeEventListener("keydown", onKeyDown)
76
+ }
24
77
  }, [open])
25
78
 
79
+ React.useEffect(() => {
80
+ if (!open) return
81
+ itemRefs.current[activeIndex]?.focus()
82
+ }, [activeIndex, open])
83
+
84
+ const focusNext = (direction: 1 | -1) => {
85
+ if (enabledItems.length === 0) return
86
+ const currentEnabledIndex = enabledItems.findIndex(({ index }) => index === activeIndex)
87
+ const nextEnabled =
88
+ enabledItems[(currentEnabledIndex + direction + enabledItems.length) % enabledItems.length]
89
+ setActiveIndex(nextEnabled.index)
90
+ }
91
+
26
92
  return (
27
93
  <div
28
94
  data-slot="right-click-menu"
29
- className={cn("contents", className)}
95
+ ref={rootRef}
96
+ tabIndex={0}
97
+ className={cn("contents focus:outline-none", className)}
30
98
  onContextMenu={(event) => {
31
99
  event.preventDefault()
32
- setPoint({ x: event.clientX, y: event.clientY })
33
- setOpen(true)
100
+ openAt(event.clientX, event.clientY)
101
+ }}
102
+ onKeyDown={(event) => {
103
+ if (event.key === "ContextMenu" || (event.shiftKey && event.key === "F10")) {
104
+ event.preventDefault()
105
+ const rect = rootRef.current?.getBoundingClientRect()
106
+ openAt(rect ? rect.left + 12 : 12, rect ? rect.top + 12 : 12)
107
+ }
34
108
  }}
35
109
  {...props}
36
110
  >
37
111
  {children}
38
112
  {open ? (
39
- <div className="fixed z-50 min-w-40 rounded-xl border border-border bg-popover p-1.5 text-sm text-popover-foreground shadow-xl" style={{ left: point.x, top: point.y }}>
113
+ <div
114
+ data-slot="right-click-menu-content"
115
+ role="menu"
116
+ aria-label={label}
117
+ className="fixed z-50 min-w-56 max-w-[calc(100vw-1rem)] 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-1.5 text-sm text-popover-foreground shadow-[var(--aui-popover-shadow,0_18px_42px_rgba(15,23,42,0.16))] outline-none"
118
+ style={{ left: point.x, top: point.y }}
119
+ onPointerDown={(event) => event.stopPropagation()}
120
+ onKeyDown={(event) => {
121
+ if (event.key === "ArrowDown") {
122
+ event.preventDefault()
123
+ focusNext(1)
124
+ }
125
+ if (event.key === "ArrowUp") {
126
+ event.preventDefault()
127
+ focusNext(-1)
128
+ }
129
+ if (event.key === "Home") {
130
+ event.preventDefault()
131
+ setActiveIndex(enabledItems[0]?.index ?? activeIndex)
132
+ }
133
+ if (event.key === "End") {
134
+ event.preventDefault()
135
+ setActiveIndex(enabledItems.at(-1)?.index ?? activeIndex)
136
+ }
137
+ }}
138
+ >
40
139
  {items.map((item, index) => (
41
140
  <button
42
141
  key={index}
142
+ ref={(node) => {
143
+ itemRefs.current[index] = node
144
+ }}
43
145
  type="button"
146
+ role="menuitem"
44
147
  disabled={item.disabled}
45
- className="block w-full rounded-lg px-3 py-2 text-left hover:bg-accent disabled:pointer-events-none disabled:opacity-50"
148
+ data-variant={item.variant ?? "default"}
149
+ className="group flex min-h-9 w-full items-center gap-2 rounded-[var(--radius-md)] px-2.5 py-2 text-left text-popover-foreground outline-none transition-[background-color,color] hover:bg-accent focus-visible:bg-accent data-[variant=destructive]:text-destructive data-[variant=destructive]:hover:bg-[color:color-mix(in_oklch,var(--destructive),transparent_90%)] data-[variant=destructive]:focus-visible:bg-[color:color-mix(in_oklch,var(--destructive),transparent_90%)] disabled:pointer-events-none disabled:opacity-50 [&_svg]:size-4 [&_svg]:shrink-0"
46
150
  onClick={() => {
151
+ if (item.disabled) return
47
152
  item.onSelect?.()
48
153
  setOpen(false)
49
154
  }}
50
155
  >
51
- {item.label}
156
+ {item.icon}
157
+ <span className="min-w-0 flex-1 truncate">{item.label}</span>
158
+ {item.shortcut ? (
159
+ <span className="ml-3 text-[11px] font-medium tracking-[0.08em] text-muted-foreground group-hover:text-foreground group-focus-visible:text-foreground">
160
+ {item.shortcut}
161
+ </span>
162
+ ) : null}
52
163
  </button>
53
164
  ))}
54
165
  </div>
@@ -16,6 +16,7 @@ export type SegmentedControlProps<TValue extends string = string> = Omit<React.C
16
16
  options: SegmentedControlOption<TValue>[]
17
17
  size?: "sm" | "md" | "lg"
18
18
  fullWidth?: boolean
19
+ equalWidth?: boolean
19
20
  }
20
21
 
21
22
  const sizeClassName = {
@@ -31,17 +32,28 @@ function SegmentedControl<TValue extends string = string>({
31
32
  options,
32
33
  size = "md",
33
34
  fullWidth = false,
35
+ equalWidth = false,
34
36
  className,
35
37
  ...props
36
38
  }: SegmentedControlProps<TValue>) {
37
39
  const [internalValue, setInternalValue] = React.useState<TValue | undefined>(defaultValue ?? options[0]?.value)
38
40
  const currentValue = value ?? internalValue
41
+ const buttonRefs = React.useRef<Array<HTMLButtonElement | null>>([])
39
42
 
40
43
  const selectValue = (nextValue: TValue) => {
41
44
  if (value === undefined) setInternalValue(nextValue)
42
45
  onValueChange?.(nextValue)
43
46
  }
44
47
 
48
+ const moveFocus = (fromIndex: number, direction: 1 | -1) => {
49
+ const enabledOptions = options
50
+ .map((option, index) => ({ option, index }))
51
+ .filter(({ option }) => !option.disabled)
52
+ const enabledIndex = enabledOptions.findIndex(({ index }) => index === fromIndex)
53
+ const next = enabledOptions[(enabledIndex + direction + enabledOptions.length) % enabledOptions.length]
54
+ buttonRefs.current[next?.index ?? fromIndex]?.focus()
55
+ }
56
+
45
57
  return (
46
58
  <div
47
59
  data-slot="segmented-control"
@@ -49,26 +61,40 @@ function SegmentedControl<TValue extends string = string>({
49
61
  className={cn(
50
62
  "inline-flex gap-1 rounded-[var(--radius-2xl)] border border-border/80 bg-muted/72 p-1 text-muted-foreground shadow-[inset_0_1px_0_rgba(255,255,255,0.06),0_10px_26px_rgba(15,23,42,0.05)] backdrop-blur",
51
63
  fullWidth && "flex w-full",
64
+ equalWidth && "grid auto-cols-fr grid-flow-col",
52
65
  className
53
66
  )}
54
67
  {...props}
55
68
  >
56
- {options.map((option) => {
69
+ {options.map((option, optionIndex) => {
57
70
  const selected = option.value === currentValue
58
71
  return (
59
72
  <button
60
73
  key={option.value}
74
+ ref={(node) => {
75
+ buttonRefs.current[optionIndex] = node
76
+ }}
61
77
  type="button"
62
78
  role="radio"
63
79
  aria-checked={selected}
64
80
  disabled={option.disabled}
65
81
  data-selected={selected || undefined}
66
82
  className={cn(
67
- "inline-flex items-center justify-center gap-1.5 rounded-[calc(var(--radius-xl)-2px)] border border-transparent font-medium text-muted-foreground outline-none transition-[background-color,color,border-color,box-shadow,transform] hover:bg-background/58 hover:text-foreground focus-visible:ring-2 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50 data-[selected=true]:-translate-y-px data-[selected=true]:border-border/85 data-[selected=true]:bg-background data-[selected=true]:text-foreground data-[selected=true]:shadow-[0_1px_0_rgba(255,255,255,0.24),0_12px_24px_rgba(15,23,42,0.12)]",
83
+ "inline-flex items-center justify-center gap-1.5 whitespace-nowrap rounded-[calc(var(--radius-xl)-2px)] border border-transparent font-medium text-muted-foreground outline-none transition-[background-color,color,border-color,box-shadow,transform] hover:bg-background/58 hover:text-foreground focus-visible:ring-2 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50 data-[selected=true]:-translate-y-px data-[selected=true]:border-border/85 data-[selected=true]:bg-background data-[selected=true]:text-foreground data-[selected=true]:shadow-[0_1px_0_rgba(255,255,255,0.24),0_12px_24px_rgba(15,23,42,0.12)] [&_svg]:size-4 [&_svg]:shrink-0",
68
84
  sizeClassName[size],
69
- fullWidth && "flex-1"
85
+ (fullWidth || equalWidth) && "w-full"
70
86
  )}
71
87
  onClick={() => selectValue(option.value)}
88
+ onKeyDown={(event) => {
89
+ if (event.key === "ArrowRight" || event.key === "ArrowDown") {
90
+ event.preventDefault()
91
+ moveFocus(optionIndex, 1)
92
+ }
93
+ if (event.key === "ArrowLeft" || event.key === "ArrowUp") {
94
+ event.preventDefault()
95
+ moveFocus(optionIndex, -1)
96
+ }
97
+ }}
72
98
  >
73
99
  {option.icon}
74
100
  {option.label}
@@ -29,14 +29,21 @@ export type SelectOption = {
29
29
  keywords?: string[]
30
30
  }
31
31
 
32
+ export type SelectOptionGroup = {
33
+ label?: React.ReactNode
34
+ options: SelectOption[]
35
+ }
36
+
32
37
  export type SelectProps = Omit<SelectRootProps, "value" | "defaultValue" | "onValueChange"> & {
33
38
  value?: string | null
34
39
  defaultValue?: string | null
35
40
  onValueChange?: (value: string | undefined) => void
36
41
  options?: SelectOption[]
42
+ groups?: SelectOptionGroup[]
37
43
  placeholder?: string
38
44
  searchPlaceholder?: string
39
45
  emptyLabel?: React.ReactNode
46
+ emptyMessage?: React.ReactNode
40
47
  clearLabel?: string
41
48
  size?: "sm" | "default" | "lg"
42
49
  clearable?: boolean
@@ -51,6 +58,7 @@ export type SelectProps = Omit<SelectRootProps, "value" | "defaultValue" | "onVa
51
58
  searchClassName?: string
52
59
  renderOption?: (option: SelectOption, state: { selected: boolean }) => React.ReactNode
53
60
  invalid?: boolean
61
+ onSearchChange?: (value: string) => void
54
62
  }
55
63
 
56
64
  const SelectRoot = SelectPrimitive.Root
@@ -72,9 +80,11 @@ function Select({
72
80
  defaultValue,
73
81
  onValueChange,
74
82
  options,
83
+ groups,
75
84
  placeholder = "Select",
76
85
  searchPlaceholder = "Search options...",
77
86
  emptyLabel = "No options found",
87
+ emptyMessage,
78
88
  clearLabel = "Clear selection",
79
89
  size = "default",
80
90
  clearable = false,
@@ -91,9 +101,10 @@ function Select({
91
101
  invalid,
92
102
  children,
93
103
  onOpenChange,
104
+ onSearchChange,
94
105
  ...props
95
106
  }: SelectProps) {
96
- if (!options) {
107
+ if (!options && !groups) {
97
108
  return (
98
109
  <SelectRoot
99
110
  value={value ?? undefined}
@@ -109,8 +120,22 @@ function Select({
109
120
  }
110
121
 
111
122
  const [search, setSearch] = React.useState("")
112
- const selectedOption = options.find((option) => option.value === value)
113
- const filteredOptions = options.filter((option) => optionMatchesSearch(option, search))
123
+ const optionGroups = React.useMemo<SelectOptionGroup[]>(
124
+ () => groups ?? [{ options: options ?? [] }],
125
+ [groups, options]
126
+ )
127
+ const flatOptions = React.useMemo(
128
+ () => optionGroups.flatMap((group) => group.options),
129
+ [optionGroups]
130
+ )
131
+ const selectedOption = flatOptions.find((option) => option.value === value)
132
+ const filteredGroups = optionGroups
133
+ .map((group) => ({
134
+ ...group,
135
+ options: group.options.filter((option) => optionMatchesSearch(option, search)),
136
+ }))
137
+ .filter((group) => group.options.length > 0)
138
+ const filteredOptionsCount = filteredGroups.reduce((count, group) => count + group.options.length, 0)
114
139
 
115
140
  return (
116
141
  <SelectRoot
@@ -175,7 +200,10 @@ function Select({
175
200
  <SearchIcon className="size-4 text-muted-foreground" />
176
201
  <input
177
202
  value={search}
178
- onChange={(event) => setSearch(event.target.value)}
203
+ onChange={(event) => {
204
+ setSearch(event.target.value)
205
+ onSearchChange?.(event.target.value)
206
+ }}
179
207
  placeholder={searchPlaceholder}
180
208
  className={cn(
181
209
  "min-w-0 flex-1 bg-transparent outline-none placeholder:text-muted-foreground",
@@ -193,39 +221,44 @@ function Select({
193
221
  <LoaderCircleIcon className="size-4 animate-spin" />
194
222
  {loadingLabel}
195
223
  </div>
196
- ) : filteredOptions.length === 0 ? (
224
+ ) : filteredOptionsCount === 0 ? (
197
225
  <div
198
226
  data-slot="select-state"
199
227
  className="rounded-[var(--radius-md)] border border-[color:var(--aui-card-border,var(--border))] bg-[color:color-mix(in_oklch,var(--muted),transparent_55%)] px-3 py-2.5 text-sm text-muted-foreground"
200
228
  >
201
- {emptyLabel}
229
+ {emptyMessage ?? emptyLabel}
202
230
  </div>
203
231
  ) : (
204
- filteredOptions.map((option) => {
205
- const selected = option.value === value
206
- return (
207
- <SelectItem
208
- key={option.value}
209
- value={option.value}
210
- disabled={option.disabled}
211
- className={cn("rounded-[var(--radius-md)]", itemClassName)}
212
- >
213
- {renderOption ? (
214
- renderOption(option, { selected })
215
- ) : (
216
- <span className="flex min-w-0 flex-1 flex-col">
217
- <span className="flex min-w-0 items-center gap-2">
218
- <span className="truncate">{option.label}</span>
219
- {selected ? <CheckIcon className="ml-auto size-3.5 text-primary" /> : null}
220
- </span>
221
- {option.description ? (
222
- <span className="truncate text-xs text-muted-foreground">{option.description}</span>
223
- ) : null}
224
- </span>
225
- )}
226
- </SelectItem>
227
- )
228
- })
232
+ filteredGroups.map((group, groupIndex) => (
233
+ <SelectGroup key={groupIndex}>
234
+ {group.label ? <SelectLabel>{group.label}</SelectLabel> : null}
235
+ {group.options.map((option) => {
236
+ const selected = option.value === value
237
+ return (
238
+ <SelectItem
239
+ key={option.value}
240
+ value={option.value}
241
+ disabled={option.disabled}
242
+ className={cn("rounded-[var(--radius-md)]", itemClassName)}
243
+ >
244
+ {renderOption ? (
245
+ renderOption(option, { selected })
246
+ ) : (
247
+ <span className="flex min-w-0 flex-1 flex-col">
248
+ <span className="flex min-w-0 items-center gap-2">
249
+ <span className="truncate">{option.label}</span>
250
+ {selected ? <CheckIcon className="ml-auto size-3.5 text-primary" /> : null}
251
+ </span>
252
+ {option.description ? (
253
+ <span className="truncate text-xs text-muted-foreground">{option.description}</span>
254
+ ) : null}
255
+ </span>
256
+ )}
257
+ </SelectItem>
258
+ )
259
+ })}
260
+ </SelectGroup>
261
+ ))
229
262
  )}
230
263
  </SelectContent>
231
264
  </SelectRoot>
@@ -1,4 +1,5 @@
1
1
  import * as React from "react"
2
+ import { Loader2Icon } from "lucide-react"
2
3
 
3
4
  import { cn } from "@/lib/utils"
4
5
 
@@ -9,8 +10,29 @@ export type SwitchProps = Omit<
9
10
  checked?: boolean
10
11
  defaultChecked?: boolean
11
12
  onCheckedChange?: (checked: boolean) => void
13
+ size?: "sm" | "md" | "lg"
14
+ loading?: boolean
15
+ invalid?: boolean
16
+ label?: React.ReactNode
17
+ description?: React.ReactNode
18
+ labelPlacement?: "start" | "end" | "top" | "bottom"
19
+ switchClassName?: string
20
+ labelClassName?: string
21
+ descriptionClassName?: string
12
22
  }
13
23
 
24
+ const switchSizeClassName = {
25
+ sm: "h-5 w-9",
26
+ md: "h-6.5 w-11.5",
27
+ lg: "h-8 w-14",
28
+ } satisfies Record<NonNullable<SwitchProps["size"]>, string>
29
+
30
+ const thumbSizeClassName = {
31
+ sm: "size-4 data-[state=checked]:translate-x-4.5 data-[state=unchecked]:translate-x-0.5",
32
+ md: "size-5 data-[state=checked]:translate-x-5.5 data-[state=unchecked]:translate-x-0.5",
33
+ lg: "size-6 data-[state=checked]:translate-x-7 data-[state=unchecked]:translate-x-1",
34
+ } satisfies Record<NonNullable<SwitchProps["size"]>, string>
35
+
14
36
  const Switch = React.forwardRef<HTMLButtonElement, SwitchProps>(
15
37
  (
16
38
  {
@@ -18,6 +40,15 @@ const Switch = React.forwardRef<HTMLButtonElement, SwitchProps>(
18
40
  checked,
19
41
  defaultChecked = false,
20
42
  onCheckedChange,
43
+ size = "md",
44
+ loading = false,
45
+ invalid = false,
46
+ label,
47
+ description,
48
+ labelPlacement = "end",
49
+ switchClassName,
50
+ labelClassName,
51
+ descriptionClassName,
21
52
  disabled,
22
53
  onClick,
23
54
  ...props
@@ -27,8 +58,10 @@ const Switch = React.forwardRef<HTMLButtonElement, SwitchProps>(
27
58
  const isControlled = checked !== undefined
28
59
  const [internalChecked, setInternalChecked] = React.useState(defaultChecked)
29
60
  const currentChecked = isControlled ? checked : internalChecked
61
+ const isDisabled = disabled || loading
30
62
 
31
63
  const handleClick: React.MouseEventHandler<HTMLButtonElement> = (event) => {
64
+ if (isDisabled) return
32
65
  const nextChecked = !currentChecked
33
66
 
34
67
  if (!isControlled) {
@@ -39,18 +72,23 @@ const Switch = React.forwardRef<HTMLButtonElement, SwitchProps>(
39
72
  onClick?.(event)
40
73
  }
41
74
 
42
- return (
75
+ const control = (
43
76
  <button
44
77
  ref={ref}
45
78
  type="button"
46
79
  role="switch"
47
80
  aria-checked={currentChecked}
81
+ aria-invalid={invalid || undefined}
82
+ aria-busy={loading || undefined}
48
83
  data-state={currentChecked ? "checked" : "unchecked"}
84
+ data-size={size}
49
85
  data-slot="switch"
50
- disabled={disabled}
86
+ disabled={isDisabled}
51
87
  className={cn(
52
- "peer inline-flex h-6.5 w-11.5 shrink-0 cursor-pointer items-center rounded-full border border-border/78 bg-input/70 shadow-[inset_0_1px_0_rgba(255,255,255,0.08)] transition-[background-color,border-color,box-shadow] outline-none hover:border-ring/30 focus-visible:border-ring focus-visible:ring-3 focus-visible:ring-ring/45 disabled:cursor-not-allowed disabled:opacity-50 data-[state=checked]:border-primary/22 data-[state=checked]:bg-primary data-[state=checked]:shadow-[0_10px_22px_color-mix(in_oklch,var(--primary),transparent_82%)] dark:border-white/10 dark:bg-white/[0.08]",
53
- className
88
+ "peer inline-flex shrink-0 cursor-pointer items-center rounded-full border border-border/78 bg-input/70 shadow-[inset_0_1px_0_rgba(255,255,255,0.08)] transition-[background-color,border-color,box-shadow] outline-none hover:border-ring/30 focus-visible:border-ring focus-visible:ring-3 focus-visible:ring-ring/45 disabled:cursor-not-allowed disabled:opacity-50 aria-invalid:border-destructive aria-invalid:ring-3 aria-invalid:ring-destructive/20 data-[state=checked]:border-primary/22 data-[state=checked]:bg-primary data-[state=checked]:shadow-[0_10px_22px_color-mix(in_oklch,var(--primary),transparent_82%)] dark:border-white/10 dark:bg-white/[0.08]",
89
+ switchSizeClassName[size],
90
+ switchClassName,
91
+ !label && className
54
92
  )}
55
93
  onClick={handleClick}
56
94
  {...props}
@@ -59,11 +97,38 @@ const Switch = React.forwardRef<HTMLButtonElement, SwitchProps>(
59
97
  data-slot="switch-thumb"
60
98
  data-state={currentChecked ? "checked" : "unchecked"}
61
99
  className={cn(
62
- "pointer-events-none block size-5 rounded-full bg-white shadow-[0_2px_10px_color-mix(in_oklch,var(--foreground),transparent_88%)] ring-1 ring-foreground/6 transition-transform data-[state=checked]:translate-x-5.5 data-[state=unchecked]:translate-x-0.5 dark:bg-[rgba(255,255,255,0.96)]"
100
+ "pointer-events-none flex items-center justify-center rounded-full bg-white shadow-[0_2px_10px_color-mix(in_oklch,var(--foreground),transparent_88%)] ring-1 ring-foreground/6 transition-transform dark:bg-[rgba(255,255,255,0.96)]",
101
+ thumbSizeClassName[size]
63
102
  )}
64
- />
103
+ >
104
+ {loading ? <Loader2Icon className="size-3 animate-spin text-muted-foreground" /> : null}
105
+ </span>
65
106
  </button>
66
107
  )
108
+
109
+ if (!label && !description) return control
110
+
111
+ const labelBlock = (
112
+ <span className="grid min-w-0 gap-0.5">
113
+ {label ? <span className={cn("text-sm font-medium leading-5 text-foreground", labelClassName)}>{label}</span> : null}
114
+ {description ? <span className={cn("text-xs leading-5 text-muted-foreground", descriptionClassName)}>{description}</span> : null}
115
+ </span>
116
+ )
117
+
118
+ return (
119
+ <label
120
+ data-slot="switch-field"
121
+ data-label-placement={labelPlacement}
122
+ className={cn(
123
+ "inline-flex min-w-0 gap-3",
124
+ labelPlacement === "top" || labelPlacement === "bottom" ? "flex-col" : "items-start",
125
+ labelPlacement === "start" && "flex-row-reverse justify-end",
126
+ className
127
+ )}
128
+ >
129
+ {labelPlacement === "bottom" ? <>{control}{labelBlock}</> : <>{labelBlock}{control}</>}
130
+ </label>
131
+ )
67
132
  }
68
133
  )
69
134
  Switch.displayName = "Switch"
@@ -4,8 +4,13 @@ import { Tabs as BaseTabs } from "@base-ui/react/tabs"
4
4
  import { cn } from "@/lib/utils"
5
5
 
6
6
  export type TabsRootProps = React.ComponentPropsWithoutRef<typeof BaseTabs.Root>
7
- export type TabsListProps = React.ComponentPropsWithoutRef<typeof BaseTabs.List>
8
- export type TabsTriggerProps = React.ComponentPropsWithoutRef<typeof BaseTabs.Tab>
7
+ export type TabsListProps = React.ComponentPropsWithoutRef<typeof BaseTabs.List> & {
8
+ variant?: "default" | "pills" | "underline" | "compact"
9
+ overflow?: "wrap" | "scroll"
10
+ }
11
+ export type TabsTriggerProps = React.ComponentPropsWithoutRef<typeof BaseTabs.Tab> & {
12
+ variant?: "default" | "pills" | "underline" | "compact"
13
+ }
9
14
  export type TabsContentProps = React.ComponentPropsWithoutRef<typeof BaseTabs.Panel>
10
15
 
11
16
  const Tabs = BaseTabs.Root
@@ -13,12 +18,19 @@ const Tabs = BaseTabs.Root
13
18
  const TabsList = React.forwardRef<
14
19
  React.ElementRef<typeof BaseTabs.List>,
15
20
  TabsListProps
16
- >(({ className, ...props }, ref) => (
21
+ >(({ className, variant = "default", overflow = "scroll", ...props }, ref) => (
17
22
  <BaseTabs.List
18
23
  ref={ref}
19
24
  data-slot="tabs-list"
25
+ data-variant={variant}
26
+ data-overflow={overflow}
20
27
  className={cn(
21
- "inline-flex min-h-11 items-center justify-center gap-1 rounded-[var(--aui-card-radius,var(--radius-xl))] border border-[color:color-mix(in_oklch,var(--border),white_4%)] bg-[color:var(--aui-control-panel-bg,var(--muted))] p-1 text-muted-foreground shadow-[var(--aui-control-panel-shadow,var(--aui-control-shadow,none))] backdrop-blur",
28
+ "inline-flex max-w-full min-h-11 items-center justify-start gap-1 rounded-[var(--aui-card-radius,var(--radius-xl))] border border-[color:color-mix(in_oklch,var(--border),white_4%)] bg-[color:var(--aui-control-panel-bg,var(--muted))] p-1 text-muted-foreground shadow-[var(--aui-control-panel-shadow,var(--aui-control-shadow,none))] backdrop-blur",
29
+ overflow === "scroll" && "overflow-x-auto overflow-y-hidden overscroll-x-contain [-ms-overflow-style:none] [scrollbar-width:none] [&::-webkit-scrollbar]:hidden",
30
+ overflow === "wrap" && "flex-wrap",
31
+ variant === "underline" && "min-h-10 rounded-none border-x-0 border-t-0 bg-transparent p-0 shadow-none",
32
+ variant === "compact" && "min-h-9 rounded-[var(--radius-lg)] p-0.5",
33
+ variant === "pills" && "rounded-full",
22
34
  className
23
35
  )}
24
36
  {...props}
@@ -29,12 +41,16 @@ TabsList.displayName = "TabsList"
29
41
  const TabsTrigger = React.forwardRef<
30
42
  React.ElementRef<typeof BaseTabs.Tab>,
31
43
  TabsTriggerProps
32
- >(({ className, ...props }, ref) => (
44
+ >(({ className, variant = "default", ...props }, ref) => (
33
45
  <BaseTabs.Tab
34
46
  ref={ref}
35
47
  data-slot="tabs-trigger"
48
+ data-variant={variant}
36
49
  className={cn(
37
- "inline-flex min-h-9 items-center justify-center whitespace-nowrap rounded-[var(--radius-md)] border border-transparent px-3.5 py-1.5 text-sm font-medium text-muted-foreground ring-offset-background transition-[background-color,color,box-shadow,border-color] hover:bg-[color:color-mix(in_oklch,var(--background),transparent_18%)] hover:text-foreground data-[selected]:border-[color:color-mix(in_oklch,var(--border),var(--foreground)_8%)] data-[selected]:bg-[color:var(--aui-control-surface,var(--background))] data-[selected]:text-foreground data-[selected]:shadow-[var(--aui-control-shadow,none)] aria-selected:border-[color:color-mix(in_oklch,var(--border),var(--foreground)_8%)] aria-selected:bg-[color:var(--aui-control-surface,var(--background))] aria-selected:text-foreground aria-selected:shadow-[var(--aui-control-shadow,none)] focus-visible:outline-none focus-visible:ring-0 focus-visible:shadow-[var(--aui-control-shadow,none),0_0_0_1px_var(--aui-focus-ring,var(--ring)),0_0_0_5px_var(--aui-focus-ring-soft,transparent)] disabled:pointer-events-none disabled:opacity-50",
50
+ "inline-flex min-h-9 shrink-0 items-center justify-center gap-2 whitespace-nowrap rounded-[var(--radius-md)] border border-transparent px-3.5 py-1.5 text-sm font-medium text-muted-foreground ring-offset-background transition-[background-color,color,box-shadow,border-color] hover:bg-[color:color-mix(in_oklch,var(--background),transparent_18%)] hover:text-foreground data-[selected]:border-[color:color-mix(in_oklch,var(--border),var(--foreground)_8%)] data-[selected]:bg-[color:var(--aui-control-surface,var(--background))] data-[selected]:text-foreground data-[selected]:shadow-[var(--aui-control-shadow,none)] aria-selected:border-[color:color-mix(in_oklch,var(--border),var(--foreground)_8%)] aria-selected:bg-[color:var(--aui-control-surface,var(--background))] aria-selected:text-foreground aria-selected:shadow-[var(--aui-control-shadow,none)] focus-visible:outline-none focus-visible:ring-0 focus-visible:shadow-[var(--aui-control-shadow,none),0_0_0_1px_var(--aui-focus-ring,var(--ring)),0_0_0_5px_var(--aui-focus-ring-soft,transparent)] disabled:pointer-events-none disabled:opacity-50 [&_svg]:size-4 [&_svg]:shrink-0",
51
+ variant === "underline" && "min-h-10 rounded-none border-b-2 px-2 shadow-none data-[selected]:border-b-primary data-[selected]:bg-transparent data-[selected]:shadow-none aria-selected:border-b-primary aria-selected:bg-transparent aria-selected:shadow-none",
52
+ variant === "pills" && "rounded-full",
53
+ variant === "compact" && "min-h-8 px-2.5 text-xs",
38
54
  className
39
55
  )}
40
56
  {...props}