@printstack/print-studio 0.1.0 → 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 (72) hide show
  1. package/README.md +122 -154
  2. package/assets/render.worker-DkH7TepL.js +109 -0
  3. package/{cloneDeep-C5UZRjbH.js → cloneDeep-waBDTGc3.js} +10 -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/dialogs/preview-dialog.vue.d.ts +10 -1
  16. package/designer/components/dialogs/print-preview-dialog.vue.d.ts +14 -0
  17. package/designer/components/dialogs/print-preview-source.d.ts +22 -0
  18. package/designer/components/dialogs/use-document-preview.d.ts +5 -1
  19. package/designer/components/dialogs/use-preview-renderer.d.ts +2 -0
  20. package/designer/components/dialogs/use-print-preview.d.ts +33 -0
  21. package/designer/components/fields/use-table-draft.d.ts +0 -4
  22. package/designer/components/panels/layer-row-types.d.ts +37 -0
  23. package/designer/components/panels/layer-row.vue.d.ts +17 -0
  24. package/designer/components/stage/marquee-overlay.vue.d.ts +8 -0
  25. package/designer/components/stage/node-style.d.ts +3 -0
  26. package/designer/components/stage/selection-member.vue.d.ts +14 -0
  27. package/designer/composables/use-theme.d.ts +3 -0
  28. package/designer/facade/editing.d.ts +2 -2
  29. package/designer/facade/entities.d.ts +1156 -22
  30. package/designer/facade/output.d.ts +2 -2
  31. package/designer/frame/print-designer-frame.vue.d.ts +2 -2
  32. package/designer/frame/shared.d.ts +2 -0
  33. package/designer/frame/view.d.ts +9 -0
  34. package/designer/interactions/marquee.d.ts +1 -1
  35. package/designer/interactions/move.d.ts +3 -1
  36. package/designer/mount-print-designer.d.ts +1 -1
  37. package/designer/mount-print-preview.d.ts +5 -0
  38. package/designer/plugins/plugin-manager.d.ts +3 -3
  39. package/designer/plugins/types.d.ts +1 -1
  40. package/designer/print-designer.vue.d.ts +2 -2
  41. package/designer/print-preview.vue.d.ts +4 -0
  42. package/designer/stores/document-store.d.ts +72 -0
  43. package/designer/stores/editor-store.d.ts +770 -14
  44. package/designer/stores/page-store.d.ts +25 -1
  45. package/designer/stores/template-store.d.ts +52 -4
  46. package/designer/stores/types.d.ts +1 -0
  47. package/designer/stores/ui-store.d.ts +232 -3
  48. package/designer/stores/view-store.d.ts +10 -1
  49. package/designer.d.ts +1 -1
  50. package/designer.js +3 -3
  51. package/{document-model-DC9sn2WV.js → document-model-Cc5RoO4j.js} +160 -179
  52. package/elements/table/table-style.d.ts +3 -10
  53. package/host-OAp3gFDx.js +123 -0
  54. package/index.js +5 -5
  55. package/locales/runtime.d.ts +8 -2
  56. package/locales/translations/zh-CN/app.json.d.ts +1 -0
  57. package/locales/translations/zh-CN/designer.json.d.ts +9 -4
  58. package/{mount-print-designer-BzHLGlv-.js → mount-print-designer-DnHTrBE9.js} +4 -3
  59. package/mount-print-preview-Bcb08lJ-.js +66 -0
  60. package/package.json +1 -1
  61. package/presets-BunYODhE.js +13 -0
  62. package/{registries-BOU8RLim.js → registries-sg39PGF1.js} +793 -790
  63. package/runtime/browser-output.d.ts +2 -0
  64. package/runtime.js +4 -4
  65. package/{saas-B3fJOgHX.js → saas-D-q51uTz.js} +1 -1
  66. package/saas.js +1 -1
  67. package/{studio-C_rqbJ9q.js → studio-B3B6zI06.js} +830 -754
  68. package/studio-types.d.ts +3 -2
  69. package/style.css +1 -1
  70. package/vue.js +1035 -941
  71. package/assets/render.worker-Cfbk18NW.js +0 -109
  72. package/presets-Cwp20ef6.js +0 -133
package/README.md CHANGED
@@ -6,231 +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: '张女士' } }
77
+ import { createPrintStudio } from '@printstack/print-studio'
100
78
 
101
- // 全屏预览层展示,用户自行关闭
102
- await studio.preview(input)
79
+ const studio = createPrintStudio()
103
80
 
