pptx-angular-viewer 1.3.1 → 1.4.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.
@@ -1,6 +1,6 @@
1
1
  import { NgStyle, NgClass } from '@angular/common';
2
2
  import * as i0 from '@angular/core';
3
- import { InjectionToken, input, output, computed, ChangeDetectionStrategy, Component, signal, Injectable, inject, DestroyRef, HostListener, effect, ElementRef, viewChild, afterNextRender, Injector } from '@angular/core';
3
+ import { InjectionToken, input, output, computed, ChangeDetectionStrategy, Component, signal, Injectable, inject, Injector, DestroyRef, effect, HostListener, ElementRef, viewChild, afterNextRender } from '@angular/core';
4
4
  import { TranslatePipe, translate, TranslateService } from '@ngx-translate/core';
5
5
  import { guideEmuToPx, getShapeClipPath, getAdjustmentAwareShapeClipPath, getShapeClipPathFromPreset, getCloudPathForRendering, hasShapeProperties, applyDrawingColorTransforms as applyDrawingColorTransforms$1, hslToRgb as hslToRgb$1, PRESET_COLOR_MAP, isImageLikeElement, hasTextProperties, MIN_ELEMENT_SIZE as MIN_ELEMENT_SIZE$2, THEME_COLOR_SCHEME_KEYS, getLinkedTextBoxSegments, svgPathToPolygons, deobfuscateFont, detectFontFormat, getSubstituteFontFamily, checkMissingAltText, checkMissingSlideTitle, checkLowContrast, checkComplexTables, checkBlankSlide, checkDuplicateTitles, createChartElement, formatCommentTimestamp as formatCommentTimestamp$1, PptxHandler, EncryptedFileError, parseSignatureXml, setChartTitle, setChartLegend, setChartDataLabels, setChartAxis, setChartSeriesTrendline, setChartSeriesErrorBars, setChartDataPointLabel, setChartAxisLogScale, setChartAxisTitleStyle, setChartAxisGridlineStyle, setChartSeriesMarker, setChartSeriesChartType, setChartDataPointFill, setChartDataPointExplosion, chartDataAddSeries, chartDataRemoveSeries, chartDataAddCategory, chartDataRemoveCategory, chartDataUpdatePoint, chartDataChangeType, setSmartArtNodeStyle, updateSmartArtNodeText, addSmartArtNodeAsChild, removeSmartArtNode, promoteSmartArtNode, demoteSmartArtNode, reorderSmartArtNode, switchSmartArtLayout, SWITCHABLE_LAYOUT_TYPES, isInkElement, parseDataUrlToBytes, isZoomElement, THEME_PRESETS, applyThemeToData, getAnimationPresetInfo } from 'pptx-viewer-core';
6
6
  import DOMPurify from 'dompurify';
@@ -32137,6 +32137,194 @@ const MATERIAL_PRESETS = [
32137
32137
  { value: 'translucentPowder', label: 'Translucent Powder' },
32138
32138
  ];
32139
32139
 
32140
+ /**
32141
+ * PowerPoint-style title bar: shared pure logic + Tailwind class tokens.
32142
+ *
32143
+ * The title bar is the top chrome row above the ribbon (AutoSave toggle,
32144
+ * quick-access Save/Undo/Redo, file name + save-location status, centred
32145
+ * search box). Every binding (React/Vue/Angular) renders its own thin view
32146
+ * from these tokens so the three stay pixel-identical.
32147
+ */
32148
+ /**
32149
+ * Resolve the i18n key for the save-status text shown next to the file name
32150
+ * (PowerPoint shows "Saved to this PC" there).
32151
+ */
32152
+ function resolveTitleBarStatusKey(input) {
32153
+ const { autosaveState, isDirty, autosaveEnabled } = input;
32154
+ if (autosaveEnabled && autosaveState === 'saving') {
32155
+ return 'pptx.autosave.saving';
32156
+ }
32157
+ if (autosaveEnabled && autosaveState === 'error') {
32158
+ return 'pptx.autosave.error';
32159
+ }
32160
+ if (isDirty) {
32161
+ return 'pptx.statusBar.unsavedChanges';
32162
+ }
32163
+ return 'pptx.titleBar.savedToThisPc';
32164
+ }
32165
+ /** Default document name shown when the host supplies no file name. */
32166
+ const TITLE_BAR_DEFAULT_FILE_KEY = 'pptx.titleBar.defaultFileName';
32167
+ // ---------------------------------------------------------------------------
32168
+ // Class tokens (Tailwind), shared verbatim by all three bindings
32169
+ // ---------------------------------------------------------------------------
32170
+ const TITLE_BAR_CLASSES = {
32171
+ /** Outer row container. Hidden on mobile (the compact toolbar covers it). */
32172
+ container: 'flex items-center gap-1 h-9 px-2 border-b border-border/60 bg-secondary/80 text-[11px] select-none max-md:hidden',
32173
+ /** Small square app mark on the far left. */
32174
+ logo: 'flex items-center justify-center w-5 h-5 rounded-sm bg-[#c43e1c] text-white text-[10px] font-bold shrink-0',
32175
+ /** Wrapper for the AutoSave label + switch. */
32176
+ autosaveGroup: 'flex items-center gap-1.5 pl-1.5 pr-0.5 shrink-0',
32177
+ autosaveLabel: 'text-[11px] text-muted-foreground whitespace-nowrap',
32178
+ /** Switch track, base classes; combine with on/off variant. */
32179
+ toggleTrack: 'relative inline-flex items-center w-7 h-3.5 rounded-full transition-colors cursor-pointer disabled:opacity-40 disabled:cursor-not-allowed',
32180
+ toggleTrackOn: 'bg-primary',
32181
+ toggleTrackOff: 'bg-muted-foreground/40',
32182
+ /** Switch knob, base classes; combine with on/off variant. */
32183
+ toggleKnob: 'absolute w-2.5 h-2.5 rounded-full bg-white shadow-sm transition-transform',
32184
+ toggleKnobOn: 'translate-x-[15px]',
32185
+ toggleKnobOff: 'translate-x-0.5',
32186
+ /** Quick-access icon button (Save / Undo / Redo). */
32187
+ quickButton: 'p-1 rounded-sm transition-colors hover:bg-accent/60 text-muted-foreground disabled:opacity-40 disabled:cursor-not-allowed active:scale-90 active:opacity-70',
32188
+ separator: 'w-px h-4 bg-border/60 mx-1 shrink-0',
32189
+ /** File name + status wrapper (centred block in PowerPoint sits left of search). */
32190
+ fileGroup: 'flex items-baseline gap-1.5 px-1 min-w-0 shrink',
32191
+ fileName: 'text-[12px] font-medium text-foreground whitespace-nowrap overflow-hidden text-ellipsis max-w-[240px]',
32192
+ statusDot: 'text-muted-foreground/70',
32193
+ statusText: 'text-[11px] text-muted-foreground whitespace-nowrap',
32194
+ statusError: 'text-red-400',
32195
+ statusSaving: 'text-yellow-500',
32196
+ /** Centred search area. */
32197
+ searchWrap: 'flex-1 flex justify-center min-w-0 px-2',
32198
+ searchBox: 'flex items-center gap-2 w-full max-w-md px-3 py-[3px] rounded-md bg-background/70 border border-border/60 text-muted-foreground hover:bg-background hover:text-foreground transition-colors',
32199
+ searchIcon: 'w-3 h-3 shrink-0',
32200
+ searchLabel: 'text-[11px] truncate',
32201
+ /** Right-hand spacer mirroring the left block so search stays centred. */
32202
+ rightSpacer: 'flex items-center justify-end gap-1 shrink-0',
32203
+ };
32204
+ /** Ribbon tab-row right-side actions (Record + Share live on the tab row). */
32205
+ const TAB_ROW_ACTION_CLASSES = {
32206
+ record: 'inline-flex items-center gap-1.5 px-2.5 py-1 mr-1 rounded-sm text-[11px] font-medium text-foreground hover:bg-accent/60 transition-colors whitespace-nowrap',
32207
+ recordDot: 'w-2 h-2 rounded-full bg-red-600 shrink-0',
32208
+ };
32209
+
32210
+ /**
32211
+ * IndexedDB-backed autosave recovery store, shared by every binding.
32212
+ *
32213
+ * Extracted from the React `useAutosave` hook so Vue/Angular reuse the same
32214
+ * database (`pptx-viewer-autosave` / `recoveryVersions`) instead of each
32215
+ * binding growing its own copy. Records are keyed by the host-supplied file
32216
+ * path; on quota exhaustion the oldest record is evicted and the write is
32217
+ * retried once.
32218
+ */
32219
+ const AUTOSAVE_DB_NAME = 'pptx-viewer-autosave';
32220
+ const AUTOSAVE_DB_VERSION = 1;
32221
+ const AUTOSAVE_STORE_NAME = 'recoveryVersions';
32222
+ /** Default autosave interval in seconds. */
32223
+ const AUTOSAVE_DEFAULT_INTERVAL_SECONDS = 120;
32224
+ /** Minimum allowed autosave interval in seconds. */
32225
+ const AUTOSAVE_MIN_INTERVAL_SECONDS = 10;
32226
+ /** Clamp a user-supplied interval (seconds) and convert to milliseconds. */
32227
+ function autosaveIntervalMs(intervalSeconds) {
32228
+ return Math.max(intervalSeconds, AUTOSAVE_MIN_INTERVAL_SECONDS) * 1000;
32229
+ }
32230
+ function openAutosaveDb$1() {
32231
+ return new Promise((resolve, reject) => {
32232
+ const req = indexedDB.open(AUTOSAVE_DB_NAME, AUTOSAVE_DB_VERSION);
32233
+ req.onupgradeneeded = () => {
32234
+ const db = req.result;
32235
+ if (!db.objectStoreNames.contains(AUTOSAVE_STORE_NAME)) {
32236
+ db.createObjectStore(AUTOSAVE_STORE_NAME, { keyPath: 'key' });
32237
+ }
32238
+ };
32239
+ req.onsuccess = () => resolve(req.result);
32240
+ req.onerror = () => reject(req.error);
32241
+ });
32242
+ }
32243
+ /** Delete the oldest entry in the autosave store. Returns true if one was removed. */
32244
+ async function deleteOldestAutosaveEntry() {
32245
+ const db = await openAutosaveDb$1();
32246
+ return new Promise((resolve) => {
32247
+ try {
32248
+ const tx = db.transaction(AUTOSAVE_STORE_NAME, 'readwrite');
32249
+ const store = tx.objectStore(AUTOSAVE_STORE_NAME);
32250
+ let oldestKey = null;
32251
+ let oldestTimestamp = Infinity;
32252
+ const cursorReq = store.openCursor();
32253
+ cursorReq.onsuccess = () => {
32254
+ const cursor = cursorReq.result;
32255
+ if (cursor) {
32256
+ const value = cursor.value;
32257
+ if (typeof value.timestamp === 'number' && value.timestamp < oldestTimestamp) {
32258
+ oldestTimestamp = value.timestamp;
32259
+ oldestKey = cursor.primaryKey;
32260
+ }
32261
+ cursor.continue();
32262
+ }
32263
+ else if (oldestKey !== null) {
32264
+ store.delete(oldestKey);
32265
+ }
32266
+ };
32267
+ tx.oncomplete = () => {
32268
+ db.close();
32269
+ resolve(oldestKey !== null);
32270
+ };
32271
+ tx.onerror = () => {
32272
+ db.close();
32273
+ resolve(false);
32274
+ };
32275
+ }
32276
+ catch {
32277
+ try {
32278
+ db.close();
32279
+ }
32280
+ catch {
32281
+ // Ignore
32282
+ }
32283
+ resolve(false);
32284
+ }
32285
+ });
32286
+ }
32287
+ function putAutosaveRecord(filePath, data) {
32288
+ return openAutosaveDb$1().then((db) => new Promise((resolve, reject) => {
32289
+ const tx = db.transaction(AUTOSAVE_STORE_NAME, 'readwrite');
32290
+ const store = tx.objectStore(AUTOSAVE_STORE_NAME);
32291
+ store.put({
32292
+ key: filePath,
32293
+ data,
32294
+ timestamp: Date.now(),
32295
+ size: data.byteLength,
32296
+ });
32297
+ tx.oncomplete = () => {
32298
+ db.close();
32299
+ resolve(true);
32300
+ };
32301
+ tx.onerror = () => {
32302
+ db.close();
32303
+ reject(tx.error);
32304
+ };
32305
+ }));
32306
+ }
32307
+ /**
32308
+ * Persist a recovery snapshot. On QuotaExceededError the oldest record is
32309
+ * dropped and the write retried once.
32310
+ */
32311
+ async function saveAutosaveSnapshot(filePath, data) {
32312
+ try {
32313
+ return await putAutosaveRecord(filePath, data);
32314
+ }
32315
+ catch (err) {
32316
+ const errName = err instanceof Error || err instanceof DOMException ? err.name : '';
32317
+ if (errName !== 'QuotaExceededError') {
32318
+ throw err;
32319
+ }
32320
+ const deleted = await deleteOldestAutosaveEntry();
32321
+ if (!deleted) {
32322
+ throw err;
32323
+ }
32324
+ return putAutosaveRecord(filePath, data);
32325
+ }
32326
+ }
32327
+
32140
32328
  /**
32141
32329
  * Framework-agnostic rendering & editing helpers shared by the React, Vue, and
32142
32330
  * Angular `pptx-viewer` bindings. Pure TypeScript (no framework imports) — each
@@ -34902,6 +35090,98 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.5", ngImpor
34902
35090
  type: Injectable
34903
35091
  }] });
34904
35092
 
35093
+ /**
35094
+ * autosave.service.ts: periodic recovery-snapshot autosave for the Angular
35095
+ * editor, the counterpart of React's `useAutosave` hook.
35096
+ *
35097
+ * Every N seconds (default {@link AUTOSAVE_DEFAULT_INTERVAL_SECONDS}, clamped by
35098
+ * the shared {@link autosaveIntervalMs}) it serialises the edited deck and writes
35099
+ * it to the shared IndexedDB recovery store via {@link saveAutosaveSnapshot} when
35100
+ * the document is dirty, a `filePath` key is set, autosave is enabled, and no
35101
+ * save is already in flight. The IndexedDB store itself lives in
35102
+ * `pptx-viewer-shared` so React/Vue/Angular share one recovery database.
35103
+ *
35104
+ * Provide it once on the viewer component (`providers: [AutosaveService]`). The
35105
+ * component wires its reactive accessors via {@link bind}; the resulting
35106
+ * {@link status} signal feeds both the title bar and the status bar.
35107
+ */
35108
+ class AutosaveService {
35109
+ injector = inject(Injector);
35110
+ destroyRef = inject(DestroyRef);
35111
+ /** Current autosave status, surfaced in the title bar and status bar. */
35112
+ status = signal({ state: 'idle' }, /* @ts-ignore */
35113
+ ...(ngDevMode ? [{ debugName: "status" }] : /* istanbul ignore next */ []));
35114
+ host = null;
35115
+ timer = null;
35116
+ saving = false;
35117
+ /**
35118
+ * Wire the host accessors (called once from the component constructor). An
35119
+ * effect re-establishes the interval whenever `enabled`, `filePath`, or the
35120
+ * interval length changes, matching React's interval-effect dependencies.
35121
+ */
35122
+ bind(host) {
35123
+ this.host = host;
35124
+ this.destroyRef.onDestroy(() => this.clearTimer());
35125
+ effect(() => {
35126
+ const enabled = host.enabled();
35127
+ const filePath = host.filePath();
35128
+ const seconds = host.intervalSeconds?.() ?? AUTOSAVE_DEFAULT_INTERVAL_SECONDS;
35129
+ this.clearTimer();
35130
+ if (!enabled || !filePath) {
35131
+ return;
35132
+ }
35133
+ this.timer = setInterval(() => {
35134
+ void this.doAutosave();
35135
+ }, autosaveIntervalMs(seconds));
35136
+ }, { injector: this.injector });
35137
+ }
35138
+ /** Manually trigger an autosave right now (mirrors React's `triggerAutosave`). */
35139
+ async triggerAutosave() {
35140
+ await this.doAutosave();
35141
+ }
35142
+ async doAutosave() {
35143
+ const host = this.host;
35144
+ if (!host) {
35145
+ return;
35146
+ }
35147
+ const filePath = host.filePath();
35148
+ if (!filePath || !host.isDirty() || this.saving) {
35149
+ return;
35150
+ }
35151
+ this.saving = true;
35152
+ this.status.set({ state: 'saving' });
35153
+ try {
35154
+ const data = await host.serialize();
35155
+ if (!data) {
35156
+ this.status.set({ state: 'idle' });
35157
+ return;
35158
+ }
35159
+ await saveAutosaveSnapshot(filePath, data);
35160
+ this.status.set({ state: 'saved', timestamp: Date.now() });
35161
+ }
35162
+ catch (err) {
35163
+ this.status.set({
35164
+ state: 'error',
35165
+ message: err instanceof Error ? err.message : 'Autosave failed',
35166
+ });
35167
+ }
35168
+ finally {
35169
+ this.saving = false;
35170
+ }
35171
+ }
35172
+ clearTimer() {
35173
+ if (this.timer !== null) {
35174
+ clearInterval(this.timer);
35175
+ this.timer = null;
35176
+ }
35177
+ }
35178
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.5", ngImport: i0, type: AutosaveService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
35179
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.0.5", ngImport: i0, type: AutosaveService });
35180
+ }
35181
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.5", ngImport: i0, type: AutosaveService, decorators: [{
35182
+ type: Injectable
35183
+ }] });
35184
+
34905
35185
  /**
34906
35186
  * broadcast-helpers.ts: thin re-export of the shared Broadcast-dialog helpers.
34907
35187
  *
@@ -69016,23 +69296,20 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.5", ngImpor
69016
69296
  * chrome, at parity with React's `toolbar/ToolbarPrimaryRow.tsx`.
69017
69297
  *
69018
69298
  * Layout (mirrors React):
69019
- * LEFT : slides-pane toggle, Undo, Redo, Find
69299
+ * LEFT : slides-pane toggle
69020
69300
  * RIGHT : Comments (with count), Present split-button + dropdown
69021
69301
  * (From Beginning / Presenter View / Broadcast), +Show (custom
69022
- * shows), Share, Inspector toggle, overflow "..." menu (exports /
69023
- * print / properties / accessibility / save).
69302
+ * shows), Inspector toggle, overflow "..." menu (exports / print /
69303
+ * properties / accessibility / save).
69024
69304
  *
69025
- * Slide navigation and zoom intentionally live in the bottom status bar (see
69026
- * {@link StatusBarComponent}), matching React. Undo/redo bind straight to the
69027
- * shared {@link EditorStateService}; everything else is an `output()` the
69028
- * {@link PowerPointViewerComponent} already handles.
69305
+ * Undo/Redo/Find and Save moved up to the title bar; Record and Share moved to
69306
+ * the ribbon tab row (both mirroring React). Slide navigation and zoom live in
69307
+ * the bottom status bar (see {@link StatusBarComponent}). Everything here is an
69308
+ * `output()` the {@link PowerPointViewerComponent} already handles.
69029
69309
  */
