pptx-angular-viewer 0.1.0 → 1.1.11

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.
@@ -1,7 +1,9 @@
1
1
  import * as pptx_viewer_core from 'pptx-viewer-core';
2
- import { PptxSlide, PptxTheme, PptxSlideMaster, PptxElement } from 'pptx-viewer-core';
2
+ import { PptxSlide, PptxElement, PptxTheme, PptxSlideMaster, PptxTableCell, Model3DPptxElement, ZoomPptxElement, TextSegment, XmlObject, ShapeStyle } from 'pptx-viewer-core';
3
3
  import * as _angular_core from '@angular/core';
4
- import { InjectionToken, Provider } from '@angular/core';
4
+ import { OnInit, OnDestroy, InjectionToken, Provider } from '@angular/core';
5
+ import { Options } from 'html2canvas-pro';
6
+ import { SafeHtml } from '@angular/platform-browser';
5
7
 
6
8
  /**
7
9
  * Theme configuration types for the PowerPoint viewer.
@@ -164,6 +166,108 @@ declare const DEFAULT_FILL_COLOR = "#3b82f6";
164
166
  /** Fallback shape stroke colour. */
165
167
  declare const DEFAULT_STROKE_COLOR = "#1f2937";
166
168
 
169
+ /**
170
+ * Pure geometry helpers for aligning and distributing selected editor elements.
171
+ *
172
+ * No Angular imports, no DOM, no side effects — only data in, data out.
173
+ * All inputs are treated as immutable.
174
+ */
175
+ /** Horizontal or vertical alignment mode. */
176
+ type AlignMode = 'left' | 'centerH' | 'right' | 'top' | 'middle' | 'bottom';
177
+ /** Axis along which to distribute spacing evenly. */
178
+ type DistributeMode = 'horizontal' | 'vertical';
179
+
180
+ declare class EditorStateService {
181
+ private readonly history;
182
+ /** The editable slide deck (a clone of the loaded presentation). */
183
+ readonly slides: _angular_core.WritableSignal<readonly PptxSlide[]>;
184
+ /** Ids of the currently selected elements (on the active slide). */
185
+ readonly selectedIds: _angular_core.WritableSignal<readonly string[]>;
186
+ /** Whether the deck has unsaved edits. */
187
+ readonly dirty: _angular_core.WritableSignal<boolean>;
188
+ readonly canUndo: _angular_core.WritableSignal<boolean>;
189
+ readonly canRedo: _angular_core.WritableSignal<boolean>;
190
+ readonly undoLabel: _angular_core.WritableSignal<string | undefined>;
191
+ readonly redoLabel: _angular_core.WritableSignal<string | undefined>;
192
+ readonly hasSelection: _angular_core.Signal<boolean>;
193
+ /** Replace the editable deck (clones the source); resets selection + history. */
194
+ setSlides(slides: readonly PptxSlide[]): void;
195
+ /** Current editable slides as a fresh (cloned) array. */
196
+ snapshot(): readonly PptxSlide[];
197
+ select(ids: readonly string[]): void;
198
+ toggleSelect(id: string, additive: boolean): void;
199
+ clearSelection(): void;
200
+ /** Select every element on a slide. */
201
+ selectAll(slideIndex: number): void;
202
+ isSelected(id: string): boolean;
203
+ moveSelectedBy(slideIndex: number, dx: number, dy: number): void;
204
+ nudgeSelected(slideIndex: number, dirX: number, dirY: number): void;
205
+ setPosition(slideIndex: number, id: string, x: number, y: number): void;
206
+ resize(slideIndex: number, id: string, width: number, height: number): void;
207
+ updateElement(slideIndex: number, id: string, patch: Partial<PptxElement>): void;
208
+ deleteSelected(slideIndex: number): void;
209
+ duplicateSelected(slideIndex: number): void;
210
+ bringSelectedToFront(slideIndex: number): void;
211
+ sendSelectedToBack(slideIndex: number): void;
212
+ bringSelectedForward(slideIndex: number): void;
213
+ sendSelectedBackward(slideIndex: number): void;
214
+ /** Record a single history snapshot at the start of a drag/resize gesture. */
215
+ beginTransform(label: string): void;
216
+ /**
217
+ * Apply a live transform during a gesture WITHOUT recording history (the
218
+ * gesture's snapshot was taken in {@link beginTransform}). Accepts any subset
219
+ * of x/y/width/height.
220
+ */
221
+ applyTransform(slideIndex: number, id: string, box: {
222
+ x?: number;
223
+ y?: number;
224
+ width?: number;
225
+ height?: number;
226
+ rotation?: number;
227
+ }): void;
228
+ undo(): void;
229
+ redo(): void;
230
+ /** Align the selected elements within their group bounds (one history entry). */
231
+ alignSelected(slideIndex: number, mode: AlignMode): void;
232
+ /** Evenly distribute the selected elements along an axis (one history entry). */
233
+ distributeSelected(slideIndex: number, mode: DistributeMode): void;
234
+ private applyPositionMap;
235
+ /** Group the selected elements into a single group element. */
236
+ groupSelected(slideIndex: number): void;
237
+ /** Ungroup the single selected group back into its children. */
238
+ ungroupSelected(slideIndex: number): void;
239
+ private clipboard;
240
+ /** Whether the clipboard holds copied elements (enables paste). */
241
+ readonly hasClipboard: _angular_core.WritableSignal<boolean>;
242
+ /** Copy the selected elements to the in-memory clipboard. */
243
+ copySelected(slideIndex: number): void;
244
+ /** Copy then delete the selected elements. */
245
+ cutSelected(slideIndex: number): void;
246
+ /** Paste clipboard elements onto a slide (offset + fresh ids) and select them. */
247
+ paste(slideIndex: number): void;
248
+ /** Append a new element to a slide (records history) and select it. */
249
+ addElement(slideIndex: number, element: PptxElement): void;
250
+ /** Patch slide-level properties (background, notes, …); one history entry. */
251
+ updateSlide(slideIndex: number, patch: Partial<PptxSlide>): void;
252
+ /** Insert a blank slide after `afterIndex` (records history). */
253
+ addSlide(afterIndex: number): void;
254
+ /** Delete a slide (keeps at least one; records history). */
255
+ deleteSlide(index: number): void;
256
+ /** Duplicate a slide, inserting the copy after it (records history). */
257
+ duplicateSlide(index: number): void;
258
+ /** Reorder a slide from `from` to `to` (records history). */
259
+ moveSlide(from: number, to: number): void;
260
+ private renumber;
261
+ private zOrder;
262
+ private commit;
263
+ private syncHistory;
264
+ private clone;
265
+ private newId;
266
+ private idCounter;
267
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<EditorStateService, never>;
268
+ static ɵprov: _angular_core.ɵɵInjectableDeclaration<EditorStateService>;
269
+ }
270
+
167
271
  /**
168
272
  * `LoadContentService` — Angular port of the React `useLoadContent` hook and
169
273
  * the Vue `useLoadContent` composable.
@@ -205,8 +309,13 @@ declare class LoadContentService {
205
309
  private renderToken;
206
310
  private activeBlobUrls;
207
311
  constructor();
208
- /** Serialise the current presentation back to `.pptx` bytes. */
312
+ /** Serialise the current (loaded) presentation back to `.pptx` bytes. */
209
313
  getContent(): Promise<Uint8Array>;
314
+ /**
315
+ * Serialise an explicit set of slides back to `.pptx` bytes (e.g. the
316
+ * editor's edited deck) using the loaded presentation's handler.
317
+ */
318
+ saveSlides(slides: readonly PptxSlide[]): Promise<Uint8Array>;
210
319
  /** Parse the supplied `.pptx` bytes into the reactive signals. */
211
320
  load(raw: Uint8Array | ArrayBuffer | null | undefined): Promise<void>;
212
321
  private disposeHandler;
@@ -250,34 +359,160 @@ declare class PowerPointViewerComponent {
250
359
  /** Fired when the in-memory content changes after edits. (Editing not yet ported.) */
251
360
  readonly contentChange: _angular_core.OutputEmitterRef<Uint8Array<ArrayBufferLike>>;
252
361
  protected readonly loader: LoadContentService;
362
+ private readonly exportSvc;
363
+ protected readonly editor: EditorStateService;
364
+ /** The `<main>` host; used to locate the live `.pptx-ng-canvas-stage`. */
365
+ private readonly mainEl;
366
+ /** True while a PNG/PDF export is in progress (disables the buttons). */
367
+ protected readonly exporting: _angular_core.WritableSignal<boolean>;
253
368
  protected readonly activeSlideIndex: _angular_core.WritableSignal<number>;
369
+ /** Slides to display: the editable deck when `canEdit`, else the loaded deck. */
370
+ protected readonly displaySlides: _angular_core.Signal<readonly pptx_viewer_core.PptxSlide[]>;
254
371
  protected readonly slideCount: _angular_core.Signal<number>;
255
372
  protected readonly activeSlide: _angular_core.Signal<pptx_viewer_core.PptxSlide>;
256
373
  protected readonly rootStyle: _angular_core.Signal<Record<string, string>>;
257
374
  protected readonly zoom: _angular_core.WritableSignal<number>;
258
375
  protected readonly zoomPercent: _angular_core.Signal<number>;
376
+ /** Fullscreen presentation-mode overlay visibility. */
377
+ protected readonly presenting: _angular_core.WritableSignal<boolean>;
378
+ /** Slide-sorter grid overlay visibility. */
379
+ protected readonly showSorter: _angular_core.WritableSignal<boolean>;
380
+ /** Speaker-notes strip visibility. */
381
+ protected readonly showNotes: _angular_core.WritableSignal<boolean>;
382
+ /** Find-in-slides bar visibility. */
383
+ protected readonly showFind: _angular_core.WritableSignal<boolean>;
384
+ /** Open editor context-menu position (client coords), or null. */
385
+ protected readonly contextMenuPos: _angular_core.WritableSignal<{
386
+ x: number;
387
+ y: number;
388
+ } | null>;
389
+ /** Id of the element being inline text-edited, or null. */
390
+ protected readonly editingId: _angular_core.WritableSignal<string | null>;
391
+ /** Notes for the active slide, if any. */
392
+ protected readonly activeNotes: _angular_core.Signal<string>;
393
+ /**
394
+ * Stable, always-truthy key for the slide-properties form. Changes only when
395
+ * the active slide changes, so the `@if` recreates (and reseeds) the
396
+ * uncontrolled notes/background inputs on navigation — but never mid-typing.
397
+ * String-prefixed so slide index 0 stays truthy under `@if (…; as key)`.
398
+ */
399
+ protected readonly slidePropsKey: _angular_core.Signal<string>;
400
+ /** The single selected element on the active slide (for the inspector). */
401
+ protected readonly selectedElement: _angular_core.Signal<PptxElement | null>;
259
402
  constructor();
260
- /** Serialise the current presentation to `.pptx` bytes (imperative handle). */
403
+ /**
404
+ * Serialise the current presentation to `.pptx` bytes (imperative handle).
405
+ * When editing, this serialises the editor's edited deck so changes persist.
406
+ */
261
407
  getContent(): Promise<Uint8Array>;
262
408
  goTo(index: number): void;
263
409
  goPrev(): void;
264
410
  goNext(): void;
411
+ /** Horizontal-swipe tracking start coordinates (touch begins on the canvas). */
412
+ private swipeStartX;
413
+ private swipeStartY;
414
+ /**
415
+ * Begin tracking a horizontal swipe for slide navigation.
416
+ *
417
+ * To disambiguate a navigation swipe from an element drag, swipe-nav is only
418
+ * armed when editing is off (`!canEdit()`). When `canEdit()` is true,
419
+ * pointer/touch gestures belong to element manipulation (move/resize/rotate),
420
+ * so we never hijack them. The large ‹ › buttons remain available in all
421
+ * modes for explicit navigation.
422
+ */
423
+ onMainTouchStart(event: TouchEvent): void;
424
+ /**
425
+ * Complete a swipe: a predominantly horizontal drag of at least the threshold
426
+ * navigates to the previous (swipe right) or next (swipe left) slide.
427
+ */
428
+ onMainTouchEnd(event: TouchEvent): void;
265
429
  zoomIn(): void;
266
430
  zoomOut(): void;
267
431
  zoomReset(): void;
432
+ /** Open the fullscreen presentation overlay from the current slide. */
433
+ present(): void;
434
+ /** Toggle the speaker-notes strip. */
435
+ toggleNotes(): void;
436
+ /**
437
+ * Handle an element press from the canvas. Additive (Shift/Ctrl) toggles
438
+ * membership; a plain press selects the element (keeping it selected if it
439
+ * already was, so a subsequent drag works).
440
+ */
441
+ onElementSelect(event: {
442
+ id: string;
443
+ additive: boolean;
444
+ }): void;
445
+ /** Right-click: select the element under the cursor and open the menu. */
446
+ onContextMenu(event: {
447
+ id: string | null;
448
+ x: number;
449
+ y: number;
450
+ }): void;
451
+ /** Update the active slide's background colour. */
452
+ onSlideBackground(event: Event): void;
453
+ /** Update the active slide's speaker notes. */
454
+ onSlideNotes(event: Event): void;
455
+ /** Commit an inline text edit: replace the element's text (one history entry). */
456
+ onTextCommit(event: {
457
+ id: string;
458
+ text: string;
459
+ }): void;
460
+ /**
461
+ * Editing keyboard shortcuts (only when `canEdit` and not typing in a
462
+ * field or presenting): Delete, Ctrl/Cmd+Z/Y undo/redo, Ctrl/Cmd+D
463
+ * duplicate, arrow-key nudge (Shift = ×10).
464
+ */
465
+ onKeyDown(event: KeyboardEvent): void;
466
+ /** Resolve the live slide-stage element within `<main>`. */
467
+ private stageElement;
468
+ /** Export the current slide as a PNG download. */
469
+ exportPng(): Promise<void>;
470
+ /**
471
+ * Export every slide to a multi-page PDF. Each slide is made the live stage,
472
+ * given a render tick to settle, captured to a canvas, then the original
473
+ * slide is restored.
474
+ */
475
+ exportPdf(): Promise<void>;
268
476
  static ɵfac: _angular_core.ɵɵFactoryDeclaration<PowerPointViewerComponent, never>;
269
477
  static ɵcmp: _angular_core.ɵɵComponentDeclaration<PowerPointViewerComponent, "pptx-viewer", never, { "content": { "alias": "content"; "required": false; "isSignal": true; }; "canEdit": { "alias": "canEdit"; "required": false; "isSignal": true; }; "class": { "alias": "class"; "required": false; "isSignal": true; }; "theme": { "alias": "theme"; "required": false; "isSignal": true; }; "collaboration": { "alias": "collaboration"; "required": false; "isSignal": true; }; }, { "activeSlideChange": "activeSlideChange"; "dirtyChange": "dirtyChange"; "contentChange": "contentChange"; }, never, never, true, never>;
270
478
  }
271
479
 
