@squadbase/vantage 0.6.2-dev1.d7c0911 → 0.6.2-dev1.e85faec

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 (221) hide show
  1. package/dist/chunk-2IAPIOPS.js +152 -0
  2. package/dist/chunk-2IAPIOPS.js.map +1 -0
  3. package/dist/chunk-57GHR5LN.js +163 -0
  4. package/dist/chunk-57GHR5LN.js.map +1 -0
  5. package/dist/chunk-6OTTGAPO.js +44 -0
  6. package/dist/chunk-6OTTGAPO.js.map +1 -0
  7. package/dist/{chunk-XPQSTZUU.js → chunk-7S52M2SL.js} +4 -3
  8. package/dist/chunk-7S52M2SL.js.map +1 -0
  9. package/dist/chunk-JXFCSF3K.js +673 -0
  10. package/dist/chunk-JXFCSF3K.js.map +1 -0
  11. package/dist/{chunk-WRSX2MDK.js → chunk-QOXXOFGL.js} +115 -930
  12. package/dist/chunk-QOXXOFGL.js.map +1 -0
  13. package/dist/components/index.d.ts +13 -249
  14. package/dist/components/index.js +5 -2
  15. package/dist/delta-text-CvwBGJ95.d.ts +15 -0
  16. package/dist/doc/index.d.ts +215 -2
  17. package/dist/doc/index.js +300 -3
  18. package/dist/doc/index.js.map +1 -1
  19. package/dist/format-U0cQl069.d.ts +243 -0
  20. package/dist/slide/index.d.ts +272 -1
  21. package/dist/slide/index.js +968 -3
  22. package/dist/slide/index.js.map +1 -1
  23. package/dist/table/index.js +6 -3
  24. package/dist/table/index.js.map +1 -1
  25. package/dist/ui/index.d.ts +4 -1
  26. package/dist/ui/index.js +3 -3
  27. package/dist/ui/index.js.map +1 -1
  28. package/docs/en/components.md +13 -2
  29. package/docs/en/doc/delta-text.md +40 -0
  30. package/docs/en/doc/doc-action-items.md +49 -0
  31. package/docs/en/doc/doc-callout.md +38 -0
  32. package/docs/en/doc/doc-data-table.md +60 -0
  33. package/docs/en/doc/doc-executive-summary.md +64 -0
  34. package/docs/en/doc/doc-figure.md +56 -0
  35. package/docs/en/doc/doc-key-findings.md +61 -0
  36. package/docs/en/doc/doc-kpi-scorecard.md +80 -0
  37. package/docs/en/doc/doc-notes-and-sources.md +43 -0
  38. package/docs/en/doc/doc-report-header.md +46 -0
  39. package/docs/en/parts/area-chart.md +99 -0
  40. package/docs/en/parts/bar-chart.md +91 -0
  41. package/docs/en/parts/bar-list.md +50 -0
  42. package/docs/en/parts/category-bar.md +37 -0
  43. package/docs/en/parts/chart-frame.md +39 -0
  44. package/docs/en/parts/delta.md +4 -3
  45. package/docs/en/parts/donut-chart.md +72 -0
  46. package/docs/en/parts/funnel-steps.md +2 -1
  47. package/docs/en/parts/heatmap.md +53 -0
  48. package/docs/en/parts/kpi-card.md +2 -1
  49. package/docs/en/parts/legend.md +35 -0
  50. package/docs/en/parts/line-chart.md +94 -0
  51. package/docs/en/parts/progress-circle.md +33 -0
  52. package/docs/en/parts/sample-data.md +39 -0
  53. package/docs/en/parts/scatter-chart.md +56 -0
  54. package/docs/en/parts/tracker.md +36 -0
  55. package/docs/en/parts/updated-at.md +30 -0
  56. package/docs/en/parts/waterfall-chart.md +56 -0
  57. package/docs/en/slide/slide-chart-full.md +48 -0
  58. package/docs/en/slide/slide-chart-insight.md +52 -0
  59. package/docs/en/slide/slide-columns.md +46 -0
  60. package/docs/en/slide/slide-comparison.md +68 -0
  61. package/docs/en/slide/slide-cover.md +39 -0
  62. package/docs/en/slide/slide-exec-summary.md +47 -0
  63. package/docs/en/slide/slide-heading.md +38 -0
  64. package/docs/en/slide/slide-kpi-grid.md +55 -0
  65. package/docs/en/slide/slide-kpi-hero.md +58 -0
  66. package/docs/en/slide/slide-next-actions.md +49 -0
  67. package/docs/en/slide/slide-scorecard-table.md +54 -0
  68. package/docs/en/slide/slide-section.md +44 -0
  69. package/docs/en/slide/slide-source-line.md +34 -0
  70. package/docs/en/ui/alert-dialog.md +42 -0
  71. package/docs/en/ui/avatar.md +31 -0
  72. package/docs/en/ui/combobox.md +74 -0
  73. package/docs/en/ui/drawer.md +41 -0
  74. package/docs/en/ui/empty.md +1 -1
  75. package/docs/en/ui/error-state.md +4 -3
  76. package/docs/en/ui/field.md +42 -0
  77. package/docs/en/ui/hover-card.md +21 -0
  78. package/docs/en/ui/kbd.md +17 -0
  79. package/docs/en/ui/loading.md +1 -1
  80. package/docs/en/ui/pagination.md +36 -0
  81. package/docs/en/ui/radio-group.md +21 -0
  82. package/docs/en/ui/toast.md +44 -0
  83. package/docs/en/ui/toggle-group.md +4 -3
  84. package/docs/index.json +857 -77
  85. package/docs/ja/components.md +12 -1
  86. package/docs/ja/doc/delta-text.md +40 -0
  87. package/docs/ja/doc/doc-action-items.md +49 -0
  88. package/docs/ja/doc/doc-callout.md +38 -0
  89. package/docs/ja/doc/doc-data-table.md +60 -0
  90. package/docs/ja/doc/doc-executive-summary.md +64 -0
  91. package/docs/ja/doc/doc-figure.md +56 -0
  92. package/docs/ja/doc/doc-key-findings.md +61 -0
  93. package/docs/ja/doc/doc-kpi-scorecard.md +80 -0
  94. package/docs/ja/doc/doc-notes-and-sources.md +43 -0
  95. package/docs/ja/doc/doc-report-header.md +46 -0
  96. package/docs/ja/parts/area-chart.md +49 -25
  97. package/docs/ja/parts/bar-chart.md +50 -24
  98. package/docs/ja/parts/bar-list.md +31 -8
  99. package/docs/ja/parts/chart-frame.md +36 -0
  100. package/docs/ja/parts/delta.md +5 -4
  101. package/docs/ja/parts/donut-chart.md +45 -26
  102. package/docs/ja/parts/funnel-steps.md +27 -8
  103. package/docs/ja/parts/heatmap.md +45 -0
  104. package/docs/ja/parts/kpi-card.md +2 -1
  105. package/docs/ja/parts/legend.md +36 -0
  106. package/docs/ja/parts/line-chart.md +48 -22
  107. package/docs/ja/parts/sample-data.md +61 -0
  108. package/docs/ja/parts/scatter-chart.md +69 -0
  109. package/docs/ja/parts/updated-at.md +27 -0
  110. package/docs/ja/parts/waterfall-chart.md +61 -0
  111. package/docs/ja/slide/slide-chart-full.md +48 -0
  112. package/docs/ja/slide/slide-chart-insight.md +52 -0
  113. package/docs/ja/slide/slide-columns.md +46 -0
  114. package/docs/ja/slide/slide-comparison.md +68 -0
  115. package/docs/ja/slide/slide-cover.md +39 -0
  116. package/docs/ja/slide/slide-exec-summary.md +47 -0
  117. package/docs/ja/slide/slide-heading.md +38 -0
  118. package/docs/ja/slide/slide-kpi-grid.md +55 -0
  119. package/docs/ja/slide/slide-kpi-hero.md +58 -0
  120. package/docs/ja/slide/slide-next-actions.md +49 -0
  121. package/docs/ja/slide/slide-scorecard-table.md +54 -0
  122. package/docs/ja/slide/slide-section.md +44 -0
  123. package/docs/ja/slide/slide-source-line.md +34 -0
  124. package/docs/ja/ui/empty.md +1 -1
  125. package/docs/ja/ui/error-state.md +4 -3
  126. package/docs/ja/ui/loading.md +1 -1
  127. package/docs/ja/ui/toggle-group.md +4 -3
  128. package/package.json +26 -25
  129. package/registry/ui/accordion.tsx +1 -1
  130. package/registry/ui/alert-dialog.tsx +1 -1
  131. package/registry/ui/alert.tsx +1 -1
  132. package/registry/ui/app-shell.tsx +1 -1
  133. package/registry/ui/area-chart.tsx +89 -27
  134. package/registry/ui/attention-list.tsx +303 -0
  135. package/registry/ui/avatar.tsx +1 -1
  136. package/registry/ui/badge.tsx +1 -1
  137. package/registry/ui/bar-chart.tsx +89 -27
  138. package/registry/ui/bar-list.tsx +88 -25
  139. package/registry/ui/box-plot-chart.tsx +3906 -0
  140. package/registry/ui/breadcrumb.tsx +1 -1
  141. package/registry/ui/button.tsx +1 -1
  142. package/registry/ui/calendar.tsx +1 -1
  143. package/registry/ui/card.tsx +1 -1
  144. package/registry/ui/category-bar.tsx +55 -20
  145. package/registry/ui/chart-frame.tsx +57 -22
  146. package/registry/ui/checkbox.tsx +1 -1
  147. package/registry/ui/collapsible.tsx +1 -1
  148. package/registry/ui/combobox.tsx +1 -1
  149. package/registry/ui/command.tsx +1 -1
  150. package/registry/ui/dashboard-card.tsx +5 -5
  151. package/registry/ui/data-table.tsx +1 -1
  152. package/registry/ui/date-range-picker.tsx +1 -1
  153. package/registry/ui/delta.tsx +12 -9
  154. package/registry/ui/dialog.tsx +1 -1
  155. package/registry/ui/donut-chart.tsx +90 -27
  156. package/registry/ui/drawer.tsx +1 -1
  157. package/registry/ui/dropdown-menu.tsx +1 -1
  158. package/registry/ui/echart.tsx +195 -45
  159. package/registry/ui/field.tsx +1 -1
  160. package/registry/ui/filter-bar.tsx +1 -1
  161. package/registry/ui/funnel-steps.tsx +34 -6
  162. package/registry/ui/heatmap.tsx +56 -22
  163. package/registry/ui/histogram-chart.tsx +3986 -0
  164. package/registry/ui/hover-card.tsx +1 -1
  165. package/registry/ui/input-group.tsx +1 -1
  166. package/registry/ui/input.tsx +1 -1
  167. package/registry/ui/kbd.tsx +1 -1
  168. package/registry/ui/kpi-card.tsx +42 -15
  169. package/registry/ui/label.tsx +1 -1
  170. package/registry/ui/legend.tsx +88 -25
  171. package/registry/ui/line-chart.tsx +89 -27
  172. package/registry/ui/metric-value.tsx +1 -1
  173. package/registry/ui/multi-select.tsx +1 -1
  174. package/registry/ui/page-shell.tsx +11 -11
  175. package/registry/ui/pagination.tsx +1 -1
  176. package/registry/ui/paired-chart.tsx +3827 -0
  177. package/registry/ui/placeholder.tsx +1 -1
  178. package/registry/ui/popover.tsx +1 -1
  179. package/registry/ui/progress-circle.tsx +1 -1
  180. package/registry/ui/progress.tsx +1 -1
  181. package/registry/ui/radio-group.tsx +1 -1
  182. package/registry/ui/sample-data.tsx +2 -2
  183. package/registry/ui/scatter-chart.tsx +89 -27
  184. package/registry/ui/scroll-area.tsx +1 -1
  185. package/registry/ui/searchable-select.tsx +1 -1
  186. package/registry/ui/section-header.tsx +3 -3
  187. package/registry/ui/segmented-control.tsx +1 -1
  188. package/registry/ui/select.tsx +1 -1
  189. package/registry/ui/separator.tsx +1 -1
  190. package/registry/ui/sheet.tsx +1 -1
  191. package/registry/ui/sidebar.tsx +1 -1
  192. package/registry/ui/skeleton.tsx +1 -1
  193. package/registry/ui/slider.tsx +2 -2
  194. package/registry/ui/sparkline.tsx +1 -1
  195. package/registry/ui/spinner.tsx +1 -1
  196. package/registry/ui/states.tsx +1 -1
  197. package/registry/ui/status-badge.tsx +9 -9
  198. package/registry/ui/switch.tsx +1 -1
  199. package/registry/ui/table.tsx +1 -1
  200. package/registry/ui/tabs.tsx +1 -1
  201. package/registry/ui/textarea.tsx +1 -1
  202. package/registry/ui/toast.tsx +1 -1
  203. package/registry/ui/toggle-group.tsx +1 -1
  204. package/registry/ui/toggle.tsx +1 -1
  205. package/registry/ui/tooltip.tsx +7 -3
  206. package/registry/ui/tracker.tsx +10 -4
  207. package/registry/ui/trend-indicator.tsx +3 -3
  208. package/registry/ui/updated-at.tsx +1 -1
  209. package/registry/ui/waterfall-chart.tsx +89 -27
  210. package/skills/vantage-design/SKILL.md +34 -24
  211. package/skills/vantage-design/references/extract.md +16 -14
  212. package/skills/vantage-design/references/format.md +6 -5
  213. package/skills/vantage-design/references/presets.md +60 -110
  214. package/skills/vantage-slide/SKILL.md +54 -36
  215. package/templates/AGENTS.md +2 -2
  216. package/templates/agents/doc.md +48 -0
  217. package/templates/agents/page.md +32 -1
  218. package/templates/agents/slide.md +70 -2
  219. package/theme.css +25 -20
  220. package/dist/chunk-WRSX2MDK.js.map +0 -1
  221. package/dist/chunk-XPQSTZUU.js.map +0 -1
