@web-ppt/editor 0.5.0-beta.1

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 (83) hide show
  1. package/CHANGELOG.md +274 -0
  2. package/LICENSE +21 -0
  3. package/README.md +473 -0
  4. package/dist/adapter-format-painter.d.ts +15 -0
  5. package/dist/adapter-link.d.ts +3 -0
  6. package/dist/adapter-options.d.ts +6 -0
  7. package/dist/adapter-recovery.d.ts +14 -0
  8. package/dist/adapter-selection-pane.d.ts +22 -0
  9. package/dist/adapter-text-search.d.ts +28 -0
  10. package/dist/animation-preview.d.ts +26 -0
  11. package/dist/dom-identity.d.ts +17 -0
  12. package/dist/dom-patch.d.ts +9 -0
  13. package/dist/editor-keyboard.d.ts +13 -0
  14. package/dist/editor.js +6332 -0
  15. package/dist/element-clipboard.d.ts +23 -0
  16. package/dist/format-painter-types.d.ts +32 -0
  17. package/dist/format-painter-view.d.ts +17 -0
  18. package/dist/format-painter.d.ts +21 -0
  19. package/dist/framework-adapter-binding.d.ts +4 -0
  20. package/dist/framework-adapter-state.d.ts +9 -0
  21. package/dist/framework-adapter-types.d.ts +114 -0
  22. package/dist/framework-adapter.d.ts +2 -0
  23. package/dist/image-crop-gesture.d.ts +40 -0
  24. package/dist/image-insertion.d.ts +46 -0
  25. package/dist/index.d.ts +28 -0
  26. package/dist/indexeddb-recovery-store.d.ts +30 -0
  27. package/dist/keyboard-context.d.ts +8 -0
  28. package/dist/keyboard-delete.d.ts +7 -0
  29. package/dist/keyboard-history.d.ts +7 -0
  30. package/dist/keyboard-layer.d.ts +7 -0
  31. package/dist/keyboard-nudge.d.ts +10 -0
  32. package/dist/keyboard-owner.d.ts +5 -0
  33. package/dist/marquee-gesture.d.ts +31 -0
  34. package/dist/move-gesture.d.ts +34 -0
  35. package/dist/placeholder-overlay.d.ts +3 -0
  36. package/dist/pointer-gesture.d.ts +37 -0
  37. package/dist/recovery-session.d.ts +24 -0
  38. package/dist/recovery-store.d.ts +64 -0
  39. package/dist/resize-geometry.d.ts +19 -0
  40. package/dist/resize-gesture.d.ts +30 -0
  41. package/dist/rotation-geometry.d.ts +9 -0
  42. package/dist/rotation-gesture.d.ts +33 -0
  43. package/dist/selection-body-properties.d.ts +3 -0
  44. package/dist/selection-combine.d.ts +10 -0
  45. package/dist/selection-handles.d.ts +3 -0
  46. package/dist/selection-hit.d.ts +8 -0
  47. package/dist/selection-overlay.d.ts +13 -0
  48. package/dist/selection-pane-types.d.ts +18 -0
  49. package/dist/selection-pane.d.ts +3 -0
  50. package/dist/session-state.d.ts +20 -0
  51. package/dist/session.d.ts +24 -0
  52. package/dist/slide-dom-renderer.d.ts +22 -0
  53. package/dist/slide-dom-update.d.ts +13 -0
  54. package/dist/slide-editor-commands.d.ts +76 -0
  55. package/dist/slide-editor-dom.d.ts +2 -0
  56. package/dist/slide-editor-events.d.ts +20 -0
  57. package/dist/slide-editor-keyboard-events.d.ts +39 -0
  58. package/dist/slide-editor-types.d.ts +90 -0
  59. package/dist/slide-editor.d.ts +3 -0
  60. package/dist/slide-link-controller.d.ts +26 -0
  61. package/dist/slide-pointer-controller.d.ts +43 -0
  62. package/dist/snap-guides.d.ts +3 -0
  63. package/dist/snap.d.ts +60 -0
  64. package/dist/source-fingerprint.d.ts +9 -0
  65. package/dist/table-insertion.d.ts +7 -0
  66. package/dist/text-autofit.d.ts +18 -0
  67. package/dist/text-clipboard-controller.d.ts +32 -0
  68. package/dist/text-clipboard.d.ts +7 -0
  69. package/dist/text-dom.d.ts +30 -0
  70. package/dist/text-editor-context.d.ts +13 -0
  71. package/dist/text-editor-target.d.ts +10 -0
  72. package/dist/text-editor-types.d.ts +30 -0
  73. package/dist/text-editor-view.d.ts +4 -0
  74. package/dist/text-editor.d.ts +51 -0
  75. package/dist/text-input-plan.d.ts +20 -0
  76. package/dist/text-search-highlight.d.ts +18 -0
  77. package/dist/text-search-index.d.ts +11 -0
  78. package/dist/text-search-types.d.ts +41 -0
  79. package/dist/text-search-view.d.ts +33 -0
  80. package/dist/text-search.d.ts +46 -0
  81. package/dist/transform-frame.d.ts +14 -0
  82. package/dist/transition-preview.d.ts +24 -0
  83. package/package.json +54 -0
