pptx-angular-viewer 1.1.15 → 1.1.17
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/fesm2022/pptx-angular-viewer.mjs +25947 -18559
- package/fesm2022/pptx-angular-viewer.mjs.map +1 -1
- package/package.json +4 -2
- package/types/pptx-angular-viewer.d.ts +1236 -64
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import * as _angular_core from '@angular/core';
|
|
2
2
|
import { Signal, OnInit, OnDestroy, InjectionToken, Provider } from '@angular/core';
|
|
3
3
|
import * as pptx_viewer_core from 'pptx-viewer-core';
|
|
4
|
-
import { PptxSlide, AccessibilityCheckOptions, AccessibilityIssue, PptxElement, PptxTheme, PptxSlideMaster, PptxEmbeddedFont, PptxCoreProperties, PptxComment, PptxTableCell, Model3DPptxElement, ZoomPptxElement,
|
|
4
|
+
import { PptxSlide, AccessibilityCheckOptions, AccessibilityIssue, PptxElement, PptxTheme, PptxSlideMaster, PptxEmbeddedFont, PptxCoreProperties, ParsedSignature, PptxComment, TextSegment, TextStyle, PptxTableCell, Model3DPptxElement, ZoomPptxElement, PptxSlideTransition, TablePptxElement, ChartPptxElement, XmlObject, SignatureStatus, AccessibilityIssueSeverity, AccessibilityIssueType, PptxElementAnimation, PptxTransitionType, ShapeStyle } from 'pptx-viewer-core';
|
|
5
|
+
import * as pptx_angular_viewer from 'pptx-angular-viewer';
|
|
5
6
|
import { Options } from 'html2canvas-pro';
|
|
6
7
|
import { SafeHtml } from '@angular/platform-browser';
|
|
7
|
-
import * as pptx_angular_viewer from 'pptx-angular-viewer';
|
|
8
8
|
|
|
9
9
|
/**
|
|
10
10
|
* Theme configuration types for the PowerPoint viewer.
|
|
@@ -192,6 +192,55 @@ declare class AccessibilityService {
|
|
|
192
192
|
static ɵprov: _angular_core.ɵɵInjectableDeclaration<AccessibilityService>;
|
|
193
193
|
}
|
|
194
194
|
|
|
195
|
+
/**
|
|
196
|
+
* broadcast-helpers.ts — Pure (no Angular) helpers for the Broadcast dialog.
|
|
197
|
+
*
|
|
198
|
+
* A broadcast is a one-way collaboration session: the presenter drives slide
|
|
199
|
+
* navigation and viewers follow along via a shareable link. These helpers
|
|
200
|
+
* cover the testable, framework-agnostic parts of the Vue `BroadcastDialog.vue`
|
|
201
|
+
* and React `BroadcastDialog.tsx`: room-id generation, form validation, and
|
|
202
|
+
* the viewer-link builder.
|
|
203
|
+
*
|
|
204
|
+
* No `any`; all regexes use the `/u` flag; no `String.prototype.replaceAll`,
|
|
205
|
+
* no regex named-capture-groups (ng-packagr lib-target constraints).
|
|
206
|
+
*/
|
|
207
|
+
/** Default y-websocket server URL used when no default is supplied. */
|
|
208
|
+
declare const DEFAULT_BROADCAST_SERVER_URL = "ws://localhost:1234";
|
|
209
|
+
/** Optional seed values for the broadcast start form. */
|
|
210
|
+
interface BroadcastDefaults {
|
|
211
|
+
roomId?: string;
|
|
212
|
+
serverUrl?: string;
|
|
213
|
+
}
|
|
214
|
+
/** The configuration emitted when a broadcast starts. */
|
|
215
|
+
interface BroadcastConfig {
|
|
216
|
+
roomId: string;
|
|
217
|
+
serverUrl: string;
|
|
218
|
+
}
|
|
219
|
+
/** Generate a fresh, broadcast-scoped room id (`broadcast-<suffix>`). */
|
|
220
|
+
declare function generateBroadcastRoomId(): string;
|
|
221
|
+
/**
|
|
222
|
+
* Seed the start form from the (optional) defaults, generating a fresh room id
|
|
223
|
+
* when none is supplied and falling back to the default server URL.
|
|
224
|
+
*/
|
|
225
|
+
declare function seedBroadcastFields(defaults?: BroadcastDefaults): BroadcastConfig;
|
|
226
|
+
/** Whether both required fields are non-blank (after trimming). */
|
|
227
|
+
declare function canStartBroadcast(fields: BroadcastConfig): boolean;
|
|
228
|
+
/**
|
|
229
|
+
* Assemble a {@link BroadcastConfig} from the (trimmed) form fields, or `null`
|
|
230
|
+
* when incomplete.
|
|
231
|
+
*/
|
|
232
|
+
declare function buildBroadcastConfig(fields: BroadcastConfig): BroadcastConfig | null;
|
|
233
|
+
/**
|
|
234
|
+
* Build the shareable viewer follow-link for a broadcast. Returns just the
|
|
235
|
+
* room id when no `origin`/`pathname` are available (non-browser environments).
|
|
236
|
+
*/
|
|
237
|
+
declare function buildBroadcastViewerUrl(roomId: string, serverUrl: string, location?: {
|
|
238
|
+
origin: string;
|
|
239
|
+
pathname: string;
|
|
240
|
+
}): string;
|
|
241
|
+
/** Whether the runtime exposes a usable async clipboard write API. */
|
|
242
|
+
declare function canUseClipboard(nav: Navigator | undefined): boolean;
|
|
243
|
+
|
|
195
244
|
/**
|
|
196
245
|
* collaboration-helpers.ts — Pure, framework-agnostic logic for the real-time
|
|
197
246
|
* collaboration subsystem (Yjs-backed presence + remote cursors).
|
|
@@ -383,6 +432,12 @@ declare class EditorStateService {
|
|
|
383
432
|
setSlides(slides: readonly PptxSlide[]): void;
|
|
384
433
|
/** Current editable slides as a fresh (cloned) array. */
|
|
385
434
|
snapshot(): readonly PptxSlide[];
|
|
435
|
+
/**
|
|
436
|
+
* Replace the whole deck with pre-computed slides (e.g. a find/replace
|
|
437
|
+
* result) as a single undoable history entry. Unlike {@link setSlides} this
|
|
438
|
+
* preserves history and selection.
|
|
439
|
+
*/
|
|
440
|
+
applyReplacement(newSlides: readonly PptxSlide[], label?: string): void;
|
|
386
441
|
select(ids: readonly string[]): void;
|
|
387
442
|
toggleSelect(id: string, additive: boolean): void;
|
|
388
443
|
clearSelection(): void;
|
|
@@ -457,6 +512,151 @@ declare class EditorStateService {
|
|
|
457
512
|
static ɵprov: _angular_core.ɵɵInjectableDeclaration<EditorStateService>;
|
|
458
513
|
}
|
|
459
514
|
|
|
515
|
+
/** Emitted when the user changes the find query or the case-sensitive toggle. */
|
|
516
|
+
interface FindEvent {
|
|
517
|
+
query: string;
|
|
518
|
+
matchCase: boolean;
|
|
519
|
+
}
|
|
520
|
+
/** Emitted when the user confirms a replacement action. */
|
|
521
|
+
interface ReplaceEvent {
|
|
522
|
+
query: string;
|
|
523
|
+
replacement: string;
|
|
524
|
+
matchCase: boolean;
|
|
525
|
+
}
|
|
526
|
+
declare class FindReplaceBarComponent {
|
|
527
|
+
/**
|
|
528
|
+
* Total number of matches found across all slides for the current query.
|
|
529
|
+
* Kept at 0 when no search has been performed yet.
|
|
530
|
+
*/
|
|
531
|
+
readonly matchCount: _angular_core.InputSignal<number>;
|
|
532
|
+
/**
|
|
533
|
+
* Zero-based index of the currently highlighted match.
|
|
534
|
+
* Used to derive the 1-based display counter.
|
|
535
|
+
*/
|
|
536
|
+
readonly matchIndex: _angular_core.InputSignal<number>;
|
|
537
|
+
/**
|
|
538
|
+
* Emitted whenever the find query or the case-sensitive toggle changes.
|
|
539
|
+
* The parent should run `findInSlides` and update `matchCount`/`matchIndex`.
|
|
540
|
+
*/
|
|
541
|
+
readonly find: _angular_core.OutputEmitterRef<FindEvent>;
|
|
542
|
+
/**
|
|
543
|
+
* Emitted when the user clicks ↑ / ↓ or presses Enter in the find input.
|
|
544
|
+
* Payload is `1` (next) or `-1` (previous).
|
|
545
|
+
* The parent advances `matchIndex` and navigates to the matching slide.
|
|
546
|
+
*/
|
|
547
|
+
readonly navigate: _angular_core.OutputEmitterRef<1 | -1>;
|
|
548
|
+
/**
|
|
549
|
+
* Emitted when the user clicks "Replace" (single match).
|
|
550
|
+
* The parent calls `replaceMatch(...)` on `EditorStateService`.
|
|
551
|
+
*/
|
|
552
|
+
readonly replaceOne: _angular_core.OutputEmitterRef<ReplaceEvent>;
|
|
553
|
+
/**
|
|
554
|
+
* Emitted when the user clicks "Replace All".
|
|
555
|
+
* The parent calls `replaceInSlides(...)` and commits the result to history.
|
|
556
|
+
*/
|
|
557
|
+
readonly replaceAll: _angular_core.OutputEmitterRef<ReplaceEvent>;
|
|
558
|
+
/** Emitted when the user closes the bar (Escape or ✕ button). */
|
|
559
|
+
readonly close: _angular_core.OutputEmitterRef<void>;
|
|
560
|
+
private readonly findInputRef;
|
|
561
|
+
/** Current text in the find input. */
|
|
562
|
+
readonly query: _angular_core.WritableSignal<string>;
|
|
563
|
+
/** Current text in the replacement input. */
|
|
564
|
+
readonly replacement: _angular_core.WritableSignal<string>;
|
|
565
|
+
/** Whether the search should be case-sensitive. */
|
|
566
|
+
readonly matchCase: _angular_core.WritableSignal<boolean>;
|
|
567
|
+
/** 1-based display index for the counter (e.g. "2 / 5"). Clamps to bounds. */
|
|
568
|
+
readonly displayIndex: _angular_core.Signal<number>;
|
|
569
|
+
/** Escape anywhere on the document closes the bar. */
|
|
570
|
+
onDocumentKeydown(event: KeyboardEvent): void;
|
|
571
|
+
onQueryInput(event: Event): void;
|
|
572
|
+
onReplacementInput(event: Event): void;
|
|
573
|
+
toggleCase(): void;
|
|
574
|
+
emitReplaceOne(): void;
|
|
575
|
+
emitReplaceAll(): void;
|
|
576
|
+
/** Focus the find input (called by the parent after toggling the bar open). */
|
|
577
|
+
focusFindInput(): void;
|
|
578
|
+
static ɵfac: _angular_core.ɵɵFactoryDeclaration<FindReplaceBarComponent, never>;
|
|
579
|
+
static ɵcmp: _angular_core.ɵɵComponentDeclaration<FindReplaceBarComponent, "pptx-find-replace-bar", never, { "matchCount": { "alias": "matchCount"; "required": false; "isSignal": true; }; "matchIndex": { "alias": "matchIndex"; "required": false; "isSignal": true; }; }, { "find": "find"; "navigate": "navigate"; "replaceOne": "replaceOne"; "replaceAll": "replaceAll"; "close": "close"; }, never, never, true, never>;
|
|
580
|
+
}
|
|
581
|
+
|
|
582
|
+
/**
|
|
583
|
+
* find-replace-helpers.ts — Pure find & replace helpers for PPTX slides.
|
|
584
|
+
*
|
|
585
|
+
* Ported from:
|
|
586
|
+
* packages/react/src/viewer/hooks/useFindReplace.ts (findInSlides, applyFindReplacements)
|
|
587
|
+
*
|
|
588
|
+
* No Angular imports; safe to use in web workers or server-side code.
|
|
589
|
+
* All functions are immutable — they never mutate their input arrays.
|
|
590
|
+
*
|
|
591
|
+
* @module find-replace-helpers
|
|
592
|
+
*/
|
|
593
|
+
|
|
594
|
+
/**
|
|
595
|
+
* Identifies a single match of the find query at segment-level precision.
|
|
596
|
+
* Mirrors the React `FindResult` shape.
|
|
597
|
+
*/
|
|
598
|
+
interface FindResult {
|
|
599
|
+
/** Zero-based index of the slide in the slides array. */
|
|
600
|
+
slideIndex: number;
|
|
601
|
+
/** Id of the element that contains the match. */
|
|
602
|
+
elementId: string;
|
|
603
|
+
/** Zero-based index of the text segment within the element's `textSegments`. */
|
|
604
|
+
segmentIndex: number;
|
|
605
|
+
/** Character offset of the match start within the segment text. */
|
|
606
|
+
startOffset: number;
|
|
607
|
+
/** Number of characters matched (equals `query.length`). */
|
|
608
|
+
length: number;
|
|
609
|
+
}
|
|
610
|
+
/** Options passed to search and replace helpers. */
|
|
611
|
+
interface FindOptions {
|
|
612
|
+
/** When `true`, the search is case-sensitive. Defaults to `false`. */
|
|
613
|
+
matchCase?: boolean;
|
|
614
|
+
}
|
|
615
|
+
/** Result returned by {@link replaceInSlides} and {@link replaceMatch}. */
|
|
616
|
+
interface ReplaceResult {
|
|
617
|
+
/** Updated slides (immutable copy; unchanged slides share the original reference). */
|
|
618
|
+
slides: readonly PptxSlide[];
|
|
619
|
+
/** Number of text replacements actually applied. */
|
|
620
|
+
replacements: number;
|
|
621
|
+
}
|
|
622
|
+
/**
|
|
623
|
+
* Search all slides for occurrences of `query` at segment-level precision.
|
|
624
|
+
*
|
|
625
|
+
* - Only elements that pass `hasTextProperties` (text / shape / connector) are
|
|
626
|
+
* searched; tables, smartArt, and groups are skipped (they have no
|
|
627
|
+
* `textSegments`).
|
|
628
|
+
* - Overlapping matches are counted (search advances by 1 character after each
|
|
629
|
+
* hit, not by `query.length`).
|
|
630
|
+
* - Returns an empty array when `query` is empty.
|
|
631
|
+
*/
|
|
632
|
+
declare function findInSlides(slides: readonly PptxSlide[], query: string, opts?: FindOptions): FindResult[];
|
|
633
|
+
/**
|
|
634
|
+
* Apply a set of find-replace substitutions to slides immutably.
|
|
635
|
+
*
|
|
636
|
+
* Replacements inside the same segment are applied in **descending offset**
|
|
637
|
+
* order so that earlier matches are not shifted by later substitutions.
|
|
638
|
+
*
|
|
639
|
+
* Returns the original `slides` reference (no allocation) when `toReplace` is
|
|
640
|
+
* empty.
|
|
641
|
+
*/
|
|
642
|
+
declare function applyFindReplacements(slides: readonly PptxSlide[], toReplace: readonly FindResult[], replacement: string): ReplaceResult;
|
|
643
|
+
/**
|
|
644
|
+
* Replace a single match (identified by its position in `allResults`) and
|
|
645
|
+
* return the updated slides together with the count of replacements applied
|
|
646
|
+
* (always 0 or 1).
|
|
647
|
+
*
|
|
648
|
+
* This is a convenience wrapper around {@link applyFindReplacements} for the
|
|
649
|
+
* "Replace current" action.
|
|
650
|
+
*/
|
|
651
|
+
declare function replaceMatch(slides: readonly PptxSlide[], allResults: readonly FindResult[], matchIndex: number, replacement: string): ReplaceResult;
|
|
652
|
+
/**
|
|
653
|
+
* Replace **all** current matches and return the updated slides.
|
|
654
|
+
*
|
|
655
|
+
* This is a convenience wrapper around {@link applyFindReplacements} for the
|
|
656
|
+
* "Replace All" action.
|
|
657
|
+
*/
|
|
658
|
+
declare function replaceInSlides(slides: readonly PptxSlide[], query: string, replacement: string, opts?: FindOptions): ReplaceResult;
|
|
659
|
+
|
|
460
660
|
/**
|
|
461
661
|
* `LoadContentService` — Angular port of the React `useLoadContent` hook and
|
|
462
662
|
* the Vue `useLoadContent` composable.
|
|
@@ -491,6 +691,8 @@ declare class LoadContentService {
|
|
|
491
691
|
/** Core document properties from `docProps/core.xml`. */
|
|
492
692
|
readonly coreProperties: _angular_core.WritableSignal<PptxCoreProperties | undefined>;
|
|
493
693
|
/** Whether the presentation contains digital signatures. */
|
|
694
|
+
/** Parsed digital signatures (empty when unsigned or parsing fails). */
|
|
695
|
+
readonly signatures: _angular_core.WritableSignal<ParsedSignature[]>;
|
|
494
696
|
readonly hasDigitalSignatures: _angular_core.WritableSignal<boolean>;
|
|
495
697
|
/** Number of digital signatures found. */
|
|
496
698
|
readonly digitalSignatureCount: _angular_core.WritableSignal<number>;
|
|
@@ -736,18 +938,31 @@ declare class PowerPointViewerComponent {
|
|
|
736
938
|
protected readonly zoomPercent: _angular_core.Signal<number>;
|
|
737
939
|
/** Fullscreen presentation-mode overlay visibility. */
|
|
738
940
|
protected readonly presenting: _angular_core.WritableSignal<boolean>;
|
|
941
|
+
/** Presenter-view (speaker) overlay visibility. */
|
|
942
|
+
protected readonly presentingPresenter: _angular_core.WritableSignal<boolean>;
|
|
943
|
+
/** Epoch ms when presenter view started (drives the elapsed timer). */
|
|
944
|
+
protected readonly presenterStartTime: _angular_core.WritableSignal<number | null>;
|
|
739
945
|
/** Slide-sorter grid overlay visibility. */
|
|
740
946
|
protected readonly showSorter: _angular_core.WritableSignal<boolean>;
|
|
741
947
|
/** Speaker-notes strip visibility. */
|
|
742
948
|
protected readonly showNotes: _angular_core.WritableSignal<boolean>;
|
|
743
949
|
/** Find-in-slides bar visibility. */
|
|
744
950
|
protected readonly showFind: _angular_core.WritableSignal<boolean>;
|
|
951
|
+
/** Find-and-replace bar state (edit mode only). */
|
|
952
|
+
protected readonly showFindReplace: _angular_core.WritableSignal<boolean>;
|
|
953
|
+
protected readonly findResults: _angular_core.WritableSignal<readonly FindResult[]>;
|
|
954
|
+
protected readonly findActiveIndex: _angular_core.WritableSignal<number>;
|
|
955
|
+
private findMatchCase;
|
|
745
956
|
/** Active right-docked tool panel (comments / accessibility), or null. */
|
|
746
|
-
protected readonly activePanel: _angular_core.WritableSignal<"comments" | "accessibility" | null>;
|
|
957
|
+
protected readonly activePanel: _angular_core.WritableSignal<"comments" | "accessibility" | "signatures" | null>;
|
|
747
958
|
/** Document-properties (Info) dialog visibility. */
|
|
748
959
|
protected readonly showProperties: _angular_core.WritableSignal<boolean>;
|
|
749
960
|
/** Hyperlink-edit dialog visibility. */
|
|
750
961
|
protected readonly showHyperlink: _angular_core.WritableSignal<boolean>;
|
|
962
|
+
/** Share (collaboration) dialog visibility. */
|
|
963
|
+
protected readonly showShare: _angular_core.WritableSignal<boolean>;
|
|
964
|
+
/** Broadcast dialog visibility. */
|
|
965
|
+
protected readonly showBroadcast: _angular_core.WritableSignal<boolean>;
|
|
751
966
|
/** Local overrides applied to document properties via the Info dialog. */
|
|
752
967
|
private readonly coreOverride;
|
|
753
968
|
/** Comments on the active slide. */
|
|
@@ -781,6 +996,20 @@ declare class PowerPointViewerComponent {
|
|
|
781
996
|
goTo(index: number): void;
|
|
782
997
|
goPrev(): void;
|
|
783
998
|
goNext(): void;
|
|
999
|
+
/** Open the find/replace bar (mutually exclusive with the find-only bar). */
|
|
1000
|
+
protected openFindReplace(): void;
|
|
1001
|
+
/** Re-run the search over the editable deck and refresh the match list. */
|
|
1002
|
+
private refreshFindResults;
|
|
1003
|
+
protected onFindReplaceFind(evt: FindEvent): void;
|
|
1004
|
+
protected onFindReplaceNavigate(dir: 1 | -1): void;
|
|
1005
|
+
protected onFindReplaceReplaceOne(evt: ReplaceEvent): void;
|
|
1006
|
+
protected onFindReplaceReplaceAll(evt: ReplaceEvent): void;
|
|
1007
|
+
/** Start a real-time collaboration session from the share dialog config. */
|
|
1008
|
+
protected onShareStart(config: CollaborationConfig): void;
|
|
1009
|
+
protected onShareStop(): void;
|
|
1010
|
+
/** Start broadcasting (presenter as session owner) from the broadcast config. */
|
|
1011
|
+
protected onBroadcastStart(config: BroadcastConfig): void;
|
|
1012
|
+
protected onBroadcastStop(): void;
|
|
784
1013
|
/** Horizontal-swipe tracking start coordinates (touch begins on the canvas). */
|
|
785
1014
|
private swipeStartX;
|
|
786
1015
|
private swipeStartY;
|
|
@@ -804,10 +1033,14 @@ declare class PowerPointViewerComponent {
|
|
|
804
1033
|
zoomReset(): void;
|
|
805
1034
|
/** Open the fullscreen presentation overlay from the current slide. */
|
|
806
1035
|
present(): void;
|
|
1036
|
+
/** Open the presenter (speaker) view — current+next slide, notes, timer. */
|
|
1037
|
+
presentPresenter(): void;
|
|
1038
|
+
/** Close the presenter view (and any audience overlay it opened). */
|
|
1039
|
+
exitPresenter(): void;
|
|
807
1040
|
/** Toggle the speaker-notes strip. */
|
|
808
1041
|
toggleNotes(): void;
|
|
809
1042
|
/** Toggle a right-docked tool panel (clicking the active one closes it). */
|
|
810
|
-
togglePanel(panel: 'comments' | 'accessibility'): void;
|
|
1043
|
+
togglePanel(panel: 'comments' | 'accessibility' | 'signatures'): void;
|
|
811
1044
|
/** Append a comment to the active slide (one history entry). */
|
|
812
1045
|
onCommentAdd(text: string): void;
|
|
813
1046
|
/** Remove a comment from the active slide. */
|
|
@@ -866,6 +1099,12 @@ declare class PowerPointViewerComponent {
|
|
|
866
1099
|
* slide is restored.
|
|
867
1100
|
*/
|
|
868
1101
|
exportPdf(): Promise<void>;
|
|
1102
|
+
/** Render every slide to a canvas (each made the live stage in turn). */
|
|
1103
|
+
private renderAllSlideCanvases;
|
|
1104
|
+
/** Export every slide as an animated GIF (2s per slide). */
|
|
1105
|
+
exportGif(): Promise<void>;
|
|
1106
|
+
/** Export every slide as a WebM video (3s per slide) via MediaRecorder. */
|
|
1107
|
+
exportVideo(): Promise<void>;
|
|
869
1108
|
static ɵfac: _angular_core.ɵɵFactoryDeclaration<PowerPointViewerComponent, never>;
|
|
870
1109
|
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"; "propertiesChange": "propertiesChange"; }, never, never, true, never>;
|
|
871
1110
|
}
|
|
@@ -896,6 +1135,184 @@ declare function applyMove(start: Box, dx: number, dy: number): Box;
|
|
|
896
1135
|
*/
|
|
897
1136
|
declare function applyResize(start: Box, handle: ResizeHandle, dx: number, dy: number, min?: number): Box;
|
|
898
1137
|
|
|
1138
|
+
/**
|
|
1139
|
+
* Duotone SVG `<filter>` descriptor for Angular templates.
|
|
1140
|
+
*
|
|
1141
|
+
* Ported from:
|
|
1142
|
+
* packages/react/src/viewer/utils/effect-dag-filters.ts (getDuotoneSvgFilterMarkup, hexToRgbUnit)
|
|
1143
|
+
* packages/angular/src/viewer/visual-effects.ts (getDuotoneFilterId, getDuotoneSvgFilter)
|
|
1144
|
+
*
|
|
1145
|
+
* The React package serialises the SVG filter as a raw HTML string. The Angular
|
|
1146
|
+
* package instead returns a **structured descriptor** (`DuotoneFilterDef`) that
|
|
1147
|
+
* the template can render declaratively with `@for` / `@switch`, matching the
|
|
1148
|
+
* `SvgPrimitive` pattern used by `chart-renderer-helpers.ts`.
|
|
1149
|
+
*
|
|
1150
|
+
* @module viewer/duotone-filter
|
|
1151
|
+
*/
|
|
1152
|
+
|
|
1153
|
+
/**
|
|
1154
|
+
* Descriptor for an SVG `<feColorMatrix type="matrix">` primitive.
|
|
1155
|
+
* The `values` string is a space-separated 4×5 colour-transformation matrix.
|
|
1156
|
+
*/
|
|
1157
|
+
interface FeColorMatrixPrimitive {
|
|
1158
|
+
kind: 'feColorMatrix';
|
|
1159
|
+
/** Space-separated 4×5 matrix values (`type="matrix"`). */
|
|
1160
|
+
values: string;
|
|
1161
|
+
/** `color-interpolation-filters` attribute (always `"sRGB"`). */
|
|
1162
|
+
colorInterpolationFilters: 'sRGB';
|
|
1163
|
+
}
|
|
1164
|
+
/**
|
|
1165
|
+
* One channel entry for an `<feComponentTransfer>` child function element.
|
|
1166
|
+
* Maps to `<feFuncR>`, `<feFuncG>`, or `<feFuncB>` with `type="linear"`.
|
|
1167
|
+
*/
|
|
1168
|
+
interface FeComponentTransferChannel {
|
|
1169
|
+
/** Which SVG component-transfer channel this entry corresponds to. */
|
|
1170
|
+
channel: 'R' | 'G' | 'B';
|
|
1171
|
+
/** The `slope` attribute value (highlight − shadow for that channel). */
|
|
1172
|
+
slope: number;
|
|
1173
|
+
/** The `intercept` attribute value (shadow colour for that channel, 0–1). */
|
|
1174
|
+
intercept: number;
|
|
1175
|
+
}
|
|
1176
|
+
/**
|
|
1177
|
+
* Descriptor for an SVG `<feComponentTransfer>` primitive, containing one
|
|
1178
|
+
* linear ramp per RGB channel.
|
|
1179
|
+
*
|
|
1180
|
+
* The template should render:
|
|
1181
|
+
* ```html
|
|
1182
|
+
* <feComponentTransfer>
|
|
1183
|
+
* <feFuncR type="linear" [attr.slope]="ch.slope" [attr.intercept]="ch.intercept" />
|
|
1184
|
+
* …
|
|
1185
|
+
* </feComponentTransfer>
|
|
1186
|
+
* ```
|
|
1187
|
+
*/
|
|
1188
|
+
interface FeComponentTransferPrimitive {
|
|
1189
|
+
kind: 'feComponentTransfer';
|
|
1190
|
+
/** Exactly three entries — R, G, B in that order. */
|
|
1191
|
+
channels: [FeComponentTransferChannel, FeComponentTransferChannel, FeComponentTransferChannel];
|
|
1192
|
+
}
|
|
1193
|
+
/**
|
|
1194
|
+
* A fully structured descriptor for a duotone SVG `<filter>` definition.
|
|
1195
|
+
*
|
|
1196
|
+
* ### Integration guide (for the orchestrator)
|
|
1197
|
+
*
|
|
1198
|
+
* **Step 1 – Render the `<defs>` block.**
|
|
1199
|
+
* Inside the element's host component (or a shared slide-level `<svg>`), emit
|
|
1200
|
+
* a hidden `<svg>` containing one `<filter>` per element that has a duotone:
|
|
1201
|
+
*
|
|
1202
|
+
* ```html
|
|
1203
|
+
* @if (duotone) {
|
|
1204
|
+
* <svg width="0" height="0" style="position:absolute;overflow:hidden" aria-hidden="true">
|
|
1205
|
+
* <defs>
|
|
1206
|
+
* <filter [id]="duotone.id" color-interpolation-filters="sRGB">
|
|
1207
|
+
* @for (p of duotone.primitives; track p.kind) {
|
|
1208
|
+
* @switch (p.kind) {
|
|
1209
|
+
* @case ('feColorMatrix') {
|
|
1210
|
+
* <feColorMatrix type="matrix" [attr.values]="p.values" />
|
|
1211
|
+
* }
|
|
1212
|
+
* @case ('feComponentTransfer') {
|
|
1213
|
+
* <feComponentTransfer>
|
|
1214
|
+
* @for (ch of p.channels; track ch.channel) {
|
|
1215
|
+
* @switch (ch.channel) {
|
|
1216
|
+
* @case ('R') { <feFuncR type="linear" [attr.slope]="ch.slope" [attr.intercept]="ch.intercept" /> }
|
|
1217
|
+
* @case ('G') { <feFuncG type="linear" [attr.slope]="ch.slope" [attr.intercept]="ch.intercept" /> }
|
|
1218
|
+
* @case ('B') { <feFuncB type="linear" [attr.slope]="ch.slope" [attr.intercept]="ch.intercept" /> }
|
|
1219
|
+
* }
|
|
1220
|
+
* }
|
|
1221
|
+
* </feComponentTransfer>
|
|
1222
|
+
* }
|
|
1223
|
+
* }
|
|
1224
|
+
* }
|
|
1225
|
+
* </filter>
|
|
1226
|
+
* </defs>
|
|
1227
|
+
* </svg>
|
|
1228
|
+
* }
|
|
1229
|
+
* ```
|
|
1230
|
+
*
|
|
1231
|
+
* **Step 2 – Apply the CSS `filter` reference.**
|
|
1232
|
+
* In `element-style.ts` (or the image host component), when `duotone` is
|
|
1233
|
+
* defined, append `duotone.cssFilter` to the element's `filter` CSS property
|
|
1234
|
+
* *instead of* stripping the `url(#…)` reference as `getShapeFillStrokeStyle`
|
|
1235
|
+
* currently does. Example integration in `getShapeFillStrokeStyle`:
|
|
1236
|
+
*
|
|
1237
|
+
* ```ts
|
|
1238
|
+
* const duotone = buildDuotoneFilter(el);
|
|
1239
|
+
* const dagFilter = getEffectFilterCss(el.shapeStyle, el.id);
|
|
1240
|
+
* if (dagFilter) {
|
|
1241
|
+
* // duotone url(#…) is now meaningful — keep it
|
|
1242
|
+
* style['filter'] = dagFilter;
|
|
1243
|
+
* } else if (duotone) {
|
|
1244
|
+
* style['filter'] = duotone.cssFilter;
|
|
1245
|
+
* }
|
|
1246
|
+
* // Expose duotone so the template can render the <defs> block:
|
|
1247
|
+
* return { style, duotone };
|
|
1248
|
+
* ```
|
|
1249
|
+
*/
|
|
1250
|
+
interface DuotoneFilterDef {
|
|
1251
|
+
/**
|
|
1252
|
+
* Stable SVG `filter` element `id`, derived deterministically from the
|
|
1253
|
+
* element id. Format: `dag-duotone-<elementId>`.
|
|
1254
|
+
*/
|
|
1255
|
+
id: string;
|
|
1256
|
+
/**
|
|
1257
|
+
* Ordered list of SVG filter primitives that make up the `<filter>` body.
|
|
1258
|
+
* Always contains exactly two entries:
|
|
1259
|
+
* 0. `feColorMatrix` — BT.709 luminance-to-grayscale matrix
|
|
1260
|
+
* 1. `feComponentTransfer` — per-channel linear ramp (shadow → highlight)
|
|
1261
|
+
*/
|
|
1262
|
+
primitives: [FeColorMatrixPrimitive, FeComponentTransferPrimitive];
|
|
1263
|
+
/**
|
|
1264
|
+
* Ready-to-use CSS `filter` function string.
|
|
1265
|
+
* Example: `"url(#dag-duotone-shape1)"`.
|
|
1266
|
+
* Append this to the element's existing `filter` CSS value.
|
|
1267
|
+
*/
|
|
1268
|
+
cssFilter: string;
|
|
1269
|
+
/**
|
|
1270
|
+
* The raw shadow colour (`color1`) in 6-digit hex, preserved for tests and
|
|
1271
|
+
* debugging without re-parsing the matrix.
|
|
1272
|
+
*/
|
|
1273
|
+
shadowHex: string;
|
|
1274
|
+
/**
|
|
1275
|
+
* The raw highlight colour (`color2`) in 6-digit hex, preserved for tests and
|
|
1276
|
+
* debugging without re-parsing the matrix.
|
|
1277
|
+
*/
|
|
1278
|
+
highlightHex: string;
|
|
1279
|
+
}
|
|
1280
|
+
/**
|
|
1281
|
+
* Build a stable SVG filter `id` for a duotone effect on the given element.
|
|
1282
|
+
*
|
|
1283
|
+
* Matches the format used by `getDuotoneFilterId` in `visual-effects.ts` so
|
|
1284
|
+
* that the `url(#…)` reference emitted by `getEffectDagCssFilter` points to
|
|
1285
|
+
* the correct `<filter>` definition.
|
|
1286
|
+
*
|
|
1287
|
+
* @param elementId - The element's `id` from `PptxElement.id`.
|
|
1288
|
+
* @returns A CSS-identifier-safe string (no spaces, starts with a letter).
|
|
1289
|
+
*/
|
|
1290
|
+
declare function buildDuotoneFilterId(elementId: string): string;
|
|
1291
|
+
/**
|
|
1292
|
+
* Derive a fully structured duotone `<filter>` descriptor from a
|
|
1293
|
+
* `PptxElement`.
|
|
1294
|
+
*
|
|
1295
|
+
* The function reads `element.shapeStyle.dagDuotone` — the parsed
|
|
1296
|
+
* `<a:duotone>` colour pair populated by the core parser. Returns
|
|
1297
|
+
* `undefined` when the element carries no duotone effect.
|
|
1298
|
+
*
|
|
1299
|
+
* ### Colour math
|
|
1300
|
+
* 1. Convert to grayscale using BT.709 luminance weights (feColorMatrix).
|
|
1301
|
+
* 2. Map grayscale 0 → `color1` (shadow) and 1 → `color2` (highlight) via
|
|
1302
|
+
* per-channel linear ramps (feComponentTransfer / feFuncR|G|B):
|
|
1303
|
+
* ```
|
|
1304
|
+
* slope = highlight_channel − shadow_channel
|
|
1305
|
+
* intercept = shadow_channel
|
|
1306
|
+
* ```
|
|
1307
|
+
* At luminance 0: `output = intercept = shadow`.
|
|
1308
|
+
* At luminance 1: `output = slope + intercept = highlight`.
|
|
1309
|
+
*
|
|
1310
|
+
* @param element - Any `PptxElement`; elements without `shapeStyle` or
|
|
1311
|
+
* `dagDuotone` return `undefined`.
|
|
1312
|
+
* @returns A {@link DuotoneFilterDef} or `undefined`.
|
|
1313
|
+
*/
|
|
1314
|
+
declare function buildDuotoneFilter(element: PptxElement): DuotoneFilterDef | undefined;
|
|
1315
|
+
|
|
899
1316
|
/**
|
|
900
1317
|
* Basic, framework-agnostic style computation for slide elements, returning
|
|
901
1318
|
* `[ngStyle]`-compatible maps.
|
|
@@ -911,6 +1328,13 @@ declare function applyResize(start: Box, handle: ResizeHandle, dx: number, dy: n
|
|
|
911
1328
|
* return type (CSS map shape) differs per framework — so a future refactor
|
|
912
1329
|
* could hoist a neutral core into `pptx-viewer-shared`.
|
|
913
1330
|
*/
|
|
1331
|
+
/**
|
|
1332
|
+
* Resolve the duotone SVG `<filter>` descriptor for an element, or `undefined`
|
|
1333
|
+
* when it carries no duotone image effect. The renderer pairs this with the
|
|
1334
|
+
* `filter: url(#…)` set in {@link getShapeFillStrokeStyle} by injecting the
|
|
1335
|
+
* matching `<filter>` def into a hidden `<defs>` block.
|
|
1336
|
+
*/
|
|
1337
|
+
declare function getDuotoneFilterDef(el: PptxElement): DuotoneFilterDef | undefined;
|
|
914
1338
|
/** `[ngStyle]`-compatible style map. */
|
|
915
1339
|
type StyleMap = Record<string, string | number>;
|
|
916
1340
|
/**
|
|
@@ -1049,6 +1473,17 @@ declare class SlideCanvasComponent {
|
|
|
1049
1473
|
*/
|
|
1050
1474
|
private recomputeFit;
|
|
1051
1475
|
readonly elements: _angular_core.Signal<PptxElement[]>;
|
|
1476
|
+
/**
|
|
1477
|
+
* Obstacle rects (absolute slide coords) for connector A* routing: every
|
|
1478
|
+
* non-connector element with a positive footprint. Bent connectors detour
|
|
1479
|
+
* around these instead of cutting straight through neighbouring shapes.
|
|
1480
|
+
*/
|
|
1481
|
+
readonly connectorObstacles: _angular_core.Signal<{
|
|
1482
|
+
x: number;
|
|
1483
|
+
y: number;
|
|
1484
|
+
width: number;
|
|
1485
|
+
height: number;
|
|
1486
|
+
}[]>;
|
|
1052
1487
|
/** Bounding boxes (stage coords) for the selected elements. */
|
|
1053
1488
|
readonly selectionBoxes: _angular_core.Signal<{
|
|
1054
1489
|
id: string;
|
|
@@ -1099,6 +1534,86 @@ declare class SlideCanvasComponent {
|
|
|
1099
1534
|
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>;
|
|
1100
1535
|
}
|
|
1101
1536
|
|
|
1537
|
+
/**
|
|
1538
|
+
* Pure, framework-agnostic A* orthogonal connector router.
|
|
1539
|
+
*
|
|
1540
|
+
* Angular port of the React connector-router suite:
|
|
1541
|
+
* packages/react/src/viewer/utils/connector-router.ts
|
|
1542
|
+
* packages/react/src/viewer/utils/connector-router-graph.ts
|
|
1543
|
+
* packages/react/src/viewer/utils/connector-router-astar.ts
|
|
1544
|
+
*
|
|
1545
|
+
* All logic is consolidated into this single file (no barrel split needed for
|
|
1546
|
+
* an Angular helper module). Compatible with `connector-path.ts` / the
|
|
1547
|
+
* `ConnectorRendererComponent`: pass the returned `Point[]` to
|
|
1548
|
+
* `waypointsToPathD()` to obtain the SVG `d` attribute string that the
|
|
1549
|
+
* component renders on a `<path>`.
|
|
1550
|
+
*
|
|
1551
|
+
* Constraints kept from the React source:
|
|
1552
|
+
* - No `any`.
|
|
1553
|
+
* - No `String.prototype.replaceAll` / named regex capture groups.
|
|
1554
|
+
* - No `Math.random` / `Date` — fully deterministic.
|
|
1555
|
+
* - No Angular / Vue / React imports.
|
|
1556
|
+
*/
|
|
1557
|
+
/** A 2-D point in pixel space. */
|
|
1558
|
+
interface Point {
|
|
1559
|
+
x: number;
|
|
1560
|
+
y: number;
|
|
1561
|
+
}
|
|
1562
|
+
/** An axis-aligned bounding rectangle in pixel space. */
|
|
1563
|
+
interface Rect {
|
|
1564
|
+
x: number;
|
|
1565
|
+
y: number;
|
|
1566
|
+
width: number;
|
|
1567
|
+
height: number;
|
|
1568
|
+
}
|
|
1569
|
+
/** Options for {@link routeOrthogonalConnector}. */
|
|
1570
|
+
interface OrthogonalRouterOptions {
|
|
1571
|
+
/** Start point (absolute pixel coordinates). */
|
|
1572
|
+
start: Point;
|
|
1573
|
+
/** End point (absolute pixel coordinates). */
|
|
1574
|
+
end: Point;
|
|
1575
|
+
/** Obstacle bounding boxes the path must avoid. */
|
|
1576
|
+
obstacles: ReadonlyArray<Rect>;
|
|
1577
|
+
/**
|
|
1578
|
+
* Width of the routing canvas (used to clip candidate nodes to valid area).
|
|
1579
|
+
* Defaults to a large sentinel when omitted.
|
|
1580
|
+
*/
|
|
1581
|
+
canvasWidth?: number;
|
|
1582
|
+
/**
|
|
1583
|
+
* Height of the routing canvas.
|
|
1584
|
+
* Defaults to a large sentinel when omitted.
|
|
1585
|
+
*/
|
|
1586
|
+
canvasHeight?: number;
|
|
1587
|
+
/**
|
|
1588
|
+
* Padding (in pixels) expanded around each obstacle to keep the path
|
|
1589
|
+
* away from obstacle edges. Default: {@link ROUTING_PADDING_DEFAULT}.
|
|
1590
|
+
*/
|
|
1591
|
+
padding?: number;
|
|
1592
|
+
}
|
|
1593
|
+
/**
|
|
1594
|
+
* Route an orthogonal connector between `start` and `end`, avoiding all
|
|
1595
|
+
* `obstacles`. Returns a list of waypoints (including the start and end
|
|
1596
|
+
* points) that form an axis-aligned polyline.
|
|
1597
|
+
*
|
|
1598
|
+
* Strategy (fast-path first, A* as fallback):
|
|
1599
|
+
* 1. No obstacles → return `[start, end]` directly.
|
|
1600
|
+
* 2. Direct line clear → return `[start, end]`.
|
|
1601
|
+
* 3. Single horizontal elbow (`start → (end.x, start.y) → end`) clear → use it.
|
|
1602
|
+
* 4. Single vertical elbow (`start → (start.x, end.y) → end`) clear → use it.
|
|
1603
|
+
* 5. Full A* search on the navigation graph.
|
|
1604
|
+
*/
|
|
1605
|
+
declare function routeOrthogonalConnector(start: Point, end: Point, obstacles: ReadonlyArray<Rect>, opts?: Pick<OrthogonalRouterOptions, 'canvasWidth' | 'canvasHeight' | 'padding'>): Point[];
|
|
1606
|
+
/**
|
|
1607
|
+
* Convert an array of waypoints to an SVG `path` `d` attribute string.
|
|
1608
|
+
*
|
|
1609
|
+
* Returns an empty string for an empty waypoint array, `"M x y"` for a
|
|
1610
|
+
* single point, and `"M x y L x1 y1 …"` for a polyline.
|
|
1611
|
+
*
|
|
1612
|
+
* This output is compatible with the `pathD` field on `ConnectorGeometry`
|
|
1613
|
+
* from `connector-path.ts` and can be bound directly to a `<path [attr.d]>`.
|
|
1614
|
+
*/
|
|
1615
|
+
declare function waypointsToPathD(waypoints: ReadonlyArray<Point>): string;
|
|
1616
|
+
|
|
1102
1617
|
interface TextRun {
|
|
1103
1618
|
text: string;
|
|
1104
1619
|
style: StyleMap;
|
|
@@ -1146,6 +1661,12 @@ declare class ElementRendererComponent {
|
|
|
1146
1661
|
readonly element: _angular_core.InputSignal<PptxElement>;
|
|
1147
1662
|
readonly mediaDataUrls: _angular_core.InputSignal<Map<string, string>>;
|
|
1148
1663
|
readonly zIndex: _angular_core.InputSignal<number>;
|
|
1664
|
+
/** Obstacle rects (absolute slide coords) for connector A* routing. */
|
|
1665
|
+
readonly obstacles: _angular_core.InputSignal<readonly Rect[]>;
|
|
1666
|
+
readonly canvasWidth: _angular_core.InputSignal<number>;
|
|
1667
|
+
readonly canvasHeight: _angular_core.InputSignal<number>;
|
|
1668
|
+
/** Duotone SVG `<filter>` descriptor for this element, if any. */
|
|
1669
|
+
readonly duotoneFilter: _angular_core.Signal<pptx_angular_viewer.DuotoneFilterDef | undefined>;
|
|
1149
1670
|
readonly containerStyle: _angular_core.Signal<StyleMap>;
|
|
1150
1671
|
readonly shapeContainerStyle: _angular_core.Signal<StyleMap>;
|
|
1151
1672
|
readonly textStyle: _angular_core.Signal<StyleMap>;
|
|
@@ -1158,7 +1679,7 @@ declare class ElementRendererComponent {
|
|
|
1158
1679
|
readonly placeholderLabel: _angular_core.Signal<string>;
|
|
1159
1680
|
private segmentStyle;
|
|
1160
1681
|
static ɵfac: _angular_core.ɵɵFactoryDeclaration<ElementRendererComponent, never>;
|
|
1161
|
-
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>;
|
|
1682
|
+
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; }; "obstacles": { "alias": "obstacles"; "required": false; "isSignal": true; }; "canvasWidth": { "alias": "canvasWidth"; "required": false; "isSignal": true; }; "canvasHeight": { "alias": "canvasHeight"; "required": false; "isSignal": true; }; }, {}, never, never, true, never>;
|
|
1162
1683
|
}
|
|
1163
1684
|
|
|
1164
1685
|
/**
|
|
@@ -1172,6 +1693,17 @@ declare class ElementRendererComponent {
|
|
|
1172
1693
|
* `ConnectorElementRenderer` path logic (basic straight-line subset).
|
|
1173
1694
|
*/
|
|
1174
1695
|
|
|
1696
|
+
/**
|
|
1697
|
+
* Optional obstacle-avoidance routing context for bent connectors. When
|
|
1698
|
+
* supplied with a non-empty obstacle list, a bent connector's elbow path is
|
|
1699
|
+
* replaced by an A* orthogonal route that detours around the obstacle rects
|
|
1700
|
+
* (absolute slide coordinates). Straight/curved connectors ignore this.
|
|
1701
|
+
*/
|
|
1702
|
+
interface ConnectorRouting {
|
|
1703
|
+
obstacles: ReadonlyArray<Rect>;
|
|
1704
|
+
canvasWidth: number;
|
|
1705
|
+
canvasHeight: number;
|
|
1706
|
+
}
|
|
1175
1707
|
/** Shape description for a SVG `<marker>` element (viewBox 0 0 10 10). */
|
|
1176
1708
|
interface MarkerShape {
|
|
1177
1709
|
shape: 'path' | 'circle';
|
|
@@ -1216,21 +1748,84 @@ interface ConnectorGeometry {
|
|
|
1216
1748
|
* is baked into the endpoints (not a CSS transform) so arrowheads point the
|
|
1217
1749
|
* right way.
|
|
1218
1750
|
*
|
|
1219
|
-
*
|
|
1220
|
-
*
|
|
1751
|
+
* Renders straight (`<line>`), bent (elbow) and curved (Bézier) connectors via
|
|
1752
|
+
* `connector-path.ts`. When obstacle rects are supplied (`obstacles` input,
|
|
1753
|
+
* absolute slide coords), bent connectors are routed around them with an A*
|
|
1754
|
+
* orthogonal router. A connector's optional text label is painted on top via
|
|
1755
|
+
* `ConnectorTextOverlayComponent`.
|
|
1221
1756
|
*
|
|
1222
|
-
*
|
|
1223
|
-
* (
|
|
1224
|
-
*
|
|
1757
|
+
* All path/style math lives in `connector-path.ts` / `connector-routing.ts`
|
|
1758
|
+
* (pure TS, no Angular dependency) so it can be unit-tested without TestBed.
|
|
1759
|
+
*
|
|
1760
|
+
* Not yet ported (TODO, see PORTING.md): compound (double/triple) lines, line
|
|
1761
|
+
* shadows/glow.
|
|
1225
1762
|
*/
|
|
1226
1763
|
declare class ConnectorRendererComponent {
|
|
1227
1764
|
readonly element: _angular_core.InputSignal<PptxElement>;
|
|
1228
1765
|
readonly zIndex: _angular_core.InputSignal<number>;
|
|
1766
|
+
/** Obstacle rects (absolute slide coords) for A* routing of bent connectors. */
|
|
1767
|
+
readonly obstacles: _angular_core.InputSignal<readonly Rect[]>;
|
|
1768
|
+
readonly canvasWidth: _angular_core.InputSignal<number>;
|
|
1769
|
+
readonly canvasHeight: _angular_core.InputSignal<number>;
|
|
1229
1770
|
/** All derived geometry, recomputed on every input change. */
|
|
1230
1771
|
readonly geo: _angular_core.Signal<ConnectorGeometry>;
|
|
1231
1772
|
readonly viewBox: _angular_core.Signal<string>;
|
|
1773
|
+
private readonly textProps;
|
|
1774
|
+
readonly connectorText: _angular_core.Signal<string | undefined>;
|
|
1775
|
+
readonly connectorSegments: _angular_core.Signal<TextSegment[] | undefined>;
|
|
1776
|
+
readonly connectorTextStyle: _angular_core.Signal<TextStyle | undefined>;
|
|
1232
1777
|
static ɵfac: _angular_core.ɵɵFactoryDeclaration<ConnectorRendererComponent, never>;
|
|
1233
|
-
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>;
|
|
1778
|
+
static ɵcmp: _angular_core.ɵɵComponentDeclaration<ConnectorRendererComponent, "pptx-connector-renderer", never, { "element": { "alias": "element"; "required": true; "isSignal": true; }; "zIndex": { "alias": "zIndex"; "required": false; "isSignal": true; }; "obstacles": { "alias": "obstacles"; "required": false; "isSignal": true; }; "canvasWidth": { "alias": "canvasWidth"; "required": false; "isSignal": true; }; "canvasHeight": { "alias": "canvasHeight"; "required": false; "isSignal": true; }; }, {}, never, never, true, never>;
|
|
1779
|
+
}
|
|
1780
|
+
|
|
1781
|
+
/** A `TextSegment` pre-processed with its computed inline style. */
|
|
1782
|
+
interface StyledSegment {
|
|
1783
|
+
text: string;
|
|
1784
|
+
style: string;
|
|
1785
|
+
}
|
|
1786
|
+
/**
|
|
1787
|
+
* `<pptx-connector-text-overlay>` — renders a connector's text label.
|
|
1788
|
+
*
|
|
1789
|
+
* **Usage** (inside `ConnectorRendererComponent`'s host wrapper `<div>`):
|
|
1790
|
+
* ```html
|
|
1791
|
+
* @if (hasLabel()) {
|
|
1792
|
+
* <pptx-connector-text-overlay
|
|
1793
|
+
* [text]="element().text"
|
|
1794
|
+
* [segments]="element().textSegments"
|
|
1795
|
+
* [textStyle]="element().textStyle"
|
|
1796
|
+
* />
|
|
1797
|
+
* }
|
|
1798
|
+
* ```
|
|
1799
|
+
*
|
|
1800
|
+
* All inputs are optional; the component renders nothing when `text` is falsy
|
|
1801
|
+
* or `segments` is empty.
|
|
1802
|
+
*/
|
|
1803
|
+
declare class ConnectorTextOverlayComponent {
|
|
1804
|
+
/**
|
|
1805
|
+
* Trimmed plain-text label. When falsy the overlay is not rendered.
|
|
1806
|
+
* This is the `text` property from `ConnectorPptxElement`.
|
|
1807
|
+
*/
|
|
1808
|
+
readonly text: _angular_core.InputSignal<string | undefined>;
|
|
1809
|
+
/**
|
|
1810
|
+
* Per-run rich-text segments from `ConnectorPptxElement.textSegments`.
|
|
1811
|
+
* When absent or empty the overlay is not rendered.
|
|
1812
|
+
*/
|
|
1813
|
+
readonly segments: _angular_core.InputSignal<readonly TextSegment[] | undefined>;
|
|
1814
|
+
/**
|
|
1815
|
+
* Paragraph-level text style from `ConnectorPptxElement.textStyle`.
|
|
1816
|
+
* Controls alignment, default font, colour, etc.
|
|
1817
|
+
*/
|
|
1818
|
+
readonly textStyle: _angular_core.InputSignal<TextStyle | undefined>;
|
|
1819
|
+
/** True when there is a non-empty label to display. */
|
|
1820
|
+
readonly hasText: _angular_core.Signal<boolean>;
|
|
1821
|
+
/** Inline style for the outer flex container. */
|
|
1822
|
+
readonly containerStyle: _angular_core.Signal<string>;
|
|
1823
|
+
/** Inline style for the inner paragraph block. */
|
|
1824
|
+
readonly blockStyle: _angular_core.Signal<string>;
|
|
1825
|
+
/** Pre-computed segments with their individual inline style strings. */
|
|
1826
|
+
readonly styledSegments: _angular_core.Signal<StyledSegment[]>;
|
|
1827
|
+
static ɵfac: _angular_core.ɵɵFactoryDeclaration<ConnectorTextOverlayComponent, never>;
|
|
1828
|
+
static ɵcmp: _angular_core.ɵɵComponentDeclaration<ConnectorTextOverlayComponent, "pptx-connector-text-overlay", never, { "text": { "alias": "text"; "required": false; "isSignal": true; }; "segments": { "alias": "segments"; "required": false; "isSignal": true; }; "textStyle": { "alias": "textStyle"; "required": false; "isSignal": true; }; }, {}, never, never, true, never>;
|
|
1234
1829
|
}
|
|
1235
1830
|
|
|
1236
1831
|
/**
|
|
@@ -1361,9 +1956,11 @@ declare class TableRendererComponent {
|
|
|
1361
1956
|
* area / area3D -> polygon fill + polyline
|
|
1362
1957
|
* pie / doughnut / pie3D / ofPie -> arc paths
|
|
1363
1958
|
* scatter -> circle dots
|
|
1959
|
+
* bubble -> circle dots sized by a 3rd series
|
|
1960
|
+
* radar / radar3D -> polar polygons + spokes
|
|
1364
1961
|
*
|
|
1365
1962
|
* Deferred (fallback box rendered instead):
|
|
1366
|
-
*
|
|
1963
|
+
* stock, waterfall, combo, surface, treemap, sunburst,
|
|
1367
1964
|
* funnel, boxWhisker, histogram, regionMap, bar3D (complex 3-D shading),
|
|
1368
1965
|
* error bars, trendlines, secondary axes, data tables.
|
|
1369
1966
|
*
|
|
@@ -1426,12 +2023,21 @@ interface SvgText {
|
|
|
1426
2023
|
dominantBaseline?: string;
|
|
1427
2024
|
opacity?: number;
|
|
1428
2025
|
}
|
|
2026
|
+
interface SvgPolygon {
|
|
2027
|
+
kind: 'polygon';
|
|
2028
|
+
points: string;
|
|
2029
|
+
fill: string;
|
|
2030
|
+
stroke: string;
|
|
2031
|
+
strokeWidth: number;
|
|
2032
|
+
opacity?: number;
|
|
2033
|
+
dashArray?: string;
|
|
2034
|
+
}
|
|
1429
2035
|
interface SvgAreaGradient {
|
|
1430
2036
|
kind: 'areaGradient';
|
|
1431
2037
|
id: string;
|
|
1432
2038
|
color: string;
|
|
1433
2039
|
}
|
|
1434
|
-
type SvgPrimitive = SvgRect | SvgPath | SvgPolyline | SvgCircle | SvgLine | SvgText | SvgAreaGradient;
|
|
2040
|
+
type SvgPrimitive = SvgRect | SvgPath | SvgPolyline | SvgCircle | SvgLine | SvgPolygon | SvgText | SvgAreaGradient;
|
|
1435
2041
|
interface LegendEntry {
|
|
1436
2042
|
color: string;
|
|
1437
2043
|
label: string;
|
|
@@ -1465,6 +2071,7 @@ declare class ChartRendererComponent {
|
|
|
1465
2071
|
asPolyline(p: SvgPrimitive): SvgPolyline;
|
|
1466
2072
|
asCircle(p: SvgPrimitive): SvgCircle;
|
|
1467
2073
|
asLine(p: SvgPrimitive): SvgLine;
|
|
2074
|
+
asPolygon(p: SvgPrimitive): SvgPolygon;
|
|
1468
2075
|
asText(p: SvgPrimitive): SvgText;
|
|
1469
2076
|
static ɵfac: _angular_core.ɵɵFactoryDeclaration<ChartRendererComponent, never>;
|
|
1470
2077
|
static ɵcmp: _angular_core.ɵɵComponentDeclaration<ChartRendererComponent, "pptx-chart-renderer", never, { "element": { "alias": "element"; "required": true; "isSignal": true; }; }, {}, never, never, true, never>;
|
|
@@ -1880,6 +2487,14 @@ declare class PresentationOverlayComponent implements OnInit, OnDestroy {
|
|
|
1880
2487
|
readonly closed: _angular_core.OutputEmitterRef<void>;
|
|
1881
2488
|
/** Zero-based index into `slides()`. */
|
|
1882
2489
|
protected readonly currentIndex: _angular_core.WritableSignal<number>;
|
|
2490
|
+
/**
|
|
2491
|
+
* Active slide-transition animation: the outgoing slide + the incoming
|
|
2492
|
+
* slide's transition, played over the new slide. Cleared on completion.
|
|
2493
|
+
*/
|
|
2494
|
+
protected readonly activeTransition: _angular_core.WritableSignal<{
|
|
2495
|
+
outgoing: PptxSlide;
|
|
2496
|
+
transition: PptxSlideTransition;
|
|
2497
|
+
} | null>;
|
|
1883
2498
|
/** Viewport dimensions — updated on resize. */
|
|
1884
2499
|
private readonly viewportW;
|
|
1885
2500
|
private readonly viewportH;
|
|
@@ -2118,6 +2733,14 @@ declare class InspectorPanelComponent {
|
|
|
2118
2733
|
protected readonly currentBold: _angular_core.Signal<boolean>;
|
|
2119
2734
|
protected readonly currentItalic: _angular_core.Signal<boolean>;
|
|
2120
2735
|
protected readonly currentUnderline: _angular_core.Signal<boolean>;
|
|
2736
|
+
/** The selected element narrowed to a table, or undefined. */
|
|
2737
|
+
protected readonly tableEl: _angular_core.Signal<TablePptxElement | undefined>;
|
|
2738
|
+
/** The selected element narrowed to a chart, or undefined. */
|
|
2739
|
+
protected readonly chartEl: _angular_core.Signal<ChartPptxElement | undefined>;
|
|
2740
|
+
/** Commit a partial-element patch from an advanced sub-panel as one history entry. */
|
|
2741
|
+
protected onPatch(patch: Partial<PptxElement>): void;
|
|
2742
|
+
/** Commit a fully-replaced element (table/chart data editors) as one history entry. */
|
|
2743
|
+
protected onElementReplace(updated: PptxElement): void;
|
|
2121
2744
|
protected onPositionChange(event: Event, axis: 'x' | 'y'): void;
|
|
2122
2745
|
protected onSizeChange(event: Event, dim: 'width' | 'height'): void;
|
|
2123
2746
|
protected onRotationChange(event: Event): void;
|
|
@@ -2133,6 +2756,281 @@ declare class InspectorPanelComponent {
|
|
|
2133
2756
|
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>;
|
|
2134
2757
|
}
|
|
2135
2758
|
|
|
2759
|
+
/**
|
|
2760
|
+
* gradient-picker-helpers.ts — Pure (no Angular) helpers for GradientPickerComponent.
|
|
2761
|
+
*
|
|
2762
|
+
* Ported from / models the patterns in:
|
|
2763
|
+
* packages/react/src/viewer/components/inspector/FillAdvancedControls.tsx
|
|
2764
|
+
* packages/react/src/viewer/components/inspector/FillStrokeProperties.tsx
|
|
2765
|
+
* packages/angular/src/viewer/color-gradient.ts
|
|
2766
|
+
*
|
|
2767
|
+
* Readers extract current gradient values from a PptxElement (falling back to
|
|
2768
|
+
* sensible defaults), and patch-builders produce shallow-merge-ready
|
|
2769
|
+
* Partial<PptxElement> objects safe to pass to EditorStateService.updateElement.
|
|
2770
|
+
*
|
|
2771
|
+
* No `any` — every type is concrete or `unknown` + narrowed.
|
|
2772
|
+
*/
|
|
2773
|
+
|
|
2774
|
+
/** A single gradient stop, mirroring the ShapeStyle array item shape. */
|
|
2775
|
+
interface GradientStop {
|
|
2776
|
+
color: string;
|
|
2777
|
+
position: number;
|
|
2778
|
+
opacity?: number;
|
|
2779
|
+
}
|
|
2780
|
+
/** The editable gradient state surfaced to the component. */
|
|
2781
|
+
interface GradientState {
|
|
2782
|
+
type: 'linear' | 'radial';
|
|
2783
|
+
/** Angle in degrees (only meaningful for linear). */
|
|
2784
|
+
angle: number;
|
|
2785
|
+
stops: GradientStop[];
|
|
2786
|
+
}
|
|
2787
|
+
|
|
2788
|
+
declare class GradientPickerComponent {
|
|
2789
|
+
/** The element whose gradient fill is being edited. */
|
|
2790
|
+
readonly element: _angular_core.InputSignal<PptxElement>;
|
|
2791
|
+
/**
|
|
2792
|
+
* Emits a Partial<PptxElement> patch each time the user commits a change.
|
|
2793
|
+
* The orchestrator (InspectorPanelComponent or a wrapper) should call
|
|
2794
|
+
* EditorStateService.updateElement(slideIndex, element().id, patch).
|
|
2795
|
+
*/
|
|
2796
|
+
readonly patch: _angular_core.OutputEmitterRef<Partial<PptxElement>>;
|
|
2797
|
+
/** Derived gradient state from the current element. */
|
|
2798
|
+
protected readonly state: _angular_core.Signal<GradientState>;
|
|
2799
|
+
/** CSS gradient string for the preview strip. */
|
|
2800
|
+
protected readonly previewCss: _angular_core.Signal<string>;
|
|
2801
|
+
protected onTypeChange(event: Event): void;
|
|
2802
|
+
protected onAngleChange(event: Event): void;
|
|
2803
|
+
protected onStopColorChange(event: Event, index: number): void;
|
|
2804
|
+
protected onStopPositionChange(event: Event, index: number): void;
|
|
2805
|
+
protected onStopOpacityChange(event: Event, index: number): void;
|
|
2806
|
+
protected onRemoveStop(index: number): void;
|
|
2807
|
+
protected onAddStop(): void;
|
|
2808
|
+
private emit;
|
|
2809
|
+
static ɵfac: _angular_core.ɵɵFactoryDeclaration<GradientPickerComponent, never>;
|
|
2810
|
+
static ɵcmp: _angular_core.ɵɵComponentDeclaration<GradientPickerComponent, "pptx-gradient-picker", never, { "element": { "alias": "element"; "required": true; "isSignal": true; }; }, { "patch": "patch"; }, never, never, true, never>;
|
|
2811
|
+
}
|
|
2812
|
+
|
|
2813
|
+
/**
|
|
2814
|
+
* effects-helpers.ts — Pure (no Angular) helpers for EffectsPanelComponent.
|
|
2815
|
+
*
|
|
2816
|
+
* Ported from / models the patterns in:
|
|
2817
|
+
* packages/react/src/viewer/components/inspector/fill-stroke-effect-configs.ts
|
|
2818
|
+
* packages/react/src/viewer/components/inspector/fill-stroke-visual-configs.ts
|
|
2819
|
+
* packages/angular/src/viewer/visual-effects.ts
|
|
2820
|
+
* packages/angular/src/viewer/inspector-helpers.ts
|
|
2821
|
+
*
|
|
2822
|
+
* Readers extract effect values from a PptxElement (with sensible defaults),
|
|
2823
|
+
* and patch-builders produce shallow-merge-ready Partial<PptxElement> objects
|
|
2824
|
+
* for EditorStateService.updateElement.
|
|
2825
|
+
*
|
|
2826
|
+
* @module viewer/effects-helpers
|
|
2827
|
+
*/
|
|
2828
|
+
|
|
2829
|
+
/** Editable outer shadow state. */
|
|
2830
|
+
interface OuterShadowState {
|
|
2831
|
+
enabled: boolean;
|
|
2832
|
+
color: string;
|
|
2833
|
+
opacity: number;
|
|
2834
|
+
blur: number;
|
|
2835
|
+
/** Direction angle in degrees. */
|
|
2836
|
+
angle: number;
|
|
2837
|
+
/** Distance in px. */
|
|
2838
|
+
distance: number;
|
|
2839
|
+
}
|
|
2840
|
+
/** Editable inner shadow state. */
|
|
2841
|
+
interface InnerShadowState {
|
|
2842
|
+
enabled: boolean;
|
|
2843
|
+
color: string;
|
|
2844
|
+
opacity: number;
|
|
2845
|
+
blur: number;
|
|
2846
|
+
offsetX: number;
|
|
2847
|
+
offsetY: number;
|
|
2848
|
+
}
|
|
2849
|
+
/** Editable glow state. */
|
|
2850
|
+
interface GlowState {
|
|
2851
|
+
enabled: boolean;
|
|
2852
|
+
color: string;
|
|
2853
|
+
radius: number;
|
|
2854
|
+
opacity: number;
|
|
2855
|
+
}
|
|
2856
|
+
/** Editable reflection state. */
|
|
2857
|
+
interface ReflectionState {
|
|
2858
|
+
enabled: boolean;
|
|
2859
|
+
blurRadius: number;
|
|
2860
|
+
startOpacity: number;
|
|
2861
|
+
endOpacity: number;
|
|
2862
|
+
distance: number;
|
|
2863
|
+
direction: number;
|
|
2864
|
+
}
|
|
2865
|
+
/** Editable soft-edge (blur) state. */
|
|
2866
|
+
interface SoftEdgeState {
|
|
2867
|
+
enabled: boolean;
|
|
2868
|
+
radius: number;
|
|
2869
|
+
}
|
|
2870
|
+
/** All effect values collected for the panel. */
|
|
2871
|
+
interface EffectsState {
|
|
2872
|
+
outerShadow: OuterShadowState;
|
|
2873
|
+
innerShadow: InnerShadowState;
|
|
2874
|
+
glow: GlowState;
|
|
2875
|
+
reflection: ReflectionState;
|
|
2876
|
+
softEdge: SoftEdgeState;
|
|
2877
|
+
}
|
|
2878
|
+
|
|
2879
|
+
declare class EffectsPanelComponent {
|
|
2880
|
+
/** The element whose effects are being edited. */
|
|
2881
|
+
readonly element: _angular_core.InputSignal<PptxElement>;
|
|
2882
|
+
/**
|
|
2883
|
+
* Emits a Partial<PptxElement> patch each time the user commits a change.
|
|
2884
|
+
* The orchestrator should call EditorStateService.updateElement(slideIndex, element().id, patch).
|
|
2885
|
+
*/
|
|
2886
|
+
readonly patch: _angular_core.OutputEmitterRef<Partial<PptxElement>>;
|
|
2887
|
+
/** Derived EffectsState from the current element. */
|
|
2888
|
+
protected readonly state: _angular_core.Signal<EffectsState>;
|
|
2889
|
+
/** Stable key for keying inputs to the current element (prevents caret-reset). */
|
|
2890
|
+
protected readonly elementKey: _angular_core.Signal<string>;
|
|
2891
|
+
protected onOuterShadowToggle(event: Event): void;
|
|
2892
|
+
protected onOuterShadowField(field: 'color' | 'opacity' | 'blur' | 'angle' | 'distance', event: Event): void;
|
|
2893
|
+
protected onInnerShadowToggle(event: Event): void;
|
|
2894
|
+
protected onInnerShadowField(field: 'color' | 'opacity' | 'blur' | 'offsetX' | 'offsetY', event: Event): void;
|
|
2895
|
+
protected onGlowToggle(event: Event): void;
|
|
2896
|
+
protected onGlowField(field: 'color' | 'radius' | 'opacity', event: Event): void;
|
|
2897
|
+
protected onReflectionToggle(event: Event): void;
|
|
2898
|
+
protected onReflectionField(field: 'blurRadius' | 'startOpacity' | 'endOpacity' | 'distance' | 'direction', event: Event): void;
|
|
2899
|
+
protected onSoftEdgeToggle(event: Event): void;
|
|
2900
|
+
protected onSoftEdgeRadius(event: Event): void;
|
|
2901
|
+
private emit;
|
|
2902
|
+
static ɵfac: _angular_core.ɵɵFactoryDeclaration<EffectsPanelComponent, never>;
|
|
2903
|
+
static ɵcmp: _angular_core.ɵɵComponentDeclaration<EffectsPanelComponent, "pptx-effects-panel", never, { "element": { "alias": "element"; "required": true; "isSignal": true; }; }, { "patch": "patch"; }, never, never, true, never>;
|
|
2904
|
+
}
|
|
2905
|
+
|
|
2906
|
+
/**
|
|
2907
|
+
* text-advanced-helpers.ts — Pure (no Angular) helpers for TextAdvancedPanelComponent.
|
|
2908
|
+
*
|
|
2909
|
+
* Ported from / models the patterns in:
|
|
2910
|
+
* packages/react/src/viewer/components/inspector/TextPropertiesHelpers.tsx
|
|
2911
|
+
* packages/react/src/viewer/components/inspector/TextProperties.tsx
|
|
2912
|
+
* packages/angular/src/viewer/inspector-helpers.ts
|
|
2913
|
+
*
|
|
2914
|
+
* Readers extract advanced text values from a PptxElement (with sensible
|
|
2915
|
+
* defaults), and patch-builders produce shallow-merge-ready Partial<PptxElement>
|
|
2916
|
+
* objects for EditorStateService.updateElement.
|
|
2917
|
+
*
|
|
2918
|
+
* @module viewer/text-advanced-helpers
|
|
2919
|
+
*/
|
|
2920
|
+
|
|
2921
|
+
/**
|
|
2922
|
+
* The advanced text properties surfaced to the panel.
|
|
2923
|
+
*
|
|
2924
|
+
* Covers: character spacing, line spacing, paragraph alignment + spacing,
|
|
2925
|
+
* indent, text direction, and vertical anchor.
|
|
2926
|
+
*/
|
|
2927
|
+
interface TextAdvancedState {
|
|
2928
|
+
/** Character spacing in hundredths of a point (0 = normal). */
|
|
2929
|
+
characterSpacing: number;
|
|
2930
|
+
/** Line spacing multiplier (1.0 = single). */
|
|
2931
|
+
lineSpacing: number;
|
|
2932
|
+
/** Exact line spacing in points, or null when using multiplier mode. */
|
|
2933
|
+
lineSpacingExactPt: number | null;
|
|
2934
|
+
/** Paragraph spacing before in px. */
|
|
2935
|
+
paragraphSpacingBefore: number;
|
|
2936
|
+
/** Paragraph spacing after in px. */
|
|
2937
|
+
paragraphSpacingAfter: number;
|
|
2938
|
+
/** Paragraph text alignment. */
|
|
2939
|
+
align: NonNullable<TextStyle['align']>;
|
|
2940
|
+
/** Vertical anchor within the text body. */
|
|
2941
|
+
vAlign: NonNullable<TextStyle['vAlign']>;
|
|
2942
|
+
/** Paragraph first-line indent in px. */
|
|
2943
|
+
paragraphIndent: number;
|
|
2944
|
+
/** Paragraph left margin in px. */
|
|
2945
|
+
paragraphMarginLeft: number;
|
|
2946
|
+
/** Body text direction. */
|
|
2947
|
+
textDirection: NonNullable<TextStyle['textDirection']>;
|
|
2948
|
+
/** Right-to-left paragraph/run direction. */
|
|
2949
|
+
rtl: boolean;
|
|
2950
|
+
}
|
|
2951
|
+
|
|
2952
|
+
declare class TextAdvancedPanelComponent {
|
|
2953
|
+
/** The element whose advanced text properties are being edited. */
|
|
2954
|
+
readonly element: _angular_core.InputSignal<PptxElement>;
|
|
2955
|
+
/**
|
|
2956
|
+
* Emits a Partial<PptxElement> patch each time the user commits a change.
|
|
2957
|
+
* The orchestrator should call EditorStateService.updateElement(slideIndex, element().id, patch).
|
|
2958
|
+
*/
|
|
2959
|
+
readonly patch: _angular_core.OutputEmitterRef<Partial<PptxElement>>;
|
|
2960
|
+
/** Whether the element supports text properties. */
|
|
2961
|
+
protected readonly hasText: _angular_core.Signal<boolean>;
|
|
2962
|
+
/** Derived advanced text state from the current element. */
|
|
2963
|
+
protected readonly state: _angular_core.Signal<TextAdvancedState>;
|
|
2964
|
+
/** Stable key for keying inputs to the current element (prevents caret-reset mid-edit). */
|
|
2965
|
+
protected readonly elementKey: _angular_core.Signal<string>;
|
|
2966
|
+
/** Exposed option arrays for the template. */
|
|
2967
|
+
protected readonly alignOptions: [NonNullable<"center" | "left" | "right" | "justify" | "justLow" | "dist" | "thaiDist" | undefined>, string][];
|
|
2968
|
+
protected readonly vAlignOptions: [NonNullable<"top" | "middle" | "bottom" | undefined>, string][];
|
|
2969
|
+
protected readonly textDirectionOptions: [NonNullable<"eaVert" | "wordArtVert" | "wordArtVertRtl" | "mongolianVert" | "horizontal" | "vertical" | "vertical270" | undefined>, string][];
|
|
2970
|
+
protected alignLabel(align: NonNullable<TextStyle['align']>): string;
|
|
2971
|
+
protected onAlignChange(align: NonNullable<TextStyle['align']>): void;
|
|
2972
|
+
protected onVAlignChange(event: Event): void;
|
|
2973
|
+
protected onTextDirectionChange(event: Event): void;
|
|
2974
|
+
protected onRtlToggle(event: Event): void;
|
|
2975
|
+
protected onCharacterSpacingChange(event: Event): void;
|
|
2976
|
+
protected onLineSpacingChange(event: Event): void;
|
|
2977
|
+
protected onLineSpacingExactPtChange(event: Event): void;
|
|
2978
|
+
protected onSpacingBeforeChange(event: Event): void;
|
|
2979
|
+
protected onSpacingAfterChange(event: Event): void;
|
|
2980
|
+
protected onIndentChange(event: Event): void;
|
|
2981
|
+
protected onMarginLeftChange(event: Event): void;
|
|
2982
|
+
private emit;
|
|
2983
|
+
static ɵfac: _angular_core.ɵɵFactoryDeclaration<TextAdvancedPanelComponent, never>;
|
|
2984
|
+
static ɵcmp: _angular_core.ɵɵComponentDeclaration<TextAdvancedPanelComponent, "pptx-text-advanced-panel", never, { "element": { "alias": "element"; "required": true; "isSignal": true; }; }, { "patch": "patch"; }, never, never, true, never>;
|
|
2985
|
+
}
|
|
2986
|
+
|
|
2987
|
+
declare class TableDataEditorComponent {
|
|
2988
|
+
/** The table element being edited. */
|
|
2989
|
+
readonly element: _angular_core.InputSignal<TablePptxElement>;
|
|
2990
|
+
/** Whether editing is enabled (read-only mode when false). */
|
|
2991
|
+
readonly canEdit: _angular_core.InputSignal<boolean>;
|
|
2992
|
+
/** Emits the updated element after any edit operation. */
|
|
2993
|
+
readonly elementChange: _angular_core.OutputEmitterRef<TablePptxElement>;
|
|
2994
|
+
protected readonly rows: _angular_core.Signal<pptx_viewer_core.PptxTableRow[]>;
|
|
2995
|
+
protected readonly rowCount: _angular_core.Signal<number>;
|
|
2996
|
+
protected readonly colCount: _angular_core.Signal<number>;
|
|
2997
|
+
protected readonly colIndices: _angular_core.Signal<number[]>;
|
|
2998
|
+
protected onCellChange(event: Event, rowIndex: number, colIndex: number): void;
|
|
2999
|
+
protected onAddRow(): void;
|
|
3000
|
+
protected onRemoveLastRow(): void;
|
|
3001
|
+
protected onRemoveRow(rowIndex: number): void;
|
|
3002
|
+
protected onAddColumn(): void;
|
|
3003
|
+
protected onRemoveLastColumn(): void;
|
|
3004
|
+
protected onRemoveColumn(colIndex: number): void;
|
|
3005
|
+
static ɵfac: _angular_core.ɵɵFactoryDeclaration<TableDataEditorComponent, never>;
|
|
3006
|
+
static ɵcmp: _angular_core.ɵɵComponentDeclaration<TableDataEditorComponent, "pptx-table-data-editor", never, { "element": { "alias": "element"; "required": true; "isSignal": true; }; "canEdit": { "alias": "canEdit"; "required": false; "isSignal": true; }; }, { "elementChange": "elementChange"; }, never, never, true, never>;
|
|
3007
|
+
}
|
|
3008
|
+
|
|
3009
|
+
declare class ChartDataEditorComponent {
|
|
3010
|
+
/** The chart element being edited. */
|
|
3011
|
+
readonly element: _angular_core.InputSignal<ChartPptxElement>;
|
|
3012
|
+
/** Whether editing is enabled (read-only mode when false). */
|
|
3013
|
+
readonly canEdit: _angular_core.InputSignal<boolean>;
|
|
3014
|
+
/** Emits the updated element after any edit operation. */
|
|
3015
|
+
readonly elementChange: _angular_core.OutputEmitterRef<ChartPptxElement>;
|
|
3016
|
+
protected readonly hasData: _angular_core.Signal<boolean>;
|
|
3017
|
+
protected readonly series: _angular_core.Signal<pptx_viewer_core.PptxChartSeries[]>;
|
|
3018
|
+
protected readonly categories: _angular_core.Signal<string[]>;
|
|
3019
|
+
protected readonly seriesCount: _angular_core.Signal<number>;
|
|
3020
|
+
protected readonly catCount: _angular_core.Signal<number>;
|
|
3021
|
+
protected onSeriesNameChange(event: Event, seriesIndex: number): void;
|
|
3022
|
+
protected onCategoryLabelChange(event: Event, catIndex: number): void;
|
|
3023
|
+
protected onValueChange(event: Event, seriesIndex: number, catIndex: number): void;
|
|
3024
|
+
protected onAddSeries(): void;
|
|
3025
|
+
protected onRemoveLastSeries(): void;
|
|
3026
|
+
protected onRemoveSeries(seriesIndex: number): void;
|
|
3027
|
+
protected onAddCategory(): void;
|
|
3028
|
+
protected onRemoveLastCategory(): void;
|
|
3029
|
+
protected onRemoveCategory(catIndex: number): void;
|
|
3030
|
+
static ɵfac: _angular_core.ɵɵFactoryDeclaration<ChartDataEditorComponent, never>;
|
|
3031
|
+
static ɵcmp: _angular_core.ɵɵComponentDeclaration<ChartDataEditorComponent, "pptx-chart-data-editor", never, { "element": { "alias": "element"; "required": true; "isSignal": true; }; "canEdit": { "alias": "canEdit"; "required": false; "isSignal": true; }; }, { "elementChange": "elementChange"; }, never, never, true, never>;
|
|
3032
|
+
}
|
|
3033
|
+
|
|
2136
3034
|
/**
|
|
2137
3035
|
* SlidesPanelComponent — vertical slide-strip for the editor sidebar.
|
|
2138
3036
|
*
|
|
@@ -2247,6 +3145,26 @@ declare class ExportService {
|
|
|
2247
3145
|
* @param fileName - Suggested download file name (unsafe chars stripped).
|
|
2248
3146
|
*/
|
|
2249
3147
|
exportCanvasesToPdf(canvases: HTMLCanvasElement[], canvasWidth: number, canvasHeight: number, fileName: string): void;
|
|
3148
|
+
/**
|
|
3149
|
+
* Assemble an animated GIF from pre-rendered slide canvases (one frame per
|
|
3150
|
+
* slide) and trigger a download. Frame delay is derived from
|
|
3151
|
+
* `slideDurationMs` via the pure {@link planGifFrames} planner.
|
|
3152
|
+
*
|
|
3153
|
+
* @param canvases - One canvas per slide, in order.
|
|
3154
|
+
* @param slideDurationMs - Display time per slide in milliseconds.
|
|
3155
|
+
* @param fileName - Suggested download file name.
|
|
3156
|
+
*/
|
|
3157
|
+
exportCanvasesToGif(canvases: HTMLCanvasElement[], slideDurationMs: number, fileName: string): void;
|
|
3158
|
+
/**
|
|
3159
|
+
* Record a WebM video from pre-rendered slide canvases (each held for
|
|
3160
|
+
* `slideDurationMs`) via the browser `MediaRecorder` and trigger a download.
|
|
3161
|
+
*
|
|
3162
|
+
* @param canvases - One canvas per slide, in order.
|
|
3163
|
+
* @param slideDurationMs - Display time per slide in milliseconds.
|
|
3164
|
+
* @param fileName - Suggested download file name.
|
|
3165
|
+
* @param signal - Optional abort signal to cancel recording.
|
|
3166
|
+
*/
|
|
3167
|
+
exportCanvasesToWebm(canvases: HTMLCanvasElement[], slideDurationMs: number, fileName: string, signal?: AbortSignal): Promise<void>;
|
|
2250
3168
|
static ɵfac: _angular_core.ɵɵFactoryDeclaration<ExportService, never>;
|
|
2251
3169
|
static ɵprov: _angular_core.ɵɵInjectableDeclaration<ExportService>;
|
|
2252
3170
|
}
|
|
@@ -2269,6 +3187,309 @@ declare class ExportService {
|
|
|
2269
3187
|
*/
|
|
2270
3188
|
declare function renderToCanvas(element: HTMLElement, options?: Partial<Options>): Promise<HTMLCanvasElement>;
|
|
2271
3189
|
|
|
3190
|
+
/**
|
|
3191
|
+
* GIF export helpers for the Angular viewer.
|
|
3192
|
+
*
|
|
3193
|
+
* Source: ported from packages/react/src/viewer/utils/export-gif-encoder.ts
|
|
3194
|
+
* and packages/react/src/viewer/utils/export-gif.ts.
|
|
3195
|
+
*
|
|
3196
|
+
* Split into two concerns:
|
|
3197
|
+
* 1. Pure, browser-free planning helpers (frame ordering, per-frame delay
|
|
3198
|
+
* computation, dimension clamping) — fully unit-testable.
|
|
3199
|
+
* 2. A thin browser-facing `encodeGif()` function that assembles an animated
|
|
3200
|
+
* GIF89a Uint8Array from per-slide ImageData objects and a pre-computed
|
|
3201
|
+
* frame delay. The caller (ExportService) is responsible for rasterising
|
|
3202
|
+
* slides to canvases and extracting ImageData via `ctx.getImageData()`.
|
|
3203
|
+
*
|
|
3204
|
+
* No external encoder dependency is required — the encoder is a self-contained
|
|
3205
|
+
* pure-JS GIF89a implementation (median-cut quantisation + LZW) that mirrors
|
|
3206
|
+
* the React package exactly.
|
|
3207
|
+
*/
|
|
3208
|
+
/**
|
|
3209
|
+
* A single GIF frame descriptor produced by the planning helpers.
|
|
3210
|
+
* The `imageData` field is filled in by the caller (ExportService) after
|
|
3211
|
+
* rasterising the corresponding slide.
|
|
3212
|
+
*/
|
|
3213
|
+
interface GifFramePlan {
|
|
3214
|
+
/** 0-based slide index this frame corresponds to. */
|
|
3215
|
+
slideIndex: number;
|
|
3216
|
+
/** Frame delay in **centiseconds** (1 cs = 10 ms), as required by GIF89a. */
|
|
3217
|
+
delayCs: number;
|
|
3218
|
+
}
|
|
3219
|
+
/**
|
|
3220
|
+
* Options controlling GIF frame planning.
|
|
3221
|
+
*/
|
|
3222
|
+
interface GifPlanOptions {
|
|
3223
|
+
/** Total number of slides in the presentation. */
|
|
3224
|
+
totalSlides: number;
|
|
3225
|
+
/**
|
|
3226
|
+
* Duration each slide is shown, in **milliseconds** (default: 2000).
|
|
3227
|
+
* Per-slide overrides can be supplied via {@link slideTimingsMs}.
|
|
3228
|
+
*/
|
|
3229
|
+
slideDurationMs?: number;
|
|
3230
|
+
/**
|
|
3231
|
+
* Per-slide duration overrides in milliseconds (index maps to slide index).
|
|
3232
|
+
* When a slide's index is present here its value takes precedence over
|
|
3233
|
+
* {@link slideDurationMs}.
|
|
3234
|
+
*/
|
|
3235
|
+
slideTimingsMs?: number[];
|
|
3236
|
+
}
|
|
3237
|
+
/**
|
|
3238
|
+
* Compute the ordered list of {@link GifFramePlan} objects for a presentation.
|
|
3239
|
+
*
|
|
3240
|
+
* All timing is derived here; nothing browser-specific is touched.
|
|
3241
|
+
*
|
|
3242
|
+
* @param opts - Planning options.
|
|
3243
|
+
* @returns One {@link GifFramePlan} per slide, in slide order (0-based).
|
|
3244
|
+
*
|
|
3245
|
+
* @example
|
|
3246
|
+
* const plans = planGifFrames({ totalSlides: 5, slideDurationMs: 3000 });
|
|
3247
|
+
* // plans[0].slideIndex === 0, plans[0].delayCs === 300, …
|
|
3248
|
+
*/
|
|
3249
|
+
declare function planGifFrames(opts: GifPlanOptions): GifFramePlan[];
|
|
3250
|
+
/**
|
|
3251
|
+
* Convert a slide duration in milliseconds to a GIF89a frame delay in
|
|
3252
|
+
* centiseconds (1 cs = 10 ms), clamped to a minimum of 1 cs.
|
|
3253
|
+
*
|
|
3254
|
+
* @param ms - Duration in milliseconds (must be > 0).
|
|
3255
|
+
* @returns Frame delay in centiseconds (integer ≥ 1).
|
|
3256
|
+
*/
|
|
3257
|
+
declare function msToFrameDelayCs(ms: number): number;
|
|
3258
|
+
/**
|
|
3259
|
+
* Clamp canvas/image dimensions so neither side exceeds `maxSide` pixels
|
|
3260
|
+
* while preserving the aspect ratio. When both dimensions are already within
|
|
3261
|
+
* the limit the original values are returned unchanged.
|
|
3262
|
+
*
|
|
3263
|
+
* GIF is limited to 65535 × 65535 but practical encoders perform best at
|
|
3264
|
+
* much smaller sizes (the React package defaults to 0.5× scale). This
|
|
3265
|
+
* helper lets callers enforce a reasonable cap without coupling the logic to
|
|
3266
|
+
* a specific scale factor.
|
|
3267
|
+
*
|
|
3268
|
+
* @param width - Original width in pixels.
|
|
3269
|
+
* @param height - Original height in pixels.
|
|
3270
|
+
* @param maxSide - Maximum permitted dimension on either axis (default 1920).
|
|
3271
|
+
* @returns `{ width, height }` clamped to `maxSide`, floored to whole pixels.
|
|
3272
|
+
*/
|
|
3273
|
+
declare function clampGifDimensions(width: number, height: number, maxSide?: number): {
|
|
3274
|
+
width: number;
|
|
3275
|
+
height: number;
|
|
3276
|
+
};
|
|
3277
|
+
/**
|
|
3278
|
+
* A single animated GIF frame: raw RGBA pixel data plus its dimensions.
|
|
3279
|
+
*/
|
|
3280
|
+
interface GifFrame {
|
|
3281
|
+
imageData: ImageData;
|
|
3282
|
+
width: number;
|
|
3283
|
+
height: number;
|
|
3284
|
+
}
|
|
3285
|
+
/**
|
|
3286
|
+
* Options for {@link encodeGif}.
|
|
3287
|
+
*/
|
|
3288
|
+
interface EncodeGifOptions {
|
|
3289
|
+
/**
|
|
3290
|
+
* Frame delay in **centiseconds** (1 cs = 10 ms). All frames share the
|
|
3291
|
+
* same delay; for per-frame delays compute them with {@link planGifFrames}
|
|
3292
|
+
* and encode each frame separately.
|
|
3293
|
+
*
|
|
3294
|
+
* Default: 200 cs (2 s).
|
|
3295
|
+
*/
|
|
3296
|
+
delayCs?: number;
|
|
3297
|
+
/**
|
|
3298
|
+
* Number of times the animation loops (0 = loop forever, default).
|
|
3299
|
+
*/
|
|
3300
|
+
loopCount?: number;
|
|
3301
|
+
}
|
|
3302
|
+
/**
|
|
3303
|
+
* Encode an ordered list of RGBA image frames into an animated GIF89a byte
|
|
3304
|
+
* sequence.
|
|
3305
|
+
*
|
|
3306
|
+
* Uses median-cut colour quantisation (256 colours per frame) and LZW
|
|
3307
|
+
* compression. All frames must have identical dimensions.
|
|
3308
|
+
*
|
|
3309
|
+
* This function is browser-safe but does NOT require any browser API — it
|
|
3310
|
+
* operates on pre-extracted `ImageData` objects. Callers must rasterise
|
|
3311
|
+
* slides to canvases themselves (see `ExportService.renderElement`).
|
|
3312
|
+
*
|
|
3313
|
+
* @param frames - Ordered array of frame descriptors.
|
|
3314
|
+
* @param opts - Encoding options.
|
|
3315
|
+
* @returns Raw GIF89a bytes.
|
|
3316
|
+
*
|
|
3317
|
+
* @example
|
|
3318
|
+
* // In ExportService:
|
|
3319
|
+
* const canvas = await this.renderElement(el, 0.5);
|
|
3320
|
+
* const ctx = canvas.getContext('2d')!;
|
|
3321
|
+
* const id = ctx.getImageData(0, 0, canvas.width, canvas.height);
|
|
3322
|
+
* const bytes = encodeGif([{ imageData: id, width: canvas.width, height: canvas.height }]);
|
|
3323
|
+
* const blob = new Blob([bytes.buffer], { type: 'image/gif' });
|
|
3324
|
+
*/
|
|
3325
|
+
declare function encodeGif(frames: GifFrame[], opts?: EncodeGifOptions): Uint8Array;
|
|
3326
|
+
|
|
3327
|
+
/**
|
|
3328
|
+
* Video (WebM) export helpers for the Angular viewer.
|
|
3329
|
+
*
|
|
3330
|
+
* Source: ported from packages/react/src/viewer/utils/export-video.ts.
|
|
3331
|
+
*
|
|
3332
|
+
* Split into two concerns:
|
|
3333
|
+
* 1. Pure, browser-free planning helpers (frame-segment timing, MIME-type
|
|
3334
|
+
* selection) — fully unit-testable with no DOM/MediaRecorder dependency.
|
|
3335
|
+
* 2. A thin browser-facing `recordWebm()` function that drives a
|
|
3336
|
+
* `MediaRecorder` over a canvas `captureStream()` to produce a WebM Blob.
|
|
3337
|
+
* The caller (ExportService) supplies the pre-rendered slide canvases and
|
|
3338
|
+
* a `recordingCanvas` for compositing.
|
|
3339
|
+
*
|
|
3340
|
+
* No new npm dependency is needed — `MediaRecorder` is a browser built-in.
|
|
3341
|
+
*/
|
|
3342
|
+
/**
|
|
3343
|
+
* Timing plan for one slide's contribution to the video.
|
|
3344
|
+
*/
|
|
3345
|
+
interface VideoSegmentPlan {
|
|
3346
|
+
/** 0-based slide index. */
|
|
3347
|
+
slideIndex: number;
|
|
3348
|
+
/** Duration this segment should be held, in milliseconds. */
|
|
3349
|
+
durationMs: number;
|
|
3350
|
+
/** Target frame rate used to compute the segment frame count. */
|
|
3351
|
+
fps: number;
|
|
3352
|
+
/** Total number of draw-loop iterations for this segment at `fps`. */
|
|
3353
|
+
frameCount: number;
|
|
3354
|
+
}
|
|
3355
|
+
/**
|
|
3356
|
+
* Options for {@link planVideoSegments}.
|
|
3357
|
+
*/
|
|
3358
|
+
interface VideoPlanOptions {
|
|
3359
|
+
/** Total number of slides. */
|
|
3360
|
+
totalSlides: number;
|
|
3361
|
+
/**
|
|
3362
|
+
* Default slide display duration in **milliseconds** (default: 3000).
|
|
3363
|
+
* Overridden per-slide by {@link slideTimingsMs}.
|
|
3364
|
+
*/
|
|
3365
|
+
slideDurationMs?: number;
|
|
3366
|
+
/**
|
|
3367
|
+
* Per-slide duration overrides in milliseconds (index maps to slide index).
|
|
3368
|
+
* `undefined` entries fall back to {@link slideDurationMs}.
|
|
3369
|
+
*/
|
|
3370
|
+
slideTimingsMs?: number[];
|
|
3371
|
+
/**
|
|
3372
|
+
* Desired recording frame rate in frames-per-second (default: 30).
|
|
3373
|
+
* Used to compute the number of draw iterations per segment.
|
|
3374
|
+
*/
|
|
3375
|
+
fps?: number;
|
|
3376
|
+
}
|
|
3377
|
+
/**
|
|
3378
|
+
* Compute an ordered list of {@link VideoSegmentPlan} objects for a
|
|
3379
|
+
* presentation video. Nothing browser-specific is touched.
|
|
3380
|
+
*
|
|
3381
|
+
* @param opts - Planning options.
|
|
3382
|
+
* @returns One {@link VideoSegmentPlan} per slide, in slide order (0-based).
|
|
3383
|
+
*
|
|
3384
|
+
* @example
|
|
3385
|
+
* const segs = planVideoSegments({ totalSlides: 3, slideDurationMs: 2000, fps: 30 });
|
|
3386
|
+
* // segs[0].durationMs === 2000, segs[0].frameCount === 60
|
|
3387
|
+
*/
|
|
3388
|
+
declare function planVideoSegments(opts: VideoPlanOptions): VideoSegmentPlan[];
|
|
3389
|
+
/**
|
|
3390
|
+
* Select the first MIME type from `candidates` that `MediaRecorder.isTypeSupported`
|
|
3391
|
+
* accepts, falling back to the last candidate in the list when none is supported.
|
|
3392
|
+
*
|
|
3393
|
+
* This is a pure browser-API wrapper (no DOM, no canvas) that can be
|
|
3394
|
+
* spied/mocked in unit tests.
|
|
3395
|
+
*
|
|
3396
|
+
* Priority order recommended for WebM:
|
|
3397
|
+
* ```
|
|
3398
|
+
* ['video/webm;codecs=vp9', 'video/webm;codecs=vp8', 'video/webm']
|
|
3399
|
+
* ```
|
|
3400
|
+
*
|
|
3401
|
+
* @param candidates - Ordered list of MIME type strings to test (most preferred first).
|
|
3402
|
+
* @returns The first supported MIME type, or the last candidate as the fallback.
|
|
3403
|
+
* @throws When `candidates` is empty.
|
|
3404
|
+
*/
|
|
3405
|
+
declare function pickSupportedMimeType(candidates: string[]): string;
|
|
3406
|
+
/**
|
|
3407
|
+
* Compute the frame interval in milliseconds for a target frame rate.
|
|
3408
|
+
*
|
|
3409
|
+
* @param fps - Desired frames per second (must be > 0).
|
|
3410
|
+
* @returns Frame interval in milliseconds.
|
|
3411
|
+
*/
|
|
3412
|
+
declare function fpsToFrameIntervalMs(fps: number): number;
|
|
3413
|
+
/**
|
|
3414
|
+
* Compute the number of draw-loop frames needed to fill a segment of `durationMs`
|
|
3415
|
+
* at `fps`. Always at least 1.
|
|
3416
|
+
*
|
|
3417
|
+
* @param durationMs - Segment duration in milliseconds.
|
|
3418
|
+
* @param fps - Frame rate in frames per second.
|
|
3419
|
+
* @returns Number of frames (integer ≥ 1).
|
|
3420
|
+
*/
|
|
3421
|
+
declare function segmentFrameCount(durationMs: number, fps: number): number;
|
|
3422
|
+
/**
|
|
3423
|
+
* Default ordered MIME-type candidates for WebM recording, most preferred first.
|
|
3424
|
+
* Pass to {@link pickSupportedMimeType} or directly to `recordWebm`.
|
|
3425
|
+
*/
|
|
3426
|
+
declare const WEBM_MIME_CANDIDATES: readonly string[];
|
|
3427
|
+
/**
|
|
3428
|
+
* Options for {@link recordWebm}.
|
|
3429
|
+
*/
|
|
3430
|
+
interface RecordWebmOptions {
|
|
3431
|
+
/**
|
|
3432
|
+
* Desired recording frame rate fed to `captureStream()` (default: 30).
|
|
3433
|
+
*/
|
|
3434
|
+
fps?: number;
|
|
3435
|
+
/**
|
|
3436
|
+
* Per-slide durations in milliseconds (index maps to slide order in `canvases`).
|
|
3437
|
+
* When absent, `slideDurationMs` is used for every slide.
|
|
3438
|
+
*/
|
|
3439
|
+
slideTimingsMs?: number[];
|
|
3440
|
+
/**
|
|
3441
|
+
* Default slide duration in milliseconds (default: 3000).
|
|
3442
|
+
*/
|
|
3443
|
+
slideDurationMs?: number;
|
|
3444
|
+
/**
|
|
3445
|
+
* MIME type for `MediaRecorder` (default: result of
|
|
3446
|
+
* `pickSupportedMimeType(WEBM_MIME_CANDIDATES)`).
|
|
3447
|
+
*/
|
|
3448
|
+
mimeType?: string;
|
|
3449
|
+
/**
|
|
3450
|
+
* Video bit rate in bits/s (default: 5_000_000 = 5 Mbps, matching the
|
|
3451
|
+
* React package).
|
|
3452
|
+
*/
|
|
3453
|
+
videoBitsPerSecond?: number;
|
|
3454
|
+
/**
|
|
3455
|
+
* Optional `AbortSignal` to cancel the recording mid-way.
|
|
3456
|
+
*/
|
|
3457
|
+
signal?: AbortSignal;
|
|
3458
|
+
/**
|
|
3459
|
+
* Progress callback invoked at the start of each slide's recording segment.
|
|
3460
|
+
* Receives `(currentSlide, totalSlides)`.
|
|
3461
|
+
*/
|
|
3462
|
+
onProgress?: (current: number, total: number) => void;
|
|
3463
|
+
}
|
|
3464
|
+
/**
|
|
3465
|
+
* Record an ordered list of pre-rendered slide canvases as a WebM video Blob.
|
|
3466
|
+
*
|
|
3467
|
+
* Strategy (mirrors the React `exportAllSlidesAsVideo`):
|
|
3468
|
+
* 1. Create an off-screen `recordingCanvas` sized to the first slide canvas.
|
|
3469
|
+
* 2. Start a `captureStream(fps)` + `MediaRecorder` on it.
|
|
3470
|
+
* 3. For each slide canvas, draw it repeatedly onto `recordingCanvas` for the
|
|
3471
|
+
* slide's duration at `fps`, feeding frames to the stream.
|
|
3472
|
+
* 4. Stop the recorder and return the accumulated WebM Blob.
|
|
3473
|
+
*
|
|
3474
|
+
* The caller is responsible for rasterising slides to canvases beforehand
|
|
3475
|
+
* (via `ExportService.renderElement`). This keeps the heavy html2canvas-pro
|
|
3476
|
+
* work outside this function and makes progress reporting easy.
|
|
3477
|
+
*
|
|
3478
|
+
* @param canvases - Pre-rendered slide canvases in slide order.
|
|
3479
|
+
* @param opts - Recording options.
|
|
3480
|
+
* @returns A `Promise<Blob>` resolving to a `video/webm` Blob.
|
|
3481
|
+
*
|
|
3482
|
+
* @throws `DOMException('Export cancelled', 'AbortError')` when `signal` fires.
|
|
3483
|
+
* @throws `Error` when no canvases are supplied or when 2D context creation fails.
|
|
3484
|
+
*
|
|
3485
|
+
* @example
|
|
3486
|
+
* // In ExportService:
|
|
3487
|
+
* const canvases = await Promise.all(slides.map(el => this.renderElement(el)));
|
|
3488
|
+
* const blob = await recordWebm(canvases, { slideDurationMs: 3000 });
|
|
3489
|
+
* downloadBlob(blob, 'presentation.webm');
|
|
3490
|
+
*/
|
|
3491
|
+
declare function recordWebm(canvases: HTMLCanvasElement[], opts?: RecordWebmOptions): Promise<Blob>;
|
|
3492
|
+
|
|
2272
3493
|
/**
|
|
2273
3494
|
* editor-history.ts — Generic undo/redo history stack.
|
|
2274
3495
|
*
|
|
@@ -3355,55 +4576,6 @@ declare class HyperlinkDialogComponent {
|
|
|
3355
4576
|
static ɵcmp: _angular_core.ɵɵComponentDeclaration<HyperlinkDialogComponent, "pptx-hyperlink-dialog", never, { "open": { "alias": "open"; "required": false; "isSignal": true; }; "element": { "alias": "element"; "required": false; "isSignal": true; }; }, { "save": "save"; "close": "close"; }, never, never, true, never>;
|
|
3356
4577
|
}
|
|
3357
4578
|
|
|
3358
|
-
/**
|
|
3359
|
-
* broadcast-helpers.ts — Pure (no Angular) helpers for the Broadcast dialog.
|
|
3360
|
-
*
|
|
3361
|
-
* A broadcast is a one-way collaboration session: the presenter drives slide
|
|
3362
|
-
* navigation and viewers follow along via a shareable link. These helpers
|
|
3363
|
-
* cover the testable, framework-agnostic parts of the Vue `BroadcastDialog.vue`
|
|
3364
|
-
* and React `BroadcastDialog.tsx`: room-id generation, form validation, and
|
|
3365
|
-
* the viewer-link builder.
|
|
3366
|
-
*
|
|
3367
|
-
* No `any`; all regexes use the `/u` flag; no `String.prototype.replaceAll`,
|
|
3368
|
-
* no regex named-capture-groups (ng-packagr lib-target constraints).
|
|
3369
|
-
*/
|
|
3370
|
-
/** Default y-websocket server URL used when no default is supplied. */
|
|
3371
|
-
declare const DEFAULT_BROADCAST_SERVER_URL = "ws://localhost:1234";
|
|
3372
|
-
/** Optional seed values for the broadcast start form. */
|
|
3373
|
-
interface BroadcastDefaults {
|
|
3374
|
-
roomId?: string;
|
|
3375
|
-
serverUrl?: string;
|
|
3376
|
-
}
|
|
3377
|
-
/** The configuration emitted when a broadcast starts. */
|
|
3378
|
-
interface BroadcastConfig {
|
|
3379
|
-
roomId: string;
|
|
3380
|
-
serverUrl: string;
|
|
3381
|
-
}
|
|
3382
|
-
/** Generate a fresh, broadcast-scoped room id (`broadcast-<suffix>`). */
|
|
3383
|
-
declare function generateBroadcastRoomId(): string;
|
|
3384
|
-
/**
|
|
3385
|
-
* Seed the start form from the (optional) defaults, generating a fresh room id
|
|
3386
|
-
* when none is supplied and falling back to the default server URL.
|
|
3387
|
-
*/
|
|
3388
|
-
declare function seedBroadcastFields(defaults?: BroadcastDefaults): BroadcastConfig;
|
|
3389
|
-
/** Whether both required fields are non-blank (after trimming). */
|
|
3390
|
-
declare function canStartBroadcast(fields: BroadcastConfig): boolean;
|
|
3391
|
-
/**
|
|
3392
|
-
* Assemble a {@link BroadcastConfig} from the (trimmed) form fields, or `null`
|
|
3393
|
-
* when incomplete.
|
|
3394
|
-
*/
|
|
3395
|
-
declare function buildBroadcastConfig(fields: BroadcastConfig): BroadcastConfig | null;
|
|
3396
|
-
/**
|
|
3397
|
-
* Build the shareable viewer follow-link for a broadcast. Returns just the
|
|
3398
|
-
* room id when no `origin`/`pathname` are available (non-browser environments).
|
|
3399
|
-
*/
|
|
3400
|
-
declare function buildBroadcastViewerUrl(roomId: string, serverUrl: string, location?: {
|
|
3401
|
-
origin: string;
|
|
3402
|
-
pathname: string;
|
|
3403
|
-
}): string;
|
|
3404
|
-
/** Whether the runtime exposes a usable async clipboard write API. */
|
|
3405
|
-
declare function canUseClipboard(nav: Navigator | undefined): boolean;
|
|
3406
|
-
|
|
3407
4579
|
declare class BroadcastDialogComponent {
|
|
3408
4580
|
/** Whether the dialog is visible. */
|
|
3409
4581
|
readonly open: _angular_core.InputSignal<boolean>;
|
|
@@ -4006,5 +5178,5 @@ declare function themeStyle(theme: ViewerTheme | undefined): Record<string, stri
|
|
|
4006
5178
|
type ClassValue = string | number | false | null | undefined;
|
|
4007
5179
|
declare function cn(...values: ClassValue[]): string;
|
|
4008
5180
|
|
|
4009
|
-
export { AccessibilityPanelComponent, AccessibilityService, AnimationPanelComponent, AnimationPlaybackService, BroadcastDialogComponent, CURSOR_PALETTE, ChartRendererComponent, CollaborationCursorsComponent, CollaborationService, CommentsPanelComponent, CommentsService, ConnectorRendererComponent, DEFAULT_BROADCAST_SERVER_URL, DEFAULT_CANVAS_HEIGHT, DEFAULT_CANVAS_WIDTH, DEFAULT_FILL_COLOR, DEFAULT_PRINT_SETTINGS, DEFAULT_SLIDE_BACKGROUND, DEFAULT_STROKE_COLOR, DEFAULT_TEXT_COLOR, EMBEDDED_FONTS_STYLE_ID, EditorContextMenuComponent, EditorHistory, EditorStateService, EditorToolbarComponent, ElementRendererComponent, EmbeddedFontsService, EquationRendererComponent, ExportService, FindBarComponent, HANDOUT_OPTIONS, HyperlinkDialogComponent, InkRendererComponent, InspectorPanelComponent, LoadContentService, ModalDialogComponent, Model3DRendererComponent, OleRendererComponent, PowerPointViewerComponent, PresentationOverlayComponent, PresentationTransitionOverlayComponent, PresenterViewComponent, PrintDialogComponent, PrintService, PrintSettingsPanelComponent, PropertiesDialogComponent, RESIZE_HANDLES, SEVERITY_GROUPS, SEVERITY_LABELS, SLIDE_TRANSITION_KEYFRAMES, ShareDialogComponent, SignaturesPanelComponent, SignaturesService, SlideCanvasComponent, SlideSorterOverlayComponent, SlidesPanelComponent, SmartArtRendererComponent, TYPE_LABELS, TableRendererComponent, VIEWER_THEME, ZoomRendererComponent, addCommentToList, advanceStep, applyMove, applyResize, assignUserColor, bringForward, bringToFront, buildBroadcastConfig, buildBroadcastViewerUrl, buildClearHyperlinkPatch, buildClickGroups, buildCollaborationConfig, buildCssGradientFromShapeStyle, buildEmbeddedFontStyles, buildFontFaceRule, buildHyperlinkPatch, buildPatternFillCss, buildPrintDocument, buildPropertiesPatch, buildShareUrl, bulletIndentPx, canStartBroadcast, canStartShare, canUseClipboard, clampCursorPosition, clampNotesFontSize, clampStep, cn, collectAccessibilityIssues, collectElementText, collectSlideText, computeHandoutLayout, computePageCount, computeSlideIndices, computeTimerProgress, convertOmmlToMathMl, countAccessibilityIssues, defaultCssVars, defaultRadius, defaultThemeColors, deleteElementsByIds, derivePresenceList, duplicateElementById, durationOf, estimatePageCount, fontMimeForFormat, formatAutoNumber, formatCursorLabel, formatElapsed, formatPropertyDate, formatTime, generateBroadcastRoomId, generateCommentId, getContainerStyle, getImageSrc, getPatternSvg, getResolvedShapeClipPath, getResolvedShapeClipPathFor, getShapeFillStrokeStyle, getSlideBackgroundStyle, getSlideTransitionAnimations, getTextBlockStyle, groupIssuesBySeverity, hasExistingLink, headerLabel, isInjectableUrl, isPpactionUrl, isSigned, isUrlSafe, isValidRoomId, issueTrackKey, issueTypeLabel, moveElementBy, normalizeFontFormat, normalizeSlidesPerPage, ommlToMathml, overallStatus, pendingElementStyles, presenceToCursors, provideViewerTheme, removeCommentFromList, renderToCanvas, resizeElement, resolveFontVariant, resolveHyperlinkHref, resolveParagraphBullet, resolvePresenterNotes, resolveTransitionDuration, revealedElementStyles, sanitizeColor, sanitizeSlideIndex, sanitizeUserName, searchSlides, seedBroadcastFields, seedHyperlinkDraft, seedPropertiesDraft, seedShareFields, sendBackward, sendToBack, setElementPosition, signatureCountLabel, signatureKey, signatureTimestamp, signerName, statusKind, statusLabel, themeStyle, themeToCssVars, toggleCommentResolvedInList, updateElementById, validatePrintSettings, validateRoomId, worstStatus };
|
|
4010
|
-
export type { AccessibilityIssueGroup, AnimationClickGroup, Box, BroadcastConfig, BroadcastDefaults, CSSProperties, CanvasSize, ClassValue, CollaborationConfig, CollaborationRole, DocumentProperties, EmbeddedFontStyles, HandoutSlidesPerPage, HyperlinkDraft, NotesSegmentViewModel, ObjectUrlFactory, OverallSignatureStatus, PresenterNotes, PrintColorMode, PrintDocumentOptions, PrintOrientation, PrintSettings, PrintSlideRange, PrintWhat, PropertiesDraft, RemoteCursor, RemotePresence, ResizeHandle, ResolvedFontVariant, ShareDefaults, ShareFormFields, SignatureStatusKind, SlideTransitionAnimations, StyleMap, TimerProgress, ViewerTheme, ViewerThemeColors };
|
|
5181
|
+
export { AccessibilityPanelComponent, AccessibilityService, AnimationPanelComponent, AnimationPlaybackService, BroadcastDialogComponent, CURSOR_PALETTE, ChartDataEditorComponent, ChartRendererComponent, CollaborationCursorsComponent, CollaborationService, CommentsPanelComponent, CommentsService, ConnectorRendererComponent, ConnectorTextOverlayComponent, DEFAULT_BROADCAST_SERVER_URL, DEFAULT_CANVAS_HEIGHT, DEFAULT_CANVAS_WIDTH, DEFAULT_FILL_COLOR, DEFAULT_PRINT_SETTINGS, DEFAULT_SLIDE_BACKGROUND, DEFAULT_STROKE_COLOR, DEFAULT_TEXT_COLOR, EMBEDDED_FONTS_STYLE_ID, EditorContextMenuComponent, EditorHistory, EditorStateService, EditorToolbarComponent, EffectsPanelComponent, ElementRendererComponent, EmbeddedFontsService, EquationRendererComponent, ExportService, FindBarComponent, FindReplaceBarComponent, GradientPickerComponent, HANDOUT_OPTIONS, HyperlinkDialogComponent, InkRendererComponent, InspectorPanelComponent, LoadContentService, ModalDialogComponent, Model3DRendererComponent, OleRendererComponent, PowerPointViewerComponent, PresentationOverlayComponent, PresentationTransitionOverlayComponent, PresenterViewComponent, PrintDialogComponent, PrintService, PrintSettingsPanelComponent, PropertiesDialogComponent, RESIZE_HANDLES, SEVERITY_GROUPS, SEVERITY_LABELS, SLIDE_TRANSITION_KEYFRAMES, ShareDialogComponent, SignaturesPanelComponent, SignaturesService, SlideCanvasComponent, SlideSorterOverlayComponent, SlidesPanelComponent, SmartArtRendererComponent, TYPE_LABELS, TableDataEditorComponent, TableRendererComponent, TextAdvancedPanelComponent, VIEWER_THEME, WEBM_MIME_CANDIDATES, ZoomRendererComponent, addCommentToList, advanceStep, applyFindReplacements, applyMove, applyResize, assignUserColor, bringForward, bringToFront, buildBroadcastConfig, buildBroadcastViewerUrl, buildClearHyperlinkPatch, buildClickGroups, buildCollaborationConfig, buildCssGradientFromShapeStyle, buildDuotoneFilter, buildDuotoneFilterId, buildEmbeddedFontStyles, buildFontFaceRule, buildHyperlinkPatch, buildPatternFillCss, buildPrintDocument, buildPropertiesPatch, buildShareUrl, bulletIndentPx, canStartBroadcast, canStartShare, canUseClipboard, clampCursorPosition, clampGifDimensions, clampNotesFontSize, clampStep, cn, collectAccessibilityIssues, collectElementText, collectSlideText, computeHandoutLayout, computePageCount, computeSlideIndices, computeTimerProgress, convertOmmlToMathMl, countAccessibilityIssues, defaultCssVars, defaultRadius, defaultThemeColors, deleteElementsByIds, derivePresenceList, duplicateElementById, durationOf, encodeGif, estimatePageCount, findInSlides, fontMimeForFormat, formatAutoNumber, formatCursorLabel, formatElapsed, formatPropertyDate, formatTime, fpsToFrameIntervalMs, generateBroadcastRoomId, generateCommentId, getContainerStyle, getDuotoneFilterDef, getImageSrc, getPatternSvg, getResolvedShapeClipPath, getResolvedShapeClipPathFor, getShapeFillStrokeStyle, getSlideBackgroundStyle, getSlideTransitionAnimations, getTextBlockStyle, groupIssuesBySeverity, hasExistingLink, headerLabel, isInjectableUrl, isPpactionUrl, isSigned, isUrlSafe, isValidRoomId, issueTrackKey, issueTypeLabel, moveElementBy, msToFrameDelayCs, normalizeFontFormat, normalizeSlidesPerPage, ommlToMathml, overallStatus, pendingElementStyles, pickSupportedMimeType, planGifFrames, planVideoSegments, presenceToCursors, provideViewerTheme, recordWebm, removeCommentFromList, renderToCanvas, replaceInSlides, replaceMatch, resizeElement, resolveFontVariant, resolveHyperlinkHref, resolveParagraphBullet, resolvePresenterNotes, resolveTransitionDuration, revealedElementStyles, routeOrthogonalConnector, sanitizeColor, sanitizeSlideIndex, sanitizeUserName, searchSlides, seedBroadcastFields, seedHyperlinkDraft, seedPropertiesDraft, seedShareFields, segmentFrameCount, sendBackward, sendToBack, setElementPosition, signatureCountLabel, signatureKey, signatureTimestamp, signerName, statusKind, statusLabel, themeStyle, themeToCssVars, toggleCommentResolvedInList, updateElementById, validatePrintSettings, validateRoomId, waypointsToPathD, worstStatus };
|
|
5182
|
+
export type { AccessibilityIssueGroup, AnimationClickGroup, Box, BroadcastConfig, BroadcastDefaults, CSSProperties, CanvasSize, ClassValue, CollaborationConfig, CollaborationRole, Rect as ConnectorObstacle, Point as ConnectorPoint, ConnectorRouting, DocumentProperties, DuotoneFilterDef, EmbeddedFontStyles, FindOptions, FindResult, GifFrame, GifFramePlan, GifPlanOptions, HandoutSlidesPerPage, HyperlinkDraft, NotesSegmentViewModel, ObjectUrlFactory, OverallSignatureStatus, PresenterNotes, PrintColorMode, PrintDocumentOptions, PrintOrientation, PrintSettings, PrintSlideRange, PrintWhat, PropertiesDraft, RecordWebmOptions, RemoteCursor, RemotePresence, ReplaceResult, ResizeHandle, ResolvedFontVariant, ShareDefaults, ShareFormFields, SignatureStatusKind, SlideTransitionAnimations, StyleMap, TimerProgress, VideoPlanOptions, VideoSegmentPlan, ViewerTheme, ViewerThemeColors };
|