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.
Files changed (49) hide show
  1. package/AGENT_PPTX_EXPORT.md +81 -0
  2. package/AGENT_USAGE.md +87 -0
  3. package/LICENSE +21 -0
  4. package/README.md +112 -0
  5. package/THIRD_PARTY_NOTICES.md +43 -0
  6. package/dist/browser/renderer.css +1 -0
  7. package/dist/browser/renderer.js +80 -0
  8. package/dist/cli.js +243 -0
  9. package/dist/index.js +140 -0
  10. package/dist/pptx/exporter.js +129 -0
  11. package/dist/pptx/index.js +7437 -0
  12. package/dist/vue/renderer.css +1 -0
  13. package/dist/vue/renderer.js +577 -0
  14. package/docs/AGENT.md +36 -0
  15. package/docs/DSL.md +60 -0
  16. package/docs/VUE.md +231 -0
  17. package/examples/deck.json +302 -0
  18. package/package.json +85 -0
  19. package/src/index.d.ts +24 -0
  20. package/src/pptx.d.ts +30 -0
  21. package/src/types/ppt-dsl.d.ts +241 -0
  22. package/src/types/vue.d.ts +40 -0
  23. package/src/vue.d.ts +16 -0
  24. package/third-party-licenses/core-util-is/LICENSE +19 -0
  25. package/third-party-licenses/dompurify/LICENSE +568 -0
  26. package/third-party-licenses/echarts/LICENSE +222 -0
  27. package/third-party-licenses/echarts/LICENSE-d3 +27 -0
  28. package/third-party-licenses/echarts/NOTICE +5 -0
  29. package/third-party-licenses/immediate/LICENSE.txt +20 -0
  30. package/third-party-licenses/inherits/LICENSE +16 -0
  31. package/third-party-licenses/isarray/LICENSE +22 -0
  32. package/third-party-licenses/jszip/LICENSE.markdown +651 -0
  33. package/third-party-licenses/lie/license.md +7 -0
  34. package/third-party-licenses/pako/LICENSE +21 -0
  35. package/third-party-licenses/pptxgenjs/LICENSE +21 -0
  36. package/third-party-licenses/readable-stream/LICENSE +47 -0
  37. package/third-party-licenses/safe-buffer/LICENSE +21 -0
  38. package/third-party-licenses/setimmediate/LICENSE.txt +20 -0
  39. package/third-party-licenses/string_decoder/LICENSE +48 -0
  40. package/third-party-licenses/svg-pathdata/LICENSE +20 -0
  41. package/third-party-licenses/tinycolor2/LICENSE +20 -0
  42. package/third-party-licenses/tslib/LICENSE.txt +12 -0
  43. package/third-party-licenses/util-deprecate/LICENSE +24 -0
  44. package/third-party-licenses/vue/LICENSE +21 -0
  45. package/third-party-licenses/vue-reactivity/LICENSE +21 -0
  46. package/third-party-licenses/vue-runtime-core/LICENSE +21 -0
  47. package/third-party-licenses/vue-runtime-dom/LICENSE +21 -0
  48. package/third-party-licenses/vue-shared/LICENSE +21 -0
  49. package/third-party-licenses/zrender/LICENSE +29 -0
