tembro 5.0.0 → 6.0.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 (103) hide show
  1. package/CHANGELOG.md +20 -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/ui/number-field/index.cjs +1 -0
  7. package/dist/components/ui/number-field/index.d.ts +18 -0
  8. package/dist/components/ui/number-field/index.js +1 -0
  9. package/dist/components/ui/toggle-group/index.cjs +1 -0
  10. package/dist/components/ui/toggle-group/index.d.ts +13 -0
  11. package/dist/components/ui/toggle-group/index.js +1 -0
  12. package/dist/components/ui/toolbar/index.cjs +1 -0
  13. package/dist/components/ui/toolbar/index.d.ts +14 -0
  14. package/dist/components/ui/toolbar/index.js +1 -0
  15. package/dist/index.d.ts +3 -0
  16. package/dist/src/components/charts/progress-circle.cjs +1 -1
  17. package/dist/src/components/charts/progress-circle.js +57 -3
  18. package/dist/src/components/data-table/data-table.cjs +1 -1
  19. package/dist/src/components/data-table/data-table.js +102 -100
  20. package/dist/src/components/feedback/index.cjs +1 -1
  21. package/dist/src/components/feedback/index.js +2 -4
  22. package/dist/src/components/layout/index.cjs +1 -1
  23. package/dist/src/components/layout/index.js +3 -3
  24. package/dist/src/components/layout/public.cjs +1 -1
  25. package/dist/src/components/layout/public.js +3 -3
  26. package/dist/src/components/layout/section.cjs +1 -1
  27. package/dist/src/components/layout/section.js +2 -26
  28. package/dist/src/components/ui/number-field/index.cjs +1 -0
  29. package/dist/src/components/ui/number-field/index.js +73 -0
  30. package/dist/src/components/ui/toggle-group/index.cjs +1 -0
  31. package/dist/src/components/ui/toggle-group/index.js +32 -0
  32. package/dist/src/components/ui/toolbar/index.cjs +1 -0
  33. package/dist/src/components/ui/toolbar/index.js +50 -0
  34. package/dist/src/index.cjs +1 -1
  35. package/dist/src/index.js +92 -91
  36. package/dist/src/public-component-surface.cjs +1 -1
  37. package/dist/src/public-component-surface.js +15 -0
  38. package/package.json +13 -9
  39. package/packages/cli/dist/index.cjs +72 -72
  40. package/packages/cli/vendor/src/components/charts/progress-circle.tsx +78 -3
  41. package/packages/cli/vendor/src/components/data-table/data-table.tsx +4 -4
  42. package/packages/cli/vendor/src/components/feedback/index.ts +0 -2
  43. package/packages/cli/vendor/src/components/layout/section.tsx +1 -28
  44. package/packages/cli/vendor/src/components/ui/number-field/index.tsx +89 -0
  45. package/packages/cli/vendor/src/components/ui/toggle-group/index.tsx +72 -0
  46. package/packages/cli/vendor/src/components/ui/toolbar/index.tsx +67 -0
  47. package/packages/cli/vendor/src/index.ts +6 -3
  48. package/packages/cli/vendor/src/public-component-surface.ts +3 -0
  49. package/packages/cli/vendor/templates/showcase/src/showcase/data/registry.ts +4 -2
  50. package/packages/cli/vendor/templates/showcase/src/showcase/layout/HeroSection.tsx +2 -2
  51. package/packages/cli/vendor/templates/showcase/src/showcase/layout/WorkbenchSidebar.tsx +1 -1
  52. package/packages/cli/vendor/templates/showcase/src/showcase/sections/ComponentLivePreview.tsx +2 -2
  53. package/packages/cli/vendor/templates/showcase/src/showcase/sections/FormsSection.tsx +2 -2
  54. package/packages/cli/vendor/templates/styles/globals.css +5 -5
  55. package/registry.json +962 -431
  56. package/dist/components/charts/progress-ring.cjs +0 -1
  57. package/dist/components/charts/progress-ring.d.ts +0 -13
  58. package/dist/components/charts/progress-ring.js +0 -1
  59. package/dist/components/feedback/loading-state.cjs +0 -1
  60. package/dist/components/feedback/loading-state.d.ts +0 -9
  61. package/dist/components/feedback/loading-state.js +0 -1
  62. package/dist/components/feedback/page-state.cjs +0 -1
  63. package/dist/components/feedback/page-state.d.ts +0 -18
  64. package/dist/components/feedback/page-state.js +0 -1
  65. package/dist/components/layout/page-container.cjs +0 -1
  66. package/dist/components/layout/page-container.d.ts +0 -7
  67. package/dist/components/layout/page-container.js +0 -1
  68. package/dist/components/layout/page-header.cjs +0 -1
  69. package/dist/components/layout/page-header.d.ts +0 -23
  70. package/dist/components/layout/page-header.js +0 -1
  71. package/dist/components/layout/section-header.cjs +0 -1
  72. package/dist/components/layout/section-header.d.ts +0 -14
  73. package/dist/components/layout/section-header.js +0 -1
  74. package/dist/components/layout/sidebar-nav.cjs +0 -1
  75. package/dist/components/layout/sidebar-nav.d.ts +0 -37
  76. package/dist/components/layout/sidebar-nav.js +0 -1
  77. package/dist/components/layout/sticky-footer-bar.cjs +0 -1
  78. package/dist/components/layout/sticky-footer-bar.d.ts +0 -7
  79. package/dist/components/layout/sticky-footer-bar.js +0 -1
  80. package/dist/src/components/charts/progress-ring.cjs +0 -1
  81. package/dist/src/components/charts/progress-ring.js +0 -57
  82. package/dist/src/components/feedback/loading-state.cjs +0 -1
  83. package/dist/src/components/feedback/loading-state.js +0 -15
  84. package/dist/src/components/feedback/page-state.cjs +0 -1
  85. package/dist/src/components/feedback/page-state.js +0 -28
  86. package/dist/src/components/layout/page-container.cjs +0 -1
  87. package/dist/src/components/layout/page-container.js +0 -21
  88. package/dist/src/components/layout/page-header.cjs +0 -1
  89. package/dist/src/components/layout/page-header.js +0 -92
  90. package/dist/src/components/layout/section-header.cjs +0 -1
  91. package/dist/src/components/layout/section-header.js +0 -44
  92. package/dist/src/components/layout/sidebar-nav.cjs +0 -1
  93. package/dist/src/components/layout/sidebar-nav.js +0 -220
  94. package/dist/src/components/layout/sticky-footer-bar.cjs +0 -1
  95. package/dist/src/components/layout/sticky-footer-bar.js +0 -20
  96. package/packages/cli/vendor/src/components/charts/progress-ring.tsx +0 -56
  97. package/packages/cli/vendor/src/components/feedback/loading-state.tsx +0 -15
  98. package/packages/cli/vendor/src/components/feedback/page-state.tsx +0 -29
  99. package/packages/cli/vendor/src/components/layout/page-container.tsx +0 -30
  100. package/packages/cli/vendor/src/components/layout/page-header.tsx +0 -104
  101. package/packages/cli/vendor/src/components/layout/section-header.tsx +0 -56
  102. package/packages/cli/vendor/src/components/layout/sidebar-nav.tsx +0 -377
  103. package/packages/cli/vendor/src/components/layout/sticky-footer-bar.tsx +0 -23
