@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/angular.cjs CHANGED
@@ -785,6 +785,8 @@ var FilePreviewViewer = class {
785
785
  keyHandler = null;
786
786
  currentContainer = null;
787
787
  currentOptions = {};
788
+ resizeObserver = null;
789
+ fullscreenHandler = null;
788
790
  /**
789
791
  * Register a preview plugin.
790
792
  */
@@ -857,12 +859,31 @@ var FilePreviewViewer = class {
857
859
  label: "Toggle Fullscreen",
858
860
  type: "button",
859
861
  group: "view",
860
- execute: () => {
861
- if (!document.fullscreenElement) {
862
- this.wrapperEl?.requestFullscreen?.();
863
- } else {
864
- document.exitFullscreen?.();
862
+ execute: async () => {
863
+ try {
864
+ const isNativeFs = !!document.fullscreenElement;
865
+ const isCssFs = this.wrapperEl?.classList.contains("fp-fullscreen-active");
866
+ if (!isNativeFs && !isCssFs) {
867
+ if (this.wrapperEl?.requestFullscreen) {
868
+ await this.wrapperEl.requestFullscreen().catch(() => {
869
+ this.wrapperEl?.classList.add("fp-fullscreen-active");
870
+ });
871
+ } else {
872
+ this.wrapperEl?.classList.add("fp-fullscreen-active");
873
+ }
874
+ } else {
875
+ if (document.fullscreenElement) {
876
+ await document.exitFullscreen().catch(() => {
877
+ });
878
+ }
879
+ this.wrapperEl?.classList.remove("fp-fullscreen-active");
880
+ }
881
+ } catch {
882
+ this.wrapperEl?.classList.toggle("fp-fullscreen-active");
865
883
  }
884
+ setTimeout(() => {
885
+ this.activeInstance?.fitToPage?.();
886
+ }, 120);
866
887
  }
867
888
  });
868
889
  }
@@ -912,6 +933,15 @@ var FilePreviewViewer = class {
912
933
  window.removeEventListener("keydown", this.keyHandler);
913
934
  this.keyHandler = null;
914
935
  }
936
+ if (this.resizeObserver) {
937
+ this.resizeObserver.disconnect();
938
+ this.resizeObserver = null;
939
+ }
940
+ if (this.fullscreenHandler) {
941
+ document.removeEventListener("fullscreenchange", this.fullscreenHandler);
942
+ document.removeEventListener("webkitfullscreenchange", this.fullscreenHandler);
943
+ this.fullscreenHandler = null;
944
+ }
915
945
  this.abort();
916
946
  this.destroyInstance();
917
947
  this.toolbar?.destroy();
@@ -991,6 +1021,25 @@ var FilePreviewViewer = class {
991
1021
  this.thumbnailPanel = new ThumbnailPanel(thumbnailEl);
992
1022
  this.setupKeyboardShortcuts();
993
1023
  this.setupDragAndDrop(container, options);
1024
+ this.setupResizeAndFullscreenListeners();
1025
+ }
1026
+ setupResizeAndFullscreenListeners() {
1027
+ if (this.fullscreenHandler) return;
1028
+ this.fullscreenHandler = () => {
1029
+ setTimeout(() => {
1030
+ this.activeInstance?.fitToPage?.();
1031
+ }, 100);
1032
+ };
1033
+ document.addEventListener("fullscreenchange", this.fullscreenHandler);
1034
+ document.addEventListener("webkitfullscreenchange", this.fullscreenHandler);
1035
+ if (typeof ResizeObserver !== "undefined" && this.contentEl) {
1036
+ this.resizeObserver = new ResizeObserver(() => {
1037
+ if (this.activeInstance && (!this.activeInstance.getZoom || Math.abs((this.activeInstance.getZoom?.() ?? 1) - 1) < 0.05)) {
1038
+ this.activeInstance.fitToPage?.();
1039
+ }
1040
+ });
1041
+ this.resizeObserver.observe(this.contentEl);
1042
+ }
994
1043
  }
995
1044
  setupKeyboardShortcuts() {
996
1045
  if (this.keyHandler) return;
@@ -1382,7 +1431,8 @@ var PdfPlugin = class {
1382
1431
  container.style.display = "flex";
1383
1432
  container.style.flexDirection = "column";
1384
1433
  container.style.alignItems = "center";
1385
- container.style.padding = "24px 16px";
1434
+ container.style.justifyContent = "flex-start";
1435
+ container.style.padding = "20px 16px";
1386
1436
  container.style.backgroundColor = "#0f172a";
1387
1437
  container.style.boxSizing = "border-box";
1388
1438
  container.style.position = "relative";
@@ -1395,7 +1445,8 @@ var PdfPlugin = class {
1395
1445
  pageCard.style.lineHeight = "0";
1396
1446
  pageCard.style.transition = "transform 0.15s ease";
1397
1447
  pageCard.style.position = "relative";
1398
- const canvas = document.createElement("canvas");
1448
+ pageCard.style.flexShrink = "0";
1449
+ let canvas = document.createElement("canvas");
1399
1450
  pageCard.appendChild(canvas);
1400
1451
  container.appendChild(pageCard);
1401
1452
  const indicator = document.createElement("div");
@@ -1437,14 +1488,22 @@ var PdfPlugin = class {
1437
1488
  }
1438
1489
  currentRenderTask = null;
1439
1490
  }
1491
+ const newCanvas = document.createElement("canvas");
1492
+ pageCard.replaceChild(newCanvas, canvas);
1493
+ canvas = newCanvas;
1440
1494
  currentPage = Math.max(1, Math.min(totalPages, pageNum));
1441
1495
  indicator.textContent = `Page ${currentPage} of ${totalPages}`;
1442
1496
  ctx.emit("page-change", { page: currentPage, total: totalPages });
1443
1497
  const page = await pdfDoc.getPage(currentPage);
1444
1498
  const containerWidth = container.clientWidth || 900;
1499
+ const containerHeight = container.clientHeight || 700;
1445
1500
  const unscaledVp = page.getViewport({ scale: 1, rotation });
1446
- const baseScale = Math.min((containerWidth - 64) / unscaledVp.width, 1.6);
1447
- const effectiveScale = (baseScale > 0 ? baseScale : 1) * zoomScale;
1501
+ const availWidth = Math.max(100, containerWidth - 48);
1502
+ const availHeight = Math.max(100, containerHeight - 88);
1503
+ const scaleW = availWidth / unscaledVp.width;
1504
+ const scaleH = availHeight / unscaledVp.height;
1505
+ const fitScale = Math.min(scaleW, scaleH);
1506
+ const effectiveScale = (fitScale > 0 ? fitScale : 1) * zoomScale;
1448
1507
  const pixelRatio = window.devicePixelRatio || 1;
1449
1508
  const viewport = page.getViewport({ scale: effectiveScale, rotation });
1450
1509
  canvas.width = Math.floor(viewport.width * pixelRatio);
@@ -1501,6 +1560,7 @@ var PdfPlugin = class {
1501
1560
  },
1502
1561
  fitToPage: () => {
1503
1562
  zoomScale = 1;
1563
+ rotation = 0;
1504
1564
  renderPage(currentPage);
1505
1565
  },
1506
1566
  rotateCW: () => {
@@ -1951,6 +2011,14 @@ var DocxPlugin = class {
1951
2011
  group: "zoom",
1952
2012
  execute: () => instance.fitToPage?.()
1953
2013
  },
2014
+ {
2015
+ id: "rotate-cw",
2016
+ icon: "rotate-cw",
2017
+ label: "Rotate",
2018
+ type: "button",
2019
+ group: "view",
2020
+ execute: () => instance.rotateCW?.()
2021
+ },
1954
2022
  {
1955
2023
  id: "download",
1956
2024
  icon: "download",
@@ -2087,6 +2155,26 @@ var DocxPlugin = class {
2087
2155
  if (totalPages > 1) {
2088
2156
  showPage(1);
2089
2157
  }
2158
+ scale = 1;
2159
+ let rotation = 0;
2160
+ const calculateFitScale = () => {
2161
+ const activeEl = pageElements[currentPage - 1] || wrapper.firstElementChild || wrapper;
2162
+ const elW = activeEl.offsetWidth || 816;
2163
+ const elH = activeEl.offsetHeight || 1056;
2164
+ const availW = Math.max(200, ctx.container.clientWidth - 48);
2165
+ const availH = Math.max(200, ctx.container.clientHeight - 80);
2166
+ const sW = availW / elW;
2167
+ const sH = availH / elH;
2168
+ return Math.min(1.1, Math.min(sW, sH));
2169
+ };
2170
+ const applyTransform = () => {
2171
+ wrapper.style.transform = `scale(${scale}) rotate(${rotation}deg)`;
2172
+ wrapper.style.transformOrigin = "top center";
2173
+ };
2174
+ setTimeout(() => {
2175
+ scale = calculateFitScale();
2176
+ applyTransform();
2177
+ }, 60);
2090
2178
  const cleanup = () => {
2091
2179
  indicator?.remove();
2092
2180
  for (const url of createdBlobUrls) {
@@ -2105,21 +2193,30 @@ var DocxPlugin = class {
2105
2193
  showPage(page);
2106
2194
  },
2107
2195
  zoomIn: () => {
2108
- scale += 0.1;
2109
- wrapper.style.transform = `scale(${scale})`;
2196
+ scale += 0.15;
2197
+ applyTransform();
2110
2198
  },
2111
2199
  zoomOut: () => {
2112
- scale = Math.max(0.2, scale - 0.1);
2113
- wrapper.style.transform = `scale(${scale})`;
2200
+ scale = Math.max(0.2, scale - 0.15);
2201
+ applyTransform();
2114
2202
  },
2115
2203
  getZoom: () => scale,
2116
2204
  setZoom: (level) => {
2117
2205
  scale = level;
2118
- wrapper.style.transform = `scale(${scale})`;
2206
+ applyTransform();
2119
2207
  },
2120
2208
  fitToPage: () => {
2121
- scale = 1;
2122
- wrapper.style.transform = "scale(1)";
2209
+ scale = calculateFitScale();
2210
+ rotation = 0;
2211
+ applyTransform();
2212
+ },
2213
+ rotateCW: () => {
2214
+ rotation = (rotation + 90) % 360;
2215
+ applyTransform();
2216
+ },
2217
+ rotateCCW: () => {
2218
+ rotation = (rotation - 90 + 360) % 360;
2219
+ applyTransform();
2123
2220
  },
2124
2221
  download: () => {
2125
2222
  const blob = new Blob([ctx.buffer], { type: this.mimeTypes[0] });
@@ -2413,6 +2510,26 @@ var ExcelPlugin = class {
2413
2510
  instance.zoomIn?.();
2414
2511
  }
2415
2512
  },
2513
+ {
2514
+ id: "fit-page",
2515
+ icon: "fit-page",
2516
+ label: "Fit to View",
2517
+ type: "button",
2518
+ group: "zoom",
2519
+ execute: () => {
2520
+ instance.fitToPage?.();
2521
+ }
2522
+ },
2523
+ {
2524
+ id: "rotate-cw",
2525
+ icon: "rotate-cw",
2526
+ label: "Rotate",
2527
+ type: "button",
2528
+ group: "view",
2529
+ execute: () => {
2530
+ instance.rotateCW?.();
2531
+ }
2532
+ },
2416
2533
  {
2417
2534
  id: "download",
2418
2535
  icon: "download",
@@ -2463,9 +2580,23 @@ var ExcelPlugin = class {
2463
2580
  container.appendChild(tabsArea);
2464
2581
  ctx.container.appendChild(container);
2465
2582
  let scale = 1;
2583
+ let rotation = 0;
2466
2584
  let currentSheetIndex = 1;
2467
2585
  let sheetNames = [];
2468
2586
  let wb = null;
2587
+ const applyTransform = () => {
2588
+ contentArea.style.transform = `scale(${scale}) rotate(${rotation}deg)`;
2589
+ contentArea.style.transformOrigin = "top left";
2590
+ };
2591
+ const calculateFitScale = () => {
2592
+ const table = contentArea.querySelector("table");
2593
+ if (!table) return 1;
2594
+ const availW = Math.max(200, container.clientWidth - 48);
2595
+ const availH = Math.max(200, container.clientHeight - 80);
2596
+ const tW = table.offsetWidth || 800;
2597
+ const tH = table.offsetHeight || 600;
2598
+ return Math.min(1, Math.min(availW / tW, availH / tH));
2599
+ };
2469
2600
  try {
2470
2601
  wb = XLSX__namespace.read(new Uint8Array(ctx.buffer), { type: "array", cellDates: true });
2471
2602
  sheetNames = wb.SheetNames || [];
@@ -2553,17 +2684,30 @@ var ExcelPlugin = class {
2553
2684
  return {
2554
2685
  destroy: cleanup,
2555
2686
  zoomIn: () => {
2556
- scale += 0.1;
2557
- contentArea.style.transform = `scale(${scale})`;
2687
+ scale += 0.15;
2688
+ applyTransform();
2558
2689
  },
2559
2690
  zoomOut: () => {
2560
- scale = Math.max(0.2, scale - 0.1);
2561
- contentArea.style.transform = `scale(${scale})`;
2691
+ scale = Math.max(0.2, scale - 0.15);
2692
+ applyTransform();
2562
2693
  },
2563
2694
  getZoom: () => scale,
2564
2695
  setZoom: (level) => {
2565
2696
  scale = level;
2566
- contentArea.style.transform = `scale(${scale})`;
2697
+ applyTransform();
2698
+ },
2699
+ fitToPage: () => {
2700
+ scale = calculateFitScale();
2701
+ rotation = 0;
2702
+ applyTransform();
2703
+ },
2704
+ rotateCW: () => {
2705
+ rotation = (rotation + 90) % 360;
2706
+ applyTransform();
2707
+ },
2708
+ rotateCCW: () => {
2709
+ rotation = (rotation - 90 + 360) % 360;
2710
+ applyTransform();
2567
2711
  },
2568
2712
  goToPage: (page) => {
2569
2713
  if (page > 0 && page <= sheetNames.length) {
@@ -2813,6 +2957,26 @@ var CodePlugin = class {
2813
2957
  instance.zoomIn?.();
2814
2958
  }
2815
2959
  },
2960
+ {
2961
+ id: "fit-page",
2962
+ icon: "fit-page",
2963
+ label: "Fit to View",
2964
+ type: "button",
2965
+ group: "zoom",
2966
+ execute: () => {
2967
+ instance.fitToPage?.();
2968
+ }
2969
+ },
2970
+ {
2971
+ id: "rotate-cw",
2972
+ icon: "rotate-cw",
2973
+ label: "Rotate",
2974
+ type: "button",
2975
+ group: "view",
2976
+ execute: () => {
2977
+ instance.rotateCW?.();
2978
+ }
2979
+ },
2816
2980
  {
2817
2981
  id: "copy",
2818
2982
  icon: "copy",
@@ -2862,6 +3026,7 @@ var CodePlugin = class {
2862
3026
  container.style.padding = "16px";
2863
3027
  container.style.boxSizing = "border-box";
2864
3028
  let fontSize = 13;
3029
+ let rotation = 0;
2865
3030
  const pre = document.createElement("pre");
2866
3031
  pre.style.margin = "0";
2867
3032
  pre.style.fontFamily = "Consolas, Menlo, Monaco, monospace";
@@ -2944,6 +3109,22 @@ var CodePlugin = class {
2944
3109
  fontSize = Math.round(13 * level);
2945
3110
  pre.style.fontSize = `${fontSize}px`;
2946
3111
  },
3112
+ fitToPage: () => {
3113
+ fontSize = 13;
3114
+ rotation = 0;
3115
+ pre.style.fontSize = "13px";
3116
+ pre.style.transform = "none";
3117
+ },
3118
+ rotateCW: () => {
3119
+ rotation = (rotation + 90) % 360;
3120
+ pre.style.transform = `rotate(${rotation}deg)`;
3121
+ pre.style.transformOrigin = "top left";
3122
+ },
3123
+ rotateCCW: () => {
3124
+ rotation = (rotation - 90 + 360) % 360;
3125
+ pre.style.transform = `rotate(${rotation}deg)`;
3126
+ pre.style.transformOrigin = "top left";
3127
+ },
2947
3128
  download: () => {
2948
3129
  const mimeType = ctx.metadata.mimeType || "text/plain";
2949
3130
  const blob = new Blob([ctx.buffer], { type: mimeType });
@@ -3455,6 +3636,14 @@ var PptxPlugin = class {
3455
3636
  group: "zoom",
3456
3637
  execute: () => instance.fitToPage?.()
3457
3638
  },
3639
+ {
3640
+ id: "rotate-cw",
3641
+ icon: "rotate-cw",
3642
+ label: "Rotate",
3643
+ type: "button",
3644
+ group: "view",
3645
+ execute: () => instance.rotateCW?.()
3646
+ },
3458
3647
  {
3459
3648
  id: "download",
3460
3649
  icon: "download",
@@ -3479,6 +3668,7 @@ var PptxPlugin = class {
3479
3668
  const slideCount = renderer.slidePaths?.length || 1;
3480
3669
  let currentSlide = 1;
3481
3670
  let scale = 1;
3671
+ let rotation = 0;
3482
3672
  const wrapper = document.createElement("div");
3483
3673
  wrapper.className = "fp-pptx-wrapper";
3484
3674
  wrapper.style.cssText = `
@@ -3501,6 +3691,8 @@ var PptxPlugin = class {
3501
3691
  background: #ffffff;
3502
3692
  transform-origin: top center;
3503
3693
  transition: transform 0.2s ease;
3694
+ max-width: calc(100% - 32px);
3695
+ max-height: calc(100% - 48px);
3504
3696
  `;
3505
3697
  const canvas = document.createElement("canvas");
3506
3698
  slideContainer.appendChild(canvas);
@@ -3508,10 +3700,22 @@ var PptxPlugin = class {
3508
3700
  ctx.container.innerHTML = "";
3509
3701
  ctx.container.style.overflow = "auto";
3510
3702
  ctx.container.appendChild(wrapper);
3703
+ const calculateFitScale = () => {
3704
+ const availW = Math.max(200, ctx.container.clientWidth - 48);
3705
+ const availH = Math.max(200, ctx.container.clientHeight - 72);
3706
+ const cW = canvas.offsetWidth || 1280;
3707
+ const cH = canvas.offsetHeight || 720;
3708
+ return Math.min(1, Math.min(availW / cW, availH / cH));
3709
+ };
3710
+ const applyTransform = () => {
3711
+ slideContainer.style.transform = `scale(${scale}) rotate(${rotation}deg)`;
3712
+ };
3511
3713
  const renderCurrentSlide = async () => {
3512
3714
  try {
3513
3715
  await renderer.renderSlide(currentSlide - 1, canvas, 1280);
3514
3716
  ctx.emit("page-change", { page: currentSlide, totalPages: slideCount });
3717
+ scale = calculateFitScale();
3718
+ applyTransform();
3515
3719
  } catch (err) {
3516
3720
  console.error("[PptxPlugin] Failed to render slide:", err);
3517
3721
  }
@@ -3534,21 +3738,30 @@ var PptxPlugin = class {
3534
3738
  getPageCount: () => slideCount,
3535
3739
  getCurrentPage: () => currentSlide,
3536
3740
  zoomIn: () => {
3537
- scale += 0.1;
3538
- slideContainer.style.transform = `scale(${scale})`;
3741
+ scale += 0.15;
3742
+ applyTransform();
3539
3743
  },
3540
3744
  zoomOut: () => {
3541
- scale = Math.max(0.2, scale - 0.1);
3542
- slideContainer.style.transform = `scale(${scale})`;
3745
+ scale = Math.max(0.2, scale - 0.15);
3746
+ applyTransform();
3543
3747
  },
3544
3748
  getZoom: () => scale,
3545
3749
  setZoom: (level) => {
3546
3750
  scale = level;
3547
- slideContainer.style.transform = `scale(${scale})`;
3751
+ applyTransform();
3548
3752
  },
3549
3753
  fitToPage: () => {
3550
- scale = 1;
3551
- slideContainer.style.transform = "scale(1)";
3754
+ scale = calculateFitScale();
3755
+ rotation = 0;
3756
+ applyTransform();
3757
+ },
3758
+ rotateCW: () => {
3759
+ rotation = (rotation + 90) % 360;
3760
+ applyTransform();
3761
+ },
3762
+ rotateCCW: () => {
3763
+ rotation = (rotation - 90 + 360) % 360;
3764
+ applyTransform();
3552
3765
  },
3553
3766
  getThumbnails: () => {
3554
3767
  const list = [];
@@ -3829,6 +4042,14 @@ var RtfPlugin = class {
3829
4042
  group: "zoom",
3830
4043
  execute: () => instance.fitToPage?.()
3831
4044
  },
4045
+ {
4046
+ id: "rotate-cw",
4047
+ icon: "rotate-cw",
4048
+ label: "Rotate",
4049
+ type: "button",
4050
+ group: "view",
4051
+ execute: () => instance.rotateCW?.()
4052
+ },
3832
4053
  {
3833
4054
  id: "download",
3834
4055
  icon: "download",
@@ -3865,7 +4086,24 @@ var RtfPlugin = class {
3865
4086
  ctx.container.style.backgroundColor = "#f1f5f9";
3866
4087
  ctx.container.appendChild(wrapper);
3867
4088
  let scale = 1;
4089
+ let rotation = 0;
3868
4090
  let pageElements = [];
4091
+ const calculateFitScale = () => {
4092
+ const activeEl = pageElements[currentPage - 1] || wrapper;
4093
+ const elW = activeEl.offsetWidth || 850;
4094
+ const elH = activeEl.offsetHeight || 1e3;
4095
+ const availW = Math.max(200, ctx.container.clientWidth - 48);
4096
+ const availH = Math.max(200, ctx.container.clientHeight - 80);
4097
+ return Math.min(1.1, Math.min(availW / elW, availH / elH));
4098
+ };
4099
+ const applyTransform = () => {
4100
+ wrapper.style.transform = `scale(${scale}) rotate(${rotation}deg)`;
4101
+ wrapper.style.transformOrigin = "top center";
4102
+ };
4103
+ setTimeout(() => {
4104
+ scale = calculateFitScale();
4105
+ applyTransform();
4106
+ }, 60);
3869
4107
  try {
3870
4108
  if (typeof RTFJS__namespace.loggingEnabled === "function") {
3871
4109
  RTFJS__namespace.loggingEnabled(false);
@@ -3942,21 +4180,30 @@ var RtfPlugin = class {
3942
4180
  getCurrentPage: () => currentPage,
3943
4181
  goToPage: (page) => showPage(page),
3944
4182
  zoomIn: () => {
3945
- scale += 0.1;
3946
- wrapper.style.transform = `scale(${scale})`;
4183
+ scale += 0.15;
4184
+ applyTransform();
3947
4185
  },
3948
4186
  zoomOut: () => {
3949
- scale = Math.max(0.2, scale - 0.1);
3950
- wrapper.style.transform = `scale(${scale})`;
4187
+ scale = Math.max(0.2, scale - 0.15);
4188
+ applyTransform();
3951
4189
  },
3952
4190
  getZoom: () => scale,
3953
4191
  setZoom: (level) => {
3954
4192
  scale = level;
3955
- wrapper.style.transform = `scale(${scale})`;
4193
+ applyTransform();
3956
4194
  },
3957
4195
  fitToPage: () => {
3958
- scale = 1;
3959
- wrapper.style.transform = "scale(1)";
4196
+ scale = calculateFitScale();
4197
+ rotation = 0;
4198
+ applyTransform();
4199
+ },
4200
+ rotateCW: () => {
4201
+ rotation = (rotation + 90) % 360;
4202
+ applyTransform();
4203
+ },
4204
+ rotateCCW: () => {
4205
+ rotation = (rotation - 90 + 360) % 360;
4206
+ applyTransform();
3960
4207
  },
3961
4208
  download: () => {
3962
4209
  const blob = new Blob([ctx.buffer], { type: "application/rtf" });
@@ -4184,11 +4431,19 @@ var OpenDocumentPlugin = class {
4184
4431
  {
4185
4432
  id: "fit-page",
4186
4433
  icon: "fit-page",
4187
- label: "Fit to Page",
4434
+ label: isPresentation ? "Fit to Slide" : "Fit to Page",
4188
4435
  type: "button",
4189
4436
  group: "zoom",
4190
4437
  execute: () => instance.fitToPage?.()
4191
4438
  },
4439
+ {
4440
+ id: "rotate-cw",
4441
+ icon: "rotate-cw",
4442
+ label: "Rotate",
4443
+ type: "button",
4444
+ group: "view",
4445
+ execute: () => instance.rotateCW?.()
4446
+ },
4192
4447
  {
4193
4448
  id: "download",
4194
4449
  icon: "download",
@@ -4252,6 +4507,22 @@ var OpenDocumentPlugin = class {
4252
4507
  container.appendChild(wrapper);
4253
4508
  ctx.container.appendChild(container);
4254
4509
  let scale = 1;
4510
+ let rotation = 0;
4511
+ const calculateFitScale = () => {
4512
+ const elW = wrapper.offsetWidth || 850;
4513
+ const elH = wrapper.offsetHeight || (isPresentation ? 540 : 1e3);
4514
+ const availW = Math.max(200, ctx.container.clientWidth - 48);
4515
+ const availH = Math.max(200, ctx.container.clientHeight - 80);
4516
+ return Math.min(1, Math.min(availW / elW, availH / elH));
4517
+ };
4518
+ const applyTransform = () => {
4519
+ wrapper.style.transform = `scale(${scale}) rotate(${rotation}deg)`;
4520
+ wrapper.style.transformOrigin = "top center";
4521
+ };
4522
+ setTimeout(() => {
4523
+ scale = calculateFitScale();
4524
+ applyTransform();
4525
+ }, 60);
4255
4526
  let currentPage = 1;
4256
4527
  let totalPages = 1;
4257
4528
  let slides = [];
@@ -4310,21 +4581,30 @@ var OpenDocumentPlugin = class {
4310
4581
  destroy: cleanup,
4311
4582
  isPresentation,
4312
4583
  zoomIn: () => {
4313
- scale += 0.1;
4314
- wrapper.style.transform = `scale(${scale})`;
4584
+ scale += 0.15;
4585
+ applyTransform();
4315
4586
  },
4316
4587
  zoomOut: () => {
4317
- scale = Math.max(0.2, scale - 0.1);
4318
- wrapper.style.transform = `scale(${scale})`;
4588
+ scale = Math.max(0.2, scale - 0.15);
4589
+ applyTransform();
4319
4590
  },
4320
4591
  getZoom: () => scale,
4321
4592
  setZoom: (level) => {
4322
4593
  scale = level;
4323
- wrapper.style.transform = `scale(${scale})`;
4594
+ applyTransform();
4324
4595
  },
4325
4596
  fitToPage: () => {
4326
- scale = 1;
4327
- wrapper.style.transform = "scale(1)";
4597
+ scale = calculateFitScale();
4598
+ rotation = 0;
4599
+ applyTransform();
4600
+ },
4601
+ rotateCW: () => {
4602
+ rotation = (rotation + 90) % 360;
4603
+ applyTransform();
4604
+ },
4605
+ rotateCCW: () => {
4606
+ rotation = (rotation - 90 + 360) % 360;
4607
+ applyTransform();
4328
4608
  },
4329
4609
  goToPage,
4330
4610
  getPageCount: () => totalPages,
@@ -4594,6 +4874,14 @@ var DocPlugin = class {
4594
4874
  group: "zoom",
4595
4875
  execute: () => instance.fitToPage?.()
4596
4876
  },
4877
+ {
4878
+ id: "rotate-cw",
4879
+ icon: "rotate-cw",
4880
+ label: "Rotate",
4881
+ type: "button",
4882
+ group: "view",
4883
+ execute: () => instance.rotateCW?.()
4884
+ },
4597
4885
  {
4598
4886
  id: "copy",
4599
4887
  icon: "copy",
@@ -4732,6 +5020,23 @@ var DocPlugin = class {
4732
5020
  if (totalPages > 1) {
4733
5021
  showPage(1);
4734
5022
  }
5023
+ let rotation = 0;
5024
+ const calculateFitScale = () => {
5025
+ const activeCard = pageCards[currentPage - 1] || wrapper;
5026
+ const elW = activeCard.offsetWidth || 850;
5027
+ const elH = activeCard.offsetHeight || 1e3;
5028
+ const availW = Math.max(200, ctx.container.clientWidth - 48);
5029
+ const availH = Math.max(200, ctx.container.clientHeight - 80);
5030
+ return Math.min(1.1, Math.min(availW / elW, availH / elH));
5031
+ };
5032
+ const applyTransform = () => {
5033
+ wrapper.style.transform = `scale(${scale}) rotate(${rotation}deg)`;
5034
+ wrapper.style.transformOrigin = "top center";
5035
+ };
5036
+ setTimeout(() => {
5037
+ scale = calculateFitScale();
5038
+ applyTransform();
5039
+ }, 60);
4735
5040
  const cleanup = () => {
4736
5041
  indicator?.remove();
4737
5042
  container.remove();
@@ -4744,21 +5049,30 @@ var DocPlugin = class {
4744
5049
  getCurrentPage: () => currentPage,
4745
5050
  goToPage: (page) => showPage(page),
4746
5051
  zoomIn: () => {
4747
- scale += 0.1;
4748
- wrapper.style.transform = `scale(${scale})`;
5052
+ scale += 0.15;
5053
+ applyTransform();
4749
5054
  },
4750
5055
  zoomOut: () => {
4751
- scale = Math.max(0.2, scale - 0.1);
4752
- wrapper.style.transform = `scale(${scale})`;
5056
+ scale = Math.max(0.2, scale - 0.15);
5057
+ applyTransform();
4753
5058
  },
4754
5059
  getZoom: () => scale,
4755
5060
  setZoom: (level) => {
4756
5061
  scale = level;
4757
- wrapper.style.transform = `scale(${scale})`;
5062
+ applyTransform();
4758
5063
  },
4759
5064
  fitToPage: () => {
4760
- scale = 1;
4761
- wrapper.style.transform = "scale(1)";
5065
+ scale = calculateFitScale();
5066
+ rotation = 0;
5067
+ applyTransform();
5068
+ },
5069
+ rotateCW: () => {
5070
+ rotation = (rotation + 90) % 360;
5071
+ applyTransform();
5072
+ },
5073
+ rotateCCW: () => {
5074
+ rotation = (rotation - 90 + 360) % 360;
5075
+ applyTransform();
4762
5076
  },
4763
5077
  copy: () => {
4764
5078
  navigator.clipboard.writeText(extractedRawText);
@@ -4998,6 +5312,14 @@ var PptPlugin = class {
4998
5312
  group: "zoom",
4999
5313
  execute: () => instance.fitToPage?.()
5000
5314
  },
5315
+ {
5316
+ id: "rotate-cw",
5317
+ icon: "rotate-cw",
5318
+ label: "Rotate",
5319
+ type: "button",
5320
+ group: "view",
5321
+ execute: () => instance.rotateCW?.()
5322
+ },
5001
5323
  {
5002
5324
  id: "download",
5003
5325
  icon: "download",
@@ -5031,22 +5353,36 @@ var PptPlugin = class {
5031
5353
  const slideCard = document.createElement("div");
5032
5354
  slideCard.className = "fp-ppt-slide-card";
5033
5355
  slideCard.style.width = "960px";
5034
- slideCard.style.maxWidth = "92%";
5356
+ slideCard.style.maxWidth = "calc(100% - 32px)";
5357
+ slideCard.style.maxHeight = "calc(100% - 48px)";
5035
5358
  slideCard.style.aspectRatio = "16 / 9";
5036
5359
  slideCard.style.backgroundColor = "#ffffff";
5037
5360
  slideCard.style.boxShadow = "0 12px 40px rgba(0,0,0,0.35)";
5038
5361
  slideCard.style.borderRadius = "8px";
5039
5362
  slideCard.style.boxSizing = "border-box";
5040
5363
  slideCard.style.position = "relative";
5041
- slideCard.style.overflow = "hidden";
5042
- slideCard.style.transformOrigin = "center center";
5043
5364
  slideCard.style.transition = "transform 0.2s ease";
5365
+ slideCard.style.transformOrigin = "center center";
5366
+ slideCard.style.flexShrink = "0";
5044
5367
  container.appendChild(slideCard);
5045
5368
  ctx.container.appendChild(container);
5046
5369
  let scale = 1;
5370
+ let rotation = 0;
5047
5371
  let currentSlide = 1;
5048
5372
  let slides = [];
5049
5373
  const createdBlobUrls = [];
5374
+ const calculateFitScale = () => {
5375
+ const availW = Math.max(200, container.clientWidth - 48);
5376
+ const availH = Math.max(200, container.clientHeight - 72);
5377
+ return Math.min(1, Math.min(availW / 960, availH / 540));
5378
+ };
5379
+ const applyTransform = () => {
5380
+ slideCard.style.transform = `scale(${scale}) rotate(${rotation}deg)`;
5381
+ };
5382
+ setTimeout(() => {
5383
+ scale = calculateFitScale();
5384
+ applyTransform();
5385
+ }, 60);
5050
5386
  try {
5051
5387
  const cfbf = new CfbfReader(ctx.buffer);
5052
5388
  const pptStream = cfbf.readStream("PowerPoint Document");
@@ -5147,21 +5483,30 @@ var PptPlugin = class {
5147
5483
  return {
5148
5484
  destroy: cleanup,
5149
5485
  zoomIn: () => {
5150
- scale += 0.1;
5151
- slideCard.style.transform = `scale(${scale})`;
5486
+ scale += 0.15;
5487
+ applyTransform();
5152
5488
  },
5153
5489
  zoomOut: () => {
5154
- scale = Math.max(0.3, scale - 0.1);
5155
- slideCard.style.transform = `scale(${scale})`;
5490
+ scale = Math.max(0.2, scale - 0.15);
5491
+ applyTransform();
5156
5492
  },
5157
5493
  getZoom: () => scale,
5158
5494
  setZoom: (level) => {
5159
5495
  scale = level;
5160
- slideCard.style.transform = `scale(${scale})`;
5496
+ applyTransform();
5161
5497
  },
5162
5498
  fitToPage: () => {
5163
- scale = 1;
5164
- slideCard.style.transform = "scale(1)";
5499
+ scale = calculateFitScale();
5500
+ rotation = 0;
5501
+ applyTransform();
5502
+ },
5503
+ rotateCW: () => {
5504
+ rotation = (rotation + 90) % 360;
5505
+ applyTransform();
5506
+ },
5507
+ rotateCCW: () => {
5508
+ rotation = (rotation - 90 + 360) % 360;
5509
+ applyTransform();
5165
5510
  },
5166
5511
  goToPage: (page) => {
5167
5512
  if (page >= 1 && page <= totalSlides) {