104
- // 需要编程控制时使用返回的句柄
105
- const handle = await studio.preview(input)
106
- handle.close()
81
+ // 加载系统已有模板数据(不挂载设计器)
82
+ studio.document.loadJson(templateJson)
107
83
 
108
- // 或嵌入页面指定容器(容器需要有明确高度)
109
- await studio.preview(input, {
110
- container: document.querySelector('#preview-box')!,
111
- })
84
+ // 业务数据渲染 + 输出
85
+ await studio.print({ orderNo: 'A001' })
86
+ const { blob } = await studio.toPDF({ orderNo: 'A001' })
112
87
  ```
113
88
 
114
- ### 打印
89
+ 不需要界面时直接用 `createPrintStudio()`,即可完成加载模板、注入数据、预览、打印、导出。不需要任何编辑 UI 时,可用更轻量的纯输出运行时 `createPrintRenderer()`,详见 [createPrintRenderer() 参考](https://print-studio-docs.github.io/reference/renderer)。
115
90
 
116
- `studio.print(input)` 注入数据后调用浏览器打印,在浏览器打印对话框中由用户确认:
91
+ ## 模板保存到自己的系统
92
+
93
+ 模板在设计器中就是一份 JSON 文档(`PrintDocument`),接入点是 `onSave` 回调:
117
94
 
118
95
  ```ts
119
- 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
+ })
120
102
  ```
121
103
 
122
- 注意事项:
104
+ - 触发途径:界面「保存」按钮、文件菜单的保存命令,或代码调用 `studio.document.save()`。`save()` 返回只表示回调执行完成。
105
+ - 若未提供 `onSave`,界面保存能力不可用(`studio.document.dirty` 仍正常)。
106
+ - 程序化获取当前文档:`studio.document.data`;导出 JSON 字符串:`studio.export.json()`。
107
+ - 文档有未保存修改时 `studio.document.dirty` 为 `true`,可用于自己的保存提示;挂载方式可另传 `onDirtyChange` 监听脏状态。
123
108
 
124
- - `print()` 返回仅表示打印任务已提交,不代表用户确认或设备出纸成功。
125
- - 输出界面渲染在隐藏 iframe 中完成;需要时可通过 `signal` 与 `timeoutMs` 控制取消与超时:
109
+ ## 加载系统已有模板
110
+
111
+ 两种途径:
112
+
113
+ **代码加载**(嵌入与非嵌入方式都适用):
126
114
 
127
115
  ```ts
128
- const controller = new AbortController()
129
- await studio.print(input, { signal: controller.signal, timeoutMs: 15_000 })
116
+ // 字符串 JSON
117
+ studio.document.loadJson(json)
118
+ // 对象
119
+ studio.document.load(document)
130
120
  ```
131
121
 
132
- ### 导出
133
-
134
- `studio.toHTML(input)` 生成独立 HTML 字符串,`studio.toPDF(input)` 生成 PDF Blob,交给宿主下载或上传:
122
+ 创建实例时直接带入初始模板:
135
123
 
136
124
  ```ts
137
- // HTML:返回 { html, warnings }
138
- const { html } = await studio.toHTML(input)
139
-
140
- // PDF:返回 { blob, warnings };以下载为例
141
- const { blob } = await studio.toPDF(input)
142
- const url = URL.createObjectURL(blob)
143
- const link = document.createElement('a')
144
- link.href = url
145
- link.download = 'order.pdf'
146
- link.click()
147
- URL.revokeObjectURL(url)
125
+ const studio = usePrintStudio({ initialDocument: myTemplate })
148
126
  ```
149
127
 
150
- ## 第三方系统集成示例
151
-
152
- 以 ERP 订单打印为例。典型接入方式:模板在设计器中定稿后以 JSON 保存到业务系统;业务页面调用打印服务,加载模板、注入订单数据,提供预览与打印:
128
+ **接入模板库**(让用户在设计器「文件 > 模板库」中浏览、选用、上传、维护系统模板):
153
129
 
154
130
  ```ts
