pptx-react-viewer 4.48.0 → 4.50.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (123) hide show
  1. package/CHANGELOG.md +126 -0
  2. package/dist/{AiChatPanel-NKTBHT5B.mjs → AiChatPanel-VJV5OEG2.mjs} +1 -1
  3. package/dist/AiChatPanel-VJV5OEG2.mjs.br +0 -0
  4. package/dist/AiChatPanel-VJV5OEG2.mjs.gz +0 -0
  5. package/dist/{AiChatPanel-S4WNQCY4.js → AiChatPanel-WYAL24DX.js} +9 -9
  6. package/dist/AiChatPanel-WYAL24DX.js.br +0 -0
  7. package/dist/AiChatPanel-WYAL24DX.js.gz +0 -0
  8. package/dist/{chunk-5FAX7F3O.js → chunk-4OF7X5EE.js} +1754 -3189
  9. package/dist/chunk-4OF7X5EE.js.br +0 -0
  10. package/dist/chunk-4OF7X5EE.js.gz +0 -0
  11. package/dist/{chunk-H7JRMKYC.mjs → chunk-5JJQLK7N.mjs} +542 -1977
  12. package/dist/chunk-5JJQLK7N.mjs.br +0 -0
  13. package/dist/chunk-5JJQLK7N.mjs.gz +0 -0
  14. package/dist/{chunk-PFV626ED.mjs → chunk-77IXTLKU.mjs} +3 -4
  15. package/dist/chunk-77IXTLKU.mjs.br +0 -0
  16. package/dist/chunk-77IXTLKU.mjs.gz +0 -0
  17. package/dist/{chunk-JKZNL6HP.js → chunk-D5NXYXPP.js} +773 -1245
  18. package/dist/chunk-D5NXYXPP.js.br +0 -0
  19. package/dist/chunk-D5NXYXPP.js.gz +0 -0
  20. package/dist/chunk-DDJ634MV.js.br +0 -0
  21. package/dist/chunk-DDJ634MV.js.gz +0 -0
  22. package/dist/{chunk-JAI42EXQ.js → chunk-JWNBTFZZ.js} +0 -6
  23. package/dist/chunk-JWNBTFZZ.js.br +0 -0
  24. package/dist/chunk-JWNBTFZZ.js.gz +0 -0
  25. package/dist/{chunk-JHQHAO43.mjs → chunk-QHGEPW5G.mjs} +596 -1068
  26. package/dist/chunk-QHGEPW5G.mjs.br +0 -0
  27. package/dist/chunk-QHGEPW5G.mjs.gz +0 -0
  28. package/dist/chunk-QIUK53JR.mjs.br +0 -0
  29. package/dist/chunk-QIUK53JR.mjs.gz +0 -0
  30. package/dist/i18n/de.cjs +1138 -221
  31. package/dist/i18n/de.cjs.br +0 -0
  32. package/dist/i18n/de.cjs.gz +0 -0
  33. package/dist/i18n/de.mjs +1138 -221
  34. package/dist/i18n/de.mjs.br +0 -0
  35. package/dist/i18n/de.mjs.gz +0 -0
  36. package/dist/i18n/es.cjs +1138 -221
  37. package/dist/i18n/es.cjs.br +0 -0
  38. package/dist/i18n/es.cjs.gz +0 -0
  39. package/dist/i18n/es.mjs +1138 -221
  40. package/dist/i18n/es.mjs.br +0 -0
  41. package/dist/i18n/es.mjs.gz +0 -0
  42. package/dist/i18n/fr.cjs +1138 -221
  43. package/dist/i18n/fr.cjs.br +0 -0
  44. package/dist/i18n/fr.cjs.gz +0 -0
  45. package/dist/i18n/fr.mjs +1138 -221
  46. package/dist/i18n/fr.mjs.br +0 -0
  47. package/dist/i18n/fr.mjs.gz +0 -0
  48. package/dist/i18n/zh-CN.cjs +1138 -221
  49. package/dist/i18n/zh-CN.cjs.br +0 -0
  50. package/dist/i18n/zh-CN.cjs.gz +0 -0
  51. package/dist/i18n/zh-CN.mjs +1138 -221
  52. package/dist/i18n/zh-CN.mjs.br +0 -0
  53. package/dist/i18n/zh-CN.mjs.gz +0 -0
  54. package/dist/index.d.ts +5 -15
  55. package/dist/index.js +24 -24
  56. package/dist/index.js.br +0 -0
  57. package/dist/index.js.gz +0 -0
  58. package/dist/index.mjs +3 -3
  59. package/dist/index.mjs.br +0 -0
  60. package/dist/index.mjs.gz +0 -0
  61. package/dist/internals.d.ts +105 -94
  62. package/dist/internals.js +81 -81
  63. package/dist/internals.js.br +0 -0
  64. package/dist/internals.js.gz +0 -0
  65. package/dist/internals.mjs +2 -2
  66. package/dist/internals.mjs.br +0 -0
  67. package/dist/internals.mjs.gz +0 -0
  68. package/dist/pptx-viewer-canvas.css +1 -1
  69. package/dist/pptx-viewer-canvas.css.br +0 -0
  70. package/dist/pptx-viewer-canvas.css.gz +0 -0
  71. package/dist/pptx-viewer.css +1 -1
  72. package/dist/pptx-viewer.css.br +0 -0
  73. package/dist/pptx-viewer.css.gz +0 -0
  74. package/dist/viewer/index.d.ts +7 -12
  75. package/dist/viewer/index.js +19 -19
  76. package/dist/viewer/index.js.br +0 -0
  77. package/dist/viewer/index.js.gz +0 -0
  78. package/dist/viewer/index.mjs +3 -3
  79. package/dist/viewer/index.mjs.br +0 -0
  80. package/dist/viewer/index.mjs.gz +0 -0
  81. package/dist/{y-webrtc-2H7UYAQD.mjs → y-webrtc-HRGGVQZH.mjs} +1 -1
  82. package/dist/y-webrtc-HRGGVQZH.mjs.br +0 -0
  83. package/dist/y-webrtc-HRGGVQZH.mjs.gz +0 -0
  84. package/dist/{y-webrtc-DVPQNFLL.js → y-webrtc-QVVT5PCK.js} +124 -124
  85. package/dist/y-webrtc-QVVT5PCK.js.br +0 -0
  86. package/dist/y-webrtc-QVVT5PCK.js.gz +0 -0
  87. package/dist/{y-websocket-WORVRRQS.mjs → y-websocket-46M6UFI7.mjs} +1 -1
  88. package/dist/y-websocket-46M6UFI7.mjs.br +0 -0
  89. package/dist/y-websocket-46M6UFI7.mjs.gz +0 -0
  90. package/dist/{y-websocket-TN4OKPXQ.js → y-websocket-EDOMWMAD.js} +78 -78
  91. package/dist/y-websocket-EDOMWMAD.js.br +0 -0
  92. package/dist/y-websocket-EDOMWMAD.js.gz +0 -0
  93. package/package.json +3 -3
  94. package/dist/AiChatPanel-NKTBHT5B.mjs.br +0 -0
  95. package/dist/AiChatPanel-NKTBHT5B.mjs.gz +0 -0
  96. package/dist/AiChatPanel-S4WNQCY4.js.br +0 -0
  97. package/dist/AiChatPanel-S4WNQCY4.js.gz +0 -0
  98. package/dist/chunk-3VVZGHHY.mjs.br +0 -0
  99. package/dist/chunk-3VVZGHHY.mjs.gz +0 -0
  100. package/dist/chunk-5FAX7F3O.js.br +0 -0
  101. package/dist/chunk-5FAX7F3O.js.gz +0 -0
  102. package/dist/chunk-H7JRMKYC.mjs.br +0 -0
  103. package/dist/chunk-H7JRMKYC.mjs.gz +0 -0
  104. package/dist/chunk-JAI42EXQ.js.br +0 -0
  105. package/dist/chunk-JAI42EXQ.js.gz +0 -0
  106. package/dist/chunk-JHQHAO43.mjs.br +0 -0
  107. package/dist/chunk-JHQHAO43.mjs.gz +0 -0
  108. package/dist/chunk-JKZNL6HP.js.br +0 -0
  109. package/dist/chunk-JKZNL6HP.js.gz +0 -0
  110. package/dist/chunk-NUNDT6EL.js.br +0 -0
  111. package/dist/chunk-NUNDT6EL.js.gz +0 -0
  112. package/dist/chunk-PFV626ED.mjs.br +0 -0
  113. package/dist/chunk-PFV626ED.mjs.gz +0 -0
  114. package/dist/y-webrtc-2H7UYAQD.mjs.br +0 -0
  115. package/dist/y-webrtc-2H7UYAQD.mjs.gz +0 -0
  116. package/dist/y-webrtc-DVPQNFLL.js.br +0 -0
  117. package/dist/y-webrtc-DVPQNFLL.js.gz +0 -0
  118. package/dist/y-websocket-TN4OKPXQ.js.br +0 -0
  119. package/dist/y-websocket-TN4OKPXQ.js.gz +0 -0
  120. package/dist/y-websocket-WORVRRQS.mjs.br +0 -0
  121. package/dist/y-websocket-WORVRRQS.mjs.gz +0 -0
  122. package/dist/{chunk-NUNDT6EL.js → chunk-DDJ634MV.js} +436 -436
  123. package/dist/{chunk-3VVZGHHY.mjs → chunk-QIUK53JR.mjs} +436 -436
@@ -1,6 +1,6 @@
1
1
  'use strict';
2
2
 
3
- var chunkJAI42EXQ_js = require('./chunk-JAI42EXQ.js');
3
+ var chunkJWNBTFZZ_js = require('./chunk-JWNBTFZZ.js');
4
4
  var pptx = require('ooxml-ui/pptx');
5
5
  var React17 = require('react');
6
6
  var jsxRuntime = require('react/jsx-runtime');
@@ -80,240 +80,59 @@ function useVirtualizedSlides({
80
80
  scrollToIndex
81
81
  };
82
82
  }
