@squadbase/vantage 0.6.1-dev2.5f947f1 → 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 (178) 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-LSRMRIXA.js → chunk-AG6RZ2RR.js} +1004 -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-RPZAALCX.js → chunk-OB6UBJXF.js} +153 -153
  16. package/dist/{chunk-RPZAALCX.js.map → chunk-OB6UBJXF.js.map} +1 -1
  17. package/dist/{chunk-BCE22JSM.js → chunk-P7W4LR3Z.js} +32 -13
  18. package/dist/chunk-P7W4LR3Z.js.map +1 -0
  19. package/dist/{chunk-3G43C6OL.js → chunk-QI3XQKHS.js} +39 -3
  20. package/dist/chunk-QI3XQKHS.js.map +1 -0
  21. package/dist/{chunk-QDZA5JSL.js → chunk-U2M6HGKQ.js} +3 -3
  22. package/dist/{chunk-QDZA5JSL.js.map → chunk-U2M6HGKQ.js.map} +1 -1
  23. package/dist/{chunk-T3FLAGI6.js → chunk-VA776YE5.js} +3 -3
  24. package/dist/{chunk-T3FLAGI6.js.map → chunk-VA776YE5.js.map} +1 -1
  25. package/dist/cli.js +14 -11
  26. package/dist/cli.js.map +1 -1
  27. package/dist/components/index.d.ts +223 -1
  28. package/dist/components/index.js +2 -2
  29. package/dist/{dev-NZRLOQCL.js → dev-GDKATCC7.js} +22 -11
  30. package/dist/dev-GDKATCC7.js.map +1 -0
  31. package/dist/doc/index.js +2 -0
  32. package/dist/doc/index.js.map +1 -1
  33. package/dist/{docs-ZGDJUHJI.js → docs-EJJ3BECT.js} +3 -3
  34. package/dist/{docs-ZGDJUHJI.js.map → docs-EJJ3BECT.js.map} +1 -1
  35. package/dist/{doctor-VFKEMR54.js → doctor-WQXPXP6K.js} +7 -7
  36. package/dist/doctor-WQXPXP6K.js.map +1 -0
  37. package/dist/{preview-QDCIVVSR.js → preview-OGMCNQUO.js} +12 -4
  38. package/dist/preview-OGMCNQUO.js.map +1 -0
  39. package/dist/{routes-RHP5FVGD.js → routes-MWBWWOJ2.js} +5 -5
  40. package/dist/{routes-RHP5FVGD.js.map → routes-MWBWWOJ2.js.map} +1 -1
  41. package/dist/{search-RFBELGY7.js → search-6Y422SV6.js} +3 -3
  42. package/dist/{search-RFBELGY7.js.map → search-6Y422SV6.js.map} +1 -1
  43. package/dist/slide/index.js +61 -15
  44. package/dist/slide/index.js.map +1 -1
  45. package/dist/table/index.js +6 -5
  46. package/dist/table/index.js.map +1 -1
  47. package/dist/ui/index.d.ts +140 -10
  48. package/dist/ui/index.js +1405 -63
  49. package/dist/ui/index.js.map +1 -1
  50. package/dist/{upgrade-GF2P67M6.js → upgrade-HCANX4GQ.js} +6 -6
  51. package/dist/{upgrade-GF2P67M6.js.map → upgrade-HCANX4GQ.js.map} +1 -1
  52. package/dist/vite/index.js +3 -3
  53. package/docs/en/changelog.md +24 -0
  54. package/docs/en/cli-reference.md +30 -0
  55. package/docs/en/parts/page-shell.md +1 -1
  56. package/docs/index.json +291 -61
  57. package/docs/ja/changelog.md +50 -0
  58. package/docs/ja/cli-reference.md +29 -0
  59. package/docs/ja/components.md +33 -89
  60. package/docs/ja/page-types/csv.md +83 -0
  61. package/docs/ja/page-types/doc.md +83 -0
  62. package/docs/ja/page-types/excel.md +82 -0
  63. package/docs/ja/page-types/slide.md +132 -0
  64. package/docs/ja/page-types.md +47 -0
  65. package/docs/ja/parts/area-chart.md +61 -0
  66. package/docs/ja/parts/bar-chart.md +69 -0
  67. package/docs/ja/parts/bar-list.md +35 -0
  68. package/docs/ja/parts/category-bar.md +36 -0
  69. package/docs/ja/parts/donut-chart.md +47 -0
  70. package/docs/ja/parts/echart.md +3 -0
  71. package/docs/ja/parts/line-chart.md +58 -0
  72. package/docs/ja/parts/page-shell.md +1 -1
  73. package/docs/ja/parts/progress-circle.md +34 -0
  74. package/docs/ja/parts/sparkline.md +1 -1
  75. package/docs/ja/parts/tracker.md +32 -0
  76. package/docs/ja/routing.md +8 -86
  77. package/docs/ja/ui/alert-dialog.md +41 -0
  78. package/docs/ja/ui/avatar.md +31 -0
  79. package/docs/ja/ui/combobox.md +74 -0
  80. package/docs/ja/ui/drawer.md +41 -0
  81. package/docs/ja/ui/field.md +42 -0
  82. package/docs/ja/ui/hover-card.md +21 -0
  83. package/docs/ja/ui/kbd.md +16 -0
  84. package/docs/ja/ui/pagination.md +36 -0
  85. package/docs/ja/ui/radio-group.md +21 -0
  86. package/docs/ja/ui/toast.md +46 -0
  87. package/docs/ja/ui-and-theming.md +14 -7
  88. package/package.json +18 -12
  89. package/registry/ui/accordion.tsx +74 -0
  90. package/registry/ui/alert-dialog.tsx +189 -0
  91. package/registry/ui/alert.tsx +78 -0
  92. package/registry/ui/app-shell.tsx +281 -0
  93. package/registry/ui/area-chart.tsx +1015 -0
  94. package/registry/ui/avatar.tsx +110 -0
  95. package/registry/ui/badge.tsx +54 -0
  96. package/registry/ui/bar-chart.tsx +1013 -0
  97. package/registry/ui/bar-list.tsx +302 -0
  98. package/registry/ui/breadcrumb.tsx +126 -0
  99. package/registry/ui/button.tsx +60 -0
  100. package/registry/ui/calendar.tsx +221 -0
  101. package/registry/ui/card.tsx +105 -0
  102. package/registry/ui/category-bar.tsx +281 -0
  103. package/registry/ui/checkbox.tsx +28 -0
  104. package/registry/ui/collapsible.tsx +21 -0
  105. package/registry/ui/combobox.tsx +310 -0
  106. package/registry/ui/command.tsx +196 -0
  107. package/registry/ui/dashboard-card.tsx +174 -0
  108. package/registry/ui/data-table.tsx +16 -91
  109. package/registry/ui/date-range-picker.tsx +209 -0
  110. package/registry/ui/dialog.tsx +159 -0
  111. package/registry/ui/donut-chart.tsx +1004 -0
  112. package/registry/ui/drawer.tsx +229 -0
  113. package/registry/ui/dropdown-menu.tsx +272 -0
  114. package/registry/ui/echart.tsx +486 -0
  115. package/registry/ui/field.tsx +240 -0
  116. package/registry/ui/filter-bar.tsx +365 -0
  117. package/registry/ui/funnel-steps.tsx +274 -0
  118. package/registry/ui/hover-card.tsx +52 -0
  119. package/registry/ui/input-group.tsx +158 -0
  120. package/registry/ui/input.tsx +22 -0
  121. package/registry/ui/kbd.tsx +28 -0
  122. package/registry/ui/label.tsx +20 -0
  123. package/registry/ui/line-chart.tsx +1007 -0
  124. package/registry/ui/metric-value.tsx +54 -0
  125. package/registry/ui/multi-select.tsx +226 -0
  126. package/registry/ui/page-shell.tsx +227 -0
  127. package/registry/ui/pagination.tsx +138 -0
  128. package/registry/ui/placeholder.tsx +30 -0
  129. package/registry/ui/popover.tsx +90 -0
  130. package/registry/ui/progress-circle.tsx +272 -0
  131. package/registry/ui/progress.tsx +83 -0
  132. package/registry/ui/radio-group.tsx +39 -0
  133. package/registry/ui/scroll-area.tsx +55 -0
  134. package/registry/ui/searchable-select.tsx +209 -0
  135. package/registry/ui/section-header.tsx +41 -0
  136. package/registry/ui/segmented-control.tsx +71 -0
  137. package/registry/ui/select.tsx +253 -0
  138. package/registry/ui/separator.tsx +25 -0
  139. package/registry/ui/sheet.tsx +137 -0
  140. package/registry/ui/sidebar.tsx +723 -0
  141. package/registry/ui/skeleton.tsx +15 -0
  142. package/registry/ui/slider.tsx +54 -0
  143. package/registry/ui/sparkline.tsx +155 -0
  144. package/registry/ui/spinner.tsx +12 -0
  145. package/registry/ui/states.tsx +61 -0
  146. package/registry/ui/status-badge.tsx +79 -0
  147. package/registry/ui/switch.tsx +32 -0
  148. package/registry/ui/table.tsx +116 -0
  149. package/registry/ui/tabs.tsx +82 -0
  150. package/registry/ui/textarea.tsx +20 -0
  151. package/registry/ui/toast.tsx +250 -0
  152. package/registry/ui/toggle-group.tsx +89 -0
  153. package/registry/ui/toggle.tsx +45 -0
  154. package/registry/ui/tooltip.tsx +66 -0
  155. package/registry/ui/tracker.tsx +236 -0
  156. package/registry/ui/trend-indicator.tsx +62 -0
  157. package/skills/vantage-add-feature/SKILL.md +9 -7
  158. package/skills/vantage-design/SKILL.md +3 -1
  159. package/skills/vantage-design/references/format.md +1 -1
  160. package/skills/vantage-pitfalls/SKILL.md +5 -1
  161. package/skills/vantage-slide/SKILL.md +17 -0
  162. package/templates/AGENTS.md +10 -1
  163. package/templates/agents/api.md +29 -0
  164. package/templates/agents/csv.md +2 -1
  165. package/templates/agents/doc.md +4 -3
  166. package/templates/agents/page.md +22 -8
  167. package/templates/agents/slide.md +13 -1
  168. package/templates/agents/xlsx.md +2 -1
  169. package/theme.css +15 -1
  170. package/dist/add-EISGSZAH.js +0 -6
  171. package/dist/add-EISGSZAH.js.map +0 -1
  172. package/dist/chunk-3G43C6OL.js.map +0 -1
  173. package/dist/chunk-BCE22JSM.js.map +0 -1
  174. package/dist/chunk-KLEIVDUV.js.map +0 -1
  175. package/dist/chunk-LSRMRIXA.js.map +0 -1
  176. package/dist/dev-NZRLOQCL.js.map +0 -1
  177. package/dist/doctor-VFKEMR54.js.map +0 -1
  178. package/dist/preview-QDCIVVSR.js.map +0 -1
