Skip to content

Canvas Types

这一页列出 @hy-bricks/canvas 接入时最常用的公开类型。完整导出以 packages/canvas/src/index.ts 为准。

Source

ts
interface Source {
  html: string
  js: string
  css: string
}

组件源码永远是三段式。SDK 负责编译,宿主负责保存、发布和传输。

ComponentVersionKey

ts
type ComponentVersionKey = string

推荐格式:

类型形态示例
正式版本${componentId}@${version}chart@3
编辑草稿${componentId}@draft:${pageId}:${baseVersion}chart@draft:p1:3

运行时用 helper 判断:

ts
import { isDraftKey, parseComponentVersionKey } from '@hy-bricks/canvas'

页面推版本时后端必须拒收 @draft: key。

ComponentContract

ts
interface ComponentContract {
  propsDecl: PropDecl[]
  emitsDecl: EmitDecl[]
  methodsDecl: MethodDecl[]
  slotsDecl: SlotDecl[]
  modelDecl: ModelDecl[]
  dataInputsDecl: DataInputDecl[]
  dataOutputsDecl: DataOutputDecl[]
  layoutDecl?: ComponentLayoutDecl
}

命名口径:

字段用途
key代码标识符,用于 prop / method / model / data
eventemit 事件名
nameslot 名,保持 Vue <slot name="..."> 语义
label展示名

layoutDecl 是容器能力声明,用于告诉宿主“这是容器、支持哪些布局、默认如何摆子实例”。SDK 当前不会替组件源码自动生成 split/grid DOM。

ComponentVersionAsset

ts
type ComponentVersionStatus = 'ok' | 'unavailable' | 'missing' | 'broken'

interface ComponentVersionAsset {
  key: ComponentVersionKey
  componentId: string
  version: string
  status: ComponentVersionStatus
  invalidReason?: string
  name?: string
  source?: Source
  contract?: ComponentContract
  kind?: 'visual' | 'layout' | 'data'
  updatedAt?: string
}

status === 'ok' 时应提供 sourcecontract。其它状态表示宿主无法提供源码,SDK 渲染降级卡。

DraftComponentVersionAsset

ts
interface DraftComponentVersionAsset {
  key: ComponentVersionKey
  baseVersionKey: ComponentVersionKey
  componentId: string
  isDraft: true
  status: 'ok'
  source: Source
  contract: ComponentContract
  contractParseError?: { message: string; at: string }
  lastGoodSource: Source
  lastGoodContract: ComponentContract
  createdAt: string
  updatedAt: string
}

草稿只在前端编辑期使用。RuntimeBox 编译应使用 lastGoodSource,属性面板读取 lastGoodContract

PageComponentOverride

ts
interface PageComponentOverride {
  instanceId: string
  baseVersionKey: ComponentVersionKey
  source: Source
  contract: ComponentContract
  contractParseError?: {
    message: string
    line?: number
    column?: number
  }
  createdAt?: string
  updatedAt?: string
}

覆盖只影响当前页面的当前实例。只有 baseVersionKey === instance.componentVersionKey 时生效,否则是 stale override。

PageInstance

ts
interface PageInstance {
  instanceId: string
  componentId: string
  componentVersionKey: ComponentVersionKey
  alias?: string
  rect: { x: number; y: number; w: number; h: number }
  zIndex: number
  rotation?: number
  locked?: boolean
  hidden?: boolean
  props: Record<string, unknown>
  layoutBox?: LayoutBox
  layoutItem?: LayoutItem
  parentId?: string
  slot?: string
  placement?: 'canvas' | 'container' | 'absolute' | 'slot'
  size?: PageInstanceSize
  containerLayout?: ContainerLayoutConfig
}

新接入优先写:

  • layoutBox:实例外层盒子。
  • layoutItem:在父 flex/grid/split 中的位置、顺序、比例。
  • placement: 'canvas' | 'container':当前的标准值。

兼容字段:

  • rect:老 reducer / hit-test 仍依赖,normalize 会和 layoutBox 同步维护。
  • size:兼容层,已被 layoutBox 合并。
  • placement: 'absolute' | 'slot':老值,normalize 后转成 canvas / container

LayoutBox

ts
type LayoutBoxAxisMode = 'px' | 'percent' | 'fill' | 'auto'

interface LayoutBox {
  x: number
  y: number
  width: number
  height: number
  widthMode: LayoutBoxAxisMode
  heightMode: LayoutBoxAxisMode
  overflow?: 'hidden' | 'visible' | 'auto'
}

LayoutBox 不包含 zIndexrotationlockedhidden。这些仍在 PageInstance 顶层。

LayoutItem

