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
package/dist/index.js CHANGED
@@ -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, useMemo41 = 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, useMemo41 = 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;
@@ -75535,9 +75535,9 @@ function renderImageAlphaSvgFilter(element2) {
75535
75535
  const primitives = [];
75536
75536
  let resultIdx = 0;
75537
75537
  let inputRef = "SourceGraphic";
75538
- const next = (jsx229) => {
75538
+ const next = (jsx235) => {
75539
75539
  const result = `r${resultIdx++}`;
75540
- primitives.push(jsx229(inputRef, result));
75540
+ primitives.push(jsx235(inputRef, result));
75541
75541
  inputRef = result;
75542
75542
  };
75543
75543
  if (typeof e2.alphaModFix === "number") {
@@ -79578,8 +79578,8 @@ function renderTableElement(element2, textStyle, options) {
79578
79578
  {
79579
79579
  style: rowHeight ? { height: rowHeight } : void 0,
79580
79580
  children: cells.map((cell, cellIndex) => {
79581
- const isHMerged = cell["@_hMerge"] === "1" || cell["@_hMerge"] === true;
79582
- const isVMerged = cell["@_vMerge"] === "1" || cell["@_vMerge"] === true;
79581
+ const isHMerged = cell["@_hMerge"] === "1";
79582
+ const isVMerged = cell["@_vMerge"] === "1";
79583
79583
  if (isHMerged || isVMerged) {
79584
79584
  return null;
79585
79585
  }
@@ -85588,6 +85588,15 @@ function copyFormatFromElement(element2) {
85588
85588
  }
85589
85589
  return result;
85590
85590
  }
85591
+ function definedEntries(obj) {
85592
+ const out = {};
85593
+ for (const key in obj) {
85594
+ if (obj[key] !== void 0) {
85595
+ out[key] = obj[key];
85596
+ }
85597
+ }
85598
+ return out;
85599
+ }
85591
85600
  function applyFormatToElement(element2, format) {
85592
85601
  let updated = { ...element2 };
85593
85602
  if (format.shapeStyle && pptxViewerCore.hasShapeProperties(updated)) {
@@ -85595,7 +85604,7 @@ function applyFormatToElement(element2, format) {
85595
85604
  ...updated,
85596
85605
  shapeStyle: {
85597
85606
  ...updated.shapeStyle,
85598
- ...format.shapeStyle
85607
+ ...definedEntries(format.shapeStyle)
85599
85608
  }
85600
85609
  };
85601
85610
  }
@@ -85604,12 +85613,18 @@ function applyFormatToElement(element2, format) {
85604
85613
  ...updated,
85605
85614
  textStyle: {
85606
85615
  ...updated.textStyle,
85607
- ...format.textStyle
85616
+ ...definedEntries(format.textStyle)
85608
85617
  }
85609
85618
  };
85610
85619
  }
85611
85620
  return updated;
85612
85621
  }
85622
+ function hasCopyableFormat(element2) {
85623
+ if (!element2) {
85624
+ return false;
85625
+ }
85626
+ return pptxViewerCore.hasShapeProperties(element2) || pptxViewerCore.hasTextProperties(element2);
85627
+ }
85613
85628
 
85614
85629
  // src/viewer/utils/animation-preview.ts
85615
85630
  var PRESET_TO_EFFECT = {
@@ -86958,8 +86973,8 @@ function ThumbnailTable({
86958
86973
  {
86959
86974
  style: rowHeight ? { height: rowHeight } : void 0,
86960
86975
  children: cells.map((cell, ci) => {
86961
- const isHMerged = cell["@_hMerge"] === "1" || cell["@_hMerge"] === true;
86962
- const isVMerged = cell["@_vMerge"] === "1" || cell["@_vMerge"] === true;
86976
+ const isHMerged = cell["@_hMerge"] === "1";
86977
+ const isVMerged = cell["@_vMerge"] === "1";
86963
86978
  if (isHMerged || isVMerged) {
86964
86979
  return null;
86965
86980
  }
@@ -92050,11 +92065,16 @@ function usePresenceTracking({
92050
92065
  if (cid === localClientId) {
92051
92066
  return;
92052
92067
  }
92053
- const raw = state2?.presence;
92068
+ const stateRecord = state2;
92069
+ const raw = stateRecord?.presence;
92054
92070
  if (!raw || typeof raw !== "object") {
92055
92071
  return;
92056
92072
  }
92057
- const sanitized = sanitizePresence({ ...raw, clientId: cid }, canvasWidth, canvasHeight);
92073
+ const sanitized = sanitizePresence(
92074
+ { ...raw, clientId: cid },
92075
+ canvasWidth,
92076
+ canvasHeight
92077
+ );
92058
92078
  if (!sanitized) {
92059
92079
  return;
92060
92080
  }
@@ -92122,15 +92142,9 @@ function useYjsProvider({ config }) {
92122
92142
  try {
92123
92143
  const [Y, { WebsocketProvider: WebsocketProvider2 }] = await Promise.all([Promise.resolve().then(() => (init_yjs(), yjs_exports)), Promise.resolve().then(() => (init_y_websocket(), y_websocket_exports))]);
92124
92144
  const yDoc = new Y.Doc();
92125
- const provider = new WebsocketProvider2(
92126
- config.serverUrl,
92127
- roomId,
92128
- yDoc,
92129
- // eslint-disable-line @typescript-eslint/no-explicit-any
92130
- {
92131
- params: config.authToken ? { token: config.authToken } : void 0
92132
- }
92133
- );
92145
+ const provider = new WebsocketProvider2(config.serverUrl, roomId, yDoc, {
92146
+ params: config.authToken ? { token: config.authToken } : void 0
92147
+ });
92134
92148
  let connected = false;
92135
92149
  const handleStatus = (event) => {
92136
92150
  if (event.status === "connected") {
@@ -95696,90 +95710,101 @@ var SlideNotesPanel = ({
95696
95710
  });
95697
95711
  const hasNotes = draft.trim().length > 0;
95698
95712
  const slideLabel = activeSlide ? t2("pptx.notes.slideN", { n: activeSlide.slideNumber }) : t2("pptx.notes.noSlide");
95699
- return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col border-t border-border/60 bg-background select-none", children: [
95700
- /* @__PURE__ */ jsxRuntime.jsxs(
95701
- "button",
95702
- {
95703
- type: "button",
95704
- onClick: onToggle,
95705
- 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",
95706
- "aria-expanded": isExpanded,
95707
- "aria-controls": "slide-notes-content",
95708
- children: [
95709
- "Notes",
95710
- !isExpanded && hasNotes && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-muted-foreground/50 text-[10px]", children: "(has notes)" })
95711
- ]
95712
- }
95713
- ),
95714
- isExpanded && /* @__PURE__ */ jsxRuntime.jsxs(
95715
- "div",
95716
- {
95717
- id: "slide-notes-content",
95718
- className: "px-3 pb-2 overflow-y-auto",
95719
- style: { maxHeight: panelHeight ?? EXPANDED_MAX_HEIGHT + 40 },
95720
- children: [
95721
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-[10px] text-muted-foreground mb-1", children: slideLabel }),
95722
- canEdit ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
95723
- /* @__PURE__ */ jsxRuntime.jsx(
95724
- NotesToolbar,
95725
- {
95726
- isRichEditEnabled,
95727
- showLinkPopover,
95728
- savedSelectionText: savedSelectionRef.current?.text ?? "",
95729
- hasAllSlides: allSlides !== void 0 && allSlides.length > 0,
95730
- onApplyRichCommand: applyRichCommand,
95731
- onToggleBulletList: toggleBulletList,
95732
- onToggleNumberedList: toggleNumberedList,
95733
- onIndent: handleIndent,
95734
- onOutdent: handleOutdent,
95735
- onLinkButtonClick: handleLinkButtonClick,
95736
- onInsertLink: handleInsertLink,
95737
- onCloseLinkPopover: () => setShowLinkPopover(false),
95738
- onPrintClick: () => setShowPrintDialog(true),
95739
- onToggleRichEdit: () => setIsRichEditEnabled((prev) => !prev)
95740
- }
95741
- ),
95742
- isRichEditEnabled ? /* @__PURE__ */ jsxRuntime.jsx(
95743
- "div",
95744
- {
95745
- ref: richEditorRef,
95746
- contentEditable: true,
95747
- suppressContentEditableWarning: true,
95748
- onInput: handleRichInput,
95749
- onBlur: handleBlur,
95750
- onKeyDown: handleKeyDownRich,
95751
- onClick: handleEditorClick,
95752
- 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",
95753
- style: { maxHeight: EXPANDED_MAX_HEIGHT - 8, minHeight: 72 }
95754
- }
95755
- ) : /* @__PURE__ */ jsxRuntime.jsx(
95756
- "textarea",
95757
- {
95758
- ref: textareaRef,
95759
- name: "slide-notes",
95760
- value: draft,
95761
- onChange: handlePlainChange,
95762
- onBlur: handleBlur,
95763
- onKeyDown: handleKeyDownPlain,
95764
- placeholder: t2("pptx.notes.clickToAddNotes"),
95765
- rows: 4,
95766
- 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",
95767
- style: { maxHeight: EXPANDED_MAX_HEIGHT - 8 }
95768
- }
95769
- )
95770
- ] }) : /* @__PURE__ */ jsxRuntime.jsx(
95771
- "div",
95772
- {
95773
- 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",
95774
- style: { maxHeight: EXPANDED_MAX_HEIGHT - 32, minHeight: 60 },
95775
- children: hasNotes ? renderRichNotesSegments(draftSegments) : /* @__PURE__ */ jsxRuntime.jsx("span", { className: "italic text-muted-foreground", children: t2("pptx.notes.noNotes") })
95776
- }
95777
- )
95778
- ]
95779
- }
95780
- ),
95781
- showPrintDialog && allSlides && /* @__PURE__ */ jsxRuntime.jsx(NotesPrintDialog, { slides: allSlides, onClose: () => setShowPrintDialog(false) })
95782
- ] });
95713
+ return /* @__PURE__ */ jsxRuntime.jsxs(
95714
+ "div",
95715
+ {
95716
+ className: cn(
95717
+ "flex flex-col border-t border-border/60 bg-background select-none",
95718
+ // On mobile, hide the entire notes strip when collapsed — the
95719
+ // MobileBottomBar's Notes button is the entry point instead.
95720
+ !isExpanded && "max-md:hidden"
95721
+ ),
95722
+ children: [
95723
+ /* @__PURE__ */ jsxRuntime.jsxs(
95724
+ "button",
95725
+ {
95726
+ type: "button",
95727
+ onClick: onToggle,
95728
+ 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",
95729
+ "aria-expanded": isExpanded,
95730
+ "aria-controls": "slide-notes-content",
95731
+ children: [
95732
+ "Notes",
95733
+ !isExpanded && hasNotes && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-muted-foreground/50 text-[10px]", children: "(has notes)" })
95734
+ ]
95735
+ }
95736
+ ),
95737
+ isExpanded && /* @__PURE__ */ jsxRuntime.jsxs(
95738
+ "div",
95739
+ {
95740
+ id: "slide-notes-content",
95741
+ className: "px-3 pb-2 overflow-y-auto",
95742
+ style: { maxHeight: panelHeight ?? EXPANDED_MAX_HEIGHT + 40 },
95743
+ children: [
95744
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-[10px] text-muted-foreground mb-1", children: slideLabel }),
95745
+ canEdit ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
95746
+ /* @__PURE__ */ jsxRuntime.jsx(
95747
+ NotesToolbar,
95748
+ {
95749
+ isRichEditEnabled,
95750
+ showLinkPopover,
95751
+ savedSelectionText: savedSelectionRef.current?.text ?? "",
95752
+ hasAllSlides: allSlides !== void 0 && allSlides.length > 0,
95753
+ onApplyRichCommand: applyRichCommand,
95754
+ onToggleBulletList: toggleBulletList,
95755
+ onToggleNumberedList: toggleNumberedList,
95756
+ onIndent: handleIndent,
95757
+ onOutdent: handleOutdent,
95758
+ onLinkButtonClick: handleLinkButtonClick,
95759
+ onInsertLink: handleInsertLink,
95760
+ onCloseLinkPopover: () => setShowLinkPopover(false),
95761
+ onPrintClick: () => setShowPrintDialog(true),
95762
+ onToggleRichEdit: () => setIsRichEditEnabled((prev) => !prev)
95763
+ }
95764
+ ),
95765
+ isRichEditEnabled ? /* @__PURE__ */ jsxRuntime.jsx(
95766
+ "div",
95767
+ {
95768
+ ref: richEditorRef,
95769
+ contentEditable: true,
95770
+ suppressContentEditableWarning: true,
95771
+ onInput: handleRichInput,
95772
+ onBlur: handleBlur,
95773
+ onKeyDown: handleKeyDownRich,
95774
+ onClick: handleEditorClick,
95775
+ 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",
95776
+ style: { maxHeight: EXPANDED_MAX_HEIGHT - 8, minHeight: 72 }
95777
+ }
95778
+ ) : /* @__PURE__ */ jsxRuntime.jsx(
95779
+ "textarea",
95780
+ {
95781
+ ref: textareaRef,
95782
+ name: "slide-notes",
95783
+ value: draft,
95784
+ onChange: handlePlainChange,
95785
+ onBlur: handleBlur,
95786
+ onKeyDown: handleKeyDownPlain,
95787
+ placeholder: t2("pptx.notes.clickToAddNotes"),
95788
+ rows: 4,
95789
+ 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",
95790
+ style: { maxHeight: EXPANDED_MAX_HEIGHT - 8 }
95791
+ }
95792
+ )
95793
+ ] }) : /* @__PURE__ */ jsxRuntime.jsx(
95794
+ "div",
95795
+ {
95796
+ 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",
95797
+ style: { maxHeight: EXPANDED_MAX_HEIGHT - 32, minHeight: 60 },
95798
+ children: hasNotes ? renderRichNotesSegments(draftSegments) : /* @__PURE__ */ jsxRuntime.jsx("span", { className: "italic text-muted-foreground", children: t2("pptx.notes.noNotes") })
95799
+ }
95800
+ )
95801
+ ]
95802
+ }
95803
+ ),
95804
+ showPrintDialog && allSlides && /* @__PURE__ */ jsxRuntime.jsx(NotesPrintDialog, { slides: allSlides, onClose: () => setShowPrintDialog(false) })
95805
+ ]
95806
+ }
95807
+ );
95783
95808
  };
95784
95809
  var DB_NAME = "pptx-viewer-autosave";
95785
95810
  var DB_VERSION = 1;
@@ -98316,7 +98341,8 @@ function ArrangeSection(p3) {
98316
98341
  {
98317
98342
  type: "button",
98318
98343
  onClick: p3.onToggleFormatPainter,
98319
- disabled: !p3.canEdit,
98344
+ disabled: !p3.canEdit || p3.canActivateFormatPainter === false && !p3.formatPainterActive,
98345
+ "data-testid": "format-painter-toggle",
98320
98346
  className: cn(
98321
98347
  pill,
98322
98348
  p3.formatPainterActive ? "bg-amber-600 hover:bg-amber-500 text-amber-50" : ""
@@ -98768,7 +98794,8 @@ function HomeSection(p3) {
98768
98794
  const { fontFamily, fontSize } = extractFontInfo(p3.selectedElement);
98769
98795
  const handleNewSlide = React10.useCallback(() => {
98770
98796
  if (p3.layoutOptions.length > 0) {
98771
- p3.onInsertSlideFromLayout(p3.layoutOptions[0].path);
98797
+ const first = p3.layoutOptions[0];
98798
+ p3.onInsertSlideFromLayout(first.path, first.name);
98772
98799
  }
98773
98800
  }, [p3]);
98774
98801
  React10.useEffect(() => {
@@ -98855,7 +98882,8 @@ function HomeSection(p3) {
98855
98882
  {
98856
98883
  type: "button",
98857
98884
  onClick: p3.onToggleFormatPainter,
98858
- disabled: !p3.canEdit,
98885
+ disabled: !p3.canEdit || p3.canActivateFormatPainter === false && !p3.formatPainterActive,
98886
+ "data-testid": "format-painter-toggle",
98859
98887
  className: cn(
98860
98888
  gL,
98861
98889
  p3.formatPainterActive ? "bg-amber-600 hover:bg-amber-500 text-amber-50" : ""
@@ -98905,7 +98933,7 @@ function HomeSection(p3) {
98905
98933
  type: "button",
98906
98934
  className: "flex items-center gap-2 w-full px-3 py-1.5 text-xs text-foreground hover:bg-muted transition-colors",
98907
98935
  onClick: () => {
98908
- p3.onInsertSlideFromLayout(lo.path);
98936
+ p3.onInsertSlideFromLayout(lo.path, lo.name);
98909
98937
  setLayoutMenuOpen(false);
98910
98938
  },
98911
98939
  children: lo.name
@@ -99805,6 +99833,561 @@ function TextSection(p3) {
99805
99833
  ] })
99806
99834
  ] });
99807
99835
  }
99836
+ function ViewSection(p3) {
99837
+ const { t: t2 } = reactI18next.useTranslation();
99838
+ return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
99839
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col items-center gap-0.5", children: [
99840
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-0.5", children: [
99841
+ /* @__PURE__ */ jsxRuntime.jsx("button", { className: pill, title: "Normal view", children: "Normal" }),
99842
+ 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" }),
99843
+ /* @__PURE__ */ jsxRuntime.jsx("button", { className: pill, title: "Reading View", children: "Reading View" })
99844
+ ] }),
99845
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-[9px] text-muted-foreground leading-none", children: "Presentation Views" })
99846
+ ] }),
99847
+ sep,
99848
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col items-center gap-0.5", children: [
99849
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex items-center gap-0.5", children: /* @__PURE__ */ jsxRuntime.jsx(
99850
+ "button",
99851
+ {
99852
+ onClick: p3.onEnterMasterView,
99853
+ disabled: !p3.canEdit,
99854
+ className: pill,
99855
+ title: "Edit slide masters and layouts",
99856
+ children: "Slide Master"
99857
+ }
99858
+ ) }),
99859
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-[9px] text-muted-foreground leading-none", children: "Master Views" })
99860
+ ] }),
99861
+ sep,
99862
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col items-center gap-0.5", children: [
99863
+ /* @__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" }) }),
99864
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-[9px] text-muted-foreground leading-none", children: "Zoom" })
99865
+ ] }),
99866
+ sep,
99867
+ /* @__PURE__ */ jsxRuntime.jsx(
99868
+ "button",
99869
+ {
99870
+ onClick: () => p3.onSetEditTemplateMode(!p3.editTemplateMode),
99871
+ disabled: !p3.canEdit,
99872
+ className: cn(
99873
+ pill,
99874
+ p3.editTemplateMode ? "bg-amber-600 hover:bg-amber-500 text-amber-50" : ""
99875
+ ),
99876
+ title: "Toggle template/master element editing",
99877
+ children: p3.editTemplateMode ? "Templates On" : "Templates Off"
99878
+ }
99879
+ ),
99880
+ p3.onToggleSelectionPane && /* @__PURE__ */ jsxRuntime.jsxs(
99881
+ "button",
99882
+ {
99883
+ type: "button",
99884
+ onClick: p3.onToggleSelectionPane,
99885
+ className: cn(
99886
+ pill,
99887
+ p3.isSelectionPaneOpen ? "bg-primary hover:bg-primary/80 text-primary-foreground" : ""
99888
+ ),
99889
+ title: "Selection Pane",
99890
+ children: [
99891
+ /* @__PURE__ */ jsxRuntime.jsx(lu.LuList, { className: ic2 }),
99892
+ "Selection"
99893
+ ]
99894
+ }
99895
+ ),
99896
+ p3.onToggleEyedropper && /* @__PURE__ */ jsxRuntime.jsxs(
99897
+ "button",
99898
+ {
99899
+ type: "button",
99900
+ onClick: p3.onToggleEyedropper,
99901
+ disabled: !p3.canEdit,
99902
+ className: cn(
99903
+ pill,
99904
+ p3.eyedropperActive ? "bg-purple-600 hover:bg-purple-500 text-purple-50" : ""
99905
+ ),
99906
+ title: "Eyedropper \u2014 sample a colour from the slide",
99907
+ children: [
99908
+ /* @__PURE__ */ jsxRuntime.jsx(lu.LuPipette, { className: ic2 }),
99909
+ "Eyedropper"
99910
+ ]
99911
+ }
99912
+ ),
99913
+ /* @__PURE__ */ jsxRuntime.jsx(
99914
+ "button",
99915
+ {
99916
+ onClick: () => p3.onSetShowGrid(!p3.showGrid),
99917
+ className: cn(pill, p3.showGrid ? "bg-primary text-primary-foreground" : ""),
99918
+ title: t2("pptx.grid.toggleGrid"),
99919
+ children: t2("pptx.grid.grid")
99920
+ }
99921
+ ),
99922
+ /* @__PURE__ */ jsxRuntime.jsx(
99923
+ "button",
99924
+ {
99925
+ onClick: () => p3.onSetShowRulers(!p3.showRulers),
99926
+ className: cn(pill, p3.showRulers ? "bg-primary text-primary-foreground" : ""),
99927
+ title: t2("pptx.ruler.toggleRulers"),
99928
+ children: t2("pptx.ruler.rulers")
99929
+ }
99930
+ ),
99931
+ /* @__PURE__ */ jsxRuntime.jsx(
99932
+ "button",
99933
+ {
99934
+ onClick: () => p3.onSetSnapToGrid(!p3.snapToGrid),
99935
+ className: cn(pill, p3.snapToGrid ? "bg-primary text-primary-foreground" : ""),
99936
+ title: t2("pptx.grid.snapToGrid"),
99937
+ children: t2("pptx.grid.snapToGrid")
99938
+ }
99939
+ ),
99940
+ /* @__PURE__ */ jsxRuntime.jsx(
99941
+ "button",
99942
+ {
99943
+ onClick: () => p3.onSetSnapToShape(!p3.snapToShape),
99944
+ className: cn(pill, p3.snapToShape ? "bg-primary text-primary-foreground" : ""),
99945
+ title: t2("pptx.grid.snapToShape"),
99946
+ children: t2("pptx.grid.snapToShape")
99947
+ }
99948
+ ),
99949
+ /* @__PURE__ */ jsxRuntime.jsx("button", { onClick: () => p3.onAddGuide("h"), className: pill, title: "Add horizontal guide", children: "H Guide" }),
99950
+ /* @__PURE__ */ jsxRuntime.jsx("button", { onClick: () => p3.onAddGuide("v"), className: pill, title: "Add vertical guide", children: "V Guide" }),
99951
+ /* @__PURE__ */ jsxRuntime.jsx(
99952
+ "button",
99953
+ {
99954
+ onClick: () => p3.onSetSpellCheckEnabled(!p3.spellCheckEnabled),
99955
+ className: cn(pill, p3.spellCheckEnabled ? "bg-primary text-primary-foreground" : ""),
99956
+ title: "Toggle spell check",
99957
+ children: "Spell"
99958
+ }
99959
+ )
99960
+ ] });
99961
+ }
99962
+ function MobileSheet({
99963
+ open,
99964
+ onClose,
99965
+ title,
99966
+ children,
99967
+ heightFraction = 0.6,
99968
+ fullScreen = false,
99969
+ className,
99970
+ headerRight
99971
+ }) {
99972
+ const sheetRef = React10.useRef(null);
99973
+ const [dragY, setDragY] = React10.useState(0);
99974
+ const dragStartRef = React10.useRef(null);
99975
+ const onPointerDown = React10.useCallback((e2) => {
99976
+ dragStartRef.current = e2.clientY;
99977
+ e2.target.setPointerCapture?.(e2.pointerId);
99978
+ }, []);
99979
+ const onPointerMove = React10.useCallback((e2) => {
99980
+ if (dragStartRef.current === null) {
99981
+ return;
99982
+ }
99983
+ const delta = e2.clientY - dragStartRef.current;
99984
+ setDragY(Math.max(0, delta));
99985
+ }, []);
99986
+ const onPointerUp = React10.useCallback(
99987
+ (e2) => {
99988
+ if (dragStartRef.current === null) {
99989
+ return;
99990
+ }
99991
+ const delta = e2.clientY - dragStartRef.current;
99992
+ dragStartRef.current = null;
99993
+ e2.target.releasePointerCapture?.(e2.pointerId);
99994
+ if (delta > 120) {
99995
+ onClose();
99996
+ }
99997
+ setDragY(0);
99998
+ },
99999
+ [onClose]
100000
+ );
100001
+ React10.useEffect(() => {
100002
+ if (!open) {
100003
+ return;
100004
+ }
100005
+ const handleKey = (e2) => {
100006
+ if (e2.key === "Escape") {
100007
+ onClose();
100008
+ }
100009
+ };
100010
+ window.addEventListener("keydown", handleKey);
100011
+ return () => window.removeEventListener("keydown", handleKey);
100012
+ }, [open, onClose]);
100013
+ if (!open) {
100014
+ return null;
100015
+ }
100016
+ const heightStyle = fullScreen ? { height: "calc(100dvh - env(safe-area-inset-top))" } : { height: `${Math.round(heightFraction * 100)}dvh` };
100017
+ return /* @__PURE__ */ jsxRuntime.jsxs(
100018
+ "div",
100019
+ {
100020
+ className: "fixed inset-0 z-50 flex flex-col justify-end md:hidden",
100021
+ role: "dialog",
100022
+ "aria-modal": "true",
100023
+ children: [
100024
+ /* @__PURE__ */ jsxRuntime.jsx(
100025
+ "button",
100026
+ {
100027
+ type: "button",
100028
+ "aria-label": "Close",
100029
+ className: "absolute inset-0 bg-black/40 backdrop-blur-[2px] animate-in fade-in duration-150",
100030
+ onClick: onClose
100031
+ }
100032
+ ),
100033
+ /* @__PURE__ */ jsxRuntime.jsxs(
100034
+ "div",
100035
+ {
100036
+ ref: sheetRef,
100037
+ className: cn(
100038
+ "relative bg-background border-t border-border rounded-t-2xl shadow-2xl flex flex-col overflow-hidden",
100039
+ "animate-in slide-in-from-bottom duration-200",
100040
+ className
100041
+ ),
100042
+ style: {
100043
+ ...heightStyle,
100044
+ transform: dragY > 0 ? `translateY(${dragY}px)` : void 0,
100045
+ transition: dragStartRef.current === null ? "transform 150ms ease-out" : "none"
100046
+ },
100047
+ children: [
100048
+ /* @__PURE__ */ jsxRuntime.jsx(
100049
+ "div",
100050
+ {
100051
+ className: "flex items-center justify-center pt-2 pb-1 cursor-grab active:cursor-grabbing touch-none",
100052
+ onPointerDown,
100053
+ onPointerMove,
100054
+ onPointerUp,
100055
+ onPointerCancel: onPointerUp,
100056
+ children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "h-1 w-10 rounded-full bg-muted-foreground/40" })
100057
+ }
100058
+ ),
100059
+ (title || headerRight) && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between gap-2 px-4 pb-2 border-b border-border/60", children: [
100060
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-sm font-semibold text-foreground truncate", children: title }),
100061
+ headerRight
100062
+ ] }),
100063
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex-1 overflow-y-auto overscroll-contain", children })
100064
+ ]
100065
+ }
100066
+ )
100067
+ ]
100068
+ }
100069
+ );
100070
+ }
100071
+ var MENU_ITEMS = [
100072
+ { key: "home", label: "Home", icon: lu.LuClipboardCopy },
100073
+ { key: "insert", label: "Insert", icon: lu.LuPlus },
100074
+ { key: "text", label: "Text", icon: lu.LuType },
100075
+ { key: "draw", label: "Draw", icon: lu.LuPaintbrush },
100076
+ { key: "arrange", label: "Arrange", icon: lu.LuShapes },
100077
+ { key: "design", label: "Design", icon: lu.LuLayoutGrid },
100078
+ { key: "transitions", label: "Transitions", icon: lu.LuSparkles },
100079
+ { key: "animations", label: "Animations", icon: lu.LuWand },
100080
+ { key: "slideShow", label: "Slide Show", icon: lu.LuPresentation },
100081
+ { key: "review", label: "Review", icon: lu.LuTextCursorInput },
100082
+ { key: "view", label: "View", icon: lu.LuSettings },
100083
+ { key: "file", label: "File", icon: lu.LuFile }
100084
+ ];
100085
+ function MobileMenuSheet(props) {
100086
+ const { open, onClose } = props;
100087
+ const [active, setActive] = React10.useState("home");
100088
+ return /* @__PURE__ */ jsxRuntime.jsx(MobileSheet, { open, onClose, fullScreen: true, title: "Menu", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col", children: [
100089
+ /* @__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(
100090
+ "button",
100091
+ {
100092
+ type: "button",
100093
+ onClick: () => setActive(active === key ? null : key),
100094
+ className: cn(
100095
+ "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]",
100096
+ active === key ? "bg-primary text-primary-foreground border-primary" : "border-border text-muted-foreground hover:text-foreground hover:bg-accent/40"
100097
+ ),
100098
+ children: [
100099
+ /* @__PURE__ */ jsxRuntime.jsx(Icon, { className: "w-4 h-4" }),
100100
+ label
100101
+ ]
100102
+ },
100103
+ key
100104
+ )) }) }),
100105
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "p-3", children: /* @__PURE__ */ jsxRuntime.jsx(MobileSectionBody, { active, ...props }) })
100106
+ ] }) });
100107
+ }
100108
+ function MobileSectionBody({
100109
+ active,
100110
+ ...p3
100111
+ }) {
100112
+ const wrap = "flex flex-wrap items-center gap-2";
100113
+ switch (active) {
100114
+ case "home":
100115
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { className: wrap, children: /* @__PURE__ */ jsxRuntime.jsx(
100116
+ HomeSection,
100117
+ {
100118
+ canEdit: p3.canEdit,
100119
+ clipboardPayload: p3.clipboardPayload,
100120
+ formatPainterActive: p3.formatPainterActive,
100121
+ canActivateFormatPainter: p3.canActivateFormatPainter,
100122
+ onCopy: p3.onCopy,
100123
+ onCut: p3.onCut,
100124
+ onPaste: p3.onPaste,
100125
+ onToggleFormatPainter: p3.onToggleFormatPainter,
100126
+ layoutOptions: p3.layoutOptions,
100127
+ onInsertSlideFromLayout: p3.onInsertSlideFromLayout,
100128
+ selectedElement: p3.selectedElement,
100129
+ onUpdateTextStyle: p3.onUpdateTextStyle
100130
+ }
100131
+ ) });
100132
+ case "insert":
100133
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { className: wrap, children: /* @__PURE__ */ jsxRuntime.jsx(
100134
+ InsertSection,
100135
+ {
100136
+ canEdit: p3.canEdit,
100137
+ newShapeType: p3.newShapeType,
100138
+ onSetNewShapeType: p3.onSetNewShapeType,
100139
+ onAddTextBox: p3.onAddTextBox,
100140
+ onAddShape: p3.onAddShape,
100141
+ onAddTable: p3.onAddTable,
100142
+ onAddSmartArt: p3.onAddSmartArt,
100143
+ onAddEquation: p3.onAddEquation,
100144
+ onAddActionButton: p3.onAddActionButton,
100145
+ onInsertField: p3.onInsertField,
100146
+ onOpenImagePicker: p3.onOpenImagePicker,
100147
+ onOpenMediaPicker: p3.onOpenMediaPicker
100148
+ }
100149
+ ) });
100150
+ case "text":
100151
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { className: wrap, children: /* @__PURE__ */ jsxRuntime.jsx(
100152
+ TextSection,
100153
+ {
100154
+ canEdit: p3.canEdit,
100155
+ selectedElement: p3.selectedElement,
100156
+ tableEditorState: p3.tableEditorState,
100157
+ onUpdateTextStyle: p3.onUpdateTextStyle
100158
+ }
100159
+ ) });
100160
+ case "draw":
100161
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { className: wrap, children: /* @__PURE__ */ jsxRuntime.jsx(
100162
+ DrawSection,
100163
+ {
100164
+ activeTool: p3.activeTool,
100165
+ drawingColor: p3.drawingColor,
100166
+ drawingWidth: p3.drawingWidth,
100167
+ onSetActiveTool: p3.onSetActiveTool,
100168
+ onSetDrawingColor: p3.onSetDrawingColor,
100169
+ onSetDrawingWidth: p3.onSetDrawingWidth
100170
+ }
100171
+ ) });
100172
+ case "arrange":
100173
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { className: wrap, children: /* @__PURE__ */ jsxRuntime.jsx(
100174
+ ArrangeSection,
100175
+ {
100176
+ canEdit: p3.canEdit,
100177
+ selectedElement: p3.selectedElement,
100178
+ clipboardPayload: p3.clipboardPayload,
100179
+ onAlignElements: p3.onAlignElements,
100180
+ onCopy: p3.onCopy,
100181
+ onCut: p3.onCut,
100182
+ onPaste: p3.onPaste,
100183
+ onFlip: p3.onFlip,
100184
+ onMoveLayer: p3.onMoveLayer,
100185
+ onMoveLayerToEdge: p3.onMoveLayerToEdge,
100186
+ onDuplicate: p3.onDuplicate,
100187
+ onDelete: p3.onDelete,
100188
+ formatPainterActive: p3.formatPainterActive,
100189
+ onToggleFormatPainter: p3.onToggleFormatPainter,
100190
+ canActivateFormatPainter: p3.canActivateFormatPainter
100191
+ }
100192
+ ) });
100193
+ case "design":
100194
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { className: wrap, children: /* @__PURE__ */ jsxRuntime.jsx(
100195
+ DesignSection,
100196
+ {
100197
+ canEdit: p3.canEdit,
100198
+ onToggleThemeGallery: p3.onToggleThemeGallery,
100199
+ isThemeGalleryOpen: p3.isThemeGalleryOpen,
100200
+ onToggleThemeEditor: p3.onToggleThemeEditor,
100201
+ isThemeEditorOpen: p3.isThemeEditorOpen,
100202
+ onOpenDocumentProperties: p3.onOpenDocumentProperties,
100203
+ onToggleInspector: p3.onToggleInspector,
100204
+ isInspectorPaneOpen: p3.isInspectorPaneOpen
100205
+ }
100206
+ ) });
100207
+ case "transitions":
100208
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { className: wrap, children: /* @__PURE__ */ jsxRuntime.jsx(
100209
+ TransitionsSection,
100210
+ {
100211
+ isInspectorPaneOpen: p3.isInspectorPaneOpen,
100212
+ onToggleInspector: p3.onToggleInspector
100213
+ }
100214
+ ) });
100215
+ case "animations":
100216
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { className: wrap, children: /* @__PURE__ */ jsxRuntime.jsx(
100217
+ AnimationsSection,
100218
+ {
100219
+ canEdit: p3.canEdit,
100220
+ selectedElement: p3.selectedElement,
100221
+ isInspectorPaneOpen: p3.isInspectorPaneOpen,
100222
+ onToggleInspector: p3.onToggleInspector,
100223
+ onOpenAnimationPanel: p3.onOpenAnimationPanel,
100224
+ onAddAnimation: p3.onAddAnimation,
100225
+ onRemoveAnimation: p3.onRemoveAnimation
100226
+ }
100227
+ ) });
100228
+ case "slideShow":
100229
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { className: wrap, children: /* @__PURE__ */ jsxRuntime.jsx(
100230
+ SlideShowSection,
100231
+ {
100232
+ onPresent: () => p3.onSetMode("present"),
100233
+ onEnterPresenterView: p3.onEnterPresenterView ?? (() => {
100234
+ }),
100235
+ onEnterRehearsalMode: p3.onEnterRehearsalMode ?? (() => {
100236
+ }),
100237
+ onOpenSetUpSlideShow: p3.onOpenSetUpSlideShow ?? (() => {
100238
+ }),
100239
+ onOpenBroadcastDialog: p3.onOpenBroadcastDialog ?? (() => {
100240
+ }),
100241
+ onToggleSubtitles: p3.onToggleSubtitles ?? (() => {
100242
+ }),
100243
+ showSubtitles: p3.showSubtitles ?? false,
100244
+ onSetMode: p3.onSetMode
100245
+ }
100246
+ ) });
100247
+ case "review":
100248
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { className: wrap, children: /* @__PURE__ */ jsxRuntime.jsx(
100249
+ ReviewSection,
100250
+ {
100251
+ canEdit: p3.canEdit,
100252
+ spellCheckEnabled: p3.spellCheckEnabled,
100253
+ onSetSpellCheckEnabled: p3.onSetSpellCheckEnabled,
100254
+ onToggleComments: p3.onToggleComments,
100255
+ isCommentsPanelOpen: p3.isCommentsPanelOpen,
100256
+ slideCommentCount: p3.slideCommentCount,
100257
+ onCompare: p3.onCompare
100258
+ }
100259
+ ) });
100260
+ case "view":
100261
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { className: wrap, children: /* @__PURE__ */ jsxRuntime.jsx(
100262
+ ViewSection,
100263
+ {
100264
+ canEdit: p3.canEdit,
100265
+ editTemplateMode: p3.editTemplateMode,
100266
+ onSetEditTemplateMode: p3.onSetEditTemplateMode,
100267
+ spellCheckEnabled: p3.spellCheckEnabled,
100268
+ onSetSpellCheckEnabled: p3.onSetSpellCheckEnabled,
100269
+ showGrid: p3.showGrid,
100270
+ showRulers: p3.showRulers,
100271
+ snapToGrid: p3.snapToGrid,
100272
+ snapToShape: p3.snapToShape,
100273
+ onSetShowGrid: p3.onSetShowGrid,
100274
+ onSetShowRulers: p3.onSetShowRulers,
100275
+ onSetSnapToGrid: p3.onSetSnapToGrid,
100276
+ onSetSnapToShape: p3.onSetSnapToShape,
100277
+ onAddGuide: p3.onAddGuide,
100278
+ onEnterMasterView: p3.onEnterMasterView,
100279
+ isSelectionPaneOpen: p3.isSelectionPaneOpen,
100280
+ onToggleSelectionPane: p3.onToggleSelectionPane,
100281
+ eyedropperActive: p3.eyedropperActive,
100282
+ onToggleEyedropper: p3.onToggleEyedropper
100283
+ }
100284
+ ) });
100285
+ case "file":
100286
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { className: wrap, children: /* @__PURE__ */ jsxRuntime.jsx(
100287
+ FileSection,
100288
+ {
100289
+ onExportPng: p3.onExportPng,
100290
+ onExportPdf: p3.onExportPdf,
100291
+ onExportVideo: p3.onExportVideo,
100292
+ onExportGif: p3.onExportGif,
100293
+ onPackageForSharing: p3.onPackageForSharing,
100294
+ onSaveAsPptx: p3.onSaveAsPptx,
100295
+ onSaveAsPpsx: p3.onSaveAsPpsx,
100296
+ onSaveAsPptm: p3.onSaveAsPptm,
100297
+ hasMacros: p3.hasMacros,
100298
+ onCopySlideAsImage: p3.onCopySlideAsImage,
100299
+ onPrint: p3.onPrint,
100300
+ onOpenDocumentProperties: p3.onOpenDocumentProperties,
100301
+ onOpenPasswordProtection: p3.onOpenPasswordProtection,
100302
+ onOpenFontEmbedding: p3.onOpenFontEmbedding,
100303
+ onOpenDigitalSignatures: p3.onOpenDigitalSignatures
100304
+ }
100305
+ ) });
100306
+ default:
100307
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "text-center text-sm text-muted-foreground py-8", children: [
100308
+ /* @__PURE__ */ jsxRuntime.jsx(lu.LuChevronRight, { className: "w-5 h-5 inline-block opacity-50" }),
100309
+ " Select a section above"
100310
+ ] });
100311
+ }
100312
+ }
100313
+ function MobileToolbar(props) {
100314
+ const { t: t2 } = reactI18next.useTranslation();
100315
+ const { mode, canUndo, canRedo, onUndo, onRedo, onSetMode } = props;
100316
+ const [menuOpen, setMenuOpen] = React10.useState(false);
100317
+ const showEdit = mode === "edit" || mode === "master";
100318
+ 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";
100319
+ return /* @__PURE__ */ jsxRuntime.jsxs(
100320
+ "div",
100321
+ {
100322
+ role: "toolbar",
100323
+ "aria-label": "Toolbar",
100324
+ 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)]",
100325
+ children: [
100326
+ showEdit && /* @__PURE__ */ jsxRuntime.jsx(
100327
+ "button",
100328
+ {
100329
+ type: "button",
100330
+ onClick: () => setMenuOpen(true),
100331
+ className: btn,
100332
+ title: "Menu",
100333
+ "aria-label": "Menu",
100334
+ children: /* @__PURE__ */ jsxRuntime.jsx(lu.LuMenu, { className: "w-5 h-5" })
100335
+ }
100336
+ ),
100337
+ showEdit && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
100338
+ /* @__PURE__ */ jsxRuntime.jsx(
100339
+ "button",
100340
+ {
100341
+ type: "button",
100342
+ onClick: onUndo,
100343
+ disabled: !canUndo,
100344
+ className: btn,
100345
+ title: t2("pptx.toolbar.undo"),
100346
+ "aria-label": t2("pptx.toolbar.undo"),
100347
+ children: /* @__PURE__ */ jsxRuntime.jsx(lu.LuUndo, { className: "w-5 h-5" })
100348
+ }
100349
+ ),
100350
+ /* @__PURE__ */ jsxRuntime.jsx(
100351
+ "button",
100352
+ {
100353
+ type: "button",
100354
+ onClick: onRedo,
100355
+ disabled: !canRedo,
100356
+ className: btn,
100357
+ title: t2("pptx.toolbar.redo"),
100358
+ "aria-label": t2("pptx.toolbar.redo"),
100359
+ children: /* @__PURE__ */ jsxRuntime.jsx(lu.LuRedo, { className: "w-5 h-5" })
100360
+ }
100361
+ )
100362
+ ] }),
100363
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex-1" }),
100364
+ /* @__PURE__ */ jsxRuntime.jsx(
100365
+ "button",
100366
+ {
100367
+ type: "button",
100368
+ onClick: () => onSetMode("present"),
100369
+ className: cn(btn, "text-primary"),
100370
+ title: t2("pptx.toolbar.present"),
100371
+ "aria-label": t2("pptx.toolbar.present"),
100372
+ children: /* @__PURE__ */ jsxRuntime.jsx(lu.LuPresentation, { className: "w-5 h-5" })
100373
+ }
100374
+ ),
100375
+ showEdit && /* @__PURE__ */ jsxRuntime.jsx(
100376
+ "button",
100377
+ {
100378
+ type: "button",
100379
+ onClick: props.onOpenShareDialog ?? props.onPackageForSharing,
100380
+ className: cn(btn, "bg-primary text-primary-foreground hover:bg-primary/90 px-3"),
100381
+ title: t2("pptx.toolbar.share"),
100382
+ "aria-label": t2("pptx.toolbar.share"),
100383
+ children: /* @__PURE__ */ jsxRuntime.jsx(lu.LuShare2, { className: "w-4 h-4" })
100384
+ }
100385
+ ),
100386
+ /* @__PURE__ */ jsxRuntime.jsx(MobileMenuSheet, { open: menuOpen, onClose: () => setMenuOpen(false), ...props })
100387
+ ]
100388
+ }
100389
+ );
100390
+ }
99808
100391
  function CustomShowsControls({
99809
100392
  customShows,
99810
100393
  activeCustomShowId,
@@ -100233,7 +100816,7 @@ function ToolbarPrimaryRow(p3) {
100233
100816
  onClick: p3.onToggleComments,
100234
100817
  className: cn(
100235
100818
  qab,
100236
- "max-md:hidden",
100819
+ "relative max-md:hidden",
100237
100820
  p3.isCommentsPanelOpen ? "text-foreground" : "text-muted-foreground"
100238
100821
  ),
100239
100822
  title: t2("pptx.toolbar.comments"),
@@ -100349,134 +100932,11 @@ function ToolbarPrimaryRow(p3) {
100349
100932
  /* @__PURE__ */ jsxRuntime.jsx(OverflowMenu, { ...p3 })
100350
100933
  ] });
100351
100934
  }
