pptx-react-viewer 1.1.6 → 1.1.7

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 (31) hide show
  1. package/dist/{PowerPointViewer-CX0a7wz_.d.mts → PowerPointViewer-C5jGuKGB.d.mts} +3 -1
  2. package/dist/{PowerPointViewer-CX0a7wz_.d.ts → PowerPointViewer-C5jGuKGB.d.ts} +3 -1
  3. package/dist/index.d.mts +3 -2
  4. package/dist/index.d.ts +3 -2
  5. package/dist/index.js +1224 -454
  6. package/dist/index.mjs +1225 -455
  7. package/dist/pptx-viewer.css +1 -1
  8. package/dist/viewer/index.d.mts +6 -25
  9. package/dist/viewer/index.d.ts +6 -25
  10. package/dist/viewer/index.js +1224 -454
  11. package/dist/viewer/index.mjs +1225 -455
  12. package/node_modules/emf-converter/package.json +1 -1
  13. package/node_modules/mtx-decompressor/package.json +1 -1
  14. package/node_modules/pptx-viewer-core/dist/{SvgExporter-CTDG-t_z.d.ts → SvgExporter-BtZczTlB.d.ts} +1 -1
  15. package/node_modules/pptx-viewer-core/dist/{SvgExporter-BTkk4oNQ.d.mts → SvgExporter-D4mBWJHE.d.mts} +1 -1
  16. package/node_modules/pptx-viewer-core/dist/cli/index.d.mts +2 -2
  17. package/node_modules/pptx-viewer-core/dist/cli/index.d.ts +2 -2
  18. package/node_modules/pptx-viewer-core/dist/cli/index.js +0 -0
  19. package/node_modules/pptx-viewer-core/dist/cli/index.mjs +0 -0
  20. package/node_modules/pptx-viewer-core/dist/converter/index.d.mts +3 -3
  21. package/node_modules/pptx-viewer-core/dist/converter/index.d.ts +3 -3
  22. package/node_modules/pptx-viewer-core/dist/index.d.mts +108 -19
  23. package/node_modules/pptx-viewer-core/dist/index.d.ts +108 -19
  24. package/node_modules/pptx-viewer-core/dist/index.js +532 -306
  25. package/node_modules/pptx-viewer-core/dist/index.mjs +524 -307
  26. package/node_modules/pptx-viewer-core/dist/{presentation-4fhI3din.d.mts → presentation-nZxgWvXq.d.mts} +40 -1
  27. package/node_modules/pptx-viewer-core/dist/{presentation-4fhI3din.d.ts → presentation-nZxgWvXq.d.ts} +40 -1
  28. package/node_modules/pptx-viewer-core/dist/{text-operations-C89Jn6S0.d.mts → text-operations-DCTGMltY.d.mts} +1 -1
  29. package/node_modules/pptx-viewer-core/dist/{text-operations-B9EwbptL.d.ts → text-operations-DYmhoi7U.d.ts} +1 -1
  30. package/node_modules/pptx-viewer-core/package.json +1 -1
  31. package/package.json +4 -4
