tembro 6.0.3 → 6.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (253) hide show
  1. package/CHANGELOG.md +13 -0
  2. package/dist/components/actions/action-menu.d.ts +11 -1
  3. package/dist/components/calendar/calendar-range-scheduler.cjs +1 -0
  4. package/dist/components/calendar/calendar-range-scheduler.d.ts +20 -0
  5. package/dist/components/calendar/calendar-range-scheduler.js +1 -0
  6. package/dist/components/calendar/date-time-picker.cjs +1 -0
  7. package/dist/components/calendar/date-time-picker.d.ts +15 -0
  8. package/dist/components/calendar/date-time-picker.js +1 -0
  9. package/dist/components/calendar/index.d.ts +2 -0
  10. package/dist/components/charts/chart-card.cjs +1 -0
  11. package/dist/components/charts/chart-card.d.ts +24 -0
  12. package/dist/components/charts/chart-card.js +1 -0
  13. package/dist/components/charts/index.d.ts +1 -0
  14. package/dist/components/command/advanced-command-menu.cjs +1 -0
  15. package/dist/components/command/advanced-command-menu.d.ts +25 -0
  16. package/dist/components/command/advanced-command-menu.js +1 -0
  17. package/dist/components/command/index.d.ts +1 -0
  18. package/dist/components/data-table/data-grid.cjs +1 -0
  19. package/dist/components/data-table/data-grid.d.ts +15 -0
  20. package/dist/components/data-table/data-grid.js +1 -0
  21. package/dist/components/data-table/index.d.ts +1 -0
  22. package/dist/components/data-table/public.d.ts +1 -0
  23. package/dist/components/display/index.d.ts +0 -2
  24. package/dist/components/feedback/async-boundary.cjs +1 -0
  25. package/dist/components/feedback/async-boundary.d.ts +12 -0
  26. package/dist/components/feedback/async-boundary.js +1 -0
  27. package/dist/components/feedback/index.d.ts +1 -0
  28. package/dist/components/filters/index.d.ts +0 -1
  29. package/dist/components/inputs/index.d.ts +1 -0
  30. package/dist/components/inputs/multi-select.cjs +1 -0
  31. package/dist/components/inputs/multi-select.d.ts +16 -0
  32. package/dist/components/inputs/multi-select.js +1 -0
  33. package/dist/components/inputs/public.d.ts +1 -0
  34. package/dist/components/inputs/time-picker.d.ts +11 -3
  35. package/dist/components/modern/file-manager.cjs +1 -0
  36. package/dist/components/modern/file-manager.d.ts +20 -0
  37. package/dist/components/modern/file-manager.js +1 -0
  38. package/dist/components/modern/index.d.ts +4 -1
  39. package/dist/components/modern/map.cjs +1 -0
  40. package/dist/components/modern/map.d.ts +29 -0
  41. package/dist/components/modern/map.js +1 -0
  42. package/dist/components/modern/media-player.cjs +1 -0
  43. package/dist/components/modern/media-player.d.ts +21 -0
  44. package/dist/components/modern/media-player.js +1 -0
  45. package/dist/components/modern/spreadsheet.cjs +1 -0
  46. package/dist/components/modern/spreadsheet.d.ts +35 -0
  47. package/dist/components/modern/spreadsheet.js +1 -0
  48. package/dist/components/notifications/action-toast.cjs +1 -0
  49. package/dist/components/notifications/action-toast.d.ts +16 -0
  50. package/dist/components/notifications/action-toast.js +1 -0
  51. package/dist/components/notifications/index.d.ts +1 -0
  52. package/dist/components/overlay/drawer.d.ts +3 -1
  53. package/dist/components/patterns/index.d.ts +1 -0
  54. package/dist/components/patterns/permissions-matrix.cjs +1 -0
  55. package/dist/components/patterns/permissions-matrix.d.ts +19 -0
  56. package/dist/components/patterns/permissions-matrix.js +1 -0
  57. package/dist/components/patterns/public.d.ts +1 -0
  58. package/dist/index.d.ts +0 -2
  59. package/dist/src/components/actions/action-menu.cjs +1 -1
  60. package/dist/src/components/actions/action-menu.js +47 -39
  61. package/dist/src/components/actions/copy-button.cjs +1 -1
  62. package/dist/src/components/actions/copy-button.js +4 -1
  63. package/dist/src/components/calendar/calendar-range-scheduler.cjs +1 -0
  64. package/dist/src/components/calendar/calendar-range-scheduler.js +75 -0
  65. package/dist/src/components/calendar/date-picker.cjs +1 -1
  66. package/dist/src/components/calendar/date-picker.js +5 -8
  67. package/dist/src/components/calendar/date-range-picker.cjs +1 -1
  68. package/dist/src/components/calendar/date-range-picker.js +12 -27
  69. package/dist/src/components/calendar/date-time-picker.cjs +1 -0
  70. package/dist/src/components/calendar/date-time-picker.js +36 -0
  71. package/dist/src/components/calendar/index.cjs +1 -1
  72. package/dist/src/components/calendar/index.js +5 -3
  73. package/dist/src/components/charts/chart-card.cjs +1 -0
  74. package/dist/src/components/charts/chart-card.js +55 -0
  75. package/dist/src/components/charts/index.cjs +1 -1
  76. package/dist/src/components/charts/index.js +3 -2
  77. package/dist/src/components/command/advanced-command-menu.cjs +1 -0
  78. package/dist/src/components/command/advanced-command-menu.js +57 -0
  79. package/dist/src/components/command/index.cjs +1 -1
  80. package/dist/src/components/command/index.js +3 -2
  81. package/dist/src/components/data-table/data-grid.cjs +1 -0
  82. package/dist/src/components/data-table/data-grid.js +32 -0
  83. package/dist/src/components/data-table/data-table-saved-filters.cjs +1 -1
  84. package/dist/src/components/data-table/data-table-saved-filters.js +11 -11
  85. package/dist/src/components/data-table/data-table.cjs +1 -1
  86. package/dist/src/components/data-table/data-table.js +175 -174
  87. package/dist/src/components/data-table/index.cjs +1 -1
  88. package/dist/src/components/data-table/index.js +15 -14
  89. package/dist/src/components/data-table/public.cjs +1 -1
  90. package/dist/src/components/data-table/public.js +3 -2
  91. package/dist/src/components/display/index.cjs +1 -1
  92. package/dist/src/components/display/index.js +9 -11
  93. package/dist/src/components/feedback/async-boundary.cjs +1 -0
  94. package/dist/src/components/feedback/async-boundary.js +22 -0
  95. package/dist/src/components/feedback/index.cjs +1 -1
  96. package/dist/src/components/feedback/index.js +2 -1
  97. package/dist/src/components/filters/index.cjs +1 -1
  98. package/dist/src/components/filters/index.js +2 -3
  99. package/dist/src/components/inputs/color-picker.cjs +1 -1
  100. package/dist/src/components/inputs/color-picker.js +63 -46
  101. package/dist/src/components/inputs/index.cjs +1 -1
  102. package/dist/src/components/inputs/index.js +13 -12
  103. package/dist/src/components/inputs/multi-select.cjs +1 -0
  104. package/dist/src/components/inputs/multi-select.js +80 -0
  105. package/dist/src/components/inputs/public.cjs +1 -1
  106. package/dist/src/components/inputs/public.js +13 -12
  107. package/dist/src/components/inputs/slider.cjs +1 -1
  108. package/dist/src/components/inputs/slider.js +3 -3
  109. package/dist/src/components/inputs/tag-input.cjs +1 -1
  110. package/dist/src/components/inputs/tag-input.js +7 -4
  111. package/dist/src/components/inputs/time-picker.cjs +1 -1
  112. package/dist/src/components/inputs/time-picker.js +90 -34
  113. package/dist/src/components/modern/file-manager.cjs +1 -0
  114. package/dist/src/components/modern/file-manager.js +75 -0
  115. package/dist/src/components/modern/index.cjs +1 -1
  116. package/dist/src/components/modern/index.js +7 -4
  117. package/dist/src/components/modern/map.cjs +1 -0
  118. package/dist/src/components/modern/map.js +158 -0
  119. package/dist/src/components/modern/media-player.cjs +1 -0
  120. package/dist/src/components/modern/media-player.js +176 -0
  121. package/dist/src/components/modern/resizable-panel.cjs +1 -1
  122. package/dist/src/components/modern/resizable-panel.js +39 -32
  123. package/dist/src/components/modern/spreadsheet.cjs +1 -0
  124. package/dist/src/components/modern/spreadsheet.js +97 -0
  125. package/dist/src/components/navigation/pagination.cjs +1 -1
  126. package/dist/src/components/navigation/pagination.js +5 -5
  127. package/dist/src/components/notifications/action-toast.cjs +1 -0
  128. package/dist/src/components/notifications/action-toast.js +49 -0
  129. package/dist/src/components/notifications/index.cjs +1 -1
  130. package/dist/src/components/notifications/index.js +3 -2
  131. package/dist/src/components/notifications/toast.cjs +1 -1
  132. package/dist/src/components/notifications/toast.js +68 -63
  133. package/dist/src/components/overlay/alert-dialog.cjs +1 -1
  134. package/dist/src/components/overlay/alert-dialog.js +8 -6
  135. package/dist/src/components/overlay/drawer.cjs +1 -1
  136. package/dist/src/components/overlay/drawer.js +38 -20
  137. package/dist/src/components/patterns/index.cjs +1 -1
  138. package/dist/src/components/patterns/index.js +2 -1
  139. package/dist/src/components/patterns/permissions-matrix.cjs +1 -0
  140. package/dist/src/components/patterns/permissions-matrix.js +43 -0
  141. package/dist/src/components/patterns/public.cjs +1 -1
  142. package/dist/src/components/patterns/public.js +2 -1
  143. package/dist/src/components/ui/checkbox/index.cjs +1 -1
  144. package/dist/src/components/ui/checkbox/index.js +2 -1
  145. package/dist/src/components/ui/dialog/index.cjs +1 -1
  146. package/dist/src/components/ui/dialog/index.js +8 -8
  147. package/dist/src/components/ui/dropdown-menu/index.cjs +1 -1
  148. package/dist/src/components/ui/dropdown-menu/index.js +21 -19
  149. package/dist/src/components/ui/input/group.cjs +1 -1
  150. package/dist/src/components/ui/input/group.js +8 -8
  151. package/dist/src/components/ui/popover/index.cjs +1 -1
  152. package/dist/src/components/ui/popover/index.js +10 -10
  153. package/dist/src/components/ui/tabs/index.cjs +1 -1
  154. package/dist/src/components/ui/tabs/index.js +6 -6
  155. package/dist/src/components/ui/toggle-group/index.cjs +1 -1
  156. package/dist/src/components/ui/toggle-group/index.js +2 -2
  157. package/dist/src/index.cjs +1 -1
  158. package/dist/src/index.js +111 -104
  159. package/dist/src/public-component-surface.cjs +1 -1
  160. package/dist/src/public-component-surface.js +59 -14
  161. package/package.json +1 -2
  162. package/packages/cli/dist/index.cjs +45 -165
  163. package/packages/cli/vendor/src/components/actions/action-menu.tsx +47 -19
  164. package/packages/cli/vendor/src/components/actions/copy-button.tsx +2 -2
  165. package/packages/cli/vendor/src/components/calendar/calendar-range-scheduler.tsx +72 -0
  166. package/packages/cli/vendor/src/components/calendar/date-picker.tsx +2 -5
  167. package/packages/cli/vendor/src/components/calendar/date-range-picker.tsx +5 -12
  168. package/packages/cli/vendor/src/components/calendar/date-time-picker.tsx +53 -0
  169. package/packages/cli/vendor/src/components/calendar/index.ts +5 -3
  170. package/packages/cli/vendor/src/components/charts/chart-card.tsx +81 -0
  171. package/packages/cli/vendor/src/components/charts/index.ts +1 -0
  172. package/packages/cli/vendor/src/components/command/advanced-command-menu.tsx +88 -0
  173. package/packages/cli/vendor/src/components/command/index.ts +2 -1
  174. package/packages/cli/vendor/src/components/data-table/data-grid.tsx +59 -0
  175. package/packages/cli/vendor/src/components/data-table/data-table.tsx +45 -34
  176. package/packages/cli/vendor/src/components/data-table/index.ts +3 -2
  177. package/packages/cli/vendor/src/components/data-table/public.ts +1 -0
  178. package/packages/cli/vendor/src/components/display/index.ts +3 -5
  179. package/packages/cli/vendor/src/components/feedback/async-boundary.tsx +36 -0
  180. package/packages/cli/vendor/src/components/feedback/index.ts +1 -0
  181. package/packages/cli/vendor/src/components/filters/index.ts +0 -1
  182. package/packages/cli/vendor/src/components/inputs/color-picker.tsx +15 -1
  183. package/packages/cli/vendor/src/components/inputs/index.ts +1 -0
  184. package/packages/cli/vendor/src/components/inputs/multi-select.tsx +75 -0
  185. package/packages/cli/vendor/src/components/inputs/public.ts +1 -0
  186. package/packages/cli/vendor/src/components/inputs/slider.tsx +3 -3
  187. package/packages/cli/vendor/src/components/inputs/tag-input.tsx +4 -4
  188. package/packages/cli/vendor/src/components/inputs/time-picker.tsx +91 -38
  189. package/packages/cli/vendor/src/components/modern/file-manager.tsx +79 -0
  190. package/packages/cli/vendor/src/components/modern/index.ts +4 -1
  191. package/packages/cli/vendor/src/components/modern/map.tsx +146 -0
  192. package/packages/cli/vendor/src/components/modern/media-player.tsx +182 -0
  193. package/packages/cli/vendor/src/components/modern/resizable-panel.tsx +15 -5
  194. package/packages/cli/vendor/src/components/modern/spreadsheet.tsx +155 -0
  195. package/packages/cli/vendor/src/components/navigation/pagination.tsx +9 -5
  196. package/packages/cli/vendor/src/components/notifications/action-toast.tsx +78 -0
  197. package/packages/cli/vendor/src/components/notifications/index.ts +2 -1
  198. package/packages/cli/vendor/src/components/notifications/toast.tsx +20 -10
  199. package/packages/cli/vendor/src/components/overlay/alert-dialog.tsx +3 -5
  200. package/packages/cli/vendor/src/components/overlay/drawer.tsx +22 -11
  201. package/packages/cli/vendor/src/components/patterns/index.ts +1 -0
  202. package/packages/cli/vendor/src/components/patterns/permissions-matrix.tsx +71 -0
  203. package/packages/cli/vendor/src/components/patterns/public.ts +1 -0
  204. package/packages/cli/vendor/src/components/ui/checkbox/index.tsx +3 -1
  205. package/packages/cli/vendor/src/components/ui/dialog/index.tsx +4 -4
  206. package/packages/cli/vendor/src/components/ui/dropdown-menu/index.tsx +18 -22
  207. package/packages/cli/vendor/src/components/ui/popover/index.tsx +4 -4
  208. package/packages/cli/vendor/src/components/ui/tabs/index.tsx +8 -3
  209. package/packages/cli/vendor/src/components/ui/toggle-group/index.tsx +6 -6
  210. package/packages/cli/vendor/src/index.ts +0 -2
  211. package/packages/cli/vendor/src/public-component-surface.ts +13 -4
  212. package/packages/cli/vendor/templates/showcase/src/showcase/data/registry.ts +6 -6
  213. package/packages/cli/vendor/templates/showcase/src/showcase/layout/HeroSection.tsx +23 -8
  214. package/packages/cli/vendor/templates/showcase/src/showcase/layout/WorkbenchSidebar.tsx +1 -1
  215. package/packages/cli/vendor/templates/showcase/src/showcase/sections/PatternsSection.tsx +1 -1
  216. package/packages/cli/vendor/templates/styles/globals.css +0 -120
  217. package/registry.json +3197 -2794
  218. package/dist/components/display/info-card.cjs +0 -1
  219. package/dist/components/display/info-card.d.ts +0 -51
  220. package/dist/components/display/info-card.js +0 -1
  221. package/dist/components/display/statistic.cjs +0 -1
  222. package/dist/components/display/statistic.d.ts +0 -25
  223. package/dist/components/display/statistic.js +0 -1
  224. package/dist/components/filters/filter-bar.cjs +0 -1
  225. package/dist/components/filters/filter-bar.d.ts +0 -28
  226. package/dist/components/filters/filter-bar.js +0 -1
  227. package/dist/components/modern/image-cropper.cjs +0 -1
  228. package/dist/components/modern/image-cropper.d.ts +0 -39
  229. package/dist/components/modern/image-cropper.js +0 -1
  230. package/dist/components/ui/number-field/index.cjs +0 -1
  231. package/dist/components/ui/number-field/index.d.ts +0 -18
  232. package/dist/components/ui/number-field/index.js +0 -1
  233. package/dist/components/ui/toolbar/index.cjs +0 -1
  234. package/dist/components/ui/toolbar/index.d.ts +0 -14
  235. package/dist/components/ui/toolbar/index.js +0 -1
  236. package/dist/src/components/display/info-card.cjs +0 -1
  237. package/dist/src/components/display/info-card.js +0 -124
  238. package/dist/src/components/display/statistic.cjs +0 -1
  239. package/dist/src/components/display/statistic.js +0 -104
  240. package/dist/src/components/filters/filter-bar.cjs +0 -1
  241. package/dist/src/components/filters/filter-bar.js +0 -103
  242. package/dist/src/components/modern/image-cropper.cjs +0 -1
  243. package/dist/src/components/modern/image-cropper.js +0 -143
  244. package/dist/src/components/ui/number-field/index.cjs +0 -1
  245. package/dist/src/components/ui/number-field/index.js +0 -73
  246. package/dist/src/components/ui/toolbar/index.cjs +0 -1
  247. package/dist/src/components/ui/toolbar/index.js +0 -50
  248. package/packages/cli/vendor/src/components/display/info-card.tsx +0 -195
  249. package/packages/cli/vendor/src/components/display/statistic.tsx +0 -114
  250. package/packages/cli/vendor/src/components/filters/filter-bar.tsx +0 -163
  251. package/packages/cli/vendor/src/components/modern/image-cropper.tsx +0 -226
  252. package/packages/cli/vendor/src/components/ui/number-field/index.tsx +0 -89
  253. package/packages/cli/vendor/src/components/ui/toolbar/index.tsx +0 -67