69030
69310
  class RibbonPrimaryRowComponent {
69031
- editor = inject(EditorStateService);
69032
69311
  slideCount = input(0, /* @ts-ignore */
69033
69312
  ...(ngDevMode ? [{ debugName: "slideCount" }] : /* istanbul ignore next */ []));
69034
- canEdit = input(false, /* @ts-ignore */
69035
- ...(ngDevMode ? [{ debugName: "canEdit" }] : /* istanbul ignore next */ []));
69036
69313
  sidebarCollapsed = input(false, /* @ts-ignore */
69037
69314
  ...(ngDevMode ? [{ debugName: "sidebarCollapsed" }] : /* istanbul ignore next */ []));
69038
69315
  inspectorOpen = input(false, /* @ts-ignore */
@@ -69041,20 +69318,12 @@ class RibbonPrimaryRowComponent {
69041
69318
  ...(ngDevMode ? [{ debugName: "commentsOpen" }] : /* istanbul ignore next */ []));
69042
69319
  commentCount = input(0, /* @ts-ignore */
69043
69320
  ...(ngDevMode ? [{ debugName: "commentCount" }] : /* istanbul ignore next */ []));
69044
- findOpen = input(false, /* @ts-ignore */
69045
- ...(ngDevMode ? [{ debugName: "findOpen" }] : /* istanbul ignore next */ []));
69046
- collabConnected = input(false, /* @ts-ignore */
69047
- ...(ngDevMode ? [{ debugName: "collabConnected" }] : /* istanbul ignore next */ []));
69048
- connectedCount = input(0, /* @ts-ignore */
69049
- ...(ngDevMode ? [{ debugName: "connectedCount" }] : /* istanbul ignore next */ []));
69050
69321
  toggleSidebar = output();
69051
- toggleFind = output();
69052
69322
  toggleComments = output();
69053
69323
  present = output();
69054
69324
  presenter = output();
69055
69325
  broadcast = output();
69056
69326
  openCustomShows = output();
69057
- share = output();
69058
69327
  toggleInspector = output();
69059
69328
  exportPng = output();
69060
69329
  exportPdf = output();
@@ -69112,9 +69381,9 @@ class RibbonPrimaryRowComponent {
69112
69381
  }
69113
69382
  }
69114
69383
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.5", ngImport: i0, type: RibbonPrimaryRowComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
69115
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.5", type: RibbonPrimaryRowComponent, isStandalone: true, selector: "pptx-ribbon-primary-row", inputs: { slideCount: { classPropertyName: "slideCount", publicName: "slideCount", isSignal: true, isRequired: false, transformFunction: null }, canEdit: { classPropertyName: "canEdit", publicName: "canEdit", isSignal: true, isRequired: false, transformFunction: null }, sidebarCollapsed: { classPropertyName: "sidebarCollapsed", publicName: "sidebarCollapsed", isSignal: true, isRequired: false, transformFunction: null }, inspectorOpen: { classPropertyName: "inspectorOpen", publicName: "inspectorOpen", isSignal: true, isRequired: false, transformFunction: null }, commentsOpen: { classPropertyName: "commentsOpen", publicName: "commentsOpen", isSignal: true, isRequired: false, transformFunction: null }, commentCount: { classPropertyName: "commentCount", publicName: "commentCount", isSignal: true, isRequired: false, transformFunction: null }, findOpen: { classPropertyName: "findOpen", publicName: "findOpen", isSignal: true, isRequired: false, transformFunction: null }, collabConnected: { classPropertyName: "collabConnected", publicName: "collabConnected", isSignal: true, isRequired: false, transformFunction: null }, connectedCount: { classPropertyName: "connectedCount", publicName: "connectedCount", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { toggleSidebar: "toggleSidebar", toggleFind: "toggleFind", toggleComments: "toggleComments", present: "present", presenter: "presenter", broadcast: "broadcast", openCustomShows: "openCustomShows", share: "share", toggleInspector: "toggleInspector", exportPng: "exportPng", exportPdf: "exportPdf", exportGif: "exportGif", exportVideo: "exportVideo", print: "print", info: "info", a11y: "a11y", save: "save" }, ngImport: i0, template: `
69384
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.5", type: RibbonPrimaryRowComponent, isStandalone: true, selector: "pptx-ribbon-primary-row", inputs: { slideCount: { classPropertyName: "slideCount", publicName: "slideCount", isSignal: true, isRequired: false, transformFunction: null }, sidebarCollapsed: { classPropertyName: "sidebarCollapsed", publicName: "sidebarCollapsed", isSignal: true, isRequired: false, transformFunction: null }, inspectorOpen: { classPropertyName: "inspectorOpen", publicName: "inspectorOpen", isSignal: true, isRequired: false, transformFunction: null }, commentsOpen: { classPropertyName: "commentsOpen", publicName: "commentsOpen", isSignal: true, isRequired: false, transformFunction: null }, commentCount: { classPropertyName: "commentCount", publicName: "commentCount", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { toggleSidebar: "toggleSidebar", toggleComments: "toggleComments", present: "present", presenter: "presenter", broadcast: "broadcast", openCustomShows: "openCustomShows", toggleInspector: "toggleInspector", exportPng: "exportPng", exportPdf: "exportPdf", exportGif: "exportGif", exportVideo: "exportVideo", print: "print", info: "info", a11y: "a11y", save: "save" }, ngImport: i0, template: `
69116
69385
  <div class="flex items-center gap-0.5 px-1.5 py-0.5">
69117
- <!-- Left: slides pane toggle + undo/redo + find -->
69386
+ <!-- Left: slides pane toggle (undo/redo/find moved to the title bar) -->
69118
69387
  <button
69119
69388
  type="button"
69120
69389
  class="pptx-rb-icon"
@@ -69125,40 +69394,11 @@ class RibbonPrimaryRowComponent {
69125
69394
  >
69126
69395
 
69127
69396
  </button>
69128
- <span class="mx-1 h-5 w-px self-center bg-border/50"></span>
69129
- <button
69130
- type="button"
69131
- class="pptx-rb-icon"
69132
- [attr.aria-label]="'pptx.toolbar.undo' | translate"
69133
- [disabled]="!canEdit() || !editor.canUndo()"
69134
- (click)="editor.undo()"
69135
- >
69136
-
69137
- </button>
69138
- <button
69139
- type="button"
69140
- class="pptx-rb-icon"
69141
- [attr.aria-label]="'pptx.toolbar.redo' | translate"
69142
- [disabled]="!canEdit() || !editor.canRedo()"
69143
- (click)="editor.redo()"
69144
- >
69145
-
69146
- </button>
69147
- <button
69148
- type="button"
69149
- class="pptx-rb-icon"
69150
- [ngClass]="findOpen() ? 'text-foreground' : 'text-muted-foreground'"
69151
- [title]="'pptx.toolbar.findAndReplace' | translate"
69152
- [attr.aria-label]="'pptx.toolbar.findAndReplace' | translate"
69153
- (click)="toggleFind.emit()"
69154
- >
69155
-
69156
- </button>
69157
69397
 
69158
69398
  <!-- Center spacer -->
69159
69399
  <div class="min-w-2 flex-1"></div>
69160
69400
 
69161
- <!-- Right: comments + present + show + share + inspector + overflow -->
69401
+ <!-- Right: comments + present + show + inspector + overflow -->
69162
69402
  <button
69163
69403
  type="button"
69164
69404
  class="pptx-rb-icon relative"
@@ -69239,24 +69479,6 @@ class RibbonPrimaryRowComponent {
69239
69479
 
69240
69480
  <span class="mx-1 h-5 w-px self-center bg-border/50"></span>
69241
69481
 
69242
- <button
69243
- type="button"
69244
- class="inline-flex items-center gap-1 rounded-sm px-2.5 py-1 text-[11px] font-medium text-white transition-colors"
69245
- [ngClass]="
69246
- collabConnected() ? 'bg-green-600 hover:bg-green-500' : 'bg-primary hover:bg-primary/90'
69247
- "
69248
- [title]="'pptx.ribbon.shareForCollaboration' | translate"
69249
- [attr.aria-label]="'pptx.toolbar.share' | translate"
69250
- (click)="share.emit()"
69251
- >
69252
-
69253
- {{
69254
- collabConnected()
69255
- ? ('pptx.toolbar.sharingCount' | translate: { count: connectedCount() })
69256
- : ('pptx.toolbar.share' | translate)
69257
- }}
69258
- </button>
69259
-
69260
69482
  <button
69261
69483
  type="button"
69262
69484
  class="pptx-rb-icon"
@@ -69313,7 +69535,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.5", ngImpor
69313
69535
  imports: [NgClass, TranslatePipe],
69314
69536
  template: `
69315
69537
  <div class="flex items-center gap-0.5 px-1.5 py-0.5">
69316
- <!-- Left: slides pane toggle + undo/redo + find -->
69538
+ <!-- Left: slides pane toggle (undo/redo/find moved to the title bar) -->
69317
69539
  <button
69318
69540
  type="button"
69319
69541
  class="pptx-rb-icon"
@@ -69324,40 +69546,11 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.5", ngImpor
69324
69546
  >
69325
69547
 
69326
69548
  </button>
69327
- <span class="mx-1 h-5 w-px self-center bg-border/50"></span>
69328
- <button
69329
- type="button"
69330
- class="pptx-rb-icon"
69331
- [attr.aria-label]="'pptx.toolbar.undo' | translate"
69332
- [disabled]="!canEdit() || !editor.canUndo()"
69333
- (click)="editor.undo()"
69334
- >
69335
-
69336
- </button>
69337
- <button
69338
- type="button"
69339
- class="pptx-rb-icon"
69340
- [attr.aria-label]="'pptx.toolbar.redo' | translate"
69341
- [disabled]="!canEdit() || !editor.canRedo()"
69342
- (click)="editor.redo()"
69343
- >
69344
-
69345
- </button>
69346
- <button
69347
- type="button"
69348
- class="pptx-rb-icon"
69349
- [ngClass]="findOpen() ? 'text-foreground' : 'text-muted-foreground'"
69350
- [title]="'pptx.toolbar.findAndReplace' | translate"
69351
- [attr.aria-label]="'pptx.toolbar.findAndReplace' | translate"
69352
- (click)="toggleFind.emit()"
69353
- >
69354
-
69355
- </button>
69356
69549
 
69357
69550
  <!-- Center spacer -->
69358
69551
  <div class="min-w-2 flex-1"></div>
69359
69552
 
69360
- <!-- Right: comments + present + show + share + inspector + overflow -->
69553
+ <!-- Right: comments + present + show + inspector + overflow -->
69361
69554
  <button
69362
69555
  type="button"
69363
69556
  class="pptx-rb-icon relative"
@@ -69438,24 +69631,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.5", ngImpor
69438
69631
 
69439
69632
  <span class="mx-1 h-5 w-px self-center bg-border/50"></span>
69440
69633
 
69441
- <button
69442
- type="button"
69443
- class="inline-flex items-center gap-1 rounded-sm px-2.5 py-1 text-[11px] font-medium text-white transition-colors"
69444
- [ngClass]="
69445
- collabConnected() ? 'bg-green-600 hover:bg-green-500' : 'bg-primary hover:bg-primary/90'
69446
- "
69447
- [title]="'pptx.ribbon.shareForCollaboration' | translate"
69448
- [attr.aria-label]="'pptx.toolbar.share' | translate"
69449
- (click)="share.emit()"
69450
- >
69451
-
69452
- {{
69453
- collabConnected()
69454
- ? ('pptx.toolbar.sharingCount' | translate: { count: connectedCount() })
69455
- : ('pptx.toolbar.share' | translate)
69456
- }}
69457
- </button>
69458
-
69459
69634
  <button
69460
69635
  type="button"
69461
69636
  class="pptx-rb-icon"
@@ -69503,7 +69678,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.5", ngImpor
69503
69678
  </div>
69504
69679
  `,
69505
69680
  }]
69506
- }], propDecorators: { slideCount: [{ type: i0.Input, args: [{ isSignal: true, alias: "slideCount", required: false }] }], canEdit: [{ type: i0.Input, args: [{ isSignal: true, alias: "canEdit", required: false }] }], sidebarCollapsed: [{ type: i0.Input, args: [{ isSignal: true, alias: "sidebarCollapsed", required: false }] }], inspectorOpen: [{ type: i0.Input, args: [{ isSignal: true, alias: "inspectorOpen", required: false }] }], commentsOpen: [{ type: i0.Input, args: [{ isSignal: true, alias: "commentsOpen", required: false }] }], commentCount: [{ type: i0.Input, args: [{ isSignal: true, alias: "commentCount", required: false }] }], findOpen: [{ type: i0.Input, args: [{ isSignal: true, alias: "findOpen", required: false }] }], collabConnected: [{ type: i0.Input, args: [{ isSignal: true, alias: "collabConnected", required: false }] }], connectedCount: [{ type: i0.Input, args: [{ isSignal: true, alias: "connectedCount", required: false }] }], toggleSidebar: [{ type: i0.Output, args: ["toggleSidebar"] }], toggleFind: [{ type: i0.Output, args: ["toggleFind"] }], toggleComments: [{ type: i0.Output, args: ["toggleComments"] }], present: [{ type: i0.Output, args: ["present"] }], presenter: [{ type: i0.Output, args: ["presenter"] }], broadcast: [{ type: i0.Output, args: ["broadcast"] }], openCustomShows: [{ type: i0.Output, args: ["openCustomShows"] }], share: [{ type: i0.Output, args: ["share"] }], toggleInspector: [{ type: i0.Output, args: ["toggleInspector"] }], exportPng: [{ type: i0.Output, args: ["exportPng"] }], exportPdf: [{ type: i0.Output, args: ["exportPdf"] }], exportGif: [{ type: i0.Output, args: ["exportGif"] }], exportVideo: [{ type: i0.Output, args: ["exportVideo"] }], print: [{ type: i0.Output, args: ["print"] }], info: [{ type: i0.Output, args: ["info"] }], a11y: [{ type: i0.Output, args: ["a11y"] }], save: [{ type: i0.Output, args: ["save"] }] } });
69681
+ }], propDecorators: { slideCount: [{ type: i0.Input, args: [{ isSignal: true, alias: "slideCount", required: false }] }], sidebarCollapsed: [{ type: i0.Input, args: [{ isSignal: true, alias: "sidebarCollapsed", required: false }] }], inspectorOpen: [{ type: i0.Input, args: [{ isSignal: true, alias: "inspectorOpen", required: false }] }], commentsOpen: [{ type: i0.Input, args: [{ isSignal: true, alias: "commentsOpen", required: false }] }], commentCount: [{ type: i0.Input, args: [{ isSignal: true, alias: "commentCount", required: false }] }], toggleSidebar: [{ type: i0.Output, args: ["toggleSidebar"] }], toggleComments: [{ type: i0.Output, args: ["toggleComments"] }], present: [{ type: i0.Output, args: ["present"] }], presenter: [{ type: i0.Output, args: ["presenter"] }], broadcast: [{ type: i0.Output, args: ["broadcast"] }], openCustomShows: [{ type: i0.Output, args: ["openCustomShows"] }], toggleInspector: [{ type: i0.Output, args: ["toggleInspector"] }], exportPng: [{ type: i0.Output, args: ["exportPng"] }], exportPdf: [{ type: i0.Output, args: ["exportPdf"] }], exportGif: [{ type: i0.Output, args: ["exportGif"] }], exportVideo: [{ type: i0.Output, args: ["exportVideo"] }], print: [{ type: i0.Output, args: ["print"] }], info: [{ type: i0.Output, args: ["info"] }], a11y: [{ type: i0.Output, args: ["a11y"] }], save: [{ type: i0.Output, args: ["save"] }] } });
69507
69682
 
