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
@@ -87,7 +87,7 @@ function DataTableToolbar({
87
87
  </div>
88
88
  )}
89
89
 
90
- {actions && <div className={cn("flex min-w-0 shrink-0 flex-wrap items-center gap-2 xl:justify-end", actionsClassName)}>{actions}</div>}
90
+ {actions && <div className={cn("flex w-full min-w-0 flex-wrap items-center gap-2 sm:w-auto xl:shrink-0 xl:justify-end", actionsClassName)}>{actions}</div>}
91
91
  </div>
92
92
  )}
93
93
 
@@ -95,10 +95,12 @@ function DataTableToolbar({
95
95
  <div className="flex flex-col gap-3 xl:flex-row xl:items-start xl:justify-between">
96
96
  <div className="flex min-w-0 flex-1 flex-col gap-3">
97
97
  {hasMainControls && (
98
- <div className="flex min-w-0 flex-1 flex-col gap-2 lg:flex-row lg:flex-wrap lg:items-center">
99
- {search ? <div className={cn("min-w-[16rem] max-w-xl flex-1", searchClassName)}>{search}</div> : null}
100
- {filters ? <div className={cn("flex min-w-0 flex-1 flex-wrap items-center gap-2", filtersClassName)}>{filters}</div> : null}
101
- {children}
98
+ <div className="grid min-w-0 flex-1 gap-2 lg:grid-cols-[minmax(14rem,24rem)_minmax(0,1fr)] lg:items-start">
99
+ {search ? <div className={cn("min-w-0 max-w-full", searchClassName)}>{search}</div> : null}
100
+ <div className="flex min-w-0 flex-wrap items-center gap-2">
101
+ {filters ? <div className={cn("flex min-w-0 flex-1 flex-wrap items-center gap-2 [&>*]:min-w-0", filtersClassName)}>{filters}</div> : null}
102
+ {children}
103
+ </div>
102
104
  </div>
103
105
  )}
104
106
  {summary ? (
@@ -112,7 +114,7 @@ function DataTableToolbar({
112
114
  </div>
113
115
 
114
116
  {hasSelection && (
115
- <div data-slot="data-table-selection-bar" className="flex shrink-0 flex-wrap items-center gap-2 rounded-[var(--radius-md)] border border-[color:var(--aui-control-border-strong,var(--border))] bg-[color:var(--aui-control-surface,var(--background))] px-2.5 py-1.5 text-sm shadow-[var(--aui-control-shadow,none)] backdrop-blur">
117
+ <div data-slot="data-table-selection-bar" className="flex w-full shrink-0 flex-wrap items-center gap-2 rounded-[var(--radius-md)] border border-[color:var(--aui-control-border-strong,var(--border))] bg-[color:var(--aui-control-surface,var(--background))] px-2.5 py-1.5 text-sm shadow-[var(--aui-control-shadow,none)] backdrop-blur sm:w-auto">
116
118
  <span className="text-muted-foreground">{selectedLabel(selectedCount, totalCount)}</span>
117
119
  {selectionActions}
118
120
  </div>
@@ -22,8 +22,15 @@ export type CarouselProps = React.ComponentProps<"div"> & {
22
22
  pauseOnHover?: boolean
23
23
  stopAutoplayOnInteraction?: boolean
24
24
  showPlaybackControl?: boolean
25
+ showStatus?: boolean
26
+ showThumbnails?: boolean
25
27
  playLabel?: string
26
28
  pauseLabel?: string
29
+ statusLabel?: (index: number, total: number) => string
30
+ renderThumbnail?: (item: React.ReactNode, index: number, active: boolean) => React.ReactNode
31
+ renderActiveDetail?: (item: React.ReactNode, index: number) => React.ReactNode
32
+ aspectRatio?: string
33
+ mouseDrag?: boolean
27
34
  onAutoplayChange?: (playing: boolean) => void
28
35
  viewportClassName?: string
29
36
  controlsClassName?: string
@@ -31,6 +38,7 @@ export type CarouselProps = React.ComponentProps<"div"> & {
31
38
  arrowClassName?: string
32
39
  dotClassName?: string
33
40
  activeDotClassName?: string
41
+ thumbnailsClassName?: string
34
42
  }
35
43
 
36
44
  export type CarouselItemProps = React.ComponentProps<"div">
@@ -59,8 +67,15 @@ function Carousel({
59
67
  pauseOnHover = true,
60
68
  stopAutoplayOnInteraction = true,
61
69
  showPlaybackControl = false,
70
+ showStatus = false,
71
+ showThumbnails = false,
62
72
  playLabel = "Start autoplay",
63
73
  pauseLabel = "Pause autoplay",
74
+ statusLabel,
75
+ renderThumbnail,
76
+ renderActiveDetail,
77
+ aspectRatio,
78
+ mouseDrag = true,
64
79
  onAutoplayChange,
65
80
  viewportClassName,
66
81
  controlsClassName,
@@ -68,6 +83,7 @@ function Carousel({
68
83
  arrowClassName,
69
84
  dotClassName,
70
85
  activeDotClassName,
86
+ thumbnailsClassName,
71
87
  className,
72
88
  children,
73
89
  ...props
@@ -75,11 +91,13 @@ function Carousel({
75
91
  const items = React.Children.toArray(children)
76
92
  const [internalIndex, setInternalIndex] = React.useState(defaultIndex)
77
93
  const touchStartXRef = React.useRef<number | null>(null)
94
+ const pointerStartXRef = React.useRef<number | null>(null)
78
95
  const [isHovered, setIsHovered] = React.useState(false)
79
96
  const [autoplayStopped, setAutoplayStopped] = React.useState(false)
80
97
  const [autoplayEnabled, setAutoplayEnabled] = React.useState(autoplay)
81
98
  const controlled = index !== undefined
82
99
  const activeIndex = clampIndex(controlled ? index : internalIndex, items.length, loop)
100
+ const activeItem = items[activeIndex]
83
101
 
84
102
  React.useEffect(() => {
85
103
  setAutoplayEnabled(autoplay)
@@ -116,6 +134,21 @@ function Carousel({
116
134
  if (deltaX < 0 && canGoNext) setActiveIndex(activeIndex + 1)
117
135
  }
118
136
 
137
+ const handlePointerDown: React.PointerEventHandler<HTMLDivElement> = (event) => {
138
+ if (!mouseDrag || event.pointerType === "touch") return
139
+ pointerStartXRef.current = event.clientX
140
+ }
141
+
142
+ const handlePointerUp: React.PointerEventHandler<HTMLDivElement> = (event) => {
143
+ if (!mouseDrag || pointerStartXRef.current == null || items.length <= 1) return
144
+ const deltaX = event.clientX - pointerStartXRef.current
145
+ pointerStartXRef.current = null
146
+
147
+ if (Math.abs(deltaX) < swipeThreshold) return
148
+ if (deltaX > 0 && canGoPrevious) setActiveIndex(activeIndex - 1)
149
+ if (deltaX < 0 && canGoNext) setActiveIndex(activeIndex + 1)
150
+ }
151
+
119
152
  React.useEffect(() => {
120
153
  if (!autoplayEnabled || items.length <= 1 || autoplayStopped) return
121
154
  if (pauseOnHover && isHovered) return
@@ -152,9 +185,19 @@ function Carousel({
152
185
  event.preventDefault()
153
186
  setActiveIndex(activeIndex + 1)
154
187
  }
188
+ if (event.key === "Home") {
189
+ event.preventDefault()
190
+ setActiveIndex(0)
191
+ }
192
+ if (event.key === "End") {
193
+ event.preventDefault()
194
+ setActiveIndex(items.length - 1)
195
+ }
155
196
  }}
156
197
  onTouchStart={handleTouchStart}
157
198
  onTouchEnd={handleTouchEnd}
199
+ onPointerDown={handlePointerDown}
200
+ onPointerUp={handlePointerUp}
158
201
  onMouseEnter={() => setIsHovered(true)}
159
202
  onMouseLeave={() => setIsHovered(false)}
160
203
  {...props}
@@ -164,7 +207,16 @@ function Carousel({
164
207
  variant === "hero" && "min-h-72",
165
208
  variant === "minimal" && "rounded-[var(--radius-md)] shadow-none"
166
209
  , viewportClassName)}>
167
- <div className="transition-transform duration-300 ease-out" aria-live="polite">
210
+ {showStatus ? (
211
+ <div className="pointer-events-none absolute right-3 top-3 z-10 rounded-full border border-border/70 bg-background/92 px-2.5 py-1 text-[11px] font-medium text-muted-foreground shadow-sm">
212
+ {statusLabel?.(activeIndex, items.length) ?? `Slide ${activeIndex + 1} / ${items.length}`}
213
+ </div>
214
+ ) : null}
215
+ <div
216
+ className="transition-transform duration-300 ease-out"
217
+ aria-live="polite"
218
+ style={aspectRatio ? { aspectRatio } : undefined}
219
+ >
168
220
  {items[activeIndex]}
169
221
  </div>
170
222
  {showArrows && items.length > 1 ? (
@@ -228,9 +280,38 @@ function Carousel({
228
280
  ) : null}
229
281
  </div>
230
282
  )}
283
+ {showThumbnails && items.length > 1 ? (
284
+ <div className={cn("grid grid-cols-2 gap-2 sm:grid-cols-4", thumbnailsClassName)}>
285
+ {items.map((item, itemIndex) => {
286
+ const active = itemIndex === activeIndex
287
+
288
+ return (
289
+ <button
290
+ key={itemIndex}
291
+ type="button"
292
+ aria-current={active ? "true" : undefined}
293
+ aria-label={`Open slide ${itemIndex + 1}`}
294
+ className={cn(
295
+ "overflow-hidden rounded-[min(var(--radius-xl),16px)] border bg-card text-left transition hover:border-primary/35 hover:shadow-sm",
296
+ active ? "border-primary/35 ring-2 ring-primary/15" : "border-border/70"
297
+ )}
298
+ onClick={() => setActiveIndex(itemIndex)}
299
+ >
300
+ {renderThumbnail
301
+ ? renderThumbnail(item, itemIndex, active)
302
+ : <div className="line-clamp-2 min-h-16 p-3 text-xs text-muted-foreground">Slide {itemIndex + 1}</div>}
303
+ </button>
304
+ )
305
+ })}
306
+ </div>
307
+ ) : null}
308
+ {renderActiveDetail ? renderActiveDetail(activeItem, activeIndex) : null}
309
+ <span className="sr-only" aria-live="polite">
310
+ {statusLabel?.(activeIndex, items.length) ?? `${ariaLabel}: slide ${activeIndex + 1} of ${items.length}`}
311
+ </span>
231
312
  </div>
232
- )
233
- }
313
+ )
314
+ }
234
315
 
235
316
  function CarouselItem({ className, ...props }: CarouselItemProps) {
236
317
  return <div data-slot="carousel-item" className={cn("min-h-40 p-5 sm:p-6", className)} {...props} />
@@ -10,6 +10,7 @@ export type CodeBlockProps = React.ComponentProps<"div"> & {
10
10
  showCopy?: boolean
11
11
  wrap?: boolean
12
12
  lineNumbers?: boolean
13
+ highlightLines?: number[] | readonly number[]
13
14
  maxHeight?: number | string
14
15
  }
15
16
 
@@ -20,11 +21,13 @@ function CodeBlock({
20
21
  showCopy = true,
21
22
  wrap = false,
22
23
  lineNumbers = false,
24
+ highlightLines = [],
23
25
  maxHeight,
24
26
  className,
25
27
  ...props
26
28
  }: CodeBlockProps) {
27
29
  const lines = React.useMemo(() => code.split("\n"), [code])
30
+ const highlightedLineSet = React.useMemo(() => new Set(highlightLines), [highlightLines])
28
31
 
29
32
  return (
30
33
  <div
@@ -48,14 +51,31 @@ function CodeBlock({
48
51
  {lineNumbers ? (
49
52
  <code className="grid">
50
53
  {lines.map((line, index) => (
51
- <span key={`${index}-${line}`} className="grid grid-cols-[auto_1fr] gap-4">
54
+ <span
55
+ key={`${index}-${line}`}
56
+ data-highlighted={highlightedLineSet.has(index + 1) || undefined}
57
+ className={cn(
58
+ "grid grid-cols-[auto_1fr] gap-4 rounded px-1",
59
+ highlightedLineSet.has(index + 1) && "bg-primary/10 text-foreground"
60
+ )}
61
+ >
52
62
  <span className="select-none text-right text-xs text-muted-foreground/75">{index + 1}</span>
53
63
  <span>{line || " "}</span>
54
64
  </span>
55
65
  ))}
56
66
  </code>
57
67
  ) : (
58
- <code>{code}</code>
68
+ <code>
69
+ {lines.map((line, index) => (
70
+ <span
71
+ key={`${index}-${line}`}
72
+ data-highlighted={highlightedLineSet.has(index + 1) || undefined}
73
+ className={cn("block rounded px-1", highlightedLineSet.has(index + 1) && "bg-primary/10 text-foreground")}
74
+ >
75
+ {line || " "}
76
+ </span>
77
+ ))}
78
+ </code>
59
79
  )}
60
80
  </pre>
61
81
  </div>
@@ -1,9 +1,10 @@
1
1
  import * as React from "react"
2
2
  import { ArrowDownIcon, ArrowUpIcon, MinusIcon } from "lucide-react"
3
3
 
4
+ import { Badge, type BadgeProps } from "@/components/ui/badge"
4
5
  import { cn } from "@/lib/utils"
5
6
 
6
- export type DeltaBadgeProps = React.ComponentProps<"span"> & {
7
+ export type DeltaBadgeProps = Omit<BadgeProps, "children" | "label" | "tone" | "status" | "leftIcon" | "variant" | "size"> & {
7
8
  value: React.ReactNode
8
9
  trend?: "up" | "down" | "neutral"
9
10
  size?: "sm" | "default"
@@ -19,23 +20,22 @@ function DeltaBadge({
19
20
  ...props
20
21
  }: DeltaBadgeProps) {
21
22
  const TrendIcon = trend === "up" ? ArrowUpIcon : trend === "down" ? ArrowDownIcon : MinusIcon
23
+ const tone = trend === "up" ? "success" : trend === "down" ? "danger" : "muted"
22
24
 
23
25
  return (
24
- <span
26
+ <Badge
25
27
  data-slot="delta-badge"
28
+ variant="soft"
29
+ tone={tone}
30
+ size={size}
31
+ leftIcon={icon ? <TrendIcon className={cn("shrink-0", size === "sm" ? "size-2.5" : "size-3")} /> : undefined}
32
+ label={value}
26
33
  className={cn(
27
- "inline-flex items-center justify-center font-medium",
28
- size === "sm" ? "gap-0.5 rounded px-1 py-0.5 text-[10px]" : "gap-1 rounded-full px-1.5 py-0.5 text-xs",
29
- trend === "up" && "bg-emerald-500/10 text-emerald-600 dark:text-emerald-400",
30
- trend === "down" && "bg-destructive/10 text-destructive",
31
- trend === "neutral" && "bg-muted text-muted-foreground",
34
+ size === "sm" && "min-h-5 px-1.5 text-[10px]",
32
35
  className
33
36
  )}
34
37
  {...props}
35
- >
36
- {icon && <TrendIcon className={cn("shrink-0", size === "sm" ? "size-2.5" : "size-3")} />}
37
- {value}
38
- </span>
38
+ />
39
39
  )
40
40
  }
41
41
 
@@ -3,14 +3,15 @@ import * as React from "react"
3
3
  import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"
4
4
  import { cn } from "@/lib/utils"
5
5
 
6
- export type KanbanCard = {
7
- key: string
8
- title: React.ReactNode
9
- description?: React.ReactNode
10
- meta?: React.ReactNode
11
- extra?: React.ReactNode
12
- disabled?: boolean
13
- }
6
+ export type KanbanCard = {
7
+ key: string
8
+ title: React.ReactNode
9
+ description?: React.ReactNode
10
+ meta?: React.ReactNode
11
+ extra?: React.ReactNode
12
+ actions?: React.ReactNode
13
+ disabled?: boolean
14
+ }
14
15
 
15
16
  export type KanbanColumn = {
16
17
  key: string
@@ -22,24 +23,31 @@ export type KanbanColumn = {
22
23
 
23
24
  export type KanbanBoardProps = React.ComponentProps<"div"> & {
24
25
  columns: KanbanColumn[]
25
- renderCard?: (card: KanbanCard, column: KanbanColumn) => React.ReactNode
26
- onCardClick?: (card: KanbanCard, column: KanbanColumn) => void
27
- columnClassName?: string
28
- cardClassName?: string
29
- }
30
-
31
- function KanbanBoard({ columns, renderCard, onCardClick, columnClassName, cardClassName, className, ...props }: KanbanBoardProps) {
32
- return (
33
- <div data-slot="kanban-board" className={cn("grid auto-cols-[minmax(280px,1fr)] grid-flow-col gap-4 overflow-x-auto pb-2", className)} {...props}>
34
- {columns.map((column) => (
26
+ renderCard?: (card: KanbanCard, column: KanbanColumn) => React.ReactNode
27
+ onCardClick?: (card: KanbanCard, column: KanbanColumn) => void
28
+ onCardMove?: (card: KanbanCard, fromColumn: KanbanColumn, toColumn: KanbanColumn) => void
29
+ emptyColumn?: React.ReactNode | ((column: KanbanColumn) => React.ReactNode)
30
+ columnClassName?: string
31
+ cardClassName?: string
32
+ }
33
+
34
+ function KanbanBoard({ columns, renderCard, onCardClick, onCardMove, emptyColumn = "No cards yet.", columnClassName, cardClassName, className, ...props }: KanbanBoardProps) {
35
+ const columnByKey = React.useMemo(() => new Map(columns.map((column) => [column.key, column])), [columns])
36
+
37
+ return (
38
+ <div data-slot="kanban-board" className={cn("grid auto-cols-[minmax(280px,1fr)] grid-flow-col gap-4 overflow-x-auto pb-2", className)} {...props}>
39
+ {columns.map((column) => (
35
40
  <KanbanColumnView
36
41
  key={column.key}
37
42
  column={column}
38
- renderCard={renderCard}
39
- onCardClick={onCardClick}
40
- columnClassName={columnClassName}
41
- cardClassName={cardClassName}
42
- />
43
+ renderCard={renderCard}
44
+ onCardClick={onCardClick}
45
+ onCardMove={onCardMove}
46
+ columnByKey={columnByKey}
47
+ emptyColumn={emptyColumn}
48
+ columnClassName={columnClassName}
49
+ cardClassName={cardClassName}
50
+ />
43
51
  ))}
44
52
  </div>
45
53
  )
@@ -47,46 +55,84 @@ function KanbanBoard({ columns, renderCard, onCardClick, columnClassName, cardCl
47
55
 
48
56
  function KanbanColumnView({
49
57
  column,
50
- renderCard,
51
- onCardClick,
52
- columnClassName,
53
- cardClassName,
54
- }: {
55
- column: KanbanColumn
56
- renderCard?: (card: KanbanCard, column: KanbanColumn) => React.ReactNode
57
- onCardClick?: (card: KanbanCard, column: KanbanColumn) => void
58
- columnClassName?: string
59
- cardClassName?: string
60
- }) {
61
- return (
62
- <section data-slot="kanban-column" className={cn("grid min-h-40 content-start gap-3 rounded-lg border bg-muted/35 p-3", columnClassName)}>
58
+ renderCard,
59
+ onCardClick,
60
+ onCardMove,
61
+ columnByKey,
62
+ emptyColumn,
63
+ columnClassName,
64
+ cardClassName,
65
+ }: {
66
+ column: KanbanColumn
67
+ renderCard?: (card: KanbanCard, column: KanbanColumn) => React.ReactNode
68
+ onCardClick?: (card: KanbanCard, column: KanbanColumn) => void
69
+ onCardMove?: (card: KanbanCard, fromColumn: KanbanColumn, toColumn: KanbanColumn) => void
70
+ columnByKey: Map<string, KanbanColumn>
71
+ emptyColumn: React.ReactNode | ((column: KanbanColumn) => React.ReactNode)
72
+ columnClassName?: string
73
+ cardClassName?: string
74
+ }) {
75
+ return (
76
+ <section
77
+ data-slot="kanban-column"
78
+ className={cn("grid min-h-40 content-start gap-3 rounded-lg border bg-muted/35 p-3", columnClassName)}
79
+ onDragOver={(event) => {
80
+ if (onCardMove) event.preventDefault()
81
+ }}
82
+ onDrop={(event) => {
83
+ const cardKey = event.dataTransfer.getData("application/x-tembro-kanban-card")
84
+ const fromColumnKey = event.dataTransfer.getData("application/x-tembro-kanban-column")
85
+ const fromColumn = columnByKey.get(fromColumnKey)
86
+ const card = fromColumn?.cards.find((item) => item.key === cardKey)
87
+ if (card && fromColumn && fromColumn.key !== column.key) onCardMove?.(card, fromColumn, column)
88
+ }}
89
+ >
63
90
  <div className="flex items-start justify-between gap-3">
64
91
  <div className="grid gap-0.5">
65
92
  <h3 className="text-sm font-semibold text-foreground">{column.title}</h3>
66
93
  {column.description && <p className="text-xs text-muted-foreground">{column.description}</p>}
67
94
  </div>
68
95
  <div className="rounded-full bg-background px-2 py-0.5 text-xs text-muted-foreground">{column.count ?? column.cards.length}</div>
69
- </div>
70
- <div className="grid gap-2">
71
- {column.cards.map((card) => (
72
- renderCard?.(card, column) ?? (
73
- <Card
74
- key={card.key}
75
- data-slot="kanban-card"
76
- className={cn(
77
- "transition-colors hover:bg-muted/40",
78
- onCardClick && !card.disabled && "cursor-pointer",
79
- card.disabled && "pointer-events-none opacity-55",
80
- cardClassName
81
- )}
82
- onClick={() => onCardClick?.(card, column)}
83
- >
84
- <CardHeader className="p-3 pb-1">
85
- <div className="flex items-start justify-between gap-2">
86
- <CardTitle className="text-sm">{card.title}</CardTitle>
87
- {card.extra}
88
- </div>
89
- </CardHeader>
96
+ </div>
97
+ <div className="grid gap-2">
98
+ {column.cards.length === 0 ? (
99
+ <div data-slot="kanban-column-empty" className="rounded-md border border-dashed bg-background/60 px-3 py-6 text-center text-sm text-muted-foreground">
100
+ {typeof emptyColumn === "function" ? emptyColumn(column) : emptyColumn}
101
+ </div>
102
+ ) : column.cards.map((card) => (
103
+ renderCard?.(card, column) ?? (
104
+ <Card
105
+ key={card.key}
106
+ data-slot="kanban-card"
107
+ role={onCardClick ? "button" : undefined}
108
+ tabIndex={onCardClick && !card.disabled ? 0 : undefined}
109
+ draggable={Boolean(onCardMove && !card.disabled)}
110
+ className={cn(
111
+ "transition-colors hover:bg-muted/40",
112
+ onCardClick && !card.disabled && "cursor-pointer",
113
+ onCardMove && !card.disabled && "cursor-grab active:cursor-grabbing",
114
+ card.disabled && "pointer-events-none opacity-55",
115
+ cardClassName
116
+ )}
117
+ onDragStart={(event) => {
118
+ event.dataTransfer.setData("application/x-tembro-kanban-card", card.key)
119
+ event.dataTransfer.setData("application/x-tembro-kanban-column", column.key)
120
+ event.dataTransfer.effectAllowed = "move"
121
+ }}
122
+ onClick={() => onCardClick?.(card, column)}
123
+ onKeyDown={(event) => {
124
+ if ((event.key === "Enter" || event.key === " ") && onCardClick && !card.disabled) {
125
+ event.preventDefault()
126
+ onCardClick(card, column)
127
+ }
128
+ }}
129
+ >
130
+ <CardHeader className="p-3 pb-1">
131
+ <div className="flex items-start justify-between gap-2">
132
+ <CardTitle className="text-sm">{card.title}</CardTitle>
133
+ {(card.extra || card.actions) && <div className="flex shrink-0 items-center gap-1">{card.extra}{card.actions}</div>}
134
+ </div>
135
+ </CardHeader>
90
136
  {(card.description || card.meta) && (
91
137
  <CardContent className="grid gap-2 p-3 pt-0 text-xs text-muted-foreground">
92
138
  {card.description}
@@ -6,17 +6,18 @@ import { cn } from "@/lib/utils"
6
6
  export type MetricTone = "default" | "success" | "warning" | "danger" | "info" | "muted"
7
7
  export type MetricGridColumn = 1 | 2 | 3 | 4
8
8
 
9
- export type MetricItem = {
9
+ export type MetricItem = {
10
10
  key: string
11
11
  label: React.ReactNode
12
12
  value: React.ReactNode
13
13
  description?: React.ReactNode
14
14
  icon?: React.ReactNode
15
15
  trend?: React.ReactNode
16
- tone?: MetricTone
17
- hidden?: boolean
18
- className?: string
19
- }
16
+ tone?: MetricTone
17
+ hidden?: boolean
18
+ className?: string
19
+ loading?: boolean
20
+ }
20
21
 
21
22
  export type MetricGridProps = React.ComponentProps<"div"> & {
22
23
  items: MetricItem[]
@@ -63,14 +64,16 @@ function MetricGrid({
63
64
  data-slot="stat-card"
64
65
  data-tone={item.tone ?? "default"}
65
66
  className={cn("min-w-0 overflow-hidden", toneClassName[item.tone ?? "default"], itemClassName, item.className)}
66
- >
67
- <CardHeader className={cn("flex flex-row items-start justify-between gap-3 space-y-0", compact ? "p-3 pb-1" : "pb-2")}>
68
- <div className="min-w-0 space-y-1">
69
- <CardDescription className="truncate">{item.label}</CardDescription>
70
- <CardTitle className={cn("truncate", compact ? "text-xl" : "text-2xl")}>{item.value}</CardTitle>
71
- </div>
72
- {item.icon && <div className="shrink-0 rounded-lg bg-muted p-2 text-muted-foreground [&_svg]:size-4">{item.icon}</div>}
73
- </CardHeader>
67
+ >
68
+ <CardHeader className={cn("flex flex-row items-start justify-between gap-3 space-y-0", compact ? "p-3 pb-1" : "pb-2")}>
69
+ <div className="min-w-0 space-y-1">
70
+ <CardDescription className="truncate">{item.label}</CardDescription>
71
+ <CardTitle className={cn("truncate", compact ? "text-xl" : "text-2xl")}>
72
+ {item.loading ? <span className="block h-8 w-24 animate-pulse rounded bg-muted" /> : item.value}
73
+ </CardTitle>
74
+ </div>
75
+ {item.icon && <div className="shrink-0 rounded-lg bg-muted p-2 text-muted-foreground [&_svg]:size-4">{item.icon}</div>}
76
+ </CardHeader>
74
77
  {(item.description || item.trend) && (
75
78
  <CardContent className={cn("flex min-w-0 items-center justify-between gap-2", compact ? "p-3 pt-1" : "pt-0")}>
76
79
  {item.description && <div className="min-w-0 truncate text-xs text-muted-foreground">{item.description}</div>}
@@ -2,13 +2,14 @@ import * as React from "react"
2
2
 
3
3
  import { cn } from "@/lib/utils"
4
4
 
5
- export type QRCodeProps = React.ComponentProps<"div"> & {
6
- value: string
7
- src?: string
8
- alt?: string
9
- size?: number
10
- cells?: number
11
- }
5
+ export type QRCodeProps = React.ComponentProps<"div"> & {
6
+ value: string
7
+ src?: string
8
+ alt?: string
9
+ size?: number
10
+ cells?: number
11
+ visualOnlyLabel?: React.ReactNode
12
+ }
12
13
 
13
14
  function hashValue(value: string) {
14
15
  let hash = 2166136261
@@ -53,18 +54,19 @@ function QRCodeSvg({ value, cells = 29, title }: { value: string; cells?: number
53
54
  )
54
55
  }
55
56
 
56
- function QRCode({ value, src, alt, size = 160, cells = 29, className, ...props }: QRCodeProps) {
57
- return (
58
- <div data-slot="qr-code" className={cn("inline-flex flex-col items-center gap-2 rounded-xl border bg-background p-3", className)} {...props}>
57
+ function QRCode({ value, src, alt, size = 160, cells = 29, visualOnlyLabel = "Visual preview only. Provide src from a certified QR encoder for scan-critical use.", className, ...props }: QRCodeProps) {
58
+ return (
59
+ <div data-slot="qr-code" className={cn("inline-flex flex-col items-center gap-2 rounded-xl border bg-background p-3", className)} {...props}>
59
60
  <div className="rounded-md bg-white p-2" style={{ width: size, height: size }}>
60
61
  {src ? (
61
62
  <img src={src} alt={alt ?? value} width={size} height={size} className="size-full rounded-sm object-contain" />
62
63
  ) : (
63
64
  <QRCodeSvg value={value} cells={cells} title={alt} />
64
- )}
65
- </div>
66
- </div>
67
- )
68
- }
65
+ )}
66
+ </div>
67
+ {!src && visualOnlyLabel && <div className="max-w-48 text-center text-xs text-muted-foreground">{visualOnlyLabel}</div>}
68
+ </div>
69
+ )
70
+ }
69
71
 
70
72
  export { QRCode, QRCodeSvg }