@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.js CHANGED
@@ -1104,6 +1104,10 @@ var FilePreviewViewer = class _FilePreviewViewer {
1104
1104
  * Preview a file in the given container element.
1105
1105
  */
1106
1106
  async preview(container, source, options = {}) {
1107
+ options = {
1108
+ ...options,
1109
+ fitMode: options.fitMode ?? "width"
1110
+ };
1107
1111
  this.currentOptions = options;
1108
1112
  this.abort();
1109
1113
  this.abortController = new AbortController();
@@ -1152,8 +1156,8 @@ var FilePreviewViewer = class _FilePreviewViewer {
1152
1156
  this.activeInstance = instance;
1153
1157
  instance.openInSeparateWindow = () => this.openInSeparateWindow();
1154
1158
  instance.toggleThumbnails = () => this.toggleThumbnails();
1155
- if (!instance.resetZoom && instance.fitToPage) {
1156
- instance.resetZoom = () => instance.fitToPage?.();
1159
+ if (!instance.resetZoom) {
1160
+ instance.resetZoom = () => instance.fitToWidth ? instance.fitToWidth() : instance.fitToPage?.();
1157
1161
  }
1158
1162
  this.hideLoading();
1159
1163
  this.eventEmitter.emit("loaded", { metadata, plugin: matchedPlugin.id });
@@ -1550,7 +1554,7 @@ var FilePreviewViewer = class _FilePreviewViewer {
1550
1554
  this.wrapperEl?.classList.toggle("fp-fullscreen-active");
1551
1555
  }
1552
1556
  setTimeout(() => {
1553
- this.activeInstance?.fitToPage?.();
1557
+ this.triggerAutoFit();
1554
1558
  }, 120);
1555
1559
  }
1556
1560
  /**
@@ -1642,19 +1646,85 @@ var FilePreviewViewer = class _FilePreviewViewer {
1642
1646
  if (this.wrapperEl?.parentNode) {
1643
1647
  this.wrapperEl.parentNode.removeChild(this.wrapperEl);
1644
1648
  }
1649
+ if (typeof document !== "undefined" && !document.getElementById("fp-core-injected-styles")) {
1650
+ const styleEl = document.createElement("style");
1651
+ styleEl.id = "fp-core-injected-styles";
1652
+ styleEl.textContent = `
1653
+ .fp-viewer {
1654
+ display: flex !important;
1655
+ flex-direction: column !important;
1656
+ width: 100% !important;
1657
+ height: 100% !important;
1658
+ overflow: hidden !important;
1659
+ position: relative !important;
1660
+ box-sizing: border-box !important;
1661
+ }
1662
+ .fp-body {
1663
+ display: flex !important;
1664
+ flex: 1 1 0% !important;
1665
+ min-height: 0 !important;
1666
+ min-width: 0 !important;
1667
+ width: 100% !important;
1668
+ height: 100% !important;
1669
+ overflow: hidden !important;
1670
+ position: relative !important;
1671
+ box-sizing: border-box !important;
1672
+ }
1673
+ .fp-content {
1674
+ flex: 1 1 0% !important;
1675
+ position: relative !important;
1676
+ overflow: auto !important;
1677
+ display: flex !important;
1678
+ flex-direction: column !important;
1679
+ align-items: stretch !important;
1680
+ justify-content: flex-start !important;
1681
+ width: 100% !important;
1682
+ height: 100% !important;
1683
+ min-width: 0 !important;
1684
+ min-height: 0 !important;
1685
+ box-sizing: border-box !important;
1686
+ }
1687
+ `;
1688
+ document.head.appendChild(styleEl);
1689
+ }
1645
1690
  const themeClass = options.theme === "dark" ? "fp-theme-dark" : "";
1646
1691
  const toolbarPos = options.toolbarPosition ?? "top";
1647
1692
  this.wrapperEl = document.createElement("div");
1648
1693
  this.wrapperEl.className = `fp-viewer ${themeClass} ${options.className ?? ""}`.trim();
1649
1694
  this.wrapperEl.tabIndex = 0;
1695
+ this.wrapperEl.style.display = "flex";
1696
+ this.wrapperEl.style.flexDirection = "column";
1697
+ this.wrapperEl.style.width = "100%";
1698
+ this.wrapperEl.style.height = "100%";
1699
+ this.wrapperEl.style.overflow = "hidden";
1700
+ this.wrapperEl.style.position = "relative";
1650
1701
  const toolbarEl = document.createElement("div");
1651
1702
  toolbarEl.className = "fp-toolbar-container";
1652
1703
  this.contentEl = document.createElement("div");
1653
1704
  this.contentEl.className = "fp-content";
1705
+ this.contentEl.style.flex = "1 1 0%";
1706
+ this.contentEl.style.position = "relative";
1707
+ this.contentEl.style.overflow = "auto";
1708
+ this.contentEl.style.display = "flex";
1709
+ this.contentEl.style.flexDirection = "column";
1710
+ this.contentEl.style.alignItems = "stretch";
1711
+ this.contentEl.style.justifyContent = "flex-start";
1712
+ this.contentEl.style.width = "100%";
1713
+ this.contentEl.style.height = "100%";
1714
+ this.contentEl.style.minWidth = "0";
1715
+ this.contentEl.style.minHeight = "0";
1716
+ this.contentEl.style.boxSizing = "border-box";
1654
1717
  const thumbnailEl = document.createElement("div");
1655
1718
  thumbnailEl.className = "fp-thumbnail-container";
1656
1719
  const bodyEl = document.createElement("div");
1657
1720
  bodyEl.className = "fp-body";
1721
+ bodyEl.style.display = "flex";
1722
+ bodyEl.style.flex = "1 1 0%";
1723
+ bodyEl.style.minHeight = "0";
1724
+ bodyEl.style.minWidth = "0";
1725
+ bodyEl.style.width = "100%";
1726
+ bodyEl.style.overflow = "hidden";
1727
+ bodyEl.style.position = "relative";
1658
1728
  bodyEl.appendChild(thumbnailEl);
1659
1729
  bodyEl.appendChild(this.contentEl);
1660
1730
  const titleBarEl = document.createElement("div");
@@ -1677,18 +1747,29 @@ var FilePreviewViewer = class _FilePreviewViewer {
1677
1747
  this.thumbnailPanel = new ThumbnailPanel(thumbnailEl, (isOpen) => {
1678
1748
  this.toolbar?.setActionActive("thumbnails", isOpen);
1679
1749
  setTimeout(() => {
1680
- this.activeInstance?.fitToPage?.();
1750
+ this.triggerAutoFit();
1681
1751
  }, 260);
1682
1752
  });
1683
1753
  this.setupKeyboardShortcuts();
1684
1754
  this.setupDragAndDrop(container, options);
1685
1755
  this.setupResizeAndFullscreenListeners();
1686
1756
  }
1757
+ triggerAutoFit() {
1758
+ if (!this.activeInstance) return;
1759
+ const mode = this.currentOptions?.fitMode ?? "width";
1760
+ if (mode === "width" && this.activeInstance.fitToWidth) {
1761
+ this.activeInstance.fitToWidth();
1762
+ } else if (this.activeInstance.fitToPage) {
1763
+ this.activeInstance.fitToPage();
1764
+ } else if (this.activeInstance.resetZoom) {
1765
+ this.activeInstance.resetZoom();
1766
+ }
1767
+ }
1687
1768
  setupResizeAndFullscreenListeners() {
1688
1769
  if (this.fullscreenHandler) return;
1689
1770
  this.fullscreenHandler = () => {
1690
1771
  setTimeout(() => {
1691
- this.activeInstance?.fitToPage?.();
1772
+ this.triggerAutoFit();
1692
1773
  }, 100);
1693
1774
  };
1694
1775
  document.addEventListener("fullscreenchange", this.fullscreenHandler);
@@ -1696,7 +1777,7 @@ var FilePreviewViewer = class _FilePreviewViewer {
1696
1777
  if (typeof ResizeObserver !== "undefined" && this.contentEl) {
1697
1778
  this.resizeObserver = new ResizeObserver(() => {
1698
1779
  if (this.activeInstance && (!this.activeInstance.getZoom || Math.abs((this.activeInstance.getZoom?.() ?? 1) - 1) < 0.05)) {
1699
- this.activeInstance.fitToPage?.();
1780
+ this.triggerAutoFit();
1700
1781
  }
1701
1782
  });
1702
1783
  this.resizeObserver.observe(this.contentEl);
@@ -1724,7 +1805,7 @@ var FilePreviewViewer = class _FilePreviewViewer {
1724
1805
  } else if (e.key === "-" || e.key === "_") {
1725
1806
  this.activeInstance.zoomOut?.();
1726
1807
  } else if (e.key === "0") {
1727
- this.activeInstance.fitToPage?.();
1808
+ this.resetZoom();
1728
1809
  } else if (e.key === "r" || e.key === "R") {
1729
1810
  this.activeInstance.rotateCW?.();
1730
1811
  } else if (e.key === "f" || e.key === "F") {
@@ -2347,7 +2428,7 @@ var PdfPlugin = class {
2347
2428
  renderPage(currentPage);
2348
2429
  },
2349
2430
  resetZoom: () => {
2350
- fitMode = "page";
2431
+ fitMode = ctx?.options?.fitMode || "width";
2351
2432
  zoomScale = 1;
2352
2433
  rotation = 0;
2353
2434
  container.scrollTop = 0;
@@ -2531,6 +2612,16 @@ var MediaPlugin = class {
2531
2612
  instance.resetZoom?.();
2532
2613
  }
2533
2614
  },
2615
+ {
2616
+ id: "fit-width",
2617
+ icon: "fit-width",
2618
+ label: "Fit to Width",
2619
+ type: "button",
2620
+ group: "zoom",
2621
+ execute: () => {
2622
+ instance.fitToWidth?.();
2623
+ }
2624
+ },
2534
2625
  {
2535
2626
  id: "rotate-cw",
2536
2627
  icon: "rotate-cw",
@@ -2627,9 +2718,30 @@ var MediaPlugin = class {
2627
2718
  const isVideo = mimeType.startsWith("video/") || VIDEO_EXTS.includes(ctx.metadata.extension || "");
2628
2719
  const isAudio = mimeType.startsWith("audio/") || AUDIO_EXTS.includes(ctx.metadata.extension || "");
2629
2720
  let url = "";
2721
+ let naturalW = 800;
2722
+ let naturalH = 600;
2630
2723
  if (ctx.metadata.extension === ".svg" || mimeType === "image/svg+xml") {
2631
2724
  const decoder = new TextDecoder("utf-8");
2632
2725
  const svgText = decoder.decode(ctx.buffer);
2726
+ try {
2727
+ const vbMatch = svgText.match(/viewBox=["']\s*([0-9.-]+)\s+([0-9.-]+)\s+([0-9.-]+)\s+([0-9.-]+)\s*["']/i);
2728
+ if (vbMatch) {
2729
+ const vw = parseFloat(vbMatch[3]);
2730
+ const vh = parseFloat(vbMatch[4]);
2731
+ if (vw > 0 && vh > 0) {
2732
+ naturalW = vw;
2733
+ naturalH = vh;
2734
+ }
2735
+ } else {
2736
+ const wMatch = svgText.match(/width=["']([0-9.]+)(?:px)?["']/i);
2737
+ const hMatch = svgText.match(/height=["']([0-9.]+)(?:px)?["']/i);
2738
+ if (wMatch && hMatch) {
2739
+ naturalW = parseFloat(wMatch[1]) || naturalW;
2740
+ naturalH = parseFloat(hMatch[1]) || naturalH;
2741
+ }
2742
+ }
2743
+ } catch {
2744
+ }
2633
2745
  const blob = new Blob([svgText], { type: "image/svg+xml" });
2634
2746
  url = URL.createObjectURL(blob);
2635
2747
  } else {
@@ -2677,7 +2789,7 @@ var MediaPlugin = class {
2677
2789
  scrollWrapper.style.width = "max-content";
2678
2790
  scrollWrapper.style.height = "max-content";
2679
2791
  scrollWrapper.style.display = "flex";
2680
- scrollWrapper.style.justifyContent = "center";
2792
+ scrollWrapper.style.flexDirection = "column";
2681
2793
  scrollWrapper.style.alignItems = "center";
2682
2794
  scrollWrapper.style.padding = "16px";
2683
2795
  scrollWrapper.style.boxSizing = "border-box";
@@ -2688,40 +2800,54 @@ var MediaPlugin = class {
2688
2800
  sizer.style.display = "flex";
2689
2801
  sizer.style.justifyContent = "center";
2690
2802
  sizer.style.alignItems = "center";
2803
+ sizer.style.margin = "auto 0";
2691
2804
  sizer.appendChild(element);
2692
2805
  scrollWrapper.appendChild(sizer);
2693
2806
  ctx.container.style.overflow = "auto";
2694
2807
  ctx.container.style.padding = "0";
2695
2808
  ctx.container.innerHTML = "";
2696
2809
  ctx.container.appendChild(scrollWrapper);
2697
- let naturalW = 800;
2698
- let naturalH = 600;
2699
- let baseW = 800;
2700
- let baseH = 600;
2810
+ let baseW = naturalW;
2811
+ let baseH = naturalH;
2812
+ let fitMode = ctx?.options?.fitMode || "width";
2813
+ let isUserZoomed = false;
2701
2814
  const updateBaseDimensions = () => {
2702
2815
  if (!isImage) return;
2703
2816
  const img = element;
2704
- naturalW = img.naturalWidth || naturalW;
2705
- naturalH = img.naturalHeight || naturalH;
2706
- const availW = Math.max(100, ctx.container.clientWidth - 48);
2707
- const availH = Math.max(100, ctx.container.clientHeight - 48);
2708
- const fitRatio = Math.min(1, availW / naturalW, availH / naturalH);
2817
+ if (img.naturalWidth > 0 && img.naturalHeight > 0) {
2818
+ naturalW = img.naturalWidth;
2819
+ naturalH = img.naturalHeight;
2820
+ }
2821
+ const availW = Math.max(100, ctx.container.clientWidth - 32);
2822
+ const availH = Math.max(100, ctx.container.clientHeight - 32);
2823
+ let fitRatio;
2824
+ if (fitMode === "page") {
2825
+ fitRatio = Math.min(availW / naturalW, availH / naturalH);
2826
+ } else {
2827
+ fitRatio = availW / naturalW;
2828
+ }
2709
2829
  baseW = Math.max(1, Math.round(naturalW * fitRatio));
2710
2830
  baseH = Math.max(1, Math.round(naturalH * fitRatio));
2711
2831
  };
2712
2832
  const applyTransform = () => {
2713
2833
  if (isImage) {
2714
- updateBaseDimensions();
2834
+ if (!isUserZoomed) {
2835
+ updateBaseDimensions();
2836
+ }
2837
+ const availH = Math.max(100, ctx.container.clientHeight - 32);
2715
2838
  const isRotated90 = rotation % 180 !== 0;
2716
2839
  const boxW = Math.round((isRotated90 ? baseH : baseW) * currentZoom);
2717
2840
  const boxH = Math.round((isRotated90 ? baseW : baseH) * currentZoom);
2718
2841
  sizer.style.width = `${boxW}px`;
2719
2842
  sizer.style.height = `${boxH}px`;
2720
- element.style.width = `${baseW}px`;
2721
- element.style.height = `${baseH}px`;
2843
+ sizer.style.margin = boxH < availH ? "auto 0" : "0";
2844
+ const imgW = isRotated90 ? boxH : boxW;
2845
+ const imgH = isRotated90 ? boxW : boxH;
2846
+ element.style.width = `${imgW}px`;
2847
+ element.style.height = `${imgH}px`;
2722
2848
  element.style.maxWidth = "none";
2723
2849
  element.style.maxHeight = "none";
2724
- element.style.transform = `scale(${currentZoom}) rotate(${rotation}deg)`;
2850
+ element.style.transform = rotation ? `rotate(${rotation}deg)` : "none";
2725
2851
  element.style.transformOrigin = "center center";
2726
2852
  element.style.flexShrink = "0";
2727
2853
  } else {
@@ -2741,7 +2867,8 @@ var MediaPlugin = class {
2741
2867
  }
2742
2868
  }
2743
2869
  const ro = typeof ResizeObserver !== "undefined" ? new ResizeObserver(() => {
2744
- if (currentZoom === 1) {
2870
+ if (!isUserZoomed && currentZoom === 1) {
2871
+ updateBaseDimensions();
2745
2872
  applyTransform();
2746
2873
  }
2747
2874
  }) : null;
@@ -2756,28 +2883,49 @@ var MediaPlugin = class {
2756
2883
  return {
2757
2884
  destroy: cleanup,
2758
2885
  zoomIn: isImage ? () => {
2759
- currentZoom += 0.1;
2886
+ isUserZoomed = true;
2887
+ currentZoom = Math.min(5, Math.round((currentZoom + 0.15) * 100) / 100);
2760
2888
  applyTransform();
2761
2889
  } : void 0,
2762
2890
  zoomOut: isImage ? () => {
2763
- currentZoom = Math.max(0.1, currentZoom - 0.1);
2891
+ isUserZoomed = true;
2892
+ currentZoom = Math.max(0.1, Math.round((currentZoom - 0.15) * 100) / 100);
2764
2893
  applyTransform();
2765
2894
  } : void 0,
2766
2895
  getZoom: isImage ? () => currentZoom : void 0,
2767
2896
  setZoom: isImage ? (level) => {
2897
+ isUserZoomed = true;
2768
2898
  currentZoom = level;
2769
2899
  applyTransform();
2770
2900
  } : void 0,
2771
2901
  fitToPage: isImage ? () => {
2902
+ isUserZoomed = false;
2903
+ fitMode = "page";
2904
+ currentZoom = 1;
2905
+ rotation = 0;
2906
+ ctx.container.scrollTop = 0;
2907
+ ctx.container.scrollLeft = 0;
2908
+ updateBaseDimensions();
2909
+ applyTransform();
2910
+ } : void 0,
2911
+ fitToWidth: isImage ? () => {
2912
+ isUserZoomed = false;
2913
+ fitMode = "width";
2772
2914
  currentZoom = 1;
2773
2915
  rotation = 0;
2916
+ ctx.container.scrollTop = 0;
2917
+ ctx.container.scrollLeft = 0;
2918
+ updateBaseDimensions();
2774
2919
  applyTransform();
2775
2920
  } : void 0,
2776
2921
  resetZoom: isImage ? () => {
2922
+ isUserZoomed = false;
2923
+ fitMode = ctx?.options?.fitMode || "width";
2777
2924
  currentZoom = 1;
2778
2925
  rotation = 0;
2779
2926
  ctx.container.scrollTop = 0;
2780
2927
  ctx.container.scrollLeft = 0;
2928
+ updateBaseDimensions();
2781
2929
  applyTransform();
2782
2930
  } : void 0,
2783
2931
  rotateCW: isImage || isVideo ? () => {
@@ -2904,6 +3052,14 @@ var DocxPlugin = class {
2904
3052
  group: "zoom",
2905
3053
  execute: () => instance.resetZoom?.()
2906
3054
  },
3055
+ {
3056
+ id: "fit-width",
3057
+ icon: "fit-width",
3058
+ label: "Fit to Width",
3059
+ type: "button",
3060
+ group: "zoom",
3061
+ execute: () => instance.fitToWidth?.()
3062
+ },
2907
3063
  {
2908
3064
  id: "rotate-cw",
2909
3065
  icon: "rotate-cw",
@@ -3163,13 +3319,19 @@ var DocxPlugin = class {
3163
3319
  }
3164
3320
  scale = 1;
3165
3321
  let rotation = 0;
3166
- let fitMode = "page";
3322
+ let fitMode = ctx?.options?.fitMode || "width";
3167
3323
  let isUserZoomed = false;
3168
- const calculateFitScale = (_mode = fitMode) => {
3324
+ const calculateFitScale = (mode = fitMode) => {
3169
3325
  const activeEl = pageElements[currentPage - 1] || wrapper.querySelector("section.docx") || wrapper;
3170
3326
  const elW = activeEl.offsetWidth || 816;
3327
+ const elH = activeEl.offsetHeight || 1056;
3171
3328
  const availW = Math.max(280, ctx.container.clientWidth - 32);
3329
+ const availH = Math.max(280, ctx.container.clientHeight - 32);
3172
3330
  const sW = availW / elW;
3331
+ const sH = availH / elH;
3332
+ if (mode === "page") {
3333
+ return Math.max(0.35, Math.min(3, Math.min(sW, sH)));
3334
+ }
3173
3335
  return Math.max(0.35, Math.min(3, sW));
3174
3336
  };
3175
3337
  const applyTransform = () => {
@@ -3190,7 +3352,7 @@ var DocxPlugin = class {
3190
3352
  if (typeof ResizeObserver !== "undefined") {
3191
3353
  resizeObserver = new ResizeObserver(() => {
3192
3354
  if (!isUserZoomed) {
3193
- const newFit = calculateFitScale("page");
3355
+ const newFit = calculateFitScale(fitMode);
3194
3356
  if (Math.abs(scale - newFit) > 0.015) {
3195
3357
  scale = newFit;
3196
3358
  applyTransform();
@@ -3200,7 +3362,7 @@ var DocxPlugin = class {
3200
3362
  resizeObserver.observe(ctx.container);
3201
3363
  }
3202
3364
  setTimeout(() => {
3203
- scale = calculateFitScale("page");
3365
+ scale = calculateFitScale(fitMode);
3204
3366
  applyTransform();
3205
3367
  }, 40);
3206
3368
  const cleanup = () => {
@@ -3239,13 +3401,22 @@ var DocxPlugin = class {
3239
3401
  },
3240
3402
  fitToPage: () => {
3241
3403
  isUserZoomed = false;
3404
+ fitMode = "page";
3242
3405
  scale = calculateFitScale("page");
3243
3406
  rotation = 0;
3244
3407
  applyTransform();
3245
3408
  },
3409
+ fitToWidth: () => {
3410
+ isUserZoomed = false;
3411
+ fitMode = "width";
3412
+ scale = calculateFitScale("width");
3413
+ rotation = 0;
3414
+ applyTransform();
3415
+ },
3246
3416
  resetZoom: () => {
3247
3417
  isUserZoomed = false;
3248
- scale = calculateFitScale("page");
3418
+ fitMode = ctx?.options?.fitMode || "width";
3419
+ scale = calculateFitScale(fitMode);
3249
3420
  rotation = 0;
3250
3421
  ctx.container.scrollTop = 0;
3251
3422
  ctx.container.scrollLeft = 0;
@@ -3710,6 +3881,16 @@ var ExcelPlugin = class {
3710
3881
  instance.resetZoom?.();
3711
3882
  }
3712
3883
  },
3884
+ {
3885
+ id: "fit-width",
3886
+ icon: "fit-width",
3887
+ label: "Fit to Width",
3888
+ type: "button",
3889
+ group: "zoom",
3890
+ execute: () => {
3891
+ instance.fitToWidth?.();
3892
+ }
3893
+ },
3713
3894
  {
3714
3895
  id: "download",
3715
3896
  icon: "download",
@@ -3926,6 +4107,11 @@ var ExcelPlugin = class {
3926
4107
  scale = calculateFitScale();
3927
4108
  applyTransform();
3928
4109
  },
4110
+ fitToWidth: () => {
4111
+ isUserZoomed = false;
4112
+ scale = calculateFitScale();
4113
+ applyTransform();
4114
+ },
3929
4115
  resetZoom: () => {
3930
4116
  isUserZoomed = false;
3931
4117
  scale = calculateFitScale();
@@ -4073,6 +4259,16 @@ var CsvPlugin = class {
4073
4259
  instance.resetZoom?.();
4074
4260
  }
4075
4261
  },
4262
+ {
4263
+ id: "fit-width",
4264
+ icon: "fit-width",
4265
+ label: "Fit to Width",
4266
+ type: "button",
4267
+ group: "zoom",
4268
+ execute: () => {
4269
+ instance.fitToWidth?.();
4270
+ }
4271
+ },
4076
4272
  {
4077
4273
  id: "download",
4078
4274
  icon: "download",
@@ -4286,6 +4482,11 @@ var CsvPlugin = class {
4286
4482
  scale = calculateFitScale();
4287
4483
  applyScale();
4288
4484
  },
4485
+ fitToWidth: () => {
4486
+ isUserZoomed = false;
4487
+ scale = calculateFitScale();
4488
+ applyScale();
4489
+ },
4289
4490
  resetZoom: () => {
4290
4491
  isUserZoomed = false;
4291
4492
  scale = calculateFitScale();
@@ -4317,31 +4518,80 @@ function csvPlugin() {
4317
4518
  }
4318
4519
  var CODE_EXTENSIONS = [
4319
4520
  ".txt",
4521
+ ".log",
4522
+ ".ini",
4523
+ ".cfg",
4524
+ ".conf",
4525
+ ".env",
4320
4526
  ".json",
4527
+ ".jsonc",
4528
+ ".json5",
4321
4529
  ".js",
4322
- ".ts",
4530
+ ".mjs",
4531
+ ".cjs",
4323
4532
  ".jsx",
4533
+ ".ts",
4534
+ ".mts",
4535
+ ".cts",
4324
4536
  ".tsx",
4325
4537
  ".html",
4538
+ ".htm",
4539
+ ".xhtml",
4326
4540
  ".css",
4327
4541
  ".scss",
4542
+ ".sass",
4328
4543
  ".less",
4329
4544
  ".md",
4545
+ ".markdown",
4330
4546
  ".xml",
4547
+ ".svg",
4548
+ ".xaml",
4331
4549
  ".yml",
4332
4550
  ".yaml",
4551
+ ".toml",
4333
4552
  ".sh",
4334
4553
  ".bash",
4554
+ ".zsh",
4555
+ ".fish",
4556
+ ".bat",
4557
+ ".cmd",
4558
+ ".ps1",
4335
4559
  ".py",
4560
+ ".pyw",
4336
4561
  ".java",
4562
+ ".class",
4337
4563
  ".c",
4338
4564
  ".cpp",
4565
+ ".cc",
4566
+ ".cxx",
4339
4567
  ".h",
4568
+ ".hpp",
4569
+ ".hxx",
4340
4570
  ".cs",
4571
+ ".csx",
4341
4572
  ".go",
4342
4573
  ".rs",
4343
4574
  ".sql",
4344
- ".php"
4575
+ ".php",
4576
+ ".phtml",
4577
+ ".rb",
4578
+ ".swift",
4579
+ ".kt",
4580
+ ".kts",
4581
+ ".scala",
4582
+ ".r",
4583
+ ".lua",
4584
+ ".pl",
4585
+ ".pm",
4586
+ ".dart",
4587
+ ".graphql",
4588
+ ".gql",
4589
+ ".proto",
4590
+ ".diff",
4591
+ ".patch",
4592
+ ".dockerfile",
4593
+ ".properties",
4594
+ ".gradle"
4345
4595
  ];
4346
4596
  var CodePlugin = class {
4347
4597
  id = "code";
@@ -4359,34 +4609,36 @@ var CodePlugin = class {
4359
4609
  getToolbarActions(instance) {
4360
4610
  const totalPages = instance.getPageCount?.() ?? 1;
4361
4611
  const actions = [];
4362
- actions.push({
4363
- id: "thumbnails",
4364
- icon: "thumbnails",
4365
- label: "Page Thumbnails",
4366
- type: "button",
4367
- group: "navigation",
4368
- execute: () => instance.toggleThumbnails?.()
4369
- });
4370
- actions.push({
4371
- id: "page-nav",
4372
- icon: "",
4373
- label: "Page Navigation",
4374
- type: "page-nav",
4375
- group: "navigation",
4376
- value: instance.getCurrentPage?.() ?? 1,
4377
- max: totalPages,
4378
- execute: (action, page) => {
4379
- const cur = instance.getCurrentPage?.() ?? 1;
4380
- const max = instance.getPageCount?.() ?? 1;
4381
- if (action === "prev") {
4382
- if (cur > 1) instance.goToPage?.(cur - 1);
4383
- } else if (action === "next") {
4384
- if (cur < max) instance.goToPage?.(cur + 1);
4385
- } else if (typeof page === "number") {
4386
- instance.goToPage?.(page);
4612
+ if (totalPages > 1) {
4613
+ actions.push({
4614
+ id: "thumbnails",
4615
+ icon: "thumbnails",
4616
+ label: "Page Thumbnails",
4617
+ type: "button",
4618
+ group: "navigation",
4619
+ execute: () => instance.toggleThumbnails?.()
4620
+ });
4621
+ actions.push({
4622
+ id: "page-nav",
4623
+ icon: "",
4624
+ label: "Page Navigation",
4625
+ type: "page-nav",
4626
+ group: "navigation",
4627
+ value: instance.getCurrentPage?.() ?? 1,
4628
+ max: totalPages,
4629
+ execute: (action, page) => {
4630
+ const cur = instance.getCurrentPage?.() ?? 1;
4631
+ const max = instance.getPageCount?.() ?? 1;
4632
+ if (action === "prev") {
4633
+ if (cur > 1) instance.goToPage?.(cur - 1);
4634
+ } else if (action === "next") {
4635
+ if (cur < max) instance.goToPage?.(cur + 1);
4636
+ } else if (typeof page === "number") {
4637
+ instance.goToPage?.(page);
4638
+ }
4387
4639
  }
4388
- }
4389
- });
4640
+ });
4641
+ }
4390
4642
  actions.push(
4391
4643
  {
4392
4644
  id: "zoom-out",
@@ -4418,6 +4670,16 @@ var CodePlugin = class {
4418
4670
  instance.resetZoom?.();
4419
4671
  }
4420
4672
  },
4673
+ {
4674
+ id: "fit-width",
4675
+ icon: "fit-width",
4676
+ label: "Fit to Width",
4677
+ type: "button",
4678
+ group: "zoom",
4679
+ execute: () => {
4680
+ instance.fitToWidth?.();
4681
+ }
4682
+ },
4421
4683
  {
4422
4684
  id: "copy",
4423
4685
  icon: "copy",
@@ -4513,10 +4775,6 @@ var CodePlugin = class {
4513
4775
  }
4514
4776
  const totalPages = Math.max(1, rawPages.length);
4515
4777
  let currentPage = 1;
4516
- const container = document.createElement("div");
4517
- container.style.width = "100%";
4518
- container.style.height = "100%";
4519
- container.style.overflow = "auto";
4520
4778
  let fontSize = 13;
4521
4779
  let rotation = 0;
4522
4780
  let zoomLevel = 1;
@@ -4525,9 +4783,10 @@ var CodePlugin = class {
4525
4783
  const code = document.createElement("code");
4526
4784
  const sizer = document.createElement("div");
4527
4785
  const scrollWrapper = document.createElement("div");
4786
+ const lineGutter = document.createElement("div");
4787
+ ctx.container.style.overflow = "auto";
4528
4788
  if (isTxt) {
4529
- container.style.overflow = "auto";
4530
- container.style.backgroundColor = "#f1f5f9";
4789
+ ctx.container.style.backgroundColor = "#f1f5f9";
4531
4790
  scrollWrapper.className = "fp-code-scroll-wrapper";
4532
4791
  scrollWrapper.style.minWidth = "100%";
4533
4792
  scrollWrapper.style.minHeight = "100%";
@@ -4562,18 +4821,42 @@ var CodePlugin = class {
4562
4821
  pre.style.transition = "transform 0.15s ease";
4563
4822
  pre.style.flexShrink = "0";
4564
4823
  } else {
4565
- container.style.overflow = "auto";
4566
- container.style.backgroundColor = "#1e1e1e";
4567
- container.style.color = "#d4d4d4";
4568
- container.style.padding = "16px";
4569
- container.style.boxSizing = "border-box";
4824
+ ctx.container.style.backgroundColor = "#1e1e1e";
4825
+ ctx.container.style.color = "#d4d4d4";
4826
+ scrollWrapper.className = "fp-code-scroll-wrapper";
4827
+ scrollWrapper.style.minWidth = "100%";
4828
+ scrollWrapper.style.minHeight = "100%";
4829
+ scrollWrapper.style.width = "max-content";
4830
+ scrollWrapper.style.height = "max-content";
4831
+ scrollWrapper.style.display = "flex";
4832
+ scrollWrapper.style.alignItems = "flex-start";
4833
+ scrollWrapper.style.padding = "16px";
4834
+ scrollWrapper.style.boxSizing = "border-box";
4835
+ const lineCount = fullText.split(/\r?\n/).length || 1;
4836
+ const gutterLines = [];
4837
+ for (let i = 1; i <= lineCount; i++) {
4838
+ gutterLines.push(String(i));
4839
+ }
4840
+ lineGutter.className = "fp-code-gutter";
4841
+ lineGutter.style.userSelect = "none";
4842
+ lineGutter.style.textAlign = "right";
4843
+ lineGutter.style.paddingRight = "16px";
4844
+ lineGutter.style.marginRight = "16px";
4845
+ lineGutter.style.borderRight = "1px solid #333333";
4846
+ lineGutter.style.color = "#858585";
4847
+ lineGutter.style.fontFamily = "Consolas, Menlo, Monaco, 'Courier New', monospace";
4848
+ lineGutter.style.fontSize = `${fontSize}px`;
4849
+ lineGutter.style.lineHeight = "1.6";
4850
+ lineGutter.style.flexShrink = "0";
4851
+ lineGutter.textContent = gutterLines.join("\n");
4570
4852
  pre.style.margin = "0";
4571
- pre.style.fontFamily = "Consolas, Menlo, Monaco, monospace";
4853
+ pre.style.fontFamily = "Consolas, Menlo, Monaco, 'Courier New', monospace";
4572
4854
  pre.style.fontSize = `${fontSize}px`;
4573
- pre.style.lineHeight = "1.5";
4574
- pre.style.whiteSpace = "pre-wrap";
4575
- pre.style.wordBreak = "break-all";
4576
- pre.style.transformOrigin = "top left";
4855
+ pre.style.lineHeight = "1.6";
4856
+ pre.style.whiteSpace = "pre";
4857
+ pre.style.wordBreak = "normal";
4858
+ pre.style.overflowWrap = "normal";
4859
+ pre.style.flex = "1";
4577
4860
  }
4578
4861
  const ext = (ctx.metadata.extension || "").replace(".", "");
4579
4862
  const renderCodePage = (text) => {
@@ -4593,25 +4876,27 @@ var CodePlugin = class {
4593
4876
  };
4594
4877
  renderCodePage(rawPages[0] || (isTxt ? "" : fullText));
4595
4878
  pre.appendChild(code);
4879
+ ctx.container.innerHTML = "";
4596
4880
  if (isTxt) {
4597
4881
  sizer.appendChild(pre);
4598
4882
  scrollWrapper.appendChild(sizer);
4599
- container.appendChild(scrollWrapper);
4883
+ ctx.container.appendChild(scrollWrapper);
4600
4884
  } else {
4601
- container.appendChild(pre);
4885
+ scrollWrapper.appendChild(lineGutter);
4886
+ scrollWrapper.appendChild(pre);
4887
+ ctx.container.appendChild(scrollWrapper);
4602
4888
  }
4603
4889
  const showPage = (pageNum) => {
4604
4890
  currentPage = Math.max(1, Math.min(totalPages, pageNum));
4605
4891
  renderCodePage(rawPages[currentPage - 1] || (isTxt ? "" : fullText));
4606
- container.scrollTop = 0;
4892
+ ctx.container.scrollTop = 0;
4607
4893
  ctx.emit("page-change", { page: currentPage, total: totalPages });
4608
4894
  };
4609
4895
  if (totalPages > 1) {
4610
4896
  showPage(1);
4611
4897
  }
4612
- ctx.container.appendChild(container);
4613
4898
  const calculateTxtFit = () => {
4614
- const availW = Math.max(280, container.clientWidth - 32);
4899
+ const availW = Math.max(280, ctx.container.clientWidth - 32);
4615
4900
  return Math.max(0.4, Math.min(3, availW / 816));
4616
4901
  };
4617
4902
  const updateTransform = () => {
@@ -4629,6 +4914,7 @@ var CodePlugin = class {
4629
4914
  } else {
4630
4915
  pre.style.transform = `rotate(${rotation}deg)`;
4631
4916
  pre.style.fontSize = `${fontSize}px`;
4917
+ lineGutter.style.fontSize = `${fontSize}px`;
4632
4918
  }
4633
4919
  };
4634
4920
  let resizeObserver = null;
@@ -4643,11 +4929,11 @@ var CodePlugin = class {
4643
4929
  updateTransform();
4644
4930
  }
4645
4931
  }) : null;
4646
- resizeObserver?.observe(container);
4932
+ resizeObserver?.observe(ctx.container);
4647
4933
  }
4648
4934
  const cleanup = () => {
4649
4935
  resizeObserver?.disconnect();
4650
- container.remove();
4936
+ scrollWrapper.remove();
4651
4937
  ctx.container.innerHTML = "";
4652
4938
  };
4653
4939
  ctx.signal.addEventListener("abort", cleanup);
@@ -4692,7 +4978,7 @@ var CodePlugin = class {
4692
4978
  if (isTxt) {
4693
4979
  zoomLevel = Math.min(3.5, zoomLevel + 0.15);
4694
4980
  } else {
4695
- fontSize = Math.min(32, fontSize + 2);
4981
+ fontSize = Math.min(48, fontSize + 2);
4696
4982
  }
4697
4983
  updateTransform();
4698
4984
  },
@@ -4701,7 +4987,7 @@ var CodePlugin = class {
4701
4987
  if (isTxt) {
4702
4988
  zoomLevel = Math.max(0.1, zoomLevel - 0.15);
4703
4989
  } else {
4704
- fontSize = Math.max(8, fontSize - 2);
4990
+ fontSize = Math.max(9, fontSize - 2);
4705
4991
  }
4706
4992
  updateTransform();
4707
4993
  },
@@ -4722,13 +5008,20 @@ var CodePlugin = class {
4722
5008
  zoomLevel = isTxt ? calculateTxtFit() : 1;
4723
5009
  updateTransform();
4724
5010
  },
5011
+ fitToWidth: () => {
5012
+ isUserZoomed = false;
5013
+ fontSize = 13;
5014
+ rotation = 0;
5015
+ zoomLevel = isTxt ? calculateTxtFit() : 1;
5016
+ updateTransform();
5017
+ },
4725
5018
  resetZoom: () => {
4726
5019
  isUserZoomed = false;
4727
5020
  fontSize = 13;
4728
5021
  rotation = 0;
4729
5022
  zoomLevel = isTxt ? calculateTxtFit() : 1;
4730
- container.scrollTop = 0;
4731
- container.scrollLeft = 0;
5023
+ ctx.container.scrollTop = 0;
5024
+ ctx.container.scrollLeft = 0;
4732
5025
  updateTransform();
4733
5026
  },
4734
5027
  rotateCW: () => {
@@ -4806,6 +5099,14 @@ var ArchivePlugin = class {
4806
5099
  group: "zoom",
4807
5100
  execute: () => instance.resetZoom?.()
4808
5101
  },
5102
+ {
5103
+ id: "fit-width",
5104
+ icon: "fit-width",
5105
+ label: "Fit to Width",
5106
+ type: "button",
5107
+ group: "zoom",
5108
+ execute: () => instance.fitToWidth?.()
5109
+ },
4809
5110
  {
4810
5111
  id: "download",
4811
5112
  icon: "download",
@@ -5003,6 +5304,10 @@ var ArchivePlugin = class {
5003
5304
  scale = 1;
5004
5305
  applyTransform();
5005
5306
  },
5307
+ fitToWidth: () => {
5308
+ scale = 1;
5309
+ applyTransform();
5310
+ },
5006
5311
  resetZoom: () => {
5007
5312
  scale = 1;
5008
5313
  wrapper.scrollTop = 0;
@@ -5038,7 +5343,7 @@ var MarkdownPlugin = class {
5038
5343
  {
5039
5344
  id: "zoom-out",
5040
5345
  icon: "zoom-out",
5041
- label: "Decrease Font",
5346
+ label: "Zoom Out",
5042
5347
  type: "button",
5043
5348
  group: "zoom",
5044
5349
  execute: () => instance.zoomOut?.()
@@ -5046,19 +5351,11 @@ var MarkdownPlugin = class {
5046
5351
  {
5047
5352
  id: "zoom-in",
5048
5353
  icon: "zoom-in",
5049
- label: "Increase Font",
5354
+ label: "Zoom In",
5050
5355
  type: "button",
5051
5356
  group: "zoom",
5052
5357
  execute: () => instance.zoomIn?.()
5053
5358
  },
5054
- {
5055
- id: "fit-page",
5056
- icon: "fit-page",
5057
- label: "Default Size",
5058
- type: "button",
5059
- group: "zoom",
5060
- execute: () => instance.fitToPage?.()
5061
- },
5062
5359
  {
5063
5360
  id: "reset-zoom",
5064
5361
  icon: "reset-zoom",
@@ -5067,6 +5364,22 @@ var MarkdownPlugin = class {
5067
5364
  group: "zoom",
5068
5365
  execute: () => instance.resetZoom?.()
5069
5366
  },
5367
+ {
5368
+ id: "fit-width",
5369
+ icon: "fit-width",
5370
+ label: "Fit to Width",
5371
+ type: "button",
5372
+ group: "zoom",
5373
+ execute: () => instance.fitToWidth?.()
5374
+ },
5375
+ {
5376
+ id: "fit-page",
5377
+ icon: "fit-page",
5378
+ label: "Fit to Page",
5379
+ type: "button",
5380
+ group: "zoom",
5381
+ execute: () => instance.fitToPage?.()
5382
+ },
5070
5383
  {
5071
5384
  id: "copy",
5072
5385
  icon: "copy",
@@ -5090,10 +5403,18 @@ var MarkdownPlugin = class {
5090
5403
  type: "button",
5091
5404
  group: "actions",
5092
5405
  execute: () => instance.print?.()
5093
- }
5094
- ];
5095
- }
5096
- async render(ctx) {
5406
+ },
5407
+ {
5408
+ id: "open-window",
5409
+ icon: "open-window",
5410
+ label: "Open in Separate Full Window",
5411
+ type: "button",
5412
+ group: "actions",
5413
+ execute: () => instance.openInSeparateWindow?.()
5414
+ }
5415
+ ];
5416
+ }
5417
+ async render(ctx) {
5097
5418
  const text = new TextDecoder("utf-8", { fatal: false }).decode(ctx.buffer);
5098
5419
  const rawHtml = await marked.parse(text, {
5099
5420
  gfm: true,
@@ -5102,35 +5423,57 @@ var MarkdownPlugin = class {
5102
5423
  const cleanHtml = DOMPurify6.sanitize(rawHtml, {
5103
5424
  USE_PROFILES: { html: true }
5104
5425
  });
5105
- const wrapper = document.createElement("div");
5106
- wrapper.className = "fp-markdown-wrapper";
5107
- wrapper.style.cssText = `
5108
- width: 100%;
5109
- height: 100%;
5110
- overflow: auto;
5111
- padding: 32px 40px;
5426
+ const scrollWrapper = document.createElement("div");
5427
+ scrollWrapper.className = "fp-markdown-scroll-wrapper";
5428
+ scrollWrapper.style.minWidth = "100%";
5429
+ scrollWrapper.style.minHeight = "100%";
5430
+ scrollWrapper.style.width = "max-content";
5431
+ scrollWrapper.style.height = "max-content";
5432
+ scrollWrapper.style.display = "flex";
5433
+ scrollWrapper.style.justifyContent = "center";
5434
+ scrollWrapper.style.alignItems = "flex-start";
5435
+ scrollWrapper.style.padding = "24px 16px";
5436
+ scrollWrapper.style.boxSizing = "border-box";
5437
+ const sizer = document.createElement("div");
5438
+ sizer.className = "fp-markdown-sizer";
5439
+ sizer.style.position = "relative";
5440
+ sizer.style.flexShrink = "0";
5441
+ sizer.style.display = "flex";
5442
+ sizer.style.justifyContent = "center";
5443
+ sizer.style.alignItems = "flex-start";
5444
+ const docCard = document.createElement("div");
5445
+ docCard.className = "fp-markdown-doc-card";
5446
+ docCard.style.cssText = `
5447
+ width: 860px;
5448
+ min-height: 600px;
5449
+ padding: 40px 48px;
5112
5450
  box-sizing: border-box;
5113
5451
  line-height: 1.6;
5114
5452
  font-size: 15px;
5115
5453
  color: var(--fp-text, #24292f);
5116
5454
  background: var(--fp-bg, #ffffff);
5455
+ border-radius: 6px;
5456
+ box-shadow: 0 4px 24px rgba(0, 0, 0, 0.08);
5117
5457
  font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Noto Sans", Helvetica, Arial, sans-serif;
5458
+ transform-origin: top center;
5459
+ transition: transform 0.15s ease;
5460
+ flex-shrink: 0;
5118
5461
  `;
5119
- wrapper.innerHTML = `
5462
+ docCard.innerHTML = `
5120
5463
  <style>
5121
- .fp-markdown-wrapper h1, .fp-markdown-wrapper h2, .fp-markdown-wrapper h3,
5122
- .fp-markdown-wrapper h4, .fp-markdown-wrapper h5, .fp-markdown-wrapper h6 {
5464
+ .fp-markdown-doc-card h1, .fp-markdown-doc-card h2, .fp-markdown-doc-card h3,
5465
+ .fp-markdown-doc-card h4, .fp-markdown-doc-card h5, .fp-markdown-doc-card h6 {
5123
5466
  margin-top: 24px;
5124
5467
  margin-bottom: 16px;
5125
5468
  font-weight: 600;
5126
5469
  line-height: 1.25;
5127
5470
  color: var(--fp-text, #1f2328);
5128
5471
  }
5129
- .fp-markdown-wrapper h1 { font-size: 2em; padding-bottom: 0.3em; border-bottom: 1px solid var(--fp-border, #d0d7de); }
5130
- .fp-markdown-wrapper h2 { font-size: 1.5em; padding-bottom: 0.3em; border-bottom: 1px solid var(--fp-border, #d0d7de); }
5131
- .fp-markdown-wrapper h3 { font-size: 1.25em; }
5132
- .fp-markdown-wrapper p { margin-top: 0; margin-bottom: 16px; }
5133
- .fp-markdown-wrapper table {
5472
+ .fp-markdown-doc-card h1 { font-size: 2em; padding-bottom: 0.3em; border-bottom: 1px solid var(--fp-border, #d0d7de); }
5473
+ .fp-markdown-doc-card h2 { font-size: 1.5em; padding-bottom: 0.3em; border-bottom: 1px solid var(--fp-border, #d0d7de); }
5474
+ .fp-markdown-doc-card h3 { font-size: 1.25em; }
5475
+ .fp-markdown-doc-card p { margin-top: 0; margin-bottom: 16px; }
5476
+ .fp-markdown-doc-card table {
5134
5477
  border-spacing: 0;
5135
5478
  border-collapse: collapse;
5136
5479
  margin-top: 0;
@@ -5138,20 +5481,20 @@ var MarkdownPlugin = class {
5138
5481
  width: 100%;
5139
5482
  overflow: auto;
5140
5483
  }
5141
- .fp-markdown-wrapper table th, .fp-markdown-wrapper table td {
5484
+ .fp-markdown-doc-card table th, .fp-markdown-doc-card table td {
5142
5485
  padding: 6px 13px;
5143
5486
  border: 1px solid var(--fp-border, #d0d7de);
5144
5487
  }
5145
- .fp-markdown-wrapper table tr:nth-child(2n) {
5488
+ .fp-markdown-doc-card table tr:nth-child(2n) {
5146
5489
  background-color: var(--fp-toolbar-bg, #f6f8fa);
5147
5490
  }
5148
- .fp-markdown-wrapper blockquote {
5491
+ .fp-markdown-doc-card blockquote {
5149
5492
  margin: 0 0 16px 0;
5150
5493
  padding: 0 1em;
5151
5494
  color: var(--fp-text-muted, #59636e);
5152
5495
  border-left: 0.25em solid var(--fp-border, #d0d7de);
5153
5496
  }
5154
- .fp-markdown-wrapper pre {
5497
+ .fp-markdown-doc-card pre {
5155
5498
  padding: 16px;
5156
5499
  overflow: auto;
5157
5500
  font-size: 85%;
@@ -5160,7 +5503,7 @@ var MarkdownPlugin = class {
5160
5503
  border-radius: 6px;
5161
5504
  border: 1px solid var(--fp-border, #d0d7de);
5162
5505
  }
5163
- .fp-markdown-wrapper code {
5506
+ .fp-markdown-doc-card code {
5164
5507
  padding: 0.2em 0.4em;
5165
5508
  margin: 0;
5166
5509
  font-size: 85%;
@@ -5168,16 +5511,16 @@ var MarkdownPlugin = class {
5168
5511
  border-radius: 4px;
5169
5512
  font-family: ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, monospace;
5170
5513
  }
5171
- .fp-markdown-wrapper pre code {
5514
+ .fp-markdown-doc-card pre code {
5172
5515
  padding: 0;
5173
5516
  background: transparent;
5174
5517
  }
5175
- .fp-markdown-wrapper ul, .fp-markdown-wrapper ol {
5518
+ .fp-markdown-doc-card ul, .fp-markdown-doc-card ol {
5176
5519
  padding-left: 2em;
5177
5520
  margin-top: 0;
5178
5521
  margin-bottom: 16px;
5179
5522
  }
5180
- .fp-markdown-wrapper hr {
5523
+ .fp-markdown-doc-card hr {
5181
5524
  height: 0.25em;
5182
5525
  padding: 0;
5183
5526
  margin: 24px 0;
@@ -5185,46 +5528,95 @@ var MarkdownPlugin = class {
5185
5528
  border: 0;
5186
5529
  }
5187
5530
  </style>
5188
- <div class="fp-markdown-content" style="max-width: 860px; margin: 0 auto;">
5531
+ <div class="fp-markdown-body">
5189
5532
  ${cleanHtml}
5190
5533
  </div>
5191
5534
  `;
5192
- wrapper.querySelectorAll("pre code").forEach((block) => {
5535
+ docCard.querySelectorAll("pre code").forEach((block) => {
5193
5536
  hljs.highlightElement(block);
5194
5537
  });
5538
+ sizer.appendChild(docCard);
5539
+ scrollWrapper.appendChild(sizer);
5195
5540
  ctx.container.innerHTML = "";
5196
5541
  ctx.container.style.overflow = "auto";
5197
- ctx.container.appendChild(wrapper);
5198
- let fontSize = 15;
5542
+ ctx.container.style.backgroundColor = "#f1f5f9";
5543
+ ctx.container.appendChild(scrollWrapper);
5544
+ let scale = 1;
5545
+ let isUserZoomed = false;
5546
+ const calculateFitScale = () => {
5547
+ const availW = Math.max(280, ctx.container.clientWidth - 48);
5548
+ if (availW < 860) {
5549
+ return Math.max(0.35, availW / 860);
5550
+ }
5551
+ return 1;
5552
+ };
5553
+ const applyTransform = () => {
5554
+ const baseW = 860;
5555
+ const baseH = docCard.offsetHeight || 600;
5556
+ const scaledW = Math.round(baseW * scale);
5557
+ const scaledH = Math.round(baseH * scale);
5558
+ sizer.style.width = `${scaledW}px`;
5559
+ sizer.style.height = `${scaledH}px`;
5560
+ docCard.style.width = `${baseW}px`;
5561
+ docCard.style.transform = `scale(${scale})`;
5562
+ docCard.style.transformOrigin = scaledW > ctx.container.clientWidth - 32 ? "top left" : "top center";
5563
+ };
5564
+ const ro = typeof ResizeObserver !== "undefined" ? new ResizeObserver(() => {
5565
+ if (!isUserZoomed) {
5566
+ scale = calculateFitScale();
5567
+ applyTransform();
5568
+ }
5569
+ }) : null;
5570
+ ro?.observe(ctx.container);
5571
+ requestAnimationFrame(() => {
5572
+ if (!isUserZoomed) {
5573
+ scale = calculateFitScale();
5574
+ }
5575
+ applyTransform();
5576
+ });
5199
5577
  const cleanup = () => {
5200
- wrapper.remove();
5578
+ ro?.disconnect();
5579
+ scrollWrapper.remove();
5201
5580
  ctx.container.innerHTML = "";
5202
5581
  };
5203
5582
  ctx.signal.addEventListener("abort", cleanup);
5204
5583
  return {
5205
5584
  destroy: cleanup,
5206
5585
  zoomIn: () => {
5207
- fontSize = Math.min(28, fontSize + 2);
5208
- wrapper.style.fontSize = `${fontSize}px`;
5586
+ isUserZoomed = true;
5587
+ scale = Math.min(3.5, scale + 0.15);
5588
+ applyTransform();
5209
5589
  },
5210
5590
  zoomOut: () => {
5211
- fontSize = Math.max(10, fontSize - 2);
5212
- wrapper.style.fontSize = `${fontSize}px`;
5591
+ isUserZoomed = true;
5592
+ scale = Math.max(0.25, scale - 0.15);
5593
+ applyTransform();
5213
5594
  },
5214
- getZoom: () => fontSize / 15,
5595
+ getZoom: () => scale,
5215
5596
  setZoom: (level) => {
5216
- fontSize = Math.round(15 * level);
5217
- wrapper.style.fontSize = `${fontSize}px`;
5597
+ isUserZoomed = true;
5598
+ scale = level;
5599
+ applyTransform();
5218
5600
  },
5219
5601
  fitToPage: () => {
5220
- fontSize = 15;
5221
- wrapper.style.fontSize = "15px";
5602
+ isUserZoomed = false;
5603
+ scale = calculateFitScale();
5604
+ applyTransform();
5605
+ },
5606
+ fitToWidth: () => {
5607
+ isUserZoomed = false;
5608
+ scale = calculateFitScale();
5609
+ applyTransform();
5222
5610
  },
5223
5611
  resetZoom: () => {
5224
- fontSize = 15;
5225
- wrapper.style.fontSize = "15px";
5612
+ isUserZoomed = false;
5613
+ scale = calculateFitScale();
5226
5614
  ctx.container.scrollTop = 0;
5227
5615
  ctx.container.scrollLeft = 0;
5616
+ applyTransform();
5617
+ },
5618
+ openInSeparateWindow: () => {
5619
+ ctx?.openInSeparateWindow?.();
5228
5620
  },
5229
5621
  download: () => {
5230
5622
  downloadFile(ctx.buffer, ctx.metadata.name || "document.md", "text/markdown");
@@ -5327,6 +5719,14 @@ var PptxPlugin = class {
5327
5719
  group: "zoom",
5328
5720
  execute: () => instance.resetZoom?.()
5329
5721
  },
5722
+ {
5723
+ id: "fit-width",
5724
+ icon: "fit-width",
5725
+ label: "Fit to Width",
5726
+ type: "button",
5727
+ group: "zoom",
5728
+ execute: () => instance.fitToWidth?.()
5729
+ },
5330
5730
  {
5331
5731
  id: "rotate-cw",
5332
5732
  icon: "rotate-cw",
@@ -5410,12 +5810,17 @@ var PptxPlugin = class {
5410
5810
  ctx.container.innerHTML = "";
5411
5811
  ctx.container.style.overflow = "auto";
5412
5812
  ctx.container.appendChild(wrapper);
5413
- const calculateFitScale = () => {
5414
- const availW = Math.max(200, ctx.container.clientWidth - 48);
5415
- const availH = Math.max(200, ctx.container.clientHeight - 72);
5813
+ let fitMode = ctx?.options?.fitMode || "width";
5814
+ let isUserZoomed = false;
5815
+ const calculateFitScale = (mode = fitMode) => {
5816
+ const availW = Math.max(200, ctx.container.clientWidth - 32);
5817
+ const availH = Math.max(200, ctx.container.clientHeight - 32);
5416
5818
  const cW = canvas.offsetWidth || 1280;
5417
5819
  const cH = canvas.offsetHeight || 720;
5418
- return Math.min(1, Math.min(availW / cW, availH / cH));
5820
+ if (mode === "page") {
5821
+ return Math.min(2.5, Math.min(availW / cW, availH / cH));
5822
+ }
5823
+ return Math.min(2.5, availW / cW);
5419
5824
  };
5420
5825
  const applyTransform = () => {
5421
5826
  const cW = canvas.offsetWidth || 1280;
@@ -5434,14 +5839,24 @@ var PptxPlugin = class {
5434
5839
  try {
5435
5840
  await renderer.renderSlide(currentSlide - 1, canvas, 1280);
5436
5841
  ctx.emit("page-change", { page: currentSlide, totalPages: slideCount });
5437
- scale = calculateFitScale();
5842
+ if (!isUserZoomed) {
5843
+ scale = calculateFitScale(fitMode);
5844
+ }
5438
5845
  applyTransform();
5439
5846
  } catch (err) {
5440
5847
  console.error("[PptxPlugin] Failed to render slide:", err);
5441
5848
  }
5442
5849
  };
5443
5850
  await renderCurrentSlide();
5851
+ const ro = typeof ResizeObserver !== "undefined" ? new ResizeObserver(() => {
5852
+ if (!isUserZoomed) {
5853
+ scale = calculateFitScale(fitMode);
5854
+ applyTransform();
5855
+ }
5856
+ }) : null;
5857
+ ro?.observe(ctx.container);
5444
5858
  const cleanup = () => {
5859
+ ro?.disconnect();
5445
5860
  renderer.destroy();
5446
5861
  wrapper.remove();
5447
5862
  ctx.container.innerHTML = "";
@@ -5458,28 +5873,44 @@ var PptxPlugin = class {
5458
5873
  getPageCount: () => slideCount,
5459
5874
  getCurrentPage: () => currentSlide,
5460
5875
  zoomIn: () => {
5876
+ isUserZoomed = true;
5461
5877
  scale += 0.15;
5462
5878
  applyTransform();
5463
5879
  },
5464
5880
  zoomOut: () => {
5881
+ isUserZoomed = true;
5465
5882
  scale = Math.max(0.2, scale - 0.15);
5466
5883
  applyTransform();
5467
5884
  },
5468
5885
  getZoom: () => scale,
5469
5886
  setZoom: (level) => {
5887
+ isUserZoomed = true;
5470
5888
  scale = level;
5471
5889
  applyTransform();
5472
5890
  },
5473
5891
  fitToPage: () => {
5474
- scale = calculateFitScale();
5892
+ isUserZoomed = false;
5893
+ fitMode = "page";
5894
+ scale = calculateFitScale("page");
5895
+ rotation = 0;
5896
+ applyTransform();
5897
+ },
5898
+ fitToWidth: () => {
5899
+ isUserZoomed = false;
5900
+ fitMode = "width";
5901
+ scale = calculateFitScale("width");
5475
5902
  rotation = 0;
5476
5903
  applyTransform();
5477
5904
  },
5478
5905
  resetZoom: () => {
5479
- scale = calculateFitScale();
5906
+ isUserZoomed = false;
5907
+ fitMode = ctx?.options?.fitMode || "width";
5908
+ scale = calculateFitScale(fitMode);
5480
5909
  rotation = 0;
5481
5910
  wrapper.scrollTop = 0;
5482
5911
  wrapper.scrollLeft = 0;
5912
+ ctx.container.scrollTop = 0;
5913
+ ctx.container.scrollLeft = 0;
5483
5914
  applyTransform();
5484
5915
  },
5485
5916
  rotateCW: () => {
@@ -5924,6 +6355,14 @@ var RtfPlugin = class {
5924
6355
  group: "zoom",
5925
6356
  execute: () => instance.resetZoom?.()
5926
6357
  },
6358
+ {
6359
+ id: "fit-width",
6360
+ icon: "fit-width",
6361
+ label: "Fit to Width",
6362
+ type: "button",
6363
+ group: "zoom",
6364
+ execute: () => instance.fitToWidth?.()
6365
+ },
5927
6366
  {
5928
6367
  id: "rotate-cw",
5929
6368
  icon: "rotate-cw",
@@ -6412,6 +6851,13 @@ var RtfPlugin = class {
6412
6851
  applyTransform();
6413
6852
  },
6414
6853
  fitToPage: () => {
6854
+ isUserZoomed = false;
6855
+ fitMode = "page";
6856
+ scale = calculateFitScale("page");
6857
+ rotation = 0;
6858
+ applyTransform();
6859
+ },
6860
+ fitToWidth: () => {
6415
6861
  isUserZoomed = false;
6416
6862
  fitMode = "width";
6417
6863
  scale = calculateFitScale("width");
@@ -6420,8 +6866,8 @@ var RtfPlugin = class {
6420
6866
  },
6421
6867
  resetZoom: () => {
6422
6868
  isUserZoomed = false;
6423
- fitMode = "width";
6424
- scale = calculateFitScale("width");
6869
+ fitMode = ctx?.options?.fitMode || "width";
6870
+ scale = calculateFitScale(fitMode);
6425
6871
  rotation = 0;
6426
6872
  ctx.container.scrollTop = 0;
6427
6873
  ctx.container.scrollLeft = 0;
@@ -6486,14 +6932,6 @@ var HtmlPreviewPlugin = class {
6486
6932
  group: "zoom",
6487
6933
  execute: () => instance.zoomIn?.()
6488
6934
  },
6489
- {
6490
- id: "fit-page",
6491
- icon: "fit-page",
6492
- label: "Fit to Page",
6493
- type: "button",
6494
- group: "zoom",
6495
- execute: () => instance.fitToPage?.()
6496
- },
6497
6935
  {
6498
6936
  id: "reset-zoom",
6499
6937
  icon: "reset-zoom",
@@ -6502,6 +6940,22 @@ var HtmlPreviewPlugin = class {
6502
6940
  group: "zoom",
6503
6941
  execute: () => instance.resetZoom?.()
6504
6942
  },
6943
+ {
6944
+ id: "fit-width",
6945
+ icon: "fit-width",
6946
+ label: "Fit to Width",
6947
+ type: "button",
6948
+ group: "zoom",
6949
+ execute: () => instance.fitToWidth?.()
6950
+ },
6951
+ {
6952
+ id: "fit-page",
6953
+ icon: "fit-page",
6954
+ label: "Fit to Page",
6955
+ type: "button",
6956
+ group: "zoom",
6957
+ execute: () => instance.fitToPage?.()
6958
+ },
6505
6959
  {
6506
6960
  id: "copy",
6507
6961
  icon: "copy",
@@ -6525,6 +6979,14 @@ var HtmlPreviewPlugin = class {
6525
6979
  type: "button",
6526
6980
  group: "actions",
6527
6981
  execute: () => instance.print?.()
6982
+ },
6983
+ {
6984
+ id: "open-window",
6985
+ icon: "open-window",
6986
+ label: "Open in Separate Full Window",
6987
+ type: "button",
6988
+ group: "actions",
6989
+ execute: () => instance.openInSeparateWindow?.()
6528
6990
  }
6529
6991
  ];
6530
6992
  }
@@ -6535,27 +6997,39 @@ var HtmlPreviewPlugin = class {
6535
6997
  ADD_TAGS: ["style", "link"],
6536
6998
  ADD_ATTR: ["target", "rel"]
6537
6999
  });
7000
+ const scrollWrapper = document.createElement("div");
7001
+ scrollWrapper.className = "fp-html-scroll-wrapper";
7002
+ scrollWrapper.style.minWidth = "100%";
7003
+ scrollWrapper.style.minHeight = "100%";
7004
+ scrollWrapper.style.width = "max-content";
7005
+ scrollWrapper.style.height = "max-content";
7006
+ scrollWrapper.style.display = "flex";
7007
+ scrollWrapper.style.justifyContent = "flex-start";
7008
+ scrollWrapper.style.alignItems = "flex-start";
7009
+ scrollWrapper.style.boxSizing = "border-box";
6538
7010
  const sizer = document.createElement("div");
6539
7011
  sizer.className = "fp-html-sizer";
6540
7012
  sizer.style.position = "relative";
7013
+ sizer.style.flexShrink = "0";
6541
7014
  const iframe = document.createElement("iframe");
6542
7015
  iframe.className = "fp-html-iframe";
6543
7016
  iframe.style.border = "none";
6544
7017
  iframe.style.backgroundColor = "#ffffff";
6545
7018
  iframe.style.transformOrigin = "top left";
6546
- iframe.style.transition = "transform 0.2s ease";
7019
+ iframe.style.transition = "transform 0.15s ease";
6547
7020
  iframe.sandbox.add("allow-same-origin");
6548
7021
  sizer.appendChild(iframe);
7022
+ scrollWrapper.appendChild(sizer);
6549
7023
  ctx.container.style.overflow = "auto";
6550
7024
  ctx.container.style.width = "100%";
6551
7025
  ctx.container.style.height = "100%";
6552
7026
  ctx.container.innerHTML = "";
6553
- ctx.container.appendChild(sizer);
7027
+ ctx.container.appendChild(scrollWrapper);
6554
7028
  iframe.srcdoc = sanitized;
6555
7029
  let scale = 1;
7030
+ let baseW = Math.max(600, ctx.container.clientWidth || 800);
7031
+ let baseH = Math.max(400, ctx.container.clientHeight || 600);
6556
7032
  const applyTransform = () => {
6557
- const baseW = Math.max(600, ctx.container.clientWidth || 800);
6558
- const baseH = Math.max(400, ctx.container.clientHeight || 600);
6559
7033
  const scaledW = Math.round(baseW * scale);
6560
7034
  const scaledH = Math.round(baseH * scale);
6561
7035
  sizer.style.width = `${scaledW}px`;
@@ -6568,22 +7042,33 @@ var HtmlPreviewPlugin = class {
6568
7042
  iframe.style.transform = `scale(${scale})`;
6569
7043
  iframe.style.transformOrigin = "top left";
6570
7044
  };
7045
+ const ro = typeof ResizeObserver !== "undefined" ? new ResizeObserver(() => {
7046
+ if (Math.abs(scale - 1) < 0.05) {
7047
+ baseW = Math.max(600, ctx.container.clientWidth || 800);
7048
+ baseH = Math.max(400, ctx.container.clientHeight || 600);
7049
+ applyTransform();
7050
+ }
7051
+ }) : null;
7052
+ ro?.observe(ctx.container);
6571
7053
  requestAnimationFrame(() => {
7054
+ baseW = Math.max(600, ctx.container.clientWidth || 800);
7055
+ baseH = Math.max(400, ctx.container.clientHeight || 600);
6572
7056
  applyTransform();
6573
7057
  });
6574
7058
  const cleanup = () => {
6575
- sizer.remove();
7059
+ ro?.disconnect();
7060
+ scrollWrapper.remove();
6576
7061
  ctx.container.innerHTML = "";
6577
7062
  };
6578
7063
  ctx.signal.addEventListener("abort", cleanup);
6579
7064
  return {
6580
7065
  destroy: cleanup,
6581
7066
  zoomIn: () => {
6582
- scale += 0.1;
7067
+ scale = Math.min(3.5, scale + 0.15);
6583
7068
  applyTransform();
6584
7069
  },
6585
7070
  zoomOut: () => {
6586
- scale = Math.max(0.2, scale - 0.1);
7071
+ scale = Math.max(0.25, scale - 0.15);
6587
7072
  applyTransform();
6588
7073
  },
6589
7074
  getZoom: () => scale,
@@ -6595,14 +7080,21 @@ var HtmlPreviewPlugin = class {
6595
7080
  scale = 1;
6596
7081
  applyTransform();
6597
7082
  },
7083
+ fitToWidth: () => {
7084
+ scale = 1;
7085
+ applyTransform();
7086
+ },
6598
7087
  resetZoom: () => {
6599
7088
  scale = 1;
6600
7089
  ctx.container.scrollTop = 0;
6601
7090
  ctx.container.scrollLeft = 0;
6602
7091
  applyTransform();
6603
7092
  },
7093
+ openInSeparateWindow: () => {
7094
+ ctx?.openInSeparateWindow?.();
7095
+ },
6604
7096
  copy: () => {
6605
- navigator.clipboard.writeText(rawHtml);
7097
+ navigator.clipboard?.writeText(rawHtml);
6606
7098
  },
6607
7099
  download: () => {
6608
7100
  const blob = new Blob([ctx.buffer], { type: "text/html" });
@@ -6709,6 +7201,14 @@ var OpenDocumentPlugin = class {
6709
7201
  group: "zoom",
6710
7202
  execute: () => instance.resetZoom?.()
6711
7203
  },
7204
+ {
7205
+ id: "fit-width",
7206
+ icon: "fit-width",
7207
+ label: "Fit to Width",
7208
+ type: "button",
7209
+ group: "zoom",
7210
+ execute: () => instance.fitToWidth?.()
7211
+ },
6712
7212
  {
6713
7213
  id: "rotate-cw",
6714
7214
  icon: "rotate-cw",
@@ -6825,7 +7325,10 @@ var OpenDocumentPlugin = class {
6825
7325
  const sW = availW / elW;
6826
7326
  const sH = availH / (isPresentation ? 540 : singlePageH);
6827
7327
  if (isPresentation) {
6828
- return Math.min(2.5, Math.min(sW, sH));
7328
+ if (mode === "page") {
7329
+ return Math.min(2.5, Math.min(sW, sH));
7330
+ }
7331
+ return Math.min(2.5, sW);
6829
7332
  }
6830
7333
  if (mode === "page") {
6831
7334
  return Math.max(0.35, Math.min(3, Math.min(sW, sH)));
@@ -6994,6 +7497,13 @@ var OpenDocumentPlugin = class {
6994
7497
  applyTransform();
6995
7498
  },
6996
7499
  fitToPage: () => {
7500
+ isUserZoomed = false;
7501
+ fitMode = "page";
7502
+ scale = calculateFitScale("page");
7503
+ rotation = 0;
7504
+ applyTransform();
7505
+ },
7506
+ fitToWidth: () => {
6997
7507
  isUserZoomed = false;
6998
7508
  fitMode = "width";
6999
7509
  scale = calculateFitScale("width");
@@ -7002,8 +7512,8 @@ var OpenDocumentPlugin = class {
7002
7512
  },
7003
7513
  resetZoom: () => {
7004
7514
  isUserZoomed = false;
7005
- fitMode = "width";
7006
- scale = calculateFitScale("width");
7515
+ fitMode = ctx?.options?.fitMode || "width";
7516
+ scale = calculateFitScale(fitMode);
7007
7517
  rotation = 0;
7008
7518
  container.scrollTop = 0;
7009
7519
  container.scrollLeft = 0;
@@ -7360,6 +7870,14 @@ var DocPlugin = class {
7360
7870
  group: "zoom",
7361
7871
  execute: () => instance.resetZoom?.()
7362
7872
  },
7873
+ {
7874
+ id: "fit-width",
7875
+ icon: "fit-width",
7876
+ label: "Fit to Width",
7877
+ type: "button",
7878
+ group: "zoom",
7879
+ execute: () => instance.fitToWidth?.()
7880
+ },
7363
7881
  {
7364
7882
  id: "rotate-cw",
7365
7883
  icon: "rotate-cw",
@@ -7581,6 +8099,13 @@ var DocPlugin = class {
7581
8099
  applyTransform();
7582
8100
  },
7583
8101
  fitToPage: () => {
8102
+ isUserZoomed = false;
8103
+ fitMode = "page";
8104
+ scale = calculateFitScale("page");
8105
+ rotation = 0;
8106
+ applyTransform();
8107
+ },
8108
+ fitToWidth: () => {
7584
8109
  isUserZoomed = false;
7585
8110
  fitMode = "width";
7586
8111
  scale = calculateFitScale("width");
@@ -7589,8 +8114,8 @@ var DocPlugin = class {
7589
8114
  },
7590
8115
  resetZoom: () => {
7591
8116
  isUserZoomed = false;
7592
- fitMode = "width";
7593
- scale = calculateFitScale("width");
8117
+ fitMode = ctx?.options?.fitMode || "width";
8118
+ scale = calculateFitScale(fitMode);
7594
8119
  rotation = 0;
7595
8120
  container.scrollTop = 0;
7596
8121
  container.scrollLeft = 0;
@@ -8086,6 +8611,14 @@ var PptPlugin = class {
8086
8611
  group: "zoom",
8087
8612
  execute: () => instance.resetZoom?.()
8088
8613
  },
8614
+ {
8615
+ id: "fit-width",
8616
+ icon: "fit-width",
8617
+ label: "Fit to Width",
8618
+ type: "button",
8619
+ group: "zoom",
8620
+ execute: () => instance.fitToWidth?.()
8621
+ },
8089
8622
  {
8090
8623
  id: "rotate-cw",
8091
8624
  icon: "rotate-cw",
@@ -8160,10 +8693,15 @@ var PptPlugin = class {
8160
8693
  let currentSlide = 1;
8161
8694
  let slides = [];
8162
8695
  const createdBlobUrls = [];
8163
- const calculateFitScale = () => {
8164
- const availW = Math.max(200, container.clientWidth - 48);
8165
- const availH = Math.max(200, container.clientHeight - 72);
8166
- return Math.min(1, Math.min(availW / 960, availH / 540));
8696
+ let fitMode = ctx?.options?.fitMode || "width";
8697
+ let isUserZoomed = false;
8698
+ const calculateFitScale = (mode = fitMode) => {
8699
+ const availW = Math.max(200, container.clientWidth - 32);
8700
+ const availH = Math.max(200, container.clientHeight - 32);
8701
+ if (mode === "page") {
8702
+ return Math.min(2.5, Math.min(availW / 960, availH / 540));
8703
+ }
8704
+ return Math.min(2.5, availW / 960);
8167
8705
  };
8168
8706
  const applyTransform = () => {
8169
8707
  const cW = 960;
@@ -8178,8 +8716,15 @@ var PptPlugin = class {
8178
8716
  slideCard.style.transform = `scale(${scale}) rotate(${rotation}deg)`;
8179
8717
  slideCard.style.transformOrigin = "center center";
8180
8718
  };
8719
+ const ro = typeof ResizeObserver !== "undefined" ? new ResizeObserver(() => {
8720
+ if (!isUserZoomed) {
8721
+ scale = calculateFitScale(fitMode);
8722
+ applyTransform();
8723
+ }
8724
+ }) : null;
8725
+ ro?.observe(container);
8181
8726
  setTimeout(() => {
8182
- scale = calculateFitScale();
8727
+ scale = calculateFitScale(fitMode);
8183
8728
  applyTransform();
8184
8729
  }, 60);
8185
8730
  try {
@@ -8272,6 +8817,7 @@ var PptPlugin = class {
8272
8817
  };
8273
8818
  renderSlide(1);
8274
8819
  const cleanup = () => {
8820
+ ro?.disconnect();
8275
8821
  for (const u of createdBlobUrls) {
8276
8822
  URL.revokeObjectURL(u);
8277
8823
  }
@@ -8282,28 +8828,44 @@ var PptPlugin = class {
8282
8828
  return {
8283
8829
  destroy: cleanup,
8284
8830
  zoomIn: () => {
8831
+ isUserZoomed = true;
8285
8832
  scale += 0.15;
8286
8833
  applyTransform();
8287
8834
  },
8288
8835
  zoomOut: () => {
8836
+ isUserZoomed = true;
8289
8837
  scale = Math.max(0.2, scale - 0.15);
8290
8838
  applyTransform();
8291
8839
  },
8292
8840
  getZoom: () => scale,
8293
8841
  setZoom: (level) => {
8842
+ isUserZoomed = true;
8294
8843
  scale = level;
8295
8844
  applyTransform();
8296
8845
  },
8297
8846
  fitToPage: () => {
8298
- scale = calculateFitScale();
8847
+ isUserZoomed = false;
8848
+ fitMode = "page";
8849
+ scale = calculateFitScale("page");
8850
+ rotation = 0;
8851
+ applyTransform();
8852
+ },
8853
+ fitToWidth: () => {
8854
+ isUserZoomed = false;
8855
+ fitMode = "width";
8856
+ scale = calculateFitScale("width");
8299
8857
  rotation = 0;
8300
8858
  applyTransform();
8301
8859
  },
8302
8860
  resetZoom: () => {
8303
- scale = calculateFitScale();
8861
+ isUserZoomed = false;
8862
+ fitMode = ctx?.options?.fitMode || "width";
8863
+ scale = calculateFitScale(fitMode);
8304
8864
  rotation = 0;
8305
8865
  container.scrollTop = 0;
8306
8866
  container.scrollLeft = 0;
8867
+ ctx.container.scrollTop = 0;
8868
+ ctx.container.scrollLeft = 0;
8307
8869
  applyTransform();
8308
8870
  },
8309
8871
  rotateCW: () => {
@@ -8594,7 +9156,7 @@ _FilePreviewComponent_decorators = [Component({
8594
9156
  selector: "fp-file-preview",
8595
9157
  standalone: true,
8596
9158
  imports: [CommonModule],
8597
- template: `<div #container [style.width]="'100%'" [style.height]="'100%'"></div>`,
9159
+ template: `<div #container [style.width]="'100%'" [style.height]="'100%'" [style.position]="'relative'" [style.overflow]="'hidden'"></div>`,
8598
9160
  changeDetection: ChangeDetectionStrategy.OnPush
8599
9161
  })], _src_dec = [Input({ required: true })], _plugins_dec = [Input()], _options_dec = [Input()], _loading_dec = [Output()], _loaded_dec = [Output()], _error_dec = [Output()], _pageChange_dec = [Output()], _zoomChange_dec = [Output()], _rotate_dec = [Output()], _destroyed_dec = [Output()], _container_dec = [ViewChild("container", { static: true })];
8600
9162
  var FilePreviewComponent = class {