ts
interface LayoutItem {
  order?: number
  grow?: number
  shrink?: number
  row?: number
  column?: number
  rowSpan?: number
  columnSpan?: number
  ratio?: number
}

父布局决定哪个字段生效:

父布局消费字段
flexorder / grow / shrink
gridrow / column / rowSpan / columnSpan
splitratio
free / none不消费 layoutItem

ContainerLayoutConfig

ts
type ContainerLayoutConfig =
  | { mode: 'none' }
  | { mode: 'free' }
  | FlexContainerLayout
  | SplitContainerLayout
  | GridContainerLayout
ts
interface FlexContainerLayout {
  mode: 'flex'
  direction: 'row' | 'column'
  wrap?: boolean
  gap?: number
  justify?: 'start' | 'center' | 'end' | 'space-between' | 'space-around'
  align?: 'start' | 'center' | 'end' | 'stretch'
}

interface SplitContainerLayout {
  mode: 'split'
  direction: 'horizontal' | 'vertical'
  ratios: number[]
  gap?: number
}

interface GridContainerLayout {
  mode: 'grid'
  columns: Array<{ mode: 'fr' | 'px' | 'percent'; value: number }>
  rows: Array<{ mode: 'fr' | 'px' | 'percent' | 'auto'; value?: number }>
  gap?: number | { row?: number; column?: number }
  cells?: Record<string, {
    row: number
    column: number
    rowSpan?: number
    columnSpan?: number
  }>
}

layout.rootLayout 控制顶层实例布局;instance.containerLayout 控制某个容器实例 default slot 的子布局。

PageDocument

ts
interface PageDocument {
  schemaVersion?: '1'
  layout: PageLayout | CanvasLayoutConfig
  instances: PageInstance[]
  bindings: PageBinding[]
  componentOverrides?: Record<string, PageComponentOverride>
}

PageDocument 是设计器写视图,只存结构和 pinned key,不存源码字典。

PageRenderPayload

ts
interface PageRenderPayload {
  page: {
    id: string
    name: string
    targets: Array<'pc' | 'mobile' | 'screen'>
  }
  version: {
    version: string
    label: string
    publishedAt: string
  } | null
  document: PageDocument
  componentVersions: Record<
    ComponentVersionKey,
    ComponentVersionAsset | DraftComponentVersionAsset
  >
}

PageRenderPayload 是运行态只读视图。宿主拿到后可以直接传给 HyperCardPageRenderer

CanvasLayoutConfig

ts
interface CanvasLayoutConfig {
  type: 'free' | 'flow' | 'nested'
  canvas: CanvasViewportConfig
  background?: CanvasBackgroundConfig
  behavior?: CanvasBehaviorConfig
  rootLayout?: ContainerLayoutConfig
  guides?: {
    grid?: CanvasGridConfig
    ruler?: CanvasRulerConfig
    items?: CanvasGuide[]
  }
}

type 是历史字段。顶层布局以 rootLayout 为准。

AssetRef

ts
interface AssetRef {
  id: string
  type?: 'image' | 'video' | 'font' | 'json' | 'file'
  url?: string
  name?: string
  meta?: Record<string, unknown>
}

没有 adapter 时 SDK 使用 url;有 assets.resolve(ref) adapter 时优先调 adapter。

Tree And Commands

常用辅助类型:

类型说明
PageInstanceTreeNodehandle.getInstanceTree() 的树节点
TreeMoveTargetmoveInstanceInTree() 的目标位置
CannotReparentEventreparent 被拒事件
DropTargetgetDropTarget() 命中的 outlet
CanvasToolModeselect / hand / marquee / inspect 等工具态
CanvasCommandIdtoolbar / 快捷键 / 右键菜单的命令 id
CanvasShortcutBinding默认快捷键绑定描述

纯函数 Helpers

常用导出:

Helper说明
normalizePageDocumentv0/v1 文档归一,补齐 layoutBox / rootLayout 等字段
validateInstanceTree校验 parent/slot/accepts/multiple/depth
canReparent单次 reparent dry-run
computeContentBounds / computeSelectionBounds视口 fit 计算前置几何
computeFit / computeVisibleBounds视口适配和可见范围
getDefaultShortcuts / matchBinding默认快捷键表和匹配逻辑
renderLayoutBoxStyle把 LayoutBox 渲染成 wrapper CSS
computeEffectiveSplitRatiossplit 子数量变化后的有效 ratios

进一步阅读

@hy-bricks/canvas 还导出 trace 协议相关类型(TraceCollectorOptions / StoreTraceKind 及 13 个 trace kind)、PageBinding 规范化、BindingErrorCode 全枚举、HandleDisposedError、0.3.0 mount-ready 信号类型等。完整导出以 packages/canvas/src/index.ts 为准。