@web-ppt/editor 0.5.0-beta.2 → 0.5.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 (47) hide show
  1. package/CHANGELOG.md +183 -0
  2. package/README.md +96 -5
  3. package/dist/accessibility.js +60 -0
  4. package/dist/adjustments/index.d.ts +2 -0
  5. package/dist/adjustments/preset-adjustment-editor.d.ts +4 -0
  6. package/dist/adjustments/types.d.ts +22 -0
  7. package/dist/adjustments.js +300 -0
  8. package/dist/canvas-accessibility.d.ts +6 -0
  9. package/dist/chart/index.d.ts +2 -0
  10. package/dist/chart-shared/index.d.ts +2 -0
  11. package/dist/chart-shared.js +7 -0
  12. package/dist/chart.js +6 -0
  13. package/dist/common-object-slide-commands.d.ts +20 -0
  14. package/dist/design/index.d.ts +3 -0
  15. package/dist/design-editor-types.d.ts +15 -0
  16. package/dist/design-editor.d.ts +3 -0
  17. package/dist/design.js +108 -0
  18. package/dist/dom-identity.d.ts +2 -1
  19. package/dist/edit-context/geometry.d.ts +8 -0
  20. package/dist/edit-context/index.d.ts +8 -0
  21. package/dist/edit-context/native.d.ts +33 -0
  22. package/dist/edit-context.js +333 -0
  23. package/dist/editor.js +1 -6706
  24. package/dist/element-clipboard.d.ts +4 -2
  25. package/dist/framework-adapter-types.d.ts +14 -2
  26. package/dist/image-insertion.d.ts +4 -2
  27. package/dist/index.d.ts +5 -4
  28. package/dist/media/index.d.ts +1 -0
  29. package/dist/media.js +1 -0
  30. package/dist/rotation-geometry.d.ts +4 -1
  31. package/dist/selection-hit.d.ts +6 -0
  32. package/dist/selection-pane-types.d.ts +1 -0
  33. package/dist/session-state.d.ts +5 -1
  34. package/dist/session.d.ts +17 -1
  35. package/dist/slide-dom-renderer.d.ts +1 -0
  36. package/dist/slide-editor-commands.d.ts +14 -2
  37. package/dist/slide-editor-events.d.ts +1 -0
  38. package/dist/slide-editor-types.d.ts +35 -2
  39. package/dist/slide-pointer-controller.d.ts +3 -0
  40. package/dist/templates/index.d.ts +2 -0
  41. package/dist/templates.js +5 -0
  42. package/dist/text-edit-commit.d.ts +8 -0
  43. package/dist/text-editor.d.ts +7 -3
  44. package/dist/text-keyboard.d.ts +2 -2
  45. package/dist/touch-gesture.d.ts +42 -0
  46. package/dist/transform-frame.d.ts +11 -6
  47. package/package.json +38 -6
