@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.d.cts CHANGED
@@ -20,13 +20,7 @@ interface InitOutput {
20
20
  }
21
21
 
22
22
  type WasmSource = InitInput;
23
- /**
24
- * Override where the `docx_wasm_bg.wasm` binary is loaded from (URL, Response,
25
- * bytes, or a compiled module). Must be called before the first operation that
26
- * touches WASM; by default the binary shipped alongside this package is used.
27
- */
28
- declare function setWasmSource(source: WasmSource): void;
29
- declare function initWasm(source?: WasmSource): Promise<InitOutput>;
23
+ declare function initWasm$1(source?: WasmSource): Promise<InitOutput>;
30
24
  interface WasmOoxmlPart {
31
25
  name: string;
32
26
  content: string;
@@ -1690,6 +1684,9 @@ declare function modelToDocumentXml(model: DocModel, basePackage?: OoxmlPackage)
1690
1684
  declare function serializeDocModel(model: DocModel, basePackage?: OoxmlPackage): Promise<OoxmlPackage>;
1691
1685
  declare function serializeDocx(model: DocModel, basePackage?: OoxmlPackage): Promise<ArrayBuffer>;
1692
1686
 
1687
+ declare function setWasmSource(source: WasmSource): void;
1688
+ declare function initWasm(source?: WasmSource): ReturnType<typeof initWasm$1>;
1689
+
1693
1690
  interface ReactDocxViewerProps {
1694
1691
  /**
1695
1692
  * Raw `.docx` file contents to parse and render.
package/dist/index.d.ts CHANGED
@@ -20,13 +20,7 @@ interface InitOutput {
20
20
  }
21
21
 
22
22
  type WasmSource = InitInput;
23
- /**
24
- * Override where the `docx_wasm_bg.wasm` binary is loaded from (URL, Response,
25
- * bytes, or a compiled module). Must be called before the first operation that
26
- * touches WASM; by default the binary shipped alongside this package is used.
27
- */
28
- declare function setWasmSource(source: WasmSource): void;
29
- declare function initWasm(source?: WasmSource): Promise<InitOutput>;
23
+ declare function initWasm$1(source?: WasmSource): Promise<InitOutput>;
30
24
  interface WasmOoxmlPart {
31
25
  name: string;
32
26
  content: string;
@@ -1690,6 +1684,9 @@ declare function modelToDocumentXml(model: DocModel, basePackage?: OoxmlPackage)
1690
1684
  declare function serializeDocModel(model: DocModel, basePackage?: OoxmlPackage): Promise<OoxmlPackage>;
1691
1685
  declare function serializeDocx(model: DocModel, basePackage?: OoxmlPackage): Promise<ArrayBuffer>;
1692
1686
 
1687
+ declare function setWasmSource(source: WasmSource): void;
1688
+ declare function initWasm(source?: WasmSource): ReturnType<typeof initWasm$1>;
1689
+
1693
1690
  interface ReactDocxViewerProps {
1694
1691
  /**
1695
1692
  * Raw `.docx` file contents to parse and render.
package/dist/index.js CHANGED
@@ -4,20 +4,20 @@ import {
4
4
  packageToArrayBuffer,
5
5
  parseDocx,
6
6
  withPart
7
- } from "./chunk-QOXSE6WY.js";
7
+ } from "./chunk-XBI2PYTU.js";
8
8
  import {
9
9
  buildDocModel,
10
10
  buildDocModelFromBytes,
11
11
  cloneDocModel,
12
12
  normalizeDocModel
13
- } from "./chunk-P3B3Q7Y6.js";
13
+ } from "./chunk-P3MKA55V.js";
14
14
  import {
15
15
  initWasm,
16
16
  mapsToWasmPackage,
17
17
  setWasmSource,
18
18
  wasmModelToDocumentXml,
19
19
  wasmSerializeDocx
20
- } from "./chunk-2SXGXGWO.js";
20
+ } from "./chunk-WKBPLHUA.js";
21
21
 
22
22
  // src/index.tsx
23
23
  import * as React2 from "react";
@@ -244,6 +244,56 @@ function layoutDocument(model, options = {}) {
244
244
  return pages;
245
245
  }
246
246
 
247
+ // src/wasm-source.ts
248
+ var hasConfiguredWasmSource = false;
249
+ var configuredWorkerWasmSource;
250
+ function bufferSourceToArrayBuffer(source) {
251
+ if (source instanceof ArrayBuffer) {
252
+ return source.slice(0);
253
+ }
254
+ const bytes = new Uint8Array(source.buffer, source.byteOffset, source.byteLength);
255
+ const copy = new Uint8Array(bytes);
256
+ return copy.buffer;
257
+ }
258
+ function sourceToWorkerSource(source) {
259
+ if (typeof source === "string") {
260
+ return source;
261
+ }
262
+ if (typeof URL !== "undefined" && source instanceof URL) {
263
+ return source.href;
264
+ }
265
+ if (source instanceof ArrayBuffer || ArrayBuffer.isView(source)) {
266
+ return bufferSourceToArrayBuffer(source);
267
+ }
268
+ if (typeof WebAssembly !== "undefined" && source instanceof WebAssembly.Module) {
269
+ return source;
270
+ }
271
+ if (typeof Request !== "undefined" && source instanceof Request) {
272
+ return source.url;
273
+ }
274
+ return void 0;
275
+ }
276
+ function rememberWorkerWasmSource(source) {
277
+ hasConfiguredWasmSource = true;
278
+ configuredWorkerWasmSource = sourceToWorkerSource(source);
279
+ }
280
+ function setWasmSource2(source) {
281
+ setWasmSource(source);
282
+ rememberWorkerWasmSource(source);
283
+ }
284
+ function initWasm2(source) {
285
+ if (source !== void 0) {
286
+ rememberWorkerWasmSource(source);
287
+ }
288
+ return initWasm(source);
289
+ }
290
+ function canUseConfiguredWasmSourceInWorker() {
291
+ return !hasConfiguredWasmSource || configuredWorkerWasmSource !== void 0;
292
+ }
293
+ function getConfiguredWorkerWasmSource() {
294
+ return configuredWorkerWasmSource;
295
+ }
296
+
247
297
  // src/docx-import.ts
248
298
  var nextImportWorkerRequestId = 1;
249
299
  function createAbortError() {
@@ -263,7 +313,7 @@ function errorFromWorkerResponse(response) {
263
313
  return error;
264
314
  }
265
315
  function canUseDocxImportWorker(options) {
266
- return options.useWorker !== false && typeof Worker !== "undefined";
316
+ return options.useWorker !== false && typeof Worker !== "undefined" && canUseConfiguredWasmSourceInWorker();
267
317
  }
268
318
  function createDocxImportWorker() {
269
319
  return new Worker(new URL("./docx-import-worker.js", import.meta.url), {
@@ -277,8 +327,8 @@ async function importDocxOnMainThread(buffer, signal) {
277
327
  }
278
328
  const startedAt = performanceNow();
279
329
  const [{ parseDocx: parseDocx2 }, { buildDocModel: buildDocModel2 }] = await Promise.all([
280
- import("./src-PJYTN6DB.js"),
281
- import("./src-NDPFDRVM.js")
330
+ import("./src-2FP7IUE6.js"),
331
+ import("./src-VN4V5N3K.js")
282
332
  ]);
283
333
  const pkg = await parseDocx2(buffer);
284
334
  const parsedAt = performanceNow();
@@ -372,7 +422,8 @@ async function importDocxBuffer(buffer, options = {}) {
372
422
  const request = {
373
423
  id: requestId,
374
424
  type: "import-docx",
375
- buffer
425
+ buffer,
426
+ wasmSource: getConfiguredWorkerWasmSource()
376
427
  };
377
428
  const transfer = options.transferBuffer ? [buffer] : [];
378
429
  worker.postMessage(request, transfer);
@@ -433,6 +484,18 @@ function readStringAttribute(tagXml, attribute) {
433
484
  }
434
485
  return tagXml.match(new RegExp(`${attribute}="([^"]+)"`, "i"))?.[1];
435
486
  }
487
+ function resolvePageSizeForOrientation(params) {
488
+ const normalizedOrientation = params.orientation?.trim().toLowerCase();
489
+ const widthPx = Math.max(1, params.widthPx);
490
+ const heightPx = Math.max(1, params.heightPx);
491
+ if (normalizedOrientation === "landscape" && widthPx < heightPx) {
492
+ return { widthPx: heightPx, heightPx: widthPx };
493
+ }
494
+ if (normalizedOrientation === "portrait" && widthPx > heightPx) {
495
+ return { widthPx: heightPx, heightPx: widthPx };
496
+ }
497
+ return { widthPx, heightPx };
498
+ }
436
499
  function normalizeHexColor(value) {
437
500
  if (!value) {
438
501
  return void 0;
@@ -518,8 +581,13 @@ function parseSectionLayout(sectionPropertiesXml) {
518
581
  const pageSizeTag = sectionPropertiesXml.match(/<w:pgSz\b[^>]*>/i)?.[0];
519
582
  const pageMarginTag = sectionPropertiesXml.match(/<w:pgMar\b[^>]*>/i)?.[0];
520
583
  const docGridTag = sectionPropertiesXml.match(/<w:docGrid\b[^>]*\/?>/i)?.[0];
521
- const pageWidthPx = twipsToPixels(readTwipsAttribute(pageSizeTag, "w:w")) ?? DEFAULT_DOCUMENT_LAYOUT.pageWidthPx;
522
- const pageHeightPx = twipsToPixels(readTwipsAttribute(pageSizeTag, "w:h")) ?? DEFAULT_DOCUMENT_LAYOUT.pageHeightPx;
584
+ const rawPageWidthPx = twipsToPixels(readTwipsAttribute(pageSizeTag, "w:w")) ?? DEFAULT_DOCUMENT_LAYOUT.pageWidthPx;
585
+ const rawPageHeightPx = twipsToPixels(readTwipsAttribute(pageSizeTag, "w:h")) ?? DEFAULT_DOCUMENT_LAYOUT.pageHeightPx;
586
+ const pageSize = resolvePageSizeForOrientation({
587
+ widthPx: rawPageWidthPx,
588
+ heightPx: rawPageHeightPx,
589
+ orientation: readStringAttribute(pageSizeTag, "w:orient")
590
+ });
523
591
  const topMarginPx = twipsToPixels(readTwipsAttribute(pageMarginTag, "w:top")) ?? DEFAULT_DOCUMENT_LAYOUT.marginsPx.top;
524
592
  const rightMarginPx = twipsToPixels(readTwipsAttribute(pageMarginTag, "w:right")) ?? DEFAULT_DOCUMENT_LAYOUT.marginsPx.right;
525
593
  const bottomMarginPx = twipsToPixels(readTwipsAttribute(pageMarginTag, "w:bottom")) ?? DEFAULT_DOCUMENT_LAYOUT.marginsPx.bottom;
@@ -529,8 +597,8 @@ function parseSectionLayout(sectionPropertiesXml) {
529
597
  const docGridType = readStringAttribute(docGridTag, "w:type")?.toLowerCase();
530
598
  const docGridLinePitchPx = docGridType === "lines" || docGridType === "linesandchars" || docGridType === "snaptochars" ? twipsToPixels(readTwipsAttribute(docGridTag, "w:linePitch")) ?? DEFAULT_DOCUMENT_LAYOUT.docGridLinePitchPx : DEFAULT_DOCUMENT_LAYOUT.docGridLinePitchPx;
531
599
  return {
532
- pageWidthPx,
533
- pageHeightPx,
600
+ pageWidthPx: pageSize.widthPx,
601
+ pageHeightPx: pageSize.heightPx,
534
602
  marginsPx: {
535
603
  top: topMarginPx,
536
604
  right: rightMarginPx,
@@ -1747,7 +1815,7 @@ async function serializeDocModel(model, basePackage) {
1747
1815
  model,
1748
1816
  basePackage ? mapsToWasmPackage(basePackage) : void 0
1749
1817
  );
1750
- const { parseDocx: parseDocx2 } = await import("./src-PJYTN6DB.js");
1818
+ const { parseDocx: parseDocx2 } = await import("./src-2FP7IUE6.js");
1751
1819
  return parseDocx2(bytes);
1752
1820
  }
1753
1821
  async function serializeDocx(model, basePackage) {
@@ -3231,6 +3299,26 @@ function getDownscaledThumbnailImageDataUri(src) {
3231
3299
  downscaledThumbnailImageCache.set(src, pending);
3232
3300
  return pending;
3233
3301
  }
3302
+ var THUMBNAIL_DECODED_IMAGE_CACHE_MAX_ENTRIES = 48;
3303
+ var decodedThumbnailImageCache = /* @__PURE__ */ new Map();
3304
+ function getDecodedThumbnailImage(src) {
3305
+ const cached = decodedThumbnailImageCache.get(src);
3306
+ if (cached) {
3307
+ decodedThumbnailImageCache.delete(src);
3308
+ decodedThumbnailImageCache.set(src, cached);
3309
+ return cached;
3310
+ }
3311
+ const pending = loadThumbnailImage(src).catch(() => void 0);
3312
+ decodedThumbnailImageCache.set(src, pending);
3313
+ while (decodedThumbnailImageCache.size > THUMBNAIL_DECODED_IMAGE_CACHE_MAX_ENTRIES) {
3314
+ const oldestKey = decodedThumbnailImageCache.keys().next().value;
3315
+ if (oldestKey === void 0) {
3316
+ break;
3317
+ }
3318
+ decodedThumbnailImageCache.delete(oldestKey);
3319
+ }
3320
+ return pending;
3321
+ }
3234
3322
  function directThumbnailPositivePx(value, fallback = 1) {
3235
3323
  return Number.isFinite(value) && value > 0 ? Math.max(1, Number(value)) : fallback;
3236
3324
  }
@@ -3486,6 +3574,32 @@ function drawDirectThumbnailImagePlaceholder(context, image, hairlineSourcePx) {
3486
3574
  context.lineWidth = hairlineSourcePx;
3487
3575
  context.strokeRect(xPx, yPx, widthPx, heightPx);
3488
3576
  }
3577
+ function drawDirectThumbnailImage(context, image, decoded, hairlineSourcePx) {
3578
+ const xPx = Math.round(image.xPx);
3579
+ const yPx = Math.round(image.yPx);
3580
+ const widthPx = Math.max(1, Math.round(image.widthPx));
3581
+ const heightPx = Math.max(1, Math.round(image.heightPx));
3582
+ if (decoded && decoded.naturalWidth > 0 && decoded.naturalHeight > 0) {
3583
+ try {
3584
+ context.drawImage(decoded, xPx, yPx, widthPx, heightPx);
3585
+ return;
3586
+ } catch {
3587
+ }
3588
+ }
3589
+ setCanvasFillStyle(
3590
+ context,
3591
+ image.backgroundColor,
3592
+ THUMBNAIL_DIRECT_IMAGE_BACKGROUND
3593
+ );
3594
+ context.fillRect(xPx, yPx, widthPx, heightPx);
3595
+ setCanvasStrokeStyle(
3596
+ context,
3597
+ image.borderColor,
3598
+ THUMBNAIL_DIRECT_TABLE_BORDER_COLOR
3599
+ );
3600
+ context.lineWidth = hairlineSourcePx;
3601
+ context.strokeRect(xPx, yPx, widthPx, heightPx);
3602
+ }
3489
3603
  function drawDirectThumbnailTable(context, table, hairlineSourcePx) {
3490
3604
  const tableXPx = Math.round(table.xPx);
3491
3605
  const tableYPx = Math.round(table.yPx);
@@ -3525,7 +3639,7 @@ function drawDirectThumbnailTable(context, table, hairlineSourcePx) {
3525
3639
  });
3526
3640
  context.restore();
3527
3641
  }
3528
- function renderDocxThumbnailSnapshotSurface(params) {
3642
+ async function renderDocxThumbnailSnapshotSurface(params) {
3529
3643
  if (typeof document === "undefined") {
3530
3644
  throw new Error("DOCX thumbnails require a browser environment.");
3531
3645
  }
@@ -3540,6 +3654,21 @@ function renderDocxThumbnailSnapshotSurface(params) {
3540
3654
  if (!context) {
3541
3655
  throw new Error("2D canvas context is unavailable for DOCX thumbnails.");
3542
3656
  }
3657
+ const elements = params.snapshot.elements.slice(0, THUMBNAIL_DIRECT_MAX_ELEMENTS);
3658
+ const decodedImagesBySrc = /* @__PURE__ */ new Map();
3659
+ const imageSrcs = /* @__PURE__ */ new Set();
3660
+ for (const element of elements) {
3661
+ if (element.kind === "image" && element.src) {
3662
+ imageSrcs.add(element.src);
3663
+ }
3664
+ }
3665
+ if (imageSrcs.size > 0) {
3666
+ await Promise.all(
3667
+ Array.from(imageSrcs, async (src) => {
3668
+ decodedImagesBySrc.set(src, await getDecodedThumbnailImage(src));
3669
+ })
3670
+ );
3671
+ }
3543
3672
  const scaleX = pixelWidthPx / sourceWidthPx;
3544
3673
  const scaleY = pixelHeightPx / sourceHeightPx;
3545
3674
  const hairlineSourcePx = Math.max(0.75, 1 / Math.max(scaleX, scaleY));
@@ -3552,7 +3681,7 @@ function renderDocxThumbnailSnapshotSurface(params) {
3552
3681
  "#ffffff"
3553
3682
  );
3554
3683
  context.fillRect(0, 0, sourceWidthPx, sourceHeightPx);
3555
- params.snapshot.elements.slice(0, THUMBNAIL_DIRECT_MAX_ELEMENTS).forEach((element) => {
3684
+ elements.forEach((element) => {
3556
3685
  switch (element.kind) {
3557
3686
  case "paragraph":
3558
3687
  drawDirectThumbnailParagraph(context, element);
@@ -3564,6 +3693,14 @@ function renderDocxThumbnailSnapshotSurface(params) {
3564
3693
  hairlineSourcePx
3565
3694
  );
3566
3695
  break;
3696
+ case "image":
3697
+ drawDirectThumbnailImage(
3698
+ context,
3699
+ element,
3700
+ decodedImagesBySrc.get(element.src),
3701
+ hairlineSourcePx
3702
+ );
3703
+ break;
3567
3704
  case "table":
3568
3705
  drawDirectThumbnailTable(context, element, hairlineSourcePx);
3569
3706
  break;
@@ -23020,7 +23157,7 @@ function docxThumbnailTextRunsFromParagraph(paragraph, documentTheme, maxChars =
23020
23157
  return;
23021
23158
  }
23022
23159
  const style = child.type === "text" || child.type === "form-field" ? child.style : void 0;
23023
- const text = child.type === "text" ? child.text : child.type === "form-field" ? formFieldDisplayValue2(child) : child.type === "image" ? child.alt || "[image]" : "";
23160
+ const text = child.type === "text" ? child.text : child.type === "form-field" ? formFieldDisplayValue2(child) : "";
23024
23161
  appendDocxThumbnailTextRun(
23025
23162
  runs,
23026
23163
  {
@@ -23111,13 +23248,29 @@ function buildDocxThumbnailParagraphElements(params) {
23111
23248
  (widthPx - 4) / imageWidthPx,
23112
23249
  (bodyHeightPx - 4) / imageHeightPx
23113
23250
  );
23114
- elements.push({
23115
- kind: "image-placeholder",
23116
- xPx: xPx + 2,
23117
- yPx: bodyYPx + 2,
23118
- widthPx: Math.max(12, imageWidthPx * scale),
23119
- heightPx: Math.max(12, imageHeightPx * scale)
23120
- });
23251
+ const elementXPx = xPx + 2;
23252
+ const elementYPx = bodyYPx + 2;
23253
+ const elementWidthPx = Math.max(12, imageWidthPx * scale);
23254
+ const elementHeightPx = Math.max(12, imageHeightPx * scale);
23255
+ const renderableSrc = resolveRenderableImageSource(imageRun);
23256
+ if (renderableSrc) {
23257
+ elements.push({
23258
+ kind: "image",
23259
+ xPx: elementXPx,
23260
+ yPx: elementYPx,
23261
+ widthPx: elementWidthPx,
23262
+ heightPx: elementHeightPx,
23263
+ src: renderableSrc
23264
+ });
23265
+ } else {
23266
+ elements.push({
23267
+ kind: "image-placeholder",
23268
+ xPx: elementXPx,
23269
+ yPx: elementYPx,
23270
+ widthPx: elementWidthPx,
23271
+ heightPx: elementHeightPx
23272
+ });
23273
+ }
23121
23274
  });
23122
23275
  }
23123
23276
  return elements;
@@ -23216,6 +23369,24 @@ function buildDocxThumbnailTableElement(params) {
23216
23369
  cells
23217
23370
  };
23218
23371
  }
23372
+ function docxThumbnailNodeRequiresDomRaster(node) {
23373
+ if (!node) {
23374
+ return false;
23375
+ }
23376
+ if (node.type === "paragraph") {
23377
+ return node.children.some((child) => child.type === "image");
23378
+ }
23379
+ return node.rows.some(
23380
+ (row) => row.cells.some(
23381
+ (cell) => cell.nodes.some((cellNode) => docxThumbnailNodeRequiresDomRaster(cellNode))
23382
+ )
23383
+ );
23384
+ }
23385
+ function docxThumbnailPageRequiresDomRaster(model, pageSegments) {
23386
+ return pageSegments.some(
23387
+ (segment) => docxThumbnailNodeRequiresDomRaster(model.nodes[segment.nodeIndex])
23388
+ );
23389
+ }
23219
23390
  function buildDocxPageThumbnailRenderSnapshotEntries(params) {
23220
23391
  const {
23221
23392
  model,
@@ -23228,6 +23399,9 @@ function buildDocxPageThumbnailRenderSnapshotEntries(params) {
23228
23399
  numberingDefinitions
23229
23400
  } = params;
23230
23401
  return pageNodeSegmentsByPage.map((pageSegments, pageIndex) => {
23402
+ if (docxThumbnailPageRequiresDomRaster(model, pageSegments)) {
23403
+ return void 0;
23404
+ }
23231
23405
  const key = `${contentKeysByPage[pageIndex] ?? ""}|theme:${documentTheme}`;
23232
23406
  let cachedSnapshot;
23233
23407
  return {
@@ -23674,7 +23848,7 @@ function useDocxPageThumbnails(editor, options = {}) {
23674
23848
  if (!surface) {
23675
23849
  const thumbnailSnapshot = thumbnailSnapshotEntry?.getSnapshot();
23676
23850
  if (thumbnailSnapshot) {
23677
- surface = renderDocxThumbnailSnapshotSurface({
23851
+ surface = await renderDocxThumbnailSnapshotSurface({
23678
23852
  snapshot: thumbnailSnapshot,
23679
23853
  widthPx: resolution.widthPx,
23680
23854
  heightPx: resolution.heightPx,
@@ -44857,7 +45031,7 @@ export {
44857
45031
  defaultStarterModel,
44858
45032
  duplicateParagraph,
44859
45033
  getPart,
44860
- initWasm,
45034
+ initWasm2 as initWasm,
44861
45035
  insertParagraph,
44862
45036
  layoutDocument,
44863
45037
  modelToDocumentXml,
@@ -44899,7 +45073,7 @@ export {
44899
45073
  setParagraphHeading,
44900
45074
  setRunColor,
44901
45075
  setRunHighlight,
44902
- setWasmSource,
45076
+ setWasmSource2 as setWasmSource,
44903
45077
  splitParagraphChildrenAtTextOffsets,
44904
45078
  toggleRunStyleFlag,
44905
45079
  updateParagraphText,