480
+ /**
481
+ * Pure geometry for interactive element drag/resize.
482
+ *
483
+ * Stage-space deltas in, a new bounding box out — no DOM, no framework, so the
484
+ * SlideCanvas pointer wiring stays thin and the maths is unit-testable.
485
+ */
486
+ /** The eight resize-handle positions around a selection box. */
487
+ type ResizeHandle = 'nw' | 'n' | 'ne' | 'e' | 'se' | 's' | 'sw' | 'w';
488
+ /** An axis-aligned box in stage (slide) coordinates. */
489
+ interface Box {
490
+ x: number;
491
+ y: number;
492
+ width: number;
493
+ height: number;
494
+ }
495
+ /** All handles, in render order (corners + edge midpoints). */
496
+ declare const RESIZE_HANDLES: readonly ResizeHandle[];
497
+ /** Translate a box by a stage-space delta. */
498
+ declare function applyMove(start: Box, dx: number, dy: number): Box;
499
+ /**
500
+ * Resize `start` by dragging `handle` with a stage-space delta, clamping to
501
+ * `min`. When clamping at the min size, the edge opposite the dragged handle
502
+ * stays fixed.
503
+ */
504
+ declare function applyResize(start: Box, handle: ResizeHandle, dx: number, dy: number, min?: number): Box;
505
+
272
506
  /**
273
507
  * Basic, framework-agnostic style computation for slide elements, returning
274
508
  * `[ngStyle]`-compatible maps.
275
509
  *
276
510
  * This mirrors the Vue package's `element-style.ts` (and a deliberately small
277
511
  * subset of the React `viewer/utils/*` style layer). It is enough to position
278
- * and paint text boxes, basic preset shapes, and images. Advanced visuals
279
- * (gradients, custom geometry clip-paths, shadows, 3D, image effects, text
280
- * warp) are tracked in PORTING.md.
512
+ * and paint text boxes, basic preset shapes, images, and image/gradient fills
513
+ * (the latter via the parser's prebuilt CSS gradient string). Advanced visuals
514
+ * (the structured gradient builder, pattern fills, custom geometry clip-paths,
515
+ * shadows, 3D, image effects, text warp) are tracked in PORTING.md.
281
516
  *
282
517
  * Long term the *logic* here is a shared-extraction candidate — only the
283
518
  * return type (CSS map shape) differs per framework — so a future refactor
@@ -303,30 +538,174 @@ declare function getTextBlockStyle(el: PptxElement): StyleMap;
303
538
  /** Resolve a displayable image source for picture/image/media poster frames. */
304
539
  declare function getImageSrc(el: PptxElement, mediaDataUrls: Map<string, string>): string | undefined;
305
540
 
541
+ /**
542
+ * A single guide line to draw.
543
+ *
544
+ * `axis: 'x'` → a vertical line at x = `pos`, spanning y ∈ [start, end].
545
+ * `axis: 'y'` → a horizontal line at y = `pos`, spanning x ∈ [start, end].
546
+ */
547
+ interface SnapGuide {
548
+ axis: 'x' | 'y';
549
+ /** The fixed coordinate of the line on its own axis. */
550
+ pos: number;
551
+ /** Start of the line along the perpendicular axis. */
552
+ start: number;
553
+ /** End of the line along the perpendicular axis. */
554
+ end: number;
555
+ }
556
+
306
557
  /**
307
558
  * SlideCanvasComponent — Angular port of the React `SlideCanvas.tsx` and Vue
308
- * `SlideCanvas.vue` (viewer-first subset).
559
+ * `SlideCanvas.vue`.
309
560
  *
310
561
  * Renders the active slide as a fixed-size stage scaled by `zoom`, with each
311
- * element absolutely positioned. The React version additionally layered in
312
- * rulers, grid, guides, marquee/selection, connector-creation, drawing, and
313
- * collaboration overlays all tracked in PORTING.md.
562
+ * element absolutely positioned. When `editable`, supports click-to-select
563
+ * (event delegation), selection outlines, and pointer drag-to-move / resize
564
+ * handles. Rulers, grid, guides, marquee, and collaboration overlays are
565
+ * tracked in PORTING.md.
314
566
  */
315
567
  declare class SlideCanvasComponent {
316
568
  readonly slide: _angular_core.InputSignal<PptxSlide | undefined>;
317
569
  readonly canvasSize: _angular_core.InputSignal<CanvasSize>;
318
570
  readonly mediaDataUrls: _angular_core.InputSignal<Map<string, string>>;
319
571
  readonly zoom: _angular_core.InputSignal<number>;
320
- readonly elements: _angular_core.Signal<pptx_viewer_core.PptxElement[]>;
572
+ /** When true, elements are selectable and drag/resize handles are shown. */
573
+ readonly editable: _angular_core.InputSignal<boolean>;
574
+ /** Ids of currently-selected elements (drawn with a selection outline). */
575
+ readonly selectedIds: _angular_core.InputSignal<readonly string[]>;
576
+ /** Id of the element currently being text-edited inline (or null). */
577
+ readonly editingId: _angular_core.InputSignal<string | null>;
578
+ /** Emitted when an element is pointer-pressed (with the additive modifier). */
579
+ readonly elementSelect: _angular_core.OutputEmitterRef<{
580
+ id: string;
581
+ additive: boolean;
582
+ }>;
583
+ /** Emitted when empty stage space is pressed (deselect). */
584
+ readonly backgroundClick: _angular_core.OutputEmitterRef<void>;
585
+ /** Emitted once when a drag/resize gesture actually starts moving. */
586
+ readonly transformStart: _angular_core.OutputEmitterRef<{
587
+ id: string;
588
+ label: string;
589
+ }>;
590
+ /** Emitted on each pointer move during a gesture with the new box. */
591
+ readonly transformUpdate: _angular_core.OutputEmitterRef<{
592
+ id: string;
593
+ box: Box;
594
+ }>;
595
+ /** Emitted on right-click with the element under the cursor (or null). */
596
+ readonly contextMenu: _angular_core.OutputEmitterRef<{
597
+ id: string | null;
598
+ x: number;
599
+ y: number;
600
+ }>;
601
+ /** Emitted on double-click of a text-bearing element to begin inline edit. */
602
+ readonly textEditStart: _angular_core.OutputEmitterRef<{
603
+ id: string;
604
+ }>;
605
+ /** Emitted with the new text when an inline edit commits. */
606
+ readonly textCommit: _angular_core.OutputEmitterRef<{
607
+ id: string;
608
+ text: string;
609
+ }>;
610
+ /** Emitted when an inline edit is cancelled (Escape). */
611
+ readonly textCancel: _angular_core.OutputEmitterRef<void>;
612
+ /** Emitted during a rotate gesture with the new rotation (degrees). */
613
+ readonly rotateUpdate: _angular_core.OutputEmitterRef<{
614
+ id: string;
615
+ rotation: number;
616
+ }>;
617
+ /** Emitted on marquee release with the ids of enclosed/overlapping elements. */
618
+ readonly marqueeSelect: _angular_core.OutputEmitterRef<string[]>;
619
+ private drag;
620
+ private editCancelled;
621
+ private marquee;
622
+ /** Live marquee rectangle (stage coords) while rubber-band selecting. */
623
+ readonly marqueeRect: _angular_core.WritableSignal<{
624
+ x: number;
625
+ y: number;
626
+ width: number;
627
+ height: number;
628
+ } | null>;
629
+ /** Live alignment-snap guide lines (stage coords) during a move. */
630
+ readonly snapGuides: _angular_core.WritableSignal<readonly SnapGuide[]>;
631
+ private readonly textEditor;
632
+ private readonly stageRef;
633
+ /** The editing id we've already initialised the textarea for, to avoid re-seeding its value mid-edit. */
634
+ private seededEditId;
635
+ /** Last-tap timestamp + element id, for synthetic double-tap detection on touch. */
636
+ private lastTap;
637
+ constructor();
638
+ readonly elements: _angular_core.Signal<PptxElement[]>;
639
+ /** Bounding boxes (stage coords) for the selected elements. */
640
+ readonly selectionBoxes: _angular_core.Signal<{
641
+ id: string;
642
+ x: number;
643
+ y: number;
644
+ width: number;
645
+ height: number;
646
+ }[]>;
647
+ /** The single selected element's box, or null when 0 or >1 are selected. */
648
+ readonly singleSelected: _angular_core.Signal<(Box & {
649
+ id: string;
650
+ }) | null>;
651
+ /** Resize-handle render boxes (stage coords) for the single selection. */
652
+ readonly handleBoxes: _angular_core.Signal<{
653
+ handle: ResizeHandle;
654
+ left: number;
655
+ top: number;
656
+ size: number;
657
+ cursor: string;
658
+ }[]>;
659
+ /** Rotation-handle box (stage coords) above the single selection, or null. */
660
+ readonly rotateHandle: _angular_core.Signal<{
661
+ left: number;
662
+ top: number;
663
+ size: number;
664
+ } | null>;
665
+ onStagePointerDown(event: PointerEvent): void;
666
+ /** Box + current plain text for the element under inline edit, or null. */
667
+ readonly editingBox: _angular_core.Signal<{
668
+ id: string;
669
+ x: number;
670
+ y: number;
671
+ width: number;
672
+ height: number;
673
+ text: string;
674
+ } | null>;
675
+ onDblClick(event: MouseEvent): void;
676
+ onEditorKeydown(event: KeyboardEvent): void;
677
+ commitText(event: Event, id: string): void;
678
+ onContextMenu(event: MouseEvent): void;
679
+ onHandlePointerDown(event: PointerEvent, handle: ResizeHandle): void;
680
+ onRotatePointerDown(event: PointerEvent): void;
681
+ onPointerMove(event: PointerEvent): void;
682
+ onPointerUp(): void;
321
683
  readonly wrapperStyle: _angular_core.Signal<StyleMap>;
322
684
  readonly stageStyle: _angular_core.Signal<StyleMap>;
323
685
  static ɵfac: _angular_core.ɵɵFactoryDeclaration<SlideCanvasComponent, never>;
324
- static ɵcmp: _angular_core.ɵɵComponentDeclaration<SlideCanvasComponent, "pptx-slide-canvas", never, { "slide": { "alias": "slide"; "required": false; "isSignal": true; }; "canvasSize": { "alias": "canvasSize"; "required": true; "isSignal": true; }; "mediaDataUrls": { "alias": "mediaDataUrls"; "required": false; "isSignal": true; }; "zoom": { "alias": "zoom"; "required": false; "isSignal": true; }; }, {}, never, never, true, never>;
686
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<SlideCanvasComponent, "pptx-slide-canvas", never, { "slide": { "alias": "slide"; "required": false; "isSignal": true; }; "canvasSize": { "alias": "canvasSize"; "required": true; "isSignal": true; }; "mediaDataUrls": { "alias": "mediaDataUrls"; "required": false; "isSignal": true; }; "zoom": { "alias": "zoom"; "required": false; "isSignal": true; }; "editable": { "alias": "editable"; "required": false; "isSignal": true; }; "selectedIds": { "alias": "selectedIds"; "required": false; "isSignal": true; }; "editingId": { "alias": "editingId"; "required": false; "isSignal": true; }; }, { "elementSelect": "elementSelect"; "backgroundClick": "backgroundClick"; "transformStart": "transformStart"; "transformUpdate": "transformUpdate"; "contextMenu": "contextMenu"; "textEditStart": "textEditStart"; "textCommit": "textCommit"; "textCancel": "textCancel"; "rotateUpdate": "rotateUpdate"; "marqueeSelect": "marqueeSelect"; }, never, never, true, never>;
325
687
  }
326
688
 
327
689
  interface TextRun {
328
690
  text: string;
329
691
  style: StyleMap;
692
+ /** Safe `href` when this run carries a renderable hyperlink. */
693
+ href?: string;
694
+ /** Hyperlink tooltip / title text. */
695
+ tooltip?: string;
696
+ /** Parsed OMML for an inline equation run (rendered as MathML). */
697
+ equationXml?: Record<string, unknown>;
698
+ /** Optional equation number for numbered equations. */
699
+ equationNumber?: string;
700
+ }
701
+ interface Paragraph {
702
+ runs: TextRun[];
703
+ /** Bullet / number marker text, when this paragraph is a list item. */
704
+ bulletMarker?: string;
705
+ /** `[ngStyle]` map for the bullet marker (colour / font). */
706
+ bulletStyle: StyleMap;
707
+ /** Left indent in px derived from the paragraph outline level. */
708
+ indentPx: number;
330
709
  }
331
710
  /**
332
711
  * ElementRendererComponent — Angular port of the React `ElementRenderer.tsx`
@@ -334,14 +713,21 @@ interface TextRun {
334
713
  *
335
714
  * Renders a single slide element by its `type` discriminant (viewer-first
336
715
  * subset):
337
- * - `text` / `shape` → positioned box with fill/stroke + rich text
716
+ * - `text` / `shape` → positioned box with fill/stroke + rich text + effects
717
+ * - `connector` → SVG straight/bent/curved connector
718
+ * - `chart` → inline-SVG chart (bar/line/area/pie/scatter)
719
+ * - `table` → HTML `<table>`
720
+ * - `smartArt` → SVG drawing-shapes / node-text fallback
721
+ * - `ink` → SVG ink strokes
722
+ * - `ole` → embedded-object preview / icon
723
+ * - `model3d` → poster / placeholder (no three.js)
724
+ * - `zoom` → slide/section zoom thumbnail
338
725
  * - `picture` / `image` → `<img>`
339
726
  * - `media` → poster frame (`<img>`) — playback TODO
340
727
  * - `group` → recursive children (self-referencing selector)
341
728
  * - everything else → labelled placeholder (TODO, see PORTING.md)
342
729
  *
343
- * Interaction (selection, resize, inline editing), connectors, charts, tables,
344
- * SmartArt, ink, OLE, and 3D are not yet ported.
730
+ * Interaction (selection, resize, inline editing) is not yet ported.
345
731
  */
