@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/vue.cjs CHANGED
@@ -737,6 +737,8 @@ var FilePreviewViewer = class {
737
737
  keyHandler = null;
738
738
  currentContainer = null;
739
739
  currentOptions = {};
740
+ resizeObserver = null;
741
+ fullscreenHandler = null;
740
742
  /**
741
743
  * Register a preview plugin.
742
744
  */
@@ -809,12 +811,31 @@ var FilePreviewViewer = class {
809
811
  label: "Toggle Fullscreen",
810
812
  type: "button",
811
813
  group: "view",
812
- execute: () => {
813
- if (!document.fullscreenElement) {
814
- this.wrapperEl?.requestFullscreen?.();
815
- } else {
816
- document.exitFullscreen?.();
814
+ execute: async () => {
815
+ try {
816
+ const isNativeFs = !!document.fullscreenElement;
817
+ const isCssFs = this.wrapperEl?.classList.contains("fp-fullscreen-active");
818
+ if (!isNativeFs && !isCssFs) {
819
+ if (this.wrapperEl?.requestFullscreen) {
820
+ await this.wrapperEl.requestFullscreen().catch(() => {
821
+ this.wrapperEl?.classList.add("fp-fullscreen-active");
822
+ });
823
+ } else {
824
+ this.wrapperEl?.classList.add("fp-fullscreen-active");
825
+ }
826
+ } else {
827
+ if (document.fullscreenElement) {
828
+ await document.exitFullscreen().catch(() => {
829
+ });
830
+ }
831
+ this.wrapperEl?.classList.remove("fp-fullscreen-active");
832
+ }
833
+ } catch {
834
+ this.wrapperEl?.classList.toggle("fp-fullscreen-active");
817
835
  }
836
+ setTimeout(() => {
837
+ this.activeInstance?.fitToPage?.();
838
+ }, 120);
818
839
  }
819
840
  });
820
841
  }
@@ -864,6 +885,15 @@ var FilePreviewViewer = class {
864
885
  window.removeEventListener("keydown", this.keyHandler);
865
886
  this.keyHandler = null;
866
887
  }
888
+ if (this.resizeObserver) {
889
+ this.resizeObserver.disconnect();
890
+ this.resizeObserver = null;
891
+ }
892
+ if (this.fullscreenHandler) {
893
+ document.removeEventListener("fullscreenchange", this.fullscreenHandler);
894
+ document.removeEventListener("webkitfullscreenchange", this.fullscreenHandler);
895
+ this.fullscreenHandler = null;
896
+ }
867
897
  this.abort();
868
898
  this.destroyInstance();
869
899
  this.toolbar?.destroy();
@@ -943,6 +973,25 @@ var FilePreviewViewer = class {
943
973
  this.thumbnailPanel = new ThumbnailPanel(thumbnailEl);
944
974
  this.setupKeyboardShortcuts();
945
975
  this.setupDragAndDrop(container, options);
976
+ this.setupResizeAndFullscreenListeners();
977
+ }
978
+ setupResizeAndFullscreenListeners() {
979
+ if (this.fullscreenHandler) return;
980
+ this.fullscreenHandler = () => {
981
+ setTimeout(() => {
982
+ this.activeInstance?.fitToPage?.();
983
+ }, 100);
984
+ };
985
+ document.addEventListener("fullscreenchange", this.fullscreenHandler);
986
+ document.addEventListener("webkitfullscreenchange", this.fullscreenHandler);
987
+ if (typeof ResizeObserver !== "undefined" && this.contentEl) {
988
+ this.resizeObserver = new ResizeObserver(() => {
989
+ if (this.activeInstance && (!this.activeInstance.getZoom || Math.abs((this.activeInstance.getZoom?.() ?? 1) - 1) < 0.05)) {
990
+ this.activeInstance.fitToPage?.();
991
+ }
992
+ });
993
+ this.resizeObserver.observe(this.contentEl);
994
+ }
946
995
  }
947
996
  setupKeyboardShortcuts() {
948
997
  if (this.keyHandler) return;
@@ -1334,7 +1383,8 @@ var PdfPlugin = class {
1334
1383
  container.style.display = "flex";
1335
1384
  container.style.flexDirection = "column";
1336
1385
  container.style.alignItems = "center";
1337
- container.style.padding = "24px 16px";
1386
+ container.style.justifyContent = "flex-start";
1387
+ container.style.padding = "20px 16px";
1338
1388
  container.style.backgroundColor = "#0f172a";
1339
1389
  container.style.boxSizing = "border-box";
1340
1390
  container.style.position = "relative";
@@ -1347,7 +1397,8 @@ var PdfPlugin = class {
1347
1397
  pageCard.style.lineHeight = "0";
1348
1398
  pageCard.style.transition = "transform 0.15s ease";
1349
1399
  pageCard.style.position = "relative";
1350
- const canvas = document.createElement("canvas");
1400
+ pageCard.style.flexShrink = "0";
1401
+ let canvas = document.createElement("canvas");
1351
1402
  pageCard.appendChild(canvas);
1352
1403
  container.appendChild(pageCard);
1353
1404
  const indicator = document.createElement("div");
@@ -1389,14 +1440,22 @@ var PdfPlugin = class {
1389
1440
  }
1390
1441
  currentRenderTask = null;
1391
1442
  }
1443
+ const newCanvas = document.createElement("canvas");
1444
+ pageCard.replaceChild(newCanvas, canvas);
1445
+ canvas = newCanvas;
1392
1446
  currentPage = Math.max(1, Math.min(totalPages, pageNum));
1393
1447
  indicator.textContent = `Page ${currentPage} of ${totalPages}`;
1394
1448
  ctx.emit("page-change", { page: currentPage, total: totalPages });
1395
1449
  const page = await pdfDoc.getPage(currentPage);
1396
1450
  const containerWidth = container.clientWidth || 900;
1451
+ const containerHeight = container.clientHeight || 700;
1397
1452
  const unscaledVp = page.getViewport({ scale: 1, rotation });
1398
- const baseScale = Math.min((containerWidth - 64) / unscaledVp.width, 1.6);
1399
- const effectiveScale = (baseScale > 0 ? baseScale : 1) * zoomScale;
1453
+ const availWidth = Math.max(100, containerWidth - 48);
1454
+ const availHeight = Math.max(100, containerHeight - 88);
1455
+ const scaleW = availWidth / unscaledVp.width;
1456
+ const scaleH = availHeight / unscaledVp.height;
1457
+ const fitScale = Math.min(scaleW, scaleH);
1458
+ const effectiveScale = (fitScale > 0 ? fitScale : 1) * zoomScale;
1400
1459
  const pixelRatio = window.devicePixelRatio || 1;
1401
1460
  const viewport = page.getViewport({ scale: effectiveScale, rotation });
1402
1461
  canvas.width = Math.floor(viewport.width * pixelRatio);
@@ -1453,6 +1512,7 @@ var PdfPlugin = class {
1453
1512
  },
1454
1513
  fitToPage: () => {
1455
1514
  zoomScale = 1;
1515
+ rotation = 0;
1456
1516
  renderPage(currentPage);
1457
1517
  },
1458
1518
  rotateCW: () => {
@@ -1903,6 +1963,14 @@ var DocxPlugin = class {
1903
1963
  group: "zoom",
1904
1964
  execute: () => instance.fitToPage?.()
1905
1965
  },
1966
+ {
1967
+ id: "rotate-cw",
1968
+ icon: "rotate-cw",
1969
+ label: "Rotate",
1970
+ type: "button",
1971
+ group: "view",
1972
+ execute: () => instance.rotateCW?.()
1973
+ },
1906
1974
  {
1907
1975
  id: "download",
1908
1976
  icon: "download",
@@ -2039,6 +2107,26 @@ var DocxPlugin = class {
2039
2107
  if (totalPages > 1) {
2040
2108
  showPage(1);
2041
2109
  }
2110
+ scale = 1;
2111
+ let rotation = 0;
2112
+ const calculateFitScale = () => {
2113
+ const activeEl = pageElements[currentPage - 1] || wrapper.firstElementChild || wrapper;
2114
+ const elW = activeEl.offsetWidth || 816;
2115
+ const elH = activeEl.offsetHeight || 1056;
2116
+ const availW = Math.max(200, ctx.container.clientWidth - 48);
2117
+ const availH = Math.max(200, ctx.container.clientHeight - 80);
2118
+ const sW = availW / elW;
2119
+ const sH = availH / elH;
2120
+ return Math.min(1.1, Math.min(sW, sH));
2121
+ };
2122
+ const applyTransform = () => {
2123
+ wrapper.style.transform = `scale(${scale}) rotate(${rotation}deg)`;
2124
+ wrapper.style.transformOrigin = "top center";
2125
+ };
2126
+ setTimeout(() => {
2127
+ scale = calculateFitScale();
2128
+ applyTransform();
2129
+ }, 60);
2042
2130
  const cleanup = () => {
2043
2131
  indicator?.remove();
2044
2132
  for (const url of createdBlobUrls) {
@@ -2057,21 +2145,30 @@ var DocxPlugin = class {
2057
2145
  showPage(page);
2058
2146
  },
2059
2147
  zoomIn: () => {
2060
- scale += 0.1;
2061
- wrapper.style.transform = `scale(${scale})`;
2148
+ scale += 0.15;
2149
+ applyTransform();
2062
2150
  },
2063
2151
  zoomOut: () => {
2064
- scale = Math.max(0.2, scale - 0.1);
2065
- wrapper.style.transform = `scale(${scale})`;
2152
+ scale = Math.max(0.2, scale - 0.15);
2153
+ applyTransform();
2066
2154
  },
2067
2155
  getZoom: () => scale,
2068
2156
  setZoom: (level) => {
2069
2157
  scale = level;
2070
- wrapper.style.transform = `scale(${scale})`;
2158
+ applyTransform();
2071
2159
  },
2072
2160
  fitToPage: () => {
2073
- scale = 1;
2074
- wrapper.style.transform = "scale(1)";
2161
+ scale = calculateFitScale();
2162
+ rotation = 0;
2163
+ applyTransform();
2164
+ },
2165
+ rotateCW: () => {
2166
+ rotation = (rotation + 90) % 360;
2167
+ applyTransform();
2168
+ },
2169
+ rotateCCW: () => {
2170
+ rotation = (rotation - 90 + 360) % 360;
2171
+ applyTransform();
2075
2172
  },
2076
2173
  download: () => {
2077
2174
  const blob = new Blob([ctx.buffer], { type: this.mimeTypes[0] });
@@ -2365,6 +2462,26 @@ var ExcelPlugin = class {
2365
2462
  instance.zoomIn?.();
2366
2463
  }
2367
2464
  },
2465
+ {
2466
+ id: "fit-page",
2467
+ icon: "fit-page",
2468
+ label: "Fit to View",
2469
+ type: "button",
2470
+ group: "zoom",
2471
+ execute: () => {
2472
+ instance.fitToPage?.();
2473
+ }
2474
+ },
2475
+ {
2476
+ id: "rotate-cw",
2477
+ icon: "rotate-cw",
2478
+ label: "Rotate",
2479
+ type: "button",
2480
+ group: "view",
2481
+ execute: () => {
2482
+ instance.rotateCW?.();
2483
+ }
2484
+ },
2368
2485
  {
2369
2486
  id: "download",
2370
2487
  icon: "download",
@@ -2415,9 +2532,23 @@ var ExcelPlugin = class {
2415
2532
  container.appendChild(tabsArea);
2416
2533
  ctx.container.appendChild(container);
2417
2534
  let scale = 1;
2535
+ let rotation = 0;
2418
2536
  let currentSheetIndex = 1;
2419
2537
  let sheetNames = [];
2420
2538
  let wb = null;
2539
+ const applyTransform = () => {
2540
+ contentArea.style.transform = `scale(${scale}) rotate(${rotation}deg)`;
2541
+ contentArea.style.transformOrigin = "top left";
2542
+ };
2543
+ const calculateFitScale = () => {
2544
+ const table = contentArea.querySelector("table");
2545
+ if (!table) return 1;
2546
+ const availW = Math.max(200, container.clientWidth - 48);
2547
+ const availH = Math.max(200, container.clientHeight - 80);
2548
+ const tW = table.offsetWidth || 800;
2549
+ const tH = table.offsetHeight || 600;
2550
+ return Math.min(1, Math.min(availW / tW, availH / tH));
2551
+ };
2421
2552
  try {
2422
2553
  wb = XLSX__namespace.read(new Uint8Array(ctx.buffer), { type: "array", cellDates: true });
2423
2554
  sheetNames = wb.SheetNames || [];
@@ -2505,17 +2636,30 @@ var ExcelPlugin = class {
2505
2636
  return {
2506
2637
  destroy: cleanup,
2507
2638
  zoomIn: () => {
2508
- scale += 0.1;
2509
- contentArea.style.transform = `scale(${scale})`;
2639
+ scale += 0.15;
2640
+ applyTransform();
2510
2641
  },
2511
2642
  zoomOut: () => {
2512
- scale = Math.max(0.2, scale - 0.1);
2513
- contentArea.style.transform = `scale(${scale})`;
2643
+ scale = Math.max(0.2, scale - 0.15);
2644
+ applyTransform();
2514
2645
  },
2515
2646
  getZoom: () => scale,
2516
2647
  setZoom: (level) => {
2517
2648
  scale = level;
2518
- contentArea.style.transform = `scale(${scale})`;
2649
+ applyTransform();
2650
+ },
2651
+ fitToPage: () => {
2652
+ scale = calculateFitScale();
2653
+ rotation = 0;
2654
+ applyTransform();
2655
+ },
2656
+ rotateCW: () => {
2657
+ rotation = (rotation + 90) % 360;
2658
+ applyTransform();
2659
+ },
2660
+ rotateCCW: () => {
2661
+ rotation = (rotation - 90 + 360) % 360;
2662
+ applyTransform();
2519
2663
  },
2520
2664
  goToPage: (page) => {
2521
2665
  if (page > 0 && page <= sheetNames.length) {
@@ -2765,6 +2909,26 @@ var CodePlugin = class {
2765
2909
  instance.zoomIn?.();
2766
2910
  }
2767
2911
  },
2912
+ {
2913
+ id: "fit-page",
2914
+ icon: "fit-page",
2915
+ label: "Fit to View",
2916
+ type: "button",
2917
+ group: "zoom",
2918
+ execute: () => {
2919
+ instance.fitToPage?.();
2920
+ }
2921
+ },
2922
+ {
2923
+ id: "rotate-cw",
2924
+ icon: "rotate-cw",
2925
+ label: "Rotate",
2926
+ type: "button",
2927
+ group: "view",
2928
+ execute: () => {
2929
+ instance.rotateCW?.();
2930
+ }
2931
+ },
2768
2932
  {
2769
2933
  id: "copy",
2770
2934
  icon: "copy",
@@ -2814,6 +2978,7 @@ var CodePlugin = class {
2814
2978
  container.style.padding = "16px";
2815
2979
  container.style.boxSizing = "border-box";
2816
2980
  let fontSize = 13;
2981
+ let rotation = 0;
2817
2982
  const pre = document.createElement("pre");
2818
2983
  pre.style.margin = "0";
2819
2984
  pre.style.fontFamily = "Consolas, Menlo, Monaco, monospace";
@@ -2896,6 +3061,22 @@ var CodePlugin = class {
2896
3061
  fontSize = Math.round(13 * level);
2897
3062
  pre.style.fontSize = `${fontSize}px`;
2898
3063
  },
3064
+ fitToPage: () => {
3065
+ fontSize = 13;
3066
+ rotation = 0;
3067
+ pre.style.fontSize = "13px";
3068
+ pre.style.transform = "none";
3069
+ },
3070
+ rotateCW: () => {
3071
+ rotation = (rotation + 90) % 360;
3072
+ pre.style.transform = `rotate(${rotation}deg)`;
3073
+ pre.style.transformOrigin = "top left";
3074
+ },
3075
+ rotateCCW: () => {
3076
+ rotation = (rotation - 90 + 360) % 360;
3077
+ pre.style.transform = `rotate(${rotation}deg)`;
3078
+ pre.style.transformOrigin = "top left";
3079
+ },
2899
3080
  download: () => {
2900
3081
  const mimeType = ctx.metadata.mimeType || "text/plain";
2901
3082
  const blob = new Blob([ctx.buffer], { type: mimeType });
@@ -3407,6 +3588,14 @@ var PptxPlugin = class {
3407
3588
  group: "zoom",
3408
3589
  execute: () => instance.fitToPage?.()
3409
3590
  },
3591
+ {
3592
+ id: "rotate-cw",
3593
+ icon: "rotate-cw",
3594
+ label: "Rotate",
3595
+ type: "button",
3596
+ group: "view",
3597
+ execute: () => instance.rotateCW?.()
3598
+ },
3410
3599
  {
3411
3600
  id: "download",
3412
3601
  icon: "download",
@@ -3431,6 +3620,7 @@ var PptxPlugin = class {
3431
3620
  const slideCount = renderer.slidePaths?.length || 1;
3432
3621
  let currentSlide = 1;
3433
3622
  let scale = 1;
3623
+ let rotation = 0;
3434
3624
  const wrapper = document.createElement("div");
3435
3625
  wrapper.className = "fp-pptx-wrapper";
3436
3626
  wrapper.style.cssText = `
@@ -3453,6 +3643,8 @@ var PptxPlugin = class {
3453
3643
  background: #ffffff;
3454
3644
  transform-origin: top center;
3455
3645
  transition: transform 0.2s ease;
3646
+ max-width: calc(100% - 32px);
3647
+ max-height: calc(100% - 48px);
3456
3648
  `;
3457
3649
  const canvas = document.createElement("canvas");
3458
3650
  slideContainer.appendChild(canvas);
@@ -3460,10 +3652,22 @@ var PptxPlugin = class {
3460
3652
  ctx.container.innerHTML = "";
3461
3653
  ctx.container.style.overflow = "auto";
3462
3654
  ctx.container.appendChild(wrapper);
3655
+ const calculateFitScale = () => {
3656
+ const availW = Math.max(200, ctx.container.clientWidth - 48);
3657
+ const availH = Math.max(200, ctx.container.clientHeight - 72);
3658
+ const cW = canvas.offsetWidth || 1280;
3659
+ const cH = canvas.offsetHeight || 720;
3660
+ return Math.min(1, Math.min(availW / cW, availH / cH));
3661
+ };
3662
+ const applyTransform = () => {
3663
+ slideContainer.style.transform = `scale(${scale}) rotate(${rotation}deg)`;
3664
+ };
3463
3665
  const renderCurrentSlide = async () => {
3464
3666
  try {
3465
3667
  await renderer.renderSlide(currentSlide - 1, canvas, 1280);
3466
3668
  ctx.emit("page-change", { page: currentSlide, totalPages: slideCount });
3669
+ scale = calculateFitScale();
3670
+ applyTransform();
3467
3671
  } catch (err) {
3468
3672
  console.error("[PptxPlugin] Failed to render slide:", err);
3469
3673
  }
@@ -3486,21 +3690,30 @@ var PptxPlugin = class {
3486
3690
  getPageCount: () => slideCount,
3487
3691
  getCurrentPage: () => currentSlide,
3488
3692
  zoomIn: () => {
3489
- scale += 0.1;
3490
- slideContainer.style.transform = `scale(${scale})`;
3693
+ scale += 0.15;
3694
+ applyTransform();
3491
3695
  },
3492
3696
  zoomOut: () => {
3493
- scale = Math.max(0.2, scale - 0.1);
3494
- slideContainer.style.transform = `scale(${scale})`;
3697
+ scale = Math.max(0.2, scale - 0.15);
3698
+ applyTransform();
3495
3699
  },
3496
3700
  getZoom: () => scale,
3497
3701
  setZoom: (level) => {
3498
3702
  scale = level;
3499
- slideContainer.style.transform = `scale(${scale})`;
3703
+ applyTransform();
3500
3704
  },
3501
3705
  fitToPage: () => {
3502
- scale = 1;
3503
- slideContainer.style.transform = "scale(1)";
3706
+ scale = calculateFitScale();
3707
+ rotation = 0;
3708
+ applyTransform();
3709
+ },
3710
+ rotateCW: () => {
3711
+ rotation = (rotation + 90) % 360;
3712
+ applyTransform();
3713
+ },
3714
+ rotateCCW: () => {
3715
+ rotation = (rotation - 90 + 360) % 360;
3716
+ applyTransform();
3504
3717
  },
3505
3718
  getThumbnails: () => {
3506
3719
  const list = [];
@@ -3781,6 +3994,14 @@ var RtfPlugin = class {
3781
3994
  group: "zoom",
3782
3995
  execute: () => instance.fitToPage?.()
3783
3996
  },
3997
+ {
3998
+ id: "rotate-cw",
3999
+ icon: "rotate-cw",
4000
+ label: "Rotate",
4001
+ type: "button",
4002
+ group: "view",
4003
+ execute: () => instance.rotateCW?.()
4004
+ },
3784
4005
  {
3785
4006
  id: "download",
3786
4007
  icon: "download",
@@ -3817,7 +4038,24 @@ var RtfPlugin = class {
3817
4038
  ctx.container.style.backgroundColor = "#f1f5f9";
3818
4039
  ctx.container.appendChild(wrapper);
3819
4040
  let scale = 1;
4041
+ let rotation = 0;
3820
4042
  let pageElements = [];
4043
+ const calculateFitScale = () => {
4044
+ const activeEl = pageElements[currentPage - 1] || wrapper;
4045
+ const elW = activeEl.offsetWidth || 850;
4046
+ const elH = activeEl.offsetHeight || 1e3;
4047
+ const availW = Math.max(200, ctx.container.clientWidth - 48);
4048
+ const availH = Math.max(200, ctx.container.clientHeight - 80);
4049
+ return Math.min(1.1, Math.min(availW / elW, availH / elH));
4050
+ };
4051
+ const applyTransform = () => {
4052
+ wrapper.style.transform = `scale(${scale}) rotate(${rotation}deg)`;
4053
+ wrapper.style.transformOrigin = "top center";
4054
+ };
4055
+ setTimeout(() => {
4056
+ scale = calculateFitScale();
4057
+ applyTransform();
4058
+ }, 60);
3821
4059
  try {
3822
4060
  if (typeof RTFJS__namespace.loggingEnabled === "function") {
3823
4061
  RTFJS__namespace.loggingEnabled(false);
@@ -3894,21 +4132,30 @@ var RtfPlugin = class {
3894
4132
  getCurrentPage: () => currentPage,
3895
4133
  goToPage: (page) => showPage(page),
3896
4134
  zoomIn: () => {
3897
- scale += 0.1;
3898
- wrapper.style.transform = `scale(${scale})`;
4135
+ scale += 0.15;
4136
+ applyTransform();
3899
4137
  },
3900
4138
  zoomOut: () => {
3901
- scale = Math.max(0.2, scale - 0.1);
3902
- wrapper.style.transform = `scale(${scale})`;
4139
+ scale = Math.max(0.2, scale - 0.15);
4140
+ applyTransform();
3903
4141
  },
3904
4142
  getZoom: () => scale,
3905
4143
  setZoom: (level) => {
3906
4144
  scale = level;
3907
- wrapper.style.transform = `scale(${scale})`;
4145
+ applyTransform();
3908
4146
  },
3909
4147
  fitToPage: () => {
3910
- scale = 1;
3911
- wrapper.style.transform = "scale(1)";
4148
+ scale = calculateFitScale();
4149
+ rotation = 0;
4150
+ applyTransform();
4151
+ },
4152
+ rotateCW: () => {
4153
+ rotation = (rotation + 90) % 360;
4154
+ applyTransform();
4155
+ },
4156
+ rotateCCW: () => {
4157
+ rotation = (rotation - 90 + 360) % 360;
4158
+ applyTransform();
3912
4159
  },
3913
4160
  download: () => {
3914
4161
  const blob = new Blob([ctx.buffer], { type: "application/rtf" });
@@ -4136,11 +4383,19 @@ var OpenDocumentPlugin = class {
4136
4383
  {
4137
4384
  id: "fit-page",
4138
4385
  icon: "fit-page",
4139
- label: "Fit to Page",
4386
+ label: isPresentation ? "Fit to Slide" : "Fit to Page",
4140
4387
  type: "button",
4141
4388
  group: "zoom",
4142
4389
  execute: () => instance.fitToPage?.()
4143
4390
  },
4391
+ {
4392
+ id: "rotate-cw",
4393
+ icon: "rotate-cw",
4394
+ label: "Rotate",
4395
+ type: "button",
4396
+ group: "view",
4397
+ execute: () => instance.rotateCW?.()
4398
+ },
4144
4399
  {
4145
4400
  id: "download",
4146
4401
  icon: "download",
@@ -4204,6 +4459,22 @@ var OpenDocumentPlugin = class {
4204
4459
  container.appendChild(wrapper);
4205
4460
  ctx.container.appendChild(container);
4206
4461
  let scale = 1;
4462
+ let rotation = 0;
4463
+ const calculateFitScale = () => {
4464
+ const elW = wrapper.offsetWidth || 850;
4465
+ const elH = wrapper.offsetHeight || (isPresentation ? 540 : 1e3);
4466
+ const availW = Math.max(200, ctx.container.clientWidth - 48);
4467
+ const availH = Math.max(200, ctx.container.clientHeight - 80);
4468
+ return Math.min(1, Math.min(availW / elW, availH / elH));
4469
+ };
4470
+ const applyTransform = () => {
4471
+ wrapper.style.transform = `scale(${scale}) rotate(${rotation}deg)`;
4472
+ wrapper.style.transformOrigin = "top center";
4473
+ };
4474
+ setTimeout(() => {
4475
+ scale = calculateFitScale();
4476
+ applyTransform();
4477
+ }, 60);
4207
4478
  let currentPage = 1;
4208
4479
  let totalPages = 1;
4209
4480
  let slides = [];
@@ -4262,21 +4533,30 @@ var OpenDocumentPlugin = class {
4262
4533
  destroy: cleanup,
4263
4534
  isPresentation,
4264
4535
  zoomIn: () => {
4265
- scale += 0.1;
4266
- wrapper.style.transform = `scale(${scale})`;
4536
+ scale += 0.15;
4537
+ applyTransform();
4267
4538
  },
4268
4539
  zoomOut: () => {
4269
- scale = Math.max(0.2, scale - 0.1);
4270
- wrapper.style.transform = `scale(${scale})`;
4540
+ scale = Math.max(0.2, scale - 0.15);
4541
+ applyTransform();
4271
4542
  },
4272
4543
  getZoom: () => scale,
4273
4544
  setZoom: (level) => {
4274
4545
  scale = level;
4275
- wrapper.style.transform = `scale(${scale})`;
4546
+ applyTransform();
4276
4547
  },
4277
4548
  fitToPage: () => {
4278
- scale = 1;
4279
- wrapper.style.transform = "scale(1)";
4549
+ scale = calculateFitScale();
4550
+ rotation = 0;
4551
+ applyTransform();
4552
+ },
4553
+ rotateCW: () => {
4554
+ rotation = (rotation + 90) % 360;
4555
+ applyTransform();
4556
+ },
4557
+ rotateCCW: () => {
4558
+ rotation = (rotation - 90 + 360) % 360;
4559
+ applyTransform();
4280
4560
  },
4281
4561
  goToPage,
4282
4562
  getPageCount: () => totalPages,
@@ -4546,6 +4826,14 @@ var DocPlugin = class {
4546
4826
  group: "zoom",
4547
4827
  execute: () => instance.fitToPage?.()
4548
4828
  },
4829
+ {
4830
+ id: "rotate-cw",
4831
+ icon: "rotate-cw",
4832
+ label: "Rotate",
4833
+ type: "button",
4834
+ group: "view",
4835
+ execute: () => instance.rotateCW?.()
4836
+ },
4549
4837
  {
4550
4838
  id: "copy",
4551
4839
  icon: "copy",
@@ -4684,6 +4972,23 @@ var DocPlugin = class {
4684
4972
  if (totalPages > 1) {
4685
4973
  showPage(1);
4686
4974
  }
4975
+ let rotation = 0;
4976
+ const calculateFitScale = () => {
4977
+ const activeCard = pageCards[currentPage - 1] || wrapper;
4978
+ const elW = activeCard.offsetWidth || 850;
4979
+ const elH = activeCard.offsetHeight || 1e3;
4980
+ const availW = Math.max(200, ctx.container.clientWidth - 48);
4981
+ const availH = Math.max(200, ctx.container.clientHeight - 80);
4982
+ return Math.min(1.1, Math.min(availW / elW, availH / elH));
4983
+ };
4984
+ const applyTransform = () => {
4985
+ wrapper.style.transform = `scale(${scale}) rotate(${rotation}deg)`;
4986
+ wrapper.style.transformOrigin = "top center";
4987
+ };
4988
+ setTimeout(() => {
4989
+ scale = calculateFitScale();
4990
+ applyTransform();
4991
+ }, 60);
4687
4992
  const cleanup = () => {
4688
4993
  indicator?.remove();
4689
4994
  container.remove();
@@ -4696,21 +5001,30 @@ var DocPlugin = class {
4696
5001
  getCurrentPage: () => currentPage,
4697
5002
  goToPage: (page) => showPage(page),
4698
5003
  zoomIn: () => {
4699
- scale += 0.1;
4700
- wrapper.style.transform = `scale(${scale})`;
5004
+ scale += 0.15;
5005
+ applyTransform();
4701
5006
  },
4702
5007
  zoomOut: () => {
4703
- scale = Math.max(0.2, scale - 0.1);
4704
- wrapper.style.transform = `scale(${scale})`;
5008
+ scale = Math.max(0.2, scale - 0.15);
5009
+ applyTransform();
4705
5010
  },
4706
5011
  getZoom: () => scale,
4707
5012
  setZoom: (level) => {
4708
5013
  scale = level;
4709
- wrapper.style.transform = `scale(${scale})`;
5014
+ applyTransform();
4710
5015
  },
4711
5016
  fitToPage: () => {
4712
- scale = 1;
4713
- wrapper.style.transform = "scale(1)";
5017
+ scale = calculateFitScale();
5018
+ rotation = 0;
5019
+ applyTransform();
5020
+ },
5021
+ rotateCW: () => {
5022
+ rotation = (rotation + 90) % 360;
5023
+ applyTransform();
5024
+ },
5025
+ rotateCCW: () => {
5026
+ rotation = (rotation - 90 + 360) % 360;
5027
+ applyTransform();
4714
5028
  },
4715
5029
  copy: () => {
4716
5030
  navigator.clipboard.writeText(extractedRawText);
@@ -4950,6 +5264,14 @@ var PptPlugin = class {
4950
5264
  group: "zoom",
4951
5265
  execute: () => instance.fitToPage?.()
4952
5266
  },
5267
+ {
5268
+ id: "rotate-cw",
5269
+ icon: "rotate-cw",
5270
+ label: "Rotate",
5271
+ type: "button",
5272
+ group: "view",
5273
+ execute: () => instance.rotateCW?.()
5274
+ },
4953
5275
  {
4954
5276
  id: "download",
4955
5277
  icon: "download",
@@ -4983,22 +5305,36 @@ var PptPlugin = class {
4983
5305
  const slideCard = document.createElement("div");
4984
5306
  slideCard.className = "fp-ppt-slide-card";
4985
5307
  slideCard.style.width = "960px";
4986
- slideCard.style.maxWidth = "92%";
5308
+ slideCard.style.maxWidth = "calc(100% - 32px)";
5309
+ slideCard.style.maxHeight = "calc(100% - 48px)";
4987
5310
  slideCard.style.aspectRatio = "16 / 9";
4988
5311
  slideCard.style.backgroundColor = "#ffffff";
4989
5312
  slideCard.style.boxShadow = "0 12px 40px rgba(0,0,0,0.35)";
4990
5313
  slideCard.style.borderRadius = "8px";
4991
5314
  slideCard.style.boxSizing = "border-box";
4992
5315
  slideCard.style.position = "relative";
4993
- slideCard.style.overflow = "hidden";
4994
- slideCard.style.transformOrigin = "center center";
4995
5316
  slideCard.style.transition = "transform 0.2s ease";
5317
+ slideCard.style.transformOrigin = "center center";
5318
+ slideCard.style.flexShrink = "0";
4996
5319
  container.appendChild(slideCard);
4997
5320
  ctx.container.appendChild(container);
4998
5321
  let scale = 1;
5322
+ let rotation = 0;
4999
5323
  let currentSlide = 1;
5000
5324
  let slides = [];
5001
5325
  const createdBlobUrls = [];
5326
+ const calculateFitScale = () => {
5327
+ const availW = Math.max(200, container.clientWidth - 48);
5328
+ const availH = Math.max(200, container.clientHeight - 72);
5329
+ return Math.min(1, Math.min(availW / 960, availH / 540));
5330
+ };
5331
+ const applyTransform = () => {
5332
+ slideCard.style.transform = `scale(${scale}) rotate(${rotation}deg)`;
5333
+ };
5334
+ setTimeout(() => {
5335
+ scale = calculateFitScale();
5336
+ applyTransform();
5337
+ }, 60);
5002
5338
  try {
5003
5339
  const cfbf = new CfbfReader(ctx.buffer);
5004
5340
  const pptStream = cfbf.readStream("PowerPoint Document");
@@ -5099,21 +5435,30 @@ var PptPlugin = class {
5099
5435
  return {
5100
5436
  destroy: cleanup,
5101
5437
  zoomIn: () => {
5102
- scale += 0.1;
5103
- slideCard.style.transform = `scale(${scale})`;
5438
+ scale += 0.15;
5439
+ applyTransform();
5104
5440
  },
5105
5441
  zoomOut: () => {
5106
- scale = Math.max(0.3, scale - 0.1);
5107
- slideCard.style.transform = `scale(${scale})`;
5442
+ scale = Math.max(0.2, scale - 0.15);
5443
+ applyTransform();
5108
5444
  },
5109
5445
  getZoom: () => scale,
5110
5446
  setZoom: (level) => {
5111
5447
  scale = level;
5112
- slideCard.style.transform = `scale(${scale})`;
5448
+ applyTransform();
5113
5449
  },
5114
5450
  fitToPage: () => {
5115
- scale = 1;
5116
- slideCard.style.transform = "scale(1)";
5451
+ scale = calculateFitScale();
5452
+ rotation = 0;
5453
+ applyTransform();
5454
+ },
5455
+ rotateCW: () => {
5456
+ rotation = (rotation + 90) % 360;
5457
+ applyTransform();
5458
+ },
5459
+ rotateCCW: () => {
5460
+ rotation = (rotation - 90 + 360) % 360;
5461
+ applyTransform();
5117
5462
  },
5118
5463
  goToPage: (page) => {
5119
5464
  if (page >= 1 && page <= totalSlides) {