# Canvas 兼容表

`.canvas.tsx` 是实验格式。上传结果带 `experimental: true`。阅读页在沙箱里用 Sucrase 转译，再执行默认导出的函数组件。只允许从 `cursor/canvas` 导入，名字必须在下表里。其它模块、未列出的导出名、默认导入，都报 `UNSUPPORTED_IMPORT`，并写明模块和导出名。

转译优先放在 Web Worker 里，5 秒后终止。沙箱不允许创建 Worker 时，改在沙箱页面里同步转译。本页第一次转译的耗时记在预览根节点的 `data-canvas-cold-ms` 上，之后的渲染不覆盖这个数。

`useCanvasState` 只在当次打开的页面里保持，刷新后回到默认值。`useCanvasAction` 不调用 Cursor，点击后提示该操作只在 Cursor 内可用。运行时 `namespace` 和装饰器在转译前报 `UNSUPPORTED_SYNTAX`。`declare namespace`、`import type` 和具名导入里的 `type` 说明会被擦掉，不报错。

## 布局

| 导出 | 属性 |
| --- | --- |
| `Stack` | `children`、`gap`（默认 12）、`style` |
| `Row` | `children`、`gap`（默认 8）、`align`（`start` `center` `end` `stretch`）、`justify`（`start` `center` `end` `space-between`）、`wrap`、`style` |
| `Grid` | `children`、`columns`（数字或模板字符串）、`gap`、`align`、`style` |
| `Divider` | `style` |
| `Spacer` | 无 |
| `Card` | `children`、`variant`（`default` `borderless`）、`size`（`base` `lg`）、`collapsible`、`defaultOpen`、`open`、`onOpenChange`、`style` |
| `CardHeader` | `children`、`trailing`、`style` |
| `CardBody` | `children`、`style`。折叠的卡片关闭时不渲染 |

## 文本

| 导出 | 属性 |
| --- | --- |
| `H1` `H2` `H3` | `children`、`style` |
| `Text` | `children`、`tone`（`primary` `secondary` `tertiary` `quaternary`）、`size`（`body` `small`）、`as`（`p` `span`）、`weight`、`italic`、`truncate`、`style`。字符串里的 Markdown 链接会变成链接 |
| `Code` | `children`、`style` |
| `Link` | `children`、`href`、`style`。`http(s)` 由阅读页确认后打开 |
| `Pill` | `children`、`active`、`size`（`sm` `md`）、`leadingContent`、`keyboardHint`、`disabled`、`title`、`onClick`、`style` |
| `Callout` | `children`、`tone`（`success` `danger` `warning` `info` `neutral`）、`title`、`icon`、`style` |
| `Stat` | `value`、`label`、`tone`、`style` |

## 表格、差异、待办

| 导出 | 属性 |
| --- | --- |
| `Table` | `headers`、`rows`、`columnAlign`、`rowTone`、`framed`、`striped`、`stickyHeader`、`emptyMessage`、`style` |
| `DiffView` | `lines`（`type` 为 `added` `removed` `unchanged`，`content`，可选 `lineNumber`）、`showLineNumbers`、`coloredLineNumbers`、`showAccentStrip`、`style`。`path` 与 `language` 只保留在类型里，不改变显示 |
| `DiffStats` | `additions`、`deletions`、`style`。两边都是 0 时不渲染 |
| `TodoList` | `todos`（`id`、`content`、`status`：`pending` `in_progress` `completed` `cancelled`）、`dimmedTodoIds`、`onTodoClick`、`style` |
| `TodoListCard` | 同上，另有 `defaultExpanded` |
| `CollapsibleSection` | `title`、`leading`、`count`、`trailing`、`children`、`defaultOpen`、`style` |

## 表单

| 导出 | 属性 |
| --- | --- |
| `Button` | `children`、`variant`（`primary` `secondary` `ghost`）、`disabled`、`type`、`onClick`、`style` |
| `IconButton` | `children`、`onClick`、`disabled`、`title`、`variant`（`default` `circle`）、`size`（`sm` `md`）、`style` |
| `TextInput` | `value`、`onChange`、`placeholder`、`disabled`、`type`、`style` |
| `TextArea` | `value`、`onChange`、`placeholder`、`disabled`、`rows`、`style` |
| `Checkbox` | `checked`、`onChange`、`disabled`、`label`、`style` |
| `Toggle` | `checked`、`onChange`、`disabled`、`size`（`sm` `md`）、`style` |
| `Select` | `value`、`onChange`、`options`（`value`、`label`、`disabled`）、`placeholder`、`disabled`、`style` |

## 图表与色板

| 导出 | 属性 |
| --- | --- |
| `BarChart` | `categories`、`series`（`name`、`data`、`tone`）、`height`、`stacked`、`horizontal`、`normalized`、`valuePrefix`、`valueSuffix`、`showValues`、`beginAtZero`、`yMin`、`yMax`、`referenceLines`、`style` |
| `LineChart` | `categories`、`series`、`height`、`fill`、`valuePrefix`、`valueSuffix`、`showValues`、`beginAtZero`、`yMin`、`yMax`、`referenceLines`、`style` |
| `PieChart` | `data`（`label`、`value`、`tone`）、`size`、`donut`、`style` |
| `UsageBar` | `segments`（`id`、`value`、`color`）、`total`、`topLeftLabel`、`topRightLabel`、`style` |
| `Swatch` | `color`（`gray` `purple` `green` `yellow` `cyan` `pink` `blue` `orange` `red`）、`style` |

图用 SVG 画在沙箱里，不加载图表库，也不请求外部资源。

## 状态与布局计算

| 导出 | 说明 |
| --- | --- |
| `useState` `useMemo` `useRef` `useEffect` | React 19 的同名 hook |
| `useHostTheme` | 返回当前浅色或深色主题，跟随系统 |
| `useCanvasState` | `(key, defaultValue) => [value, setValue]`。只活在当次页面 |
| `useCanvasAction` | 接受 `{ type: "openAgent", agentId }`、`{ type: "newComposerChat", userPrompt? }` 或 `{ type: "openFile", path, selection? }`。不调用 IDE |
| `computeDAGLayout` | `{ nodes, edges, direction?, nodeWidth?, nodeHeight?, rankGap?, nodeGap?, padding? }`。返回节点坐标、边和 `isBackEdge` |

## 主题常量

这些值可以直接拿来写 `style`。样例可以不导入它们。

`canvasPaletteDark`、`canvasPaletteLight`、`canvasPaletteGrokDark`、`canvasPaletteGrokLight`、`canvasTokens`、`canvasTokensLight`、`categoryPaletteDark`、`categoryPaletteLight`、`colorPalette`、`usageColorSequence`、`mergeStyle`。

`mergeStyle(base, override)` 合并两份样式。

## 明确不支持

- 除 `cursor/canvas` 以外的模块，包括 `react`、相对路径和 `import()`。
- `cursor/canvas` 里上表没有的导出名，以及默认导入。
- 运行时 `namespace` 和装饰器。Sucrase 会静默丢掉它们，所以转译前直接拒绝。
- 类型检查。转译只做语法转换，类型错误要到运行时才出现。
