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

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