@files-preview-app/preview-file 1.3.7 → 1.3.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/vue.js CHANGED
@@ -1056,6 +1056,10 @@ var FilePreviewViewer = class _FilePreviewViewer {
1056
1056
  * Preview a file in the given container element.
1057
1057
  */
1058
1058
  async preview(container, source, options = {}) {
1059
+ options = {
1060
+ ...options,
1061
+ fitMode: options.fitMode ?? "width"
1062
+ };
1059
1063
  this.currentOptions = options;
1060
1064
  this.abort();
1061
1065
  this.abortController = new AbortController();
@@ -1104,8 +1108,8 @@ var FilePreviewViewer = class _FilePreviewViewer {
1104
1108
  this.activeInstance = instance;
1105
1109
  instance.openInSeparateWindow = () => this.openInSeparateWindow();
1106
1110
  instance.toggleThumbnails = () => this.toggleThumbnails();
1107
- if (!instance.resetZoom && instance.fitToPage) {
1108
- instance.resetZoom = () => instance.fitToPage?.();
1111
+ if (!instance.resetZoom) {
1112
+ instance.resetZoom = () => instance.fitToWidth ? instance.fitToWidth() : instance.fitToPage?.();
1109
1113
  }
1110
1114
  this.hideLoading();
1111
1115
  this.eventEmitter.emit("loaded", { metadata, plugin: matchedPlugin.id });
@@ -1502,7 +1506,7 @@ var FilePreviewViewer = class _FilePreviewViewer {
1502
1506
  this.wrapperEl?.classList.toggle("fp-fullscreen-active");
1503
1507
  }
1504
1508
  setTimeout(() => {
1505
- this.activeInstance?.fitToPage?.();
1509
+ this.triggerAutoFit();
1506
1510
  }, 120);
1507
1511
  }
1508
1512
  /**
@@ -1594,19 +1598,85 @@ var FilePreviewViewer = class _FilePreviewViewer {
1594
1598
  if (this.wrapperEl?.parentNode) {
1595
1599
  this.wrapperEl.parentNode.removeChild(this.wrapperEl);
1596
1600
  }
1601
+ if (typeof document !== "undefined" && !document.getElementById("fp-core-injected-styles")) {
1602
+ const styleEl = document.createElement("style");
1603
+ styleEl.id = "fp-core-injected-styles";
1604
+ styleEl.textContent = `
1605
+ .fp-viewer {
1606
+ display: flex !important;
1607
+ flex-direction: column !important;
1608
+ width: 100% !important;
1609
+ height: 100% !important;
1610
+ overflow: hidden !important;
1611
+ position: relative !important;
1612
+ box-sizing: border-box !important;
1613
+ }
1614
+ .fp-body {
1615
+ display: flex !important;
1616
+ flex: 1 1 0% !important;
1617
+ min-height: 0 !important;
1618
+ min-width: 0 !important;
1619
+ width: 100% !important;
1620
+ height: 100% !important;
1621
+ overflow: hidden !important;
1622
+ position: relative !important;
1623
+ box-sizing: border-box !important;
1624
+ }
1625
+ .fp-content {
1626
+ flex: 1 1 0% !important;
1627
+ position: relative !important;
1628
+ overflow: auto !important;
1629
+ display: flex !important;
1630
+ flex-direction: column !important;
1631
+ align-items: stretch !important;
1632
+ justify-content: flex-start !important;
1633
+ width: 100% !important;
1634
+ height: 100% !important;
1635
+ min-width: 0 !important;
1636
+ min-height: 0 !important;
1637
+ box-sizing: border-box !important;
1638
+ }
1639
+ `;
1640
+ document.head.appendChild(styleEl);
1641
+ }
1597
1642
  const themeClass = options.theme === "dark" ? "fp-theme-dark" : "";
1598
1643
  const toolbarPos = options.toolbarPosition ?? "top";
1599
1644
  this.wrapperEl = document.createElement("div");
1600
1645
  this.wrapperEl.className = `fp-viewer ${themeClass} ${options.className ?? ""}`.trim();
1601
1646
  this.wrapperEl.tabIndex = 0;
1647
+ this.wrapperEl.style.display = "flex";
1648
+ this.wrapperEl.style.flexDirection = "column";
1649
+ this.wrapperEl.style.width = "100%";
1650
+ this.wrapperEl.style.height = "100%";
1651
+ this.wrapperEl.style.overflow = "hidden";
1652
+ this.wrapperEl.style.position = "relative";
1602
1653
  const toolbarEl = document.createElement("div");
1603
1654
  toolbarEl.className = "fp-toolbar-container";
1604
1655
  this.contentEl = document.createElement("div");
1605
1656
  this.contentEl.className = "fp-content";
1657
+ this.contentEl.style.flex = "1 1 0%";
1658
+ this.contentEl.style.position = "relative";
1659
+ this.contentEl.style.overflow = "auto";
1660
+ this.contentEl.style.display = "flex";
1661
+ this.contentEl.style.flexDirection = "column";
1662
+ this.contentEl.style.alignItems = "stretch";
1663
+ this.contentEl.style.justifyContent = "flex-start";
1664
+ this.contentEl.style.width = "100%";
1665
+ this.contentEl.style.height = "100%";
1666
+ this.contentEl.style.minWidth = "0";
1667
+ this.contentEl.style.minHeight = "0";
1668
+ this.contentEl.style.boxSizing = "border-box";
1606
1669
  const thumbnailEl = document.createElement("div");
1607
1670
  thumbnailEl.className = "fp-thumbnail-container";
1608
1671
  const bodyEl = document.createElement("div");
1609
1672
  bodyEl.className = "fp-body";
1673
+ bodyEl.style.display = "flex";
1674
+ bodyEl.style.flex = "1 1 0%";
1675
+ bodyEl.style.minHeight = "0";
1676
+ bodyEl.style.minWidth = "0";
1677
+ bodyEl.style.width = "100%";
1678
+ bodyEl.style.overflow = "hidden";
1679
+ bodyEl.style.position = "relative";
1610
1680
  bodyEl.appendChild(thumbnailEl);
1611
1681
  bodyEl.appendChild(this.contentEl);
1612
1682
  const titleBarEl = document.createElement("div");
@@ -1629,18 +1699,29 @@ var FilePreviewViewer = class _FilePreviewViewer {
1629
1699
  this.thumbnailPanel = new ThumbnailPanel(thumbnailEl, (isOpen) => {
1630
1700
  this.toolbar?.setActionActive("thumbnails", isOpen);
1631
1701
  setTimeout(() => {
1632
- this.activeInstance?.fitToPage?.();
1702
+ this.triggerAutoFit();
1633
1703
  }, 260);
1634
1704
  });
1635
1705
  this.setupKeyboardShortcuts();
1636
1706
  this.setupDragAndDrop(container, options);
1637
1707
  this.setupResizeAndFullscreenListeners();
1638
1708
  }
1709
+ triggerAutoFit() {
1710
+ if (!this.activeInstance) return;
1711
+ const mode = this.currentOptions?.fitMode ?? "width";
1712
+ if (mode === "width" && this.activeInstance.fitToWidth) {
1713
+ this.activeInstance.fitToWidth();
1714
+ } else if (this.activeInstance.fitToPage) {
1715
+ this.activeInstance.fitToPage();
1716
+ } else if (this.activeInstance.resetZoom) {
1717
+ this.activeInstance.resetZoom();
1718
+ }
1719
+ }
1639
1720
  setupResizeAndFullscreenListeners() {
1640
1721
  if (this.fullscreenHandler) return;
1641
1722
  this.fullscreenHandler = () => {
1642
1723
  setTimeout(() => {
1643
- this.activeInstance?.fitToPage?.();
1724
+ this.triggerAutoFit();
1644
1725
  }, 100);
1645
1726
  };
1646
1727
  document.addEventListener("fullscreenchange", this.fullscreenHandler);
@@ -1648,7 +1729,7 @@ var FilePreviewViewer = class _FilePreviewViewer {
1648
1729
  if (typeof ResizeObserver !== "undefined" && this.contentEl) {
1649
1730
  this.resizeObserver = new ResizeObserver(() => {
1650
1731
  if (this.activeInstance && (!this.activeInstance.getZoom || Math.abs((this.activeInstance.getZoom?.() ?? 1) - 1) < 0.05)) {
1651
- this.activeInstance.fitToPage?.();
1732
+ this.triggerAutoFit();
1652
1733
  }
1653
1734
  });
1654
1735
  this.resizeObserver.observe(this.contentEl);
@@ -1676,7 +1757,7 @@ var FilePreviewViewer = class _FilePreviewViewer {
1676
1757
  } else if (e.key === "-" || e.key === "_") {
1677
1758
  this.activeInstance.zoomOut?.();
1678
1759
  } else if (e.key === "0") {
1679
- this.activeInstance.fitToPage?.();
1760
+ this.resetZoom();
1680
1761
  } else if (e.key === "r" || e.key === "R") {
1681
1762
  this.activeInstance.rotateCW?.();
1682
1763
  } else if (e.key === "f" || e.key === "F") {
@@ -2299,7 +2380,7 @@ var PdfPlugin = class {
2299
2380
  renderPage(currentPage);
2300
2381
  },
2301
2382
  resetZoom: () => {
2302
- fitMode = "page";
2383
+ fitMode = ctx?.options?.fitMode || "width";
2303
2384
  zoomScale = 1;
2304
2385
  rotation = 0;
2305
2386
  container.scrollTop = 0;
@@ -2483,6 +2564,16 @@ var MediaPlugin = class {
2483
2564
  instance.resetZoom?.();
2484
2565
  }
2485
2566
  },
2567
+ {
2568
+ id: "fit-width",
2569
+ icon: "fit-width",
2570
+ label: "Fit to Width",
2571
+ type: "button",
2572
+ group: "zoom",
2573
+ execute: () => {
2574
+ instance.fitToWidth?.();
2575
+ }
2576
+ },
2486
2577
  {
2487
2578
  id: "rotate-cw",
2488
2579
  icon: "rotate-cw",
@@ -2579,9 +2670,30 @@ var MediaPlugin = class {
2579
2670
  const isVideo = mimeType.startsWith("video/") || VIDEO_EXTS.includes(ctx.metadata.extension || "");
2580
2671
  const isAudio = mimeType.startsWith("audio/") || AUDIO_EXTS.includes(ctx.metadata.extension || "");
2581
2672
  let url = "";
2673
+ let naturalW = 800;
2674
+ let naturalH = 600;
2582
2675
  if (ctx.metadata.extension === ".svg" || mimeType === "image/svg+xml") {
2583
2676
  const decoder = new TextDecoder("utf-8");
2584
2677
  const svgText = decoder.decode(ctx.buffer);
2678
+ try {
2679
+ const vbMatch = svgText.match(/viewBox=["']\s*([0-9.-]+)\s+([0-9.-]+)\s+([0-9.-]+)\s+([0-9.-]+)\s*["']/i);
2680
+ if (vbMatch) {
2681
+ const vw = parseFloat(vbMatch[3]);
2682
+ const vh = parseFloat(vbMatch[4]);
2683
+ if (vw > 0 && vh > 0) {
2684
+ naturalW = vw;
2685
+ naturalH = vh;
2686
+ }
2687
+ } else {
2688
+ const wMatch = svgText.match(/width=["']([0-9.]+)(?:px)?["']/i);
2689
+ const hMatch = svgText.match(/height=["']([0-9.]+)(?:px)?["']/i);
2690
+ if (wMatch && hMatch) {
2691
+ naturalW = parseFloat(wMatch[1]) || naturalW;
2692
+ naturalH = parseFloat(hMatch[1]) || naturalH;
2693
+ }
2694
+ }
2695
+ } catch {
2696
+ }
2585
2697
  const blob = new Blob([svgText], { type: "image/svg+xml" });
2586
2698
  url = URL.createObjectURL(blob);
2587
2699
  } else {
@@ -2629,7 +2741,7 @@ var MediaPlugin = class {
2629
2741
  scrollWrapper.style.width = "max-content";
2630
2742
  scrollWrapper.style.height = "max-content";
2631
2743
  scrollWrapper.style.display = "flex";
2632
- scrollWrapper.style.justifyContent = "center";
2744
+ scrollWrapper.style.flexDirection = "column";
2633
2745
  scrollWrapper.style.alignItems = "center";
2634
2746
  scrollWrapper.style.padding = "16px";
2635
2747
  scrollWrapper.style.boxSizing = "border-box";
@@ -2640,40 +2752,54 @@ var MediaPlugin = class {
2640
2752
  sizer.style.display = "flex";
2641
2753
  sizer.style.justifyContent = "center";
2642
2754
  sizer.style.alignItems = "center";
2755
+ sizer.style.margin = "auto 0";
2643
2756
  sizer.appendChild(element);
2644
2757
  scrollWrapper.appendChild(sizer);
2645
2758
  ctx.container.style.overflow = "auto";
2646
2759
  ctx.container.style.padding = "0";
2647
2760
  ctx.container.innerHTML = "";
2648
2761
  ctx.container.appendChild(scrollWrapper);
2649
- let naturalW = 800;
2650
- let naturalH = 600;
2651
- let baseW = 800;
2652
- let baseH = 600;
2762
+ let baseW = naturalW;
2763
+ let baseH = naturalH;
2764
+ let fitMode = ctx?.options?.fitMode || "width";
2765
+ let isUserZoomed = false;
2653
2766
  const updateBaseDimensions = () => {
2654
2767
  if (!isImage) return;
2655
2768
  const img = element;
2656
- naturalW = img.naturalWidth || naturalW;
2657
- naturalH = img.naturalHeight || naturalH;
2658
- const availW = Math.max(100, ctx.container.clientWidth - 48);
2659
- const availH = Math.max(100, ctx.container.clientHeight - 48);
2660
- const fitRatio = Math.min(1, availW / naturalW, availH / naturalH);
2769
+ if (img.naturalWidth > 0 && img.naturalHeight > 0) {
2770
+ naturalW = img.naturalWidth;
2771
+ naturalH = img.naturalHeight;
2772
+ }
2773
+ const availW = Math.max(100, ctx.container.clientWidth - 32);
2774
+ const availH = Math.max(100, ctx.container.clientHeight - 32);
2775
+ let fitRatio;
2776
+ if (fitMode === "page") {
2777
+ fitRatio = Math.min(availW / naturalW, availH / naturalH);
2778
+ } else {
2779
+ fitRatio = availW / naturalW;
2780
+ }
2661
2781
  baseW = Math.max(1, Math.round(naturalW * fitRatio));
2662
2782
  baseH = Math.max(1, Math.round(naturalH * fitRatio));
2663
2783
  };
2664
2784
  const applyTransform = () => {
2665
2785
  if (isImage) {
2666
- updateBaseDimensions();
2786
+ if (!isUserZoomed) {
2787
+ updateBaseDimensions();
2788
+ }
2789
+ const availH = Math.max(100, ctx.container.clientHeight - 32);
2667
2790
  const isRotated90 = rotation % 180 !== 0;
2668
2791
  const boxW = Math.round((isRotated90 ? baseH : baseW) * currentZoom);
2669
2792
  const boxH = Math.round((isRotated90 ? baseW : baseH) * currentZoom);
2670
2793
  sizer.style.width = `${boxW}px`;
2671
2794
  sizer.style.height = `${boxH}px`;
2672
- element.style.width = `${baseW}px`;
2673
- element.style.height = `${baseH}px`;
2795
+ sizer.style.margin = boxH < availH ? "auto 0" : "0";
2796
+ const imgW = isRotated90 ? boxH : boxW;
2797
+ const imgH = isRotated90 ? boxW : boxH;
2798
+ element.style.width = `${imgW}px`;
2799
+ element.style.height = `${imgH}px`;
2674
2800
  element.style.maxWidth = "none";
2675
2801
  element.style.maxHeight = "none";
2676
- element.style.transform = `scale(${currentZoom}) rotate(${rotation}deg)`;
2802
+ element.style.transform = rotation ? `rotate(${rotation}deg)` : "none";
2677
2803
  element.style.transformOrigin = "center center";
2678
2804
  element.style.flexShrink = "0";
2679
2805
  } else {
@@ -2693,7 +2819,8 @@ var MediaPlugin = class {
2693
2819
  }
2694
2820
  }
2695
2821
  const ro = typeof ResizeObserver !== "undefined" ? new ResizeObserver(() => {
2696
- if (currentZoom === 1) {
2822
+ if (!isUserZoomed && currentZoom === 1) {
2823
+ updateBaseDimensions();
2697
2824
  applyTransform();
2698
2825
  }
2699
2826
  }) : null;
@@ -2708,28 +2835,49 @@ var MediaPlugin = class {
2708
2835
  return {
2709
2836
  destroy: cleanup,
2710
2837
  zoomIn: isImage ? () => {
2711
- currentZoom += 0.1;
2838
+ isUserZoomed = true;
2839
+ currentZoom = Math.min(5, Math.round((currentZoom + 0.15) * 100) / 100);
2712
2840
  applyTransform();
2713
2841
  } : void 0,
2714
2842
  zoomOut: isImage ? () => {
2715
- currentZoom = Math.max(0.1, currentZoom - 0.1);
2843
+ isUserZoomed = true;
2844
+ currentZoom = Math.max(0.1, Math.round((currentZoom - 0.15) * 100) / 100);
2716
2845
  applyTransform();
2717
2846
  } : void 0,
2718
2847
  getZoom: isImage ? () => currentZoom : void 0,
2719
2848
  setZoom: isImage ? (level) => {
2849
+ isUserZoomed = true;
2720
2850
  currentZoom = level;
2721
2851
  applyTransform();
2722
2852
  } : void 0,
2723
2853
  fitToPage: isImage ? () => {
2854
+ isUserZoomed = false;
2855
+ fitMode = "page";
2856
+ currentZoom = 1;
2857
+ rotation = 0;
2858
+ ctx.container.scrollTop = 0;
2859
+ ctx.container.scrollLeft = 0;
2860
+ updateBaseDimensions();
2861
+ applyTransform();
2862
+ } : void 0,
2863
+ fitToWidth: isImage ? () => {
2864
+ isUserZoomed = false;
2865
+ fitMode = "width";
2724
2866
  currentZoom = 1;
2725
2867
  rotation = 0;
2868
+ ctx.container.scrollTop = 0;
2869
+ ctx.container.scrollLeft = 0;
2870
+ updateBaseDimensions();
2726
2871
  applyTransform();
2727
2872
  } : void 0,
2728
2873
  resetZoom: isImage ? () => {
2874
+ isUserZoomed = false;
2875
+ fitMode = ctx?.options?.fitMode || "width";
2729
2876
  currentZoom = 1;
2730
2877
  rotation = 0;
2731
2878
  ctx.container.scrollTop = 0;
2732
2879
  ctx.container.scrollLeft = 0;
2880
+ updateBaseDimensions();
2733
2881
  applyTransform();
2734
2882
  } : void 0,
2735
2883
  rotateCW: isImage || isVideo ? () => {
@@ -2856,6 +3004,14 @@ var DocxPlugin = class {
2856
3004
  group: "zoom",
2857
3005
  execute: () => instance.resetZoom?.()
2858
3006
  },
3007
+ {
3008
+ id: "fit-width",
3009
+ icon: "fit-width",
3010
+ label: "Fit to Width",
3011
+ type: "button",
3012
+ group: "zoom",
3013
+ execute: () => instance.fitToWidth?.()
3014
+ },
2859
3015
  {
2860
3016
  id: "rotate-cw",
2861
3017
  icon: "rotate-cw",
@@ -3115,13 +3271,19 @@ var DocxPlugin = class {
3115
3271
  }
3116
3272
  scale = 1;
3117
3273
  let rotation = 0;
3118
- let fitMode = "page";
3274
+ let fitMode = ctx?.options?.fitMode || "width";
3119
3275
  let isUserZoomed = false;
3120
- const calculateFitScale = (_mode = fitMode) => {
3276
+ const calculateFitScale = (mode = fitMode) => {
3121
3277
  const activeEl = pageElements[currentPage - 1] || wrapper.querySelector("section.docx") || wrapper;
3122
3278
  const elW = activeEl.offsetWidth || 816;
3279
+ const elH = activeEl.offsetHeight || 1056;
3123
3280
  const availW = Math.max(280, ctx.container.clientWidth - 32);
3281
+ const availH = Math.max(280, ctx.container.clientHeight - 32);
3124
3282
  const sW = availW / elW;
3283
+ const sH = availH / elH;
3284
+ if (mode === "page") {
3285
+ return Math.max(0.35, Math.min(3, Math.min(sW, sH)));
3286
+ }
3125
3287
  return Math.max(0.35, Math.min(3, sW));
3126
3288
  };
3127
3289
  const applyTransform = () => {
@@ -3142,7 +3304,7 @@ var DocxPlugin = class {
3142
3304
  if (typeof ResizeObserver !== "undefined") {
3143
3305
  resizeObserver = new ResizeObserver(() => {
3144
3306
  if (!isUserZoomed) {
3145
- const newFit = calculateFitScale("page");
3307
+ const newFit = calculateFitScale(fitMode);
3146
3308
  if (Math.abs(scale - newFit) > 0.015) {
3147
3309
  scale = newFit;
3148
3310
  applyTransform();
@@ -3152,7 +3314,7 @@ var DocxPlugin = class {
3152
3314
  resizeObserver.observe(ctx.container);
3153
3315
  }
3154
3316
  setTimeout(() => {
3155
- scale = calculateFitScale("page");
3317
+ scale = calculateFitScale(fitMode);
3156
3318
  applyTransform();
3157
3319
  }, 40);
3158
3320
  const cleanup = () => {
@@ -3191,13 +3353,22 @@ var DocxPlugin = class {
3191
3353
  },
3192
3354
  fitToPage: () => {
3193
3355
  isUserZoomed = false;
3356
+ fitMode = "page";
3194
3357
  scale = calculateFitScale("page");
3195
3358
  rotation = 0;
3196
3359
  applyTransform();
3197
3360
  },
3361
+ fitToWidth: () => {
3362
+ isUserZoomed = false;
3363
+ fitMode = "width";
3364
+ scale = calculateFitScale("width");
3365
+ rotation = 0;
3366
+ applyTransform();
3367
+ },
3198
3368
  resetZoom: () => {
3199
3369
  isUserZoomed = false;
3200
- scale = calculateFitScale("page");
3370
+ fitMode = ctx?.options?.fitMode || "width";
3371
+ scale = calculateFitScale(fitMode);
3201
3372
  rotation = 0;
3202
3373
  ctx.container.scrollTop = 0;
3203
3374
  ctx.container.scrollLeft = 0;
@@ -3662,6 +3833,16 @@ var ExcelPlugin = class {
3662
3833
  instance.resetZoom?.();
3663
3834
  }
3664
3835
  },
3836
+ {
3837
+ id: "fit-width",
3838
+ icon: "fit-width",
3839
+ label: "Fit to Width",
3840
+ type: "button",
3841
+ group: "zoom",
3842
+ execute: () => {
3843
+ instance.fitToWidth?.();
3844
+ }
3845
+ },
3665
3846
  {
3666
3847
  id: "download",
3667
3848
  icon: "download",
@@ -3878,6 +4059,11 @@ var ExcelPlugin = class {
3878
4059
  scale = calculateFitScale();
3879
4060
  applyTransform();
3880
4061
  },
4062
+ fitToWidth: () => {
4063
+ isUserZoomed = false;
4064
+ scale = calculateFitScale();
4065
+ applyTransform();
4066
+ },
3881
4067
  resetZoom: () => {
3882
4068
  isUserZoomed = false;
3883
4069
  scale = calculateFitScale();
@@ -4025,6 +4211,16 @@ var CsvPlugin = class {
4025
4211
  instance.resetZoom?.();
4026
4212
  }
4027
4213
  },
4214
+ {
4215
+ id: "fit-width",
4216
+ icon: "fit-width",
4217
+ label: "Fit to Width",
4218
+ type: "button",
4219
+ group: "zoom",
4220
+ execute: () => {
4221
+ instance.fitToWidth?.();
4222
+ }
4223
+ },
4028
4224
  {
4029
4225
  id: "download",
4030
4226
  icon: "download",
@@ -4238,6 +4434,11 @@ var CsvPlugin = class {
4238
4434
  scale = calculateFitScale();
4239
4435
  applyScale();
4240
4436
  },
4437
+ fitToWidth: () => {
4438
+ isUserZoomed = false;
4439
+ scale = calculateFitScale();
4440
+ applyScale();
4441
+ },
4241
4442
  resetZoom: () => {
4242
4443
  isUserZoomed = false;
4243
4444
  scale = calculateFitScale();
@@ -4269,31 +4470,80 @@ function csvPlugin() {
4269
4470
  }
4270
4471
  var CODE_EXTENSIONS = [
4271
4472
  ".txt",
4473
+ ".log",
4474
+ ".ini",
4475
+ ".cfg",
4476
+ ".conf",
4477
+ ".env",
4272
4478
  ".json",
4479
+ ".jsonc",
4480
+ ".json5",
4273
4481
  ".js",
4274
- ".ts",
4482
+ ".mjs",
4483
+ ".cjs",
4275
4484
  ".jsx",
4485
+ ".ts",
4486
+ ".mts",
4487
+ ".cts",
4276
4488
  ".tsx",
4277
4489
  ".html",
4490
+ ".htm",
4491
+ ".xhtml",
4278
4492
  ".css",
4279
4493
  ".scss",
4494
+ ".sass",
4280
4495
  ".less",
4281
4496
  ".md",
4497
+ ".markdown",
4282
4498
  ".xml",
4499
+ ".svg",
4500
+ ".xaml",
4283
4501
  ".yml",
4284
4502
  ".yaml",
4503
+ ".toml",
4285
4504
  ".sh",
4286
4505
  ".bash",
4506
+ ".zsh",
4507
+ ".fish",
4508
+ ".bat",
4509
+ ".cmd",
4510
+ ".ps1",
4287
4511
  ".py",
4512
+ ".pyw",
4288
4513
  ".java",
4514
+ ".class",
4289
4515
  ".c",
4290
4516
  ".cpp",
4517
+ ".cc",
4518
+ ".cxx",
4291
4519
  ".h",
4520
+ ".hpp",
4521
+ ".hxx",
4292
4522
  ".cs",
4523
+ ".csx",
4293
4524
  ".go",
4294
4525
  ".rs",
4295
4526
  ".sql",
4296
- ".php"
4527
+ ".php",
4528
+ ".phtml",
4529
+ ".rb",
4530
+ ".swift",
4531
+ ".kt",
4532
+ ".kts",
4533
+ ".scala",
4534
+ ".r",
4535
+ ".lua",
4536
+ ".pl",
4537
+ ".pm",
4538
+ ".dart",
4539
+ ".graphql",
4540
+ ".gql",
4541
+ ".proto",
4542
+ ".diff",
4543
+ ".patch",
4544
+ ".dockerfile",
4545
+ ".properties",
4546
+ ".gradle"
4297
4547
  ];
4298
4548
  var CodePlugin = class {
4299
4549
  id = "code";
@@ -4311,34 +4561,36 @@ var CodePlugin = class {
4311
4561
  getToolbarActions(instance) {
4312
4562
  const totalPages = instance.getPageCount?.() ?? 1;
4313
4563
  const actions = [];
4314
- actions.push({
4315
- id: "thumbnails",
4316
- icon: "thumbnails",
4317
- label: "Page Thumbnails",
4318
- type: "button",
4319
- group: "navigation",
4320
- execute: () => instance.toggleThumbnails?.()
4321
- });
4322
- actions.push({
4323
- id: "page-nav",
4324
- icon: "",
4325
- label: "Page Navigation",
4326
- type: "page-nav",
4327
- group: "navigation",
4328
- value: instance.getCurrentPage?.() ?? 1,
4329
- max: totalPages,
4330
- execute: (action, page) => {
4331
- const cur = instance.getCurrentPage?.() ?? 1;
4332
- const max = instance.getPageCount?.() ?? 1;
4333
- if (action === "prev") {
4334
- if (cur > 1) instance.goToPage?.(cur - 1);
4335
- } else if (action === "next") {
4336
- if (cur < max) instance.goToPage?.(cur + 1);
4337
- } else if (typeof page === "number") {
4338
- instance.goToPage?.(page);
4564
+ if (totalPages > 1) {
4565
+ actions.push({
4566
+ id: "thumbnails",
4567
+ icon: "thumbnails",
4568
+ label: "Page Thumbnails",
4569
+ type: "button",
4570
+ group: "navigation",
4571
+ execute: () => instance.toggleThumbnails?.()
4572
+ });
4573
+ actions.push({
4574
+ id: "page-nav",
4575
+ icon: "",
4576
+ label: "Page Navigation",
4577
+ type: "page-nav",
4578
+ group: "navigation",
4579
+ value: instance.getCurrentPage?.() ?? 1,
4580
+ max: totalPages,
4581
+ execute: (action, page) => {
4582
+ const cur = instance.getCurrentPage?.() ?? 1;
4583
+ const max = instance.getPageCount?.() ?? 1;
4584
+ if (action === "prev") {
4585
+ if (cur > 1) instance.goToPage?.(cur - 1);
4586
+ } else if (action === "next") {
4587
+ if (cur < max) instance.goToPage?.(cur + 1);
4588
+ } else if (typeof page === "number") {
4589
+ instance.goToPage?.(page);
4590
+ }
4339
4591
  }
4340
- }
4341
- });
4592
+ });
4593
+ }
4342
4594
  actions.push(
4343
4595
  {
4344
4596
  id: "zoom-out",
@@ -4370,6 +4622,16 @@ var CodePlugin = class {
4370
4622
  instance.resetZoom?.();
4371
4623
  }
4372
4624
  },
4625
+ {
4626
+ id: "fit-width",
4627
+ icon: "fit-width",
4628
+ label: "Fit to Width",
4629
+ type: "button",
4630
+ group: "zoom",
4631
+ execute: () => {
4632
+ instance.fitToWidth?.();
4633
+ }
4634
+ },
4373
4635
  {
4374
4636
  id: "copy",
4375
4637
  icon: "copy",
@@ -4465,10 +4727,6 @@ var CodePlugin = class {
4465
4727
  }
4466
4728
  const totalPages = Math.max(1, rawPages.length);
4467
4729
  let currentPage = 1;
4468
- const container = document.createElement("div");
4469
- container.style.width = "100%";
4470
- container.style.height = "100%";
4471
- container.style.overflow = "auto";
4472
4730
  let fontSize = 13;
4473
4731
  let rotation = 0;
4474
4732
  let zoomLevel = 1;
@@ -4477,9 +4735,10 @@ var CodePlugin = class {
4477
4735
  const code = document.createElement("code");
4478
4736
  const sizer = document.createElement("div");
4479
4737
  const scrollWrapper = document.createElement("div");
4738
+ const lineGutter = document.createElement("div");
4739
+ ctx.container.style.overflow = "auto";
4480
4740
  if (isTxt) {
4481
- container.style.overflow = "auto";
4482
- container.style.backgroundColor = "#f1f5f9";
4741
+ ctx.container.style.backgroundColor = "#f1f5f9";
4483
4742
  scrollWrapper.className = "fp-code-scroll-wrapper";
4484
4743
  scrollWrapper.style.minWidth = "100%";
4485
4744
  scrollWrapper.style.minHeight = "100%";
@@ -4514,18 +4773,42 @@ var CodePlugin = class {
4514
4773
  pre.style.transition = "transform 0.15s ease";
4515
4774
  pre.style.flexShrink = "0";
4516
4775
  } else {
4517
- container.style.overflow = "auto";
4518
- container.style.backgroundColor = "#1e1e1e";
4519
- container.style.color = "#d4d4d4";
4520
- container.style.padding = "16px";
4521
- container.style.boxSizing = "border-box";
4776
+ ctx.container.style.backgroundColor = "#1e1e1e";
4777
+ ctx.container.style.color = "#d4d4d4";
4778
+ scrollWrapper.className = "fp-code-scroll-wrapper";
4779
+ scrollWrapper.style.minWidth = "100%";
4780
+ scrollWrapper.style.minHeight = "100%";
4781
+ scrollWrapper.style.width = "max-content";
4782
+ scrollWrapper.style.height = "max-content";
4783
+ scrollWrapper.style.display = "flex";
4784
+ scrollWrapper.style.alignItems = "flex-start";
4785
+ scrollWrapper.style.padding = "16px";
4786
+ scrollWrapper.style.boxSizing = "border-box";
4787
+ const lineCount = fullText.split(/\r?\n/).length || 1;
4788
+ const gutterLines = [];
4789
+ for (let i = 1; i <= lineCount; i++) {
4790
+ gutterLines.push(String(i));
4791
+ }
4792
+ lineGutter.className = "fp-code-gutter";
4793
+ lineGutter.style.userSelect = "none";
4794
+ lineGutter.style.textAlign = "right";
4795
+ lineGutter.style.paddingRight = "16px";
4796
+ lineGutter.style.marginRight = "16px";
4797
+ lineGutter.style.borderRight = "1px solid #333333";
4798
+ lineGutter.style.color = "#858585";
4799
+ lineGutter.style.fontFamily = "Consolas, Menlo, Monaco, 'Courier New', monospace";
4800
+ lineGutter.style.fontSize = `${fontSize}px`;
4801
+ lineGutter.style.lineHeight = "1.6";
4802
+ lineGutter.style.flexShrink = "0";
4803
+ lineGutter.textContent = gutterLines.join("\n");
4522
4804
  pre.style.margin = "0";
4523
- pre.style.fontFamily = "Consolas, Menlo, Monaco, monospace";
4805
+ pre.style.fontFamily = "Consolas, Menlo, Monaco, 'Courier New', monospace";
4524
4806
  pre.style.fontSize = `${fontSize}px`;
4525
- pre.style.lineHeight = "1.5";
4526
- pre.style.whiteSpace = "pre-wrap";
4527
- pre.style.wordBreak = "break-all";
4528
- pre.style.transformOrigin = "top left";
4807
+ pre.style.lineHeight = "1.6";
4808
+ pre.style.whiteSpace = "pre";
4809
+ pre.style.wordBreak = "normal";
4810
+ pre.style.overflowWrap = "normal";
4811
+ pre.style.flex = "1";
4529
4812
  }
4530
4813
  const ext = (ctx.metadata.extension || "").replace(".", "");
4531
4814
  const renderCodePage = (text) => {
@@ -4545,25 +4828,27 @@ var CodePlugin = class {
4545
4828
  };
4546
4829
  renderCodePage(rawPages[0] || (isTxt ? "" : fullText));
4547
4830
  pre.appendChild(code);
4831
+ ctx.container.innerHTML = "";
4548
4832
  if (isTxt) {
4549
4833
  sizer.appendChild(pre);
4550
4834
  scrollWrapper.appendChild(sizer);
4551
- container.appendChild(scrollWrapper);
4835
+ ctx.container.appendChild(scrollWrapper);
4552
4836
  } else {
4553
- container.appendChild(pre);
4837
+ scrollWrapper.appendChild(lineGutter);
4838
+ scrollWrapper.appendChild(pre);
4839
+ ctx.container.appendChild(scrollWrapper);
4554
4840
  }
4555
4841
  const showPage = (pageNum) => {
4556
4842
  currentPage = Math.max(1, Math.min(totalPages, pageNum));
4557
4843
  renderCodePage(rawPages[currentPage - 1] || (isTxt ? "" : fullText));
4558
- container.scrollTop = 0;
4844
+ ctx.container.scrollTop = 0;
4559
4845
  ctx.emit("page-change", { page: currentPage, total: totalPages });
4560
4846
  };
4561
4847
  if (totalPages > 1) {
4562
4848
  showPage(1);
4563
4849
  }
4564
- ctx.container.appendChild(container);
4565
4850
  const calculateTxtFit = () => {
4566
- const availW = Math.max(280, container.clientWidth - 32);
4851
+ const availW = Math.max(280, ctx.container.clientWidth - 32);
4567
4852
  return Math.max(0.4, Math.min(3, availW / 816));
4568
4853
  };
4569
4854
  const updateTransform = () => {
@@ -4581,6 +4866,7 @@ var CodePlugin = class {
4581
4866
  } else {
4582
4867
  pre.style.transform = `rotate(${rotation}deg)`;
4583
4868
  pre.style.fontSize = `${fontSize}px`;
4869
+ lineGutter.style.fontSize = `${fontSize}px`;
4584
4870
  }
4585
4871
  };
4586
4872
  let resizeObserver = null;
@@ -4595,11 +4881,11 @@ var CodePlugin = class {
4595
4881
  updateTransform();
4596
4882
  }
4597
4883
  }) : null;
4598
- resizeObserver?.observe(container);
4884
+ resizeObserver?.observe(ctx.container);
4599
4885
  }
4600
4886
  const cleanup = () => {
4601
4887
  resizeObserver?.disconnect();
4602
- container.remove();
4888
+ scrollWrapper.remove();
4603
4889
  ctx.container.innerHTML = "";
4604
4890
  };
4605
4891
  ctx.signal.addEventListener("abort", cleanup);
@@ -4644,7 +4930,7 @@ var CodePlugin = class {
4644
4930
  if (isTxt) {
4645
4931
  zoomLevel = Math.min(3.5, zoomLevel + 0.15);
4646
4932
  } else {
4647
- fontSize = Math.min(32, fontSize + 2);
4933
+ fontSize = Math.min(48, fontSize + 2);
4648
4934
  }
4649
4935
  updateTransform();
4650
4936
  },
@@ -4653,7 +4939,7 @@ var CodePlugin = class {
4653
4939
  if (isTxt) {
4654
4940
  zoomLevel = Math.max(0.1, zoomLevel - 0.15);
4655
4941
  } else {
4656
- fontSize = Math.max(8, fontSize - 2);
4942
+ fontSize = Math.max(9, fontSize - 2);
4657
4943
  }
4658
4944
  updateTransform();
4659
4945
  },
@@ -4674,13 +4960,20 @@ var CodePlugin = class {
4674
4960
  zoomLevel = isTxt ? calculateTxtFit() : 1;
4675
4961
  updateTransform();
4676
4962
  },
4963
+ fitToWidth: () => {
4964
+ isUserZoomed = false;
4965
+ fontSize = 13;
4966
+ rotation = 0;
4967
+ zoomLevel = isTxt ? calculateTxtFit() : 1;
4968
+ updateTransform();
4969
+ },
4677
4970
  resetZoom: () => {
4678
4971
  isUserZoomed = false;
4679
4972
  fontSize = 13;
4680
4973
  rotation = 0;
4681
4974
  zoomLevel = isTxt ? calculateTxtFit() : 1;
4682
- container.scrollTop = 0;
4683
- container.scrollLeft = 0;
4975
+ ctx.container.scrollTop = 0;
4976
+ ctx.container.scrollLeft = 0;
4684
4977
  updateTransform();
4685
4978
  },
4686
4979
  rotateCW: () => {
@@ -4758,6 +5051,14 @@ var ArchivePlugin = class {
4758
5051
  group: "zoom",
4759
5052
  execute: () => instance.resetZoom?.()
4760
5053
  },
5054
+ {
5055
+ id: "fit-width",
5056
+ icon: "fit-width",
5057
+ label: "Fit to Width",
5058
+ type: "button",
5059
+ group: "zoom",
5060
+ execute: () => instance.fitToWidth?.()
5061
+ },
4761
5062
  {
4762
5063
  id: "download",
4763
5064
  icon: "download",
@@ -4955,6 +5256,10 @@ var ArchivePlugin = class {
4955
5256
  scale = 1;
4956
5257
  applyTransform();
4957
5258
  },
5259
+ fitToWidth: () => {
5260
+ scale = 1;
5261
+ applyTransform();
5262
+ },
4958
5263
  resetZoom: () => {
4959
5264
  scale = 1;
4960
5265
  wrapper.scrollTop = 0;
@@ -4990,7 +5295,7 @@ var MarkdownPlugin = class {
4990
5295
  {
4991
5296
  id: "zoom-out",
4992
5297
  icon: "zoom-out",
4993
- label: "Decrease Font",
5298
+ label: "Zoom Out",
4994
5299
  type: "button",
4995
5300
  group: "zoom",
4996
5301
  execute: () => instance.zoomOut?.()
@@ -4998,19 +5303,11 @@ var MarkdownPlugin = class {
4998
5303
  {
4999
5304
  id: "zoom-in",
5000
5305
  icon: "zoom-in",
5001
- label: "Increase Font",
5306
+ label: "Zoom In",
5002
5307
  type: "button",
5003
5308
  group: "zoom",
5004
5309
  execute: () => instance.zoomIn?.()
5005
5310
  },
5006
- {
5007
- id: "fit-page",
5008
- icon: "fit-page",
5009
- label: "Default Size",
5010
- type: "button",
5011
- group: "zoom",
5012
- execute: () => instance.fitToPage?.()
5013
- },
5014
5311
  {
5015
5312
  id: "reset-zoom",
5016
5313
  icon: "reset-zoom",
@@ -5019,6 +5316,22 @@ var MarkdownPlugin = class {
5019
5316
  group: "zoom",
5020
5317
  execute: () => instance.resetZoom?.()
5021
5318
  },
5319
+ {
5320
+ id: "fit-width",
5321
+ icon: "fit-width",
5322
+ label: "Fit to Width",
5323
+ type: "button",
5324
+ group: "zoom",
5325
+ execute: () => instance.fitToWidth?.()
5326
+ },
5327
+ {
5328
+ id: "fit-page",
5329
+ icon: "fit-page",
5330
+ label: "Fit to Page",
5331
+ type: "button",
5332
+ group: "zoom",
5333
+ execute: () => instance.fitToPage?.()
5334
+ },
5022
5335
  {
5023
5336
  id: "copy",
5024
5337
  icon: "copy",
@@ -5042,10 +5355,18 @@ var MarkdownPlugin = class {
5042
5355
  type: "button",
5043
5356
  group: "actions",
5044
5357
  execute: () => instance.print?.()
5045
- }
5046
- ];
5047
- }
5048
- async render(ctx) {
5358
+ },
5359
+ {
5360
+ id: "open-window",
5361
+ icon: "open-window",
5362
+ label: "Open in Separate Full Window",
5363
+ type: "button",
5364
+ group: "actions",
5365
+ execute: () => instance.openInSeparateWindow?.()
5366
+ }
5367
+ ];
5368
+ }
5369
+ async render(ctx) {
5049
5370
  const text = new TextDecoder("utf-8", { fatal: false }).decode(ctx.buffer);
5050
5371
  const rawHtml = await marked.parse(text, {
5051
5372
  gfm: true,
@@ -5054,35 +5375,57 @@ var MarkdownPlugin = class {
5054
5375
  const cleanHtml = DOMPurify6.sanitize(rawHtml, {
5055
5376
  USE_PROFILES: { html: true }
5056
5377
  });
5057
- const wrapper = document.createElement("div");
5058
- wrapper.className = "fp-markdown-wrapper";
5059
- wrapper.style.cssText = `
5060
- width: 100%;
5061
- height: 100%;
5062
- overflow: auto;
5063
- padding: 32px 40px;
5378
+ const scrollWrapper = document.createElement("div");
5379
+ scrollWrapper.className = "fp-markdown-scroll-wrapper";
5380
+ scrollWrapper.style.minWidth = "100%";
5381
+ scrollWrapper.style.minHeight = "100%";
5382
+ scrollWrapper.style.width = "max-content";
5383
+ scrollWrapper.style.height = "max-content";
5384
+ scrollWrapper.style.display = "flex";
5385
+ scrollWrapper.style.justifyContent = "center";
5386
+ scrollWrapper.style.alignItems = "flex-start";
5387
+ scrollWrapper.style.padding = "24px 16px";
5388
+ scrollWrapper.style.boxSizing = "border-box";
5389
+ const sizer = document.createElement("div");
5390
+ sizer.className = "fp-markdown-sizer";
5391
+ sizer.style.position = "relative";
5392
+ sizer.style.flexShrink = "0";
5393
+ sizer.style.display = "flex";
5394
+ sizer.style.justifyContent = "center";
5395
+ sizer.style.alignItems = "flex-start";
5396
+ const docCard = document.createElement("div");
5397
+ docCard.className = "fp-markdown-doc-card";
5398
+ docCard.style.cssText = `
5399
+ width: 860px;
5400
+ min-height: 600px;
5401
+ padding: 40px 48px;
5064
5402
  box-sizing: border-box;
5065
5403
  line-height: 1.6;
5066
5404
  font-size: 15px;
5067
5405
  color: var(--fp-text, #24292f);
5068
5406
  background: var(--fp-bg, #ffffff);
5407
+ border-radius: 6px;
5408
+ box-shadow: 0 4px 24px rgba(0, 0, 0, 0.08);
5069
5409
  font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Noto Sans", Helvetica, Arial, sans-serif;
5410
+ transform-origin: top center;
5411
+ transition: transform 0.15s ease;
5412
+ flex-shrink: 0;
5070
5413
  `;
5071
- wrapper.innerHTML = `
5414
+ docCard.innerHTML = `
5072
5415
  <style>
5073
- .fp-markdown-wrapper h1, .fp-markdown-wrapper h2, .fp-markdown-wrapper h3,
5074
- .fp-markdown-wrapper h4, .fp-markdown-wrapper h5, .fp-markdown-wrapper h6 {
5416
+ .fp-markdown-doc-card h1, .fp-markdown-doc-card h2, .fp-markdown-doc-card h3,
5417
+ .fp-markdown-doc-card h4, .fp-markdown-doc-card h5, .fp-markdown-doc-card h6 {
5075
5418
  margin-top: 24px;
5076
5419
  margin-bottom: 16px;
5077
5420
  font-weight: 600;
5078
5421
  line-height: 1.25;
5079
5422
  color: var(--fp-text, #1f2328);
5080
5423
  }
5081
- .fp-markdown-wrapper h1 { font-size: 2em; padding-bottom: 0.3em; border-bottom: 1px solid var(--fp-border, #d0d7de); }
5082
- .fp-markdown-wrapper h2 { font-size: 1.5em; padding-bottom: 0.3em; border-bottom: 1px solid var(--fp-border, #d0d7de); }
5083
- .fp-markdown-wrapper h3 { font-size: 1.25em; }
5084
- .fp-markdown-wrapper p { margin-top: 0; margin-bottom: 16px; }
5085
- .fp-markdown-wrapper table {
5424
+ .fp-markdown-doc-card h1 { font-size: 2em; padding-bottom: 0.3em; border-bottom: 1px solid var(--fp-border, #d0d7de); }
5425
+ .fp-markdown-doc-card h2 { font-size: 1.5em; padding-bottom: 0.3em; border-bottom: 1px solid var(--fp-border, #d0d7de); }
5426
+ .fp-markdown-doc-card h3 { font-size: 1.25em; }
5427
+ .fp-markdown-doc-card p { margin-top: 0; margin-bottom: 16px; }
5428
+ .fp-markdown-doc-card table {
5086
5429
  border-spacing: 0;
5087
5430
  border-collapse: collapse;
5088
5431
  margin-top: 0;
@@ -5090,20 +5433,20 @@ var MarkdownPlugin = class {
5090
5433
  width: 100%;
5091
5434
  overflow: auto;
5092
5435
  }
5093
- .fp-markdown-wrapper table th, .fp-markdown-wrapper table td {
5436
+ .fp-markdown-doc-card table th, .fp-markdown-doc-card table td {
5094
5437
  padding: 6px 13px;
5095
5438
  border: 1px solid var(--fp-border, #d0d7de);
5096
5439
  }
5097
- .fp-markdown-wrapper table tr:nth-child(2n) {
5440
+ .fp-markdown-doc-card table tr:nth-child(2n) {
5098
5441
  background-color: var(--fp-toolbar-bg, #f6f8fa);
5099
5442
  }
5100
- .fp-markdown-wrapper blockquote {
5443
+ .fp-markdown-doc-card blockquote {
5101
5444
  margin: 0 0 16px 0;
5102
5445
  padding: 0 1em;
5103
5446
  color: var(--fp-text-muted, #59636e);
5104
5447
  border-left: 0.25em solid var(--fp-border, #d0d7de);
5105
5448
  }
5106
- .fp-markdown-wrapper pre {
5449
+ .fp-markdown-doc-card pre {
5107
5450
  padding: 16px;
5108
5451
  overflow: auto;
5109
5452
  font-size: 85%;
@@ -5112,7 +5455,7 @@ var MarkdownPlugin = class {
5112
5455
  border-radius: 6px;
5113
5456
  border: 1px solid var(--fp-border, #d0d7de);
5114
5457
  }
5115
- .fp-markdown-wrapper code {
5458
+ .fp-markdown-doc-card code {
5116
5459
  padding: 0.2em 0.4em;
5117
5460
  margin: 0;
5118
5461
  font-size: 85%;
@@ -5120,16 +5463,16 @@ var MarkdownPlugin = class {
5120
5463
  border-radius: 4px;
5121
5464
  font-family: ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, monospace;
5122
5465
  }
5123
- .fp-markdown-wrapper pre code {
5466
+ .fp-markdown-doc-card pre code {
5124
5467
  padding: 0;
5125
5468
  background: transparent;
5126
5469
  }
5127
- .fp-markdown-wrapper ul, .fp-markdown-wrapper ol {
5470
+ .fp-markdown-doc-card ul, .fp-markdown-doc-card ol {
5128
5471
  padding-left: 2em;
5129
5472
  margin-top: 0;
5130
5473
  margin-bottom: 16px;
5131
5474
  }
5132
- .fp-markdown-wrapper hr {
5475
+ .fp-markdown-doc-card hr {
5133
5476
  height: 0.25em;
5134
5477
  padding: 0;
5135
5478
  margin: 24px 0;
@@ -5137,46 +5480,95 @@ var MarkdownPlugin = class {
5137
5480
  border: 0;
5138
5481
  }
5139
5482
  </style>
5140
- <div class="fp-markdown-content" style="max-width: 860px; margin: 0 auto;">
5483
+ <div class="fp-markdown-body">
5141
5484
  ${cleanHtml}
5142
5485
  </div>
5143
5486
  `;
5144
- wrapper.querySelectorAll("pre code").forEach((block) => {
5487
+ docCard.querySelectorAll("pre code").forEach((block) => {
5145
5488
  hljs.highlightElement(block);
5146
5489
  });
5490
+ sizer.appendChild(docCard);
5491
+ scrollWrapper.appendChild(sizer);
5147
5492
  ctx.container.innerHTML = "";
5148
5493
  ctx.container.style.overflow = "auto";
5149
- ctx.container.appendChild(wrapper);
5150
- let fontSize = 15;
5494
+ ctx.container.style.backgroundColor = "#f1f5f9";
5495
+ ctx.container.appendChild(scrollWrapper);
5496
+ let scale = 1;
5497
+ let isUserZoomed = false;
5498
+ const calculateFitScale = () => {
5499
+ const availW = Math.max(280, ctx.container.clientWidth - 48);
5500
+ if (availW < 860) {
5501
+ return Math.max(0.35, availW / 860);
5502
+ }
5503
+ return 1;
5504
+ };
5505
+ const applyTransform = () => {
5506
+ const baseW = 860;
5507
+ const baseH = docCard.offsetHeight || 600;
5508
+ const scaledW = Math.round(baseW * scale);
5509
+ const scaledH = Math.round(baseH * scale);
5510
+ sizer.style.width = `${scaledW}px`;
5511
+ sizer.style.height = `${scaledH}px`;
5512
+ docCard.style.width = `${baseW}px`;
5513
+ docCard.style.transform = `scale(${scale})`;
5514
+ docCard.style.transformOrigin = scaledW > ctx.container.clientWidth - 32 ? "top left" : "top center";
5515
+ };
5516
+ const ro = typeof ResizeObserver !== "undefined" ? new ResizeObserver(() => {
5517
+ if (!isUserZoomed) {
5518
+ scale = calculateFitScale();
5519
+ applyTransform();
5520
+ }
5521
+ }) : null;
5522
+ ro?.observe(ctx.container);
5523
+ requestAnimationFrame(() => {
5524
+ if (!isUserZoomed) {
5525
+ scale = calculateFitScale();
5526
+ }
5527
+ applyTransform();
5528
+ });
5151
5529
  const cleanup = () => {
5152
- wrapper.remove();
5530
+ ro?.disconnect();
5531
+ scrollWrapper.remove();
5153
5532
  ctx.container.innerHTML = "";
5154
5533
  };
5155
5534
  ctx.signal.addEventListener("abort", cleanup);
5156
5535
  return {
5157
5536
  destroy: cleanup,
5158
5537
  zoomIn: () => {
5159
- fontSize = Math.min(28, fontSize + 2);
5160
- wrapper.style.fontSize = `${fontSize}px`;
5538
+ isUserZoomed = true;
5539
+ scale = Math.min(3.5, scale + 0.15);
5540
+ applyTransform();
5161
5541
  },
5162
5542
  zoomOut: () => {
5163
- fontSize = Math.max(10, fontSize - 2);
5164
- wrapper.style.fontSize = `${fontSize}px`;
5543
+ isUserZoomed = true;
5544
+ scale = Math.max(0.25, scale - 0.15);
5545
+ applyTransform();
5165
5546
  },
5166
- getZoom: () => fontSize / 15,
5547
+ getZoom: () => scale,
5167
5548
  setZoom: (level) => {
5168
- fontSize = Math.round(15 * level);
5169
- wrapper.style.fontSize = `${fontSize}px`;
5549
+ isUserZoomed = true;
5550
+ scale = level;
5551
+ applyTransform();
5170
5552
  },
5171
5553
  fitToPage: () => {
5172
- fontSize = 15;
5173
- wrapper.style.fontSize = "15px";
5554
+ isUserZoomed = false;
5555
+ scale = calculateFitScale();
5556
+ applyTransform();
5557
+ },
5558
+ fitToWidth: () => {
5559
+ isUserZoomed = false;
5560
+ scale = calculateFitScale();
5561
+ applyTransform();
5174
5562
  },
5175
5563
  resetZoom: () => {
5176
- fontSize = 15;
5177
- wrapper.style.fontSize = "15px";
5564
+ isUserZoomed = false;
5565
+ scale = calculateFitScale();
5178
5566
  ctx.container.scrollTop = 0;
5179
5567
  ctx.container.scrollLeft = 0;
5568
+ applyTransform();
5569
+ },
5570
+ openInSeparateWindow: () => {
5571
+ ctx?.openInSeparateWindow?.();
5180
5572
  },
5181
5573
  download: () => {
5182
5574
  downloadFile(ctx.buffer, ctx.metadata.name || "document.md", "text/markdown");
@@ -5279,6 +5671,14 @@ var PptxPlugin = class {
5279
5671
  group: "zoom",
5280
5672
  execute: () => instance.resetZoom?.()
5281
5673
  },
5674
+ {
5675
+ id: "fit-width",
5676
+ icon: "fit-width",
5677
+ label: "Fit to Width",
5678
+ type: "button",
5679
+ group: "zoom",
5680
+ execute: () => instance.fitToWidth?.()
5681
+ },
5282
5682
  {
5283
5683
  id: "rotate-cw",
5284
5684
  icon: "rotate-cw",
@@ -5362,12 +5762,17 @@ var PptxPlugin = class {
5362
5762
  ctx.container.innerHTML = "";
5363
5763
  ctx.container.style.overflow = "auto";
5364
5764
  ctx.container.appendChild(wrapper);
5365
- const calculateFitScale = () => {
5366
- const availW = Math.max(200, ctx.container.clientWidth - 48);
5367
- const availH = Math.max(200, ctx.container.clientHeight - 72);
5765
+ let fitMode = ctx?.options?.fitMode || "width";
5766
+ let isUserZoomed = false;
5767
+ const calculateFitScale = (mode = fitMode) => {
5768
+ const availW = Math.max(200, ctx.container.clientWidth - 32);
5769
+ const availH = Math.max(200, ctx.container.clientHeight - 32);
5368
5770
  const cW = canvas.offsetWidth || 1280;
5369
5771
  const cH = canvas.offsetHeight || 720;
5370
- return Math.min(1, Math.min(availW / cW, availH / cH));
5772
+ if (mode === "page") {
5773
+ return Math.min(2.5, Math.min(availW / cW, availH / cH));
5774
+ }
5775
+ return Math.min(2.5, availW / cW);
5371
5776
  };
5372
5777
  const applyTransform = () => {
5373
5778
  const cW = canvas.offsetWidth || 1280;
@@ -5386,14 +5791,24 @@ var PptxPlugin = class {
5386
5791
  try {
5387
5792
  await renderer.renderSlide(currentSlide - 1, canvas, 1280);
5388
5793
  ctx.emit("page-change", { page: currentSlide, totalPages: slideCount });
5389
- scale = calculateFitScale();
5794
+ if (!isUserZoomed) {
5795
+ scale = calculateFitScale(fitMode);
5796
+ }
5390
5797
  applyTransform();
5391
5798
  } catch (err) {
5392
5799
  console.error("[PptxPlugin] Failed to render slide:", err);
5393
5800
  }
5394
5801
  };
5395
5802
  await renderCurrentSlide();
5803
+ const ro = typeof ResizeObserver !== "undefined" ? new ResizeObserver(() => {
5804
+ if (!isUserZoomed) {
5805
+ scale = calculateFitScale(fitMode);
5806
+ applyTransform();
5807
+ }
5808
+ }) : null;
5809
+ ro?.observe(ctx.container);
5396
5810
  const cleanup = () => {
5811
+ ro?.disconnect();
5397
5812
  renderer.destroy();
5398
5813
  wrapper.remove();
5399
5814
  ctx.container.innerHTML = "";
@@ -5410,28 +5825,44 @@ var PptxPlugin = class {
5410
5825
  getPageCount: () => slideCount,
5411
5826
  getCurrentPage: () => currentSlide,
5412
5827
  zoomIn: () => {
5828
+ isUserZoomed = true;
5413
5829
  scale += 0.15;
5414
5830
  applyTransform();
5415
5831
  },
5416
5832
  zoomOut: () => {
5833
+ isUserZoomed = true;
5417
5834
  scale = Math.max(0.2, scale - 0.15);
5418
5835
  applyTransform();
5419
5836
  },
5420
5837
  getZoom: () => scale,
5421
5838
  setZoom: (level) => {
5839
+ isUserZoomed = true;
5422
5840
  scale = level;
5423
5841
  applyTransform();
5424
5842
  },
5425
5843
  fitToPage: () => {
5426
- scale = calculateFitScale();
5844
+ isUserZoomed = false;
5845
+ fitMode = "page";
5846
+ scale = calculateFitScale("page");
5847
+ rotation = 0;
5848
+ applyTransform();
5849
+ },
5850
+ fitToWidth: () => {
5851
+ isUserZoomed = false;
5852
+ fitMode = "width";
5853
+ scale = calculateFitScale("width");
5427
5854
  rotation = 0;
5428
5855
  applyTransform();
5429
5856
  },
5430
5857
  resetZoom: () => {
5431
- scale = calculateFitScale();
5858
+ isUserZoomed = false;
5859
+ fitMode = ctx?.options?.fitMode || "width";
5860
+ scale = calculateFitScale(fitMode);
5432
5861
  rotation = 0;
5433
5862
  wrapper.scrollTop = 0;
5434
5863
  wrapper.scrollLeft = 0;
5864
+ ctx.container.scrollTop = 0;
5865
+ ctx.container.scrollLeft = 0;
5435
5866
  applyTransform();
5436
5867
  },
5437
5868
  rotateCW: () => {
@@ -5876,6 +6307,14 @@ var RtfPlugin = class {
5876
6307
  group: "zoom",
5877
6308
  execute: () => instance.resetZoom?.()
5878
6309
  },
6310
+ {
6311
+ id: "fit-width",
6312
+ icon: "fit-width",
6313
+ label: "Fit to Width",
6314
+ type: "button",
6315
+ group: "zoom",
6316
+ execute: () => instance.fitToWidth?.()
6317
+ },
5879
6318
  {
5880
6319
  id: "rotate-cw",
5881
6320
  icon: "rotate-cw",
@@ -6364,6 +6803,13 @@ var RtfPlugin = class {
6364
6803
  applyTransform();
6365
6804
  },
6366
6805
  fitToPage: () => {
6806
+ isUserZoomed = false;
6807
+ fitMode = "page";
6808
+ scale = calculateFitScale("page");
6809
+ rotation = 0;
6810
+ applyTransform();
6811
+ },
6812
+ fitToWidth: () => {
6367
6813
  isUserZoomed = false;
6368
6814
  fitMode = "width";
6369
6815
  scale = calculateFitScale("width");
@@ -6372,8 +6818,8 @@ var RtfPlugin = class {
6372
6818
  },
6373
6819
  resetZoom: () => {
6374
6820
  isUserZoomed = false;
6375
- fitMode = "width";
6376
- scale = calculateFitScale("width");
6821
+ fitMode = ctx?.options?.fitMode || "width";
6822
+ scale = calculateFitScale(fitMode);
6377
6823
  rotation = 0;
6378
6824
  ctx.container.scrollTop = 0;
6379
6825
  ctx.container.scrollLeft = 0;
@@ -6438,14 +6884,6 @@ var HtmlPreviewPlugin = class {
6438
6884
  group: "zoom",
6439
6885
  execute: () => instance.zoomIn?.()
6440
6886
  },
6441
- {
6442
- id: "fit-page",
6443
- icon: "fit-page",
6444
- label: "Fit to Page",
6445
- type: "button",
6446
- group: "zoom",
6447
- execute: () => instance.fitToPage?.()
6448
- },
6449
6887
  {
6450
6888
  id: "reset-zoom",
6451
6889
  icon: "reset-zoom",
@@ -6454,6 +6892,22 @@ var HtmlPreviewPlugin = class {
6454
6892
  group: "zoom",
6455
6893
  execute: () => instance.resetZoom?.()
6456
6894
  },
6895
+ {
6896
+ id: "fit-width",
6897
+ icon: "fit-width",
6898
+ label: "Fit to Width",
6899
+ type: "button",
6900
+ group: "zoom",
6901
+ execute: () => instance.fitToWidth?.()
6902
+ },
6903
+ {
6904
+ id: "fit-page",
6905
+ icon: "fit-page",
6906
+ label: "Fit to Page",
6907
+ type: "button",
6908
+ group: "zoom",
6909
+ execute: () => instance.fitToPage?.()
6910
+ },
6457
6911
  {
6458
6912
  id: "copy",
6459
6913
  icon: "copy",
@@ -6477,6 +6931,14 @@ var HtmlPreviewPlugin = class {
6477
6931
  type: "button",
6478
6932
  group: "actions",
6479
6933
  execute: () => instance.print?.()
6934
+ },
6935
+ {
6936
+ id: "open-window",
6937
+ icon: "open-window",
6938
+ label: "Open in Separate Full Window",
6939
+ type: "button",
6940
+ group: "actions",
6941
+ execute: () => instance.openInSeparateWindow?.()
6480
6942
  }
6481
6943
  ];
6482
6944
  }
@@ -6487,27 +6949,39 @@ var HtmlPreviewPlugin = class {
6487
6949
  ADD_TAGS: ["style", "link"],
6488
6950
  ADD_ATTR: ["target", "rel"]
6489
6951
  });
6952
+ const scrollWrapper = document.createElement("div");
6953
+ scrollWrapper.className = "fp-html-scroll-wrapper";
6954
+ scrollWrapper.style.minWidth = "100%";
6955
+ scrollWrapper.style.minHeight = "100%";
6956
+ scrollWrapper.style.width = "max-content";
6957
+ scrollWrapper.style.height = "max-content";
6958
+ scrollWrapper.style.display = "flex";
6959
+ scrollWrapper.style.justifyContent = "flex-start";
6960
+ scrollWrapper.style.alignItems = "flex-start";
6961
+ scrollWrapper.style.boxSizing = "border-box";
6490
6962
  const sizer = document.createElement("div");
6491
6963
  sizer.className = "fp-html-sizer";
6492
6964
  sizer.style.position = "relative";
6965
+ sizer.style.flexShrink = "0";
6493
6966
  const iframe = document.createElement("iframe");
6494
6967
  iframe.className = "fp-html-iframe";
6495
6968
  iframe.style.border = "none";
6496
6969
  iframe.style.backgroundColor = "#ffffff";
6497
6970
  iframe.style.transformOrigin = "top left";
6498
- iframe.style.transition = "transform 0.2s ease";
6971
+ iframe.style.transition = "transform 0.15s ease";
6499
6972
  iframe.sandbox.add("allow-same-origin");
6500
6973
  sizer.appendChild(iframe);
6974
+ scrollWrapper.appendChild(sizer);
6501
6975
  ctx.container.style.overflow = "auto";
6502
6976
  ctx.container.style.width = "100%";
6503
6977
  ctx.container.style.height = "100%";
6504
6978
  ctx.container.innerHTML = "";
6505
- ctx.container.appendChild(sizer);
6979
+ ctx.container.appendChild(scrollWrapper);
6506
6980
  iframe.srcdoc = sanitized;
6507
6981
  let scale = 1;
6982
+ let baseW = Math.max(600, ctx.container.clientWidth || 800);
6983
+ let baseH = Math.max(400, ctx.container.clientHeight || 600);
6508
6984
  const applyTransform = () => {
6509
- const baseW = Math.max(600, ctx.container.clientWidth || 800);
6510
- const baseH = Math.max(400, ctx.container.clientHeight || 600);
6511
6985
  const scaledW = Math.round(baseW * scale);
6512
6986
  const scaledH = Math.round(baseH * scale);
6513
6987
  sizer.style.width = `${scaledW}px`;
@@ -6520,22 +6994,33 @@ var HtmlPreviewPlugin = class {
6520
6994
  iframe.style.transform = `scale(${scale})`;
6521
6995
  iframe.style.transformOrigin = "top left";
6522
6996
  };
6997
+ const ro = typeof ResizeObserver !== "undefined" ? new ResizeObserver(() => {
6998
+ if (Math.abs(scale - 1) < 0.05) {
6999
+ baseW = Math.max(600, ctx.container.clientWidth || 800);
7000
+ baseH = Math.max(400, ctx.container.clientHeight || 600);
7001
+ applyTransform();
7002
+ }
7003
+ }) : null;
7004
+ ro?.observe(ctx.container);
6523
7005
  requestAnimationFrame(() => {
7006
+ baseW = Math.max(600, ctx.container.clientWidth || 800);
7007
+ baseH = Math.max(400, ctx.container.clientHeight || 600);
6524
7008
  applyTransform();
6525
7009
  });
6526
7010
  const cleanup = () => {
6527
- sizer.remove();
7011
+ ro?.disconnect();
7012
+ scrollWrapper.remove();
6528
7013
  ctx.container.innerHTML = "";
6529
7014
  };
6530
7015
  ctx.signal.addEventListener("abort", cleanup);
6531
7016
  return {
6532
7017
  destroy: cleanup,
6533
7018
  zoomIn: () => {
6534
- scale += 0.1;
7019
+ scale = Math.min(3.5, scale + 0.15);
6535
7020
  applyTransform();
6536
7021
  },
6537
7022
  zoomOut: () => {
6538
- scale = Math.max(0.2, scale - 0.1);
7023
+ scale = Math.max(0.25, scale - 0.15);
6539
7024
  applyTransform();
6540
7025
  },
6541
7026
  getZoom: () => scale,
@@ -6547,14 +7032,21 @@ var HtmlPreviewPlugin = class {
6547
7032
  scale = 1;
6548
7033
  applyTransform();
6549
7034
  },
7035
+ fitToWidth: () => {
7036
+ scale = 1;
7037
+ applyTransform();
7038
+ },
6550
7039
  resetZoom: () => {
6551
7040
  scale = 1;
6552
7041
  ctx.container.scrollTop = 0;
6553
7042
  ctx.container.scrollLeft = 0;
6554
7043
  applyTransform();
6555
7044
  },
7045
+ openInSeparateWindow: () => {
7046
+ ctx?.openInSeparateWindow?.();
7047
+ },
6556
7048
  copy: () => {
6557
- navigator.clipboard.writeText(rawHtml);
7049
+ navigator.clipboard?.writeText(rawHtml);
6558
7050
  },
6559
7051
  download: () => {
6560
7052
  const blob = new Blob([ctx.buffer], { type: "text/html" });
@@ -6661,6 +7153,14 @@ var OpenDocumentPlugin = class {
6661
7153
  group: "zoom",
6662
7154
  execute: () => instance.resetZoom?.()
6663
7155
  },
7156
+ {
7157
+ id: "fit-width",
7158
+ icon: "fit-width",
7159
+ label: "Fit to Width",
7160
+ type: "button",
7161
+ group: "zoom",
7162
+ execute: () => instance.fitToWidth?.()
7163
+ },
6664
7164
  {
6665
7165
  id: "rotate-cw",
6666
7166
  icon: "rotate-cw",
@@ -6777,7 +7277,10 @@ var OpenDocumentPlugin = class {
6777
7277
  const sW = availW / elW;
6778
7278
  const sH = availH / (isPresentation ? 540 : singlePageH);
6779
7279
  if (isPresentation) {
6780
- return Math.min(2.5, Math.min(sW, sH));
7280
+ if (mode === "page") {
7281
+ return Math.min(2.5, Math.min(sW, sH));
7282
+ }
7283
+ return Math.min(2.5, sW);
6781
7284
  }
6782
7285
  if (mode === "page") {
6783
7286
  return Math.max(0.35, Math.min(3, Math.min(sW, sH)));
@@ -6946,6 +7449,13 @@ var OpenDocumentPlugin = class {
6946
7449
  applyTransform();
6947
7450
  },
6948
7451
  fitToPage: () => {
7452
+ isUserZoomed = false;
7453
+ fitMode = "page";
7454
+ scale = calculateFitScale("page");
7455
+ rotation = 0;
7456
+ applyTransform();
7457
+ },
7458
+ fitToWidth: () => {
6949
7459
  isUserZoomed = false;
6950
7460
  fitMode = "width";
6951
7461
  scale = calculateFitScale("width");
@@ -6954,8 +7464,8 @@ var OpenDocumentPlugin = class {
6954
7464
  },
6955
7465
  resetZoom: () => {
6956
7466
  isUserZoomed = false;
6957
- fitMode = "width";
6958
- scale = calculateFitScale("width");
7467
+ fitMode = ctx?.options?.fitMode || "width";
7468
+ scale = calculateFitScale(fitMode);
6959
7469
  rotation = 0;
6960
7470
  container.scrollTop = 0;
6961
7471
  container.scrollLeft = 0;
@@ -7312,6 +7822,14 @@ var DocPlugin = class {
7312
7822
  group: "zoom",
7313
7823
  execute: () => instance.resetZoom?.()
7314
7824
  },
7825
+ {
7826
+ id: "fit-width",
7827
+ icon: "fit-width",
7828
+ label: "Fit to Width",
7829
+ type: "button",
7830
+ group: "zoom",
7831
+ execute: () => instance.fitToWidth?.()
7832
+ },
7315
7833
  {
7316
7834
  id: "rotate-cw",
7317
7835
  icon: "rotate-cw",
@@ -7533,6 +8051,13 @@ var DocPlugin = class {
7533
8051
  applyTransform();
7534
8052
  },
7535
8053
  fitToPage: () => {
8054
+ isUserZoomed = false;
8055
+ fitMode = "page";
8056
+ scale = calculateFitScale("page");
8057
+ rotation = 0;
8058
+ applyTransform();
8059
+ },
8060
+ fitToWidth: () => {
7536
8061
  isUserZoomed = false;
7537
8062
  fitMode = "width";
7538
8063
  scale = calculateFitScale("width");
@@ -7541,8 +8066,8 @@ var DocPlugin = class {
7541
8066
  },
7542
8067
  resetZoom: () => {
7543
8068
  isUserZoomed = false;
7544
- fitMode = "width";
7545
- scale = calculateFitScale("width");
8069
+ fitMode = ctx?.options?.fitMode || "width";
8070
+ scale = calculateFitScale(fitMode);
7546
8071
  rotation = 0;
7547
8072
  container.scrollTop = 0;
7548
8073
  container.scrollLeft = 0;
@@ -8038,6 +8563,14 @@ var PptPlugin = class {
8038
8563
  group: "zoom",
8039
8564
  execute: () => instance.resetZoom?.()
8040
8565
  },
8566
+ {
8567
+ id: "fit-width",
8568
+ icon: "fit-width",
8569
+ label: "Fit to Width",
8570
+ type: "button",
8571
+ group: "zoom",
8572
+ execute: () => instance.fitToWidth?.()
8573
+ },
8041
8574
  {
8042
8575
  id: "rotate-cw",
8043
8576
  icon: "rotate-cw",
@@ -8112,10 +8645,15 @@ var PptPlugin = class {
8112
8645
  let currentSlide = 1;
8113
8646
  let slides = [];
8114
8647
  const createdBlobUrls = [];
8115
- const calculateFitScale = () => {
8116
- const availW = Math.max(200, container.clientWidth - 48);
8117
- const availH = Math.max(200, container.clientHeight - 72);
8118
- return Math.min(1, Math.min(availW / 960, availH / 540));
8648
+ let fitMode = ctx?.options?.fitMode || "width";
8649
+ let isUserZoomed = false;
8650
+ const calculateFitScale = (mode = fitMode) => {
8651
+ const availW = Math.max(200, container.clientWidth - 32);
8652
+ const availH = Math.max(200, container.clientHeight - 32);
8653
+ if (mode === "page") {
8654
+ return Math.min(2.5, Math.min(availW / 960, availH / 540));
8655
+ }
8656
+ return Math.min(2.5, availW / 960);
8119
8657
  };
8120
8658
  const applyTransform = () => {
8121
8659
  const cW = 960;
@@ -8130,8 +8668,15 @@ var PptPlugin = class {
8130
8668
  slideCard.style.transform = `scale(${scale}) rotate(${rotation}deg)`;
8131
8669
  slideCard.style.transformOrigin = "center center";
8132
8670
  };
8671
+ const ro = typeof ResizeObserver !== "undefined" ? new ResizeObserver(() => {
8672
+ if (!isUserZoomed) {
8673
+ scale = calculateFitScale(fitMode);
8674
+ applyTransform();
8675
+ }
8676
+ }) : null;
8677
+ ro?.observe(container);
8133
8678
  setTimeout(() => {
8134
- scale = calculateFitScale();
8679
+ scale = calculateFitScale(fitMode);
8135
8680
  applyTransform();
8136
8681
  }, 60);
8137
8682
  try {
@@ -8224,6 +8769,7 @@ var PptPlugin = class {
8224
8769
  };
8225
8770
  renderSlide(1);
8226
8771
  const cleanup = () => {
8772
+ ro?.disconnect();
8227
8773
  for (const u of createdBlobUrls) {
8228
8774
  URL.revokeObjectURL(u);
8229
8775
  }
@@ -8234,28 +8780,44 @@ var PptPlugin = class {
8234
8780
  return {
8235
8781
  destroy: cleanup,
8236
8782
  zoomIn: () => {
8783
+ isUserZoomed = true;
8237
8784
  scale += 0.15;
8238
8785
  applyTransform();
8239
8786
  },
8240
8787
  zoomOut: () => {
8788
+ isUserZoomed = true;
8241
8789
  scale = Math.max(0.2, scale - 0.15);
8242
8790
  applyTransform();
8243
8791
  },
8244
8792
  getZoom: () => scale,
8245
8793
  setZoom: (level) => {
8794
+ isUserZoomed = true;
8246
8795
  scale = level;
8247
8796
  applyTransform();
8248
8797
  },
8249
8798
  fitToPage: () => {
8250
- scale = calculateFitScale();
8799
+ isUserZoomed = false;
8800
+ fitMode = "page";
8801
+ scale = calculateFitScale("page");
8802
+ rotation = 0;
8803
+ applyTransform();
8804
+ },
8805
+ fitToWidth: () => {
8806
+ isUserZoomed = false;
8807
+ fitMode = "width";
8808
+ scale = calculateFitScale("width");
8251
8809
  rotation = 0;
8252
8810
  applyTransform();
8253
8811
  },
8254
8812
  resetZoom: () => {
8255
- scale = calculateFitScale();
8813
+ isUserZoomed = false;
8814
+ fitMode = ctx?.options?.fitMode || "width";
8815
+ scale = calculateFitScale(fitMode);
8256
8816
  rotation = 0;
8257
8817
  container.scrollTop = 0;
8258
8818
  container.scrollLeft = 0;
8819
+ ctx.container.scrollTop = 0;
8820
+ ctx.container.scrollLeft = 0;
8259
8821
  applyTransform();
8260
8822
  },
8261
8823
  rotateCW: () => {
@@ -8600,7 +9162,7 @@ var FilePreview = defineComponent({
8600
9162
  return () => {
8601
9163
  return h("div", {
8602
9164
  ref: containerRef,
8603
- style: { width: "100%", height: "100%", position: "relative" }
9165
+ style: { width: "100%", height: "100%", position: "relative", overflow: "hidden" }
8604
9166
  });
8605
9167
  };
8606
9168
  }