@flesler/cursor-canvas-web 1.0.2 → 1.1.0

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 (33) hide show
  1. package/README.md +9 -8
  2. package/dist/cursor-canvas.cjs +1 -1
  3. package/dist/cursor-canvas.js +571 -764
  4. package/dist/host-tokens-Cjzmp0z_.cjs +1 -0
  5. package/dist/host-tokens-Dh2BFFjv.js +412 -0
  6. package/dist/runtime/index.d.ts +5 -7
  7. package/dist/runtime.cjs +1 -1
  8. package/dist/runtime.js +101 -14
  9. package/package.json +21 -13
  10. package/src/vendor/canvas/SKILL.md +113 -0
  11. package/src/vendor/canvas-sdk/callout-tone-icons.d.ts +10 -0
  12. package/src/vendor/canvas-sdk/canvas-tokens.d.ts +259 -0
  13. package/src/vendor/canvas-sdk/chart-primitives.d.ts +272 -0
  14. package/src/vendor/canvas-sdk/collapsible-section.d.ts +66 -0
  15. package/src/vendor/canvas-sdk/dag-layout.d.ts +101 -0
  16. package/src/vendor/canvas-sdk/diff-view.d.ts +129 -0
  17. package/src/vendor/canvas-sdk/form-primitives.d.ts +194 -0
  18. package/src/vendor/canvas-sdk/hooks.d.ts +173 -0
  19. package/src/vendor/canvas-sdk/index.d.ts +65 -0
  20. package/src/vendor/canvas-sdk/internal/canvas-action-dispatch.d.ts +17 -0
  21. package/src/vendor/canvas-sdk/manifest.json +5 -0
  22. package/src/vendor/canvas-sdk/swatch.d.ts +39 -0
  23. package/src/vendor/canvas-sdk/theme.d.ts +107 -0
  24. package/src/vendor/canvas-sdk/todo-list.d.ts +48 -0
  25. package/src/vendor/canvas-sdk/ui-primitives.d.ts +569 -0
  26. package/src/vendor/canvas-sdk/usage-bar.d.ts +55 -0
  27. package/dist/shim/charts.d.ts +0 -66
  28. package/dist/shim/cursor-canvas.d.ts +0 -278
  29. package/dist/shim/dag.d.ts +0 -55
  30. package/dist/shim/diff.d.ts +0 -23
  31. package/dist/shim/theme.d.ts +0 -323
  32. package/dist/shim/todo.d.ts +0 -22
  33. package/dist/shim/use-tokens.d.ts +0 -6
