@extend-ai/react-docx 0.7.6 → 0.8.0

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.js CHANGED
@@ -6,11 +6,17 @@ import {
6
6
  withPart
7
7
  } from "./chunk-XBI2PYTU.js";
8
8
  import {
9
+ allocateBlockId,
9
10
  buildDocModel,
10
11
  buildDocModelFromBytes,
11
12
  cloneDocModel,
13
+ cloneParagraphNode,
14
+ cloneTableNode,
15
+ collectDuplicateDocModelBlockIds,
16
+ deepFreezeDocModel,
17
+ ensureDocModelBlockIds,
12
18
  normalizeDocModel
13
- } from "./chunk-P3MKA55V.js";
19
+ } from "./chunk-HWEQ63UE.js";
14
20
  import {
15
21
  initWasm,
16
22
  mapsToWasmPackage,
@@ -326,16 +332,16 @@ async function importDocxOnMainThread(buffer, signal) {
326
332
  throw createAbortError();
327
333
  }
328
334
  const startedAt = performanceNow();
329
- const [{ parseDocx: parseDocx2 }, { buildDocModel: buildDocModel2 }] = await Promise.all([
335
+ const [{ parseDocx: parseDocx2 }, { buildDocModel: buildDocModel2, ensureDocModelBlockIds: ensureDocModelBlockIds2 }] = await Promise.all([
330
336
  import("./src-2FP7IUE6.js"),
331
- import("./src-VN4V5N3K.js")
337
+ import("./src-FCCRPRMV.js")
332
338
  ]);
333
339
  const pkg = await parseDocx2(buffer);
334
340
  const parsedAt = performanceNow();
335
341
  if (signal?.aborted) {
336
342
  throw createAbortError();
337
343
  }
338
- const model = await buildDocModel2(pkg);
344
+ const model = ensureDocModelBlockIds2(await buildDocModel2(pkg));
339
345
  const finishedAt = performanceNow();
340
346
  if (signal?.aborted) {
341
347
  throw createAbortError();
@@ -369,7 +375,7 @@ async function importDocxBuffer(buffer, options = {}) {
369
375
  }
370
376
  const requestId = nextImportWorkerRequestId;
371
377
  nextImportWorkerRequestId += 1;
372
- return new Promise((resolve, reject) => {
378
+ const workerResult = new Promise((resolve, reject) => {
373
379
  let settled = false;
374
380
  const cleanup = () => {
375
381
  worker.removeEventListener("message", handleMessage);
@@ -433,6 +439,10 @@ async function importDocxBuffer(buffer, options = {}) {
433
439
  );
434
440
  }
435
441
  });
442
+ const result = await workerResult;
443
+ const { ensureDocModelBlockIds: ensureDocModelBlockIds2 } = await import("./src-FCCRPRMV.js");
444
+ ensureDocModelBlockIds2(result.model);
445
+ return result;
436
446
  }
437
447
 
438
448
  // src/section-layout.ts
@@ -824,6 +834,7 @@ import { useVirtualizer, useWindowVirtualizer } from "@tanstack/react-virtual";
824
834
  function paragraphFromText(text, options) {
825
835
  return {
826
836
  type: "paragraph",
837
+ blockId: allocateBlockId(),
827
838
  style: options?.paragraphStyle,
828
839
  children: [{ type: "text", text, style: options?.runStyle }]
829
840
  };
@@ -1409,6 +1420,7 @@ function splitParagraphChildrenAtTextOffsets(paragraph, text, startOffset, endOf
1409
1420
  function cloneParagraph(paragraph) {
1410
1421
  return {
1411
1422
  type: "paragraph",
1423
+ blockId: allocateBlockId(),
1412
1424
  style: paragraph.style ? { ...paragraph.style } : void 0,
1413
1425
  sourceXml: paragraph.sourceXml,
1414
1426
  children: paragraph.children.map(cloneParagraphChildRun)
@@ -1442,26 +1454,31 @@ function duplicateParagraph(model, index) {
1442
1454
  return next;
1443
1455
  }
1444
1456
  function updateParagraphText(model, index, text, options) {
1445
- const next = cloneDocModel(model);
1446
- const paragraph = getParagraph(next, index);
1447
- if (!paragraph) {
1448
- return next;
1457
+ const source = getParagraph(model, index);
1458
+ if (!source) {
1459
+ return { ...model, nodes: [...model.nodes] };
1449
1460
  }
1450
- paragraph.children = distributeTextAcrossParagraphChildren(paragraph, text, options);
1461
+ const paragraph = cloneParagraphNode(source);
1462
+ paragraph.children = distributeTextAcrossParagraphChildren(source, text, options);
1451
1463
  paragraph.sourceXml = void 0;
1452
- return next;
1464
+ const nextNodes = [...model.nodes];
1465
+ nextNodes[index] = paragraph;
1466
+ return { ...model, nodes: nextNodes };
1453
1467
  }
1454
1468
  function updateTableCellText(model, tableIndex, rowIndex, cellIndex, text, options) {
1455
- const next = cloneDocModel(model);
1456
- const tableNode = next.nodes[tableIndex];
1457
- if (!tableNode || tableNode.type !== "table") {
1458
- return next;
1469
+ const sourceTable = model.nodes[tableIndex];
1470
+ if (!sourceTable || sourceTable.type !== "table") {
1471
+ return { ...model, nodes: [...model.nodes] };
1459
1472
  }
1473
+ const tableNode = cloneTableNode(sourceTable);
1460
1474
  const row = tableNode.rows[rowIndex];
1461
1475
  const cell = row?.cells[cellIndex];
1462
1476
  if (!cell) {
1463
- return next;
1477
+ return { ...model, nodes: [...model.nodes] };
1464
1478
  }
1479
+ const nextNodes = [...model.nodes];
1480
+ nextNodes[tableIndex] = tableNode;
1481
+ const next = { ...model, nodes: nextNodes };
1465
1482
  const paragraphs = cell.nodes.filter((node) => node.type === "paragraph");
1466
1483
  const incomingParagraphTexts = text.replace(/\r\n/g, "\n").replace(/\r/g, "\n").split("\n");
1467
1484
  if (incomingParagraphTexts.length === 0) {
@@ -1490,21 +1507,23 @@ function updateTableCellText(model, tableIndex, rowIndex, cellIndex, text, optio
1490
1507
  return next;
1491
1508
  }
1492
1509
  function updateTableCellParagraphText(model, tableIndex, rowIndex, cellIndex, paragraphIndex, text, options) {
1493
- const next = cloneDocModel(model);
1494
- const tableNode = next.nodes[tableIndex];
1495
- if (!tableNode || tableNode.type !== "table") {
1496
- return next;
1510
+ const sourceTable = model.nodes[tableIndex];
1511
+ if (!sourceTable || sourceTable.type !== "table") {
1512
+ return { ...model, nodes: [...model.nodes] };
1497
1513
  }
1514
+ const tableNode = cloneTableNode(sourceTable);
1498
1515
  const row = tableNode.rows[rowIndex];
1499
1516
  const cell = row?.cells[cellIndex];
1500
1517
  const paragraph = cell?.nodes.filter((node) => node.type === "paragraph")[paragraphIndex];
1501
1518
  if (!cell || !paragraph) {
1502
- return next;
1519
+ return { ...model, nodes: [...model.nodes] };
1503
1520
  }
1504
1521
  paragraph.children = distributeTextAcrossParagraphChildren(paragraph, text, options);
1505
1522
  paragraph.sourceXml = void 0;
1506
1523
  tableNode.sourceXml = void 0;
1507
- return next;
1524
+ const nextNodes = [...model.nodes];
1525
+ nextNodes[tableIndex] = tableNode;
1526
+ return { ...model, nodes: nextNodes };
1508
1527
  }
1509
1528
  function updateTableCellParagraphTextRecursive(model, tableIndex, rowIndex, cellIndex, paragraphIndex, text, options) {
1510
1529
  const next = cloneDocModel(model);
@@ -1822,6 +1841,221 @@ async function serializeDocx(model, basePackage) {
1822
1841
  return wasmSerializeDocx(model, basePackage ? mapsToWasmPackage(basePackage) : void 0);
1823
1842
  }
1824
1843
 
1844
+ // src/editing-intents.ts
1845
+ function resolveEditingIntent(source) {
1846
+ const insertedText = source.data ?? source.dataTransferText ?? "";
1847
+ const transferredText = source.dataTransferText ?? source.data ?? "";
1848
+ switch (source.inputType) {
1849
+ case "insertCompositionText":
1850
+ case "deleteCompositionText":
1851
+ return void 0;
1852
+ case "insertText":
1853
+ case "insertFromYank":
1854
+ case "insertFromPasteAsQuotation":
1855
+ return { kind: "insertText", text: insertedText };
1856
+ case "insertFromPaste":
1857
+ case "insertFromDrop":
1858
+ return { kind: "insertText", text: transferredText };
1859
+ case "insertReplacementText":
1860
+ case "insertTranspose":
1861
+ return { kind: "replaceText", text: insertedText };
1862
+ case "insertParagraph":
1863
+ return { kind: "insertParagraph" };
1864
+ case "insertLineBreak":
1865
+ return { kind: "insertLineBreak" };
1866
+ case "deleteContentBackward":
1867
+ return { kind: "deleteContent", direction: "backward", unit: "character" };
1868
+ case "deleteContentForward":
1869
+ return { kind: "deleteContent", direction: "forward", unit: "character" };
1870
+ case "deleteWordBackward":
1871
+ return { kind: "deleteContent", direction: "backward", unit: "word" };
1872
+ case "deleteWordForward":
1873
+ return { kind: "deleteContent", direction: "forward", unit: "word" };
1874
+ case "deleteSoftLineBackward":
1875
+ case "deleteHardLineBackward":
1876
+ return { kind: "deleteContent", direction: "backward", unit: "line" };
1877
+ case "deleteSoftLineForward":
1878
+ case "deleteHardLineForward":
1879
+ return { kind: "deleteContent", direction: "forward", unit: "line" };
1880
+ case "deleteEntireSoftLine":
1881
+ return {
1882
+ kind: "deleteContent",
1883
+ direction: "backward",
1884
+ unit: "entire-line"
1885
+ };
1886
+ case "deleteContent":
1887
+ case "deleteByCut":
1888
+ case "deleteByDrag":
1889
+ return { kind: "deleteRange" };
1890
+ case "historyUndo":
1891
+ return { kind: "historyUndo" };
1892
+ case "historyRedo":
1893
+ return { kind: "historyRedo" };
1894
+ default:
1895
+ return { kind: "blocked" };
1896
+ }
1897
+ }
1898
+ function editingIntentCoalesceClass(intent) {
1899
+ switch (intent.kind) {
1900
+ case "insertText":
1901
+ case "insertLineBreak":
1902
+ case "replaceText":
1903
+ return "insert";
1904
+ case "deleteContent":
1905
+ case "deleteRange":
1906
+ return "delete";
1907
+ default:
1908
+ return void 0;
1909
+ }
1910
+ }
1911
+ function isWhitespaceChar(char) {
1912
+ return /\s/.test(char);
1913
+ }
1914
+ function codePointLengthBefore(text, offset) {
1915
+ if (offset >= 2) {
1916
+ const codePoint = text.codePointAt(offset - 2);
1917
+ if (codePoint !== void 0 && codePoint > 65535) {
1918
+ return 2;
1919
+ }
1920
+ }
1921
+ return offset > 0 ? 1 : 0;
1922
+ }
1923
+ function codePointLengthAt(text, offset) {
1924
+ if (offset >= text.length) {
1925
+ return 0;
1926
+ }
1927
+ const codePoint = text.codePointAt(offset);
1928
+ return codePoint !== void 0 && codePoint > 65535 ? 2 : 1;
1929
+ }
1930
+ function wordDeleteStartBefore(text, offset) {
1931
+ let index = offset;
1932
+ while (index > 0 && isWhitespaceChar(text[index - 1])) {
1933
+ index -= 1;
1934
+ }
1935
+ while (index > 0 && !isWhitespaceChar(text[index - 1])) {
1936
+ index -= 1;
1937
+ }
1938
+ return index;
1939
+ }
1940
+ function wordDeleteEndAfter(text, offset) {
1941
+ let index = offset;
1942
+ while (index < text.length && isWhitespaceChar(text[index])) {
1943
+ index += 1;
1944
+ }
1945
+ while (index < text.length && !isWhitespaceChar(text[index])) {
1946
+ index += 1;
1947
+ }
1948
+ return index;
1949
+ }
1950
+ function lineStartBefore(text, offset) {
1951
+ const newlineIndex = text.lastIndexOf("\n", Math.max(0, offset - 1));
1952
+ return newlineIndex < 0 ? 0 : newlineIndex + 1;
1953
+ }
1954
+ function lineEndAfter(text, offset) {
1955
+ const newlineIndex = text.indexOf("\n", offset);
1956
+ if (newlineIndex < 0) {
1957
+ return text.length;
1958
+ }
1959
+ return newlineIndex === offset ? offset + 1 : newlineIndex;
1960
+ }
1961
+ function replaceRange(text, start, end, replacement) {
1962
+ return {
1963
+ text: `${text.slice(0, start)}${replacement}${text.slice(end)}`,
1964
+ caret: start + replacement.length
1965
+ };
1966
+ }
1967
+ function applyTextEditingIntent(text, selectionStart, selectionEnd, intent) {
1968
+ const start = Math.max(0, Math.min(Math.round(selectionStart), text.length));
1969
+ const end = Math.max(
1970
+ start,
1971
+ Math.min(Math.round(selectionEnd), text.length)
1972
+ );
1973
+ switch (intent.kind) {
1974
+ case "insertText":
1975
+ case "replaceText": {
1976
+ const replacement = intent.text.replace(/\r\n?/g, "\n");
1977
+ if (replacement.length === 0 && start === end) {
1978
+ return void 0;
1979
+ }
1980
+ return replaceRange(text, start, end, replacement);
1981
+ }
1982
+ case "insertLineBreak":
1983
+ return replaceRange(text, start, end, "\n");
1984
+ case "deleteRange":
1985
+ if (start === end) {
1986
+ return void 0;
1987
+ }
1988
+ return replaceRange(text, start, end, "");
1989
+ case "deleteContent": {
1990
+ if (start !== end) {
1991
+ return replaceRange(text, start, end, "");
1992
+ }
1993
+ if (intent.direction === "backward") {
1994
+ if (intent.unit === "entire-line") {
1995
+ const lineStart = lineStartBefore(text, start);
1996
+ const newlineIndex = text.indexOf("\n", start);
1997
+ const lineEnd = newlineIndex < 0 ? text.length : newlineIndex;
1998
+ if (lineStart === lineEnd) {
1999
+ return void 0;
2000
+ }
2001
+ return replaceRange(text, lineStart, lineEnd, "");
2002
+ }
2003
+ if (start === 0) {
2004
+ return void 0;
2005
+ }
2006
+ const deleteFrom = intent.unit === "character" ? start - codePointLengthBefore(text, start) : intent.unit === "word" ? wordDeleteStartBefore(text, start) : lineStartBefore(text, start);
2007
+ if (deleteFrom >= start) {
2008
+ return void 0;
2009
+ }
2010
+ return replaceRange(text, deleteFrom, start, "");
2011
+ }
2012
+ if (start >= text.length) {
2013
+ return void 0;
2014
+ }
2015
+ const deleteTo = intent.unit === "character" ? start + codePointLengthAt(text, start) : intent.unit === "word" ? wordDeleteEndAfter(text, start) : lineEndAfter(text, start);
2016
+ if (deleteTo <= start) {
2017
+ return void 0;
2018
+ }
2019
+ return replaceRange(text, start, deleteTo, "");
2020
+ }
2021
+ default:
2022
+ return void 0;
2023
+ }
2024
+ }
2025
+ function shouldCoalesceTextCommit(previous, next, windowMs = 1e3) {
2026
+ return Boolean(
2027
+ previous && previous.key === next.key && next.at >= previous.at && next.at - previous.at <= windowMs && previous.caretAfter === next.caretBefore
2028
+ );
2029
+ }
2030
+ function mergeCellParagraphTexts(paragraphTexts, boundaryParagraphIndex) {
2031
+ if (boundaryParagraphIndex <= 0 || boundaryParagraphIndex >= paragraphTexts.length) {
2032
+ return void 0;
2033
+ }
2034
+ const mergedTexts = [
2035
+ ...paragraphTexts.slice(0, boundaryParagraphIndex - 1),
2036
+ `${paragraphTexts[boundaryParagraphIndex - 1]}${paragraphTexts[boundaryParagraphIndex]}`,
2037
+ ...paragraphTexts.slice(boundaryParagraphIndex + 1)
2038
+ ];
2039
+ const cellText = mergedTexts.join("\n");
2040
+ let caretGlobalOffset = 0;
2041
+ for (let index = 0; index < boundaryParagraphIndex - 1; index += 1) {
2042
+ caretGlobalOffset += paragraphTexts[index].length + 1;
2043
+ }
2044
+ caretGlobalOffset += paragraphTexts[boundaryParagraphIndex - 1].length;
2045
+ const parts = cellText.split("\n");
2046
+ let remaining = caretGlobalOffset;
2047
+ let caretParagraphIndex = 0;
2048
+ while (caretParagraphIndex < parts.length - 1 && remaining > parts[caretParagraphIndex].length) {
2049
+ remaining -= parts[caretParagraphIndex].length + 1;
2050
+ caretParagraphIndex += 1;
2051
+ }
2052
+ return {
2053
+ cellText,
2054
+ caretParagraphIndex,
2055
+ caretOffset: Math.max(0, Math.min(remaining, parts[caretParagraphIndex].length))
2056
+ };
2057
+ }
2058
+
1825
2059
  // src/pagination-breaks.ts
1826
2060
  var PAGE_BREAK_XML_PATTERN = /<w:br\b[^>]*w:type="page"[^>]*\/?>/i;
1827
2061
  var PAGE_BREAK_BEFORE_XML_PATTERN = /<w:pageBreakBefore\b[^>]*\/?>/i;
@@ -2032,6 +2266,55 @@ function resolveMeasuredBodyFooterOverlapLatchState(options) {
2032
2266
  shouldLatch: consecutivePasses >= stabilityThreshold
2033
2267
  };
2034
2268
  }
2269
+ function createEstimatedPagesBuildMemo(build) {
2270
+ const entries = [];
2271
+ return (measuredTableRowHeightsByNodeIndex, measuredPageContentHeightsPxByPageIndex, strictLastRenderedParagraphStartBreaks) => {
2272
+ const cached = entries.find(
2273
+ (entry) => entry.measuredTableRowHeightsByNodeIndex === measuredTableRowHeightsByNodeIndex && entry.measuredPageContentHeightsPxByPageIndex === measuredPageContentHeightsPxByPageIndex && entry.strictLastRenderedParagraphStartBreaks === strictLastRenderedParagraphStartBreaks
2274
+ );
2275
+ if (cached) {
2276
+ return cached.pages;
2277
+ }
2278
+ const pages = build(
2279
+ measuredTableRowHeightsByNodeIndex,
2280
+ measuredPageContentHeightsPxByPageIndex,
2281
+ strictLastRenderedParagraphStartBreaks
2282
+ );
2283
+ entries.push({
2284
+ measuredTableRowHeightsByNodeIndex,
2285
+ measuredPageContentHeightsPxByPageIndex,
2286
+ strictLastRenderedParagraphStartBreaks,
2287
+ pages
2288
+ });
2289
+ return pages;
2290
+ };
2291
+ }
2292
+ function resolveMeasuredSplitParagraphPageComparison(options) {
2293
+ if (options.canUndo || options.canRedo || !options.hasMeasuredPageContentHeights) {
2294
+ return {
2295
+ pages: options.measuredEstimatedPages,
2296
+ usedPureEstimatedPages: false
2297
+ };
2298
+ }
2299
+ const measuredPagesAreOnlySplitParagraphs = options.measuredEstimatedPages.length > 0 && options.measuredEstimatedPages.every(
2300
+ options.pageContainsOnlySplitParagraphSegments
2301
+ );
2302
+ if (!measuredPagesAreOnlySplitParagraphs) {
2303
+ return {
2304
+ pages: options.measuredEstimatedPages,
2305
+ usedPureEstimatedPages: false
2306
+ };
2307
+ }
2308
+ const pureEstimatedPages = options.buildPureEstimatedPages();
2309
+ const purePagesAreOnlySplitParagraphs = pureEstimatedPages.length > 0 && pureEstimatedPages.every(options.pageContainsOnlySplitParagraphSegments);
2310
+ if (purePagesAreOnlySplitParagraphs && pureEstimatedPages.length < options.measuredEstimatedPages.length) {
2311
+ return { pages: pureEstimatedPages, usedPureEstimatedPages: true };
2312
+ }
2313
+ return {
2314
+ pages: options.measuredEstimatedPages,
2315
+ usedPureEstimatedPages: false
2316
+ };
2317
+ }
2035
2318
  function isBetterCandidate(candidate, incumbent, targetPageCount) {
2036
2319
  const candidateDifference = Math.abs(candidate.pageCount - targetPageCount);
2037
2320
  const incumbentDifference = Math.abs(incumbent.pageCount - targetPageCount);
@@ -4184,7 +4467,6 @@ var TABLE_ROW_HEIGHT_PAGINATION_ESTIMATE_PADDING_RATIO = 1.08;
4184
4467
  var TABLE_ROW_HEIGHT_PAGINATION_ESTIMATE_PADDING_MIN_ROWS = 15;
4185
4468
  var MIN_TABLE_ROW_SLICE_REMAINING_HEIGHT_PX = MIN_PARAGRAPH_LINE_HEIGHT_PX * 2;
4186
4469
  var TABLE_ROW_SLICE_BOUNDARY_TOLERANCE_PX = 2;
4187
- var TOP_AND_BOTTOM_VERTICAL_DRAG_SNAP_PX = 10;
4188
4470
  var HEADER_FOOTER_INACTIVE_OPACITY = 0.5;
4189
4471
  var LETTERHEAD_INDENT_MIN_TWIPS = 900;
4190
4472
  var LETTERHEAD_INDENT_MAX_TWIPS = 4200;
@@ -4657,7 +4939,7 @@ function reconcileMeasuredTableRowHeightsForImportPagination(table, measuredRowH
4657
4939
  );
4658
4940
  });
4659
4941
  }
4660
- function resolveTableMeasuredRowHeightsForPagination(nodes, tableMeasuredRowHeights, options) {
4942
+ function resolveTableMeasuredRowHeightsForPagination(nodes, tableMeasuredRowHeightsByBlockId, options) {
4661
4943
  const activeTableIndexes = /* @__PURE__ */ new Set();
4662
4944
  (options?.activeDraftKeys ?? []).forEach((draftKey) => {
4663
4945
  const [tableIndexText] = draftKey.split(":");
@@ -4667,37 +4949,114 @@ function resolveTableMeasuredRowHeightsForPagination(nodes, tableMeasuredRowHeig
4667
4949
  }
4668
4950
  });
4669
4951
  const includeOnlyActiveTables = activeTableIndexes.size > 0;
4670
- if (includeOnlyActiveTables === false && options?.allowMeasuredImportPagination !== true) {
4952
+ if (includeOnlyActiveTables === false && options?.allowMeasuredImportPagination !== true && options?.allowContentSignatureValidatedTables !== true) {
4671
4953
  return void 0;
4672
4954
  }
4673
4955
  const next = {};
4674
- Object.entries(tableMeasuredRowHeights).forEach(
4675
- ([tableIndexText, measuredRowHeights]) => {
4676
- const tableIndex = Number.parseInt(tableIndexText, 10);
4677
- const tableNode = nodes[tableIndex];
4678
- if (!Number.isFinite(tableIndex) || !tableNode || tableNode.type !== "table" || !Array.isArray(measuredRowHeights) || measuredRowHeights.length !== tableNode.rows.length) {
4679
- return;
4680
- }
4681
- if (includeOnlyActiveTables && !activeTableIndexes.has(tableIndex)) {
4956
+ nodes.forEach((tableNode, tableIndex) => {
4957
+ if (tableNode.type !== "table" || !tableNode.blockId) {
4958
+ return;
4959
+ }
4960
+ const entry = tableMeasuredRowHeightsByBlockId[tableNode.blockId];
4961
+ if (!entry || !Array.isArray(entry.rowHeightsPx) || entry.rowHeightsPx.length !== tableNode.rows.length) {
4962
+ return;
4963
+ }
4964
+ const measuredRowHeights = entry.rowHeightsPx;
4965
+ if (includeOnlyActiveTables) {
4966
+ if (!activeTableIndexes.has(tableIndex)) {
4682
4967
  return;
4683
4968
  }
4684
- const nextHeights = includeOnlyActiveTables ? measuredRowHeights.map(
4685
- (heightPx) => normalizeMeasuredTableRowHeightPx(heightPx)
4686
- ) : reconcileMeasuredTableRowHeightsForImportPagination(
4687
- tableNode,
4688
- measuredRowHeights,
4689
- options?.pageContentWidthPxByNodeIndex?.get(tableIndex),
4690
- options?.pageContentHeightPxByNodeIndex?.get(tableIndex),
4691
- options?.numberingDefinitions,
4692
- options?.docGridLinePitchPxByNodeIndex?.get(tableIndex)
4693
- ) ?? measuredRowHeights.map(
4969
+ next[tableIndex] = measuredRowHeights.map(
4694
4970
  (heightPx) => normalizeMeasuredTableRowHeightPx(heightPx)
4695
4971
  );
4696
- next[tableIndex] = nextHeights;
4972
+ return;
4697
4973
  }
4698
- );
4974
+ if (options?.allowMeasuredImportPagination !== true && entry.contentSignature !== docNodeContentSignature(tableNode)) {
4975
+ return;
4976
+ }
4977
+ next[tableIndex] = reconcileMeasuredTableRowHeightsForImportPagination(
4978
+ tableNode,
4979
+ measuredRowHeights,
4980
+ options?.pageContentWidthPxByNodeIndex?.get(tableIndex),
4981
+ options?.pageContentHeightPxByNodeIndex?.get(tableIndex),
4982
+ options?.numberingDefinitions,
4983
+ options?.docGridLinePitchPxByNodeIndex?.get(tableIndex)
4984
+ ) ?? measuredRowHeights.map(
4985
+ (heightPx) => normalizeMeasuredTableRowHeightPx(heightPx)
4986
+ );
4987
+ });
4699
4988
  return Object.keys(next).length > 0 ? next : void 0;
4700
4989
  }
4990
+ function buildMeasuredPageContentValidationForPageSegments(pageSegments, nodes, contextSignature) {
4991
+ const blocks = [];
4992
+ let previousNodeIndex;
4993
+ for (const segment of pageSegments) {
4994
+ if (segment.nodeIndex === previousNodeIndex) {
4995
+ continue;
4996
+ }
4997
+ previousNodeIndex = segment.nodeIndex;
4998
+ const node = nodes[segment.nodeIndex];
4999
+ blocks.push({
5000
+ blockId: node?.blockId,
5001
+ contentSignature: node ? docNodeContentSignature(node) : ""
5002
+ });
5003
+ }
5004
+ return { contextSignature, blocks };
5005
+ }
5006
+ function measuredPageContentValidationsEqual(left, right) {
5007
+ if (left === right) {
5008
+ return true;
5009
+ }
5010
+ if (!left || !right) {
5011
+ return false;
5012
+ }
5013
+ if (left.contextSignature !== right.contextSignature || left.blocks.length !== right.blocks.length) {
5014
+ return false;
5015
+ }
5016
+ for (let index = 0; index < left.blocks.length; index += 1) {
5017
+ if (left.blocks[index].blockId !== right.blocks[index].blockId || left.blocks[index].contentSignature !== right.blocks[index].contentSignature) {
5018
+ return false;
5019
+ }
5020
+ }
5021
+ return true;
5022
+ }
5023
+ function resolveMeasuredPageContentHeightsPxForEditedModel(nodes, measuredPageContentHeightsPxByPageIndex, validationByPageIndex, contextSignature) {
5024
+ let cursor = 0;
5025
+ let previousPageLastBlockId;
5026
+ let validPageCount = 0;
5027
+ for (let pageIndex = 0; pageIndex < measuredPageContentHeightsPxByPageIndex.length; pageIndex += 1) {
5028
+ const validation = validationByPageIndex[pageIndex];
5029
+ if (!validation || validation.contextSignature !== contextSignature || validation.blocks.length === 0) {
5030
+ break;
5031
+ }
5032
+ let pageIsValid = true;
5033
+ for (let blockIndex = 0; blockIndex < validation.blocks.length; blockIndex += 1) {
5034
+ const block = validation.blocks[blockIndex];
5035
+ if (!block.blockId) {
5036
+ pageIsValid = false;
5037
+ break;
5038
+ }
5039
+ if (blockIndex === 0 && block.blockId === previousPageLastBlockId) {
5040
+ continue;
5041
+ }
5042
+ const node = nodes[cursor];
5043
+ if (!node || node.blockId !== block.blockId || docNodeContentSignature(node) !== block.contentSignature) {
5044
+ pageIsValid = false;
5045
+ break;
5046
+ }
5047
+ cursor += 1;
5048
+ }
5049
+ if (!pageIsValid) {
5050
+ break;
5051
+ }
5052
+ previousPageLastBlockId = validation.blocks[validation.blocks.length - 1]?.blockId;
5053
+ validPageCount += 1;
5054
+ }
5055
+ if (validPageCount === 0) {
5056
+ return void 0;
5057
+ }
5058
+ return validPageCount >= measuredPageContentHeightsPxByPageIndex.length ? measuredPageContentHeightsPxByPageIndex : measuredPageContentHeightsPxByPageIndex.slice(0, validPageCount);
5059
+ }
4701
5060
  function placeCaretInsideElementDom(element) {
4702
5061
  const selection = window.getSelection();
4703
5062
  if (!selection) {
@@ -4742,6 +5101,34 @@ function selectionOffsetsWithinElementDom(element) {
4742
5101
  return void 0;
4743
5102
  }
4744
5103
  }
5104
+ function staticRangeOffsetsWithinElementDom(element, staticRange) {
5105
+ if (!element.contains(staticRange.startContainer) || !element.contains(staticRange.endContainer)) {
5106
+ return void 0;
5107
+ }
5108
+ try {
5109
+ const textLengthWithoutNumberingLabels = (range) => {
5110
+ const fragment = range.cloneContents();
5111
+ fragment.querySelectorAll("[data-docx-numbering-label='true']").forEach((label) => {
5112
+ label.remove();
5113
+ });
5114
+ return fragment.textContent?.length ?? 0;
5115
+ };
5116
+ const startRange = document.createRange();
5117
+ startRange.setStart(element, 0);
5118
+ startRange.setEnd(staticRange.startContainer, staticRange.startOffset);
5119
+ const endRange = document.createRange();
5120
+ endRange.setStart(element, 0);
5121
+ endRange.setEnd(staticRange.endContainer, staticRange.endOffset);
5122
+ const startOffset = textLengthWithoutNumberingLabels(startRange);
5123
+ const endOffset = textLengthWithoutNumberingLabels(endRange);
5124
+ return {
5125
+ start: Math.min(startOffset, endOffset),
5126
+ end: Math.max(startOffset, endOffset)
5127
+ };
5128
+ } catch {
5129
+ return void 0;
5130
+ }
5131
+ }
4745
5132
  function setSelectionWithinElementByTextOffsetsDom(element, startOffset, endOffset) {
4746
5133
  const selection = window.getSelection();
4747
5134
  if (!selection) {
@@ -6195,8 +6582,11 @@ var defaultStarterModel = {
6195
6582
  defaultParagraphStyleId: "Normal"
6196
6583
  }
6197
6584
  };
6585
+ function cloneDocModelWithBlockIds(model) {
6586
+ return ensureDocModelBlockIds(cloneDocModel(model));
6587
+ }
6198
6588
  function createBlankDocumentModel() {
6199
- return cloneDocModel(defaultStarterModel);
6589
+ return cloneDocModelWithBlockIds(defaultStarterModel);
6200
6590
  }
6201
6591
  function textRuns2(paragraph) {
6202
6592
  return paragraph.children.filter(
@@ -6862,6 +7252,8 @@ function paragraphLooksLikeCheckboxChoiceRow(paragraph) {
6862
7252
  }
6863
7253
  var KEEP_ALL_SCRIPT_RE = /[\p{Script=Han}\p{Script=Hiragana}\p{Script=Katakana}\p{Script=Hangul}]/u;
6864
7254
  var MIN_DUAL_WRAPPED_INTERIOR_BAND_PX = 72;
7255
+ var WRAP_BAND_RECONCILE_TOLERANCE_PX = 2;
7256
+ var WRAP_BAND_RECONCILE_MAX_PASSES = 24;
6865
7257
  function resolveDualWrapParagraphRenderBlockHeightPx(layout, geometries) {
6866
7258
  const fullHeightPx = wrappedPretextParagraphBlockHeightPx(layout);
6867
7259
  const textBottomPx = pretextLayoutContentBottomPx(layout);
@@ -6878,10 +7270,27 @@ function resolveDualWrapParagraphRenderBlockHeightPx(layout, geometries) {
6878
7270
  }
6879
7271
  return fullHeightPx;
6880
7272
  }
7273
+ function resolveDragPreviewAwareWrapBlockHeightPx(layout, geometries, foreignExclusions) {
7274
+ const baseHeightPx = resolveDualWrapParagraphRenderBlockHeightPx(
7275
+ layout,
7276
+ geometries
7277
+ );
7278
+ if (!foreignExclusions?.some((exclusion) => exclusion.fromDragPreview)) {
7279
+ return baseHeightPx;
7280
+ }
7281
+ const lineHeightPx = Math.max(1, Math.round(layout.lineHeightPx ?? 1));
7282
+ const staticBottomPx = Math.max(
7283
+ lineHeightPx,
7284
+ pretextLayoutContentBottomPx(layout),
7285
+ ...geometries.map((geometry) => geometry.exclusion.bottom),
7286
+ ...foreignExclusions.filter((exclusion) => !exclusion.fromDragPreview).map((exclusion) => exclusion.bottom)
7287
+ );
7288
+ return Math.min(baseHeightPx, Math.max(1, Math.round(staticBottomPx)));
7289
+ }
6881
7290
  function resolveForeignWrapExclusionsForFlowRange(obstacles, sourceNodeIndex, pageFlowTopPx, pageFlowBottomPx) {
6882
7291
  const foreignExclusions = [];
6883
7292
  for (const obstacle of obstacles) {
6884
- if (obstacle.sourceNodeIndex === sourceNodeIndex) {
7293
+ if (obstacle.sourceNodeIndex === sourceNodeIndex && !obstacle.appliesToSourceNode) {
6885
7294
  continue;
6886
7295
  }
6887
7296
  if (obstacle.bottom <= pageFlowTopPx || obstacle.top >= pageFlowBottomPx) {
@@ -6937,7 +7346,8 @@ function collectPageFlowWrapObstaclesForParagraph(paragraph, nodeIndex, pageFlow
6937
7346
  paragraphTopPx: options?.paragraphTopPx,
6938
7347
  pageMarginTopPx: options?.pageMarginTopPx,
6939
7348
  movePreviewByImageIndex,
6940
- allowNegativeImageTop: movePreviewByImageIndex.size > 0
7349
+ allowNegativeImageTop: movePreviewByImageIndex.size > 0,
7350
+ foreignExclusions: options?.foreignExclusions
6941
7351
  }
6942
7352
  );
6943
7353
  const coveredImageIndexes = /* @__PURE__ */ new Set();
@@ -7015,18 +7425,28 @@ function resolveParagraphForeignOnlyWrappedTextLayout(paragraph, containerWidthP
7015
7425
  };
7016
7426
  }
7017
7427
  function precomputePageSegmentForeignWrapExclusions(segments, model, availableWidthPx, numberingDefinitions, docGridLinePitchPxByNodeIndex, pageContentWidthPxByNodeIndex, pageLayout, interaction) {
7018
- const flowTopPxBySegmentIndex = [];
7019
- const flowHeightPxBySegmentIndex = [];
7020
- let pageFlowTopPx = 0;
7021
- for (const segment of segments) {
7022
- flowTopPxBySegmentIndex.push(pageFlowTopPx);
7428
+ const segmentWidthPxAt = (nodeIndex) => pageContentWidthPxByNodeIndex.get(nodeIndex) ?? availableWidthPx;
7429
+ const measuredWrapBands = interaction?.measuredWrapBands;
7430
+ const measuredBandAt = (key) => {
7431
+ const band = measuredWrapBands?.get(key);
7432
+ return band && band.bottomPx > band.topPx && band.rightPx > band.leftPx ? band : void 0;
7433
+ };
7434
+ const flowTopsFromHeights = (heights) => {
7435
+ const flowTops = [];
7436
+ let pageFlowTopPx = 0;
7437
+ for (const heightPx of heights) {
7438
+ flowTops.push(pageFlowTopPx);
7439
+ pageFlowTopPx += heightPx;
7440
+ }
7441
+ return flowTops;
7442
+ };
7443
+ const baseFlowHeightPxBySegmentIndex = segments.map((segment) => {
7023
7444
  const node = model.nodes[segment.nodeIndex];
7024
- const segmentWidthPx = pageContentWidthPxByNodeIndex.get(segment.nodeIndex) ?? availableWidthPx;
7025
- const segmentHeightPx = estimateRenderedPageSegmentHeightPx(
7445
+ return estimateRenderedPageSegmentHeightPx(
7026
7446
  node,
7027
7447
  segment,
7028
7448
  model,
7029
- segmentWidthPx,
7449
+ segmentWidthPxAt(segment.nodeIndex),
7030
7450
  numberingDefinitions,
7031
7451
  docGridLinePitchPxByNodeIndex.get(segment.nodeIndex),
7032
7452
  // For the wrap-exclusion flow simulation, a square/tight-wrapped float
@@ -7036,54 +7456,313 @@ function precomputePageSegmentForeignWrapExclusions(segments, model, availableWi
7036
7456
  // the float's exclusion rect to overlap and indent them.
7037
7457
  { excludeWrappedFloatingImageFootprint: true }
7038
7458
  );
7039
- flowHeightPxBySegmentIndex.push(segmentHeightPx);
7040
- pageFlowTopPx += segmentHeightPx;
7041
- }
7042
- const obstacles = [];
7043
- for (let segmentIndex = 0; segmentIndex < segments.length; segmentIndex += 1) {
7044
- const segment = segments[segmentIndex];
7045
- const node = model.nodes[segment.nodeIndex];
7046
- if (node?.type !== "paragraph") {
7047
- continue;
7048
- }
7049
- const segmentWidthPx = pageContentWidthPxByNodeIndex.get(segment.nodeIndex) ?? availableWidthPx;
7050
- const paragraphRenderTextWidthPx = paragraphAvailableTextWidthPx(
7051
- node,
7052
- segmentWidthPx,
7053
- numberingDefinitions
7054
- );
7055
- obstacles.push(
7056
- ...collectPageFlowWrapObstaclesForParagraph(
7459
+ });
7460
+ const collectObstacles = (flowTopPxBySegmentIndex2, flowHeightPxBySegmentIndex2, previousObstacles) => {
7461
+ const obstacles2 = [];
7462
+ for (let segmentIndex = 0; segmentIndex < segments.length; segmentIndex += 1) {
7463
+ const segment = segments[segmentIndex];
7464
+ const node = model.nodes[segment.nodeIndex];
7465
+ if (node?.type === "table" && node.style?.floating && !segment.tableRowRange) {
7466
+ const tableContainerWidthPx = segmentWidthPxAt(segment.nodeIndex);
7467
+ const tableFlowTopPx = flowTopPxBySegmentIndex2[segmentIndex] ?? 0;
7468
+ const measuredTableBand = measuredBandAt(`tbl:${segment.nodeIndex}`);
7469
+ if (measuredTableBand) {
7470
+ const floating = node.style.floating;
7471
+ const distLPx = twipsToPixels(floating.leftFromTextTwips) ?? 0;
7472
+ const distRPx = twipsToPixels(floating.rightFromTextTwips) ?? 0;
7473
+ const distTPx = twipsToPixels(floating.topFromTextTwips) ?? 0;
7474
+ const distBPx = twipsToPixels(floating.bottomFromTextTwips) ?? 0;
7475
+ let exclusionLeftPx = Math.max(0, measuredTableBand.leftPx - distLPx);
7476
+ let exclusionRightPx = Math.min(
7477
+ tableContainerWidthPx,
7478
+ measuredTableBand.rightPx + distRPx
7479
+ );
7480
+ if (exclusionLeftPx > 0 && exclusionLeftPx < MIN_DUAL_WRAPPED_INTERIOR_BAND_PX) {
7481
+ exclusionLeftPx = 0;
7482
+ }
7483
+ if (exclusionRightPx < tableContainerWidthPx && tableContainerWidthPx - exclusionRightPx < MIN_DUAL_WRAPPED_INTERIOR_BAND_PX) {
7484
+ exclusionRightPx = tableContainerWidthPx;
7485
+ }
7486
+ obstacles2.push({
7487
+ sourceNodeIndex: segment.nodeIndex,
7488
+ left: exclusionLeftPx,
7489
+ right: exclusionRightPx,
7490
+ top: measuredTableBand.topPx - distTPx,
7491
+ bottom: measuredTableBand.bottomPx + distBPx
7492
+ });
7493
+ continue;
7494
+ }
7495
+ const geometry = resolveFloatingTableGeometry(
7496
+ node,
7497
+ tableContainerWidthPx,
7498
+ {
7499
+ tableWidthPx: estimateFloatingTableWidthPx(
7500
+ node,
7501
+ tableContainerWidthPx
7502
+ ),
7503
+ tableHeightPx: estimateTableHeightPx(
7504
+ node,
7505
+ tableContainerWidthPx,
7506
+ numberingDefinitions,
7507
+ docGridLinePitchPxByNodeIndex.get(segment.nodeIndex)
7508
+ ),
7509
+ indentPx: twipsToSignedPixels(node.style?.indentTwips) ?? 0,
7510
+ flowTopPx: tableFlowTopPx,
7511
+ pageMarginTopPx: pageLayout.marginsPx.top,
7512
+ pageMarginLeftPx: pageLayout.marginsPx.left
7513
+ }
7514
+ );
7515
+ if (geometry) {
7516
+ obstacles2.push({
7517
+ sourceNodeIndex: segment.nodeIndex,
7518
+ left: geometry.exclusion.left,
7519
+ right: geometry.exclusion.right,
7520
+ top: tableFlowTopPx + geometry.exclusion.top,
7521
+ bottom: tableFlowTopPx + geometry.exclusion.bottom
7522
+ });
7523
+ }
7524
+ continue;
7525
+ }
7526
+ if (node?.type !== "paragraph") {
7527
+ continue;
7528
+ }
7529
+ const paragraphRenderTextWidthPx = paragraphAvailableTextWidthPx(
7057
7530
  node,
7058
- segment.nodeIndex,
7059
- flowTopPxBySegmentIndex[segmentIndex] ?? 0,
7060
- paragraphRenderTextWidthPx,
7061
- estimateParagraphLineHeightPx(
7531
+ segmentWidthPxAt(segment.nodeIndex),
7532
+ numberingDefinitions
7533
+ );
7534
+ node.children.forEach((child, childIndex) => {
7535
+ if (child.type !== "image" || !child.floating?.wrapType || child.floating.wrapType === "none" || child.floating.behindDocument === true || shouldRenderWrappedFloatingImage(child)) {
7536
+ return;
7537
+ }
7538
+ const band = measuredBandAt(
7539
+ `img:p:${segment.nodeIndex}:${childIndex}`
7540
+ );
7541
+ if (!band) {
7542
+ return;
7543
+ }
7544
+ const floating = child.floating;
7545
+ const containerWidthPx = segmentWidthPxAt(segment.nodeIndex);
7546
+ const fullWidthWrap = floating.wrapType === "topAndBottom";
7547
+ let exclusionLeftPx = fullWidthWrap ? 0 : Math.max(0, band.leftPx - (floating.distLPx ?? 0));
7548
+ let exclusionRightPx = fullWidthWrap ? containerWidthPx : Math.min(containerWidthPx, band.rightPx + (floating.distRPx ?? 0));
7549
+ if (exclusionLeftPx > 0 && exclusionLeftPx < MIN_DUAL_WRAPPED_INTERIOR_BAND_PX) {
7550
+ exclusionLeftPx = 0;
7551
+ }
7552
+ if (exclusionRightPx < containerWidthPx && containerWidthPx - exclusionRightPx < MIN_DUAL_WRAPPED_INTERIOR_BAND_PX) {
7553
+ exclusionRightPx = containerWidthPx;
7554
+ }
7555
+ if (exclusionRightPx <= exclusionLeftPx) {
7556
+ return;
7557
+ }
7558
+ obstacles2.push({
7559
+ sourceNodeIndex: segment.nodeIndex,
7560
+ appliesToSourceNode: true,
7561
+ left: exclusionLeftPx,
7562
+ right: exclusionRightPx,
7563
+ top: band.topPx - (floating.distTPx ?? 0),
7564
+ bottom: band.bottomPx + (floating.distBPx ?? 0)
7565
+ });
7566
+ });
7567
+ const flowTopPx = measuredBandAt(`para:${segment.nodeIndex}`)?.topPx ?? flowTopPxBySegmentIndex2[segmentIndex] ?? 0;
7568
+ obstacles2.push(
7569
+ ...collectPageFlowWrapObstaclesForParagraph(
7062
7570
  node,
7063
- docGridLinePitchPxByNodeIndex.get(segment.nodeIndex)
7064
- ),
7065
- {
7066
- paragraphTopPx: flowTopPxBySegmentIndex[segmentIndex] ?? 0,
7067
- pageMarginTopPx: pageLayout.marginsPx.top,
7068
- location: {
7069
- kind: "paragraph",
7070
- nodeIndex: segment.nodeIndex
7071
- },
7072
- floatingMovePreview: interaction?.floatingMovePreview,
7073
- resizePreview: interaction?.resizePreview
7571
+ segment.nodeIndex,
7572
+ flowTopPx,
7573
+ paragraphRenderTextWidthPx,
7574
+ estimateParagraphLineHeightPx(
7575
+ node,
7576
+ docGridLinePitchPxByNodeIndex.get(segment.nodeIndex)
7577
+ ),
7578
+ {
7579
+ paragraphTopPx: flowTopPx,
7580
+ pageMarginTopPx: pageLayout.marginsPx.top,
7581
+ location: {
7582
+ kind: "paragraph",
7583
+ nodeIndex: segment.nodeIndex
7584
+ },
7585
+ floatingMovePreview: interaction?.floatingMovePreview,
7586
+ resizePreview: interaction?.resizePreview,
7587
+ foreignExclusions: previousObstacles ? resolveForeignWrapExclusionsForFlowRange(
7588
+ previousObstacles,
7589
+ segment.nodeIndex,
7590
+ flowTopPx,
7591
+ flowTopPx + (flowHeightPxBySegmentIndex2[segmentIndex] ?? 0)
7592
+ ) : void 0
7593
+ }
7594
+ )
7595
+ );
7596
+ }
7597
+ return obstacles2;
7598
+ };
7599
+ const baseFlowTopPxBySegmentIndex = flowTopsFromHeights(
7600
+ baseFlowHeightPxBySegmentIndex
7601
+ );
7602
+ const firstPassObstacles = collectObstacles(
7603
+ baseFlowTopPxBySegmentIndex,
7604
+ baseFlowHeightPxBySegmentIndex
7605
+ );
7606
+ let flowTopPxBySegmentIndex = baseFlowTopPxBySegmentIndex;
7607
+ let flowHeightPxBySegmentIndex = baseFlowHeightPxBySegmentIndex;
7608
+ let obstacles = firstPassObstacles;
7609
+ const hasInteractionPreview = Boolean(
7610
+ interaction?.floatingMovePreview || interaction?.resizePreview
7611
+ );
7612
+ const hasFloatingTableObstacle = segments.some((segment) => {
7613
+ const node = model.nodes[segment.nodeIndex];
7614
+ return node?.type === "table" && Boolean(node.style?.floating) && !segment.tableRowRange;
7615
+ });
7616
+ if ((hasInteractionPreview || hasFloatingTableObstacle) && firstPassObstacles.length > 0) {
7617
+ const reflowHeightPxBySegmentIndex = segments.map(
7618
+ (segment, segmentIndex) => {
7619
+ const baseHeightPx = baseFlowHeightPxBySegmentIndex[segmentIndex] ?? 0;
7620
+ const node = model.nodes[segment.nodeIndex];
7621
+ if (node?.type !== "paragraph" || segment.tableRowRange || segment.tableRowSlice || segment.paragraphLineRange) {
7622
+ return baseHeightPx;
7623
+ }
7624
+ if (node.children.some(
7625
+ (child) => child.type === "image" && shouldRenderWrappedFloatingImage(child)
7626
+ )) {
7627
+ return baseHeightPx;
7628
+ }
7629
+ const flowTopPx = baseFlowTopPxBySegmentIndex[segmentIndex] ?? 0;
7630
+ const foreignExclusions = resolveForeignWrapExclusionsForFlowRange(
7631
+ firstPassObstacles,
7632
+ segment.nodeIndex,
7633
+ flowTopPx,
7634
+ flowTopPx + baseHeightPx
7635
+ );
7636
+ if (foreignExclusions.length === 0) {
7637
+ return baseHeightPx;
7074
7638
  }
7075
- )
7639
+ const source = buildParagraphPretextLayoutSource(node);
7640
+ if (!source) {
7641
+ return baseHeightPx;
7642
+ }
7643
+ const textWidthPx = paragraphAvailableTextWidthPx(
7644
+ node,
7645
+ segmentWidthPxAt(segment.nodeIndex),
7646
+ numberingDefinitions
7647
+ );
7648
+ const lineHeightPx = Math.max(
7649
+ 1,
7650
+ Math.round(
7651
+ estimateParagraphLineHeightPx(
7652
+ node,
7653
+ docGridLinePitchPxByNodeIndex.get(segment.nodeIndex)
7654
+ )
7655
+ )
7656
+ );
7657
+ const unexcludedLayout = layoutParagraphPretextSource(
7658
+ node,
7659
+ source,
7660
+ textWidthPx,
7661
+ lineHeightPx,
7662
+ []
7663
+ );
7664
+ const excludedLayout = layoutParagraphPretextSource(
7665
+ node,
7666
+ source,
7667
+ textWidthPx,
7668
+ lineHeightPx,
7669
+ foreignExclusions
7670
+ );
7671
+ if (!unexcludedLayout || !excludedLayout) {
7672
+ return baseHeightPx;
7673
+ }
7674
+ const lineExtentPx = (layout) => layout.lines.length > 0 ? (layout.lines[layout.lines.length - 1]?.y ?? 0) + lineHeightPx : 0;
7675
+ return baseHeightPx + Math.max(
7676
+ 0,
7677
+ lineExtentPx(excludedLayout) - lineExtentPx(unexcludedLayout)
7678
+ );
7679
+ }
7680
+ );
7681
+ flowHeightPxBySegmentIndex = reflowHeightPxBySegmentIndex;
7682
+ flowTopPxBySegmentIndex = flowTopsFromHeights(reflowHeightPxBySegmentIndex);
7683
+ obstacles = collectObstacles(
7684
+ flowTopPxBySegmentIndex,
7685
+ flowHeightPxBySegmentIndex,
7686
+ firstPassObstacles
7076
7687
  );
7077
7688
  }
7078
- const result = segments.map(
7079
- (segment, segmentIndex) => resolveForeignWrapExclusionsForFlowRange(
7689
+ const result = segments.map((segment, segmentIndex) => {
7690
+ const segmentLineRange = segment.paragraphLineRange;
7691
+ const segmentCoversWholeParagraph = !segmentLineRange || segmentLineRange.startLineIndex === 0 && segmentLineRange.endLineIndex >= segmentLineRange.totalLineCount;
7692
+ const measuredParagraphBand = segmentCoversWholeParagraph ? measuredBandAt(`para:${segment.nodeIndex}`) : void 0;
7693
+ const flowTopPx = measuredParagraphBand?.topPx ?? flowTopPxBySegmentIndex[segmentIndex] ?? 0;
7694
+ const flowBottomPx = measuredParagraphBand?.bottomPx ?? flowTopPx + (flowHeightPxBySegmentIndex[segmentIndex] ?? 0);
7695
+ return resolveForeignWrapExclusionsForFlowRange(
7080
7696
  obstacles,
7081
7697
  segment.nodeIndex,
7082
- flowTopPxBySegmentIndex[segmentIndex] ?? 0,
7083
- (flowTopPxBySegmentIndex[segmentIndex] ?? 0) + (flowHeightPxBySegmentIndex[segmentIndex] ?? 0)
7084
- )
7698
+ flowTopPx,
7699
+ flowBottomPx
7700
+ );
7701
+ });
7702
+ const measuredBands = interaction?.floatingMovePreview?.measuredBands;
7703
+ const draggedAnchorNodeIndex = (() => {
7704
+ const key = interaction?.floatingMovePreview?.imageKey;
7705
+ const match = key ? /^p:(\d+):/.exec(key) : null;
7706
+ return match ? Number.parseInt(match[1], 10) : void 0;
7707
+ })();
7708
+ if (!measuredBands || draggedAnchorNodeIndex === void 0) {
7709
+ return result;
7710
+ }
7711
+ const measuredFlowBandAt = (nodeIndex) => {
7712
+ const band = measuredBands.hostByNodeIndex[nodeIndex];
7713
+ if (!band) {
7714
+ return void 0;
7715
+ }
7716
+ return {
7717
+ top: band.topPx - pageLayout.marginsPx.top,
7718
+ bottom: band.bottomPx - pageLayout.marginsPx.top
7719
+ };
7720
+ };
7721
+ const anchorSegmentIndex = segments.findIndex(
7722
+ (segment) => segment.nodeIndex === draggedAnchorNodeIndex
7085
7723
  );
7086
- return result;
7724
+ const anchorMeasuredBand = measuredFlowBandAt(draggedAnchorNodeIndex);
7725
+ if (anchorSegmentIndex < 0 || !anchorMeasuredBand) {
7726
+ return result;
7727
+ }
7728
+ const anchorEstimatedFlowTopPx = flowTopPxBySegmentIndex[anchorSegmentIndex] ?? 0;
7729
+ const draggedObstacles = [];
7730
+ const otherObstacles = [];
7731
+ for (const obstacle of obstacles) {
7732
+ if (obstacle.sourceNodeIndex === draggedAnchorNodeIndex) {
7733
+ draggedObstacles.push({
7734
+ ...obstacle,
7735
+ top: obstacle.top - anchorEstimatedFlowTopPx + anchorMeasuredBand.top,
7736
+ bottom: obstacle.bottom - anchorEstimatedFlowTopPx + anchorMeasuredBand.top
7737
+ });
7738
+ } else {
7739
+ otherObstacles.push(obstacle);
7740
+ }
7741
+ }
7742
+ if (draggedObstacles.length === 0) {
7743
+ return result;
7744
+ }
7745
+ return segments.map((segment, segmentIndex) => {
7746
+ const node = model.nodes[segment.nodeIndex];
7747
+ const measuredBand = measuredFlowBandAt(segment.nodeIndex);
7748
+ if (node?.type !== "paragraph" || segment.nodeIndex === draggedAnchorNodeIndex || !measuredBand) {
7749
+ return result[segmentIndex] ?? [];
7750
+ }
7751
+ return [
7752
+ ...resolveForeignWrapExclusionsForFlowRange(
7753
+ otherObstacles,
7754
+ segment.nodeIndex,
7755
+ flowTopPxBySegmentIndex[segmentIndex] ?? 0,
7756
+ (flowTopPxBySegmentIndex[segmentIndex] ?? 0) + (flowHeightPxBySegmentIndex[segmentIndex] ?? 0)
7757
+ ),
7758
+ ...resolveForeignWrapExclusionsForFlowRange(
7759
+ draggedObstacles,
7760
+ segment.nodeIndex,
7761
+ measuredBand.top,
7762
+ measuredBand.bottom
7763
+ ).map((exclusion) => ({ ...exclusion, fromDragPreview: true }))
7764
+ ];
7765
+ });
7087
7766
  }
7088
7767
  function applyWrappedFloatingInteractionPreviewToParagraph(paragraph, location, paragraphRenderTextWidthPx, options) {
7089
7768
  const hasInteractionPreview = Boolean(
@@ -7702,12 +8381,27 @@ function layoutParagraphPretextSource(paragraph, source, containerWidthPx, lineH
7702
8381
  );
7703
8382
  const wordBreak = pretextWordBreakModeForText(source.text);
7704
8383
  const items = buildParagraphPretextLayoutItems(paragraph, source);
8384
+ const firstLineIndentPx = twipsToSignedPixels(
8385
+ paragraph.style?.indent?.firstLineTwips
8386
+ );
8387
+ const layoutExclusions = Number.isFinite(firstLineIndentPx) && firstLineIndentPx > 0 ? [
8388
+ ...exclusions ?? [],
8389
+ {
8390
+ left: 0,
8391
+ right: Math.min(
8392
+ Math.max(1, Math.round(containerWidthPx)),
8393
+ Math.round(firstLineIndentPx)
8394
+ ),
8395
+ top: 0,
8396
+ bottom: 1
8397
+ }
8398
+ ] : exclusions;
7705
8399
  const richLayout = items.length > 0 ? layoutItemsWithPretextAroundExclusions(
7706
8400
  source.text,
7707
8401
  items,
7708
8402
  containerWidthPx,
7709
8403
  lineHeightPx,
7710
- exclusions,
8404
+ layoutExclusions,
7711
8405
  fallbackFont
7712
8406
  ) : void 0;
7713
8407
  if (richLayout) {
@@ -7718,7 +8412,7 @@ function layoutParagraphPretextSource(paragraph, source, containerWidthPx, lineH
7718
8412
  fallbackFont,
7719
8413
  containerWidthPx,
7720
8414
  lineHeightPx,
7721
- exclusions,
8415
+ layoutExclusions,
7722
8416
  {
7723
8417
  wordBreak
7724
8418
  }
@@ -7845,6 +8539,7 @@ function resolveDualWrappedFloatingImageGeometry(image, containerWidthPx, option
7845
8539
  const rawImageTopPx = (hasExplicitBaseTopPx ? baseTopPx : paragraphLocalBaseTopPx + (isInlinePreview ? 0 : distTPx)) + deltaY;
7846
8540
  const modelAllowsNegativeTop = Number.isFinite(floating?.yPx) && floating?.yPx < 0;
7847
8541
  const imageTopPx = options?.allowNegativeImageTop || modelAllowsNegativeTop ? Math.round(rawImageTopPx) : Math.max(0, Math.round(rawImageTopPx));
8542
+ const horizontalAlignIsOperative = !hasExplicitBaseLeftPx && !Number.isFinite(floating?.xPx);
7848
8543
  let exclusionLeftPx = Math.max(0, imageLeftPx - distLPx);
7849
8544
  let exclusionRightPx = Math.min(
7850
8545
  safeContainerWidthPx,
@@ -7853,9 +8548,9 @@ function resolveDualWrappedFloatingImageGeometry(image, containerWidthPx, option
7853
8548
  if (wrapType === "topAndBottom") {
7854
8549
  exclusionLeftPx = 0;
7855
8550
  exclusionRightPx = safeContainerWidthPx;
7856
- } else if (horizontalAlign === "left" || horizontalAlign === "inside") {
8551
+ } else if (horizontalAlignIsOperative && (horizontalAlign === "left" || horizontalAlign === "inside")) {
7857
8552
  exclusionLeftPx = 0;
7858
- } else if (horizontalAlign === "right" || horizontalAlign === "outside") {
8553
+ } else if (horizontalAlignIsOperative && (horizontalAlign === "right" || horizontalAlign === "outside")) {
7859
8554
  exclusionRightPx = safeContainerWidthPx;
7860
8555
  }
7861
8556
  if (!isInlinePreview && wrapType !== "topAndBottom") {
@@ -10757,6 +11452,9 @@ function estimateRenderedPageSegmentHeightPx(node, segment, model, availableWidt
10757
11452
  )
10758
11453
  );
10759
11454
  }
11455
+ if (node.type === "table" && node.style?.floating) {
11456
+ return 0;
11457
+ }
10760
11458
  return Math.max(
10761
11459
  MIN_PARAGRAPH_LINE_HEIGHT_PX,
10762
11460
  estimateTableHeightPx(
@@ -11085,7 +11783,7 @@ function buildDocumentPageNodeSegments(model, pageContentHeightPx, pageContentWi
11085
11783
  const preferLastRenderedParagraphStartBreaks = options?.preferLastRenderedParagraphStartBreaks ?? false;
11086
11784
  const strictLastRenderedParagraphStartBreaks = options?.strictLastRenderedParagraphStartBreaks ?? false;
11087
11785
  const hardBreakStartNodeIndexes = collectDocxHardPageBreakStartNodeIndexes(model);
11088
- const paginationNumberingLabels = buildParagraphNumberingLabels(model);
11786
+ const paginationNumberingLabels = options?.precomputedNumberingLabels ?? buildParagraphNumberingLabels(model);
11089
11787
  const sectionStartPageBreakNodeIndexes = collectDocxSectionStartPageBreakNodeIndexes(model);
11090
11788
  const nextHardBreakStartNodeIndexByNodeIndex = buildNextHardBreakStartNodeIndexLookup(
11091
11789
  model.nodes.length,
@@ -11657,6 +12355,11 @@ function buildDocumentPageNodeSegments(model, pageContentHeightPx, pageContentWi
11657
12355
  previousParagraphAfterPx = afterSpacingPx;
11658
12356
  continue;
11659
12357
  }
12358
+ if (node.style?.floating) {
12359
+ currentPageSegments.push({ nodeIndex });
12360
+ previousParagraphAfterPx = 0;
12361
+ continue;
12362
+ }
11660
12363
  const measuredRowHeightsPxRaw = options?.measuredTableRowHeightsByNodeIndex?.[nodeIndex];
11661
12364
  const measuredRowHeightsPx = measuredRowHeightsPxRaw && measuredRowHeightsPxRaw.length === node.rows.length ? measuredRowHeightsPxRaw.map(
11662
12365
  (heightPx) => Math.max(
@@ -12191,6 +12894,22 @@ function absoluteFloatingImageStyle(image, options) {
12191
12894
  }
12192
12895
  return style;
12193
12896
  }
12897
+ function normalizeFloatingDragDeltaForZoom(screenDeltaPx, zoomScale) {
12898
+ const safeScale = Number.isFinite(zoomScale) && zoomScale > 0 ? zoomScale : 1;
12899
+ return screenDeltaPx / safeScale;
12900
+ }
12901
+ function normalizeFloatingDropRectForZoom(rect, zoomScale) {
12902
+ const safeScale = Number.isFinite(zoomScale) && zoomScale > 0 ? zoomScale : 1;
12903
+ if (safeScale === 1) {
12904
+ return rect;
12905
+ }
12906
+ return {
12907
+ left: rect.left / safeScale,
12908
+ top: rect.top / safeScale,
12909
+ ...Number.isFinite(rect.width) ? { width: rect.width / safeScale } : void 0,
12910
+ ...Number.isFinite(rect.height) ? { height: rect.height / safeScale } : void 0
12911
+ };
12912
+ }
12194
12913
  function resolveAbsoluteFloatingImageDropPatch(floating, layout, options) {
12195
12914
  const nextLeftPx = options.wrapperRect.left + Math.round(options.deltaX);
12196
12915
  const nextTopPx = options.wrapperRect.top + Math.round(options.deltaY);
@@ -12262,11 +12981,9 @@ function resolveWrappedFloatingImageDropPatch(image, hostWidth, movedLeft, moved
12262
12981
  }
12263
12982
  );
12264
12983
  const previewUsesSideFloat = previewGeometry === void 0 || previewGeometry.exclusion.left <= 0 || previewGeometry.exclusion.right >= hostWidth;
12265
- const rawExplicitTopPx = Math.round(
12984
+ const explicitTopPx = Math.round(
12266
12985
  movedTop - Math.round(baseFloating.distTPx ?? 0)
12267
12986
  );
12268
- const currentTopPx = Math.round(baseFloating.yPx ?? 0);
12269
- const explicitTopPx = wrapType.trim().toLowerCase() === "topandbottom" && Math.abs(rawExplicitTopPx - currentTopPx) < TOP_AND_BOTTOM_VERTICAL_DRAG_SNAP_PX ? currentTopPx : rawExplicitTopPx;
12270
12987
  return {
12271
12988
  wrapType,
12272
12989
  wrapText,
@@ -12282,6 +12999,47 @@ function resolveWrappedFloatingImageDropPatch(image, hostWidth, movedLeft, moved
12282
12999
  behindDocument: false
12283
13000
  };
12284
13001
  }
13002
+ function resolveWrappedDropAnchorParagraphHost(wrapperElement, droppedTopScreenPx, droppedLeftScreenPx) {
13003
+ const viewerRoot = wrapperElement.closest("[data-testid='docx-editor-viewer']") ?? wrapperElement.ownerDocument;
13004
+ if (!viewerRoot) {
13005
+ return void 0;
13006
+ }
13007
+ const hosts = Array.from(
13008
+ viewerRoot.querySelectorAll(
13009
+ "[data-docx-paragraph-host='true'][data-docx-paragraph-kind='paragraph'][data-docx-paragraph-node-index]"
13010
+ )
13011
+ );
13012
+ let best;
13013
+ let bestDistance = Number.POSITIVE_INFINITY;
13014
+ for (const host of hosts) {
13015
+ const nodeIndex = Number.parseInt(
13016
+ host.getAttribute("data-docx-paragraph-node-index") ?? "",
13017
+ 10
13018
+ );
13019
+ if (!Number.isFinite(nodeIndex)) {
13020
+ continue;
13021
+ }
13022
+ const rect = host.getBoundingClientRect();
13023
+ if (rect.width <= 0 && rect.height <= 0) {
13024
+ continue;
13025
+ }
13026
+ const verticalDistance = droppedTopScreenPx < rect.top ? rect.top - droppedTopScreenPx : droppedTopScreenPx >= rect.bottom ? droppedTopScreenPx - rect.bottom : 0;
13027
+ const horizontalDistance = droppedLeftScreenPx < rect.left ? rect.left - droppedLeftScreenPx : droppedLeftScreenPx > rect.right ? droppedLeftScreenPx - rect.right : 0;
13028
+ const distance = verticalDistance * 4 + horizontalDistance;
13029
+ if (distance < bestDistance) {
13030
+ bestDistance = distance;
13031
+ best = { host, nodeIndex, rect };
13032
+ }
13033
+ }
13034
+ return best;
13035
+ }
13036
+ function wrappedDragCanReanchorToParagraph(floating) {
13037
+ if (!floatingImageMovesWithText(floating)) {
13038
+ return true;
13039
+ }
13040
+ const verticalRelativeTo = floating.verticalRelativeTo?.trim().toLowerCase() ?? "";
13041
+ return verticalRelativeTo === "" || verticalRelativeTo === "paragraph" || verticalRelativeTo === "line";
13042
+ }
12285
13043
  function resolvePageSpanningAbsoluteFloatingDimensions(image, widthPx, heightPx, floatingPageOriginPx) {
12286
13044
  const floating = image.floating;
12287
13045
  const pageWidthPx = Number.isFinite(floatingPageOriginPx?.pageWidth) ? Math.max(1, Math.round(floatingPageOriginPx?.pageWidth)) : void 0;
@@ -16245,6 +17003,7 @@ function createEmptyParagraphFromTemplate(template) {
16245
17003
  const nextTextStyle = cloneTextStyle2(firstRunStyle(template));
16246
17004
  return {
16247
17005
  type: "paragraph",
17006
+ blockId: allocateBlockId(),
16248
17007
  style: cloneParagraphStyle(template?.style),
16249
17008
  children: [
16250
17009
  {
@@ -16395,6 +17154,65 @@ function resolveFloatingTableSide(table) {
16395
17154
  }
16396
17155
  return "left";
16397
17156
  }
17157
+ function estimateFloatingTableWidthPx(table, containerWidthPx) {
17158
+ const explicitWidthPx = twipsToPixels(table.style?.widthTwips);
17159
+ const columnWidthsTwips = table.style?.columnWidthsTwips;
17160
+ const columnsWidthPx = columnWidthsTwips && columnWidthsTwips.length > 0 ? columnWidthsTwips.reduce(
17161
+ (total, widthTwips) => total + (twipsToPixels(widthTwips) ?? 0),
17162
+ 0
17163
+ ) : void 0;
17164
+ return Math.max(
17165
+ 24,
17166
+ Math.min(
17167
+ Math.max(1, Math.round(containerWidthPx)),
17168
+ Math.round(explicitWidthPx ?? columnsWidthPx ?? containerWidthPx)
17169
+ )
17170
+ );
17171
+ }
17172
+ function resolveFloatingTableGeometry(table, containerWidthPx, options) {
17173
+ const floating = table.style?.floating;
17174
+ if (!floating) {
17175
+ return void 0;
17176
+ }
17177
+ const safeContainerWidthPx = Math.max(1, Math.round(containerWidthPx));
17178
+ const tableWidthPx = Math.max(1, Math.round(options.tableWidthPx));
17179
+ const tableHeightPx = Math.max(0, Math.round(options.tableHeightPx));
17180
+ const distLPx = twipsToPixels(floating.leftFromTextTwips) ?? 0;
17181
+ const distRPx = twipsToPixels(floating.rightFromTextTwips) ?? 0;
17182
+ const distTPx = twipsToPixels(floating.topFromTextTwips) ?? 0;
17183
+ const distBPx = twipsToPixels(floating.bottomFromTextTwips) ?? 0;
17184
+ const xPx = twipsToSignedPixels(floating.xTwips);
17185
+ const yPx = twipsToSignedPixels(floating.yTwips);
17186
+ const horizontalAnchor = floating.horizontalAnchor?.trim().toLowerCase();
17187
+ const verticalAnchor = floating.verticalAnchor?.trim().toLowerCase();
17188
+ const horizontalAlign = floating.horizontalAlign?.trim().toLowerCase();
17189
+ const flowTopPx = Math.round(options.flowTopPx ?? 0);
17190
+ const deltaX = Math.round(options.deltaX ?? 0);
17191
+ const deltaY = Math.round(options.deltaY ?? 0);
17192
+ const leftPx = (xPx !== void 0 ? horizontalAnchor === "page" ? xPx - Math.round(options.pageMarginLeftPx ?? 0) : xPx : horizontalAlign === "right" || horizontalAlign === "outside" ? safeContainerWidthPx - tableWidthPx - distRPx : horizontalAlign === "center" ? Math.round((safeContainerWidthPx - tableWidthPx) / 2) : horizontalAlign === "left" || horizontalAlign === "inside" ? distLPx : Math.round(options.indentPx ?? 0)) + deltaX;
17193
+ const topPx = (yPx !== void 0 ? verticalAnchor === "margin" ? yPx - flowTopPx : verticalAnchor === "page" ? yPx - Math.round(options.pageMarginTopPx ?? 0) - flowTopPx : yPx : 0) + deltaY;
17194
+ let exclusionLeftPx = Math.max(0, leftPx - distLPx);
17195
+ let exclusionRightPx = Math.min(
17196
+ safeContainerWidthPx,
17197
+ leftPx + tableWidthPx + distRPx
17198
+ );
17199
+ if (exclusionLeftPx > 0 && exclusionLeftPx < MIN_DUAL_WRAPPED_INTERIOR_BAND_PX) {
17200
+ exclusionLeftPx = 0;
17201
+ }
17202
+ if (exclusionRightPx < safeContainerWidthPx && safeContainerWidthPx - exclusionRightPx < MIN_DUAL_WRAPPED_INTERIOR_BAND_PX) {
17203
+ exclusionRightPx = safeContainerWidthPx;
17204
+ }
17205
+ return {
17206
+ leftPx,
17207
+ topPx,
17208
+ exclusion: {
17209
+ left: exclusionLeftPx,
17210
+ right: exclusionRightPx,
17211
+ top: topPx - distTPx,
17212
+ bottom: topPx + tableHeightPx + distBPx
17213
+ }
17214
+ };
17215
+ }
16398
17216
  function tableWrapperStyle(table, indentPx) {
16399
17217
  const floating = table.style?.floating;
16400
17218
  if (!floating) {
@@ -18929,6 +19747,22 @@ function shouldReissueDomSelectionRestore(options) {
18929
19747
  }
18930
19748
  return options.modelChanged;
18931
19749
  }
19750
+ function stableInnerHtmlProp(cache, key, html) {
19751
+ const cached = cache.get(key);
19752
+ if (cached && cached.__html === html) {
19753
+ return cached;
19754
+ }
19755
+ const next = { __html: html };
19756
+ cache.set(key, next);
19757
+ return next;
19758
+ }
19759
+ function isCompositionKeyboardEvent(event) {
19760
+ const nativeKeyboardEvent = event.nativeEvent;
19761
+ if (nativeKeyboardEvent?.isComposing) {
19762
+ return true;
19763
+ }
19764
+ return event.keyCode === 229;
19765
+ }
18932
19766
  function shouldSyncActiveRangeOnKeyUp(event) {
18933
19767
  const nativeKeyboardEvent = event.nativeEvent;
18934
19768
  if (nativeKeyboardEvent?.isComposing) {
@@ -19473,12 +20307,14 @@ function updateSectionImageFloatingAtLocation(model, location, patch) {
19473
20307
  });
19474
20308
  return changed ? next : model;
19475
20309
  }
20310
+ var NO_TRACKED_CHANGES = [];
20311
+ var NO_COMMENTS = [];
19476
20312
  function useDocxEditor(options = {}) {
19477
20313
  const starterTemplateRef = React.useRef(
19478
- cloneDocModel(options.starterModel ?? defaultStarterModel)
20314
+ cloneDocModelWithBlockIds(options.starterModel ?? defaultStarterModel)
19479
20315
  );
19480
20316
  const [model, setModel] = React.useState(
19481
- () => cloneDocModel(starterTemplateRef.current)
20317
+ () => cloneDocModelWithBlockIds(starterTemplateRef.current)
19482
20318
  );
19483
20319
  const [basePackage, setBasePackage] = React.useState();
19484
20320
  const [documentLoadNonce, setDocumentLoadNonce] = React.useState(0);
@@ -19522,6 +20358,9 @@ function useDocxEditor(options = {}) {
19522
20358
  pendingRunStyle
19523
20359
  );
19524
20360
  const suppressNextDomSelectionRestoreRef = React.useRef(false);
20361
+ const textCommitBurstRef = React.useRef(
20362
+ void 0
20363
+ );
19525
20364
  const domSelectionRestoreModelRef = React.useRef(model);
19526
20365
  const selectionSessionRef = React.useRef("idle");
19527
20366
  const selectionSessionTimeoutRef = React.useRef(null);
@@ -19533,6 +20372,17 @@ function useDocxEditor(options = {}) {
19533
20372
  React.useEffect(() => {
19534
20373
  modelRef.current = model;
19535
20374
  }, [model]);
20375
+ React.useEffect(() => {
20376
+ if (typeof process === "undefined" || process.env?.NODE_ENV === "production") {
20377
+ return;
20378
+ }
20379
+ const duplicateBlockIds = collectDuplicateDocModelBlockIds(model);
20380
+ if (duplicateBlockIds.length > 0) {
20381
+ console.error(
20382
+ `Duplicate doc-model block ids detected (an op copied a node without allocating a fresh id): ${duplicateBlockIds.join(", ")}`
20383
+ );
20384
+ }
20385
+ }, [model]);
19536
20386
  React.useEffect(() => {
19537
20387
  selectionRef.current = selection;
19538
20388
  }, [selection]);
@@ -19814,12 +20664,13 @@ function useDocxEditor(options = {}) {
19814
20664
  }, [activeTextRange, selectedParagraph, selectedParagraphLocation]);
19815
20665
  const selectedListType = selectedParagraph ? paragraphListType(selectedParagraph, model.metadata.numberingDefinitions) : void 0;
19816
20666
  const trackedChanges = React.useMemo(
19817
- () => collectTrackedChangesFromModel(model),
19818
- [model]
20667
+ () => showTrackedChanges ? collectTrackedChangesFromModel(model) : NO_TRACKED_CHANGES,
20668
+ [model, showTrackedChanges]
20669
+ );
20670
+ const comments = React.useMemo(
20671
+ () => showComments ? collectCommentsFromModel(model) : NO_COMMENTS,
20672
+ [model, showComments]
19819
20673
  );
19820
- const comments = React.useMemo(() => collectCommentsFromModel(model), [
19821
- model
19822
- ]);
19823
20674
  const hasUnorderedList = selectedListType === "unordered";
19824
20675
  const hasOrderedList = selectedListType === "ordered";
19825
20676
  const canUndo = history.past.length > 0;
@@ -20142,7 +20993,7 @@ function useDocxEditor(options = {}) {
20142
20993
  activeImportAbortControllerRef.current?.abort();
20143
20994
  activeImportAbortControllerRef.current = void 0;
20144
20995
  unloadEmbeddedFonts();
20145
- setModel(cloneDocModel(starterTemplateRef.current));
20996
+ setModel(cloneDocModelWithBlockIds(starterTemplateRef.current));
20146
20997
  setDocumentLoadNonce((current) => current + 1);
20147
20998
  setBasePackage(void 0);
20148
20999
  setFileName("(new document)");
@@ -20179,6 +21030,7 @@ function useDocxEditor(options = {}) {
20179
21030
  setStatus("Exported DOCX");
20180
21031
  }, [basePackage, fileName]);
20181
21032
  const undo = React.useCallback(() => {
21033
+ textCommitBurstRef.current = void 0;
20182
21034
  setHistory((currentHistory) => {
20183
21035
  const previousSnapshot = currentHistory.past[currentHistory.past.length - 1];
20184
21036
  const previous = previousSnapshot?.model;
@@ -20218,6 +21070,7 @@ function useDocxEditor(options = {}) {
20218
21070
  });
20219
21071
  }, []);
20220
21072
  const redo = React.useCallback(() => {
21073
+ textCommitBurstRef.current = void 0;
20221
21074
  setHistory((currentHistory) => {
20222
21075
  const nextSnapshot = currentHistory.future[0];
20223
21076
  const next = nextSnapshot?.model;
@@ -20770,6 +21623,7 @@ function useDocxEditor(options = {}) {
20770
21623
  next.nodes = [
20771
21624
  {
20772
21625
  type: "paragraph",
21626
+ blockId: allocateBlockId(),
20773
21627
  children: [
20774
21628
  {
20775
21629
  type: "text",
@@ -20969,6 +21823,7 @@ function useDocxEditor(options = {}) {
20969
21823
  next.nodes = [
20970
21824
  {
20971
21825
  type: "paragraph",
21826
+ blockId: allocateBlockId(),
20972
21827
  children: [{ type: "text", text: "" }]
20973
21828
  }
20974
21829
  ];
@@ -21008,6 +21863,7 @@ function useDocxEditor(options = {}) {
21008
21863
  next.nodes = [
21009
21864
  {
21010
21865
  type: "paragraph",
21866
+ blockId: allocateBlockId(),
21011
21867
  children: [{ type: "text", text: "" }]
21012
21868
  }
21013
21869
  ];
@@ -21747,6 +22603,7 @@ function useDocxEditor(options = {}) {
21747
22603
  paragraphNode.sourceXml = void 0;
21748
22604
  next.nodes.splice(insertionIndex, 0, {
21749
22605
  type: "paragraph",
22606
+ blockId: allocateBlockId(),
21750
22607
  style: cloneParagraphStyle(paragraphNode.style),
21751
22608
  children: [
21752
22609
  {
@@ -21843,6 +22700,7 @@ function useDocxEditor(options = {}) {
21843
22700
  paragraphNode.sourceXml = void 0;
21844
22701
  next.nodes.splice(insertionIndex, 0, {
21845
22702
  type: "paragraph",
22703
+ blockId: allocateBlockId(),
21846
22704
  style: cloneParagraphStyle(splitParagraphStyle),
21847
22705
  children: splitChildren.afterChildren
21848
22706
  });
@@ -21889,6 +22747,7 @@ function useDocxEditor(options = {}) {
21889
22747
  0,
21890
22748
  {
21891
22749
  type: "table",
22750
+ blockId: allocateBlockId(),
21892
22751
  style: {
21893
22752
  borders: createDefaultEditorTableBorders()
21894
22753
  },
@@ -21902,6 +22761,7 @@ function useDocxEditor(options = {}) {
21902
22761
  nodes: [
21903
22762
  {
21904
22763
  type: "paragraph",
22764
+ blockId: allocateBlockId(),
21905
22765
  children: [
21906
22766
  {
21907
22767
  type: "text",
@@ -21917,6 +22777,7 @@ function useDocxEditor(options = {}) {
21917
22777
  nodes: [
21918
22778
  {
21919
22779
  type: "paragraph",
22780
+ blockId: allocateBlockId(),
21920
22781
  children: [
21921
22782
  {
21922
22783
  type: "text",
@@ -21937,6 +22798,7 @@ function useDocxEditor(options = {}) {
21937
22798
  nodes: [
21938
22799
  {
21939
22800
  type: "paragraph",
22801
+ blockId: allocateBlockId(),
21940
22802
  children: [{ type: "text", text: "Value 1" }]
21941
22803
  }
21942
22804
  ]
@@ -21946,6 +22808,7 @@ function useDocxEditor(options = {}) {
21946
22808
  nodes: [
21947
22809
  {
21948
22810
  type: "paragraph",
22811
+ blockId: allocateBlockId(),
21949
22812
  children: [{ type: "text", text: "Value 2" }]
21950
22813
  }
21951
22814
  ]
@@ -22015,6 +22878,7 @@ function useDocxEditor(options = {}) {
22015
22878
  const next = cloneDocModel(current);
22016
22879
  next.nodes.push({
22017
22880
  type: "paragraph",
22881
+ blockId: allocateBlockId(),
22018
22882
  children: [{ type: "text", text }]
22019
22883
  });
22020
22884
  return next;
@@ -22130,7 +22994,7 @@ function useDocxEditor(options = {}) {
22130
22994
  [applyModelChange]
22131
22995
  );
22132
22996
  const moveFloatingImage = React.useCallback(
22133
- (location, patch) => {
22997
+ (location, patch, options2) => {
22134
22998
  applyModelChange((current) => {
22135
22999
  const next = cloneDocModel(current);
22136
23000
  const { paragraph, tableNode } = getParagraphAtLocation(
@@ -22148,6 +23012,16 @@ function useDocxEditor(options = {}) {
22148
23012
  ...child.floating ?? {},
22149
23013
  ...patch
22150
23014
  };
23015
+ const reparentNodeIndex = options2?.reparentToParagraphNodeIndex;
23016
+ const reparentTarget = reparentNodeIndex !== void 0 ? next.nodes[reparentNodeIndex] : void 0;
23017
+ if (reparentTarget && reparentTarget.type === "paragraph" && reparentTarget !== paragraph) {
23018
+ paragraph.children.splice(location.childIndex, 1);
23019
+ if (paragraph.children.length === 0) {
23020
+ paragraph.children.push({ type: "text", text: "" });
23021
+ }
23022
+ reparentTarget.children.unshift(child);
23023
+ reparentTarget.sourceXml = void 0;
23024
+ }
22151
23025
  paragraph.sourceXml = void 0;
22152
23026
  if (tableNode) {
22153
23027
  tableNode.sourceXml = void 0;
@@ -22407,6 +23281,7 @@ function useDocxEditor(options = {}) {
22407
23281
  const firstParagraph = paragraphs[0];
22408
23282
  const nextParagraph = {
22409
23283
  type: "paragraph",
23284
+ blockId: allocateBlockId(),
22410
23285
  style: cloneParagraphStyle(firstParagraph?.style),
22411
23286
  children: [
22412
23287
  {
@@ -22498,6 +23373,7 @@ function useDocxEditor(options = {}) {
22498
23373
  if (next.nodes.length === 0) {
22499
23374
  next.nodes.push({
22500
23375
  type: "paragraph",
23376
+ blockId: allocateBlockId(),
22501
23377
  children: [{ type: "text", text: "" }]
22502
23378
  });
22503
23379
  nextSelection = { kind: "paragraph", nodeIndex: 0 };
@@ -22569,6 +23445,51 @@ function useDocxEditor(options = {}) {
22569
23445
  },
22570
23446
  [applyModelChange]
22571
23447
  );
23448
+ const setTableFloating = React.useCallback(
23449
+ (tableIndex, patch, options2) => {
23450
+ applyModelChange((current) => {
23451
+ const tableNode = current.nodes[tableIndex];
23452
+ if (!tableNode || tableNode.type !== "table") {
23453
+ return current;
23454
+ }
23455
+ const next = cloneDocModel(current);
23456
+ const nextTable = next.nodes[tableIndex];
23457
+ if (!nextTable || nextTable.type !== "table") {
23458
+ return current;
23459
+ }
23460
+ nextTable.style = {
23461
+ ...nextTable.style ?? {},
23462
+ floating: {
23463
+ ...nextTable.style?.floating ?? {},
23464
+ ...patch
23465
+ }
23466
+ };
23467
+ nextTable.sourceXml = void 0;
23468
+ const moveToNodeIndex = options2?.moveToNodeIndex;
23469
+ if (moveToNodeIndex !== void 0 && moveToNodeIndex !== tableIndex && moveToNodeIndex !== tableIndex + 1) {
23470
+ const clampedTarget = clampNumber(
23471
+ moveToNodeIndex,
23472
+ 0,
23473
+ next.nodes.length
23474
+ );
23475
+ const extracted = next.nodes.splice(tableIndex, 1)[0];
23476
+ if (extracted) {
23477
+ next.nodes.splice(
23478
+ clampNumber(
23479
+ clampedTarget > tableIndex ? clampedTarget - 1 : clampedTarget,
23480
+ 0,
23481
+ next.nodes.length
23482
+ ),
23483
+ 0,
23484
+ extracted
23485
+ );
23486
+ }
23487
+ }
23488
+ return next;
23489
+ }, "Moved table");
23490
+ },
23491
+ [applyModelChange]
23492
+ );
22572
23493
  const moveEmbeddedTableToBody = React.useCallback(
22573
23494
  (tableRuntimeKey, targetNodeIndex) => {
22574
23495
  const runtimeLocation = parseEmbeddedTableRuntimeKey(tableRuntimeKey);
@@ -23022,6 +23943,100 @@ function useDocxEditor(options = {}) {
23022
23943
  },
23023
23944
  [applyModelChange]
23024
23945
  );
23946
+ const commitParagraphTextAtRange = React.useCallback(
23947
+ (location, text, caret, options2) => {
23948
+ const now = Date.now();
23949
+ return dispatchEditorTransaction((current) => {
23950
+ const paragraph = getParagraphAtLocation(
23951
+ current.model,
23952
+ location
23953
+ ).paragraph;
23954
+ if (!paragraph) {
23955
+ return void 0;
23956
+ }
23957
+ const insertionOffset = options2?.insertionOffset ?? caret.start;
23958
+ const insertedStyle = cloneTextStyle2(current.pendingRunStyle) ?? firstTextStyleAtOffset(paragraph, insertionOffset, false);
23959
+ const nextModel = paragraphText(paragraph) === text ? current.model : updateParagraphTextAtLocation(current.model, location, text, {
23960
+ insertedStyle
23961
+ });
23962
+ const coalesce = options2?.coalesceKey !== void 0 && shouldCoalesceTextCommit(textCommitBurstRef.current, {
23963
+ key: options2.coalesceKey,
23964
+ caretBefore: insertionOffset,
23965
+ at: now
23966
+ });
23967
+ textCommitBurstRef.current = options2?.coalesceKey !== void 0 ? { key: options2.coalesceKey, caretAfter: caret.end, at: now } : void 0;
23968
+ return {
23969
+ model: nextModel,
23970
+ selection: selectionFromTextRangeLocation(location),
23971
+ activeTextRange: {
23972
+ start: {
23973
+ location: cloneTextRangeLocation(location),
23974
+ offset: caret.start
23975
+ },
23976
+ end: {
23977
+ location: cloneTextRangeLocation(location),
23978
+ offset: caret.end
23979
+ }
23980
+ },
23981
+ pushHistory: !coalesce,
23982
+ clearSelectedFormField: true
23983
+ };
23984
+ });
23985
+ },
23986
+ [dispatchEditorTransaction]
23987
+ );
23988
+ const commitTableCellTextAtRange = React.useCallback(
23989
+ (tableIndex, rowIndex, cellIndex, text, caret) => {
23990
+ textCommitBurstRef.current = void 0;
23991
+ return dispatchEditorTransaction((current) => {
23992
+ const tableNode = current.model.nodes[tableIndex];
23993
+ if (!tableNode || tableNode.type !== "table") {
23994
+ return void 0;
23995
+ }
23996
+ if (!tableNode.rows[rowIndex]?.cells[cellIndex]) {
23997
+ return void 0;
23998
+ }
23999
+ const caretLocation = {
24000
+ kind: "table-cell",
24001
+ tableIndex,
24002
+ rowIndex,
24003
+ cellIndex,
24004
+ paragraphIndex: caret.paragraphIndex
24005
+ };
24006
+ const caretParagraph = getParagraphAtLocation(
24007
+ current.model,
24008
+ caretLocation
24009
+ ).paragraph;
24010
+ const insertedStyle = cloneTextStyle2(current.pendingRunStyle) ?? (caretParagraph ? firstTextStyleAtOffset(caretParagraph, caret.start, false) : void 0);
24011
+ const nextModel = updateTableCellText(
24012
+ current.model,
24013
+ tableIndex,
24014
+ rowIndex,
24015
+ cellIndex,
24016
+ text,
24017
+ {
24018
+ insertedStyle
24019
+ }
24020
+ );
24021
+ return {
24022
+ model: nextModel,
24023
+ selection: selectionFromTextRangeLocation(caretLocation),
24024
+ activeTextRange: {
24025
+ start: {
24026
+ location: cloneTextRangeLocation(caretLocation),
24027
+ offset: caret.start
24028
+ },
24029
+ end: {
24030
+ location: cloneTextRangeLocation(caretLocation),
24031
+ offset: caret.end
24032
+ }
24033
+ },
24034
+ clearSelectedFormField: true
24035
+ };
24036
+ });
24037
+ },
24038
+ [dispatchEditorTransaction]
24039
+ );
23025
24040
  const commitSectionParagraphText = React.useCallback(
23026
24041
  (location, text) => {
23027
24042
  applyModelChange(
@@ -23150,12 +24165,15 @@ function useDocxEditor(options = {}) {
23150
24165
  deleteTableColumn,
23151
24166
  deleteTable,
23152
24167
  moveTable,
24168
+ setTableFloating,
23153
24169
  moveEmbeddedTableToBody,
23154
24170
  replaceExpandedSelection,
23155
24171
  deleteExpandedSelection,
23156
24172
  commitParagraphText,
23157
24173
  commitTableCellText,
23158
24174
  commitTableCellParagraphTextRecursive,
24175
+ commitParagraphTextAtRange,
24176
+ commitTableCellTextAtRange,
23159
24177
  commitSectionParagraphText
23160
24178
  };
23161
24179
  }
@@ -25583,8 +26601,9 @@ function DocxEditorViewer({
25583
26601
  ]
25584
26602
  );
25585
26603
  const viewerRootRef = React.useRef(null);
25586
- const paragraphDraftsRef = React.useRef(/* @__PURE__ */ new Map());
25587
26604
  const tableCellDraftsRef = React.useRef(/* @__PURE__ */ new Map());
26605
+ const editableParagraphHtmlPropsRef = React.useRef(/* @__PURE__ */ new Map());
26606
+ const editableTableCellHtmlPropsRef = React.useRef(/* @__PURE__ */ new Map());
25588
26607
  const tableCellParagraphDraftsRef = React.useRef(
25589
26608
  /* @__PURE__ */ new Map()
25590
26609
  );
@@ -25597,9 +26616,27 @@ function DocxEditorViewer({
25597
26616
  /* @__PURE__ */ new Map()
25598
26617
  );
25599
26618
  const [
25600
- measuredParagraphOuterHeightsPxByNodeIndex,
25601
- setMeasuredParagraphOuterHeightsPxByNodeIndex
26619
+ measuredParagraphOuterHeightsPxByBlockId,
26620
+ setMeasuredParagraphOuterHeightsPxByBlockId
25602
26621
  ] = React.useState(() => /* @__PURE__ */ new Map());
26622
+ const measuredParagraphOuterHeightsPxByNodeIndex = React.useMemo(() => {
26623
+ const byNodeIndex = /* @__PURE__ */ new Map();
26624
+ if (measuredParagraphOuterHeightsPxByBlockId.size === 0) {
26625
+ return byNodeIndex;
26626
+ }
26627
+ editor.model.nodes.forEach((node, nodeIndex) => {
26628
+ if (node.type !== "paragraph" || !node.blockId) {
26629
+ return;
26630
+ }
26631
+ const outerHeightPx = measuredParagraphOuterHeightsPxByBlockId.get(
26632
+ node.blockId
26633
+ );
26634
+ if (outerHeightPx !== void 0) {
26635
+ byNodeIndex.set(nodeIndex, outerHeightPx);
26636
+ }
26637
+ });
26638
+ return byNodeIndex;
26639
+ }, [editor.model.nodes, measuredParagraphOuterHeightsPxByBlockId]);
25603
26640
  const tableCellEditorElementsRef = React.useRef(
25604
26641
  /* @__PURE__ */ new Map()
25605
26642
  );
@@ -25638,6 +26675,8 @@ function DocxEditorViewer({
25638
26675
  const tableDraftLayoutRefreshRafRef = React.useRef(null);
25639
26676
  const activeRangeFlushFrameRef = React.useRef(null);
25640
26677
  const pendingEditableCaretRef = React.useRef(null);
26678
+ const editingIntentContinuationRef = React.useRef(void 0);
26679
+ const compositionActiveRef = React.useRef(false);
25641
26680
  const pointerSelectionDragRef = React.useRef({ down: false, moved: false });
25642
26681
  const deferredCollapsedSelectionSyncTimeoutRef = React.useRef(
25643
26682
  null
@@ -25722,6 +26761,10 @@ function DocxEditorViewer({
25722
26761
  measuredPageContentIdentityKeysByIndex,
25723
26762
  setMeasuredPageContentIdentityKeysByIndex
25724
26763
  ] = React.useState([]);
26764
+ const [
26765
+ measuredPageContentValidationByIndex,
26766
+ setMeasuredPageContentValidationByIndex
26767
+ ] = React.useState([]);
25725
26768
  const [hasMeasuredBodyFooterOverlap, setHasMeasuredBodyFooterOverlap] = React.useState(false);
25726
26769
  const measuredBodyFooterOverlapCandidateRef = React.useRef({
25727
26770
  signature: void 0,
@@ -25781,6 +26824,7 @@ function DocxEditorViewer({
25781
26824
  React.useEffect(() => {
25782
26825
  setMeasuredPageContentHeightByIndex([]);
25783
26826
  setMeasuredPageContentIdentityKeysByIndex([]);
26827
+ setMeasuredPageContentValidationByIndex([]);
25784
26828
  setHasMeasuredBodyFooterOverlap(false);
25785
26829
  measuredBodyFooterOverlapCandidateRef.current = {
25786
26830
  signature: void 0,
@@ -25803,7 +26847,7 @@ function DocxEditorViewer({
25803
26847
  setActiveDropTarget(void 0);
25804
26848
  setIsDraggingImage(false);
25805
26849
  setActiveHeaderFooterEdit(void 0);
25806
- paragraphDraftsRef.current.clear();
26850
+ editingIntentContinuationRef.current = void 0;
25807
26851
  tableCellDraftsRef.current.clear();
25808
26852
  tableCellParagraphDraftsRef.current.clear();
25809
26853
  sectionParagraphDraftsRef.current.clear();
@@ -25851,6 +26895,7 @@ function DocxEditorViewer({
25851
26895
  const suppressNextTableCellClickRef = React.useRef(false);
25852
26896
  const [tableCellSelectionRange, setTableCellSelectionRange] = React.useState();
25853
26897
  const [tableMoveDropPreview, setTableMoveDropPreview] = React.useState();
26898
+ const [tableFloatingDragPreview, setTableFloatingDragPreview] = React.useState();
25854
26899
  const [tableContextMenuState, setTableContextMenuState] = React.useState();
25855
26900
  const [contextMenuState, setContextMenuState] = React.useState();
25856
26901
  const [activeHeaderFooterEdit, setActiveHeaderFooterEdit] = React.useState();
@@ -25860,13 +26905,36 @@ function DocxEditorViewer({
25860
26905
  );
25861
26906
  const [paragraphStructureEpoch, bumpParagraphStructureEpoch] = React.useReducer((value) => value + 1, 0);
25862
26907
  const [paginationMeasurementEpoch, bumpPaginationMeasurementEpoch] = React.useReducer((value) => value + 1, 0);
26908
+ const [measuredWrapBands, setMeasuredWrapBands] = React.useState(() => /* @__PURE__ */ new Map());
26909
+ const wrapBandReconcileModelRef = React.useRef(void 0);
26910
+ const wrapBandReconcilePassCountRef = React.useRef(0);
25863
26911
  const paginationMeasurementSuspendUntilRef = React.useRef(0);
25864
26912
  const paginationMeasurementResumeTimeoutRef = React.useRef(
25865
26913
  null
25866
26914
  );
25867
26915
  React.useLayoutEffect(() => {
25868
- setMeasuredParagraphOuterHeightsPxByNodeIndex(/* @__PURE__ */ new Map());
25869
- }, [editor.documentLoadNonce, paragraphStructureEpoch]);
26916
+ setMeasuredParagraphOuterHeightsPxByBlockId(/* @__PURE__ */ new Map());
26917
+ }, [editor.documentLoadNonce]);
26918
+ React.useEffect(() => {
26919
+ setMeasuredParagraphOuterHeightsPxByBlockId((current) => {
26920
+ if (current.size === 0) {
26921
+ return current;
26922
+ }
26923
+ const liveBlockIds = /* @__PURE__ */ new Set();
26924
+ for (const node of editor.model.nodes) {
26925
+ if (node.blockId) {
26926
+ liveBlockIds.add(node.blockId);
26927
+ }
26928
+ }
26929
+ let next;
26930
+ current.forEach((_, blockId) => {
26931
+ if (!liveBlockIds.has(blockId)) {
26932
+ (next ??= new Map(current)).delete(blockId);
26933
+ }
26934
+ });
26935
+ return next ?? current;
26936
+ });
26937
+ }, [editor.model.nodes]);
25870
26938
  const schedulePaginationMeasurementResume = React.useCallback(
25871
26939
  (delayMs) => {
25872
26940
  if (typeof window === "undefined") {
@@ -25962,6 +27030,7 @@ function DocxEditorViewer({
25962
27030
  setHoveredEmbeddedTableKey(void 0);
25963
27031
  setFocusedEmbeddedTableKey(void 0);
25964
27032
  setTableMoveDropPreview(void 0);
27033
+ setTableFloatingDragPreview(void 0);
25965
27034
  tableMoveDragRef.current = void 0;
25966
27035
  setTableContextMenuState(void 0);
25967
27036
  setContextMenuState(void 0);
@@ -26016,18 +27085,12 @@ function DocxEditorViewer({
26016
27085
  const nextNodeCount = editor.model.nodes.length;
26017
27086
  const structureChanged = previousNodeCount !== nextNodeCount;
26018
27087
  if (structureChanged) {
26019
- paragraphDraftsRef.current.clear();
27088
+ editingIntentContinuationRef.current = void 0;
26020
27089
  tableCellDraftsRef.current.clear();
26021
27090
  tableCellParagraphDraftsRef.current.clear();
26022
27091
  pendingTableCellFocusRef.current = void 0;
26023
27092
  bumpParagraphStructureEpoch();
26024
27093
  }
26025
- paragraphDraftsRef.current.forEach((_, nodeIndex) => {
26026
- const node = editor.model.nodes[nodeIndex];
26027
- if (!node || node.type !== "paragraph") {
26028
- paragraphDraftsRef.current.delete(nodeIndex);
26029
- }
26030
- });
26031
27094
  tableCellDraftsRef.current.forEach((_, draftKey) => {
26032
27095
  const [tableIndexRaw, rowIndexRaw, cellIndexRaw] = draftKey.split(":");
26033
27096
  const tableIndex = Number.parseInt(tableIndexRaw ?? "", 10);
@@ -26079,6 +27142,27 @@ function DocxEditorViewer({
26079
27142
  () => buildPaginationSectionMetrics(documentSections, documentLayout),
26080
27143
  [documentLayout, documentSections]
26081
27144
  );
27145
+ const paginationMeasurementContextSignature = React.useMemo(
27146
+ () => [
27147
+ Math.round(documentLayout.pageWidthPx),
27148
+ Math.round(documentLayout.pageHeightPx),
27149
+ Math.round(documentLayout.marginsPx.top),
27150
+ Math.round(documentLayout.marginsPx.bottom),
27151
+ Math.round(documentLayout.marginsPx.left),
27152
+ Math.round(documentLayout.marginsPx.right),
27153
+ trackedChangesEnabled ? "tc1" : "tc0",
27154
+ docNodeContentSignature(paginationSectionMetrics)
27155
+ ].join("|"),
27156
+ [documentLayout, paginationSectionMetrics, trackedChangesEnabled]
27157
+ );
27158
+ React.useEffect(() => {
27159
+ setMeasuredParagraphOuterHeightsPxByBlockId(
27160
+ (current) => current.size === 0 ? current : /* @__PURE__ */ new Map()
27161
+ );
27162
+ setTableMeasuredRowHeights(
27163
+ (current) => Object.keys(current).length === 0 ? current : {}
27164
+ );
27165
+ }, [paginationMeasurementContextSignature]);
26082
27166
  const {
26083
27167
  docGridLinePitchPxByNodeIndex,
26084
27168
  pageContentWidthPxByNodeIndex,
@@ -26176,6 +27260,7 @@ function DocxEditorViewer({
26176
27260
  tableMeasuredRowHeights,
26177
27261
  {
26178
27262
  allowMeasuredImportPagination,
27263
+ allowContentSignatureValidatedTables: !disableMeasuredImportPagination,
26179
27264
  activeDraftKeys,
26180
27265
  numberingDefinitions: editor.model.metadata.numberingDefinitions,
26181
27266
  pageContentWidthPxByNodeIndex,
@@ -26206,36 +27291,52 @@ function DocxEditorViewer({
26206
27291
  );
26207
27292
  const suppressSpacingBeforeAfterPageBreak = editor.model.metadata.compatibility?.suppressSpacingBeforeAfterPageBreak === true;
26208
27293
  const preferLastRenderedParagraphStartBreaks = !editor.canUndo && !editor.canRedo;
26209
- const canUseMeasuredPageContentHeights = !editor.canUndo && !editor.canRedo && !disableMeasuredImportPagination && !floatingMovePreview && !dropCapMovePreview && (measuredPageContentHeightByIndex?.length ?? 0) > 0;
27294
+ const measuredPageContentHeightsPxForPagination = (measuredPageContentHeightByIndex?.length ?? 0) === 0 ? void 0 : !editor.canUndo && !editor.canRedo ? measuredPageContentHeightByIndex : resolveMeasuredPageContentHeightsPxForEditedModel(
27295
+ editor.model.nodes,
27296
+ measuredPageContentHeightByIndex,
27297
+ measuredPageContentValidationByIndex,
27298
+ paginationMeasurementContextSignature
27299
+ );
27300
+ const canUseMeasuredPageContentHeights = !disableMeasuredImportPagination && !floatingMovePreview && !dropCapMovePreview && (measuredPageContentHeightsPxForPagination?.length ?? 0) > 0;
27301
+ const buildEstimatedPagesForInputs = createEstimatedPagesBuildMemo(
27302
+ (measuredTableRowHeightsByNodeIndex, measuredPageContentHeightsPx, strictLastRenderedParagraphStartBreaks) => {
27303
+ const buildPagesWithHeights = (resolvedPageContentHeights) => buildDocumentPageNodeSegments(
27304
+ editor.model,
27305
+ pageContentHeightPx,
27306
+ pageContentWidthPx,
27307
+ editor.model.metadata.numberingDefinitions,
27308
+ paginationSectionMetrics,
27309
+ {
27310
+ allowParagraphLineSplitting: true,
27311
+ suppressSpacingBeforeAfterPageBreak,
27312
+ preferLastRenderedParagraphStartBreaks,
27313
+ strictLastRenderedParagraphStartBreaks,
27314
+ measuredTableRowHeightsByNodeIndex,
27315
+ measuredPageContentHeightsPxByPageIndex: resolvedPageContentHeights,
27316
+ measuredParagraphOuterHeightsPxByNodeIndex,
27317
+ precomputedNumberingLabels: paragraphNumberingLabels
27318
+ }
27319
+ );
27320
+ const basePages = buildPagesWithHeights(measuredPageContentHeightsPx);
27321
+ return applyEstimatedFootnoteReserveToPages(
27322
+ editor.model,
27323
+ basePages,
27324
+ pageContentHeightPx,
27325
+ pageContentWidthPx,
27326
+ paginationSectionMetrics,
27327
+ editor.model.metadata.numberingDefinitions,
27328
+ editor.model.metadata.footnotes ?? [],
27329
+ (pageContentHeightsOverride) => buildPagesWithHeights(pageContentHeightsOverride)
27330
+ );
27331
+ }
27332
+ );
26210
27333
  const buildEstimatedPages = (measuredTableRowHeightsByNodeIndex, measuredPageContentHeightsOverride, paginationOptions) => {
26211
- const allowMeasuredPageContentHeights = !editor.canUndo && !editor.canRedo && !disableMeasuredImportPagination && !floatingMovePreview && !dropCapMovePreview;
26212
- const baseMeasuredHeights = !allowMeasuredPageContentHeights || measuredPageContentHeightsOverride === null ? void 0 : measuredPageContentHeightsOverride ?? measuredPageContentHeightByIndex;
26213
- const buildPagesWithHeights = (resolvedPageContentHeights) => buildDocumentPageNodeSegments(
26214
- editor.model,
26215
- pageContentHeightPx,
26216
- pageContentWidthPx,
26217
- editor.model.metadata.numberingDefinitions,
26218
- paginationSectionMetrics,
26219
- {
26220
- allowParagraphLineSplitting: true,
26221
- suppressSpacingBeforeAfterPageBreak,
26222
- preferLastRenderedParagraphStartBreaks,
26223
- strictLastRenderedParagraphStartBreaks: paginationOptions?.strictLastRenderedParagraphStartBreaks ?? false,
26224
- measuredTableRowHeightsByNodeIndex,
26225
- measuredPageContentHeightsPxByPageIndex: resolvedPageContentHeights,
26226
- measuredParagraphOuterHeightsPxByNodeIndex
26227
- }
26228
- );
26229
- const basePages = buildPagesWithHeights(baseMeasuredHeights);
26230
- return applyEstimatedFootnoteReserveToPages(
26231
- editor.model,
26232
- basePages,
26233
- pageContentHeightPx,
26234
- pageContentWidthPx,
26235
- paginationSectionMetrics,
26236
- editor.model.metadata.numberingDefinitions,
26237
- editor.model.metadata.footnotes ?? [],
26238
- (pageContentHeightsOverride) => buildPagesWithHeights(pageContentHeightsOverride)
27334
+ const allowMeasuredPageContentHeights = !disableMeasuredImportPagination && !floatingMovePreview && !dropCapMovePreview;
27335
+ const baseMeasuredHeights = !allowMeasuredPageContentHeights || measuredPageContentHeightsOverride === null ? void 0 : measuredPageContentHeightsOverride ?? measuredPageContentHeightsPxForPagination;
27336
+ return buildEstimatedPagesForInputs(
27337
+ measuredTableRowHeightsByNodeIndex,
27338
+ baseMeasuredHeights,
27339
+ paginationOptions?.strictLastRenderedParagraphStartBreaks ?? false
26239
27340
  );
26240
27341
  };
26241
27342
  const storedDocumentPageCount2 = editor.model.metadata.documentPageCount;
@@ -26274,7 +27375,7 @@ function DocxEditorViewer({
26274
27375
  tableMeasuredRowHeightsForPagination
26275
27376
  );
26276
27377
  let estimatedPagesUseMeasuredPageContentHeightsForRender = canUseMeasuredPageContentHeights;
26277
- let estimatedRenderMeasuredPageContentHeightsPxByPageIndex = canUseMeasuredPageContentHeights ? measuredPageContentHeightByIndex : void 0;
27378
+ let estimatedRenderMeasuredPageContentHeightsPxByPageIndex = canUseMeasuredPageContentHeights ? measuredPageContentHeightsPxForPagination : void 0;
26278
27379
  let estimatedRenderPageContentHeightScale = void 0;
26279
27380
  const deferExpensiveInitialPaginationReconciliation = deferInitialPaginationPaint && !initialPaginationBackgroundRefinementUnlocked;
26280
27381
  if (deferExpensiveInitialPaginationReconciliation) {
@@ -26285,23 +27386,21 @@ function DocxEditorViewer({
26285
27386
  renderPageContentHeightScale: estimatedRenderPageContentHeightScale
26286
27387
  };
26287
27388
  }
26288
- if (measuredPageContentHeightByIndex && measuredPageContentHeightByIndex.length > 0) {
26289
- const pureEstimatedPages = buildEstimatedPages(
26290
- tableMeasuredRowHeightsForPagination,
26291
- null
26292
- );
26293
- const measuredPagesAreOnlySplitParagraphs = estimatedPages.length > 0 && estimatedPages.every(
26294
- (pageSegments) => documentPageContainsOnlySplitParagraphSegments(pageSegments)
26295
- );
26296
- const purePagesAreOnlySplitParagraphs = pureEstimatedPages.length > 0 && pureEstimatedPages.every(
26297
- (pageSegments) => documentPageContainsOnlySplitParagraphSegments(pageSegments)
26298
- );
26299
- if (measuredPagesAreOnlySplitParagraphs && purePagesAreOnlySplitParagraphs && pureEstimatedPages.length < estimatedPages.length) {
26300
- estimatedPages = pureEstimatedPages;
26301
- estimatedPagesUseMeasuredPageContentHeightsForRender = false;
26302
- estimatedRenderMeasuredPageContentHeightsPxByPageIndex = void 0;
26303
- estimatedRenderPageContentHeightScale = void 0;
27389
+ const splitParagraphComparison = resolveMeasuredSplitParagraphPageComparison(
27390
+ {
27391
+ canUndo: editor.canUndo,
27392
+ canRedo: editor.canRedo,
27393
+ hasMeasuredPageContentHeights: (measuredPageContentHeightsPxForPagination?.length ?? 0) > 0,
27394
+ measuredEstimatedPages: estimatedPages,
27395
+ buildPureEstimatedPages: () => buildEstimatedPages(tableMeasuredRowHeightsForPagination, null),
27396
+ pageContainsOnlySplitParagraphSegments: documentPageContainsOnlySplitParagraphSegments
26304
27397
  }
27398
+ );
27399
+ if (splitParagraphComparison.usedPureEstimatedPages) {
27400
+ estimatedPages = splitParagraphComparison.pages;
27401
+ estimatedPagesUseMeasuredPageContentHeightsForRender = false;
27402
+ estimatedRenderMeasuredPageContentHeightsPxByPageIndex = void 0;
27403
+ estimatedRenderPageContentHeightScale = void 0;
26305
27404
  }
26306
27405
  if (!editor.canUndo && !editor.canRedo && targetPageCount !== void 0 && tableMeasuredRowHeightsForPagination && !hasMultiColumnRenderedPageBreakHints) {
26307
27406
  const candidatePages = [
@@ -26314,7 +27413,7 @@ function DocxEditorViewer({
26314
27413
  {
26315
27414
  pages: buildEstimatedPages(void 0),
26316
27415
  useMeasuredPageContentHeightsForRender: canUseMeasuredPageContentHeights,
26317
- renderMeasuredPageContentHeightsPxByPageIndex: canUseMeasuredPageContentHeights ? measuredPageContentHeightByIndex : void 0,
27416
+ renderMeasuredPageContentHeightsPxByPageIndex: canUseMeasuredPageContentHeights ? measuredPageContentHeightsPxForPagination : void 0,
26318
27417
  renderPageContentHeightScale: void 0
26319
27418
  },
26320
27419
  {
@@ -26345,7 +27444,7 @@ function DocxEditorViewer({
26345
27444
  }
26346
27445
  }
26347
27446
  const measuredPageHeightOverridesReduceContent = !editor.canUndo && !editor.canRedo && !floatingMovePreview && !dropCapMovePreview && estimatedPages.some((segments, pageIndex) => {
26348
- const measuredHeightPx = measuredPageContentHeightByIndex?.[pageIndex];
27447
+ const measuredHeightPx = measuredPageContentHeightsPxForPagination?.[pageIndex];
26349
27448
  if (!Number.isFinite(measuredHeightPx)) {
26350
27449
  return false;
26351
27450
  }
@@ -26455,7 +27554,7 @@ function DocxEditorViewer({
26455
27554
  return {
26456
27555
  pages: hintAlignedPages,
26457
27556
  useMeasuredPageContentHeightsForRender: canUseMeasuredPageContentHeights,
26458
- renderMeasuredPageContentHeightsPxByPageIndex: canUseMeasuredPageContentHeights ? measuredPageContentHeightByIndex : void 0,
27557
+ renderMeasuredPageContentHeightsPxByPageIndex: canUseMeasuredPageContentHeights ? measuredPageContentHeightsPxForPagination : void 0,
26459
27558
  renderPageContentHeightScale: void 0
26460
27559
  };
26461
27560
  }
@@ -26497,22 +27596,23 @@ function DocxEditorViewer({
26497
27596
  preferLastRenderedParagraphStartBreaks,
26498
27597
  measuredTableRowHeightsByNodeIndex,
26499
27598
  measuredPageContentHeightsPxByPageIndex: measuredPageContentHeightsOverride === null ? void 0 : scaleMeasuredPageContentHeights(
26500
- measuredPageContentHeightsOverride ?? measuredPageContentHeightByIndex,
27599
+ measuredPageContentHeightsOverride ?? measuredPageContentHeightsPxForPagination,
26501
27600
  heightScale
26502
27601
  ),
26503
- measuredParagraphOuterHeightsPxByNodeIndex
27602
+ measuredParagraphOuterHeightsPxByNodeIndex,
27603
+ precomputedNumberingLabels: paragraphNumberingLabels
26504
27604
  }
26505
27605
  )
26506
27606
  });
26507
27607
  let reconciledCandidate = reconcileCandidatePages(
26508
27608
  estimatedPages,
26509
27609
  tableMeasuredRowHeightsForPagination,
26510
- estimatedPagesUseMeasuredPageContentHeightsForRender ? measuredPageContentHeightByIndex : null
27610
+ estimatedPagesUseMeasuredPageContentHeightsForRender ? measuredPageContentHeightsPxForPagination : null
26511
27611
  );
26512
27612
  let reconciledPages = reconciledCandidate.pages;
26513
27613
  let reconciledPagesUseMeasuredPageContentHeightsForRender = estimatedPagesUseMeasuredPageContentHeightsForRender;
26514
27614
  let reconciledRenderMeasuredPageContentHeightsPxByPageIndex = reconciledPagesUseMeasuredPageContentHeightsForRender ? scaleMeasuredPageContentHeights(
26515
- measuredPageContentHeightByIndex,
27615
+ measuredPageContentHeightsPxForPagination,
26516
27616
  reconciledCandidate.scale
26517
27617
  ) : void 0;
26518
27618
  let reconciledRenderPageContentHeightScale = void 0;
@@ -26573,7 +27673,10 @@ function DocxEditorViewer({
26573
27673
  hasMeasuredBodyFooterOverlap,
26574
27674
  initialPaginationBackgroundRefinementUnlocked,
26575
27675
  measuredPageContentHeightByIndex,
27676
+ measuredPageContentValidationByIndex,
26576
27677
  measuredParagraphOuterHeightsPxByNodeIndex,
27678
+ paginationMeasurementContextSignature,
27679
+ paragraphNumberingLabels,
26577
27680
  tableMeasuredRowHeightsForPagination
26578
27681
  ]);
26579
27682
  const pageNodeSegmentsByPage = pageSegmentationPlan.pages;
@@ -27006,6 +28109,132 @@ function DocxEditorViewer({
27006
28109
  },
27007
28110
  [explicitPageVirtualizationZoomScale]
27008
28111
  );
28112
+ React.useEffect(() => {
28113
+ if (floatingMovePreview || resizePreview || tableFloatingDragPreview || tableMoveDragRef.current) {
28114
+ return;
28115
+ }
28116
+ const modelChanged = wrapBandReconcileModelRef.current !== editor.model;
28117
+ if (modelChanged) {
28118
+ wrapBandReconcileModelRef.current = editor.model;
28119
+ wrapBandReconcilePassCountRef.current = 0;
28120
+ }
28121
+ if (wrapBandReconcilePassCountRef.current >= WRAP_BAND_RECONCILE_MAX_PASSES) {
28122
+ return;
28123
+ }
28124
+ const fresh = /* @__PURE__ */ new Map();
28125
+ pageBodyElementsRef.current.forEach((bodyElement) => {
28126
+ if (!bodyElement.isConnected) {
28127
+ return;
28128
+ }
28129
+ const origin = bodyElement.getBoundingClientRect();
28130
+ if (origin.width <= 0) {
28131
+ return;
28132
+ }
28133
+ const zoomScale = resolveViewerMeasurementZoomScale(bodyElement, 1);
28134
+ const toBand = (rect) => ({
28135
+ topPx: (rect.top - origin.top) / zoomScale,
28136
+ bottomPx: (rect.bottom - origin.top) / zoomScale,
28137
+ leftPx: (rect.left - origin.left) / zoomScale,
28138
+ rightPx: (rect.right - origin.left) / zoomScale
28139
+ });
28140
+ let pageHasFloatingObject = false;
28141
+ tableElementsRef.current.forEach((element, nodeIndex) => {
28142
+ if (!element.isConnected || !bodyElement.contains(element)) {
28143
+ return;
28144
+ }
28145
+ const node = editor.model.nodes[nodeIndex];
28146
+ if (node?.type !== "table" || !node.style?.floating) {
28147
+ return;
28148
+ }
28149
+ pageHasFloatingObject = true;
28150
+ fresh.set(`tbl:${nodeIndex}`, toBand(element.getBoundingClientRect()));
28151
+ });
28152
+ bodyElement.querySelectorAll("[data-docx-image-location]").forEach((span) => {
28153
+ if (!(span instanceof HTMLElement)) {
28154
+ return;
28155
+ }
28156
+ const location = span.getAttribute("data-docx-image-location") ?? "";
28157
+ const match = /^p:(\d+):(\d+)$/.exec(location);
28158
+ if (!match) {
28159
+ return;
28160
+ }
28161
+ const nodeIndex = Number.parseInt(match[1] ?? "", 10);
28162
+ const childIndex = Number.parseInt(match[2] ?? "", 10);
28163
+ const node = editor.model.nodes[nodeIndex];
28164
+ const child = node?.type === "paragraph" ? node.children[childIndex] : void 0;
28165
+ if (!child || child.type !== "image" || !child.floating?.wrapType || child.floating.wrapType === "none" || child.floating.behindDocument === true || shouldRenderWrappedFloatingImage(child)) {
28166
+ return;
28167
+ }
28168
+ if (getComputedStyle(span).position !== "absolute") {
28169
+ return;
28170
+ }
28171
+ pageHasFloatingObject = true;
28172
+ fresh.set(`img:${location}`, toBand(span.getBoundingClientRect()));
28173
+ });
28174
+ if (!pageHasFloatingObject) {
28175
+ let hasInFlowWrappedFloat = false;
28176
+ paragraphElementsRef.current.forEach((element, nodeIndex) => {
28177
+ if (hasInFlowWrappedFloat || !element.isConnected || !bodyElement.contains(element)) {
28178
+ return;
28179
+ }
28180
+ const candidate = editor.model.nodes[nodeIndex];
28181
+ if (candidate?.type === "paragraph" && candidate.children.some(
28182
+ (child) => child.type === "image" && shouldRenderWrappedFloatingImage(child)
28183
+ )) {
28184
+ hasInFlowWrappedFloat = true;
28185
+ }
28186
+ });
28187
+ if (!hasInFlowWrappedFloat) {
28188
+ return;
28189
+ }
28190
+ }
28191
+ paragraphElementsRef.current.forEach((element, nodeIndex) => {
28192
+ if (!element.isConnected || !bodyElement.contains(element)) {
28193
+ return;
28194
+ }
28195
+ const rect = element.getBoundingClientRect();
28196
+ if (rect.height <= 0) {
28197
+ return;
28198
+ }
28199
+ fresh.set(`para:${nodeIndex}`, toBand(rect));
28200
+ });
28201
+ });
28202
+ const withinTolerance = (previous, candidate) => Math.abs(previous.topPx - candidate.topPx) <= WRAP_BAND_RECONCILE_TOLERANCE_PX && Math.abs(previous.bottomPx - candidate.bottomPx) <= WRAP_BAND_RECONCILE_TOLERANCE_PX && Math.abs(previous.leftPx - candidate.leftPx) <= WRAP_BAND_RECONCILE_TOLERANCE_PX && Math.abs(previous.rightPx - candidate.rightPx) <= WRAP_BAND_RECONCILE_TOLERANCE_PX;
28203
+ const next = /* @__PURE__ */ new Map();
28204
+ if (!modelChanged) {
28205
+ measuredWrapBands.forEach((band, key) => {
28206
+ next.set(key, band);
28207
+ });
28208
+ }
28209
+ let modifiedExistingBand = false;
28210
+ fresh.forEach((band, key) => {
28211
+ const previous = measuredWrapBands.get(key);
28212
+ if (previous && withinTolerance(previous, band)) {
28213
+ next.set(key, previous);
28214
+ return;
28215
+ }
28216
+ if (previous && !modelChanged) {
28217
+ modifiedExistingBand = true;
28218
+ }
28219
+ next.set(key, band);
28220
+ });
28221
+ let changed = next.size !== measuredWrapBands.size;
28222
+ if (!changed) {
28223
+ for (const [key, band] of next) {
28224
+ if (measuredWrapBands.get(key) !== band) {
28225
+ changed = true;
28226
+ break;
28227
+ }
28228
+ }
28229
+ }
28230
+ if (!changed) {
28231
+ return;
28232
+ }
28233
+ if (modifiedExistingBand) {
28234
+ wrapBandReconcilePassCountRef.current += 1;
28235
+ }
28236
+ setMeasuredWrapBands(next);
28237
+ });
27009
28238
  React.useEffect(() => {
27010
28239
  setDeferInternalPageVirtualization(!hasLargeTableLayoutSurface);
27011
28240
  }, [editor.documentLoadNonce, hasLargeTableLayoutSurface]);
@@ -27485,12 +28714,16 @@ function DocxEditorViewer({
27485
28714
  if (Date.now() < paginationMeasurementSuspendUntilRef.current) {
27486
28715
  return;
27487
28716
  }
27488
- setMeasuredParagraphOuterHeightsPxByNodeIndex((current) => {
28717
+ setMeasuredParagraphOuterHeightsPxByBlockId((current) => {
27489
28718
  const next = new Map(current);
27490
28719
  let changed = false;
27491
28720
  const rootElement = viewerRootRef.current;
27492
28721
  const zoomScale = resolveViewerMeasurementZoomScale(rootElement, 1);
27493
28722
  paragraphElementsRef.current.forEach((element, nodeIndex) => {
28723
+ const node = editor.model.nodes[nodeIndex];
28724
+ if (node?.type !== "paragraph" || !node.blockId) {
28725
+ return;
28726
+ }
27494
28727
  if (!element.isConnected || element.dataset.docxParagraphPartialLineRange === "true" || element.closest('[data-docx-header-footer-region="footer"]') || element.closest('[data-docx-header-footer-region="header"]')) {
27495
28728
  return;
27496
28729
  }
@@ -27507,9 +28740,9 @@ function DocxEditorViewer({
27507
28740
  rect.height / zoomScale + (Number.isFinite(marginTop) ? marginTop : 0) + (Number.isFinite(marginBottom) ? marginBottom : 0)
27508
28741
  )
27509
28742
  );
27510
- const previousHeightPx = next.get(nodeIndex);
28743
+ const previousHeightPx = next.get(node.blockId);
27511
28744
  if (previousHeightPx === void 0 || Math.abs(previousHeightPx - outerHeightPx) > 1) {
27512
- next.set(nodeIndex, outerHeightPx);
28745
+ next.set(node.blockId, outerHeightPx);
27513
28746
  changed = true;
27514
28747
  }
27515
28748
  });
@@ -27517,7 +28750,9 @@ function DocxEditorViewer({
27517
28750
  });
27518
28751
  }, [
27519
28752
  editor.documentLoadNonce,
28753
+ editor.model.nodes,
27520
28754
  pageNodeSegmentIdentityKeysByPage,
28755
+ paginationMeasurementEpoch,
27521
28756
  resolveViewerMeasurementZoomScale,
27522
28757
  visiblePageEndIndex,
27523
28758
  visiblePageStartIndex
@@ -27580,7 +28815,7 @@ function DocxEditorViewer({
27580
28815
  if (segment.tableRowSlice) {
27581
28816
  continue;
27582
28817
  }
27583
- const measuredHeights = tableMeasuredRowHeights[segment.nodeIndex];
28818
+ const measuredHeights = tableNode.blockId ? tableMeasuredRowHeights[tableNode.blockId]?.rowHeightsPx : void 0;
27584
28819
  if (!measuredHeights || measuredHeights.length !== tableNode.rows.length) {
27585
28820
  return true;
27586
28821
  }
@@ -28144,6 +29379,9 @@ function DocxEditorViewer({
28144
29379
  setMeasuredPageContentIdentityKeysByIndex(
28145
29380
  (current) => current.length === 0 ? current : []
28146
29381
  );
29382
+ setMeasuredPageContentValidationByIndex(
29383
+ (current) => current.length === 0 ? current : []
29384
+ );
28147
29385
  return;
28148
29386
  }
28149
29387
  if (!paginationMeasurementEnabled) {
@@ -28157,6 +29395,9 @@ function DocxEditorViewer({
28157
29395
  setMeasuredPageContentIdentityKeysByIndex(
28158
29396
  (current) => current.length === 0 ? current : []
28159
29397
  );
29398
+ setMeasuredPageContentValidationByIndex(
29399
+ (current) => current.length === 0 ? current : []
29400
+ );
28160
29401
  return;
28161
29402
  }
28162
29403
  if (Date.now() < paginationMeasurementSuspendUntilRef.current) {
@@ -28290,6 +29531,19 @@ function DocxEditorViewer({
28290
29531
  const nextMeasuredHeights = nextMeasuredPageDiagnostics.map(
28291
29532
  (diagnostics) => diagnostics.heightPx
28292
29533
  );
29534
+ const nextMeasuredPageValidation = pageNodeSegmentsByPage.map(
29535
+ (pageSegments, pageIndex) => {
29536
+ const pageIsVisible = pageIndex >= visiblePageStartIndex && pageIndex <= visiblePageEndIndex;
29537
+ if (!pageIsVisible || !pageElementsRef.current.get(pageIndex)) {
29538
+ return void 0;
29539
+ }
29540
+ return buildMeasuredPageContentValidationForPageSegments(
29541
+ pageSegments,
29542
+ editor.model.nodes,
29543
+ paginationMeasurementContextSignature
29544
+ );
29545
+ }
29546
+ );
28293
29547
  const overlappingPageIndexes = nextMeasuredPageDiagnostics.reduce(
28294
29548
  (indexes, diagnostics, pageIndex) => {
28295
29549
  if (diagnostics.bodyOverrunsFooter) {
@@ -28360,6 +29614,27 @@ function DocxEditorViewer({
28360
29614
  }
28361
29615
  return nextMeasuredPageIdentityKeys;
28362
29616
  });
29617
+ setMeasuredPageContentValidationByIndex((current) => {
29618
+ const merged = nextMeasuredPageValidation.map(
29619
+ (validation, pageIndex) => validation ?? current[pageIndex]
29620
+ );
29621
+ if (current.length === merged.length) {
29622
+ let equal = true;
29623
+ for (let pageIndex = 0; pageIndex < merged.length; pageIndex += 1) {
29624
+ if (!measuredPageContentValidationsEqual(
29625
+ current[pageIndex],
29626
+ merged[pageIndex]
29627
+ )) {
29628
+ equal = false;
29629
+ break;
29630
+ }
29631
+ }
29632
+ if (equal) {
29633
+ return current;
29634
+ }
29635
+ }
29636
+ return merged;
29637
+ });
28363
29638
  });
28364
29639
  return () => {
28365
29640
  window.cancelAnimationFrame(frameId);
@@ -28367,8 +29642,10 @@ function DocxEditorViewer({
28367
29642
  }, [
28368
29643
  disableMeasuredImportPagination,
28369
29644
  documentLayout,
29645
+ editor.model.nodes,
28370
29646
  measuredPageContentHeightByIndex,
28371
29647
  measuredPageContentIdentityKeysByIndex,
29648
+ paginationMeasurementContextSignature,
28372
29649
  paginationMeasurementEnabled,
28373
29650
  paginationMeasurementEpoch,
28374
29651
  pageCount,
@@ -28401,6 +29678,7 @@ function DocxEditorViewer({
28401
29678
  initialPaginationStableSignatureRef.current = void 0;
28402
29679
  setDisableMeasuredImportPagination(true);
28403
29680
  setMeasuredPageContentHeightByIndex([]);
29681
+ setMeasuredPageContentValidationByIndex([]);
28404
29682
  setTableMeasuredRowHeights({});
28405
29683
  }, [
28406
29684
  deferInitialPaginationPaint,
@@ -28484,7 +29762,8 @@ function DocxEditorViewer({
28484
29762
  (pageIndex) => (pageNodeSegmentsByPage[pageIndex] ?? []).filter(
28485
29763
  (segment) => editor.model.nodes[segment.nodeIndex]?.type === "table"
28486
29764
  ).map((segment) => {
28487
- const measuredHeights = tableMeasuredRowHeights[segment.nodeIndex] ?? [];
29765
+ const tableNode = editor.model.nodes[segment.nodeIndex];
29766
+ const measuredHeights = (tableNode?.blockId ? tableMeasuredRowHeights[tableNode.blockId]?.rowHeightsPx : void 0) ?? [];
28488
29767
  return `${segment.nodeIndex}:${measuredHeights.join(",")}`;
28489
29768
  }).join(";")
28490
29769
  ).join("|");
@@ -28739,22 +30018,29 @@ function DocxEditorViewer({
28739
30018
  startY: event.clientY,
28740
30019
  hasMoved: false
28741
30020
  };
30021
+ const zoomScale = resolveViewerMeasurementZoomScale(
30022
+ viewerRootRef.current,
30023
+ 1
30024
+ );
30025
+ const tableElementAtStart = tableElementsRef.current.get(tableIndex);
30026
+ const tableRectAtStart = tableElementAtStart?.getBoundingClientRect();
30027
+ const floatingHostRectAtStart = tableElementAtStart?.closest("[data-docx-floating-table-host]")?.getBoundingClientRect();
28742
30028
  const onPointerMove = (pointerMoveEvent) => {
28743
30029
  const dragState = tableMoveDragRef.current;
28744
30030
  if (!dragState || pointerMoveEvent.pointerId !== dragState.pointerId) {
28745
30031
  return;
28746
30032
  }
28747
- const deltaX = Math.abs(pointerMoveEvent.clientX - dragState.startX);
28748
- const deltaY = Math.abs(pointerMoveEvent.clientY - dragState.startY);
28749
- if (deltaX + deltaY < TABLE_MOVE_DRAG_THRESHOLD_PX) {
30033
+ const movedX = pointerMoveEvent.clientX - dragState.startX;
30034
+ const movedY = pointerMoveEvent.clientY - dragState.startY;
30035
+ if (!dragState.hasMoved && Math.abs(movedX) + Math.abs(movedY) < TABLE_MOVE_DRAG_THRESHOLD_PX) {
28750
30036
  return;
28751
30037
  }
28752
30038
  dragState.hasMoved = true;
28753
- const target = resolveTableMoveDropTarget(dragState.tableIndex, {
28754
- x: pointerMoveEvent.clientX,
28755
- y: pointerMoveEvent.clientY
30039
+ setTableFloatingDragPreview({
30040
+ tableIndex: dragState.tableIndex,
30041
+ deltaX: normalizeFloatingDragDeltaForZoom(movedX, zoomScale),
30042
+ deltaY: normalizeFloatingDragDeltaForZoom(movedY, zoomScale)
28756
30043
  });
28757
- setTableMoveDropPreview(target?.preview);
28758
30044
  pointerMoveEvent.preventDefault();
28759
30045
  };
28760
30046
  const onPointerUp = (pointerUpEvent) => {
@@ -28777,18 +30063,57 @@ function DocxEditorViewer({
28777
30063
  setHoveredTableHandleTableIndex(
28778
30064
  pointerStillOverTable ? dragState.tableIndex : void 0
28779
30065
  );
28780
- const target = resolveTableMoveDropTarget(dragState.tableIndex, {
28781
- x: pointerUpEvent.clientX,
28782
- y: pointerUpEvent.clientY
28783
- });
28784
- setTableMoveDropPreview(void 0);
28785
- if (!dragState.hasMoved) {
30066
+ setTableFloatingDragPreview(void 0);
30067
+ if (!dragState.hasMoved || !tableRectAtStart) {
28786
30068
  return;
28787
30069
  }
28788
- if (!target) {
30070
+ const deltaX = normalizeFloatingDragDeltaForZoom(
30071
+ pointerUpEvent.clientX - dragState.startX,
30072
+ zoomScale
30073
+ );
30074
+ const deltaY = normalizeFloatingDragDeltaForZoom(
30075
+ pointerUpEvent.clientY - dragState.startY,
30076
+ zoomScale
30077
+ );
30078
+ const tableNode = editor.model.nodes[dragState.tableIndex];
30079
+ if (!tableNode || tableNode.type !== "table") {
28789
30080
  return;
28790
30081
  }
28791
- editor.moveTable(dragState.tableIndex, target.targetNodeIndex);
30082
+ const currentFloating = tableNode.style?.floating;
30083
+ const baseLeftPx = floatingHostRectAtStart ? (tableRectAtStart.left - floatingHostRectAtStart.left) / zoomScale : twipsToSignedPixels(tableNode.style?.indentTwips) ?? 0;
30084
+ const baseTopPx = floatingHostRectAtStart ? (tableRectAtStart.top - floatingHostRectAtStart.top) / zoomScale : 0;
30085
+ const dropTarget = resolveTableMoveDropTarget(dragState.tableIndex, {
30086
+ x: pointerUpEvent.clientX,
30087
+ y: pointerUpEvent.clientY
30088
+ });
30089
+ const rootRect = viewerRootRef.current?.getBoundingClientRect();
30090
+ const shouldReanchor = dropTarget !== void 0 && rootRect !== void 0 && dropTarget.targetNodeIndex !== dragState.tableIndex && dropTarget.targetNodeIndex !== dragState.tableIndex + 1;
30091
+ let committedTopPx = baseTopPx + deltaY;
30092
+ if (shouldReanchor && dropTarget && rootRect) {
30093
+ let targetScreenTop = rootRect.top + dropTarget.preview.top;
30094
+ if (!floatingHostRectAtStart && dropTarget.targetNodeIndex > dragState.tableIndex) {
30095
+ targetScreenTop -= tableRectAtStart.height;
30096
+ }
30097
+ const droppedTopScreenPx = tableRectAtStart.top + (pointerUpEvent.clientY - dragState.startY);
30098
+ committedTopPx = (droppedTopScreenPx - targetScreenTop) / zoomScale;
30099
+ }
30100
+ committedTopPx = Math.max(0, committedTopPx);
30101
+ editor.setTableFloating(
30102
+ dragState.tableIndex,
30103
+ {
30104
+ xTwips: pixelsToTwips(baseLeftPx + deltaX),
30105
+ yTwips: pixelsToTwips(committedTopPx),
30106
+ horizontalAnchor: "margin",
30107
+ verticalAnchor: "text",
30108
+ horizontalAlign: void 0,
30109
+ verticalAlign: void 0,
30110
+ leftFromTextTwips: currentFloating?.leftFromTextTwips ?? 187,
30111
+ rightFromTextTwips: currentFloating?.rightFromTextTwips ?? 187,
30112
+ topFromTextTwips: currentFloating?.topFromTextTwips ?? 0,
30113
+ bottomFromTextTwips: currentFloating?.bottomFromTextTwips ?? 0
30114
+ },
30115
+ shouldReanchor && dropTarget ? { moveToNodeIndex: dropTarget.targetNodeIndex } : void 0
30116
+ );
28792
30117
  };
28793
30118
  window.addEventListener("pointermove", onPointerMove);
28794
30119
  window.addEventListener("pointerup", onPointerUp, { once: true });
@@ -29937,7 +31262,7 @@ function DocxEditorViewer({
29937
31262
  editorHasFocus && (!liveSelection || liveSelection.rangeCount === 0)
29938
31263
  );
29939
31264
  if (collapsedElementAnchor || selectionDropped) {
29940
- if (session === "keyboard" || session === "composition") {
31265
+ if (session === "keyboard" || session === "composition" || compositionActiveRef.current) {
29941
31266
  return;
29942
31267
  }
29943
31268
  const anchorElement = anchorNode instanceof Element ? anchorNode : anchorNode?.parentElement ?? null;
@@ -29996,7 +31321,7 @@ function DocxEditorViewer({
29996
31321
  return;
29997
31322
  }
29998
31323
  const session = editor.selectionSessionKind;
29999
- if (pointerSelectionDragRef.current.moved || session === "composition") {
31324
+ if (pointerSelectionDragRef.current.moved || session === "composition" || compositionActiveRef.current) {
30000
31325
  return;
30001
31326
  }
30002
31327
  const rootElement = viewerRootRef.current;
@@ -30375,7 +31700,7 @@ function DocxEditorViewer({
30375
31700
  appliedHistoryRestoreNonceRef.current = restoreRequest.nonce;
30376
31701
  const selectionIntentNonce = beginSelectionIntent();
30377
31702
  editor.beginSelectionSession("history-restore", { settleAfterMs: 180 });
30378
- paragraphDraftsRef.current.clear();
31703
+ editingIntentContinuationRef.current = void 0;
30379
31704
  tableCellDraftsRef.current.clear();
30380
31705
  tableCellParagraphDraftsRef.current.clear();
30381
31706
  sectionParagraphDraftsRef.current.clear();
@@ -31051,7 +32376,7 @@ function DocxEditorViewer({
31051
32376
  normalizedActiveRange
31052
32377
  );
31053
32378
  if (collapsedRange) {
31054
- paragraphDraftsRef.current.clear();
32379
+ editingIntentContinuationRef.current = void 0;
31055
32380
  tableCellDraftsRef.current.clear();
31056
32381
  tableCellParagraphDraftsRef.current.clear();
31057
32382
  syncSelectionFromDocxRange(collapsedRange);
@@ -31152,7 +32477,7 @@ function DocxEditorViewer({
31152
32477
  normalizedActiveRange
31153
32478
  );
31154
32479
  if (collapsedRange) {
31155
- paragraphDraftsRef.current.clear();
32480
+ editingIntentContinuationRef.current = void 0;
31156
32481
  tableCellDraftsRef.current.clear();
31157
32482
  tableCellParagraphDraftsRef.current.clear();
31158
32483
  syncSelectionFromDocxRange(collapsedRange);
@@ -31210,7 +32535,7 @@ function DocxEditorViewer({
31210
32535
  if (!collapsedRange) {
31211
32536
  return false;
31212
32537
  }
31213
- paragraphDraftsRef.current.clear();
32538
+ editingIntentContinuationRef.current = void 0;
31214
32539
  tableCellDraftsRef.current.clear();
31215
32540
  tableCellParagraphDraftsRef.current.clear();
31216
32541
  syncSelectionFromDocxRange(collapsedRange);
@@ -31365,7 +32690,7 @@ function DocxEditorViewer({
31365
32690
  return true;
31366
32691
  };
31367
32692
  const clearDraftsAndSetSelection = (range) => {
31368
- paragraphDraftsRef.current.clear();
32693
+ editingIntentContinuationRef.current = void 0;
31369
32694
  tableCellDraftsRef.current.clear();
31370
32695
  tableCellParagraphDraftsRef.current.clear();
31371
32696
  syncSelectionFromDocxRange(range);
@@ -31858,7 +33183,7 @@ function DocxEditorViewer({
31858
33183
  if (!collapsedRange) {
31859
33184
  return;
31860
33185
  }
31861
- paragraphDraftsRef.current.clear();
33186
+ editingIntentContinuationRef.current = void 0;
31862
33187
  tableCellDraftsRef.current.clear();
31863
33188
  tableCellParagraphDraftsRef.current.clear();
31864
33189
  syncSelectionFromDocxRange(collapsedRange);
@@ -32299,20 +33624,6 @@ function DocxEditorViewer({
32299
33624
  },
32300
33625
  [clearTableCellSelection, editor, selectionOffsetsWithinElement]
32301
33626
  );
32302
- const commitParagraphDraftFromElement = React.useCallback(
32303
- (nodeIndex, paragraph, element) => {
32304
- const nextText = editableTextFromElement(element);
32305
- const nextHtml = element.innerHTML;
32306
- if (nextText === paragraphText(paragraph)) {
32307
- paragraphDraftsRef.current.delete(nodeIndex);
32308
- return;
32309
- }
32310
- paragraphDraftsRef.current.set(nodeIndex, nextHtml);
32311
- editor.suppressNextDomSelectionRestore();
32312
- editor.commitParagraphText(nodeIndex, nextText);
32313
- },
32314
- [editor]
32315
- );
32316
33627
  const commitTableCellDraftFromElement = React.useCallback(
32317
33628
  (tableIndex, rowIndex, cellIndex, cellParagraphs, draftKey, element) => {
32318
33629
  const nextText = editableTextFromTableCellElement(element);
@@ -32529,33 +33840,14 @@ function DocxEditorViewer({
32529
33840
  }
32530
33841
  React.useEffect(() => {
32531
33842
  const flushPendingDraftsForExport = (currentModel) => {
32532
- if (paragraphDraftsRef.current.size === 0 && tableCellDraftsRef.current.size === 0 && tableCellParagraphDraftsRef.current.size === 0 && sectionParagraphDraftsRef.current.size === 0) {
33843
+ if (tableCellDraftsRef.current.size === 0 && tableCellParagraphDraftsRef.current.size === 0 && sectionParagraphDraftsRef.current.size === 0) {
32533
33844
  return currentModel;
32534
33845
  }
32535
33846
  let nextModel = currentModel;
32536
33847
  const insertedStyle = cloneTextStyle2(editor.pendingRunStyle);
32537
- const consumedParagraphDraftIndexes = [];
32538
33848
  const consumedTableDraftKeys = [];
32539
33849
  const consumedTableParagraphDraftKeys = [];
32540
33850
  const consumedSectionDraftKeys = [];
32541
- paragraphDraftsRef.current.forEach((draftHtml, nodeIndex) => {
32542
- const element = paragraphElementsRef.current.get(nodeIndex);
32543
- if (!element && typeof draftHtml !== "string") {
32544
- return;
32545
- }
32546
- consumedParagraphDraftIndexes.push(nodeIndex);
32547
- const paragraph = nextModel.nodes[nodeIndex];
32548
- if (!paragraph || paragraph.type !== "paragraph") {
32549
- return;
32550
- }
32551
- const nextText = element ? editableTextFromElement(element) : editableTextFromDraftHtml(draftHtml);
32552
- if (nextText === paragraphText(paragraph)) {
32553
- return;
32554
- }
32555
- nextModel = updateParagraphText(nextModel, nodeIndex, nextText, {
32556
- insertedStyle
32557
- });
32558
- });
32559
33851
  tableCellParagraphDraftsRef.current.forEach((draftHtml, draftKey) => {
32560
33852
  const element = tableCellParagraphElementsRef.current.get(draftKey);
32561
33853
  if (!element && typeof draftHtml !== "string") {
@@ -32652,9 +33944,6 @@ function DocxEditorViewer({
32652
33944
  }
32653
33945
  );
32654
33946
  });
32655
- consumedParagraphDraftIndexes.forEach((nodeIndex) => {
32656
- paragraphDraftsRef.current.delete(nodeIndex);
32657
- });
32658
33947
  consumedTableDraftKeys.forEach((draftKey) => {
32659
33948
  tableCellDraftsRef.current.delete(draftKey);
32660
33949
  });
@@ -32696,6 +33985,430 @@ function DocxEditorViewer({
32696
33985
  },
32697
33986
  [editor]
32698
33987
  );
33988
+ const handleEditableHostBeforeInput = React.useCallback(
33989
+ (event) => {
33990
+ if (isReadOnly) {
33991
+ return;
33992
+ }
33993
+ if (event.isComposing || compositionActiveRef.current) {
33994
+ return;
33995
+ }
33996
+ const targetElement = event.target instanceof Element ? event.target : event.target instanceof Node ? event.target.parentElement : null;
33997
+ if (!targetElement) {
33998
+ return;
33999
+ }
34000
+ if (targetElement.closest("textarea, input") || targetElement.closest("[data-docx-header-footer-region]")) {
34001
+ return;
34002
+ }
34003
+ const intent = resolveEditingIntent({
34004
+ inputType: event.inputType,
34005
+ data: event.data,
34006
+ dataTransferText: event.dataTransfer?.getData("text/plain")
34007
+ });
34008
+ if (!intent) {
34009
+ return;
34010
+ }
34011
+ const resolveTargetRangeOffsets = (element) => {
34012
+ const targetRange = typeof event.getTargetRanges === "function" ? event.getTargetRanges()[0] : void 0;
34013
+ return targetRange ? staticRangeOffsetsWithinElementDom(element, targetRange) : void 0;
34014
+ };
34015
+ const paragraphHost = targetElement.closest(
34016
+ "[data-docx-paragraph-host='true'][data-docx-paragraph-kind='paragraph']"
34017
+ );
34018
+ if (paragraphHost) {
34019
+ if (!paragraphHost.isContentEditable) {
34020
+ return;
34021
+ }
34022
+ const nodeIndexAttr = paragraphHost.getAttribute(
34023
+ "data-docx-paragraph-node-index"
34024
+ );
34025
+ const nodeIndex = nodeIndexAttr != null ? Number.parseInt(nodeIndexAttr, 10) : Number.NaN;
34026
+ const node = Number.isFinite(nodeIndex) ? editor.model.nodes[nodeIndex] : void 0;
34027
+ if (!node || node.type !== "paragraph") {
34028
+ return;
34029
+ }
34030
+ event.preventDefault();
34031
+ cancelPendingPointerSelectionReconcile();
34032
+ if (intent.kind === "blocked") {
34033
+ return;
34034
+ }
34035
+ if (intent.kind === "historyUndo") {
34036
+ editor.undo();
34037
+ return;
34038
+ }
34039
+ if (intent.kind === "historyRedo") {
34040
+ editor.redo();
34041
+ return;
34042
+ }
34043
+ const location = { kind: "paragraph", nodeIndex };
34044
+ const continuationKey = `p:${nodeIndex}`;
34045
+ const domText = editableTextFromElement(paragraphHost);
34046
+ const continuation2 = editingIntentContinuationRef.current;
34047
+ const continuationActive2 = Boolean(
34048
+ continuation2 && continuation2.key === continuationKey && continuation2.text !== domText
34049
+ );
34050
+ const currentText2 = continuationActive2 && continuation2 ? continuation2.text : domText;
34051
+ let selectionOffsets2 = continuationActive2 && continuation2 ? { start: continuation2.caret, end: continuation2.caret } : selectionOffsetsWithinElement(paragraphHost);
34052
+ if (!selectionOffsets2) {
34053
+ const activeRange = editor.activeTextRange ? normalizeTextRange(editor.activeTextRange) : void 0;
34054
+ if (activeRange && sameParagraphLocation(activeRange.start.location, location) && sameParagraphLocation(activeRange.end.location, location)) {
34055
+ const safeStart = Math.max(
34056
+ 0,
34057
+ Math.min(
34058
+ Math.round(activeRange.start.offset),
34059
+ currentText2.length
34060
+ )
34061
+ );
34062
+ selectionOffsets2 = {
34063
+ start: safeStart,
34064
+ end: Math.max(
34065
+ safeStart,
34066
+ Math.min(
34067
+ Math.round(activeRange.end.offset),
34068
+ currentText2.length
34069
+ )
34070
+ )
34071
+ };
34072
+ }
34073
+ }
34074
+ if (!selectionOffsets2) {
34075
+ selectionOffsets2 = {
34076
+ start: currentText2.length,
34077
+ end: currentText2.length
34078
+ };
34079
+ }
34080
+ if (intent.kind === "insertParagraph") {
34081
+ editingIntentContinuationRef.current = void 0;
34082
+ const start = Math.max(
34083
+ 0,
34084
+ Math.min(selectionOffsets2.start, currentText2.length)
34085
+ );
34086
+ const end = Math.max(
34087
+ start,
34088
+ Math.min(selectionOffsets2.end, currentText2.length)
34089
+ );
34090
+ tableCellDraftsRef.current.clear();
34091
+ tableCellParagraphDraftsRef.current.clear();
34092
+ if (paragraphIsList(node, currentText2)) {
34093
+ const insertedListItem = editor.insertListItemAfterSelection(
34094
+ currentText2,
34095
+ start,
34096
+ end,
34097
+ location
34098
+ );
34099
+ if (insertedListItem !== void 0) {
34100
+ focusParagraphAtOffset(
34101
+ insertedListItem.paragraphIndex,
34102
+ insertedListItem.caretOffset
34103
+ );
34104
+ }
34105
+ return;
34106
+ }
34107
+ const splitParagraph = editor.splitParagraphAtSelection(
34108
+ currentText2,
34109
+ start,
34110
+ end,
34111
+ location
34112
+ );
34113
+ if (splitParagraph !== void 0) {
34114
+ focusParagraphAtOffset(
34115
+ splitParagraph.paragraphIndex,
34116
+ splitParagraph.caretOffset
34117
+ );
34118
+ }
34119
+ return;
34120
+ }
34121
+ if (intent.kind === "deleteContent" || intent.kind === "deleteRange") {
34122
+ const activeRange = editor.activeTextRange ? normalizeTextRange(editor.activeTextRange) : void 0;
34123
+ const expandedBeyondParagraph = Boolean(
34124
+ activeRange && compareTextRangeBoundaries(activeRange.start, activeRange.end) < 0 && !(sameParagraphLocation(activeRange.start.location, location) && sameParagraphLocation(activeRange.end.location, location))
34125
+ );
34126
+ if (expandedBeyondParagraph && activeRange) {
34127
+ editingIntentContinuationRef.current = void 0;
34128
+ const collapsedRange = editor.deleteExpandedSelection(activeRange);
34129
+ if (collapsedRange) {
34130
+ tableCellDraftsRef.current.clear();
34131
+ tableCellParagraphDraftsRef.current.clear();
34132
+ syncSelectionFromDocxRange(collapsedRange);
34133
+ }
34134
+ return;
34135
+ }
34136
+ }
34137
+ const rangeOffsets2 = !continuationActive2 && (intent.kind === "insertText" || intent.kind === "replaceText" || intent.kind === "insertLineBreak" || intent.kind === "deleteContent" || intent.kind === "deleteRange") ? resolveTargetRangeOffsets(paragraphHost) ?? selectionOffsets2 : selectionOffsets2;
34138
+ const applied2 = applyTextEditingIntent(
34139
+ currentText2,
34140
+ rangeOffsets2.start,
34141
+ rangeOffsets2.end,
34142
+ intent
34143
+ );
34144
+ if (!applied2) {
34145
+ if (intent.kind === "deleteContent" && rangeOffsets2.start === rangeOffsets2.end) {
34146
+ if (intent.direction === "backward" && rangeOffsets2.start === 0) {
34147
+ editingIntentContinuationRef.current = void 0;
34148
+ let previousLocation;
34149
+ for (let scanNodeIndex = nodeIndex - 1; scanNodeIndex >= 0; scanNodeIndex -= 1) {
34150
+ const candidate = lastParagraphLocationInNode(
34151
+ editor.model,
34152
+ scanNodeIndex
34153
+ );
34154
+ if (candidate) {
34155
+ previousLocation = candidate;
34156
+ break;
34157
+ }
34158
+ }
34159
+ const previousParagraph = previousLocation ? getParagraphAtLocation(editor.model, previousLocation).paragraph : void 0;
34160
+ if (previousLocation && previousParagraph) {
34161
+ const collapsedRange = editor.deleteExpandedSelection({
34162
+ start: {
34163
+ location: cloneTextRangeLocation(previousLocation),
34164
+ offset: paragraphText(previousParagraph).length
34165
+ },
34166
+ end: {
34167
+ location: cloneTextRangeLocation(location),
34168
+ offset: 0
34169
+ }
34170
+ });
34171
+ if (collapsedRange) {
34172
+ syncSelectionFromDocxRange(collapsedRange);
34173
+ }
34174
+ }
34175
+ return;
34176
+ }
34177
+ if (intent.direction === "forward" && rangeOffsets2.start >= currentText2.length) {
34178
+ editingIntentContinuationRef.current = void 0;
34179
+ const nextLocation = nextParagraphLocation(
34180
+ editor.model,
34181
+ location
34182
+ );
34183
+ const nextParagraph = nextLocation ? getParagraphAtLocation(editor.model, nextLocation).paragraph : void 0;
34184
+ if (nextLocation && nextParagraph) {
34185
+ const collapsedRange = editor.deleteExpandedSelection({
34186
+ start: {
34187
+ location: cloneTextRangeLocation(location),
34188
+ offset: currentText2.length
34189
+ },
34190
+ end: {
34191
+ location: cloneTextRangeLocation(nextLocation),
34192
+ offset: 0
34193
+ }
34194
+ });
34195
+ if (collapsedRange) {
34196
+ syncSelectionFromDocxRange(collapsedRange);
34197
+ }
34198
+ }
34199
+ return;
34200
+ }
34201
+ }
34202
+ return;
34203
+ }
34204
+ const coalesceClass2 = editingIntentCoalesceClass(intent);
34205
+ editor.commitParagraphTextAtRange(
34206
+ location,
34207
+ applied2.text,
34208
+ { start: applied2.caret, end: applied2.caret },
34209
+ {
34210
+ insertionOffset: rangeOffsets2.start,
34211
+ ...coalesceClass2 ? { coalesceKey: `p:${nodeIndex}:${coalesceClass2}` } : void 0
34212
+ }
34213
+ );
34214
+ editingIntentContinuationRef.current = {
34215
+ key: continuationKey,
34216
+ text: applied2.text,
34217
+ caret: applied2.caret
34218
+ };
34219
+ pendingEditableCaretRef.current = {
34220
+ nodeIndex,
34221
+ start: applied2.caret,
34222
+ end: applied2.caret
34223
+ };
34224
+ schedulePaginationMeasurementResume();
34225
+ return;
34226
+ }
34227
+ const cellHost = targetElement.closest(
34228
+ "[data-docx-cell-key]"
34229
+ );
34230
+ if (!cellHost || !cellHost.isContentEditable) {
34231
+ return;
34232
+ }
34233
+ const cellKeyMatch = /^cell-(\d+)-(\d+)-(\d+)$/.exec(
34234
+ cellHost.getAttribute("data-docx-cell-key") ?? ""
34235
+ );
34236
+ if (!cellKeyMatch) {
34237
+ return;
34238
+ }
34239
+ const tableIndex = Number.parseInt(cellKeyMatch[1], 10);
34240
+ const rowIndex = Number.parseInt(cellKeyMatch[2], 10);
34241
+ const cellIndex = Number.parseInt(cellKeyMatch[3], 10);
34242
+ const tableNode = editor.model.nodes[tableIndex];
34243
+ if (!tableNode || tableNode.type !== "table") {
34244
+ return;
34245
+ }
34246
+ const cell = tableNode.rows[rowIndex]?.cells[cellIndex];
34247
+ if (!cell) {
34248
+ return;
34249
+ }
34250
+ if (cell.nodes.some((cellContent) => cellContent.type === "table")) {
34251
+ return;
34252
+ }
34253
+ event.preventDefault();
34254
+ cancelPendingPointerSelectionReconcile();
34255
+ if (intent.kind === "blocked") {
34256
+ return;
34257
+ }
34258
+ if (intent.kind === "historyUndo") {
34259
+ editor.undo();
34260
+ return;
34261
+ }
34262
+ if (intent.kind === "historyRedo") {
34263
+ editor.redo();
34264
+ return;
34265
+ }
34266
+ const cellParagraphNodes = tableCellParagraphs(cell.nodes);
34267
+ const context = activeTableCellParagraphContext(cellHost);
34268
+ const continuation = editingIntentContinuationRef.current;
34269
+ const continuationPrefix = `c:${tableIndex}:${rowIndex}:${cellIndex}:`;
34270
+ let continuationActive = false;
34271
+ let paragraphIndex = context?.paragraphIndex;
34272
+ let paragraphElement = context?.paragraphElement;
34273
+ if (continuation && continuation.key.startsWith(continuationPrefix)) {
34274
+ const continuationParagraphIndex = Number.parseInt(
34275
+ continuation.key.slice(continuationPrefix.length),
34276
+ 10
34277
+ );
34278
+ const continuationElement = Number.isFinite(continuationParagraphIndex) ? cellHost.querySelector(
34279
+ `[data-docx-table-paragraph-index='${continuationParagraphIndex}']`
34280
+ ) ?? void 0 : void 0;
34281
+ if (continuationElement && continuation.text !== editableTextFromElement(continuationElement)) {
34282
+ continuationActive = true;
34283
+ paragraphIndex = continuationParagraphIndex;
34284
+ paragraphElement = continuationElement;
34285
+ }
34286
+ }
34287
+ let rangeSelectionOffsets;
34288
+ if (paragraphIndex === void 0 || !paragraphElement) {
34289
+ const activeRange = editor.activeTextRange ? normalizeTextRange(editor.activeTextRange) : void 0;
34290
+ const startLocation = activeRange?.start.location;
34291
+ if (activeRange && startLocation && startLocation.kind === "table-cell" && startLocation.tableIndex === tableIndex && startLocation.rowIndex === rowIndex && startLocation.cellIndex === cellIndex && sameParagraphLocation(startLocation, activeRange.end.location)) {
34292
+ const rangeParagraphElement = cellHost.querySelector(
34293
+ `[data-docx-table-paragraph-index='${startLocation.paragraphIndex}']`
34294
+ ) ?? void 0;
34295
+ if (rangeParagraphElement) {
34296
+ paragraphIndex = startLocation.paragraphIndex;
34297
+ paragraphElement = rangeParagraphElement;
34298
+ rangeSelectionOffsets = {
34299
+ start: Math.max(0, Math.round(activeRange.start.offset)),
34300
+ end: Math.max(0, Math.round(activeRange.end.offset))
34301
+ };
34302
+ }
34303
+ }
34304
+ }
34305
+ if (paragraphIndex === void 0 || !paragraphElement || !cellParagraphNodes[paragraphIndex]) {
34306
+ return;
34307
+ }
34308
+ const cellLocation = {
34309
+ kind: "table-cell",
34310
+ tableIndex,
34311
+ rowIndex,
34312
+ cellIndex,
34313
+ paragraphIndex
34314
+ };
34315
+ const currentText = continuationActive && continuation ? continuation.text : editableTextFromElement(paragraphElement);
34316
+ const selectionOffsets = continuationActive && continuation ? { start: continuation.caret, end: continuation.caret } : rangeSelectionOffsets ?? selectionOffsetsWithinElement(paragraphElement) ?? {
34317
+ start: currentText.length,
34318
+ end: currentText.length
34319
+ };
34320
+ if (intent.kind === "deleteContent" || intent.kind === "deleteRange") {
34321
+ const activeRange = editor.activeTextRange ? normalizeTextRange(editor.activeTextRange) : void 0;
34322
+ const expandedBeyondParagraph = Boolean(
34323
+ activeRange && compareTextRangeBoundaries(activeRange.start, activeRange.end) < 0 && !(sameParagraphLocation(activeRange.start.location, cellLocation) && sameParagraphLocation(activeRange.end.location, cellLocation))
34324
+ );
34325
+ if (expandedBeyondParagraph && activeRange) {
34326
+ editingIntentContinuationRef.current = void 0;
34327
+ const collapsedRange = editor.deleteExpandedSelection(activeRange);
34328
+ if (collapsedRange) {
34329
+ tableCellDraftsRef.current.clear();
34330
+ tableCellParagraphDraftsRef.current.clear();
34331
+ syncSelectionFromDocxRange(collapsedRange);
34332
+ }
34333
+ return;
34334
+ }
34335
+ }
34336
+ const effectiveIntent = intent.kind === "insertParagraph" ? { kind: "insertLineBreak" } : intent;
34337
+ const rangeOffsets = !continuationActive && (effectiveIntent.kind === "insertText" || effectiveIntent.kind === "replaceText" || effectiveIntent.kind === "insertLineBreak" || effectiveIntent.kind === "deleteContent" || effectiveIntent.kind === "deleteRange") ? resolveTargetRangeOffsets(paragraphElement) ?? selectionOffsets : selectionOffsets;
34338
+ const applied = applyTextEditingIntent(
34339
+ currentText,
34340
+ rangeOffsets.start,
34341
+ rangeOffsets.end,
34342
+ effectiveIntent
34343
+ );
34344
+ if (!applied) {
34345
+ if (effectiveIntent.kind === "deleteContent" && rangeOffsets.start === rangeOffsets.end) {
34346
+ const paragraphTexts = cellParagraphNodes.map(
34347
+ (cellParagraph, cellParagraphIndex) => cellParagraphIndex === paragraphIndex ? currentText : paragraphText(cellParagraph)
34348
+ );
34349
+ const mergeBoundaryIndex = effectiveIntent.direction === "backward" && rangeOffsets.start === 0 ? paragraphIndex : effectiveIntent.direction === "forward" && rangeOffsets.start >= currentText.length ? paragraphIndex + 1 : void 0;
34350
+ const merged = mergeBoundaryIndex !== void 0 ? mergeCellParagraphTexts(paragraphTexts, mergeBoundaryIndex) : void 0;
34351
+ if (merged) {
34352
+ editingIntentContinuationRef.current = void 0;
34353
+ editor.commitTableCellTextAtRange(
34354
+ tableIndex,
34355
+ rowIndex,
34356
+ cellIndex,
34357
+ merged.cellText,
34358
+ {
34359
+ paragraphIndex: merged.caretParagraphIndex,
34360
+ start: merged.caretOffset,
34361
+ end: merged.caretOffset
34362
+ }
34363
+ );
34364
+ schedulePaginationMeasurementResume();
34365
+ }
34366
+ }
34367
+ return;
34368
+ }
34369
+ const coalesceClass = editingIntentCoalesceClass(effectiveIntent);
34370
+ editor.commitParagraphTextAtRange(
34371
+ cellLocation,
34372
+ applied.text,
34373
+ { start: applied.caret, end: applied.caret },
34374
+ {
34375
+ insertionOffset: rangeOffsets.start,
34376
+ ...coalesceClass ? {
34377
+ coalesceKey: `${continuationPrefix}${paragraphIndex}:${coalesceClass}`
34378
+ } : void 0
34379
+ }
34380
+ );
34381
+ editingIntentContinuationRef.current = {
34382
+ key: `${continuationPrefix}${paragraphIndex}`,
34383
+ text: applied.text,
34384
+ caret: applied.caret
34385
+ };
34386
+ schedulePaginationMeasurementResume();
34387
+ },
34388
+ [
34389
+ activeTableCellParagraphContext,
34390
+ cancelPendingPointerSelectionReconcile,
34391
+ editor,
34392
+ focusParagraphAtOffset,
34393
+ isReadOnly,
34394
+ schedulePaginationMeasurementResume,
34395
+ selectionOffsetsWithinElement,
34396
+ syncSelectionFromDocxRange
34397
+ ]
34398
+ );
34399
+ React.useEffect(() => {
34400
+ const rootElement = viewerRootRef.current;
34401
+ if (!rootElement) {
34402
+ return;
34403
+ }
34404
+ const handleBeforeInput = (event) => {
34405
+ handleEditableHostBeforeInput(event);
34406
+ };
34407
+ rootElement.addEventListener("beforeinput", handleBeforeInput);
34408
+ return () => {
34409
+ rootElement.removeEventListener("beforeinput", handleBeforeInput);
34410
+ };
34411
+ }, [handleEditableHostBeforeInput]);
32699
34412
  const resolveTableColumnWidths = React.useCallback(
32700
34413
  (tableIndex, table, tableWidthPx) => {
32701
34414
  const columnCount = tableColumnCount(table);
@@ -32897,7 +34610,7 @@ function DocxEditorViewer({
32897
34610
  docGridLinePitchPxByNodeIndex.get(nodeIndex),
32898
34611
  pageContentHeightPxByNodeIndex.get(nodeIndex)
32899
34612
  );
32900
- const previousMeasuredRowHeights = tableMeasuredRowHeights[nodeIndex];
34613
+ const previousMeasuredRowHeights = node.blockId ? tableMeasuredRowHeights[node.blockId]?.rowHeightsPx : void 0;
32901
34614
  const measuredHeights = node.rows.map((_, rowIndex) => {
32902
34615
  const measuredHeight = measuredByRowIndex.get(rowIndex);
32903
34616
  if (measuredHeight !== void 0) {
@@ -32916,35 +34629,46 @@ function DocxEditorViewer({
32916
34629
  setTableMeasuredRowHeights((current) => {
32917
34630
  let changed = false;
32918
34631
  const next = {};
32919
- Object.entries(current).forEach(([tableIndexText, heights]) => {
32920
- const tableIndex = Number.parseInt(tableIndexText, 10);
32921
- const tableNode = editor.model.nodes[tableIndex];
32922
- if (!tableNode || tableNode.type !== "table") {
32923
- changed = true;
32924
- return;
34632
+ const tableNodesByBlockId = /* @__PURE__ */ new Map();
34633
+ const tableBlockIdsByNodeIndex = /* @__PURE__ */ new Map();
34634
+ editor.model.nodes.forEach((node, nodeIndex) => {
34635
+ if (node.type === "table" && node.blockId) {
34636
+ tableNodesByBlockId.set(node.blockId, node);
34637
+ tableBlockIdsByNodeIndex.set(nodeIndex, node.blockId);
32925
34638
  }
32926
- if (!Array.isArray(heights) || heights.length !== tableNode.rows.length) {
34639
+ });
34640
+ Object.entries(current).forEach(([blockId, entry]) => {
34641
+ const tableNode = tableNodesByBlockId.get(blockId);
34642
+ if (!tableNode || !Array.isArray(entry.rowHeightsPx) || entry.rowHeightsPx.length !== tableNode.rows.length) {
32927
34643
  changed = true;
32928
34644
  return;
32929
34645
  }
32930
- next[tableIndex] = heights;
34646
+ next[blockId] = entry;
32931
34647
  });
32932
34648
  Object.entries(nextMeasuredHeights).forEach(
32933
34649
  ([tableIndexText, measuredHeights]) => {
32934
34650
  const tableIndex = Number.parseInt(tableIndexText, 10);
32935
- const currentHeights = next[tableIndex] ?? [];
32936
- if (currentHeights.length !== measuredHeights.length) {
32937
- next[tableIndex] = measuredHeights;
32938
- changed = true;
34651
+ const blockId = tableBlockIdsByNodeIndex.get(tableIndex);
34652
+ const tableNode = blockId ? tableNodesByBlockId.get(blockId) : void 0;
34653
+ if (!blockId || !tableNode) {
32939
34654
  return;
32940
34655
  }
32941
- for (let index = 0; index < measuredHeights.length; index += 1) {
32942
- if (currentHeights[index] !== measuredHeights[index]) {
32943
- next[tableIndex] = measuredHeights;
32944
- changed = true;
32945
- return;
34656
+ const contentSignature = docNodeContentSignature(tableNode);
34657
+ const currentEntry = next[blockId];
34658
+ const currentHeights = currentEntry?.rowHeightsPx ?? [];
34659
+ let heightsChanged = currentHeights.length !== measuredHeights.length;
34660
+ if (!heightsChanged) {
34661
+ for (let index = 0; index < measuredHeights.length; index += 1) {
34662
+ if (currentHeights[index] !== measuredHeights[index]) {
34663
+ heightsChanged = true;
34664
+ break;
34665
+ }
32946
34666
  }
32947
34667
  }
34668
+ if (heightsChanged || currentEntry?.contentSignature !== contentSignature) {
34669
+ next[blockId] = { rowHeightsPx: measuredHeights, contentSignature };
34670
+ changed = true;
34671
+ }
32948
34672
  }
32949
34673
  );
32950
34674
  return changed ? next : current;
@@ -33455,27 +35179,72 @@ function DocxEditorViewer({
33455
35179
  "[data-docx-paragraph-host='true']"
33456
35180
  );
33457
35181
  const paragraphRect = paragraphHost?.getBoundingClientRect();
35182
+ const zoomScale = resolveViewerMeasurementZoomScale(wrapperElement, 1);
33458
35183
  const baseFloating = image.floating ? { ...image.floating } : {};
35184
+ const dragStartAnchor = isWrappedFloatingImage && location.kind === "paragraph" ? resolveWrappedDropAnchorParagraphHost(
35185
+ wrapperElement,
35186
+ wrapperRect.top,
35187
+ wrapperRect.left
35188
+ ) : void 0;
33459
35189
  let latestDeltaX = 0;
33460
35190
  let latestDeltaY = 0;
33461
35191
  let frameId;
33462
35192
  let inlineDragActivated = false;
33463
35193
  let latestInlineDropTarget;
33464
35194
  let latestInlineDropTargetKey;
35195
+ const measuredBands = (() => {
35196
+ if (!isWrappedFloatingImage || !pageSurface || !pageSurfaceRect) {
35197
+ return void 0;
35198
+ }
35199
+ const hostByNodeIndex = {};
35200
+ for (const host of Array.from(
35201
+ pageSurface.querySelectorAll(
35202
+ "[data-docx-paragraph-host='true'][data-docx-paragraph-kind='paragraph'][data-docx-paragraph-node-index]"
35203
+ )
35204
+ )) {
35205
+ const nodeIndex = Number.parseInt(
35206
+ host.getAttribute("data-docx-paragraph-node-index") ?? "",
35207
+ 10
35208
+ );
35209
+ if (!Number.isFinite(nodeIndex)) {
35210
+ continue;
35211
+ }
35212
+ const rect = host.getBoundingClientRect();
35213
+ if (rect.height <= 0) {
35214
+ continue;
35215
+ }
35216
+ hostByNodeIndex[nodeIndex] = {
35217
+ topPx: (rect.top - pageSurfaceRect.top) / zoomScale,
35218
+ bottomPx: (rect.bottom - pageSurfaceRect.top) / zoomScale
35219
+ };
35220
+ }
35221
+ return Object.keys(hostByNodeIndex).length > 0 ? { hostByNodeIndex } : void 0;
35222
+ })();
33465
35223
  const updatePreview = () => {
33466
35224
  setFloatingMovePreview({
33467
35225
  imageKey,
33468
35226
  deltaX: latestDeltaX,
33469
35227
  deltaY: latestDeltaY,
35228
+ measuredBands,
33470
35229
  ...paragraphRect ? {
33471
- baseLeftPx: Math.round(wrapperRect.left - paragraphRect.left),
33472
- baseTopPx: Math.round(wrapperRect.top - paragraphRect.top)
35230
+ baseLeftPx: Math.round(
35231
+ (wrapperRect.left - paragraphRect.left) / zoomScale
35232
+ ),
35233
+ baseTopPx: Math.round(
35234
+ (wrapperRect.top - paragraphRect.top) / zoomScale
35235
+ )
33473
35236
  } : void 0
33474
35237
  });
33475
35238
  };
33476
35239
  const onPointerMove = (pointerEvent) => {
33477
- latestDeltaX = pointerEvent.clientX - startX;
33478
- latestDeltaY = pointerEvent.clientY - startY;
35240
+ latestDeltaX = normalizeFloatingDragDeltaForZoom(
35241
+ pointerEvent.clientX - startX,
35242
+ zoomScale
35243
+ );
35244
+ latestDeltaY = normalizeFloatingDragDeltaForZoom(
35245
+ pointerEvent.clientY - startY,
35246
+ zoomScale
35247
+ );
33479
35248
  if (isInlineImage) {
33480
35249
  if (!inlineDragActivated) {
33481
35250
  const movementDistancePx = Math.abs(latestDeltaX) + Math.abs(latestDeltaY);
@@ -33552,9 +35321,9 @@ function DocxEditorViewer({
33552
35321
  return;
33553
35322
  }
33554
35323
  if (isWrappedFloatingImage) {
33555
- const hostWidth = paragraphRect?.width ?? DEFAULT_DOC_PAGE_WIDTH;
33556
- const imageWidth = image.widthPx ?? Math.max(24, Math.round(wrapperRect.width));
33557
- const imageHeight = image.heightPx ?? Math.max(24, Math.round(wrapperRect.height));
35324
+ const hostWidth = paragraphRect ? paragraphRect.width / zoomScale : DEFAULT_DOC_PAGE_WIDTH;
35325
+ const imageWidth = image.widthPx ?? Math.max(24, Math.round(wrapperRect.width / zoomScale));
35326
+ const imageHeight = image.heightPx ?? Math.max(24, Math.round(wrapperRect.height / zoomScale));
33558
35327
  const baseGeometry = resolveDualWrappedFloatingImageGeometry(
33559
35328
  image,
33560
35329
  hostWidth,
@@ -33563,9 +35332,11 @@ function DocxEditorViewer({
33563
35332
  heightPx: imageHeight,
33564
35333
  ...paragraphRect ? {
33565
35334
  baseLeftPx: Math.round(
33566
- wrapperRect.left - paragraphRect.left
35335
+ (wrapperRect.left - paragraphRect.left) / zoomScale
33567
35336
  ),
33568
- baseTopPx: Math.round(wrapperRect.top - paragraphRect.top)
35337
+ baseTopPx: Math.round(
35338
+ (wrapperRect.top - paragraphRect.top) / zoomScale
35339
+ )
33569
35340
  } : void 0
33570
35341
  }
33571
35342
  );
@@ -33577,6 +35348,46 @@ function DocxEditorViewer({
33577
35348
  const movedTop = Math.round(
33578
35349
  (baseGeometry?.imageTopPx ?? 0) + latestDeltaY
33579
35350
  );
35351
+ const droppedTopScreenPx = wrapperRect.top + latestDeltaY * zoomScale;
35352
+ const droppedLeftScreenPx = wrapperRect.left + latestDeltaX * zoomScale;
35353
+ const dropAnchor = location.kind === "paragraph" && wrappedDragCanReanchorToParagraph(baseFloating) ? resolveWrappedDropAnchorParagraphHost(
35354
+ wrapperElement,
35355
+ droppedTopScreenPx,
35356
+ droppedLeftScreenPx
35357
+ ) : void 0;
35358
+ if (dropAnchor && location.kind === "paragraph" && dropAnchor.nodeIndex !== location.nodeIndex && dropAnchor.nodeIndex !== dragStartAnchor?.nodeIndex) {
35359
+ const targetHostWidth = dropAnchor.rect.width / zoomScale;
35360
+ const targetMovedLeft = clampNumber(
35361
+ Math.round(
35362
+ (droppedLeftScreenPx - dropAnchor.rect.left) / zoomScale
35363
+ ),
35364
+ 0,
35365
+ Math.max(0, targetHostWidth - imageWidth)
35366
+ );
35367
+ const targetMovedTop = Math.round(
35368
+ (droppedTopScreenPx - dropAnchor.rect.top) / zoomScale
35369
+ );
35370
+ editor.moveFloatingImage(
35371
+ location,
35372
+ resolveWrappedFloatingImageDropPatch(
35373
+ image,
35374
+ targetHostWidth,
35375
+ targetMovedLeft,
35376
+ targetMovedTop,
35377
+ {
35378
+ widthPx: imageWidth,
35379
+ heightPx: imageHeight
35380
+ }
35381
+ ),
35382
+ { reparentToParagraphNodeIndex: dropAnchor.nodeIndex }
35383
+ );
35384
+ setSelectedImage({
35385
+ kind: "paragraph",
35386
+ nodeIndex: dropAnchor.nodeIndex,
35387
+ childIndex: 0
35388
+ });
35389
+ return;
35390
+ }
33580
35391
  editor.moveFloatingImage(
33581
35392
  location,
33582
35393
  resolveWrappedFloatingImageDropPatch(
@@ -33593,14 +35404,21 @@ function DocxEditorViewer({
33593
35404
  return;
33594
35405
  }
33595
35406
  if (isAbsoluteFloatingImage) {
35407
+ const dropPageSurfaceRect = pageSurface && pageSurface.isConnected ? pageSurface.getBoundingClientRect() : pageSurfaceRect;
33596
35408
  editor.moveFloatingImage(
33597
35409
  location,
33598
35410
  resolveAbsoluteFloatingImageDropPatch(
33599
35411
  baseFloating,
33600
35412
  documentLayout,
33601
35413
  {
33602
- wrapperRect,
33603
- pageSurfaceRect,
35414
+ wrapperRect: normalizeFloatingDropRectForZoom(
35415
+ wrapperRect,
35416
+ zoomScale
35417
+ ),
35418
+ pageSurfaceRect: dropPageSurfaceRect ? normalizeFloatingDropRectForZoom(
35419
+ dropPageSurfaceRect,
35420
+ zoomScale
35421
+ ) : void 0,
33604
35422
  deltaX: latestDeltaX,
33605
35423
  deltaY: latestDeltaY
33606
35424
  }
@@ -33613,7 +35431,7 @@ function DocxEditorViewer({
33613
35431
  window.addEventListener("pointerup", onPointerUp, { once: true });
33614
35432
  window.addEventListener("pointercancel", onPointerUp, { once: true });
33615
35433
  },
33616
- [documentLayout, editor, isReadOnly]
35434
+ [documentLayout, editor, isReadOnly, resolveViewerMeasurementZoomScale]
33617
35435
  );
33618
35436
  const beginDropCapMove = React.useCallback(
33619
35437
  (event, nodeIndex, dropCap) => {
@@ -33750,6 +35568,7 @@ function DocxEditorViewer({
33750
35568
  "[data-docx-section-paragraph-host='true']"
33751
35569
  );
33752
35570
  const paragraphRect = paragraphHost?.getBoundingClientRect();
35571
+ const zoomScale = resolveViewerMeasurementZoomScale(wrapperElement, 1);
33753
35572
  const baseFloating = image.floating ? { ...image.floating } : {};
33754
35573
  let latestDeltaX = 0;
33755
35574
  let latestDeltaY = 0;
@@ -33760,14 +35579,24 @@ function DocxEditorViewer({
33760
35579
  deltaX: latestDeltaX,
33761
35580
  deltaY: latestDeltaY,
33762
35581
  ...paragraphRect ? {
33763
- baseLeftPx: Math.round(wrapperRect.left - paragraphRect.left),
33764
- baseTopPx: Math.round(wrapperRect.top - paragraphRect.top)
35582
+ baseLeftPx: Math.round(
35583
+ (wrapperRect.left - paragraphRect.left) / zoomScale
35584
+ ),
35585
+ baseTopPx: Math.round(
35586
+ (wrapperRect.top - paragraphRect.top) / zoomScale
35587
+ )
33765
35588
  } : void 0
33766
35589
  });
33767
35590
  };
33768
35591
  const onPointerMove = (pointerEvent) => {
33769
- latestDeltaX = pointerEvent.clientX - startX;
33770
- latestDeltaY = pointerEvent.clientY - startY;
35592
+ latestDeltaX = normalizeFloatingDragDeltaForZoom(
35593
+ pointerEvent.clientX - startX,
35594
+ zoomScale
35595
+ );
35596
+ latestDeltaY = normalizeFloatingDragDeltaForZoom(
35597
+ pointerEvent.clientY - startY,
35598
+ zoomScale
35599
+ );
33771
35600
  if (frameId !== void 0) {
33772
35601
  window.cancelAnimationFrame(frameId);
33773
35602
  }
@@ -33785,9 +35614,9 @@ function DocxEditorViewer({
33785
35614
  return;
33786
35615
  }
33787
35616
  if (isWrappedFloatingImage) {
33788
- const hostWidth = paragraphRect?.width ?? documentLayout.pageWidthPx;
33789
- const imageWidth = image.widthPx ?? Math.max(24, Math.round(wrapperRect.width));
33790
- const imageHeight = image.heightPx ?? Math.max(24, Math.round(wrapperRect.height));
35617
+ const hostWidth = paragraphRect ? paragraphRect.width / zoomScale : documentLayout.pageWidthPx;
35618
+ const imageWidth = image.widthPx ?? Math.max(24, Math.round(wrapperRect.width / zoomScale));
35619
+ const imageHeight = image.heightPx ?? Math.max(24, Math.round(wrapperRect.height / zoomScale));
33791
35620
  const baseGeometry = resolveDualWrappedFloatingImageGeometry(
33792
35621
  image,
33793
35622
  hostWidth,
@@ -33796,9 +35625,11 @@ function DocxEditorViewer({
33796
35625
  heightPx: imageHeight,
33797
35626
  ...paragraphRect ? {
33798
35627
  baseLeftPx: Math.round(
33799
- wrapperRect.left - paragraphRect.left
35628
+ (wrapperRect.left - paragraphRect.left) / zoomScale
33800
35629
  ),
33801
- baseTopPx: Math.round(wrapperRect.top - paragraphRect.top)
35630
+ baseTopPx: Math.round(
35631
+ (wrapperRect.top - paragraphRect.top) / zoomScale
35632
+ )
33802
35633
  } : void 0
33803
35634
  }
33804
35635
  );
@@ -33828,14 +35659,21 @@ function DocxEditorViewer({
33828
35659
  return;
33829
35660
  }
33830
35661
  if (isAbsoluteFloatingImage) {
35662
+ const dropPageSurfaceRect = pageSurface && pageSurface.isConnected ? pageSurface.getBoundingClientRect() : pageSurfaceRect;
33831
35663
  editor.moveSectionFloatingImage(
33832
35664
  location,
33833
35665
  resolveAbsoluteFloatingImageDropPatch(
33834
35666
  baseFloating,
33835
35667
  documentLayout,
33836
35668
  {
33837
- wrapperRect,
33838
- pageSurfaceRect,
35669
+ wrapperRect: normalizeFloatingDropRectForZoom(
35670
+ wrapperRect,
35671
+ zoomScale
35672
+ ),
35673
+ pageSurfaceRect: dropPageSurfaceRect ? normalizeFloatingDropRectForZoom(
35674
+ dropPageSurfaceRect,
35675
+ zoomScale
35676
+ ) : void 0,
33839
35677
  deltaX: latestDeltaX,
33840
35678
  deltaY: latestDeltaY
33841
35679
  }
@@ -33847,7 +35685,13 @@ function DocxEditorViewer({
33847
35685
  window.addEventListener("pointerup", onPointerUp, { once: true });
33848
35686
  window.addEventListener("pointercancel", onPointerUp, { once: true });
33849
35687
  },
33850
- [activeHeaderFooterEdit, documentLayout, editor, isReadOnly]
35688
+ [
35689
+ activeHeaderFooterEdit,
35690
+ documentLayout,
35691
+ editor,
35692
+ isReadOnly,
35693
+ resolveViewerMeasurementZoomScale
35694
+ ]
33851
35695
  );
33852
35696
  const onSectionImageClick = React.useCallback(
33853
35697
  (location) => {
@@ -34514,6 +36358,10 @@ function DocxEditorViewer({
34514
36358
  display: "inline-block",
34515
36359
  whiteSpace: "pre",
34516
36360
  lineHeight: `${lineHeightPx}px`,
36361
+ // Each fragment is its own block, so an inherited paragraph
36362
+ // text-indent would shift every fragment past its computed
36363
+ // interval; the layout reserves first-line indent itself.
36364
+ textIndent: 0,
34517
36365
  pointerEvents: activeSession ? "none" : void 0
34518
36366
  },
34519
36367
  children: pieces
@@ -34760,15 +36608,24 @@ function DocxEditorViewer({
34760
36608
  "aria-label": "Wrapped paragraph text",
34761
36609
  onChange: (event) => {
34762
36610
  cancelPendingPointerSelectionReconcile();
34763
- editor.beginSelectionSession("keyboard", {
34764
- settleAfterMs: 220
34765
- });
34766
36611
  const nextText = event.currentTarget.value.replace(
34767
36612
  /\r\n?/g,
34768
36613
  "\n"
34769
36614
  );
34770
36615
  const nextStart = event.currentTarget.selectionStart ?? nextText.length;
34771
36616
  const nextEnd = event.currentTarget.selectionEnd ?? nextStart;
36617
+ const nativeInputEvent = event.nativeEvent;
36618
+ if (nativeInputEvent?.isComposing || compositionActiveRef.current) {
36619
+ editor.beginSelectionSession("composition");
36620
+ syncWrappedParagraphRange(location, nextStart, nextEnd, {
36621
+ textOverride: nextText,
36622
+ textLength: nextText.length
36623
+ });
36624
+ return;
36625
+ }
36626
+ editor.beginSelectionSession("keyboard", {
36627
+ settleAfterMs: 220
36628
+ });
34772
36629
  syncWrappedParagraphRange(location, nextStart, nextEnd, {
34773
36630
  textOverride: nextText,
34774
36631
  textLength: nextText.length
@@ -34786,12 +36643,14 @@ function DocxEditorViewer({
34786
36643
  });
34787
36644
  },
34788
36645
  onCompositionStart: () => {
36646
+ compositionActiveRef.current = true;
34789
36647
  editor.beginSelectionSession("composition");
34790
36648
  setActiveWrappedParagraphSession(
34791
36649
  (current) => current && current.locationKey === locationKey ? { ...current, isComposing: true } : current
34792
36650
  );
34793
36651
  },
34794
36652
  onCompositionEnd: (event) => {
36653
+ compositionActiveRef.current = false;
34795
36654
  editor.beginSelectionSession("keyboard", {
34796
36655
  settleAfterMs: 260
34797
36656
  });
@@ -34801,18 +36660,20 @@ function DocxEditorViewer({
34801
36660
  );
34802
36661
  const nextStart = event.currentTarget.selectionStart ?? nextText.length;
34803
36662
  const nextEnd = event.currentTarget.selectionEnd ?? nextStart;
34804
- setActiveWrappedParagraphSession(
34805
- (current) => current && current.locationKey === locationKey ? {
34806
- ...current,
34807
- isComposing: false,
34808
- text: nextText,
34809
- selectionStart: nextStart,
34810
- selectionEnd: nextEnd
34811
- } : current
34812
- );
36663
+ syncWrappedParagraphRange(location, nextStart, nextEnd, {
36664
+ textOverride: nextText,
36665
+ textLength: nextText.length,
36666
+ isComposing: false
36667
+ });
36668
+ commitWrappedParagraphTextAtLocation(location, nextText);
36669
+ schedulePaginationMeasurementResume();
34813
36670
  },
34814
36671
  onKeyDown: (event) => {
34815
36672
  cancelPendingPointerSelectionReconcile();
36673
+ if (isCompositionKeyboardEvent(event)) {
36674
+ editor.beginSelectionSession("composition");
36675
+ return;
36676
+ }
34816
36677
  editor.beginSelectionSession("keyboard", {
34817
36678
  settleAfterMs: 220
34818
36679
  });
@@ -34935,6 +36796,13 @@ function DocxEditorViewer({
34935
36796
  }
34936
36797
  },
34937
36798
  onBlur: (event) => {
36799
+ if (compositionActiveRef.current) {
36800
+ compositionActiveRef.current = false;
36801
+ commitWrappedParagraphTextAtLocation(
36802
+ location,
36803
+ event.currentTarget.value.replace(/\r\n?/g, "\n")
36804
+ );
36805
+ }
34938
36806
  const currentTarget = event.currentTarget;
34939
36807
  const wrappedParagraphRoot = currentTarget.closest(
34940
36808
  "[data-docx-wrapped-paragraph-root='true']"
@@ -35292,7 +37160,8 @@ function DocxEditorViewer({
35292
37160
  top: activeDualWrappedLayout.layout.lines[lineIndex]?.y ?? 0,
35293
37161
  display: "inline-block",
35294
37162
  whiteSpace: "pre",
35295
- lineHeight: `${activeDualWrappedLayout.lineHeightPx}px`
37163
+ lineHeight: `${activeDualWrappedLayout.lineHeightPx}px`,
37164
+ textIndent: 0
35296
37165
  },
35297
37166
  children: pieces
35298
37167
  },
@@ -36014,9 +37883,10 @@ function DocxEditorViewer({
36014
37883
  source: activeWrappedSource,
36015
37884
  layout: activeWrappedLayout,
36016
37885
  lineHeightPx: activeDualWrappedLayout.lineHeightPx,
36017
- blockHeightPx: resolveDualWrapParagraphRenderBlockHeightPx(
37886
+ blockHeightPx: resolveDragPreviewAwareWrapBlockHeightPx(
36018
37887
  activeWrappedLayout,
36019
- activeDualWrappedLayout.geometries
37888
+ activeDualWrappedLayout.geometries,
37889
+ options?.pageFlowForeignExclusions
36020
37890
  ),
36021
37891
  obstacleNodes: /* @__PURE__ */ jsxs(Fragment2, { children: [
36022
37892
  activeDualWrappedLayout.geometries.map(
@@ -37630,6 +39500,9 @@ function DocxEditorViewer({
37630
39500
  ),
37631
39501
  top: 0,
37632
39502
  marginRight: 0,
39503
+ // Left-align the glyph in its hanging box (see body-paragraph twin)
39504
+ // so a split list item's marker doesn't overlap the body text.
39505
+ justifyContent: "flex-start",
37633
39506
  zIndex: 1,
37634
39507
  pointerEvents: "none"
37635
39508
  },
@@ -37668,7 +39541,11 @@ function DocxEditorViewer({
37668
39541
  ...baseParagraphStyle,
37669
39542
  ...hasPartialLineRange ? {
37670
39543
  marginTop: paragraphSegmentStartLine === 0 ? baseParagraphStyle.marginTop : 0,
37671
- marginBottom: paragraphSegmentEndLine >= paragraphSegmentTotalLines ? baseParagraphStyle.marginBottom : 0
39544
+ marginBottom: paragraphSegmentEndLine >= paragraphSegmentTotalLines ? baseParagraphStyle.marginBottom : 0,
39545
+ // See body-paragraph twin: the pretext split path positions
39546
+ // everything absolutely, so drop the block hanging text-indent that
39547
+ // would otherwise shift the segment left by the hanging amount.
39548
+ ...shouldRenderParagraphSegmentWithPretext ? { textIndent: 0 } : void 0
37672
39549
  } : void 0,
37673
39550
  outline: "none"
37674
39551
  };
@@ -37857,6 +39734,11 @@ function DocxEditorViewer({
37857
39734
  ),
37858
39735
  top: 0,
37859
39736
  marginRight: 0,
39737
+ // Left-align the marker glyph within its hanging-indent box so it
39738
+ // sits at the number position with a gap before the text, instead
39739
+ // of flex-end pinning it against the body text (which starts at
39740
+ // the box's right edge) and overlapping it on split paragraphs.
39741
+ justifyContent: "flex-start",
37860
39742
  zIndex: 1,
37861
39743
  pointerEvents: "none"
37862
39744
  },
@@ -37959,7 +39841,14 @@ function DocxEditorViewer({
37959
39841
  ...baseParagraphStyle,
37960
39842
  ...hasPartialLineRange ? {
37961
39843
  marginTop: paragraphSegmentStartLine === 0 ? resolvedBeforeSpacingPx ?? beforeSpacingPx : 0,
37962
- marginBottom: paragraphSegmentEndLine >= paragraphSegmentTotalLines ? resolvedAfterSpacingPx ?? afterSpacingPx : 0
39844
+ marginBottom: paragraphSegmentEndLine >= paragraphSegmentTotalLines ? resolvedAfterSpacingPx ?? afterSpacingPx : 0,
39845
+ // The pretext split path positions the marker and every line
39846
+ // fragment absolutely, so it does not want the block hanging
39847
+ // `text-indent: -hanging` (which otherwise shifts the whole
39848
+ // absolutely-positioned segment left by the hanging amount,
39849
+ // dropping the paragraph's left indent). The clip-fallback path
39850
+ // still renders inline and keeps the text-indent.
39851
+ ...shouldRenderParagraphSegmentWithPretext ? { textIndent: 0 } : void 0
37963
39852
  } : resolvedBeforeSpacingPx !== void 0 || resolvedAfterSpacingPx !== void 0 ? {
37964
39853
  ...resolvedBeforeSpacingPx !== void 0 ? { marginTop: resolvedBeforeSpacingPx } : void 0,
37965
39854
  ...resolvedAfterSpacingPx !== void 0 ? { marginBottom: resolvedAfterSpacingPx } : void 0
@@ -38059,8 +39948,9 @@ function DocxEditorViewer({
38059
39948
  )
38060
39949
  }
38061
39950
  ) : getFallbackParagraphRuns();
38062
- const paragraphDraftHtml = paragraphDraftsRef.current.get(nodeIndex);
38063
- const renderedEditableParagraphHtml = typeof paragraphDraftHtml === "string" ? paragraphDraftHtml : renderStaticHtml(renderedInteractiveParagraphContent);
39951
+ const renderedEditableParagraphHtml = renderStaticHtml(
39952
+ renderedInteractiveParagraphContent
39953
+ );
38064
39954
  return /* @__PURE__ */ jsx(
38065
39955
  "div",
38066
39956
  {
@@ -38071,9 +39961,11 @@ function DocxEditorViewer({
38071
39961
  "data-docx-paragraph-end-line": paragraphSegmentEndLine,
38072
39962
  "data-docx-paragraph-partial-line-range": hasPartialLineRange ? "true" : void 0,
38073
39963
  style: paragraphStyle,
38074
- dangerouslySetInnerHTML: editable ? {
38075
- __html: renderedEditableParagraphHtml
38076
- } : void 0,
39964
+ dangerouslySetInnerHTML: editable ? stableInnerHtmlProp(
39965
+ editableParagraphHtmlPropsRef.current,
39966
+ nodeIndex,
39967
+ renderedEditableParagraphHtml
39968
+ ) : void 0,
38077
39969
  ref: (element) => {
38078
39970
  if (shouldTrackParagraphElement) {
38079
39971
  if (element) {
@@ -38103,49 +39995,6 @@ function DocxEditorViewer({
38103
39995
  }
38104
39996
  });
38105
39997
  }
38106
- const draft = paragraphDraftsRef.current.get(nodeIndex);
38107
- if (typeof draft === "string") {
38108
- const draftHtml = draft;
38109
- scheduleDomWrite(() => {
38110
- if (!element.isConnected) {
38111
- return;
38112
- }
38113
- const latestDraft = paragraphDraftsRef.current.get(nodeIndex);
38114
- if (latestDraft !== draftHtml) {
38115
- return;
38116
- }
38117
- if (element.innerHTML !== draftHtml) {
38118
- const activeElement = document.activeElement;
38119
- const shouldRestoreSelection = activeElement === element || activeElement instanceof Element && element.contains(activeElement);
38120
- const selectionOffsets = shouldRestoreSelection ? selectionOffsetsWithinElement(element) : void 0;
38121
- element.innerHTML = draftHtml;
38122
- if (shouldRestoreSelection) {
38123
- if (selectionOffsets) {
38124
- const textLength = editableTextFromElement(element).length;
38125
- const safeStart = Math.max(
38126
- 0,
38127
- Math.min(selectionOffsets.start, textLength)
38128
- );
38129
- const safeEnd = Math.max(
38130
- safeStart,
38131
- Math.min(selectionOffsets.end, textLength)
38132
- );
38133
- setSelectionWithinElementByTextOffsets(
38134
- element,
38135
- safeStart,
38136
- safeEnd
38137
- );
38138
- } else {
38139
- placeCaretInsideElement(element);
38140
- }
38141
- }
38142
- }
38143
- const latestParagraph = editor.model.nodes[nodeIndex];
38144
- if (latestParagraph && latestParagraph.type === "paragraph" && editableTextFromElement(element) === paragraphText(latestParagraph)) {
38145
- paragraphDraftsRef.current.delete(nodeIndex);
38146
- }
38147
- });
38148
- }
38149
39998
  },
38150
39999
  onPointerDown: (event) => {
38151
40000
  if (eventTargetIsInteractiveControl(event.target) || !editable) {
@@ -38263,36 +40112,78 @@ function DocxEditorViewer({
38263
40112
  return;
38264
40113
  }
38265
40114
  cancelPendingPointerSelectionReconcile();
38266
- editor.beginSelectionSession("keyboard", { settleAfterMs: 220 });
38267
- if (hasPartialLineRange) {
38268
- activateEditableParagraphSegment(nodeIndex, paragraphLineRange);
40115
+ const nativeInputEvent = event.nativeEvent;
40116
+ if (nativeInputEvent?.isComposing || compositionActiveRef.current) {
40117
+ editor.beginSelectionSession("composition");
40118
+ return;
40119
+ }
40120
+ const domText = editableTextFromElement(event.currentTarget);
40121
+ const latestParagraph = editor.model.nodes[nodeIndex];
40122
+ if (!latestParagraph || latestParagraph.type !== "paragraph" || domText === paragraphText(latestParagraph)) {
40123
+ return;
38269
40124
  }
40125
+ const continuation = editingIntentContinuationRef.current;
40126
+ if (continuation && continuation.key === `p:${nodeIndex}` && continuation.text !== domText) {
40127
+ return;
40128
+ }
40129
+ editor.beginSelectionSession("keyboard", { settleAfterMs: 220 });
38270
40130
  schedulePaginationMeasurementResume();
38271
- paragraphDraftsRef.current.set(
38272
- nodeIndex,
38273
- event.currentTarget.innerHTML
38274
- );
38275
40131
  const typedOffsets = selectionOffsetsWithinElement(
38276
40132
  event.currentTarget
38277
40133
  );
38278
- pendingEditableCaretRef.current = typedOffsets ? {
38279
- nodeIndex,
38280
- start: typedOffsets.start,
38281
- end: typedOffsets.end
38282
- } : null;
40134
+ const caretOffset = typedOffsets?.end ?? domText.length;
40135
+ editor.commitParagraphTextAtRange(
40136
+ { kind: "paragraph", nodeIndex },
40137
+ domText,
40138
+ {
40139
+ start: typedOffsets?.start ?? caretOffset,
40140
+ end: caretOffset
40141
+ }
40142
+ );
40143
+ editingIntentContinuationRef.current = {
40144
+ key: `p:${nodeIndex}`,
40145
+ text: domText,
40146
+ caret: caretOffset
40147
+ };
38283
40148
  },
38284
40149
  onCompositionStart: () => {
38285
40150
  if (!editable) {
38286
40151
  return;
38287
40152
  }
38288
40153
  cancelPendingPointerSelectionReconcile();
40154
+ compositionActiveRef.current = true;
38289
40155
  editor.beginSelectionSession("composition");
38290
40156
  },
38291
- onCompositionEnd: () => {
40157
+ onCompositionEnd: (event) => {
38292
40158
  if (!editable) {
38293
40159
  return;
38294
40160
  }
40161
+ compositionActiveRef.current = false;
38295
40162
  editor.beginSelectionSession("keyboard", { settleAfterMs: 260 });
40163
+ schedulePaginationMeasurementResume();
40164
+ const composedText = editableTextFromElement(event.currentTarget);
40165
+ const composedOffsets = selectionOffsetsWithinElement(
40166
+ event.currentTarget
40167
+ );
40168
+ const caretEnd = composedOffsets?.end ?? composedText.length;
40169
+ editor.commitParagraphTextAtRange(
40170
+ { kind: "paragraph", nodeIndex },
40171
+ composedText,
40172
+ {
40173
+ start: composedOffsets?.start ?? caretEnd,
40174
+ end: caretEnd
40175
+ }
40176
+ );
40177
+ editingIntentContinuationRef.current = {
40178
+ key: `p:${nodeIndex}`,
40179
+ text: composedText,
40180
+ caret: caretEnd
40181
+ };
40182
+ pendingEditableCaretRef.current = composedOffsets ? {
40183
+ nodeIndex,
40184
+ start: composedOffsets.start,
40185
+ end: composedOffsets.end
40186
+ } : null;
38296
40187
  },
38297
40188
  onPaste: (event) => {
38298
40189
  const pastedText = event.clipboardData.getData("text/plain");
@@ -38305,13 +40196,16 @@ function DocxEditorViewer({
38305
40196
  }
38306
40197
  event.preventDefault();
38307
40198
  event.stopPropagation();
38308
- paragraphDraftsRef.current.delete(nodeIndex);
38309
40199
  },
38310
40200
  onKeyDown: (event) => {
38311
40201
  if (!editable) {
38312
40202
  return;
38313
40203
  }
38314
40204
  cancelPendingPointerSelectionReconcile();
40205
+ if (isCompositionKeyboardEvent(event)) {
40206
+ editor.beginSelectionSession("composition");
40207
+ return;
40208
+ }
38315
40209
  editor.beginSelectionSession("keyboard", { settleAfterMs: 220 });
38316
40210
  if (hasPartialLineRange) {
38317
40211
  activateEditableParagraphSegment(nodeIndex, paragraphLineRange);
@@ -38325,11 +40219,6 @@ function DocxEditorViewer({
38325
40219
  const handledHistoryShortcut = handleEditorHistoryShortcut(
38326
40220
  event,
38327
40221
  () => {
38328
- commitParagraphDraftFromElement(
38329
- nodeIndex,
38330
- node,
38331
- event.currentTarget
38332
- );
38333
40222
  }
38334
40223
  );
38335
40224
  if (handledHistoryShortcut) {
@@ -38341,7 +40230,6 @@ function DocxEditorViewer({
38341
40230
  if (replaced) {
38342
40231
  event.preventDefault();
38343
40232
  event.stopPropagation();
38344
- paragraphDraftsRef.current.delete(nodeIndex);
38345
40233
  return;
38346
40234
  }
38347
40235
  }
@@ -38351,7 +40239,6 @@ function DocxEditorViewer({
38351
40239
  if (replaced) {
38352
40240
  event.preventDefault();
38353
40241
  event.stopPropagation();
38354
- paragraphDraftsRef.current.delete(nodeIndex);
38355
40242
  return;
38356
40243
  }
38357
40244
  }
@@ -38413,7 +40300,7 @@ function DocxEditorViewer({
38413
40300
  if (previousLocation && previousParagraph) {
38414
40301
  event.preventDefault();
38415
40302
  event.stopPropagation();
38416
- paragraphDraftsRef.current.delete(nodeIndex);
40303
+ editingIntentContinuationRef.current = void 0;
38417
40304
  const caretClientPoint = collapsedCaretClientPointWithinElement(event.currentTarget);
38418
40305
  if (caretClientPoint && focusParagraphLocationAtClientPoint(
38419
40306
  previousLocation,
@@ -38435,7 +40322,7 @@ function DocxEditorViewer({
38435
40322
  if (nextLocation && nextParagraph) {
38436
40323
  event.preventDefault();
38437
40324
  event.stopPropagation();
38438
- paragraphDraftsRef.current.delete(nodeIndex);
40325
+ editingIntentContinuationRef.current = void 0;
38439
40326
  const caretClientPoint = collapsedCaretClientPointWithinElement(event.currentTarget);
38440
40327
  const fallbackOffset = paragraphText(nextParagraph).length;
38441
40328
  if (caretClientPoint && focusParagraphLocationAtClientPoint(
@@ -38470,7 +40357,7 @@ function DocxEditorViewer({
38470
40357
  if (previousLocation && previousParagraph) {
38471
40358
  event.preventDefault();
38472
40359
  event.stopPropagation();
38473
- paragraphDraftsRef.current.delete(nodeIndex);
40360
+ editingIntentContinuationRef.current = void 0;
38474
40361
  const collapsedRange = editor.deleteExpandedSelection({
38475
40362
  start: {
38476
40363
  location: cloneTextRangeLocation(previousLocation),
@@ -38496,7 +40383,7 @@ function DocxEditorViewer({
38496
40383
  if (nextLocation && nextParagraph) {
38497
40384
  event.preventDefault();
38498
40385
  event.stopPropagation();
38499
- paragraphDraftsRef.current.delete(nodeIndex);
40386
+ editingIntentContinuationRef.current = void 0;
38500
40387
  const collapsedRange = editor.deleteExpandedSelection({
38501
40388
  start: {
38502
40389
  location: cloneTextRangeLocation(currentLocation),
@@ -38533,7 +40420,7 @@ function DocxEditorViewer({
38533
40420
  if (handledBackspace) {
38534
40421
  event.preventDefault();
38535
40422
  event.stopPropagation();
38536
- paragraphDraftsRef.current.delete(nodeIndex);
40423
+ editingIntentContinuationRef.current = void 0;
38537
40424
  focusParagraphAtOffset(nodeIndex, 0);
38538
40425
  return;
38539
40426
  }
@@ -38557,7 +40444,7 @@ function DocxEditorViewer({
38557
40444
  start
38558
40445
  )}
38559
40446
  ${currentText.slice(end)}`;
38560
- paragraphDraftsRef.current.delete(nodeIndex);
40447
+ editingIntentContinuationRef.current = void 0;
38561
40448
  editor.commitParagraphText(nodeIndex, nextText);
38562
40449
  focusParagraphAtOffset(nodeIndex, start + 1);
38563
40450
  return;
@@ -38569,7 +40456,7 @@ ${currentText.slice(end)}`;
38569
40456
  currentText
38570
40457
  );
38571
40458
  if (listDepthChanged) {
38572
- paragraphDraftsRef.current.delete(nodeIndex);
40459
+ editingIntentContinuationRef.current = void 0;
38573
40460
  const targetOffset = selectionOffsets?.end ?? currentText.length;
38574
40461
  focusParagraphAtOffset(nodeIndex, targetOffset);
38575
40462
  }
@@ -38580,7 +40467,7 @@ ${currentText.slice(end)}`;
38580
40467
  event.stopPropagation();
38581
40468
  const start = selectionOffsets?.start ?? currentText.length;
38582
40469
  const end = selectionOffsets?.end ?? start;
38583
- paragraphDraftsRef.current.clear();
40470
+ editingIntentContinuationRef.current = void 0;
38584
40471
  tableCellDraftsRef.current.clear();
38585
40472
  tableCellParagraphDraftsRef.current.clear();
38586
40473
  const insertedListItem = editor.insertListItemAfterSelection(
@@ -38614,7 +40501,7 @@ ${currentText.slice(end)}`;
38614
40501
  start,
38615
40502
  Math.min(selectionOffsets?.end ?? start, currentText.length)
38616
40503
  );
38617
- paragraphDraftsRef.current.clear();
40504
+ editingIntentContinuationRef.current = void 0;
38618
40505
  tableCellDraftsRef.current.clear();
38619
40506
  tableCellParagraphDraftsRef.current.clear();
38620
40507
  const splitParagraph = editor.splitParagraphAtSelection(
@@ -38639,14 +40526,16 @@ ${currentText.slice(end)}`;
38639
40526
  if (!editable) {
38640
40527
  return;
38641
40528
  }
38642
- if (!paragraphDraftsRef.current.has(nodeIndex)) {
38643
- return;
40529
+ if (compositionActiveRef.current) {
40530
+ compositionActiveRef.current = false;
40531
+ const composedText = editableTextFromElement(
40532
+ event.currentTarget
40533
+ );
40534
+ if (composedText !== paragraphText(node)) {
40535
+ editor.suppressNextDomSelectionRestore();
40536
+ editor.commitParagraphText(nodeIndex, composedText);
40537
+ }
38644
40538
  }
38645
- commitParagraphDraftFromElement(
38646
- nodeIndex,
38647
- node,
38648
- event.currentTarget
38649
- );
38650
40539
  },
38651
40540
  children: !editable ? renderedInteractiveParagraphContent : null
38652
40541
  },
@@ -38656,7 +40545,19 @@ ${currentText.slice(end)}`;
38656
40545
  const tableRowSliceOffsetPxForWrapper = tableRowSlice ? Math.max(0, Math.round(tableRowSlice.startOffsetPx)) : 0;
38657
40546
  const tableRowSliceTopBleedPxForWrapper = tableRowSlice && tableRowSliceOffsetPxForWrapper > 0 ? TABLE_ROW_SLICE_VISUAL_BLEED_PX : 0;
38658
40547
  const tableRowSliceBottomBleedPxForWrapper = tableRowSlice ? TABLE_ROW_SLICE_VISUAL_BLEED_PX : 0;
38659
- return /* @__PURE__ */ jsx(
40548
+ const floatingTablePageLayout = options?.pageLayout ?? documentLayout;
40549
+ const floatingTableGeometry = node.style?.floating && !tableRowRange && !tableRowSlice ? resolveFloatingTableGeometry(node, nodeContentWidthPx, {
40550
+ tableWidthPx: estimateFloatingTableWidthPx(
40551
+ node,
40552
+ nodeContentWidthPx
40553
+ ),
40554
+ tableHeightPx: 0,
40555
+ indentPx: twipsToSignedPixels(node.style?.indentTwips) ?? 0,
40556
+ flowTopPx: options?.pageFlowTopPx ?? 0,
40557
+ pageMarginTopPx: floatingTablePageLayout.marginsPx.top,
40558
+ pageMarginLeftPx: floatingTablePageLayout.marginsPx.left
40559
+ }) : void 0;
40560
+ const renderedTableBlock = /* @__PURE__ */ jsx(
38660
40561
  "div",
38661
40562
  {
38662
40563
  ref: (element) => {
@@ -38671,10 +40572,21 @@ ${currentText.slice(end)}`;
38671
40572
  }
38672
40573
  },
38673
40574
  style: {
38674
- ...tableWrapperStyle(
40575
+ ...floatingTableGeometry ? {
40576
+ position: "absolute",
40577
+ left: floatingTableGeometry.leftPx,
40578
+ top: floatingTableGeometry.topPx,
40579
+ maxWidth: nodeContentWidthPx,
40580
+ zIndex: 2
40581
+ } : tableWrapperStyle(
38675
40582
  node,
38676
40583
  twipsToSignedPixels(node.style?.indentTwips) ?? 0
38677
40584
  ),
40585
+ ...tableFloatingDragPreview?.tableIndex === nodeIndex ? {
40586
+ transform: `translate(${tableFloatingDragPreview.deltaX}px, ${tableFloatingDragPreview.deltaY}px)`,
40587
+ zIndex: 30,
40588
+ opacity: 0.9
40589
+ } : void 0,
38678
40590
  ...tableRowSlice ? {
38679
40591
  height: Math.max(
38680
40592
  MIN_PARAGRAPH_LINE_HEIGHT_PX,
@@ -38782,7 +40694,7 @@ ${currentText.slice(end)}`;
38782
40694
  const normalizedRowHeightsPx = rowHeightsPx.map(
38783
40695
  (value) => Number.isFinite(value) && value > 0 ? Math.max(24, value) : 24
38784
40696
  );
38785
- const measuredRowHeightsPx = tableMeasuredRowHeights[nodeIndex];
40697
+ const measuredRowHeightsPx = node.blockId ? tableMeasuredRowHeights[node.blockId]?.rowHeightsPx : void 0;
38786
40698
  const rowBoundarySourceHeightsPx = measuredRowHeightsPx && measuredRowHeightsPx.length === node.rows.length ? measuredRowHeightsPx.map(
38787
40699
  (value) => Number.isFinite(value) && value > 0 ? Math.max(24, value) : 24
38788
40700
  ) : normalizedRowHeightsPx;
@@ -39010,6 +40922,9 @@ ${currentText.slice(end)}`;
39010
40922
  } : void 0;
39011
40923
  const cellDraftKey = `${nodeIndex}:${rowIndex}:${cellIndex}`;
39012
40924
  const cellElementKey = `cell-${nodeIndex}-${rowIndex}-${cellIndex}`;
40925
+ const cellUsesLegacyDraftEditing = cell.nodes.some(
40926
+ (cellContent) => cellContent.type === "table"
40927
+ );
39013
40928
  const colSpanValue = cell.style?.gridSpan && cell.style.gridSpan > 1 ? cell.style.gridSpan : 1;
39014
40929
  const rowSpanValue = cell.style?.rowSpan && cell.style.rowSpan > 1 ? cell.style.rowSpan : 1;
39015
40930
  const colSpan = colSpanValue > 1 ? colSpanValue : void 0;
@@ -39518,9 +41433,11 @@ ${currentText.slice(end)}`;
39518
41433
  overflowWrap: "break-word",
39519
41434
  wordBreak: "break-word"
39520
41435
  },
39521
- dangerouslySetInnerHTML: renderedEditableCellHtml ? {
39522
- __html: renderedEditableCellHtml
39523
- } : void 0,
41436
+ dangerouslySetInnerHTML: renderedEditableCellHtml ? stableInnerHtmlProp(
41437
+ editableTableCellHtmlPropsRef.current,
41438
+ cellDraftKey,
41439
+ renderedEditableCellHtml
41440
+ ) : void 0,
39524
41441
  ref: (element) => {
39525
41442
  if (element) {
39526
41443
  tableCellEditorElementsRef.current.set(
@@ -39538,10 +41455,10 @@ ${currentText.slice(end)}`;
39538
41455
  const draft = tableCellDraftsRef.current.get(
39539
41456
  cellDraftKey
39540
41457
  );
39541
- if (typeof draft === "string") {
41458
+ if (!compositionActiveRef.current && typeof draft === "string") {
39542
41459
  const draftHtml = draft;
39543
41460
  scheduleDomWrite(() => {
39544
- if (!element.isConnected) {
41461
+ if (!element.isConnected || compositionActiveRef.current) {
39545
41462
  return;
39546
41463
  }
39547
41464
  const latestDraft = tableCellDraftsRef.current.get(
@@ -39663,28 +41580,6 @@ ${currentText.slice(end)}`;
39663
41580
  boundary,
39664
41581
  boundary
39665
41582
  );
39666
- const verifyBoundaryRestore = (attempt) => {
39667
- window.requestAnimationFrame(() => {
39668
- if (!element.isConnected) {
39669
- return;
39670
- }
39671
- const selection = window.getSelection();
39672
- const range = selection && selection.rangeCount > 0 ? selection.getRangeAt(0) : null;
39673
- const degenerate = !range || selection?.isCollapsed === true && range.startContainer === element && range.startOffset === 0;
39674
- if (degenerate) {
39675
- setSelectionFromDocxBoundaries(
39676
- boundary,
39677
- boundary
39678
- );
39679
- }
39680
- if (attempt < 6) {
39681
- verifyBoundaryRestore(
39682
- attempt + 1
39683
- );
39684
- }
39685
- });
39686
- };
39687
- verifyBoundaryRestore(0);
39688
41583
  } else if (paragraphElement) {
39689
41584
  placeCaretInsideElement(
39690
41585
  paragraphElement,
@@ -39710,24 +41605,130 @@ ${currentText.slice(end)}`;
39710
41605
  },
39711
41606
  onInput: (event) => {
39712
41607
  cancelPendingPointerSelectionReconcile();
41608
+ const nativeInputEvent = event.nativeEvent;
41609
+ if (nativeInputEvent?.isComposing || compositionActiveRef.current) {
41610
+ editor.beginSelectionSession(
41611
+ "composition"
41612
+ );
41613
+ return;
41614
+ }
41615
+ if (cellUsesLegacyDraftEditing) {
41616
+ editor.beginSelectionSession("keyboard", {
41617
+ settleAfterMs: 220
41618
+ });
41619
+ schedulePaginationMeasurementResume();
41620
+ tableCellDraftsRef.current.set(
41621
+ cellDraftKey,
41622
+ event.currentTarget.innerHTML
41623
+ );
41624
+ requestTableDraftLayoutRefresh();
41625
+ return;
41626
+ }
41627
+ const context = activeTableCellParagraphContext(
41628
+ event.currentTarget
41629
+ );
41630
+ const contextParagraph = context ? cellParagraphs[context.paragraphIndex] : void 0;
41631
+ if (!context || !contextParagraph) {
41632
+ return;
41633
+ }
41634
+ const domText = editableTextFromElement(
41635
+ context.paragraphElement
41636
+ );
41637
+ if (domText === paragraphText(contextParagraph)) {
41638
+ return;
41639
+ }
41640
+ const continuationKey = `c:${nodeIndex}:${rowIndex}:${cellIndex}:${context.paragraphIndex}`;
41641
+ const continuation = editingIntentContinuationRef.current;
41642
+ if (continuation && continuation.key === continuationKey && continuation.text !== domText) {
41643
+ return;
41644
+ }
39713
41645
  editor.beginSelectionSession("keyboard", {
39714
41646
  settleAfterMs: 220
39715
41647
  });
39716
41648
  schedulePaginationMeasurementResume();
39717
- tableCellDraftsRef.current.set(
39718
- cellDraftKey,
39719
- event.currentTarget.innerHTML
41649
+ const typedOffsets = selectionOffsetsWithinElement(
41650
+ context.paragraphElement
39720
41651
  );
39721
- requestTableDraftLayoutRefresh();
41652
+ const caretOffset = typedOffsets?.end ?? domText.length;
41653
+ editor.commitParagraphTextAtRange(
41654
+ {
41655
+ kind: "table-cell",
41656
+ tableIndex: nodeIndex,
41657
+ rowIndex,
41658
+ cellIndex,
41659
+ paragraphIndex: context.paragraphIndex
41660
+ },
41661
+ domText,
41662
+ {
41663
+ start: typedOffsets?.start ?? caretOffset,
41664
+ end: caretOffset
41665
+ }
41666
+ );
41667
+ editingIntentContinuationRef.current = {
41668
+ key: continuationKey,
41669
+ text: domText,
41670
+ caret: caretOffset
41671
+ };
39722
41672
  },
39723
41673
  onCompositionStart: () => {
39724
41674
  cancelPendingPointerSelectionReconcile();
41675
+ compositionActiveRef.current = true;
39725
41676
  editor.beginSelectionSession("composition");
39726
41677
  },
39727
- onCompositionEnd: () => {
41678
+ onCompositionEnd: (event) => {
41679
+ compositionActiveRef.current = false;
39728
41680
  editor.beginSelectionSession("keyboard", {
39729
41681
  settleAfterMs: 260
39730
41682
  });
41683
+ schedulePaginationMeasurementResume();
41684
+ if (cellUsesLegacyDraftEditing) {
41685
+ tableCellDraftsRef.current.set(
41686
+ cellDraftKey,
41687
+ event.currentTarget.innerHTML
41688
+ );
41689
+ requestTableDraftLayoutRefresh();
41690
+ return;
41691
+ }
41692
+ const context = activeTableCellParagraphContext(
41693
+ event.currentTarget
41694
+ );
41695
+ if (context && cellParagraphs[context.paragraphIndex]) {
41696
+ const composedText = editableTextFromElement(
41697
+ context.paragraphElement
41698
+ );
41699
+ const composedOffsets = selectionOffsetsWithinElement(
41700
+ context.paragraphElement
41701
+ );
41702
+ const caretEnd = composedOffsets?.end ?? composedText.length;
41703
+ editor.commitParagraphTextAtRange(
41704
+ {
41705
+ kind: "table-cell",
41706
+ tableIndex: nodeIndex,
41707
+ rowIndex,
41708
+ cellIndex,
41709
+ paragraphIndex: context.paragraphIndex
41710
+ },
41711
+ composedText,
41712
+ {
41713
+ start: composedOffsets?.start ?? caretEnd,
41714
+ end: caretEnd
41715
+ }
41716
+ );
41717
+ editingIntentContinuationRef.current = {
41718
+ key: `c:${nodeIndex}:${rowIndex}:${cellIndex}:${context.paragraphIndex}`,
41719
+ text: composedText,
41720
+ caret: caretEnd
41721
+ };
41722
+ return;
41723
+ }
41724
+ editor.commitTableCellText(
41725
+ nodeIndex,
41726
+ rowIndex,
41727
+ cellIndex,
41728
+ editableTextFromTableCellElement(
41729
+ event.currentTarget
41730
+ )
41731
+ );
39731
41732
  },
39732
41733
  onClick: (event) => {
39733
41734
  if (eventTargetIsInteractiveControl(
@@ -39902,6 +41903,12 @@ ${currentText.slice(end)}`;
39902
41903
  },
39903
41904
  onKeyDown: (event) => {
39904
41905
  cancelPendingPointerSelectionReconcile();
41906
+ if (isCompositionKeyboardEvent(event)) {
41907
+ editor.beginSelectionSession(
41908
+ "composition"
41909
+ );
41910
+ return;
41911
+ }
39905
41912
  editor.beginSelectionSession("keyboard", {
39906
41913
  settleAfterMs: 220
39907
41914
  });
@@ -39914,6 +41921,9 @@ ${currentText.slice(end)}`;
39914
41921
  return;
39915
41922
  }
39916
41923
  const handledHistoryShortcut = handleEditorHistoryShortcut(event, () => {
41924
+ if (!cellUsesLegacyDraftEditing) {
41925
+ return;
41926
+ }
39917
41927
  commitTableCellDraftFromElement(
39918
41928
  nodeIndex,
39919
41929
  rowIndex,
@@ -39993,6 +42003,7 @@ ${currentText.slice(end)}`;
39993
42003
  start
39994
42004
  )}
39995
42005
  ${currentText.slice(end)}`;
42006
+ editingIntentContinuationRef.current = void 0;
39996
42007
  tableCellDraftsRef.current.delete(
39997
42008
  cellDraftKey
39998
42009
  );
@@ -40037,6 +42048,7 @@ ${currentText.slice(end)}`;
40037
42048
  if (handledBackspace) {
40038
42049
  event.preventDefault();
40039
42050
  event.stopPropagation();
42051
+ editingIntentContinuationRef.current = void 0;
40040
42052
  tableCellDraftsRef.current.delete(
40041
42053
  cellDraftKey
40042
42054
  );
@@ -40055,6 +42067,7 @@ ${currentText.slice(end)}`;
40055
42067
  currentText
40056
42068
  );
40057
42069
  if (listDepthChanged) {
42070
+ editingIntentContinuationRef.current = void 0;
40058
42071
  tableCellDraftsRef.current.delete(
40059
42072
  cellDraftKey
40060
42073
  );
@@ -40068,6 +42081,31 @@ ${currentText.slice(end)}`;
40068
42081
  }
40069
42082
  },
40070
42083
  onBlur: (event) => {
42084
+ if (!cellUsesLegacyDraftEditing) {
42085
+ if (compositionActiveRef.current) {
42086
+ compositionActiveRef.current = false;
42087
+ const composedText = editableTextFromTableCellElement(
42088
+ event.currentTarget
42089
+ );
42090
+ if (composedText !== tableCellText(cellParagraphs)) {
42091
+ editor.suppressNextDomSelectionRestore();
42092
+ editor.commitTableCellText(
42093
+ nodeIndex,
42094
+ rowIndex,
42095
+ cellIndex,
42096
+ composedText
42097
+ );
42098
+ }
42099
+ }
42100
+ return;
42101
+ }
42102
+ if (compositionActiveRef.current) {
42103
+ compositionActiveRef.current = false;
42104
+ tableCellDraftsRef.current.set(
42105
+ cellDraftKey,
42106
+ event.currentTarget.innerHTML
42107
+ );
42108
+ }
40071
42109
  if (!tableCellDraftsRef.current.has(
40072
42110
  cellDraftKey
40073
42111
  )) {
@@ -40475,6 +42513,18 @@ ${currentText.slice(end)}`;
40475
42513
  Math.round(tableRowSlice.sliceHeightPx)
40476
42514
  )}` : ""}` : `node-${nodeIndex}`
40477
42515
  );
42516
+ if (floatingTableGeometry) {
42517
+ return /* @__PURE__ */ jsx(
42518
+ "div",
42519
+ {
42520
+ "data-docx-floating-table-host": "true",
42521
+ style: { height: 0, position: "relative", overflow: "visible" },
42522
+ children: renderedTableBlock
42523
+ },
42524
+ `floating-table-host-${nodeIndex}`
42525
+ );
42526
+ }
42527
+ return renderedTableBlock;
40478
42528
  };
40479
42529
  const renderNodeSegments = React.useCallback(
40480
42530
  (nodeSegments, options) => {
@@ -40491,7 +42541,8 @@ ${currentText.slice(end)}`;
40491
42541
  resolvedPageLayout,
40492
42542
  {
40493
42543
  floatingMovePreview,
40494
- resizePreview
42544
+ resizePreview,
42545
+ measuredWrapBands
40495
42546
  }
40496
42547
  );
40497
42548
  for (let offset = 0; offset < nodeSegments.length; offset += 1) {
@@ -41144,6 +43195,8 @@ ${currentText.slice(end)}`;
41144
43195
  continue;
41145
43196
  }
41146
43197
  }
43198
+ const segmentParagraphLineRange = segment.paragraphLineRange;
43199
+ const measuredSegmentFlowTopPx = node.type === "paragraph" && (!segmentParagraphLineRange || segmentParagraphLineRange.startLineIndex === 0 && segmentParagraphLineRange.endLineIndex >= segmentParagraphLineRange.totalLineCount) ? measuredWrapBands.get(`para:${nodeIndex}`)?.topPx : void 0;
41147
43200
  rendered.push(
41148
43201
  renderDocumentNode(
41149
43202
  node,
@@ -41153,7 +43206,7 @@ ${currentText.slice(end)}`;
41153
43206
  segment.paragraphLineRange,
41154
43207
  {
41155
43208
  pageLayout: options?.pageLayout,
41156
- pageFlowTopPx,
43209
+ pageFlowTopPx: measuredSegmentFlowTopPx ?? pageFlowTopPx,
41157
43210
  pageFlowForeignExclusions: foreignWrapExclusionsBySegmentIndex[offset],
41158
43211
  suppressLikelyFullPageCoverImageKeys: options?.suppressLikelyFullPageCoverImageKeys
41159
43212
  }
@@ -41185,6 +43238,7 @@ ${currentText.slice(end)}`;
41185
43238
  focusDropCapWrappedParagraph,
41186
43239
  hoveredDropCapNodeIndex,
41187
43240
  isReadOnly,
43241
+ measuredWrapBands,
41188
43242
  pageContentWidthPxByNodeIndex,
41189
43243
  renderDocumentNode,
41190
43244
  resizePreview,
@@ -45260,6 +47314,7 @@ export {
45260
47314
  DEFAULT_PAGE_OVERFLOW_TOLERANCE_PX,
45261
47315
  DocxEditorViewer,
45262
47316
  ReactDocxViewer,
47317
+ allocateBlockId,
45263
47318
  applyRunStyle,
45264
47319
  buildDocModel,
45265
47320
  buildDocModelFromBytes,
@@ -45267,15 +47322,20 @@ export {
45267
47322
  buildDocumentPageRanges,
45268
47323
  buildLayoutSnapshot,
45269
47324
  cloneDocModel,
47325
+ cloneParagraphNode,
47326
+ cloneTableNode,
45270
47327
  collectDocxEstimatedOverflowBreakStartNodeIndexes,
45271
47328
  collectDocxHardPageBreakStartNodeIndexes2 as collectDocxHardPageBreakStartNodeIndexes,
45272
47329
  collectDocxLastRenderedPageBreakStartNodeIndexes,
47330
+ collectDuplicateDocModelBlockIds,
45273
47331
  collectTableExplicitPageBreakInfo2 as collectTableExplicitPageBreakInfo,
45274
47332
  collectTopLevelExplicitPageBreakStartNodeIndexes2 as collectTopLevelExplicitPageBreakStartNodeIndexes,
45275
47333
  copyParagraphs,
45276
47334
  createMinimalDocxPackage,
47335
+ deepFreezeDocModel,
45277
47336
  defaultStarterModel,
45278
47337
  duplicateParagraph,
47338
+ ensureDocModelBlockIds,
45279
47339
  getPart,
45280
47340
  initWasm2 as initWasm,
45281
47341
  insertParagraph,