@files-preview-app/preview-file 1.3.2 → 1.3.3

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
@@ -3476,26 +3476,6 @@ var ExcelPlugin = class {
3476
3476
  instance.zoomIn?.();
3477
3477
  }
3478
3478
  },
3479
- {
3480
- id: "fit-page",
3481
- icon: "fit-page",
3482
- label: "Fit to View",
3483
- type: "button",
3484
- group: "zoom",
3485
- execute: () => {
3486
- instance.fitToPage?.();
3487
- }
3488
- },
3489
- {
3490
- id: "rotate-cw",
3491
- icon: "rotate-cw",
3492
- label: "Rotate",
3493
- type: "button",
3494
- group: "view",
3495
- execute: () => {
3496
- instance.rotateCW?.();
3497
- }
3498
- },
3499
3479
  {
3500
3480
  id: "download",
3501
3481
  icon: "download",
@@ -3556,12 +3536,11 @@ var ExcelPlugin = class {
3556
3536
  container.appendChild(tabsArea);
3557
3537
  ctx.container.appendChild(container);
3558
3538
  let scale = 1;
3559
- let rotation = 0;
3560
3539
  let currentSheetIndex = 1;
3561
3540
  let sheetNames = [];
3562
3541
  let wb = null;
3563
3542
  const applyTransform = () => {
3564
- contentArea.style.transform = `scale(${scale}) rotate(${rotation}deg)`;
3543
+ contentArea.style.transform = `scale(${scale})`;
3565
3544
  contentArea.style.transformOrigin = "top left";
3566
3545
  };
3567
3546
  const calculateFitScale = () => {
@@ -3569,7 +3548,7 @@ var ExcelPlugin = class {
3569
3548
  if (!table) return 1;
3570
3549
  const availW = Math.max(280, container.clientWidth - 48);
3571
3550
  const tW = table.offsetWidth || 800;
3572
- return Math.max(0.65, Math.min(1, availW / tW));
3551
+ return Math.max(0.4, Math.min(1, availW / tW));
3573
3552
  };
3574
3553
  try {
3575
3554
  wb = XLSX.read(new Uint8Array(ctx.buffer), { type: "array", cellDates: true });
@@ -3624,7 +3603,16 @@ var ExcelPlugin = class {
3624
3603
  }
3625
3604
  });
3626
3605
  ctx.emit("page-change", { page: currentSheetIndex, total: sheetNames.length });
3606
+ requestAnimationFrame(() => {
3607
+ scale = calculateFitScale();
3608
+ applyTransform();
3609
+ });
3627
3610
  };
3611
+ const ro = new ResizeObserver(() => {
3612
+ scale = calculateFitScale();
3613
+ applyTransform();
3614
+ });
3615
+ ro.observe(container);
3628
3616
  if (sheetNames.length > 0) {
3629
3617
  sheetNames.forEach((name, idx) => {
3630
3618
  const btn = document.createElement("button");
@@ -3651,6 +3639,7 @@ var ExcelPlugin = class {
3651
3639
  `;
3652
3640
  }
3653
3641
  const cleanup = () => {
3642
+ ro.disconnect();
3654
3643
  container.remove();
3655
3644
  ctx.container.innerHTML = "";
3656
3645
  };
@@ -3672,16 +3661,11 @@ var ExcelPlugin = class {
3672
3661
  },
3673
3662
  fitToPage: () => {
3674
3663
  scale = calculateFitScale();
3675
- rotation = 0;
3676
3664
  applyTransform();
3677
3665
  },
3678
3666
  rotateCW: () => {
3679
- rotation = (rotation + 90) % 360;
3680
- applyTransform();
3681
3667
  },
3682
3668
  rotateCCW: () => {
3683
- rotation = (rotation - 90 + 360) % 360;
3684
- applyTransform();
3685
3669
  },
3686
3670
  goToPage: (page) => {
3687
3671
  if (page > 0 && page <= sheetNames.length) {
@@ -3779,38 +3763,15 @@ var CsvPlugin = class {
3779
3763
  return ext === ".csv" || ext === ".tsv" || mime === "text/csv" || mime === "text/tab-separated-values";
3780
3764
  }
3781
3765
  getToolbarActions(instance) {
3782
- const totalPages = instance.getPageCount?.() ?? 1;
3783
3766
  const actions = [];
3784
3767
  actions.push({
3785
3768
  id: "thumbnails",
3786
3769
  icon: "thumbnails",
3787
- label: "Page Thumbnails",
3770
+ label: "Sheet Thumbnails",
3788
3771
  type: "button",
3789
3772
  group: "navigation",
3790
3773
  execute: () => instance.toggleThumbnails?.()
3791
3774
  });
3792
- if (totalPages > 1) {
3793
- actions.push({
3794
- id: "page-nav",
3795
- icon: "",
3796
- label: "Page Navigation",
3797
- type: "page-nav",
3798
- group: "navigation",
3799
- value: instance.getCurrentPage?.() ?? 1,
3800
- max: totalPages,
3801
- execute: (action, page) => {
3802
- const cur = instance.getCurrentPage?.() ?? 1;
3803
- const max = instance.getPageCount?.() ?? 1;
3804
- if (action === "prev") {
3805
- if (cur > 1) instance.goToPage?.(cur - 1);
3806
- } else if (action === "next") {
3807
- if (cur < max) instance.goToPage?.(cur + 1);
3808
- } else if (typeof page === "number") {
3809
- instance.goToPage?.(page);
3810
- }
3811
- }
3812
- });
3813
- }
3814
3775
  actions.push(
3815
3776
  {
3816
3777
  id: "zoom-out",
@@ -3832,16 +3793,6 @@ var CsvPlugin = class {
3832
3793
  instance.zoomIn?.();
3833
3794
  }
3834
3795
  },
3835
- {
3836
- id: "fit-page",
3837
- icon: "fit-page",
3838
- label: "Fit to View",
3839
- type: "button",
3840
- group: "zoom",
3841
- execute: () => {
3842
- instance.fitToPage?.();
3843
- }
3844
- },
3845
3796
  {
3846
3797
  id: "download",
3847
3798
  icon: "download",
@@ -3884,131 +3835,135 @@ var CsvPlugin = class {
3884
3835
  container.style.overflow = "auto";
3885
3836
  container.style.padding = "16px";
3886
3837
  container.style.boxSizing = "border-box";
3887
- container.style.transformOrigin = "top left";
3838
+ const tableWrapper = document.createElement("div");
3839
+ tableWrapper.style.transformOrigin = "top left";
3888
3840
  const delimiter = ctx.metadata.extension === ".tsv" ? " " : ",";
3889
3841
  const allLines = text.split(/\r?\n/).filter((r) => r.trim().length > 0);
3890
3842
  const headerLine = allLines[0] || "";
3891
3843
  const headerCells = headerLine.split(delimiter);
3892
3844
  const dataLines = allLines.slice(1);
3893
- const ROWS_PER_PAGE = 100;
3894
- const totalPages = Math.max(1, Math.ceil(dataLines.length / ROWS_PER_PAGE));
3895
- let currentPage = 1;
3896
3845
  const table = document.createElement("table");
3897
3846
  table.style.borderCollapse = "collapse";
3898
- table.style.width = "100%";
3847
+ table.style.minWidth = "100%";
3899
3848
  table.style.fontFamily = '-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, monospace';
3900
3849
  table.style.fontSize = "13px";
3901
- const renderPage = (pageNum) => {
3902
- currentPage = Math.max(1, Math.min(totalPages, pageNum));
3903
- table.innerHTML = "";
3904
- const headerTr = document.createElement("tr");
3905
- headerCells.forEach((cell) => {
3906
- const th = document.createElement("th");
3907
- th.textContent = cell.trim();
3908
- th.style.border = "1px solid #d0d7de";
3909
- th.style.padding = "8px 12px";
3910
- th.style.backgroundColor = "#f6f8fa";
3911
- th.style.fontWeight = "600";
3912
- th.style.whiteSpace = "nowrap";
3913
- headerTr.appendChild(th);
3914
- });
3915
- table.appendChild(headerTr);
3916
- const start = (currentPage - 1) * ROWS_PER_PAGE;
3917
- const end = Math.min(dataLines.length, start + ROWS_PER_PAGE);
3918
- const pageRows = dataLines.slice(start, end);
3919
- pageRows.forEach((row, idx) => {
3920
- const tr = document.createElement("tr");
3921
- if (idx % 2 === 1) tr.style.backgroundColor = "#f8fafc";
3922
- const cells = row.split(delimiter);
3923
- cells.forEach((cell) => {
3924
- const td = document.createElement("td");
3925
- td.textContent = cell.trim();
3926
- td.style.border = "1px solid #d0d7de";
3927
- td.style.padding = "6px 12px";
3928
- td.style.whiteSpace = "nowrap";
3929
- tr.appendChild(td);
3930
- });
3931
- table.appendChild(tr);
3850
+ table.style.background = "#ffffff";
3851
+ table.style.border = "1px solid #d0d7de";
3852
+ const headerTr = document.createElement("tr");
3853
+ headerCells.forEach((cell) => {
3854
+ const th = document.createElement("th");
3855
+ th.textContent = cell.trim();
3856
+ th.style.border = "1px solid #d0d7de";
3857
+ th.style.padding = "8px 12px";
3858
+ th.style.backgroundColor = "#f6f8fa";
3859
+ th.style.fontWeight = "600";
3860
+ th.style.whiteSpace = "nowrap";
3861
+ headerTr.appendChild(th);
3862
+ });
3863
+ table.appendChild(headerTr);
3864
+ dataLines.forEach((row, idx) => {
3865
+ const tr = document.createElement("tr");
3866
+ if (idx % 2 === 1) tr.style.backgroundColor = "#f8fafc";
3867
+ const cells = row.split(delimiter);
3868
+ cells.forEach((cell) => {
3869
+ const td = document.createElement("td");
3870
+ td.textContent = cell.trim();
3871
+ td.style.border = "1px solid #d0d7de";
3872
+ td.style.padding = "6px 12px";
3873
+ td.style.whiteSpace = "nowrap";
3874
+ tr.appendChild(td);
3932
3875
  });
3933
- container.scrollTop = 0;
3934
- ctx.emit("page-change", { page: currentPage, total: totalPages });
3935
- };
3936
- renderPage(1);
3937
- container.appendChild(table);
3876
+ table.appendChild(tr);
3877
+ });
3878
+ tableWrapper.appendChild(table);
3879
+ container.appendChild(tableWrapper);
3938
3880
  ctx.container.appendChild(container);
3939
3881
  let scale = 1;
3882
+ const calculateFitScale = () => {
3883
+ const availW = Math.max(280, container.clientWidth - 48);
3884
+ const tW = table.offsetWidth || 800;
3885
+ return Math.max(0.4, Math.min(1, availW / tW));
3886
+ };
3940
3887
  const applyScale = () => {
3941
- container.style.transform = `scale(${scale})`;
3942
- container.style.transformOrigin = "top left";
3888
+ tableWrapper.style.transform = `scale(${scale})`;
3943
3889
  };
3890
+ requestAnimationFrame(() => {
3891
+ scale = calculateFitScale();
3892
+ applyScale();
3893
+ });
3894
+ const ro = new ResizeObserver(() => {
3895
+ scale = calculateFitScale();
3896
+ applyScale();
3897
+ });
3898
+ ro.observe(container);
3944
3899
  const cleanup = () => {
3900
+ ro.disconnect();
3945
3901
  container.remove();
3946
3902
  ctx.container.innerHTML = "";
3947
3903
  };
3948
3904
  ctx.signal.addEventListener("abort", cleanup);
3949
3905
  return {
3950
3906
  destroy: cleanup,
3951
- getPageCount: () => totalPages,
3952
- getCurrentPage: () => currentPage,
3953
- goToPage: (page) => renderPage(page),
3907
+ getPageCount: () => 1,
3908
+ getCurrentPage: () => 1,
3909
+ goToPage: () => {
3910
+ },
3954
3911
  getThumbnails: () => {
3955
- const thumbnails = [];
3956
- for (let i = 0; i < totalPages; i++) {
3957
- const pageIdx = i;
3958
- const startRow = pageIdx * ROWS_PER_PAGE + 1;
3959
- const endRow = Math.min(dataLines.length, (pageIdx + 1) * ROWS_PER_PAGE);
3960
- const label = totalPages === 1 ? "Table" : `Page ${pageIdx + 1} (${startRow}-${endRow})`;
3961
- thumbnails.push({
3962
- index: pageIdx,
3963
- label,
3964
- render: async (canvas) => {
3965
- canvas.width = 140;
3966
- canvas.height = 100;
3967
- const c = canvas.getContext("2d");
3968
- if (!c) return;
3969
- c.fillStyle = "#ffffff";
3970
- c.fillRect(0, 0, canvas.width, canvas.height);
3971
- c.fillStyle = "#2563eb";
3972
- c.fillRect(0, 0, canvas.width, 16);
3973
- c.fillStyle = "#ffffff";
3974
- c.font = "bold 8px sans-serif";
3975
- c.fillText(`\u{1F4C8} ${label.slice(0, 18)}`, 6, 11);
3976
- const startY = 17;
3977
- const rowH = 13;
3978
- const colW = 28;
3979
- const cols = Math.min(4, headerCells.length || 4);
3980
- c.fillStyle = "#f1f5f9";
3981
- c.fillRect(0, startY, canvas.width, rowH);
3982
- c.strokeStyle = "#cbd5e1";
3983
- c.lineWidth = 0.8;
3984
- c.strokeRect(0, startY, canvas.width, rowH);
3985
- c.fillStyle = "#64748b";
3986
- c.font = "bold 7px sans-serif";
3987
- for (let ci = 0; ci < cols; ci++) {
3988
- const hName = headerCells[ci] || `Col ${ci + 1}`;
3989
- c.fillText(hName.slice(0, 5), 8 + ci * colW, startY + 9);
3990
- }
3991
- const rowsToPreview = dataLines.slice(pageIdx * ROWS_PER_PAGE, pageIdx * ROWS_PER_PAGE + 5);
3992
- for (let ri = 0; ri < rowsToPreview.length; ri++) {
3993
- const y = startY + (ri + 1) * rowH;
3994
- if (y > canvas.height - 2) break;
3995
- c.strokeStyle = "#e2e8f0";
3996
- c.strokeRect(0, y, canvas.width, rowH);
3997
- const cVals = rowsToPreview[ri].split(delimiter);
3998
- c.fillStyle = "#334155";
3999
- c.font = "6px sans-serif";
4000
- for (let ci = 0; ci < cols; ci++) {
4001
- const val = cVals[ci] || "";
4002
- c.fillText(val.trim().slice(0, 6), 8 + ci * colW, y + 9);
3912
+ const sheetName = ctx.metadata.name?.replace(/\.[^/.]+$/, "") || "Sheet1";
3913
+ return [{
3914
+ index: 0,
3915
+ label: sheetName,
3916
+ render: async (canvas) => {
3917
+ canvas.width = 140;
3918
+ canvas.height = 100;
3919
+ const c = canvas.getContext("2d");
3920
+ if (!c) return;
3921
+ c.fillStyle = "#ffffff";
3922
+ c.fillRect(0, 0, canvas.width, canvas.height);
3923
+ c.fillStyle = "#107c41";
3924
+ c.fillRect(0, 0, canvas.width, 16);
3925
+ c.fillStyle = "#ffffff";
3926
+ c.font = 'bold 8px -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif';
3927
+ c.fillText(`\u{1F4CA} ${sheetName.slice(0, 16)}`, 6, 11);
3928
+ const startY = 17;
3929
+ const rowH = 13;
3930
+ const colW = 30;
3931
+ const cols = headerCells.slice(0, 4).map((h) => h.trim() || "Col");
3932
+ c.fillStyle = "#f1f5f9";
3933
+ c.fillRect(0, startY, canvas.width, rowH);
3934
+ c.strokeStyle = "#cbd5e1";
3935
+ c.lineWidth = 0.8;
3936
+ c.strokeRect(0, startY, canvas.width, rowH);
3937
+ c.fillStyle = "#64748b";
3938
+ c.font = "bold 7px sans-serif";
3939
+ for (let ci = 0; ci < cols.length; ci++) {
3940
+ c.fillText(cols[ci].slice(0, 5), 14 + ci * colW, startY + 9);
3941
+ }
3942
+ for (let ri = 0; ri < Math.min(5, dataLines.length); ri++) {
3943
+ const y = startY + (ri + 1) * rowH;
3944
+ if (y > canvas.height - 2) break;
3945
+ c.fillStyle = "#f8fafc";
3946
+ c.fillRect(0, y, 12, rowH);
3947
+ c.fillStyle = "#94a3b8";
3948
+ c.font = "6px sans-serif";
3949
+ c.fillText(String(ri + 1), 3, y + 9);
3950
+ c.strokeStyle = "#e2e8f0";
3951
+ c.strokeRect(0, y, canvas.width, rowH);
3952
+ const rowCells = dataLines[ri].split(delimiter);
3953
+ c.fillStyle = "#334155";
3954
+ c.font = "6px sans-serif";
3955
+ for (let ci = 0; ci < cols.length; ci++) {
3956
+ const val = (rowCells[ci] || "").trim();
3957
+ if (val) {
3958
+ c.fillText(val.slice(0, 6), 14 + ci * colW, y + 9);
4003
3959
  }
4004
3960
  }
4005
- c.strokeStyle = "#cbd5e1";
4006
- c.lineWidth = 1;
4007
- c.strokeRect(0.5, 0.5, canvas.width - 1, canvas.height - 1);
4008
3961
  }
4009
- });
4010
- }
4011
- return thumbnails;
3962
+ c.strokeStyle = "#cbd5e1";
3963
+ c.lineWidth = 1;
3964
+ c.strokeRect(0.5, 0.5, canvas.width - 1, canvas.height - 1);
3965
+ }
3966
+ }];
4012
3967
  },
4013
3968
  zoomIn: () => {
4014
3969
  scale += 0.1;
@@ -4024,11 +3979,13 @@ var CsvPlugin = class {
4024
3979
  applyScale();
4025
3980
  },
4026
3981
  fitToPage: () => {
4027
- const availW = Math.max(280, (ctx.container.clientWidth || window.innerWidth) - 48);
4028
- const tW = table.offsetWidth || 600;
4029
- scale = Math.max(0.35, Math.min(1, availW / tW));
3982
+ scale = calculateFitScale();
4030
3983
  applyScale();
4031
3984
  },
3985
+ rotateCW: () => {
3986
+ },
3987
+ rotateCCW: () => {
3988
+ },
4032
3989
  download: () => {
4033
3990
  const blob = new Blob([ctx.buffer], { type: "text/csv" });
4034
3991
  const url = URL.createObjectURL(blob);
@@ -4140,26 +4097,6 @@ var CodePlugin = class {
4140
4097
  instance.zoomIn?.();
4141
4098
  }
4142
4099
  },
4143
- {
4144
- id: "fit-page",
4145
- icon: "fit-page",
4146
- label: "Fit to View",
4147
- type: "button",
4148
- group: "zoom",
4149
- execute: () => {
4150
- instance.fitToPage?.();
4151
- }
4152
- },
4153
- {
4154
- id: "rotate-cw",
4155
- icon: "rotate-cw",
4156
- label: "Rotate",
4157
- type: "button",
4158
- group: "view",
4159
- execute: () => {
4160
- instance.rotateCW?.();
4161
- }
4162
- },
4163
4100
  {
4164
4101
  id: "copy",
4165
4102
  icon: "copy",
@@ -5303,6 +5240,148 @@ var ThreeDPlugin = class {
5303
5240
  function threeDPlugin() {
5304
5241
  return new ThreeDPlugin();
5305
5242
  }
5243
+ function cleanRtfText(raw) {
5244
+ return raw.replace(/\\bin\d+\s/g, "").replace(/{\\\*[^}]+}/g, "").replace(/\\u(-?\d+)\??/g, (_, code) => {
5245
+ let num = parseInt(code, 10);
5246
+ if (num < 0) num += 65536;
5247
+ return String.fromCharCode(num);
5248
+ }).replace(/\\'([0-9a-fA-F]{2})/g, (_, hex) => {
5249
+ return String.fromCharCode(parseInt(hex, 16));
5250
+ }).replace(/\\tab\b/g, " ").replace(/\\emdash\b/g, "\u2014").replace(/\\endash\b/g, "\u2013").replace(/\\bullet\b/g, "\u2022").replace(/\\lquote\b/g, "\u2018").replace(/\\rquote\b/g, "\u2019").replace(/\\ldblquote\b/g, "\u201C").replace(/\\rdblquote\b/g, "\u201D").replace(/\\\w+(?:-?\d+)?\s?/g, " ").replace(/[{}\r\n]/g, " ").replace(/\s+/g, " ").trim();
5251
+ }
5252
+ function parseRtfTables(rtfText) {
5253
+ const rowSegments = rtfText.split(/\\row\b/);
5254
+ if (rowSegments.length <= 1) return [];
5255
+ const rawTables = [];
5256
+ let currentTable = null;
5257
+ let charOffset = 0;
5258
+ for (let i = 0; i < rowSegments.length - 1; i++) {
5259
+ const segment = rowSegments[i];
5260
+ const segmentStart = charOffset;
5261
+ const segmentEnd = charOffset + segment.length + 4;
5262
+ const cellParts = segment.split(/\\cell\b/);
5263
+ if (cellParts.length > 1) {
5264
+ const cellxMatches = [...segment.matchAll(/\\cellx(\d+)/g)].map((m) => parseInt(m[1], 10));
5265
+ let cellWidths = [];
5266
+ if (cellxMatches.length > 0) {
5267
+ let seq = [cellxMatches[0]];
5268
+ for (let k = 1; k < cellxMatches.length; k++) {
5269
+ if (cellxMatches[k] > cellxMatches[k - 1]) seq.push(cellxMatches[k]);
5270
+ else break;
5271
+ }
5272
+ let prev = 0;
5273
+ cellWidths = seq.map((x) => {
5274
+ const w = x - prev;
5275
+ prev = x;
5276
+ return w;
5277
+ });
5278
+ }
5279
+ const cells = [];
5280
+ for (let c = 0; c < cellParts.length - 1; c++) {
5281
+ let rawCell = cellParts[c];
5282
+ if (c === 0) {
5283
+ const lastTrowd = rawCell.lastIndexOf("\\trowd");
5284
+ if (lastTrowd !== -1) rawCell = rawCell.slice(lastTrowd);
5285
+ }
5286
+ cells.push(cleanRtfText(rawCell));
5287
+ }
5288
+ const isNewTable = !currentTable || segmentStart - currentTable.lastEnd > 2500;
5289
+ if (isNewTable) {
5290
+ const prevTextSlice = rtfText.slice(Math.max(0, segmentStart - 4e3), segmentStart);
5291
+ const cleanPrev = cleanRtfText(prevTextSlice);
5292
+ const anchorBefore = cleanPrev.slice(-80).trim();
5293
+ currentTable = {
5294
+ id: `RTF_TABLE_${rawTables.length}`,
5295
+ startPos: segmentStart,
5296
+ lastEnd: segmentEnd,
5297
+ rows: [],
5298
+ columnWidths: cellWidths,
5299
+ anchorBefore,
5300
+ anchorAfter: ""
5301
+ };
5302
+ rawTables.push(currentTable);
5303
+ }
5304
+ if (currentTable) {
5305
+ currentTable.rows.push({
5306
+ cells,
5307
+ widths: cellWidths.length === cells.length ? cellWidths : currentTable.columnWidths
5308
+ });
5309
+ currentTable.lastEnd = segmentEnd;
5310
+ }
5311
+ }
5312
+ charOffset += segment.length + 4;
5313
+ }
5314
+ rawTables.forEach((tbl) => {
5315
+ const afterSlice = rtfText.slice(tbl.lastEnd, Math.min(rtfText.length, tbl.lastEnd + 2e3));
5316
+ const cleanAfter = cleanRtfText(afterSlice);
5317
+ tbl.anchorAfter = cleanAfter.slice(0, 80).trim();
5318
+ });
5319
+ return rawTables.map((tbl) => {
5320
+ const totalW = (tbl.columnWidths || []).reduce((a, b) => a + b, 0);
5321
+ const colPercents = totalW > 0 ? tbl.columnWidths.map((w) => Math.round(w / totalW * 100)) : [];
5322
+ return {
5323
+ id: tbl.id,
5324
+ rows: tbl.rows.map((r) => r.cells),
5325
+ colPercents,
5326
+ anchorBefore: tbl.anchorBefore,
5327
+ anchorAfter: tbl.anchorAfter
5328
+ };
5329
+ });
5330
+ }
5331
+ function renderRtfTableElement(table) {
5332
+ const tableEl = document.createElement("table");
5333
+ tableEl.className = "fp-rtf-table";
5334
+ tableEl.style.width = "100%";
5335
+ tableEl.style.borderCollapse = "collapse";
5336
+ tableEl.style.margin = "16px 0 20px";
5337
+ tableEl.style.fontSize = "10pt";
5338
+ tableEl.style.lineHeight = "1.5";
5339
+ tableEl.style.border = "1px solid #cbd5e1";
5340
+ tableEl.style.borderRadius = "4px";
5341
+ tableEl.style.boxSizing = "border-box";
5342
+ tableEl.style.backgroundColor = "#ffffff";
5343
+ const thead = document.createElement("thead");
5344
+ const tbody = document.createElement("tbody");
5345
+ table.rows.forEach((rowCells, rIdx) => {
5346
+ const tr = document.createElement("tr");
5347
+ const isHeader = rIdx === 0;
5348
+ if (isHeader) {
5349
+ tr.style.backgroundColor = "#f8fafc";
5350
+ tr.style.borderBottom = "2px solid #cbd5e1";
5351
+ } else {
5352
+ tr.style.borderBottom = "1px solid #e2e8f0";
5353
+ if (rIdx % 2 === 0) {
5354
+ tr.style.backgroundColor = "#fcfdfe";
5355
+ }
5356
+ }
5357
+ rowCells.forEach((cellText, cIdx) => {
5358
+ const cellEl = document.createElement(isHeader ? "th" : "td");
5359
+ cellEl.style.padding = "8px 12px";
5360
+ cellEl.style.border = "1px solid #cbd5e1";
5361
+ cellEl.style.verticalAlign = "top";
5362
+ cellEl.style.color = isHeader ? "#0f172a" : "#1e293b";
5363
+ cellEl.style.fontWeight = isHeader ? "600" : "normal";
5364
+ if (table.colPercents && table.colPercents[cIdx]) {
5365
+ cellEl.style.width = `${table.colPercents[cIdx]}%`;
5366
+ }
5367
+ if (/^\d+$/.test(cellText.trim()) || cellText.trim() === "#") {
5368
+ cellEl.style.textAlign = "center";
5369
+ } else {
5370
+ cellEl.style.textAlign = "left";
5371
+ }
5372
+ cellEl.textContent = cellText;
5373
+ tr.appendChild(cellEl);
5374
+ });
5375
+ if (isHeader) {
5376
+ thead.appendChild(tr);
5377
+ } else {
5378
+ tbody.appendChild(tr);
5379
+ }
5380
+ });
5381
+ tableEl.appendChild(thead);
5382
+ tableEl.appendChild(tbody);
5383
+ return tableEl;
5384
+ }
5306
5385
  var RtfPlugin = class {
5307
5386
  id = "rtf";
5308
5387
  name = "Rich Text Format (RTF)";
@@ -5338,6 +5417,14 @@ var RtfPlugin = class {
5338
5417
  }
5339
5418
  });
5340
5419
  actions.push(
5420
+ {
5421
+ id: "thumbnails",
5422
+ icon: "thumbnails",
5423
+ label: "Thumbnails",
5424
+ type: "button",
5425
+ group: "view",
5426
+ execute: () => instance.toggleThumbnails?.()
5427
+ },
5341
5428
  {
5342
5429
  id: "zoom-out",
5343
5430
  icon: "zoom-out",
@@ -5465,6 +5552,8 @@ var RtfPlugin = class {
5465
5552
  if (typeof RTFJS.loggingEnabled === "function") {
5466
5553
  RTFJS.loggingEnabled(false);
5467
5554
  }
5555
+ const rawText = new TextDecoder("latin1").decode(ctx.buffer);
5556
+ const tables = parseRtfTables(rawText);
5468
5557
  const doc = new RTFJS.Document(ctx.buffer, {});
5469
5558
  const htmlElements = await doc.render();
5470
5559
  const contentNodes = [];
@@ -5479,6 +5568,20 @@ var RtfPlugin = class {
5479
5568
  if (hasChildBlocks && !["table", "tr", "td", "th", "ul", "ol", "li"].includes(tag)) {
5480
5569
  extractBlocks(Array.from(item.children));
5481
5570
  } else {
5571
+ const svgs = item.querySelectorAll("svg, img");
5572
+ svgs.forEach((s) => {
5573
+ const el = s;
5574
+ el.style.maxWidth = "100%";
5575
+ el.style.maxHeight = "360px";
5576
+ el.style.display = "block";
5577
+ el.style.margin = "12px auto";
5578
+ if (s.tagName.toLowerCase() === "svg") {
5579
+ s.removeAttribute("width");
5580
+ s.removeAttribute("height");
5581
+ el.style.width = "100%";
5582
+ el.style.maxHeight = "360px";
5583
+ }
5584
+ });
5482
5585
  if (tag === "p" || tag === "div") {
5483
5586
  item.style.display = "block";
5484
5587
  item.style.marginBottom = "12px";
@@ -5489,14 +5592,46 @@ var RtfPlugin = class {
5489
5592
  }
5490
5593
  };
5491
5594
  extractBlocks(htmlElements);
5595
+ tables.forEach((table) => {
5596
+ const tableEl = renderRtfTableElement(table);
5597
+ let inserted = false;
5598
+ if (table.anchorBefore && table.anchorBefore.length > 10) {
5599
+ const keyword = table.anchorBefore.slice(-35).trim();
5600
+ for (let i = 0; i < contentNodes.length; i++) {
5601
+ if (contentNodes[i].textContent?.includes(keyword)) {
5602
+ contentNodes.splice(i + 1, 0, tableEl);
5603
+ inserted = true;
5604
+ break;
5605
+ }
5606
+ }
5607
+ }
5608
+ if (!inserted && table.anchorAfter && table.anchorAfter.length > 10) {
5609
+ const keyword = table.anchorAfter.slice(0, 35).trim();
5610
+ for (let i = 0; i < contentNodes.length; i++) {
5611
+ if (contentNodes[i].textContent?.includes(keyword)) {
5612
+ contentNodes.splice(i, 0, tableEl);
5613
+ inserted = true;
5614
+ break;
5615
+ }
5616
+ }
5617
+ }
5618
+ if (!inserted) {
5619
+ if (contentNodes.length > 2) {
5620
+ contentNodes.splice(2, 0, tableEl);
5621
+ } else {
5622
+ contentNodes.push(tableEl);
5623
+ }
5624
+ }
5625
+ });
5492
5626
  wrapper.innerHTML = "";
5493
5627
  contentNodes.forEach((node) => wrapper.appendChild(node));
5494
5628
  const childHeights = contentNodes.map((c) => {
5495
5629
  const rectH = c.getBoundingClientRect ? c.getBoundingClientRect().height : 0;
5496
5630
  const offH = c.offsetHeight || 0;
5631
+ const realH = Math.max(rectH, offH);
5632
+ if (realH > 0) return realH;
5497
5633
  const textLen = c.textContent?.trim().length || 0;
5498
- const estH = Math.max(28, Math.ceil(textLen / 75) * 24 + 16);
5499
- return Math.max(rectH, offH, estH);
5634
+ return Math.max(24, Math.ceil(textLen / 95) * 22 + 12);
5500
5635
  });
5501
5636
  wrapper.innerHTML = "";
5502
5637
  const createRtfCard = () => {
@@ -5505,7 +5640,7 @@ var RtfPlugin = class {
5505
5640
  card.style.backgroundColor = "#ffffff";
5506
5641
  card.style.boxShadow = "0 4px 24px rgba(0,0,0,0.08)";
5507
5642
  card.style.borderRadius = "4px";
5508
- card.style.padding = "72px 56px";
5643
+ card.style.padding = "64px 56px";
5509
5644
  card.style.width = "816px";
5510
5645
  card.style.minHeight = "1056px";
5511
5646
  card.style.boxSizing = "border-box";
@@ -5519,22 +5654,35 @@ var RtfPlugin = class {
5519
5654
  wrapper.appendChild(curCard);
5520
5655
  pageElements = [curCard];
5521
5656
  let curH = 0;
5522
- const maxH = 912;
5657
+ const maxH = 928;
5523
5658
  for (let i = 0; i < contentNodes.length; i++) {
5524
5659
  const child = contentNodes[i];
5525
5660
  const chH = childHeights[i];
5526
- curCard.appendChild(child);
5527
- curH += chH;
5528
- if (curH >= maxH && i < contentNodes.length - 1) {
5661
+ const isChildEmpty = (child.textContent || "").trim().length === 0 && !child.querySelector("table, img, svg, canvas");
5662
+ if (curH === 0 && isChildEmpty) {
5663
+ continue;
5664
+ }
5665
+ if (curH + chH > maxH && curCard.childNodes.length > 0) {
5529
5666
  curCard = createRtfCard();
5530
5667
  wrapper.appendChild(curCard);
5531
5668
  pageElements.push(curCard);
5532
5669
  curH = 0;
5533
5670
  }
5671
+ curCard.appendChild(child);
5672
+ curH += chH;
5673
+ }
5674
+ pageElements = pageElements.filter((card) => {
5675
+ const hasText = (card.textContent || "").trim().length > 0;
5676
+ const hasMedia = card.querySelector("table, img, svg, canvas") !== null;
5677
+ return hasText || hasMedia;
5678
+ });
5679
+ if (pageElements.length === 0) {
5680
+ pageElements = [curCard];
5534
5681
  }
5535
5682
  } catch (err) {
5536
5683
  console.warn("[RtfPlugin] RTF render error, fallback text:", err);
5537
5684
  const text = new TextDecoder("latin1").decode(ctx.buffer);
5685
+ const tables = parseRtfTables(text);
5538
5686
  const rawPages = text.split(/\\page\b/).map((segment) => {
5539
5687
  return segment.replace(/\\par[d]?/g, "\n").replace(/\\[a-zA-Z0-9\-]+/g, "").replace(/[{}]/g, "").trim();
5540
5688
  }).filter((p) => p.length > 0);
@@ -5545,7 +5693,7 @@ var RtfPlugin = class {
5545
5693
  pageCard.style.backgroundColor = "#ffffff";
5546
5694
  pageCard.style.boxShadow = "0 2px 12px rgba(0,0,0,0.08)";
5547
5695
  pageCard.style.borderRadius = "4px";
5548
- pageCard.style.padding = "72px 56px";
5696
+ pageCard.style.padding = "64px 56px";
5549
5697
  pageCard.style.width = "816px";
5550
5698
  pageCard.style.minHeight = "1056px";
5551
5699
  pageCard.style.boxSizing = "border-box";
@@ -5556,6 +5704,9 @@ var RtfPlugin = class {
5556
5704
  pageCard.style.whiteSpace = "pre-wrap";
5557
5705
  pageCard.style.display = i === 0 ? "block" : "none";
5558
5706
  pageCard.textContent = pages[i];
5707
+ if (i === 1 && tables.length > 0) {
5708
+ tables.forEach((tbl) => pageCard.appendChild(renderRtfTableElement(tbl)));
5709
+ }
5559
5710
  wrapper.appendChild(pageCard);
5560
5711
  pageElements.push(pageCard);
5561
5712
  }
@@ -5586,6 +5737,32 @@ var RtfPlugin = class {
5586
5737
  getPageCount: () => totalPages,
5587
5738
  getCurrentPage: () => currentPage,
5588
5739
  goToPage: (page) => showPage(page),
5740
+ getThumbnails: async () => {
5741
+ const items = [];
5742
+ for (let idx = 0; idx < totalPages; idx++) {
5743
+ const pageIdx = idx;
5744
+ items.push({
5745
+ index: pageIdx,
5746
+ label: `Page ${pageIdx + 1}`,
5747
+ render: async (canvas) => {
5748
+ const ctx2d = canvas.getContext("2d");
5749
+ if (!ctx2d) return;
5750
+ canvas.width = 140;
5751
+ canvas.height = 180;
5752
+ ctx2d.fillStyle = "#ffffff";
5753
+ ctx2d.fillRect(0, 0, 140, 180);
5754
+ ctx2d.strokeStyle = "#cbd5e1";
5755
+ ctx2d.lineWidth = 1;
5756
+ ctx2d.strokeRect(0.5, 0.5, 139, 179);
5757
+ ctx2d.fillStyle = "#334155";
5758
+ ctx2d.font = 'bold 11px -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif';
5759
+ ctx2d.textAlign = "center";
5760
+ ctx2d.fillText(`Page ${pageIdx + 1}`, 70, 95);
5761
+ }
5762
+ });
5763
+ }
5764
+ return items;
5765
+ },
5589
5766
  zoomIn: () => {
5590
5767
  isUserZoomed = true;
5591
5768
  scale += 0.15;
@@ -7623,6 +7800,8 @@ var FilePreview = memo(forwardRef(
7623
7800
  onError,
7624
7801
  onPageChange,
7625
7802
  onZoomChange,
7803
+ onRotate,
7804
+ onDestroy,
7626
7805
  className,
7627
7806
  style
7628
7807
  }, ref) => {
@@ -7645,6 +7824,8 @@ var FilePreview = memo(forwardRef(
7645
7824
  if (onError) unsubs.push(viewer.on("error", (e) => onError(e instanceof Error ? e : new Error(String(e)))));
7646
7825
  if (onPageChange) unsubs.push(viewer.on("page-change", onPageChange));
7647
7826
  if (onZoomChange) unsubs.push(viewer.on("zoom-change", onZoomChange));
7827
+ if (onRotate) unsubs.push(viewer.on("rotate", onRotate));
7828
+ if (onDestroy) unsubs.push(viewer.on("destroy", onDestroy));
7648
7829
  return () => {
7649
7830
  unsubs.forEach((fn) => fn());
7650
7831
  viewer.destroy();