@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.js CHANGED
@@ -706,6 +706,8 @@ var FilePreviewViewer = class {
706
706
  keyHandler = null;
707
707
  currentContainer = null;
708
708
  currentOptions = {};
709
+ resizeObserver = null;
710
+ fullscreenHandler = null;
709
711
  /**
710
712
  * Register a preview plugin.
711
713
  */
@@ -778,12 +780,31 @@ var FilePreviewViewer = class {
778
780
  label: "Toggle Fullscreen",
779
781
  type: "button",
780
782
  group: "view",
781
- execute: () => {
782
- if (!document.fullscreenElement) {
783
- this.wrapperEl?.requestFullscreen?.();
784
- } else {
785
- document.exitFullscreen?.();
783
+ execute: async () => {
784
+ try {
785
+ const isNativeFs = !!document.fullscreenElement;
786
+ const isCssFs = this.wrapperEl?.classList.contains("fp-fullscreen-active");
787
+ if (!isNativeFs && !isCssFs) {
788
+ if (this.wrapperEl?.requestFullscreen) {
789
+ await this.wrapperEl.requestFullscreen().catch(() => {
790
+ this.wrapperEl?.classList.add("fp-fullscreen-active");
791
+ });
792
+ } else {
793
+ this.wrapperEl?.classList.add("fp-fullscreen-active");
794
+ }
795
+ } else {
796
+ if (document.fullscreenElement) {
797
+ await document.exitFullscreen().catch(() => {
798
+ });
799
+ }
800
+ this.wrapperEl?.classList.remove("fp-fullscreen-active");
801
+ }
802
+ } catch {
803
+ this.wrapperEl?.classList.toggle("fp-fullscreen-active");
786
804
  }
805
+ setTimeout(() => {
806
+ this.activeInstance?.fitToPage?.();
807
+ }, 120);
787
808
  }
788
809
  });
789
810
  }
@@ -833,6 +854,15 @@ var FilePreviewViewer = class {
833
854
  window.removeEventListener("keydown", this.keyHandler);
834
855
  this.keyHandler = null;
835
856
  }
857
+ if (this.resizeObserver) {
858
+ this.resizeObserver.disconnect();
859
+ this.resizeObserver = null;
860
+ }
861
+ if (this.fullscreenHandler) {
862
+ document.removeEventListener("fullscreenchange", this.fullscreenHandler);
863
+ document.removeEventListener("webkitfullscreenchange", this.fullscreenHandler);
864
+ this.fullscreenHandler = null;
865
+ }
836
866
  this.abort();
837
867
  this.destroyInstance();
838
868
  this.toolbar?.destroy();
@@ -912,6 +942,25 @@ var FilePreviewViewer = class {
912
942
  this.thumbnailPanel = new ThumbnailPanel(thumbnailEl);
913
943
  this.setupKeyboardShortcuts();
914
944
  this.setupDragAndDrop(container, options);
945
+ this.setupResizeAndFullscreenListeners();
946
+ }
947
+ setupResizeAndFullscreenListeners() {
948
+ if (this.fullscreenHandler) return;
949
+ this.fullscreenHandler = () => {
950
+ setTimeout(() => {
951
+ this.activeInstance?.fitToPage?.();
952
+ }, 100);
953
+ };
954
+ document.addEventListener("fullscreenchange", this.fullscreenHandler);
955
+ document.addEventListener("webkitfullscreenchange", this.fullscreenHandler);
956
+ if (typeof ResizeObserver !== "undefined" && this.contentEl) {
957
+ this.resizeObserver = new ResizeObserver(() => {
958
+ if (this.activeInstance && (!this.activeInstance.getZoom || Math.abs((this.activeInstance.getZoom?.() ?? 1) - 1) < 0.05)) {
959
+ this.activeInstance.fitToPage?.();
960
+ }
961
+ });
962
+ this.resizeObserver.observe(this.contentEl);
963
+ }
915
964
  }
916
965
  setupKeyboardShortcuts() {
917
966
  if (this.keyHandler) return;
@@ -1303,7 +1352,8 @@ var PdfPlugin = class {
1303
1352
  container.style.display = "flex";
1304
1353
  container.style.flexDirection = "column";
1305
1354
  container.style.alignItems = "center";
1306
- container.style.padding = "24px 16px";
1355
+ container.style.justifyContent = "flex-start";
1356
+ container.style.padding = "20px 16px";
1307
1357
  container.style.backgroundColor = "#0f172a";
1308
1358
  container.style.boxSizing = "border-box";
1309
1359
  container.style.position = "relative";
@@ -1316,7 +1366,8 @@ var PdfPlugin = class {
1316
1366
  pageCard.style.lineHeight = "0";
1317
1367
  pageCard.style.transition = "transform 0.15s ease";
1318
1368
  pageCard.style.position = "relative";
1319
- const canvas = document.createElement("canvas");
1369
+ pageCard.style.flexShrink = "0";
1370
+ let canvas = document.createElement("canvas");
1320
1371
  pageCard.appendChild(canvas);
1321
1372
  container.appendChild(pageCard);
1322
1373
  const indicator = document.createElement("div");
@@ -1358,14 +1409,22 @@ var PdfPlugin = class {
1358
1409
  }
1359
1410
  currentRenderTask = null;
1360
1411
  }
1412
+ const newCanvas = document.createElement("canvas");
1413
+ pageCard.replaceChild(newCanvas, canvas);
1414
+ canvas = newCanvas;
1361
1415
  currentPage = Math.max(1, Math.min(totalPages, pageNum));
1362
1416
  indicator.textContent = `Page ${currentPage} of ${totalPages}`;
1363
1417
  ctx.emit("page-change", { page: currentPage, total: totalPages });
1364
1418
  const page = await pdfDoc.getPage(currentPage);
1365
1419
  const containerWidth = container.clientWidth || 900;
1420
+ const containerHeight = container.clientHeight || 700;
1366
1421
  const unscaledVp = page.getViewport({ scale: 1, rotation });
1367
- const baseScale = Math.min((containerWidth - 64) / unscaledVp.width, 1.6);
1368
- const effectiveScale = (baseScale > 0 ? baseScale : 1) * zoomScale;
1422
+ const availWidth = Math.max(100, containerWidth - 48);
1423
+ const availHeight = Math.max(100, containerHeight - 88);
1424
+ const scaleW = availWidth / unscaledVp.width;
1425
+ const scaleH = availHeight / unscaledVp.height;
1426
+ const fitScale = Math.min(scaleW, scaleH);
1427
+ const effectiveScale = (fitScale > 0 ? fitScale : 1) * zoomScale;
1369
1428
  const pixelRatio = window.devicePixelRatio || 1;
1370
1429
  const viewport = page.getViewport({ scale: effectiveScale, rotation });
1371
1430
  canvas.width = Math.floor(viewport.width * pixelRatio);
@@ -1422,6 +1481,7 @@ var PdfPlugin = class {
1422
1481
  },
1423
1482
  fitToPage: () => {
1424
1483
  zoomScale = 1;
1484
+ rotation = 0;
1425
1485
  renderPage(currentPage);
1426
1486
  },
1427
1487
  rotateCW: () => {
@@ -1872,6 +1932,14 @@ var DocxPlugin = class {
1872
1932
  group: "zoom",
1873
1933
  execute: () => instance.fitToPage?.()
1874
1934
  },
1935
+ {
1936
+ id: "rotate-cw",
1937
+ icon: "rotate-cw",
1938
+ label: "Rotate",
1939
+ type: "button",
1940
+ group: "view",
1941
+ execute: () => instance.rotateCW?.()
1942
+ },
1875
1943
  {
1876
1944
  id: "download",
1877
1945
  icon: "download",
@@ -2008,6 +2076,26 @@ var DocxPlugin = class {
2008
2076
  if (totalPages > 1) {
2009
2077
  showPage(1);
2010
2078
  }
2079
+ scale = 1;
2080
+ let rotation = 0;
2081
+ const calculateFitScale = () => {
2082
+ const activeEl = pageElements[currentPage - 1] || wrapper.firstElementChild || wrapper;
2083
+ const elW = activeEl.offsetWidth || 816;
2084
+ const elH = activeEl.offsetHeight || 1056;
2085
+ const availW = Math.max(200, ctx.container.clientWidth - 48);
2086
+ const availH = Math.max(200, ctx.container.clientHeight - 80);
2087
+ const sW = availW / elW;
2088
+ const sH = availH / elH;
2089
+ return Math.min(1.1, Math.min(sW, sH));
2090
+ };
2091
+ const applyTransform = () => {
2092
+ wrapper.style.transform = `scale(${scale}) rotate(${rotation}deg)`;
2093
+ wrapper.style.transformOrigin = "top center";
2094
+ };
2095
+ setTimeout(() => {
2096
+ scale = calculateFitScale();
2097
+ applyTransform();
2098
+ }, 60);
2011
2099
  const cleanup = () => {
2012
2100
  indicator?.remove();
2013
2101
  for (const url of createdBlobUrls) {
@@ -2026,21 +2114,30 @@ var DocxPlugin = class {
2026
2114
  showPage(page);
2027
2115
  },
2028
2116
  zoomIn: () => {
2029
- scale += 0.1;
2030
- wrapper.style.transform = `scale(${scale})`;
2117
+ scale += 0.15;
2118
+ applyTransform();
2031
2119
  },
2032
2120
  zoomOut: () => {
2033
- scale = Math.max(0.2, scale - 0.1);
2034
- wrapper.style.transform = `scale(${scale})`;
2121
+ scale = Math.max(0.2, scale - 0.15);
2122
+ applyTransform();
2035
2123
  },
2036
2124
  getZoom: () => scale,
2037
2125
  setZoom: (level) => {
2038
2126
  scale = level;
2039
- wrapper.style.transform = `scale(${scale})`;
2127
+ applyTransform();
2040
2128
  },
2041
2129
  fitToPage: () => {
2042
- scale = 1;
2043
- wrapper.style.transform = "scale(1)";
2130
+ scale = calculateFitScale();
2131
+ rotation = 0;
2132
+ applyTransform();
2133
+ },
2134
+ rotateCW: () => {
2135
+ rotation = (rotation + 90) % 360;
2136
+ applyTransform();
2137
+ },
2138
+ rotateCCW: () => {
2139
+ rotation = (rotation - 90 + 360) % 360;
2140
+ applyTransform();
2044
2141
  },
2045
2142
  download: () => {
2046
2143
  const blob = new Blob([ctx.buffer], { type: this.mimeTypes[0] });
@@ -2334,6 +2431,26 @@ var ExcelPlugin = class {
2334
2431
  instance.zoomIn?.();
2335
2432
  }
2336
2433
  },
2434
+ {
2435
+ id: "fit-page",
2436
+ icon: "fit-page",
2437
+ label: "Fit to View",
2438
+ type: "button",
2439
+ group: "zoom",
2440
+ execute: () => {
2441
+ instance.fitToPage?.();
2442
+ }
2443
+ },
2444
+ {
2445
+ id: "rotate-cw",
2446
+ icon: "rotate-cw",
2447
+ label: "Rotate",
2448
+ type: "button",
2449
+ group: "view",
2450
+ execute: () => {
2451
+ instance.rotateCW?.();
2452
+ }
2453
+ },
2337
2454
  {
2338
2455
  id: "download",
2339
2456
  icon: "download",
@@ -2384,9 +2501,23 @@ var ExcelPlugin = class {
2384
2501
  container.appendChild(tabsArea);
2385
2502
  ctx.container.appendChild(container);
2386
2503
  let scale = 1;
2504
+ let rotation = 0;
2387
2505
  let currentSheetIndex = 1;
2388
2506
  let sheetNames = [];
2389
2507
  let wb = null;
2508
+ const applyTransform = () => {
2509
+ contentArea.style.transform = `scale(${scale}) rotate(${rotation}deg)`;
2510
+ contentArea.style.transformOrigin = "top left";
2511
+ };
2512
+ const calculateFitScale = () => {
2513
+ const table = contentArea.querySelector("table");
2514
+ if (!table) return 1;
2515
+ const availW = Math.max(200, container.clientWidth - 48);
2516
+ const availH = Math.max(200, container.clientHeight - 80);
2517
+ const tW = table.offsetWidth || 800;
2518
+ const tH = table.offsetHeight || 600;
2519
+ return Math.min(1, Math.min(availW / tW, availH / tH));
2520
+ };
2390
2521
  try {
2391
2522
  wb = XLSX.read(new Uint8Array(ctx.buffer), { type: "array", cellDates: true });
2392
2523
  sheetNames = wb.SheetNames || [];
@@ -2474,17 +2605,30 @@ var ExcelPlugin = class {
2474
2605
  return {
2475
2606
  destroy: cleanup,
2476
2607
  zoomIn: () => {
2477
- scale += 0.1;
2478
- contentArea.style.transform = `scale(${scale})`;
2608
+ scale += 0.15;
2609
+ applyTransform();
2479
2610
  },
2480
2611
  zoomOut: () => {
2481
- scale = Math.max(0.2, scale - 0.1);
2482
- contentArea.style.transform = `scale(${scale})`;
2612
+ scale = Math.max(0.2, scale - 0.15);
2613
+ applyTransform();
2483
2614
  },
2484
2615
  getZoom: () => scale,
2485
2616
  setZoom: (level) => {
2486
2617
  scale = level;
2487
- contentArea.style.transform = `scale(${scale})`;
2618
+ applyTransform();
2619
+ },
2620
+ fitToPage: () => {
2621
+ scale = calculateFitScale();
2622
+ rotation = 0;
2623
+ applyTransform();
2624
+ },
2625
+ rotateCW: () => {
2626
+ rotation = (rotation + 90) % 360;
2627
+ applyTransform();
2628
+ },
2629
+ rotateCCW: () => {
2630
+ rotation = (rotation - 90 + 360) % 360;
2631
+ applyTransform();
2488
2632
  },
2489
2633
  goToPage: (page) => {
2490
2634
  if (page > 0 && page <= sheetNames.length) {
@@ -2734,6 +2878,26 @@ var CodePlugin = class {
2734
2878
  instance.zoomIn?.();
2735
2879
  }
2736
2880
  },
2881
+ {
2882
+ id: "fit-page",
2883
+ icon: "fit-page",
2884
+ label: "Fit to View",
2885
+ type: "button",
2886
+ group: "zoom",
2887
+ execute: () => {
2888
+ instance.fitToPage?.();
2889
+ }
2890
+ },
2891
+ {
2892
+ id: "rotate-cw",
2893
+ icon: "rotate-cw",
2894
+ label: "Rotate",
2895
+ type: "button",
2896
+ group: "view",
2897
+ execute: () => {
2898
+ instance.rotateCW?.();
2899
+ }
2900
+ },
2737
2901
  {
2738
2902
  id: "copy",
2739
2903
  icon: "copy",
@@ -2783,6 +2947,7 @@ var CodePlugin = class {
2783
2947
  container.style.padding = "16px";
2784
2948
  container.style.boxSizing = "border-box";
2785
2949
  let fontSize = 13;
2950
+ let rotation = 0;
2786
2951
  const pre = document.createElement("pre");
2787
2952
  pre.style.margin = "0";
2788
2953
  pre.style.fontFamily = "Consolas, Menlo, Monaco, monospace";
@@ -2865,6 +3030,22 @@ var CodePlugin = class {
2865
3030
  fontSize = Math.round(13 * level);
2866
3031
  pre.style.fontSize = `${fontSize}px`;
2867
3032
  },
3033
+ fitToPage: () => {
3034
+ fontSize = 13;
3035
+ rotation = 0;
3036
+ pre.style.fontSize = "13px";
3037
+ pre.style.transform = "none";
3038
+ },
3039
+ rotateCW: () => {
3040
+ rotation = (rotation + 90) % 360;
3041
+ pre.style.transform = `rotate(${rotation}deg)`;
3042
+ pre.style.transformOrigin = "top left";
3043
+ },
3044
+ rotateCCW: () => {
3045
+ rotation = (rotation - 90 + 360) % 360;
3046
+ pre.style.transform = `rotate(${rotation}deg)`;
3047
+ pre.style.transformOrigin = "top left";
3048
+ },
2868
3049
  download: () => {
2869
3050
  const mimeType = ctx.metadata.mimeType || "text/plain";
2870
3051
  const blob = new Blob([ctx.buffer], { type: mimeType });
@@ -3376,6 +3557,14 @@ var PptxPlugin = class {
3376
3557
  group: "zoom",
3377
3558
  execute: () => instance.fitToPage?.()
3378
3559
  },
3560
+ {
3561
+ id: "rotate-cw",
3562
+ icon: "rotate-cw",
3563
+ label: "Rotate",
3564
+ type: "button",
3565
+ group: "view",
3566
+ execute: () => instance.rotateCW?.()
3567
+ },
3379
3568
  {
3380
3569
  id: "download",
3381
3570
  icon: "download",
@@ -3400,6 +3589,7 @@ var PptxPlugin = class {
3400
3589
  const slideCount = renderer.slidePaths?.length || 1;
3401
3590
  let currentSlide = 1;
3402
3591
  let scale = 1;
3592
+ let rotation = 0;
3403
3593
  const wrapper = document.createElement("div");
3404
3594
  wrapper.className = "fp-pptx-wrapper";
3405
3595
  wrapper.style.cssText = `
@@ -3422,6 +3612,8 @@ var PptxPlugin = class {
3422
3612
  background: #ffffff;
3423
3613
  transform-origin: top center;
3424
3614
  transition: transform 0.2s ease;
3615
+ max-width: calc(100% - 32px);
3616
+ max-height: calc(100% - 48px);
3425
3617
  `;
3426
3618
  const canvas = document.createElement("canvas");
3427
3619
  slideContainer.appendChild(canvas);
@@ -3429,10 +3621,22 @@ var PptxPlugin = class {
3429
3621
  ctx.container.innerHTML = "";
3430
3622
  ctx.container.style.overflow = "auto";
3431
3623
  ctx.container.appendChild(wrapper);
3624
+ const calculateFitScale = () => {
3625
+ const availW = Math.max(200, ctx.container.clientWidth - 48);
3626
+ const availH = Math.max(200, ctx.container.clientHeight - 72);
3627
+ const cW = canvas.offsetWidth || 1280;
3628
+ const cH = canvas.offsetHeight || 720;
3629
+ return Math.min(1, Math.min(availW / cW, availH / cH));
3630
+ };
3631
+ const applyTransform = () => {
3632
+ slideContainer.style.transform = `scale(${scale}) rotate(${rotation}deg)`;
3633
+ };
3432
3634
  const renderCurrentSlide = async () => {
3433
3635
  try {
3434
3636
  await renderer.renderSlide(currentSlide - 1, canvas, 1280);
3435
3637
  ctx.emit("page-change", { page: currentSlide, totalPages: slideCount });
3638
+ scale = calculateFitScale();
3639
+ applyTransform();
3436
3640
  } catch (err) {
3437
3641
  console.error("[PptxPlugin] Failed to render slide:", err);
3438
3642
  }
@@ -3455,21 +3659,30 @@ var PptxPlugin = class {
3455
3659
  getPageCount: () => slideCount,
3456
3660
  getCurrentPage: () => currentSlide,
3457
3661
  zoomIn: () => {
3458
- scale += 0.1;
3459
- slideContainer.style.transform = `scale(${scale})`;
3662
+ scale += 0.15;
3663
+ applyTransform();
3460
3664
  },
3461
3665
  zoomOut: () => {
3462
- scale = Math.max(0.2, scale - 0.1);
3463
- slideContainer.style.transform = `scale(${scale})`;
3666
+ scale = Math.max(0.2, scale - 0.15);
3667
+ applyTransform();
3464
3668
  },
3465
3669
  getZoom: () => scale,
3466
3670
  setZoom: (level) => {
3467
3671
  scale = level;
3468
- slideContainer.style.transform = `scale(${scale})`;
3672
+ applyTransform();
3469
3673
  },
3470
3674
  fitToPage: () => {
3471
- scale = 1;
3472
- slideContainer.style.transform = "scale(1)";
3675
+ scale = calculateFitScale();
3676
+ rotation = 0;
3677
+ applyTransform();
3678
+ },
3679
+ rotateCW: () => {
3680
+ rotation = (rotation + 90) % 360;
3681
+ applyTransform();
3682
+ },
3683
+ rotateCCW: () => {
3684
+ rotation = (rotation - 90 + 360) % 360;
3685
+ applyTransform();
3473
3686
  },
3474
3687
  getThumbnails: () => {
3475
3688
  const list = [];
@@ -3750,6 +3963,14 @@ var RtfPlugin = class {
3750
3963
  group: "zoom",
3751
3964
  execute: () => instance.fitToPage?.()
3752
3965
  },
3966
+ {
3967
+ id: "rotate-cw",
3968
+ icon: "rotate-cw",
3969
+ label: "Rotate",
3970
+ type: "button",
3971
+ group: "view",
3972
+ execute: () => instance.rotateCW?.()
3973
+ },
3753
3974
  {
3754
3975
  id: "download",
3755
3976
  icon: "download",
@@ -3786,7 +4007,24 @@ var RtfPlugin = class {
3786
4007
  ctx.container.style.backgroundColor = "#f1f5f9";
3787
4008
  ctx.container.appendChild(wrapper);
3788
4009
  let scale = 1;
4010
+ let rotation = 0;
3789
4011
  let pageElements = [];
4012
+ const calculateFitScale = () => {
4013
+ const activeEl = pageElements[currentPage - 1] || wrapper;
4014
+ const elW = activeEl.offsetWidth || 850;
4015
+ const elH = activeEl.offsetHeight || 1e3;
4016
+ const availW = Math.max(200, ctx.container.clientWidth - 48);
4017
+ const availH = Math.max(200, ctx.container.clientHeight - 80);
4018
+ return Math.min(1.1, Math.min(availW / elW, availH / elH));
4019
+ };
4020
+ const applyTransform = () => {
4021
+ wrapper.style.transform = `scale(${scale}) rotate(${rotation}deg)`;
4022
+ wrapper.style.transformOrigin = "top center";
4023
+ };
4024
+ setTimeout(() => {
4025
+ scale = calculateFitScale();
4026
+ applyTransform();
4027
+ }, 60);
3790
4028
  try {
3791
4029
  if (typeof RTFJS.loggingEnabled === "function") {
3792
4030
  RTFJS.loggingEnabled(false);
@@ -3863,21 +4101,30 @@ var RtfPlugin = class {
3863
4101
  getCurrentPage: () => currentPage,
3864
4102
  goToPage: (page) => showPage(page),
3865
4103
  zoomIn: () => {
3866
- scale += 0.1;
3867
- wrapper.style.transform = `scale(${scale})`;
4104
+ scale += 0.15;
4105
+ applyTransform();
3868
4106
  },
3869
4107
  zoomOut: () => {
3870
- scale = Math.max(0.2, scale - 0.1);
3871
- wrapper.style.transform = `scale(${scale})`;
4108
+ scale = Math.max(0.2, scale - 0.15);
4109
+ applyTransform();
3872
4110
  },
3873
4111
  getZoom: () => scale,
3874
4112
  setZoom: (level) => {
3875
4113
  scale = level;
3876
- wrapper.style.transform = `scale(${scale})`;
4114
+ applyTransform();
3877
4115
  },
3878
4116
  fitToPage: () => {
3879
- scale = 1;
3880
- wrapper.style.transform = "scale(1)";
4117
+ scale = calculateFitScale();
4118
+ rotation = 0;
4119
+ applyTransform();
4120
+ },
4121
+ rotateCW: () => {
4122
+ rotation = (rotation + 90) % 360;
4123
+ applyTransform();
4124
+ },
4125
+ rotateCCW: () => {
4126
+ rotation = (rotation - 90 + 360) % 360;
4127
+ applyTransform();
3881
4128
  },
3882
4129
  download: () => {
3883
4130
  const blob = new Blob([ctx.buffer], { type: "application/rtf" });
@@ -4105,11 +4352,19 @@ var OpenDocumentPlugin = class {
4105
4352
  {
4106
4353
  id: "fit-page",
4107
4354
  icon: "fit-page",
4108
- label: "Fit to Page",
4355
+ label: isPresentation ? "Fit to Slide" : "Fit to Page",
4109
4356
  type: "button",
4110
4357
  group: "zoom",
4111
4358
  execute: () => instance.fitToPage?.()
4112
4359
  },
4360
+ {
4361
+ id: "rotate-cw",
4362
+ icon: "rotate-cw",
4363
+ label: "Rotate",
4364
+ type: "button",
4365
+ group: "view",
4366
+ execute: () => instance.rotateCW?.()
4367
+ },
4113
4368
  {
4114
4369
  id: "download",
4115
4370
  icon: "download",
@@ -4173,6 +4428,22 @@ var OpenDocumentPlugin = class {
4173
4428
  container.appendChild(wrapper);
4174
4429
  ctx.container.appendChild(container);
4175
4430
  let scale = 1;
4431
+ let rotation = 0;
4432
+ const calculateFitScale = () => {
4433
+ const elW = wrapper.offsetWidth || 850;
4434
+ const elH = wrapper.offsetHeight || (isPresentation ? 540 : 1e3);
4435
+ const availW = Math.max(200, ctx.container.clientWidth - 48);
4436
+ const availH = Math.max(200, ctx.container.clientHeight - 80);
4437
+ return Math.min(1, Math.min(availW / elW, availH / elH));
4438
+ };
4439
+ const applyTransform = () => {
4440
+ wrapper.style.transform = `scale(${scale}) rotate(${rotation}deg)`;
4441
+ wrapper.style.transformOrigin = "top center";
4442
+ };
4443
+ setTimeout(() => {
4444
+ scale = calculateFitScale();
4445
+ applyTransform();
4446
+ }, 60);
4176
4447
  let currentPage = 1;
4177
4448
  let totalPages = 1;
4178
4449
  let slides = [];
@@ -4231,21 +4502,30 @@ var OpenDocumentPlugin = class {
4231
4502
  destroy: cleanup,
4232
4503
  isPresentation,
4233
4504
  zoomIn: () => {
4234
- scale += 0.1;
4235
- wrapper.style.transform = `scale(${scale})`;
4505
+ scale += 0.15;
4506
+ applyTransform();
4236
4507
  },
4237
4508
  zoomOut: () => {
4238
- scale = Math.max(0.2, scale - 0.1);
4239
- wrapper.style.transform = `scale(${scale})`;
4509
+ scale = Math.max(0.2, scale - 0.15);
4510
+ applyTransform();
4240
4511
  },
4241
4512
  getZoom: () => scale,
4242
4513
  setZoom: (level) => {
4243
4514
  scale = level;
4244
- wrapper.style.transform = `scale(${scale})`;
4515
+ applyTransform();
4245
4516
  },
4246
4517
  fitToPage: () => {
4247
- scale = 1;
4248
- wrapper.style.transform = "scale(1)";
4518
+ scale = calculateFitScale();
4519
+ rotation = 0;
4520
+ applyTransform();
4521
+ },
4522
+ rotateCW: () => {
4523
+ rotation = (rotation + 90) % 360;
4524
+ applyTransform();
4525
+ },
4526
+ rotateCCW: () => {
4527
+ rotation = (rotation - 90 + 360) % 360;
4528
+ applyTransform();
4249
4529
  },
4250
4530
  goToPage,
4251
4531
  getPageCount: () => totalPages,
@@ -4515,6 +4795,14 @@ var DocPlugin = class {
4515
4795
  group: "zoom",
4516
4796
  execute: () => instance.fitToPage?.()
4517
4797
  },
4798
+ {
4799
+ id: "rotate-cw",
4800
+ icon: "rotate-cw",
4801
+ label: "Rotate",
4802
+ type: "button",
4803
+ group: "view",
4804
+ execute: () => instance.rotateCW?.()
4805
+ },
4518
4806
  {
4519
4807
  id: "copy",
4520
4808
  icon: "copy",
@@ -4653,6 +4941,23 @@ var DocPlugin = class {
4653
4941
  if (totalPages > 1) {
4654
4942
  showPage(1);
4655
4943
  }
4944
+ let rotation = 0;
4945
+ const calculateFitScale = () => {
4946
+ const activeCard = pageCards[currentPage - 1] || wrapper;
4947
+ const elW = activeCard.offsetWidth || 850;
4948
+ const elH = activeCard.offsetHeight || 1e3;
4949
+ const availW = Math.max(200, ctx.container.clientWidth - 48);
4950
+ const availH = Math.max(200, ctx.container.clientHeight - 80);
4951
+ return Math.min(1.1, Math.min(availW / elW, availH / elH));
4952
+ };
4953
+ const applyTransform = () => {
4954
+ wrapper.style.transform = `scale(${scale}) rotate(${rotation}deg)`;
4955
+ wrapper.style.transformOrigin = "top center";
4956
+ };
4957
+ setTimeout(() => {
4958
+ scale = calculateFitScale();
4959
+ applyTransform();
4960
+ }, 60);
4656
4961
  const cleanup = () => {
4657
4962
  indicator?.remove();
4658
4963
  container.remove();
@@ -4665,21 +4970,30 @@ var DocPlugin = class {
4665
4970
  getCurrentPage: () => currentPage,
4666
4971
  goToPage: (page) => showPage(page),
4667
4972
  zoomIn: () => {
4668
- scale += 0.1;
4669
- wrapper.style.transform = `scale(${scale})`;
4973
+ scale += 0.15;
4974
+ applyTransform();
4670
4975
  },
4671
4976
  zoomOut: () => {
4672
- scale = Math.max(0.2, scale - 0.1);
4673
- wrapper.style.transform = `scale(${scale})`;
4977
+ scale = Math.max(0.2, scale - 0.15);
4978
+ applyTransform();
4674
4979
  },
4675
4980
  getZoom: () => scale,
4676
4981
  setZoom: (level) => {
4677
4982
  scale = level;
4678
- wrapper.style.transform = `scale(${scale})`;
4983
+ applyTransform();
4679
4984
  },
4680
4985
  fitToPage: () => {
4681
- scale = 1;
4682
- wrapper.style.transform = "scale(1)";
4986
+ scale = calculateFitScale();
4987
+ rotation = 0;
4988
+ applyTransform();
4989
+ },
4990
+ rotateCW: () => {
4991
+ rotation = (rotation + 90) % 360;
4992
+ applyTransform();
4993
+ },
4994
+ rotateCCW: () => {
4995
+ rotation = (rotation - 90 + 360) % 360;
4996
+ applyTransform();
4683
4997
  },
4684
4998
  copy: () => {
4685
4999
  navigator.clipboard.writeText(extractedRawText);
@@ -4919,6 +5233,14 @@ var PptPlugin = class {
4919
5233
  group: "zoom",
4920
5234
  execute: () => instance.fitToPage?.()
4921
5235
  },
5236
+ {
5237
+ id: "rotate-cw",
5238
+ icon: "rotate-cw",
5239
+ label: "Rotate",
5240
+ type: "button",
5241
+ group: "view",
5242
+ execute: () => instance.rotateCW?.()
5243
+ },
4922
5244
  {
4923
5245
  id: "download",
4924
5246
  icon: "download",
@@ -4952,22 +5274,36 @@ var PptPlugin = class {
4952
5274
  const slideCard = document.createElement("div");
4953
5275
  slideCard.className = "fp-ppt-slide-card";
4954
5276
  slideCard.style.width = "960px";
4955
- slideCard.style.maxWidth = "92%";
5277
+ slideCard.style.maxWidth = "calc(100% - 32px)";
5278
+ slideCard.style.maxHeight = "calc(100% - 48px)";
4956
5279
  slideCard.style.aspectRatio = "16 / 9";
4957
5280
  slideCard.style.backgroundColor = "#ffffff";
4958
5281
  slideCard.style.boxShadow = "0 12px 40px rgba(0,0,0,0.35)";
4959
5282
  slideCard.style.borderRadius = "8px";
4960
5283
  slideCard.style.boxSizing = "border-box";
4961
5284
  slideCard.style.position = "relative";
4962
- slideCard.style.overflow = "hidden";
4963
- slideCard.style.transformOrigin = "center center";
4964
5285
  slideCard.style.transition = "transform 0.2s ease";
5286
+ slideCard.style.transformOrigin = "center center";
5287
+ slideCard.style.flexShrink = "0";
4965
5288
  container.appendChild(slideCard);
4966
5289
  ctx.container.appendChild(container);
4967
5290
  let scale = 1;
5291
+ let rotation = 0;
4968
5292
  let currentSlide = 1;
4969
5293
  let slides = [];
4970
5294
  const createdBlobUrls = [];
5295
+ const calculateFitScale = () => {
5296
+ const availW = Math.max(200, container.clientWidth - 48);
5297
+ const availH = Math.max(200, container.clientHeight - 72);
5298
+ return Math.min(1, Math.min(availW / 960, availH / 540));
5299
+ };
5300
+ const applyTransform = () => {
5301
+ slideCard.style.transform = `scale(${scale}) rotate(${rotation}deg)`;
5302
+ };
5303
+ setTimeout(() => {
5304
+ scale = calculateFitScale();
5305
+ applyTransform();
5306
+ }, 60);
4971
5307
  try {
4972
5308
  const cfbf = new CfbfReader(ctx.buffer);
4973
5309
  const pptStream = cfbf.readStream("PowerPoint Document");
@@ -5068,21 +5404,30 @@ var PptPlugin = class {
5068
5404
  return {
5069
5405
  destroy: cleanup,
5070
5406
  zoomIn: () => {
5071
- scale += 0.1;
5072
- slideCard.style.transform = `scale(${scale})`;
5407
+ scale += 0.15;
5408
+ applyTransform();
5073
5409
  },
5074
5410
  zoomOut: () => {
5075
- scale = Math.max(0.3, scale - 0.1);
5076
- slideCard.style.transform = `scale(${scale})`;
5411
+ scale = Math.max(0.2, scale - 0.15);
5412
+ applyTransform();
5077
5413
  },
5078
5414
  getZoom: () => scale,
5079
5415
  setZoom: (level) => {
5080
5416
  scale = level;
5081
- slideCard.style.transform = `scale(${scale})`;
5417
+ applyTransform();
5082
5418
  },
5083
5419
  fitToPage: () => {
5084
- scale = 1;
5085
- slideCard.style.transform = "scale(1)";
5420
+ scale = calculateFitScale();
5421
+ rotation = 0;
5422
+ applyTransform();
5423
+ },
5424
+ rotateCW: () => {
5425
+ rotation = (rotation + 90) % 360;
5426
+ applyTransform();
5427
+ },
5428
+ rotateCCW: () => {
5429
+ rotation = (rotation - 90 + 360) % 360;
5430
+ applyTransform();
5086
5431
  },
5087
5432
  goToPage: (page) => {
5088
5433
  if (page >= 1 && page <= totalSlides) {