tembro 2.0.5 → 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 (381) 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-pagination.cjs +1 -1
  17. package/dist/components/data-table/data-table-pagination.js +4 -4
  18. package/dist/components/data-table/data-table-toolbar.cjs +1 -1
  19. package/dist/components/data-table/data-table-toolbar.js +12 -13
  20. package/dist/components/data-table/data-table.cjs +1 -1
  21. package/dist/components/data-table/data-table.d.ts +2 -2
  22. package/dist/components/data-table/data-table.js +2 -1
  23. package/dist/components/display/carousel.cjs +1 -1
  24. package/dist/components/display/carousel.d.ts +15 -1
  25. package/dist/components/display/carousel.js +128 -86
  26. package/dist/components/display/code-block.cjs +2 -2
  27. package/dist/components/display/code-block.d.ts +2 -1
  28. package/dist/components/display/code-block.js +17 -12
  29. package/dist/components/display/delta-badge.cjs +1 -1
  30. package/dist/components/display/delta-badge.d.ts +2 -1
  31. package/dist/components/display/delta-badge.js +11 -7
  32. package/dist/components/display/kanban.cjs +1 -1
  33. package/dist/components/display/kanban.d.ts +4 -1
  34. package/dist/components/display/kanban.js +60 -33
  35. package/dist/components/display/metric-grid.cjs +1 -1
  36. package/dist/components/display/metric-grid.d.ts +1 -0
  37. package/dist/components/display/metric-grid.js +1 -1
  38. package/dist/components/display/qr-code.cjs +1 -1
  39. package/dist/components/display/qr-code.d.ts +2 -1
  40. package/dist/components/display/qr-code.js +19 -16
  41. package/dist/components/display/smart-card.d.ts +1 -1
  42. package/dist/components/display/status-legend.d.ts +1 -1
  43. package/dist/components/display/tag.cjs +1 -1
  44. package/dist/components/display/tag.d.ts +2 -1
  45. package/dist/components/display/tag.js +28 -22
  46. package/dist/components/display/tree-view.cjs +1 -1
  47. package/dist/components/display/tree-view.d.ts +9 -1
  48. package/dist/components/display/tree-view.js +104 -40
  49. package/dist/components/display/trend-card.cjs +1 -1
  50. package/dist/components/display/trend-card.js +27 -41
  51. package/dist/components/feedback/alert.cjs +1 -1
  52. package/dist/components/feedback/alert.d.ts +2 -1
  53. package/dist/components/feedback/alert.js +6 -6
  54. package/dist/components/feedback/loading-state.cjs +1 -1
  55. package/dist/components/feedback/loading-state.d.ts +3 -1
  56. package/dist/components/feedback/loading-state.js +23 -10
  57. package/dist/components/feedback/page-state.cjs +1 -1
  58. package/dist/components/feedback/page-state.d.ts +2 -1
  59. package/dist/components/feedback/page-state.js +7 -4
  60. package/dist/components/form/form-field-shell.cjs +1 -1
  61. package/dist/components/form/form-field-shell.d.ts +4 -2
  62. package/dist/components/form/form-field-shell.js +57 -41
  63. package/dist/components/form/form-input.cjs +1 -1
  64. package/dist/components/form/form-input.d.ts +3 -4
  65. package/dist/components/form/form-input.js +259 -257
  66. package/dist/components/form/form-select.cjs +1 -1
  67. package/dist/components/form/form-select.d.ts +2 -2
  68. package/dist/components/form/form-select.js +8 -6
  69. package/dist/components/form/form-switch.cjs +1 -1
  70. package/dist/components/form/form-switch.d.ts +1 -1
  71. package/dist/components/form/form-switch.js +58 -54
  72. package/dist/components/form/form-textarea.cjs +1 -1
  73. package/dist/components/form/form-textarea.d.ts +1 -1
  74. package/dist/components/form/form-textarea.js +29 -27
  75. package/dist/components/inputs/async-select.d.ts +3 -0
  76. package/dist/components/inputs/search-input.d.ts +3 -0
  77. package/dist/components/inputs/simple-select.cjs +1 -1
  78. package/dist/components/inputs/simple-select.d.ts +10 -32
  79. package/dist/components/inputs/simple-select.js +5 -101
  80. package/dist/components/layout/app-sidebar.cjs +1 -1
  81. package/dist/components/layout/app-sidebar.d.ts +1 -0
  82. package/dist/components/layout/app-sidebar.js +36 -36
  83. package/dist/components/layout/breadcrumbs.cjs +1 -1
  84. package/dist/components/layout/breadcrumbs.d.ts +2 -1
  85. package/dist/components/layout/breadcrumbs.js +7 -7
  86. package/dist/components/modern/calendar-scheduler.cjs +1 -1
  87. package/dist/components/modern/calendar-scheduler.d.ts +5 -1
  88. package/dist/components/modern/calendar-scheduler.js +47 -28
  89. package/dist/components/modern/dual-list-picker.cjs +1 -1
  90. package/dist/components/modern/dual-list-picker.d.ts +5 -1
  91. package/dist/components/modern/dual-list-picker.js +81 -23
  92. package/dist/components/modern/rich-text-editor.cjs +1 -1
  93. package/dist/components/modern/rich-text-editor.d.ts +3 -1
  94. package/dist/components/modern/rich-text-editor.js +12 -9
  95. package/dist/components/modern/tour.cjs +1 -1
  96. package/dist/components/modern/tour.d.ts +5 -1
  97. package/dist/components/modern/tour.js +57 -35
  98. package/dist/components/navigation/command-bar.cjs +1 -1
  99. package/dist/components/navigation/command-bar.d.ts +3 -1
  100. package/dist/components/navigation/command-bar.js +10 -7
  101. package/dist/components/navigation/demo.cjs +1 -1
  102. package/dist/components/navigation/demo.js +0 -1
  103. package/dist/components/navigation/nav-tabs.cjs +1 -1
  104. package/dist/components/navigation/nav-tabs.js +39 -27
  105. package/dist/components/navigation/page-tabs.cjs +1 -1
  106. package/dist/components/navigation/page-tabs.js +41 -30
  107. package/dist/components/navigation/pagination.cjs +1 -1
  108. package/dist/components/navigation/pagination.d.ts +7 -1
  109. package/dist/components/navigation/pagination.js +48 -25
  110. package/dist/components/notifications/notification-center.cjs +1 -1
  111. package/dist/components/notifications/notification-center.d.ts +3 -1
  112. package/dist/components/notifications/notification-center.js +56 -38
  113. package/dist/components/notifications/toast.cjs +1 -1
  114. package/dist/components/notifications/toast.d.ts +1 -0
  115. package/dist/components/notifications/toast.js +4 -0
  116. package/dist/components/overlay/alert-dialog.cjs +1 -1
  117. package/dist/components/overlay/alert-dialog.js +1 -1
  118. package/dist/components/overlay/confirm-dialog.cjs +1 -1
  119. package/dist/components/overlay/confirm-dialog.d.ts +4 -2
  120. package/dist/components/overlay/confirm-dialog.js +31 -22
  121. package/dist/components/overlay/drawer.cjs +1 -1
  122. package/dist/components/overlay/drawer.d.ts +3 -1
  123. package/dist/components/overlay/drawer.js +24 -16
  124. package/dist/components/ui/accordion/index.d.ts +4 -0
  125. package/dist/components/ui/badge/index.cjs +1 -1
  126. package/dist/components/ui/badge/index.d.ts +1 -1
  127. package/dist/components/ui/badge/index.js +2 -1
  128. package/dist/components/ui/button/index.cjs +1 -1
  129. package/dist/components/ui/button/index.d.ts +2 -1
  130. package/dist/components/ui/button/index.js +13 -10
  131. package/dist/components/ui/card/index.cjs +1 -1
  132. package/dist/components/ui/card/index.d.ts +13 -2
  133. package/dist/components/ui/card/index.js +74 -49
  134. package/dist/components/ui/dialog/index.cjs +1 -1
  135. package/dist/components/ui/dialog/index.js +2 -1
  136. package/dist/components/ui/hover-card.cjs +1 -1
  137. package/dist/components/ui/hover-card.d.ts +11 -3
  138. package/dist/components/ui/hover-card.js +29 -24
  139. package/dist/components/ui/input/index.cjs +1 -1
  140. package/dist/components/ui/input/index.d.ts +9 -1
  141. package/dist/components/ui/input/index.js +63 -30
  142. package/dist/components/ui/popover/index.cjs +1 -1
  143. package/dist/components/ui/popover/index.d.ts +2 -2
  144. package/dist/components/ui/popover/index.js +6 -5
  145. package/dist/components/ui/radio-group/index.cjs +1 -1
  146. package/dist/components/ui/radio-group/index.d.ts +5 -1
  147. package/dist/components/ui/radio-group/index.js +50 -16
  148. package/dist/components/ui/right-click-menu/index.cjs +1 -1
  149. package/dist/components/ui/right-click-menu/index.d.ts +5 -1
  150. package/dist/components/ui/right-click-menu/index.js +77 -23
  151. package/dist/components/ui/segmented-control/index.cjs +1 -1
  152. package/dist/components/ui/segmented-control/index.d.ts +2 -1
  153. package/dist/components/ui/segmented-control/index.js +23 -11
  154. package/dist/components/ui/select/index.cjs +1 -1
  155. package/dist/components/ui/select/index.d.ts +40 -1
  156. package/dist/components/ui/select/index.js +159 -48
  157. package/dist/components/ui/switch/index.cjs +1 -1
  158. package/dist/components/ui/switch/index.d.ts +18 -0
  159. package/dist/components/ui/switch/index.js +47 -17
  160. package/dist/components/ui/tabs/index.cjs +1 -1
  161. package/dist/components/ui/tabs/index.d.ts +14 -4
  162. package/dist/components/ui/tabs/index.js +11 -8
  163. package/dist/components/ui/textarea/index.cjs +1 -1
  164. package/dist/components/ui/textarea/index.d.ts +10 -2
  165. package/dist/components/ui/textarea/index.js +37 -8
  166. package/dist/components/ui/textarea.cjs +1 -0
  167. package/dist/components/ui/textarea.d.ts +1 -0
  168. package/dist/components/ui/textarea.js +2 -0
  169. package/dist/components/ui/tooltip/index.cjs +1 -1
  170. package/dist/components/ui/tooltip/index.d.ts +11 -3
  171. package/dist/components/ui/tooltip/index.js +41 -20
  172. package/dist/components/upload/file-upload.cjs +1 -1
  173. package/dist/components/upload/file-upload.d.ts +8 -1
  174. package/dist/components/upload/file-upload.js +132 -100
  175. package/dist/components/upload/image-upload.cjs +1 -1
  176. package/dist/components/upload/image-upload.d.ts +5 -1
  177. package/dist/components/upload/image-upload.js +34 -9
  178. package/dist/index.cjs +1 -1
  179. package/dist/index.js +31 -31
  180. package/dist/public-component-surface.cjs +1 -1
  181. package/dist/public-component-surface.js +15 -0
  182. package/dist/showcase/component-api-schema.cjs +1 -1
  183. package/dist/showcase/component-api-schema.js +187 -10
  184. package/dist/showcase/create-demo.cjs +5 -4
  185. package/dist/showcase/create-demo.js +2 -2
  186. package/dist/showcase/fallback.cjs +3 -3
  187. package/dist/showcase/fallback.js +221 -243
  188. package/dist/showcase/premium/alert/showcase.cjs +1 -1
  189. package/dist/showcase/premium/alert/showcase.js +1 -0
  190. package/dist/showcase/premium/app-sidebar/showcase.cjs +1 -1
  191. package/dist/showcase/premium/app-sidebar/showcase.js +1 -0
  192. package/dist/showcase/premium/badge/showcase.cjs +1 -1
  193. package/dist/showcase/premium/badge/showcase.js +7 -0
  194. package/dist/showcase/premium/badge/types.d.ts +1 -1
  195. package/dist/showcase/premium/breadcrumbs/showcase.cjs +1 -1
  196. package/dist/showcase/premium/breadcrumbs/showcase.js +12 -1
  197. package/dist/showcase/premium/button/mock.cjs +1 -4
  198. package/dist/showcase/premium/button/mock.js +1 -1
  199. package/dist/showcase/premium/button/showcase.cjs +1 -1
  200. package/dist/showcase/premium/button/showcase.js +2 -2
  201. package/dist/showcase/premium/card/showcase.cjs +1 -1
  202. package/dist/showcase/premium/card/showcase.js +96 -47
  203. package/dist/showcase/premium/carousel/showcase.cjs +1 -1
  204. package/dist/showcase/premium/carousel/showcase.js +76 -49
  205. package/dist/showcase/premium/command-bar/showcase.cjs +1 -1
  206. package/dist/showcase/premium/command-bar/showcase.js +2 -0
  207. package/dist/showcase/premium/data-table/mock.cjs +12 -11
  208. package/dist/showcase/premium/data-table/mock.js +1 -1
  209. package/dist/showcase/premium/data-table/showcase.cjs +1 -1
  210. package/dist/showcase/premium/data-table/showcase.js +1 -1
  211. package/dist/showcase/premium/data-table-parts/showcase.cjs +1 -1
  212. package/dist/showcase/premium/data-table-parts/showcase.js +3 -1
  213. package/dist/showcase/premium/file-upload/showcase.cjs +1 -1
  214. package/dist/showcase/premium/file-upload/showcase.js +25 -4
  215. package/dist/showcase/premium/image-upload/showcase.cjs +1 -1
  216. package/dist/showcase/premium/image-upload/showcase.js +4 -1
  217. package/dist/showcase/premium/index.cjs +1 -1
  218. package/dist/showcase/premium/index.js +396 -402
  219. package/dist/showcase/premium/loading-state/showcase.cjs +1 -1
  220. package/dist/showcase/premium/loading-state/showcase.js +3 -1
  221. package/dist/showcase/premium/metric-grid/showcase.cjs +1 -1
  222. package/dist/showcase/premium/metric-grid/showcase.js +96 -28
  223. package/dist/showcase/premium/notification-center/showcase.cjs +1 -1
  224. package/dist/showcase/premium/notification-center/showcase.js +7 -3
  225. package/dist/showcase/premium/page-state/showcase.cjs +1 -1
  226. package/dist/showcase/premium/page-state/showcase.js +5 -1
  227. package/dist/showcase/premium/pagination/showcase.cjs +1 -1
  228. package/dist/showcase/premium/pagination/showcase.js +15 -2
  229. package/dist/showcase/premium/popover/showcase.cjs +1 -1
  230. package/dist/showcase/premium/popover/showcase.js +85 -50
  231. package/dist/showcase/premium/radio-group/showcase.cjs +1 -1
  232. package/dist/showcase/premium/radio-group/showcase.js +27 -4
  233. package/dist/showcase/premium/right-click-menu/showcase.cjs +1 -1
  234. package/dist/showcase/premium/right-click-menu/showcase.js +56 -43
  235. package/dist/showcase/premium/segmented-control/showcase.cjs +1 -1
  236. package/dist/showcase/premium/segmented-control/showcase.js +1 -0
  237. package/dist/showcase/premium/select/data.cjs +1 -1
  238. package/dist/showcase/premium/select/data.js +69 -34
  239. package/dist/showcase/premium/select/mock.cjs +20 -8
  240. package/dist/showcase/premium/select/mock.js +3 -2
  241. package/dist/showcase/premium/select/showcase.cjs +1 -1
  242. package/dist/showcase/premium/select/showcase.js +101 -86
  243. package/dist/showcase/premium/select/types.d.ts +3 -0
  244. package/dist/showcase/premium/statistic/showcase.cjs +1 -1
  245. package/dist/showcase/premium/statistic/showcase.js +57 -25
  246. package/dist/showcase/premium/switch/showcase.cjs +1 -1
  247. package/dist/showcase/premium/switch/showcase.js +25 -14
  248. package/dist/showcase/premium/tabs/showcase.cjs +1 -1
  249. package/dist/showcase/premium/tabs/showcase.js +171 -48
  250. package/dist/showcase/premium/textarea/mock.cjs +12 -4
  251. package/dist/showcase/premium/textarea/mock.js +1 -1
  252. package/dist/showcase/premium/textarea/showcase.cjs +1 -1
  253. package/dist/showcase/premium/textarea/showcase.js +8 -3
  254. package/dist/showcase/premium/toast/showcase.cjs +1 -1
  255. package/dist/showcase/premium/toast/showcase.js +32 -6
  256. package/dist/showcase/premium/types.d.ts +1 -1
  257. package/dist/showcase/registry-quality.cjs +1 -1
  258. package/dist/showcase/registry-quality.js +1 -0
  259. package/dist/showcase/registry-specific.cjs +1 -1
  260. package/dist/showcase/registry-specific.js +78 -74
  261. package/dist/showcase/render-registry-preview.cjs +1 -1
  262. package/dist/showcase/render-registry-preview.js +90 -108
  263. package/dist/showcase/site-data.cjs +1 -1
  264. package/dist/showcase/site-data.js +60 -21
  265. package/dist/showcase/tembro-registry.json.cjs +1 -1
  266. package/dist/showcase/tembro-registry.json.js +34 -20
  267. package/dist/showcase/types.d.ts +1 -1
  268. package/package.json +1 -1
  269. package/packages/cli/dist/index.cjs +31 -31
  270. package/packages/cli/vendor/src/components/calendar/calendar.tsx +59 -50
  271. package/packages/cli/vendor/src/components/calendar/date-range-picker.tsx +7 -4
  272. package/packages/cli/vendor/src/components/charts/charts.tsx +109 -66
  273. package/packages/cli/vendor/src/components/charts/progress-ring.tsx +37 -26
  274. package/packages/cli/vendor/src/components/data-table/data-table-column-visibility-menu.tsx +41 -22
  275. package/packages/cli/vendor/src/components/data-table/data-table-pagination.tsx +7 -7
  276. package/packages/cli/vendor/src/components/data-table/data-table-toolbar.tsx +8 -6
  277. package/packages/cli/vendor/src/components/data-table/data-table.tsx +21 -20
  278. package/packages/cli/vendor/src/components/display/carousel.tsx +102 -9
  279. package/packages/cli/vendor/src/components/display/code-block.tsx +22 -2
  280. package/packages/cli/vendor/src/components/display/delta-badge.tsx +11 -11
  281. package/packages/cli/vendor/src/components/display/kanban.tsx +103 -57
  282. package/packages/cli/vendor/src/components/display/metric-grid.tsx +16 -13
  283. package/packages/cli/vendor/src/components/display/qr-code.tsx +17 -15
  284. package/packages/cli/vendor/src/components/display/smart-card.tsx +1 -1
  285. package/packages/cli/vendor/src/components/display/status-legend.tsx +1 -1
  286. package/packages/cli/vendor/src/components/display/tag.tsx +39 -21
  287. package/packages/cli/vendor/src/components/display/tree-view.tsx +221 -84
  288. package/packages/cli/vendor/src/components/display/trend-card.tsx +6 -40
  289. package/packages/cli/vendor/src/components/feedback/alert.tsx +3 -1
  290. package/packages/cli/vendor/src/components/feedback/loading-state.tsx +33 -17
  291. package/packages/cli/vendor/src/components/feedback/page-state.tsx +8 -7
  292. package/packages/cli/vendor/src/components/form/form-field-shell.tsx +37 -8
  293. package/packages/cli/vendor/src/components/form/form-input.tsx +11 -12
  294. package/packages/cli/vendor/src/components/form/form-select.tsx +6 -4
  295. package/packages/cli/vendor/src/components/form/form-switch.tsx +9 -3
  296. package/packages/cli/vendor/src/components/form/form-textarea.tsx +6 -2
  297. package/packages/cli/vendor/src/components/inputs/async-select.tsx +11 -8
  298. package/packages/cli/vendor/src/components/inputs/search-input.tsx +5 -2
  299. package/packages/cli/vendor/src/components/inputs/simple-select.tsx +20 -190
  300. package/packages/cli/vendor/src/components/layout/app-sidebar.tsx +3 -1
  301. package/packages/cli/vendor/src/components/layout/breadcrumbs.tsx +3 -1
  302. package/packages/cli/vendor/src/components/modern/calendar-scheduler.tsx +28 -13
  303. package/packages/cli/vendor/src/components/modern/dual-list-picker.tsx +103 -35
  304. package/packages/cli/vendor/src/components/modern/rich-text-editor.tsx +25 -22
  305. package/packages/cli/vendor/src/components/modern/tour.tsx +47 -29
  306. package/packages/cli/vendor/src/components/navigation/command-bar.tsx +6 -0
  307. package/packages/cli/vendor/src/components/navigation/demo.tsx +0 -1
  308. package/packages/cli/vendor/src/components/navigation/nav-tabs.tsx +38 -29
  309. package/packages/cli/vendor/src/components/navigation/page-tabs.tsx +35 -23
  310. package/packages/cli/vendor/src/components/navigation/pagination.tsx +65 -31
  311. package/packages/cli/vendor/src/components/notifications/notification-center.tsx +64 -39
  312. package/packages/cli/vendor/src/components/notifications/toast.tsx +23 -21
  313. package/packages/cli/vendor/src/components/overlay/alert-dialog.tsx +1 -1
  314. package/packages/cli/vendor/src/components/overlay/confirm-dialog.tsx +45 -22
  315. package/packages/cli/vendor/src/components/overlay/drawer.tsx +18 -5
  316. package/packages/cli/vendor/src/components/ui/accordion/index.tsx +4 -0
  317. package/packages/cli/vendor/src/components/ui/badge/index.tsx +2 -1
  318. package/packages/cli/vendor/src/components/ui/button/index.tsx +11 -5
  319. package/packages/cli/vendor/src/components/ui/card/index.tsx +95 -25
  320. package/packages/cli/vendor/src/components/ui/dialog/index.tsx +2 -1
  321. package/packages/cli/vendor/src/components/ui/hover-card.tsx +54 -28
  322. package/packages/cli/vendor/src/components/ui/input/index.tsx +98 -0
  323. package/packages/cli/vendor/src/components/ui/popover/index.tsx +10 -8
  324. package/packages/cli/vendor/src/components/ui/radio-group/index.tsx +55 -6
  325. package/packages/cli/vendor/src/components/ui/right-click-menu/index.tsx +120 -9
  326. package/packages/cli/vendor/src/components/ui/segmented-control/index.tsx +29 -3
  327. package/packages/cli/vendor/src/components/ui/select/index.tsx +260 -34
  328. package/packages/cli/vendor/src/components/ui/switch/index.tsx +71 -6
  329. package/packages/cli/vendor/src/components/ui/tabs/index.tsx +22 -6
  330. package/packages/cli/vendor/src/components/ui/textarea/index.tsx +105 -15
  331. package/packages/cli/vendor/src/components/ui/textarea.tsx +2 -0
  332. package/packages/cli/vendor/src/components/ui/tooltip/index.tsx +67 -22
  333. package/packages/cli/vendor/src/components/upload/file-upload.tsx +120 -57
  334. package/packages/cli/vendor/src/components/upload/image-upload.tsx +71 -24
  335. package/packages/cli/vendor/src/public-component-surface.ts +3 -0
  336. package/packages/cli/vendor/src/showcase/component-api-schema.ts +79 -41
  337. package/packages/cli/vendor/src/showcase/create-demo.tsx +16 -15
  338. package/packages/cli/vendor/src/showcase/fallback.tsx +4 -19
  339. package/packages/cli/vendor/src/showcase/premium/alert/showcase.tsx +1 -0
  340. package/packages/cli/vendor/src/showcase/premium/app-sidebar/showcase.tsx +1 -0
  341. package/packages/cli/vendor/src/showcase/premium/badge/showcase.tsx +4 -2
  342. package/packages/cli/vendor/src/showcase/premium/badge/types.ts +1 -1
  343. package/packages/cli/vendor/src/showcase/premium/breadcrumbs/showcase.tsx +3 -1
  344. package/packages/cli/vendor/src/showcase/premium/button/mock.ts +2 -5
  345. package/packages/cli/vendor/src/showcase/premium/button/showcase.tsx +2 -2
  346. package/packages/cli/vendor/src/showcase/premium/card/showcase.tsx +26 -1
  347. package/packages/cli/vendor/src/showcase/premium/carousel/showcase.tsx +19 -3
  348. package/packages/cli/vendor/src/showcase/premium/command-bar/showcase.tsx +1 -1
  349. package/packages/cli/vendor/src/showcase/premium/data-table/mock.ts +26 -25
  350. package/packages/cli/vendor/src/showcase/premium/data-table/showcase.tsx +3 -3
  351. package/packages/cli/vendor/src/showcase/premium/data-table-parts/showcase.tsx +3 -3
  352. package/packages/cli/vendor/src/showcase/premium/file-upload/showcase.tsx +21 -1
  353. package/packages/cli/vendor/src/showcase/premium/image-upload/showcase.tsx +4 -1
  354. package/packages/cli/vendor/src/showcase/premium/index.ts +0 -2
  355. package/packages/cli/vendor/src/showcase/premium/loading-state/showcase.tsx +1 -1
  356. package/packages/cli/vendor/src/showcase/premium/metric-grid/showcase.tsx +36 -4
  357. package/packages/cli/vendor/src/showcase/premium/notification-center/showcase.tsx +4 -3
  358. package/packages/cli/vendor/src/showcase/premium/page-state/showcase.tsx +1 -0
  359. package/packages/cli/vendor/src/showcase/premium/pagination/showcase.tsx +13 -1
  360. package/packages/cli/vendor/src/showcase/premium/popover/showcase.tsx +27 -11
  361. package/packages/cli/vendor/src/showcase/premium/radio-group/showcase.tsx +13 -1
  362. package/packages/cli/vendor/src/showcase/premium/right-click-menu/showcase.tsx +8 -5
  363. package/packages/cli/vendor/src/showcase/premium/segmented-control/showcase.tsx +1 -0
  364. package/packages/cli/vendor/src/showcase/premium/select/data.ts +12 -3
  365. package/packages/cli/vendor/src/showcase/premium/select/mock.ts +4 -4
  366. package/packages/cli/vendor/src/showcase/premium/select/showcase.tsx +35 -22
  367. package/packages/cli/vendor/src/showcase/premium/select/types.ts +3 -0
  368. package/packages/cli/vendor/src/showcase/premium/statistic/showcase.tsx +10 -1
  369. package/packages/cli/vendor/src/showcase/premium/switch/showcase.tsx +15 -6
  370. package/packages/cli/vendor/src/showcase/premium/tabs/showcase.tsx +48 -1
  371. package/packages/cli/vendor/src/showcase/premium/textarea/mock.ts +12 -4
  372. package/packages/cli/vendor/src/showcase/premium/textarea/showcase.tsx +5 -0
  373. package/packages/cli/vendor/src/showcase/premium/toast/showcase.tsx +17 -1
  374. package/packages/cli/vendor/src/showcase/premium/types.ts +1 -1
  375. package/packages/cli/vendor/src/showcase/registry-quality.ts +3 -2
  376. package/packages/cli/vendor/src/showcase/registry-specific.tsx +7 -8
  377. package/packages/cli/vendor/src/showcase/render-registry-preview.tsx +5 -21
  378. package/packages/cli/vendor/src/showcase/site-data.tsx +21 -15
  379. package/packages/cli/vendor/src/showcase/tembro-registry.json +42 -20
  380. package/packages/cli/vendor/src/showcase/types.ts +1 -1
  381. package/registry.json +18 -6