@@ -0,0 +1,300 @@
1
+ import { resolvePresetAdjustmentHandles as m, dragPresetAdjustmentHandle as g } from "@web-ppt/core/geometry/handles";
2
+ import { queryElementPresetGeometry as p, slideOfElement as f, elementFrameToSlidePoint as v, screenToSlidePoint as w, slideToElementFramePoint as E } from "@web-ppt/edit-core";
3
+ const A = 3, d = (c) => c.pointerId ?? 0;
4
+ class b {
5
+ constructor(t) {
6
+ this.active = null, this.root = t;
7
+ }
8
+ get isActive() {
9
+ return this.active !== null;
10
+ }
11
+ begin(t, e) {
12
+ var s, n;
13
+ this.cancel();
14
+ const r = { x: t.clientX, y: t.clientY };
15
+ this.active = {
16
+ pointerId: d(t),
17
+ startScreen: r,
18
+ snapshot: {
19
+ screen: r,
20
+ altKey: t.altKey,
21
+ ctrlKey: t.ctrlKey,
22
+ metaKey: t.metaKey,
23
+ shiftKey: t.shiftKey
24
+ },
25
+ gesture: e,
26
+ started: !1,
27
+ frame: null,
28
+ cursor: this.root.style.cursor
29
+ };
30
+ try {
31
+ (n = (s = this.root).setPointerCapture) == null || n.call(s, d(t));
32
+ } catch {
33
+ }
34
+ }
35
+ move(t) {
36
+ var r, s;
37
+ const e = this.active;
38
+ if (!(!e || d(t) !== e.pointerId)) {
39
+ this.updateSnapshot(e, t);
40
+ try {
41
+ (s = (r = e.gesture).observePointer) == null || s.call(r, e.snapshot);
42
+ } catch (n) {
43
+ throw this.clear(e), n;
44
+ }
45
+ if (!e.started) {
46
+ if (Math.hypot(
47
+ e.snapshot.screen.x - e.startScreen.x,
48
+ e.snapshot.screen.y - e.startScreen.y
49
+ ) < A) return;
50
+ e.started = !0;
51
+ try {
52
+ e.gesture.start();
53
+ } catch (i) {
54
+ throw this.clear(e), i;
55
+ }
56
+ this.root.style.cursor = e.gesture.cursor, this.root.dataset[e.gesture.dataset.name] = e.gesture.dataset.value;
57
+ }
58
+ t.preventDefault(), this.scheduleFrame(e);
59
+ }
60
+ }
61
+ finish(t) {
62
+ var s, n;
63
+ const e = this.active;
64
+ if (!e || d(t) !== e.pointerId) return "ignored";
65
+ this.updateSnapshot(e, t);
66
+ let r;
67
+ try {
68
+ (n = (s = e.gesture).observePointer) == null || n.call(s, e.snapshot), r = e.started ? e.gesture.finish(e.snapshot) : null;
69
+ } catch (i) {
70
+ throw this.clear(e), i;
71
+ }
72
+ return this.clear(e), r == null || r(), r && t.preventDefault(), e.started ? "gesture" : "click";
73
+ }
74
+ /** 键盘确认使用最后一次指针快照;先清理 capture/rAF,再执行提交,避免订阅回调重入活动手势。 */
75
+ commit() {
76
+ const t = this.active;
77
+ if (!t) return !1;
78
+ let e = null;
79
+ try {
80
+ e = t.started ? t.gesture.finish(t.snapshot) : null;
81
+ } catch (r) {
82
+ throw this.clear(t), r;
83
+ }
84
+ return this.clear(t), e == null || e(), t.started;
85
+ }
86
+ modifier(t) {
87
+ const e = this.active;
88
+ return !e || !["Shift", "Alt", "Control", "Meta"].includes(t.key) ? !1 : (e.snapshot = {
89
+ ...e.snapshot,
90
+ altKey: t.altKey,
91
+ ctrlKey: t.ctrlKey,
92
+ metaKey: t.metaKey,
93
+ shiftKey: t.shiftKey
94
+ }, e.started && this.scheduleFrame(e), !0);
95
+ }
96
+ cancel() {
97
+ this.active && this.clear(this.active);
98
+ }
99
+ cancelPointer(t) {
100
+ this.active && d(t) === this.active.pointerId && this.clear(this.active);
101
+ }
102
+ updateSnapshot(t, e) {
103
+ t.snapshot = {
104
+ screen: { x: e.clientX, y: e.clientY },
105
+ altKey: e.altKey,
106
+ ctrlKey: e.ctrlKey,
107
+ metaKey: e.metaKey,
108
+ shiftKey: e.shiftKey
109
+ };
110
+ }
111
+ scheduleFrame(t) {
112
+ if (t.frame !== null) return;
113
+ const e = this.root.ownerDocument.defaultView;
114
+ if (!(e != null && e.requestAnimationFrame)) {
115
+ try {
116
+ t.gesture.frame(t.snapshot);
117
+ } catch (r) {
118
+ throw this.clear(t), r;
119
+ }
120
+ return;
121
+ }
122
+ t.frame = e.requestAnimationFrame(() => {
123
+ if (t.frame = null, this.active === t)
124
+ try {
125
+ t.gesture.frame(t.snapshot);
126
+ } catch (r) {
127
+ throw this.clear(t), r;
128
+ }
129
+ });
130
+ }
131
+ clear(t) {
132
+ var r, s;
133
+ this.active = null;
134
+ const e = this.root.ownerDocument.defaultView;
135
+ t.frame !== null && (e != null && e.cancelAnimationFrame) && e.cancelAnimationFrame(t.frame);
136
+ try {
137
+ t.started && t.gesture.clear();
138
+ } finally {
139
+ this.root.style.cursor = t.cursor, delete this.root.dataset[t.gesture.dataset.name];
140
+ try {
141
+ (s = (r = this.root).hasPointerCapture) != null && s.call(r, t.pointerId) && this.root.releasePointerCapture(t.pointerId);
142
+ } catch {
143
+ }
144
+ }
145
+ }
146
+ }
147
+ const I = "http://www.w3.org/2000/svg";
148
+ function y(c, t) {
149
+ return c.createElementNS(I, t);
150
+ }
151
+ class P {
152
+ constructor(t, e, r) {
153
+ var a;
154
+ if (this.session = t, this.view = e, this.options = r, this.activeId = null, this.preview = null, this.isDestroyed = !1, this.pointerDown = (o) => {
155
+ const h = o.target instanceof Element ? o.target.closest("[data-ppt-preset-handle]") : null;
156
+ if (!(!h || o.button !== 0 || o.isPrimary === !1))
157
+ try {
158
+ const u = this.geometry;
159
+ if (!u) return;
160
+ this.lifecycle.begin(o, this.gesture(Number(h.dataset.pptPresetHandle), u)), this.stop(o);
161
+ } catch (u) {
162
+ this.report(u);
163
+ }
164
+ }, this.pointerMove = (o) => {
165
+ if (this.lifecycle.isActive)
166
+ try {
167
+ this.lifecycle.move(o), this.stop(o);
168
+ } catch (h) {
169
+ this.report(h);
170
+ }
171
+ }, this.pointerUp = (o) => {
172
+ if (this.lifecycle.isActive)
173
+ try {
174
+ this.lifecycle.finish(o), this.stop(o);
175
+ } catch (h) {
176
+ this.report(h);
177
+ }
178
+ }, this.pointerCancel = (o) => {
179
+ this.lifecycle.isActive && (this.lifecycle.cancelPointer(o), this.stop(o));
180
+ }, this.keyDown = (o) => {
181
+ o.key !== "Escape" || !this.lifecycle.isActive || (this.lifecycle.cancel(), this.stop(o));
182
+ }, t.disposed || e.destroyed) throw new Error("不能挂载到已释放的编辑视图");
183
+ this.root = e.element;
184
+ const s = this.root.querySelector("[data-ppt-stage]"), n = this.root.querySelector('[data-ppt-layer="interaction"]'), i = this.root.querySelector('[data-ppt-layer="static"]');
185
+ if (!s || !n || !i) throw new Error("编辑视图缺少三层 DOM");
186
+ this.stage = s, this.layer = n, this.lifecycle = new b(this.root), this.root.addEventListener("pointerdown", this.pointerDown, !0), this.root.addEventListener("pointermove", this.pointerMove, !0), this.root.addEventListener("pointerup", this.pointerUp, !0), this.root.addEventListener("pointercancel", this.pointerCancel, !0), this.root.addEventListener("keydown", this.keyDown, !0), this.unsubscribe = t.editor.subscribe(() => this.render());
187
+ const l = ((a = this.root.ownerDocument.defaultView) == null ? void 0 : a.MutationObserver) ?? MutationObserver;
188
+ this.observer = new l(() => this.render()), this.observer.observe(i, { childList: !0 });
189
+ }
190
+ get elementId() {
191
+ return this.activeId;
192
+ }
193
+ get geometry() {
194
+ return !this.activeId || !this.session.editor.doc.elements[this.activeId] ? null : p(this.session.editor.doc, [this.activeId]).value;
195
+ }
196
+ get handles() {
197
+ const t = this.activeId, e = this.preview ?? this.geometry;
198
+ if (!t || !e) return [];
199
+ const r = this.session.editor.effectiveElement(t);
200
+ return m(e, r.w, r.h);
201
+ }
202
+ get destroyed() {
203
+ return this.isDestroyed;
204
+ }
205
+ start(t) {
206
+ this.assertAlive();
207
+ const e = this.session.editor.selection, r = t ?? (e.kind === "elements" && e.ids.length === 1 ? e.ids[0] : null);
208
+ return !r || this.view.mode !== "edit" || f(this.session.editor.doc, r) !== this.view.slideId || !p(this.session.editor.doc, [r]).value ? !1 : (this.activeId = r, this.preview = null, this.render(), !0);
209
+ }
210
+ end() {
211
+ var t;
212
+ this.lifecycle.cancel(), this.activeId = null, this.preview = null, (t = this.group()) == null || t.remove();
213
+ }
214
+ setPreset(t) {
215
+ this.assertAlive();
216
+ const e = this.session.editor.selection, r = this.activeId ?? (e.kind === "elements" && e.ids.length === 1 ? e.ids[0] : null);
217
+ if (!r || this.view.mode !== "edit") return !1;
218
+ try {
219
+ return this.session.editor.exec({ type: "SetPreset", id: r, preset: t }), this.activeId = r, this.preview = null, this.render(), !0;
220
+ } catch (s) {
221
+ return this.report(s), !1;
222
+ }
223
+ }
224
+ refresh() {
225
+ this.assertAlive(), this.render();
226
+ }
227
+ destroy() {
228
+ var t;
229
+ this.isDestroyed || (this.isDestroyed = !0, this.lifecycle.cancel(), this.unsubscribe(), this.observer.disconnect(), this.root.removeEventListener("pointerdown", this.pointerDown, !0), this.root.removeEventListener("pointermove", this.pointerMove, !0), this.root.removeEventListener("pointerup", this.pointerUp, !0), this.root.removeEventListener("pointercancel", this.pointerCancel, !0), this.root.removeEventListener("keydown", this.keyDown, !0), (t = this.group()) == null || t.remove(), this.activeId = null, this.preview = null);
230
+ }
231
+ assertAlive() {
232
+ if (this.isDestroyed || this.session.disposed || this.view.destroyed)
233
+ throw new Error("预设调节柄扩展已经释放");
234
+ }
235
+ group() {
236
+ return this.layer.querySelector("[data-ppt-preset-adjustments]");
237
+ }
238
+ render() {
239
+ var r;
240
+ (r = this.group()) == null || r.remove();
241
+ const t = this.activeId;
242
+ if (!t || this.isDestroyed || this.view.destroyed || this.view.mode !== "edit" || !this.session.editor.doc.elements[t] || f(this.session.editor.doc, t) !== this.view.slideId) return;
243
+ const e = y(this.layer.ownerDocument, "g");
244
+ e.dataset.pptPresetAdjustments = "", e.dataset.pptPresetElement = t;
245
+ for (const s of this.handles) {
246
+ const n = v(this.session.editor.doc, t, s), i = y(this.layer.ownerDocument, "circle");
247
+ i.dataset.pptPresetHandle = String(s.index), i.dataset.pptPresetKind = s.kind, i.setAttribute("cx", String(n.x)), i.setAttribute("cy", String(n.y)), i.setAttribute("r", String(6 / this.view.zoom)), i.setAttribute("fill", "#f59e0b"), i.setAttribute("stroke", "#fff"), i.setAttribute("stroke-width", String(2 / this.view.zoom)), i.style.pointerEvents = "all", i.style.cursor = "crosshair", e.append(i);
248
+ }
249
+ this.layer.append(e);
250
+ }
251
+ geometryAt(t, e, r) {
252
+ const s = this.activeId, n = this.stage.getBoundingClientRect(), i = w(t.screen, {
253
+ left: n.left,
254
+ top: n.top,
255
+ zoom: this.view.zoom
256
+ }), l = E(this.session.editor.doc, s, i), a = this.session.editor.effectiveElement(s);
257
+ return g(r, a.w, a.h, e, l);
258
+ }
259
+ gesture(t, e) {
260
+ let r = e;
261
+ const s = (n) => {
262
+ r = this.geometryAt(n, t, e), this.preview = r, this.render();
263
+ };
264
+ return {
265
+ cursor: "crosshair",
266
+ dataset: { name: "pptPresetDragging", value: String(t) },
267
+ start: () => {
268
+ },
269
+ frame: s,
270
+ finish: (n) => {
271
+ s(n);
272
+ const i = this.activeId, l = Object.entries(r.adj).filter(([a, o]) => e.adj[a] !== o);
273
+ return l.length ? () => {
274
+ this.preview = null, this.session.editor.transaction((a) => {
275
+ for (const [o, h] of l)
276
+ a.exec({ type: "SetAdj", id: i, name: o, value: h });
277
+ }, "拖动预设调节柄");
278
+ } : null;
279
+ },
280
+ clear: () => {
281
+ this.preview = null, this.render();
282
+ }
283
+ };
284
+ }
285
+ stop(t) {
286
+ t.preventDefault(), t.stopImmediatePropagation();
287
+ }
288
+ report(t) {
289
+ var e, r;
290
+ this.lifecycle.cancel(), (r = (e = this.options).onError) == null || r.call(e, t), this.options.onError || queueMicrotask(() => {
291
+ throw t;
292
+ });
293
+ }
294
+ }
295
+ function D(c, t, e = {}) {
296
+ return new P(c, t, e);
297
+ }
298
+ export {
299
+ D as createPresetAdjustmentEditor
300
+ };
@@ -0,0 +1,6 @@
1
+ import type { EditorSession } from './session';
2
+ import type { SlideEditor } from './slide-editor-types';
3
+ /** 产品可在挂载后启用;不使用辅助对象目录的宿主不承担其模型遍历与 DOM 成本。 */
4
+ export declare function createCanvasAccessibility(session: EditorSession, view: SlideEditor): {
5
+ dispose(): void;
6
+ };
@@ -0,0 +1,2 @@
1
+ export { createChartDataEditor, listEditableCharts, queryChartData, } from '@web-ppt/edit-core/chart';
2
+ export type { ChartCategory, ChartDataBinding, ChartDataEditor, ChartDataset, ChartFormulaBinding, ChartPlotKind, ChartPoint, ChartPointId, ChartSeries, ChartSeriesId, EditableChart, } from '@web-ppt/edit-core/chart';
@@ -0,0 +1,2 @@
1
+ export { registerSharedChartEditing, createChartDataEditor, listEditableCharts, queryChartData, } from '@web-ppt/edit-core/chart-shared';
2
+ export type { ChartCategory, ChartDataBinding, ChartDataEditor, ChartDataset, ChartFormulaBinding, ChartPlotKind, ChartPoint, ChartPointId, ChartSeries, ChartSeriesId, EditableChart, } from '@web-ppt/edit-core/chart-shared';
@@ -0,0 +1,7 @@
1
+ import { createChartDataEditor as a, listEditableCharts as e, queryChartData as i, registerSharedChartEditing as h } from "@web-ppt/edit-core/chart-shared";
2
+ export {
3
+ a as createChartDataEditor,
4
+ e as listEditableCharts,
5
+ i as queryChartData,
6
+ h as registerSharedChartEditing
7
+ };
package/dist/chart.js ADDED
@@ -0,0 +1,6 @@
1
+ import { createChartDataEditor as r, listEditableCharts as e, queryChartData as h } from "@web-ppt/edit-core/chart";
2
+ export {
3
+ r as createChartDataEditor,
4
+ e as listEditableCharts,
5
+ h as queryChartData
6
+ };
@@ -0,0 +1,20 @@
1
+ import type { AddSectionCommand, DistributeElementsCommand, Editor, ElementAltTextState, ElementId, SectionId, SectionRecord, SetAltTextCommand, SetSlideSizeCommand, SlideSizeState } from '@web-ppt/edit-core';
2
+ /** 挂载视图与 headless adapter 共享同一套公共命令语义。 */
3
+ export declare class CommonObjectSlideCommands {
4
+ private readonly editor;
5
+ constructor(editor: Editor);
6
+ distribute(enabled: boolean, axis: DistributeElementsCommand['axis'], ids?: readonly ElementId[]): boolean;
7
+ queryAltText(id?: ElementId): ElementAltTextState | null;
8
+ setAltText(enabled: boolean, value: Pick<SetAltTextCommand, 'title' | 'descr'>, id?: ElementId): boolean;
9
+ listSections(): SectionRecord[];
10
+ addSection(enabled: boolean, value: Omit<AddSectionCommand, 'type'>): SectionRecord | null;
11
+ renameSection(enabled: boolean, id: SectionId, name: string): boolean;
12
+ moveSection(enabled: boolean, id: SectionId, after: SectionId | null): boolean;
13
+ removeSection(enabled: boolean, id: SectionId): boolean;
14
+ querySlideSize(): SlideSizeState;
15
+ setSlideSize(enabled: boolean, value: Pick<SetSlideSizeCommand, 'w' | 'h' | 'fit'>): boolean;
16
+ private writable;
17
+ private exec;
18
+ private selectedElementId;
19
+ }
20
+ export declare function commonObjectSlideCommands(editor: Editor): CommonObjectSlideCommands;
@@ -0,0 +1,3 @@
1
+ export { createDesignEditor } from '../design-editor';
2
+ export type { DesignEditor, DesignEditorOptions } from '../design-editor-types';
3
+ export { listLayouts, listMasters, queryLayout, queryMaster, toDesignCanvas, } from '@web-ppt/edit-core';
@@ -0,0 +1,15 @@
1
+ import type { DesignCommand, DesignTarget, TransactionResult } from '@web-ppt/edit-core';
2
+ export interface DesignEditorOptions {
3
+ readonly target: DesignTarget;
4
+ readonly textMode?: 'auto' | 'html' | 'svg';
5
+ }
6
+ /** 版式 DOM 适配器只暴露设计目标命令,不混入页序、备注或动画入口。 */
7
+ export interface DesignEditor {
8
+ readonly element: HTMLDivElement;
9
+ readonly target: DesignTarget;
10
+ readonly destroyed: boolean;
11
+ setTarget(target: DesignTarget): void;
12
+ exec(...commands: DesignCommand[]): TransactionResult;
13
+ render(): void;
14
+ destroy(): void;
15
+ }
@@ -0,0 +1,3 @@
1
+ import type { DesignEditor, DesignEditorOptions } from './design-editor-types';
2
+ import type { EditorSession } from './session';
3
+ export declare function createDesignEditor(container: HTMLElement, session: EditorSession, options: DesignEditorOptions): DesignEditor;
package/dist/design.js ADDED
@@ -0,0 +1,108 @@
1
+ import { renderSlideToSvg as u } from "@web-ppt/core";
2
+ import { foreignObjectScalesCorrectly as f } from "@web-ppt/viewer-core";
3
+ import { listLayouts as x, listMasters as T, queryLayout as M, queryMaster as b, toDesignCanvas as $ } from "@web-ppt/edit-core";
4
+ function h(s, e) {
5
+ const t = [], r = (d) => {
6
+ for (const i of d) {
7
+ t.push(i);
8
+ const n = s.elements[i];
9
+ n && n.meta.editable !== "frame" && n.children && r(n.children);
10
+ }
11
+ };
12
+ return r(e), t;
13
+ }
14
+ function c(s, e) {
15
+ return [...s.nodeType === 1 && s.matches(e) ? [s] : [], ...s.querySelectorAll(e)];
16
+ }
17
+ function m(s, e, t) {
18
+ return c(s, "[data-edit-id]").find((r) => r.dataset[e] === t) ?? null;
19
+ }
20
+ function l(s, e, t) {
21
+ var d;
22
+ const r = c(s, "[data-el]");
23
+ if (r.length !== t.length) throw new Error("渲染节点与编辑投影的元素数量不一致");
24
+ r.forEach((i, n) => {
25
+ const o = t[n];
26
+ if (o === null) return;
27
+ const a = e.elements[o].src.id;
28
+ if ((a === void 0 ? "" : String(a)) !== i.dataset.el)
29
+ throw new Error(`渲染节点与编辑投影的顺序不一致:${o}`);
30
+ i.dataset.editId = o;
31
+ });
32
+ for (const i of t) {
33
+ if (i === null) continue;
34
+ const n = m(s, "editId", i);
35
+ if (!n) throw new Error(`渲染结果缺少编辑元素:${i}`);
36
+ const o = ((d = n.parentElement) == null ? void 0 : d.localName) === "a" ? n.parentElement : n;
37
+ o.dataset.editRoot = i;
38
+ }
39
+ for (const i of s.querySelectorAll("[data-r]"))
40
+ i.dataset.pptSearchR = i.dataset.r, delete i.dataset.r, i.dataset.from !== void 0 && (i.dataset.pptSearchFrom = i.dataset.from, delete i.dataset.from), i.dataset.to !== void 0 && (i.dataset.pptSearchTo = i.dataset.to, delete i.dataset.to);
41
+ }
42
+ function p(s, e, t) {
43
+ if (t.kind === "master") {
44
+ const i = e.masters[t.id];
45
+ if (!i) throw new Error(`找不到母版设计目标:${t.id}`);
46
+ l(s, e, h(e, i.children));
47
+ return;
48
+ }
49
+ const r = e.layouts[t.id];
50
+ if (!r) throw new Error(`找不到版式设计目标:${t.id}`);
51
+ const d = r.showMasterShapes === !1 ? void 0 : e.masters[r.origin.masterPart];
52
+ l(s, e, h(e, [
53
+ ...(d == null ? void 0 : d.children) ?? [],
54
+ ...r.children
55
+ ]));
56
+ }
57
+ let g = 0;
58
+ class w {
59
+ constructor(e, t, r) {
60
+ if (this.session = t, this.isDestroyed = !1, t.disposed) throw new Error("不能挂载已经释放的编辑会话");
61
+ this.currentTarget = structuredClone(r.target), t.editor.toDesignCanvas(this.currentTarget), this.idPrefix = `${t.editor.doc.identity.prefix}design-view-${++g}-`, this.presentation = t.toPresentation(), this.textMode = r.textMode === "svg" || r.textMode === "html" ? r.textMode : f(e.ownerDocument) ? "html" : "svg", this.element = e.ownerDocument.createElement("div"), this.element.dataset.pptDesignEditor = this.currentTarget.kind, this.element.style.position = "relative", this.element.style.width = "100%", this.element.style.height = "100%", e.append(this.element), this.unsubscribe = t.editor.subscribe((d) => this.update(d)), this.render();
62
+ }
63
+ get target() {
64
+ return structuredClone(this.currentTarget);
65
+ }
66
+ get destroyed() {
67
+ return this.isDestroyed;
68
+ }
69
+ setTarget(e) {
70
+ this.assertAlive(), this.session.editor.toDesignCanvas(e), this.currentTarget = structuredClone(e), this.element.dataset.pptDesignEditor = e.kind, this.render();
71
+ }
72
+ exec(...e) {
73
+ return this.assertAlive(), this.session.editor.execDesign(this.currentTarget, ...e);
74
+ }
75
+ render() {
76
+ this.assertAlive(), this.element.innerHTML = u(
77
+ this.presentation,
78
+ this.session.editor.toDesignCanvas(this.currentTarget),
79
+ {
80
+ textMode: this.textMode,
81
+ idPrefix: `${this.idPrefix}${this.currentTarget.id}-`,
82
+ includeEditMarkers: !0
83
+ }
84
+ ), p(this.element, this.session.editor.doc, this.currentTarget);
85
+ }
86
+ destroy() {
87
+ this.isDestroyed || (this.isDestroyed = !0, this.unsubscribe(), this.element.remove());
88
+ }
89
+ assertAlive() {
90
+ if (this.isDestroyed || this.session.disposed) throw new Error("设计视图已经销毁");
91
+ }
92
+ update(e) {
93
+ if (e.source === "selection") return;
94
+ const t = this.session.editor.doc;
95
+ this.presentation.width = t.meta.width, this.presentation.height = t.meta.height, (e.createdSlides.size || e.removedSlides.size || e.movedSlides.size) && (this.presentation.slides = t.slideOrder.map((r) => this.session.editor.toSlide(r))), this.render();
96
+ }
97
+ }
98
+ function D(s, e, t) {
99
+ return new w(s, e, t);
100
+ }
101
+ export {
102
+ D as createDesignEditor,
103
+ x as listLayouts,
104
+ T as listMasters,
105
+ M as queryLayout,
106
+ b as queryMaster,
107
+ $ as toDesignCanvas
108
+ };
@@ -1,9 +1,10 @@
1
- import type { EditDoc, ElementId, SlideId } from '@web-ppt/edit-core';
1
+ import type { DesignTarget, EditDoc, ElementId, SlideId } from '@web-ppt/edit-core';
2
2
  export declare function elementIds(doc: EditDoc, roots: readonly ElementId[]): ElementId[];
