@printstack/print-studio 0.1.1 → 0.1.2

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 (58) hide show
  1. package/README.md +121 -160
  2. package/assets/render.worker-DkH7TepL.js +109 -0
  3. package/{cloneDeep-PCw2ErRl.js → cloneDeep-waBDTGc3.js} +9 -4
  4. package/components/print-s-logo/print-s-logo.vue.d.ts +1 -1
  5. package/components/s-form/types.d.ts +1 -1
  6. package/core/coordinate-space.d.ts +16 -0
  7. package/core/document-model.d.ts +1 -1
  8. package/core/element-registry.d.ts +3 -8
  9. package/core/page-extensions.d.ts +1 -1
  10. package/core/types.d.ts +8 -0
  11. package/core.js +2 -2
  12. package/designer/commands/menu-adapter.d.ts +3 -3
  13. package/designer/commands/menu-types.d.ts +8 -1
  14. package/designer/commands/types.d.ts +2 -0
  15. package/designer/components/fields/use-table-draft.d.ts +0 -4
  16. package/designer/components/panels/layer-row-types.d.ts +37 -0
  17. package/designer/components/panels/layer-row.vue.d.ts +17 -0
  18. package/designer/components/stage/marquee-overlay.vue.d.ts +8 -0
  19. package/designer/components/stage/node-style.d.ts +3 -0
  20. package/designer/components/stage/selection-member.vue.d.ts +14 -0
  21. package/designer/composables/use-theme.d.ts +3 -0
  22. package/designer/facade/editing.d.ts +2 -2
  23. package/designer/facade/entities.d.ts +1156 -22
  24. package/designer/frame/view.d.ts +2 -0
  25. package/designer/interactions/marquee.d.ts +1 -1
  26. package/designer/interactions/move.d.ts +3 -1
  27. package/designer/mount-print-designer.d.ts +1 -1
  28. package/designer/plugins/plugin-manager.d.ts +3 -3
  29. package/designer/plugins/types.d.ts +1 -1
  30. package/designer/stores/document-store.d.ts +72 -0
  31. package/designer/stores/editor-store.d.ts +770 -14
  32. package/designer/stores/page-store.d.ts +25 -1
  33. package/designer/stores/template-store.d.ts +52 -4
  34. package/designer/stores/types.d.ts +1 -0
  35. package/designer/stores/ui-store.d.ts +232 -3
  36. package/designer/stores/view-store.d.ts +10 -1
  37. package/designer.d.ts +1 -1
  38. package/designer.js +3 -3
  39. package/{document-model-GhFP9OGp.js → document-model-Cc5RoO4j.js} +160 -179
  40. package/elements/table/table-style.d.ts +3 -10
  41. package/host-OAp3gFDx.js +123 -0
  42. package/index.js +5 -5
  43. package/locales/runtime.d.ts +7 -2
  44. package/locales/translations/zh-CN/designer.json.d.ts +9 -4
  45. package/{mount-print-designer-BLgVZOnm.js → mount-print-designer-DnHTrBE9.js} +4 -4
  46. package/{mount-print-preview-D7M-1AqH.js → mount-print-preview-Bcb08lJ-.js} +4 -3
  47. package/package.json +1 -1
  48. package/{presets-D3WhkbZK.js → presets-BunYODhE.js} +2 -2
  49. package/{registries-dZq8MewR.js → registries-sg39PGF1.js} +767 -780
  50. package/runtime.js +2 -2
  51. package/{saas-B1H161e1.js → saas-D-q51uTz.js} +1 -1
  52. package/saas.js +1 -1
  53. package/{studio-BFQYHZsg.js → studio-B3B6zI06.js} +796 -722
  54. package/studio-types.d.ts +1 -1
  55. package/style.css +1 -1
  56. package/vue.js +786 -693
  57. package/assets/render.worker-Ch4qWx3S.js +0 -109
  58. package/host-CuGR8rD6.js +0 -123
