tembro 4.2.1 → 6.0.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 (177) hide show
  1. package/CHANGELOG.md +29 -0
  2. package/dist/components/charts/progress-circle.d.ts +12 -3
  3. package/dist/components/data-table/data-table.d.ts +2 -2
  4. package/dist/components/feedback/index.d.ts +0 -2
  5. package/dist/components/layout/section.d.ts +1 -8
  6. package/dist/components/patterns/index.d.ts +0 -8
  7. package/dist/components/patterns/public.d.ts +0 -8
  8. package/dist/components/ui/hover-card/index.cjs +1 -0
  9. package/dist/components/ui/hover-card/index.d.ts +11 -0
  10. package/dist/components/ui/hover-card/index.js +1 -0
  11. package/dist/components/ui/menubar/index.cjs +1 -0
  12. package/dist/components/ui/menubar/index.d.ts +42 -0
  13. package/dist/components/ui/menubar/index.js +1 -0
  14. package/dist/components/ui/navigation-menu/index.cjs +1 -0
  15. package/dist/components/ui/navigation-menu/index.d.ts +20 -0
  16. package/dist/components/ui/navigation-menu/index.js +1 -0
  17. package/dist/components/ui/number-field/index.cjs +1 -0
  18. package/dist/components/ui/number-field/index.d.ts +18 -0
  19. package/dist/components/ui/number-field/index.js +1 -0
  20. package/dist/components/ui/toggle-group/index.cjs +1 -0
  21. package/dist/components/ui/toggle-group/index.d.ts +13 -0
  22. package/dist/components/ui/toggle-group/index.js +1 -0
  23. package/dist/components/ui/toolbar/index.cjs +1 -0
  24. package/dist/components/ui/toolbar/index.d.ts +14 -0
  25. package/dist/components/ui/toolbar/index.js +1 -0
  26. package/dist/index.d.ts +7 -0
  27. package/dist/src/components/charts/progress-circle.cjs +1 -1
  28. package/dist/src/components/charts/progress-circle.js +57 -3
  29. package/dist/src/components/data-table/data-table.cjs +1 -1
  30. package/dist/src/components/data-table/data-table.js +102 -100
  31. package/dist/src/components/feedback/index.cjs +1 -1
  32. package/dist/src/components/feedback/index.js +2 -4
  33. package/dist/src/components/layout/index.cjs +1 -1
  34. package/dist/src/components/layout/index.js +3 -3
  35. package/dist/src/components/layout/public.cjs +1 -1
  36. package/dist/src/components/layout/public.js +3 -3
  37. package/dist/src/components/layout/section.cjs +1 -1
  38. package/dist/src/components/layout/section.js +2 -26
  39. package/dist/src/components/patterns/index.cjs +1 -1
  40. package/dist/src/components/patterns/index.js +2 -10
  41. package/dist/src/components/patterns/public.cjs +1 -1
  42. package/dist/src/components/patterns/public.js +2 -10
  43. package/dist/src/components/ui/hover-card/index.cjs +1 -0
  44. package/dist/src/components/ui/hover-card/index.js +50 -0
  45. package/dist/src/components/ui/menubar/index.cjs +1 -0
  46. package/dist/src/components/ui/menubar/index.js +132 -0
  47. package/dist/src/components/ui/navigation-menu/index.cjs +1 -0
  48. package/dist/src/components/ui/navigation-menu/index.js +73 -0
  49. package/dist/src/components/ui/number-field/index.cjs +1 -0
  50. package/dist/src/components/ui/number-field/index.js +73 -0
  51. package/dist/src/components/ui/toggle-group/index.cjs +1 -0
  52. package/dist/src/components/ui/toggle-group/index.js +32 -0
  53. package/dist/src/components/ui/toolbar/index.cjs +1 -0
  54. package/dist/src/components/ui/toolbar/index.js +50 -0
  55. package/dist/src/index.cjs +1 -1
  56. package/dist/src/index.js +92 -95
  57. package/dist/src/public-component-surface.cjs +1 -1
  58. package/dist/src/public-component-surface.js +31 -42
  59. package/package.json +1 -1
  60. package/packages/cli/dist/index.cjs +112 -112
  61. package/packages/cli/vendor/src/components/charts/progress-circle.tsx +78 -3
  62. package/packages/cli/vendor/src/components/data-table/data-table.tsx +4 -4
  63. package/packages/cli/vendor/src/components/feedback/index.ts +0 -2
  64. package/packages/cli/vendor/src/components/layout/section.tsx +1 -28
  65. package/packages/cli/vendor/src/components/patterns/index.ts +0 -8
  66. package/packages/cli/vendor/src/components/patterns/public.ts +0 -8
  67. package/packages/cli/vendor/src/components/ui/hover-card/index.tsx +72 -0
  68. package/packages/cli/vendor/src/components/ui/menubar/index.tsx +140 -0
  69. package/packages/cli/vendor/src/components/ui/navigation-menu/index.tsx +100 -0
  70. package/packages/cli/vendor/src/components/ui/number-field/index.tsx +89 -0
  71. package/packages/cli/vendor/src/components/ui/toggle-group/index.tsx +72 -0
  72. package/packages/cli/vendor/src/components/ui/toolbar/index.tsx +67 -0
  73. package/packages/cli/vendor/src/index.ts +12 -5
  74. package/packages/cli/vendor/src/public-component-surface.ts +7 -10
  75. package/packages/cli/vendor/templates/showcase/src/showcase/data/registry.ts +14 -12
  76. package/packages/cli/vendor/templates/showcase/src/showcase/layout/HeroSection.tsx +2 -2
  77. package/packages/cli/vendor/templates/showcase/src/showcase/layout/WorkbenchSidebar.tsx +1 -1
  78. package/packages/cli/vendor/templates/showcase/src/showcase/sections/ComponentLivePreview.tsx +2 -2
  79. package/packages/cli/vendor/templates/showcase/src/showcase/sections/FormsSection.tsx +2 -2
  80. package/packages/cli/vendor/templates/styles/globals.css +5 -5
  81. package/registry.json +2630 -233
  82. package/dist/components/charts/progress-ring.cjs +0 -1
  83. package/dist/components/charts/progress-ring.d.ts +0 -13
  84. package/dist/components/charts/progress-ring.js +0 -1
  85. package/dist/components/feedback/loading-state.cjs +0 -1
  86. package/dist/components/feedback/loading-state.d.ts +0 -9
  87. package/dist/components/feedback/loading-state.js +0 -1
  88. package/dist/components/feedback/page-state.cjs +0 -1
  89. package/dist/components/feedback/page-state.d.ts +0 -18
  90. package/dist/components/feedback/page-state.js +0 -1
  91. package/dist/components/layout/page-container.cjs +0 -1
  92. package/dist/components/layout/page-container.d.ts +0 -7
  93. package/dist/components/layout/page-container.js +0 -1
  94. package/dist/components/layout/page-header.cjs +0 -1
  95. package/dist/components/layout/page-header.d.ts +0 -23
  96. package/dist/components/layout/page-header.js +0 -1
  97. package/dist/components/layout/section-header.cjs +0 -1
  98. package/dist/components/layout/section-header.d.ts +0 -14
  99. package/dist/components/layout/section-header.js +0 -1
  100. package/dist/components/layout/sidebar-nav.cjs +0 -1
  101. package/dist/components/layout/sidebar-nav.d.ts +0 -37
  102. package/dist/components/layout/sidebar-nav.js +0 -1
  103. package/dist/components/layout/sticky-footer-bar.cjs +0 -1
  104. package/dist/components/layout/sticky-footer-bar.d.ts +0 -7
  105. package/dist/components/layout/sticky-footer-bar.js +0 -1
  106. package/dist/components/patterns/bulk-action-bar.cjs +0 -1
  107. package/dist/components/patterns/bulk-action-bar.d.ts +0 -10
  108. package/dist/components/patterns/bulk-action-bar.js +0 -1
  109. package/dist/components/patterns/data-view.cjs +0 -1
  110. package/dist/components/patterns/data-view.d.ts +0 -17
  111. package/dist/components/patterns/data-view.js +0 -1
  112. package/dist/components/patterns/detail-layout.cjs +0 -1
  113. package/dist/components/patterns/detail-layout.d.ts +0 -16
  114. package/dist/components/patterns/detail-layout.js +0 -1
  115. package/dist/components/patterns/form-builder.cjs +0 -1
  116. package/dist/components/patterns/form-builder.d.ts +0 -110
  117. package/dist/components/patterns/form-builder.js +0 -1
  118. package/dist/components/patterns/page-toolbar.cjs +0 -1
  119. package/dist/components/patterns/page-toolbar.d.ts +0 -11
  120. package/dist/components/patterns/page-toolbar.js +0 -1
  121. package/dist/components/patterns/resource-detail-page.cjs +0 -1
  122. package/dist/components/patterns/resource-detail-page.d.ts +0 -39
  123. package/dist/components/patterns/resource-detail-page.js +0 -1
  124. package/dist/components/patterns/resource-page.cjs +0 -1
  125. package/dist/components/patterns/resource-page.d.ts +0 -30
  126. package/dist/components/patterns/resource-page.js +0 -1
  127. package/dist/components/patterns/settings-page.cjs +0 -1
  128. package/dist/components/patterns/settings-page.d.ts +0 -21
  129. package/dist/components/patterns/settings-page.js +0 -1
  130. package/dist/src/components/charts/progress-ring.cjs +0 -1
  131. package/dist/src/components/charts/progress-ring.js +0 -57
  132. package/dist/src/components/feedback/loading-state.cjs +0 -1
  133. package/dist/src/components/feedback/loading-state.js +0 -15
  134. package/dist/src/components/feedback/page-state.cjs +0 -1
  135. package/dist/src/components/feedback/page-state.js +0 -28
  136. package/dist/src/components/layout/page-container.cjs +0 -1
  137. package/dist/src/components/layout/page-container.js +0 -21
  138. package/dist/src/components/layout/page-header.cjs +0 -1
  139. package/dist/src/components/layout/page-header.js +0 -92
  140. package/dist/src/components/layout/section-header.cjs +0 -1
  141. package/dist/src/components/layout/section-header.js +0 -44
  142. package/dist/src/components/layout/sidebar-nav.cjs +0 -1
  143. package/dist/src/components/layout/sidebar-nav.js +0 -220
  144. package/dist/src/components/layout/sticky-footer-bar.cjs +0 -1
  145. package/dist/src/components/layout/sticky-footer-bar.js +0 -20
  146. package/dist/src/components/patterns/bulk-action-bar.cjs +0 -1
  147. package/dist/src/components/patterns/bulk-action-bar.js +0 -34
  148. package/dist/src/components/patterns/data-view.cjs +0 -1
  149. package/dist/src/components/patterns/data-view.js +0 -47
  150. package/dist/src/components/patterns/detail-layout.cjs +0 -1
  151. package/dist/src/components/patterns/detail-layout.js +0 -65
  152. package/dist/src/components/patterns/form-builder.cjs +0 -1
  153. package/dist/src/components/patterns/form-builder.js +0 -263
  154. package/dist/src/components/patterns/page-toolbar.cjs +0 -1
  155. package/dist/src/components/patterns/page-toolbar.js +0 -41
  156. package/dist/src/components/patterns/resource-detail-page.cjs +0 -1
  157. package/dist/src/components/patterns/resource-detail-page.js +0 -100
  158. package/dist/src/components/patterns/resource-page.cjs +0 -1
  159. package/dist/src/components/patterns/resource-page.js +0 -88
  160. package/dist/src/components/patterns/settings-page.cjs +0 -1
  161. package/dist/src/components/patterns/settings-page.js +0 -64
  162. package/packages/cli/vendor/src/components/charts/progress-ring.tsx +0 -56
  163. package/packages/cli/vendor/src/components/feedback/loading-state.tsx +0 -15
  164. package/packages/cli/vendor/src/components/feedback/page-state.tsx +0 -29
  165. package/packages/cli/vendor/src/components/layout/page-container.tsx +0 -30
  166. package/packages/cli/vendor/src/components/layout/page-header.tsx +0 -104
  167. package/packages/cli/vendor/src/components/layout/section-header.tsx +0 -56
  168. package/packages/cli/vendor/src/components/layout/sidebar-nav.tsx +0 -377
  169. package/packages/cli/vendor/src/components/layout/sticky-footer-bar.tsx +0 -23
  170. package/packages/cli/vendor/src/components/patterns/bulk-action-bar.tsx +0 -53
  171. package/packages/cli/vendor/src/components/patterns/data-view.tsx +0 -64
  172. package/packages/cli/vendor/src/components/patterns/detail-layout.tsx +0 -75
  173. package/packages/cli/vendor/src/components/patterns/form-builder.tsx +0 -472
  174. package/packages/cli/vendor/src/components/patterns/page-toolbar.tsx +0 -61
  175. package/packages/cli/vendor/src/components/patterns/resource-detail-page.tsx +0 -164
  176. package/packages/cli/vendor/src/components/patterns/resource-page.tsx +0 -149
  177. package/packages/cli/vendor/src/components/patterns/settings-page.tsx +0 -84