@@ -0,0 +1 @@
1
+ .ppt-text-content[data-v-c728acd4],.ppt-text-static[data-v-c728acd4]{width:100%;box-sizing:border-box}.ppt-text-content[data-v-c728acd4]{display:flex;flex-direction:column;height:100%;position:relative;overflow-wrap:break-word;word-break:normal;white-space:normal}.ppt-text-editable[data-v-c728acd4]{-webkit-user-select:text;user-select:text}.ppt-text-static[data-v-c728acd4]{font-size:16px;position:relative}.ppt-text-static[data-v-c728acd4] p,.ppt-text-static[data-v-c728acd4] h1,.ppt-text-static[data-v-c728acd4] h2,.ppt-text-static[data-v-c728acd4] h3,.ppt-text-static[data-v-c728acd4] h4,.ppt-text-static[data-v-c728acd4] h5,.ppt-text-static[data-v-c728acd4] ol,.ppt-text-static[data-v-c728acd4] ul,.ppt-text-static[data-v-c728acd4] li{margin:0}.ppt-text-static[data-v-c728acd4] ol,.ppt-text-static[data-v-c728acd4] ul{padding-inline-start:1.25em}.ppt-text-static[data-v-c728acd4] li[style*="text-align: center"],.ppt-text-static[data-v-c728acd4] li[style*="text-align: right"]{list-style-position:inside}.ppt-text-static[data-v-c728acd4] li[style*="text-align: center"]>p,.ppt-text-static[data-v-c728acd4] li[style*="text-align: right"]>p{display:inline}.ppt-text-static-fixed[data-v-c728acd4]{display:flex;flex-direction:column;height:100%;justify-content:inherit}.ppt-image-content[data-v-bb8ba6cb]{position:relative;width:100%;height:100%;box-sizing:border-box}.ppt-image-content img[data-v-bb8ba6cb]{width:100%;height:100%;pointer-events:none}.ppt-image-mask[data-v-bb8ba6cb]{position:absolute;top:0;right:0;bottom:0;left:0;pointer-events:none}.ppt-shape-content[data-v-bde892d3],.ppt-shape-content svg[data-v-bde892d3],.ppt-shape-text[data-v-bde892d3]{position:absolute;top:0;right:0;bottom:0;left:0;width:100%;height:100%}.ppt-shape-text[data-v-bde892d3]{display:flex;justify-content:center;box-sizing:border-box;text-align:center;pointer-events:none}.ppt-shape-text[data-v-bde892d3] p,.ppt-shape-text[data-v-bde892d3] h1,.ppt-shape-text[data-v-bde892d3] h2,.ppt-shape-text[data-v-bde892d3] h3,.ppt-shape-text[data-v-bde892d3] h4,.ppt-shape-text[data-v-bde892d3] h5{margin:0}.ppt-shape-text-static[data-v-bde892d3]{width:100%}.ppt-shape-text-static[data-v-bde892d3] ol,.ppt-shape-text-static[data-v-bde892d3] ul,.ppt-shape-text-static[data-v-bde892d3] li{margin:0}.ppt-shape-text-static[data-v-bde892d3] ol,.ppt-shape-text-static[data-v-bde892d3] ul{padding-inline-start:1.25em}.ppt-shape-text-editable[data-v-bde892d3]{pointer-events:auto;-webkit-user-select:text;user-select:text}.ppt-shape-text-static[data-v-bde892d3] li[style*="text-align: center"],.ppt-shape-text-static[data-v-bde892d3] li[style*="text-align: right"]{list-style-position:inside}.ppt-shape-text-static[data-v-bde892d3] li[style*="text-align: center"]>p,.ppt-shape-text-static[data-v-bde892d3] li[style*="text-align: right"]>p{display:inline}.ppt-line-content[data-v-029177ed]{width:100%;height:100%;overflow:visible}.ppt-chart-content[data-v-d0925046]{width:100%;height:100%}.ppt-table-content[data-v-b7c947a1]{width:100%;height:100%;border-collapse:collapse;table-layout:fixed}.ppt-table-content td[data-v-b7c947a1]{padding:6px 10px;border:inherit;box-sizing:border-box;outline:0}.ppt-table-cell-editable[data-v-b7c947a1]{-webkit-user-select:text;user-select:text}.ppt-latex-content[data-v-bc1283bd]{display:flex;align-items:center;justify-content:center;width:100%;height:100%;color:#333;font:20px Georgia,serif}.ppt-latex-content svg[data-v-bc1283bd]{width:100%;height:100%}.ppt-video-content[data-v-51f57e49]{width:100%;height:100%;background:#111}.ppt-video-content img[data-v-51f57e49]{width:100%;height:100%;object-fit:contain}.ppt-audio-content[data-v-100cc51b]{display:flex;align-items:center;gap:8px;width:100%;height:100%;padding:8px;box-sizing:border-box;border:1px solid #e2e5ec;border-radius:8px;background:#fff}.ppt-audio-icon[data-v-100cc51b]{font-size:26px;font-weight:700}.ppt-audio-content audio[data-v-100cc51b]{width:calc(100% - 36px);height:32px;pointer-events:none}.ppt-element[data-v-4031d518]{position:absolute;transform-origin:center;-webkit-user-select:none;user-select:none;color:#272931;font-family:PingFang SC,Microsoft YaHei,sans-serif}.ppt-slide[data-v-a6a99631]{position:relative;overflow:hidden;isolation:isolate;color:#272931;font-family:PingFang SC,Microsoft YaHei,sans-serif}
@@ -0,0 +1,577 @@
1
+ import { defineComponent as g, computed as f, openBlock as r, createElementBlock as a, normalizeClass as x, normalizeStyle as v, renderSlot as b, createElementVNode as _, createCommentVNode as T, getCurrentInstance as z, Fragment as S, renderList as E, ref as j, inject as P, watch as V, onMounted as D, onBeforeUnmount as O, createTextVNode as Y, toDisplayString as C, pushScopeId as q, popScopeId as G, createBlock as H, resolveDynamicComponent as X, createSlots as Z, withCtx as I, normalizeProps as M, guardReactiveProps as L } from "vue";
2
+ import R from "dompurify";
3
+ import * as J from "echarts";
4
+ const A = (o) => ({
5
+ height: Math.max(Math.abs(o.end[1] - o.start[1]), 24),
6
+ left: o.left,
7
+ rotate: 0,
8
+ top: o.top,
9
+ width: Math.max(Math.abs(o.end[0] - o.start[0]), 24)
10
+ }), K = (o) => o.type === "line" ? A(o) : {
11
+ height: o.height || 40,
12
+ left: o.left,
13
+ rotate: o.rotate || 0,
14
+ top: o.top,
15
+ width: o.width || 120
16
+ }, U = (o, e, s, i = 1) => {
17
+ var c, m;
18
+ const t = o.background, l = t == null ? void 0 : t.gradient, n = l == null ? void 0 : l.colors.map((u) => `${u.color} ${u.pos}%`).join(", ");
19
+ let d;
20
+ return (t == null ? void 0 : t.type) === "gradient" && n ? d = (l == null ? void 0 : l.type) === "radial" ? `radial-gradient(${n})` : `linear-gradient(${(l == null ? void 0 : l.rotate) || 0}deg, ${n})` : (t == null ? void 0 : t.type) === "image" && ((c = t.image) != null && c.src) && (d = `url(${JSON.stringify(t.image.src)})`), {
21
+ backgroundColor: (t == null ? void 0 : t.color) || "#fff",
22
+ backgroundImage: d,
23
+ backgroundPosition: "center",
24
+ backgroundRepeat: "no-repeat",
25
+ backgroundSize: ((m = t == null ? void 0 : t.image) == null ? void 0 : m.size) || "cover",
26
+ height: `${s}px`,
27
+ transform: `scale(${i})`,
28
+ transformOrigin: "top left",
29
+ width: `${e}px`
30
+ };
31
+ };
32
+ function B(o) {
33
+ const e = "p, h1, h2, h3, h4, h5, h6, li";
34
+ for (const s of o.querySelectorAll(e)) {
35
+ if (s.style.fontSize || s.querySelector(e))
36
+ continue;
37
+ const i = o.ownerDocument.createTreeWalker(s, 4);
38
+ let t = 1 / 0;
39
+ for (let l = i.nextNode(); l; l = i.nextNode()) {
40
+ if (!l.textContent.trim())
41
+ continue;
42
+ let n = l.parentElement;
43
+ for (; n !== s && !n.style.fontSize; )
44
+ n = n.parentElement;
45
+ const d = n === s ? "" : n.style.fontSize;
46
+ if (!/^\d*\.?\d+px$/.test(d)) {
47
+ t = 1 / 0;
48
+ break;
49
+ }
50
+ t = Math.min(t, Number.parseFloat(d));
51
+ }
52
+ Number.isFinite(t) && (s.style.fontSize = `${t}px`);
53
+ }
54
+ }
55
+ const Q = ["innerHTML"], ee = /* @__PURE__ */ g({
56
+ __name: "TextElement",
57
+ props: {
58
+ element: {}
59
+ },
60
+ setup(o) {
61
+ const e = o, s = f(() => {
62
+ const t = document.createElement("div");
63
+ return t.innerHTML = R.sanitize(e.element.content), B(t), t.querySelectorAll('[style*="font-weight"]').forEach((l) => {
64
+ const n = Number.parseInt(l.style.fontWeight, 10);
65
+ n >= 550 && n < 700 && (l.style.fontWeight = "700");
66
+ }), t.innerHTML;
67
+ }), i = f(() => ({
68
+ background: e.element.fill || "transparent",
69
+ color: e.element.defaultColor || "#333333",
70
+ fontFamily: e.element.defaultFontName || "Microsoft YaHei",
71
+ letterSpacing: `${e.element.wordSpace || 0}px`,
72
+ lineHeight: e.element.lineHeight || 1.4,
73
+ padding: (e.element.inset || [0, 0, 0, 0]).map((t) => `${t}px`).join(" "),
74
+ justifyContent: e.element.vAlign === "bottom" ? "flex-end" : e.element.vAlign === "middle" ? "center" : "flex-start",
75
+ writingMode: e.element.vertical ? "vertical-rl" : "horizontal-tb"
76
+ }));
77
+ return (t, l) => (r(), a("div", {
78
+ class: x(["ppt-text-content", { "ppt-text-editable": t.$slots["text-editor"] }]),
79
+ style: v(i.value)
80
+ }, [
81
+ b(t.$slots, "text-editor", {
82
+ element: t.element,
83
+ content: t.element.content
84
+ }, () => [
85
+ _("div", {
86
+ class: x(["ppt-text-static", { "ppt-text-static-fixed": t.element.fixedHeight }]),
87
+ innerHTML: s.value
88
+ }, null, 10, Q)
89
+ ], !0)
90
+ ], 6));
91
+ }
92
+ });
93
+ const $ = (o, e) => {
94
+ const s = o.__vccOpts || o;
95
+ for (const [i, t] of e)
96
+ s[i] = t;
97
+ return s;
98
+ }, te = /* @__PURE__ */ $(ee, [["__scopeId", "data-v-c728acd4"]]), ne = ["src"], le = /* @__PURE__ */ g({
99
+ __name: "ImageElement",
100
+ props: {
101
+ element: {}
102
+ },
103
+ setup(o) {
104
+ const e = o, s = f(() => {
105
+ var l;
106
+ return {
107
+ border: (l = e.element.outline) != null && l.width ? `${e.element.outline.width}px ${e.element.outline.style || "solid"} ${e.element.outline.color || "#000"}` : "none",
108
+ borderRadius: `${e.element.radius || 0}px`,
109
+ boxShadow: e.element.shadow ? `${e.element.shadow.h}px ${e.element.shadow.v}px ${e.element.shadow.blur}px ${e.element.shadow.color}` : void 0,
110
+ filter: Object.entries(e.element.filters || {}).map(([n, d]) => `${n}(${d})`).join(" "),
111
+ // 图片只在 DSL 明确配置裁剪或圆角时限制溢出,不自行补裁剪行为。
112
+ overflow: e.element.clip || e.element.radius ? "hidden" : void 0,
113
+ transform: `scale(${e.element.flipH ? -1 : 1}, ${e.element.flipV ? -1 : 1})`
114
+ };
115
+ }), i = f(() => {
116
+ var m;
117
+ const [[l, n], [d, c]] = ((m = e.element.clip) == null ? void 0 : m.range) || [[0, 0], [1, 1]];
118
+ return { height: c - n, left: l, top: n, width: d - l };
119
+ }), t = f(() => ({
120
+ height: e.element.clip ? `${100 / i.value.height}%` : "100%",
121
+ left: e.element.clip ? `${-i.value.left / i.value.width * 100}%` : "0",
122
+ objectFit: e.element.fit || "cover",
123
+ position: e.element.clip ? "absolute" : "static",
124
+ top: e.element.clip ? `${-i.value.top / i.value.height * 100}%` : "0",
125
+ width: e.element.clip ? `${100 / i.value.width}%` : "100%"
126
+ }));
127
+ return (l, n) => (r(), a("div", {
128
+ class: "ppt-image-content",
129
+ style: v(s.value)
130
+ }, [
131
+ _("img", {
132
+ src: l.element.src,
133
+ style: v(t.value),
134
+ alt: "",
135
+ draggable: "false"
136
+ }, null, 12, ne),
137
+ l.element.colorMask ? (r(), a("span", {
138
+ key: 0,
139
+ class: "ppt-image-mask",
140
+ style: v({ background: l.element.colorMask })
141
+ }, null, 4)) : T("", !0)
142
+ ], 4));
143
+ }
144
+ });
145
+ const oe = /* @__PURE__ */ $(le, [["__scopeId", "data-v-bb8ba6cb"]]), se = { class: "ppt-shape-content" }, re = ["viewBox"], ae = ["offset", "stop-color"], ie = ["gradient-transform"], de = ["offset", "stop-color"], pe = ["d", "fill", "stroke", "stroke-dasharray", "stroke-width"], ce = ["innerHTML"], me = /* @__PURE__ */ g({
146
+ __name: "ShapeElement",
147
+ props: {
148
+ element: {}
149
+ },
150
+ setup(o) {
151
+ const e = o, s = `ppt-gradient-${z().uid}`, i = f(() => {
152
+ var d;
153
+ const n = document.createElement("div");
154
+ return n.innerHTML = R.sanitize(((d = e.element.text) == null ? void 0 : d.content) || ""), B(n), n.innerHTML;
155
+ }), t = f(() => ({
156
+ filter: e.element.shadow ? `drop-shadow(${e.element.shadow.h}px ${e.element.shadow.v}px ${e.element.shadow.blur}px ${e.element.shadow.color})` : void 0,
157
+ transform: `scale(${e.element.flipH ? -1 : 1}, ${e.element.flipV ? -1 : 1})`,
158
+ transformOrigin: "center"
159
+ })), l = f(() => {
160
+ var n, d, c, m, u, p;
161
+ return {
162
+ alignItems: ((n = e.element.text) == null ? void 0 : n.align) === "top" ? "flex-start" : ((d = e.element.text) == null ? void 0 : d.align) === "bottom" ? "flex-end" : "center",
163
+ color: ((c = e.element.text) == null ? void 0 : c.defaultColor) || "#333",
164
+ fontFamily: ((m = e.element.text) == null ? void 0 : m.defaultFontName) || "Microsoft YaHei",
165
+ lineHeight: ((u = e.element.text) == null ? void 0 : u.lineHeight) || 1.4,
166
+ padding: (((p = e.element.text) == null ? void 0 : p.inset) || [8, 8, 8, 8]).map((y) => `${y}px`).join(" ")
167
+ };
168
+ });
169
+ return (n, d) => {
170
+ var c, m, u, p, y;
171
+ return r(), a("div", se, [
172
+ (r(), a("svg", {
173
+ style: v(t.value),
174
+ viewBox: `0 0 ${n.element.viewBox[0]} ${n.element.viewBox[1]}`,
175
+ overflow: "visible",
176
+ preserveAspectRatio: "none"
177
+ }, [
178
+ _("defs", null, [
179
+ ((c = n.element.gradient) == null ? void 0 : c.type) === "radial" ? (r(), a("radialGradient", {
180
+ key: 0,
181
+ id: s
182
+ }, [
183
+ (r(!0), a(S, null, E(n.element.gradient.colors, (h) => (r(), a("stop", {
184
+ key: h.pos,
185
+ offset: `${h.pos}%`,
186
+ "stop-color": h.color
187
+ }, null, 8, ae))), 128))
188
+ ])) : n.element.gradient ? (r(), a("linearGradient", {
189
+ key: 1,
190
+ id: s,
191
+ "gradient-transform": `rotate(${n.element.gradient.rotate || 0} .5 .5)`,
192
+ x1: "0",
193
+ y1: "0",
194
+ x2: "1",
195
+ y2: "0"
196
+ }, [
197
+ (r(!0), a(S, null, E(n.element.gradient.colors, (h) => (r(), a("stop", {
198
+ key: h.pos,
199
+ offset: `${h.pos}%`,
200
+ "stop-color": h.color
201
+ }, null, 8, de))), 128))
202
+ ], 8, ie)) : T("", !0)
203
+ ]),
204
+ _("path", {
205
+ d: n.element.path,
206
+ fill: n.element.gradient ? `url(#${s})` : n.element.fill || "transparent",
207
+ stroke: ((m = n.element.outline) == null ? void 0 : m.color) || "transparent",
208
+ "stroke-dasharray": ((u = n.element.outline) == null ? void 0 : u.style) === "dashed" ? "8 5" : ((p = n.element.outline) == null ? void 0 : p.style) === "dotted" ? "2 4" : void 0,
209
+ "stroke-width": ((y = n.element.outline) == null ? void 0 : y.width) || 0,
210
+ "vector-effect": "non-scaling-stroke"
211
+ }, null, 8, pe)
212
+ ], 12, re)),
213
+ n.element.text ? (r(), a("div", {
214
+ key: 0,
215
+ class: x(["ppt-shape-text", { "ppt-shape-text-editable": n.$slots["shape-text-editor"] }]),
216
+ style: v(l.value)
217
+ }, [
218
+ b(n.$slots, "shape-text-editor", {
219
+ element: n.element,
220
+ content: n.element.text.content
221
+ }, () => [
222
+ _("div", {
223
+ class: "ppt-shape-text-static",
224
+ innerHTML: i.value
225
+ }, null, 8, ce)
226
+ ], !0)
227
+ ], 6)) : T("", !0)
228
+ ]);
229
+ };
230
+ }
231
+ });
232
+ const ue = /* @__PURE__ */ $(me, [["__scopeId", "data-v-bde892d3"]]), he = ["height", "width"], _e = ["fill"], fe = ["fill"], ye = ["fill"], ve = ["fill"], ge = ["x1", "y1", "x2", "y2", "stroke", "stroke-dasharray", "stroke-width", "marker-start", "marker-end"], $e = /* @__PURE__ */ g({
233
+ __name: "LineElement",
234
+ props: {
235
+ element: {}
236
+ },
237
+ setup(o) {
238
+ const e = o, s = z().uid, i = `ppt-line-start-${s}`, t = `ppt-line-arrow-${s}`, l = f(() => A(e.element));
239
+ return (n, d) => {
240
+ var c, m, u, p;
241
+ return r(), a("svg", {
242
+ class: "ppt-line-content",
243
+ height: l.value.height,
244
+ width: l.value.width
245
+ }, [
246
+ _("defs", null, [
247
+ _("marker", {
248
+ id: i,
249
+ markerWidth: "8",
250
+ markerHeight: "8",
251
+ refX: "1",
252
+ refY: "4",
253
+ orient: "auto-start-reverse"
254
+ }, [
255
+ ((c = n.element.points) == null ? void 0 : c[0]) === "dot" ? (r(), a("circle", {
256
+ key: 0,
257
+ cx: "4",
258
+ cy: "4",
259
+ r: "3",
260
+ fill: n.element.color
261
+ }, null, 8, _e)) : (r(), a("path", {
262
+ key: 1,
263
+ d: "M 0 4 L 8 0 L 8 8 Z",
264
+ fill: n.element.color
265
+ }, null, 8, fe))
266
+ ]),
267
+ _("marker", {
268
+ id: t,
269
+ markerWidth: "8",
270
+ markerHeight: "8",
271
+ refX: "7",
272
+ refY: "4",
273
+ orient: "auto"
274
+ }, [
275
+ ((m = n.element.points) == null ? void 0 : m[1]) === "dot" ? (r(), a("circle", {
276
+ key: 0,
277
+ cx: "4",
278
+ cy: "4",
279
+ r: "3",
280
+ fill: n.element.color
281
+ }, null, 8, ye)) : (r(), a("path", {
282
+ key: 1,
283
+ d: "M 0 0 L 8 4 L 0 8 Z",
284
+ fill: n.element.color
285
+ }, null, 8, ve))
286
+ ])
287
+ ]),
288
+ _("line", {
289
+ x1: n.element.start[0],
290
+ y1: n.element.start[1],
291
+ x2: n.element.end[0],
292
+ y2: n.element.end[1],
293
+ stroke: n.element.color,
294
+ "stroke-dasharray": n.element.style === "dashed" ? "8 5" : n.element.style === "dotted" ? "2 4" : void 0,
295
+ "stroke-width": n.element.width || 2,
296
+ "marker-start": (u = n.element.points) != null && u[0] ? `url(#${i})` : void 0,
297
+ "marker-end": (p = n.element.points) != null && p[1] ? `url(#${t})` : void 0
298
+ }, null, 8, ge)
299
+ ], 8, he);
300
+ };
301
+ }
302
+ });
303
+ const be = /* @__PURE__ */ $($e, [["__scopeId", "data-v-029177ed"]]), ke = Symbol("ppt-render-tasks"), we = /* @__PURE__ */ g({
304
+ __name: "ChartElement",
305
+ props: {
306
+ element: {}
307
+ },
308
+ setup(o) {
309
+ const e = o, s = j(), i = P(ke, void 0);
310
+ let t, l, n = !1, d = !1;
311
+ i && i.push(new Promise((p) => {
312
+ l = p;
313
+ }));
314
+ const c = f(() => {
315
+ var p;
316
+ return {
317
+ background: e.element.fill || "transparent",
318
+ border: (p = e.element.outline) != null && p.width ? `${e.element.outline.width}px ${e.element.outline.style || "solid"} ${e.element.outline.color || "#d9dce6"}` : "none",
319
+ boxSizing: "border-box"
320
+ };
321
+ }), m = () => e.element.data.legends.map((p, y) => {
322
+ var k, w;
323
+ const h = e.element.data.series[y] || [];
324
+ return ["pie", "ring"].includes(e.element.chartType) ? {
325
+ data: e.element.data.labels.map((N, W) => ({ name: N, value: h[W] || 0 })),
326
+ name: p,
327
+ radius: e.element.chartType === "ring" ? ["50%", "72%"] : "66%",
328
+ type: "pie"
329
+ } : e.element.chartType === "radar" ? { data: [{ name: p, value: h }], name: p, type: "radar" } : {
330
+ areaStyle: e.element.chartType === "area" ? {} : void 0,
331
+ data: h,
332
+ name: p,
333
+ smooth: (k = e.element.options) == null ? void 0 : k.lineSmooth,
334
+ stack: (w = e.element.options) != null && w.stack ? "total" : void 0,
335
+ type: e.element.chartType === "column" || e.element.chartType === "bar" ? "bar" : e.element.chartType === "scatter" ? "scatter" : "line"
336
+ };
337
+ }), u = () => {
338
+ if (!n || d || !s.value)
339
+ return;
340
+ t ? t.resize() : (t = J.init(s.value), l && t.on("finished", l));
341
+ const p = e.element.chartType === "bar";
342
+ t.setOption({
343
+ animation: !1,
344
+ color: e.element.themeColors,
345
+ grid: { bottom: 30, containLabel: !0, left: 24, right: 18, top: 36 },
346
+ legend: { show: e.element.data.legends.length > 1, textStyle: { color: e.element.textColor } },
347
+ radar: e.element.chartType === "radar" ? { indicator: e.element.data.labels.map((y) => ({ name: y })) } : void 0,
348
+ series: m(),
349
+ tooltip: { trigger: "axis" },
350
+ xAxis: ["pie", "ring", "radar"].includes(e.element.chartType) ? void 0 : {
351
+ data: p ? void 0 : e.element.data.labels,
352
+ splitLine: { lineStyle: { color: e.element.lineColor || "#e6e8ef" } },
353
+ type: p ? "value" : "category"
354
+ },
355
+ yAxis: ["pie", "ring", "radar"].includes(e.element.chartType) ? void 0 : {
356
+ data: p ? e.element.data.labels : void 0,
357
+ splitLine: { lineStyle: { color: e.element.lineColor || "#e6e8ef" } },
358
+ type: p ? "category" : "value"
359
+ }
360
+ }, !0);
361
+ };
362
+ return V(() => e.element, u, { deep: !0, flush: "post" }), D(async () => {
363
+ await document.fonts.ready, n = !0, u();
364
+ }), O(() => {
365
+ d = !0, t == null || t.dispose(), l == null || l();
366
+ }), (p, y) => (r(), a("div", {
367
+ ref_key: "chartRoot",
368
+ ref: s,
369
+ class: "ppt-chart-content",
370
+ style: v(c.value)
371
+ }, null, 4));
372
+ }
373
+ });
374
+ const xe = /* @__PURE__ */ $(we, [["__scopeId", "data-v-d0925046"]]), Se = ["colspan", "rowspan"], Ee = /* @__PURE__ */ g({
375
+ __name: "TableElement",
376
+ props: {
377
+ element: {}
378
+ },
379
+ setup(o) {
380
+ const e = o, s = f(() => {
381
+ var t, l, n, d;
382
+ return {
383
+ background: e.element.fill || "#fff",
384
+ borderColor: ((t = e.element.outline) == null ? void 0 : t.color) || "#d9dce6",
385
+ borderStyle: ((l = e.element.outline) == null ? void 0 : l.width) === 0 ? "none" : ((n = e.element.outline) == null ? void 0 : n.style) || "solid",
386
+ borderWidth: `${((d = e.element.outline) == null ? void 0 : d.width) ?? 1}px`
387
+ };
388
+ }), i = (t, l) => {
389
+ var n, d, c, m, u, p, y, h, k, w;
390
+ return {
391
+ background: ((n = t.style) == null ? void 0 : n.backcolor) || "transparent",
392
+ color: ((d = t.style) == null ? void 0 : d.color) || "#333",
393
+ fontFamily: (c = t.style) == null ? void 0 : c.fontname,
394
+ fontSize: ((m = t.style) == null ? void 0 : m.fontsize) || "16px",
395
+ fontStyle: (u = t.style) != null && u.em ? "italic" : "normal",
396
+ fontWeight: (p = t.style) != null && p.bold ? 600 : 400,
397
+ height: `${e.element.cellMinHeight || 36}px`,
398
+ textAlign: ((y = t.style) == null ? void 0 : y.align) || "left",
399
+ verticalAlign: ((h = t.style) == null ? void 0 : h.vAlign) || "middle",
400
+ width: `${(((k = e.element.colWidths) == null ? void 0 : k[l]) || 1 / Math.max(1, ((w = e.element.data[0]) == null ? void 0 : w.length) || 1)) * 100}%`
401
+ };
402
+ };
403
+ return (t, l) => (r(), a("table", {
404
+ class: "ppt-table-content",
405
+ style: v(s.value)
406
+ }, [
407
+ _("tbody", null, [
408
+ (r(!0), a(S, null, E(t.element.data, (n, d) => (r(), a("tr", { key: d }, [
409
+ (r(!0), a(S, null, E(n, (c, m) => (r(), a("td", {
410
+ key: c.id,
411
+ colspan: c.colspan || 1,
412
+ rowspan: c.rowspan || 1,
413
+ class: x({ "ppt-table-cell-editable": t.$slots["table-cell-editor"] }),
414
+ style: v(i(c, m))
415
+ }, [
416
+ b(t.$slots, "table-cell-editor", {
417
+ element: t.element,
418
+ cell: c,
419
+ rowIndex: d,
420
+ colIndex: m
421
+ }, () => [
422
+ Y(C(c.text), 1)
423
+ ], !0)
424
+ ], 14, Se))), 128))
425
+ ]))), 128))
426
+ ])
427
+ ], 4));
428
+ }
429
+ });
430
+ const Te = /* @__PURE__ */ $(Ee, [["__scopeId", "data-v-b7c947a1"]]), Ie = { class: "ppt-latex-content" }, Me = ["viewBox"], Le = ["d", "fill", "stroke", "stroke-width"], ze = { key: 1 }, Ce = /* @__PURE__ */ g({
431
+ __name: "LatexElement",
432
+ props: {
433
+ element: {}
434
+ },
435
+ setup(o) {
436
+ return (e, s) => (r(), a("div", Ie, [
437
+ e.element.path && e.element.viewBox ? (r(), a("svg", {
438
+ key: 0,
439
+ viewBox: `0 0 ${e.element.viewBox[0]} ${e.element.viewBox[1]}`
440
+ }, [
441
+ _("path", {
442
+ d: e.element.path,
443
+ fill: e.element.color || "#333",
444
+ stroke: e.element.color || "#333",
445
+ "stroke-width": e.element.strokeWidth || 0
446
+ }, null, 8, Le)
447
+ ], 8, Me)) : (r(), a("span", ze, C(e.element.latex), 1))
448
+ ]));
449
+ }
450
+ });
451
+ const He = /* @__PURE__ */ $(Ce, [["__scopeId", "data-v-bc1283bd"]]), Re = { class: "ppt-video-content" }, Ae = ["src"], Be = /* @__PURE__ */ g({
452
+ __name: "VideoElement",
453
+ props: {
454
+ element: {}
455
+ },
456
+ setup(o) {
457
+ return (e, s) => (r(), a("div", Re, [
458
+ e.element.poster ? (r(), a("img", {
459
+ key: 0,
460
+ src: e.element.poster,
461
+ alt: ""
462
+ }, null, 8, Ae)) : T("", !0)
463
+ ]));
464
+ }
465
+ });
466
+ const Fe = /* @__PURE__ */ $(Be, [["__scopeId", "data-v-51f57e49"]]), F = (o) => (q("data-v-100cc51b"), o = o(), G(), o), Ne = /* @__PURE__ */ F(() => /* @__PURE__ */ _("span", { class: "ppt-audio-icon" }, "♪", -1)), We = /* @__PURE__ */ F(() => /* @__PURE__ */ _("audio", {
467
+ controls: "",
468
+ preload: "none",
469
+ tabindex: "-1",
470
+ "aria-disabled": "true"
471
+ }, null, -1)), je = [
472
+ Ne,
473
+ We
474
+ ], Pe = /* @__PURE__ */ g({
475
+ __name: "AudioElement",
476
+ props: {
477
+ element: {}
478
+ },
479
+ setup(o) {
480
+ return (e, s) => (r(), a("div", {
481
+ class: "ppt-audio-content",
482
+ style: v({ color: e.element.color || "#5b5ce2" })
483
+ }, je, 4));
484
+ }
485
+ });
486
+ const Ve = /* @__PURE__ */ $(Pe, [["__scopeId", "data-v-100cc51b"]]), De = ["data-ppt-element-id"], Oe = /* @__PURE__ */ g({
487
+ __name: "ElementRenderer",
488
+ props: {
489
+ element: {},
490
+ elementIndex: {}
491
+ },
492
+ setup(o) {
493
+ const e = o, s = {
494
+ text: te,
495
+ image: oe,
496
+ shape: ue,
497
+ line: be,
498
+ chart: xe,
499
+ table: Te,
500
+ latex: He,
501
+ video: Fe,
502
+ audio: Ve
503
+ }, i = f(() => {
504
+ const t = K(e.element);
505
+ return {
506
+ width: `${t.width}px`,
507
+ height: `${t.height}px`,
508
+ left: `${t.left}px`,
509
+ top: `${t.top}px`,
510
+ transform: `rotate(${t.rotate}deg)`,
511
+ opacity: e.element.opacity ?? 1,
512
+ // DSL 数组顺序就是图层顺序。
513
+ zIndex: e.elementIndex + 1
514
+ };
515
+ });
516
+ return (t, l) => (r(), a("div", {
517
+ class: x(["ppt-element", [`ppt-${t.element.type}`, t.element.class]]),
518
+ "data-ppt-element-id": t.element.id,
519
+ style: v(i.value)
520
+ }, [
521
+ (r(), H(X(s[t.element.type]), { element: t.element }, Z({ _: 2 }, [
522
+ t.$slots["text-editor"] ? {
523
+ name: "text-editor",
524
+ fn: I((n) => [
525
+ b(t.$slots, "text-editor", M(L(n)), void 0, !0)
526
+ ]),
527
+ key: "0"
528
+ } : void 0,
529
+ t.$slots["shape-text-editor"] ? {
530
+ name: "shape-text-editor",
531
+ fn: I((n) => [
532
+ b(t.$slots, "shape-text-editor", M(L(n)), void 0, !0)
533
+ ]),
534
+ key: "1"
535
+ } : void 0,
536
+ t.$slots["table-cell-editor"] ? {
537
+ name: "table-cell-editor",
538
+ fn: I((n) => [
539
+ b(t.$slots, "table-cell-editor", M(L(n)), void 0, !0)
540
+ ]),
541
+ key: "2"
542
+ } : void 0
543
+ ]), 1032, ["element"]))
544
+ ], 14, De));
545
+ }
546
+ });
547
+ const Ye = /* @__PURE__ */ $(Oe, [["__scopeId", "data-v-4031d518"]]), qe = ["data-ppt-slide-id"], Ge = /* @__PURE__ */ g({
548
+ __name: "SlideRenderer",
549
+ props: {
550
+ slide: {},
551
+ width: {},
552
+ height: {},
553
+ scale: { default: 1 }
554
+ },
555
+ setup(o) {
556
+ const e = o, s = f(() => U(e.slide, e.width, e.height, e.scale));
557
+ return (i, t) => (r(), a("div", {
558
+ class: "ppt-slide",
559
+ "data-ppt-slide-id": i.slide.id,
560
+ style: v(s.value)
561
+ }, [
562
+ (r(!0), a(S, null, E(i.slide.elements, (l, n) => (r(), H(Ye, {
563
+ key: l.id,
564
+ element: l,
565
+ "element-index": n
566
+ }, null, 8, ["element", "element-index"]))), 128))
567
+ ], 12, qe));
568
+ }
569
+ });
570
+ const Je = /* @__PURE__ */ $(Ge, [["__scopeId", "data-v-a6a99631"]]);
571
+ export {
572
+ Ye as ElementRenderer,
573
+ Je as SlideRenderer,
574
+ K as getPptDslElementFrame,
575
+ A as getPptDslLineFrame,
576
+ U as getPptDslSlideStyle
577
+ };
package/docs/AGENT.md ADDED
@@ -0,0 +1,36 @@
1
+ # Agent 渲染与截图协议
2
+
3
+ CLI 与 Node API 生成 HTML 后结束,不会等待远程素材加载。agent 应在自己的浏览器环境打开文件并检查状态。
4
+
5
+ ```ts
6
+ window.__PPT_DSL_RENDER__: {
7
+ status: 'loading' | 'ready' | 'error'
8
+ errors: string[]
9
+ }
10
+ ```
11
+
12
+ `ready` 表示 Vue 挂载、字体加载等待、图片解码、背景图加载和 ECharts 绘制完成,且经过浏览器绘制帧。图片或代码错误会记录在 `errors`;超过 30 秒仍未完成也会报错。状态不包含版式评价,不保证远程图片内容稳定,也无法冻结 GIF/APNG 等素材自身的动画。需要重复对照时使用固定素材、同一浏览器版本和相同字体环境。
13
+
14
+ 截图根节点固定为 `#ppt-slide`,内部尺寸保持 DSL 的 CSS 像素宽高。HTML 会等比例缩小以适配窗口并居中,窗口较大时保持原尺寸。节点截图得到的是当前显示尺寸;需要原始分辨率时,在打开 HTML 前将浏览器 viewport 设置为 DSL 的 width、height。元素节点带有 `data-ppt-element-id`,页面节点带有 `data-ppt-slide-id`。这些属性可以定位元素,但包不主动计算文字溢出或布局评分。
15
+
16
+ 下面只是调用方已安装 Playwright 时的示例;Playwright 不属于本包依赖,也不会由本包下载或启动:
17
+
18
+ ```js
19
+ import { pathToFileURL } from 'node:url'
20
+
21
+ // page 是 agent 自己管理的浏览器页。
22
+ await page.goto(pathToFileURL(htmlFile).href)
23
+ await page.waitForFunction(
24
+ () => window.__PPT_DSL_RENDER__?.status === 'ready'
25
+ || window.__PPT_DSL_RENDER__?.status === 'error',
26
+ null,
27
+ { timeout: 35000 },
28
+ )
29
+ const state = await page.evaluate(() => window.__PPT_DSL_RENDER__)
30
+ if (state.status === 'error') throw new Error(state.errors.join('\n'))
31
+ await page.locator('#ppt-slide').screenshot({ path: screenshotFile })
32
+ ```
33
+
34
+ 若 agent 的浏览器工具不允许 `file:`,由调用方使用已有的文件预览或静态文件服务打开同一 HTML;包不会启动服务。浏览器必须允许执行内嵌脚本。
35
+
36
+ 生成失败先处理 stderr;浏览器加载失败先处理状态中的错误;视觉审查发现的问题再通过修改 DSL 解决。不要把“HTML 写入成功”当作“素材加载成功”,也不要自动将缺失素材替换为其他地址。