@extend-ai/react-docx 0.6.0 → 0.6.2

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
@@ -3978,10 +3978,14 @@ function parseParagraphRuns(paragraphXml2, context) {
3978
3978
  }
3979
3979
  }
3980
3980
  });
3981
+ let hyperlinkRangeCursor = 0;
3981
3982
  return runRanges.map((range, runIndex) => {
3982
- const link = hyperlinkRanges.find(
3983
- (hyperlinkRange) => range.start >= hyperlinkRange.start && range.end <= hyperlinkRange.end && hyperlinkRange.href
3984
- )?.href ?? fieldLinksByRun.get(runIndex);
3983
+ while (hyperlinkRangeCursor < hyperlinkRanges.length && hyperlinkRanges[hyperlinkRangeCursor].end <= range.start) {
3984
+ hyperlinkRangeCursor += 1;
3985
+ }
3986
+ const currentHyperlinkRange = hyperlinkRanges[hyperlinkRangeCursor];
3987
+ const hyperlinkHref = currentHyperlinkRange && range.start >= currentHyperlinkRange.start && range.end <= currentHyperlinkRange.end ? currentHyperlinkRange.href : void 0;
3988
+ const link = hyperlinkHref ?? fieldLinksByRun.get(runIndex);
3985
3989
  return {
3986
3990
  xml: paragraphXml2.slice(range.start, range.end),
3987
3991
  start: range.start,
@@ -4577,9 +4581,14 @@ function parseParagraph(paragraphXml2, context) {
4577
4581
  runs
4578
4582
  );
4579
4583
  const contentTokens = [];
4584
+ let formFieldTokenCursor = 0;
4580
4585
  for (const run of runs) {
4581
- const insideFormField = formFieldTokens.some(
4582
- (formFieldToken) => run.start >= formFieldToken.start && run.end <= formFieldToken.end
4586
+ while (formFieldTokenCursor < formFieldTokens.length && formFieldTokens[formFieldTokenCursor].end <= run.start) {
4587
+ formFieldTokenCursor += 1;
4588
+ }
4589
+ const currentFormFieldToken = formFieldTokens[formFieldTokenCursor];
4590
+ const insideFormField = Boolean(
4591
+ currentFormFieldToken && run.start >= currentFormFieldToken.start && run.end <= currentFormFieldToken.end
4583
4592
  );
4584
4593
  if (insideFormField) {
4585
4594
  continue;
@@ -7799,107 +7808,6 @@ function parseParagraphsFromClipboard(input) {
7799
7808
  }
7800
7809
  }
7801
7810
 
7802
- // src/docx-import-worker-client.ts
7803
- var import_meta = {};
7804
- var cachedWorker;
7805
- var cachedWorkerUnavailable = false;
7806
- var nextRequestId = 1;
7807
- function resolveWorker() {
7808
- if (cachedWorkerUnavailable) {
7809
- return void 0;
7810
- }
7811
- if (cachedWorker) {
7812
- return cachedWorker;
7813
- }
7814
- if (typeof window === "undefined" || typeof Worker === "undefined" || typeof URL === "undefined") {
7815
- cachedWorkerUnavailable = true;
7816
- return void 0;
7817
- }
7818
- try {
7819
- const workerUrl = new URL(
7820
- "./docx-import-worker.ts",
7821
- import_meta.url
7822
- );
7823
- cachedWorker = new Worker(workerUrl, {
7824
- type: "module",
7825
- name: "docx-import"
7826
- });
7827
- return cachedWorker;
7828
- } catch {
7829
- cachedWorkerUnavailable = true;
7830
- cachedWorker = void 0;
7831
- return void 0;
7832
- }
7833
- }
7834
- async function importDocxOnMainThread(buffer) {
7835
- const pkg = await parseDocx(buffer);
7836
- const model = buildDocModel(pkg);
7837
- return { pkg, model };
7838
- }
7839
- async function importDocxViaWorker(buffer) {
7840
- const worker = resolveWorker();
7841
- if (!worker) {
7842
- return importDocxOnMainThread(buffer);
7843
- }
7844
- const requestId = nextRequestId;
7845
- nextRequestId += 1;
7846
- return new Promise((resolve, reject) => {
7847
- const handleMessage = (event) => {
7848
- const data = event.data;
7849
- if (!data || data.requestId !== requestId) {
7850
- return;
7851
- }
7852
- worker.removeEventListener("message", handleMessage);
7853
- worker.removeEventListener("error", handleError);
7854
- worker.removeEventListener("messageerror", handleMessageError);
7855
- if (data.type === "imported") {
7856
- resolve({ pkg: data.pkg, model: data.model });
7857
- } else {
7858
- reject(new Error(data.message));
7859
- }
7860
- };
7861
- const handleError = (event) => {
7862
- worker.removeEventListener("message", handleMessage);
7863
- worker.removeEventListener("error", handleError);
7864
- worker.removeEventListener("messageerror", handleMessageError);
7865
- const message = event instanceof ErrorEvent && event.message ? event.message : "DOCX import worker crashed";
7866
- try {
7867
- worker.terminate();
7868
- } catch {
7869
- }
7870
- if (cachedWorker === worker) {
7871
- cachedWorker = void 0;
7872
- }
7873
- reject(new Error(message));
7874
- };
7875
- const handleMessageError = () => {
7876
- handleError(new Event("messageerror"));
7877
- };
7878
- worker.addEventListener("message", handleMessage);
7879
- worker.addEventListener("error", handleError);
7880
- worker.addEventListener("messageerror", handleMessageError);
7881
- const request = {
7882
- type: "import",
7883
- requestId,
7884
- buffer
7885
- };
7886
- try {
7887
- worker.postMessage(request, [buffer]);
7888
- } catch (error) {
7889
- worker.removeEventListener("message", handleMessage);
7890
- worker.removeEventListener("error", handleError);
7891
- worker.removeEventListener("messageerror", handleMessageError);
7892
- if (typeof console !== "undefined") {
7893
- console.warn(
7894
- "DOCX import worker postMessage failed; falling back to main thread.",
7895
- error
7896
- );
7897
- }
7898
- importDocxOnMainThread(buffer).then(resolve, reject);
7899
- }
7900
- });
7901
- }
7902
-
7903
7811
  // ../serializer/src/index.ts
7904
7812
  var REL_TYPE_IMAGE = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/image";
7905
7813
  var REL_TYPE_HYPERLINK = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/hyperlink";
@@ -9095,6 +9003,9 @@ function paragraphHasExplicitPageBreak(paragraph) {
9095
9003
  return sourceXml.length > 0 && PAGE_BREAK_XML_PATTERN.test(sourceXml);
9096
9004
  }
9097
9005
  function paragraphHasPageBreakBefore(paragraph) {
9006
+ if (paragraph.style?.pageBreakBefore === true) {
9007
+ return true;
9008
+ }
9098
9009
  const sourceXml = paragraph.sourceXml ?? "";
9099
9010
  if (!sourceXml) {
9100
9011
  return false;
@@ -9430,10 +9341,12 @@ function reconcilePageCountCandidateToTargetCountByScalingHeight(options) {
9430
9341
 
9431
9342
  // src/pretext-layout.ts
9432
9343
  var import_pretext = require("@chenglou/pretext");
9433
- var PREPARED_TEXT_CACHE_MAX_ENTRIES = 512;
9434
- var LAYOUT_CACHE_MAX_ENTRIES = 256;
9344
+ var PREPARED_TEXT_CACHE_MAX_ENTRIES = 8192;
9345
+ var LAYOUT_CACHE_MAX_ENTRIES = 4096;
9346
+ var LINE_COUNT_CACHE_MAX_ENTRIES = 16384;
9435
9347
  var preparedTextByKey = /* @__PURE__ */ new Map();
9436
9348
  var layoutByKey = /* @__PURE__ */ new Map();
9349
+ var lineCountByKey = /* @__PURE__ */ new Map();
9437
9350
  var fragmentOffsetAdvancesByFragment = /* @__PURE__ */ new WeakMap();
9438
9351
  var graphemeOffsetsByText = /* @__PURE__ */ new Map();
9439
9352
  var measureCanvas;
@@ -9442,6 +9355,24 @@ var graphemeSegmenter;
9442
9355
  function canUsePretext() {
9443
9356
  return typeof OffscreenCanvas !== "undefined" || typeof document !== "undefined";
9444
9357
  }
9358
+ function getCachedValue(cache, key) {
9359
+ const cached = cache.get(key);
9360
+ if (cached === void 0) {
9361
+ return void 0;
9362
+ }
9363
+ cache.delete(key);
9364
+ cache.set(key, cached);
9365
+ return cached;
9366
+ }
9367
+ function trimCache(cache, maxEntries) {
9368
+ while (cache.size > maxEntries) {
9369
+ const firstKey = cache.keys().next().value;
9370
+ if (firstKey === void 0) {
9371
+ break;
9372
+ }
9373
+ cache.delete(firstKey);
9374
+ }
9375
+ }
9445
9376
  function getMeasureContext() {
9446
9377
  if (!canUsePretext()) {
9447
9378
  return void 0;
@@ -9628,7 +9559,7 @@ function prepareCached(text, font, wordBreak = "normal") {
9628
9559
  return void 0;
9629
9560
  }
9630
9561
  const cacheKey = `${font}\0${wordBreak}\0${text}`;
9631
- const cached = preparedTextByKey.get(cacheKey);
9562
+ const cached = getCachedValue(preparedTextByKey, cacheKey);
9632
9563
  if (cached) {
9633
9564
  return cached;
9634
9565
  }
@@ -9638,13 +9569,7 @@ function prepareCached(text, font, wordBreak = "normal") {
9638
9569
  wordBreak
9639
9570
  });
9640
9571
  preparedTextByKey.set(cacheKey, prepared);
9641
- while (preparedTextByKey.size > PREPARED_TEXT_CACHE_MAX_ENTRIES) {
9642
- const firstKey = preparedTextByKey.keys().next().value;
9643
- if (!firstKey) {
9644
- break;
9645
- }
9646
- preparedTextByKey.delete(firstKey);
9647
- }
9572
+ trimCache(preparedTextByKey, PREPARED_TEXT_CACHE_MAX_ENTRIES);
9648
9573
  return prepared;
9649
9574
  } catch {
9650
9575
  return void 0;
@@ -9655,13 +9580,21 @@ function measurePretextPlainTextLineCount(text, font, containerWidthPx, options)
9655
9580
  return 0;
9656
9581
  }
9657
9582
  const wordBreak = options?.wordBreak ?? "normal";
9583
+ const safeWidth = Math.max(1, Math.round(containerWidthPx));
9584
+ const cacheKey = `line-count\0${font}\0${wordBreak}\0${safeWidth}\0${text}`;
9585
+ const cached = getCachedValue(lineCountByKey, cacheKey);
9586
+ if (cached !== void 0) {
9587
+ return cached;
9588
+ }
9658
9589
  const prepared = prepareCached(text, font, wordBreak);
9659
9590
  if (!prepared) {
9660
9591
  return void 0;
9661
9592
  }
9662
9593
  try {
9663
- const safeWidth = Math.max(1, Math.round(containerWidthPx));
9664
- return (0, import_pretext.measureLineStats)(prepared, safeWidth).lineCount;
9594
+ const lineCount = (0, import_pretext.measureLineStats)(prepared, safeWidth).lineCount;
9595
+ lineCountByKey.set(cacheKey, lineCount);
9596
+ trimCache(lineCountByKey, LINE_COUNT_CACHE_MAX_ENTRIES);
9597
+ return lineCount;
9665
9598
  } catch {
9666
9599
  return void 0;
9667
9600
  }
@@ -9921,7 +9854,7 @@ function layoutTextWithPretextAroundExclusions(text, font, containerWidthPx, lin
9921
9854
  safeLineHeightPx,
9922
9855
  normalizedExclusions
9923
9856
  );
9924
- const cachedLayout = layoutByKey.get(cacheKey);
9857
+ const cachedLayout = getCachedValue(layoutByKey, cacheKey);
9925
9858
  if (cachedLayout) {
9926
9859
  return cachedLayout;
9927
9860
  }
@@ -9995,13 +9928,7 @@ function layoutTextWithPretextAroundExclusions(text, font, containerWidthPx, lin
9995
9928
  exclusions: normalizedExclusions
9996
9929
  };
9997
9930
  layoutByKey.set(cacheKey, nextLayout);
9998
- while (layoutByKey.size > LAYOUT_CACHE_MAX_ENTRIES) {
9999
- const firstKey = layoutByKey.keys().next().value;
10000
- if (!firstKey) {
10001
- break;
10002
- }
10003
- layoutByKey.delete(firstKey);
10004
- }
9931
+ trimCache(layoutByKey, LAYOUT_CACHE_MAX_ENTRIES);
10005
9932
  return nextLayout;
10006
9933
  }
10007
9934
  function layoutItemsWithPretextAroundExclusions(text, items, containerWidthPx, lineHeightPx, exclusions, fallbackFont) {
@@ -10053,7 +9980,7 @@ function layoutItemsWithPretextAroundExclusions(text, items, containerWidthPx, l
10053
9980
  safeLineHeightPx,
10054
9981
  normalizedExclusions
10055
9982
  );
10056
- const cachedLayout = layoutByKey.get(cacheKey);
9983
+ const cachedLayout = getCachedValue(layoutByKey, cacheKey);
10057
9984
  if (cachedLayout) {
10058
9985
  return cachedLayout;
10059
9986
  }
@@ -10167,13 +10094,7 @@ function layoutItemsWithPretextAroundExclusions(text, items, containerWidthPx, l
10167
10094
  exclusions: normalizedExclusions
10168
10095
  };
10169
10096
  layoutByKey.set(cacheKey, nextLayout);
10170
- while (layoutByKey.size > LAYOUT_CACHE_MAX_ENTRIES) {
10171
- const firstKey = layoutByKey.keys().next().value;
10172
- if (!firstKey) {
10173
- break;
10174
- }
10175
- layoutByKey.delete(firstKey);
10176
- }
10097
+ trimCache(layoutByKey, LAYOUT_CACHE_MAX_ENTRIES);
10177
10098
  return nextLayout;
10178
10099
  }
10179
10100
  function resolveOffsetAtPoint(layout, x, y) {
@@ -10466,8 +10387,12 @@ var INITIAL_PAGINATION_PAGE_COUNT_OSCILLATION_DISTINCT_THRESHOLD = 2;
10466
10387
  var INITIAL_PAGINATION_PAGE_COUNT_OSCILLATION_CHANGE_THRESHOLD = 4;
10467
10388
  var INITIAL_PAGINATION_BACKGROUND_REFINEMENT_DELAY_MS = 96;
10468
10389
  var DEFAULT_PAGE_VIRTUALIZATION_OVERSCAN = 2;
10390
+ var LARGE_TABLE_PAGE_VIRTUALIZATION_OVERSCAN = 0;
10391
+ var LARGE_TABLE_PAGE_ADJACENT_RENDER_COUNT = 1;
10469
10392
  var DEFAULT_PAGE_VIRTUALIZATION_SETTLE_DELAY_MS = 350;
10470
10393
  var ENABLE_TABLE_ROW_SLICING = true;
10394
+ var MIN_TABLE_ROW_SLICE_REMAINING_HEIGHT_PX = MIN_PARAGRAPH_LINE_HEIGHT_PX * 2;
10395
+ var TABLE_ROW_SLICE_BOUNDARY_TOLERANCE_PX = 2;
10471
10396
  var TOP_AND_BOTTOM_VERTICAL_DRAG_SNAP_PX = 10;
10472
10397
  var HEADER_FOOTER_INACTIVE_OPACITY = 0.5;
10473
10398
  var LETTERHEAD_INDENT_MIN_TWIPS = 900;
@@ -10503,6 +10428,10 @@ var paragraphDropCapBySourceXml = /* @__PURE__ */ new Map();
10503
10428
  var paragraphTrackedMarkupBySourceXml = /* @__PURE__ */ new Map();
10504
10429
  var paragraphMeasureCanvasContext;
10505
10430
  var textWidthByFontAndValue = /* @__PURE__ */ new Map();
10431
+ var estimatedTextAdvanceWidthByFontAndValue = /* @__PURE__ */ new Map();
10432
+ var pretextWordBreakModeByText = /* @__PURE__ */ new Map();
10433
+ var paragraphBaseFontSizePxByParagraph = /* @__PURE__ */ new WeakMap();
10434
+ var paragraphDominantFontFamilyByParagraph = /* @__PURE__ */ new WeakMap();
10506
10435
  function setCacheEntry(cache, key, value) {
10507
10436
  if (!cache.has(key) && cache.size >= XML_CACHE_MAX_ENTRIES) {
10508
10437
  const oldestKey = cache.keys().next().value;
@@ -11966,7 +11895,23 @@ function resolvePageContentHeightPxForPageSegments(pageSegments, pageIndex, defa
11966
11895
  );
11967
11896
  }
11968
11897
  function resolveRenderPageContentHeightPxForPageSegments(params) {
11969
- const resolvedHeightPx = resolvePageContentHeightPxForPageSegments(
11898
+ const firstNodeIndex = params.pageSegments[0]?.nodeIndex ?? 0;
11899
+ const metricsIndex = resolvePaginationSectionMetricsIndexForNodeIndex(
11900
+ params.metricsBySection,
11901
+ firstNodeIndex,
11902
+ 0
11903
+ );
11904
+ const sectionHeightMultiplier = Math.max(
11905
+ 1,
11906
+ Math.round(
11907
+ params.metricsBySection[metricsIndex]?.pageContentHeightMultiplier ?? 1
11908
+ )
11909
+ );
11910
+ const pageContainsOnlySplitParagraphSegments = documentPageContainsOnlySplitParagraphSegments(params.pageSegments);
11911
+ const measuredHeightPx = params.useMeasuredPageContentHeights === false ? void 0 : params.measuredPageContentHeightsPxByPageIndex?.[params.pageIndex];
11912
+ const measuredHeightMatchesCurrentPage = params.pageIdentityKey === void 0 || params.measuredPageContentIdentityKeysByPageIndex?.[params.pageIndex] === void 0 || params.measuredPageContentIdentityKeysByPageIndex?.[params.pageIndex] === params.pageIdentityKey;
11913
+ const usesMeasuredVisualHeight = Number.isFinite(measuredHeightPx) && measuredHeightMatchesCurrentPage && !pageContainsOnlySplitParagraphSegments;
11914
+ let resolvedHeightPx = resolvePageContentHeightPxForPageSegments(
11970
11915
  params.pageSegments,
11971
11916
  params.pageIndex,
11972
11917
  params.defaultPageContentHeightPx,
@@ -11976,12 +11921,15 @@ function resolveRenderPageContentHeightPxForPageSegments(params) {
11976
11921
  params.pageIdentityKey
11977
11922
  );
11978
11923
  if (params.useMeasuredPageContentHeights === false && Number.isFinite(params.pageContentHeightScale) && Math.abs(params.pageContentHeightScale - 1) >= 1e-3) {
11979
- return Math.max(
11924
+ resolvedHeightPx = Math.max(
11980
11925
  120,
11981
11926
  Math.round(resolvedHeightPx * params.pageContentHeightScale)
11982
11927
  );
11983
11928
  }
11984
- return resolvedHeightPx;
11929
+ if (usesMeasuredVisualHeight || sectionHeightMultiplier <= 1) {
11930
+ return resolvedHeightPx;
11931
+ }
11932
+ return Math.max(120, Math.round(resolvedHeightPx / sectionHeightMultiplier));
11985
11933
  }
11986
11934
  function documentPageContainsOnlySplitParagraphSegments(pageSegments) {
11987
11935
  return pageSegments.length > 0 && pageSegments.every(
@@ -12535,7 +12483,9 @@ function firstExplicitFontFamilyInNodeTree(nodes) {
12535
12483
  if (node.type === "table") {
12536
12484
  for (const row of node.rows) {
12537
12485
  for (const cell of row.cells) {
12538
- const nestedFontFamily = firstExplicitFontFamilyInNodeTree(cell.nodes);
12486
+ const nestedFontFamily = firstExplicitFontFamilyInNodeTree(
12487
+ cell.nodes
12488
+ );
12539
12489
  if (nestedFontFamily) {
12540
12490
  return nestedFontFamily;
12541
12491
  }
@@ -13441,11 +13391,19 @@ function buildParagraphPretextTabSpacerText(widthPx, style, paragraphBaseFontPx)
13441
13391
  while (measuredWidthPx + spacerAdvancePx * 0.5 < safeWidthPx && spacerCount < 64) {
13442
13392
  spacerCount += 1;
13443
13393
  spacerText = spacerCharacter.repeat(spacerCount);
13444
- measuredWidthPx = measureTextWidthPx2(spacerText, style, paragraphBaseFontPx);
13394
+ measuredWidthPx = measureTextWidthPx2(
13395
+ spacerText,
13396
+ style,
13397
+ paragraphBaseFontPx
13398
+ );
13445
13399
  }
13446
13400
  while (spacerCount > 1) {
13447
13401
  const nextText = spacerCharacter.repeat(spacerCount - 1);
13448
- const nextWidthPx = measureTextWidthPx2(nextText, style, paragraphBaseFontPx);
13402
+ const nextWidthPx = measureTextWidthPx2(
13403
+ nextText,
13404
+ style,
13405
+ paragraphBaseFontPx
13406
+ );
13449
13407
  if (Math.abs(nextWidthPx - safeWidthPx) >= Math.abs(measuredWidthPx - safeWidthPx)) {
13450
13408
  break;
13451
13409
  }
@@ -13736,7 +13694,20 @@ function buildSyntheticPretextLayoutSource(text, style) {
13736
13694
  };
13737
13695
  }
13738
13696
  function pretextWordBreakModeForText(text) {
13739
- return KEEP_ALL_SCRIPT_RE.test(text) ? "keep-all" : "normal";
13697
+ const cached = pretextWordBreakModeByText.get(text);
13698
+ if (cached) {
13699
+ return cached;
13700
+ }
13701
+ const mode = KEEP_ALL_SCRIPT_RE.test(text) ? "keep-all" : "normal";
13702
+ setCacheEntry(pretextWordBreakModeByText, text, mode);
13703
+ while (pretextWordBreakModeByText.size > TEXT_MEASURE_CACHE_MAX_ENTRIES) {
13704
+ const firstKey = pretextWordBreakModeByText.keys().next().value;
13705
+ if (!firstKey) {
13706
+ break;
13707
+ }
13708
+ pretextWordBreakModeByText.delete(firstKey);
13709
+ }
13710
+ return mode;
13740
13711
  }
13741
13712
  function sanitizeRenderedPretextFragmentText(text) {
13742
13713
  return text.replace(/\r\n?|\n/g, "");
@@ -14220,36 +14191,55 @@ function estimateTextAdvanceWidthPx(text, style) {
14220
14191
  if (!text) {
14221
14192
  return 0;
14222
14193
  }
14223
- const normalized = text.replace(/\u00a0/g, " ");
14224
14194
  const fontSizePx = runFontSizePx(style);
14195
+ const normalized = text.includes("\xA0") ? text.replace(/\u00a0/g, " ") : text;
14196
+ const cacheKey = `${fontSizePx}\0${normalized}`;
14197
+ const cached = estimatedTextAdvanceWidthByFontAndValue.get(cacheKey);
14198
+ if (cached !== void 0) {
14199
+ return cached;
14200
+ }
14225
14201
  let total = 0;
14226
- for (const char of normalized) {
14227
- if (char === "\n" || char === "\r") {
14202
+ for (let index = 0; index < normalized.length; index += 1) {
14203
+ const code = normalized.charCodeAt(index);
14204
+ if (code === 10 || code === 13) {
14228
14205
  continue;
14229
14206
  }
14230
- if (char === " ") {
14207
+ if (code === 9) {
14231
14208
  total += fontSizePx * 2;
14232
14209
  continue;
14233
14210
  }
14234
- if (char === " ") {
14211
+ if (code === 32) {
14235
14212
  total += fontSizePx * 0.33;
14236
14213
  continue;
14237
14214
  }
14238
- if (/[.,:;'"`!|ilI1]/.test(char)) {
14215
+ if (code === 33 || code === 39 || code === 44 || code === 46 || code === 49 || code === 58 || code === 59 || code === 73 || code === 96 || code === 105 || code === 108 || code === 124) {
14239
14216
  total += fontSizePx * 0.29;
14240
14217
  continue;
14241
14218
  }
14242
- if (/[A-Z0-9]/.test(char)) {
14219
+ if (code >= 65 && code <= 90 || code >= 48 && code <= 57) {
14243
14220
  total += fontSizePx * 0.6;
14244
14221
  continue;
14245
14222
  }
14246
- if (/[\u3000-\u9fff]/.test(char)) {
14223
+ if (code >= 12288 && code <= 40959) {
14247
14224
  total += fontSizePx * 0.95;
14248
14225
  continue;
14249
14226
  }
14250
14227
  total += fontSizePx * 0.54;
14251
14228
  }
14252
- return Math.max(0, Math.round(total));
14229
+ const estimatedWidthPx = Math.max(0, Math.round(total));
14230
+ setCacheEntry(
14231
+ estimatedTextAdvanceWidthByFontAndValue,
14232
+ cacheKey,
14233
+ estimatedWidthPx
14234
+ );
14235
+ while (estimatedTextAdvanceWidthByFontAndValue.size > TEXT_MEASURE_CACHE_MAX_ENTRIES) {
14236
+ const firstKey = estimatedTextAdvanceWidthByFontAndValue.keys().next().value;
14237
+ if (!firstKey) {
14238
+ break;
14239
+ }
14240
+ estimatedTextAdvanceWidthByFontAndValue.delete(firstKey);
14241
+ }
14242
+ return estimatedWidthPx;
14253
14243
  }
14254
14244
  function updateEstimatedLineWidthPxForText(currentLineWidthPx, text, style) {
14255
14245
  if (!text) {
@@ -14555,7 +14545,8 @@ function paragraphHasLastRenderedPageBreak(paragraph) {
14555
14545
  if (cached) {
14556
14546
  return cached.lastRenderedPageBreak;
14557
14547
  }
14558
- return paragraphHasExplicitPageBreak2(paragraph) ? paragraphBreakFlagsBySourceXml.get(xml)?.lastRenderedPageBreak ?? false : false;
14548
+ paragraphHasExplicitPageBreak2(paragraph);
14549
+ return paragraphBreakFlagsBySourceXml.get(xml)?.lastRenderedPageBreak ?? false;
14559
14550
  }
14560
14551
  function paragraphStartsWithLastRenderedPageBreak(paragraph) {
14561
14552
  const xml = paragraph.sourceXml ?? "";
@@ -14729,7 +14720,8 @@ function paragraphHasPageBreakBefore2(paragraph) {
14729
14720
  if (cached) {
14730
14721
  return cached.pageBreakBefore;
14731
14722
  }
14732
- return paragraphHasExplicitPageBreak2(paragraph) ? paragraphBreakFlagsBySourceXml.get(xml)?.pageBreakBefore ?? false : false;
14723
+ paragraphHasExplicitPageBreak2(paragraph);
14724
+ return paragraphBreakFlagsBySourceXml.get(xml)?.pageBreakBefore ?? false;
14733
14725
  }
14734
14726
  function sectionBreakAfterParagraphStartsNewPage(paragraph) {
14735
14727
  const xml = paragraph.sourceXml ?? "";
@@ -14909,9 +14901,15 @@ function paragraphDominantFontSizePt(paragraph) {
14909
14901
  return dominantFontSizePt;
14910
14902
  }
14911
14903
  function paragraphBaseFontSizePx(paragraph) {
14904
+ const cached = paragraphBaseFontSizePxByParagraph.get(paragraph);
14905
+ if (cached !== void 0) {
14906
+ return cached;
14907
+ }
14912
14908
  const dominantRunFontSizePt = paragraphDominantFontSizePt(paragraph);
14913
14909
  const fontSizePt = dominantRunFontSizePt && dominantRunFontSizePt > 0 ? dominantRunFontSizePt : Number.isFinite(paragraph.style?.headingLevel) ? DEFAULT_PARAGRAPH_FONT_SIZE_PT + Math.max(0, 6 - (paragraph.style?.headingLevel ?? 6)) : DEFAULT_PARAGRAPH_FONT_SIZE_PT;
14914
- return Math.max(10, Math.round(fontSizePt * 96 / 72));
14910
+ const baseFontSizePx = Math.max(10, Math.round(fontSizePt * 96 / 72));
14911
+ paragraphBaseFontSizePxByParagraph.set(paragraph, baseFontSizePx);
14912
+ return baseFontSizePx;
14915
14913
  }
14916
14914
  function paragraphMaxFontSizePx(paragraph) {
14917
14915
  const paragraphBaseFontPx = paragraphBaseFontSizePx(paragraph);
@@ -14936,6 +14934,10 @@ function normalizeFontFamilyToken(fontFamily) {
14936
14934
  return normalized || void 0;
14937
14935
  }
14938
14936
  function paragraphDominantFontFamily(paragraph) {
14937
+ const cached = paragraphDominantFontFamilyByParagraph.get(paragraph);
14938
+ if (cached !== void 0) {
14939
+ return cached ?? void 0;
14940
+ }
14939
14941
  const weightByFamily = /* @__PURE__ */ new Map();
14940
14942
  const addWeight = (fontFamily, weight) => {
14941
14943
  const normalizedFamily = normalizeFontFamilyToken(fontFamily);
@@ -14956,6 +14958,7 @@ function paragraphDominantFontFamily(paragraph) {
14956
14958
  addWeight(child.style?.fontFamily, text.length);
14957
14959
  });
14958
14960
  if (weightByFamily.size === 0) {
14961
+ paragraphDominantFontFamilyByParagraph.set(paragraph, null);
14959
14962
  return void 0;
14960
14963
  }
14961
14964
  let dominantFamily;
@@ -14966,6 +14969,7 @@ function paragraphDominantFontFamily(paragraph) {
14966
14969
  dominantWeight = weight;
14967
14970
  }
14968
14971
  }
14972
+ paragraphDominantFontFamilyByParagraph.set(paragraph, dominantFamily ?? null);
14969
14973
  return dominantFamily;
14970
14974
  }
14971
14975
  function singleLineAutoScaleForFontFamily(fontFamily) {
@@ -15303,12 +15307,37 @@ function estimateTabLeaderWrappedLineCountForParagraph(paragraph, maxLineWidthPx
15303
15307
  paragraphBaseFontPx
15304
15308
  );
15305
15309
  }
15310
+ var wrappedLineCountByParagraph = /* @__PURE__ */ new WeakMap();
15311
+ function cachedWrappedLineCountForParagraph(paragraph, widthPx) {
15312
+ return wrappedLineCountByParagraph.get(paragraph)?.get(widthPx);
15313
+ }
15314
+ function rememberWrappedLineCountForParagraph(paragraph, widthPx, lineCount) {
15315
+ let countsByWidth = wrappedLineCountByParagraph.get(paragraph);
15316
+ if (!countsByWidth) {
15317
+ countsByWidth = /* @__PURE__ */ new Map();
15318
+ wrappedLineCountByParagraph.set(paragraph, countsByWidth);
15319
+ }
15320
+ countsByWidth.set(widthPx, lineCount);
15321
+ return lineCount;
15322
+ }
15306
15323
  function estimateWrappedLineCountForParagraph(paragraph, availableWidthPx) {
15307
15324
  const paragraphBaseFontPx = paragraphBaseFontSizePx(paragraph);
15308
15325
  const maxLineWidthPx = Math.max(
15309
15326
  paragraphBaseFontPx * 2,
15310
15327
  Math.round(availableWidthPx)
15311
15328
  );
15329
+ const cachedLineCount = cachedWrappedLineCountForParagraph(
15330
+ paragraph,
15331
+ maxLineWidthPx
15332
+ );
15333
+ if (cachedLineCount !== void 0) {
15334
+ return cachedLineCount;
15335
+ }
15336
+ const rememberLineCount = (lineCount2) => rememberWrappedLineCountForParagraph(
15337
+ paragraph,
15338
+ maxLineWidthPx,
15339
+ Math.max(1, Math.round(lineCount2))
15340
+ );
15312
15341
  const tabStopsPx = resolveParagraphTabStopsPx(paragraph);
15313
15342
  const useTabLeaderLayout = paragraphUsesTabLeaders(paragraph);
15314
15343
  const anchoredTabLayout = paragraphAnchoredTabLayout(paragraph);
@@ -15349,7 +15378,7 @@ function estimateWrappedLineCountForParagraph(paragraph, availableWidthPx) {
15349
15378
  return layout?.lineCount;
15350
15379
  })();
15351
15380
  if (pretextPlainLineCount) {
15352
- return Math.max(1, pretextPlainLineCount);
15381
+ return rememberLineCount(pretextPlainLineCount);
15353
15382
  }
15354
15383
  }
15355
15384
  if (useTabLeaderLayout) {
@@ -15359,7 +15388,7 @@ function estimateWrappedLineCountForParagraph(paragraph, availableWidthPx) {
15359
15388
  paragraphBaseFontPx
15360
15389
  );
15361
15390
  if (tabLeaderLineCount !== void 0) {
15362
- return tabLeaderLineCount;
15391
+ return rememberLineCount(tabLeaderLineCount);
15363
15392
  }
15364
15393
  }
15365
15394
  let lineCount = 1;
@@ -15477,7 +15506,7 @@ function estimateWrappedLineCountForParagraph(paragraph, availableWidthPx) {
15477
15506
  commitToken(token, child.style);
15478
15507
  }
15479
15508
  }
15480
- return hasVisibleContent ? Math.max(1, lineCount) : 1;
15509
+ return rememberLineCount(hasVisibleContent ? lineCount : 1);
15481
15510
  }
15482
15511
  function paragraphAvailableTextWidthPx(paragraph, availableWidthPx, numberingDefinitions) {
15483
15512
  const safeAvailableWidthPx = Math.max(24, Math.round(availableWidthPx));
@@ -16030,6 +16059,11 @@ function rowHasDeepFlowContent(row) {
16030
16059
  }
16031
16060
  return nestedTableCount > 0 || blockNodeCount >= SPLITTABLE_TABLE_ROW_DEEP_CONTENT_NODE_THRESHOLD;
16032
16061
  }
16062
+ function rowHasNestedTableContent(row) {
16063
+ return row.cells.some(
16064
+ (cell) => cell.nodes.some((contentNode) => contentNode.type === "table")
16065
+ );
16066
+ }
16033
16067
  function capSplitFriendlyTableRowEstimatePx(row, estimatedRowHeightPx, explicitHeightPx, pageContentHeightPx) {
16034
16068
  if (!rowAllowsPageSplit(row)) {
16035
16069
  return estimatedRowHeightPx;
@@ -16163,6 +16197,280 @@ function estimateTableRowHeightsPx(table, maxAvailableWidthPx, numberingDefiniti
16163
16197
  return Math.max(MIN_PARAGRAPH_LINE_HEIGHT_PX, rowHeightPx);
16164
16198
  });
16165
16199
  }
16200
+ function uniqueSortedPixelBoundaries(values) {
16201
+ const sorted = values.filter((value) => Number.isFinite(value)).map((value) => Math.max(0, Math.round(value))).sort((left, right) => left - right);
16202
+ const unique = [];
16203
+ for (const value of sorted) {
16204
+ const previous = unique[unique.length - 1];
16205
+ if (previous === void 0 || Math.abs(previous - value) > TABLE_ROW_SLICE_BOUNDARY_TOLERANCE_PX) {
16206
+ unique.push(value);
16207
+ }
16208
+ }
16209
+ return unique;
16210
+ }
16211
+ function estimateParagraphBoundaryOffsetsPx(paragraph, availableWidthPx, numberingDefinitions, applyWordTableDefaults, docGridLinePitchPx, paragraphIndex) {
16212
+ const paragraphForLayout = wordLikeTableCellParagraph(
16213
+ paragraph,
16214
+ applyWordTableDefaults
16215
+ );
16216
+ const disableDocGridSnap = paragraphDocGridSnapState(paragraph) === "disable";
16217
+ const paragraphHeightPx = estimateParagraphHeightPx(
16218
+ paragraphForLayout,
16219
+ availableWidthPx,
16220
+ numberingDefinitions,
16221
+ docGridLinePitchPx,
16222
+ disableDocGridSnap
16223
+ );
16224
+ const suppressTopSpacing = paragraphIndex === 0 && suppressFirstTableCellParagraphTopSpacing(paragraph);
16225
+ const beforeSpacingPx = suppressTopSpacing ? 0 : twipsToPixels(paragraphForLayout.style?.spacing?.beforeTwips) ?? 0;
16226
+ const afterSpacingPx = twipsToPixels(paragraphForLayout.style?.spacing?.afterTwips) ?? 0;
16227
+ const topBorderInsetPx = paragraphBorderInsetPx(
16228
+ paragraphForLayout.style?.borders?.top
16229
+ );
16230
+ const bottomBorderInsetPx = paragraphBorderInsetPx(
16231
+ paragraphForLayout.style?.borders?.bottom
16232
+ );
16233
+ const lineHeightPx = Math.max(
16234
+ MIN_PARAGRAPH_LINE_HEIGHT_PX,
16235
+ estimateParagraphLineHeightPx(
16236
+ paragraphForLayout,
16237
+ docGridLinePitchPx,
16238
+ disableDocGridSnap
16239
+ )
16240
+ );
16241
+ const pretextSource = buildParagraphPretextLayoutSource(paragraphForLayout, {
16242
+ allowExplicitLineBreakText: true,
16243
+ expandTabsForLayout: true
16244
+ });
16245
+ const paragraphTextWidthPx = paragraphAvailableTextWidthPx(
16246
+ paragraphForLayout,
16247
+ availableWidthPx,
16248
+ numberingDefinitions
16249
+ );
16250
+ const pretextLayout = pretextSource ? layoutParagraphPretextSource(
16251
+ paragraphForLayout,
16252
+ pretextSource,
16253
+ paragraphTextWidthPx,
16254
+ lineHeightPx,
16255
+ []
16256
+ ) : void 0;
16257
+ const lineTopOffsetsPx = pretextLayout ? pretextLayout.lines.map((line) => Math.max(0, Math.round(line.y))) : Array.from(
16258
+ {
16259
+ length: Math.max(
16260
+ 1,
16261
+ paragraphLineCountWithinWidth(
16262
+ paragraphForLayout,
16263
+ availableWidthPx,
16264
+ numberingDefinitions
16265
+ )
16266
+ )
16267
+ },
16268
+ (_, lineIndex) => lineIndex * lineHeightPx
16269
+ );
16270
+ const textTopPx = beforeSpacingPx + topBorderInsetPx;
16271
+ const textHeightPx = pretextLayout ? wrappedPretextParagraphBlockHeightPx(pretextLayout) : lineTopOffsetsPx.length * lineHeightPx;
16272
+ const visualHeightPx = Math.max(
16273
+ 1,
16274
+ beforeSpacingPx + topBorderInsetPx + textHeightPx + bottomBorderInsetPx + afterSpacingPx
16275
+ );
16276
+ const heightPx = Math.max(1, paragraphHeightPx, visualHeightPx);
16277
+ const lineBoundariesPx = lineTopOffsetsPx.map(
16278
+ (lineTopPx) => textTopPx + lineTopPx + lineHeightPx
16279
+ );
16280
+ return {
16281
+ heightPx,
16282
+ safeBoundariesPx: uniqueSortedPixelBoundaries([
16283
+ ...lineBoundariesPx,
16284
+ heightPx
16285
+ ])
16286
+ };
16287
+ }
16288
+ function estimateNestedTableBoundaryOffsetsPx(table, availableWidthPx, numberingDefinitions, docGridLinePitchPx) {
16289
+ const rowHeightsPx = estimateTableRowHeightsPx(
16290
+ table,
16291
+ availableWidthPx,
16292
+ numberingDefinitions,
16293
+ docGridLinePitchPx
16294
+ );
16295
+ const boundariesPx = [];
16296
+ let cursorPx = 0;
16297
+ for (const rowHeightPx of rowHeightsPx) {
16298
+ cursorPx += Math.max(MIN_PARAGRAPH_LINE_HEIGHT_PX, rowHeightPx);
16299
+ boundariesPx.push(cursorPx);
16300
+ }
16301
+ return {
16302
+ heightPx: Math.max(MIN_PARAGRAPH_LINE_HEIGHT_PX, cursorPx),
16303
+ safeBoundariesPx: uniqueSortedPixelBoundaries(boundariesPx)
16304
+ };
16305
+ }
16306
+ function estimateTableCellSliceBoundaryLayoutPx(params) {
16307
+ const {
16308
+ cell,
16309
+ rowHeightPx,
16310
+ contentWidthPx,
16311
+ tableCellMarginTwips,
16312
+ numberingDefinitions,
16313
+ applyWordTableDefaults,
16314
+ docGridLinePitchPx
16315
+ } = params;
16316
+ const paddingPx = resolveTableSpacingPaddingPx(
16317
+ mergeTableSpacing(tableCellMarginTwips, cell.style?.marginTwips)
16318
+ );
16319
+ const localBoundariesPx = [0, paddingPx.top];
16320
+ let contentCursorPx = paddingPx.top;
16321
+ let paragraphIndex = 0;
16322
+ for (const contentNode of cell.nodes) {
16323
+ const layout = contentNode.type === "paragraph" ? estimateParagraphBoundaryOffsetsPx(
16324
+ contentNode,
16325
+ contentWidthPx,
16326
+ numberingDefinitions,
16327
+ applyWordTableDefaults,
16328
+ docGridLinePitchPx,
16329
+ paragraphIndex++
16330
+ ) : estimateNestedTableBoundaryOffsetsPx(
16331
+ contentNode,
16332
+ contentWidthPx,
16333
+ numberingDefinitions,
16334
+ docGridLinePitchPx
16335
+ );
16336
+ localBoundariesPx.push(
16337
+ ...layout.safeBoundariesPx.map(
16338
+ (boundaryPx) => contentCursorPx + boundaryPx
16339
+ )
16340
+ );
16341
+ contentCursorPx += layout.heightPx;
16342
+ }
16343
+ const contentBottomPx = contentCursorPx + paddingPx.bottom;
16344
+ const contentFlowHeightPx = Math.max(0, contentCursorPx - paddingPx.top);
16345
+ const availableContentHeightPx = Math.max(
16346
+ 0,
16347
+ rowHeightPx - paddingPx.top - paddingPx.bottom
16348
+ );
16349
+ const extraVerticalSpacePx = Math.max(
16350
+ 0,
16351
+ availableContentHeightPx - contentFlowHeightPx
16352
+ );
16353
+ const verticalOffsetPx = cell.style?.verticalAlign === "center" ? Math.round(extraVerticalSpacePx / 2) : cell.style?.verticalAlign === "bottom" ? extraVerticalSpacePx : 0;
16354
+ return {
16355
+ safeBoundariesPx: uniqueSortedPixelBoundaries(
16356
+ localBoundariesPx.map(
16357
+ (boundaryPx) => Math.min(rowHeightPx, boundaryPx + verticalOffsetPx)
16358
+ )
16359
+ ),
16360
+ contentBottomPx: Math.min(rowHeightPx, contentBottomPx + verticalOffsetPx)
16361
+ };
16362
+ }
16363
+ function tableCellSliceBoundaryIsSafe(layout, boundaryPx) {
16364
+ if (boundaryPx <= TABLE_ROW_SLICE_BOUNDARY_TOLERANCE_PX) {
16365
+ return true;
16366
+ }
16367
+ if (boundaryPx >= layout.contentBottomPx - TABLE_ROW_SLICE_BOUNDARY_TOLERANCE_PX) {
16368
+ return true;
16369
+ }
16370
+ return layout.safeBoundariesPx.some(
16371
+ (safeBoundaryPx) => Math.abs(safeBoundaryPx - boundaryPx) <= TABLE_ROW_SLICE_BOUNDARY_TOLERANCE_PX
16372
+ );
16373
+ }
16374
+ function resolveTableRowSliceHeightOnSafeBoundaryPx(params) {
16375
+ const {
16376
+ table,
16377
+ rowIndex,
16378
+ rowHeightPx,
16379
+ rowSliceOffsetPx,
16380
+ preferredSliceHeightPx,
16381
+ maxAvailableWidthPx,
16382
+ numberingDefinitions,
16383
+ docGridLinePitchPx
16384
+ } = params;
16385
+ const row = table.rows[rowIndex];
16386
+ if (!row || !rowHasNestedTableContent(row)) {
16387
+ return preferredSliceHeightPx;
16388
+ }
16389
+ const sliceStartPx = Math.max(0, Math.round(rowSliceOffsetPx));
16390
+ const preferredSliceEndPx = Math.min(
16391
+ rowHeightPx,
16392
+ sliceStartPx + Math.max(0, Math.round(preferredSliceHeightPx))
16393
+ );
16394
+ if (preferredSliceEndPx >= rowHeightPx - TABLE_ROW_SLICE_BOUNDARY_TOLERANCE_PX) {
16395
+ return Math.max(0, rowHeightPx - sliceStartPx);
16396
+ }
16397
+ const columnCount = tableColumnCount(table);
16398
+ const tableWidthPx = twipsToPixels(table.style?.widthTwips);
16399
+ const rawTableColumnWidthsPx = (() => {
16400
+ const definedWidthsTwips = columnWidthsFromTableDefinition(
16401
+ table,
16402
+ columnCount
16403
+ );
16404
+ if (!definedWidthsTwips || definedWidthsTwips.length === 0) {
16405
+ return defaultColumnWidthsPx(columnCount, tableWidthPx);
16406
+ }
16407
+ const widthsPx = definedWidthsTwips.map(
16408
+ (widthTwips) => twipsToPixels(widthTwips) ?? 0
16409
+ );
16410
+ return normalizeColumnWidthsPx(widthsPx, columnCount, tableWidthPx, 1);
16411
+ })();
16412
+ const rawResolvedTableWidthPx = tableWidthPx ?? rawTableColumnWidthsPx.reduce((sum, widthPx) => sum + widthPx, 0);
16413
+ const collapsedHorizontalBorderBleedPx = resolveCollapsedTableHorizontalOuterBleedPx(table, columnCount);
16414
+ const maxTableWidthPx = Number.isFinite(maxAvailableWidthPx) && maxAvailableWidthPx > 0 ? Math.max(
16415
+ 120,
16416
+ maxAvailableWidthPx - collapsedHorizontalBorderBleedPx
16417
+ ) : void 0;
16418
+ const resolvedTableWidthPx = clampTableWidthPx(
16419
+ rawResolvedTableWidthPx,
16420
+ maxTableWidthPx
16421
+ );
16422
+ const tableColumnWidthsPx = fitColumnWidthsToWidth(
16423
+ rawTableColumnWidthsPx,
16424
+ resolvedTableWidthPx
16425
+ );
16426
+ const applyWordTableDefaults = tableUsesWordLikeParagraphDefaults(table);
16427
+ const tableCellMarginTwips = table.style?.cellMarginTwips;
16428
+ const cellLayouts = [];
16429
+ const candidateBoundariesPx = [preferredSliceEndPx];
16430
+ let columnCursor = 0;
16431
+ for (const cell of row.cells) {
16432
+ const colSpanValue = cell.style?.gridSpan && cell.style.gridSpan > 1 ? cell.style.gridSpan : 1;
16433
+ const startColumnIndex = columnCursor;
16434
+ const endColumnIndex = Math.min(
16435
+ columnCount - 1,
16436
+ startColumnIndex + colSpanValue - 1
16437
+ );
16438
+ columnCursor += colSpanValue;
16439
+ const spannedWidthPx = tableColumnWidthsPx.slice(startColumnIndex, endColumnIndex + 1).reduce((sum, widthPx) => sum + widthPx, 0);
16440
+ const fallbackCellWidthPx = resolvedTableWidthPx / Math.max(1, columnCount) * colSpanValue;
16441
+ const cellRenderedWidthPx = twipsToPixels(cell.style?.widthTwips) ?? (spannedWidthPx > 0 ? spannedWidthPx : fallbackCellWidthPx);
16442
+ const cellPaddingPx = resolveTableSpacingPaddingPx(
16443
+ mergeTableSpacing(tableCellMarginTwips, cell.style?.marginTwips)
16444
+ );
16445
+ const cellContentWidthPx = Math.max(
16446
+ 1,
16447
+ cellRenderedWidthPx - cellPaddingPx.left - cellPaddingPx.right
16448
+ );
16449
+ const cellLayout = estimateTableCellSliceBoundaryLayoutPx({
16450
+ cell,
16451
+ rowHeightPx,
16452
+ contentWidthPx: cellContentWidthPx,
16453
+ tableCellMarginTwips,
16454
+ numberingDefinitions,
16455
+ applyWordTableDefaults,
16456
+ docGridLinePitchPx
16457
+ });
16458
+ cellLayouts.push(cellLayout);
16459
+ candidateBoundariesPx.push(...cellLayout.safeBoundariesPx);
16460
+ }
16461
+ const minimumSliceEndPx = sliceStartPx + Math.max(1, MIN_TABLE_ROW_SLICE_REMAINING_HEIGHT_PX);
16462
+ const candidatesPx = uniqueSortedPixelBoundaries(candidateBoundariesPx).filter(
16463
+ (boundaryPx) => boundaryPx >= minimumSliceEndPx && boundaryPx <= preferredSliceEndPx + TABLE_ROW_SLICE_BOUNDARY_TOLERANCE_PX
16464
+ ).sort((left, right) => right - left);
16465
+ for (const candidatePx of candidatesPx) {
16466
+ if (cellLayouts.every(
16467
+ (layout) => tableCellSliceBoundaryIsSafe(layout, candidatePx)
16468
+ )) {
16469
+ return Math.max(0, candidatePx - sliceStartPx);
16470
+ }
16471
+ }
16472
+ return void 0;
16473
+ }
16166
16474
  function estimateTableHeightPx(table, maxAvailableWidthPx, numberingDefinitions, docGridLinePitchPx) {
16167
16475
  const sourceXml = table.sourceXml;
16168
16476
  const widthKey = heightEstimateCacheKeyPx(
@@ -16451,6 +16759,234 @@ function estimateRenderedPageSegmentHeightPx(node, segment, model, availableWidt
16451
16759
  )
16452
16760
  );
16453
16761
  }
16762
+ function resolveParagraphColumnRenderLineRange(paragraph, segment, availableWidthPx, numberingDefinitions, docGridLinePitchPx) {
16763
+ const lineHeightPx = Math.max(
16764
+ 1,
16765
+ segment.paragraphLineRange?.lineHeightPx ?? estimateParagraphLineHeightPx(paragraph, docGridLinePitchPx)
16766
+ );
16767
+ if (segment.paragraphLineRange) {
16768
+ return {
16769
+ ...segment.paragraphLineRange,
16770
+ lineHeightPx
16771
+ };
16772
+ }
16773
+ const paragraphTextWidthPx = paragraphAvailableTextWidthPx(
16774
+ paragraph,
16775
+ availableWidthPx,
16776
+ numberingDefinitions
16777
+ );
16778
+ const pretextSource = buildParagraphPretextLayoutSource(paragraph, {
16779
+ allowExplicitLineBreakText: true,
16780
+ expandTabsForLayout: true
16781
+ });
16782
+ const pretextLayout = pretextSource ? layoutParagraphPretextSource(
16783
+ paragraph,
16784
+ pretextSource,
16785
+ paragraphTextWidthPx,
16786
+ lineHeightPx,
16787
+ []
16788
+ ) : void 0;
16789
+ const totalLineCount = pretextLayout && pretextLayout.lineCount > 0 ? pretextLayout.lineCount : paragraphLineCountWithinWidth(
16790
+ paragraph,
16791
+ availableWidthPx,
16792
+ numberingDefinitions
16793
+ );
16794
+ return {
16795
+ startLineIndex: 0,
16796
+ endLineIndex: Math.max(1, totalLineCount),
16797
+ totalLineCount: Math.max(1, totalLineCount),
16798
+ lineHeightPx
16799
+ };
16800
+ }
16801
+ function splitParagraphSegmentForColumnRender(params) {
16802
+ const {
16803
+ paragraph,
16804
+ segment,
16805
+ model,
16806
+ availableWidthPx,
16807
+ availableHeightPx,
16808
+ numberingDefinitions,
16809
+ docGridLinePitchPx
16810
+ } = params;
16811
+ if (segment.tableRowRange || segment.tableRowSlice || paragraphHasExplicitColumnBreak(paragraph)) {
16812
+ return void 0;
16813
+ }
16814
+ const fullLineRange = resolveParagraphColumnRenderLineRange(
16815
+ paragraph,
16816
+ segment,
16817
+ availableWidthPx,
16818
+ numberingDefinitions,
16819
+ docGridLinePitchPx
16820
+ );
16821
+ const startLineIndex = Math.max(0, fullLineRange.startLineIndex);
16822
+ const endLineIndex = Math.max(startLineIndex, fullLineRange.endLineIndex);
16823
+ if (endLineIndex - startLineIndex < 2 || !paragraphCanSplitAcrossPages(paragraph, fullLineRange.totalLineCount)) {
16824
+ return void 0;
16825
+ }
16826
+ const safeAvailableHeightPx = Math.max(0, Math.round(availableHeightPx));
16827
+ let bestSegment;
16828
+ let bestHeightPx = 0;
16829
+ for (let candidateEndLineIndex = startLineIndex + 1; candidateEndLineIndex < endLineIndex; candidateEndLineIndex += 1) {
16830
+ const candidateSegment = {
16831
+ ...segment,
16832
+ paragraphLineRange: {
16833
+ startLineIndex,
16834
+ endLineIndex: candidateEndLineIndex,
16835
+ totalLineCount: fullLineRange.totalLineCount,
16836
+ lineHeightPx: fullLineRange.lineHeightPx
16837
+ }
16838
+ };
16839
+ const candidateHeightPx = estimateRenderedPageSegmentHeightPx(
16840
+ paragraph,
16841
+ candidateSegment,
16842
+ model,
16843
+ availableWidthPx,
16844
+ numberingDefinitions,
16845
+ docGridLinePitchPx
16846
+ );
16847
+ if (candidateHeightPx > safeAvailableHeightPx + PAGE_OVERFLOW_TOLERANCE_PX) {
16848
+ break;
16849
+ }
16850
+ bestSegment = candidateSegment;
16851
+ bestHeightPx = candidateHeightPx;
16852
+ }
16853
+ if (!bestSegment?.paragraphLineRange) {
16854
+ return void 0;
16855
+ }
16856
+ return {
16857
+ currentSegment: bestSegment,
16858
+ currentHeightPx: bestHeightPx,
16859
+ remainderSegment: {
16860
+ ...segment,
16861
+ paragraphLineRange: {
16862
+ startLineIndex: bestSegment.paragraphLineRange.endLineIndex,
16863
+ endLineIndex,
16864
+ totalLineCount: fullLineRange.totalLineCount,
16865
+ lineHeightPx: fullLineRange.lineHeightPx
16866
+ }
16867
+ }
16868
+ };
16869
+ }
16870
+ function buildRenderColumnSegmentsForPageSection(model, flowSegments, columnWidthsPx, columnHeightPx, numberingDefinitions, docGridLinePitchPxByNodeIndex, measuredParagraphOuterHeightsPxByNodeIndex, balanceColumns = false) {
16871
+ const columnCount = Math.max(1, columnWidthsPx.length);
16872
+ const columns = Array.from(
16873
+ { length: columnCount },
16874
+ () => []
16875
+ );
16876
+ const maxColumnHeightPx = Math.max(120, Math.round(columnHeightPx));
16877
+ const resolveSegmentHeightPx = (segment, columnWidthPx) => {
16878
+ const segmentNode = model.nodes[segment.nodeIndex];
16879
+ if (!segmentNode) {
16880
+ return MIN_PARAGRAPH_LINE_HEIGHT_PX;
16881
+ }
16882
+ const docGridLinePitchPx = docGridLinePitchPxByNodeIndex?.get(
16883
+ segment.nodeIndex
16884
+ );
16885
+ const measuredSegmentHeightPx = segmentNode.type === "paragraph" && !segment.paragraphLineRange && !segment.tableRowRange && !segment.tableRowSlice ? measuredParagraphOuterHeightsPxByNodeIndex?.get(segment.nodeIndex) : void 0;
16886
+ return Number.isFinite(measuredSegmentHeightPx) && measuredSegmentHeightPx > 0 ? Math.max(1, Math.round(measuredSegmentHeightPx)) : estimateRenderedPageSegmentHeightPx(
16887
+ segmentNode,
16888
+ segment,
16889
+ model,
16890
+ columnWidthPx,
16891
+ numberingDefinitions,
16892
+ docGridLinePitchPx
16893
+ );
16894
+ };
16895
+ const safeColumnHeightPx = balanceColumns && columnCount > 1 ? Math.min(
16896
+ maxColumnHeightPx,
16897
+ Math.max(
16898
+ MIN_PARAGRAPH_LINE_HEIGHT_PX * 4,
16899
+ Math.ceil(
16900
+ flowSegments.reduce((totalHeightPx, segment) => {
16901
+ const columnWidthPx = Math.max(
16902
+ 120,
16903
+ Math.round(columnWidthsPx[0] ?? 120)
16904
+ );
16905
+ return totalHeightPx + resolveSegmentHeightPx(segment, columnWidthPx);
16906
+ }, 0) / columnCount
16907
+ ) + PAGE_OVERFLOW_TOLERANCE_PX
16908
+ )
16909
+ ) : maxColumnHeightPx;
16910
+ let columnIndex = 0;
16911
+ let consumedHeightPx = 0;
16912
+ const moveToNextColumn = () => {
16913
+ if (columnIndex + 1 >= columnCount) {
16914
+ return false;
16915
+ }
16916
+ columnIndex += 1;
16917
+ consumedHeightPx = 0;
16918
+ return true;
16919
+ };
16920
+ const pushSegment = (segment, heightPx) => {
16921
+ columns[columnIndex]?.push(segment);
16922
+ consumedHeightPx += Math.max(1, Math.round(heightPx));
16923
+ };
16924
+ for (const flowSegment of flowSegments) {
16925
+ let pendingSegment = flowSegment;
16926
+ let splitGuard = 0;
16927
+ while (pendingSegment && splitGuard < 256) {
16928
+ splitGuard += 1;
16929
+ const currentSegment = pendingSegment;
16930
+ const segmentNode = model.nodes[currentSegment.nodeIndex];
16931
+ if (!segmentNode) {
16932
+ columns[columnIndex]?.push(currentSegment);
16933
+ break;
16934
+ }
16935
+ const columnWidthPx = Math.max(
16936
+ 120,
16937
+ Math.round(columnWidthsPx[columnIndex] ?? columnWidthsPx[0] ?? 120)
16938
+ );
16939
+ const docGridLinePitchPx = docGridLinePitchPxByNodeIndex?.get(
16940
+ currentSegment.nodeIndex
16941
+ );
16942
+ const segmentHeightPx = resolveSegmentHeightPx(
16943
+ currentSegment,
16944
+ columnWidthPx
16945
+ );
16946
+ const remainingHeightPx = Math.max(
16947
+ 0,
16948
+ safeColumnHeightPx - consumedHeightPx
16949
+ );
16950
+ if (segmentHeightPx <= remainingHeightPx + PAGE_OVERFLOW_TOLERANCE_PX || columnIndex + 1 >= columnCount) {
16951
+ pushSegment(currentSegment, segmentHeightPx);
16952
+ pendingSegment = void 0;
16953
+ break;
16954
+ }
16955
+ const splitSegment = segmentNode.type === "paragraph" ? splitParagraphSegmentForColumnRender({
16956
+ paragraph: segmentNode,
16957
+ segment: currentSegment,
16958
+ model,
16959
+ availableWidthPx: columnWidthPx,
16960
+ availableHeightPx: remainingHeightPx,
16961
+ numberingDefinitions,
16962
+ docGridLinePitchPx
16963
+ }) : void 0;
16964
+ if (splitSegment) {
16965
+ pushSegment(splitSegment.currentSegment, splitSegment.currentHeightPx);
16966
+ pendingSegment = splitSegment.remainderSegment;
16967
+ if (!moveToNextColumn()) {
16968
+ const remainderSegment = splitSegment.remainderSegment;
16969
+ const remainderHeightPx = estimateRenderedPageSegmentHeightPx(
16970
+ segmentNode,
16971
+ remainderSegment,
16972
+ model,
16973
+ columnWidthPx,
16974
+ numberingDefinitions,
16975
+ docGridLinePitchPx
16976
+ );
16977
+ pushSegment(remainderSegment, remainderHeightPx);
16978
+ pendingSegment = void 0;
16979
+ }
16980
+ continue;
16981
+ }
16982
+ if (!moveToNextColumn()) {
16983
+ pushSegment(currentSegment, segmentHeightPx);
16984
+ pendingSegment = void 0;
16985
+ }
16986
+ }
16987
+ }
16988
+ return columns;
16989
+ }
16454
16990
  function sumEstimatedTableRowHeightsPx(rowHeightsPx, startRowIndex, endRowIndex) {
16455
16991
  let total = 0;
16456
16992
  const clampedStart = Math.max(0, startRowIndex);
@@ -16924,16 +17460,10 @@ function buildDocumentPageNodeSegments(model, pageContentHeightPx, pageContentWi
16924
17460
  const exactSegmentEndLineIndex = resolveMaxPretextLineRangeEndIndexThatFits(
16925
17461
  pretextLayoutForSegmentSplitting,
16926
17462
  lineCursor,
16927
- Math.min(
16928
- resolvedParagraphLineCount,
16929
- lineCursor + linesThatFit
16930
- ),
17463
+ Math.min(resolvedParagraphLineCount, lineCursor + linesThatFit),
16931
17464
  availableForLinesPx
16932
17465
  );
16933
- linesThatFit = Math.max(
16934
- 0,
16935
- exactSegmentEndLineIndex - lineCursor
16936
- );
17466
+ linesThatFit = Math.max(0, exactSegmentEndLineIndex - lineCursor);
16937
17467
  }
16938
17468
  if (linesThatFit < minLinesPerSegment) {
16939
17469
  if (currentPageSegments.length > 0) {
@@ -16970,10 +17500,7 @@ function buildDocumentPageNodeSegments(model, pageContentHeightPx, pageContentWi
16970
17500
  lineCursor,
16971
17501
  segmentEndLineIndex
16972
17502
  );
16973
- if (topSpacingPx + resolveSegmentContentHeightPx(
16974
- lineCursor,
16975
- segmentEndLineIndex
16976
- ) + segmentReservePx <= remainingHeightPx2) {
17503
+ if (topSpacingPx + resolveSegmentContentHeightPx(lineCursor, segmentEndLineIndex) + segmentReservePx <= remainingHeightPx2) {
16977
17504
  break;
16978
17505
  }
16979
17506
  linesThatFit -= 1;
@@ -17174,6 +17701,7 @@ function buildDocumentPageNodeSegments(model, pageContentHeightPx, pageContentWi
17174
17701
  let rowStartIndex = 0;
17175
17702
  let rowSliceOffsetPx = 0;
17176
17703
  let repeatedHeaderHeightPxOnThisPage = 0;
17704
+ let tableBreakStartRowCursor = 0;
17177
17705
  while (rowStartIndex < estimatedRowHeightsPx.length) {
17178
17706
  if (currentPageSegments.length === 0) {
17179
17707
  repeatedHeaderHeightPxOnThisPage = 0;
@@ -17208,9 +17736,10 @@ function buildDocumentPageNodeSegments(model, pageContentHeightPx, pageContentWi
17208
17736
  currentPageContentHeightPx - repeatedHeaderHeightPxOnThisPage
17209
17737
  );
17210
17738
  const rowExceedsFreshPageHeightPx = currentRowTotalHeightPx > freshPageAvailableHeightPx + PAGE_OVERFLOW_TOLERANCE_PX;
17739
+ const hasUsableCurrentPageSliceSpace = pageConsumedHeightPx > 0 && remainingHeightPx >= MIN_TABLE_ROW_SLICE_REMAINING_HEIGHT_PX;
17211
17740
  const canSplitCurrentRow = rowSliceOffsetPx > 0 || rowAllowsPageSplit(currentRow) || rowExceedsFreshPageHeightPx;
17212
17741
  const shouldContinueExistingRowSlice = rowSliceOffsetPx > 0;
17213
- const rowNeedsSliceOnThisPage = ENABLE_TABLE_ROW_SLICING && canSplitCurrentRow && currentRowRemainingHeightPx > remainingHeightPx + PAGE_OVERFLOW_TOLERANCE_PX && (shouldContinueExistingRowSlice || rowExceedsFreshPageHeightPx);
17742
+ const rowNeedsSliceOnThisPage = ENABLE_TABLE_ROW_SLICING && canSplitCurrentRow && currentRowRemainingHeightPx > remainingHeightPx + PAGE_OVERFLOW_TOLERANCE_PX && (shouldContinueExistingRowSlice || rowExceedsFreshPageHeightPx || hasUsableCurrentPageSliceSpace);
17214
17743
  if (canSplitCurrentRow && currentRowRemainingHeightPx > remainingHeightPx + PAGE_OVERFLOW_TOLERANCE_PX && !rowNeedsSliceOnThisPage && currentPageSegments.length > 0) {
17215
17744
  startNextPage();
17216
17745
  pageConsumedHeightPx = 0;
@@ -17238,10 +17767,38 @@ function buildDocumentPageNodeSegments(model, pageContentHeightPx, pageContentWi
17238
17767
  MIN_PARAGRAPH_LINE_HEIGHT_PX,
17239
17768
  Math.round(remainingHeightPx)
17240
17769
  );
17241
- const sliceHeightPx = Math.max(
17770
+ const preferredSliceHeightPx = Math.max(
17242
17771
  MIN_PARAGRAPH_LINE_HEIGHT_PX,
17243
17772
  Math.min(currentRowRemainingHeightPx, availableSliceHeightPx)
17244
17773
  );
17774
+ const safeSliceHeightPx = resolveTableRowSliceHeightOnSafeBoundaryPx({
17775
+ table: node,
17776
+ rowIndex: rowStartIndex,
17777
+ rowHeightPx: currentRowTotalHeightPx,
17778
+ rowSliceOffsetPx,
17779
+ preferredSliceHeightPx,
17780
+ maxAvailableWidthPx: nodeMetrics.pageContentWidthPx,
17781
+ numberingDefinitions,
17782
+ docGridLinePitchPx: nodeMetrics.docGridLinePitchPx
17783
+ });
17784
+ if (safeSliceHeightPx === void 0 && pageConsumedHeightPx > 0 && currentPageSegments.length > 0) {
17785
+ startNextPage();
17786
+ pageConsumedHeightPx = 0;
17787
+ previousParagraphAfterPx = 0;
17788
+ currentSectionPageFlowOriginPx = 0;
17789
+ currentPageContentHeightPx = resolveMetricsPageContentHeightPx(
17790
+ currentPageIndex,
17791
+ nodeMetrics
17792
+ );
17793
+ continue;
17794
+ }
17795
+ const sliceHeightPx = Math.max(
17796
+ MIN_PARAGRAPH_LINE_HEIGHT_PX,
17797
+ Math.min(
17798
+ currentRowRemainingHeightPx,
17799
+ safeSliceHeightPx ?? preferredSliceHeightPx
17800
+ )
17801
+ );
17245
17802
  currentPageSegments.push({
17246
17803
  nodeIndex,
17247
17804
  tableRowRange: {
@@ -17307,9 +17864,10 @@ function buildDocumentPageNodeSegments(model, pageContentHeightPx, pageContentWi
17307
17864
  pageConsumedHeightPx <= 0
17308
17865
  );
17309
17866
  let rowEndIndex = fittedRowEndIndex;
17310
- const forcedBreakRowIndex = tableBreakStartRows.find(
17311
- (breakRowIndex) => breakRowIndex > rowStartIndex
17312
- );
17867
+ while (tableBreakStartRowCursor < tableBreakStartRows.length && tableBreakStartRows[tableBreakStartRowCursor] <= rowStartIndex) {
17868
+ tableBreakStartRowCursor += 1;
17869
+ }
17870
+ const forcedBreakRowIndex = tableBreakStartRows[tableBreakStartRowCursor];
17313
17871
  if (forcedBreakRowIndex !== void 0) {
17314
17872
  rowEndIndex = Math.min(rowEndIndex, forcedBreakRowIndex);
17315
17873
  }
@@ -17375,6 +17933,19 @@ function buildDocumentPageNodeSegments(model, pageContentHeightPx, pageContentWi
17375
17933
  rowStartIndex = rowEndIndex;
17376
17934
  rowSliceOffsetPx = 0;
17377
17935
  if (rowStartIndex < estimatedRowHeightsPx.length) {
17936
+ const nextRow = node.rows[rowStartIndex];
17937
+ const nextRowHeightPx = Math.max(
17938
+ MIN_PARAGRAPH_LINE_HEIGHT_PX,
17939
+ estimatedRowHeightsPx[rowStartIndex] ?? MIN_PARAGRAPH_LINE_HEIGHT_PX
17940
+ );
17941
+ const remainingHeightAfterSegmentPx = Math.max(
17942
+ 0,
17943
+ currentPageContentHeightPx - pageConsumedHeightPx
17944
+ );
17945
+ const canSliceNextRowOnCurrentPage = ENABLE_TABLE_ROW_SLICING && nextRow !== void 0 && rowAllowsPageSplit(nextRow) && !tableBreakStartRows.includes(rowStartIndex) && remainingHeightAfterSegmentPx >= MIN_TABLE_ROW_SLICE_REMAINING_HEIGHT_PX && nextRowHeightPx > remainingHeightAfterSegmentPx + PAGE_OVERFLOW_TOLERANCE_PX;
17946
+ if (canSliceNextRowOnCurrentPage) {
17947
+ continue;
17948
+ }
17378
17949
  startNextPage();
17379
17950
  pageConsumedHeightPx = 0;
17380
17951
  previousParagraphAfterPx = 0;
@@ -24951,32 +25522,22 @@ function useDocxEditor(options = {}) {
24951
25522
  return;
24952
25523
  }
24953
25524
  setIsImporting(true);
24954
- setStatus(`Loading ${file.name}\u2026`);
24955
- await new Promise((resolve) => {
24956
- if (typeof requestAnimationFrame === "function") {
24957
- requestAnimationFrame(() => {
24958
- requestAnimationFrame(() => resolve());
24959
- });
24960
- } else {
24961
- setTimeout(resolve, 0);
24962
- }
24963
- });
25525
+ setStatus(`Loading ${file.name}...`);
24964
25526
  try {
24965
25527
  const buffer = await file.arrayBuffer();
24966
- const { pkg, model: nextModel } = await importDocxViaWorker(buffer);
25528
+ const pkg = await parseDocx(buffer);
24967
25529
  await loadEmbeddedFontsFromPackage(pkg);
24968
- React.startTransition(() => {
24969
- setModel(nextModel);
24970
- setDocumentLoadNonce((current) => current + 1);
24971
- setHistory({ past: [], future: [] });
24972
- setHistoryRestoreRequest(void 0);
24973
- setBasePackage(pkg);
24974
- setFileName(file.name);
24975
- setSelection({ kind: "paragraph", nodeIndex: 0 });
24976
- setActiveTextRangeState(void 0);
24977
- setPendingRunStyle(void 0);
24978
- setSelectedFormFieldLocation(void 0);
24979
- });
25530
+ const nextModel = buildDocModel(pkg);
25531
+ setModel(nextModel);
25532
+ setDocumentLoadNonce((current) => current + 1);
25533
+ setHistory({ past: [], future: [] });
25534
+ setHistoryRestoreRequest(void 0);
25535
+ setBasePackage(pkg);
25536
+ setFileName(file.name);
25537
+ setSelection({ kind: "paragraph", nodeIndex: 0 });
25538
+ setActiveTextRangeState(void 0);
25539
+ setPendingRunStyle(void 0);
25540
+ setSelectedFormFieldLocation(void 0);
24980
25541
  setStatus(`Loaded ${file.name}`);
24981
25542
  } catch (error) {
24982
25543
  setStatus(
@@ -29473,7 +30034,7 @@ function DocxEditorViewer({
29473
30034
  style,
29474
30035
  pageBackgroundColor,
29475
30036
  pageGapBackgroundColor,
29476
- deferInitialPaginationPaint = true,
30037
+ deferInitialPaginationPaint = false,
29477
30038
  loadingState,
29478
30039
  pageVirtualization,
29479
30040
  visiblePageRange,
@@ -29534,6 +30095,10 @@ function DocxEditorViewer({
29534
30095
  const paragraphElementsRef = React.useRef(
29535
30096
  /* @__PURE__ */ new Map()
29536
30097
  );
30098
+ const [
30099
+ measuredParagraphOuterHeightsPxByNodeIndex,
30100
+ setMeasuredParagraphOuterHeightsPxByNodeIndex
30101
+ ] = React.useState(() => /* @__PURE__ */ new Map());
29537
30102
  const tableCellEditorElementsRef = React.useRef(
29538
30103
  /* @__PURE__ */ new Map()
29539
30104
  );
@@ -29808,6 +30373,9 @@ function DocxEditorViewer({
29808
30373
  const paginationMeasurementResumeTimeoutRef = React.useRef(
29809
30374
  null
29810
30375
  );
30376
+ React.useLayoutEffect(() => {
30377
+ setMeasuredParagraphOuterHeightsPxByNodeIndex(/* @__PURE__ */ new Map());
30378
+ }, [editor.documentLoadNonce, paragraphStructureEpoch]);
29811
30379
  const schedulePaginationMeasurementResume = React.useCallback(
29812
30380
  (delayMs) => {
29813
30381
  if (typeof window === "undefined") {
@@ -30020,10 +30588,20 @@ function DocxEditorViewer({
30020
30588
  () => buildPaginationSectionMetrics(documentSections, documentLayout),
30021
30589
  [documentLayout, documentSections]
30022
30590
  );
30023
- const docGridLinePitchPxByNodeIndex = React.useMemo(() => {
30591
+ const {
30592
+ docGridLinePitchPxByNodeIndex,
30593
+ pageContentWidthPxByNodeIndex,
30594
+ pageContentHeightPxByNodeIndex
30595
+ } = React.useMemo(() => {
30024
30596
  const pitchByNodeIndex = /* @__PURE__ */ new Map();
30597
+ const widthByNodeIndex = /* @__PURE__ */ new Map();
30598
+ const heightByNodeIndex = /* @__PURE__ */ new Map();
30025
30599
  if (editor.model.nodes.length === 0 || paginationSectionMetrics.length === 0) {
30026
- return pitchByNodeIndex;
30600
+ return {
30601
+ docGridLinePitchPxByNodeIndex: pitchByNodeIndex,
30602
+ pageContentWidthPxByNodeIndex: widthByNodeIndex,
30603
+ pageContentHeightPxByNodeIndex: heightByNodeIndex
30604
+ };
30027
30605
  }
30028
30606
  let currentMetricsIndex = 0;
30029
30607
  for (let nodeIndex = 0; nodeIndex < editor.model.nodes.length; nodeIndex += 1) {
@@ -30032,51 +30610,22 @@ function DocxEditorViewer({
30032
30610
  nodeIndex,
30033
30611
  currentMetricsIndex
30034
30612
  );
30035
- const docGridLinePitchPx = paginationSectionMetrics[currentMetricsIndex]?.docGridLinePitchPx;
30613
+ const nodeMetrics = paginationSectionMetrics[currentMetricsIndex];
30614
+ const docGridLinePitchPx = nodeMetrics?.docGridLinePitchPx;
30036
30615
  if (Number.isFinite(docGridLinePitchPx) && docGridLinePitchPx > 0) {
30037
30616
  pitchByNodeIndex.set(
30038
30617
  nodeIndex,
30039
30618
  Math.round(docGridLinePitchPx)
30040
30619
  );
30041
30620
  }
30042
- }
30043
- return pitchByNodeIndex;
30044
- }, [editor.model.nodes, paginationSectionMetrics]);
30045
- const pageContentWidthPxByNodeIndex = React.useMemo(() => {
30046
- const widthByNodeIndex = /* @__PURE__ */ new Map();
30047
- if (editor.model.nodes.length === 0 || paginationSectionMetrics.length === 0) {
30048
- return widthByNodeIndex;
30049
- }
30050
- let currentMetricsIndex = 0;
30051
- for (let nodeIndex = 0; nodeIndex < editor.model.nodes.length; nodeIndex += 1) {
30052
- currentMetricsIndex = resolvePaginationSectionMetricsIndexForNodeIndex(
30053
- paginationSectionMetrics,
30054
- nodeIndex,
30055
- currentMetricsIndex
30056
- );
30057
- const pageContentWidthPx = paginationSectionMetrics[currentMetricsIndex]?.pageContentWidthPx;
30621
+ const pageContentWidthPx = nodeMetrics?.pageContentWidthPx;
30058
30622
  if (Number.isFinite(pageContentWidthPx) && pageContentWidthPx > 0) {
30059
30623
  widthByNodeIndex.set(
30060
30624
  nodeIndex,
30061
30625
  Math.round(pageContentWidthPx)
30062
30626
  );
30063
30627
  }
30064
- }
30065
- return widthByNodeIndex;
30066
- }, [editor.model.nodes, paginationSectionMetrics]);
30067
- const pageContentHeightPxByNodeIndex = React.useMemo(() => {
30068
- const heightByNodeIndex = /* @__PURE__ */ new Map();
30069
- if (editor.model.nodes.length === 0 || paginationSectionMetrics.length === 0) {
30070
- return heightByNodeIndex;
30071
- }
30072
- let currentMetricsIndex = 0;
30073
- for (let nodeIndex = 0; nodeIndex < editor.model.nodes.length; nodeIndex += 1) {
30074
- currentMetricsIndex = resolvePaginationSectionMetricsIndexForNodeIndex(
30075
- paginationSectionMetrics,
30076
- nodeIndex,
30077
- currentMetricsIndex
30078
- );
30079
- const pageContentHeightPx = paginationSectionMetrics[currentMetricsIndex]?.pageContentHeightPx;
30628
+ const pageContentHeightPx = nodeMetrics?.pageContentHeightPx;
30080
30629
  if (Number.isFinite(pageContentHeightPx) && pageContentHeightPx > 0) {
30081
30630
  heightByNodeIndex.set(
30082
30631
  nodeIndex,
@@ -30084,7 +30633,11 @@ function DocxEditorViewer({
30084
30633
  );
30085
30634
  }
30086
30635
  }
30087
- return heightByNodeIndex;
30636
+ return {
30637
+ docGridLinePitchPxByNodeIndex: pitchByNodeIndex,
30638
+ pageContentWidthPxByNodeIndex: widthByNodeIndex,
30639
+ pageContentHeightPxByNodeIndex: heightByNodeIndex
30640
+ };
30088
30641
  }, [editor.model.nodes, paginationSectionMetrics]);
30089
30642
  const sectionColumnsBySectionIndex = React.useMemo(
30090
30643
  () => documentSections.map(
@@ -30236,11 +30789,11 @@ function DocxEditorViewer({
30236
30789
  renderPageContentHeightScale: estimatedRenderPageContentHeightScale
30237
30790
  };
30238
30791
  }
30239
- const pureEstimatedPages = buildEstimatedPages(
30240
- tableMeasuredRowHeightsForPagination,
30241
- null
30242
- );
30243
30792
  if (measuredPageContentHeightByIndex && measuredPageContentHeightByIndex.length > 0) {
30793
+ const pureEstimatedPages = buildEstimatedPages(
30794
+ tableMeasuredRowHeightsForPagination,
30795
+ null
30796
+ );
30244
30797
  const measuredPagesAreOnlySplitParagraphs = estimatedPages.length > 0 && estimatedPages.every(
30245
30798
  (pageSegments) => documentPageContainsOnlySplitParagraphSegments(pageSegments)
30246
30799
  );
@@ -30287,9 +30840,9 @@ function DocxEditorViewer({
30287
30840
  estimatedRenderMeasuredPageContentHeightsPxByPageIndex = bestCandidate.renderMeasuredPageContentHeightsPxByPageIndex;
30288
30841
  estimatedRenderPageContentHeightScale = bestCandidate.renderPageContentHeightScale;
30289
30842
  } else if (!editor.canUndo && !editor.canRedo && targetPageCount !== void 0 && !hasMultiColumnRenderedPageBreakHints) {
30290
- const pureEstimatedPages2 = buildEstimatedPages(void 0, null);
30291
- if (Math.abs(pureEstimatedPages2.length - targetPageCount) < Math.abs(estimatedPages.length - targetPageCount)) {
30292
- estimatedPages = pureEstimatedPages2;
30843
+ const pureEstimatedPages = buildEstimatedPages(void 0, null);
30844
+ if (Math.abs(pureEstimatedPages.length - targetPageCount) < Math.abs(estimatedPages.length - targetPageCount)) {
30845
+ estimatedPages = pureEstimatedPages;
30293
30846
  estimatedPagesUseMeasuredPageContentHeightsForRender = false;
30294
30847
  estimatedRenderMeasuredPageContentHeightsPxByPageIndex = void 0;
30295
30848
  estimatedRenderPageContentHeightScale = void 0;
@@ -30409,9 +30962,9 @@ function DocxEditorViewer({
30409
30962
  ) : void 0;
30410
30963
  let reconciledRenderPageContentHeightScale = reconciledPagesUseMeasuredPageContentHeightsForRender ? void 0 : reconciledCandidate.scale;
30411
30964
  if (!editor.canUndo && !editor.canRedo) {
30412
- const pureEstimatedPages2 = buildEstimatedPages(void 0, null);
30965
+ const pureEstimatedPages = buildEstimatedPages(void 0, null);
30413
30966
  const pureReconciledCandidate = reconcileCandidatePages(
30414
- pureEstimatedPages2,
30967
+ pureEstimatedPages,
30415
30968
  void 0,
30416
30969
  null
30417
30970
  );
@@ -30782,7 +31335,7 @@ function DocxEditorViewer({
30782
31335
  Number.isFinite(pageVirtualization?.overscan) ? pageVirtualization?.overscan : DEFAULT_PAGE_VIRTUALIZATION_OVERSCAN
30783
31336
  )
30784
31337
  );
30785
- const pageVirtualizationOverscan = hasLargeTableLayoutSurface && !Number.isFinite(pageVirtualization?.overscan) ? 0 : rawPageVirtualizationOverscan;
31338
+ const pageVirtualizationOverscan = hasLargeTableLayoutSurface && !Number.isFinite(pageVirtualization?.overscan) ? LARGE_TABLE_PAGE_VIRTUALIZATION_OVERSCAN : rawPageVirtualizationOverscan;
30786
31339
  const webdriverActive = typeof navigator !== "undefined" && navigator.webdriver === true;
30787
31340
  const internalPageVirtualizationRequested = pageVirtualization?.enabled !== false && !hasExternalVisiblePageRange && !hideDocumentUntilPaginationSettled && isInitialPaginationSettled && !deferInternalPageVirtualization && !webdriverActive && pageCount > 1;
30788
31341
  React.useEffect(() => {
@@ -30877,8 +31430,40 @@ function DocxEditorViewer({
30877
31430
  endPageIndex
30878
31431
  };
30879
31432
  }, [internalPageVirtualizationEnabled, internalVirtualItems, pageCount]);
31433
+ const internalRenderVisiblePageRange = React.useMemo(() => {
31434
+ if (!internalVisiblePageRange) {
31435
+ return void 0;
31436
+ }
31437
+ if (!hasLargeTableLayoutSurface || Number.isFinite(pageVirtualization?.overscan)) {
31438
+ return internalVisiblePageRange;
31439
+ }
31440
+ const scrollDirection = internalPageVirtualizer.scrollDirection;
31441
+ const renderPreviousPage = scrollDirection !== "backward";
31442
+ const renderNextPage = scrollDirection === "backward";
31443
+ const startPageIndex = clampNumber(
31444
+ internalVisiblePageRange.startPageIndex - (renderPreviousPage ? LARGE_TABLE_PAGE_ADJACENT_RENDER_COUNT : 0),
31445
+ 0,
31446
+ pageCount - 1
31447
+ );
31448
+ const endPageIndex = clampNumber(
31449
+ internalVisiblePageRange.endPageIndex + (renderNextPage ? LARGE_TABLE_PAGE_ADJACENT_RENDER_COUNT : 0),
31450
+ startPageIndex,
31451
+ pageCount - 1
31452
+ );
31453
+ return {
31454
+ startPageIndex,
31455
+ endPageIndex
31456
+ };
31457
+ }, [
31458
+ hasLargeTableLayoutSurface,
31459
+ internalPageVirtualizer.scrollDirection,
31460
+ internalVisiblePageRange,
31461
+ pageCount,
31462
+ pageVirtualization?.overscan
31463
+ ]);
31464
+ const shouldObserveVisiblePageRange = hasLargeTableLayoutSurface || internalVirtualItems.length === 0;
30880
31465
  React.useLayoutEffect(() => {
30881
- if (!internalPageVirtualizationEnabled || !internalVirtualScrollElement || typeof window === "undefined") {
31466
+ if (!internalPageVirtualizationEnabled || !internalVirtualScrollElement || !shouldObserveVisiblePageRange || typeof window === "undefined") {
30882
31467
  setObservedVisiblePageRange(
30883
31468
  (current) => current === void 0 ? current : void 0
30884
31469
  );
@@ -30892,6 +31477,15 @@ function DocxEditorViewer({
30892
31477
  return;
30893
31478
  }
30894
31479
  let frameId = null;
31480
+ const commitObservedVisiblePageRange = (updater) => {
31481
+ if (hasLargeTableLayoutSurface) {
31482
+ (0, import_react_dom.flushSync)(() => {
31483
+ setObservedVisiblePageRange(updater);
31484
+ });
31485
+ return;
31486
+ }
31487
+ setObservedVisiblePageRange(updater);
31488
+ };
30895
31489
  const syncVisiblePageRange = () => {
30896
31490
  frameId = null;
30897
31491
  const viewportRect = internalVirtualScrollUsesWindow ? {
@@ -30925,7 +31519,7 @@ function DocxEditorViewer({
30925
31519
  lastVisiblePageIndex = pageIndex;
30926
31520
  }
30927
31521
  if (firstVisiblePageIndex === void 0 || lastVisiblePageIndex === void 0) {
30928
- setObservedVisiblePageRange(
31522
+ commitObservedVisiblePageRange(
30929
31523
  (current) => current === void 0 ? current : void 0
30930
31524
  );
30931
31525
  return;
@@ -30940,7 +31534,7 @@ function DocxEditorViewer({
30940
31534
  startPageIndex,
30941
31535
  pageCount - 1
30942
31536
  );
30943
- setObservedVisiblePageRange((current) => {
31537
+ commitObservedVisiblePageRange((current) => {
30944
31538
  if (current?.startPageIndex === startPageIndex && current?.endPageIndex === endPageIndex) {
30945
31539
  return current;
30946
31540
  }
@@ -30992,13 +31586,42 @@ function DocxEditorViewer({
30992
31586
  }
30993
31587
  };
30994
31588
  }, [
31589
+ hasLargeTableLayoutSurface,
30995
31590
  internalPageVirtualizationEnabled,
31591
+ internalVirtualItems.length,
30996
31592
  internalVirtualScrollElement,
30997
31593
  internalVirtualScrollUsesWindow,
30998
31594
  pageCount,
30999
- pageVirtualizationOverscan
31595
+ pageVirtualizationOverscan,
31596
+ shouldObserveVisiblePageRange
31000
31597
  ]);
31001
- const effectiveVisiblePageRange = visiblePageRange ?? observedVisiblePageRange ?? internalVisiblePageRange ?? (internalPageVirtualizationPending ? {
31598
+ const internalEffectiveRenderVisiblePageRange = React.useMemo(() => {
31599
+ if (!internalRenderVisiblePageRange) {
31600
+ return observedVisiblePageRange;
31601
+ }
31602
+ if (!observedVisiblePageRange || !hasLargeTableLayoutSurface) {
31603
+ return internalRenderVisiblePageRange;
31604
+ }
31605
+ const rangesAreAdjacentOrOverlapping = observedVisiblePageRange.startPageIndex <= internalRenderVisiblePageRange.endPageIndex + 2 && internalRenderVisiblePageRange.startPageIndex <= observedVisiblePageRange.endPageIndex + 2;
31606
+ if (!rangesAreAdjacentOrOverlapping) {
31607
+ return internalRenderVisiblePageRange;
31608
+ }
31609
+ return {
31610
+ startPageIndex: Math.min(
31611
+ internalRenderVisiblePageRange.startPageIndex,
31612
+ observedVisiblePageRange.startPageIndex
31613
+ ),
31614
+ endPageIndex: Math.max(
31615
+ internalRenderVisiblePageRange.endPageIndex,
31616
+ observedVisiblePageRange.endPageIndex
31617
+ )
31618
+ };
31619
+ }, [
31620
+ hasLargeTableLayoutSurface,
31621
+ internalRenderVisiblePageRange,
31622
+ observedVisiblePageRange
31623
+ ]);
31624
+ const effectiveVisiblePageRange = visiblePageRange ?? internalEffectiveRenderVisiblePageRange ?? observedVisiblePageRange ?? (internalPageVirtualizationPending ? {
31002
31625
  startPageIndex: 0,
31003
31626
  endPageIndex: Math.min(
31004
31627
  pageCount - 1,
@@ -31047,6 +31670,43 @@ function DocxEditorViewer({
31047
31670
  }
31048
31671
  return indexes;
31049
31672
  }, [pageCount, visiblePageEndIndex, visiblePageStartIndex]);
31673
+ React.useLayoutEffect(() => {
31674
+ if (typeof window === "undefined") {
31675
+ return;
31676
+ }
31677
+ setMeasuredParagraphOuterHeightsPxByNodeIndex((current) => {
31678
+ const next = new Map(current);
31679
+ let changed = false;
31680
+ paragraphElementsRef.current.forEach((element, nodeIndex) => {
31681
+ if (!element.isConnected || element.dataset.docxParagraphPartialLineRange === "true" || element.closest('[data-docx-header-footer-region="footer"]') || element.closest('[data-docx-header-footer-region="header"]')) {
31682
+ return;
31683
+ }
31684
+ const rect = element.getBoundingClientRect();
31685
+ if (rect.width <= 0 && rect.height <= 0) {
31686
+ return;
31687
+ }
31688
+ const style2 = window.getComputedStyle(element);
31689
+ const marginTop = Number.parseFloat(style2.marginTop || "0");
31690
+ const marginBottom = Number.parseFloat(style2.marginBottom || "0");
31691
+ const outerHeightPx = Math.max(
31692
+ 1,
31693
+ Math.round(
31694
+ rect.height + (Number.isFinite(marginTop) ? marginTop : 0) + (Number.isFinite(marginBottom) ? marginBottom : 0)
31695
+ )
31696
+ );
31697
+ if (next.get(nodeIndex) !== outerHeightPx) {
31698
+ next.set(nodeIndex, outerHeightPx);
31699
+ changed = true;
31700
+ }
31701
+ });
31702
+ return changed ? next : current;
31703
+ });
31704
+ }, [
31705
+ editor.documentLoadNonce,
31706
+ pageNodeSegmentIdentityKeysByPage,
31707
+ visiblePageEndIndex,
31708
+ visiblePageStartIndex
31709
+ ]);
31050
31710
  const visibleTableRowIndexesByNodeIndex = React.useMemo(() => {
31051
31711
  const rowsByNodeIndex = /* @__PURE__ */ new Map();
31052
31712
  const addRowIndex = (nodeIndex, rowIndex) => {
@@ -31121,7 +31781,8 @@ function DocxEditorViewer({
31121
31781
  tableMeasuredRowHeights,
31122
31782
  visiblePageIndexes
31123
31783
  ]);
31124
- const visiblePagesNeedMeasurementUnlock = !hideDocumentUntilPaginationSettled && visiblePagesHavePendingPaginationMeasurements;
31784
+ const allowPostImportPaginationMeasurement = !hasLargeTableLayoutSurface || !internalPageVirtualizationEnabled;
31785
+ const visiblePagesNeedMeasurementUnlock = !hideDocumentUntilPaginationSettled && allowPostImportPaginationMeasurement && visiblePagesHavePendingPaginationMeasurements;
31125
31786
  React.useEffect(() => {
31126
31787
  if (!visiblePagesNeedMeasurementUnlock) {
31127
31788
  return;
@@ -31186,7 +31847,13 @@ function DocxEditorViewer({
31186
31847
  rootElement.querySelectorAll(
31187
31848
  '[data-docx-page-wrapper="true"][data-index]'
31188
31849
  )
31189
- );
31850
+ ).filter((element) => {
31851
+ const pageIndex = Number.parseInt(
31852
+ element.getAttribute("data-index") ?? "",
31853
+ 10
31854
+ );
31855
+ return Number.isFinite(pageIndex) && pageIndex >= visiblePageStartIndex && pageIndex <= visiblePageEndIndex;
31856
+ });
31190
31857
  const nextElements = new Set(pageWrappers);
31191
31858
  observedElements.forEach((element) => {
31192
31859
  if (!nextElements.has(element)) {
@@ -31222,7 +31889,9 @@ function DocxEditorViewer({
31222
31889
  internalPageVirtualizationEnabled,
31223
31890
  internalPageVirtualizer,
31224
31891
  internalVirtualScrollElement,
31225
- pageCount
31892
+ pageCount,
31893
+ visiblePageEndIndex,
31894
+ visiblePageStartIndex
31226
31895
  ]);
31227
31896
  React.useEffect(() => {
31228
31897
  if (!internalPageVirtualizationEnabled) {
@@ -31735,11 +32404,18 @@ function DocxEditorViewer({
31735
32404
  const nextMeasuredPageDiagnostics = pageNodeSegmentsByPage.map(
31736
32405
  (_, pageIndex) => {
31737
32406
  const pageLayout = pageSectionInfoByIndex[pageIndex]?.layout ?? documentLayout;
31738
- const pageElement = pageElementsRef.current.get(pageIndex);
31739
32407
  const fallbackHeightPx = Math.max(
31740
32408
  120,
31741
32409
  pageLayout.pageHeightPx - pageLayout.marginsPx.top - pageLayout.marginsPx.bottom
31742
32410
  );
32411
+ const pageIsVisible = pageIndex >= visiblePageStartIndex && pageIndex <= visiblePageEndIndex;
32412
+ if (!pageIsVisible) {
32413
+ return {
32414
+ heightPx: measuredPageContentHeightByIndex?.[pageIndex] ?? fallbackHeightPx,
32415
+ bodyOverrunsFooter: false
32416
+ };
32417
+ }
32418
+ const pageElement = pageElementsRef.current.get(pageIndex);
31743
32419
  if (!pageElement) {
31744
32420
  return {
31745
32421
  heightPx: fallbackHeightPx,
@@ -31932,7 +32608,9 @@ function DocxEditorViewer({
31932
32608
  pageNodeSegmentsByPage,
31933
32609
  pageNodeSegmentIdentityKeysByPage,
31934
32610
  pageSectionInfoByIndex,
31935
- pageHeaderAndFooterNodes
32611
+ pageHeaderAndFooterNodes,
32612
+ visiblePageEndIndex,
32613
+ visiblePageStartIndex
31936
32614
  ]);
31937
32615
  React.useEffect(() => {
31938
32616
  if (!deferInitialPaginationPaint || isInitialPaginationSettled || disableMeasuredImportPagination) {
@@ -41076,11 +41754,17 @@ function DocxEditorViewer({
41076
41754
  } : void 0,
41077
41755
  outline: "none"
41078
41756
  };
41079
- const fallbackParagraphRuns = renderInteractiveParagraphRuns(
41080
- paragraph,
41081
- `body-cell-${tableIndex}-${rowIndex}-${cellIndex}-${contentIndex}`,
41082
- location
41083
- );
41757
+ let fallbackParagraphRuns;
41758
+ const getFallbackParagraphRuns = () => {
41759
+ if (fallbackParagraphRuns === void 0) {
41760
+ fallbackParagraphRuns = renderInteractiveParagraphRuns(
41761
+ paragraph,
41762
+ `body-cell-${tableIndex}-${rowIndex}-${cellIndex}-${contentIndex}`,
41763
+ location
41764
+ );
41765
+ }
41766
+ return fallbackParagraphRuns;
41767
+ };
41084
41768
  const renderedInteractiveParagraphContent = shouldRenderParagraphSegmentWithPretext ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
41085
41769
  "div",
41086
41770
  {
@@ -41118,11 +41802,11 @@ function DocxEditorViewer({
41118
41802
  style: {
41119
41803
  transform: `translateY(-${paragraphSegmentTranslateYPx - paragraphSegmentClipBleedTopPx}px)`
41120
41804
  },
41121
- children: fallbackParagraphRuns
41805
+ children: getFallbackParagraphRuns()
41122
41806
  }
41123
41807
  )
41124
41808
  }
41125
- ) : fallbackParagraphRuns;
41809
+ ) : getFallbackParagraphRuns();
41126
41810
  return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
41127
41811
  "div",
41128
41812
  {
@@ -41364,6 +42048,7 @@ function DocxEditorViewer({
41364
42048
  ...resolvedAfterSpacingPx !== void 0 ? { marginBottom: resolvedAfterSpacingPx } : void 0
41365
42049
  } : void 0,
41366
42050
  ...letterheadStyleAdjustments ?? void 0,
42051
+ ...options?.normalizeParagraphHostFontSize ? { fontSize: `${paragraphBaseFontSizePx(node)}px` } : void 0,
41367
42052
  ...options?.suppressLetterheadColumnLayout && options?.isFirstInLetterheadColumn ? { marginTop: 0 } : void 0,
41368
42053
  ...pageAbsoluteAnchorOnlyParagraph ? {
41369
42054
  position: "relative",
@@ -41382,19 +42067,25 @@ function DocxEditorViewer({
41382
42067
  } : void 0,
41383
42068
  outline: "none"
41384
42069
  };
41385
- const fallbackParagraphRuns = renderInteractiveParagraphRuns(
41386
- node,
41387
- `node-${nodeIndex}`,
41388
- {
41389
- kind: "paragraph",
41390
- nodeIndex
41391
- },
41392
- {
41393
- pageFlowTopPx: paragraphPageFlowTopPx,
41394
- pageLayout: resolvedPageLayout,
41395
- suppressLikelyFullPageCoverImageKeys: options?.suppressLikelyFullPageCoverImageKeys
42070
+ let fallbackParagraphRuns;
42071
+ const getFallbackParagraphRuns = () => {
42072
+ if (fallbackParagraphRuns === void 0) {
42073
+ fallbackParagraphRuns = renderInteractiveParagraphRuns(
42074
+ node,
42075
+ `node-${nodeIndex}`,
42076
+ {
42077
+ kind: "paragraph",
42078
+ nodeIndex
42079
+ },
42080
+ {
42081
+ pageFlowTopPx: paragraphPageFlowTopPx,
42082
+ pageLayout: resolvedPageLayout,
42083
+ suppressLikelyFullPageCoverImageKeys: options?.suppressLikelyFullPageCoverImageKeys
42084
+ }
42085
+ );
41396
42086
  }
41397
- );
42087
+ return fallbackParagraphRuns;
42088
+ };
41398
42089
  const renderedInteractiveParagraphContent = shouldRenderParagraphSegmentWithPretext ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
41399
42090
  "div",
41400
42091
  {
@@ -41435,11 +42126,11 @@ function DocxEditorViewer({
41435
42126
  style: {
41436
42127
  transform: `translateY(-${paragraphSegmentTranslateYPx - paragraphSegmentClipBleedTopPx}px)`
41437
42128
  },
41438
- children: fallbackParagraphRuns
42129
+ children: getFallbackParagraphRuns()
41439
42130
  }
41440
42131
  )
41441
42132
  }
41442
- ) : fallbackParagraphRuns;
42133
+ ) : getFallbackParagraphRuns();
41443
42134
  const paragraphDraftHtml = paragraphDraftsRef.current.get(nodeIndex);
41444
42135
  const renderedEditableParagraphHtml = typeof paragraphDraftHtml === "string" ? paragraphDraftHtml : renderStaticHtml(renderedInteractiveParagraphContent);
41445
42136
  return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
@@ -41450,6 +42141,7 @@ function DocxEditorViewer({
41450
42141
  "data-docx-paragraph-node-index": nodeIndex,
41451
42142
  "data-docx-paragraph-start-line": paragraphSegmentStartLine,
41452
42143
  "data-docx-paragraph-end-line": paragraphSegmentEndLine,
42144
+ "data-docx-paragraph-partial-line-range": hasPartialLineRange ? "true" : void 0,
41453
42145
  style: paragraphStyle,
41454
42146
  dangerouslySetInnerHTML: editable ? {
41455
42147
  __html: renderedEditableParagraphHtml
@@ -42487,6 +43179,68 @@ ${currentText.slice(end)}`;
42487
43179
  })() : void 0;
42488
43180
  const tableCellDraftHtml = tableCellDraftsRef.current.get(cellDraftKey);
42489
43181
  const renderedEditableCellHtml = editableCell ? typeof tableCellDraftHtml === "string" ? tableCellDraftHtml : renderStaticHtml(renderedEditableCellContent) : void 0;
43182
+ const renderStaticCellContent = () => {
43183
+ let paragraphCursor = 0;
43184
+ return cell.nodes.map(
43185
+ (cellContent, contentIndex) => {
43186
+ if (cellContent.type === "paragraph") {
43187
+ const paragraphIndex = paragraphCursor;
43188
+ paragraphCursor += 1;
43189
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
43190
+ "div",
43191
+ {
43192
+ "data-docx-paragraph-host": "true",
43193
+ "data-docx-paragraph-kind": "table-cell",
43194
+ "data-docx-table-index": nodeIndex,
43195
+ "data-docx-row-index": rowIndex,
43196
+ "data-docx-cell-index": cellIndex,
43197
+ "data-docx-paragraph-index": paragraphIndex,
43198
+ "data-docx-table-paragraph-index": paragraphIndex,
43199
+ style: tableCellParagraphBlockStyle(
43200
+ cellContent,
43201
+ editor.model.metadata.numberingDefinitions,
43202
+ headingStyles,
43203
+ paragraphIndex,
43204
+ applyWordTableDefaults,
43205
+ nodeDocGridLinePitchPx
43206
+ ),
43207
+ children: renderInteractiveParagraphRuns(
43208
+ cellContent,
43209
+ `body-cell-${nodeIndex}-${rowIndex}-${cellIndex}-${contentIndex}`,
43210
+ {
43211
+ kind: "table-cell",
43212
+ tableIndex: nodeIndex,
43213
+ rowIndex,
43214
+ cellIndex,
43215
+ paragraphIndex
43216
+ }
43217
+ )
43218
+ },
43219
+ `body-cell-p-${nodeIndex}-${rowIndex}-${cellIndex}-${contentIndex}`
43220
+ );
43221
+ }
43222
+ return renderHeaderNode(
43223
+ cellContent,
43224
+ `body-cell-nested-table-${nodeIndex}-${rowIndex}-${cellIndex}-${contentIndex}`,
43225
+ documentContentTheme,
43226
+ editor.model.metadata.numberingDefinitions,
43227
+ headingStyles,
43228
+ spannedWidthPx > 0 ? spannedWidthPx : void 0,
43229
+ scrollToBookmark,
43230
+ void 0,
43231
+ void 0,
43232
+ void 0,
43233
+ void 0,
43234
+ paragraphRunRenderOptions,
43235
+ void 0,
43236
+ void 0,
43237
+ tableCellEditScope,
43238
+ void 0,
43239
+ embeddedTableResizeController
43240
+ );
43241
+ }
43242
+ );
43243
+ };
42490
43244
  return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
42491
43245
  "td",
42492
43246
  {
@@ -43372,68 +44126,27 @@ ${currentText.slice(end)}`;
43372
44126
  );
43373
44127
  })
43374
44128
  }
43375
- ) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { style: { display: "grid", gap: 4 }, children: (() => {
43376
- let paragraphCursor = 0;
43377
- return cell.nodes.map(
43378
- (cellContent, contentIndex) => {
43379
- if (cellContent.type === "paragraph") {
43380
- const paragraphIndex = paragraphCursor;
43381
- paragraphCursor += 1;
43382
- return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
43383
- "div",
43384
- {
43385
- "data-docx-paragraph-host": "true",
43386
- "data-docx-paragraph-kind": "table-cell",
43387
- "data-docx-table-index": nodeIndex,
43388
- "data-docx-row-index": rowIndex,
43389
- "data-docx-cell-index": cellIndex,
43390
- "data-docx-paragraph-index": paragraphIndex,
43391
- "data-docx-table-paragraph-index": paragraphIndex,
43392
- style: tableCellParagraphBlockStyle(
43393
- cellContent,
43394
- editor.model.metadata.numberingDefinitions,
43395
- headingStyles,
43396
- paragraphIndex,
43397
- applyWordTableDefaults,
43398
- nodeDocGridLinePitchPx
43399
- ),
43400
- children: renderInteractiveParagraphRuns(
43401
- cellContent,
43402
- `body-cell-${nodeIndex}-${rowIndex}-${cellIndex}-${contentIndex}`,
43403
- {
43404
- kind: "table-cell",
43405
- tableIndex: nodeIndex,
43406
- rowIndex,
43407
- cellIndex,
43408
- paragraphIndex
43409
- }
43410
- )
43411
- },
43412
- `body-cell-p-${nodeIndex}-${rowIndex}-${cellIndex}-${contentIndex}`
43413
- );
44129
+ ) : isSlicedRow && slicedCellViewportHeightPx ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
44130
+ "div",
44131
+ {
44132
+ style: {
44133
+ height: slicedCellViewportHeightPx,
44134
+ overflow: "hidden",
44135
+ position: "relative"
44136
+ },
44137
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
44138
+ "div",
44139
+ {
44140
+ style: {
44141
+ display: "grid",
44142
+ gap: 0,
44143
+ transform: `translateY(-${tableRowSliceOffsetPx}px)`
44144
+ },
44145
+ children: renderStaticCellContent()
43414
44146
  }
43415
- return renderHeaderNode(
43416
- cellContent,
43417
- `body-cell-nested-table-${nodeIndex}-${rowIndex}-${cellIndex}-${contentIndex}`,
43418
- documentContentTheme,
43419
- editor.model.metadata.numberingDefinitions,
43420
- headingStyles,
43421
- spannedWidthPx > 0 ? spannedWidthPx : void 0,
43422
- scrollToBookmark,
43423
- void 0,
43424
- void 0,
43425
- void 0,
43426
- void 0,
43427
- paragraphRunRenderOptions,
43428
- void 0,
43429
- void 0,
43430
- tableCellEditScope,
43431
- void 0,
43432
- embeddedTableResizeController
43433
- );
43434
- }
43435
- );
43436
- })() })
44147
+ )
44148
+ }
44149
+ ) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { style: { display: "grid", gap: 0 }, children: renderStaticCellContent() })
43437
44150
  },
43438
44151
  `cell-${nodeIndex}-${rowIndex}-${cellIndex}`
43439
44152
  );
@@ -44492,8 +45205,11 @@ ${currentText.slice(end)}`;
44492
45205
  () => new Map(endnotes.map((note) => [note.id, note])),
44493
45206
  [endnotes]
44494
45207
  );
44495
- const pageFootnotesByIndex = React.useMemo(
44496
- () => pageNodeSegmentsByPage.map((nodeSegments) => {
45208
+ const pageFootnotesByIndex = React.useMemo(() => {
45209
+ if (footnotes.length === 0) {
45210
+ return pageNodeSegmentsByPage.map(() => []);
45211
+ }
45212
+ return pageNodeSegmentsByPage.map((nodeSegments) => {
44497
45213
  const referencedIds = [];
44498
45214
  const seen = /* @__PURE__ */ new Set();
44499
45215
  nodeSegments.forEach((segment) => {
@@ -44515,10 +45231,17 @@ ${currentText.slice(end)}`;
44515
45231
  });
44516
45232
  });
44517
45233
  return referencedIds.map((referenceId) => footnotesById.get(referenceId)).filter((note) => Boolean(note));
44518
- }),
44519
- [editor.model.nodes, footnotesById, pageNodeSegmentsByPage]
44520
- );
45234
+ });
45235
+ }, [
45236
+ editor.model.nodes,
45237
+ footnotes.length,
45238
+ footnotesById,
45239
+ pageNodeSegmentsByPage
45240
+ ]);
44521
45241
  const referencedEndnotes = React.useMemo(() => {
45242
+ if (endnotes.length === 0) {
45243
+ return endnotes;
45244
+ }
44522
45245
  const referencedIds = [];
44523
45246
  const seen = /* @__PURE__ */ new Set();
44524
45247
  editor.model.nodes.forEach((node) => {
@@ -44748,6 +45471,7 @@ ${currentText.slice(end)}`;
44748
45471
  const pageVisible = isPageVisible(pageIndex);
44749
45472
  const pageWrapperWidthPx = showTrackedChangeGutter ? pageLayout.pageWidthPx + TRACKED_CHANGE_GUTTER_WIDTH_PX : pageLayout.pageWidthPx;
44750
45473
  if (!pageVisible) {
45474
+ const placeholderBackgroundColor = pageBackgroundColor ?? editor.model.metadata.documentBackgroundColor ?? pageSurfaceBaseStyle.backgroundColor;
44751
45475
  return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
44752
45476
  "div",
44753
45477
  {
@@ -44765,8 +45489,12 @@ ${currentText.slice(end)}`;
44765
45489
  "data-docx-page-placeholder": "true",
44766
45490
  ref: pagePlaceholderRefForIndex(pageIndex),
44767
45491
  style: {
45492
+ ...pageSurfaceBaseStyle,
44768
45493
  height: pageLayout.pageHeightPx,
44769
- width: pageLayout.pageWidthPx
45494
+ minHeight: pageLayout.pageHeightPx,
45495
+ width: pageLayout.pageWidthPx,
45496
+ backgroundColor: placeholderBackgroundColor,
45497
+ pointerEvents: "none"
44770
45498
  }
44771
45499
  }
44772
45500
  )
@@ -45224,6 +45952,14 @@ ${currentText.slice(end)}`;
45224
45952
  }
45225
45953
  );
45226
45954
  const explicitColumnWidthsPx = sectionColumns && sectionColumns.widthsPx?.length === sectionColumns.count ? sectionColumns.widthsPx : void 0;
45955
+ const flowSegmentsHaveExplicitColumnBreak = flowSegments.some((segment) => {
45956
+ if (segment.tableRowRange) {
45957
+ return false;
45958
+ }
45959
+ const segmentNode = editor.model.nodes[segment.nodeIndex];
45960
+ return segmentNode?.type === "paragraph" && paragraphHasExplicitColumnBreak(segmentNode);
45961
+ });
45962
+ const canUseColumnLineSplitRender = flowSegments.length > 0 && !flowSegmentsHaveExplicitColumnBreak;
45227
45963
  const renderSegmentInColumn = (columnSegment, columnContentWidthPx) => {
45228
45964
  const columnNode = editor.model.nodes[columnSegment.nodeIndex];
45229
45965
  if (!columnNode) {
@@ -45255,7 +45991,8 @@ ${currentText.slice(end)}`;
45255
45991
  suppressParagraphElementTracking: segmentIndex > 0,
45256
45992
  syntheticKeySuffix: `column-break-${segmentIndex}`,
45257
45993
  overrideBeforeSpacingPx: segmentIndex === 0 ? void 0 : 0,
45258
- overrideAfterSpacingPx: isLastSegment ? void 0 : 0
45994
+ overrideAfterSpacingPx: isLastSegment ? void 0 : 0,
45995
+ normalizeParagraphHostFontSize: true
45259
45996
  }
45260
45997
  )
45261
45998
  },
@@ -45276,7 +46013,8 @@ ${currentText.slice(end)}`;
45276
46013
  {
45277
46014
  pageLayout,
45278
46015
  contentWidthPxOverride: columnContentWidthPx,
45279
- suppressLikelyFullPageCoverImageKeys: suppressedLikelyFullPageCoverImageKeys
46016
+ suppressLikelyFullPageCoverImageKeys: suppressedLikelyFullPageCoverImageKeys,
46017
+ normalizeParagraphHostFontSize: true
45280
46018
  }
45281
46019
  );
45282
46020
  const segmentKeySuffix = columnSegment.tableRowRange ? `rows-${columnSegment.tableRowRange.startRowIndex}-${columnSegment.tableRowRange.endRowIndex}${columnSegment.tableRowSlice ? `-slice-${Math.max(
@@ -45315,7 +46053,91 @@ ${currentText.slice(end)}`;
45315
46053
  "div",
45316
46054
  {
45317
46055
  style: { position: "relative" },
45318
- children: explicitColumnWidthsPx && explicitColumnWidthsPx.length === 2 && flowSegments.length > 0 ? (() => {
46056
+ children: canUseColumnLineSplitRender ? (() => {
46057
+ const columnWidthsPx = explicitColumnWidthsPx && explicitColumnWidthsPx.length === sectionColumns.count ? explicitColumnWidthsPx : (() => {
46058
+ const inferredColumnWidthPx = Math.max(
46059
+ 120,
46060
+ Math.round(
46061
+ (pageContentWidthPx - sectionColumns.gapPx * Math.max(
46062
+ 0,
46063
+ sectionColumns.count - 1
46064
+ )) / Math.max(1, sectionColumns.count)
46065
+ )
46066
+ );
46067
+ return Array.from(
46068
+ { length: sectionColumns.count },
46069
+ () => inferredColumnWidthPx
46070
+ );
46071
+ })();
46072
+ const columnSegments = buildRenderColumnSegmentsForPageSection(
46073
+ editor.model,
46074
+ flowSegments,
46075
+ columnWidthsPx,
46076
+ pageBodyAvailableHeightPx,
46077
+ editor.model.metadata.numberingDefinitions,
46078
+ docGridLinePitchPxByNodeIndex,
46079
+ measuredParagraphOuterHeightsPxByNodeIndex,
46080
+ isLastPage
46081
+ );
46082
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
46083
+ overlaySegments.map((overlaySegment) => {
46084
+ const overlayNode = editor.model.nodes[overlaySegment.nodeIndex];
46085
+ if (!overlayNode) {
46086
+ return null;
46087
+ }
46088
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
46089
+ React.Fragment,
46090
+ {
46091
+ children: renderDocumentNode(
46092
+ overlayNode,
46093
+ overlaySegment.nodeIndex,
46094
+ overlaySegment.tableRowRange,
46095
+ overlaySegment.tableRowSlice,
46096
+ overlaySegment.paragraphLineRange,
46097
+ {
46098
+ pageLayout,
46099
+ suppressLikelyFullPageCoverImageKeys: suppressedLikelyFullPageCoverImageKeys
46100
+ }
46101
+ )
46102
+ },
46103
+ `column-layout-overlay-${pageIndex}-${overlaySegment.nodeIndex}-${segmentIdentityKey(
46104
+ overlaySegment
46105
+ )}`
46106
+ );
46107
+ }),
46108
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
46109
+ "div",
46110
+ {
46111
+ style: {
46112
+ display: "grid",
46113
+ gridTemplateColumns: columnWidthsPx.map((widthPx) => `${widthPx}px`).join(" "),
46114
+ columnGap: sectionColumns.gapPx,
46115
+ alignItems: "start",
46116
+ minHeight: pageBodyAvailableHeightPx,
46117
+ position: "relative",
46118
+ zIndex: 1
46119
+ },
46120
+ children: columnSegments.map(
46121
+ (segmentsForColumn, columnIndex) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
46122
+ "div",
46123
+ {
46124
+ style: {
46125
+ minHeight: pageBodyAvailableHeightPx
46126
+ },
46127
+ children: segmentsForColumn.map(
46128
+ (segment) => renderSegmentInColumn(
46129
+ segment,
46130
+ columnWidthsPx[columnIndex]
46131
+ )
46132
+ )
46133
+ },
46134
+ `column-layout-flow-${pageIndex}-${groupIndex}-${columnIndex}`
46135
+ )
46136
+ )
46137
+ }
46138
+ )
46139
+ ] });
46140
+ })() : explicitColumnWidthsPx && explicitColumnWidthsPx.length === 2 && flowSegments.length > 0 ? (() => {
45319
46141
  const [leftColumnWidthPx, rightColumnWidthPx] = explicitColumnWidthsPx;
45320
46142
  const prefixHeightsPx = new Array(
45321
46143
  flowSegments.length + 1
@@ -47629,6 +48451,7 @@ function buildDocumentPageNodeSegments2(model, pageContentHeightPx, pageContentW
47629
48451
  );
47630
48452
  }
47631
48453
  let rowStartIndex = 0;
48454
+ let tableBreakStartRowCursor = 0;
47632
48455
  while (rowStartIndex < estimatedRowHeightsPx.length) {
47633
48456
  const remainingHeightPx = Math.max(0, currentPageContentHeightPx - pageConsumedHeightPx);
47634
48457
  const fittedRowEndIndex = fitTableRowsWithinHeightPx2(
@@ -47640,9 +48463,10 @@ function buildDocumentPageNodeSegments2(model, pageContentHeightPx, pageContentW
47640
48463
  pageOverflowTolerancePx
47641
48464
  );
47642
48465
  let rowEndIndex = fittedRowEndIndex;
47643
- const forcedBreakRowIndex = tableBreakStartRows.find(
47644
- (breakRowIndex) => breakRowIndex > rowStartIndex
47645
- );
48466
+ while (tableBreakStartRowCursor < tableBreakStartRows.length && tableBreakStartRows[tableBreakStartRowCursor] <= rowStartIndex) {
48467
+ tableBreakStartRowCursor += 1;
48468
+ }
48469
+ const forcedBreakRowIndex = tableBreakStartRows[tableBreakStartRowCursor];
47646
48470
  if (forcedBreakRowIndex !== void 0) {
47647
48471
  rowEndIndex = Math.min(rowEndIndex, forcedBreakRowIndex);
47648
48472
  }