@files-preview-app/preview-file 1.2.7 → 1.2.9

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
@@ -434,7 +434,8 @@ function createElement(tag, attrs, ...children) {
434
434
  }
435
435
  var ICON_ZOOM_IN = `<svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="11" cy="11" r="8"></circle><line x1="21" y1="21" x2="16.65" y2="16.65"></line><line x1="11" y1="8" x2="11" y2="14"></line><line x1="8" y1="11" x2="14" y2="11"></line></svg>`;
436
436
  var ICON_ZOOM_OUT = `<svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="11" cy="11" r="8"></circle><line x1="21" y1="21" x2="16.65" y2="16.65"></line><line x1="8" y1="11" x2="14" y2="11"></line></svg>`;
437
- var ICON_FIT_PAGE = `<svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" y1="3" x2="14" y2="10"></line><line x1="3" y1="21" x2="10" y2="14"></line></svg>`;
437
+ var ICON_FIT_PAGE = `<svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="3" y="3" width="18" height="18" rx="2"></rect><line x1="8" y1="12" x2="16" y2="12"></line><polyline points="11 9 8 12 11 15"></polyline><polyline points="13 9 16 12 13 15"></polyline></svg>`;
438
+ var ICON_FIT_WIDTH = `<svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><line x1="2" y1="12" x2="22" y2="12"></line><polyline points="5 9 2 12 5 15"></polyline><polyline points="19 9 22 12 19 15"></polyline><line x1="2" y1="5" x2="2" y2="19"></line><line x1="22" y1="5" x2="22" y2="19"></line></svg>`;
438
439
  var ICON_ROTATE_CW = `<svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="23 4 23 10 17 10"></polyline><path d="M20.49 15a9 9 0 1 1-2.12-9.36L23 10"></path></svg>`;
439
440
  var ICON_ROTATE_CCW = `<svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="1 4 1 10 7 10"></polyline><path d="M3.51 15a9 9 0 1 0 2.13-9.36L1 10"></path></svg>`;
440
441
  var ICON_DOWNLOAD = `<svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"></path><polyline points="7 10 12 15 17 10"></polyline><line x1="12" y1="15" x2="12" y2="3"></line></svg>`;