@@ -43598,7 +43598,7 @@ var require_use_sync_external_store_shim_development = __commonJS({
43598
43598
  return x2 === y && (0 !== x2 || 1 / x2 === 1 / y) || x2 !== x2 && y !== y;
43599
43599
  }
43600
43600
  function useSyncExternalStore$2(subscribe3, getSnapshot2) {
43601
- didWarnOld18Alpha || void 0 === React100.startTransition || (didWarnOld18Alpha = true, console.error(
43601
+ didWarnOld18Alpha || void 0 === React103.startTransition || (didWarnOld18Alpha = true, console.error(
43602
43602
  "You are using an outdated, pre-release alpha of React 18 that does not support useSyncExternalStore. The use-sync-external-store shim will not work correctly. Upgrade to a newer pre-release."
43603
43603
  ));
43604
43604
  var value = getSnapshot2();
@@ -43608,7 +43608,7 @@ var require_use_sync_external_store_shim_development = __commonJS({
43608
43608
  "The result of getSnapshot should be cached to avoid an infinite loop"
43609
43609
  ), didWarnUncachedGetSnapshot = true);
43610
43610
  }
43611
- cachedValue = useState86({
43611
+ cachedValue = useState89({
43612
43612
  inst: { value, getSnapshot: getSnapshot2 }
43613
43613
  });
43614
43614
  var inst = cachedValue[0].inst, forceUpdate = cachedValue[1];
@@ -43620,7 +43620,7 @@ var require_use_sync_external_store_shim_development = __commonJS({
43620
43620
  },
43621
43621
  [subscribe3, value, getSnapshot2]
43622
43622
  );
43623
- useEffect72(
43623
+ useEffect73(
43624
43624
  function() {
43625
43625
  checkIfSnapshotChanged(inst) && forceUpdate({ inst });
43626
43626
  return subscribe3(function() {
@@ -43646,8 +43646,8 @@ var require_use_sync_external_store_shim_development = __commonJS({
43646
43646
  return getSnapshot2();
43647
43647
  }
43648
43648
  "undefined" !== typeof __REACT_DEVTOOLS_GLOBAL_HOOK__ && "function" === typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.registerInternalModuleStart && __REACT_DEVTOOLS_GLOBAL_HOOK__.registerInternalModuleStart(Error());
43649
- var React100 = __require("react"), objectIs = "function" === typeof Object.is ? Object.is : is2, useState86 = React100.useState, useEffect72 = React100.useEffect, useLayoutEffect7 = React100.useLayoutEffect, useDebugValue = React100.useDebugValue, didWarnOld18Alpha = false, didWarnUncachedGetSnapshot = false, shim = "undefined" === typeof window || "undefined" === typeof window.document || "undefined" === typeof window.document.createElement ? useSyncExternalStore$1 : useSyncExternalStore$2;
43650
- exports$1.useSyncExternalStore = void 0 !== React100.useSyncExternalStore ? React100.useSyncExternalStore : shim;
43649
+ var React103 = __require("react"), objectIs = "function" === typeof Object.is ? Object.is : is2, useState89 = React103.useState, useEffect73 = React103.useEffect, useLayoutEffect7 = React103.useLayoutEffect, useDebugValue = React103.useDebugValue, didWarnOld18Alpha = false, didWarnUncachedGetSnapshot = false, shim = "undefined" === typeof window || "undefined" === typeof window.document || "undefined" === typeof window.document.createElement ? useSyncExternalStore$1 : useSyncExternalStore$2;
43650
+ exports$1.useSyncExternalStore = void 0 !== React103.useSyncExternalStore ? React103.useSyncExternalStore : shim;
43651
43651
  "undefined" !== typeof __REACT_DEVTOOLS_GLOBAL_HOOK__ && "function" === typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.registerInternalModuleStop && __REACT_DEVTOOLS_GLOBAL_HOOK__.registerInternalModuleStop(Error());
43652
43652
  })();
43653
43653
  }
@@ -43670,9 +43670,9 @@ var require_with_selector_development = __commonJS({
43670
43670
  return x2 === y && (0 !== x2 || 1 / x2 === 1 / y) || x2 !== x2 && y !== y;
43671
43671
  }
43672
43672
  "undefined" !== typeof __REACT_DEVTOOLS_GLOBAL_HOOK__ && "function" === typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.registerInternalModuleStart && __REACT_DEVTOOLS_GLOBAL_HOOK__.registerInternalModuleStart(Error());
43673
- var React100 = __require("react"), shim = require_shim(), objectIs = "function" === typeof Object.is ? Object.is : is2, useSyncExternalStore3 = shim.useSyncExternalStore, useRef73 = React100.useRef, useEffect72 = React100.useEffect, useMemo42 = React100.useMemo, useDebugValue = React100.useDebugValue;
43673
+ var React103 = __require("react"), shim = require_shim(), objectIs = "function" === typeof Object.is ? Object.is : is2, useSyncExternalStore3 = shim.useSyncExternalStore, useRef74 = React103.useRef, useEffect73 = React103.useEffect, useMemo42 = React103.useMemo, useDebugValue = React103.useDebugValue;
43674
43674
  exports$1.useSyncExternalStoreWithSelector = function(subscribe3, getSnapshot2, getServerSnapshot2, selector, isEqual) {
43675
- var instRef = useRef73(null);
43675
+ var instRef = useRef74(null);
43676
43676
  if (null === instRef.current) {
43677
43677
  var inst = { hasValue: false, value: null };
43678
43678
  instRef.current = inst;
@@ -43713,7 +43713,7 @@ var require_with_selector_development = __commonJS({
43713
43713
  [getSnapshot2, getServerSnapshot2, selector, isEqual]
43714
43714
  );
43715
43715
  var value = useSyncExternalStore3(subscribe3, instRef[0], instRef[1]);
43716
- useEffect72(
43716
+ useEffect73(
43717
43717
  function() {
43718
43718
  inst.hasValue = true;
43719
43719
  inst.value = value;
@@ -75524,9 +75524,9 @@ function renderImageAlphaSvgFilter(element2) {
75524
75524
  const primitives = [];
75525
75525
  let resultIdx = 0;
75526
75526
  let inputRef = "SourceGraphic";
75527
- const next = (jsx229) => {
75527
+ const next = (jsx235) => {
75528
75528
  const result = `r${resultIdx++}`;
75529
- primitives.push(jsx229(inputRef, result));
75529
+ primitives.push(jsx235(inputRef, result));
75530
75530
  inputRef = result;
75531
75531
  };
75532
75532
  if (typeof e2.alphaModFix === "number") {
@@ -79567,8 +79567,8 @@ function renderTableElement(element2, textStyle, options) {
79567
79567
  {
79568
79568
  style: rowHeight ? { height: rowHeight } : void 0,
79569
79569
  children: cells.map((cell, cellIndex) => {
79570
- const isHMerged = cell["@_hMerge"] === "1" || cell["@_hMerge"] === true;
79571
- const isVMerged = cell["@_vMerge"] === "1" || cell["@_vMerge"] === true;
79570
+ const isHMerged = cell["@_hMerge"] === "1";
79571
+ const isVMerged = cell["@_vMerge"] === "1";
79572
79572
  if (isHMerged || isVMerged) {
79573
79573
  return null;
79574
79574
  }
@@ -85577,6 +85577,15 @@ function copyFormatFromElement(element2) {
85577
85577
  }
85578
85578
  return result;
85579
85579
  }
85580
+ function definedEntries(obj) {
85581
+ const out = {};
85582
+ for (const key in obj) {
85583
+ if (obj[key] !== void 0) {
85584
+ out[key] = obj[key];
85585
+ }
85586
+ }
85587
+ return out;
85588
+ }
85580
85589
  function applyFormatToElement(element2, format) {
85581
85590
  let updated = { ...element2 };
85582
85591
  if (format.shapeStyle && pptxViewerCore.hasShapeProperties(updated)) {
@@ -85584,7 +85593,7 @@ function applyFormatToElement(element2, format) {
85584
85593
  ...updated,
85585
85594
  shapeStyle: {
85586
85595
  ...updated.shapeStyle,
85587
- ...format.shapeStyle
85596
+ ...definedEntries(format.shapeStyle)
85588
85597
  }
85589
85598
  };
85590
85599
  }
@@ -85593,12 +85602,18 @@ function applyFormatToElement(element2, format) {
85593
85602
  ...updated,
85594
85603
  textStyle: {
85595
85604
  ...updated.textStyle,
85596
- ...format.textStyle
85605
+ ...definedEntries(format.textStyle)
85597
85606
  }
85598
85607
  };
85599
85608
  }
85600
85609
  return updated;
85601
85610
  }
85611
+ function hasCopyableFormat(element2) {
85612
+ if (!element2) {
85613
+ return false;
85614
+ }
85615
+ return pptxViewerCore.hasShapeProperties(element2) || pptxViewerCore.hasTextProperties(element2);
85616
+ }
85602
85617
 
85603
85618
  // src/viewer/utils/animation-preview.ts
85604
85619
  var PRESET_TO_EFFECT = {
@@ -86947,8 +86962,8 @@ function ThumbnailTable({
86947
86962
  {
86948
86963
  style: rowHeight ? { height: rowHeight } : void 0,
86949
86964
  children: cells.map((cell, ci) => {
86950
- const isHMerged = cell["@_hMerge"] === "1" || cell["@_hMerge"] === true;
86951
- const isVMerged = cell["@_vMerge"] === "1" || cell["@_vMerge"] === true;
86965
+ const isHMerged = cell["@_hMerge"] === "1";
86966
+ const isVMerged = cell["@_vMerge"] === "1";
86952
86967
  if (isHMerged || isVMerged) {
86953
86968
  return null;
86954
86969
  }
@@ -92039,11 +92054,16 @@ function usePresenceTracking({
92039
92054
  if (cid === localClientId) {
92040
92055
  return;
92041
92056
  }
92042
- const raw = state2?.presence;
92057
+ const stateRecord = state2;
92058
+ const raw = stateRecord?.presence;
92043
92059
  if (!raw || typeof raw !== "object") {
92044
92060
  return;
92045
92061
  }
92046
- const sanitized = sanitizePresence({ ...raw, clientId: cid }, canvasWidth, canvasHeight);
92062
+ const sanitized = sanitizePresence(
92063
+ { ...raw, clientId: cid },
92064
+ canvasWidth,
92065
+ canvasHeight
92066
+ );
92047
92067
  if (!sanitized) {
92048
92068
  return;
92049
92069
  }
@@ -92111,15 +92131,9 @@ function useYjsProvider({ config }) {
92111
92131
  try {
92112
92132
  const [Y, { WebsocketProvider: WebsocketProvider2 }] = await Promise.all([Promise.resolve().then(() => (init_yjs(), yjs_exports)), Promise.resolve().then(() => (init_y_websocket(), y_websocket_exports))]);
92113
92133
  const yDoc = new Y.Doc();
92114
- const provider = new WebsocketProvider2(
92115
- config.serverUrl,
92116
- roomId,
92117
- yDoc,
92118
- // eslint-disable-line @typescript-eslint/no-explicit-any
92119
- {
92120
- params: config.authToken ? { token: config.authToken } : void 0
92121
- }
92122
- );
92134
+ const provider = new WebsocketProvider2(config.serverUrl, roomId, yDoc, {
92135
+ params: config.authToken ? { token: config.authToken } : void 0
92136
+ });
92123
92137
  let connected = false;
92124
92138
  const handleStatus = (event) => {
92125
92139
  if (event.status === "connected") {
@@ -95780,90 +95794,101 @@ var SlideNotesPanel = ({
95780
95794
  });
95781
95795
  const hasNotes = draft.trim().length > 0;
95782
95796
  const slideLabel = activeSlide ? t2("pptx.notes.slideN", { n: activeSlide.slideNumber }) : t2("pptx.notes.noSlide");
95783
- return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col border-t border-border/60 bg-background select-none", children: [
95784
- /* @__PURE__ */ jsxRuntime.jsxs(
95785
- "button",
95786
- {
95787
- type: "button",
95788
- onClick: onToggle,
95789
- className: "flex items-center gap-1.5 px-3 py-1 text-[11px] text-muted-foreground hover:text-foreground hover:bg-accent/30 transition-colors w-full text-left shrink-0",
95790
- "aria-expanded": isExpanded,
95791
- "aria-controls": "slide-notes-content",
95792
- children: [
95793
- "Notes",
95794
- !isExpanded && hasNotes && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-muted-foreground/50 text-[10px]", children: "(has notes)" })
95795
- ]
95796
- }
95797
- ),
95798
- isExpanded && /* @__PURE__ */ jsxRuntime.jsxs(
95799
- "div",
95800
- {
95801
- id: "slide-notes-content",
95802
- className: "px-3 pb-2 overflow-y-auto",
95803
- style: { maxHeight: panelHeight ?? EXPANDED_MAX_HEIGHT + 40 },
95804
- children: [
95805
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-[10px] text-muted-foreground mb-1", children: slideLabel }),
95806
- canEdit ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
95807
- /* @__PURE__ */ jsxRuntime.jsx(
95808
- NotesToolbar,
95809
- {
95810
- isRichEditEnabled,
95811
- showLinkPopover,
95812
- savedSelectionText: savedSelectionRef.current?.text ?? "",
95813
- hasAllSlides: allSlides !== void 0 && allSlides.length > 0,
95814
- onApplyRichCommand: applyRichCommand,
95815
- onToggleBulletList: toggleBulletList,
95816
- onToggleNumberedList: toggleNumberedList,
95817
- onIndent: handleIndent,
95818
- onOutdent: handleOutdent,
95819
- onLinkButtonClick: handleLinkButtonClick,
95820
- onInsertLink: handleInsertLink,
95821
- onCloseLinkPopover: () => setShowLinkPopover(false),
95822
- onPrintClick: () => setShowPrintDialog(true),
95823
- onToggleRichEdit: () => setIsRichEditEnabled((prev) => !prev)
95824
- }
95825
- ),
95826
- isRichEditEnabled ? /* @__PURE__ */ jsxRuntime.jsx(
95827
- "div",
95828
- {
95829
- ref: richEditorRef,
95830
- contentEditable: true,
95831
- suppressContentEditableWarning: true,
95832
- onInput: handleRichInput,
95833
- onBlur: handleBlur,
95834
- onKeyDown: handleKeyDownRich,
95835
- onClick: handleEditorClick,
95836
- className: "w-full overflow-y-auto rounded-md border border-border/50 bg-muted/60 px-2.5 py-1.5 text-xs text-foreground focus:border-primary/50 focus:outline-none focus:ring-1 focus:ring-primary/30 transition-colors whitespace-pre-wrap",
95837
- style: { maxHeight: EXPANDED_MAX_HEIGHT - 8, minHeight: 72 }
95838
- }
95839
- ) : /* @__PURE__ */ jsxRuntime.jsx(
95840
- "textarea",
95841
- {
95842
- ref: textareaRef,
95843
- name: "slide-notes",
95844
- value: draft,
95845
- onChange: handlePlainChange,
95846
- onBlur: handleBlur,
95847
- onKeyDown: handleKeyDownPlain,
95848
- placeholder: t2("pptx.notes.clickToAddNotes"),
95849
- rows: 4,
95850
- className: "w-full resize-none rounded-md border border-border/50 bg-muted/60 px-2.5 py-1.5 text-xs text-foreground placeholder:text-muted-foreground focus:border-primary/50 focus:outline-none focus:ring-1 focus:ring-primary/30 transition-colors",
95851
- style: { maxHeight: EXPANDED_MAX_HEIGHT - 8 }
95852
- }
95853
- )
95854
- ] }) : /* @__PURE__ */ jsxRuntime.jsx(
95855
- "div",
95856
- {
95857
- className: "w-full rounded-md border border-border/30 bg-muted/40 px-2.5 py-1.5 text-xs text-muted-foreground overflow-y-auto whitespace-pre-wrap",
95858
- style: { maxHeight: EXPANDED_MAX_HEIGHT - 32, minHeight: 60 },
95859
- children: hasNotes ? renderRichNotesSegments(draftSegments) : /* @__PURE__ */ jsxRuntime.jsx("span", { className: "italic text-muted-foreground", children: t2("pptx.notes.noNotes") })
95860
- }
95861
- )
95862
- ]
95863
- }
95864
- ),
95865
- showPrintDialog && allSlides && /* @__PURE__ */ jsxRuntime.jsx(NotesPrintDialog, { slides: allSlides, onClose: () => setShowPrintDialog(false) })
95866
- ] });
95797
+ return /* @__PURE__ */ jsxRuntime.jsxs(
95798
+ "div",
95799
+ {
95800
+ className: cn(
95801
+ "flex flex-col border-t border-border/60 bg-background select-none",
95802
+ // On mobile, hide the entire notes strip when collapsed — the
95803
+ // MobileBottomBar's Notes button is the entry point instead.
95804
+ !isExpanded && "max-md:hidden"
95805
+ ),
95806
+ children: [
95807
+ /* @__PURE__ */ jsxRuntime.jsxs(
95808
+ "button",
95809
+ {
95810
+ type: "button",
95811
+ onClick: onToggle,
95812
+ className: "flex items-center gap-1.5 px-3 py-1 text-[11px] text-muted-foreground hover:text-foreground hover:bg-accent/30 transition-colors w-full text-left shrink-0 max-md:hidden",
95813
+ "aria-expanded": isExpanded,
95814
+ "aria-controls": "slide-notes-content",
95815
+ children: [
95816
+ "Notes",
95817
+ !isExpanded && hasNotes && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-muted-foreground/50 text-[10px]", children: "(has notes)" })
95818
+ ]
95819
+ }
95820
+ ),
95821
+ isExpanded && /* @__PURE__ */ jsxRuntime.jsxs(
95822
+ "div",
95823
+ {
95824
+ id: "slide-notes-content",
95825
+ className: "px-3 pb-2 overflow-y-auto",
95826
+ style: { maxHeight: panelHeight ?? EXPANDED_MAX_HEIGHT + 40 },
95827
+ children: [
95828
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-[10px] text-muted-foreground mb-1", children: slideLabel }),
95829
+ canEdit ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
95830
+ /* @__PURE__ */ jsxRuntime.jsx(
95831
+ NotesToolbar,
95832
+ {
95833
+ isRichEditEnabled,
95834
+ showLinkPopover,
95835
+ savedSelectionText: savedSelectionRef.current?.text ?? "",
95836
+ hasAllSlides: allSlides !== void 0 && allSlides.length > 0,
95837
+ onApplyRichCommand: applyRichCommand,
95838
+ onToggleBulletList: toggleBulletList,
95839
+ onToggleNumberedList: toggleNumberedList,
95840
+ onIndent: handleIndent,
95841
+ onOutdent: handleOutdent,
95842
+ onLinkButtonClick: handleLinkButtonClick,
95843
+ onInsertLink: handleInsertLink,
95844
+ onCloseLinkPopover: () => setShowLinkPopover(false),
95845
+ onPrintClick: () => setShowPrintDialog(true),
95846
+ onToggleRichEdit: () => setIsRichEditEnabled((prev) => !prev)
95847
+ }
95848
+ ),
95849
+ isRichEditEnabled ? /* @__PURE__ */ jsxRuntime.jsx(
95850
+ "div",
95851
+ {
95852
+ ref: richEditorRef,
95853
+ contentEditable: true,
95854
+ suppressContentEditableWarning: true,
95855
+ onInput: handleRichInput,
95856
+ onBlur: handleBlur,
95857
+ onKeyDown: handleKeyDownRich,
95858
+ onClick: handleEditorClick,
95859
+ className: "w-full overflow-y-auto rounded-md border border-border/50 bg-muted/60 px-2.5 py-1.5 text-xs text-foreground focus:border-primary/50 focus:outline-none focus:ring-1 focus:ring-primary/30 transition-colors whitespace-pre-wrap",
95860
+ style: { maxHeight: EXPANDED_MAX_HEIGHT - 8, minHeight: 72 }
95861
+ }
95862
+ ) : /* @__PURE__ */ jsxRuntime.jsx(
95863
+ "textarea",
95864
+ {
95865
+ ref: textareaRef,
95866
+ name: "slide-notes",
95867
+ value: draft,
95868
+ onChange: handlePlainChange,
95869
+ onBlur: handleBlur,
95870
+ onKeyDown: handleKeyDownPlain,
95871
+ placeholder: t2("pptx.notes.clickToAddNotes"),
95872
+ rows: 4,
95873
+ className: "w-full resize-none rounded-md border border-border/50 bg-muted/60 px-2.5 py-1.5 text-xs text-foreground placeholder:text-muted-foreground focus:border-primary/50 focus:outline-none focus:ring-1 focus:ring-primary/30 transition-colors",
95874
+ style: { maxHeight: EXPANDED_MAX_HEIGHT - 8 }
95875
+ }
95876
+ )
95877
+ ] }) : /* @__PURE__ */ jsxRuntime.jsx(
95878
+ "div",
95879
+ {
95880
+ className: "w-full rounded-md border border-border/30 bg-muted/40 px-2.5 py-1.5 text-xs text-muted-foreground overflow-y-auto whitespace-pre-wrap",
95881
+ style: { maxHeight: EXPANDED_MAX_HEIGHT - 32, minHeight: 60 },
95882
+ children: hasNotes ? renderRichNotesSegments(draftSegments) : /* @__PURE__ */ jsxRuntime.jsx("span", { className: "italic text-muted-foreground", children: t2("pptx.notes.noNotes") })
95883
+ }
95884
+ )
95885
+ ]
95886
+ }
95887
+ ),
95888
+ showPrintDialog && allSlides && /* @__PURE__ */ jsxRuntime.jsx(NotesPrintDialog, { slides: allSlides, onClose: () => setShowPrintDialog(false) })
95889
+ ]
95890
+ }
95891
+ );
95867
95892
  };
95868
95893
  var DB_NAME = "pptx-viewer-autosave";
95869
95894
  var DB_VERSION = 1;
@@ -98400,7 +98425,8 @@ function ArrangeSection(p3) {
98400
98425
  {
98401
98426
  type: "button",
98402
98427
  onClick: p3.onToggleFormatPainter,
98403
- disabled: !p3.canEdit,
98428
+ disabled: !p3.canEdit || p3.canActivateFormatPainter === false && !p3.formatPainterActive,
98429
+ "data-testid": "format-painter-toggle",
98404
98430
  className: cn(
98405
98431
  pill,
98406
98432
  p3.formatPainterActive ? "bg-amber-600 hover:bg-amber-500 text-amber-50" : ""
@@ -98852,7 +98878,8 @@ function HomeSection(p3) {
98852
98878
  const { fontFamily, fontSize } = extractFontInfo(p3.selectedElement);
98853
98879
  const handleNewSlide = React10.useCallback(() => {
98854
98880
  if (p3.layoutOptions.length > 0) {
98855
- p3.onInsertSlideFromLayout(p3.layoutOptions[0].path);
98881
+ const first = p3.layoutOptions[0];
98882
+ p3.onInsertSlideFromLayout(first.path, first.name);
98856
98883
  }
98857
98884
  }, [p3]);
98858
98885
  React10.useEffect(() => {
@@ -98939,7 +98966,8 @@ function HomeSection(p3) {
98939
98966
  {
98940
98967
  type: "button",
98941
98968
  onClick: p3.onToggleFormatPainter,
98942
- disabled: !p3.canEdit,
98969
+ disabled: !p3.canEdit || p3.canActivateFormatPainter === false && !p3.formatPainterActive,
98970
+ "data-testid": "format-painter-toggle",
98943
98971
  className: cn(
98944
98972
  gL,
98945
98973
  p3.formatPainterActive ? "bg-amber-600 hover:bg-amber-500 text-amber-50" : ""
@@ -98989,7 +99017,7 @@ function HomeSection(p3) {
98989
99017
  type: "button",
98990
99018
  className: "flex items-center gap-2 w-full px-3 py-1.5 text-xs text-foreground hover:bg-muted transition-colors",
98991
99019
  onClick: () => {
98992
- p3.onInsertSlideFromLayout(lo.path);
99020
+ p3.onInsertSlideFromLayout(lo.path, lo.name);
98993
99021
  setLayoutMenuOpen(false);
98994
99022
  },
98995
99023
  children: lo.name
@@ -99889,6 +99917,561 @@ function TextSection(p3) {
99889
99917
  ] })
99890
99918
  ] });
99891
99919
  }
99920
+ function ViewSection(p3) {
99921
+ const { t: t2 } = reactI18next.useTranslation();
99922
+ return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
99923
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col items-center gap-0.5", children: [
99924
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-0.5", children: [
99925
+ /* @__PURE__ */ jsxRuntime.jsx("button", { className: pill, title: "Normal view", children: "Normal" }),
99926
+ p3.onToggleSlideSorter ? /* @__PURE__ */ jsxRuntime.jsx("button", { className: pill, onClick: p3.onToggleSlideSorter, title: "Slide Sorter view", children: "Slide Sorter" }) : /* @__PURE__ */ jsxRuntime.jsx("button", { className: pill, title: "Slide Sorter view", children: "Slide Sorter" }),
99927
+ /* @__PURE__ */ jsxRuntime.jsx("button", { className: pill, title: "Reading View", children: "Reading View" })
99928
+ ] }),
99929
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-[9px] text-muted-foreground leading-none", children: "Presentation Views" })
99930
+ ] }),
99931
+ sep,
99932
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col items-center gap-0.5", children: [
99933
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex items-center gap-0.5", children: /* @__PURE__ */ jsxRuntime.jsx(
99934
+ "button",
99935
+ {
99936
+ onClick: p3.onEnterMasterView,
99937
+ disabled: !p3.canEdit,
99938
+ className: pill,
99939
+ title: "Edit slide masters and layouts",
99940
+ children: "Slide Master"
99941
+ }
99942
+ ) }),
99943
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-[9px] text-muted-foreground leading-none", children: "Master Views" })
99944
+ ] }),
99945
+ sep,
99946
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col items-center gap-0.5", children: [
99947
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex items-center gap-0.5", children: p3.onZoomToFit && /* @__PURE__ */ jsxRuntime.jsx("button", { className: pill, onClick: p3.onZoomToFit, title: "Zoom to fit slide in window", children: "Zoom to Fit" }) }),
99948
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-[9px] text-muted-foreground leading-none", children: "Zoom" })
99949
+ ] }),
99950
+ sep,
99951
+ /* @__PURE__ */ jsxRuntime.jsx(
99952
+ "button",
99953
+ {
99954
+ onClick: () => p3.onSetEditTemplateMode(!p3.editTemplateMode),
99955
+ disabled: !p3.canEdit,
99956
+ className: cn(
99957
+ pill,
99958
+ p3.editTemplateMode ? "bg-amber-600 hover:bg-amber-500 text-amber-50" : ""
99959
+ ),
99960
+ title: "Toggle template/master element editing",
99961
+ children: p3.editTemplateMode ? "Templates On" : "Templates Off"
99962
+ }
99963
+ ),
99964
+ p3.onToggleSelectionPane && /* @__PURE__ */ jsxRuntime.jsxs(
99965
+ "button",
99966
+ {
99967
+ type: "button",
99968
+ onClick: p3.onToggleSelectionPane,
99969
+ className: cn(
99970
+ pill,
99971
+ p3.isSelectionPaneOpen ? "bg-primary hover:bg-primary/80 text-primary-foreground" : ""
99972
+ ),
99973
+ title: "Selection Pane",
99974
+ children: [
99975
+ /* @__PURE__ */ jsxRuntime.jsx(lu.LuList, { className: ic2 }),
99976
+ "Selection"
99977
+ ]
99978
+ }
99979
+ ),
99980
+ p3.onToggleEyedropper && /* @__PURE__ */ jsxRuntime.jsxs(
99981
+ "button",
99982
+ {
99983
+ type: "button",
99984
+ onClick: p3.onToggleEyedropper,
99985
+ disabled: !p3.canEdit,
99986
+ className: cn(
99987
+ pill,
99988
+ p3.eyedropperActive ? "bg-purple-600 hover:bg-purple-500 text-purple-50" : ""
99989
+ ),
99990
+ title: "Eyedropper \u2014 sample a colour from the slide",
99991
+ children: [
99992
+ /* @__PURE__ */ jsxRuntime.jsx(lu.LuPipette, { className: ic2 }),
99993
+ "Eyedropper"
99994
+ ]
99995
+ }
99996
+ ),
99997
+ /* @__PURE__ */ jsxRuntime.jsx(
99998
+ "button",
99999
+ {
100000
+ onClick: () => p3.onSetShowGrid(!p3.showGrid),
100001
+ className: cn(pill, p3.showGrid ? "bg-primary text-primary-foreground" : ""),
100002
+ title: t2("pptx.grid.toggleGrid"),
100003
+ children: t2("pptx.grid.grid")
100004
+ }
100005
+ ),
100006
+ /* @__PURE__ */ jsxRuntime.jsx(
100007
+ "button",
100008
+ {
100009
+ onClick: () => p3.onSetShowRulers(!p3.showRulers),
100010
+ className: cn(pill, p3.showRulers ? "bg-primary text-primary-foreground" : ""),
100011
+ title: t2("pptx.ruler.toggleRulers"),
100012
+ children: t2("pptx.ruler.rulers")
100013
+ }
100014
+ ),
100015
+ /* @__PURE__ */ jsxRuntime.jsx(
100016
+ "button",
100017
+ {
100018
+ onClick: () => p3.onSetSnapToGrid(!p3.snapToGrid),
100019
+ className: cn(pill, p3.snapToGrid ? "bg-primary text-primary-foreground" : ""),
100020
+ title: t2("pptx.grid.snapToGrid"),
100021
+ children: t2("pptx.grid.snapToGrid")
100022
+ }
100023
+ ),
100024
+ /* @__PURE__ */ jsxRuntime.jsx(
100025
+ "button",
100026
+ {
100027
+ onClick: () => p3.onSetSnapToShape(!p3.snapToShape),
100028
+ className: cn(pill, p3.snapToShape ? "bg-primary text-primary-foreground" : ""),
100029
+ title: t2("pptx.grid.snapToShape"),
100030
+ children: t2("pptx.grid.snapToShape")
100031
+ }
100032
+ ),
100033
+ /* @__PURE__ */ jsxRuntime.jsx("button", { onClick: () => p3.onAddGuide("h"), className: pill, title: "Add horizontal guide", children: "H Guide" }),
100034
+ /* @__PURE__ */ jsxRuntime.jsx("button", { onClick: () => p3.onAddGuide("v"), className: pill, title: "Add vertical guide", children: "V Guide" }),
100035
+ /* @__PURE__ */ jsxRuntime.jsx(
100036
+ "button",
100037
+ {
100038
+ onClick: () => p3.onSetSpellCheckEnabled(!p3.spellCheckEnabled),
100039
+ className: cn(pill, p3.spellCheckEnabled ? "bg-primary text-primary-foreground" : ""),
100040
+ title: "Toggle spell check",
100041
+ children: "Spell"
100042
+ }
100043
+ )
100044
+ ] });
100045
+ }
100046
+ function MobileSheet({
100047
+ open,
100048
+ onClose,
100049
+ title,
100050
+ children,
100051
+ heightFraction = 0.6,
100052
+ fullScreen = false,
100053
+ className,
100054
+ headerRight
100055
+ }) {
100056
+ const sheetRef = React10.useRef(null);
100057
+ const [dragY, setDragY] = React10.useState(0);
100058
+ const dragStartRef = React10.useRef(null);
100059
+ const onPointerDown = React10.useCallback((e2) => {
100060
+ dragStartRef.current = e2.clientY;
100061
+ e2.target.setPointerCapture?.(e2.pointerId);
100062
+ }, []);
100063
+ const onPointerMove = React10.useCallback((e2) => {
100064
+ if (dragStartRef.current === null) {
100065
+ return;
100066
+ }
100067
+ const delta = e2.clientY - dragStartRef.current;
100068
+ setDragY(Math.max(0, delta));
100069
+ }, []);
100070
+ const onPointerUp = React10.useCallback(
100071
+ (e2) => {
100072
+ if (dragStartRef.current === null) {
100073
+ return;
100074
+ }
100075
+ const delta = e2.clientY - dragStartRef.current;
100076
+ dragStartRef.current = null;
100077
+ e2.target.releasePointerCapture?.(e2.pointerId);
100078
+ if (delta > 120) {
100079
+ onClose();
100080
+ }
100081
+ setDragY(0);
100082
+ },
100083
+ [onClose]
100084
+ );
100085
+ React10.useEffect(() => {
100086
+ if (!open) {
100087
+ return;
100088
+ }
100089
+ const handleKey = (e2) => {
100090
+ if (e2.key === "Escape") {
100091
+ onClose();
100092
+ }
100093
+ };
100094
+ window.addEventListener("keydown", handleKey);
100095
+ return () => window.removeEventListener("keydown", handleKey);
100096
+ }, [open, onClose]);
100097
+ if (!open) {
100098
+ return null;
100099
+ }
100100
+ const heightStyle = fullScreen ? { height: "calc(100dvh - env(safe-area-inset-top))" } : { height: `${Math.round(heightFraction * 100)}dvh` };
100101
+ return /* @__PURE__ */ jsxRuntime.jsxs(
100102
+ "div",
100103
+ {
100104
+ className: "fixed inset-0 z-50 flex flex-col justify-end md:hidden",
100105
+ role: "dialog",
100106
+ "aria-modal": "true",
100107
+ children: [
100108
+ /* @__PURE__ */ jsxRuntime.jsx(
100109
+ "button",
100110
+ {
100111
+ type: "button",
100112
+ "aria-label": "Close",
100113
+ className: "absolute inset-0 bg-black/40 backdrop-blur-[2px] animate-in fade-in duration-150",
100114
+ onClick: onClose
100115
+ }
100116
+ ),
100117
+ /* @__PURE__ */ jsxRuntime.jsxs(
100118
+ "div",
100119
+ {
100120
+ ref: sheetRef,
100121
+ className: cn(
100122
+ "relative bg-background border-t border-border rounded-t-2xl shadow-2xl flex flex-col overflow-hidden",
100123
+ "animate-in slide-in-from-bottom duration-200",
100124
+ className
100125
+ ),
100126
+ style: {
100127
+ ...heightStyle,
100128
+ transform: dragY > 0 ? `translateY(${dragY}px)` : void 0,
100129
+ transition: dragStartRef.current === null ? "transform 150ms ease-out" : "none"
100130
+ },
100131
+ children: [
100132
+ /* @__PURE__ */ jsxRuntime.jsx(
100133
+ "div",
100134
+ {
100135
+ className: "flex items-center justify-center pt-2 pb-1 cursor-grab active:cursor-grabbing touch-none",
100136
+ onPointerDown,
100137
+ onPointerMove,
100138
+ onPointerUp,
100139
+ onPointerCancel: onPointerUp,
100140
+ children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "h-1 w-10 rounded-full bg-muted-foreground/40" })
100141
+ }
100142
+ ),
100143
+ (title || headerRight) && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between gap-2 px-4 pb-2 border-b border-border/60", children: [
100144
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-sm font-semibold text-foreground truncate", children: title }),
100145
+ headerRight
100146
+ ] }),
100147
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex-1 overflow-y-auto overscroll-contain", children })
100148
+ ]
100149
+ }
100150
+ )
100151
+ ]
100152
+ }
100153
+ );
100154
+ }
100155
+ var MENU_ITEMS = [
100156
+ { key: "home", label: "Home", icon: lu.LuClipboardCopy },
100157
+ { key: "insert", label: "Insert", icon: lu.LuPlus },
100158
+ { key: "text", label: "Text", icon: lu.LuType },
100159
+ { key: "draw", label: "Draw", icon: lu.LuPaintbrush },
100160
+ { key: "arrange", label: "Arrange", icon: lu.LuShapes },
100161
+ { key: "design", label: "Design", icon: lu.LuLayoutGrid },
100162
+ { key: "transitions", label: "Transitions", icon: lu.LuSparkles },
100163
+ { key: "animations", label: "Animations", icon: lu.LuWand },
100164
+ { key: "slideShow", label: "Slide Show", icon: lu.LuPresentation },
100165
+ { key: "review", label: "Review", icon: lu.LuTextCursorInput },
100166
+ { key: "view", label: "View", icon: lu.LuSettings },
100167
+ { key: "file", label: "File", icon: lu.LuFile }
100168
+ ];
100169
+ function MobileMenuSheet(props) {
100170
+ const { open, onClose } = props;
100171
+ const [active, setActive] = React10.useState("home");
100172
+ return /* @__PURE__ */ jsxRuntime.jsx(MobileSheet, { open, onClose, fullScreen: true, title: "Menu", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col", children: [
100173
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "sticky top-0 z-10 bg-background border-b border-border", children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex gap-1.5 overflow-x-auto px-3 py-2 scrollbar-none", children: MENU_ITEMS.map(({ key, label, icon: Icon }) => /* @__PURE__ */ jsxRuntime.jsxs(
100174
+ "button",
100175
+ {
100176
+ type: "button",
100177
+ onClick: () => setActive(active === key ? null : key),
100178
+ className: cn(
100179
+ "inline-flex items-center gap-1.5 shrink-0 px-3 py-2 rounded-full text-[12px] font-medium border transition-colors min-h-[36px]",
100180
+ active === key ? "bg-primary text-primary-foreground border-primary" : "border-border text-muted-foreground hover:text-foreground hover:bg-accent/40"
100181
+ ),
100182
+ children: [
100183
+ /* @__PURE__ */ jsxRuntime.jsx(Icon, { className: "w-4 h-4" }),
100184
+ label
100185
+ ]
100186
+ },
100187
+ key
100188
+ )) }) }),
100189
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "p-3", children: /* @__PURE__ */ jsxRuntime.jsx(MobileSectionBody, { active, ...props }) })
100190
+ ] }) });
100191
+ }
100192
+ function MobileSectionBody({
100193
+ active,
100194
+ ...p3
100195
+ }) {
100196
+ const wrap = "flex flex-wrap items-center gap-2";
100197
+ switch (active) {
100198
+ case "home":
100199
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { className: wrap, children: /* @__PURE__ */ jsxRuntime.jsx(
100200
+ HomeSection,
100201
+ {
100202
+ canEdit: p3.canEdit,
100203
+ clipboardPayload: p3.clipboardPayload,
100204
+ formatPainterActive: p3.formatPainterActive,
100205
+ canActivateFormatPainter: p3.canActivateFormatPainter,
100206
+ onCopy: p3.onCopy,
100207
+ onCut: p3.onCut,
100208
+ onPaste: p3.onPaste,
100209
+ onToggleFormatPainter: p3.onToggleFormatPainter,
100210
+ layoutOptions: p3.layoutOptions,
100211
+ onInsertSlideFromLayout: p3.onInsertSlideFromLayout,
100212
+ selectedElement: p3.selectedElement,
100213
+ onUpdateTextStyle: p3.onUpdateTextStyle
100214
+ }
100215
+ ) });
100216
+ case "insert":
100217
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { className: wrap, children: /* @__PURE__ */ jsxRuntime.jsx(
100218
+ InsertSection,
100219
+ {
100220
+ canEdit: p3.canEdit,
100221
+ newShapeType: p3.newShapeType,
100222
+ onSetNewShapeType: p3.onSetNewShapeType,
100223
+ onAddTextBox: p3.onAddTextBox,
100224
+ onAddShape: p3.onAddShape,
100225
+ onAddTable: p3.onAddTable,
100226
+ onAddSmartArt: p3.onAddSmartArt,
100227
+ onAddEquation: p3.onAddEquation,
100228
+ onAddActionButton: p3.onAddActionButton,
100229
+ onInsertField: p3.onInsertField,
100230
+ onOpenImagePicker: p3.onOpenImagePicker,
100231
+ onOpenMediaPicker: p3.onOpenMediaPicker
100232
+ }
100233
+ ) });
100234
+ case "text":
100235
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { className: wrap, children: /* @__PURE__ */ jsxRuntime.jsx(
100236
+ TextSection,
100237
+ {
100238
+ canEdit: p3.canEdit,
100239
+ selectedElement: p3.selectedElement,
100240
+ tableEditorState: p3.tableEditorState,
100241
+ onUpdateTextStyle: p3.onUpdateTextStyle
100242
+ }
100243
+ ) });
100244
+ case "draw":
100245
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { className: wrap, children: /* @__PURE__ */ jsxRuntime.jsx(
100246
+ DrawSection,
100247
+ {
100248
+ activeTool: p3.activeTool,
100249
+ drawingColor: p3.drawingColor,
100250
+ drawingWidth: p3.drawingWidth,
100251
+ onSetActiveTool: p3.onSetActiveTool,
100252
+ onSetDrawingColor: p3.onSetDrawingColor,
100253
+ onSetDrawingWidth: p3.onSetDrawingWidth
100254
+ }
100255
+ ) });
100256
+ case "arrange":
100257
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { className: wrap, children: /* @__PURE__ */ jsxRuntime.jsx(
100258
+ ArrangeSection,
100259
+ {
100260
+ canEdit: p3.canEdit,
100261
+ selectedElement: p3.selectedElement,
100262
+ clipboardPayload: p3.clipboardPayload,
100263
+ onAlignElements: p3.onAlignElements,
100264
+ onCopy: p3.onCopy,
100265
+ onCut: p3.onCut,
100266
+ onPaste: p3.onPaste,
100267
+ onFlip: p3.onFlip,
100268
+ onMoveLayer: p3.onMoveLayer,
100269
+ onMoveLayerToEdge: p3.onMoveLayerToEdge,
100270
+ onDuplicate: p3.onDuplicate,
100271
+ onDelete: p3.onDelete,
100272
+ formatPainterActive: p3.formatPainterActive,
100273
+ onToggleFormatPainter: p3.onToggleFormatPainter,
100274
+ canActivateFormatPainter: p3.canActivateFormatPainter
100275
+ }
100276
+ ) });
100277
+ case "design":
100278
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { className: wrap, children: /* @__PURE__ */ jsxRuntime.jsx(
100279
+ DesignSection,
100280
+ {
100281
+ canEdit: p3.canEdit,
100282
+ onToggleThemeGallery: p3.onToggleThemeGallery,
100283
+ isThemeGalleryOpen: p3.isThemeGalleryOpen,
100284
+ onToggleThemeEditor: p3.onToggleThemeEditor,
100285
+ isThemeEditorOpen: p3.isThemeEditorOpen,
100286
+ onOpenDocumentProperties: p3.onOpenDocumentProperties,
100287
+ onToggleInspector: p3.onToggleInspector,
100288
+ isInspectorPaneOpen: p3.isInspectorPaneOpen
100289
+ }
100290
+ ) });
100291
+ case "transitions":
100292
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { className: wrap, children: /* @__PURE__ */ jsxRuntime.jsx(
100293
+ TransitionsSection,
100294
+ {
100295
+ isInspectorPaneOpen: p3.isInspectorPaneOpen,
100296
+ onToggleInspector: p3.onToggleInspector
100297
+ }
100298
+ ) });
100299
+ case "animations":
100300
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { className: wrap, children: /* @__PURE__ */ jsxRuntime.jsx(
100301
+ AnimationsSection,
100302
+ {
100303
+ canEdit: p3.canEdit,
100304
+ selectedElement: p3.selectedElement,
100305
+ isInspectorPaneOpen: p3.isInspectorPaneOpen,
100306
+ onToggleInspector: p3.onToggleInspector,
100307
+ onOpenAnimationPanel: p3.onOpenAnimationPanel,
100308
+ onAddAnimation: p3.onAddAnimation,
100309
+ onRemoveAnimation: p3.onRemoveAnimation
100310
+ }
100311
+ ) });
100312
+ case "slideShow":
100313
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { className: wrap, children: /* @__PURE__ */ jsxRuntime.jsx(
100314
+ SlideShowSection,
100315
+ {
100316
+ onPresent: () => p3.onSetMode("present"),
100317
+ onEnterPresenterView: p3.onEnterPresenterView ?? (() => {
100318
+ }),
100319
+ onEnterRehearsalMode: p3.onEnterRehearsalMode ?? (() => {
100320
+ }),
100321
+ onOpenSetUpSlideShow: p3.onOpenSetUpSlideShow ?? (() => {
100322
+ }),
100323
+ onOpenBroadcastDialog: p3.onOpenBroadcastDialog ?? (() => {
100324
+ }),
100325
+ onToggleSubtitles: p3.onToggleSubtitles ?? (() => {
100326
+ }),
100327
+ showSubtitles: p3.showSubtitles ?? false,
100328
+ onSetMode: p3.onSetMode
100329
+ }
100330
+ ) });
100331
+ case "review":
100332
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { className: wrap, children: /* @__PURE__ */ jsxRuntime.jsx(
100333
+ ReviewSection,
100334
+ {
100335
+ canEdit: p3.canEdit,
100336
+ spellCheckEnabled: p3.spellCheckEnabled,
100337
+ onSetSpellCheckEnabled: p3.onSetSpellCheckEnabled,
100338
+ onToggleComments: p3.onToggleComments,
100339
+ isCommentsPanelOpen: p3.isCommentsPanelOpen,
100340
+ slideCommentCount: p3.slideCommentCount,
100341
+ onCompare: p3.onCompare
100342
+ }
100343
+ ) });
100344
+ case "view":
100345
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { className: wrap, children: /* @__PURE__ */ jsxRuntime.jsx(
100346
+ ViewSection,
100347
+ {
100348
+ canEdit: p3.canEdit,
100349
+ editTemplateMode: p3.editTemplateMode,
100350
+ onSetEditTemplateMode: p3.onSetEditTemplateMode,
100351
+ spellCheckEnabled: p3.spellCheckEnabled,
100352
+ onSetSpellCheckEnabled: p3.onSetSpellCheckEnabled,
100353
+ showGrid: p3.showGrid,
100354
+ showRulers: p3.showRulers,
100355
+ snapToGrid: p3.snapToGrid,
100356
+ snapToShape: p3.snapToShape,
100357
+ onSetShowGrid: p3.onSetShowGrid,
100358
+ onSetShowRulers: p3.onSetShowRulers,
100359
+ onSetSnapToGrid: p3.onSetSnapToGrid,
100360
+ onSetSnapToShape: p3.onSetSnapToShape,
100361
+ onAddGuide: p3.onAddGuide,
100362
+ onEnterMasterView: p3.onEnterMasterView,
100363
+ isSelectionPaneOpen: p3.isSelectionPaneOpen,
100364
+ onToggleSelectionPane: p3.onToggleSelectionPane,
100365
+ eyedropperActive: p3.eyedropperActive,
100366
+ onToggleEyedropper: p3.onToggleEyedropper
100367
+ }
100368
+ ) });
100369
+ case "file":
100370
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { className: wrap, children: /* @__PURE__ */ jsxRuntime.jsx(
100371
+ FileSection,
100372
+ {
100373
+ onExportPng: p3.onExportPng,
100374
+ onExportPdf: p3.onExportPdf,
100375
+ onExportVideo: p3.onExportVideo,
100376
+ onExportGif: p3.onExportGif,
100377
+ onPackageForSharing: p3.onPackageForSharing,
100378
+ onSaveAsPptx: p3.onSaveAsPptx,
100379
+ onSaveAsPpsx: p3.onSaveAsPpsx,
100380
+ onSaveAsPptm: p3.onSaveAsPptm,
100381
+ hasMacros: p3.hasMacros,
100382
+ onCopySlideAsImage: p3.onCopySlideAsImage,
100383
+ onPrint: p3.onPrint,
100384
+ onOpenDocumentProperties: p3.onOpenDocumentProperties,
100385
+ onOpenPasswordProtection: p3.onOpenPasswordProtection,
100386
+ onOpenFontEmbedding: p3.onOpenFontEmbedding,
100387
+ onOpenDigitalSignatures: p3.onOpenDigitalSignatures
100388
+ }
100389
+ ) });
100390
+ default:
100391
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "text-center text-sm text-muted-foreground py-8", children: [
100392
+ /* @__PURE__ */ jsxRuntime.jsx(lu.LuChevronRight, { className: "w-5 h-5 inline-block opacity-50" }),
100393
+ " Select a section above"
100394
+ ] });
100395
+ }
100396
+ }
100397
+ function MobileToolbar(props) {
100398
+ const { t: t2 } = reactI18next.useTranslation();
100399
+ const { mode, canUndo, canRedo, onUndo, onRedo, onSetMode } = props;
100400
+ const [menuOpen, setMenuOpen] = React10.useState(false);
100401
+ const showEdit = mode === "edit" || mode === "master";
100402
+ const btn = "inline-flex items-center justify-center min-w-[44px] min-h-[44px] rounded-md text-foreground/80 hover:bg-accent/60 disabled:opacity-40 disabled:cursor-not-allowed active:scale-95 transition-transform";
100403
+ return /* @__PURE__ */ jsxRuntime.jsxs(
100404
+ "div",
100405
+ {
100406
+ role: "toolbar",
100407
+ "aria-label": "Toolbar",
100408
+ className: "relative z-20 flex items-center gap-1 px-2 py-1 border-b border-border bg-secondary/50 min-h-[52px] pt-[max(env(safe-area-inset-top),0px)]",
100409
+ children: [
100410
+ showEdit && /* @__PURE__ */ jsxRuntime.jsx(
100411
+ "button",
100412
+ {
100413
+ type: "button",
100414
+ onClick: () => setMenuOpen(true),
100415
+ className: btn,
100416
+ title: "Menu",
100417
+ "aria-label": "Menu",
100418
+ children: /* @__PURE__ */ jsxRuntime.jsx(lu.LuMenu, { className: "w-5 h-5" })
100419
+ }
100420
+ ),
100421
+ showEdit && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
100422
+ /* @__PURE__ */ jsxRuntime.jsx(
100423
+ "button",
100424
+ {
100425
+ type: "button",
100426
+ onClick: onUndo,
100427
+ disabled: !canUndo,
100428
+ className: btn,
100429
+ title: t2("pptx.toolbar.undo"),
100430
+ "aria-label": t2("pptx.toolbar.undo"),
100431
+ children: /* @__PURE__ */ jsxRuntime.jsx(lu.LuUndo, { className: "w-5 h-5" })
100432
+ }
100433
+ ),
100434
+ /* @__PURE__ */ jsxRuntime.jsx(
100435
+ "button",
100436
+ {
100437
+ type: "button",
100438
+ onClick: onRedo,
100439
+ disabled: !canRedo,
100440
+ className: btn,
100441
+ title: t2("pptx.toolbar.redo"),
100442
+ "aria-label": t2("pptx.toolbar.redo"),
100443
+ children: /* @__PURE__ */ jsxRuntime.jsx(lu.LuRedo, { className: "w-5 h-5" })
100444
+ }
100445
+ )
100446
+ ] }),
100447
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex-1" }),
100448
+ /* @__PURE__ */ jsxRuntime.jsx(
100449
+ "button",
100450
+ {
100451
+ type: "button",
100452
+ onClick: () => onSetMode("present"),
100453
+ className: cn(btn, "text-primary"),
100454
+ title: t2("pptx.toolbar.present"),
100455
+ "aria-label": t2("pptx.toolbar.present"),
100456
+ children: /* @__PURE__ */ jsxRuntime.jsx(lu.LuPresentation, { className: "w-5 h-5" })
100457
+ }
100458
+ ),
100459
+ showEdit && /* @__PURE__ */ jsxRuntime.jsx(
100460
+ "button",
100461
+ {
100462
+ type: "button",
100463
+ onClick: props.onOpenShareDialog ?? props.onPackageForSharing,
100464
+ className: cn(btn, "bg-primary text-primary-foreground hover:bg-primary/90 px-3"),
100465
+ title: t2("pptx.toolbar.share"),
100466
+ "aria-label": t2("pptx.toolbar.share"),
100467
+ children: /* @__PURE__ */ jsxRuntime.jsx(lu.LuShare2, { className: "w-4 h-4" })
100468
+ }
100469
+ ),
100470
+ /* @__PURE__ */ jsxRuntime.jsx(MobileMenuSheet, { open: menuOpen, onClose: () => setMenuOpen(false), ...props })
100471
+ ]
100472
+ }
100473
+ );
100474
+ }
99892
100475
  function CustomShowsControls({
99893
100476
  customShows,
99894
100477
  activeCustomShowId,
@@ -100317,7 +100900,7 @@ function ToolbarPrimaryRow(p3) {
100317
100900
  onClick: p3.onToggleComments,
100318
100901
  className: cn(
100319
100902
  qab,
100320
- "max-md:hidden",
100903
+ "relative max-md:hidden",
100321
100904
  p3.isCommentsPanelOpen ? "text-foreground" : "text-muted-foreground"
100322
100905
  ),
100323
100906
  title: t2("pptx.toolbar.comments"),
@@ -100433,134 +101016,11 @@ function ToolbarPrimaryRow(p3) {
100433
101016
  /* @__PURE__ */ jsxRuntime.jsx(OverflowMenu, { ...p3 })
100434
101017
  ] });
100435
101018
  }
