pptx-angular-viewer 2.0.1 → 2.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -7,7 +7,7 @@ import DOMPurify from 'dompurify';
7
7
  import { z } from 'zod';
8
8
  import * as mcp from 'pptx-viewer-mcp';
9
9
  import * as mcpSchemas from 'pptx-viewer-mcp/schemas';
10
- import { LucideX, LucideSquare, LucideCircle, LucideSlash, LucideCopy, LucideTrash2, LucideChevronsUp, LucideChevronsDown, LucideArrowUp, LucideArrowDown, LucideGroup, LucideUngroup, LucideTextAlignStart, LucideTextAlignCenter, LucideTextAlignEnd, LucideChevronUp, LucideChevronDown, LucideAlignHorizontalSpaceAround, LucideAlignVerticalSpaceAround, LucideShare2, LucideChevronRight, LucidePenTool, LucideHighlighter, LucideEraser, LucideMousePointer2, LucideChevronLeft, LucidePlay, LucideSparkles, LucidePanelRight, LucideMoveRight, LucidePencil, LucideType, LucideMinus, LucideSpline, LucideArrowLeft, LucideDownload, LucideFilePlus2, LucideFolderOpen, LucideHome, LucideInfo, LucidePrinter, LucideSave, LucideSettings, LucideUpload, LucideUserRound, LucideAArrowUp, LucideAArrowDown, LucideRemoveFormatting, LucideList, LucideListOrdered, LucideListIndentDecrease, LucideListIndentIncrease, LucideTextAlignJustify, LucidePlus, LucideClipboardPaste, LucideFolderPlus, LucideLayoutGrid, LucidePaintbrush, LucideRotateCcw, LucideScissors, LucideImage, LucideVideo, LucideDatabase, LucideLayers, LucidePanelLeft, LucideMessageSquare, LucideEllipsis, LucideEye, LucideEyeOff, LucideSettings2, LucideStickyNote, LucideMonitor, LucideColumns2, LucidePresentation, LucideCheck, LucideUndo, LucideRedo, LucideSearch, LucideBug, LucideSend, LucideCrosshair, LucideGitMerge, LucidePin, LucidePinOff, LucideWrench, LucideLoaderCircle, LucideTriangleAlert, LucideShapes, LucidePalette, LucideTable, LucideLayoutTemplate, LucideChartColumn, LucideMove, LucideNavigation, LucideFilm, LucideBot, LucideUser } from '@lucide/angular';
10
+ import { LucideX, LucideSquare, LucideCircle, LucideSlash, LucideCopy, LucideTrash2, LucideChevronsUp, LucideChevronsDown, LucideArrowUp, LucideArrowDown, LucideGroup, LucideUngroup, LucideTextAlignStart, LucideTextAlignCenter, LucideTextAlignEnd, LucideChevronUp, LucideChevronDown, LucideAlignHorizontalSpaceAround, LucideAlignVerticalSpaceAround, LucideLayers, LucideMessageSquare, LucidePlus, LucideSettings2, LucideStickyNote, LucideDownload, LucideMenu, LucidePresentation, LucideRedo, LucideShare2, LucideSparkles, LucideUndo, LucideChevronRight, LucidePenTool, LucideHighlighter, LucideEraser, LucideMousePointer2, LucideChevronLeft, LucidePlay, LucidePanelRight, LucideMoveRight, LucidePencil, LucideType, LucideMinus, LucideSpline, LucideArrowLeft, LucideFilePlus2, LucideFolderOpen, LucideHome, LucideInfo, LucidePrinter, LucideSave, LucideSettings, LucideUpload, LucideUserRound, LucideAArrowUp, LucideAArrowDown, LucideRemoveFormatting, LucideList, LucideListOrdered, LucideListIndentDecrease, LucideListIndentIncrease, LucideTextAlignJustify, LucideClipboardPaste, LucideFolderPlus, LucideLayoutGrid, LucidePaintbrush, LucideRotateCcw, LucideScissors, LucideImage, LucideVideo, LucideDatabase, LucidePanelLeft, LucideEllipsis, LucideEye, LucideEyeOff, LucideMonitor, LucideColumns2, LucideCheck, LucideSearch, LucideBug, LucideSend, LucideCrosshair, LucideGitMerge, LucidePin, LucidePinOff, LucideWrench, LucideLoaderCircle, LucideTriangleAlert, LucideShapes, LucidePalette, LucideTable, LucideLayoutTemplate, LucideChartColumn, LucideMove, LucideNavigation, LucideFilm, LucideBot, LucideUser } from '@lucide/angular';
11
11
  import { DomSanitizer } from '@angular/platform-browser';
12
12
  import { jsPDF } from 'jspdf';
13
13
  import JSZip from 'jszip';
@@ -29174,7 +29174,16 @@ function reconcileComplexFields(ymap, rec, fields) {
29174
29174
  }
29175
29175
  }
29176
29176
  }
