@squadbase/vantage 0.6.1 → 0.6.2-dev1.31accb1

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 (183) hide show
  1. package/dist/add-DY4AXANK.js +6 -0
  2. package/dist/add-DY4AXANK.js.map +1 -0
  3. package/dist/{build-O5TVNH4E.js → build-TVKFIVFQ.js} +8 -8
  4. package/dist/{build-O5TVNH4E.js.map → build-TVKFIVFQ.js.map} +1 -1
  5. package/dist/{check-WFBEDHDR.js → check-3KHZXZMQ.js} +6 -6
  6. package/dist/{check-WFBEDHDR.js.map → check-3KHZXZMQ.js.map} +1 -1
  7. package/dist/{chunk-PLST5Q7T.js → chunk-AG6RZ2RR.js} +1010 -23
  8. package/dist/chunk-AG6RZ2RR.js.map +1 -0
  9. package/dist/{chunk-KLEIVDUV.js → chunk-CEXAQQ5W.js} +150 -11
  10. package/dist/chunk-CEXAQQ5W.js.map +1 -0
  11. package/dist/{chunk-JGRMRXXZ.js → chunk-JKLLFVEU.js} +3 -3
  12. package/dist/{chunk-JGRMRXXZ.js.map → chunk-JKLLFVEU.js.map} +1 -1
  13. package/dist/{chunk-EP6JHXSR.js → chunk-LMUACBMA.js} +3 -3
  14. package/dist/{chunk-EP6JHXSR.js.map → chunk-LMUACBMA.js.map} +1 -1
  15. package/dist/{chunk-MXI3PZFT.js → chunk-OB6UBJXF.js} +156 -200
  16. package/dist/chunk-OB6UBJXF.js.map +1 -0
  17. package/dist/{chunk-BCE22JSM.js → chunk-P7W4LR3Z.js} +32 -13
  18. package/dist/chunk-P7W4LR3Z.js.map +1 -0
  19. package/dist/chunk-PXRX5PEC.js +54 -0
  20. package/dist/chunk-PXRX5PEC.js.map +1 -0
  21. package/dist/{chunk-3G43C6OL.js → chunk-QI3XQKHS.js} +39 -3
  22. package/dist/chunk-QI3XQKHS.js.map +1 -0
  23. package/dist/{chunk-QDZA5JSL.js → chunk-U2M6HGKQ.js} +3 -3
  24. package/dist/{chunk-QDZA5JSL.js.map → chunk-U2M6HGKQ.js.map} +1 -1
  25. package/dist/{chunk-T3FLAGI6.js → chunk-VA776YE5.js} +3 -3
  26. package/dist/{chunk-T3FLAGI6.js.map → chunk-VA776YE5.js.map} +1 -1
  27. package/dist/cli.js +14 -11
  28. package/dist/cli.js.map +1 -1
  29. package/dist/components/index.d.ts +223 -1
  30. package/dist/components/index.js +3 -2
  31. package/dist/{dev-NZRLOQCL.js → dev-GDKATCC7.js} +22 -11
  32. package/dist/dev-GDKATCC7.js.map +1 -0
  33. package/dist/doc/index.d.ts +4 -0
  34. package/dist/doc/index.js +107 -11
  35. package/dist/doc/index.js.map +1 -1
  36. package/dist/{docs-ZGDJUHJI.js → docs-EJJ3BECT.js} +3 -3
  37. package/dist/{docs-ZGDJUHJI.js.map → docs-EJJ3BECT.js.map} +1 -1
  38. package/dist/{doctor-VFKEMR54.js → doctor-WQXPXP6K.js} +7 -7
  39. package/dist/doctor-WQXPXP6K.js.map +1 -0
  40. package/dist/{preview-QDCIVVSR.js → preview-OGMCNQUO.js} +12 -4
  41. package/dist/preview-OGMCNQUO.js.map +1 -0
  42. package/dist/{routes-RHP5FVGD.js → routes-MWBWWOJ2.js} +5 -5
  43. package/dist/{routes-RHP5FVGD.js.map → routes-MWBWWOJ2.js.map} +1 -1
  44. package/dist/{search-RFBELGY7.js → search-6Y422SV6.js} +3 -3
  45. package/dist/{search-RFBELGY7.js.map → search-6Y422SV6.js.map} +1 -1
  46. package/dist/slide/index.js +61 -15
  47. package/dist/slide/index.js.map +1 -1
  48. package/dist/table/index.js +7 -5
  49. package/dist/table/index.js.map +1 -1
  50. package/dist/ui/index.d.ts +140 -10
  51. package/dist/ui/index.js +1406 -63
  52. package/dist/ui/index.js.map +1 -1
  53. package/dist/{upgrade-GF2P67M6.js → upgrade-HCANX4GQ.js} +6 -6
  54. package/dist/{upgrade-GF2P67M6.js.map → upgrade-HCANX4GQ.js.map} +1 -1
  55. package/dist/vite/index.js +3 -3
  56. package/docs/en/changelog.md +24 -0
  57. package/docs/en/cli-reference.md +30 -0
  58. package/docs/en/parts/page-shell.md +1 -1
  59. package/docs/en/routing.md +4 -2
  60. package/docs/index.json +291 -61
  61. package/docs/ja/changelog.md +50 -0
  62. package/docs/ja/cli-reference.md +29 -0
  63. package/docs/ja/components.md +33 -89
  64. package/docs/ja/page-types/csv.md +83 -0
  65. package/docs/ja/page-types/doc.md +83 -0
  66. package/docs/ja/page-types/excel.md +82 -0
  67. package/docs/ja/page-types/slide.md +132 -0
  68. package/docs/ja/page-types.md +47 -0
  69. package/docs/ja/parts/area-chart.md +61 -0
  70. package/docs/ja/parts/bar-chart.md +69 -0
  71. package/docs/ja/parts/bar-list.md +35 -0
  72. package/docs/ja/parts/category-bar.md +36 -0
  73. package/docs/ja/parts/donut-chart.md +47 -0
  74. package/docs/ja/parts/echart.md +3 -0
  75. package/docs/ja/parts/line-chart.md +58 -0
  76. package/docs/ja/parts/page-shell.md +1 -1
  77. package/docs/ja/parts/progress-circle.md +34 -0
  78. package/docs/ja/parts/sparkline.md +1 -1
  79. package/docs/ja/parts/tracker.md +32 -0
  80. package/docs/ja/routing.md +8 -84
  81. package/docs/ja/ui/alert-dialog.md +41 -0
  82. package/docs/ja/ui/avatar.md +31 -0
  83. package/docs/ja/ui/combobox.md +74 -0
  84. package/docs/ja/ui/drawer.md +41 -0
  85. package/docs/ja/ui/field.md +42 -0
  86. package/docs/ja/ui/hover-card.md +21 -0
  87. package/docs/ja/ui/kbd.md +16 -0
  88. package/docs/ja/ui/pagination.md +36 -0
  89. package/docs/ja/ui/radio-group.md +21 -0
  90. package/docs/ja/ui/toast.md +46 -0
  91. package/docs/ja/ui-and-theming.md +14 -7
  92. package/package.json +18 -12
  93. package/registry/ui/accordion.tsx +74 -0
  94. package/registry/ui/alert-dialog.tsx +189 -0
  95. package/registry/ui/alert.tsx +78 -0
  96. package/registry/ui/app-shell.tsx +281 -0
  97. package/registry/ui/area-chart.tsx +1015 -0
  98. package/registry/ui/avatar.tsx +110 -0
  99. package/registry/ui/badge.tsx +54 -0
  100. package/registry/ui/bar-chart.tsx +1013 -0
  101. package/registry/ui/bar-list.tsx +302 -0
  102. package/registry/ui/breadcrumb.tsx +126 -0
  103. package/registry/ui/button.tsx +60 -0
  104. package/registry/ui/calendar.tsx +221 -0
  105. package/registry/ui/card.tsx +105 -0
  106. package/registry/ui/category-bar.tsx +281 -0
  107. package/registry/ui/checkbox.tsx +28 -0
  108. package/registry/ui/collapsible.tsx +21 -0
  109. package/registry/ui/combobox.tsx +310 -0
  110. package/registry/ui/command.tsx +196 -0
  111. package/registry/ui/dashboard-card.tsx +174 -0
  112. package/registry/ui/data-table.tsx +16 -91
  113. package/registry/ui/date-range-picker.tsx +209 -0
  114. package/registry/ui/dialog.tsx +159 -0
  115. package/registry/ui/donut-chart.tsx +1004 -0
  116. package/registry/ui/drawer.tsx +229 -0
  117. package/registry/ui/dropdown-menu.tsx +272 -0
  118. package/registry/ui/echart.tsx +486 -0
  119. package/registry/ui/field.tsx +240 -0
  120. package/registry/ui/filter-bar.tsx +365 -0
  121. package/registry/ui/funnel-steps.tsx +274 -0
  122. package/registry/ui/hover-card.tsx +52 -0
  123. package/registry/ui/input-group.tsx +158 -0
  124. package/registry/ui/input.tsx +22 -0
  125. package/registry/ui/kbd.tsx +28 -0
  126. package/registry/ui/label.tsx +20 -0
  127. package/registry/ui/line-chart.tsx +1007 -0
  128. package/registry/ui/metric-value.tsx +54 -0
  129. package/registry/ui/multi-select.tsx +226 -0
  130. package/registry/ui/page-shell.tsx +227 -0
  131. package/registry/ui/pagination.tsx +138 -0
  132. package/registry/ui/placeholder.tsx +30 -0
  133. package/registry/ui/popover.tsx +90 -0
  134. package/registry/ui/progress-circle.tsx +272 -0
  135. package/registry/ui/progress.tsx +83 -0
  136. package/registry/ui/radio-group.tsx +39 -0
  137. package/registry/ui/scroll-area.tsx +55 -0
  138. package/registry/ui/searchable-select.tsx +209 -0
  139. package/registry/ui/section-header.tsx +41 -0
  140. package/registry/ui/segmented-control.tsx +71 -0
  141. package/registry/ui/select.tsx +253 -0
  142. package/registry/ui/separator.tsx +25 -0
  143. package/registry/ui/sheet.tsx +137 -0
  144. package/registry/ui/sidebar.tsx +723 -0
  145. package/registry/ui/skeleton.tsx +15 -0
  146. package/registry/ui/slider.tsx +54 -0
  147. package/registry/ui/sparkline.tsx +155 -0
  148. package/registry/ui/spinner.tsx +12 -0
  149. package/registry/ui/states.tsx +61 -0
  150. package/registry/ui/status-badge.tsx +79 -0
  151. package/registry/ui/switch.tsx +32 -0
  152. package/registry/ui/table.tsx +116 -0
  153. package/registry/ui/tabs.tsx +82 -0
  154. package/registry/ui/textarea.tsx +20 -0
  155. package/registry/ui/toast.tsx +250 -0
  156. package/registry/ui/toggle-group.tsx +89 -0
  157. package/registry/ui/toggle.tsx +45 -0
  158. package/registry/ui/tooltip.tsx +66 -0
  159. package/registry/ui/tracker.tsx +236 -0
  160. package/registry/ui/trend-indicator.tsx +62 -0
  161. package/skills/vantage-add-feature/SKILL.md +9 -7
  162. package/skills/vantage-design/SKILL.md +3 -1
  163. package/skills/vantage-design/references/format.md +1 -1
  164. package/skills/vantage-pitfalls/SKILL.md +5 -1
  165. package/skills/vantage-slide/SKILL.md +17 -0
  166. package/templates/AGENTS.md +10 -1
  167. package/templates/agents/api.md +29 -0
  168. package/templates/agents/csv.md +2 -1
  169. package/templates/agents/doc.md +6 -3
  170. package/templates/agents/page.md +22 -8
  171. package/templates/agents/slide.md +13 -1
  172. package/templates/agents/xlsx.md +2 -1
  173. package/theme.css +51 -1
  174. package/dist/add-EISGSZAH.js +0 -6
  175. package/dist/add-EISGSZAH.js.map +0 -1
  176. package/dist/chunk-3G43C6OL.js.map +0 -1
  177. package/dist/chunk-BCE22JSM.js.map +0 -1
  178. package/dist/chunk-KLEIVDUV.js.map +0 -1
  179. package/dist/chunk-MXI3PZFT.js.map +0 -1
  180. package/dist/chunk-PLST5Q7T.js.map +0 -1
  181. package/dist/dev-NZRLOQCL.js.map +0 -1
  182. package/dist/doctor-VFKEMR54.js.map +0 -1
  183. package/dist/preview-QDCIVVSR.js.map +0 -1
