pptx-angular-viewer 1.3.0 → 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';
@@ -22029,6 +22029,35 @@ function hasCopyableFormat(element) {
22029
22029
  return hasShapeProperties(element) || hasTextProperties(element);
22030
22030
  }
22031
22031
 
22032
+ /**
22033
+ * Copy segment-level metadata (equation, field) from an original segment onto
22034
+ * its remapped counterpart. Without this, entering and leaving inline text
22035
+ * editing destroys the data these fields carry even when nothing was typed:
22036
+ * an equation collapses to its literal "[Equation]" placeholder text and a
22037
+ * slide-number/date field degrades to frozen plain text. Hyperlink and other
22038
+ * style-level properties already survive via the copied `style` object.
22039
+ */
22040
+ function copySegmentMetadata(from, to) {
22041
+ if (from.equationXml !== undefined) {
22042
+ to.equationXml = from.equationXml;
22043
+ }
22044
+ if (from.equationNumber !== undefined) {
22045
+ to.equationNumber = from.equationNumber;
22046
+ }
22047
+ if (from.fieldType !== undefined) {
22048
+ to.fieldType = from.fieldType;
22049
+ }
22050
+ if (from.fieldGuid !== undefined) {
22051
+ to.fieldGuid = from.fieldGuid;
22052
+ }
22053
+ if (from.fieldGuidAttr !== undefined) {
22054
+ to.fieldGuidAttr = from.fieldGuidAttr;
22055
+ }
22056
+ if (from.fieldParagraphPropertiesXml !== undefined) {
22057
+ to.fieldParagraphPropertiesXml = from.fieldParagraphPropertiesXml;
22058
+ }
22059
+ return to;
22060
+ }
22032
22061
  /**
22033
22062
  * Strategy:
22034
22063
  * 1. Split both original segments and new text into paragraphs by "\n".
@@ -22074,7 +22103,10 @@ function remapTextToSegments(newText, originalSegments, elementTextStyle) {
22074
22103
  const totalOrigLen = paraOrigSegments.reduce((sum, s) => sum + s.text.length, 0);
22075
22104
  if (totalOrigLen === 0) {
22076
22105
  const result = [
22077
- { text: paraNewText, style: { ...paraOrigSegments[0].style } },
22106
+ copySegmentMetadata(paraOrigSegments[0], {
22107
+ text: paraNewText,
22108
+ style: { ...paraOrigSegments[0].style },
22109
+ }),
22078
22110
  ];
22079
22111
  if (paragraphBulletInfo) {
22080
22112
  result[0].bulletInfo = paragraphBulletInfo;
@@ -22098,10 +22130,10 @@ function remapTextToSegments(newText, originalSegments, elementTextStyle) {
22098
22130
  segText = paraNewText.slice(newPos, newPos + origLen);
22099
22131
  }
22100
22132
  if (segText.length > 0) {
22101
- const outSeg = {
22133
+ const outSeg = copySegmentMetadata(origSeg, {
22102
22134
  text: segText,
22103
22135
  style: { ...origSeg.style },
22104
- };
22136
+ });
22105
22137
  if (remapped.length === 0 && paragraphBulletInfo) {
22106
22138
  outSeg.bulletInfo = paragraphBulletInfo;
22107
22139
  }
@@ -22110,10 +22142,10 @@ function remapTextToSegments(newText, originalSegments, elementTextStyle) {
22110
22142
  newPos += isLastSeg ? segText.length : origLen;
22111
22143
  }
22112
22144
  if (remapped.length === 0) {
22113
- const fallback = {
22145
+ const fallback = copySegmentMetadata(paraOrigSegments[0], {
22114
22146
  text: paraNewText,
22115
22147
  style: { ...paraOrigSegments[0].style },
22116
- };
22148
+ });
22117
22149
  if (paragraphBulletInfo) {
22118
22150
  fallback.bulletInfo = paragraphBulletInfo;
22119
22151
  }
@@ -32105,6 +32137,194 @@ const MATERIAL_PRESETS = [
32105
32137
  { value: 'translucentPowder', label: 'Translucent Powder' },
32106
32138
  ];
32107
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
+
32108
32328
  /**
32109
32329
  * Framework-agnostic rendering & editing helpers shared by the React, Vue, and
32110
32330
  * Angular `pptx-viewer` bindings. Pure TypeScript (no framework imports) — each
@@ -34870,6 +35090,98 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.5", ngImpor
34870
35090
  type: Injectable
34871
35091
  }] });
34872
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
+
34873
35185
  /**
34874
35186
  * broadcast-helpers.ts: thin re-export of the shared Broadcast-dialog helpers.
34875
35187
  *
@@ -68984,23 +69296,20 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.5", ngImpor
68984
69296
  * chrome, at parity with React's `toolbar/ToolbarPrimaryRow.tsx`.
68985
69297
  *
68986
69298
  * Layout (mirrors React):
68987
- * LEFT : slides-pane toggle, Undo, Redo, Find
69299
+ * LEFT : slides-pane toggle
68988
69300
  * RIGHT : Comments (with count), Present split-button + dropdown
68989
69301
  * (From Beginning / Presenter View / Broadcast), +Show (custom
68990
- * shows), Share, Inspector toggle, overflow "..." menu (exports /
68991
- * print / properties / accessibility / save).
69302
+ * shows), Inspector toggle, overflow "..." menu (exports / print /
69303
+ * properties / accessibility / save).
68992
69304
  *
68993
- * Slide navigation and zoom intentionally live in the bottom status bar (see
68994
- * {@link StatusBarComponent}), matching React. Undo/redo bind straight to the
68995
- * shared {@link EditorStateService}; everything else is an `output()` the
68996
- * {@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.
68997
69309
  */