100436
- function ViewSection(p3) {
100437
- const { t: t2 } = reactI18next.useTranslation();
100438
- return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
100439
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col items-center gap-0.5", children: [
100440
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-0.5", children: [
100441
- /* @__PURE__ */ jsxRuntime.jsx("button", { className: pill, title: "Normal view", children: "Normal" }),
100442
- p3.onToggleSlideSorter ? /* @__PURE__ */ jsxRuntime.jsx("button", { className: pill, onClick: p3.onToggleSlideSorter, title: "Slide Sorter view", children: "Slide Sorter" }) : /* @__PURE__ */ jsxRuntime.jsx("button", { className: pill, title: "Slide Sorter view", children: "Slide Sorter" }),
100443
- /* @__PURE__ */ jsxRuntime.jsx("button", { className: pill, title: "Reading View", children: "Reading View" })
100444
- ] }),
100445
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-[9px] text-muted-foreground leading-none", children: "Presentation Views" })
100446
- ] }),
100447
- sep,
100448
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col items-center gap-0.5", children: [
100449
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex items-center gap-0.5", children: /* @__PURE__ */ jsxRuntime.jsx(
100450
- "button",
100451
- {
100452
- onClick: p3.onEnterMasterView,
100453
- disabled: !p3.canEdit,
100454
- className: pill,
100455
- title: "Edit slide masters and layouts",
100456
- children: "Slide Master"
100457
- }
100458
- ) }),
100459
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-[9px] text-muted-foreground leading-none", children: "Master Views" })
100460
- ] }),
100461
- sep,
100462
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col items-center gap-0.5", children: [
100463
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex items-center gap-0.5", children: p3.onZoomToFit && /* @__PURE__ */ jsxRuntime.jsx("button", { className: pill, onClick: p3.onZoomToFit, title: "Zoom to fit slide in window", children: "Zoom to Fit" }) }),
100464
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-[9px] text-muted-foreground leading-none", children: "Zoom" })
100465
- ] }),
100466
- sep,
100467
- /* @__PURE__ */ jsxRuntime.jsx(
100468
- "button",
100469
- {
100470
- onClick: () => p3.onSetEditTemplateMode(!p3.editTemplateMode),
100471
- disabled: !p3.canEdit,
100472
- className: cn(
100473
- pill,
100474
- p3.editTemplateMode ? "bg-amber-600 hover:bg-amber-500 text-amber-50" : ""
100475
- ),
100476
- title: "Toggle template/master element editing",
100477
- children: p3.editTemplateMode ? "Templates On" : "Templates Off"
100478
- }
100479
- ),
100480
- p3.onToggleSelectionPane && /* @__PURE__ */ jsxRuntime.jsxs(
100481
- "button",
100482
- {
100483
- type: "button",
100484
- onClick: p3.onToggleSelectionPane,
100485
- className: cn(
100486
- pill,
100487
- p3.isSelectionPaneOpen ? "bg-primary hover:bg-primary/80 text-primary-foreground" : ""
100488
- ),
100489
- title: "Selection Pane",
100490
- children: [
100491
- /* @__PURE__ */ jsxRuntime.jsx(lu.LuList, { className: ic2 }),
100492
- "Selection"
100493
- ]
100494
- }
100495
- ),
100496
- p3.onToggleEyedropper && /* @__PURE__ */ jsxRuntime.jsxs(
100497
- "button",
100498
- {
100499
- type: "button",
100500
- onClick: p3.onToggleEyedropper,
100501
- disabled: !p3.canEdit,
100502
- className: cn(
100503
- pill,
100504
- p3.eyedropperActive ? "bg-purple-600 hover:bg-purple-500 text-purple-50" : ""
100505
- ),
100506
- title: "Eyedropper \u2014 sample a colour from the slide",
100507
- children: [
100508
- /* @__PURE__ */ jsxRuntime.jsx(lu.LuPipette, { className: ic2 }),
100509
- "Eyedropper"
100510
- ]
100511
- }
100512
- ),
100513
- /* @__PURE__ */ jsxRuntime.jsx(
100514
- "button",
100515
- {
100516
- onClick: () => p3.onSetShowGrid(!p3.showGrid),
100517
- className: cn(pill, p3.showGrid ? "bg-primary text-primary-foreground" : ""),
100518
- title: t2("pptx.grid.toggleGrid"),
100519
- children: t2("pptx.grid.grid")
100520
- }
100521
- ),
100522
- /* @__PURE__ */ jsxRuntime.jsx(
100523
- "button",
100524
- {
100525
- onClick: () => p3.onSetShowRulers(!p3.showRulers),
100526
- className: cn(pill, p3.showRulers ? "bg-primary text-primary-foreground" : ""),
100527
- title: t2("pptx.ruler.toggleRulers"),
100528
- children: t2("pptx.ruler.rulers")
100529
- }
100530
- ),
100531
- /* @__PURE__ */ jsxRuntime.jsx(
100532
- "button",
100533
- {
100534
- onClick: () => p3.onSetSnapToGrid(!p3.snapToGrid),
100535
- className: cn(pill, p3.snapToGrid ? "bg-primary text-primary-foreground" : ""),
100536
- title: t2("pptx.grid.snapToGrid"),
100537
- children: t2("pptx.grid.snapToGrid")
100538
- }
100539
- ),
100540
- /* @__PURE__ */ jsxRuntime.jsx(
100541
- "button",
100542
- {
100543
- onClick: () => p3.onSetSnapToShape(!p3.snapToShape),
100544
- className: cn(pill, p3.snapToShape ? "bg-primary text-primary-foreground" : ""),
100545
- title: t2("pptx.grid.snapToShape"),
100546
- children: t2("pptx.grid.snapToShape")
100547
- }
100548
- ),
100549
- /* @__PURE__ */ jsxRuntime.jsx("button", { onClick: () => p3.onAddGuide("h"), className: pill, title: "Add horizontal guide", children: "H Guide" }),
100550
- /* @__PURE__ */ jsxRuntime.jsx("button", { onClick: () => p3.onAddGuide("v"), className: pill, title: "Add vertical guide", children: "V Guide" }),
100551
- /* @__PURE__ */ jsxRuntime.jsx(
100552
- "button",
100553
- {
100554
- onClick: () => p3.onSetSpellCheckEnabled(!p3.spellCheckEnabled),
100555
- className: cn(pill, p3.spellCheckEnabled ? "bg-primary text-primary-foreground" : ""),
100556
- title: "Toggle spell check",
100557
- children: "Spell"
100558
- }
100559
- )
100560
- ] });
100561
- }
100562
101019
  function Toolbar(p3) {
100563
101020
  const { mode, isNarrowViewport, isCompactToolbarOpen, toolbarSection, onSetToolbarSection } = p3;
101021
+ if (isNarrowViewport && mode !== "present") {
101022
+ return /* @__PURE__ */ jsxRuntime.jsx(MobileToolbar, { ...p3 });
101023
+ }
100564
101024
  const sFil = toolbarSection === "file";
100565
101025
  const sHome = toolbarSection === "home";
100566
101026
  const sIns = toolbarSection === "insert";
@@ -100646,6 +101106,7 @@ function Toolbar(p3) {
100646
101106
  canEdit: p3.canEdit,
100647
101107
  clipboardPayload: p3.clipboardPayload,
100648
101108
  formatPainterActive: p3.formatPainterActive,
101109
+ canActivateFormatPainter: p3.canActivateFormatPainter,
100649
101110
  onCopy: p3.onCopy,
100650
101111
  onCut: p3.onCut,
100651
101112
  onPaste: p3.onPaste,
@@ -100709,7 +101170,8 @@ function Toolbar(p3) {
100709
101170
  onDuplicate: p3.onDuplicate,
100710
101171
  onDelete: p3.onDelete,
100711
101172
  formatPainterActive: p3.formatPainterActive,
100712
- onToggleFormatPainter: p3.onToggleFormatPainter
101173
+ onToggleFormatPainter: p3.onToggleFormatPainter,
101174
+ canActivateFormatPainter: p3.canActivateFormatPainter
100713
101175
  }
100714
101176
  ),
100715
101177
  sDes && /* @__PURE__ */ jsxRuntime.jsx(
@@ -106422,181 +106884,194 @@ function InspectorPane(props) {
106422
106884
  const fallback = themeOptions[0]?.path ?? "";
106423
106885
  setSelectedThemePath((previous) => previous || fallback);
106424
106886
  }, [slideMasters, themeOptions]);
106425
- return /* @__PURE__ */ jsxRuntime.jsxs(
106426
- "div",
106427
- {
106428
- className: cn(
106429
- // Shared styles
106430
- "bg-background flex flex-col text-xs text-foreground shadow-xl",
106431
- // Mobile: absolute bottom sheet overlay
106432
- "max-md:fixed max-md:inset-x-0 max-md:bottom-0 max-md:top-auto max-md:w-full max-md:max-h-[60vh] max-md:rounded-t-xl max-md:border-t max-md:border-border max-md:z-30",
106433
- "max-md:transition-transform max-md:duration-200 max-md:ease-in-out",
106434
- isOpen ? "max-md:translate-y-0" : "max-md:translate-y-full",
106435
- // Desktop: flow-based flex child (takes space from canvas)
106436
- "md:h-full md:border-l md:border-border",
106437
- !panelWidth && "md:w-72"
106438
- ),
106439
- style: panelWidth ? { width: panelWidth } : void 0,
106440
- children: [
106441
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between gap-2 px-3 py-2 border-b border-border", children: [
106442
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex items-center gap-1 rounded bg-muted p-0.5", children: INSPECTOR_TABS.map(({ key, label, icon: Icon }) => /* @__PURE__ */ jsxRuntime.jsxs(
106443
- "button",
106444
- {
106445
- type: "button",
106446
- title: label,
106447
- className: cn(
106448
- "flex items-center gap-1 px-2 py-1 rounded text-[11px] transition-colors",
106449
- activeTab === key ? "bg-primary text-primary-foreground" : "text-muted-foreground hover:text-foreground hover:bg-accent"
106450
- ),
106451
- onClick: () => onSetActiveTab(key),
106452
- children: [
106453
- /* @__PURE__ */ jsxRuntime.jsx(Icon, { className: "w-3.5 h-3.5" }),
106454
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "hidden sm:inline", children: label })
106455
- ]
106456
- },
106457
- key
106458
- )) }),
106459
- /* @__PURE__ */ jsxRuntime.jsx(
106460
- "button",
106461
- {
106462
- type: "button",
106463
- onClick: onClose,
106464
- title: t2("common.close"),
106465
- className: "p-1 rounded text-muted-foreground hover:text-foreground hover:bg-muted transition-colors",
106466
- children: /* @__PURE__ */ jsxRuntime.jsx(lu.LuX, { className: "w-4 h-4" })
106467
- }
106468
- )
106469
- ] }),
106470
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex-1 overflow-y-auto p-3 space-y-3", children: [
106471
- activeTab === "elements" && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-1", children: [
106472
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: cn(HEADING, "mb-2"), children: t2("pptx.inspector.layerOrder") }),
106473
- activeSlide ? [...activeSlide.elements || []].reverse().map((el, ri) => {
106474
- const idx = (activeSlide.elements || []).length - 1 - ri;
106475
- const sel = selectedElement?.id === el.id || selectedElementIds.includes(el.id);
106476
- const label = (pptxViewerCore.hasTextProperties(el) ? (el.text || "").slice(0, 24) : void 0) || el.type;
106477
- return /* @__PURE__ */ jsxRuntime.jsxs(
106478
- "div",
106479
- {
106480
- title: `${el.type} \u2014 ${el.id}`,
106481
- className: cn(
106482
- "flex items-center gap-2 px-2 py-1 rounded cursor-pointer transition-colors",
106483
- sel ? "bg-primary/30 text-primary" : "hover:bg-muted text-foreground"
106484
- ),
106485
- onClick: () => onSelectElement(el.id),
106486
- children: [
106487
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-muted-foreground w-4 text-right", children: idx + 1 }),
106488
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "flex-1 truncate", children: label })
106489
- ]
106490
- },
106491
- el.id
106492
- );
106493
- }) : /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-muted-foreground italic", children: t2("pptx.inspector.noSlideSelected") })
106494
- ] }),
106495
- activeTab === "properties" && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "space-y-3", children: hasSelection && selectedElement ? /* @__PURE__ */ jsxRuntime.jsx(
106496
- ElementInspectorBody,
106497
- {
106498
- selectedElement,
106499
- canEdit,
106500
- slides,
106501
- tableEditorState,
106502
- mediaDataUrls,
106503
- onUpdateElement,
106504
- onUpdateElementStyle,
106505
- onUpdateTextStyle,
106506
- onMoveLayer
106507
- }
106508
- ) : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
106887
+ return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
106888
+ isOpen && /* @__PURE__ */ jsxRuntime.jsx(
106889
+ "button",
106890
+ {
106891
+ type: "button",
106892
+ "aria-label": t2("common.close"),
106893
+ onClick: onClose,
106894
+ className: "md:hidden fixed inset-0 z-20 bg-black/40 backdrop-blur-[2px] animate-in fade-in duration-150"
106895
+ }
106896
+ ),
106897
+ /* @__PURE__ */ jsxRuntime.jsxs(
106898
+ "div",
106899
+ {
106900
+ className: cn(
106901
+ // Shared styles
106902
+ "bg-background flex flex-col text-xs text-foreground shadow-xl",
106903
+ // Mobile: absolute bottom sheet overlay sized via dvh so it
106904
+ // adapts to the on-screen keyboard / dynamic browser chrome.
106905
+ "max-md:fixed max-md:inset-x-0 max-md:bottom-0 max-md:top-auto max-md:w-full max-md:max-h-[75dvh] max-md:rounded-t-2xl max-md:border-t max-md:border-border max-md:z-30 max-md:pb-[max(env(safe-area-inset-bottom),0px)]",
106906
+ "max-md:transition-transform max-md:duration-200 max-md:ease-in-out",
106907
+ isOpen ? "max-md:translate-y-0" : "max-md:translate-y-full",
106908
+ // Desktop: flow-based flex child (takes space from canvas)
106909
+ "md:h-full md:border-l md:border-border",
106910
+ !panelWidth && "md:w-72"
106911
+ ),
106912
+ style: panelWidth ? { width: panelWidth } : void 0,
106913
+ children: [
106914
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "md:hidden flex items-center justify-center pt-2 pb-1", children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "h-1 w-10 rounded-full bg-muted-foreground/40" }) }),
106915
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between gap-2 px-3 py-2 border-b border-border", children: [
106916
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex items-center gap-1 rounded bg-muted p-0.5", children: INSPECTOR_TABS.map(({ key, label, icon: Icon }) => /* @__PURE__ */ jsxRuntime.jsxs(
106917
+ "button",
106918
+ {
106919
+ type: "button",
106920
+ title: label,
106921
+ className: cn(
106922
+ "flex items-center gap-1 px-2 py-1 rounded text-[11px] transition-colors",
106923
+ activeTab === key ? "bg-primary text-primary-foreground" : "text-muted-foreground hover:text-foreground hover:bg-accent"
106924
+ ),
106925
+ onClick: () => onSetActiveTab(key),
106926
+ children: [
106927
+ /* @__PURE__ */ jsxRuntime.jsx(Icon, { className: "w-3.5 h-3.5" }),
106928
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "hidden sm:inline", children: label })
106929
+ ]
106930
+ },
106931
+ key
106932
+ )) }),
106509
106933
  /* @__PURE__ */ jsxRuntime.jsx(
106510
- PresentationPropertiesPanel,
106934
+ "button",
106511
106935
  {
106512
- canEdit,
106513
- canvasSize,
106514
- presentationProperties,
106515
- onUpdatePresentationProperties,
106516
- notesMaster,
106517
- handoutMaster,
106518
- notesCanvasSize,
106519
- coreProperties,
106520
- appProperties,
106521
- customProperties,
106522
- themeOptions,
106523
- selectedThemePath,
106524
- setSelectedThemePath,
106525
- onApplyTheme,
106526
- onUpdateCoreProperties,
106527
- onUpdateAppProperties,
106528
- onUpdateCustomProperties,
106529
- tagCollections,
106530
- onUpdateTagCollections,
106531
- onUpdateCanvasSize,
106532
- activeSlide,
106533
- theme,
106534
- onUpdateSlide
106936
+ type: "button",
106937
+ onClick: onClose,
106938
+ title: t2("common.close"),
106939
+ className: "p-1 rounded text-muted-foreground hover:text-foreground hover:bg-muted transition-colors",
106940
+ children: /* @__PURE__ */ jsxRuntime.jsx(lu.LuX, { className: "w-4 h-4" })
106535
106941
  }
106536
- ),
106537
- activeSlide && /* @__PURE__ */ jsxRuntime.jsx(
106538
- SlideBackgroundPanel,
106942
+ )
106943
+ ] }),
106944
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex-1 overflow-y-auto p-3 space-y-3", children: [
106945
+ activeTab === "elements" && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-1", children: [
106946
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: cn(HEADING, "mb-2"), children: t2("pptx.inspector.layerOrder") }),
106947
+ activeSlide ? [...activeSlide.elements || []].reverse().map((el, ri) => {
106948
+ const idx = (activeSlide.elements || []).length - 1 - ri;
106949
+ const sel = selectedElement?.id === el.id || selectedElementIds.includes(el.id);
106950
+ const label = (pptxViewerCore.hasTextProperties(el) ? (el.text || "").slice(0, 24) : void 0) || el.type;
106951
+ return /* @__PURE__ */ jsxRuntime.jsxs(
106952
+ "div",
106953
+ {
106954
+ title: `${el.type} \u2014 ${el.id}`,
106955
+ className: cn(
106956
+ "flex items-center gap-2 px-2 py-1 rounded cursor-pointer transition-colors",
106957
+ sel ? "bg-primary/30 text-primary" : "hover:bg-muted text-foreground"
106958
+ ),
106959
+ onClick: () => onSelectElement(el.id),
106960
+ children: [
106961
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-muted-foreground w-4 text-right", children: idx + 1 }),
106962
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "flex-1 truncate", children: label })
106963
+ ]
106964
+ },
106965
+ el.id
106966
+ );
106967
+ }) : /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-muted-foreground italic", children: t2("pptx.inspector.noSlideSelected") })
106968
+ ] }),
106969
+ activeTab === "properties" && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "space-y-3", children: hasSelection && selectedElement ? /* @__PURE__ */ jsxRuntime.jsx(
106970
+ ElementInspectorBody,
106539
106971
  {
106540
- activeSlide,
106972
+ selectedElement,
106541
106973
  canEdit,
106542
- onUpdateSlide,
106543
- editTemplateMode,
106544
- slideMasters,
106545
- onSetTemplateBackground,
106546
- onGetTemplateBackgroundColor
106974
+ slides,
106975
+ tableEditorState,
106976
+ mediaDataUrls,
106977
+ onUpdateElement,
106978
+ onUpdateElementStyle,
106979
+ onUpdateTextStyle,
106980
+ onMoveLayer
106547
106981
  }
106548
- )
106549
- ] }) }),
106550
- activeTab === "comments" && /* @__PURE__ */ jsxRuntime.jsx(
106551
- InspectorCommentsSection,
106552
- {
106553
- comments,
106554
- canEdit,
106555
- activeSlide,
106556
- selectedElement,
106557
- editingCommentId,
106558
- commentEditDraft,
106559
- commentDraft,
106560
- replyingToCommentId: replyingToCommentId ?? null,
106561
- replyDraftByCommentId: replyDraftByCommentId ?? {},
106562
- onSetCommentDraft,
106563
- onAddComment,
106564
- onDeleteComment,
106565
- onStartEditComment,
106566
- onSaveEditComment,
106567
- onCancelEditComment,
106568
- onSetCommentEditDraft,
106569
- onToggleCommentResolved,
106570
- onStartReply,
106571
- onCancelReply,
106572
- onReplyDraftChange,
106573
- onSubmitReply,
106574
- onSelectElement
106575
- }
106576
- )
106577
- ] }),
106578
- hasSelection && selectedElement && activeSlide && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
106579
- /* @__PURE__ */ jsxRuntime.jsx(ResizeHandle, { direction: "vertical", onResize: onResizeAnim }),
106580
- /* @__PURE__ */ jsxRuntime.jsx(
106581
- "div",
106582
- {
106583
- className: "border-t border-border p-3 overflow-y-auto flex-shrink-0",
106584
- style: { height: animPanelHeight },
106585
- children: /* @__PURE__ */ jsxRuntime.jsx(
106586
- AnimationPanel,
106982
+ ) : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
106983
+ /* @__PURE__ */ jsxRuntime.jsx(
106984
+ PresentationPropertiesPanel,
106587
106985
  {
106588
- selectedElement,
106589
- activeSlide,
106590
106986
  canEdit,
106987
+ canvasSize,
106988
+ presentationProperties,
106989
+ onUpdatePresentationProperties,
106990
+ notesMaster,
106991
+ handoutMaster,
106992
+ notesCanvasSize,
106993
+ coreProperties,
106994
+ appProperties,
106995
+ customProperties,
106996
+ themeOptions,
106997
+ selectedThemePath,
106998
+ setSelectedThemePath,
106999
+ onApplyTheme,
107000
+ onUpdateCoreProperties,
107001
+ onUpdateAppProperties,
107002
+ onUpdateCustomProperties,
107003
+ tagCollections,
107004
+ onUpdateTagCollections,
107005
+ onUpdateCanvasSize,
107006
+ activeSlide,
107007
+ theme,
106591
107008
  onUpdateSlide
106592
107009
  }
107010
+ ),
107011
+ activeSlide && /* @__PURE__ */ jsxRuntime.jsx(
107012
+ SlideBackgroundPanel,
107013
+ {
107014
+ activeSlide,
107015
+ canEdit,
107016
+ onUpdateSlide,
107017
+ editTemplateMode,
107018
+ slideMasters,
107019
+ onSetTemplateBackground,
107020
+ onGetTemplateBackgroundColor
107021
+ }
106593
107022
  )
106594
- }
106595
- )
106596
- ] })
106597
- ]
106598
- }
106599
- );
107023
+ ] }) }),
107024
+ activeTab === "comments" && /* @__PURE__ */ jsxRuntime.jsx(
107025
+ InspectorCommentsSection,
107026
+ {
107027
+ comments,
107028
+ canEdit,
107029
+ activeSlide,
107030
+ selectedElement,
107031
+ editingCommentId,
107032
+ commentEditDraft,
107033
+ commentDraft,
107034
+ replyingToCommentId: replyingToCommentId ?? null,
107035
+ replyDraftByCommentId: replyDraftByCommentId ?? {},
107036
+ onSetCommentDraft,
107037
+ onAddComment,
107038
+ onDeleteComment,
107039
+ onStartEditComment,
107040
+ onSaveEditComment,
107041
+ onCancelEditComment,
107042
+ onSetCommentEditDraft,
107043
+ onToggleCommentResolved,
107044
+ onStartReply,
107045
+ onCancelReply,
107046
+ onReplyDraftChange,
107047
+ onSubmitReply,
107048
+ onSelectElement
107049
+ }
107050
+ )
107051
+ ] }),
107052
+ hasSelection && selectedElement && activeSlide && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
107053
+ /* @__PURE__ */ jsxRuntime.jsx(ResizeHandle, { direction: "vertical", onResize: onResizeAnim }),
107054
+ /* @__PURE__ */ jsxRuntime.jsx(
107055
+ "div",
107056
+ {
107057
+ className: "border-t border-border p-3 overflow-y-auto flex-shrink-0",
107058
+ style: { height: animPanelHeight },
107059
+ children: /* @__PURE__ */ jsxRuntime.jsx(
107060
+ AnimationPanel,
107061
+ {
107062
+ selectedElement,
107063
+ activeSlide,
107064
+ canEdit,
107065
+ onUpdateSlide
107066
+ }
107067
+ )
107068
+ }
107069
+ )
107070
+ ] })
107071
+ ]
107072
+ }
107073
+ )
107074
+ ] });
106600
107075
  }