@@ -0,0 +1,30 @@
1
+ import type { Editor, ElementId } from '@web-ppt/edit-core';
2
+ import type { ResizeHandle } from './resize-geometry';
3
+ interface ResizeGestureOptions {
4
+ root: HTMLElement;
5
+ stage: HTMLElement;
6
+ staticLayer: HTMLElement;
7
+ interactionLayer: SVGSVGElement;
8
+ editor: Editor;
9
+ zoom: () => number;
10
+ }
11
+ export declare class ResizeGestureController {
12
+ private readonly options;
13
+ private readonly lifecycle;
14
+ constructor(options: ResizeGestureOptions);
15
+ get isActive(): boolean;
16
+ begin(event: PointerEvent, handle: ResizeHandle, ids: readonly ElementId[]): void;
17
+ move(event: PointerEvent): void;
18
+ finish(event: PointerEvent): void;
19
+ modifier(event: KeyboardEvent): boolean;
20
+ cancel(): void;
21
+ cancelPointer(event: PointerEvent): void;
22
+ private currentSlide;
23
+ private proposal;
24
+ private startPreview;
25
+ private applyFrame;
26
+ private commit;
27
+ private clearPreview;
28
+ private sameFrame;
29
+ }
30
+ export {};
@@ -0,0 +1,9 @@
1
+ import type { EditDoc, ElementId, SpacePoint } from '@web-ppt/edit-core';
2
+ import type { TransformFrame } from './transform-frame';
3
+ export declare const ROTATION_SNAP_DEGREES = 15;
4
+ export declare function pointerAngle(center: SpacePoint, pointer: SpacePoint): number;
5
+ export declare function shortestRotationDelta(degrees: number): number;
6
+ export declare function constrainedRotation(degrees: number, shiftKey: boolean): number;
7
+ export declare function rotatePointAround(point: SpacePoint, center: SpacePoint, degrees: number): SpacePoint;
8
+ /** 多选中心在幻灯片空间刚性旋转;方向轴反解回父空间,避免把组缩放误当成角度。 */
9
+ export declare function rotateElementAroundSlideCenter(doc: EditDoc, id: ElementId, source: TransformFrame, selectionCenter: SpacePoint, degrees: number): TransformFrame;
@@ -0,0 +1,33 @@
1
+ import type { Editor, ElementId } from '@web-ppt/edit-core';
2
+ interface RotationGestureOptions {
3
+ root: HTMLElement;
4
+ stage: HTMLElement;
5
+ staticLayer: HTMLElement;
6
+ interactionLayer: SVGSVGElement;
7
+ editor: Editor;
8
+ zoom: () => number;
9
+ }
10
+ export declare class RotationGestureController {
11
+ private readonly options;
12
+ private readonly lifecycle;
13
+ constructor(options: RotationGestureOptions);
14
+ get isActive(): boolean;
15
+ begin(event: PointerEvent, ids: readonly ElementId[]): void;
16
+ move(event: PointerEvent): void;
17
+ finish(event: PointerEvent): void;
18
+ modifier(event: KeyboardEvent): boolean;
19
+ cancel(): void;
20
+ cancelPointer(event: PointerEvent): void;
21
+ private currentSlide;
22
+ private anglePointer;
23
+ private observe;
24
+ private proposal;
25
+ private startPreview;
26
+ private applyFrame;
27
+ private commit;
28
+ private clearPreview;
29
+ private angleElement;
30
+ private showAngle;
31
+ private changed;
32
+ }
33
+ export {};
@@ -0,0 +1,3 @@
1
+ import type { Editor, SlideId, TextBodyProperties, TextBodyPropertyOverrides } from '@web-ppt/edit-core';
2
+ export declare function querySelectionBodyProps(editor: Editor, slideId: SlideId): TextBodyProperties | null;
3
+ export declare function setSelectionBodyProps(editor: Editor, slideId: SlideId, props: TextBodyPropertyOverrides): boolean;
@@ -0,0 +1,10 @@
1
+ import type { ElementId } from '@web-ppt/edit-core';
2
+ interface SelectionModifiers {
3
+ readonly shiftKey: boolean;
4
+ readonly ctrlKey: boolean;
5
+ readonly metaKey: boolean;
6
+ }
7
+ export declare function selectionModifierActive(modifiers: SelectionModifiers): boolean;
8
+ /** 结果始终服从当前作用域绘制顺序,点击先后不成为隐藏的主元素。 */
9
+ export declare function combineSelectionIds(scope: readonly ElementId[], prior: readonly ElementId[], affected: readonly ElementId[], toggle: boolean): ElementId[];
10
+ export {};
@@ -0,0 +1,3 @@
1
+ import type { ResizeHandle } from './resize-geometry';
2
+ export declare function resizeHandleAt(target: EventTarget | null, interactionLayer: SVGSVGElement): ResizeHandle | null;
3
+ export declare function isRotationHandleAt(target: EventTarget | null, interactionLayer: SVGSVGElement): boolean;
@@ -0,0 +1,8 @@
1
+ import type { EditDoc, ElementId, Selection, SlideId, TableCellAddress } from '@web-ppt/edit-core';
2
+ export declare function tableCellAddressFromPath(path: EventTarget[], root: Element): TableCellAddress | null;
3
+ export declare function isSelectable(doc: EditDoc, id: ElementId): boolean;
4
+ export declare function selectableElementIdsFromPath(doc: EditDoc, path: EventTarget[], root: Element): ElementId[];
5
+ export declare function alternateSelectableElementId(doc: EditDoc, elements: readonly Element[], root: Element, enteredGroup: ElementId | null, selection: Selection, preferUnselected: boolean): ElementId | undefined;
6
+ export declare function directSelectableChildIds(doc: EditDoc, slideId: SlideId, enteredGroup: ElementId | null): ElementId[];
7
+ export declare function enteredGroupOnSlide(doc: EditDoc, enteredGroup: ElementId | null, slideId: SlideId): ElementId | null;
8
+ export declare function outermostHitCandidate(doc: EditDoc, candidates: ElementId[], enteredGroup: ElementId | null): ElementId | undefined;
@@ -0,0 +1,13 @@
1
+ import type { EditDoc, ElementId, Selection, SlideId, SpacePoint } from '@web-ppt/edit-core';
2
+ interface SelectionFrame {
3
+ ids: ElementId[];
4
+ corners: [SpacePoint, SpacePoint, SpacePoint, SpacePoint];
5
+ handles: boolean;
6
+ }
7
+ /** 手势帧只改已有属性,避免每次缩放都重建交互 DOM。 */
8
+ export declare function updateSelectionOverlayFrame(layer: SVGSVGElement, corners: SelectionFrame['corners'], zoom: number, handleFlip?: {
9
+ horizontal: boolean;
10
+ vertical: boolean;
11
+ }): void;
12
+ export declare function renderSelectionOverlay(layer: SVGSVGElement, doc: EditDoc, selection: Selection, slideId: SlideId, zoom: number): void;
13
+ export {};
@@ -0,0 +1,18 @@
1
+ import type { ElementId, SlideId } from '@web-ppt/edit-core';
2
+ import type { EditorMode } from './slide-editor-types';
3
+ export interface SelectionPaneOptions {
4
+ readonly slideId?: SlideId;
5
+ readonly mode?: EditorMode;
6
+ readonly ariaLabel?: string;
7
+ readonly onError?: (error: unknown) => void;
8
+ }
9
+ export interface SelectionPane {
10
+ readonly element: HTMLDivElement;
11
+ readonly slideId: SlideId;
12
+ readonly mode: EditorMode;
13
+ readonly destroyed: boolean;
14
+ setSlide(slideId: SlideId): void;
15
+ setMode(mode: EditorMode): void;
16
+ focusElement(id: ElementId): boolean;
17
+ destroy(): void;
18
+ }
@@ -0,0 +1,3 @@
1
+ import type { EditorSession } from './session';
2
+ import type { SelectionPane, SelectionPaneOptions } from './selection-pane-types';
3
+ export declare function createSelectionPane(container: HTMLElement, session: EditorSession, options?: SelectionPaneOptions): SelectionPane;
@@ -0,0 +1,20 @@
1
+ import type { Presentation } from '@web-ppt/core';
2
+ import type { EditorSession } from './session';
3
+ import type { SlideEditor } from './slide-editor-types';
4
+ import type { SelectionPane } from './selection-pane-types';
5
+ interface SessionState {
6
+ presentation: Presentation;
7
+ views: Set<SlideEditor>;
8
+ panes: Set<SelectionPane>;
9
+ textOwner: TextEditingOwner | null;
10
+ }
11
+ interface TextEditingOwner {
12
+ releaseTextEditing(): void;
13
+ }
14
+ export declare function registerSession(session: EditorSession, presentation: Presentation): void;
15
+ export declare function sessionState(session: EditorSession): SessionState;
16
+ export declare function releaseSession(session: EditorSession): void;
17
+ /** contenteditable 是视图本地资源;同一会话只能有一个 DOM 所有者。 */
18
+ export declare function claimTextEditing(session: EditorSession, owner: TextEditingOwner): void;
19
+ export declare function releaseTextEditing(session: EditorSession, owner: TextEditingOwner): void;
20
+ export {};
@@ -0,0 +1,24 @@
1
+ import type { ParseOptions } from '@web-ppt/core';
2
+ import { Editor } from '@web-ppt/edit-core';
3
+ import type { CreateDocOptions, EditorOptions } from '@web-ppt/edit-core';
4
+ import type { SlideEditor, SlideEditorOptions } from './slide-editor-types';
5
+ import type { EditorRecovery, RecoveryOptions } from './recovery-store';
6
+ import type { SelectionPane, SelectionPaneOptions } from './selection-pane-types';
7
+ import type { FormatPainter } from './format-painter-types';
8
+ import type { TextSearch } from './text-search-types';
9
+ export interface OpenEditorOptions extends CreateDocOptions, EditorOptions {
10
+ password?: ParseOptions['password'];
11
+ recovery?: RecoveryOptions;
12
+ }
13
+ /** 一份源文件只建立一个所有者,DOM 视图与框架适配器共享同一 headless Editor。 */
14
+ export interface EditorSession {
15
+ readonly editor: Editor;
16
+ readonly recovery: EditorRecovery | null;
17
+ readonly formatPainter: FormatPainter;
18
+ readonly textSearch: TextSearch;
19
+ readonly disposed: boolean;
20
+ mount(container: HTMLElement, options?: SlideEditorOptions): SlideEditor;
21
+ mountSelectionPane(container: HTMLElement, options?: SelectionPaneOptions): SelectionPane;
22
+ dispose(): void;
23
+ }
24
+ export declare function openEditor(input: File | Blob | ArrayBuffer | Uint8Array, options?: OpenEditorOptions): Promise<EditorSession>;
@@ -0,0 +1,22 @@
1
+ import type { Presentation } from '@web-ppt/core';
2
+ import type { Editor, EditorChange, ElementId, Selection, SlideId } from '@web-ppt/edit-core';
3
+ interface SlideDomRendererOptions {
4
+ presentation: Presentation;
5
+ editor: Editor;
6
+ staticLayer: HTMLElement;
7
+ interactionLayer: SVGSVGElement;
8
+ slideId: () => SlideId;
9
+ zoom: () => number;
10
+ idPrefix: string;
11
+ textMode: 'html' | 'svg';
12
+ editable: () => boolean;
13
+ }
14
+ export declare class SlideDomRenderer {
15
+ private readonly options;
16
+ constructor(options: SlideDomRendererOptions);
17
+ render(selection: Selection): void;
18
+ update(change: EditorChange, deferElement: ElementId | null): void;
19
+ syncElement(id: ElementId): void;
20
+ renderSelection(selection: Selection): void;
21
+ }
22
+ export {};
@@ -0,0 +1,13 @@
1
+ import type { Editor, EditorChange, ElementId, SlideId } from '@web-ppt/edit-core';
2
+ interface SlideDomUpdateOptions {
3
+ staticLayer: HTMLElement;
4
+ editor: Editor;
5
+ slideId: SlideId;
6
+ change: EditorChange;
7
+ idPrefix: string;
8
+ textMode: 'html' | 'svg';
9
+ deferElement: ElementId | null;
10
+ }
11
+ /** 返回 false 表示局部分区身份不足,调用方应统一回退整页渲染。 */
12
+ export declare function patchSlideDom(options: SlideDomUpdateOptions): boolean;
13
+ export {};
@@ -0,0 +1,76 @@
1
+ import type { EditAnimationStep, ElementId, ImageCrop, LinkTarget, ParagraphPropertiesState, ParagraphPropertyOverrides, RunLinkState, RunPropertiesState, RunPropertyOverrides, SlideId, SlideLayoutState, SlideNotesState, TextBodyProperties, TextBodyPropertyOverrides, SlideAnimationState, SlideTransitionInput, SlideTransitionState } from '@web-ppt/edit-core';
2
+ import type { EditorSession } from './session';
3
+ import type { TextEditorController } from './text-editor';
4
+ import type { ImageInsertionController } from './image-insertion';
5
+ import type { ImageBackgroundOptions, ImageInsertOptions, ImageReplaceOptions } from './image-insertion';
6
+ import type { ImageCropGestureController } from './image-crop-gesture';
7
+ import type { SlideLinkController } from './slide-link-controller';
8
+ import type { EditorMode } from './slide-editor-types';
9
+ import type { TableInsertOptions } from './table-insertion';
10
+ import type { FormatPainterStartOptions } from './format-painter-types';
11
+ import type { FormatPainterViewBinding } from './format-painter-view';
12
+ import type { TextSearchOpenOptions } from './text-search-types';
13
+ import type { TextSearchViewBinding } from './text-search-view';
14
+ import type { TransitionPreviewController } from './transition-preview';
15
+ import type { AnimationPreviewController } from './animation-preview';
16
+ interface SlideEditorCommandsOptions {
17
+ readonly session: EditorSession;
18
+ readonly element: HTMLElement;
19
+ readonly textEditor: TextEditorController;
20
+ readonly imageInsertion: ImageInsertionController;
21
+ readonly imageCropGesture: ImageCropGestureController;
22
+ readonly links: SlideLinkController;
23
+ readonly formatPainter: FormatPainterViewBinding;
24
+ readonly textSearch: TextSearchViewBinding;
25
+ transitionPreview(): TransitionPreviewController;
26
+ animationPreview(): AnimationPreviewController;
27
+ mode(): EditorMode;
28
+ slideId(): SlideId;
29
+ destroyed(): boolean;
30
+ cancelGestures(): void;
31
+ }
32
+ /** 把公开工具栏动作收敛为薄能力层,视图本体只负责 DOM 与生命周期装配。 */
33
+ export declare class SlideEditorCommands {
34
+ private readonly options;
35
+ constructor(options: SlideEditorCommandsOptions);
36
+ startFormatPainter(options: FormatPainterStartOptions): boolean;
37
+ cancelFormatPainter(): void;
38
+ openTextSearch(options: TextSearchOpenOptions): void;
39
+ closeTextSearch(): void;
40
+ nextTextSearch(): import("@web-ppt/edit-core").TextSearchMatch | null;
41
+ previousTextSearch(): import("@web-ppt/edit-core").TextSearchMatch | null;
42
+ replaceCurrentText(): boolean;
43
+ replaceAllText(): number;
44
+ followLink(target?: LinkTarget): boolean;
45
+ releaseTextEditing(): void;
46
+ registerTextUi(element: HTMLElement): () => void;
47
+ queryRunProps(): RunPropertiesState | null;
48
+ queryRunLink(): RunLinkState | null;
49
+ setRunProps(props: RunPropertyOverrides): boolean;
50
+ queryParaProps(): ParagraphPropertiesState | null;
51
+ setParaProps(props: ParagraphPropertyOverrides): boolean;
52
+ queryBodyProps(): TextBodyProperties | null;
53
+ setBodyProps(props: TextBodyPropertyOverrides): boolean;
54
+ insertImage(file: Blob, options: ImageInsertOptions): Promise<ElementId>;
55
+ chooseImage(options: ImageInsertOptions): Promise<ElementId | null>;
56
+ replaceImage(file: Blob, options: ImageReplaceOptions): Promise<ElementId>;
57
+ chooseReplacementImage(options: ImageReplaceOptions): Promise<ElementId | null>;
58
+ setBackgroundImage(file: Blob, options: ImageBackgroundOptions): Promise<SlideId>;
59
+ chooseBackgroundImage(options: ImageBackgroundOptions): Promise<SlideId | null>;
60
+ setBackgroundCrop(crop: ImageCrop | null): boolean;
61
+ queryTransition(): SlideTransitionState;
62
+ setTransition(value: SlideTransitionInput | null): boolean;
63
+ previewTransition(value?: SlideTransitionInput): Promise<boolean>;
64
+ queryAnimations(): SlideAnimationState;
65
+ setAnimations(value: readonly EditAnimationStep[] | null): boolean;
66
+ previewAnimations(value?: readonly EditAnimationStep[]): Promise<boolean>;
67
+ queryLayout(): SlideLayoutState;
68
+ setLayout(layoutId: string): boolean;
69
+ queryNotes(): SlideNotesState;
70
+ setNotes(text: string): boolean;
71
+ insertTable(rows: number, cols: number, options: TableInsertOptions): ElementId;
72
+ startImageCrop(id?: ElementId): boolean;
73
+ endImageCrop(): void;
74
+ private selectedImageId;
75
+ }
76
+ export {};
@@ -0,0 +1,2 @@
1
+ export declare function nextViewIdPrefix(documentPrefix: string): string;
2
+ export declare function createEditorLayer(document: Document, name: string): HTMLDivElement;
@@ -0,0 +1,20 @@
1
+ interface SlideEditorEventHandlers {
2
+ pointerdown: (event: PointerEvent) => void;
3
+ pointermove: (event: PointerEvent) => void;
4
+ pointerup: (event: PointerEvent) => void;
5
+ pointercancel: (event: PointerEvent) => void;
6
+ dblclick: (event: MouseEvent) => void;
7
+ keydown: (event: KeyboardEvent) => void;
8
+ keyup: (event: KeyboardEvent) => void;
9
+ blur: (event: FocusEvent) => void;
10
+ copy: (event: ClipboardEvent) => void;
11
+ cut: (event: ClipboardEvent) => void;
12
+ paste: (event: ClipboardEvent) => void;
13
+ }
14
+ /** 事件表集中绑定与释放,构造失败和 destroy 共用同一份对称清理。 */
15
+ export declare function bindSlideEditorEditEvents(element: HTMLElement, handlers: SlideEditorEventHandlers): () => void;
16
+ export declare function bindSlideEditorLinkEvent(element: HTMLElement, handlers: {
17
+ click: (event: MouseEvent) => void;
18
+ keydown: (event: KeyboardEvent) => void;
19
+ }): () => void;
20
+ export {};
@@ -0,0 +1,39 @@
1
+ import type { EditorSession } from './session';
2
+ import type { EditorKeyboardController } from './editor-keyboard';
3
+ import type { ElementClipboardController } from './element-clipboard';
4
+ import type { MarqueeGestureController } from './marquee-gesture';
5
+ import type { MoveGestureController } from './move-gesture';
6
+ import type { ResizeGestureController } from './resize-gesture';
7
+ import type { RotationGestureController } from './rotation-gesture';
8
+ import type { ImageCropGestureController } from './image-crop-gesture';
9
+ import type { TextEditorController } from './text-editor';
10
+ import type { SlideLinkController } from './slide-link-controller';
11
+ import type { FormatPainterViewBinding } from './format-painter-view';
12
+ import type { EditorMode } from './slide-editor-types';
13
+ interface SlideEditorKeyboardEventOptions {
14
+ readonly session: EditorSession;
15
+ readonly keyboard: EditorKeyboardController;
16
+ readonly clipboard: ElementClipboardController;
17
+ readonly marquee: MarqueeGestureController;
18
+ readonly move: MoveGestureController;
19
+ readonly resize: ResizeGestureController;
20
+ readonly rotation: RotationGestureController;
21
+ readonly crop: ImageCropGestureController;
22
+ readonly textEditor: TextEditorController;
23
+ readonly links: SlideLinkController;
24
+ readonly formatPainter: FormatPainterViewBinding;
25
+ mode(): EditorMode;
26
+ cancelActiveGesture(): boolean;
27
+ }
28
+ /** 键盘/剪贴板事件共享焦点与 Escape 优先级,集中路由可避免视图类继续膨胀。 */
29
+ export declare class SlideEditorKeyboardEvents {
30
+ private readonly options;
31
+ constructor(options: SlideEditorKeyboardEventOptions);
32
+ readonly keydown: (event: KeyboardEvent) => void;
33
+ readonly keyup: (event: KeyboardEvent) => void;
34
+ readonly blur: () => void;
35
+ readonly copy: (event: ClipboardEvent) => void;
36
+ readonly cut: (event: ClipboardEvent) => void;
37
+ readonly paste: (event: ClipboardEvent) => void;
38
+ }
39
+ export {};
@@ -0,0 +1,90 @@
1
+ import type { EditAnimationStep, ElementId, ImageCrop, LinkTarget, ParagraphPropertiesState, ParagraphPropertyOverrides, RunLinkState, RunPropertiesState, RunPropertyOverrides, SlideId, SlideLayoutState, TextBodyProperties, TextBodyPropertyOverrides, SlideNotesState, SlideAnimationState, SlideTransitionInput, SlideTransitionState } from '@web-ppt/edit-core';
2
+ import type { ImageBackgroundOptions, ImageInsertOptions, ImageReplaceOptions } from './image-insertion';
3
+ import type { SnapMargins } from './snap';
4
+ import type { TableInsertOptions } from './table-insertion';
5
+ import type { FormatPainterStartOptions } from './format-painter-types';
6
+ import type { TextSearchOpenOptions } from './text-search-types';
7
+ export type EditorMode = 'view' | 'edit';
8
+ export type LinkFollowSource = 'view' | 'edit' | 'api';
9
+ export interface LinkFollowContext {
10
+ source: LinkFollowSource;
11
+ event?: MouseEvent | KeyboardEvent;
12
+ }
13
+ /** 返回 true 表示宿主已经完成路由,编辑器不再执行默认跳转。 */
14
+ export type LinkFollowHandler = (target: LinkTarget, context: LinkFollowContext) => boolean | void;
15
+ export interface SlideEditorOptions {
16
+ slideId?: SlideId;
17
+ mode?: EditorMode;
18
+ zoom?: number;
19
+ /** 默认 auto;受 WebKit foreignObject 缩放缺陷影响时自动切到原生 SVG 文本。 */
20
+ textMode?: 'auto' | 'html' | 'svg';
21
+ /** 默认开启;false 使本视图的移动手势保留原始指针位移。 */
22
+ snapping?: boolean;
23
+ /** 文档没有通用形状页边距;需要时由宿主在幻灯片 px 中显式给出。 */
24
+ snapMargins?: SnapMargins;
25
+ /** React/Vue 等宿主可接管路由;返回 true 阻止内置页跳转或安全新窗口。 */
26
+ onLinkFollow?: LinkFollowHandler;
27
+ /** 与自定义事件 webpptformaterror 同源,adapter 用它接入全局 onError。 */
28
+ onError?: (error: unknown) => void;
29
+ }
30
+ export interface SlideEditor {
31
+ readonly element: HTMLDivElement;
32
+ readonly mode: EditorMode;
33
+ readonly slideId: SlideId;
34
+ readonly zoom: number;
35
+ readonly snapping: boolean;
36
+ readonly destroyed: boolean;
37
+ setMode(mode: EditorMode): void;
38
+ setSlide(slideId: SlideId): void;
39
+ setZoom(zoom: number): void;
40
+ setSnapping(enabled: boolean): void;
41
+ /** 从当前单元素或文字选区启用会话级格式刷。 */
42
+ startFormatPainter(options?: FormatPainterStartOptions): boolean;
43
+ cancelFormatPainter(): void;
44
+ openTextSearch(options?: TextSearchOpenOptions): void;
45
+ closeTextSearch(): void;
46
+ nextTextSearch(): import('@web-ppt/edit-core').TextSearchMatch | null;
47
+ previousTextSearch(): import('@web-ppt/edit-core').TextSearchMatch | null;
48
+ replaceCurrentText(): boolean;
49
+ replaceAllText(): number;
50
+ /** 省略目标时跟随当前单一元素或文字选区;内部页始终使用稳定 SlideId。 */
51
+ followLink(target?: LinkTarget): boolean;
52
+ /** 注册外置工具栏,使其 pointer 交互不结束当前文字编辑。 */
53
+ registerTextUi(element: HTMLElement): () => void;
54
+ queryRunProps(): RunPropertiesState | null;
55
+ queryRunLink(): RunLinkState | null;
56
+ setRunProps(props: RunPropertyOverrides): boolean;
57
+ queryParaProps(): ParagraphPropertiesState | null;
58
+ setParaProps(props: ParagraphPropertyOverrides): boolean;
59
+ queryBodyProps(): TextBodyProperties | null;
60
+ setBodyProps(props: TextBodyPropertyOverrides): boolean;
61
+ insertImage(file: Blob, options?: ImageInsertOptions): Promise<ElementId>;
62
+ chooseImage(options?: ImageInsertOptions): Promise<ElementId | null>;
63
+ replaceImage(file: Blob, options?: ImageReplaceOptions): Promise<ElementId>;
64
+ chooseReplacementImage(options?: ImageReplaceOptions): Promise<ElementId | null>;
65
+ setBackgroundImage(file: Blob, options?: ImageBackgroundOptions): Promise<SlideId>;
66
+ chooseBackgroundImage(options?: ImageBackgroundOptions): Promise<SlideId | null>;
67
+ setBackgroundCrop(crop: ImageCrop | null): boolean;
68
+ queryTransition(): SlideTransitionState;
69
+ /** 查看模式同样可预览;省略值时播放当前页有效切换,不写模型。 */
70
+ previewTransition(value?: SlideTransitionInput): Promise<boolean>;
71
+ /** null 恢复来源;查看模式不改模型并返回 false。 */
72
+ setTransition(value: SlideTransitionInput | null): boolean;
73
+ queryAnimations(): SlideAnimationState;
74
+ /** 查看和编辑模式均可试听;传值时先校验草稿但不写模型。 */
75
+ previewAnimations(value?: readonly EditAnimationStep[]): Promise<boolean>;
76
+ /** null 恢复来源,空数组删除时间线;查看模式不改模型。 */
77
+ setAnimations(value: readonly EditAnimationStep[] | null): boolean;
78
+ queryLayout(): SlideLayoutState;
79
+ /** 只接受当前文档的 layoutId;查看模式不改模型。 */
80
+ setLayout(layoutId: string): boolean;
81
+ /** 普通 textarea 可直接读取当前页纯文本备注。 */
82
+ queryNotes(): SlideNotesState;
83
+ /** 查看模式不改模型并返回 false;空字符串表示显式清空。 */
84
+ setNotes(text: string): boolean;
85
+ insertTable(rows: number, cols: number, options?: TableInsertOptions): ElementId;
86
+ /** 双击图片之外的框架无关入口;省略 id 时使用当前单选图片。 */
87
+ startImageCrop(id?: ElementId): boolean;
88
+ endImageCrop(): void;
89
+ destroy(): void;
90
+ }
@@ -0,0 +1,3 @@
1
+ import type { EditorSession } from './session';
2
+ import type { SlideEditor, SlideEditorOptions } from './slide-editor-types';
3
+ export declare function createSlideEditor(container: HTMLElement, session: EditorSession, options?: SlideEditorOptions): SlideEditor;
@@ -0,0 +1,26 @@
1
+ import type { Editor, LinkTarget, RunLinkState, SlideId } from '@web-ppt/edit-core';
2
+ import type { EditorMode, LinkFollowHandler, LinkFollowSource } from './slide-editor-types';
3
+ interface SlideLinkControllerOptions {
4
+ editor: Editor;
5
+ root: HTMLElement;
6
+ mode(): EditorMode;
7
+ slideId(): SlideId;
8
+ setSlide(slideId: SlideId): void;
9
+ queryRunLink(): RunLinkState | null;
10
+ onFollow?: LinkFollowHandler;
11
+ }
12
+ /** 单个 view 独占路由状态;共享的只有 headless 文档与选区。 */
13
+ export declare class SlideLinkController {
14
+ private readonly options;
15
+ constructor(options: SlideLinkControllerOptions);
16
+ readonly click: (event: MouseEvent) => void;
17
+ readonly keydown: (event: KeyboardEvent) => void;
18
+ follow(target?: LinkTarget): boolean;
19
+ followSelection(source: LinkFollowSource, event?: KeyboardEvent): boolean;
20
+ private eventLinkNode;
21
+ private selectedValue;
22
+ private valueFromNode;
23
+ private followValue;
24
+ private perform;
25
+ }
26
+ export {};
@@ -0,0 +1,43 @@
1
+ import type { Editor, ElementId, SlideId } from '@web-ppt/edit-core';
2
+ import { ImageInsertionController } from './image-insertion';
3
+ import type { MarqueeGestureController } from './marquee-gesture';
4
+ import type { MoveGestureController } from './move-gesture';
5
+ import type { ResizeGestureController } from './resize-gesture';
6
+ import type { RotationGestureController } from './rotation-gesture';
7
+ import type { TextEditorController } from './text-editor';
8
+ import type { ImageCropGestureController } from './image-crop-gesture';
9
+ import type { FormatPainterTarget } from './format-painter-types';
10
+ interface SlidePointerControllerOptions {
11
+ readonly editor: Editor;
12
+ readonly root: HTMLElement;
13
+ readonly staticLayer: HTMLElement;
14
+ readonly interactionLayer: SVGSVGElement;
15
+ readonly textEditor: TextEditorController;
16
+ readonly imageInsertion: ImageInsertionController;
17
+ readonly marquee: MarqueeGestureController;
18
+ readonly move: MoveGestureController;
19
+ readonly resize: ResizeGestureController;
20
+ readonly rotation: RotationGestureController;
21
+ readonly crop: ImageCropGestureController;
22
+ editable(): boolean;
23
+ slideId(): SlideId;
24
+ hitCandidates(path: EventTarget[]): ElementId[];
25
+ formatPainter: {
26
+ active(): boolean;
27
+ apply(target: FormatPainterTarget): boolean;
28
+ error(error: unknown): void;
29
+ };
30
+ }
31
+ /** 统一路由画布 pointer 命中;视图生命周期类只负责装配控制器。 */
32
+ export declare class SlidePointerController {
33
+ private readonly options;
34
+ constructor(options: SlidePointerControllerOptions);
35
+ readonly down: (event: PointerEvent) => void;
36
+ private applyFormat;
37
+ private pointedElement;
38
+ readonly move: (event: PointerEvent) => void;
39
+ readonly up: (event: PointerEvent) => void;
40
+ readonly cancel: (event: PointerEvent) => void;
41
+ readonly doubleClick: (event: MouseEvent) => void;
42
+ }
43
+ export {};
@@ -0,0 +1,3 @@
1
+ import type { SnapGuide } from './snap';
2
+ export declare function createSnapGuideLayer(document: Document): SVGGElement;
3
+ export declare function renderSnapGuides(layer: SVGGElement, guides: readonly SnapGuide[], zoom: number): void;
package/dist/snap.d.ts ADDED
@@ -0,0 +1,60 @@
1
+ import type { SpacePoint } from '@web-ppt/edit-core';
2
+ export interface SnapBounds {
3
+ left: number;
4
+ top: number;
5
+ right: number;
6
+ bottom: number;
7
+ }
8
+ export interface SnapTarget {
9
+ id: string;
10
+ bounds: SnapBounds;
11
+ }
12
+ export interface SnapMargins {
13
+ left: number;
14
+ right: number;
15
+ top: number;
16
+ bottom: number;
17
+ }
18
+ export interface AlignmentSnapGuide {
19
+ kind: 'alignment';
20
+ axis: 'x' | 'y';
21
+ position: number;
22
+ start: number;
23
+ end: number;
24
+ source: 'canvas-center' | 'canvas-edge' | 'page-margin' | 'element-edge' | 'element-center';
25
+ }
26
+ export interface SpacingSnapGuide {
27
+ kind: 'spacing';
28
+ axis: 'x' | 'y';
29
+ cross: number;
30
+ intervals: readonly [
31
+ {
32
+ start: number;
33
+ end: number;
34
+ },
35
+ {
36
+ start: number;
37
+ end: number;
38
+ }
39
+ ];
40
+ source: 'equal-spacing';
41
+ }
42
+ export type SnapGuide = AlignmentSnapGuide | SpacingSnapGuide;
43
+ export interface MoveSnapRequest {
44
+ bounds: SnapBounds;
45
+ delta: SpacePoint;
46
+ threshold: number;
47
+ siblings: readonly SnapTarget[];
48
+ slide: {
49
+ width: number;
50
+ height: number;
51
+ };
52
+ margins?: SnapMargins;
53
+ }
54
+ export interface MoveSnapResult {
55
+ delta: SpacePoint;
56
+ guides: SnapGuide[];
57
+ }
58
+ export declare function normalizeSnapMargins(margins: SnapMargins | undefined, slide: MoveSnapRequest['slide']): SnapMargins | undefined;
59
+ /** 阈值和候选都在幻灯片空间,DOM 缩放与父组矩阵不会改变求解结果。 */
60
+ export declare function snapMove(request: MoveSnapRequest): MoveSnapResult;
@@ -0,0 +1,9 @@
1
+ export type WebPptSource = File | Blob | ArrayBuffer | Uint8Array;
2
+ export interface WebPptSourceIdentity {
3
+ readonly fingerprint: `sha256:${string}`;
4
+ readonly byteLength: number;
5
+ }
6
+ export declare function sourceBytes(source: WebPptSource): Promise<Uint8Array<ArrayBuffer>>;
7
+ export declare function fingerprintSourceBytes(bytes: Uint8Array<ArrayBuffer>): Promise<WebPptSourceIdentity>;
8
+ /** 只按完整源字节识别恢复日志;文件名与时间戳都不是内容身份。 */
9
+ export declare function fingerprintSource(source: WebPptSource): Promise<WebPptSourceIdentity>;
@@ -0,0 +1,7 @@
1
+ import { type AddTableCommand, type Editor, type ElementId, type SlideId } from '@web-ppt/edit-core';
2
+ export interface TableInsertOptions {
3
+ readonly rect?: AddTableCommand['rect'];
4
+ /** 通常无需传;显式工具栏可指定要原子替换的空内容占位符。 */
5
+ readonly placeholderId?: ElementId;
6
+ }
7
+ export declare function insertTable(editor: Editor, slideId: SlideId, rows: number, cols: number, options?: TableInsertOptions): ElementId;
@@ -0,0 +1,18 @@
1
+ import type { ElementId, TableCellAddress } from '@web-ppt/edit-core';
2
+ import type { ActiveText } from './text-editor-types';
3
+ export interface TextAutofitTarget {
4
+ id: ElementId;
5
+ cell: TableCellAddress | null;
6
+ }
7
+ /** normAutofit 是视图派生状态;输入突发期不应污染可序列化文档与历史。 */
8
+ export declare class TextAutofitThrottle {
9
+ private readonly view;
10
+ private current;
11
+ private timer;
12
+ constructor(view: Window);
13
+ displayScale(active: ActiveText): number | undefined;
14
+ schedule(active: ActiveText, settle: (target: TextAutofitTarget) => void): void;
15
+ settle(active: ActiveText, expectedTarget: TextAutofitTarget): boolean;
16
+ reset(): void;
17
+ private cancelTimer;
18
+ }