@@ -1,7 +1,82 @@
1
- import { ProgressRing, type ProgressRingProps } from "@/components/charts/progress-ring"
1
+ import * as React from "react"
2
2
 
3
- export type ProgressCircleProps = ProgressRingProps
3
+ import { cn } from "@/lib/utils"
4
4
 
5
- const ProgressCircle = ProgressRing
5
+ export type ProgressCircleProps = React.ComponentProps<"svg"> & {
6
+ value?: number
7
+ max?: number
8
+ size?: number
9
+ strokeWidth?: number
10
+ label?: React.ReactNode
11
+ description?: React.ReactNode
12
+ tone?: "default" | "success" | "warning" | "danger"
13
+ loading?: boolean
14
+ }
15
+
16
+ const toneClassName = {
17
+ default: "stroke-primary",
18
+ success: "stroke-[color:var(--aui-success,var(--primary))]",
19
+ warning: "stroke-[color:var(--aui-warning,var(--primary))]",
20
+ danger: "stroke-destructive",
21
+ }
22
+
23
+ function ProgressCircle({
24
+ value,
25
+ max = 100,
26
+ size = 120,
27
+ strokeWidth = 10,
28
+ label,
29
+ description,
30
+ tone = "default",
31
+ loading = false,
32
+ className,
33
+ ...props
34
+ }: ProgressCircleProps) {
35
+ const radius = (size - strokeWidth) / 2
36
+ const circumference = 2 * Math.PI * radius
37
+ const percentage = typeof value === "number" ? Math.min(Math.max(value / max, 0), 1) : 0
38
+ const offset = circumference - percentage * circumference
39
+ const progressLabel = label ?? (typeof value === "number" ? `${Math.round(percentage * 100)}%` : undefined)
40
+
41
+ return (
42
+ <svg
43
+ data-slot="progress-circle"
44
+ viewBox={`0 0 ${size} ${size}`}
45
+ className={cn("h-auto w-full max-w-32", className)}
46
+ role="img"
47
+ {...props}
48
+ >
49
+ <circle
50
+ cx={size / 2}
51
+ cy={size / 2}
52
+ r={radius}
53
+ fill="none"
54
+ strokeWidth={strokeWidth}
55
+ className="stroke-muted"
56
+ />
57
+ <circle
58
+ cx={size / 2}
59
+ cy={size / 2}
60
+ r={radius}
61
+ fill="none"
62
+ strokeWidth={strokeWidth}
63
+ strokeLinecap="round"
64
+ strokeDasharray={circumference}
65
+ strokeDashoffset={loading ? circumference * 0.28 : offset}
66
+ className={cn("origin-center -rotate-90 transition-[stroke-dashoffset]", toneClassName[tone], loading && "animate-pulse")}
67
+ />
68
+ {progressLabel ? (
69
+ <text x="50%" y={description ? "46%" : "52%"} textAnchor="middle" dominantBaseline="middle" className="fill-foreground text-lg font-semibold">
70
+ {progressLabel}
71
+ </text>
72
+ ) : null}
73
+ {description ? (
74
+ <text x="50%" y="62%" textAnchor="middle" dominantBaseline="middle" className="fill-muted-foreground text-[10px]">
75
+ {description}
76
+ </text>
77
+ ) : null}
78
+ </svg>
79
+ )
80
+ }
6
81
 