68998
69310
  class RibbonPrimaryRowComponent {
68999
- editor = inject(EditorStateService);
69000
69311
  slideCount = input(0, /* @ts-ignore */
69001
69312
  ...(ngDevMode ? [{ debugName: "slideCount" }] : /* istanbul ignore next */ []));
69002
- canEdit = input(false, /* @ts-ignore */
69003
- ...(ngDevMode ? [{ debugName: "canEdit" }] : /* istanbul ignore next */ []));
69004
69313
  sidebarCollapsed = input(false, /* @ts-ignore */
69005
69314
  ...(ngDevMode ? [{ debugName: "sidebarCollapsed" }] : /* istanbul ignore next */ []));
69006
69315
  inspectorOpen = input(false, /* @ts-ignore */
@@ -69009,20 +69318,12 @@ class RibbonPrimaryRowComponent {
69009
69318
  ...(ngDevMode ? [{ debugName: "commentsOpen" }] : /* istanbul ignore next */ []));
69010
69319
  commentCount = input(0, /* @ts-ignore */
69011
69320
  ...(ngDevMode ? [{ debugName: "commentCount" }] : /* istanbul ignore next */ []));
69012
- findOpen = input(false, /* @ts-ignore */
69013
- ...(ngDevMode ? [{ debugName: "findOpen" }] : /* istanbul ignore next */ []));
69014
- collabConnected = input(false, /* @ts-ignore */
69015
- ...(ngDevMode ? [{ debugName: "collabConnected" }] : /* istanbul ignore next */ []));
69016
- connectedCount = input(0, /* @ts-ignore */
69017
- ...(ngDevMode ? [{ debugName: "connectedCount" }] : /* istanbul ignore next */ []));
69018
69321
  toggleSidebar = output();
69019
- toggleFind = output();
69020
69322
  toggleComments = output();
69021
69323
  present = output();
69022
69324
  presenter = output();
69023
69325
  broadcast = output();
69024
69326
  openCustomShows = output();
69025
- share = output();
69026
69327
  toggleInspector = output();
69027
69328
  exportPng = output();
69028
69329
  exportPdf = output();
@@ -69080,9 +69381,9 @@ class RibbonPrimaryRowComponent {
69080
69381
  }
69081
69382
  }
69082
69383
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.5", ngImport: i0, type: RibbonPrimaryRowComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
69083
- 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: `
69084
69385
  <div class="flex items-center gap-0.5 px-1.5 py-0.5">
69085
- <!-- Left: slides pane toggle + undo/redo + find -->
69386
+ <!-- Left: slides pane toggle (undo/redo/find moved to the title bar) -->
69086
69387
  <button
69087
69388
  type="button"
69088
69389
  class="pptx-rb-icon"
@@ -69093,40 +69394,11 @@ class RibbonPrimaryRowComponent {
69093
69394
  >
69094
69395
 
69095
69396
  </button>
69096
- <span class="mx-1 h-5 w-px self-center bg-border/50"></span>
69097
- <button
69098
- type="button"
69099
- class="pptx-rb-icon"
69100
- [attr.aria-label]="'pptx.toolbar.undo' | translate"
69101
- [disabled]="!canEdit() || !editor.canUndo()"
69102
- (click)="editor.undo()"
69103
- >
69104
-
69105
- </button>
69106
- <button
69107
- type="button"
69108
- class="pptx-rb-icon"
69109
- [attr.aria-label]="'pptx.toolbar.redo' | translate"
69110
- [disabled]="!canEdit() || !editor.canRedo()"
69111
- (click)="editor.redo()"
69112
- >
69113
-
69114
- </button>
69115
- <button
69116
- type="button"
69117
- class="pptx-rb-icon"
69118
- [ngClass]="findOpen() ? 'text-foreground' : 'text-muted-foreground'"
69119
- [title]="'pptx.toolbar.findAndReplace' | translate"
69120
- [attr.aria-label]="'pptx.toolbar.findAndReplace' | translate"
69121
- (click)="toggleFind.emit()"
69122
- >
69123
-
69124
- </button>
69125
69397
 
69126
69398
  <!-- Center spacer -->
69127
69399
  <div class="min-w-2 flex-1"></div>
69128
69400
 
69129
- <!-- Right: comments + present + show + share + inspector + overflow -->
69401
+ <!-- Right: comments + present + show + inspector + overflow -->
69130
69402
  <button
69131
69403
  type="button"
69132
69404
  class="pptx-rb-icon relative"
@@ -69207,24 +69479,6 @@ class RibbonPrimaryRowComponent {
69207
69479
 
69208
69480
  <span class="mx-1 h-5 w-px self-center bg-border/50"></span>
69209
69481
 
69210
- <button
69211
- type="button"
69212
- class="inline-flex items-center gap-1 rounded-sm px-2.5 py-1 text-[11px] font-medium text-white transition-colors"
69213
- [ngClass]="
69214
- collabConnected() ? 'bg-green-600 hover:bg-green-500' : 'bg-primary hover:bg-primary/90'
69215
- "
69216
- [title]="'pptx.ribbon.shareForCollaboration' | translate"
69217
- [attr.aria-label]="'pptx.toolbar.share' | translate"
69218
- (click)="share.emit()"
69219
- >
69220
-
69221
- {{
69222
- collabConnected()
69223
- ? ('pptx.toolbar.sharingCount' | translate: { count: connectedCount() })
69224
- : ('pptx.toolbar.share' | translate)
69225
- }}
69226
- </button>
69227
-
69228
69482
  <button
69229
69483
  type="button"
69230
69484
  class="pptx-rb-icon"
@@ -69281,7 +69535,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.5", ngImpor
69281
69535
  imports: [NgClass, TranslatePipe],
69282
69536
  template: `
69283
69537
  <div class="flex items-center gap-0.5 px-1.5 py-0.5">
69284
- <!-- Left: slides pane toggle + undo/redo + find -->
69538
+ <!-- Left: slides pane toggle (undo/redo/find moved to the title bar) -->
69285
69539
  <button
69286
69540
  type="button"
69287
69541
  class="pptx-rb-icon"
@@ -69292,40 +69546,11 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.5", ngImpor
69292
69546
  >
69293
69547
 
69294
69548
  </button>
69295
- <span class="mx-1 h-5 w-px self-center bg-border/50"></span>
69296
- <button
69297
- type="button"
69298
- class="pptx-rb-icon"
69299
- [attr.aria-label]="'pptx.toolbar.undo' | translate"
69300
- [disabled]="!canEdit() || !editor.canUndo()"
69301
- (click)="editor.undo()"
69302
- >
69303
-
69304
- </button>
69305
- <button
69306
- type="button"
69307
- class="pptx-rb-icon"
69308
- [attr.aria-label]="'pptx.toolbar.redo' | translate"
69309
- [disabled]="!canEdit() || !editor.canRedo()"
69310
- (click)="editor.redo()"
69311
- >
69312
-
69313
- </button>
69314
- <button
69315
- type="button"
69316
- class="pptx-rb-icon"
69317
- [ngClass]="findOpen() ? 'text-foreground' : 'text-muted-foreground'"
69318
- [title]="'pptx.toolbar.findAndReplace' | translate"
69319
- [attr.aria-label]="'pptx.toolbar.findAndReplace' | translate"
69320
- (click)="toggleFind.emit()"
69321
- >
69322
-
69323
- </button>
69324
69549
 
69325
69550
  <!-- Center spacer -->
69326
69551
  <div class="min-w-2 flex-1"></div>
69327
69552
 
69328
- <!-- Right: comments + present + show + share + inspector + overflow -->
69553
+ <!-- Right: comments + present + show + inspector + overflow -->
69329
69554
  <button
69330
69555
  type="button"
69331
69556
  class="pptx-rb-icon relative"
@@ -69406,24 +69631,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.5", ngImpor
69406
69631
 
69407
69632
  <span class="mx-1 h-5 w-px self-center bg-border/50"></span>
69408
69633
 
69409
- <button
69410
- type="button"
69411
- class="inline-flex items-center gap-1 rounded-sm px-2.5 py-1 text-[11px] font-medium text-white transition-colors"
69412
- [ngClass]="
69413
- collabConnected() ? 'bg-green-600 hover:bg-green-500' : 'bg-primary hover:bg-primary/90'
69414
- "
69415
- [title]="'pptx.ribbon.shareForCollaboration' | translate"
69416
- [attr.aria-label]="'pptx.toolbar.share' | translate"
69417
- (click)="share.emit()"
69418
- >
69419
-
69420
- {{
69421
- collabConnected()
69422
- ? ('pptx.toolbar.sharingCount' | translate: { count: connectedCount() })
69423
- : ('pptx.toolbar.share' | translate)
69424
- }}
69425
- </button>
69426
-
69427
69634
  <button
69428
69635
  type="button"
69429
69636
  class="pptx-rb-icon"
@@ -69471,7 +69678,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.5", ngImpor
69471
69678
  </div>
69472
69679
  `,
69473
69680
  }]
69474
- }], 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"] }] } });
69475
69682
 
69476
69683
  /**
69477
69684
  * ribbon-review-section.component.ts: the Review ribbon tab (Comments,
@@ -70177,6 +70384,8 @@ class RibbonComponent {
70177
70384
  find = output();
70178
70385
  present = output();
70179
70386
  presenter = output();
70387
+ /** Emitted by the tab-row Record button (starts a slide-show run-through). */
70388
+ record = output();
70180
70389
  share = output();
70181
70390
  broadcast = output();
70182
70391
  openFile = output();
@@ -70251,6 +70460,8 @@ class RibbonComponent {
70251
70460
  /** Emitted when the user clicks "Shortcuts" in the Help tab. */
70252
70461
  openShortcuts = output();
70253
70462
  tabs = TABS;
70463
+ /** Shared class tokens for the tab-row Record button. */
70464
+ tra = TAB_ROW_ACTION_CLASSES;
70254
70465
  activeTab = signal('home', /* @ts-ignore */
70255
70466
  ...(ngDevMode ? [{ debugName: "activeTab" }] : /* istanbul ignore next */ []));
70256
70467
  /** Ribbon content expanded (true) vs collapsed to just the tab bar (false). */
@@ -70283,7 +70494,7 @@ class RibbonComponent {
70283
70494
  this.drawToolChange.emit(state);
70284
70495
  }
70285
70496
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.5", ngImport: i0, type: RibbonComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
70286
- 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: `
70287
70498
  <div
70288
70499
  role="toolbar"
70289
70500
  aria-label="Presentation toolbar"
@@ -70292,22 +70503,16 @@ class RibbonComponent {
70292
70503
  <!-- ── Primary quick-access row (ToolbarPrimaryRow parity) ──── -->
70293
70504
  <pptx-ribbon-primary-row
70294
70505
  [slideCount]="slideCount()"
70295
- [canEdit]="canEdit()"
70296
70506
  [sidebarCollapsed]="sidebarCollapsed()"
70297
70507
  [inspectorOpen]="inspectorOpen()"
70298
70508
  [commentsOpen]="commentsOpen()"
70299
70509
  [commentCount]="commentCount()"
70300
- [findOpen]="findOpen()"
70301
- [collabConnected]="collabConnected()"
70302
- [connectedCount]="connectedCount()"
70303
70510
  (toggleSidebar)="toggleSidebar.emit()"
70304
- (toggleFind)="replace.emit()"
70305
70511
  (toggleComments)="comments.emit()"
70306
70512
  (present)="present.emit()"
70307
70513
  (presenter)="presenter.emit()"
70308
70514
  (broadcast)="broadcast.emit()"
70309
70515
  (openCustomShows)="openCustomShows.emit()"
70310
- (share)="share.emit()"
70311
70516
  (toggleInspector)="toggleInspector.emit()"
70312
70517
  (exportPng)="exportPng.emit()"
70313
70518
  (exportPdf)="exportPdf.emit()"
@@ -70336,6 +70541,46 @@ class RibbonComponent {
70336
70541
  </button>
70337
70542
  }
70338
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
+
70339
70584
  <button
70340
70585
  type="button"
70341
70586
  class="mr-1 rounded px-2 py-1 text-[11px] text-muted-foreground transition-colors hover:text-foreground"
@@ -70493,7 +70738,7 @@ class RibbonComponent {
70493
70738
  }
70494
70739
  </div>
70495
70740
  </div>
70496
- `, 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 });
70497
70742
  }
70498
70743
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.5", ngImport: i0, type: RibbonComponent, decorators: [{
70499
70744
  type: Component,
@@ -70528,22 +70773,16 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.5", ngImpor
70528
70773
  <!-- ── Primary quick-access row (ToolbarPrimaryRow parity) ──── -->
70529
70774
  <pptx-ribbon-primary-row
70530
70775
  [slideCount]="slideCount()"
70531
- [canEdit]="canEdit()"
70532
70776
  [sidebarCollapsed]="sidebarCollapsed()"
70533
70777
  [inspectorOpen]="inspectorOpen()"
70534
70778
  [commentsOpen]="commentsOpen()"
70535
70779
  [commentCount]="commentCount()"
70536
- [findOpen]="findOpen()"
70537
- [collabConnected]="collabConnected()"
70538
- [connectedCount]="connectedCount()"
70539
70780
  (toggleSidebar)="toggleSidebar.emit()"
70540
- (toggleFind)="replace.emit()"
70541
70781
  (toggleComments)="comments.emit()"
70542
70782
  (present)="present.emit()"
70543
70783
  (presenter)="presenter.emit()"
70544
70784
  (broadcast)="broadcast.emit()"
70545
70785
  (openCustomShows)="openCustomShows.emit()"
70546
- (share)="share.emit()"
70547
70786
  (toggleInspector)="toggleInspector.emit()"
70548
70787
  (exportPng)="exportPng.emit()"
70549
70788
  (exportPdf)="exportPdf.emit()"
@@ -70572,6 +70811,46 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.5", ngImpor
70572
70811
  </button>
70573
70812
  }
70574
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
+
70575
70854
  <button
70576
70855
  type="button"
70577
70856
  class="mr-1 rounded px-2 py-1 text-[11px] text-muted-foreground transition-colors hover:text-foreground"
@@ -70731,7 +71010,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.5", ngImpor
70731
71010
  </div>
70732
71011
  `,
70733
71012
  }]
