pptx-angular-viewer 1.30.0 → 1.30.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +6 -0
- package/README.md +55 -20
- package/fesm2022/pptx-angular-viewer.mjs +43 -2
- package/fesm2022/pptx-angular-viewer.mjs.map +1 -1
- package/package.json +2 -2
- package/types/pptx-angular-viewer.d.ts +15 -1
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,12 @@ 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.30.0](https://github.com/ChristopherVR/pptx-viewer/releases/tag/pptx-angular-viewer@1.30.0) - 2026-07-18
|
|
8
|
+
|
|
9
|
+
### Features
|
|
10
|
+
|
|
11
|
+
- **angular:** Promote RibbonComponent for independent composition (by @ChristopherVR) ([00ab33e](https://github.com/ChristopherVR/pptx-viewer/commit/00ab33e515857cd60a5aef01537c1024297e08e5))
|
|
12
|
+
|
|
7
13
|
## [1.29.0](https://github.com/ChristopherVR/pptx-viewer/releases/tag/pptx-angular-viewer@1.29.0) - 2026-07-18
|
|
8
14
|
|
|
9
15
|
### Dependencies
|
package/README.md
CHANGED
|
@@ -14,8 +14,6 @@ The rendering is done by the framework-agnostic [`pptx-viewer-core`](https://www
|
|
|
14
14
|
|
|
15
15
|
<samp>**[▶️ Try the live demo](https://christophervr.github.io/pptx-viewer/demo-angular/)** · **[📦 npm](https://www.npmjs.com/package/pptx-angular-viewer)** · **[📖 Full docs](https://christophervr.github.io/pptx-viewer/)** · **[🧩 Core SDK](https://www.npmjs.com/package/pptx-viewer-core)**</samp>
|
|
16
16
|
|
|
17
|
-
> **[▶️ Try the live demo](https://christophervr.github.io/pptx-viewer/demo-angular/)**: open a `.pptx` and render it in your browser, no install required.
|
|
18
|
-
|
|
19
17
|
## Features
|
|
20
18
|
|
|
21
19
|
- **Standalone component**: `<pptx-viewer>`, no NgModule needed.
|
|
@@ -48,7 +46,18 @@ The rendering is done by the framework-agnostic [`pptx-viewer-core`](https://www
|
|
|
48
46
|
npm install pptx-angular-viewer
|
|
49
47
|
```
|
|
50
48
|
|
|
51
|
-
**Peer requirements:** Angular 22+ (`@angular/core`, `@angular/common`)
|
|
49
|
+
**Peer requirements:** Angular 22+ (`@angular/core`, `@angular/common`), `rxjs`,
|
|
50
|
+
and `@ngx-translate/core` (all UI labels go through it, see
|
|
51
|
+
[Localization](#localization-i18n)):
|
|
52
|
+
|
|
53
|
+
```bash
|
|
54
|
+
npm install @angular/core @angular/common rxjs @ngx-translate/core
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
**Optional peers:** `three` enables interactive GLB/GLTF 3D models and the
|
|
58
|
+
`smartArt3D` renderer; `yjs` + `y-websocket` (or `y-webrtc` for serverless
|
|
59
|
+
peer-to-peer) enable real-time collaboration. Without them those features
|
|
60
|
+
degrade gracefully (poster images, no live session).
|
|
52
61
|
|
|
53
62
|
## Usage
|
|
54
63
|
|
|
@@ -205,26 +214,43 @@ and `LoadContentService` are the two nearly everything depends on).
|
|
|
205
214
|
|
|
206
215
|
### Inputs
|
|
207
216
|
|
|
208
|
-
| Input
|
|
209
|
-
|
|
|
210
|
-
| `content`
|
|
211
|
-
| `theme`
|
|
212
|
-
| `class`
|
|
213
|
-
| `canEdit`
|
|
214
|
-
| `
|
|
215
|
-
| `
|
|
217
|
+
| Input | Type | Default | Description |
|
|
218
|
+
| ------------------ | ------------------------------------ | ------- | ---------------------------------------------------------------------------------------------------------------------- |
|
|
219
|
+
| `content` | `Uint8Array \| ArrayBuffer \| null` | `null` | The `.pptx` bytes to render. |
|
|
220
|
+
| `theme` | `ViewerTheme` | n/a | Color/radius overrides applied as CSS custom properties. Always wins over the File > Options theme picker. |
|
|
221
|
+
| `class` | `string` | `''` | Class applied to the root element. |
|
|
222
|
+
| `canEdit` | `boolean` | `false` | Enables the editor toolbar, inspector, and drag-and-drop editing. |
|
|
223
|
+
| `filePath` | `string` | n/a | Host file path/identifier keying the version-history store. |
|
|
224
|
+
| `fileName` | `string` | n/a | Display name of the open document, shown in the title bar. |
|
|
225
|
+
| `fonts` | `ViewerFontSource[]` | `[]` | Licensed font sources supplied by the host application. |
|
|
226
|
+
| `authorName` | `string` | n/a | Display name for the local user in collaboration/broadcast sessions and presence avatars. |
|
|
227
|
+
| `collaboration` | `CollaborationConfig` | n/a | Yjs real-time collaboration config (server URL, room, role). |
|
|
228
|
+
| `shareDefaults` | `{ roomId?, userName?, serverUrl? }` | n/a | Seed values for the Share dialog's start form. |
|
|
229
|
+
| `onOpenFile` | `() => void` | n/a | Host override for File > Open; bypasses the built-in file picker. |
|
|
230
|
+
| `smartArt3D` | `boolean` | `false` | Opt-in Three.js 3D SmartArt renderer (needs the optional `three` peer; falls back to SVG without it). |
|
|
231
|
+
| `hiddenActions` | `ToolbarActionId[]` | `[]` | Toolbar buttons/ribbon tabs to hide individually (e.g. `['share', 'broadcast']`), instead of hiding the whole toolbar. |
|
|
232
|
+
| `defaultThemeKey` | `string` | n/a | Initial File > Options > Appearance selection when no persisted preference exists. |
|
|
233
|
+
| `availableThemes` | `ThemeCatalogEntry[]` | n/a | Theme choices offered by File > Options > Appearance (defaults to the built-in catalog). |
|
|
234
|
+
| `onThemeChange` | `(key: string) => void` | n/a | Host hook for the appearance picker; when set, the host owns persisting the choice. |
|
|
235
|
+
| `defaultLocale` | `string` | n/a | Initial locale code when no persisted preference exists. |
|
|
236
|
+
| `availableLocales` | `LocaleCatalogEntry[]` | n/a | Locale choices offered by File > Options > Language (defaults to the registered `TranslateService` languages). |
|
|
237
|
+
| `onLocaleChange` | `(code: string) => void` | n/a | Host hook for the language picker; when set, the host owns applying/persisting the switch. |
|
|
238
|
+
| `accountAuth` | `AccountAuthConfig` | n/a | Optional sign-in hook point for File > Account (disabled unless `enabled: true`). |
|
|
216
239
|
|
|
217
240
|
### Outputs
|
|
218
241
|
|
|
219
|
-
| Output
|
|
220
|
-
|
|
|
221
|
-
| `activeSlideChange`
|
|
222
|
-
| `dirtyChange`
|
|
223
|
-
| `contentChange`
|
|
224
|
-
| `modeChange`
|
|
225
|
-
| `zoomChange`
|
|
226
|
-
| `selectionChange`
|
|
227
|
-
| `slideCountChange`
|
|
242
|
+
| Output | Payload | Description |
|
|
243
|
+
| -------------------- | ----------------------------- | -------------------------------------------------------------------- |
|
|
244
|
+
| `activeSlideChange` | `number` | Emits the active slide index on navigation. |
|
|
245
|
+
| `dirtyChange` | `boolean` | Emits `true`/`false` when the dirty state changes. |
|
|
246
|
+
| `contentChange` | `Uint8Array` | Emits updated bytes after any editing change. |
|
|
247
|
+
| `modeChange` | `string` | Emits the new mode (`'preview'`, `'edit'`, `'present'`, `'master'`). |
|
|
248
|
+
| `zoomChange` | `number` | Emits the new zoom level (1 = 100%). |
|
|
249
|
+
| `selectionChange` | `string[]` | Emits the selected element IDs when selection changes. |
|
|
250
|
+
| `slideCountChange` | `number` | Emits the total slide count when slides change. |
|
|
251
|
+
| `propertiesChange` | `Partial<PptxCoreProperties>` | Emits when the user edits document properties in the Info dialog. |
|
|
252
|
+
| `startCollaboration` | `CollaborationConfig` | Emits when a collaboration/broadcast session starts. |
|
|
253
|
+
| `stopCollaboration` | `void` | Emits when the collaboration/broadcast session stops. |
|
|
228
254
|
|
|
229
255
|
### Methods
|
|
230
256
|
|
|
@@ -252,6 +278,15 @@ and `LoadContentService` are the two nearly everything depends on).
|
|
|
252
278
|
| `selectElements(ids)` | `void` | Programmatically select elements by ID. |
|
|
253
279
|
| `clearSelection()` | `void` | Clear the current selection. |
|
|
254
280
|
|
|
281
|
+
The component implements the full shared `PowerPointViewerAPI`, so the
|
|
282
|
+
following slide/element manipulation methods are also available:
|
|
283
|
+
`setActiveSlideIndex(index)`, `getSlides()`, `getSlide(index)`,
|
|
284
|
+
`getActiveSlide()`, `addSlide(afterIndex?)`, `deleteSlides(indexes)`,
|
|
285
|
+
`duplicateSlides(indexes)`, `moveSlide(from, to)`, `toggleHideSlides(indexes)`,
|
|
286
|
+
`getElements(slideIndex?)`, `getElementById(id, slideIndex?)`,
|
|
287
|
+
`updateElement(id, patch)`, `deleteElements(ids)`, and
|
|
288
|
+
`duplicateElement(id)`.
|
|
289
|
+
|
|
255
290
|
### Exported components & helpers
|
|
256
291
|
|
|
257
292
|
`PowerPointViewerComponent`, `SlideCanvasComponent`, `RibbonComponent`,
|
|
@@ -25116,7 +25116,12 @@ function decodeDelta(delta) {
|
|
|
25116
25116
|
/* skip */
|
|
25117
25117
|
}
|
|
25118
25118
|
}
|
|
25119
|
-
|
|
25119
|
+
// '\n' is only the synthetic break marker when the op carries a break
|
|
25120
|
+
// attribute; a literal newline TEXT run (no pb/lb) must keep its text or
|
|
25121
|
+
// runs like "Project\nAtlas" collapse to "ProjectAtlas" on decode. The
|
|
25122
|
+
// zero-width space is always the empty-run attribute holder.
|
|
25123
|
+
const isBreakMarker = op.insert === '\n' && (a.pb === '1' || a.lb === '1');
|
|
25124
|
+
if (!isBreakMarker && op.insert !== '') {
|
|
25120
25125
|
seg.text = op.insert;
|
|
25121
25126
|
}
|
|
25122
25127
|
segments.push(seg);
|
|
@@ -44379,6 +44384,33 @@ class CollaborationService {
|
|
|
44379
44384
|
seedBaseline(slides) {
|
|
44380
44385
|
this.lastSynced = JSON.stringify(slides);
|
|
44381
44386
|
}
|
|
44387
|
+
/**
|
|
44388
|
+
* Re-adopt the shared document's slides after a local content load has been
|
|
44389
|
+
* committed to viewer state. The load pipeline applies its parsed deck
|
|
44390
|
+
* unconditionally, so a load that finishes AFTER the room's slides were
|
|
44391
|
+
* already applied (a late joiner's bootstrap deck parsing slower than the
|
|
44392
|
+
* doc sync) silently clobbers the synced state and, with the doc itself
|
|
44393
|
+
* unchanged, the remote observer never re-fires. When the room already has
|
|
44394
|
+
* slides they win: the doc content is re-applied through `onRemoteSlides`
|
|
44395
|
+
* and recorded as the sync baseline (bypassing the usual JSON dedupe) so
|
|
44396
|
+
* the follow-up local broadcast of the adopted deck is a no-op. An empty
|
|
44397
|
+
* room means this client is the seeder and the loaded deck stands, written
|
|
44398
|
+
* by the normal gated broadcast path. Returns true when the doc was adopted.
|
|
44399
|
+
*/
|
|
44400
|
+
adoptDocSlidesAfterLoad() {
|
|
44401
|
+
if (!this.ydoc || !this.connected()) {
|
|
44402
|
+
return false;
|
|
44403
|
+
}
|
|
44404
|
+
const docSlides = readSlidesFromYDoc(this.ydoc);
|
|
44405
|
+
if (docSlides.length === 0) {
|
|
44406
|
+
return false;
|
|
44407
|
+
}
|
|
44408
|
+
this.lastSynced = JSON.stringify(docSlides);
|
|
44409
|
+
this.applyingRemote = true;
|
|
44410
|
+
this.onRemoteSlides?.(docSlides);
|
|
44411
|
+
this.applyingRemote = false;
|
|
44412
|
+
return true;
|
|
44413
|
+
}
|
|
44382
44414
|
broadcastSlides(slides) {
|
|
44383
44415
|
if (!this.ydoc || !this.yFactories || this.applyingRemote || slides.length === 0) {
|
|
44384
44416
|
return;
|
|
@@ -72505,7 +72537,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.7", ngImpor
|
|
|
72505
72537
|
}], propDecorators: { canEdit: [{ type: i0.Input, args: [{ isSignal: true, alias: "canEdit", required: false }] }], slideIndex: [{ type: i0.Input, args: [{ isSignal: true, alias: "slideIndex", required: false }] }] } });
|
|
72506
72538
|
|
|
72507
72539
|
// Generated by scripts/inline-shared.mjs from package.json. Do not edit.
|
|
72508
|
-
const PPTX_ANGULAR_VIEWER_VERSION = "1.
|
|
72540
|
+
const PPTX_ANGULAR_VIEWER_VERSION = "1.30.0";
|
|
72509
72541
|
|
|
72510
72542
|
/**
|
|
72511
72543
|
* account-page.component.ts: File > Account content.
|
|
@@ -95648,6 +95680,15 @@ class PowerPointViewerComponent {
|
|
|
95648
95680
|
untracked(() => {
|
|
95649
95681
|
this.editor.setSlides(slides, this.loader.sections());
|
|
95650
95682
|
this.activeSlideIndex.set(0);
|
|
95683
|
+
// A load that lands mid-session must not clobber remotely synced
|
|
95684
|
+
// slides: when the shared doc already holds the room's content, a
|
|
95685
|
+
// late joiner's bootstrap deck (parsed slower than the doc sync)
|
|
95686
|
+
// would silently overwrite it here and, with the doc unchanged,
|
|
95687
|
+
// never see it re-applied. Re-adopt the doc's slides synchronously
|
|
95688
|
+
// so the broadcast effect below (which only runs after this effect
|
|
95689
|
+
// completes) sees the adopted deck, never the placeholder, and its
|
|
95690
|
+
// write dedupes against the adopted baseline.
|
|
95691
|
+
this.collab.adoptDocSlidesAfterLoad();
|
|
95651
95692
|
});
|
|
95652
95693
|
});
|
|
95653
95694
|
// Selecting an element re-opens the inspector if a prior swipe had hidden
|