346
732
  declare class ElementRendererComponent {
347
733
  readonly element: _angular_core.InputSignal<PptxElement>;
@@ -354,7 +740,7 @@ declare class ElementRendererComponent {
354
740
  readonly children: _angular_core.Signal<PptxElement[]>;
355
741
  readonly isShapeLike: _angular_core.Signal<boolean>;
356
742
  readonly isImageLike: _angular_core.Signal<boolean>;
357
- readonly paragraphs: _angular_core.Signal<TextRun[][]>;
743
+ readonly paragraphs: _angular_core.Signal<Paragraph[]>;
358
744
  readonly hasText: _angular_core.Signal<boolean>;
359
745
  readonly placeholderLabel: _angular_core.Signal<string>;
360
746
  private segmentStyle;
@@ -362,6 +748,1645 @@ declare class ElementRendererComponent {
362
748
  static ɵcmp: _angular_core.ɵɵComponentDeclaration<ElementRendererComponent, "pptx-element-renderer", never, { "element": { "alias": "element"; "required": true; "isSignal": true; }; "mediaDataUrls": { "alias": "mediaDataUrls"; "required": false; "isSignal": true; }; "zIndex": { "alias": "zIndex"; "required": false; "isSignal": true; }; }, {}, never, never, true, never>;
363
749
  }
364
750
 
751
+ /**
752
+ * Pure, framework-agnostic helpers for rendering connector elements.
753
+ *
754
+ * These are extracted from the component so they can be unit-tested without
755
+ * the Angular compiler or TestBed (the vitest setup for this package is
756
+ * plain happy-dom, no Analog plugin yet — see PORTING.md).
757
+ *
758
+ * Mirror of the Vue `ConnectorRenderer.vue` helpers and the React
759
+ * `ConnectorElementRenderer` path logic (basic straight-line subset).
760
+ */
761
+
762
+ /** Shape description for a SVG `<marker>` element (viewBox 0 0 10 10). */
763
+ interface MarkerShape {
764
+ shape: 'path' | 'circle';
765
+ d?: string;
766
+ }
767
+ /** All derived connector rendering values, computed from a `PptxElement`. */
768
+ interface ConnectorGeometry {
769
+ strokeWidth: number;
770
+ strokeColor: string;
771
+ strokeOpacity: number;
772
+ dashArray: string | undefined;
773
+ /** SVG width (clamped to at least 1). */
774
+ svgW: number;
775
+ /** SVG height (clamped to at least 1). */
776
+ svgH: number;
777
+ x1: number;
778
+ y1: number;
779
+ x2: number;
780
+ y2: number;
781
+ /**
782
+ * SVG `path` data for bent / curved connectors. `undefined` for straight
783
+ * connectors, in which case the component renders a `<line>` from
784
+ * `(x1,y1)` to `(x2,y2)` instead.
785
+ */
786
+ pathD: string | undefined;
787
+ startMarkerId: string;
788
+ endMarkerId: string;
789
+ startMarker: MarkerShape | null;
790
+ endMarker: MarkerShape | null;
791
+ startMarkerRef: string | null;
792
+ endMarkerRef: string | null;
793
+ /** Inline `style` string for the wrapper `<div>`. */
794
+ wrapperStyle: string;
795
+ }
796
+
797
+ /**
798
+ * ConnectorRendererComponent — Angular port of the Vue `ConnectorRenderer.vue`
799
+ * (and the React `ConnectorElementRenderer`, basic subset).
800
+ *
801
+ * Renders straight connectors/lines as an inline SVG spanning the element's
802
+ * bounding box, with stroke colour/width/dash and start/end arrowheads. Flip
803
+ * is baked into the endpoints (not a CSS transform) so arrowheads point the
804
+ * right way.
805
+ *
806
+ * All path/style math lives in `connector-path.ts` (pure TS, no Angular
807
+ * dependency) so it can be unit-tested without TestBed.
808
+ *
809
+ * Not yet ported (TODO, see PORTING.md): bent/curved connector routing
810
+ * (`getConnectorPathGeometry`), compound lines, connector text overlay, line
811
+ * shadows/glow. Bent/curved connectors currently fall back to a straight line.
812
+ */
813
+ declare class ConnectorRendererComponent {
814
+ readonly element: _angular_core.InputSignal<PptxElement>;
815
+ readonly zIndex: _angular_core.InputSignal<number>;
816
+ /** All derived geometry, recomputed on every input change. */
817
+ readonly geo: _angular_core.Signal<ConnectorGeometry>;
818
+ readonly viewBox: _angular_core.Signal<string>;
819
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<ConnectorRendererComponent, never>;
820
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<ConnectorRendererComponent, "pptx-connector-renderer", never, { "element": { "alias": "element"; "required": true; "isSignal": true; }; "zIndex": { "alias": "zIndex"; "required": false; "isSignal": true; }; }, {}, never, never, true, never>;
821
+ }
822
+
823
+ /**
824
+ * Pure, framework-agnostic helpers for table rendering.
825
+ *
826
+ * Ported from:
827
+ * - packages/react/src/viewer/utils/table-render-helpers.ts (cellStyleToCss,
828
+ * ooxmlDashToCssBorderStyle)
829
+ * - packages/react/src/viewer/utils/table-render-data.tsx (row / cell
830
+ * view-model projection)
831
+ *
832
+ * All functions are pure (no Angular dependencies) so they can be unit-tested
833
+ * with plain vitest without TestBed or the Angular compiler.
834
+ */
835
+
836
+ /**
837
+ * A single styled text run inside a cell paragraph.
838
+ *
839
+ * The `style` map is an `[ngStyle]`-compatible object derived from the cell's
840
+ * `PptxTableCellStyle` (bold, italic, underline, color, fontSize). When the
841
+ * cell has no style the map is empty ({}) and CSS inherits.
842
+ *
843
+ * `isLineBreak` is true for soft line-break runs. The template renders them
844
+ * as `<br>`.
845
+ */
846
+ interface CellTextRun {
847
+ text: string;
848
+ style: StyleMap;
849
+ isLineBreak?: true;
850
+ }
851
+ /**
852
+ * A single paragraph inside a table cell, made up of one or more `CellTextRun`s.
853
+ *
854
+ * In the current implementation each paragraph has exactly one run (styled by
855
+ * the cell-level `PptxTableCellStyle`). When the core later exposes per-run
856
+ * segments on `PptxTableCell`, additional runs per paragraph will be populated.
857
+ */
858
+ type CellParagraph = CellTextRun[];
859
+ /**
860
+ * A flattened cell descriptor ready for template iteration. Cells flagged
861
+ * `hMerge` or `vMerge` are excluded; the template produces no `<td>` for
862
+ * them (the origin cell's colspan/rowspan expands to cover the gap).
863
+ */
864
+ interface TableCellViewModel {
865
+ cell: PptxTableCell;
866
+ /** Resolved colspan from `gridSpan` (>= 2) or undefined. */
867
+ colSpan: number | undefined;
868
+ /** Resolved rowspan from `rowSpan` (>= 2) or undefined. */
869
+ rowSpan: number | undefined;
870
+ /** Pre-computed `[ngStyle]` map for this cell's `<td>`. */
871
+ tdStyle: StyleMap;
872
+ /**
873
+ * Display text — non-breaking space when the cell is empty to keep the row
874
+ * height. Used as fallback when `paragraphs` is empty (no text AND no style).
875
+ */
876
+ displayText: string;
877
+ /**
878
+ * Rich-text paragraphs built from the cell's text content and cell-level
879
+ * style. When non-empty the template renders this instead of `displayText`.
880
+ * Each entry is a paragraph (array of styled runs); runs with `isLineBreak`
881
+ * render as `<br>`.
882
+ *
883
+ * When this array is empty (cell is completely empty + unstyled) the template
884
+ * falls back to rendering `displayText` (a non-breaking space) so the row
885
+ * retains its height.
886
+ */
887
+ paragraphs: CellParagraph[];
888
+ }
889
+ interface TableRowViewModel {
890
+ rowStyle: StyleMap;
891
+ cells: TableCellViewModel[];
892
+ }
893
+
894
+ /**
895
+ * TableRendererComponent — Angular port of the React `renderTableFromTableData`
896
+ * (packages/react/src/viewer/utils/table-render-data.tsx).
897
+ *
898
+ * Renders a `<table>` from the typed `PptxTableData` structure that the core
899
+ * parser populates on every `TablePptxElement`. This is the viewer-first path:
900
+ * editing, resize overlays, and inline cell input are not yet ported.
901
+ *
902
+ * Key behaviours:
903
+ * - Merged cells: cells with `hMerge`/`vMerge` are skipped; the origin cell
904
+ * receives `[attr.colspan]`/`[attr.rowspan]` from `gridSpan`/`rowSpan`.
905
+ * - Column widths: a `<colgroup>` drives proportional widths from
906
+ * `PptxTableData.columnWidths` (0–1 fractions).
907
+ * - Row heights: `[ngStyle]` on `<tr>` sets an explicit pixel height when
908
+ * `PptxTableRow.height` is present.
909
+ * - Cell fill: solid `backgroundColor` or the parser's pre-built
910
+ * `gradientFillCss` string (gradient). Pattern fills are deferred.
911
+ * - Cell borders: per-edge (top/bottom/left/right) width + colour.
912
+ * - Cell text: rich-text paragraphs of styled `<span>` runs when the cell
913
+ * carries text or formatting; falls back to a non-breaking-space placeholder
914
+ * for empty+unstyled cells (preserves row height).
915
+ *
916
+ * Pure helpers (view-model projection, style maps) live in
917
+ * `table-renderer-helpers.ts` so tests can exercise them without TestBed.
918
+ */
919
+ declare class TableRendererComponent {
920
+ /** The table element to render. Must be `type === 'table'`. */
921
+ readonly element: _angular_core.InputSignal<PptxElement>;
922
+ /** Pre-computed `<col>` styles for the colgroup. */
923
+ readonly colStyles: _angular_core.Signal<StyleMap[]>;
924
+ /** Projected view-model rows with merged-cell resolution applied. */
925
+ readonly rows: _angular_core.Signal<TableRowViewModel[]>;
926
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<TableRendererComponent, never>;
927
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<TableRendererComponent, "pptx-table-renderer", never, { "element": { "alias": "element"; "required": true; "isSignal": true; }; }, {}, never, never, true, never>;
928
+ }
929
+
930
+ /**
931
+ * Pure, framework-agnostic helpers for chart rendering.
932
+ *
933
+ * Ported from:
934
+ * packages/react/src/viewer/utils/chart-helpers.ts (value range, Y mapping, formatting, palette)
935
+ * packages/react/src/viewer/utils/chart-layout.ts (plot-area layout)
936
+ * packages/react/src/viewer/utils/chart-pie.tsx (pie/doughnut geometry)
937
+ * packages/react/src/viewer/utils/chart-bar.tsx (bar rect projection)
938
+ * packages/react/src/viewer/utils/chart-area-line.tsx (line/area point projection)
939
+ * packages/react/src/viewer/utils/chart-scatter-bubble.tsx (scatter point projection)
940
+ *
941
+ * All functions here are pure TypeScript with zero Angular dependencies.
942
+ * The component consumes a single `ChartViewModel` that is the projection
943
+ * of a `ChartPptxElement` -> SVG primitives.
944
+ *
945
+ * Supported chart kinds (viewer-first):
946
+ * bar / column (clustered, stacked, percentStacked) -> bar rects
947
+ * line / line3D -> polyline + dots
948
+ * area / area3D -> polygon fill + polyline
949
+ * pie / doughnut / pie3D / ofPie -> arc paths
950
+ * scatter -> circle dots
951
+ *
952
+ * Deferred (fallback box rendered instead):
953
+ * bubble, radar, stock, waterfall, combo, surface, treemap, sunburst,
954
+ * funnel, boxWhisker, histogram, regionMap, bar3D (complex 3-D shading),
955
+ * error bars, trendlines, secondary axes, data tables.
956
+ *
957
+ * @module chart-renderer-helpers
958
+ */
959
+
960
+ interface SvgRect {
961
+ kind: 'rect';
962
+ x: number;
963
+ y: number;
964
+ w: number;
965
+ h: number;
966
+ fill: string;
967
+ rx?: number;
968
+ opacity?: number;
969
+ }
970
+ interface SvgPath {
971
+ kind: 'path';
972
+ d: string;
973
+ fill: string;
974
+ stroke?: string;
975
+ strokeWidth?: number;
976
+ }
977
+ interface SvgPolyline {
978
+ kind: 'polyline';
979
+ points: string;
980
+ stroke: string;
981
+ strokeWidth: number;
982
+ fill: string;
983
+ opacity?: number;
984
+ }
985
+ interface SvgCircle {
986
+ kind: 'circle';
987
+ cx: number;
988
+ cy: number;
989
+ r: number;
990
+ fill: string;
991
+ opacity?: number;
992
+ }
993
+ interface SvgLine {
994
+ kind: 'line';
995
+ x1: number;
996
+ y1: number;
997
+ x2: number;
998
+ y2: number;
999
+ stroke: string;
1000
+ strokeWidth: number;
1001
+ dashArray?: string;
1002
+ opacity?: number;
1003
+ }
1004
+ interface SvgText {
1005
+ kind: 'text';
1006
+ x: number;
1007
+ y: number;
1008
+ text: string;
1009
+ fontSize: number;
1010
+ fill: string;
1011
+ textAnchor: 'start' | 'middle' | 'end';
1012
+ fontWeight?: 'normal' | 'bold';
1013
+ dominantBaseline?: string;
1014
+ opacity?: number;
1015
+ }
1016
+ interface SvgAreaGradient {
1017
+ kind: 'areaGradient';
1018
+ id: string;
1019
+ color: string;
1020
+ }
1021
+ type SvgPrimitive = SvgRect | SvgPath | SvgPolyline | SvgCircle | SvgLine | SvgText | SvgAreaGradient;
1022
+ interface LegendEntry {
1023
+ color: string;
1024
+ label: string;
1025
+ }
1026
+ interface ChartViewModel {
1027
+ svgWidth: number;
1028
+ svgHeight: number;
1029
+ title: string | undefined;
1030
+ titleX: number;
1031
+ titleY: number;
1032
+ gridlines: SvgLine[];
1033
+ axisLabels: SvgText[];
1034
+ zeroLine: SvgLine | undefined;
1035
+ categoryLabels: SvgText[];
1036
+ primitives: SvgPrimitive[];
1037
+ dataLabels: SvgText[];
1038
+ legend: LegendEntry[];
1039
+ legendX: number;
1040
+ legendY: number;
1041
+ legendAnchor: 'start' | 'middle' | 'end';
1042
+ }
1043
+
1044
+ declare class ChartRendererComponent {
1045
+ readonly element: _angular_core.InputSignal<PptxElement>;
1046
+ readonly vm: _angular_core.Signal<ChartViewModel>;
1047
+ readonly viewBox: _angular_core.Signal<string>;
1048
+ readonly swatchSize = 10;
1049
+ legendTransform(index: number): string;
1050
+ asRect(p: SvgPrimitive): SvgRect;
1051
+ asPath(p: SvgPrimitive): SvgPath;
1052
+ asPolyline(p: SvgPrimitive): SvgPolyline;
1053
+ asCircle(p: SvgPrimitive): SvgCircle;
1054
+ asLine(p: SvgPrimitive): SvgLine;
1055
+ asText(p: SvgPrimitive): SvgText;
1056
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<ChartRendererComponent, never>;
1057
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<ChartRendererComponent, "pptx-chart-renderer", never, { "element": { "alias": "element"; "required": true; "isSignal": true; }; }, {}, never, never, true, never>;
1058
+ }
1059
+
1060
+ /**
1061
+ * Pure TypeScript SmartArt family layout engines.
1062
+ *
1063
+ * Computes node box positions for the four core SmartArt families so the
1064
+ * Angular `SmartArtRendererComponent` can lay out nodes when no explicit
1065
+ * drawing-shapes are present.
1066
+ *
1067
+ * No Angular imports — all exports are plain TypeScript so they can be
1068
+ * unit-tested with vitest without TestBed or the Angular compiler.
1069
+ *
1070
+ * Geometry ported from the React renderers:
1071
+ * packages/react/src/viewer/components/elements/smartart-layout-renderers.tsx
1072
+ * packages/react/src/viewer/components/elements/smartart-renderer-hierarchy.tsx
1073
+ * packages/react/src/viewer/utils/smartart-helpers.tsx
1074
+ */
1075
+
1076
+ /**
1077
+ * A positioned node box ready to be rendered as `<rect>` + `<text>` in an SVG.
1078
+ */
1079
+ interface PositionedNode {
1080
+ /** Original node id from `PptxSmartArtNode`. */
1081
+ id: string;
1082
+ /** Display text (may be truncated by the caller). */
1083
+ text: string;
1084
+ /** Left edge (SVG user units). */
1085
+ x: number;
1086
+ /** Top edge (SVG user units). */
1087
+ y: number;
1088
+ /** Box width (SVG user units). */
1089
+ w: number;
1090
+ /** Box height (SVG user units). */
1091
+ h: number;
1092
+ /**
1093
+ * Zero-based tree depth / band index.
1094
+ * For flat families (list, process, cycle) all nodes are at level 0.
1095
+ */
1096
+ level: number;
1097
+ /**
1098
+ * Node radius — only set for cycle nodes (rendered as `<circle>`).
1099
+ * When defined the caller should render a circle at (x + r, y + r) instead
1100
+ * of a rect.
1101
+ */
1102
+ r?: number;
1103
+ }
1104
+ /**
1105
+ * A connector segment rendered as `<line x1 y1 x2 y2 />` or SVG `<path>`.
1106
+ */
1107
+ interface ConnectorSegment {
1108
+ x1: number;
1109
+ y1: number;
1110
+ x2: number;
1111
+ y2: number;
1112
+ }
1113
+ /**
1114
+ * Result returned by `layoutSmartArtNodes`.
1115
+ */
1116
+ interface SmartArtLayoutResult {
1117
+ nodes: PositionedNode[];
1118
+ connectors: ConnectorSegment[];
1119
+ }
1120
+
1121
+ /**
1122
+ * Pure, framework-agnostic helpers for SmartArt rendering.
1123
+ *
1124
+ * Ported from the Vue component
1125
+ * packages/vue/src/viewer/components/SmartArtRenderer.vue
1126
+ * (viewer-first subset — drawing-shapes path + stacked-block fallback).
1127
+ *
1128
+ * No Angular imports: all exports are plain TypeScript functions / types so
1129
+ * they can be unit-tested with vitest without TestBed or the Angular compiler.
1130
+ */
1131
+
1132
+ /**
1133
+ * Projected view-model for a single pre-computed drawing shape, ready for
1134
+ * direct use in an SVG `<g>` block.
1135
+ */
1136
+ interface RenderedShape {
1137
+ /** Stable React-style key. */
1138
+ key: string;
1139
+ /** True → render `<ellipse>`, false → render `<rect>`. */
1140
+ isEllipse: boolean;
1141
+ /** Rect top-left (relative to the viewBox origin). */
1142
+ x: number;
1143
+ y: number;
1144
+ width: number;
1145
+ height: number;
1146
+ /** Border-radius for `<rect rx>` (roundRect shapes). */
1147
+ rx: number;
1148
+ /** Ellipse centre x. */
1149
+ cx: number;
1150
+ /** Ellipse centre y. */
1151
+ cy: number;
1152
+ fill: string;
1153
+ stroke: string;
1154
+ strokeWidth: number;
1155
+ /** SVG `transform` attribute, e.g. `rotate(30 50 40)`. */
1156
+ transform: string | undefined;
1157
+ /** Truncated text label (≤30 chars), or `undefined` when absent. */
1158
+ text: string | undefined;
1159
+ /** Text anchor x (centre of shape). */
1160
+ textX: number;
1161
+ /** Text anchor y (centre of shape). */
1162
+ textY: number;
1163
+ fontColor: string;
1164
+ fontSize: number;
1165
+ }
1166
+ /**
1167
+ * SVG `viewBox` bounding-box derived from all drawing shapes.
1168
+ *
1169
+ * Returns the minimal bounding box plus `minX`/`minY` offsets used to
1170
+ * rebase each shape's position to (0, 0).
1171
+ */
1172
+ interface DrawingViewBox {
1173
+ minX: number;
1174
+ minY: number;
1175
+ width: number;
1176
+ height: number;
1177
+ }
1178
+ /**
1179
+ * A single coloured block in the stacked fallback list.
1180
+ */
1181
+ interface FallbackBlock {
1182
+ /** Stable key for `@for` tracking. */
1183
+ key: string;
1184
+ text: string;
1185
+ fill: string;
1186
+ }
1187
+
1188
+ /**
1189
+ * SmartArtRendererComponent — Angular port of the Vue `SmartArtRenderer.vue`
1190
+ * (packages/vue/src/viewer/components/SmartArtRenderer.vue).
1191
+ *
1192
+ * Viewer-first subset: renders from pre-computed drawing shapes
1193
+ * (`smartArtData.drawingShapes`) when present, otherwise falls back to a
1194
+ * stacked coloured block list of node text. When neither is available a small
1195
+ * "SmartArt" placeholder is shown.
1196
+ *
1197
+ * Editing, interaction, and the full family-specific layout renderers
1198
+ * (hierarchy / cycle / process / …) are out of scope — tracked in PORTING.md.
1199
+ */
1200
+ declare class SmartArtRendererComponent {
1201
+ /** The smartArt element to render. Must be `type === 'smartArt'`. */
1202
+ readonly element: _angular_core.InputSignal<PptxElement>;
1203
+ readonly zIndex: _angular_core.InputSignal<number>;
1204
+ readonly containerStyle: _angular_core.Signal<StyleMap>;
1205
+ readonly chromeStyle: _angular_core.Signal<StyleMap>;
1206
+ readonly palette: _angular_core.Signal<string[]>;
1207
+ readonly artStyle: _angular_core.Signal<pptx_viewer_core.SmartArtStyle>;
1208
+ readonly nodes: _angular_core.Signal<pptx_viewer_core.PptxSmartArtNode[]>;
1209
+ readonly rawDrawingShapes: _angular_core.Signal<pptx_viewer_core.PptxSmartArtDrawingShape[]>;
1210
+ readonly hasDrawingShapes: _angular_core.Signal<boolean>;
1211
+ readonly viewBox: _angular_core.Signal<DrawingViewBox>;
1212
+ /** `viewBox` attribute string for the `<svg>` element. */
1213
+ readonly svgViewBox: _angular_core.Signal<string>;
1214
+ readonly renderedShapes: _angular_core.Signal<RenderedShape[]>;
1215
+ readonly shadowFilter: _angular_core.Signal<string | undefined>;
1216
+ readonly layoutResult: _angular_core.Signal<SmartArtLayoutResult>;
1217
+ readonly hasLayout: _angular_core.Signal<boolean>;
1218
+ readonly layoutViewBox: _angular_core.Signal<string>;
1219
+ /** Palette colour for a node at the given depth level. */
1220
+ nodeFill(level: number): string;
1221
+ readonly fallbackBlocks: _angular_core.Signal<FallbackBlock[]>;
1222
+ readonly isEmpty: _angular_core.Signal<boolean>;
1223
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<SmartArtRendererComponent, never>;
1224
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<SmartArtRendererComponent, "pptx-smart-art-renderer", never, { "element": { "alias": "element"; "required": true; "isSignal": true; }; "zIndex": { "alias": "zIndex"; "required": false; "isSignal": true; }; }, {}, never, never, true, never>;
1225
+ }
1226
+
1227
+ /**
1228
+ * Pure helpers for `InkRendererComponent`.
1229
+ *
1230
+ * All functions are framework-agnostic (no Angular dependency) so they can be
1231
+ * unit-tested without TestBed, following the same pattern as
1232
+ * `connector-path.ts`.
1233
+ */
1234
+ /** Resolved per-stroke data used to render a single `<path>`. */
1235
+ interface InkStroke {
1236
+ d: string;
1237
+ color: string;
1238
+ width: number;
1239
+ opacity: number;
1240
+ }
1241
+
1242
+ /**
1243
+ * InkRendererComponent — Angular port of the Vue `InkRenderer.vue`
1244
+ * (and the React `renderInk` inside `InkGroupRenderers.tsx`), viewer-first
1245
+ * subset.
1246
+ *
1247
+ * Renders freehand ink strokes (`InkPptxElement.inkPaths`) as inline SVG
1248
+ * `<path>` elements inside the element's bounding box, with per-stroke colour,
1249
+ * width, and opacity resolved from the parallel `inkColors`/`inkWidths`/
1250
+ * `inkOpacities` arrays.
1251
+ *
1252
+ * Not ported (TODO, see PORTING.md): pressure-sensitive variable-width strokes
1253
+ * (`inkPointPressures`), ink replay animation, and the highlighter/eraser tool
1254
+ * blend modes. These all degrade gracefully to plain constant-width strokes.
1255
+ *
1256
+ * All non-trivial pure computation lives in `ink-renderer-helpers.ts` (no
1257
+ * Angular dependency) so it can be unit-tested without TestBed.
1258
+ */
1259
+ declare class InkRendererComponent {
1260
+ readonly element: _angular_core.InputSignal<PptxElement>;
1261
+ readonly zIndex: _angular_core.InputSignal<number>;
1262
+ readonly mediaDataUrls: _angular_core.InputSignal<Map<string, string>>;
1263
+ readonly containerStyle: _angular_core.Signal<StyleMap>;
1264
+ readonly strokes: _angular_core.Signal<InkStroke[]>;
1265
+ readonly viewBox: _angular_core.Signal<string>;
1266
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<InkRendererComponent, never>;
1267
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<InkRendererComponent, "pptx-ink-renderer", never, { "element": { "alias": "element"; "required": true; "isSignal": true; }; "zIndex": { "alias": "zIndex"; "required": false; "isSignal": true; }; "mediaDataUrls": { "alias": "mediaDataUrls"; "required": false; "isSignal": true; }; }, {}, never, never, true, never>;
1268
+ }
1269
+
1270
+ /**
1271
+ * Pure, framework-agnostic helpers for OLE renderer.
1272
+ *
1273
+ * Ported from:
1274
+ * - packages/react/src/viewer/components/elements/InkGroupRenderers.tsx
1275
+ * (resolveOleType, getOleTypeColor, getOleTypeLabel, getOleAriaLabel)
1276
+ * - packages/vue/src/viewer/components/OleRenderer.vue
1277
+ * (placeholder style, badge label, display name)
1278
+ *
1279
+ * All functions are pure (no Angular dependencies) so they can be unit-tested
1280
+ * with plain vitest without TestBed or the Angular compiler.
1281
+ */
1282
+
1283
+ /**
1284
+ * Resolved OLE application type, narrowed from the raw `OleObjectType` union.
1285
+ *
1286
+ * `package` and `unknown` from the core type both collapse to `'unknown'` here
1287
+ * so that every branch is guaranteed to have a colour and label.
1288
+ */
1289
+ type ResolvedOleType = 'excel' | 'word' | 'pdf' | 'visio' | 'mathtype' | 'unknown';
1290
+
1291
+ /**
1292
+ * OleRendererComponent — Angular port of the React `renderOleElement`
1293
+ * (packages/react/src/viewer/components/elements/InkGroupRenderers.tsx) and
1294
+ * the Vue `OleRenderer.vue`.
1295
+ *
1296
+ * Renders an embedded OLE object (`OlePptxElement`). When a decoded preview
1297
+ * image is present (`previewImageData`) it is shown full-size with a small
1298
+ * type-badge overlay; otherwise a type-specific icon + label placeholder box
1299
+ * is drawn, mirroring the React / Vue fallback.
1300
+ *
1301
+ * Pure helpers (type resolution, colour / label maps, placeholder style) live
1302
+ * in `ole-renderer-helpers.ts` so they can be unit-tested without TestBed.
1303
+ *
1304
+ * Double-click-to-open and OLE extraction are not ported (viewer-only).
1305
+ */
1306
+ declare class OleRendererComponent {
1307
+ /** The element to render. Must be `type === 'ole'`. */
1308
+ readonly element: _angular_core.InputSignal<PptxElement>;
1309
+ readonly zIndex: _angular_core.InputSignal<number>;
1310
+ /** Absolute container positioning + dimensions. */
1311
+ readonly containerStyle: _angular_core.Signal<StyleMap>;
1312
+ /** Narrowed OLE element — undefined when the input is not `type === 'ole'`. */
1313
+ private readonly ole;
1314
+ /** Resolved application type (excel / word / pdf / visio / mathtype / unknown). */
1315
+ readonly oleType: _angular_core.Signal<ResolvedOleType>;
1316
+ /** Brand hex colour for the resolved type. */
1317
+ readonly typeColor: _angular_core.Signal<string>;
1318
+ /** Human-readable type label (e.g. "Excel Spreadsheet"). */
1319
+ readonly typeLabel: _angular_core.Signal<string>;
1320
+ /** Short uppercase badge text shown over the preview image. */
1321
+ readonly badgeLabel: _angular_core.Signal<string>;
1322
+ /** Preview image data-URL, or undefined to show the placeholder. */
1323
+ readonly previewSrc: _angular_core.Signal<string | undefined>;
1324
+ /** Original file name, if present. */
1325
+ readonly fileName: _angular_core.Signal<string | undefined>;
1326
+ /** Primary display name: file name if present, otherwise the type label. */
1327
+ readonly displayName: _angular_core.Signal<string>;
1328
+ /** Accessible label for the role="img" wrapper. */
1329
+ readonly ariaLabel: _angular_core.Signal<string>;
1330
+ /** Border + background style for the placeholder box. */
1331
+ readonly placeholderStyle: _angular_core.Signal<StyleMap>;
1332
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<OleRendererComponent, never>;
1333
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<OleRendererComponent, "pptx-ole-renderer", never, { "element": { "alias": "element"; "required": true; "isSignal": true; }; "zIndex": { "alias": "zIndex"; "required": false; "isSignal": true; }; }, {}, never, never, true, never>;
1334
+ }
1335
+
1336
+ /**
1337
+ * Pure helpers for `Model3DRendererComponent`.
1338
+ *
1339
+ * All functions are framework-agnostic (no Angular dependency) so they can be
1340
+ * unit-tested without TestBed, following the same pattern as
1341
+ * `connector-path.ts`.
1342
+ */
1343
+ /** Narrowed view-model derived from a `Model3DPptxElement`. */
1344
+ interface Model3DViewModel {
1345
+ /** Resolved model element, or undefined when the element is not a model3d. */
1346
+ readonly model: Model3DPptxElement | undefined;
1347
+ /**
1348
+ * Poster image src: `posterImage` is preferred over the raster `imageData`
1349
+ * fallback (mirrors the React `PosterFallback` and the Vue port).
1350
+ */
1351
+ readonly posterSrc: string | undefined;
1352
+ }
1353
+
1354
+ /**
1355
+ * Model3DRendererComponent — Angular port of the Vue `Model3DRenderer.vue`
1356
+ * (and the React `Model3DRenderer` / `PosterFallback`), poster-only subset.
1357
+ *
1358
+ * Interactive 3D rendering (three.js) is intentionally OUT OF SCOPE for the
1359
+ * Angular port — see PORTING.md. This component always renders the
1360
+ * poster/preview image (`posterImage`, falling back to `imageData`); when
1361
+ * neither exists it draws a labelled "3D Model" placeholder, exactly like the
1362
+ * React poster fallback.
1363
+ *
1364
+ * All non-trivial pure computation lives in `model3d-renderer-helpers.ts` (no
1365
+ * Angular dependency) so it can be unit-tested without TestBed.
1366
+ */
1367
+ declare class Model3DRendererComponent {
1368
+ readonly element: _angular_core.InputSignal<PptxElement>;
1369
+ readonly zIndex: _angular_core.InputSignal<number>;
1370
+ readonly mediaDataUrls: _angular_core.InputSignal<Map<string, string>>;
1371
+ readonly containerStyle: _angular_core.Signal<StyleMap>;
1372
+ readonly vm: _angular_core.Signal<Model3DViewModel>;
1373
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<Model3DRendererComponent, never>;
1374
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<Model3DRendererComponent, "pptx-model3d-renderer", never, { "element": { "alias": "element"; "required": true; "isSignal": true; }; "zIndex": { "alias": "zIndex"; "required": false; "isSignal": true; }; "mediaDataUrls": { "alias": "mediaDataUrls"; "required": false; "isSignal": true; }; }, {}, never, never, true, never>;
1375
+ }
1376
+
1377
+ /**
1378
+ * Pure helpers for `ZoomRendererComponent`.
1379
+ *
1380
+ * All functions are framework-agnostic (no Angular dependency) so they can be
1381
+ * unit-tested without TestBed, following the same pattern as
1382
+ * `connector-path.ts`.
1383
+ */
1384
+ /** Narrowed view-model derived from a `ZoomPptxElement`. */
1385
+ interface ZoomViewModel {
1386
+ /** Resolved zoom element, or undefined when the element is not a zoom. */
1387
+ readonly zoom: ZoomPptxElement | undefined;
1388
+ /** Preview image src (the `imageData` embedded thumbnail). */
1389
+ readonly previewSrc: string | undefined;
1390
+ /** Zero-based target slide index. */
1391
+ readonly targetSlideIndex: number;
1392
+ /** Zoom type string used as the badge label source and data attribute. */
1393
+ readonly zoomType: 'slide' | 'section';
1394
+ /** Optional section identifier for section zooms. */
1395
+ readonly targetSectionId: string | undefined;
1396
+ /** Human-readable badge text ("Slide Zoom" / "Section Zoom"). */
1397
+ readonly badgeText: string;
1398
+ /** Human-readable slide label ("Slide N"). */
1399
+ readonly slideLabel: string;
1400
+ /** Accessible label for the element. */
1401
+ readonly ariaLabel: string;
1402
+ }
1403
+
1404
+ /**
1405
+ * ZoomRendererComponent — Angular port of the Vue `ZoomRenderer.vue`
1406
+ * (and the React `ZoomElementRenderer`), static viewer-first subset.
1407
+ *
1408
+ * Renders a Slide-Zoom / Section-Zoom tile (`ZoomPptxElement`): the element's
1409
+ * own preview thumbnail (`imageData`) when available, otherwise a fallback tile
1410
+ * showing the target slide number. A small "Slide Zoom" / "Section Zoom" badge
1411
+ * is drawn in the corner.
1412
+ *
1413
+ * Navigation (click-to-jump in presentation mode) and live target-slide preview
1414
+ * rendering are NOT ported — this is a static link tile only (see PORTING.md).
1415
+ * The `slides` array is not threaded through, so the fallback uses the target
1416
+ * slide index rather than the real target background.
1417
+ *
1418
+ * All non-trivial pure computation lives in `zoom-renderer-helpers.ts` (no
1419
+ * Angular dependency) so it can be unit-tested without TestBed.
1420
+ */
1421
+ declare class ZoomRendererComponent {
1422
+ readonly element: _angular_core.InputSignal<PptxElement>;
1423
+ readonly zIndex: _angular_core.InputSignal<number>;
1424
+ readonly mediaDataUrls: _angular_core.InputSignal<Map<string, string>>;
1425
+ readonly containerStyle: _angular_core.Signal<StyleMap>;
1426
+ readonly vm: _angular_core.Signal<ZoomViewModel>;
1427
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<ZoomRendererComponent, never>;
1428
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<ZoomRendererComponent, "pptx-zoom-renderer", never, { "element": { "alias": "element"; "required": true; "isSignal": true; }; "zIndex": { "alias": "zIndex"; "required": false; "isSignal": true; }; "mediaDataUrls": { "alias": "mediaDataUrls"; "required": false; "isSignal": true; }; }, {}, never, never, true, never>;
1429
+ }
1430
+
1431
+ /**
1432
+ * PresentationOverlayComponent — full-viewport black overlay that renders
1433
+ * slides in presentation (kiosk) mode.
1434
+ *
1435
+ * Selector: `pptx-presentation-overlay`
1436
+ *
1437
+ * Inputs:
1438
+ * - `slides` (required) — all slides in the deck
1439
+ * - `canvasSize` (required) — logical canvas dimensions in pixels
1440
+ * - `mediaDataUrls` — data-URL map for media assets (default: empty Map)
1441
+ * - `startIndex` — zero-based slide to show first (default: 0)
1442
+ *
1443
+ * Outputs:
1444
+ * - `indexChange` — emits the new index on every navigation
1445
+ * - `closed` — emits void when the overlay should be dismissed
1446
+ *
1447
+ * Keyboard bindings (document-level so no focusable element is required):
1448
+ * ArrowRight / Space / PageDown → next visible slide
1449
+ * ArrowLeft / PageUp → previous visible slide
1450
+ * Home → first slide
1451
+ * End → last slide
1452
+ * Escape → emit `closed`
1453
+ *
1454
+ * Touch bindings (mobile has no keyboard):
1455
+ * Always-visible ✕ button (top-right) → emit `closed`
1456
+ * ‹ / › edge buttons → previous / next visible slide
1457
+ * Horizontal swipe → left → next, right → previous
1458
+ *
1459
+ * Click on the overlay body → advance to next visible slide.
1460
+ */
1461
+ declare class PresentationOverlayComponent implements OnInit, OnDestroy {
1462
+ readonly slides: _angular_core.InputSignal<PptxSlide[]>;
1463
+ readonly canvasSize: _angular_core.InputSignal<CanvasSize>;
1464
+ readonly mediaDataUrls: _angular_core.InputSignal<Map<string, string>>;
1465
+ readonly startIndex: _angular_core.InputSignal<number>;
1466
+ readonly indexChange: _angular_core.OutputEmitterRef<number>;
1467
+ readonly closed: _angular_core.OutputEmitterRef<void>;
1468
+ /** Zero-based index into `slides()`. */
1469
+ protected readonly currentIndex: _angular_core.WritableSignal<number>;
1470
+ /** Viewport dimensions — updated on resize. */
1471
+ private readonly viewportW;
1472
+ private readonly viewportH;
1473
+ protected readonly currentSlide: _angular_core.Signal<PptxSlide | undefined>;
1474
+ /** Zoom level that fits the canvas into the current viewport. */
1475
+ protected readonly zoom: _angular_core.Signal<number>;
1476
+ /** Centre the scaled slide in the viewport. */
1477
+ protected readonly stageContainerStyle: _angular_core.Signal<Record<string, string>>;
1478
+ /** "3 / 12" label. */
1479
+ protected readonly counterLabel: _angular_core.Signal<string>;
1480
+ /**
1481
+ * Always-visible close button, fixed at the top-right and offset by the
1482
+ * device safe-area insets so it clears notches / rounded corners. Sits on a
1483
+ * higher z-index than the stage so taps never fall through to tap-advance.
1484
+ */
1485
+ protected readonly closeButtonStyle: Record<string, string>;
1486
+ /** Shared geometry for the left/right edge navigation buttons. */
1487
+ private readonly navButtonBase;
1488
+ protected readonly prevButtonStyle: Record<string, string>;
1489
+ protected readonly nextButtonStyle: Record<string, string>;
1490
+ protected readonly counterStyle: Record<string, string>;
1491
+ /** Horizontal swipe distance (px) required to trigger navigation. */
1492
+ private static readonly SWIPE_THRESHOLD;
1493
+ /** X coordinate captured on touchstart, or null when no swipe is active. */
1494
+ private touchStartX;
1495
+ private touchStartY;
1496
+ ngOnInit(): void;
1497
+ ngOnDestroy(): void;
1498
+ onWindowResize(): void;
1499
+ private snapViewport;
1500
+ onKeyDown(event: KeyboardEvent): void;
1501
+ /** Left-click on the slide area advances to the next visible slide. */
1502
+ protected onBodyClick(event: MouseEvent): void;
1503
+ /** Close button click — stop propagation so it does not also advance. */
1504
+ protected onClose(event: MouseEvent): void;
1505
+ /**
1506
+ * Close button touch — stop propagation and prevent the synthesized click
1507
+ * so a tap exits without bubbling to the tap-advance handler.
1508
+ */
1509
+ protected onCloseTouch(event: TouchEvent): void;
1510
+ /** Previous-edge button — stop propagation so the tap does not double-fire. */
1511
+ protected onPrev(event: MouseEvent): void;
1512
+ protected onPrevTouch(event: TouchEvent): void;
1513
+ /** Next-edge button — stop propagation so the tap does not double-fire. */
1514
+ protected onNext(event: MouseEvent): void;
1515
+ protected onNextTouch(event: TouchEvent): void;
1516
+ /** Record the initial touch position. */
1517
+ protected onTouchStart(event: TouchEvent): void;
1518
+ /**
1519
+ * On touchend, treat a predominantly horizontal drag past the threshold as a
1520
+ * swipe: left-swipe → next, right-swipe → prev.
1521
+ */
1522
+ protected onTouchEnd(event: TouchEvent): void;
1523
+ private navigate;
1524
+ private emitClosed;
1525
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<PresentationOverlayComponent, never>;
1526
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<PresentationOverlayComponent, "pptx-presentation-overlay", never, { "slides": { "alias": "slides"; "required": true; "isSignal": true; }; "canvasSize": { "alias": "canvasSize"; "required": true; "isSignal": true; }; "mediaDataUrls": { "alias": "mediaDataUrls"; "required": false; "isSignal": true; }; "startIndex": { "alias": "startIndex"; "required": false; "isSignal": true; }; }, { "indexChange": "indexChange"; "closed": "closed"; }, never, never, true, never>;
1527
+ }
1528
+
1529
+ /**
1530
+ * SlideSorterOverlayComponent — Angular port of the React `SlideSorterOverlay`.
1531
+ *
1532
+ * Renders a fixed full-screen modal overlay containing a responsive grid of
1533
+ * scaled slide previews. Clicking a thumbnail emits `select(index)`; pressing
1534
+ * Escape or clicking the ✕ button emits `closed`.
1535
+ *
1536
+ * Viewer-first scope: no drag-reorder, no context menu, no section grouping.
1537
+ * Those features are tracked in PORTING.md.
1538
+ *
1539
+ * Usage:
1540
+ * ```html
1541
+ * <pptx-slide-sorter-overlay
1542
+ * [slides]="slides()"
1543
+ * [canvasSize]="canvasSize()"
1544
+ * [mediaDataUrls]="mediaDataUrls()"
1545
+ * [activeIndex]="activeSlideIndex()"
1546
+ * (select)="goTo($event)"
1547
+ * (closed)="showSorter.set(false)"
1548
+ * />
1549
+ * ```
1550
+ */
1551
+ declare class SlideSorterOverlayComponent {
1552
+ /** Full list of slides to display. */
1553
+ readonly slides: _angular_core.InputSignal<PptxSlide[]>;
1554
+ /** Natural (100 %) canvas dimensions — passed through to SlideCanvasComponent. */
1555
+ readonly canvasSize: _angular_core.InputSignal<CanvasSize>;
1556
+ /** Media asset lookup table — forwarded to each SlideCanvasComponent. */
1557
+ readonly mediaDataUrls: _angular_core.InputSignal<Map<string, string>>;
1558
+ /** Zero-based index of the currently active slide (highlighted in blue). */
1559
+ readonly activeIndex: _angular_core.InputSignal<number>;
1560
+ /** Emits the zero-based index of the thumbnail the user clicked. */
1561
+ readonly select: _angular_core.OutputEmitterRef<number>;
1562
+ /** Emits when the user closes the overlay (✕ button or Escape key). */
1563
+ readonly closed: _angular_core.OutputEmitterRef<void>;
1564
+ /** Zoom level that fits the full canvas width into THUMB_W pixels. */
1565
+ readonly thumbZoom: _angular_core.Signal<number>;
1566
+ /** Pixel height of the clipping box (aspect-correct). */
1567
+ readonly thumbH: _angular_core.Signal<number>;
1568
+ /** ngStyle object for the thumbnail clipping box. */
1569
+ readonly clipStyle: _angular_core.Signal<Record<string, string>>;
1570
+ /** ngStyle object for the grid: responsive auto-fill columns. */
1571
+ readonly gridStyle: _angular_core.Signal<Record<string, string>>;
1572
+ /** Keyboard handler: Escape closes the overlay. */
1573
+ onKeydown(event: KeyboardEvent): void;
1574
+ /** Clicking the backdrop (outside the panel) closes the overlay. */
1575
+ onBackdropClick(event: MouseEvent): void;
1576
+ /** Clicking a thumbnail selects the slide. */
1577
+ onThumbClick(index: number): void;
1578
+ /** Returns true when a slide has been marked as hidden in the presentation. */
1579
+ isHiddenSlide(slide: PptxSlide): boolean;
1580
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<SlideSorterOverlayComponent, never>;
1581
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<SlideSorterOverlayComponent, "pptx-slide-sorter-overlay", never, { "slides": { "alias": "slides"; "required": true; "isSignal": true; }; "canvasSize": { "alias": "canvasSize"; "required": true; "isSignal": true; }; "mediaDataUrls": { "alias": "mediaDataUrls"; "required": false; "isSignal": true; }; "activeIndex": { "alias": "activeIndex"; "required": false; "isSignal": true; }; }, { "select": "select"; "closed": "closed"; }, never, never, true, never>;
1582
+ }
1583
+
1584
+ /**
1585
+ * slide-search.ts — Pure text-search helpers for PPTX slides.
1586
+ *
1587
+ * No Angular imports; safe to use in web workers or server-side code.
1588
+ *
1589
+ * @module slide-search
1590
+ */
1591
+
1592
+ /**
1593
+ * A single slide that matched a text search query.
1594
+ */
1595
+ interface SlideSearchMatch {
1596
+ /** Zero-based index of the matching slide in the slides array. */
1597
+ slideIndex: number;
1598
+ /** Number of (overlapping) occurrences of the query on this slide. */
1599
+ matchCount: number;
1600
+ /**
1601
+ * A short snippet of text surrounding the first match.
1602
+ * Includes a few characters of context on each side.
1603
+ */
1604
+ snippet: string;
1605
+ }
1606
+ /**
1607
+ * Collect all visible text from a single {@link PptxElement}.
1608
+ *
1609
+ * - `text` / `shape` / `connector` — flat `text` field + `textSegments[].text`.
1610
+ * - `table` — iterates `tableData.rows[].cells[].text`.
1611
+ * - `smartArt` — recursively collects `smartArtData.nodes[].text`.
1612
+ * - `group` — recurses into `children`.
1613
+ * - All other element types produce an empty string.
1614
+ */
1615
+ declare function collectElementText(element: PptxElement): string;
1616
+ /**
1617
+ * Collect all visible text from a {@link PptxSlide}, including speaker notes.
1618
+ */
1619
+ declare function collectSlideText(slide: PptxSlide): string;
1620
+ /**
1621
+ * Search all slides for `query` (case-insensitive substring match).
1622
+ *
1623
+ * Returns an empty array when `query` is empty or whitespace-only.
1624
+ */
1625
+ declare function searchSlides(slides: readonly PptxSlide[], query: string): SlideSearchMatch[];
1626
+
1627
+ declare class FindBarComponent {
1628
+ /** All slides in the current presentation. */
1629
+ readonly slides: _angular_core.InputSignal<PptxSlide[]>;
1630
+ /** Emits the zero-based slide index to navigate to. */
1631
+ readonly navigate: _angular_core.OutputEmitterRef<number>;
1632
+ /** Emits when the user closes the find bar (Escape or ✕). */
1633
+ readonly closed: _angular_core.OutputEmitterRef<void>;
1634
+ private readonly queryInputRef;
1635
+ /** Current text typed into the search input. */
1636
+ readonly query: _angular_core.WritableSignal<string>;
1637
+ /**
1638
+ * Zero-based index into the flat `matches` array tracking which result is
1639
+ * currently highlighted. Clamped whenever `matches` changes.
1640
+ */
1641
+ readonly activeMatchIndex: _angular_core.WritableSignal<number>;
1642
+ /** Slides that contain at least one match for the current query. */
1643
+ readonly matches: _angular_core.Signal<SlideSearchMatch[]>;
1644
+ /** Total number of individual occurrences across all matching slides. */
1645
+ readonly totalMatches: _angular_core.Signal<number>;
1646
+ /**
1647
+ * 1-based display position (which slide-level result we're on).
1648
+ * Accounts for clamping when the match list shrinks.
1649
+ */
1650
+ readonly activeMatchDisplay: _angular_core.Signal<number>;
1651
+ /** Snippet text for the currently active match. */
1652
+ readonly activeSnippet: _angular_core.Signal<string>;
1653
+ /**
1654
+ * Pressing Escape anywhere on the document closes the find bar.
1655
+ * (Enter inside the input already calls `next()` via `keydown.enter`.)
1656
+ */
1657
+ onDocumentKeydown(event: KeyboardEvent): void;
1658
+ onInput(event: Event): void;
1659
+ next(): void;
1660
+ prev(): void;
1661
+ close(): void;
1662
+ private _emitCurrentSlide;
1663
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<FindBarComponent, never>;
1664
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<FindBarComponent, "pptx-find-bar", never, { "slides": { "alias": "slides"; "required": true; "isSignal": true; }; }, { "navigate": "navigate"; "closed": "closed"; }, never, never, true, never>;
1665
+ }
1666
+
1667
+ declare class InspectorPanelComponent {
1668
+ /** The single selected element whose properties are being edited. */
1669
+ readonly element: _angular_core.InputSignal<PptxElement>;
1670
+ /** Zero-based index of the active slide. */
1671
+ readonly slideIndex: _angular_core.InputSignal<number>;
1672
+ protected readonly editor: EditorStateService;
1673
+ /** Alias so the template can call el() without conflicting with Angular internals. */
1674
+ protected readonly el: _angular_core.Signal<PptxElement>;
1675
+ /**
1676
+ * Stable identity key for the selected element. Only changes when a
1677
+ * *different* element is selected. The seed signal below is keyed on this so
1678
+ * input [value] bindings never get rewritten while the user is typing into
1679
+ * the currently-selected element (caret-reset / keyboard-dismiss guard).
1680
+ */
1681
+ protected readonly elementKey: _angular_core.Signal<string>;
1682
+ /**
1683
+ * One-shot seed of every editable field's initial display value, recomputed
1684
+ * only when `elementKey` changes (i.e. on selection change), NOT on every
1685
+ * edit commit. Bound to each <input>'s [value] so Angular re-evaluating the
1686
+ * binding during change-detection always yields the same value mid-edit and
1687
+ * therefore never rewrites the element's `.value` / resets the caret.
1688
+ */
1689
+ protected readonly seed: _angular_core.Signal<{
1690
+ x: number;
1691
+ y: number;
1692
+ width: number;
1693
+ height: number;
1694
+ rotation: number;
1695
+ opacity: number;
1696
+ fillColor: string;
1697
+ strokeColor: string;
1698
+ textColor: string;
1699
+ fontSize: number;
1700
+ }>;
1701
+ /** Whether the element supports shape-style (fill/stroke) editing. */
1702
+ protected readonly hasShape: _angular_core.Signal<boolean>;
1703
+ /** Whether the element supports text-style editing. */
1704
+ protected readonly hasText: _angular_core.Signal<boolean>;
1705
+ protected readonly currentBold: _angular_core.Signal<boolean>;
1706
+ protected readonly currentItalic: _angular_core.Signal<boolean>;
1707
+ protected readonly currentUnderline: _angular_core.Signal<boolean>;
1708
+ protected onPositionChange(event: Event, axis: 'x' | 'y'): void;
1709
+ protected onSizeChange(event: Event, dim: 'width' | 'height'): void;
1710
+ protected onRotationChange(event: Event): void;
1711
+ protected onOpacityChange(event: Event): void;
1712
+ protected onFillColorChange(event: Event): void;
1713
+ protected onStrokeColorChange(event: Event): void;
1714
+ protected onTextColorChange(event: Event): void;
1715
+ protected onFontSizeChange(event: Event): void;
1716
+ protected onBoldToggle(): void;
1717
+ protected onItalicToggle(): void;
1718
+ protected onUnderlineToggle(): void;
1719
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<InspectorPanelComponent, never>;
1720
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<InspectorPanelComponent, "pptx-inspector-panel", never, { "element": { "alias": "element"; "required": true; "isSignal": true; }; "slideIndex": { "alias": "slideIndex"; "required": true; "isSignal": true; }; }, {}, never, never, true, never>;
1721
+ }
1722
+
1723
+ /**
1724
+ * SlidesPanelComponent — vertical slide-strip for the editor sidebar.
1725
+ *
1726
+ * Renders the live editable deck (from {@link EditorStateService}) as a
1727
+ * scrollable vertical list of numbered thumbnail cards. Clicking a card emits
1728
+ * `select(index)`; the active card is highlighted. Per-card hover toolbar
1729
+ * provides Duplicate, Delete (disabled when only 1 slide), Move up, and Move
1730
+ * down. A footer "+ Add slide" button appends a blank slide after the current
1731
+ * `activeIndex`.
1732
+ *
1733
+ * Usage:
1734
+ * ```html
1735
+ * <pptx-slides-panel
1736
+ * [canvasSize]="loader.canvasSize()"
1737
+ * [mediaDataUrls]="loader.mediaDataUrls()"
1738
+ * [activeIndex]="activeSlideIndex()"
1739
+ * (select)="goTo($event)"
1740
+ * />
1741
+ * ```
1742
+ */
1743
+ declare class SlidesPanelComponent {
1744
+ /** Natural (100 %) canvas dimensions — forwarded to each SlideCanvasComponent. */
1745
+ readonly canvasSize: _angular_core.InputSignal<CanvasSize>;
1746
+ /** Media asset lookup table — forwarded to each SlideCanvasComponent. */
1747
+ readonly mediaDataUrls: _angular_core.InputSignal<Map<string, string>>;
1748
+ /** Zero-based index of the currently active slide (highlighted in blue). */
1749
+ readonly activeIndex: _angular_core.InputSignal<number>;
1750
+ /** Emits the zero-based index of the card the user clicked. */
1751
+ readonly select: _angular_core.OutputEmitterRef<number>;
1752
+ protected readonly editor: EditorStateService;
1753
+ /** Zoom level that fits the full canvas width into THUMB_W pixels. */
1754
+ readonly thumbZoom: _angular_core.Signal<number>;
1755
+ /** Pixel height of the clipping box (aspect-correct). */
1756
+ readonly thumbH: _angular_core.Signal<number>;
1757
+ /** ngStyle object for the thumbnail clipping box. */
1758
+ readonly clipStyle: _angular_core.Signal<Record<string, string>>;
1759
+ onDuplicate(index: number): void;
1760
+ onDelete(index: number): void;
1761
+ onMoveUp(index: number): void;
1762
+ onMoveDown(index: number): void;
1763
+ onAddSlide(): void;
1764
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<SlidesPanelComponent, never>;
1765
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<SlidesPanelComponent, "pptx-slides-panel", never, { "canvasSize": { "alias": "canvasSize"; "required": true; "isSignal": true; }; "mediaDataUrls": { "alias": "mediaDataUrls"; "required": false; "isSignal": true; }; "activeIndex": { "alias": "activeIndex"; "required": false; "isSignal": true; }; }, { "select": "select"; }, never, never, true, never>;
1766
+ }
1767
+
1768
+ declare class EditorToolbarComponent {
1769
+ /** Zero-based index of the slide being edited. */
1770
+ readonly slideIndex: _angular_core.InputSignal<number>;
1771
+ protected readonly editor: EditorStateService;
1772
+ /** Align needs ≥2 selected elements; distribute needs ≥3. */
1773
+ protected readonly canAlign: _angular_core.Signal<boolean>;
1774
+ protected readonly canDistribute: _angular_core.Signal<boolean>;
1775
+ /** Group needs ≥2 selected; ungroup needs exactly one selected group. */
1776
+ protected readonly canGroup: _angular_core.Signal<boolean>;
1777
+ protected readonly canUngroup: _angular_core.Signal<boolean>;
1778
+ protected onInsertText(): void;
1779
+ protected onInsertShape(shapeType: 'rect' | 'ellipse' | 'line'): void;
1780
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<EditorToolbarComponent, never>;
1781
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<EditorToolbarComponent, "pptx-editor-toolbar", never, { "slideIndex": { "alias": "slideIndex"; "required": true; "isSignal": true; }; }, {}, never, never, true, never>;
1782
+ }
1783
+
1784
+ declare class EditorContextMenuComponent {
1785
+ /** Horizontal viewport coordinate (px) of the top-left corner of the menu. */
1786
+ readonly x: _angular_core.InputSignal<number>;
1787
+ /** Vertical viewport coordinate (px) of the top-left corner of the menu. */
1788
+ readonly y: _angular_core.InputSignal<number>;
1789
+ /** Zero-based index of the slide being edited. */
1790
+ readonly slideIndex: _angular_core.InputSignal<number>;
1791
+ /** Emitted when the menu should close (Escape or outside click). */
1792
+ readonly closed: _angular_core.OutputEmitterRef<void>;
1793
+ protected readonly editor: EditorStateService;
1794
+ private readonly host;
1795
+ onEscape(): void;
1796
+ onDocumentPointerDown(event: PointerEvent): void;
1797
+ protected onCut(): void;
1798
+ protected onCopy(): void;
1799
+ protected onPaste(): void;
1800
+ protected onDuplicate(): void;
1801
+ protected onDelete(): void;
1802
+ protected onBringToFront(): void;
1803
+ protected onSendToBack(): void;
1804
+ protected onBringForward(): void;
1805
+ protected onSendBackward(): void;
1806
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<EditorContextMenuComponent, never>;
1807
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<EditorContextMenuComponent, "pptx-editor-context-menu", never, { "x": { "alias": "x"; "required": true; "isSignal": true; }; "y": { "alias": "y"; "required": true; "isSignal": true; }; "slideIndex": { "alias": "slideIndex"; "required": true; "isSignal": true; }; }, { "closed": "closed"; }, never, never, true, never>;
1808
+ }
1809
+
1810
+ declare class ExportService {
1811
+ /**
1812
+ * Rasterize a single DOM element to PNG and trigger a browser download.
1813
+ *
1814
+ * @param el - The element to capture (e.g. the `.pptx-ng-canvas-stage`).
1815
+ * @param fileName - Suggested download file name (unsafe chars are stripped).
1816
+ * @param scale - Device-pixel ratio multiplier (default 2 for sharp output).
1817
+ */
1818
+ exportElementToPng(el: HTMLElement, fileName: string, scale?: number): Promise<void>;
1819
+ /**
1820
+ * Rasterize a single element to a canvas (passthrough to html2canvas-pro).
1821
+ * Capture each slide's canvas *while that slide is the live DOM* — the
1822
+ * viewer reuses one stage node, so a deferred capture would yield the same
1823
+ * (last) slide for every page.
1824
+ */
1825
+ renderElement(el: HTMLElement, scale?: number): Promise<HTMLCanvasElement>;
1826
+ /**
1827
+ * Assemble a multi-page PDF from pre-rendered slide canvases (one page per
1828
+ * canvas, sized to the slide aspect ratio in pt) and trigger a download.
1829
+ *
1830
+ * @param canvases - One canvas per slide, in order, each captured while
1831
+ * its slide was the live stage.
1832
+ * @param canvasWidth - Slide canvas width in pixels (for aspect ratio).
1833
+ * @param canvasHeight - Slide canvas height in pixels (for aspect ratio).
1834
+ * @param fileName - Suggested download file name (unsafe chars stripped).
1835
+ */
1836
+ exportCanvasesToPdf(canvases: HTMLCanvasElement[], canvasWidth: number, canvasHeight: number, fileName: string): void;
1837
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<ExportService, never>;
1838
+ static ɵprov: _angular_core.ɵɵInjectableDeclaration<ExportService>;
1839
+ }
1840
+
1841
+ /**
1842
+ * A drop-in replacement for `html2canvas(element, options)` that first
1843
+ * resolves any oklch / oklab / lch / lab / color() values in the cloned
1844
+ * DOM to rgb()/hex, preventing parse errors in html2canvas ≤ 1.x.
1845
+ *
1846
+ * Three-pronged approach:
1847
+ * 1. Patch `<style>` elements to replace oklch in CSS custom properties.
1848
+ * 2. Resolve `:root` / `<body>` inline custom properties.
1849
+ * 3. Walk every element and convert computed colour values to sRGB.
1850
+ *
1851
+ * Usage:
1852
+ * ```ts
1853
+ * import { renderToCanvas } from '../lib/canvas-export';
1854
+ * const canvas = await renderToCanvas(element, { scale: 2 });
1855
+ * ```
1856
+ */
1857
+ declare function renderToCanvas(element: HTMLElement, options?: Partial<Options>): Promise<HTMLCanvasElement>;
1858
+
1859
+ /**
1860
+ * editor-history.ts — Generic undo/redo history stack.
1861
+ *
1862
+ * Framework-agnostic: no Angular, React, or any other framework imports.
1863
+ * Designed to be consumed by an Angular service (e.g. EditorStateService).
1864
+ *
1865
+ * ## Snapshot semantics (PRE-mutation model)
1866
+ *
1867
+ * `record(snapshot, label)` must be called with the snapshot taken BEFORE the
1868
+ * caller applies its mutation. The class never deep-clones values: the caller
1869
+ * is responsible for passing already-cloned / immutable snapshots so that
1870
+ * mutations to the live state do not retroactively corrupt stored history
1871
+ * entries.
1872
+ *
1873
+ * ## Example usage inside EditorStateService
1874
+ *
1875
+ * // before mutating:
1876
+ * this.history.record(this.currentSnapshot(), 'Move element');
1877
+ * // apply mutation to the live signal …
1878
+ *
1879
+ * // undo:
1880
+ * const result = this.history.undo(this.currentSnapshot());
1881
+ * if (result) this.applySnapshot(result.snapshot);
1882
+ *
1883
+ * // redo:
1884
+ * const result = this.history.redo(this.currentSnapshot());
1885
+ * if (result) this.applySnapshot(result.snapshot);
1886
+ */
1887
+ interface UndoRedoResult<T> {
1888
+ readonly snapshot: T;
1889
+ readonly label: string;
1890
+ }
1891
+ interface EditorHistoryOptions {
1892
+ /**
1893
+ * Maximum number of past entries kept on the undo stack.
1894
+ * When exceeded, the oldest entry is silently dropped.
1895
+ * @default 100
1896
+ */
1897
+ maxDepth?: number;
1898
+ }
1899
+ /**
1900
+ * Generic undo/redo history stack.
1901
+ *
1902
+ * `T` is the snapshot type; the caller decides what constitutes a snapshot
1903
+ * (e.g. `PptxSlide[]`, a plain state object, etc.).
1904
+ *
1905
+ * No deep-cloning is performed inside this class — the caller must pass
1906
+ * already-cloned snapshots.
1907
+ */
1908
+ declare class EditorHistory<T> {
1909
+ private readonly _maxDepth;
1910
+ private readonly _past;
1911
+ private readonly _future;
1912
+ constructor(options?: EditorHistoryOptions);
1913
+ /** True when at least one undo step is available. */
1914
+ get canUndo(): boolean;
1915
+ /** True when at least one redo step is available. */
1916
+ get canRedo(): boolean;
1917
+ /**
1918
+ * Label of the most-recently recorded entry (the action that would be
1919
+ * undone on the next `undo()` call), or `undefined` when the stack is
1920
+ * empty.
1921
+ */
1922
+ get undoLabel(): string | undefined;
1923
+ /**
1924
+ * Label of the most-recently undone entry (the action that would be
1925
+ * redone on the next `redo()` call), or `undefined` when the redo stack
1926
+ * is empty.
1927
+ */
1928
+ get redoLabel(): string | undefined;
1929
+ /** Number of entries currently on the undo (past) stack. */
1930
+ get depth(): number;
1931
+ /**
1932
+ * Push `snapshot` (taken **before** the caller's mutation) onto the undo
1933
+ * stack with the given `label`, then clear the redo stack.
1934
+ *
1935
+ * When the stack length exceeds `maxDepth`, the oldest entry is dropped.
1936
+ *
1937
+ * The caller must pass an already-cloned snapshot — this method does NOT
1938
+ * deep-clone.
1939
+ */
1940
+ record(snapshot: T, label: string): void;
1941
+ /**
1942
+ * Undo the last recorded action.
1943
+ *
1944
+ * Pops the top of the past stack, pushes `current` onto the future stack
1945
+ * (so it can be redone), and returns the popped entry so the caller can
1946
+ * restore it.
1947
+ *
1948
+ * Returns `undefined` when there is nothing to undo (`canUndo === false`).
1949
+ *
1950
+ * The caller must pass an already-cloned snapshot for `current` — this
1951
+ * method does NOT deep-clone.
1952
+ */
1953
+ undo(current: T): UndoRedoResult<T> | undefined;
1954
+ /**
1955
+ * Redo the last undone action.
1956
+ *
1957
+ * Pops the top of the future stack, pushes `current` back onto the past
1958
+ * stack, and returns the popped entry so the caller can restore it.
1959
+ *
1960
+ * Returns `undefined` when there is nothing to redo (`canRedo === false`).
1961
+ *
1962
+ * The caller must pass an already-cloned snapshot for `current` — this
1963
+ * method does NOT deep-clone.
1964
+ */
1965
+ redo(current: T): UndoRedoResult<T> | undefined;
1966
+ /**
1967
+ * Clear both the undo and redo stacks, resetting history to an empty
1968
+ * state.
1969
+ */
1970
+ clear(): void;
1971
+ }
1972
+
1973
+ /**
1974
+ * element-operations — Pure array-transformation functions for slide elements.
1975
+ *
1976
+ * All functions are framework-agnostic (no Angular imports). Each takes a
1977
+ * `readonly PptxElement[]` representing the ordered element list for a slide
1978
+ * (array index 0 = back, last index = front/top in paint order) and returns a
1979
+ * NEW array — the input is never mutated.
1980
+ *
1981
+ * Callers supply a `newId` wherever a new element identity is needed, keeping
1982
+ * these functions deterministic and side-effect-free.
1983
+ *
1984
+ * Usage in an Angular service:
1985
+ * history.snapshot();
1986
+ * slides.update(s => replaceSlideElements(s, idx, ops(s[idx].elements, …)));
1987
+ */
1988
+
1989
+ /**
1990
+ * Shallow-merge `patch` onto the element with `id`.
1991
+ * The discriminant `type` is always preserved from the original element.
1992
+ *
1993
+ * @example
1994
+ * updateElementById(elements, 'el1', { x: 50, hidden: true })
1995
+ */
1996
+ declare function updateElementById(elements: readonly PptxElement[], id: string, patch: Partial<PptxElement>): PptxElement[];
1997
+ /**
1998
+ * Translate the element by `(dx, dy)` relative to its current position.
1999
+ *
2000
+ * @example
2001
+ * moveElementBy(elements, 'el1', 10, -5)
2002
+ */
2003
+ declare function moveElementBy(elements: readonly PptxElement[], id: string, dx: number, dy: number): PptxElement[];
2004
+ /**
2005
+ * Set the absolute position of the element with `id`.
2006
+ *
2007
+ * @example
2008
+ * setElementPosition(elements, 'el1', 100, 200)
2009
+ */
2010
+ declare function setElementPosition(elements: readonly PptxElement[], id: string, x: number, y: number): PptxElement[];
2011
+ /**
2012
+ * Set the size of the element with `id`, clamping both dimensions to at
2013
+ * least `MIN_ELEMENT_SIZE` (mirrors React's min-size guard).
2014
+ *
2015
+ * @example
2016
+ * resizeElement(elements, 'el1', 300, 150)
2017
+ */
2018
+ declare function resizeElement(elements: readonly PptxElement[], id: string, width: number, height: number): PptxElement[];
2019
+ /**
2020
+ * Remove all elements whose `id` is contained in `ids`.
2021
+ * Elements not in `ids` are returned in their original order.
2022
+ *
2023
+ * @example
2024
+ * deleteElementsByIds(elements, ['el1', 'el3'])
2025
+ */
2026
+ declare function deleteElementsByIds(elements: readonly PptxElement[], ids: readonly string[]): PptxElement[];
2027
+ /**
2028
+ * Insert a copy of the element with `id` at the end of the array, using
2029
+ * `newId` as the copy's identity. The copy is nudged by `offset` on both
2030
+ * axes so it does not exactly overlap the original.
2031
+ *
2032
+ * The caller is responsible for supplying a unique `newId` — keeping this
2033
+ * function pure and deterministic.
2034
+ *
2035
+ * @example
2036
+ * duplicateElementById(elements, 'el1', crypto.randomUUID(), 20)
2037
+ */
2038
+ declare function duplicateElementById(elements: readonly PptxElement[], id: string, newId: string, offset?: number): PptxElement[];
2039
+ /**
2040
+ * Move the element with `id` to the end of the array (top/front in paint order).
2041
+ *
2042
+ * @example
2043
+ * bringToFront(elements, 'el1')
2044
+ */
2045
+ declare function bringToFront(elements: readonly PptxElement[], id: string): PptxElement[];
2046
+ /**
2047
+ * Move the element with `id` to index 0 (bottom/back in paint order).
2048
+ *
2049
+ * @example
2050
+ * sendToBack(elements, 'el1')
2051
+ */
2052
+ declare function sendToBack(elements: readonly PptxElement[], id: string): PptxElement[];
2053
+ /**
2054
+ * Swap the element with `id` with the element one position higher in the
2055
+ * array (one step toward the front/top). No-op if already at the top.
2056
+ *
2057
+ * @example
2058
+ * bringForward(elements, 'el1')
2059
+ */
2060
+ declare function bringForward(elements: readonly PptxElement[], id: string): PptxElement[];
2061
+ /**
2062
+ * Swap the element with `id` with the element one position lower in the
2063
+ * array (one step toward the back/bottom). No-op if already at the bottom.
2064
+ *
2065
+ * @example
2066
+ * sendBackward(elements, 'el1')
2067
+ */
2068
+ declare function sendBackward(elements: readonly PptxElement[], id: string): PptxElement[];
2069
+
2070
+ /**
2071
+ * Pure paragraph bullet / list-marker helpers for the Angular text renderer.
2072
+ *
2073
+ * No Angular imports — all exports are plain TypeScript functions suitable for
2074
+ * use inside computed signals or template helper calls.
2075
+ *
2076
+ * Numbering schemes follow the OOXML `ST_TextAutonumberScheme` enumeration
2077
+ * (ECMA-376 §20.1.10.81). The `autoNumType` strings come from
2078
+ * `BulletInfo.autoNumType` as parsed by `pptx-viewer-core`.
2079
+ */
2080
+
2081
+ /**
2082
+ * Render the n-th (1-based) marker for an OOXML auto-numbering scheme.
2083
+ *
2084
+ * Suffix conventions:
2085
+ * - `…Period` → `label.` (e.g. "1.", "a.", "i.")
2086
+ * - `…ParenR` → `label)` (e.g. "1)", "a)", "i)")
2087
+ * - `…ParenBoth` → `(label)` (e.g. "(1)", "(a)", "(i)")
2088
+ * - `…Plain` → `label` (bare numeral)
2089
+ *
2090
+ * Unrecognised schemes fall back to `"<n>."`.
2091
+ *
2092
+ * @param autoNumType - The OOXML auto-number type string (e.g. "arabicPeriod").
2093
+ * @param n - 1-based sequence number to format.
2094
+ */
2095
+ declare function formatAutoNumber(autoNumType: string | undefined, n: number): string;
2096
+ /**
2097
+ * Resolved bullet marker for a single paragraph.
2098
+ *
2099
+ * `marker` — the text to prepend (e.g. "•", "1.", "a)").
2100
+ * `isNumbered` — true for auto-numbered lists; false for character bullets.
2101
+ * `color` — optional explicit bullet colour (hex string from `BulletInfo.color`).
2102
+ * `fontFamily` — optional explicit bullet font (from `BulletInfo.fontFamily`).
2103
+ */
2104
+ interface ParagraphBulletResult {
2105
+ marker: string;
2106
+ isNumbered: boolean;
2107
+ color?: string;
2108
+ fontFamily?: string;
2109
+ }
2110
+ /**
2111
+ * Resolve the bullet marker for the first segment of a paragraph.
2112
+ *
2113
+ * Returns `undefined` when:
2114
+ * - `firstSegment` is undefined or carries no `bulletInfo`.
2115
+ * - `bulletInfo.none` is `true` (`a:buNone` explicitly suppresses the bullet).
2116
+ * - The paragraph's `listType` is `'none'`.
2117
+ * - Neither `char` nor `autoNumType` is present.
2118
+ *
2119
+ * For auto-numbered bullets the 1-based sequence index is derived from
2120
+ * `bulletInfo.autoNumStartAt` (default 1) plus `bulletInfo.paragraphIndex`
2121
+ * (0-based paragraph position within the text body).
2122
+ *
2123
+ * @param firstSegment - The first `TextSegment` of the paragraph (carries `bulletInfo`).
2124
+ */
2125
+ declare function resolveParagraphBullet(firstSegment: TextSegment | undefined): ParagraphBulletResult | undefined;
2126
+ /**
2127
+ * Return the left-indent in pixels for the given list nesting level.
2128
+ *
2129
+ * `level` is the 0-based `paragraphLevel` from `TextSegment` (matches
2130
+ * OOXML `a:p/@lvl`). `undefined` or negative values are treated as level 0.
2131
+ *
2132
+ * @example
2133
+ * bulletIndentPx(0) // 0
2134
+ * bulletIndentPx(1) // 18
2135
+ * bulletIndentPx(3) // 54
2136
+ * bulletIndentPx(undefined) // 0
2137
+ */
2138
+ declare function bulletIndentPx(level: number | undefined): number;
2139
+
2140
+ /**
2141
+ * EquationRendererComponent — Angular port of the Vue `EquationRenderer.vue`
2142
+ * (single-equation variant).
2143
+ *
2144
+ * Renders one parsed OMML equation tree as inline MathML via Angular's
2145
+ * `DomSanitizer.bypassSecurityTrustHtml`, which is required because Angular's
2146
+ * default HTML sanitizer strips `<math>` namespace markup.
2147
+ *
2148
+ * The wrapper is an inline-block `<span>` so the component flows inside a text
2149
+ * paragraph in place of a regular text run. When an equation number is
2150
+ * supplied the layout mirrors the Vue numbered-equation row: centred equation
2151
+ * with the number right-aligned (flex row, width 100%).
2152
+ *
2153
+ * Pure conversion logic lives in `omml-to-mathml.ts` (Angular-free) so it can
2154
+ * be unit-tested without TestBed.
2155
+ */
2156
+ declare class EquationRendererComponent {
2157
+ /** Parsed OMML equation tree (the `equationXml` field of a `TextSegment`). */
2158
+ readonly equationXml: _angular_core.InputSignal<Record<string, unknown>>;
2159
+ /** Optional equation number shown right-aligned, e.g. `"1"` → `(1)`. */
2160
+ readonly equationNumber: _angular_core.InputSignal<string | undefined>;
2161
+ private readonly sanitizer;
2162
+ /**
2163
+ * Converts the OMML input to MathML and wraps it in a `SafeHtml` value so
2164
+ * Angular's `[innerHTML]` binding renders the `<math>` markup instead of
2165
+ * stripping it.
2166
+ */
2167
+ readonly safeMathml: _angular_core.Signal<SafeHtml>;
2168
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<EquationRendererComponent, never>;
2169
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<EquationRendererComponent, "pptx-equation-renderer", never, { "equationXml": { "alias": "equationXml"; "required": true; "isSignal": true; }; "equationNumber": { "alias": "equationNumber"; "required": false; "isSignal": true; }; }, {}, never, never, true, never>;
2170
+ }
2171
+
2172
+ /**
2173
+ * omml-to-mathml.ts — pure OMML → MathML conversion.
2174
+ *
2175
+ * Angular port of the Vue `viewer/composables/omml-to-mathml.ts`, consolidated
2176
+ * into a single self-contained, framework-agnostic module. No Angular/Vue/DOM
2177
+ * dependencies.
2178
+ *
2179
+ * Converts Office MathML (OMML) XML objects — as parsed by fast-xml-parser
2180
+ * during PPTX load (attributes prefixed with `@_`) — into standard MathML
2181
+ * markup strings (`<math>…</math>`) that browsers render natively.
2182
+ *
2183
+ * `pptx-viewer-core` does NOT ship an OMML→MathML converter (its
2184
+ * `OmmlLatexConverter` only does OMML↔LaTeX), so this logic is ported here.
2185
+ */
2186
+
2187
+ /**
2188
+ * A parsed OMML node. Structurally a parsed-XML object: attributes live under
2189
+ * `@_`-prefixed keys, children under their (namespaced) tag name, text under
2190
+ * `#text` (or a collapsed bare string). Aliased to core's `XmlObject`.
2191
+ */
2192
+ type OmmlNode = XmlObject;
2193
+ /**
2194
+ * Convert an OMML XML node (from fast-xml-parser) into a MathML string.
2195
+ *
2196
+ * Accepts the object at the `<a14:m>` / `<m:oMathPara>` level or directly at
2197
+ * `<m:oMath>`. Returns a `<math>` element string, or empty string if the input
2198
+ * is empty / unparseable.
2199
+ */
2200
+ declare function convertOmmlToMathMl(ommlNode: OmmlNode): string;
2201
+ /**
2202
+ * Convenience wrapper used by the Angular viewer: `ommlToMathml(omml)`.
2203
+ *
2204
+ * Accepts the parsed OMML object (the shape stored on
2205
+ * {@link TextSegment.equationXml}) or a raw OMML markup string. String inputs
2206
+ * are not re-parsed here (no XML parser dependency in this pure module) — they
2207
+ * are returned wrapped so callers can still surface raw markup if needed.
2208
+ */
2209
+ declare function ommlToMathml(omml: Record<string, unknown> | string | undefined): string;
2210
+
2211
+ /**
2212
+ * Shape-geometry clip-path helper.
2213
+ *
2214
+ * Wires the core geometry APIs into the Angular viewer's shape clipping
2215
+ * pipeline. Implements a priority cascade so renderers always pick the
2216
+ * highest-fidelity geometry available for a given element:
2217
+ *
2218
+ * 1. **Adjustment-aware** — if `shapeAdjustments` exist, consult
2219
+ * {@link getAdjustmentAwareShapeClipPath} so shapes like `pie`, `arc`,
2220
+ * `donut`, `blockArc`, and the wedge callouts respond to their
2221
+ * adjustment values.
2222
+ * 2. **Spec-correct preset evaluator** — {@link getShapeClipPathFromPreset}
2223
+ * uses the ECMA-376 `pathLst` evaluator to produce a `path('…')`
2224
+ * clip-path for any shape covered by the preset table.
2225
+ * 3. **Cloud Bezier path** — {@link getCloudPathForRendering} produces a
2226
+ * DPI-stable cubic-Bezier `path('…')` for `cloud` / `cloudCallout`.
2227
+ * 4. **Static polygon table** — {@link getShapeClipPath} (the core preset
2228
+ * table) is the final fallback for shapes none of the higher-fidelity
2229
+ * APIs cover.
2230
+ *
2231
+ * This module is a plain-TypeScript port of the React package's
2232
+ * `viewer/utils/resolved-shape-clip-path.ts`, with no framework imports.
2233
+ * It mirrors the Vue port's `viewer/composables/shape-geometry.ts` exactly
2234
+ * so the exported function names and signatures are drop-in compatible.
2235
+ */
2236
+
2237
+ /**
2238
+ * Resolve the best available CSS `clip-path` value for a shape type at a
2239
+ * given pixel size. Implements the priority cascade described in the module
2240
+ * docstring.
2241
+ *
2242
+ * @param shapeType The OOXML preset geometry name (case-insensitive).
2243
+ * @param width Element width in pixels (must be > 0 for path output).
2244
+ * @param height Element height in pixels (must be > 0 for path output).
2245
+ * @param adjustments Optional `shapeAdjustments` record from the element.
2246
+ * @returns A CSS `clip-path` value (`polygon(...)`, `path('…')`, or `inset(...)`),
2247
+ * or `undefined` if no clipping is needed.
2248
+ */
2249
+ declare function getResolvedShapeClipPathFor(shapeType: string | undefined, width: number, height: number, adjustments?: Record<string, number>): string | undefined;
2250
+ /**
2251
+ * Element-level convenience wrapper. Pulls `shapeType`, `width`, `height`,
2252
+ * and `shapeAdjustments` off a {@link PptxElement} and delegates to
2253
+ * {@link getResolvedShapeClipPathFor}.
2254
+ *
2255
+ * @param element The PPTX element to resolve a clip-path for.
2256
+ * @param width Optional width override (pixels). Defaults to `element.width`.
2257
+ * @param height Optional height override (pixels). Defaults to `element.height`.
2258
+ * @returns A CSS `clip-path` value, or `undefined`.
2259
+ */
2260
+ declare function getResolvedShapeClipPath(element: PptxElement, width?: number, height?: number): string | undefined;
2261
+
2262
+ /**
2263
+ * Slide-background style resolution.
2264
+ *
2265
+ * Maps a `PptxSlide`'s background fields to a `[ngStyle]`-compatible map for
2266
+ * the slide stage. Mirrors the React `SlideCanvas` background handling and the
2267
+ * Vue port: the core parser resolves the theme/master chain onto the slide, so
2268
+ * here we only translate the already-resolved fields to CSS.
2269
+ *
2270
+ * Precedence (highest first): image fill → gradient → pattern → solid colour.
2271
+ * Pattern fills currently approximate to their background colour (the SVG
2272
+ * pattern preset renderer — `color-patterns.ts` in React — is a shared
2273
+ * extraction candidate; see PORTING.md).
2274
+ */
2275
+
2276
+ /** Default slide stage colour when a slide carries no usable background. */
2277
+ declare const DEFAULT_SLIDE_BACKGROUND = "#ffffff";
2278
+ /**
2279
+ * Build the background portion of the slide stage style from a slide's
2280
+ * resolved background fields. Returns only `background-*` properties so the
2281
+ * caller can spread it into the rest of the stage style.
2282
+ */
2283
+ declare function getSlideBackgroundStyle(slide: PptxSlide | undefined): StyleMap;
2284
+
2285
+ /**
2286
+ * Hyperlink resolution + URL safety for the viewer.
2287
+ *
2288
+ * Viewer-first subset of the React `hyperlink-security.ts`: enough to render
2289
+ * safe `<a href>` links on text runs. Internal PowerPoint actions
2290
+ * (`ppaction://…` slide jumps) and unsafe protocols are not turned into
2291
+ * navigable hrefs here — slide-jump wiring is a follow-up (see PORTING.md).
2292
+ */
2293
+ /**
2294
+ * Whether a URL is safe to expose as an `href`. Blocks `javascript:`,
2295
+ * `data:`, `vbscript:`, and `mhtml:` (case- and whitespace-bypass resistant);
2296
+ * allows `http(s)`, `mailto:`, `tel:`, `ftp:`, and relative URLs.
2297
+ */
2298
+ declare function isUrlSafe(url: string | undefined): boolean;
2299
+ /** Whether a URL is a PowerPoint internal action (`ppaction://…`). */
2300
+ declare function isPpactionUrl(url: string | undefined): boolean;
2301
+ /**
2302
+ * Resolve a raw hyperlink value to a renderable, safe `href`, or `undefined`
2303
+ * when it should not be a plain link (empty, unsafe, or an internal
2304
+ * `ppaction://` slide jump).
2305
+ */
2306
+ declare function resolveHyperlinkHref(url: string | undefined): string | undefined;
2307
+
2308
+ /**
2309
+ * Gradient fill CSS builder — pure TypeScript, no Angular dependency.
2310
+ *
2311
+ * Ported from `packages/react/src/viewer/utils/color-gradient.ts`.
2312
+ *
2313
+ * Handles sanitization of gradient stop arrays and conversion to CSS gradient
2314
+ * strings. Gradient rendering follows ECMA-376 Part 1, §20.1.8.35 (gradFill)
2315
+ * and §20.1.8.49 (pathFill). The three path types — circle, rect, shape — each
2316
+ * have dedicated builders that approximate the OOXML behaviour as closely as
2317
+ * CSS radial-gradient permits.
2318
+ *
2319
+ * Pattern fill (`a:pattFill`) is intentionally NOT included here — it lives in
2320
+ * a separate module.
2321
+ */
2322
+
2323
+ /**
2324
+ * Builds a complete CSS `linear-gradient()` or `radial-gradient()` string
2325
+ * from a ShapeStyle's gradient properties.
2326
+ *
2327
+ * For radial gradients, the rendering varies by `fillGradientPathType`:
2328
+ * - `"circle"` (default): Simple circular radial gradient at the focal point.
2329
+ * - `"rect"`: Elliptical radial gradient sized from the fillToRect rectangle,
2330
+ * approximating the OOXML rectangular path gradient.
2331
+ * - `"shape"`: Radial gradient using farthest-side sizing, approximating a
2332
+ * gradient that follows the shape boundary.
2333
+ *
2334
+ * Falls back to `style.fillGradient` if no valid stops are present.
2335
+ *
2336
+ * @param style - The shape style containing gradient configuration.
2337
+ * @returns A CSS gradient string, or `undefined` if not a gradient fill.
2338
+ */
2339
+ declare function buildCssGradientFromShapeStyle(style: ShapeStyle | undefined): string | undefined;
2340
+
2341
+ /**
2342
+ * SVG pattern generation for OOXML pattern fill presets.
2343
+ *
2344
+ * Each preset maps to a tiled inline SVG data URI that closely approximates
2345
+ * the corresponding ECMA-376 pattern (ST_PresetPatternVal). Patterns use
2346
+ * two colours: foreground (`fg`) drawn on top of a background (`bg`) fill.
2347
+ *
2348
+ * Tile sizes are kept small (4-16 px) for performance when used as CSS
2349
+ * `background-image` data URIs.
2350
+ *
2351
+ * Reference: ECMA-376 Part 1, section 20.1.10.33 (ST_PresetPatternVal)
2352
+ *
2353
+ * Ported from `packages/react/src/viewer/utils/color-patterns.ts`.
2354
+ * Pure TypeScript — no Angular, Vue, or React runtime imports.
2355
+ */
2356
+
2357
+ /**
2358
+ * Generate an inline SVG string for an OOXML preset pattern fill.
2359
+ *
2360
+ * @param preset - DrawingML `ST_PresetPatternVal` string (e.g. `"pct5"`, `"horz"`).
2361
+ * @param fgColor - Foreground hex colour (e.g. `"#000000"`).
2362
+ * @param bgColor - Background hex colour (e.g. `"#ffffff"`).
2363
+ * @returns An SVG string for use as a tiled `background-image`, or `undefined`
2364
+ * when the preset is not implemented.
2365
+ */
2366
+ declare function getPatternSvg(preset: string, fgColor: string, bgColor: string): string | undefined;
2367
+ /**
2368
+ * Build CSS `background-image` and `background-color` values for an OOXML
2369
+ * pattern fill (`a:pattFill`) from a resolved `ShapeStyle`.
2370
+ *
2371
+ * Returns `undefined` when:
2372
+ * - `style` is absent,
2373
+ * - `style.fillMode` is not `"pattern"`,
2374
+ * - `style.fillPatternPreset` is missing, or
2375
+ * - the preset is not implemented by `getPatternSvg`.
2376
+ *
2377
+ * Colour values are hex-normalised before being passed to `getPatternSvg` so
2378
+ * the SVG is always well-formed even when the parser emits bare colour strings
2379
+ * without a leading `#`.
2380
+ *
2381
+ * @param style - Resolved shape style from the core parser.
2382
+ * @returns `{ backgroundImage, backgroundColor }` ready for `[ngStyle]`, or
2383
+ * `undefined` when pattern rendering is not applicable.
2384
+ */
2385
+ declare function buildPatternFillCss(style: ShapeStyle | undefined): {
2386
+ backgroundImage: string;
2387
+ backgroundColor: string;
2388
+ } | undefined;
2389
+
365
2390
  /**
366
2391
  * Theme system for the Angular PowerPoint viewer.
367
2392
  *
@@ -402,5 +2427,5 @@ declare function themeStyle(theme: ViewerTheme | undefined): Record<string, stri
402
2427
  type ClassValue = string | number | false | null | undefined;
403
2428
  declare function cn(...values: ClassValue[]): string;
404
2429
 
405
- export { DEFAULT_CANVAS_HEIGHT, DEFAULT_CANVAS_WIDTH, DEFAULT_FILL_COLOR, DEFAULT_STROKE_COLOR, DEFAULT_TEXT_COLOR, ElementRendererComponent, LoadContentService, PowerPointViewerComponent, SlideCanvasComponent, VIEWER_THEME, cn, defaultCssVars, defaultRadius, defaultThemeColors, getContainerStyle, getImageSrc, getShapeFillStrokeStyle, getTextBlockStyle, provideViewerTheme, themeStyle, themeToCssVars };
406
- export type { CanvasSize, ClassValue, CollaborationConfig, CollaborationRole, StyleMap, ViewerTheme, ViewerThemeColors };
2430
+ export { ChartRendererComponent, ConnectorRendererComponent, DEFAULT_CANVAS_HEIGHT, DEFAULT_CANVAS_WIDTH, DEFAULT_FILL_COLOR, DEFAULT_SLIDE_BACKGROUND, DEFAULT_STROKE_COLOR, DEFAULT_TEXT_COLOR, EditorContextMenuComponent, EditorHistory, EditorStateService, EditorToolbarComponent, ElementRendererComponent, EquationRendererComponent, ExportService, FindBarComponent, InkRendererComponent, InspectorPanelComponent, LoadContentService, Model3DRendererComponent, OleRendererComponent, PowerPointViewerComponent, PresentationOverlayComponent, RESIZE_HANDLES, SlideCanvasComponent, SlideSorterOverlayComponent, SlidesPanelComponent, SmartArtRendererComponent, TableRendererComponent, VIEWER_THEME, ZoomRendererComponent, applyMove, applyResize, bringForward, bringToFront, buildCssGradientFromShapeStyle, buildPatternFillCss, bulletIndentPx, cn, collectElementText, collectSlideText, convertOmmlToMathMl, defaultCssVars, defaultRadius, defaultThemeColors, deleteElementsByIds, duplicateElementById, formatAutoNumber, getContainerStyle, getImageSrc, getPatternSvg, getResolvedShapeClipPath, getResolvedShapeClipPathFor, getShapeFillStrokeStyle, getSlideBackgroundStyle, getTextBlockStyle, isPpactionUrl, isUrlSafe, moveElementBy, ommlToMathml, provideViewerTheme, renderToCanvas, resizeElement, resolveHyperlinkHref, resolveParagraphBullet, searchSlides, sendBackward, sendToBack, setElementPosition, themeStyle, themeToCssVars, updateElementById };
2431
+ export type { Box, CanvasSize, ClassValue, CollaborationConfig, CollaborationRole, ResizeHandle, StyleMap, ViewerTheme, ViewerThemeColors };