@@ -1,5 +1,5 @@
1
1
  // Copied by `vantage add ui placeholder`. This file is yours to edit.
2
- // Generated from @squadbase/squadkit registry/components/placeholder.tsx by `npm run registry` (in Vantage, edit packages/squadkit, not registry/).
2
+ // Generated from @squadbase/squadkit registry/components/placeholder.tsx by `pnpm run registry` (in Vantage, edit packages/squadkit, not registry/).
3
3
  "use client"
4
4
 
5
5
  /**
@@ -1,5 +1,5 @@
1
1
  // Copied by `vantage add ui popover`. This file is yours to edit.
2
- // Generated from @squadbase/squadkit registry/ui/popover.tsx by `npm run registry` (in Vantage, edit packages/squadkit, not registry/).
2
+ // Generated from @squadbase/squadkit registry/ui/popover.tsx by `pnpm run registry` (in Vantage, edit packages/squadkit, not registry/).
3
3
  "use client"
4
4
 
5
5
  import * as React from "react"
@@ -1,5 +1,5 @@
1
1
  // Copied by `vantage add ui progress-circle`. This file is yours to edit.
2
- // Generated from @squadbase/squadkit registry/charts/progress-circle.tsx by `npm run registry` (in Vantage, edit packages/squadkit, not registry/).
2
+ // Generated from @squadbase/squadkit registry/charts/progress-circle.tsx by `pnpm run registry` (in Vantage, edit packages/squadkit, not registry/).
3
3
  "use client"
4
4
 
5
5
  /**
@@ -1,5 +1,5 @@
1
1
  // Copied by `vantage add ui progress`. This file is yours to edit.
2
- // Generated from @squadbase/squadkit registry/ui/progress.tsx by `npm run registry` (in Vantage, edit packages/squadkit, not registry/).
2
+ // Generated from @squadbase/squadkit registry/ui/progress.tsx by `pnpm run registry` (in Vantage, edit packages/squadkit, not registry/).
3
3
  "use client"
4
4
 
5
5
  import { Progress as ProgressPrimitive } from "@base-ui/react/progress"
@@ -1,5 +1,5 @@
1
1
  // Copied by `vantage add ui radio-group`. This file is yours to edit.
2
- // Generated from @squadbase/squadkit registry/ui/radio-group.tsx by `npm run registry` (in Vantage, edit packages/squadkit, not registry/).
2
+ // Generated from @squadbase/squadkit registry/ui/radio-group.tsx by `pnpm run registry` (in Vantage, edit packages/squadkit, not registry/).
3
3
  "use client"
4
4
 
5
5
  import { Radio as RadioPrimitive } from "@base-ui/react/radio"
@@ -1,5 +1,5 @@
1
1
  // Copied by `vantage add ui sample-data`. This file is yours to edit.
2
- // Generated from @squadbase/squadkit registry/components/sample-data.tsx by `npm run registry` (in Vantage, edit packages/squadkit, not registry/).
2
+ // Generated from @squadbase/squadkit registry/components/sample-data.tsx by `pnpm run registry` (in Vantage, edit packages/squadkit, not registry/).
3
3
  "use client"
4
4
 
5
5
  /**
@@ -61,7 +61,7 @@ export function SampleBadge({ label = DEFAULT_SAMPLE_LABEL, className, ...props
61
61
  <Badge
62
62
  data-slot="sample-badge"
63
63
  title={SAMPLE_TITLE}
64
- className={cn("border-warning/30 bg-warning-subtle text-warning align-middle", className)}
64
+ className={cn("border-warning/20 dark:border-warning/25 bg-warning-subtle text-warning align-middle", className)}
65
65
  {...props}
66
66
  >
67
67
  {label}
@@ -1,5 +1,5 @@
1
1
  // Copied by `vantage add ui scatter-chart`. This file is yours to edit.
2
- // Generated from @squadbase/squadkit registry/charts/scatter-chart.tsx by `npm run registry` (in Vantage, edit packages/squadkit, not registry/).
2
+ // Generated from @squadbase/squadkit registry/charts/scatter-chart.tsx by `pnpm run registry` (in Vantage, edit packages/squadkit, not registry/).
3
3
  "use client"
4
4
 
5
5
  /**
@@ -29,7 +29,7 @@ import { ChartFrame } from "@squadbase/vantage/components"
29
29
  import { EChart } from "@squadbase/vantage/components"
30
30
  import { EMPTY_VALUE, type ValueFormat } from "@squadbase/vantage/components"
31
31
  import type { ChartCommonProps, ChartEmptyState, ChartSeriesColor, NumericKeys, ValueFormatter } from "@squadbase/vantage/components"
32
- import { createContext, useCallback, useEffect, useRef, useState } from "react"
32
+ import { createContext, useCallback, useEffect, useRef, useState, type RefObject } from "react"
33
33
  import type { ChartTone } from "@squadbase/vantage/components"
34
34
  import { type ReactNode } from "react"
35
35
  import { computeComparison, defaultChangeDisplay, formatChange, toneForValue, type ComparisonKind, type PeriodGrain } from "@squadbase/vantage/components"
@@ -62,6 +62,8 @@ const SERIES_TOKENS = ["--chart-1", "--chart-2", "--chart-3", "--chart-4", "--ch
62
62
  interface ChartTokens {
63
63
  /** Resolved `--chart-1..5`, in order. */
