@open-file-viewer/core 0.1.11 → 0.1.13

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.d.cts CHANGED
@@ -152,7 +152,26 @@ declare function epubPlugin(): PreviewPlugin;
152
152
 
153
153
  declare function xpsPlugin(): PreviewPlugin;
154
154
 
155
- declare function officePlugin(): PreviewPlugin;
155
+ interface OfficeConversionContext {
156
+ file: PreviewContext["file"];
157
+ arrayBuffer: ArrayBuffer;
158
+ extension: string;
159
+ detectedFormat?: "docx" | "xlsx" | "pptx";
160
+ reason: "complex-docx" | "legacy-office" | "manual";
161
+ }
162
+ type OfficeConversionResult = Blob | ArrayBuffer | string | {
163
+ blob?: Blob;
164
+ data?: Blob | ArrayBuffer;
165
+ url?: string;
166
+ fileName?: string;
167
+ mimeType?: string;
168
+ };
169
+ interface OfficePluginOptions {
170
+ convert?: (ctx: OfficeConversionContext) => Promise<OfficeConversionResult | null | undefined> | OfficeConversionResult | null | undefined;
171
+ preferConversion?: boolean | ((ctx: OfficeConversionContext) => boolean | Promise<boolean>);
172
+ pdf?: PdfPluginOptions;
173
+ }
174
+ declare function officePlugin(options?: OfficePluginOptions): PreviewPlugin;
156
175
 
157
176
  declare function ofdPlugin(): PreviewPlugin;
158
177
 
@@ -211,4 +230,4 @@ declare function assetPlugin(): PreviewPlugin;
211
230
 
212
231
  declare function fallbackPlugin(): PreviewPlugin;
213
232
 
214
- export { type CadBinaryPreviewContext, type CadPluginOptions, type FileViewer, type LibreDwgPreviewOptions, type PreviewCommand, type PreviewContext, type PreviewFallback, type PreviewFile, type PreviewFit, type PreviewInstance, type PreviewItem, type PreviewOptions, type PreviewPlugin, type PreviewSize, type PreviewSource, type PreviewTheme, type PreviewToolbarActionId, type PreviewToolbarBuiltInAction, type PreviewToolbarCustomAction, type PreviewToolbarOptions, type PreviewToolbarRenderContext, archivePlugin, assetPlugin, audioPlugin, cadPlugin, createViewer, drawingPlugin, emailPlugin, epubPlugin, fallbackPlugin, gisPlugin, imagePlugin, model3dPlugin, ofdPlugin, officePlugin, pdfPlugin, textPlugin, videoPlugin, xpsPlugin };
233
+ export { type CadBinaryPreviewContext, type CadPluginOptions, type FileViewer, type LibreDwgPreviewOptions, type OfficeConversionContext, type OfficeConversionResult, type OfficePluginOptions, type PreviewCommand, type PreviewContext, type PreviewFallback, type PreviewFile, type PreviewFit, type PreviewInstance, type PreviewItem, type PreviewOptions, type PreviewPlugin, type PreviewSize, type PreviewSource, type PreviewTheme, type PreviewToolbarActionId, type PreviewToolbarBuiltInAction, type PreviewToolbarCustomAction, type PreviewToolbarOptions, type PreviewToolbarRenderContext, archivePlugin, assetPlugin, audioPlugin, cadPlugin, createViewer, drawingPlugin, emailPlugin, epubPlugin, fallbackPlugin, gisPlugin, imagePlugin, model3dPlugin, ofdPlugin, officePlugin, pdfPlugin, textPlugin, videoPlugin, xpsPlugin };
package/dist/index.d.ts CHANGED
@@ -152,7 +152,26 @@ declare function epubPlugin(): PreviewPlugin;
152
152
 
153
153
  declare function xpsPlugin(): PreviewPlugin;
154
154
 
155
- declare function officePlugin(): PreviewPlugin;
155
+ interface OfficeConversionContext {
156
+ file: PreviewContext["file"];
157
+ arrayBuffer: ArrayBuffer;
158
+ extension: string;
159
+ detectedFormat?: "docx" | "xlsx" | "pptx";
160
+ reason: "complex-docx" | "legacy-office" | "manual";
161
+ }
162
+ type OfficeConversionResult = Blob | ArrayBuffer | string | {
163
+ blob?: Blob;
164
+ data?: Blob | ArrayBuffer;
165
+ url?: string;
166
+ fileName?: string;
167
+ mimeType?: string;
168
+ };
169
+ interface OfficePluginOptions {
170
+ convert?: (ctx: OfficeConversionContext) => Promise<OfficeConversionResult | null | undefined> | OfficeConversionResult | null | undefined;
171
+ preferConversion?: boolean | ((ctx: OfficeConversionContext) => boolean | Promise<boolean>);
172
+ pdf?: PdfPluginOptions;
173
+ }
174
+ declare function officePlugin(options?: OfficePluginOptions): PreviewPlugin;
156
175
 
