@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/react.cjs CHANGED
@@ -1090,6 +1090,10 @@ var FilePreviewViewer = class _FilePreviewViewer {
1090
1090
  * Preview a file in the given container element.
1091
1091
  */
1092
1092
  async preview(container, source, options = {}) {
1093
+ options = {
1094
+ ...options,
1095
+ fitMode: options.fitMode ?? "width"
1096
+ };
1093
1097
  this.currentOptions = options;
1094
1098
  this.abort();
1095
1099
  this.abortController = new AbortController();
@@ -1138,8 +1142,8 @@ var FilePreviewViewer = class _FilePreviewViewer {
1138
1142
  this.activeInstance = instance;
1139
1143
  instance.openInSeparateWindow = () => this.openInSeparateWindow();
1140
1144
  instance.toggleThumbnails = () => this.toggleThumbnails();
1141
- if (!instance.resetZoom && instance.fitToPage) {
1142
- instance.resetZoom = () => instance.fitToPage?.();
1145
+ if (!instance.resetZoom) {
1146
+ instance.resetZoom = () => instance.fitToWidth ? instance.fitToWidth() : instance.fitToPage?.();
1143
1147
  }
1144
1148
  this.hideLoading();
1145
1149
  this.eventEmitter.emit("loaded", { metadata, plugin: matchedPlugin.id });
@@ -1536,7 +1540,7 @@ var FilePreviewViewer = class _FilePreviewViewer {
1536
1540
  this.wrapperEl?.classList.toggle("fp-fullscreen-active");
1537
1541
  }
1538
1542
  setTimeout(() => {
1539
- this.activeInstance?.fitToPage?.();
1543
+ this.triggerAutoFit();
1540
1544
  }, 120);
1541
1545
  }
1542
1546
  /**
@@ -1628,19 +1632,85 @@ var FilePreviewViewer = class _FilePreviewViewer {
1628
1632
  if (this.wrapperEl?.parentNode) {
1629
1633
  this.wrapperEl.parentNode.removeChild(this.wrapperEl);
1630
1634
  }
1635
+ if (typeof document !== "undefined" && !document.getElementById("fp-core-injected-styles")) {
1636
+ const styleEl = document.createElement("style");
1637
+ styleEl.id = "fp-core-injected-styles";
1638
+ styleEl.textContent = `
1639
+ .fp-viewer {
1640
+ display: flex !important;
1641
+ flex-direction: column !important;
1642
+ width: 100% !important;
1643
+ height: 100% !important;
1644
+ overflow: hidden !important;
1645
+ position: relative !important;
1646
+ box-sizing: border-box !important;
1647
+ }
1648
+ .fp-body {
1649
+ display: flex !important;
1650
+ flex: 1 1 0% !important;
1651
+ min-height: 0 !important;
1652
+ min-width: 0 !important;
1653
+ width: 100% !important;
1654
+ height: 100% !important;
1655
+ overflow: hidden !important;
1656
+ position: relative !important;
1657
+ box-sizing: border-box !important;
1658
+ }
1659
+ .fp-content {
1660
+ flex: 1 1 0% !important;
1661
+ position: relative !important;
1662
+ overflow: auto !important;
1663
+ display: flex !important;
1664
+ flex-direction: column !important;
1665
+ align-items: stretch !important;
1666
+ justify-content: flex-start !important;
1667
+ width: 100% !important;
1668
+ height: 100% !important;
1669
+ min-width: 0 !important;
1670
+ min-height: 0 !important;
1671
+ box-sizing: border-box !important;
1672
+ }
1673
+ `;
1674
+ document.head.appendChild(styleEl);
1675
+ }
1631
1676
  const themeClass = options.theme === "dark" ? "fp-theme-dark" : "";
1632
1677
  const toolbarPos = options.toolbarPosition ?? "top";
1633
1678
  this.wrapperEl = document.createElement("div");
1634
1679
  this.wrapperEl.className = `fp-viewer ${themeClass} ${options.className ?? ""}`.trim();
1635
1680
  this.wrapperEl.tabIndex = 0;
1681
+ this.wrapperEl.style.display = "flex";
1682
+ this.wrapperEl.style.flexDirection = "column";
1683
+ this.wrapperEl.style.width = "100%";
1684
+ this.wrapperEl.style.height = "100%";
1685
+ this.wrapperEl.style.overflow = "hidden";
1686
+ this.wrapperEl.style.position = "relative";
1636
1687
  const toolbarEl = document.createElement("div");
1637
1688
  toolbarEl.className = "fp-toolbar-container";
1638
1689
  this.contentEl = document.createElement("div");
1639
1690
  this.contentEl.className = "fp-content";
1691
+ this.contentEl.style.flex = "1 1 0%";
1692
+ this.contentEl.style.position = "relative";
1693
+ this.contentEl.style.overflow = "auto";
1694
+ this.contentEl.style.display = "flex";
1695
+ this.contentEl.style.flexDirection = "column";
1696
+ this.contentEl.style.alignItems = "stretch";
1697
+ this.contentEl.style.justifyContent = "flex-start";
1698
+ this.contentEl.style.width = "100%";
1699
+ this.contentEl.style.height = "100%";
1700
+ this.contentEl.style.minWidth = "0";
1701
+ this.contentEl.style.minHeight = "0";
1702
+ this.contentEl.style.boxSizing = "border-box";
1640
1703
  const thumbnailEl = document.createElement("div");
1641
1704
  thumbnailEl.className = "fp-thumbnail-container";
1642
1705
  const bodyEl = document.createElement("div");
1643
1706
  bodyEl.className = "fp-body";
1707
+ bodyEl.style.display = "flex";
1708
+ bodyEl.style.flex = "1 1 0%";
1709
+ bodyEl.style.minHeight = "0";
1710
+ bodyEl.style.minWidth = "0";
1711
+ bodyEl.style.width = "100%";
1712
+ bodyEl.style.overflow = "hidden";
1713
+ bodyEl.style.position = "relative";
1644
1714
  bodyEl.appendChild(thumbnailEl);
1645
1715
  bodyEl.appendChild(this.contentEl);
1646
1716
  const titleBarEl = document.createElement("div");
@@ -1663,18 +1733,29 @@ var FilePreviewViewer = class _FilePreviewViewer {
1663
1733
  this.thumbnailPanel = new ThumbnailPanel(thumbnailEl, (isOpen) => {
1664
1734
  this.toolbar?.setActionActive("thumbnails", isOpen);
1665
1735
  setTimeout(() => {
1666
- this.activeInstance?.fitToPage?.();
1736
+ this.triggerAutoFit();
1667
1737
  }, 260);
1668
1738
  });
1669
1739
  this.setupKeyboardShortcuts();
1670
1740
  this.setupDragAndDrop(container, options);
1671
1741
  this.setupResizeAndFullscreenListeners();
1672
1742
  }
1743
+ triggerAutoFit() {
1744
+ if (!this.activeInstance) return;
1745
+ const mode = this.currentOptions?.fitMode ?? "width";
1746
+ if (mode === "width" && this.activeInstance.fitToWidth) {
1747
+ this.activeInstance.fitToWidth();
1748
+ } else if (this.activeInstance.fitToPage) {
1749
+ this.activeInstance.fitToPage();
1750
+ } else if (this.activeInstance.resetZoom) {
1751
+ this.activeInstance.resetZoom();
1752
+ }
1753
+ }
1673
1754
  setupResizeAndFullscreenListeners() {
1674
1755
  if (this.fullscreenHandler) return;
1675
1756
  this.fullscreenHandler = () => {
1676
1757
  setTimeout(() => {
1677
- this.activeInstance?.fitToPage?.();
1758
+ this.triggerAutoFit();
1678
1759
  }, 100);
1679
1760
  };
1680
1761
  document.addEventListener("fullscreenchange", this.fullscreenHandler);
@@ -1682,7 +1763,7 @@ var FilePreviewViewer = class _FilePreviewViewer {
1682
1763
  if (typeof ResizeObserver !== "undefined" && this.contentEl) {
1683
1764
  this.resizeObserver = new ResizeObserver(() => {
1684
1765
  if (this.activeInstance && (!this.activeInstance.getZoom || Math.abs((this.activeInstance.getZoom?.() ?? 1) - 1) < 0.05)) {
1685
- this.activeInstance.fitToPage?.();
1766
+ this.triggerAutoFit();
1686
1767
  }
1687
1768
  });
1688
1769
  this.resizeObserver.observe(this.contentEl);
@@ -1710,7 +1791,7 @@ var FilePreviewViewer = class _FilePreviewViewer {
1710
1791
  } else if (e.key === "-" || e.key === "_") {
1711
1792
  this.activeInstance.zoomOut?.();
1712
1793
  } else if (e.key === "0") {
1713
- this.activeInstance.fitToPage?.();
1794
+ this.resetZoom();
1714
1795
  } else if (e.key === "r" || e.key === "R") {
1715
1796
  this.activeInstance.rotateCW?.();
1716
1797
  } else if (e.key === "f" || e.key === "F") {
@@ -2333,7 +2414,7 @@ var PdfPlugin = class {
2333
2414
  renderPage(currentPage);
2334
2415
  },
2335
2416
  resetZoom: () => {
2336
- fitMode = "page";
2417
+ fitMode = ctx?.options?.fitMode || "width";
2337
2418
  zoomScale = 1;
2338
2419
  rotation = 0;
2339
2420
  container.scrollTop = 0;
@@ -2517,6 +2598,16 @@ var MediaPlugin = class {
2517
2598
  instance.resetZoom?.();
2518
2599
  }
2519
2600
  },
2601
+ {
2602
+ id: "fit-width",
2603
+ icon: "fit-width",
2604
+ label: "Fit to Width",
2605
+ type: "button",
2606
+ group: "zoom",
2607
+ execute: () => {
2608
+ instance.fitToWidth?.();
2609
+ }
2610
+ },
2520
2611
  {
2521
2612
  id: "rotate-cw",
2522
2613
  icon: "rotate-cw",
@@ -2613,9 +2704,30 @@ var MediaPlugin = class {
2613
2704
  const isVideo = mimeType.startsWith("video/") || VIDEO_EXTS.includes(ctx.metadata.extension || "");
2614
2705
  const isAudio = mimeType.startsWith("audio/") || AUDIO_EXTS.includes(ctx.metadata.extension || "");
2615
2706
  let url = "";
2707
+ let naturalW = 800;
2708
+ let naturalH = 600;
2616
2709
  if (ctx.metadata.extension === ".svg" || mimeType === "image/svg+xml") {
2617
2710
  const decoder = new TextDecoder("utf-8");
2618
2711
  const svgText = decoder.decode(ctx.buffer);
2712
+ try {
2713
+ const vbMatch = svgText.match(/viewBox=["']\s*([0-9.-]+)\s+([0-9.-]+)\s+([0-9.-]+)\s+([0-9.-]+)\s*["']/i);
2714
+ if (vbMatch) {
2715
+ const vw = parseFloat(vbMatch[3]);
2716
+ const vh = parseFloat(vbMatch[4]);
2717
+ if (vw > 0 && vh > 0) {
2718
+ naturalW = vw;
2719
+ naturalH = vh;
2720
+ }
2721
+ } else {
2722
+ const wMatch = svgText.match(/width=["']([0-9.]+)(?:px)?["']/i);
2723
+ const hMatch = svgText.match(/height=["']([0-9.]+)(?:px)?["']/i);
2724
+ if (wMatch && hMatch) {
2725
+ naturalW = parseFloat(wMatch[1]) || naturalW;
2726
+ naturalH = parseFloat(hMatch[1]) || naturalH;
2727
+ }
2728
+ }
2729
+ } catch {
2730
+ }
2619
2731
  const blob = new Blob([svgText], { type: "image/svg+xml" });
2620
2732
  url = URL.createObjectURL(blob);
2621
2733
  } else {
@@ -2663,7 +2775,7 @@ var MediaPlugin = class {
2663
2775
  scrollWrapper.style.width = "max-content";
2664
2776
  scrollWrapper.style.height = "max-content";
2665
2777
  scrollWrapper.style.display = "flex";
2666
- scrollWrapper.style.justifyContent = "center";
2778
+ scrollWrapper.style.flexDirection = "column";
2667
2779
  scrollWrapper.style.alignItems = "center";
2668
2780
  scrollWrapper.style.padding = "16px";
2669
2781
  scrollWrapper.style.boxSizing = "border-box";
@@ -2674,40 +2786,54 @@ var MediaPlugin = class {
2674
2786
  sizer.style.display = "flex";
2675
2787
  sizer.style.justifyContent = "center";
2676
2788
  sizer.style.alignItems = "center";
2789
+ sizer.style.margin = "auto 0";
2677
2790
  sizer.appendChild(element);
2678
2791
  scrollWrapper.appendChild(sizer);
2679
2792
  ctx.container.style.overflow = "auto";
2680
2793
  ctx.container.style.padding = "0";
2681
2794
  ctx.container.innerHTML = "";
2682
2795
  ctx.container.appendChild(scrollWrapper);
2683
- let naturalW = 800;
2684
- let naturalH = 600;
2685
- let baseW = 800;
2686
- let baseH = 600;
2796
+ let baseW = naturalW;
2797
+ let baseH = naturalH;
2798
+ let fitMode = ctx?.options?.fitMode || "width";
2799
+ let isUserZoomed = false;
2687
2800
  const updateBaseDimensions = () => {
2688
2801
  if (!isImage) return;
2689
2802
  const img = element;
2690
- naturalW = img.naturalWidth || naturalW;
2691
- naturalH = img.naturalHeight || naturalH;
2692
- const availW = Math.max(100, ctx.container.clientWidth - 48);
2693
- const availH = Math.max(100, ctx.container.clientHeight - 48);
2694
- const fitRatio = Math.min(1, availW / naturalW, availH / naturalH);
2803
+ if (img.naturalWidth > 0 && img.naturalHeight > 0) {
2804
+ naturalW = img.naturalWidth;
2805
+ naturalH = img.naturalHeight;
2806
+ }
2807
+ const availW = Math.max(100, ctx.container.clientWidth - 32);
2808
+ const availH = Math.max(100, ctx.container.clientHeight - 32);
2809
+ let fitRatio;
2810
+ if (fitMode === "page") {
2811
+ fitRatio = Math.min(availW / naturalW, availH / naturalH);
2812
+ } else {
2813
+ fitRatio = availW / naturalW;
2814
+ }
2695
2815
  baseW = Math.max(1, Math.round(naturalW * fitRatio));
2696
2816
  baseH = Math.max(1, Math.round(naturalH * fitRatio));
2697
2817
  };
2698
2818
  const applyTransform = () => {
2699
2819
  if (isImage) {
2700
- updateBaseDimensions();
2820
+ if (!isUserZoomed) {
2821
+ updateBaseDimensions();
2822
+ }
2823
+ const availH = Math.max(100, ctx.container.clientHeight - 32);
2701
2824
  const isRotated90 = rotation % 180 !== 0;
2702
2825
  const boxW = Math.round((isRotated90 ? baseH : baseW) * currentZoom);
2703
2826
  const boxH = Math.round((isRotated90 ? baseW : baseH) * currentZoom);
2704
2827
  sizer.style.width = `${boxW}px`;
2705
2828
  sizer.style.height = `${boxH}px`;
2706
- element.style.width = `${baseW}px`;
2707
- element.style.height = `${baseH}px`;
2829
+ sizer.style.margin = boxH < availH ? "auto 0" : "0";
2830
+ const imgW = isRotated90 ? boxH : boxW;
2831
+ const imgH = isRotated90 ? boxW : boxH;
2832
+ element.style.width = `${imgW}px`;
2833
+ element.style.height = `${imgH}px`;
2708
2834
  element.style.maxWidth = "none";
2709
2835
  element.style.maxHeight = "none";
2710
- element.style.transform = `scale(${currentZoom}) rotate(${rotation}deg)`;
2836
+ element.style.transform = rotation ? `rotate(${rotation}deg)` : "none";
2711
2837
  element.style.transformOrigin = "center center";
2712
2838
  element.style.flexShrink = "0";
2713
2839
  } else {
@@ -2727,7 +2853,8 @@ var MediaPlugin = class {
2727
2853
  }
2728
2854
  }
2729
2855
  const ro = typeof ResizeObserver !== "undefined" ? new ResizeObserver(() => {
2730
- if (currentZoom === 1) {
2856
+ if (!isUserZoomed && currentZoom === 1) {
2857
+ updateBaseDimensions();
2731
2858
  applyTransform();
2732
2859
  }
2733
2860
  }) : null;
@@ -2742,28 +2869,49 @@ var MediaPlugin = class {
2742
2869
  return {
2743
2870
  destroy: cleanup,
2744
2871
  zoomIn: isImage ? () => {
2745
- currentZoom += 0.1;
2872
+ isUserZoomed = true;
2873
+ currentZoom = Math.min(5, Math.round((currentZoom + 0.15) * 100) / 100);
2746
2874
  applyTransform();
2747
2875
  } : void 0,
2748
2876
  zoomOut: isImage ? () => {
2749
- currentZoom = Math.max(0.1, currentZoom - 0.1);
2877
+ isUserZoomed = true;
2878
+ currentZoom = Math.max(0.1, Math.round((currentZoom - 0.15) * 100) / 100);
2750
2879
  applyTransform();
2751
2880
  } : void 0,
2752
2881
  getZoom: isImage ? () => currentZoom : void 0,
2753
2882
  setZoom: isImage ? (level) => {
2883
+ isUserZoomed = true;
2754
2884
  currentZoom = level;
2755
2885
  applyTransform();
2756
2886
  } : void 0,
2757
2887
  fitToPage: isImage ? () => {
2888
+ isUserZoomed = false;
2889
+ fitMode = "page";
2890
+ currentZoom = 1;
2891
+ rotation = 0;
2892
+ ctx.container.scrollTop = 0;
2893
+ ctx.container.scrollLeft = 0;
2894
+ updateBaseDimensions();
2895
+ applyTransform();
2896
+ } : void 0,
2897
+ fitToWidth: isImage ? () => {
2898
+ isUserZoomed = false;
2899
+ fitMode = "width";
2758
2900
  currentZoom = 1;
2759
2901
  rotation = 0;
2902
+ ctx.container.scrollTop = 0;
2903
+ ctx.container.scrollLeft = 0;
2904
+ updateBaseDimensions();
2760
2905
  applyTransform();
2761
2906
  } : void 0,
2762
2907
  resetZoom: isImage ? () => {
2908
+ isUserZoomed = false;
2909
+ fitMode = ctx?.options?.fitMode || "width";
2763
2910
  currentZoom = 1;
2764
2911
  rotation = 0;
2765
2912
  ctx.container.scrollTop = 0;
2766
2913
  ctx.container.scrollLeft = 0;
2914
+ updateBaseDimensions();
2767
2915
  applyTransform();
2768
2916
  } : void 0,
2769
2917
  rotateCW: isImage || isVideo ? () => {
@@ -2890,6 +3038,14 @@ var DocxPlugin = class {
2890
3038
  group: "zoom",
2891
3039
  execute: () => instance.resetZoom?.()
2892
3040
  },
3041
+ {
3042
+ id: "fit-width",
3043
+ icon: "fit-width",
3044
+ label: "Fit to Width",
3045
+ type: "button",
3046
+ group: "zoom",
3047
+ execute: () => instance.fitToWidth?.()
3048
+ },
2893
3049
  {
2894
3050
  id: "rotate-cw",
2895
3051
  icon: "rotate-cw",
@@ -3149,13 +3305,19 @@ var DocxPlugin = class {
3149
3305
  }
3150
3306
  scale = 1;
3151
3307
  let rotation = 0;
3152
- let fitMode = "page";
3308
+ let fitMode = ctx?.options?.fitMode || "width";
3153
3309
  let isUserZoomed = false;
3154
- const calculateFitScale = (_mode = fitMode) => {
3310
+ const calculateFitScale = (mode = fitMode) => {
3155
3311
  const activeEl = pageElements[currentPage - 1] || wrapper.querySelector("section.docx") || wrapper;
3156
3312
  const elW = activeEl.offsetWidth || 816;
3313
+ const elH = activeEl.offsetHeight || 1056;
3157
3314
  const availW = Math.max(280, ctx.container.clientWidth - 32);
3315
+ const availH = Math.max(280, ctx.container.clientHeight - 32);
3158
3316
  const sW = availW / elW;
3317
+ const sH = availH / elH;
3318
+ if (mode === "page") {
3319
+ return Math.max(0.35, Math.min(3, Math.min(sW, sH)));
3320
+ }
3159
3321
  return Math.max(0.35, Math.min(3, sW));
3160
3322
  };
3161
3323
  const applyTransform = () => {
@@ -3176,7 +3338,7 @@ var DocxPlugin = class {
3176
3338
  if (typeof ResizeObserver !== "undefined") {
3177
3339
  resizeObserver = new ResizeObserver(() => {
3178
3340
  if (!isUserZoomed) {
3179
- const newFit = calculateFitScale("page");
3341
+ const newFit = calculateFitScale(fitMode);
3180
3342
  if (Math.abs(scale - newFit) > 0.015) {
3181
3343
  scale = newFit;
3182
3344
  applyTransform();
@@ -3186,7 +3348,7 @@ var DocxPlugin = class {
3186
3348
  resizeObserver.observe(ctx.container);
3187
3349
  }
3188
3350
  setTimeout(() => {
3189
- scale = calculateFitScale("page");
3351
+ scale = calculateFitScale(fitMode);
3190
3352
  applyTransform();
3191
3353
  }, 40);
3192
3354
  const cleanup = () => {
@@ -3225,13 +3387,22 @@ var DocxPlugin = class {
3225
3387
  },
3226
3388
  fitToPage: () => {
3227
3389
  isUserZoomed = false;
3390
+ fitMode = "page";
3228
3391
  scale = calculateFitScale("page");
3229
3392
  rotation = 0;
3230
3393
  applyTransform();
3231
3394
  },
3395
+ fitToWidth: () => {
3396
+ isUserZoomed = false;
3397
+ fitMode = "width";
3398
+ scale = calculateFitScale("width");
3399
+ rotation = 0;
3400
+ applyTransform();
3401
+ },
3232
3402
  resetZoom: () => {
3233
3403
  isUserZoomed = false;
3234
- scale = calculateFitScale("page");
3404
+ fitMode = ctx?.options?.fitMode || "width";
3405
+ scale = calculateFitScale(fitMode);
3235
3406
  rotation = 0;
3236
3407
  ctx.container.scrollTop = 0;
3237
3408
  ctx.container.scrollLeft = 0;
@@ -3696,6 +3867,16 @@ var ExcelPlugin = class {
3696
3867
  instance.resetZoom?.();
3697
3868
  }
3698
3869
  },
3870
+ {
3871
+ id: "fit-width",
3872
+ icon: "fit-width",
3873
+ label: "Fit to Width",
3874
+ type: "button",
3875
+ group: "zoom",
3876
+ execute: () => {
3877
+ instance.fitToWidth?.();
3878
+ }
3879
+ },
3699
3880
  {
3700
3881
  id: "download",
3701
3882
  icon: "download",
@@ -3912,6 +4093,11 @@ var ExcelPlugin = class {
3912
4093
  scale = calculateFitScale();
3913
4094
  applyTransform();
3914
4095
  },
4096
+ fitToWidth: () => {
4097
+ isUserZoomed = false;
4098
+ scale = calculateFitScale();
4099
+ applyTransform();
4100
+ },
3915
4101
  resetZoom: () => {
3916
4102
  isUserZoomed = false;
3917
4103
  scale = calculateFitScale();
@@ -4059,6 +4245,16 @@ var CsvPlugin = class {
4059
4245
  instance.resetZoom?.();
4060
4246
  }
4061
4247
  },
4248
+ {
4249
+ id: "fit-width",
4250
+ icon: "fit-width",
4251
+ label: "Fit to Width",
4252
+ type: "button",
4253
+ group: "zoom",
4254
+ execute: () => {
4255
+ instance.fitToWidth?.();
4256
+ }
4257
+ },
4062
4258
  {
4063
4259
  id: "download",
4064
4260
  icon: "download",
@@ -4272,6 +4468,11 @@ var CsvPlugin = class {
4272
4468
  scale = calculateFitScale();
4273
4469
  applyScale();
4274
4470
  },
4471
+ fitToWidth: () => {
4472
+ isUserZoomed = false;
4473
+ scale = calculateFitScale();
4474
+ applyScale();
4475
+ },
4275
4476
  resetZoom: () => {
4276
4477
  isUserZoomed = false;
4277
4478
  scale = calculateFitScale();
@@ -4303,31 +4504,80 @@ function csvPlugin() {
4303
4504
  }
4304
4505
  var CODE_EXTENSIONS = [
4305
4506
  ".txt",
4507
+ ".log",
4508
+ ".ini",
4509
+ ".cfg",
4510
+ ".conf",
4511
+ ".env",
4306
4512
  ".json",
4513
+ ".jsonc",
4514
+ ".json5",
4307
4515
  ".js",
4308
- ".ts",
4516
+ ".mjs",
4517
+ ".cjs",
4309
4518
  ".jsx",
4519
+ ".ts",
4520
+ ".mts",
4521
+ ".cts",
4310
4522
  ".tsx",
4311
4523
  ".html",
4524
+ ".htm",
4525
+ ".xhtml",
4312
4526
  ".css",
4313
4527
  ".scss",
4528
+ ".sass",
4314
4529
  ".less",
4315
4530
  ".md",
4531
+ ".markdown",
4316
4532
  ".xml",
4533
+ ".svg",
4534
+ ".xaml",
4317
4535
  ".yml",
4318
4536
  ".yaml",
4537
+ ".toml",
4319
4538
  ".sh",
4320
4539
  ".bash",
4540
+ ".zsh",
4541
+ ".fish",
4542
+ ".bat",
4543
+ ".cmd",
4544
+ ".ps1",
4321
4545
  ".py",
4546
+ ".pyw",
4322
4547
  ".java",
4548
+ ".class",
4323
4549
  ".c",
4324
4550
  ".cpp",
4551
+ ".cc",
4552
+ ".cxx",
4325
4553
  ".h",
4554
+ ".hpp",
4555
+ ".hxx",
4326
4556
  ".cs",
4557
+ ".csx",
4327
4558
  ".go",
4328
4559
  ".rs",
4329
4560
  ".sql",
4330
- ".php"
4561
+ ".php",
4562
+ ".phtml",
4563
+ ".rb",
4564
+ ".swift",
4565
+ ".kt",
4566
+ ".kts",
4567
+ ".scala",
4568
+ ".r",
4569
+ ".lua",
4570
+ ".pl",
4571
+ ".pm",
4572
+ ".dart",
4573
+ ".graphql",
4574
+ ".gql",
4575
+ ".proto",
4576
+ ".diff",
4577
+ ".patch",
4578
+ ".dockerfile",
4579
+ ".properties",
4580
+ ".gradle"
4331
4581
  ];
4332
4582
  var CodePlugin = class {
4333
4583
  id = "code";
@@ -4345,34 +4595,36 @@ var CodePlugin = class {
4345
4595
  getToolbarActions(instance) {
4346
4596
  const totalPages = instance.getPageCount?.() ?? 1;
4347
4597
  const actions = [];
4348
- actions.push({
4349
- id: "thumbnails",
4350
- icon: "thumbnails",
4351
- label: "Page Thumbnails",
4352
- type: "button",
4353
- group: "navigation",
4354
- execute: () => instance.toggleThumbnails?.()
4355
- });
4356
- actions.push({
4357
- id: "page-nav",
4358
- icon: "",
4359
- label: "Page Navigation",
4360
- type: "page-nav",
4361
- group: "navigation",
4362
- value: instance.getCurrentPage?.() ?? 1,
4363
- max: totalPages,
4364
- execute: (action, page) => {
4365
- const cur = instance.getCurrentPage?.() ?? 1;
4366
- const max = instance.getPageCount?.() ?? 1;
4367
- if (action === "prev") {
4368
- if (cur > 1) instance.goToPage?.(cur - 1);
4369
- } else if (action === "next") {
4370
- if (cur < max) instance.goToPage?.(cur + 1);
4371
- } else if (typeof page === "number") {
4372
- instance.goToPage?.(page);
4598
+ if (totalPages > 1) {
4599
+ actions.push({
4600
+ id: "thumbnails",
4601
+ icon: "thumbnails",
4602
+ label: "Page Thumbnails",
4603
+ type: "button",
4604
+ group: "navigation",
4605
+ execute: () => instance.toggleThumbnails?.()
4606
+ });
4607
+ actions.push({
4608
+ id: "page-nav",
4609
+ icon: "",
4610
+ label: "Page Navigation",
4611
+ type: "page-nav",
4612
+ group: "navigation",
4613
+ value: instance.getCurrentPage?.() ?? 1,
4614
+ max: totalPages,
4615
+ execute: (action, page) => {
4616
+ const cur = instance.getCurrentPage?.() ?? 1;
4617
+ const max = instance.getPageCount?.() ?? 1;
4618
+ if (action === "prev") {
4619
+ if (cur > 1) instance.goToPage?.(cur - 1);
4620
+ } else if (action === "next") {
4621
+ if (cur < max) instance.goToPage?.(cur + 1);
4622
+ } else if (typeof page === "number") {
4623
+ instance.goToPage?.(page);
4624
+ }
4373
4625
  }
4374
- }
4375
- });
4626
+ });
4627
+ }
4376
4628
  actions.push(
4377
4629
  {
4378
4630
  id: "zoom-out",
@@ -4404,6 +4656,16 @@ var CodePlugin = class {
4404
4656
  instance.resetZoom?.();
4405
4657
  }
4406
4658
  },
4659
+ {
4660
+ id: "fit-width",
4661
+ icon: "fit-width",
4662
+ label: "Fit to Width",
4663
+ type: "button",
4664
+ group: "zoom",
4665
+ execute: () => {
4666
+ instance.fitToWidth?.();
4667
+ }
4668
+ },
4407
4669
  {
4408
4670
  id: "copy",
4409
4671
  icon: "copy",
@@ -4499,10 +4761,6 @@ var CodePlugin = class {
4499
4761
  }
4500
4762
  const totalPages = Math.max(1, rawPages.length);
4501
4763
  let currentPage = 1;
4502
- const container = document.createElement("div");
4503
- container.style.width = "100%";
4504
- container.style.height = "100%";
4505
- container.style.overflow = "auto";
4506
4764
  let fontSize = 13;
4507
4765
  let rotation = 0;
4508
4766
  let zoomLevel = 1;
@@ -4511,9 +4769,10 @@ var CodePlugin = class {
4511
4769
  const code = document.createElement("code");
4512
4770
  const sizer = document.createElement("div");
4513
4771
  const scrollWrapper = document.createElement("div");
4772
+ const lineGutter = document.createElement("div");
4773
+ ctx.container.style.overflow = "auto";
4514
4774
  if (isTxt) {
4515
- container.style.overflow = "auto";
4516
- container.style.backgroundColor = "#f1f5f9";
4775
+ ctx.container.style.backgroundColor = "#f1f5f9";
4517
4776
  scrollWrapper.className = "fp-code-scroll-wrapper";
4518
4777
  scrollWrapper.style.minWidth = "100%";
4519
4778
  scrollWrapper.style.minHeight = "100%";
@@ -4548,18 +4807,42 @@ var CodePlugin = class {
4548
4807
  pre.style.transition = "transform 0.15s ease";
4549
4808
  pre.style.flexShrink = "0";
4550
4809
  } else {
4551
- container.style.overflow = "auto";
4552
- container.style.backgroundColor = "#1e1e1e";
4553
- container.style.color = "#d4d4d4";
4554
- container.style.padding = "16px";
4555
- container.style.boxSizing = "border-box";
4810
+ ctx.container.style.backgroundColor = "#1e1e1e";
4811
+ ctx.container.style.color = "#d4d4d4";
4812
+ scrollWrapper.className = "fp-code-scroll-wrapper";
4813
+ scrollWrapper.style.minWidth = "100%";
4814
+ scrollWrapper.style.minHeight = "100%";
4815
+ scrollWrapper.style.width = "max-content";
4816
+ scrollWrapper.style.height = "max-content";
4817
+ scrollWrapper.style.display = "flex";
4818
+ scrollWrapper.style.alignItems = "flex-start";
4819
+ scrollWrapper.style.padding = "16px";
4820
+ scrollWrapper.style.boxSizing = "border-box";
4821
+ const lineCount = fullText.split(/\r?\n/).length || 1;
4822
+ const gutterLines = [];
4823
+ for (let i = 1; i <= lineCount; i++) {
4824
+ gutterLines.push(String(i));
4825
+ }
4826
+ lineGutter.className = "fp-code-gutter";
4827
+ lineGutter.style.userSelect = "none";
4828
+ lineGutter.style.textAlign = "right";
4829
+ lineGutter.style.paddingRight = "16px";
4830
+ lineGutter.style.marginRight = "16px";
4831
+ lineGutter.style.borderRight = "1px solid #333333";
4832
+ lineGutter.style.color = "#858585";
4833
+ lineGutter.style.fontFamily = "Consolas, Menlo, Monaco, 'Courier New', monospace";
4834
+ lineGutter.style.fontSize = `${fontSize}px`;
4835
+ lineGutter.style.lineHeight = "1.6";
4836
+ lineGutter.style.flexShrink = "0";
4837
+ lineGutter.textContent = gutterLines.join("\n");
4556
4838
  pre.style.margin = "0";
4557
- pre.style.fontFamily = "Consolas, Menlo, Monaco, monospace";
4839
+ pre.style.fontFamily = "Consolas, Menlo, Monaco, 'Courier New', monospace";
4558
4840
  pre.style.fontSize = `${fontSize}px`;
4559
- pre.style.lineHeight = "1.5";
4560
- pre.style.whiteSpace = "pre-wrap";
4561
- pre.style.wordBreak = "break-all";
4562
- pre.style.transformOrigin = "top left";
4841
+ pre.style.lineHeight = "1.6";
4842
+ pre.style.whiteSpace = "pre";
4843
+ pre.style.wordBreak = "normal";
4844
+ pre.style.overflowWrap = "normal";
4845
+ pre.style.flex = "1";
4563
4846
  }
4564
4847
  const ext = (ctx.metadata.extension || "").replace(".", "");
4565
4848
  const renderCodePage = (text) => {
@@ -4579,25 +4862,27 @@ var CodePlugin = class {
4579
4862
  };
4580
4863
  renderCodePage(rawPages[0] || (isTxt ? "" : fullText));
4581
4864
  pre.appendChild(code);
4865
+ ctx.container.innerHTML = "";
4582
4866
  if (isTxt) {
4583
4867
  sizer.appendChild(pre);
4584
4868
  scrollWrapper.appendChild(sizer);
4585
- container.appendChild(scrollWrapper);
4869
+ ctx.container.appendChild(scrollWrapper);
4586
4870
  } else {
4587
- container.appendChild(pre);
4871
+ scrollWrapper.appendChild(lineGutter);
4872
+ scrollWrapper.appendChild(pre);
4873
+ ctx.container.appendChild(scrollWrapper);
4588
4874
  }
4589
4875
  const showPage = (pageNum) => {
4590
4876
  currentPage = Math.max(1, Math.min(totalPages, pageNum));
4591
4877
  renderCodePage(rawPages[currentPage - 1] || (isTxt ? "" : fullText));
4592
- container.scrollTop = 0;
4878
+ ctx.container.scrollTop = 0;
4593
4879
  ctx.emit("page-change", { page: currentPage, total: totalPages });
4594
4880
  };
4595
4881
  if (totalPages > 1) {
4596
4882
  showPage(1);
4597
4883
  }
4598
- ctx.container.appendChild(container);
4599
4884
  const calculateTxtFit = () => {
4600
- const availW = Math.max(280, container.clientWidth - 32);
4885
+ const availW = Math.max(280, ctx.container.clientWidth - 32);
4601
4886
  return Math.max(0.4, Math.min(3, availW / 816));
4602
4887
  };
4603
4888
  const updateTransform = () => {
@@ -4615,6 +4900,7 @@ var CodePlugin = class {
4615
4900
  } else {
4616
4901
  pre.style.transform = `rotate(${rotation}deg)`;
4617
4902
  pre.style.fontSize = `${fontSize}px`;
4903
+ lineGutter.style.fontSize = `${fontSize}px`;
4618
4904
  }
4619
4905
  };
4620
4906
  let resizeObserver = null;
@@ -4629,11 +4915,11 @@ var CodePlugin = class {
4629
4915
  updateTransform();
4630
4916
  }
4631
4917
  }) : null;
4632
- resizeObserver?.observe(container);
4918
+ resizeObserver?.observe(ctx.container);
4633
4919
  }
4634
4920
  const cleanup = () => {
4635
4921
  resizeObserver?.disconnect();
4636
- container.remove();
4922
+ scrollWrapper.remove();
4637
4923
  ctx.container.innerHTML = "";
4638
4924
  };
4639
4925
  ctx.signal.addEventListener("abort", cleanup);
@@ -4678,7 +4964,7 @@ var CodePlugin = class {
4678
4964
  if (isTxt) {
4679
4965
  zoomLevel = Math.min(3.5, zoomLevel + 0.15);
4680
4966
  } else {
4681
- fontSize = Math.min(32, fontSize + 2);
4967
+ fontSize = Math.min(48, fontSize + 2);
4682
4968
  }
4683
4969
  updateTransform();
4684
4970
  },
@@ -4687,7 +4973,7 @@ var CodePlugin = class {
4687
4973
  if (isTxt) {
4688
4974
  zoomLevel = Math.max(0.1, zoomLevel - 0.15);
4689
4975
  } else {
4690
- fontSize = Math.max(8, fontSize - 2);
4976
+ fontSize = Math.max(9, fontSize - 2);
4691
4977
  }
4692
4978
  updateTransform();
4693
4979
  },
@@ -4708,13 +4994,20 @@ var CodePlugin = class {
4708
4994
  zoomLevel = isTxt ? calculateTxtFit() : 1;
4709
4995
  updateTransform();
4710
4996
  },
4997
+ fitToWidth: () => {
4998
+ isUserZoomed = false;
4999
+ fontSize = 13;
5000
+ rotation = 0;
5001
+ zoomLevel = isTxt ? calculateTxtFit() : 1;
5002
+ updateTransform();
5003
+ },
4711
5004
  resetZoom: () => {
4712
5005
  isUserZoomed = false;
4713
5006
  fontSize = 13;
4714
5007
  rotation = 0;
4715
5008
  zoomLevel = isTxt ? calculateTxtFit() : 1;
4716
- container.scrollTop = 0;
4717
- container.scrollLeft = 0;
5009
+ ctx.container.scrollTop = 0;
5010
+ ctx.container.scrollLeft = 0;
4718
5011
  updateTransform();
4719
5012
  },
4720
5013
  rotateCW: () => {
@@ -4792,6 +5085,14 @@ var ArchivePlugin = class {
4792
5085
  group: "zoom",
4793
5086
  execute: () => instance.resetZoom?.()
4794
5087
  },
5088
+ {
5089
+ id: "fit-width",
5090
+ icon: "fit-width",
5091
+ label: "Fit to Width",
5092
+ type: "button",
5093
+ group: "zoom",
5094
+ execute: () => instance.fitToWidth?.()
5095
+ },
4795
5096
  {
4796
5097
  id: "download",
4797
5098
  icon: "download",
@@ -4989,6 +5290,10 @@ var ArchivePlugin = class {
4989
5290
  scale = 1;
4990
5291
  applyTransform();
4991
5292
  },
5293
+ fitToWidth: () => {
5294
+ scale = 1;
5295
+ applyTransform();
5296
+ },
4992
5297
  resetZoom: () => {
4993
5298
  scale = 1;
4994
5299
  wrapper.scrollTop = 0;
@@ -5024,7 +5329,7 @@ var MarkdownPlugin = class {
5024
5329
  {
5025
5330
  id: "zoom-out",
5026
5331
  icon: "zoom-out",
5027
- label: "Decrease Font",
5332
+ label: "Zoom Out",
5028
5333
  type: "button",
5029
5334
  group: "zoom",
5030
5335
  execute: () => instance.zoomOut?.()
@@ -5032,19 +5337,11 @@ var MarkdownPlugin = class {
5032
5337
  {
5033
5338
  id: "zoom-in",
5034
5339
  icon: "zoom-in",
5035
- label: "Increase Font",
5340
+ label: "Zoom In",
5036
5341
  type: "button",
5037
5342
  group: "zoom",
5038
5343
  execute: () => instance.zoomIn?.()
5039
5344
  },
5040
- {
5041
- id: "fit-page",
5042
- icon: "fit-page",
5043
- label: "Default Size",
5044
- type: "button",
5045
- group: "zoom",
5046
- execute: () => instance.fitToPage?.()
5047
- },
5048
5345
  {
5049
5346
  id: "reset-zoom",
5050
5347
  icon: "reset-zoom",
@@ -5053,6 +5350,22 @@ var MarkdownPlugin = class {
5053
5350
  group: "zoom",
5054
5351
  execute: () => instance.resetZoom?.()
5055
5352
  },
5353
+ {
5354
+ id: "fit-width",
5355
+ icon: "fit-width",
5356
+ label: "Fit to Width",
5357
+ type: "button",
5358
+ group: "zoom",
5359
+ execute: () => instance.fitToWidth?.()
5360
+ },
5361
+ {
5362
+ id: "fit-page",
5363
+ icon: "fit-page",
5364
+ label: "Fit to Page",
5365
+ type: "button",
5366
+ group: "zoom",
5367
+ execute: () => instance.fitToPage?.()
5368
+ },
5056
5369
  {
5057
5370
  id: "copy",
5058
5371
  icon: "copy",
@@ -5076,10 +5389,18 @@ var MarkdownPlugin = class {
5076
5389
  type: "button",
5077
5390
  group: "actions",
5078
5391
  execute: () => instance.print?.()
5079
- }
5080
- ];
5081
- }
5082
- async render(ctx) {
5392
+ },
5393
+ {
5394
+ id: "open-window",
5395
+ icon: "open-window",
5396
+ label: "Open in Separate Full Window",
5397
+ type: "button",
5398
+ group: "actions",
5399
+ execute: () => instance.openInSeparateWindow?.()
5400
+ }
5401
+ ];
5402
+ }
5403
+ async render(ctx) {
5083
5404
  const text = new TextDecoder("utf-8", { fatal: false }).decode(ctx.buffer);
5084
5405
  const rawHtml = await marked.marked.parse(text, {
5085
5406
  gfm: true,
@@ -5088,35 +5409,57 @@ var MarkdownPlugin = class {
5088
5409
  const cleanHtml = DOMPurify6__default.default.sanitize(rawHtml, {
5089
5410
  USE_PROFILES: { html: true }
5090
5411
  });
5091
- const wrapper = document.createElement("div");
5092
- wrapper.className = "fp-markdown-wrapper";
5093
- wrapper.style.cssText = `
5094
- width: 100%;
5095
- height: 100%;
5096
- overflow: auto;
5097
- padding: 32px 40px;
5412
+ const scrollWrapper = document.createElement("div");
5413
+ scrollWrapper.className = "fp-markdown-scroll-wrapper";
5414
+ scrollWrapper.style.minWidth = "100%";
5415
+ scrollWrapper.style.minHeight = "100%";
5416
+ scrollWrapper.style.width = "max-content";
5417
+ scrollWrapper.style.height = "max-content";
5418
+ scrollWrapper.style.display = "flex";
5419
+ scrollWrapper.style.justifyContent = "center";
5420
+ scrollWrapper.style.alignItems = "flex-start";
5421
+ scrollWrapper.style.padding = "24px 16px";
5422
+ scrollWrapper.style.boxSizing = "border-box";
5423
+ const sizer = document.createElement("div");
5424
+ sizer.className = "fp-markdown-sizer";
5425
+ sizer.style.position = "relative";
5426
+ sizer.style.flexShrink = "0";
5427
+ sizer.style.display = "flex";
5428
+ sizer.style.justifyContent = "center";
5429
+ sizer.style.alignItems = "flex-start";
5430
+ const docCard = document.createElement("div");
5431
+ docCard.className = "fp-markdown-doc-card";
5432
+ docCard.style.cssText = `
5433
+ width: 860px;
5434
+ min-height: 600px;
5435
+ padding: 40px 48px;
5098
5436
  box-sizing: border-box;
5099
5437
  line-height: 1.6;
5100
5438
  font-size: 15px;
5101
5439
  color: var(--fp-text, #24292f);
5102
5440
  background: var(--fp-bg, #ffffff);
5441
+ border-radius: 6px;
5442
+ box-shadow: 0 4px 24px rgba(0, 0, 0, 0.08);
5103
5443
  font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Noto Sans", Helvetica, Arial, sans-serif;
5444
+ transform-origin: top center;
5445
+ transition: transform 0.15s ease;
5446
+ flex-shrink: 0;
5104
5447
  `;
5105
- wrapper.innerHTML = `
5448
+ docCard.innerHTML = `
5106
5449
  <style>
5107
- .fp-markdown-wrapper h1, .fp-markdown-wrapper h2, .fp-markdown-wrapper h3,
5108
- .fp-markdown-wrapper h4, .fp-markdown-wrapper h5, .fp-markdown-wrapper h6 {
5450
+ .fp-markdown-doc-card h1, .fp-markdown-doc-card h2, .fp-markdown-doc-card h3,
5451
+ .fp-markdown-doc-card h4, .fp-markdown-doc-card h5, .fp-markdown-doc-card h6 {
5109
5452
  margin-top: 24px;
5110
5453
  margin-bottom: 16px;
5111
5454
  font-weight: 600;
5112
5455
  line-height: 1.25;
5113
5456
  color: var(--fp-text, #1f2328);
5114
5457
  }
5115
- .fp-markdown-wrapper h1 { font-size: 2em; padding-bottom: 0.3em; border-bottom: 1px solid var(--fp-border, #d0d7de); }
5116
- .fp-markdown-wrapper h2 { font-size: 1.5em; padding-bottom: 0.3em; border-bottom: 1px solid var(--fp-border, #d0d7de); }
5117
- .fp-markdown-wrapper h3 { font-size: 1.25em; }
5118
- .fp-markdown-wrapper p { margin-top: 0; margin-bottom: 16px; }
5119
- .fp-markdown-wrapper table {
5458
+ .fp-markdown-doc-card h1 { font-size: 2em; padding-bottom: 0.3em; border-bottom: 1px solid var(--fp-border, #d0d7de); }
5459
+ .fp-markdown-doc-card h2 { font-size: 1.5em; padding-bottom: 0.3em; border-bottom: 1px solid var(--fp-border, #d0d7de); }
5460
+ .fp-markdown-doc-card h3 { font-size: 1.25em; }
5461
+ .fp-markdown-doc-card p { margin-top: 0; margin-bottom: 16px; }
5462
+ .fp-markdown-doc-card table {
5120
5463
  border-spacing: 0;
5121
5464
  border-collapse: collapse;
5122
5465
  margin-top: 0;
@@ -5124,20 +5467,20 @@ var MarkdownPlugin = class {
5124
5467
  width: 100%;
5125
5468
  overflow: auto;
5126
5469
  }
5127
- .fp-markdown-wrapper table th, .fp-markdown-wrapper table td {
5470
+ .fp-markdown-doc-card table th, .fp-markdown-doc-card table td {
5128
5471
  padding: 6px 13px;
5129
5472
  border: 1px solid var(--fp-border, #d0d7de);
5130
5473
  }
5131
- .fp-markdown-wrapper table tr:nth-child(2n) {
5474
+ .fp-markdown-doc-card table tr:nth-child(2n) {
5132
5475
  background-color: var(--fp-toolbar-bg, #f6f8fa);
5133
5476
  }
5134
- .fp-markdown-wrapper blockquote {
5477
+ .fp-markdown-doc-card blockquote {
5135
5478
  margin: 0 0 16px 0;
5136
5479
  padding: 0 1em;
5137
5480
  color: var(--fp-text-muted, #59636e);
5138
5481
  border-left: 0.25em solid var(--fp-border, #d0d7de);
5139
5482
  }
5140
- .fp-markdown-wrapper pre {
5483
+ .fp-markdown-doc-card pre {
5141
5484
  padding: 16px;
5142
5485
  overflow: auto;
5143
5486
  font-size: 85%;
@@ -5146,7 +5489,7 @@ var MarkdownPlugin = class {
5146
5489
  border-radius: 6px;
5147
5490
  border: 1px solid var(--fp-border, #d0d7de);
5148
5491
  }
5149
- .fp-markdown-wrapper code {
5492
+ .fp-markdown-doc-card code {
5150
5493
  padding: 0.2em 0.4em;
5151
5494
  margin: 0;
5152
5495
  font-size: 85%;
@@ -5154,16 +5497,16 @@ var MarkdownPlugin = class {
5154
5497
  border-radius: 4px;
5155
5498
  font-family: ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, monospace;
5156
5499
  }
5157
- .fp-markdown-wrapper pre code {
5500
+ .fp-markdown-doc-card pre code {
5158
5501
  padding: 0;
5159
5502
  background: transparent;
5160
5503
  }
5161
- .fp-markdown-wrapper ul, .fp-markdown-wrapper ol {
5504
+ .fp-markdown-doc-card ul, .fp-markdown-doc-card ol {
5162
5505
  padding-left: 2em;
5163
5506
  margin-top: 0;
5164
5507
  margin-bottom: 16px;
5165
5508
  }
5166
- .fp-markdown-wrapper hr {
5509
+ .fp-markdown-doc-card hr {
5167
5510
  height: 0.25em;
5168
5511
  padding: 0;
5169
5512
  margin: 24px 0;
@@ -5171,46 +5514,95 @@ var MarkdownPlugin = class {
5171
5514
  border: 0;
5172
5515
  }
5173
5516
  </style>
5174
- <div class="fp-markdown-content" style="max-width: 860px; margin: 0 auto;">
5517
+ <div class="fp-markdown-body">
5175
5518
  ${cleanHtml}
5176
5519
  </div>
5177
5520
  `;
5178
- wrapper.querySelectorAll("pre code").forEach((block) => {
5521
+ docCard.querySelectorAll("pre code").forEach((block) => {
5179
5522
  hljs__default.default.highlightElement(block);
5180
5523
  });
5524
+ sizer.appendChild(docCard);
5525
+ scrollWrapper.appendChild(sizer);
5181
5526
  ctx.container.innerHTML = "";
5182
5527
  ctx.container.style.overflow = "auto";
5183
- ctx.container.appendChild(wrapper);
5184
- let fontSize = 15;
5528
+ ctx.container.style.backgroundColor = "#f1f5f9";
5529
+ ctx.container.appendChild(scrollWrapper);
5530
+ let scale = 1;
5531
+ let isUserZoomed = false;
5532
+ const calculateFitScale = () => {
5533
+ const availW = Math.max(280, ctx.container.clientWidth - 48);
5534
+ if (availW < 860) {
5535
+ return Math.max(0.35, availW / 860);
5536
+ }
5537
+ return 1;
5538
+ };
5539
+ const applyTransform = () => {
5540
+ const baseW = 860;
5541
+ const baseH = docCard.offsetHeight || 600;
5542
+ const scaledW = Math.round(baseW * scale);
5543
+ const scaledH = Math.round(baseH * scale);
5544
+ sizer.style.width = `${scaledW}px`;
5545
+ sizer.style.height = `${scaledH}px`;
5546
+ docCard.style.width = `${baseW}px`;
5547
+ docCard.style.transform = `scale(${scale})`;
5548
+ docCard.style.transformOrigin = scaledW > ctx.container.clientWidth - 32 ? "top left" : "top center";
5549
+ };
5550
+ const ro = typeof ResizeObserver !== "undefined" ? new ResizeObserver(() => {
5551
+ if (!isUserZoomed) {
5552
+ scale = calculateFitScale();
5553
+ applyTransform();
5554
+ }
5555
+ }) : null;
5556
+ ro?.observe(ctx.container);
5557
+ requestAnimationFrame(() => {
5558
+ if (!isUserZoomed) {
5559
+ scale = calculateFitScale();
5560
+ }
5561
+ applyTransform();
5562
+ });
5185
5563
  const cleanup = () => {
5186
- wrapper.remove();
5564
+ ro?.disconnect();
5565
+ scrollWrapper.remove();
5187
5566
  ctx.container.innerHTML = "";
5188
5567
  };
5189
5568
  ctx.signal.addEventListener("abort", cleanup);
5190
5569
  return {
5191
5570
  destroy: cleanup,
5192
5571
  zoomIn: () => {
5193
- fontSize = Math.min(28, fontSize + 2);
5194
- wrapper.style.fontSize = `${fontSize}px`;
5572
+ isUserZoomed = true;
5573
+ scale = Math.min(3.5, scale + 0.15);
5574
+ applyTransform();
5195
5575
  },
5196
5576
  zoomOut: () => {
5197
- fontSize = Math.max(10, fontSize - 2);
5198
- wrapper.style.fontSize = `${fontSize}px`;
5577
+ isUserZoomed = true;
5578
+ scale = Math.max(0.25, scale - 0.15);
5579
+ applyTransform();
5199
5580
  },
5200
- getZoom: () => fontSize / 15,
5581
+ getZoom: () => scale,
5201
5582
  setZoom: (level) => {
5202
- fontSize = Math.round(15 * level);
5203
- wrapper.style.fontSize = `${fontSize}px`;
5583
+ isUserZoomed = true;
5584
+ scale = level;
5585
+ applyTransform();
5204
5586
  },
5205
5587
  fitToPage: () => {
5206
- fontSize = 15;
5207
- wrapper.style.fontSize = "15px";
5588
+ isUserZoomed = false;
5589
+ scale = calculateFitScale();
5590
+ applyTransform();
5591
+ },
5592
+ fitToWidth: () => {
5593
+ isUserZoomed = false;
5594
+ scale = calculateFitScale();
5595
+ applyTransform();
5208
5596
  },
5209
5597
  resetZoom: () => {
5210
- fontSize = 15;
5211
- wrapper.style.fontSize = "15px";
5598
+ isUserZoomed = false;
5599
+ scale = calculateFitScale();
5212
5600
  ctx.container.scrollTop = 0;
5213
5601
  ctx.container.scrollLeft = 0;
5602
+ applyTransform();
5603
+ },
5604
+ openInSeparateWindow: () => {
5605
+ ctx?.openInSeparateWindow?.();
5214
5606
  },
5215
5607
  download: () => {
5216
5608
  downloadFile(ctx.buffer, ctx.metadata.name || "document.md", "text/markdown");
@@ -5313,6 +5705,14 @@ var PptxPlugin = class {
5313
5705
  group: "zoom",
5314
5706
  execute: () => instance.resetZoom?.()
5315
5707
  },
5708
+ {
5709
+ id: "fit-width",
5710
+ icon: "fit-width",
5711
+ label: "Fit to Width",
5712
+ type: "button",
5713
+ group: "zoom",
5714
+ execute: () => instance.fitToWidth?.()
5715
+ },
5316
5716
  {
5317
5717
  id: "rotate-cw",
5318
5718
  icon: "rotate-cw",
@@ -5396,12 +5796,17 @@ var PptxPlugin = class {
5396
5796
  ctx.container.innerHTML = "";
5397
5797
  ctx.container.style.overflow = "auto";
5398
5798
  ctx.container.appendChild(wrapper);
5399
- const calculateFitScale = () => {
5400
- const availW = Math.max(200, ctx.container.clientWidth - 48);
5401
- const availH = Math.max(200, ctx.container.clientHeight - 72);
5799
+ let fitMode = ctx?.options?.fitMode || "width";
5800
+ let isUserZoomed = false;
5801
+ const calculateFitScale = (mode = fitMode) => {
5802
+ const availW = Math.max(200, ctx.container.clientWidth - 32);
5803
+ const availH = Math.max(200, ctx.container.clientHeight - 32);
5402
5804
  const cW = canvas.offsetWidth || 1280;
5403
5805
  const cH = canvas.offsetHeight || 720;
5404
- return Math.min(1, Math.min(availW / cW, availH / cH));
5806
+ if (mode === "page") {
5807
+ return Math.min(2.5, Math.min(availW / cW, availH / cH));
5808
+ }
5809
+ return Math.min(2.5, availW / cW);
5405
5810
  };
5406
5811
  const applyTransform = () => {
5407
5812
  const cW = canvas.offsetWidth || 1280;
@@ -5420,14 +5825,24 @@ var PptxPlugin = class {
5420
5825
  try {
5421
5826
  await renderer.renderSlide(currentSlide - 1, canvas, 1280);
5422
5827
  ctx.emit("page-change", { page: currentSlide, totalPages: slideCount });
5423
- scale = calculateFitScale();
5828
+ if (!isUserZoomed) {
5829
+ scale = calculateFitScale(fitMode);
5830
+ }
5424
5831
  applyTransform();
5425
5832
  } catch (err) {
5426
5833
  console.error("[PptxPlugin] Failed to render slide:", err);
5427
5834
  }
5428
5835
  };
5429
5836
  await renderCurrentSlide();
5837
+ const ro = typeof ResizeObserver !== "undefined" ? new ResizeObserver(() => {
5838
+ if (!isUserZoomed) {
5839
+ scale = calculateFitScale(fitMode);
5840
+ applyTransform();
5841
+ }
5842
+ }) : null;
5843
+ ro?.observe(ctx.container);
5430
5844
  const cleanup = () => {
5845
+ ro?.disconnect();
5431
5846
  renderer.destroy();
5432
5847
  wrapper.remove();
5433
5848
  ctx.container.innerHTML = "";
@@ -5444,28 +5859,44 @@ var PptxPlugin = class {
5444
5859
  getPageCount: () => slideCount,
5445
5860
  getCurrentPage: () => currentSlide,
5446
5861
  zoomIn: () => {
5862
+ isUserZoomed = true;
5447
5863
  scale += 0.15;
5448
5864
  applyTransform();
5449
5865
  },
5450
5866
  zoomOut: () => {
5867
+ isUserZoomed = true;
5451
5868
  scale = Math.max(0.2, scale - 0.15);
5452
5869
  applyTransform();
5453
5870
  },
5454
5871
  getZoom: () => scale,
5455
5872
  setZoom: (level) => {
5873
+ isUserZoomed = true;
5456
5874
  scale = level;
5457
5875
  applyTransform();
5458
5876
  },
5459
5877
  fitToPage: () => {
5460
- scale = calculateFitScale();
5878
+ isUserZoomed = false;
5879
+ fitMode = "page";
5880
+ scale = calculateFitScale("page");
5881
+ rotation = 0;
5882
+ applyTransform();
5883
+ },
5884
+ fitToWidth: () => {
5885
+ isUserZoomed = false;
5886
+ fitMode = "width";
5887
+ scale = calculateFitScale("width");
5461
5888
  rotation = 0;
5462
5889
  applyTransform();
5463
5890
  },
5464
5891
  resetZoom: () => {
5465
- scale = calculateFitScale();
5892
+ isUserZoomed = false;
5893
+ fitMode = ctx?.options?.fitMode || "width";
5894
+ scale = calculateFitScale(fitMode);
5466
5895
  rotation = 0;
5467
5896
  wrapper.scrollTop = 0;
5468
5897
  wrapper.scrollLeft = 0;
5898
+ ctx.container.scrollTop = 0;
5899
+ ctx.container.scrollLeft = 0;
5469
5900
  applyTransform();
5470
5901
  },
5471
5902
  rotateCW: () => {
@@ -5910,6 +6341,14 @@ var RtfPlugin = class {
5910
6341
  group: "zoom",
5911
6342
  execute: () => instance.resetZoom?.()
5912
6343
  },
6344
+ {
6345
+ id: "fit-width",
6346
+ icon: "fit-width",
6347
+ label: "Fit to Width",
6348
+ type: "button",
6349
+ group: "zoom",
6350
+ execute: () => instance.fitToWidth?.()
6351
+ },
5913
6352
  {
5914
6353
  id: "rotate-cw",
5915
6354
  icon: "rotate-cw",
@@ -6398,6 +6837,13 @@ var RtfPlugin = class {
6398
6837
  applyTransform();
6399
6838
  },
6400
6839
  fitToPage: () => {
6840
+ isUserZoomed = false;
6841
+ fitMode = "page";
6842
+ scale = calculateFitScale("page");
6843
+ rotation = 0;
6844
+ applyTransform();
6845
+ },
6846
+ fitToWidth: () => {
6401
6847
  isUserZoomed = false;
6402
6848
  fitMode = "width";
6403
6849
  scale = calculateFitScale("width");
@@ -6406,8 +6852,8 @@ var RtfPlugin = class {
6406
6852
  },
6407
6853
  resetZoom: () => {
6408
6854
  isUserZoomed = false;
6409
- fitMode = "width";
6410
- scale = calculateFitScale("width");
6855
+ fitMode = ctx?.options?.fitMode || "width";
6856
+ scale = calculateFitScale(fitMode);
6411
6857
  rotation = 0;
6412
6858
  ctx.container.scrollTop = 0;
6413
6859
  ctx.container.scrollLeft = 0;
@@ -6472,14 +6918,6 @@ var HtmlPreviewPlugin = class {
6472
6918
  group: "zoom",
6473
6919
  execute: () => instance.zoomIn?.()
6474
6920
  },
6475
- {
6476
- id: "fit-page",
6477
- icon: "fit-page",
6478
- label: "Fit to Page",
6479
- type: "button",
6480
- group: "zoom",
6481
- execute: () => instance.fitToPage?.()
6482
- },
6483
6921
  {
6484
6922
  id: "reset-zoom",
6485
6923
  icon: "reset-zoom",
@@ -6488,6 +6926,22 @@ var HtmlPreviewPlugin = class {
6488
6926
  group: "zoom",
6489
6927
  execute: () => instance.resetZoom?.()
6490
6928
  },
6929
+ {
6930
+ id: "fit-width",
6931
+ icon: "fit-width",
6932
+ label: "Fit to Width",
6933
+ type: "button",
6934
+ group: "zoom",
6935
+ execute: () => instance.fitToWidth?.()
6936
+ },
6937
+ {
6938
+ id: "fit-page",
6939
+ icon: "fit-page",
6940
+ label: "Fit to Page",
6941
+ type: "button",
6942
+ group: "zoom",
6943
+ execute: () => instance.fitToPage?.()
6944
+ },
6491
6945
  {
6492
6946
  id: "copy",
6493
6947
  icon: "copy",
@@ -6511,6 +6965,14 @@ var HtmlPreviewPlugin = class {
6511
6965
  type: "button",
6512
6966
  group: "actions",
6513
6967
  execute: () => instance.print?.()
6968
+ },
6969
+ {
6970
+ id: "open-window",
6971
+ icon: "open-window",
6972
+ label: "Open in Separate Full Window",
6973
+ type: "button",
6974
+ group: "actions",
6975
+ execute: () => instance.openInSeparateWindow?.()
6514
6976
  }
6515
6977
  ];
6516
6978
  }
@@ -6521,27 +6983,39 @@ var HtmlPreviewPlugin = class {
6521
6983
  ADD_TAGS: ["style", "link"],
6522
6984
  ADD_ATTR: ["target", "rel"]
6523
6985
  });
6986
+ const scrollWrapper = document.createElement("div");
6987
+ scrollWrapper.className = "fp-html-scroll-wrapper";
6988
+ scrollWrapper.style.minWidth = "100%";
6989
+ scrollWrapper.style.minHeight = "100%";
6990
+ scrollWrapper.style.width = "max-content";
6991
+ scrollWrapper.style.height = "max-content";
6992
+ scrollWrapper.style.display = "flex";
6993
+ scrollWrapper.style.justifyContent = "flex-start";
6994
+ scrollWrapper.style.alignItems = "flex-start";
6995
+ scrollWrapper.style.boxSizing = "border-box";
6524
6996
  const sizer = document.createElement("div");
6525
6997
  sizer.className = "fp-html-sizer";
6526
6998
  sizer.style.position = "relative";
6999
+ sizer.style.flexShrink = "0";
6527
7000
  const iframe = document.createElement("iframe");
6528
7001
  iframe.className = "fp-html-iframe";
6529
7002
  iframe.style.border = "none";
6530
7003
  iframe.style.backgroundColor = "#ffffff";
6531
7004
  iframe.style.transformOrigin = "top left";
6532
- iframe.style.transition = "transform 0.2s ease";
7005
+ iframe.style.transition = "transform 0.15s ease";
6533
7006
  iframe.sandbox.add("allow-same-origin");
6534
7007
  sizer.appendChild(iframe);
7008
+ scrollWrapper.appendChild(sizer);
6535
7009
  ctx.container.style.overflow = "auto";
6536
7010
  ctx.container.style.width = "100%";
6537
7011
  ctx.container.style.height = "100%";
6538
7012
  ctx.container.innerHTML = "";
6539
- ctx.container.appendChild(sizer);
7013
+ ctx.container.appendChild(scrollWrapper);
6540
7014
  iframe.srcdoc = sanitized;
6541
7015
  let scale = 1;
7016
+ let baseW = Math.max(600, ctx.container.clientWidth || 800);
7017
+ let baseH = Math.max(400, ctx.container.clientHeight || 600);
6542
7018
  const applyTransform = () => {
6543
- const baseW = Math.max(600, ctx.container.clientWidth || 800);
6544
- const baseH = Math.max(400, ctx.container.clientHeight || 600);
6545
7019
  const scaledW = Math.round(baseW * scale);
6546
7020
  const scaledH = Math.round(baseH * scale);
6547
7021
  sizer.style.width = `${scaledW}px`;
@@ -6554,22 +7028,33 @@ var HtmlPreviewPlugin = class {
6554
7028
  iframe.style.transform = `scale(${scale})`;
6555
7029
  iframe.style.transformOrigin = "top left";
6556
7030
  };
7031
+ const ro = typeof ResizeObserver !== "undefined" ? new ResizeObserver(() => {
7032
+ if (Math.abs(scale - 1) < 0.05) {
7033
+ baseW = Math.max(600, ctx.container.clientWidth || 800);
7034
+ baseH = Math.max(400, ctx.container.clientHeight || 600);
7035
+ applyTransform();
7036
+ }
7037
+ }) : null;
7038
+ ro?.observe(ctx.container);
6557
7039
  requestAnimationFrame(() => {
7040
+ baseW = Math.max(600, ctx.container.clientWidth || 800);
7041
+ baseH = Math.max(400, ctx.container.clientHeight || 600);
6558
7042
  applyTransform();
6559
7043
  });
6560
7044
  const cleanup = () => {
6561
- sizer.remove();
7045
+ ro?.disconnect();
7046
+ scrollWrapper.remove();
6562
7047
  ctx.container.innerHTML = "";
6563
7048
  };
6564
7049
  ctx.signal.addEventListener("abort", cleanup);
6565
7050
  return {
6566
7051
  destroy: cleanup,
6567
7052
  zoomIn: () => {
6568
- scale += 0.1;
7053
+ scale = Math.min(3.5, scale + 0.15);
6569
7054
  applyTransform();
6570
7055
  },
6571
7056
  zoomOut: () => {
6572
- scale = Math.max(0.2, scale - 0.1);
7057
+ scale = Math.max(0.25, scale - 0.15);
6573
7058
  applyTransform();
6574
7059
  },
6575
7060
  getZoom: () => scale,
@@ -6581,14 +7066,21 @@ var HtmlPreviewPlugin = class {
6581
7066
  scale = 1;
6582
7067
  applyTransform();
6583
7068
  },
7069
+ fitToWidth: () => {
7070
+ scale = 1;
7071
+ applyTransform();
7072
+ },
6584
7073
  resetZoom: () => {
6585
7074
  scale = 1;
6586
7075
  ctx.container.scrollTop = 0;
6587
7076
  ctx.container.scrollLeft = 0;
6588
7077
  applyTransform();
6589
7078
  },
7079
+ openInSeparateWindow: () => {
7080
+ ctx?.openInSeparateWindow?.();
7081
+ },
6590
7082
  copy: () => {
6591
- navigator.clipboard.writeText(rawHtml);
7083
+ navigator.clipboard?.writeText(rawHtml);
6592
7084
  },
6593
7085
  download: () => {
6594
7086
  const blob = new Blob([ctx.buffer], { type: "text/html" });
@@ -6695,6 +7187,14 @@ var OpenDocumentPlugin = class {
6695
7187
  group: "zoom",
6696
7188
  execute: () => instance.resetZoom?.()
6697
7189
  },
7190
+ {
7191
+ id: "fit-width",
7192
+ icon: "fit-width",
7193
+ label: "Fit to Width",
7194
+ type: "button",
7195
+ group: "zoom",
7196
+ execute: () => instance.fitToWidth?.()
7197
+ },
6698
7198
  {
6699
7199
  id: "rotate-cw",
6700
7200
  icon: "rotate-cw",
@@ -6811,7 +7311,10 @@ var OpenDocumentPlugin = class {
6811
7311
  const sW = availW / elW;
6812
7312
  const sH = availH / (isPresentation ? 540 : singlePageH);
6813
7313
  if (isPresentation) {
6814
- return Math.min(2.5, Math.min(sW, sH));
7314
+ if (mode === "page") {
7315
+ return Math.min(2.5, Math.min(sW, sH));
7316
+ }
7317
+ return Math.min(2.5, sW);
6815
7318
  }
6816
7319
  if (mode === "page") {
6817
7320
  return Math.max(0.35, Math.min(3, Math.min(sW, sH)));
@@ -6980,6 +7483,13 @@ var OpenDocumentPlugin = class {
6980
7483
  applyTransform();
6981
7484
  },
6982
7485
  fitToPage: () => {
7486
+ isUserZoomed = false;
7487
+ fitMode = "page";
7488
+ scale = calculateFitScale("page");
7489
+ rotation = 0;
7490
+ applyTransform();
7491
+ },
7492
+ fitToWidth: () => {
6983
7493
  isUserZoomed = false;
6984
7494
  fitMode = "width";
6985
7495
  scale = calculateFitScale("width");
@@ -6988,8 +7498,8 @@ var OpenDocumentPlugin = class {
6988
7498
  },
6989
7499
  resetZoom: () => {
6990
7500
  isUserZoomed = false;
6991
- fitMode = "width";
6992
- scale = calculateFitScale("width");
7501
+ fitMode = ctx?.options?.fitMode || "width";
7502
+ scale = calculateFitScale(fitMode);
6993
7503
  rotation = 0;
6994
7504
  container.scrollTop = 0;
6995
7505
  container.scrollLeft = 0;
@@ -7346,6 +7856,14 @@ var DocPlugin = class {
7346
7856
  group: "zoom",
7347
7857
  execute: () => instance.resetZoom?.()
7348
7858
  },
7859
+ {
7860
+ id: "fit-width",
7861
+ icon: "fit-width",
7862
+ label: "Fit to Width",
7863
+ type: "button",
7864
+ group: "zoom",
7865
+ execute: () => instance.fitToWidth?.()
7866
+ },
7349
7867
  {
7350
7868
  id: "rotate-cw",
7351
7869
  icon: "rotate-cw",
@@ -7567,6 +8085,13 @@ var DocPlugin = class {
7567
8085
  applyTransform();
7568
8086
  },
7569
8087
  fitToPage: () => {
8088
+ isUserZoomed = false;
8089
+ fitMode = "page";
8090
+ scale = calculateFitScale("page");
8091
+ rotation = 0;
8092
+ applyTransform();
8093
+ },
8094
+ fitToWidth: () => {
7570
8095
  isUserZoomed = false;
7571
8096
  fitMode = "width";
7572
8097
  scale = calculateFitScale("width");
@@ -7575,8 +8100,8 @@ var DocPlugin = class {
7575
8100
  },
7576
8101
  resetZoom: () => {
7577
8102
  isUserZoomed = false;
7578
- fitMode = "width";
7579
- scale = calculateFitScale("width");
8103
+ fitMode = ctx?.options?.fitMode || "width";
8104
+ scale = calculateFitScale(fitMode);
7580
8105
  rotation = 0;
7581
8106
  container.scrollTop = 0;
7582
8107
  container.scrollLeft = 0;
@@ -8072,6 +8597,14 @@ var PptPlugin = class {
8072
8597
  group: "zoom",
8073
8598
  execute: () => instance.resetZoom?.()
8074
8599
  },
8600
+ {
8601
+ id: "fit-width",
8602
+ icon: "fit-width",
8603
+ label: "Fit to Width",
8604
+ type: "button",
8605
+ group: "zoom",
8606
+ execute: () => instance.fitToWidth?.()
8607
+ },
8075
8608
  {
8076
8609
  id: "rotate-cw",
8077
8610
  icon: "rotate-cw",
@@ -8146,10 +8679,15 @@ var PptPlugin = class {
8146
8679
  let currentSlide = 1;
8147
8680
  let slides = [];
8148
8681
  const createdBlobUrls = [];
8149
- const calculateFitScale = () => {
8150
- const availW = Math.max(200, container.clientWidth - 48);
8151
- const availH = Math.max(200, container.clientHeight - 72);
8152
- return Math.min(1, Math.min(availW / 960, availH / 540));
8682
+ let fitMode = ctx?.options?.fitMode || "width";
8683
+ let isUserZoomed = false;
8684
+ const calculateFitScale = (mode = fitMode) => {
8685
+ const availW = Math.max(200, container.clientWidth - 32);
8686
+ const availH = Math.max(200, container.clientHeight - 32);
8687
+ if (mode === "page") {
8688
+ return Math.min(2.5, Math.min(availW / 960, availH / 540));
8689
+ }
8690
+ return Math.min(2.5, availW / 960);
8153
8691
  };
8154
8692
  const applyTransform = () => {
8155
8693
  const cW = 960;
@@ -8164,8 +8702,15 @@ var PptPlugin = class {
8164
8702
  slideCard.style.transform = `scale(${scale}) rotate(${rotation}deg)`;
8165
8703
  slideCard.style.transformOrigin = "center center";
8166
8704
  };
8705
+ const ro = typeof ResizeObserver !== "undefined" ? new ResizeObserver(() => {
8706
+ if (!isUserZoomed) {
8707
+ scale = calculateFitScale(fitMode);
8708
+ applyTransform();
8709
+ }
8710
+ }) : null;
8711
+ ro?.observe(container);
8167
8712
  setTimeout(() => {
8168
- scale = calculateFitScale();
8713
+ scale = calculateFitScale(fitMode);
8169
8714
  applyTransform();
8170
8715
  }, 60);
8171
8716
  try {
@@ -8258,6 +8803,7 @@ var PptPlugin = class {
8258
8803
  };
8259
8804
  renderSlide(1);
8260
8805
  const cleanup = () => {
8806
+ ro?.disconnect();
8261
8807
  for (const u of createdBlobUrls) {
8262
8808
  URL.revokeObjectURL(u);
8263
8809
  }
@@ -8268,28 +8814,44 @@ var PptPlugin = class {
8268
8814
  return {
8269
8815
  destroy: cleanup,
8270
8816
  zoomIn: () => {
8817
+ isUserZoomed = true;
8271
8818
  scale += 0.15;
8272
8819
  applyTransform();
8273
8820
  },
8274
8821
  zoomOut: () => {
8822
+ isUserZoomed = true;
8275
8823
  scale = Math.max(0.2, scale - 0.15);
8276
8824
  applyTransform();
8277
8825
  },
8278
8826
  getZoom: () => scale,
8279
8827
  setZoom: (level) => {
8828
+ isUserZoomed = true;
8280
8829
  scale = level;
8281
8830
  applyTransform();
8282
8831
  },
8283
8832
  fitToPage: () => {
8284
- scale = calculateFitScale();
8833
+ isUserZoomed = false;
8834
+ fitMode = "page";
8835
+ scale = calculateFitScale("page");
8836
+ rotation = 0;
8837
+ applyTransform();
8838
+ },
8839
+ fitToWidth: () => {
8840
+ isUserZoomed = false;
8841
+ fitMode = "width";
8842
+ scale = calculateFitScale("width");
8285
8843
  rotation = 0;
8286
8844
  applyTransform();
8287
8845
  },
8288
8846
  resetZoom: () => {
8289
- scale = calculateFitScale();
8847
+ isUserZoomed = false;
8848
+ fitMode = ctx?.options?.fitMode || "width";
8849
+ scale = calculateFitScale(fitMode);
8290
8850
  rotation = 0;
8291
8851
  container.scrollTop = 0;
8292
8852
  container.scrollLeft = 0;
8853
+ ctx.container.scrollTop = 0;
8854
+ ctx.container.scrollLeft = 0;
8293
8855
  applyTransform();
8294
8856
  },
8295
8857
  rotateCW: () => {
@@ -8639,7 +9201,7 @@ var FilePreview = react.memo(react.forwardRef(
8639
9201
  {
8640
9202
  ref: containerRef,
8641
9203
  className,
8642
- style: { width: "100%", height: "100%", position: "relative", ...style }
9204
+ style: { width: "100%", height: "100%", position: "relative", overflow: "hidden", ...style }
8643
9205
  }
8644
9206
  );
8645
9207
  }