@hy-bricks/canvas 0.1.1
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/LICENSE +21 -0
- package/README.md +227 -0
- package/dist/index.cjs +2 -0
- package/dist/index.d.ts +1982 -0
- package/dist/index.mjs +2 -0
- package/package.json +62 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 hy_top
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,227 @@
|
|
|
1
|
+
# @hy-bricks/canvas
|
|
2
|
+
|
|
3
|
+
> HyperCard 画布 — 多组件实例编排 / 渐进渲染 / 只读渲染器。受控组件,SDK 边界守住:不 fetch / 不知后端 / 不开 Drawer。
|
|
4
|
+
|
|
5
|
+
[](https://www.npmjs.com/package/@hy-bricks/canvas)
|
|
6
|
+
[](./LICENSE)
|
|
7
|
+
[](https://vuejs.org/)
|
|
8
|
+
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
## 简介
|
|
12
|
+
|
|
13
|
+
`@hy-bricks/canvas` 是 HyperCard 画布 SDK,提供:
|
|
14
|
+
|
|
15
|
+
- **`<HyperCardPageRenderer>`** — 只读页面渲染器:接受 `PageRenderPayload`,用 `<RuntimeBox>` 渲染所有实例,支持 IntersectionObserver 渐进 mount + 视口外缓冲 dispose
|
|
16
|
+
- **`createRenderScheduler`** — 渲染调度器 composable:管理实例级 mount/dispose 状态机,与渲染组件解耦
|
|
17
|
+
- **协议类型** — PageDocument / PageRenderPayload / ComponentContract / ComponentVersionKey 等完整类型导出
|
|
18
|
+
- **helper** — `isDraftKey()` / `parseComponentVersionKey()` 用于区分正式版本 vs 编辑期草稿
|
|
19
|
+
|
|
20
|
+
SDK 边界铁律:
|
|
21
|
+
|
|
22
|
+
- **不 fetch** — 所有数据由宿主通过 props 传入
|
|
23
|
+
- **不知后端** — 不依赖任何特定后端 schema / API
|
|
24
|
+
- **不开 Drawer / Dialog** — UI 交互由宿主控制
|
|
25
|
+
- **不绑定 UI 框架** — 不强依赖 Element Plus / Pinia / Monaco
|
|
26
|
+
|
|
27
|
+
---
|
|
28
|
+
|
|
29
|
+
## 快速开始
|
|
30
|
+
|
|
31
|
+
```bash
|
|
32
|
+
pnpm add @hy-bricks/canvas @hy-bricks/core vue
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
```vue
|
|
36
|
+
<script setup lang="ts">
|
|
37
|
+
import { HyperCardPageRenderer } from '@hy-bricks/canvas'
|
|
38
|
+
import type { PageRenderPayload } from '@hy-bricks/canvas'
|
|
39
|
+
|
|
40
|
+
const payload: PageRenderPayload = {
|
|
41
|
+
page: { id: 'p1', name: 'Demo', targets: ['pc'] },
|
|
42
|
+
version: { version: 'v1', label: 'v1', publishedAt: '2026-05-11T00:00:00Z' },
|
|
43
|
+
document: {
|
|
44
|
+
layout: { type: 'free', canvas: { w: 1920, h: 1080 } },
|
|
45
|
+
instances: [
|
|
46
|
+
{
|
|
47
|
+
instanceId: 'inst-1',
|
|
48
|
+
componentId: 'button',
|
|
49
|
+
componentVersionKey: 'button@v1',
|
|
50
|
+
rect: { x: 100, y: 100, w: 200, h: 60 },
|
|
51
|
+
zIndex: 1,
|
|
52
|
+
props: {},
|
|
53
|
+
},
|
|
54
|
+
],
|
|
55
|
+
bindings: [],
|
|
56
|
+
},
|
|
57
|
+
componentVersions: {
|
|
58
|
+
'button@v1': {
|
|
59
|
+
key: 'button@v1',
|
|
60
|
+
componentId: 'button',
|
|
61
|
+
version: 'v1',
|
|
62
|
+
status: 'ok',
|
|
63
|
+
source: {
|
|
64
|
+
html: '<el-button @click="say">{{ msg }}</el-button>',
|
|
65
|
+
js: 'export default { data(){ return { msg:"Hi" } }, methods:{ say(){ this.msg="Clicked" } } }',
|
|
66
|
+
css: '',
|
|
67
|
+
},
|
|
68
|
+
contract: {
|
|
69
|
+
propsDecl: [],
|
|
70
|
+
emitsDecl: [],
|
|
71
|
+
methodsDecl: [{ key: 'say', params: [] }],
|
|
72
|
+
slotsDecl: [],
|
|
73
|
+
modelDecl: [],
|
|
74
|
+
dataInputsDecl: [],
|
|
75
|
+
dataOutputsDecl: [],
|
|
76
|
+
},
|
|
77
|
+
},
|
|
78
|
+
},
|
|
79
|
+
}
|
|
80
|
+
</script>
|
|
81
|
+
|
|
82
|
+
<template>
|
|
83
|
+
<HyperCardPageRenderer :payload="payload" />
|
|
84
|
+
</template>
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
---
|
|
88
|
+
|
|
89
|
+
## API 概览
|
|
90
|
+
|
|
91
|
+
### 组件:`<HyperCardPageRenderer>`
|
|
92
|
+
|
|
93
|
+
只读页面渲染器。接受宿主拼好的 payload 或拆开的 document + sourceMap。
|
|
94
|
+
|
|
95
|
+
**Props:**
|
|
96
|
+
|
|
97
|
+
| Prop | 类型 | 默认值 | 说明 |
|
|
98
|
+
|---|---|---|---|
|
|
99
|
+
| `payload` | `PageRenderPayload?` | — | `/render` 端点产物(含 document + componentVersions)。优先使用 |
|
|
100
|
+
| `document` | `PageDocument?` | — | 页面结构(payload 为空时使用,设计器场景) |
|
|
101
|
+
| `componentSourceMap` | `ComponentSourceMap?` | — | 组件版本 source 字典(payload 为空时使用) |
|
|
102
|
+
| `schedulerOptions` | `RenderSchedulerOptions?` | — | 调度器配置(透传给 createRenderScheduler) |
|
|
103
|
+
|
|
104
|
+
**行为:**
|
|
105
|
+
- 每个 `PageInstance` 渲染一个 wrapper div(absolute 定位)+ `<RuntimeBox>`
|
|
106
|
+
- 视口内:渐进 mount(每 idle frame 最多 N 个)
|
|
107
|
+
- 视口外:缓冲一段(默认 1500ms)后 dispose,滚回来 LRU 命中不重编
|
|
108
|
+
- `status !== 'ok'` 的实例渲染降级卡,不阻断整页
|
|
109
|
+
|
|
110
|
+
### Composable:`createRenderScheduler`
|
|
111
|
+
|
|
112
|
+
渲染调度器 — 管理实例级 `pending → mounting → mounted → disposing` 状态机。
|
|
113
|
+
|
|
114
|
+
```ts
|
|
115
|
+
import { createRenderScheduler } from '@hy-bricks/canvas'
|
|
116
|
+
|
|
117
|
+
const scheduler = createRenderScheduler({
|
|
118
|
+
rootMargin: '500px', // 视口缓冲
|
|
119
|
+
disposeDelayMs: 1500, // 视口外延迟 dispose
|
|
120
|
+
mountConcurrency: 2, // 每帧最多挂 2 个
|
|
121
|
+
})
|
|
122
|
+
|
|
123
|
+
scheduler.register('inst-1', element) // 注册实例 + 开始观察
|
|
124
|
+
scheduler.unregister('inst-1') // 停止观察 + 清单实例 state
|
|
125
|
+
scheduler.isMounted('inst-1') // boolean — Vue 模板 reactive 跟踪
|
|
126
|
+
scheduler.getState('inst-1') // MountState — 渲染 RuntimeBox vs skeleton 判别
|
|
127
|
+
scheduler.dispose() // 全量清理(取消 IO + 清 timer + 清 state),onBeforeUnmount 调
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
**配置(`RenderSchedulerOptions`):**
|
|
131
|
+
|
|
132
|
+
| 字段 | 类型 | 默认值 | 说明 |
|
|
133
|
+
|---|---|---|---|
|
|
134
|
+
| `rootMargin` | `string` | `'500px'` | IntersectionObserver 视口缓冲距离 |
|
|
135
|
+
| `disposeDelayMs` | `number` | `1500` | 视口外多久才真 dispose |
|
|
136
|
+
| `mountConcurrency` | `number` | `2` | 渐进 mount 每帧个数 |
|
|
137
|
+
| `root` | `Element?` | `null`(viewport) | IntersectionObserver root(画布自有滚动容器时传) |
|
|
138
|
+
|
|
139
|
+
**状态(`MountState`):**
|
|
140
|
+
|
|
141
|
+
| 状态 | 说明 |
|
|
142
|
+
|---|---|
|
|
143
|
+
| `pending` | 已注册,未进入视口 |
|
|
144
|
+
| `mounting` | 已进入视口,排队等 idle frame |
|
|
145
|
+
| `mounted` | 已挂载,正在渲染 |
|
|
146
|
+
| `disposing` | 已离开视口,缓冲倒计时中 |
|
|
147
|
+
|
|
148
|
+
### 协议类型
|
|
149
|
+
|
|
150
|
+
从 `@hy-bricks/canvas` 直接 import,不需要额外装包:
|
|
151
|
+
|
|
152
|
+
```ts
|
|
153
|
+
import type {
|
|
154
|
+
// 基础
|
|
155
|
+
Source,
|
|
156
|
+
// ComponentVersionKey
|
|
157
|
+
ComponentVersionKey,
|
|
158
|
+
ParsedComponentVersionKey,
|
|
159
|
+
// ComponentContract(7 字段)
|
|
160
|
+
PropDecl,
|
|
161
|
+
EmitDecl,
|
|
162
|
+
MethodDecl,
|
|
163
|
+
SlotDecl,
|
|
164
|
+
ModelDecl,
|
|
165
|
+
DataInputDecl,
|
|
166
|
+
DataOutputDecl,
|
|
167
|
+
ComponentContract,
|
|
168
|
+
ComponentKind,
|
|
169
|
+
// ComponentVersionAsset
|
|
170
|
+
ComponentVersionStatus,
|
|
171
|
+
ComponentVersionAsset,
|
|
172
|
+
DraftComponentVersionAsset,
|
|
173
|
+
// Page 结构
|
|
174
|
+
PageInstance,
|
|
175
|
+
PageBinding,
|
|
176
|
+
PageLayout,
|
|
177
|
+
PageDocument,
|
|
178
|
+
PageRenderPayload,
|
|
179
|
+
ComponentSourceMap,
|
|
180
|
+
// 版本状态 / 特性开关
|
|
181
|
+
CanvasVersionStatus,
|
|
182
|
+
CanvasFeatures,
|
|
183
|
+
// 组件库面板
|
|
184
|
+
ComponentCatalogItem,
|
|
185
|
+
} from '@hy-bricks/canvas'
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
### Helper
|
|
189
|
+
|
|
190
|
+
```ts
|
|
191
|
+
import { isDraftKey, parseComponentVersionKey } from '@hy-bricks/canvas'
|
|
192
|
+
|
|
193
|
+
isDraftKey('button@v3') // false
|
|
194
|
+
isDraftKey('button@draft:p1:v3') // true
|
|
195
|
+
|
|
196
|
+
parseComponentVersionKey('button@v3')
|
|
197
|
+
// → { kind: 'published', componentId: 'button', version: 'v3' }
|
|
198
|
+
|
|
199
|
+
parseComponentVersionKey('button@draft:p1:v3')
|
|
200
|
+
// → { kind: 'draft', componentId: 'button', pageId: 'p1',
|
|
201
|
+
// baseVersion: 'v3', baseVersionKey: 'button@v3' }
|
|
202
|
+
|
|
203
|
+
parseComponentVersionKey('garbage')
|
|
204
|
+
// → null
|
|
205
|
+
```
|
|
206
|
+
|
|
207
|
+
---
|
|
208
|
+
|
|
209
|
+
## 性能特性
|
|
210
|
+
|
|
211
|
+
得益于 IntersectionObserver 渐进 mount + LRU 编译缓存,在数十到上百个实例的页面上仍能保持流畅:
|
|
212
|
+
|
|
213
|
+
- **首屏骨架(skeleton)**:payload 到达后即出占位框,不阻塞首屏
|
|
214
|
+
- **渐进挂载**:视口内实例按 idle frame 节流挂载,避免单帧卡顿
|
|
215
|
+
- **滚动重用**:视口外延迟 dispose + 滚回 LRU 命中,组件不重新编译
|
|
216
|
+
|
|
217
|
+
---
|
|
218
|
+
|
|
219
|
+
## 配合使用 / Ecosystem
|
|
220
|
+
|
|
221
|
+
- [@hy-bricks/core](https://www.npmjs.com/package/@hy-bricks/core) — 运行时核心(canvas 的 peerDep)
|
|
222
|
+
- [@hy-bricks/editor](https://www.npmjs.com/package/@hy-bricks/editor) — 嵌入式编辑器(组件源码 IDE)
|
|
223
|
+
- [@hy-bricks/devtools](https://www.npmjs.com/package/@hy-bricks/devtools) — 运行时诊断浮窗
|
|
224
|
+
|
|
225
|
+
## License
|
|
226
|
+
|
|
227
|
+
[MIT](./LICENSE) © hy_top
|