64
64
  series: string[]
65
+ /** Computed `font-family` of the container, so canvas text matches the DOM. Optional. */
66
+ fontFamily?: string
65
67
  /** Body text: titles and the default `textStyle`. */
66
68
  foreground: string | null
67
69
  /** Secondary text: axis labels, legend, subtitles. */
@@ -70,10 +72,23 @@ interface ChartTokens {
70
72
  border: string | null
71
73
  /** Tooltip surface. */
72
74
  popover: string | null
75
+ /** Semantic and surface dependencies used by typed chart options. Optional for hand-built tokens. */
76
+ colors?: Record<string, string>
77
+ /** Actual inherited painting surface (may change without a token changing). */
78
+ surface?: string | null
73
79
  /** Tooltip text. */
74
80
  popoverForeground: string | null
75
81
  }
76
82
 
83
+ // Keep scope out of the public token shape. A resolved snapshot remembers where arbitrary
84
+ // var(--token) expressions must be read, without retaining unmounted charts globally.
85
+ const tokenScopes = new WeakMap<ChartTokens, Element>()
86
+ const OPTION_COLOR_TOKENS = [
87
+ "--background", "--card", "--muted", "--primary", "--destructive",
88
+ ...["positive", "negative", "warning", "neutral", "info"].flatMap((tone) =>
89
+ ["", "-fill", "-subtle"].map((suffix) => `--${tone}${suffix}`)),
90
+ ]
91
+
77
92
  let normalizeContext: CanvasRenderingContext2D | null | undefined