@@ -14,13 +14,15 @@ import { cn } from "@/lib/utils"
14
14
 
15
15
  export type DrawerSide = "left" | "right" | "top" | "bottom"
16
16
  export type DrawerWidth = "sm" | "md" | "lg" | "xl" | "full"
17
-
17
+ export type DrawerDensity = "compact" | "default" | "comfortable"
18
+
18
19
  export type DrawerProps = Omit<React.ComponentProps<typeof Dialog>, "children"> & {
19
20
  trigger?: React.ReactNode
20
21
  title?: React.ReactNode
21
22
  description?: React.ReactNode
22
23
  side?: DrawerSide
23
24
  width?: DrawerWidth
25
+ density?: DrawerDensity
24
26
  footer?: React.ReactNode
25
27
  headerClassName?: string
26
28
  bodyClassName?: string
@@ -29,12 +31,12 @@ export type DrawerProps = Omit<React.ComponentProps<typeof Dialog>, "children">
29
31
  showCloseButton?: boolean
30
32
  children?: React.ReactNode
31
33
  }
32
-
34
+
33
35
  const sideClassName: Record<DrawerSide, string> = {
34
- right: "left-auto right-0 top-0 h-dvh max-h-dvh w-full translate-x-0 translate-y-0 rounded-none rounded-l-[var(--radius-3xl)] data-open:slide-in-from-right data-closed:slide-out-to-right",
35
- left: "left-0 top-0 h-dvh max-h-dvh w-full translate-x-0 translate-y-0 rounded-none rounded-r-[var(--radius-3xl)] data-open:slide-in-from-left data-closed:slide-out-to-left",
36
- top: "left-0 top-0 h-auto max-h-[85dvh] w-full max-w-none translate-x-0 translate-y-0 rounded-none rounded-b-[var(--radius-3xl)] data-open:slide-in-from-top data-closed:slide-out-to-top",
37
- bottom: "bottom-0 left-0 top-auto h-auto max-h-[85dvh] w-full max-w-none translate-x-0 translate-y-0 rounded-none rounded-t-[var(--radius-3xl)] data-open:slide-in-from-bottom data-closed:slide-out-to-bottom",
36
+ right: "!left-auto !right-0 !top-0 !h-dvh !max-h-dvh !w-full !translate-x-0 !translate-y-0 rounded-none rounded-l-[var(--radius-3xl)] data-open:slide-in-from-right data-closed:slide-out-to-right",
37
+ left: "!left-0 !top-0 !h-dvh !max-h-dvh !w-full !translate-x-0 !translate-y-0 rounded-none rounded-r-[var(--radius-3xl)] data-open:slide-in-from-left data-closed:slide-out-to-left",
38
+ top: "!left-0 !top-0 !h-auto !max-h-[85dvh] !w-full !max-w-none !translate-x-0 !translate-y-0 rounded-none rounded-b-[var(--radius-3xl)] data-open:slide-in-from-top data-closed:slide-out-to-top",
39
+ bottom: "!bottom-0 !left-0 !top-auto !h-auto !max-h-[85dvh] !w-full !max-w-none !translate-x-0 !translate-y-0 rounded-none rounded-t-[var(--radius-3xl)] data-open:slide-in-from-bottom data-closed:slide-out-to-bottom",
38
40
  }