package/README.md CHANGED
@@ -6,238 +6,199 @@
6
6
  - **数据绑定**:字符串属性 `{{ 路径 | 格式化器 }}` 注入业务数据,表格跨页续排、循环区块展开明细。
7
7
  - **输出**:浏览器预览与打印、独立 HTML、PDF Blob。全部在浏览器内完成,无服务端依赖,打印数据由调用方传入。
8
8
 
9
- ## 安装
9
+ > **完整文档(API 参考、教程、示例、演练场)请访问 [https://print-studio-docs.github.io](https://print-studio-docs.github.io)**。
10
10
 
11
- 预览、打印和 PDF 导出依赖浏览器 DOM / Canvas,不支持 Node.js / SSR。发布包为纯 ESM,Vue、Pinia 等运行时依赖随包自动安装,非 Vue 项目无需编写 Vue 组件;样式已随隔离 iframe 内联加载,无需手动导入。
11
+ ## 安装
12
12
 
13
13
  ```bash
14
14
  npm install @printstack/print-studio
15
+ ```
15
16
 
16
- # 或
17
+ ```bash
17
18
  pnpm add @printstack/print-studio
19
+ ```
20
+
21
+ ```bash
18
22
  yarn add @printstack/print-studio
19
23
  ```
20
24
 
21
- ### 包导出入口
25
+ ### 环境要求与兼容范围
22
26
 
23
- | 导入路径 | 内容 |
24
- | --- | --- |
25
- | `@printstack/print-studio` | `createPrintStudio()` 工作区工厂与公共类型 |
26
- | `@printstack/print-studio/vue` | `PrintDesigner` 组件、`usePrintStudio()` |
27
- | `@printstack/print-studio/designer` | `mountPrintDesigner()` 命令式挂载 |
28
- | `@printstack/print-studio/runtime` | `createPrintRenderer()` 纯输出运行时 |
29
- | `@printstack/print-studio/core` | 文档模型与工具(`deserializeDocument()` 等) |
27
+ - **浏览器**:Chrome / Edge / Firefox / Safari 现代版本;系统打印行为由浏览器决定,建议按目标浏览器实际验收。
28
+ - **模块格式**:纯 ESM 包,不提供 CommonJS 接入。Vue、Pinia 等运行时依赖随包自动安装,非 Vue 项目无需编写 Vue 组件;样式已随隔离 iframe 内联加载,无需手动导入。
29
+ - **Node.js / SSR**:模板渲染依赖浏览器 DOM / Canvas,不在服务端直接运行;服务端输出需以无头浏览器等宿主承载。
30
+ - **PDF / 图片 / 字体**:浏览器资源加载与跨域策略参与输出结果,需用实际资源验证。
31
+ - **移动端**:可打开文档;设计器需要足够的容器宽高。
30
32
 
31
- ## 基础使用
33
+ ## 选择接入方式
32
34
 
33
- ### 引入与初始化
35
+ 按业务场景二选一,两种方式可同时使用:
34
36
 
35
- `createPrintStudio()` 创建工作区实例,`mount()` 把可视化设计器挂载到业务页面的容器。适用于任意前端框架:
37
+ | 接入方式 | 适用场景 | 需要的能力 |
38
+ | --- | --- | --- |
39
+ | **嵌入设计器** | 让用户在系统内可视化设计、维护模板 | `PrintDesigner` 组件(Vue)或 `studio.mount()`(任意技术栈) |
40
+ | **仅输出,不嵌设计器** | 只在业务页面用已有模板渲染数据、预览打印 | 仅 `createPrintStudio()`,不调用 `mount()`;或更轻量的 `createPrintRenderer()` |
36
41
 
37
- ```ts
38
- import { createPrintStudio } from '@printstack/print-studio'
42
+ 不嵌入设计器时,设计器视图与相关插件代码不会加载(视图运行时按需加载)。
43
+
44
+ ### 方式一:嵌入设计器(Vue 应用)
39
45
 
40
- // 1. 创建工作区
41
- const studio = createPrintStudio({
42
- storage: false, // 关闭自动草稿,由 onSave 决定保存时机
43
- async onSave(document) {
44
- // 收到文档对象(非 JSON 字符串);等待持久化完成后再 resolve,失败抛错
46
+ ```vue
47
+ <script setup lang="ts">
48
+ import { PrintDesigner, usePrintStudio } from '@printstack/print-studio/vue'
49
+
50
+ const studio = usePrintStudio({
51
+ storage: false, // 关闭自动草稿,见下文「配置偏好与草稿」
52
+ onSave: async (document) => {
45
53
  await fetch('/api/templates', {
46
54
  method: 'POST',
47
55
  body: JSON.stringify(document),
48
56
  })
49
57
  },
50
58
  })
51
-
52
- // 2. 挂载设计器界面;resolve 即界面就绪
53
- await studio.mount({ el: '#designer' })
54
-
55
- // 3. 编辑模板:代码与设计器界面操作同一份文档
56
- const page = studio.page.active
57
- const cell = page.elements.add({
58
- type: 'text',
59
- x: 20,
60
- y: 30,
61
- width: 100,
62
- height: 12,
63
- })
64
- page.elements.updateProps(cell, { text: '订单号:{{ order.number }}' })
65
-
66
- // 4. 页面退出时释放工作区
67
- // studio.unmount() // 仅卸载界面,文档保留,可再次 mount
68
- // studio.dispose() // 彻底释放
69
- ```
70
-
71
- 要点:
72
-
73
- - `el` 接受元素或 CSS 选择器,**容器需要有明确高度**,设计器界面填满其容器。
74
- - 界面配置(`ui` / `settings` / `plugins` / `zIndex`)与回调(`onDirtyChange` / `onError`)作为 `mount()` 选项传入,工作区创建选项仍在 `createPrintStudio()` 中配置。
75
- - 不传 `initialDocument` 时默认打开内置欢迎模板,可直接试用;业务模板通过 `initialDocument` 或 `studio.document.loadJson(json)` 加载。
76
- - 一个工作区同时只挂载一个设计器;`mount()` 失败或就绪前卸载会 reject,调用方应捕获并 `dispose()` 工作区。
77
-
78
- Vue 项目也可以使用组件方式。`usePrintStudio()` 在 setup 中创建同一工作区,页面卸载时自动清理:
79
-
80
- ```vue
81
- <script setup lang="ts">
82
- import { PrintDesigner, usePrintStudio } from '@printstack/print-studio/vue'
83
-
84
- const studio = usePrintStudio({ storage: false })
85
59
  </script>
86
60
 
87
61
  <template>
88
- <div style="height: 100vh">
62
+ <!-- 容器需要有明确高度 -->
63
+ <div style="height: 80vh">
89
64
  <PrintDesigner :studio="studio" />
90
65
  </div>
91
66
  </template>
92
67
  ```
93
68
 
94
- ### 预览
69
+ 要点:
70
+
71
+ - `usePrintStudio()` 在 setup 作用域中创建实例,页面卸载时自动 `dispose()`;组件与界面操作同一份文档。
72
+ - 通过 `studio.mount()` 也可把设计器挂载到任意容器(支持元素或 CSS 选择器),一个工作区同时只挂载一个设计器,可用 `unmount()` 移除后重新挂载。非 Vue 技术栈用这种方式。
95
73
 
96
- `studio.preview(input)` 注入本次业务数据并打开打印预览。默认以全屏预览层展示;`input` 是普通对象,属性路径与模板中 `{{ }}` 绑定对应:
74
+ ### 方式二:不嵌设计器,只做输出
97
75
 
98
76
  ```ts
99
- const input = { order: { number: 'SO-20261114-001', customer: '张女士' } }
100
-
101
- // 全屏预览层展示,用户自行关闭
102
- await studio.preview(input)
77
+ import { createPrintStudio } from '@printstack/print-studio'
103
78
 
104
- // 需要编程控制时使用返回的句柄
105
- const handle = await studio.preview(input)
106
- handle.close()
79
+ const studio = createPrintStudio()
107
80
 
108
- // 或嵌入页面指定容器(容器需要有明确高度)
109
- await studio.preview(input, {
110
- container: document.querySelector('#preview-box')!,
111
- })
81
+ // 加载系统已有模板数据(不挂载设计器)
82
+ studio.document.loadJson(templateJson)
112
83
 
113
- // 独立挂载完整打印预览,无需挂载设计器;支持 container,缺省挂到 body
114
- const designerPreview = await studio.preview(input, { mode: 'designer' })
115
- // 关闭时释放预览界面与渲染会话;也可在指定 container 中展示
116
- designerPreview.close()
84
+ // 业务数据渲染 + 输出
85
+ await studio.print({ orderNo: 'A001' })
86
+ const { blob } = await studio.toPDF({ orderNo: 'A001' })
117
87
  ```
118
88
 
119
- `mode: 'designer'` 使用调用时的文档与数据快照,独立显示带分页导航、缩放、数据编辑和打印操作的完整打印预览;不要求先调用 `studio.mount()`。预览窗口关闭后再调用 `studio.dispose()` 释放工作区。
89
+ 不需要界面时直接用 `createPrintStudio()`,即可完成加载模板、注入数据、预览、打印、导出。不需要任何编辑 UI 时,可用更轻量的纯输出运行时 `createPrintRenderer()`,详见 [createPrintRenderer() 参考](https://print-studio-docs.github.io/reference/renderer)。
120
90
 
121
- ### 打印
91
+ ## 模板保存到自己的系统
122
92
 
123
- `studio.print(input)` 注入数据后调用浏览器打印,在浏览器打印对话框中由用户确认:
93
+ 模板在设计器中就是一份 JSON 文档(`PrintDocument`),接入点是 `onSave` 回调:
124
94
 
125
95
  ```ts
126
- const { warnings } = await studio.print(input)
96
+ const studio = usePrintStudio({
97
+ onSave: async (document) => {
98
+ // document 为完整模板 JSON,存到你的数据库 / 接口
99
+ await saveToMySystem(templateId, JSON.stringify(document))
100
+ },
101
+ })
127
102
  ```
128
103
 
129
- 注意事项:
104
+ - 触发途径:界面「保存」按钮、文件菜单的保存命令,或代码调用 `studio.document.save()`。`save()` 返回只表示回调执行完成。
105
+ - 若未提供 `onSave`,界面保存能力不可用(`studio.document.dirty` 仍正常)。
106
+ - 程序化获取当前文档:`studio.document.data`;导出 JSON 字符串:`studio.export.json()`。
107
+ - 文档有未保存修改时 `studio.document.dirty` 为 `true`,可用于自己的保存提示;挂载方式可另传 `onDirtyChange` 监听脏状态。
130
108
 
131
- - `print()` 返回仅表示打印任务已提交,不代表用户确认或设备出纸成功。
132
- - 输出界面渲染在隐藏 iframe 中完成;需要时可通过 `signal` 与 `timeoutMs` 控制取消与超时:
109
+ ## 加载系统已有模板
110
+
111
+ 两种途径:
112
+
113
+ **代码加载**(嵌入与非嵌入方式都适用):
133
114
 
134
115
  ```ts
135
- const controller = new AbortController()
136
- await studio.print(input, { signal: controller.signal, timeoutMs: 15_000 })
116
+ // 字符串 JSON
117
+ studio.document.loadJson(json)
118
+ // 对象
119
+ studio.document.load(document)
137
120
  ```
138
121
 
139
- ### 导出
140
-
141
- `studio.toHTML(input)` 生成独立 HTML 字符串,`studio.toPDF(input)` 生成 PDF Blob,交给宿主下载或上传:
122
+ 创建实例时直接带入初始模板:
142
123
 
143
124
  ```ts
144
- // HTML:返回 { html, warnings }
145
- const { html } = await studio.toHTML(input)
146
-
147
- // PDF:返回 { blob, warnings };以下载为例
148
- const { blob } = await studio.toPDF(input)
149
- const url = URL.createObjectURL(blob)
150
- const link = document.createElement('a')
151
- link.href = url
152
- link.download = 'order.pdf'
153
- link.click()
154
- URL.revokeObjectURL(url)
125
+ const studio = usePrintStudio({ initialDocument: myTemplate })
155
126
  ```
156
127
 
157
- ## 第三方系统集成示例
158
-
159
- 以 ERP 订单打印为例。典型接入方式:模板在设计器中定稿后以 JSON 保存到业务系统;业务页面调用打印服务,加载模板、注入订单数据,提供预览与打印:
128
+ **接入模板库**(让用户在设计器「文件 > 模板库」中浏览、选用、上传、维护系统模板):
160
129
 
161
130
  ```ts
162
- // print-service.ts —— ERP 订单打印服务
163
- import { createPrintStudio, type DesignStudio } from '@printstack/print-studio'
164
-
165
- interface Order {
166
- number: string
167
- customer: string
168
- }
169
-
170
- let studio: DesignStudio | undefined
171
-
172
- function getStudio(): DesignStudio {
173
- studio ??= createPrintStudio({ storage: false })
174
- return studio
175
- }
176
-
177
- /** 加载业务系统保存的订单模板 JSON;模板更新频率低时可缓存加载结果 */
178
- async function loadOrderTemplate(): Promise<void> {
179
- const response = await fetch('/api/templates/order')
180
- getStudio().document.loadJson(await response.text())
181
- }
182
-
183
- /** 点击「打印预览」:打开预览层,用户核对后关闭 */
184
- export async function previewOrder(order: Order): Promise<void> {
185
- await loadOrderTemplate()
186
- await getStudio().preview({ order })
187
- }
188
-
189
- /** 点击「打印」:浏览器打印对话框中确认 */
190
- export async function printOrder(order: Order): Promise<void> {
191
- await loadOrderTemplate()
192
- await getStudio().print({ order })
193
- }
194
-
195
- /** 点击「导出 PDF」:拿到 Blob 后下载或上传 */
196
- export async function exportOrderPdf(order: Order): Promise<Blob> {
197
- await loadOrderTemplate()
198
- const { blob } = await getStudio().toPDF({ order })
199
- return blob
200
- }
201
-
202
- /** 应用退出时释放 */
203
- export function destroyPrintService(): void {
204
- studio?.dispose()
205
- studio = undefined
206
- }
131
+ import { definePlugin } from '@printstack/print-studio'
132
+ import { createRemoteTemplateProvider } from '@printstack/print-studio/designer'
133
+
134
+ const myTemplateLibrary = definePlugin({
135
+ manifest: {
136
+ apiVersion: '1.0',
137
+ id: 'my-company:templates',
138
+ version: '1.0.0',
139
+ permissions: ['templates'],
140
+ },
141
+ setup(ctx) {
142
+ return ctx.templateLibrary.register(
143
+ createRemoteTemplateProvider({
144
+ id: 'my-company:remote',
145
+ manifestUrl: '/api/templates/manifest',
146
+ title: () => '系统模板',
147
+ headers: { Authorization: `Bearer ${token}` },
148
+ }),
149
+ )
150
+ },
151
+ })
152
+
153
+ const studio = usePrintStudio()
154
+ studio.use(myTemplateLibrary)
207
155
  ```
208
156
 
209
- 业务页面只需调用这些函数:
157
+ - Provider 支持 `create` / `update` / `remove` 时,用户可在模板库中把当前文档存入你的系统、更新或删除已有模板。
158
+ - 不需要模板库时也可用 `studio.template.import()` 程序化导入模板对象。
159
+
160
+ ## 配置偏好与草稿
161
+
162
+ 两类自动持久化默认都写入 `localStorage`,均有开关和自定义存储接口:
163
+
164
+ | 配置项 | 默认行为 | 关闭 | 自定义存储 |
165
+ | --- | --- | --- | --- |
166
+ | **草稿(未保存的模板数据)** | 修改自动写入 `localStorage`(键 `print-studio:document`),下次打开自动恢复 | `storage: false` | `storage: { get(): string \| null, set(json) }`,实现 `DocumentStorage` 接口 |
167
+ | **偏好设置(主题等界面偏好)** | 变更时写入 `localStorage` | `persistPreferences: false` | `preferenceStorage: { get(key), set(key, value) }`,实现 `PreferenceStorage` 接口 |
168
+
169
+ 典型配置:宿主系统统一管理模板,关闭本地草稿,只信任 `onSave`:
210
170
 
211
171
  ```ts
212
- printButton.addEventListener('click', () => printOrder(currentOrder))
172
+ usePrintStudio({ storage: false, onSave })
213
173
  ```
214
174
 
215
- 模板已定稿、不再需要设计器界面时,改用纯输出运行时 `createPrintRenderer()`,不加载任何编辑 UI。注意参数顺序为模板在前、数据在后:
175
+ 需要把草稿/偏好存到服务端或 IndexedDB 时,实现对应接口传入即可。
216
176
 
217
- ```ts
218
- import { createPrintRenderer } from '@printstack/print-studio/runtime'
219
- import { deserializeDocument } from '@printstack/print-studio/core'
177
+ ## 在业务场景中预览与打印
220
178
 
221
- const renderer = createPrintRenderer()
179
+ 拿到模板和业务数据后,输出入口都接受 `input`(数据源值,键需与模板中的数据绑定一致):
222
180
 
223
- // 业务保存的模板 JSON:解析后可先经 deserializeDocument 校验补全
224
- const { document: template } = deserializeDocument(
225
- JSON.parse(savedTemplateJson),
226
- )
181
+ ```ts
182
+ // 预览:打开成品视图,返回句柄,用完 dispose()
183
+ const handle = await studio.preview({ orderNo: 'A001' })
184
+ handle.dispose()
227
185
 
228
- const input = { order: { number: 'SO-20261114-001' } }
229
- const { blob } = await renderer.toPDF(template, input)
230
- await renderer.print(template, input)
186
+ // 打印:提交浏览器打印任务;resolve 表示任务已提交,不代表用户确认或设备出纸
187
+ await studio.print({ orderNo: 'A001' })
231
188
 
232
- renderer.dispose()
189
+ // 导出
190
+ const { blob } = await studio.toPDF({ orderNo: 'A001' })
191
+ const { html } = await studio.toHTML({ orderNo: 'A001' })
233
192
  ```
234
193
 
194
+ 批量打印、PDF 批量导出等进阶输出见教程 [批量打印与批量导出](https://print-studio-docs.github.io/tutorial/batch)。
195
+
235
196
  ## 更多功能与完整文档
236
197
 
237
198
  > 更多高级功能、详细配置说明及完整 API 文档,请访问 [Print Studio 官方文档](https://print-studio-docs.github.io)。
238
199
 
239
- - [快速开始](https://print-studio-docs.github.io/guide/getting-started):从创建项目到预览、打印的完整流程
240
200
  - [循序渐进教程](https://print-studio-docs.github.io/tutorial/):模板设计、页面尺寸、元素绘制、数据绑定、保存加载、批量打印
201
+ - [API 参考](https://print-studio-docs.github.io/reference/studio):`createPrintStudio()` 与工作区 API
241
202
  - [数据绑定参考](https://print-studio-docs.github.io/reference/data-binding):数据源声明、表达式与格式化器
242
203
  - [预览 / 打印 / 导出 API](https://print-studio-docs.github.io/reference/output):输出选项、取消与超时、批量输出
243
204
  - [Vue 集成](https://print-studio-docs.github.io/reference/vue-designer):组件 props、事件与上下文