@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/angular.cjs CHANGED
@@ -1137,6 +1137,10 @@ var FilePreviewViewer = class _FilePreviewViewer {
1137
1137
  * Preview a file in the given container element.
1138
1138
  */
1139
1139
  async preview(container, source, options = {}) {
1140
+ options = {
1141
+ ...options,
1142
+ fitMode: options.fitMode ?? "width"
1143
+ };
1140
1144
  this.currentOptions = options;
1141
1145
  this.abort();
1142
1146
  this.abortController = new AbortController();
@@ -1185,8 +1189,8 @@ var FilePreviewViewer = class _FilePreviewViewer {
1185
1189
  this.activeInstance = instance;
1186
1190
  instance.openInSeparateWindow = () => this.openInSeparateWindow();
1187
1191
  instance.toggleThumbnails = () => this.toggleThumbnails();
1188
- if (!instance.resetZoom && instance.fitToPage) {
1189
- instance.resetZoom = () => instance.fitToPage?.();
1192
+ if (!instance.resetZoom) {
1193
+ instance.resetZoom = () => instance.fitToWidth ? instance.fitToWidth() : instance.fitToPage?.();
1190
1194
  }
1191
1195
  this.hideLoading();
1192
1196
  this.eventEmitter.emit("loaded", { metadata, plugin: matchedPlugin.id });
@@ -1583,7 +1587,7 @@ var FilePreviewViewer = class _FilePreviewViewer {
1583
1587
  this.wrapperEl?.classList.toggle("fp-fullscreen-active");
1584
1588
  }
1585
1589
  setTimeout(() => {
1586
- this.activeInstance?.fitToPage?.();
1590
+ this.triggerAutoFit();
1587
1591
  }, 120);
1588
1592
  }
1589
1593
  /**
@@ -1675,19 +1679,85 @@ var FilePreviewViewer = class _FilePreviewViewer {
1675
1679
  if (this.wrapperEl?.parentNode) {
1676
1680
  this.wrapperEl.parentNode.removeChild(this.wrapperEl);
1677
1681
  }
1682
+ if (typeof document !== "undefined" && !document.getElementById("fp-core-injected-styles")) {
1683
+ const styleEl = document.createElement("style");
1684
+ styleEl.id = "fp-core-injected-styles";
1685
+ styleEl.textContent = `
1686
+ .fp-viewer {
1687
+ display: flex !important;
1688
+ flex-direction: column !important;
1689
+ width: 100% !important;
1690
+ height: 100% !important;
1691
+ overflow: hidden !important;
1692
+ position: relative !important;
1693
+ box-sizing: border-box !important;
1694
+ }
1695
+ .fp-body {
1696
+ display: flex !important;
1697
+ flex: 1 1 0% !important;
1698
+ min-height: 0 !important;
1699
+ min-width: 0 !important;
1700
+ width: 100% !important;
1701
+ height: 100% !important;
1702
+ overflow: hidden !important;
1703
+ position: relative !important;
1704
+ box-sizing: border-box !important;
1705
+ }
1706
+ .fp-content {
1707
+ flex: 1 1 0% !important;
1708
+ position: relative !important;
1709
+ overflow: auto !important;
1710
+ display: flex !important;
1711
+ flex-direction: column !important;
1712
+ align-items: stretch !important;
1713
+ justify-content: flex-start !important;
1714
+ width: 100% !important;
1715
+ height: 100% !important;
1716
+ min-width: 0 !important;
1717
+ min-height: 0 !important;
1718
+ box-sizing: border-box !important;
1719
+ }
1720
+ `;
1721
+ document.head.appendChild(styleEl);
1722
+ }
1678
1723
  const themeClass = options.theme === "dark" ? "fp-theme-dark" : "";
1679
1724
  const toolbarPos = options.toolbarPosition ?? "top";
1680
1725
  this.wrapperEl = document.createElement("div");
1681
1726
  this.wrapperEl.className = `fp-viewer ${themeClass} ${options.className ?? ""}`.trim();
1682
1727
  this.wrapperEl.tabIndex = 0;
1728
+ this.wrapperEl.style.display = "flex";
1729
+ this.wrapperEl.style.flexDirection = "column";
1730
+ this.wrapperEl.style.width = "100%";
1731
+ this.wrapperEl.style.height = "100%";
1732
+ this.wrapperEl.style.overflow = "hidden";
1733
+ this.wrapperEl.style.position = "relative";
1683
1734
  const toolbarEl = document.createElement("div");
1684
1735
  toolbarEl.className = "fp-toolbar-container";
1685
1736
  this.contentEl = document.createElement("div");
1686
1737
  this.contentEl.className = "fp-content";
1738
+ this.contentEl.style.flex = "1 1 0%";
1739
+ this.contentEl.style.position = "relative";
1740
+ this.contentEl.style.overflow = "auto";
1741
+ this.contentEl.style.display = "flex";
1742
+ this.contentEl.style.flexDirection = "column";
1743
+ this.contentEl.style.alignItems = "stretch";
1744
+ this.contentEl.style.justifyContent = "flex-start";
1745
+ this.contentEl.style.width = "100%";
1746
+ this.contentEl.style.height = "100%";
1747
+ this.contentEl.style.minWidth = "0";
1748
+ this.contentEl.style.minHeight = "0";
1749
+ this.contentEl.style.boxSizing = "border-box";
1687
1750
  const thumbnailEl = document.createElement("div");
1688
1751
  thumbnailEl.className = "fp-thumbnail-container";
1689
1752
  const bodyEl = document.createElement("div");
1690
1753
  bodyEl.className = "fp-body";
1754
+ bodyEl.style.display = "flex";
1755
+ bodyEl.style.flex = "1 1 0%";
1756
+ bodyEl.style.minHeight = "0";
1757
+ bodyEl.style.minWidth = "0";
1758
+ bodyEl.style.width = "100%";
1759
+ bodyEl.style.overflow = "hidden";
1760
+ bodyEl.style.position = "relative";
1691
1761
  bodyEl.appendChild(thumbnailEl);
1692
1762
  bodyEl.appendChild(this.contentEl);
1693
1763
  const titleBarEl = document.createElement("div");
@@ -1710,18 +1780,29 @@ var FilePreviewViewer = class _FilePreviewViewer {
1710
1780
  this.thumbnailPanel = new ThumbnailPanel(thumbnailEl, (isOpen) => {
1711
1781
  this.toolbar?.setActionActive("thumbnails", isOpen);
1712
1782
  setTimeout(() => {
1713
- this.activeInstance?.fitToPage?.();
1783
+ this.triggerAutoFit();
1714
1784
  }, 260);
1715
1785
  });
1716
1786
  this.setupKeyboardShortcuts();
1717
1787
  this.setupDragAndDrop(container, options);
1718
1788
  this.setupResizeAndFullscreenListeners();
1719
1789
  }
1790
+ triggerAutoFit() {
1791
+ if (!this.activeInstance) return;
1792
+ const mode = this.currentOptions?.fitMode ?? "width";
1793
+ if (mode === "width" && this.activeInstance.fitToWidth) {
1794
+ this.activeInstance.fitToWidth();
1795
+ } else if (this.activeInstance.fitToPage) {
1796
+ this.activeInstance.fitToPage();
1797
+ } else if (this.activeInstance.resetZoom) {
1798
+ this.activeInstance.resetZoom();
1799
+ }
1800
+ }
1720
1801
  setupResizeAndFullscreenListeners() {
1721
1802
  if (this.fullscreenHandler) return;
1722
1803
  this.fullscreenHandler = () => {
1723
1804
  setTimeout(() => {
1724
- this.activeInstance?.fitToPage?.();
1805
+ this.triggerAutoFit();
1725
1806
  }, 100);
1726
1807
  };
1727
1808
  document.addEventListener("fullscreenchange", this.fullscreenHandler);
@@ -1729,7 +1810,7 @@ var FilePreviewViewer = class _FilePreviewViewer {
1729
1810
  if (typeof ResizeObserver !== "undefined" && this.contentEl) {
1730
1811
  this.resizeObserver = new ResizeObserver(() => {
1731
1812
  if (this.activeInstance && (!this.activeInstance.getZoom || Math.abs((this.activeInstance.getZoom?.() ?? 1) - 1) < 0.05)) {
1732
- this.activeInstance.fitToPage?.();
1813
+ this.triggerAutoFit();
1733
1814
  }
1734
1815
  });
1735
1816
  this.resizeObserver.observe(this.contentEl);
@@ -1757,7 +1838,7 @@ var FilePreviewViewer = class _FilePreviewViewer {
1757
1838
  } else if (e.key === "-" || e.key === "_") {
1758
1839
  this.activeInstance.zoomOut?.();
1759
1840
  } else if (e.key === "0") {
1760
- this.activeInstance.fitToPage?.();
1841
+ this.resetZoom();
1761
1842
  } else if (e.key === "r" || e.key === "R") {
1762
1843
  this.activeInstance.rotateCW?.();
1763
1844
  } else if (e.key === "f" || e.key === "F") {
@@ -2380,7 +2461,7 @@ var PdfPlugin = class {
2380
2461
  renderPage(currentPage);
2381
2462
  },
2382
2463
  resetZoom: () => {
2383
- fitMode = "page";
2464
+ fitMode = ctx?.options?.fitMode || "width";
2384
2465
  zoomScale = 1;
2385
2466
  rotation = 0;
2386
2467
  container.scrollTop = 0;
@@ -2564,6 +2645,16 @@ var MediaPlugin = class {
2564
2645
  instance.resetZoom?.();
2565
2646
  }
2566
2647
  },
2648
+ {
2649
+ id: "fit-width",
2650
+ icon: "fit-width",
2651
+ label: "Fit to Width",
2652
+ type: "button",
2653
+ group: "zoom",
2654
+ execute: () => {
2655
+ instance.fitToWidth?.();
2656
+ }
2657
+ },
2567
2658
  {
2568
2659
  id: "rotate-cw",
2569
2660
  icon: "rotate-cw",
@@ -2660,9 +2751,30 @@ var MediaPlugin = class {
2660
2751
  const isVideo = mimeType.startsWith("video/") || VIDEO_EXTS.includes(ctx.metadata.extension || "");
2661
2752
  const isAudio = mimeType.startsWith("audio/") || AUDIO_EXTS.includes(ctx.metadata.extension || "");
2662
2753
  let url = "";
2754
+ let naturalW = 800;
2755
+ let naturalH = 600;
2663
2756
  if (ctx.metadata.extension === ".svg" || mimeType === "image/svg+xml") {
2664
2757
  const decoder = new TextDecoder("utf-8");
2665
2758
  const svgText = decoder.decode(ctx.buffer);
2759
+ try {
2760
+ const vbMatch = svgText.match(/viewBox=["']\s*([0-9.-]+)\s+([0-9.-]+)\s+([0-9.-]+)\s+([0-9.-]+)\s*["']/i);
2761
+ if (vbMatch) {
2762
+ const vw = parseFloat(vbMatch[3]);
2763
+ const vh = parseFloat(vbMatch[4]);
2764
+ if (vw > 0 && vh > 0) {
2765
+ naturalW = vw;
2766
+ naturalH = vh;
2767
+ }
2768
+ } else {
2769
+ const wMatch = svgText.match(/width=["']([0-9.]+)(?:px)?["']/i);
2770
+ const hMatch = svgText.match(/height=["']([0-9.]+)(?:px)?["']/i);
2771
+ if (wMatch && hMatch) {
2772
+ naturalW = parseFloat(wMatch[1]) || naturalW;
2773
+ naturalH = parseFloat(hMatch[1]) || naturalH;
2774
+ }
2775
+ }
2776
+ } catch {
2777
+ }
2666
2778
  const blob = new Blob([svgText], { type: "image/svg+xml" });
2667
2779
  url = URL.createObjectURL(blob);
2668
2780
  } else {
@@ -2710,7 +2822,7 @@ var MediaPlugin = class {
2710
2822
  scrollWrapper.style.width = "max-content";
2711
2823
  scrollWrapper.style.height = "max-content";
2712
2824
  scrollWrapper.style.display = "flex";
2713
- scrollWrapper.style.justifyContent = "center";
2825
+ scrollWrapper.style.flexDirection = "column";
2714
2826
  scrollWrapper.style.alignItems = "center";
2715
2827
  scrollWrapper.style.padding = "16px";
2716
2828
  scrollWrapper.style.boxSizing = "border-box";
@@ -2721,40 +2833,54 @@ var MediaPlugin = class {
2721
2833
  sizer.style.display = "flex";
2722
2834
  sizer.style.justifyContent = "center";
2723
2835
  sizer.style.alignItems = "center";
2836
+ sizer.style.margin = "auto 0";
2724
2837
  sizer.appendChild(element);
2725
2838
  scrollWrapper.appendChild(sizer);
2726
2839
  ctx.container.style.overflow = "auto";
2727
2840
  ctx.container.style.padding = "0";
2728
2841
  ctx.container.innerHTML = "";
2729
2842
  ctx.container.appendChild(scrollWrapper);
2730
- let naturalW = 800;
2731
- let naturalH = 600;
2732
- let baseW = 800;
2733
- let baseH = 600;
2843
+ let baseW = naturalW;
2844
+ let baseH = naturalH;
2845
+ let fitMode = ctx?.options?.fitMode || "width";
2846
+ let isUserZoomed = false;
2734
2847
  const updateBaseDimensions = () => {
2735
2848
  if (!isImage) return;
2736
2849
  const img = element;
2737
- naturalW = img.naturalWidth || naturalW;
2738
- naturalH = img.naturalHeight || naturalH;
2739
- const availW = Math.max(100, ctx.container.clientWidth - 48);
2740
- const availH = Math.max(100, ctx.container.clientHeight - 48);
2741
- const fitRatio = Math.min(1, availW / naturalW, availH / naturalH);
2850
+ if (img.naturalWidth > 0 && img.naturalHeight > 0) {
2851
+ naturalW = img.naturalWidth;
2852
+ naturalH = img.naturalHeight;
2853
+ }
2854
+ const availW = Math.max(100, ctx.container.clientWidth - 32);
2855
+ const availH = Math.max(100, ctx.container.clientHeight - 32);
2856
+ let fitRatio;
2857
+ if (fitMode === "page") {
2858
+ fitRatio = Math.min(availW / naturalW, availH / naturalH);
2859
+ } else {
2860
+ fitRatio = availW / naturalW;
2861
+ }
2742
2862
  baseW = Math.max(1, Math.round(naturalW * fitRatio));
2743
2863
  baseH = Math.max(1, Math.round(naturalH * fitRatio));
2744
2864
  };
2745
2865
  const applyTransform = () => {
2746
2866
  if (isImage) {
2747
- updateBaseDimensions();
2867
+ if (!isUserZoomed) {
2868
+ updateBaseDimensions();
2869
+ }
2870
+ const availH = Math.max(100, ctx.container.clientHeight - 32);
2748
2871
  const isRotated90 = rotation % 180 !== 0;
2749
2872
  const boxW = Math.round((isRotated90 ? baseH : baseW) * currentZoom);
2750
2873
  const boxH = Math.round((isRotated90 ? baseW : baseH) * currentZoom);
2751
2874
  sizer.style.width = `${boxW}px`;
2752
2875
  sizer.style.height = `${boxH}px`;
2753
- element.style.width = `${baseW}px`;
2754
- element.style.height = `${baseH}px`;
2876
+ sizer.style.margin = boxH < availH ? "auto 0" : "0";
2877
+ const imgW = isRotated90 ? boxH : boxW;
2878
+ const imgH = isRotated90 ? boxW : boxH;
2879
+ element.style.width = `${imgW}px`;
2880
+ element.style.height = `${imgH}px`;
2755
2881
  element.style.maxWidth = "none";
2756
2882
  element.style.maxHeight = "none";
2757
- element.style.transform = `scale(${currentZoom}) rotate(${rotation}deg)`;
2883
+ element.style.transform = rotation ? `rotate(${rotation}deg)` : "none";
2758
2884
  element.style.transformOrigin = "center center";
2759
2885
  element.style.flexShrink = "0";
2760
2886
  } else {
@@ -2774,7 +2900,8 @@ var MediaPlugin = class {
2774
2900
  }
2775
2901
  }
2776
2902
  const ro = typeof ResizeObserver !== "undefined" ? new ResizeObserver(() => {
2777
- if (currentZoom === 1) {
2903
+ if (!isUserZoomed && currentZoom === 1) {
2904
+ updateBaseDimensions();
2778
2905
  applyTransform();
2779
2906
  }
2780
2907
  }) : null;
@@ -2789,28 +2916,49 @@ var MediaPlugin = class {
2789
2916
  return {
2790
2917
  destroy: cleanup,
2791
2918
  zoomIn: isImage ? () => {
2792
- currentZoom += 0.1;
2919
+ isUserZoomed = true;
2920
+ currentZoom = Math.min(5, Math.round((currentZoom + 0.15) * 100) / 100);
2793
2921
  applyTransform();
2794
2922
  } : void 0,
2795
2923
  zoomOut: isImage ? () => {
2796
- currentZoom = Math.max(0.1, currentZoom - 0.1);
2924
+ isUserZoomed = true;
2925
+ currentZoom = Math.max(0.1, Math.round((currentZoom - 0.15) * 100) / 100);
2797
2926
  applyTransform();
2798
2927
  } : void 0,
2799
2928
  getZoom: isImage ? () => currentZoom : void 0,
2800
2929
  setZoom: isImage ? (level) => {
2930
+ isUserZoomed = true;
2801
2931
  currentZoom = level;
2802
2932
  applyTransform();
2803
2933
  } : void 0,
2804
2934
  fitToPage: isImage ? () => {
2935
+ isUserZoomed = false;
2936
+ fitMode = "page";
2937
+ currentZoom = 1;
2938
+ rotation = 0;
2939
+ ctx.container.scrollTop = 0;
2940
+ ctx.container.scrollLeft = 0;
2941
+ updateBaseDimensions();
2942
+ applyTransform();
2943
+ } : void 0,
2944
+ fitToWidth: isImage ? () => {
2945
+ isUserZoomed = false;
2946
+ fitMode = "width";
2805
2947
  currentZoom = 1;
2806
2948
  rotation = 0;
2949
+ ctx.container.scrollTop = 0;
2950
+ ctx.container.scrollLeft = 0;
2951
+ updateBaseDimensions();
2807
2952
  applyTransform();
2808
2953
  } : void 0,
2809
2954
  resetZoom: isImage ? () => {
2955
+ isUserZoomed = false;
2956
+ fitMode = ctx?.options?.fitMode || "width";
2810
2957
  currentZoom = 1;
2811
2958
  rotation = 0;
2812
2959
  ctx.container.scrollTop = 0;
2813
2960
  ctx.container.scrollLeft = 0;
2961
+ updateBaseDimensions();
2814
2962
  applyTransform();
2815
2963
  } : void 0,
2816
2964
  rotateCW: isImage || isVideo ? () => {
@@ -2937,6 +3085,14 @@ var DocxPlugin = class {
2937
3085
  group: "zoom",
2938
3086
  execute: () => instance.resetZoom?.()
2939
3087
  },
3088
+ {
3089
+ id: "fit-width",
3090
+ icon: "fit-width",
3091
+ label: "Fit to Width",
3092
+ type: "button",
3093
+ group: "zoom",
3094
+ execute: () => instance.fitToWidth?.()
3095
+ },
2940
3096
  {
2941
3097
  id: "rotate-cw",
2942
3098
  icon: "rotate-cw",
@@ -3196,13 +3352,19 @@ var DocxPlugin = class {
3196
3352
  }
3197
3353
  scale = 1;
3198
3354
  let rotation = 0;
3199
- let fitMode = "page";
3355
+ let fitMode = ctx?.options?.fitMode || "width";
3200
3356
  let isUserZoomed = false;
3201
- const calculateFitScale = (_mode = fitMode) => {
3357
+ const calculateFitScale = (mode = fitMode) => {
3202
3358
  const activeEl = pageElements[currentPage - 1] || wrapper.querySelector("section.docx") || wrapper;
3203
3359
  const elW = activeEl.offsetWidth || 816;
3360
+ const elH = activeEl.offsetHeight || 1056;
3204
3361
  const availW = Math.max(280, ctx.container.clientWidth - 32);
3362
+ const availH = Math.max(280, ctx.container.clientHeight - 32);
3205
3363
  const sW = availW / elW;
3364
+ const sH = availH / elH;
3365
+ if (mode === "page") {
3366
+ return Math.max(0.35, Math.min(3, Math.min(sW, sH)));
3367
+ }
3206
3368
  return Math.max(0.35, Math.min(3, sW));
3207
3369
  };
3208
3370
  const applyTransform = () => {
@@ -3223,7 +3385,7 @@ var DocxPlugin = class {
3223
3385
  if (typeof ResizeObserver !== "undefined") {
3224
3386
  resizeObserver = new ResizeObserver(() => {
3225
3387
  if (!isUserZoomed) {
3226
- const newFit = calculateFitScale("page");
3388
+ const newFit = calculateFitScale(fitMode);
3227
3389
  if (Math.abs(scale - newFit) > 0.015) {
3228
3390
  scale = newFit;
3229
3391
  applyTransform();
@@ -3233,7 +3395,7 @@ var DocxPlugin = class {
3233
3395
  resizeObserver.observe(ctx.container);
3234
3396
  }
3235
3397
  setTimeout(() => {
3236
- scale = calculateFitScale("page");
3398
+ scale = calculateFitScale(fitMode);
3237
3399
  applyTransform();
3238
3400
  }, 40);
3239
3401
  const cleanup = () => {
@@ -3272,13 +3434,22 @@ var DocxPlugin = class {
3272
3434
  },
3273
3435
  fitToPage: () => {
3274
3436
  isUserZoomed = false;
3437
+ fitMode = "page";
3275
3438
  scale = calculateFitScale("page");
3276
3439
  rotation = 0;
3277
3440
  applyTransform();
3278
3441
  },
3442
+ fitToWidth: () => {
3443
+ isUserZoomed = false;
3444
+ fitMode = "width";
3445
+ scale = calculateFitScale("width");
3446
+ rotation = 0;
3447
+ applyTransform();
3448
+ },
3279
3449
  resetZoom: () => {
3280
3450
  isUserZoomed = false;
3281
- scale = calculateFitScale("page");
3451
+ fitMode = ctx?.options?.fitMode || "width";
3452
+ scale = calculateFitScale(fitMode);
3282
3453
  rotation = 0;
3283
3454
  ctx.container.scrollTop = 0;
3284
3455
  ctx.container.scrollLeft = 0;
@@ -3743,6 +3914,16 @@ var ExcelPlugin = class {
3743
3914
  instance.resetZoom?.();
3744
3915
  }
3745
3916
  },
3917
+ {
3918
+ id: "fit-width",
3919
+ icon: "fit-width",
3920
+ label: "Fit to Width",
3921
+ type: "button",
3922
+ group: "zoom",
3923
+ execute: () => {
3924
+ instance.fitToWidth?.();
3925
+ }
3926
+ },
3746
3927
  {
3747
3928
  id: "download",
3748
3929
  icon: "download",
@@ -3959,6 +4140,11 @@ var ExcelPlugin = class {
3959
4140
  scale = calculateFitScale();
3960
4141
  applyTransform();
3961
4142
  },
4143
+ fitToWidth: () => {
4144
+ isUserZoomed = false;
4145
+ scale = calculateFitScale();
4146
+ applyTransform();
4147
+ },
3962
4148
  resetZoom: () => {
3963
4149
  isUserZoomed = false;
3964
4150
  scale = calculateFitScale();
@@ -4106,6 +4292,16 @@ var CsvPlugin = class {
4106
4292
  instance.resetZoom?.();
4107
4293
  }
4108
4294
  },
4295
+ {
4296
+ id: "fit-width",
4297
+ icon: "fit-width",
4298
+ label: "Fit to Width",
4299
+ type: "button",
4300
+ group: "zoom",
4301
+ execute: () => {
4302
+ instance.fitToWidth?.();
4303
+ }
4304
+ },
4109
4305
  {
4110
4306
  id: "download",
4111
4307
  icon: "download",
@@ -4319,6 +4515,11 @@ var CsvPlugin = class {
4319
4515
  scale = calculateFitScale();
4320
4516
  applyScale();
4321
4517
  },
4518
+ fitToWidth: () => {
4519
+ isUserZoomed = false;
4520
+ scale = calculateFitScale();
4521
+ applyScale();
4522
+ },
4322
4523
  resetZoom: () => {
4323
4524
  isUserZoomed = false;
4324
4525
  scale = calculateFitScale();
@@ -4350,31 +4551,80 @@ function csvPlugin() {
4350
4551
  }
4351
4552
  var CODE_EXTENSIONS = [
4352
4553
  ".txt",
4554
+ ".log",
4555
+ ".ini",
4556
+ ".cfg",
4557
+ ".conf",
4558
+ ".env",
4353
4559
  ".json",
4560
+ ".jsonc",
4561
+ ".json5",
4354
4562
  ".js",
4355
- ".ts",
4563
+ ".mjs",
4564
+ ".cjs",
4356
4565
  ".jsx",
4566
+ ".ts",
4567
+ ".mts",
4568
+ ".cts",
4357
4569
  ".tsx",
4358
4570
  ".html",
4571
+ ".htm",
4572
+ ".xhtml",
4359
4573
  ".css",
4360
4574
  ".scss",
4575
+ ".sass",
4361
4576
  ".less",
4362
4577
  ".md",
4578
+ ".markdown",
4363
4579
  ".xml",
4580
+ ".svg",
4581
+ ".xaml",
4364
4582
  ".yml",
4365
4583
  ".yaml",
4584
+ ".toml",
4366
4585
  ".sh",
4367
4586
  ".bash",
4587
+ ".zsh",
4588
+ ".fish",
4589
+ ".bat",
4590
+ ".cmd",
4591
+ ".ps1",
4368
4592
  ".py",
4593
+ ".pyw",
4369
4594
  ".java",
4595
+ ".class",
4370
4596
  ".c",
4371
4597
  ".cpp",
4598
+ ".cc",
4599
+ ".cxx",
4372
4600
  ".h",
4601
+ ".hpp",
4602
+ ".hxx",
4373
4603
  ".cs",
4604
+ ".csx",
4374
4605
  ".go",
4375
4606
  ".rs",
4376
4607
  ".sql",
4377
- ".php"
4608
+ ".php",
4609
+ ".phtml",
4610
+ ".rb",
4611
+ ".swift",
4612
+ ".kt",
4613
+ ".kts",
4614
+ ".scala",
4615
+ ".r",
4616
+ ".lua",
4617
+ ".pl",
4618
+ ".pm",
4619
+ ".dart",
4620
+ ".graphql",
4621
+ ".gql",
4622
+ ".proto",
4623
+ ".diff",
4624
+ ".patch",
4625
+ ".dockerfile",
4626
+ ".properties",
4627
+ ".gradle"
4378
4628
  ];
4379
4629
  var CodePlugin = class {
4380
4630
  id = "code";
@@ -4392,34 +4642,36 @@ var CodePlugin = class {
4392
4642
  getToolbarActions(instance) {
4393
4643
  const totalPages = instance.getPageCount?.() ?? 1;
4394
4644
  const actions = [];
4395
- actions.push({
4396
- id: "thumbnails",
4397
- icon: "thumbnails",
4398
- label: "Page Thumbnails",
4399
- type: "button",
4400
- group: "navigation",
4401
- execute: () => instance.toggleThumbnails?.()
4402
- });
4403
- actions.push({
4404
- id: "page-nav",
4405
- icon: "",
4406
- label: "Page Navigation",
4407
- type: "page-nav",
4408
- group: "navigation",
4409
- value: instance.getCurrentPage?.() ?? 1,
4410
- max: totalPages,
4411
- execute: (action, page) => {
4412
- const cur = instance.getCurrentPage?.() ?? 1;
4413
- const max = instance.getPageCount?.() ?? 1;
4414
- if (action === "prev") {
4415
- if (cur > 1) instance.goToPage?.(cur - 1);
4416
- } else if (action === "next") {
4417
- if (cur < max) instance.goToPage?.(cur + 1);
4418
- } else if (typeof page === "number") {
4419
- instance.goToPage?.(page);
4645
+ if (totalPages > 1) {
4646
+ actions.push({
4647
+ id: "thumbnails",
4648
+ icon: "thumbnails",
4649
+ label: "Page Thumbnails",
4650
+ type: "button",
4651
+ group: "navigation",
4652
+ execute: () => instance.toggleThumbnails?.()
4653
+ });
4654
+ actions.push({
4655
+ id: "page-nav",
4656
+ icon: "",
4657
+ label: "Page Navigation",
4658
+ type: "page-nav",
4659
+ group: "navigation",
4660
+ value: instance.getCurrentPage?.() ?? 1,
4661
+ max: totalPages,
4662
+ execute: (action, page) => {
4663
+ const cur = instance.getCurrentPage?.() ?? 1;
4664
+ const max = instance.getPageCount?.() ?? 1;
4665
+ if (action === "prev") {
4666
+ if (cur > 1) instance.goToPage?.(cur - 1);
4667
+ } else if (action === "next") {
4668
+ if (cur < max) instance.goToPage?.(cur + 1);
4669
+ } else if (typeof page === "number") {
4670
+ instance.goToPage?.(page);
4671
+ }
4420
4672
  }
4421
- }
4422
- });
4673
+ });
4674
+ }
4423
4675
  actions.push(
4424
4676
  {
4425
4677
  id: "zoom-out",
@@ -4451,6 +4703,16 @@ var CodePlugin = class {
4451
4703
  instance.resetZoom?.();
4452
4704
  }
4453
4705
  },
4706
+ {
4707
+ id: "fit-width",
4708
+ icon: "fit-width",
4709
+ label: "Fit to Width",
4710
+ type: "button",
4711
+ group: "zoom",
4712
+ execute: () => {
4713
+ instance.fitToWidth?.();
4714
+ }
4715
+ },
4454
4716
  {
4455
4717
  id: "copy",
4456
4718
  icon: "copy",
@@ -4546,10 +4808,6 @@ var CodePlugin = class {
4546
4808
  }
4547
4809
  const totalPages = Math.max(1, rawPages.length);
4548
4810
  let currentPage = 1;
4549
- const container = document.createElement("div");
4550
- container.style.width = "100%";
4551
- container.style.height = "100%";
4552
- container.style.overflow = "auto";
4553
4811
  let fontSize = 13;
4554
4812
  let rotation = 0;
4555
4813
  let zoomLevel = 1;
@@ -4558,9 +4816,10 @@ var CodePlugin = class {
4558
4816
  const code = document.createElement("code");
4559
4817
  const sizer = document.createElement("div");
4560
4818
  const scrollWrapper = document.createElement("div");
4819
+ const lineGutter = document.createElement("div");
4820
+ ctx.container.style.overflow = "auto";
4561
4821
  if (isTxt) {
4562
- container.style.overflow = "auto";
4563
- container.style.backgroundColor = "#f1f5f9";
4822
+ ctx.container.style.backgroundColor = "#f1f5f9";
4564
4823
  scrollWrapper.className = "fp-code-scroll-wrapper";
4565
4824
  scrollWrapper.style.minWidth = "100%";
4566
4825
  scrollWrapper.style.minHeight = "100%";
@@ -4595,18 +4854,42 @@ var CodePlugin = class {
4595
4854
  pre.style.transition = "transform 0.15s ease";
4596
4855
  pre.style.flexShrink = "0";
4597
4856
  } else {
4598
- container.style.overflow = "auto";
4599
- container.style.backgroundColor = "#1e1e1e";
4600
- container.style.color = "#d4d4d4";
4601
- container.style.padding = "16px";
4602
- container.style.boxSizing = "border-box";
4857
+ ctx.container.style.backgroundColor = "#1e1e1e";
4858
+ ctx.container.style.color = "#d4d4d4";
4859
+ scrollWrapper.className = "fp-code-scroll-wrapper";
4860
+ scrollWrapper.style.minWidth = "100%";
4861
+ scrollWrapper.style.minHeight = "100%";
4862
+ scrollWrapper.style.width = "max-content";
4863
+ scrollWrapper.style.height = "max-content";
4864
+ scrollWrapper.style.display = "flex";
4865
+ scrollWrapper.style.alignItems = "flex-start";
4866
+ scrollWrapper.style.padding = "16px";
4867
+ scrollWrapper.style.boxSizing = "border-box";
4868
+ const lineCount = fullText.split(/\r?\n/).length || 1;
4869
+ const gutterLines = [];
4870
+ for (let i = 1; i <= lineCount; i++) {
4871
+ gutterLines.push(String(i));
4872
+ }
4873
+ lineGutter.className = "fp-code-gutter";
4874
+ lineGutter.style.userSelect = "none";
4875
+ lineGutter.style.textAlign = "right";
4876
+ lineGutter.style.paddingRight = "16px";
4877
+ lineGutter.style.marginRight = "16px";
4878
+ lineGutter.style.borderRight = "1px solid #333333";
4879
+ lineGutter.style.color = "#858585";
4880
+ lineGutter.style.fontFamily = "Consolas, Menlo, Monaco, 'Courier New', monospace";
4881
+ lineGutter.style.fontSize = `${fontSize}px`;
4882
+ lineGutter.style.lineHeight = "1.6";
4883
+ lineGutter.style.flexShrink = "0";
4884
+ lineGutter.textContent = gutterLines.join("\n");
4603
4885
  pre.style.margin = "0";
4604
- pre.style.fontFamily = "Consolas, Menlo, Monaco, monospace";
4886
+ pre.style.fontFamily = "Consolas, Menlo, Monaco, 'Courier New', monospace";
4605
4887
  pre.style.fontSize = `${fontSize}px`;
4606
- pre.style.lineHeight = "1.5";
4607
- pre.style.whiteSpace = "pre-wrap";
4608
- pre.style.wordBreak = "break-all";
4609
- pre.style.transformOrigin = "top left";
4888
+ pre.style.lineHeight = "1.6";
4889
+ pre.style.whiteSpace = "pre";
4890
+ pre.style.wordBreak = "normal";
4891
+ pre.style.overflowWrap = "normal";
4892
+ pre.style.flex = "1";
4610
4893
  }
4611
4894
  const ext = (ctx.metadata.extension || "").replace(".", "");
4612
4895
  const renderCodePage = (text) => {
@@ -4626,25 +4909,27 @@ var CodePlugin = class {
4626
4909
  };
4627
4910
  renderCodePage(rawPages[0] || (isTxt ? "" : fullText));
4628
4911
  pre.appendChild(code);
4912
+ ctx.container.innerHTML = "";
4629
4913
  if (isTxt) {
4630
4914
  sizer.appendChild(pre);
4631
4915
  scrollWrapper.appendChild(sizer);
4632
- container.appendChild(scrollWrapper);
4916
+ ctx.container.appendChild(scrollWrapper);
4633
4917
  } else {
4634
- container.appendChild(pre);
4918
+ scrollWrapper.appendChild(lineGutter);
4919
+ scrollWrapper.appendChild(pre);
4920
+ ctx.container.appendChild(scrollWrapper);
4635
4921
  }
4636
4922
  const showPage = (pageNum) => {
4637
4923
  currentPage = Math.max(1, Math.min(totalPages, pageNum));
4638
4924
  renderCodePage(rawPages[currentPage - 1] || (isTxt ? "" : fullText));
4639
- container.scrollTop = 0;
4925
+ ctx.container.scrollTop = 0;
4640
4926
  ctx.emit("page-change", { page: currentPage, total: totalPages });
4641
4927
  };
4642
4928
  if (totalPages > 1) {
4643
4929
  showPage(1);
4644
4930
  }
4645
- ctx.container.appendChild(container);
4646
4931
  const calculateTxtFit = () => {
4647
- const availW = Math.max(280, container.clientWidth - 32);
4932
+ const availW = Math.max(280, ctx.container.clientWidth - 32);
4648
4933
  return Math.max(0.4, Math.min(3, availW / 816));
4649
4934
  };
4650
4935
  const updateTransform = () => {
@@ -4662,6 +4947,7 @@ var CodePlugin = class {
4662
4947
  } else {
4663
4948
  pre.style.transform = `rotate(${rotation}deg)`;
4664
4949
  pre.style.fontSize = `${fontSize}px`;
4950
+ lineGutter.style.fontSize = `${fontSize}px`;
4665
4951
  }
4666
4952
  };
4667
4953
  let resizeObserver = null;
@@ -4676,11 +4962,11 @@ var CodePlugin = class {
4676
4962
  updateTransform();
4677
4963
  }
4678
4964
  }) : null;
4679
- resizeObserver?.observe(container);
4965
+ resizeObserver?.observe(ctx.container);
4680
4966
  }
4681
4967
  const cleanup = () => {
4682
4968
  resizeObserver?.disconnect();
4683
- container.remove();
4969
+ scrollWrapper.remove();
4684
4970
  ctx.container.innerHTML = "";
4685
4971
  };
4686
4972
  ctx.signal.addEventListener("abort", cleanup);
@@ -4725,7 +5011,7 @@ var CodePlugin = class {
4725
5011
  if (isTxt) {
4726
5012
  zoomLevel = Math.min(3.5, zoomLevel + 0.15);
4727
5013
  } else {
4728
- fontSize = Math.min(32, fontSize + 2);
5014
+ fontSize = Math.min(48, fontSize + 2);
4729
5015
  }
4730
5016
  updateTransform();
4731
5017
  },
@@ -4734,7 +5020,7 @@ var CodePlugin = class {
4734
5020
  if (isTxt) {
4735
5021
  zoomLevel = Math.max(0.1, zoomLevel - 0.15);
4736
5022
  } else {
4737
- fontSize = Math.max(8, fontSize - 2);
5023
+ fontSize = Math.max(9, fontSize - 2);
4738
5024
  }
4739
5025
  updateTransform();
4740
5026
  },
@@ -4755,13 +5041,20 @@ var CodePlugin = class {
4755
5041
  zoomLevel = isTxt ? calculateTxtFit() : 1;
4756
5042
  updateTransform();
4757
5043
  },
5044
+ fitToWidth: () => {
5045
+ isUserZoomed = false;
5046
+ fontSize = 13;
5047
+ rotation = 0;
5048
+ zoomLevel = isTxt ? calculateTxtFit() : 1;
5049
+ updateTransform();
5050
+ },
4758
5051
  resetZoom: () => {
4759
5052
  isUserZoomed = false;
4760
5053
  fontSize = 13;
4761
5054
  rotation = 0;
4762
5055
  zoomLevel = isTxt ? calculateTxtFit() : 1;
4763
- container.scrollTop = 0;
4764
- container.scrollLeft = 0;
5056
+ ctx.container.scrollTop = 0;
5057
+ ctx.container.scrollLeft = 0;
4765
5058
  updateTransform();
4766
5059
  },
4767
5060
  rotateCW: () => {
@@ -4839,6 +5132,14 @@ var ArchivePlugin = class {
4839
5132
  group: "zoom",
4840
5133
  execute: () => instance.resetZoom?.()
4841
5134
  },
5135
+ {
5136
+ id: "fit-width",
5137
+ icon: "fit-width",
5138
+ label: "Fit to Width",
5139
+ type: "button",
5140
+ group: "zoom",
5141
+ execute: () => instance.fitToWidth?.()
5142
+ },
4842
5143
  {
4843
5144
  id: "download",
4844
5145
  icon: "download",
@@ -5036,6 +5337,10 @@ var ArchivePlugin = class {
5036
5337
  scale = 1;
5037
5338
  applyTransform();
5038
5339
  },
5340
+ fitToWidth: () => {
5341
+ scale = 1;
5342
+ applyTransform();
5343
+ },
5039
5344
  resetZoom: () => {
5040
5345
  scale = 1;
5041
5346
  wrapper.scrollTop = 0;
@@ -5071,7 +5376,7 @@ var MarkdownPlugin = class {
5071
5376
  {
5072
5377
  id: "zoom-out",
5073
5378
  icon: "zoom-out",
5074
- label: "Decrease Font",
5379
+ label: "Zoom Out",
5075
5380
  type: "button",
5076
5381
  group: "zoom",
5077
5382
  execute: () => instance.zoomOut?.()
@@ -5079,19 +5384,11 @@ var MarkdownPlugin = class {
5079
5384
  {
5080
5385
  id: "zoom-in",
5081
5386
  icon: "zoom-in",
5082
- label: "Increase Font",
5387
+ label: "Zoom In",
5083
5388
  type: "button",
5084
5389
  group: "zoom",
5085
5390
  execute: () => instance.zoomIn?.()
5086
5391
  },
5087
- {
5088
- id: "fit-page",
5089
- icon: "fit-page",
5090
- label: "Default Size",
5091
- type: "button",
5092
- group: "zoom",
5093
- execute: () => instance.fitToPage?.()
5094
- },
5095
5392
  {
5096
5393
  id: "reset-zoom",
5097
5394
  icon: "reset-zoom",
@@ -5100,6 +5397,22 @@ var MarkdownPlugin = class {
5100
5397
  group: "zoom",
5101
5398
  execute: () => instance.resetZoom?.()
5102
5399
  },
5400
+ {
5401
+ id: "fit-width",
5402
+ icon: "fit-width",
5403
+ label: "Fit to Width",
5404
+ type: "button",
5405
+ group: "zoom",
5406
+ execute: () => instance.fitToWidth?.()
5407
+ },
5408
+ {
5409
+ id: "fit-page",
5410
+ icon: "fit-page",
5411
+ label: "Fit to Page",
5412
+ type: "button",
5413
+ group: "zoom",
5414
+ execute: () => instance.fitToPage?.()
5415
+ },
5103
5416
  {
5104
5417
  id: "copy",
5105
5418
  icon: "copy",
@@ -5123,10 +5436,18 @@ var MarkdownPlugin = class {
5123
5436
  type: "button",
5124
5437
  group: "actions",
5125
5438
  execute: () => instance.print?.()
5126
- }
5127
- ];
5128
- }
5129
- async render(ctx) {
5439
+ },
5440
+ {
5441
+ id: "open-window",
5442
+ icon: "open-window",
5443
+ label: "Open in Separate Full Window",
5444
+ type: "button",
5445
+ group: "actions",
5446
+ execute: () => instance.openInSeparateWindow?.()
5447
+ }
5448
+ ];
5449
+ }
5450
+ async render(ctx) {
5130
5451
  const text = new TextDecoder("utf-8", { fatal: false }).decode(ctx.buffer);
5131
5452
  const rawHtml = await marked.marked.parse(text, {
5132
5453
  gfm: true,
@@ -5135,35 +5456,57 @@ var MarkdownPlugin = class {
5135
5456
  const cleanHtml = DOMPurify6__default.default.sanitize(rawHtml, {
5136
5457
  USE_PROFILES: { html: true }
5137
5458
  });
5138
- const wrapper = document.createElement("div");
5139
- wrapper.className = "fp-markdown-wrapper";
5140
- wrapper.style.cssText = `
5141
- width: 100%;
5142
- height: 100%;
5143
- overflow: auto;
5144
- padding: 32px 40px;
5459
+ const scrollWrapper = document.createElement("div");
5460
+ scrollWrapper.className = "fp-markdown-scroll-wrapper";
5461
+ scrollWrapper.style.minWidth = "100%";
5462
+ scrollWrapper.style.minHeight = "100%";
5463
+ scrollWrapper.style.width = "max-content";
5464
+ scrollWrapper.style.height = "max-content";
5465
+ scrollWrapper.style.display = "flex";
5466
+ scrollWrapper.style.justifyContent = "center";
5467
+ scrollWrapper.style.alignItems = "flex-start";
5468
+ scrollWrapper.style.padding = "24px 16px";
5469
+ scrollWrapper.style.boxSizing = "border-box";
5470
+ const sizer = document.createElement("div");
5471
+ sizer.className = "fp-markdown-sizer";
5472
+ sizer.style.position = "relative";
5473
+ sizer.style.flexShrink = "0";
5474
+ sizer.style.display = "flex";
5475
+ sizer.style.justifyContent = "center";
5476
+ sizer.style.alignItems = "flex-start";
5477
+ const docCard = document.createElement("div");
5478
+ docCard.className = "fp-markdown-doc-card";
5479
+ docCard.style.cssText = `
5480
+ width: 860px;
5481
+ min-height: 600px;
5482
+ padding: 40px 48px;
5145
5483
  box-sizing: border-box;
5146
5484
  line-height: 1.6;
5147
5485
  font-size: 15px;
5148
5486
  color: var(--fp-text, #24292f);
5149
5487
  background: var(--fp-bg, #ffffff);
5488
+ border-radius: 6px;
5489
+ box-shadow: 0 4px 24px rgba(0, 0, 0, 0.08);
5150
5490
  font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Noto Sans", Helvetica, Arial, sans-serif;
5491
+ transform-origin: top center;
5492
+ transition: transform 0.15s ease;
5493
+ flex-shrink: 0;
5151
5494
  `;
5152
- wrapper.innerHTML = `
5495
+ docCard.innerHTML = `
5153
5496
  <style>
5154
- .fp-markdown-wrapper h1, .fp-markdown-wrapper h2, .fp-markdown-wrapper h3,
5155
- .fp-markdown-wrapper h4, .fp-markdown-wrapper h5, .fp-markdown-wrapper h6 {
5497
+ .fp-markdown-doc-card h1, .fp-markdown-doc-card h2, .fp-markdown-doc-card h3,
5498
+ .fp-markdown-doc-card h4, .fp-markdown-doc-card h5, .fp-markdown-doc-card h6 {
5156
5499
  margin-top: 24px;
5157
5500
  margin-bottom: 16px;
5158
5501
  font-weight: 600;
5159
5502
  line-height: 1.25;
5160
5503
  color: var(--fp-text, #1f2328);
5161
5504
  }
5162
- .fp-markdown-wrapper h1 { font-size: 2em; padding-bottom: 0.3em; border-bottom: 1px solid var(--fp-border, #d0d7de); }
5163
- .fp-markdown-wrapper h2 { font-size: 1.5em; padding-bottom: 0.3em; border-bottom: 1px solid var(--fp-border, #d0d7de); }
5164
- .fp-markdown-wrapper h3 { font-size: 1.25em; }
5165
- .fp-markdown-wrapper p { margin-top: 0; margin-bottom: 16px; }
5166
- .fp-markdown-wrapper table {
5505
+ .fp-markdown-doc-card h1 { font-size: 2em; padding-bottom: 0.3em; border-bottom: 1px solid var(--fp-border, #d0d7de); }
5506
+ .fp-markdown-doc-card h2 { font-size: 1.5em; padding-bottom: 0.3em; border-bottom: 1px solid var(--fp-border, #d0d7de); }
5507
+ .fp-markdown-doc-card h3 { font-size: 1.25em; }
5508
+ .fp-markdown-doc-card p { margin-top: 0; margin-bottom: 16px; }
5509
+ .fp-markdown-doc-card table {
5167
5510
  border-spacing: 0;
5168
5511
  border-collapse: collapse;
5169
5512
  margin-top: 0;
@@ -5171,20 +5514,20 @@ var MarkdownPlugin = class {
5171
5514
  width: 100%;
5172
5515
  overflow: auto;
5173
5516
  }
5174
- .fp-markdown-wrapper table th, .fp-markdown-wrapper table td {
5517
+ .fp-markdown-doc-card table th, .fp-markdown-doc-card table td {
5175
5518
  padding: 6px 13px;
5176
5519
  border: 1px solid var(--fp-border, #d0d7de);
5177
5520
  }
5178
- .fp-markdown-wrapper table tr:nth-child(2n) {
5521
+ .fp-markdown-doc-card table tr:nth-child(2n) {
5179
5522
  background-color: var(--fp-toolbar-bg, #f6f8fa);
5180
5523
  }
5181
- .fp-markdown-wrapper blockquote {
5524
+ .fp-markdown-doc-card blockquote {
5182
5525
  margin: 0 0 16px 0;
5183
5526
  padding: 0 1em;
5184
5527
  color: var(--fp-text-muted, #59636e);
5185
5528
  border-left: 0.25em solid var(--fp-border, #d0d7de);
5186
5529
  }
5187
- .fp-markdown-wrapper pre {
5530
+ .fp-markdown-doc-card pre {
5188
5531
  padding: 16px;
5189
5532
  overflow: auto;
5190
5533
  font-size: 85%;
@@ -5193,7 +5536,7 @@ var MarkdownPlugin = class {
5193
5536
  border-radius: 6px;
5194
5537
  border: 1px solid var(--fp-border, #d0d7de);
5195
5538
  }
5196
- .fp-markdown-wrapper code {
5539
+ .fp-markdown-doc-card code {
5197
5540
  padding: 0.2em 0.4em;
5198
5541
  margin: 0;
5199
5542
  font-size: 85%;
@@ -5201,16 +5544,16 @@ var MarkdownPlugin = class {
5201
5544
  border-radius: 4px;
5202
5545
  font-family: ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, monospace;
5203
5546
  }
5204
- .fp-markdown-wrapper pre code {
5547
+ .fp-markdown-doc-card pre code {
5205
5548
  padding: 0;
5206
5549
  background: transparent;
5207
5550
  }
5208
- .fp-markdown-wrapper ul, .fp-markdown-wrapper ol {
5551
+ .fp-markdown-doc-card ul, .fp-markdown-doc-card ol {
5209
5552
  padding-left: 2em;
5210
5553
  margin-top: 0;
5211
5554
  margin-bottom: 16px;
5212
5555
  }
5213
- .fp-markdown-wrapper hr {
5556
+ .fp-markdown-doc-card hr {
5214
5557
  height: 0.25em;
5215
5558
  padding: 0;
5216
5559
  margin: 24px 0;
@@ -5218,46 +5561,95 @@ var MarkdownPlugin = class {
5218
5561
  border: 0;
5219
5562
  }
5220
5563
  </style>
5221
- <div class="fp-markdown-content" style="max-width: 860px; margin: 0 auto;">
5564
+ <div class="fp-markdown-body">
5222
5565
  ${cleanHtml}
5223
5566
  </div>
5224
5567
  `;
5225
- wrapper.querySelectorAll("pre code").forEach((block) => {
5568
+ docCard.querySelectorAll("pre code").forEach((block) => {
5226
5569
  hljs__default.default.highlightElement(block);
5227
5570
  });
5571
+ sizer.appendChild(docCard);
5572
+ scrollWrapper.appendChild(sizer);
5228
5573
  ctx.container.innerHTML = "";
5229
5574
  ctx.container.style.overflow = "auto";
5230
- ctx.container.appendChild(wrapper);
5231
- let fontSize = 15;
5575
+ ctx.container.style.backgroundColor = "#f1f5f9";
5576
+ ctx.container.appendChild(scrollWrapper);
5577
+ let scale = 1;
5578
+ let isUserZoomed = false;
5579
+ const calculateFitScale = () => {
5580
+ const availW = Math.max(280, ctx.container.clientWidth - 48);
5581
+ if (availW < 860) {
5582
+ return Math.max(0.35, availW / 860);
5583
+ }
5584
+ return 1;
5585
+ };
5586
+ const applyTransform = () => {
5587
+ const baseW = 860;
5588
+ const baseH = docCard.offsetHeight || 600;
5589
+ const scaledW = Math.round(baseW * scale);
5590
+ const scaledH = Math.round(baseH * scale);
5591
+ sizer.style.width = `${scaledW}px`;
5592
+ sizer.style.height = `${scaledH}px`;
5593
+ docCard.style.width = `${baseW}px`;
5594
+ docCard.style.transform = `scale(${scale})`;
5595
+ docCard.style.transformOrigin = scaledW > ctx.container.clientWidth - 32 ? "top left" : "top center";
5596
+ };
5597
+ const ro = typeof ResizeObserver !== "undefined" ? new ResizeObserver(() => {
5598
+ if (!isUserZoomed) {
5599
+ scale = calculateFitScale();
5600
+ applyTransform();
5601
+ }
5602
+ }) : null;
5603
+ ro?.observe(ctx.container);
5604
+ requestAnimationFrame(() => {
5605
+ if (!isUserZoomed) {
5606
+ scale = calculateFitScale();
5607
+ }
5608
+ applyTransform();
5609
+ });
5232
5610
  const cleanup = () => {
5233
- wrapper.remove();
5611
+ ro?.disconnect();
5612
+ scrollWrapper.remove();
5234
5613
  ctx.container.innerHTML = "";
5235
5614
  };
5236
5615
  ctx.signal.addEventListener("abort", cleanup);
5237
5616
  return {
5238
5617
  destroy: cleanup,
5239
5618
  zoomIn: () => {
5240
- fontSize = Math.min(28, fontSize + 2);
5241
- wrapper.style.fontSize = `${fontSize}px`;
5619
+ isUserZoomed = true;
5620
+ scale = Math.min(3.5, scale + 0.15);
5621
+ applyTransform();
5242
5622
  },
5243
5623
  zoomOut: () => {
5244
- fontSize = Math.max(10, fontSize - 2);
5245
- wrapper.style.fontSize = `${fontSize}px`;
5624
+ isUserZoomed = true;
5625
+ scale = Math.max(0.25, scale - 0.15);
5626
+ applyTransform();
5246
5627
  },
5247
- getZoom: () => fontSize / 15,
5628
+ getZoom: () => scale,
5248
5629
  setZoom: (level) => {
5249
- fontSize = Math.round(15 * level);
5250
- wrapper.style.fontSize = `${fontSize}px`;
5630
+ isUserZoomed = true;
5631
+ scale = level;
5632
+ applyTransform();
5251
5633
  },
5252
5634
  fitToPage: () => {
5253
- fontSize = 15;
5254
- wrapper.style.fontSize = "15px";
5635
+ isUserZoomed = false;
5636
+ scale = calculateFitScale();
5637
+ applyTransform();
5638
+ },
5639
+ fitToWidth: () => {
5640
+ isUserZoomed = false;
5641
+ scale = calculateFitScale();
5642
+ applyTransform();
5255
5643
  },
5256
5644
  resetZoom: () => {
5257
- fontSize = 15;
5258
- wrapper.style.fontSize = "15px";
5645
+ isUserZoomed = false;
5646
+ scale = calculateFitScale();
5259
5647
  ctx.container.scrollTop = 0;
5260
5648
  ctx.container.scrollLeft = 0;
5649
+ applyTransform();
5650
+ },
5651
+ openInSeparateWindow: () => {
5652
+ ctx?.openInSeparateWindow?.();
5261
5653
  },
5262
5654
  download: () => {
5263
5655
  downloadFile(ctx.buffer, ctx.metadata.name || "document.md", "text/markdown");
@@ -5360,6 +5752,14 @@ var PptxPlugin = class {
5360
5752
  group: "zoom",
5361
5753
  execute: () => instance.resetZoom?.()
5362
5754
  },
5755
+ {
5756
+ id: "fit-width",
5757
+ icon: "fit-width",
5758
+ label: "Fit to Width",
5759
+ type: "button",
5760
+ group: "zoom",
5761
+ execute: () => instance.fitToWidth?.()
5762
+ },
5363
5763
  {
5364
5764
  id: "rotate-cw",
5365
5765
  icon: "rotate-cw",
@@ -5443,12 +5843,17 @@ var PptxPlugin = class {
5443
5843
  ctx.container.innerHTML = "";
5444
5844
  ctx.container.style.overflow = "auto";
5445
5845
  ctx.container.appendChild(wrapper);
5446
- const calculateFitScale = () => {
5447
- const availW = Math.max(200, ctx.container.clientWidth - 48);
5448
- const availH = Math.max(200, ctx.container.clientHeight - 72);
5846
+ let fitMode = ctx?.options?.fitMode || "width";
5847
+ let isUserZoomed = false;
5848
+ const calculateFitScale = (mode = fitMode) => {
5849
+ const availW = Math.max(200, ctx.container.clientWidth - 32);
5850
+ const availH = Math.max(200, ctx.container.clientHeight - 32);
5449
5851
  const cW = canvas.offsetWidth || 1280;
5450
5852
  const cH = canvas.offsetHeight || 720;
5451
- return Math.min(1, Math.min(availW / cW, availH / cH));
5853
+ if (mode === "page") {
5854
+ return Math.min(2.5, Math.min(availW / cW, availH / cH));
5855
+ }
5856
+ return Math.min(2.5, availW / cW);
5452
5857
  };
5453
5858
  const applyTransform = () => {
5454
5859
  const cW = canvas.offsetWidth || 1280;
@@ -5467,14 +5872,24 @@ var PptxPlugin = class {
5467
5872
  try {
5468
5873
  await renderer.renderSlide(currentSlide - 1, canvas, 1280);
5469
5874
  ctx.emit("page-change", { page: currentSlide, totalPages: slideCount });
5470
- scale = calculateFitScale();
5875
+ if (!isUserZoomed) {
5876
+ scale = calculateFitScale(fitMode);
5877
+ }
5471
5878
  applyTransform();
5472
5879
  } catch (err) {
5473
5880
  console.error("[PptxPlugin] Failed to render slide:", err);
5474
5881
  }
5475
5882
  };
5476
5883
  await renderCurrentSlide();
5884
+ const ro = typeof ResizeObserver !== "undefined" ? new ResizeObserver(() => {
5885
+ if (!isUserZoomed) {
5886
+ scale = calculateFitScale(fitMode);
5887
+ applyTransform();
5888
+ }
5889
+ }) : null;
5890
+ ro?.observe(ctx.container);
5477
5891
  const cleanup = () => {
5892
+ ro?.disconnect();
5478
5893
  renderer.destroy();
5479
5894
  wrapper.remove();
5480
5895
  ctx.container.innerHTML = "";
@@ -5491,28 +5906,44 @@ var PptxPlugin = class {
5491
5906
  getPageCount: () => slideCount,
5492
5907
  getCurrentPage: () => currentSlide,
5493
5908
  zoomIn: () => {
5909
+ isUserZoomed = true;
5494
5910
  scale += 0.15;
5495
5911
  applyTransform();
5496
5912
  },
5497
5913
  zoomOut: () => {
5914
+ isUserZoomed = true;
5498
5915
  scale = Math.max(0.2, scale - 0.15);
5499
5916
  applyTransform();
5500
5917
  },
5501
5918
  getZoom: () => scale,
5502
5919
  setZoom: (level) => {
5920
+ isUserZoomed = true;
5503
5921
  scale = level;
5504
5922
  applyTransform();
5505
5923
  },
5506
5924
  fitToPage: () => {
5507
- scale = calculateFitScale();
5925
+ isUserZoomed = false;
5926
+ fitMode = "page";
5927
+ scale = calculateFitScale("page");
5928
+ rotation = 0;
5929
+ applyTransform();
5930
+ },
5931
+ fitToWidth: () => {
5932
+ isUserZoomed = false;
5933
+ fitMode = "width";
5934
+ scale = calculateFitScale("width");
5508
5935
  rotation = 0;
5509
5936
  applyTransform();
5510
5937
  },
5511
5938
  resetZoom: () => {
5512
- scale = calculateFitScale();
5939
+ isUserZoomed = false;
5940
+ fitMode = ctx?.options?.fitMode || "width";
5941
+ scale = calculateFitScale(fitMode);
5513
5942
  rotation = 0;
5514
5943
  wrapper.scrollTop = 0;
5515
5944
  wrapper.scrollLeft = 0;
5945
+ ctx.container.scrollTop = 0;
5946
+ ctx.container.scrollLeft = 0;
5516
5947
  applyTransform();
5517
5948
  },
5518
5949
  rotateCW: () => {
@@ -5957,6 +6388,14 @@ var RtfPlugin = class {
5957
6388
  group: "zoom",
5958
6389
  execute: () => instance.resetZoom?.()
5959
6390
  },
6391
+ {
6392
+ id: "fit-width",
6393
+ icon: "fit-width",
6394
+ label: "Fit to Width",
6395
+ type: "button",
6396
+ group: "zoom",
6397
+ execute: () => instance.fitToWidth?.()
6398
+ },
5960
6399
  {
5961
6400
  id: "rotate-cw",
5962
6401
  icon: "rotate-cw",
@@ -6445,6 +6884,13 @@ var RtfPlugin = class {
6445
6884
  applyTransform();
6446
6885
  },
6447
6886
  fitToPage: () => {
6887
+ isUserZoomed = false;
6888
+ fitMode = "page";
6889
+ scale = calculateFitScale("page");
6890
+ rotation = 0;
6891
+ applyTransform();
6892
+ },
6893
+ fitToWidth: () => {
6448
6894
  isUserZoomed = false;
6449
6895
  fitMode = "width";
6450
6896
  scale = calculateFitScale("width");
@@ -6453,8 +6899,8 @@ var RtfPlugin = class {
6453
6899
  },
6454
6900
  resetZoom: () => {
6455
6901
  isUserZoomed = false;
6456
- fitMode = "width";
6457
- scale = calculateFitScale("width");
6902
+ fitMode = ctx?.options?.fitMode || "width";
6903
+ scale = calculateFitScale(fitMode);
6458
6904
  rotation = 0;
6459
6905
  ctx.container.scrollTop = 0;
6460
6906
  ctx.container.scrollLeft = 0;
@@ -6519,14 +6965,6 @@ var HtmlPreviewPlugin = class {
6519
6965
  group: "zoom",
6520
6966
  execute: () => instance.zoomIn?.()
6521
6967
  },
6522
- {
6523
- id: "fit-page",
6524
- icon: "fit-page",
6525
- label: "Fit to Page",
6526
- type: "button",
6527
- group: "zoom",
6528
- execute: () => instance.fitToPage?.()
6529
- },
6530
6968
  {
6531
6969
  id: "reset-zoom",
6532
6970
  icon: "reset-zoom",
@@ -6535,6 +6973,22 @@ var HtmlPreviewPlugin = class {
6535
6973
  group: "zoom",
6536
6974
  execute: () => instance.resetZoom?.()
6537
6975
  },
6976
+ {
6977
+ id: "fit-width",
6978
+ icon: "fit-width",
6979
+ label: "Fit to Width",
6980
+ type: "button",
6981
+ group: "zoom",
6982
+ execute: () => instance.fitToWidth?.()
6983
+ },
6984
+ {
6985
+ id: "fit-page",
6986
+ icon: "fit-page",
6987
+ label: "Fit to Page",
6988
+ type: "button",
6989
+ group: "zoom",
6990
+ execute: () => instance.fitToPage?.()
6991
+ },
6538
6992
  {
6539
6993
  id: "copy",
6540
6994
  icon: "copy",
@@ -6558,6 +7012,14 @@ var HtmlPreviewPlugin = class {
6558
7012
  type: "button",
6559
7013
  group: "actions",
6560
7014
  execute: () => instance.print?.()
7015
+ },
7016
+ {
7017
+ id: "open-window",
7018
+ icon: "open-window",
7019
+ label: "Open in Separate Full Window",
7020
+ type: "button",
7021
+ group: "actions",
7022
+ execute: () => instance.openInSeparateWindow?.()
6561
7023
  }
6562
7024
  ];
6563
7025
  }
@@ -6568,27 +7030,39 @@ var HtmlPreviewPlugin = class {
6568
7030
  ADD_TAGS: ["style", "link"],
6569
7031
  ADD_ATTR: ["target", "rel"]
6570
7032
  });
7033
+ const scrollWrapper = document.createElement("div");
7034
+ scrollWrapper.className = "fp-html-scroll-wrapper";
7035
+ scrollWrapper.style.minWidth = "100%";
7036
+ scrollWrapper.style.minHeight = "100%";
7037
+ scrollWrapper.style.width = "max-content";
7038
+ scrollWrapper.style.height = "max-content";
7039
+ scrollWrapper.style.display = "flex";
7040
+ scrollWrapper.style.justifyContent = "flex-start";
7041
+ scrollWrapper.style.alignItems = "flex-start";
7042
+ scrollWrapper.style.boxSizing = "border-box";
6571
7043
  const sizer = document.createElement("div");
6572
7044
  sizer.className = "fp-html-sizer";
6573
7045
  sizer.style.position = "relative";
7046
+ sizer.style.flexShrink = "0";
6574
7047
  const iframe = document.createElement("iframe");
6575
7048
  iframe.className = "fp-html-iframe";
6576
7049
  iframe.style.border = "none";
6577
7050
  iframe.style.backgroundColor = "#ffffff";
6578
7051
  iframe.style.transformOrigin = "top left";
6579
- iframe.style.transition = "transform 0.2s ease";
7052
+ iframe.style.transition = "transform 0.15s ease";
6580
7053
  iframe.sandbox.add("allow-same-origin");
6581
7054
  sizer.appendChild(iframe);
7055
+ scrollWrapper.appendChild(sizer);
6582
7056
  ctx.container.style.overflow = "auto";
6583
7057
  ctx.container.style.width = "100%";
6584
7058
  ctx.container.style.height = "100%";
6585
7059
  ctx.container.innerHTML = "";
6586
- ctx.container.appendChild(sizer);
7060
+ ctx.container.appendChild(scrollWrapper);
6587
7061
  iframe.srcdoc = sanitized;
6588
7062
  let scale = 1;
7063
+ let baseW = Math.max(600, ctx.container.clientWidth || 800);
7064
+ let baseH = Math.max(400, ctx.container.clientHeight || 600);
6589
7065
  const applyTransform = () => {
6590
- const baseW = Math.max(600, ctx.container.clientWidth || 800);
6591
- const baseH = Math.max(400, ctx.container.clientHeight || 600);
6592
7066
  const scaledW = Math.round(baseW * scale);
6593
7067
  const scaledH = Math.round(baseH * scale);
6594
7068
  sizer.style.width = `${scaledW}px`;
@@ -6601,22 +7075,33 @@ var HtmlPreviewPlugin = class {
6601
7075
  iframe.style.transform = `scale(${scale})`;
6602
7076
  iframe.style.transformOrigin = "top left";
6603
7077
  };
7078
+ const ro = typeof ResizeObserver !== "undefined" ? new ResizeObserver(() => {
7079
+ if (Math.abs(scale - 1) < 0.05) {
7080
+ baseW = Math.max(600, ctx.container.clientWidth || 800);
7081
+ baseH = Math.max(400, ctx.container.clientHeight || 600);
7082
+ applyTransform();
7083
+ }
7084
+ }) : null;
7085
+ ro?.observe(ctx.container);
6604
7086
  requestAnimationFrame(() => {
7087
+ baseW = Math.max(600, ctx.container.clientWidth || 800);
7088
+ baseH = Math.max(400, ctx.container.clientHeight || 600);
6605
7089
  applyTransform();
6606
7090
  });
6607
7091
  const cleanup = () => {
6608
- sizer.remove();
7092
+ ro?.disconnect();
7093
+ scrollWrapper.remove();
6609
7094
  ctx.container.innerHTML = "";
6610
7095
  };
6611
7096
  ctx.signal.addEventListener("abort", cleanup);
6612
7097
  return {
6613
7098
  destroy: cleanup,
6614
7099
  zoomIn: () => {
6615
- scale += 0.1;
7100
+ scale = Math.min(3.5, scale + 0.15);
6616
7101
  applyTransform();
6617
7102
  },
6618
7103
  zoomOut: () => {
6619
- scale = Math.max(0.2, scale - 0.1);
7104
+ scale = Math.max(0.25, scale - 0.15);
6620
7105
  applyTransform();
6621
7106
  },
6622
7107
  getZoom: () => scale,
@@ -6628,14 +7113,21 @@ var HtmlPreviewPlugin = class {
6628
7113
  scale = 1;
6629
7114
  applyTransform();
6630
7115
  },
7116
+ fitToWidth: () => {
7117
+ scale = 1;
7118
+ applyTransform();
7119
+ },
6631
7120
  resetZoom: () => {
6632
7121
  scale = 1;
6633
7122
  ctx.container.scrollTop = 0;
6634
7123
  ctx.container.scrollLeft = 0;
6635
7124
  applyTransform();
6636
7125
  },
7126
+ openInSeparateWindow: () => {
7127
+ ctx?.openInSeparateWindow?.();
7128
+ },
6637
7129
  copy: () => {
6638
- navigator.clipboard.writeText(rawHtml);
7130
+ navigator.clipboard?.writeText(rawHtml);
6639
7131
  },
6640
7132
  download: () => {
6641
7133
  const blob = new Blob([ctx.buffer], { type: "text/html" });
@@ -6742,6 +7234,14 @@ var OpenDocumentPlugin = class {
6742
7234
  group: "zoom",
6743
7235
  execute: () => instance.resetZoom?.()
6744
7236
  },
7237
+ {
7238
+ id: "fit-width",
7239
+ icon: "fit-width",
7240
+ label: "Fit to Width",
7241
+ type: "button",
7242
+ group: "zoom",
7243
+ execute: () => instance.fitToWidth?.()
7244
+ },
6745
7245
  {
6746
7246
  id: "rotate-cw",
6747
7247
  icon: "rotate-cw",
@@ -6858,7 +7358,10 @@ var OpenDocumentPlugin = class {
6858
7358
  const sW = availW / elW;
6859
7359
  const sH = availH / (isPresentation ? 540 : singlePageH);
6860
7360
  if (isPresentation) {
6861
- return Math.min(2.5, Math.min(sW, sH));
7361
+ if (mode === "page") {
7362
+ return Math.min(2.5, Math.min(sW, sH));
7363
+ }
7364
+ return Math.min(2.5, sW);
6862
7365
  }
6863
7366
  if (mode === "page") {
6864
7367
  return Math.max(0.35, Math.min(3, Math.min(sW, sH)));
@@ -7027,6 +7530,13 @@ var OpenDocumentPlugin = class {
7027
7530
  applyTransform();
7028
7531
  },
7029
7532
  fitToPage: () => {
7533
+ isUserZoomed = false;
7534
+ fitMode = "page";
7535
+ scale = calculateFitScale("page");
7536
+ rotation = 0;
7537
+ applyTransform();
7538
+ },
7539
+ fitToWidth: () => {
7030
7540
  isUserZoomed = false;
7031
7541
  fitMode = "width";
7032
7542
  scale = calculateFitScale("width");
@@ -7035,8 +7545,8 @@ var OpenDocumentPlugin = class {
7035
7545
  },
7036
7546
  resetZoom: () => {
7037
7547
  isUserZoomed = false;
7038
- fitMode = "width";
7039
- scale = calculateFitScale("width");
7548
+ fitMode = ctx?.options?.fitMode || "width";
7549
+ scale = calculateFitScale(fitMode);
7040
7550
  rotation = 0;
7041
7551
  container.scrollTop = 0;
7042
7552
  container.scrollLeft = 0;
@@ -7393,6 +7903,14 @@ var DocPlugin = class {
7393
7903
  group: "zoom",
7394
7904
  execute: () => instance.resetZoom?.()
7395
7905
  },
7906
+ {
7907
+ id: "fit-width",
7908
+ icon: "fit-width",
7909
+ label: "Fit to Width",
7910
+ type: "button",
7911
+ group: "zoom",
7912
+ execute: () => instance.fitToWidth?.()
7913
+ },
7396
7914
  {
7397
7915
  id: "rotate-cw",
7398
7916
  icon: "rotate-cw",
@@ -7614,6 +8132,13 @@ var DocPlugin = class {
7614
8132
  applyTransform();
7615
8133
  },
7616
8134
  fitToPage: () => {
8135
+ isUserZoomed = false;
8136
+ fitMode = "page";
8137
+ scale = calculateFitScale("page");
8138
+ rotation = 0;
8139
+ applyTransform();
8140
+ },
8141
+ fitToWidth: () => {
7617
8142
  isUserZoomed = false;
7618
8143
  fitMode = "width";
7619
8144
  scale = calculateFitScale("width");
@@ -7622,8 +8147,8 @@ var DocPlugin = class {
7622
8147
  },
7623
8148
  resetZoom: () => {
7624
8149
  isUserZoomed = false;
7625
- fitMode = "width";
7626
- scale = calculateFitScale("width");
8150
+ fitMode = ctx?.options?.fitMode || "width";
8151
+ scale = calculateFitScale(fitMode);
7627
8152
  rotation = 0;
7628
8153
  container.scrollTop = 0;
7629
8154
  container.scrollLeft = 0;
@@ -8119,6 +8644,14 @@ var PptPlugin = class {
8119
8644
  group: "zoom",
8120
8645
  execute: () => instance.resetZoom?.()
8121
8646
  },
8647
+ {
8648
+ id: "fit-width",
8649
+ icon: "fit-width",
8650
+ label: "Fit to Width",
8651
+ type: "button",
8652
+ group: "zoom",
8653
+ execute: () => instance.fitToWidth?.()
8654
+ },
8122
8655
  {
8123
8656
  id: "rotate-cw",
8124
8657
  icon: "rotate-cw",
@@ -8193,10 +8726,15 @@ var PptPlugin = class {
8193
8726
  let currentSlide = 1;
8194
8727
  let slides = [];
8195
8728
  const createdBlobUrls = [];
8196
- const calculateFitScale = () => {
8197
- const availW = Math.max(200, container.clientWidth - 48);
8198
- const availH = Math.max(200, container.clientHeight - 72);
8199
- return Math.min(1, Math.min(availW / 960, availH / 540));
8729
+ let fitMode = ctx?.options?.fitMode || "width";
8730
+ let isUserZoomed = false;
8731
+ const calculateFitScale = (mode = fitMode) => {
8732
+ const availW = Math.max(200, container.clientWidth - 32);
8733
+ const availH = Math.max(200, container.clientHeight - 32);
8734
+ if (mode === "page") {
8735
+ return Math.min(2.5, Math.min(availW / 960, availH / 540));
8736
+ }
8737
+ return Math.min(2.5, availW / 960);
8200
8738
  };
8201
8739
  const applyTransform = () => {
8202
8740
  const cW = 960;
@@ -8211,8 +8749,15 @@ var PptPlugin = class {
8211
8749
  slideCard.style.transform = `scale(${scale}) rotate(${rotation}deg)`;
8212
8750
  slideCard.style.transformOrigin = "center center";
8213
8751
  };
8752
+ const ro = typeof ResizeObserver !== "undefined" ? new ResizeObserver(() => {
8753
+ if (!isUserZoomed) {
8754
+ scale = calculateFitScale(fitMode);
8755
+ applyTransform();
8756
+ }
8757
+ }) : null;
8758
+ ro?.observe(container);
8214
8759
  setTimeout(() => {
8215
- scale = calculateFitScale();
8760
+ scale = calculateFitScale(fitMode);
8216
8761
  applyTransform();
8217
8762
  }, 60);
8218
8763
  try {
@@ -8305,6 +8850,7 @@ var PptPlugin = class {
8305
8850
  };
8306
8851
  renderSlide(1);
8307
8852
  const cleanup = () => {
8853
+ ro?.disconnect();
8308
8854
  for (const u of createdBlobUrls) {
8309
8855
  URL.revokeObjectURL(u);
8310
8856
  }
@@ -8315,28 +8861,44 @@ var PptPlugin = class {
8315
8861
  return {
8316
8862
  destroy: cleanup,
8317
8863
  zoomIn: () => {
8864
+ isUserZoomed = true;
8318
8865
  scale += 0.15;
8319
8866
  applyTransform();
8320
8867
  },
8321
8868
  zoomOut: () => {
8869
+ isUserZoomed = true;
8322
8870
  scale = Math.max(0.2, scale - 0.15);
8323
8871
  applyTransform();
8324
8872
  },
8325
8873
  getZoom: () => scale,
8326
8874
  setZoom: (level) => {
8875
+ isUserZoomed = true;
8327
8876
  scale = level;
8328
8877
  applyTransform();
8329
8878
  },
8330
8879
  fitToPage: () => {
8331
- scale = calculateFitScale();
8880
+ isUserZoomed = false;
8881
+ fitMode = "page";
8882
+ scale = calculateFitScale("page");
8883
+ rotation = 0;
8884
+ applyTransform();
8885
+ },
8886
+ fitToWidth: () => {
8887
+ isUserZoomed = false;
8888
+ fitMode = "width";
8889
+ scale = calculateFitScale("width");
8332
8890
  rotation = 0;
8333
8891
  applyTransform();
8334
8892
  },
8335
8893
  resetZoom: () => {
8336
- scale = calculateFitScale();
8894
+ isUserZoomed = false;
8895
+ fitMode = ctx?.options?.fitMode || "width";
8896
+ scale = calculateFitScale(fitMode);
8337
8897
  rotation = 0;
8338
8898
  container.scrollTop = 0;
8339
8899
  container.scrollLeft = 0;
8900
+ ctx.container.scrollTop = 0;
8901
+ ctx.container.scrollLeft = 0;
8340
8902
  applyTransform();
8341
8903
  },
8342
8904
  rotateCW: () => {
@@ -8627,7 +9189,7 @@ _FilePreviewComponent_decorators = [core.Component({
8627
9189
  selector: "fp-file-preview",
8628
9190
  standalone: true,
8629
9191
  imports: [common.CommonModule],
8630
- template: `<div #container [style.width]="'100%'" [style.height]="'100%'"></div>`,
9192
+ template: `<div #container [style.width]="'100%'" [style.height]="'100%'" [style.position]="'relative'" [style.overflow]="'hidden'"></div>`,
8631
9193
  changeDetection: core.ChangeDetectionStrategy.OnPush
8632
9194
  })], _src_dec = [core.Input({ required: true })], _plugins_dec = [core.Input()], _options_dec = [core.Input()], _loading_dec = [core.Output()], _loaded_dec = [core.Output()], _error_dec = [core.Output()], _pageChange_dec = [core.Output()], _zoomChange_dec = [core.Output()], _rotate_dec = [core.Output()], _destroyed_dec = [core.Output()], _container_dec = [core.ViewChild("container", { static: true })];
8633
9195
  exports.FilePreviewComponent = class FilePreviewComponent {