83
+ function useController(controller) {
84
+ return React17.useSyncExternalStore(controller.subscribe, controller.getSnapshot, controller.getSnapshot);
85
+ }
86
+
87
+ // src/viewer/hooks/collaboration/collaboration-modules.ts
88
+ var collabModules = {
89
+ loadYjs: () => import('yjs'),
90
+ loadWebsocket: () => import('./y-websocket-EDOMWMAD.js'),
91
+ loadWebrtc: () => import('./y-webrtc-QVVT5PCK.js')
92
+ };
93
+
94
+ // src/viewer/hooks/collaboration/useYjsProvider.ts
83
95
  function useYjsProvider({ config: inputConfig }) {
84
96
  const config = inputConfig?.externalSession ? void 0 : inputConfig;
85
- const [status, setStatus] = React17.useState("disconnected");
86
- const [awareness, setAwareness] = React17.useState(null);
87
- const [doc, setDoc] = React17.useState(null);
88
- const [clientId, setClientId] = React17.useState(null);
89
- const [synced, setSynced] = React17.useState(false);
90
- const cleanupRef = React17.useRef(null);
91
- const generationRef = React17.useRef(0);
92
- const timeoutRef = React17.useRef(null);
93
- const departureRef = React17.useRef(null);
94
- const gateRef = React17.useRef(null);
95
- if (!gateRef.current) {
96
- gateRef.current = pptx.createSyncGate(() => setSynced(true));
97
- }
98
- const teardown = React17.useCallback(() => {
99
- generationRef.current += 1;
100
- if (timeoutRef.current) {
101
- clearTimeout(timeoutRef.current);
102
- timeoutRef.current = null;
103
- }
104
- gateRef.current?.reset();
105
- setSynced(false);
106
- cleanupRef.current?.();
107
- cleanupRef.current = null;
108
- }, []);
109
- const announceDeparture = React17.useCallback(() => {
110
- departureRef.current?.announce();
111
- departureRef.current?.dispose();
112
- departureRef.current = null;
113
- }, []);
114
- const buildCleanup = React17.useCallback(
115
- (provider, yDoc) => () => {
116
- announceDeparture();
117
- pptx.clearLocalAwareness(provider.awareness);
118
- provider.destroy();
119
- yDoc.destroy();
120
- setDoc(null);
121
- setAwareness(null);
122
- setClientId(null);
123
- setStatus("disconnected");
124
- },
125
- [announceDeparture]
97
+ const [controller] = React17.useState(
98
+ () => pptx.createCollaborationSessionController({ modules: collabModules, registerTeardown: false })
126
99
  );
127
- const initWebrtc = React17.useCallback(async () => {
128
- const generation = generationRef.current;
129
- if (!config) {
130
- return;
131
- }
132
- setStatus("connecting");
133
- try {
134
- const [Y, { WebrtcProvider }] = await Promise.all([import('yjs'), import('./y-webrtc-DVPQNFLL.js')]);
135
- if (generation !== generationRef.current) {
136
- return;
137
- }
138
- const yDoc = new Y.Doc();
139
- const opts = {};
140
- if (config.signaling && config.signaling.length > 0) {
141
- opts.signaling = config.signaling;
142
- }
143
- if (config.authToken) {
144
- opts.password = config.authToken;
145
- }
146
- const roomId = pptx.validateRoomId(config.roomId);
147
- const provider = new WebrtcProvider(roomId, yDoc, opts);
148
- departureRef.current = pptx.createDepartureChannel(roomId, provider.awareness);
149
- setDoc(yDoc);
150
- setAwareness(provider.awareness);
151
- setClientId(provider.awareness.clientID);
152
- setStatus("connected");
153
- const handleSynced = (event) => {
154
- if (event?.synced !== false) {
155
- gateRef.current?.open();
156
- }
157
- };
158
- provider.on("synced", handleSynced);
159
- gateRef.current?.arm();
160
- const handleStatus = (event) => {
161
- if (event.connected === false) {
162
- setStatus("disconnected");
163
- gateRef.current?.reset();
164
- setSynced(false);
165
- gateRef.current?.arm();
166
- } else if (event.connected) {
167
- setStatus("connected");
168
- }
169
- };
170
- provider.on("status", handleStatus);
171
- const baseCleanup = buildCleanup(provider, yDoc);
172
- cleanupRef.current = () => {
173
- provider.off("synced", handleSynced);
174
- provider.off("status", handleStatus);
175
- baseCleanup();
176
- };
177
- } catch (err) {
178
- if (generation !== generationRef.current) {
179
- return;
180
- }
181
- console.warn(
182
- "[pptx-viewer] WebRTC collaboration packages not available:",
183
- err instanceof Error ? err.message : err
184
- );
185
- setStatus("error");
186
- }
187
- }, [config?.roomId, config?.authToken, config?.signaling, buildCleanup]);
188
- const init = React17.useCallback(async () => {
189
- teardown();
190
- const generation = generationRef.current;
100
+ const state = useController(controller);
101
+ const signalingKey = config?.signaling?.join("\n");
102
+ React17.useEffect(() => {
191
103
  if (!config) {
104
+ controller.stop();
192
105
  return;
193
106
  }
194
- const roomId = pptx.validateRoomId(config.roomId);
195
- const transport = config.transport ?? pptx.resolveTransportForServerUrl(config.serverUrl);
196
- if (transport === "webrtc") {
197
- await initWebrtc();
198
- return;
199
- }
200
- if (pptx.isMixedContentBlocked(config.serverUrl)) {
201
- console.warn(
202
- `[pptx-viewer] Refusing to connect: insecure ws:// server "${config.serverUrl}" is blocked from a secure (https) page. Use a wss:// URL.`
203
- );
204
- setStatus("error");
205
- return;
206
- }
207
- setStatus("connecting");
208
- try {
209
- const [Y, { WebsocketProvider }] = await Promise.all([import('yjs'), import('./y-websocket-TN4OKPXQ.js')]);
210
- if (generation !== generationRef.current) {
211
- return;
212
- }
213
- const yDoc = new Y.Doc();
214
- const provider = new WebsocketProvider(config.serverUrl, roomId, yDoc, {
215
- params: config.authToken ? { token: config.authToken } : void 0
216
- });
217
- departureRef.current = pptx.createDepartureChannel(roomId, provider.awareness);
218
- let connected = false;
219
- const handleStatus = (event) => {
220
- if (event.status === "connected") {
221
- connected = true;
222
- if (timeoutRef.current) {
223
- clearTimeout(timeoutRef.current);
224
- timeoutRef.current = null;
225
- }
226
- setStatus("connected");
227
- gateRef.current?.arm();
228
- } else if (event.status === "disconnected") {
229
- setStatus("disconnected");
230
- gateRef.current?.reset();
231
- setSynced(false);
232
- gateRef.current?.arm();
233
- }
234
- };
235
- const handleSynced = (isSynced) => {
236
- if (isSynced) {
237
- gateRef.current?.open();
238
- }
239
- };
240
- provider.on("status", handleStatus);
241
- provider.on("sync", handleSynced);
242
- if (provider.wsconnected) {
243
- connected = true;
244
- setStatus("connected");
245
- gateRef.current?.arm();
246
- }
247
- if (provider.synced) {
248
- gateRef.current?.open();
249
- }
250
- if (!connected) {
251
- timeoutRef.current = setTimeout(() => {
252
- timeoutRef.current = null;
253
- if (!connected) {
254
- provider.off("status", handleStatus);
255
- provider.off("sync", handleSynced);
256
- announceDeparture();
257
- pptx.clearLocalAwareness(provider.awareness);
258
- provider.destroy();
259
- yDoc.destroy();
260
- setDoc(null);
261
- setAwareness(null);
262
- setClientId(null);
263
- cleanupRef.current = null;
264
- setStatus("error");
265
- }
266
- }, pptx.CONNECTION_TIMEOUT_MS);
267
- }
268
- setDoc(yDoc);
269
- setAwareness(provider.awareness);
270
- setClientId(provider.awareness.clientID);
271
- cleanupRef.current = () => {
272
- provider.off("status", handleStatus);
273
- provider.off("sync", handleSynced);
274
- announceDeparture();
275
- pptx.clearLocalAwareness(provider.awareness);
276
- provider.destroy();
277
- yDoc.destroy();
278
- setDoc(null);
279
- setAwareness(null);
280
- setClientId(null);
281
- setStatus("disconnected");
282
- };
283
- } catch (err) {
284
- if (generation !== generationRef.current) {
285
- return;
286
- }
287
- console.warn(
288
- "[pptx-viewer] Collaboration packages not available:",
289
- err instanceof Error ? err.message : err
290
- );
291
- setStatus("error");
292
- }
107
+ void controller.start(config);
108
+ const disposeTeardown = pptx.registerCollaborationTeardown({
109
+ leave: () => controller.stop(),
110
+ rejoin: () => void controller.retry()
111
+ });
112
+ return () => {
113
+ disposeTeardown();
114
+ controller.stop();
115
+ };
293
116
  }, [
117
+ controller,
294
118
  config?.roomId,
295
119
  config?.serverUrl,
296
120
  config?.authToken,
297
121
  config?.transport,
298
- announceDeparture,
299
- initWebrtc,
300
- teardown
122
+ signalingKey,
123
+ Boolean(config)
301
124
  ]);
302
- React17.useEffect(() => {
303
- init();
304
- const disposeTeardown = pptx.registerCollaborationTeardown({
305
- leave: teardown,
306
- rejoin: init
307
- });
308
- return () => {
309
- disposeTeardown();
310
- teardown();
311
- };
312
- }, [init, teardown]);
313
- const retry = React17.useCallback(() => {
314
- init();
315
- }, [init]);
316
- return { status, awareness, doc, clientId, synced, retry };
125
+ const session = state.active ? controller.getSession() : null;
126
+ return {
127
+ status: state.status,
128
+ awareness: session?.awareness ?? null,
129
+ doc: session?.doc ?? null,
130
+ clientId: state.clientId,
131
+ synced: state.synced,
132
+ retry: () => {
133
+ void controller.retry();
134
+ }
135
+ };
317
136
  }
318
137
  function usePresenceTracking({
319
138
  awareness,
@@ -762,15 +581,11 @@ function serializeHistoryDocument(snapshot) {
762
581
  )
763
582
  });
764
583
  }
765
- function recordExplicitSlideUpdate(past, future, previous, before, label, maxDepth) {
584
+ function recordExplicitSlideUpdate(history, previous, before, label) {
766
585
  if (previous && serializeHistoryDocument(previous) !== serializeHistoryDocument(before)) {
767
- past.push(chunkJAI42EXQ_js.cloneHistorySnapshot(previous));
768
- }
769
- past.push({ ...chunkJAI42EXQ_js.cloneHistorySnapshot(before), actionLabel: label });
770
- while (past.length > Math.max(1, maxDepth)) {
771
- past.shift();
586
+ history.record(chunkJWNBTFZZ_js.cloneHistorySnapshot(previous), previous.actionLabel);
772
587
  }
773
- future.length = 0;
588
+ history.record({ ...chunkJWNBTFZZ_js.cloneHistorySnapshot(before), actionLabel: label }, label);
774
589
  }
775
590
  var POLL_INTERVAL_MS = 16;
776
591
  function usePointerReleaseWakeup(hasActivePointerInteraction) {
@@ -806,7 +621,6 @@ function usePointerReleaseWakeup(hasActivePointerInteraction) {
806
621
  }
807
622
 
808
623
  // src/viewer/hooks/useEditorHistory.ts
809
- var DEFAULT_MAX_HISTORY_ENTRIES = 120;
810
624
  function useEditorHistory(input) {
811
625
  const {
812
626
  slides,
@@ -815,7 +629,7 @@ function useEditorHistory(input) {
815
629
  templateElementsBySlideId,
816
630
  loading,
817
631
  error,
818
- maxHistoryEntries = DEFAULT_MAX_HISTORY_ENTRIES,
632
+ maxHistoryEntries,
819
633
  hasActivePointerInteraction,
820
634
  pointerCommitNonce,
821
635
  onDirty,
@@ -826,38 +640,31 @@ function useEditorHistory(input) {
826
640
  setSelectedElementId,
827
641
  setSelectedElementIds
828
642
  } = input;
829
- const historyPastRef = React17.useRef([]);
830
- const historyFutureRef = React17.useRef([]);
643
+ const [history] = React17.useState(() => pptx.createEditorHistoryController());
644
+ const historyState = useController(history);
831
645
  const lastHistorySnapshotRef = React17.useRef(null);
832
646
  const lastHistorySerializedRef = React17.useRef("");
833
647
  const lastCheapHashRef = React17.useRef("");
834
648
  const isApplyingHistoryRef = React17.useRef(false);
835
649
  const trackingHeldRef = React17.useRef(false);
836
650
  const unlockHistoryTimerRef = React17.useRef(null);
837
- const [canUndo, setCanUndo] = React17.useState(false);
838
- const [canRedo, setCanRedo] = React17.useState(false);
839
- const [undoLabel, setUndoLabel] = React17.useState(void 0);
840
- const [redoLabel, setRedoLabel] = React17.useState(void 0);
841
651
  const [editCommitNonce, setEditCommitNonce] = React17.useState(0);
842
652
  const { pointerReleaseNonce, deferUntilPointerReleased } = usePointerReleaseWakeup(
843
653
  hasActivePointerInteraction
844
654
  );
845
- const updateHistoryAvailability = React17.useCallback(() => {
846
- setCanUndo(historyPastRef.current.length > 0);
847
- setCanRedo(historyFutureRef.current.length > 0);
848
- const pastTop = historyPastRef.current[historyPastRef.current.length - 1];
849
- setUndoLabel(pastTop?.actionLabel);
850
- const futureTop = historyFutureRef.current[historyFutureRef.current.length - 1];
851
- setRedoLabel(futureTop?.actionLabel);
852
- }, []);
655
+ React17.useEffect(() => {
656
+ if (maxHistoryEntries !== void 0) {
657
+ history.setMaxDepth(maxHistoryEntries);
658
+ }
659
+ }, [history, maxHistoryEntries]);
853
660
  const buildHistorySnapshot = React17.useCallback(
854
661
  (actionLabel) => {
855
662
  return {
856
663
  width: canvasSize.width,
857
664
  height: canvasSize.height,
858
665
  activeSlideIndex,
859
- slides: slides.map(chunkJAI42EXQ_js.cloneSlide),
860
- templateElementsBySlideId: chunkJAI42EXQ_js.cloneTemplateElementsBySlideId(templateElementsBySlideId),
666
+ slides: slides.map(chunkJWNBTFZZ_js.cloneSlide),
667
+ templateElementsBySlideId: chunkJWNBTFZZ_js.cloneTemplateElementsBySlideId(templateElementsBySlideId),
861
668
  ...actionLabel ? { actionLabel } : {}
862
669
  };
863
670
  },
@@ -870,9 +677,9 @@ function useEditorHistory(input) {
870
677
  width: snapshot.width,
871
678
  height: snapshot.height
872
679
  });
873
- setSlides(snapshot.slides.map(chunkJAI42EXQ_js.cloneSlide));
680
+ setSlides(snapshot.slides.map(chunkJWNBTFZZ_js.cloneSlide));
874
681
  setTemplateElementsBySlideId(
875
- chunkJAI42EXQ_js.cloneTemplateElementsBySlideId(snapshot.templateElementsBySlideId)
682
+ chunkJWNBTFZZ_js.cloneTemplateElementsBySlideId(snapshot.templateElementsBySlideId)
876
683
  );
877
684
  setActiveSlideIndex(Math.min(snapshot.activeSlideIndex, maxSlideIndex));
878
685
  setSelectedElementIds([]);
@@ -904,64 +711,50 @@ function useEditorHistory(input) {
904
711
  onDirtyRef.current?.();
905
712
  }, []);
906
713
  const handleUndo = React17.useCallback(() => {
907
- const previousSnapshot = historyPastRef.current.pop();
908
- if (!previousSnapshot) {
714
+ if (!history.getSnapshot().canUndo) {
715
+ return;
716
+ }
717
+ const result = history.undo(buildHistorySnapshot());
718
+ if (!result) {
909
719
  return;
910
720
  }
911
- const currentSnapshot = buildHistorySnapshot(previousSnapshot.actionLabel);
912
- historyFutureRef.current.push(currentSnapshot);
913
721
  isApplyingHistoryRef.current = true;
914
- const nextSnapshot = chunkJAI42EXQ_js.cloneHistorySnapshot(previousSnapshot);
915
- lastHistorySnapshotRef.current = chunkJAI42EXQ_js.cloneHistorySnapshot(nextSnapshot);
722
+ const nextSnapshot = chunkJWNBTFZZ_js.cloneHistorySnapshot(result.snapshot);
723
+ lastHistorySnapshotRef.current = chunkJWNBTFZZ_js.cloneHistorySnapshot(nextSnapshot);
916
724
  lastHistorySerializedRef.current = serializeHistoryDocument(nextSnapshot);
917
725
  applyHistorySnapshot(nextSnapshot);
918
- updateHistoryAvailability();
919
726
  unlockHistoryTracking();
920
727
  markDirty();
921
- }, [
922
- applyHistorySnapshot,
923
- buildHistorySnapshot,
924
- markDirty,
925
- unlockHistoryTracking,
926
- updateHistoryAvailability
927
- ]);
728
+ }, [applyHistorySnapshot, buildHistorySnapshot, history, markDirty, unlockHistoryTracking]);
928
729
  const handleRedo = React17.useCallback(() => {
929
- const nextSnapshot = historyFutureRef.current.pop();
930
- if (!nextSnapshot) {
730
+ if (!history.getSnapshot().canRedo) {
731
+ return;
732
+ }
733
+ const result = history.redo(buildHistorySnapshot());
734
+ if (!result) {
931
735
  return;
932
736
  }
933
- const currentSnapshot = buildHistorySnapshot(nextSnapshot.actionLabel);
934
- historyPastRef.current.push(currentSnapshot);
935
737
  isApplyingHistoryRef.current = true;
936
- const targetSnapshot = chunkJAI42EXQ_js.cloneHistorySnapshot(nextSnapshot);
937
- lastHistorySnapshotRef.current = chunkJAI42EXQ_js.cloneHistorySnapshot(targetSnapshot);
738
+ const targetSnapshot = chunkJWNBTFZZ_js.cloneHistorySnapshot(result.snapshot);
739
+ lastHistorySnapshotRef.current = chunkJWNBTFZZ_js.cloneHistorySnapshot(targetSnapshot);
938
740
  lastHistorySerializedRef.current = serializeHistoryDocument(targetSnapshot);
939
741
  applyHistorySnapshot(targetSnapshot);
940
- updateHistoryAvailability();
941
742
  unlockHistoryTracking();
942
743
  markDirty();
943
- }, [
944
- applyHistorySnapshot,
945
- buildHistorySnapshot,
946
- markDirty,
947
- unlockHistoryTracking,
948
- updateHistoryAvailability
949
- ]);
744
+ }, [applyHistorySnapshot, buildHistorySnapshot, history, markDirty, unlockHistoryTracking]);
950
745
  const resetHistory = React17.useCallback(
951
746
  (initialSnapshot) => {
952
- historyPastRef.current = [];
953
- historyFutureRef.current = [];
747
+ history.clear();
954
748
  if (initialSnapshot) {
955
- const clonedInitial = chunkJAI42EXQ_js.cloneHistorySnapshot(initialSnapshot);
749
+ const clonedInitial = chunkJWNBTFZZ_js.cloneHistorySnapshot(initialSnapshot);
956
750
  lastHistorySnapshotRef.current = clonedInitial;
957
751
  lastHistorySerializedRef.current = serializeHistoryDocument(clonedInitial);
958
752
  } else {
959
753
  lastHistorySnapshotRef.current = null;
960
754
  lastHistorySerializedRef.current = "";
961
755
  }
962
- updateHistoryAvailability();
963
756
  },
964
- [updateHistoryAvailability]
757
+ [history]
965
758
  );
966
759
  React17.useEffect(() => {
967
760
  return () => {
@@ -1004,19 +797,13 @@ function useEditorHistory(input) {
1004
797
  lastHistorySnapshotRef.current = snapshot;
1005
798
  lastHistorySerializedRef.current = serialized;
1006
799
  lastCheapHashRef.current = cheapHash;
1007
- updateHistoryAvailability();
1008
800
  return;
1009
801
  }
1010
802
  onDirtyRef.current?.();
1011
- historyPastRef.current.push(previousSnapshot);
1012
- while (historyPastRef.current.length > Math.max(1, maxHistoryEntries)) {
1013
- historyPastRef.current.shift();
1014
- }
1015
- historyFutureRef.current = [];
803
+ history.record(previousSnapshot, previousSnapshot.actionLabel);
1016
804
  lastHistorySnapshotRef.current = snapshot;
1017
805
  lastHistorySerializedRef.current = serialized;
1018
806
  lastCheapHashRef.current = cheapHash;
1019
- updateHistoryAvailability();
1020
807
  }, [
1021
808
  activeSlideIndex,
1022
809
  buildHistorySnapshot,
@@ -1026,30 +813,21 @@ function useEditorHistory(input) {
1026
813
  editCommitNonce,
1027
814
  error,
1028
815
  hasActivePointerInteraction,
816
+ history,
1029
817
  loading,
1030
- maxHistoryEntries,
1031
818
  pointerCommitNonce,
1032
819
  pointerReleaseNonce,
1033
- slides,
1034
- updateHistoryAvailability
820
+ slides
1035
821
  ]);
1036
822
  const commitSlides = (nextSlides, label, beforeSlides = slides) => {
1037
- const before = { ...buildHistorySnapshot(), slides: beforeSlides.map(chunkJAI42EXQ_js.cloneSlide) };
1038
- const after = { ...before, slides: nextSlides.map(chunkJAI42EXQ_js.cloneSlide) };
1039
- recordExplicitSlideUpdate(
1040
- historyPastRef.current,
1041
- historyFutureRef.current,
1042
- lastHistorySnapshotRef.current,
1043
- before,
1044
- label,
1045
- maxHistoryEntries
1046
- );
1047
- lastHistorySnapshotRef.current = chunkJAI42EXQ_js.cloneHistorySnapshot(after);
823
+ const before = { ...buildHistorySnapshot(), slides: beforeSlides.map(chunkJWNBTFZZ_js.cloneSlide) };
824
+ const after = { ...before, slides: nextSlides.map(chunkJWNBTFZZ_js.cloneSlide) };
825
+ recordExplicitSlideUpdate(history, lastHistorySnapshotRef.current, before, label);
826
+ lastHistorySnapshotRef.current = chunkJWNBTFZZ_js.cloneHistorySnapshot(after);
1048
827
  lastHistorySerializedRef.current = serializeHistoryDocument(after);
1049
828
  isApplyingHistoryRef.current = false;
1050
829
  setSlides(nextSlides);
1051
830
  onDirtyRef.current?.();
1052
- updateHistoryAvailability();
1053
831
  };
1054
832
  const holdTracking = React17.useCallback((held) => {
1055
833
  trackingHeldRef.current = held;
@@ -1057,10 +835,10 @@ function useEditorHistory(input) {
1057
835
  return {
1058
836
  commitSlides,
1059
837
  holdTracking,
1060
- canUndo,
1061
- canRedo,
1062
- undoLabel,
1063
- redoLabel,
838
+ canUndo: historyState.canUndo,
839
+ canRedo: historyState.canRedo,
840
+ undoLabel: historyState.undoLabel,
841
+ redoLabel: historyState.redoLabel,
1064
842
  handleUndo,
1065
843
  handleRedo,
1066
844
  resetHistory,
@@ -1230,22 +1008,22 @@ function useZoomViewport({
1230
1008
  selectedElements.forEach((element) => {
1231
1009
  minX = Math.min(minX, element.x);
1232
1010
  minY = Math.min(minY, element.y);
1233
- maxX = Math.max(maxX, element.x + Math.max(element.width, chunkJAI42EXQ_js.MIN_ELEMENT_SIZE));
1234
- maxY = Math.max(maxY, element.y + Math.max(element.height, chunkJAI42EXQ_js.MIN_ELEMENT_SIZE));
1011
+ maxX = Math.max(maxX, element.x + Math.max(element.width, chunkJWNBTFZZ_js.MIN_ELEMENT_SIZE));
1012
+ maxY = Math.max(maxY, element.y + Math.max(element.height, chunkJWNBTFZZ_js.MIN_ELEMENT_SIZE));
1235
1013
  });
1236
1014
  if (!Number.isFinite(minX) || !Number.isFinite(minY) || !Number.isFinite(maxX) || !Number.isFinite(maxY)) {
1237
1015
  return;
1238
1016
  }
1239
1017
  const selectionBounds = { minX, minY, maxX, maxY };
1240
- const boundsWidth = Math.max(selectionBounds.maxX - selectionBounds.minX, chunkJAI42EXQ_js.MIN_ELEMENT_SIZE);
1241
- const boundsHeight = Math.max(selectionBounds.maxY - selectionBounds.minY, chunkJAI42EXQ_js.MIN_ELEMENT_SIZE);
1018
+ const boundsWidth = Math.max(selectionBounds.maxX - selectionBounds.minX, chunkJWNBTFZZ_js.MIN_ELEMENT_SIZE);
1019
+ const boundsHeight = Math.max(selectionBounds.maxY - selectionBounds.minY, chunkJWNBTFZZ_js.MIN_ELEMENT_SIZE);
1242
1020
  const availableWidth = Math.max(
1243
- effectiveEditorDimensions.width - chunkJAI42EXQ_js.ZOOM_TO_SELECTION_PADDING,
1244
- chunkJAI42EXQ_js.MIN_ELEMENT_SIZE
1021
+ effectiveEditorDimensions.width - chunkJWNBTFZZ_js.ZOOM_TO_SELECTION_PADDING,
1022
+ chunkJWNBTFZZ_js.MIN_ELEMENT_SIZE
1245
1023
  );
1246
1024
  const availableHeight = Math.max(
1247
- effectiveEditorDimensions.height - chunkJAI42EXQ_js.ZOOM_TO_SELECTION_PADDING,
1248
- chunkJAI42EXQ_js.MIN_ELEMENT_SIZE
1025
+ effectiveEditorDimensions.height - chunkJWNBTFZZ_js.ZOOM_TO_SELECTION_PADDING,
1026
+ chunkJWNBTFZZ_js.MIN_ELEMENT_SIZE
1249
1027
  );
1250
1028
  const targetEditorScale = Math.min(
1251
1029
  availableWidth / boundsWidth,
@@ -2203,9 +1981,6 @@ function executeSlideTransition(nextSlideIndex, deps) {
2203
1981
  }
2204
1982
 
2205
1983
  // src/viewer/hooks/presentation-mode/useSlideNavigation.ts
2206
- function isClickAdvanceBlocked(slide, direction, trigger) {
2207
- return trigger === "click" && direction === 1 && slide?.transition?.advanceOnClick === false;
2208
- }
2209
1984
  function useSlideNavigation(input) {
2210
1985
  const {
2211
1986
  slides,
@@ -2255,50 +2030,71 @@ function useSlideNavigation(input) {
2255
2030
  );
2256
2031
  const movePresentationSlide = React17.useCallback(
2257
2032
  (direction, trigger = "explicit") => {
2258
- if (direction === 1 && playNextAnimationGroup()) {
2259
- return;
2260
- }
2261
- if (isClickAdvanceBlocked(slides[presentationSlideIndex], direction, trigger)) {
2033
+ const showOrder = visibleSlideIndexes.length > 0 ? visibleSlideIndexes : slides.map((_slide, slideIndex) => slideIndex);
2034
+ const current = presentationSlideIndex;
2035
+ const transitionTo = (index, options = {}) => executeSlideTransition(index, {
2036
+ slides,
2037
+ currentSlideIndex: current,
2038
+ onPlayActionSound,
2039
+ onStopActionSound,
2040
+ setPresentationSlideVisible,
2041
+ clearPresentationTimers,
2042
+ setPresentationSlideIndex,
2043
+ onSetActiveSlideIndex,
2044
+ seedSlideAnimations,
2045
+ startSlideAnimations,
2046
+ scheduleAutoAdvanceForSlide: rehearsing ? void 0 : scheduleAutoAdvanceForSlide,
2047
+ presentationTimersRef,
2048
+ setTransitionOverlay,
2049
+ // PowerPoint plays a slide's transition only when advancing into it,
2050
+ // and replays the LEAVING slide's transition in reverse when stepping
2051
+ // back (a morph glides its shapes back to where they came from).
2052
+ playTransition: true,
2053
+ ...options
2054
+ });
2055
+ if (direction === -1) {
2056
+ const step2 = pptx.resolveShowBackward({
2057
+ currentIndex: current,
2058
+ showOrder,
2059
+ endOfShow: false,
2060
+ seededCompleted: false
2061
+ });
2062
+ if (step2.kind === "go") {
2063
+ transitionTo(step2.index, { reverse: true, seedCompleted: true });
2064
+ }
2262
2065
  return;
2263
2066
  }
2264
- if (direction === 1) {
2265
- const consumedExcursion = zoomExcursionRef.current;
2266
- const step = pptx.resolveForwardSlideWithZoomReturn(
2267
- presentationSlideIndex,
2268
- void 0,
2269
- consumedExcursion
2270
- );
2271
- if (step.returnedToZoom && step.nextSlideIndex !== void 0) {
2272
- zoomExcursionRef.current = step.excursion;
2273
- executeSlideTransition(step.nextSlideIndex, {
2274
- slides,
2275
- currentSlideIndex: presentationSlideIndex,
2276
- onPlayActionSound,
2277
- onStopActionSound,
2278
- setPresentationSlideVisible,
2279
- clearPresentationTimers,
2280
- setPresentationSlideIndex,
2281
- onSetActiveSlideIndex,
2282
- seedSlideAnimations,
2283
- startSlideAnimations,
2067
+ const step = pptx.resolveShowForward({
2068
+ currentIndex: current,
2069
+ currentSlide: slides[current],
2070
+ showOrder,
2071
+ endOfShow: false,
2072
+ fromClick: trigger === "click",
2073
+ loop: Boolean(loopContinuously) && !rehearsing,
2074
+ endWithBlackSlide: true,
2075
+ zoomExcursion: zoomExcursionRef.current,
2076
+ advanceBuild: playNextAnimationGroup
2077
+ });
2078
+ if (step.kind === "go") {
2079
+ if (step.zoomReturn) {
2080
+ zoomExcursionRef.current = step.zoomReturn.excursion;
2081
+ transitionTo(step.index, {
2284
2082
  scheduleAutoAdvanceForSlide,
2285
- presentationTimersRef,
2286
- setTransitionOverlay,
2287
- playTransition: true,
2288
- transitionOverride: pptx.buildZoomTransitionOverride(
2289
- consumedExcursion?.transitionDurationMs
2290
- )
2083
+ transitionOverride: step.zoomReturn.transitionOverride
2291
2084
  });
2292
2085
  return;
2293
2086
  }
2087
+ if (rehearsing) {
2088
+ recordCurrentSlideTime(current);
2089
+ }
2090
+ transitionTo(step.index);
2091
+ return;
2294
2092
  }
2295
- const availableSlideIndexes = visibleSlideIndexes.length > 0 ? visibleSlideIndexes : slides.map((_slide, slideIndex) => slideIndex);
2296
- if (availableSlideIndexes.length === 0) {
2093
+ if (step.kind !== "end-screen" && step.kind !== "exit") {
2297
2094
  return;
2298
2095
  }
2299
- const pastLastSlide = direction === 1 && !pptx.hasShowSlideAfter(presentationSlideIndex, availableSlideIndexes);
2300
- if (rehearsing && pastLastSlide) {
2301
- recordCurrentSlideTime(presentationSlideIndex);
2096
+ if (rehearsing) {
2097
+ recordCurrentSlideTime(current);
2302
2098
  try {
2303
2099
  if (document.fullscreenElement) {
2304
2100
  void document.exitFullscreen().catch(() => {
@@ -2310,41 +2106,7 @@ function useSlideNavigation(input) {
2310
2106
  setShowRehearsalSummary(true);
2311
2107
  return;
2312
2108
  }
2313
- if (!loopContinuously && !rehearsing && pastLastSlide && onAdvancePastLastSlide) {
2314
- onAdvancePastLastSlide();
2315
- return;
2316
- }
2317
- const nextSlideIndex = direction === 1 ? pptx.nextShowSlideIndex(presentationSlideIndex, availableSlideIndexes, {
2318
- loop: Boolean(loopContinuously) && !rehearsing
2319
- }) : pptx.previousShowSlideIndex(presentationSlideIndex, availableSlideIndexes);
2320
- if (nextSlideIndex === void 0 || nextSlideIndex === presentationSlideIndex) {
2321
- return;
2322
- }
2323
- if (rehearsing && direction === 1) {
2324
- recordCurrentSlideTime(presentationSlideIndex);
2325
- }
2326
- executeSlideTransition(nextSlideIndex, {
2327
- slides,
2328
- currentSlideIndex: presentationSlideIndex,
2329
- onPlayActionSound,
2330
- onStopActionSound,
2331
- setPresentationSlideVisible,
2332
- clearPresentationTimers,
2333
- setPresentationSlideIndex,
2334
- onSetActiveSlideIndex,
2335
- seedSlideAnimations,
2336
- startSlideAnimations,
2337
- scheduleAutoAdvanceForSlide: rehearsing ? void 0 : scheduleAutoAdvanceForSlide,
2338
- presentationTimersRef,
2339
- setTransitionOverlay,
2340
- // PowerPoint plays a slide's transition only when advancing into it,
2341
- // and replays the LEAVING slide's transition in reverse when stepping
2342
- // back (a morph glides its shapes back to where they came from).
2343
- playTransition: true,
2344
- reverse: direction === -1,
2345
- // Stepping back onto a slide shows it with its builds already played.
2346
- seedCompleted: direction === -1
2347
- });
2109
+ onAdvancePastLastSlide?.();
2348
2110
  },
2349
2111
  [
2350
2112
  clearPresentationTimers,
@@ -4204,6 +3966,7 @@ function useViewerCoreState(_input) {
4204
3966
  const marqueeStateRef = React17.useRef(null);
4205
3967
  const isDrawingRef = React17.useRef(false);
4206
3968
  const justInteractedRef = React17.useRef(false);
3969
+ const gestureControllerRef = React17.useRef(null);
4207
3970
  const livePatcher = React17.useMemo(() => pptx.createCollaborationLivePatcher(), []);
4208
3971
  React17.useEffect(() => () => livePatcher.dispose(), [livePatcher]);
4209
3972
  const [mode, setMode] = React17.useState("edit");
@@ -4212,18 +3975,19 @@ function useViewerCoreState(_input) {
4212
3975
  const { slides, setSlides, slidesRef } = useSlideState();
4213
3976
  const [templateElementsBySlideId, setTemplateElementsBySlideId] = React17.useState({});
4214
3977
  const [canvasSize, setCanvasSize] = React17.useState({
4215
- width: chunkJAI42EXQ_js.DEFAULT_CANVAS_WIDTH,
4216
- height: chunkJAI42EXQ_js.DEFAULT_CANVAS_HEIGHT
3978
+ width: chunkJWNBTFZZ_js.DEFAULT_CANVAS_WIDTH,
3979
+ height: chunkJWNBTFZZ_js.DEFAULT_CANVAS_HEIGHT
4217
3980
  });
4218
3981
  const [slideSizeEmu, setSlideSizeEmu] = React17.useState();
4219
3982
  const [activeSlideIndex, setActiveSlideIndex] = React17.useState(0);
4220
3983
  const [selectedElementId, setSelectedElementId] = React17.useState(null);
4221
3984
  const [selectedElementIds, setSelectedElementIds] = React17.useState([]);
4222
3985
  const [isDirty, setIsDirty] = React17.useState(false);
3986
+ const autosaveDraftSinkRef = React17.useRef(null);
4223
3987
  const publishInlineText = React17.useCallback(
4224
3988
  (elementId, text) => {
4225
- pptx.publishLiveInlineText(
4226
- livePatcher,
3989
+ pptx.reportInlineTextDraft(
3990
+ { livePatcher, autosave: autosaveDraftSinkRef.current },
4227
3991
  slidesRef.current[activeSlideIndexRef.current],
4228
3992
  elementId,
4229
3993
  text
@@ -4289,6 +4053,7 @@ function useViewerCoreState(_input) {
4289
4053
  imageInputRef,
4290
4054
  mediaInputRef,
4291
4055
  activeSlideIndexRef,
4056
+ autosaveDraftSinkRef,
4292
4057
  ...inlineEditing,
4293
4058
  ...editPointsMode,
4294
4059
  dragStateRef,
@@ -4297,6 +4062,7 @@ function useViewerCoreState(_input) {
4297
4062
  marqueeStateRef,
4298
4063
  isDrawingRef,
4299
4064
  justInteractedRef,
4065
+ gestureControllerRef,
4300
4066
  livePatcher,
4301
4067
  mode,
4302
4068
  setMode,
@@ -4686,12 +4452,12 @@ function useLoadContent({
4686
4452
  }
4687
4453
  resources.commit();
4688
4454
  handlerRef.current = handler;
4689
- const partition = chunkJAI42EXQ_js.partitionTemplateElements(nextSlides);
4455
+ const partition = chunkJWNBTFZZ_js.partitionTemplateElements(nextSlides);
4690
4456
  setSlides(partition.slides);
4691
4457
  setTemplateElementsBySlideId(partition.templateElementsBySlideId);
4692
4458
  setCanvasSize({
4693
- width: parsed.width ?? chunkJAI42EXQ_js.DEFAULT_CANVAS_WIDTH,
4694
- height: parsed.height ?? chunkJAI42EXQ_js.DEFAULT_CANVAS_HEIGHT
4459
+ width: parsed.width ?? chunkJWNBTFZZ_js.DEFAULT_CANVAS_WIDTH,
4460
+ height: parsed.height ?? chunkJWNBTFZZ_js.DEFAULT_CANVAS_HEIGHT
4695
4461
  });
4696
4462
  setSlideSizeEmu(
4697
4463
  typeof parsed.widthEmu === "number" && typeof parsed.heightEmu === "number" && parsed.widthEmu > 0 && parsed.heightEmu > 0 ? {
@@ -4783,96 +4549,43 @@ function useLoadContent({
4783
4549
  return { handlerRef };
4784
4550
  }
4785
4551
  function useAutosave(input) {
4786
- const { isDirty, filePath, serializeSlides, enabled = true, getChangeSources } = input;
4552
+ const { isDirty, filePath, enabled = true } = input;
4787
4553
  const intervalMs = pptx.resolveAutosaveIntervalMs({
4788
4554
  hostIntervalMs: input.intervalMs,
4789
4555
  optionsIntervalSeconds: input.intervalSeconds
4790
4556
  });
4791
- const [autosaveStatus, setAutosaveStatus] = React17.useState({
4792
- state: "idle"
4793
- });
4794
- const isDirtyRef = React17.useRef(isDirty);
4795
- const filePathRef = React17.useRef(filePath);
4796
- const serializeRef = React17.useRef(serializeSlides);
4797
- const storageRef = React17.useRef(input.storage);
4798
- storageRef.current = input.storage;
4799
- const isSavingRef = React17.useRef(false);
4800
- const changeSourcesRef = React17.useRef(getChangeSources);
4801
- const lastSnapshotRef = React17.useRef(void 0);
4802
- const onSavedRef = React17.useRef(input.onSaved);
4803
- React17.useEffect(() => {
4804
- onSavedRef.current = input.onSaved;
4805
- }, [input.onSaved]);
4806
- React17.useEffect(() => {
4807
- isDirtyRef.current = isDirty;
4808
- }, [isDirty]);
4809
- React17.useEffect(() => {
4810
- filePathRef.current = filePath;
4811
- }, [filePath]);
4812
- React17.useEffect(() => {
4813
- serializeRef.current = serializeSlides;
4814
- }, [serializeSlides]);
4557
+ const live = React17.useRef(input);
4558
+ live.current = input;
4559
+ const [controller] = React17.useState(
4560
+ () => pptx.createAutosaveController({
4561
+ getActivation: () => ({ active: live.current.enabled ?? true }),
4562
+ getFilePath: () => live.current.filePath,
4563
+ getIntervalMs: () => pptx.resolveAutosaveIntervalMs({
4564
+ hostIntervalMs: live.current.intervalMs,
4565
+ optionsIntervalSeconds: live.current.intervalSeconds
4566
+ }),
4567
+ serialize: () => live.current.serializeSlides(),
4568
+ getStorage: () => live.current.storage,
4569
+ onSaved: (data) => live.current.onSaved?.(data),
4570
+ writeSnapshot: pptx.saveAutosaveSnapshot,
4571
+ // serializeSlides already overlays the live inline draft from its refs.
4572
+ getInlineEditingId: () => live.current.getInlineEditingId?.()
4573
+ })
4574
+ );
4575
+ if (input.inlineDraftSinkRef) {
4576
+ input.inlineDraftSinkRef.current = controller;
4577
+ }
4578
+ const { status } = useController(controller);
4815
4579
  React17.useEffect(() => {
4816
- changeSourcesRef.current = getChangeSources;
4817
- }, [getChangeSources]);
4818
- const doAutosave = React17.useCallback(async (options) => {
4819
- const path = filePathRef.current;
4820
- if (!path) {
4821
- return;
4822
- }
4823
- const sources = changeSourcesRef.current?.() ?? [];
4824
- if (!pptx.shouldWriteAutosaveSnapshot({
4825
- filePath: path,
4826
- isDirty: isDirtyRef.current,
4827
- saving: isSavingRef.current,
4828
- sources: options?.polled === true ? sources : [],
4829
- lastSnapshot: lastSnapshotRef.current
4830
- })) {
4831
- return;
4832
- }
4833
- isSavingRef.current = true;
4834
- setAutosaveStatus({ state: "saving" });
4835
- try {
4836
- const data = await serializeRef.current();
4837
- if (!data) {
4838
- setAutosaveStatus({ state: "idle" });
4839
- isSavingRef.current = false;
4840
- return;
4841
- }
4842
- await pptx.saveAutosaveSnapshot(path, data, storageRef.current);
4843
- lastSnapshotRef.current = pptx.autosaveSnapshotMark(path, sources);
4844
- setAutosaveStatus({ state: "saved", timestamp: Date.now() });
4845
- onSavedRef.current?.(data);
4846
- } catch (err) {
4847
- setAutosaveStatus({
4848
- state: "error",
4849
- message: err instanceof Error ? err.message : "Autosave failed"
4850
- });
4851
- } finally {
4852
- isSavingRef.current = false;
4853
- }
4854
- }, []);
4580
+ controller.refresh();
4581
+ }, [controller, enabled, filePath, intervalMs]);
4855
4582
  React17.useEffect(() => {
4856
- if (!enabled) {
4857
- setAutosaveStatus({ state: "disabled", reason: "autosave_toggle_off" });
4858
- return;
4859
- }
4860
- if (!filePath) {
4861
- setAutosaveStatus({
4862
- state: "disabled",
4863
- reason: "no_file_path"
4864
- });
4865
- return;
4866
- }
4867
- setAutosaveStatus((prev) => prev.state === "disabled" ? { state: "idle" } : prev);
4868
- const id = setInterval(() => {
4869
- void doAutosave({ polled: true });
4870
- }, intervalMs);
4871
- return () => clearInterval(id);
4872
- }, [enabled, filePath, intervalMs, doAutosave]);
4583
+ controller.observe(isDirty, live.current.getChangeSources?.() ?? []);
4584
+ });
4585
+ React17.useEffect(() => () => controller.markClean(), [controller]);
4873
4586
  return {
4874
- autosaveStatus,
4875
- triggerAutosave: () => doAutosave()
4587
+ autosaveStatus: status,
4588
+ triggerAutosave: () => controller.saveNow()
4876
4589
  };
4877
4590
  }
4878
4591
 
@@ -5150,7 +4863,7 @@ function useElementOperations(input) {
5150
4863
  );
5151
4864
  return;
5152
4865
  }
5153
- if (chunkJAI42EXQ_js.isTemplateElementId(elementId)) {
4866
+ if (chunkJWNBTFZZ_js.isTemplateElementId(elementId)) {
5154
4867
  const slideId = activeSlide?.id;
5155
4868
  if (slideId) {
5156
4869
  setTemplateElementsBySlideId((prev) => ({
@@ -5387,45 +5100,238 @@ function syncSelectionHandleOverlay(elementNode, elementId, geometry) {
5387
5100
  }
5388
5101
  }
5389
5102
 
5390
- // src/viewer/hooks/pointer-move-handlers.ts
5391
- function computeResizeGeometry(handle, startX, startY, startWidth, startHeight, dx, dy, snapToGrid, gridSpacingPx, lockAspect = false) {
5392
- const startBox = { x: startX, y: startY, width: startWidth, height: startHeight };
5393
- let resized = pptx.applyResize(startBox, handle, dx, dy, 1, { minSize: chunkJAI42EXQ_js.MIN_ELEMENT_SIZE });
5394
- if (lockAspect) {
5395
- resized = pptx.lockResizeAspect(resized, startBox, handle, chunkJAI42EXQ_js.MIN_ELEMENT_SIZE);
5103
+ // src/viewer/hooks/canvas-gestures.ts
5104
+ var animationFrames = {
5105
+ request: (callback) => requestAnimationFrame(callback),
5106
+ cancel: (handle) => cancelAnimationFrame(handle)
5107
+ };
5108
+ function createCanvasGestures(getInput, frames = animationFrames) {
5109
+ let armed = null;
5110
+ let pending = null;
5111
+ let frameHandle = 0;
5112
+ let lastSnapLinesKey = "";
5113
+ const liveTarget = () => {
5114
+ const { livePatcher, editTemplateMode, activeSlide } = getInput();
5115
+ return livePatcher && !editTemplateMode && livePatcher.isActive() ? { patcher: livePatcher, slideId: activeSlide?.id } : void 0;
5116
+ };
5117
+ function showSnapLines(lines) {
5118
+ const next = lines.map((line) => ({
5119
+ axis: line.axis === "v" ? "x" : "y",
5120
+ position: line.position
5121
+ }));
5122
+ const key = JSON.stringify(next);
5123
+ if (key !== lastSnapLinesKey) {
5124
+ lastSnapLinesKey = key;
5125
+ getInput().setSnapLines(next);
5126
+ }
5396
5127
  }
5397
- const box = { x: resized.x, y: resized.y, width: resized.width, height: resized.height };
5398
- if (!snapToGrid) {
5399
- return box;
5128
+ function paintMove(drag, transform) {
5129
+ const start = drag.startPositionsById[transform.id];
5130
+ if (!start) {
5131
+ return;
5132
+ }
5133
+ drag.lastDx = transform.x - start.x;
5134
+ drag.lastDy = transform.y - start.y;
5135
+ const live = liveTarget();
5136
+ for (const [id, from] of Object.entries(drag.startPositionsById)) {
5137
+ const x = from.x + drag.lastDx;
5138
+ const y = from.y + drag.lastDy;
5139
+ const domEl = drag.domEls.get(id);
5140
+ if (domEl) {
5141
+ domEl.style.left = `${x}px`;
5142
+ domEl.style.top = `${y}px`;
5143
+ syncSelectionHandleOverlay(domEl, id, { x, y });
5144
+ }
5145
+ if (live) {
5146
+ pptx.publishLiveGeometry(live.patcher, live.slideId, id, { x, y });
5147
+ }
5148
+ }
5149
+ }
5150
+ function paintResize(resize, transform) {
5151
+ const { x, y } = transform;
5152
+ const width = Math.max(transform.width, chunkJWNBTFZZ_js.MIN_ELEMENT_SIZE);
5153
+ const height = Math.max(transform.height, chunkJWNBTFZZ_js.MIN_ELEMENT_SIZE);
5154
+ resize.lastX = x;
5155
+ resize.lastY = y;
5156
+ resize.lastWidth = transform.width;
5157
+ resize.lastHeight = transform.height;
5158
+ if (resize.domEl) {
5159
+ Object.assign(resize.domEl.style, {
5160
+ left: `${x}px`,
5161
+ top: `${y}px`,
5162
+ width: `${width}px`,
5163
+ height: `${height}px`
5164
+ });
5165
+ syncSelectionHandleOverlay(resize.domEl, resize.elementId, { x, y, width, height });
5166
+ }
5167
+ const live = liveTarget();
5168
+ if (live) {
5169
+ pptx.publishLiveGeometry(live.patcher, live.slideId, resize.elementId, { x, y, width, height });
5170
+ }
5171
+ }
5172
+ function paintPending() {
5173
+ const frame = pending;
5174
+ pending = null;
5175
+ frameHandle = 0;
5176
+ if (!frame || !armed) {
5177
+ return;
5178
+ }
5179
+ if (armed.kind === "move") {
5180
+ armed.drag.moved = true;
5181
+ showSnapLines(frame.lines);
5182
+ paintMove(armed.drag, frame.transform);
5183
+ } else {
5184
+ armed.resize.moved = true;
5185
+ paintResize(armed.resize, frame.transform);
5186
+ }
5187
+ }
5188
+ function flushFrame() {
5189
+ if (frameHandle !== 0) {
5190
+ frames.cancel(frameHandle);
5191
+ }
5192
+ paintPending();
5400
5193
  }
5401
- return pptx.snapBoxToGrid(box, handle, gridSpacingPx, chunkJAI42EXQ_js.MIN_ELEMENT_SIZE);
5194
+ const controller = pptx.createGestureController({
5195
+ getScale: () => getInput().editorScale,
5196
+ // Axis-aligned, as the canvas has always moved and resized (no rotation).
5197
+ getElementBox: (id) => {
5198
+ const el = getInput().elementLookup.get(id);
5199
+ return el ? { x: el.x, y: el.y, width: el.width, height: el.height } : void 0;
5200
+ },
5201
+ getSiblings: () => {
5202
+ const { editTemplateMode, templateElements, activeSlide } = getInput();
5203
+ const source = editTemplateMode ? templateElements : activeSlide?.elements ?? [];
5204
+ return source.map(({ id, x, y, width, height }) => ({ id, x, y, width, height }));
5205
+ },
5206
+ getSnapToGrid: () => getInput().snapToGrid,
5207
+ getGridSize: () => getInput().gridSpacingPx,
5208
+ getSnapToShape: () => getInput().snapToShape,
5209
+ getGuides: () => getInput().guides.map(({ axis, position }) => ({ axis, position })),
5210
+ getMinSize: () => chunkJWNBTFZZ_js.MIN_ELEMENT_SIZE,
5211
+ getSnapExcludeIds: () => armed?.kind === "move" ? Object.keys(armed.drag.startPositionsById) : [],
5212
+ getStageOrigin: () => {
5213
+ const rect = getInput().canvasStageRef.current?.getBoundingClientRect();
5214
+ return { left: rect?.left ?? 0, top: rect?.top ?? 0 };
5215
+ },
5216
+ onStart: () => void 0,
5217
+ onPreview: (transform, lines) => {
5218
+ pending = { transform, lines };
5219
+ if (frameHandle === 0) {
5220
+ frameHandle = frames.request(paintPending);
5221
+ }
5222
+ },
5223
+ onEnd: (transform, moved) => {
5224
+ flushFrame();
5225
+ const ended = armed;
5226
+ armed = null;
5227
+ if (ended) {
5228
+ finishGesture(ended, moved ? transform : null);
5229
+ }
5230
+ }
5231
+ });
5232
+ function finishGesture(ended, transform) {
5233
+ const input = getInput();
5234
+ if (transform) {
5235
+ if (ended.kind === "move") {
5236
+ commitMove(input, ended.drag);
5237
+ } else {
5238
+ commitResize(input, ended.resize);
5239
+ }
5240
+ input.justInteractedRef.current = true;
5241
+ input.livePatcher?.flush();
5242
+ }
5243
+ input.dragStateRef.current = null;
5244
+ input.resizeStateRef.current = null;
5245
+ lastSnapLinesKey = "";
5246
+ input.setSnapLines([]);
5247
+ if (transform) {
5248
+ input.markDirty();
5249
+ }
5250
+ input.setPointerCommitNonce((n) => n + 1);
5251
+ }
5252
+ return {
5253
+ begin(kind, id, pointer) {
5254
+ if (controller.isActive()) {
5255
+ return;
5256
+ }
5257
+ const input = getInput();
5258
+ const drag = input.dragStateRef.current;
5259
+ const resize = input.resizeStateRef.current;
5260
+ armed = kind === "move" && drag ? { kind, drag } : kind === "resize" && resize ? { kind, resize } : null;
5261
+ if (!armed) {
5262
+ return;
5263
+ }
5264
+ lastSnapLinesKey = "";
5265
+ const handle = armed.kind === "resize" ? armed.resize.handle : void 0;
5266
+ controller.begin(kind, id, pointer, handle);
5267
+ if (!controller.isActive()) {
5268
+ armed = null;
5269
+ }
5270
+ },
5271
+ isActive: () => controller.isActive(),
5272
+ dispose: () => {
5273
+ if (frameHandle !== 0) {
5274
+ frames.cancel(frameHandle);
5275
+ frameHandle = 0;
5276
+ }
5277
+ pending = null;
5278
+ armed = null;
5279
+ controller.dispose();
5280
+ }
5281
+ };
5402
5282
  }
5403
- function resolveLiveTarget(input) {
5404
- const { livePatcher, editTemplateMode, activeSlide } = input;
5405
- if (!livePatcher || editTemplateMode || !livePatcher.isActive()) {
5406
- return void 0;
5283
+ function commitMove(input, drag) {
5284
+ const { lastDx: dx, lastDy: dy } = drag;
5285
+ const movedIds = new Set(Object.keys(drag.startPositionsById));
5286
+ const moveElements = (elements) => {
5287
+ const moved = elements.map((el) => {
5288
+ const start = drag.startPositionsById[el.id];
5289
+ return start ? { ...el, x: start.x + dx, y: start.y + dy } : el;
5290
+ });
5291
+ return chunkJWNBTFZZ_js.applyReroutedConnectors(moved, chunkJWNBTFZZ_js.rerouteConnectorsForMovedElements(moved, movedIds));
5292
+ };
5293
+ if (input.editTemplateMode) {
5294
+ const slideId = input.activeSlide?.id;
5295
+ if (slideId) {
5296
+ input.setTemplateElementsBySlideId((prev) => ({
5297
+ ...prev,
5298
+ [slideId]: moveElements(prev[slideId] ?? [])
5299
+ }));
5300
+ }
5301
+ return;
5407
5302
  }
5408
- return { patcher: livePatcher, slideId: activeSlide?.id };
5303
+ input.updateSlides(
5304
+ (prev) => prev.map(
5305
+ (s, i) => i !== input.activeSlideIndex ? s : { ...s, elements: moveElements(s.elements) }
5306
+ )
5307
+ );
5308
+ }
5309
+ function commitResize(input, resize) {
5310
+ input.updateElementById(resize.elementId, {
5311
+ x: resize.lastX,
5312
+ y: resize.lastY,
5313
+ width: resize.lastWidth,
5314
+ height: resize.lastHeight
5315
+ });
5316
+ const movedIds = /* @__PURE__ */ new Set([resize.elementId]);
5317
+ input.updateSlides(
5318
+ (prev) => prev.map((s, i) => {
5319
+ if (i !== input.activeSlideIndex) {
5320
+ return s;
5321
+ }
5322
+ const rerouted = chunkJWNBTFZZ_js.rerouteConnectorsForMovedElements(s.elements, movedIds);
5323
+ return rerouted.length === 0 ? s : { ...s, elements: chunkJWNBTFZZ_js.applyReroutedConnectors(s.elements, rerouted) };
5324
+ })
5325
+ );
5409
5326
  }
5410
- function processPointerMove(e, input, tracker) {
5327
+ function processPointerMove(e, input) {
5411
5328
  const {
5412
5329
  editorScale,
5413
5330
  canvasStageRef,
5414
5331
  canvasSize,
5415
- snapToGrid,
5416
- snapToShape,
5417
- gridSpacingPx,
5418
- editTemplateMode,
5419
- templateElements,
5420
- activeSlide,
5421
- guides,
5422
- elementLookup,
5423
5332
  marqueeStateRef,
5424
- dragStateRef,
5425
- resizeStateRef,
5426
5333
  shapeAdjustmentDragStateRef,
5427
5334
  setMarqueeSelectionState,
5428
- setSnapLines,
5429
5335
  updateElementById
5430
5336
  } = input;
5431
5337
  const marquee = marqueeStateRef.current;
@@ -5440,31 +5346,6 @@ function processPointerMove(e, input, tracker) {
5440
5346
  );
5441
5347
  return;
5442
5348
  }
5443
- const drag = dragStateRef.current;
5444
- if (drag) {
5445
- processDragMove(
5446
- e,
5447
- drag,
5448
- editorScale,
5449
- snapToGrid,
5450
- snapToShape,
5451
- gridSpacingPx,
5452
- editTemplateMode,
5453
- templateElements,
5454
- activeSlide,
5455
- guides,
5456
- elementLookup,
5457
- tracker,
5458
- setSnapLines,
5459
- resolveLiveTarget(input)
5460
- );
5461
- return;
5462
- }
5463
- const rs = resizeStateRef.current;
5464
- if (rs) {
5465
- processResizeMove(e, rs, editorScale, snapToGrid, gridSpacingPx, resolveLiveTarget(input));
5466
- return;
5467
- }
5468
5349
  const adj = shapeAdjustmentDragStateRef.current;
5469
5350
  if (adj) {
5470
5351
  processAdjustmentMove(e, adj, editorScale, updateElementById);
@@ -5480,129 +5361,6 @@ function processMarqueeMove(e, marquee, canvasStageRef, canvasSize, editorScale,
5480
5361
  marquee.currentY = Math.max(0, Math.min(canvasSize.height, (e.clientY - rect.top) / editorScale));
5481
5362
  setMarqueeSelectionState({ ...marquee });
5482
5363
  }
5483
- function processDragMove(e, drag, editorScale, snapToGrid, snapToShape, gridSpacingPx, editTemplateMode, templateElements, activeSlide, guides, elementLookup, tracker, setSnapLines, live) {
5484
- const dx = (e.clientX - drag.startClientX) / editorScale;
5485
- const dy = (e.clientY - drag.startClientY) / editorScale;
5486
- if (!drag.moved && (Math.abs(dx) > 2 || Math.abs(dy) > 2)) {
5487
- drag.moved = true;
5488
- }
5489
- if (!drag.moved) {
5490
- return;
5491
- }
5492
- let appliedDx = dx;
5493
- let appliedDy = dy;
5494
- const draggedIds = Object.keys(drag.startPositionsById);
5495
- const primaryId = draggedIds[0];
5496
- const primaryStart = primaryId ? drag.startPositionsById[primaryId] : void 0;
5497
- const primaryEl = primaryId ? elementLookup.get(primaryId) : void 0;
5498
- if (primaryStart && primaryEl) {
5499
- let targetX = primaryStart.x + appliedDx;
5500
- let targetY = primaryStart.y + appliedDy;
5501
- if (snapToGrid) {
5502
- targetX = Math.round(targetX / gridSpacingPx) * gridSpacingPx;
5503
- targetY = Math.round(targetY / gridSpacingPx) * gridSpacingPx;
5504
- }
5505
- if (snapToShape) {
5506
- const siblingSource = editTemplateMode ? templateElements : activeSlide?.elements ?? [];
5507
- const siblings = siblingSource.map((el) => ({
5508
- id: el.id,
5509
- x: el.x,
5510
- y: el.y,
5511
- width: el.width,
5512
- height: el.height
5513
- }));
5514
- const snapResult = chunkJAI42EXQ_js.computeSnapToShape(
5515
- targetX,
5516
- targetY,
5517
- primaryEl.width,
5518
- primaryEl.height,
5519
- siblings,
5520
- new Set(draggedIds),
5521
- guides.map((g) => ({ axis: g.axis, position: g.position }))
5522
- );
5523
- targetX = snapResult.x;
5524
- targetY = snapResult.y;
5525
- const newSnapLines = snapResult.lines.map((line) => ({
5526
- axis: line.axis === "v" ? "x" : "y",
5527
- position: line.position
5528
- }));
5529
- const newKey = JSON.stringify(newSnapLines);
5530
- if (newKey !== tracker.lastSnapLinesKey) {
5531
- tracker.lastSnapLinesKey = newKey;
5532
- setSnapLines(newSnapLines);
5533
- }
5534
- } else if (tracker.lastSnapLinesKey !== "[]") {
5535
- tracker.lastSnapLinesKey = "[]";
5536
- setSnapLines([]);
5537
- }
5538
- appliedDx = targetX - primaryStart.x;
5539
- appliedDy = targetY - primaryStart.y;
5540
- }
5541
- drag.lastDx = appliedDx;
5542
- drag.lastDy = appliedDy;
5543
- for (const [id, domEl] of drag.domEls) {
5544
- const start = drag.startPositionsById[id];
5545
- if (start) {
5546
- const x = start.x + appliedDx;
5547
- const y = start.y + appliedDy;
5548
- domEl.style.left = `${x}px`;
5549
- domEl.style.top = `${y}px`;
5550
- syncSelectionHandleOverlay(domEl, id, { x, y });
5551
- }
5552
- }
5553
- if (live) {
5554
- for (const id of Object.keys(drag.startPositionsById)) {
5555
- const start = drag.startPositionsById[id];
5556
- pptx.publishLiveGeometry(live.patcher, live.slideId, id, {
5557
- x: start.x + appliedDx,
5558
- y: start.y + appliedDy
5559
- });
5560
- }
5561
- }
5562
- }
5563
- function processResizeMove(e, rs, editorScale, snapToGrid, gridSpacingPx, live) {
5564
- const dx = (e.clientX - rs.startClientX) / editorScale;
5565
- const dy = (e.clientY - rs.startClientY) / editorScale;
5566
- if (!rs.moved && (Math.abs(dx) > 2 || Math.abs(dy) > 2)) {
5567
- rs.moved = true;
5568
- }
5569
- if (!rs.moved) {
5570
- return;
5571
- }
5572
- const geo = computeResizeGeometry(
5573
- rs.handle,
5574
- rs.startX,
5575
- rs.startY,
5576
- rs.startWidth,
5577
- rs.startHeight,
5578
- dx,
5579
- dy,
5580
- snapToGrid,
5581
- gridSpacingPx,
5582
- e.shiftKey
5583
- );
5584
- rs.lastX = geo.x;
5585
- rs.lastY = geo.y;
5586
- rs.lastWidth = geo.width;
5587
- rs.lastHeight = geo.height;
5588
- const width = Math.max(geo.width, chunkJAI42EXQ_js.MIN_ELEMENT_SIZE);
5589
- const height = Math.max(geo.height, chunkJAI42EXQ_js.MIN_ELEMENT_SIZE);
5590
- if (rs.domEl) {
5591
- rs.domEl.style.left = `${geo.x}px`;
5592
- rs.domEl.style.top = `${geo.y}px`;
5593
- rs.domEl.style.width = `${width}px`;
5594
- rs.domEl.style.height = `${height}px`;
5595
- syncSelectionHandleOverlay(rs.domEl, rs.elementId, { x: geo.x, y: geo.y, width, height });
5596
- }
5597
- if (live) {
5598
- pptx.publishLiveGeometry(live.patcher, live.slideId, rs.elementId, {
5599
- x: geo.x,
5600
- y: geo.y,
5601
- width,
5602
- height
5603
- });
5604
- }
5605
- }
5606
5364
  function processAdjustmentMove(e, adj, editorScale, updateElementById) {
5607
5365
  const dx = (e.clientX - adj.startClientX) / editorScale;
5608
5366
  const dy = (e.clientY - adj.startClientY) / editorScale;
@@ -5621,26 +5379,20 @@ function processPointerUp(input) {
5621
5379
  editTemplateMode,
5622
5380
  templateElements,
5623
5381
  activeSlide,
5624
- activeSlideIndex,
5625
5382
  marqueeStateRef,
5626
5383
  dragStateRef,
5627
5384
  resizeStateRef,
5628
5385
  shapeAdjustmentDragStateRef,
5629
5386
  justInteractedRef,
5387
+ gestureRef,
5630
5388
  setMarqueeSelectionState,
5631
- setSnapLines,
5632
- setTemplateElementsBySlideId,
5633
5389
  setPointerCommitNonce,
5634
5390
  applySelection,
5635
5391
  clearSelection,
5636
- updateSlides,
5637
- updateElementById,
5638
5392
  markDirty,
5639
5393
  livePatcher
5640
5394
  } = input;
5641
5395
  const marquee = marqueeStateRef.current;
5642
- const drag = dragStateRef.current;
5643
- const rs = resizeStateRef.current;
5644
5396
  const adj = shapeAdjustmentDragStateRef.current;
5645
5397
  if (marquee) {
5646
5398
  commitMarquee(
@@ -5651,62 +5403,22 @@ function processPointerUp(input) {
5651
5403
  applySelection,
5652
5404
  clearSelection
5653
5405
  );
5654
- marqueeStateRef.current = null;
5655
- setMarqueeSelectionState(null);
5656
5406
  }
5657
- if (drag?.moved) {
5658
- commitDrag(
5659
- drag,
5660
- editTemplateMode,
5661
- activeSlide,
5662
- activeSlideIndex,
5663
- setTemplateElementsBySlideId,
5664
- updateSlides
5665
- );
5407
+ if (!gestureRef?.current?.isActive()) {
5408
+ dragStateRef.current = null;
5409
+ resizeStateRef.current = null;
5666
5410
  }
5667
- if (rs?.moved) {
5668
- const resizedId = rs.elementId;
5669
- const resizeUpdates = {
5670
- x: rs.lastX,
5671
- y: rs.lastY,
5672
- width: rs.lastWidth,
5673
- height: rs.lastHeight
5674
- };
5675
- updateElementById(resizedId, resizeUpdates);
5676
- const movedIds = /* @__PURE__ */ new Set([resizedId]);
5677
- updateSlides(
5678
- (prev) => prev.map((s, i) => {
5679
- if (i !== activeSlideIndex) {
5680
- return s;
5681
- }
5682
- const rerouted = chunkJAI42EXQ_js.rerouteConnectorsForMovedElements(s.elements, movedIds);
5683
- if (rerouted.length === 0) {
5684
- return s;
5685
- }
5686
- return {
5687
- ...s,
5688
- elements: chunkJAI42EXQ_js.applyReroutedConnectors(s.elements, rerouted)
5689
- };
5690
- })
5691
- );
5692
- }
5693
- const wasMoved = drag?.moved || rs?.moved || adj?.moved;
5694
- if (wasMoved) {
5411
+ if (adj?.moved) {
5695
5412
  justInteractedRef.current = true;
5696
- }
5697
- if (wasMoved) {
5698
5413
  livePatcher?.flush();
5699
5414
  }
5700
5415
  marqueeStateRef.current = null;
5701
- dragStateRef.current = null;
5702
- resizeStateRef.current = null;
5703
5416
  shapeAdjustmentDragStateRef.current = null;
5704
5417
  setMarqueeSelectionState(null);
5705
- setSnapLines([]);
5706
- if (wasMoved) {
5418
+ if (adj?.moved) {
5707
5419
  markDirty();
5708
5420
  }
5709
- if (drag || rs || adj || marquee) {
5421
+ if (adj || marquee) {
5710
5422
  setPointerCommitNonce((n) => n + 1);
5711
5423
  }
5712
5424
  }
@@ -5726,35 +5438,6 @@ function commitMarquee(marquee, editTemplateMode, templateElements, activeSlide,
5726
5438
  clearSelection();
5727
5439
  }
5728
5440
  }
5729
- function commitDrag(drag, editTemplateMode, activeSlide, activeSlideIndex, setTemplateElementsBySlideId, updateSlides) {
5730
- const dx = drag.lastDx, dy = drag.lastDy;
5731
- const movedIds = new Set(Object.keys(drag.startPositionsById));
5732
- const moveElements = (elements) => {
5733
- const movedElements = elements.map((el) => {
5734
- const start = drag.startPositionsById[el.id];
5735
- if (!start) {
5736
- return el;
5737
- }
5738
- return { ...el, x: start.x + dx, y: start.y + dy };
5739
- });
5740
- const rerouted = chunkJAI42EXQ_js.rerouteConnectorsForMovedElements(movedElements, movedIds);
5741
- return chunkJAI42EXQ_js.applyReroutedConnectors(movedElements, rerouted);
5742
- };
5743
- if (editTemplateMode) {
5744
- const slideId = activeSlide?.id;
5745
- if (!slideId) {
5746
- return;
5747
- }
5748
- setTemplateElementsBySlideId((prev) => ({
5749
- ...prev,
5750
- [slideId]: moveElements(prev[slideId] ?? [])
5751
- }));
5752
- return;
5753
- }
5754
- updateSlides(
5755
- (prev) => prev.map((s, i) => i !== activeSlideIndex ? s : { ...s, elements: moveElements(s.elements) })
5756
- );
5757
- }
5758
5441
 
5759
5442
  // src/viewer/hooks/usePointerHandlers.ts
5760
5443
  function usePointerHandlers(input) {
@@ -5764,41 +5447,42 @@ function usePointerHandlers(input) {
5764
5447
  canvasSize,
5765
5448
  activeSlide,
5766
5449
  activeSlideIndex,
5767
- gridSpacingPx,
5768
- dragStateRef,
5769
- resizeStateRef,
5770
5450
  shapeAdjustmentDragStateRef,
5771
5451
  marqueeStateRef,
5772
5452
  editTemplateMode,
5773
- snapToGrid,
5774
- snapToShape,
5775
- guides,
5776
5453
  templateElements,
5777
- elementLookup,
5778
5454
  setMarqueeSelectionState,
5779
- setSnapLines,
5780
- setTemplateElementsBySlideId,
5781
5455
  setPointerCommitNonce,
5782
5456
  applySelection,
5783
5457
  clearSelection,
5784
- updateSlides,
5785
5458
  updateElementById,
5786
5459
  markDirty,
5787
- livePatcher
5460
+ livePatcher,
5461
+ gestureRef
5788
5462
  } = input;
5463
+ const inputRef = React17.useRef(input);
5464
+ inputRef.current = input;
5465
+ const gestures = React17.useMemo(() => createCanvasGestures(() => inputRef.current), []);
5789
5466
  React17.useEffect(() => {
5790
- const tracker = {
5791
- rafId: 0,
5792
- pendingMoveEvent: null,
5793
- lastSnapLinesKey: ""
5467
+ if (gestureRef) {
5468
+ gestureRef.current = gestures;
5469
+ }
5470
+ return () => {
5471
+ gestures.dispose();
5472
+ if (gestureRef?.current === gestures) {
5473
+ gestureRef.current = null;
5474
+ }
5794
5475
  };
5476
+ }, [gestures, gestureRef]);
5477
+ React17.useEffect(() => {
5478
+ const tracker = { rafId: 0, pendingMoveEvent: null };
5795
5479
  const handlePointerMove = (e) => {
5796
5480
  tracker.pendingMoveEvent = e;
5797
5481
  if (tracker.rafId === 0) {
5798
5482
  tracker.rafId = requestAnimationFrame(() => {
5799
5483
  tracker.rafId = 0;
5800
5484
  if (tracker.pendingMoveEvent) {
5801
- processPointerMove(tracker.pendingMoveEvent, input, tracker);
5485
+ processPointerMove(tracker.pendingMoveEvent, input);
5802
5486
  tracker.pendingMoveEvent = null;
5803
5487
  }
5804
5488
  });
@@ -5826,31 +5510,22 @@ function usePointerHandlers(input) {
5826
5510
  }, [
5827
5511
  editorScale,
5828
5512
  canvasStageRef,
5829
- dragStateRef,
5830
- resizeStateRef,
5831
5513
  shapeAdjustmentDragStateRef,
5832
5514
  marqueeStateRef,
5833
5515
  editTemplateMode,
5834
- snapToGrid,
5835
- snapToShape,
5836
- guides,
5837
5516
  templateElements,
5838
5517
  setMarqueeSelectionState,
5839
- setSnapLines,
5840
- elementLookup,
5841
- setTemplateElementsBySlideId,
5842
5518
  setPointerCommitNonce,
5843
5519
  activeSlide,
5844
5520
  activeSlideIndex,
5845
5521
  canvasSize.width,
5846
5522
  canvasSize.height,
5847
- gridSpacingPx,
5848
5523
  applySelection,
5849
5524
  clearSelection,
5850
- updateSlides,
5851
5525
  updateElementById,
5852
5526
  markDirty,
5853
- livePatcher
5527
+ livePatcher,
5528
+ gestureRef
5854
5529
  ]);
5855
5530
  }
5856
5531
  function mouseDownStartsSelectionDrag(event) {
@@ -5876,6 +5551,7 @@ function useCanvasInteractions(input) {
5876
5551
  shapeAdjustmentDragStateRef,
5877
5552
  marqueeStateRef,
5878
5553
  justInteractedRef,
5554
+ gestureRef,
5879
5555
  setInlineEditingElementId,
5880
5556
  setInlineEditingText,
5881
5557
  setContextMenuState,
@@ -5901,25 +5577,7 @@ function useCanvasInteractions(input) {
5901
5577
  const scale = editorScale || 1;
5902
5578
  return rect ? { x: (e.clientX - rect.left) / scale, y: (e.clientY - rect.top) / scale } : null;
5903
5579
  };
5904
- const drillChain = (elementId, e) => {
5905
- if (!slideElements) {
5906
- return null;
5907
- }
5908
- const top = slideElements.find((el) => el.id === elementId);
5909
- const point = slidePoint(e);
5910
- if (!top || !point || !pptx.isEnterableGroup(top)) {
5911
- return null;
5912
- }
5913
- return pptx.memberChainAtPoint(slideElements, elementId, point);
5914
- };
5915
- const resolvePressTarget = (elementId, e) => {
5916
- const chain = drillChain(elementId, e);
5917
- if (!chain || !slideElements) {
5918
- return elementId;
5919
- }
5920
- const selectedPath = selectedElementId ? pptx.findElementPath(slideElements, selectedElementId) : null;
5921
- return pptx.drillSelectionForClick(chain, selectedPath) ?? elementId;
5922
- };
5580
+ const resolvePressTarget = (elementId, e) => slideElements ? pptx.resolveGroupPressTarget(slideElements, elementId, slidePoint(e), effectiveSelectedIds) : elementId;
5923
5581
  const handleInlineEditCommit = () => {
5924
5582
  const editId = inlineEditingElementId;
5925
5583
  if (!editId) {
@@ -6019,9 +5677,7 @@ function useCanvasInteractions(input) {
6019
5677
  }
6020
5678
  };
6021
5679
  const handleElementDoubleClick = (pressedId, e) => {
6022
- const chain = mode === "present" ? null : drillChain(pressedId, e);
6023
- const innermost = chain ? pptx.drillSelectionForDoubleClick(chain) : null;
6024
- const elementId = innermost && pptx.canInteractWithElement(elementLookup.get(innermost), "select") ? innermost : pressedId;
5680
+ const elementId = mode === "present" || !slideElements ? pressedId : pptx.resolveGroupDoubleClickTarget(slideElements, pressedId, slidePoint(e));
6025
5681
  if (elementId !== pressedId) {
6026
5682
  ops.applySelection(elementId);
6027
5683
  }
@@ -6084,6 +5740,7 @@ function useCanvasInteractions(input) {
6084
5740
  lastDy: 0
6085
5741
  };
6086
5742
  setSnapLines([]);
5743
+ gestureRef?.current?.begin("move", movableIds[0], e);
6087
5744
  };
6088
5745
  const handleElementContextMenu = (elementId, e) => {
6089
5746
  if (mode === "present") {
@@ -6156,6 +5813,7 @@ function useCanvasInteractions(input) {
6156
5813
  lastWidth: el.width,
6157
5814
  lastHeight: el.height
6158
5815
  };
5816
+ gestureRef?.current?.begin("resize", elementId, e);
6159
5817
  };
6160
5818
  const handleRotate = (elementId, rotationDeg) => {
6161
5819
  const el = elementLookup.get(elementId);
@@ -6497,7 +6155,7 @@ function createStructuredElementHandlers(deps) {
6497
6155
  return;
6498
6156
  }
6499
6157
  const resolved = resolveHyperlinkEditResult(data);
6500
- if (resolved.url && !chunkJAI42EXQ_js.isUrlSafe(resolved.url)) {
6158
+ if (resolved.url && !chunkJWNBTFZZ_js.isUrlSafe(resolved.url)) {
6501
6159
  return;
6502
6160
  }
6503
6161
  const actionClick = {
@@ -6543,7 +6201,7 @@ function createStructuredElementHandlers(deps) {
6543
6201
  if (!activeSlide) {
6544
6202
  return;
6545
6203
  }
6546
- const preset = chunkJAI42EXQ_js.ACTION_BUTTON_PRESETS.find((p) => p.shapeType === shapeType);
6204
+ const preset = chunkJWNBTFZZ_js.ACTION_BUTTON_PRESETS.find((p) => p.shapeType === shapeType);
6547
6205
  if (!preset) {
6548
6206
  return;
6549
6207
  }
@@ -6630,7 +6288,7 @@ function useInsertElements(input) {
6630
6288
  width: 300,
6631
6289
  height: 60,
6632
6290
  text: "",
6633
- textStyle: { fontSize: chunkJAI42EXQ_js.DEFAULT_TEXT_FONT_SIZE }
6291
+ textStyle: { fontSize: chunkJWNBTFZZ_js.DEFAULT_TEXT_FONT_SIZE }
6634
6292
  });
6635
6293
  };
6636
6294
  const handleAddShape = () => {
@@ -6652,7 +6310,7 @@ function useInsertElements(input) {
6652
6310
  }
6653
6311
  });
6654
6312
  };
6655
- const handleAddTable = (rows = chunkJAI42EXQ_js.DEFAULT_TABLE_ROWS, columns = chunkJAI42EXQ_js.DEFAULT_TABLE_COLUMNS) => {
6313
+ const handleAddTable = (rows = chunkJWNBTFZZ_js.DEFAULT_TABLE_ROWS, columns = chunkJWNBTFZZ_js.DEFAULT_TABLE_COLUMNS) => {
6656
6314
  if (!activeSlide) {
6657
6315
  return;
6658
6316
  }
@@ -6661,11 +6319,11 @@ function useInsertElements(input) {
6661
6319
  id: pptx.generateElementId()
6662
6320
  });
6663
6321
  };
6664
- const handleAddChart = (chartKind) => {
6322
+ const handleAddChart = (chartKind, options) => {
6665
6323
  if (!activeSlide) {
6666
6324
  return;
6667
6325
  }
6668
- addElement(pptx.createDefaultChartElement(chartKind));
6326
+ addElement(pptx.createDefaultChartElement(chartKind, void 0, options));
6669
6327
  };
6670
6328
  const structured = createStructuredElementHandlers({
6671
6329
  activeSlide,
@@ -6826,7 +6484,7 @@ function useGroupAlignLayerHandlers(input) {
6826
6484
  history
6827
6485
  } = input;
6828
6486
  const updateElementsOwning = (elementId, updater) => {
6829
- if (editTemplateMode && !chunkJAI42EXQ_js.isTemplateElementId(elementId)) {
6487
+ if (editTemplateMode && !chunkJWNBTFZZ_js.isTemplateElementId(elementId)) {
6830
6488
  ops.updateSlides(
6831
6489
  (prev) => prev.map(
6832
6490
  (slide, index) => index === activeSlideIndex ? { ...slide, elements: updater(slide.elements) } : slide
@@ -6860,9 +6518,9 @@ function useGroupAlignLayerHandlers(input) {
6860
6518
  return;
6861
6519
  }
6862
6520
  const group = selectedElement;
6863
- const intoTemplate = chunkJAI42EXQ_js.isTemplateElementId(group.id);
6521
+ const intoTemplate = chunkJWNBTFZZ_js.isTemplateElementId(group.id);
6864
6522
  const childIds = group.children.map(
6865
- (child) => intoTemplate ? chunkJAI42EXQ_js.makeCloneId(true, child.id || group.id) : child.id || pptx.generateElementId()
6523
+ (child) => intoTemplate ? chunkJWNBTFZZ_js.makeCloneId(true, child.id || group.id) : child.id || pptx.generateElementId()
6866
6524
  );
6867
6525
  const { elements, childIds: usedIds } = pptx.ungroupElements(
6868
6526
  ops.activeElements,
@@ -7298,7 +6956,7 @@ function createTableMergeHandlers(input) {
7298
6956
  if (!nextCell || nextCell.hMerge || nextCell.vMerge) {
7299
6957
  return;
7300
6958
  }
7301
- const newTableData = chunkJAI42EXQ_js.mergeCells(
6959
+ const newTableData = chunkJWNBTFZZ_js.mergeCells(
7302
6960
  [
7303
6961
  { row: rowIndex, col: columnIndex },
7304
6962
  { row: rowIndex, col: nextColIdx }
@@ -7306,7 +6964,7 @@ function createTableMergeHandlers(input) {
7306
6964
  td
7307
6965
  );
7308
6966
  const updates = { tableData: newTableData };
7309
- const newRawXml = chunkJAI42EXQ_js.updateMergeAttrsInRawXml(selectedElement, newTableData);
6967
+ const newRawXml = chunkJWNBTFZZ_js.updateMergeAttrsInRawXml(selectedElement, newTableData);
7310
6968
  if (newRawXml) {
7311
6969
  updates.rawXml = newRawXml;
7312
6970
  }
@@ -7332,7 +6990,7 @@ function createTableMergeHandlers(input) {
7332
6990
  if (!targetNextCell || targetNextCell.hMerge || targetNextCell.vMerge) {
7333
6991
  return;
7334
6992
  }
7335
- const newTableData = chunkJAI42EXQ_js.mergeCells(
6993
+ const newTableData = chunkJWNBTFZZ_js.mergeCells(
7336
6994
  [
7337
6995
  { row: rowIndex, col: columnIndex },
7338
6996
  { row: targetNextRowIdx, col: columnIndex }
@@ -7340,7 +6998,7 @@ function createTableMergeHandlers(input) {
7340
6998
  td
7341
6999
  );
7342
7000
  const updates = { tableData: newTableData };
7343
- const newRawXml = chunkJAI42EXQ_js.updateMergeAttrsInRawXml(selectedElement, newTableData);
7001
+ const newRawXml = chunkJWNBTFZZ_js.updateMergeAttrsInRawXml(selectedElement, newTableData);
7344
7002
  if (newRawXml) {
7345
7003
  updates.rawXml = newRawXml;
7346
7004
  }
@@ -7355,9 +7013,9 @@ function createTableMergeHandlers(input) {
7355
7013
  return;
7356
7014
  }
7357
7015
  const td = selectedElement.tableData;
7358
- const newTableData = chunkJAI42EXQ_js.mergeCells(ts.selectedCells, td);
7016
+ const newTableData = chunkJWNBTFZZ_js.mergeCells(ts.selectedCells, td);
7359
7017
  const updates = { tableData: newTableData };
7360
- const newRawXml = chunkJAI42EXQ_js.updateMergeAttrsInRawXml(selectedElement, newTableData);
7018
+ const newRawXml = chunkJWNBTFZZ_js.updateMergeAttrsInRawXml(selectedElement, newTableData);
7361
7019
  if (newRawXml) {
7362
7020
  updates.rawXml = newRawXml;
7363
7021
  }
@@ -7374,9 +7032,9 @@ function createTableMergeHandlers(input) {
7374
7032
  }
7375
7033
  const { rowIndex, columnIndex } = ts;
7376
7034
  const td = selectedElement.tableData;
7377
- const newTableData = chunkJAI42EXQ_js.splitCell(rowIndex, columnIndex, td);
7035
+ const newTableData = chunkJWNBTFZZ_js.splitCell(rowIndex, columnIndex, td);
7378
7036
  const updates = { tableData: newTableData };
7379
- const newRawXml = chunkJAI42EXQ_js.updateMergeAttrsInRawXml(selectedElement, newTableData);
7037
+ const newRawXml = chunkJWNBTFZZ_js.updateMergeAttrsInRawXml(selectedElement, newTableData);
7380
7038
  if (newRawXml) {
7381
7039
  updates.rawXml = newRawXml;
7382
7040
  }
@@ -7411,7 +7069,7 @@ function createTableStructHandlers(input) {
7411
7069
  updates.tableData = pptx.setCellText(el, rowIndex, colIndex, text).tableData;
7412
7070
  }
7413
7071
  if (el.rawXml) {
7414
- const newRawXml = chunkJAI42EXQ_js.updateCellTextInRawXml(el, rowIndex, colIndex, text);
7072
+ const newRawXml = chunkJWNBTFZZ_js.updateCellTextInRawXml(el, rowIndex, colIndex, text);
7415
7073
  if (newRawXml) {
7416
7074
  updates.rawXml = newRawXml;
7417
7075
  }
@@ -7435,7 +7093,7 @@ function createTableStructHandlers(input) {
7435
7093
  const { rowIndex, columnIndex: colIndex } = ts;
7436
7094
  const updates = {};
7437
7095
  if (selectedElement.rawXml) {
7438
- const newRawXml = chunkJAI42EXQ_js.updateCellTextStyleInRawXml(
7096
+ const newRawXml = chunkJWNBTFZZ_js.updateCellTextStyleInRawXml(
7439
7097
  selectedElement,
7440
7098
  rowIndex,
7441
7099
  colIndex,
@@ -7556,6 +7214,8 @@ async function renderToCanvas(element, options = {}) {
7556
7214
  const { default: html2canvasPro } = await import('html2canvas-pro');
7557
7215
  return html2canvasPro(element, {
7558
7216
  ...options,
7217
+ // Clone only the captured element's branch: html2canvas would copy the whole page.
7218
+ ignoreElements: pptx.html2canvasCaptureScope(element, options.ignoreElements),
7559
7219
  onclone: async (doc, clonedEl) => {
7560
7220
  await pptx.prepareHtml2CanvasClone(element, doc, clonedEl);
7561
7221
  if (typeof userOnClone === "function") {
@@ -7611,7 +7271,7 @@ function useExportSaveAs(input) {
7611
7271
  const sourceName = filePath ? filePath.replace(/\\/gu, "/").split("/").pop() : void 0;
7612
7272
  const slideSize = pptx.resolveSlideSizeSelection({ current: slideSizeEmu, canvas: canvasSize }).size;
7613
7273
  const data = {
7614
- slides: chunkJAI42EXQ_js.buildSaveSlides(slides, templateElementsBySlideId),
7274
+ slides: chunkJWNBTFZZ_js.buildSaveSlides(slides, templateElementsBySlideId),
7615
7275
  width: canvasSize.width,
7616
7276
  height: canvasSize.height,
7617
7277
  widthEmu: slideSize.widthEmu,
@@ -7773,7 +7433,7 @@ async function captureAllSlidesAsPngDataUrls(slideStageRef, totalSlides, setActi
7773
7433
  }
7774
7434
  function tilesToPdfPage(tilesResult) {
7775
7435
  return tilesResult.tiles.map((tile) => ({
7776
- image: chunkJAI42EXQ_js.canvasToJpegData(tile.canvas),
7436
+ image: chunkJWNBTFZZ_js.canvasToJpegData(tile.canvas),
7777
7437
  placement: pptx.placeTileOnPage(
7778
7438
  tile,
7779
7439
  tilesResult.fullWidth,
@@ -7806,7 +7466,7 @@ async function exportAllSlidesAsPdf(slideStageRef, totalSlides, setActiveSlide,
7806
7466
  if (pages.length === 0) {
7807
7467
  throw new Error(i18n.translationsEn["pptx.export.errorNoSlidesPdf"]);
7808
7468
  }
7809
- const pdfBlobUrl = chunkJAI42EXQ_js.buildPdfFromTiledImageData(pages);
7469
+ const pdfBlobUrl = chunkJWNBTFZZ_js.buildPdfFromTiledImageData(pages);
7810
7470
  pptx.downloadDataUrl(pdfBlobUrl, filename);
7811
7471
  }
7812
7472
  async function exportAllSlidesAsNotesPdf(slideStageRef, totalSlides, setActiveSlide, currentSlideIndex, slideNotes, filename = "presentation-notes.pdf", options = {}) {
@@ -7836,7 +7496,7 @@ async function exportAllSlidesAsNotesPdf(slideStageRef, totalSlides, setActiveSl
7836
7496
  if (pages.length === 0) {
7837
7497
  throw new Error(i18n.translationsEn["pptx.export.errorNoSlidesNotesPdf"]);
7838
7498
  }
7839
- const pdfDataUrl = chunkJAI42EXQ_js.buildNotesPdf(pages);
7499
+ const pdfDataUrl = chunkJWNBTFZZ_js.buildNotesPdf(pages);
7840
7500
  pptx.downloadDataUrl(pdfDataUrl, filename);
7841
7501
  }
7842
7502
  async function exportAllSlidesAsVideo(slideStageRef, totalSlides, setActiveSlide, currentSlideIndex, options = {}) {
@@ -8939,7 +8599,7 @@ function usePropertyHandlers(input) {
8939
8599
  width: canvasSize.width,
8940
8600
  height: canvasSize.height
8941
8601
  };
8942
- setCompareResult(chunkJAI42EXQ_js.comparePresentation(cur, other));
8602
+ setCompareResult(chunkJWNBTFZZ_js.comparePresentation(cur, other));
8943
8603
  setIsComparePanelOpen(true);
8944
8604
  } catch (err) {
8945
8605
  console.warn("Compare failed:", err);
@@ -9108,6 +8768,7 @@ function useViewerDialogs(input) {
9108
8768
  embeddedFontFamilies
9109
8769
  } = input;
9110
8770
  const [isSmartArtDialogOpen, setIsSmartArtDialogOpen] = React17.useState(false);
8771
+ const [isChartDialogOpen, setIsChartDialogOpen] = React17.useState(false);
9111
8772
  const [isEquationDialogOpen, setIsEquationDialogOpen] = React17.useState(false);
9112
8773
  const [isHyperlinkDialogOpen, setIsHyperlinkDialogOpen] = React17.useState(false);
9113
8774
  const [isPasswordDialogOpen, setIsPasswordDialogOpen] = React17.useState(false);
@@ -9252,6 +8913,8 @@ function useViewerDialogs(input) {
9252
8913
  return {
9253
8914
  isSmartArtDialogOpen,
9254
8915
  setIsSmartArtDialogOpen,
8916
+ isChartDialogOpen,
8917
+ setIsChartDialogOpen,
9255
8918
  isEquationDialogOpen,
9256
8919
  setIsEquationDialogOpen,
9257
8920
  isHyperlinkDialogOpen,
@@ -9292,7 +8955,7 @@ function useViewerDialogs(input) {
9292
8955
  };
9293
8956
  }
9294
8957
  function computeGridSpacingPx(documentGridSpacing) {
9295
- return pptx.computeGridSpacingPx(documentGridSpacing, chunkJAI42EXQ_js.GRID_SIZE);
8958
+ return pptx.computeGridSpacingPx(documentGridSpacing, chunkJWNBTFZZ_js.GRID_SIZE);
9296
8959
  }
9297
8960
  function computeVisibleSlideIndexes(slides, activeCustomShowId, customShows, presentationProperties) {
9298
8961
  const activeShow = activeCustomShowId ? customShows.find((show) => show.id === activeCustomShowId) : void 0;
@@ -9301,7 +8964,7 @@ function computeVisibleSlideIndexes(slides, activeCustomShowId, customShows, pre
9301
8964
  }
9302
8965
  function computeSlideSectionGroups(slides, sections) {
9303
8966
  return pptx.groupSlidesBySection(sections, slides).map((group) => ({
9304
- id: group.section?.id ?? (sections.length > 0 ? chunkJAI42EXQ_js.UNGROUPED_SECTION_ID : chunkJAI42EXQ_js.DEFAULT_SECTION_GROUP_ID),
8967
+ id: group.section?.id ?? (sections.length > 0 ? chunkJWNBTFZZ_js.UNGROUPED_SECTION_ID : chunkJWNBTFZZ_js.DEFAULT_SECTION_GROUP_ID),
9305
8968
  label: group.section?.name ?? (sections.length > 0 ? "Ungrouped Slides" : "Slides"),
9306
8969
  slideIndexes: group.slideIndexes,
9307
8970
  ...group.section?.color !== void 0 ? { color: group.section.color } : {},
@@ -9346,10 +9009,10 @@ function useDerivedSlideState(input) {
9346
9009
  );
9347
9010
  const slideSectionGroups = React17.useMemo(
9348
9011
  () => computeSlideSectionGroups(slides, sections).map((group) => {
9349
- if (group.id === chunkJAI42EXQ_js.UNGROUPED_SECTION_ID && group.label === "Ungrouped Slides") {
9012
+ if (group.id === chunkJWNBTFZZ_js.UNGROUPED_SECTION_ID && group.label === "Ungrouped Slides") {
9350
9013
  return { ...group, label: t("pptx.slides.ungroupedSlides") };
9351
9014
  }
9352
- if (group.id === chunkJAI42EXQ_js.DEFAULT_SECTION_GROUP_ID && group.label === "Slides") {
9015
+ if (group.id === chunkJWNBTFZZ_js.DEFAULT_SECTION_GROUP_ID && group.label === "Slides") {
9353
9016
  return { ...group, label: t("pptx.sections.slides") };
9354
9017
  }
9355
9018
  return group;
@@ -9456,7 +9119,7 @@ function useAnnotationHandlers(input) {
9456
9119
  if (nextMode === "present") {
9457
9120
  presentation.enterPresentMode();
9458
9121
  } else if (mode === "present" && annotations.hasAnyAnnotations) {
9459
- chunkJAI42EXQ_js.stopAllPersistentAudio();
9122
+ chunkJWNBTFZZ_js.stopAllPersistentAudio();
9460
9123
  if (promptKeepInkAnnotations) {
9461
9124
  pendingModeAfterAnnotationsRef.current = nextMode;
9462
9125
  setShowKeepAnnotationsDialog(true);
@@ -9466,7 +9129,7 @@ function useAnnotationHandlers(input) {
9466
9129
  }
9467
9130
  } else {
9468
9131
  if (mode === "present") {
9469
- chunkJAI42EXQ_js.stopAllPersistentAudio();
9132
+ chunkJWNBTFZZ_js.stopAllPersistentAudio();
9470
9133
  }
9471
9134
  setMode(nextMode);
9472
9135
  }
@@ -9633,7 +9296,7 @@ function useSerialize(input) {
9633
9296
  guides: pptxGuides.length > 0 ? pptxGuides : void 0
9634
9297
  };
9635
9298
  });
9636
- const slidesToSave = chunkJAI42EXQ_js.buildSaveSlides(slidesWithGuides, pending.templateElementsBySlideId);
9299
+ const slidesToSave = chunkJWNBTFZZ_js.buildSaveSlides(slidesWithGuides, pending.templateElementsBySlideId);
9637
9300
  const saveOptions = pptx.buildDeckSaveOptions({
9638
9301
  // Without this the Slide Size card edited a viewer-only pixel value and
9639
9302
  // the saved `p:sldSz` never moved: passing `slideSize` is the only way a
@@ -9697,84 +9360,35 @@ function useSerialize(input) {
9697
9360
  }
9698
9361
  function useRecoveryDetection(input) {
9699
9362
  const { filePath, fileName, loading, error, slideCount, autosaveAllowed = true } = input;
9700
- const recoveryCheckedRef = React17.useRef(false);
9701
- const recordRef = React17.useRef(null);
9702
- const actionPendingRef = React17.useRef(false);
9703
- const [prompt, setPrompt] = React17.useState(null);
9704
- const [discarding, setDiscarding] = React17.useState(false);
9705
- const onRestore = input.onRestore;
9706
- const storageRef = React17.useRef(input.storage);
9707
- storageRef.current = input.storage;
9708
- const onOfferedRef = React17.useRef(input.onOffered);
9709
- React17.useEffect(() => {
9710
- onOfferedRef.current = input.onOffered;
9711
- }, [input.onOffered]);
9712
- const openVersionHistory = input.openVersionHistory;
9363
+ const live = React17.useRef(input);
9364
+ live.current = input;
9365
+ const [controller] = React17.useState(
9366
+ () => pptx.createAutosaveRecoveryController({
9367
+ getStorage: () => live.current.storage,
9368
+ load: (bytes) => live.current.onRestore?.(bytes),
9369
+ onOffered: (record) => {
9370
+ live.current.onOffered?.(record);
9371
+ live.current.openVersionHistory?.();
9372
+ },
9373
+ probe: pptx.probeAutosaveRecovery,
9374
+ discardRecord: pptx.discardAutosaveRecovery
9375
+ })
9376
+ );
9377
+ const { prompt, discarding } = useController(controller);
9713
9378
  React17.useEffect(() => {
9714
- if (!pptx.shouldProbeAutosaveRecovery({
9715
- alreadyChecked: recoveryCheckedRef.current,
9716
- filePath,
9717
- loading,
9718
- error,
9719
- slideCount,
9720
- autosaveAllowed
9721
- })) {
9722
- return;
9723
- }
9724
- recoveryCheckedRef.current = true;
9725
- void (async () => {
9726
- const offer = await pptx.probeAutosaveRecovery(
9727
- filePath,
9728
- Date.now(),
9729
- fileName,
9730
- storageRef.current
9731
- );
9732
- if (!offer) {
9733
- return;
9734
- }
9735
- recordRef.current = offer.record;
9736
- setPrompt(offer.prompt);
9737
- onOfferedRef.current?.(offer.record);
9738
- openVersionHistory?.();
9739
- })();
9740
- }, [filePath, fileName, loading, error, slideCount, autosaveAllowed, openVersionHistory]);
9741
- const restore = React17.useCallback(() => {
9742
- if (actionPendingRef.current) {
9743
- return;
9744
- }
9745
- actionPendingRef.current = true;
9746
- const record = recordRef.current;
9747
- setPrompt(null);
9748
- if (record && onRestore) {
9749
- onRestore(pptx.acceptAutosaveRecovery(record));
9750
- pptx.acknowledgeAutosaveRecovery(record);
9751
- }
9752
- recordRef.current = null;
9753
- }, [onRestore]);
9754
- const discard = React17.useCallback(() => {
9755
- if (actionPendingRef.current) {
9756
- return;
9757
- }
9758
- const record = recordRef.current;
9759
- if (!record) {
9760
- setPrompt(null);
9761
- return;
9379
+ controller.check({ filePath, fileName, loading, error, slideCount, autosaveAllowed });
9380
+ }, [controller, filePath, fileName, loading, error, slideCount, autosaveAllowed]);
9381
+ return {
9382
+ prompt,
9383
+ discarding,
9384
+ restore: () => {
9385
+ void controller.restore().catch(() => {
9386
+ });
9387
+ },
9388
+ discard: () => {
9389
+ void controller.discard();
9762
9390
  }
9763
- actionPendingRef.current = true;
9764
- setDiscarding(true);
9765
- void (async () => {
9766
- try {
9767
- await pptx.discardAutosaveRecovery(record, storageRef.current);
9768
- recordRef.current = null;
9769
- setPrompt(null);
9770
- } catch {
9771
- } finally {
9772
- actionPendingRef.current = false;
9773
- setDiscarding(false);
9774
- }
9775
- })();
9776
- }, []);
9777
- return { prompt, restore, discard, discarding };
9391
+ };
9778
9392
  }
9779
9393
  function usePresentationSetup(input) {
9780
9394
  const {
@@ -9826,7 +9440,7 @@ function usePresentationSetup(input) {
9826
9440
  return;
9827
9441
  }
9828
9442
  if (mode === "present" && nextMode !== "present") {
9829
- chunkJAI42EXQ_js.stopAllPersistentAudio();
9443
+ chunkJWNBTFZZ_js.stopAllPersistentAudio();
9830
9444
  stopAnimationSound();
9831
9445
  const exitHandler = exitModeHandlerRef.current;
9832
9446
  if (exitHandler) {
@@ -9947,7 +9561,7 @@ function useCanvasImagePaste(input) {
9947
9561
  );
9948
9562
  }
9949
9563
  function formatPatchFor(element, format) {
9950
- const updated = chunkJAI42EXQ_js.applyFormatToElement(element, format);
9564
+ const updated = chunkJWNBTFZZ_js.applyFormatToElement(element, format);
9951
9565
  const updates = {};
9952
9566
  if (pptx$1.hasShapeProperties(updated)) {
9953
9567
  updates.shapeStyle = updated.shapeStyle;
@@ -9970,7 +9584,7 @@ function useFormatPainterEditing(input) {
9970
9584
  const prevFormatPainterRef = React17.useRef(false);
9971
9585
  React17.useEffect(() => {
9972
9586
  if (formatPainterActive && !prevFormatPainterRef.current && selectedElement) {
9973
- copiedFormatRef.current = chunkJAI42EXQ_js.copyFormatFromElement(selectedElement);
9587
+ copiedFormatRef.current = chunkJWNBTFZZ_js.copyFormatFromElement(selectedElement);
9974
9588
  } else if (!formatPainterActive) {
9975
9589
  copiedFormatRef.current = null;
9976
9590
  }
@@ -10248,6 +9862,7 @@ function useEditorOperations(input) {
10248
9862
  shapeAdjustmentDragStateRef: state.shapeAdjustmentDragStateRef,
10249
9863
  marqueeStateRef: state.marqueeStateRef,
10250
9864
  justInteractedRef: state.justInteractedRef,
9865
+ gestureRef: state.gestureControllerRef,
10251
9866
  setInlineEditingElementId: state.setInlineEditingElementId,
10252
9867
  setInlineEditingText: state.setInlineEditingText,
10253
9868
  setContextMenuState: state.setContextMenuState,
@@ -10780,6 +10395,8 @@ function useContentLifecycle(input) {
10780
10395
  // deck it has already snapshotted. The two refs are read by `.current`
10781
10396
  // because an inline edit in progress lives there and nowhere else yet.
10782
10397
  onSaved: input.onAutosave,
10398
+ inlineDraftSinkRef: state.autosaveDraftSinkRef,
10399
+ getInlineEditingId: () => state.inlineEditingElementIdRef.current,
10783
10400
  getChangeSources: () => [
10784
10401
  slides,
10785
10402
  state.templateElementsBySlideId,
@@ -10809,138 +10426,27 @@ function useKeyboardShortcuts(input) {
10809
10426
  inputRef.current = input;
10810
10427
  const handleKeyDown = React17.useCallback((e) => {
10811
10428
  const current = inputRef.current;
10812
- const startAction = current.customization && !pptx.isFeatureEnabled(current.customization, "presentMode") ? null : pptx.mapSlideShowStartKey(e, { isPresenting: current.mode === "present" });
10813
- if (startAction !== null) {
10814
- e.preventDefault();
10815
- if (startAction === "fromBeginning") {
10816
- current.onStartShowFromBeginning();
10817
- } else {
10818
- current.onStartShowFromCurrent();
10819
- }
10820
- return;
10821
- }
10822
- const { action, dx, dy } = pptx.mapCustomizedEditorKey(
10429
+ pptx.dispatchEditorKey(
10823
10430
  e,
10824
10431
  {
10825
10432
  canEdit: current.canEdit,
10826
- canPaste: current.canPaste,
10827
- // The Slide Master view is an editing surface, not a viewing one.
10828
- // Gating on `mode !== 'edit'` alone made `mapEditorKey` return
10829
- // NO_ACTION there, so Delete, the arrow-key nudges and the clipboard
10830
- // keys were all inert over a master shape even though the write path
10831
- // behind them routes to the owning part correctly. Svelte and
10832
- // vanilla, which render the master into their ordinary editable
10833
- // stage, never had the gap.
10433
+ ...current.canPaste === void 0 ? {} : { canPaste: current.canPaste },
10434
+ // The Slide Master view is an editing surface, not a viewing one, so
10435
+ // only the other modes count as "not editing" for the editor keymap.
10834
10436
  isPresenting: current.mode !== "edit" && current.mode !== "master",
10437
+ // F5 is only inert while the show itself runs: a read-only viewer can
10438
+ // still start a show (it has a "From Beginning" button too).
10439
+ isShowRunning: current.mode === "present",
10440
+ canStartShow: !current.customization || pptx.isFeatureEnabled(current.customization, "presentMode"),
10835
10441
  hasSelection: current.hasSelection,
10836
10442
  isEditingText: Boolean(
10837
10443
  current.inlineEditingElementId || current.tableEditorState?.isEditing
10838
10444
  ),
10839
10445
  isDrawing: current.activeTool !== "select",
10840
- isTextInputTarget: pptx.isEditorTextInputTarget(e.target),
10841
- isControlTarget: pptx.isEditorControlTarget(e.target)
10446
+ keyboard: current.customization?.keyboard
10842
10447
  },
10843
- current.customization?.keyboard
10448
+ toEditorKeyHandlers(current)
10844
10449
  );
10845
- if (action === null) {
10846
- return;
10847
- }
10848
- e.preventDefault();
10849
- switch (action) {
10850
- case "escape":
10851
- current.onEscape();
10852
- break;
10853
- case "delete":
10854
- current.onDelete();
10855
- break;
10856
- case "undo":
10857
- current.onUndo();
10858
- break;
10859
- case "redo":
10860
- current.onRedo();
10861
- break;
10862
- case "copy":
10863
- current.onCopy();
10864
- break;
10865
- case "cut":
10866
- current.onCut();
10867
- break;
10868
- case "paste":
10869
- current.onPaste();
10870
- break;
10871
- case "duplicate":
10872
- current.onDuplicate();
10873
- break;
10874
- case "selectAll":
10875
- current.onSelectAll();
10876
- break;
10877
- case "group":
10878
- current.onGroup?.();
10879
- break;
10880
- case "ungroup":
10881
- current.onUngroup?.();
10882
- break;
10883
- case "toggleShortcuts":
10884
- current.onToggleShortcuts?.();
10885
- break;
10886
- case "find":
10887
- current.onFind?.();
10888
- break;
10889
- case "nudge":
10890
- current.onNudge(dx ?? 0, dy ?? 0);
10891
- break;
10892
- case "prevSlide":
10893
- current.onPrevSlide?.();
10894
- break;
10895
- case "nextSlide":
10896
- current.onNextSlide?.();
10897
- break;
10898
- case "alignLeft":
10899
- current.onAlignLeft?.();
10900
- break;
10901
- case "alignCenter":
10902
- current.onAlignCenter?.();
10903
- break;
10904
- case "alignRight":
10905
- current.onAlignRight?.();
10906
- break;
10907
- case "alignJustify":
10908
- current.onAlignJustify?.();
10909
- break;
10910
- case "increaseFontSize":
10911
- current.onIncreaseFontSize?.();
10912
- break;
10913
- case "decreaseFontSize":
10914
- current.onDecreaseFontSize?.();
10915
- break;
10916
- case "copyFormat":
10917
- current.onCopyFormat?.();
10918
- break;
10919
- case "pasteFormat":
10920
- current.onPasteFormat?.();
10921
- break;
10922
- case "newSlide":
10923
- current.onNewSlide?.();
10924
- break;
10925
- case "hyperlink":
10926
- current.onHyperlink?.();
10927
- break;
10928
- case "findReplace":
10929
- current.onFindReplace?.();
10930
- break;
10931
- case "clearFormatting":
10932
- current.onClearFormatting?.();
10933
- break;
10934
- case "cycleSelectionNext":
10935
- current.onCycleSelectionNext?.();
10936
- break;
10937
- case "cycleSelectionPrev":
10938
- current.onCycleSelectionPrev?.();
10939
- break;
10940
- case "pasteSpecial":
10941
- current.onPasteSpecial?.();
10942
- break;
10943
- }
10944
10450
  }, []);
10945
10451
  React17.useEffect(() => {
10946
10452
  window.addEventListener("keydown", handleKeyDown);
@@ -10949,6 +10455,43 @@ function useKeyboardShortcuts(input) {
10949
10455
  };
10950
10456
  }, [handleKeyDown]);
10951
10457
  }
10458
+ function toEditorKeyHandlers(current) {
10459
+ return {
10460
+ startShowFromBeginning: current.onStartShowFromBeginning,
10461
+ startShowFromCurrent: current.onStartShowFromCurrent,
10462
+ escape: current.onEscape,
10463
+ delete: current.onDelete,
10464
+ undo: current.onUndo,
10465
+ redo: current.onRedo,
10466
+ copy: current.onCopy,
10467
+ cut: current.onCut,
10468
+ paste: current.onPaste,
10469
+ duplicate: current.onDuplicate,
10470
+ selectAll: current.onSelectAll,
10471
+ group: current.onGroup,
10472
+ ungroup: current.onUngroup,
10473
+ toggleShortcuts: current.onToggleShortcuts,
10474
+ find: current.onFind,
10475
+ nudge: current.onNudge,
10476
+ prevSlide: current.onPrevSlide,
10477
+ nextSlide: current.onNextSlide,
10478
+ alignLeft: current.onAlignLeft,
10479
+ alignCenter: current.onAlignCenter,
10480
+ alignRight: current.onAlignRight,
10481
+ alignJustify: current.onAlignJustify,
10482
+ increaseFontSize: current.onIncreaseFontSize,
10483
+ decreaseFontSize: current.onDecreaseFontSize,
10484
+ copyFormat: current.onCopyFormat,
10485
+ pasteFormat: current.onPasteFormat,
10486
+ newSlide: current.onNewSlide,
10487
+ hyperlink: current.onHyperlink,
10488
+ findReplace: current.onFindReplace,
10489
+ clearFormatting: current.onClearFormatting,
10490
+ cycleSelectionNext: current.onCycleSelectionNext,
10491
+ cycleSelectionPrev: current.onCycleSelectionPrev,
10492
+ pasteSpecial: current.onPasteSpecial
10493
+ };
10494
+ }
10952
10495
  var CLEAR_FORMATTING_PATCH = {
10953
10496
  bold: false,
10954
10497
  italic: false,
@@ -11214,7 +10757,8 @@ function useViewerIntegration(input) {
11214
10757
  updateSlides: editorOps.ops.updateSlides,
11215
10758
  updateElementById: editorOps.ops.updateElementById,
11216
10759
  markDirty: history.markDirty,
11217
- livePatcher: state.livePatcher
10760
+ livePatcher: state.livePatcher,
10761
+ gestureRef: state.gestureControllerRef
11218
10762
  });
11219
10763
  const [isEncryptedDialogOpen, setIsEncryptedDialogOpen] = React17.useState(false);
11220
10764
  const [loadVersion, setLoadVersion] = React17.useState(0);
@@ -11662,7 +11206,7 @@ function useCollaborationWriteBack(input) {
11662
11206
  getSourceBytes: () => latest.current.getSourceBytes?.() ?? null,
11663
11207
  getSaveOptions: () => latest.current.getSaveOptions?.(),
11664
11208
  getTemplateElements: () => latest.current.templateElementsBySlideId,
11665
- mergeTemplateElements: chunkJAI42EXQ_js.buildSaveSlides,
11209
+ mergeTemplateElements: chunkJWNBTFZZ_js.buildSaveSlides,
11666
11210
  onWriteBackStatus: () => latest.current.onWriteBackStatus?.(
11667
11211
  pptx.writeBackReport(latest.current.config, created.getState())
11668
11212
  )
@@ -12221,8 +11765,8 @@ function useTouchGestures(input) {
12221
11765
  }
12222
11766
  const recognizer = pptx.createTouchGestureRecognizer({
12223
11767
  getScale: () => scaleRef.current,
12224
- minScale: chunkJAI42EXQ_js.MIN_ZOOM_SCALE,
12225
- maxScale: chunkJAI42EXQ_js.MAX_ZOOM_SCALE,
11768
+ minScale: chunkJWNBTFZZ_js.MIN_ZOOM_SCALE,
11769
+ maxScale: chunkJWNBTFZZ_js.MAX_ZOOM_SCALE,
12226
11770
  callbacks: {
12227
11771
  onPinchZoom: (newScale) => callbacksRef.current.onPinchZoom?.(newScale),
12228
11772
  onSwipe: (direction) => callbacksRef.current.onSwipe?.(direction),
@@ -12346,7 +11890,7 @@ function buildCanvasProps(input) {
12346
11890
  if (pptx.shouldConfirmExternalHyperlink(viewerOptions, url) && !window.confirm(buildHyperlinkConfirmMessage(url))) {
12347
11891
  return;
12348
11892
  }
12349
- chunkJAI42EXQ_js.safeOpenUrl(url, target);
11893
+ chunkJWNBTFZZ_js.safeOpenUrl(url, target);
12350
11894
  };
12351
11895
  const handleActionClick = (elementId, action) => {
12352
11896
  if (mode === "present") {
@@ -12361,9 +11905,9 @@ function buildCanvasProps(input) {
12361
11905
  }
12362
11906
  };
12363
11907
  const handleHyperlinkClick = (url, target) => {
12364
- if (chunkJAI42EXQ_js.isPpactionUrl(url)) {
11908
+ if (chunkJWNBTFZZ_js.isPpactionUrl(url)) {
12365
11909
  if (mode === "present") {
12366
- const parsed = chunkJAI42EXQ_js.parsePpactionUrl(url);
11910
+ const parsed = chunkJWNBTFZZ_js.parsePpactionUrl(url);
12367
11911
  if (parsed) {
12368
11912
  presentation.handlePresentationAction({
12369
11913
  action: parsed.action,
@@ -12651,6 +12195,7 @@ function buildToolbarProps(input) {
12651
12195
  onAddShape: insertHandlers.handleAddShape,
12652
12196
  onAddTable: insertHandlers.handleAddTable,
12653
12197
  onAddChart: insertHandlers.handleAddChart,
12198
+ onOpenChartDialog: () => dialogs.setIsChartDialogOpen(true),
12654
12199
  onAddSmartArt: () => dialogs.setIsSmartArtDialogOpen(true),
12655
12200
  onAddEquation: () => {
12656
12201
  dialogs.setEditingEquationOmml(null);
@@ -12790,7 +12335,7 @@ function buildToolbarProps(input) {
12790
12335
  markDirty: history.markDirty
12791
12336
  }),
12792
12337
  formatPainterActive: s.formatPainterActive,
12793
- canActivateFormatPainter: chunkJAI42EXQ_js.hasCopyableFormat(selectedElement),
12338
+ canActivateFormatPainter: chunkJWNBTFZZ_js.hasCopyableFormat(selectedElement),
12794
12339
  onToggleFormatPainter: () => s.setFormatPainterActive((p) => !p),
12795
12340
  isSelectionPaneOpen: s.isSelectionPaneOpen,
12796
12341
  onToggleSelectionPane: () => s.setIsSelectionPaneOpen((p) => !p),
@@ -13183,73 +12728,47 @@ function useReadOnlyRecommendationState(content) {
13183
12728
  () => pptx.readOnlyRecommendation(void 0)
13184
12729
  );
13185
12730
  const [modifyVerifier, setModifyVerifier] = React17.useState(void 0);
13186
- const [bannerHidden, setBannerHidden] = React17.useState(false);
13187
- const [editAnywayActive, setEditAnywayActive] = React17.useState(false);
13188
- const [passwordPromptOpen, setPasswordPromptOpen] = React17.useState(false);
13189
- const [passwordError, setPasswordError] = React17.useState(null);
13190
- const [checkingPassword, setCheckingPassword] = React17.useState(false);
13191
- React17.useEffect(() => {
13192
- setBannerHidden(false);
13193
- setEditAnywayActive(false);
13194
- setPasswordPromptOpen(false);
13195
- setPasswordError(null);
13196
- setCheckingPassword(false);
13197
- }, [content]);
13198
- const unlock = React17.useCallback(() => {
13199
- setEditAnywayActive(true);
13200
- setBannerHidden(true);
13201
- setPasswordPromptOpen(false);
13202
- setPasswordError(null);
13203
- }, []);
13204
- const editAnyway = React17.useCallback(() => {
13205
- if (recommendation.requiresPassword) {
13206
- setPasswordPromptOpen(true);
13207
- setPasswordError(null);
13208
- return;
13209
- }
13210
- unlock();
13211
- }, [recommendation.requiresPassword, unlock]);
13212
- const dismiss = React17.useCallback(() => {
13213
- setBannerHidden(true);
13214
- }, []);
13215
- const cancelPasswordPrompt = React17.useCallback(() => {
13216
- setPasswordPromptOpen(false);
13217
- setPasswordError(null);
13218
- }, []);
13219
- const submitPassword = React17.useCallback(
13220
- async (password) => {
13221
- setCheckingPassword(true);
13222
- try {
13223
- const result = await pptx.checkModifyPassword(modifyVerifier, password);
13224
- if (result.ok) {
13225
- unlock();
13226
- } else {
13227
- setPasswordError(result.reason);
13228
- }
13229
- } finally {
13230
- setCheckingPassword(false);
12731
+ const [session, setSession] = React17.useState(pptx.INITIAL_READ_ONLY_SESSION);
12732
+ const latestSession = React17.useRef(session);
12733
+ const store = React17.useMemo(
12734
+ () => ({
12735
+ get: () => latestSession.current,
12736
+ set: (next) => {
12737
+ latestSession.current = next;
12738
+ setSession(next);
13231
12739
  }
13232
- },
13233
- // oxlint-disable-next-line react/memo-dependencies -- see comment above
13234
- [modifyVerifier, unlock]
12740
+ }),
12741
+ []
13235
12742
  );
12743
+ const actions = React17.useMemo(
12744
+ () => pptx.readOnlySessionActions(store, {
12745
+ recommendation: () => recommendation,
12746
+ modifyVerifier: () => modifyVerifier
12747
+ }),
12748
+ [store, recommendation, modifyVerifier]
12749
+ );
12750
+ React17.useEffect(() => {
12751
+ pptx.applyReadOnlySessionEvent(store, { type: "reset" });
12752
+ }, [content, store]);
13236
12753
  return {
13237
12754
  recommendation,
13238
12755
  setRecommendation,
13239
12756
  setModifyVerifier,
13240
12757
  /** Whether the viewer's `canEdit` should be forced off. */
13241
- locked: recommendation.defaultReadOnly && !editAnywayActive,
13242
- bannerVisible: recommendation.kind !== null && !bannerHidden,
13243
- editAnyway,
13244
- dismiss,
12758
+ locked: pptx.readOnlyLocked(recommendation, session),
12759
+ bannerVisible: pptx.readOnlyBannerVisible(recommendation, session),
12760
+ /** The banner's "Edit anyway": opens the password prompt when one is required, else unlocks. */
12761
+ editAnyway: actions.editAnyway,
12762
+ dismiss: actions.dismiss,
13245
12763
  /** Whether the inline password prompt should render in place of the banner's buttons. */
13246
- passwordPromptOpen,
12764
+ passwordPromptOpen: session.passwordPromptOpen,
13247
12765
  /** Reason the last password attempt failed, or null before any attempt / after success. */
13248
- passwordError,
12766
+ passwordError: session.passwordError,
13249
12767
  /** True while `submitPassword`'s check is in flight (disables the form). */
13250
- checkingPassword,
13251
- submitPassword,
13252
- cancelPasswordPrompt
12768
+ checkingPassword: session.checkingPassword,
12769
+ /** Check `password` against the deck's `modifyVerifier`; unlocks on a match. */
12770
+ submitPassword: actions.submitPassword,
12771
+ cancelPasswordPrompt: actions.cancelPassword
13253
12772
  };
13254
12773
  }
13255
12774
  function useViewPreferencesSync(input) {
@@ -13694,23 +13213,23 @@ function ColorChangedImage({
13694
13213
  className,
13695
13214
  alt
13696
13215
  }) {
13697
- const tolerance = tolerancePct ?? chunkJAI42EXQ_js.DEFAULT_COLOR_CHANGE_TOLERANCE;
13698
- const cacheKey = chunkJAI42EXQ_js.buildCacheKey(
13216
+ const tolerance = tolerancePct ?? chunkJWNBTFZZ_js.DEFAULT_COLOR_CHANGE_TOLERANCE;
13217
+ const cacheKey = chunkJWNBTFZZ_js.buildCacheKey(
13699
13218
  src,
13700
13219
  clrChange.clrFrom,
13701
13220
  clrChange.clrTo,
13702
13221
  tolerance,
13703
13222
  Boolean(clrChange.clrToTransparent)
13704
13223
  );
13705
- const cached = chunkJAI42EXQ_js.getCachedResult(cacheKey);
13224
+ const cached = chunkJWNBTFZZ_js.getCachedResult(cacheKey);
13706
13225
  const [processedSrc, setProcessedSrc] = React17.useState(cached ?? null);
13707
13226
  React17.useEffect(() => {
13708
- if (chunkJAI42EXQ_js.getCachedResult(cacheKey)) {
13709
- setProcessedSrc(chunkJAI42EXQ_js.getCachedResult(cacheKey) ?? null);
13227
+ if (chunkJWNBTFZZ_js.getCachedResult(cacheKey)) {
13228
+ setProcessedSrc(chunkJWNBTFZZ_js.getCachedResult(cacheKey) ?? null);
13710
13229
  return;
13711
13230
  }
13712
13231
  let cancelled = false;
13713
- chunkJAI42EXQ_js.applyColorChange(
13232
+ chunkJWNBTFZZ_js.applyColorChange(
13714
13233
  src,
13715
13234
  clrChange.clrFrom,
13716
13235
  clrChange.clrTo,
@@ -13718,7 +13237,7 @@ function ColorChangedImage({
13718
13237
  Boolean(clrChange.clrToTransparent)
13719
13238
  ).then((result) => {
13720
13239
  if (!cancelled) {
13721
- chunkJAI42EXQ_js.setCachedResult(cacheKey, result.dataUrl);
13240
+ chunkJWNBTFZZ_js.setCachedResult(cacheKey, result.dataUrl);
13722
13241
  setProcessedSrc(result.dataUrl);
13723
13242
  }
13724
13243
  return void 0;
@@ -13810,7 +13329,7 @@ function TiledImageLayer({
13810
13329
  cancelled = true;
13811
13330
  };
13812
13331
  }, [src]);
13813
- return /* @__PURE__ */ jsxRuntime.jsx("div", { className, style: { ...chunkJAI42EXQ_js.getImageTilingStyle(element, nativeSize), ...style } });
13332
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { className, style: { ...chunkJWNBTFZZ_js.getImageTilingStyle(element, nativeSize), ...style } });
13814
13333
  }
13815
13334
  function renderImageEffectDefinitions(element, excludeDuotone = false) {
13816
13335
  return pptx.getImageSvgFilters(element).filter((definition) => !excludeDuotone || definition.id !== `duotone-${element.id}`).map((definition) => /* @__PURE__ */ jsxRuntime.jsx(
@@ -13879,7 +13398,7 @@ function renderImg(el, style, filter, alt, opacity) {
13879
13398
  ...filter ? { filter } : {},
13880
13399
  ...opacity !== void 0 ? { opacity } : {}
13881
13400
  };
13882
- if (chunkJAI42EXQ_js.isImageTiled(el)) {
13401
+ if (chunkJWNBTFZZ_js.isImageTiled(el)) {
13883
13402
  const tileSrc = imgSrc(el);
13884
13403
  if (!tileSrc) {
13885
13404
  return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-full h-full flex items-center justify-center text-[11px] text-gray-500 bg-gray-100", children: "Image" });
@@ -13901,9 +13420,9 @@ function renderImg(el, style, filter, alt, opacity) {
13901
13420
  pptx$1.isImageLikeElement(el) ? el.imageEffects?.colorWash : void 0
13902
13421
  );
13903
13422
  const clrChange = "imageEffects" in el ? el.imageEffects?.clrChange : void 0;
13904
- const duotoneColors = chunkJAI42EXQ_js.getDuotoneColors(el);
13423
+ const duotoneColors = chunkJWNBTFZZ_js.getDuotoneColors(el);
13905
13424
  const useDuotoneCanvas = Boolean(duotoneColors && !clrChange);
13906
- const filterForImg = useDuotoneCanvas ? chunkJAI42EXQ_js.getImageEffectsFilter(el, { excludeDuotone: true }) : filter;
13425
+ const filterForImg = useDuotoneCanvas ? chunkJWNBTFZZ_js.getImageEffectsFilter(el, { excludeDuotone: true }) : filter;
13907
13426
  const canvasEffectStyles = {
13908
13427
  ...filterForImg ? { filter: filterForImg } : {},
13909
13428
  ...opacity !== void 0 ? { opacity } : {}
@@ -13979,10 +13498,10 @@ function SlideBackgroundImageLayer({
13979
13498
  style: { zIndex: 0 },
13980
13499
  children: renderImg(
13981
13500
  backgroundElement,
13982
- chunkJAI42EXQ_js.getImageRenderStyle(backgroundElement),
13983
- chunkJAI42EXQ_js.getImageEffectsFilter(backgroundElement),
13501
+ chunkJWNBTFZZ_js.getImageRenderStyle(backgroundElement),
13502
+ chunkJWNBTFZZ_js.getImageEffectsFilter(backgroundElement),
13984
13503
  "",
13985
- chunkJAI42EXQ_js.getImageEffectsOpacity(backgroundElement)
13504
+ chunkJWNBTFZZ_js.getImageEffectsOpacity(backgroundElement)
13986
13505
  )
13987
13506
  }
13988
13507
  );
@@ -14268,7 +13787,7 @@ function ChartElementView({
14268
13787
  pptx.getBarFacePicturePixelSampleVersion
14269
13788
  );
14270
13789
  const viewModel = React17.useMemo(() => {
14271
- return canEdit ? chunkJAI42EXQ_js.buildReactChartViewModel(element) : null;
13790
+ return canEdit ? chunkJWNBTFZZ_js.buildReactChartViewModel(element) : null;
14272
13791
  }, [canEdit, element, barFacePictureSampleVersion]);
14273
13792
  React17.useEffect(pptx.ensureChartInteractionStyles, []);
14274
13793
  React17.useEffect(() => {
@@ -14373,9 +13892,9 @@ function ChartElementView({
14373
13892
  textStyle: animationState?.textStyle,
14374
13893
  onSelect: chart3D.onSelect,
14375
13894
  onDrag: chart3D.onDrag,
14376
- children: chunkJAI42EXQ_js.renderChartElement(renderedElement, (key) => t(key))
13895
+ children: chunkJWNBTFZZ_js.renderChartElement(renderedElement, (key) => t(key))
14377
13896
  }
14378
- ) : chunkJAI42EXQ_js.renderChartElement(renderedElement, (key) => t(key)),
13897
+ ) : chunkJWNBTFZZ_js.renderChartElement(renderedElement, (key) => t(key)),
14379
13898
  dragValue !== null && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "absolute top-1 right-1 z-10 rounded bg-primary/90 px-1.5 py-0.5 text-[10px] font-medium text-white pointer-events-none", children: pptx.formatAxisValue(dragValue) }),
14380
13899
  titleDraft !== null && /* @__PURE__ */ jsxRuntime.jsx(
14381
13900
  "input",
@@ -14536,6 +14055,50 @@ var EDGE_HANDLES = [
14536
14055
  sizeClass: "w-2 h-5 max-md:w-3 max-md:h-8 rounded-sm"
14537
14056
  }
14538
14057
  ];
14058
+ var wholeDegrees = (deg) => Math.round((deg % 360 + 360) % 360) % 360;
14059
+ function startRotateKnobGesture(options) {
14060
+ const { button, elementId, rotation, onRotate } = options;
14061
+ const scope = button.closest("[data-pptx-viewport]") ?? document;
14062
+ const wrapper = scope.querySelector(pptx.elementIdSelector(elementId));
14063
+ if (!wrapper) {
14064
+ return;
14065
+ }
14066
+ const rect = wrapper.getBoundingClientRect();
14067
+ const base = options.nonRotationTransform ? ` ${options.nonRotationTransform}` : "";
14068
+ const paint = (deg) => {
14069
+ const transform = `rotate(${deg}deg)${base}`;
14070
+ wrapper.style.transform = transform;
14071
+ syncSelectionHandleOverlay(wrapper, elementId, { transform });
14072
+ };
14073
+ if (options.pointerId !== void 0) {
14074
+ button.setPointerCapture?.(options.pointerId);
14075
+ }
14076
+ const gesture = pptx.createGestureController({
14077
+ getScale: () => 1,
14078
+ getElementBox: () => ({
14079
+ x: rect.left,
14080
+ y: rect.top,
14081
+ width: rect.width,
14082
+ height: rect.height,
14083
+ rotation
14084
+ }),
14085
+ getSiblings: () => [],
14086
+ getStageOrigin: () => ({ left: 0, top: 0 }),
14087
+ onStart: () => void 0,
14088
+ onPreview: (transform) => paint(wholeDegrees(transform.rotation)),
14089
+ onEnd: (transform) => {
14090
+ const deg = transform ? wholeDegrees(transform.rotation) : rotation;
14091
+ if (deg !== rotation) {
14092
+ onRotate?.(elementId, deg);
14093
+ }
14094
+ }
14095
+ });
14096
+ gesture.begin("rotate", elementId, {
14097
+ clientX: options.pointer.clientX,
14098
+ clientY: options.pointer.clientY,
14099
+ shiftKey: false
14100
+ });
14101
+ }
14539
14102
  var appearance = { fill: "var(--color-primary)", borderColor: "#ffffff" };
14540
14103
  var cornerSize = "var(--pptx-react-corner-default, 12px)";
14541
14104
  var edgeLength = "var(--pptx-react-edge-length-default, 20px)";
@@ -14649,50 +14212,15 @@ function ResizeHandles({
14649
14212
  e.currentTarget.setPointerCapture?.(e.pointerId);
14650
14213
  onResizePointerDown(elementId, e, handle);
14651
14214
  };
14652
- const startRotate = (btn, pointer, pointerId) => {
14653
- const scope = btn.closest("[data-pptx-viewport]") ?? document;
14654
- const wrapper = scope.querySelector(pptx.elementIdSelector(elementId));
14655
- if (!wrapper) {
14656
- return;
14657
- }
14658
- const rect = wrapper.getBoundingClientRect();
14659
- const cx = rect.left + rect.width / 2;
14660
- const cy = rect.top + rect.height / 2;
14661
- const base = nonRotationTransform ? ` ${nonRotationTransform}` : "";
14662
- const startDeg = rotation ?? 0;
14663
- const dragRotation = pptx.createRotationDrag(
14664
- { x: cx, y: cy },
14665
- { x: pointer.clientX, y: pointer.clientY },
14666
- startDeg
14667
- );
14668
- let last = startDeg;
14669
- if (pointerId !== void 0) {
14670
- btn.setPointerCapture?.(pointerId);
14671
- }
14672
- const apply = (clientX, clientY, shift) => {
14673
- let deg = dragRotation({ x: clientX, y: clientY });
14674
- if (shift) {
14675
- deg = Math.round(deg / 15) * 15;
14676
- }
14677
- deg = Math.round((deg % 360 + 360) % 360);
14678
- last = deg;
14679
- const transform = `rotate(${deg}deg)${base}`;
14680
- wrapper.style.transform = transform;
14681
- syncSelectionHandleOverlay(wrapper, elementId, { transform });
14682
- };
14683
- const onPointerMove = (ev) => apply(ev.clientX, ev.clientY, ev.shiftKey);
14684
- const end = () => {
14685
- window.removeEventListener("pointermove", onPointerMove);
14686
- window.removeEventListener("pointerup", end);
14687
- window.removeEventListener("pointercancel", end);
14688
- if (last !== startDeg) {
14689
- onRotate?.(elementId, last);
14690
- }
14691
- };
14692
- window.addEventListener("pointermove", onPointerMove);
14693
- window.addEventListener("pointerup", end);
14694
- window.addEventListener("pointercancel", end);
14695
- };
14215
+ const startRotate = (button, pointer) => startRotateKnobGesture({
14216
+ button,
14217
+ elementId,
14218
+ pointer,
14219
+ pointerId: pointer.pointerId,
14220
+ rotation: rotation ?? 0,
14221
+ ...nonRotationTransform ? { nonRotationTransform } : {},
14222
+ ...onRotate ? { onRotate } : {}
14223
+ });
14696
14224
  return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
14697
14225
  [...CORNER_HANDLES, ...EDGE_HANDLES].map(({ handle, posClass, cursor }) => {
14698
14226
  const corner = handle.length === 2;
@@ -14705,7 +14233,7 @@ function ResizeHandles({
14705
14233
  "aria-label": t("pptx.selectionOverlay.resize", { handle }),
14706
14234
  "data-pptx-handle-kind": "resize",
14707
14235
  "data-pptx-compact": true,
14708
- className: chunkJAI42EXQ_js.cn(
14236
+ className: chunkJWNBTFZZ_js.cn(
14709
14237
  "absolute z-10 group border-0 bg-transparent p-0",
14710
14238
  RESIZE_DEFAULT_CLASSES,
14711
14239
  posClass,
@@ -14731,7 +14259,7 @@ function ResizeHandles({
14731
14259
  "div",
14732
14260
  {
14733
14261
  "data-pptx-handle-hit": true,
14734
- className: chunkJAI42EXQ_js.cn(
14262
+ className: chunkJWNBTFZZ_js.cn(
14735
14263
  "absolute -inset-px pointer-events-auto [--pptx-handle-hit-inset:-1px]",
14736
14264
  corner ? "max-md:-inset-1.5 max-md:[--pptx-handle-hit-inset:-6px]" : "max-md:-inset-2 max-md:[--pptx-handle-hit-inset:-8px]"
14737
14265
  ),
@@ -14752,7 +14280,7 @@ function ResizeHandles({
14752
14280
  "aria-label": t("pptx.selectionOverlay.rotate"),
14753
14281
  "data-pptx-handle-kind": "rotate",
14754
14282
  "data-pptx-compact": true,
14755
- className: chunkJAI42EXQ_js.cn(
14283
+ className: chunkJWNBTFZZ_js.cn(
14756
14284
  "absolute left-1/2 top-0 -translate-x-1/2 -translate-y-1/2 z-20 border-0 bg-transparent p-0 cursor-grab active:cursor-grabbing",
14757
14285
  ROTATE_DEFAULT_CLASSES
14758
14286
  ),
@@ -14763,7 +14291,7 @@ function ResizeHandles({
14763
14291
  },
14764
14292
  onPointerDown: (e) => {
14765
14293
  e.stopPropagation();
14766
- startRotate(e.currentTarget, e, e.pointerId);
14294
+ startRotate(e.currentTarget, e);
14767
14295
  },
14768
14296
  onMouseDown: (e) => {
14769
14297
  e.stopPropagation();
@@ -14829,10 +14357,10 @@ var ConnectorElementRendererMemo = /* @__PURE__ */ React17__default.default.memo
14829
14357
  const svgHeight = Math.max(el.height, 1);
14830
14358
  const ss = shapeEl?.shapeStyle;
14831
14359
  const strokeWidth = Math.max(0, ss?.strokeWidth ?? 2);
14832
- const strokeColor = chunkJAI42EXQ_js.normalizeHexColor(ss?.strokeColor, chunkJAI42EXQ_js.DEFAULT_STROKE_COLOR);
14833
- const strokePaint = chunkJAI42EXQ_js.colorWithOpacity(strokeColor, ss?.strokeOpacity);
14834
- const dashType = chunkJAI42EXQ_js.normalizeStrokeDashType(ss?.strokeDash);
14835
- const dashArray = chunkJAI42EXQ_js.getSvgStrokeDasharray(
14360
+ const strokeColor = chunkJWNBTFZZ_js.normalizeHexColor(ss?.strokeColor, chunkJWNBTFZZ_js.DEFAULT_STROKE_COLOR);
14361
+ const strokePaint = chunkJWNBTFZZ_js.colorWithOpacity(strokeColor, ss?.strokeOpacity);
14362
+ const dashType = chunkJWNBTFZZ_js.normalizeStrokeDashType(ss?.strokeDash);
14363
+ const dashArray = chunkJWNBTFZZ_js.getSvgStrokeDasharray(
14836
14364
  dashType,
14837
14365
  Math.max(strokeWidth, 1),
14838
14366
  ss?.customDashSegments
@@ -14843,14 +14371,14 @@ var ConnectorElementRendererMemo = /* @__PURE__ */ React17__default.default.memo
14843
14371
  const markerSeed = el.id.replace(/[^a-zA-Z0-9_-]/gu, "_");
14844
14372
  const startMarkerId = `${markerSeed}-sel-start`;
14845
14373
  const endMarkerId = `${markerSeed}-sel-end`;
14846
- const compoundOffsets = chunkJAI42EXQ_js.getCompoundLineOffsets(compoundLine, strokeWidth);
14847
- const compoundWidths = chunkJAI42EXQ_js.getCompoundLineWidths(compoundLine, strokeWidth);
14374
+ const compoundOffsets = chunkJWNBTFZZ_js.getCompoundLineOffsets(compoundLine, strokeWidth);
14375
+ const compoundWidths = chunkJWNBTFZZ_js.getCompoundLineWidths(compoundLine, strokeWidth);
14848
14376
  const strokeCap = pptx.svgLineCap(ss?.lineCap);
14849
14377
  const textEl = pptx$1.hasTextProperties(el) ? el : void 0;
14850
14378
  const connectorText = textEl?.text?.trim() ?? "";
14851
14379
  const connectorTextSegments = textEl?.textSegments;
14852
14380
  const connectorTextStyle = textEl?.textStyle;
14853
- const pathGeometry = shapeEl ? chunkJAI42EXQ_js.getConnectorPathGeometry(shapeEl) : {
14381
+ const pathGeometry = shapeEl ? chunkJWNBTFZZ_js.getConnectorPathGeometry(shapeEl) : {
14854
14382
  pathData: `M 0 0 L ${viewWidth} ${viewHeight}`,
14855
14383
  startX: 0,
14856
14384
  startY: 0,
@@ -14859,16 +14387,16 @@ var ConnectorElementRendererMemo = /* @__PURE__ */ React17__default.default.memo
14859
14387
  };
14860
14388
  const hitTargetWidth = Math.max(strokeWidth * 3, 14);
14861
14389
  const selColor = selClr === "blue-400" ? "#60a5fa" : "#3b82f6";
14862
- const lineShadow = chunkJAI42EXQ_js.buildLineShadowCss(el);
14863
- const lineGlow = chunkJAI42EXQ_js.buildLineGlowFilter(el);
14390
+ const lineShadow = chunkJWNBTFZZ_js.buildLineShadowCss(el);
14391
+ const lineGlow = chunkJWNBTFZZ_js.buildLineGlowFilter(el);
14864
14392
  return /* @__PURE__ */ jsxRuntime.jsxs(
14865
14393
  "div",
14866
14394
  {
14867
14395
  "data-pptx-element": "true",
14868
14396
  "data-element-id": el.id,
14869
- role: chunkJAI42EXQ_js.getAriaRole(el, { actionable: false }),
14870
- "aria-label": chunkJAI42EXQ_js.getAriaLabel(el),
14871
- "aria-roledescription": chunkJAI42EXQ_js.getAriaRoleDescription(el),
14397
+ role: chunkJWNBTFZZ_js.getAriaRole(el, { actionable: false }),
14398
+ "aria-label": chunkJWNBTFZZ_js.getAriaLabel(el),
14399
+ "aria-roledescription": chunkJWNBTFZZ_js.getAriaRoleDescription(el),
14872
14400
  "aria-selected": isSelected ? true : void 0,
14873
14401
  className: "absolute",
14874
14402
  style: {
@@ -14901,14 +14429,14 @@ var ConnectorElementRendererMemo = /* @__PURE__ */ React17__default.default.memo
14901
14429
  style: { overflow: "visible", pointerEvents: "none" },
14902
14430
  children: [
14903
14431
  /* @__PURE__ */ jsxRuntime.jsxs("defs", { children: [
14904
- chunkJAI42EXQ_js.renderConnectorMarker(
14432
+ chunkJWNBTFZZ_js.renderConnectorMarker(
14905
14433
  startMarkerId,
14906
14434
  startArrow,
14907
14435
  strokePaint,
14908
14436
  ss?.connectorStartArrowWidth,
14909
14437
  ss?.connectorStartArrowLength
14910
14438
  ),
14911
- chunkJAI42EXQ_js.renderConnectorMarker(
14439
+ chunkJWNBTFZZ_js.renderConnectorMarker(
14912
14440
  endMarkerId,
14913
14441
  endArrow,
14914
14442
  strokePaint,
@@ -15117,14 +14645,14 @@ function getElementInteractionProps({
15117
14645
  };
15118
14646
  }
15119
14647
  function renderDagDuotoneFilterForElement(el) {
15120
- if (!chunkJAI42EXQ_js.hasDagDuotoneEffect(el)) {
14648
+ if (!chunkJWNBTFZZ_js.hasDagDuotoneEffect(el)) {
15121
14649
  return null;
15122
14650
  }
15123
14651
  const duotone = el.shapeStyle?.dagDuotone;
15124
14652
  if (!duotone) {
15125
14653
  return null;
15126
14654
  }
15127
- return chunkJAI42EXQ_js.renderDagDuotoneSvgFilter(el.id, duotone.color1, duotone.color2);
14655
+ return chunkJWNBTFZZ_js.renderDagDuotoneSvgFilter(el.id, duotone.color1, duotone.color2);
15128
14656
  }
15129
14657
  function getContainerStyle({
15130
14658
  el,
@@ -15151,10 +14679,10 @@ function getContainerStyle({
15151
14679
  top: isFullscreenMedia ? fs.top : el.y,
15152
14680
  width: isFullscreenMedia ? fs.width : painted.width,
15153
14681
  ...heightStyle,
15154
- transform: isFullscreenMedia ? fs.transform : chunkJAI42EXQ_js.getElementTransform(el),
14682
+ transform: isFullscreenMedia ? fs.transform : chunkJWNBTFZZ_js.getElementTransform(el),
15155
14683
  transformOrigin: "center",
15156
14684
  overflow: overflowValue,
15157
- clipPath: isPicture ? void 0 : isImg && !has3DExtrusion ? chunkJAI42EXQ_js.getCropShapeClipPath(el) : void 0,
14685
+ clipPath: isPicture ? void 0 : isImg && !has3DExtrusion ? chunkJWNBTFZZ_js.getCropShapeClipPath(el) : void 0,
15158
14686
  zIndex: isFullscreenMedia ? fs.zIndex : zIndex,
15159
14687
  visibility: animationState?.visible === false ? "hidden" : "visible",
15160
14688
  animation: animationState?.cssAnimation,
@@ -15191,9 +14719,9 @@ function getContainerStyle({
15191
14719
  function shapeParams(element) {
15192
14720
  const style = pptx$1.hasShapeProperties(element) ? element.shapeStyle : void 0;
15193
14721
  const strokeWidth = pptx.paintedStrokeWidth(style);
15194
- const strokeColor = chunkJAI42EXQ_js.normalizeHexColor(style?.strokeColor, chunkJAI42EXQ_js.DEFAULT_STROKE_COLOR);
15195
- const fillColor = chunkJAI42EXQ_js.normalizeHexColor(style?.fillColor, chunkJAI42EXQ_js.DEFAULT_FILL_COLOR);
15196
- const hasFill = style?.fillColor !== void 0 && style.fillColor !== "transparent" || Boolean(chunkJAI42EXQ_js.buildCssGradientFromShapeStyle(style) || style?.fillGradient) || style?.fillMode === "pattern" && Boolean(style.fillPatternPreset);
14722
+ const strokeColor = chunkJWNBTFZZ_js.normalizeHexColor(style?.strokeColor, chunkJWNBTFZZ_js.DEFAULT_STROKE_COLOR);
14723
+ const fillColor = chunkJWNBTFZZ_js.normalizeHexColor(style?.fillColor, chunkJWNBTFZZ_js.DEFAULT_FILL_COLOR);
14724
+ const hasFill = style?.fillColor !== void 0 && style.fillColor !== "transparent" || Boolean(chunkJWNBTFZZ_js.buildCssGradientFromShapeStyle(style) || style?.fillGradient) || style?.fillMode === "pattern" && Boolean(style.fillPatternPreset);
15197
14725
  return { hf: hasFill, fc: fillColor, sw: strokeWidth, sc: strokeColor };
15198
14726
  }
15199
14727
  var Extrusion3DOverlayMemo = /* @__PURE__ */ React17__default.default.memo(
@@ -15301,7 +14829,7 @@ function ShapeEffectOverlay({
15301
14829
  const fillOverlayStyle = overlay ? {
15302
14830
  position: "absolute",
15303
14831
  inset: 0,
15304
- ...pptx$1.isImageLikeElement(element) ? chunkJAI42EXQ_js.getImageSurfaceMaskStyle(element) : {},
14832
+ ...pptx$1.isImageLikeElement(element) ? chunkJWNBTFZZ_js.getImageSurfaceMaskStyle(element) : {},
15305
14833
  background: overlay.color,
15306
14834
  mixBlendMode: overlay.blendMode,
15307
14835
  pointerEvents: "none"
@@ -15508,10 +15036,10 @@ var ElementRenderer = /* @__PURE__ */ React17__default.default.memo(
15508
15036
  const backgroundAnimationState = pptx.getBackgroundAnimationState(el, presentationElementStates);
15509
15037
  const effectPlacement = pptx.getShapeEffectLayerPlacement(el);
15510
15038
  const visualAnimationState = backgroundAnimationState ?? animationState;
15511
- const isTxt = chunkJAI42EXQ_js.isEditableTextElement(el) && allow.textEditable;
15039
+ const isTxt = chunkJWNBTFZZ_js.isEditableTextElement(el) && allow.textEditable;
15512
15040
  const txtSE = pptx$1.hasTextProperties(el) ? el.textStyle : void 0;
15513
15041
  const textStyleOverrideCss = pptx.buildTextStyleOverrideCss(el.id, visualAnimationState?.textStyle);
15514
- const ss = chunkJAI42EXQ_js.getShapeVisualStyle(
15042
+ const ss = chunkJWNBTFZZ_js.getShapeVisualStyle(
15515
15043
  el,
15516
15044
  hf,
15517
15045
  fc,
@@ -15520,9 +15048,9 @@ var ElementRenderer = /* @__PURE__ */ React17__default.default.memo(
15520
15048
  visualAnimationState?.animatesFill,
15521
15049
  visualAnimationState?.animatesStroke
15522
15050
  );
15523
- const ts = chunkJAI42EXQ_js.getTextStyleForElement(el, chunkJAI42EXQ_js.DEFAULT_TEXT_COLOR);
15051
+ const ts = chunkJWNBTFZZ_js.getTextStyleForElement(el, chunkJWNBTFZZ_js.DEFAULT_TEXT_COLOR);
15524
15052
  const isImg = el.type === "picture" || el.type === "image";
15525
- const vs = chunkJAI42EXQ_js.renderVectorShape(
15053
+ const vs = chunkJWNBTFZZ_js.renderVectorShape(
15526
15054
  el,
15527
15055
  isImg ? false : hf,
15528
15056
  fc,
@@ -15532,10 +15060,10 @@ var ElementRenderer = /* @__PURE__ */ React17__default.default.memo(
15532
15060
  visualAnimationState?.animatesStroke
15533
15061
  );
15534
15062
  const isModel3D = el.type === "model3d";
15535
- const isConn = chunkJAI42EXQ_js.isConnectorOrLineElement(el);
15063
+ const isConn = chunkJWNBTFZZ_js.isConnectorOrLineElement(el);
15536
15064
  const shapeStyle3d = pptx$1.hasShapeProperties(el) ? el.shapeStyle : void 0;
15537
15065
  const extrusionData = React17.useMemo(
15538
- () => chunkJAI42EXQ_js.build3DExtrusionData(shapeStyle3d?.shape3d, shapeStyle3d?.scene3d, fc, el.width, el.height),
15066
+ () => chunkJWNBTFZZ_js.build3DExtrusionData(shapeStyle3d?.shape3d, shapeStyle3d?.scene3d, fc, el.width, el.height),
15539
15067
  [shapeStyle3d?.shape3d, shapeStyle3d?.scene3d, fc, el.width, el.height]
15540
15068
  );
15541
15069
  const actionAffordance = useActionAffordance(el, canInteract);
@@ -15625,7 +15153,7 @@ var ElementRenderer = /* @__PURE__ */ React17__default.default.memo(
15625
15153
  "aria-hidden": aria.hidden ? true : void 0,
15626
15154
  "aria-selected": isSelected ? true : void 0,
15627
15155
  tabIndex: isFocusable ? 0 : -1,
15628
- className: chunkJAI42EXQ_js.cn(
15156
+ className: chunkJWNBTFZZ_js.cn(
15629
15157
  "absolute",
15630
15158
  "focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-blue-500",
15631
15159
  cur,
@@ -15698,9 +15226,9 @@ var ElementRenderer = /* @__PURE__ */ React17__default.default.memo(
15698
15226
  txtSE,
15699
15227
  txtS: ts,
15700
15228
  vecShape: backgroundAnimationState && !isImg ? null : vs,
15701
- imgStyle: chunkJAI42EXQ_js.getImageRenderStyle(el),
15702
- imgFilter: chunkJAI42EXQ_js.getImageEffectsFilter(el),
15703
- imgOpacity: chunkJAI42EXQ_js.getImageEffectsOpacity(el),
15229
+ imgStyle: chunkJWNBTFZZ_js.getImageRenderStyle(el),
15230
+ imgFilter: chunkJWNBTFZZ_js.getImageEffectsFilter(el),
15231
+ imgOpacity: chunkJWNBTFZZ_js.getImageEffectsOpacity(el),
15704
15232
  imgAlt: imageAltText,
15705
15233
  isTxtEl: isTxt,
15706
15234
  media: mediaDataUrls,
@@ -15837,10 +15365,10 @@ function renderStrokeView(view, pressureSensitive, replayStyle, key) {
15837
15365
  }
15838
15366
  function renderInk(el, options) {
15839
15367
  const replay = options?.replay ?? false;
15840
- const strokes = chunkJAI42EXQ_js.buildInkGroupStrokes(el, { color: "#000", width: 3 });
15368
+ const strokes = chunkJWNBTFZZ_js.buildInkGroupStrokes(el, { color: "#000", width: 3 });
15841
15369
  strokes.some((s) => s.circles || s.nibMarks);
15842
15370
  const pressureSensitive = options?.pressureSensitive;
15843
- const replayStyles = replay ? chunkJAI42EXQ_js.getInkReplayStyles(el, options?.replayConfig) : null;
15371
+ const replayStyles = replay ? chunkJWNBTFZZ_js.getInkReplayStyles(el, options?.replayConfig) : null;
15844
15372
  return /* @__PURE__ */ jsxRuntime.jsxs(
15845
15373
  "svg",
15846
15374
  {
@@ -15848,7 +15376,7 @@ function renderInk(el, options) {
15848
15376
  viewBox: `0 0 ${Math.max(el.width, 1)} ${Math.max(el.height, 1)}`,
15849
15377
  preserveAspectRatio: "none",
15850
15378
  children: [
15851
- replay && /* @__PURE__ */ jsxRuntime.jsx("style", { children: chunkJAI42EXQ_js.INK_REPLAY_KEYFRAMES }),
15379
+ replay && /* @__PURE__ */ jsxRuntime.jsx("style", { children: chunkJWNBTFZZ_js.INK_REPLAY_KEYFRAMES }),
15852
15380
  strokes.map(
15853
15381
  (s, i) => renderStrokeView(s, pressureSensitive, replayStyles?.[i], `${el.id}-ink-${i}`)
15854
15382
  )
@@ -15859,7 +15387,7 @@ function renderInk(el, options) {
15859
15387
  function renderGroup(children, parentGroupFill) {
15860
15388
  return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "relative w-full h-full pointer-events-none", children: pptx.filterRenderedElements(children).map((c, childIndex) => {
15861
15389
  const { hf, fc, sw, sc } = shapeParams(c);
15862
- const baseSs = chunkJAI42EXQ_js.getShapeVisualStyle(c, hf, fc, sw, sc);
15390
+ const baseSs = chunkJWNBTFZZ_js.getShapeVisualStyle(c, hf, fc, sw, sc);
15863
15391
  const inheritedFill = pptx.resolveGroupChildFill(c, parentGroupFill);
15864
15392
  const ss = inheritedFill ? {
15865
15393
  ...baseSs,
@@ -15870,9 +15398,9 @@ function renderGroup(children, parentGroupFill) {
15870
15398
  backgroundPosition: inheritedFill.backgroundPosition
15871
15399
  } : baseSs;
15872
15400
  const isI = c.type === "picture" || c.type === "image";
15873
- const vs = chunkJAI42EXQ_js.renderVectorShape(c, isI ? false : hf, fc, sw, sc);
15874
- const ts = chunkJAI42EXQ_js.getTextStyleForElement(c, chunkJAI42EXQ_js.DEFAULT_TEXT_COLOR);
15875
- const isTxt = chunkJAI42EXQ_js.isEditableTextElement(c);
15401
+ const vs = chunkJWNBTFZZ_js.renderVectorShape(c, isI ? false : hf, fc, sw, sc);
15402
+ const ts = chunkJWNBTFZZ_js.getTextStyleForElement(c, chunkJWNBTFZZ_js.DEFAULT_TEXT_COLOR);
15403
+ const isTxt = chunkJWNBTFZZ_js.isEditableTextElement(c);
15876
15404
  return /* @__PURE__ */ jsxRuntime.jsxs(
15877
15405
  "div",
15878
15406
  {
@@ -15881,9 +15409,9 @@ function renderGroup(children, parentGroupFill) {
15881
15409
  style: {
15882
15410
  left: c.x,
15883
15411
  top: c.y,
15884
- width: Math.max(c.width, chunkJAI42EXQ_js.MIN_ELEMENT_SIZE),
15885
- height: Math.max(c.height, chunkJAI42EXQ_js.MIN_ELEMENT_SIZE),
15886
- transform: chunkJAI42EXQ_js.getElementTransform(c),
15412
+ width: Math.max(c.width, chunkJWNBTFZZ_js.MIN_ELEMENT_SIZE),
15413
+ height: Math.max(c.height, chunkJWNBTFZZ_js.MIN_ELEMENT_SIZE),
15414
+ transform: chunkJWNBTFZZ_js.getElementTransform(c),
15887
15415
  transformOrigin: "center",
15888
15416
  ...ss,
15889
15417
  ...isI ? {
@@ -15908,8 +15436,8 @@ function renderGroup(children, parentGroupFill) {
15908
15436
  // A nested group: recurse, chaining the inherited fill so a
15909
15437
  // `grpFill` shape under a fill-less sub-group still paints.
15910
15438
  renderGroup(c.children, pptx.getGroupChildParentFill(c, parentGroupFill))
15911
- ) : isI && ("svgData" in c && c.svgData || "imageData" in c && c.imageData) ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "absolute inset-0 pointer-events-none", style: chunkJAI42EXQ_js.getImageSurfaceStyle(c), children: [
15912
- chunkJAI42EXQ_js.isImageTiled(c) ? /* @__PURE__ */ jsxRuntime.jsx(
15439
+ ) : isI && ("svgData" in c && c.svgData || "imageData" in c && c.imageData) ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "absolute inset-0 pointer-events-none", style: chunkJWNBTFZZ_js.getImageSurfaceStyle(c), children: [
15440
+ chunkJWNBTFZZ_js.isImageTiled(c) ? /* @__PURE__ */ jsxRuntime.jsx(
15913
15441
  TiledImageLayer,
15914
15442
  {
15915
15443
  element: c,
@@ -15922,7 +15450,7 @@ function renderGroup(children, parentGroupFill) {
15922
15450
  src: "svgData" in c && c.svgData ? c.svgData : c.imageData,
15923
15451
  alt: i18n.translationsEn["pptx.ink.groupChildAlt"],
15924
15452
  className: "pointer-events-none select-none",
15925
- style: chunkJAI42EXQ_js.getImageRenderStyle(c),
15453
+ style: chunkJWNBTFZZ_js.getImageRenderStyle(c),
15926
15454
  draggable: false
15927
15455
  }
15928
15456
  ),
@@ -15934,7 +15462,7 @@ function renderGroup(children, parentGroupFill) {
15934
15462
  {
15935
15463
  className: "relative z-10 w-full h-full pointer-events-none whitespace-pre-wrap break-words leading-[1.3]",
15936
15464
  style: ts,
15937
- children: chunkJAI42EXQ_js.renderTextSegments(c, chunkJAI42EXQ_js.DEFAULT_TEXT_COLOR)
15465
+ children: chunkJWNBTFZZ_js.renderTextSegments(c, chunkJWNBTFZZ_js.DEFAULT_TEXT_COLOR)
15938
15466
  }
15939
15467
  ) : null
15940
15468
  ] })
@@ -15948,8 +15476,8 @@ function renderContentPart(el, options) {
15948
15476
  if (el.inkStrokes && el.inkStrokes.length > 0) {
15949
15477
  const replay = options?.replay ?? false;
15950
15478
  const pressureSensitive = options?.pressureSensitive ?? true;
15951
- const strokes = chunkJAI42EXQ_js.buildContentPartStrokes(el);
15952
- const replayStyles = replay ? chunkJAI42EXQ_js.getContentPartReplayStyles(el.inkStrokes, options?.replayConfig) : null;
15479
+ const strokes = chunkJWNBTFZZ_js.buildContentPartStrokes(el);
15480
+ const replayStyles = replay ? chunkJWNBTFZZ_js.getContentPartReplayStyles(el.inkStrokes, options?.replayConfig) : null;
15953
15481
  return /* @__PURE__ */ jsxRuntime.jsxs(
15954
15482
  "svg",
15955
15483
  {
@@ -15957,7 +15485,7 @@ function renderContentPart(el, options) {
15957
15485
  viewBox: `0 0 ${Math.max(el.width, 1)} ${Math.max(el.height, 1)}`,
15958
15486
  preserveAspectRatio: "none",
15959
15487
  children: [
15960
- replay && /* @__PURE__ */ jsxRuntime.jsx("style", { children: chunkJAI42EXQ_js.INK_REPLAY_KEYFRAMES }),
15488
+ replay && /* @__PURE__ */ jsxRuntime.jsx("style", { children: chunkJWNBTFZZ_js.INK_REPLAY_KEYFRAMES }),
15961
15489
  strokes.map(
15962
15490
  (s, i) => renderStrokeView(s, pressureSensitive, replayStyles?.[i], `${el.id}-cp-ink-${i}`)
15963
15491
  )
@@ -16184,9 +15712,9 @@ function useInlineListEditor(element, rootRef, onChange, onModelReplacement) {
16184
15712
  collaboration: connected,
16185
15713
  model: pptx.createInlineListModelObserver(element),
16186
15714
  activationSelection,
16187
- children: seed && !connected ? chunkJAI42EXQ_js.renderTextSegments(
15715
+ children: seed && !connected ? chunkJWNBTFZZ_js.renderTextSegments(
16188
15716
  element,
16189
- chunkJAI42EXQ_js.DEFAULT_TEXT_COLOR,
15717
+ chunkJWNBTFZZ_js.DEFAULT_TEXT_COLOR,
16190
15718
  void 0,
16191
15719
  void 0,
16192
15720
  void 0,
@@ -16422,8 +15950,8 @@ function InlineTextEditor({
16422
15950
  pending.endOffset
16423
15951
  );
16424
15952
  });
16425
- const warpStyle = chunkJAI42EXQ_js.getTextWarpStyle(textStyleRaw);
16426
- const compensationTransform = chunkJAI42EXQ_js.getTextCompensationTransform(element);
15953
+ const warpStyle = chunkJWNBTFZZ_js.getTextWarpStyle(textStyleRaw);
15954
+ const compensationTransform = chunkJWNBTFZZ_js.getTextCompensationTransform(element);
16427
15955
  const warpTransform = warpStyle?.transform;
16428
15956
  const mergedTransform = [compensationTransform, warpTransform].filter(Boolean).join(" ") || void 0;
16429
15957
  const wrapperStyle = {
@@ -16511,7 +16039,7 @@ function InlineTextEditor({
16511
16039
  const text = e.clipboardData.getData("text/plain");
16512
16040
  document.execCommand("insertText", false, text);
16513
16041
  },
16514
- children: list.seed ? list.children : seed.hasRichSegments ? chunkJAI42EXQ_js.renderTextSegments(element, chunkJAI42EXQ_js.DEFAULT_TEXT_COLOR) : seed.initialText
16042
+ children: list.seed ? list.children : seed.hasRichSegments ? chunkJWNBTFZZ_js.renderTextSegments(element, chunkJWNBTFZZ_js.DEFAULT_TEXT_COLOR) : seed.initialText
16515
16043
  },
16516
16044
  list.seed?.paragraphs[0].token ?? "plain"
16517
16045
  );
@@ -17658,7 +17186,7 @@ function groupIntoParagraphs(element, fieldContext) {
17658
17186
  element,
17659
17187
  fieldContext ? (seg) => {
17660
17188
  if (seg.fieldType) {
17661
- const substituted = chunkJAI42EXQ_js.substituteFieldText(
17189
+ const substituted = chunkJWNBTFZZ_js.substituteFieldText(
17662
17190
  seg.text,
17663
17191
  seg.fieldType,
17664
17192
  fieldContext,
@@ -17693,13 +17221,13 @@ function getSegmentTspanProps(segment, element, fallbackColor) {
17693
17221
  if (s.strikethrough) {
17694
17222
  decos.push("line-through");
17695
17223
  }
17696
- const fill = s.hyperlink ? chunkJAI42EXQ_js.normalizeHexColor(s.color || element.textStyle?.color, chunkJAI42EXQ_js.HYPERLINK_COLOR) : chunkJAI42EXQ_js.normalizeHexColor(s.color || element.textStyle?.color, fallbackColor);
17224
+ const fill = s.hyperlink ? chunkJWNBTFZZ_js.normalizeHexColor(s.color || element.textStyle?.color, chunkJWNBTFZZ_js.HYPERLINK_COLOR) : chunkJWNBTFZZ_js.normalizeHexColor(s.color || element.textStyle?.color, fallbackColor);
17697
17225
  return {
17698
17226
  fill,
17699
- fontSize: s.fontSize ?? element.textStyle?.fontSize ?? chunkJAI42EXQ_js.DEFAULT_TEXT_FONT_SIZE,
17227
+ fontSize: s.fontSize ?? element.textStyle?.fontSize ?? chunkJWNBTFZZ_js.DEFAULT_TEXT_FONT_SIZE,
17700
17228
  fontWeight: pptx.resolveFontWeight(s.fontFamily || element.textStyle?.fontFamily, s.bold),
17701
17229
  fontStyle: pptx.resolveFontItalic(s.fontFamily || element.textStyle?.fontFamily, s.italic) ? "italic" : void 0,
17702
- fontFamily: s.fontFamily || element.textStyle?.fontFamily ? pptx$1.getSubstituteFontFamily(s.fontFamily || element.textStyle?.fontFamily || "") : chunkJAI42EXQ_js.DEFAULT_FONT_FAMILY,
17230
+ fontFamily: s.fontFamily || element.textStyle?.fontFamily ? pptx$1.getSubstituteFontFamily(s.fontFamily || element.textStyle?.fontFamily || "") : chunkJWNBTFZZ_js.DEFAULT_FONT_FAMILY,
17703
17231
  textDecoration: decos.length > 0 ? decos.join(" ") : void 0
17704
17232
  };
17705
17233
  }
@@ -17707,8 +17235,8 @@ function resolveSegmentFont(segment, element) {
17707
17235
  const s = segment.style || {};
17708
17236
  const family = s.fontFamily || element.textStyle?.fontFamily;
17709
17237
  return {
17710
- fontFamily: family ? pptx$1.getSubstituteFontFamily(family) : chunkJAI42EXQ_js.DEFAULT_FONT_FAMILY,
17711
- fontSizePx: s.fontSize ?? element.textStyle?.fontSize ?? chunkJAI42EXQ_js.DEFAULT_TEXT_FONT_SIZE,
17238
+ fontFamily: family ? pptx$1.getSubstituteFontFamily(family) : chunkJWNBTFZZ_js.DEFAULT_FONT_FAMILY,
17239
+ fontSizePx: s.fontSize ?? element.textStyle?.fontSize ?? chunkJWNBTFZZ_js.DEFAULT_TEXT_FONT_SIZE,
17712
17240
  bold: s.bold ?? element.textStyle?.bold,
17713
17241
  italic: s.italic ?? element.textStyle?.italic
17714
17242
  };
@@ -17792,9 +17320,9 @@ function WarpedText({
17792
17320
  const warpAdj2 = textEl.textStyle?.textWarpAdj2;
17793
17321
  const align = textEl.textStyle?.align ?? "center";
17794
17322
  const { startOffset, textAnchor } = getAlignmentProps(align);
17795
- const baseFontSize = textEl.textStyle?.fontSize ?? chunkJAI42EXQ_js.DEFAULT_TEXT_FONT_SIZE;
17796
- const baseFontFamily = textEl.textStyle?.fontFamily ? pptx$1.getSubstituteFontFamily(textEl.textStyle.fontFamily) : chunkJAI42EXQ_js.DEFAULT_FONT_FAMILY;
17797
- const baseFill = chunkJAI42EXQ_js.normalizeHexColor(textEl.textStyle?.color, fallbackColor);
17323
+ const baseFontSize = textEl.textStyle?.fontSize ?? chunkJWNBTFZZ_js.DEFAULT_TEXT_FONT_SIZE;
17324
+ const baseFontFamily = textEl.textStyle?.fontFamily ? pptx$1.getSubstituteFontFamily(textEl.textStyle.fontFamily) : chunkJWNBTFZZ_js.DEFAULT_FONT_FAMILY;
17325
+ const baseFill = chunkJWNBTFZZ_js.normalizeHexColor(textEl.textStyle?.color, fallbackColor);
17798
17326
  if (pptx.hasGlyphEnvelope(preset)) {
17799
17327
  const perLine = pptx.buildGlyphEnvelopeBlock(
17800
17328
  preset,
@@ -17896,7 +17424,7 @@ function WarpedText({
17896
17424
  var GLYPH_BY_SHAPE = /* @__PURE__ */ buildGlyphByShape();
17897
17425
  function buildGlyphByShape() {
17898
17426
  const glyphs = Object.fromEntries(
17899
- chunkJAI42EXQ_js.ACTION_BUTTON_PRESETS.map((p) => [p.shapeType, p.iconPath])
17427
+ chunkJWNBTFZZ_js.ACTION_BUTTON_PRESETS.map((p) => [p.shapeType, p.iconPath])
17900
17428
  );
17901
17429
  glyphs["actionButtonForwardOrNext"] = glyphs["actionButtonForwardNext"];
17902
17430
  glyphs["actionButtonBackOrPrevious"] = glyphs["actionButtonBackPrevious"];
@@ -17970,9 +17498,9 @@ function renderTextElementBody(options) {
17970
17498
  const useSvgWarp = pptx.shouldUseSvgWarp(
17971
17499
  pptx$1.hasTextProperties(el) ? el.textStyle?.textWarpPreset : void 0
17972
17500
  );
17973
- const scene3dStyle = pptx$1.hasTextProperties(el) ? chunkJAI42EXQ_js.buildTextBody3DSceneStyle(el.textStyle, { width: el.width, height: el.height }) : void 0;
17501
+ const scene3dStyle = pptx$1.hasTextProperties(el) ? chunkJWNBTFZZ_js.buildTextBody3DSceneStyle(el.textStyle, { width: el.width, height: el.height }) : void 0;
17974
17502
  const rotationTransform = pptx.getTextBodyRotationTransform(el);
17975
- const composedTransform = [rotationTransform, chunkJAI42EXQ_js.getTextCompensationTransform(el), scene3dStyle?.transform].filter(Boolean).join(" ") || void 0;
17503
+ const composedTransform = [rotationTransform, chunkJWNBTFZZ_js.getTextCompensationTransform(el), scene3dStyle?.transform].filter(Boolean).join(" ") || void 0;
17976
17504
  const transformStyle = {
17977
17505
  transform: composedTransform,
17978
17506
  // A COM-measured homography (`scene3dStyle.transformOrigin === '0 0'`)
@@ -18002,18 +17530,18 @@ function renderTextElementBody(options) {
18002
17530
  shouldRenderText && (useSvgWarp ? /* @__PURE__ */ jsxRuntime.jsx(
18003
17531
  "div",
18004
17532
  {
18005
- className: chunkJAI42EXQ_js.cn(
17533
+ className: chunkJWNBTFZZ_js.cn(
18006
17534
  "relative z-10 w-full h-full",
18007
17535
  onHyperlinkClick ? "" : "pointer-events-none"
18008
17536
  ),
18009
- style: { ...chunkJAI42EXQ_js.getTextLayoutStyle(el), ...transformStyle },
17537
+ style: { ...chunkJWNBTFZZ_js.getTextLayoutStyle(el), ...transformStyle },
18010
17538
  children: /* @__PURE__ */ jsxRuntime.jsx(
18011
17539
  WarpedText,
18012
17540
  {
18013
17541
  element: el,
18014
17542
  width: el.width,
18015
17543
  height: el.height,
18016
- fallbackColor: chunkJAI42EXQ_js.DEFAULT_TEXT_COLOR,
17544
+ fallbackColor: chunkJWNBTFZZ_js.DEFAULT_TEXT_COLOR,
18017
17545
  findHighlights: findHl,
18018
17546
  fieldContext
18019
17547
  }
@@ -18022,19 +17550,19 @@ function renderTextElementBody(options) {
18022
17550
  ) : /* @__PURE__ */ jsxRuntime.jsx(
18023
17551
  "div",
18024
17552
  {
18025
- className: chunkJAI42EXQ_js.cn(
17553
+ className: chunkJWNBTFZZ_js.cn(
18026
17554
  "relative z-10 w-full h-full whitespace-pre-wrap break-words leading-[1.3]",
18027
17555
  onHyperlinkClick ? "" : "pointer-events-none"
18028
17556
  ),
18029
17557
  style: {
18030
- ...chunkJAI42EXQ_js.getTextLayoutStyle(el),
17558
+ ...chunkJWNBTFZZ_js.getTextLayoutStyle(el),
18031
17559
  ...txtS,
18032
- ...chunkJAI42EXQ_js.getTextWarpStyle(txtSE),
17560
+ ...chunkJWNBTFZZ_js.getTextWarpStyle(txtSE),
18033
17561
  ...transformStyle
18034
17562
  },
18035
- children: chunkJAI42EXQ_js.renderTextSegments(
17563
+ children: chunkJWNBTFZZ_js.renderTextSegments(
18036
17564
  el,
18037
- chunkJAI42EXQ_js.DEFAULT_TEXT_COLOR,
17565
+ chunkJWNBTFZZ_js.DEFAULT_TEXT_COLOR,
18038
17566
  void 0,
18039
17567
  findHl,
18040
17568
  onHyperlinkClick,
@@ -18353,7 +17881,7 @@ function renderBody(options) {
18353
17881
  );
18354
17882
  }
18355
17883
  if (isImg) {
18356
- return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "absolute inset-0 pointer-events-none", style: chunkJAI42EXQ_js.getImageSurfaceStyle(el), children: [
17884
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "absolute inset-0 pointer-events-none", style: chunkJWNBTFZZ_js.getImageSurfaceStyle(el), children: [
18357
17885
  renderImg(el, imgStyle, imgFilter, imgAlt, imgOpacity),
18358
17886
  vecShape ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "pointer-events-none absolute inset-0", children: vecShape }) : null
18359
17887
  ] });
@@ -18370,7 +17898,7 @@ function renderBody(options) {
18370
17898
  textDirection: txtSE?.textDirection,
18371
17899
  textStyle: txtS,
18372
17900
  textStyleRaw: txtSE,
18373
- layoutStyle: chunkJAI42EXQ_js.getTextLayoutStyle(el),
17901
+ layoutStyle: chunkJWNBTFZZ_js.getTextLayoutStyle(el),
18374
17902
  element: el,
18375
17903
  onCommit,
18376
17904
  onCancel,
@@ -18381,7 +17909,7 @@ function renderBody(options) {
18381
17909
  ] });
18382
17910
  }
18383
17911
  if (el.type === "table") {
18384
- return chunkJAI42EXQ_js.renderTableElement(el, txtS, {
17912
+ return chunkJWNBTFZZ_js.renderTableElement(el, txtS, {
18385
17913
  editable: isSel,
18386
17914
  selectedCell: isSel ? tableSt : null,
18387
17915
  onSelectCell: onCellSel,
@@ -18414,7 +17942,7 @@ function renderBody(options) {
18414
17942
  );
18415
17943
  }
18416
17944
  if (el.type === "media") {
18417
- return chunkJAI42EXQ_js.renderMediaElement(el, media, {
17945
+ return chunkJWNBTFZZ_js.renderMediaElement(el, media, {
18418
17946
  // Present mode autoplays every media element on the active slide,
18419
17947
  // not only ones persisted with their own `autoPlay` flag (matching
18420
17948
  // the other four bindings' unconditional `presenting`-gated
@@ -18466,27 +17994,27 @@ function renderBody(options) {
18466
17994
  }
18467
17995
  return renderGroup(el.children, pptx.getGroupChildParentFill(el));
18468
17996
  }
18469
- if (chunkJAI42EXQ_js.shouldRenderFallbackLabel(el, isTxtEl)) {
18470
- return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-full h-full flex items-center justify-center text-[11px] text-white/80 pointer-events-none", children: chunkJAI42EXQ_js.getElementLabel(el) });
17997
+ if (chunkJWNBTFZZ_js.shouldRenderFallbackLabel(el, isTxtEl)) {
17998
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-full h-full flex items-center justify-center text-[11px] text-white/80 pointer-events-none", children: chunkJWNBTFZZ_js.getElementLabel(el) });
18471
17999
  }
18472
18000
  return renderTextElementBody(options);
18473
18001
  }
18474
18002
  function defaultTextColorForFill(fillColor) {
18475
18003
  const hex = String(fillColor ?? "").replace(/^#/u, "");
18476
18004
  if (!/^[0-9a-f]{6}$/iu.test(hex)) {
18477
- return chunkJAI42EXQ_js.DEFAULT_TEXT_COLOR;
18005
+ return chunkJWNBTFZZ_js.DEFAULT_TEXT_COLOR;
18478
18006
  }
18479
18007
  const channels = [0, 2, 4].map((offset) => Number.parseInt(hex.slice(offset, offset + 2), 16) / 255).map((channel) => channel <= 0.04045 ? channel / 12.92 : ((channel + 0.055) / 1.055) ** 2.4);
18480
18008
  const luminance = channels[0] * 0.2126 + channels[1] * 0.7152 + channels[2] * 0.0722;
18481
- return luminance > 0.179 ? chunkJAI42EXQ_js.DEFAULT_TEXT_COLOR : "#ffffff";
18009
+ return luminance > 0.179 ? chunkJWNBTFZZ_js.DEFAULT_TEXT_COLOR : "#ffffff";
18482
18010
  }
18483
18011
  function getStaticElementVisualState(element, parentGroupFill) {
18484
18012
  const style = pptx$1.hasShapeProperties(element) ? element.shapeStyle : void 0;
18485
- const hasFill = style?.fillColor !== void 0 && style.fillColor !== "transparent" || Boolean(chunkJAI42EXQ_js.buildCssGradientFromShapeStyle(style) || style?.fillGradient) || style?.fillMode === "pattern" && Boolean(style.fillPatternPreset);
18486
- const fill = chunkJAI42EXQ_js.normalizeHexColor(style?.fillColor, chunkJAI42EXQ_js.DEFAULT_FILL_COLOR);
18013
+ const hasFill = style?.fillColor !== void 0 && style.fillColor !== "transparent" || Boolean(chunkJWNBTFZZ_js.buildCssGradientFromShapeStyle(style) || style?.fillGradient) || style?.fillMode === "pattern" && Boolean(style.fillPatternPreset);
18014
+ const fill = chunkJWNBTFZZ_js.normalizeHexColor(style?.fillColor, chunkJWNBTFZZ_js.DEFAULT_FILL_COLOR);
18487
18015
  const strokeWidth = pptx.paintedStrokeWidth(style);
18488
- const stroke = chunkJAI42EXQ_js.normalizeHexColor(style?.strokeColor, chunkJAI42EXQ_js.DEFAULT_STROKE_COLOR);
18489
- const baseVisualStyle = chunkJAI42EXQ_js.getShapeVisualStyle(element, hasFill, fill, strokeWidth, stroke);
18016
+ const stroke = chunkJWNBTFZZ_js.normalizeHexColor(style?.strokeColor, chunkJWNBTFZZ_js.DEFAULT_STROKE_COLOR);
18017
+ const baseVisualStyle = chunkJWNBTFZZ_js.getShapeVisualStyle(element, hasFill, fill, strokeWidth, stroke);
18490
18018
  const inheritedFill = pptx.resolveGroupChildFill(element, parentGroupFill);
18491
18019
  const visualStyle = inheritedFill ? {
18492
18020
  ...baseVisualStyle,
@@ -18496,9 +18024,9 @@ function getStaticElementVisualState(element, parentGroupFill) {
18496
18024
  backgroundSize: inheritedFill.backgroundSize,
18497
18025
  backgroundPosition: inheritedFill.backgroundPosition
18498
18026
  } : baseVisualStyle;
18499
- const textStyle = chunkJAI42EXQ_js.getTextStyleForElement(
18027
+ const textStyle = chunkJWNBTFZZ_js.getTextStyleForElement(
18500
18028
  element,
18501
- element.type === "shape" && hasFill ? defaultTextColorForFill(fill) : chunkJAI42EXQ_js.DEFAULT_TEXT_COLOR
18029
+ element.type === "shape" && hasFill ? defaultTextColorForFill(fill) : chunkJWNBTFZZ_js.DEFAULT_TEXT_COLOR
18502
18030
  );
18503
18031
  const isImage = element.type === "picture" || element.type === "image";
18504
18032
  const letsTextOverflow = pptx$1.hasTextProperties(element) && element.textStyle?.autoFitMode === "shrink" && (element.type === "text" || element.locks?.txBox === true);
@@ -18523,7 +18051,7 @@ function getStaticElementInteractionState(element, hasActionHandler, exposeEleme
18523
18051
  return { action, isActionable, contractRole };
18524
18052
  }
18525
18053
  function getStaticElementWrapperClassName(element, visual, positioned, isActionable) {
18526
- const overflowClass = visual.isImage || visual.strokeWidth > 0 || element.type === "group" || chunkJAI42EXQ_js.isConnectorOrLineElement(element) || visual.isCallout || visual.letsTextOverflow ? "" : "overflow-hidden";
18054
+ const overflowClass = visual.isImage || visual.strokeWidth > 0 || element.type === "group" || chunkJWNBTFZZ_js.isConnectorOrLineElement(element) || visual.isCallout || visual.letsTextOverflow ? "" : "overflow-hidden";
18527
18055
  const pointerClass = isActionable ? "pointer-events-auto cursor-pointer" : "pointer-events-none";
18528
18056
  return `${positioned ? "absolute" : "relative"} ${overflowClass} ${pointerClass}`;
18529
18057
  }
@@ -18606,7 +18134,7 @@ function StaticElementRendererImpl({
18606
18134
  top: positioned ? element.y : void 0,
18607
18135
  width: positioned ? Math.max(element.width, 1) : "100%",
18608
18136
  height: positioned ? Math.max(element.height, 1) : "100%",
18609
- transform: positioned ? chunkJAI42EXQ_js.getElementTransform(element) : void 0,
18137
+ transform: positioned ? chunkJWNBTFZZ_js.getElementTransform(element) : void 0,
18610
18138
  transformOrigin: "center",
18611
18139
  zIndex,
18612
18140
  ...visualStyle,
@@ -18649,18 +18177,18 @@ function StaticElementRendererImpl({
18649
18177
  spellCheck: false,
18650
18178
  txtSE: pptx$1.hasTextProperties(element) ? element.textStyle : void 0,
18651
18179
  txtS: textStyle,
18652
- vecShape: chunkJAI42EXQ_js.renderVectorShape(
18180
+ vecShape: chunkJWNBTFZZ_js.renderVectorShape(
18653
18181
  element,
18654
18182
  isImage ? false : hasFill,
18655
18183
  fill,
18656
18184
  strokeWidth,
18657
18185
  stroke
18658
18186
  ),
18659
- imgStyle: imageAnimation ? { ...chunkJAI42EXQ_js.getImageRenderStyle(element), animation: imageAnimation } : chunkJAI42EXQ_js.getImageRenderStyle(element),
18660
- imgFilter: chunkJAI42EXQ_js.getImageEffectsFilter(element),
18661
- imgOpacity: chunkJAI42EXQ_js.getImageEffectsOpacity(element),
18187
+ imgStyle: imageAnimation ? { ...chunkJWNBTFZZ_js.getImageRenderStyle(element), animation: imageAnimation } : chunkJWNBTFZZ_js.getImageRenderStyle(element),
18188
+ imgFilter: chunkJWNBTFZZ_js.getImageEffectsFilter(element),
18189
+ imgOpacity: chunkJWNBTFZZ_js.getImageEffectsOpacity(element),
18662
18190
  imgAlt: "",
18663
- isTxtEl: chunkJAI42EXQ_js.isEditableTextElement(element),
18191
+ isTxtEl: chunkJWNBTFZZ_js.isEditableTextElement(element),
18664
18192
  media: mediaDataUrls,
18665
18193
  tableSt: null,
18666
18194
  isSel: false,
@@ -18708,7 +18236,7 @@ function SlideLayer({
18708
18236
  style: {
18709
18237
  width: safeWidth,
18710
18238
  height: safeHeight,
18711
- backgroundColor: slide.backgroundColor ? chunkJAI42EXQ_js.normalizeHexColor(slide.backgroundColor, "#ffffff") : "#ffffff",
18239
+ backgroundColor: slide.backgroundColor ? chunkJWNBTFZZ_js.normalizeHexColor(slide.backgroundColor, "#ffffff") : "#ffffff",
18712
18240
  backgroundImage: slide.backgroundImage ? `url(${slide.backgroundImage})` : slide.backgroundGradient ? slide.backgroundGradient : void 0,
18713
18241
  backgroundSize: slide.backgroundImage ? "cover" : void 0,
18714
18242
  backgroundPosition: slide.backgroundImage ? "center" : void 0
@@ -19230,7 +18758,6 @@ exports.Rendering3DFlagsContext = Rendering3DFlagsContext;
19230
18758
  exports.ResizeHandles = ResizeHandles;
19231
18759
  exports.SlideBackgroundImageLayer = SlideBackgroundImageLayer;
19232
18760
  exports.SlideLayer = SlideLayer;
19233
- exports.SmartArtRenderer = SmartArtRenderer;
19234
18761
  exports.StaticElementRenderer = StaticElementRenderer;
19235
18762
  exports.ViewerOptionsContext = ViewerOptionsContext;
19236
18763
  exports.ViewerOptionsStoreContext = ViewerOptionsStoreContext;
@@ -19264,6 +18791,7 @@ exports.useCollaborativeState = useCollaborativeState;
19264
18791
  exports.useComments = useComments;
19265
18792
  exports.useCompatibilityToastsState = useCompatibilityToastsState;
19266
18793
  exports.useContentLifecycle = useContentLifecycle;
18794
+ exports.useController = useController;
19267
18795
  exports.useDerivedElementState = useDerivedElementState;
19268
18796
  exports.useDerivedSlideState = useDerivedSlideState;
19269
18797
  exports.useDialogCustomShows = useDialogCustomShows;