@@ -0,0 +1,90 @@
1
+ // Copied by `vantage add ui popover`. This file is yours to edit.
2
+ // Generated from @squadbase/vantage src/ui/popover.tsx by `npm run registry` (in Vantage, edit src/, not registry/).
3
+ import * as React from "react"
4
+ import { Popover as PopoverPrimitive } from "@base-ui/react/popover"
5
+
6
+ import { cn } from "@squadbase/vantage/ui"
7
+
8
+ function Popover({ ...props }: PopoverPrimitive.Root.Props) {
9
+ return <PopoverPrimitive.Root data-slot="popover" {...props} />
10
+ }
11
+
12
+ function PopoverTrigger({ ...props }: PopoverPrimitive.Trigger.Props) {
13
+ return <PopoverPrimitive.Trigger data-slot="popover-trigger" {...props} />
14
+ }
15
+
16
+ function PopoverContent({
17
+ className,
18
+ align = "center",
19
+ alignOffset = 0,
20
+ side = "bottom",
21
+ sideOffset = 4,
22
+ ...props
23
+ }: PopoverPrimitive.Popup.Props &
24
+ Pick<
25
+ PopoverPrimitive.Positioner.Props,
26
+ "align" | "alignOffset" | "side" | "sideOffset"
27
+ >) {
28
+ return (
29
+ <PopoverPrimitive.Portal>
30
+ <PopoverPrimitive.Positioner
31
+ align={align}
32
+ alignOffset={alignOffset}
33
+ side={side}
34
+ sideOffset={sideOffset}
35
+ className="isolate z-50"
36
+ >
37
+ <PopoverPrimitive.Popup
38
+ data-slot="popover-content"
39
+ className={cn(
40
+ "z-50 flex w-72 origin-(--transform-origin) flex-col gap-2.5 rounded-lg bg-popover p-2.5 text-sm text-popover-foreground shadow-md ring-1 ring-foreground/10 outline-hidden duration-100 data-[side=bottom]:slide-in-from-top-2 data-[side=inline-end]:slide-in-from-left-2 data-[side=inline-start]:slide-in-from-right-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 data-open:animate-in data-open:fade-in-0 data-open:zoom-in-95 data-closed:animate-out data-closed:fade-out-0 data-closed:zoom-out-95",
41
+ className
42
+ )}
43
+ {...props}
44
+ />
45
+ </PopoverPrimitive.Positioner>
46
+ </PopoverPrimitive.Portal>
47
+ )
48
+ }
49
+
50
+ function PopoverHeader({ className, ...props }: React.ComponentProps<"div">) {
51
+ return (
52
+ <div
53
+ data-slot="popover-header"
54
+ className={cn("flex flex-col gap-0.5 text-sm", className)}
55
+ {...props}
56
+ />
57
+ )
58
+ }
59
+
60
+ function PopoverTitle({ className, ...props }: PopoverPrimitive.Title.Props) {
61
+ return (
62
+ <PopoverPrimitive.Title
63
+ data-slot="popover-title"
64
+ className={cn("font-medium", className)}
65
+ {...props}
66
+ />
67
+ )
68
+ }
69
+
70
+ function PopoverDescription({
71
+ className,
72
+ ...props
73
+ }: PopoverPrimitive.Description.Props) {
74
+ return (
75
+ <PopoverPrimitive.Description
76
+ data-slot="popover-description"
77
+ className={cn("text-muted-foreground", className)}
78
+ {...props}
79
+ />
80
+ )
81
+ }
82
+
83
+ export {
84
+ Popover,
85
+ PopoverContent,
86
+ PopoverDescription,
87
+ PopoverHeader,
88
+ PopoverTitle,
89
+ PopoverTrigger,
90
+ }
@@ -0,0 +1,272 @@
1
+ // Copied by `vantage add ui progress-circle`. This file is yours to edit.
2
+ // Generated from @squadbase/vantage src/components/progress-circle.tsx by `npm run registry` (in Vantage, edit src/, not registry/).
3
+ /**
4
+ * ProgressCircle — a ring that fills to `value / max`, with anything you pass
5
+ * as children in the middle (usually the percentage). Plain SVG, coloured by
6
+ * a chart token, so a row of them in KPI tiles stays light.
7
+ */
8
+ import { forwardRef, useEffect, useState, type ComponentProps } from "react"
9
+
10
+ import { cn } from "@squadbase/vantage/ui"
11
+ import type { ChartColor } from "@squadbase/vantage/components"
12
+ import type { ValueFormatter } from "@squadbase/vantage/components"
13
+
14
+ /* ---------- inlined from src/components/chart-utils.ts (internal to @squadbase/vantage) ---------- */
15
+
16
+ /** The series tokens, in palette order — the default `colors` of every typed chart. */
17
+ const DEFAULT_CHART_COLORS: readonly ChartColor[] = [
18
+ "chart-1",
19
+ "chart-2",
20
+ "chart-3",
21
+ "chart-4",
22
+ "chart-5",
23
+ ]
24
+
25
+ const TOKEN_NAME_RE = /^chart-[1-5]$/
26
+
27
+ /**
28
+ * A chart colour as a CSS value: `"chart-2"` → `var(--chart-2)` (so it follows
29
+ * light/dark on its own), anything else passes through unchanged.
30
+ */
31
+ function chartColorToCss(color: ChartColor): string {
32
+ const value = color.trim()
33
+ return TOKEN_NAME_RE.test(value) ? `var(--${value})` : value
34
+ }
35
+
36
+ /** The `i`-th colour, cycling through `colors` (the token palette when empty). */
37
+ function chartColorAt(colors: readonly ChartColor[] | undefined, i: number): ChartColor {
38
+ const palette = colors && colors.length > 0 ? colors : DEFAULT_CHART_COLORS
39
+ return palette[i % palette.length]!
40
+ }
41
+
42
+ /** `colors` extended (by cycling) to exactly `count` entries. */
43
+ function chartColorsFor(colors: readonly ChartColor[] | undefined, count: number): ChartColor[] {
44
+ return Array.from({ length: count }, (_, i) => chartColorAt(colors, i))
45
+ }
46
+
47
+ /** A translucent version of a CSS colour (works for `var(--…)` too). */
48
+ function tintCss(cssColor: string, percent: number): string {
49
+ return `color-mix(in oklab, ${cssColor} ${percent}%, transparent)`
50
+ }
51
+
52
+ const numberFormat = new Intl.NumberFormat("ja-JP", { maximumFractionDigits: 2 })
53
+
54
+ /** Default `valueFormatter`: grouped digits, up to two decimals (`1,234.5`). */
55
+ const defaultValueFormatter: ValueFormatter = (value) => numberFormat.format(value)
56
+
57
+ /**
58
+ * A data cell as a number, or `null` for a gap. Numeric strings count — SQL
59
+ * `DECIMAL` / `BIGINT` columns usually arrive as strings.
60
+ */
61
+ function toChartNumber(value: unknown): number | null {
62
+ if (typeof value === "number") return Number.isFinite(value) ? value : null
63
+ if (typeof value === "bigint") return Number(value)
64
+ if (typeof value === "string" && value.trim() !== "") {
65
+ const n = Number(value)
66
+ return Number.isFinite(n) ? n : null
67
+ }
68
+ return null
69
+ }
70
+
71
+ /** Clamp `value` into `[min, max]`. */
72
+ function clamp(value: number, min: number, max: number): number {
73
+ return Math.min(max, Math.max(min, value))
74
+ }
75
+
76
+ /* ---------------------------------------------------------------- BarList */
77
+
78
+ type BarListSortOrder = "ascending" | "descending" | "none"
79
+
80
+ /** Sort a copy of the rows by value; `"none"` keeps the given order. */
81
+ function sortBarListData<T extends { value: number }>(data: readonly T[], sortOrder: BarListSortOrder): T[] {
82
+ const rows = [...data]
83
+ if (sortOrder === "ascending") rows.sort((a, b) => a.value - b.value)
84
+ else if (sortOrder === "descending") rows.sort((a, b) => b.value - a.value)
85
+ return rows
86
+ }
87
+
88
+ /** Bar widths in percent of the largest value (at least a sliver for non-zero values). */
89
+ function barListWidths(values: readonly number[]): number[] {
90
+ const max = Math.max(0, ...values)
91
+ if (max === 0) return values.map(() => 0)
92
+ return values.map((v) => (v <= 0 ? 0 : Math.max(1, (v / max) * 100)))
93
+ }
94
+
95
+ /* ------------------------------------------------------------ CategoryBar */
96
+
97
+ interface CategoryBarSegment {
98
+ /** Width in percent of the whole bar. */
99
+ width: number
100
+ /** Where the segment starts, in percent. */
101
+ start: number
102
+ /** The running total at the segment's end — what its right-hand label shows. */
103
+ end: number
104
+ }
105
+
106
+ /** Lay the values side by side; negative values count as zero. */
107
+ function categoryBarSegments(values: readonly number[]): CategoryBarSegment[] {
108
+ const clean = values.map((v) => (Number.isFinite(v) && v > 0 ? v : 0))
109
+ const total = clean.reduce((sum, v) => sum + v, 0)
110
+ let running = 0
111
+ return clean.map((v) => {
112
+ const start = total === 0 ? 0 : (running / total) * 100
113
+ running += v
114
+ return { width: total === 0 ? 0 : (v / total) * 100, start, end: running }
115
+ })
116
+ }
117
+
118
+ interface CategoryBarLabel {
119
+ /** Position in percent of the bar. */
120
+ position: number
121
+ /** The running total printed there. */
122
+ value: number
123
+ }
124
+
125
+ /**
126
+ * Tick labels under the bar: `0` at the start, then the running total at each
127
+ * segment's end. A label closer than `minGap` percent to the one before is
128
+ * dropped so narrow segments don't print on top of each other — except the
129
+ * last one (the total), which replaces its neighbour instead.
130
+ */
131
+ function categoryBarLabels(values: readonly number[], minGap = 8): CategoryBarLabel[] {
132
+ const segments = categoryBarSegments(values).filter((s) => s.width > 0)
133
+ if (segments.length === 0) return []
134
+ const labels: CategoryBarLabel[] = [{ position: 0, value: 0 }]
135
+ segments.forEach((s, i) => {
136
+ const label = { position: s.start + s.width, value: s.end }
137
+ const prev = labels[labels.length - 1]!
138
+ if (label.position - prev.position >= minGap) labels.push(label)
139
+ else if (i === segments.length - 1 && labels.length > 1) labels[labels.length - 1] = label
140
+ })
141
+ return labels
142
+ }
143
+
144
+ /** Marker position in percent of the bar, clamped to its ends. */
145
+ function categoryBarMarkerPosition(value: number, values: readonly number[]): number {
146
+ const total = values.reduce((sum, v) => sum + (Number.isFinite(v) && v > 0 ? v : 0), 0)
147
+ if (total === 0) return 0
148
+ return clamp((value / total) * 100, 0, 100)
149
+ }
150
+
151
+ /** Index of the segment the marker sits on (the last one for a value past the end). */
152
+ function categoryBarMarkerSegment(value: number, values: readonly number[]): number {
153
+ const segments = categoryBarSegments(values)
154
+ const index = segments.findIndex((s) => s.width > 0 && value <= s.end)
155
+ if (index !== -1) return index
156
+ for (let i = segments.length - 1; i >= 0; i--) if (segments[i]!.width > 0) return i
157
+ return 0
158
+ }
159
+
160
+ /* --------------------------------------------------------- ProgressCircle */
161
+
162
+ interface ProgressCircleGeometry {
163
+ /** SVG width/height. */
164
+ size: number
165
+ /** Radius of the stroke's centre line. */
166
+ normalizedRadius: number
167
+ circumference: number
168
+ /** `stroke-dashoffset` for the value arc. */
169
+ offset: number
170
+ /** The value as a fraction of `max`, clamped to `[0, 1]`. */
171
+ ratio: number
172
+ }
173
+
174
+ function progressCircleGeometry(
175
+ value: number,
176
+ max: number,
177
+ radius: number,
178
+ strokeWidth: number,
179
+ ): ProgressCircleGeometry {
180
+ const ratio = max > 0 && Number.isFinite(value) ? clamp(value / max, 0, 1) : 0
181
+ const normalizedRadius = Math.max(0, radius - strokeWidth / 2)
182
+ const circumference = 2 * Math.PI * normalizedRadius
183
+ return { size: radius * 2, normalizedRadius, circumference, offset: circumference * (1 - ratio), ratio }
184
+ }
185
+
186
+ /* ---------- end of inlined code ---------- */
187
+
188
+ export interface ProgressCircleProps extends ComponentProps<"div"> {
189
+ /** 現在値。`0`〜`max` に丸める。 */
190
+ value?: number
191
+ /** 満タンの値。既定 `100`。 */
192
+ max?: number
193
+ /** 外側の半径(px)。既定 `32`(64px 四方)。 */
194
+ radius?: number
195
+ /** 線の太さ(px)。既定 `6`。 */
196
+ strokeWidth?: number
197
+ /** 色。`"chart-1"`〜`"chart-5"` か CSS カラー。既定 `"chart-1"`。地のリングは同じ色を淡くしたもの。 */
198
+ color?: ChartColor
199
+ /** マウント時と値の変化をアニメーションする。既定 `true`。 */
200
+ showAnimation?: boolean
201
+ }
202
+
203
+ export const ProgressCircle = forwardRef<HTMLDivElement, ProgressCircleProps>(function ProgressCircle(
204
+ {
205
+ value = 0,
206
+ max = 100,
207
+ radius = 32,
208
+ strokeWidth = 6,
209
+ color = "chart-1",
210
+ showAnimation = true,
211
+ className,
212
+ children,
213
+ ...props
214
+ },
215
+ ref,
216
+ ) {
217
+ const [mounted, setMounted] = useState(!showAnimation)
218
+ useEffect(() => {
219
+ if (!showAnimation) return
220
+ const frame = requestAnimationFrame(() => setMounted(true))
221
+ return () => cancelAnimationFrame(frame)
222
+ }, [showAnimation])
223
+
224
+ const { size, normalizedRadius, circumference, offset, ratio } = progressCircleGeometry(value, max, radius, strokeWidth)
225
+ const css = chartColorToCss(color)
226
+
227
+ return (
228
+ <div
229
+ ref={ref}
230
+ data-slot="progress-circle"
231
+ role="progressbar"
232
+ aria-valuemin={0}
233
+ aria-valuemax={max}
234
+ aria-valuenow={value}
235
+ className={cn("relative inline-flex shrink-0 items-center justify-center", className)}
236
+ style={{ width: size, height: size }}
237
+ {...props}
238
+ >
239
+ <svg width={size} height={size} viewBox={`0 0 ${size} ${size}`} className="-rotate-90" aria-hidden="true">
240
+ <circle
241
+ cx={radius}
242
+ cy={radius}
243
+ r={normalizedRadius}
244
+ fill="none"
245
+ strokeWidth={strokeWidth}
246
+ style={{ stroke: tintCss(css, 20) }}
247
+ />
248
+ {ratio > 0 && (
249
+ <circle
250
+ data-slot="progress-circle-value"
251
+ cx={radius}
252
+ cy={radius}
253
+ r={normalizedRadius}
254
+ fill="none"
255
+ strokeWidth={strokeWidth}
256
+ strokeLinecap="round"
257
+ strokeDasharray={`${circumference} ${circumference}`}
258
+ strokeDashoffset={mounted ? offset : circumference}
259
+ className={cn(showAnimation && "transition-[stroke-dashoffset] duration-700 ease-out")}
260
+ style={{ stroke: css }}
261
+ />
262
+ )}
263
+ </svg>
264
+ {children != null && (
265
+ <div className="absolute inset-0 flex items-center justify-center text-sm font-medium text-foreground tabular-nums">
266
+ {children}
267
+ </div>
268
+ )}
269
+ </div>
270
+ )
271
+ })
272
+ ProgressCircle.displayName = "ProgressCircle"
@@ -0,0 +1,83 @@
1
+ // Copied by `vantage add ui progress`. This file is yours to edit.
2
+ // Generated from @squadbase/vantage src/ui/progress.tsx by `npm run registry` (in Vantage, edit src/, not registry/).
3
+ import { Progress as ProgressPrimitive } from "@base-ui/react/progress"
4
+
5
+ import { cn } from "@squadbase/vantage/ui"
6
+
7
+ function Progress({
8
+ className,
9
+ children,
10
+ value,
11
+ ...props
12
+ }: ProgressPrimitive.Root.Props) {
13
+ return (
14
+ <ProgressPrimitive.Root
15
+ value={value}
16
+ data-slot="progress"
17
+ className={cn("flex flex-wrap gap-3", className)}
18
+ {...props}
19
+ >
20
+ {children}
21
+ <ProgressTrack>
22
+ <ProgressIndicator />
23
+ </ProgressTrack>
24
+ </ProgressPrimitive.Root>
25
+ )
26
+ }
27
+
28
+ function ProgressTrack({ className, ...props }: ProgressPrimitive.Track.Props) {
29
+ return (
30
+ <ProgressPrimitive.Track
31
+ className={cn(
32
+ "relative flex h-1 w-full items-center overflow-x-hidden rounded-full bg-muted",
33
+ className
34
+ )}
35
+ data-slot="progress-track"
36
+ {...props}
37
+ />
38
+ )
39
+ }
40
+
41
+ function ProgressIndicator({
42
+ className,
43
+ ...props
44
+ }: ProgressPrimitive.Indicator.Props) {
45
+ return (
46
+ <ProgressPrimitive.Indicator
47
+ data-slot="progress-indicator"
48
+ className={cn("h-full bg-primary transition-all", className)}
49
+ {...props}
50
+ />
51
+ )
52
+ }
53
+
54
+ function ProgressLabel({ className, ...props }: ProgressPrimitive.Label.Props) {
55
+ return (
56
+ <ProgressPrimitive.Label
57
+ className={cn("text-sm font-medium", className)}
58
+ data-slot="progress-label"
59
+ {...props}
60
+ />
61
+ )
62
+ }
63
+
64
+ function ProgressValue({ className, ...props }: ProgressPrimitive.Value.Props) {
65
+ return (
66
+ <ProgressPrimitive.Value
67
+ className={cn(
68
+ "ml-auto text-sm text-muted-foreground tabular-nums",
69
+ className
70
+ )}
71
+ data-slot="progress-value"
72
+ {...props}
73
+ />
74
+ )
75
+ }
76
+
77
+ export {
78
+ Progress,
79
+ ProgressTrack,
80
+ ProgressIndicator,
81
+ ProgressLabel,
82
+ ProgressValue,
83
+ }
@@ -0,0 +1,39 @@
1
+ // Copied by `vantage add ui radio-group`. This file is yours to edit.
2
+ // Generated from @squadbase/vantage src/ui/radio-group.tsx by `npm run registry` (in Vantage, edit src/, not registry/).
3
+ "use client"
4
+
5
+ import { Radio as RadioPrimitive } from "@base-ui/react/radio"
6
+ import { RadioGroup as RadioGroupPrimitive } from "@base-ui/react/radio-group"
7
+ import { cn } from "@squadbase/vantage/ui"
8
+
9
+ function RadioGroup({ className, ...props }: RadioGroupPrimitive.Props) {
10
+ return (
11
+ <RadioGroupPrimitive
12
+ data-slot="radio-group"
13
+ className={cn("grid w-full gap-2", className)}
14
+ {...props}
15
+ />
16
+ )
17
+ }
18
+
19
+ function RadioGroupItem({ className, ...props }: RadioPrimitive.Root.Props) {
20
+ return (
21
+ <RadioPrimitive.Root
22
+ data-slot="radio-group-item"
23
+ className={cn(
24
+ "group/radio-group-item peer relative flex aspect-square size-4 shrink-0 rounded-full border border-input outline-none group-has-[:focus-visible]/field-label:ring-0 group-has-[:focus-visible]/field-label:not-data-checked:border-input after:absolute after:-inset-x-3 after:-inset-y-2 focus-visible:border-ring focus-visible:ring-3 focus-visible:ring-ring/50 disabled:cursor-not-allowed disabled:opacity-50 aria-invalid:border-destructive aria-invalid:ring-3 aria-invalid:ring-destructive/20 aria-invalid:aria-checked:border-primary dark:bg-input/30 dark:aria-invalid:border-destructive/50 dark:aria-invalid:ring-destructive/40 data-checked:border-primary data-checked:bg-primary data-checked:text-primary-foreground group-has-[:focus-visible]/field-label:data-checked:border-primary dark:data-checked:bg-primary",
25
+ className
26
+ )}
27
+ {...props}
28
+ >
29
+ <RadioPrimitive.Indicator
30
+ data-slot="radio-group-indicator"
31
+ className="flex size-4 items-center justify-center"
32
+ >
33
+ <span className="absolute top-1/2 left-1/2 size-2 -translate-x-1/2 -translate-y-1/2 rounded-full bg-primary-foreground" />
34
+ </RadioPrimitive.Indicator>
35
+ </RadioPrimitive.Root>
36
+ )
37
+ }
38
+
39
+ export { RadioGroup, RadioGroupItem }
@@ -0,0 +1,55 @@
1
+ // Copied by `vantage add ui scroll-area`. This file is yours to edit.
2
+ // Generated from @squadbase/vantage src/ui/scroll-area.tsx by `npm run registry` (in Vantage, edit src/, not registry/).
3
+ import * as React from "react"
4
+ import { ScrollArea as ScrollAreaPrimitive } from "@base-ui/react/scroll-area"
5
+
6
+ import { cn } from "@squadbase/vantage/ui"
7
+
8
+ function ScrollArea({
9
+ className,
10
+ children,
11
+ ...props
12
+ }: ScrollAreaPrimitive.Root.Props) {
13
+ return (
14
+ <ScrollAreaPrimitive.Root
15
+ data-slot="scroll-area"
16
+ className={cn("relative", className)}
17
+ {...props}
18
+ >
19
+ <ScrollAreaPrimitive.Viewport
20
+ data-slot="scroll-area-viewport"
21
+ className="size-full rounded-[inherit] transition-[color,box-shadow] outline-none focus-visible:ring-[3px] focus-visible:ring-ring/50 focus-visible:outline-1"
22
+ >
23
+ {children}
24
+ </ScrollAreaPrimitive.Viewport>
25
+ <ScrollBar />
26
+ <ScrollAreaPrimitive.Corner />
27
+ </ScrollAreaPrimitive.Root>
28
+ )
29
+ }
30
+
31
+ function ScrollBar({
32
+ className,
33
+ orientation = "vertical",
34
+ ...props
35
+ }: ScrollAreaPrimitive.Scrollbar.Props) {
36
+ return (
37
+ <ScrollAreaPrimitive.Scrollbar
38
+ data-slot="scroll-area-scrollbar"
39
+ data-orientation={orientation}
40
+ orientation={orientation}
41
+ className={cn(
42
+ "flex touch-none p-px transition-colors select-none data-horizontal:h-2.5 data-horizontal:flex-col data-horizontal:border-t data-horizontal:border-t-transparent data-vertical:h-full data-vertical:w-2.5 data-vertical:border-l data-vertical:border-l-transparent",
43
+ className
44
+ )}
45
+ {...props}
46
+ >
47
+ <ScrollAreaPrimitive.Thumb
48
+ data-slot="scroll-area-thumb"
49
+ className="relative flex-1 rounded-full bg-border"
50
+ />
51
+ </ScrollAreaPrimitive.Scrollbar>
52
+ )
53
+ }
54
+
55
+ export { ScrollArea, ScrollBar }