@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.js CHANGED
@@ -753,6 +753,8 @@ var FilePreviewViewer = class {
753
753
  keyHandler = null;
754
754
  currentContainer = null;
755
755
  currentOptions = {};
756
+ resizeObserver = null;
757
+ fullscreenHandler = null;
756
758
  /**
757
759
  * Register a preview plugin.
758
760
  */
@@ -825,12 +827,31 @@ var FilePreviewViewer = class {
825
827
  label: "Toggle Fullscreen",
826
828
  type: "button",
827
829
  group: "view",
828
- execute: () => {
829
- if (!document.fullscreenElement) {
830
- this.wrapperEl?.requestFullscreen?.();
831
- } else {
832
- document.exitFullscreen?.();
830
+ execute: async () => {
831
+ try {
832
+ const isNativeFs = !!document.fullscreenElement;
833
+ const isCssFs = this.wrapperEl?.classList.contains("fp-fullscreen-active");
834
+ if (!isNativeFs && !isCssFs) {
835
+ if (this.wrapperEl?.requestFullscreen) {
836
+ await this.wrapperEl.requestFullscreen().catch(() => {
837
+ this.wrapperEl?.classList.add("fp-fullscreen-active");
838
+ });
839
+ } else {
840
+ this.wrapperEl?.classList.add("fp-fullscreen-active");
841
+ }
842
+ } else {
843
+ if (document.fullscreenElement) {
844
+ await document.exitFullscreen().catch(() => {
845
+ });
846
+ }
847
+ this.wrapperEl?.classList.remove("fp-fullscreen-active");
848
+ }
849
+ } catch {
850
+ this.wrapperEl?.classList.toggle("fp-fullscreen-active");
833
851
  }
852
+ setTimeout(() => {
853
+ this.activeInstance?.fitToPage?.();
854
+ }, 120);
834
855
  }
835
856
  });
836
857
  }
@@ -880,6 +901,15 @@ var FilePreviewViewer = class {
880
901
  window.removeEventListener("keydown", this.keyHandler);
881
902
  this.keyHandler = null;
882
903
  }
904
+ if (this.resizeObserver) {
905
+ this.resizeObserver.disconnect();
906
+ this.resizeObserver = null;
907
+ }
908
+ if (this.fullscreenHandler) {
909
+ document.removeEventListener("fullscreenchange", this.fullscreenHandler);
910
+ document.removeEventListener("webkitfullscreenchange", this.fullscreenHandler);
911
+ this.fullscreenHandler = null;
912
+ }
883
913
  this.abort();
884
914
  this.destroyInstance();
885
915
  this.toolbar?.destroy();
@@ -959,6 +989,25 @@ var FilePreviewViewer = class {
959
989
  this.thumbnailPanel = new ThumbnailPanel(thumbnailEl);
960
990
  this.setupKeyboardShortcuts();
961
991
  this.setupDragAndDrop(container, options);
992
+ this.setupResizeAndFullscreenListeners();
993
+ }
994
+ setupResizeAndFullscreenListeners() {
995
+ if (this.fullscreenHandler) return;
996
+ this.fullscreenHandler = () => {
997
+ setTimeout(() => {
998
+ this.activeInstance?.fitToPage?.();
999
+ }, 100);
1000
+ };
1001
+ document.addEventListener("fullscreenchange", this.fullscreenHandler);
1002
+ document.addEventListener("webkitfullscreenchange", this.fullscreenHandler);
1003
+ if (typeof ResizeObserver !== "undefined" && this.contentEl) {
1004
+ this.resizeObserver = new ResizeObserver(() => {
1005
+ if (this.activeInstance && (!this.activeInstance.getZoom || Math.abs((this.activeInstance.getZoom?.() ?? 1) - 1) < 0.05)) {
1006
+ this.activeInstance.fitToPage?.();
1007
+ }
1008
+ });
1009
+ this.resizeObserver.observe(this.contentEl);
1010
+ }
962
1011
  }
963
1012
  setupKeyboardShortcuts() {
964
1013
  if (this.keyHandler) return;
@@ -1350,7 +1399,8 @@ var PdfPlugin = class {
1350
1399
  container.style.display = "flex";
1351
1400
  container.style.flexDirection = "column";
1352
1401
  container.style.alignItems = "center";
1353
- container.style.padding = "24px 16px";
1402
+ container.style.justifyContent = "flex-start";
1403
+ container.style.padding = "20px 16px";
1354
1404
  container.style.backgroundColor = "#0f172a";
1355
1405
  container.style.boxSizing = "border-box";
1356
1406
  container.style.position = "relative";
@@ -1363,7 +1413,8 @@ var PdfPlugin = class {
1363
1413
  pageCard.style.lineHeight = "0";
1364
1414
  pageCard.style.transition = "transform 0.15s ease";
1365
1415
  pageCard.style.position = "relative";
1366
- const canvas = document.createElement("canvas");
1416
+ pageCard.style.flexShrink = "0";
1417
+ let canvas = document.createElement("canvas");
1367
1418
  pageCard.appendChild(canvas);
1368
1419
  container.appendChild(pageCard);
1369
1420
  const indicator = document.createElement("div");
@@ -1405,14 +1456,22 @@ var PdfPlugin = class {
1405
1456
  }
1406
1457
  currentRenderTask = null;
1407
1458
  }
1459
+ const newCanvas = document.createElement("canvas");
1460
+ pageCard.replaceChild(newCanvas, canvas);
1461
+ canvas = newCanvas;
1408
1462
  currentPage = Math.max(1, Math.min(totalPages, pageNum));
1409
1463
  indicator.textContent = `Page ${currentPage} of ${totalPages}`;
1410
1464
  ctx.emit("page-change", { page: currentPage, total: totalPages });
1411
1465
  const page = await pdfDoc.getPage(currentPage);
1412
1466
  const containerWidth = container.clientWidth || 900;
1467
+ const containerHeight = container.clientHeight || 700;
1413
1468
  const unscaledVp = page.getViewport({ scale: 1, rotation });
1414
- const baseScale = Math.min((containerWidth - 64) / unscaledVp.width, 1.6);
1415
- const effectiveScale = (baseScale > 0 ? baseScale : 1) * zoomScale;
1469
+ const availWidth = Math.max(100, containerWidth - 48);
1470
+ const availHeight = Math.max(100, containerHeight - 88);
1471
+ const scaleW = availWidth / unscaledVp.width;
1472
+ const scaleH = availHeight / unscaledVp.height;
1473
+ const fitScale = Math.min(scaleW, scaleH);
1474
+ const effectiveScale = (fitScale > 0 ? fitScale : 1) * zoomScale;
1416
1475
  const pixelRatio = window.devicePixelRatio || 1;
1417
1476
  const viewport = page.getViewport({ scale: effectiveScale, rotation });
1418
1477
  canvas.width = Math.floor(viewport.width * pixelRatio);
@@ -1469,6 +1528,7 @@ var PdfPlugin = class {
1469
1528
  },
1470
1529
  fitToPage: () => {
1471
1530
  zoomScale = 1;
1531
+ rotation = 0;
1472
1532
  renderPage(currentPage);
1473
1533
  },
1474
1534
  rotateCW: () => {
@@ -1919,6 +1979,14 @@ var DocxPlugin = class {
1919
1979
  group: "zoom",
1920
1980
  execute: () => instance.fitToPage?.()
1921
1981
  },
1982
+ {
1983
+ id: "rotate-cw",
1984
+ icon: "rotate-cw",
1985
+ label: "Rotate",
1986
+ type: "button",
1987
+ group: "view",
1988
+ execute: () => instance.rotateCW?.()
1989
+ },
1922
1990
  {
1923
1991
  id: "download",
1924
1992
  icon: "download",
@@ -2055,6 +2123,26 @@ var DocxPlugin = class {
2055
2123
  if (totalPages > 1) {
2056
2124
  showPage(1);
2057
2125
  }
2126
+ scale = 1;
2127
+ let rotation = 0;
2128
+ const calculateFitScale = () => {
2129
+ const activeEl = pageElements[currentPage - 1] || wrapper.firstElementChild || wrapper;
2130
+ const elW = activeEl.offsetWidth || 816;
2131
+ const elH = activeEl.offsetHeight || 1056;
2132
+ const availW = Math.max(200, ctx.container.clientWidth - 48);
2133
+ const availH = Math.max(200, ctx.container.clientHeight - 80);
2134
+ const sW = availW / elW;
2135
+ const sH = availH / elH;
2136
+ return Math.min(1.1, Math.min(sW, sH));
2137
+ };
2138
+ const applyTransform = () => {
2139
+ wrapper.style.transform = `scale(${scale}) rotate(${rotation}deg)`;
2140
+ wrapper.style.transformOrigin = "top center";
2141
+ };
2142
+ setTimeout(() => {
2143
+ scale = calculateFitScale();
2144
+ applyTransform();
2145
+ }, 60);
2058
2146
  const cleanup = () => {
2059
2147
  indicator?.remove();
2060
2148
  for (const url of createdBlobUrls) {
@@ -2073,21 +2161,30 @@ var DocxPlugin = class {
2073
2161
  showPage(page);
2074
2162
  },
2075
2163
  zoomIn: () => {
2076
- scale += 0.1;
2077
- wrapper.style.transform = `scale(${scale})`;
2164
+ scale += 0.15;
2165
+ applyTransform();
2078
2166
  },
2079
2167
  zoomOut: () => {
2080
- scale = Math.max(0.2, scale - 0.1);
2081
- wrapper.style.transform = `scale(${scale})`;
2168
+ scale = Math.max(0.2, scale - 0.15);
2169
+ applyTransform();
2082
2170
  },
2083
2171
  getZoom: () => scale,
2084
2172
  setZoom: (level) => {
2085
2173
  scale = level;
2086
- wrapper.style.transform = `scale(${scale})`;
2174
+ applyTransform();
2087
2175
  },
2088
2176
  fitToPage: () => {
2089
- scale = 1;
2090
- wrapper.style.transform = "scale(1)";
2177
+ scale = calculateFitScale();
2178
+ rotation = 0;
2179
+ applyTransform();
2180
+ },
2181
+ rotateCW: () => {
2182
+ rotation = (rotation + 90) % 360;
2183
+ applyTransform();
2184
+ },
2185
+ rotateCCW: () => {
2186
+ rotation = (rotation - 90 + 360) % 360;
2187
+ applyTransform();
2091
2188
  },
2092
2189
  download: () => {
2093
2190
  const blob = new Blob([ctx.buffer], { type: this.mimeTypes[0] });
@@ -2381,6 +2478,26 @@ var ExcelPlugin = class {
2381
2478
  instance.zoomIn?.();
2382
2479
  }
2383
2480
  },
2481
+ {
2482
+ id: "fit-page",
2483
+ icon: "fit-page",
2484
+ label: "Fit to View",
2485
+ type: "button",
2486
+ group: "zoom",
2487
+ execute: () => {
2488
+ instance.fitToPage?.();
2489
+ }
2490
+ },
2491
+ {
2492
+ id: "rotate-cw",
2493
+ icon: "rotate-cw",
2494
+ label: "Rotate",
2495
+ type: "button",
2496
+ group: "view",
2497
+ execute: () => {
2498
+ instance.rotateCW?.();
2499
+ }
2500
+ },
2384
2501
  {
2385
2502
  id: "download",
2386
2503
  icon: "download",
@@ -2431,9 +2548,23 @@ var ExcelPlugin = class {
2431
2548
  container.appendChild(tabsArea);
2432
2549
  ctx.container.appendChild(container);
2433
2550
  let scale = 1;
2551
+ let rotation = 0;
2434
2552
  let currentSheetIndex = 1;
2435
2553
  let sheetNames = [];
2436
2554
  let wb = null;
2555
+ const applyTransform = () => {
2556
+ contentArea.style.transform = `scale(${scale}) rotate(${rotation}deg)`;
2557
+ contentArea.style.transformOrigin = "top left";
2558
+ };
2559
+ const calculateFitScale = () => {
2560
+ const table = contentArea.querySelector("table");
2561
+ if (!table) return 1;
2562
+ const availW = Math.max(200, container.clientWidth - 48);
2563
+ const availH = Math.max(200, container.clientHeight - 80);
2564
+ const tW = table.offsetWidth || 800;
2565
+ const tH = table.offsetHeight || 600;
2566
+ return Math.min(1, Math.min(availW / tW, availH / tH));
2567
+ };
2437
2568
  try {
2438
2569
  wb = XLSX.read(new Uint8Array(ctx.buffer), { type: "array", cellDates: true });
2439
2570
  sheetNames = wb.SheetNames || [];
@@ -2521,17 +2652,30 @@ var ExcelPlugin = class {
2521
2652
  return {
2522
2653
  destroy: cleanup,
2523
2654
  zoomIn: () => {
2524
- scale += 0.1;
2525
- contentArea.style.transform = `scale(${scale})`;
2655
+ scale += 0.15;
2656
+ applyTransform();
2526
2657
  },
2527
2658
  zoomOut: () => {
2528
- scale = Math.max(0.2, scale - 0.1);
2529
- contentArea.style.transform = `scale(${scale})`;
2659
+ scale = Math.max(0.2, scale - 0.15);
2660
+ applyTransform();
2530
2661
  },
2531
2662
  getZoom: () => scale,
2532
2663
  setZoom: (level) => {
2533
2664
  scale = level;
2534
- contentArea.style.transform = `scale(${scale})`;
2665
+ applyTransform();
2666
+ },
2667
+ fitToPage: () => {
2668
+ scale = calculateFitScale();
2669
+ rotation = 0;
2670
+ applyTransform();
2671
+ },
2672
+ rotateCW: () => {
2673
+ rotation = (rotation + 90) % 360;
2674
+ applyTransform();
2675
+ },
2676
+ rotateCCW: () => {
2677
+ rotation = (rotation - 90 + 360) % 360;
2678
+ applyTransform();
2535
2679
  },
2536
2680
  goToPage: (page) => {
2537
2681
  if (page > 0 && page <= sheetNames.length) {
@@ -2781,6 +2925,26 @@ var CodePlugin = class {
2781
2925
  instance.zoomIn?.();
2782
2926
  }
2783
2927
  },
2928
+ {
2929
+ id: "fit-page",
2930
+ icon: "fit-page",
2931
+ label: "Fit to View",
2932
+ type: "button",
2933
+ group: "zoom",
2934
+ execute: () => {
2935
+ instance.fitToPage?.();
2936
+ }
2937
+ },
2938
+ {
2939
+ id: "rotate-cw",
2940
+ icon: "rotate-cw",
2941
+ label: "Rotate",
2942
+ type: "button",
2943
+ group: "view",
2944
+ execute: () => {
2945
+ instance.rotateCW?.();
2946
+ }
2947
+ },
2784
2948
  {
2785
2949
  id: "copy",
2786
2950
  icon: "copy",
@@ -2830,6 +2994,7 @@ var CodePlugin = class {
2830
2994
  container.style.padding = "16px";
2831
2995
  container.style.boxSizing = "border-box";
2832
2996
  let fontSize = 13;
2997
+ let rotation = 0;
2833
2998
  const pre = document.createElement("pre");
2834
2999
  pre.style.margin = "0";
2835
3000
  pre.style.fontFamily = "Consolas, Menlo, Monaco, monospace";
@@ -2912,6 +3077,22 @@ var CodePlugin = class {
2912
3077
  fontSize = Math.round(13 * level);
2913
3078
  pre.style.fontSize = `${fontSize}px`;
2914
3079
  },
3080
+ fitToPage: () => {
3081
+ fontSize = 13;
3082
+ rotation = 0;
3083
+ pre.style.fontSize = "13px";
3084
+ pre.style.transform = "none";
3085
+ },
3086
+ rotateCW: () => {
3087
+ rotation = (rotation + 90) % 360;
3088
+ pre.style.transform = `rotate(${rotation}deg)`;
3089
+ pre.style.transformOrigin = "top left";
3090
+ },
3091
+ rotateCCW: () => {
3092
+ rotation = (rotation - 90 + 360) % 360;
3093
+ pre.style.transform = `rotate(${rotation}deg)`;
3094
+ pre.style.transformOrigin = "top left";
3095
+ },
2915
3096
  download: () => {
2916
3097
  const mimeType = ctx.metadata.mimeType || "text/plain";
2917
3098
  const blob = new Blob([ctx.buffer], { type: mimeType });
@@ -3423,6 +3604,14 @@ var PptxPlugin = class {
3423
3604
  group: "zoom",
3424
3605
  execute: () => instance.fitToPage?.()
3425
3606
  },
3607
+ {
3608
+ id: "rotate-cw",
3609
+ icon: "rotate-cw",
3610
+ label: "Rotate",
3611
+ type: "button",
3612
+ group: "view",
3613
+ execute: () => instance.rotateCW?.()
3614
+ },
3426
3615
  {
3427
3616
  id: "download",
3428
3617
  icon: "download",
@@ -3447,6 +3636,7 @@ var PptxPlugin = class {
3447
3636
  const slideCount = renderer.slidePaths?.length || 1;
3448
3637
  let currentSlide = 1;
3449
3638
  let scale = 1;
3639
+ let rotation = 0;
3450
3640
  const wrapper = document.createElement("div");
3451
3641
  wrapper.className = "fp-pptx-wrapper";
3452
3642
  wrapper.style.cssText = `
@@ -3469,6 +3659,8 @@ var PptxPlugin = class {
3469
3659
  background: #ffffff;
3470
3660
  transform-origin: top center;
3471
3661
  transition: transform 0.2s ease;
3662
+ max-width: calc(100% - 32px);
3663
+ max-height: calc(100% - 48px);
3472
3664
  `;
3473
3665
  const canvas = document.createElement("canvas");
3474
3666
  slideContainer.appendChild(canvas);
@@ -3476,10 +3668,22 @@ var PptxPlugin = class {
3476
3668
  ctx.container.innerHTML = "";
3477
3669
  ctx.container.style.overflow = "auto";
3478
3670
  ctx.container.appendChild(wrapper);
3671
+ const calculateFitScale = () => {
3672
+ const availW = Math.max(200, ctx.container.clientWidth - 48);
3673
+ const availH = Math.max(200, ctx.container.clientHeight - 72);
3674
+ const cW = canvas.offsetWidth || 1280;
3675
+ const cH = canvas.offsetHeight || 720;
3676
+ return Math.min(1, Math.min(availW / cW, availH / cH));
3677
+ };
3678
+ const applyTransform = () => {
3679
+ slideContainer.style.transform = `scale(${scale}) rotate(${rotation}deg)`;
3680
+ };
3479
3681
  const renderCurrentSlide = async () => {
3480
3682
  try {
3481
3683
  await renderer.renderSlide(currentSlide - 1, canvas, 1280);
3482
3684
  ctx.emit("page-change", { page: currentSlide, totalPages: slideCount });
3685
+ scale = calculateFitScale();
3686
+ applyTransform();
3483
3687
  } catch (err) {
3484
3688
  console.error("[PptxPlugin] Failed to render slide:", err);
3485
3689
  }
@@ -3502,21 +3706,30 @@ var PptxPlugin = class {
3502
3706
  getPageCount: () => slideCount,
3503
3707
  getCurrentPage: () => currentSlide,
3504
3708
  zoomIn: () => {
3505
- scale += 0.1;
3506
- slideContainer.style.transform = `scale(${scale})`;
3709
+ scale += 0.15;
3710
+ applyTransform();
3507
3711
  },
3508
3712
  zoomOut: () => {
3509
- scale = Math.max(0.2, scale - 0.1);
3510
- slideContainer.style.transform = `scale(${scale})`;
3713
+ scale = Math.max(0.2, scale - 0.15);
3714
+ applyTransform();
3511
3715
  },
3512
3716
  getZoom: () => scale,
3513
3717
  setZoom: (level) => {
3514
3718
  scale = level;
3515
- slideContainer.style.transform = `scale(${scale})`;
3719
+ applyTransform();
3516
3720
  },
3517
3721
  fitToPage: () => {
3518
- scale = 1;
3519
- slideContainer.style.transform = "scale(1)";
3722
+ scale = calculateFitScale();
3723
+ rotation = 0;
3724
+ applyTransform();
3725
+ },
3726
+ rotateCW: () => {
3727
+ rotation = (rotation + 90) % 360;
3728
+ applyTransform();
3729
+ },
3730
+ rotateCCW: () => {
3731
+ rotation = (rotation - 90 + 360) % 360;
3732
+ applyTransform();
3520
3733
  },
3521
3734
  getThumbnails: () => {
3522
3735
  const list = [];
@@ -3797,6 +4010,14 @@ var RtfPlugin = class {
3797
4010
  group: "zoom",
3798
4011
  execute: () => instance.fitToPage?.()
3799
4012
  },
4013
+ {
4014
+ id: "rotate-cw",
4015
+ icon: "rotate-cw",
4016
+ label: "Rotate",
4017
+ type: "button",
4018
+ group: "view",
4019
+ execute: () => instance.rotateCW?.()
4020
+ },
3800
4021
  {
3801
4022
  id: "download",
3802
4023
  icon: "download",
@@ -3833,7 +4054,24 @@ var RtfPlugin = class {
3833
4054
  ctx.container.style.backgroundColor = "#f1f5f9";
3834
4055
  ctx.container.appendChild(wrapper);
3835
4056
  let scale = 1;
4057
+ let rotation = 0;
3836
4058
  let pageElements = [];
4059
+ const calculateFitScale = () => {
4060
+ const activeEl = pageElements[currentPage - 1] || wrapper;
4061
+ const elW = activeEl.offsetWidth || 850;
4062
+ const elH = activeEl.offsetHeight || 1e3;
4063
+ const availW = Math.max(200, ctx.container.clientWidth - 48);
4064
+ const availH = Math.max(200, ctx.container.clientHeight - 80);
4065
+ return Math.min(1.1, Math.min(availW / elW, availH / elH));
4066
+ };
4067
+ const applyTransform = () => {
4068
+ wrapper.style.transform = `scale(${scale}) rotate(${rotation}deg)`;
4069
+ wrapper.style.transformOrigin = "top center";
4070
+ };
4071
+ setTimeout(() => {
4072
+ scale = calculateFitScale();
4073
+ applyTransform();
4074
+ }, 60);
3837
4075
  try {
3838
4076
  if (typeof RTFJS.loggingEnabled === "function") {
3839
4077
  RTFJS.loggingEnabled(false);
@@ -3910,21 +4148,30 @@ var RtfPlugin = class {
3910
4148
  getCurrentPage: () => currentPage,
3911
4149
  goToPage: (page) => showPage(page),
3912
4150
  zoomIn: () => {
3913
- scale += 0.1;
3914
- wrapper.style.transform = `scale(${scale})`;
4151
+ scale += 0.15;
4152
+ applyTransform();
3915
4153
  },
3916
4154
  zoomOut: () => {
3917
- scale = Math.max(0.2, scale - 0.1);
3918
- wrapper.style.transform = `scale(${scale})`;
4155
+ scale = Math.max(0.2, scale - 0.15);
4156
+ applyTransform();
3919
4157
  },
3920
4158
  getZoom: () => scale,
3921
4159
  setZoom: (level) => {
3922
4160
  scale = level;
3923
- wrapper.style.transform = `scale(${scale})`;
4161
+ applyTransform();
3924
4162
  },
3925
4163
  fitToPage: () => {
3926
- scale = 1;
3927
- wrapper.style.transform = "scale(1)";
4164
+ scale = calculateFitScale();
4165
+ rotation = 0;
4166
+ applyTransform();
4167
+ },
4168
+ rotateCW: () => {
4169
+ rotation = (rotation + 90) % 360;
4170
+ applyTransform();
4171
+ },
4172
+ rotateCCW: () => {
4173
+ rotation = (rotation - 90 + 360) % 360;
4174
+ applyTransform();
3928
4175
  },
3929
4176
  download: () => {
3930
4177
  const blob = new Blob([ctx.buffer], { type: "application/rtf" });
@@ -4152,11 +4399,19 @@ var OpenDocumentPlugin = class {
4152
4399
  {
4153
4400
  id: "fit-page",
4154
4401
  icon: "fit-page",
4155
- label: "Fit to Page",
4402
+ label: isPresentation ? "Fit to Slide" : "Fit to Page",
4156
4403
  type: "button",
4157
4404
  group: "zoom",
4158
4405
  execute: () => instance.fitToPage?.()
4159
4406
  },
4407
+ {
4408
+ id: "rotate-cw",
4409
+ icon: "rotate-cw",
4410
+ label: "Rotate",
4411
+ type: "button",
4412
+ group: "view",
4413
+ execute: () => instance.rotateCW?.()
4414
+ },
4160
4415
  {
4161
4416
  id: "download",
4162
4417
  icon: "download",
@@ -4220,6 +4475,22 @@ var OpenDocumentPlugin = class {
4220
4475
  container.appendChild(wrapper);
4221
4476
  ctx.container.appendChild(container);
4222
4477
  let scale = 1;
4478
+ let rotation = 0;
4479
+ const calculateFitScale = () => {
4480
+ const elW = wrapper.offsetWidth || 850;
4481
+ const elH = wrapper.offsetHeight || (isPresentation ? 540 : 1e3);
4482
+ const availW = Math.max(200, ctx.container.clientWidth - 48);
4483
+ const availH = Math.max(200, ctx.container.clientHeight - 80);
4484
+ return Math.min(1, Math.min(availW / elW, availH / elH));
4485
+ };
4486
+ const applyTransform = () => {
4487
+ wrapper.style.transform = `scale(${scale}) rotate(${rotation}deg)`;
4488
+ wrapper.style.transformOrigin = "top center";
4489
+ };
4490
+ setTimeout(() => {
4491
+ scale = calculateFitScale();
4492
+ applyTransform();
4493
+ }, 60);
4223
4494
  let currentPage = 1;
4224
4495
  let totalPages = 1;
4225
4496
  let slides = [];
@@ -4278,21 +4549,30 @@ var OpenDocumentPlugin = class {
4278
4549
  destroy: cleanup,
4279
4550
  isPresentation,
4280
4551
  zoomIn: () => {
4281
- scale += 0.1;
4282
- wrapper.style.transform = `scale(${scale})`;
4552
+ scale += 0.15;
4553
+ applyTransform();
4283
4554
  },
4284
4555
  zoomOut: () => {
4285
- scale = Math.max(0.2, scale - 0.1);
4286
- wrapper.style.transform = `scale(${scale})`;
4556
+ scale = Math.max(0.2, scale - 0.15);
4557
+ applyTransform();
4287
4558
  },
4288
4559
  getZoom: () => scale,
4289
4560
  setZoom: (level) => {
4290
4561
  scale = level;
4291
- wrapper.style.transform = `scale(${scale})`;
4562
+ applyTransform();
4292
4563
  },
4293
4564
  fitToPage: () => {
4294
- scale = 1;
4295
- wrapper.style.transform = "scale(1)";
4565
+ scale = calculateFitScale();
4566
+ rotation = 0;
4567
+ applyTransform();
4568
+ },
4569
+ rotateCW: () => {
4570
+ rotation = (rotation + 90) % 360;
4571
+ applyTransform();
4572
+ },
4573
+ rotateCCW: () => {
4574
+ rotation = (rotation - 90 + 360) % 360;
4575
+ applyTransform();
4296
4576
  },
4297
4577
  goToPage,
4298
4578
  getPageCount: () => totalPages,
@@ -4562,6 +4842,14 @@ var DocPlugin = class {
4562
4842
  group: "zoom",
4563
4843
  execute: () => instance.fitToPage?.()
4564
4844
  },
4845
+ {
4846
+ id: "rotate-cw",
4847
+ icon: "rotate-cw",
4848
+ label: "Rotate",
4849
+ type: "button",
4850
+ group: "view",
4851
+ execute: () => instance.rotateCW?.()
4852
+ },
4565
4853
  {
4566
4854
  id: "copy",
4567
4855
  icon: "copy",
@@ -4700,6 +4988,23 @@ var DocPlugin = class {
4700
4988
  if (totalPages > 1) {
4701
4989
  showPage(1);
4702
4990
  }
4991
+ let rotation = 0;
4992
+ const calculateFitScale = () => {
4993
+ const activeCard = pageCards[currentPage - 1] || wrapper;
4994
+ const elW = activeCard.offsetWidth || 850;
4995
+ const elH = activeCard.offsetHeight || 1e3;
4996
+ const availW = Math.max(200, ctx.container.clientWidth - 48);
4997
+ const availH = Math.max(200, ctx.container.clientHeight - 80);
4998
+ return Math.min(1.1, Math.min(availW / elW, availH / elH));
4999
+ };
5000
+ const applyTransform = () => {
5001
+ wrapper.style.transform = `scale(${scale}) rotate(${rotation}deg)`;
5002
+ wrapper.style.transformOrigin = "top center";
5003
+ };
5004
+ setTimeout(() => {
5005
+ scale = calculateFitScale();
5006
+ applyTransform();
5007
+ }, 60);
4703
5008
  const cleanup = () => {
4704
5009
  indicator?.remove();
4705
5010
  container.remove();
@@ -4712,21 +5017,30 @@ var DocPlugin = class {
4712
5017
  getCurrentPage: () => currentPage,
4713
5018
  goToPage: (page) => showPage(page),
4714
5019
  zoomIn: () => {
4715
- scale += 0.1;
4716
- wrapper.style.transform = `scale(${scale})`;
5020
+ scale += 0.15;
5021
+ applyTransform();
4717
5022
  },
4718
5023
  zoomOut: () => {
4719
- scale = Math.max(0.2, scale - 0.1);
4720
- wrapper.style.transform = `scale(${scale})`;
5024
+ scale = Math.max(0.2, scale - 0.15);
5025
+ applyTransform();
4721
5026
  },
4722
5027
  getZoom: () => scale,
4723
5028
  setZoom: (level) => {
4724
5029
  scale = level;
4725
- wrapper.style.transform = `scale(${scale})`;
5030
+ applyTransform();
4726
5031
  },
4727
5032
  fitToPage: () => {
4728
- scale = 1;
4729
- wrapper.style.transform = "scale(1)";
5033
+ scale = calculateFitScale();
5034
+ rotation = 0;
5035
+ applyTransform();
5036
+ },
5037
+ rotateCW: () => {
5038
+ rotation = (rotation + 90) % 360;
5039
+ applyTransform();
5040
+ },
5041
+ rotateCCW: () => {
5042
+ rotation = (rotation - 90 + 360) % 360;
5043
+ applyTransform();
4730
5044
  },
4731
5045
  copy: () => {
4732
5046
  navigator.clipboard.writeText(extractedRawText);
@@ -4966,6 +5280,14 @@ var PptPlugin = class {
4966
5280
  group: "zoom",
4967
5281
  execute: () => instance.fitToPage?.()
4968
5282
  },
5283
+ {
5284
+ id: "rotate-cw",
5285
+ icon: "rotate-cw",
5286
+ label: "Rotate",
5287
+ type: "button",
5288
+ group: "view",
5289
+ execute: () => instance.rotateCW?.()
5290
+ },
4969
5291
  {
4970
5292
  id: "download",
4971
5293
  icon: "download",
@@ -4999,22 +5321,36 @@ var PptPlugin = class {
4999
5321
  const slideCard = document.createElement("div");
5000
5322
  slideCard.className = "fp-ppt-slide-card";
5001
5323
  slideCard.style.width = "960px";
5002
- slideCard.style.maxWidth = "92%";
5324
+ slideCard.style.maxWidth = "calc(100% - 32px)";
5325
+ slideCard.style.maxHeight = "calc(100% - 48px)";
5003
5326
  slideCard.style.aspectRatio = "16 / 9";
5004
5327
  slideCard.style.backgroundColor = "#ffffff";
5005
5328
  slideCard.style.boxShadow = "0 12px 40px rgba(0,0,0,0.35)";
5006
5329
  slideCard.style.borderRadius = "8px";
5007
5330
  slideCard.style.boxSizing = "border-box";
5008
5331
  slideCard.style.position = "relative";
5009
- slideCard.style.overflow = "hidden";
5010
- slideCard.style.transformOrigin = "center center";
5011
5332
  slideCard.style.transition = "transform 0.2s ease";
5333
+ slideCard.style.transformOrigin = "center center";
5334
+ slideCard.style.flexShrink = "0";
5012
5335
  container.appendChild(slideCard);
5013
5336
  ctx.container.appendChild(container);
5014
5337
  let scale = 1;
5338
+ let rotation = 0;
5015
5339
  let currentSlide = 1;
5016
5340
  let slides = [];
5017
5341
  const createdBlobUrls = [];
5342
+ const calculateFitScale = () => {
5343
+ const availW = Math.max(200, container.clientWidth - 48);
5344
+ const availH = Math.max(200, container.clientHeight - 72);
5345
+ return Math.min(1, Math.min(availW / 960, availH / 540));
5346
+ };
5347
+ const applyTransform = () => {
5348
+ slideCard.style.transform = `scale(${scale}) rotate(${rotation}deg)`;
5349
+ };
5350
+ setTimeout(() => {
5351
+ scale = calculateFitScale();
5352
+ applyTransform();
5353
+ }, 60);
5018
5354
  try {
5019
5355
  const cfbf = new CfbfReader(ctx.buffer);
5020
5356
  const pptStream = cfbf.readStream("PowerPoint Document");
@@ -5115,21 +5451,30 @@ var PptPlugin = class {
5115
5451
  return {
5116
5452
  destroy: cleanup,
5117
5453
  zoomIn: () => {
5118
- scale += 0.1;
5119
- slideCard.style.transform = `scale(${scale})`;
5454
+ scale += 0.15;
5455
+ applyTransform();
5120
5456
  },
5121
5457
  zoomOut: () => {
5122
- scale = Math.max(0.3, scale - 0.1);
5123
- slideCard.style.transform = `scale(${scale})`;
5458
+ scale = Math.max(0.2, scale - 0.15);
5459
+ applyTransform();
5124
5460
  },
5125
5461
  getZoom: () => scale,
5126
5462
  setZoom: (level) => {
5127
5463
  scale = level;
5128
- slideCard.style.transform = `scale(${scale})`;
5464
+ applyTransform();
5129
5465
  },
5130
5466
  fitToPage: () => {
5131
- scale = 1;
5132
- slideCard.style.transform = "scale(1)";
5467
+ scale = calculateFitScale();
5468
+ rotation = 0;
5469
+ applyTransform();
5470
+ },
5471
+ rotateCW: () => {
5472
+ rotation = (rotation + 90) % 360;
5473
+ applyTransform();
5474
+ },
5475
+ rotateCCW: () => {
5476
+ rotation = (rotation - 90 + 360) % 360;
5477
+ applyTransform();
5133
5478
  },
5134
5479
  goToPage: (page) => {
5135
5480
  if (page >= 1 && page <= totalSlides) {