@@ -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 }
@@ -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 }
@@ -0,0 +1,67 @@
1
+ "use client"
2
+
3
+ import { Toolbar as ToolbarPrimitive } from "@base-ui/react/toolbar"
4
+
5
+ import { cn } from "@/lib/utils"
6
+
7
+ export type ToolbarProps = ToolbarPrimitive.Root.Props
8
+ export type ToolbarGroupProps = ToolbarPrimitive.Group.Props
9
+ export type ToolbarButtonProps = ToolbarPrimitive.Button.Props
10
+ export type ToolbarLinkProps = ToolbarPrimitive.Link.Props
11
+ export type ToolbarInputProps = ToolbarPrimitive.Input.Props
12
+ export type ToolbarSeparatorProps = ToolbarPrimitive.Separator.Props
13
+
14
+ function Toolbar({ className, orientation = "horizontal", ...props }: ToolbarProps) {
15
+ return (
16
+ <ToolbarPrimitive.Root
17
+ data-slot="toolbar"
18
+ orientation={orientation}
19
+ className={cn(
20
+ "flex min-w-0 items-center gap-1 rounded-[var(--radius-lg)] border border-border bg-card p-1 text-card-foreground shadow-xs",
21
+ orientation === "vertical" && "w-max flex-col items-stretch",
22
+ className
23
+ )}
24
+ {...props}
25
+ />
26
+ )
27
+ }
28
+
29
+ function ToolbarGroup({ className, ...props }: ToolbarGroupProps) {
30
+ return <ToolbarPrimitive.Group data-slot="toolbar-group" className={cn("flex min-w-0 items-center gap-1", className)} {...props} />
31
+ }
32
+
33
+ function ToolbarButton({ className, ...props }: ToolbarButtonProps) {
34
+ return (
35
+ <ToolbarPrimitive.Button
36
+ data-slot="toolbar-button"
37
+ className={cn("inline-flex h-8 min-w-8 items-center justify-center gap-1.5 rounded-[var(--radius-md)] px-2.5 text-sm font-medium text-muted-foreground outline-none transition-colors hover:bg-muted hover:text-foreground focus-visible:ring-2 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50 data-[pressed]:bg-muted data-[pressed]:text-foreground [&_svg]:size-4 [&_svg]:shrink-0", className)}
38
+ {...props}
39
+ />
40
+ )
41
+ }
42
+
43
+ function ToolbarLink({ className, ...props }: ToolbarLinkProps) {
44
+ return (
45
+ <ToolbarPrimitive.Link
46
+ data-slot="toolbar-link"
47
+ className={cn("inline-flex h-8 items-center justify-center gap-1.5 rounded-[var(--radius-md)] px-2.5 text-sm font-medium text-muted-foreground outline-none transition-colors hover:bg-muted hover:text-foreground focus-visible:ring-2 focus-visible:ring-ring", className)}
48
+ {...props}
49
+ />
50
+ )
51
+ }
52
+
53
+ function ToolbarInput({ className, ...props }: ToolbarInputProps) {
54
+ return (
55
+ <ToolbarPrimitive.Input
56
+ data-slot="toolbar-input"
57
+ className={cn("h-8 min-w-32 rounded-[var(--radius-md)] border border-input bg-background px-2.5 text-sm outline-none placeholder:text-muted-foreground focus-visible:ring-2 focus-visible:ring-ring", className)}
58
+ {...props}
59
+ />
60
+ )
61
+ }
62
+
63
+ function ToolbarSeparator({ className, ...props }: ToolbarSeparatorProps) {
64
+ return <ToolbarPrimitive.Separator data-slot="toolbar-separator" className={cn("mx-1 h-5 w-px bg-border data-[orientation=vertical]:h-px data-[orientation=vertical]:w-full", className)} {...props} />
65
+ }
66
+
67
+ export { Toolbar, ToolbarButton, ToolbarGroup, ToolbarInput, ToolbarLink, ToolbarSeparator }
@@ -24,9 +24,12 @@ export * from './components/ui/segmented-control'
24
24
  export * from './components/ui/spinner'
