pptx-angular-viewer 1.5.2 → 1.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -4,6 +4,10 @@ All notable changes to this project are documented here.
4
4
  This file is generated from [Conventional Commits](https://www.conventionalcommits.org)
5
5
  by [git-cliff](https://git-cliff.org); do not edit it by hand.
6
6
 
7
+ ## [1.5.3](https://github.com/ChristopherVR/pptx-viewer/releases/tag/pptx-angular-viewer@1.5.3) - 2026-07-04
8
+
9
+ ## [1.5.2](https://github.com/ChristopherVR/pptx-viewer/releases/tag/pptx-angular-viewer@1.5.2) - 2026-07-04
10
+
7
11
  ## [1.5.1](https://github.com/ChristopherVR/pptx-viewer/releases/tag/pptx-angular-viewer@1.5.1) - 2026-07-04
8
12
 
9
13
  ## [1.5.0](https://github.com/ChristopherVR/pptx-viewer/releases/tag/pptx-angular-viewer@1.5.0) - 2026-07-04
package/README.md CHANGED
@@ -143,17 +143,41 @@ async save() {
143
143
 
144
144
  ### Outputs
145
145
 
146
- | Output | Payload | Description |
147
- | ------------------- | ------------ | -------------------------------------------------- |
148
- | `activeSlideChange` | `number` | Emits the active slide index on navigation. |
149
- | `dirtyChange` | `boolean` | Emits `true`/`false` when the dirty state changes. |
150
- | `contentChange` | `Uint8Array` | Emits updated bytes after any editing change. |
146
+ | Output | Payload | Description |
147
+ | ------------------- | ------------ | -------------------------------------------------------------------- |
148
+ | `activeSlideChange` | `number` | Emits the active slide index on navigation. |
149
+ | `dirtyChange` | `boolean` | Emits `true`/`false` when the dirty state changes. |
150
+ | `contentChange` | `Uint8Array` | Emits updated bytes after any editing change. |
151
+ | `modeChange` | `string` | Emits the new mode (`'preview'`, `'edit'`, `'present'`, `'master'`). |
152
+ | `zoomChange` | `number` | Emits the new zoom level (1 = 100%). |
153
+ | `selectionChange` | `string[]` | Emits the selected element IDs when selection changes. |
154
+ | `slideCountChange` | `number` | Emits the total slide count when slides change. |
151
155
 
152
156
  ### Methods
153
157
 
154
- | Method | Returns | Description |
155
- | -------------- | --------------------- | ---------------------------------------------- |
156
- | `getContent()` | `Promise<Uint8Array>` | Serialise the current presentation to `.pptx`. |
158
+ | Method | Returns | Description |
159
+ | ------------------------- | --------------------- | ---------------------------------------------- |
160
+ | `getContent()` | `Promise<Uint8Array>` | Serialise the current presentation to `.pptx`. |
161
+ | `goTo(index)` | `void` | Navigate to a slide by zero-based index. |
162
+ | `goPrev()` | `void` | Navigate to the previous slide. |
163
+ | `goNext()` | `void` | Navigate to the next slide. |
164
+ | `undo()` | `void` | Undo the last editing action. |
165
+ | `redo()` | `void` | Redo the last undone action. |
166
+ | `canUndo()` | `boolean` | Whether an undo action is available. |
167
+ | `canRedo()` | `boolean` | Whether a redo action is available. |
168
+ | `getZoom()` | `number` | Get the current zoom level. |
169
+ | `setZoom(level)` | `void` | Set the zoom level (clamped to 0.2 - 3.0). |
170
+ | `zoomIn()` | `void` | Zoom in by one step. |
171
+ | `zoomOut()` | `void` | Zoom out by one step. |
172
+ | `zoomReset()` | `void` | Reset zoom to 100%. |
173
+ | `getMode()` | `string` | Get the current viewer mode. |
174
+ | `setMode(mode)` | `void` | Switch mode programmatically. |
175
+ | `getActiveSlideIndex()` | `number` | Get the zero-based active slide index. |
176
+ | `getSlideCount()` | `number` | Get the total number of slides. |
177
+ | `isDirty()` | `boolean` | Whether the document has unsaved changes. |
178
+ | `getSelectedElementIds()` | `string[]` | Get IDs of currently selected elements. |
179
+ | `selectElements(ids)` | `void` | Programmatically select elements by ID. |
180
+ | `clearSelection()` | `void` | Clear the current selection. |
157
181
 
158
182
  ### Exported components & helpers
159
183
 
@@ -180,18 +204,12 @@ Unlike React/Vue, `translationsEn`, `keyToLabel`, and the `TranslationKey` type
180
204
 
181
205
  ## Limitations
182
206
 
183
- The Angular package has reached functional parity with the React package: all 11
184
- element types render; the full Tailwind 4 Office ribbon is wired; editing
185
- (including slide master/layout template editing), presentation, export,
186
- collaboration, comments, and mobile chrome all work. The remaining items are
187
- polish/cosmetic, not behavioural gaps:
188
-
189
- - **Pixel-level cosmetic differences** - Some toolbar controls are not pixel-
190
- identical to their React counterparts (spacing, split-button affordances,
191
- dropdown chrome).
192
207
  - **3D models need the Three.js peer** - GLB/GLTF models render interactively when
193
208
  the optional `three` peer dependency is installed, and fall back to their poster
194
- image otherwise (the same as the React package).
209
+ image otherwise.
210
+ - **CSS-rendering approximations** - A handful of effects (`backdrop-filter`, path
211
+ gradients) are approximated on screen, and a few effects flatten in raster
212
+ export; see the root README's Limitations for details.
195
213
 
196
214
  The `pptx-viewer-core` engine parses all element data, so you can access it from
197
215
  the model even where the UI does not expose it yet.
@@ -78861,6 +78861,14 @@ class PowerPointViewerComponent {
78861
78861
  contentChange = output();
78862
78862
  /** Fired when the user edits document properties in the Info dialog. */
78863
78863
  propertiesChange = output();
78864
+ /** Fired when the viewer mode changes (preview, edit, present, master). */
78865
+ modeChange = output();
78866
+ /** Fired when the zoom level changes. */
78867
+ zoomChange = output();
78868
+ /** Fired when element selection changes. */
78869
+ selectionChange = output();
78870
+ /** Fired when the total slide count changes (slide added/deleted). */
78871
+ slideCountChange = output();
78864
78872
  /**
78865
78873
  * Fired when a collaboration/broadcast session starts, with the connected
78866
78874
  * config (role `collaborator` for Share, `owner` for Broadcast). Lets the
@@ -79069,6 +79077,29 @@ class PowerPointViewerComponent {
79069
79077
  effect(() => {
79070
79078
  this.dirtyChange.emit(this.editor.dirty());
79071
79079
  });
79080
+ // Emit mode changes.
79081
+ effect(() => {
79082
+ const mode = this.presentationMode.presenting()
79083
+ ? 'present'
79084
+ : this.editor.editTemplateMode()
79085
+ ? 'master'
79086
+ : this.canEdit()
79087
+ ? 'edit'
79088
+ : 'preview';
79089
+ this.modeChange.emit(mode);
79090
+ });
79091
+ // Emit zoom changes.
79092
+ effect(() => {
79093
+ this.zoomChange.emit(this.zoomSvc.zoom());
79094
+ });
79095
+ // Emit selection changes.
79096
+ effect(() => {
79097
+ this.selectionChange.emit([...this.editor.selectedIds()]);
79098
+ });
79099
+ // Emit slide count changes.
79100
+ effect(() => {
79101
+ this.slideCountChange.emit(this.slideCount());
79102
+ });
79072
79103
  // Keep the active index in range when the deck shrinks (slide deleted).
79073
79104
  effect(() => {
79074
79105
  const count = this.displaySlides().length;
@@ -79278,6 +79309,162 @@ class PowerPointViewerComponent {
79278
79309
  goNext() {
79279
79310
  this.goTo(this.activeSlideIndex() + 1);
79280
79311
  }
79312
+ /** Undo the last editing action. No-op when nothing to undo. */
79313
+ undo() {
79314
+ this.editor.undo();
79315
+ }
79316
+ /** Redo the last undone action. No-op when nothing to redo. */
79317
+ redo() {
79318
+ this.editor.redo();
79319
+ }
79320
+ /** Whether an undo action is available. */
79321
+ canUndo() {
79322
+ return this.editor.canUndo();
79323
+ }
79324
+ /** Whether a redo action is available. */
79325
+ canRedo() {
79326
+ return this.editor.canRedo();
79327
+ }
79328
+ /** Get the current zoom level (1 = 100%). */
79329
+ getZoom() {
79330
+ return this.zoomSvc.zoom();
79331
+ }
79332
+ /** Set the zoom level (clamped to min/max bounds). */
79333
+ setZoom(level) {
79334
+ this.zoomSvc.zoom.set(Math.min(Math.max(level, 0.2), 3));
79335
+ }
79336
+ /** Zoom in by one step. */
79337
+ zoomIn() {
79338
+ this.zoomSvc.zoomIn();
79339
+ }
79340
+ /** Zoom out by one step. */
79341
+ zoomOut() {
79342
+ this.zoomSvc.zoomOut();
79343
+ }
79344
+ /** Reset zoom to 100%. */
79345
+ zoomReset() {
79346
+ this.zoomSvc.zoomReset();
79347
+ }
79348
+ /** Get the current viewer mode. */
79349
+ getMode() {
79350
+ if (this.presentationMode.presenting()) {
79351
+ return 'present';
79352
+ }
79353
+ if (this.editor.editTemplateMode()) {
79354
+ return 'master';
79355
+ }
79356
+ return this.canEdit() ? 'edit' : 'preview';
79357
+ }
79358
+ /** Switch the viewer mode (e.g. 'edit', 'preview', 'present'). */
79359
+ setMode(mode) {
79360
+ if (mode === 'present') {
79361
+ this.presentationMode.present();
79362
+ }
79363
+ else if (mode === 'master') {
79364
+ this.editor.setEditTemplateMode(true);
79365
+ }
79366
+ else {
79367
+ this.presentationMode.presenting.set(false);
79368
+ this.editor.setEditTemplateMode(false);
79369
+ }
79370
+ }
79371
+ /** Get the zero-based active slide index. */
79372
+ getActiveSlideIndex() {
79373
+ return this.activeSlideIndex();
79374
+ }
79375
+ /** Get the total number of slides. */
79376
+ getSlideCount() {
79377
+ return this.slideCount();
79378
+ }
79379
+ /** Whether the document has unsaved changes. */
79380
+ isDirty() {
79381
+ return this.editor.dirty();
79382
+ }
79383
+ /** Get the IDs of currently selected elements. */
79384
+ getSelectedElementIds() {
79385
+ return [...this.editor.selectedIds()];
79386
+ }
79387
+ /** Programmatically select elements by their IDs. */
79388
+ selectElements(ids) {
79389
+ this.editor.selectedIds.set(ids);
79390
+ }
79391
+ /** Clear the current selection. */
79392
+ clearSelection() {
79393
+ this.editor.selectedIds.set([]);
79394
+ }
79395
+ /** Set the active slide by zero-based index (alias of goTo). */
79396
+ setActiveSlideIndex(index) {
79397
+ this.goTo(index);
79398
+ }
79399
+ /** Get a read-only reference to all slides. */
79400
+ getSlides() {
79401
+ return this.displaySlides();
79402
+ }
79403
+ /** Get a single slide by zero-based index. */
79404
+ getSlide(index) {
79405
+ return this.displaySlides()[index];
79406
+ }
79407
+ /** Get the currently active slide. */
79408
+ getActiveSlide() {
79409
+ return this.displaySlides()[this.activeSlideIndex()];
79410
+ }
79411
+ /** Add a blank slide after the given index (or after the active slide). */
79412
+ addSlide(afterIndex) {
79413
+ const idx = afterIndex ?? this.activeSlideIndex();
79414
+ this.editor.addSlide(idx);
79415
+ }
79416
+ /** Delete slides at the given zero-based indexes. */
79417
+ deleteSlides(indexes) {
79418
+ for (const i of [...indexes].sort((a, b) => b - a)) {
79419
+ this.editor.deleteSlide(i);
79420
+ }
79421
+ }
79422
+ /** Duplicate slides at the given zero-based indexes. */
79423
+ duplicateSlides(indexes) {
79424
+ for (const i of indexes) {
79425
+ this.editor.duplicateSlide(i);
79426
+ }
79427
+ }
79428
+ /** Move a slide from one position to another. */
79429
+ moveSlide(fromIndex, toIndex) {
79430
+ this.editor.moveSlide(fromIndex, toIndex);
79431
+ }
79432
+ /** Toggle the hidden flag on slides at the given indexes. */
79433
+ toggleHideSlides(indexes) {
79434
+ for (const i of indexes) {
79435
+ const s = this.displaySlides()[i];
79436
+ if (s) {
79437
+ this.editor.updateSlide(i, { hidden: !s.hidden });
79438
+ }
79439
+ }
79440
+ }
79441
+ /** Get elements on a slide (defaults to active slide). */
79442
+ getElements(slideIndex) {
79443
+ const idx = slideIndex ?? this.activeSlideIndex();
79444
+ const s = this.displaySlides()[idx];
79445
+ return s?.elements ?? [];
79446
+ }
79447
+ /** Get a single element by ID. */
79448
+ getElementById(elementId, slideIndex) {
79449
+ const idx = slideIndex ?? this.activeSlideIndex();
79450
+ const s = this.displaySlides()[idx];
79451
+ return s?.elements.find((e) => e.id === elementId);
79452
+ }
79453
+ /** Update one or more properties of an element by ID. */
79454
+ updateElement(elementId, updates) {
79455
+ this.editor.updateElement(this.activeSlideIndex(), elementId, updates);
79456
+ }
79457
+ /** Delete elements by their IDs from the active slide. */
79458
+ deleteElements(elementIds) {
79459
+ this.editor.selectedIds.set(elementIds);
79460
+ this.editor.deleteSelected(this.activeSlideIndex());
79461
+ }
79462
+ /** Duplicate an element. Returns the new element's ID. */
79463
+ duplicateElement(elementId) {
79464
+ this.editor.selectedIds.set([elementId]);
79465
+ this.editor.duplicateSelected(this.activeSlideIndex());
79466
+ return this.editor.selectedIds()[0];
79467
+ }
79281
79468
  /** Toggle the Find & Replace panel from the title-bar search button. */
79282
79469
  toggleFindReplace() {
79283
79470
  if (this.findReplace.showFindReplace()) {
@@ -79371,7 +79558,7 @@ class PowerPointViewerComponent {
79371
79558
  return (this.mainEl()?.nativeElement.querySelector('.pptx-ng-canvas-stage') ?? undefined);
79372
79559
  }
79373
79560
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.5", ngImport: i0, type: PowerPointViewerComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
79374
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.5", type: PowerPointViewerComponent, isStandalone: true, selector: "pptx-viewer", inputs: { content: { classPropertyName: "content", publicName: "content", isSignal: true, isRequired: false, transformFunction: null }, canEdit: { classPropertyName: "canEdit", publicName: "canEdit", isSignal: true, isRequired: false, transformFunction: null }, class: { classPropertyName: "class", publicName: "class", isSignal: true, isRequired: false, transformFunction: null }, theme: { classPropertyName: "theme", publicName: "theme", isSignal: true, isRequired: false, transformFunction: null }, filePath: { classPropertyName: "filePath", publicName: "filePath", isSignal: true, isRequired: false, transformFunction: null }, fileName: { classPropertyName: "fileName", publicName: "fileName", isSignal: true, isRequired: false, transformFunction: null }, collaboration: { classPropertyName: "collaboration", publicName: "collaboration", isSignal: true, isRequired: false, transformFunction: null }, authorName: { classPropertyName: "authorName", publicName: "authorName", isSignal: true, isRequired: false, transformFunction: null }, shareDefaults: { classPropertyName: "shareDefaults", publicName: "shareDefaults", isSignal: true, isRequired: false, transformFunction: null }, onOpenFile: { classPropertyName: "onOpenFile", publicName: "onOpenFile", isSignal: true, isRequired: false, transformFunction: null }, smartArt3D: { classPropertyName: "smartArt3D", publicName: "smartArt3D", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { activeSlideChange: "activeSlideChange", dirtyChange: "dirtyChange", contentChange: "contentChange", propertiesChange: "propertiesChange", startCollaboration: "startCollaboration", stopCollaboration: "stopCollaboration" }, host: { listeners: { "document:keydown": "onKeyDown($event)" } }, providers: [
79561
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.5", type: PowerPointViewerComponent, isStandalone: true, selector: "pptx-viewer", inputs: { content: { classPropertyName: "content", publicName: "content", isSignal: true, isRequired: false, transformFunction: null }, canEdit: { classPropertyName: "canEdit", publicName: "canEdit", isSignal: true, isRequired: false, transformFunction: null }, class: { classPropertyName: "class", publicName: "class", isSignal: true, isRequired: false, transformFunction: null }, theme: { classPropertyName: "theme", publicName: "theme", isSignal: true, isRequired: false, transformFunction: null }, filePath: { classPropertyName: "filePath", publicName: "filePath", isSignal: true, isRequired: false, transformFunction: null }, fileName: { classPropertyName: "fileName", publicName: "fileName", isSignal: true, isRequired: false, transformFunction: null }, collaboration: { classPropertyName: "collaboration", publicName: "collaboration", isSignal: true, isRequired: false, transformFunction: null }, authorName: { classPropertyName: "authorName", publicName: "authorName", isSignal: true, isRequired: false, transformFunction: null }, shareDefaults: { classPropertyName: "shareDefaults", publicName: "shareDefaults", isSignal: true, isRequired: false, transformFunction: null }, onOpenFile: { classPropertyName: "onOpenFile", publicName: "onOpenFile", isSignal: true, isRequired: false, transformFunction: null }, smartArt3D: { classPropertyName: "smartArt3D", publicName: "smartArt3D", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { activeSlideChange: "activeSlideChange", dirtyChange: "dirtyChange", contentChange: "contentChange", propertiesChange: "propertiesChange", modeChange: "modeChange", zoomChange: "zoomChange", selectionChange: "selectionChange", slideCountChange: "slideCountChange", startCollaboration: "startCollaboration", stopCollaboration: "stopCollaboration" }, host: { listeners: { "document:keydown": "onKeyDown($event)" } }, providers: [
79375
79562
  LoadContentService,
79376
79563
  ExportService,
79377
79564
  EditorStateService,
@@ -80659,7 +80846,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.5", ngImpor
80659
80846
  </div>
80660
80847
  `,
80661
80848
  }]
80662
- }], ctorParameters: () => [], propDecorators: { content: [{ type: i0.Input, args: [{ isSignal: true, alias: "content", required: false }] }], canEdit: [{ type: i0.Input, args: [{ isSignal: true, alias: "canEdit", required: false }] }], class: [{ type: i0.Input, args: [{ isSignal: true, alias: "class", required: false }] }], theme: [{ type: i0.Input, args: [{ isSignal: true, alias: "theme", required: false }] }], filePath: [{ type: i0.Input, args: [{ isSignal: true, alias: "filePath", required: false }] }], fileName: [{ type: i0.Input, args: [{ isSignal: true, alias: "fileName", required: false }] }], collaboration: [{ type: i0.Input, args: [{ isSignal: true, alias: "collaboration", required: false }] }], authorName: [{ type: i0.Input, args: [{ isSignal: true, alias: "authorName", required: false }] }], shareDefaults: [{ type: i0.Input, args: [{ isSignal: true, alias: "shareDefaults", required: false }] }], onOpenFile: [{ type: i0.Input, args: [{ isSignal: true, alias: "onOpenFile", required: false }] }], smartArt3D: [{ type: i0.Input, args: [{ isSignal: true, alias: "smartArt3D", required: false }] }], activeSlideChange: [{ type: i0.Output, args: ["activeSlideChange"] }], dirtyChange: [{ type: i0.Output, args: ["dirtyChange"] }], contentChange: [{ type: i0.Output, args: ["contentChange"] }], propertiesChange: [{ type: i0.Output, args: ["propertiesChange"] }], startCollaboration: [{ type: i0.Output, args: ["startCollaboration"] }], stopCollaboration: [{ type: i0.Output, args: ["stopCollaboration"] }], extraDialogs: [{ type: i0.ViewChild, args: [i0.forwardRef(() => ViewerExtraDialogsComponent), { isSignal: true }] }], mainEl: [{ type: i0.ViewChild, args: ['mainEl', { isSignal: true }] }], onKeyDown: [{
80849
+ }], ctorParameters: () => [], propDecorators: { content: [{ type: i0.Input, args: [{ isSignal: true, alias: "content", required: false }] }], canEdit: [{ type: i0.Input, args: [{ isSignal: true, alias: "canEdit", required: false }] }], class: [{ type: i0.Input, args: [{ isSignal: true, alias: "class", required: false }] }], theme: [{ type: i0.Input, args: [{ isSignal: true, alias: "theme", required: false }] }], filePath: [{ type: i0.Input, args: [{ isSignal: true, alias: "filePath", required: false }] }], fileName: [{ type: i0.Input, args: [{ isSignal: true, alias: "fileName", required: false }] }], collaboration: [{ type: i0.Input, args: [{ isSignal: true, alias: "collaboration", required: false }] }], authorName: [{ type: i0.Input, args: [{ isSignal: true, alias: "authorName", required: false }] }], shareDefaults: [{ type: i0.Input, args: [{ isSignal: true, alias: "shareDefaults", required: false }] }], onOpenFile: [{ type: i0.Input, args: [{ isSignal: true, alias: "onOpenFile", required: false }] }], smartArt3D: [{ type: i0.Input, args: [{ isSignal: true, alias: "smartArt3D", required: false }] }], activeSlideChange: [{ type: i0.Output, args: ["activeSlideChange"] }], dirtyChange: [{ type: i0.Output, args: ["dirtyChange"] }], contentChange: [{ type: i0.Output, args: ["contentChange"] }], propertiesChange: [{ type: i0.Output, args: ["propertiesChange"] }], modeChange: [{ type: i0.Output, args: ["modeChange"] }], zoomChange: [{ type: i0.Output, args: ["zoomChange"] }], selectionChange: [{ type: i0.Output, args: ["selectionChange"] }], slideCountChange: [{ type: i0.Output, args: ["slideCountChange"] }], startCollaboration: [{ type: i0.Output, args: ["startCollaboration"] }], stopCollaboration: [{ type: i0.Output, args: ["stopCollaboration"] }], extraDialogs: [{ type: i0.ViewChild, args: [i0.forwardRef(() => ViewerExtraDialogsComponent), { isSignal: true }] }], mainEl: [{ type: i0.ViewChild, args: ['mainEl', { isSignal: true }] }], onKeyDown: [{
80663
80850
  type: HostListener,
80664
80851
  args: ['document:keydown', ['$event']]
80665
80852
  }] } });