78
93
 
79
94
  /** The forms `fillStyle` serializes legacy colours to, and zrender can parse. */
@@ -129,14 +144,19 @@ function readChartTokens(el?: Element | null): ChartTokens | null {
129
144
  const color = read(token)
130
145
  if (color) series.push(color)
131
146
  }
132
- return {
147
+ const tokens: ChartTokens = {
133
148
  series,
149
+ colors: Object.fromEntries(OPTION_COLOR_TOKENS.map((name) => [name, styles.getPropertyValue(name).trim()])),
150
+ surface: readChartSurface(target),
151
+ ...(styles.fontFamily ? { fontFamily: styles.fontFamily } : {}),
134
152
  foreground: read("--foreground"),
135
153
  mutedForeground: read("--muted-foreground"),
136
154
  border: read("--border"),
137
155
  popover: read("--popover"),
138
156
  popoverForeground: read("--popover-foreground"),
139
157
  }
158
+ tokenScopes.set(tokens, target)
159
+ return tokens
140
160
  }
141
161
 
142
162
  /** Structural equality, so a theme toggle that changes nothing doesn't re-init. */
@@ -144,8 +164,13 @@ function sameChartTokens(a: ChartTokens | null, b: ChartTokens | null): boolean
144
164
  if (a === b) return true
145
165
  if (!a || !b) return false