25
25
  export * from './components/ui/tooltip'
26
26
  export * from './components/ui/kbd'
27
- export * from './components/ui/radio-group'
28
- export * from './components/ui/scroll-box'
29
- export * from './components/ui/right-click-menu'
27
+ export * from './components/ui/radio-group'
28
+ export * from './components/ui/scroll-box'
29
+ export * from './components/ui/right-click-menu'
30
+ export * from './components/ui/number-field'
31
+ export * from './components/ui/toggle-group'
32
+ export * from './components/ui/toolbar'
30
33
 
31
34
  // Reusable groups
32
35
  export * from './components/actions/public'
@@ -16,6 +16,9 @@ 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" },
20
+ { slug: "toggle-group", registryName: "toggle-group", surface: "documented" },
21
+ { slug: "toolbar", registryName: "toolbar", surface: "documented" },
19
22
  { slug: "overlay", registryName: "dialog", surface: "documented" },
20
23
  { slug: "dropdown-menu", registryName: "dropdown-menu", surface: "documented" },
21
24
  { slug: "popover", registryName: "popover", surface: "documented" },
@@ -52,6 +52,8 @@ export const registryGroups: RegistryGroup[] = [
52
52
  component("kbd", "stable", "src/components/ui/kbd"),
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
+ component("toggle-group", "preview", "src/components/ui/toggle-group"),
56
+ component("toolbar", "preview", "src/components/ui/toolbar"),
55
57
  component("collapse", "preview", "src/components/ui/collapse"),
56
58
  component("command", "preview", "src/components/ui/command"),
57
59
  component("divider", "preview", "src/components/ui/divider"),
@@ -80,6 +82,7 @@ export const registryGroups: RegistryGroup[] = [
80
82
  component("inline-editable", "preview", "src/components/inputs/inline-editable.tsx"),
81
83
  component("json-input", "preview", "src/components/inputs/json-input.tsx"),
82
84
  component("time-picker", "preview", "src/components/inputs/time-picker.tsx"),
85
+ component("number-field", "preview", "src/components/ui/number-field"),
83
86
  ],
84
87
  },