106601
107076
  function buildPathD(points) {
106602
107077
  if (points.length === 0) {
@@ -110730,7 +111205,8 @@ function ViewerBottomPanels({
110730
111205
  onZoomToFit,
110731
111206
  mode,
110732
111207
  onSetMode,
110733
- onToggleSlideSorter
111208
+ onToggleSlideSorter,
111209
+ hideStatusBar = false
110734
111210
  }) {
110735
111211
  return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
110736
111212
  onResizeBottom && !isSlideNotesCollapsed && /* @__PURE__ */ jsxRuntime.jsx(ResizeHandle, { direction: "vertical", onResize: onResizeBottom }),
@@ -110746,7 +111222,7 @@ function ViewerBottomPanels({
110746
111222
  panelHeight: notesPanelHeight
110747
111223
  }
110748
111224
  ),
110749
- /* @__PURE__ */ jsxRuntime.jsx(
111225
+ !hideStatusBar && /* @__PURE__ */ jsxRuntime.jsx(
110750
111226
  StatusBar,
110751
111227
  {
110752
111228
  slideCount,
@@ -110903,6 +111379,45 @@ function ViewerInspector({
110903
111379
  }
110904
111380
  );
110905
111381
  }
111382
+
111383
+ // src/viewer/hooks/useScopedLayoutOptions.ts
111384
+ function scopeLayoutOptionsToActiveSlide(options, activeSlide) {
111385
+ if (!activeSlide?.layoutPath) {
111386
+ return options;
111387
+ }
111388
+ const hasAnyMasterInfo = options.some((o3) => o3.masterPath);
111389
+ if (!hasAnyMasterInfo) {
111390
+ return options;
111391
+ }
111392
+ const activeOption = options.find((o3) => o3.path === activeSlide.layoutPath);
111393
+ const activeMaster = activeOption?.masterPath;
111394
+ if (!activeMaster) {
111395
+ return options;
111396
+ }
111397
+ const scoped = options.filter((o3) => o3.masterPath === activeMaster);
111398
+ const seen = /* @__PURE__ */ new Map();
111399
+ for (const opt of scoped) {
111400
+ const isActive = opt.path === activeSlide.layoutPath;
111401
+ const existing = seen.get(opt.name);
111402
+ if (!existing || isActive) {
111403
+ seen.set(opt.name, opt);
111404
+ }
111405
+ }
111406
+ const chosen = new Set(Array.from(seen.values()).map((o3) => o3.path));
111407
+ const result = [];
111408
+ const usedNames = /* @__PURE__ */ new Set();
111409
+ for (const opt of scoped) {
111410
+ if (!chosen.has(opt.path)) {
111411
+ continue;
111412
+ }
111413
+ if (usedNames.has(opt.name)) {
111414
+ continue;
111415
+ }
111416
+ usedNames.add(opt.name);
111417
+ result.push(opt);
111418
+ }
111419
+ return result;
111420
+ }
110906
111421
  function ViewerToolbarSection(props) {
110907
111422
  const {
110908
111423
  mode,
@@ -110972,6 +111487,10 @@ function ViewerToolbarSection(props) {
110972
111487
  },
110973
111488
  [activeSlide, propertyHandlers]
110974
111489
  );
111490
+ const scopedLayoutOptions = React10__namespace.default.useMemo(
111491
+ () => scopeLayoutOptionsToActiveSlide(s.layoutOptions, activeSlide),
111492
+ [s.layoutOptions, activeSlide]
111493
+ );
110975
111494
  const handleApplyTransitionToAll = React10.useCallback(() => {
110976
111495
  const transition = activeSlide?.transition;
110977
111496
  if (!transition) {
@@ -111078,7 +111597,7 @@ function ViewerToolbarSection(props) {
111078
111597
  onUpdateTextStyle: ops.updateSelectedTextStyle,
111079
111598
  isOverflowMenuOpen: s.isOverflowMenuOpen,
111080
111599
  onSetOverflowMenuOpen: s.setIsOverflowMenuOpen,
111081
- layoutOptions: s.layoutOptions,
111600
+ layoutOptions: scopedLayoutOptions,
111082
111601
  onInsertSlideFromLayout: slideOps.handleInsertSlideFromLayout,
111083
111602
  customShows: s.customShows,
111084
111603
  activeCustomShowId: s.activeCustomShowId,
@@ -111111,6 +111630,7 @@ function ViewerToolbarSection(props) {
111111
111630
  isCommentsPanelOpen: s.isInspectorPaneOpen,
111112
111631
  slideCommentCount: activeSlide?.comments?.length ?? 0,
111113
111632
  formatPainterActive: s.formatPainterActive,
111633
+ canActivateFormatPainter: hasCopyableFormat(selectedElement),
111114
111634
  onToggleFormatPainter: onToggleFormatPainterProp ?? (() => s.setFormatPainterActive((p3) => !p3)),
111115
111635
  isSelectionPaneOpen: s.isSelectionPaneOpen,
111116
111636
  onToggleSelectionPane: () => s.setIsSelectionPaneOpen((p3) => !p3),
@@ -114259,6 +114779,166 @@ function ViewerMainContent(props) {
114259
114779
  )
114260
114780
  ] });
114261
114781
  }
114782
+ function MobileBottomBar({
114783
+ onOpenSlides,
114784
+ onOpenInsert,
114785
+ onOpenInspector,
114786
+ onOpenComments,
114787
+ onToggleNotes,
114788
+ activeSheet,
114789
+ commentCount
114790
+ }) {
114791
+ const actions = [
114792
+ {
114793
+ key: "slides",
114794
+ label: "Slides",
114795
+ icon: lu.LuLayers,
114796
+ onClick: onOpenSlides
114797
+ },
114798
+ {
114799
+ key: "insert",
114800
+ label: "Insert",
114801
+ icon: lu.LuPlus,
114802
+ onClick: onOpenInsert
114803
+ },
114804
+ {
114805
+ key: "inspector",
114806
+ label: "Format",
114807
+ icon: lu.LuSettings2,
114808
+ onClick: onOpenInspector
114809
+ },
114810
+ {
114811
+ key: "comments",
114812
+ label: "Comments",
114813
+ icon: lu.LuMessageSquare,
114814
+ onClick: onOpenComments,
114815
+ badge: commentCount
114816
+ },
114817
+ {
114818
+ key: "notes",
114819
+ label: "Notes",
114820
+ icon: lu.LuStickyNote,
114821
+ onClick: onToggleNotes
114822
+ }
114823
+ ];
114824
+ return /* @__PURE__ */ jsxRuntime.jsx(
114825
+ "nav",
114826
+ {
114827
+ "aria-label": "Editor actions",
114828
+ className: "md:hidden flex items-stretch justify-around border-t border-border bg-secondary/80 backdrop-blur supports-[backdrop-filter]:bg-secondary/60 pb-[max(env(safe-area-inset-bottom),0px)]",
114829
+ children: actions.map(({ key, label, icon: Icon, onClick, badge }) => {
114830
+ const active = activeSheet === key;
114831
+ return /* @__PURE__ */ jsxRuntime.jsxs(
114832
+ "button",
114833
+ {
114834
+ type: "button",
114835
+ onClick,
114836
+ className: cn(
114837
+ "relative flex flex-col items-center justify-center gap-0.5 flex-1 min-h-[56px] py-1.5 text-[10px] font-medium transition-colors active:scale-95",
114838
+ active ? "text-primary" : "text-muted-foreground hover:text-foreground"
114839
+ ),
114840
+ "aria-pressed": active,
114841
+ children: [
114842
+ /* @__PURE__ */ jsxRuntime.jsx(Icon, { className: "w-5 h-5" }),
114843
+ /* @__PURE__ */ jsxRuntime.jsx("span", { children: label }),
114844
+ badge !== void 0 && badge > 0 && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "absolute top-1 right-1/4 flex items-center justify-center min-w-[16px] h-4 px-1 rounded-full bg-primary text-[9px] font-semibold text-primary-foreground", children: badge > 99 ? "99+" : badge }),
114845
+ active && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "absolute top-0 left-1/2 -translate-x-1/2 w-8 h-0.5 rounded-full bg-primary" })
114846
+ ]
114847
+ },
114848
+ key
114849
+ );
114850
+ })
114851
+ }
114852
+ );
114853
+ }
114854
+ function MobileSlidesSheet({
114855
+ open,
114856
+ onClose,
114857
+ ...sidebar
114858
+ }) {
114859
+ return /* @__PURE__ */ jsxRuntime.jsx(MobileSheet, { open, onClose, heightFraction: 0.7, title: "Slides", children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "h-full", children: /* @__PURE__ */ jsxRuntime.jsx(SlidesPaneSidebar, { ...sidebar }) }) });
114860
+ }
114861
+ function MobileChromeOverlay(props) {
114862
+ const {
114863
+ state: s,
114864
+ editorOps,
114865
+ presentation,
114866
+ slides,
114867
+ activeSlideIndex,
114868
+ canvasSize,
114869
+ slideSectionGroups,
114870
+ canEdit,
114871
+ commentCount
114872
+ } = props;
114873
+ const activeSheet = s.isSlidesPaneOpen ? "slides" : s.isInspectorPaneOpen ? s.sidebarPanelMode === "comments" ? "comments" : "inspector" : !s.isSlideNotesCollapsed ? "notes" : null;
114874
+ const closeAllSheets = () => {
114875
+ s.setIsSlidesPaneOpen(false);
114876
+ s.setIsInspectorPaneOpen(false);
114877
+ s.setIsSlideNotesCollapsed(true);
114878
+ };
114879
+ const openSheet = (which) => {
114880
+ closeAllSheets();
114881
+ switch (which) {
114882
+ case "slides":
114883
+ s.setIsSlidesPaneOpen(true);
114884
+ break;
114885
+ case "inspector":
114886
+ s.setSidebarPanelMode("properties");
114887
+ s.setIsInspectorPaneOpen(true);
114888
+ break;
114889
+ case "comments":
114890
+ s.setSidebarPanelMode("comments");
114891
+ s.setIsInspectorPaneOpen(true);
114892
+ break;
114893
+ case "notes":
114894
+ s.setIsSlideNotesCollapsed(false);
114895
+ break;
114896
+ }
114897
+ };
114898
+ return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
114899
+ /* @__PURE__ */ jsxRuntime.jsx(
114900
+ MobileSlidesSheet,
114901
+ {
114902
+ open: s.isSlidesPaneOpen,
114903
+ onClose: () => s.setIsSlidesPaneOpen(false),
114904
+ slides,
114905
+ activeSlideIndex,
114906
+ canvasSize,
114907
+ sectionGroups: slideSectionGroups,
114908
+ isOpen: true,
114909
+ canEdit,
114910
+ onSelectSlide: (index) => {
114911
+ s.setActiveSlideIndex(index);
114912
+ s.setIsSlidesPaneOpen(false);
114913
+ },
114914
+ onSlideContextMenu: editorOps.slideOps.handleSlideContextMenu,
114915
+ onMoveSlide: editorOps.slideOps.handleMoveSlide,
114916
+ onAddSlide: editorOps.slideOps.handleAddSlide,
114917
+ onCollapse: () => s.setIsSlidesPaneOpen(false),
114918
+ onAddSection: editorOps.sectionOps.addSection,
114919
+ onRenameSection: editorOps.sectionOps.renameSection,
114920
+ onDeleteSection: editorOps.sectionOps.deleteSection,
114921
+ onMoveSectionUp: editorOps.sectionOps.moveSectionUp,
114922
+ onMoveSectionDown: editorOps.sectionOps.moveSectionDown,
114923
+ rehearsalTimings: Object.keys(presentation.recordedTimings).length > 0 ? presentation.recordedTimings : void 0
114924
+ }
114925
+ ),
114926
+ /* @__PURE__ */ jsxRuntime.jsx(
114927
+ MobileBottomBar,
114928
+ {
114929
+ activeSheet,
114930
+ commentCount,
114931
+ onOpenSlides: () => s.isSlidesPaneOpen ? s.setIsSlidesPaneOpen(false) : openSheet("slides"),
114932
+ onOpenInsert: () => {
114933
+ editorOps.insertHandlers.handleAddTextBox();
114934
+ },
114935
+ onOpenInspector: () => s.isInspectorPaneOpen && s.sidebarPanelMode !== "comments" ? s.setIsInspectorPaneOpen(false) : openSheet("inspector"),
114936
+ onOpenComments: () => s.isInspectorPaneOpen && s.sidebarPanelMode === "comments" ? s.setIsInspectorPaneOpen(false) : openSheet("comments"),
114937
+ onToggleNotes: () => !s.isSlideNotesCollapsed ? s.setIsSlideNotesCollapsed(true) : openSheet("notes")
114938
+ }
114939
+ )
114940
+ ] });
114941
+ }
114262
114942
  function ToggleSwitch({
114263
114943
  label,
114264
114944
  enabled,
@@ -114480,14 +115160,10 @@ function useYjsDocumentSync({
114480
115160
  const lastSyncedRef = React10.useRef("");
114481
115161
  const hasInitializedRef = React10.useRef(false);
114482
115162
  const getDocMap = React10.useCallback(() => {
114483
- if (!doc2 || typeof doc2 !== "object") {
115163
+ if (!doc2) {
114484
115164
  return null;
114485
115165
  }
114486
- const d = doc2;
114487
- if (typeof d.getMap !== "function") {
114488
- return null;
114489
- }
114490
- return d.getMap("slides-data");
115166
+ return doc2.getMap("slides-data");
114491
115167
  }, [doc2]);
114492
115168
  React10.useEffect(() => {
114493
115169
  if (!isConnected || !doc2) {
@@ -114508,10 +115184,9 @@ function useYjsDocumentSync({
114508
115184
  return;
114509
115185
  }
114510
115186
  lastSyncedRef.current = serialized;
114511
- const d = doc2;
114512
- d.transact(() => {
115187
+ doc2.transact(() => {
114513
115188
  const currentCount = map3.get("count");
114514
- if (currentCount && currentCount > slides.length) {
115189
+ if (typeof currentCount === "number" && currentCount > slides.length) {
114515
115190
  for (let i3 = slides.length; i3 < currentCount; i3++) {
114516
115191
  map3.delete(`slide-${i3}`);
114517
115192
  }
@@ -114536,13 +115211,13 @@ function useYjsDocumentSync({
114536
115211
  }
114537
115212
  const handleUpdate = () => {
114538
115213
  const count = map3.get("count");
114539
- if (!count || count === 0) {
115214
+ if (typeof count !== "number" || count === 0) {
114540
115215
  return;
114541
115216
  }
114542
115217
  const remoteSlides = [];
114543
115218
  for (let i3 = 0; i3 < count; i3++) {
114544
115219
  const slideJson = map3.get(`slide-${i3}`);
114545
- if (slideJson) {
115220
+ if (typeof slideJson === "string") {
114546
115221
  try {
114547
115222
  remoteSlides.push(JSON.parse(slideJson));
114548
115223
  } catch {
@@ -114567,7 +115242,7 @@ function useYjsDocumentSync({
114567
115242
  if (!hasInitializedRef.current) {
114568
115243
  hasInitializedRef.current = true;
114569
115244
  const count = map3.get("count");
114570
- if (count && count > 0) {
115245
+ if (typeof count === "number" && count > 0) {
114571
115246
  handleUpdate();
114572
115247
  }
114573
115248
  }
@@ -115128,13 +115803,14 @@ function useCanvasInteractions(input) {
115128
115803
  if (e2.button !== 0) {
115129
115804
  return;
115130
115805
  }
115131
- if (!selectedElementIdSet.has(elementId)) {
115806
+ const wasSelected = selectedElementIdSet.has(elementId);
115807
+ if (!wasSelected) {
115132
115808
  ops.applySelection(elementId);
115133
115809
  justSelectedRef.current = true;
115134
115810
  } else {
115135
115811
  justSelectedRef.current = false;
115136
115812
  }
115137
- const ids = effectiveSelectedIds.length ? effectiveSelectedIds : [elementId];
115813
+ const ids = !wasSelected ? [elementId] : effectiveSelectedIds.length ? effectiveSelectedIds : [elementId];
115138
115814
  const startPositions = {};
115139
115815
  const domEls = /* @__PURE__ */ new Map();
115140
115816
  for (const id2 of ids) {
@@ -117171,8 +117847,14 @@ function useSectionOperations(input) {
117171
117847
  }
117172
117848
 
117173
117849
  // src/viewer/hooks/useSlideManagement.ts
117850
+ function insertSlideFromLayoutUpdater(slides, activeIndex, draft) {
117851
+ const next = [...slides];
117852
+ const insertAt = Math.max(0, Math.min(activeIndex + 1, next.length));
117853
+ next.splice(insertAt, 0, draft);
117854
+ return next;
117855
+ }
117174
117856
  function useSlideManagement(input) {
117175
- const { slides, activeSlideIndex, setActiveSlideIndex, ops, history } = input;
117857
+ const { slides, activeSlideIndex, setActiveSlideIndex, ops, history, handlerRef } = input;
117176
117858
  const handleAddSlide = () => {
117177
117859
  const newSlide = {
117178
117860
  id: `slide-${Date.now()}-${Math.random().toString(36).slice(2, 6)}`,
@@ -117271,8 +117953,42 @@ function useSlideManagement(input) {
117271
117953
  });
117272
117954
  history.markDirty();
117273
117955
  };
117274
- const handleInsertSlideFromLayout = (_layoutPath) => {
117275
- handleAddSlide();
117956
+ const handleInsertSlideFromLayout = (layoutPath, layoutName) => {
117957
+ const insertAt = activeSlideIndex + 1;
117958
+ const draft = {
117959
+ id: `slide-${Date.now()}-${Math.random().toString(36).slice(2, 6)}`,
117960
+ rId: "",
117961
+ slideNumber: slides.length + 1,
117962
+ elements: [],
117963
+ layoutPath,
117964
+ ...layoutName ? { layoutName } : {}
117965
+ };
117966
+ let inserted = [];
117967
+ ops.updateSlides((prev) => {
117968
+ inserted = insertSlideFromLayoutUpdater(prev, activeSlideIndex, draft);
117969
+ return inserted;
117970
+ });
117971
+ setActiveSlideIndex(insertAt);
117972
+ history.markDirty();
117973
+ const handler = handlerRef?.current;
117974
+ if (handler) {
117975
+ void handler.applyLayoutToSlide(insertAt, layoutPath, inserted).then(
117976
+ (updated) => {
117977
+ ops.updateSlides((prev) => {
117978
+ if (prev[insertAt]?.id !== draft.id) {
117979
+ return prev;
117980
+ }
117981
+ const next = [...prev];
117982
+ next[insertAt] = updated;
117983
+ return next;
117984
+ });
117985
+ return void 0;
117986
+ },
117987
+ () => {
117988
+ return void 0;
117989
+ }
117990
+ );
117991
+ }
117276
117992
  };
117277
117993
  return {
117278
117994
  handleAddSlide,
@@ -117808,7 +118524,8 @@ function useEditorOperations(input) {
117808
118524
  canvasSize,
117809
118525
  dialogs,
117810
118526
  presentation,
117811
- userName
118527
+ userName,
118528
+ handlerRef
117812
118529
  } = input;
117813
118530
  const ops = useElementOperations({
117814
118531
  activeSlide,
@@ -117910,7 +118627,8 @@ function useEditorOperations(input) {
117910
118627
  activeSlideIndex,
117911
118628
  setActiveSlideIndex: state2.setActiveSlideIndex,
117912
118629
  ops,
117913
- history
118630
+ history,
118631
+ handlerRef
117914
118632
  });
117915
118633
  const tableOps = useTableOperations({
117916
118634
  selectedElement,
@@ -117939,21 +118657,34 @@ function useEditorOperations(input) {
117939
118657
  );
117940
118658
  const copiedFormatRef = React10.useRef(null);
117941
118659
  const prevFormatPainterRef = React10.useRef(false);
118660
+ const { formatPainterActive, setFormatPainterActive, elementLookup } = state2;
117942
118661
  React10.useEffect(() => {
117943
- if (state2.formatPainterActive && !prevFormatPainterRef.current && selectedElement) {
118662
+ if (formatPainterActive && !prevFormatPainterRef.current && selectedElement) {
117944
118663
  copiedFormatRef.current = copyFormatFromElement(selectedElement);
117945
- } else if (!state2.formatPainterActive) {
118664
+ } else if (!formatPainterActive) {
117946
118665
  copiedFormatRef.current = null;
117947
118666
  }
117948
- prevFormatPainterRef.current = state2.formatPainterActive;
117949
- }, [state2.formatPainterActive, selectedElement]);
118667
+ prevFormatPainterRef.current = formatPainterActive;
118668
+ }, [formatPainterActive, selectedElement]);
118669
+ React10.useEffect(() => {
118670
+ if (!formatPainterActive) {
118671
+ return;
118672
+ }
118673
+ const onKey = (e2) => {
118674
+ if (e2.key === "Escape") {
118675
+ setFormatPainterActive(false);
118676
+ }
118677
+ };
118678
+ window.addEventListener("keydown", onKey);
118679
+ return () => window.removeEventListener("keydown", onKey);
118680
+ }, [formatPainterActive, setFormatPainterActive]);
117950
118681
  const formatPainterCanvasHandlers = React10.useMemo(
117951
118682
  () => ({
117952
118683
  ...canvasHandlers,
117953
118684
  handleElementClick: (elementId, e2) => {
117954
- if (state2.formatPainterActive && copiedFormatRef.current) {
118685
+ if (formatPainterActive && copiedFormatRef.current) {
117955
118686
  e2.stopPropagation();
117956
- const element2 = state2.elementLookup.get(elementId);
118687
+ const element2 = elementLookup.get(elementId);
117957
118688
  if (element2) {
117958
118689
  const updated = applyFormatToElement(element2, copiedFormatRef.current);
117959
118690
  const updates = {};
@@ -117966,14 +118697,21 @@ function useEditorOperations(input) {
117966
118697
  ops.updateElementById(elementId, updates);
117967
118698
  }
117968
118699
  copiedFormatRef.current = null;
117969
- state2.setFormatPainterActive(false);
118700
+ setFormatPainterActive(false);
117970
118701
  ops.applySelection(elementId);
117971
118702
  return;
117972
118703
  }
117973
118704
  canvasHandlers.handleElementClick(elementId, e2);
118705
+ },
118706
+ handleCanvasMouseDown: (e2) => {
118707
+ if (formatPainterActive) {
118708
+ setFormatPainterActive(false);
118709
+ return;
118710
+ }
118711
+ canvasHandlers.handleCanvasMouseDown(e2);
117974
118712
  }
117975
118713
  }),
117976
- [canvasHandlers, ops, state2]
118714
+ [canvasHandlers, ops, formatPainterActive, setFormatPainterActive, elementLookup]
117977
118715
  );
117978
118716
  return {
117979
118717
  ops: combinedOps,
@@ -120151,21 +120889,35 @@ function useViewerDialogs(input) {
120151
120889
  null
120152
120890
  );
120153
120891
  const [embedFontsEnabled, setEmbedFontsEnabled] = React10.useState(false);
120154
- const [isNarrowViewport, setIsNarrowViewport] = React10.useState(false);
120892
+ const [isNarrowViewport, setIsNarrowViewport] = React10.useState(
120893
+ () => typeof window !== "undefined" ? window.innerWidth < 768 : false
120894
+ );
120155
120895
  React10.useEffect(() => {
120156
- const el = containerRef.current;
120157
- if (!el) {
120158
- return;
120159
- }
120160
- const observer = new ResizeObserver((entries) => {
120161
- const entry = entries[0];
120162
- if (entry) {
120163
- setIsNarrowViewport(entry.contentRect.width < 768);
120896
+ const handleWindow = () => setIsNarrowViewport(window.innerWidth < 768);
120897
+ let observer = null;
120898
+ let raf = 0;
120899
+ const attach2 = () => {
120900
+ const el = containerRef.current;
120901
+ if (!el) {
120902
+ raf = requestAnimationFrame(attach2);
120903
+ return;
120164
120904
  }
120165
- });
120166
- observer.observe(el);
120167
- setIsNarrowViewport(el.clientWidth < 768);
120168
- return () => observer.disconnect();
120905
+ observer = new ResizeObserver((entries) => {
120906
+ const entry = entries[0];
120907
+ if (entry) {
120908
+ setIsNarrowViewport(entry.contentRect.width < 768);
120909
+ }
120910
+ });
120911
+ observer.observe(el);
120912
+ setIsNarrowViewport(el.clientWidth < 768);
120913
+ };
120914
+ attach2();
120915
+ window.addEventListener("resize", handleWindow);
120916
+ return () => {
120917
+ cancelAnimationFrame(raf);
120918
+ observer?.disconnect();
120919
+ window.removeEventListener("resize", handleWindow);
120920
+ };
120169
120921
  }, []);
120170
120922
  React10.useEffect(() => {
120171
120923
  if (isDirty && hasDigitalSignatures && !signatureStripAcknowledgedRef.current) {
@@ -124637,7 +125389,9 @@ function useViewerCoreState(_input) {
124637
125389
  function useViewerUIState() {
124638
125390
  const [isCompactToolbarOpen, setIsCompactToolbarOpen] = React10.useState(false);
124639
125391
  const [toolbarSection, setToolbarSection] = React10.useState("home");
124640
- const [isSlidesPaneOpen, setIsSlidesPaneOpen] = React10.useState(true);
125392
+ const [isSlidesPaneOpen, setIsSlidesPaneOpen] = React10.useState(
125393
+ () => typeof window === "undefined" ? true : window.innerWidth >= 768
125394
+ );
124641
125395
  const [isInspectorPaneOpen, setIsInspectorPaneOpen] = React10.useState(false);
124642
125396
  const [isSlideNotesCollapsed, setIsSlideNotesCollapsed] = React10.useState(true);
124643
125397
  const [isOverflowMenuOpen, setIsOverflowMenuOpen] = React10.useState(false);
@@ -125080,7 +125834,8 @@ var PowerPointViewer = React10.forwardRef(
125080
125834
  canvasSize,
125081
125835
  dialogs,
125082
125836
  presentation,
125083
- userName: authorName ?? collaboration?.userName
125837
+ userName: authorName ?? collaboration?.userName,
125838
+ handlerRef: actionSoundHandlerRef
125084
125839
  });
125085
125840
  const {
125086
125841
  exportHandlers,
@@ -125203,7 +125958,7 @@ var PowerPointViewer = React10.forwardRef(
125203
125958
  {
125204
125959
  activeSlide,
125205
125960
  allSlides: slides,
125206
- isSlideNotesCollapsed: isMobile || state2.isSlideNotesCollapsed,
125961
+ isSlideNotesCollapsed: state2.isSlideNotesCollapsed,
125207
125962
  canEdit,
125208
125963
  slideCount: slides.length,
125209
125964
  activeSlideIndex,
@@ -125220,7 +125975,22 @@ var PowerPointViewer = React10.forwardRef(
125220
125975
  onZoomToFit: zoom.handleZoomToFit,
125221
125976
  mode,
125222
125977
  onSetMode: handleSetMode,
125223
- onToggleSlideSorter: () => state2.setShowSlideSorter((p3) => !p3)
125978
+ onToggleSlideSorter: () => state2.setShowSlideSorter((p3) => !p3),
125979
+ hideStatusBar: isMobile
125980
+ }
125981
+ ),
125982
+ mode !== "present" && isMobile && /* @__PURE__ */ jsxRuntime.jsx(
125983
+ MobileChromeOverlay,
125984
+ {
125985
+ state: state2,
125986
+ editorOps,
125987
+ presentation,
125988
+ slides,
125989
+ activeSlideIndex,
125990
+ canvasSize,
125991
+ slideSectionGroups,
125992
+ canEdit,
125993
+ commentCount: activeSlide?.comments?.length ?? 0
125224
125994
  }
125225
125995
  ),
125226
125996
  /* @__PURE__ */ jsxRuntime.jsx(