155
- // print-service.ts —— ERP 订单打印服务
156
- import { createPrintStudio, type DesignStudio } from '@printstack/print-studio'
157
-
158
- interface Order {
159
- number: string
160
- customer: string
161
- }
162
-
163
- let studio: DesignStudio | undefined
164
-
165
- function getStudio(): DesignStudio {
166
- studio ??= createPrintStudio({ storage: false })
167
- return studio
168
- }
169
-
170
- /** 加载业务系统保存的订单模板 JSON;模板更新频率低时可缓存加载结果 */
171
- async function loadOrderTemplate(): Promise<void> {
172
- const response = await fetch('/api/templates/order')
173
- getStudio().document.loadJson(await response.text())
174
- }
175
-
176
- /** 点击「打印预览」:打开预览层,用户核对后关闭 */
177
- export async function previewOrder(order: Order): Promise<void> {
178
- await loadOrderTemplate()
179
- await getStudio().preview({ order })
180
- }
181
-
182
- /** 点击「打印」:浏览器打印对话框中确认 */
183
- export async function printOrder(order: Order): Promise<void> {
184
- await loadOrderTemplate()
185
- await getStudio().print({ order })
186
- }
187
-
188
- /** 点击「导出 PDF」:拿到 Blob 后下载或上传 */
189
- export async function exportOrderPdf(order: Order): Promise<Blob> {
190
- await loadOrderTemplate()
191
- const { blob } = await getStudio().toPDF({ order })
192
- return blob
193
- }
194
-
195
- /** 应用退出时释放 */
196
- export function destroyPrintService(): void {
197
- studio?.dispose()
198
- studio = undefined
199
- }
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)
200
155
  ```
201
156
 
202
- 业务页面只需调用这些函数:
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`:
203
170
 
204
171
  ```ts
205
- printButton.addEventListener('click', () => printOrder(currentOrder))
172
+ usePrintStudio({ storage: false, onSave })
206
173
  ```
207
174
 
208
- 模板已定稿、不再需要设计器界面时,改用纯输出运行时 `createPrintRenderer()`,不加载任何编辑 UI。注意参数顺序为模板在前、数据在后:
175
+ 需要把草稿/偏好存到服务端或 IndexedDB 时,实现对应接口传入即可。
209
176
 
210
- ```ts
211
- import { createPrintRenderer } from '@printstack/print-studio/runtime'
212
- import { deserializeDocument } from '@printstack/print-studio/core'
177
+ ## 在业务场景中预览与打印
213
178
 
214
- const renderer = createPrintRenderer()
179
+ 拿到模板和业务数据后,输出入口都接受 `input`(数据源值,键需与模板中的数据绑定一致):
215
180
 
216
- // 业务保存的模板 JSON:解析后可先经 deserializeDocument 校验补全
217
- const { document: template } = deserializeDocument(
218
- JSON.parse(savedTemplateJson),
219
- )
181
+ ```ts
182
+ // 预览:打开成品视图,返回句柄,用完 dispose()
183
+ const handle = await studio.preview({ orderNo: 'A001' })
184
+ handle.dispose()
220
185
 
221
- const input = { order: { number: 'SO-20261114-001' } }
222
- const { blob } = await renderer.toPDF(template, input)
223
- await renderer.print(template, input)
186
+ // 打印:提交浏览器打印任务;resolve 表示任务已提交,不代表用户确认或设备出纸
187
+ await studio.print({ orderNo: 'A001' })
224
188
 
225
- renderer.dispose()
189
+ // 导出
190
+ const { blob } = await studio.toPDF({ orderNo: 'A001' })
191
+ const { html } = await studio.toHTML({ orderNo: 'A001' })
226
192
  ```
227
193
 
194
+ 批量打印、PDF 批量导出等进阶输出见教程 [批量打印与批量导出](https://print-studio-docs.github.io/tutorial/batch)。
195
+
228
196
  ## 更多功能与完整文档
229
197
 
230
198
  > 更多高级功能、详细配置说明及完整 API 文档,请访问 [Print Studio 官方文档](https://print-studio-docs.github.io)。
231
199
 
232
- - [快速开始](https://print-studio-docs.github.io/guide/getting-started):从创建项目到预览、打印的完整流程
233
200
  - [循序渐进教程](https://print-studio-docs.github.io/tutorial/):模板设计、页面尺寸、元素绘制、数据绑定、保存加载、批量打印
201
+ - [API 参考](https://print-studio-docs.github.io/reference/studio):`createPrintStudio()` 与工作区 API
234
202
  - [数据绑定参考](https://print-studio-docs.github.io/reference/data-binding):数据源声明、表达式与格式化器
235
203
  - [预览 / 打印 / 导出 API](https://print-studio-docs.github.io/reference/output):输出选项、取消与超时、批量输出
236
204
  - [Vue 集成](https://print-studio-docs.github.io/reference/vue-designer):组件 props、事件与上下文