157
176
  declare function ofdPlugin(): PreviewPlugin;
158
177
 
@@ -211,4 +230,4 @@ declare function assetPlugin(): PreviewPlugin;
211
230
 
212
231
  declare function fallbackPlugin(): PreviewPlugin;
213
232
 
214
- export { type CadBinaryPreviewContext, type CadPluginOptions, type FileViewer, type LibreDwgPreviewOptions, type PreviewCommand, type PreviewContext, type PreviewFallback, type PreviewFile, type PreviewFit, type PreviewInstance, type PreviewItem, type PreviewOptions, type PreviewPlugin, type PreviewSize, type PreviewSource, type PreviewTheme, type PreviewToolbarActionId, type PreviewToolbarBuiltInAction, type PreviewToolbarCustomAction, type PreviewToolbarOptions, type PreviewToolbarRenderContext, archivePlugin, assetPlugin, audioPlugin, cadPlugin, createViewer, drawingPlugin, emailPlugin, epubPlugin, fallbackPlugin, gisPlugin, imagePlugin, model3dPlugin, ofdPlugin, officePlugin, pdfPlugin, textPlugin, videoPlugin, xpsPlugin };
233
+ export { type CadBinaryPreviewContext, type CadPluginOptions, type FileViewer, type LibreDwgPreviewOptions, type OfficeConversionContext, type OfficeConversionResult, type OfficePluginOptions, type PreviewCommand, type PreviewContext, type PreviewFallback, type PreviewFile, type PreviewFit, type PreviewInstance, type PreviewItem, type PreviewOptions, type PreviewPlugin, type PreviewSize, type PreviewSource, type PreviewTheme, type PreviewToolbarActionId, type PreviewToolbarBuiltInAction, type PreviewToolbarCustomAction, type PreviewToolbarOptions, type PreviewToolbarRenderContext, archivePlugin, assetPlugin, audioPlugin, cadPlugin, createViewer, drawingPlugin, emailPlugin, epubPlugin, fallbackPlugin, gisPlugin, imagePlugin, model3dPlugin, ofdPlugin, officePlugin, pdfPlugin, textPlugin, videoPlugin, xpsPlugin };
package/dist/index.js CHANGED
@@ -682,7 +682,7 @@ function createViewer(options) {
682
682
  if (destroyed || token !== renderToken) {
683
683
  return;
684
684
  }
685
- currentInstance?.destroy();
685
+ destroyPreviewInstance(currentInstance);
686
686
  currentInstance = void 0;
687
687
  viewport.replaceChildren();
688
688
  setLoading(true);
@@ -704,7 +704,7 @@ function createViewer(options) {
704
704
  setError
705
705
  });
706
706
  if (destroyed || token !== renderToken) {
707
- nextInstance.destroy();
707
+ destroyPreviewInstance(nextInstance);
708
708
  return;
709
709
  }
710
710
  currentInstance = nextInstance;
@@ -761,7 +761,7 @@ function createViewer(options) {
761
761
  destroyed = true;
762
762
  renderToken += 1;
763
763
  resizeObserver.destroy();
764
- currentInstance?.destroy();
764
+ destroyPreviewInstance(currentInstance);
765
765
  toolbar?.destroy();
766
766
  theme.destroy();
767
767
  container.replaceChildren();
@@ -772,6 +772,16 @@ function createViewer(options) {
772
772
  }
773
773
  };
774
774
  }
