@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.js CHANGED
@@ -1140,6 +1140,10 @@ var FilePreviewViewer = class _FilePreviewViewer {
1140
1140
  * Preview a file in the given container element.
1141
1141
  */
1142
1142
  async preview(container, source, options = {}) {
1143
+ options = {
1144
+ ...options,
1145
+ fitMode: options.fitMode ?? "width"
1146
+ };
1143
1147
  this.currentOptions = options;
1144
1148
  this.abort();
1145
1149
  this.abortController = new AbortController();
@@ -1188,8 +1192,8 @@ var FilePreviewViewer = class _FilePreviewViewer {
1188
1192
  this.activeInstance = instance;
1189
1193
  instance.openInSeparateWindow = () => this.openInSeparateWindow();
1190
1194
  instance.toggleThumbnails = () => this.toggleThumbnails();
1191
- if (!instance.resetZoom && instance.fitToPage) {
1192
- instance.resetZoom = () => instance.fitToPage?.();
1195
+ if (!instance.resetZoom) {
1196
+ instance.resetZoom = () => instance.fitToWidth ? instance.fitToWidth() : instance.fitToPage?.();
1193
1197
  }
1194
1198
  this.hideLoading();
1195
1199
  this.eventEmitter.emit("loaded", { metadata, plugin: matchedPlugin.id });
@@ -1586,7 +1590,7 @@ var FilePreviewViewer = class _FilePreviewViewer {
1586
1590
  this.wrapperEl?.classList.toggle("fp-fullscreen-active");
1587
1591
  }
1588
1592
  setTimeout(() => {
1589
- this.activeInstance?.fitToPage?.();
1593
+ this.triggerAutoFit();
1590
1594
  }, 120);
1591
1595
  }
1592
1596
  /**
@@ -1678,19 +1682,85 @@ var FilePreviewViewer = class _FilePreviewViewer {
1678
1682
  if (this.wrapperEl?.parentNode) {
1679
1683
  this.wrapperEl.parentNode.removeChild(this.wrapperEl);
1680
1684
  }
1685
+ if (typeof document !== "undefined" && !document.getElementById("fp-core-injected-styles")) {
1686
+ const styleEl = document.createElement("style");
1687
+ styleEl.id = "fp-core-injected-styles";
1688
+ styleEl.textContent = `
1689
+ .fp-viewer {
1690
+ display: flex !important;
1691
+ flex-direction: column !important;
1692
+ width: 100% !important;
1693
+ height: 100% !important;
1694
+ overflow: hidden !important;
1695
+ position: relative !important;
1696
+ box-sizing: border-box !important;
1697
+ }
1698
+ .fp-body {
1699
+ display: flex !important;
1700
+ flex: 1 1 0% !important;
1701
+ min-height: 0 !important;
1702
+ min-width: 0 !important;
1703
+ width: 100% !important;
1704
+ height: 100% !important;
1705
+ overflow: hidden !important;
1706
+ position: relative !important;
1707
+ box-sizing: border-box !important;
1708
+ }
1709
+ .fp-content {
1710
+ flex: 1 1 0% !important;
1711
+ position: relative !important;
1712
+ overflow: auto !important;
1713
+ display: flex !important;
1714
+ flex-direction: column !important;
1715
+ align-items: stretch !important;
1716
+ justify-content: flex-start !important;
1717
+ width: 100% !important;
1718
+ height: 100% !important;
1719
+ min-width: 0 !important;
1720
+ min-height: 0 !important;
1721
+ box-sizing: border-box !important;
1722
+ }
1723
+ `;
1724
+ document.head.appendChild(styleEl);
1725
+ }
1681
1726
  const themeClass = options.theme === "dark" ? "fp-theme-dark" : "";
1682
1727
  const toolbarPos = options.toolbarPosition ?? "top";
1683
1728
  this.wrapperEl = document.createElement("div");
1684
1729
  this.wrapperEl.className = `fp-viewer ${themeClass} ${options.className ?? ""}`.trim();
1685
1730
  this.wrapperEl.tabIndex = 0;
1731
+ this.wrapperEl.style.display = "flex";
1732
+ this.wrapperEl.style.flexDirection = "column";
1733
+ this.wrapperEl.style.width = "100%";
1734
+ this.wrapperEl.style.height = "100%";
1735
+ this.wrapperEl.style.overflow = "hidden";
1736
+ this.wrapperEl.style.position = "relative";
1686
1737
  const toolbarEl = document.createElement("div");
1687
1738
  toolbarEl.className = "fp-toolbar-container";
1688
1739
  this.contentEl = document.createElement("div");
1689
1740
  this.contentEl.className = "fp-content";
1741
+ this.contentEl.style.flex = "1 1 0%";
1742
+ this.contentEl.style.position = "relative";
1743
+ this.contentEl.style.overflow = "auto";
1744
+ this.contentEl.style.display = "flex";
1745
+ this.contentEl.style.flexDirection = "column";
1746
+ this.contentEl.style.alignItems = "stretch";
1747
+ this.contentEl.style.justifyContent = "flex-start";
1748
+ this.contentEl.style.width = "100%";
1749
+ this.contentEl.style.height = "100%";
1750
+ this.contentEl.style.minWidth = "0";
1751
+ this.contentEl.style.minHeight = "0";
1752
+ this.contentEl.style.boxSizing = "border-box";
1690
1753
  const thumbnailEl = document.createElement("div");
1691
1754
  thumbnailEl.className = "fp-thumbnail-container";
1692
1755
  const bodyEl = document.createElement("div");
1693
1756
  bodyEl.className = "fp-body";
1757
+ bodyEl.style.display = "flex";
1758
+ bodyEl.style.flex = "1 1 0%";
1759
+ bodyEl.style.minHeight = "0";
1760
+ bodyEl.style.minWidth = "0";
1761
+ bodyEl.style.width = "100%";
1762
+ bodyEl.style.overflow = "hidden";
1763
+ bodyEl.style.position = "relative";
1694
1764
  bodyEl.appendChild(thumbnailEl);
1695
1765
  bodyEl.appendChild(this.contentEl);
1696
1766
  const titleBarEl = document.createElement("div");
@@ -1713,18 +1783,29 @@ var FilePreviewViewer = class _FilePreviewViewer {
1713
1783
  this.thumbnailPanel = new ThumbnailPanel(thumbnailEl, (isOpen) => {
1714
1784
  this.toolbar?.setActionActive("thumbnails", isOpen);
1715
1785
  setTimeout(() => {
1716
- this.activeInstance?.fitToPage?.();
1786
+ this.triggerAutoFit();
1717
1787
  }, 260);
1718
1788
  });
1719
1789
  this.setupKeyboardShortcuts();
1720
1790
  this.setupDragAndDrop(container, options);
1721
1791
  this.setupResizeAndFullscreenListeners();
1722
1792
  }
1793
+ triggerAutoFit() {
1794
+ if (!this.activeInstance) return;
1795
+ const mode = this.currentOptions?.fitMode ?? "width";
1796
+ if (mode === "width" && this.activeInstance.fitToWidth) {
1797
+ this.activeInstance.fitToWidth();
1798
+ } else if (this.activeInstance.fitToPage) {
1799
+ this.activeInstance.fitToPage();
1800
+ } else if (this.activeInstance.resetZoom) {
1801
+ this.activeInstance.resetZoom();
1802
+ }
1803
+ }
1723
1804
  setupResizeAndFullscreenListeners() {
1724
1805
  if (this.fullscreenHandler) return;
1725
1806
  this.fullscreenHandler = () => {
1726
1807
  setTimeout(() => {
1727
- this.activeInstance?.fitToPage?.();
1808
+ this.triggerAutoFit();
1728
1809
  }, 100);
1729
1810
  };
1730
1811
  document.addEventListener("fullscreenchange", this.fullscreenHandler);
@@ -1732,7 +1813,7 @@ var FilePreviewViewer = class _FilePreviewViewer {
1732
1813
  if (typeof ResizeObserver !== "undefined" && this.contentEl) {
1733
1814
  this.resizeObserver = new ResizeObserver(() => {
1734
1815
  if (this.activeInstance && (!this.activeInstance.getZoom || Math.abs((this.activeInstance.getZoom?.() ?? 1) - 1) < 0.05)) {
1735
- this.activeInstance.fitToPage?.();
1816
+ this.triggerAutoFit();
1736
1817
  }
1737
1818
  });
1738
1819
  this.resizeObserver.observe(this.contentEl);
@@ -1760,7 +1841,7 @@ var FilePreviewViewer = class _FilePreviewViewer {
1760
1841
  } else if (e.key === "-" || e.key === "_") {
1761
1842
  this.activeInstance.zoomOut?.();
1762
1843
  } else if (e.key === "0") {
1763
- this.activeInstance.fitToPage?.();
1844
+ this.resetZoom();
1764
1845
  } else if (e.key === "r" || e.key === "R") {
1765
1846
  this.activeInstance.rotateCW?.();
1766
1847
  } else if (e.key === "f" || e.key === "F") {
@@ -2383,7 +2464,7 @@ var PdfPlugin = class {
2383
2464
  renderPage(currentPage);
2384
2465
  },
2385
2466
  resetZoom: () => {
2386
- fitMode = "page";
2467
+ fitMode = ctx?.options?.fitMode || "width";
2387
2468
  zoomScale = 1;
2388
2469
  rotation = 0;
2389
2470
  container.scrollTop = 0;
@@ -2567,6 +2648,16 @@ var MediaPlugin = class {
2567
2648
  instance.resetZoom?.();
2568
2649
  }
2569
2650
  },
2651
+ {
2652
+ id: "fit-width",
2653
+ icon: "fit-width",
2654
+ label: "Fit to Width",
2655
+ type: "button",
2656
+ group: "zoom",
2657
+ execute: () => {
2658
+ instance.fitToWidth?.();
2659
+ }
2660
+ },
2570
2661
  {
2571
2662
  id: "rotate-cw",
2572
2663
  icon: "rotate-cw",
@@ -2663,9 +2754,30 @@ var MediaPlugin = class {
2663
2754
  const isVideo = mimeType.startsWith("video/") || VIDEO_EXTS.includes(ctx.metadata.extension || "");
2664
2755
  const isAudio = mimeType.startsWith("audio/") || AUDIO_EXTS.includes(ctx.metadata.extension || "");
2665
2756
  let url = "";
2757
+ let naturalW = 800;
2758
+ let naturalH = 600;
2666
2759
  if (ctx.metadata.extension === ".svg" || mimeType === "image/svg+xml") {
2667
2760
  const decoder = new TextDecoder("utf-8");
2668
2761
  const svgText = decoder.decode(ctx.buffer);
2762
+ try {
2763
+ const vbMatch = svgText.match(/viewBox=["']\s*([0-9.-]+)\s+([0-9.-]+)\s+([0-9.-]+)\s+([0-9.-]+)\s*["']/i);
2764
+ if (vbMatch) {
2765
+ const vw = parseFloat(vbMatch[3]);
2766
+ const vh = parseFloat(vbMatch[4]);
2767
+ if (vw > 0 && vh > 0) {
2768
+ naturalW = vw;
2769
+ naturalH = vh;
2770
+ }
2771
+ } else {
2772
+ const wMatch = svgText.match(/width=["']([0-9.]+)(?:px)?["']/i);
2773
+ const hMatch = svgText.match(/height=["']([0-9.]+)(?:px)?["']/i);
2774
+ if (wMatch && hMatch) {
2775
+ naturalW = parseFloat(wMatch[1]) || naturalW;
2776
+ naturalH = parseFloat(hMatch[1]) || naturalH;
2777
+ }
2778
+ }
2779
+ } catch {
2780
+ }
2669
2781
  const blob = new Blob([svgText], { type: "image/svg+xml" });
2670
2782
  url = URL.createObjectURL(blob);
2671
2783
  } else {
@@ -2713,7 +2825,7 @@ var MediaPlugin = class {
2713
2825
  scrollWrapper.style.width = "max-content";
2714
2826
  scrollWrapper.style.height = "max-content";
2715
2827
  scrollWrapper.style.display = "flex";
2716
- scrollWrapper.style.justifyContent = "center";
2828
+ scrollWrapper.style.flexDirection = "column";
2717
2829
  scrollWrapper.style.alignItems = "center";
2718
2830
  scrollWrapper.style.padding = "16px";
2719
2831
  scrollWrapper.style.boxSizing = "border-box";
@@ -2724,40 +2836,54 @@ var MediaPlugin = class {
2724
2836
  sizer.style.display = "flex";
2725
2837
  sizer.style.justifyContent = "center";
2726
2838
  sizer.style.alignItems = "center";
2839
+ sizer.style.margin = "auto 0";
2727
2840
  sizer.appendChild(element);
2728
2841
  scrollWrapper.appendChild(sizer);
2729
2842
  ctx.container.style.overflow = "auto";
2730
2843
  ctx.container.style.padding = "0";
2731
2844
  ctx.container.innerHTML = "";
2732
2845
  ctx.container.appendChild(scrollWrapper);
2733
- let naturalW = 800;
2734
- let naturalH = 600;
2735
- let baseW = 800;
2736
- let baseH = 600;
2846
+ let baseW = naturalW;
2847
+ let baseH = naturalH;
2848
+ let fitMode = ctx?.options?.fitMode || "width";
2849
+ let isUserZoomed = false;
2737
2850
  const updateBaseDimensions = () => {
2738
2851
  if (!isImage) return;
2739
2852
  const img = element;
2740
- naturalW = img.naturalWidth || naturalW;
2741
- naturalH = img.naturalHeight || naturalH;
2742
- const availW = Math.max(100, ctx.container.clientWidth - 48);
2743
- const availH = Math.max(100, ctx.container.clientHeight - 48);
2744
- const fitRatio = Math.min(1, availW / naturalW, availH / naturalH);
2853
+ if (img.naturalWidth > 0 && img.naturalHeight > 0) {
2854
+ naturalW = img.naturalWidth;
2855
+ naturalH = img.naturalHeight;
2856
+ }
2857
+ const availW = Math.max(100, ctx.container.clientWidth - 32);
2858
+ const availH = Math.max(100, ctx.container.clientHeight - 32);
2859
+ let fitRatio;
2860
+ if (fitMode === "page") {
2861
+ fitRatio = Math.min(availW / naturalW, availH / naturalH);
2862
+ } else {
2863
+ fitRatio = availW / naturalW;
2864
+ }
2745
2865
  baseW = Math.max(1, Math.round(naturalW * fitRatio));
2746
2866
  baseH = Math.max(1, Math.round(naturalH * fitRatio));
2747
2867
  };
2748
2868
  const applyTransform = () => {
2749
2869
  if (isImage) {
2750
- updateBaseDimensions();
2870
+ if (!isUserZoomed) {
2871
+ updateBaseDimensions();
2872
+ }
2873
+ const availH = Math.max(100, ctx.container.clientHeight - 32);
2751
2874
  const isRotated90 = rotation % 180 !== 0;
2752
2875
  const boxW = Math.round((isRotated90 ? baseH : baseW) * currentZoom);
2753
2876
  const boxH = Math.round((isRotated90 ? baseW : baseH) * currentZoom);
2754
2877
  sizer.style.width = `${boxW}px`;
2755
2878
  sizer.style.height = `${boxH}px`;
2756
- element.style.width = `${baseW}px`;
2757
- element.style.height = `${baseH}px`;
2879
+ sizer.style.margin = boxH < availH ? "auto 0" : "0";
2880
+ const imgW = isRotated90 ? boxH : boxW;
2881
+ const imgH = isRotated90 ? boxW : boxH;
2882
+ element.style.width = `${imgW}px`;
2883
+ element.style.height = `${imgH}px`;
2758
2884
  element.style.maxWidth = "none";
2759
2885
  element.style.maxHeight = "none";
2760
- element.style.transform = `scale(${currentZoom}) rotate(${rotation}deg)`;
2886
+ element.style.transform = rotation ? `rotate(${rotation}deg)` : "none";
2761
2887
  element.style.transformOrigin = "center center";
2762
2888
  element.style.flexShrink = "0";
2763
2889
  } else {
@@ -2777,7 +2903,8 @@ var MediaPlugin = class {
2777
2903
  }
2778
2904
  }
2779
2905
  const ro = typeof ResizeObserver !== "undefined" ? new ResizeObserver(() => {
2780
- if (currentZoom === 1) {
2906
+ if (!isUserZoomed && currentZoom === 1) {
2907
+ updateBaseDimensions();
2781
2908
  applyTransform();
2782
2909
  }
2783
2910
  }) : null;
@@ -2792,28 +2919,49 @@ var MediaPlugin = class {
2792
2919
  return {
2793
2920
  destroy: cleanup,
2794
2921
  zoomIn: isImage ? () => {
2795
- currentZoom += 0.1;
2922
+ isUserZoomed = true;
2923
+ currentZoom = Math.min(5, Math.round((currentZoom + 0.15) * 100) / 100);
2796
2924
  applyTransform();
2797
2925
  } : void 0,
2798
2926
  zoomOut: isImage ? () => {
2799
- currentZoom = Math.max(0.1, currentZoom - 0.1);
2927
+ isUserZoomed = true;
2928
+ currentZoom = Math.max(0.1, Math.round((currentZoom - 0.15) * 100) / 100);
2800
2929
  applyTransform();
2801
2930
  } : void 0,
2802
2931
  getZoom: isImage ? () => currentZoom : void 0,
2803
2932
  setZoom: isImage ? (level) => {
2933
+ isUserZoomed = true;
2804
2934
  currentZoom = level;
2805
2935
  applyTransform();
2806
2936
  } : void 0,
2807
2937
  fitToPage: isImage ? () => {
2938
+ isUserZoomed = false;
2939
+ fitMode = "page";
2940
+ currentZoom = 1;
2941
+ rotation = 0;
2942
+ ctx.container.scrollTop = 0;
2943
+ ctx.container.scrollLeft = 0;
2944
+ updateBaseDimensions();
2945
+ applyTransform();
2946
+ } : void 0,
2947
+ fitToWidth: isImage ? () => {
2948
+ isUserZoomed = false;
2949
+ fitMode = "width";
2808
2950
  currentZoom = 1;
2809
2951
  rotation = 0;
2952
+ ctx.container.scrollTop = 0;
2953
+ ctx.container.scrollLeft = 0;
2954
+ updateBaseDimensions();
2810
2955
  applyTransform();
2811
2956
  } : void 0,
2812
2957
  resetZoom: isImage ? () => {
2958
+ isUserZoomed = false;
2959
+ fitMode = ctx?.options?.fitMode || "width";
2813
2960
  currentZoom = 1;
2814
2961
  rotation = 0;
2815
2962
  ctx.container.scrollTop = 0;
2816
2963
  ctx.container.scrollLeft = 0;
2964
+ updateBaseDimensions();
2817
2965
  applyTransform();
2818
2966
  } : void 0,
2819
2967
  rotateCW: isImage || isVideo ? () => {
@@ -2940,6 +3088,14 @@ var DocxPlugin = class {
2940
3088
  group: "zoom",
2941
3089
  execute: () => instance.resetZoom?.()
2942
3090
  },
3091
+ {
3092
+ id: "fit-width",
3093
+ icon: "fit-width",
3094
+ label: "Fit to Width",
3095
+ type: "button",
3096
+ group: "zoom",
3097
+ execute: () => instance.fitToWidth?.()
3098
+ },
2943
3099
  {
2944
3100
  id: "rotate-cw",
2945
3101
  icon: "rotate-cw",
@@ -3199,13 +3355,19 @@ var DocxPlugin = class {
3199
3355
  }
3200
3356
  scale = 1;
3201
3357
  let rotation = 0;
3202
- let fitMode = "page";
3358
+ let fitMode = ctx?.options?.fitMode || "width";
3203
3359
  let isUserZoomed = false;
3204
- const calculateFitScale = (_mode = fitMode) => {
3360
+ const calculateFitScale = (mode = fitMode) => {
3205
3361
  const activeEl = pageElements[currentPage - 1] || wrapper.querySelector("section.docx") || wrapper;
3206
3362
  const elW = activeEl.offsetWidth || 816;
3363
+ const elH = activeEl.offsetHeight || 1056;
3207
3364
  const availW = Math.max(280, ctx.container.clientWidth - 32);
3365
+ const availH = Math.max(280, ctx.container.clientHeight - 32);
3208
3366
  const sW = availW / elW;
3367
+ const sH = availH / elH;
3368
+ if (mode === "page") {
3369
+ return Math.max(0.35, Math.min(3, Math.min(sW, sH)));
3370
+ }
3209
3371
  return Math.max(0.35, Math.min(3, sW));
3210
3372
  };
3211
3373
  const applyTransform = () => {
@@ -3226,7 +3388,7 @@ var DocxPlugin = class {
3226
3388
  if (typeof ResizeObserver !== "undefined") {
3227
3389
  resizeObserver = new ResizeObserver(() => {
3228
3390
  if (!isUserZoomed) {
3229
- const newFit = calculateFitScale("page");
3391
+ const newFit = calculateFitScale(fitMode);
3230
3392
  if (Math.abs(scale - newFit) > 0.015) {
3231
3393
  scale = newFit;
3232
3394
  applyTransform();
@@ -3236,7 +3398,7 @@ var DocxPlugin = class {
3236
3398
  resizeObserver.observe(ctx.container);
3237
3399
  }
3238
3400
  setTimeout(() => {
3239
- scale = calculateFitScale("page");
3401
+ scale = calculateFitScale(fitMode);
3240
3402
  applyTransform();
3241
3403
  }, 40);
3242
3404
  const cleanup = () => {
@@ -3275,13 +3437,22 @@ var DocxPlugin = class {
3275
3437
  },
3276
3438
  fitToPage: () => {
3277
3439
  isUserZoomed = false;
3440
+ fitMode = "page";
3278
3441
  scale = calculateFitScale("page");
3279
3442
  rotation = 0;
3280
3443
  applyTransform();
3281
3444
  },
3445
+ fitToWidth: () => {
3446
+ isUserZoomed = false;
3447
+ fitMode = "width";
3448
+ scale = calculateFitScale("width");
3449
+ rotation = 0;
3450
+ applyTransform();
3451
+ },
3282
3452
  resetZoom: () => {
3283
3453
  isUserZoomed = false;
3284
- scale = calculateFitScale("page");
3454
+ fitMode = ctx?.options?.fitMode || "width";
3455
+ scale = calculateFitScale(fitMode);
3285
3456
  rotation = 0;
3286
3457
  ctx.container.scrollTop = 0;
3287
3458
  ctx.container.scrollLeft = 0;
@@ -3746,6 +3917,16 @@ var ExcelPlugin = class {
3746
3917
  instance.resetZoom?.();
3747
3918
  }
3748
3919
  },
3920
+ {
3921
+ id: "fit-width",
3922
+ icon: "fit-width",
3923
+ label: "Fit to Width",
3924
+ type: "button",
3925
+ group: "zoom",
3926
+ execute: () => {
3927
+ instance.fitToWidth?.();
3928
+ }
3929
+ },
3749
3930
  {
3750
3931
  id: "download",
3751
3932
  icon: "download",
@@ -3962,6 +4143,11 @@ var ExcelPlugin = class {
3962
4143
  scale = calculateFitScale();
3963
4144
  applyTransform();
3964
4145
  },
4146
+ fitToWidth: () => {
4147
+ isUserZoomed = false;
4148
+ scale = calculateFitScale();
4149
+ applyTransform();
4150
+ },
3965
4151
  resetZoom: () => {
3966
4152
  isUserZoomed = false;
3967
4153
  scale = calculateFitScale();
@@ -4109,6 +4295,16 @@ var CsvPlugin = class {
4109
4295
  instance.resetZoom?.();
4110
4296
  }
4111
4297
  },
4298
+ {
4299
+ id: "fit-width",
4300
+ icon: "fit-width",
4301
+ label: "Fit to Width",
4302
+ type: "button",
4303
+ group: "zoom",
4304
+ execute: () => {
4305
+ instance.fitToWidth?.();
4306
+ }
4307
+ },
4112
4308
  {
4113
4309
  id: "download",
4114
4310
  icon: "download",
@@ -4322,6 +4518,11 @@ var CsvPlugin = class {
4322
4518
  scale = calculateFitScale();
4323
4519
  applyScale();
4324
4520
  },
4521
+ fitToWidth: () => {
4522
+ isUserZoomed = false;
4523
+ scale = calculateFitScale();
4524
+ applyScale();
4525
+ },
4325
4526
  resetZoom: () => {
4326
4527
  isUserZoomed = false;
4327
4528
  scale = calculateFitScale();
@@ -4353,31 +4554,80 @@ function csvPlugin() {
4353
4554
  }
4354
4555
  var CODE_EXTENSIONS = [
4355
4556
  ".txt",
4557
+ ".log",
4558
+ ".ini",
4559
+ ".cfg",
4560
+ ".conf",
4561
+ ".env",
4356
4562
  ".json",
4563
+ ".jsonc",
4564
+ ".json5",
4357
4565
  ".js",
4358
- ".ts",
4566
+ ".mjs",
4567
+ ".cjs",
4359
4568
  ".jsx",
4569
+ ".ts",
4570
+ ".mts",
4571
+ ".cts",
4360
4572
  ".tsx",
4361
4573
  ".html",
4574
+ ".htm",
4575
+ ".xhtml",
4362
4576
  ".css",
4363
4577
  ".scss",
4578
+ ".sass",
4364
4579
  ".less",
4365
4580
  ".md",
4581
+ ".markdown",
4366
4582
  ".xml",
4583
+ ".svg",
4584
+ ".xaml",
4367
4585
  ".yml",
4368
4586
  ".yaml",
4587
+ ".toml",
4369
4588
  ".sh",
4370
4589
  ".bash",
4590
+ ".zsh",
4591
+ ".fish",
4592
+ ".bat",
4593
+ ".cmd",
4594
+ ".ps1",
4371
4595
  ".py",
4596
+ ".pyw",
4372
4597
  ".java",
4598
+ ".class",
4373
4599
  ".c",
4374
4600
  ".cpp",
4601
+ ".cc",
4602
+ ".cxx",
4375
4603
  ".h",
4604
+ ".hpp",
4605
+ ".hxx",
4376
4606
  ".cs",
4607
+ ".csx",
4377
4608
  ".go",
4378
4609
  ".rs",
4379
4610
  ".sql",
4380
- ".php"
4611
+ ".php",
4612
+ ".phtml",
4613
+ ".rb",
4614
+ ".swift",
4615
+ ".kt",
4616
+ ".kts",
4617
+ ".scala",
4618
+ ".r",
4619
+ ".lua",
4620
+ ".pl",
4621
+ ".pm",
4622
+ ".dart",
4623
+ ".graphql",
4624
+ ".gql",
4625
+ ".proto",
4626
+ ".diff",
4627
+ ".patch",
4628
+ ".dockerfile",
4629
+ ".properties",
4630
+ ".gradle"
4381
4631
  ];
4382
4632
  var CodePlugin = class {
4383
4633
  id = "code";
@@ -4395,34 +4645,36 @@ var CodePlugin = class {
4395
4645
  getToolbarActions(instance) {
4396
4646
  const totalPages = instance.getPageCount?.() ?? 1;
4397
4647
  const actions = [];
4398
- actions.push({
4399
- id: "thumbnails",
4400
- icon: "thumbnails",
4401
- label: "Page Thumbnails",
4402
- type: "button",
4403
- group: "navigation",
4404
- execute: () => instance.toggleThumbnails?.()
4405
- });
4406
- actions.push({
4407
- id: "page-nav",
4408
- icon: "",
4409
- label: "Page Navigation",
4410
- type: "page-nav",
4411
- group: "navigation",
4412
- value: instance.getCurrentPage?.() ?? 1,
4413
- max: totalPages,
4414
- execute: (action, page) => {
4415
- const cur = instance.getCurrentPage?.() ?? 1;
4416
- const max = instance.getPageCount?.() ?? 1;
4417
- if (action === "prev") {
4418
- if (cur > 1) instance.goToPage?.(cur - 1);
4419
- } else if (action === "next") {
4420
- if (cur < max) instance.goToPage?.(cur + 1);
4421
- } else if (typeof page === "number") {
4422
- instance.goToPage?.(page);
4648
+ if (totalPages > 1) {
4649
+ actions.push({
4650
+ id: "thumbnails",
4651
+ icon: "thumbnails",
4652
+ label: "Page Thumbnails",
4653
+ type: "button",
4654
+ group: "navigation",
4655
+ execute: () => instance.toggleThumbnails?.()
4656
+ });
4657
+ actions.push({
4658
+ id: "page-nav",
4659
+ icon: "",
4660
+ label: "Page Navigation",
4661
+ type: "page-nav",
4662
+ group: "navigation",
4663
+ value: instance.getCurrentPage?.() ?? 1,
4664
+ max: totalPages,
4665
+ execute: (action, page) => {
4666
+ const cur = instance.getCurrentPage?.() ?? 1;
4667
+ const max = instance.getPageCount?.() ?? 1;
4668
+ if (action === "prev") {
4669
+ if (cur > 1) instance.goToPage?.(cur - 1);
4670
+ } else if (action === "next") {
4671
+ if (cur < max) instance.goToPage?.(cur + 1);
4672
+ } else if (typeof page === "number") {
4673
+ instance.goToPage?.(page);
4674
+ }
4423
4675
  }
4424
- }
4425
- });
4676
+ });
4677
+ }
4426
4678
  actions.push(
4427
4679
  {
4428
4680
  id: "zoom-out",
@@ -4454,6 +4706,16 @@ var CodePlugin = class {
4454
4706
  instance.resetZoom?.();
4455
4707
  }
4456
4708
  },
4709
+ {
4710
+ id: "fit-width",
4711
+ icon: "fit-width",
4712
+ label: "Fit to Width",
4713
+ type: "button",
4714
+ group: "zoom",
4715
+ execute: () => {
4716
+ instance.fitToWidth?.();
4717
+ }
4718
+ },
4457
4719
  {
4458
4720
  id: "copy",
4459
4721
  icon: "copy",
@@ -4549,10 +4811,6 @@ var CodePlugin = class {
4549
4811
  }
4550
4812
  const totalPages = Math.max(1, rawPages.length);
4551
4813
  let currentPage = 1;
4552
- const container = document.createElement("div");
4553
- container.style.width = "100%";
4554
- container.style.height = "100%";
4555
- container.style.overflow = "auto";
4556
4814
  let fontSize = 13;
4557
4815
  let rotation = 0;
4558
4816
  let zoomLevel = 1;
@@ -4561,9 +4819,10 @@ var CodePlugin = class {
4561
4819
  const code = document.createElement("code");
4562
4820
  const sizer = document.createElement("div");
4563
4821
  const scrollWrapper = document.createElement("div");
4822
+ const lineGutter = document.createElement("div");
4823
+ ctx.container.style.overflow = "auto";
4564
4824
  if (isTxt) {
4565
- container.style.overflow = "auto";
4566
- container.style.backgroundColor = "#f1f5f9";
4825
+ ctx.container.style.backgroundColor = "#f1f5f9";
4567
4826
  scrollWrapper.className = "fp-code-scroll-wrapper";
4568
4827
  scrollWrapper.style.minWidth = "100%";
4569
4828
  scrollWrapper.style.minHeight = "100%";
@@ -4598,18 +4857,42 @@ var CodePlugin = class {
4598
4857
  pre.style.transition = "transform 0.15s ease";
4599
4858
  pre.style.flexShrink = "0";
4600
4859
  } else {
4601
- container.style.overflow = "auto";
4602
- container.style.backgroundColor = "#1e1e1e";
4603
- container.style.color = "#d4d4d4";
4604
- container.style.padding = "16px";
4605
- container.style.boxSizing = "border-box";
4860
+ ctx.container.style.backgroundColor = "#1e1e1e";
4861
+ ctx.container.style.color = "#d4d4d4";
4862
+ scrollWrapper.className = "fp-code-scroll-wrapper";
4863
+ scrollWrapper.style.minWidth = "100%";
4864
+ scrollWrapper.style.minHeight = "100%";
4865
+ scrollWrapper.style.width = "max-content";
4866
+ scrollWrapper.style.height = "max-content";
4867
+ scrollWrapper.style.display = "flex";
4868
+ scrollWrapper.style.alignItems = "flex-start";
4869
+ scrollWrapper.style.padding = "16px";
4870
+ scrollWrapper.style.boxSizing = "border-box";
4871
+ const lineCount = fullText.split(/\r?\n/).length || 1;
4872
+ const gutterLines = [];
4873
+ for (let i = 1; i <= lineCount; i++) {
4874
+ gutterLines.push(String(i));
4875
+ }
4876
+ lineGutter.className = "fp-code-gutter";
4877
+ lineGutter.style.userSelect = "none";
4878
+ lineGutter.style.textAlign = "right";
4879
+ lineGutter.style.paddingRight = "16px";
4880
+ lineGutter.style.marginRight = "16px";
4881
+ lineGutter.style.borderRight = "1px solid #333333";
4882
+ lineGutter.style.color = "#858585";
4883
+ lineGutter.style.fontFamily = "Consolas, Menlo, Monaco, 'Courier New', monospace";
4884
+ lineGutter.style.fontSize = `${fontSize}px`;
4885
+ lineGutter.style.lineHeight = "1.6";
4886
+ lineGutter.style.flexShrink = "0";
4887
+ lineGutter.textContent = gutterLines.join("\n");
4606
4888
  pre.style.margin = "0";
4607
- pre.style.fontFamily = "Consolas, Menlo, Monaco, monospace";
4889
+ pre.style.fontFamily = "Consolas, Menlo, Monaco, 'Courier New', monospace";
4608
4890
  pre.style.fontSize = `${fontSize}px`;
4609
- pre.style.lineHeight = "1.5";
4610
- pre.style.whiteSpace = "pre-wrap";
4611
- pre.style.wordBreak = "break-all";
4612
- pre.style.transformOrigin = "top left";
4891
+ pre.style.lineHeight = "1.6";
4892
+ pre.style.whiteSpace = "pre";
4893
+ pre.style.wordBreak = "normal";
4894
+ pre.style.overflowWrap = "normal";
4895
+ pre.style.flex = "1";
4613
4896
  }
4614
4897
  const ext = (ctx.metadata.extension || "").replace(".", "");
4615
4898
  const renderCodePage = (text) => {
@@ -4629,25 +4912,27 @@ var CodePlugin = class {
4629
4912
  };
4630
4913
  renderCodePage(rawPages[0] || (isTxt ? "" : fullText));
4631
4914
  pre.appendChild(code);
4915
+ ctx.container.innerHTML = "";
4632
4916
  if (isTxt) {
4633
4917
  sizer.appendChild(pre);
4634
4918
  scrollWrapper.appendChild(sizer);
4635
- container.appendChild(scrollWrapper);
4919
+ ctx.container.appendChild(scrollWrapper);
4636
4920
  } else {
4637
- container.appendChild(pre);
4921
+ scrollWrapper.appendChild(lineGutter);
4922
+ scrollWrapper.appendChild(pre);
4923
+ ctx.container.appendChild(scrollWrapper);
4638
4924
  }
4639
4925
  const showPage = (pageNum) => {
4640
4926
  currentPage = Math.max(1, Math.min(totalPages, pageNum));
4641
4927
  renderCodePage(rawPages[currentPage - 1] || (isTxt ? "" : fullText));
4642
- container.scrollTop = 0;
4928
+ ctx.container.scrollTop = 0;
4643
4929
  ctx.emit("page-change", { page: currentPage, total: totalPages });
4644
4930
  };
4645
4931
  if (totalPages > 1) {
4646
4932
  showPage(1);
4647
4933
  }
4648
- ctx.container.appendChild(container);
4649
4934
  const calculateTxtFit = () => {
4650
- const availW = Math.max(280, container.clientWidth - 32);
4935
+ const availW = Math.max(280, ctx.container.clientWidth - 32);
4651
4936
  return Math.max(0.4, Math.min(3, availW / 816));
4652
4937
  };
4653
4938
  const updateTransform = () => {
@@ -4665,6 +4950,7 @@ var CodePlugin = class {
4665
4950
  } else {
4666
4951
  pre.style.transform = `rotate(${rotation}deg)`;
4667
4952
  pre.style.fontSize = `${fontSize}px`;
4953
+ lineGutter.style.fontSize = `${fontSize}px`;
4668
4954
  }
4669
4955
  };
4670
4956
  let resizeObserver = null;
@@ -4679,11 +4965,11 @@ var CodePlugin = class {
4679
4965
  updateTransform();
4680
4966
  }
4681
4967
  }) : null;
4682
- resizeObserver?.observe(container);
4968
+ resizeObserver?.observe(ctx.container);
4683
4969
  }
4684
4970
  const cleanup = () => {
4685
4971
  resizeObserver?.disconnect();
4686
- container.remove();
4972
+ scrollWrapper.remove();
4687
4973
  ctx.container.innerHTML = "";
4688
4974
  };
4689
4975
  ctx.signal.addEventListener("abort", cleanup);
@@ -4728,7 +5014,7 @@ var CodePlugin = class {
4728
5014
  if (isTxt) {
4729
5015
  zoomLevel = Math.min(3.5, zoomLevel + 0.15);
4730
5016
  } else {
4731
- fontSize = Math.min(32, fontSize + 2);
5017
+ fontSize = Math.min(48, fontSize + 2);
4732
5018
  }
4733
5019
  updateTransform();
4734
5020
  },
@@ -4737,7 +5023,7 @@ var CodePlugin = class {
4737
5023
  if (isTxt) {
4738
5024
  zoomLevel = Math.max(0.1, zoomLevel - 0.15);
4739
5025
  } else {
4740
- fontSize = Math.max(8, fontSize - 2);
5026
+ fontSize = Math.max(9, fontSize - 2);
4741
5027
  }
4742
5028
  updateTransform();
4743
5029
  },
@@ -4758,13 +5044,20 @@ var CodePlugin = class {
4758
5044
  zoomLevel = isTxt ? calculateTxtFit() : 1;
4759
5045
  updateTransform();
4760
5046
  },
5047
+ fitToWidth: () => {
5048
+ isUserZoomed = false;
5049
+ fontSize = 13;
5050
+ rotation = 0;
5051
+ zoomLevel = isTxt ? calculateTxtFit() : 1;
5052
+ updateTransform();
5053
+ },
4761
5054
  resetZoom: () => {
4762
5055
  isUserZoomed = false;
4763
5056
  fontSize = 13;
4764
5057
  rotation = 0;
4765
5058
  zoomLevel = isTxt ? calculateTxtFit() : 1;
4766
- container.scrollTop = 0;
4767
- container.scrollLeft = 0;
5059
+ ctx.container.scrollTop = 0;
5060
+ ctx.container.scrollLeft = 0;
4768
5061
  updateTransform();
4769
5062
  },
4770
5063
  rotateCW: () => {
@@ -4842,6 +5135,14 @@ var ArchivePlugin = class {
4842
5135
  group: "zoom",
4843
5136
  execute: () => instance.resetZoom?.()
4844
5137
  },
5138
+ {
5139
+ id: "fit-width",
5140
+ icon: "fit-width",
5141
+ label: "Fit to Width",
5142
+ type: "button",
5143
+ group: "zoom",
5144
+ execute: () => instance.fitToWidth?.()
5145
+ },
4845
5146
  {
4846
5147
  id: "download",
4847
5148
  icon: "download",
@@ -5039,6 +5340,10 @@ var ArchivePlugin = class {
5039
5340
  scale = 1;
5040
5341
  applyTransform();
5041
5342
  },
5343
+ fitToWidth: () => {
5344
+ scale = 1;
5345
+ applyTransform();
5346
+ },
5042
5347
  resetZoom: () => {
5043
5348
  scale = 1;
5044
5349
  wrapper.scrollTop = 0;
@@ -5074,7 +5379,7 @@ var MarkdownPlugin = class {
5074
5379
  {
5075
5380
  id: "zoom-out",
5076
5381
  icon: "zoom-out",
5077
- label: "Decrease Font",
5382
+ label: "Zoom Out",
5078
5383
  type: "button",
5079
5384
  group: "zoom",
5080
5385
  execute: () => instance.zoomOut?.()
@@ -5082,19 +5387,11 @@ var MarkdownPlugin = class {
5082
5387
  {
5083
5388
  id: "zoom-in",
5084
5389
  icon: "zoom-in",
5085
- label: "Increase Font",
5390
+ label: "Zoom In",
5086
5391
  type: "button",
5087
5392
  group: "zoom",
5088
5393
  execute: () => instance.zoomIn?.()
5089
5394
  },
5090
- {
5091
- id: "fit-page",
5092
- icon: "fit-page",
5093
- label: "Default Size",
5094
- type: "button",
5095
- group: "zoom",
5096
- execute: () => instance.fitToPage?.()
5097
- },
5098
5395
  {
5099
5396
  id: "reset-zoom",
5100
5397
  icon: "reset-zoom",
@@ -5103,6 +5400,22 @@ var MarkdownPlugin = class {
5103
5400
  group: "zoom",
5104
5401
  execute: () => instance.resetZoom?.()
5105
5402
  },
5403
+ {
5404
+ id: "fit-width",
5405
+ icon: "fit-width",
5406
+ label: "Fit to Width",
5407
+ type: "button",
5408
+ group: "zoom",
5409
+ execute: () => instance.fitToWidth?.()
5410
+ },
5411
+ {
5412
+ id: "fit-page",
5413
+ icon: "fit-page",
5414
+ label: "Fit to Page",
5415
+ type: "button",
5416
+ group: "zoom",
5417
+ execute: () => instance.fitToPage?.()
5418
+ },
5106
5419
  {
5107
5420
  id: "copy",
5108
5421
  icon: "copy",
@@ -5126,10 +5439,18 @@ var MarkdownPlugin = class {
5126
5439
  type: "button",
5127
5440
  group: "actions",
5128
5441
  execute: () => instance.print?.()
5129
- }
5130
- ];
5131
- }
5132
- async render(ctx) {
5442
+ },
5443
+ {
5444
+ id: "open-window",
5445
+ icon: "open-window",
5446
+ label: "Open in Separate Full Window",
5447
+ type: "button",
5448
+ group: "actions",
5449
+ execute: () => instance.openInSeparateWindow?.()
5450
+ }
5451
+ ];
5452
+ }
5453
+ async render(ctx) {
5133
5454
  const text = new TextDecoder("utf-8", { fatal: false }).decode(ctx.buffer);
5134
5455
  const rawHtml = await marked.parse(text, {
5135
5456
  gfm: true,
@@ -5138,35 +5459,57 @@ var MarkdownPlugin = class {
5138
5459
  const cleanHtml = DOMPurify6.sanitize(rawHtml, {
5139
5460
  USE_PROFILES: { html: true }
5140
5461
  });
5141
- const wrapper = document.createElement("div");
5142
- wrapper.className = "fp-markdown-wrapper";
5143
- wrapper.style.cssText = `
5144
- width: 100%;
5145
- height: 100%;
5146
- overflow: auto;
5147
- padding: 32px 40px;
5462
+ const scrollWrapper = document.createElement("div");
5463
+ scrollWrapper.className = "fp-markdown-scroll-wrapper";
5464
+ scrollWrapper.style.minWidth = "100%";
5465
+ scrollWrapper.style.minHeight = "100%";
5466
+ scrollWrapper.style.width = "max-content";
5467
+ scrollWrapper.style.height = "max-content";
5468
+ scrollWrapper.style.display = "flex";
5469
+ scrollWrapper.style.justifyContent = "center";
5470
+ scrollWrapper.style.alignItems = "flex-start";
5471
+ scrollWrapper.style.padding = "24px 16px";
5472
+ scrollWrapper.style.boxSizing = "border-box";
5473
+ const sizer = document.createElement("div");
5474
+ sizer.className = "fp-markdown-sizer";
5475
+ sizer.style.position = "relative";
5476
+ sizer.style.flexShrink = "0";
5477
+ sizer.style.display = "flex";
5478
+ sizer.style.justifyContent = "center";
5479
+ sizer.style.alignItems = "flex-start";
5480
+ const docCard = document.createElement("div");
5481
+ docCard.className = "fp-markdown-doc-card";
5482
+ docCard.style.cssText = `
5483
+ width: 860px;
5484
+ min-height: 600px;
5485
+ padding: 40px 48px;
5148
5486
  box-sizing: border-box;
5149
5487
  line-height: 1.6;
5150
5488
  font-size: 15px;
5151
5489
  color: var(--fp-text, #24292f);
5152
5490
  background: var(--fp-bg, #ffffff);
5491
+ border-radius: 6px;
5492
+ box-shadow: 0 4px 24px rgba(0, 0, 0, 0.08);
5153
5493
  font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Noto Sans", Helvetica, Arial, sans-serif;
5494
+ transform-origin: top center;
5495
+ transition: transform 0.15s ease;
5496
+ flex-shrink: 0;
5154
5497
  `;
5155
- wrapper.innerHTML = `
5498
+ docCard.innerHTML = `
5156
5499
  <style>
5157
- .fp-markdown-wrapper h1, .fp-markdown-wrapper h2, .fp-markdown-wrapper h3,
5158
- .fp-markdown-wrapper h4, .fp-markdown-wrapper h5, .fp-markdown-wrapper h6 {
5500
+ .fp-markdown-doc-card h1, .fp-markdown-doc-card h2, .fp-markdown-doc-card h3,
5501
+ .fp-markdown-doc-card h4, .fp-markdown-doc-card h5, .fp-markdown-doc-card h6 {
5159
5502
  margin-top: 24px;
5160
5503
  margin-bottom: 16px;
5161
5504
  font-weight: 600;
5162
5505
  line-height: 1.25;
5163
5506
  color: var(--fp-text, #1f2328);
5164
5507
  }
5165
- .fp-markdown-wrapper h1 { font-size: 2em; padding-bottom: 0.3em; border-bottom: 1px solid var(--fp-border, #d0d7de); }
5166
- .fp-markdown-wrapper h2 { font-size: 1.5em; padding-bottom: 0.3em; border-bottom: 1px solid var(--fp-border, #d0d7de); }
5167
- .fp-markdown-wrapper h3 { font-size: 1.25em; }
5168
- .fp-markdown-wrapper p { margin-top: 0; margin-bottom: 16px; }
5169
- .fp-markdown-wrapper table {
5508
+ .fp-markdown-doc-card h1 { font-size: 2em; padding-bottom: 0.3em; border-bottom: 1px solid var(--fp-border, #d0d7de); }
5509
+ .fp-markdown-doc-card h2 { font-size: 1.5em; padding-bottom: 0.3em; border-bottom: 1px solid var(--fp-border, #d0d7de); }
5510
+ .fp-markdown-doc-card h3 { font-size: 1.25em; }
5511
+ .fp-markdown-doc-card p { margin-top: 0; margin-bottom: 16px; }
5512
+ .fp-markdown-doc-card table {
5170
5513
  border-spacing: 0;
5171
5514
  border-collapse: collapse;
5172
5515
  margin-top: 0;
@@ -5174,20 +5517,20 @@ var MarkdownPlugin = class {
5174
5517
  width: 100%;
5175
5518
  overflow: auto;
5176
5519
  }
5177
- .fp-markdown-wrapper table th, .fp-markdown-wrapper table td {
5520
+ .fp-markdown-doc-card table th, .fp-markdown-doc-card table td {
5178
5521
  padding: 6px 13px;
5179
5522
  border: 1px solid var(--fp-border, #d0d7de);
5180
5523
  }
5181
- .fp-markdown-wrapper table tr:nth-child(2n) {
5524
+ .fp-markdown-doc-card table tr:nth-child(2n) {
5182
5525
  background-color: var(--fp-toolbar-bg, #f6f8fa);
5183
5526
  }
5184
- .fp-markdown-wrapper blockquote {
5527
+ .fp-markdown-doc-card blockquote {
5185
5528
  margin: 0 0 16px 0;
5186
5529
  padding: 0 1em;
5187
5530
  color: var(--fp-text-muted, #59636e);
5188
5531
  border-left: 0.25em solid var(--fp-border, #d0d7de);
5189
5532
  }
5190
- .fp-markdown-wrapper pre {
5533
+ .fp-markdown-doc-card pre {
5191
5534
  padding: 16px;
5192
5535
  overflow: auto;
5193
5536
  font-size: 85%;
@@ -5196,7 +5539,7 @@ var MarkdownPlugin = class {
5196
5539
  border-radius: 6px;
5197
5540
  border: 1px solid var(--fp-border, #d0d7de);
5198
5541
  }
5199
- .fp-markdown-wrapper code {
5542
+ .fp-markdown-doc-card code {
5200
5543
  padding: 0.2em 0.4em;
5201
5544
  margin: 0;
5202
5545
  font-size: 85%;
@@ -5204,16 +5547,16 @@ var MarkdownPlugin = class {
5204
5547
  border-radius: 4px;
5205
5548
  font-family: ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, monospace;
5206
5549
  }
5207
- .fp-markdown-wrapper pre code {
5550
+ .fp-markdown-doc-card pre code {
5208
5551
  padding: 0;
5209
5552
  background: transparent;
5210
5553
  }
5211
- .fp-markdown-wrapper ul, .fp-markdown-wrapper ol {
5554
+ .fp-markdown-doc-card ul, .fp-markdown-doc-card ol {
5212
5555
  padding-left: 2em;
5213
5556
  margin-top: 0;
5214
5557
  margin-bottom: 16px;
5215
5558
  }
5216
- .fp-markdown-wrapper hr {
5559
+ .fp-markdown-doc-card hr {
5217
5560
  height: 0.25em;
5218
5561
  padding: 0;
5219
5562
  margin: 24px 0;
@@ -5221,46 +5564,95 @@ var MarkdownPlugin = class {
5221
5564
  border: 0;
5222
5565
  }
5223
5566
  </style>
5224
- <div class="fp-markdown-content" style="max-width: 860px; margin: 0 auto;">
5567
+ <div class="fp-markdown-body">
5225
5568
  ${cleanHtml}
5226
5569
  </div>
5227
5570
  `;
5228
- wrapper.querySelectorAll("pre code").forEach((block) => {
5571
+ docCard.querySelectorAll("pre code").forEach((block) => {
5229
5572
  hljs.highlightElement(block);
5230
5573
  });
5574
+ sizer.appendChild(docCard);
5575
+ scrollWrapper.appendChild(sizer);
5231
5576
  ctx.container.innerHTML = "";
5232
5577
  ctx.container.style.overflow = "auto";
5233
- ctx.container.appendChild(wrapper);
5234
- let fontSize = 15;
5578
+ ctx.container.style.backgroundColor = "#f1f5f9";
5579
+ ctx.container.appendChild(scrollWrapper);
5580
+ let scale = 1;
5581
+ let isUserZoomed = false;
5582
+ const calculateFitScale = () => {
5583
+ const availW = Math.max(280, ctx.container.clientWidth - 48);
5584
+ if (availW < 860) {
5585
+ return Math.max(0.35, availW / 860);
5586
+ }
5587
+ return 1;
5588
+ };
5589
+ const applyTransform = () => {
5590
+ const baseW = 860;
5591
+ const baseH = docCard.offsetHeight || 600;
5592
+ const scaledW = Math.round(baseW * scale);
5593
+ const scaledH = Math.round(baseH * scale);
5594
+ sizer.style.width = `${scaledW}px`;
5595
+ sizer.style.height = `${scaledH}px`;
5596
+ docCard.style.width = `${baseW}px`;
5597
+ docCard.style.transform = `scale(${scale})`;
5598
+ docCard.style.transformOrigin = scaledW > ctx.container.clientWidth - 32 ? "top left" : "top center";
5599
+ };
5600
+ const ro = typeof ResizeObserver !== "undefined" ? new ResizeObserver(() => {
5601
+ if (!isUserZoomed) {
5602
+ scale = calculateFitScale();
5603
+ applyTransform();
5604
+ }
5605
+ }) : null;
5606
+ ro?.observe(ctx.container);
5607
+ requestAnimationFrame(() => {
5608
+ if (!isUserZoomed) {
5609
+ scale = calculateFitScale();
5610
+ }
5611
+ applyTransform();
5612
+ });
5235
5613
  const cleanup = () => {
5236
- wrapper.remove();
5614
+ ro?.disconnect();
5615
+ scrollWrapper.remove();
5237
5616
  ctx.container.innerHTML = "";
5238
5617
  };
5239
5618
  ctx.signal.addEventListener("abort", cleanup);
5240
5619
  return {
5241
5620
  destroy: cleanup,
5242
5621
  zoomIn: () => {
5243
- fontSize = Math.min(28, fontSize + 2);
5244
- wrapper.style.fontSize = `${fontSize}px`;
5622
+ isUserZoomed = true;
5623
+ scale = Math.min(3.5, scale + 0.15);
5624
+ applyTransform();
5245
5625
  },
5246
5626
  zoomOut: () => {
5247
- fontSize = Math.max(10, fontSize - 2);
5248
- wrapper.style.fontSize = `${fontSize}px`;
5627
+ isUserZoomed = true;
5628
+ scale = Math.max(0.25, scale - 0.15);
5629
+ applyTransform();
5249
5630
  },
5250
- getZoom: () => fontSize / 15,
5631
+ getZoom: () => scale,
5251
5632
  setZoom: (level) => {
5252
- fontSize = Math.round(15 * level);
5253
- wrapper.style.fontSize = `${fontSize}px`;
5633
+ isUserZoomed = true;
5634
+ scale = level;
5635
+ applyTransform();
5254
5636
  },
5255
5637
  fitToPage: () => {
5256
- fontSize = 15;
5257
- wrapper.style.fontSize = "15px";
5638
+ isUserZoomed = false;
5639
+ scale = calculateFitScale();
5640
+ applyTransform();
5641
+ },
5642
+ fitToWidth: () => {
5643
+ isUserZoomed = false;
5644
+ scale = calculateFitScale();
5645
+ applyTransform();
5258
5646
  },
5259
5647
  resetZoom: () => {
5260
- fontSize = 15;
5261
- wrapper.style.fontSize = "15px";
5648
+ isUserZoomed = false;
5649
+ scale = calculateFitScale();
5262
5650
  ctx.container.scrollTop = 0;
5263
5651
  ctx.container.scrollLeft = 0;
5652
+ applyTransform();
5653
+ },
5654
+ openInSeparateWindow: () => {
5655
+ ctx?.openInSeparateWindow?.();
5264
5656
  },
5265
5657
  download: () => {
5266
5658
  downloadFile(ctx.buffer, ctx.metadata.name || "document.md", "text/markdown");
@@ -5363,6 +5755,14 @@ var PptxPlugin = class {
5363
5755
  group: "zoom",
5364
5756
  execute: () => instance.resetZoom?.()
5365
5757
  },
5758
+ {
5759
+ id: "fit-width",
5760
+ icon: "fit-width",
5761
+ label: "Fit to Width",
5762
+ type: "button",
5763
+ group: "zoom",
5764
+ execute: () => instance.fitToWidth?.()
5765
+ },
5366
5766
  {
5367
5767
  id: "rotate-cw",
5368
5768
  icon: "rotate-cw",
@@ -5446,12 +5846,17 @@ var PptxPlugin = class {
5446
5846
  ctx.container.innerHTML = "";
5447
5847
  ctx.container.style.overflow = "auto";
5448
5848
  ctx.container.appendChild(wrapper);
5449
- const calculateFitScale = () => {
5450
- const availW = Math.max(200, ctx.container.clientWidth - 48);
5451
- const availH = Math.max(200, ctx.container.clientHeight - 72);
5849
+ let fitMode = ctx?.options?.fitMode || "width";
5850
+ let isUserZoomed = false;
5851
+ const calculateFitScale = (mode = fitMode) => {
5852
+ const availW = Math.max(200, ctx.container.clientWidth - 32);
5853
+ const availH = Math.max(200, ctx.container.clientHeight - 32);
5452
5854
  const cW = canvas.offsetWidth || 1280;
5453
5855
  const cH = canvas.offsetHeight || 720;
5454
- return Math.min(1, Math.min(availW / cW, availH / cH));
5856
+ if (mode === "page") {
5857
+ return Math.min(2.5, Math.min(availW / cW, availH / cH));
5858
+ }
5859
+ return Math.min(2.5, availW / cW);
5455
5860
  };
5456
5861
  const applyTransform = () => {
5457
5862
  const cW = canvas.offsetWidth || 1280;
@@ -5470,14 +5875,24 @@ var PptxPlugin = class {
5470
5875
  try {
5471
5876
  await renderer.renderSlide(currentSlide - 1, canvas, 1280);
5472
5877
  ctx.emit("page-change", { page: currentSlide, totalPages: slideCount });
5473
- scale = calculateFitScale();
5878
+ if (!isUserZoomed) {
5879
+ scale = calculateFitScale(fitMode);
5880
+ }
5474
5881
  applyTransform();
5475
5882
  } catch (err) {
5476
5883
  console.error("[PptxPlugin] Failed to render slide:", err);
5477
5884
  }
5478
5885
  };
5479
5886
  await renderCurrentSlide();
5887
+ const ro = typeof ResizeObserver !== "undefined" ? new ResizeObserver(() => {
5888
+ if (!isUserZoomed) {
5889
+ scale = calculateFitScale(fitMode);
5890
+ applyTransform();
5891
+ }
5892
+ }) : null;
5893
+ ro?.observe(ctx.container);
5480
5894
  const cleanup = () => {
5895
+ ro?.disconnect();
5481
5896
  renderer.destroy();
5482
5897
  wrapper.remove();
5483
5898
  ctx.container.innerHTML = "";
@@ -5494,28 +5909,44 @@ var PptxPlugin = class {
5494
5909
  getPageCount: () => slideCount,
5495
5910
  getCurrentPage: () => currentSlide,
5496
5911
  zoomIn: () => {
5912
+ isUserZoomed = true;
5497
5913
  scale += 0.15;
5498
5914
  applyTransform();
5499
5915
  },
5500
5916
  zoomOut: () => {
5917
+ isUserZoomed = true;
5501
5918
  scale = Math.max(0.2, scale - 0.15);
5502
5919
  applyTransform();
5503
5920
  },
5504
5921
  getZoom: () => scale,
5505
5922
  setZoom: (level) => {
5923
+ isUserZoomed = true;
5506
5924
  scale = level;
5507
5925
  applyTransform();
5508
5926
  },
5509
5927
  fitToPage: () => {
5510
- scale = calculateFitScale();
5928
+ isUserZoomed = false;
5929
+ fitMode = "page";
5930
+ scale = calculateFitScale("page");
5931
+ rotation = 0;
5932
+ applyTransform();
5933
+ },
5934
+ fitToWidth: () => {
5935
+ isUserZoomed = false;
5936
+ fitMode = "width";
5937
+ scale = calculateFitScale("width");
5511
5938
  rotation = 0;
5512
5939
  applyTransform();
5513
5940
  },
5514
5941
  resetZoom: () => {
5515
- scale = calculateFitScale();
5942
+ isUserZoomed = false;
5943
+ fitMode = ctx?.options?.fitMode || "width";
5944
+ scale = calculateFitScale(fitMode);
5516
5945
  rotation = 0;
5517
5946
  wrapper.scrollTop = 0;
5518
5947
  wrapper.scrollLeft = 0;
5948
+ ctx.container.scrollTop = 0;
5949
+ ctx.container.scrollLeft = 0;
5519
5950
  applyTransform();
5520
5951
  },
5521
5952
  rotateCW: () => {
@@ -5960,6 +6391,14 @@ var RtfPlugin = class {
5960
6391
  group: "zoom",
5961
6392
  execute: () => instance.resetZoom?.()
5962
6393
  },
6394
+ {
6395
+ id: "fit-width",
6396
+ icon: "fit-width",
6397
+ label: "Fit to Width",
6398
+ type: "button",
6399
+ group: "zoom",
6400
+ execute: () => instance.fitToWidth?.()
6401
+ },
5963
6402
  {
5964
6403
  id: "rotate-cw",
5965
6404
  icon: "rotate-cw",
@@ -6448,6 +6887,13 @@ var RtfPlugin = class {
6448
6887
  applyTransform();
6449
6888
  },
6450
6889
  fitToPage: () => {
6890
+ isUserZoomed = false;
6891
+ fitMode = "page";
6892
+ scale = calculateFitScale("page");
6893
+ rotation = 0;
6894
+ applyTransform();
6895
+ },
6896
+ fitToWidth: () => {
6451
6897
  isUserZoomed = false;
6452
6898
  fitMode = "width";
6453
6899
  scale = calculateFitScale("width");
@@ -6456,8 +6902,8 @@ var RtfPlugin = class {
6456
6902
  },
6457
6903
  resetZoom: () => {
6458
6904
  isUserZoomed = false;
6459
- fitMode = "width";
6460
- scale = calculateFitScale("width");
6905
+ fitMode = ctx?.options?.fitMode || "width";
6906
+ scale = calculateFitScale(fitMode);
6461
6907
  rotation = 0;
6462
6908
  ctx.container.scrollTop = 0;
6463
6909
  ctx.container.scrollLeft = 0;
@@ -6522,14 +6968,6 @@ var HtmlPreviewPlugin = class {
6522
6968
  group: "zoom",
6523
6969
  execute: () => instance.zoomIn?.()
6524
6970
  },
6525
- {
6526
- id: "fit-page",
6527
- icon: "fit-page",
6528
- label: "Fit to Page",
6529
- type: "button",
6530
- group: "zoom",
6531
- execute: () => instance.fitToPage?.()
6532
- },
6533
6971
  {
6534
6972
  id: "reset-zoom",
6535
6973
  icon: "reset-zoom",
@@ -6538,6 +6976,22 @@ var HtmlPreviewPlugin = class {
6538
6976
  group: "zoom",
6539
6977
  execute: () => instance.resetZoom?.()
6540
6978
  },
6979
+ {
6980
+ id: "fit-width",
6981
+ icon: "fit-width",
6982
+ label: "Fit to Width",
6983
+ type: "button",
6984
+ group: "zoom",
6985
+ execute: () => instance.fitToWidth?.()
6986
+ },
6987
+ {
6988
+ id: "fit-page",
6989
+ icon: "fit-page",
6990
+ label: "Fit to Page",
6991
+ type: "button",
6992
+ group: "zoom",
6993
+ execute: () => instance.fitToPage?.()
6994
+ },
6541
6995
  {
6542
6996
  id: "copy",
6543
6997
  icon: "copy",
@@ -6561,6 +7015,14 @@ var HtmlPreviewPlugin = class {
6561
7015
  type: "button",
6562
7016
  group: "actions",
6563
7017
  execute: () => instance.print?.()
7018
+ },
7019
+ {
7020
+ id: "open-window",
7021
+ icon: "open-window",
7022
+ label: "Open in Separate Full Window",
7023
+ type: "button",
7024
+ group: "actions",
7025
+ execute: () => instance.openInSeparateWindow?.()
6564
7026
  }
6565
7027
  ];
6566
7028
  }
@@ -6571,27 +7033,39 @@ var HtmlPreviewPlugin = class {
6571
7033
  ADD_TAGS: ["style", "link"],
6572
7034
  ADD_ATTR: ["target", "rel"]
6573
7035
  });
7036
+ const scrollWrapper = document.createElement("div");
7037
+ scrollWrapper.className = "fp-html-scroll-wrapper";
7038
+ scrollWrapper.style.minWidth = "100%";
7039
+ scrollWrapper.style.minHeight = "100%";
7040
+ scrollWrapper.style.width = "max-content";
7041
+ scrollWrapper.style.height = "max-content";
7042
+ scrollWrapper.style.display = "flex";
7043
+ scrollWrapper.style.justifyContent = "flex-start";
7044
+ scrollWrapper.style.alignItems = "flex-start";
7045
+ scrollWrapper.style.boxSizing = "border-box";
6574
7046
  const sizer = document.createElement("div");
6575
7047
  sizer.className = "fp-html-sizer";
6576
7048
  sizer.style.position = "relative";
7049
+ sizer.style.flexShrink = "0";
6577
7050
  const iframe = document.createElement("iframe");
6578
7051
  iframe.className = "fp-html-iframe";
6579
7052
  iframe.style.border = "none";
6580
7053
  iframe.style.backgroundColor = "#ffffff";
6581
7054
  iframe.style.transformOrigin = "top left";
6582
- iframe.style.transition = "transform 0.2s ease";
7055
+ iframe.style.transition = "transform 0.15s ease";
6583
7056
  iframe.sandbox.add("allow-same-origin");
6584
7057
  sizer.appendChild(iframe);
7058
+ scrollWrapper.appendChild(sizer);
6585
7059
  ctx.container.style.overflow = "auto";
6586
7060
  ctx.container.style.width = "100%";
6587
7061
  ctx.container.style.height = "100%";
6588
7062
  ctx.container.innerHTML = "";
6589
- ctx.container.appendChild(sizer);
7063
+ ctx.container.appendChild(scrollWrapper);
6590
7064
  iframe.srcdoc = sanitized;
6591
7065
  let scale = 1;
7066
+ let baseW = Math.max(600, ctx.container.clientWidth || 800);
7067
+ let baseH = Math.max(400, ctx.container.clientHeight || 600);
6592
7068
  const applyTransform = () => {
6593
- const baseW = Math.max(600, ctx.container.clientWidth || 800);
6594
- const baseH = Math.max(400, ctx.container.clientHeight || 600);
6595
7069
  const scaledW = Math.round(baseW * scale);
6596
7070
  const scaledH = Math.round(baseH * scale);
6597
7071
  sizer.style.width = `${scaledW}px`;
@@ -6604,22 +7078,33 @@ var HtmlPreviewPlugin = class {
6604
7078
  iframe.style.transform = `scale(${scale})`;
6605
7079
  iframe.style.transformOrigin = "top left";
6606
7080
  };
7081
+ const ro = typeof ResizeObserver !== "undefined" ? new ResizeObserver(() => {
7082
+ if (Math.abs(scale - 1) < 0.05) {
7083
+ baseW = Math.max(600, ctx.container.clientWidth || 800);
7084
+ baseH = Math.max(400, ctx.container.clientHeight || 600);
7085
+ applyTransform();
7086
+ }
7087
+ }) : null;
7088
+ ro?.observe(ctx.container);
6607
7089
  requestAnimationFrame(() => {
7090
+ baseW = Math.max(600, ctx.container.clientWidth || 800);
7091
+ baseH = Math.max(400, ctx.container.clientHeight || 600);
6608
7092
  applyTransform();
6609
7093
  });
6610
7094
  const cleanup = () => {
6611
- sizer.remove();
7095
+ ro?.disconnect();
7096
+ scrollWrapper.remove();
6612
7097
  ctx.container.innerHTML = "";
6613
7098
  };
6614
7099
  ctx.signal.addEventListener("abort", cleanup);
6615
7100
  return {
6616
7101
  destroy: cleanup,
6617
7102
  zoomIn: () => {
6618
- scale += 0.1;
7103
+ scale = Math.min(3.5, scale + 0.15);
6619
7104
  applyTransform();
6620
7105
  },
6621
7106
  zoomOut: () => {
6622
- scale = Math.max(0.2, scale - 0.1);
7107
+ scale = Math.max(0.25, scale - 0.15);
6623
7108
  applyTransform();
6624
7109
  },
6625
7110
  getZoom: () => scale,
@@ -6631,14 +7116,21 @@ var HtmlPreviewPlugin = class {
6631
7116
  scale = 1;
6632
7117
  applyTransform();
6633
7118
  },
7119
+ fitToWidth: () => {
7120
+ scale = 1;
7121
+ applyTransform();
7122
+ },
6634
7123
  resetZoom: () => {
6635
7124
  scale = 1;
6636
7125
  ctx.container.scrollTop = 0;
6637
7126
  ctx.container.scrollLeft = 0;
6638
7127
  applyTransform();
6639
7128
  },
7129
+ openInSeparateWindow: () => {
7130
+ ctx?.openInSeparateWindow?.();
7131
+ },
6640
7132
  copy: () => {
6641
- navigator.clipboard.writeText(rawHtml);
7133
+ navigator.clipboard?.writeText(rawHtml);
6642
7134
  },
6643
7135
  download: () => {
6644
7136
  const blob = new Blob([ctx.buffer], { type: "text/html" });
@@ -6745,6 +7237,14 @@ var OpenDocumentPlugin = class {
6745
7237
  group: "zoom",
6746
7238
  execute: () => instance.resetZoom?.()
6747
7239
  },
7240
+ {
7241
+ id: "fit-width",
7242
+ icon: "fit-width",
7243
+ label: "Fit to Width",
7244
+ type: "button",
7245
+ group: "zoom",
7246
+ execute: () => instance.fitToWidth?.()
7247
+ },
6748
7248
  {
6749
7249
  id: "rotate-cw",
6750
7250
  icon: "rotate-cw",
@@ -6861,7 +7361,10 @@ var OpenDocumentPlugin = class {
6861
7361
  const sW = availW / elW;
6862
7362
  const sH = availH / (isPresentation ? 540 : singlePageH);
6863
7363
  if (isPresentation) {
6864
- return Math.min(2.5, Math.min(sW, sH));
7364
+ if (mode === "page") {
7365
+ return Math.min(2.5, Math.min(sW, sH));
7366
+ }
7367
+ return Math.min(2.5, sW);
6865
7368
  }
6866
7369
  if (mode === "page") {
6867
7370
  return Math.max(0.35, Math.min(3, Math.min(sW, sH)));
@@ -7030,6 +7533,13 @@ var OpenDocumentPlugin = class {
7030
7533
  applyTransform();
7031
7534
  },
7032
7535
  fitToPage: () => {
7536
+ isUserZoomed = false;
7537
+ fitMode = "page";
7538
+ scale = calculateFitScale("page");
7539
+ rotation = 0;
7540
+ applyTransform();
7541
+ },
7542
+ fitToWidth: () => {
7033
7543
  isUserZoomed = false;
7034
7544
  fitMode = "width";
7035
7545
  scale = calculateFitScale("width");
@@ -7038,8 +7548,8 @@ var OpenDocumentPlugin = class {
7038
7548
  },
7039
7549
  resetZoom: () => {
7040
7550
  isUserZoomed = false;
7041
- fitMode = "width";
7042
- scale = calculateFitScale("width");
7551
+ fitMode = ctx?.options?.fitMode || "width";
7552
+ scale = calculateFitScale(fitMode);
7043
7553
  rotation = 0;
7044
7554
  container.scrollTop = 0;
7045
7555
  container.scrollLeft = 0;
@@ -7396,6 +7906,14 @@ var DocPlugin = class {
7396
7906
  group: "zoom",
7397
7907
  execute: () => instance.resetZoom?.()
7398
7908
  },
7909
+ {
7910
+ id: "fit-width",
7911
+ icon: "fit-width",
7912
+ label: "Fit to Width",
7913
+ type: "button",
7914
+ group: "zoom",
7915
+ execute: () => instance.fitToWidth?.()
7916
+ },
7399
7917
  {
7400
7918
  id: "rotate-cw",
7401
7919
  icon: "rotate-cw",
@@ -7617,6 +8135,13 @@ var DocPlugin = class {
7617
8135
  applyTransform();
7618
8136
  },
7619
8137
  fitToPage: () => {
8138
+ isUserZoomed = false;
8139
+ fitMode = "page";
8140
+ scale = calculateFitScale("page");
8141
+ rotation = 0;
8142
+ applyTransform();
8143
+ },
8144
+ fitToWidth: () => {
7620
8145
  isUserZoomed = false;
7621
8146
  fitMode = "width";
7622
8147
  scale = calculateFitScale("width");
@@ -7625,8 +8150,8 @@ var DocPlugin = class {
7625
8150
  },
7626
8151
  resetZoom: () => {
7627
8152
  isUserZoomed = false;
7628
- fitMode = "width";
7629
- scale = calculateFitScale("width");
8153
+ fitMode = ctx?.options?.fitMode || "width";
8154
+ scale = calculateFitScale(fitMode);
7630
8155
  rotation = 0;
7631
8156
  container.scrollTop = 0;
7632
8157
  container.scrollLeft = 0;
@@ -8122,6 +8647,14 @@ var PptPlugin = class {
8122
8647
  group: "zoom",
8123
8648
  execute: () => instance.resetZoom?.()
8124
8649
  },
8650
+ {
8651
+ id: "fit-width",
8652
+ icon: "fit-width",
8653
+ label: "Fit to Width",
8654
+ type: "button",
8655
+ group: "zoom",
8656
+ execute: () => instance.fitToWidth?.()
8657
+ },
8125
8658
  {
8126
8659
  id: "rotate-cw",
8127
8660
  icon: "rotate-cw",
@@ -8196,10 +8729,15 @@ var PptPlugin = class {
8196
8729
  let currentSlide = 1;
8197
8730
  let slides = [];
8198
8731
  const createdBlobUrls = [];
8199
- const calculateFitScale = () => {
8200
- const availW = Math.max(200, container.clientWidth - 48);
8201
- const availH = Math.max(200, container.clientHeight - 72);
8202
- return Math.min(1, Math.min(availW / 960, availH / 540));
8732
+ let fitMode = ctx?.options?.fitMode || "width";
8733
+ let isUserZoomed = false;
8734
+ const calculateFitScale = (mode = fitMode) => {
8735
+ const availW = Math.max(200, container.clientWidth - 32);
8736
+ const availH = Math.max(200, container.clientHeight - 32);
8737
+ if (mode === "page") {
8738
+ return Math.min(2.5, Math.min(availW / 960, availH / 540));
8739
+ }
8740
+ return Math.min(2.5, availW / 960);
8203
8741
  };
8204
8742
  const applyTransform = () => {
8205
8743
  const cW = 960;
@@ -8214,8 +8752,15 @@ var PptPlugin = class {
8214
8752
  slideCard.style.transform = `scale(${scale}) rotate(${rotation}deg)`;
8215
8753
  slideCard.style.transformOrigin = "center center";
8216
8754
  };
8755
+ const ro = typeof ResizeObserver !== "undefined" ? new ResizeObserver(() => {
8756
+ if (!isUserZoomed) {
8757
+ scale = calculateFitScale(fitMode);
8758
+ applyTransform();
8759
+ }
8760
+ }) : null;
8761
+ ro?.observe(container);
8217
8762
  setTimeout(() => {
8218
- scale = calculateFitScale();
8763
+ scale = calculateFitScale(fitMode);
8219
8764
  applyTransform();
8220
8765
  }, 60);
8221
8766
  try {
@@ -8308,6 +8853,7 @@ var PptPlugin = class {
8308
8853
  };
8309
8854
  renderSlide(1);
8310
8855
  const cleanup = () => {
8856
+ ro?.disconnect();
8311
8857
  for (const u of createdBlobUrls) {
8312
8858
  URL.revokeObjectURL(u);
8313
8859
  }
@@ -8318,28 +8864,44 @@ var PptPlugin = class {
8318
8864
  return {
8319
8865
  destroy: cleanup,
8320
8866
  zoomIn: () => {
8867
+ isUserZoomed = true;
8321
8868
  scale += 0.15;
8322
8869
  applyTransform();
8323
8870
  },
8324
8871
  zoomOut: () => {
8872
+ isUserZoomed = true;
8325
8873
  scale = Math.max(0.2, scale - 0.15);
8326
8874
  applyTransform();
8327
8875
  },
8328
8876
  getZoom: () => scale,
8329
8877
  setZoom: (level) => {
8878
+ isUserZoomed = true;
8330
8879
  scale = level;
8331
8880
  applyTransform();
8332
8881
  },
8333
8882
  fitToPage: () => {
8334
- scale = calculateFitScale();
8883
+ isUserZoomed = false;
8884
+ fitMode = "page";
8885
+ scale = calculateFitScale("page");
8886
+ rotation = 0;
8887
+ applyTransform();
8888
+ },
8889
+ fitToWidth: () => {
8890
+ isUserZoomed = false;
8891
+ fitMode = "width";
8892
+ scale = calculateFitScale("width");
8335
8893
  rotation = 0;
8336
8894
  applyTransform();
8337
8895
  },
8338
8896
  resetZoom: () => {
8339
- scale = calculateFitScale();
8897
+ isUserZoomed = false;
8898
+ fitMode = ctx?.options?.fitMode || "width";
8899
+ scale = calculateFitScale(fitMode);
8340
8900
  rotation = 0;
8341
8901
  container.scrollTop = 0;
8342
8902
  container.scrollLeft = 0;
8903
+ ctx.container.scrollTop = 0;
8904
+ ctx.container.scrollLeft = 0;
8343
8905
  applyTransform();
8344
8906
  },
8345
8907
  rotateCW: () => {