69508
69683
  /**
69509
69684
  * ribbon-review-section.component.ts: the Review ribbon tab (Comments,
@@ -70209,6 +70384,8 @@ class RibbonComponent {
70209
70384
  find = output();
70210
70385
  present = output();
70211
70386
  presenter = output();
70387
+ /** Emitted by the tab-row Record button (starts a slide-show run-through). */
70388
+ record = output();
70212
70389
  share = output();
70213
70390
  broadcast = output();
70214
70391
  openFile = output();
@@ -70283,6 +70460,8 @@ class RibbonComponent {
70283
70460
  /** Emitted when the user clicks "Shortcuts" in the Help tab. */
70284
70461
  openShortcuts = output();
70285
70462
  tabs = TABS;
70463
+ /** Shared class tokens for the tab-row Record button. */
70464
+ tra = TAB_ROW_ACTION_CLASSES;
70286
70465
  activeTab = signal('home', /* @ts-ignore */
70287
70466
  ...(ngDevMode ? [{ debugName: "activeTab" }] : /* istanbul ignore next */ []));
70288
70467
  /** Ribbon content expanded (true) vs collapsed to just the tab bar (false). */
@@ -70315,7 +70494,7 @@ class RibbonComponent {
70315
70494
  this.drawToolChange.emit(state);
70316
70495
  }
70317
70496
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.5", ngImport: i0, type: RibbonComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
70318
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.5", type: RibbonComponent, isStandalone: true, selector: "pptx-ribbon", inputs: { slideIndex: { classPropertyName: "slideIndex", publicName: "slideIndex", isSignal: true, isRequired: false, transformFunction: null }, slideCount: { classPropertyName: "slideCount", publicName: "slideCount", isSignal: true, isRequired: false, transformFunction: null }, canEdit: { classPropertyName: "canEdit", publicName: "canEdit", isSignal: true, isRequired: false, transformFunction: null }, selectedElement: { classPropertyName: "selectedElement", publicName: "selectedElement", isSignal: true, isRequired: false, transformFunction: null }, zoomPercent: { classPropertyName: "zoomPercent", publicName: "zoomPercent", isSignal: true, isRequired: false, transformFunction: null }, formatPainterActive: { classPropertyName: "formatPainterActive", publicName: "formatPainterActive", isSignal: true, isRequired: false, transformFunction: null }, canActivateFormatPainter: { classPropertyName: "canActivateFormatPainter", publicName: "canActivateFormatPainter", isSignal: true, isRequired: false, transformFunction: null }, exporting: { classPropertyName: "exporting", publicName: "exporting", isSignal: true, isRequired: false, transformFunction: null }, showGrid: { classPropertyName: "showGrid", publicName: "showGrid", isSignal: true, isRequired: false, transformFunction: null }, showRulers: { classPropertyName: "showRulers", publicName: "showRulers", isSignal: true, isRequired: false, transformFunction: null }, showGuides: { classPropertyName: "showGuides", publicName: "showGuides", isSignal: true, isRequired: false, transformFunction: null }, snapToGrid: { classPropertyName: "snapToGrid", publicName: "snapToGrid", isSignal: true, isRequired: false, transformFunction: null }, eyedropperActive: { classPropertyName: "eyedropperActive", publicName: "eyedropperActive", isSignal: true, isRequired: false, transformFunction: null }, themeGalleryOpen: { classPropertyName: "themeGalleryOpen", publicName: "themeGalleryOpen", isSignal: true, isRequired: false, transformFunction: null }, sidebarCollapsed: { classPropertyName: "sidebarCollapsed", publicName: "sidebarCollapsed", isSignal: true, isRequired: false, transformFunction: null }, inspectorOpen: { classPropertyName: "inspectorOpen", publicName: "inspectorOpen", isSignal: true, isRequired: false, transformFunction: null }, commentsOpen: { classPropertyName: "commentsOpen", publicName: "commentsOpen", isSignal: true, isRequired: false, transformFunction: null }, commentCount: { classPropertyName: "commentCount", publicName: "commentCount", isSignal: true, isRequired: false, transformFunction: null }, findOpen: { classPropertyName: "findOpen", publicName: "findOpen", isSignal: true, isRequired: false, transformFunction: null }, collabConnected: { classPropertyName: "collabConnected", publicName: "collabConnected", isSignal: true, isRequired: false, transformFunction: null }, connectedCount: { classPropertyName: "connectedCount", publicName: "connectedCount", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { prev: "prev", next: "next", zoomIn: "zoomIn", zoomOut: "zoomOut", zoomReset: "zoomReset", find: "find", present: "present", presenter: "presenter", share: "share", broadcast: "broadcast", openFile: "openFile", save: "save", toggleSidebar: "toggleSidebar", signatures: "signatures", info: "info", print: "print", comments: "comments", a11y: "a11y", link: "link", openSorter: "openSorter", toggleNotes: "toggleNotes", toggleFormatPainter: "toggleFormatPainter", exportPng: "exportPng", exportPdf: "exportPdf", exportGif: "exportGif", exportVideo: "exportVideo", replace: "replace", toggleInspector: "toggleInspector", drawToolChange: "drawToolChange", toggleThemeGallery: "toggleThemeGallery", toggleGrid: "toggleGrid", toggleRulers: "toggleRulers", toggleGuides: "toggleGuides", toggleSelectionPane: "toggleSelectionPane", openCustomShows: "openCustomShows", toggleSnapToGrid: "toggleSnapToGrid", toggleEyedropper: "toggleEyedropper", openSmartArtDialog: "openSmartArtDialog", openEquationDialog: "openEquationDialog", openSetUpSlideShow: "openSetUpSlideShow", openCompare: "openCompare", openPassword: "openPassword", openFontEmbedding: "openFontEmbedding", openVersionHistory: "openVersionHistory", openShortcuts: "openShortcuts" }, ngImport: i0, template: `
70497
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.5", type: RibbonComponent, isStandalone: true, selector: "pptx-ribbon", inputs: { slideIndex: { classPropertyName: "slideIndex", publicName: "slideIndex", isSignal: true, isRequired: false, transformFunction: null }, slideCount: { classPropertyName: "slideCount", publicName: "slideCount", isSignal: true, isRequired: false, transformFunction: null }, canEdit: { classPropertyName: "canEdit", publicName: "canEdit", isSignal: true, isRequired: false, transformFunction: null }, selectedElement: { classPropertyName: "selectedElement", publicName: "selectedElement", isSignal: true, isRequired: false, transformFunction: null }, zoomPercent: { classPropertyName: "zoomPercent", publicName: "zoomPercent", isSignal: true, isRequired: false, transformFunction: null }, formatPainterActive: { classPropertyName: "formatPainterActive", publicName: "formatPainterActive", isSignal: true, isRequired: false, transformFunction: null }, canActivateFormatPainter: { classPropertyName: "canActivateFormatPainter", publicName: "canActivateFormatPainter", isSignal: true, isRequired: false, transformFunction: null }, exporting: { classPropertyName: "exporting", publicName: "exporting", isSignal: true, isRequired: false, transformFunction: null }, showGrid: { classPropertyName: "showGrid", publicName: "showGrid", isSignal: true, isRequired: false, transformFunction: null }, showRulers: { classPropertyName: "showRulers", publicName: "showRulers", isSignal: true, isRequired: false, transformFunction: null }, showGuides: { classPropertyName: "showGuides", publicName: "showGuides", isSignal: true, isRequired: false, transformFunction: null }, snapToGrid: { classPropertyName: "snapToGrid", publicName: "snapToGrid", isSignal: true, isRequired: false, transformFunction: null }, eyedropperActive: { classPropertyName: "eyedropperActive", publicName: "eyedropperActive", isSignal: true, isRequired: false, transformFunction: null }, themeGalleryOpen: { classPropertyName: "themeGalleryOpen", publicName: "themeGalleryOpen", isSignal: true, isRequired: false, transformFunction: null }, sidebarCollapsed: { classPropertyName: "sidebarCollapsed", publicName: "sidebarCollapsed", isSignal: true, isRequired: false, transformFunction: null }, inspectorOpen: { classPropertyName: "inspectorOpen", publicName: "inspectorOpen", isSignal: true, isRequired: false, transformFunction: null }, commentsOpen: { classPropertyName: "commentsOpen", publicName: "commentsOpen", isSignal: true, isRequired: false, transformFunction: null }, commentCount: { classPropertyName: "commentCount", publicName: "commentCount", isSignal: true, isRequired: false, transformFunction: null }, findOpen: { classPropertyName: "findOpen", publicName: "findOpen", isSignal: true, isRequired: false, transformFunction: null }, collabConnected: { classPropertyName: "collabConnected", publicName: "collabConnected", isSignal: true, isRequired: false, transformFunction: null }, connectedCount: { classPropertyName: "connectedCount", publicName: "connectedCount", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { prev: "prev", next: "next", zoomIn: "zoomIn", zoomOut: "zoomOut", zoomReset: "zoomReset", find: "find", present: "present", presenter: "presenter", record: "record", share: "share", broadcast: "broadcast", openFile: "openFile", save: "save", toggleSidebar: "toggleSidebar", signatures: "signatures", info: "info", print: "print", comments: "comments", a11y: "a11y", link: "link", openSorter: "openSorter", toggleNotes: "toggleNotes", toggleFormatPainter: "toggleFormatPainter", exportPng: "exportPng", exportPdf: "exportPdf", exportGif: "exportGif", exportVideo: "exportVideo", replace: "replace", toggleInspector: "toggleInspector", drawToolChange: "drawToolChange", toggleThemeGallery: "toggleThemeGallery", toggleGrid: "toggleGrid", toggleRulers: "toggleRulers", toggleGuides: "toggleGuides", toggleSelectionPane: "toggleSelectionPane", openCustomShows: "openCustomShows", toggleSnapToGrid: "toggleSnapToGrid", toggleEyedropper: "toggleEyedropper", openSmartArtDialog: "openSmartArtDialog", openEquationDialog: "openEquationDialog", openSetUpSlideShow: "openSetUpSlideShow", openCompare: "openCompare", openPassword: "openPassword", openFontEmbedding: "openFontEmbedding", openVersionHistory: "openVersionHistory", openShortcuts: "openShortcuts" }, ngImport: i0, template: `
70319
70498
  <div
70320
70499
  role="toolbar"
70321
70500
  aria-label="Presentation toolbar"
@@ -70324,22 +70503,16 @@ class RibbonComponent {
70324
70503
  <!-- ── Primary quick-access row (ToolbarPrimaryRow parity) ──── -->
70325
70504
  <pptx-ribbon-primary-row
70326
70505
  [slideCount]="slideCount()"
70327
- [canEdit]="canEdit()"
70328
70506
  [sidebarCollapsed]="sidebarCollapsed()"
70329
70507
  [inspectorOpen]="inspectorOpen()"
70330
70508
  [commentsOpen]="commentsOpen()"
70331
70509
  [commentCount]="commentCount()"
70332
- [findOpen]="findOpen()"
70333
- [collabConnected]="collabConnected()"
70334
- [connectedCount]="connectedCount()"
70335
70510
  (toggleSidebar)="toggleSidebar.emit()"
70336
- (toggleFind)="replace.emit()"
70337
70511
  (toggleComments)="comments.emit()"
70338
70512
  (present)="present.emit()"
70339
70513
  (presenter)="presenter.emit()"
70340
70514
  (broadcast)="broadcast.emit()"
70341
70515
  (openCustomShows)="openCustomShows.emit()"
70342
- (share)="share.emit()"
70343
70516
  (toggleInspector)="toggleInspector.emit()"
70344
70517
  (exportPng)="exportPng.emit()"
70345
70518
  (exportPdf)="exportPdf.emit()"
@@ -70368,6 +70541,46 @@ class RibbonComponent {
70368
70541
  </button>
70369
70542
  }
70370
70543
  <div class="flex-1"></div>
70544
+
70545
+ <!-- Tab-row right actions (Record + Share), mirroring React's TabRowActions -->
70546
+ <div class="flex items-center gap-1 pr-1">
70547
+ @if (canEdit()) {
70548
+ <button
70549
+ type="button"
70550
+ [class]="tra.record"
70551
+ [title]="'pptx.titleBar.record' | translate"
70552
+ [attr.aria-label]="'pptx.titleBar.record' | translate"
70553
+ (click)="record.emit()"
70554
+ >
70555
+ <span [class]="tra.recordDot" aria-hidden="true"></span>
70556
+ <span>{{ 'pptx.titleBar.record' | translate }}</span>
70557
+ </button>
70558
+ }
70559
+ <button
70560
+ type="button"
70561
+ class="relative inline-flex items-center gap-1 whitespace-nowrap rounded-sm px-2.5 py-1 text-[11px] font-medium text-white transition-colors"
70562
+ [ngClass]="
70563
+ collabConnected()
70564
+ ? 'bg-green-600 hover:bg-green-500'
70565
+ : 'bg-primary hover:bg-primary/90'
70566
+ "
70567
+ [title]="
70568
+ collabConnected()
70569
+ ? ('pptx.toolbar.sharingUsers' | translate: { count: connectedCount() })
70570
+ : ('pptx.toolbar.share' | translate)
70571
+ "
70572
+ [attr.aria-label]="'pptx.toolbar.share' | translate"
70573
+ (click)="share.emit()"
70574
+ >
70575
+
70576
+ <span>{{
70577
+ collabConnected()
70578
+ ? ('pptx.toolbar.sharingCount' | translate: { count: connectedCount() })
70579
+ : ('pptx.toolbar.share' | translate)
70580
+ }}</span>
70581
+ </button>
70582
+ </div>
70583
+
70371
70584
  <button
70372
70585
  type="button"
70373
70586
  class="mr-1 rounded px-2 py-1 text-[11px] text-muted-foreground transition-colors hover:text-foreground"
@@ -70525,7 +70738,7 @@ class RibbonComponent {
70525
70738
  }
70526
70739
  </div>
70527
70740
  </div>
70528
- `, isInline: true, dependencies: [{ kind: "directive", type: NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "component", type: RibbonPrimaryRowComponent, selector: "pptx-ribbon-primary-row", inputs: ["slideCount", "canEdit", "sidebarCollapsed", "inspectorOpen", "commentsOpen", "commentCount", "findOpen", "collabConnected", "connectedCount"], outputs: ["toggleSidebar", "toggleFind", "toggleComments", "present", "presenter", "broadcast", "openCustomShows", "share", "toggleInspector", "exportPng", "exportPdf", "exportGif", "exportVideo", "print", "info", "a11y", "save"] }, { kind: "component", type: RibbonFileSectionComponent, selector: "pptx-ribbon-file-section", inputs: ["slideCount", "exporting"], outputs: ["openFile", "save", "exportPng", "exportPdf", "exportGif", "exportVideo", "print", "info", "signatures", "replace", "openPassword", "openFontEmbedding", "openVersionHistory"] }, { kind: "component", type: RibbonHomeSectionComponent, selector: "pptx-ribbon-home-section", inputs: ["slideIndex", "selectedElement", "formatPainterActive", "canActivateFormatPainter"], outputs: ["toggleFormatPainter"] }, { kind: "component", type: RibbonInsertSectionComponent, selector: "pptx-ribbon-insert-section", inputs: ["slideIndex", "newChartType"], outputs: ["openSmartArtDialog", "openEquationDialog", "chartTypeChange"] }, { kind: "component", type: RibbonFontControlsComponent, selector: "pptx-ribbon-font-controls", inputs: ["slideIndex", "selectedElement"] }, { kind: "component", type: RibbonParagraphControlsComponent, selector: "pptx-ribbon-paragraph-controls", inputs: ["slideIndex", "selectedElement"] }, { kind: "component", type: RibbonArrangeSectionComponent, selector: "pptx-ribbon-arrange-section", inputs: ["slideIndex", "formatPainterActive", "canActivateFormatPainter"], outputs: ["toggleFormatPainter"] }, { kind: "component", type: RibbonSlideshowSectionComponent, selector: "pptx-ribbon-slideshow-section", inputs: ["slideCount"], outputs: ["present", "presenter", "broadcast", "openCustomShows", "openSetUpSlideShow"] }, { kind: "component", type: RibbonReviewSectionComponent, selector: "pptx-ribbon-review-section", outputs: ["comments", "a11y", "openCompare", "link"] }, { kind: "component", type: RibbonViewSectionComponent, selector: "pptx-ribbon-view-section", inputs: ["canEdit", "showGrid", "showRulers", "showGuides", "snapToGrid", "eyedropperActive"], outputs: ["openSorter", "toggleNotes", "print", "openShortcuts", "toggleGrid", "toggleRulers", "toggleGuides", "toggleSelectionPane", "toggleSnapToGrid", "toggleEyedropper"] }, { kind: "component", type: RibbonDrawSectionComponent, selector: "pptx-ribbon-draw-section", inputs: ["activeTool", "drawingColor", "drawingWidth"], outputs: ["drawToolChange"] }, { kind: "component", type: RibbonDesignSectionComponent, selector: "pptx-ribbon-design-section", inputs: ["themeGalleryOpen"], outputs: ["toggleThemeGallery", "info", "toggleInspector"] }, { kind: "component", type: RibbonTransitionsSectionComponent, selector: "pptx-ribbon-transitions-section", inputs: ["slideIndex", "selectedTransition", "transitionDurationSec"], outputs: ["present", "toggleInspector", "transitionChange", "durationChange"] }, { kind: "component", type: RibbonAnimationsSectionComponent, selector: "pptx-ribbon-animations-section", inputs: ["slideIndex", "selectedElement"], outputs: ["present", "toggleInspector"] }, { kind: "pipe", type: TranslatePipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
70741
+ `, isInline: true, dependencies: [{ kind: "directive", type: NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "component", type: RibbonPrimaryRowComponent, selector: "pptx-ribbon-primary-row", inputs: ["slideCount", "sidebarCollapsed", "inspectorOpen", "commentsOpen", "commentCount"], outputs: ["toggleSidebar", "toggleComments", "present", "presenter", "broadcast", "openCustomShows", "toggleInspector", "exportPng", "exportPdf", "exportGif", "exportVideo", "print", "info", "a11y", "save"] }, { kind: "component", type: RibbonFileSectionComponent, selector: "pptx-ribbon-file-section", inputs: ["slideCount", "exporting"], outputs: ["openFile", "save", "exportPng", "exportPdf", "exportGif", "exportVideo", "print", "info", "signatures", "replace", "openPassword", "openFontEmbedding", "openVersionHistory"] }, { kind: "component", type: RibbonHomeSectionComponent, selector: "pptx-ribbon-home-section", inputs: ["slideIndex", "selectedElement", "formatPainterActive", "canActivateFormatPainter"], outputs: ["toggleFormatPainter"] }, { kind: "component", type: RibbonInsertSectionComponent, selector: "pptx-ribbon-insert-section", inputs: ["slideIndex", "newChartType"], outputs: ["openSmartArtDialog", "openEquationDialog", "chartTypeChange"] }, { kind: "component", type: RibbonFontControlsComponent, selector: "pptx-ribbon-font-controls", inputs: ["slideIndex", "selectedElement"] }, { kind: "component", type: RibbonParagraphControlsComponent, selector: "pptx-ribbon-paragraph-controls", inputs: ["slideIndex", "selectedElement"] }, { kind: "component", type: RibbonArrangeSectionComponent, selector: "pptx-ribbon-arrange-section", inputs: ["slideIndex", "formatPainterActive", "canActivateFormatPainter"], outputs: ["toggleFormatPainter"] }, { kind: "component", type: RibbonSlideshowSectionComponent, selector: "pptx-ribbon-slideshow-section", inputs: ["slideCount"], outputs: ["present", "presenter", "broadcast", "openCustomShows", "openSetUpSlideShow"] }, { kind: "component", type: RibbonReviewSectionComponent, selector: "pptx-ribbon-review-section", outputs: ["comments", "a11y", "openCompare", "link"] }, { kind: "component", type: RibbonViewSectionComponent, selector: "pptx-ribbon-view-section", inputs: ["canEdit", "showGrid", "showRulers", "showGuides", "snapToGrid", "eyedropperActive"], outputs: ["openSorter", "toggleNotes", "print", "openShortcuts", "toggleGrid", "toggleRulers", "toggleGuides", "toggleSelectionPane", "toggleSnapToGrid", "toggleEyedropper"] }, { kind: "component", type: RibbonDrawSectionComponent, selector: "pptx-ribbon-draw-section", inputs: ["activeTool", "drawingColor", "drawingWidth"], outputs: ["drawToolChange"] }, { kind: "component", type: RibbonDesignSectionComponent, selector: "pptx-ribbon-design-section", inputs: ["themeGalleryOpen"], outputs: ["toggleThemeGallery", "info", "toggleInspector"] }, { kind: "component", type: RibbonTransitionsSectionComponent, selector: "pptx-ribbon-transitions-section", inputs: ["slideIndex", "selectedTransition", "transitionDurationSec"], outputs: ["present", "toggleInspector", "transitionChange", "durationChange"] }, { kind: "component", type: RibbonAnimationsSectionComponent, selector: "pptx-ribbon-animations-section", inputs: ["slideIndex", "selectedElement"], outputs: ["present", "toggleInspector"] }, { kind: "pipe", type: TranslatePipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
70529
70742
  }
70530
70743
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.5", ngImport: i0, type: RibbonComponent, decorators: [{
70531
70744
  type: Component,
@@ -70560,22 +70773,16 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.5", ngImpor
70560
70773
  <!-- ── Primary quick-access row (ToolbarPrimaryRow parity) ──── -->
70561
70774
  <pptx-ribbon-primary-row
70562
70775
  [slideCount]="slideCount()"
70563
- [canEdit]="canEdit()"
70564
70776
  [sidebarCollapsed]="sidebarCollapsed()"
70565
70777
  [inspectorOpen]="inspectorOpen()"
70566
70778
  [commentsOpen]="commentsOpen()"
70567
70779
  [commentCount]="commentCount()"
70568
- [findOpen]="findOpen()"
70569
- [collabConnected]="collabConnected()"
70570
- [connectedCount]="connectedCount()"
70571
70780
  (toggleSidebar)="toggleSidebar.emit()"
70572
- (toggleFind)="replace.emit()"
70573
70781
  (toggleComments)="comments.emit()"
70574
70782
  (present)="present.emit()"
70575
70783
  (presenter)="presenter.emit()"
70576
70784
  (broadcast)="broadcast.emit()"
70577
70785
  (openCustomShows)="openCustomShows.emit()"
70578
- (share)="share.emit()"
70579
70786
  (toggleInspector)="toggleInspector.emit()"
70580
70787
  (exportPng)="exportPng.emit()"
70581
70788
  (exportPdf)="exportPdf.emit()"
@@ -70604,6 +70811,46 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.5", ngImpor
70604
70811
  </button>
70605
70812
  }
70606
70813
  <div class="flex-1"></div>
70814
+
70815
+ <!-- Tab-row right actions (Record + Share), mirroring React's TabRowActions -->
70816
+ <div class="flex items-center gap-1 pr-1">
70817
+ @if (canEdit()) {
70818
+ <button
70819
+ type="button"
70820
+ [class]="tra.record"
70821
+ [title]="'pptx.titleBar.record' | translate"
70822
+ [attr.aria-label]="'pptx.titleBar.record' | translate"
70823
+ (click)="record.emit()"
70824
+ >
70825
+ <span [class]="tra.recordDot" aria-hidden="true"></span>
70826
+ <span>{{ 'pptx.titleBar.record' | translate }}</span>
70827
+ </button>
70828
+ }
70829
+ <button
70830
+ type="button"
70831
+ class="relative inline-flex items-center gap-1 whitespace-nowrap rounded-sm px-2.5 py-1 text-[11px] font-medium text-white transition-colors"
70832
+ [ngClass]="
70833
+ collabConnected()
70834
+ ? 'bg-green-600 hover:bg-green-500'
70835
+ : 'bg-primary hover:bg-primary/90'
70836
+ "
70837
+ [title]="
70838
+ collabConnected()
70839
+ ? ('pptx.toolbar.sharingUsers' | translate: { count: connectedCount() })
70840
+ : ('pptx.toolbar.share' | translate)
70841
+ "
70842
+ [attr.aria-label]="'pptx.toolbar.share' | translate"
70843
+ (click)="share.emit()"
70844
+ >
70845
+
70846
+ <span>{{
70847
+ collabConnected()
70848
+ ? ('pptx.toolbar.sharingCount' | translate: { count: connectedCount() })
70849
+ : ('pptx.toolbar.share' | translate)
70850
+ }}</span>
70851
+ </button>
70852
+ </div>
70853
+
70607
70854
  <button
70608
70855
  type="button"
70609
70856
  class="mr-1 rounded px-2 py-1 text-[11px] text-muted-foreground transition-colors hover:text-foreground"
@@ -70763,7 +71010,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.5", ngImpor
70763
71010
  </div>
70764
71011
  `,
70765
71012
  }]
70766
- }], propDecorators: { slideIndex: [{ type: i0.Input, args: [{ isSignal: true, alias: "slideIndex", required: false }] }], slideCount: [{ type: i0.Input, args: [{ isSignal: true, alias: "slideCount", required: false }] }], canEdit: [{ type: i0.Input, args: [{ isSignal: true, alias: "canEdit", required: false }] }], selectedElement: [{ type: i0.Input, args: [{ isSignal: true, alias: "selectedElement", required: false }] }], zoomPercent: [{ type: i0.Input, args: [{ isSignal: true, alias: "zoomPercent", required: false }] }], formatPainterActive: [{ type: i0.Input, args: [{ isSignal: true, alias: "formatPainterActive", required: false }] }], canActivateFormatPainter: [{ type: i0.Input, args: [{ isSignal: true, alias: "canActivateFormatPainter", required: false }] }], exporting: [{ type: i0.Input, args: [{ isSignal: true, alias: "exporting", required: false }] }], showGrid: [{ type: i0.Input, args: [{ isSignal: true, alias: "showGrid", required: false }] }], showRulers: [{ type: i0.Input, args: [{ isSignal: true, alias: "showRulers", required: false }] }], showGuides: [{ type: i0.Input, args: [{ isSignal: true, alias: "showGuides", required: false }] }], snapToGrid: [{ type: i0.Input, args: [{ isSignal: true, alias: "snapToGrid", required: false }] }], eyedropperActive: [{ type: i0.Input, args: [{ isSignal: true, alias: "eyedropperActive", required: false }] }], themeGalleryOpen: [{ type: i0.Input, args: [{ isSignal: true, alias: "themeGalleryOpen", required: false }] }], sidebarCollapsed: [{ type: i0.Input, args: [{ isSignal: true, alias: "sidebarCollapsed", required: false }] }], inspectorOpen: [{ type: i0.Input, args: [{ isSignal: true, alias: "inspectorOpen", required: false }] }], commentsOpen: [{ type: i0.Input, args: [{ isSignal: true, alias: "commentsOpen", required: false }] }], commentCount: [{ type: i0.Input, args: [{ isSignal: true, alias: "commentCount", required: false }] }], findOpen: [{ type: i0.Input, args: [{ isSignal: true, alias: "findOpen", required: false }] }], collabConnected: [{ type: i0.Input, args: [{ isSignal: true, alias: "collabConnected", required: false }] }], connectedCount: [{ type: i0.Input, args: [{ isSignal: true, alias: "connectedCount", required: false }] }], prev: [{ type: i0.Output, args: ["prev"] }], next: [{ type: i0.Output, args: ["next"] }], zoomIn: [{ type: i0.Output, args: ["zoomIn"] }], zoomOut: [{ type: i0.Output, args: ["zoomOut"] }], zoomReset: [{ type: i0.Output, args: ["zoomReset"] }], find: [{ type: i0.Output, args: ["find"] }], present: [{ type: i0.Output, args: ["present"] }], presenter: [{ type: i0.Output, args: ["presenter"] }], share: [{ type: i0.Output, args: ["share"] }], broadcast: [{ type: i0.Output, args: ["broadcast"] }], openFile: [{ type: i0.Output, args: ["openFile"] }], save: [{ type: i0.Output, args: ["save"] }], toggleSidebar: [{ type: i0.Output, args: ["toggleSidebar"] }], signatures: [{ type: i0.Output, args: ["signatures"] }], info: [{ type: i0.Output, args: ["info"] }], print: [{ type: i0.Output, args: ["print"] }], comments: [{ type: i0.Output, args: ["comments"] }], a11y: [{ type: i0.Output, args: ["a11y"] }], link: [{ type: i0.Output, args: ["link"] }], openSorter: [{ type: i0.Output, args: ["openSorter"] }], toggleNotes: [{ type: i0.Output, args: ["toggleNotes"] }], toggleFormatPainter: [{ type: i0.Output, args: ["toggleFormatPainter"] }], exportPng: [{ type: i0.Output, args: ["exportPng"] }], exportPdf: [{ type: i0.Output, args: ["exportPdf"] }], exportGif: [{ type: i0.Output, args: ["exportGif"] }], exportVideo: [{ type: i0.Output, args: ["exportVideo"] }], replace: [{ type: i0.Output, args: ["replace"] }], toggleInspector: [{ type: i0.Output, args: ["toggleInspector"] }], drawToolChange: [{ type: i0.Output, args: ["drawToolChange"] }], toggleThemeGallery: [{ type: i0.Output, args: ["toggleThemeGallery"] }], toggleGrid: [{ type: i0.Output, args: ["toggleGrid"] }], toggleRulers: [{ type: i0.Output, args: ["toggleRulers"] }], toggleGuides: [{ type: i0.Output, args: ["toggleGuides"] }], toggleSelectionPane: [{ type: i0.Output, args: ["toggleSelectionPane"] }], openCustomShows: [{ type: i0.Output, args: ["openCustomShows"] }], toggleSnapToGrid: [{ type: i0.Output, args: ["toggleSnapToGrid"] }], toggleEyedropper: [{ type: i0.Output, args: ["toggleEyedropper"] }], openSmartArtDialog: [{ type: i0.Output, args: ["openSmartArtDialog"] }], openEquationDialog: [{ type: i0.Output, args: ["openEquationDialog"] }], openSetUpSlideShow: [{ type: i0.Output, args: ["openSetUpSlideShow"] }], openCompare: [{ type: i0.Output, args: ["openCompare"] }], openPassword: [{ type: i0.Output, args: ["openPassword"] }], openFontEmbedding: [{ type: i0.Output, args: ["openFontEmbedding"] }], openVersionHistory: [{ type: i0.Output, args: ["openVersionHistory"] }], openShortcuts: [{ type: i0.Output, args: ["openShortcuts"] }] } });
71013
+ }], propDecorators: { slideIndex: [{ type: i0.Input, args: [{ isSignal: true, alias: "slideIndex", required: false }] }], slideCount: [{ type: i0.Input, args: [{ isSignal: true, alias: "slideCount", required: false }] }], canEdit: [{ type: i0.Input, args: [{ isSignal: true, alias: "canEdit", required: false }] }], selectedElement: [{ type: i0.Input, args: [{ isSignal: true, alias: "selectedElement", required: false }] }], zoomPercent: [{ type: i0.Input, args: [{ isSignal: true, alias: "zoomPercent", required: false }] }], formatPainterActive: [{ type: i0.Input, args: [{ isSignal: true, alias: "formatPainterActive", required: false }] }], canActivateFormatPainter: [{ type: i0.Input, args: [{ isSignal: true, alias: "canActivateFormatPainter", required: false }] }], exporting: [{ type: i0.Input, args: [{ isSignal: true, alias: "exporting", required: false }] }], showGrid: [{ type: i0.Input, args: [{ isSignal: true, alias: "showGrid", required: false }] }], showRulers: [{ type: i0.Input, args: [{ isSignal: true, alias: "showRulers", required: false }] }], showGuides: [{ type: i0.Input, args: [{ isSignal: true, alias: "showGuides", required: false }] }], snapToGrid: [{ type: i0.Input, args: [{ isSignal: true, alias: "snapToGrid", required: false }] }], eyedropperActive: [{ type: i0.Input, args: [{ isSignal: true, alias: "eyedropperActive", required: false }] }], themeGalleryOpen: [{ type: i0.Input, args: [{ isSignal: true, alias: "themeGalleryOpen", required: false }] }], sidebarCollapsed: [{ type: i0.Input, args: [{ isSignal: true, alias: "sidebarCollapsed", required: false }] }], inspectorOpen: [{ type: i0.Input, args: [{ isSignal: true, alias: "inspectorOpen", required: false }] }], commentsOpen: [{ type: i0.Input, args: [{ isSignal: true, alias: "commentsOpen", required: false }] }], commentCount: [{ type: i0.Input, args: [{ isSignal: true, alias: "commentCount", required: false }] }], findOpen: [{ type: i0.Input, args: [{ isSignal: true, alias: "findOpen", required: false }] }], collabConnected: [{ type: i0.Input, args: [{ isSignal: true, alias: "collabConnected", required: false }] }], connectedCount: [{ type: i0.Input, args: [{ isSignal: true, alias: "connectedCount", required: false }] }], prev: [{ type: i0.Output, args: ["prev"] }], next: [{ type: i0.Output, args: ["next"] }], zoomIn: [{ type: i0.Output, args: ["zoomIn"] }], zoomOut: [{ type: i0.Output, args: ["zoomOut"] }], zoomReset: [{ type: i0.Output, args: ["zoomReset"] }], find: [{ type: i0.Output, args: ["find"] }], present: [{ type: i0.Output, args: ["present"] }], presenter: [{ type: i0.Output, args: ["presenter"] }], record: [{ type: i0.Output, args: ["record"] }], share: [{ type: i0.Output, args: ["share"] }], broadcast: [{ type: i0.Output, args: ["broadcast"] }], openFile: [{ type: i0.Output, args: ["openFile"] }], save: [{ type: i0.Output, args: ["save"] }], toggleSidebar: [{ type: i0.Output, args: ["toggleSidebar"] }], signatures: [{ type: i0.Output, args: ["signatures"] }], info: [{ type: i0.Output, args: ["info"] }], print: [{ type: i0.Output, args: ["print"] }], comments: [{ type: i0.Output, args: ["comments"] }], a11y: [{ type: i0.Output, args: ["a11y"] }], link: [{ type: i0.Output, args: ["link"] }], openSorter: [{ type: i0.Output, args: ["openSorter"] }], toggleNotes: [{ type: i0.Output, args: ["toggleNotes"] }], toggleFormatPainter: [{ type: i0.Output, args: ["toggleFormatPainter"] }], exportPng: [{ type: i0.Output, args: ["exportPng"] }], exportPdf: [{ type: i0.Output, args: ["exportPdf"] }], exportGif: [{ type: i0.Output, args: ["exportGif"] }], exportVideo: [{ type: i0.Output, args: ["exportVideo"] }], replace: [{ type: i0.Output, args: ["replace"] }], toggleInspector: [{ type: i0.Output, args: ["toggleInspector"] }], drawToolChange: [{ type: i0.Output, args: ["drawToolChange"] }], toggleThemeGallery: [{ type: i0.Output, args: ["toggleThemeGallery"] }], toggleGrid: [{ type: i0.Output, args: ["toggleGrid"] }], toggleRulers: [{ type: i0.Output, args: ["toggleRulers"] }], toggleGuides: [{ type: i0.Output, args: ["toggleGuides"] }], toggleSelectionPane: [{ type: i0.Output, args: ["toggleSelectionPane"] }], openCustomShows: [{ type: i0.Output, args: ["openCustomShows"] }], toggleSnapToGrid: [{ type: i0.Output, args: ["toggleSnapToGrid"] }], toggleEyedropper: [{ type: i0.Output, args: ["toggleEyedropper"] }], openSmartArtDialog: [{ type: i0.Output, args: ["openSmartArtDialog"] }], openEquationDialog: [{ type: i0.Output, args: ["openEquationDialog"] }], openSetUpSlideShow: [{ type: i0.Output, args: ["openSetUpSlideShow"] }], openCompare: [{ type: i0.Output, args: ["openCompare"] }], openPassword: [{ type: i0.Output, args: ["openPassword"] }], openFontEmbedding: [{ type: i0.Output, args: ["openFontEmbedding"] }], openVersionHistory: [{ type: i0.Output, args: ["openVersionHistory"] }], openShortcuts: [{ type: i0.Output, args: ["openShortcuts"] }] } });
70767
71014
 
70768
71015
  /**
70769
71016
  * selection-pane.component.ts: Side panel listing all elements on the active slide.
@@ -72223,6 +72470,9 @@ class StatusBarComponent {
72223
72470
  ...(ngDevMode ? [{ debugName: "canEdit" }] : /* istanbul ignore next */ []));
72224
72471
  dirty = input(false, /* @ts-ignore */
72225
72472
  ...(ngDevMode ? [{ debugName: "dirty" }] : /* istanbul ignore next */ []));
72473
+ /** Current autosave engine status; drives the save-state text + colour. */
72474
+ autosaveStatus = input(undefined, /* @ts-ignore */
72475
+ ...(ngDevMode ? [{ debugName: "autosaveStatus" }] : /* istanbul ignore next */ []));
72226
72476
  notesOpen = input(false, /* @ts-ignore */
72227
72477
  ...(ngDevMode ? [{ debugName: "notesOpen" }] : /* istanbul ignore next */ []));
72228
72478
  zoomPercent = input(100, /* @ts-ignore */
@@ -72240,6 +72490,7 @@ class StatusBarComponent {
72240
72490
  zoomIn = output();
72241
72491
  zoomOut = output();
72242
72492
  zoomReset = output();
72493
+ translate = inject(TranslateService);
72243
72494
  /** "Normal" is active when neither the sorter nor the slideshow is showing. */
72244
72495
  isNormal() {
72245
72496
  return !this.sorterActive() && !this.presenting();
@@ -72247,8 +72498,50 @@ class StatusBarComponent {
72247
72498
  min(a, b) {
72248
72499
  return Math.min(a, b);
72249
72500
  }
72501
+ /**
72502
+ * Save-state text next to the slide counter, mirroring React's StatusBar:
72503
+ * autosave saving/saved-time/error take precedence, then the dirty flag, then
72504
+ * "All saved".
72505
+ */
72506
+ saveStatusText() {
72507
+ const status = this.autosaveStatus();
72508
+ if (status?.state === 'saving') {
72509
+ return this.translate.instant('pptx.autosave.saving');
72510
+ }
72511
+ if (status?.state === 'saved') {
72512
+ return this.translate.instant('pptx.autosave.saved', {
72513
+ time: this.formatAutosaveAge(status.timestamp),
72514
+ });
72515
+ }
72516
+ if (status?.state === 'error') {
72517
+ return this.translate.instant('pptx.autosave.error');
72518
+ }
72519
+ return this.translate.instant(this.dirty() ? 'pptx.statusBar.unsavedChanges' : 'pptx.statusBar.allSaved');
72520
+ }
72521
+ /** Colour override for the save-state text while saving (yellow) / errored (red). */
72522
+ saveStateClass() {
72523
+ const state = this.autosaveStatus()?.state;
72524
+ if (state === 'error') {
72525
+ return 'text-red-400';
72526
+ }
72527
+ if (state === 'saving') {
72528
+ return 'text-yellow-400';
72529
+ }
72530
+ return '';
72531
+ }
72532
+ /** Relative age label for a saved timestamp ("just now" / "N min ago"). */
72533
+ formatAutosaveAge(timestamp) {
72534
+ const minutes = Math.floor((Date.now() - timestamp) / 60_000);
72535
+ if (minutes < 1) {
72536
+ return this.translate.instant('pptx.autosave.justNow');
72537
+ }
72538
+ if (minutes === 1) {
72539
+ return this.translate.instant('pptx.autosave.oneMinAgo');
72540
+ }
72541
+ return this.translate.instant('pptx.autosave.minutesAgo', { count: minutes });
72542
+ }
72250
72543
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.5", ngImport: i0, type: StatusBarComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
72251
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.5", type: StatusBarComponent, isStandalone: true, selector: "pptx-status-bar", inputs: { slideIndex: { classPropertyName: "slideIndex", publicName: "slideIndex", isSignal: true, isRequired: false, transformFunction: null }, slideCount: { classPropertyName: "slideCount", publicName: "slideCount", isSignal: true, isRequired: false, transformFunction: null }, canEdit: { classPropertyName: "canEdit", publicName: "canEdit", isSignal: true, isRequired: false, transformFunction: null }, dirty: { classPropertyName: "dirty", publicName: "dirty", isSignal: true, isRequired: false, transformFunction: null }, notesOpen: { classPropertyName: "notesOpen", publicName: "notesOpen", isSignal: true, isRequired: false, transformFunction: null }, zoomPercent: { classPropertyName: "zoomPercent", publicName: "zoomPercent", isSignal: true, isRequired: false, transformFunction: null }, sorterActive: { classPropertyName: "sorterActive", publicName: "sorterActive", isSignal: true, isRequired: false, transformFunction: null }, presenting: { classPropertyName: "presenting", publicName: "presenting", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { toggleNotes: "toggleNotes", normalView: "normalView", openSorter: "openSorter", slideShow: "slideShow", zoomIn: "zoomIn", zoomOut: "zoomOut", zoomReset: "zoomReset" }, ngImport: i0, template: `
72544
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.5", type: StatusBarComponent, isStandalone: true, selector: "pptx-status-bar", inputs: { slideIndex: { classPropertyName: "slideIndex", publicName: "slideIndex", isSignal: true, isRequired: false, transformFunction: null }, slideCount: { classPropertyName: "slideCount", publicName: "slideCount", isSignal: true, isRequired: false, transformFunction: null }, canEdit: { classPropertyName: "canEdit", publicName: "canEdit", isSignal: true, isRequired: false, transformFunction: null }, dirty: { classPropertyName: "dirty", publicName: "dirty", isSignal: true, isRequired: false, transformFunction: null }, autosaveStatus: { classPropertyName: "autosaveStatus", publicName: "autosaveStatus", isSignal: true, isRequired: false, transformFunction: null }, notesOpen: { classPropertyName: "notesOpen", publicName: "notesOpen", isSignal: true, isRequired: false, transformFunction: null }, zoomPercent: { classPropertyName: "zoomPercent", publicName: "zoomPercent", isSignal: true, isRequired: false, transformFunction: null }, sorterActive: { classPropertyName: "sorterActive", publicName: "sorterActive", isSignal: true, isRequired: false, transformFunction: null }, presenting: { classPropertyName: "presenting", publicName: "presenting", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { toggleNotes: "toggleNotes", normalView: "normalView", openSorter: "openSorter", slideShow: "slideShow", zoomIn: "zoomIn", zoomOut: "zoomOut", zoomReset: "zoomReset" }, ngImport: i0, template: `
72252
72545
  <div
72253
72546
  class="flex w-full items-center gap-1 border-t border-border bg-secondary/50 px-2 py-0.5 text-[10px] text-muted-foreground"
72254
72547
  >
@@ -72267,9 +72560,7 @@ class StatusBarComponent {
72267
72560
 
72268
72561
  @if (canEdit()) {
72269
72562
  <div class="mx-1 h-3 w-px bg-border/60"></div>
72270
- <span class="shrink-0">{{
72271
- (dirty() ? 'pptx.statusBar.unsavedChanges' : 'pptx.statusBar.allSaved') | translate
72272
- }}</span>
72563
+ <span class="shrink-0" [ngClass]="saveStateClass()">{{ saveStatusText() }}</span>
72273
72564
  }
72274
72565
 
72275
72566
  <!-- Center spacer -->
@@ -72384,9 +72675,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.5", ngImpor
72384
72675
 
72385
72676
  @if (canEdit()) {
72386
72677
  <div class="mx-1 h-3 w-px bg-border/60"></div>
72387
- <span class="shrink-0">{{
72388
- (dirty() ? 'pptx.statusBar.unsavedChanges' : 'pptx.statusBar.allSaved') | translate
72389
- }}</span>
72678
+ <span class="shrink-0" [ngClass]="saveStateClass()">{{ saveStatusText() }}</span>
72390
72679
  }
72391
72680
 
72392
72681
  <!-- Center spacer -->
@@ -72475,7 +72764,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.5", ngImpor
72475
72764
  </div>
72476
72765
  `,
72477
72766
  }]
72478
- }], propDecorators: { slideIndex: [{ type: i0.Input, args: [{ isSignal: true, alias: "slideIndex", required: false }] }], slideCount: [{ type: i0.Input, args: [{ isSignal: true, alias: "slideCount", required: false }] }], canEdit: [{ type: i0.Input, args: [{ isSignal: true, alias: "canEdit", required: false }] }], dirty: [{ type: i0.Input, args: [{ isSignal: true, alias: "dirty", required: false }] }], notesOpen: [{ type: i0.Input, args: [{ isSignal: true, alias: "notesOpen", required: false }] }], zoomPercent: [{ type: i0.Input, args: [{ isSignal: true, alias: "zoomPercent", required: false }] }], sorterActive: [{ type: i0.Input, args: [{ isSignal: true, alias: "sorterActive", required: false }] }], presenting: [{ type: i0.Input, args: [{ isSignal: true, alias: "presenting", required: false }] }], toggleNotes: [{ type: i0.Output, args: ["toggleNotes"] }], normalView: [{ type: i0.Output, args: ["normalView"] }], openSorter: [{ type: i0.Output, args: ["openSorter"] }], slideShow: [{ type: i0.Output, args: ["slideShow"] }], zoomIn: [{ type: i0.Output, args: ["zoomIn"] }], zoomOut: [{ type: i0.Output, args: ["zoomOut"] }], zoomReset: [{ type: i0.Output, args: ["zoomReset"] }] } });
72767
+ }], propDecorators: { slideIndex: [{ type: i0.Input, args: [{ isSignal: true, alias: "slideIndex", required: false }] }], slideCount: [{ type: i0.Input, args: [{ isSignal: true, alias: "slideCount", required: false }] }], canEdit: [{ type: i0.Input, args: [{ isSignal: true, alias: "canEdit", required: false }] }], dirty: [{ type: i0.Input, args: [{ isSignal: true, alias: "dirty", required: false }] }], autosaveStatus: [{ type: i0.Input, args: [{ isSignal: true, alias: "autosaveStatus", required: false }] }], notesOpen: [{ type: i0.Input, args: [{ isSignal: true, alias: "notesOpen", required: false }] }], zoomPercent: [{ type: i0.Input, args: [{ isSignal: true, alias: "zoomPercent", required: false }] }], sorterActive: [{ type: i0.Input, args: [{ isSignal: true, alias: "sorterActive", required: false }] }], presenting: [{ type: i0.Input, args: [{ isSignal: true, alias: "presenting", required: false }] }], toggleNotes: [{ type: i0.Output, args: ["toggleNotes"] }], normalView: [{ type: i0.Output, args: ["normalView"] }], openSorter: [{ type: i0.Output, args: ["openSorter"] }], slideShow: [{ type: i0.Output, args: ["slideShow"] }], zoomIn: [{ type: i0.Output, args: ["zoomIn"] }], zoomOut: [{ type: i0.Output, args: ["zoomOut"] }], zoomReset: [{ type: i0.Output, args: ["zoomReset"] }] } });
72479
72768
 
72480
72769
  /**
72481
72770
  * theme-gallery-presets.ts: the exact theme set shown in the Design tab's
@@ -72871,6 +73160,292 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.5", ngImpor
72871
73160
  }]
72872
73161
  }], propDecorators: { open: [{ type: i0.Input, args: [{ isSignal: true, alias: "open", required: false }] }], activeName: [{ type: i0.Input, args: [{ isSignal: true, alias: "activeName", required: false }] }], applyTheme: [{ type: i0.Output, args: ["applyTheme"] }], close: [{ type: i0.Output, args: ["close"] }] } });
72873
73162
 
73163
+ /**
73164
+ * title-bar.component.ts: PowerPoint-style top chrome row for the Angular
73165
+ * editor, at parity with React's `viewer/components/toolbar/TitleBar.tsx`.
73166
+ *
73167
+ * Renders (left to right): the square "P" app mark, an AutoSave label + switch
73168
+ * toggle + On/Off text, quick-access Save/Undo/Redo icon buttons, the open
73169
+ * document's name + a save-location status (resolved via the shared
73170
+ * {@link resolveTitleBarStatusKey}), and a centred search button that opens
73171
+ * Find & Replace. Rendered ABOVE and OUTSIDE the ribbon's `role="toolbar"`
73172
+ * container so the toolbar height stays measurable for the e2e parity spec.
73173
+ *
73174
+ * Purely presentational + `OnPush`: every action is an `output()` the
73175
+ * {@link PowerPointViewerComponent} already has handlers for. Class tokens come
73176
+ * verbatim from the shared {@link TITLE_BAR_CLASSES} so the three bindings stay
73177
+ * pixel-identical. The host is a plain block (no `display:contents`) so the row
73178
+ * renders as one 36px flex strip.
73179
+ */
73180
+ class TitleBarComponent {
73181
+ /** Whether the deck is editable (gates the autosave/quick-access/search chrome). */
73182
+ canEdit = input(false, /* @ts-ignore */
73183
+ ...(ngDevMode ? [{ debugName: "canEdit" }] : /* istanbul ignore next */ []));
73184
+ /** Display name of the open document (host-supplied). */
73185
+ fileName = input(undefined, /* @ts-ignore */
73186
+ ...(ngDevMode ? [{ debugName: "fileName" }] : /* istanbul ignore next */ []));
73187
+ /** Whether the document has unsaved changes. */
73188
+ isDirty = input(false, /* @ts-ignore */
73189
+ ...(ngDevMode ? [{ debugName: "isDirty" }] : /* istanbul ignore next */ []));
73190
+ /** Current autosave engine status (drives the save-location text). */
73191
+ autosaveStatus = input(undefined, /* @ts-ignore */
73192
+ ...(ngDevMode ? [{ debugName: "autosaveStatus" }] : /* istanbul ignore next */ []));
73193
+ /** Whether the AutoSave toggle is on. */
73194
+ autosaveEnabled = input(true, /* @ts-ignore */
73195
+ ...(ngDevMode ? [{ debugName: "autosaveEnabled" }] : /* istanbul ignore next */ []));
73196
+ canUndo = input(false, /* @ts-ignore */
73197
+ ...(ngDevMode ? [{ debugName: "canUndo" }] : /* istanbul ignore next */ []));
73198
+ canRedo = input(false, /* @ts-ignore */
73199
+ ...(ngDevMode ? [{ debugName: "canRedo" }] : /* istanbul ignore next */ []));
73200
+ undoLabel = input(undefined, /* @ts-ignore */
73201
+ ...(ngDevMode ? [{ debugName: "undoLabel" }] : /* istanbul ignore next */ []));
73202
+ redoLabel = input(undefined, /* @ts-ignore */
73203
+ ...(ngDevMode ? [{ debugName: "redoLabel" }] : /* istanbul ignore next */ []));
73204
+ /** Whether the Find & Replace panel is open (search-button active state). */
73205
+ findReplaceOpen = input(false, /* @ts-ignore */
73206
+ ...(ngDevMode ? [{ debugName: "findReplaceOpen" }] : /* istanbul ignore next */ []));
73207
+ toggleAutosave = output();
73208
+ /** Quick-access save (downloads the `.pptx`). */
73209
+ save = output();
73210
+ undo = output();
73211
+ redo = output();
73212
+ toggleFindReplace = output();
73213
+ tb = TITLE_BAR_CLASSES;
73214
+ defaultFileKey = TITLE_BAR_DEFAULT_FILE_KEY;
73215
+ /** The i18n key for the save-location status text (next to the file name). */
73216
+ statusKey = computed(() => resolveTitleBarStatusKey({
73217
+ autosaveState: this.autosaveStatus()?.state ?? 'idle',
73218
+ isDirty: this.isDirty(),
73219
+ autosaveEnabled: this.autosaveEnabled(),
73220
+ }), /* @ts-ignore */
73221
+ ...(ngDevMode ? [{ debugName: "statusKey" }] : /* istanbul ignore next */ []));
73222
+ /** Colour override for the status text on saving/error (when autosave is on). */
73223
+ statusStateClass = computed(() => {
73224
+ const state = this.autosaveStatus()?.state;
73225
+ if (!this.autosaveEnabled()) {
73226
+ return '';
73227
+ }
73228
+ if (state === 'error') {
73229
+ return this.tb.statusError;
73230
+ }
73231
+ if (state === 'saving') {
73232
+ return this.tb.statusSaving;
73233
+ }
73234
+ return '';
73235
+ }, /* @ts-ignore */
73236
+ ...(ngDevMode ? [{ debugName: "statusStateClass" }] : /* istanbul ignore next */ []));
73237
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.5", ngImport: i0, type: TitleBarComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
73238
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.5", type: TitleBarComponent, isStandalone: true, selector: "pptx-title-bar", inputs: { canEdit: { classPropertyName: "canEdit", publicName: "canEdit", isSignal: true, isRequired: false, transformFunction: null }, fileName: { classPropertyName: "fileName", publicName: "fileName", isSignal: true, isRequired: false, transformFunction: null }, isDirty: { classPropertyName: "isDirty", publicName: "isDirty", isSignal: true, isRequired: false, transformFunction: null }, autosaveStatus: { classPropertyName: "autosaveStatus", publicName: "autosaveStatus", isSignal: true, isRequired: false, transformFunction: null }, autosaveEnabled: { classPropertyName: "autosaveEnabled", publicName: "autosaveEnabled", isSignal: true, isRequired: false, transformFunction: null }, canUndo: { classPropertyName: "canUndo", publicName: "canUndo", isSignal: true, isRequired: false, transformFunction: null }, canRedo: { classPropertyName: "canRedo", publicName: "canRedo", isSignal: true, isRequired: false, transformFunction: null }, undoLabel: { classPropertyName: "undoLabel", publicName: "undoLabel", isSignal: true, isRequired: false, transformFunction: null }, redoLabel: { classPropertyName: "redoLabel", publicName: "redoLabel", isSignal: true, isRequired: false, transformFunction: null }, findReplaceOpen: { classPropertyName: "findReplaceOpen", publicName: "findReplaceOpen", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { toggleAutosave: "toggleAutosave", save: "save", undo: "undo", redo: "redo", toggleFindReplace: "toggleFindReplace" }, ngImport: i0, template: `
73239
+ <div [class]="tb.container" data-pptx-title-bar>
73240
+ <span [class]="tb.logo" aria-hidden="true">P</span>
73241
+
73242
+ @if (canEdit()) {
73243
+ <span [class]="tb.autosaveGroup">
73244
+ <span [class]="tb.autosaveLabel">{{ 'pptx.titleBar.autoSave' | translate }}</span>
73245
+ <button
73246
+ type="button"
73247
+ role="switch"
73248
+ [attr.aria-checked]="autosaveEnabled()"
73249
+ [class]="tb.toggleTrack"
73250
+ [ngClass]="autosaveEnabled() ? tb.toggleTrackOn : tb.toggleTrackOff"
73251
+ [title]="'pptx.titleBar.toggleAutoSave' | translate"
73252
+ [attr.aria-label]="'pptx.titleBar.toggleAutoSave' | translate"
73253
+ (click)="toggleAutosave.emit()"
73254
+ >
73255
+ <span
73256
+ [class]="tb.toggleKnob"
73257
+ [ngClass]="autosaveEnabled() ? tb.toggleKnobOn : tb.toggleKnobOff"
73258
+ ></span>
73259
+ </button>
73260
+ <span [class]="tb.autosaveLabel">{{
73261
+ (autosaveEnabled() ? 'pptx.titleBar.autoSaveOn' : 'pptx.titleBar.autoSaveOff')
73262
+ | translate
73263
+ }}</span>
73264
+ </span>
73265
+
73266
+ <div [class]="tb.separator"></div>
73267
+
73268
+ <button
73269
+ type="button"
73270
+ [class]="tb.quickButton"
73271
+ [title]="'pptx.titleBar.save' | translate"
73272
+ [attr.aria-label]="'pptx.titleBar.save' | translate"
73273
+ (click)="save.emit()"
73274
+ >
73275
+ 💾
73276
+ </button>
73277
+ <button
73278
+ type="button"
73279
+ [class]="tb.quickButton"
73280
+ [disabled]="!canUndo()"
73281
+ [title]="
73282
+ undoLabel()
73283
+ ? ('pptx.toolbar.undoAction' | translate: { action: undoLabel() })
73284
+ : ('pptx.toolbar.undo' | translate)
73285
+ "
73286
+ [attr.aria-label]="'pptx.toolbar.undo' | translate"
73287
+ (click)="undo.emit()"
73288
+ >
73289
+
73290
+ </button>
73291
+ <button
73292
+ type="button"
73293
+ [class]="tb.quickButton"
73294
+ [disabled]="!canRedo()"
73295
+ [title]="
73296
+ redoLabel()
73297
+ ? ('pptx.toolbar.redoAction' | translate: { action: redoLabel() })
73298
+ : ('pptx.toolbar.redo' | translate)
73299
+ "
73300
+ [attr.aria-label]="'pptx.toolbar.redo' | translate"
73301
+ (click)="redo.emit()"
73302
+ >
73303
+
73304
+ </button>
73305
+
73306
+ <div [class]="tb.separator"></div>
73307
+ }
73308
+
73309
+ <span [class]="tb.fileGroup">
73310
+ <span [class]="tb.fileName">{{ fileName() || (defaultFileKey | translate) }}</span>
73311
+ @if (canEdit()) {
73312
+ <span [class]="tb.statusDot" aria-hidden="true">&bull;</span>
73313
+ <span [class]="tb.statusText" [ngClass]="statusStateClass()">{{
73314
+ statusKey() | translate
73315
+ }}</span>
73316
+ }
73317
+ </span>
73318
+
73319
+ <span [class]="tb.searchWrap">
73320
+ @if (canEdit()) {
73321
+ <button
73322
+ type="button"
73323
+ [class]="tb.searchBox"
73324
+ [ngClass]="findReplaceOpen() ? 'text-foreground bg-background' : ''"
73325
+ [title]="'pptx.findReplace.title' | translate"
73326
+ [attr.aria-label]="'pptx.titleBar.search' | translate"
73327
+ (click)="toggleFindReplace.emit()"
73328
+ >
73329
+ <span [class]="tb.searchIcon" aria-hidden="true">⌕</span>
73330
+ <span [class]="tb.searchLabel">{{ 'pptx.titleBar.search' | translate }}</span>
73331
+ </button>
73332
+ }
73333
+ </span>
73334
+
73335
+ <span [class]="tb.rightSpacer"></span>
73336
+ </div>
73337
+ `, isInline: true, dependencies: [{ kind: "directive", type: NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "pipe", type: TranslatePipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
73338
+ }
73339
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.5", ngImport: i0, type: TitleBarComponent, decorators: [{
73340
+ type: Component,
73341
+ args: [{
73342
+ selector: 'pptx-title-bar',
73343
+ standalone: true,
73344
+ changeDetection: ChangeDetectionStrategy.OnPush,
73345
+ imports: [NgClass, TranslatePipe],
73346
+ template: `
73347
+ <div [class]="tb.container" data-pptx-title-bar>
73348
+ <span [class]="tb.logo" aria-hidden="true">P</span>
73349
+
73350
+ @if (canEdit()) {
73351
+ <span [class]="tb.autosaveGroup">
73352
+ <span [class]="tb.autosaveLabel">{{ 'pptx.titleBar.autoSave' | translate }}</span>
73353
+ <button
73354
+ type="button"
73355
+ role="switch"
73356
+ [attr.aria-checked]="autosaveEnabled()"
73357
+ [class]="tb.toggleTrack"
73358
+ [ngClass]="autosaveEnabled() ? tb.toggleTrackOn : tb.toggleTrackOff"
73359
+ [title]="'pptx.titleBar.toggleAutoSave' | translate"
73360
+ [attr.aria-label]="'pptx.titleBar.toggleAutoSave' | translate"
73361
+ (click)="toggleAutosave.emit()"
73362
+ >
73363
+ <span
73364
+ [class]="tb.toggleKnob"
73365
+ [ngClass]="autosaveEnabled() ? tb.toggleKnobOn : tb.toggleKnobOff"
73366
+ ></span>
73367
+ </button>
73368
+ <span [class]="tb.autosaveLabel">{{
73369
+ (autosaveEnabled() ? 'pptx.titleBar.autoSaveOn' : 'pptx.titleBar.autoSaveOff')
73370
+ | translate
73371
+ }}</span>
73372
+ </span>
73373
+
73374
+ <div [class]="tb.separator"></div>
73375
+
73376
+ <button
73377
+ type="button"
73378
+ [class]="tb.quickButton"
73379
+ [title]="'pptx.titleBar.save' | translate"
73380
+ [attr.aria-label]="'pptx.titleBar.save' | translate"
73381
+ (click)="save.emit()"
73382
+ >
73383
+ 💾
73384
+ </button>
73385
+ <button
73386
+ type="button"
73387
+ [class]="tb.quickButton"
73388
+ [disabled]="!canUndo()"
73389
+ [title]="
73390
+ undoLabel()
73391
+ ? ('pptx.toolbar.undoAction' | translate: { action: undoLabel() })
73392
+ : ('pptx.toolbar.undo' | translate)
73393
+ "
73394
+ [attr.aria-label]="'pptx.toolbar.undo' | translate"
73395
+ (click)="undo.emit()"
73396
+ >
73397
+
73398
+ </button>
73399
+ <button
73400
+ type="button"
73401
+ [class]="tb.quickButton"
73402
+ [disabled]="!canRedo()"
73403
+ [title]="
73404
+ redoLabel()
73405
+ ? ('pptx.toolbar.redoAction' | translate: { action: redoLabel() })
73406
+ : ('pptx.toolbar.redo' | translate)
73407
+ "
73408
+ [attr.aria-label]="'pptx.toolbar.redo' | translate"
73409
+ (click)="redo.emit()"
73410
+ >
73411
+
73412
+ </button>
73413
+
73414
+ <div [class]="tb.separator"></div>
73415
+ }
73416
+
73417
+ <span [class]="tb.fileGroup">
73418
+ <span [class]="tb.fileName">{{ fileName() || (defaultFileKey | translate) }}</span>
73419
+ @if (canEdit()) {
73420
+ <span [class]="tb.statusDot" aria-hidden="true">&bull;</span>
73421
+ <span [class]="tb.statusText" [ngClass]="statusStateClass()">{{
73422
+ statusKey() | translate
73423
+ }}</span>
73424
+ }
73425
+ </span>
73426
+
73427
+ <span [class]="tb.searchWrap">
73428
+ @if (canEdit()) {
73429
+ <button
73430
+ type="button"
73431
+ [class]="tb.searchBox"
73432
+ [ngClass]="findReplaceOpen() ? 'text-foreground bg-background' : ''"
73433
+ [title]="'pptx.findReplace.title' | translate"
73434
+ [attr.aria-label]="'pptx.titleBar.search' | translate"
73435
+ (click)="toggleFindReplace.emit()"
73436
+ >
73437
+ <span [class]="tb.searchIcon" aria-hidden="true">⌕</span>
73438
+ <span [class]="tb.searchLabel">{{ 'pptx.titleBar.search' | translate }}</span>
73439
+ </button>
73440
+ }
73441
+ </span>
73442
+
73443
+ <span [class]="tb.rightSpacer"></span>
73444
+ </div>
73445
+ `,
73446
+ }]
73447
+ }], propDecorators: { canEdit: [{ type: i0.Input, args: [{ isSignal: true, alias: "canEdit", required: false }] }], fileName: [{ type: i0.Input, args: [{ isSignal: true, alias: "fileName", required: false }] }], isDirty: [{ type: i0.Input, args: [{ isSignal: true, alias: "isDirty", required: false }] }], autosaveStatus: [{ type: i0.Input, args: [{ isSignal: true, alias: "autosaveStatus", required: false }] }], autosaveEnabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "autosaveEnabled", required: false }] }], canUndo: [{ type: i0.Input, args: [{ isSignal: true, alias: "canUndo", required: false }] }], canRedo: [{ type: i0.Input, args: [{ isSignal: true, alias: "canRedo", required: false }] }], undoLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "undoLabel", required: false }] }], redoLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "redoLabel", required: false }] }], findReplaceOpen: [{ type: i0.Input, args: [{ isSignal: true, alias: "findReplaceOpen", required: false }] }], toggleAutosave: [{ type: i0.Output, args: ["toggleAutosave"] }], save: [{ type: i0.Output, args: ["save"] }], undo: [{ type: i0.Output, args: ["undo"] }], redo: [{ type: i0.Output, args: ["redo"] }], toggleFindReplace: [{ type: i0.Output, args: ["toggleFindReplace"] }] } });
73448
+
72874
73449
  /**
72875
73450
  * viewer-dialogs.service.ts: Viewer-scoped open-state + light state for the
72876
73451
  * secondary dialogs and side panels (equation editor, set-up-slide-show,
@@ -78237,6 +78812,13 @@ class PowerPointViewerComponent {
78237
78812
  */
78238
78813
  filePath = input(undefined, /* @ts-ignore */
78239
78814
  ...(ngDevMode ? [{ debugName: "filePath" }] : /* istanbul ignore next */ []));
78815
+ /**
78816
+ * Display name of the open document, shown in the title bar next to the
78817
+ * save-location status. Falls back to a localised "Presentation" when omitted.
78818
+ * Mirrors React's `fileName` prop.
78819
+ */
78820
+ fileName = input(undefined, /* @ts-ignore */
78821
+ ...(ngDevMode ? [{ debugName: "fileName" }] : /* istanbul ignore next */ []));
78240
78822
  /** Optional real-time collaboration config; when set, connects and shows remote cursors. */
78241
78823
  collaboration = input(undefined, /* @ts-ignore */
78242
78824
  ...(ngDevMode ? [{ debugName: "collaboration" }] : /* istanbul ignore next */ []));
@@ -78292,6 +78874,7 @@ class PowerPointViewerComponent {
78292
78874
  fonts = inject(EmbeddedFontsService);
78293
78875
  collab = inject(CollaborationService);
78294
78876
  accessibility = inject(AccessibilityService);
78877
+ autosave = inject(AutosaveService);
78295
78878
  print = inject(PrintService);
78296
78879
  mobile = inject(IsMobileService);
78297
78880
  smartArt3DSvc = inject(SmartArt3DService);
@@ -78367,6 +78950,9 @@ class PowerPointViewerComponent {
78367
78950
  /** Whether the left slides panel is collapsed (top-bar sidebar toggle). */
78368
78951
  slidesPanelCollapsed = signal(false, /* @ts-ignore */
78369
78952
  ...(ngDevMode ? [{ debugName: "slidesPanelCollapsed" }] : /* istanbul ignore next */ []));
78953
+ /** Whether periodic autosave is enabled (title-bar AutoSave toggle; default on). */
78954
+ autosaveEnabled = signal(true, /* @ts-ignore */
78955
+ ...(ngDevMode ? [{ debugName: "autosaveEnabled" }] : /* istanbul ignore next */ []));
78370
78956
  // ── Draw tool state (forwarded to slide-canvas) ───────────────────────────
78371
78957
  /** Active drawing tool (from the ribbon Draw tab). */
78372
78958
  activeDrawTool = signal('select', /* @ts-ignore */
@@ -78663,6 +79249,15 @@ class PowerPointViewerComponent {
78663
79249
  activeSlideIndex: () => this.activeSlideIndex(),
78664
79250
  emitPropertiesChange: (patch) => this.propertiesChange.emit(patch),
78665
79251
  });
79252
+ // Hand the autosave engine the reactive accessors it reads (enabled toggle,
79253
+ // file-path key, dirty flag) and a deck serialiser. It writes a recovery
79254
+ // snapshot to the shared IndexedDB store every N seconds while dirty.
79255
+ this.autosave.bind({
79256
+ enabled: () => this.autosaveEnabled(),
79257
+ filePath: () => this.filePath(),
79258
+ isDirty: () => this.editor.dirty(),
79259
+ serialize: () => this.serializeForAutosave(),
79260
+ });
78666
79261
  }
78667
79262
  /**
78668
79263
  * Serialise the current presentation to `.pptx` bytes (imperative handle).
@@ -78683,6 +79278,27 @@ class PowerPointViewerComponent {
78683
79278
  goNext() {
78684
79279
  this.goTo(this.activeSlideIndex() + 1);
78685
79280
  }
79281
+ /** Toggle the Find & Replace panel from the title-bar search button. */
79282
+ toggleFindReplace() {
79283
+ if (this.findReplace.showFindReplace()) {
79284
+ this.findReplace.showFindReplace.set(false);
79285
+ return;
79286
+ }
79287
+ this.findReplace.openFindReplace();
79288
+ }
79289
+ /**
79290
+ * Serialise the edited deck (templates merged back) to `.pptx` bytes for an
79291
+ * autosave recovery snapshot. Returns null when the deck is read-only so the
79292
+ * autosave engine skips the write. Distinct from {@link getContent}, this does
79293
+ * NOT emit `contentChange` (autosave is a background recovery write, not a
79294
+ * host-visible save).
79295
+ */
79296
+ async serializeForAutosave() {
79297
+ if (!this.canEdit()) {
79298
+ return null;
79299
+ }
79300
+ return this.loader.saveSlides(buildSaveSlides(this.editor.slides(), this.editor.templateElementsBySlideId()));
79301
+ }
78686
79302
  /** Review ▸ Compare: pick a `.pptx` and diff it against the current deck. */
78687
79303
  onOpenCompare() {
78688
79304
  this.compareSvc.startCompare();
@@ -78755,7 +79371,7 @@ class PowerPointViewerComponent {
78755
79371
  return (this.mainEl()?.nativeElement.querySelector('.pptx-ng-canvas-stage') ?? undefined);
78756
79372
  }
78757
79373
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.5", ngImport: i0, type: PowerPointViewerComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
78758
- 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 }, 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: [
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: [
78759
79375
  LoadContentService,
78760
79376
  ExportService,
78761
79377
  EditorStateService,
@@ -78763,6 +79379,7 @@ class PowerPointViewerComponent {
78763
79379
  EmbeddedFontsService,
78764
79380
  CollaborationService,
78765
79381
  AccessibilityService,
79382
+ AutosaveService,
78766
79383
  PrintService,
78767
79384
  IsMobileService,
78768
79385
  SmartArt3DService,
@@ -78804,6 +79421,23 @@ class PowerPointViewerComponent {
78804
79421
  </div>
78805
79422
  } @else {
78806
79423
  @if (!mobile.isMobile()) {
79424
+ <pptx-title-bar
79425
+ [canEdit]="canEdit()"
79426
+ [fileName]="fileName()"
79427
+ [isDirty]="editor.dirty()"
79428
+ [autosaveStatus]="autosave.status()"
79429
+ [autosaveEnabled]="autosaveEnabled()"
79430
+ [canUndo]="editor.canUndo()"
79431
+ [canRedo]="editor.canRedo()"
79432
+ [undoLabel]="editor.undoLabel()"
79433
+ [redoLabel]="editor.redoLabel()"
79434
+ [findReplaceOpen]="findReplace.showFind() || findReplace.showFindReplace()"
79435
+ (toggleAutosave)="autosaveEnabled.update(v => !v)"
79436
+ (save)="fileIO.saveAsPptx()"
79437
+ (undo)="editor.undo()"
79438
+ (redo)="editor.redo()"
79439
+ (toggleFindReplace)="toggleFindReplace()"
79440
+ />
78807
79441
  <pptx-ribbon
78808
79442
  [slideIndex]="activeSlideIndex()"
78809
79443
  [slideCount]="slideCount()"
@@ -78829,6 +79463,7 @@ class PowerPointViewerComponent {
78829
79463
  (find)="findReplace.showFind.set(true)"
78830
79464
  (present)="presentationMode.present()"
78831
79465
  (presenter)="presentationMode.presentPresenter()"
79466
+ (record)="presentationMode.present()"
78832
79467
  (share)="session.showShare.set(true)"
78833
79468
  (broadcast)="session.showBroadcast.set(true)"
78834
79469
  (openFile)="fileIO.openFile()"
@@ -79080,6 +79715,7 @@ class PowerPointViewerComponent {
79080
79715
  [slideCount]="slideCount()"
79081
79716
  [canEdit]="canEdit()"
79082
79717
  [dirty]="editor.dirty()"
79718
+ [autosaveStatus]="autosave.status()"
79083
79719
  [notesOpen]="mobileSheetSvc.showNotes()"
79084
79720
  [zoomPercent]="zoomSvc.zoomPercent()"
79085
79721
  [sorterActive]="showSorter()"
@@ -79353,7 +79989,7 @@ class PowerPointViewerComponent {
79353
79989
  />
79354
79990
  }
79355
79991
  </div>
79356
- `, isInline: true, dependencies: [{ kind: "directive", type: NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }, { kind: "component", type: SlideCanvasComponent, selector: "pptx-slide-canvas", inputs: ["slide", "canvasSize", "mediaDataUrls", "zoom", "editable", "showGrid", "showRulers", "showGuides", "snapToGrid", "snapToGuides", "autoFit", "interactive", "selectedIds", "editingId", "editTemplateMode", "templateElements", "drawTool", "drawColor", "drawWidth"], outputs: ["elementSelect", "backgroundClick", "transformStart", "transformUpdate", "contextMenu", "textEditStart", "textCommit", "textCancel", "textFormat", "rotateUpdate", "marqueeSelect", "inkStrokeComplete", "eraserHit", "cellCommit", "tableChange"] }, { kind: "component", type: PresentationOverlayComponent, selector: "pptx-presentation-overlay", inputs: ["slides", "canvasSize", "mediaDataUrls", "startIndex"], outputs: ["indexChange", "closed", "annotationsExit"] }, { kind: "component", type: PresenterViewComponent, selector: "pptx-presenter-view", inputs: ["slides", "currentSlideIndex", "canvasSize", "templateElements", "mediaDataUrls", "presentationStartTime", "isAudienceWindowOpen"], outputs: ["movePresentationSlide", "exit", "openAudienceWindow", "closeAudienceWindow"] }, { kind: "component", type: MobilePresenterViewComponent, selector: "pptx-mobile-presenter-view", inputs: ["slides", "currentSlideIndex", "canvasSize", "templateElements", "mediaDataUrls", "presentationStartTime"], outputs: ["movePresentationSlide", "exit"] }, { kind: "component", type: SlideSorterOverlayComponent, selector: "pptx-slide-sorter-overlay", inputs: ["slides", "canvasSize", "mediaDataUrls", "activeIndex"], outputs: ["select", "closed"] }, { kind: "component", type: FindBarComponent, selector: "pptx-find-bar", inputs: ["slides"], outputs: ["navigate", "closed"] }, { kind: "component", type: FindReplaceBarComponent, selector: "pptx-find-replace-bar", inputs: ["matchCount", "matchIndex"], outputs: ["find", "navigate", "replaceOne", "replaceAll", "close"] }, { kind: "component", type: InspectorPanelComponent, selector: "pptx-inspector-panel", inputs: ["element", "slideIndex"] }, { kind: "component", type: SlidesPanelComponent, selector: "pptx-slides-panel", inputs: ["canvasSize", "mediaDataUrls", "activeIndex"], outputs: ["select"] }, { kind: "component", type: StatusBarComponent, selector: "pptx-status-bar", inputs: ["slideIndex", "slideCount", "canEdit", "dirty", "notesOpen", "zoomPercent", "sorterActive", "presenting"], outputs: ["toggleNotes", "normalView", "openSorter", "slideShow", "zoomIn", "zoomOut", "zoomReset"] }, { kind: "component", type: EditorContextMenuComponent, selector: "pptx-editor-context-menu", inputs: ["x", "y", "slideIndex"], outputs: ["closed"] }, { kind: "component", type: ExportProgressModalComponent, selector: "pptx-export-progress-modal", inputs: ["open", "title", "progress", "statusMessage"], outputs: ["cancel"] }, { kind: "component", type: CommentsPanelComponent, selector: "pptx-comments-panel", inputs: ["comments", "authorName"], outputs: ["add", "remove", "resolve"] }, { kind: "component", type: SignaturesPanelComponent, selector: "pptx-signatures-panel", inputs: ["signatures"] }, { kind: "component", type: AccessibilityPanelComponent, selector: "pptx-accessibility-panel", inputs: ["issues"], outputs: ["selectSlide"] }, { kind: "component", type: CollaborationCursorsComponent, selector: "pptx-collaboration-cursors", inputs: ["cursors", "zoom"] }, { kind: "component", type: RemoteSelectionOverlayComponent, selector: "pptx-remote-selection-overlay", inputs: ["presences", "elements", "activeSlideIndex", "zoom"] }, { kind: "component", type: FollowModeBarComponent, selector: "pptx-follow-mode-bar", inputs: ["presences", "followedClientId"], outputs: ["follow"] }, { kind: "component", type: PropertiesDialogComponent, selector: "pptx-properties-dialog", inputs: ["open", "properties"], outputs: ["save", "close"] }, { kind: "component", type: HyperlinkDialogComponent, selector: "pptx-hyperlink-dialog", inputs: ["open", "element"], outputs: ["save", "close"] }, { kind: "component", type: PrintDialogComponent, selector: "pptx-print-dialog", inputs: ["slides", "activeSlideIndex", "defaultSlidesPerPage", "defaultFrameSlides"], outputs: ["print", "cancel"] }, { kind: "component", type: ShareDialogComponent, selector: "pptx-share-dialog", inputs: ["open", "defaults", "active", "connected", "userCount", "shareUrl", "p2p"], outputs: ["start", "stop", "close"] }, { kind: "component", type: BroadcastDialogComponent, selector: "pptx-broadcast-dialog", inputs: ["open", "defaults", "active", "connected", "viewerCount", "viewerUrl", "p2p"], outputs: ["start", "stop", "close"] }, { kind: "component", type: MobileBottomBarComponent, selector: "pptx-mobile-bottom-bar", inputs: ["slideCount", "commentCount", "activeSheet"], outputs: ["openSlides", "insert", "openFormat", "openComments", "notes"] }, { kind: "component", type: MobileMenuSheetComponent, selector: "pptx-mobile-menu-sheet", inputs: ["open", "slideCount", "exporting", "showNotes", "canEdit"], outputs: ["closed", "openFind", "openSorter", "toggleNotes", "insertText", "present", "openFile", "savePptx", "exportPng", "exportPdf", "exportGif", "exportVideo", "print"] }, { kind: "component", type: MobileSlidesSheetComponent, selector: "pptx-mobile-slides-sheet", inputs: ["open", "slides", "canvasSize", "mediaDataUrls", "activeIndex"], outputs: ["closed", "jumpToSlide"] }, { kind: "component", type: MobileToolbarComponent, selector: "pptx-mobile-toolbar", inputs: ["canUndo", "canRedo", "canPresent", "canEdit", "menuOpen"], outputs: ["toggleMenu", "undo", "redo", "save", "present"] }, { kind: "component", type: NotesPanelComponent, selector: "pptx-notes-panel", inputs: ["slide"], outputs: ["update"] }, { kind: "component", type: RibbonComponent, selector: "pptx-ribbon", inputs: ["slideIndex", "slideCount", "canEdit", "selectedElement", "zoomPercent", "formatPainterActive", "canActivateFormatPainter", "exporting", "showGrid", "showRulers", "showGuides", "snapToGrid", "eyedropperActive", "themeGalleryOpen", "sidebarCollapsed", "inspectorOpen", "commentsOpen", "commentCount", "findOpen", "collabConnected", "connectedCount"], outputs: ["prev", "next", "zoomIn", "zoomOut", "zoomReset", "find", "present", "presenter", "share", "broadcast", "openFile", "save", "toggleSidebar", "signatures", "info", "print", "comments", "a11y", "link", "openSorter", "toggleNotes", "toggleFormatPainter", "exportPng", "exportPdf", "exportGif", "exportVideo", "replace", "toggleInspector", "drawToolChange", "toggleThemeGallery", "toggleGrid", "toggleRulers", "toggleGuides", "toggleSelectionPane", "openCustomShows", "toggleSnapToGrid", "toggleEyedropper", "openSmartArtDialog", "openEquationDialog", "openSetUpSlideShow", "openCompare", "openPassword", "openFontEmbedding", "openVersionHistory", "openShortcuts"] }, { kind: "component", type: ThemeGalleryComponent, selector: "pptx-theme-gallery", inputs: ["open", "activeName"], outputs: ["applyTheme", "close"] }, { kind: "component", type: SelectionPaneComponent, selector: "pptx-selection-pane", inputs: ["elements", "selectedIds"], outputs: ["selectElement", "bringForward", "sendBackward", "toggleHidden"] }, { kind: "component", type: CustomShowsComponent, selector: "pptx-custom-shows", inputs: ["open", "slides", "customShows", "activeCustomShowId"], outputs: ["create", "remove", "update", "setActive", "close"] }, { kind: "component", type: InsertSmartArtDialogComponent, selector: "pptx-insert-smart-art-dialog", inputs: ["open"], outputs: ["close", "insert"] }, { kind: "component", type: ViewerExtraDialogsComponent, selector: "pptx-viewer-extra-dialogs", inputs: ["activeSlideIndex", "selectedElementId", "filePath", "customShows"], outputs: ["restoreContent"] }, { kind: "pipe", type: TranslatePipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
79992
+ `, isInline: true, dependencies: [{ kind: "directive", type: NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }, { kind: "component", type: SlideCanvasComponent, selector: "pptx-slide-canvas", inputs: ["slide", "canvasSize", "mediaDataUrls", "zoom", "editable", "showGrid", "showRulers", "showGuides", "snapToGrid", "snapToGuides", "autoFit", "interactive", "selectedIds", "editingId", "editTemplateMode", "templateElements", "drawTool", "drawColor", "drawWidth"], outputs: ["elementSelect", "backgroundClick", "transformStart", "transformUpdate", "contextMenu", "textEditStart", "textCommit", "textCancel", "textFormat", "rotateUpdate", "marqueeSelect", "inkStrokeComplete", "eraserHit", "cellCommit", "tableChange"] }, { kind: "component", type: PresentationOverlayComponent, selector: "pptx-presentation-overlay", inputs: ["slides", "canvasSize", "mediaDataUrls", "startIndex"], outputs: ["indexChange", "closed", "annotationsExit"] }, { kind: "component", type: PresenterViewComponent, selector: "pptx-presenter-view", inputs: ["slides", "currentSlideIndex", "canvasSize", "templateElements", "mediaDataUrls", "presentationStartTime", "isAudienceWindowOpen"], outputs: ["movePresentationSlide", "exit", "openAudienceWindow", "closeAudienceWindow"] }, { kind: "component", type: MobilePresenterViewComponent, selector: "pptx-mobile-presenter-view", inputs: ["slides", "currentSlideIndex", "canvasSize", "templateElements", "mediaDataUrls", "presentationStartTime"], outputs: ["movePresentationSlide", "exit"] }, { kind: "component", type: SlideSorterOverlayComponent, selector: "pptx-slide-sorter-overlay", inputs: ["slides", "canvasSize", "mediaDataUrls", "activeIndex"], outputs: ["select", "closed"] }, { kind: "component", type: FindBarComponent, selector: "pptx-find-bar", inputs: ["slides"], outputs: ["navigate", "closed"] }, { kind: "component", type: FindReplaceBarComponent, selector: "pptx-find-replace-bar", inputs: ["matchCount", "matchIndex"], outputs: ["find", "navigate", "replaceOne", "replaceAll", "close"] }, { kind: "component", type: InspectorPanelComponent, selector: "pptx-inspector-panel", inputs: ["element", "slideIndex"] }, { kind: "component", type: SlidesPanelComponent, selector: "pptx-slides-panel", inputs: ["canvasSize", "mediaDataUrls", "activeIndex"], outputs: ["select"] }, { kind: "component", type: StatusBarComponent, selector: "pptx-status-bar", inputs: ["slideIndex", "slideCount", "canEdit", "dirty", "autosaveStatus", "notesOpen", "zoomPercent", "sorterActive", "presenting"], outputs: ["toggleNotes", "normalView", "openSorter", "slideShow", "zoomIn", "zoomOut", "zoomReset"] }, { kind: "component", type: EditorContextMenuComponent, selector: "pptx-editor-context-menu", inputs: ["x", "y", "slideIndex"], outputs: ["closed"] }, { kind: "component", type: ExportProgressModalComponent, selector: "pptx-export-progress-modal", inputs: ["open", "title", "progress", "statusMessage"], outputs: ["cancel"] }, { kind: "component", type: CommentsPanelComponent, selector: "pptx-comments-panel", inputs: ["comments", "authorName"], outputs: ["add", "remove", "resolve"] }, { kind: "component", type: SignaturesPanelComponent, selector: "pptx-signatures-panel", inputs: ["signatures"] }, { kind: "component", type: AccessibilityPanelComponent, selector: "pptx-accessibility-panel", inputs: ["issues"], outputs: ["selectSlide"] }, { kind: "component", type: CollaborationCursorsComponent, selector: "pptx-collaboration-cursors", inputs: ["cursors", "zoom"] }, { kind: "component", type: RemoteSelectionOverlayComponent, selector: "pptx-remote-selection-overlay", inputs: ["presences", "elements", "activeSlideIndex", "zoom"] }, { kind: "component", type: FollowModeBarComponent, selector: "pptx-follow-mode-bar", inputs: ["presences", "followedClientId"], outputs: ["follow"] }, { kind: "component", type: PropertiesDialogComponent, selector: "pptx-properties-dialog", inputs: ["open", "properties"], outputs: ["save", "close"] }, { kind: "component", type: HyperlinkDialogComponent, selector: "pptx-hyperlink-dialog", inputs: ["open", "element"], outputs: ["save", "close"] }, { kind: "component", type: PrintDialogComponent, selector: "pptx-print-dialog", inputs: ["slides", "activeSlideIndex", "defaultSlidesPerPage", "defaultFrameSlides"], outputs: ["print", "cancel"] }, { kind: "component", type: ShareDialogComponent, selector: "pptx-share-dialog", inputs: ["open", "defaults", "active", "connected", "userCount", "shareUrl", "p2p"], outputs: ["start", "stop", "close"] }, { kind: "component", type: BroadcastDialogComponent, selector: "pptx-broadcast-dialog", inputs: ["open", "defaults", "active", "connected", "viewerCount", "viewerUrl", "p2p"], outputs: ["start", "stop", "close"] }, { kind: "component", type: MobileBottomBarComponent, selector: "pptx-mobile-bottom-bar", inputs: ["slideCount", "commentCount", "activeSheet"], outputs: ["openSlides", "insert", "openFormat", "openComments", "notes"] }, { kind: "component", type: MobileMenuSheetComponent, selector: "pptx-mobile-menu-sheet", inputs: ["open", "slideCount", "exporting", "showNotes", "canEdit"], outputs: ["closed", "openFind", "openSorter", "toggleNotes", "insertText", "present", "openFile", "savePptx", "exportPng", "exportPdf", "exportGif", "exportVideo", "print"] }, { kind: "component", type: MobileSlidesSheetComponent, selector: "pptx-mobile-slides-sheet", inputs: ["open", "slides", "canvasSize", "mediaDataUrls", "activeIndex"], outputs: ["closed", "jumpToSlide"] }, { kind: "component", type: MobileToolbarComponent, selector: "pptx-mobile-toolbar", inputs: ["canUndo", "canRedo", "canPresent", "canEdit", "menuOpen"], outputs: ["toggleMenu", "undo", "redo", "save", "present"] }, { kind: "component", type: NotesPanelComponent, selector: "pptx-notes-panel", inputs: ["slide"], outputs: ["update"] }, { kind: "component", type: RibbonComponent, selector: "pptx-ribbon", inputs: ["slideIndex", "slideCount", "canEdit", "selectedElement", "zoomPercent", "formatPainterActive", "canActivateFormatPainter", "exporting", "showGrid", "showRulers", "showGuides", "snapToGrid", "eyedropperActive", "themeGalleryOpen", "sidebarCollapsed", "inspectorOpen", "commentsOpen", "commentCount", "findOpen", "collabConnected", "connectedCount"], outputs: ["prev", "next", "zoomIn", "zoomOut", "zoomReset", "find", "present", "presenter", "record", "share", "broadcast", "openFile", "save", "toggleSidebar", "signatures", "info", "print", "comments", "a11y", "link", "openSorter", "toggleNotes", "toggleFormatPainter", "exportPng", "exportPdf", "exportGif", "exportVideo", "replace", "toggleInspector", "drawToolChange", "toggleThemeGallery", "toggleGrid", "toggleRulers", "toggleGuides", "toggleSelectionPane", "openCustomShows", "toggleSnapToGrid", "toggleEyedropper", "openSmartArtDialog", "openEquationDialog", "openSetUpSlideShow", "openCompare", "openPassword", "openFontEmbedding", "openVersionHistory", "openShortcuts"] }, { kind: "component", type: TitleBarComponent, selector: "pptx-title-bar", inputs: ["canEdit", "fileName", "isDirty", "autosaveStatus", "autosaveEnabled", "canUndo", "canRedo", "undoLabel", "redoLabel", "findReplaceOpen"], outputs: ["toggleAutosave", "save", "undo", "redo", "toggleFindReplace"] }, { kind: "component", type: ThemeGalleryComponent, selector: "pptx-theme-gallery", inputs: ["open", "activeName"], outputs: ["applyTheme", "close"] }, { kind: "component", type: SelectionPaneComponent, selector: "pptx-selection-pane", inputs: ["elements", "selectedIds"], outputs: ["selectElement", "bringForward", "sendBackward", "toggleHidden"] }, { kind: "component", type: CustomShowsComponent, selector: "pptx-custom-shows", inputs: ["open", "slides", "customShows", "activeCustomShowId"], outputs: ["create", "remove", "update", "setActive", "close"] }, { kind: "component", type: InsertSmartArtDialogComponent, selector: "pptx-insert-smart-art-dialog", inputs: ["open"], outputs: ["close", "insert"] }, { kind: "component", type: ViewerExtraDialogsComponent, selector: "pptx-viewer-extra-dialogs", inputs: ["activeSlideIndex", "selectedElementId", "filePath", "customShows"], outputs: ["restoreContent"] }, { kind: "pipe", type: TranslatePipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
79357
79993
  }
79358
79994
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.5", ngImport: i0, type: PowerPointViewerComponent, decorators: [{
79359
79995
  type: Component,
@@ -79369,6 +80005,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.5", ngImpor
79369
80005
  EmbeddedFontsService,
79370
80006
  CollaborationService,
79371
80007
  AccessibilityService,
80008
+ AutosaveService,
79372
80009
  PrintService,
79373
80010
  IsMobileService,
79374
80011
  SmartArt3DService,
@@ -79426,6 +80063,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.5", ngImpor
79426
80063
  MobileToolbarComponent,
79427
80064
  NotesPanelComponent,
79428
80065
  RibbonComponent,
80066
+ TitleBarComponent,
79429
80067
  ThemeGalleryComponent,
79430
80068
  SelectionPaneComponent,
79431
80069
  CustomShowsComponent,
@@ -79451,6 +80089,23 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.5", ngImpor
79451
80089
  </div>
79452
80090
  } @else {
79453
80091
  @if (!mobile.isMobile()) {
80092
+ <pptx-title-bar
80093
+ [canEdit]="canEdit()"
80094
+ [fileName]="fileName()"
80095
+ [isDirty]="editor.dirty()"
80096
+ [autosaveStatus]="autosave.status()"
80097
+ [autosaveEnabled]="autosaveEnabled()"
80098
+ [canUndo]="editor.canUndo()"
80099
+ [canRedo]="editor.canRedo()"
80100
+ [undoLabel]="editor.undoLabel()"
80101
+ [redoLabel]="editor.redoLabel()"
80102
+ [findReplaceOpen]="findReplace.showFind() || findReplace.showFindReplace()"
80103
+ (toggleAutosave)="autosaveEnabled.update(v => !v)"
80104
+ (save)="fileIO.saveAsPptx()"
80105
+ (undo)="editor.undo()"
80106
+ (redo)="editor.redo()"
80107
+ (toggleFindReplace)="toggleFindReplace()"
80108
+ />
79454
80109
  <pptx-ribbon
79455
80110
  [slideIndex]="activeSlideIndex()"
79456
80111
  [slideCount]="slideCount()"
@@ -79476,6 +80131,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.5", ngImpor
79476
80131
  (find)="findReplace.showFind.set(true)"
79477
80132
  (present)="presentationMode.present()"
79478
80133
  (presenter)="presentationMode.presentPresenter()"
80134
+ (record)="presentationMode.present()"
79479
80135
  (share)="session.showShare.set(true)"
79480
80136
  (broadcast)="session.showBroadcast.set(true)"
79481
80137
  (openFile)="fileIO.openFile()"
@@ -79727,6 +80383,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.5", ngImpor
79727
80383
  [slideCount]="slideCount()"
79728
80384
  [canEdit]="canEdit()"
79729
80385
  [dirty]="editor.dirty()"
80386
+ [autosaveStatus]="autosave.status()"
79730
80387
  [notesOpen]="mobileSheetSvc.showNotes()"
79731
80388
  [zoomPercent]="zoomSvc.zoomPercent()"
79732
80389
  [sorterActive]="showSorter()"
@@ -80002,7 +80659,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.5", ngImpor
80002
80659
  </div>
80003
80660
  `,
80004
80661
  }]
80005
- }], 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 }] }], 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: [{
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: [{
80006
80663
  type: HostListener,
80007
80664
  args: ['document:keydown', ['$event']]
80008
80665
  }] } });
@@ -80432,6 +81089,16 @@ const translationsEn = {
80432
81089
  'pptx.autosave.saveFailed': 'Save failed',
80433
81090
  'pptx.autosave.savedShort': 'Saved',
80434
81091
  'pptx.autosave.allChangesSaved': 'All changes saved',
81092
+ // Title bar (PowerPoint-style top chrome row)
81093
+ 'pptx.titleBar.autoSave': 'AutoSave',
81094
+ 'pptx.titleBar.autoSaveOn': 'On',
81095
+ 'pptx.titleBar.autoSaveOff': 'Off',
81096
+ 'pptx.titleBar.toggleAutoSave': 'Toggle AutoSave',
81097
+ 'pptx.titleBar.save': 'Save',
81098
+ 'pptx.titleBar.savedToThisPc': 'Saved to this PC',
81099
+ 'pptx.titleBar.defaultFileName': 'Presentation',
81100
+ 'pptx.titleBar.search': 'Search',
81101
+ 'pptx.titleBar.record': 'Record',
80435
81102
  // Toolbar
80436
81103
  'pptx.toolbar.toggleSlidesPanel': 'Toggle slides panel',
80437
81104
  'pptx.toolbar.undo': 'Undo',