775
+ function destroyPreviewInstance(instance) {
776
+ if (!instance) {
777
+ return;
778
+ }
779
+ try {
780
+ instance.destroy();
781
+ } catch (error) {
782
+ console.error("Failed to destroy file preview instance:", error);
783
+ }
784
+ }
775
785
  function normalizeQueue(options) {
776
786
  if (options.files && options.files.length > 0) {
777
787
  return options.files.map(
@@ -4575,7 +4585,7 @@ async function renderPdfDocumentPreview(options) {
4575
4585
  },
4576
4586
  destroy() {
4577
4587
  options.viewport.classList.remove("ofv-center");
4578
- documentTask?.destroy?.();
4588
+ destroyPdfResource(documentTask);
4579
4589
  if (options.revokeUrlOnDestroy) {
4580
4590
  revokeObjectUrl(options.fileUrl, Boolean(options.isExternal));
4581
4591
  }
@@ -4808,13 +4818,27 @@ async function renderPdfDocumentPreview(options) {
4808
4818
  }
4809
4819
  });
4810
4820
  pageStates.length = 0;
4811
- void pdfDocument.destroy?.();
4821
+ destroyPdfResource(pdfDocument);
4822
+ destroyPdfResource(documentTask);
4812
4823
  if (options.revokeUrlOnDestroy) {
4813
4824
  revokeObjectUrl(options.fileUrl, Boolean(options.isExternal));
4814
4825
  }
4815
4826
  }
4816
4827
  };
4817
4828
  }
