@files-preview-app/preview-file 1.2.5 → 1.2.6

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/index.cjs CHANGED
@@ -778,6 +778,8 @@ var FilePreviewViewer = class {
778
778
  keyHandler = null;
779
779
  currentContainer = null;
780
780
  currentOptions = {};
781
+ resizeObserver = null;
782
+ fullscreenHandler = null;
781
783
  /**
782
784
  * Register a preview plugin.
783
785
  */
@@ -850,12 +852,31 @@ var FilePreviewViewer = class {
850
852
  label: "Toggle Fullscreen",
851
853
  type: "button",
852
854
  group: "view",
853
- execute: () => {
854
- if (!document.fullscreenElement) {
855
- this.wrapperEl?.requestFullscreen?.();
856
- } else {
857
- document.exitFullscreen?.();
855
+ execute: async () => {
856
+ try {
857
+ const isNativeFs = !!document.fullscreenElement;
858
+ const isCssFs = this.wrapperEl?.classList.contains("fp-fullscreen-active");
859
+ if (!isNativeFs && !isCssFs) {
860
+ if (this.wrapperEl?.requestFullscreen) {
861
+ await this.wrapperEl.requestFullscreen().catch(() => {
862
+ this.wrapperEl?.classList.add("fp-fullscreen-active");
863
+ });
864
+ } else {
865
+ this.wrapperEl?.classList.add("fp-fullscreen-active");
866
+ }
867
+ } else {
868
+ if (document.fullscreenElement) {
869
+ await document.exitFullscreen().catch(() => {
870
+ });
871
+ }
872
+ this.wrapperEl?.classList.remove("fp-fullscreen-active");
873
+ }
874
+ } catch {
875
+ this.wrapperEl?.classList.toggle("fp-fullscreen-active");
858
876
  }
877
+ setTimeout(() => {
878
+ this.activeInstance?.fitToPage?.();
879
+ }, 120);
859
880
  }
860
881
  });
861
882
  }
@@ -905,6 +926,15 @@ var FilePreviewViewer = class {
905
926
  window.removeEventListener("keydown", this.keyHandler);
906
927
  this.keyHandler = null;
907
928
  }
929
+ if (this.resizeObserver) {
930
+ this.resizeObserver.disconnect();
931
+ this.resizeObserver = null;
932
+ }
933
+ if (this.fullscreenHandler) {
934
+ document.removeEventListener("fullscreenchange", this.fullscreenHandler);
935
+ document.removeEventListener("webkitfullscreenchange", this.fullscreenHandler);
936
+ this.fullscreenHandler = null;
937
+ }
908
938
  this.abort();
909
939
  this.destroyInstance();
910
940
  this.toolbar?.destroy();
@@ -984,6 +1014,25 @@ var FilePreviewViewer = class {
984
1014
  this.thumbnailPanel = new ThumbnailPanel(thumbnailEl);
985
1015
  this.setupKeyboardShortcuts();
986
1016
  this.setupDragAndDrop(container, options);
1017
+ this.setupResizeAndFullscreenListeners();
1018
+ }
1019
+ setupResizeAndFullscreenListeners() {
1020
+ if (this.fullscreenHandler) return;
1021
+ this.fullscreenHandler = () => {
1022
+ setTimeout(() => {
1023
+ this.activeInstance?.fitToPage?.();
1024
+ }, 100);
1025
+ };
1026
+ document.addEventListener("fullscreenchange", this.fullscreenHandler);
1027
+ document.addEventListener("webkitfullscreenchange", this.fullscreenHandler);
1028
+ if (typeof ResizeObserver !== "undefined" && this.contentEl) {
1029
+ this.resizeObserver = new ResizeObserver(() => {
1030
+ if (this.activeInstance && (!this.activeInstance.getZoom || Math.abs((this.activeInstance.getZoom?.() ?? 1) - 1) < 0.05)) {
1031
+ this.activeInstance.fitToPage?.();
1032
+ }
1033
+ });
1034
+ this.resizeObserver.observe(this.contentEl);
1035
+ }
987
1036
  }
988
1037
  setupKeyboardShortcuts() {
989
1038
  if (this.keyHandler) return;
@@ -1375,7 +1424,8 @@ var PdfPlugin = class {
1375
1424
  container.style.display = "flex";
1376
1425
  container.style.flexDirection = "column";
1377
1426
  container.style.alignItems = "center";
1378
- container.style.padding = "24px 16px";
1427
+ container.style.justifyContent = "flex-start";
1428
+ container.style.padding = "20px 16px";
1379
1429
  container.style.backgroundColor = "#0f172a";
1380
1430
  container.style.boxSizing = "border-box";
1381
1431
  container.style.position = "relative";
@@ -1388,7 +1438,8 @@ var PdfPlugin = class {
1388
1438
  pageCard.style.lineHeight = "0";
1389
1439
  pageCard.style.transition = "transform 0.15s ease";
1390
1440
  pageCard.style.position = "relative";
1391
- const canvas = document.createElement("canvas");
1441
+ pageCard.style.flexShrink = "0";
1442
+ let canvas = document.createElement("canvas");
1392
1443
  pageCard.appendChild(canvas);
1393
1444
  container.appendChild(pageCard);
1394
1445
  const indicator = document.createElement("div");
@@ -1430,14 +1481,22 @@ var PdfPlugin = class {
1430
1481
  }
1431
1482
  currentRenderTask = null;
1432
1483
  }
1484
+ const newCanvas = document.createElement("canvas");
1485
+ pageCard.replaceChild(newCanvas, canvas);
1486
+ canvas = newCanvas;
1433
1487
  currentPage = Math.max(1, Math.min(totalPages, pageNum));
1434
1488
  indicator.textContent = `Page ${currentPage} of ${totalPages}`;
1435
1489
  ctx.emit("page-change", { page: currentPage, total: totalPages });
1436
1490
  const page = await pdfDoc.getPage(currentPage);
1437
1491
  const containerWidth = container.clientWidth || 900;
1492
+ const containerHeight = container.clientHeight || 700;
1438
1493
  const unscaledVp = page.getViewport({ scale: 1, rotation });
1439
- const baseScale = Math.min((containerWidth - 64) / unscaledVp.width, 1.6);
1440
- const effectiveScale = (baseScale > 0 ? baseScale : 1) * zoomScale;
1494
+ const availWidth = Math.max(100, containerWidth - 48);
1495
+ const availHeight = Math.max(100, containerHeight - 88);
1496
+ const scaleW = availWidth / unscaledVp.width;
1497
+ const scaleH = availHeight / unscaledVp.height;
1498
+ const fitScale = Math.min(scaleW, scaleH);
1499
+ const effectiveScale = (fitScale > 0 ? fitScale : 1) * zoomScale;
1441
1500
  const pixelRatio = window.devicePixelRatio || 1;
1442
1501
  const viewport = page.getViewport({ scale: effectiveScale, rotation });
1443
1502
  canvas.width = Math.floor(viewport.width * pixelRatio);
@@ -1494,6 +1553,7 @@ var PdfPlugin = class {
1494
1553
  },
1495
1554
  fitToPage: () => {
1496
1555
  zoomScale = 1;
1556
+ rotation = 0;
1497
1557
  renderPage(currentPage);
1498
1558
  },
1499
1559
  rotateCW: () => {
@@ -1944,6 +2004,14 @@ var DocxPlugin = class {
1944
2004
  group: "zoom",
1945
2005
  execute: () => instance.fitToPage?.()
1946
2006
  },
2007
+ {
2008
+ id: "rotate-cw",
2009
+ icon: "rotate-cw",
2010
+ label: "Rotate",
2011
+ type: "button",
2012
+ group: "view",
2013
+ execute: () => instance.rotateCW?.()
2014
+ },
1947
2015
  {
1948
2016
  id: "download",
1949
2017
  icon: "download",
@@ -2080,6 +2148,26 @@ var DocxPlugin = class {
2080
2148
  if (totalPages > 1) {
2081
2149
  showPage(1);
2082
2150
  }
2151
+ scale = 1;
2152
+ let rotation = 0;
2153
+ const calculateFitScale = () => {
2154
+ const activeEl = pageElements[currentPage - 1] || wrapper.firstElementChild || wrapper;
2155
+ const elW = activeEl.offsetWidth || 816;
2156
+ const elH = activeEl.offsetHeight || 1056;
2157
+ const availW = Math.max(200, ctx.container.clientWidth - 48);
2158
+ const availH = Math.max(200, ctx.container.clientHeight - 80);
2159
+ const sW = availW / elW;
2160
+ const sH = availH / elH;
2161
+ return Math.min(1.1, Math.min(sW, sH));
2162
+ };
2163
+ const applyTransform = () => {
2164
+ wrapper.style.transform = `scale(${scale}) rotate(${rotation}deg)`;
2165
+ wrapper.style.transformOrigin = "top center";
2166
+ };
2167
+ setTimeout(() => {
2168
+ scale = calculateFitScale();
2169
+ applyTransform();
2170
+ }, 60);
2083
2171
  const cleanup = () => {
2084
2172
  indicator?.remove();
2085
2173
  for (const url of createdBlobUrls) {
@@ -2098,21 +2186,30 @@ var DocxPlugin = class {
2098
2186
  showPage(page);
2099
2187
  },
2100
2188
  zoomIn: () => {
2101
- scale += 0.1;
2102
- wrapper.style.transform = `scale(${scale})`;
2189
+ scale += 0.15;
2190
+ applyTransform();
2103
2191
  },
2104
2192
  zoomOut: () => {
2105
- scale = Math.max(0.2, scale - 0.1);
2106
- wrapper.style.transform = `scale(${scale})`;
2193
+ scale = Math.max(0.2, scale - 0.15);
2194
+ applyTransform();
2107
2195
  },
2108
2196
  getZoom: () => scale,
2109
2197
  setZoom: (level) => {
2110
2198
  scale = level;
2111
- wrapper.style.transform = `scale(${scale})`;
2199
+ applyTransform();
2112
2200
  },
2113
2201
  fitToPage: () => {
2114
- scale = 1;
2115
- wrapper.style.transform = "scale(1)";
2202
+ scale = calculateFitScale();
2203
+ rotation = 0;
2204
+ applyTransform();
2205
+ },
2206
+ rotateCW: () => {
2207
+ rotation = (rotation + 90) % 360;
2208
+ applyTransform();
2209
+ },
2210
+ rotateCCW: () => {
2211
+ rotation = (rotation - 90 + 360) % 360;
2212
+ applyTransform();
2116
2213
  },
2117
2214
  download: () => {
2118
2215
  const blob = new Blob([ctx.buffer], { type: this.mimeTypes[0] });
@@ -2406,6 +2503,26 @@ var ExcelPlugin = class {
2406
2503
  instance.zoomIn?.();
2407
2504
  }
2408
2505
  },
2506
+ {
2507
+ id: "fit-page",
2508
+ icon: "fit-page",
2509
+ label: "Fit to View",
2510
+ type: "button",
2511
+ group: "zoom",
2512
+ execute: () => {
2513
+ instance.fitToPage?.();
2514
+ }
2515
+ },
2516
+ {
2517
+ id: "rotate-cw",
2518
+ icon: "rotate-cw",
2519
+ label: "Rotate",
2520
+ type: "button",
2521
+ group: "view",
2522
+ execute: () => {
2523
+ instance.rotateCW?.();
2524
+ }
2525
+ },
2409
2526
  {
2410
2527
  id: "download",
2411
2528
  icon: "download",
@@ -2456,9 +2573,23 @@ var ExcelPlugin = class {
2456
2573
  container.appendChild(tabsArea);
2457
2574
  ctx.container.appendChild(container);
2458
2575
  let scale = 1;
2576
+ let rotation = 0;
2459
2577
  let currentSheetIndex = 1;
2460
2578
  let sheetNames = [];
2461
2579
  let wb = null;
2580
+ const applyTransform = () => {
2581
+ contentArea.style.transform = `scale(${scale}) rotate(${rotation}deg)`;
2582
+ contentArea.style.transformOrigin = "top left";
2583
+ };
2584
+ const calculateFitScale = () => {
2585
+ const table = contentArea.querySelector("table");
2586
+ if (!table) return 1;
2587
+ const availW = Math.max(200, container.clientWidth - 48);
2588
+ const availH = Math.max(200, container.clientHeight - 80);
2589
+ const tW = table.offsetWidth || 800;
2590
+ const tH = table.offsetHeight || 600;
2591
+ return Math.min(1, Math.min(availW / tW, availH / tH));
2592
+ };
2462
2593
  try {
2463
2594
  wb = XLSX__namespace.read(new Uint8Array(ctx.buffer), { type: "array", cellDates: true });
2464
2595
  sheetNames = wb.SheetNames || [];
@@ -2546,17 +2677,30 @@ var ExcelPlugin = class {
2546
2677
  return {
2547
2678
  destroy: cleanup,
2548
2679
  zoomIn: () => {
2549
- scale += 0.1;
2550
- contentArea.style.transform = `scale(${scale})`;
2680
+ scale += 0.15;
2681
+ applyTransform();
2551
2682
  },
2552
2683
  zoomOut: () => {
2553
- scale = Math.max(0.2, scale - 0.1);
2554
- contentArea.style.transform = `scale(${scale})`;
2684
+ scale = Math.max(0.2, scale - 0.15);
2685
+ applyTransform();
2555
2686
  },
2556
2687
  getZoom: () => scale,
2557
2688
  setZoom: (level) => {
2558
2689
  scale = level;
2559
- contentArea.style.transform = `scale(${scale})`;
2690
+ applyTransform();
2691
+ },
2692
+ fitToPage: () => {
2693
+ scale = calculateFitScale();
2694
+ rotation = 0;
2695
+ applyTransform();
2696
+ },
2697
+ rotateCW: () => {
2698
+ rotation = (rotation + 90) % 360;
2699
+ applyTransform();
2700
+ },
2701
+ rotateCCW: () => {
2702
+ rotation = (rotation - 90 + 360) % 360;
2703
+ applyTransform();
2560
2704
  },
2561
2705
  goToPage: (page) => {
2562
2706
  if (page > 0 && page <= sheetNames.length) {
@@ -2806,6 +2950,26 @@ var CodePlugin = class {
2806
2950
  instance.zoomIn?.();
2807
2951
  }
2808
2952
  },
2953
+ {
2954
+ id: "fit-page",
2955
+ icon: "fit-page",
2956
+ label: "Fit to View",
2957
+ type: "button",
2958
+ group: "zoom",
2959
+ execute: () => {
2960
+ instance.fitToPage?.();
2961
+ }
2962
+ },
2963
+ {
2964
+ id: "rotate-cw",
2965
+ icon: "rotate-cw",
2966
+ label: "Rotate",
2967
+ type: "button",
2968
+ group: "view",
2969
+ execute: () => {
2970
+ instance.rotateCW?.();
2971
+ }
2972
+ },
2809
2973
  {
2810
2974
  id: "copy",
2811
2975
  icon: "copy",
@@ -2855,6 +3019,7 @@ var CodePlugin = class {
2855
3019
  container.style.padding = "16px";
2856
3020
  container.style.boxSizing = "border-box";
2857
3021
  let fontSize = 13;
3022
+ let rotation = 0;
2858
3023
  const pre = document.createElement("pre");
2859
3024
  pre.style.margin = "0";
2860
3025
  pre.style.fontFamily = "Consolas, Menlo, Monaco, monospace";
@@ -2937,6 +3102,22 @@ var CodePlugin = class {
2937
3102
  fontSize = Math.round(13 * level);
2938
3103
  pre.style.fontSize = `${fontSize}px`;
2939
3104
  },
3105
+ fitToPage: () => {
3106
+ fontSize = 13;
3107
+ rotation = 0;
3108
+ pre.style.fontSize = "13px";
3109
+ pre.style.transform = "none";
3110
+ },
3111
+ rotateCW: () => {
3112
+ rotation = (rotation + 90) % 360;
3113
+ pre.style.transform = `rotate(${rotation}deg)`;
3114
+ pre.style.transformOrigin = "top left";
3115
+ },
3116
+ rotateCCW: () => {
3117
+ rotation = (rotation - 90 + 360) % 360;
3118
+ pre.style.transform = `rotate(${rotation}deg)`;
3119
+ pre.style.transformOrigin = "top left";
3120
+ },
2940
3121
  download: () => {
2941
3122
  const mimeType = ctx.metadata.mimeType || "text/plain";
2942
3123
  const blob = new Blob([ctx.buffer], { type: mimeType });
@@ -3448,6 +3629,14 @@ var PptxPlugin = class {
3448
3629
  group: "zoom",
3449
3630
  execute: () => instance.fitToPage?.()
3450
3631
  },
3632
+ {
3633
+ id: "rotate-cw",
3634
+ icon: "rotate-cw",
3635
+ label: "Rotate",
3636
+ type: "button",
3637
+ group: "view",
3638
+ execute: () => instance.rotateCW?.()
3639
+ },
3451
3640
  {
3452
3641
  id: "download",
3453
3642
  icon: "download",
@@ -3472,6 +3661,7 @@ var PptxPlugin = class {
3472
3661
  const slideCount = renderer.slidePaths?.length || 1;
3473
3662
  let currentSlide = 1;
3474
3663
  let scale = 1;
3664
+ let rotation = 0;
3475
3665
  const wrapper = document.createElement("div");
3476
3666
  wrapper.className = "fp-pptx-wrapper";
3477
3667
  wrapper.style.cssText = `
@@ -3494,6 +3684,8 @@ var PptxPlugin = class {
3494
3684
  background: #ffffff;
3495
3685
  transform-origin: top center;
3496
3686
  transition: transform 0.2s ease;
3687
+ max-width: calc(100% - 32px);
3688
+ max-height: calc(100% - 48px);
3497
3689
  `;
3498
3690
  const canvas = document.createElement("canvas");
3499
3691
  slideContainer.appendChild(canvas);
@@ -3501,10 +3693,22 @@ var PptxPlugin = class {
3501
3693
  ctx.container.innerHTML = "";
3502
3694
  ctx.container.style.overflow = "auto";
3503
3695
  ctx.container.appendChild(wrapper);
3696
+ const calculateFitScale = () => {
3697
+ const availW = Math.max(200, ctx.container.clientWidth - 48);
3698
+ const availH = Math.max(200, ctx.container.clientHeight - 72);
3699
+ const cW = canvas.offsetWidth || 1280;
3700
+ const cH = canvas.offsetHeight || 720;
3701
+ return Math.min(1, Math.min(availW / cW, availH / cH));
3702
+ };
3703
+ const applyTransform = () => {
3704
+ slideContainer.style.transform = `scale(${scale}) rotate(${rotation}deg)`;
3705
+ };
3504
3706
  const renderCurrentSlide = async () => {
3505
3707
  try {
3506
3708
  await renderer.renderSlide(currentSlide - 1, canvas, 1280);
3507
3709
  ctx.emit("page-change", { page: currentSlide, totalPages: slideCount });
3710
+ scale = calculateFitScale();
3711
+ applyTransform();
3508
3712
  } catch (err) {
3509
3713
  console.error("[PptxPlugin] Failed to render slide:", err);
3510
3714
  }
@@ -3527,21 +3731,30 @@ var PptxPlugin = class {
3527
3731
  getPageCount: () => slideCount,
3528
3732
  getCurrentPage: () => currentSlide,
3529
3733
  zoomIn: () => {
3530
- scale += 0.1;
3531
- slideContainer.style.transform = `scale(${scale})`;
3734
+ scale += 0.15;
3735
+ applyTransform();
3532
3736
  },
3533
3737
  zoomOut: () => {
3534
- scale = Math.max(0.2, scale - 0.1);
3535
- slideContainer.style.transform = `scale(${scale})`;
3738
+ scale = Math.max(0.2, scale - 0.15);
3739
+ applyTransform();
3536
3740
  },
3537
3741
  getZoom: () => scale,
3538
3742
  setZoom: (level) => {
3539
3743
  scale = level;
3540
- slideContainer.style.transform = `scale(${scale})`;
3744
+ applyTransform();
3541
3745
  },
3542
3746
  fitToPage: () => {
3543
- scale = 1;
3544
- slideContainer.style.transform = "scale(1)";
3747
+ scale = calculateFitScale();
3748
+ rotation = 0;
3749
+ applyTransform();
3750
+ },
3751
+ rotateCW: () => {
3752
+ rotation = (rotation + 90) % 360;
3753
+ applyTransform();
3754
+ },
3755
+ rotateCCW: () => {
3756
+ rotation = (rotation - 90 + 360) % 360;
3757
+ applyTransform();
3545
3758
  },
3546
3759
  getThumbnails: () => {
3547
3760
  const list = [];
@@ -3822,6 +4035,14 @@ var RtfPlugin = class {
3822
4035
  group: "zoom",
3823
4036
  execute: () => instance.fitToPage?.()
3824
4037
  },
4038
+ {
4039
+ id: "rotate-cw",
4040
+ icon: "rotate-cw",
4041
+ label: "Rotate",
4042
+ type: "button",
4043
+ group: "view",
4044
+ execute: () => instance.rotateCW?.()
4045
+ },
3825
4046
  {
3826
4047
  id: "download",
3827
4048
  icon: "download",
@@ -3858,7 +4079,24 @@ var RtfPlugin = class {
3858
4079
  ctx.container.style.backgroundColor = "#f1f5f9";
3859
4080
  ctx.container.appendChild(wrapper);
3860
4081
  let scale = 1;
4082
+ let rotation = 0;
3861
4083
  let pageElements = [];
4084
+ const calculateFitScale = () => {
4085
+ const activeEl = pageElements[currentPage - 1] || wrapper;
4086
+ const elW = activeEl.offsetWidth || 850;
4087
+ const elH = activeEl.offsetHeight || 1e3;
4088
+ const availW = Math.max(200, ctx.container.clientWidth - 48);
4089
+ const availH = Math.max(200, ctx.container.clientHeight - 80);
4090
+ return Math.min(1.1, Math.min(availW / elW, availH / elH));
4091
+ };
4092
+ const applyTransform = () => {
4093
+ wrapper.style.transform = `scale(${scale}) rotate(${rotation}deg)`;
4094
+ wrapper.style.transformOrigin = "top center";
4095
+ };
4096
+ setTimeout(() => {
4097
+ scale = calculateFitScale();
4098
+ applyTransform();
4099
+ }, 60);
3862
4100
  try {
3863
4101
  if (typeof RTFJS__namespace.loggingEnabled === "function") {
3864
4102
  RTFJS__namespace.loggingEnabled(false);
@@ -3935,21 +4173,30 @@ var RtfPlugin = class {
3935
4173
  getCurrentPage: () => currentPage,
3936
4174
  goToPage: (page) => showPage(page),
3937
4175
  zoomIn: () => {
3938
- scale += 0.1;
3939
- wrapper.style.transform = `scale(${scale})`;
4176
+ scale += 0.15;
4177
+ applyTransform();
3940
4178
  },
3941
4179
  zoomOut: () => {
3942
- scale = Math.max(0.2, scale - 0.1);
3943
- wrapper.style.transform = `scale(${scale})`;
4180
+ scale = Math.max(0.2, scale - 0.15);
4181
+ applyTransform();
3944
4182
  },
3945
4183
  getZoom: () => scale,
3946
4184
  setZoom: (level) => {
3947
4185
  scale = level;
3948
- wrapper.style.transform = `scale(${scale})`;
4186
+ applyTransform();
3949
4187
  },
3950
4188
  fitToPage: () => {
3951
- scale = 1;
3952
- wrapper.style.transform = "scale(1)";
4189
+ scale = calculateFitScale();
4190
+ rotation = 0;
4191
+ applyTransform();
4192
+ },
4193
+ rotateCW: () => {
4194
+ rotation = (rotation + 90) % 360;
4195
+ applyTransform();
4196
+ },
4197
+ rotateCCW: () => {
4198
+ rotation = (rotation - 90 + 360) % 360;
4199
+ applyTransform();
3953
4200
  },
3954
4201
  download: () => {
3955
4202
  const blob = new Blob([ctx.buffer], { type: "application/rtf" });
@@ -4177,11 +4424,19 @@ var OpenDocumentPlugin = class {
4177
4424
  {
4178
4425
  id: "fit-page",
4179
4426
  icon: "fit-page",
4180
- label: "Fit to Page",
4427
+ label: isPresentation ? "Fit to Slide" : "Fit to Page",
4181
4428
  type: "button",
4182
4429
  group: "zoom",
4183
4430
  execute: () => instance.fitToPage?.()
4184
4431
  },
4432
+ {
4433
+ id: "rotate-cw",
4434
+ icon: "rotate-cw",
4435
+ label: "Rotate",
4436
+ type: "button",
4437
+ group: "view",
4438
+ execute: () => instance.rotateCW?.()
4439
+ },
4185
4440
  {
4186
4441
  id: "download",
4187
4442
  icon: "download",
@@ -4245,6 +4500,22 @@ var OpenDocumentPlugin = class {
4245
4500
  container.appendChild(wrapper);
4246
4501
  ctx.container.appendChild(container);
4247
4502
  let scale = 1;
4503
+ let rotation = 0;
4504
+ const calculateFitScale = () => {
4505
+ const elW = wrapper.offsetWidth || 850;
4506
+ const elH = wrapper.offsetHeight || (isPresentation ? 540 : 1e3);
4507
+ const availW = Math.max(200, ctx.container.clientWidth - 48);
4508
+ const availH = Math.max(200, ctx.container.clientHeight - 80);
4509
+ return Math.min(1, Math.min(availW / elW, availH / elH));
4510
+ };
4511
+ const applyTransform = () => {
4512
+ wrapper.style.transform = `scale(${scale}) rotate(${rotation}deg)`;
4513
+ wrapper.style.transformOrigin = "top center";
4514
+ };
4515
+ setTimeout(() => {
4516
+ scale = calculateFitScale();
4517
+ applyTransform();
4518
+ }, 60);
4248
4519
  let currentPage = 1;
4249
4520
  let totalPages = 1;
4250
4521
  let slides = [];
@@ -4303,21 +4574,30 @@ var OpenDocumentPlugin = class {
4303
4574
  destroy: cleanup,
4304
4575
  isPresentation,
4305
4576
  zoomIn: () => {
4306
- scale += 0.1;
4307
- wrapper.style.transform = `scale(${scale})`;
4577
+ scale += 0.15;
4578
+ applyTransform();
4308
4579
  },
4309
4580
  zoomOut: () => {
4310
- scale = Math.max(0.2, scale - 0.1);
4311
- wrapper.style.transform = `scale(${scale})`;
4581
+ scale = Math.max(0.2, scale - 0.15);
4582
+ applyTransform();
4312
4583
  },
4313
4584
  getZoom: () => scale,
4314
4585
  setZoom: (level) => {
4315
4586
  scale = level;
4316
- wrapper.style.transform = `scale(${scale})`;
4587
+ applyTransform();
4317
4588
  },
4318
4589
  fitToPage: () => {
4319
- scale = 1;
4320
- wrapper.style.transform = "scale(1)";
4590
+ scale = calculateFitScale();
4591
+ rotation = 0;
4592
+ applyTransform();
4593
+ },
4594
+ rotateCW: () => {
4595
+ rotation = (rotation + 90) % 360;
4596
+ applyTransform();
4597
+ },
4598
+ rotateCCW: () => {
4599
+ rotation = (rotation - 90 + 360) % 360;
4600
+ applyTransform();
4321
4601
  },
4322
4602
  goToPage,
4323
4603
  getPageCount: () => totalPages,
@@ -4587,6 +4867,14 @@ var DocPlugin = class {
4587
4867
  group: "zoom",
4588
4868
  execute: () => instance.fitToPage?.()
4589
4869
  },
4870
+ {
4871
+ id: "rotate-cw",
4872
+ icon: "rotate-cw",
4873
+ label: "Rotate",
4874
+ type: "button",
4875
+ group: "view",
4876
+ execute: () => instance.rotateCW?.()
4877
+ },
4590
4878
  {
4591
4879
  id: "copy",
4592
4880
  icon: "copy",
@@ -4725,6 +5013,23 @@ var DocPlugin = class {
4725
5013
  if (totalPages > 1) {
4726
5014
  showPage(1);
4727
5015
  }
5016
+ let rotation = 0;
5017
+ const calculateFitScale = () => {
5018
+ const activeCard = pageCards[currentPage - 1] || wrapper;
5019
+ const elW = activeCard.offsetWidth || 850;
5020
+ const elH = activeCard.offsetHeight || 1e3;
5021
+ const availW = Math.max(200, ctx.container.clientWidth - 48);
5022
+ const availH = Math.max(200, ctx.container.clientHeight - 80);
5023
+ return Math.min(1.1, Math.min(availW / elW, availH / elH));
5024
+ };
5025
+ const applyTransform = () => {
5026
+ wrapper.style.transform = `scale(${scale}) rotate(${rotation}deg)`;
5027
+ wrapper.style.transformOrigin = "top center";
5028
+ };
5029
+ setTimeout(() => {
5030
+ scale = calculateFitScale();
5031
+ applyTransform();
5032
+ }, 60);
4728
5033
  const cleanup = () => {
4729
5034
  indicator?.remove();
4730
5035
  container.remove();
@@ -4737,21 +5042,30 @@ var DocPlugin = class {
4737
5042
  getCurrentPage: () => currentPage,
4738
5043
  goToPage: (page) => showPage(page),
4739
5044
  zoomIn: () => {
4740
- scale += 0.1;
4741
- wrapper.style.transform = `scale(${scale})`;
5045
+ scale += 0.15;
5046
+ applyTransform();
4742
5047
  },
4743
5048
  zoomOut: () => {
4744
- scale = Math.max(0.2, scale - 0.1);
4745
- wrapper.style.transform = `scale(${scale})`;
5049
+ scale = Math.max(0.2, scale - 0.15);
5050
+ applyTransform();
4746
5051
  },
4747
5052
  getZoom: () => scale,
4748
5053
  setZoom: (level) => {
4749
5054
  scale = level;
4750
- wrapper.style.transform = `scale(${scale})`;
5055
+ applyTransform();
4751
5056
  },
4752
5057
  fitToPage: () => {
4753
- scale = 1;
4754
- wrapper.style.transform = "scale(1)";
5058
+ scale = calculateFitScale();
5059
+ rotation = 0;
5060
+ applyTransform();
5061
+ },
5062
+ rotateCW: () => {
5063
+ rotation = (rotation + 90) % 360;
5064
+ applyTransform();
5065
+ },
5066
+ rotateCCW: () => {
5067
+ rotation = (rotation - 90 + 360) % 360;
5068
+ applyTransform();
4755
5069
  },
4756
5070
  copy: () => {
4757
5071
  navigator.clipboard.writeText(extractedRawText);
@@ -4991,6 +5305,14 @@ var PptPlugin = class {
4991
5305
  group: "zoom",
4992
5306
  execute: () => instance.fitToPage?.()
4993
5307
  },
5308
+ {
5309
+ id: "rotate-cw",
5310
+ icon: "rotate-cw",
5311
+ label: "Rotate",
5312
+ type: "button",
5313
+ group: "view",
5314
+ execute: () => instance.rotateCW?.()
5315
+ },
4994
5316
  {
4995
5317
  id: "download",
4996
5318
  icon: "download",
@@ -5024,22 +5346,36 @@ var PptPlugin = class {
5024
5346
  const slideCard = document.createElement("div");
5025
5347
  slideCard.className = "fp-ppt-slide-card";
5026
5348
  slideCard.style.width = "960px";
5027
- slideCard.style.maxWidth = "92%";
5349
+ slideCard.style.maxWidth = "calc(100% - 32px)";
5350
+ slideCard.style.maxHeight = "calc(100% - 48px)";
5028
5351
  slideCard.style.aspectRatio = "16 / 9";
5029
5352
  slideCard.style.backgroundColor = "#ffffff";
5030
5353
  slideCard.style.boxShadow = "0 12px 40px rgba(0,0,0,0.35)";
5031
5354
  slideCard.style.borderRadius = "8px";
5032
5355
  slideCard.style.boxSizing = "border-box";
5033
5356
  slideCard.style.position = "relative";
5034
- slideCard.style.overflow = "hidden";
5035
- slideCard.style.transformOrigin = "center center";
5036
5357
  slideCard.style.transition = "transform 0.2s ease";
5358
+ slideCard.style.transformOrigin = "center center";
5359
+ slideCard.style.flexShrink = "0";
5037
5360
  container.appendChild(slideCard);
5038
5361
  ctx.container.appendChild(container);
5039
5362
  let scale = 1;
5363
+ let rotation = 0;
5040
5364
  let currentSlide = 1;
5041
5365
  let slides = [];
5042
5366
  const createdBlobUrls = [];
5367
+ const calculateFitScale = () => {
5368
+ const availW = Math.max(200, container.clientWidth - 48);
5369
+ const availH = Math.max(200, container.clientHeight - 72);
5370
+ return Math.min(1, Math.min(availW / 960, availH / 540));
5371
+ };
5372
+ const applyTransform = () => {
5373
+ slideCard.style.transform = `scale(${scale}) rotate(${rotation}deg)`;
5374
+ };
5375
+ setTimeout(() => {
5376
+ scale = calculateFitScale();
5377
+ applyTransform();
5378
+ }, 60);
5043
5379
  try {
5044
5380
  const cfbf = new CfbfReader(ctx.buffer);
5045
5381
  const pptStream = cfbf.readStream("PowerPoint Document");
@@ -5140,21 +5476,30 @@ var PptPlugin = class {
5140
5476
  return {
5141
5477
  destroy: cleanup,
5142
5478
  zoomIn: () => {
5143
- scale += 0.1;
5144
- slideCard.style.transform = `scale(${scale})`;
5479
+ scale += 0.15;
5480
+ applyTransform();
5145
5481
  },
5146
5482
  zoomOut: () => {
5147
- scale = Math.max(0.3, scale - 0.1);
5148
- slideCard.style.transform = `scale(${scale})`;
5483
+ scale = Math.max(0.2, scale - 0.15);
5484
+ applyTransform();
5149
5485
  },
5150
5486
  getZoom: () => scale,
5151
5487
  setZoom: (level) => {
5152
5488
  scale = level;
5153
- slideCard.style.transform = `scale(${scale})`;
5489
+ applyTransform();
5154
5490
  },
5155
5491
  fitToPage: () => {
5156
- scale = 1;
5157
- slideCard.style.transform = "scale(1)";
5492
+ scale = calculateFitScale();
5493
+ rotation = 0;
5494
+ applyTransform();
5495
+ },
5496
+ rotateCW: () => {
5497
+ rotation = (rotation + 90) % 360;
5498
+ applyTransform();
5499
+ },
5500
+ rotateCCW: () => {
5501
+ rotation = (rotation - 90 + 360) % 360;
5502
+ applyTransform();
5158
5503
  },
5159
5504
  goToPage: (page) => {
5160
5505
  if (page >= 1 && page <= totalSlides) {