100352
- function ViewSection(p3) {
100353
- const { t: t2 } = reactI18next.useTranslation();
100354
- return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
100355
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col items-center gap-0.5", children: [
100356
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-0.5", children: [
100357
- /* @__PURE__ */ jsxRuntime.jsx("button", { className: pill, title: "Normal view", children: "Normal" }),
100358
- 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" }),
100359
- /* @__PURE__ */ jsxRuntime.jsx("button", { className: pill, title: "Reading View", children: "Reading View" })
100360
- ] }),
100361
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-[9px] text-muted-foreground leading-none", children: "Presentation Views" })
100362
- ] }),
100363
- sep,
100364
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col items-center gap-0.5", children: [
100365
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex items-center gap-0.5", children: /* @__PURE__ */ jsxRuntime.jsx(
100366
- "button",
100367
- {
100368
- onClick: p3.onEnterMasterView,
100369
- disabled: !p3.canEdit,
100370
- className: pill,
100371
- title: "Edit slide masters and layouts",
100372
- children: "Slide Master"
100373
- }
100374
- ) }),
100375
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-[9px] text-muted-foreground leading-none", children: "Master Views" })
100376
- ] }),
100377
- sep,
100378
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col items-center gap-0.5", children: [
100379
- /* @__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" }) }),
100380
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-[9px] text-muted-foreground leading-none", children: "Zoom" })
100381
- ] }),
100382
- sep,
100383
- /* @__PURE__ */ jsxRuntime.jsx(
100384
- "button",
100385
- {
100386
- onClick: () => p3.onSetEditTemplateMode(!p3.editTemplateMode),
100387
- disabled: !p3.canEdit,
100388
- className: cn(
100389
- pill,
100390
- p3.editTemplateMode ? "bg-amber-600 hover:bg-amber-500 text-amber-50" : ""
100391
- ),
100392
- title: "Toggle template/master element editing",
100393
- children: p3.editTemplateMode ? "Templates On" : "Templates Off"
100394
- }
100395
- ),
100396
- p3.onToggleSelectionPane && /* @__PURE__ */ jsxRuntime.jsxs(
100397
- "button",
100398
- {
100399
- type: "button",
100400
- onClick: p3.onToggleSelectionPane,
100401
- className: cn(
100402
- pill,
100403
- p3.isSelectionPaneOpen ? "bg-primary hover:bg-primary/80 text-primary-foreground" : ""
100404
- ),
100405
- title: "Selection Pane",
100406
- children: [
100407
- /* @__PURE__ */ jsxRuntime.jsx(lu.LuList, { className: ic2 }),
100408
- "Selection"
100409
- ]
100410
- }
100411
- ),
100412
- p3.onToggleEyedropper && /* @__PURE__ */ jsxRuntime.jsxs(
100413
- "button",
100414
- {
100415
- type: "button",
100416
- onClick: p3.onToggleEyedropper,
100417
- disabled: !p3.canEdit,
100418
- className: cn(
100419
- pill,
100420
- p3.eyedropperActive ? "bg-purple-600 hover:bg-purple-500 text-purple-50" : ""
100421
- ),
100422
- title: "Eyedropper \u2014 sample a colour from the slide",
100423
- children: [
100424
- /* @__PURE__ */ jsxRuntime.jsx(lu.LuPipette, { className: ic2 }),
100425
- "Eyedropper"
100426
- ]
100427
- }
100428
- ),
100429
- /* @__PURE__ */ jsxRuntime.jsx(
100430
- "button",
100431
- {
100432
- onClick: () => p3.onSetShowGrid(!p3.showGrid),
100433
- className: cn(pill, p3.showGrid ? "bg-primary text-primary-foreground" : ""),
100434
- title: t2("pptx.grid.toggleGrid"),
100435
- children: t2("pptx.grid.grid")
100436
- }
100437
- ),
100438
- /* @__PURE__ */ jsxRuntime.jsx(
100439
- "button",
100440
- {
100441
- onClick: () => p3.onSetShowRulers(!p3.showRulers),
100442
- className: cn(pill, p3.showRulers ? "bg-primary text-primary-foreground" : ""),
100443
- title: t2("pptx.ruler.toggleRulers"),
100444
- children: t2("pptx.ruler.rulers")
100445
- }
100446
- ),
100447
- /* @__PURE__ */ jsxRuntime.jsx(
100448
- "button",
100449
- {
100450
- onClick: () => p3.onSetSnapToGrid(!p3.snapToGrid),
100451
- className: cn(pill, p3.snapToGrid ? "bg-primary text-primary-foreground" : ""),
100452
- title: t2("pptx.grid.snapToGrid"),
100453
- children: t2("pptx.grid.snapToGrid")
100454
- }
100455
- ),
100456
- /* @__PURE__ */ jsxRuntime.jsx(
100457
- "button",
100458
- {
100459
- onClick: () => p3.onSetSnapToShape(!p3.snapToShape),
100460
- className: cn(pill, p3.snapToShape ? "bg-primary text-primary-foreground" : ""),
100461
- title: t2("pptx.grid.snapToShape"),
100462
- children: t2("pptx.grid.snapToShape")
100463
- }
100464
- ),
100465
- /* @__PURE__ */ jsxRuntime.jsx("button", { onClick: () => p3.onAddGuide("h"), className: pill, title: "Add horizontal guide", children: "H Guide" }),
100466
- /* @__PURE__ */ jsxRuntime.jsx("button", { onClick: () => p3.onAddGuide("v"), className: pill, title: "Add vertical guide", children: "V Guide" }),
100467
- /* @__PURE__ */ jsxRuntime.jsx(
100468
- "button",
100469
- {
100470
- onClick: () => p3.onSetSpellCheckEnabled(!p3.spellCheckEnabled),
100471
- className: cn(pill, p3.spellCheckEnabled ? "bg-primary text-primary-foreground" : ""),
100472
- title: "Toggle spell check",
100473
- children: "Spell"
100474
- }
100475
- )
100476
- ] });
100477
- }
100478
100935
  function Toolbar(p3) {
100479
100936
  const { mode, isNarrowViewport, isCompactToolbarOpen, toolbarSection, onSetToolbarSection } = p3;
100937
+ if (isNarrowViewport && mode !== "present") {
100938
+ return /* @__PURE__ */ jsxRuntime.jsx(MobileToolbar, { ...p3 });
100939
+ }
100480
100940
  const sFil = toolbarSection === "file";
100481
100941
  const sHome = toolbarSection === "home";
100482
100942
  const sIns = toolbarSection === "insert";
@@ -100562,6 +101022,7 @@ function Toolbar(p3) {
100562
101022
  canEdit: p3.canEdit,
100563
101023
  clipboardPayload: p3.clipboardPayload,
100564
101024
  formatPainterActive: p3.formatPainterActive,
101025
+ canActivateFormatPainter: p3.canActivateFormatPainter,
100565
101026
  onCopy: p3.onCopy,
100566
101027
  onCut: p3.onCut,
100567
101028
  onPaste: p3.onPaste,
@@ -100625,7 +101086,8 @@ function Toolbar(p3) {
100625
101086
  onDuplicate: p3.onDuplicate,
100626
101087
  onDelete: p3.onDelete,
100627
101088
  formatPainterActive: p3.formatPainterActive,
100628
- onToggleFormatPainter: p3.onToggleFormatPainter
101089
+ onToggleFormatPainter: p3.onToggleFormatPainter,
101090
+ canActivateFormatPainter: p3.canActivateFormatPainter
100629
101091
  }
100630
101092
  ),
100631
101093
  sDes && /* @__PURE__ */ jsxRuntime.jsx(
@@ -106338,181 +106800,194 @@ function InspectorPane(props) {
106338
106800
  const fallback = themeOptions[0]?.path ?? "";
106339
106801
  setSelectedThemePath((previous) => previous || fallback);
106340
106802
  }, [slideMasters, themeOptions]);
106341
- return /* @__PURE__ */ jsxRuntime.jsxs(
106342
- "div",
106343
- {
106344
- className: cn(
106345
- // Shared styles
106346
- "bg-background flex flex-col text-xs text-foreground shadow-xl",
106347
- // Mobile: absolute bottom sheet overlay
106348
- "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",
106349
- "max-md:transition-transform max-md:duration-200 max-md:ease-in-out",
106350
- isOpen ? "max-md:translate-y-0" : "max-md:translate-y-full",
106351
- // Desktop: flow-based flex child (takes space from canvas)
106352
- "md:h-full md:border-l md:border-border",
106353
- !panelWidth && "md:w-72"
106354
- ),
106355
- style: panelWidth ? { width: panelWidth } : void 0,
106356
- children: [
106357
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between gap-2 px-3 py-2 border-b border-border", children: [
106358
- /* @__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(
106359
- "button",
106360
- {
106361
- type: "button",
106362
- title: label,
106363
- className: cn(
106364
- "flex items-center gap-1 px-2 py-1 rounded text-[11px] transition-colors",
106365
- activeTab === key ? "bg-primary text-primary-foreground" : "text-muted-foreground hover:text-foreground hover:bg-accent"
106366
- ),
106367
- onClick: () => onSetActiveTab(key),
106368
- children: [
106369
- /* @__PURE__ */ jsxRuntime.jsx(Icon, { className: "w-3.5 h-3.5" }),
106370
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "hidden sm:inline", children: label })
106371
- ]
106372
- },
106373
- key
106374
- )) }),
106375
- /* @__PURE__ */ jsxRuntime.jsx(
106376
- "button",
106377
- {
106378
- type: "button",
106379
- onClick: onClose,
106380
- title: t2("common.close"),
106381
- className: "p-1 rounded text-muted-foreground hover:text-foreground hover:bg-muted transition-colors",
106382
- children: /* @__PURE__ */ jsxRuntime.jsx(lu.LuX, { className: "w-4 h-4" })
106383
- }
106384
- )
106385
- ] }),
106386
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex-1 overflow-y-auto p-3 space-y-3", children: [
106387
- activeTab === "elements" && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-1", children: [
106388
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: cn(HEADING, "mb-2"), children: t2("pptx.inspector.layerOrder") }),
106389
- activeSlide ? [...activeSlide.elements || []].reverse().map((el, ri) => {
106390
- const idx = (activeSlide.elements || []).length - 1 - ri;
106391
- const sel = selectedElement?.id === el.id || selectedElementIds.includes(el.id);
106392
- const label = (pptxViewerCore.hasTextProperties(el) ? (el.text || "").slice(0, 24) : void 0) || el.type;
106393
- return /* @__PURE__ */ jsxRuntime.jsxs(
106394
- "div",
106395
- {
106396
- title: `${el.type} \u2014 ${el.id}`,
106397
- className: cn(
106398
- "flex items-center gap-2 px-2 py-1 rounded cursor-pointer transition-colors",
106399
- sel ? "bg-primary/30 text-primary" : "hover:bg-muted text-foreground"
106400
- ),
106401
- onClick: () => onSelectElement(el.id),
106402
- children: [
106403
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-muted-foreground w-4 text-right", children: idx + 1 }),
106404
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "flex-1 truncate", children: label })
106405
- ]
106406
- },
106407
- el.id
106408
- );
106409
- }) : /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-muted-foreground italic", children: t2("pptx.inspector.noSlideSelected") })
106410
- ] }),
106411
- activeTab === "properties" && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "space-y-3", children: hasSelection && selectedElement ? /* @__PURE__ */ jsxRuntime.jsx(
106412
- ElementInspectorBody,
106413
- {
106414
- selectedElement,
106415
- canEdit,
106416
- slides,
106417
- tableEditorState,
106418
- mediaDataUrls,
106419
- onUpdateElement,
106420
- onUpdateElementStyle,
106421
- onUpdateTextStyle,
106422
- onMoveLayer
106423
- }
106424
- ) : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
106803
+ return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
106804
+ isOpen && /* @__PURE__ */ jsxRuntime.jsx(
106805
+ "button",
106806
+ {
106807
+ type: "button",
106808
+ "aria-label": t2("common.close"),
106809
+ onClick: onClose,
106810
+ className: "md:hidden fixed inset-0 z-20 bg-black/40 backdrop-blur-[2px] animate-in fade-in duration-150"
106811
+ }
106812
+ ),
106813
+ /* @__PURE__ */ jsxRuntime.jsxs(
106814
+ "div",
106815
+ {
106816
+ className: cn(
106817
+ // Shared styles
106818
+ "bg-background flex flex-col text-xs text-foreground shadow-xl",
106819
+ // Mobile: absolute bottom sheet overlay sized via dvh so it
106820
+ // adapts to the on-screen keyboard / dynamic browser chrome.
106821
+ "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)]",
106822
+ "max-md:transition-transform max-md:duration-200 max-md:ease-in-out",
106823
+ isOpen ? "max-md:translate-y-0" : "max-md:translate-y-full",
106824
+ // Desktop: flow-based flex child (takes space from canvas)
106825
+ "md:h-full md:border-l md:border-border",
106826
+ !panelWidth && "md:w-72"
106827
+ ),
106828
+ style: panelWidth ? { width: panelWidth } : void 0,
106829
+ children: [
106830
+ /* @__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" }) }),
106831
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between gap-2 px-3 py-2 border-b border-border", children: [
106832
+ /* @__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(
106833
+ "button",
106834
+ {
106835
+ type: "button",
106836
+ title: label,
106837
+ className: cn(
106838
+ "flex items-center gap-1 px-2 py-1 rounded text-[11px] transition-colors",
106839
+ activeTab === key ? "bg-primary text-primary-foreground" : "text-muted-foreground hover:text-foreground hover:bg-accent"
106840
+ ),
106841
+ onClick: () => onSetActiveTab(key),
106842
+ children: [
106843
+ /* @__PURE__ */ jsxRuntime.jsx(Icon, { className: "w-3.5 h-3.5" }),
106844
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "hidden sm:inline", children: label })
106845
+ ]
106846
+ },
106847
+ key
106848
+ )) }),
106425
106849
  /* @__PURE__ */ jsxRuntime.jsx(
106426
- PresentationPropertiesPanel,
106850
+ "button",
106427
106851
  {
106428
- canEdit,
106429
- canvasSize,
106430
- presentationProperties,
106431
- onUpdatePresentationProperties,
106432
- notesMaster,
106433
- handoutMaster,
106434
- notesCanvasSize,
106435
- coreProperties,
106436
- appProperties,
106437
- customProperties,
106438
- themeOptions,
106439
- selectedThemePath,
106440
- setSelectedThemePath,
106441
- onApplyTheme,
106442
- onUpdateCoreProperties,
106443
- onUpdateAppProperties,
106444
- onUpdateCustomProperties,
106445
- tagCollections,
106446
- onUpdateTagCollections,
106447
- onUpdateCanvasSize,
106448
- activeSlide,
106449
- theme,
106450
- onUpdateSlide
106852
+ type: "button",
106853
+ onClick: onClose,
106854
+ title: t2("common.close"),
106855
+ className: "p-1 rounded text-muted-foreground hover:text-foreground hover:bg-muted transition-colors",
106856
+ children: /* @__PURE__ */ jsxRuntime.jsx(lu.LuX, { className: "w-4 h-4" })
106451
106857
  }
106452
- ),
106453
- activeSlide && /* @__PURE__ */ jsxRuntime.jsx(
106454
- SlideBackgroundPanel,
106858
+ )
106859
+ ] }),
106860
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex-1 overflow-y-auto p-3 space-y-3", children: [
106861
+ activeTab === "elements" && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-1", children: [
106862
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: cn(HEADING, "mb-2"), children: t2("pptx.inspector.layerOrder") }),
106863
+ activeSlide ? [...activeSlide.elements || []].reverse().map((el, ri) => {
106864
+ const idx = (activeSlide.elements || []).length - 1 - ri;
106865
+ const sel = selectedElement?.id === el.id || selectedElementIds.includes(el.id);
106866
+ const label = (pptxViewerCore.hasTextProperties(el) ? (el.text || "").slice(0, 24) : void 0) || el.type;
106867
+ return /* @__PURE__ */ jsxRuntime.jsxs(
106868
+ "div",
106869
+ {
106870
+ title: `${el.type} \u2014 ${el.id}`,
106871
+ className: cn(
106872
+ "flex items-center gap-2 px-2 py-1 rounded cursor-pointer transition-colors",
106873
+ sel ? "bg-primary/30 text-primary" : "hover:bg-muted text-foreground"
106874
+ ),
106875
+ onClick: () => onSelectElement(el.id),
106876
+ children: [
106877
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-muted-foreground w-4 text-right", children: idx + 1 }),
106878
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "flex-1 truncate", children: label })
106879
+ ]
106880
+ },
106881
+ el.id
106882
+ );
106883
+ }) : /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-muted-foreground italic", children: t2("pptx.inspector.noSlideSelected") })
106884
+ ] }),
106885
+ activeTab === "properties" && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "space-y-3", children: hasSelection && selectedElement ? /* @__PURE__ */ jsxRuntime.jsx(
106886
+ ElementInspectorBody,
106455
106887
  {
106456
- activeSlide,
106888
+ selectedElement,
106457
106889
  canEdit,
106458
- onUpdateSlide,
106459
- editTemplateMode,
106460
- slideMasters,
106461
- onSetTemplateBackground,
106462
- onGetTemplateBackgroundColor
106890
+ slides,
106891
+ tableEditorState,
106892
+ mediaDataUrls,
106893
+ onUpdateElement,
106894
+ onUpdateElementStyle,
106895
+ onUpdateTextStyle,
106896
+ onMoveLayer
106463
106897
  }
106464
- )
106465
- ] }) }),
106466
- activeTab === "comments" && /* @__PURE__ */ jsxRuntime.jsx(
106467
- InspectorCommentsSection,
106468
- {
106469
- comments,
106470
- canEdit,
106471
- activeSlide,
106472
- selectedElement,
106473
- editingCommentId,
106474
- commentEditDraft,
106475
- commentDraft,
106476
- replyingToCommentId: replyingToCommentId ?? null,
106477
- replyDraftByCommentId: replyDraftByCommentId ?? {},
106478
- onSetCommentDraft,
106479
- onAddComment,
106480
- onDeleteComment,
106481
- onStartEditComment,
106482
- onSaveEditComment,
106483
- onCancelEditComment,
106484
- onSetCommentEditDraft,
106485
- onToggleCommentResolved,
106486
- onStartReply,
106487
- onCancelReply,
106488
- onReplyDraftChange,
106489
- onSubmitReply,
106490
- onSelectElement
106491
- }
106492
- )
106493
- ] }),
106494
- hasSelection && selectedElement && activeSlide && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
106495
- /* @__PURE__ */ jsxRuntime.jsx(ResizeHandle, { direction: "vertical", onResize: onResizeAnim }),
106496
- /* @__PURE__ */ jsxRuntime.jsx(
106497
- "div",
106498
- {
106499
- className: "border-t border-border p-3 overflow-y-auto flex-shrink-0",
106500
- style: { height: animPanelHeight },
106501
- children: /* @__PURE__ */ jsxRuntime.jsx(
106502
- AnimationPanel,
106898
+ ) : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
106899
+ /* @__PURE__ */ jsxRuntime.jsx(
106900
+ PresentationPropertiesPanel,
106503
106901
  {
106504
- selectedElement,
106505
- activeSlide,
106506
106902
  canEdit,
106903
+ canvasSize,
106904
+ presentationProperties,
106905
+ onUpdatePresentationProperties,
106906
+ notesMaster,
106907
+ handoutMaster,
106908
+ notesCanvasSize,
106909
+ coreProperties,
106910
+ appProperties,
106911
+ customProperties,
106912
+ themeOptions,
106913
+ selectedThemePath,
106914
+ setSelectedThemePath,
106915
+ onApplyTheme,
106916
+ onUpdateCoreProperties,
106917
+ onUpdateAppProperties,
106918
+ onUpdateCustomProperties,
106919
+ tagCollections,
106920
+ onUpdateTagCollections,
106921
+ onUpdateCanvasSize,
106922
+ activeSlide,
106923
+ theme,
106507
106924
  onUpdateSlide
106508
106925
  }
106926
+ ),
106927
+ activeSlide && /* @__PURE__ */ jsxRuntime.jsx(
106928
+ SlideBackgroundPanel,
106929
+ {
106930
+ activeSlide,
106931
+ canEdit,
106932
+ onUpdateSlide,
106933
+ editTemplateMode,
106934
+ slideMasters,
106935
+ onSetTemplateBackground,
106936
+ onGetTemplateBackgroundColor
106937
+ }
106509
106938
  )
106510
- }
106511
- )
106512
- ] })
106513
- ]
106514
- }
106515
- );
106939
+ ] }) }),
106940
+ activeTab === "comments" && /* @__PURE__ */ jsxRuntime.jsx(
106941
+ InspectorCommentsSection,
106942
+ {
106943
+ comments,
106944
+ canEdit,
106945
+ activeSlide,
106946
+ selectedElement,
106947
+ editingCommentId,
106948
+ commentEditDraft,
106949
+ commentDraft,
106950
+ replyingToCommentId: replyingToCommentId ?? null,
106951
+ replyDraftByCommentId: replyDraftByCommentId ?? {},
106952
+ onSetCommentDraft,
106953
+ onAddComment,
106954
+ onDeleteComment,
106955
+ onStartEditComment,
106956
+ onSaveEditComment,
106957
+ onCancelEditComment,
106958
+ onSetCommentEditDraft,
106959
+ onToggleCommentResolved,
106960
+ onStartReply,
106961
+ onCancelReply,
106962
+ onReplyDraftChange,
106963
+ onSubmitReply,
106964
+ onSelectElement
106965
+ }
106966
+ )
106967
+ ] }),
106968
+ hasSelection && selectedElement && activeSlide && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
106969
+ /* @__PURE__ */ jsxRuntime.jsx(ResizeHandle, { direction: "vertical", onResize: onResizeAnim }),
106970
+ /* @__PURE__ */ jsxRuntime.jsx(
106971
+ "div",
106972
+ {
106973
+ className: "border-t border-border p-3 overflow-y-auto flex-shrink-0",
106974
+ style: { height: animPanelHeight },
106975
+ children: /* @__PURE__ */ jsxRuntime.jsx(
106976
+ AnimationPanel,
106977
+ {
106978
+ selectedElement,
106979
+ activeSlide,
106980
+ canEdit,
106981
+ onUpdateSlide
106982
+ }
106983
+ )
106984
+ }
106985
+ )
106986
+ ] })
106987
+ ]
106988
+ }
106989
+ )
106990
+ ] });
106516
106991
  }