@@ -0,0 +1,15 @@
1
+ // Copied by `vantage add ui skeleton`. This file is yours to edit.
2
+ // Generated from @squadbase/vantage src/ui/skeleton.tsx by `npm run registry` (in Vantage, edit src/, not registry/).
3
+ import { cn } from "@squadbase/vantage/ui"
4
+
5
+ function Skeleton({ className, ...props }: React.ComponentProps<"div">) {
6
+ return (
7
+ <div
8
+ data-slot="skeleton"
9
+ className={cn("animate-pulse rounded-md bg-muted", className)}
10
+ {...props}
11
+ />
12
+ )
13
+ }
14
+
15
+ export { Skeleton }
@@ -0,0 +1,54 @@
1
+ // Copied by `vantage add ui slider`. This file is yours to edit.
2
+ // Generated from @squadbase/vantage src/ui/slider.tsx by `npm run registry` (in Vantage, edit src/, not registry/).
3
+ import { Slider as SliderPrimitive } from "@base-ui/react/slider"
4
+
5
+ import { cn } from "@squadbase/vantage/ui"
6
+
7
+ function Slider({
8
+ className,
9
+ defaultValue,
10
+ value,
11
+ min = 0,
12
+ max = 100,
13
+ ...props
14
+ }: SliderPrimitive.Root.Props) {
15
+ const _values = Array.isArray(value)
16
+ ? value
17
+ : Array.isArray(defaultValue)
18
+ ? defaultValue
19
+ : [min, max]
20
+
21
+ return (
22
+ <SliderPrimitive.Root
23
+ className={cn("data-horizontal:w-full data-vertical:h-full", className)}
24
+ data-slot="slider"
25
+ defaultValue={defaultValue}
26
+ value={value}
27
+ min={min}
28
+ max={max}
29
+ thumbAlignment="edge"
30
+ {...props}
31
+ >
32
+ <SliderPrimitive.Control className="relative flex w-full touch-none items-center select-none data-disabled:opacity-50 data-vertical:h-full data-vertical:min-h-40 data-vertical:w-auto data-vertical:flex-col">
33
+ <SliderPrimitive.Track
34
+ data-slot="slider-track"
35
+ className="relative grow overflow-hidden rounded-full bg-muted select-none data-horizontal:h-1 data-horizontal:w-full data-vertical:h-full data-vertical:w-1"
36
+ >
37
+ <SliderPrimitive.Indicator
38
+ data-slot="slider-range"
39
+ className="bg-primary select-none data-horizontal:h-full data-vertical:w-full"
40
+ />
41
+ </SliderPrimitive.Track>
42
+ {Array.from({ length: _values.length }, (_, index) => (
43
+ <SliderPrimitive.Thumb
44
+ data-slot="slider-thumb"
45
+ key={index}
46
+ className="relative block size-3 shrink-0 rounded-full border border-ring bg-white ring-ring/50 transition-[color,box-shadow] select-none after:absolute after:-inset-2 hover:ring-3 focus-visible:ring-3 focus-visible:outline-hidden active:ring-3 disabled:pointer-events-none disabled:opacity-50"
47
+ />
48
+ ))}
49
+ </SliderPrimitive.Control>
50
+ </SliderPrimitive.Root>
51
+ )
52
+ }
53
+
54
+ export { Slider }
@@ -0,0 +1,155 @@
1
+ // Copied by `vantage add ui sparkline`. This file is yours to edit.
2
+ // Generated from @squadbase/vantage src/components/sparkline.tsx by `npm run registry` (in Vantage, edit src/, not registry/).
3
+ /**
4
+ * Sparkline — an inline trend micro-chart. Deliberately *not* an `EChart`: a
5
+ * sparkline sits inside table cells and KPI tiles by the dozen, where one
6
+ * ECharts instance per cell would be wasteful. This renders a single stateless
7
+ * `<svg>` instead, so hundreds of them stay cheap.
8
+ */
9
+ import { forwardRef, useEffect, useState, type SVGAttributes } from "react"
10
+
11
+ import { cn } from "@squadbase/vantage/ui"
12
+
13
+ export type SparklineVariant = "line" | "bar"
14
+
15
+ export interface SparklineDataPoint {
16
+ value: number
17
+ label?: string
18
+ }
19
+
20
+ export interface SparklineProps extends SVGAttributes<SVGSVGElement> {
21
+ data: SparklineDataPoint[]
22
+ variant?: SparklineVariant
23
+ height?: number
24
+ /** Tailwind text-colour class; drives both stroke and fill via `currentColor`. */
25
+ color?: string
26
+ area?: boolean
27
+ animate?: boolean
28
+ className?: string
29
+ }
30
+
31
+ const VB_WIDTH = 100
32
+
33
+ /** Map raw values onto SVG y-coordinates (inverted, padded). */
34
+ function normalizeData(values: number[], height: number, vPad = 2): number[] {
35
+ const min = Math.min(...values)
36
+ const max = Math.max(...values)
37
+ const range = max - min
38
+ const drawHeight = height - vPad * 2
39
+ if (range === 0) return values.map(() => vPad + drawHeight / 2)
40
+ return values.map((v) => height - vPad - ((v - min) / range) * drawHeight)
41
+ }
42
+
43
+ function buildLinePath(ys: number[]): string {
44
+ if (ys.length === 0) return ""
45
+ const step = ys.length > 1 ? VB_WIDTH / (ys.length - 1) : 0
46
+ return ys
47
+ .map((y, i) => `${i === 0 ? "M" : "L"}${(i * step).toFixed(2)},${y.toFixed(2)}`)
48
+ .join(" ")
49
+ }
50
+
51
+ function buildAreaPath(ys: number[], height: number): string {
52
+ if (ys.length === 0) return ""
53
+ const step = ys.length > 1 ? VB_WIDTH / (ys.length - 1) : 0
54
+ const lastX = ((ys.length - 1) * step).toFixed(2)
55
+ return `${buildLinePath(ys)} L${lastX},${height} L0,${height} Z`
56
+ }
57
+
58
+ interface BarRect {
59
+ x: number
60
+ y: number
61
+ w: number
62
+ h: number
63
+ }
64
+
65
+ function buildBarRects(ys: number[], height: number, gap = 1): BarRect[] {
66
+ const barW = Math.max(1, VB_WIDTH / ys.length - gap)
67
+ return ys.map((y, i) => ({ x: i * (barW + gap), y, w: barW, h: height - y }))
68
+ }
69
+
70
+ export const Sparkline = forwardRef<SVGSVGElement, SparklineProps>(function Sparkline(
71
+ {
72
+ data,
73
+ variant = "line",
74
+ height = 40,
75
+ color = "text-chart-1",
76
+ area = false,
77
+ animate = false,
78
+ className,
79
+ ...props
80
+ },
81
+ ref,
82
+ ) {
83
+ const [mounted, setMounted] = useState(false)
84
+
85
+ useEffect(() => {
86
+ if (animate) setMounted(true)
87
+ }, [animate])
88
+
89
+ if (data.length === 0) return null
90
+
91
+ const ys = normalizeData(
92
+ data.map((d) => d.value),
93
+ height,
94
+ )
95
+
96
+ return (
97
+ <svg
98
+ ref={ref}
99
+ data-slot="sparkline"
100
+ viewBox={`0 0 ${VB_WIDTH} ${height}`}
101
+ preserveAspectRatio="none"
102
+ width="100%"
103
+ height={height}
104
+ aria-hidden="true"
105
+ className={cn("overflow-visible", className)}
106
+ {...props}
107
+ >
108
+ {variant === "line" && (
109
+ <>
110
+ {area && (
111
+ <path
112
+ d={buildAreaPath(ys, height)}
113
+ strokeWidth={0}
114
+ className={cn("fill-current opacity-15", color)}
115
+ />
116
+ )}
117
+ <path
118
+ d={buildLinePath(ys)}
119
+ fill="none"
120
+ strokeWidth={1.5}
121
+ strokeLinecap="round"
122
+ strokeLinejoin="round"
123
+ vectorEffect="non-scaling-stroke"
124
+ pathLength={animate ? 1 : undefined}
125
+ strokeDasharray={animate ? 1 : undefined}
126
+ strokeDashoffset={animate ? (mounted ? 0 : 1) : undefined}
127
+ className={cn("stroke-current", color)}
128
+ style={animate ? { transition: "stroke-dashoffset 0.6s ease-in-out" } : undefined}
129
+ />
130
+ </>
131
+ )}
132
+
133
+ {variant === "bar" &&
134
+ buildBarRects(ys, height).map((rect, i) => (
135
+ <rect
136
+ key={i}
137
+ x={rect.x}
138
+ y={animate ? (mounted ? rect.y : height) : rect.y}
139
+ width={rect.w}
140
+ height={animate ? (mounted ? rect.h : 0) : rect.h}
141
+ rx={0.5}
142
+ className={cn("fill-current", color)}
143
+ style={
144
+ animate
145
+ ? {
146
+ transition: `height 0.4s ease-out ${i * 0.02}s, y 0.4s ease-out ${i * 0.02}s`,
147
+ }
148
+ : undefined
149
+ }
150
+ />
151
+ ))}
152
+ </svg>
153
+ )
154
+ })
155
+ Sparkline.displayName = "Sparkline"
@@ -0,0 +1,12 @@
1
+ // Copied by `vantage add ui spinner`. This file is yours to edit.
2
+ // Generated from @squadbase/vantage src/ui/spinner.tsx by `npm run registry` (in Vantage, edit src/, not registry/).
3
+ import { cn } from "@squadbase/vantage/ui"
4
+ import { Loader2Icon } from "lucide-react"
5
+
6
+ function Spinner({ className, ...props }: React.ComponentProps<"svg">) {
7
+ return (
8
+ <Loader2Icon data-slot="spinner" role="status" aria-label="Loading" className={cn("size-4 animate-spin", className)} {...props} />
9
+ )
10
+ }
11
+
12
+ export { Spinner }
@@ -0,0 +1,61 @@
1
+ // Copied by `vantage add ui states`. This file is yours to edit.
2
+ // Generated from @squadbase/vantage src/ui/states.tsx by `npm run registry` (in Vantage, edit src/, not registry/).
3
+ import type { ReactNode } from "react"
4
+ import { cn } from "@squadbase/vantage/ui"
5
+
6
+ export function Loading({ label = "Loading…", className }: { label?: string; className?: string }) {
7
+ return (
8
+ <div className={cn("flex min-h-[30vh] items-center justify-center", className)} role="status" aria-live="polite">
9
+ <div className="flex items-center gap-3 text-sm text-muted-foreground">
10
+ <span className="h-4 w-4 animate-spin rounded-full border-2 border-current border-t-transparent" />
11
+ {label}
12
+ </div>
13
+ </div>
14
+ )
15
+ }
16
+
17
+ export function Empty({
18
+ title = "Nothing here yet",
19
+ description,
20
+ icon,
21
+ action,
22
+ className,
23
+ }: {
24
+ title?: string
25
+ description?: string
26
+ icon?: ReactNode
27
+ action?: ReactNode
28
+ className?: string
29
+ }) {
30
+ return (
31
+ <div className={cn("flex flex-col items-center justify-center gap-2 p-10 text-center", className)}>
32
+ {icon ? <div className="text-3xl text-muted-foreground">{icon}</div> : null}
33
+ <p className="font-medium">{title}</p>
34
+ {description ? <p className="max-w-sm text-sm text-muted-foreground">{description}</p> : null}
35
+ {action ? <div className="mt-2">{action}</div> : null}
36
+ </div>
37
+ )
38
+ }
39
+
40
+ export function ErrorState({
41
+ title = "Something went wrong",
42
+ message,
43
+ action,
44
+ className,
45
+ }: {
46
+ title?: string
47
+ message?: ReactNode
48
+ action?: ReactNode
49
+ className?: string
50
+ }) {
51
+ return (
52
+ <div
53
+ className={cn("rounded-xl border border-destructive/30 bg-destructive/5 p-6", className)}
54
+ role="alert"
55
+ >
56
+ <p className="font-semibold text-destructive">{title}</p>
57
+ {message ? <p className="mt-1 text-sm text-muted-foreground">{message}</p> : null}
58
+ {action ? <div className="mt-3">{action}</div> : null}
59
+ </div>
60
+ )
61
+ }
@@ -0,0 +1,79 @@
1
+ // Copied by `vantage add ui status-badge`. This file is yours to edit.
2
+ // Generated from @squadbase/vantage src/components/status-badge.tsx by `npm run registry` (in Vantage, edit src/, not registry/).
3
+ /**
4
+ * StatusBadge — a dot-plus-label badge for row/record status. Statuses map to
5
+ * colours through `defaultColorMap`; pass `colorMap` to extend or override it.
6
+ */
7
+ import { forwardRef } from "react"
8
+
9
+ import { cn } from "@squadbase/vantage/ui"
10
+ import { Badge } from "@squadbase/vantage/ui"
11
+
12
+ const defaultColorMap: Record<string, string> = {
13
+ active: "green",
14
+ inactive: "gray",
15
+ warning: "yellow",
16
+ error: "red",
17
+ pending: "blue",
18
+ }
19
+
20
+ const colorStyles: Record<string, { dot: string; bg: string; text: string }> = {
21
+ green: {
22
+ dot: "bg-green-500",
23
+ bg: "bg-green-50 dark:bg-green-950",
24
+ text: "text-green-700 dark:text-green-300",
25
+ },
26
+ gray: {
27
+ dot: "bg-gray-500",
28
+ bg: "bg-gray-50 dark:bg-gray-950",
29
+ text: "text-gray-700 dark:text-gray-300",
30
+ },
31
+ yellow: {
32
+ dot: "bg-yellow-500",
33
+ bg: "bg-yellow-50 dark:bg-yellow-950",
34
+ text: "text-yellow-700 dark:text-yellow-300",
35
+ },
36
+ red: {
37
+ dot: "bg-red-500",
38
+ bg: "bg-red-50 dark:bg-red-950",
39
+ text: "text-red-700 dark:text-red-300",
40
+ },
41
+ blue: {
42
+ dot: "bg-blue-500",
43
+ bg: "bg-blue-50 dark:bg-blue-950",
44
+ text: "text-blue-700 dark:text-blue-300",
45
+ },
46
+ }
47
+
48
+ const fallbackStyle = colorStyles.gray!
49
+
50
+ export interface StatusBadgeProps {
51
+ status: string
52
+ label?: string
53
+ colorMap?: Partial<Record<string, string>>
54
+ className?: string
55
+ }
56
+
57
+ export const StatusBadge = forwardRef<HTMLSpanElement, StatusBadgeProps>(function StatusBadge(
58
+ { status, label, colorMap, className },
59
+ ref,
60
+ ) {
61
+ const mergedColorMap = { ...defaultColorMap, ...colorMap }
62
+ const color = mergedColorMap[status] ?? "gray"
63
+ const style = colorStyles[color] ?? fallbackStyle
64
+ const displayLabel = label ?? status
65
+
66
+ return (
67
+ <Badge
68
+ ref={ref}
69
+ data-slot="status-badge"
70
+ variant="outline"
71
+ className={cn("gap-1.5 border-transparent", style.bg, style.text, className)}
72
+ aria-label={displayLabel}
73
+ >
74
+ <span className={cn("inline-block size-2 rounded-full", style.dot)} aria-hidden="true" />
75
+ {displayLabel}
76
+ </Badge>
77
+ )
78
+ })
79
+ StatusBadge.displayName = "StatusBadge"
@@ -0,0 +1,32 @@
1
+ // Copied by `vantage add ui switch`. This file is yours to edit.
2
+ // Generated from @squadbase/vantage src/ui/switch.tsx by `npm run registry` (in Vantage, edit src/, not registry/).
3
+ import { Switch as SwitchPrimitive } from "@base-ui/react/switch"
4
+
5
+ import { cn } from "@squadbase/vantage/ui"
6
+
7
+ function Switch({
8
+ className,
9
+ size = "default",
10
+ ...props
11
+ }: SwitchPrimitive.Root.Props & {
12
+ size?: "sm" | "default"
13
+ }) {
14
+ return (
15
+ <SwitchPrimitive.Root
16
+ data-slot="switch"
17
+ data-size={size}
18
+ className={cn(
19
+ "peer group/switch relative inline-flex shrink-0 items-center rounded-full border border-transparent transition-all outline-none after:absolute after:-inset-x-3 after:-inset-y-2 focus-visible:border-ring focus-visible:ring-3 focus-visible:ring-ring/50 aria-invalid:border-destructive aria-invalid:ring-3 aria-invalid:ring-destructive/20 data-[size=default]:h-[18.4px] data-[size=default]:w-[32px] data-[size=sm]:h-[14px] data-[size=sm]:w-[24px] dark:aria-invalid:border-destructive/50 dark:aria-invalid:ring-destructive/40 data-checked:bg-primary data-unchecked:bg-input dark:data-unchecked:bg-input/80 data-disabled:cursor-not-allowed data-disabled:opacity-50",
20
+ className
21
+ )}
22
+ {...props}
23
+ >
24
+ <SwitchPrimitive.Thumb
25
+ data-slot="switch-thumb"
26
+ className="pointer-events-none block rounded-full bg-background ring-0 transition-transform group-data-[size=default]/switch:size-4 group-data-[size=sm]/switch:size-3 group-data-[size=default]/switch:data-checked:translate-x-[calc(100%-2px)] group-data-[size=sm]/switch:data-checked:translate-x-[calc(100%-2px)] dark:data-checked:bg-primary-foreground group-data-[size=default]/switch:data-unchecked:translate-x-0 group-data-[size=sm]/switch:data-unchecked:translate-x-0 dark:data-unchecked:bg-foreground"
27
+ />
28
+ </SwitchPrimitive.Root>
29
+ )
30
+ }
31
+
32
+ export { Switch }
@@ -0,0 +1,116 @@
1
+ // Copied by `vantage add ui table`. This file is yours to edit.
2
+ // Generated from @squadbase/vantage src/ui/table.tsx by `npm run registry` (in Vantage, edit src/, not registry/).
3
+ import * as React from "react"
4
+
5
+ import { cn } from "@squadbase/vantage/ui"
6
+
7
+ function Table({ className, ...props }: React.ComponentProps<"table">) {
8
+ return (
9
+ <div
10
+ data-slot="table-container"
11
+ className="relative w-full overflow-x-auto"
12
+ >
13
+ <table
14
+ data-slot="table"
15
+ className={cn("w-full caption-bottom text-sm", className)}
16
+ {...props}
17
+ />
18
+ </div>
19
+ )
20
+ }
21
+
22
+ function TableHeader({ className, ...props }: React.ComponentProps<"thead">) {
23
+ return (
24
+ <thead
25
+ data-slot="table-header"
26
+ className={cn("[&_tr]:border-b", className)}
27
+ {...props}
28
+ />
29
+ )
30
+ }
31
+
32
+ function TableBody({ className, ...props }: React.ComponentProps<"tbody">) {
33
+ return (
34
+ <tbody
35
+ data-slot="table-body"
36
+ className={cn("[&_tr:last-child]:border-0", className)}
37
+ {...props}
38
+ />
39
+ )
40
+ }
41
+
42
+ function TableFooter({ className, ...props }: React.ComponentProps<"tfoot">) {
43
+ return (
44
+ <tfoot
45
+ data-slot="table-footer"
46
+ className={cn(
47
+ "border-t bg-muted/50 font-medium [&>tr]:last:border-b-0",
48
+ className
49
+ )}
50
+ {...props}
51
+ />
52
+ )
53
+ }
54
+
55
+ function TableRow({ className, ...props }: React.ComponentProps<"tr">) {
56
+ return (
57
+ <tr
58
+ data-slot="table-row"
59
+ className={cn(
60
+ "border-b transition-colors hover:bg-muted/50 has-aria-expanded:bg-muted/50 data-[state=selected]:bg-muted",
61
+ className
62
+ )}
63
+ {...props}
64
+ />
65
+ )
66
+ }
67
+
68
+ function TableHead({ className, ...props }: React.ComponentProps<"th">) {
69
+ return (
70
+ <th
71
+ data-slot="table-head"
72
+ className={cn(
73
+ "h-10 px-2 text-left align-middle font-medium whitespace-nowrap text-foreground [&:has([role=checkbox])]:pr-0",
74
+ className
75
+ )}
76
+ {...props}
77
+ />
78
+ )
79
+ }
80
+
81
+ function TableCell({ className, ...props }: React.ComponentProps<"td">) {
82
+ return (
83
+ <td
84
+ data-slot="table-cell"
85
+ className={cn(
86
+ "p-2 align-middle whitespace-nowrap [&:has([role=checkbox])]:pr-0",
87
+ className
88
+ )}
89
+ {...props}
90
+ />
91
+ )
92
+ }
93
+
94
+ function TableCaption({
95
+ className,
96
+ ...props
97
+ }: React.ComponentProps<"caption">) {
98
+ return (
99
+ <caption
100
+ data-slot="table-caption"
101
+ className={cn("mt-4 text-sm text-muted-foreground", className)}
102
+ {...props}
103
+ />
104
+ )
105
+ }
106
+
107
+ export {
108
+ Table,
109
+ TableHeader,
110
+ TableBody,
111
+ TableFooter,
112
+ TableHead,
113
+ TableRow,
114
+ TableCell,
115
+ TableCaption,
116
+ }
@@ -0,0 +1,82 @@
1
+ // Copied by `vantage add ui tabs`. This file is yours to edit.
2
+ // Generated from @squadbase/vantage src/ui/tabs.tsx by `npm run registry` (in Vantage, edit src/, not registry/).
3
+ import { Tabs as TabsPrimitive } from "@base-ui/react/tabs"
4
+ import { cva, type VariantProps } from "class-variance-authority"
5
+
6
+ import { cn } from "@squadbase/vantage/ui"
7
+
8
+ function Tabs({
9
+ className,
10
+ orientation = "horizontal",
11
+ ...props
12
+ }: TabsPrimitive.Root.Props) {
13
+ return (
14
+ <TabsPrimitive.Root
15
+ data-slot="tabs"
16
+ data-orientation={orientation}
17
+ className={cn(
18
+ "group/tabs flex gap-2 data-horizontal:flex-col",
19
+ className
20
+ )}
21
+ {...props}
22
+ />
23
+ )
24
+ }
25
+
26
+ const tabsListVariants = cva(
27
+ "group/tabs-list inline-flex w-fit items-center justify-center rounded-lg p-[3px] text-muted-foreground group-data-horizontal/tabs:h-8 group-data-vertical/tabs:h-fit group-data-vertical/tabs:flex-col data-[variant=line]:rounded-none",
28
+ {
29
+ variants: {
30
+ variant: {
31
+ default: "bg-muted",
32
+ line: "gap-1 bg-transparent",
33
+ },
34
+ },
35
+ defaultVariants: {
36
+ variant: "default",
37
+ },
38
+ }
39
+ )
40
+
41
+ function TabsList({
42
+ className,
43
+ variant = "default",
44
+ ...props
45
+ }: TabsPrimitive.List.Props & VariantProps<typeof tabsListVariants>) {
46
+ return (
47
+ <TabsPrimitive.List
48
+ data-slot="tabs-list"
49
+ data-variant={variant}
50
+ className={cn(tabsListVariants({ variant }), className)}
51
+ {...props}
52
+ />
53
+ )
54
+ }
55
+
56
+ function TabsTrigger({ className, ...props }: TabsPrimitive.Tab.Props) {
57
+ return (
58
+ <TabsPrimitive.Tab
59
+ data-slot="tabs-trigger"
60
+ className={cn(
61
+ "relative inline-flex h-[calc(100%-1px)] flex-1 items-center justify-center gap-1.5 rounded-md border border-transparent px-1.5 py-0.5 text-sm font-medium whitespace-nowrap text-foreground/60 transition-all group-data-vertical/tabs:w-full group-data-vertical/tabs:justify-start hover:text-foreground focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50 focus-visible:outline-1 focus-visible:outline-ring disabled:pointer-events-none disabled:opacity-50 has-data-[icon=inline-end]:pr-1 has-data-[icon=inline-start]:pl-1 aria-disabled:pointer-events-none aria-disabled:opacity-50 dark:text-muted-foreground dark:hover:text-foreground group-data-[variant=default]/tabs-list:data-active:shadow-sm group-data-[variant=line]/tabs-list:data-active:shadow-none [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
62
+ "group-data-[variant=line]/tabs-list:bg-transparent group-data-[variant=line]/tabs-list:data-active:bg-transparent dark:group-data-[variant=line]/tabs-list:data-active:border-transparent dark:group-data-[variant=line]/tabs-list:data-active:bg-transparent",
63
+ "data-active:bg-background data-active:text-foreground dark:data-active:border-input dark:data-active:bg-input/30 dark:data-active:text-foreground",
64
+ "after:absolute after:bg-foreground after:opacity-0 after:transition-opacity group-data-horizontal/tabs:after:inset-x-0 group-data-horizontal/tabs:after:bottom-[-5px] group-data-horizontal/tabs:after:h-0.5 group-data-vertical/tabs:after:inset-y-0 group-data-vertical/tabs:after:-right-1 group-data-vertical/tabs:after:w-0.5 group-data-[variant=line]/tabs-list:data-active:after:opacity-100",
65
+ className
66
+ )}
67
+ {...props}
68
+ />
69
+ )
70
+ }
71
+
72
+ function TabsContent({ className, ...props }: TabsPrimitive.Panel.Props) {
73
+ return (
74
+ <TabsPrimitive.Panel
75
+ data-slot="tabs-content"
76
+ className={cn("flex-1 text-sm outline-none", className)}
77
+ {...props}
78
+ />
79
+ )
80
+ }
81
+
82
+ export { Tabs, TabsList, TabsTrigger, TabsContent, tabsListVariants }
@@ -0,0 +1,20 @@
1
+ // Copied by `vantage add ui textarea`. This file is yours to edit.
2
+ // Generated from @squadbase/vantage src/ui/textarea.tsx by `npm run registry` (in Vantage, edit src/, not registry/).
3
+ import * as React from "react"
4
+
5
+ import { cn } from "@squadbase/vantage/ui"
6
+
7
+ function Textarea({ className, ...props }: React.ComponentProps<"textarea">) {
8
+ return (
9
+ <textarea
10
+ data-slot="textarea"
11
+ className={cn(
12
+ "flex field-sizing-content min-h-16 w-full rounded-lg border border-input bg-transparent px-2.5 py-2 text-base transition-colors outline-none placeholder:text-muted-foreground focus-visible:border-ring focus-visible:ring-3 focus-visible:ring-ring/50 disabled:cursor-not-allowed disabled:bg-input/50 disabled:opacity-50 aria-invalid:border-destructive aria-invalid:ring-3 aria-invalid:ring-destructive/20 md:text-sm dark:bg-input/30 dark:disabled:bg-input/80 dark:aria-invalid:border-destructive/50 dark:aria-invalid:ring-destructive/40",
13
+ className
14
+ )}
15
+ {...props}
16
+ />
17
+ )
18
+ }
19
+
20
+ export { Textarea }