39
41
 
40
42
  const widthClassName: Record<DrawerWidth, string> = {
@@ -44,13 +46,20 @@ const widthClassName: Record<DrawerWidth, string> = {
44
46
  xl: "sm:max-w-2xl",
45
47
  full: "max-w-none sm:max-w-[min(100vw,72rem)]",
46
48
  }
47
-
48
- function Drawer({
49
+
50
+ const densityClassName: Record<DrawerDensity, { header: string; body: string; footer: string }> = {
51
+ compact: { header: "p-4", body: "p-4", footer: "p-4" },
52
+ default: { header: "p-5", body: "p-5", footer: "p-5" },
53
+ comfortable: { header: "p-6", body: "p-6", footer: "p-6" },
54
+ }
55
+
56
+ function Drawer({
49
57
  trigger,
50
58
  title,
51
59
  description,
52
60
  side = "right",
53
61
  width = "lg",
62
+ density = "default",
54
63
  footer,
55
64
  headerClassName,
56
65
  bodyClassName,
@@ -65,21 +74,23 @@ function Drawer({
65
74
  {trigger ? <DialogTrigger render={trigger as React.ReactElement} /> : null}
66
75
  <DialogContent
67
76
  size="full"
77
+ surface="plain"
68
78
  showCloseButton={showCloseButton}
69
79
  data-side={side}
70
80
  data-width={width}
81
+ data-density={density}
71
82
  className={cn("fixed grid grid-rows-[auto_minmax(0,1fr)_auto] gap-0 overscroll-contain p-0", sideClassName[side], (side === "left" || side === "right") && widthClassName[width], contentClassName)}
72
83
  >
73
84
  {(title || description) && (
74
- <DialogHeader className={cn("border-b border-border/70 p-6", headerClassName)}>
85
+ <DialogHeader className={cn("border-b border-border/70 bg-background/95 backdrop-blur", densityClassName[density].header, headerClassName)}>
75
86
  {title ? <DialogTitle>{title}</DialogTitle> : null}
76
87
  {description ? <DialogDescription>{description}</DialogDescription> : null}
77
88
  </DialogHeader>
78
89
  )}
79
- <div data-slot="drawer-body" className={cn("min-h-0 flex-1 overflow-y-auto p-6", bodyClassName)}>
90
+ <div data-slot="drawer-body" className={cn("min-h-0 flex-1 overflow-y-auto bg-background", densityClassName[density].body, bodyClassName)}>
80
91
  {children}
81
92
  </div>
82
- {footer ? <div data-slot="drawer-footer" className={cn("border-t border-border/70 p-5", footerClassName)}>{footer}</div> : null}
93
+ {footer ? <div data-slot="drawer-footer" className={cn("border-t border-border/70 bg-background/95 backdrop-blur", densityClassName[density].footer, footerClassName)}>{footer}</div> : null}
83
94
  </DialogContent>
84
95
  </Dialog>
85
96
  )
@@ -1 +1,2 @@
1
1
  export * from "./empty-state"
2
+ export * from "./permissions-matrix"
@@ -0,0 +1,71 @@
1
+ "use client"
2
+
3
+ import * as React from "react"
4
+
5
+ import { Checkbox } from "@/components/ui/checkbox"
6
+ import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from "@/components/ui/table"
7
+ import { cn } from "@/lib/utils"
8
+
9
+ export type PermissionMatrixRole = {
10
+ key: string
11
+ label: React.ReactNode
12
+ }
13
+
14
+ export type PermissionMatrixPermission = {
15
+ key: string
16
+ label: React.ReactNode
17
+ description?: React.ReactNode
18
+ }
19
+
20
+ export type PermissionMatrixValue = Record<string, string[]>
21
+
22
+ export type PermissionsMatrixProps = React.ComponentProps<"div"> & {
23
+ roles: PermissionMatrixRole[]
24
+ permissions: PermissionMatrixPermission[]
25
+ value?: PermissionMatrixValue
26
+ onValueChange?: (value: PermissionMatrixValue) => void
27
+ }
28
+
29
+ function PermissionsMatrix({ roles, permissions, value = {}, onValueChange, className, ...props }: PermissionsMatrixProps) {
30
+ const toggle = (permissionKey: string, roleKey: string) => {
31
+ const current = value[permissionKey] ?? []
32
+ const next = current.includes(roleKey) ? current.filter((item) => item !== roleKey) : [...current, roleKey]
33
+ onValueChange?.({ ...value, [permissionKey]: next })
34
+ }
35
+
36
+ return (
37
+ <div data-slot="permissions-matrix" className={cn("overflow-hidden rounded-lg border", className)} {...props}>
38
+ <Table>
39
+ <TableHeader>
40
+ <TableRow>
41
+ <TableHead>Permission</TableHead>
42
+ {roles.map((role) => <TableHead key={role.key} className="text-center">{role.label}</TableHead>)}
43
+ </TableRow>
44
+ </TableHeader>
45
+ <TableBody>
46
+ {permissions.map((permission) => (
47
+ <TableRow key={permission.key}>
48
+ <TableCell>
49
+ <span className="grid gap-0.5">
50
+ <span className="font-medium">{permission.label}</span>
51
+ {permission.description ? <span className="text-xs text-muted-foreground">{permission.description}</span> : null}
52
+ </span>
53
+ </TableCell>
54
+ {roles.map((role) => (
55
+ <TableCell key={role.key} className="text-center">
56
+ <Checkbox
57
+ aria-label={`${permission.label} for ${role.label}`}
58
+ checked={(value[permission.key] ?? []).includes(role.key)}
59
+ onCheckedChange={() => toggle(permission.key, role.key)}
60
+ />
61
+ </TableCell>
62
+ ))}
63
+ </TableRow>
64
+ ))}
65
+ </TableBody>
66
+ </Table>
67
+ </div>
68
+ )
69
+ }
70
+
71
+ export { PermissionsMatrix }
@@ -1 +1,2 @@
1
1
  export * from "./empty-state"
2
+ export * from "./permissions-matrix"
@@ -60,6 +60,8 @@ const Checkbox = React.forwardRef<HTMLButtonElement, CheckboxProps>(
60
60
  const dataState = currentChecked === "indeterminate" ? "indeterminate" : currentChecked ? "checked" : "unchecked"
61
61
 
62
62
  const handleClick: React.MouseEventHandler<HTMLButtonElement> = (event) => {
63
+ event.preventDefault()
64
+ event.stopPropagation()
63
65
  const nextChecked = getNextCheckedState(currentChecked, allowIndeterminate)
64
66
 
65
67
  if (!isControlled) {
@@ -98,7 +100,7 @@ const Checkbox = React.forwardRef<HTMLButtonElement, CheckboxProps>(
98
100
  disabled={disabled}
99
101
  aria-invalid={invalid || undefined}
100
102
  className={cn(
101
- "peer flex shrink-0 items-center justify-center rounded-[10px] border border-input/88 bg-background text-primary-foreground shadow-[inset_0_1px_0_rgba(255,255,255,0.10)] outline-none transition-[background-color,border-color,box-shadow,color,transform] hover:border-ring/30 hover:bg-background focus-visible:border-ring focus-visible:ring-3 focus-visible:ring-ring/45 disabled:cursor-not-allowed disabled:opacity-50 aria-invalid:border-destructive aria-invalid:ring-destructive/25 data-[size=sm]:size-4 data-[size=md]:size-5 data-[size=lg]:size-6 data-[state=checked]:border-primary/28 data-[state=checked]:bg-primary data-[state=checked]:shadow-[0_10px_24px_color-mix(in_oklch,var(--primary),transparent_82%)] data-[state=indeterminate]:border-primary/28 data-[state=indeterminate]:bg-primary data-[state=indeterminate]:shadow-[0_10px_24px_color-mix(in_oklch,var(--primary),transparent_82%)] dark:border-white/12 dark:bg-white/[0.04] dark:hover:bg-white/[0.08]",
103
+ "peer flex shrink-0 items-center justify-center rounded-[10px] border border-input/88 bg-background text-primary-foreground shadow-[inset_0_1px_0_rgba(255,255,255,0.10)] outline-none transition-[background-color,border-color,box-shadow,color,transform] hover:border-ring/30 hover:bg-background focus-visible:border-ring focus-visible:ring-3 focus-visible:ring-ring/45 disabled:cursor-not-allowed disabled:opacity-50 aria-invalid:border-destructive aria-invalid:ring-destructive/25 data-[size=sm]:size-4 data-[size=md]:size-5 data-[size=lg]:size-6 data-[state=checked]:border-primary/28 data-[state=checked]:bg-primary data-[state=checked]:text-primary-foreground data-[state=checked]:shadow-[0_10px_24px_color-mix(in_oklch,var(--primary),transparent_82%)] data-[state=indeterminate]:border-primary/28 data-[state=indeterminate]:bg-primary data-[state=indeterminate]:text-primary-foreground data-[state=indeterminate]:shadow-[0_10px_24px_color-mix(in_oklch,var(--primary),transparent_82%)] dark:data-[state=unchecked]:border-white/12 dark:data-[state=unchecked]:bg-white/[0.04] dark:data-[state=unchecked]:hover:bg-white/[0.08] [&_svg]:stroke-[2.6]",
102
104
  className
103
105
  )}
104
106
  onClick={handleClick}
@@ -47,7 +47,7 @@ function DialogOverlay({
47
47
  <DialogPrimitive.Backdrop
48
48
  data-slot="dialog-overlay"
49
49
  className={cn(
50
- "fixed inset-0 isolate z-50 duration-100 data-open:animate-in data-open:fade-in-0 data-closed:animate-out data-closed:fade-out-0",
50
+ "fixed inset-0 isolate z-50 bg-black/45 backdrop-blur-[2px] duration-100 data-open:animate-in data-open:fade-in-0 data-closed:animate-out data-closed:fade-out-0 dark:bg-black/62",
51
51
  className
52
52
  )}
53
53
  {...props}
@@ -73,7 +73,7 @@ function DialogContent({
73
73
  role="dialog"
74
74
  aria-modal="true"
75
75
  className={cn(
76
- "fixed top-1/2 left-1/2 z-50 grid max-h-[min(92vh,calc(100dvh-2rem))] w-full max-w-[calc(100%-2rem)] -translate-x-1/2 -translate-y-1/2 grid-rows-[auto_minmax(0,1fr)_auto] gap-5 overflow-hidden overscroll-contain duration-100 outline-none data-[surface=plain]:overflow-visible data-[size=xs]:sm:max-w-sm data-[size=sm]:sm:max-w-md data-[size=md]:sm:max-w-lg data-[size=lg]:sm:max-w-2xl data-[size=xl]:sm:max-w-4xl data-[size=full]:h-[min(92vh,56rem)] data-[size=full]:max-w-[min(96vw,84rem)] data-open:animate-in data-open:fade-in-0 data-open:zoom-in-95 data-closed:animate-out data-closed:fade-out-0 data-closed:zoom-out-95",
76
+ "fixed top-1/2 left-1/2 z-50 grid max-h-[min(92vh,calc(100dvh-2rem))] w-full max-w-[calc(100%-2rem)] -translate-x-1/2 -translate-y-1/2 grid-rows-[auto_minmax(0,1fr)_auto] gap-5 overflow-hidden overscroll-contain rounded-[var(--aui-card-radius,var(--radius-xl))] border border-border/78 bg-background p-6 text-foreground shadow-[0_32px_90px_rgba(15,23,42,0.24)] duration-100 outline-none data-[surface=plain]:overflow-visible data-[surface=plain]:border-0 data-[surface=plain]:bg-transparent data-[surface=plain]:p-0 data-[surface=plain]:shadow-none data-[size=xs]:sm:max-w-sm data-[size=sm]:sm:max-w-md data-[size=md]:sm:max-w-lg data-[size=lg]:sm:max-w-2xl data-[size=xl]:sm:max-w-4xl data-[size=full]:h-[min(92vh,56rem)] data-[size=full]:max-w-[min(96vw,84rem)] data-open:animate-in data-open:fade-in-0 data-open:zoom-in-95 data-closed:animate-out data-closed:fade-out-0 data-closed:zoom-out-95",
77
77
  className
78
78
  )}
79
79
  {...props}
@@ -148,7 +148,7 @@ function DialogTitle({ className, ...props }: DialogTitleProps) {
148
148
  return (
149
149
  <DialogPrimitive.Title
150
150
  data-slot="dialog-title"
151
- className={className}
151
+ className={cn("text-lg font-semibold tracking-tight text-foreground", className)}
152
152
  {...props}
153
153
  />
154
154
  )
@@ -161,7 +161,7 @@ function DialogDescription({
161
161
  return (
162
162
  <DialogPrimitive.Description
163
163
  data-slot="dialog-description"
164
- className={className}
164
+ className={cn("mt-1 text-sm leading-6 text-muted-foreground", className)}
165
165
  {...props}
166
166
  />
167
167
  )
@@ -38,7 +38,7 @@ export type DropdownMenuShortcutProps = React.ComponentProps<"span">
38
38
  export type DropdownMenuItemDescriptionProps = React.ComponentProps<"span">
39
39
 
40
40
  const menuItemClassName =
41
- "relative group/dropdown-menu-item [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4"
41
+ "relative group/dropdown-menu-item flex min-h-9 w-full cursor-default select-none items-center gap-2 rounded-[var(--radius-md)] px-2.5 py-2 text-sm text-popover-foreground outline-none transition-[background-color,color] data-[disabled]:pointer-events-none data-[disabled]:opacity-50 data-[highlighted]:bg-accent data-[highlighted]:text-accent-foreground data-[inset=true]:pl-8 data-[variant=destructive]:text-destructive data-[variant=destructive]:data-[highlighted]:bg-destructive/10 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4"
42
42
 
43
43
  function DropdownMenu({ ...props }: MenuPrimitive.Root.Props) {
44
44
  return <MenuPrimitive.Root data-slot="dropdown-menu" {...props} />
@@ -76,7 +76,7 @@ function DropdownMenuContent({
76
76
  >
77
77
  <MenuPrimitive.Popup
78
78
  data-slot="dropdown-menu-content"
79
- className={cn("z-50 max-h-(--available-height) w-(--anchor-width) min-w-56 origin-(--transform-origin) overflow-x-hidden overflow-y-auto duration-100 outline-none data-[side=bottom]:slide-in-from-top-2 data-[side=inline-end]:slide-in-from-left-2 data-[side=inline-start]:slide-in-from-right-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 data-open:animate-in data-open:fade-in-0 data-open:zoom-in-95 data-closed:animate-out data-closed:overflow-hidden data-closed:fade-out-0 data-closed:zoom-out-95", className)}
79
+ className={cn("z-50 max-h-[min(var(--available-height),24rem)] w-(--anchor-width) min-w-56 origin-(--transform-origin) overflow-x-hidden overflow-y-auto rounded-[var(--aui-card-radius,var(--radius-lg))] border border-border/78 bg-popover p-1 text-popover-foreground shadow-[0_18px_50px_rgba(15,23,42,0.18)] outline-none backdrop-blur duration-100 data-[side=bottom]:slide-in-from-top-2 data-[side=inline-end]:slide-in-from-left-2 data-[side=inline-start]:slide-in-from-right-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 data-open:animate-in data-open:fade-in-0 data-open:zoom-in-95 data-closed:animate-out data-closed:overflow-hidden data-closed:fade-out-0 data-closed:zoom-out-95", className)}
80
80
  {...props}
81
81
  />
82
82
  </MenuPrimitive.Positioner>
@@ -97,7 +97,7 @@ function DropdownMenuLabel({
97
97
  <div
98
98
  data-slot="dropdown-menu-label"
99
99
  data-inset={inset}
100
- className={className}
100
+ className={cn("px-2.5 py-1.5 text-xs font-semibold uppercase tracking-[0.14em] text-muted-foreground data-[inset=true]:pl-8", className)}
101
101
  {...props}
102
102
  />
103
103
  )
@@ -118,6 +118,7 @@ function DropdownMenuItem({
118
118
  data-variant={variant}
119
119
  className={cn(
120
120
  menuItemClassName,
121
+ "pl-8 pr-8",
121
122
  className
122
123
  )}
123
124
  onSelect={(event) => {
@@ -147,6 +148,7 @@ function DropdownMenuSubTrigger({
147
148
  data-inset={inset}
148
149
  className={cn(
149
150
  menuItemClassName,
151
+ "pl-8",
150
152
  className
151
153
  )}
152
154
  {...props}
@@ -204,14 +206,11 @@ function DropdownMenuCheckboxItem({
204
206
  }}
205
207
  {...props}
206
208
  >
207
- <span
208
- data-slot="dropdown-menu-checkbox-item-indicator"
209
- >
210
- <MenuPrimitive.CheckboxItemIndicator>
211
- <CheckIcon
212
- />
213
- </MenuPrimitive.CheckboxItemIndicator>
214
- </span>
209
+ <span data-slot="dropdown-menu-checkbox-item-indicator" className="absolute left-2 grid size-4 place-items-center">
210
+ <MenuPrimitive.CheckboxItemIndicator>
211
+ <CheckIcon className="size-4" />
212
+ </MenuPrimitive.CheckboxItemIndicator>
213
+ </span>
215
214
  {children}
216
215
  </MenuPrimitive.CheckboxItem>
217
216
  )
@@ -250,14 +249,11 @@ function DropdownMenuRadioItem({
250
249
  }}
251
250
  {...props}
252
251
  >
253
- <span
254
- data-slot="dropdown-menu-radio-item-indicator"
255
- >
256
- <MenuPrimitive.RadioItemIndicator>
257
- <CheckIcon
258
- />
259
- </MenuPrimitive.RadioItemIndicator>
260
- </span>
252
+ <span data-slot="dropdown-menu-radio-item-indicator" className="absolute left-2 grid size-4 place-items-center">
253
+ <MenuPrimitive.RadioItemIndicator>
254
+ <CheckIcon className="size-4" />
255
+ </MenuPrimitive.RadioItemIndicator>
256
+ </span>
261
257
  {children}
262
258
  </MenuPrimitive.RadioItem>
263
259
  )
@@ -270,7 +266,7 @@ function DropdownMenuSeparator({
270
266
  return (
271
267
  <MenuPrimitive.Separator
272
268
  data-slot="dropdown-menu-separator"
273
- className={className}
269
+ className={cn("-mx-1 my-1 h-px bg-border/72", className)}
274
270
  {...props}
275
271
  />
276
272
  )
@@ -283,7 +279,7 @@ function DropdownMenuShortcut({
283
279
  return (
284
280
  <span
285
281
  data-slot="dropdown-menu-shortcut"
286
- className={className}
282
+ className={cn("ml-auto text-xs tracking-widest text-muted-foreground", className)}
287
283
  {...props}
288
284
  />
289
285
  )
@@ -296,7 +292,7 @@ function DropdownMenuItemDescription({
296
292
  return (
297
293
  <span
298
294
  data-slot="dropdown-menu-item-description"
299
- className={className}
295
+ className={cn("block text-xs leading-5 text-muted-foreground group-data-[highlighted]/dropdown-menu-item:text-accent-foreground/75", className)}
300
296
  {...props}
301
297
  />
302
298
  )
@@ -46,7 +46,7 @@ function PopoverContent({
46
46
  <PopoverPrimitive.Popup
47
47
  data-slot="popover-content"
48
48
  className={cn(
49
- "z-50 flex max-h-[min(var(--available-height),calc(100dvh-1rem))] w-[min(var(--anchor-width),20rem)] min-w-60 max-w-[calc(100vw-1rem)] origin-(--transform-origin) flex-col gap-3 overflow-y-auto rounded-[var(--radius-lg)] border border-border bg-popover text-popover-foreground shadow-lg outline-hidden duration-100 data-[side=bottom]:slide-in-from-top-2 data-[side=inline-end]:slide-in-from-left-2 data-[side=inline-start]:slide-in-from-right-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 data-open:animate-in data-open:fade-in-0 data-open:zoom-in-95 data-closed:animate-out data-closed:fade-out-0 data-closed:zoom-out-95",
49
+ "z-50 flex max-h-[min(var(--available-height),calc(100dvh-1rem))] w-[min(var(--anchor-width),20rem)] min-w-60 max-w-[calc(100vw-1rem)] origin-(--transform-origin) flex-col gap-3 overflow-y-auto rounded-[var(--aui-card-radius,var(--radius-lg))] border border-border/78 bg-popover p-3 text-popover-foreground shadow-[0_18px_50px_rgba(15,23,42,0.18)] outline-hidden backdrop-blur duration-100 data-[side=bottom]:slide-in-from-top-2 data-[side=inline-end]:slide-in-from-left-2 data-[side=inline-start]:slide-in-from-right-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 data-open:animate-in data-open:fade-in-0 data-open:zoom-in-95 data-closed:animate-out data-closed:fade-out-0 data-closed:zoom-out-95",
50
50
  className
51
51
  )}
52
52
  {...props}
@@ -60,7 +60,7 @@ function PopoverHeader({ className, ...props }: PopoverHeaderProps) {
60
60
  return (
61
61
  <div
62
62
  data-slot="popover-header"
63
- className={className}
63
+ className={cn("grid gap-1", className)}
64
64
  {...props}
65
65
  />
66
66
  )
@@ -70,7 +70,7 @@ function PopoverTitle({ className, ...props }: PopoverTitleProps) {
70
70
  return (
71
71
  <PopoverPrimitive.Title
72
72
  data-slot="popover-title"
73
- className={className}
73
+ className={cn("text-sm font-semibold text-foreground", className)}
74
74
  {...props}
75
75
  />
76
76
  )
@@ -83,7 +83,7 @@ function PopoverDescription({
83
83
  return (
84
84
  <PopoverPrimitive.Description
85
85
  data-slot="popover-description"
86
- className={className}
86
+ className={cn("text-sm leading-6 text-muted-foreground", className)}
87
87
  {...props}
88
88
  />
89
89
  )
@@ -25,7 +25,9 @@ const TabsList = React.forwardRef<
25
25
  data-variant={variant}
26
26
  data-overflow={overflow}
27
27
  className={cn(
28
- "inline-flex max-w-full items-center justify-start",
28
+ "inline-flex max-w-full items-center justify-start gap-1 rounded-[var(--radius-lg)] border border-border/72 bg-muted/45 p-1",
29
+ variant === "underline" && "gap-4 rounded-none border-x-0 border-t-0 bg-transparent p-0",
30
+ variant === "compact" && "rounded-[var(--radius-md)] p-0.5",
29
31
  overflow === "scroll" && "overflow-x-auto overflow-y-hidden overscroll-x-contain [-ms-overflow-style:none] [scrollbar-width:none] [&::-webkit-scrollbar]:hidden",
30
32
  overflow === "wrap" && "flex-wrap",
31
33
  className
@@ -44,7 +46,10 @@ const TabsTrigger = React.forwardRef<
44
46
  data-slot="tabs-trigger"
45
47
  data-variant={variant}
46
48
  className={cn(
47
- "inline-flex shrink-0 items-center justify-center whitespace-nowrap disabled:pointer-events-none",
49
+ "inline-flex h-9 shrink-0 items-center justify-center whitespace-nowrap rounded-[var(--radius-md)] px-3 text-sm font-medium text-muted-foreground outline-none transition-[background-color,border-color,color,box-shadow] hover:bg-background/72 hover:text-foreground focus-visible:ring-2 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50 data-[selected]:bg-background data-[selected]:text-foreground data-[selected]:shadow-sm",
50
+ variant === "pills" && "rounded-full px-4 data-[selected]:bg-primary data-[selected]:text-primary-foreground",
51
+ variant === "underline" && "h-10 rounded-none border-b-2 border-transparent bg-transparent px-0 shadow-none hover:bg-transparent data-[selected]:border-primary data-[selected]:bg-transparent data-[selected]:shadow-none",
52
+ variant === "compact" && "h-8 rounded-[calc(var(--radius-md)-2px)] px-2.5 text-xs",
48
53
  className
49
54
  )}
50
55
  {...props}
@@ -59,7 +64,7 @@ const TabsContent = React.forwardRef<
59
64
  <BaseTabs.Panel
60
65
  ref={ref}
61
66
  data-slot="tabs-content"
62
- className={className}
67
+ className={cn("mt-3 outline-none focus-visible:ring-2 focus-visible:ring-ring", className)}
63
68
  {...props}
64
69
  />
65
70
  ))
@@ -35,8 +35,8 @@ function ToggleGroup<TValue extends string = string>({
35
35
  orientation={orientation}
36
36
  className={cn(
37
37
  "inline-flex items-center gap-1 rounded-[var(--radius-lg)]",
38
- variant === "default" && "border border-border bg-muted/60 p-1",
39
- variant === "outline" && "gap-0 overflow-hidden rounded-[var(--radius-lg)] border border-border",
38
+ variant === "default" && "border border-border/72 bg-muted/45 p-1 shadow-[inset_0_1px_0_rgba(255,255,255,0.18)]",
39
+ variant === "outline" && "gap-0 overflow-hidden rounded-[var(--radius-lg)] border border-border/78 bg-background",
40
40
  orientation === "vertical" && "flex-col items-stretch",
41
41
  className
42
42
  )}
@@ -57,11 +57,11 @@ function ToggleGroupItem<TValue extends string = string>({
57
57
  data-variant={variant}
58
58
  data-size={size}
59
59
  className={cn(
60
- "inline-flex items-center justify-center gap-1.5 whitespace-nowrap font-medium outline-none transition-[background-color,color,border-color,box-shadow] disabled:pointer-events-none disabled:opacity-50 data-[pressed]:text-foreground focus-visible:ring-2 focus-visible:ring-ring [&_svg]:size-4 [&_svg]:shrink-0",
60
+ "inline-flex items-center justify-center gap-1.5 whitespace-nowrap font-medium outline-none transition-[background-color,color,border-color,box-shadow,transform] disabled:pointer-events-none disabled:opacity-50 data-[pressed]:text-foreground focus-visible:ring-2 focus-visible:ring-ring [&_svg]:size-4 [&_svg]:shrink-0",
61
61
  sizeClassName[size],
62
- variant === "default" && "rounded-[calc(var(--radius-md)-1px)] text-muted-foreground hover:bg-background/70 data-[pressed]:bg-background data-[pressed]:shadow-sm",
63
- variant === "outline" && "-m-px border border-border text-muted-foreground hover:bg-muted/60 data-[pressed]:bg-muted data-[pressed]:shadow-inner first:rounded-l-[var(--radius-md)] last:rounded-r-[var(--radius-md)]",
64
- variant === "ghost" && "rounded-[var(--radius-md)] text-muted-foreground hover:bg-muted/70 data-[pressed]:bg-muted",
62
+ variant === "default" && "rounded-[calc(var(--radius-md)-1px)] text-muted-foreground hover:bg-background/70 hover:text-foreground data-[pressed]:-translate-y-px data-[pressed]:bg-background data-[pressed]:shadow-sm",
63
+ variant === "outline" && "-m-px border border-border/78 text-muted-foreground hover:bg-muted/60 hover:text-foreground data-[pressed]:bg-primary data-[pressed]:text-primary-foreground data-[pressed]:shadow-inner first:rounded-l-[var(--radius-md)] last:rounded-r-[var(--radius-md)]",
64
+ variant === "ghost" && "rounded-[var(--radius-md)] text-muted-foreground hover:bg-muted/70 hover:text-foreground data-[pressed]:bg-accent data-[pressed]:text-accent-foreground",
65
65
  className
66
66
  )}
67
67
  {...props}
@@ -27,9 +27,7 @@ export * from './components/ui/kbd'
27
27
  export * from './components/ui/radio-group'
28
28
  export * from './components/ui/scroll-box'
29
29
  export * from './components/ui/right-click-menu'
30
- export * from './components/ui/number-field'
31
30
  export * from './components/ui/toggle-group'
32
- export * from './components/ui/toolbar'
33
31
 
34
32
  // Reusable groups
35
33
  export * from './components/actions/public'
@@ -16,9 +16,8 @@ export const documentedPublicComponentSurfaces: readonly PublicComponentSurfaceE
16
16
  { slug: "checkbox", registryName: "checkbox", surface: "documented" },
17
17
  { slug: "switch", registryName: "switch", surface: "documented" },
18
18
  { slug: "radio-group", registryName: "radio-group", surface: "documented" },
19
- { slug: "number-field", registryName: "number-field", surface: "documented" },
19
+ { slug: "multi-select", registryName: "multi-select", surface: "documented" },
20
20
  { slug: "toggle-group", registryName: "toggle-group", surface: "documented" },
21
- { slug: "toolbar", registryName: "toolbar", surface: "documented" },
22
21
  { slug: "overlay", registryName: "dialog", surface: "documented" },
23
22
  { slug: "dropdown-menu", registryName: "dropdown-menu", surface: "documented" },
24
23
  { slug: "popover", registryName: "popover", surface: "documented" },
@@ -34,11 +33,14 @@ export const documentedPublicComponentSurfaces: readonly PublicComponentSurfaceE
34
33
  { slug: "alert", registryName: "alert", surface: "documented" },
35
34
  { slug: "toast", registryName: "toast", surface: "documented" },
36
35
  { slug: "notification-center", registryName: "notification-center", surface: "documented" },
36
+ { slug: "action-toast", registryName: "action-toast", surface: "documented" },
37
37
  { slug: "bar-chart", registryName: "charts", surface: "documented" },
38
+ { slug: "chart-card", registryName: "chart-card", surface: "documented" },
38
39
  { slug: "sidebar", registryName: "sidebar", surface: "documented" },
39
40
  { slug: "breadcrumbs", registryName: "breadcrumbs", surface: "documented" },
40
41
  { slug: "workspace-layout", registryName: "workspace-layout", surface: "documented" },
41
42
  { slug: "state-view", registryName: "state-view", surface: "documented" },
43
+ { slug: "async-boundary", registryName: "async-boundary", surface: "documented" },
42
44
  { slug: "file-upload", registryName: "file-upload", surface: "documented" },
43
45
  { slug: "progress", registryName: "progress", surface: "documented" },
44
46
  { slug: "accordion", registryName: "accordion", surface: "documented" },
@@ -47,6 +49,7 @@ export const documentedPublicComponentSurfaces: readonly PublicComponentSurfaceE
47
49
  { slug: "skeleton", registryName: "skeleton", surface: "documented" },
48
50
  { slug: "spinner", registryName: "spinner", surface: "documented" },
49
51
  { slug: "command-palette", registryName: "command-palette", surface: "documented" },
52
+ { slug: "advanced-command-menu", registryName: "advanced-command-menu", surface: "documented" },
50
53
  { slug: "inline-editable", registryName: "inline-editable", surface: "documented" },
51
54
  { slug: "avatar", registryName: "avatar", surface: "documented" },
52
55
  { slug: "code-block", registryName: "code-block", surface: "documented" },
@@ -55,26 +58,32 @@ export const documentedPublicComponentSurfaces: readonly PublicComponentSurfaceE
55
58
  { slug: "chat", registryName: "chat", surface: "documented" },
56
59
  { slug: "list", registryName: "list", surface: "documented" },
57
60
  { slug: "description-list", registryName: "description-list", surface: "documented" },
58
- { slug: "statistic", registryName: "statistic", surface: "documented" },
59
61
  { slug: "tree-view", registryName: "tree-view", surface: "documented" },
60
62
  { slug: "copy-button", registryName: "copy-button", surface: "documented" },
61
63
  { slug: "section", registryName: "section", surface: "documented" },
62
64
  { slug: "empty-state", registryName: "empty-state", surface: "documented" },
65
+ { slug: "permissions-matrix", registryName: "permissions-matrix", surface: "documented" },
63
66
  { slug: "calendar-scheduler", registryName: "calendar-scheduler", surface: "documented" },
67
+ { slug: "calendar-range-scheduler", registryName: "calendar-range-scheduler", surface: "documented" },
64
68
  { slug: "dual-list-picker", registryName: "dual-list-picker", surface: "documented" },
65
69
  { slug: "resizable-panel", registryName: "resizable-panel", surface: "documented" },
70
+ { slug: "file-manager", registryName: "file-manager", surface: "documented" },
71
+ { slug: "map", registryName: "map", surface: "documented" },
72
+ { slug: "media-player", registryName: "media-player", surface: "documented" },
73
+ { slug: "spreadsheet", registryName: "spreadsheet", surface: "documented" },
66
74
  { slug: "tag", registryName: "tag", surface: "documented" },
67
75
  { slug: "carousel", registryName: "carousel", surface: "documented" },
68
76
  { slug: "typography", registryName: "typography", surface: "documented" },
69
77
  { slug: "json-input", registryName: "json-input", surface: "documented" },
70
78
  { slug: "time-picker", registryName: "time-picker", surface: "documented" },
79
+ { slug: "date-time-picker", registryName: "date-time-picker", surface: "documented" },
71
80
  { slug: "sortable-list", registryName: "sortable-list", surface: "documented" },
72
81
  { slug: "virtual-list", registryName: "virtual-list", surface: "documented" },
73
82
  { slug: "color-picker", registryName: "color-picker", surface: "documented" },
74
83
  { slug: "signature-pad", registryName: "signature-pad", surface: "documented" },
75
84
  { slug: "qr-code", registryName: "qr-code", surface: "documented" },
76
85
  { slug: "rich-text-editor", registryName: "rich-text-editor", surface: "documented" },
77
- { slug: "image-cropper", registryName: "image-cropper", surface: "documented" },
86
+ { slug: "data-grid", registryName: "data-grid", surface: "documented" },
78
87
  ] as const
79
88
 
80
89
  export const standalonePublicComponentSurfaces: readonly PublicComponentSurfaceEntry[] = [] as const
@@ -53,7 +53,6 @@ export const registryGroups: RegistryGroup[] = [
53
53
  component("scroll-box", "stable", "src/components/ui/scroll-box"),
54
54
  component("right-click-menu", "stable", "src/components/ui/right-click-menu"),
55
55
  component("toggle-group", "preview", "src/components/ui/toggle-group"),
56
- component("toolbar", "preview", "src/components/ui/toolbar"),
57
56
  component("collapse", "preview", "src/components/ui/collapse"),
58
57
  component("command", "preview", "src/components/ui/command"),
59
58
  component("divider", "preview", "src/components/ui/divider"),
@@ -82,7 +81,6 @@ export const registryGroups: RegistryGroup[] = [
82
81
  component("inline-editable", "preview", "src/components/inputs/inline-editable.tsx"),
83
82
  component("json-input", "preview", "src/components/inputs/json-input.tsx"),
84
83
  component("time-picker", "preview", "src/components/inputs/time-picker.tsx"),
85
- component("number-field", "preview", "src/components/ui/number-field"),
86
84
  ],
87
85
  },
88
86
  {
@@ -112,8 +110,6 @@ export const registryGroups: RegistryGroup[] = [
112
110
  component("kanban", "preview", "src/components/display/kanban.tsx"),
113
111
  component("list", "preview", "src/components/display/list.tsx"),
114
112
  component("progress", "stable", "src/components/display/progress.tsx"),
115
- component("info-card", "stable", "src/components/display/info-card.tsx"),
116
- component("statistic", "preview", "src/components/display/statistic.tsx"),
117
113
  component("status-dot", "preview", "src/components/display/status-dot.tsx"),
118
114
  component("status-legend", "preview", "src/components/display/status-legend.tsx"),
119
115
  component("timeline", "stable", "src/components/display/timeline.tsx"),
@@ -167,7 +163,9 @@ export const registryGroups: RegistryGroup[] = [
167
163
  component("dual-list-picker", "preview", "src/components/modern/dual-list-picker.tsx"),
168
164
  component("resizable-panel", "preview", "src/components/modern/resizable-panel.tsx"),
169
165
  component("rich-text-editor", "preview", "src/components/modern/rich-text-editor.tsx"),
170
- component("image-cropper", "preview", "src/components/modern/image-cropper.tsx"),
166
+ component("map", "preview", "src/components/modern/map.tsx"),
167
+ component("media-player", "preview", "src/components/modern/media-player.tsx"),
168
+ component("spreadsheet", "preview", "src/components/modern/spreadsheet.tsx"),
171
169
  ],
172
170
  },
173
171
  {
@@ -180,7 +178,6 @@ export const registryGroups: RegistryGroup[] = [
180
178
  {
181
179
  name: "filters",
182
180
  components: [
183
- component("filter-bar", "stable", "src/components/filters/filter-bar.tsx"),
184
181
  component("saved-filter-select", "preview", "src/components/filters/saved-filter-select.tsx"),
185
182
  ],
186
183
  },
@@ -219,6 +216,9 @@ export const componentRows: ComponentRow[] = [
219
216
  { id: "cmp-006", component: "wizard", category: "wizard", status: "Review", props: 12 },
220
217
  { id: "cmp-007", component: "button", category: "ui", status: "Ready", props: 9 },
221
218
  { id: "cmp-008", component: "input", category: "ui", status: "Ready", props: 11 },
219
+ { id: "cmp-009", component: "map", category: "modern", status: "Testing", props: 13 },
220
+ { id: "cmp-010", component: "media-player", category: "modern", status: "Testing", props: 12 },
221
+ { id: "cmp-011", component: "spreadsheet", category: "modern", status: "Testing", props: 13 },
222
222
  ]
223
223
 
224
224
  export const wizardSteps = [
@@ -1,11 +1,18 @@
1
1
  import { PlusIcon, SettingsIcon } from "lucide-react"
2
2
 
3
3
  import { CopyButton } from "@/components/actions/copy-button"
4
- import { StatisticCard, StatisticGrid } from "@/components/display/statistic"
5
4
  import { Badge } from "@/components/ui/badge"
6
5
  import { Button } from "@/components/ui/button"
6
+ import { Card, CardContent } from "@/components/ui/card"
7
7
  import { moduleCount, registryGroups } from "@/showcase/data/registry"
8
8
 
9
+ const metrics = [
10
+ { label: "Registry components", value: moduleCount, change: "visible below", description: "tembro add <name>" },
11
+ { label: "Local source files", value: "152", change: "with hooks/lib", description: "installed by CLI" },
12
+ { label: "Categories", value: registryGroups.length, change: "all shown", description: "actions to wizard" },
13
+ { label: "Build", value: "Pass", change: "doctor pass", description: "tembro@6.1.1" },
14
+ ]
15
+
9
16
  export function HeroSection() {
10
17
  return (
11
18
  <section className="border-b bg-card">
@@ -25,16 +32,24 @@ export function HeroSection() {
25
32
  <div className="flex flex-wrap gap-2">
26
33
  <Button leftIcon={<PlusIcon className="size-4" />}>Create</Button>
27
34
  <Button variant="outline" leftIcon={<SettingsIcon className="size-4" />}>Settings</Button>
28
- <CopyButton value="npx tembro@6.0.3 list --json">Copy list command</CopyButton>
35
+ <CopyButton value="npx tembro@6.1.1 list --json">Copy list command</CopyButton>
29
36
  </div>
30
37
  </div>
31
38
 
32
- <StatisticGrid columns={4} className="mt-8">
33
- <StatisticCard label="Registry components" value={moduleCount} change="visible below" trend="up" description="tembro add <name>" />
34
- <StatisticCard label="Local source files" value="152" change="with hooks/lib" trend="up" description="installed by CLI" />
35
- <StatisticCard label="Categories" value={registryGroups.length} change="all shown" trend="up" description="actions to wizard" />
36
- <StatisticCard label="Build" value="Pass" change="doctor pass" trend="up" description="tembro@6.0.3" />
37
- </StatisticGrid>
39
+ <div className="mt-8 grid gap-4 sm:grid-cols-2 xl:grid-cols-4">
40
+ {metrics.map((metric) => (
41
+ <Card key={metric.label}>
42
+ <CardContent className="p-4">
43
+ <p className="text-sm text-muted-foreground">{metric.label}</p>
44
+ <p className="mt-5 text-2xl font-semibold tracking-tight">{metric.value}</p>
45
+ <div className="mt-2 flex flex-wrap items-center gap-2 text-xs">
46
+ <Badge tone="success" variant="soft">{metric.change}</Badge>
47
+ <span className="text-muted-foreground">{metric.description}</span>
48
+ </div>
49
+ </CardContent>
50
+ </Card>
51
+ ))}
52
+ </div>
38
53
  </div>
39
54
  </section>
40
55
  )
@@ -72,7 +72,7 @@ export function WorkbenchSidebar({ selectedKey, onSelect }: WorkbenchSidebarProp
72
72
  }),
73
73
  ]}
74
74
  footerAccount={{
75
- label: "tembro@6.0.3",
75
+ label: "tembro@6.1.1",
76
76
  description: `${moduleCount} registry components`,
77
77
  }}
78
78
  activeIndicator="bar"