4829
+ function destroyPdfResource(resource) {
4830
+ if (!resource || typeof resource !== "object") {
4831
+ return;
4832
+ }
4833
+ const candidate = resource;
4834
+ if (typeof candidate.destroy === "function") {
4835
+ void candidate.destroy();
4836
+ return;
4837
+ }
4838
+ if (typeof candidate.cleanup === "function") {
4839
+ void candidate.cleanup();
4840
+ }
4841
+ }
4818
4842
  function getPdfOutputScale() {
4819
4843
  if (typeof window === "undefined") {
4820
4844
  return 1;
@@ -5802,7 +5826,7 @@ var officeMimeFormatMap = {
5802
5826
  "application/vnd.oasis.opendocument.presentation-flat-xml": "fodp",
5803
5827
  "application/vnd.apple.keynote": "key"
5804
5828
  };
5805
- function officePlugin() {
5829
+ function officePlugin(options = {}) {
5806
5830
  return {
5807
5831
  name: "office",
5808
5832
  match(file) {
@@ -5815,7 +5839,11 @@ function officePlugin() {
5815
5839
  const arrayBuffer = await readArrayBuffer(ctx.file);
5816
5840
  const packageFormat = shouldSniffPackagedOffice(extension) ? await detectPackagedOfficeFormat(arrayBuffer) : void 0;
5817
5841
  let disposeDocxFit;
5818
- if (packageFormat === "docx" && !fileIsDocx(extension)) {
5842
+ let delegatedInstance;
5843
+ const conversionContext = await createOfficeConversionContext(ctx, arrayBuffer, extension, packageFormat);
5844
+ if (conversionContext && await shouldUseOfficeConversion(options, conversionContext)) {
5845
+ delegatedInstance = await renderConvertedOfficePreview(panel, ctx, options, conversionContext);
5846
+ } else if (packageFormat === "docx" && !fileIsDocx(extension)) {
5819
5847
  disposeDocxFit = await renderDocx(panel, arrayBuffer);
5820
5848
  } else if (packageFormat === "xlsx" && !sheetExtensions.has(extension)) {
5821
5849
  await renderSheet(panel, arrayBuffer, "xlsx");
@@ -5849,12 +5877,13 @@ function officePlugin() {
5849
5877
  ctx.toolbar?.refreshCommandSupport();
5850
5878
  return {
5851
5879
  canCommand(command) {
5852
- return controller?.canCommand(command) ?? false;
5880
+ return delegatedInstance?.canCommand?.(command) || controller?.canCommand(command) || false;
5853
5881
  },
5854
5882
  command(command) {
5855
- return controller?.command(command) ?? false;
5883
+ return delegatedInstance?.command?.(command) || controller?.command(command) || false;
5856
5884
  },
5857
5885
  destroy() {
5886
+ delegatedInstance?.destroy();
5858
5887
  controller?.destroy();
5859
5888
  disposeDocxFit?.();
5860
5889
  panel.remove();
@@ -5863,6 +5892,104 @@ function officePlugin() {
5863
5892
  }
5864
5893
  };
5865
5894
  }
5895
+ async function createOfficeConversionContext(ctx, arrayBuffer, extension, detectedFormat) {
5896
+ const effectiveFormat = detectedFormat || extension;
5897
+ if ((effectiveFormat === "docx" || fileIsDocx(extension)) && await docxShouldPreferTextboxLayoutFallback(arrayBuffer)) {
5898
+ return { file: ctx.file, arrayBuffer, extension, detectedFormat, reason: "complex-docx" };
5899
+ }
5900
+ if (isLegacyOfficeBinary(extension)) {
5901
+ return { file: ctx.file, arrayBuffer, extension, detectedFormat, reason: "legacy-office" };
5902
+ }
5903
+ return void 0;
5904
+ }
5905
+ async function shouldUseOfficeConversion(options, context) {
5906
+ if (!options.convert) {
5907
+ return false;
5908
+ }
5909
+ if (typeof options.preferConversion === "function") {
5910
+ return Boolean(await options.preferConversion(context));
5911
+ }
5912
+ if (options.preferConversion !== void 0) {
5913
+ return options.preferConversion;
5914
+ }
5915
+ return context.reason === "complex-docx" || context.reason === "legacy-office";
5916
+ }
5917
+ async function renderConvertedOfficePreview(panel, ctx, options, conversionContext) {
5918
+ if (!options.convert) {
5919
+ throw new Error("Office conversion handler is not configured.");
5920
+ }
5921
+ const converted = normalizeOfficeConversionResult(await options.convert(conversionContext), ctx.file.name);
5922
+ if (!converted) {
5923
+ throw new Error("Office conversion handler did not return a previewable file.");
5924
+ }
5925
+ if (converted.mimeType !== "application/pdf" && !converted.fileName.toLowerCase().endsWith(".pdf")) {
5926
+ throw new Error("Office conversion handler must return a PDF Blob, ArrayBuffer or URL.");
5927
+ }
5928
+ return renderPdfDocumentPreview({
5929
+ ...options.pdf || {},
5930
+ fileName: converted.fileName,
5931
+ fileUrl: converted.fileUrl,
5932
+ fileSize: converted.fileSize,
5933
+ isExternal: !converted.revokeUrlOnDestroy,
5934
+ viewport: panel,
5935
+ size: ctx.size,
5936
+ fit: ctx.options.fit,
5937
+ toolbar: ctx.toolbar,
5938
+ title: "Office \u9AD8\u4FDD\u771F\u8F6C\u6362\u9884\u89C8",
5939
+ fallbackTitle: "Office \u8F6C\u6362\u540E\u7684 PDF \u65E0\u6CD5\u9884\u89C8",
5940
+ revokeUrlOnDestroy: converted.revokeUrlOnDestroy
5941
+ });
5942
+ }
5943
+ function normalizeOfficeConversionResult(result, sourceFileName) {
5944
+ if (!result) {
5945
+ return void 0;
5946
+ }
5947
+ const fallbackFileName = `${stripFileExtension(sourceFileName) || "office-preview"}.pdf`;
5948
+ if (typeof result === "string") {
5949
+ return {
5950
+ fileName: fallbackFileName,
5951
+ fileUrl: result,
5952
+ mimeType: "application/pdf",
5953
+ revokeUrlOnDestroy: false
5954
+ };
5955
+ }
5956
+ if (result instanceof ArrayBuffer) {
5957
+ const blob = new Blob([result], { type: "application/pdf" });
5958
+ return createConvertedOfficeBlobPreview(blob, fallbackFileName);
5959
+ }
5960
+ if (result instanceof Blob) {
5961
+ return createConvertedOfficeBlobPreview(result, fallbackFileName);
5962
+ }
5963
+ if (result.url) {
5964
+ return {
5965
+ fileName: result.fileName || fallbackFileName,
5966
+ fileUrl: result.url,
5967
+ mimeType: result.mimeType || "application/pdf",
5968
+ revokeUrlOnDestroy: false
5969
+ };
5970
+ }
5971
+ const data = result.blob || result.data;
5972
+ if (data instanceof ArrayBuffer) {
5973
+ const blob = new Blob([data], { type: result.mimeType || "application/pdf" });
5974
+ return createConvertedOfficeBlobPreview(blob, result.fileName || fallbackFileName);
5975
+ }
5976
+ if (data instanceof Blob) {
5977
+ return createConvertedOfficeBlobPreview(data, result.fileName || fallbackFileName);
5978
+ }
5979
+ return void 0;
5980
+ }
5981
+ function createConvertedOfficeBlobPreview(blob, fileName) {
5982
+ return {
5983
+ fileName,
5984
+ fileUrl: URL.createObjectURL(blob),
5985
+ fileSize: blob.size,
5986
+ mimeType: blob.type || "application/pdf",
5987
+ revokeUrlOnDestroy: true
5988
+ };
5989
+ }
5990
+ function stripFileExtension(fileName) {
5991
+ return fileName.replace(/\.[^.]+$/, "");
5992
+ }
5866
5993
  function createOfficeZoomController(panel, ctx) {
5867
5994
  const canZoom = Boolean(
5868
5995
  panel.querySelector(".ofv-docx-document, .ofv-sheet, .ofv-pptx-viewer > div, .ofv-document, .ofv-text-block, .ofv-slide")
@@ -5959,7 +6086,7 @@ async function renderDocx(panel, arrayBuffer) {
5959
6086
  useBase64URL: true
5960
6087
  });
5961
6088
  await normalizeDocxLayout(content, arrayBuffer);
5962
- const shouldUseTextboxFallback = await docxPreviewLooksBlank(content, arrayBuffer) || await docxPreviewMissesRichTextboxContent(content, arrayBuffer);
6089
+ const shouldUseTextboxFallback = await docxPreviewLooksBlank(content, arrayBuffer) || await docxPreviewMissesRichTextboxContent(content, arrayBuffer) || await docxShouldPreferTextboxLayoutFallback(arrayBuffer);
5963
6090
  if (shouldUseTextboxFallback) {
5964
6091
  disposeFit?.();
5965
6092
  styleContainer.remove();
@@ -6042,6 +6169,27 @@ async function docxHasRichTextboxContent(arrayBuffer) {
6042
6169
  return false;
6043
6170
  }
6044
6171
  }
6172
+ async function docxShouldPreferTextboxLayoutFallback(arrayBuffer) {
6173
+ try {
6174
+ const zip = await JSZip3.loadAsync(arrayBuffer);
6175
+ const documentXml = await zip.file("word/document.xml")?.async("text");
6176
+ if (!documentXml || !/\btxbxContent\b/.test(documentXml)) {
6177
+ return false;
6178
+ }
6179
+ const blocks = extractDocxTextboxBlocks(documentXml);
6180
+ const meaningfulBlocks = blocks.filter((block) => block.paragraphs.length > 0);
6181
+ const sidebarBackgrounds = blocks.filter(
6182
+ (block) => block.paragraphs.length === 0 && block.fill && block.relativeV === "page" && block.x < 0 && block.width >= 120 && block.height >= 500
6183
+ );
6184
+ const pageAnchoredTextboxes = meaningfulBlocks.filter((block) => block.relativeV === "page");
6185
+ const paragraphAnchoredTextboxes = meaningfulBlocks.filter((block) => block.relativeV !== "page");
6186
+ const leftTextboxes = meaningfulBlocks.filter((block) => block.x < 0);
6187
+ const rightTextboxes = meaningfulBlocks.filter((block) => block.x >= 80);
6188
+ return sidebarBackgrounds.length >= 2 && meaningfulBlocks.length >= 8 && pageAnchoredTextboxes.length >= 4 && paragraphAnchoredTextboxes.length >= 2 && leftTextboxes.length >= 3 && rightTextboxes.length >= 3;
6189
+ } catch {
6190
+ return false;
6191
+ }
6192
+ }
6045
6193
  async function renderDocxContentFallback(container, arrayBuffer, options = {}) {
6046
6194
  if (options.showNote !== false) {
6047
6195
  const fallbackNote = document.createElement("div");
@@ -6493,6 +6641,10 @@ function createDocxTextboxBlockElement(block) {
6493
6641
  const paragraphs = normalizeDocxTextboxParagraphOrder(block);
6494
6642
  const [first, ...rest] = paragraphs;
6495
6643
  if (first) {
6644
+ const sectionKind = getDocxTextboxSectionKind(first);
6645
+ if (sectionKind) {
6646
+ section.classList.add(`ofv-docx-textbox-section-${sectionKind}`);
6647
+ }
6496
6648
  const heading = document.createElement("h3");
6497
6649
  heading.textContent = first;
6498
6650
  section.append(heading);
@@ -6505,6 +6657,28 @@ function createDocxTextboxBlockElement(block) {
6505
6657
  }
6506
6658
  return section;
6507
6659
  }
6660
+ function getDocxTextboxSectionKind(heading) {
6661
+ const text = normalizePreviewText(heading);
6662
+ if (text.includes("\u6559\u80B2\u80CC\u666F")) {
6663
+ return "education";
6664
+ }
6665
+ if (text.includes("\u4E13\u4E1A\u6280\u80FD")) {
6666
+ return "skills";
6667
+ }
6668
+ if (text.includes("\u5DE5\u4F5C\u7ECF\u5386")) {
6669
+ return "work";
6670
+ }
6671
+ if (text.includes("\u9879\u76EE\u7ECF\u9A8C")) {
6672
+ return "projects";
6673
+ }
6674
+ if (text.includes("\u81EA\u6211\u8BC4\u4EF7")) {
6675
+ return "summary";
6676
+ }
6677
+ if (text.includes("\u57FA\u672C\u4FE1\u606F")) {
6678
+ return "profile";
6679
+ }
6680
+ return "";
6681
+ }
6508
6682
  function estimateDocxTextboxBlockHeight(block) {
6509
6683
  return Math.max(block.height, 18 + block.paragraphs.length * 14);
6510
6684
  }
@@ -6548,14 +6722,58 @@ function repairDocxHeadingShapeAlignment(page) {
6548
6722
  if (!svg) {
6549
6723
  continue;
6550
6724
  }
6551
- const width = parseCssPixelValue(svg.getAttribute("width") || svg.style.width);
6725
+ const width = parseCssPixelValue(svg.style.width) || parseCssPixelValue(svg.getAttribute("width") || "");
6552
6726
  const marginLeft = parseCssPixelValue(svg.style.marginLeft);
6553
6727
  if (width < 300 || marginLeft < 28 || marginLeft > 44) {
6554
6728
  continue;
6555
6729
  }
6556
- svg.style.marginLeft = "48px";
6730
+ const textWidth = getDocxParagraphVisibleTextWidth(paragraph);
6731
+ svg.style.marginLeft = `${formatCssNumber(Math.max(48, marginLeft + textWidth * 0.68))}pt`;
6732
+ svg.style.marginTop = `${formatCssNumber(parseCssPixelValue(svg.style.marginTop) - 4)}pt`;
6733
+ normalizeDocxHeadingShapeFill(svg);
6734
+ repairDocxHeadingTextBackground(paragraph);
6557
6735
  }
6558
6736
  }
6737
+ function normalizeDocxHeadingShapeFill(svg) {
6738
+ const headingFill = "#3f4aa3";
6739
+ const fillNodes = svg.querySelectorAll("image[fill], rect[data-ofv-docx-shape-fill]");
6740
+ for (const node of fillNodes) {
6741
+ const fill = node.getAttribute("fill") || "";
6742
+ if (fill.toLowerCase() === "#38449a") {
6743
+ node.setAttribute("fill", headingFill);
6744
+ }
6745
+ }
6746
+ }
6747
+ function repairDocxHeadingTextBackground(paragraph) {
6748
+ const textSpans = Array.from(paragraph.querySelectorAll("span")).filter(
6749
+ (element) => normalizePreviewText(element.textContent || "")
6750
+ );
6751
+ const lastTextSpan = textSpans.at(-1);
6752
+ if (!lastTextSpan || !hasWhiteBackground(lastTextSpan)) {
6753
+ return;
6754
+ }
6755
+ lastTextSpan.style.paddingRight = "3pt";
6756
+ lastTextSpan.style.paddingTop = "2pt";
6757
+ lastTextSpan.style.paddingBottom = "2pt";
6758
+ lastTextSpan.style.boxDecorationBreak = "clone";
6759
+ }
6760
+ function hasWhiteBackground(element) {
6761
+ const background = element.style.backgroundColor.replace(/\s+/g, "").toLowerCase();
6762
+ return background === "white" || background === "#fff" || background === "#ffffff" || background === "rgb(255,255,255)";
6763
+ }
6764
+ function getDocxParagraphVisibleTextWidth(paragraph) {
6765
+ let textWidth = 0;
6766
+ for (const element of paragraph.querySelectorAll("span")) {
6767
+ if (!normalizePreviewText(element.textContent || "")) {
6768
+ continue;
6769
+ }
6770
+ textWidth += pxToPt(element.getBoundingClientRect().width);
6771
+ }
6772
+ return textWidth;
6773
+ }
6774
+ function pxToPt(value) {
6775
+ return value * 0.75;
6776
+ }
6559
6777
  function repairDocxListIndentAlignment(page) {
6560
6778
  for (const paragraph of page.querySelectorAll("p[class*='ofv-docx-num-']")) {
6561
6779
  const text = normalizePreviewText(paragraph.textContent || "");