70734
- }], 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"] }] } });
70735
71014
 
70736
71015
  /**
70737
71016
  * selection-pane.component.ts: Side panel listing all elements on the active slide.
@@ -72191,6 +72470,9 @@ class StatusBarComponent {
72191
72470
  ...(ngDevMode ? [{ debugName: "canEdit" }] : /* istanbul ignore next */ []));
72192
72471
  dirty = input(false, /* @ts-ignore */
72193
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 */ []));
72194
72476
  notesOpen = input(false, /* @ts-ignore */
72195
72477
  ...(ngDevMode ? [{ debugName: "notesOpen" }] : /* istanbul ignore next */ []));
72196
72478
  zoomPercent = input(100, /* @ts-ignore */
@@ -72208,6 +72490,7 @@ class StatusBarComponent {
72208
72490
  zoomIn = output();
72209
72491
  zoomOut = output();
72210
72492
  zoomReset = output();
72493
+ translate = inject(TranslateService);
72211
72494
  /** "Normal" is active when neither the sorter nor the slideshow is showing. */
72212
72495
  isNormal() {
72213
72496
  return !this.sorterActive() && !this.presenting();
@@ -72215,8 +72498,50 @@ class StatusBarComponent {
72215
72498
  min(a, b) {
72216
72499
  return Math.min(a, b);
72217
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
+ }
72218
72543
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.5", ngImport: i0, type: StatusBarComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
72219
- 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: `
72220
72545
  <div
72221
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"
72222
72547
  >
@@ -72235,9 +72560,7 @@ class StatusBarComponent {
72235
72560
 
72236
72561
  @if (canEdit()) {
72237
72562
  <div class="mx-1 h-3 w-px bg-border/60"></div>
72238
- <span class="shrink-0">{{
72239
- (dirty() ? 'pptx.statusBar.unsavedChanges' : 'pptx.statusBar.allSaved') | translate
72240
- }}</span>
72563
+ <span class="shrink-0" [ngClass]="saveStateClass()">{{ saveStatusText() }}</span>
72241
72564
  }
72242
72565
 
72243
72566
  <!-- Center spacer -->
@@ -72352,9 +72675,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.5", ngImpor
72352
72675
 
72353
72676
  @if (canEdit()) {
72354
72677
  <div class="mx-1 h-3 w-px bg-border/60"></div>
72355
- <span class="shrink-0">{{
72356
- (dirty() ? 'pptx.statusBar.unsavedChanges' : 'pptx.statusBar.allSaved') | translate
72357
- }}</span>
72678
+ <span class="shrink-0" [ngClass]="saveStateClass()">{{ saveStatusText() }}</span>
72358
72679
  }
72359
72680
 
72360
72681
  <!-- Center spacer -->
@@ -72443,7 +72764,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.5", ngImpor
72443
72764
  </div>
72444
72765
  `,
72445
72766
  }]
72446
- }], 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"] }] } });
72447
72768
 
