@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/index.js CHANGED
@@ -476,7 +476,8 @@ function createElement(tag, attrs, ...children) {
476
476
  }
477
477
  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>`;
478
478
  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>`;
479
- 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>`;
479
+ 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>`;
480
+ 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>`;
480
481
  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>`;
481
482
  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>`;
482
483
  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>`;
@@ -496,6 +497,7 @@ var ICON_MAP = {
496
497
  "zoom-in": ICON_ZOOM_IN,
497
498
  "zoom-out": ICON_ZOOM_OUT,
498
499
  "fit-page": ICON_FIT_PAGE,
500
+ "fit-width": ICON_FIT_WIDTH,
499
501
  "fit-slide": ICON_FIT_PAGE,
500
502
  "rotate-cw": ICON_ROTATE_CW,
501
503
  "rotate-ccw": ICON_ROTATE_CCW,
@@ -1442,6 +1444,7 @@ var PdfPlugin = class {
1442
1444
  let currentPage = 1;
1443
1445
  let zoomScale = 1;
1444
1446
  let rotation = 0;
1447
+ let fitMode = "width";
1445
1448
  let currentRenderTask = null;
1446
1449
  const renderPage = async (pageNum) => {
1447
1450
  if (currentRenderTask) {
@@ -1461,11 +1464,16 @@ var PdfPlugin = class {
1461
1464
  const containerWidth = container.clientWidth || 900;
1462
1465
  const containerHeight = container.clientHeight || 700;
1463
1466
  const unscaledVp = page.getViewport({ scale: 1, rotation });
1464
- const availWidth = Math.max(100, containerWidth - 48);
1465
- const availHeight = Math.max(100, containerHeight - 88);
1467
+ const availWidth = Math.max(280, containerWidth - 48);
1468
+ const availHeight = Math.max(280, containerHeight - 88);
1466
1469
  const scaleW = availWidth / unscaledVp.width;
1467
1470
  const scaleH = availHeight / unscaledVp.height;
1468
- const fitScale = Math.min(scaleW, scaleH);
1471
+ let fitScale;
1472
+ if (fitMode === "page") {
1473
+ fitScale = Math.max(0.5, Math.min(scaleW, scaleH));
1474
+ } else {
1475
+ fitScale = Math.max(0.65, Math.min(1.15, scaleW));
1476
+ }
1469
1477
  const effectiveScale = (fitScale > 0 ? fitScale : 1) * zoomScale;
1470
1478
  const pixelRatio = window.devicePixelRatio || 1;
1471
1479
  const viewport = page.getViewport({ scale: effectiveScale, rotation });
@@ -1534,6 +1542,7 @@ var PdfPlugin = class {
1534
1542
  renderPage(currentPage);
1535
1543
  },
1536
1544
  fitToPage: () => {
1545
+ fitMode = fitMode === "width" ? "page" : "width";
1537
1546
  zoomScale = 1;
1538
1547
  rotation = 0;
1539
1548
  renderPage(currentPage);
@@ -1550,6 +1559,7 @@ var PdfPlugin = class {
1550
1559
  getPageCount: () => totalPages,
1551
1560
  getCurrentPage: () => currentPage,
1552
1561
  goToPage: (page) => {
1562
+ container.scrollTop = 0;
1553
1563
  renderPage(page);
1554
1564
  },
1555
1565
  download: () => {
@@ -2054,7 +2064,14 @@ var DocxPlugin = class {
2054
2064
  ignoreFonts: true,
2055
2065
  // Avoid crashes on embedded obfuscated fonts
2056
2066
  breakPages: true,
2057
- experimental: true
2067
+ experimental: true,
2068
+ ignoreLastRenderedPageBreak: false,
2069
+ // Honor Word's exact page breaks!
2070
+ renderHeaders: true,
2071
+ renderFooters: true,
2072
+ renderFootnotes: true,
2073
+ renderEndnotes: true,
2074
+ useBase64URL: true
2058
2075
  });
2059
2076
  if (!ctx.container.contains(wrapper)) {
2060
2077
  ctx.container.appendChild(wrapper);
@@ -2075,11 +2092,14 @@ var DocxPlugin = class {
2075
2092
  renderedSuccessfully = true;
2076
2093
  } catch (fallbackErr) {
2077
2094
  console.error("[DocxPlugin] Native fallback failed:", fallbackErr);
2095
+ const isCorrupt = fallbackErr?.message?.includes("invalid zip") || fallbackErr?.message?.includes("corrupted");
2078
2096
  wrapper.innerHTML = `
2079
- <div style="text-align:center; padding: 48px; background: #fff; border-radius: 8px; box-shadow: 0 4px 20px rgba(0,0,0,0.06);">
2080
- <div style="font-size:48px; margin-bottom: 16px;">\u{1F4C4}</div>
2081
- <h3 style="margin: 0 0 8px; color: #1e293b;">${ctx.metadata.name || "Word Document"}</h3>
2082
- <p style="color: #64748b; margin: 0;">Could not parse document content</p>
2097
+ <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;">
2098
+ <div style="font-size:48px; margin-bottom: 16px;">${isCorrupt ? "\u26A0\uFE0F" : "\u{1F4C4}"}</div>
2099
+ <h3 style="margin: 0 0 8px; color: #1e293b; font-size: 18px;">${ctx.metadata.name || "Word Document"}</h3>
2100
+ <p style="color: #64748b; margin: 0 0 16px; font-size: 14px; line-height: 1.5;">
2101
+ ${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."}
2102
+ </p>
2083
2103
  </div>
2084
2104
  `;
2085
2105
  if (!ctx.container.contains(wrapper)) {
@@ -2087,8 +2107,67 @@ var DocxPlugin = class {
2087
2107
  }
2088
2108
  }
2089
2109
  }
2090
- const sections = wrapper.querySelectorAll("section.docx");
2091
- const cards = wrapper.querySelectorAll(".fp-docx-page-card");
2110
+ let sections = Array.from(wrapper.querySelectorAll("section.docx"));
2111
+ const cards = Array.from(wrapper.querySelectorAll(".fp-docx-page-card"));
2112
+ if (sections.length === 1 && cards.length === 0) {
2113
+ const singleSec = sections[0];
2114
+ const contentContainer = singleSec.querySelector("article") || singleSec;
2115
+ const children = Array.from(contentContainer.children);
2116
+ const pageH = singleSec.offsetHeight > 1300 ? 1122 : Math.max(1056, singleSec.offsetHeight);
2117
+ const secH = singleSec.offsetHeight || singleSec.scrollHeight;
2118
+ if (secH > pageH * 1.25 && children.length > 1) {
2119
+ const childHeights = children.map((c) => {
2120
+ const rectH = c.getBoundingClientRect().height;
2121
+ const offH = c.offsetHeight;
2122
+ const textLen = c.textContent?.trim().length || 0;
2123
+ const estH = Math.max(24, Math.ceil(textLen / 80) * 22 + 16);
2124
+ return Math.max(rectH, offH, estH);
2125
+ });
2126
+ const parent = singleSec.parentElement || wrapper;
2127
+ const newSections = [singleSec];
2128
+ const headerEl = singleSec.querySelector("header");
2129
+ const footerEl = singleSec.querySelector("footer");
2130
+ contentContainer.innerHTML = "";
2131
+ singleSec.style.minHeight = `${pageH}px`;
2132
+ singleSec.style.boxSizing = "border-box";
2133
+ let curContent = contentContainer;
2134
+ let curH = 0;
2135
+ const maxH = pageH - 140;
2136
+ for (let i = 0; i < children.length; i++) {
2137
+ const child = children[i];
2138
+ const chH = childHeights[i];
2139
+ curContent.appendChild(child);
2140
+ curH += chH;
2141
+ if (curH >= maxH && i < children.length - 1) {
2142
+ const nextSec = document.createElement("section");
2143
+ nextSec.className = singleSec.className;
2144
+ nextSec.style.cssText = singleSec.style.cssText;
2145
+ nextSec.style.minHeight = `${pageH}px`;
2146
+ nextSec.style.boxSizing = "border-box";
2147
+ nextSec.style.backgroundColor = "#ffffff";
2148
+ nextSec.style.boxShadow = "0 4px 24px rgba(0, 0, 0, 0.08)";
2149
+ nextSec.style.borderRadius = "4px";
2150
+ nextSec.style.marginBottom = "24px";
2151
+ if (headerEl) {
2152
+ nextSec.appendChild(headerEl.cloneNode(true));
2153
+ }
2154
+ const nextArticle = document.createElement("article");
2155
+ if (contentContainer.tagName.toLowerCase() === "article") {
2156
+ nextArticle.style.cssText = contentContainer.style.cssText;
2157
+ }
2158
+ nextSec.appendChild(nextArticle);
2159
+ if (footerEl) {
2160
+ nextSec.appendChild(footerEl.cloneNode(true));
2161
+ }
2162
+ parent.appendChild(nextSec);
2163
+ newSections.push(nextSec);
2164
+ curContent = nextArticle;
2165
+ curH = 0;
2166
+ }
2167
+ }
2168
+ sections = newSections;
2169
+ }
2170
+ }
2092
2171
  const pageElements = sections.length > 0 ? sections : cards;
2093
2172
  const totalPages = Math.max(1, pageElements.length);
2094
2173
  let currentPage = 1;
@@ -2125,6 +2204,7 @@ var DocxPlugin = class {
2125
2204
  if (indicator) {
2126
2205
  indicator.textContent = `Page ${currentPage} of ${totalPages}`;
2127
2206
  }
2207
+ ctx.container.scrollTop = 0;
2128
2208
  ctx.emit("page-change", { page: currentPage, total: totalPages });
2129
2209
  };
2130
2210
  if (totalPages > 1) {
@@ -2132,22 +2212,27 @@ var DocxPlugin = class {
2132
2212
  }
2133
2213
  scale = 1;
2134
2214
  let rotation = 0;
2135
- const calculateFitScale = () => {
2215
+ let fitMode = "width";
2216
+ const calculateFitScale = (mode = fitMode) => {
2136
2217
  const activeEl = pageElements[currentPage - 1] || wrapper.firstElementChild || wrapper;
2137
2218
  const elW = activeEl.offsetWidth || 816;
2138
- const elH = activeEl.offsetHeight || 1056;
2139
- const availW = Math.max(200, ctx.container.clientWidth - 48);
2140
- const availH = Math.max(200, ctx.container.clientHeight - 80);
2219
+ const singlePageH = Math.min(activeEl.offsetHeight || 1056, Math.round(elW * 1.32));
2220
+ const availW = Math.max(280, ctx.container.clientWidth - 48);
2221
+ const availH = Math.max(280, ctx.container.clientHeight - 80);
2141
2222
  const sW = availW / elW;
2142
- const sH = availH / elH;
2143
- return Math.min(1.1, Math.min(sW, sH));
2223
+ const sH = availH / singlePageH;
2224
+ if (mode === "page") {
2225
+ return Math.max(0.55, Math.min(1.15, Math.min(sW, sH)));
2226
+ }
2227
+ return Math.max(0.65, Math.min(1.05, sW));
2144
2228
  };
2145
2229
  const applyTransform = () => {
2146
2230
  wrapper.style.transform = `scale(${scale}) rotate(${rotation}deg)`;
2147
2231
  wrapper.style.transformOrigin = "top center";
2148
2232
  };
2149
2233
  setTimeout(() => {
2150
- scale = calculateFitScale();
2234
+ fitMode = "width";
2235
+ scale = calculateFitScale("width");
2151
2236
  applyTransform();
2152
2237
  }, 60);
2153
2238
  const cleanup = () => {
@@ -2181,7 +2266,8 @@ var DocxPlugin = class {
2181
2266
  applyTransform();
2182
2267
  },
2183
2268
  fitToPage: () => {
2184
- scale = calculateFitScale();
2269
+ fitMode = fitMode === "width" ? "page" : "width";
2270
+ scale = calculateFitScale(fitMode);
2185
2271
  rotation = 0;
2186
2272
  applyTransform();
2187
2273
  },
@@ -2625,11 +2711,9 @@ var ExcelPlugin = class {
2625
2711
  const calculateFitScale = () => {
2626
2712
  const table = contentArea.querySelector("table");
2627
2713
  if (!table) return 1;
2628
- const availW = Math.max(200, container.clientWidth - 48);
2629
- const availH = Math.max(200, container.clientHeight - 80);
2714
+ const availW = Math.max(280, container.clientWidth - 48);
2630
2715
  const tW = table.offsetWidth || 800;
2631
- const tH = table.offsetHeight || 600;
2632
- return Math.min(1, Math.min(availW / tW, availH / tH));
2716
+ return Math.max(0.65, Math.min(1, availW / tW));
2633
2717
  };
2634
2718
  try {
2635
2719
  wb = XLSX.read(new Uint8Array(ctx.buffer), { type: "array", cellDates: true });
@@ -3053,17 +3137,39 @@ var CodePlugin = class {
3053
3137
  let rawPages = [];
3054
3138
  if (isTxt) {
3055
3139
  const explicitPages = fullText.split(/(?:\f|\x0C)/);
3140
+ const charsPerLine = 85;
3141
+ const maxVisualLines = 45;
3142
+ const charsPerPage = charsPerLine * maxVisualLines;
3056
3143
  for (const ep of explicitPages) {
3057
3144
  const lines = ep.split(/\r?\n/);
3058
3145
  let currentChunk = [];
3146
+ let currentLines = 0;
3059
3147
  for (let i = 0; i < lines.length; i++) {
3060
- currentChunk.push(lines[i]);
3061
- if (currentChunk.length >= 46) {
3148
+ const line = lines[i];
3149
+ const vLines = Math.max(1, Math.ceil((line.length || 1) / charsPerLine));
3150
+ if (currentLines + vLines > maxVisualLines && currentChunk.length > 0) {
3062
3151
  rawPages.push(currentChunk.join("\n"));
3063
3152
  currentChunk = [];
3153
+ currentLines = 0;
3154
+ }
3155
+ if (vLines > maxVisualLines) {
3156
+ let remaining = line;
3157
+ while (remaining.length > charsPerPage) {
3158
+ let splitIdx = remaining.lastIndexOf(" ", charsPerPage);
3159
+ if (splitIdx < charsPerPage * 0.75) splitIdx = charsPerPage;
3160
+ rawPages.push(remaining.slice(0, splitIdx));
3161
+ remaining = remaining.slice(splitIdx).trimStart();
3162
+ }
3163
+ if (remaining.length > 0) {
3164
+ currentChunk.push(remaining);
3165
+ currentLines = Math.ceil(remaining.length / charsPerLine);
3166
+ }
3167
+ } else {
3168
+ currentChunk.push(line);
3169
+ currentLines += vLines;
3064
3170
  }
3065
3171
  }
3066
- if (currentChunk.length > 0 || lines.length === 0) {
3172
+ if (currentChunk.length > 0) {
3067
3173
  rawPages.push(currentChunk.join("\n"));
3068
3174
  }
3069
3175
  }
@@ -3173,6 +3279,7 @@ var CodePlugin = class {
3173
3279
  if (indicator) {
3174
3280
  indicator.textContent = `Page ${currentPage} of ${totalPages}`;
3175
3281
  }
3282
+ container.scrollTop = 0;
3176
3283
  ctx.emit("page-change", { page: currentPage, total: totalPages });
3177
3284
  };
3178
3285
  if (totalPages > 1) {
@@ -3226,7 +3333,7 @@ var CodePlugin = class {
3226
3333
  fitToPage: () => {
3227
3334
  fontSize = 13;
3228
3335
  rotation = 0;
3229
- zoomLevel = 1;
3336
+ zoomLevel = isTxt ? Math.max(0.65, Math.min(1.05, (container.clientWidth - 48) / 816)) : 1;
3230
3337
  updateTransform();
3231
3338
  },
3232
3339
  rotateCW: () => {
@@ -4208,20 +4315,27 @@ var RtfPlugin = class {
4208
4315
  let scale = 1;
4209
4316
  let rotation = 0;
4210
4317
  let pageElements = [];
4211
- const calculateFitScale = () => {
4318
+ let fitMode = "width";
4319
+ const calculateFitScale = (mode = fitMode) => {
4212
4320
  const activeEl = pageElements[currentPage - 1] || wrapper;
4213
4321
  const elW = activeEl.offsetWidth || 850;
4214
- const elH = activeEl.offsetHeight || 1e3;
4215
- const availW = Math.max(200, ctx.container.clientWidth - 48);
4216
- const availH = Math.max(200, ctx.container.clientHeight - 80);
4217
- return Math.min(1.1, Math.min(availW / elW, availH / elH));
4322
+ const singlePageH = Math.min(activeEl.offsetHeight || 1056, Math.round(elW * 1.32));
4323
+ const availW = Math.max(280, ctx.container.clientWidth - 48);
4324
+ const availH = Math.max(280, ctx.container.clientHeight - 80);
4325
+ const sW = availW / elW;
4326
+ const sH = availH / singlePageH;
4327
+ if (mode === "page") {
4328
+ return Math.max(0.55, Math.min(1.15, Math.min(sW, sH)));
4329
+ }
4330
+ return Math.max(0.65, Math.min(1.05, sW));
4218
4331
  };
4219
4332
  const applyTransform = () => {
4220
4333
  wrapper.style.transform = `scale(${scale}) rotate(${rotation}deg)`;
4221
4334
  wrapper.style.transformOrigin = "top center";
4222
4335
  };
4223
4336
  setTimeout(() => {
4224
- scale = calculateFitScale();
4337
+ fitMode = "width";
4338
+ scale = calculateFitScale("width");
4225
4339
  applyTransform();
4226
4340
  }, 60);
4227
4341
  try {
@@ -4230,11 +4344,60 @@ var RtfPlugin = class {
4230
4344
  }
4231
4345
  const doc = new RTFJS.Document(ctx.buffer, {});
4232
4346
  const htmlElements = await doc.render();
4233
- pageElements = htmlElements;
4234
- for (let i = 0; i < htmlElements.length; i++) {
4235
- const el = htmlElements[i];
4236
- el.style.display = i === 0 ? "block" : "none";
4237
- wrapper.appendChild(el);
4347
+ if (htmlElements.length === 1) {
4348
+ const singleEl = htmlElements[0];
4349
+ wrapper.appendChild(singleEl);
4350
+ const children = Array.from(singleEl.children);
4351
+ const secH = singleEl.offsetHeight || singleEl.scrollHeight;
4352
+ if (secH > 1300 && children.length > 1) {
4353
+ const childHeights = children.map((c) => {
4354
+ const rectH = c.getBoundingClientRect().height;
4355
+ const offH = c.offsetHeight;
4356
+ const textLen = c.textContent?.trim().length || 0;
4357
+ const estH = Math.max(24, Math.ceil(textLen / 80) * 22 + 16);
4358
+ return Math.max(rectH, offH, estH);
4359
+ });
4360
+ wrapper.innerHTML = "";
4361
+ const createRtfCard = () => {
4362
+ const card = document.createElement("div");
4363
+ card.className = "fp-rtf-page-card";
4364
+ card.style.backgroundColor = "#ffffff";
4365
+ card.style.boxShadow = "0 4px 24px rgba(0,0,0,0.08)";
4366
+ card.style.borderRadius = "4px";
4367
+ card.style.padding = "72px 56px";
4368
+ card.style.width = "816px";
4369
+ card.style.minHeight = "1056px";
4370
+ card.style.boxSizing = "border-box";
4371
+ card.style.marginBottom = "24px";
4372
+ return card;
4373
+ };
4374
+ let curCard = createRtfCard();
4375
+ wrapper.appendChild(curCard);
4376
+ pageElements = [curCard];
4377
+ let curH = 0;
4378
+ const maxH = 920;
4379
+ for (let i = 0; i < children.length; i++) {
4380
+ const child = children[i];
4381
+ const chH = childHeights[i];
4382
+ curCard.appendChild(child);
4383
+ curH += chH;
4384
+ if (curH >= maxH && i < children.length - 1) {
4385
+ curCard = createRtfCard();
4386
+ wrapper.appendChild(curCard);
4387
+ pageElements.push(curCard);
4388
+ curH = 0;
4389
+ }
4390
+ }
4391
+ } else {
4392
+ pageElements = [singleEl];
4393
+ }
4394
+ } else {
4395
+ pageElements = htmlElements;
4396
+ for (let i = 0; i < htmlElements.length; i++) {
4397
+ const el = htmlElements[i];
4398
+ el.style.display = i === 0 ? "block" : "none";
4399
+ wrapper.appendChild(el);
4400
+ }
4238
4401
  }
4239
4402
  } catch (err) {
4240
4403
  console.warn("[RtfPlugin] RTF render error, fallback text:", err);
@@ -4300,6 +4463,7 @@ var RtfPlugin = class {
4300
4463
  if (indicator) {
4301
4464
  indicator.textContent = `Page ${currentPage} of ${totalPages}`;
4302
4465
  }
4466
+ ctx.container.scrollTop = 0;
4303
4467
  ctx.emit("page-change", { page: currentPage, total: totalPages });
4304
4468
  };
4305
4469
  if (totalPages > 1) {
@@ -4330,7 +4494,8 @@ var RtfPlugin = class {
4330
4494
  applyTransform();
4331
4495
  },
4332
4496
  fitToPage: () => {
4333
- scale = calculateFitScale();
4497
+ fitMode = fitMode === "width" ? "page" : "width";
4498
+ scale = calculateFitScale(fitMode);
4334
4499
  rotation = 0;
4335
4500
  applyTransform();
4336
4501
  },
@@ -4649,19 +4814,29 @@ var OpenDocumentPlugin = class {
4649
4814
  ctx.container.appendChild(container);
4650
4815
  let scale = 1;
4651
4816
  let rotation = 0;
4652
- const calculateFitScale = () => {
4817
+ let fitMode = "width";
4818
+ const calculateFitScale = (mode = fitMode) => {
4653
4819
  const elW = wrapper.offsetWidth || 850;
4654
- const elH = wrapper.offsetHeight || (isPresentation ? 540 : 1e3);
4655
- const availW = Math.max(200, ctx.container.clientWidth - 48);
4656
- const availH = Math.max(200, ctx.container.clientHeight - 80);
4657
- return Math.min(1, Math.min(availW / elW, availH / elH));
4820
+ const singlePageH = Math.min(wrapper.offsetHeight || 1056, Math.round(elW * 1.32));
4821
+ const availW = Math.max(280, ctx.container.clientWidth - 48);
4822
+ const availH = Math.max(280, ctx.container.clientHeight - 80);
4823
+ const sW = availW / elW;
4824
+ const sH = availH / (isPresentation ? 540 : singlePageH);
4825
+ if (isPresentation) {
4826
+ return Math.min(1, Math.min(sW, sH));
4827
+ }
4828
+ if (mode === "page") {
4829
+ return Math.max(0.55, Math.min(1.15, Math.min(sW, sH)));
4830
+ }
4831
+ return Math.max(0.65, Math.min(1.05, sW));
4658
4832
  };
4659
4833
  const applyTransform = () => {
4660
4834
  wrapper.style.transform = `scale(${scale}) rotate(${rotation}deg)`;
4661
4835
  wrapper.style.transformOrigin = "top center";
4662
4836
  };
4663
4837
  setTimeout(() => {
4664
- scale = calculateFitScale();
4838
+ fitMode = "width";
4839
+ scale = calculateFitScale("width");
4665
4840
  applyTransform();
4666
4841
  }, 60);
4667
4842
  let currentPage = 1;
@@ -4760,12 +4935,9 @@ var OpenDocumentPlugin = class {
4760
4935
  page.style.backgroundColor = "#ffffff";
4761
4936
  page.style.boxShadow = "0 2px 10px rgba(0,0,0,0.08)";
4762
4937
  page.style.borderRadius = "4px";
4763
- page.style.boxSizing = "border-box";
4764
4938
  page.style.display = idx === 0 ? "block" : "none";
4765
- page.style.position = "absolute";
4766
- page.style.top = "0";
4767
- page.style.left = "50%";
4768
- page.style.transform = "translateX(-50%)";
4939
+ page.style.margin = "0 auto 24px";
4940
+ page.style.boxShadow = "0 4px 24px rgba(0, 0, 0, 0.08)";
4769
4941
  elements.forEach((el) => page.appendChild(el));
4770
4942
  wrapper.appendChild(page);
4771
4943
  slides.push(page);
@@ -4803,6 +4975,7 @@ var OpenDocumentPlugin = class {
4803
4975
  if (indicator) {
4804
4976
  indicator.textContent = `Page ${currentPage} of ${totalPages}`;
4805
4977
  }
4978
+ container.scrollTop = 0;
4806
4979
  ctx.emit("page-change", { page: currentPage, total: totalPages });
4807
4980
  };
4808
4981
  return {
@@ -4822,7 +4995,8 @@ var OpenDocumentPlugin = class {
4822
4995
  applyTransform();
4823
4996
  },
4824
4997
  fitToPage: () => {
4825
- scale = calculateFitScale();
4998
+ fitMode = fitMode === "width" ? "page" : "width";
4999
+ scale = calculateFitScale(fitMode);
4826
5000
  rotation = 0;
4827
5001
  applyTransform();
4828
5002
  },
@@ -5294,20 +5468,28 @@ var DocPlugin = class {
5294
5468
  if (indicator) {
5295
5469
  indicator.textContent = `Page ${currentPage} of ${totalPages}`;
5296
5470
  }
5471
+ container.scrollTop = 0;
5297
5472
  ctx.emit("page-change", { page: currentPage, total: totalPages });
5298
5473
  };
5299
5474
  if (totalPages > 1) {
5300
5475
  showPage(1);
5301
5476
  }
5302
- const calculateFitScale = () => {
5477
+ let fitMode = "width";
5478
+ const calculateFitScale = (mode = fitMode) => {
5303
5479
  const elW = 816;
5304
5480
  const elH = 1056;
5305
- const availW = Math.max(200, ctx.container.clientWidth - 48);
5306
- const availH = Math.max(200, ctx.container.clientHeight - 80);
5307
- return Math.min(1.1, Math.min(availW / elW, availH / elH));
5481
+ const availW = Math.max(280, ctx.container.clientWidth - 48);
5482
+ const availH = Math.max(280, ctx.container.clientHeight - 80);
5483
+ const sW = availW / elW;
5484
+ const sH = availH / elH;
5485
+ if (mode === "page") {
5486
+ return Math.max(0.55, Math.min(1.15, Math.min(sW, sH)));
5487
+ }
5488
+ return Math.max(0.65, Math.min(1.05, sW));
5308
5489
  };
5309
5490
  setTimeout(() => {
5310
- scale = calculateFitScale();
5491
+ fitMode = "width";
5492
+ scale = calculateFitScale("width");
5311
5493
  applyTransform();
5312
5494
  }, 60);
5313
5495
  const cleanup = () => {
@@ -5335,7 +5517,8 @@ var DocPlugin = class {
5335
5517
  applyTransform();
5336
5518
  },
5337
5519
  fitToPage: () => {
5338
- scale = calculateFitScale();
5520
+ fitMode = fitMode === "width" ? "page" : "width";
5521
+ scale = calculateFitScale(fitMode);
5339
5522
  rotation = 0;
5340
5523
  applyTransform();
5341
5524
  },
@@ -5463,45 +5646,50 @@ var DocPlugin = class {
5463
5646
  }
5464
5647
  splitIntoPages(text) {
5465
5648
  if (!text) return [""];
5466
- 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);
5467
- if (explicitParts.length === 0) explicitParts.push(text);
5468
- const maxLinesPerPage = 48;
5649
+ const normalized = text.replace(/\r\n/g, "\n").replace(/\r/g, "\n").replace(/\x0B/g, "\n").replace(/\x07\n/g, "\n").replace(/\x07/g, " ");
5650
+ 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);
5651
+ if (explicitParts.length === 0) explicitParts.push(normalized);
5652
+ const maxLinesPerPage = 32;
5653
+ const charsPerLine = 80;
5469
5654
  const finalPages = [];
5470
5655
  for (const part of explicitParts) {
5471
- const lines = part.split(/\r?\n/);
5656
+ const lines = part.split("\n");
5472
5657
  let currentLines = [];
5473
5658
  let count = 0;
5474
5659
  for (const line of lines) {
5475
- currentLines.push(line);
5476
- count++;
5477
- if (count >= maxLinesPerPage) {
5660
+ const vLines = Math.max(1, Math.ceil((line.length || 1) / charsPerLine));
5661
+ if (count + vLines > maxLinesPerPage && currentLines.length > 0) {
5478
5662
  finalPages.push(currentLines.join("\n"));
5479
5663
  currentLines = [];
5480
5664
  count = 0;
5481
5665
  }
5666
+ currentLines.push(line);
5667
+ count += vLines;
5482
5668
  }
5483
5669
  if (currentLines.length > 0) {
5484
5670
  finalPages.push(currentLines.join("\n"));
5485
5671
  }
5486
5672
  }
5487
- return finalPages.length > 0 ? finalPages : [text];
5673
+ return finalPages.length > 0 ? finalPages : [normalized];
5488
5674
  }
5489
5675
  /**
5490
5676
  * Format cleaned extracted text into attractive HTML paragraphs, headings, and lists
5491
5677
  */
5492
5678
  formatDocToHtml(text, filename) {
5493
- const lines = text.replace(/\r\n/g, "\n").replace(/\r/g, "\n").replace(/\x0B/g, "\n").split("\n");
5679
+ 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");
5494
5680
  let html = "";
5495
5681
  let inList = false;
5496
5682
  let tableLines = [];
5497
5683
  const flushTable = () => {
5498
5684
  if (tableLines.length > 0) {
5499
- html += '<table style="width: 100%; border-collapse: collapse; margin: 16px 0; font-size: 12px;">';
5500
- for (const tLine of tableLines) {
5501
- html += "<tr>";
5502
- const cols = tLine.split(" ");
5685
+ html += '<table style="width: 100%; border-collapse: collapse; margin: 16px 0; font-size: 13px; font-family: Calibri, sans-serif;">';
5686
+ for (let rIdx = 0; rIdx < tableLines.length; rIdx++) {
5687
+ const tLine = tableLines[rIdx];
5688
+ const isHeader = rIdx === 0;
5689
+ html += `<tr style="${isHeader ? "background-color: #f8fafc; font-weight: 600;" : ""}">`;
5690
+ const cols = tLine.split(" ").filter((c) => c.trim().length > 0);
5503
5691
  for (const col of cols) {
5504
- html += `<td style="border: 1px solid #cbd5e1; padding: 6px 8px;">${DOMPurify6.sanitize(col.trim())}</td>`;
5692
+ html += `<td style="border: 1px solid #cbd5e1; padding: 8px 12px;">${DOMPurify6.sanitize(col.trim())}</td>`;
5505
5693
  }
5506
5694
  html += "</tr>";
5507
5695
  }
@@ -5514,27 +5702,18 @@ var DocPlugin = class {
5514
5702
  let line = lines[i];
5515
5703
  let tabCount = (line.match(/\t/g) || []).length;
5516
5704
  if (tabCount > 0) {
5517
- let consecutiveTableLines = 1;
5518
- let j = i + 1;
5519
- while (j < lines.length) {
5520
- const nextTabCount = (lines[j].match(/\t/g) || []).length;
5521
- if (nextTabCount === tabCount) {
5522
- consecutiveTableLines++;
5523
- j++;
5524
- } else {
5525
- break;
5526
- }
5705
+ let j = i;
5706
+ while (j < lines.length && (lines[j].match(/\t/g) || []).length > 0) {
5707
+ j++;
5527
5708
  }
5528
- if (consecutiveTableLines >= 3) {
5529
- if (inList) {
5530
- html += "</ul>";
5531
- inList = false;
5532
- }
5533
- tableLines = lines.slice(i, j);
5534
- flushTable();
5535
- i = j;
5536
- continue;
5709
+ if (inList) {
5710
+ html += "</ul>";
5711
+ inList = false;
5537
5712
  }
5713
+ tableLines = lines.slice(i, j);
5714
+ flushTable();
5715
+ i = j;
5716
+ continue;
5538
5717
  }
5539
5718
  line = line.trim();
5540
5719
  if (!line) {