@files-preview-app/preview-file 1.3.7 → 1.3.9

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.
package/dist/index.cjs CHANGED
@@ -1171,6 +1171,10 @@ var FilePreviewViewer = class _FilePreviewViewer {
1171
1171
  * Preview a file in the given container element.
1172
1172
  */
1173
1173
  async preview(container, source, options = {}) {
1174
+ options = {
1175
+ ...options,
1176
+ fitMode: options.fitMode ?? "width"
1177
+ };
1174
1178
  this.currentOptions = options;
1175
1179
  this.abort();
1176
1180
  this.abortController = new AbortController();
@@ -1219,8 +1223,8 @@ var FilePreviewViewer = class _FilePreviewViewer {
1219
1223
  this.activeInstance = instance;
1220
1224
  instance.openInSeparateWindow = () => this.openInSeparateWindow();
1221
1225
  instance.toggleThumbnails = () => this.toggleThumbnails();
1222
- if (!instance.resetZoom && instance.fitToPage) {
1223
- instance.resetZoom = () => instance.fitToPage?.();
1226
+ if (!instance.resetZoom) {
1227
+ instance.resetZoom = () => instance.fitToWidth ? instance.fitToWidth() : instance.fitToPage?.();
1224
1228
  }
1225
1229
  this.hideLoading();
1226
1230
  this.eventEmitter.emit("loaded", { metadata, plugin: matchedPlugin.id });
@@ -1617,7 +1621,7 @@ var FilePreviewViewer = class _FilePreviewViewer {
1617
1621
  this.wrapperEl?.classList.toggle("fp-fullscreen-active");
1618
1622
  }
1619
1623
  setTimeout(() => {
1620
- this.activeInstance?.fitToPage?.();
1624
+ this.triggerAutoFit();
1621
1625
  }, 120);
1622
1626
  }
1623
1627
  /**
@@ -1709,19 +1713,85 @@ var FilePreviewViewer = class _FilePreviewViewer {
1709
1713
  if (this.wrapperEl?.parentNode) {
1710
1714
  this.wrapperEl.parentNode.removeChild(this.wrapperEl);
1711
1715
  }
1716
+ if (typeof document !== "undefined" && !document.getElementById("fp-core-injected-styles")) {
1717
+ const styleEl = document.createElement("style");
1718
+ styleEl.id = "fp-core-injected-styles";
1719
+ styleEl.textContent = `
1720
+ .fp-viewer {
1721
+ display: flex !important;
1722
+ flex-direction: column !important;
1723
+ width: 100% !important;
1724
+ height: 100% !important;
1725
+ overflow: hidden !important;
1726
+ position: relative !important;
1727
+ box-sizing: border-box !important;
1728
+ }
1729
+ .fp-body {
1730
+ display: flex !important;
1731
+ flex: 1 1 0% !important;
1732
+ min-height: 0 !important;
1733
+ min-width: 0 !important;
1734
+ width: 100% !important;
1735
+ height: 100% !important;
1736
+ overflow: hidden !important;
1737
+ position: relative !important;
1738
+ box-sizing: border-box !important;
1739
+ }
1740
+ .fp-content {
1741
+ flex: 1 1 0% !important;
1742
+ position: relative !important;
1743
+ overflow: auto !important;
1744
+ display: flex !important;
1745
+ flex-direction: column !important;
1746
+ align-items: stretch !important;
1747
+ justify-content: flex-start !important;
1748
+ width: 100% !important;
1749
+ height: 100% !important;
1750
+ min-width: 0 !important;
1751
+ min-height: 0 !important;
1752
+ box-sizing: border-box !important;
1753
+ }
1754
+ `;
1755
+ document.head.appendChild(styleEl);
1756
+ }
1712
1757
  const themeClass = options.theme === "dark" ? "fp-theme-dark" : "";
1713
1758
  const toolbarPos = options.toolbarPosition ?? "top";
1714
1759
  this.wrapperEl = document.createElement("div");
1715
1760
  this.wrapperEl.className = `fp-viewer ${themeClass} ${options.className ?? ""}`.trim();
1716
1761
  this.wrapperEl.tabIndex = 0;
1762
+ this.wrapperEl.style.display = "flex";
1763
+ this.wrapperEl.style.flexDirection = "column";
1764
+ this.wrapperEl.style.width = "100%";
1765
+ this.wrapperEl.style.height = "100%";
1766
+ this.wrapperEl.style.overflow = "hidden";
1767
+ this.wrapperEl.style.position = "relative";
1717
1768
  const toolbarEl = document.createElement("div");
1718
1769
  toolbarEl.className = "fp-toolbar-container";
1719
1770
  this.contentEl = document.createElement("div");
1720
1771
  this.contentEl.className = "fp-content";
1772
+ this.contentEl.style.flex = "1 1 0%";
1773
+ this.contentEl.style.position = "relative";
1774
+ this.contentEl.style.overflow = "auto";
1775
+ this.contentEl.style.display = "flex";
1776
+ this.contentEl.style.flexDirection = "column";
1777
+ this.contentEl.style.alignItems = "stretch";
1778
+ this.contentEl.style.justifyContent = "flex-start";
1779
+ this.contentEl.style.width = "100%";
1780
+ this.contentEl.style.height = "100%";
1781
+ this.contentEl.style.minWidth = "0";
1782
+ this.contentEl.style.minHeight = "0";
1783
+ this.contentEl.style.boxSizing = "border-box";
1721
1784
  const thumbnailEl = document.createElement("div");
1722
1785
  thumbnailEl.className = "fp-thumbnail-container";
1723
1786
  const bodyEl = document.createElement("div");
1724
1787
  bodyEl.className = "fp-body";
1788
+ bodyEl.style.display = "flex";
1789
+ bodyEl.style.flex = "1 1 0%";
1790
+ bodyEl.style.minHeight = "0";
1791
+ bodyEl.style.minWidth = "0";
1792
+ bodyEl.style.width = "100%";
1793
+ bodyEl.style.overflow = "hidden";
1794
+ bodyEl.style.position = "relative";
1725
1795
  bodyEl.appendChild(thumbnailEl);
1726
1796
  bodyEl.appendChild(this.contentEl);
1727
1797
  const titleBarEl = document.createElement("div");
@@ -1744,18 +1814,29 @@ var FilePreviewViewer = class _FilePreviewViewer {
1744
1814
  this.thumbnailPanel = new ThumbnailPanel(thumbnailEl, (isOpen) => {
1745
1815
  this.toolbar?.setActionActive("thumbnails", isOpen);
1746
1816
  setTimeout(() => {
1747
- this.activeInstance?.fitToPage?.();
1817
+ this.triggerAutoFit();
1748
1818
  }, 260);
1749
1819
  });
1750
1820
  this.setupKeyboardShortcuts();
1751
1821
  this.setupDragAndDrop(container, options);
1752
1822
  this.setupResizeAndFullscreenListeners();
1753
1823
  }
1824
+ triggerAutoFit() {
1825
+ if (!this.activeInstance) return;
1826
+ const mode = this.currentOptions?.fitMode ?? "width";
1827
+ if (mode === "width" && this.activeInstance.fitToWidth) {
1828
+ this.activeInstance.fitToWidth();
1829
+ } else if (this.activeInstance.fitToPage) {
1830
+ this.activeInstance.fitToPage();
1831
+ } else if (this.activeInstance.resetZoom) {
1832
+ this.activeInstance.resetZoom();
1833
+ }
1834
+ }
1754
1835
  setupResizeAndFullscreenListeners() {
1755
1836
  if (this.fullscreenHandler) return;
1756
1837
  this.fullscreenHandler = () => {
1757
1838
  setTimeout(() => {
1758
- this.activeInstance?.fitToPage?.();
1839
+ this.triggerAutoFit();
1759
1840
  }, 100);
1760
1841
  };
1761
1842
  document.addEventListener("fullscreenchange", this.fullscreenHandler);
@@ -1763,7 +1844,7 @@ var FilePreviewViewer = class _FilePreviewViewer {
1763
1844
  if (typeof ResizeObserver !== "undefined" && this.contentEl) {
1764
1845
  this.resizeObserver = new ResizeObserver(() => {
1765
1846
  if (this.activeInstance && (!this.activeInstance.getZoom || Math.abs((this.activeInstance.getZoom?.() ?? 1) - 1) < 0.05)) {
1766
- this.activeInstance.fitToPage?.();
1847
+ this.triggerAutoFit();
1767
1848
  }
1768
1849
  });
1769
1850
  this.resizeObserver.observe(this.contentEl);
@@ -1791,7 +1872,7 @@ var FilePreviewViewer = class _FilePreviewViewer {
1791
1872
  } else if (e.key === "-" || e.key === "_") {
1792
1873
  this.activeInstance.zoomOut?.();
1793
1874
  } else if (e.key === "0") {
1794
- this.activeInstance.fitToPage?.();
1875
+ this.resetZoom();
1795
1876
  } else if (e.key === "r" || e.key === "R") {
1796
1877
  this.activeInstance.rotateCW?.();
1797
1878
  } else if (e.key === "f" || e.key === "F") {
@@ -2414,7 +2495,7 @@ var PdfPlugin = class {
2414
2495
  renderPage(currentPage);
2415
2496
  },
2416
2497
  resetZoom: () => {
2417
- fitMode = "page";
2498
+ fitMode = ctx?.options?.fitMode || "width";
2418
2499
  zoomScale = 1;
2419
2500
  rotation = 0;
2420
2501
  container.scrollTop = 0;
@@ -2598,6 +2679,16 @@ var MediaPlugin = class {
2598
2679
  instance.resetZoom?.();
2599
2680
  }
2600
2681
  },
2682
+ {
2683
+ id: "fit-width",
2684
+ icon: "fit-width",
2685
+ label: "Fit to Width",
2686
+ type: "button",
2687
+ group: "zoom",
2688
+ execute: () => {
2689
+ instance.fitToWidth?.();
2690
+ }
2691
+ },
2601
2692
  {
2602
2693
  id: "rotate-cw",
2603
2694
  icon: "rotate-cw",
@@ -2694,9 +2785,30 @@ var MediaPlugin = class {
2694
2785
  const isVideo = mimeType.startsWith("video/") || VIDEO_EXTS.includes(ctx.metadata.extension || "");
2695
2786
  const isAudio = mimeType.startsWith("audio/") || AUDIO_EXTS.includes(ctx.metadata.extension || "");
2696
2787
  let url = "";
2788
+ let naturalW = 800;
2789
+ let naturalH = 600;
2697
2790
  if (ctx.metadata.extension === ".svg" || mimeType === "image/svg+xml") {
2698
2791
  const decoder = new TextDecoder("utf-8");
2699
2792
  const svgText = decoder.decode(ctx.buffer);
2793
+ try {
2794
+ const vbMatch = svgText.match(/viewBox=["']\s*([0-9.-]+)\s+([0-9.-]+)\s+([0-9.-]+)\s+([0-9.-]+)\s*["']/i);
2795
+ if (vbMatch) {
2796
+ const vw = parseFloat(vbMatch[3]);
2797
+ const vh = parseFloat(vbMatch[4]);
2798
+ if (vw > 0 && vh > 0) {
2799
+ naturalW = vw;
2800
+ naturalH = vh;
2801
+ }
2802
+ } else {
2803
+ const wMatch = svgText.match(/width=["']([0-9.]+)(?:px)?["']/i);
2804
+ const hMatch = svgText.match(/height=["']([0-9.]+)(?:px)?["']/i);
2805
+ if (wMatch && hMatch) {
2806
+ naturalW = parseFloat(wMatch[1]) || naturalW;
2807
+ naturalH = parseFloat(hMatch[1]) || naturalH;
2808
+ }
2809
+ }
2810
+ } catch {
2811
+ }
2700
2812
  const blob = new Blob([svgText], { type: "image/svg+xml" });
2701
2813
  url = URL.createObjectURL(blob);
2702
2814
  } else {
@@ -2744,7 +2856,7 @@ var MediaPlugin = class {
2744
2856
  scrollWrapper.style.width = "max-content";
2745
2857
  scrollWrapper.style.height = "max-content";
2746
2858
  scrollWrapper.style.display = "flex";
2747
- scrollWrapper.style.justifyContent = "center";
2859
+ scrollWrapper.style.flexDirection = "column";
2748
2860
  scrollWrapper.style.alignItems = "center";
2749
2861
  scrollWrapper.style.padding = "16px";
2750
2862
  scrollWrapper.style.boxSizing = "border-box";
@@ -2755,40 +2867,54 @@ var MediaPlugin = class {
2755
2867
  sizer.style.display = "flex";
2756
2868
  sizer.style.justifyContent = "center";
2757
2869
  sizer.style.alignItems = "center";
2870
+ sizer.style.margin = "auto 0";
2758
2871
  sizer.appendChild(element);
2759
2872
  scrollWrapper.appendChild(sizer);
2760
2873
  ctx.container.style.overflow = "auto";
2761
2874
  ctx.container.style.padding = "0";
2762
2875
  ctx.container.innerHTML = "";
2763
2876
  ctx.container.appendChild(scrollWrapper);
2764
- let naturalW = 800;
2765
- let naturalH = 600;
2766
- let baseW = 800;
2767
- let baseH = 600;
2877
+ let baseW = naturalW;
2878
+ let baseH = naturalH;
2879
+ let fitMode = ctx?.options?.fitMode || "width";
2880
+ let isUserZoomed = false;
2768
2881
  const updateBaseDimensions = () => {
2769
2882
  if (!isImage) return;
2770
2883
  const img = element;
2771
- naturalW = img.naturalWidth || naturalW;
2772
- naturalH = img.naturalHeight || naturalH;
2773
- const availW = Math.max(100, ctx.container.clientWidth - 48);
2774
- const availH = Math.max(100, ctx.container.clientHeight - 48);
2775
- const fitRatio = Math.min(1, availW / naturalW, availH / naturalH);
2884
+ if (img.naturalWidth > 0 && img.naturalHeight > 0) {
2885
+ naturalW = img.naturalWidth;
2886
+ naturalH = img.naturalHeight;
2887
+ }
2888
+ const availW = Math.max(100, ctx.container.clientWidth - 32);
2889
+ const availH = Math.max(100, ctx.container.clientHeight - 32);
2890
+ let fitRatio;
2891
+ if (fitMode === "page") {
2892
+ fitRatio = Math.min(availW / naturalW, availH / naturalH);
2893
+ } else {
2894
+ fitRatio = availW / naturalW;
2895
+ }
2776
2896
  baseW = Math.max(1, Math.round(naturalW * fitRatio));
2777
2897
  baseH = Math.max(1, Math.round(naturalH * fitRatio));
2778
2898
  };
2779
2899
  const applyTransform = () => {
2780
2900
  if (isImage) {
2781
- updateBaseDimensions();
2901
+ if (!isUserZoomed) {
2902
+ updateBaseDimensions();
2903
+ }
2904
+ const availH = Math.max(100, ctx.container.clientHeight - 32);
2782
2905
  const isRotated90 = rotation % 180 !== 0;
2783
2906
  const boxW = Math.round((isRotated90 ? baseH : baseW) * currentZoom);
2784
2907
  const boxH = Math.round((isRotated90 ? baseW : baseH) * currentZoom);
2785
2908
  sizer.style.width = `${boxW}px`;
2786
2909
  sizer.style.height = `${boxH}px`;
2787
- element.style.width = `${baseW}px`;
2788
- element.style.height = `${baseH}px`;
2910
+ sizer.style.margin = boxH < availH ? "auto 0" : "0";
2911
+ const imgW = isRotated90 ? boxH : boxW;
2912
+ const imgH = isRotated90 ? boxW : boxH;
2913
+ element.style.width = `${imgW}px`;
2914
+ element.style.height = `${imgH}px`;
2789
2915
  element.style.maxWidth = "none";
2790
2916
  element.style.maxHeight = "none";
2791
- element.style.transform = `scale(${currentZoom}) rotate(${rotation}deg)`;
2917
+ element.style.transform = rotation ? `rotate(${rotation}deg)` : "none";
2792
2918
  element.style.transformOrigin = "center center";
2793
2919
  element.style.flexShrink = "0";
2794
2920
  } else {
@@ -2808,7 +2934,8 @@ var MediaPlugin = class {
2808
2934
  }
2809
2935
  }
2810
2936
  const ro = typeof ResizeObserver !== "undefined" ? new ResizeObserver(() => {
2811
- if (currentZoom === 1) {
2937
+ if (!isUserZoomed && currentZoom === 1) {
2938
+ updateBaseDimensions();
2812
2939
  applyTransform();
2813
2940
  }
2814
2941
  }) : null;
@@ -2823,28 +2950,49 @@ var MediaPlugin = class {
2823
2950
  return {
2824
2951
  destroy: cleanup,
2825
2952
  zoomIn: isImage ? () => {
2826
- currentZoom += 0.1;
2953
+ isUserZoomed = true;
2954
+ currentZoom = Math.min(5, Math.round((currentZoom + 0.15) * 100) / 100);
2827
2955
  applyTransform();
2828
2956
  } : void 0,
2829
2957
  zoomOut: isImage ? () => {
2830
- currentZoom = Math.max(0.1, currentZoom - 0.1);
2958
+ isUserZoomed = true;
2959
+ currentZoom = Math.max(0.1, Math.round((currentZoom - 0.15) * 100) / 100);
2831
2960
  applyTransform();
2832
2961
  } : void 0,
2833
2962
  getZoom: isImage ? () => currentZoom : void 0,
2834
2963
  setZoom: isImage ? (level) => {
2964
+ isUserZoomed = true;
2835
2965
  currentZoom = level;
2836
2966
  applyTransform();
2837
2967
  } : void 0,
2838
2968
  fitToPage: isImage ? () => {
2969
+ isUserZoomed = false;
2970
+ fitMode = "page";
2971
+ currentZoom = 1;
2972
+ rotation = 0;
2973
+ ctx.container.scrollTop = 0;
2974
+ ctx.container.scrollLeft = 0;
2975
+ updateBaseDimensions();
2976
+ applyTransform();
2977
+ } : void 0,
2978
+ fitToWidth: isImage ? () => {
2979
+ isUserZoomed = false;
2980
+ fitMode = "width";
2839
2981
  currentZoom = 1;
2840
2982
  rotation = 0;
2983
+ ctx.container.scrollTop = 0;
2984
+ ctx.container.scrollLeft = 0;
2985
+ updateBaseDimensions();
2841
2986
  applyTransform();
2842
2987
  } : void 0,
2843
2988
  resetZoom: isImage ? () => {
2989
+ isUserZoomed = false;
2990
+ fitMode = ctx?.options?.fitMode || "width";
2844
2991
  currentZoom = 1;
2845
2992
  rotation = 0;
2846
2993
  ctx.container.scrollTop = 0;
2847
2994
  ctx.container.scrollLeft = 0;
2995
+ updateBaseDimensions();
2848
2996
  applyTransform();
2849
2997
  } : void 0,
2850
2998
  rotateCW: isImage || isVideo ? () => {
@@ -2971,6 +3119,14 @@ var DocxPlugin = class {
2971
3119
  group: "zoom",
2972
3120
  execute: () => instance.resetZoom?.()
2973
3121
  },
3122
+ {
3123
+ id: "fit-width",
3124
+ icon: "fit-width",
3125
+ label: "Fit to Width",
3126
+ type: "button",
3127
+ group: "zoom",
3128
+ execute: () => instance.fitToWidth?.()
3129
+ },
2974
3130
  {
2975
3131
  id: "rotate-cw",
2976
3132
  icon: "rotate-cw",
@@ -3230,13 +3386,19 @@ var DocxPlugin = class {
3230
3386
  }
3231
3387
  scale = 1;
3232
3388
  let rotation = 0;
3233
- let fitMode = "page";
3389
+ let fitMode = ctx?.options?.fitMode || "width";
3234
3390
  let isUserZoomed = false;
3235
- const calculateFitScale = (_mode = fitMode) => {
3391
+ const calculateFitScale = (mode = fitMode) => {
3236
3392
  const activeEl = pageElements[currentPage - 1] || wrapper.querySelector("section.docx") || wrapper;
3237
3393
  const elW = activeEl.offsetWidth || 816;
3394
+ const elH = activeEl.offsetHeight || 1056;
3238
3395
  const availW = Math.max(280, ctx.container.clientWidth - 32);
3396
+ const availH = Math.max(280, ctx.container.clientHeight - 32);
3239
3397
  const sW = availW / elW;
3398
+ const sH = availH / elH;
3399
+ if (mode === "page") {
3400
+ return Math.max(0.35, Math.min(3, Math.min(sW, sH)));
3401
+ }
3240
3402
  return Math.max(0.35, Math.min(3, sW));
3241
3403
  };
3242
3404
  const applyTransform = () => {
@@ -3257,7 +3419,7 @@ var DocxPlugin = class {
3257
3419
  if (typeof ResizeObserver !== "undefined") {
3258
3420
  resizeObserver = new ResizeObserver(() => {
3259
3421
  if (!isUserZoomed) {
3260
- const newFit = calculateFitScale("page");
3422
+ const newFit = calculateFitScale(fitMode);
3261
3423
  if (Math.abs(scale - newFit) > 0.015) {
3262
3424
  scale = newFit;
3263
3425
  applyTransform();
@@ -3267,7 +3429,7 @@ var DocxPlugin = class {
3267
3429
  resizeObserver.observe(ctx.container);
3268
3430
  }
3269
3431
  setTimeout(() => {
3270
- scale = calculateFitScale("page");
3432
+ scale = calculateFitScale(fitMode);
3271
3433
  applyTransform();
3272
3434
  }, 40);
3273
3435
  const cleanup = () => {
@@ -3306,13 +3468,22 @@ var DocxPlugin = class {
3306
3468
  },
3307
3469
  fitToPage: () => {
3308
3470
  isUserZoomed = false;
3471
+ fitMode = "page";
3309
3472
  scale = calculateFitScale("page");
3310
3473
  rotation = 0;
3311
3474
  applyTransform();
3312
3475
  },
3476
+ fitToWidth: () => {
3477
+ isUserZoomed = false;
3478
+ fitMode = "width";
3479
+ scale = calculateFitScale("width");
3480
+ rotation = 0;
3481
+ applyTransform();
3482
+ },
3313
3483
  resetZoom: () => {
3314
3484
  isUserZoomed = false;
3315
- scale = calculateFitScale("page");
3485
+ fitMode = ctx?.options?.fitMode || "width";
3486
+ scale = calculateFitScale(fitMode);
3316
3487
  rotation = 0;
3317
3488
  ctx.container.scrollTop = 0;
3318
3489
  ctx.container.scrollLeft = 0;
@@ -3777,6 +3948,16 @@ var ExcelPlugin = class {
3777
3948
  instance.resetZoom?.();
3778
3949
  }
3779
3950
  },
3951
+ {
3952
+ id: "fit-width",
3953
+ icon: "fit-width",
3954
+ label: "Fit to Width",
3955
+ type: "button",
3956
+ group: "zoom",
3957
+ execute: () => {
3958
+ instance.fitToWidth?.();
3959
+ }
3960
+ },
3780
3961
  {
3781
3962
  id: "download",
3782
3963
  icon: "download",
@@ -3993,6 +4174,11 @@ var ExcelPlugin = class {
3993
4174
  scale = calculateFitScale();
3994
4175
  applyTransform();
3995
4176
  },
4177
+ fitToWidth: () => {
4178
+ isUserZoomed = false;
4179
+ scale = calculateFitScale();
4180
+ applyTransform();
4181
+ },
3996
4182
  resetZoom: () => {
3997
4183
  isUserZoomed = false;
3998
4184
  scale = calculateFitScale();
@@ -4140,6 +4326,16 @@ var CsvPlugin = class {
4140
4326
  instance.resetZoom?.();
4141
4327
  }
4142
4328
  },
4329
+ {
4330
+ id: "fit-width",
4331
+ icon: "fit-width",
4332
+ label: "Fit to Width",
4333
+ type: "button",
4334
+ group: "zoom",
4335
+ execute: () => {
4336
+ instance.fitToWidth?.();
4337
+ }
4338
+ },
4143
4339
  {
4144
4340
  id: "download",
4145
4341
  icon: "download",
@@ -4353,6 +4549,11 @@ var CsvPlugin = class {
4353
4549
  scale = calculateFitScale();
4354
4550
  applyScale();
4355
4551
  },
4552
+ fitToWidth: () => {
4553
+ isUserZoomed = false;
4554
+ scale = calculateFitScale();
4555
+ applyScale();
4556
+ },
4356
4557
  resetZoom: () => {
4357
4558
  isUserZoomed = false;
4358
4559
  scale = calculateFitScale();
@@ -4384,31 +4585,80 @@ function csvPlugin() {
4384
4585
  }
4385
4586
  var CODE_EXTENSIONS = [
4386
4587
  ".txt",
4588
+ ".log",
4589
+ ".ini",
4590
+ ".cfg",
4591
+ ".conf",
4592
+ ".env",
4387
4593
  ".json",
4594
+ ".jsonc",
4595
+ ".json5",
4388
4596
  ".js",
4389
- ".ts",
4597
+ ".mjs",
4598
+ ".cjs",
4390
4599
  ".jsx",
4600
+ ".ts",
4601
+ ".mts",
4602
+ ".cts",
4391
4603
  ".tsx",
4392
4604
  ".html",
4605
+ ".htm",
4606
+ ".xhtml",
4393
4607
  ".css",
4394
4608
  ".scss",
4609
+ ".sass",
4395
4610
  ".less",
4396
4611
  ".md",
4612
+ ".markdown",
4397
4613
  ".xml",
4614
+ ".svg",
4615
+ ".xaml",
4398
4616
  ".yml",
4399
4617
  ".yaml",
4618
+ ".toml",
4400
4619
  ".sh",
4401
4620
  ".bash",
4621
+ ".zsh",
4622
+ ".fish",
4623
+ ".bat",
4624
+ ".cmd",
4625
+ ".ps1",
4402
4626
  ".py",
4627
+ ".pyw",
4403
4628
  ".java",
4629
+ ".class",
4404
4630
  ".c",
4405
4631
  ".cpp",
4632
+ ".cc",
4633
+ ".cxx",
4406
4634
  ".h",
4635
+ ".hpp",
4636
+ ".hxx",
4407
4637
  ".cs",
4638
+ ".csx",
4408
4639
  ".go",
4409
4640
  ".rs",
4410
4641
  ".sql",
4411
- ".php"
4642
+ ".php",
4643
+ ".phtml",
4644
+ ".rb",
4645
+ ".swift",
4646
+ ".kt",
4647
+ ".kts",
4648
+ ".scala",
4649
+ ".r",
4650
+ ".lua",
4651
+ ".pl",
4652
+ ".pm",
4653
+ ".dart",
4654
+ ".graphql",
4655
+ ".gql",
4656
+ ".proto",
4657
+ ".diff",
4658
+ ".patch",
4659
+ ".dockerfile",
4660
+ ".properties",
4661
+ ".gradle"
4412
4662
  ];
4413
4663
  var CodePlugin = class {
4414
4664
  id = "code";
@@ -4426,34 +4676,36 @@ var CodePlugin = class {
4426
4676
  getToolbarActions(instance) {
4427
4677
  const totalPages = instance.getPageCount?.() ?? 1;
4428
4678
  const actions = [];
4429
- actions.push({
4430
- id: "thumbnails",
4431
- icon: "thumbnails",
4432
- label: "Page Thumbnails",
4433
- type: "button",
4434
- group: "navigation",
4435
- execute: () => instance.toggleThumbnails?.()
4436
- });
4437
- actions.push({
4438
- id: "page-nav",
4439
- icon: "",
4440
- label: "Page Navigation",
4441
- type: "page-nav",
4442
- group: "navigation",
4443
- value: instance.getCurrentPage?.() ?? 1,
4444
- max: totalPages,
4445
- execute: (action, page) => {
4446
- const cur = instance.getCurrentPage?.() ?? 1;
4447
- const max = instance.getPageCount?.() ?? 1;
4448
- if (action === "prev") {
4449
- if (cur > 1) instance.goToPage?.(cur - 1);
4450
- } else if (action === "next") {
4451
- if (cur < max) instance.goToPage?.(cur + 1);
4452
- } else if (typeof page === "number") {
4453
- instance.goToPage?.(page);
4679
+ if (totalPages > 1) {
4680
+ actions.push({
4681
+ id: "thumbnails",
4682
+ icon: "thumbnails",
4683
+ label: "Page Thumbnails",
4684
+ type: "button",
4685
+ group: "navigation",
4686
+ execute: () => instance.toggleThumbnails?.()
4687
+ });
4688
+ actions.push({
4689
+ id: "page-nav",
4690
+ icon: "",
4691
+ label: "Page Navigation",
4692
+ type: "page-nav",
4693
+ group: "navigation",
4694
+ value: instance.getCurrentPage?.() ?? 1,
4695
+ max: totalPages,
4696
+ execute: (action, page) => {
4697
+ const cur = instance.getCurrentPage?.() ?? 1;
4698
+ const max = instance.getPageCount?.() ?? 1;
4699
+ if (action === "prev") {
4700
+ if (cur > 1) instance.goToPage?.(cur - 1);
4701
+ } else if (action === "next") {
4702
+ if (cur < max) instance.goToPage?.(cur + 1);
4703
+ } else if (typeof page === "number") {
4704
+ instance.goToPage?.(page);
4705
+ }
4454
4706
  }
4455
- }
4456
- });
4707
+ });
4708
+ }
4457
4709
  actions.push(
4458
4710
  {
4459
4711
  id: "zoom-out",
@@ -4485,6 +4737,16 @@ var CodePlugin = class {
4485
4737
  instance.resetZoom?.();
4486
4738
  }
4487
4739
  },
4740
+ {
4741
+ id: "fit-width",
4742
+ icon: "fit-width",
4743
+ label: "Fit to Width",
4744
+ type: "button",
4745
+ group: "zoom",
4746
+ execute: () => {
4747
+ instance.fitToWidth?.();
4748
+ }
4749
+ },
4488
4750
  {
4489
4751
  id: "copy",
4490
4752
  icon: "copy",
@@ -4580,10 +4842,6 @@ var CodePlugin = class {
4580
4842
  }
4581
4843
  const totalPages = Math.max(1, rawPages.length);
4582
4844
  let currentPage = 1;
4583
- const container = document.createElement("div");
4584
- container.style.width = "100%";
4585
- container.style.height = "100%";
4586
- container.style.overflow = "auto";
4587
4845
  let fontSize = 13;
4588
4846
  let rotation = 0;
4589
4847
  let zoomLevel = 1;
@@ -4592,9 +4850,10 @@ var CodePlugin = class {
4592
4850
  const code = document.createElement("code");
4593
4851
  const sizer = document.createElement("div");
4594
4852
  const scrollWrapper = document.createElement("div");
4853
+ const lineGutter = document.createElement("div");
4854
+ ctx.container.style.overflow = "auto";
4595
4855
  if (isTxt) {
4596
- container.style.overflow = "auto";
4597
- container.style.backgroundColor = "#f1f5f9";
4856
+ ctx.container.style.backgroundColor = "#f1f5f9";
4598
4857
  scrollWrapper.className = "fp-code-scroll-wrapper";
4599
4858
  scrollWrapper.style.minWidth = "100%";
4600
4859
  scrollWrapper.style.minHeight = "100%";
@@ -4629,18 +4888,42 @@ var CodePlugin = class {
4629
4888
  pre.style.transition = "transform 0.15s ease";
4630
4889
  pre.style.flexShrink = "0";
4631
4890
  } else {
4632
- container.style.overflow = "auto";
4633
- container.style.backgroundColor = "#1e1e1e";
4634
- container.style.color = "#d4d4d4";
4635
- container.style.padding = "16px";
4636
- container.style.boxSizing = "border-box";
4891
+ ctx.container.style.backgroundColor = "#1e1e1e";
4892
+ ctx.container.style.color = "#d4d4d4";
4893
+ scrollWrapper.className = "fp-code-scroll-wrapper";
4894
+ scrollWrapper.style.minWidth = "100%";
4895
+ scrollWrapper.style.minHeight = "100%";
4896
+ scrollWrapper.style.width = "max-content";
4897
+ scrollWrapper.style.height = "max-content";
4898
+ scrollWrapper.style.display = "flex";
4899
+ scrollWrapper.style.alignItems = "flex-start";
4900
+ scrollWrapper.style.padding = "16px";
4901
+ scrollWrapper.style.boxSizing = "border-box";
4902
+ const lineCount = fullText.split(/\r?\n/).length || 1;
4903
+ const gutterLines = [];
4904
+ for (let i = 1; i <= lineCount; i++) {
4905
+ gutterLines.push(String(i));
4906
+ }
4907
+ lineGutter.className = "fp-code-gutter";
4908
+ lineGutter.style.userSelect = "none";
4909
+ lineGutter.style.textAlign = "right";
4910
+ lineGutter.style.paddingRight = "16px";
4911
+ lineGutter.style.marginRight = "16px";
4912
+ lineGutter.style.borderRight = "1px solid #333333";
4913
+ lineGutter.style.color = "#858585";
4914
+ lineGutter.style.fontFamily = "Consolas, Menlo, Monaco, 'Courier New', monospace";
4915
+ lineGutter.style.fontSize = `${fontSize}px`;
4916
+ lineGutter.style.lineHeight = "1.6";
4917
+ lineGutter.style.flexShrink = "0";
4918
+ lineGutter.textContent = gutterLines.join("\n");
4637
4919
  pre.style.margin = "0";
4638
- pre.style.fontFamily = "Consolas, Menlo, Monaco, monospace";
4920
+ pre.style.fontFamily = "Consolas, Menlo, Monaco, 'Courier New', monospace";
4639
4921
  pre.style.fontSize = `${fontSize}px`;
4640
- pre.style.lineHeight = "1.5";
4641
- pre.style.whiteSpace = "pre-wrap";
4642
- pre.style.wordBreak = "break-all";
4643
- pre.style.transformOrigin = "top left";
4922
+ pre.style.lineHeight = "1.6";
4923
+ pre.style.whiteSpace = "pre";
4924
+ pre.style.wordBreak = "normal";
4925
+ pre.style.overflowWrap = "normal";
4926
+ pre.style.flex = "1";
4644
4927
  }
4645
4928
  const ext = (ctx.metadata.extension || "").replace(".", "");
4646
4929
  const renderCodePage = (text) => {
@@ -4660,25 +4943,27 @@ var CodePlugin = class {
4660
4943
  };
4661
4944
  renderCodePage(rawPages[0] || (isTxt ? "" : fullText));
4662
4945
  pre.appendChild(code);
4946
+ ctx.container.innerHTML = "";
4663
4947
  if (isTxt) {
4664
4948
  sizer.appendChild(pre);
4665
4949
  scrollWrapper.appendChild(sizer);
4666
- container.appendChild(scrollWrapper);
4950
+ ctx.container.appendChild(scrollWrapper);
4667
4951
  } else {
4668
- container.appendChild(pre);
4952
+ scrollWrapper.appendChild(lineGutter);
4953
+ scrollWrapper.appendChild(pre);
4954
+ ctx.container.appendChild(scrollWrapper);
4669
4955
  }
4670
4956
  const showPage = (pageNum) => {
4671
4957
  currentPage = Math.max(1, Math.min(totalPages, pageNum));
4672
4958
  renderCodePage(rawPages[currentPage - 1] || (isTxt ? "" : fullText));
4673
- container.scrollTop = 0;
4959
+ ctx.container.scrollTop = 0;
4674
4960
  ctx.emit("page-change", { page: currentPage, total: totalPages });
4675
4961
  };
4676
4962
  if (totalPages > 1) {
4677
4963
  showPage(1);
4678
4964
  }
4679
- ctx.container.appendChild(container);
4680
4965
  const calculateTxtFit = () => {
4681
- const availW = Math.max(280, container.clientWidth - 32);
4966
+ const availW = Math.max(280, ctx.container.clientWidth - 32);
4682
4967
  return Math.max(0.4, Math.min(3, availW / 816));
4683
4968
  };
4684
4969
  const updateTransform = () => {
@@ -4696,6 +4981,7 @@ var CodePlugin = class {
4696
4981
  } else {
4697
4982
  pre.style.transform = `rotate(${rotation}deg)`;
4698
4983
  pre.style.fontSize = `${fontSize}px`;
4984
+ lineGutter.style.fontSize = `${fontSize}px`;
4699
4985
  }
4700
4986
  };
4701
4987
  let resizeObserver = null;
@@ -4710,11 +4996,11 @@ var CodePlugin = class {
4710
4996
  updateTransform();
4711
4997
  }
4712
4998
  }) : null;
4713
- resizeObserver?.observe(container);
4999
+ resizeObserver?.observe(ctx.container);
4714
5000
  }
4715
5001
  const cleanup = () => {
4716
5002
  resizeObserver?.disconnect();
4717
- container.remove();
5003
+ scrollWrapper.remove();
4718
5004
  ctx.container.innerHTML = "";
4719
5005
  };
4720
5006
  ctx.signal.addEventListener("abort", cleanup);
@@ -4759,7 +5045,7 @@ var CodePlugin = class {
4759
5045
  if (isTxt) {
4760
5046
  zoomLevel = Math.min(3.5, zoomLevel + 0.15);
4761
5047
  } else {
4762
- fontSize = Math.min(32, fontSize + 2);
5048
+ fontSize = Math.min(48, fontSize + 2);
4763
5049
  }
4764
5050
  updateTransform();
4765
5051
  },
@@ -4768,7 +5054,7 @@ var CodePlugin = class {
4768
5054
  if (isTxt) {
4769
5055
  zoomLevel = Math.max(0.1, zoomLevel - 0.15);
4770
5056
  } else {
4771
- fontSize = Math.max(8, fontSize - 2);
5057
+ fontSize = Math.max(9, fontSize - 2);
4772
5058
  }
4773
5059
  updateTransform();
4774
5060
  },
@@ -4789,13 +5075,20 @@ var CodePlugin = class {
4789
5075
  zoomLevel = isTxt ? calculateTxtFit() : 1;
4790
5076
  updateTransform();
4791
5077
  },
5078
+ fitToWidth: () => {
5079
+ isUserZoomed = false;
5080
+ fontSize = 13;
5081
+ rotation = 0;
5082
+ zoomLevel = isTxt ? calculateTxtFit() : 1;
5083
+ updateTransform();
5084
+ },
4792
5085
  resetZoom: () => {
4793
5086
  isUserZoomed = false;
4794
5087
  fontSize = 13;
4795
5088
  rotation = 0;
4796
5089
  zoomLevel = isTxt ? calculateTxtFit() : 1;
4797
- container.scrollTop = 0;
4798
- container.scrollLeft = 0;
5090
+ ctx.container.scrollTop = 0;
5091
+ ctx.container.scrollLeft = 0;
4799
5092
  updateTransform();
4800
5093
  },
4801
5094
  rotateCW: () => {
@@ -4873,6 +5166,14 @@ var ArchivePlugin = class {
4873
5166
  group: "zoom",
4874
5167
  execute: () => instance.resetZoom?.()
4875
5168
  },
5169
+ {
5170
+ id: "fit-width",
5171
+ icon: "fit-width",
5172
+ label: "Fit to Width",
5173
+ type: "button",
5174
+ group: "zoom",
5175
+ execute: () => instance.fitToWidth?.()
5176
+ },
4876
5177
  {
4877
5178
  id: "download",
4878
5179
  icon: "download",
@@ -5070,6 +5371,10 @@ var ArchivePlugin = class {
5070
5371
  scale = 1;
5071
5372
  applyTransform();
5072
5373
  },
5374
+ fitToWidth: () => {
5375
+ scale = 1;
5376
+ applyTransform();
5377
+ },
5073
5378
  resetZoom: () => {
5074
5379
  scale = 1;
5075
5380
  wrapper.scrollTop = 0;
@@ -5105,7 +5410,7 @@ var MarkdownPlugin = class {
5105
5410
  {
5106
5411
  id: "zoom-out",
5107
5412
  icon: "zoom-out",
5108
- label: "Decrease Font",
5413
+ label: "Zoom Out",
5109
5414
  type: "button",
5110
5415
  group: "zoom",
5111
5416
  execute: () => instance.zoomOut?.()
@@ -5113,19 +5418,11 @@ var MarkdownPlugin = class {
5113
5418
  {
5114
5419
  id: "zoom-in",
5115
5420
  icon: "zoom-in",
5116
- label: "Increase Font",
5421
+ label: "Zoom In",
5117
5422
  type: "button",
5118
5423
  group: "zoom",
5119
5424
  execute: () => instance.zoomIn?.()
5120
5425
  },
5121
- {
5122
- id: "fit-page",
5123
- icon: "fit-page",
5124
- label: "Default Size",
5125
- type: "button",
5126
- group: "zoom",
5127
- execute: () => instance.fitToPage?.()
5128
- },
5129
5426
  {
5130
5427
  id: "reset-zoom",
5131
5428
  icon: "reset-zoom",
@@ -5134,6 +5431,22 @@ var MarkdownPlugin = class {
5134
5431
  group: "zoom",
5135
5432
  execute: () => instance.resetZoom?.()
5136
5433
  },
5434
+ {
5435
+ id: "fit-width",
5436
+ icon: "fit-width",
5437
+ label: "Fit to Width",
5438
+ type: "button",
5439
+ group: "zoom",
5440
+ execute: () => instance.fitToWidth?.()
5441
+ },
5442
+ {
5443
+ id: "fit-page",
5444
+ icon: "fit-page",
5445
+ label: "Fit to Page",
5446
+ type: "button",
5447
+ group: "zoom",
5448
+ execute: () => instance.fitToPage?.()
5449
+ },
5137
5450
  {
5138
5451
  id: "copy",
5139
5452
  icon: "copy",
@@ -5157,10 +5470,18 @@ var MarkdownPlugin = class {
5157
5470
  type: "button",
5158
5471
  group: "actions",
5159
5472
  execute: () => instance.print?.()
5160
- }
5161
- ];
5162
- }
5163
- async render(ctx) {
5473
+ },
5474
+ {
5475
+ id: "open-window",
5476
+ icon: "open-window",
5477
+ label: "Open in Separate Full Window",
5478
+ type: "button",
5479
+ group: "actions",
5480
+ execute: () => instance.openInSeparateWindow?.()
5481
+ }
5482
+ ];
5483
+ }
5484
+ async render(ctx) {
5164
5485
  const text = new TextDecoder("utf-8", { fatal: false }).decode(ctx.buffer);
5165
5486
  const rawHtml = await marked.marked.parse(text, {
5166
5487
  gfm: true,
@@ -5169,35 +5490,57 @@ var MarkdownPlugin = class {
5169
5490
  const cleanHtml = DOMPurify6__default.default.sanitize(rawHtml, {
5170
5491
  USE_PROFILES: { html: true }
5171
5492
  });
5172
- const wrapper = document.createElement("div");
5173
- wrapper.className = "fp-markdown-wrapper";
5174
- wrapper.style.cssText = `
5175
- width: 100%;
5176
- height: 100%;
5177
- overflow: auto;
5178
- padding: 32px 40px;
5493
+ const scrollWrapper = document.createElement("div");
5494
+ scrollWrapper.className = "fp-markdown-scroll-wrapper";
5495
+ scrollWrapper.style.minWidth = "100%";
5496
+ scrollWrapper.style.minHeight = "100%";
5497
+ scrollWrapper.style.width = "max-content";
5498
+ scrollWrapper.style.height = "max-content";
5499
+ scrollWrapper.style.display = "flex";
5500
+ scrollWrapper.style.justifyContent = "center";
5501
+ scrollWrapper.style.alignItems = "flex-start";
5502
+ scrollWrapper.style.padding = "24px 16px";
5503
+ scrollWrapper.style.boxSizing = "border-box";
5504
+ const sizer = document.createElement("div");
5505
+ sizer.className = "fp-markdown-sizer";
5506
+ sizer.style.position = "relative";
5507
+ sizer.style.flexShrink = "0";
5508
+ sizer.style.display = "flex";
5509
+ sizer.style.justifyContent = "center";
5510
+ sizer.style.alignItems = "flex-start";
5511
+ const docCard = document.createElement("div");
5512
+ docCard.className = "fp-markdown-doc-card";
5513
+ docCard.style.cssText = `
5514
+ width: 860px;
5515
+ min-height: 600px;
5516
+ padding: 40px 48px;
5179
5517
  box-sizing: border-box;
5180
5518
  line-height: 1.6;
5181
5519
  font-size: 15px;
5182
5520
  color: var(--fp-text, #24292f);
5183
5521
  background: var(--fp-bg, #ffffff);
5522
+ border-radius: 6px;
5523
+ box-shadow: 0 4px 24px rgba(0, 0, 0, 0.08);
5184
5524
  font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Noto Sans", Helvetica, Arial, sans-serif;
5525
+ transform-origin: top center;
5526
+ transition: transform 0.15s ease;
5527
+ flex-shrink: 0;
5185
5528
  `;
5186
- wrapper.innerHTML = `
5529
+ docCard.innerHTML = `
5187
5530
  <style>
5188
- .fp-markdown-wrapper h1, .fp-markdown-wrapper h2, .fp-markdown-wrapper h3,
5189
- .fp-markdown-wrapper h4, .fp-markdown-wrapper h5, .fp-markdown-wrapper h6 {
5531
+ .fp-markdown-doc-card h1, .fp-markdown-doc-card h2, .fp-markdown-doc-card h3,
5532
+ .fp-markdown-doc-card h4, .fp-markdown-doc-card h5, .fp-markdown-doc-card h6 {
5190
5533
  margin-top: 24px;
5191
5534
  margin-bottom: 16px;
5192
5535
  font-weight: 600;
5193
5536
  line-height: 1.25;
5194
5537
  color: var(--fp-text, #1f2328);
5195
5538
  }
5196
- .fp-markdown-wrapper h1 { font-size: 2em; padding-bottom: 0.3em; border-bottom: 1px solid var(--fp-border, #d0d7de); }
5197
- .fp-markdown-wrapper h2 { font-size: 1.5em; padding-bottom: 0.3em; border-bottom: 1px solid var(--fp-border, #d0d7de); }
5198
- .fp-markdown-wrapper h3 { font-size: 1.25em; }
5199
- .fp-markdown-wrapper p { margin-top: 0; margin-bottom: 16px; }
5200
- .fp-markdown-wrapper table {
5539
+ .fp-markdown-doc-card h1 { font-size: 2em; padding-bottom: 0.3em; border-bottom: 1px solid var(--fp-border, #d0d7de); }
5540
+ .fp-markdown-doc-card h2 { font-size: 1.5em; padding-bottom: 0.3em; border-bottom: 1px solid var(--fp-border, #d0d7de); }
5541
+ .fp-markdown-doc-card h3 { font-size: 1.25em; }
5542
+ .fp-markdown-doc-card p { margin-top: 0; margin-bottom: 16px; }
5543
+ .fp-markdown-doc-card table {
5201
5544
  border-spacing: 0;
5202
5545
  border-collapse: collapse;
5203
5546
  margin-top: 0;
@@ -5205,20 +5548,20 @@ var MarkdownPlugin = class {
5205
5548
  width: 100%;
5206
5549
  overflow: auto;
5207
5550
  }
5208
- .fp-markdown-wrapper table th, .fp-markdown-wrapper table td {
5551
+ .fp-markdown-doc-card table th, .fp-markdown-doc-card table td {
5209
5552
  padding: 6px 13px;
5210
5553
  border: 1px solid var(--fp-border, #d0d7de);
5211
5554
  }
5212
- .fp-markdown-wrapper table tr:nth-child(2n) {
5555
+ .fp-markdown-doc-card table tr:nth-child(2n) {
5213
5556
  background-color: var(--fp-toolbar-bg, #f6f8fa);
5214
5557
  }
5215
- .fp-markdown-wrapper blockquote {
5558
+ .fp-markdown-doc-card blockquote {
5216
5559
  margin: 0 0 16px 0;
5217
5560
  padding: 0 1em;
5218
5561
  color: var(--fp-text-muted, #59636e);
5219
5562
  border-left: 0.25em solid var(--fp-border, #d0d7de);
5220
5563
  }
5221
- .fp-markdown-wrapper pre {
5564
+ .fp-markdown-doc-card pre {
5222
5565
  padding: 16px;
5223
5566
  overflow: auto;
5224
5567
  font-size: 85%;
@@ -5227,7 +5570,7 @@ var MarkdownPlugin = class {
5227
5570
  border-radius: 6px;
5228
5571
  border: 1px solid var(--fp-border, #d0d7de);
5229
5572
  }
5230
- .fp-markdown-wrapper code {
5573
+ .fp-markdown-doc-card code {
5231
5574
  padding: 0.2em 0.4em;
5232
5575
  margin: 0;
5233
5576
  font-size: 85%;
@@ -5235,16 +5578,16 @@ var MarkdownPlugin = class {
5235
5578
  border-radius: 4px;
5236
5579
  font-family: ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, monospace;
5237
5580
  }
5238
- .fp-markdown-wrapper pre code {
5581
+ .fp-markdown-doc-card pre code {
5239
5582
  padding: 0;
5240
5583
  background: transparent;
5241
5584
  }
5242
- .fp-markdown-wrapper ul, .fp-markdown-wrapper ol {
5585
+ .fp-markdown-doc-card ul, .fp-markdown-doc-card ol {
5243
5586
  padding-left: 2em;
5244
5587
  margin-top: 0;
5245
5588
  margin-bottom: 16px;
5246
5589
  }
5247
- .fp-markdown-wrapper hr {
5590
+ .fp-markdown-doc-card hr {
5248
5591
  height: 0.25em;
5249
5592
  padding: 0;
5250
5593
  margin: 24px 0;
@@ -5252,46 +5595,95 @@ var MarkdownPlugin = class {
5252
5595
  border: 0;
5253
5596
  }
5254
5597
  </style>
5255
- <div class="fp-markdown-content" style="max-width: 860px; margin: 0 auto;">
5598
+ <div class="fp-markdown-body">
5256
5599
  ${cleanHtml}
5257
5600
  </div>
5258
5601
  `;
5259
- wrapper.querySelectorAll("pre code").forEach((block) => {
5602
+ docCard.querySelectorAll("pre code").forEach((block) => {
5260
5603
  hljs__default.default.highlightElement(block);
5261
5604
  });
5605
+ sizer.appendChild(docCard);
5606
+ scrollWrapper.appendChild(sizer);
5262
5607
  ctx.container.innerHTML = "";
5263
5608
  ctx.container.style.overflow = "auto";
5264
- ctx.container.appendChild(wrapper);
5265
- let fontSize = 15;
5609
+ ctx.container.style.backgroundColor = "#f1f5f9";
5610
+ ctx.container.appendChild(scrollWrapper);
5611
+ let scale = 1;
5612
+ let isUserZoomed = false;
5613
+ const calculateFitScale = () => {
5614
+ const availW = Math.max(280, ctx.container.clientWidth - 48);
5615
+ if (availW < 860) {
5616
+ return Math.max(0.35, availW / 860);
5617
+ }
5618
+ return 1;
5619
+ };
5620
+ const applyTransform = () => {
5621
+ const baseW = 860;
5622
+ const baseH = docCard.offsetHeight || 600;
5623
+ const scaledW = Math.round(baseW * scale);
5624
+ const scaledH = Math.round(baseH * scale);
5625
+ sizer.style.width = `${scaledW}px`;
5626
+ sizer.style.height = `${scaledH}px`;
5627
+ docCard.style.width = `${baseW}px`;
5628
+ docCard.style.transform = `scale(${scale})`;
5629
+ docCard.style.transformOrigin = scaledW > ctx.container.clientWidth - 32 ? "top left" : "top center";
5630
+ };
5631
+ const ro = typeof ResizeObserver !== "undefined" ? new ResizeObserver(() => {
5632
+ if (!isUserZoomed) {
5633
+ scale = calculateFitScale();
5634
+ applyTransform();
5635
+ }
5636
+ }) : null;
5637
+ ro?.observe(ctx.container);
5638
+ requestAnimationFrame(() => {
5639
+ if (!isUserZoomed) {
5640
+ scale = calculateFitScale();
5641
+ }
5642
+ applyTransform();
5643
+ });
5266
5644
  const cleanup = () => {
5267
- wrapper.remove();
5645
+ ro?.disconnect();
5646
+ scrollWrapper.remove();
5268
5647
  ctx.container.innerHTML = "";
5269
5648
  };
5270
5649
  ctx.signal.addEventListener("abort", cleanup);
5271
5650
  return {
5272
5651
  destroy: cleanup,
5273
5652
  zoomIn: () => {
5274
- fontSize = Math.min(28, fontSize + 2);
5275
- wrapper.style.fontSize = `${fontSize}px`;
5653
+ isUserZoomed = true;
5654
+ scale = Math.min(3.5, scale + 0.15);
5655
+ applyTransform();
5276
5656
  },
5277
5657
  zoomOut: () => {
5278
- fontSize = Math.max(10, fontSize - 2);
5279
- wrapper.style.fontSize = `${fontSize}px`;
5658
+ isUserZoomed = true;
5659
+ scale = Math.max(0.25, scale - 0.15);
5660
+ applyTransform();
5280
5661
  },
5281
- getZoom: () => fontSize / 15,
5662
+ getZoom: () => scale,
5282
5663
  setZoom: (level) => {
5283
- fontSize = Math.round(15 * level);
5284
- wrapper.style.fontSize = `${fontSize}px`;
5664
+ isUserZoomed = true;
5665
+ scale = level;
5666
+ applyTransform();
5285
5667
  },
5286
5668
  fitToPage: () => {
5287
- fontSize = 15;
5288
- wrapper.style.fontSize = "15px";
5669
+ isUserZoomed = false;
5670
+ scale = calculateFitScale();
5671
+ applyTransform();
5672
+ },
5673
+ fitToWidth: () => {
5674
+ isUserZoomed = false;
5675
+ scale = calculateFitScale();
5676
+ applyTransform();
5289
5677
  },
5290
5678
  resetZoom: () => {
5291
- fontSize = 15;
5292
- wrapper.style.fontSize = "15px";
5679
+ isUserZoomed = false;
5680
+ scale = calculateFitScale();
5293
5681
  ctx.container.scrollTop = 0;
5294
5682
  ctx.container.scrollLeft = 0;
5683
+ applyTransform();
5684
+ },
5685
+ openInSeparateWindow: () => {
5686
+ ctx?.openInSeparateWindow?.();
5295
5687
  },
5296
5688
  download: () => {
5297
5689
  downloadFile(ctx.buffer, ctx.metadata.name || "document.md", "text/markdown");
@@ -5394,6 +5786,14 @@ var PptxPlugin = class {
5394
5786
  group: "zoom",
5395
5787
  execute: () => instance.resetZoom?.()
5396
5788
  },
5789
+ {
5790
+ id: "fit-width",
5791
+ icon: "fit-width",
5792
+ label: "Fit to Width",
5793
+ type: "button",
5794
+ group: "zoom",
5795
+ execute: () => instance.fitToWidth?.()
5796
+ },
5397
5797
  {
5398
5798
  id: "rotate-cw",
5399
5799
  icon: "rotate-cw",
@@ -5477,12 +5877,17 @@ var PptxPlugin = class {
5477
5877
  ctx.container.innerHTML = "";
5478
5878
  ctx.container.style.overflow = "auto";
5479
5879
  ctx.container.appendChild(wrapper);
5480
- const calculateFitScale = () => {
5481
- const availW = Math.max(200, ctx.container.clientWidth - 48);
5482
- const availH = Math.max(200, ctx.container.clientHeight - 72);
5880
+ let fitMode = ctx?.options?.fitMode || "width";
5881
+ let isUserZoomed = false;
5882
+ const calculateFitScale = (mode = fitMode) => {
5883
+ const availW = Math.max(200, ctx.container.clientWidth - 32);
5884
+ const availH = Math.max(200, ctx.container.clientHeight - 32);
5483
5885
  const cW = canvas.offsetWidth || 1280;
5484
5886
  const cH = canvas.offsetHeight || 720;
5485
- return Math.min(1, Math.min(availW / cW, availH / cH));
5887
+ if (mode === "page") {
5888
+ return Math.min(2.5, Math.min(availW / cW, availH / cH));
5889
+ }
5890
+ return Math.min(2.5, availW / cW);
5486
5891
  };
5487
5892
  const applyTransform = () => {
5488
5893
  const cW = canvas.offsetWidth || 1280;
@@ -5501,14 +5906,24 @@ var PptxPlugin = class {
5501
5906
  try {
5502
5907
  await renderer.renderSlide(currentSlide - 1, canvas, 1280);
5503
5908
  ctx.emit("page-change", { page: currentSlide, totalPages: slideCount });
5504
- scale = calculateFitScale();
5909
+ if (!isUserZoomed) {
5910
+ scale = calculateFitScale(fitMode);
5911
+ }
5505
5912
  applyTransform();
5506
5913
  } catch (err) {
5507
5914
  console.error("[PptxPlugin] Failed to render slide:", err);
5508
5915
  }
5509
5916
  };
5510
5917
  await renderCurrentSlide();
5918
+ const ro = typeof ResizeObserver !== "undefined" ? new ResizeObserver(() => {
5919
+ if (!isUserZoomed) {
5920
+ scale = calculateFitScale(fitMode);
5921
+ applyTransform();
5922
+ }
5923
+ }) : null;
5924
+ ro?.observe(ctx.container);
5511
5925
  const cleanup = () => {
5926
+ ro?.disconnect();
5512
5927
  renderer.destroy();
5513
5928
  wrapper.remove();
5514
5929
  ctx.container.innerHTML = "";
@@ -5525,28 +5940,44 @@ var PptxPlugin = class {
5525
5940
  getPageCount: () => slideCount,
5526
5941
  getCurrentPage: () => currentSlide,
5527
5942
  zoomIn: () => {
5943
+ isUserZoomed = true;
5528
5944
  scale += 0.15;
5529
5945
  applyTransform();
5530
5946
  },
5531
5947
  zoomOut: () => {
5948
+ isUserZoomed = true;
5532
5949
  scale = Math.max(0.2, scale - 0.15);
5533
5950
  applyTransform();
5534
5951
  },
5535
5952
  getZoom: () => scale,
5536
5953
  setZoom: (level) => {
5954
+ isUserZoomed = true;
5537
5955
  scale = level;
5538
5956
  applyTransform();
5539
5957
  },
5540
5958
  fitToPage: () => {
5541
- scale = calculateFitScale();
5959
+ isUserZoomed = false;
5960
+ fitMode = "page";
5961
+ scale = calculateFitScale("page");
5962
+ rotation = 0;
5963
+ applyTransform();
5964
+ },
5965
+ fitToWidth: () => {
5966
+ isUserZoomed = false;
5967
+ fitMode = "width";
5968
+ scale = calculateFitScale("width");
5542
5969
  rotation = 0;
5543
5970
  applyTransform();
5544
5971
  },
5545
5972
  resetZoom: () => {
5546
- scale = calculateFitScale();
5973
+ isUserZoomed = false;
5974
+ fitMode = ctx?.options?.fitMode || "width";
5975
+ scale = calculateFitScale(fitMode);
5547
5976
  rotation = 0;
5548
5977
  wrapper.scrollTop = 0;
5549
5978
  wrapper.scrollLeft = 0;
5979
+ ctx.container.scrollTop = 0;
5980
+ ctx.container.scrollLeft = 0;
5550
5981
  applyTransform();
5551
5982
  },
5552
5983
  rotateCW: () => {
@@ -5991,6 +6422,14 @@ var RtfPlugin = class {
5991
6422
  group: "zoom",
5992
6423
  execute: () => instance.resetZoom?.()
5993
6424
  },
6425
+ {
6426
+ id: "fit-width",
6427
+ icon: "fit-width",
6428
+ label: "Fit to Width",
6429
+ type: "button",
6430
+ group: "zoom",
6431
+ execute: () => instance.fitToWidth?.()
6432
+ },
5994
6433
  {
5995
6434
  id: "rotate-cw",
5996
6435
  icon: "rotate-cw",
@@ -6479,6 +6918,13 @@ var RtfPlugin = class {
6479
6918
  applyTransform();
6480
6919
  },
6481
6920
  fitToPage: () => {
6921
+ isUserZoomed = false;
6922
+ fitMode = "page";
6923
+ scale = calculateFitScale("page");
6924
+ rotation = 0;
6925
+ applyTransform();
6926
+ },
6927
+ fitToWidth: () => {
6482
6928
  isUserZoomed = false;
6483
6929
  fitMode = "width";
6484
6930
  scale = calculateFitScale("width");
@@ -6487,8 +6933,8 @@ var RtfPlugin = class {
6487
6933
  },
6488
6934
  resetZoom: () => {
6489
6935
  isUserZoomed = false;
6490
- fitMode = "width";
6491
- scale = calculateFitScale("width");
6936
+ fitMode = ctx?.options?.fitMode || "width";
6937
+ scale = calculateFitScale(fitMode);
6492
6938
  rotation = 0;
6493
6939
  ctx.container.scrollTop = 0;
6494
6940
  ctx.container.scrollLeft = 0;
@@ -6553,14 +6999,6 @@ var HtmlPreviewPlugin = class {
6553
6999
  group: "zoom",
6554
7000
  execute: () => instance.zoomIn?.()
6555
7001
  },
6556
- {
6557
- id: "fit-page",
6558
- icon: "fit-page",
6559
- label: "Fit to Page",
6560
- type: "button",
6561
- group: "zoom",
6562
- execute: () => instance.fitToPage?.()
6563
- },
6564
7002
  {
6565
7003
  id: "reset-zoom",
6566
7004
  icon: "reset-zoom",
@@ -6569,6 +7007,22 @@ var HtmlPreviewPlugin = class {
6569
7007
  group: "zoom",
6570
7008
  execute: () => instance.resetZoom?.()
6571
7009
  },
7010
+ {
7011
+ id: "fit-width",
7012
+ icon: "fit-width",
7013
+ label: "Fit to Width",
7014
+ type: "button",
7015
+ group: "zoom",
7016
+ execute: () => instance.fitToWidth?.()
7017
+ },
7018
+ {
7019
+ id: "fit-page",
7020
+ icon: "fit-page",
7021
+ label: "Fit to Page",
7022
+ type: "button",
7023
+ group: "zoom",
7024
+ execute: () => instance.fitToPage?.()
7025
+ },
6572
7026
  {
6573
7027
  id: "copy",
6574
7028
  icon: "copy",
@@ -6592,6 +7046,14 @@ var HtmlPreviewPlugin = class {
6592
7046
  type: "button",
6593
7047
  group: "actions",
6594
7048
  execute: () => instance.print?.()
7049
+ },
7050
+ {
7051
+ id: "open-window",
7052
+ icon: "open-window",
7053
+ label: "Open in Separate Full Window",
7054
+ type: "button",
7055
+ group: "actions",
7056
+ execute: () => instance.openInSeparateWindow?.()
6595
7057
  }
6596
7058
  ];
6597
7059
  }
@@ -6602,27 +7064,39 @@ var HtmlPreviewPlugin = class {
6602
7064
  ADD_TAGS: ["style", "link"],
6603
7065
  ADD_ATTR: ["target", "rel"]
6604
7066
  });
7067
+ const scrollWrapper = document.createElement("div");
7068
+ scrollWrapper.className = "fp-html-scroll-wrapper";
7069
+ scrollWrapper.style.minWidth = "100%";
7070
+ scrollWrapper.style.minHeight = "100%";
7071
+ scrollWrapper.style.width = "max-content";
7072
+ scrollWrapper.style.height = "max-content";
7073
+ scrollWrapper.style.display = "flex";
7074
+ scrollWrapper.style.justifyContent = "flex-start";
7075
+ scrollWrapper.style.alignItems = "flex-start";
7076
+ scrollWrapper.style.boxSizing = "border-box";
6605
7077
  const sizer = document.createElement("div");
6606
7078
  sizer.className = "fp-html-sizer";
6607
7079
  sizer.style.position = "relative";
7080
+ sizer.style.flexShrink = "0";
6608
7081
  const iframe = document.createElement("iframe");
6609
7082
  iframe.className = "fp-html-iframe";
6610
7083
  iframe.style.border = "none";
6611
7084
  iframe.style.backgroundColor = "#ffffff";
6612
7085
  iframe.style.transformOrigin = "top left";
6613
- iframe.style.transition = "transform 0.2s ease";
7086
+ iframe.style.transition = "transform 0.15s ease";
6614
7087
  iframe.sandbox.add("allow-same-origin");
6615
7088
  sizer.appendChild(iframe);
7089
+ scrollWrapper.appendChild(sizer);
6616
7090
  ctx.container.style.overflow = "auto";
6617
7091
  ctx.container.style.width = "100%";
6618
7092
  ctx.container.style.height = "100%";
6619
7093
  ctx.container.innerHTML = "";
6620
- ctx.container.appendChild(sizer);
7094
+ ctx.container.appendChild(scrollWrapper);
6621
7095
  iframe.srcdoc = sanitized;
6622
7096
  let scale = 1;
7097
+ let baseW = Math.max(600, ctx.container.clientWidth || 800);
7098
+ let baseH = Math.max(400, ctx.container.clientHeight || 600);
6623
7099
  const applyTransform = () => {
6624
- const baseW = Math.max(600, ctx.container.clientWidth || 800);
6625
- const baseH = Math.max(400, ctx.container.clientHeight || 600);
6626
7100
  const scaledW = Math.round(baseW * scale);
6627
7101
  const scaledH = Math.round(baseH * scale);
6628
7102
  sizer.style.width = `${scaledW}px`;
@@ -6635,22 +7109,33 @@ var HtmlPreviewPlugin = class {
6635
7109
  iframe.style.transform = `scale(${scale})`;
6636
7110
  iframe.style.transformOrigin = "top left";
6637
7111
  };
7112
+ const ro = typeof ResizeObserver !== "undefined" ? new ResizeObserver(() => {
7113
+ if (Math.abs(scale - 1) < 0.05) {
7114
+ baseW = Math.max(600, ctx.container.clientWidth || 800);
7115
+ baseH = Math.max(400, ctx.container.clientHeight || 600);
7116
+ applyTransform();
7117
+ }
7118
+ }) : null;
7119
+ ro?.observe(ctx.container);
6638
7120
  requestAnimationFrame(() => {
7121
+ baseW = Math.max(600, ctx.container.clientWidth || 800);
7122
+ baseH = Math.max(400, ctx.container.clientHeight || 600);
6639
7123
  applyTransform();
6640
7124
  });
6641
7125
  const cleanup = () => {
6642
- sizer.remove();
7126
+ ro?.disconnect();
7127
+ scrollWrapper.remove();
6643
7128
  ctx.container.innerHTML = "";
6644
7129
  };
6645
7130
  ctx.signal.addEventListener("abort", cleanup);
6646
7131
  return {
6647
7132
  destroy: cleanup,
6648
7133
  zoomIn: () => {
6649
- scale += 0.1;
7134
+ scale = Math.min(3.5, scale + 0.15);
6650
7135
  applyTransform();
6651
7136
  },
6652
7137
  zoomOut: () => {
6653
- scale = Math.max(0.2, scale - 0.1);
7138
+ scale = Math.max(0.25, scale - 0.15);
6654
7139
  applyTransform();
6655
7140
  },
6656
7141
  getZoom: () => scale,
@@ -6662,14 +7147,21 @@ var HtmlPreviewPlugin = class {
6662
7147
  scale = 1;
6663
7148
  applyTransform();
6664
7149
  },
7150
+ fitToWidth: () => {
7151
+ scale = 1;
7152
+ applyTransform();
7153
+ },
6665
7154
  resetZoom: () => {
6666
7155
  scale = 1;
6667
7156
  ctx.container.scrollTop = 0;
6668
7157
  ctx.container.scrollLeft = 0;
6669
7158
  applyTransform();
6670
7159
  },
7160
+ openInSeparateWindow: () => {
7161
+ ctx?.openInSeparateWindow?.();
7162
+ },
6671
7163
  copy: () => {
6672
- navigator.clipboard.writeText(rawHtml);
7164
+ navigator.clipboard?.writeText(rawHtml);
6673
7165
  },
6674
7166
  download: () => {
6675
7167
  const blob = new Blob([ctx.buffer], { type: "text/html" });
@@ -6776,6 +7268,14 @@ var OpenDocumentPlugin = class {
6776
7268
  group: "zoom",
6777
7269
  execute: () => instance.resetZoom?.()
6778
7270
  },
7271
+ {
7272
+ id: "fit-width",
7273
+ icon: "fit-width",
7274
+ label: "Fit to Width",
7275
+ type: "button",
7276
+ group: "zoom",
7277
+ execute: () => instance.fitToWidth?.()
7278
+ },
6779
7279
  {
6780
7280
  id: "rotate-cw",
6781
7281
  icon: "rotate-cw",
@@ -6892,7 +7392,10 @@ var OpenDocumentPlugin = class {
6892
7392
  const sW = availW / elW;
6893
7393
  const sH = availH / (isPresentation ? 540 : singlePageH);
6894
7394
  if (isPresentation) {
6895
- return Math.min(2.5, Math.min(sW, sH));
7395
+ if (mode === "page") {
7396
+ return Math.min(2.5, Math.min(sW, sH));
7397
+ }
7398
+ return Math.min(2.5, sW);
6896
7399
  }
6897
7400
  if (mode === "page") {
6898
7401
  return Math.max(0.35, Math.min(3, Math.min(sW, sH)));
@@ -7061,6 +7564,13 @@ var OpenDocumentPlugin = class {
7061
7564
  applyTransform();
7062
7565
  },
7063
7566
  fitToPage: () => {
7567
+ isUserZoomed = false;
7568
+ fitMode = "page";
7569
+ scale = calculateFitScale("page");
7570
+ rotation = 0;
7571
+ applyTransform();
7572
+ },
7573
+ fitToWidth: () => {
7064
7574
  isUserZoomed = false;
7065
7575
  fitMode = "width";
7066
7576
  scale = calculateFitScale("width");
@@ -7069,8 +7579,8 @@ var OpenDocumentPlugin = class {
7069
7579
  },
7070
7580
  resetZoom: () => {
7071
7581
  isUserZoomed = false;
7072
- fitMode = "width";
7073
- scale = calculateFitScale("width");
7582
+ fitMode = ctx?.options?.fitMode || "width";
7583
+ scale = calculateFitScale(fitMode);
7074
7584
  rotation = 0;
7075
7585
  container.scrollTop = 0;
7076
7586
  container.scrollLeft = 0;
@@ -7427,6 +7937,14 @@ var DocPlugin = class {
7427
7937
  group: "zoom",
7428
7938
  execute: () => instance.resetZoom?.()
7429
7939
  },
7940
+ {
7941
+ id: "fit-width",
7942
+ icon: "fit-width",
7943
+ label: "Fit to Width",
7944
+ type: "button",
7945
+ group: "zoom",
7946
+ execute: () => instance.fitToWidth?.()
7947
+ },
7430
7948
  {
7431
7949
  id: "rotate-cw",
7432
7950
  icon: "rotate-cw",
@@ -7648,6 +8166,13 @@ var DocPlugin = class {
7648
8166
  applyTransform();
7649
8167
  },
7650
8168
  fitToPage: () => {
8169
+ isUserZoomed = false;
8170
+ fitMode = "page";
8171
+ scale = calculateFitScale("page");
8172
+ rotation = 0;
8173
+ applyTransform();
8174
+ },
8175
+ fitToWidth: () => {
7651
8176
  isUserZoomed = false;
7652
8177
  fitMode = "width";
7653
8178
  scale = calculateFitScale("width");
@@ -7656,8 +8181,8 @@ var DocPlugin = class {
7656
8181
  },
7657
8182
  resetZoom: () => {
7658
8183
  isUserZoomed = false;
7659
- fitMode = "width";
7660
- scale = calculateFitScale("width");
8184
+ fitMode = ctx?.options?.fitMode || "width";
8185
+ scale = calculateFitScale(fitMode);
7661
8186
  rotation = 0;
7662
8187
  container.scrollTop = 0;
7663
8188
  container.scrollLeft = 0;
@@ -8153,6 +8678,14 @@ var PptPlugin = class {
8153
8678
  group: "zoom",
8154
8679
  execute: () => instance.resetZoom?.()
8155
8680
  },
8681
+ {
8682
+ id: "fit-width",
8683
+ icon: "fit-width",
8684
+ label: "Fit to Width",
8685
+ type: "button",
8686
+ group: "zoom",
8687
+ execute: () => instance.fitToWidth?.()
8688
+ },
8156
8689
  {
8157
8690
  id: "rotate-cw",
8158
8691
  icon: "rotate-cw",
@@ -8227,10 +8760,15 @@ var PptPlugin = class {
8227
8760
  let currentSlide = 1;
8228
8761
  let slides = [];
8229
8762
  const createdBlobUrls = [];
8230
- const calculateFitScale = () => {
8231
- const availW = Math.max(200, container.clientWidth - 48);
8232
- const availH = Math.max(200, container.clientHeight - 72);
8233
- return Math.min(1, Math.min(availW / 960, availH / 540));
8763
+ let fitMode = ctx?.options?.fitMode || "width";
8764
+ let isUserZoomed = false;
8765
+ const calculateFitScale = (mode = fitMode) => {
8766
+ const availW = Math.max(200, container.clientWidth - 32);
8767
+ const availH = Math.max(200, container.clientHeight - 32);
8768
+ if (mode === "page") {
8769
+ return Math.min(2.5, Math.min(availW / 960, availH / 540));
8770
+ }
8771
+ return Math.min(2.5, availW / 960);
8234
8772
  };
8235
8773
  const applyTransform = () => {
8236
8774
  const cW = 960;
@@ -8245,8 +8783,15 @@ var PptPlugin = class {
8245
8783
  slideCard.style.transform = `scale(${scale}) rotate(${rotation}deg)`;
8246
8784
  slideCard.style.transformOrigin = "center center";
8247
8785
  };
8786
+ const ro = typeof ResizeObserver !== "undefined" ? new ResizeObserver(() => {
8787
+ if (!isUserZoomed) {
8788
+ scale = calculateFitScale(fitMode);
8789
+ applyTransform();
8790
+ }
8791
+ }) : null;
8792
+ ro?.observe(container);
8248
8793
  setTimeout(() => {
8249
- scale = calculateFitScale();
8794
+ scale = calculateFitScale(fitMode);
8250
8795
  applyTransform();
8251
8796
  }, 60);
8252
8797
  try {
@@ -8339,6 +8884,7 @@ var PptPlugin = class {
8339
8884
  };
8340
8885
  renderSlide(1);
8341
8886
  const cleanup = () => {
8887
+ ro?.disconnect();
8342
8888
  for (const u of createdBlobUrls) {
8343
8889
  URL.revokeObjectURL(u);
8344
8890
  }
@@ -8349,28 +8895,44 @@ var PptPlugin = class {
8349
8895
  return {
8350
8896
  destroy: cleanup,
8351
8897
  zoomIn: () => {
8898
+ isUserZoomed = true;
8352
8899
  scale += 0.15;
8353
8900
  applyTransform();
8354
8901
  },
8355
8902
  zoomOut: () => {
8903
+ isUserZoomed = true;
8356
8904
  scale = Math.max(0.2, scale - 0.15);
8357
8905
  applyTransform();
8358
8906
  },
8359
8907
  getZoom: () => scale,
8360
8908
  setZoom: (level) => {
8909
+ isUserZoomed = true;
8361
8910
  scale = level;
8362
8911
  applyTransform();
8363
8912
  },
8364
8913
  fitToPage: () => {
8365
- scale = calculateFitScale();
8914
+ isUserZoomed = false;
8915
+ fitMode = "page";
8916
+ scale = calculateFitScale("page");
8917
+ rotation = 0;
8918
+ applyTransform();
8919
+ },
8920
+ fitToWidth: () => {
8921
+ isUserZoomed = false;
8922
+ fitMode = "width";
8923
+ scale = calculateFitScale("width");
8366
8924
  rotation = 0;
8367
8925
  applyTransform();
8368
8926
  },
8369
8927
  resetZoom: () => {
8370
- scale = calculateFitScale();
8928
+ isUserZoomed = false;
8929
+ fitMode = ctx?.options?.fitMode || "width";
8930
+ scale = calculateFitScale(fitMode);
8371
8931
  rotation = 0;
8372
8932
  container.scrollTop = 0;
8373
8933
  container.scrollLeft = 0;
8934
+ ctx.container.scrollTop = 0;
8935
+ ctx.container.scrollLeft = 0;
8374
8936
  applyTransform();
8375
8937
  },
8376
8938
  rotateCW: () => {