@@ -454,6 +455,7 @@ var ICON_MAP = {
454
455
  "zoom-in": ICON_ZOOM_IN,
455
456
  "zoom-out": ICON_ZOOM_OUT,
456
457
  "fit-page": ICON_FIT_PAGE,
458
+ "fit-width": ICON_FIT_WIDTH,
457
459
  "fit-slide": ICON_FIT_PAGE,
458
460
  "rotate-cw": ICON_ROTATE_CW,
459
461
  "rotate-ccw": ICON_ROTATE_CCW,
@@ -1400,6 +1402,7 @@ var PdfPlugin = class {
1400
1402
  let currentPage = 1;
1401
1403
  let zoomScale = 1;
1402
1404
  let rotation = 0;
1405
+ let fitMode = "width";
1403
1406
  let currentRenderTask = null;
1404
1407
  const renderPage = async (pageNum) => {
1405
1408
  if (currentRenderTask) {
@@ -1419,11 +1422,16 @@ var PdfPlugin = class {
1419
1422
  const containerWidth = container.clientWidth || 900;
1420
1423
  const containerHeight = container.clientHeight || 700;
1421
1424
  const unscaledVp = page.getViewport({ scale: 1, rotation });
1422
- const availWidth = Math.max(100, containerWidth - 48);
1423
- const availHeight = Math.max(100, containerHeight - 88);
1425
+ const availWidth = Math.max(280, containerWidth - 48);
1426
+ const availHeight = Math.max(280, containerHeight - 88);
1424
1427
  const scaleW = availWidth / unscaledVp.width;
1425
1428
  const scaleH = availHeight / unscaledVp.height;
1426
- const fitScale = Math.min(scaleW, scaleH);
1429
+ let fitScale;
1430
+ if (fitMode === "page") {
1431
+ fitScale = Math.max(0.5, Math.min(scaleW, scaleH));
1432
+ } else {
1433
+ fitScale = Math.max(0.65, Math.min(1.15, scaleW));
1434
+ }
1427
1435
  const effectiveScale = (fitScale > 0 ? fitScale : 1) * zoomScale;
1428
1436
  const pixelRatio = window.devicePixelRatio || 1;
1429
1437
  const viewport = page.getViewport({ scale: effectiveScale, rotation });
@@ -1492,6 +1500,7 @@ var PdfPlugin = class {
1492
1500
  renderPage(currentPage);
1493
1501
  },
1494
1502
  fitToPage: () => {
1503
+ fitMode = fitMode === "width" ? "page" : "width";
1495
1504
  zoomScale = 1;
1496
1505
  rotation = 0;
1497
1506
  renderPage(currentPage);
@@ -1508,6 +1517,7 @@ var PdfPlugin = class {
1508
1517
  getPageCount: () => totalPages,
1509
1518
  getCurrentPage: () => currentPage,
1510
1519
  goToPage: (page) => {
1520
+ container.scrollTop = 0;
1511
1521
  renderPage(page);
1512
1522
  },
1513
1523
  download: () => {
@@ -2012,7 +2022,14 @@ var DocxPlugin = class {
2012
2022
  ignoreFonts: true,
2013
2023
  // Avoid crashes on embedded obfuscated fonts
2014
2024
  breakPages: true,
2015
- experimental: true
2025
+ experimental: true,
2026
+ ignoreLastRenderedPageBreak: false,
2027
+ // Honor Word's exact page breaks!
2028
+ renderHeaders: true,
2029
+ renderFooters: true,
2030
+ renderFootnotes: true,
2031
+ renderEndnotes: true,
2032
+ useBase64URL: true
2016
2033
  });
2017
2034
  if (!ctx.container.contains(wrapper)) {
2018
2035
  ctx.container.appendChild(wrapper);
@@ -2033,11 +2050,14 @@ var DocxPlugin = class {
2033
2050
  renderedSuccessfully = true;
2034
2051
  } catch (fallbackErr) {
2035
2052
  console.error("[DocxPlugin] Native fallback failed:", fallbackErr);
2053
+ const isCorrupt = fallbackErr?.message?.includes("invalid zip") || fallbackErr?.message?.includes("corrupted");
2036
2054
  wrapper.innerHTML = `
2037
- <div style="text-align:center; padding: 48px; background: #fff; border-radius: 8px; box-shadow: 0 4px 20px rgba(0,0,0,0.06);">
2038
- <div style="font-size:48px; margin-bottom: 16px;">\u{1F4C4}</div>
2039
- <h3 style="margin: 0 0 8px; color: #1e293b;">${ctx.metadata.name || "Word Document"}</h3>
2040
- <p style="color: #64748b; margin: 0;">Could not parse document content</p>
2055
+ <div style="text-align:center; padding: 48px 32px; background: #fff; border-radius: 8px; box-shadow: 0 4px 20px rgba(0,0,0,0.06); max-width: 600px; margin: 40px auto;">
2056
+ <div style="font-size:48px; margin-bottom: 16px;">${isCorrupt ? "\u26A0\uFE0F" : "\u{1F4C4}"}</div>
2057
+ <h3 style="margin: 0 0 8px; color: #1e293b; font-size: 18px;">${ctx.metadata.name || "Word Document"}</h3>
2058
+ <p style="color: #64748b; margin: 0 0 16px; font-size: 14px; line-height: 1.5;">
2059
+ ${isCorrupt ? "This document appears to be corrupted or contains invalid archive data and cannot be opened (matches Microsoft Word on Windows)." : "Could not render document content. The file structure may be damaged."}
2060
+ </p>
2041
2061
  </div>
2042
2062
  `;
2043
2063
  if (!ctx.container.contains(wrapper)) {
@@ -2045,8 +2065,67 @@ var DocxPlugin = class {
2045
2065
  }
2046
2066
  }
2047
2067
  }
2048
- const sections = wrapper.querySelectorAll("section.docx");
2049
- const cards = wrapper.querySelectorAll(".fp-docx-page-card");
2068
+ let sections = Array.from(wrapper.querySelectorAll("section.docx"));
2069
+ const cards = Array.from(wrapper.querySelectorAll(".fp-docx-page-card"));
2070
+ if (sections.length === 1 && cards.length === 0) {
2071
+ const singleSec = sections[0];
2072
+ const contentContainer = singleSec.querySelector("article") || singleSec;
2073
+ const children = Array.from(contentContainer.children);
2074
+ const pageH = singleSec.offsetHeight > 1300 ? 1122 : Math.max(1056, singleSec.offsetHeight);
2075
+ const secH = singleSec.offsetHeight || singleSec.scrollHeight;
2076
+ if (secH > pageH * 1.25 && children.length > 1) {
2077
+ const childHeights = children.map((c) => {
2078
+ const rectH = c.getBoundingClientRect().height;
2079
+ const offH = c.offsetHeight;
2080
+ const textLen = c.textContent?.trim().length || 0;
2081
+ const estH = Math.max(24, Math.ceil(textLen / 80) * 22 + 16);
2082
+ return Math.max(rectH, offH, estH);
2083
+ });
2084
+ const parent = singleSec.parentElement || wrapper;
2085
+ const newSections = [singleSec];
2086
+ const headerEl = singleSec.querySelector("header");
2087
+ const footerEl = singleSec.querySelector("footer");
2088
+ contentContainer.innerHTML = "";
2089
+ singleSec.style.minHeight = `${pageH}px`;
2090
+ singleSec.style.boxSizing = "border-box";
2091
+ let curContent = contentContainer;
2092
+ let curH = 0;
2093
+ const maxH = pageH - 140;
2094
+ for (let i = 0; i < children.length; i++) {
2095
+ const child = children[i];
2096
+ const chH = childHeights[i];
2097
+ curContent.appendChild(child);
2098
+ curH += chH;
2099
+ if (curH >= maxH && i < children.length - 1) {
2100
+ const nextSec = document.createElement("section");
2101
+ nextSec.className = singleSec.className;
2102
+ nextSec.style.cssText = singleSec.style.cssText;
2103
+ nextSec.style.minHeight = `${pageH}px`;
2104
+ nextSec.style.boxSizing = "border-box";
2105
+ nextSec.style.backgroundColor = "#ffffff";
2106
+ nextSec.style.boxShadow = "0 4px 24px rgba(0, 0, 0, 0.08)";
2107
+ nextSec.style.borderRadius = "4px";
2108
+ nextSec.style.marginBottom = "24px";
2109
+ if (headerEl) {
2110
+ nextSec.appendChild(headerEl.cloneNode(true));
2111
+ }
2112
+ const nextArticle = document.createElement("article");
2113
+ if (contentContainer.tagName.toLowerCase() === "article") {
2114
+ nextArticle.style.cssText = contentContainer.style.cssText;
2115
+ }
2116
+ nextSec.appendChild(nextArticle);
2117
+ if (footerEl) {
2118
+ nextSec.appendChild(footerEl.cloneNode(true));
2119
+ }
2120
+ parent.appendChild(nextSec);
2121
+ newSections.push(nextSec);
2122
+ curContent = nextArticle;
2123
+ curH = 0;
2124
+ }
2125
+ }
2126
+ sections = newSections;
2127
+ }
2128
+ }
2050
2129
  const pageElements = sections.length > 0 ? sections : cards;
2051
2130
  const totalPages = Math.max(1, pageElements.length);
2052
2131
  let currentPage = 1;
@@ -2083,6 +2162,7 @@ var DocxPlugin = class {
2083
2162
  if (indicator) {
2084
2163
  indicator.textContent = `Page ${currentPage} of ${totalPages}`;
2085
2164
  }
2165
+ ctx.container.scrollTop = 0;
2086
2166
  ctx.emit("page-change", { page: currentPage, total: totalPages });
2087
2167
  };
2088
2168
  if (totalPages > 1) {
@@ -2090,22 +2170,27 @@ var DocxPlugin = class {
2090
2170
  }
2091
2171
  scale = 1;
2092
2172
  let rotation = 0;
2093
- const calculateFitScale = () => {
2173
+ let fitMode = "width";
2174
+ const calculateFitScale = (mode = fitMode) => {
2094
2175
  const activeEl = pageElements[currentPage - 1] || wrapper.firstElementChild || wrapper;
2095
2176
  const elW = activeEl.offsetWidth || 816;
2096
- const elH = activeEl.offsetHeight || 1056;
2097
- const availW = Math.max(200, ctx.container.clientWidth - 48);
2098
- const availH = Math.max(200, ctx.container.clientHeight - 80);
2177
+ const singlePageH = Math.min(activeEl.offsetHeight || 1056, Math.round(elW * 1.32));
2178
+ const availW = Math.max(280, ctx.container.clientWidth - 48);
2179
+ const availH = Math.max(280, ctx.container.clientHeight - 80);
2099
2180
  const sW = availW / elW;
2100
- const sH = availH / elH;
2101
- return Math.min(1.1, Math.min(sW, sH));
2181
+ const sH = availH / singlePageH;
2182
+ if (mode === "page") {
2183
+ return Math.max(0.55, Math.min(1.15, Math.min(sW, sH)));
2184
+ }
2185
+ return Math.max(0.65, Math.min(1.05, sW));
2102
2186
  };
2103
2187
  const applyTransform = () => {
2104
2188
  wrapper.style.transform = `scale(${scale}) rotate(${rotation}deg)`;
2105
2189
  wrapper.style.transformOrigin = "top center";
2106
2190
  };
2107
2191
  setTimeout(() => {
2108
- scale = calculateFitScale();
2192
+ fitMode = "width";
2193
+ scale = calculateFitScale("width");
2109
2194
  applyTransform();
2110
2195
  }, 60);
2111
2196
  const cleanup = () => {
@@ -2139,7 +2224,8 @@ var DocxPlugin = class {
2139
2224
  applyTransform();
2140
2225
  },
2141
2226
  fitToPage: () => {
2142
- scale = calculateFitScale();
2227
+ fitMode = fitMode === "width" ? "page" : "width";
2228
+ scale = calculateFitScale(fitMode);
2143
2229
  rotation = 0;
2144
2230
  applyTransform();
2145
2231
  },
@@ -2583,11 +2669,9 @@ var ExcelPlugin = class {
2583
2669
  const calculateFitScale = () => {
2584
2670
  const table = contentArea.querySelector("table");
2585
2671
  if (!table) return 1;
2586
- const availW = Math.max(200, container.clientWidth - 48);
2587
- const availH = Math.max(200, container.clientHeight - 80);
2672
+ const availW = Math.max(280, container.clientWidth - 48);
2588
2673
  const tW = table.offsetWidth || 800;
2589
- const tH = table.offsetHeight || 600;
2590
- return Math.min(1, Math.min(availW / tW, availH / tH));
2674
+ return Math.max(0.65, Math.min(1, availW / tW));
2591
2675
  };
2592
2676
  try {
2593
2677
  wb = XLSX.read(new Uint8Array(ctx.buffer), { type: "array", cellDates: true });
@@ -3011,17 +3095,39 @@ var CodePlugin = class {
3011
3095
  let rawPages = [];
3012
3096
  if (isTxt) {
3013
3097
  const explicitPages = fullText.split(/(?:\f|\x0C)/);
3098
+ const charsPerLine = 85;
3099
+ const maxVisualLines = 45;
3100
+ const charsPerPage = charsPerLine * maxVisualLines;
3014
3101
  for (const ep of explicitPages) {
3015
3102
  const lines = ep.split(/\r?\n/);
3016
3103
  let currentChunk = [];
3104
+ let currentLines = 0;
3017
3105
  for (let i = 0; i < lines.length; i++) {
3018
- currentChunk.push(lines[i]);
3019
- if (currentChunk.length >= 46) {
3106
+ const line = lines[i];
3107
+ const vLines = Math.max(1, Math.ceil((line.length || 1) / charsPerLine));
3108
+ if (currentLines + vLines > maxVisualLines && currentChunk.length > 0) {
3020
3109
  rawPages.push(currentChunk.join("\n"));
3021
3110
  currentChunk = [];
3111
+ currentLines = 0;
3112
+ }
3113
+ if (vLines > maxVisualLines) {
3114
+ let remaining = line;
3115
+ while (remaining.length > charsPerPage) {
3116
+ let splitIdx = remaining.lastIndexOf(" ", charsPerPage);
3117
+ if (splitIdx < charsPerPage * 0.75) splitIdx = charsPerPage;
3118
+ rawPages.push(remaining.slice(0, splitIdx));
3119
+ remaining = remaining.slice(splitIdx).trimStart();
3120
+ }
3121
+ if (remaining.length > 0) {
3122
+ currentChunk.push(remaining);
3123
+ currentLines = Math.ceil(remaining.length / charsPerLine);
3124
+ }
3125
+ } else {
3126
+ currentChunk.push(line);
3127
+ currentLines += vLines;
3022
3128
  }
3023
3129
  }
3024
- if (currentChunk.length > 0 || lines.length === 0) {
3130
+ if (currentChunk.length > 0) {
3025
3131
  rawPages.push(currentChunk.join("\n"));
3026
3132
  }
3027
3133
  }
@@ -3131,6 +3237,7 @@ var CodePlugin = class {
3131
3237
  if (indicator) {
3132
3238
  indicator.textContent = `Page ${currentPage} of ${totalPages}`;
3133
3239
  }
3240
+ container.scrollTop = 0;
3134
3241
  ctx.emit("page-change", { page: currentPage, total: totalPages });
3135
3242
  };
3136
3243
  if (totalPages > 1) {
@@ -3184,7 +3291,7 @@ var CodePlugin = class {
3184
3291
  fitToPage: () => {
3185
3292
  fontSize = 13;
3186
3293
  rotation = 0;
3187
- zoomLevel = 1;
3294
+ zoomLevel = isTxt ? Math.max(0.65, Math.min(1.05, (container.clientWidth - 48) / 816)) : 1;
3188
3295
  updateTransform();
3189
3296
  },
3190
3297
  rotateCW: () => {
@@ -4166,20 +4273,27 @@ var RtfPlugin = class {
4166
4273
  let scale = 1;
4167
4274
  let rotation = 0;
4168
4275
  let pageElements = [];
4169
- const calculateFitScale = () => {
4276
+ let fitMode = "width";
4277
+ const calculateFitScale = (mode = fitMode) => {
4170
4278
  const activeEl = pageElements[currentPage - 1] || wrapper;
4171
4279
  const elW = activeEl.offsetWidth || 850;
4172
- const elH = activeEl.offsetHeight || 1e3;
4173
- const availW = Math.max(200, ctx.container.clientWidth - 48);
4174
- const availH = Math.max(200, ctx.container.clientHeight - 80);
4175
- return Math.min(1.1, Math.min(availW / elW, availH / elH));
4280
+ const singlePageH = Math.min(activeEl.offsetHeight || 1056, Math.round(elW * 1.32));
4281
+ const availW = Math.max(280, ctx.container.clientWidth - 48);
4282
+ const availH = Math.max(280, ctx.container.clientHeight - 80);
4283
+ const sW = availW / elW;
4284
+ const sH = availH / singlePageH;
4285
+ if (mode === "page") {
4286
+ return Math.max(0.55, Math.min(1.15, Math.min(sW, sH)));
4287
+ }
4288
+ return Math.max(0.65, Math.min(1.05, sW));
4176
4289
  };
4177
4290
  const applyTransform = () => {
4178
4291
  wrapper.style.transform = `scale(${scale}) rotate(${rotation}deg)`;
4179
4292
  wrapper.style.transformOrigin = "top center";
4180
4293
  };
4181
4294
  setTimeout(() => {
4182
- scale = calculateFitScale();
4295
+ fitMode = "width";
4296
+ scale = calculateFitScale("width");
4183
4297
  applyTransform();
4184
4298
  }, 60);
4185
4299
  try {
@@ -4188,11 +4302,60 @@ var RtfPlugin = class {
4188
4302
  }
4189
4303
  const doc = new RTFJS.Document(ctx.buffer, {});
4190
4304
  const htmlElements = await doc.render();
4191
- pageElements = htmlElements;
4192
- for (let i = 0; i < htmlElements.length; i++) {
4193
- const el = htmlElements[i];
4194
- el.style.display = i === 0 ? "block" : "none";
4195
- wrapper.appendChild(el);
4305
+ if (htmlElements.length === 1) {
4306
+ const singleEl = htmlElements[0];
4307
+ wrapper.appendChild(singleEl);
4308
+ const children = Array.from(singleEl.children);
4309
+ const secH = singleEl.offsetHeight || singleEl.scrollHeight;
4310
+ if (secH > 1300 && children.length > 1) {
4311
+ const childHeights = children.map((c) => {
4312
+ const rectH = c.getBoundingClientRect().height;
4313
+ const offH = c.offsetHeight;
4314
+ const textLen = c.textContent?.trim().length || 0;
4315
+ const estH = Math.max(24, Math.ceil(textLen / 80) * 22 + 16);
4316
+ return Math.max(rectH, offH, estH);
4317
+ });
4318
+ wrapper.innerHTML = "";
4319
+ const createRtfCard = () => {
4320
+ const card = document.createElement("div");
4321
+ card.className = "fp-rtf-page-card";
4322
+ card.style.backgroundColor = "#ffffff";
4323
+ card.style.boxShadow = "0 4px 24px rgba(0,0,0,0.08)";
4324
+ card.style.borderRadius = "4px";
4325
+ card.style.padding = "72px 56px";
4326
+ card.style.width = "816px";
4327
+ card.style.minHeight = "1056px";
4328
+ card.style.boxSizing = "border-box";
4329
+ card.style.marginBottom = "24px";
4330
+ return card;
4331
+ };
4332
+ let curCard = createRtfCard();
4333
+ wrapper.appendChild(curCard);
4334
+ pageElements = [curCard];
4335
+ let curH = 0;
4336
+ const maxH = 920;
4337
+ for (let i = 0; i < children.length; i++) {
4338
+ const child = children[i];
4339
+ const chH = childHeights[i];
4340
+ curCard.appendChild(child);
4341
+ curH += chH;
4342
+ if (curH >= maxH && i < children.length - 1) {
4343
+ curCard = createRtfCard();
4344
+ wrapper.appendChild(curCard);
4345
+ pageElements.push(curCard);
4346
+ curH = 0;
4347
+ }
4348
+ }
4349
+ } else {
4350
+ pageElements = [singleEl];
4351
+ }
4352
+ } else {
4353
+ pageElements = htmlElements;
4354
+ for (let i = 0; i < htmlElements.length; i++) {
4355
+ const el = htmlElements[i];
4356
+ el.style.display = i === 0 ? "block" : "none";
4357
+ wrapper.appendChild(el);
4358
+ }
4196
4359
  }
4197
4360
  } catch (err) {
4198
4361
  console.warn("[RtfPlugin] RTF render error, fallback text:", err);
@@ -4258,6 +4421,7 @@ var RtfPlugin = class {
4258
4421
  if (indicator) {
4259
4422
  indicator.textContent = `Page ${currentPage} of ${totalPages}`;
4260
4423
  }
4424
+ ctx.container.scrollTop = 0;
4261
4425
  ctx.emit("page-change", { page: currentPage, total: totalPages });
4262
4426
  };
4263
4427
  if (totalPages > 1) {
@@ -4288,7 +4452,8 @@ var RtfPlugin = class {
4288
4452
  applyTransform();
4289
4453
  },
4290
4454
  fitToPage: () => {
4291
- scale = calculateFitScale();
4455
+ fitMode = fitMode === "width" ? "page" : "width";
4456
+ scale = calculateFitScale(fitMode);
4292
4457
  rotation = 0;
4293
4458
  applyTransform();
4294
4459
  },
@@ -4607,19 +4772,29 @@ var OpenDocumentPlugin = class {
4607
4772
  ctx.container.appendChild(container);
4608
4773
  let scale = 1;
4609
4774
  let rotation = 0;
4610
- const calculateFitScale = () => {
4775
+ let fitMode = "width";
4776
+ const calculateFitScale = (mode = fitMode) => {
4611
4777
  const elW = wrapper.offsetWidth || 850;
4612
- const elH = wrapper.offsetHeight || (isPresentation ? 540 : 1e3);
4613
- const availW = Math.max(200, ctx.container.clientWidth - 48);
4614
- const availH = Math.max(200, ctx.container.clientHeight - 80);
4615
- return Math.min(1, Math.min(availW / elW, availH / elH));
4778
+ const singlePageH = Math.min(wrapper.offsetHeight || 1056, Math.round(elW * 1.32));
4779
+ const availW = Math.max(280, ctx.container.clientWidth - 48);
4780
+ const availH = Math.max(280, ctx.container.clientHeight - 80);
4781
+ const sW = availW / elW;
4782
+ const sH = availH / (isPresentation ? 540 : singlePageH);
4783
+ if (isPresentation) {
4784
+ return Math.min(1, Math.min(sW, sH));
4785
+ }
4786
+ if (mode === "page") {
4787
+ return Math.max(0.55, Math.min(1.15, Math.min(sW, sH)));
4788
+ }
4789
+ return Math.max(0.65, Math.min(1.05, sW));
4616
4790
  };
4617
4791
  const applyTransform = () => {
4618
4792
  wrapper.style.transform = `scale(${scale}) rotate(${rotation}deg)`;
4619
4793
  wrapper.style.transformOrigin = "top center";
4620
4794
  };
4621
4795
  setTimeout(() => {
4622
- scale = calculateFitScale();
4796
+ fitMode = "width";
4797
+ scale = calculateFitScale("width");
4623
4798
  applyTransform();
4624
4799
  }, 60);
4625
4800
  let currentPage = 1;
@@ -4718,12 +4893,9 @@ var OpenDocumentPlugin = class {
4718
4893
  page.style.backgroundColor = "#ffffff";
4719
4894
  page.style.boxShadow = "0 2px 10px rgba(0,0,0,0.08)";
4720
4895
  page.style.borderRadius = "4px";
4721
- page.style.boxSizing = "border-box";
4722
4896
  page.style.display = idx === 0 ? "block" : "none";
4723
- page.style.position = "absolute";
4724
- page.style.top = "0";
4725
- page.style.left = "50%";
4726
- page.style.transform = "translateX(-50%)";
4897
+ page.style.margin = "0 auto 24px";
4898
+ page.style.boxShadow = "0 4px 24px rgba(0, 0, 0, 0.08)";
4727
4899
  elements.forEach((el) => page.appendChild(el));
4728
4900
  wrapper.appendChild(page);
4729
4901
  slides.push(page);
@@ -4761,6 +4933,7 @@ var OpenDocumentPlugin = class {
4761
4933
  if (indicator) {
4762
4934
  indicator.textContent = `Page ${currentPage} of ${totalPages}`;
4763
4935
  }
4936
+ container.scrollTop = 0;
4764
4937
  ctx.emit("page-change", { page: currentPage, total: totalPages });
4765
4938
  };
4766
4939
  return {
@@ -4780,7 +4953,8 @@ var OpenDocumentPlugin = class {
4780
4953
  applyTransform();
4781
4954
  },
4782
4955
  fitToPage: () => {
4783
- scale = calculateFitScale();
4956
+ fitMode = fitMode === "width" ? "page" : "width";
4957
+ scale = calculateFitScale(fitMode);
4784
4958
  rotation = 0;
4785
4959
  applyTransform();
4786
4960
  },
@@ -5252,20 +5426,28 @@ var DocPlugin = class {
5252
5426
  if (indicator) {
5253
5427
  indicator.textContent = `Page ${currentPage} of ${totalPages}`;
5254
5428
  }
5429
+ container.scrollTop = 0;
5255
5430
  ctx.emit("page-change", { page: currentPage, total: totalPages });
5256
5431
  };
5257
5432
  if (totalPages > 1) {
5258
5433
  showPage(1);
5259
5434
  }
5260
- const calculateFitScale = () => {
5435
+ let fitMode = "width";
5436
+ const calculateFitScale = (mode = fitMode) => {
5261
5437
  const elW = 816;
5262
5438
  const elH = 1056;
5263
- const availW = Math.max(200, ctx.container.clientWidth - 48);
5264
- const availH = Math.max(200, ctx.container.clientHeight - 80);
5265
- return Math.min(1.1, Math.min(availW / elW, availH / elH));
5439
+ const availW = Math.max(280, ctx.container.clientWidth - 48);
5440
+ const availH = Math.max(280, ctx.container.clientHeight - 80);
5441
+ const sW = availW / elW;
5442
+ const sH = availH / elH;
5443
+ if (mode === "page") {
5444
+ return Math.max(0.55, Math.min(1.15, Math.min(sW, sH)));
5445
+ }
5446
+ return Math.max(0.65, Math.min(1.05, sW));
5266
5447
  };
5267
5448
  setTimeout(() => {
5268
- scale = calculateFitScale();
5449
+ fitMode = "width";
5450
+ scale = calculateFitScale("width");
5269
5451
  applyTransform();
5270
5452
  }, 60);
5271
5453
  const cleanup = () => {
@@ -5293,7 +5475,8 @@ var DocPlugin = class {
5293
5475
  applyTransform();
5294
5476
  },
5295
5477
  fitToPage: () => {
5296
- scale = calculateFitScale();
5478
+ fitMode = fitMode === "width" ? "page" : "width";
5479
+ scale = calculateFitScale(fitMode);
5297
5480
  rotation = 0;
5298
5481
  applyTransform();
5299
5482
  },
@@ -5421,45 +5604,50 @@ var DocPlugin = class {
5421
5604
  }
5422
5605
  splitIntoPages(text) {
5423
5606
  if (!text) return [""];
5424
- const explicitParts = text.split(/[\x0C\f]|\r?\n\s*[-=_]{3,}\s*(?:PAGE|Page|page break)[\s\d\w-]*[-=_]{3,}\s*\r?\n/i).map((p) => p.trim()).filter((p) => p.length > 0);
5425
- if (explicitParts.length === 0) explicitParts.push(text);
5426
- const maxLinesPerPage = 48;
5607
+ const normalized = text.replace(/\r\n/g, "\n").replace(/\r/g, "\n").replace(/\x0B/g, "\n").replace(/\x07\n/g, "\n").replace(/\x07/g, " ");
5608
+ const explicitParts = normalized.split(/[\x0C\f]|\n\s*[-=_]{3,}\s*(?:PAGE|Page|page break)[\s\d\w-]*[-=_]{3,}\s*\n/i).map((p) => p.trim()).filter((p) => p.length > 0);
5609
+ if (explicitParts.length === 0) explicitParts.push(normalized);
5610
+ const maxLinesPerPage = 32;
5611
+ const charsPerLine = 80;
5427
5612
  const finalPages = [];
5428
5613
  for (const part of explicitParts) {
5429
- const lines = part.split(/\r?\n/);
5614
+ const lines = part.split("\n");
5430
5615
  let currentLines = [];
5431
5616
  let count = 0;
5432
5617
  for (const line of lines) {
5433
- currentLines.push(line);
5434
- count++;
5435
- if (count >= maxLinesPerPage) {
5618
+ const vLines = Math.max(1, Math.ceil((line.length || 1) / charsPerLine));
5619
+ if (count + vLines > maxLinesPerPage && currentLines.length > 0) {
5436
5620
  finalPages.push(currentLines.join("\n"));
5437
5621
  currentLines = [];
5438
5622
  count = 0;
5439
5623
  }
5624
+ currentLines.push(line);
5625
+ count += vLines;
5440
5626
  }
5441
5627
  if (currentLines.length > 0) {
5442
5628
  finalPages.push(currentLines.join("\n"));
5443
5629
  }
5444
5630
  }
5445
- return finalPages.length > 0 ? finalPages : [text];
5631
+ return finalPages.length > 0 ? finalPages : [normalized];
5446
5632
  }
5447
5633
  /**
5448
5634
  * Format cleaned extracted text into attractive HTML paragraphs, headings, and lists
5449
5635
  */
5450
5636
  formatDocToHtml(text, filename) {
5451
- const lines = text.replace(/\r\n/g, "\n").replace(/\r/g, "\n").replace(/\x0B/g, "\n").split("\n");
5637
+ const lines = text.replace(/\r\n/g, "\n").replace(/\r/g, "\n").replace(/\x0B/g, "\n").replace(/\x07\n/g, "\n").replace(/\x07/g, " ").split("\n");
5452
5638
  let html = "";
5453
5639
  let inList = false;
5454
5640
  let tableLines = [];
5455
5641
  const flushTable = () => {
5456
5642
  if (tableLines.length > 0) {
5457
- html += '<table style="width: 100%; border-collapse: collapse; margin: 16px 0; font-size: 12px;">';
5458
- for (const tLine of tableLines) {
5459
- html += "<tr>";
5460
- const cols = tLine.split(" ");
5643
+ html += '<table style="width: 100%; border-collapse: collapse; margin: 16px 0; font-size: 13px; font-family: Calibri, sans-serif;">';
5644
+ for (let rIdx = 0; rIdx < tableLines.length; rIdx++) {
5645
+ const tLine = tableLines[rIdx];
5646
+ const isHeader = rIdx === 0;
5647
+ html += `<tr style="${isHeader ? "background-color: #f8fafc; font-weight: 600;" : ""}">`;
5648
+ const cols = tLine.split(" ").filter((c) => c.trim().length > 0);
5461
5649
  for (const col of cols) {
5462
- html += `<td style="border: 1px solid #cbd5e1; padding: 6px 8px;">${DOMPurify6.sanitize(col.trim())}</td>`;
5650
+ html += `<td style="border: 1px solid #cbd5e1; padding: 8px 12px;">${DOMPurify6.sanitize(col.trim())}</td>`;
5463
5651
  }
5464
5652
  html += "</tr>";
5465
5653
  }
@@ -5472,27 +5660,18 @@ var DocPlugin = class {
5472
5660
  let line = lines[i];
5473
5661
  let tabCount = (line.match(/\t/g) || []).length;
5474
5662
  if (tabCount > 0) {
5475
- let consecutiveTableLines = 1;
5476
- let j = i + 1;
5477
- while (j < lines.length) {
5478
- const nextTabCount = (lines[j].match(/\t/g) || []).length;
5479
- if (nextTabCount === tabCount) {
5480
- consecutiveTableLines++;
5481
- j++;
5482
- } else {
5483
- break;
5484
- }
5663
+ let j = i;
5664
+ while (j < lines.length && (lines[j].match(/\t/g) || []).length > 0) {
5665
+ j++;
5485
5666
  }
5486
- if (consecutiveTableLines >= 3) {
5487
- if (inList) {
5488
- html += "</ul>";
5489
- inList = false;
5490
- }
5491
- tableLines = lines.slice(i, j);
5492
- flushTable();
5493
- i = j;
5494
- continue;
5667
+ if (inList) {
5668
+ html += "</ul>";
5669
+ inList = false;
5495
5670
  }
5671
+ tableLines = lines.slice(i, j);
5672
+ flushTable();
5673
+ i = j;
5674
+ continue;
5496
5675
  }
5497
5676
  line = line.trim();
5498
5677
  if (!line) {