7
82
  export { ProgressCircle }
@@ -28,7 +28,7 @@ import { DataTablePagination, type DataTablePaginationProps } from "@/components
28
28
  import { type DataTableRowAction } from "@/components/data-table/data-table-row-actions"
29
29
  import { DataTableToolbar, type DataTableToolbarProps } from "@/components/data-table/data-table-toolbar"
30
30
  import { DataState, type DataStateProps } from "@/components/display/data-state"
31
- import { LoadingState, type LoadingStateProps } from "@/components/feedback/loading-state"
31
+ import { StateView, type StateViewProps } from "@/components/feedback/state-view"
32
32
  import { Button } from "@/components/ui/button"
33
33
  import { Input, type InputSearchProps } from "@/components/ui/input"
34
34
  import { useIsMobile } from "@/hooks/use-is-mobile"
@@ -130,7 +130,7 @@ export type DataTableProps<TData, TValue = unknown> = Omit<
130
130
  isError?: boolean
131
131
  emptyState?: Omit<DataStateProps, "status">
132
132
  errorState?: Omit<DataStateProps, "status">
133
- loadingState?: LoadingStateProps
133
+ loadingState?: Omit<StateViewProps, "status">
134
134
  loadingVariant?: DataTableLoadingVariant
135
135
  toolbar?: React.ReactNode | ((table: TanStackTable<TData>) => React.ReactNode)
