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