106517
106992
  function buildPathD(points) {
106518
106993
  if (points.length === 0) {
@@ -110646,7 +111121,8 @@ function ViewerBottomPanels({
110646
111121
  onZoomToFit,
110647
111122
  mode,
110648
111123
  onSetMode,
110649
- onToggleSlideSorter
111124
+ onToggleSlideSorter,
111125
+ hideStatusBar = false
110650
111126
  }) {
110651
111127
  return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
110652
111128
  onResizeBottom && !isSlideNotesCollapsed && /* @__PURE__ */ jsxRuntime.jsx(ResizeHandle, { direction: "vertical", onResize: onResizeBottom }),
@@ -110662,7 +111138,7 @@ function ViewerBottomPanels({
110662
111138
  panelHeight: notesPanelHeight
110663
111139
  }
110664
111140
  ),
110665
- /* @__PURE__ */ jsxRuntime.jsx(
111141
+ !hideStatusBar && /* @__PURE__ */ jsxRuntime.jsx(
110666
111142
  StatusBar,
110667
111143
  {
110668
111144
  slideCount,
@@ -110819,6 +111295,45 @@ function ViewerInspector({
110819
111295
  }
110820
111296
  );
110821
111297
  }
111298
+
111299
+ // src/viewer/hooks/useScopedLayoutOptions.ts
111300
+ function scopeLayoutOptionsToActiveSlide(options, activeSlide) {
111301
+ if (!activeSlide?.layoutPath) {
111302
+ return options;
111303
+ }
111304
+ const hasAnyMasterInfo = options.some((o3) => o3.masterPath);
111305
+ if (!hasAnyMasterInfo) {
111306
+ return options;
111307
+ }
111308
+ const activeOption = options.find((o3) => o3.path === activeSlide.layoutPath);
111309
+ const activeMaster = activeOption?.masterPath;
111310
+ if (!activeMaster) {
111311
+ return options;
111312
+ }
111313
+ const scoped = options.filter((o3) => o3.masterPath === activeMaster);
111314
+ const seen = /* @__PURE__ */ new Map();
111315
+ for (const opt of scoped) {
111316
+ const isActive = opt.path === activeSlide.layoutPath;
111317
+ const existing = seen.get(opt.name);
111318
+ if (!existing || isActive) {
111319
+ seen.set(opt.name, opt);
111320
+ }
111321
+ }
111322
+ const chosen = new Set(Array.from(seen.values()).map((o3) => o3.path));
111323
+ const result = [];
111324
+ const usedNames = /* @__PURE__ */ new Set();
111325
+ for (const opt of scoped) {
111326
+ if (!chosen.has(opt.path)) {
111327
+ continue;
111328
+ }
111329
+ if (usedNames.has(opt.name)) {
111330
+ continue;
111331
+ }
111332
+ usedNames.add(opt.name);
111333
+ result.push(opt);
111334
+ }
111335
+ return result;
111336
+ }
110822
111337
  function ViewerToolbarSection(props) {
110823
111338
  const {
110824
111339
  mode,
@@ -110888,6 +111403,10 @@ function ViewerToolbarSection(props) {
110888
111403
  },
110889
111404
  [activeSlide, propertyHandlers]
110890
111405
  );
111406
+ const scopedLayoutOptions = React10__namespace.default.useMemo(
111407
+ () => scopeLayoutOptionsToActiveSlide(s.layoutOptions, activeSlide),
111408
+ [s.layoutOptions, activeSlide]
111409
+ );
110891
111410
  const handleApplyTransitionToAll = React10.useCallback(() => {
110892
111411
  const transition = activeSlide?.transition;
110893
111412
  if (!transition) {
@@ -110994,7 +111513,7 @@ function ViewerToolbarSection(props) {
110994
111513
  onUpdateTextStyle: ops.updateSelectedTextStyle,
110995
111514
  isOverflowMenuOpen: s.isOverflowMenuOpen,
110996
111515
  onSetOverflowMenuOpen: s.setIsOverflowMenuOpen,
110997
- layoutOptions: s.layoutOptions,
111516
+ layoutOptions: scopedLayoutOptions,
110998
111517
  onInsertSlideFromLayout: slideOps.handleInsertSlideFromLayout,
110999
111518
  customShows: s.customShows,
111000
111519
  activeCustomShowId: s.activeCustomShowId,
@@ -111027,6 +111546,7 @@ function ViewerToolbarSection(props) {
111027
111546
  isCommentsPanelOpen: s.isInspectorPaneOpen,
111028
111547
  slideCommentCount: activeSlide?.comments?.length ?? 0,
111029
111548
  formatPainterActive: s.formatPainterActive,
111549
+ canActivateFormatPainter: hasCopyableFormat(selectedElement),
111030
111550
  onToggleFormatPainter: onToggleFormatPainterProp ?? (() => s.setFormatPainterActive((p3) => !p3)),
111031
111551
  isSelectionPaneOpen: s.isSelectionPaneOpen,
111032
111552
  onToggleSelectionPane: () => s.setIsSelectionPaneOpen((p3) => !p3),
@@ -114175,6 +114695,166 @@ function ViewerMainContent(props) {
114175
114695
  )
114176
114696
  ] });
114177
114697
  }
114698
+ function MobileBottomBar({
114699
+ onOpenSlides,
114700
+ onOpenInsert,
114701
+ onOpenInspector,
114702
+ onOpenComments,
114703
+ onToggleNotes,
114704
+ activeSheet,
114705
+ commentCount
114706
+ }) {
114707
+ const actions = [
114708
+ {
114709
+ key: "slides",
114710
+ label: "Slides",
114711
+ icon: lu.LuLayers,
114712
+ onClick: onOpenSlides
114713
+ },
114714
+ {
114715
+ key: "insert",
114716
+ label: "Insert",
114717
+ icon: lu.LuPlus,
114718
+ onClick: onOpenInsert
114719
+ },
114720
+ {
114721
+ key: "inspector",
114722
+ label: "Format",
114723
+ icon: lu.LuSettings2,
114724
+ onClick: onOpenInspector
114725
+ },
114726
+ {
114727
+ key: "comments",
114728
+ label: "Comments",
114729
+ icon: lu.LuMessageSquare,
114730
+ onClick: onOpenComments,
114731
+ badge: commentCount
114732
+ },
114733
+ {
114734
+ key: "notes",
114735
+ label: "Notes",
114736
+ icon: lu.LuStickyNote,
114737
+ onClick: onToggleNotes
114738
+ }
114739
+ ];
114740
+ return /* @__PURE__ */ jsxRuntime.jsx(
114741
+ "nav",
114742
+ {
114743
+ "aria-label": "Editor actions",
114744
+ 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)]",
114745
+ children: actions.map(({ key, label, icon: Icon, onClick, badge }) => {
114746
+ const active = activeSheet === key;
114747
+ return /* @__PURE__ */ jsxRuntime.jsxs(
114748
+ "button",
114749
+ {
114750
+ type: "button",
114751
+ onClick,
114752
+ className: cn(
114753
+ "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",
114754
+ active ? "text-primary" : "text-muted-foreground hover:text-foreground"
114755
+ ),
114756
+ "aria-pressed": active,
114757
+ children: [
114758
+ /* @__PURE__ */ jsxRuntime.jsx(Icon, { className: "w-5 h-5" }),
114759
+ /* @__PURE__ */ jsxRuntime.jsx("span", { children: label }),
114760
+ 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 }),
114761
+ 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" })
114762
+ ]
114763
+ },
114764
+ key
114765
+ );
114766
+ })
114767
+ }
114768
+ );
114769
+ }
114770
+ function MobileSlidesSheet({
114771
+ open,
114772
+ onClose,
114773
+ ...sidebar
114774
+ }) {
114775
+ 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 }) }) });
114776
+ }
114777
+ function MobileChromeOverlay(props) {
114778
+ const {
114779
+ state: s,
114780
+ editorOps,
114781
+ presentation,
114782
+ slides,
114783
+ activeSlideIndex,
114784
+ canvasSize,
114785
+ slideSectionGroups,
114786
+ canEdit,
114787
+ commentCount
114788
+ } = props;
114789
+ const activeSheet = s.isSlidesPaneOpen ? "slides" : s.isInspectorPaneOpen ? s.sidebarPanelMode === "comments" ? "comments" : "inspector" : !s.isSlideNotesCollapsed ? "notes" : null;
114790
+ const closeAllSheets = () => {
114791
+ s.setIsSlidesPaneOpen(false);
114792
+ s.setIsInspectorPaneOpen(false);
114793
+ s.setIsSlideNotesCollapsed(true);
114794
+ };
114795
+ const openSheet = (which) => {
114796
+ closeAllSheets();
114797
+ switch (which) {
114798
+ case "slides":
114799
+ s.setIsSlidesPaneOpen(true);
114800
+ break;
114801
+ case "inspector":
114802
+ s.setSidebarPanelMode("properties");
114803
+ s.setIsInspectorPaneOpen(true);
114804
+ break;
114805
+ case "comments":
114806
+ s.setSidebarPanelMode("comments");
114807
+ s.setIsInspectorPaneOpen(true);
114808
+ break;
114809
+ case "notes":
114810
+ s.setIsSlideNotesCollapsed(false);
114811
+ break;
114812
+ }
114813
+ };
114814
+ return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
114815
+ /* @__PURE__ */ jsxRuntime.jsx(
114816
+ MobileSlidesSheet,
114817
+ {
114818
+ open: s.isSlidesPaneOpen,
114819
+ onClose: () => s.setIsSlidesPaneOpen(false),
114820
+ slides,
114821
+ activeSlideIndex,
114822
+ canvasSize,
114823
+ sectionGroups: slideSectionGroups,
114824
+ isOpen: true,
114825
+ canEdit,
114826
+ onSelectSlide: (index) => {
114827
+ s.setActiveSlideIndex(index);
114828
+ s.setIsSlidesPaneOpen(false);
114829
+ },
114830
+ onSlideContextMenu: editorOps.slideOps.handleSlideContextMenu,
114831
+ onMoveSlide: editorOps.slideOps.handleMoveSlide,
114832
+ onAddSlide: editorOps.slideOps.handleAddSlide,
114833
+ onCollapse: () => s.setIsSlidesPaneOpen(false),
114834
+ onAddSection: editorOps.sectionOps.addSection,
114835
+ onRenameSection: editorOps.sectionOps.renameSection,
114836
+ onDeleteSection: editorOps.sectionOps.deleteSection,
114837
+ onMoveSectionUp: editorOps.sectionOps.moveSectionUp,
114838
+ onMoveSectionDown: editorOps.sectionOps.moveSectionDown,
114839
+ rehearsalTimings: Object.keys(presentation.recordedTimings).length > 0 ? presentation.recordedTimings : void 0
114840
+ }
114841
+ ),
114842
+ /* @__PURE__ */ jsxRuntime.jsx(
114843
+ MobileBottomBar,
114844
+ {
114845
+ activeSheet,
114846
+ commentCount,
114847
+ onOpenSlides: () => s.isSlidesPaneOpen ? s.setIsSlidesPaneOpen(false) : openSheet("slides"),
114848
+ onOpenInsert: () => {
114849
+ editorOps.insertHandlers.handleAddTextBox();
114850
+ },
114851
+ onOpenInspector: () => s.isInspectorPaneOpen && s.sidebarPanelMode !== "comments" ? s.setIsInspectorPaneOpen(false) : openSheet("inspector"),
114852
+ onOpenComments: () => s.isInspectorPaneOpen && s.sidebarPanelMode === "comments" ? s.setIsInspectorPaneOpen(false) : openSheet("comments"),
114853
+ onToggleNotes: () => !s.isSlideNotesCollapsed ? s.setIsSlideNotesCollapsed(true) : openSheet("notes")
114854
+ }
114855
+ )
114856
+ ] });
114857
+ }
114178
114858
  function ToggleSwitch({
114179
114859
  label,
114180
114860
  enabled,
@@ -114367,14 +115047,10 @@ function useYjsDocumentSync({
114367
115047
  const lastSyncedRef = React10.useRef("");
114368
115048
  const hasInitializedRef = React10.useRef(false);
114369
115049
  const getDocMap = React10.useCallback(() => {
114370
- if (!doc2 || typeof doc2 !== "object") {
115050
+ if (!doc2) {
114371
115051
  return null;
114372
115052
  }
114373
- const d = doc2;
114374
- if (typeof d.getMap !== "function") {
114375
- return null;
114376
- }
114377
- return d.getMap("slides-data");
115053
+ return doc2.getMap("slides-data");
114378
115054
  }, [doc2]);
114379
115055
  React10.useEffect(() => {
114380
115056
  if (!isConnected || !doc2) {
@@ -114395,10 +115071,9 @@ function useYjsDocumentSync({
114395
115071
  return;
114396
115072
  }
114397
115073
  lastSyncedRef.current = serialized;
114398
- const d = doc2;
114399
- d.transact(() => {
115074
+ doc2.transact(() => {
114400
115075
  const currentCount = map3.get("count");
114401
- if (currentCount && currentCount > slides.length) {
115076
+ if (typeof currentCount === "number" && currentCount > slides.length) {
114402
115077
  for (let i3 = slides.length; i3 < currentCount; i3++) {
114403
115078
  map3.delete(`slide-${i3}`);
114404
115079
  }
@@ -114423,13 +115098,13 @@ function useYjsDocumentSync({
114423
115098
  }
114424
115099
  const handleUpdate = () => {
114425
115100
  const count = map3.get("count");
114426
- if (!count || count === 0) {
115101
+ if (typeof count !== "number" || count === 0) {
114427
115102
  return;
114428
115103
  }
114429
115104
  const remoteSlides = [];
114430
115105
  for (let i3 = 0; i3 < count; i3++) {
114431
115106
  const slideJson = map3.get(`slide-${i3}`);
114432
- if (slideJson) {
115107
+ if (typeof slideJson === "string") {
114433
115108
  try {
114434
115109
  remoteSlides.push(JSON.parse(slideJson));
114435
115110
  } catch {
@@ -114454,7 +115129,7 @@ function useYjsDocumentSync({
114454
115129
  if (!hasInitializedRef.current) {
114455
115130
  hasInitializedRef.current = true;
114456
115131
  const count = map3.get("count");
114457
- if (count && count > 0) {
115132
+ if (typeof count === "number" && count > 0) {
114458
115133
  handleUpdate();
114459
115134
  }
114460
115135
  }
@@ -115015,13 +115690,14 @@ function useCanvasInteractions(input) {
115015
115690
  if (e2.button !== 0) {
115016
115691
  return;
115017
115692
  }
115018
- if (!selectedElementIdSet.has(elementId)) {
115693
+ const wasSelected = selectedElementIdSet.has(elementId);
115694
+ if (!wasSelected) {
115019
115695
  ops.applySelection(elementId);
115020
115696
  justSelectedRef.current = true;
115021
115697
  } else {
115022
115698
  justSelectedRef.current = false;
115023
115699
  }
115024
- const ids = effectiveSelectedIds.length ? effectiveSelectedIds : [elementId];
115700
+ const ids = !wasSelected ? [elementId] : effectiveSelectedIds.length ? effectiveSelectedIds : [elementId];
115025
115701
  const startPositions = {};
115026
115702
  const domEls = /* @__PURE__ */ new Map();
115027
115703
  for (const id2 of ids) {
@@ -117058,8 +117734,14 @@ function useSectionOperations(input) {
117058
117734
  }
117059
117735
 
117060
117736
  // src/viewer/hooks/useSlideManagement.ts
117737
+ function insertSlideFromLayoutUpdater(slides, activeIndex, draft) {
117738
+ const next = [...slides];
117739
+ const insertAt = Math.max(0, Math.min(activeIndex + 1, next.length));
117740
+ next.splice(insertAt, 0, draft);
117741
+ return next;
117742
+ }
117061
117743
  function useSlideManagement(input) {
117062
- const { slides, activeSlideIndex, setActiveSlideIndex, ops, history } = input;
117744
+ const { slides, activeSlideIndex, setActiveSlideIndex, ops, history, handlerRef } = input;
117063
117745
  const handleAddSlide = () => {
117064
117746
  const newSlide = {
117065
117747
  id: `slide-${Date.now()}-${Math.random().toString(36).slice(2, 6)}`,
@@ -117158,8 +117840,42 @@ function useSlideManagement(input) {
117158
117840
  });
117159
117841
  history.markDirty();
117160
117842
  };
117161
- const handleInsertSlideFromLayout = (_layoutPath) => {
117162
- handleAddSlide();
117843
+ const handleInsertSlideFromLayout = (layoutPath, layoutName) => {
117844
+ const insertAt = activeSlideIndex + 1;
117845
+ const draft = {
117846
+ id: `slide-${Date.now()}-${Math.random().toString(36).slice(2, 6)}`,
117847
+ rId: "",
117848
+ slideNumber: slides.length + 1,
117849
+ elements: [],
117850
+ layoutPath,
117851
+ ...layoutName ? { layoutName } : {}
117852
+ };
117853
+ let inserted = [];
117854
+ ops.updateSlides((prev) => {
117855
+ inserted = insertSlideFromLayoutUpdater(prev, activeSlideIndex, draft);
117856
+ return inserted;
117857
+ });
117858
+ setActiveSlideIndex(insertAt);
117859
+ history.markDirty();
117860
+ const handler = handlerRef?.current;
117861
+ if (handler) {
117862
+ void handler.applyLayoutToSlide(insertAt, layoutPath, inserted).then(
117863
+ (updated) => {
117864
+ ops.updateSlides((prev) => {
117865
+ if (prev[insertAt]?.id !== draft.id) {
117866
+ return prev;
117867
+ }
117868
+ const next = [...prev];
117869
+ next[insertAt] = updated;
117870
+ return next;
117871
+ });
117872
+ return void 0;
117873
+ },
117874
+ () => {
117875
+ return void 0;
117876
+ }
117877
+ );
117878
+ }
117163
117879
  };
117164
117880
  return {
117165
117881
  handleAddSlide,
@@ -117695,7 +118411,8 @@ function useEditorOperations(input) {
117695
118411
  canvasSize,
117696
118412
  dialogs,
117697
118413
  presentation,
117698
- userName
118414
+ userName,
118415
+ handlerRef
117699
118416
  } = input;
117700
118417
  const ops = useElementOperations({
117701
118418
  activeSlide,
@@ -117797,7 +118514,8 @@ function useEditorOperations(input) {
117797
118514
  activeSlideIndex,
117798
118515
  setActiveSlideIndex: state2.setActiveSlideIndex,
117799
118516
  ops,
117800
- history
118517
+ history,
118518
+ handlerRef
117801
118519
  });
117802
118520
  const tableOps = useTableOperations({
117803
118521
  selectedElement,
@@ -117826,21 +118544,34 @@ function useEditorOperations(input) {
117826
118544
  );
117827
118545
  const copiedFormatRef = React10.useRef(null);
117828
118546
  const prevFormatPainterRef = React10.useRef(false);
118547
+ const { formatPainterActive, setFormatPainterActive, elementLookup } = state2;
117829
118548
  React10.useEffect(() => {
117830
- if (state2.formatPainterActive && !prevFormatPainterRef.current && selectedElement) {
118549
+ if (formatPainterActive && !prevFormatPainterRef.current && selectedElement) {
117831
118550
  copiedFormatRef.current = copyFormatFromElement(selectedElement);
117832
- } else if (!state2.formatPainterActive) {
118551
+ } else if (!formatPainterActive) {
117833
118552
  copiedFormatRef.current = null;
117834
118553
  }
117835
- prevFormatPainterRef.current = state2.formatPainterActive;
117836
- }, [state2.formatPainterActive, selectedElement]);
118554
+ prevFormatPainterRef.current = formatPainterActive;
118555
+ }, [formatPainterActive, selectedElement]);
118556
+ React10.useEffect(() => {
118557
+ if (!formatPainterActive) {
118558
+ return;
118559
+ }
118560
+ const onKey = (e2) => {
118561
+ if (e2.key === "Escape") {
118562
+ setFormatPainterActive(false);
118563
+ }
118564
+ };
118565
+ window.addEventListener("keydown", onKey);
118566
+ return () => window.removeEventListener("keydown", onKey);
118567
+ }, [formatPainterActive, setFormatPainterActive]);
117837
118568
  const formatPainterCanvasHandlers = React10.useMemo(
117838
118569
  () => ({
117839
118570
  ...canvasHandlers,
117840
118571
  handleElementClick: (elementId, e2) => {
117841
- if (state2.formatPainterActive && copiedFormatRef.current) {
118572
+ if (formatPainterActive && copiedFormatRef.current) {
117842
118573
  e2.stopPropagation();
117843
- const element2 = state2.elementLookup.get(elementId);
118574
+ const element2 = elementLookup.get(elementId);
117844
118575
  if (element2) {
117845
118576
  const updated = applyFormatToElement(element2, copiedFormatRef.current);
117846
118577
  const updates = {};
@@ -117853,14 +118584,21 @@ function useEditorOperations(input) {
117853
118584
  ops.updateElementById(elementId, updates);
117854
118585
  }
117855
118586
  copiedFormatRef.current = null;
117856
- state2.setFormatPainterActive(false);
118587
+ setFormatPainterActive(false);
117857
118588
  ops.applySelection(elementId);
117858
118589
  return;
117859
118590
  }
117860
118591
  canvasHandlers.handleElementClick(elementId, e2);
118592
+ },
118593
+ handleCanvasMouseDown: (e2) => {
118594
+ if (formatPainterActive) {
118595
+ setFormatPainterActive(false);
118596
+ return;
118597
+ }
118598
+ canvasHandlers.handleCanvasMouseDown(e2);
117861
118599
  }
117862
118600
  }),
117863
- [canvasHandlers, ops, state2]
118601
+ [canvasHandlers, ops, formatPainterActive, setFormatPainterActive, elementLookup]
117864
118602
  );
117865
118603
  return {
117866
118604
  ops: combinedOps,
@@ -119999,21 +120737,35 @@ function useViewerDialogs(input) {
119999
120737
  null
120000
120738
  );
120001
120739
  const [embedFontsEnabled, setEmbedFontsEnabled] = React10.useState(false);
120002
- const [isNarrowViewport, setIsNarrowViewport] = React10.useState(false);
120740
+ const [isNarrowViewport, setIsNarrowViewport] = React10.useState(
120741
+ () => typeof window !== "undefined" ? window.innerWidth < 768 : false
120742
+ );
120003
120743
  React10.useEffect(() => {
120004
- const el = containerRef.current;
120005
- if (!el) {
120006
- return;
120007
- }
120008
- const observer = new ResizeObserver((entries) => {
120009
- const entry = entries[0];
120010
- if (entry) {
120011
- setIsNarrowViewport(entry.contentRect.width < 768);
120744
+ const handleWindow = () => setIsNarrowViewport(window.innerWidth < 768);
120745
+ let observer = null;
120746
+ let raf = 0;
120747
+ const attach2 = () => {
120748
+ const el = containerRef.current;
120749
+ if (!el) {
120750
+ raf = requestAnimationFrame(attach2);
120751
+ return;
120012
120752
  }
120013
- });
120014
- observer.observe(el);
120015
- setIsNarrowViewport(el.clientWidth < 768);
120016
- return () => observer.disconnect();
120753
+ observer = new ResizeObserver((entries) => {
120754
+ const entry = entries[0];
120755
+ if (entry) {
120756
+ setIsNarrowViewport(entry.contentRect.width < 768);
120757
+ }
120758
+ });
120759
+ observer.observe(el);
120760
+ setIsNarrowViewport(el.clientWidth < 768);
120761
+ };
120762
+ attach2();
120763
+ window.addEventListener("resize", handleWindow);
120764
+ return () => {
120765
+ cancelAnimationFrame(raf);
120766
+ observer?.disconnect();
120767
+ window.removeEventListener("resize", handleWindow);
120768
+ };
120017
120769
  }, []);
120018
120770
  React10.useEffect(() => {
120019
120771
  if (isDirty && hasDigitalSignatures && !signatureStripAcknowledgedRef.current) {
@@ -124485,7 +125237,9 @@ function useViewerCoreState(_input) {
124485
125237
  function useViewerUIState() {
124486
125238
  const [isCompactToolbarOpen, setIsCompactToolbarOpen] = React10.useState(false);
124487
125239
  const [toolbarSection, setToolbarSection] = React10.useState("home");
124488
- const [isSlidesPaneOpen, setIsSlidesPaneOpen] = React10.useState(true);
125240
+ const [isSlidesPaneOpen, setIsSlidesPaneOpen] = React10.useState(
125241
+ () => typeof window === "undefined" ? true : window.innerWidth >= 768
125242
+ );
124489
125243
  const [isInspectorPaneOpen, setIsInspectorPaneOpen] = React10.useState(false);
124490
125244
  const [isSlideNotesCollapsed, setIsSlideNotesCollapsed] = React10.useState(true);
124491
125245
  const [isOverflowMenuOpen, setIsOverflowMenuOpen] = React10.useState(false);
@@ -124928,7 +125682,8 @@ var PowerPointViewer = React10.forwardRef(
124928
125682
  canvasSize,
124929
125683
  dialogs,
124930
125684
  presentation,
124931
- userName: authorName ?? collaboration?.userName
125685
+ userName: authorName ?? collaboration?.userName,
125686
+ handlerRef: actionSoundHandlerRef
124932
125687
  });
124933
125688
  const {
124934
125689
  exportHandlers,
@@ -125051,7 +125806,7 @@ var PowerPointViewer = React10.forwardRef(
125051
125806
  {
125052
125807
  activeSlide,
125053
125808
  allSlides: slides,
125054
- isSlideNotesCollapsed: isMobile || state2.isSlideNotesCollapsed,
125809
+ isSlideNotesCollapsed: state2.isSlideNotesCollapsed,
125055
125810
  canEdit,
125056
125811
  slideCount: slides.length,
125057
125812
  activeSlideIndex,
@@ -125068,7 +125823,22 @@ var PowerPointViewer = React10.forwardRef(
125068
125823
  onZoomToFit: zoom.handleZoomToFit,
125069
125824
  mode,
125070
125825
  onSetMode: handleSetMode,
125071
- onToggleSlideSorter: () => state2.setShowSlideSorter((p3) => !p3)
125826
+ onToggleSlideSorter: () => state2.setShowSlideSorter((p3) => !p3),
125827
+ hideStatusBar: isMobile
125828
+ }
125829
+ ),
125830
+ mode !== "present" && isMobile && /* @__PURE__ */ jsxRuntime.jsx(
125831
+ MobileChromeOverlay,
125832
+ {
125833
+ state: state2,
125834
+ editorOps,
125835
+ presentation,
125836
+ slides,
125837
+ activeSlideIndex,
125838
+ canvasSize,
125839
+ slideSectionGroups,
125840
+ canEdit,
125841
+ commentCount: activeSlide?.comments?.length ?? 0
125072
125842
  }
125073
125843
  ),
125074
125844
  /* @__PURE__ */ jsxRuntime.jsx(