136
136
  toolbarProps?: DataTableToolbarProps | ((table: TanStackTable<TData>) => DataTableToolbarProps)
@@ -511,7 +511,7 @@ function DataTable<TData, TValue = unknown>({
511
511
  ))
512
512
 
513
513
  const stateContent = shouldRenderSkeleton ? null : isLoading ? (
514
- <LoadingState label="Loading data..." {...loadingState} />
514
+ <StateView status="loading" title="Loading data..." {...loadingState} />
515
515
  ) : isError ? (
516
516
  <DataState status="error" title="Could not load data" description="Please try again." variant="plain" {...errorState} />
517
517
  ) : rows.length === 0 ? (
@@ -657,7 +657,7 @@ function DataTable<TData, TValue = unknown>({
657
657
  <div className="grid gap-3">
658
658
  {stateContent ??
659
659
  (shouldRenderSkeleton ? (
660
- <LoadingState label="Loading data..." {...loadingState} />
660
+ <StateView status="loading" title="Loading data..." {...loadingState} />
661
661
  ) : (
662
662
  rows.map((row) => (
663
663
  <React.Fragment key={row.id}>
@@ -1,4 +1,2 @@
1
1
  export * from "./alert"
2
- export * from "./loading-state"
3
- export * from "./page-state"
4
2
  export * from "./state-view"
@@ -69,33 +69,6 @@ function Section({
69
69
  )
70
70
  }
71
71
 
72
- export type ToolbarProps = React.ComponentProps<"div"> & {
73
- title?: React.ReactNode
74
- description?: React.ReactNode
75
- filters?: React.ReactNode
76
- actions?: React.ReactNode
77
- }
78
-
79
- function Toolbar({ title, description, filters, actions, className, children, ...props }: ToolbarProps) {
80
- return (
81
- <div data-slot="toolbar" className={cn("flex flex-wrap items-center justify-between gap-3", className)} {...props}>
82
- {(title || description) && (
83
- <div className="grid gap-0.5">
84
- {title && <div className="font-medium text-foreground">{title}</div>}
85
- {description && <div className="text-sm text-muted-foreground">{description}</div>}
86
- </div>
87
- )}
88
- {children}
89
- {(filters || actions) && (
90
- <div className="flex flex-wrap items-center gap-2">
91
- {filters}
92
- {actions}
93
- </div>
94
- )}
95
- </div>
96
- )
97
- }
98
-
99
72
  export type SplitLayoutProps = React.ComponentProps<"div"> & {
100
73
  aside: React.ReactNode
101
74
  asidePosition?: "start" | "end"
@@ -125,4 +98,4 @@ function SplitLayout({ aside, asidePosition = "end", asideClassName, contentClas
125
98
  )
126
99
  }
127
100
 
128
- export { Section, SplitLayout, Toolbar }
101
+ export { Section, SplitLayout }
@@ -1,9 +1 @@
1
- export * from './form-builder'
2
- export * from './resource-page'
3
- export * from './resource-detail-page'
4
1
  export * from "./empty-state"
5
- export * from "./page-toolbar"
6
- export * from "./bulk-action-bar"
7
- export * from "./detail-layout"
8
- export * from "./settings-page"
9
- export * from "./data-view"
@@ -1,9 +1 @@
1
- export * from "./form-builder"
2
- export * from "./resource-page"
3
- export * from "./resource-detail-page"
4
1
  export * from "./empty-state"
5
- export * from "./page-toolbar"
6
- export * from "./bulk-action-bar"
7
- export * from "./detail-layout"
8
- export * from "./settings-page"
9
- export * from "./data-view"
@@ -0,0 +1,72 @@
1
+ "use client"
2
+
3
+ import * as React from "react"
4
+ import { PreviewCard as PreviewCardPrimitive } from "@base-ui/react/preview-card"
5
+
6
+ import { cn } from "@/lib/utils"
7
+
8
+ export type HoverCardProps = PreviewCardPrimitive.Root.Props
9
+ export type HoverCardTriggerProps = PreviewCardPrimitive.Trigger.Props
10
+ export type HoverCardContentProps = PreviewCardPrimitive.Popup.Props &
11
+ Pick<
12
+ PreviewCardPrimitive.Positioner.Props,
13
+ "align" | "alignOffset" | "collisionBoundary" | "collisionPadding" | "side" | "sideOffset"
14
+ >
15
+ export type HoverCardArrowProps = PreviewCardPrimitive.Arrow.Props
16
+
17
+ function HoverCard({ ...props }: HoverCardProps) {
18
+ return <PreviewCardPrimitive.Root data-slot="hover-card" {...props} />
19
+ }
20
+
21
+ function HoverCardTrigger({ ...props }: HoverCardTriggerProps) {
22
+ if (!("render" in props) && React.isValidElement(props.children)) {
23
+ const { children, ...rest } = props
24
+ return <PreviewCardPrimitive.Trigger data-slot="hover-card-trigger" render={children} {...rest} />
25
+ }
26
+
27
+ return <PreviewCardPrimitive.Trigger data-slot="hover-card-trigger" {...props} />
28
+ }
29
+
30
+ function HoverCardContent({
31
+ className,
32
+ align = "center",
33
+ alignOffset = 0,
34
+ collisionPadding = 12,
35
+ side = "bottom",
36
+ sideOffset = 8,
37
+ ...props
38
+ }: HoverCardContentProps) {
39
+ return (
40
+ <PreviewCardPrimitive.Portal>
41
+ <PreviewCardPrimitive.Positioner
42
+ align={align}
43
+ alignOffset={alignOffset}
44
+ collisionPadding={collisionPadding}
45
+ side={side}
46
+ sideOffset={sideOffset}
47
+ className="isolate z-50 outline-none"
48
+ >
49
+ <PreviewCardPrimitive.Popup
50
+ data-slot="hover-card-content"
51
+ className={cn(
52
+ "z-50 grid max-h-[min(var(--available-height),calc(100dvh-1rem))] w-80 max-w-[calc(100vw-1rem)] origin-(--transform-origin) gap-3 overflow-y-auto rounded-[var(--radius-lg)] border border-border bg-popover p-4 text-popover-foreground shadow-lg outline-none duration-100 data-[side=bottom]:slide-in-from-top-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",
53
+ className
54
+ )}
55
+ {...props}
56
+ />
57
+ </PreviewCardPrimitive.Positioner>
58
+ </PreviewCardPrimitive.Portal>
59
+ )
60
+ }
61
+
62
+ function HoverCardArrow({ className, ...props }: HoverCardArrowProps) {
63
+ return (
64
+ <PreviewCardPrimitive.Arrow
65
+ data-slot="hover-card-arrow"
66
+ className={cn("z-50 flex size-3 rotate-45 border border-border bg-popover", className)}
67
+ {...props}
68
+ />
69
+ )
70
+ }
71
+
72
+ export { HoverCard, HoverCardArrow, HoverCardContent, HoverCardTrigger }
@@ -0,0 +1,140 @@
1
+ "use client"
2
+
3
+ import * as React from "react"
4
+ import { Menubar as MenubarPrimitive } from "@base-ui/react/menubar"
5
+ import { Menu as MenuPrimitive } from "@base-ui/react/menu"
6
+ import { CheckIcon, ChevronRightIcon } from "lucide-react"
7
+
8
+ import { cn } from "@/lib/utils"
9
+
10
+ export type MenubarProps = MenubarPrimitive.Props
11
+ export type MenubarMenuProps = MenuPrimitive.Root.Props
12
+ export type MenubarTriggerProps = MenuPrimitive.Trigger.Props
13
+ export type MenubarContentProps = MenuPrimitive.Popup.Props &
14
+ Pick<MenuPrimitive.Positioner.Props, "align" | "alignOffset" | "side" | "sideOffset">
15
+ export type MenubarItemProps = MenuPrimitive.Item.Props & { inset?: boolean; variant?: "default" | "destructive" }
16
+ export type MenubarCheckboxItemProps = MenuPrimitive.CheckboxItem.Props & { inset?: boolean }
17
+ export type MenubarRadioGroupProps = MenuPrimitive.RadioGroup.Props
18
+ export type MenubarRadioItemProps = MenuPrimitive.RadioItem.Props & { inset?: boolean }
19
+ export type MenubarSubProps = MenuPrimitive.SubmenuRoot.Props
20
+ export type MenubarSubTriggerProps = MenuPrimitive.SubmenuTrigger.Props & { inset?: boolean }
21
+ export type MenubarSeparatorProps = MenuPrimitive.Separator.Props
22
+ export type MenubarLabelProps = React.ComponentProps<"div"> & { inset?: boolean }
23
+ export type MenubarShortcutProps = React.ComponentProps<"span">
24
+
25
+ const itemClassName =
26
+ "relative flex min-h-8 cursor-default select-none items-center gap-2 rounded-[var(--radius-md)] px-2.5 py-1.5 text-sm outline-none transition-colors hover:bg-accent hover:text-accent-foreground focus-visible:bg-accent focus-visible:text-accent-foreground data-[highlighted]:bg-accent data-[highlighted]:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50 data-[inset=true]:pl-8 data-[variant=destructive]:text-destructive data-[variant=destructive]:focus-visible:bg-destructive/10 data-[variant=destructive]:hover:bg-destructive/10"
27
+
28
+ function Menubar({ className, ...props }: MenubarProps) {
29
+ return (
30
+ <MenubarPrimitive
31
+ data-slot="menubar"
32
+ className={cn("flex h-10 items-center gap-1 rounded-[var(--radius-lg)] border border-border bg-card p-1 text-card-foreground shadow-sm", className)}
33
+ {...props}
34
+ />
35
+ )
36
+ }
37
+
38
+ function MenubarMenu({ ...props }: MenubarMenuProps) {
39
+ return <MenuPrimitive.Root data-slot="menubar-menu" {...props} />
40
+ }
41
+
42
+ function MenubarTrigger({ className, ...props }: MenubarTriggerProps) {
43
+ return (
44
+ <MenuPrimitive.Trigger
45
+ data-slot="menubar-trigger"
46
+ className={cn("inline-flex h-8 items-center justify-center rounded-[var(--radius-md)] px-3 text-sm font-medium outline-none transition-colors hover:bg-accent hover:text-accent-foreground focus-visible:bg-accent focus-visible:text-accent-foreground data-[popup-open]:bg-accent data-[popup-open]:text-accent-foreground disabled:pointer-events-none disabled:opacity-50", className)}
47
+ {...props}
48
+ />
49
+ )
50
+ }
51
+
52
+ function MenubarContent({ className, align = "start", alignOffset = 0, side = "bottom", sideOffset = 6, ...props }: MenubarContentProps) {
53
+ return (
54
+ <MenuPrimitive.Portal>
55
+ <MenuPrimitive.Positioner align={align} alignOffset={alignOffset} side={side} sideOffset={sideOffset} className="isolate z-50 outline-none">
56
+ <MenuPrimitive.Popup
57
+ data-slot="menubar-content"
58
+ className={cn("z-50 min-w-48 origin-(--transform-origin) overflow-hidden rounded-[var(--radius-lg)] border border-border bg-popover p-1 text-popover-foreground shadow-lg outline-none duration-100 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", className)}
59
+ {...props}
60
+ />
61
+ </MenuPrimitive.Positioner>
62
+ </MenuPrimitive.Portal>
63
+ )
64
+ }
65
+
66
+ function MenubarItem({ className, inset, variant = "default", ...props }: MenubarItemProps) {
67
+ return <MenuPrimitive.Item data-slot="menubar-item" data-inset={inset || undefined} data-variant={variant} className={cn(itemClassName, className)} {...props} />
68
+ }
69
+
70
+ function MenubarCheckboxItem({ className, children, checked, inset, ...props }: MenubarCheckboxItemProps) {
71
+ return (
72
+ <MenuPrimitive.CheckboxItem data-slot="menubar-checkbox-item" data-inset={inset || undefined} className={cn(itemClassName, "pl-8", className)} checked={checked} {...props}>
73
+ <span className="absolute left-2 inline-flex size-4 items-center justify-center">
74
+ <MenuPrimitive.CheckboxItemIndicator><CheckIcon className="size-4" /></MenuPrimitive.CheckboxItemIndicator>
75
+ </span>
76
+ {children}
77
+ </MenuPrimitive.CheckboxItem>
78
+ )
79
+ }
80
+
81
+ function MenubarRadioGroup({ ...props }: MenubarRadioGroupProps) {
82
+ return <MenuPrimitive.RadioGroup data-slot="menubar-radio-group" {...props} />
83
+ }
84
+
85
+ function MenubarRadioItem({ className, children, inset, ...props }: MenubarRadioItemProps) {
86
+ return (
87
+ <MenuPrimitive.RadioItem data-slot="menubar-radio-item" data-inset={inset || undefined} className={cn(itemClassName, "pl-8", className)} {...props}>
88
+ <span className="absolute left-2 inline-flex size-4 items-center justify-center">
89
+ <MenuPrimitive.RadioItemIndicator><CheckIcon className="size-4" /></MenuPrimitive.RadioItemIndicator>
90
+ </span>
91
+ {children}
92
+ </MenuPrimitive.RadioItem>
93
+ )
94
+ }
95
+
96
+ function MenubarSub({ ...props }: MenubarSubProps) {
97
+ return <MenuPrimitive.SubmenuRoot data-slot="menubar-sub" {...props} />
98
+ }
99
+
100
+ function MenubarSubTrigger({ className, children, inset, ...props }: MenubarSubTriggerProps) {
101
+ return (
102
+ <MenuPrimitive.SubmenuTrigger data-slot="menubar-sub-trigger" data-inset={inset || undefined} className={cn(itemClassName, className)} {...props}>
103
+ {children}
104
+ <ChevronRightIcon className="ml-auto size-4" />
105
+ </MenuPrimitive.SubmenuTrigger>
106
+ )
107
+ }
108
+
109
+ function MenubarSubContent(props: MenubarContentProps) {
110
+ return <MenubarContent data-slot="menubar-sub-content" side="right" align="start" alignOffset={-4} sideOffset={0} {...props} />
111
+ }
112
+
113
+ function MenubarSeparator({ className, ...props }: MenubarSeparatorProps) {
114
+ return <MenuPrimitive.Separator data-slot="menubar-separator" className={cn("-mx-1 my-1 h-px bg-border", className)} {...props} />
115
+ }
116
+
117
+ function MenubarLabel({ className, inset, ...props }: MenubarLabelProps) {
118
+ return <div data-slot="menubar-label" data-inset={inset || undefined} className={cn("px-2.5 py-1.5 text-xs font-semibold text-muted-foreground data-[inset=true]:pl-8", className)} {...props} />
119
+ }
120
+
121
+ function MenubarShortcut({ className, ...props }: MenubarShortcutProps) {
122
+ return <span data-slot="menubar-shortcut" className={cn("ml-auto text-xs tracking-widest text-muted-foreground", className)} {...props} />
123
+ }
124
+
125
+ export {
126
+ Menubar,
127
+ MenubarCheckboxItem,
128
+ MenubarContent,
129
+ MenubarItem,
130
+ MenubarLabel,
131
+ MenubarMenu,
132
+ MenubarRadioGroup,
133
+ MenubarRadioItem,
134
+ MenubarSeparator,
135
+ MenubarShortcut,
136
+ MenubarSub,
137
+ MenubarSubContent,
138
+ MenubarSubTrigger,
139
+ MenubarTrigger,
140
+ }
@@ -0,0 +1,100 @@
1
+ "use client"
2
+
3
+ import { NavigationMenu as NavigationMenuPrimitive } from "@base-ui/react/navigation-menu"
4
+ import { ChevronDownIcon } from "lucide-react"
5
+
6
+ import { cn } from "@/lib/utils"
7
+
8
+ export type NavigationMenuProps = NavigationMenuPrimitive.Root.Props
9
+ export type NavigationMenuListProps = NavigationMenuPrimitive.List.Props
10
+ export type NavigationMenuItemProps = NavigationMenuPrimitive.Item.Props
11
+ export type NavigationMenuTriggerProps = NavigationMenuPrimitive.Trigger.Props
12
+ export type NavigationMenuContentProps = NavigationMenuPrimitive.Content.Props
13
+ export type NavigationMenuLinkProps = NavigationMenuPrimitive.Link.Props
14
+ export type NavigationMenuViewportProps = NavigationMenuPrimitive.Viewport.Props
15
+ export type NavigationMenuPositionerProps = NavigationMenuPrimitive.Positioner.Props
16
+ export type NavigationMenuArrowProps = NavigationMenuPrimitive.Arrow.Props
17
+
18
+ function NavigationMenu({ className, ...props }: NavigationMenuProps) {
19
+ return <NavigationMenuPrimitive.Root data-slot="navigation-menu" className={cn("relative z-10 flex max-w-max flex-1 items-center justify-center", className)} {...props} />
20
+ }
21
+
22
+ function NavigationMenuList({ className, ...props }: NavigationMenuListProps) {
23
+ return <NavigationMenuPrimitive.List data-slot="navigation-menu-list" className={cn("flex flex-1 list-none items-center justify-center gap-1", className)} {...props} />
24
+ }
25
+
26
+ function NavigationMenuItem({ className, ...props }: NavigationMenuItemProps) {
27
+ return <NavigationMenuPrimitive.Item data-slot="navigation-menu-item" className={cn("relative", className)} {...props} />
28
+ }
29
+
30
+ function NavigationMenuTrigger({ className, children, ...props }: NavigationMenuTriggerProps) {
31
+ return (
32
+ <NavigationMenuPrimitive.Trigger
33
+ data-slot="navigation-menu-trigger"
34
+ className={cn("group inline-flex h-10 items-center justify-center gap-1 rounded-[var(--radius-md)] px-4 py-2 text-sm font-medium outline-none transition-colors hover:bg-accent hover:text-accent-foreground focus-visible:bg-accent focus-visible:text-accent-foreground data-[popup-open]:bg-accent data-[popup-open]:text-accent-foreground disabled:pointer-events-none disabled:opacity-50", className)}
35
+ {...props}
36
+ >
37
+ {children}
38
+ <ChevronDownIcon className="size-4 shrink-0 transition-transform duration-200 group-data-[popup-open]:rotate-180" />
39
+ </NavigationMenuPrimitive.Trigger>
40
+ )
41
+ }
42
+
43
+ function NavigationMenuContent({ className, ...props }: NavigationMenuContentProps) {
44
+ return (
45
+ <NavigationMenuPrimitive.Content
46
+ data-slot="navigation-menu-content"
47
+ className={cn("left-0 top-0 w-full p-4 md:absolute md:w-auto", className)}
48
+ {...props}
49
+ />
50
+ )
51
+ }
52
+
53
+ function NavigationMenuLink({ className, ...props }: NavigationMenuLinkProps) {
54
+ return (
55
+ <NavigationMenuPrimitive.Link
56
+ data-slot="navigation-menu-link"
57
+ className={cn("block select-none rounded-[var(--radius-md)] p-3 text-sm leading-none no-underline outline-none transition-colors hover:bg-accent hover:text-accent-foreground focus-visible:bg-accent focus-visible:text-accent-foreground data-[active]:bg-accent data-[active]:text-accent-foreground", className)}
58
+ {...props}
59
+ />
60
+ )
61
+ }
62
+
63
+ function NavigationMenuPositioner({ className, sideOffset = 8, ...props }: NavigationMenuPositionerProps) {
64
+ return (
65
+ <NavigationMenuPrimitive.Portal>
66
+ <NavigationMenuPrimitive.Positioner
67
+ data-slot="navigation-menu-positioner"
68
+ sideOffset={sideOffset}
69
+ className={cn("isolate z-50 flex justify-center", className)}
70
+ {...props}
71
+ />
72
+ </NavigationMenuPrimitive.Portal>
73
+ )
74
+ }
75
+
76
+ function NavigationMenuViewport({ className, ...props }: NavigationMenuViewportProps) {
77
+ return (
78
+ <NavigationMenuPrimitive.Viewport
79
+ data-slot="navigation-menu-viewport"
80
+ className={cn("relative h-(--height) w-full min-w-80 origin-(--transform-origin) overflow-hidden rounded-[var(--radius-lg)] border border-border bg-popover text-popover-foreground shadow-lg duration-100 md:w-(--width) 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", className)}
81
+ {...props}
82
+ />
83
+ )
84
+ }
85
+
86
+ function NavigationMenuArrow({ className, ...props }: NavigationMenuArrowProps) {
87
+ return <NavigationMenuPrimitive.Arrow data-slot="navigation-menu-arrow" className={cn("z-50 flex size-3 rotate-45 border border-border bg-popover", className)} {...props} />
88
+ }
89
+
90
+ export {
91
+ NavigationMenu,
92
+ NavigationMenuArrow,
93
+ NavigationMenuContent,
94
+ NavigationMenuItem,
95
+ NavigationMenuLink,
96
+ NavigationMenuList,
97
+ NavigationMenuPositioner,
98
+ NavigationMenuTrigger,
99
+ NavigationMenuViewport,
100
+ }
@@ -0,0 +1,89 @@
1
+ "use client"
2
+
3
+ import * as React from "react"
4
+ import { NumberField as NumberFieldPrimitive } from "@base-ui/react/number-field"
5
+ import { ChevronDownIcon, ChevronUpIcon } from "lucide-react"
6
+
7
+ import { cn } from "@/lib/utils"
8
+
9
+ export type NumberFieldProps = NumberFieldPrimitive.Root.Props
10
+ export type NumberFieldGroupProps = NumberFieldPrimitive.Group.Props
11
+ export type NumberFieldInputProps = NumberFieldPrimitive.Input.Props
12
+ export type NumberFieldIncrementProps = NumberFieldPrimitive.Increment.Props
13
+ export type NumberFieldDecrementProps = NumberFieldPrimitive.Decrement.Props
14
+ export type NumberFieldScrubAreaProps = NumberFieldPrimitive.ScrubArea.Props
15
+ export type NumberFieldScrubAreaCursorProps = NumberFieldPrimitive.ScrubAreaCursor.Props
16
+
17
+ function NumberField({ className, ...props }: NumberFieldProps) {
18
+ return <NumberFieldPrimitive.Root data-slot="number-field" className={cn("grid gap-2", className)} {...props} />
19
+ }
20
+
21
+ function NumberFieldGroup({ className, ...props }: NumberFieldGroupProps) {
22
+ return (
23
+ <NumberFieldPrimitive.Group
24
+ data-slot="number-field-group"
25
+ className={cn(
26
+ "flex min-h-10 w-full overflow-hidden rounded-[var(--radius-md)] border border-input bg-background text-foreground shadow-xs transition-[border-color,box-shadow] focus-within:border-ring focus-within:ring-2 focus-within:ring-ring/35 has-[:disabled]:cursor-not-allowed has-[:disabled]:opacity-50",
27
+ className
28
+ )}
29
+ {...props}
30
+ />
31
+ )
32
+ }
33
+
34
+ function NumberFieldInput({ className, ...props }: NumberFieldInputProps) {
35
+ return (
36
+ <NumberFieldPrimitive.Input
37
+ data-slot="number-field-input"
38
+ className={cn("min-w-0 flex-1 bg-transparent px-3 py-2 text-sm outline-none placeholder:text-muted-foreground disabled:cursor-not-allowed", className)}
39
+ {...props}
40
+ />
41
+ )
42
+ }
43
+
44
+ function NumberFieldIncrement({ className, children, ...props }: NumberFieldIncrementProps) {
45
+ return (
46
+ <NumberFieldPrimitive.Increment
47
+ data-slot="number-field-increment"
48
+ className={cn("flex h-5 w-8 items-center justify-center border-l border-border text-muted-foreground transition-colors hover:bg-muted hover:text-foreground disabled:pointer-events-none disabled:opacity-40", className)}
49
+ {...props}
50
+ >
51
+ {children ?? <ChevronUpIcon aria-hidden="true" className="size-3.5" />}
52
+ </NumberFieldPrimitive.Increment>
53
+ )
54
+ }
55
+
56
+ function NumberFieldDecrement({ className, children, ...props }: NumberFieldDecrementProps) {
57
+ return (
58
+ <NumberFieldPrimitive.Decrement
59
+ data-slot="number-field-decrement"
60
+ className={cn("flex h-5 w-8 items-center justify-center border-l border-t border-border text-muted-foreground transition-colors hover:bg-muted hover:text-foreground disabled:pointer-events-none disabled:opacity-40", className)}
61
+ {...props}
62
+ >
63
+ {children ?? <ChevronDownIcon aria-hidden="true" className="size-3.5" />}
64
+ </NumberFieldPrimitive.Decrement>
65
+ )
66
+ }
67
+
68
+ function NumberFieldStepper({ className, ...props }: React.ComponentProps<"div">) {
69
+ return <div data-slot="number-field-stepper" className={cn("grid shrink-0 grid-rows-2", className)} {...props} />
70
+ }
71
+
72
+ function NumberFieldScrubArea({ className, ...props }: NumberFieldScrubAreaProps) {
73
+ return <NumberFieldPrimitive.ScrubArea data-slot="number-field-scrub-area" className={cn("cursor-ew-resize select-none", className)} {...props} />
74
+ }
75
+
76
+ function NumberFieldScrubAreaCursor({ className, ...props }: NumberFieldScrubAreaCursorProps) {
77
+ return <NumberFieldPrimitive.ScrubAreaCursor data-slot="number-field-scrub-area-cursor" className={cn("fixed z-50 rounded bg-foreground px-2 py-1 text-xs text-background shadow-lg", className)} {...props} />
78
+ }
79
+
80
+ export {
81
+ NumberField,
82
+ NumberFieldDecrement,
83
+ NumberFieldGroup,
84
+ NumberFieldIncrement,
85
+ NumberFieldInput,
86
+ NumberFieldScrubArea,
87
+ NumberFieldScrubAreaCursor,
88
+ NumberFieldStepper,
89
+ }
@@ -0,0 +1,72 @@
1
+ "use client"
2
+
3
+ import { Toggle } from "@base-ui/react/toggle"
4
+ import { ToggleGroup as ToggleGroupPrimitive } from "@base-ui/react/toggle-group"
5
+
6
+ import { cn } from "@/lib/utils"
7
+
8
+ export type ToggleGroupProps<TValue extends string = string> = ToggleGroupPrimitive.Props<TValue> & {
9
+ variant?: "default" | "outline" | "ghost"
10
+ size?: "sm" | "md" | "lg"
11
+ }
12
+ export type ToggleGroupItemProps<TValue extends string = string> = Toggle.Props<TValue> & {
13
+ variant?: ToggleGroupProps<TValue>["variant"]
14
+ size?: ToggleGroupProps<TValue>["size"]
15
+ }
16
+
17
+ const sizeClassName = {
18
+ sm: "h-8 min-w-8 px-2 text-xs",
19
+ md: "h-9 min-w-9 px-3 text-sm",
20
+ lg: "h-10 min-w-10 px-3.5 text-sm",
21
+ }
22
+
23
+ function ToggleGroup<TValue extends string = string>({
24
+ className,
25
+ variant = "default",
26
+ size = "md",
27
+ orientation = "horizontal",
28
+ ...props
29
+ }: ToggleGroupProps<TValue>) {
30
+ return (
31
+ <ToggleGroupPrimitive
32
+ data-slot="toggle-group"
33
+ data-variant={variant}
34
+ data-size={size}
35
+ orientation={orientation}
36
+ className={cn(
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",
40
+ orientation === "vertical" && "flex-col items-stretch",
41
+ className
42
+ )}
43
+ {...props}
44
+ />
45
+ )
46
+ }
47
+
48
+ function ToggleGroupItem<TValue extends string = string>({
49
+ className,
50
+ variant = "default",
51
+ size = "md",
52
+ ...props
53
+ }: ToggleGroupItemProps<TValue>) {
54
+ return (
55
+ <Toggle
56
+ data-slot="toggle-group-item"
57
+ data-variant={variant}
58
+ data-size={size}
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",
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",
65
+ className
66
+ )}
67
+ {...props}
68
+ />
69
+ )
70
+ }
71
+
72
+ export { ToggleGroup, ToggleGroupItem }