72448
72769
  /**
72449
72770
  * theme-gallery-presets.ts: the exact theme set shown in the Design tab's
@@ -72839,6 +73160,292 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.5", ngImpor
72839
73160
  }]
72840
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"] }] } });
72841
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
+
72842
73449
  /**
72843
73450
  * viewer-dialogs.service.ts: Viewer-scoped open-state + light state for the
72844
73451
  * secondary dialogs and side panels (equation editor, set-up-slide-show,
@@ -78205,6 +78812,13 @@ class PowerPointViewerComponent {
78205
78812
  */
78206
78813
  filePath = input(undefined, /* @ts-ignore */
78207
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 */ []));
78208
78822
  /** Optional real-time collaboration config; when set, connects and shows remote cursors. */
78209
78823
  collaboration = input(undefined, /* @ts-ignore */
78210
78824
  ...(ngDevMode ? [{ debugName: "collaboration" }] : /* istanbul ignore next */ []));
@@ -78260,6 +78874,7 @@ class PowerPointViewerComponent {
78260
78874
  fonts = inject(EmbeddedFontsService);
78261
78875
  collab = inject(CollaborationService);
78262
78876
  accessibility = inject(AccessibilityService);
78877
+ autosave = inject(AutosaveService);
78263
78878
  print = inject(PrintService);
78264
78879
  mobile = inject(IsMobileService);
78265
78880
  smartArt3DSvc = inject(SmartArt3DService);
@@ -78335,6 +78950,9 @@ class PowerPointViewerComponent {
78335
78950
  /** Whether the left slides panel is collapsed (top-bar sidebar toggle). */
78336
78951
  slidesPanelCollapsed = signal(false, /* @ts-ignore */
78337
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 */ []));
78338
78956
  // ── Draw tool state (forwarded to slide-canvas) ───────────────────────────
78339
78957
  /** Active drawing tool (from the ribbon Draw tab). */
78340
78958
  activeDrawTool = signal('select', /* @ts-ignore */
@@ -78631,6 +79249,15 @@ class PowerPointViewerComponent {
78631
79249
  activeSlideIndex: () => this.activeSlideIndex(),
78632
79250
  emitPropertiesChange: (patch) => this.propertiesChange.emit(patch),
78633
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
+ });
78634
79261
  }