3
3
  export declare function bindElementIdentities(root: ParentNode, doc: EditDoc, roots: readonly ElementId[]): void;
4
4
  /** 结构壳尚未挂孩子时只绑定容器本身,孩子沿用原分区身份。 */
5
5
  export declare function bindSingleElementIdentity(root: ParentNode, doc: EditDoc, id: ElementId): void;
6
6
  export declare function bindSlideIdentities(root: ParentNode, doc: EditDoc, slideId: SlideId): void;
7
+ export declare function bindDesignIdentities(root: ParentNode, doc: EditDoc, target: DesignTarget): void;
7
8
  export declare function findElementPartition(root: ParentNode, id: ElementId): SVGElement | null;
8
9
  /**
9
10
  * visibility 会被后代的 visible 覆盖;显示元素时必须删除声明,让祖先隐藏继续继承。
@@ -0,0 +1,8 @@
1
+ import type { TextBody } from '@web-ppt/core';
2
+ import type { NativeTextFormat } from './native';
3
+ export declare function textRange(root: HTMLElement, text: TextBody, from: number, to: number): Range | null;
4
+ export declare function textBounds(root: HTMLElement, text: TextBody, from: number, to: number): DOMRect;
5
+ export declare function compositionDecoration(root: HTMLElement): {
6
+ update(text: TextBody, formats: readonly NativeTextFormat[]): void;
7
+ dispose(): void;
8
+ };
@@ -0,0 +1,8 @@
1
+ import type { EditorSession } from '../session';
2
+ import type { SlideEditor } from '../slide-editor-types';
3
+ export interface EditContextEnhancement {
4
+ readonly supported: boolean;
5
+ dispose(): void;
6
+ }
7
+ /** 仅替换浏览器输入适配;格式、历史、IME 合并与协同重基仍经过既有文字控制器。 */
8
+ export declare function enableEditContext(session: EditorSession, view: SlideEditor): EditContextEnhancement;
@@ -0,0 +1,33 @@
1
+ export interface NativeEditContext extends EventTarget {
2
+ readonly text: string;
3
+ readonly selectionStart: number;
4
+ readonly selectionEnd: number;
5
+ updateText(start: number, end: number, text: string): void;
6
+ updateSelection(start: number, end: number): void;
7
+ updateControlBounds(bounds: DOMRect): void;
8
+ updateSelectionBounds(bounds: DOMRect): void;
9
+ updateCharacterBounds(start: number, bounds: DOMRect[]): void;
10
+ }
11
+ export interface NativeTextUpdate extends Event {
12
+ readonly updateRangeStart: number;
13
+ readonly updateRangeEnd: number;
14
+ readonly text: string;
15
+ readonly selectionStart: number;
16
+ readonly selectionEnd: number;
17
+ }
18
+ export interface NativeTextFormat {
19
+ readonly rangeStart: number;
20
+ readonly rangeEnd: number;
21
+ readonly underlineStyle: string;
22
+ readonly underlineThickness: string;
23
+ }
24
+ export type EditContextWindow = Window & typeof globalThis & {
25
+ EditContext?: new (options: {
26
+ text: string;
27
+ selectionStart: number;
28
+ selectionEnd: number;
29
+ }) => NativeEditContext;
30
+ };
31
+ export type EditingHost = HTMLDivElement & {
32
+ editContext: NativeEditContext | null;
33
+ };