@@ -4,7 +4,8 @@ import { FileIcon, UploadCloudIcon, XIcon } from "lucide-react"
4
4
  import { Button } from "@/components/ui/button"
5
5
  import { cn, stopInteractivePropagation } from "@/lib/utils"
6
6
 
7
- export type FileUploadRejectReason = "max-files" | "max-size" | "type"
7
+ export type FileUploadRejectReason = "max-files" | "max-size" | "type"
8
+ export type FileUploadItemStatus = "idle" | "uploading" | "success" | "error"
8
9
 
9
10
  export type FileUploadRejectedFile = {
10
11
  file: File
@@ -24,13 +25,15 @@ export type FileUploadRejectionMessages = Partial<
24
25
  Record<FileUploadRejectReason, string | ((context: FileUploadRejectionMessageContext) => string)>
25
26
  >
26
27
 
27
- export type FileUploadRenderFileState = {
28
- file: File
29
- index: number
30
- progress?: number
31
- remove: () => void
32
- removeLabel?: string
33
- }
28
+ export type FileUploadRenderFileState = {
29
+ file: File
30
+ index: number
31
+ progress?: number
32
+ status: FileUploadItemStatus
33
+ remove: () => void
34
+ retry?: () => void
35
+ removeLabel?: string
36
+ }
34
37
 
35
38
  export type FileUploadRenderRejectedFileState = {
36
39
  rejectedFile: FileUploadRejectedFile
@@ -70,13 +73,17 @@ export type FileUploadProps = NativeFileInputProps & {
70
73
  rejectionMessages?: FileUploadRejectionMessages
71
74
  maxFiles?: number
72
75
  maxSize?: number
73
- appendFiles?: boolean
74
- showFileList?: boolean
75
- showClearButton?: boolean
76
- loading?: boolean
77
- progress?: number | Record<string, number>
78
- renderFile?: (state: FileUploadRenderFileState) => React.ReactNode
79
- renderRejectedFile?: (state: FileUploadRenderRejectedFileState) => React.ReactNode
76
+ appendFiles?: boolean
77
+ showFileList?: boolean
78
+ showClearButton?: boolean
79
+ loading?: boolean
80
+ progress?: number | Record<string, number>
81
+ status?: FileUploadItemStatus | Record<string, FileUploadItemStatus>
82
+ validateFile?: (file: File) => string | null | Promise<string | null>
83
+ onRetryFile?: (file: File, index: number) => void
84
+ fileTriggerLabel?: string
85
+ renderFile?: (state: FileUploadRenderFileState) => React.ReactNode
86
+ renderRejectedFile?: (state: FileUploadRenderRejectedFileState) => React.ReactNode
80
87
  renderActions?: (state: { openFileDialog: () => void; clearFiles: () => void; files: File[] }) => React.ReactNode
81
88
  className?: string
82
89
  inputClassName?: string
@@ -122,10 +129,15 @@ function getFileKey(file: File) {
122
129
  return `${file.name}-${file.size}-${file.lastModified}`
123
130
  }
124
131
 
125
- function getProgressForFile(progress: FileUploadProps["progress"], file: File) {
126
- if (typeof progress === "number") return progress
127
- return progress?.[getFileKey(file)] ?? progress?.[file.name]
128
- }
132
+ function getProgressForFile(progress: FileUploadProps["progress"], file: File) {
133
+ if (typeof progress === "number") return progress
134
+ return progress?.[getFileKey(file)] ?? progress?.[file.name]
135
+ }
136
+
137
+ function getStatusForFile(status: FileUploadProps["status"], file: File): FileUploadItemStatus {
138
+ if (typeof status === "string") return status
139
+ return status?.[getFileKey(file)] ?? status?.[file.name] ?? "idle"
140
+ }
129
141
 
130
142
  function resolveRejectionMessage(
131
143
  reason: FileUploadRejectReason,
@@ -148,29 +160,31 @@ function resolveRejectionMessage(
148
160
  }
149
161
  }
150
162
 
151
- function validateIncomingFiles({
163
+ function validateIncomingFiles({
152
164
  currentFiles,
153
165
  incomingFiles,
154
166
  accept,
155
167
  maxFiles,
156
- maxSize,
157
- appendFiles,
158
- rejectionMessages,
159
- }: {
168
+ maxSize,
169
+ appendFiles,
170
+ rejectionMessages,
171
+ validateFile,
172
+ }: {
160
173
  currentFiles: File[]
161
174
  incomingFiles: File[]
162
175
  accept?: string
163
176
  maxFiles?: number
164
177
  maxSize?: number
165
- appendFiles: boolean
166
- rejectionMessages?: FileUploadRejectionMessages
167
- }) {
168
- const accepted: File[] = []
169
- const rejected: FileUploadRejectedFile[] = []
178
+ appendFiles: boolean
179
+ rejectionMessages?: FileUploadRejectionMessages
180
+ validateFile?: FileUploadProps["validateFile"]
181
+ }) {
182
+ const accepted: File[] = []
183
+ const rejected: FileUploadRejectedFile[] = []
170
184
  const nextBase = appendFiles ? currentFiles : []
171
185
  const effectiveMaxFiles = maxFiles ?? (appendFiles ? undefined : incomingFiles.length)
172
186
 
173
- for (const file of incomingFiles) {
187
+ for (const file of incomingFiles) {
174
188
  if (effectiveMaxFiles !== undefined && nextBase.length + accepted.length >= effectiveMaxFiles) {
175
189
  rejected.push({
176
190
  file,
@@ -189,17 +203,27 @@ function validateIncomingFiles({
189
203
  continue
190
204
  }
191
205
 
192
- if (!fileMatchesAccept(file, accept)) {
206
+ if (!fileMatchesAccept(file, accept)) {
193
207
  rejected.push({
194
208
  file,
195
209
  reason: "type",
196
210
  message: resolveRejectionMessage("type", { file, maxFiles: effectiveMaxFiles, maxSize, accept }, rejectionMessages),
197
211
  })
198
- continue
199
- }
200
-
201
- accepted.push(file)
202
- }
212
+ continue
213
+ }
214
+
215
+ const customMessage = validateFile?.(file)
216
+ if (typeof customMessage === "string" && customMessage) {
217
+ rejected.push({
218
+ file,
219
+ reason: "type",
220
+ message: customMessage,
221
+ })
222
+ continue
223
+ }
224
+
225
+ accepted.push(file)
226
+ }
203
227
 
204
228
  return {
205
229
  accepted,
@@ -208,14 +232,25 @@ function validateIncomingFiles({
208
232
  }
209
233
  }
210
234
 
211
- function defaultRenderFile({ file, progress, remove, removeLabel = "Remove file" }: FileUploadRenderFileState) {
235
+ function defaultRenderFile({ file, progress, status, remove, retry, removeLabel = "Remove file" }: FileUploadRenderFileState) {
212
236
  return (
213
237
  <div className="flex min-w-0 items-center gap-3">
214
238
  <span className="flex size-9 shrink-0 items-center justify-center rounded-full border border-border/70 bg-background/90 shadow-sm">
215
239
  <FileIcon className="size-4 text-muted-foreground" />
216
240
  </span>
217
241
  <div className="min-w-0 flex-1">
218
- <div className="truncate text-sm font-medium text-foreground">{file.name}</div>
242
+ <div className="flex flex-wrap items-center gap-2">
243
+ <div className="truncate text-sm font-medium text-foreground">{file.name}</div>
244
+ <span className={cn(
245
+ "rounded-full px-2 py-0.5 text-[10px] font-semibold uppercase tracking-[0.16em]",
246
+ status === "uploading" && "bg-primary/10 text-primary",
247
+ status === "success" && "bg-emerald-500/10 text-emerald-600 dark:text-emerald-400",
248
+ status === "error" && "bg-destructive/10 text-destructive",
249
+ status === "idle" && "bg-muted text-muted-foreground"
250
+ )}>
251
+ {status}
252
+ </span>
253
+ </div>
219
254
  <div className="text-xs text-muted-foreground">{formatBytes(file.size)}</div>
220
255
  {typeof progress === "number" && (
221
256
  <div className="mt-2 h-1.5 overflow-hidden rounded-full bg-muted/80">
@@ -226,6 +261,11 @@ function defaultRenderFile({ file, progress, remove, removeLabel = "Remove file"
226
261
  </div>
227
262
  )}
228
263
  </div>
264
+ {status === "error" && retry ? (
265
+ <Button type="button" variant="outline" size="sm" className="rounded-full" onClick={retry}>
266
+ Retry
267
+ </Button>
268
+ ) : null}
229
269
  <Button
230
270
  type="button"
231
271
  variant="ghost"
@@ -245,7 +285,7 @@ function defaultRenderFile({ file, progress, remove, removeLabel = "Remove file"
245
285
  )
246
286
  }
247
287
 
248
- function FileUpload({
288
+ function FileUpload({
249
289
  files = [],
250
290
  onFilesChange,
251
291
  rejectedFiles,
@@ -264,9 +304,13 @@ function FileUpload({
264
304
  appendFiles = true,
265
305
  showFileList = true,
266
306
  showClearButton = true,
267
- loading = false,
268
- progress,
269
- renderFile,
307
+ loading = false,
308
+ progress,
309
+ status,
310
+ validateFile,
311
+ onRetryFile,
312
+ fileTriggerLabel = "Open file picker",
313
+ renderFile,
270
314
  renderRejectedFile,
271
315
  renderActions,
272
316
  className,
@@ -316,13 +360,22 @@ function FileUpload({
316
360
  }, [onFilesChange, setRejectedFiles])
317
361
 
318
362
  const processFiles = React.useCallback(
319
- (incomingFiles: File[]) => {
320
- const result = validateIncomingFiles({ currentFiles: files, incomingFiles, accept, maxFiles, maxSize, appendFiles, rejectionMessages })
321
- onFilesChange?.(result.nextFiles)
322
- setRejectedFiles(result.rejected)
323
- },
324
- [accept, appendFiles, files, maxFiles, maxSize, onFilesChange, rejectionMessages, setRejectedFiles]
325
- )
363
+ (incomingFiles: File[]) => {
364
+ const result = validateIncomingFiles({
365
+ currentFiles: files,
366
+ incomingFiles,
367
+ accept,
368
+ maxFiles,
369
+ maxSize,
370
+ appendFiles,
371
+ rejectionMessages,
372
+ validateFile,
373
+ })
374
+ onFilesChange?.(result.nextFiles)
375
+ setRejectedFiles(result.rejected)
376
+ },
377
+ [accept, appendFiles, files, maxFiles, maxSize, onFilesChange, rejectionMessages, setRejectedFiles, validateFile]
378
+ )
326
379
 
327
380
  const removeFile = React.useCallback(
328
381
  (fileIndex: number) => {
@@ -333,7 +386,7 @@ function FileUpload({
333
386
 
334
387
  const handleChange: React.ChangeEventHandler<HTMLInputElement> = (event) => {
335
388
  if (isDisabled) return
336
- processFiles(Array.from(event.target.files ?? []))
389
+ processFiles(Array.from(event.target.files ?? []))
337
390
  event.target.value = ""
338
391
  }
339
392
 
@@ -371,8 +424,8 @@ function FileUpload({
371
424
  event.preventDefault()
372
425
  dragDepthRef.current = 0
373
426
  setIsDragging(false)
374
- processFiles(Array.from(event.dataTransfer.files ?? []))
375
- }
427
+ processFiles(Array.from(event.dataTransfer.files ?? []))
428
+ }
376
429
 
377
430
  return (
378
431
  <div data-slot="file-upload" className={cn("grid gap-3", className)}>
@@ -391,9 +444,9 @@ function FileUpload({
391
444
  data-slot="file-upload-dropzone"
392
445
  data-dragging={isDragging || undefined}
393
446
  data-disabled={isDisabled || undefined}
394
- role="button"
395
- aria-disabled={isDisabled || undefined}
396
- aria-label={dropzoneAriaLabel}
447
+ role="button"
448
+ aria-disabled={isDisabled || undefined}
449
+ aria-label={dropzoneAriaLabel ?? fileTriggerLabel}
397
450
  tabIndex={isDisabled ? -1 : 0}
398
451
  className={cn(
399
452
  "grid cursor-pointer gap-4 rounded-[var(--radius-2xl)] border border-dashed border-border/80 bg-[linear-gradient(180deg,color-mix(in_oklch,var(--card),white_12%),var(--card))] p-6 text-center shadow-sm ring-1 ring-foreground/5 outline-none transition-[background-color,border-color,box-shadow,transform] hover:-translate-y-px hover:border-primary/35 hover:bg-muted/25 hover:shadow-[0_14px_36px_rgba(15,23,42,0.08)] focus-visible:ring-2 focus-visible:ring-ring data-[dragging=true]:border-primary data-[dragging=true]:bg-primary/6 data-[dragging=true]:shadow-[0_18px_50px_color-mix(in_oklch,var(--primary),transparent_84%)] data-[disabled=true]:cursor-not-allowed data-[disabled=true]:opacity-60",
@@ -432,6 +485,7 @@ function FileUpload({
432
485
  variant="outline"
433
486
  size="sm"
434
487
  disabled={isDisabled}
488
+ aria-label={typeof buttonLabel === "string" ? buttonLabel : fileTriggerLabel}
435
489
  onClick={(event) => {
436
490
  stopInteractivePropagation(event)
437
491
  openFileDialog()
@@ -463,13 +517,22 @@ function FileUpload({
463
517
 
464
518
  {showFileList && files.length > 0 && (
465
519
  <div data-slot="file-upload-list" className={cn("grid gap-2", fileListClassName)}>
466
- {files.map((file, index) => {
467
- const state = { file, index, progress: getProgressForFile(progress, file), remove: () => removeFile(index), removeLabel }
520
+ {files.map((file, index) => {
521
+ const state = {
522
+ file,
523
+ index,
524
+ progress: getProgressForFile(progress, file),
525
+ status: getStatusForFile(status, file),
526
+ remove: () => removeFile(index),
527
+ retry: onRetryFile ? () => onRetryFile(file, index) : undefined,
528
+ removeLabel,
529
+ }
468
530
 
469
531
  return (
470
532
  <div
471
533
  key={`${file.name}-${file.lastModified}-${index}`}
472
534
  data-slot="file-upload-item"
535
+ data-status={state.status}
473
536
  className={cn("rounded-[min(var(--radius-xl),18px)] border border-border/80 bg-[linear-gradient(180deg,color-mix(in_oklch,var(--card),white_10%),var(--card))] p-3.5 shadow-sm ring-1 ring-foreground/5", fileItemClassName)}
474
537
  >
475
538
  {renderFile?.(state) ?? defaultRenderFile(state)}
@@ -11,13 +11,33 @@ import {
11
11
  import { Button } from "@/components/ui/button"
12
12
  import { cn, stopInteractivePropagation } from "@/lib/utils"
13
13
 
14
- export type ImageUploadProps = Omit<FileUploadProps, "accept" | "renderFile"> & {
15
- accept?: string
16
- preview?: boolean
17
- previewClassName?: string
18
- imageClassName?: string
19
- renderImageFile?: (state: FileUploadRenderFileState & { previewUrl?: string }) => React.ReactNode
20
- }
14
+ export type ImageUploadProps = Omit<FileUploadProps, "accept" | "renderFile"> & {
15
+ accept?: string
16
+ preview?: boolean
17
+ previewClassName?: string
18
+ imageClassName?: string
19
+ minImageWidth?: number
20
+ minImageHeight?: number
21
+ aspectRatio?: number
22
+ aspectRatioTolerance?: number
23
+ renderImageFile?: (state: FileUploadRenderFileState & { previewUrl?: string }) => React.ReactNode
24
+ }
25
+
26
+ function readImageMeta(file: File) {
27
+ return new Promise<{ width: number; height: number }>((resolve, reject) => {
28
+ const url = URL.createObjectURL(file)
29
+ const image = new Image()
30
+ image.onload = () => {
31
+ resolve({ width: image.width, height: image.height })
32
+ URL.revokeObjectURL(url)
33
+ }
34
+ image.onerror = () => {
35
+ URL.revokeObjectURL(url)
36
+ reject(new Error("Image metadata could not be read"))
37
+ }
38
+ image.src = url
39
+ })
40
+ }
21
41
 
22
42
  function useImagePreviewUrls(files: File[], enabled = true) {
23
43
  const [urls, setUrls] = React.useState<Record<string, string>>({})
@@ -104,22 +124,49 @@ function ImageUpload({
104
124
  buttonLabel = "Choose image",
105
125
  dropzoneLabel = "Drop images here or click to upload",
106
126
  preview = true,
107
- previewClassName,
108
- imageClassName,
109
- files = [],
110
- renderImageFile,
111
- ...props
112
- }: ImageUploadProps) {
113
- const previewUrls = useImagePreviewUrls(files, preview)
114
-
115
- return (
116
- <FileUpload
117
- accept={accept}
118
- buttonLabel={buttonLabel}
119
- dropzoneLabel={dropzoneLabel}
120
- files={files}
121
- renderFile={(state) => {
122
- const previewUrl = previewUrls[getFileKey(state.file)]
127
+ previewClassName,
128
+ imageClassName,
129
+ files = [],
130
+ minImageWidth,
131
+ minImageHeight,
132
+ aspectRatio,
133
+ aspectRatioTolerance = 0.04,
134
+ renderImageFile,
135
+ ...props
136
+ }: ImageUploadProps) {
137
+ const previewUrls = useImagePreviewUrls(files, preview)
138
+
139
+ return (
140
+ <FileUpload
141
+ accept={accept}
142
+ buttonLabel={buttonLabel}
143
+ dropzoneLabel={dropzoneLabel}
144
+ files={files}
145
+ validateFile={async (file) => {
146
+ if (!file.type.startsWith("image/")) return "Only image files are allowed."
147
+ if (!minImageWidth && !minImageHeight && !aspectRatio) return null
148
+
149
+ const { width, height } = await readImageMeta(file)
150
+
151
+ if (minImageWidth && width < minImageWidth) {
152
+ return `Image width must be at least ${minImageWidth}px.`
153
+ }
154
+
155
+ if (minImageHeight && height < minImageHeight) {
156
+ return `Image height must be at least ${minImageHeight}px.`
157
+ }
158
+
159
+ if (aspectRatio) {
160
+ const ratio = width / height
161
+ if (Math.abs(ratio - aspectRatio) > aspectRatioTolerance) {
162
+ return `Image ratio must be close to ${aspectRatio.toFixed(2)}:1.`
163
+ }
164
+ }
165
+
166
+ return null
167
+ }}
168
+ renderFile={(state) => {
169
+ const previewUrl = previewUrls[getFileKey(state.file)]
123
170
 
124
171
  return renderImageFile?.({ ...state, previewUrl }) ??
125
172
  defaultRenderImageFile({ ...state, previewUrl, previewClassName, imageClassName })
@@ -129,4 +176,4 @@ function ImageUpload({
129
176
  )
130
177
  }
131
178
 
132
- export { ImageUpload, useImagePreviewUrls }
179
+ export { ImageUpload, useImagePreviewUrls }
@@ -14,6 +14,9 @@ export const documentedPublicComponentSurfaces: readonly PublicComponentSurfaceE
14
14
  { slug: "overlay", registryName: "dialog", surface: "documented" },
15
15
  { slug: "form-field", registryName: "form-field-shell", surface: "documented" },
16
16
  { slug: "data-table", registryName: "data-table", surface: "documented" },
17
+ { slug: "calendar", registryName: "calendar", surface: "documented" },
18
+ { slug: "date-picker", registryName: "date-picker", surface: "documented" },
19
+ { slug: "date-range-picker", registryName: "date-range-picker", surface: "documented" },
17
20
  { slug: "alert", registryName: "alert", surface: "documented" },
18
21
  { slug: "bar-chart", registryName: "charts", surface: "documented" },
19
22
  { slug: "sidebar", registryName: "sidebar", surface: "documented" },
@@ -29,14 +29,16 @@ export const componentApiSchemas: Record<string, ComponentApiSchema> = {
29
29
  { name: "variant", type: "'default' | 'secondary' | 'outline' | 'ghost' | 'destructive' | 'warning' | 'link'", defaultValue: "'default'", description: "Controls visual hierarchy and action tone.", example: "variant=\"destructive\"" },
30
30
  { name: "size", type: "'xs' | 'sm' | 'default' | 'md' | 'lg' | 'xl' | 'icon' | 'icon-xs' | 'icon-sm' | 'icon-lg'", defaultValue: "'default'", description: "Controls height, spacing and icon-only sizing.", example: "size=\"icon-sm\"" },
31
31
  { name: "loading", type: "boolean", defaultValue: "false", description: "Shows the spinner, disables interaction and communicates pending state.", example: "loading={isSaving}" },
32
- { name: "loadingLabel", type: "string", defaultValue: "'Loading'", description: "Accessible label displayed while the button is loading.", example: "loadingLabel=\"Saving\"" },
33
- { name: "disabled", type: "boolean", defaultValue: "false", description: "Disables the action and removes it from normal interaction.", example: "disabled={!canSubmit}" },
34
- { name: "leftIcon", type: "ReactNode", defaultValue: "-", description: "Icon rendered before the label. Use for primary verbs and scan-friendly actions." },
35
- { name: "rightIcon", type: "ReactNode", defaultValue: "-", description: "Icon rendered after the label. Use for forward navigation or external transitions." },
36
- { name: "asChild", type: "boolean", defaultValue: "false", description: "Renders the visual button style on a child element for link or router composition.", example: "asChild" },
37
- { name: "className", type: "string", defaultValue: "-", description: "Optional class override for spacing or layout composition." },
38
- { name: "children", type: "ReactNode", defaultValue: "-", required: true, description: "Button label or icon content. Icon-only buttons must still provide an accessible name." },
39
- { name: "aria-label", type: "string", defaultValue: "-", description: "Required for icon-only buttons so the action is announced correctly.", notes: "Use when children are only icons." },
32
+ { name: "loadingLabel", type: "string", defaultValue: "'Loading'", description: "Accessible label displayed while the button is loading.", example: "loadingLabel=\"Saving\"" },
33
+ { name: "disabled", type: "boolean", defaultValue: "false", description: "Disables the action and removes it from normal interaction.", example: "disabled={!canSubmit}" },
34
+ { name: "leftIcon", type: "ReactNode", defaultValue: "-", description: "Icon rendered before the label. Use for primary verbs and scan-friendly actions." },
35
+ { name: "rightIcon", type: "ReactNode", defaultValue: "-", description: "Icon rendered after the label. Use for forward navigation or external transitions." },
36
+ { name: "iconOnly", type: "boolean", defaultValue: "false", description: "Switches default sizing to the icon button size while keeping Button semantics.", example: "iconOnly aria-label=\"Download\"" },
37
+ { name: "fullWidth", type: "boolean", defaultValue: "false", description: "Expands the button to fill its parent width.", example: "fullWidth" },
38
+ { name: "pressed", type: "boolean", defaultValue: "false", description: "Marks toggle-like button state with aria-pressed and selected styling.", example: "pressed={active}" },
39
+ { name: "className", type: "string", defaultValue: "-", description: "Optional class override for spacing or layout composition." },
40
+ { name: "children", type: "ReactNode", defaultValue: "-", required: true, description: "Button label or icon content. Icon-only buttons must still provide an accessible name." },
41
+ { name: "aria-label", type: "string", defaultValue: "-", description: "Required for icon-only buttons so the action is announced correctly.", notes: "Use when children are only icons." },
40
42
  ],
41
43
  examples: [
42
44
  { title: "Primary action", code: "<Button>Save changes</Button>" },
@@ -51,18 +53,24 @@ export const componentApiSchemas: Record<string, ComponentApiSchema> = {
51
53
  source: "metadata",
52
54
  summary: "Primary typed-value surface. Start with Input and move into presets only when behavior requires it.",
53
55
  props: [
54
- { name: "value", type: "string | number", defaultValue: "-", description: "Controlled input value.", example: "value={name}" },
55
- { name: "defaultValue", type: "string | number", defaultValue: "-", description: "Uncontrolled initial value." },
56
- { name: "onChange", type: "ChangeEventHandler<HTMLInputElement>", defaultValue: "-", description: "Native change handler for value updates.", example: "onChange={(event) => setValue(event.target.value)}" },
57
- { name: "onValueChange", type: "(value: string) => void", defaultValue: "-", description: "Direct text callback for controlled string flows.", example: "onValueChange={setQuery}" },
58
- { name: "type", type: "HTMLInputTypeAttribute", defaultValue: "'text'", description: "Native input type. Prefer presets only when formatting or masking is required." },
59
- { name: "placeholder", type: "string", defaultValue: "-", description: "Short hint for empty input state." },
60
- { name: "clearable", type: "boolean", defaultValue: "false", description: "Shows the built-in clear action when a value exists.", example: "clearable" },
61
- { name: "onClear", type: "() => void", defaultValue: "-", description: "Called after the built-in clear action resets the field." },
62
- { name: "trailingAction", type: "ReactNode", defaultValue: "-", description: "Interactive trailing slot for counters, shortcuts, or toggle actions.", example: "trailingAction={<span>12 results</span>}" },
63
- { name: "replaceTrailingWhenClear", type: "boolean", defaultValue: "true", description: "Controls whether clear replaces trailing content or sits beside it." },
64
- { name: "clearOnEscape", type: "boolean", defaultValue: "false", description: "Clears the value on Escape when clearable mode is active." },
65
- { name: "disabled", type: "boolean", defaultValue: "false", description: "Disables editing and interaction." },
56
+ { name: "value", type: "string | number", defaultValue: "-", description: "Controlled input value.", example: "value={name}" },
57
+ { name: "defaultValue", type: "string | number", defaultValue: "-", description: "Uncontrolled initial value." },
58
+ { name: "kind", type: "'text' | 'search' | 'password' | 'number' | 'phone' | 'money' | 'quantity' | 'masked' | 'date' | 'date-range'", defaultValue: "'text'", description: "Routes Input into a supported preset without teaching a new public component name first.", example: "kind=\"search\"" },
59
+ { name: "onChange", type: "ChangeEventHandler<HTMLInputElement>", defaultValue: "-", description: "Native change handler for value updates.", example: "onChange={(event) => setValue(event.target.value)}" },
60
+ { name: "onValueChange", type: "(value: string) => void", defaultValue: "-", description: "Direct text callback for controlled string flows.", example: "onValueChange={setQuery}" },
61
+ { name: "type", type: "HTMLInputTypeAttribute", defaultValue: "'text'", description: "Native input type. Prefer presets only when formatting or masking is required." },
62
+ { name: "placeholder", type: "string", defaultValue: "-", description: "Short hint for empty input state." },
63
+ { name: "leading", type: "ReactNode", defaultValue: "-", description: "Non-interactive leading slot for icons, prefixes, or labels." },
64
+ { name: "trailing", type: "ReactNode", defaultValue: "-", description: "Passive trailing slot for units, counts, or status copy." },
65
+ { name: "clearable", type: "boolean", defaultValue: "false", description: "Shows the built-in clear action when a value exists.", example: "clearable" },
66
+ { name: "onClear", type: "() => void", defaultValue: "-", description: "Called after the built-in clear action resets the field." },
67
+ { name: "trailingAction", type: "ReactNode", defaultValue: "-", description: "Interactive trailing slot for counters, shortcuts, or toggle actions.", example: "trailingAction={<span>12 results</span>}" },
68
+ { name: "replaceTrailingWhenClear", type: "boolean", defaultValue: "true", description: "Controls whether clear replaces trailing content or sits beside it." },
69
+ { name: "clearOnEscape", type: "boolean", defaultValue: "false", description: "Clears the value on Escape when clearable mode is active." },
70
+ { name: "helperText", type: "ReactNode", defaultValue: "-", description: "Support copy rendered below the field." },
71
+ { name: "errorText", type: "ReactNode", defaultValue: "-", description: "Validation copy rendered below the field and connected to danger styling." },
72
+ { name: "showCharacterCount", type: "boolean", defaultValue: "false", description: "Shows current length and maxLength when available." },
73
+ { name: "disabled", type: "boolean", defaultValue: "false", description: "Disables editing and interaction." },
66
74
  { name: "required", type: "boolean", defaultValue: "false", description: "Marks the input as required for native validation." },
67
75
  { name: "name", type: "string", defaultValue: "-", description: "Form field name used during submission." },
68
76
  { name: "id", type: "string", defaultValue: "-", description: "Connects input to label and help text." },
@@ -75,27 +83,57 @@ export const componentApiSchemas: Record<string, ComponentApiSchema> = {
75
83
  ],
76
84
  accessibility: ["Always pair form inputs with labels.", "Use aria-describedby for helper/error text.", "Keep disabled and read-only states visually distinct."],
77
85
  },
78
- select: {
79
- slug: "select",
80
- source: "metadata",
81
- summary: "Primary selection surface. Start with Select and move into members only when async loading, multi-selection, or command-style filtering is required.",
82
- props: [
83
- { name: "value", type: "string | string[]", defaultValue: "-", description: "Controlled selected value. Multi-select uses an array." },
84
- { name: "defaultValue", type: "string | string[]", defaultValue: "-", description: "Uncontrolled initial selected value." },
85
- { name: "onValueChange", type: "(value: string | string[]) => void", defaultValue: "-", description: "Called when the selected value changes.", example: "onValueChange={setStatus}" },
86
- { name: "options", type: "Array<{ label: string; value: string; disabled?: boolean }>", defaultValue: "[]", required: true, description: "Selectable option list." },
87
- { name: "placeholder", type: "string", defaultValue: "-", description: "Text shown when no value is selected." },
88
- { name: "disabled", type: "boolean", defaultValue: "false", description: "Disables the control and option selection." },
89
- { name: "searchable", type: "boolean", defaultValue: "false", description: "Enables local filtering on the main Select surface." },
90
- { name: "multiple", type: "boolean", defaultValue: "false", description: "Allows multiple values when the active member supports it." },
91
- ],
92
- examples: [
93
- { title: "Primary select", code: "<Select value={status} onValueChange={setStatus} options={statusOptions} />" },
94
- { title: "Searchable primary select", code: "<Select value={owner} onValueChange={setOwner} searchable options={ownerOptions} />" },
95
- { title: "Async member direction", code: "// Prefer Select first; use AsyncSelect only when remote loading is required." },
96
- ],
97
- accessibility: ["Use clear option labels.", "Keep disabled options visible but not selectable.", "Do not replace long forms with hidden select menus."],
98
- },
86
+ select: {
87
+ slug: "select",
88
+ source: "metadata",
89
+ summary: "Primary single-selection surface. Start with Select for finite option sets, then use AsyncSelect with isMulti only when remote loading or multi-value behavior is required.",
90
+ props: [
91
+ { name: "value", type: "string | null", defaultValue: "-", description: "Controlled selected value." },
92
+ { name: "defaultValue", type: "string | null", defaultValue: "-", description: "Uncontrolled initial selected value." },
93
+ { name: "onValueChange", type: "(value: string | undefined) => void", defaultValue: "-", description: "Called when the selected value changes.", example: "onValueChange={setStatus}" },
94
+ { name: "options", type: "Array<{ label: string; value: string; disabled?: boolean }>", defaultValue: "[]", required: true, description: "Selectable option list." },
95
+ { name: "groups", type: "Array<{ label?: ReactNode; options: SelectOption[] }>", defaultValue: "-", description: "Grouped selectable options for longer finite lists." },
96
+ { name: "placeholder", type: "string", defaultValue: "-", description: "Text shown when no value is selected." },
97
+ { name: "disabled", type: "boolean", defaultValue: "false", description: "Disables the control and option selection." },
98
+ { name: "searchable", type: "boolean", defaultValue: "false", description: "Enables local filtering on the main Select surface." },
99
+ { name: "clearable", type: "boolean", defaultValue: "false", description: "Shows a clear action when a value is selected." },
100
+ { name: "loading", type: "boolean", defaultValue: "false", description: "Disables selection and renders a loading state." },
101
+ { name: "emptyLabel", type: "ReactNode", defaultValue: "'No options found'", description: "Empty state content for local filtering." },
102
+ { name: "emptyMessage", type: "ReactNode", defaultValue: "-", description: "Alias for empty state content used by newer docs." },
103
+ { name: "renderOption", type: "(option, state) => ReactNode", defaultValue: "-", description: "Custom option renderer for richer rows." },
104
+ ],
105
+ examples: [
106
+ { title: "Primary select", code: "<Select value={status} onValueChange={setStatus} options={statusOptions} />" },
107
+ { title: "Searchable primary select", code: "<Select value={owner} onValueChange={setOwner} searchable options={ownerOptions} />" },
108
+ { title: "Grouped select", code: "<Select value={region} onValueChange={setRegion} groups={regionGroups} searchable />" },
109
+ { title: "Async member direction", code: "// Prefer Select first; use AsyncSelect only when remote loading is required." },
110
+ ],
111
+ accessibility: ["Use clear option labels.", "Keep disabled options visible but not selectable.", "Do not replace long forms with hidden select menus."],
112
+ },
113
+ textarea: {
114
+ slug: "textarea",
115
+ source: "metadata",
116
+ summary: "Multi-line text entry surface with helper, error, read-only, disabled and character-count support.",
117
+ props: [
118
+ { name: "value", type: "string", defaultValue: "-", description: "Controlled textarea value." },
119
+ { name: "defaultValue", type: "string", defaultValue: "-", description: "Uncontrolled initial value." },
120
+ { name: "onChange", type: "ChangeEventHandler<HTMLTextAreaElement>", defaultValue: "-", description: "Native change handler." },
121
+ { name: "onValueChange", type: "(value: string) => void", defaultValue: "-", description: "Direct text callback for controlled flows." },
122
+ { name: "rows", type: "number", defaultValue: "-", description: "Initial visible row count." },
123
+ { name: "maxLength", type: "number", defaultValue: "-", description: "Native maximum character length." },
124
+ { name: "helperText", type: "ReactNode", defaultValue: "-", description: "Support copy rendered below the field." },
125
+ { name: "errorText", type: "ReactNode", defaultValue: "-", description: "Validation copy rendered below the field and danger styling." },
126
+ { name: "showCharacterCount", type: "boolean", defaultValue: "false", description: "Shows current length and maxLength when available." },
127
+ { name: "disabled", type: "boolean", defaultValue: "false", description: "Disables editing." },
128
+ { name: "readOnly", type: "boolean", defaultValue: "false", description: "Keeps content copyable while preventing edits." },
129
+ ],
130
+ examples: [
131
+ { title: "Controlled note", code: "<Textarea value={note} onValueChange={setNote} helperText=\"Internal note\" />" },
132
+ { title: "Limited feedback", code: "<Textarea maxLength={240} showCharacterCount />" },
133
+ { title: "Error state", code: "<Textarea errorText=\"Please add at least 10 characters.\" />" },
134
+ ],
135
+ accessibility: ["Pair textareas with visible labels.", "Use helper and error copy instead of placeholder-only instructions.", "Keep read-only distinct from disabled."],
136
+ },
99
137
  "data-table": {
100
138
  slug: "data-table",
101
139
  source: "metadata",
@@ -63,16 +63,17 @@ function createCodeSnippet(definition: ShowcaseDemoDefinition) {
63
63
  }
64
64
 
65
65
  const exactCodeSnippets: Record<string, string> = {
66
- "search-input": `import { SearchInput } from "tembro"
67
-
68
- export function Demo() {
69
- return (
70
- <SearchInput
71
- value="invoice"
72
- onValueChange={(value) => console.log(value)}
73
- placeholder="Search invoices..."
74
- resultCount={12}
75
- shortcut="Ctrl K"
66
+ "search-input": `import { Input } from "tembro"
67
+
68
+ export function Demo() {
69
+ return (
70
+ <Input
71
+ type="search"
72
+ value="invoice"
73
+ onValueChange={(value) => console.log(value)}
74
+ placeholder="Search invoices..."
75
+ resultCount={12}
76
+ shortcut="Ctrl K"
76
77
  />
77
78
  )
78
79
  }`,
@@ -133,12 +134,12 @@ export function Demo() {
133
134
  />
134
135
  )
135
136
  }`,
136
- "filter-bar": `import { Button, FilterBar, SearchInput } from "tembro"
137
-
138
- export function Demo() {
139
- return (
137
+ "filter-bar": `import { Button, FilterBar, Input } from "tembro"
138
+
139
+ export function Demo() {
140
+ return (
140
141
  <FilterBar
141
- search={<SearchInput value="" placeholder="Search rows..." readOnly />}
142
+ search={<Input type="search" value="" placeholder="Search rows..." readOnly />}
142
143
  chips={[
143
144
  { key: "status", label: "Status", value: "Active", tone: "success" },
144
145
  { key: "owner", label: "Owner", value: "Azamat" },