@squadbase/vantage 0.6.2-dev1.d7c0911 → 0.6.2-dev1.e30f2cc
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.
- package/dist/{build-X5NVCQKT.js → build-A23M4GCH.js} +7 -7
- package/dist/{build-X5NVCQKT.js.map → build-A23M4GCH.js.map} +1 -1
- package/dist/{check-ZBIH422T.js → check-FBHT6W6J.js} +5 -5
- package/dist/{check-ZBIH422T.js.map → check-FBHT6W6J.js.map} +1 -1
- package/dist/chunk-2IAPIOPS.js +152 -0
- package/dist/chunk-2IAPIOPS.js.map +1 -0
- package/dist/chunk-57GHR5LN.js +163 -0
- package/dist/chunk-57GHR5LN.js.map +1 -0
- package/dist/{chunk-7DZGJQ3P.js → chunk-5C2SEDPH.js} +21 -4
- package/dist/chunk-5C2SEDPH.js.map +1 -0
- package/dist/chunk-6OTTGAPO.js +44 -0
- package/dist/chunk-6OTTGAPO.js.map +1 -0
- package/dist/{chunk-XPQSTZUU.js → chunk-7S52M2SL.js} +4 -3
- package/dist/chunk-7S52M2SL.js.map +1 -0
- package/dist/{chunk-V3LF7BE7.js → chunk-ANZLVSEP.js} +4 -5
- package/dist/chunk-ANZLVSEP.js.map +1 -0
- package/dist/{chunk-XQUSGIDG.js → chunk-CKWPK4RO.js} +10 -3
- package/dist/chunk-CKWPK4RO.js.map +1 -0
- package/dist/chunk-JXFCSF3K.js +673 -0
- package/dist/chunk-JXFCSF3K.js.map +1 -0
- package/dist/{chunk-WRSX2MDK.js → chunk-QOXXOFGL.js} +115 -930
- package/dist/chunk-QOXXOFGL.js.map +1 -0
- package/dist/{chunk-CEXAQQ5W.js → chunk-S5MDTHH7.js} +180 -18
- package/dist/chunk-S5MDTHH7.js.map +1 -0
- package/dist/{chunk-2ICNHUG6.js → chunk-SDJTTMLK.js} +64 -7
- package/dist/chunk-SDJTTMLK.js.map +1 -0
- package/dist/{chunk-WAMZWZJB.js → chunk-SHZM3EXB.js} +19 -8
- package/dist/chunk-SHZM3EXB.js.map +1 -0
- package/dist/{chunk-JKLLFVEU.js → chunk-UWSQUHX6.js} +4 -99
- package/dist/chunk-UWSQUHX6.js.map +1 -0
- package/dist/cli.js +6 -6
- package/dist/client/index.d.ts +2 -0
- package/dist/client/index.js +8 -2
- package/dist/client/index.js.map +1 -1
- package/dist/components/index.d.ts +13 -249
- package/dist/components/index.js +5 -2
- package/dist/delta-text-CvwBGJ95.d.ts +15 -0
- package/dist/{dev-4XEDTELV.js → dev-H4I2JL63.js} +7 -7
- package/dist/{dev-4XEDTELV.js.map → dev-H4I2JL63.js.map} +1 -1
- package/dist/doc/index.d.ts +215 -2
- package/dist/doc/index.js +307 -3
- package/dist/doc/index.js.map +1 -1
- package/dist/{doctor-5E2VEZPK.js → doctor-B2O3GJDU.js} +5 -5
- package/dist/{doctor-5E2VEZPK.js.map → doctor-B2O3GJDU.js.map} +1 -1
- package/dist/format-U0cQl069.d.ts +243 -0
- package/dist/query/index.js +2 -2
- package/dist/{routes-3SGAFDMC.js → routes-PVKNT777.js} +4 -4
- package/dist/{routes-3SGAFDMC.js.map → routes-PVKNT777.js.map} +1 -1
- package/dist/slide/index.d.ts +272 -1
- package/dist/slide/index.js +974 -4
- package/dist/slide/index.js.map +1 -1
- package/dist/table/index.js +8 -5
- package/dist/table/index.js.map +1 -1
- package/dist/ui/index.d.ts +4 -1
- package/dist/ui/index.js +3 -3
- package/dist/ui/index.js.map +1 -1
- package/dist/{upgrade-JHXZBGQS.js → upgrade-6DT7ADRP.js} +4 -4
- package/dist/{upgrade-JHXZBGQS.js.map → upgrade-6DT7ADRP.js.map} +1 -1
- package/dist/vite/index.js +3 -3
- package/docs/en/changelog.md +2 -0
- package/docs/en/components.md +13 -2
- package/docs/en/doc/delta-text.md +40 -0
- package/docs/en/doc/doc-action-items.md +49 -0
- package/docs/en/doc/doc-callout.md +38 -0
- package/docs/en/doc/doc-data-table.md +60 -0
- package/docs/en/doc/doc-executive-summary.md +64 -0
- package/docs/en/doc/doc-figure.md +56 -0
- package/docs/en/doc/doc-key-findings.md +61 -0
- package/docs/en/doc/doc-kpi-scorecard.md +80 -0
- package/docs/en/doc/doc-notes-and-sources.md +43 -0
- package/docs/en/doc/doc-report-header.md +46 -0
- package/docs/en/pages-and-metadata.md +15 -0
- package/docs/en/parts/area-chart.md +99 -0
- package/docs/en/parts/bar-chart.md +91 -0
- package/docs/en/parts/bar-list.md +50 -0
- package/docs/en/parts/category-bar.md +37 -0
- package/docs/en/parts/chart-frame.md +39 -0
- package/docs/en/parts/delta.md +4 -3
- package/docs/en/parts/donut-chart.md +72 -0
- package/docs/en/parts/funnel-steps.md +2 -1
- package/docs/en/parts/heatmap.md +53 -0
- package/docs/en/parts/kpi-card.md +2 -1
- package/docs/en/parts/legend.md +35 -0
- package/docs/en/parts/line-chart.md +94 -0
- package/docs/en/parts/progress-circle.md +33 -0
- package/docs/en/parts/sample-data.md +39 -0
- package/docs/en/parts/scatter-chart.md +56 -0
- package/docs/en/parts/tracker.md +36 -0
- package/docs/en/parts/updated-at.md +30 -0
- package/docs/en/parts/waterfall-chart.md +56 -0
- package/docs/en/slide/slide-chart-full.md +48 -0
- package/docs/en/slide/slide-chart-insight.md +52 -0
- package/docs/en/slide/slide-columns.md +46 -0
- package/docs/en/slide/slide-comparison.md +68 -0
- package/docs/en/slide/slide-cover.md +39 -0
- package/docs/en/slide/slide-exec-summary.md +47 -0
- package/docs/en/slide/slide-heading.md +38 -0
- package/docs/en/slide/slide-kpi-grid.md +55 -0
- package/docs/en/slide/slide-kpi-hero.md +58 -0
- package/docs/en/slide/slide-next-actions.md +49 -0
- package/docs/en/slide/slide-scorecard-table.md +54 -0
- package/docs/en/slide/slide-section.md +44 -0
- package/docs/en/slide/slide-source-line.md +34 -0
- package/docs/en/ui/alert-dialog.md +42 -0
- package/docs/en/ui/avatar.md +31 -0
- package/docs/en/ui/combobox.md +74 -0
- package/docs/en/ui/drawer.md +41 -0
- package/docs/en/ui/empty.md +1 -1
- package/docs/en/ui/error-state.md +4 -3
- package/docs/en/ui/field.md +42 -0
- package/docs/en/ui/hover-card.md +21 -0
- package/docs/en/ui/kbd.md +17 -0
- package/docs/en/ui/loading.md +1 -1
- package/docs/en/ui/pagination.md +36 -0
- package/docs/en/ui/radio-group.md +21 -0
- package/docs/en/ui/toast.md +44 -0
- package/docs/en/ui/toggle-group.md +4 -3
- package/docs/index.json +857 -77
- package/docs/ja/changelog.md +2 -0
- package/docs/ja/components.md +12 -1
- package/docs/ja/doc/delta-text.md +40 -0
- package/docs/ja/doc/doc-action-items.md +49 -0
- package/docs/ja/doc/doc-callout.md +38 -0
- package/docs/ja/doc/doc-data-table.md +60 -0
- package/docs/ja/doc/doc-executive-summary.md +64 -0
- package/docs/ja/doc/doc-figure.md +56 -0
- package/docs/ja/doc/doc-key-findings.md +61 -0
- package/docs/ja/doc/doc-kpi-scorecard.md +80 -0
- package/docs/ja/doc/doc-notes-and-sources.md +43 -0
- package/docs/ja/doc/doc-report-header.md +46 -0
- package/docs/ja/page-types/slide.md +1 -0
- package/docs/ja/pages-and-metadata.md +15 -0
- package/docs/ja/parts/area-chart.md +49 -25
- package/docs/ja/parts/bar-chart.md +50 -24
- package/docs/ja/parts/bar-list.md +31 -8
- package/docs/ja/parts/chart-frame.md +36 -0
- package/docs/ja/parts/delta.md +5 -4
- package/docs/ja/parts/donut-chart.md +45 -26
- package/docs/ja/parts/funnel-steps.md +27 -8
- package/docs/ja/parts/heatmap.md +45 -0
- package/docs/ja/parts/kpi-card.md +2 -1
- package/docs/ja/parts/legend.md +36 -0
- package/docs/ja/parts/line-chart.md +48 -22
- package/docs/ja/parts/sample-data.md +61 -0
- package/docs/ja/parts/scatter-chart.md +69 -0
- package/docs/ja/parts/updated-at.md +27 -0
- package/docs/ja/parts/waterfall-chart.md +61 -0
- package/docs/ja/slide/slide-chart-full.md +48 -0
- package/docs/ja/slide/slide-chart-insight.md +52 -0
- package/docs/ja/slide/slide-columns.md +46 -0
- package/docs/ja/slide/slide-comparison.md +68 -0
- package/docs/ja/slide/slide-cover.md +39 -0
- package/docs/ja/slide/slide-exec-summary.md +47 -0
- package/docs/ja/slide/slide-heading.md +38 -0
- package/docs/ja/slide/slide-kpi-grid.md +55 -0
- package/docs/ja/slide/slide-kpi-hero.md +58 -0
- package/docs/ja/slide/slide-next-actions.md +49 -0
- package/docs/ja/slide/slide-scorecard-table.md +54 -0
- package/docs/ja/slide/slide-section.md +44 -0
- package/docs/ja/slide/slide-source-line.md +34 -0
- package/docs/ja/ui/empty.md +1 -1
- package/docs/ja/ui/error-state.md +4 -3
- package/docs/ja/ui/loading.md +1 -1
- package/docs/ja/ui/toggle-group.md +4 -3
- package/package.json +26 -25
- package/registry/ui/accordion.tsx +1 -1
- package/registry/ui/alert-dialog.tsx +1 -1
- package/registry/ui/alert.tsx +1 -1
- package/registry/ui/app-shell.tsx +1 -1
- package/registry/ui/area-chart.tsx +89 -27
- package/registry/ui/attention-list.tsx +303 -0
- package/registry/ui/avatar.tsx +1 -1
- package/registry/ui/badge.tsx +1 -1
- package/registry/ui/bar-chart.tsx +89 -27
- package/registry/ui/bar-list.tsx +88 -25
- package/registry/ui/box-plot-chart.tsx +3906 -0
- package/registry/ui/breadcrumb.tsx +1 -1
- package/registry/ui/button.tsx +1 -1
- package/registry/ui/calendar.tsx +1 -1
- package/registry/ui/card.tsx +1 -1
- package/registry/ui/category-bar.tsx +55 -20
- package/registry/ui/chart-frame.tsx +57 -22
- package/registry/ui/checkbox.tsx +1 -1
- package/registry/ui/collapsible.tsx +1 -1
- package/registry/ui/combobox.tsx +1 -1
- package/registry/ui/command.tsx +1 -1
- package/registry/ui/dashboard-card.tsx +5 -5
- package/registry/ui/data-table.tsx +1 -1
- package/registry/ui/date-range-picker.tsx +1 -1
- package/registry/ui/delta.tsx +12 -9
- package/registry/ui/dialog.tsx +1 -1
- package/registry/ui/donut-chart.tsx +90 -27
- package/registry/ui/drawer.tsx +1 -1
- package/registry/ui/dropdown-menu.tsx +1 -1
- package/registry/ui/echart.tsx +195 -45
- package/registry/ui/field.tsx +1 -1
- package/registry/ui/filter-bar.tsx +1 -1
- package/registry/ui/funnel-steps.tsx +34 -6
- package/registry/ui/heatmap.tsx +56 -22
- package/registry/ui/histogram-chart.tsx +3986 -0
- package/registry/ui/hover-card.tsx +1 -1
- package/registry/ui/input-group.tsx +1 -1
- package/registry/ui/input.tsx +1 -1
- package/registry/ui/kbd.tsx +1 -1
- package/registry/ui/kpi-card.tsx +42 -15
- package/registry/ui/label.tsx +1 -1
- package/registry/ui/legend.tsx +88 -25
- package/registry/ui/line-chart.tsx +89 -27
- package/registry/ui/metric-value.tsx +1 -1
- package/registry/ui/multi-select.tsx +1 -1
- package/registry/ui/page-shell.tsx +11 -11
- package/registry/ui/pagination.tsx +1 -1
- package/registry/ui/paired-chart.tsx +3827 -0
- package/registry/ui/placeholder.tsx +1 -1
- package/registry/ui/popover.tsx +1 -1
- package/registry/ui/progress-circle.tsx +1 -1
- package/registry/ui/progress.tsx +1 -1
- package/registry/ui/radio-group.tsx +1 -1
- package/registry/ui/sample-data.tsx +2 -2
- package/registry/ui/scatter-chart.tsx +89 -27
- package/registry/ui/scroll-area.tsx +1 -1
- package/registry/ui/searchable-select.tsx +1 -1
- package/registry/ui/section-header.tsx +3 -3
- package/registry/ui/segmented-control.tsx +1 -1
- package/registry/ui/select.tsx +1 -1
- package/registry/ui/separator.tsx +1 -1
- package/registry/ui/sheet.tsx +1 -1
- package/registry/ui/sidebar.tsx +1 -1
- package/registry/ui/skeleton.tsx +1 -1
- package/registry/ui/slider.tsx +2 -2
- package/registry/ui/sparkline.tsx +1 -1
- package/registry/ui/spinner.tsx +1 -1
- package/registry/ui/states.tsx +1 -1
- package/registry/ui/status-badge.tsx +9 -9
- package/registry/ui/switch.tsx +1 -1
- package/registry/ui/table.tsx +1 -1
- package/registry/ui/tabs.tsx +1 -1
- package/registry/ui/textarea.tsx +1 -1
- package/registry/ui/toast.tsx +1 -1
- package/registry/ui/toggle-group.tsx +1 -1
- package/registry/ui/toggle.tsx +1 -1
- package/registry/ui/tooltip.tsx +7 -3
- package/registry/ui/tracker.tsx +10 -4
- package/registry/ui/trend-indicator.tsx +3 -3
- package/registry/ui/updated-at.tsx +1 -1
- package/registry/ui/waterfall-chart.tsx +89 -27
- package/skills/vantage-design/SKILL.md +34 -24
- package/skills/vantage-design/references/extract.md +16 -14
- package/skills/vantage-design/references/format.md +6 -5
- package/skills/vantage-design/references/presets.md +60 -110
- package/skills/vantage-pitfalls/SKILL.md +5 -0
- package/skills/vantage-slide/SKILL.md +54 -36
- package/templates/AGENTS.md +4 -2
- package/templates/agents/doc.md +48 -0
- package/templates/agents/page.md +32 -1
- package/templates/agents/slide.md +70 -2
- package/theme.css +32 -24
- package/dist/chunk-2ICNHUG6.js.map +0 -1
- package/dist/chunk-7DZGJQ3P.js.map +0 -1
- package/dist/chunk-CEXAQQ5W.js.map +0 -1
- package/dist/chunk-JKLLFVEU.js.map +0 -1
- package/dist/chunk-V3LF7BE7.js.map +0 -1
- package/dist/chunk-WAMZWZJB.js.map +0 -1
- package/dist/chunk-WRSX2MDK.js.map +0 -1
- package/dist/chunk-XPQSTZUU.js.map +0 -1
- package/dist/chunk-XQUSGIDG.js.map +0 -1
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// Copied by `vantage add ui breadcrumb`. This file is yours to edit.
|
|
2
|
-
// Generated from @squadbase/squadkit registry/ui/breadcrumb.tsx by `
|
|
2
|
+
// Generated from @squadbase/squadkit registry/ui/breadcrumb.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"
|
package/registry/ui/button.tsx
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// Copied by `vantage add ui button`. This file is yours to edit.
|
|
2
|
-
// Generated from @squadbase/squadkit registry/ui/button.tsx by `
|
|
2
|
+
// Generated from @squadbase/squadkit registry/ui/button.tsx by `pnpm run registry` (in Vantage, edit packages/squadkit, not registry/).
|
|
3
3
|
"use client"
|
|
4
4
|
|
|
5
5
|
import { Button as ButtonPrimitive } from "@base-ui/react/button"
|
package/registry/ui/calendar.tsx
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// Copied by `vantage add ui calendar`. This file is yours to edit.
|
|
2
|
-
// Generated from @squadbase/squadkit registry/ui/calendar.tsx by `
|
|
2
|
+
// Generated from @squadbase/squadkit registry/ui/calendar.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"
|
package/registry/ui/card.tsx
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// Copied by `vantage add ui card`. This file is yours to edit.
|
|
2
|
-
// Generated from @squadbase/squadkit registry/ui/card.tsx by `
|
|
2
|
+
// Generated from @squadbase/squadkit registry/ui/card.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 category-bar`. This file is yours to edit.
|
|
2
|
-
// Generated from @squadbase/squadkit registry/charts/category-bar.tsx by `
|
|
2
|
+
// Generated from @squadbase/squadkit registry/charts/category-bar.tsx by `pnpm run registry` (in Vantage, edit packages/squadkit, not registry/).
|
|
3
3
|
"use client"
|
|
4
4
|
|
|
5
5
|
/**
|
|
@@ -13,7 +13,7 @@ import { cn } from "@squadbase/vantage/ui"
|
|
|
13
13
|
import { Tooltip, TooltipContent, TooltipTrigger } from "@squadbase/vantage/ui"
|
|
14
14
|
import type { ValueFormat } from "@squadbase/vantage/components"
|
|
15
15
|
import type { ChartColor, ValueFormatter } from "@squadbase/vantage/components"
|
|
16
|
-
import { createContext, useCallback, useEffect, useRef, useState, type ForwardedRef } from "react"
|
|
16
|
+
import { createContext, useCallback, useEffect, useRef, useState, type ForwardedRef, type RefObject } from "react"
|
|
17
17
|
import type { ChartTone } from "@squadbase/vantage/components"
|
|
18
18
|
import { DEFAULT_LOCALE, EMPTY_VALUE, formatValue, toValueFormatter } from "@squadbase/vantage/components"
|
|
19
19
|
import type { ChartColors, ChartSeriesColor } from "@squadbase/vantage/components"
|
|
@@ -42,6 +42,8 @@ const SERIES_TOKENS = ["--chart-1", "--chart-2", "--chart-3", "--chart-4", "--ch
|
|
|
42
42
|
interface ChartTokens {
|
|
43
43
|
/** Resolved `--chart-1..5`, in order. */
|
|
44
44
|
series: string[]
|
|
45
|
+
/** Computed `font-family` of the container, so canvas text matches the DOM. Optional. */
|
|
46
|
+
fontFamily?: string
|
|
45
47
|
/** Body text: titles and the default `textStyle`. */
|
|
46
48
|
foreground: string | null
|
|
47
49
|
/** Secondary text: axis labels, legend, subtitles. */
|
|
@@ -50,10 +52,23 @@ interface ChartTokens {
|
|
|
50
52
|
border: string | null
|
|
51
53
|
/** Tooltip surface. */
|
|
52
54
|
popover: string | null
|
|
55
|
+
/** Semantic and surface dependencies used by typed chart options. Optional for hand-built tokens. */
|
|
56
|
+
colors?: Record<string, string>
|
|
57
|
+
/** Actual inherited painting surface (may change without a token changing). */
|
|
58
|
+
surface?: string | null
|
|
53
59
|
/** Tooltip text. */
|
|
54
60
|
popoverForeground: string | null
|
|
55
61
|
}
|
|
56
62
|
|
|
63
|
+
// Keep scope out of the public token shape. A resolved snapshot remembers where arbitrary
|
|
64
|
+
// var(--token) expressions must be read, without retaining unmounted charts globally.
|
|
65
|
+
const tokenScopes = new WeakMap<ChartTokens, Element>()
|
|
66
|
+
const OPTION_COLOR_TOKENS = [
|
|
67
|
+
"--background", "--card", "--muted", "--primary", "--destructive",
|
|
68
|
+
...["positive", "negative", "warning", "neutral", "info"].flatMap((tone) =>
|
|
69
|
+
["", "-fill", "-subtle"].map((suffix) => `--${tone}${suffix}`)),
|
|
70
|
+
]
|
|
71
|
+
|
|
57
72
|
let normalizeContext: CanvasRenderingContext2D | null | undefined
|
|
58
73
|
|
|
59
74
|
/** The forms `fillStyle` serializes legacy colours to, and zrender can parse. */
|
|
@@ -109,14 +124,19 @@ function readChartTokens(el?: Element | null): ChartTokens | null {
|
|
|
109
124
|
const color = read(token)
|
|
110
125
|
if (color) series.push(color)
|
|
111
126
|
}
|
|
112
|
-
|
|
127
|
+
const tokens: ChartTokens = {
|
|
113
128
|
series,
|
|
129
|
+
colors: Object.fromEntries(OPTION_COLOR_TOKENS.map((name) => [name, styles.getPropertyValue(name).trim()])),
|
|
130
|
+
surface: readChartSurface(target),
|
|
131
|
+
...(styles.fontFamily ? { fontFamily: styles.fontFamily } : {}),
|
|
114
132
|
foreground: read("--foreground"),
|
|
115
133
|
mutedForeground: read("--muted-foreground"),
|
|
116
134
|
border: read("--border"),
|
|
117
135
|
popover: read("--popover"),
|
|
118
136
|
popoverForeground: read("--popover-foreground"),
|
|
119
137
|
}
|
|
138
|
+
tokenScopes.set(tokens, target)
|
|
139
|
+
return tokens
|
|
120
140
|
}
|
|
121
141
|
|
|
122
142
|
/** Structural equality, so a theme toggle that changes nothing doesn't re-init. */
|
|
@@ -124,8 +144,13 @@ function sameChartTokens(a: ChartTokens | null, b: ChartTokens | null): boolean
|
|
|
124
144
|
if (a === b) return true
|
|
125
145
|
if (!a || !b) return false
|
|
126
146
|
return (
|
|
147
|
+
tokenScopes.get(a) === tokenScopes.get(b) &&
|
|
148
|
+
a.surface === b.surface &&
|
|
149
|
+
Object.keys(a.colors ?? {}).length === Object.keys(b.colors ?? {}).length &&
|
|
150
|
+
Object.entries(a.colors ?? {}).every(([name, value]) => b.colors?.[name] === value) &&
|
|
127
151
|
a.series.length === b.series.length &&
|
|
128
152
|
a.series.every((color, i) => color === b.series[i]) &&
|
|
153
|
+
a.fontFamily === b.fontFamily &&
|
|
129
154
|
a.foreground === b.foreground &&
|
|
130
155
|
a.mutedForeground === b.mutedForeground &&
|
|
131
156
|
a.border === b.border &&
|
|
@@ -148,7 +173,7 @@ function sameChartTokens(a: ChartTokens | null, b: ChartTokens | null): boolean
|
|
|
148
173
|
* attributes alone leaves the chart painted in the previous palette until a
|
|
149
174
|
* reload — the tokens in the DOM are new, the canvas is not.
|
|
150
175
|
*/
|
|
151
|
-
function watchChartTokens(onChange: () => void): () => void {
|
|
176
|
+
function watchChartTokens(onChange: () => void, scope?: Element | null): () => void {
|
|
152
177
|
if (typeof document === "undefined") return () => {}
|
|
153
178
|
// Style edits arrive as bursts of mutations; coalesce them into one read, and
|
|
154
179
|
// take it after the next frame so a swapped stylesheet has been applied.
|
|
@@ -163,8 +188,11 @@ function watchChartTokens(onChange: () => void): () => void {
|
|
|
163
188
|
|
|
164
189
|
const themeObserver = new MutationObserver(schedule)
|
|
165
190
|
const attributeFilter = ["class", "style", "data-theme"]
|
|
166
|
-
|
|
167
|
-
|
|
191
|
+
// Only the chart and its ancestors can change its inherited theme. Never observe
|
|
192
|
+
// the document subtree: canvas/tooltip/rendering mutations would trigger every chart.
|
|
193
|
+
for (let node: Element | null = scope ?? document.body ?? document.documentElement; node; node = node.parentElement) {
|
|
194
|
+
themeObserver.observe(node, { attributes: true, attributeFilter })
|
|
195
|
+
}
|
|
168
196
|
|
|
169
197
|
const styleObserver = new MutationObserver(schedule)
|
|
170
198
|
if (document.head) {
|
|
@@ -220,7 +248,7 @@ function buildChartTheme(tokens: ChartTokens): Record<string, unknown> {
|
|
|
220
248
|
// Let the page background show through: charts sit on cards, not on a canvas.
|
|
221
249
|
backgroundColor: "transparent",
|
|
222
250
|
...(tokens.series.length > 0 ? { color: tokens.series } : {}),
|
|
223
|
-
textStyle: { color: text },
|
|
251
|
+
textStyle: { color: text, ...(tokens.fontFamily ? { fontFamily: tokens.fontFamily } : {}) },
|
|
224
252
|
title: { textStyle: { color: text }, subtextStyle: { color: muted } },
|
|
225
253
|
legend: { textStyle: { color: muted } },
|
|
226
254
|
categoryAxis: axisTheme(tokens, false),
|
|
@@ -236,7 +264,11 @@ function buildChartTheme(tokens: ChartTokens): Record<string, unknown> {
|
|
|
236
264
|
padding: [8, 12],
|
|
237
265
|
// Rounded card with a soft shadow; in dark mode the shadow barely shows, so the border carries the edge.
|
|
238
266
|
extraCssText: "border-radius:8px;box-shadow:var(--shadow-card, 0 4px 12px rgb(0 0 0 / 0.08));",
|
|
239
|
-
textStyle: {
|
|
267
|
+
textStyle: {
|
|
268
|
+
color: tokens.popoverForeground ?? undefined,
|
|
269
|
+
fontSize: 12,
|
|
270
|
+
...(tokens.fontFamily ? { fontFamily: tokens.fontFamily } : {}),
|
|
271
|
+
},
|
|
240
272
|
axisPointer: { lineStyle: { color: line }, crossStyle: { color: line } },
|
|
241
273
|
},
|
|
242
274
|
}
|
|
@@ -248,22 +280,23 @@ function buildChartTheme(tokens: ChartTokens): Record<string, unknown> {
|
|
|
248
280
|
* components that build an ECharts option from token colours themselves (the
|
|
249
281
|
* typed charts), so their palette follows light/dark like `EChart`'s theme.
|
|
250
282
|
*/
|
|
251
|
-
function useChartTokens(): ChartTokens | null {
|
|
283
|
+
function useChartTokens(scope?: Element | null | RefObject<Element | null>): ChartTokens | null {
|
|
252
284
|
const [tokens, setTokens] = useState<ChartTokens | null>(() => readChartTokens())
|
|
253
285
|
// Compared here, not inside a `setTokens` updater: an updater that reads the DOM is
|
|
254
286
|
// replayed by React on every rebase and returns a fresh object each time, so the state
|
|
255
287
|
// never settles ("Maximum update depth exceeded" once the tokens change after mount).
|
|
256
288
|
const tokensRef = useRef(tokens)
|
|
257
289
|
useEffect(() => {
|
|
290
|
+
const target = scope && "current" in scope ? scope.current : scope
|
|
258
291
|
const sync = () => {
|
|
259
|
-
const next = readChartTokens()
|
|
292
|
+
const next = readChartTokens(target)
|
|
260
293
|
if (sameChartTokens(tokensRef.current, next)) return
|
|
261
294
|
tokensRef.current = next
|
|
262
295
|
setTokens(next)
|
|
263
296
|
}
|
|
264
297
|
sync()
|
|
265
|
-
return watchChartTokens(sync)
|
|
266
|
-
}, [])
|
|
298
|
+
return watchChartTokens(sync, target)
|
|
299
|
+
}, [scope])
|
|
267
300
|
return tokens
|
|
268
301
|
}
|
|
269
302
|
|
|
@@ -275,7 +308,7 @@ const EMBEDDED_VAR_RE = /var\(\s*(--[\w-]+)\s*\)/g
|
|
|
275
308
|
/**
|
|
276
309
|
* Turn chart colours into canvas-safe strings. `"chart-1"`〜`"chart-5"` come from
|
|
277
310
|
* the resolved series tokens; `"positive"` / `"warning"` / `"negative"` / `"neutral"` (and the area
|
|
278
|
-
* variants `"positive-fill"`, …) are read
|
|
311
|
+
* variants `"positive-fill"`, …) are read in the snapshot's inherited scope (`--positive`, …); `var(--token)` uses the same scope; any
|
|
279
312
|
* other CSS colour is normalized like the tokens are. A colour that can't be
|
|
280
313
|
* resolved comes back as `""`, which ECharts treats as "use the palette".
|
|
281
314
|
*/
|
|
@@ -286,12 +319,13 @@ function resolveChartColors(colors: readonly string[], tokens: ChartTokens | nul
|
|
|
286
319
|
// Meaning colours are the theme tokens of the same name: same path as `var(--positive)`.
|
|
287
320
|
if (TONE_NAME_RE.test(color.trim())) {
|
|
288
321
|
if (typeof document === "undefined") return ""
|
|
289
|
-
|
|
322
|
+
const target = (tokens && tokenScopes.get(tokens)) ?? document.documentElement
|
|
323
|
+
return toCanvasColor(getComputedStyle(target).getPropertyValue(`--${color.trim()}`)) ?? ""
|
|
290
324
|
}
|
|
291
325
|
if (typeof document === "undefined") return color
|
|
292
326
|
let value = color.trim()
|
|
293
327
|
const cssVar = CSS_VAR_RE.exec(value)
|
|
294
|
-
const styles = getComputedStyle(document.documentElement)
|
|
328
|
+
const styles = getComputedStyle((tokens && tokenScopes.get(tokens)) ?? document.documentElement)
|
|
295
329
|
if (cssVar) {
|
|
296
330
|
value = styles.getPropertyValue(cssVar[1]!).trim() || (cssVar[2] ?? "").trim()
|
|
297
331
|
} else if (value.includes("var(")) {
|
|
@@ -337,7 +371,7 @@ function readChartSurface(el: Element | null): string | null {
|
|
|
337
371
|
if (color) return color
|
|
338
372
|
}
|
|
339
373
|
}
|
|
340
|
-
return toCanvasColor(getComputedStyle(document.documentElement).getPropertyValue("--background"))
|
|
374
|
+
return toCanvasColor(getComputedStyle(el ?? document.documentElement).getPropertyValue("--background"))
|
|
341
375
|
}
|
|
342
376
|
|
|
343
377
|
/** Widths are bucketed so a resize only rebuilds the option when the label budget can change. */
|
|
@@ -351,9 +385,10 @@ const WIDTH_BUCKET = 40
|
|
|
351
385
|
*/
|
|
352
386
|
function useChartSurface<E extends Element>(
|
|
353
387
|
forwarded: ForwardedRef<E>,
|
|
354
|
-
tokens
|
|
355
|
-
): { ref: (el: E | null) => void; surface: string | undefined; width: number | undefined } {
|
|
388
|
+
tokens?: ChartTokens | null,
|
|
389
|
+
): { ref: (el: E | null) => void; surface: string | undefined; width: number | undefined; tokens: ChartTokens | null } {
|
|
356
390
|
const [node, setNode] = useState<E | null>(null)
|
|
391
|
+
const scopedTokens = useChartTokens(node)
|
|
357
392
|
const [surface, setSurface] = useState<string | undefined>(undefined)
|
|
358
393
|
const [width, setWidth] = useState<number | undefined>(undefined)
|
|
359
394
|
const ref = useCallback(
|
|
@@ -367,7 +402,7 @@ function useChartSurface<E extends Element>(
|
|
|
367
402
|
useEffect(() => {
|
|
368
403
|
if (!node) return
|
|
369
404
|
setSurface(readChartSurface(node) ?? undefined)
|
|
370
|
-
}, [node, tokens])
|
|
405
|
+
}, [node, tokens, scopedTokens])
|
|
371
406
|
useEffect(() => {
|
|
372
407
|
if (!node || typeof ResizeObserver === "undefined") return
|
|
373
408
|
const update = (w: number) => setWidth(Math.floor(w / WIDTH_BUCKET) * WIDTH_BUCKET)
|
|
@@ -376,7 +411,7 @@ function useChartSurface<E extends Element>(
|
|
|
376
411
|
observer.observe(node)
|
|
377
412
|
return () => observer.disconnect()
|
|
378
413
|
}, [node])
|
|
379
|
-
return { ref, surface, width }
|
|
414
|
+
return { ref, surface, width, tokens: scopedTokens }
|
|
380
415
|
}
|
|
381
416
|
|
|
382
417
|
/* ---------- inlined from @squadbase/squadkit registry/lib/chart-utils.ts (internal to @squadbase/vantage) ---------- */
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// Copied by `vantage add ui chart-frame`. This file is yours to edit.
|
|
2
|
-
// Generated from @squadbase/squadkit registry/charts/chart-frame.tsx by `
|
|
2
|
+
// Generated from @squadbase/squadkit registry/charts/chart-frame.tsx by `pnpm run registry` (in Vantage, edit packages/squadkit, not registry/).
|
|
3
3
|
"use client"
|
|
4
4
|
|
|
5
5
|
/**
|
|
@@ -20,7 +20,7 @@ import { forwardRef, useId, type HTMLAttributes, type ReactNode } from "react"
|
|
|
20
20
|
|
|
21
21
|
import { cn } from "@squadbase/vantage/ui"
|
|
22
22
|
import type { ChartEmptyState } from "@squadbase/vantage/components"
|
|
23
|
-
import { createContext, useCallback, useEffect, useRef, useState, type ForwardedRef } from "react"
|
|
23
|
+
import { createContext, useCallback, useEffect, useRef, useState, type ForwardedRef, type RefObject } from "react"
|
|
24
24
|
import type { ChartTone } from "@squadbase/vantage/components"
|
|
25
25
|
import { DEFAULT_LOCALE, EMPTY_VALUE, formatValue, toValueFormatter, type ValueFormat } from "@squadbase/vantage/components"
|
|
26
26
|
import type { ChartColor, ChartColors, ChartSeriesColor, ValueFormatter } from "@squadbase/vantage/components"
|
|
@@ -49,6 +49,8 @@ const SERIES_TOKENS = ["--chart-1", "--chart-2", "--chart-3", "--chart-4", "--ch
|
|
|
49
49
|
interface ChartTokens {
|
|
50
50
|
/** Resolved `--chart-1..5`, in order. */
|
|
51
51
|
series: string[]
|
|
52
|
+
/** Computed `font-family` of the container, so canvas text matches the DOM. Optional. */
|
|
53
|
+
fontFamily?: string
|
|
52
54
|
/** Body text: titles and the default `textStyle`. */
|
|
53
55
|
foreground: string | null
|
|
54
56
|
/** Secondary text: axis labels, legend, subtitles. */
|
|
@@ -57,10 +59,23 @@ interface ChartTokens {
|
|
|
57
59
|
border: string | null
|
|
58
60
|
/** Tooltip surface. */
|
|
59
61
|
popover: string | null
|
|
62
|
+
/** Semantic and surface dependencies used by typed chart options. Optional for hand-built tokens. */
|
|
63
|
+
colors?: Record<string, string>
|
|
64
|
+
/** Actual inherited painting surface (may change without a token changing). */
|
|
65
|
+
surface?: string | null
|
|
60
66
|
/** Tooltip text. */
|
|
61
67
|
popoverForeground: string | null
|
|
62
68
|
}
|
|
63
69
|
|
|
70
|
+
// Keep scope out of the public token shape. A resolved snapshot remembers where arbitrary
|
|
71
|
+
// var(--token) expressions must be read, without retaining unmounted charts globally.
|
|
72
|
+
const tokenScopes = new WeakMap<ChartTokens, Element>()
|
|
73
|
+
const OPTION_COLOR_TOKENS = [
|
|
74
|
+
"--background", "--card", "--muted", "--primary", "--destructive",
|
|
75
|
+
...["positive", "negative", "warning", "neutral", "info"].flatMap((tone) =>
|
|
76
|
+
["", "-fill", "-subtle"].map((suffix) => `--${tone}${suffix}`)),
|
|
77
|
+
]
|
|
78
|
+
|
|
64
79
|
let normalizeContext: CanvasRenderingContext2D | null | undefined
|
|
65
80
|
|
|
66
81
|
/** The forms `fillStyle` serializes legacy colours to, and zrender can parse. */
|
|
@@ -116,14 +131,19 @@ function readChartTokens(el?: Element | null): ChartTokens | null {
|
|
|
116
131
|
const color = read(token)
|
|
117
132
|
if (color) series.push(color)
|
|
118
133
|
}
|
|
119
|
-
|
|
134
|
+
const tokens: ChartTokens = {
|
|
120
135
|
series,
|
|
136
|
+
colors: Object.fromEntries(OPTION_COLOR_TOKENS.map((name) => [name, styles.getPropertyValue(name).trim()])),
|
|
137
|
+
surface: readChartSurface(target),
|
|
138
|
+
...(styles.fontFamily ? { fontFamily: styles.fontFamily } : {}),
|
|
121
139
|
foreground: read("--foreground"),
|
|
122
140
|
mutedForeground: read("--muted-foreground"),
|
|
123
141
|
border: read("--border"),
|
|
124
142
|
popover: read("--popover"),
|
|
125
143
|
popoverForeground: read("--popover-foreground"),
|
|
126
144
|
}
|
|
145
|
+
tokenScopes.set(tokens, target)
|
|
146
|
+
return tokens
|
|
127
147
|
}
|
|
128
148
|
|
|
129
149
|
/** Structural equality, so a theme toggle that changes nothing doesn't re-init. */
|
|
@@ -131,8 +151,13 @@ function sameChartTokens(a: ChartTokens | null, b: ChartTokens | null): boolean
|
|
|
131
151
|
if (a === b) return true
|
|
132
152
|
if (!a || !b) return false
|
|
133
153
|
return (
|
|
154
|
+
tokenScopes.get(a) === tokenScopes.get(b) &&
|
|
155
|
+
a.surface === b.surface &&
|
|
156
|
+
Object.keys(a.colors ?? {}).length === Object.keys(b.colors ?? {}).length &&
|
|
157
|
+
Object.entries(a.colors ?? {}).every(([name, value]) => b.colors?.[name] === value) &&
|
|
134
158
|
a.series.length === b.series.length &&
|
|
135
159
|
a.series.every((color, i) => color === b.series[i]) &&
|
|
160
|
+
a.fontFamily === b.fontFamily &&
|
|
136
161
|
a.foreground === b.foreground &&
|
|
137
162
|
a.mutedForeground === b.mutedForeground &&
|
|
138
163
|
a.border === b.border &&
|
|
@@ -155,7 +180,7 @@ function sameChartTokens(a: ChartTokens | null, b: ChartTokens | null): boolean
|
|
|
155
180
|
* attributes alone leaves the chart painted in the previous palette until a
|
|
156
181
|
* reload — the tokens in the DOM are new, the canvas is not.
|
|
157
182
|
*/
|
|
158
|
-
function watchChartTokens(onChange: () => void): () => void {
|
|
183
|
+
function watchChartTokens(onChange: () => void, scope?: Element | null): () => void {
|
|
159
184
|
if (typeof document === "undefined") return () => {}
|
|
160
185
|
// Style edits arrive as bursts of mutations; coalesce them into one read, and
|
|
161
186
|
// take it after the next frame so a swapped stylesheet has been applied.
|
|
@@ -170,8 +195,11 @@ function watchChartTokens(onChange: () => void): () => void {
|
|
|
170
195
|
|
|
171
196
|
const themeObserver = new MutationObserver(schedule)
|
|
172
197
|
const attributeFilter = ["class", "style", "data-theme"]
|
|
173
|
-
|
|
174
|
-
|
|
198
|
+
// Only the chart and its ancestors can change its inherited theme. Never observe
|
|
199
|
+
// the document subtree: canvas/tooltip/rendering mutations would trigger every chart.
|
|
200
|
+
for (let node: Element | null = scope ?? document.body ?? document.documentElement; node; node = node.parentElement) {
|
|
201
|
+
themeObserver.observe(node, { attributes: true, attributeFilter })
|
|
202
|
+
}
|
|
175
203
|
|
|
176
204
|
const styleObserver = new MutationObserver(schedule)
|
|
177
205
|
if (document.head) {
|
|
@@ -227,7 +255,7 @@ function buildChartTheme(tokens: ChartTokens): Record<string, unknown> {
|
|
|
227
255
|
// Let the page background show through: charts sit on cards, not on a canvas.
|
|
228
256
|
backgroundColor: "transparent",
|
|
229
257
|
...(tokens.series.length > 0 ? { color: tokens.series } : {}),
|
|
230
|
-
textStyle: { color: text },
|
|
258
|
+
textStyle: { color: text, ...(tokens.fontFamily ? { fontFamily: tokens.fontFamily } : {}) },
|
|
231
259
|
title: { textStyle: { color: text }, subtextStyle: { color: muted } },
|
|
232
260
|
legend: { textStyle: { color: muted } },
|
|
233
261
|
categoryAxis: axisTheme(tokens, false),
|
|
@@ -243,7 +271,11 @@ function buildChartTheme(tokens: ChartTokens): Record<string, unknown> {
|
|
|
243
271
|
padding: [8, 12],
|
|
244
272
|
// Rounded card with a soft shadow; in dark mode the shadow barely shows, so the border carries the edge.
|
|
245
273
|
extraCssText: "border-radius:8px;box-shadow:var(--shadow-card, 0 4px 12px rgb(0 0 0 / 0.08));",
|
|
246
|
-
textStyle: {
|
|
274
|
+
textStyle: {
|
|
275
|
+
color: tokens.popoverForeground ?? undefined,
|
|
276
|
+
fontSize: 12,
|
|
277
|
+
...(tokens.fontFamily ? { fontFamily: tokens.fontFamily } : {}),
|
|
278
|
+
},
|
|
247
279
|
axisPointer: { lineStyle: { color: line }, crossStyle: { color: line } },
|
|
248
280
|
},
|
|
249
281
|
}
|
|
@@ -255,22 +287,23 @@ function buildChartTheme(tokens: ChartTokens): Record<string, unknown> {
|
|
|
255
287
|
* components that build an ECharts option from token colours themselves (the
|
|
256
288
|
* typed charts), so their palette follows light/dark like `EChart`'s theme.
|
|
257
289
|
*/
|
|
258
|
-
function useChartTokens(): ChartTokens | null {
|
|
290
|
+
function useChartTokens(scope?: Element | null | RefObject<Element | null>): ChartTokens | null {
|
|
259
291
|
const [tokens, setTokens] = useState<ChartTokens | null>(() => readChartTokens())
|
|
260
292
|
// Compared here, not inside a `setTokens` updater: an updater that reads the DOM is
|
|
261
293
|
// replayed by React on every rebase and returns a fresh object each time, so the state
|
|
262
294
|
// never settles ("Maximum update depth exceeded" once the tokens change after mount).
|
|
263
295
|
const tokensRef = useRef(tokens)
|
|
264
296
|
useEffect(() => {
|
|
297
|
+
const target = scope && "current" in scope ? scope.current : scope
|
|
265
298
|
const sync = () => {
|
|
266
|
-
const next = readChartTokens()
|
|
299
|
+
const next = readChartTokens(target)
|
|
267
300
|
if (sameChartTokens(tokensRef.current, next)) return
|
|
268
301
|
tokensRef.current = next
|
|
269
302
|
setTokens(next)
|
|
270
303
|
}
|
|
271
304
|
sync()
|
|
272
|
-
return watchChartTokens(sync)
|
|
273
|
-
}, [])
|
|
305
|
+
return watchChartTokens(sync, target)
|
|
306
|
+
}, [scope])
|
|
274
307
|
return tokens
|
|
275
308
|
}
|
|
276
309
|
|
|
@@ -282,7 +315,7 @@ const EMBEDDED_VAR_RE = /var\(\s*(--[\w-]+)\s*\)/g
|
|
|
282
315
|
/**
|
|
283
316
|
* Turn chart colours into canvas-safe strings. `"chart-1"`〜`"chart-5"` come from
|
|
284
317
|
* the resolved series tokens; `"positive"` / `"warning"` / `"negative"` / `"neutral"` (and the area
|
|
285
|
-
* variants `"positive-fill"`, …) are read
|
|
318
|
+
* variants `"positive-fill"`, …) are read in the snapshot's inherited scope (`--positive`, …); `var(--token)` uses the same scope; any
|
|
286
319
|
* other CSS colour is normalized like the tokens are. A colour that can't be
|
|
287
320
|
* resolved comes back as `""`, which ECharts treats as "use the palette".
|
|
288
321
|
*/
|
|
@@ -293,12 +326,13 @@ function resolveChartColors(colors: readonly string[], tokens: ChartTokens | nul
|
|
|
293
326
|
// Meaning colours are the theme tokens of the same name: same path as `var(--positive)`.
|
|
294
327
|
if (TONE_NAME_RE.test(color.trim())) {
|
|
295
328
|
if (typeof document === "undefined") return ""
|
|
296
|
-
|
|
329
|
+
const target = (tokens && tokenScopes.get(tokens)) ?? document.documentElement
|
|
330
|
+
return toCanvasColor(getComputedStyle(target).getPropertyValue(`--${color.trim()}`)) ?? ""
|
|
297
331
|
}
|
|
298
332
|
if (typeof document === "undefined") return color
|
|
299
333
|
let value = color.trim()
|
|
300
334
|
const cssVar = CSS_VAR_RE.exec(value)
|
|
301
|
-
const styles = getComputedStyle(document.documentElement)
|
|
335
|
+
const styles = getComputedStyle((tokens && tokenScopes.get(tokens)) ?? document.documentElement)
|
|
302
336
|
if (cssVar) {
|
|
303
337
|
value = styles.getPropertyValue(cssVar[1]!).trim() || (cssVar[2] ?? "").trim()
|
|
304
338
|
} else if (value.includes("var(")) {
|
|
@@ -344,7 +378,7 @@ function readChartSurface(el: Element | null): string | null {
|
|
|
344
378
|
if (color) return color
|
|
345
379
|
}
|
|
346
380
|
}
|
|
347
|
-
return toCanvasColor(getComputedStyle(document.documentElement).getPropertyValue("--background"))
|
|
381
|
+
return toCanvasColor(getComputedStyle(el ?? document.documentElement).getPropertyValue("--background"))
|
|
348
382
|
}
|
|
349
383
|
|
|
350
384
|
/** Widths are bucketed so a resize only rebuilds the option when the label budget can change. */
|
|
@@ -358,9 +392,10 @@ const WIDTH_BUCKET = 40
|
|
|
358
392
|
*/
|
|
359
393
|
function useChartSurface<E extends Element>(
|
|
360
394
|
forwarded: ForwardedRef<E>,
|
|
361
|
-
tokens
|
|
362
|
-
): { ref: (el: E | null) => void; surface: string | undefined; width: number | undefined } {
|
|
395
|
+
tokens?: ChartTokens | null,
|
|
396
|
+
): { ref: (el: E | null) => void; surface: string | undefined; width: number | undefined; tokens: ChartTokens | null } {
|
|
363
397
|
const [node, setNode] = useState<E | null>(null)
|
|
398
|
+
const scopedTokens = useChartTokens(node)
|
|
364
399
|
const [surface, setSurface] = useState<string | undefined>(undefined)
|
|
365
400
|
const [width, setWidth] = useState<number | undefined>(undefined)
|
|
366
401
|
const ref = useCallback(
|
|
@@ -374,7 +409,7 @@ function useChartSurface<E extends Element>(
|
|
|
374
409
|
useEffect(() => {
|
|
375
410
|
if (!node) return
|
|
376
411
|
setSurface(readChartSurface(node) ?? undefined)
|
|
377
|
-
}, [node, tokens])
|
|
412
|
+
}, [node, tokens, scopedTokens])
|
|
378
413
|
useEffect(() => {
|
|
379
414
|
if (!node || typeof ResizeObserver === "undefined") return
|
|
380
415
|
const update = (w: number) => setWidth(Math.floor(w / WIDTH_BUCKET) * WIDTH_BUCKET)
|
|
@@ -383,7 +418,7 @@ function useChartSurface<E extends Element>(
|
|
|
383
418
|
observer.observe(node)
|
|
384
419
|
return () => observer.disconnect()
|
|
385
420
|
}, [node])
|
|
386
|
-
return { ref, surface, width }
|
|
421
|
+
return { ref, surface, width, tokens: scopedTokens }
|
|
387
422
|
}
|
|
388
423
|
|
|
389
424
|
/* ---------- inlined from @squadbase/squadkit registry/lib/chart-utils.ts (internal to @squadbase/vantage) ---------- */
|
|
@@ -1219,12 +1254,12 @@ export const ChartFrame = forwardRef<HTMLDivElement, ChartFrameProps>(function C
|
|
|
1219
1254
|
{(title || summary) && (
|
|
1220
1255
|
<figcaption data-slot="chart-frame-header" className="flex flex-col gap-1">
|
|
1221
1256
|
{title && (
|
|
1222
|
-
<h3 id={titleId} data-slot="chart-frame-title" className="text-sm leading-
|
|
1257
|
+
<h3 id={titleId} data-slot="chart-frame-title" className="text-sm leading-snug font-semibold">
|
|
1223
1258
|
{title}
|
|
1224
1259
|
</h3>
|
|
1225
1260
|
)}
|
|
1226
1261
|
{summary && (
|
|
1227
|
-
<p id={summaryId} data-slot="chart-frame-summary" className="text-sm text-muted-foreground">
|
|
1262
|
+
<p id={summaryId} data-slot="chart-frame-summary" className="text-sm leading-relaxed text-muted-foreground">
|
|
1228
1263
|
{summary}
|
|
1229
1264
|
</p>
|
|
1230
1265
|
)}
|
package/registry/ui/checkbox.tsx
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// Copied by `vantage add ui checkbox`. This file is yours to edit.
|
|
2
|
-
// Generated from @squadbase/squadkit registry/ui/checkbox.tsx by `
|
|
2
|
+
// Generated from @squadbase/squadkit registry/ui/checkbox.tsx by `pnpm run registry` (in Vantage, edit packages/squadkit, not registry/).
|
|
3
3
|
"use client"
|
|
4
4
|
|
|
5
5
|
import { Checkbox as CheckboxPrimitive } from "@base-ui/react/checkbox"
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// Copied by `vantage add ui collapsible`. This file is yours to edit.
|
|
2
|
-
// Generated from @squadbase/squadkit registry/ui/collapsible.tsx by `
|
|
2
|
+
// Generated from @squadbase/squadkit registry/ui/collapsible.tsx by `pnpm run registry` (in Vantage, edit packages/squadkit, not registry/).
|
|
3
3
|
"use client"
|
|
4
4
|
|
|
5
5
|
import { Collapsible as CollapsiblePrimitive } from "@base-ui/react/collapsible"
|
package/registry/ui/combobox.tsx
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// Copied by `vantage add ui combobox`. This file is yours to edit.
|
|
2
|
-
// Generated from @squadbase/squadkit registry/ui/combobox.tsx by `
|
|
2
|
+
// Generated from @squadbase/squadkit registry/ui/combobox.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"
|
package/registry/ui/command.tsx
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// Copied by `vantage add ui command`. This file is yours to edit.
|
|
2
|
-
// Generated from @squadbase/squadkit registry/ui/command.tsx by `
|
|
2
|
+
// Generated from @squadbase/squadkit registry/ui/command.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 dashboard-card`. This file is yours to edit.
|
|
2
|
-
// Generated from @squadbase/squadkit registry/components/dashboard-card.tsx by `
|
|
2
|
+
// Generated from @squadbase/squadkit registry/components/dashboard-card.tsx by `pnpm run registry` (in Vantage, edit packages/squadkit, not registry/).
|
|
3
3
|
"use client"
|
|
4
4
|
|
|
5
5
|
/**
|
|
@@ -33,8 +33,8 @@ export interface DashboardCardProps extends HTMLAttributes<HTMLDivElement> {
|
|
|
33
33
|
}
|
|
34
34
|
|
|
35
35
|
const SUBGRID_CLASS = {
|
|
36
|
-
2: "row-span-2 grid content-start grid-rows-subgrid",
|
|
37
|
-
3: "row-span-3 grid content-start grid-rows-subgrid",
|
|
36
|
+
2: "row-span-2 grid min-w-0 grid-cols-1 content-start grid-rows-subgrid",
|
|
37
|
+
3: "row-span-3 grid min-w-0 grid-cols-1 content-start grid-rows-subgrid",
|
|
38
38
|
} as const
|
|
39
39
|
|
|
40
40
|
export const DashboardCard = forwardRef<HTMLDivElement, DashboardCardProps>(
|
|
@@ -75,7 +75,7 @@ export const DashboardCardTitle = forwardRef<HTMLHeadingElement, DashboardCardTi
|
|
|
75
75
|
<h3
|
|
76
76
|
ref={ref}
|
|
77
77
|
data-slot="dashboard-card-title"
|
|
78
|
-
className={cn("text-sm leading-
|
|
78
|
+
className={cn("text-sm leading-snug font-semibold tracking-tight", className)}
|
|
79
79
|
{...props}
|
|
80
80
|
/>
|
|
81
81
|
),
|
|
@@ -91,7 +91,7 @@ export const DashboardCardDescription = forwardRef<
|
|
|
91
91
|
<p
|
|
92
92
|
ref={ref}
|
|
93
93
|
data-slot="dashboard-card-description"
|
|
94
|
-
className={cn("text-xs text-muted-foreground", className)}
|
|
94
|
+
className={cn("text-xs leading-normal text-muted-foreground", className)}
|
|
95
95
|
{...props}
|
|
96
96
|
/>
|
|
97
97
|
))
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// Copied by `vantage add ui data-table`. This file is yours to edit.
|
|
2
|
-
// Generated from @squadbase/squadkit registry/components/data-table.tsx by `
|
|
2
|
+
// Generated from @squadbase/squadkit registry/components/data-table.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 date-range-picker`. This file is yours to edit.
|
|
2
|
-
// Generated from @squadbase/squadkit registry/components/date-range-picker.tsx by `
|
|
2
|
+
// Generated from @squadbase/squadkit registry/components/date-range-picker.tsx by `pnpm run registry` (in Vantage, edit packages/squadkit, not registry/).
|
|
3
3
|
"use client"
|
|
4
4
|
|
|
5
5
|
/**
|
package/registry/ui/delta.tsx
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// Copied by `vantage add ui delta`. This file is yours to edit.
|
|
2
|
-
// Generated from @squadbase/squadkit registry/components/delta.tsx by `
|
|
2
|
+
// Generated from @squadbase/squadkit registry/components/delta.tsx by `pnpm run registry` (in Vantage, edit packages/squadkit, not registry/).
|
|
3
3
|
"use client"
|
|
4
4
|
|
|
5
5
|
/**
|
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
* Direction, rate, colour and wording are all derived here from `value` and
|
|
10
10
|
* `comparison` (via `computeComparison`); none of them can be passed in, so they
|
|
11
11
|
* cannot contradict each other. Colour is never the only signal: the arrow and
|
|
12
|
-
* the sign always accompany it. Set `
|
|
12
|
+
* the sign always accompany it. Set `betterWhen="down"` for metrics
|
|
13
13
|
* where a rise is bad (churn, error rate).
|
|
14
14
|
*
|
|
15
15
|
* - A flat change (inside `neutralBand`) uses a right arrow (→), never a minus-like dash, so it cannot
|
|
@@ -31,7 +31,7 @@
|
|
|
31
31
|
* // Vantage: import { Delta } from "@squadbase/vantage/components"
|
|
32
32
|
*
|
|
33
33
|
* <Delta value={48_200_000} comparison={{ previous: 42_900_000, vs: "prior-period", grain: "month" }} />
|
|
34
|
-
* <Delta value={0.021} format="percent"
|
|
34
|
+
* <Delta value={0.021} format="percent" betterWhen="down"
|
|
35
35
|
* comparison={{ previous: 0.026, vs: "prior-year", grain: "month" }} />
|
|
36
36
|
*/
|
|
37
37
|
import { forwardRef, type HTMLAttributes } from "react"
|
|
@@ -56,7 +56,7 @@ const deltaVariants = cva(
|
|
|
56
56
|
{
|
|
57
57
|
variants: {
|
|
58
58
|
variant: {
|
|
59
|
-
badge: "h-5 rounded-
|
|
59
|
+
badge: "h-5 rounded-md border px-2 py-0.5 text-xs font-medium [&>svg]:size-3",
|
|
60
60
|
inline: "text-sm [&>svg]:size-3.5",
|
|
61
61
|
},
|
|
62
62
|
sentiment: {
|
|
@@ -66,9 +66,9 @@ const deltaVariants = cva(
|
|
|
66
66
|
},
|
|
67
67
|
},
|
|
68
68
|
compoundVariants: [
|
|
69
|
-
{ variant: "badge", sentiment: "positive", className: "bg-positive-subtle" },
|
|
70
|
-
{ variant: "badge", sentiment: "negative", className: "bg-negative-subtle" },
|
|
71
|
-
{ variant: "badge", sentiment: "neutral", className: "bg-neutral-subtle" },
|
|
69
|
+
{ variant: "badge", sentiment: "positive", className: "border-positive/20 bg-positive-subtle dark:border-positive/25" },
|
|
70
|
+
{ variant: "badge", sentiment: "negative", className: "border-negative/20 bg-negative-subtle dark:border-negative/25" },
|
|
71
|
+
{ variant: "badge", sentiment: "neutral", className: "border-neutral/20 bg-neutral-subtle dark:border-neutral/25" },
|
|
72
72
|
],
|
|
73
73
|
defaultVariants: {
|
|
74
74
|
variant: "badge",
|
|
@@ -85,7 +85,9 @@ export interface DeltaProps
|
|
|
85
85
|
value: number | null | undefined
|
|
86
86
|
/** What the value is compared against. Required so the delta always carries its label. */
|
|
87
87
|
comparison: Comparison
|
|
88
|
-
/**
|
|
88
|
+
/** Which direction is good: `"up"` (default) or `"down"` (churn, error rate). Wins over `polarity`. */
|
|
89
|
+
betterWhen?: "up" | "down"
|
|
90
|
+
/** @deprecated Older name of `betterWhen` (`"higher-is-better"` / `"lower-is-better"`); `"neutral"` is only reachable here. `betterWhen` wins if both are given. */
|
|
89
91
|
polarity?: Polarity
|
|
90
92
|
/** Absolute ratio below which the change reads as flat (0.01 = 1%). Default 0.01. */
|
|
91
93
|
neutralBand?: number
|
|
@@ -134,6 +136,7 @@ export const Delta = forwardRef<HTMLSpanElement, DeltaProps>(
|
|
|
134
136
|
{
|
|
135
137
|
value,
|
|
136
138
|
comparison,
|
|
139
|
+
betterWhen,
|
|
137
140
|
polarity,
|
|
138
141
|
neutralBand,
|
|
139
142
|
format,
|
|
@@ -149,7 +152,7 @@ export const Delta = forwardRef<HTMLSpanElement, DeltaProps>(
|
|
|
149
152
|
) => {
|
|
150
153
|
// Nothing to compare against yet (a draft fills props in steps).
|
|
151
154
|
if (!comparison) return null
|
|
152
|
-
const result = computeComparison(value, comparison, { polarity, neutralBand })
|
|
155
|
+
const result = computeComparison(value, comparison, { polarity: betterWhen ? (betterWhen === "down" ? "lower-is-better" : "higher-is-better") : polarity, neutralBand })
|
|
153
156
|
const display = change ?? defaultChangeDisplay(format)
|
|
154
157
|
const formatDigits = typeof format === "object" && format !== null && "digits" in format ? format.digits : undefined
|
|
155
158
|
const changeDigits = display === "points" ? (digits ?? formatDigits) : digits
|