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