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