146
166
  return (
167
+ tokenScopes.get(a) === tokenScopes.get(b) &&
168
+ a.surface === b.surface &&
169
+ Object.keys(a.colors ?? {}).length === Object.keys(b.colors ?? {}).length &&
170
+ Object.entries(a.colors ?? {}).every(([name, value]) => b.colors?.[name] === value) &&
147
171
  a.series.length === b.series.length &&
148
172
  a.series.every((color, i) => color === b.series[i]) &&
173
+ a.fontFamily === b.fontFamily &&
149
174
  a.foreground === b.foreground &&
150
175
  a.mutedForeground === b.mutedForeground &&
151
176
  a.border === b.border &&
@@ -168,7 +193,7 @@ function sameChartTokens(a: ChartTokens | null, b: ChartTokens | null): boolean
168
193
  * attributes alone leaves the chart painted in the previous palette until a
169
194
  * reload — the tokens in the DOM are new, the canvas is not.
170
195
  */
171
- function watchChartTokens(onChange: () => void): () => void {
196
+ function watchChartTokens(onChange: () => void, scope?: Element | null): () => void {
172
197
  if (typeof document === "undefined") return () => {}
173
198
  // Style edits arrive as bursts of mutations; coalesce them into one read, and
174
199
  // take it after the next frame so a swapped stylesheet has been applied.
@@ -183,8 +208,11 @@ function watchChartTokens(onChange: () => void): () => void {
183
208
 
184
209
  const themeObserver = new MutationObserver(schedule)
185
210
  const attributeFilter = ["class", "style", "data-theme"]
186
- themeObserver.observe(document.documentElement, { attributes: true, attributeFilter })
187
- if (document.body) themeObserver.observe(document.body, { attributes: true, attributeFilter })
211
+ // Only the chart and its ancestors can change its inherited theme. Never observe
212
+ // the document subtree: canvas/tooltip/rendering mutations would trigger every chart.
213
+ for (let node: Element | null = scope ?? document.body ?? document.documentElement; node; node = node.parentElement) {
214
+ themeObserver.observe(node, { attributes: true, attributeFilter })
215
+ }
188
216
 
189
217
  const styleObserver = new MutationObserver(schedule)
190
218
  if (document.head) {
@@ -240,7 +268,7 @@ function buildChartTheme(tokens: ChartTokens): Record<string, unknown> {
240
268
  // Let the page background show through: charts sit on cards, not on a canvas.
241
269
  backgroundColor: "transparent",
242
270
  ...(tokens.series.length > 0 ? { color: tokens.series } : {}),
243
- textStyle: { color: text },
271
+ textStyle: { color: text, ...(tokens.fontFamily ? { fontFamily: tokens.fontFamily } : {}) },
244
272
  title: { textStyle: { color: text }, subtextStyle: { color: muted } },
245
273
  legend: { textStyle: { color: muted } },
246
274
  categoryAxis: axisTheme(tokens, false),
@@ -256,7 +284,11 @@ function buildChartTheme(tokens: ChartTokens): Record<string, unknown> {
256
284
  padding: [8, 12],
257
285
  // Rounded card with a soft shadow; in dark mode the shadow barely shows, so the border carries the edge.
258
286
  extraCssText: "border-radius:8px;box-shadow:var(--shadow-card, 0 4px 12px rgb(0 0 0 / 0.08));",
259
- textStyle: { color: tokens.popoverForeground ?? undefined, fontSize: 12 },
287
+ textStyle: {
288
+ color: tokens.popoverForeground ?? undefined,
289
+ fontSize: 12,
290
+ ...(tokens.fontFamily ? { fontFamily: tokens.fontFamily } : {}),
291
+ },
260
292
  axisPointer: { lineStyle: { color: line }, crossStyle: { color: line } },
261
293
  },
262
294
  }
@@ -268,22 +300,23 @@ function buildChartTheme(tokens: ChartTokens): Record<string, unknown> {
268
300
  * components that build an ECharts option from token colours themselves (the
269
301
  * typed charts), so their palette follows light/dark like `EChart`'s theme.
270
302
  */
271
- function useChartTokens(): ChartTokens | null {
303
+ function useChartTokens(scope?: Element | null | RefObject<Element | null>): ChartTokens | null {
272
304
  const [tokens, setTokens] = useState<ChartTokens | null>(() => readChartTokens())
273
305
  // Compared here, not inside a `setTokens` updater: an updater that reads the DOM is
274
306
  // replayed by React on every rebase and returns a fresh object each time, so the state
275
307
  // never settles ("Maximum update depth exceeded" once the tokens change after mount).
276
308
  const tokensRef = useRef(tokens)
277
309
  useEffect(() => {
310
+ const target = scope && "current" in scope ? scope.current : scope
278
311
  const sync = () => {
279
- const next = readChartTokens()
312
+ const next = readChartTokens(target)
280
313
  if (sameChartTokens(tokensRef.current, next)) return
281
314
  tokensRef.current = next
282
315
  setTokens(next)
283
316
  }
284
317
  sync()
285
- return watchChartTokens(sync)
286
- }, [])
318
+ return watchChartTokens(sync, target)
319
+ }, [scope])
287
320
  return tokens
288
321
  }
289
322
 
@@ -295,7 +328,7 @@ const EMBEDDED_VAR_RE = /var\(\s*(--[\w-]+)\s*\)/g
295
328
  /**
296
329
  * Turn chart colours into canvas-safe strings. `"chart-1"`〜`"chart-5"` come from
297
330
  * the resolved series tokens; `"positive"` / `"warning"` / `"negative"` / `"neutral"` (and the area
298
- * variants `"positive-fill"`, …) are read off the document root (`--positive`, …); `var(--token)` is read off the document root; any
331
+ * variants `"positive-fill"`, …) are read in the snapshot's inherited scope (`--positive`, …); `var(--token)` uses the same scope; any
299
332
  * other CSS colour is normalized like the tokens are. A colour that can't be
300
333
  * resolved comes back as `""`, which ECharts treats as "use the palette".
301
334
  */
@@ -306,12 +339,13 @@ function resolveChartColors(colors: readonly string[], tokens: ChartTokens | nul
306
339
  // Meaning colours are the theme tokens of the same name: same path as `var(--positive)`.
307
340
  if (TONE_NAME_RE.test(color.trim())) {
308
341
  if (typeof document === "undefined") return ""
309
- return toCanvasColor(getComputedStyle(document.documentElement).getPropertyValue(`--${color.trim()}`)) ?? ""
342
+ const target = (tokens && tokenScopes.get(tokens)) ?? document.documentElement
343
+ return toCanvasColor(getComputedStyle(target).getPropertyValue(`--${color.trim()}`)) ?? ""
310
344
  }
311
345
  if (typeof document === "undefined") return color
312
346
  let value = color.trim()
313
347
  const cssVar = CSS_VAR_RE.exec(value)
314
- const styles = getComputedStyle(document.documentElement)
348
+ const styles = getComputedStyle((tokens && tokenScopes.get(tokens)) ?? document.documentElement)
315
349
  if (cssVar) {
316
350
  value = styles.getPropertyValue(cssVar[1]!).trim() || (cssVar[2] ?? "").trim()
317
351
  } else if (value.includes("var(")) {
@@ -357,7 +391,7 @@ function readChartSurface(el: Element | null): string | null {
357
391
  if (color) return color
358
392
  }
359
393
  }
360
- return toCanvasColor(getComputedStyle(document.documentElement).getPropertyValue("--background"))
394
+ return toCanvasColor(getComputedStyle(el ?? document.documentElement).getPropertyValue("--background"))
361
395
  }
362
396
 
363
397
  /** Widths are bucketed so a resize only rebuilds the option when the label budget can change. */
@@ -371,9 +405,10 @@ const WIDTH_BUCKET = 40
371
405
  */
372
406
  function useChartSurface<E extends Element>(
373
407
  forwarded: ForwardedRef<E>,
374
- tokens: ChartTokens | null,
375
- ): { ref: (el: E | null) => void; surface: string | undefined; width: number | undefined } {
408
+ tokens?: ChartTokens | null,
409
+ ): { ref: (el: E | null) => void; surface: string | undefined; width: number | undefined; tokens: ChartTokens | null } {
376
410
  const [node, setNode] = useState<E | null>(null)
411
+ const scopedTokens = useChartTokens(node)
377
412
  const [surface, setSurface] = useState<string | undefined>(undefined)
378
413
  const [width, setWidth] = useState<number | undefined>(undefined)
379
414
  const ref = useCallback(
@@ -387,7 +422,7 @@ function useChartSurface<E extends Element>(
387
422
  useEffect(() => {
388
423
  if (!node) return
389
424
  setSurface(readChartSurface(node) ?? undefined)
390
- }, [node, tokens])
425
+ }, [node, tokens, scopedTokens])
391
426
  useEffect(() => {
392
427
  if (!node || typeof ResizeObserver === "undefined") return
393
428
  const update = (w: number) => setWidth(Math.floor(w / WIDTH_BUCKET) * WIDTH_BUCKET)
@@ -396,7 +431,7 @@ function useChartSurface<E extends Element>(
396
431
  observer.observe(node)
397
432
  return () => observer.disconnect()
398
433
  }, [node])
399
- return { ref, surface, width }
434
+ return { ref, surface, width, tokens: scopedTokens }
400
435
  }
401
436
 
402
437
  /* ---------- inlined from @squadbase/squadkit registry/lib/chart-options.ts (internal to @squadbase/vantage) ---------- */
@@ -786,6 +821,10 @@ const toDate = (t: ParsedTime) => new Date(t.year, t.month - 1, t.day)
786
821
 
787
822
  /** How many x labels a time axis shows at most (the step is picked so the labels never crowd). */
788
823
  const TIME_AXIS_MAX_LABELS = 6
824
+ /** Under this plot width (px) the axis, legend and labels switch to their compact form. */
825
+ const NARROW_PLOT_WIDTH = 400
826
+ /** The most x labels a narrow plot shows (a 262px plot reads 4 at most). */
827
+ const NARROW_TIME_AXIS_MAX_LABELS = 4
789
828
 
790
829
  /** Calendar-friendly label steps per granularity (every 3 months, every week …). */
791
830
  const TIME_AXIS_STEPS: Record<TimeGranularity, readonly number[]> = {
@@ -1231,7 +1270,9 @@ const LEGEND_LINE_BUDGET = 320
1231
1270
  /** How many lines the plain legend takes, estimated from its labels (12px text + 8px dot + gaps). */
1232
1271
  function legendLines(items: readonly string[], plotWidth?: number, reserve = 0): number {
1233
1272
  const width = items.reduce((sum, name) => sum + [...name].length * 12 + 8 + 5 + 16, 0)
1234
- const budget = Math.max(80, (plotWidth ? Math.min(LEGEND_LINE_BUDGET, plotWidth) : LEGEND_LINE_BUDGET) - reserve)
1273
+ // A narrow plot has no room for the PNG buttons beside the legend: they move off its line, so no reserve.
1274
+ const narrow = plotWidth !== undefined && plotWidth < NARROW_PLOT_WIDTH
1275
+ const budget = Math.max(80, (plotWidth ? (narrow ? plotWidth : Math.min(LEGEND_LINE_BUDGET, plotWidth)) : LEGEND_LINE_BUDGET) - (narrow ? 0 : reserve))
1235
1276
  return Math.min(3, Math.max(1, Math.ceil(width / budget)))
1236
1277
  }
1237
1278
 
@@ -1486,7 +1527,15 @@ function buildCartesianOption(cfg: CartesianChartConfig): EChartsOption {
1486
1527
  ? null
1487
1528
  : timeAxisLabelStep(
1488
1529
  rawIndex,
1489
- plotWidth ? Math.max(2, Math.min(TIME_AXIS_MAX_LABELS, Math.floor(plotWidth / TIME_LABEL_WIDTH))) : undefined,
1530
+ plotWidth
1531
+ ? Math.max(
1532
+ 2,
1533
+ Math.min(
1534
+ plotWidth < NARROW_PLOT_WIDTH ? NARROW_TIME_AXIS_MAX_LABELS : TIME_AXIS_MAX_LABELS,
1535
+ Math.floor(plotWidth / TIME_LABEL_WIDTH),
1536
+ ),
1537
+ )
1538
+ : undefined,
1490
1539
  )
1491
1540
  // Plain (non-date) x labels of a line chart: thinned to every n-th so they never touch, never rotated.
1492
1541
  const plainStep = (() => {
@@ -1532,8 +1581,12 @@ function buildCartesianOption(cfg: CartesianChartConfig): EChartsOption {
1532
1581
  : []
1533
1582
  // On a narrow plot the max and the latest label would print over each other: keep the latest.
1534
1583
  const pointGap = plotWidth && labels.length > 1 ? plotWidth / (kind === "bar" ? labels.length : labels.length - 1) : null
1584
+ // By default only the latest value is labelled; an explicit `highlight` keeps its max + latest.
1585
+ const latestOnly = cfg.highlight === undefined && !shareHighlight && picked.length === 2
1535
1586
  const highlightPoints =
1536
- picked.length === 2 && pointGap !== null && Math.abs(picked[1]!.index - picked[0]!.index) * pointGap < HIGHLIGHT_LABEL_WIDTH
1587
+ latestOnly
1588
+ ? [picked[1]!]
1589
+ : picked.length === 2 && pointGap !== null && Math.abs(picked[1]!.index - picked[0]!.index) * pointGap < HIGHLIGHT_LABEL_WIDTH
1537
1590
  ? [picked[1]!]
1538
1591
  : picked
1539
1592
 
@@ -1744,6 +1797,8 @@ function buildCartesianOption(cfg: CartesianChartConfig): EChartsOption {
1744
1797
  ? { width: 0, color, opacity: 0 }
1745
1798
  : { width: 2, color, opacity: dimSeries ? DIMMED : 1 },
1746
1799
  itemStyle: { color, opacity: dimSeries ? DIMMED : 1 },
1800
+ // Hovering a series fades the others (not for a stack, where the bands read together).
1801
+ emphasis: stacked ? undefined : { focus: "series" as const },
1747
1802
  areaStyle: areaStyle && dimSeries ? { ...areaStyle, opacity: DIMMED * 0.3 } : areaStyle,
1748
1803
  markPoint: markPointFor(c, color),
1749
1804
  markLine: undefined,
@@ -2190,7 +2245,10 @@ function buildCartesianOption(cfg: CartesianChartConfig): EChartsOption {
2190
2245
  legend: {
2191
2246
  show: showLegend,
2192
2247
  top: 0,
2193
- right: reserveActions ? ACTIONS_RESERVE : 0,
2248
+ // Narrow: left-aligned and wrapping above the plot, so nothing is cut off at the right edge.
2249
+ ...(plotWidth !== undefined && plotWidth < NARROW_PLOT_WIDTH
2250
+ ? { left: 0, right: 0 }
2251
+ : { right: reserveActions ? ACTIONS_RESERVE : 0 }),
2194
2252
  // Plain wraps onto a second line at narrow widths instead of hiding items behind arrows.
2195
2253
  type: "plain",
2196
2254
  icon: "circle",
@@ -2251,7 +2309,12 @@ function buildCartesianOption(cfg: CartesianChartConfig): EChartsOption {
2251
2309
  }
2252
2310
  }
2253
2311
  const shares = percent ? cartesianSeriesValues(i <= lastActual ? [row] : [], categories, "percent") : null
2254
- for (const p of list) {
2312
+ // Rows follow the legend order (categories first), not ECharts' own series order.
2313
+ const legendRank = (p: AxisTooltipParam) => {
2314
+ const at = categories.indexOf(p.seriesName ?? "")
2315
+ return at === -1 ? categories.length : at
2316
+ }
2317
+ for (const p of [...list].sort((a, b) => legendRank(a) - legendRank(b))) {
2255
2318
  const color = typeof p.color === "string" ? p.color : "currentColor"
2256
2319
  if (p.seriesId === FORECAST_SERIES_ID) {
2257
2320
  // At and before the boundary the forecast repeats the actual value.
@@ -4054,8 +4117,7 @@ function ScatterChartImpl<T extends Record<string, unknown>>(
4054
4117
  }: ScatterChartProps<T>,
4055
4118
  ref: ForwardedRef<HTMLDivElement>,
4056
4119
  ) {
4057
- const tokens = useChartTokens()
4058
- const { ref: frameRef, width: plotWidth } = useChartSurface(ref, tokens)
4120
+ const { ref: frameRef, width: plotWidth, tokens } = useChartSurface(ref)
4059
4121
  // Tooltips and the table read in full; axis ticks read short.
4060
4122
  const formatters = useMemo(
4061
4123
  () => ({
@@ -1,5 +1,5 @@
1
1
  // Copied by `vantage add ui scroll-area`. This file is yours to edit.
2
- // Generated from @squadbase/squadkit registry/ui/scroll-area.tsx by `npm run registry` (in Vantage, edit packages/squadkit, not registry/).
2
+ // Generated from @squadbase/squadkit registry/ui/scroll-area.tsx by `pnpm run registry` (in Vantage, edit packages/squadkit, not registry/).
3
3
  "use client"
4
4
 
5
5
  import { ScrollArea as ScrollAreaPrimitive } from "@base-ui/react/scroll-area"
@@ -1,5 +1,5 @@
1
1
  // Copied by `vantage add ui searchable-select`. This file is yours to edit.
2
- // Generated from @squadbase/squadkit registry/components/searchable-select.tsx by `npm run registry` (in Vantage, edit packages/squadkit, not registry/).
2
+ // Generated from @squadbase/squadkit registry/components/searchable-select.tsx by `pnpm run registry` (in Vantage, edit packages/squadkit, not registry/).
3
3
  "use client"
4
4
 
5
5
  /**
@@ -1,5 +1,5 @@
1
1
  // Copied by `vantage add ui section-header`. This file is yours to edit.
2
- // Generated from @squadbase/squadkit registry/components/section-header.tsx by `npm run registry` (in Vantage, edit packages/squadkit, not registry/).
2
+ // Generated from @squadbase/squadkit registry/components/section-header.tsx by `pnpm run registry` (in Vantage, edit packages/squadkit, not registry/).
3
3
  "use client"
4
4
 
5
5
  /**
@@ -12,8 +12,8 @@ import { cn } from "@squadbase/vantage/ui"
12
12
 
13
13
  const headingStyles = {
14
14
  h1: "text-3xl font-bold tracking-tight",
15
- h2: "text-xl font-semibold tracking-tight",
16
- h3: "text-xl font-semibold",
15
+ h2: "text-base font-semibold tracking-tight",
16
+ h3: "text-base font-semibold",
17
17
  h4: "text-lg font-semibold",
18
18
  } as const
19
19
 
@@ -1,5 +1,5 @@
1
1
  // Copied by `vantage add ui segmented-control`. This file is yours to edit.
2
- // Generated from @squadbase/squadkit registry/components/segmented-control.tsx by `npm run registry` (in Vantage, edit packages/squadkit, not registry/).
2
+ // Generated from @squadbase/squadkit registry/components/segmented-control.tsx by `pnpm run registry` (in Vantage, edit packages/squadkit, not registry/).
3
3
  "use client"
4
4
 
5
5
  /**
@@ -1,5 +1,5 @@
1
1
  // Copied by `vantage add ui select`. This file is yours to edit.
2
- // Generated from @squadbase/squadkit registry/ui/select.tsx by `npm run registry` (in Vantage, edit packages/squadkit, not registry/).
2
+ // Generated from @squadbase/squadkit registry/ui/select.tsx by `pnpm run registry` (in Vantage, edit packages/squadkit, not registry/).
3
3
  "use client"
4
4
 
5
5
  import * as React from "react"
@@ -1,5 +1,5 @@
1
1
  // Copied by `vantage add ui separator`. This file is yours to edit.
2
- // Generated from @squadbase/squadkit registry/ui/separator.tsx by `npm run registry` (in Vantage, edit packages/squadkit, not registry/).
2
+ // Generated from @squadbase/squadkit registry/ui/separator.tsx by `pnpm run registry` (in Vantage, edit packages/squadkit, not registry/).
3
3
  "use client"
4
4
 
5
5
  import { Separator as SeparatorPrimitive } from "@base-ui/react/separator"
@@ -1,5 +1,5 @@
1
1
  // Copied by `vantage add ui sheet`. This file is yours to edit.
2
- // Generated from @squadbase/squadkit registry/ui/sheet.tsx by `npm run registry` (in Vantage, edit packages/squadkit, not registry/).
2
+ // Generated from @squadbase/squadkit registry/ui/sheet.tsx by `pnpm run registry` (in Vantage, edit packages/squadkit, not registry/).
3
3
  "use client"
4
4
 
5
5
  import * as React from "react"
@@ -1,5 +1,5 @@
1
1
  // Copied by `vantage add ui sidebar`. This file is yours to edit.
2
- // Generated from @squadbase/squadkit registry/ui/sidebar.tsx by `npm run registry` (in Vantage, edit packages/squadkit, not registry/).
2
+ // Generated from @squadbase/squadkit registry/ui/sidebar.tsx by `pnpm run registry` (in Vantage, edit packages/squadkit, not registry/).
3
3
  "use client"
4
4
 
5
5
  import * as React from "react"
@@ -1,5 +1,5 @@
1
1
  // Copied by `vantage add ui skeleton`. This file is yours to edit.
2
- // Generated from @squadbase/squadkit registry/ui/skeleton.tsx by `npm run registry` (in Vantage, edit packages/squadkit, not registry/).
2
+ // Generated from @squadbase/squadkit registry/ui/skeleton.tsx by `pnpm run registry` (in Vantage, edit packages/squadkit, not registry/).
3
3
  "use client"
4
4
 
5
5
  import { cn } from "@squadbase/vantage/ui"
@@ -1,5 +1,5 @@
1
1
  // Copied by `vantage add ui slider`. This file is yours to edit.
2
- // Generated from @squadbase/squadkit registry/ui/slider.tsx by `npm run registry` (in Vantage, edit packages/squadkit, not registry/).
2
+ // Generated from @squadbase/squadkit registry/ui/slider.tsx by `pnpm run registry` (in Vantage, edit packages/squadkit, not registry/).
3
3
  "use client"
4
4
 
5
5
  import { Slider as SliderPrimitive } from "@base-ui/react/slider"
@@ -45,7 +45,7 @@ function Slider({
45
45
  <SliderPrimitive.Thumb
46
46
  data-slot="slider-thumb"
47
47
  key={index}
48
- 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"
48
+ className="relative block size-3 shrink-0 rounded-full border border-ring bg-background 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"
49
49
  />
50
50
  ))}
51
51
  </SliderPrimitive.Control>
@@ -1,5 +1,5 @@
1
1
  // Copied by `vantage add ui sparkline`. This file is yours to edit.
2
- // Generated from @squadbase/squadkit registry/charts/sparkline.tsx by `npm run registry` (in Vantage, edit packages/squadkit, not registry/).
2
+ // Generated from @squadbase/squadkit registry/charts/sparkline.tsx by `pnpm run registry` (in Vantage, edit packages/squadkit, not registry/).
3
3
  "use client"
4
4
 
5
5
  /**
@@ -1,5 +1,5 @@
1
1
  // Copied by `vantage add ui spinner`. This file is yours to edit.
2
- // Generated from @squadbase/squadkit registry/ui/spinner.tsx by `npm run registry` (in Vantage, edit packages/squadkit, not registry/).
2
+ // Generated from @squadbase/squadkit registry/ui/spinner.tsx by `pnpm run registry` (in Vantage, edit packages/squadkit, not registry/).
3
3
  "use client"
4
4
 
5
5
  import { cn } from "@squadbase/vantage/ui"
@@ -1,5 +1,5 @@
1
1
  // Copied by `vantage add ui states`. This file is yours to edit.
2
- // Generated from @squadbase/squadkit registry/ui/states.tsx by `npm run registry` (in Vantage, edit packages/squadkit, not registry/).
2
+ // Generated from @squadbase/squadkit registry/ui/states.tsx by `pnpm run registry` (in Vantage, edit packages/squadkit, not registry/).
3
3
  "use client"
4
4
 
5
5
  /**
@@ -1,5 +1,5 @@
1
1
  // Copied by `vantage add ui status-badge`. This file is yours to edit.
2
- // Generated from @squadbase/squadkit registry/components/status-badge.tsx by `npm run registry` (in Vantage, edit packages/squadkit, not registry/).
2
+ // Generated from @squadbase/squadkit registry/components/status-badge.tsx by `pnpm run registry` (in Vantage, edit packages/squadkit, not registry/).
3
3
  "use client"
4
4
 
5
5
  /**
@@ -75,12 +75,12 @@ const legacyColorTones: Record<string, StatusTone> = {
75
75
  * One literal class set per tone — Tailwind only emits classes it can see
76
76
  * literally in the source.
77
77
  */
78
- const toneStyles: Record<StatusTone, { dot: string; bg: string; text: string }> = {
79
- positive: { dot: "bg-positive", bg: "bg-positive-subtle", text: "text-positive" },
80
- negative: { dot: "bg-negative", bg: "bg-negative-subtle", text: "text-negative" },
81
- warning: { dot: "bg-warning", bg: "bg-warning-subtle", text: "text-warning" },
82
- info: { dot: "bg-info", bg: "bg-info-subtle", text: "text-info" },
83
- neutral: { dot: "bg-neutral", bg: "bg-neutral-subtle", text: "text-neutral" },
78
+ const toneStyles: Record<StatusTone, { dot: string; bg: string; text: string; border: string }> = {
79
+ positive: { dot: "bg-positive", bg: "bg-positive-subtle", text: "text-positive", border: "border-positive/20 dark:border-positive/25" },
80
+ negative: { dot: "bg-negative", bg: "bg-negative-subtle", text: "text-negative", border: "border-negative/20 dark:border-negative/25" },
81
+ warning: { dot: "bg-warning", bg: "bg-warning-subtle", text: "text-warning", border: "border-warning/20 dark:border-warning/25" },
82
+ info: { dot: "bg-info", bg: "bg-info-subtle", text: "text-info", border: "border-info/20 dark:border-info/25" },
83
+ neutral: { dot: "bg-neutral", bg: "bg-neutral-subtle", text: "text-neutral", border: "border-neutral/20 dark:border-neutral/25" },
84
84
  }
85
85
 
86
86
  const resolveTone = (color: string | undefined): StatusTone => {
@@ -110,10 +110,10 @@ export const StatusBadge = forwardRef<HTMLSpanElement, StatusBadgeProps>(functio
110
110
  ref={ref}
111
111
  data-slot="status-badge"
112
112
  variant="outline"
113
- className={cn("gap-1.5 border-transparent", style.bg, style.text, className)}
113
+ className={cn("gap-1.5 rounded-md", style.border, style.bg, style.text, className)}
114
114
  aria-label={displayLabel}
115
115
  >
116
- <span className={cn("inline-block size-2 rounded-full", style.dot)} aria-hidden="true" />
116
+ <span className={cn("inline-block size-1.5 rounded-full", style.dot)} aria-hidden="true" />
117
117
  {displayLabel}
118
118
  </Badge>
119
119
  )
@@ -1,5 +1,5 @@
1
1
  // Copied by `vantage add ui switch`. This file is yours to edit.
2
- // Generated from @squadbase/squadkit registry/ui/switch.tsx by `npm run registry` (in Vantage, edit packages/squadkit, not registry/).
2
+ // Generated from @squadbase/squadkit registry/ui/switch.tsx by `pnpm run registry` (in Vantage, edit packages/squadkit, not registry/).
3
3
  "use client"
4
4
 
5
5
  import { Switch as SwitchPrimitive } from "@base-ui/react/switch"
@@ -1,5 +1,5 @@
1
1
  // Copied by `vantage add ui table`. This file is yours to edit.
2
- // Generated from @squadbase/squadkit registry/ui/table.tsx by `npm run registry` (in Vantage, edit packages/squadkit, not registry/).
2
+ // Generated from @squadbase/squadkit registry/ui/table.tsx by `pnpm run registry` (in Vantage, edit packages/squadkit, not registry/).
3
3
  "use client"
4
4
 
5
5
  import * as React from "react"
@@ -1,5 +1,5 @@
1
1
  // Copied by `vantage add ui tabs`. This file is yours to edit.
2
- // Generated from @squadbase/squadkit registry/ui/tabs.tsx by `npm run registry` (in Vantage, edit packages/squadkit, not registry/).
2
+ // Generated from @squadbase/squadkit registry/ui/tabs.tsx by `pnpm run registry` (in Vantage, edit packages/squadkit, not registry/).
3
3
  "use client"
4
4
 
5
5
  import { Tabs as TabsPrimitive } from "@base-ui/react/tabs"
@@ -1,5 +1,5 @@
1
1
  // Copied by `vantage add ui textarea`. This file is yours to edit.
2
- // Generated from @squadbase/squadkit registry/ui/textarea.tsx by `npm run registry` (in Vantage, edit packages/squadkit, not registry/).
2
+ // Generated from @squadbase/squadkit registry/ui/textarea.tsx by `pnpm run registry` (in Vantage, edit packages/squadkit, not registry/).
3
3
  "use client"
4
4
 
5
5
  import * as React from "react"
@@ -1,5 +1,5 @@
1
1
  // Copied by `vantage add ui toast`. This file is yours to edit.
2
- // Generated from @squadbase/squadkit registry/ui/toast.tsx by `npm run registry` (in Vantage, edit packages/squadkit, not registry/).
2
+ // Generated from @squadbase/squadkit registry/ui/toast.tsx by `pnpm run registry` (in Vantage, edit packages/squadkit, not registry/).
3
3
  "use client"
4
4
 
5
5
  import * as React from "react"
@@ -1,5 +1,5 @@
1
1
  // Copied by `vantage add ui toggle-group`. This file is yours to edit.
2
- // Generated from @squadbase/squadkit registry/ui/toggle-group.tsx by `npm run registry` (in Vantage, edit packages/squadkit, not registry/).
2
+ // Generated from @squadbase/squadkit registry/ui/toggle-group.tsx by `pnpm run registry` (in Vantage, edit packages/squadkit, not registry/).
3
3
  "use client"
4
4
 
5
5
  import * as React from "react"
@@ -1,5 +1,5 @@
1
1
  // Copied by `vantage add ui toggle`. This file is yours to edit.
2
- // Generated from @squadbase/squadkit registry/ui/toggle.tsx by `npm run registry` (in Vantage, edit packages/squadkit, not registry/).
2
+ // Generated from @squadbase/squadkit registry/ui/toggle.tsx by `pnpm run registry` (in Vantage, edit packages/squadkit, not registry/).
3
3
  "use client"
4
4
 
5
5
  import { Toggle as TogglePrimitive } from "@base-ui/react/toggle"
@@ -1,5 +1,5 @@
1
1
  // Copied by `vantage add ui tooltip`. This file is yours to edit.
2
- // Generated from @squadbase/squadkit registry/ui/tooltip.tsx by `npm run registry` (in Vantage, edit packages/squadkit, not registry/).
2
+ // Generated from @squadbase/squadkit registry/ui/tooltip.tsx by `pnpm run registry` (in Vantage, edit packages/squadkit, not registry/).
3
3
  "use client"
4
4
 
5
5
  import { Tooltip as TooltipPrimitive } from "@base-ui/react/tooltip"
@@ -34,14 +34,18 @@ function TooltipContent({
34
34
  align = "center",
35
35
  alignOffset = 0,
36
36
  children,
37
+ container,
37
38
  ...props
38
39
  }: TooltipPrimitive.Popup.Props &
39
40
  Pick<
40
41
  TooltipPrimitive.Positioner.Props,
41
42
  "align" | "alignOffset" | "side" | "sideOffset"
42
- >) {
43
+ > & {
44
+ /** ポータルの親要素。ローカルテーマ内の要素を渡すと、その CSS 変数を継承する。省略時は body。 */
45
+ container?: TooltipPrimitive.Portal.Props["container"]
46
+ }) {
43
47
  return (
44
- <TooltipPrimitive.Portal>
48
+ <TooltipPrimitive.Portal container={container} className={container ? "contents" : undefined}>
45
49
  <TooltipPrimitive.Positioner
46
50
  align={align}
47
51
  alignOffset={alignOffset}