@extend-ai/react-docx 0.7.0-alpha.8 → 0.7.1

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.cjs CHANGED
@@ -549,7 +549,13 @@ async function defaultWasmSource() {
549
549
  const fs = await nodeFsPromises();
550
550
  return fs.readFile(wasmUrl);
551
551
  }
552
- return wasmUrl;
552
+ const response = await fetch(wasmUrl);
553
+ if (!response.ok) {
554
+ throw new Error(
555
+ `react-docx: failed to load the bundled WebAssembly binary from ${wasmUrl.href} (${response.status} ${response.statusText}). If your bundler did not emit this asset, import @extend-ai/react-docx/docx_wasm_bg.wasm?url and pass it to setWasmSource() before importing a document.`
556
+ );
557
+ }
558
+ return response;
553
559
  }
554
560
  async function initWasm(source) {
555
561
  if (!initPromise) {
@@ -1185,7 +1191,7 @@ __export(index_exports, {
1185
1191
  defaultStarterModel: () => defaultStarterModel,
1186
1192
  duplicateParagraph: () => duplicateParagraph,
1187
1193
  getPart: () => getPart,
1188
- initWasm: () => initWasm,
1194
+ initWasm: () => initWasm2,
1189
1195
  insertParagraph: () => insertParagraph,
1190
1196
  layoutDocument: () => layoutDocument,
1191
1197
  modelToDocumentXml: () => modelToDocumentXml,
@@ -1227,7 +1233,7 @@ __export(index_exports, {
1227
1233
  setParagraphHeading: () => setParagraphHeading,
1228
1234
  setRunColor: () => setRunColor,
1229
1235
  setRunHighlight: () => setRunHighlight,
1230
- setWasmSource: () => setWasmSource,
1236
+ setWasmSource: () => setWasmSource2,
1231
1237
  splitParagraphChildrenAtTextOffsets: () => splitParagraphChildrenAtTextOffsets,
1232
1238
  toggleRunStyleFlag: () => toggleRunStyleFlag,
1233
1239
  updateParagraphText: () => updateParagraphText,
@@ -1479,6 +1485,60 @@ function layoutDocument(model, options = {}) {
1479
1485
 
1480
1486
  // src/docx-import.ts
1481
1487
  init_cjs_shims();
1488
+
1489
+ // src/wasm-source.ts
1490
+ init_cjs_shims();
1491
+ init_src();
1492
+ var hasConfiguredWasmSource = false;
1493
+ var configuredWorkerWasmSource;
1494
+ function bufferSourceToArrayBuffer(source) {
1495
+ if (source instanceof ArrayBuffer) {
1496
+ return source.slice(0);
1497
+ }
1498
+ const bytes = new Uint8Array(source.buffer, source.byteOffset, source.byteLength);
1499
+ const copy = new Uint8Array(bytes);
1500
+ return copy.buffer;
1501
+ }
1502
+ function sourceToWorkerSource(source) {
1503
+ if (typeof source === "string") {
1504
+ return source;
1505
+ }
1506
+ if (typeof URL !== "undefined" && source instanceof URL) {
1507
+ return source.href;
1508
+ }
1509
+ if (source instanceof ArrayBuffer || ArrayBuffer.isView(source)) {
1510
+ return bufferSourceToArrayBuffer(source);
1511
+ }
1512
+ if (typeof WebAssembly !== "undefined" && source instanceof WebAssembly.Module) {
1513
+ return source;
1514
+ }
1515
+ if (typeof Request !== "undefined" && source instanceof Request) {
1516
+ return source.url;
1517
+ }
1518
+ return void 0;
1519
+ }
1520
+ function rememberWorkerWasmSource(source) {
1521
+ hasConfiguredWasmSource = true;
1522
+ configuredWorkerWasmSource = sourceToWorkerSource(source);
1523
+ }
1524
+ function setWasmSource2(source) {
1525
+ setWasmSource(source);
1526
+ rememberWorkerWasmSource(source);
1527
+ }
1528
+ function initWasm2(source) {
1529
+ if (source !== void 0) {
1530
+ rememberWorkerWasmSource(source);
1531
+ }
1532
+ return initWasm(source);
1533
+ }
1534
+ function canUseConfiguredWasmSourceInWorker() {
1535
+ return !hasConfiguredWasmSource || configuredWorkerWasmSource !== void 0;
1536
+ }
1537
+ function getConfiguredWorkerWasmSource() {
1538
+ return configuredWorkerWasmSource;
1539
+ }
1540
+
1541
+ // src/docx-import.ts
1482
1542
  var nextImportWorkerRequestId = 1;
1483
1543
  function createAbortError() {
1484
1544
  if (typeof DOMException !== "undefined") {
@@ -1497,7 +1557,7 @@ function errorFromWorkerResponse(response) {
1497
1557
  return error;
1498
1558
  }
1499
1559
  function canUseDocxImportWorker(options) {
1500
- return options.useWorker !== false && typeof Worker !== "undefined";
1560
+ return options.useWorker !== false && typeof Worker !== "undefined" && canUseConfiguredWasmSourceInWorker();
1501
1561
  }
1502
1562
  function createDocxImportWorker() {
1503
1563
  return new Worker(new URL("./docx-import-worker.js", importMetaUrl), {
@@ -1606,7 +1666,8 @@ async function importDocxBuffer(buffer, options = {}) {
1606
1666
  const request = {
1607
1667
  id: requestId,
1608
1668
  type: "import-docx",
1609
- buffer
1669
+ buffer,
1670
+ wasmSource: getConfiguredWorkerWasmSource()
1610
1671
  };
1611
1672
  const transfer = options.transferBuffer ? [buffer] : [];
1612
1673
  worker.postMessage(request, transfer);
@@ -1668,6 +1729,18 @@ function readStringAttribute(tagXml, attribute) {
1668
1729
  }
1669
1730
  return tagXml.match(new RegExp(`${attribute}="([^"]+)"`, "i"))?.[1];
1670
1731
  }
1732
+ function resolvePageSizeForOrientation(params) {
1733
+ const normalizedOrientation = params.orientation?.trim().toLowerCase();
1734
+ const widthPx = Math.max(1, params.widthPx);
1735
+ const heightPx = Math.max(1, params.heightPx);
1736
+ if (normalizedOrientation === "landscape" && widthPx < heightPx) {
1737
+ return { widthPx: heightPx, heightPx: widthPx };
1738
+ }
1739
+ if (normalizedOrientation === "portrait" && widthPx > heightPx) {
1740
+ return { widthPx: heightPx, heightPx: widthPx };
1741
+ }
1742
+ return { widthPx, heightPx };
1743
+ }
1671
1744
  function normalizeHexColor(value) {
1672
1745
  if (!value) {
1673
1746
  return void 0;
@@ -1753,8 +1826,13 @@ function parseSectionLayout(sectionPropertiesXml) {
1753
1826
  const pageSizeTag = sectionPropertiesXml.match(/<w:pgSz\b[^>]*>/i)?.[0];
1754
1827
  const pageMarginTag = sectionPropertiesXml.match(/<w:pgMar\b[^>]*>/i)?.[0];
1755
1828
  const docGridTag = sectionPropertiesXml.match(/<w:docGrid\b[^>]*\/?>/i)?.[0];
1756
- const pageWidthPx = twipsToPixels(readTwipsAttribute(pageSizeTag, "w:w")) ?? DEFAULT_DOCUMENT_LAYOUT.pageWidthPx;
1757
- const pageHeightPx = twipsToPixels(readTwipsAttribute(pageSizeTag, "w:h")) ?? DEFAULT_DOCUMENT_LAYOUT.pageHeightPx;
1829
+ const rawPageWidthPx = twipsToPixels(readTwipsAttribute(pageSizeTag, "w:w")) ?? DEFAULT_DOCUMENT_LAYOUT.pageWidthPx;
1830
+ const rawPageHeightPx = twipsToPixels(readTwipsAttribute(pageSizeTag, "w:h")) ?? DEFAULT_DOCUMENT_LAYOUT.pageHeightPx;
1831
+ const pageSize = resolvePageSizeForOrientation({
1832
+ widthPx: rawPageWidthPx,
1833
+ heightPx: rawPageHeightPx,
1834
+ orientation: readStringAttribute(pageSizeTag, "w:orient")
1835
+ });
1758
1836
  const topMarginPx = twipsToPixels(readTwipsAttribute(pageMarginTag, "w:top")) ?? DEFAULT_DOCUMENT_LAYOUT.marginsPx.top;
1759
1837
  const rightMarginPx = twipsToPixels(readTwipsAttribute(pageMarginTag, "w:right")) ?? DEFAULT_DOCUMENT_LAYOUT.marginsPx.right;
1760
1838
  const bottomMarginPx = twipsToPixels(readTwipsAttribute(pageMarginTag, "w:bottom")) ?? DEFAULT_DOCUMENT_LAYOUT.marginsPx.bottom;
@@ -1764,8 +1842,8 @@ function parseSectionLayout(sectionPropertiesXml) {
1764
1842
  const docGridType = readStringAttribute(docGridTag, "w:type")?.toLowerCase();
1765
1843
  const docGridLinePitchPx = docGridType === "lines" || docGridType === "linesandchars" || docGridType === "snaptochars" ? twipsToPixels(readTwipsAttribute(docGridTag, "w:linePitch")) ?? DEFAULT_DOCUMENT_LAYOUT.docGridLinePitchPx : DEFAULT_DOCUMENT_LAYOUT.docGridLinePitchPx;
1766
1844
  return {
1767
- pageWidthPx,
1768
- pageHeightPx,
1845
+ pageWidthPx: pageSize.widthPx,
1846
+ pageHeightPx: pageSize.heightPx,
1769
1847
  marginsPx: {
1770
1848
  top: topMarginPx,
1771
1849
  right: rightMarginPx,
@@ -4474,6 +4552,26 @@ function getDownscaledThumbnailImageDataUri(src) {
4474
4552
  downscaledThumbnailImageCache.set(src, pending);
4475
4553
  return pending;
4476
4554
  }
4555
+ var THUMBNAIL_DECODED_IMAGE_CACHE_MAX_ENTRIES = 48;
4556
+ var decodedThumbnailImageCache = /* @__PURE__ */ new Map();
4557
+ function getDecodedThumbnailImage(src) {
4558
+ const cached = decodedThumbnailImageCache.get(src);
4559
+ if (cached) {
4560
+ decodedThumbnailImageCache.delete(src);
4561
+ decodedThumbnailImageCache.set(src, cached);
4562
+ return cached;
4563
+ }
4564
+ const pending = loadThumbnailImage(src).catch(() => void 0);
4565
+ decodedThumbnailImageCache.set(src, pending);
4566
+ while (decodedThumbnailImageCache.size > THUMBNAIL_DECODED_IMAGE_CACHE_MAX_ENTRIES) {
4567
+ const oldestKey = decodedThumbnailImageCache.keys().next().value;
4568
+ if (oldestKey === void 0) {
4569
+ break;
4570
+ }
4571
+ decodedThumbnailImageCache.delete(oldestKey);
4572
+ }
4573
+ return pending;
4574
+ }
4477
4575
  function directThumbnailPositivePx(value, fallback = 1) {
4478
4576
  return Number.isFinite(value) && value > 0 ? Math.max(1, Number(value)) : fallback;
4479
4577
  }
@@ -4729,6 +4827,32 @@ function drawDirectThumbnailImagePlaceholder(context, image, hairlineSourcePx) {
4729
4827
  context.lineWidth = hairlineSourcePx;
4730
4828
  context.strokeRect(xPx, yPx, widthPx, heightPx);
4731
4829
  }
4830
+ function drawDirectThumbnailImage(context, image, decoded, hairlineSourcePx) {
4831
+ const xPx = Math.round(image.xPx);
4832
+ const yPx = Math.round(image.yPx);
4833
+ const widthPx = Math.max(1, Math.round(image.widthPx));
4834
+ const heightPx = Math.max(1, Math.round(image.heightPx));
4835
+ if (decoded && decoded.naturalWidth > 0 && decoded.naturalHeight > 0) {
4836
+ try {
4837
+ context.drawImage(decoded, xPx, yPx, widthPx, heightPx);
4838
+ return;
4839
+ } catch {
4840
+ }
4841
+ }
4842
+ setCanvasFillStyle(
4843
+ context,
4844
+ image.backgroundColor,
4845
+ THUMBNAIL_DIRECT_IMAGE_BACKGROUND
4846
+ );
4847
+ context.fillRect(xPx, yPx, widthPx, heightPx);
4848
+ setCanvasStrokeStyle(
4849
+ context,
4850
+ image.borderColor,
4851
+ THUMBNAIL_DIRECT_TABLE_BORDER_COLOR
4852
+ );
4853
+ context.lineWidth = hairlineSourcePx;
4854
+ context.strokeRect(xPx, yPx, widthPx, heightPx);
4855
+ }
4732
4856
  function drawDirectThumbnailTable(context, table, hairlineSourcePx) {
4733
4857
  const tableXPx = Math.round(table.xPx);
4734
4858
  const tableYPx = Math.round(table.yPx);
@@ -4768,7 +4892,7 @@ function drawDirectThumbnailTable(context, table, hairlineSourcePx) {
4768
4892
  });
4769
4893
  context.restore();
4770
4894
  }
4771
- function renderDocxThumbnailSnapshotSurface(params) {
4895
+ async function renderDocxThumbnailSnapshotSurface(params) {
4772
4896
  if (typeof document === "undefined") {
4773
4897
  throw new Error("DOCX thumbnails require a browser environment.");
4774
4898
  }
@@ -4783,6 +4907,21 @@ function renderDocxThumbnailSnapshotSurface(params) {
4783
4907
  if (!context) {
4784
4908
  throw new Error("2D canvas context is unavailable for DOCX thumbnails.");
4785
4909
  }
4910
+ const elements = params.snapshot.elements.slice(0, THUMBNAIL_DIRECT_MAX_ELEMENTS);
4911
+ const decodedImagesBySrc = /* @__PURE__ */ new Map();
4912
+ const imageSrcs = /* @__PURE__ */ new Set();
4913
+ for (const element of elements) {
4914
+ if (element.kind === "image" && element.src) {
4915
+ imageSrcs.add(element.src);
4916
+ }
4917
+ }
4918
+ if (imageSrcs.size > 0) {
4919
+ await Promise.all(
4920
+ Array.from(imageSrcs, async (src) => {
4921
+ decodedImagesBySrc.set(src, await getDecodedThumbnailImage(src));
4922
+ })
4923
+ );
4924
+ }
4786
4925
  const scaleX = pixelWidthPx / sourceWidthPx;
4787
4926
  const scaleY = pixelHeightPx / sourceHeightPx;
4788
4927
  const hairlineSourcePx = Math.max(0.75, 1 / Math.max(scaleX, scaleY));
@@ -4795,7 +4934,7 @@ function renderDocxThumbnailSnapshotSurface(params) {
4795
4934
  "#ffffff"
4796
4935
  );
4797
4936
  context.fillRect(0, 0, sourceWidthPx, sourceHeightPx);
4798
- params.snapshot.elements.slice(0, THUMBNAIL_DIRECT_MAX_ELEMENTS).forEach((element) => {
4937
+ elements.forEach((element) => {
4799
4938
  switch (element.kind) {
4800
4939
  case "paragraph":
4801
4940
  drawDirectThumbnailParagraph(context, element);
@@ -4807,6 +4946,14 @@ function renderDocxThumbnailSnapshotSurface(params) {
4807
4946
  hairlineSourcePx
4808
4947
  );
4809
4948
  break;
4949
+ case "image":
4950
+ drawDirectThumbnailImage(
4951
+ context,
4952
+ element,
4953
+ decodedImagesBySrc.get(element.src),
4954
+ hairlineSourcePx
4955
+ );
4956
+ break;
4810
4957
  case "table":
4811
4958
  drawDirectThumbnailTable(context, element, hairlineSourcePx);
4812
4959
  break;
@@ -24263,7 +24410,7 @@ function docxThumbnailTextRunsFromParagraph(paragraph, documentTheme, maxChars =
24263
24410
  return;
24264
24411
  }
24265
24412
  const style = child.type === "text" || child.type === "form-field" ? child.style : void 0;
24266
- const text = child.type === "text" ? child.text : child.type === "form-field" ? formFieldDisplayValue2(child) : child.type === "image" ? child.alt || "[image]" : "";
24413
+ const text = child.type === "text" ? child.text : child.type === "form-field" ? formFieldDisplayValue2(child) : "";
24267
24414
  appendDocxThumbnailTextRun(
24268
24415
  runs,
24269
24416
  {
@@ -24354,13 +24501,29 @@ function buildDocxThumbnailParagraphElements(params) {
24354
24501
  (widthPx - 4) / imageWidthPx,
24355
24502
  (bodyHeightPx - 4) / imageHeightPx
24356
24503
  );
24357
- elements.push({
24358
- kind: "image-placeholder",
24359
- xPx: xPx + 2,
24360
- yPx: bodyYPx + 2,
24361
- widthPx: Math.max(12, imageWidthPx * scale),
24362
- heightPx: Math.max(12, imageHeightPx * scale)
24363
- });
24504
+ const elementXPx = xPx + 2;
24505
+ const elementYPx = bodyYPx + 2;
24506
+ const elementWidthPx = Math.max(12, imageWidthPx * scale);
24507
+ const elementHeightPx = Math.max(12, imageHeightPx * scale);
24508
+ const renderableSrc = resolveRenderableImageSource(imageRun);
24509
+ if (renderableSrc) {
24510
+ elements.push({
24511
+ kind: "image",
24512
+ xPx: elementXPx,
24513
+ yPx: elementYPx,
24514
+ widthPx: elementWidthPx,
24515
+ heightPx: elementHeightPx,
24516
+ src: renderableSrc
24517
+ });
24518
+ } else {
24519
+ elements.push({
24520
+ kind: "image-placeholder",
24521
+ xPx: elementXPx,
24522
+ yPx: elementYPx,
24523
+ widthPx: elementWidthPx,
24524
+ heightPx: elementHeightPx
24525
+ });
24526
+ }
24364
24527
  });
24365
24528
  }
24366
24529
  return elements;
@@ -24459,6 +24622,24 @@ function buildDocxThumbnailTableElement(params) {
24459
24622
  cells
24460
24623
  };
24461
24624
  }
24625
+ function docxThumbnailNodeRequiresDomRaster(node) {
24626
+ if (!node) {
24627
+ return false;
24628
+ }
24629
+ if (node.type === "paragraph") {
24630
+ return node.children.some((child) => child.type === "image");
24631
+ }
24632
+ return node.rows.some(
24633
+ (row) => row.cells.some(
24634
+ (cell) => cell.nodes.some((cellNode) => docxThumbnailNodeRequiresDomRaster(cellNode))
24635
+ )
24636
+ );
24637
+ }
24638
+ function docxThumbnailPageRequiresDomRaster(model, pageSegments) {
24639
+ return pageSegments.some(
24640
+ (segment) => docxThumbnailNodeRequiresDomRaster(model.nodes[segment.nodeIndex])
24641
+ );
24642
+ }
24462
24643
  function buildDocxPageThumbnailRenderSnapshotEntries(params) {
24463
24644
  const {
24464
24645
  model,
@@ -24471,6 +24652,9 @@ function buildDocxPageThumbnailRenderSnapshotEntries(params) {
24471
24652
  numberingDefinitions
24472
24653
  } = params;
24473
24654
  return pageNodeSegmentsByPage.map((pageSegments, pageIndex) => {
24655
+ if (docxThumbnailPageRequiresDomRaster(model, pageSegments)) {
24656
+ return void 0;
24657
+ }
24474
24658
  const key = `${contentKeysByPage[pageIndex] ?? ""}|theme:${documentTheme}`;
24475
24659
  let cachedSnapshot;
24476
24660
  return {
@@ -24917,7 +25101,7 @@ function useDocxPageThumbnails(editor, options = {}) {
24917
25101
  if (!surface) {
24918
25102
  const thumbnailSnapshot = thumbnailSnapshotEntry?.getSnapshot();
24919
25103
  if (thumbnailSnapshot) {
24920
- surface = renderDocxThumbnailSnapshotSurface({
25104
+ surface = await renderDocxThumbnailSnapshotSurface({
24921
25105
  snapshot: thumbnailSnapshot,
24922
25106
  widthPx: resolution.widthPx,
24923
25107
  heightPx: resolution.heightPx,
@@ -45732,7 +45916,6 @@ function buildLayoutSnapshot(model, options = {}) {
45732
45916
  }
45733
45917
 
45734
45918
  // src/index.tsx
45735
- init_src();
45736
45919
  var import_jsx_runtime2 = require("react/jsx-runtime");
45737
45920
  var HIGHLIGHT_TO_CSS2 = {
45738
45921
  yellow: "#fff59d",