78635
79262
  /**
78636
79263
  * Serialise the current presentation to `.pptx` bytes (imperative handle).
@@ -78651,6 +79278,27 @@ class PowerPointViewerComponent {
78651
79278
  goNext() {
78652
79279
  this.goTo(this.activeSlideIndex() + 1);
78653
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
+ }
78654
79302
  /** Review ▸ Compare: pick a `.pptx` and diff it against the current deck. */
78655
79303
  onOpenCompare() {
78656
79304
  this.compareSvc.startCompare();
@@ -78723,7 +79371,7 @@ class PowerPointViewerComponent {
78723
79371
  return (this.mainEl()?.nativeElement.querySelector('.pptx-ng-canvas-stage') ?? undefined);
78724
79372
  }
78725
79373
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.5", ngImport: i0, type: PowerPointViewerComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
78726
- 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: [
78727
79375
  LoadContentService,
78728
79376
  ExportService,
78729
79377
  EditorStateService,
@@ -78731,6 +79379,7 @@ class PowerPointViewerComponent {
78731
79379
  EmbeddedFontsService,
78732
79380
  CollaborationService,
78733
79381
  AccessibilityService,
79382
+ AutosaveService,
78734
79383
  PrintService,
78735
79384
  IsMobileService,
78736
79385
  SmartArt3DService,
@@ -78772,6 +79421,23 @@ class PowerPointViewerComponent {
78772
79421
  </div>
78773
79422
  } @else {
78774
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
+ />
78775
79441
  <pptx-ribbon
78776
79442
  [slideIndex]="activeSlideIndex()"
78777
79443
  [slideCount]="slideCount()"
@@ -78797,6 +79463,7 @@ class PowerPointViewerComponent {
78797
79463
  (find)="findReplace.showFind.set(true)"
78798
79464
  (present)="presentationMode.present()"
78799
79465
  (presenter)="presentationMode.presentPresenter()"
79466
+ (record)="presentationMode.present()"
78800
79467
  (share)="session.showShare.set(true)"
78801
79468
  (broadcast)="session.showBroadcast.set(true)"
78802
79469
  (openFile)="fileIO.openFile()"
@@ -79048,6 +79715,7 @@ class PowerPointViewerComponent {
79048
79715
  [slideCount]="slideCount()"
79049
79716
  [canEdit]="canEdit()"
79050
79717
  [dirty]="editor.dirty()"
79718
+ [autosaveStatus]="autosave.status()"
79051
79719
  [notesOpen]="mobileSheetSvc.showNotes()"
79052
79720
  [zoomPercent]="zoomSvc.zoomPercent()"
79053
79721
  [sorterActive]="showSorter()"
@@ -79321,7 +79989,7 @@ class PowerPointViewerComponent {
79321
79989
  />
79322
79990
  }
79323
79991
  </div>
79324
- `, 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 });
79325
79993
  }
79326
79994
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.5", ngImport: i0, type: PowerPointViewerComponent, decorators: [{
79327
79995
  type: Component,
@@ -79337,6 +80005,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.5", ngImpor
79337
80005
  EmbeddedFontsService,
79338
80006
  CollaborationService,
79339
80007
  AccessibilityService,
80008
+ AutosaveService,
79340
80009
  PrintService,
79341
80010
  IsMobileService,
79342
80011
  SmartArt3DService,
@@ -79394,6 +80063,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.5", ngImpor
79394
80063
  MobileToolbarComponent,
79395
80064
  NotesPanelComponent,
79396
80065
  RibbonComponent,
80066
+ TitleBarComponent,
79397
80067
  ThemeGalleryComponent,
79398
80068
  SelectionPaneComponent,
79399
80069
  CustomShowsComponent,
@@ -79419,6 +80089,23 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.5", ngImpor
79419
80089
  </div>
79420
80090
  } @else {
79421
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
+ />
79422
80109
  <pptx-ribbon
79423
80110
  [slideIndex]="activeSlideIndex()"
79424
80111
  [slideCount]="slideCount()"
@@ -79444,6 +80131,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.5", ngImpor
79444
80131
  (find)="findReplace.showFind.set(true)"
79445
80132
  (present)="presentationMode.present()"
79446
80133
  (presenter)="presentationMode.presentPresenter()"
80134
+ (record)="presentationMode.present()"
79447
80135
  (share)="session.showShare.set(true)"
79448
80136
  (broadcast)="session.showBroadcast.set(true)"
79449
80137
  (openFile)="fileIO.openFile()"
@@ -79695,6 +80383,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.5", ngImpor
79695
80383
  [slideCount]="slideCount()"
79696
80384
  [canEdit]="canEdit()"
79697
80385
  [dirty]="editor.dirty()"
80386
+ [autosaveStatus]="autosave.status()"
79698
80387
  [notesOpen]="mobileSheetSvc.showNotes()"
79699
80388
  [zoomPercent]="zoomSvc.zoomPercent()"
79700
80389
  [sorterActive]="showSorter()"
@@ -79970,7 +80659,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.5", ngImpor
79970
80659
  </div>
79971
80660
  `,
79972
80661
  }]
79973
- }], 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: [{
79974
80663
  type: HostListener,
79975
80664
  args: ['document:keydown', ['$event']]
79976
80665
  }] } });
@@ -80400,6 +81089,16 @@ const translationsEn = {
80400
81089
  'pptx.autosave.saveFailed': 'Save failed',
80401
81090
  'pptx.autosave.savedShort': 'Saved',
80402
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',
80403
81102
  // Toolbar
80404
81103
  'pptx.toolbar.toggleSlidesPanel': 'Toggle slides panel',
80405
81104
  'pptx.toolbar.undo': 'Undo',