85
88
  {
@@ -139,8 +142,7 @@ export const registryGroups: RegistryGroup[] = [
139
142
  {
140
143
  name: "feedback",
141
144
  components: [
142
- component("loading-state", "stable", "src/components/feedback/loading-state.tsx"),
143
- component("page-state", "preview", "src/components/feedback/page-state.tsx"),
145
+ component("state-view", "stable", "src/components/feedback/state-view.tsx"),
144
146
  component("alert", "preview", "src/components/feedback/alert.tsx"),
145
147
  ],
146
148
  },
@@ -25,7 +25,7 @@ export function HeroSection() {
25
25
  <div className="flex flex-wrap gap-2">
26
26
  <Button leftIcon={<PlusIcon className="size-4" />}>Create</Button>
27
27
  <Button variant="outline" leftIcon={<SettingsIcon className="size-4" />}>Settings</Button>
28
- <CopyButton value="npx tembro@5.0.0 list --json">Copy list command</CopyButton>
28
+ <CopyButton value="npx tembro@6.0.1 list --json">Copy list command</CopyButton>
29
29
  </div>
30
30
  </div>
31
31
 
@@ -33,7 +33,7 @@ export function HeroSection() {
33
33
  <StatisticCard label="Registry components" value={moduleCount} change="visible below" trend="up" description="tembro add <name>" />
34
34
  <StatisticCard label="Local source files" value="152" change="with hooks/lib" trend="up" description="installed by CLI" />
35
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@5.0.0" />
36
+ <StatisticCard label="Build" value="Pass" change="doctor pass" trend="up" description="tembro@6.0.1" />
37
37
  </StatisticGrid>
38
38
  </div>
39
39
  </section>
@@ -72,7 +72,7 @@ export function WorkbenchSidebar({ selectedKey, onSelect }: WorkbenchSidebarProp
72
72
  }),
73
73
  ]}
74
74
  footerAccount={{
75
- label: "tembro@5.0.0",
75
+ label: "tembro@6.0.1",
76
76
  description: `${moduleCount} registry components`,
77
77
  }}
78
78
  activeIndicator="bar"
@@ -19,7 +19,7 @@ import { StatusLegend } from "@/components/display/status-legend"
19
19
  import { Tag, TagGroup } from "@/components/display/tag"
20
20
  import { Timeline } from "@/components/display/timeline"
21
21
  import { Alert } from "@/components/feedback/alert"
22
- import { LoadingState } from "@/components/feedback/loading-state"
22
+ import { StateView } from "@/components/feedback/state-view"
23
23
  import { Pagination } from "@/components/navigation/pagination"
24
24
  import { EmptyState } from "@/components/patterns/empty-state"
25
25
  import { Badge } from "@/components/ui/badge"
@@ -283,7 +283,7 @@ function DirectComponentSurface({ group, component }: ComponentLivePreviewProps)
283
283
  if (group.name === "form") return <FormsSection />
284
284
  if (group.name === "display") return <DisplayPreview />
285
285
  if (group.name === "calendar" || group.name === "navigation") return group.name === "navigation" ? <Pagination page={2} pageCount={8} onPageChange={() => undefined} /> : <CalendarSection />
286
- if (group.name === "feedback") return component.name === "alert" ? <Alert tone="success" title="Alert component" description="Rendered from feedback/alert." /> : <LoadingState label="LoadingState" description="Rendered from feedback/loading-state." />
286
+ if (group.name === "feedback") return component.name === "alert" ? <Alert tone="success" title="Alert component" description="Rendered from feedback/alert." /> : <StateView status="loading" title="StateView" description="Rendered from feedback/state-view." />
287
287
  if (group.name === "patterns") return <EmptyState title="EmptyState component" description="Rendered from patterns/empty-state." primaryAction={{ label: "Create item" }} secondaryAction={{ label: "Reset" }} />
288
288
  if (group.name === "wizard") return <WizardSection />
289
289
  if (group.name === "overlay") return <OverlaySection />
@@ -1,5 +1,5 @@
1
1
  import { ProgressCard } from "@/components/display/progress"
2
- import { LoadingState } from "@/components/feedback/loading-state"
2
+ import { StateView } from "@/components/feedback/state-view"
3
3
  import { Rating } from "@/components/inputs/rating"
4
4
  import { RangeSlider, Slider } from "@/components/inputs/slider"
5
5
  import { Badge } from "@/components/ui/badge"
@@ -20,7 +20,7 @@ export function FormsSection() {
20
20
  </CardContent>
21
21
  </Card>
22
22
  <ProgressCard title="Form completeness" description="input, select, switch, textarea" value={86} tone="success" footer={<Badge label="forms" status="success" />} />
23
- <LoadingState label="Loading state" description="Spinner/skeleton/progress state component." />
23
+ <StateView status="loading" title="Loading state" description="Spinner/skeleton/progress state component." />
24
24
  </div>
25
25
  )
26
26
  }