29177
- function reconcileTextBody(ymap, rec, factories) {
29177
+ /**
29178
+ * Bring `ymap.textBody` in line with `rec.textSegments`, preferring a
29179
+ * character-level in-place merge (so concurrent typing on one element
29180
+ * converges) and falling back to a wholesale Y.Text replacement.
29181
+ *
29182
+ * Exported for the live-patch channel (collaboration-live-patch.ts), which
29183
+ * writes interim editor text into the doc mid-edit and must use the exact same
29184
+ * merge path as this reconcile pass.
29185
+ */
29186
+ function reconcileElementTextBody(ymap, rec, factories) {
29178
29187
  const segments = rec.textSegments;
29179
29188
  const current = ymap.get('textBody');
29180
29189
  if (!Array.isArray(segments)) {
@@ -29202,7 +29211,7 @@ function reconcileElementYMap(ymap, element, factories, assets) {
29202
29211
  const rec = element;
29203
29212
  reconcileScalars(ymap, rec, SCALAR_ELEMENT_KEYS);
29204
29213
  reconcileComplexFields(ymap, rec, COMPLEX_ELEMENT_FIELDS);
29205
- reconcileTextBody(ymap, rec, factories);
29214
+ reconcileElementTextBody(ymap, rec, factories);
29206
29215
  reconcileAssetFields(rec.id, rec, ymap, assets);
29207
29216
  }
29208
29217
  function mapIdAt(arr, index) {
@@ -29320,6 +29329,244 @@ function reconcileSlidesInYDoc(slides, ydoc, factories, origin = LOCAL_SYNC_ORIG
29320
29329
  }, origin);
29321
29330
  }
29322
29331
 
29332
+ /**
29333
+ * collaboration-live-patch-target.ts: locating an element inside the shared
29334
+ * Y.Doc and writing one interim patch into it.
29335
+ *
29336
+ * Split out of `collaboration-live-patch.ts` (which owns the throttled patcher
29337
+ * and the binding-facing helpers) to keep both files inside the repo's 300 LOC
29338
+ * ceiling. This half is pure: given a doc it finds the element's Y.Map through
29339
+ * the existing schema and applies geometry / text, with no timers or state.
29340
+ */
29341
+ const GEOMETRY_KEYS = ['x', 'y', 'width', 'height', 'rotation'];
29342
+ /** Interim text longer than this is left to the commit path (safety valve). */
29343
+ const MAX_LIVE_TEXT_LENGTH = 100_000;
29344
+ const asMap = (value) => typeof value === 'object' && value !== null && typeof value.get === 'function'
29345
+ ? value
29346
+ : undefined;
29347
+ const asArray = (value) => typeof value === 'object' && value !== null && typeof value.get === 'function'
29348
+ ? value
29349
+ : undefined;
29350
+ /**
29351
+ * Locate an element's Y.Map through the existing schema
29352
+ * (pptx:slides -> slide Y.Map -> `elements` Y.Array -> element Y.Map).
29353
+ * When `slideId` is undefined every slide is searched.
29354
+ *
29355
+ * Only top-level `elements` are walked, so a group's children are not
29356
+ * reachable. No binding drags a group child directly today; if one starts to,
29357
+ * this walk needs to recurse into `groupElements`.
29358
+ */
29359
+ function findElementYMap(doc, slideId, elementId) {
29360
+ const slidesArr = doc.getArray(YDOC_SLIDES_KEY);
29361
+ for (let i = 0; i < slidesArr.length; i++) {
29362
+ const slideMap = asMap(slidesArr.get(i));
29363
+ if (!slideMap || (slideId !== undefined && slideMap.get('id') !== slideId)) {
29364
+ continue;
29365
+ }
29366
+ const elements = asArray(slideMap.get('elements'));
29367
+ if (!elements) {
29368
+ continue;
29369
+ }
29370
+ for (let j = 0; j < elements.length; j++) {
29371
+ const elementMap = asMap(elements.get(j));
29372
+ if (elementMap && elementMap.get('id') === elementId) {
29373
+ return elementMap;
29374
+ }
29375
+ }
29376
+ }
29377
+ return undefined;
29378
+ }
29379
+ /** Write one queued patch into the doc. Caller owns the transaction + origin. */
29380
+ function applyLivePatch(doc, factories, patch, textPatchLimit) {
29381
+ const ymap = findElementYMap(doc, patch.slideId, patch.elementId);
29382
+ if (!ymap) {
29383
+ return;
29384
+ }
29385
+ if (patch.geometry) {
29386
+ for (const key of GEOMETRY_KEYS) {
29387
+ const next = patch.geometry[key];
29388
+ if (typeof next === 'number' && ymap.get(key) !== next) {
29389
+ ymap.set(key, next);
29390
+ }
29391
+ }
29392
+ }
29393
+ if (patch.text) {
29394
+ const { value, source } = patch.text;
29395
+ if (value.length > textPatchLimit) {
29396
+ return;
29397
+ }
29398
+ if (ymap.get('text') !== value) {
29399
+ ymap.set('text', value);
29400
+ }
29401
+ const segments = remapTextToSegments(value, source.textSegments, source.textStyle);
29402
+ reconcileElementTextBody(ymap, { textSegments: segments }, factories);
29403
+ }
29404
+ }
29405
+
29406
+ /**
29407
+ * collaboration-live-patch.ts: interim ("live preview") writes straight into
29408
+ * the shared Y.Doc, bypassing each binding's slides state.
29409
+ *
29410
+ * Why: the editors deliberately keep gestures out of framework state. React's
29411
+ * drag/resize writes `style.left/top/width/height` on the DOM node and only
29412
+ * calls `updateElementById` on pointer-up; every binding's inline text editor
29413
+ * buffers the typed string and only commits it on blur. Because the Y.Doc sync
29414
+ * is driven off the slides state, remote peers saw nothing until the gesture
29415
+ * (or the edit) ended.
29416
+ *
29417
+ * This module patches the element's Y.Map directly, so the host keeps its
29418
+ * per-frame performance design while peers see the move/typing live:
29419
+ *
29420
+ * - geometry scalars (x / y / width / height / rotation) are set in place
29421
+ * - text goes through the SAME character-level Y.Text merge the reconcile
29422
+ * pass uses (`reconcileElementTextBody`), so concurrent typing on one
29423
+ * element still merges instead of last-write-wins
29424
+ * - writes are throttled (~1 per 50ms) with a trailing write, plus an
29425
+ * explicit `flush()` for gesture end
29426
+ * - every transaction is tagged with LOCAL_SYNC_ORIGIN, exactly like
29427
+ * `reconcileSlidesInYDoc`, so the local observer skips the echo
29428
+ *
29429
+ * It is a no-op until `configure()` is handed a live doc + factories, so
29430
+ * bindings can call it unconditionally.
29431
+ */
29432
+ /** Default gap between interim doc writes. */
29433
+ const LIVE_PATCH_THROTTLE_MS = 50;
29434
+ // ---------------------------------------------------------------------------
29435
+ // Patcher
29436
+ // ---------------------------------------------------------------------------
29437
+ function createCollaborationLivePatcher(options = {}) {
29438
+ const throttleMs = options.throttleMs ?? LIVE_PATCH_THROTTLE_MS;
29439
+ const pending = new Map();
29440
+ let doc = null;
29441
+ let factories = null;
29442
+ let timer = null;
29443
+ let lastWriteAt = Number.NEGATIVE_INFINITY;
29444
+ const cancelTimer = () => {
29445
+ if (timer !== null) {
29446
+ clearTimeout(timer);
29447
+ timer = null;
29448
+ }
29449
+ };
29450
+ const writePending = () => {
29451
+ const activeDoc = doc;
29452
+ const activeFactories = factories;
29453
+ if (!activeDoc || !activeFactories || pending.size === 0) {
29454
+ pending.clear();
29455
+ return;
29456
+ }
29457
+ const patches = [...pending.values()];
29458
+ pending.clear();
29459
+ lastWriteAt = Date.now();
29460
+ try {
29461
+ activeDoc.transact(() => {
29462
+ for (const patch of patches) {
29463
+ applyLivePatch(activeDoc, activeFactories, patch, MAX_LIVE_TEXT_LENGTH);
29464
+ }
29465
+ }, LOCAL_SYNC_ORIGIN);
29466
+ }
29467
+ catch {
29468
+ /* a live preview must never break the gesture it mirrors */
29469
+ }
29470
+ };
29471
+ const schedule = () => {
29472
+ if (timer !== null) {
29473
+ return;
29474
+ }
29475
+ const elapsed = Date.now() - lastWriteAt;
29476
+ if (elapsed >= throttleMs) {
29477
+ writePending();
29478
+ return;
29479
+ }
29480
+ timer = setTimeout(() => {
29481
+ timer = null;
29482
+ writePending();
29483
+ }, throttleMs - elapsed);
29484
+ };
29485
+ const enqueue = (slideId, elementId) => {
29486
+ if (!doc || !factories || !elementId) {
29487
+ return null;
29488
+ }
29489
+ const key = `${slideId ?? ''}\u0000${elementId}`;
29490
+ let entry = pending.get(key);
29491
+ if (!entry) {
29492
+ entry = { slideId, elementId };
29493
+ pending.set(key, entry);
29494
+ }
29495
+ return entry;
29496
+ };
29497
+ return {
29498
+ configure(nextDoc, nextFactories) {
29499
+ if (nextDoc === doc && nextFactories === factories) {
29500
+ return;
29501
+ }
29502
+ cancelTimer();
29503
+ pending.clear();
29504
+ doc = nextDoc;
29505
+ factories = nextFactories;
29506
+ lastWriteAt = Number.NEGATIVE_INFINITY;
29507
+ },
29508
+ isActive() {
29509
+ return doc !== null && factories !== null;
29510
+ },
29511
+ patchGeometry(slideId, elementId, geometry) {
29512
+ const entry = enqueue(slideId, elementId);
29513
+ if (!entry) {
29514
+ return;
29515
+ }
29516
+ entry.geometry = { ...entry.geometry, ...geometry };
29517
+ schedule();
29518
+ },
29519
+ patchText(slideId, elementId, text, source) {
29520
+ const entry = enqueue(slideId, elementId);
29521
+ if (!entry) {
29522
+ return;
29523
+ }
29524
+ entry.text = { value: text, source: source ?? entry.text?.source ?? {} };
29525
+ schedule();
29526
+ },
29527
+ flush() {
29528
+ cancelTimer();
29529
+ writePending();
29530
+ },
29531
+ dispose() {
29532
+ cancelTimer();
29533
+ pending.clear();
29534
+ doc = null;
29535
+ factories = null;
29536
+ },
29537
+ };
29538
+ }
29539
+ // ---------------------------------------------------------------------------
29540
+ // Binding helpers
29541
+ // ---------------------------------------------------------------------------
29542
+ /**
29543
+ * Publish the interim inline-editor text for `elementId` on `slide`. Reads the
29544
+ * element's pre-edit segments/style so the remap keeps per-run formatting (and
29545
+ * equation/field metadata). Safe to call on every keystroke: it no-ops when
29546
+ * collaboration is off, the slide/element is unknown, or the element carries no
29547
+ * text.
29548
+ */
29549
+ function publishLiveInlineText(patcher, slide, elementId, text) {
29550
+ if (!patcher || !slide || !elementId || !patcher.isActive()) {
29551
+ return;
29552
+ }
29553
+ const element = slide.elements.find((el) => el.id === elementId);
29554
+ if (!element || !hasTextProperties(element)) {
29555
+ return;
29556
+ }
29557
+ patcher.patchText(slide.id, elementId, text, {
29558
+ textSegments: element.textSegments,
29559
+ textStyle: element.textStyle,
29560
+ });
29561
+ }
29562
+ /** Publish interim geometry for `elementId` on the slide with id `slideId`. */
29563
+ function publishLiveGeometry(patcher, slideId, elementId, geometry) {
29564
+ if (!patcher || !elementId || !patcher.isActive()) {
29565
+ return;
29566
+ }
29567
+ patcher.patchGeometry(slideId, elementId, geometry);
29568
+ }
29569
+
29323
29570
  /**
29324
29571
  * collaboration-sync-gate.ts: first-write gate for collaborative sessions.
29325
29572
  *
@@ -29372,6 +29619,231 @@ function createSyncGate(onOpen, graceMs = INITIAL_SYNC_GRACE_MS) {
29372
29619
  };
29373
29620
  }
29374
29621
 
29622
+ /**
29623
+ * collaboration-teardown.ts: make a departing peer actually leave the room.
29624
+ *
29625
+ * Every binding tears its collaboration session down on component unmount, but
29626
+ * that path never runs when the *document* goes away: closing the tab,
29627
+ * navigating away, or (the case that motivated this module) an embedding page
29628
+ * removing the viewer's `<iframe>` outright. y-webrtc installs its own
29629
+ * `beforeunload` handler, but `beforeunload` is only fired by the
29630
+ * "prompt to unload" algorithm during a navigation; destroying a document by
29631
+ * detaching its frame fires `pagehide`/`unload` and never `beforeunload`. The
29632
+ * peer therefore keeps its awareness entry until the 30s awareness timeout,
29633
+ * which reads as a ghost collaborator in everyone else's presence list.
29634
+ *
29635
+ * This helper registers the missing listeners once per session:
29636
+ * - `pagehide` (the reliable signal, and the only one mobile Safari honours),
29637
+ * - `beforeunload` (belt and braces for the plain navigation case),
29638
+ * - a `postMessage` from an embedding page (see {@link COLLAB_LEAVE_MESSAGE}),
29639
+ * so a host that is about to destroy the frame can ask it to leave first
29640
+ * instead of relying on the unload path alone.
29641
+ *
29642
+ * A `pagehide` with `persisted === true` means the document went into the
29643
+ * back/forward cache and may come back. We only leave in that case when the
29644
+ * caller supplied a `rejoin`, and then rejoin from `pageshow`.
29645
+ *
29646
+ * The window is injected (structurally typed) so bindings can unit-test the
29647
+ * behaviour without a DOM.
29648
+ */
29649
+ /**
29650
+ * `postMessage` payload an embedding page can send into a viewer frame to make
29651
+ * it leave its collaboration room before the frame is destroyed:
29652
+ * `frame.contentWindow?.postMessage({ type: COLLAB_LEAVE_MESSAGE }, '*')`.
29653
+ */
29654
+ const COLLAB_LEAVE_MESSAGE = 'pptx-viewer:collab-leave';
29655
+ /** Resolve the listener target without depending on DOM lib types. */
29656
+ function resolveTarget(target) {
29657
+ if (target) {
29658
+ return target;
29659
+ }
29660
+ const scope = globalThis;
29661
+ return scope.window ?? null;
29662
+ }
29663
+ /** Whether a `message` event carries the leave request. */
29664
+ function isLeaveMessage(data) {
29665
+ if (typeof data === 'string') {
29666
+ return data === COLLAB_LEAVE_MESSAGE;
29667
+ }
29668
+ if (typeof data !== 'object' || data === null) {
29669
+ return false;
29670
+ }
29671
+ return data.type === COLLAB_LEAVE_MESSAGE;
29672
+ }
29673
+ /**
29674
+ * Register document-teardown listeners that make the local peer leave its
29675
+ * collaboration room. Returns a disposer that removes them again; call it from
29676
+ * the binding's normal unmount cleanup (which performs its own teardown).
29677
+ *
29678
+ * Safe to call in a non-browser environment: it becomes a no-op disposer.
29679
+ */
29680
+ function registerCollaborationTeardown(options) {
29681
+ const target = resolveTarget(options.target);
29682
+ if (!target) {
29683
+ return () => { };
29684
+ }
29685
+ const { leave, rejoin } = options;
29686
+ let left = false;
29687
+ const doLeave = () => {
29688
+ if (left) {
29689
+ return;
29690
+ }
29691
+ left = true;
29692
+ leave();
29693
+ };
29694
+ const onPageHide = (event) => {
29695
+ if (event.persisted === true && !rejoin) {
29696
+ // Bfcache'd with no way back into the room: keep the session so the
29697
+ // restored page keeps working rather than silently going offline.
29698
+ return;
29699
+ }
29700
+ doLeave();
29701
+ };
29702
+ const onBeforeUnload = () => {
29703
+ doLeave();
29704
+ };
29705
+ const onPageShow = (event) => {
29706
+ if (event.persisted !== true || !left || !rejoin) {
29707
+ return;
29708
+ }
29709
+ left = false;
29710
+ rejoin();
29711
+ };
29712
+ const onMessage = (event) => {
29713
+ if (isLeaveMessage(event.data)) {
29714
+ doLeave();
29715
+ }
29716
+ };
29717
+ target.addEventListener('pagehide', onPageHide);
29718
+ target.addEventListener('beforeunload', onBeforeUnload);
29719
+ target.addEventListener('pageshow', onPageShow);
29720
+ target.addEventListener('message', onMessage);
29721
+ return () => {
29722
+ target.removeEventListener('pagehide', onPageHide);
29723
+ target.removeEventListener('beforeunload', onBeforeUnload);
29724
+ target.removeEventListener('pageshow', onPageShow);
29725
+ target.removeEventListener('message', onMessage);
29726
+ };
29727
+ }
29728
+ /**
29729
+ * Withdraw the local awareness state so peers drop us immediately instead of
29730
+ * waiting out the 30s awareness timeout. Yjs broadcasts the resulting `removed`
29731
+ * update through the still-open transport, so call this BEFORE destroying the
29732
+ * provider.
29733
+ */
29734
+ function clearLocalAwareness(awareness) {
29735
+ awareness?.setLocalState?.(null);
29736
+ }
29737
+
29738
+ /**
29739
+ * collaboration-departure.ts: a synchronous "I am leaving" announcement.
29740
+ *
29741
+ * Destroying a Yjs provider is NOT enough to make a peer disappear when the
29742
+ * document itself is going away (tab close, navigation, or an embedding page
29743
+ * detaching the viewer's iframe):
29744
+ *
29745
+ * - y-webrtc broadcasts the awareness removal through
29746
+ * `cryptoutils.encrypt(...).then(...)`, i.e. always one microtask later. By
29747
+ * then the detached frame's BroadcastChannel / RTCDataChannel are dead and
29748
+ * the browser silently drops the message.
29749
+ * - y-webrtc's `peer.on('close')` handler does not remove the peer's awareness
29750
+ * state either, so surviving peers keep the entry until the 30s awareness
29751
+ * timeout: a ghost collaborator in every presence list.
29752
+ *
29753
+ * This module closes that window for the same-browser case (which is exactly
29754
+ * the embedded-iframe case) with a plain BroadcastChannel `postMessage` issued
29755
+ * SYNCHRONOUSLY from the teardown path, which the browser does deliver even
29756
+ * from a document that is being destroyed. Every live session listens on the
29757
+ * same channel and drops the announced client from its own awareness at once.
29758
+ *
29759
+ * Cross-device peers are unaffected by this channel and still rely on the
29760
+ * transport (socket close / peer close plus the awareness timeout).
29761
+ */
29762
+ /** BroadcastChannel name shared by every viewer session in the browser. */
29763
+ const DEPARTURE_CHANNEL = 'pptx-viewer:collab-departures';
29764
+ /**
29765
+ * Drop `clients` from `awareness` locally and notify its observers, mirroring
29766
+ * `y-protocols`' `removeAwarenessStates` for remote clients (the local-client
29767
+ * clock bump is not needed here: we never announce ourselves to ourselves).
29768
+ */
29769
+ function removeAwarenessStatesLocally(awareness, clients) {
29770
+ const states = awareness?.states;
29771
+ if (!awareness || !states) {
29772
+ return [];
29773
+ }
29774
+ const removed = [];
29775
+ for (const clientId of clients) {
29776
+ if (states.delete(clientId)) {
29777
+ removed.push(clientId);
29778
+ }
29779
+ }
29780
+ if (removed.length > 0) {
29781
+ const change = { added: [], updated: [], removed };
29782
+ awareness.emit?.('change', [change, 'peer-departed']);
29783
+ awareness.emit?.('update', [change, 'peer-departed']);
29784
+ }
29785
+ return removed;
29786
+ }
29787
+ /** Whether `data` is a departure notice for a different client in `roomId`. */
29788
+ function readNotice(data, roomId, selfId) {
29789
+ if (typeof data !== 'object' || data === null) {
29790
+ return null;
29791
+ }
29792
+ const notice = data;
29793
+ if (notice.channel !== DEPARTURE_CHANNEL || notice.roomId !== roomId) {
29794
+ return null;
29795
+ }
29796
+ if (typeof notice.clientId !== 'number' || notice.clientId === selfId) {
29797
+ return null;
29798
+ }
29799
+ return notice.clientId;
29800
+ }
29801
+ function defaultFactory(name) {
29802
+ const scope = globalThis;
29803
+ if (!scope.BroadcastChannel) {
29804
+ return null;
29805
+ }
29806
+ return new scope.BroadcastChannel(name);
29807
+ }
29808
+ /**
29809
+ * Open the departure channel for one collaboration session: listens for peers
29810
+ * announcing their exit (dropping them from `awareness` immediately) and
29811
+ * exposes {@link DepartureChannel.announce} for our own exit.
29812
+ *
29813
+ * Returns a no-op channel where `BroadcastChannel` is unavailable (SSR, older
29814
+ * runtimes), so callers never need to guard.
29815
+ */
29816
+ function createDepartureChannel(roomId, awareness, factory) {
29817
+ const channel = factory ? factory(DEPARTURE_CHANNEL) : defaultFactory(DEPARTURE_CHANNEL);
29818
+ if (!channel) {
29819
+ return { announce: () => { }, dispose: () => { } };
29820
+ }
29821
+ const selfId = awareness.clientID;
29822
+ channel.onmessage = (event) => {
29823
+ const departed = readNotice(event.data, roomId, selfId);
29824
+ if (departed !== null) {
29825
+ removeAwarenessStatesLocally(awareness, [departed]);
29826
+ }
29827
+ };
29828
+ let closed = false;
29829
+ return {
29830
+ announce: () => {
29831
+ if (closed || typeof selfId !== 'number') {
29832
+ return;
29833
+ }
29834
+ channel.postMessage({ channel: DEPARTURE_CHANNEL, roomId, clientId: selfId });
29835
+ },
29836
+ dispose: () => {
29837
+ if (closed) {
29838
+ return;
29839
+ }
29840
+ closed = true;
29841
+ channel.onmessage = null;
29842
+ channel.close();
29843
+ },
29844
+ };
29845
+ }
29846
+
29375
29847
  const DEFAULT_DEBOUNCE_MS = 5_000;
29376
29848
  function createWriteBackScheduler(deps) {
29377
29849
  let timer = null;
@@ -51271,7 +51743,7 @@ function createLocalStorageBackend(namespace) {
51271
51743
  /** Try IndexedDB first; fall back to localStorage on any failure. */
51272
51744
  async function resolveBackend(dbName, namespace) {
51273
51745
  try {
51274
- const { openChatDb, createIdbBackend } = await import('./pptx-angular-viewer-chat-history-idb-D2zc6UxX.mjs');
51746
+ const { openChatDb, createIdbBackend } = await import('./pptx-angular-viewer-chat-history-idb-wNAwjS8U.mjs');
51275
51747
  const db = await openChatDb(dbName);
51276
51748
  return createIdbBackend(db);
51277
51749
  }
@@ -53502,6 +53974,129 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.8", ngImpor
53502
53974
  `, styles: [":host{position:absolute;inset:0;pointer-events:none;overflow:visible;z-index:9999}.pptx-ng-collab-cursor{position:absolute;top:0;left:0;pointer-events:none;will-change:transform;transition:transform 90ms linear}.pptx-ng-collab-pointer{display:block;filter:drop-shadow(0 1px 1px rgba(0,0,0,.35))}.pptx-ng-collab-label{position:absolute;top:16px;left:12px;max-width:150px;padding:2px 6px;border-radius:4px;color:#fff;font-family:system-ui,sans-serif;font-size:10px;font-weight:500;line-height:1.2;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;box-shadow:0 1px 2px #0000004d}\n"] }]
53503
53975
  }], propDecorators: { cursors: [{ type: i0.Input, args: [{ isSignal: true, alias: "cursors", required: false }] }], zoom: [{ type: i0.Input, args: [{ isSignal: true, alias: "zoom", required: false }] }] } });
53504
53976
 
53977
+ /**
53978
+ * collaboration-providers.ts: transport factories for the Angular
53979
+ * collaboration service.
53980
+ *
53981
+ * Isolates the dynamic `yjs` / `y-websocket` / `y-webrtc` imports and provider
53982
+ * construction so the service focuses on lifecycle + reactive state. The Yjs
53983
+ * packages are dynamically imported (plain string-literal specifiers, matching
53984
+ * React/Vue) so they are fully tree-shaken when collaboration is unused, while
53985
+ * still resolving correctly under a consuming app's Vite dev server: an
53986
+ * `@vite-ignore`d or variable specifier skips Vite's dev-time bare-specifier
53987
+ * rewrite, which then fails to resolve natively in the browser.
53988
+ */
53989
+ async function createDoc() {
53990
+ const Y = (await import('yjs'));
53991
+ const doc = new Y.Doc();
53992
+ const factories = {
53993
+ createMap: () => new Y.Map(),
53994
+ createArray: () => new Y.Array(),
53995
+ createText: () => new Y.Text(),
53996
+ };
53997
+ return { doc, factories, Y };
53998
+ }
53999
+ /** Create a y-websocket transport bundle for `config`. */
54000
+ async function createWebsocketBundle(config) {
54001
+ const [{ doc, factories }, yws] = await Promise.all([
54002
+ createDoc(),
54003
+ import('y-websocket'),
54004
+ ]);
54005
+ const provider = new yws.WebsocketProvider(config.serverUrl, config.roomId, doc, config.authToken ? { params: { token: config.authToken } } : undefined);
54006
+ return {
54007
+ doc,
54008
+ provider,
54009
+ awareness: provider.awareness,
54010
+ factories,
54011
+ departure: createDepartureChannel(config.roomId, provider.awareness),
54012
+ };
54013
+ }
54014
+ /**
54015
+ * Create a y-webrtc (peer-to-peer, serverless) transport bundle for `config`.
54016
+ * Peers rendezvous through the configured `signaling` servers (or y-webrtc's
54017
+ * public default) and same-browser tabs additionally sync via BroadcastChannel.
54018
+ * `authToken` is passed as the room `password`.
54019
+ */
54020
+ async function createWebrtcBundle(config) {
54021
+ const [{ doc, factories }, yrtc] = await Promise.all([
54022
+ createDoc(),
54023
+ import('y-webrtc'),
54024
+ ]);
54025
+ const provider = new yrtc.WebrtcProvider(config.roomId, doc, {
54026
+ signaling: config.signaling?.length ? config.signaling : undefined,
54027
+ password: config.authToken || undefined,
54028
+ });
54029
+ return {
54030
+ doc,
54031
+ provider,
54032
+ awareness: provider.awareness,
54033
+ factories,
54034
+ departure: createDepartureChannel(config.roomId, provider.awareness),
54035
+ };
54036
+ }
54037
+
54038
+ /**
54039
+ * collaboration-connection.ts: provider connection-status wiring for the
54040
+ * Angular `CollaborationService`. Owns the websocket connect timeout and drives
54041
+ * the status transitions plus the sync-gate re-arm on drops; extracted from
54042
+ * `collaboration.service.ts` so the service stays within the file-size budget.
54043
+ *
54044
+ * Mirrors the vanilla binding's module of the same name, but over Angular's
54045
+ * `ProviderLike` event surface (`on('status', payload)` with
54046
+ * `payload.connected` for webrtc / `payload.status` for websocket).
54047
+ */
54048
+ /**
54049
+ * Subscribe to the provider's status events, driving `setStatus` and the
54050
+ * sync-gate re-arm. For websocket transports this also arms a one-shot connect
54051
+ * timeout when the socket is not open yet.
54052
+ */
54053
+ function wireConnectionStatus(deps) {
54054
+ const { provider, transport } = deps;
54055
+ let connectTimer = null;
54056
+ function cancelConnectTimer() {
54057
+ if (connectTimer !== null) {
54058
+ clearTimeout(connectTimer);
54059
+ connectTimer = null;
54060
+ }
54061
+ }
54062
+ if (transport === 'webrtc') {
54063
+ // P2P: no server round-trip to wait on. Treat "created" as connected, and
54064
+ // reflect explicit disconnect events (re-arming the gate on a drop).
54065
+ deps.setStatus('connected');
54066
+ provider.on('status', (payload) => {
54067
+ if (payload.connected === false && deps.isActive()) {
54068
+ deps.setStatus('disconnected');
54069
+ deps.reArmGate();
54070
+ }
54071
+ else if (payload.connected === true) {
54072
+ deps.setStatus('connected');
54073
+ }
54074
+ });
54075
+ return { cancelConnectTimer };
54076
+ }
54077
+ provider.on('status', (payload) => {
54078
+ if (payload.status === 'connected') {
54079
+ cancelConnectTimer();
54080
+ deps.setStatus('connected');
54081
+ }
54082
+ else if (payload.status === 'disconnected' && deps.isActive()) {
54083
+ deps.setStatus('disconnected');
54084
+ deps.reArmGate();
54085
+ }
54086
+ });
54087
+ if (provider.wsconnected) {
54088
+ deps.setStatus('connected');
54089
+ return { cancelConnectTimer };
54090
+ }
54091
+ connectTimer = setTimeout(() => {
54092
+ connectTimer = null;
54093
+ if (deps.getStatus() !== 'connected') {
54094
+ deps.onConnectTimeout();
54095
+ }
54096
+ }, CONNECTION_TIMEOUT_MS);
54097
+ return { cancelConnectTimer };
54098
+ }
54099
+
53505
54100
  /**
53506
54101
  * collaboration-local-presence.ts: publishes the local user's presence into a
53507
54102
  * single awareness `presence` field.
@@ -53551,52 +54146,233 @@ class LocalPresencePublisher {
53551
54146
  }
53552
54147
 
53553
54148
  /**
53554
- * collaboration-providers.ts: transport factories for the Angular
53555
- * collaboration service.
54149
+ * collaboration-session-setup.ts: build up and tear down a live collaboration
54150
+ * session for the Angular `CollaborationService`.
53556
54151
  *
53557
- * Isolates the dynamic `yjs` / `y-websocket` / `y-webrtc` imports and provider
53558
- * construction so the service focuses on lifecycle + reactive state. The Yjs
53559
- * packages are dynamically imported (plain string-literal specifiers, matching
53560
- * React/Vue) so they are fully tree-shaken when collaboration is unused, while
53561
- * still resolving correctly under a consuming app's Vite dev server: an
53562
- * `@vite-ignore`d or variable specifier skips Vite's dev-time bare-specifier
53563
- * rewrite, which then fails to resolve natively in the browser.
54152
+ * Extracted from `collaboration.service.ts` so the service keeps only its
54153
+ * reactive state and public API. `activateSession` wires a freshly-created
54154
+ * provider bundle into a running session and returns the {@link ActiveSession}
54155
+ * the service holds as a single atomic handle; `teardownSession` disposes it.
53564
54156
  */
53565
- async function createDoc() {
53566
- const Y = (await import('yjs'));
53567
- const doc = new Y.Doc();
53568
- const factories = {
53569
- createMap: () => new Y.Map(),
53570
- createArray: () => new Y.Array(),
53571
- createText: () => new Y.Text(),
54157
+ /**
54158
+ * Wire `bundle` into an active session: configure the live-patch channel, bind
54159
+ * the slide-sync engine, publish local presence, subscribe to awareness +
54160
+ * connection-status + remote-slide changes, then open the first-write gate.
54161
+ */
54162
+ function activateSession(bundle, config, transport, deps) {
54163
+ deps.livePatcher.configure(bundle.doc, bundle.factories);
54164
+ deps.slideSync.bind({
54165
+ ydoc: bundle.doc,
54166
+ factories: bundle.factories,
54167
+ onRemoteSlides: deps.onRemoteSlides,
54168
+ scheduleWriteBack: deps.scheduleWriteBack,
54169
+ });
54170
+ const localPresence = new LocalPresencePublisher(bundle.awareness, {
54171
+ userName: config.userName,
54172
+ userColor: config.userColor ?? DEFAULT_CURSOR_COLOR,
54173
+ userAvatar: config.userAvatar,
54174
+ role: config.role,
54175
+ });
54176
+ localPresence.publish();
54177
+ bundle.awareness.on('change', deps.refreshPresence);
54178
+ bundle.awareness.on('update', deps.refreshPresence);
54179
+ deps.slideSync.gate.reset();
54180
+ const connection = wireConnectionStatus({
54181
+ provider: bundle.provider,
54182
+ transport,
54183
+ setStatus: deps.setStatus,
54184
+ getStatus: deps.getStatus,
54185
+ isActive: deps.isActive,
54186
+ reArmGate: () => {
54187
+ deps.slideSync.gate.reset();
54188
+ deps.slideSync.gate.arm();
54189
+ },
54190
+ onConnectTimeout: deps.failConnection,
54191
+ });
54192
+ deps.slideSync.wireSynced(bundle.provider);
54193
+ const unobserve = observeYDocSlides(bundle.doc, (_events, transaction) => deps.slideSync.onRemoteChange(transaction));
54194
+ return {
54195
+ ydoc: bundle.doc,
54196
+ provider: bundle.provider,
54197
+ awareness: bundle.awareness,
54198
+ departure: bundle.departure,
54199
+ factories: bundle.factories,
54200
+ selfId: bundle.awareness.clientID ?? -1,
54201
+ localPresence,
54202
+ connection,
54203
+ unobserve,
53572
54204
  };
53573
- return { doc, factories, Y };
53574
54205
  }
53575
- /** Create a y-websocket transport bundle for `config`. */
53576
- async function createWebsocketBundle(config) {
53577
- const [{ doc, factories }, yws] = await Promise.all([
53578
- createDoc(),
53579
- import('y-websocket'),
53580
- ]);
53581
- const provider = new yws.WebsocketProvider(config.serverUrl, config.roomId, doc, config.authToken ? { params: { token: config.authToken } } : undefined);
53582
- return { doc, provider, awareness: provider.awareness, factories };
54206
+ /**
54207
+ * Dispose a live session. Announces the departure synchronously first: the
54208
+ * provider's own awareness removal is broadcast a microtask later and would be
54209
+ * dropped when this runs from a document being destroyed, leaving a ghost
54210
+ * collaborator until the 30s awareness timeout.
54211
+ */
54212
+ function teardownSession(session, refreshPresence) {
54213
+ session.connection.cancelConnectTimer();
54214
+ session.unobserve();
54215
+ session.awareness.off?.('change', refreshPresence);
54216
+ session.awareness.off?.('update', refreshPresence);
54217
+ session.departure.announce();
54218
+ session.departure.dispose();
54219
+ clearLocalAwareness(session.awareness);
54220
+ session.provider.disconnect();
54221
+ session.provider.destroy();
54222
+ session.ydoc.destroy();
53583
54223
  }
54224
+
53584
54225
  /**
53585
- * Create a y-webrtc (peer-to-peer, serverless) transport bundle for `config`.
53586
- * Peers rendezvous through the configured `signaling` servers (or y-webrtc's
53587
- * public default) and same-browser tabs additionally sync via BroadcastChannel.
53588
- * `authToken` is passed as the room `password`.
54226
+ * collaboration-slide-sync.ts: the granular local<->doc slide sync engine for
54227
+ * the Angular `CollaborationService`, extracted so the service stays within the
54228
+ * repo's 300 LOC ceiling.
54229
+ *
54230
+ * Owns the first-write gate plus the echo-dedupe bookkeeping (`lastSynced`,
54231
+ * `applyingRemote`, `pendingBroadcast`) and the broadcast / remote-apply /
54232
+ * post-load-adoption logic. The service keeps provider + awareness ownership
54233
+ * and binds this engine to the live doc for the duration of a session.
53589
54234
  */
53590
- async function createWebrtcBundle(config) {
53591
- const [{ doc, factories }, yrtc] = await Promise.all([
53592
- createDoc(),
53593
- import('y-webrtc'),
53594
- ]);
53595
- const provider = new yrtc.WebrtcProvider(config.roomId, doc, {
53596
- signaling: config.signaling?.length ? config.signaling : undefined,
53597
- password: config.authToken || undefined,
53598
- });
53599
- return { doc, provider, awareness: provider.awareness, factories };
54235
+ class SlideSyncEngine {
54236
+ /**
54237
+ * First-write gate: local broadcasts are suppressed (captured as pending)
54238
+ * until the provider confirms its initial sync or the grace period lifts the
54239
+ * gate, so a late joiner never seeds its placeholder deck into a room whose
54240
+ * real content has not arrived yet.
54241
+ */
54242
+ gate = createSyncGate(() => this.#flushPending());
54243
+ #binding = null;
54244
+ #lastSynced = '';
54245
+ #applyingRemote = false;
54246
+ #pending = null;
54247
+ /** Attach the engine to a freshly connected session's doc. */
54248
+ bind(binding) {
54249
+ this.#binding = binding;
54250
+ }
54251
+ /** Clear all per-session state (call on disconnect). */
54252
+ reset() {
54253
+ this.gate.reset();
54254
+ this.#binding = null;
54255
+ this.#pending = null;
54256
+ this.#lastSynced = '';
54257
+ this.#applyingRemote = false;
54258
+ }
54259
+ /**
54260
+ * Record the current local deck as the sync baseline so the first (unchanged)
54261
+ * broadcast after connecting is suppressed. Call right after connect for a
54262
+ * joiner whose local deck is a placeholder awaiting remote sync, so it never
54263
+ * overwrites the shared document before receiving it.
54264
+ */
54265
+ seedBaseline(slides) {
54266
+ this.#lastSynced = JSON.stringify(slides);
54267
+ }
54268
+ /**
54269
+ * Open the first-write gate on the provider's initial-sync confirmation.
54270
+ * y-websocket emits 'sync' with a boolean; y-webrtc emits 'synced' with an
54271
+ * object carrying a `synced` flag (and only once a peer syncs, hence the
54272
+ * grace timer). Listen to both; opening is idempotent.
54273
+ */
54274
+ wireSynced(provider) {
54275
+ const handle = (payload) => {
54276
+ const flag = payload;
54277
+ const isSynced = typeof flag === 'boolean' ? flag : flag?.synced !== false;
54278
+ if (isSynced) {
54279
+ this.gate.open();
54280
+ }
54281
+ };
54282
+ provider.on('sync', handle);
54283
+ provider.on('synced', handle);
54284
+ if (provider.synced === true) {
54285
+ this.gate.open();
54286
+ }
54287
+ else {
54288
+ this.gate.arm();
54289
+ }
54290
+ }
54291
+ /**
54292
+ * Broadcast the local slide set to peers, reconciling only what changed into
54293
+ * the pptx:slides Y.Array. An empty deck is never written (so a late-joiner
54294
+ * that has not yet received the doc cannot clobber it), an unchanged deck is
54295
+ * skipped, and while the gate is shut the deck is held as pending.
54296
+ */
54297
+ broadcast(slides) {
54298
+ const b = this.#binding;
54299
+ if (!b || this.#applyingRemote || slides.length === 0) {
54300
+ return;
54301
+ }
54302
+ if (!this.gate.isOpen()) {
54303
+ this.#pending = slides;
54304
+ return;
54305
+ }
54306
+ const s = JSON.stringify(slides);
54307
+ if (s === this.#lastSynced) {
54308
+ return;
54309
+ }
54310
+ this.#lastSynced = s;
54311
+ reconcileSlidesInYDoc([...slides], b.ydoc, b.factories, LOCAL_SYNC_ORIGIN);
54312
+ b.scheduleWriteBack();
54313
+ }
54314
+ /** Handle a remote Y.Doc change, skipping our own local-origin transactions. */
54315
+ onRemoteChange(transaction) {
54316
+ const b = this.#binding;
54317
+ if (transaction?.origin === LOCAL_SYNC_ORIGIN || this.#applyingRemote || !b) {
54318
+ return;
54319
+ }
54320
+ const remote = readSlidesFromYDoc(b.ydoc);
54321
+ if (remote.length === 0) {
54322
+ return;
54323
+ }
54324
+ // Suppress the echo: record what we just applied so the subsequent local
54325
+ // broadcast (driven by the editor signal) is a no-op.
54326
+ this.#lastSynced = JSON.stringify(remote);
54327
+ this.#applyingRemote = true;
54328
+ b.onRemoteSlides?.(remote);
54329
+ this.#applyingRemote = false;
54330
+ b.scheduleWriteBack();
54331
+ }
54332
+ /**
54333
+ * Re-adopt the shared document's slides after a local content load committed
54334
+ * a parsed deck to viewer state. The load pipeline applies its deck
54335
+ * unconditionally, so a load finishing AFTER the room's slides were applied
54336
+ * (a late joiner's bootstrap deck parsing slower than the doc sync) would
54337
+ * clobber the synced state, and with the doc itself unchanged the observer
54338
+ * never re-fires. When the room already has slides they win, re-applied
54339
+ * through `onRemoteSlides` and recorded as the baseline (bypassing the JSON
54340
+ * dedupe) so the follow-up local broadcast is a no-op. An empty room means
54341
+ * this client is the seeder. Returns true when the doc was adopted.
54342
+ */
54343
+ adoptDocAfterLoad() {
54344
+ const b = this.#binding;
54345
+ if (!b) {
54346
+ return false;
54347
+ }
54348
+ const docSlides = readSlidesFromYDoc(b.ydoc);
54349
+ if (docSlides.length === 0) {
54350
+ return false;
54351
+ }
54352
+ this.#lastSynced = JSON.stringify(docSlides);
54353
+ this.#applyingRemote = true;
54354
+ b.onRemoteSlides?.(docSlides);
54355
+ this.#applyingRemote = false;
54356
+ return true;
54357
+ }
54358
+ /**
54359
+ * Perform the deferred first broadcast once the gate opens. When the doc is
54360
+ * still empty (fresh room, or nobody else present), clear the baseline so the
54361
+ * pending deck actually seeds it; when remote content already arrived, the
54362
+ * pending deck matches the applied baseline and the write is a no-op.
54363
+ */
54364
+ #flushPending() {
54365
+ const b = this.#binding;
54366
+ const pending = this.#pending;
54367
+ this.#pending = null;
54368
+ if (!pending || !b) {
54369
+ return;
54370
+ }
54371
+ if (b.ydoc.getArray(YDOC_SLIDES_KEY).length === 0) {
54372
+ this.#lastSynced = '';
54373
+ }
54374
+ this.broadcast(pending);
54375
+ }
53600
54376
  }
53601
54377
 
53602
54378
  /**
@@ -53733,6 +54509,7 @@ class WriteBackScheduler {
53733
54509
  *
53734
54510
  * Provide at the component level: `@Component({ providers: [CollaborationService] })`.
53735
54511
  */
54512
+ /** Sentinel canvas bound used until the host reports real dimensions. */
53736
54513
  const DEFAULT_CANVAS_BOUND = 100_000;
53737
54514
  class CollaborationService {
53738
54515
  // Reactive state
@@ -53766,25 +54543,19 @@ class CollaborationService {
53766
54543
  /** Active-slide index of the first `owner` peer (the broadcaster), or null. */
53767
54544
  broadcasterSlideIndex = computed(() => this.presence().find((p) => p.role === 'owner')?.activeSlideIndex ?? null, /* @ts-ignore */
53768
54545
  ...(ngDevMode ? [{ debugName: "broadcasterSlideIndex" }] : /* istanbul ignore next */ []));
53769
- // Internal handles
53770
- ydoc = null;
53771
- provider = null;
53772
- awareness = null;
53773
- selfId = -1;
53774
- applyingRemote = false;
53775
- yFactories = null;
53776
- lastSynced = '';
53777
- connectTimer = null;
53778
- unobserveSlides = null;
53779
- writeBack = new WriteBackScheduler();
53780
54546
  /**
53781
- * First-write gate: local broadcasts are suppressed (captured as pending)
53782
- * until the provider confirms its initial sync or the grace period lifts
53783
- * the gate, so a late joiner never seeds its placeholder deck into a room
53784
- * whose real content has not arrived yet.
54547
+ * Interim ("live preview") Y.Doc write channel: publishes in-flight inline
54548
+ * editor text that has not reached the slides state yet, so peers see typing
54549
+ * as it happens instead of on commit. Dormant outside a session.
53785
54550
  */
53786
- syncGate = createSyncGate(() => this.flushPendingBroadcast());
53787
- pendingBroadcast = null;
54551
+ livePatcher = createCollaborationLivePatcher();
54552
+ // The live session's transport objects + wiring handles, owned as one atomic
54553
+ // unit: null when disconnected, assigned by connect(), disposed by
54554
+ // disconnect(). See collaboration-session-setup.ts.
54555
+ session = null;
54556
+ writeBack = new WriteBackScheduler();
54557
+ /** Granular local<->doc slide sync (gate + echo dedupe + broadcast/adopt). */
54558
+ slideSync = new SlideSyncEngine();
53788
54559
  onRemoteSlides = null;
53789
54560
  canvasWidth = DEFAULT_CANVAS_BOUND;
53790
54561
  canvasHeight = DEFAULT_CANVAS_BOUND;
@@ -53793,7 +54564,6 @@ class CollaborationService {
53793
54564
  currentConfig = null;
53794
54565
  lastConfig = null;
53795
54566
  lastOptions = {};
53796
- localPresence = null;
53797
54567
  /**
53798
54568
  * Reentrancy token for {@link connect}: bumped by every connect() and
53799
54569
  * disconnect(). A connect() whose token no longer matches after an await was
@@ -53803,14 +54573,26 @@ class CollaborationService {
53803
54573
  */
53804
54574
  connectToken = 0;
53805
54575
  refreshPresence = () => {
53806
- if (!this.awareness) {
54576
+ const s = this.session;
54577
+ if (!s) {
53807
54578
  this.presence.set([]);
53808
54579
  return;
53809
54580
  }
53810
- this.presence.set(derivePresenceList(this.awareness.getStates(), this.selfId, this.canvasWidth, this.canvasHeight));
54581
+ this.presence.set(derivePresenceList(s.awareness.getStates(), s.selfId, this.canvasWidth, this.canvasHeight));
53811
54582
  };
53812
54583
  constructor() {
53813
- inject(DestroyRef).onDestroy(() => this.disconnect());
54584
+ // Service destruction is not the only way a session ends: a tab close, a
54585
+ // navigation, or an embedding page detaching the viewer's iframe destroys
54586
+ // the document without running Angular teardown, leaving a ghost peer in
54587
+ // everyone else's presence list. Leave the room from `pagehide` too.
54588
+ const disposeTeardown = registerCollaborationTeardown({
54589
+ leave: () => this.disconnect(),
54590
+ rejoin: () => void this.retry(),
54591
+ });
54592
+ inject(DestroyRef).onDestroy(() => {
54593
+ disposeTeardown();
54594
+ this.disconnect();
54595
+ });
53814
54596
  }
53815
54597
  async connect(config, options = {}) {
53816
54598
  this.disconnect();
@@ -53851,29 +54633,26 @@ class CollaborationService {
53851
54633
  // Superseded by a newer connect() or a disconnect() while awaiting
53852
54634
  // the transport: destroy the just-created bundle and bail without
53853
54635
  // touching the (newer call's) service state.
54636
+ bundle.departure.dispose();
53854
54637
  bundle.provider.disconnect();
53855
54638
  bundle.provider.destroy();
53856
54639
  bundle.doc.destroy();
53857
54640
  return;
53858
54641
  }
53859
- this.ydoc = bundle.doc;
53860
- this.yFactories = bundle.factories;
53861
- this.provider = bundle.provider;
53862
- this.awareness = bundle.awareness;
53863
- this.selfId = this.awareness.clientID ?? -1;
53864
- this.localPresence = new LocalPresencePublisher(this.awareness, {
53865
- userName: config.userName,
53866
- userColor: config.userColor ?? DEFAULT_CURSOR_COLOR,
53867
- userAvatar: config.userAvatar,
53868
- role: config.role,
54642
+ this.session = activateSession(bundle, config, transport, {
54643
+ slideSync: this.slideSync,
54644
+ livePatcher: this.livePatcher,
54645
+ onRemoteSlides: this.onRemoteSlides,
54646
+ refreshPresence: this.refreshPresence,
54647
+ scheduleWriteBack: () => this.scheduleWriteBack(),
54648
+ setStatus: (status) => this.status.set(status),
54649
+ getStatus: () => this.status(),
54650
+ isActive: () => this.active(),
54651
+ failConnection: () => {
54652
+ this.disconnect();
54653
+ this.status.set('error');
54654
+ },
53869
54655
  });
53870
- this.localPresence.publish();
53871
- this.awareness.on('change', this.refreshPresence);
53872
- this.awareness.on('update', this.refreshPresence);
53873
- this.wireStatus(transport);
53874
- this.syncGate.reset();
53875
- this.wireSynced();
53876
- this.unobserveSlides = observeYDocSlides(this.ydoc, (_events, transaction) => this.onRemoteChange(transaction));
53877
54656
  this.active.set(true);
53878
54657
  this.refreshPresence();
53879
54658
  }
@@ -53892,137 +54671,16 @@ class CollaborationService {
53892
54671
  await this.connect(this.lastConfig, this.lastOptions);
53893
54672
  }
53894
54673
  }
53895
- /** Wire the provider status events + (websocket-only) connection timeout. */
53896
- wireStatus(transport) {
53897
- const provider = this.provider;
53898
- if (!provider) {
53899
- return;
53900
- }
53901
- if (transport === 'webrtc') {
53902
- // P2P: no server round-trip to wait on. Treat "created" as connected,
53903
- // and reflect explicit disconnect events.
53904
- this.status.set('connected');
53905
- provider.on('status', (payload) => {
53906
- if (payload.connected === false && this.active()) {
53907
- this.status.set('disconnected');
53908
- // Re-arm on (re)connect: without this, a peer that drops and
53909
- // rejoins keeps the gate permanently open from the first
53910
- // connection and can clobber the room with a stale local doc.
53911
- this.syncGate.reset();
53912
- this.syncGate.arm();
53913
- }
53914
- else if (payload.connected === true) {
53915
- this.status.set('connected');
53916
- }
53917
- });
53918
- return;
53919
- }
53920
- provider.on('status', (payload) => {
53921
- if (payload.status === 'connected') {
53922
- this.clearConnectTimer();
53923
- this.status.set('connected');
53924
- }
53925
- else if (payload.status === 'disconnected' && this.active()) {
53926
- this.status.set('disconnected');
53927
- this.syncGate.reset();
53928
- this.syncGate.arm();
53929
- }
53930
- });
53931
- if (provider.wsconnected) {
53932
- this.status.set('connected');
53933
- return;
53934
- }
53935
- this.connectTimer = setTimeout(() => {
53936
- this.connectTimer = null;
53937
- if (this.status() !== 'connected') {
53938
- this.disconnect();
53939
- this.status.set('error');
53940
- }
53941
- }, CONNECTION_TIMEOUT_MS);
53942
- }
53943
- /**
53944
- * Open the first-write gate on the provider's initial-sync confirmation.
53945
- * y-websocket emits 'sync' with a boolean; y-webrtc emits 'synced' with an
53946
- * object carrying a `synced` flag (and only once a peer syncs, hence the
53947
- * grace timer). Listen to both; opening is idempotent.
53948
- */
53949
- wireSynced() {
53950
- const provider = this.provider;
53951
- if (!provider) {
53952
- return;
53953
- }
53954
- const handle = (payload) => {
53955
- const flag = payload;
53956
- const isSynced = typeof flag === 'boolean' ? flag : flag?.synced !== false;
53957
- if (isSynced) {
53958
- this.syncGate.open();
53959
- }
53960
- };
53961
- provider.on('sync', handle);
53962
- provider.on('synced', handle);
53963
- if (provider.synced === true) {
53964
- this.syncGate.open();
53965
- }
53966
- else {
53967
- this.syncGate.arm();
53968
- }
53969
- }
53970
- /**
53971
- * Perform the deferred first broadcast once the gate opens. When the doc is
53972
- * still empty (fresh room, or nobody else present), clear the baseline so
53973
- * the pending deck actually seeds it; when remote content already arrived,
53974
- * the pending deck matches the applied baseline and the write is a no-op.
53975
- */
53976
- flushPendingBroadcast() {
53977
- const pending = this.pendingBroadcast;
53978
- this.pendingBroadcast = null;
53979
- if (!pending || !this.ydoc || !this.yFactories) {
53980
- return;
53981
- }
53982
- if (this.ydoc.getArray(YDOC_SLIDES_KEY).length === 0) {
53983
- this.lastSynced = '';
53984
- }
53985
- this.broadcastSlides(pending);
53986
- }
53987
- /** Handle a remote Y.Doc change, skipping our own local-origin transactions. */
53988
- onRemoteChange(transaction) {
53989
- if (transaction?.origin === LOCAL_SYNC_ORIGIN || this.applyingRemote || !this.ydoc) {
53990
- return;
53991
- }
53992
- const remote = readSlidesFromYDoc(this.ydoc);
53993
- if (remote.length === 0) {
53994
- return;
53995
- }
53996
- // Suppress the echo: record what we just applied so the subsequent local
53997
- // broadcast (driven by the editor signal) is a no-op.
53998
- this.lastSynced = JSON.stringify(remote);
53999
- this.applyingRemote = true;
54000
- this.onRemoteSlides?.(remote);
54001
- this.applyingRemote = false;
54002
- this.scheduleWriteBack();
54003
- }
54004
54674
  disconnect() {
54005
54675
  // Invalidate any in-flight connect() so it discards its bundle on resume.
54006
54676
  this.connectToken += 1;
54007
- this.clearConnectTimer();
54008
- this.syncGate.reset();
54009
- this.pendingBroadcast = null;
54677
+ this.slideSync.reset();
54010
54678
  this.writeBack.cancel();
54011
- this.unobserveSlides?.();
54012
- this.unobserveSlides = null;
54013
- this.awareness?.off?.('change', this.refreshPresence);
54014
- this.awareness?.off?.('update', this.refreshPresence);
54015
- this.provider?.disconnect();
54016
- this.provider?.destroy();
54017
- this.ydoc?.destroy();
54018
- this.provider = null;
54019
- this.ydoc = null;
54020
- this.awareness = null;
54021
- this.localPresence = null;
54022
- this.selfId = -1;
54023
- this.applyingRemote = false;
54024
- this.yFactories = null;
54025
- this.lastSynced = '';
54679
+ if (this.session) {
54680
+ teardownSession(this.session, this.refreshPresence);
54681
+ this.session = null;
54682
+ }
54683
+ this.livePatcher.configure(null, null);
54026
54684
  this.onRemoteSlides = null;
54027
54685
  this.currentConfig = null;
54028
54686
  this.status.set('disconnected');
@@ -54031,88 +54689,46 @@ class CollaborationService {
54031
54689
  this.presence.set([]);
54032
54690
  this.followedClientId.set(null);
54033
54691
  }
54034
- /**
54035
- * Broadcast the local slide set to peers, reconciling only what changed into
54036
- * the pptx:slides Y.Array. An empty deck is never written (so a late-joiner
54037
- * that has not yet received the doc cannot clobber it), and an unchanged deck
54038
- * is skipped.
54039
- */
54040
54692
  /**
54041
54693
  * Record the current local deck as the sync baseline so the first (unchanged)
54042
54694
  * broadcast after connecting is suppressed. Call right after {@link connect}
54043
- * for a joiner whose local deck is a placeholder awaiting remote sync, so it
54044
- * never overwrites the shared document before receiving it.
54695
+ * for a joiner whose local deck is a placeholder awaiting remote sync.
54045
54696
  */
54046
54697
  seedBaseline(slides) {
54047
- this.lastSynced = JSON.stringify(slides);
54698
+ this.slideSync.seedBaseline(slides);
54048
54699
  }
54049
54700
  /**
54050
- * Re-adopt the shared document's slides after a local content load has been
54051
- * committed to viewer state. The load pipeline applies its parsed deck
54052
- * unconditionally, so a load that finishes AFTER the room's slides were
54053
- * already applied (a late joiner's bootstrap deck parsing slower than the
54054
- * doc sync) silently clobbers the synced state and, with the doc itself
54055
- * unchanged, the remote observer never re-fires. When the room already has
54056
- * slides they win: the doc content is re-applied through `onRemoteSlides`
54057
- * and recorded as the sync baseline (bypassing the usual JSON dedupe) so
54058
- * the follow-up local broadcast of the adopted deck is a no-op. An empty
54059
- * room means this client is the seeder and the loaded deck stands, written
54060
- * by the normal gated broadcast path. Returns true when the doc was adopted.
54701
+ * Re-adopt the shared document's slides after a local content load committed
54702
+ * a parsed deck to viewer state (see {@link SlideSyncEngine.adoptDocAfterLoad}).
54703
+ * Returns true when the room's slides were adopted over the loaded deck.
54061
54704
  */
54062
54705
  adoptDocSlidesAfterLoad() {
54063
- if (!this.ydoc || !this.connected()) {
54064
- return false;
54065
- }
54066
- const docSlides = readSlidesFromYDoc(this.ydoc);
54067
- if (docSlides.length === 0) {
54068
- return false;
54069
- }
54070
- this.lastSynced = JSON.stringify(docSlides);
54071
- this.applyingRemote = true;
54072
- this.onRemoteSlides?.(docSlides);
54073
- this.applyingRemote = false;
54074
- return true;
54706
+ return this.connected() ? this.slideSync.adoptDocAfterLoad() : false;
54075
54707
  }
54708
+ /**
54709
+ * Broadcast the local slide set to peers, reconciling only what changed into
54710
+ * the pptx:slides Y.Array. Empty/unchanged decks are skipped; while the gate
54711
+ * is shut the deck is held pending until the initial sync confirms.
54712
+ */
54076
54713
  broadcastSlides(slides) {
54077
- if (!this.ydoc || !this.yFactories || this.applyingRemote || slides.length === 0) {
54078
- return;
54079
- }
54080
- if (!this.syncGate.isOpen()) {
54081
- // Defer until the initial sync confirms; the gate flushes the latest
54082
- // pending deck when it opens.
54083
- this.pendingBroadcast = slides;
54084
- return;
54085
- }
54086
- const s = JSON.stringify(slides);
54087
- if (s === this.lastSynced) {
54088
- return;
54089
- }
54090
- this.lastSynced = s;
54091
- reconcileSlidesInYDoc([...slides], this.ydoc, this.yFactories, LOCAL_SYNC_ORIGIN);
54092
- this.scheduleWriteBack();
54714
+ this.slideSync.broadcast(slides);
54093
54715
  }
54094
54716
  setCursor(x, y, activeSlideIndex) {
54095
- this.localPresence?.setCursor(x, y, activeSlideIndex);
54717
+ this.session?.localPresence.setCursor(x, y, activeSlideIndex);
54096
54718
  }
54097
54719
  setSelection(selectedElementId, activeSlideIndex) {
54098
- this.localPresence?.setSelection(selectedElementId, activeSlideIndex);
54720
+ this.session?.localPresence.setSelection(selectedElementId, activeSlideIndex);
54099
54721
  }
54100
54722
  /** Publish the local active-slide index (drives follow-along). */
54101
54723
  setActiveSlide(index) {
54102
- this.localPresence?.setActiveSlide(index);
54724
+ this.session?.localPresence.setActiveSlide(index);
54103
54725
  }
54104
54726
  /** Follow the given peer's active slide, or `null` to stop following. */
54105
54727
  followUser(clientId) {
54106
54728
  this.followedClientId.set(clientId);
54107
54729
  }
54108
- clearConnectTimer() {
54109
- if (this.connectTimer !== null) {
54110
- clearTimeout(this.connectTimer);
54111
- this.connectTimer = null;
54112
- }
54113
- }
54114
54730
  scheduleWriteBack() {
54115
- this.writeBack.schedule(this.currentConfig, this.ydoc, this.getSourceBytes, this.getTemplateElements);
54731
+ this.writeBack.schedule(this.currentConfig, this.session?.ydoc ?? null, this.getSourceBytes, this.getTemplateElements);
54116
54732
  }
54117
54733
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: CollaborationService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
54118
54734
  static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: CollaborationService });
@@ -68560,6 +69176,12 @@ class SlideCanvasComponent {
68560
69176
  textEditStart = output();
68561
69177
  /** Emitted with the new text when an inline edit commits. */
68562
69178
  textCommit = output();
69179
+ /**
69180
+ * Emitted on EVERY keystroke while inline-editing. The commit path stays the
69181
+ * only thing that touches editor state/history; this feeds the collaboration
69182
+ * live preview so peers see typing before the edit commits.
69183
+ */
69184
+ textInput = output();
68563
69185
  /** Emitted when an inline edit is cancelled (Escape). */
68564
69186
  textCancel = output();
68565
69187
  /** Emitted on Ctrl/Cmd+B/I/U while inline-editing (parity with React/Vue). */
@@ -68947,6 +69569,10 @@ class SlideCanvasComponent {
68947
69569
  : { underline: !ts?.underline };
68948
69570
  this.textFormat.emit({ id, updates });
68949
69571
  }
69572
+ /** Mirror each keystroke out for the collaboration live preview. */
69573
+ onTextInput(event, id) {
69574
+ this.textInput.emit({ id, text: event.target.value });
69575
+ }
68950
69576
  commitText(event, id) {
68951
69577
  if (this.editCancelled) {
68952
69578
  this.editCancelled = false;
@@ -69276,7 +69902,7 @@ class SlideCanvasComponent {
69276
69902
  }, /* @ts-ignore */
69277
69903
  ...(ngDevMode ? [{ debugName: "stageStyle" }] : /* istanbul ignore next */ []));
69278
69904
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: SlideCanvasComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
69279
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.8", type: SlideCanvasComponent, isStandalone: true, selector: "pptx-slide-canvas", inputs: { slide: { classPropertyName: "slide", publicName: "slide", isSignal: true, isRequired: false, transformFunction: null }, canvasSize: { classPropertyName: "canvasSize", publicName: "canvasSize", isSignal: true, isRequired: true, transformFunction: null }, mediaDataUrls: { classPropertyName: "mediaDataUrls", publicName: "mediaDataUrls", isSignal: true, isRequired: false, transformFunction: null }, zoom: { classPropertyName: "zoom", publicName: "zoom", isSignal: true, isRequired: false, transformFunction: null }, editable: { classPropertyName: "editable", publicName: "editable", 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 }, snapToShape: { classPropertyName: "snapToShape", publicName: "snapToShape", isSignal: true, isRequired: false, transformFunction: null }, guideCommand: { classPropertyName: "guideCommand", publicName: "guideCommand", isSignal: true, isRequired: false, transformFunction: null }, spellCheck: { classPropertyName: "spellCheck", publicName: "spellCheck", isSignal: true, isRequired: false, transformFunction: null }, snapToGuides: { classPropertyName: "snapToGuides", publicName: "snapToGuides", isSignal: true, isRequired: false, transformFunction: null }, autoFit: { classPropertyName: "autoFit", publicName: "autoFit", isSignal: true, isRequired: false, transformFunction: null }, interactive: { classPropertyName: "interactive", publicName: "interactive", isSignal: true, isRequired: false, transformFunction: null }, presenting: { classPropertyName: "presenting", publicName: "presenting", isSignal: true, isRequired: false, transformFunction: null }, selectedIds: { classPropertyName: "selectedIds", publicName: "selectedIds", isSignal: true, isRequired: false, transformFunction: null }, editingId: { classPropertyName: "editingId", publicName: "editingId", isSignal: true, isRequired: false, transformFunction: null }, editTemplateMode: { classPropertyName: "editTemplateMode", publicName: "editTemplateMode", isSignal: true, isRequired: false, transformFunction: null }, templateElements: { classPropertyName: "templateElements", publicName: "templateElements", isSignal: true, isRequired: false, transformFunction: null }, aiHighlights: { classPropertyName: "aiHighlights", publicName: "aiHighlights", isSignal: true, isRequired: false, transformFunction: null }, aiActive: { classPropertyName: "aiActive", publicName: "aiActive", isSignal: true, isRequired: false, transformFunction: null }, aiActiveSlideIndex: { classPropertyName: "aiActiveSlideIndex", publicName: "aiActiveSlideIndex", isSignal: true, isRequired: false, transformFunction: null }, aiChangeBatch: { classPropertyName: "aiChangeBatch", publicName: "aiChangeBatch", isSignal: true, isRequired: false, transformFunction: null }, aiPickMode: { classPropertyName: "aiPickMode", publicName: "aiPickMode", isSignal: true, isRequired: false, transformFunction: null }, drawTool: { classPropertyName: "drawTool", publicName: "drawTool", isSignal: true, isRequired: false, transformFunction: null }, drawColor: { classPropertyName: "drawColor", publicName: "drawColor", isSignal: true, isRequired: false, transformFunction: null }, drawWidth: { classPropertyName: "drawWidth", publicName: "drawWidth", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { elementSelect: "elementSelect", backgroundClick: "backgroundClick", transformStart: "transformStart", transformUpdate: "transformUpdate", contextMenu: "contextMenu", textEditStart: "textEditStart", textCommit: "textCommit", textCancel: "textCancel", textFormat: "textFormat", rotateUpdate: "rotateUpdate", marqueeSelect: "marqueeSelect", inkStrokeComplete: "inkStrokeComplete", eraserHit: "eraserHit", cellCommit: "cellCommit", tableChange: "tableChange" }, host: { listeners: { "document:pointermove": "onPointerMove($event)", "document:pointerup": "onPointerUp()" } }, providers: [
69905
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.8", type: SlideCanvasComponent, isStandalone: true, selector: "pptx-slide-canvas", inputs: { slide: { classPropertyName: "slide", publicName: "slide", isSignal: true, isRequired: false, transformFunction: null }, canvasSize: { classPropertyName: "canvasSize", publicName: "canvasSize", isSignal: true, isRequired: true, transformFunction: null }, mediaDataUrls: { classPropertyName: "mediaDataUrls", publicName: "mediaDataUrls", isSignal: true, isRequired: false, transformFunction: null }, zoom: { classPropertyName: "zoom", publicName: "zoom", isSignal: true, isRequired: false, transformFunction: null }, editable: { classPropertyName: "editable", publicName: "editable", 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 }, snapToShape: { classPropertyName: "snapToShape", publicName: "snapToShape", isSignal: true, isRequired: false, transformFunction: null }, guideCommand: { classPropertyName: "guideCommand", publicName: "guideCommand", isSignal: true, isRequired: false, transformFunction: null }, spellCheck: { classPropertyName: "spellCheck", publicName: "spellCheck", isSignal: true, isRequired: false, transformFunction: null }, snapToGuides: { classPropertyName: "snapToGuides", publicName: "snapToGuides", isSignal: true, isRequired: false, transformFunction: null }, autoFit: { classPropertyName: "autoFit", publicName: "autoFit", isSignal: true, isRequired: false, transformFunction: null }, interactive: { classPropertyName: "interactive", publicName: "interactive", isSignal: true, isRequired: false, transformFunction: null }, presenting: { classPropertyName: "presenting", publicName: "presenting", isSignal: true, isRequired: false, transformFunction: null }, selectedIds: { classPropertyName: "selectedIds", publicName: "selectedIds", isSignal: true, isRequired: false, transformFunction: null }, editingId: { classPropertyName: "editingId", publicName: "editingId", isSignal: true, isRequired: false, transformFunction: null }, editTemplateMode: { classPropertyName: "editTemplateMode", publicName: "editTemplateMode", isSignal: true, isRequired: false, transformFunction: null }, templateElements: { classPropertyName: "templateElements", publicName: "templateElements", isSignal: true, isRequired: false, transformFunction: null }, aiHighlights: { classPropertyName: "aiHighlights", publicName: "aiHighlights", isSignal: true, isRequired: false, transformFunction: null }, aiActive: { classPropertyName: "aiActive", publicName: "aiActive", isSignal: true, isRequired: false, transformFunction: null }, aiActiveSlideIndex: { classPropertyName: "aiActiveSlideIndex", publicName: "aiActiveSlideIndex", isSignal: true, isRequired: false, transformFunction: null }, aiChangeBatch: { classPropertyName: "aiChangeBatch", publicName: "aiChangeBatch", isSignal: true, isRequired: false, transformFunction: null }, aiPickMode: { classPropertyName: "aiPickMode", publicName: "aiPickMode", isSignal: true, isRequired: false, transformFunction: null }, drawTool: { classPropertyName: "drawTool", publicName: "drawTool", isSignal: true, isRequired: false, transformFunction: null }, drawColor: { classPropertyName: "drawColor", publicName: "drawColor", isSignal: true, isRequired: false, transformFunction: null }, drawWidth: { classPropertyName: "drawWidth", publicName: "drawWidth", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { elementSelect: "elementSelect", backgroundClick: "backgroundClick", transformStart: "transformStart", transformUpdate: "transformUpdate", contextMenu: "contextMenu", textEditStart: "textEditStart", textCommit: "textCommit", textInput: "textInput", textCancel: "textCancel", textFormat: "textFormat", rotateUpdate: "rotateUpdate", marqueeSelect: "marqueeSelect", inkStrokeComplete: "inkStrokeComplete", eraserHit: "eraserHit", cellCommit: "cellCommit", tableChange: "tableChange" }, host: { listeners: { "document:pointermove": "onPointerMove($event)", "document:pointerup": "onPointerUp()" } }, providers: [
69280
69906
  CanvasFitService,
69281
69907
  InkDrawingService,
69282
69908
  RulerGuidesService,
@@ -69441,6 +70067,7 @@ class SlideCanvasComponent {
69441
70067
  [style.width.px]="eb.width"
69442
70068
  [style.height.px]="eb.height"
69443
70069
  (pointerdown)="$event.stopPropagation()"
70070
+ (input)="onTextInput($event, eb.id)"
69444
70071
  (blur)="commitText($event, eb.id)"
69445
70072
  (keydown)="onEditorKeydown($event)"
69446
70073
  ></textarea>
@@ -69848,6 +70475,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.8", ngImpor
69848
70475
  [style.width.px]="eb.width"
69849
70476
  [style.height.px]="eb.height"
69850
70477
  (pointerdown)="$event.stopPropagation()"
70478
+ (input)="onTextInput($event, eb.id)"
69851
70479
  (blur)="commitText($event, eb.id)"
69852
70480
  (keydown)="onEditorKeydown($event)"
69853
70481
  ></textarea>
@@ -70081,7 +70709,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.8", ngImpor
70081
70709
  </div>
70082
70710
  </div>
70083
70711
  `, styles: [".pptx-ng-canvas-stage.is-editable{touch-action:none}\n"] }]
70084
- }], ctorParameters: () => [], propDecorators: { slide: [{ type: i0.Input, args: [{ isSignal: true, alias: "slide", required: false }] }], canvasSize: [{ type: i0.Input, args: [{ isSignal: true, alias: "canvasSize", required: true }] }], mediaDataUrls: [{ type: i0.Input, args: [{ isSignal: true, alias: "mediaDataUrls", required: false }] }], zoom: [{ type: i0.Input, args: [{ isSignal: true, alias: "zoom", required: false }] }], editable: [{ type: i0.Input, args: [{ isSignal: true, alias: "editable", 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 }] }], snapToShape: [{ type: i0.Input, args: [{ isSignal: true, alias: "snapToShape", required: false }] }], guideCommand: [{ type: i0.Input, args: [{ isSignal: true, alias: "guideCommand", required: false }] }], spellCheck: [{ type: i0.Input, args: [{ isSignal: true, alias: "spellCheck", required: false }] }], snapToGuides: [{ type: i0.Input, args: [{ isSignal: true, alias: "snapToGuides", required: false }] }], autoFit: [{ type: i0.Input, args: [{ isSignal: true, alias: "autoFit", required: false }] }], interactive: [{ type: i0.Input, args: [{ isSignal: true, alias: "interactive", required: false }] }], presenting: [{ type: i0.Input, args: [{ isSignal: true, alias: "presenting", required: false }] }], selectedIds: [{ type: i0.Input, args: [{ isSignal: true, alias: "selectedIds", required: false }] }], editingId: [{ type: i0.Input, args: [{ isSignal: true, alias: "editingId", required: false }] }], editTemplateMode: [{ type: i0.Input, args: [{ isSignal: true, alias: "editTemplateMode", required: false }] }], templateElements: [{ type: i0.Input, args: [{ isSignal: true, alias: "templateElements", required: false }] }], aiHighlights: [{ type: i0.Input, args: [{ isSignal: true, alias: "aiHighlights", required: false }] }], aiActive: [{ type: i0.Input, args: [{ isSignal: true, alias: "aiActive", required: false }] }], aiActiveSlideIndex: [{ type: i0.Input, args: [{ isSignal: true, alias: "aiActiveSlideIndex", required: false }] }], aiChangeBatch: [{ type: i0.Input, args: [{ isSignal: true, alias: "aiChangeBatch", required: false }] }], aiPickMode: [{ type: i0.Input, args: [{ isSignal: true, alias: "aiPickMode", required: false }] }], drawTool: [{ type: i0.Input, args: [{ isSignal: true, alias: "drawTool", required: false }] }], drawColor: [{ type: i0.Input, args: [{ isSignal: true, alias: "drawColor", required: false }] }], drawWidth: [{ type: i0.Input, args: [{ isSignal: true, alias: "drawWidth", required: false }] }], elementSelect: [{ type: i0.Output, args: ["elementSelect"] }], backgroundClick: [{ type: i0.Output, args: ["backgroundClick"] }], transformStart: [{ type: i0.Output, args: ["transformStart"] }], transformUpdate: [{ type: i0.Output, args: ["transformUpdate"] }], contextMenu: [{ type: i0.Output, args: ["contextMenu"] }], textEditStart: [{ type: i0.Output, args: ["textEditStart"] }], textCommit: [{ type: i0.Output, args: ["textCommit"] }], textCancel: [{ type: i0.Output, args: ["textCancel"] }], textFormat: [{ type: i0.Output, args: ["textFormat"] }], rotateUpdate: [{ type: i0.Output, args: ["rotateUpdate"] }], marqueeSelect: [{ type: i0.Output, args: ["marqueeSelect"] }], inkStrokeComplete: [{ type: i0.Output, args: ["inkStrokeComplete"] }], eraserHit: [{ type: i0.Output, args: ["eraserHit"] }], cellCommit: [{ type: i0.Output, args: ["cellCommit"] }], tableChange: [{ type: i0.Output, args: ["tableChange"] }], textEditor: [{ type: i0.ViewChild, args: ['textEditor', { isSignal: true }] }], stageRef: [{ type: i0.ViewChild, args: ['stage', { isSignal: true }] }], viewportRef: [{ type: i0.ViewChild, args: ['viewport', { isSignal: true }] }], onPointerMove: [{
70712
+ }], ctorParameters: () => [], propDecorators: { slide: [{ type: i0.Input, args: [{ isSignal: true, alias: "slide", required: false }] }], canvasSize: [{ type: i0.Input, args: [{ isSignal: true, alias: "canvasSize", required: true }] }], mediaDataUrls: [{ type: i0.Input, args: [{ isSignal: true, alias: "mediaDataUrls", required: false }] }], zoom: [{ type: i0.Input, args: [{ isSignal: true, alias: "zoom", required: false }] }], editable: [{ type: i0.Input, args: [{ isSignal: true, alias: "editable", 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 }] }], snapToShape: [{ type: i0.Input, args: [{ isSignal: true, alias: "snapToShape", required: false }] }], guideCommand: [{ type: i0.Input, args: [{ isSignal: true, alias: "guideCommand", required: false }] }], spellCheck: [{ type: i0.Input, args: [{ isSignal: true, alias: "spellCheck", required: false }] }], snapToGuides: [{ type: i0.Input, args: [{ isSignal: true, alias: "snapToGuides", required: false }] }], autoFit: [{ type: i0.Input, args: [{ isSignal: true, alias: "autoFit", required: false }] }], interactive: [{ type: i0.Input, args: [{ isSignal: true, alias: "interactive", required: false }] }], presenting: [{ type: i0.Input, args: [{ isSignal: true, alias: "presenting", required: false }] }], selectedIds: [{ type: i0.Input, args: [{ isSignal: true, alias: "selectedIds", required: false }] }], editingId: [{ type: i0.Input, args: [{ isSignal: true, alias: "editingId", required: false }] }], editTemplateMode: [{ type: i0.Input, args: [{ isSignal: true, alias: "editTemplateMode", required: false }] }], templateElements: [{ type: i0.Input, args: [{ isSignal: true, alias: "templateElements", required: false }] }], aiHighlights: [{ type: i0.Input, args: [{ isSignal: true, alias: "aiHighlights", required: false }] }], aiActive: [{ type: i0.Input, args: [{ isSignal: true, alias: "aiActive", required: false }] }], aiActiveSlideIndex: [{ type: i0.Input, args: [{ isSignal: true, alias: "aiActiveSlideIndex", required: false }] }], aiChangeBatch: [{ type: i0.Input, args: [{ isSignal: true, alias: "aiChangeBatch", required: false }] }], aiPickMode: [{ type: i0.Input, args: [{ isSignal: true, alias: "aiPickMode", required: false }] }], drawTool: [{ type: i0.Input, args: [{ isSignal: true, alias: "drawTool", required: false }] }], drawColor: [{ type: i0.Input, args: [{ isSignal: true, alias: "drawColor", required: false }] }], drawWidth: [{ type: i0.Input, args: [{ isSignal: true, alias: "drawWidth", required: false }] }], elementSelect: [{ type: i0.Output, args: ["elementSelect"] }], backgroundClick: [{ type: i0.Output, args: ["backgroundClick"] }], transformStart: [{ type: i0.Output, args: ["transformStart"] }], transformUpdate: [{ type: i0.Output, args: ["transformUpdate"] }], contextMenu: [{ type: i0.Output, args: ["contextMenu"] }], textEditStart: [{ type: i0.Output, args: ["textEditStart"] }], textCommit: [{ type: i0.Output, args: ["textCommit"] }], textInput: [{ type: i0.Output, args: ["textInput"] }], textCancel: [{ type: i0.Output, args: ["textCancel"] }], textFormat: [{ type: i0.Output, args: ["textFormat"] }], rotateUpdate: [{ type: i0.Output, args: ["rotateUpdate"] }], marqueeSelect: [{ type: i0.Output, args: ["marqueeSelect"] }], inkStrokeComplete: [{ type: i0.Output, args: ["inkStrokeComplete"] }], eraserHit: [{ type: i0.Output, args: ["eraserHit"] }], cellCommit: [{ type: i0.Output, args: ["cellCommit"] }], tableChange: [{ type: i0.Output, args: ["tableChange"] }], textEditor: [{ type: i0.ViewChild, args: ['textEditor', { isSignal: true }] }], stageRef: [{ type: i0.ViewChild, args: ['stage', { isSignal: true }] }], viewportRef: [{ type: i0.ViewChild, args: ['viewport', { isSignal: true }] }], onPointerMove: [{
70085
70713
  type: HostListener,
70086
70714
  args: ['document:pointermove', ['$event']]
70087
70715
  }], onPointerUp: [{
@@ -70221,7 +70849,7 @@ class MasterViewCanvasComponent {
70221
70849
  <p class="empty">No master is available.</p>
70222
70850
  }
70223
70851
  </main>
70224
- `, isInline: true, styles: [".master-canvas{display:flex;min-width:0;flex:1;overflow:hidden;background:var(--pptx-background, #11111b)}pptx-slide-canvas{display:flex;min-width:0;flex:1}.empty{margin:auto;color:var(--pptx-muted-foreground, #a5a5b5)}\n"], dependencies: [{ kind: "component", type: SlideCanvasComponent, selector: "pptx-slide-canvas", inputs: ["slide", "canvasSize", "mediaDataUrls", "zoom", "editable", "showGrid", "showRulers", "showGuides", "snapToGrid", "snapToShape", "guideCommand", "spellCheck", "snapToGuides", "autoFit", "interactive", "presenting", "selectedIds", "editingId", "editTemplateMode", "templateElements", "aiHighlights", "aiActive", "aiActiveSlideIndex", "aiChangeBatch", "aiPickMode", "drawTool", "drawColor", "drawWidth"], outputs: ["elementSelect", "backgroundClick", "transformStart", "transformUpdate", "contextMenu", "textEditStart", "textCommit", "textCancel", "textFormat", "rotateUpdate", "marqueeSelect", "inkStrokeComplete", "eraserHit", "cellCommit", "tableChange"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
70852
+ `, isInline: true, styles: [".master-canvas{display:flex;min-width:0;flex:1;overflow:hidden;background:var(--pptx-background, #11111b)}pptx-slide-canvas{display:flex;min-width:0;flex:1}.empty{margin:auto;color:var(--pptx-muted-foreground, #a5a5b5)}\n"], dependencies: [{ kind: "component", type: SlideCanvasComponent, selector: "pptx-slide-canvas", inputs: ["slide", "canvasSize", "mediaDataUrls", "zoom", "editable", "showGrid", "showRulers", "showGuides", "snapToGrid", "snapToShape", "guideCommand", "spellCheck", "snapToGuides", "autoFit", "interactive", "presenting", "selectedIds", "editingId", "editTemplateMode", "templateElements", "aiHighlights", "aiActive", "aiActiveSlideIndex", "aiChangeBatch", "aiPickMode", "drawTool", "drawColor", "drawWidth"], outputs: ["elementSelect", "backgroundClick", "transformStart", "transformUpdate", "contextMenu", "textEditStart", "textCommit", "textInput", "textCancel", "textFormat", "rotateUpdate", "marqueeSelect", "inkStrokeComplete", "eraserHit", "cellCommit", "tableChange"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
70225
70853
  }
70226
70854
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: MasterViewCanvasComponent, decorators: [{
70227
70855
  type: Component,
@@ -70417,17 +71045,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.8", ngImpor
70417
71045
  * framework-neutral accessibility contract the e2e specs assert against
70418
71046
  * (`getByRole('navigation', { name: 'Editor actions' })`).
70419
71047
  *
70420
- * Inputs
70421
- * slideCount : total number of slides (gates Slides/Format/Insert)
70422
- * commentCount : number of comments on the active slide (badge)
70423
- * activeSheet : currently-active sheet, for highlighting the bar button
70424
- *
70425
- * Outputs
70426
- * openSlides : user tapped the Slides button
70427
- * insert : user tapped the Insert button
70428
- * openFormat : user tapped the Format button
70429
- * openComments : user tapped the Comments button
70430
- * notes : user tapped the Notes button
71048
+ * Icons and colours come from the same Lucide glyphs and `--pptx-*` theme
71049
+ * tokens React uses. Each input/output is documented on its declaration below.
70431
71050
  */
70432
71051
  class MobileBottomBarComponent {
70433
71052
  // ── Inputs ────────────────────────────────────────────────────────────────
@@ -70460,8 +71079,6 @@ class MobileBottomBarComponent {
70460
71079
  {
70461
71080
  key: 'slides',
70462
71081
  labelKey: 'pptx.sections.slides',
70463
- // Layers icon
70464
- svgPath: 'M12 2L2 7l10 5 10-5-10-5z M2 17l10 5 10-5 M2 12l10 5 10-5',
70465
71082
  disabled: noSlides,
70466
71083
  active: active === 'slides',
70467
71084
  emit: () => this.openSlides.emit(),
@@ -70469,8 +71086,6 @@ class MobileBottomBarComponent {
70469
71086
  {
70470
71087
  key: 'insert',
70471
71088
  labelKey: 'pptx.editorToolbar.insert',
70472
- // Plus icon
70473
- svgPath: 'M12 5v14 M5 12h14',
70474
71089
  disabled: noSlides,
70475
71090
  active: false,
70476
71091
  emit: () => this.insert.emit(),
@@ -70478,8 +71093,6 @@ class MobileBottomBarComponent {
70478
71093
  {
70479
71094
  key: 'inspector',
70480
71095
  labelKey: 'pptx.arrange.format',
70481
- // Sliders icon
70482
- svgPath: 'M4 21v-7 M4 10V3 M12 21v-9 M12 8V3 M20 21v-5 M20 12V3 M1 14h6 M9 8h6 M17 16h6',
70483
71096
  disabled: noSlides,
70484
71097
  active: active === 'inspector',
70485
71098
  emit: () => this.openFormat.emit(),
@@ -70487,8 +71100,6 @@ class MobileBottomBarComponent {
70487
71100
  {
70488
71101
  key: 'comments',
70489
71102
  labelKey: 'pptx.toolbar.comments',
70490
- // Message-square icon
70491
- svgPath: 'M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z',
70492
71103
  disabled: noSlides,
70493
71104
  active: active === 'comments',
70494
71105
  badge: this.commentCount(),
@@ -70498,8 +71109,6 @@ class MobileBottomBarComponent {
70498
71109
  key: 'notes',
70499
71110
  labelKey: 'pptx.notes.title',
70500
71111
  ariaLabelKey: 'pptx.statusBar.toggleNotes',
70501
- // Note / document-text icon
70502
- svgPath: 'M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z M14 2v6h6 M8 13h8 M8 17h5',
70503
71112
  disabled: noSlides,
70504
71113
  active: active === 'notes',
70505
71114
  emit: () => this.notes.emit(),
@@ -70520,19 +71129,23 @@ class MobileBottomBarComponent {
70520
71129
  [disabled]="action.disabled"
70521
71130
  (click)="action.emit()"
70522
71131
  >
70523
- <svg
70524
- class="pptx-ng-mbar-icon"
70525
- xmlns="http://www.w3.org/2000/svg"
70526
- viewBox="0 0 24 24"
70527
- fill="none"
70528
- stroke="currentColor"
70529
- stroke-width="2"
70530
- stroke-linecap="round"
70531
- stroke-linejoin="round"
70532
- aria-hidden="true"
70533
- >
70534
- <path [attr.d]="action.svgPath" />
70535
- </svg>
71132
+ @switch (action.key) {
71133
+ @case ('slides') {
71134
+ <svg lucideLayers class="pptx-ng-mbar-icon" aria-hidden="true"></svg>
71135
+ }
71136
+ @case ('insert') {
71137
+ <svg lucidePlus class="pptx-ng-mbar-icon" aria-hidden="true"></svg>
71138
+ }
71139
+ @case ('inspector') {
71140
+ <svg lucideSettings2 class="pptx-ng-mbar-icon" aria-hidden="true"></svg>
71141
+ }
71142
+ @case ('comments') {
71143
+ <svg lucideMessageSquare class="pptx-ng-mbar-icon" aria-hidden="true"></svg>
71144
+ }
71145
+ @case ('notes') {
71146
+ <svg lucideStickyNote class="pptx-ng-mbar-icon" aria-hidden="true"></svg>
71147
+ }
71148
+ }
70536
71149
  <span class="pptx-ng-mbar-label">{{ action.labelKey | translate }}</span>
70537
71150
  @if (action.badge && action.badge > 0) {
70538
71151
  <span class="pptx-ng-mbar-badge" aria-hidden="true">
@@ -70545,11 +71158,18 @@ class MobileBottomBarComponent {
70545
71158
  </button>
70546
71159
  }
70547
71160
  </nav>
70548
- `, isInline: true, styles: [":host{display:block}.pptx-ng-mbar{display:flex;align-items:stretch;justify-content:space-around;background:#1a1a1aeb;border-top:1px solid rgba(255,255,255,.1);backdrop-filter:blur(12px);-webkit-backdrop-filter:blur(12px);padding-bottom:max(env(safe-area-inset-bottom,0px),0px)}.pptx-ng-mbar-btn{position:relative;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:.125rem;flex:1;min-height:56px;padding:.375rem .25rem;border:none;background:transparent;color:#ffffff8c;font-size:.625rem;font-weight:500;cursor:pointer;touch-action:manipulation;transition:color .12s,transform .08s;-webkit-tap-highlight-color:transparent}.pptx-ng-mbar-btn:active:not([disabled]){transform:scale(.92)}.pptx-ng-mbar-btn.is-active{color:#3b82f6}.pptx-ng-mbar-btn:hover:not([disabled]):not(.is-active){color:#e5e5e5}.pptx-ng-mbar-btn[disabled]{opacity:.35;cursor:not-allowed}.pptx-ng-mbar-icon{width:1.25rem;height:1.25rem;flex-shrink:0}.pptx-ng-mbar-label{line-height:1;white-space:nowrap}.pptx-ng-mbar-badge{position:absolute;top:.25rem;right:calc(50% - 1.25rem);display:flex;align-items:center;justify-content:center;min-width:1rem;height:1rem;padding:0 .25rem;border-radius:9999px;background:#ef4444;color:#fff;font-size:.5625rem;font-weight:600;line-height:1}.pptx-ng-mbar-indicator{position:absolute;top:0;left:50%;transform:translate(-50%);width:2rem;height:.1875rem;border-radius:9999px;background:#3b82f6}\n"], dependencies: [{ kind: "pipe", type: TranslatePipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
71161
+ `, isInline: true, styles: [":host{display:block}.pptx-ng-mbar{display:flex;align-items:stretch;justify-content:space-around;background:color-mix(in srgb,var(--pptx-secondary, #1f2937) 80%,transparent);border-top:1px solid var(--pptx-border, #374151);padding-bottom:max(env(safe-area-inset-bottom,0px),0px)}@supports ((backdrop-filter: blur(12px)) or (-webkit-backdrop-filter: blur(12px))){.pptx-ng-mbar{background:color-mix(in srgb,var(--pptx-secondary, #1f2937) 60%,transparent);backdrop-filter:blur(12px);-webkit-backdrop-filter:blur(12px)}}.pptx-ng-mbar-btn{position:relative;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:.125rem;flex:1;min-height:56px;padding:.375rem .25rem;border:none;background:transparent;color:var(--pptx-muted-foreground, #9ca3af);font-size:.625rem;font-weight:500;cursor:pointer;touch-action:manipulation;transition:color .12s,transform .08s;-webkit-tap-highlight-color:transparent}.pptx-ng-mbar-btn:active:not([disabled]){transform:scale(.92)}.pptx-ng-mbar-btn.is-active{color:var(--pptx-primary, #6366f1)}.pptx-ng-mbar-btn:hover:not([disabled]):not(.is-active){color:var(--pptx-foreground, #f3f4f6)}.pptx-ng-mbar-btn[disabled]{opacity:.35;cursor:not-allowed}.pptx-ng-mbar-icon{width:1.25rem;height:1.25rem;flex-shrink:0}.pptx-ng-mbar-label{line-height:1;white-space:nowrap}.pptx-ng-mbar-badge{position:absolute;top:.25rem;right:calc(50% - 1.25rem);display:flex;align-items:center;justify-content:center;min-width:1rem;height:1rem;padding:0 .25rem;border-radius:9999px;background:var(--pptx-primary, #6366f1);color:var(--pptx-primary-foreground, #ffffff);font-size:.5625rem;font-weight:600;line-height:1}.pptx-ng-mbar-indicator{position:absolute;top:0;left:50%;transform:translate(-50%);width:2rem;height:.1875rem;border-radius:9999px;background:var(--pptx-primary, #6366f1)}\n"], dependencies: [{ kind: "component", type: LucideLayers, selector: "svg[lucideLayers], svg[lucideLayers3]" }, { kind: "component", type: LucideMessageSquare, selector: "svg[lucideMessageSquare]" }, { kind: "component", type: LucidePlus, selector: "svg[lucidePlus]" }, { kind: "component", type: LucideSettings2, selector: "svg[lucideSettings2]" }, { kind: "component", type: LucideStickyNote, selector: "svg[lucideStickyNote]" }, { kind: "pipe", type: TranslatePipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
70549
71162
  }
70550
71163
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: MobileBottomBarComponent, decorators: [{
70551
71164
  type: Component,
70552
- args: [{ selector: 'pptx-mobile-bottom-bar', standalone: true, imports: [TranslatePipe], changeDetection: ChangeDetectionStrategy.OnPush, template: `
71165
+ args: [{ selector: 'pptx-mobile-bottom-bar', standalone: true, imports: [
71166
+ LucideLayers,
71167
+ LucideMessageSquare,
71168
+ LucidePlus,
71169
+ LucideSettings2,
71170
+ LucideStickyNote,
71171
+ TranslatePipe,
71172
+ ], changeDetection: ChangeDetectionStrategy.OnPush, template: `
70553
71173
  <nav class="pptx-ng-mbar" [attr.aria-label]="'pptx.mobileBar.ariaLabel' | translate">
70554
71174
  @for (action of actions(); track action.key) {
70555
71175
  <button
@@ -70561,19 +71181,23 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.8", ngImpor
70561
71181
  [disabled]="action.disabled"
70562
71182
  (click)="action.emit()"
70563
71183
  >
70564
- <svg
70565
- class="pptx-ng-mbar-icon"
70566
- xmlns="http://www.w3.org/2000/svg"
70567
- viewBox="0 0 24 24"
70568
- fill="none"
70569
- stroke="currentColor"
70570
- stroke-width="2"
70571
- stroke-linecap="round"
70572
- stroke-linejoin="round"
70573
- aria-hidden="true"
70574
- >
70575
- <path [attr.d]="action.svgPath" />
70576
- </svg>
71184
+ @switch (action.key) {
71185
+ @case ('slides') {
71186
+ <svg lucideLayers class="pptx-ng-mbar-icon" aria-hidden="true"></svg>
71187
+ }
71188
+ @case ('insert') {
71189
+ <svg lucidePlus class="pptx-ng-mbar-icon" aria-hidden="true"></svg>
71190
+ }
71191
+ @case ('inspector') {
71192
+ <svg lucideSettings2 class="pptx-ng-mbar-icon" aria-hidden="true"></svg>
71193
+ }
71194
+ @case ('comments') {
71195
+ <svg lucideMessageSquare class="pptx-ng-mbar-icon" aria-hidden="true"></svg>
71196
+ }
71197
+ @case ('notes') {
71198
+ <svg lucideStickyNote class="pptx-ng-mbar-icon" aria-hidden="true"></svg>
71199
+ }
71200
+ }
70577
71201
  <span class="pptx-ng-mbar-label">{{ action.labelKey | translate }}</span>
70578
71202
  @if (action.badge && action.badge > 0) {
70579
71203
  <span class="pptx-ng-mbar-badge" aria-hidden="true">
@@ -70586,7 +71210,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.8", ngImpor
70586
71210
  </button>
70587
71211
  }
70588
71212
  </nav>
70589
- `, styles: [":host{display:block}.pptx-ng-mbar{display:flex;align-items:stretch;justify-content:space-around;background:#1a1a1aeb;border-top:1px solid rgba(255,255,255,.1);backdrop-filter:blur(12px);-webkit-backdrop-filter:blur(12px);padding-bottom:max(env(safe-area-inset-bottom,0px),0px)}.pptx-ng-mbar-btn{position:relative;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:.125rem;flex:1;min-height:56px;padding:.375rem .25rem;border:none;background:transparent;color:#ffffff8c;font-size:.625rem;font-weight:500;cursor:pointer;touch-action:manipulation;transition:color .12s,transform .08s;-webkit-tap-highlight-color:transparent}.pptx-ng-mbar-btn:active:not([disabled]){transform:scale(.92)}.pptx-ng-mbar-btn.is-active{color:#3b82f6}.pptx-ng-mbar-btn:hover:not([disabled]):not(.is-active){color:#e5e5e5}.pptx-ng-mbar-btn[disabled]{opacity:.35;cursor:not-allowed}.pptx-ng-mbar-icon{width:1.25rem;height:1.25rem;flex-shrink:0}.pptx-ng-mbar-label{line-height:1;white-space:nowrap}.pptx-ng-mbar-badge{position:absolute;top:.25rem;right:calc(50% - 1.25rem);display:flex;align-items:center;justify-content:center;min-width:1rem;height:1rem;padding:0 .25rem;border-radius:9999px;background:#ef4444;color:#fff;font-size:.5625rem;font-weight:600;line-height:1}.pptx-ng-mbar-indicator{position:absolute;top:0;left:50%;transform:translate(-50%);width:2rem;height:.1875rem;border-radius:9999px;background:#3b82f6}\n"] }]
71213
+ `, styles: [":host{display:block}.pptx-ng-mbar{display:flex;align-items:stretch;justify-content:space-around;background:color-mix(in srgb,var(--pptx-secondary, #1f2937) 80%,transparent);border-top:1px solid var(--pptx-border, #374151);padding-bottom:max(env(safe-area-inset-bottom,0px),0px)}@supports ((backdrop-filter: blur(12px)) or (-webkit-backdrop-filter: blur(12px))){.pptx-ng-mbar{background:color-mix(in srgb,var(--pptx-secondary, #1f2937) 60%,transparent);backdrop-filter:blur(12px);-webkit-backdrop-filter:blur(12px)}}.pptx-ng-mbar-btn{position:relative;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:.125rem;flex:1;min-height:56px;padding:.375rem .25rem;border:none;background:transparent;color:var(--pptx-muted-foreground, #9ca3af);font-size:.625rem;font-weight:500;cursor:pointer;touch-action:manipulation;transition:color .12s,transform .08s;-webkit-tap-highlight-color:transparent}.pptx-ng-mbar-btn:active:not([disabled]){transform:scale(.92)}.pptx-ng-mbar-btn.is-active{color:var(--pptx-primary, #6366f1)}.pptx-ng-mbar-btn:hover:not([disabled]):not(.is-active){color:var(--pptx-foreground, #f3f4f6)}.pptx-ng-mbar-btn[disabled]{opacity:.35;cursor:not-allowed}.pptx-ng-mbar-icon{width:1.25rem;height:1.25rem;flex-shrink:0}.pptx-ng-mbar-label{line-height:1;white-space:nowrap}.pptx-ng-mbar-badge{position:absolute;top:.25rem;right:calc(50% - 1.25rem);display:flex;align-items:center;justify-content:center;min-width:1rem;height:1rem;padding:0 .25rem;border-radius:9999px;background:var(--pptx-primary, #6366f1);color:var(--pptx-primary-foreground, #ffffff);font-size:.5625rem;font-weight:600;line-height:1}.pptx-ng-mbar-indicator{position:absolute;top:0;left:50%;transform:translate(-50%);width:2rem;height:.1875rem;border-radius:9999px;background:var(--pptx-primary, #6366f1)}\n"] }]
70590
71214
  }], propDecorators: { slideCount: [{ type: i0.Input, args: [{ isSignal: true, alias: "slideCount", required: false }] }], commentCount: [{ type: i0.Input, args: [{ isSignal: true, alias: "commentCount", required: false }] }], activeSheet: [{ type: i0.Input, args: [{ isSignal: true, alias: "activeSheet", required: false }] }], openSlides: [{ type: i0.Output, args: ["openSlides"] }], insert: [{ type: i0.Output, args: ["insert"] }], openFormat: [{ type: i0.Output, args: ["openFormat"] }], openComments: [{ type: i0.Output, args: ["openComments"] }], notes: [{ type: i0.Output, args: ["notes"] }] } });
70591
71215
 
70592
71216
  /**
@@ -71504,7 +72128,7 @@ class MobilePresenterViewComponent {
71504
72128
  } @else {
71505
72129
  <div class="pptx-ng-mpresenter-empty">{{ 'pptx.presenter.noSlides' | translate }}</div>
71506
72130
  }
71507
- `, isInline: true, styles: [":host{position:absolute;inset:0;z-index:50;display:flex;flex-direction:column;background:#0b0b0c;color:#f5f5f5;font-family:system-ui,sans-serif;padding-top:env(safe-area-inset-top,0px);padding-bottom:env(safe-area-inset-bottom,0px);padding-left:env(safe-area-inset-left,0px);padding-right:env(safe-area-inset-right,0px)}.pptx-ng-mpresenter-header,.pptx-ng-mpresenter-next,.pptx-ng-mpresenter-ctl{display:flex;align-items:center;gap:.75rem;padding:.5rem 1rem}.pptx-ng-mpresenter-header{justify-content:space-between;border-bottom:1px solid rgba(255,255,255,.08)}.pptx-ng-mpresenter-label{font-size:.625rem;text-transform:uppercase;letter-spacing:.06em;color:#ffffff8c}.pptx-ng-mpresenter-elapsed{font-family:ui-monospace,monospace;font-variant-numeric:tabular-nums;font-size:1.125rem;color:#6ea8fe}.pptx-ng-mpresenter-counter{font-family:ui-monospace,monospace;font-variant-numeric:tabular-nums;font-size:.875rem}.pptx-ng-mpresenter-exit{display:inline-flex;align-items:center;justify-content:center;width:44px;height:44px;min-width:44px;min-height:44px;border:none;border-radius:6px;background:transparent;color:#ffffffbf;cursor:pointer;font-size:1.25rem;line-height:1}.pptx-ng-mpresenter-exit:hover{background:#ffffff1f;color:#fff}.pptx-ng-mpresenter-main{display:flex;align-items:center;justify-content:center;background:#000;padding:.75rem}.pptx-ng-mpresenter-main-stage{width:100%;max-width:640px}.pptx-ng-mpresenter-next{border-bottom:1px solid rgba(255,255,255,.08)}.pptx-ng-mpresenter-thumb{flex:0 0 auto;overflow:hidden;border:1px solid rgba(255,255,255,.15);border-radius:4px}.pptx-ng-mpresenter-next-empty{display:flex;flex:1 1 auto;align-items:center;justify-content:center;height:3rem;border:1px solid rgba(255,255,255,.15);border-radius:4px;background:#ffffff0a;font-size:.625rem;font-style:italic;color:#ffffff80}.pptx-ng-mpresenter-notes{flex:1 1 auto;display:flex;flex-direction:column;min-height:0;padding:.5rem 1rem}.pptx-ng-mpresenter-notes-body{flex:1 1 auto;overflow-y:auto;margin-top:.25rem;border:1px solid rgba(255,255,255,.15);border-radius:6px;background:#ffffff0a;padding:.5rem .75rem;white-space:pre-wrap;line-height:1.5;font-size:15px}.pptx-ng-mpresenter-notes-empty{font-style:italic;color:#ffffff80}.pptx-ng-mpresenter-ctl{justify-content:space-between;border-top:1px solid rgba(255,255,255,.08)}.pptx-ng-mpresenter-navbtn{flex:1 1 0;display:inline-flex;align-items:center;justify-content:center;gap:.375rem;height:44px;border:none;border-radius:6px;background:#ffffff14;color:#f5f5f5;cursor:pointer;font-size:.9rem}.pptx-ng-mpresenter-navbtn:hover:not(:disabled){background:#ffffff29}.pptx-ng-mpresenter-navbtn:disabled{opacity:.4;cursor:not-allowed}.pptx-ng-mpresenter-empty{position:absolute;inset:0;display:flex;align-items:center;justify-content:center;color:#fff9}\n"], dependencies: [{ 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", "snapToShape", "guideCommand", "spellCheck", "snapToGuides", "autoFit", "interactive", "presenting", "selectedIds", "editingId", "editTemplateMode", "templateElements", "aiHighlights", "aiActive", "aiActiveSlideIndex", "aiChangeBatch", "aiPickMode", "drawTool", "drawColor", "drawWidth"], outputs: ["elementSelect", "backgroundClick", "transformStart", "transformUpdate", "contextMenu", "textEditStart", "textCommit", "textCancel", "textFormat", "rotateUpdate", "marqueeSelect", "inkStrokeComplete", "eraserHit", "cellCommit", "tableChange"] }, { kind: "pipe", type: TranslatePipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
72131
+ `, isInline: true, styles: [":host{position:absolute;inset:0;z-index:50;display:flex;flex-direction:column;background:#0b0b0c;color:#f5f5f5;font-family:system-ui,sans-serif;padding-top:env(safe-area-inset-top,0px);padding-bottom:env(safe-area-inset-bottom,0px);padding-left:env(safe-area-inset-left,0px);padding-right:env(safe-area-inset-right,0px)}.pptx-ng-mpresenter-header,.pptx-ng-mpresenter-next,.pptx-ng-mpresenter-ctl{display:flex;align-items:center;gap:.75rem;padding:.5rem 1rem}.pptx-ng-mpresenter-header{justify-content:space-between;border-bottom:1px solid rgba(255,255,255,.08)}.pptx-ng-mpresenter-label{font-size:.625rem;text-transform:uppercase;letter-spacing:.06em;color:#ffffff8c}.pptx-ng-mpresenter-elapsed{font-family:ui-monospace,monospace;font-variant-numeric:tabular-nums;font-size:1.125rem;color:#6ea8fe}.pptx-ng-mpresenter-counter{font-family:ui-monospace,monospace;font-variant-numeric:tabular-nums;font-size:.875rem}.pptx-ng-mpresenter-exit{display:inline-flex;align-items:center;justify-content:center;width:44px;height:44px;min-width:44px;min-height:44px;border:none;border-radius:6px;background:transparent;color:#ffffffbf;cursor:pointer;font-size:1.25rem;line-height:1}.pptx-ng-mpresenter-exit:hover{background:#ffffff1f;color:#fff}.pptx-ng-mpresenter-main{display:flex;align-items:center;justify-content:center;background:#000;padding:.75rem}.pptx-ng-mpresenter-main-stage{width:100%;max-width:640px}.pptx-ng-mpresenter-next{border-bottom:1px solid rgba(255,255,255,.08)}.pptx-ng-mpresenter-thumb{flex:0 0 auto;overflow:hidden;border:1px solid rgba(255,255,255,.15);border-radius:4px}.pptx-ng-mpresenter-next-empty{display:flex;flex:1 1 auto;align-items:center;justify-content:center;height:3rem;border:1px solid rgba(255,255,255,.15);border-radius:4px;background:#ffffff0a;font-size:.625rem;font-style:italic;color:#ffffff80}.pptx-ng-mpresenter-notes{flex:1 1 auto;display:flex;flex-direction:column;min-height:0;padding:.5rem 1rem}.pptx-ng-mpresenter-notes-body{flex:1 1 auto;overflow-y:auto;margin-top:.25rem;border:1px solid rgba(255,255,255,.15);border-radius:6px;background:#ffffff0a;padding:.5rem .75rem;white-space:pre-wrap;line-height:1.5;font-size:15px}.pptx-ng-mpresenter-notes-empty{font-style:italic;color:#ffffff80}.pptx-ng-mpresenter-ctl{justify-content:space-between;border-top:1px solid rgba(255,255,255,.08)}.pptx-ng-mpresenter-navbtn{flex:1 1 0;display:inline-flex;align-items:center;justify-content:center;gap:.375rem;height:44px;border:none;border-radius:6px;background:#ffffff14;color:#f5f5f5;cursor:pointer;font-size:.9rem}.pptx-ng-mpresenter-navbtn:hover:not(:disabled){background:#ffffff29}.pptx-ng-mpresenter-navbtn:disabled{opacity:.4;cursor:not-allowed}.pptx-ng-mpresenter-empty{position:absolute;inset:0;display:flex;align-items:center;justify-content:center;color:#fff9}\n"], dependencies: [{ 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", "snapToShape", "guideCommand", "spellCheck", "snapToGuides", "autoFit", "interactive", "presenting", "selectedIds", "editingId", "editTemplateMode", "templateElements", "aiHighlights", "aiActive", "aiActiveSlideIndex", "aiChangeBatch", "aiPickMode", "drawTool", "drawColor", "drawWidth"], outputs: ["elementSelect", "backgroundClick", "transformStart", "transformUpdate", "contextMenu", "textEditStart", "textCommit", "textInput", "textCancel", "textFormat", "rotateUpdate", "marqueeSelect", "inkStrokeComplete", "eraserHit", "cellCommit", "tableChange"] }, { kind: "pipe", type: TranslatePipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
71508
72132
  }
71509
72133
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: MobilePresenterViewComponent, decorators: [{
71510
72134
  type: Component,
@@ -71780,7 +72404,7 @@ class MobileSlidesSheetComponent {
71780
72404
  }
71781
72405
  </div>
71782
72406
  </pptx-mobile-sheet>
71783
- `, isInline: true, styles: [":host{display:contents}.pptx-ng-mslides-count{margin:0;padding:.5rem 1rem .25rem;font-size:.75rem;color:#ffffff73}.pptx-ng-mslides-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(160px,1fr));gap:.75rem;padding:.75rem .875rem 1.5rem}.pptx-ng-mslides-cell{display:flex;flex-direction:column;align-items:center;gap:.375rem;padding:.375rem;border:2px solid transparent;border-radius:.5rem;background:transparent;color:inherit;cursor:pointer;touch-action:manipulation;-webkit-tap-highlight-color:transparent;transition:border-color .12s,background .12s}.pptx-ng-mslides-cell:hover{background:#ffffff0d;border-color:#ffffff26}.pptx-ng-mslides-cell:active{background:#ffffff1a}.pptx-ng-mslides-cell.is-active{border-color:#3b82f6;background:#3b82f61a}.pptx-ng-mslides-clip{overflow:hidden;border-radius:.25rem;width:100%}.pptx-ng-mslides-clip ::ng-deep .pptx-ng-canvas-wrapper{margin:0!important}.pptx-ng-mslides-num{display:block;font-size:.625rem;color:#fff6;line-height:1.4;-webkit-user-select:none;user-select:none}\n"], dependencies: [{ kind: "directive", type: NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }, { kind: "component", type: MobileSheetComponent, selector: "pptx-mobile-sheet", inputs: ["open", "title", "heightFraction", "fullScreen"], outputs: ["closed"] }, { kind: "component", type: SlideCanvasComponent, selector: "pptx-slide-canvas", inputs: ["slide", "canvasSize", "mediaDataUrls", "zoom", "editable", "showGrid", "showRulers", "showGuides", "snapToGrid", "snapToShape", "guideCommand", "spellCheck", "snapToGuides", "autoFit", "interactive", "presenting", "selectedIds", "editingId", "editTemplateMode", "templateElements", "aiHighlights", "aiActive", "aiActiveSlideIndex", "aiChangeBatch", "aiPickMode", "drawTool", "drawColor", "drawWidth"], outputs: ["elementSelect", "backgroundClick", "transformStart", "transformUpdate", "contextMenu", "textEditStart", "textCommit", "textCancel", "textFormat", "rotateUpdate", "marqueeSelect", "inkStrokeComplete", "eraserHit", "cellCommit", "tableChange"] }, { kind: "pipe", type: TranslatePipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
72407
+ `, isInline: true, styles: [":host{display:contents}.pptx-ng-mslides-count{margin:0;padding:.5rem 1rem .25rem;font-size:.75rem;color:#ffffff73}.pptx-ng-mslides-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(160px,1fr));gap:.75rem;padding:.75rem .875rem 1.5rem}.pptx-ng-mslides-cell{display:flex;flex-direction:column;align-items:center;gap:.375rem;padding:.375rem;border:2px solid transparent;border-radius:.5rem;background:transparent;color:inherit;cursor:pointer;touch-action:manipulation;-webkit-tap-highlight-color:transparent;transition:border-color .12s,background .12s}.pptx-ng-mslides-cell:hover{background:#ffffff0d;border-color:#ffffff26}.pptx-ng-mslides-cell:active{background:#ffffff1a}.pptx-ng-mslides-cell.is-active{border-color:#3b82f6;background:#3b82f61a}.pptx-ng-mslides-clip{overflow:hidden;border-radius:.25rem;width:100%}.pptx-ng-mslides-clip ::ng-deep .pptx-ng-canvas-wrapper{margin:0!important}.pptx-ng-mslides-num{display:block;font-size:.625rem;color:#fff6;line-height:1.4;-webkit-user-select:none;user-select:none}\n"], dependencies: [{ kind: "directive", type: NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }, { kind: "component", type: MobileSheetComponent, selector: "pptx-mobile-sheet", inputs: ["open", "title", "heightFraction", "fullScreen"], outputs: ["closed"] }, { kind: "component", type: SlideCanvasComponent, selector: "pptx-slide-canvas", inputs: ["slide", "canvasSize", "mediaDataUrls", "zoom", "editable", "showGrid", "showRulers", "showGuides", "snapToGrid", "snapToShape", "guideCommand", "spellCheck", "snapToGuides", "autoFit", "interactive", "presenting", "selectedIds", "editingId", "editTemplateMode", "templateElements", "aiHighlights", "aiActive", "aiActiveSlideIndex", "aiChangeBatch", "aiPickMode", "drawTool", "drawColor", "drawWidth"], outputs: ["elementSelect", "backgroundClick", "transformStart", "transformUpdate", "contextMenu", "textEditStart", "textCommit", "textInput", "textCancel", "textFormat", "rotateUpdate", "marqueeSelect", "inkStrokeComplete", "eraserHit", "cellCommit", "tableChange"] }, { kind: "pipe", type: TranslatePipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
71784
72408
  }
71785
72409
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: MobileSlidesSheetComponent, decorators: [{
71786
72410
  type: Component,
@@ -71852,7 +72476,9 @@ function toolbarVisibility(hiddenActions) {
71852
72476
  * A single compact row that replaces the desktop ribbon below the 768px
71853
72477
  * breakpoint. Renders the essential always-available controls:
71854
72478
  *
71855
- * Menu · Undo · Redo · [spacer] · Present
72479
+ * Menu · Undo · Redo · [spacer] · AI · Save · Present · Share
72480
+ *
72481
+ * The slot order, icons and colours mirror React's MobileToolbar exactly.
71856
72482
  *
71857
72483
  * Section-specific functionality (Insert/Design/Export/etc.) lives in the
71858
72484
  * `MobileMenuSheetComponent` that opens from the Menu button; per-selection
@@ -71862,19 +72488,7 @@ function toolbarVisibility(hiddenActions) {
71862
72488
  * the framework-neutral accessibility contract the e2e specs assert against
71863
72489
  * (`getByRole('toolbar', { name: 'Toolbar' })`).
71864
72490
  *
71865
- * Inputs
71866
- * canUndo : whether the undo action is available
71867
- * canRedo : whether the redo action is available
71868
- * canPresent : whether the Present action should be enabled
71869
- * canEdit : whether editor-only controls (menu/undo/redo) should render
71870
- * menuOpen : whether the mobile menu sheet is currently open
71871
- *
71872
- * Outputs
71873
- * toggleMenu : user tapped the Menu (hamburger) button
71874
- * undo : user tapped Undo
71875
- * redo : user tapped Redo
71876
- * share : user tapped Share (opens the collaboration dialog)
71877
- * present : user tapped Present
72491
+ * Each input/output is documented on its own declaration below.
71878
72492
  */
71879
72493
  class MobileToolbarComponent {
71880
72494
  /** Whether the undo action is available. */
@@ -71933,19 +72547,7 @@ class MobileToolbarComponent {
71933
72547
  [title]="'pptx.mobileToolbar.menu' | translate"
71934
72548
  (click)="toggleMenu.emit()"
71935
72549
  >
71936
- <svg
71937
- class="pptx-ng-mtoolbar-icon"
71938
- xmlns="http://www.w3.org/2000/svg"
71939
- viewBox="0 0 24 24"
71940
- fill="none"
71941
- stroke="currentColor"
71942
- stroke-width="2"
71943
- stroke-linecap="round"
71944
- stroke-linejoin="round"
71945
- aria-hidden="true"
71946
- >
71947
- <path d="M3 12h18 M3 6h18 M3 18h18" />
71948
- </svg>
72550
+ <svg lucideMenu class="pptx-ng-mtoolbar-icon" aria-hidden="true"></svg>
71949
72551
  </button>
71950
72552
 
71951
72553
  @if (!toolbar.isHidden('undo')) {
@@ -71957,19 +72559,7 @@ class MobileToolbarComponent {
71957
72559
  [disabled]="!canUndo()"
71958
72560
  (click)="undo.emit()"
71959
72561
  >
71960
- <svg
71961
- class="pptx-ng-mtoolbar-icon"
71962
- xmlns="http://www.w3.org/2000/svg"
71963
- viewBox="0 0 24 24"
71964
- fill="none"
71965
- stroke="currentColor"
71966
- stroke-width="2"
71967
- stroke-linecap="round"
71968
- stroke-linejoin="round"
71969
- aria-hidden="true"
71970
- >
71971
- <path d="M3 7v6h6 M21 17a9 9 0 0 0-9-9 9 9 0 0 0-6 2.3L3 13" />
71972
- </svg>
72562
+ <svg lucideUndo class="pptx-ng-mtoolbar-icon" aria-hidden="true"></svg>
71973
72563
  </button>
71974
72564
  }
71975
72565
 
@@ -71982,19 +72572,7 @@ class MobileToolbarComponent {
71982
72572
  [disabled]="!canRedo()"
71983
72573
  (click)="redo.emit()"
71984
72574
  >
71985
- <svg
71986
- class="pptx-ng-mtoolbar-icon"
71987
- xmlns="http://www.w3.org/2000/svg"
71988
- viewBox="0 0 24 24"
71989
- fill="none"
71990
- stroke="currentColor"
71991
- stroke-width="2"
71992
- stroke-linecap="round"
71993
- stroke-linejoin="round"
71994
- aria-hidden="true"
71995
- >
71996
- <path d="M21 7v6h-6 M3 17a9 9 0 0 1 9-9 9 9 0 0 1 6 2.3L21 13" />
71997
- </svg>
72575
+ <svg lucideRedo class="pptx-ng-mtoolbar-icon" aria-hidden="true"></svg>
71998
72576
  </button>
71999
72577
  }
72000
72578
  }
@@ -72018,39 +72596,7 @@ class MobileToolbarComponent {
72018
72596
  [title]="'pptx.toolbar.toggleAiAssistant' | translate"
72019
72597
  (click)="toggleAiPanel.emit()"
72020
72598
  >
72021
- <svg
72022
- class="pptx-ng-mtoolbar-icon"
72023
- xmlns="http://www.w3.org/2000/svg"
72024
- viewBox="0 0 24 24"
72025
- fill="none"
72026
- stroke="currentColor"
72027
- stroke-width="2"
72028
- stroke-linecap="round"
72029
- stroke-linejoin="round"
72030
- aria-hidden="true"
72031
- >
72032
- <path
72033
- d="M9.937 15.5A2 2 0 0 0 8.5 14.063l-6.135-1.582a.5.5 0 0 1 0-.962L8.5 9.936A2 2 0 0 0 9.937 8.5l1.582-6.135a.5.5 0 0 1 .963 0L14.063 8.5A2 2 0 0 0 15.5 9.937l6.135 1.581a.5.5 0 0 1 0 .964L15.5 14.063a2 2 0 0 0-1.437 1.437l-1.582 6.135a.5.5 0 0 1-.963 0z"
72034
- />
72035
- <path d="M20 3v4 M22 5h-4 M4 17v2 M5 18H3" />
72036
- </svg>
72037
- </button>
72038
- }
72039
-
72040
- <!--
72041
- Share: start/join a real-time collaboration session. Gated on edit
72042
- mode and toolbar visibility, mirroring React's MobileToolbar; the
72043
- icon is the same Lucide Share2 the desktop ribbon uses.
72044
- -->
72045
- @if (canEdit() && !toolbar.isHidden('share')) {
72046
- <button
72047
- type="button"
72048
- class="pptx-ng-mtoolbar-btn"
72049
- [attr.aria-label]="'pptx.toolbar.share' | translate"
72050
- [title]="'pptx.toolbar.share' | translate"
72051
- (click)="share.emit()"
72052
- >
72053
- <svg lucideShare2 class="pptx-ng-mtoolbar-icon" aria-hidden="true"></svg>
72599
+ <svg lucideSparkles class="pptx-ng-mtoolbar-icon" aria-hidden="true"></svg>
72054
72600
  </button>
72055
72601
  }
72056
72602
 
@@ -72066,49 +72612,54 @@ class MobileToolbarComponent {
72066
72612
  [title]="'pptx.toolbar.save' | translate"
72067
72613
  (click)="save.emit()"
72068
72614
  >
72069
- <svg
72070
- class="pptx-ng-mtoolbar-icon"
72071
- xmlns="http://www.w3.org/2000/svg"
72072
- viewBox="0 0 24 24"
72073
- fill="none"
72074
- stroke="currentColor"
72075
- stroke-width="2"
72076
- stroke-linecap="round"
72077
- stroke-linejoin="round"
72078
- aria-hidden="true"
72079
- >
72080
- <path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4 M7 10l5 5 5-5 M12 15V3" />
72081
- </svg>
72615
+ <svg lucideDownload class="pptx-ng-mtoolbar-icon" aria-hidden="true"></svg>
72082
72616
  </button>
72083
72617
 
72084
- <button
72085
- type="button"
72086
- class="pptx-ng-mtoolbar-btn pptx-ng-mtoolbar-present"
72087
- [attr.aria-label]="'pptx.toolbar.present' | translate"
72088
- [title]="'pptx.toolbar.present' | translate"
72089
- [disabled]="!canPresent()"
72090
- (click)="present.emit()"
72091
- >
72092
- <svg
72093
- class="pptx-ng-mtoolbar-icon"
72094
- xmlns="http://www.w3.org/2000/svg"
72095
- viewBox="0 0 24 24"
72096
- fill="none"
72097
- stroke="currentColor"
72098
- stroke-width="2"
72099
- stroke-linecap="round"
72100
- stroke-linejoin="round"
72101
- aria-hidden="true"
72618
+ <!-- Present: same Lucide "presentation" glyph React's mobile bar uses. -->
72619
+ @if (!toolbar.isHidden('fullscreen')) {
72620
+ <button
72621
+ type="button"
72622
+ class="pptx-ng-mtoolbar-btn pptx-ng-mtoolbar-present"
72623
+ [attr.aria-label]="'pptx.toolbar.present' | translate"
72624
+ [title]="'pptx.toolbar.present' | translate"
72625
+ [disabled]="!canPresent()"
72626
+ (click)="present.emit()"
72102
72627
  >
72103
- <path d="M5 3l14 9-14 9V3z" />
72104
- </svg>
72105
- </button>
72628
+ <svg lucidePresentation class="pptx-ng-mtoolbar-icon" aria-hidden="true"></svg>
72629
+ </button>
72630
+ }
72631
+
72632
+ <!--
72633
+ Share: start/join a real-time collaboration session. Sits last in
72634
+ the row (after Present) and renders as a filled primary pill, the
72635
+ same slot and treatment React's MobileToolbar gives it.
72636
+ -->
72637
+ @if (canEdit() && !toolbar.isHidden('share')) {
72638
+ <button
72639
+ type="button"
72640
+ class="pptx-ng-mtoolbar-btn pptx-ng-mtoolbar-share"
72641
+ [attr.aria-label]="'pptx.toolbar.share' | translate"
72642
+ [title]="'pptx.toolbar.share' | translate"
72643
+ (click)="share.emit()"
72644
+ >
72645
+ <svg lucideShare2 class="pptx-ng-mtoolbar-icon is-sm" aria-hidden="true"></svg>
72646
+ </button>
72647
+ }
72106
72648
  </div>
72107
- `, isInline: true, styles: [":host{display:block}.pptx-ng-mtoolbar{position:relative;z-index:20;display:flex;align-items:center;gap:.25rem;padding:.25rem .5rem;min-height:52px;background:#1a1a1aeb;border-bottom:1px solid rgba(255,255,255,.1);backdrop-filter:blur(12px);-webkit-backdrop-filter:blur(12px);padding-top:max(env(safe-area-inset-top,0px),.25rem)}.pptx-ng-mtoolbar-spacer{flex:1 1 auto}.pptx-ng-mtoolbar-btn{display:inline-flex;align-items:center;justify-content:center;min-width:44px;min-height:44px;border:none;border-radius:.375rem;background:transparent;color:#ffffffd9;cursor:pointer;touch-action:manipulation;transition:background .12s,transform .08s;-webkit-tap-highlight-color:transparent}.pptx-ng-mtoolbar-btn:active:not([disabled]){transform:scale(.92)}.pptx-ng-mtoolbar-btn:hover:not([disabled]){background:#ffffff14}.pptx-ng-mtoolbar-btn.is-active{color:#3b82f6}.pptx-ng-mtoolbar-btn[disabled]{opacity:.35;cursor:not-allowed}.pptx-ng-mtoolbar-present{color:#3b82f6}.pptx-ng-mtoolbar-icon{width:1.25rem;height:1.25rem;flex-shrink:0}\n"], dependencies: [{ kind: "component", type: LucideShare2, selector: "svg[lucideShare2]" }, { kind: "pipe", type: TranslatePipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
72649
+ `, isInline: true, styles: [":host{display:block}.pptx-ng-mtoolbar{position:relative;z-index:20;display:flex;align-items:center;gap:.25rem;padding:.25rem .5rem;min-height:52px;background:color-mix(in srgb,var(--pptx-secondary, #1f2937) 50%,transparent);border-bottom:1px solid var(--pptx-border, #374151);padding-top:max(env(safe-area-inset-top,0px),.25rem)}.pptx-ng-mtoolbar-spacer{flex:1 1 auto}.pptx-ng-mtoolbar-btn{display:inline-flex;align-items:center;justify-content:center;min-width:44px;min-height:44px;border:none;border-radius:.375rem;background:transparent;color:color-mix(in srgb,var(--pptx-foreground, #f3f4f6) 80%,transparent);cursor:pointer;touch-action:manipulation;transition:background .12s,transform .08s;-webkit-tap-highlight-color:transparent}.pptx-ng-mtoolbar-btn:active:not([disabled]){transform:scale(.92)}.pptx-ng-mtoolbar-btn:hover:not([disabled]){background:color-mix(in srgb,var(--pptx-accent, #1f2937) 60%,transparent)}.pptx-ng-mtoolbar-btn.is-active{color:var(--pptx-primary, #6366f1)}.pptx-ng-mtoolbar-btn[disabled]{opacity:.35;cursor:not-allowed}.pptx-ng-mtoolbar-present{color:var(--pptx-primary, #6366f1)}.pptx-ng-mtoolbar-share{padding:0 .75rem;background:var(--pptx-primary, #6366f1);color:var(--pptx-primary-foreground, #ffffff)}.pptx-ng-mtoolbar-share:hover:not([disabled]){background:color-mix(in srgb,var(--pptx-primary, #6366f1) 90%,transparent)}.pptx-ng-mtoolbar-icon{width:1.25rem;height:1.25rem;flex-shrink:0}.pptx-ng-mtoolbar-icon.is-sm{width:1rem;height:1rem}\n"], dependencies: [{ kind: "component", type: LucideDownload, selector: "svg[lucideDownload]" }, { kind: "component", type: LucideMenu, selector: "svg[lucideMenu]" }, { kind: "component", type: LucidePresentation, selector: "svg[lucidePresentation]" }, { kind: "component", type: LucideRedo, selector: "svg[lucideRedo]" }, { kind: "component", type: LucideShare2, selector: "svg[lucideShare2]" }, { kind: "component", type: LucideSparkles, selector: "svg[lucideSparkles], svg[lucideStars]" }, { kind: "component", type: LucideUndo, selector: "svg[lucideUndo]" }, { kind: "pipe", type: TranslatePipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
72108
72650
  }
72109
72651
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: MobileToolbarComponent, decorators: [{
72110
72652
  type: Component,
72111
- args: [{ selector: 'pptx-mobile-toolbar', standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, imports: [LucideShare2, TranslatePipe], template: `
72653
+ args: [{ selector: 'pptx-mobile-toolbar', standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, imports: [
72654
+ LucideDownload,
72655
+ LucideMenu,
72656
+ LucidePresentation,
72657
+ LucideRedo,
72658
+ LucideShare2,
72659
+ LucideSparkles,
72660
+ LucideUndo,
72661
+ TranslatePipe,
72662
+ ], template: `
72112
72663
  <div
72113
72664
  class="pptx-ng-mtoolbar"
72114
72665
  role="toolbar"
@@ -72124,19 +72675,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.8", ngImpor
72124
72675
  [title]="'pptx.mobileToolbar.menu' | translate"
72125
72676
  (click)="toggleMenu.emit()"
72126
72677
  >
72127
- <svg
72128
- class="pptx-ng-mtoolbar-icon"
72129
- xmlns="http://www.w3.org/2000/svg"
72130
- viewBox="0 0 24 24"
72131
- fill="none"
72132
- stroke="currentColor"
72133
- stroke-width="2"
72134
- stroke-linecap="round"
72135
- stroke-linejoin="round"
72136
- aria-hidden="true"
72137
- >
72138
- <path d="M3 12h18 M3 6h18 M3 18h18" />
72139
- </svg>
72678
+ <svg lucideMenu class="pptx-ng-mtoolbar-icon" aria-hidden="true"></svg>
72140
72679
  </button>
72141
72680
 
72142
72681
  @if (!toolbar.isHidden('undo')) {
@@ -72148,19 +72687,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.8", ngImpor
72148
72687
  [disabled]="!canUndo()"
72149
72688
  (click)="undo.emit()"
72150
72689
  >
72151
- <svg
72152
- class="pptx-ng-mtoolbar-icon"
72153
- xmlns="http://www.w3.org/2000/svg"
72154
- viewBox="0 0 24 24"
72155
- fill="none"
72156
- stroke="currentColor"
72157
- stroke-width="2"
72158
- stroke-linecap="round"
72159
- stroke-linejoin="round"
72160
- aria-hidden="true"
72161
- >
72162
- <path d="M3 7v6h6 M21 17a9 9 0 0 0-9-9 9 9 0 0 0-6 2.3L3 13" />
72163
- </svg>
72690
+ <svg lucideUndo class="pptx-ng-mtoolbar-icon" aria-hidden="true"></svg>
72164
72691
  </button>
72165
72692
  }
72166
72693
 
@@ -72173,19 +72700,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.8", ngImpor
72173
72700
  [disabled]="!canRedo()"
72174
72701
  (click)="redo.emit()"
72175
72702
  >
72176
- <svg
72177
- class="pptx-ng-mtoolbar-icon"
72178
- xmlns="http://www.w3.org/2000/svg"
72179
- viewBox="0 0 24 24"
72180
- fill="none"
72181
- stroke="currentColor"
72182
- stroke-width="2"
72183
- stroke-linecap="round"
72184
- stroke-linejoin="round"
72185
- aria-hidden="true"
72186
- >
72187
- <path d="M21 7v6h-6 M3 17a9 9 0 0 1 9-9 9 9 0 0 1 6 2.3L21 13" />
72188
- </svg>
72703
+ <svg lucideRedo class="pptx-ng-mtoolbar-icon" aria-hidden="true"></svg>
72189
72704
  </button>
72190
72705
  }
72191
72706
  }
@@ -72209,39 +72724,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.8", ngImpor
72209
72724
  [title]="'pptx.toolbar.toggleAiAssistant' | translate"
72210
72725
  (click)="toggleAiPanel.emit()"
72211
72726
  >
72212
- <svg
72213
- class="pptx-ng-mtoolbar-icon"
72214
- xmlns="http://www.w3.org/2000/svg"
72215
- viewBox="0 0 24 24"
72216
- fill="none"
72217
- stroke="currentColor"
72218
- stroke-width="2"
72219
- stroke-linecap="round"
72220
- stroke-linejoin="round"
72221
- aria-hidden="true"
72222
- >
72223
- <path
72224
- d="M9.937 15.5A2 2 0 0 0 8.5 14.063l-6.135-1.582a.5.5 0 0 1 0-.962L8.5 9.936A2 2 0 0 0 9.937 8.5l1.582-6.135a.5.5 0 0 1 .963 0L14.063 8.5A2 2 0 0 0 15.5 9.937l6.135 1.581a.5.5 0 0 1 0 .964L15.5 14.063a2 2 0 0 0-1.437 1.437l-1.582 6.135a.5.5 0 0 1-.963 0z"
72225
- />
72226
- <path d="M20 3v4 M22 5h-4 M4 17v2 M5 18H3" />
72227
- </svg>
72228
- </button>
72229
- }
72230
-
72231
- <!--
72232
- Share: start/join a real-time collaboration session. Gated on edit
72233
- mode and toolbar visibility, mirroring React's MobileToolbar; the
72234
- icon is the same Lucide Share2 the desktop ribbon uses.
72235
- -->
72236
- @if (canEdit() && !toolbar.isHidden('share')) {
72237
- <button
72238
- type="button"
72239
- class="pptx-ng-mtoolbar-btn"
72240
- [attr.aria-label]="'pptx.toolbar.share' | translate"
72241
- [title]="'pptx.toolbar.share' | translate"
72242
- (click)="share.emit()"
72243
- >
72244
- <svg lucideShare2 class="pptx-ng-mtoolbar-icon" aria-hidden="true"></svg>
72727
+ <svg lucideSparkles class="pptx-ng-mtoolbar-icon" aria-hidden="true"></svg>
72245
72728
  </button>
72246
72729
  }
72247
72730
 
@@ -72257,45 +72740,41 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.8", ngImpor
72257
72740
  [title]="'pptx.toolbar.save' | translate"
72258
72741
  (click)="save.emit()"
72259
72742
  >
72260
- <svg
72261
- class="pptx-ng-mtoolbar-icon"
72262
- xmlns="http://www.w3.org/2000/svg"
72263
- viewBox="0 0 24 24"
72264
- fill="none"
72265
- stroke="currentColor"
72266
- stroke-width="2"
72267
- stroke-linecap="round"
72268
- stroke-linejoin="round"
72269
- aria-hidden="true"
72270
- >
72271
- <path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4 M7 10l5 5 5-5 M12 15V3" />
72272
- </svg>
72743
+ <svg lucideDownload class="pptx-ng-mtoolbar-icon" aria-hidden="true"></svg>
72273
72744
  </button>
72274
72745
 
72275
- <button
72276
- type="button"
72277
- class="pptx-ng-mtoolbar-btn pptx-ng-mtoolbar-present"
72278
- [attr.aria-label]="'pptx.toolbar.present' | translate"
72279
- [title]="'pptx.toolbar.present' | translate"
72280
- [disabled]="!canPresent()"
72281
- (click)="present.emit()"
72282
- >
72283
- <svg
72284
- class="pptx-ng-mtoolbar-icon"
72285
- xmlns="http://www.w3.org/2000/svg"
72286
- viewBox="0 0 24 24"
72287
- fill="none"
72288
- stroke="currentColor"
72289
- stroke-width="2"
72290
- stroke-linecap="round"
72291
- stroke-linejoin="round"
72292
- aria-hidden="true"
72746
+ <!-- Present: same Lucide "presentation" glyph React's mobile bar uses. -->
72747
+ @if (!toolbar.isHidden('fullscreen')) {
72748
+ <button
72749
+ type="button"
72750
+ class="pptx-ng-mtoolbar-btn pptx-ng-mtoolbar-present"
72751
+ [attr.aria-label]="'pptx.toolbar.present' | translate"
72752
+ [title]="'pptx.toolbar.present' | translate"
72753
+ [disabled]="!canPresent()"
72754
+ (click)="present.emit()"
72293
72755
  >
72294
- <path d="M5 3l14 9-14 9V3z" />
72295
- </svg>
72296
- </button>
72756
+ <svg lucidePresentation class="pptx-ng-mtoolbar-icon" aria-hidden="true"></svg>
72757
+ </button>
72758
+ }
72759
+
72760
+ <!--
72761
+ Share: start/join a real-time collaboration session. Sits last in
72762
+ the row (after Present) and renders as a filled primary pill, the
72763
+ same slot and treatment React's MobileToolbar gives it.
72764
+ -->
72765
+ @if (canEdit() && !toolbar.isHidden('share')) {
72766
+ <button
72767
+ type="button"
72768
+ class="pptx-ng-mtoolbar-btn pptx-ng-mtoolbar-share"
72769
+ [attr.aria-label]="'pptx.toolbar.share' | translate"
72770
+ [title]="'pptx.toolbar.share' | translate"
72771
+ (click)="share.emit()"
72772
+ >
72773
+ <svg lucideShare2 class="pptx-ng-mtoolbar-icon is-sm" aria-hidden="true"></svg>
72774
+ </button>
72775
+ }
72297
72776
  </div>
72298
- `, styles: [":host{display:block}.pptx-ng-mtoolbar{position:relative;z-index:20;display:flex;align-items:center;gap:.25rem;padding:.25rem .5rem;min-height:52px;background:#1a1a1aeb;border-bottom:1px solid rgba(255,255,255,.1);backdrop-filter:blur(12px);-webkit-backdrop-filter:blur(12px);padding-top:max(env(safe-area-inset-top,0px),.25rem)}.pptx-ng-mtoolbar-spacer{flex:1 1 auto}.pptx-ng-mtoolbar-btn{display:inline-flex;align-items:center;justify-content:center;min-width:44px;min-height:44px;border:none;border-radius:.375rem;background:transparent;color:#ffffffd9;cursor:pointer;touch-action:manipulation;transition:background .12s,transform .08s;-webkit-tap-highlight-color:transparent}.pptx-ng-mtoolbar-btn:active:not([disabled]){transform:scale(.92)}.pptx-ng-mtoolbar-btn:hover:not([disabled]){background:#ffffff14}.pptx-ng-mtoolbar-btn.is-active{color:#3b82f6}.pptx-ng-mtoolbar-btn[disabled]{opacity:.35;cursor:not-allowed}.pptx-ng-mtoolbar-present{color:#3b82f6}.pptx-ng-mtoolbar-icon{width:1.25rem;height:1.25rem;flex-shrink:0}\n"] }]
72777
+ `, styles: [":host{display:block}.pptx-ng-mtoolbar{position:relative;z-index:20;display:flex;align-items:center;gap:.25rem;padding:.25rem .5rem;min-height:52px;background:color-mix(in srgb,var(--pptx-secondary, #1f2937) 50%,transparent);border-bottom:1px solid var(--pptx-border, #374151);padding-top:max(env(safe-area-inset-top,0px),.25rem)}.pptx-ng-mtoolbar-spacer{flex:1 1 auto}.pptx-ng-mtoolbar-btn{display:inline-flex;align-items:center;justify-content:center;min-width:44px;min-height:44px;border:none;border-radius:.375rem;background:transparent;color:color-mix(in srgb,var(--pptx-foreground, #f3f4f6) 80%,transparent);cursor:pointer;touch-action:manipulation;transition:background .12s,transform .08s;-webkit-tap-highlight-color:transparent}.pptx-ng-mtoolbar-btn:active:not([disabled]){transform:scale(.92)}.pptx-ng-mtoolbar-btn:hover:not([disabled]){background:color-mix(in srgb,var(--pptx-accent, #1f2937) 60%,transparent)}.pptx-ng-mtoolbar-btn.is-active{color:var(--pptx-primary, #6366f1)}.pptx-ng-mtoolbar-btn[disabled]{opacity:.35;cursor:not-allowed}.pptx-ng-mtoolbar-present{color:var(--pptx-primary, #6366f1)}.pptx-ng-mtoolbar-share{padding:0 .75rem;background:var(--pptx-primary, #6366f1);color:var(--pptx-primary-foreground, #ffffff)}.pptx-ng-mtoolbar-share:hover:not([disabled]){background:color-mix(in srgb,var(--pptx-primary, #6366f1) 90%,transparent)}.pptx-ng-mtoolbar-icon{width:1.25rem;height:1.25rem;flex-shrink:0}.pptx-ng-mtoolbar-icon.is-sm{width:1rem;height:1rem}\n"] }]
72299
72778
  }], propDecorators: { canUndo: [{ type: i0.Input, args: [{ isSignal: true, alias: "canUndo", required: false }] }], canRedo: [{ type: i0.Input, args: [{ isSignal: true, alias: "canRedo", required: false }] }], canPresent: [{ type: i0.Input, args: [{ isSignal: true, alias: "canPresent", required: false }] }], canEdit: [{ type: i0.Input, args: [{ isSignal: true, alias: "canEdit", required: false }] }], menuOpen: [{ type: i0.Input, args: [{ isSignal: true, alias: "menuOpen", required: false }] }], aiEnabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "aiEnabled", required: false }] }], aiPanelOpen: [{ type: i0.Input, args: [{ isSignal: true, alias: "aiPanelOpen", required: false }] }], hiddenActions: [{ type: i0.Input, args: [{ isSignal: true, alias: "hiddenActions", required: false }] }], toggleMenu: [{ type: i0.Output, args: ["toggleMenu"] }], toggleAiPanel: [{ type: i0.Output, args: ["toggleAiPanel"] }], undo: [{ type: i0.Output, args: ["undo"] }], redo: [{ type: i0.Output, args: ["redo"] }], share: [{ type: i0.Output, args: ["share"] }], save: [{ type: i0.Output, args: ["save"] }], present: [{ type: i0.Output, args: ["present"] }] } });
72300
72779
 
72301
72780
  /**
@@ -73746,6 +74225,7 @@ class ViewerCanvasEditingService {
73746
74225
  editor = inject(EditorStateService);
73747
74226
  dialogs = inject(ViewerDialogsService);
73748
74227
  formatPainter = inject(ViewerFormatPainterService);
74228
+ collab = inject(CollaborationService);
73749
74229
  /** Id of the element being inline text-edited, or null. */
73750
74230
  editingId = signal(null, /* @ts-ignore */
73751
74231
  ...(ngDevMode ? [{ debugName: "editingId" }] : /* istanbul ignore next */ []));
@@ -73790,9 +74270,21 @@ class ViewerCanvasEditingService {
73790
74270
  }
73791
74271
  this.editor.updateElement(host.activeSlideIndex(), event.id, textStylePatch(element, event.updates));
73792
74272
  }
74273
+ /**
74274
+ * Mirror an in-progress inline edit to collaborators. The typed text only
74275
+ * reaches the editor state (and therefore the Y.Doc reconcile) on commit, so
74276
+ * without this peers saw nothing until the editor blurred. No-op when not
74277
+ * collaborating.
74278
+ */
74279
+ onTextInput(event) {
74280
+ publishLiveInlineText(this.collab.livePatcher, this.requireHost().activeSlide(), event.id, event.text);
74281
+ }
73793
74282
  /** Commit an inline text edit: replace the element's text (one history entry). */
73794
74283
  onTextCommit(event) {
73795
74284
  const host = this.requireHost();
74285
+ // Push any queued interim frame out first so it cannot land after the
74286
+ // committed text and revert it.
74287
+ this.collab.livePatcher.flush();
73796
74288
  this.editor.updateElement(host.activeSlideIndex(), event.id, {
73797
74289
  text: event.text,
73798
74290
  textSegments: [],
@@ -77738,7 +78230,7 @@ class PresentationTransitionOverlayComponent {
77738
78230
  />
77739
78231
  </div>
77740
78232
  </div>
77741
- `, isInline: true, styles: [":host{display:block;position:absolute;inset:0;overflow:hidden;pointer-events:none}.pptx-ng-transition-layer{position:absolute;inset:0;display:flex;align-items:center;justify-content:center}\n"], dependencies: [{ 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", "snapToShape", "guideCommand", "spellCheck", "snapToGuides", "autoFit", "interactive", "presenting", "selectedIds", "editingId", "editTemplateMode", "templateElements", "aiHighlights", "aiActive", "aiActiveSlideIndex", "aiChangeBatch", "aiPickMode", "drawTool", "drawColor", "drawWidth"], outputs: ["elementSelect", "backgroundClick", "transformStart", "transformUpdate", "contextMenu", "textEditStart", "textCommit", "textCancel", "textFormat", "rotateUpdate", "marqueeSelect", "inkStrokeComplete", "eraserHit", "cellCommit", "tableChange"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
78233
+ `, isInline: true, styles: [":host{display:block;position:absolute;inset:0;overflow:hidden;pointer-events:none}.pptx-ng-transition-layer{position:absolute;inset:0;display:flex;align-items:center;justify-content:center}\n"], dependencies: [{ 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", "snapToShape", "guideCommand", "spellCheck", "snapToGuides", "autoFit", "interactive", "presenting", "selectedIds", "editingId", "editTemplateMode", "templateElements", "aiHighlights", "aiActive", "aiActiveSlideIndex", "aiChangeBatch", "aiPickMode", "drawTool", "drawColor", "drawWidth"], outputs: ["elementSelect", "backgroundClick", "transformStart", "transformUpdate", "contextMenu", "textEditStart", "textCommit", "textInput", "textCancel", "textFormat", "rotateUpdate", "marqueeSelect", "inkStrokeComplete", "eraserHit", "cellCommit", "tableChange"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
77742
78234
  }
77743
78235
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: PresentationTransitionOverlayComponent, decorators: [{
77744
78236
  type: Component,
@@ -78539,7 +79031,7 @@ class PresentationOverlayComponent {
78539
79031
  <svg lucideChevronRight class="h-6 w-6"></svg>
78540
79032
  </button>
78541
79033
  </div>
78542
- `, isInline: true, styles: [":host{display:block;position:fixed;inset:0;z-index:10000;background:#000;cursor:pointer;-webkit-user-select:none;user-select:none}.pptx-ng-presentation-root{position:absolute;inset:0;touch-action:pan-y}.pptx-ng-presentation-close:hover,.pptx-ng-presentation-nav:hover{background:#000000bf}.pptx-ng-presentation-tools{position:absolute;bottom:max(1rem,env(safe-area-inset-bottom));left:1rem;display:flex;gap:.25rem;padding:.25rem;border-radius:.5rem;background:#0000008c;z-index:80}.pptx-ng-presentation-tools button{width:2rem;height:2rem;border:none;border-radius:.35rem;background:transparent;color:#fff;font-size:1rem;cursor:pointer}.pptx-ng-presentation-tools button:hover{background:#ffffff26}.pptx-ng-presentation-tools button.is-active{background:#ffffff4d}.presenter-blank{position:absolute;inset:0;z-index:75}.presenter-laser{position:absolute;z-index:76;width:20px;height:20px;transform:translate(-50%,-50%);border-radius:50%;background:#ef4444;box-shadow:0 0 20px 8px #ef444488;pointer-events:none}.presenter-caption{position:absolute;z-index:77;left:10%;right:10%;bottom:2rem;padding:.75rem 1.5rem;border-radius:.5rem;background:#000c;color:#fff;text-align:center;font-size:1.25rem;pointer-events:none}\n"], dependencies: [{ 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", "snapToShape", "guideCommand", "spellCheck", "snapToGuides", "autoFit", "interactive", "presenting", "selectedIds", "editingId", "editTemplateMode", "templateElements", "aiHighlights", "aiActive", "aiActiveSlideIndex", "aiChangeBatch", "aiPickMode", "drawTool", "drawColor", "drawWidth"], outputs: ["elementSelect", "backgroundClick", "transformStart", "transformUpdate", "contextMenu", "textEditStart", "textCommit", "textCancel", "textFormat", "rotateUpdate", "marqueeSelect", "inkStrokeComplete", "eraserHit", "cellCommit", "tableChange"] }, { kind: "component", type: PresentationTransitionOverlayComponent, selector: "pptx-presentation-transition-overlay", inputs: ["outgoingSlide", "canvasSize", "transition", "templateElements", "mediaDataUrls", "durationMs"], outputs: ["complete"] }, { kind: "component", type: PresentationAnnotationOverlayComponent, selector: "pptx-presentation-annotation-overlay", inputs: ["canvasSize", "zoom"] }, { kind: "component", type: PresentationSubtitleBarComponent, selector: "pptx-presentation-subtitle-bar", inputs: ["visible"] }, { kind: "component", type: LucidePenTool, selector: "svg[lucidePenTool]" }, { kind: "component", type: LucideHighlighter, selector: "svg[lucideHighlighter]" }, { kind: "component", type: LucideEraser, selector: "svg[lucideEraser]" }, { kind: "component", type: LucideMousePointer2, selector: "svg[lucideMousePointer2]" }, { kind: "component", type: LucideTrash2, selector: "svg[lucideTrash2]" }, { kind: "component", type: LucideX, selector: "svg[lucideX]" }, { kind: "component", type: LucideChevronLeft, selector: "svg[lucideChevronLeft]" }, { kind: "component", type: LucideChevronRight, selector: "svg[lucideChevronRight]" }, { kind: "pipe", type: TranslatePipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
79034
+ `, isInline: true, styles: [":host{display:block;position:fixed;inset:0;z-index:10000;background:#000;cursor:pointer;-webkit-user-select:none;user-select:none}.pptx-ng-presentation-root{position:absolute;inset:0;touch-action:pan-y}.pptx-ng-presentation-close:hover,.pptx-ng-presentation-nav:hover{background:#000000bf}.pptx-ng-presentation-tools{position:absolute;bottom:max(1rem,env(safe-area-inset-bottom));left:1rem;display:flex;gap:.25rem;padding:.25rem;border-radius:.5rem;background:#0000008c;z-index:80}.pptx-ng-presentation-tools button{width:2rem;height:2rem;border:none;border-radius:.35rem;background:transparent;color:#fff;font-size:1rem;cursor:pointer}.pptx-ng-presentation-tools button:hover{background:#ffffff26}.pptx-ng-presentation-tools button.is-active{background:#ffffff4d}.presenter-blank{position:absolute;inset:0;z-index:75}.presenter-laser{position:absolute;z-index:76;width:20px;height:20px;transform:translate(-50%,-50%);border-radius:50%;background:#ef4444;box-shadow:0 0 20px 8px #ef444488;pointer-events:none}.presenter-caption{position:absolute;z-index:77;left:10%;right:10%;bottom:2rem;padding:.75rem 1.5rem;border-radius:.5rem;background:#000c;color:#fff;text-align:center;font-size:1.25rem;pointer-events:none}\n"], dependencies: [{ 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", "snapToShape", "guideCommand", "spellCheck", "snapToGuides", "autoFit", "interactive", "presenting", "selectedIds", "editingId", "editTemplateMode", "templateElements", "aiHighlights", "aiActive", "aiActiveSlideIndex", "aiChangeBatch", "aiPickMode", "drawTool", "drawColor", "drawWidth"], outputs: ["elementSelect", "backgroundClick", "transformStart", "transformUpdate", "contextMenu", "textEditStart", "textCommit", "textInput", "textCancel", "textFormat", "rotateUpdate", "marqueeSelect", "inkStrokeComplete", "eraserHit", "cellCommit", "tableChange"] }, { kind: "component", type: PresentationTransitionOverlayComponent, selector: "pptx-presentation-transition-overlay", inputs: ["outgoingSlide", "canvasSize", "transition", "templateElements", "mediaDataUrls", "durationMs"], outputs: ["complete"] }, { kind: "component", type: PresentationAnnotationOverlayComponent, selector: "pptx-presentation-annotation-overlay", inputs: ["canvasSize", "zoom"] }, { kind: "component", type: PresentationSubtitleBarComponent, selector: "pptx-presentation-subtitle-bar", inputs: ["visible"] }, { kind: "component", type: LucidePenTool, selector: "svg[lucidePenTool]" }, { kind: "component", type: LucideHighlighter, selector: "svg[lucideHighlighter]" }, { kind: "component", type: LucideEraser, selector: "svg[lucideEraser]" }, { kind: "component", type: LucideMousePointer2, selector: "svg[lucideMousePointer2]" }, { kind: "component", type: LucideTrash2, selector: "svg[lucideTrash2]" }, { kind: "component", type: LucideX, selector: "svg[lucideX]" }, { kind: "component", type: LucideChevronLeft, selector: "svg[lucideChevronLeft]" }, { kind: "component", type: LucideChevronRight, selector: "svg[lucideChevronRight]" }, { kind: "pipe", type: TranslatePipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
78543
79035
  }
78544
79036
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: PresentationOverlayComponent, decorators: [{
78545
79037
  type: Component,
@@ -78774,7 +79266,7 @@ class PresenterControlsComponent {
78774
79266
  @for(slide of slides();track slide.id;let index=$index){<button class="tile" [class.current]="index===current()" [class.hidden]="slide.hidden" (click)="select(index)"><div class="preview" [style.height.px]="canvasSize().height*(200/canvasSize().width)"><pptx-slide-canvas [slide]="slide" [canvasSize]="canvasSize()" [mediaDataUrls]="mediaDataUrls()" [zoom]="200/canvasSize().width" [interactive]="false" /></div><span>{{index+1}}{{slide.hidden?' - hidden':''}}</span></button>}
78775
79267
  </main></div>
78776
79268
  }
78777
- `, isInline: true, styles: [":host{display:block}.strip{display:flex;flex-wrap:wrap;align-items:center;gap:4px;padding:8px 12px;background:#020617;border-bottom:1px solid #ffffff1a}.strip button,.grid button{border:0;border-radius:5px;padding:7px 10px;background:#ffffff12;color:#e2e8f0;cursor:pointer}.strip button:hover,.strip .active{background:#38bdf8;color:#082f49}.strip span{flex:1}.grid{position:fixed;inset:0;z-index:120;display:flex;flex-direction:column;background:#020617fa;color:#f8fafc}.grid header{display:flex;align-items:center;justify-content:space-between;padding:18px 24px;border-bottom:1px solid #ffffff1a}.grid main{display:grid;grid-template-columns:repeat(auto-fill,minmax(220px,1fr));gap:20px;padding:24px;overflow:auto}.tile{text-align:left}.tile.current{outline:2px solid #38bdf8}.tile.hidden{opacity:.45}.preview{width:200px;overflow:hidden}.tile span{display:block;margin-top:8px;color:#94a3b8}\n"], dependencies: [{ kind: "component", type: SlideCanvasComponent, selector: "pptx-slide-canvas", inputs: ["slide", "canvasSize", "mediaDataUrls", "zoom", "editable", "showGrid", "showRulers", "showGuides", "snapToGrid", "snapToShape", "guideCommand", "spellCheck", "snapToGuides", "autoFit", "interactive", "presenting", "selectedIds", "editingId", "editTemplateMode", "templateElements", "aiHighlights", "aiActive", "aiActiveSlideIndex", "aiChangeBatch", "aiPickMode", "drawTool", "drawColor", "drawWidth"], outputs: ["elementSelect", "backgroundClick", "transformStart", "transformUpdate", "contextMenu", "textEditStart", "textCommit", "textCancel", "textFormat", "rotateUpdate", "marqueeSelect", "inkStrokeComplete", "eraserHit", "cellCommit", "tableChange"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
79269
+ `, isInline: true, styles: [":host{display:block}.strip{display:flex;flex-wrap:wrap;align-items:center;gap:4px;padding:8px 12px;background:#020617;border-bottom:1px solid #ffffff1a}.strip button,.grid button{border:0;border-radius:5px;padding:7px 10px;background:#ffffff12;color:#e2e8f0;cursor:pointer}.strip button:hover,.strip .active{background:#38bdf8;color:#082f49}.strip span{flex:1}.grid{position:fixed;inset:0;z-index:120;display:flex;flex-direction:column;background:#020617fa;color:#f8fafc}.grid header{display:flex;align-items:center;justify-content:space-between;padding:18px 24px;border-bottom:1px solid #ffffff1a}.grid main{display:grid;grid-template-columns:repeat(auto-fill,minmax(220px,1fr));gap:20px;padding:24px;overflow:auto}.tile{text-align:left}.tile.current{outline:2px solid #38bdf8}.tile.hidden{opacity:.45}.preview{width:200px;overflow:hidden}.tile span{display:block;margin-top:8px;color:#94a3b8}\n"], dependencies: [{ kind: "component", type: SlideCanvasComponent, selector: "pptx-slide-canvas", inputs: ["slide", "canvasSize", "mediaDataUrls", "zoom", "editable", "showGrid", "showRulers", "showGuides", "snapToGrid", "snapToShape", "guideCommand", "spellCheck", "snapToGuides", "autoFit", "interactive", "presenting", "selectedIds", "editingId", "editTemplateMode", "templateElements", "aiHighlights", "aiActive", "aiActiveSlideIndex", "aiChangeBatch", "aiPickMode", "drawTool", "drawColor", "drawWidth"], outputs: ["elementSelect", "backgroundClick", "transformStart", "transformUpdate", "contextMenu", "textEditStart", "textCommit", "textInput", "textCancel", "textFormat", "rotateUpdate", "marqueeSelect", "inkStrokeComplete", "eraserHit", "cellCommit", "tableChange"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
78778
79270
  }
78779
79271
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: PresenterControlsComponent, decorators: [{
78780
79272
  type: Component,
@@ -79121,7 +79613,7 @@ class PresenterViewComponent {
79121
79613
  } @else {
79122
79614
  <div class="pptx-ng-presenter-empty">{{ 'pptx.presenter.noSlides' | translate }}</div>
79123
79615
  }
79124
- `, isInline: true, styles: [":host{position:absolute;inset:0;z-index:50;display:flex;flex-direction:column;background:#0b0b0c;color:#f5f5f5;font-family:system-ui,sans-serif}.pptx-ng-presenter-body{display:flex;flex:1 1 auto;min-height:0}.pptx-ng-presenter-current{flex:7 1 0;display:flex;flex-direction:column;align-items:center;justify-content:center;background:#000;padding:1rem;min-width:0}.pptx-ng-presenter-preview-stage{width:100%;max-width:100%;min-height:0}.pptx-ng-presenter-slide-badge{margin-top:.5rem;font-family:ui-monospace,monospace;font-variant-numeric:tabular-nums;font-size:.75rem;color:#ffffff80;-webkit-user-select:none;user-select:none}.pptx-ng-presenter-side{flex:3 1 0;display:flex;flex-direction:column;background:#18181b;border-left:1px solid rgba(255,255,255,.12);min-width:260px;max-width:440px}.pptx-ng-presenter-header,.pptx-ng-presenter-nav,.pptx-ng-presenter-next{padding:.5rem 1rem;border-bottom:1px solid rgba(255,255,255,.08)}.pptx-ng-presenter-header{display:flex;align-items:center;justify-content:space-between;gap:.5rem}.pptx-ng-presenter-label{font-size:.625rem;text-transform:uppercase;letter-spacing:.06em;color:#ffffff8c}.pptx-ng-presenter-clock{font-family:ui-monospace,monospace;font-variant-numeric:tabular-nums;font-size:1.125rem}.pptx-ng-presenter-elapsed{color:#6ea8fe}.pptx-ng-presenter-iconbtn{display:inline-flex;align-items:center;justify-content:center;width:32px;height:32px;border:none;border-radius:6px;background:transparent;color:#ffffffb3;cursor:pointer;font-size:1rem;line-height:1}.pptx-ng-presenter-iconbtn:hover{background:#ffffff1a;color:#fff}.pptx-ng-presenter-iconbtn:disabled{opacity:.3;cursor:not-allowed}.pptx-ng-presenter-nav{display:flex;align-items:center;justify-content:space-between}.pptx-ng-presenter-navbtn{display:inline-flex;align-items:center;gap:.375rem;padding:.375rem .75rem;border:none;border-radius:6px;background:#ffffff14;color:#f5f5f5;cursor:pointer;font-size:.75rem}.pptx-ng-presenter-navbtn:hover:not(:disabled){background:#ffffff29}.pptx-ng-presenter-navbtn:disabled{opacity:.4;cursor:not-allowed}.pptx-ng-presenter-counter{font-family:ui-monospace,monospace;font-variant-numeric:tabular-nums;font-size:.875rem}.pptx-ng-presenter-next-empty{display:flex;align-items:center;justify-content:center;height:4rem;border:1px solid rgba(255,255,255,.15);border-radius:6px;background:#ffffff0a;font-size:.75rem;font-style:italic;color:#ffffff80}.pptx-ng-presenter-notes{flex:1 1 auto;display:flex;flex-direction:column;min-height:0;padding:.75rem 1rem}.pptx-ng-presenter-notes-head{display:flex;align-items:center;justify-content:space-between;margin-bottom:.5rem}.pptx-ng-presenter-notes-size{display:flex;align-items:center;gap:.25rem}.pptx-ng-presenter-notes-size-value{min-width:28px;text-align:center;font-family:ui-monospace,monospace;font-variant-numeric:tabular-nums;font-size:.625rem;color:#ffffff8c;-webkit-user-select:none;user-select:none}.pptx-ng-presenter-notes-body{flex:1 1 auto;overflow-y:auto;border:1px solid rgba(255,255,255,.15);border-radius:6px;background:#ffffff0a;padding:.5rem .75rem;white-space:pre-wrap;line-height:1.5}.pptx-ng-presenter-notes-empty{font-style:italic;color:#ffffff80}.pptx-ng-presenter-progress{height:6px;width:100%;background:#ffffff1f;flex:0 0 auto}.pptx-ng-presenter-progress-fill{height:100%;background:#6ea8fe;transition:width 1s linear}.pptx-ng-presenter-empty{position:absolute;inset:0;display:flex;align-items:center;justify-content:center;color:#fff9}\n"], dependencies: [{ 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", "snapToShape", "guideCommand", "spellCheck", "snapToGuides", "autoFit", "interactive", "presenting", "selectedIds", "editingId", "editTemplateMode", "templateElements", "aiHighlights", "aiActive", "aiActiveSlideIndex", "aiChangeBatch", "aiPickMode", "drawTool", "drawColor", "drawWidth"], outputs: ["elementSelect", "backgroundClick", "transformStart", "transformUpdate", "contextMenu", "textEditStart", "textCommit", "textCancel", "textFormat", "rotateUpdate", "marqueeSelect", "inkStrokeComplete", "eraserHit", "cellCommit", "tableChange"] }, { kind: "component", type: PresenterControlsComponent, selector: "pptx-presenter-controls", inputs: ["snapshot", "audienceOpen", "slides", "current", "canvasSize", "mediaDataUrls"], outputs: ["patch", "navigate", "audience", "end"] }, { kind: "pipe", type: TranslatePipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
79616
+ `, isInline: true, styles: [":host{position:absolute;inset:0;z-index:50;display:flex;flex-direction:column;background:#0b0b0c;color:#f5f5f5;font-family:system-ui,sans-serif}.pptx-ng-presenter-body{display:flex;flex:1 1 auto;min-height:0}.pptx-ng-presenter-current{flex:7 1 0;display:flex;flex-direction:column;align-items:center;justify-content:center;background:#000;padding:1rem;min-width:0}.pptx-ng-presenter-preview-stage{width:100%;max-width:100%;min-height:0}.pptx-ng-presenter-slide-badge{margin-top:.5rem;font-family:ui-monospace,monospace;font-variant-numeric:tabular-nums;font-size:.75rem;color:#ffffff80;-webkit-user-select:none;user-select:none}.pptx-ng-presenter-side{flex:3 1 0;display:flex;flex-direction:column;background:#18181b;border-left:1px solid rgba(255,255,255,.12);min-width:260px;max-width:440px}.pptx-ng-presenter-header,.pptx-ng-presenter-nav,.pptx-ng-presenter-next{padding:.5rem 1rem;border-bottom:1px solid rgba(255,255,255,.08)}.pptx-ng-presenter-header{display:flex;align-items:center;justify-content:space-between;gap:.5rem}.pptx-ng-presenter-label{font-size:.625rem;text-transform:uppercase;letter-spacing:.06em;color:#ffffff8c}.pptx-ng-presenter-clock{font-family:ui-monospace,monospace;font-variant-numeric:tabular-nums;font-size:1.125rem}.pptx-ng-presenter-elapsed{color:#6ea8fe}.pptx-ng-presenter-iconbtn{display:inline-flex;align-items:center;justify-content:center;width:32px;height:32px;border:none;border-radius:6px;background:transparent;color:#ffffffb3;cursor:pointer;font-size:1rem;line-height:1}.pptx-ng-presenter-iconbtn:hover{background:#ffffff1a;color:#fff}.pptx-ng-presenter-iconbtn:disabled{opacity:.3;cursor:not-allowed}.pptx-ng-presenter-nav{display:flex;align-items:center;justify-content:space-between}.pptx-ng-presenter-navbtn{display:inline-flex;align-items:center;gap:.375rem;padding:.375rem .75rem;border:none;border-radius:6px;background:#ffffff14;color:#f5f5f5;cursor:pointer;font-size:.75rem}.pptx-ng-presenter-navbtn:hover:not(:disabled){background:#ffffff29}.pptx-ng-presenter-navbtn:disabled{opacity:.4;cursor:not-allowed}.pptx-ng-presenter-counter{font-family:ui-monospace,monospace;font-variant-numeric:tabular-nums;font-size:.875rem}.pptx-ng-presenter-next-empty{display:flex;align-items:center;justify-content:center;height:4rem;border:1px solid rgba(255,255,255,.15);border-radius:6px;background:#ffffff0a;font-size:.75rem;font-style:italic;color:#ffffff80}.pptx-ng-presenter-notes{flex:1 1 auto;display:flex;flex-direction:column;min-height:0;padding:.75rem 1rem}.pptx-ng-presenter-notes-head{display:flex;align-items:center;justify-content:space-between;margin-bottom:.5rem}.pptx-ng-presenter-notes-size{display:flex;align-items:center;gap:.25rem}.pptx-ng-presenter-notes-size-value{min-width:28px;text-align:center;font-family:ui-monospace,monospace;font-variant-numeric:tabular-nums;font-size:.625rem;color:#ffffff8c;-webkit-user-select:none;user-select:none}.pptx-ng-presenter-notes-body{flex:1 1 auto;overflow-y:auto;border:1px solid rgba(255,255,255,.15);border-radius:6px;background:#ffffff0a;padding:.5rem .75rem;white-space:pre-wrap;line-height:1.5}.pptx-ng-presenter-notes-empty{font-style:italic;color:#ffffff80}.pptx-ng-presenter-progress{height:6px;width:100%;background:#ffffff1f;flex:0 0 auto}.pptx-ng-presenter-progress-fill{height:100%;background:#6ea8fe;transition:width 1s linear}.pptx-ng-presenter-empty{position:absolute;inset:0;display:flex;align-items:center;justify-content:center;color:#fff9}\n"], dependencies: [{ 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", "snapToShape", "guideCommand", "spellCheck", "snapToGuides", "autoFit", "interactive", "presenting", "selectedIds", "editingId", "editTemplateMode", "templateElements", "aiHighlights", "aiActive", "aiActiveSlideIndex", "aiChangeBatch", "aiPickMode", "drawTool", "drawColor", "drawWidth"], outputs: ["elementSelect", "backgroundClick", "transformStart", "transformUpdate", "contextMenu", "textEditStart", "textCommit", "textInput", "textCancel", "textFormat", "rotateUpdate", "marqueeSelect", "inkStrokeComplete", "eraserHit", "cellCommit", "tableChange"] }, { kind: "component", type: PresenterControlsComponent, selector: "pptx-presenter-controls", inputs: ["snapshot", "audienceOpen", "slides", "current", "canvasSize", "mediaDataUrls"], outputs: ["patch", "navigate", "audience", "end"] }, { kind: "pipe", type: TranslatePipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
79125
79617
  }
79126
79618
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: PresenterViewComponent, decorators: [{
79127
79619
  type: Component,
@@ -83348,7 +83840,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.8", ngImpor
83348
83840
  }], propDecorators: { canEdit: [{ type: i0.Input, args: [{ isSignal: true, alias: "canEdit", required: false }] }], slideIndex: [{ type: i0.Input, args: [{ isSignal: true, alias: "slideIndex", required: false }] }] } });
83349
83841
 
83350
83842
  // Generated by scripts/inline-shared.mjs from package.json. Do not edit.
83351
- const PPTX_ANGULAR_VIEWER_VERSION = "2.0.0";
83843
+ const PPTX_ANGULAR_VIEWER_VERSION = "2.1.0";
83352
83844
 
83353
83845
  /**
83354
83846
  * account-page.component.ts: File > Account content.
@@ -100763,7 +101255,7 @@ class SlideSorterOverlayComponent {
100763
101255
  </div>
100764
101256
  </div>
100765
101257
  </div>
100766
- `, isInline: true, styles: [":host{display:contents}.pptx-ng-sorter-backdrop{position:fixed;inset:0;z-index:50;display:flex;align-items:center;justify-content:center;background:#000000b3;-webkit-backdrop-filter:blur(4px);backdrop-filter:blur(4px)}.pptx-ng-sorter-panel{display:flex;flex-direction:column;width:min(96vw,1200px);max-height:90vh;border-radius:.5rem;background:#1a1a1a;color:#e5e5e5;box-shadow:0 24px 64px #0009;overflow:hidden}.pptx-ng-sorter-header{display:flex;align-items:center;gap:.75rem;padding:.75rem 1.25rem;border-bottom:1px solid rgba(255,255,255,.1);flex-shrink:0}.pptx-ng-sorter-title{margin:0;font-size:.875rem;font-weight:500}.pptx-ng-sorter-count{font-size:.75rem;color:#ffffff80;flex:1}.pptx-ng-sorter-close{display:flex;align-items:center;justify-content:center;width:44px;height:44px;min-width:44px;min-height:44px;padding:0;border:none;border-radius:50%;background:#ffffff1a;color:#e5e5e5;cursor:pointer;transition:background .15s;flex-shrink:0;touch-action:manipulation}.pptx-ng-sorter-close:hover{background:#fff3}.pptx-ng-sorter-grid-scroll{flex:1;overflow-y:auto;padding:1.25rem}.pptx-ng-sorter-grid{display:grid;gap:1rem}.pptx-ng-sorter-cell{display:flex;flex-direction:column;align-items:center;gap:.5rem;padding:.5rem;border:2px solid transparent;border-radius:.375rem;background:transparent;cursor:pointer;transition:border-color .15s,background .15s;color:inherit}.pptx-ng-sorter-cell:hover{background:#ffffff0f;border-color:#fff3}.pptx-ng-sorter-cell.is-active{border-color:#3b82f6;background:#3b82f61a}.pptx-ng-sorter-cell.is-hidden{opacity:.4}.pptx-ng-sorter-thumb-clip{overflow:hidden;border-radius:2px}.pptx-ng-sorter-thumb-clip ::ng-deep .pptx-ng-canvas-wrapper{margin:0!important}.pptx-ng-sorter-index{font-size:.6875rem;color:#ffffff8c;-webkit-user-select:none;user-select:none}\n"], dependencies: [{ 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", "snapToShape", "guideCommand", "spellCheck", "snapToGuides", "autoFit", "interactive", "presenting", "selectedIds", "editingId", "editTemplateMode", "templateElements", "aiHighlights", "aiActive", "aiActiveSlideIndex", "aiChangeBatch", "aiPickMode", "drawTool", "drawColor", "drawWidth"], outputs: ["elementSelect", "backgroundClick", "transformStart", "transformUpdate", "contextMenu", "textEditStart", "textCommit", "textCancel", "textFormat", "rotateUpdate", "marqueeSelect", "inkStrokeComplete", "eraserHit", "cellCommit", "tableChange"] }, { kind: "pipe", type: TranslatePipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
101258
+ `, isInline: true, styles: [":host{display:contents}.pptx-ng-sorter-backdrop{position:fixed;inset:0;z-index:50;display:flex;align-items:center;justify-content:center;background:#000000b3;-webkit-backdrop-filter:blur(4px);backdrop-filter:blur(4px)}.pptx-ng-sorter-panel{display:flex;flex-direction:column;width:min(96vw,1200px);max-height:90vh;border-radius:.5rem;background:#1a1a1a;color:#e5e5e5;box-shadow:0 24px 64px #0009;overflow:hidden}.pptx-ng-sorter-header{display:flex;align-items:center;gap:.75rem;padding:.75rem 1.25rem;border-bottom:1px solid rgba(255,255,255,.1);flex-shrink:0}.pptx-ng-sorter-title{margin:0;font-size:.875rem;font-weight:500}.pptx-ng-sorter-count{font-size:.75rem;color:#ffffff80;flex:1}.pptx-ng-sorter-close{display:flex;align-items:center;justify-content:center;width:44px;height:44px;min-width:44px;min-height:44px;padding:0;border:none;border-radius:50%;background:#ffffff1a;color:#e5e5e5;cursor:pointer;transition:background .15s;flex-shrink:0;touch-action:manipulation}.pptx-ng-sorter-close:hover{background:#fff3}.pptx-ng-sorter-grid-scroll{flex:1;overflow-y:auto;padding:1.25rem}.pptx-ng-sorter-grid{display:grid;gap:1rem}.pptx-ng-sorter-cell{display:flex;flex-direction:column;align-items:center;gap:.5rem;padding:.5rem;border:2px solid transparent;border-radius:.375rem;background:transparent;cursor:pointer;transition:border-color .15s,background .15s;color:inherit}.pptx-ng-sorter-cell:hover{background:#ffffff0f;border-color:#fff3}.pptx-ng-sorter-cell.is-active{border-color:#3b82f6;background:#3b82f61a}.pptx-ng-sorter-cell.is-hidden{opacity:.4}.pptx-ng-sorter-thumb-clip{overflow:hidden;border-radius:2px}.pptx-ng-sorter-thumb-clip ::ng-deep .pptx-ng-canvas-wrapper{margin:0!important}.pptx-ng-sorter-index{font-size:.6875rem;color:#ffffff8c;-webkit-user-select:none;user-select:none}\n"], dependencies: [{ 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", "snapToShape", "guideCommand", "spellCheck", "snapToGuides", "autoFit", "interactive", "presenting", "selectedIds", "editingId", "editTemplateMode", "templateElements", "aiHighlights", "aiActive", "aiActiveSlideIndex", "aiChangeBatch", "aiPickMode", "drawTool", "drawColor", "drawWidth"], outputs: ["elementSelect", "backgroundClick", "transformStart", "transformUpdate", "contextMenu", "textEditStart", "textCommit", "textInput", "textCancel", "textFormat", "rotateUpdate", "marqueeSelect", "inkStrokeComplete", "eraserHit", "cellCommit", "tableChange"] }, { kind: "pipe", type: TranslatePipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
100767
101259
  }
100768
101260
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: SlideSorterOverlayComponent, decorators: [{
100769
101261
  type: Component,
@@ -100980,7 +101472,7 @@ class SlidesPanelComponent {
100980
101472
  return this.editor.sections().findIndex((section) => section.id === sectionId);
100981
101473
  }
100982
101474
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: SlidesPanelComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
100983
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.8", type: SlidesPanelComponent, isStandalone: true, selector: "pptx-slides-panel", inputs: { canvasSize: { classPropertyName: "canvasSize", publicName: "canvasSize", isSignal: true, isRequired: true, transformFunction: null }, mediaDataUrls: { classPropertyName: "mediaDataUrls", publicName: "mediaDataUrls", isSignal: true, isRequired: false, transformFunction: null }, activeIndex: { classPropertyName: "activeIndex", publicName: "activeIndex", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { select: "select" }, viewQueries: [{ propertyName: "scrollViewport", first: true, predicate: ["scrollViewport"], descendants: true, isSignal: true }], ngImport: i0, template: "<div class=\"pptx-ng-spanel\">\n\t<!-- Scrollable slide list -->\n\t<div\n\t\t#scrollViewport\n\t\tclass=\"pptx-ng-spanel-scroll\"\n\t\trole=\"listbox\"\n\t\t[attr.aria-label]=\"'pptx.sections.slides' | translate\"\n\t\t(scroll)=\"onScroll()\"\n\t>\n\t\t<div\n\t\t\tclass=\"pptx-ng-spanel-space\"\n\t\t\t[attr.data-virtualized]=\"shouldVirtualize() ? 'true' : null\"\n\t\t\t[style.height.px]=\"shouldVirtualize() ? virtualRange().totalHeight : null\"\n\t\t>\n\t\t\t<div\n\t\t\t\tclass=\"pptx-ng-spanel-window\"\n\t\t\t\t[class.is-virtualized]=\"shouldVirtualize()\"\n\t\t\t\t[style.top.px]=\"shouldVirtualize() ? virtualRange().offsetY : null\"\n\t\t\t>\n\t\t\t\t@for (item of renderedSlides(); track item.slide.id) {\n\t\t\t\t\t@let slide = item.slide;\n\t\t\t\t\t@let i = item.index;\n\t\t\t\t\t@if (item.sectionStart) {\n\t\t\t\t\t\t<header class=\"pptx-ng-section-header\" [attr.data-section-id]=\"item.section?.id\">\n\t\t\t\t\t\t\t<button\n\t\t\t\t\t\t\t\ttype=\"button\"\n\t\t\t\t\t\t\t\tclass=\"pptx-ng-section-toggle\"\n\t\t\t\t\t\t\t\t[attr.aria-expanded]=\"!item.section?.collapsed\"\n\t\t\t\t\t\t\t\t(click)=\"item.section && editor.sectionOps.toggle(item.section.id)\"\n\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t<span>{{ item.section?.collapsed ? '\u25B8' : '\u25BE' }}</span>\n\t\t\t\t\t\t\t\t<strong>{{\n\t\t\t\t\t\t\t\t\titem.section?.name ?? ('pptx.slides.ungroupedSlides' | translate)\n\t\t\t\t\t\t\t\t}}</strong>\n\t\t\t\t\t\t\t</button>\n\t\t\t\t\t\t\t@if (item.section) {\n\t\t\t\t\t\t\t\t<div class=\"pptx-ng-section-actions\">\n\t\t\t\t\t\t\t\t\t<button\n\t\t\t\t\t\t\t\t\t\ttype=\"button\"\n\t\t\t\t\t\t\t\t\t\tdata-pptx-compact\n\t\t\t\t\t\t\t\t\t\t(click)=\"onRenameSection(item.section.id, item.section.name)\"\n\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t\u270E\n\t\t\t\t\t\t\t\t\t</button>\n\t\t\t\t\t\t\t\t\t<button\n\t\t\t\t\t\t\t\t\t\ttype=\"button\"\n\t\t\t\t\t\t\t\t\t\tdata-pptx-compact\n\t\t\t\t\t\t\t\t\t\t[disabled]=\"sectionIndex(item.section.id) === 0\"\n\t\t\t\t\t\t\t\t\t\t(click)=\"editor.sectionOps.move(item.section.id, 'up')\"\n\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t\u2191\n\t\t\t\t\t\t\t\t\t</button>\n\t\t\t\t\t\t\t\t\t<button\n\t\t\t\t\t\t\t\t\t\ttype=\"button\"\n\t\t\t\t\t\t\t\t\t\tdata-pptx-compact\n\t\t\t\t\t\t\t\t\t\t[disabled]=\"sectionIndex(item.section.id) === editor.sections().length - 1\"\n\t\t\t\t\t\t\t\t\t\t(click)=\"editor.sectionOps.move(item.section.id, 'down')\"\n\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t\u2193\n\t\t\t\t\t\t\t\t\t</button>\n\t\t\t\t\t\t\t\t\t<button\n\t\t\t\t\t\t\t\t\t\ttype=\"button\"\n\t\t\t\t\t\t\t\t\t\tdata-pptx-compact\n\t\t\t\t\t\t\t\t\t\t(click)=\"editor.sectionOps.delete(item.section.id)\"\n\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t\u00D7\n\t\t\t\t\t\t\t\t\t</button>\n\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t</header>\n\t\t\t\t\t}\n\t\t\t\t\t@if (!item.section?.collapsed) {\n\t\t\t\t\t\t<div\n\t\t\t\t\t\t\tclass=\"pptx-ng-spanel-card\"\n\t\t\t\t\t\t\t[class.is-active]=\"i === activeIndex()\"\n\t\t\t\t\t\t\trole=\"option\"\n\t\t\t\t\t\t\t[attr.aria-selected]=\"i === activeIndex()\"\n\t\t\t\t\t\t\t[attr.aria-label]=\"'pptx.notes.slideN' | translate: { n: i + 1 }\"\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\t<!-- Thumbnail (clickable to select). Slide number sits to the LEFT\n\t\t\t\t\t\t\t of the preview (React SlideItem parity), not below it. -->\n\t\t\t\t\t\t\t<button\n\t\t\t\t\t\t\t\ttype=\"button\"\n\t\t\t\t\t\t\t\tclass=\"pptx-ng-spanel-thumb-btn\"\n\t\t\t\t\t\t\t\t[attr.aria-label]=\"'pptx.slidesPanel.goToSlide' | translate: { n: i + 1 }\"\n\t\t\t\t\t\t\t\t(click)=\"select.emit(i)\"\n\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t<!-- Slide number badge (left column) -->\n\t\t\t\t\t\t\t\t<span class=\"pptx-ng-spanel-num\" aria-hidden=\"true\">{{ i + 1 }}</span>\n\n\t\t\t\t\t\t\t\t<!-- Clipping wrapper: neutralises the 1rem auto margin from SlideCanvas -->\n\t\t\t\t\t\t\t\t<div class=\"pptx-ng-spanel-clip\" [ngStyle]=\"clipStyle()\">\n\t\t\t\t\t\t\t\t\t<pptx-slide-canvas\n\t\t\t\t\t\t\t\t\t\t[slide]=\"slide\"\n\t\t\t\t\t\t\t\t\t\t[templateElements]=\"editor.templateElementsBySlideId()[slide.id] ?? []\"\n\t\t\t\t\t\t\t\t\t\t[canvasSize]=\"canvasSize()\"\n\t\t\t\t\t\t\t\t\t\t[mediaDataUrls]=\"mediaDataUrls()\"\n\t\t\t\t\t\t\t\t\t\t[zoom]=\"thumbZoom()\"\n\t\t\t\t\t\t\t\t\t\t[editable]=\"false\"\n\t\t\t\t\t\t\t\t\t\t[autoFit]=\"false\"\n\t\t\t\t\t\t\t\t\t\t[interactive]=\"false\"\n\t\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t</button>\n\n\t\t\t\t\t\t\t<!-- Per-card action toolbar (visible on hover / focus-within) -->\n\t\t\t\t\t\t\t<div\n\t\t\t\t\t\t\t\tclass=\"pptx-ng-spanel-actions\"\n\t\t\t\t\t\t\t\trole=\"toolbar\"\n\t\t\t\t\t\t\t\t[attr.aria-label]=\"'pptx.slideMenu.slideActions' | translate: { n: i + 1 }\"\n\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t<button\n\t\t\t\t\t\t\t\t\ttype=\"button\"\n\t\t\t\t\t\t\t\t\tclass=\"pptx-ng-spanel-action\"\n\t\t\t\t\t\t\t\t\tdata-pptx-compact\n\t\t\t\t\t\t\t\t\t[title]=\"'pptx.ribbon.duplicateSlide' | translate\"\n\t\t\t\t\t\t\t\t\t[attr.aria-label]=\"'pptx.arrange.duplicate' | translate\"\n\t\t\t\t\t\t\t\t\t(click)=\"onDuplicate(i)\"\n\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t<svg lucideCopy class=\"h-3.5 w-3.5\"></svg>\n\t\t\t\t\t\t\t\t</button>\n\t\t\t\t\t\t\t\t<button\n\t\t\t\t\t\t\t\t\ttype=\"button\"\n\t\t\t\t\t\t\t\t\tclass=\"pptx-ng-spanel-action\"\n\t\t\t\t\t\t\t\t\tdata-pptx-compact\n\t\t\t\t\t\t\t\t\t[title]=\"'pptx.slidesPanel.deleteSlide' | translate\"\n\t\t\t\t\t\t\t\t\t[attr.aria-label]=\"'pptx.arrange.delete' | translate\"\n\t\t\t\t\t\t\t\t\t[disabled]=\"editor.slides().length <= 1\"\n\t\t\t\t\t\t\t\t\t(click)=\"onDelete(i)\"\n\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t<svg lucideTrash2 class=\"h-3.5 w-3.5\"></svg>\n\t\t\t\t\t\t\t\t</button>\n\t\t\t\t\t\t\t\t<button\n\t\t\t\t\t\t\t\t\ttype=\"button\"\n\t\t\t\t\t\t\t\t\tclass=\"pptx-ng-spanel-action\"\n\t\t\t\t\t\t\t\t\tdata-pptx-compact\n\t\t\t\t\t\t\t\t\t[title]=\"'pptx.sections.moveUp' | translate\"\n\t\t\t\t\t\t\t\t\t[attr.aria-label]=\"'pptx.sections.moveUp' | translate\"\n\t\t\t\t\t\t\t\t\t[disabled]=\"i === 0\"\n\t\t\t\t\t\t\t\t\t(click)=\"onMoveUp(i)\"\n\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t<svg lucideArrowUp class=\"h-3.5 w-3.5\"></svg>\n\t\t\t\t\t\t\t\t</button>\n\t\t\t\t\t\t\t\t<button\n\t\t\t\t\t\t\t\t\ttype=\"button\"\n\t\t\t\t\t\t\t\t\tclass=\"pptx-ng-spanel-action\"\n\t\t\t\t\t\t\t\t\tdata-pptx-compact\n\t\t\t\t\t\t\t\t\t[title]=\"'pptx.sections.moveDown' | translate\"\n\t\t\t\t\t\t\t\t\t[attr.aria-label]=\"'pptx.sections.moveDown' | translate\"\n\t\t\t\t\t\t\t\t\t[disabled]=\"i === editor.slides().length - 1\"\n\t\t\t\t\t\t\t\t\t(click)=\"onMoveDown(i)\"\n\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t<svg lucideArrowDown class=\"h-3.5 w-3.5\"></svg>\n\t\t\t\t\t\t\t\t</button>\n\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t</div>\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t</div>\n\t\t</div>\n\t</div>\n\n\t<!-- Footer: add new slide -->\n\t<footer class=\"pptx-ng-spanel-footer\">\n\t\t<button\n\t\t\ttype=\"button\"\n\t\t\tclass=\"pptx-ng-spanel-add\"\n\t\t\t[attr.aria-label]=\"'pptx.sections.addSlide' | translate\"\n\t\t\t(click)=\"onAddSlide()\"\n\t\t>\n\t\t\t<svg lucidePlus class=\"h-3.5 w-3.5\"></svg> {{ 'pptx.sections.addSlide' | translate }}\n\t\t</button>\n\t</footer>\n</div>\n", styles: [":host{display:flex;flex-direction:column;height:100%;overflow:hidden}.pptx-ng-spanel{display:flex;flex-direction:column;height:100%;background:var(--pptx-secondary, #1e1e1e);color:var(--pptx-foreground, #e5e5e5);border-right:1px solid var(--pptx-border, rgba(255, 255, 255, .08));overflow:hidden}.pptx-ng-spanel-scroll{flex:1;overflow-y:auto;padding:.5rem .375rem}.pptx-ng-spanel-space{position:relative}.pptx-ng-spanel-window{display:flex;flex-direction:column;gap:.375rem}.pptx-ng-spanel-window.is-virtualized{position:absolute;inset-inline:0}.pptx-ng-section-header{display:flex;align-items:center;gap:.2rem;min-height:1.75rem;color:var(--pptx-muted-foreground, rgba(255, 255, 255, .58))}.pptx-ng-section-toggle{display:flex;align-items:center;gap:.35rem;min-width:0;flex:1;border:0;background:transparent;color:inherit;cursor:pointer;text-align:left}.pptx-ng-section-toggle strong{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-size:.7rem}.pptx-ng-section-actions{display:flex}.pptx-ng-section-actions button{width:1.25rem;height:1.25rem;padding:0;border:0;border-radius:.2rem;background:transparent;color:inherit;cursor:pointer}.pptx-ng-section-actions button:hover:not(:disabled){background:color-mix(in srgb,var(--pptx-primary, #3b82f6) 35%,transparent);color:var(--pptx-foreground, #fff)}.pptx-ng-section-actions button:disabled{opacity:.3}.pptx-ng-spanel-card{position:relative;border-radius:.375rem;border:2px solid transparent;background:transparent;transition:border-color .15s,background .15s}.pptx-ng-spanel-card:hover,.pptx-ng-spanel-card:focus-within{background:color-mix(in srgb,var(--pptx-foreground, #fff) 5%,transparent);border-color:color-mix(in srgb,var(--pptx-foreground, #fff) 15%,transparent)}.pptx-ng-spanel-card.is-active{border-color:var(--pptx-primary, #3b82f6);background:color-mix(in srgb,var(--pptx-primary, #3b82f6) 10%,transparent)}.pptx-ng-spanel-thumb-btn{display:flex;align-items:center;gap:.25rem;width:100%;padding:.375rem;border:none;background:transparent;cursor:pointer;color:inherit;line-height:0}.pptx-ng-spanel-thumb-btn:focus-visible{outline:2px solid var(--pptx-ring, #3b82f6);outline-offset:2px;border-radius:.25rem}.pptx-ng-spanel-clip{overflow:hidden;border-radius:2px}.pptx-ng-spanel-clip ::ng-deep .pptx-ng-canvas-wrapper{margin:0!important}.pptx-ng-spanel-num{flex:0 0 auto;width:1.1rem;text-align:right;font-size:.625rem;line-height:1;font-variant-numeric:tabular-nums;color:var(--pptx-muted-foreground, rgba(255, 255, 255, .45));-webkit-user-select:none;user-select:none}.pptx-ng-spanel-card.is-active .pptx-ng-spanel-num{color:var(--pptx-primary, #3b82f6);font-weight:500}.pptx-ng-spanel-actions{position:absolute;top:.25rem;right:.25rem;display:flex;flex-direction:column;gap:.125rem;opacity:0;pointer-events:none;transition:opacity .12s}.pptx-ng-spanel-card:hover .pptx-ng-spanel-actions,.pptx-ng-spanel-card:focus-within .pptx-ng-spanel-actions{opacity:1;pointer-events:auto}.pptx-ng-spanel-action{display:flex;align-items:center;justify-content:center;width:1.375rem;height:1.375rem;padding:0;border:none;border-radius:.25rem;background:color-mix(in srgb,var(--pptx-popover, #1e1e1e) 85%,transparent);color:var(--pptx-popover-foreground, #e5e5e5);font-size:.6875rem;cursor:pointer;transition:background .12s;-webkit-backdrop-filter:blur(2px);backdrop-filter:blur(2px)}.pptx-ng-spanel-action:hover:not([disabled]){background:color-mix(in srgb,var(--pptx-primary, #3b82f6) 75%,transparent);color:var(--pptx-primary-foreground, #fff)}.pptx-ng-spanel-action[disabled]{opacity:.3;cursor:not-allowed}.pptx-ng-spanel-footer{flex-shrink:0;padding:.5rem .375rem;border-top:1px solid var(--pptx-border, rgba(255, 255, 255, .08))}.pptx-ng-spanel-add{display:flex;align-items:center;justify-content:center;gap:.25rem;width:100%;padding:.25rem .5rem;border:none;border-radius:.25rem;background:transparent;color:var(--pptx-muted-foreground, rgba(255, 255, 255, .6));font-size:.6875rem;cursor:pointer;transition:background .15s,color .15s}.pptx-ng-spanel-add:hover{background:color-mix(in srgb,var(--pptx-foreground, #fff) 8%,transparent);color:var(--pptx-foreground, #e5e5e5)}\n"], dependencies: [{ 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", "snapToShape", "guideCommand", "spellCheck", "snapToGuides", "autoFit", "interactive", "presenting", "selectedIds", "editingId", "editTemplateMode", "templateElements", "aiHighlights", "aiActive", "aiActiveSlideIndex", "aiChangeBatch", "aiPickMode", "drawTool", "drawColor", "drawWidth"], outputs: ["elementSelect", "backgroundClick", "transformStart", "transformUpdate", "contextMenu", "textEditStart", "textCommit", "textCancel", "textFormat", "rotateUpdate", "marqueeSelect", "inkStrokeComplete", "eraserHit", "cellCommit", "tableChange"] }, { kind: "component", type: LucideCopy, selector: "svg[lucideCopy]" }, { kind: "component", type: LucideTrash2, selector: "svg[lucideTrash2]" }, { kind: "component", type: LucideArrowUp, selector: "svg[lucideArrowUp]" }, { kind: "component", type: LucideArrowDown, selector: "svg[lucideArrowDown]" }, { kind: "component", type: LucidePlus, selector: "svg[lucidePlus]" }, { kind: "pipe", type: TranslatePipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
101475
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.8", type: SlidesPanelComponent, isStandalone: true, selector: "pptx-slides-panel", inputs: { canvasSize: { classPropertyName: "canvasSize", publicName: "canvasSize", isSignal: true, isRequired: true, transformFunction: null }, mediaDataUrls: { classPropertyName: "mediaDataUrls", publicName: "mediaDataUrls", isSignal: true, isRequired: false, transformFunction: null }, activeIndex: { classPropertyName: "activeIndex", publicName: "activeIndex", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { select: "select" }, viewQueries: [{ propertyName: "scrollViewport", first: true, predicate: ["scrollViewport"], descendants: true, isSignal: true }], ngImport: i0, template: "<div class=\"pptx-ng-spanel\">\n\t<!-- Scrollable slide list -->\n\t<div\n\t\t#scrollViewport\n\t\tclass=\"pptx-ng-spanel-scroll\"\n\t\trole=\"listbox\"\n\t\t[attr.aria-label]=\"'pptx.sections.slides' | translate\"\n\t\t(scroll)=\"onScroll()\"\n\t>\n\t\t<div\n\t\t\tclass=\"pptx-ng-spanel-space\"\n\t\t\t[attr.data-virtualized]=\"shouldVirtualize() ? 'true' : null\"\n\t\t\t[style.height.px]=\"shouldVirtualize() ? virtualRange().totalHeight : null\"\n\t\t>\n\t\t\t<div\n\t\t\t\tclass=\"pptx-ng-spanel-window\"\n\t\t\t\t[class.is-virtualized]=\"shouldVirtualize()\"\n\t\t\t\t[style.top.px]=\"shouldVirtualize() ? virtualRange().offsetY : null\"\n\t\t\t>\n\t\t\t\t@for (item of renderedSlides(); track item.slide.id) {\n\t\t\t\t\t@let slide = item.slide;\n\t\t\t\t\t@let i = item.index;\n\t\t\t\t\t@if (item.sectionStart) {\n\t\t\t\t\t\t<header class=\"pptx-ng-section-header\" [attr.data-section-id]=\"item.section?.id\">\n\t\t\t\t\t\t\t<button\n\t\t\t\t\t\t\t\ttype=\"button\"\n\t\t\t\t\t\t\t\tclass=\"pptx-ng-section-toggle\"\n\t\t\t\t\t\t\t\t[attr.aria-expanded]=\"!item.section?.collapsed\"\n\t\t\t\t\t\t\t\t(click)=\"item.section && editor.sectionOps.toggle(item.section.id)\"\n\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t<span>{{ item.section?.collapsed ? '\u25B8' : '\u25BE' }}</span>\n\t\t\t\t\t\t\t\t<strong>{{\n\t\t\t\t\t\t\t\t\titem.section?.name ?? ('pptx.slides.ungroupedSlides' | translate)\n\t\t\t\t\t\t\t\t}}</strong>\n\t\t\t\t\t\t\t</button>\n\t\t\t\t\t\t\t@if (item.section) {\n\t\t\t\t\t\t\t\t<div class=\"pptx-ng-section-actions\">\n\t\t\t\t\t\t\t\t\t<button\n\t\t\t\t\t\t\t\t\t\ttype=\"button\"\n\t\t\t\t\t\t\t\t\t\tdata-pptx-compact\n\t\t\t\t\t\t\t\t\t\t(click)=\"onRenameSection(item.section.id, item.section.name)\"\n\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t\u270E\n\t\t\t\t\t\t\t\t\t</button>\n\t\t\t\t\t\t\t\t\t<button\n\t\t\t\t\t\t\t\t\t\ttype=\"button\"\n\t\t\t\t\t\t\t\t\t\tdata-pptx-compact\n\t\t\t\t\t\t\t\t\t\t[disabled]=\"sectionIndex(item.section.id) === 0\"\n\t\t\t\t\t\t\t\t\t\t(click)=\"editor.sectionOps.move(item.section.id, 'up')\"\n\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t\u2191\n\t\t\t\t\t\t\t\t\t</button>\n\t\t\t\t\t\t\t\t\t<button\n\t\t\t\t\t\t\t\t\t\ttype=\"button\"\n\t\t\t\t\t\t\t\t\t\tdata-pptx-compact\n\t\t\t\t\t\t\t\t\t\t[disabled]=\"sectionIndex(item.section.id) === editor.sections().length - 1\"\n\t\t\t\t\t\t\t\t\t\t(click)=\"editor.sectionOps.move(item.section.id, 'down')\"\n\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t\u2193\n\t\t\t\t\t\t\t\t\t</button>\n\t\t\t\t\t\t\t\t\t<button\n\t\t\t\t\t\t\t\t\t\ttype=\"button\"\n\t\t\t\t\t\t\t\t\t\tdata-pptx-compact\n\t\t\t\t\t\t\t\t\t\t(click)=\"editor.sectionOps.delete(item.section.id)\"\n\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t\u00D7\n\t\t\t\t\t\t\t\t\t</button>\n\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t</header>\n\t\t\t\t\t}\n\t\t\t\t\t@if (!item.section?.collapsed) {\n\t\t\t\t\t\t<div\n\t\t\t\t\t\t\tclass=\"pptx-ng-spanel-card\"\n\t\t\t\t\t\t\t[class.is-active]=\"i === activeIndex()\"\n\t\t\t\t\t\t\trole=\"option\"\n\t\t\t\t\t\t\t[attr.aria-selected]=\"i === activeIndex()\"\n\t\t\t\t\t\t\t[attr.aria-label]=\"'pptx.notes.slideN' | translate: { n: i + 1 }\"\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\t<!-- Thumbnail (clickable to select). Slide number sits to the LEFT\n\t\t\t\t\t\t\t of the preview (React SlideItem parity), not below it. -->\n\t\t\t\t\t\t\t<button\n\t\t\t\t\t\t\t\ttype=\"button\"\n\t\t\t\t\t\t\t\tclass=\"pptx-ng-spanel-thumb-btn\"\n\t\t\t\t\t\t\t\t[attr.aria-label]=\"'pptx.slidesPanel.goToSlide' | translate: { n: i + 1 }\"\n\t\t\t\t\t\t\t\t(click)=\"select.emit(i)\"\n\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t<!-- Slide number badge (left column) -->\n\t\t\t\t\t\t\t\t<span class=\"pptx-ng-spanel-num\" aria-hidden=\"true\">{{ i + 1 }}</span>\n\n\t\t\t\t\t\t\t\t<!-- Clipping wrapper: neutralises the 1rem auto margin from SlideCanvas -->\n\t\t\t\t\t\t\t\t<div class=\"pptx-ng-spanel-clip\" [ngStyle]=\"clipStyle()\">\n\t\t\t\t\t\t\t\t\t<pptx-slide-canvas\n\t\t\t\t\t\t\t\t\t\t[slide]=\"slide\"\n\t\t\t\t\t\t\t\t\t\t[templateElements]=\"editor.templateElementsBySlideId()[slide.id] ?? []\"\n\t\t\t\t\t\t\t\t\t\t[canvasSize]=\"canvasSize()\"\n\t\t\t\t\t\t\t\t\t\t[mediaDataUrls]=\"mediaDataUrls()\"\n\t\t\t\t\t\t\t\t\t\t[zoom]=\"thumbZoom()\"\n\t\t\t\t\t\t\t\t\t\t[editable]=\"false\"\n\t\t\t\t\t\t\t\t\t\t[autoFit]=\"false\"\n\t\t\t\t\t\t\t\t\t\t[interactive]=\"false\"\n\t\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t</button>\n\n\t\t\t\t\t\t\t<!-- Per-card action toolbar (visible on hover / focus-within) -->\n\t\t\t\t\t\t\t<div\n\t\t\t\t\t\t\t\tclass=\"pptx-ng-spanel-actions\"\n\t\t\t\t\t\t\t\trole=\"toolbar\"\n\t\t\t\t\t\t\t\t[attr.aria-label]=\"'pptx.slideMenu.slideActions' | translate: { n: i + 1 }\"\n\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t<button\n\t\t\t\t\t\t\t\t\ttype=\"button\"\n\t\t\t\t\t\t\t\t\tclass=\"pptx-ng-spanel-action\"\n\t\t\t\t\t\t\t\t\tdata-pptx-compact\n\t\t\t\t\t\t\t\t\t[title]=\"'pptx.ribbon.duplicateSlide' | translate\"\n\t\t\t\t\t\t\t\t\t[attr.aria-label]=\"'pptx.arrange.duplicate' | translate\"\n\t\t\t\t\t\t\t\t\t(click)=\"onDuplicate(i)\"\n\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t<svg lucideCopy class=\"h-3.5 w-3.5\"></svg>\n\t\t\t\t\t\t\t\t</button>\n\t\t\t\t\t\t\t\t<button\n\t\t\t\t\t\t\t\t\ttype=\"button\"\n\t\t\t\t\t\t\t\t\tclass=\"pptx-ng-spanel-action\"\n\t\t\t\t\t\t\t\t\tdata-pptx-compact\n\t\t\t\t\t\t\t\t\t[title]=\"'pptx.slidesPanel.deleteSlide' | translate\"\n\t\t\t\t\t\t\t\t\t[attr.aria-label]=\"'pptx.arrange.delete' | translate\"\n\t\t\t\t\t\t\t\t\t[disabled]=\"editor.slides().length <= 1\"\n\t\t\t\t\t\t\t\t\t(click)=\"onDelete(i)\"\n\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t<svg lucideTrash2 class=\"h-3.5 w-3.5\"></svg>\n\t\t\t\t\t\t\t\t</button>\n\t\t\t\t\t\t\t\t<button\n\t\t\t\t\t\t\t\t\ttype=\"button\"\n\t\t\t\t\t\t\t\t\tclass=\"pptx-ng-spanel-action\"\n\t\t\t\t\t\t\t\t\tdata-pptx-compact\n\t\t\t\t\t\t\t\t\t[title]=\"'pptx.sections.moveUp' | translate\"\n\t\t\t\t\t\t\t\t\t[attr.aria-label]=\"'pptx.sections.moveUp' | translate\"\n\t\t\t\t\t\t\t\t\t[disabled]=\"i === 0\"\n\t\t\t\t\t\t\t\t\t(click)=\"onMoveUp(i)\"\n\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t<svg lucideArrowUp class=\"h-3.5 w-3.5\"></svg>\n\t\t\t\t\t\t\t\t</button>\n\t\t\t\t\t\t\t\t<button\n\t\t\t\t\t\t\t\t\ttype=\"button\"\n\t\t\t\t\t\t\t\t\tclass=\"pptx-ng-spanel-action\"\n\t\t\t\t\t\t\t\t\tdata-pptx-compact\n\t\t\t\t\t\t\t\t\t[title]=\"'pptx.sections.moveDown' | translate\"\n\t\t\t\t\t\t\t\t\t[attr.aria-label]=\"'pptx.sections.moveDown' | translate\"\n\t\t\t\t\t\t\t\t\t[disabled]=\"i === editor.slides().length - 1\"\n\t\t\t\t\t\t\t\t\t(click)=\"onMoveDown(i)\"\n\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t<svg lucideArrowDown class=\"h-3.5 w-3.5\"></svg>\n\t\t\t\t\t\t\t\t</button>\n\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t</div>\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t</div>\n\t\t</div>\n\t</div>\n\n\t<!-- Footer: add new slide -->\n\t<footer class=\"pptx-ng-spanel-footer\">\n\t\t<button\n\t\t\ttype=\"button\"\n\t\t\tclass=\"pptx-ng-spanel-add\"\n\t\t\t[attr.aria-label]=\"'pptx.sections.addSlide' | translate\"\n\t\t\t(click)=\"onAddSlide()\"\n\t\t>\n\t\t\t<svg lucidePlus class=\"h-3.5 w-3.5\"></svg> {{ 'pptx.sections.addSlide' | translate }}\n\t\t</button>\n\t</footer>\n</div>\n", styles: [":host{display:flex;flex-direction:column;height:100%;overflow:hidden}.pptx-ng-spanel{display:flex;flex-direction:column;height:100%;background:var(--pptx-secondary, #1e1e1e);color:var(--pptx-foreground, #e5e5e5);border-right:1px solid var(--pptx-border, rgba(255, 255, 255, .08));overflow:hidden}.pptx-ng-spanel-scroll{flex:1;overflow-y:auto;padding:.5rem .375rem}.pptx-ng-spanel-space{position:relative}.pptx-ng-spanel-window{display:flex;flex-direction:column;gap:.375rem}.pptx-ng-spanel-window.is-virtualized{position:absolute;inset-inline:0}.pptx-ng-section-header{display:flex;align-items:center;gap:.2rem;min-height:1.75rem;color:var(--pptx-muted-foreground, rgba(255, 255, 255, .58))}.pptx-ng-section-toggle{display:flex;align-items:center;gap:.35rem;min-width:0;flex:1;border:0;background:transparent;color:inherit;cursor:pointer;text-align:left}.pptx-ng-section-toggle strong{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-size:.7rem}.pptx-ng-section-actions{display:flex}.pptx-ng-section-actions button{width:1.25rem;height:1.25rem;padding:0;border:0;border-radius:.2rem;background:transparent;color:inherit;cursor:pointer}.pptx-ng-section-actions button:hover:not(:disabled){background:color-mix(in srgb,var(--pptx-primary, #3b82f6) 35%,transparent);color:var(--pptx-foreground, #fff)}.pptx-ng-section-actions button:disabled{opacity:.3}.pptx-ng-spanel-card{position:relative;border-radius:.375rem;border:2px solid transparent;background:transparent;transition:border-color .15s,background .15s}.pptx-ng-spanel-card:hover,.pptx-ng-spanel-card:focus-within{background:color-mix(in srgb,var(--pptx-foreground, #fff) 5%,transparent);border-color:color-mix(in srgb,var(--pptx-foreground, #fff) 15%,transparent)}.pptx-ng-spanel-card.is-active{border-color:var(--pptx-primary, #3b82f6);background:color-mix(in srgb,var(--pptx-primary, #3b82f6) 10%,transparent)}.pptx-ng-spanel-thumb-btn{display:flex;align-items:center;gap:.25rem;width:100%;padding:.375rem;border:none;background:transparent;cursor:pointer;color:inherit;line-height:0}.pptx-ng-spanel-thumb-btn:focus-visible{outline:2px solid var(--pptx-ring, #3b82f6);outline-offset:2px;border-radius:.25rem}.pptx-ng-spanel-clip{overflow:hidden;border-radius:2px}.pptx-ng-spanel-clip ::ng-deep .pptx-ng-canvas-wrapper{margin:0!important}.pptx-ng-spanel-num{flex:0 0 auto;width:1.1rem;text-align:right;font-size:.625rem;line-height:1;font-variant-numeric:tabular-nums;color:var(--pptx-muted-foreground, rgba(255, 255, 255, .45));-webkit-user-select:none;user-select:none}.pptx-ng-spanel-card.is-active .pptx-ng-spanel-num{color:var(--pptx-primary, #3b82f6);font-weight:500}.pptx-ng-spanel-actions{position:absolute;top:.25rem;right:.25rem;display:flex;flex-direction:column;gap:.125rem;opacity:0;pointer-events:none;transition:opacity .12s}.pptx-ng-spanel-card:hover .pptx-ng-spanel-actions,.pptx-ng-spanel-card:focus-within .pptx-ng-spanel-actions{opacity:1;pointer-events:auto}.pptx-ng-spanel-action{display:flex;align-items:center;justify-content:center;width:1.375rem;height:1.375rem;padding:0;border:none;border-radius:.25rem;background:color-mix(in srgb,var(--pptx-popover, #1e1e1e) 85%,transparent);color:var(--pptx-popover-foreground, #e5e5e5);font-size:.6875rem;cursor:pointer;transition:background .12s;-webkit-backdrop-filter:blur(2px);backdrop-filter:blur(2px)}.pptx-ng-spanel-action:hover:not([disabled]){background:color-mix(in srgb,var(--pptx-primary, #3b82f6) 75%,transparent);color:var(--pptx-primary-foreground, #fff)}.pptx-ng-spanel-action[disabled]{opacity:.3;cursor:not-allowed}.pptx-ng-spanel-footer{flex-shrink:0;padding:.5rem .375rem;border-top:1px solid var(--pptx-border, rgba(255, 255, 255, .08))}.pptx-ng-spanel-add{display:flex;align-items:center;justify-content:center;gap:.25rem;width:100%;padding:.25rem .5rem;border:none;border-radius:.25rem;background:transparent;color:var(--pptx-muted-foreground, rgba(255, 255, 255, .6));font-size:.6875rem;cursor:pointer;transition:background .15s,color .15s}.pptx-ng-spanel-add:hover{background:color-mix(in srgb,var(--pptx-foreground, #fff) 8%,transparent);color:var(--pptx-foreground, #e5e5e5)}\n"], dependencies: [{ 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", "snapToShape", "guideCommand", "spellCheck", "snapToGuides", "autoFit", "interactive", "presenting", "selectedIds", "editingId", "editTemplateMode", "templateElements", "aiHighlights", "aiActive", "aiActiveSlideIndex", "aiChangeBatch", "aiPickMode", "drawTool", "drawColor", "drawWidth"], outputs: ["elementSelect", "backgroundClick", "transformStart", "transformUpdate", "contextMenu", "textEditStart", "textCommit", "textInput", "textCancel", "textFormat", "rotateUpdate", "marqueeSelect", "inkStrokeComplete", "eraserHit", "cellCommit", "tableChange"] }, { kind: "component", type: LucideCopy, selector: "svg[lucideCopy]" }, { kind: "component", type: LucideTrash2, selector: "svg[lucideTrash2]" }, { kind: "component", type: LucideArrowUp, selector: "svg[lucideArrowUp]" }, { kind: "component", type: LucideArrowDown, selector: "svg[lucideArrowDown]" }, { kind: "component", type: LucidePlus, selector: "svg[lucidePlus]" }, { kind: "pipe", type: TranslatePipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
100984
101476
  }
100985
101477
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: SlidesPanelComponent, decorators: [{
100986
101478
  type: Component,
@@ -102465,7 +102957,7 @@ class SlideDiffThumbnailsComponent {
102465
102957
  </div>
102466
102958
  }
102467
102959
  </div>
102468
- `, isInline: true, styles: [".pptx-ng-diff-thumbs{display:flex;gap:.5rem}.pptx-ng-diff-thumb-col{flex:1}.pptx-ng-diff-thumb-label{margin-bottom:.25rem;font-size:.625rem;color:var(--pptx-muted-foreground, #9ca3af)}.pptx-ng-diff-thumb-clip{overflow:hidden;border:1px solid var(--pptx-border, #374151);border-radius:.25rem}.pptx-ng-diff-thumb-clip[data-status=added]{border-color:#15803d99}.pptx-ng-diff-thumb-clip[data-status=changed]{border-color:#b4530999}.pptx-ng-diff-thumb-clip ::ng-deep .pptx-ng-canvas-wrapper{margin:0!important}\n"], dependencies: [{ kind: "component", type: SlideCanvasComponent, selector: "pptx-slide-canvas", inputs: ["slide", "canvasSize", "mediaDataUrls", "zoom", "editable", "showGrid", "showRulers", "showGuides", "snapToGrid", "snapToShape", "guideCommand", "spellCheck", "snapToGuides", "autoFit", "interactive", "presenting", "selectedIds", "editingId", "editTemplateMode", "templateElements", "aiHighlights", "aiActive", "aiActiveSlideIndex", "aiChangeBatch", "aiPickMode", "drawTool", "drawColor", "drawWidth"], outputs: ["elementSelect", "backgroundClick", "transformStart", "transformUpdate", "contextMenu", "textEditStart", "textCommit", "textCancel", "textFormat", "rotateUpdate", "marqueeSelect", "inkStrokeComplete", "eraserHit", "cellCommit", "tableChange"] }, { kind: "pipe", type: TranslatePipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
102960
+ `, isInline: true, styles: [".pptx-ng-diff-thumbs{display:flex;gap:.5rem}.pptx-ng-diff-thumb-col{flex:1}.pptx-ng-diff-thumb-label{margin-bottom:.25rem;font-size:.625rem;color:var(--pptx-muted-foreground, #9ca3af)}.pptx-ng-diff-thumb-clip{overflow:hidden;border:1px solid var(--pptx-border, #374151);border-radius:.25rem}.pptx-ng-diff-thumb-clip[data-status=added]{border-color:#15803d99}.pptx-ng-diff-thumb-clip[data-status=changed]{border-color:#b4530999}.pptx-ng-diff-thumb-clip ::ng-deep .pptx-ng-canvas-wrapper{margin:0!important}\n"], dependencies: [{ kind: "component", type: SlideCanvasComponent, selector: "pptx-slide-canvas", inputs: ["slide", "canvasSize", "mediaDataUrls", "zoom", "editable", "showGrid", "showRulers", "showGuides", "snapToGrid", "snapToShape", "guideCommand", "spellCheck", "snapToGuides", "autoFit", "interactive", "presenting", "selectedIds", "editingId", "editTemplateMode", "templateElements", "aiHighlights", "aiActive", "aiActiveSlideIndex", "aiChangeBatch", "aiPickMode", "drawTool", "drawColor", "drawWidth"], outputs: ["elementSelect", "backgroundClick", "transformStart", "transformUpdate", "contextMenu", "textEditStart", "textCommit", "textInput", "textCancel", "textFormat", "rotateUpdate", "marqueeSelect", "inkStrokeComplete", "eraserHit", "cellCommit", "tableChange"] }, { kind: "pipe", type: TranslatePipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
102469
102961
  }
102470
102962
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: SlideDiffThumbnailsComponent, decorators: [{
102471
102963
  type: Component,
@@ -109016,6 +109508,7 @@ class PowerPointViewerComponent {
109016
109508
  (contextMenu)="canvasEditing.onContextMenu($event)"
109017
109509
  [editingId]="canvasEditing.editingId()"
109018
109510
  (textEditStart)="canvasEditing.onTextEditStart($event.id)"
109511
+ (textInput)="canvasEditing.onTextInput($event)"
109019
109512
  (textCommit)="canvasEditing.onTextCommit($event)"
109020
109513
  (textCancel)="canvasEditing.editingId.set(null)"
109021
109514
  (textFormat)="canvasEditing.onTextFormat($event)"
@@ -109522,7 +110015,7 @@ class PowerPointViewerComponent {
109522
110015
  />
109523
110016
  }
109524
110017
  </div>
109525
- `, 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", "snapToShape", "guideCommand", "spellCheck", "snapToGuides", "autoFit", "interactive", "presenting", "selectedIds", "editingId", "editTemplateMode", "templateElements", "aiHighlights", "aiActive", "aiActiveSlideIndex", "aiChangeBatch", "aiPickMode", "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", "showWithAnimation", "subtitlesVisible"], outputs: ["indexChange", "closed", "subtitlesChange", "annotationsExit"] }, { kind: "component", type: PresenterViewComponent, selector: "pptx-presenter-view", inputs: ["slides", "currentSlideIndex", "canvasSize", "templateElements", "mediaDataUrls", "presentationStartTime", "isAudienceWindowOpen"], outputs: ["movePresentationSlide", "exit", "openAudienceWindow", "closeAudienceWindow", "navigateToSlide"] }, { 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: SlideDefaultInspectorComponent, selector: "pptx-slide-default-inspector", inputs: ["slideIndex", "canEdit", "selectedElement", "comments"], outputs: ["commentAdd", "commentRemove", "commentResolve"] }, { 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: 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", "hiddenActions"], outputs: ["toggleNotes", "normalView", "openSorter", "slideShow", "zoomIn", "zoomOut", "zoomReset"] }, { kind: "component", type: EditorContextMenuComponent, selector: "pptx-editor-context-menu", inputs: ["x", "y", "slideIndex", "showAiActions"], outputs: ["closed", "askAi", "fixAi"] }, { 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", "hiddenActions"], 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", "aiEnabled", "aiPanelOpen", "hiddenActions"], outputs: ["toggleMenu", "toggleAiPanel", "undo", "redo", "share", "save", "present"] }, { kind: "component", type: MasterViewCanvasComponent, selector: "pptx-master-view-canvas", inputs: ["tab", "slideMasters", "activeMasterIndex", "activeLayoutIndex", "notesMaster", "handoutMaster", "canvasSize", "notesCanvasSize", "mediaDataUrls", "editable"], outputs: ["notesMasterChange", "handoutMasterChange"] }, { kind: "component", type: MasterViewSidebarComponent, selector: "pptx-master-view-sidebar", inputs: ["tab", "slideMasters", "notesMaster", "handoutMaster", "activeMasterIndex", "activeLayoutIndex", "handoutSlidesPerPage"], outputs: ["tabChange", "selectMaster", "selectLayout", "slidesPerPageChange", "backgroundChange", "close"] }, { kind: "component", type: NotesPanelComponent, selector: "pptx-notes-panel", inputs: ["slide", "expanded"], outputs: ["update", "notesToggle"] }, { kind: "component", type: RibbonComponent, selector: "pptx-ribbon", inputs: ["slideIndex", "slideCount", "canEdit", "selectedElement", "zoomPercent", "formatPainterActive", "canActivateFormatPainter", "exporting", "hasMacros", "showGrid", "showRulers", "showGuides", "snapToGrid", "snapToShape", "eyedropperActive", "themeGalleryOpen", "sidebarCollapsed", "inspectorOpen", "commentsOpen", "commentCount", "findOpen", "collabConnected", "connectedCount", "spellCheckEnabled", "showSubtitles", "hiddenActions", "aiEnabled", "aiPanelOpen", "accountAuth"], outputs: ["prev", "next", "zoomIn", "zoomOut", "zoomReset", "find", "present", "presenter", "record", "presentFromBeginning", "rehearseTimings", "toggleSubtitles", "openSubtitleSettings", "recordFromBeginning", "recordFromCurrent", "spellCheckChange", "share", "broadcast", "openFile", "openRecentFile", "createPresentation", "save", "savePpsx", "savePptm", "packageForSharing", "toggleSidebar", "toggleAiPanel", "signatures", "info", "print", "comments", "a11y", "link", "openSorter", "openMasterView", "toggleNotes", "toggleFormatPainter", "exportPng", "exportPdf", "exportGif", "exportVideo", "copySlideAsImage", "replace", "toggleInspector", "drawToolChange", "toggleThemeGallery", "toggleGrid", "toggleRulers", "toggleGuides", "toggleSelectionPane", "openCustomShows", "toggleSnapToGrid", "toggleSnapToShape", "addGuide", "zoomToFit", "toggleEyedropper", "openSmartArtDialog", "openEquationDialog", "openSetUpSlideShow", "openCompare", "openPassword", "openFontEmbedding", "openVersionHistory", "openShortcuts", "openSettings"] }, { kind: "component", type: TitleBarComponent, selector: "pptx-title-bar", inputs: ["canEdit", "fileName", "isDirty", "autosaveStatus", "autosaveEnabled", "canUndo", "canRedo", "undoLabel", "redoLabel", "findReplaceOpen", "hiddenActions", "quickAccess"], outputs: ["toggleAutosave", "save", "undo", "redo", "quickCommand", "toggleFindReplace", "commandSearch"] }, { kind: "component", type: ThemeGalleryComponent, selector: "pptx-theme-gallery", inputs: ["open", "activeName", "theme"], outputs: ["applyTheme", "applyCustomTheme", "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", "themeKey", "availableThemes", "localeCode", "availableLocales", "aiExportVisible"], outputs: ["restoreContent", "themeKeySelect", "localeSelect"] }, { kind: "component", type: RehearseTimingsComponent, selector: "pptx-rehearse-timings", inputs: ["summary", "paused", "slideStartedAt", "presentationStartedAt", "timings"], outputs: ["togglePause", "save", "discard"] }, { kind: "pipe", type: TranslatePipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush, deferBlockDependencies: [() => [/* @ts-ignore */
110018
+ `, 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", "snapToShape", "guideCommand", "spellCheck", "snapToGuides", "autoFit", "interactive", "presenting", "selectedIds", "editingId", "editTemplateMode", "templateElements", "aiHighlights", "aiActive", "aiActiveSlideIndex", "aiChangeBatch", "aiPickMode", "drawTool", "drawColor", "drawWidth"], outputs: ["elementSelect", "backgroundClick", "transformStart", "transformUpdate", "contextMenu", "textEditStart", "textCommit", "textInput", "textCancel", "textFormat", "rotateUpdate", "marqueeSelect", "inkStrokeComplete", "eraserHit", "cellCommit", "tableChange"] }, { kind: "component", type: PresentationOverlayComponent, selector: "pptx-presentation-overlay", inputs: ["slides", "canvasSize", "mediaDataUrls", "startIndex", "showWithAnimation", "subtitlesVisible"], outputs: ["indexChange", "closed", "subtitlesChange", "annotationsExit"] }, { kind: "component", type: PresenterViewComponent, selector: "pptx-presenter-view", inputs: ["slides", "currentSlideIndex", "canvasSize", "templateElements", "mediaDataUrls", "presentationStartTime", "isAudienceWindowOpen"], outputs: ["movePresentationSlide", "exit", "openAudienceWindow", "closeAudienceWindow", "navigateToSlide"] }, { 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: SlideDefaultInspectorComponent, selector: "pptx-slide-default-inspector", inputs: ["slideIndex", "canEdit", "selectedElement", "comments"], outputs: ["commentAdd", "commentRemove", "commentResolve"] }, { 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: 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", "hiddenActions"], outputs: ["toggleNotes", "normalView", "openSorter", "slideShow", "zoomIn", "zoomOut", "zoomReset"] }, { kind: "component", type: EditorContextMenuComponent, selector: "pptx-editor-context-menu", inputs: ["x", "y", "slideIndex", "showAiActions"], outputs: ["closed", "askAi", "fixAi"] }, { 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", "hiddenActions"], 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", "aiEnabled", "aiPanelOpen", "hiddenActions"], outputs: ["toggleMenu", "toggleAiPanel", "undo", "redo", "share", "save", "present"] }, { kind: "component", type: MasterViewCanvasComponent, selector: "pptx-master-view-canvas", inputs: ["tab", "slideMasters", "activeMasterIndex", "activeLayoutIndex", "notesMaster", "handoutMaster", "canvasSize", "notesCanvasSize", "mediaDataUrls", "editable"], outputs: ["notesMasterChange", "handoutMasterChange"] }, { kind: "component", type: MasterViewSidebarComponent, selector: "pptx-master-view-sidebar", inputs: ["tab", "slideMasters", "notesMaster", "handoutMaster", "activeMasterIndex", "activeLayoutIndex", "handoutSlidesPerPage"], outputs: ["tabChange", "selectMaster", "selectLayout", "slidesPerPageChange", "backgroundChange", "close"] }, { kind: "component", type: NotesPanelComponent, selector: "pptx-notes-panel", inputs: ["slide", "expanded"], outputs: ["update", "notesToggle"] }, { kind: "component", type: RibbonComponent, selector: "pptx-ribbon", inputs: ["slideIndex", "slideCount", "canEdit", "selectedElement", "zoomPercent", "formatPainterActive", "canActivateFormatPainter", "exporting", "hasMacros", "showGrid", "showRulers", "showGuides", "snapToGrid", "snapToShape", "eyedropperActive", "themeGalleryOpen", "sidebarCollapsed", "inspectorOpen", "commentsOpen", "commentCount", "findOpen", "collabConnected", "connectedCount", "spellCheckEnabled", "showSubtitles", "hiddenActions", "aiEnabled", "aiPanelOpen", "accountAuth"], outputs: ["prev", "next", "zoomIn", "zoomOut", "zoomReset", "find", "present", "presenter", "record", "presentFromBeginning", "rehearseTimings", "toggleSubtitles", "openSubtitleSettings", "recordFromBeginning", "recordFromCurrent", "spellCheckChange", "share", "broadcast", "openFile", "openRecentFile", "createPresentation", "save", "savePpsx", "savePptm", "packageForSharing", "toggleSidebar", "toggleAiPanel", "signatures", "info", "print", "comments", "a11y", "link", "openSorter", "openMasterView", "toggleNotes", "toggleFormatPainter", "exportPng", "exportPdf", "exportGif", "exportVideo", "copySlideAsImage", "replace", "toggleInspector", "drawToolChange", "toggleThemeGallery", "toggleGrid", "toggleRulers", "toggleGuides", "toggleSelectionPane", "openCustomShows", "toggleSnapToGrid", "toggleSnapToShape", "addGuide", "zoomToFit", "toggleEyedropper", "openSmartArtDialog", "openEquationDialog", "openSetUpSlideShow", "openCompare", "openPassword", "openFontEmbedding", "openVersionHistory", "openShortcuts", "openSettings"] }, { kind: "component", type: TitleBarComponent, selector: "pptx-title-bar", inputs: ["canEdit", "fileName", "isDirty", "autosaveStatus", "autosaveEnabled", "canUndo", "canRedo", "undoLabel", "redoLabel", "findReplaceOpen", "hiddenActions", "quickAccess"], outputs: ["toggleAutosave", "save", "undo", "redo", "quickCommand", "toggleFindReplace", "commandSearch"] }, { kind: "component", type: ThemeGalleryComponent, selector: "pptx-theme-gallery", inputs: ["open", "activeName", "theme"], outputs: ["applyTheme", "applyCustomTheme", "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", "themeKey", "availableThemes", "localeCode", "availableLocales", "aiExportVisible"], outputs: ["restoreContent", "themeKeySelect", "localeSelect"] }, { kind: "component", type: RehearseTimingsComponent, selector: "pptx-rehearse-timings", inputs: ["summary", "paused", "slideStartedAt", "presentationStartedAt", "timings"], outputs: ["togglePause", "save", "discard"] }, { kind: "pipe", type: TranslatePipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush, deferBlockDependencies: [() => [/* @ts-ignore */
109526
110019
  Promise.resolve().then(function () { return aiChatPanel_component; }).then(m => m.AiChatPanelComponent)]] });
109527
110020
  }
109528
110021
  i0.ɵɵngDeclareClassMetadataAsync({ minVersion: "18.0.0", version: "22.0.8", ngImport: i0, type: PowerPointViewerComponent, resolveDeferredDeps: () => [/* @ts-ignore */
@@ -109800,6 +110293,7 @@ i0.ɵɵngDeclareClassMetadataAsync({ minVersion: "18.0.0", version: "22.0.8", ng
109800
110293
  (contextMenu)="canvasEditing.onContextMenu($event)"
109801
110294
  [editingId]="canvasEditing.editingId()"
109802
110295
  (textEditStart)="canvasEditing.onTextEditStart($event.id)"
110296
+ (textInput)="canvasEditing.onTextInput($event)"
109803
110297
  (textCommit)="canvasEditing.onTextCommit($event)"
109804
110298
  (textCancel)="canvasEditing.editingId.set(null)"
109805
110299
  (textFormat)="canvasEditing.onTextFormat($event)"
@@ -112160,4 +112654,4 @@ function cn(...values) {
112160
112654
  */
112161
112655
 
112162
112656
  export { DATA_TABLE_KEY_W as $, ALIGN_OPTIONS as A, BroadcastDialogComponent as B, CHART_EDITOR_STYLES as C, ChartAxisOptionsComponent as D, ChartAxisStyleOptionsComponent as E, ChartComboTypeOptionsComponent as F, ChartDataEditorComponent as G, ChartDataLabelOptionsComponent as H, ChartDatapointOptionsComponent as I, ChartDisplayOptionsComponent as J, ChartElementViewComponent as K, ChartErrorBarOptionsComponent as L, ChartMarkerOptionsComponent as M, ChartPartSelectionService as N, ChartPrimitivesComponent as O, ChartRendererComponent as P, ChartTrendlineOptionsComponent as Q, CollaborationCursorsComponent as R, CollaborationService as S, ColorChangedImageComponent as T, CommentsPanelComponent as U, CommentsService as V, ComparePanelComponent as W, ConnectorRendererComponent as X, ConnectorTextOverlayComponent as Y, CustomShowsComponent as Z, DATA_TABLE_HEADER_H as _, AUDIENCE_HASH as a, MIN_ZOOM_SCALE as a$, DATA_TABLE_PADDING as a0, DATA_TABLE_ROW_H as a1, DEFAULT_BOUNDS as a2, DEFAULT_BROADCAST_SERVER_URL as a3, DEFAULT_CANVAS_HEIGHT as a4, DEFAULT_CANVAS_WIDTH as a5, DEFAULT_COLOR_SCHEME as a6, DEFAULT_FILL_COLOR as a7, DEFAULT_LAYOUT as a8, DEFAULT_PALETTE$1 as a9, ExportProgressModalComponent as aA, ExportService as aB, FieldContextService as aC, FindBarComponent as aD, FindReplaceBarComponent as aE, FollowModeBarComponent as aF, FontEmbeddingListComponent as aG, FontEmbeddingPanelComponent as aH, GALLERY_THEME_PRESETS as aI, GradientPickerComponent as aJ, HANDOUT_OPTIONS as aK, HeaderFooterDialogComponent as aL, HyperlinkDialogComponent as aM, ImagePropertiesPanelComponent as aN, InkDrawingService as aO, InkRendererComponent as aP, InsertSmartArtDialogComponent as aQ, InspectorPaneHeaderComponent as aR, InspectorPanelComponent as aS, IsMobileService as aT, KeepAnnotationsDialogComponent as aU, LOCALE_CATALOG as aV, LONG_PRESS_DURATION_MS as aW, LONG_PRESS_MOVE_TOLERANCE_PX as aX, LoadContentService as aY, LocalPresencePublisher as aZ, MAX_ZOOM_SCALE as a_, DEFAULT_PRINT_SETTINGS as aa, DEFAULT_SLIDE_BACKGROUND as ab, DEFAULT_STROKE_COLOR as ac, DEFAULT_STYLE as ad, DEFAULT_TABLE_ROW_HEIGHT as ae, DEFAULT_TEXT_COLOR$1 as af, DEFAULT_VIEWER_PROFILE as ag, DIRECTIONAL_PRESETS as ah, DIRECTION_OPTIONS as ai, DocumentPropertiesCardComponent as aj, EMBEDDED_FONTS_STYLE_ID as ak, EMPHASIS_PRESETS as al, ENTRANCE_PRESETS as am, TEMPLATES as an, EXIT_PRESETS as ao, EditorContextMenuComponent as ap, EditorHistory as aq, EditorStateService as ar, EditorToolbarComponent as as, EffectsPanelComponent as at, ElementRendererComponent as au, EmbeddedFontsService as av, EncryptedFileDialogComponent as aw, EquationEditorDialogComponent as ax, EquationRendererComponent as ay, EquationTemplateGalleryComponent as az, AUDIENCE_NONCE_KEY as b, SLIDE_PX_PER_INCH as b$, MediaPreviewComponent as b0, MediaPropertiesPanelComponent as b1, MediaRendererComponent as b2, MediaTrimTimelineComponent as b3, MobileBottomBarComponent as b4, MobileMenuSheetComponent as b5, MobilePresenterViewComponent as b6, MobileSheetComponent as b7, MobileSlidesSheetComponent as b8, MobileToolbarComponent as b9, RESIZE_HANDLES as bA, RULER_THICKNESS as bB, RemoteSelectionOverlayComponent as bC, RibbonAnimationsSectionComponent as bD, RibbonArrangeSectionComponent as bE, RibbonColorPopoverComponent as bF, RibbonComponent as bG, RibbonDesignSectionComponent as bH, RibbonDrawSectionComponent as bI, RibbonDrawingGroupComponent as bJ, RibbonEditingSectionComponent as bK, RibbonFileSectionComponent as bL, RibbonFontControlsComponent as bM, RibbonHomeSectionComponent as bN, RibbonInsertFieldsComponent as bO, RibbonInsertSectionComponent as bP, RibbonParagraphControlsComponent as bQ, RibbonPrimaryRowComponent as bR, RibbonReviewSectionComponent as bS, RibbonSlideshowSectionComponent as bT, RibbonTransitionsSectionComponent as bU, RibbonViewSectionComponent as bV, RulerGuidesService as bW, SEQUENCE_OPTIONS as bX, SEVERITY_GROUPS as bY, SEVERITY_LABELS as bZ, SHORTCUT_REFERENCE_ITEMS as b_, ModalDialogComponent as ba, Model3DRendererComponent as bb, NotesHandoutCardComponent as bc, NotesPanelComponent as bd, NotesToolbarComponent as be, OleRendererComponent as bf, POWER_POINT_VIEWER_PROVIDERS as bg, PRESENTER_CHANNEL_NAME as bh, PRESENTER_MSG_ORIGIN as bi, PasswordProtectionDialogComponent as bj, PasswordStrengthMeterComponent as bk, PowerPointViewerComponent as bl, PresentationAnnotationOverlayComponent as bm, PresentationAnnotationsService as bn, PresentationOverlayComponent as bo, PresentationPropertiesPanelComponent as bp, PresentationSettingsCardComponent as bq, PresentationSubtitleBarComponent as br, PresentationTransitionOverlayComponent as bs, PresenterViewComponent as bt, PresenterWindowService as bu, PrintDialogComponent as bv, PrintService as bw, PrintSettingsPanelComponent as bx, PropertiesDialogComponent as by, REPEAT_MODE_OPTIONS as bz, AVATAR_COLOR_SWATCHES as c, ViewerDocumentPropertiesService as c$, SLIDE_TRANSITION_KEYFRAMES as c0, DEFAULT_PALETTE as c1, PALETTES$1 as c2, SMART_ART_COLOR_SCHEMES as c3, SMART_ART_STYLE_OPTIONS as c4, SUB_ITEM_LABEL as c5, SVG_WARP_PRESETS as c6, SWIPE_MAX_VERTICAL_PX as c7, SWIPE_THRESHOLD_PX as c8, SelectionPaneComponent as c9, TABLE_STRUCTURE_TOGGLES as cA, TEXT_DIRECTION_OPTIONS$1 as cB, THEME_CATALOG as cC, TIMING_CURVE_OPTIONS as cD, TRIGGER_OPTIONS as cE, TYPE_LABELS as cF, TableCellAdvancedFillComponent as cG, TableCellFormattingComponent as cH, TableDataEditorComponent as cI, TablePropertiesComponent as cJ, TableRendererComponent as cK, TableResizeOverlayComponent as cL, TableSelectionService as cM, TextAdvancedPanelComponent as cN, ThemeEditorFieldsComponent as cO, ThemeGalleryComponent as cP, ThemeSelectorCardComponent as cQ, TitleBarComponent as cR, VALIGN_OPTIONS as cS, VIEWER_THEME as cT, VersionHistoryPanelComponent as cU, ViewerCanvasEditingService as cV, ViewerCollabCursorService as cW, ViewerCollaborationSessionService as cX, ViewerCompareService as cY, ViewerCustomShowsService as cZ, ViewerDialogsService as c_, SetUpSlideShowDialogComponent as ca, SettingsAppearanceTabComponent as cb, SettingsDialogComponent as cc, SettingsLanguageTabComponent as cd, ShareDialogComponent as ce, ShortcutPanelComponent as cf, ShowOptionsFieldsetComponent as cg, ShowSlidesFieldsetComponent as ch, SignatureStrippedDialogComponent as ci, SignaturesPanelComponent as cj, SignaturesService as ck, SlideCanvasComponent as cl, SlideDefaultInspectorComponent as cm, SlideDiffChangesComponent as cn, SlideDiffRowComponent as co, SlideDiffThumbnailsComponent as cp, SlideSizeCardComponent as cq, SlideSorterOverlayComponent as cr, SlideThemeOverridePanelComponent as cs, SlidesPanelComponent as ct, SmartArt3DRendererComponent as cu, SmartArt3DService as cv, SmartArtPreviewComponent as cw, SmartArtPropertiesComponent as cx, SmartArtRendererComponent as cy, StatusBarComponent as cz, AccessibilityPanelComponent as d, buildFallbackViewModel as d$, ViewerExportService as d0, ViewerExtraDialogsComponent as d1, ViewerFileIOService as d2, ViewerFindReplaceService as d3, ViewerFormatPainterService as d4, ViewerInspectorPanelService as d5, ViewerKeyboardService as d6, ViewerMobileSheetService as d7, ViewerPresentationModeService as d8, ViewerThemeGalleryService as d9, asMediaElement as dA, assignUserColor as dB, attachTouchGestures as dC, beginNodeEdit as dD, boolFromEvent as dE, bringForward as dF, bringToFront as dG, buildBarActions as dH, buildBroadcastConfig as dI, buildBroadcastViewerUrl as dJ, buildCategoryLabels as dK, buildCellParagraphs as dL, buildChartViewModel as dM, buildChatLogExport as dN, buildChatLogMarkdown as dO, buildChromeStyle as dP, buildClearHyperlinkPatch as dQ, buildClickGroups as dR, buildColStyles as dS, buildCollaborationConfig as dT, buildComboViewModel as dU, buildCssGradientFromShapeStyle as dV, buildDuotoneFilter as dW, buildDuotoneFilterId as dX, buildEmbeddedFontStyles as dY, buildEquationElement as dZ, buildEquationSegment as d_, ViewerTouchGesturesService as da, ViewerZoomService as db, WEBM_MIME_CANDIDATES as dc, WriteBackScheduler as dd, ZoomNavigationService as de, ZoomRendererComponent as df, ZoomTargetService as dg, addCategory as dh, addCommentToList as di, addGradientStopPatch as dj, addItem as dk, addSeries as dl, addSubItem as dm, advanceStep as dn, aiToggleVisible as dp, alignPatch as dq, animationFor as dr, annotationMapToInkInserts as ds, applyAcceptedDiff as dt, applyAnimationPreset as du, applyFindReplacements as dv, applyFormatToElement as dw, applyMove as dx, applyResize as dy, applyTableStylePreset as dz, AccessibilityService as e, computeDataTablePrimitives as e$, buildFontFaceRule as e0, buildGradientFillCss as e1, buildGridlinesAndLabels as e2, buildHyperlinkPatch as e3, buildInkContainerStyle as e4, buildInkStrokes as e5, buildLegend as e6, buildModel3DContainerStyle as e7, buildModel3DViewModel as e8, buildOleActionModel as e9, cellStyleToStyleMap as eA, cellTdStyle as eB, changeCountLabel as eC, changeIcon as eD, characterSpacingPatch as eE, checkFontAvailable as eF, clampCursorPosition as eG, clampGifDimensions as eH, clampIndex as eI, clampNotesFontSize as eJ, clampScale as eK, clampStep as eL, clearAllLocalViewerData as eM, clearAudienceContent as eN, cn as eO, collectAccessibilityIssues as eP, collectElementText as eQ, collectSlideText as eR, collectStoredChats as eS, collectUsedFontFamilies as eT, columnWidthStyle as eU, commitNodeText as eV, computeAlign as eW, computeAxisTitlePrimitives as eX, computeBarRects as eY, computeBubbleRadius as eZ, computeCornerHandle as e_, buildOleInfoRows as ea, buildPatternFillCss as eb, buildPrintHtmlDocument as ec, buildPropertiesPatch as ed, buildRegionMapViewModel as ee, buildSaveSlides as ef, buildShareUrl as eg, buildSmartArtInsertElement as eh, buildSmartArtNodes as ei, buildStockViewModel as ej, buildSurfaceViewModel as ek, buildTableViewModel as el, buildTreemapViewModel as em, buildTrimFragment as en, buildWaterfallViewModel as eo, buildZeroLine as ep, buildZoomContainerStyle as eq, buildZoomViewModel as er, bulletIndentPx as es, canAddTopLevelNode as et, canRemoveTopLevelNode as eu, canStartBroadcast as ev, canStartShare as ew, canUseClipboard as ex, captionDisplayText as ey, cellRunStyle as ez, AccountPageComponent as f, encodeGif as f$, computeDistribute as f0, computeDrawingViewBox as f1, computeErrorBarPrimitives as f2, computeFocusTargets as f3, computeHandleBoxes as f4, computeHandoutLayout as f5, computeIsMobile as f6, computeIsTablet as f7, computeLinePoints as f8, computeLinearRegression as f9, createWebsocketBundle as fA, cssObjectToStyleMap as fB, currentColorScheme as fC, currentLayout as fD, currentStyle as fE, defaultCssVars as fF, defaultRadius as fG, defaultThemeColors as fH, deleteElementsByIds as fI, deleteVersion as fJ, demoteNode as fK, deriveModel3DBlobUrl as fL, derivePresenceList as fM, describeSmartArtBounds as fN, disableGlowPatch as fO, disableInnerShadowPatch as fP, disableOuterShadowPatch as fQ, disableReflectionPatch as fR, disableSoftEdgePatch as fS, duplicateElementById as fT, durationOf as fU, effectsStateOf as fV, enableGlowPatch as fW, enableInnerShadowPatch as fX, enableOuterShadowPatch as fY, enableReflectionPatch as fZ, enableSoftEdgePatch as f_, computePageCount as fa, computePieLayout as fb, computePieSlicePath as fc, computePieSlices as fd, computePlotLayout as fe, computeRSquared as ff, computeRadarPoints as fg, computeScatterDots as fh, computeSelectionBoxes as fi, computeSingleSelected as fj, computeSlideIndices as fk, computeSnap as fl, computeStackedBarRects as fm, computeStackedValueRange as fn, computeTextLines as fo, computeTimerProgress as fp, computeTrendlinePrimitives as fq, computeValueRange as fr, convertOmmlToMathMl as fs, copyFormatFromElement as ft, countAccessibilityIssues as fu, countAnnotationStrokes as fv, createAngularAiBridge as fw, createCustomShow as fx, createSwipeDismissDrag as fy, createWebrtcBundle as fz, ActionSettingsPanelComponent as g, hasAnimation as g$, estimatePageCount as g0, evenColumnWidths as g1, evenRowHeights as g2, exitPresentationFullscreen as g3, exportAiChatLogs as g4, extractPathPoints as g5, eyedropperAvailable as g6, fillColorOf as g7, findInSlides as g8, findOwningSlideIndex as g9, getOleBadgeLabel as gA, getOleDisplayName as gB, getOleDownloadFileName as gC, getOleTypeColor as gD, getOleTypeLabel as gE, getPasswordStrength as gF, getPatternSvg as gG, getPlaceholderStyle as gH, getVersions as gI, getResolvedShapeClipPath as gJ, getResolvedShapeClipPathFor as gK, getShapeFillStrokeStyle as gL, getSlideBackgroundStyle as gM, getSlideTransitionAnimations as gN, getSmartArtNodeBounds as gO, getSpeechRecognitionCtor as gP, getTextBlockStyle as gQ, getTextWarp as gR, getTouchDistance as gS, getWarpCategory as gT, getWarpPath as gU, gradientStateFromStyle as gV, gradientStateOf as gW, gradientStatePatch as gX, gridColumns as gY, groupElements as gZ, groupIssuesBySeverity as g_, findSlideIndexByElementId as ga, fitPolynomial as gb, fitZoom as gc, focusTargetChips as gd, fontMimeForFormat as ge, fontSizeOf as gf, formatAutoNumber as gg, formatAxisValue as gh, formatBytes as gi, formatCursorLabel as gj, formatElapsed as gk, formatFileSize as gl, formatPropertyDate as gm, formatTime as gn, fpsToFrameIntervalMs as go, generateBroadcastRoomId as gp, generateCommentId as gq, generateCustomShowId as gr, generatePressureCircles as gs, generateRulerTicks as gt, getClrChangeParams as gu, getContainerStyle as gv, getDuotoneFilterDef as gw, getImageSrc as gx, getLocalStorageUsageSummary as gy, getOleAriaLabel as gz, AdvancedChartEditorComponent as h, numFromEvent as h$, hasCopyableFormat as h0, hasExistingLink as h1, hasExitedFullscreen as h2, hasGradientFill as h3, hasPressureVariation as h4, headerLabel as h5, inkViewBox as h6, insertColumn as h7, insertRow as h8, interpolateWidth as h9, mergeRight as hA, mergeSelection as hB, moveElementBy as hC, moveNodeDown as hD, moveNodeUp as hE, msToFrameDelayCs as hF, narrowToCircle as hG, narrowToPolygon as hH, narrowToRect as hI, newChartElement as hJ, newEquationElement as hK, newPresetShapeElement as hL, newShapeElement as hM, newSmartArtElement as hN, newTableElement as hO, newTextElement as hP, nextVisibleIndex as hQ, nodeBold as hR, nodeEditBox as hS, nodeFillColor as hT, nodeFontColor as hU, nodeIdFromKey as hV, nodeItalic as hW, nodeStyle as hX, normalizeFontFormat as hY, normalizeSlidesPerPage as hZ, normalizeValue as h_, isAudienceTab as ha, isBold as hb, isBrowserOpenableMime as hc, isChildNode as hd, isElementInteractive as he, isInjectableUrl as hf, isItalic as hg, isPpactionUrl as hh, isPresenterMessage as hi, isSigned as hj, isTextElement as hk, isTwoTableFocus as hl, isUnderline as hm, isUrlSafe as hn, isValidRoomId as ho, isViewportBackgroundPressTarget as hp, isZoomActivationKey as hq, issueTrackKey as hr, issueTypeLabel as hs, keyToLabel as ht, latexToMathml as hu, linePointsToSvgString as hv, lineSpacingPatch as hw, loadAudienceContent as hx, mergeCaptionResults as hy, mergeDown as hz, AiChangeOverlayComponent as i, routeOrthogonalConnector as i$, ommlToMathml as i0, ooxmlDashToCssBorderStyle as i1, openNativeEyeDropper as i2, overallStatus as i3, paletteColor as i4, parseAudienceNonce as i5, parseNodeTextarea as i6, partitionSlides as i7, patchChartData as i8, patchChartStyle as i9, removeElementAnimation as iA, removeGradientStopPatch as iB, removeNode as iC, removeRow as iD, removeSeries as iE, renderToCanvas as iF, reorderAnimationDown as iG, reorderAnimationUp as iH, replaceInSlides as iI, replaceMatch as iJ, requestPresentationFullscreen as iK, resizeElement as iL, resolveCaptionTracks as iM, resolveChartKind as iN, resolveFontVariant as iO, resolveHyperlinkHref as iP, resolveInteractiveElementId as iQ, resolveMediaSrc as iR, resolveOleType as iS, resolveParagraphBullet as iT, resolvePresenterNotes as iU, resolveProfileInitial as iV, resolveRegionCode as iW, resolvePalette as iX, resolveThemeCatalogEntry as iY, resolveTransitionDuration as iZ, revealedElementStyles as i_, patchTableData as ia, patchTextStyle as ib, pendingElementStyles as ic, pickColorByClickFallback as id, pickSupportedMimeType as ie, planGifFrames as ig, planVideoSegments as ih, pointsToSvgPathD as ii, presenceToCursors as ij, presetByLayout as ik, presetsForCategory as il, pressuresToWidths as im, prevVisibleIndex as io, projectDrawingShapes as ip, promoteNode as iq, provideViewerTheme as ir, radarAngle as is, radarRingPoints as it, recordWebm as iu, redistributeColumnWidth as iv, removeAnimation as iw, removeCategory as ix, removeColumn as iy, removeCommentFromList as iz, AiChatPanelComponent as j, signatureKey as j$, rowStyle as j0, sampleColorFromSlide as j1, sanitizeColor as j2, sanitizeSlideIndex as j3, sanitizeUserName as j4, saveViewerProfile as j5, scanAvailableFonts as j6, searchSlides as j7, seedBroadcastFields as j8, seedHyperlinkDraft as j9, setGridlineStyle as jA, setLayout as jB, setLegend as jC, setNodeStyle as jD, setNodeText as jE, setRepeatCount as jF, setRepeatMode as jG, setSequence as jH, setSeriesChartType as jI, setSeriesColor as jJ, setSeriesErrorBars as jK, setSeriesMarker as jL, setSeriesName as jM, setSeriesTrendline as jN, setSeriesValue as jO, setStyle as jP, setTimingCurve as jQ, setTitle as jR, setTrigger as jS, setTriggerShapeId as jT, shapeStylePatch as jU, sheetAfterNavigate as jV, shouldBlockClickAdvance as jW, shouldUseSvgWarp as jX, showDirectionPicker as jY, showsTemplateAffordance as jZ, signatureCountLabel as j_, seedPropertiesDraft as ja, seedShareFields as jb, segmentFrameCount as jc, selectValue$2 as jd, sendBackward as je, sendToBack as jf, sequentialColorScale as jg, serializeWriteBack as jh, seriesColor as ji, setAnimationEmphasis as jj, setAnimationEntrance as jk, setAnimationExit as jl, setAxis as jm, setAxisLogScale as jn, setAxisTitleStyle as jo, setCategoryLabel as jp, setCellText as jq, setColorScheme as jr, setDataLabels as js, setDataPointExplosion as jt, setDataPointFill as ju, setDataPointLabel as jv, setDelay as jw, setDirection as jx, setDuration as jy, setElementPosition as jz, AiChatService as k, signatureTimestamp as k0, signerName as k1, statusLabel as k2, slideNumberOf as k3, smartArtNodes as k4, paletteColour as k5, snapToGridStep as k6, splitCursorCell as k7, splitMergedCell as k8, statusKind as k9, updateGlowPatch as kA, updateGradientStopPatch as kB, updateInnerShadowPatch as kC, updateOuterShadowPatch as kD, updateReflectionPatch as kE, vAlignPatch as kF, validatePassword as kG, validatePrintSettings as kH, validateRoomId as kI, valueToY as kJ, vermilionDarkColors as kK, vermilionDarkTheme as kL, vermilionLightColors as kM, vermilionLightTheme as kN, vermilionRadius as kO, waypointsToPathD as kP, worstStatus as kQ, zoomTargetSlideIndex as kR, statusLabel$1 as ka, storeAudienceContent as kb, stringFromEvent$5 as kc, strokeColorOf as kd, strokeToInkElement as ke, styleShadowFilter as kf, textAdvancedPatch as kg, textAdvancedStateFromStyle as kh, textAdvancedStateOf as ki, textColorOf as kj, textDirectionPatch as kk, textStyleOf as kl, textStylePatch as km, themeStyle as kn, themeToCssVars as ko, thumbnailHeight as kp, thumbnailZoom as kq, toggleCommentResolvedInList as kr, toggleNodeBold as ks, toggleNodeItalic as kt, toggleSheet as ku, topLevelNodeCount as kv, transformSelectedTextCase as kw, translationsEn as kx, ungroupElements as ky, updateElementById as kz, AiComposerComponent as l, AiFocusBarComponent as m, AiFocusHighlightOverlayComponent as n, AiMessageListComponent as o, AiPanelStore as p, AiProposalCardComponent as q, AiSettingsSectionComponent as r, AiToolCallCardComponent as s, toChatSummary as t, AnimationAuthorPanelComponent as u, AnimationPanelComponent as v, AnimationPlaybackService as w, AutosaveService as x, CURSOR_PALETTE as y, CanvasFitService as z };
112163
- //# sourceMappingURL=pptx-angular-viewer-pptx-angular-viewer-D9eqILzM.mjs.map
112657
+ //# sourceMappingURL=pptx-angular-viewer-pptx-angular-viewer-BwaiF7Nf.mjs.map