ppt-dsl-renderer 1.1.0
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/AGENT_PPTX_EXPORT.md +81 -0
- package/AGENT_USAGE.md +87 -0
- package/LICENSE +21 -0
- package/README.md +112 -0
- package/THIRD_PARTY_NOTICES.md +43 -0
- package/dist/browser/renderer.css +1 -0
- package/dist/browser/renderer.js +80 -0
- package/dist/cli.js +243 -0
- package/dist/index.js +140 -0
- package/dist/pptx/exporter.js +129 -0
- package/dist/pptx/index.js +7437 -0
- package/dist/vue/renderer.css +1 -0
- package/dist/vue/renderer.js +577 -0
- package/docs/AGENT.md +36 -0
- package/docs/DSL.md +60 -0
- package/docs/VUE.md +231 -0
- package/examples/deck.json +302 -0
- package/package.json +85 -0
- package/src/index.d.ts +24 -0
- package/src/pptx.d.ts +30 -0
- package/src/types/ppt-dsl.d.ts +241 -0
- package/src/types/vue.d.ts +40 -0
- package/src/vue.d.ts +16 -0
- package/third-party-licenses/core-util-is/LICENSE +19 -0
- package/third-party-licenses/dompurify/LICENSE +568 -0
- package/third-party-licenses/echarts/LICENSE +222 -0
- package/third-party-licenses/echarts/LICENSE-d3 +27 -0
- package/third-party-licenses/echarts/NOTICE +5 -0
- package/third-party-licenses/immediate/LICENSE.txt +20 -0
- package/third-party-licenses/inherits/LICENSE +16 -0
- package/third-party-licenses/isarray/LICENSE +22 -0
- package/third-party-licenses/jszip/LICENSE.markdown +651 -0
- package/third-party-licenses/lie/license.md +7 -0
- package/third-party-licenses/pako/LICENSE +21 -0
- package/third-party-licenses/pptxgenjs/LICENSE +21 -0
- package/third-party-licenses/readable-stream/LICENSE +47 -0
- package/third-party-licenses/safe-buffer/LICENSE +21 -0
- package/third-party-licenses/setimmediate/LICENSE.txt +20 -0
- package/third-party-licenses/string_decoder/LICENSE +48 -0
- package/third-party-licenses/svg-pathdata/LICENSE +20 -0
- package/third-party-licenses/tinycolor2/LICENSE +20 -0
- package/third-party-licenses/tslib/LICENSE.txt +12 -0
- package/third-party-licenses/util-deprecate/LICENSE +24 -0
- package/third-party-licenses/vue/LICENSE +21 -0
- package/third-party-licenses/vue-reactivity/LICENSE +21 -0
- package/third-party-licenses/vue-runtime-core/LICENSE +21 -0
- package/third-party-licenses/vue-runtime-dom/LICENSE +21 -0
- package/third-party-licenses/vue-shared/LICENSE +21 -0
- package/third-party-licenses/zrender/LICENSE +29 -0
package/docs/DSL.md
ADDED
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
# DSL 数据契约
|
|
2
|
+
|
|
3
|
+
完整 TypeScript 字段定义见 `src/types/ppt-dsl.d.ts`,通过包入口以类型导出。接口延续提取来源的实际渲染行为,存在类型字段并不意味着已经实现对应视觉功能。
|
|
4
|
+
|
|
5
|
+
## 文档与页面
|
|
6
|
+
|
|
7
|
+
```ts
|
|
8
|
+
{
|
|
9
|
+
title: string,
|
|
10
|
+
width: number,
|
|
11
|
+
height: number,
|
|
12
|
+
slides: Array<{
|
|
13
|
+
id: string,
|
|
14
|
+
background?: PptDslBackground,
|
|
15
|
+
elements: PptDslElement[],
|
|
16
|
+
}>,
|
|
17
|
+
theme?: PptDslTheme,
|
|
18
|
+
}
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
文档宽高必须是正的有限数值,单位为 CSS 像素,支持小数。`slides` 不可为空,单页允许空元素数组。元素 ID 在同一页内必须唯一,不同页可以复用。默认保留原文档页序;CLI/API 的页码从 1 开始。
|
|
22
|
+
|
|
23
|
+
元素 `left/top` 是页面坐标;除线条外,外框沿用 `width || 120`、`height || 40`、`rotate || 0` 的已有规则。元素按数组顺序叠放,后面的在上层,opacity 默认 1。页面边界会裁剪;不会缩小字体、自动调整布局或移动越界元素。
|
|
24
|
+
|
|
25
|
+
背景支持 solid、gradient、image。渐变支持 linear/radial,颜色停靠点单位为百分比。图片 `size` 沿用现有浏览器 CSS 赋值,推荐 cover/contain;类型中的 stretch 尚未映射为 CSS 的 `100% 100%`。
|
|
26
|
+
|
|
27
|
+
## 元素能力
|
|
28
|
+
|
|
29
|
+
| type | 主要字段与实际行为 |
|
|
30
|
+
| --- | --- |
|
|
31
|
+
| text | content 为富文本 HTML;支持 defaultColor、defaultFontName、fill、lineHeight、wordSpace、inset、vAlign、vertical、fixedHeight。DOMPurify 清理后显示。内联数值字重 550–699 沿用已有行为显示为 700。 |
|
|
32
|
+
| image | src;支持 fit、clip.range、flipH/V、radius、filters、outline、shadow、colorMask。clip.range 使用 0–1 归一化矩形坐标。 |
|
|
33
|
+
| shape | path 和 viewBox;支持填充、渐变、轮廓、阴影、翻转及 text 富文本。直接使用给定 path,不计算 pathFormula。 |
|
|
34
|
+
| line | start、end、color;支持实线/虚线/点线和箭头/圆点端点。width 表示线宽;外框来自端点差,最小宽高 24,不使用通用 rotate。 |
|
|
35
|
+
| chart | chartType、data.labels、data.legends、data.series;支持 area/bar/column/line/pie/radar/ring/scatter,沿用当前 ECharts 映射。支持主题色、文字色、线条色、平滑和堆叠,关闭动画。 |
|
|
36
|
+
| table | data 为行和单元格数组;单元格包含 id、text 和可选 style。支持 colWidths、cellMinHeight、outline、fill、colspan、rowspan。文本按纯文本显示;不自动补齐合并单元格结构。 |
|
|
37
|
+
| latex | 有 path 与 viewBox 时绘制 SVG,否则展示 latex 字符串。没有 KaTeX/MathJax,也不把公式源码自动排成数学公式。 |
|
|
38
|
+
| video | src 保留在 DSL 中但不加载;仅展示 poster,无封面时显示深色背景,忽略自动播放。 |
|
|
39
|
+
| audio | src 保留但不加载;展示图标与禁用态音频控件,忽略自动播放和循环。 |
|
|
40
|
+
|
|
41
|
+
## 资源与字体
|
|
42
|
+
|
|
43
|
+
结构化图片、背景、封面和媒体 src 只接受 HTTP(S) URL 或 data URL。不会转换相对路径,不读取本地文件,不下载素材。富文本中的图片也应使用这两种地址,不支持依赖外部页面 CSS 的排版。`class` 按输入绑定,但包不提供自定义 class 样式注入接口。
|
|
44
|
+
|
|
45
|
+
文字常用 p、h1–h5、span、strong、em、u、ol、ul、li 和内联样式。脚本及事件属性由 DOMPurify 移除。普通文字和形状文字默认字体为 Microsoft YaHei,页面继承字体为 PingFang SC、Microsoft YaHei、sans-serif;不内置字体文件。浏览器字体替换不会自动作为渲染错误报告。
|
|
46
|
+
|
|
47
|
+
普通文本和形状内富文本中,段落未设置字号、且段内文字均使用明确的 px 字号时,渲染器以最小行内字号作为段落基准,避免默认 16px 字号撑大行框。每行仍按实际文字排版;显式段落字号、行高和垂直对齐设置保持不变。包含默认字号或相对字号的段落保留原有继承关系。此处理只作用于渲染 DOM,不修改输入 DSL。
|
|
48
|
+
|
|
49
|
+
## 兼容边界
|
|
50
|
+
|
|
51
|
+
- 文档 theme 当前不自动下沉到元素。需要效果的颜色、字体等应显式写在元素上。
|
|
52
|
+
- text 的 paragraphSpace、outline、shadow,以及 shape.text 的 paragraphSpace、wordSpace 当前未实现视觉映射。
|
|
53
|
+
- image 的 clip.shape、fixedRatio,shape 的 pathFormula、keypoints、special 等不在只读渲染中重新计算。
|
|
54
|
+
- 表格单元格 underline 当前未映射;既有字体、间距和合并逻辑原样保留。
|
|
55
|
+
- groupId、lock、name、link、页面 remark/type 等元数据不产生编辑、跳转或交互行为。
|
|
56
|
+
- 不读取 PPTX,不导出图片/PDF,不修复输入,也不检测文字溢出和元素遮挡。PPTX 导出由独立浏览器入口提供,见 [Agent PPTX 导出指南](../AGENT_PPTX_EXPORT.md)。
|
|
57
|
+
|
|
58
|
+
PPTX 导出还识别 text.textType、shape.pattern、线条的 broken/broken2/broken2Direction/curve/cubic/shadow 和 table.theme。它们不改变当前 HTML/Vue 预览行为。导出中的 bar 为横向、column 为竖向;普通文字、形状、线条、图表和表格使用原生对象,特殊/渐变形状、图片填充形状和有路径的公式使用 SVG 图片对象。音视频会读取实际内容并嵌入 PPTX,受到浏览器网络和 CORS 约束。
|
|
59
|
+
|
|
60
|
+
校验针对文档结构、资源协议和渲染必需字段,不是完整的设计语义校验。嵌套样式或素材的运行问题仍可能通过浏览器的 error 状态返回。
|
package/docs/VUE.md
ADDED
|
@@ -0,0 +1,231 @@
|
|
|
1
|
+
# Vue 接入指南
|
|
2
|
+
|
|
3
|
+
本包使用同一套九类元素组件,提供 Node 独立 HTML 和 Vue 嵌入式渲染两种入口。前端只维护编辑交互、编辑控件和业务数据,展示代码统一由本包维护。
|
|
4
|
+
|
|
5
|
+
源码已经包含以下接口。使用 npm 或 tgz 安装前,维护者需要显式构建并发布包含 `dist/vue` 的版本;直接安装未构建的源码目录不能使用 `/vue` 入口。
|
|
6
|
+
|
|
7
|
+
## 1. 安装与入口
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
yarn add ppt-dsl-renderer
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
前端需要 Vue `^3.4.21`,并在应用入口引入一次样式:
|
|
14
|
+
|
|
15
|
+
```ts
|
|
16
|
+
import 'ppt-dsl-renderer/style.css'
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
| 导入路径 | 导出内容 |
|
|
20
|
+
| --- | --- |
|
|
21
|
+
| `ppt-dsl-renderer` | Node 的 `renderToHtml()`;DSL 类型可通过 `import type` 在前端使用 |
|
|
22
|
+
| `ppt-dsl-renderer/vue` | `SlideRenderer`、`ElementRenderer`、三个共用计算方法、DSL 与组件接口类型 |
|
|
23
|
+
| `ppt-dsl-renderer/style.css` | 组件样式,不包含独立 HTML 的页面重置、光标隐藏规则 |
|
|
24
|
+
|
|
25
|
+
Vue 组件采用预编译 ESM,应用无需编译包内 `.vue` 文件。Vue 由宿主提供,ECharts、DOMPurify 由包声明为运行依赖。Vue 是可选 peer dependency,纯 Node 调用者无需安装 Vue;使用 `/vue` 的项目必须提供 Vue。
|
|
26
|
+
|
|
27
|
+
组件面向浏览器,富文本净化和图表绘制会使用 DOM;SSR 项目应在客户端挂载。组件导入不会自动创建应用、修改 `document.title` 或设置 `window.__PPT_DSL_RENDER__`。
|
|
28
|
+
|
|
29
|
+
## 2. 整页与缩略图
|
|
30
|
+
|
|
31
|
+
```vue
|
|
32
|
+
<script setup lang="ts">
|
|
33
|
+
import { computed } from 'vue'
|
|
34
|
+
import { SlideRenderer } from 'ppt-dsl-renderer/vue'
|
|
35
|
+
import type { PptDslSlide } from 'ppt-dsl-renderer'
|
|
36
|
+
|
|
37
|
+
const props = defineProps<{
|
|
38
|
+
slide: PptDslSlide
|
|
39
|
+
width: number
|
|
40
|
+
height: number
|
|
41
|
+
scale?: number
|
|
42
|
+
}>()
|
|
43
|
+
|
|
44
|
+
// transform 不改变布局占位,外层使用缩放后的尺寸。
|
|
45
|
+
const previewStyle = computed(() => ({
|
|
46
|
+
width: `${props.width * (props.scale ?? 1)}px`,
|
|
47
|
+
height: `${props.height * (props.scale ?? 1)}px`,
|
|
48
|
+
overflow: 'hidden',
|
|
49
|
+
}))
|
|
50
|
+
</script>
|
|
51
|
+
|
|
52
|
+
<template>
|
|
53
|
+
<div :style="previewStyle">
|
|
54
|
+
<SlideRenderer
|
|
55
|
+
:slide="slide"
|
|
56
|
+
:width="width"
|
|
57
|
+
:height="height"
|
|
58
|
+
:scale="scale"
|
|
59
|
+
/>
|
|
60
|
+
</div>
|
|
61
|
+
</template>
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
| 参数 | 类型 | 说明 |
|
|
65
|
+
| --- | --- | --- |
|
|
66
|
+
| `slide` | `PptDslSlide` | 必填;显示该页的背景与全部元素 |
|
|
67
|
+
| `width`、`height` | `number` | 必填;DSL 原始尺寸 |
|
|
68
|
+
| `scale` | `number` | 默认 `1`;从左上角缩放,不改写 DSL 坐标 |
|
|
69
|
+
|
|
70
|
+
同一页可以同时显示在主画布与多个缩略图中。组件没有固定 DOM ID;形状渐变和线条箭头的 SVG ID 按 Vue 组件实例区分。根节点保留 `data-ppt-slide-id`,元素保留 `data-ppt-element-id`。多个实例中的业务 ID 可以相同,查询元素时先限定到相应画布容器。
|
|
71
|
+
|
|
72
|
+
`SlideRenderer` 用于只读整页展示。编辑画布通过 `ElementRenderer` 逐个渲染元素,以便前端继续控制选择、拖动和内容编辑。
|
|
73
|
+
|
|
74
|
+
## 3. 编辑画布与原生事件
|
|
75
|
+
|
|
76
|
+
```vue
|
|
77
|
+
<script setup lang="ts">
|
|
78
|
+
import { computed } from 'vue'
|
|
79
|
+
import { ElementRenderer, getPptDslSlideStyle } from 'ppt-dsl-renderer/vue'
|
|
80
|
+
import type { PptDslElement, PptDslSlide } from 'ppt-dsl-renderer'
|
|
81
|
+
|
|
82
|
+
const props = defineProps<{ slide: PptDslSlide; width: number; height: number; scale: number }>()
|
|
83
|
+
const emit = defineEmits<{
|
|
84
|
+
(event: 'element-pointerdown', pointer: PointerEvent, element: PptDslElement): void
|
|
85
|
+
}>()
|
|
86
|
+
const slideStyle = computed(() => getPptDslSlideStyle(props.slide, props.width, props.height, props.scale))
|
|
87
|
+
</script>
|
|
88
|
+
|
|
89
|
+
<template>
|
|
90
|
+
<div :style="[slideStyle, { position: 'relative' }]">
|
|
91
|
+
<ElementRenderer
|
|
92
|
+
v-for="(element, elementIndex) in slide.elements"
|
|
93
|
+
:key="element.id"
|
|
94
|
+
:element="element"
|
|
95
|
+
:element-index="elementIndex"
|
|
96
|
+
@pointerdown="emit('element-pointerdown', $event, element)"
|
|
97
|
+
/>
|
|
98
|
+
</div>
|
|
99
|
+
</template>
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
`ElementRenderer` 只接收 `element`、`elementIndex`;后者是从 `0` 开始的 DSL 数组下标,渲染层级为 `elementIndex + 1`。元素根节点负责定位、尺寸、旋转和透明度,外层画布需要 `position: relative`。不要在每个元素外增加会改变定位参照的容器。
|
|
103
|
+
|
|
104
|
+
`class`、`style`、`id` 和原生事件透传到根节点。组件不会阻止 `pointerdown` 或 `dblclick` 冒泡,也不产生 `select`、`move`、`update`、`commit` 等业务事件;这些行为由前端交互组件处理。`readonly`、`editing`、`selected` 也属于前端交互组件的状态,不是本包的组件参数。
|
|
105
|
+
|
|
106
|
+
## 4. 编辑插槽
|
|
107
|
+
|
|
108
|
+
| 插槽 | 参数 | 保留在包中的内容 |
|
|
109
|
+
| --- | --- | --- |
|
|
110
|
+
| `text-editor` | `{ element, content }` | 文字容器、背景、内边距、垂直对齐等 |
|
|
111
|
+
| `shape-text-editor` | `{ element, content }` | SVG 形状、文字位置、对齐与内边距 |
|
|
112
|
+
| `table-cell-editor` | `{ element, cell, rowIndex, colIndex }` | table/td 结构、合并单元格、列宽、边框与单元格样式 |
|
|
113
|
+
|
|
114
|
+
`element` 类型分别是 `PptDslTextElement`、`PptDslShapeElement`、`PptDslTableElement`;行列下标从 `0` 开始。插槽参数来自当前 DSL,编辑控件需要通过前端 Store 或事件更新 DSL,渲染器不会写入输入数据。
|
|
115
|
+
|
|
116
|
+
没有提供对应插槽时显示默认只读内容。只读或锁定状态应通过 `v-if` 移除整个插槽;不能只在插槽内部渲染一个禁用的编辑器来期待恢复默认展示。包会为编辑内容开启文字选择,形状文字编辑区域也会开启指针事件。
|
|
117
|
+
|
|
118
|
+
下面是宿主交互组件中的接入片段;`ProsemirrorEditor` 使用前端现有实现。`canEdit` 应由 `!readonly && !element.lock` 计算,`editing` 沿用前端的当前编辑状态。
|
|
119
|
+
|
|
120
|
+
```vue
|
|
121
|
+
<ElementRenderer
|
|
122
|
+
:element="element"
|
|
123
|
+
:element-index="elementIndex"
|
|
124
|
+
@pointerdown="handlePointerdown"
|
|
125
|
+
@dblclick="startEditing"
|
|
126
|
+
>
|
|
127
|
+
<template v-if="canEdit && element.type === 'text'" #text-editor="{ content }">
|
|
128
|
+
<ProsemirrorEditor
|
|
129
|
+
:element-id="element.id"
|
|
130
|
+
:model-value="content"
|
|
131
|
+
@blur="emit('commit')"
|
|
132
|
+
@update:model-value="emit('update', { content: $event })"
|
|
133
|
+
/>
|
|
134
|
+
</template>
|
|
135
|
+
|
|
136
|
+
<template v-if="canEdit && element.type === 'shape'" #shape-text-editor="{ content }">
|
|
137
|
+
<ProsemirrorEditor
|
|
138
|
+
:element-id="element.id"
|
|
139
|
+
:model-value="content"
|
|
140
|
+
@blur="emit('commit')"
|
|
141
|
+
@update:model-value="updateShapeText"
|
|
142
|
+
/>
|
|
143
|
+
</template>
|
|
144
|
+
|
|
145
|
+
<template v-if="canEdit && editing && element.type === 'table'" #table-cell-editor="{ cell, rowIndex, colIndex }">
|
|
146
|
+
<div
|
|
147
|
+
contenteditable="true"
|
|
148
|
+
@pointerdown.stop
|
|
149
|
+
@blur="updateCell($event, rowIndex, colIndex)"
|
|
150
|
+
>{{ cell.text }}</div>
|
|
151
|
+
</template>
|
|
152
|
+
</ElementRenderer>
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
前端保留以下回写逻辑,传入的 `element` 类型为 `PptDslElement`;`emit('update', patch)` 由父组件连接到文档 Store,`emit('commit')` 连接到撤销快照。示例只说明内容回写,不替代现有的选择、拖动或提交时机逻辑。
|
|
156
|
+
|
|
157
|
+
```ts
|
|
158
|
+
import { toRaw } from 'vue'
|
|
159
|
+
|
|
160
|
+
const updateShapeText = (content: string) => {
|
|
161
|
+
if (props.element.type !== 'shape') return
|
|
162
|
+
emit('update', { text: { ...props.element.text, content } })
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
const updateCell = (event: FocusEvent, rowIndex: number, colIndex: number) => {
|
|
166
|
+
if (props.element.type !== 'table') return
|
|
167
|
+
const data = structuredClone(toRaw(props.element.data))
|
|
168
|
+
data[rowIndex][colIndex].text = (event.currentTarget as HTMLElement).innerText
|
|
169
|
+
emit('update', { data })
|
|
170
|
+
emit('commit')
|
|
171
|
+
}
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
文字与已有形状文字的插槽可以不依赖 `editing`,以支持单击直接聚焦 ProseMirror。空形状没有 `element.text` 时不显示文字区域,前端双击逻辑负责创建该字段。编辑控件自身的光标、选区、工具栏及内部排版样式由前端负责。
|
|
175
|
+
|
|
176
|
+
## 5. 共用计算与类型
|
|
177
|
+
|
|
178
|
+
```ts
|
|
179
|
+
import {
|
|
180
|
+
getPptDslElementFrame,
|
|
181
|
+
getPptDslLineFrame,
|
|
182
|
+
getPptDslSlideStyle,
|
|
183
|
+
} from 'ppt-dsl-renderer/vue'
|
|
184
|
+
import type { PptDslElement, ElementRendererSlots } from 'ppt-dsl-renderer/vue'
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
| 方法 | 返回值与边界 |
|
|
188
|
+
| --- | --- |
|
|
189
|
+
| `getPptDslElementFrame(element)` | `{ left, top, width, height, rotate }`,与元素定位一致 |
|
|
190
|
+
| `getPptDslLineFrame(line)` | 线条的外框,保留当前最小画布规则 |
|
|
191
|
+
| `getPptDslSlideStyle(slide, width, height, scale = 1)` | 页面背景、尺寸、缩放样式;不包含 `position: relative` |
|
|
192
|
+
|
|
193
|
+
旋转后的轴对齐选区计算、拖动、缩放最小尺寸及新建 ID 属于编辑逻辑,继续放在前端。公开类型声明随包发布,不要求使用方执行声明生成。
|
|
194
|
+
|
|
195
|
+
## 6. 迁移现有渲染器
|
|
196
|
+
|
|
197
|
+
已有渲染器的 Vue 项目可以按以下顺序接入:
|
|
198
|
+
|
|
199
|
+
1. 在应用入口引入一次 `ppt-dsl-renderer/style.css`。
|
|
200
|
+
2. 从包中导入 DSL 类型;也可在原类型文件中使用 `export type * from 'ppt-dsl-renderer'` 保留已有导入路径。
|
|
201
|
+
3. 将整页预览与缩略图替换为 `SlideRenderer`,外层继续管理缩放后的布局占位。
|
|
202
|
+
4. 编辑画布使用 `ElementRenderer`,通过插槽注入编辑控件,事件连接到宿主的选择、拖动和数据更新逻辑。
|
|
203
|
+
5. 共用的展示计算方法改为从包导入,选区计算及其他编辑规则继续由宿主维护。
|
|
204
|
+
6. 验证展示和编辑功能后,删除重复的本地展示实现。
|
|
205
|
+
|
|
206
|
+
删除旧组件前,先迁移其中的编辑回写逻辑,避免丢失编辑能力。
|
|
207
|
+
|
|
208
|
+
前端工具文件可采用以下转导出方式,内部的旋转边界计算复用同一外框规则:
|
|
209
|
+
|
|
210
|
+
```ts
|
|
211
|
+
export {
|
|
212
|
+
getPptDslElementFrame,
|
|
213
|
+
getPptDslLineFrame,
|
|
214
|
+
getPptDslSlideStyle,
|
|
215
|
+
} from 'ppt-dsl-renderer/vue'
|
|
216
|
+
|
|
217
|
+
import { getPptDslElementFrame } from 'ppt-dsl-renderer/vue'
|
|
218
|
+
// 本地选区计算可复用这个外框方法。
|
|
219
|
+
```
|
|
220
|
+
|
|
221
|
+
PPTX 导出、富文本转 PPTX、保存接口、Store、撤销重做、工具栏和 ProseMirror 继续留在前端。删除本地渲染组件后,只有确认没有其他引用时才清理前端的直接依赖。
|
|
222
|
+
|
|
223
|
+
## 7. 维护与验证边界
|
|
224
|
+
|
|
225
|
+
维护者显式执行 `yarn build` 时会生成 `dist/browser` 和 `dist/vue`。`yarn pack` 的检查要求两套 JS/CSS 及公开类型存在,不自动构建,也不判断已有产物是否陈旧;每次发布都应先显式重新构建。
|
|
226
|
+
|
|
227
|
+
Vue 图表会等待字体就绪,响应 DSL 对象替换或内部字段变更,并在 DOM 尺寸更新后重绘;卸载会释放 ECharts 实例。尺寸变更应通过 DSL 的 `width`、`height` 表达,外层 `scale` 只缩放显示。隐藏容器恢复可见而 DSL 尺寸不变的自动测量不属于当前接口。
|
|
228
|
+
|
|
229
|
+
Node 独立 HTML 仍使用 `#ppt-slide` 和 `window.__PPT_DSL_RENDER__`;Vue 入口不提供这个全局完成协议。图片、字体的真实加载及 ECharts 的实际绘制结果需要在使用方浏览器中核对。
|
|
230
|
+
|
|
231
|
+
本仓库测试使用内存编译与 JSDOM 验证组件行为,ECharts 使用交互替身;公开类型检查只覆盖一个消费端夹具。这些检查不替代真实 tgz 安装和页面视觉验收,也不运行 build、vue-tsc 或本地服务。
|
|
@@ -0,0 +1,302 @@
|
|
|
1
|
+
{
|
|
2
|
+
"title": "DSL 渲染示例",
|
|
3
|
+
"width": 1000,
|
|
4
|
+
"height": 562.5,
|
|
5
|
+
"slides": [
|
|
6
|
+
{
|
|
7
|
+
"id": "cover",
|
|
8
|
+
"background": {
|
|
9
|
+
"type": "solid",
|
|
10
|
+
"color": "#f4f7fc"
|
|
11
|
+
},
|
|
12
|
+
"elements": [
|
|
13
|
+
{
|
|
14
|
+
"id": "panel",
|
|
15
|
+
"type": "shape",
|
|
16
|
+
"left": 600,
|
|
17
|
+
"top": 0,
|
|
18
|
+
"width": 400,
|
|
19
|
+
"height": 562.5,
|
|
20
|
+
"path": "M0 0H400V563H0Z",
|
|
21
|
+
"viewBox": [
|
|
22
|
+
400,
|
|
23
|
+
563
|
|
24
|
+
],
|
|
25
|
+
"gradient": {
|
|
26
|
+
"type": "linear",
|
|
27
|
+
"rotate": 25,
|
|
28
|
+
"colors": [
|
|
29
|
+
{
|
|
30
|
+
"color": "#315fa8",
|
|
31
|
+
"pos": 0
|
|
32
|
+
},
|
|
33
|
+
{
|
|
34
|
+
"color": "#8bb6ff",
|
|
35
|
+
"pos": 100
|
|
36
|
+
}
|
|
37
|
+
]
|
|
38
|
+
}
|
|
39
|
+
},
|
|
40
|
+
{
|
|
41
|
+
"id": "headline",
|
|
42
|
+
"type": "text",
|
|
43
|
+
"left": 60,
|
|
44
|
+
"top": 110,
|
|
45
|
+
"width": 500,
|
|
46
|
+
"height": 135,
|
|
47
|
+
"content": "<p style=\"font-size:52px;font-weight:700\">让 DSL<br>成为可见的页面</p>",
|
|
48
|
+
"defaultColor": "#17233e"
|
|
49
|
+
},
|
|
50
|
+
{
|
|
51
|
+
"id": "subtitle",
|
|
52
|
+
"type": "text",
|
|
53
|
+
"left": 63,
|
|
54
|
+
"top": 288,
|
|
55
|
+
"width": 460,
|
|
56
|
+
"height": 110,
|
|
57
|
+
"content": "<p style=\"font-size:23px\">生成 HTML,交给 agent 截图审查。</p><p style=\"font-size:18px;color:#64748b\">固定尺寸 · 原始页码 · 完成状态</p>"
|
|
58
|
+
},
|
|
59
|
+
{
|
|
60
|
+
"id": "badge",
|
|
61
|
+
"type": "shape",
|
|
62
|
+
"left": 664,
|
|
63
|
+
"top": 185,
|
|
64
|
+
"width": 270,
|
|
65
|
+
"height": 150,
|
|
66
|
+
"path": "M0 0H270V150H0Z",
|
|
67
|
+
"viewBox": [
|
|
68
|
+
270,
|
|
69
|
+
150
|
|
70
|
+
],
|
|
71
|
+
"fill": "#fff",
|
|
72
|
+
"text": {
|
|
73
|
+
"content": "<p style=\"font-size:38px;font-weight:700\">DSL → HTML</p>",
|
|
74
|
+
"align": "middle",
|
|
75
|
+
"defaultColor": "#315fa8"
|
|
76
|
+
}
|
|
77
|
+
},
|
|
78
|
+
{
|
|
79
|
+
"id": "underline",
|
|
80
|
+
"type": "line",
|
|
81
|
+
"left": 65,
|
|
82
|
+
"top": 430,
|
|
83
|
+
"start": [
|
|
84
|
+
0,
|
|
85
|
+
0
|
|
86
|
+
],
|
|
87
|
+
"end": [
|
|
88
|
+
400,
|
|
89
|
+
0
|
|
90
|
+
],
|
|
91
|
+
"width": 3,
|
|
92
|
+
"color": "#315fa8",
|
|
93
|
+
"points": [
|
|
94
|
+
"",
|
|
95
|
+
"arrow"
|
|
96
|
+
]
|
|
97
|
+
}
|
|
98
|
+
]
|
|
99
|
+
},
|
|
100
|
+
{
|
|
101
|
+
"id": "data",
|
|
102
|
+
"background": {
|
|
103
|
+
"type": "solid",
|
|
104
|
+
"color": "#fff"
|
|
105
|
+
},
|
|
106
|
+
"elements": [
|
|
107
|
+
{
|
|
108
|
+
"id": "heading",
|
|
109
|
+
"type": "text",
|
|
110
|
+
"left": 54,
|
|
111
|
+
"top": 38,
|
|
112
|
+
"width": 890,
|
|
113
|
+
"height": 65,
|
|
114
|
+
"content": "<p style=\"font-size:36px;font-weight:700\">图表与表格</p>",
|
|
115
|
+
"defaultColor": "#17233e"
|
|
116
|
+
},
|
|
117
|
+
{
|
|
118
|
+
"id": "chart",
|
|
119
|
+
"type": "chart",
|
|
120
|
+
"left": 52,
|
|
121
|
+
"top": 135,
|
|
122
|
+
"width": 550,
|
|
123
|
+
"height": 340,
|
|
124
|
+
"chartType": "column",
|
|
125
|
+
"themeColors": [
|
|
126
|
+
"#315fa8",
|
|
127
|
+
"#71b5a6"
|
|
128
|
+
],
|
|
129
|
+
"data": {
|
|
130
|
+
"labels": [
|
|
131
|
+
"第一阶段",
|
|
132
|
+
"第二阶段",
|
|
133
|
+
"第三阶段"
|
|
134
|
+
],
|
|
135
|
+
"legends": [
|
|
136
|
+
"计划",
|
|
137
|
+
"完成"
|
|
138
|
+
],
|
|
139
|
+
"series": [
|
|
140
|
+
[
|
|
141
|
+
40,
|
|
142
|
+
65,
|
|
143
|
+
90
|
|
144
|
+
],
|
|
145
|
+
[
|
|
146
|
+
35,
|
|
147
|
+
61,
|
|
148
|
+
86
|
|
149
|
+
]
|
|
150
|
+
]
|
|
151
|
+
}
|
|
152
|
+
},
|
|
153
|
+
{
|
|
154
|
+
"id": "table",
|
|
155
|
+
"type": "table",
|
|
156
|
+
"left": 636,
|
|
157
|
+
"top": 160,
|
|
158
|
+
"width": 310,
|
|
159
|
+
"height": 265,
|
|
160
|
+
"colWidths": [
|
|
161
|
+
0.55,
|
|
162
|
+
0.45
|
|
163
|
+
],
|
|
164
|
+
"cellMinHeight": 52,
|
|
165
|
+
"outline": {
|
|
166
|
+
"color": "#dce3ef",
|
|
167
|
+
"width": 1,
|
|
168
|
+
"style": "solid"
|
|
169
|
+
},
|
|
170
|
+
"data": [
|
|
171
|
+
[
|
|
172
|
+
{
|
|
173
|
+
"id": "h1",
|
|
174
|
+
"text": "检查项",
|
|
175
|
+
"style": {
|
|
176
|
+
"bold": true,
|
|
177
|
+
"backcolor": "#edf2fa"
|
|
178
|
+
}
|
|
179
|
+
},
|
|
180
|
+
{
|
|
181
|
+
"id": "h2",
|
|
182
|
+
"text": "状态",
|
|
183
|
+
"style": {
|
|
184
|
+
"bold": true,
|
|
185
|
+
"backcolor": "#edf2fa"
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
],
|
|
189
|
+
[
|
|
190
|
+
{
|
|
191
|
+
"id": "a1",
|
|
192
|
+
"text": "字体排版"
|
|
193
|
+
},
|
|
194
|
+
{
|
|
195
|
+
"id": "a2",
|
|
196
|
+
"text": "人工审查"
|
|
197
|
+
}
|
|
198
|
+
],
|
|
199
|
+
[
|
|
200
|
+
{
|
|
201
|
+
"id": "b1",
|
|
202
|
+
"text": "图片位置"
|
|
203
|
+
},
|
|
204
|
+
{
|
|
205
|
+
"id": "b2",
|
|
206
|
+
"text": "人工审查"
|
|
207
|
+
}
|
|
208
|
+
],
|
|
209
|
+
[
|
|
210
|
+
{
|
|
211
|
+
"id": "c1",
|
|
212
|
+
"text": "图表内容"
|
|
213
|
+
},
|
|
214
|
+
{
|
|
215
|
+
"id": "c2",
|
|
216
|
+
"text": "人工审查"
|
|
217
|
+
}
|
|
218
|
+
]
|
|
219
|
+
]
|
|
220
|
+
},
|
|
221
|
+
{
|
|
222
|
+
"id": "note",
|
|
223
|
+
"type": "text",
|
|
224
|
+
"left": 60,
|
|
225
|
+
"top": 492,
|
|
226
|
+
"width": 880,
|
|
227
|
+
"height": 34,
|
|
228
|
+
"content": "<p style=\"font-size:16px;color:#64748b\">ready 表示渲染完成,视觉质量由调用方 agent 判断。</p>"
|
|
229
|
+
}
|
|
230
|
+
]
|
|
231
|
+
},
|
|
232
|
+
{
|
|
233
|
+
"id": "media",
|
|
234
|
+
"background": {
|
|
235
|
+
"type": "solid",
|
|
236
|
+
"color": "#f4f7fc"
|
|
237
|
+
},
|
|
238
|
+
"elements": [
|
|
239
|
+
{
|
|
240
|
+
"id": "heading",
|
|
241
|
+
"type": "text",
|
|
242
|
+
"left": 54,
|
|
243
|
+
"top": 38,
|
|
244
|
+
"width": 890,
|
|
245
|
+
"height": 65,
|
|
246
|
+
"content": "<p style=\"font-size:36px;font-weight:700\">图片、公式与静态媒体</p>",
|
|
247
|
+
"defaultColor": "#17233e"
|
|
248
|
+
},
|
|
249
|
+
{
|
|
250
|
+
"id": "picture",
|
|
251
|
+
"type": "image",
|
|
252
|
+
"left": 54,
|
|
253
|
+
"top": 138,
|
|
254
|
+
"width": 425,
|
|
255
|
+
"height": 239,
|
|
256
|
+
"src": "data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI4MDAiIGhlaWdodD0iNDUwIiB2aWV3Qm94PSIwIDAgODAwIDQ1MCI+PHJlY3Qgd2lkdGg9IjgwMCIgaGVpZ2h0PSI0NTAiIGZpbGw9IiNlNmVmZmYiLz48Y2lyY2xlIGN4PSI2MTAiIGN5PSIxMTUiIHI9Ijc1IiBmaWxsPSIjOTRiNmZmIi8+PHBhdGggZD0iTTAgNDAwTDE4MCAyMDBMMzQwIDM3MEw1NDAgMTcwTDgwMCA0MDBWNDUwSDBaIiBmaWxsPSIjNDU3NWNmIi8+PHBhdGggZD0iTTAgNDMwTDI1MCAzMTBMNDEwIDQwNUw2NDAgMzAwTDgwMCA0MTVWNDUwSDBaIiBmaWxsPSIjMjM0NTgyIi8+PC9zdmc+",
|
|
257
|
+
"radius": 12,
|
|
258
|
+
"fit": "cover"
|
|
259
|
+
},
|
|
260
|
+
{
|
|
261
|
+
"id": "video",
|
|
262
|
+
"type": "video",
|
|
263
|
+
"left": 524,
|
|
264
|
+
"top": 138,
|
|
265
|
+
"width": 422,
|
|
266
|
+
"height": 239,
|
|
267
|
+
"src": "https://example.invalid/demo.mp4",
|
|
268
|
+
"poster": "data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI4MDAiIGhlaWdodD0iNDUwIiB2aWV3Qm94PSIwIDAgODAwIDQ1MCI+PHJlY3Qgd2lkdGg9IjgwMCIgaGVpZ2h0PSI0NTAiIGZpbGw9IiNlNmVmZmYiLz48Y2lyY2xlIGN4PSI2MTAiIGN5PSIxMTUiIHI9Ijc1IiBmaWxsPSIjOTRiNmZmIi8+PHBhdGggZD0iTTAgNDAwTDE4MCAyMDBMMzQwIDM3MEw1NDAgMTcwTDgwMCA0MDBWNDUwSDBaIiBmaWxsPSIjNDU3NWNmIi8+PHBhdGggZD0iTTAgNDMwTDI1MCAzMTBMNDEwIDQwNUw2NDAgMzAwTDgwMCA0MTVWNDUwSDBaIiBmaWxsPSIjMjM0NTgyIi8+PC9zdmc+",
|
|
269
|
+
"autoplay": true
|
|
270
|
+
},
|
|
271
|
+
{
|
|
272
|
+
"id": "formula",
|
|
273
|
+
"type": "latex",
|
|
274
|
+
"left": 54,
|
|
275
|
+
"top": 409,
|
|
276
|
+
"width": 425,
|
|
277
|
+
"height": 75,
|
|
278
|
+
"latex": "E = mc²"
|
|
279
|
+
},
|
|
280
|
+
{
|
|
281
|
+
"id": "audio",
|
|
282
|
+
"type": "audio",
|
|
283
|
+
"left": 524,
|
|
284
|
+
"top": 417,
|
|
285
|
+
"width": 422,
|
|
286
|
+
"height": 60,
|
|
287
|
+
"src": "https://example.invalid/demo.mp3",
|
|
288
|
+
"autoplay": true
|
|
289
|
+
},
|
|
290
|
+
{
|
|
291
|
+
"id": "media-note",
|
|
292
|
+
"type": "text",
|
|
293
|
+
"left": 54,
|
|
294
|
+
"top": 509,
|
|
295
|
+
"width": 890,
|
|
296
|
+
"height": 28,
|
|
297
|
+
"content": "<p style=\"font-size:14px;color:#64748b\">左右为图片与视频封面;音视频源为占位地址,静态渲染不会请求它们。</p>"
|
|
298
|
+
}
|
|
299
|
+
]
|
|
300
|
+
}
|
|
301
|
+
]
|
|
302
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "ppt-dsl-renderer",
|
|
3
|
+
"version": "1.1.0",
|
|
4
|
+
"description": "Render PPT DSL with Vue components or standalone, agent-friendly HTML slides.",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"license": "MIT",
|
|
7
|
+
"engines": {
|
|
8
|
+
"node": ">=22"
|
|
9
|
+
},
|
|
10
|
+
"packageManager": "yarn@1.22.19",
|
|
11
|
+
"exports": {
|
|
12
|
+
".": {
|
|
13
|
+
"types": "./src/index.d.ts",
|
|
14
|
+
"import": "./dist/index.js"
|
|
15
|
+
},
|
|
16
|
+
"./vue": {
|
|
17
|
+
"types": "./src/vue.d.ts",
|
|
18
|
+
"import": "./dist/vue/renderer.js"
|
|
19
|
+
},
|
|
20
|
+
"./pptx": {
|
|
21
|
+
"types": "./src/pptx.d.ts",
|
|
22
|
+
"import": "./dist/pptx/index.js"
|
|
23
|
+
},
|
|
24
|
+
"./style.css": "./dist/vue/renderer.css"
|
|
25
|
+
},
|
|
26
|
+
"sideEffects": [
|
|
27
|
+
"**/*.css"
|
|
28
|
+
],
|
|
29
|
+
"types": "./src/index.d.ts",
|
|
30
|
+
"bin": {
|
|
31
|
+
"ppt-dsl-renderer": "./dist/cli.js"
|
|
32
|
+
},
|
|
33
|
+
"files": [
|
|
34
|
+
"src/index.d.ts",
|
|
35
|
+
"src/vue.d.ts",
|
|
36
|
+
"src/pptx.d.ts",
|
|
37
|
+
"src/types",
|
|
38
|
+
"dist",
|
|
39
|
+
"AGENT_USAGE.md",
|
|
40
|
+
"AGENT_PPTX_EXPORT.md",
|
|
41
|
+
"docs",
|
|
42
|
+
"examples/deck.json",
|
|
43
|
+
"third-party-licenses",
|
|
44
|
+
"THIRD_PARTY_NOTICES.md"
|
|
45
|
+
],
|
|
46
|
+
"scripts": {
|
|
47
|
+
"build": "vite build && vite build --config vite.vue.config.js && vite build --config vite.pptx.config.js && vite build --config vite.pptx-module.config.js && vite build --config vite.node.config.js && vite build --config vite.cli.config.js",
|
|
48
|
+
"test": "node --test tests/*.test.js",
|
|
49
|
+
"coverage": "node --experimental-test-coverage --test tests/*.test.js",
|
|
50
|
+
"prepack": "node scripts/check-package.js"
|
|
51
|
+
},
|
|
52
|
+
"dependencies": {
|
|
53
|
+
"dompurify": "3.3.1",
|
|
54
|
+
"echarts": "6.1.0",
|
|
55
|
+
"playwright-core": "1.62.1",
|
|
56
|
+
"pptxgenjs": "3.12.0",
|
|
57
|
+
"svg-pathdata": "7.2.0",
|
|
58
|
+
"tinycolor2": "1.6.0"
|
|
59
|
+
},
|
|
60
|
+
"peerDependencies": {
|
|
61
|
+
"vue": "^3.4.21"
|
|
62
|
+
},
|
|
63
|
+
"peerDependenciesMeta": {
|
|
64
|
+
"vue": {
|
|
65
|
+
"optional": true
|
|
66
|
+
}
|
|
67
|
+
},
|
|
68
|
+
"devDependencies": {
|
|
69
|
+
"@vitejs/plugin-vue": "4.1.0",
|
|
70
|
+
"@vue/compiler-sfc": "3.4.21",
|
|
71
|
+
"jsdom": "26.1.0",
|
|
72
|
+
"jszip": "3.10.1",
|
|
73
|
+
"sass": "1.62.1",
|
|
74
|
+
"typescript": "5.0.4",
|
|
75
|
+
"vite": "4.5.9",
|
|
76
|
+
"vue": "3.4.21"
|
|
77
|
+
},
|
|
78
|
+
"keywords": [
|
|
79
|
+
"ppt",
|
|
80
|
+
"dsl",
|
|
81
|
+
"html",
|
|
82
|
+
"agent",
|
|
83
|
+
"presentation"
|
|
84
|
+
]
|
|
85
|
+
}
|