@@ -1876,17 +1876,17 @@
1876
1876
  [data-slot="statistic-change"][data-trend="up"] { color: var(--aui-success-fg); background: var(--aui-success-bg); }
1877
1877
  [data-slot="statistic-change"][data-trend="down"] { color: var(--destructive); background: color-mix(in oklch, var(--destructive), transparent 90%); }
1878
1878
 
1879
- [data-slot="page-state"] {
1879
+ [data-slot="state-view"] {
1880
1880
  border-color: var(--aui-card-border, var(--border));
1881
1881
  border-radius: var(--aui-radius-panel);
1882
1882
  background: var(--card);
1883
1883
  box-shadow: var(--aui-card-shadow, var(--aui-shadow-xs));
1884
1884
  }
1885
1885
 
1886
- [data-slot="page-state-icon"] { color: var(--muted-foreground); background: var(--aui-surface-muted); }
1887
- [data-slot="page-state"][data-tone="error"] [data-slot="page-state-icon"] { color: var(--destructive); background: color-mix(in oklch, var(--destructive), transparent 90%); }
1888
- [data-slot="page-state"][data-tone="success"] [data-slot="page-state-icon"] { color: var(--aui-success-fg); background: var(--aui-success-bg); }
1889
- [data-slot="page-state"][data-tone="info"] [data-slot="page-state-icon"] { color: var(--aui-info-fg); background: var(--aui-info-bg); }
1886
+ [data-slot="state-view-icon"] { color: var(--muted-foreground); background: var(--aui-surface-muted); }
1887
+ [data-slot="state-view"][data-tone="danger"] [data-slot="state-view-icon"] { color: var(--destructive); background: color-mix(in oklch, var(--destructive), transparent 90%); }
1888
+ [data-slot="state-view"][data-tone="success"] [data-slot="state-view-icon"] { color: var(--aui-success-fg); background: var(--aui-success-bg); }
1889
+ [data-slot="state-view"][data-tone="info"] [data-slot="state-view-icon"] { color: var(--aui-info-fg); background: var(--aui-info-bg); }
1890
1890
 
1891
1891
  [data-slot="file-upload-dropzone"],
1892
1892
  [data-slot="file-upload-item"] {