@@ -0,0 +1,113 @@
1
+ ---
2
+ name: canvas
3
+ description: >-
4
+ A Cursor Canvas is a live React app that the user can open beside the chat.
5
+ You MUST use a canvas when the agent produces a standalone analytical artifact
6
+ — quantitative analyses, billing investigations, security audits, architecture
7
+ reviews, data-heavy content, timelines, charts, tables, interactive
8
+ explorations, repeatable tools, or any response that benefits from visual
9
+ layout. Especially prefer a canvas when presenting results from MCP tools
10
+ (Datadog, Databricks, Linear, Sentry, Slack, etc.) where the data is the
11
+ deliverable — render it in a rich canvas rather than dumping it into a
12
+ markdown table or code block. If you catch yourself about to write a markdown
13
+ table, stop and use a canvas instead. You MUST also read this skill whenever
14
+ you create, edit, or debug any .canvas.tsx file.
15
+ metadata:
16
+ surfaces:
17
+ - ide
18
+ - cloud
19
+ environments:
20
+ - local
21
+ - cloud
22
+ ---
23
+ A canvas is a single `.canvas.tsx` file the IDE compiles so the user can open it beside the chat. Follow the workflow below in order.
24
+
25
+ ## Workflow
26
+
27
+ ### 1. Decide whether to use a canvas
28
+
29
+ The trigger is **user intent**, not response shape. Ask: would the user benefit from viewing this output as its **own durable standalone artifact outside the transcript**, separate from the chat? If the output is a means to an end (a drafted message, a code fix, a dashboard in another tool), skip the canvas.
30
+
31
+ **Use a canvas when the agent produces new standalone analytical output:**
32
+ - Quantitative analyses and metrics breakdowns (e.g. "send 500 requests and tell me how many fail")
33
+ - Billing or account investigations that surface structured findings from database queries
34
+ - Security audits or architecture reviews with categorized findings
35
+ - Cross-system data analyses and overlap reports
36
+ - Structured data from MCP tools (Databricks, Datadog, etc.) where a durable standalone artifact is the deliverable
37
+ - Financial analyses, margin decompositions, usage trend reports
38
+ - Large tables the user wants to revisit or refine
39
+
40
+ **Do NOT use a canvas when:**
41
+ - The user asks for work in a **specific tool** — "create a Datadog dashboard" means give them a Datadog dashboard, not a canvas
42
+ - The user has a **specific deliverable** — "draft a support response", "fix this code", "make this PR"
43
+ - The user is **working within an existing artifact** — improving an HTML dashboard, editing an existing file
44
+ - The user is doing **targeted debugging** or active development, even if structured findings emerge along the way
45
+ - An immutable visual output belongs inside the transcript rather than in a durable standalone artifact
46
+ - Short factual answers, one-off file edits, or quick clarifying questions
47
+ - MCP tools are queried as an **intermediate step** for a different deliverable (e.g. querying Stripe to draft a support reply)
48
+
49
+ ### 2. Write the canvas
50
+
51
+ **Location.** Canvases live at `/Users/<user>/.cursor/projects/<workspace>/canvases/<name>.canvas.tsx`. The IDE only detects canvases written directly inside that exact directory — subfolders, alternate extensions, and other locations are not picked up. For a new canvas, always use the write file tool to create the `.canvas.tsx` file at that exact path; do not stop after telling the user the path or showing code in chat. Treat that managed `canvases/` directory as pre-provisioned by Cursor itself: write the canvas file directly there and do **not** spend turns creating the directory with `mkdir` or checking whether it exists before writing. Listing its contents for other purposes (e.g. checking for existing canvases) is fine. If you can't determine the workspace directory from absolute paths already in your environment (terminals, transcripts, recently-viewed files), list `~/.cursor/projects/` rather than guessing. Use a descriptive kebab-case filename ending in `.canvas.tsx`; preserve acronym capitalization and lowercase the rest.
52
+
53
+ **File rules:**
54
+ - Exactly one `.canvas.tsx` file per canvas. Never create helper files, style files, or supporting modules.
55
+ - Import **only** from `cursor/canvas`. No relative imports, no npm packages, no Node built-ins.
56
+ - Default-export the top-level component.
57
+ - Embed all data inline. **No `fetch()`, no network calls.**
58
+
59
+ **Never render empty states.** A canvas exists to show real content. If a section, chart, table, or component has no data to display, **omit it** — do not render it with placeholder text ("Add header here", "TODO", "Example"), a "No data" message, an empty array, zeroed rows, or an empty chart frame. If the entire canvas would be empty because you don't have the underlying data, do not produce a canvas — tell the user what's missing and ask for it instead.
60
+
61
+ **Label every plot.** Charts and tables must be self-describing — a reader looking at the canvas alone should know exactly what they're seeing. For every plot include:
62
+ - A title naming the **specific metric** (not "Metrics" — "API error rate by service").
63
+ - **Axis labels with units** on both axes (e.g. "Date", "Latency (ms)").
64
+ - A **legend** when more than one series is shown, with the exact series names from the source data.
65
+ - The **source and time range** in a small caption (e.g. "Source: Datadog · last 7 days"). If a value is a transformation (mean, p95, normalized, smoothed), say so in the label.
66
+
67
+ **Component discovery:** prefer built-in `cursor/canvas` components over hand-rolled markup. The full public surface (components, hooks, prop types, tokens) is declared in `~/.cursor/skills-cursor/canvas/sdk/index.d.ts` and its sibling `.d.ts` files — read them when you need exact exports, prop shapes, or hook signatures rather than guessing. Referencing an export that does not exist is the most common runtime error.
68
+
69
+ Apply the Design guidance below as you write, and complete its Pre-delivery self-check before returning the canvas.
70
+
71
+ ## Design guidance
72
+
73
+ Be creative. The SDK gives you expressive building blocks — use them in whatever combination best serves the content. But avoid slop: no gradients, no emojis, no box-shadows, no rainbow coloring. Cursor canvases are flat, minimal, and purposeful.
74
+
75
+ ### Visual hierarchy
76
+
77
+ Not everything deserves equal treatment. Primary content gets more space, larger headings, and accent color. Supporting content stays compact. Squint test: blur your eyes — can you tell what matters?
78
+
79
+ **Color.** All colors from `useHostTheme()` tokens — read its JSDoc in the SDK declarations for the return shape and usage pattern. No hardcoded hex. Use accent color deliberately, not on everything.
80
+
81
+ ### Slop patterns — forbidden
82
+
83
+ These specific patterns produce low-quality output. If 2+ are present, redesign.
84
+
85
+ - **Gradients** — no `linear-gradient`, `radial-gradient`, `background-clip: text`.
86
+ - **Emojis** — no emoji as icons, status indicators, bullets, or section markers.
87
+ - **Box shadows** — no `box-shadow`. Flat surfaces only.
88
+ - **Wall of identical cards** — every section wrapped in the same card style with no variation. Mix open sections with cards.
89
+ - **Rainbow coloring** — a different color on every element. Most elements are neutral; color is used sparingly with purpose.
90
+ - **Giant text** — font sizes above H1 (24px), or bold text stuffed in CardHeader.
91
+ - **Decorative borders** — colored borders on every element. Borders are structural (subtle stroke tokens), not decorative.
92
+
93
+ ### Pre-delivery self-check
94
+
95
+ Before returning canvas code, verify:
96
+ 1. Does the layout have visual hierarchy? One thing should stand out.
97
+ 2. Is there variety in the composition? Not just a single column of uniform blocks.
98
+ 3. Slop check: scan for the forbidden patterns above.
99
+
100
+ ## Introducing the canvas
101
+
102
+ Whenever you mention a canvas to the user — one you created, updated, or want them to open — **always** include a markdown link to that `.canvas.tsx` file using its full absolute path (for example, `[Billing Review](/Users/<user>/.cursor/projects/<workspace>/canvases/billing-review.canvas.tsx)`). Use a short descriptive label as the link text; do not refer to a canvas by name or path alone without the link.
103
+
104
+ When you create a canvas, add a short note in your chat response telling the user they can open it beside the chat, with that link:
105
+
106
+ - **First canvas** — if no other `.canvas.tsx` files exist in the workspace's `canvases/` directory, include one sentence explaining what a canvas is.
107
+ - **Unsolicited canvas** — if the user didn't ask for a canvas, include one sentence explaining why you chose it over plain text.
108
+
109
+ Both can apply at once; one or two sentences total is enough. Skip the intro for subsequent canvases unless you are mentioning that canvas again (still link it).
110
+
111
+ ## Troubleshooting
112
+
113
+ If a canvas appears blank or missing, the most common cause is that it was not written under `/Users/<user>/.cursor/projects/<workspace>/canvases/` exactly — re-save it to that path. Do not debug this by trying to create the managed directory manually; focus on correcting the file path instead. Users can click the canvas file path in the response to open it, just like any other file path in Cursor. Every canvas edit returns a `Canvas TypeScript check` line in the tool result reporting the file's current type errors (or "no errors") — treat that as the authoritative diagnostics signal.
@@ -0,0 +1,10 @@
1
+ import type { JSX } from "react";
2
+ type CalloutToneIconGlyph = "info" | "warning" | "circles-check" | "exclamation-circle";
3
+ type CalloutToneForIcon = "info" | "success" | "warning" | "danger" | "neutral";
4
+ /** Maps `Callout` tone to the same cursor icons used by `@anysphere/ui` toasts. */
5
+ export declare const calloutToneIconGlyph: Record<Exclude<CalloutToneForIcon, "neutral">, CalloutToneIconGlyph>;
6
+ export declare function CalloutToneIcon({ tone, color, }: {
7
+ tone: CalloutToneForIcon;
8
+ color: string;
9
+ }): JSX.Element;
10
+ export {};
@@ -0,0 +1,259 @@
1
+ /**
2
+ * Design tokens for `cursor/canvas` (standalone; no UI framework dependency).
3
+ *
4
+ * Color values are pinned copies of the `packages/ui` cursor-core themes
5
+ * (`src/tokens/themes/cursor-core/{dark,light}.ts`) resolved through
6
+ * `CURSOR_SEMANTIC_RULES` (`src/tokens/semantic-schema.ts`). Alpha-hex entries
7
+ * are `base` at the rule's `mixTransparent` percent so they composite
8
+ * correctly over any surface. When the ui tokens change, re-derive these —
9
+ * they do not update automatically.
10
+ *
11
+ * Mapping (dark base #F0F0F0, light base #141414):
12
+ * - foreground* → text-primary/secondary/tertiary/quaternary (100/74/60/36%)
13
+ * - editor/chrome/sidebar/elevated → the core surface hexes (elevated = editor)
14
+ * - fill* → bg-primary/secondary/tertiary/quaternary (20/14/8/6%)
15
+ * - stroke* → stroke-primary/secondary/tertiary (20/12/8%)
16
+ * - strokeFocused → core `focus` at full opacity (NOT `--cursor-stroke-focused`,
17
+ * which is 15% and layered with other cues in the app; in a canvas this is
18
+ * the sole focus affordance)
19
+ * - accent/button* → bg-accent / action-label / bg-accent-hover (mixTwo base 10%)
20
+ * - link → text-link (= core blue)
21
+ * - diff*Line → the core diff line backgrounds; diffStrip* keep the
22
+ * canvas-specific alphas on the core green/red hues
23
+ */
24
+ export declare const canvasPaletteDark: CanvasPalette;
25
+ export declare const canvasPaletteLight: CanvasPalette;
26
+ export declare const canvasPaletteGrokDark: CanvasPalette;
27
+ export declare const canvasPaletteGrokLight: CanvasPalette;
28
+ /**
29
+ * Parse a CSS hex color (`#rgb`, `#rgba`, `#rrggbb`, `#rrggbbaa`) into 0–255
30
+ * RGB components. Returns `undefined` for anything we can't confidently parse
31
+ * (named colors, `rgb()`, etc.) so callers can fall back to the base palette.
32
+ *
33
+ * Hand-rolled rather than reusing a shared color util because this package is
34
+ * deliberately dependency-light (it is bundled into every canvas), and the host
35
+ * only ever sends hex (VS Code's `Color.Format.CSS.formatHex`).
36
+ */
37
+ export declare function parseHexColor(value: string): {
38
+ r: number;
39
+ g: number;
40
+ b: number;
41
+ } | undefined;
42
+ /** Visual brand for canvas token resolve. Unknown values become `"cursor"`. */
43
+ export type CanvasHostThemeBrand = "cursor" | "grok";
44
+ export interface CanvasHostThemeOverrides {
45
+ readonly brand?: CanvasHostThemeBrand;
46
+ readonly primary?: string;
47
+ readonly editorBackground?: string;
48
+ readonly editorForeground?: string;
49
+ }
50
+ /** Unknown / omitted brand keeps the Cursor tables. */
51
+ export declare function parseCanvasHostThemeBrand(value: unknown): CanvasHostThemeBrand;
52
+ /**
53
+ * Overlay workbench editor surface colors onto the base palette so the canvas
54
+ * body and primitives using `bg.editor` match the active VS Code theme
55
+ * instead of the fixed Cursor light/dark editor hex.
56
+ */
57
+ export declare function applyWorkbenchSurfaces(palette: CanvasPalette, surfaces: Pick<CanvasHostThemeOverrides, "editorBackground" | "editorForeground">): CanvasPalette;
58
+ /**
59
+ * Overlay a host-provided primary/accent color (e.g. the active VS Code
60
+ * theme's accent) onto a base palette. Only the accent-adjacent entries
61
+ * change — accent, button background/hover, focus stroke, and links — plus a
62
+ * luminance-picked readable on-accent foreground. Every other entry (surfaces,
63
+ * text, fills, diff) keeps its base light/dark value, so any theme is
64
+ * supported without enumerating its full token set.
65
+ *
66
+ * Returns the base palette unchanged when `primary` isn't a hex color we can
67
+ * parse, keeping behaviour identical to hosts that only report a theme `kind`.
68
+ */
69
+ export declare function applyPrimaryColor(palette: CanvasPalette, primary: string): CanvasPalette;
70
+ export interface CanvasPalette {
71
+ readonly foreground: string;
72
+ readonly foregroundSecondary: string;
73
+ readonly foregroundTertiary: string;
74
+ readonly foregroundQuaternary: string;
75
+ readonly editor: string;
76
+ readonly chrome: string;
77
+ readonly sidebar: string;
78
+ readonly elevated: string;
79
+ readonly fillPrimary: string;
80
+ readonly fillSecondary: string;
81
+ readonly fillTertiary: string;
82
+ readonly fillQuaternary: string;
83
+ readonly strokePrimary: string;
84
+ readonly strokeSecondary: string;
85
+ readonly strokeTertiary: string;
86
+ readonly strokeFocused: string;
87
+ readonly accent: string;
88
+ readonly buttonBackground: string;
89
+ readonly buttonForeground: string;
90
+ readonly buttonHoverBackground: string;
91
+ readonly link: string;
92
+ readonly diffInsertedLine: string;
93
+ readonly diffRemovedLine: string;
94
+ readonly diffStripAdded: string;
95
+ readonly diffStripRemoved: string;
96
+ }
97
+ /**
98
+ * Chart color palette — distilled from portal-website analytics charts.
99
+ * 88% opacity (E0) softens vibrancy without dulling; palette maximizes
100
+ * hue + luminosity spread for distinguishable multi-series charts.
101
+ */
102
+ export declare const chartPalette: {
103
+ readonly green: "#1F8A65E8";
104
+ readonly darkGreen: "#0D855AE0";
105
+ readonly lightGreen: "#52B896E0";
106
+ readonly mintGreen: "#7DCAB0E0";
107
+ readonly blue: "#2E79B5E0";
108
+ readonly lightBlue: "#70B0D8E0";
109
+ readonly indigo: "#5A6CC0F0";
110
+ readonly lightIndigo: "#9AAADCE0";
111
+ readonly purple: "#7B64B8F0";
112
+ readonly lightPurple: "#AA98D8E0";
113
+ readonly warmPink: "#C85898E0";
114
+ readonly lightPink: "#E8A0C4E0";
115
+ readonly brightOrange: "#F0A040E0";
116
+ readonly deepOrange: "#C06028E0";
117
+ readonly goldenYellow: "#E8C030E0";
118
+ readonly darkAmber: "#C04848E0";
119
+ readonly warmPeach: "#F0A088E0";
120
+ readonly vibrantTeal: "#2A9A8AE0";
121
+ readonly muted: "#8888A8E0";
122
+ readonly neutralLine: "#888899D0";
123
+ };
124
+ /**
125
+ * Shared category palette for canvas primitives that show categorical tints
126
+ * (`Swatch`, `UsageBar` segments, etc.). Hexes mirror the cursor core hues
127
+ * from `packages/ui/src/tokens/themes/cursor-core/{dark,light}.ts` (via the
128
+ * `text-{hue}-primary` semantic tokens); `gray` reuses the palette's
129
+ * `foregroundTertiary` (= `text-tertiary`, `mixTransparent base 60%`).
130
+ * `orange` is mixed 70/30 with red to keep
131
+ * Conversation distinct from Skills' yellow in light mode while staying warm.
132
+ *
133
+ * The insertion order here is the canonical category order — primitives
134
+ * that auto-assign colors (e.g. `UsageBar` segments without an explicit
135
+ * `color`) cycle through these keys in order.
136
+ */
137
+ export type Color = "gray" | "purple" | "green" | "yellow" | "cyan" | "pink" | "blue" | "orange" | "red";
138
+ export type CategoryPalette = Readonly<Record<Color, string>>;
139
+ export declare const categoryPaletteDark: CategoryPalette;
140
+ export declare const categoryPaletteLight: CategoryPalette;
141
+ export declare const categoryPaletteGrokDark: CategoryPalette;
142
+ export declare const categoryPaletteGrokLight: CategoryPalette;
143
+ /** Legacy `colorPalette` name kept for back-compat; per-theme tables are `categoryPalette{Dark,Light}`. React consumers should read `useHostTheme().category` so the color flips with the host theme. */
144
+ export declare const colorPalette: CategoryPalette;
145
+ /**
146
+ * Auto-color rotation for `UsageBar` segments without an explicit `color`.
147
+ * Decoupled from `colorPalette`'s declaration order so the palette can grow
148
+ * or be reordered without changing how unspecified segments cycle.
149
+ *
150
+ * Matches the original `packages/ui` `ContextUsageTray` order so the same
151
+ * segment index lands on the same hue as the source.
152
+ */
153
+ export declare const usageColorSequence: readonly Color[];
154
+ /**
155
+ * Ordered array for automatic series coloring — alternates dark/light across
156
+ * distinct hue families for maximum perceptual separation.
157
+ */
158
+ export declare const chartColorSequence: readonly string[];
159
+ /**
160
+ * Sand data-categorical hues. Same key set as {@link chartPalette} so
161
+ * tone maps (`success` / `danger` / …) stay typed; the lead series colors
162
+ * are Sand blue / orange / purple.
163
+ */
164
+ export declare const chartPaletteGrok: {
165
+ readonly green: "#00C972E8";
166
+ readonly darkGreen: "#009957E0";
167
+ readonly lightGreen: "#38D591E0";
168
+ readonly mintGreen: "#78E2B4E0";
169
+ readonly blue: "#1084FEE0";
170
+ readonly lightBlue: "#459FFEE0";
171
+ readonly indigo: "#0C64C1F0";
172
+ readonly lightIndigo: "#80BEFEE0";
173
+ readonly purple: "#9159FEF0";
174
+ readonly lightPurple: "#A97EFEE0";
175
+ readonly warmPink: "#FF309BE0";
176
+ readonly lightPink: "#FF5EB1E0";
177
+ readonly brightOrange: "#FF6700E0";
178
+ readonly deepOrange: "#C24E00E0";
179
+ readonly goldenYellow: "#FF9800E0";
180
+ readonly darkAmber: "#FF263CE0";
181
+ readonly warmPeach: "#FF8838E0";
182
+ readonly vibrantTeal: "#00BCA6E0";
183
+ readonly muted: "#777777E0";
184
+ readonly neutralLine: "#777777D0";
185
+ };
186
+ export declare const chartColorSequenceGrok: readonly string[];
187
+ export type ChartPalette = {
188
+ readonly [K in keyof typeof chartPalette]: string;
189
+ };
190
+ /**
191
+ * Semantic colors for components (spacing and radius live in `theme.ts`).
192
+ * There is no `colors` bag — `theme.colors.bg.primary` is not a path.
193
+ * Use `theme.bg.editor`, `theme.fill.primary`, `theme.text.primary`,
194
+ * `theme.stroke.secondary`, `theme.accent.primary`.
195
+ */
196
+ export interface CanvasTokens {
197
+ bg: {
198
+ editor: string;
199
+ chrome: string;
200
+ elevated: string;
201
+ };
202
+ text: {
203
+ primary: string;
204
+ secondary: string;
205
+ tertiary: string;
206
+ quaternary: string;
207
+ link: string;
208
+ onAccent: string;
209
+ };
210
+ stroke: {
211
+ primary: string;
212
+ secondary: string;
213
+ tertiary: string;
214
+ focused: string;
215
+ };
216
+ fill: {
217
+ primary: string;
218
+ secondary: string;
219
+ tertiary: string;
220
+ quaternary: string;
221
+ };
222
+ accent: {
223
+ primary: string;
224
+ control: string;
225
+ controlHover: string;
226
+ };
227
+ diff: {
228
+ insertedLine: string;
229
+ removedLine: string;
230
+ stripAdded: string;
231
+ stripRemoved: string;
232
+ };
233
+ category: CategoryPalette;
234
+ }
235
+ export declare const canvasTokens: CanvasTokens;
236
+ export declare const canvasTokensLight: CanvasTokens;
237
+ /**
238
+ * Resolve the full token set for a host theme `kind`, optionally overlaying
239
+ * the active editor's primary/accent color via {@link applyPrimaryColor}.
240
+ *
241
+ * Light kinds (`light`, `hc-light`) use the light palette/categories; every
242
+ * other kind uses the dark ones. Centralizing the palette + category choice
243
+ * here keeps `useHostTheme` a thin reader of host state.
244
+ *
245
+ * Grok skips the host `primary` overlay: Grok owns ink accents
246
+ * (`#FAFAFA` / `#070707`). Hosts like Sand and VS Code always send
247
+ * `primary` (workbench `button.background`) and would otherwise wipe
248
+ * those inks. Workbench surfaces (`editorBackground` /
249
+ * `editorForeground`) still apply.
250
+ */
251
+ export declare function buildHostTokens(kind: string, overrides?: CanvasHostThemeOverrides): {
252
+ tokens: CanvasTokens;
253
+ palette: CanvasPalette;
254
+ brand: CanvasHostThemeBrand;
255
+ };
256
+ export declare function chartThemeForBrand(brand: CanvasHostThemeBrand): {
257
+ palette: ChartPalette;
258
+ sequence: readonly string[];
259
+ };
@@ -0,0 +1,272 @@
1
+ /**
2
+ * Chart primitives for `cursor/canvas` — multi-series, stacked, and pie charts
3
+ * rendered as pure inline SVG with zero external dependencies.
4
+ *
5
+ * Distilled from the portal-website Highcharts analytics charting layer.
6
+ */
7
+ import type { CSSProperties, JSX } from "react";
8
+ /**
9
+ * Semantic tone for a chart series or slice. Mirrors the tone vocabulary
10
+ * used by `Stat`, `Callout`, and `Table` `rowTone` so colors match across
11
+ * a canvas — e.g. a `Stat tone="success"` and a `ChartSeries tone="success"`
12
+ * render in the same green. `Pill` does not share this vocabulary.
13
+ *
14
+ * Omit `tone` to let the chart auto-assign a distinct color from the
15
+ * chart palette; supply `tone` only when the value carries semantic
16
+ * meaning that should match other tonal elements on the page.
17
+ */
18
+ export type ChartTone = "success" | "danger" | "warning" | "info" | "neutral";
19
+ /** A single labeled value, used by `PieChart`. */
20
+ export type ChartDataPoint = {
21
+ label: string;
22
+ /** Non-negative numeric value. */
23
+ value: number;
24
+ };
25
+ /**
26
+ * A named data series for `BarChart` and `LineChart`.
27
+ * The `data` array aligns by index with the parent component's `categories`.
28
+ * If `tone` is omitted, a color is auto-assigned from the chart palette.
29
+ */
30
+ export type ChartSeries = {
31
+ name: string;
32
+ /** Values aligned with `categories`. Must be numbers, not numeric strings. */
33
+ data: number[];
34
+ tone?: ChartTone;
35
+ };
36
+ /**
37
+ * A dashed marker line drawn across the plot at a fixed value — for targets,
38
+ * SLOs, budgets, means, or limits. Drawn horizontally on line / vertical-bar
39
+ * charts and vertically on `horizontal` bar charts; either way it marks the
40
+ * value axis and is folded into the auto domain so it stays on-canvas.
41
+ */
42
+ export type ChartReferenceLine = {
43
+ /** Position on the value axis, in the same units as the series data. */
44
+ value: number;
45
+ /** Short label drawn in a chip at the line's end. */
46
+ label?: string;
47
+ /** Line color. Omit for a muted neutral; set to match other tonal elements. */
48
+ tone?: ChartTone;
49
+ };
50
+ /**
51
+ * Shared value-axis controls (the y-axis, or the x-axis on `horizontal` bar
52
+ * charts). By default the axis starts at zero; override to zoom into a tight
53
+ * range. On stacked / normalized bars these are ignored — those always start
54
+ * at zero.
55
+ */
56
+ type ValueAxisProps = {
57
+ /**
58
+ * Start the value axis at zero. Defaults to `true`. Set `false` to
59
+ * auto-fit the axis to the data range — useful for tightly-clustered
60
+ * series (e.g. uptime 99.0–99.9%) that a zero baseline would flatten.
61
+ */
62
+ beginAtZero?: boolean;
63
+ /** Explicit axis minimum. Overrides `beginAtZero`. */
64
+ yMin?: number;
65
+ /** Explicit axis maximum. */
66
+ yMax?: number;
67
+ /** Horizontal marker lines for targets / thresholds / means. */
68
+ referenceLines?: ChartReferenceLine[];
69
+ };
70
+ export type BarChartProps = ValueAxisProps & {
71
+ /** Category labels along the independent axis. */
72
+ categories: string[];
73
+ /** One or more data series. Values align by index with `categories`. */
74
+ series: ChartSeries[];
75
+ height?: number;
76
+ /** Stack series on top of each other instead of grouping side-by-side. */
77
+ stacked?: boolean;
78
+ /** Render horizontal bars instead of vertical columns. */
79
+ horizontal?: boolean;
80
+ /** Show as 100% stacked (implies `stacked`). */
81
+ normalized?: boolean;
82
+ /** Suffix for value labels (e.g. "%", " ms"). */
83
+ valueSuffix?: string;
84
+ /** Prefix for value labels (e.g. "$"). Ignored in `normalized` mode. */
85
+ valuePrefix?: string;
86
+ /**
87
+ * Print each bar's value as a label. Defaults to auto: on for a single
88
+ * series with ≤8 categories, off otherwise. Set `true` to force labels on
89
+ * (e.g. grouped multi-series), or `false` to force them off. No effect on
90
+ * `stacked` / `normalized` charts — use the hover tooltip there.
91
+ */
92
+ showValues?: boolean;
93
+ style?: CSSProperties;
94
+ };
95
+ export type LineChartProps = ValueAxisProps & {
96
+ categories: string[];
97
+ series: ChartSeries[];
98
+ height?: number;
99
+ /** Fill the area under each line with a soft tint. */
100
+ fill?: boolean;
101
+ /** Suffix for value labels (e.g. "%", " ms"). */
102
+ valueSuffix?: string;
103
+ /** Prefix for value labels (e.g. "$"). */
104
+ valuePrefix?: string;
105
+ /** Print the value next to every data point (≤20 categories). */
106
+ showValues?: boolean;
107
+ /** Draw a vertical guide through the cursor while hovering. Defaults to `true`. */
108
+ showHoverGuide?: boolean;
109
+ style?: CSSProperties;
110
+ };
111
+ export type PieChartProps = {
112
+ data: Array<ChartDataPoint & {
113
+ tone?: ChartTone;
114
+ }>;
115
+ /** Diameter in px. Defaults to 200. */
116
+ size?: number;
117
+ /** Render as a donut with the summed total shown in the hollow center. */
118
+ donut?: boolean;
119
+ style?: CSSProperties;
120
+ };
121
+ /**
122
+ * Multi-series bar/column chart with optional stacking and normalization.
123
+ * Distilled from the portal-website Highcharts analytics charts.
124
+ *
125
+ * Pass `categories` for x-axis labels and one or more `series` whose `data`
126
+ * arrays align by index. With a single series you get simple bars; with
127
+ * multiple series the default is grouped (side-by-side) — set `stacked` for
128
+ * stacked columns or `normalized` for 100%-stacked share-mode.
129
+ *
130
+ * Colors are auto-assigned from the chart palette. With a **single series**,
131
+ * each bar gets a different color by category (so a chart of 5 categories
132
+ * shows 5 colors out of the box). With **multiple series**, each series gets
133
+ * its own color. A legend appears when there are 2+ series.
134
+ *
135
+ * For semantic coloring, pass `tone` on a series — it maps to the same
136
+ * palette entries used by `Stat`, `Pill`, and `Table` so your chart matches
137
+ * tonal elements elsewhere on the page.
138
+ *
139
+ * @example
140
+ * ```tsx
141
+ * // Simple single-series
142
+ * <BarChart
143
+ * categories={["Mon", "Tue", "Wed"]}
144
+ * series={[{ name: "Requests", data: [120, 90, 150] }]}
145
+ * />
146
+ *
147
+ * // Stacked multi-series (like portal AI commit chart)
148
+ * <BarChart
149
+ * categories={["Mon", "Tue", "Wed"]}
150
+ * series={[
151
+ * { name: "IDE", data: [120, 90, 150] },
152
+ * { name: "CLI", data: [30, 40, 25] },
153
+ * { name: "Cloud", data: [50, 60, 70] },
154
+ * ]}
155
+ * stacked
156
+ * />
157
+ *
158
+ * // Semantic tones — "accepted" renders in the same green as
159
+ * // <Stat tone="success"> elsewhere on the page.
160
+ * <BarChart
161
+ * categories={["Mon", "Tue", "Wed"]}
162
+ * series={[
163
+ * { name: "Accepted", data: [70, 80, 60], tone: "success" },
164
+ * { name: "Rejected", data: [30, 20, 40], tone: "danger" },
165
+ * ]}
166
+ * stacked
167
+ * />
168
+ *
169
+ * // Mark a target with a reference line. Grouped/single bars also accept
170
+ * // `yMin` / `yMax` to frame the axis (stacked bars stay zero-based).
171
+ * <BarChart
172
+ * categories={["Mon", "Tue", "Wed", "Thu", "Fri"]}
173
+ * series={[{ name: "Latency", data: [180, 210, 240, 200, 220] }]}
174
+ * valueSuffix=" ms"
175
+ * referenceLines={[{ value: 200, label: "Budget", tone: "warning" }]}
176
+ * />
177
+ * ```
178
+ */
179
+ export declare function BarChart({ categories, series, height, stacked, horizontal, normalized, valueSuffix, valuePrefix, showValues, beginAtZero, yMin, yMax, referenceLines, style, }: BarChartProps): JSX.Element;
180
+ /**
181
+ * Multi-series line chart with optional area fill. Distilled from the
182
+ * portal-website Highcharts analytics charts.
183
+ *
184
+ * Each series draws a polyline with dot markers at each data point.
185
+ * Set `fill` to shade the area under every line. Hover over any category
186
+ * column to see a tooltip with all series values and a vertical cursor guide.
187
+ *
188
+ * This is **not** a time-series component — it does not parse dates.
189
+ * Pass pre-formatted date strings as `categories` if plotting over time.
190
+ *
191
+ * Colors are auto-assigned from the chart palette. For semantic coloring,
192
+ * pass `tone` on a series — it maps to the same palette entries used by
193
+ * `Stat`, `Pill`, and `Table`.
194
+ *
195
+ * @example
196
+ * ```tsx
197
+ * // Single line
198
+ * <LineChart
199
+ * categories={["Jan", "Feb", "Mar", "Apr"]}
200
+ * series={[{ name: "Revenue", data: [100, 140, 120, 180] }]}
201
+ * />
202
+ *
203
+ * // Multi-series with area fill
204
+ * <LineChart
205
+ * categories={["Jan", "Feb", "Mar", "Apr"]}
206
+ * series={[
207
+ * { name: "Accepted", data: [50, 70, 60, 90] },
208
+ * { name: "Suggested", data: [120, 140, 130, 160] },
209
+ * ]}
210
+ * fill
211
+ * />
212
+ *
213
+ * // Semantic tones — "errors" renders in the same red as a
214
+ * // <Stat tone="danger"> or <Callout tone="danger"> elsewhere on the page.
215
+ * <LineChart
216
+ * categories={["00:00", "06:00", "12:00", "18:00"]}
217
+ * series={[
218
+ * { name: "p95 latency", data: [80, 95, 110, 90], tone: "info" },
219
+ * { name: "errors", data: [2, 4, 9, 3], tone: "danger" },
220
+ * ]}
221
+ * />
222
+ *
223
+ * // Zoom into a tight range and mark an SLO. `beginAtZero={false}`
224
+ * // auto-fits the axis; `referenceLines` draws the target.
225
+ * <LineChart
226
+ * categories={["Mon", "Tue", "Wed", "Thu", "Fri"]}
227
+ * series={[{ name: "Uptime", data: [99.91, 99.95, 99.7, 99.99, 99.96] }]}
228
+ * valueSuffix="%"
229
+ * beginAtZero={false}
230
+ * referenceLines={[{ value: 99.9, label: "SLO", tone: "danger" }]}
231
+ * />
232
+ * ```
233
+ */
234
+ export declare function LineChart({ categories, series, height, fill, valueSuffix, valuePrefix, showValues, showHoverGuide, beginAtZero, yMin, yMax, referenceLines, style, }: LineChartProps): JSX.Element;
235
+ /**
236
+ * Pie (or donut) chart with hover highlighting. Distilled from the
237
+ * portal-website Highcharts analytics charts.
238
+ *
239
+ * Unlike `BarChart` and `LineChart`, `PieChart` takes a flat `data` array of
240
+ * `{ label, value }` points — each slice is its own category. Colors are
241
+ * auto-assigned from the chart palette; pass `tone` on a point to give a
242
+ * slice a semantic color that matches other tonal elements on the page.
243
+ *
244
+ * Hovering a slice expands it outward and dims the others; hovering a legend
245
+ * item does the same. A tooltip with value and percentage appears below the
246
+ * chart. Set `donut` for a hollow center that shows the summed total.
247
+ *
248
+ * **Do not** use for bar-style comparisons — use `BarChart` instead.
249
+ *
250
+ * @example
251
+ * ```tsx
252
+ * // Basic pie
253
+ * <PieChart
254
+ * data={[
255
+ * { label: "IDE", value: 120 },
256
+ * { label: "CLI", value: 30 },
257
+ * { label: "Cloud", value: 50 },
258
+ * ]}
259
+ * />
260
+ *
261
+ * // Donut with semantic tones
262
+ * <PieChart
263
+ * data={[
264
+ * { label: "Passing", value: 70, tone: "success" },
265
+ * { label: "Failing", value: 30, tone: "danger" },
266
+ * ]}
267
+ * donut
268
+ * />
269
+ * ```
270
+ */
271
+ export declare function PieChart({ data, size, donut, style, }: PieChartProps): JSX.Element;
272
+ export {};