@extend-ai/react-docx 0.7.5 → 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.cjs CHANGED
@@ -821,6 +821,102 @@ var init_types = __esm({
821
821
  }
822
822
  });
823
823
 
824
+ // ../doc-model/src/block-id.ts
825
+ function allocateBlockId() {
826
+ const value = nextBlockIdValue;
827
+ nextBlockIdValue += 1;
828
+ return `b${value}`;
829
+ }
830
+ function ensureNodeBlockIds(node) {
831
+ if (!node.blockId) {
832
+ node.blockId = allocateBlockId();
833
+ }
834
+ if (node.type !== "table") {
835
+ return;
836
+ }
837
+ for (const row of node.rows) {
838
+ for (const cell of row.cells) {
839
+ for (const child of cell.nodes) {
840
+ ensureNodeBlockIds(child);
841
+ }
842
+ }
843
+ }
844
+ }
845
+ function ensureDocModelBlockIds(model) {
846
+ model.nodes.forEach(ensureNodeBlockIds);
847
+ for (const section of model.metadata.headerSections ?? []) {
848
+ section.nodes.forEach(ensureNodeBlockIds);
849
+ }
850
+ for (const section of model.metadata.footerSections ?? []) {
851
+ section.nodes.forEach(ensureNodeBlockIds);
852
+ }
853
+ for (const section of model.metadata.sections ?? []) {
854
+ for (const headerSection of section.headerSections ?? []) {
855
+ headerSection.nodes.forEach(ensureNodeBlockIds);
856
+ }
857
+ for (const footerSection of section.footerSections ?? []) {
858
+ footerSection.nodes.forEach(ensureNodeBlockIds);
859
+ }
860
+ }
861
+ for (const note of model.metadata.footnotes ?? []) {
862
+ note.nodes?.forEach(ensureNodeBlockIds);
863
+ }
864
+ for (const note of model.metadata.endnotes ?? []) {
865
+ note.nodes?.forEach(ensureNodeBlockIds);
866
+ }
867
+ return model;
868
+ }
869
+ function collectNodeBlockIds(node, seen, duplicates) {
870
+ if (node.blockId) {
871
+ if (seen.has(node.blockId)) {
872
+ duplicates.add(node.blockId);
873
+ }
874
+ seen.add(node.blockId);
875
+ }
876
+ if (node.type !== "table") {
877
+ return;
878
+ }
879
+ for (const row of node.rows) {
880
+ for (const cell of row.cells) {
881
+ for (const child of cell.nodes) {
882
+ collectNodeBlockIds(child, seen, duplicates);
883
+ }
884
+ }
885
+ }
886
+ }
887
+ function collectDuplicateDocModelBlockIds(model) {
888
+ const duplicates = /* @__PURE__ */ new Set();
889
+ const visitContainer = (nodes) => {
890
+ if (!nodes) {
891
+ return;
892
+ }
893
+ const seen = /* @__PURE__ */ new Set();
894
+ nodes.forEach((node) => collectNodeBlockIds(node, seen, duplicates));
895
+ };
896
+ visitContainer(model.nodes);
897
+ for (const section of model.metadata.headerSections ?? []) {
898
+ visitContainer(section.nodes);
899
+ }
900
+ for (const section of model.metadata.footerSections ?? []) {
901
+ visitContainer(section.nodes);
902
+ }
903
+ for (const note of model.metadata.footnotes ?? []) {
904
+ visitContainer(note.nodes);
905
+ }
906
+ for (const note of model.metadata.endnotes ?? []) {
907
+ visitContainer(note.nodes);
908
+ }
909
+ return Array.from(duplicates);
910
+ }
911
+ var nextBlockIdValue;
912
+ var init_block_id = __esm({
913
+ "../doc-model/src/block-id.ts"() {
914
+ "use strict";
915
+ init_cjs_shims();
916
+ nextBlockIdValue = 1;
917
+ }
918
+ });
919
+
824
920
  // ../doc-model/src/clone.ts
825
921
  function isParagraphCellContent(node) {
826
922
  return node.type === "paragraph";
@@ -879,9 +975,16 @@ function cloneParagraphStyle(style) {
879
975
  } : void 0
880
976
  };
881
977
  }
978
+ function cloneParagraphNode(paragraph) {
979
+ return cloneParagraph(paragraph);
980
+ }
981
+ function cloneTableNode(table) {
982
+ return cloneTable(table);
983
+ }
882
984
  function cloneParagraph(paragraph) {
883
985
  return {
884
986
  type: "paragraph",
987
+ blockId: paragraph.blockId,
885
988
  style: cloneParagraphStyle(paragraph.style),
886
989
  paragraphMarkDeleted: paragraph.paragraphMarkDeleted,
887
990
  sourceXml: paragraph.sourceXml,
@@ -1011,6 +1114,7 @@ function cloneTableFloatingStyle(floating) {
1011
1114
  function cloneTable(table) {
1012
1115
  return {
1013
1116
  type: "table",
1117
+ blockId: table.blockId,
1014
1118
  sourceXml: table.sourceXml,
1015
1119
  style: table.style ? {
1016
1120
  widthTwips: table.style.widthTwips,
@@ -1131,12 +1235,51 @@ var init_clone = __esm({
1131
1235
  }
1132
1236
  });
1133
1237
 
1238
+ // ../doc-model/src/freeze.ts
1239
+ function deepFreezeValue(value) {
1240
+ if (typeof value !== "object" || value === null) {
1241
+ return;
1242
+ }
1243
+ if (ArrayBuffer.isView(value) || value instanceof ArrayBuffer) {
1244
+ return;
1245
+ }
1246
+ if (Object.isFrozen(value)) {
1247
+ return;
1248
+ }
1249
+ Object.freeze(value);
1250
+ if (Array.isArray(value)) {
1251
+ for (const entry of value) {
1252
+ deepFreezeValue(entry);
1253
+ }
1254
+ return;
1255
+ }
1256
+ for (const key of Object.keys(value)) {
1257
+ deepFreezeValue(value[key]);
1258
+ }
1259
+ }
1260
+ function deepFreezeDocModel(model) {
1261
+ deepFreezeValue(model);
1262
+ return model;
1263
+ }
1264
+ var init_freeze = __esm({
1265
+ "../doc-model/src/freeze.ts"() {
1266
+ "use strict";
1267
+ init_cjs_shims();
1268
+ }
1269
+ });
1270
+
1134
1271
  // ../doc-model/src/index.ts
1135
1272
  var src_exports2 = {};
1136
1273
  __export(src_exports2, {
1274
+ allocateBlockId: () => allocateBlockId,
1137
1275
  buildDocModel: () => buildDocModel,
1138
1276
  buildDocModelFromBytes: () => buildDocModelFromBytes,
1139
1277
  cloneDocModel: () => cloneDocModel,
1278
+ cloneParagraphNode: () => cloneParagraphNode,
1279
+ cloneTableNode: () => cloneTableNode,
1280
+ collectDuplicateDocModelBlockIds: () => collectDuplicateDocModelBlockIds,
1281
+ deepFreezeDocModel: () => deepFreezeDocModel,
1282
+ ensureDocModelBlockIds: () => ensureDocModelBlockIds,
1140
1283
  normalizeDocModel: () => normalizeDocModel
1141
1284
  });
1142
1285
  async function buildDocModel(pkg) {
@@ -1162,7 +1305,9 @@ var init_src3 = __esm({
1162
1305
  init_src();
1163
1306
  init_normalize();
1164
1307
  init_types();
1308
+ init_block_id();
1165
1309
  init_clone();
1310
+ init_freeze();
1166
1311
  init_normalize();
1167
1312
  }
1168
1313
  });
@@ -1174,6 +1319,7 @@ __export(index_exports, {
1174
1319
  DEFAULT_PAGE_OVERFLOW_TOLERANCE_PX: () => DEFAULT_PAGE_OVERFLOW_TOLERANCE_PX,
1175
1320
  DocxEditorViewer: () => DocxEditorViewer,
1176
1321
  ReactDocxViewer: () => ReactDocxViewer,
1322
+ allocateBlockId: () => allocateBlockId,
1177
1323
  applyRunStyle: () => applyRunStyle,
1178
1324
  buildDocModel: () => buildDocModel,
1179
1325
  buildDocModelFromBytes: () => buildDocModelFromBytes,
@@ -1181,15 +1327,20 @@ __export(index_exports, {
1181
1327
  buildDocumentPageRanges: () => buildDocumentPageRanges,
1182
1328
  buildLayoutSnapshot: () => buildLayoutSnapshot,
1183
1329
  cloneDocModel: () => cloneDocModel,
1330
+ cloneParagraphNode: () => cloneParagraphNode,
1331
+ cloneTableNode: () => cloneTableNode,
1184
1332
  collectDocxEstimatedOverflowBreakStartNodeIndexes: () => collectDocxEstimatedOverflowBreakStartNodeIndexes,
1185
1333
  collectDocxHardPageBreakStartNodeIndexes: () => collectDocxHardPageBreakStartNodeIndexes2,
1186
1334
  collectDocxLastRenderedPageBreakStartNodeIndexes: () => collectDocxLastRenderedPageBreakStartNodeIndexes,
1335
+ collectDuplicateDocModelBlockIds: () => collectDuplicateDocModelBlockIds,
1187
1336
  collectTableExplicitPageBreakInfo: () => collectTableExplicitPageBreakInfo2,
1188
1337
  collectTopLevelExplicitPageBreakStartNodeIndexes: () => collectTopLevelExplicitPageBreakStartNodeIndexes2,
1189
1338
  copyParagraphs: () => copyParagraphs,
1190
1339
  createMinimalDocxPackage: () => createMinimalDocxPackage,
1340
+ deepFreezeDocModel: () => deepFreezeDocModel,
1191
1341
  defaultStarterModel: () => defaultStarterModel,
1192
1342
  duplicateParagraph: () => duplicateParagraph,
1343
+ ensureDocModelBlockIds: () => ensureDocModelBlockIds,
1193
1344
  getPart: () => getPart,
1194
1345
  initWasm: () => initWasm2,
1195
1346
  insertParagraph: () => insertParagraph,
@@ -1570,7 +1721,7 @@ async function importDocxOnMainThread(buffer, signal) {
1570
1721
  throw createAbortError();
1571
1722
  }
1572
1723
  const startedAt = performanceNow();
1573
- const [{ parseDocx: parseDocx2 }, { buildDocModel: buildDocModel2 }] = await Promise.all([
1724
+ const [{ parseDocx: parseDocx2 }, { buildDocModel: buildDocModel2, ensureDocModelBlockIds: ensureDocModelBlockIds2 }] = await Promise.all([
1574
1725
  Promise.resolve().then(() => (init_src2(), src_exports)),
1575
1726
  Promise.resolve().then(() => (init_src3(), src_exports2))
1576
1727
  ]);
@@ -1579,7 +1730,7 @@ async function importDocxOnMainThread(buffer, signal) {
1579
1730
  if (signal?.aborted) {
1580
1731
  throw createAbortError();
1581
1732
  }
1582
- const model = await buildDocModel2(pkg);
1733
+ const model = ensureDocModelBlockIds2(await buildDocModel2(pkg));
1583
1734
  const finishedAt = performanceNow();
1584
1735
  if (signal?.aborted) {
1585
1736
  throw createAbortError();
@@ -1613,7 +1764,7 @@ async function importDocxBuffer(buffer, options = {}) {
1613
1764
  }
1614
1765
  const requestId = nextImportWorkerRequestId;
1615
1766
  nextImportWorkerRequestId += 1;
1616
- return new Promise((resolve, reject) => {
1767
+ const workerResult = new Promise((resolve, reject) => {
1617
1768
  let settled = false;
1618
1769
  const cleanup = () => {
1619
1770
  worker.removeEventListener("message", handleMessage);
@@ -1677,6 +1828,10 @@ async function importDocxBuffer(buffer, options = {}) {
1677
1828
  );
1678
1829
  }
1679
1830
  });
1831
+ const result = await workerResult;
1832
+ const { ensureDocModelBlockIds: ensureDocModelBlockIds2 } = await Promise.resolve().then(() => (init_src3(), src_exports2));
1833
+ ensureDocModelBlockIds2(result.model);
1834
+ return result;
1680
1835
  }
1681
1836
 
1682
1837
  // src/section-layout.ts
@@ -2074,6 +2229,7 @@ init_src3();
2074
2229
  function paragraphFromText(text, options) {
2075
2230
  return {
2076
2231
  type: "paragraph",
2232
+ blockId: allocateBlockId(),
2077
2233
  style: options?.paragraphStyle,
2078
2234
  children: [{ type: "text", text, style: options?.runStyle }]
2079
2235
  };
@@ -2659,6 +2815,7 @@ function splitParagraphChildrenAtTextOffsets(paragraph, text, startOffset, endOf
2659
2815
  function cloneParagraph2(paragraph) {
2660
2816
  return {
2661
2817
  type: "paragraph",
2818
+ blockId: allocateBlockId(),
2662
2819
  style: paragraph.style ? { ...paragraph.style } : void 0,
2663
2820
  sourceXml: paragraph.sourceXml,
2664
2821
  children: paragraph.children.map(cloneParagraphChildRun)
@@ -2692,26 +2849,31 @@ function duplicateParagraph(model, index) {
2692
2849
  return next;
2693
2850
  }
2694
2851
  function updateParagraphText(model, index, text, options) {
2695
- const next = cloneDocModel(model);
2696
- const paragraph = getParagraph(next, index);
2697
- if (!paragraph) {
2698
- return next;
2852
+ const source = getParagraph(model, index);
2853
+ if (!source) {
2854
+ return { ...model, nodes: [...model.nodes] };
2699
2855
  }
2700
- paragraph.children = distributeTextAcrossParagraphChildren(paragraph, text, options);
2856
+ const paragraph = cloneParagraphNode(source);
2857
+ paragraph.children = distributeTextAcrossParagraphChildren(source, text, options);
2701
2858
  paragraph.sourceXml = void 0;
2702
- return next;
2859
+ const nextNodes = [...model.nodes];
2860
+ nextNodes[index] = paragraph;
2861
+ return { ...model, nodes: nextNodes };
2703
2862
  }
2704
2863
  function updateTableCellText(model, tableIndex, rowIndex, cellIndex, text, options) {
2705
- const next = cloneDocModel(model);
2706
- const tableNode = next.nodes[tableIndex];
2707
- if (!tableNode || tableNode.type !== "table") {
2708
- return next;
2864
+ const sourceTable = model.nodes[tableIndex];
2865
+ if (!sourceTable || sourceTable.type !== "table") {
2866
+ return { ...model, nodes: [...model.nodes] };
2709
2867
  }
2868
+ const tableNode = cloneTableNode(sourceTable);
2710
2869
  const row = tableNode.rows[rowIndex];
2711
2870
  const cell = row?.cells[cellIndex];
2712
2871
  if (!cell) {
2713
- return next;
2872
+ return { ...model, nodes: [...model.nodes] };
2714
2873
  }
2874
+ const nextNodes = [...model.nodes];
2875
+ nextNodes[tableIndex] = tableNode;
2876
+ const next = { ...model, nodes: nextNodes };
2715
2877
  const paragraphs = cell.nodes.filter((node) => node.type === "paragraph");
2716
2878
  const incomingParagraphTexts = text.replace(/\r\n/g, "\n").replace(/\r/g, "\n").split("\n");
2717
2879
  if (incomingParagraphTexts.length === 0) {
@@ -2740,21 +2902,23 @@ function updateTableCellText(model, tableIndex, rowIndex, cellIndex, text, optio
2740
2902
  return next;
2741
2903
  }
2742
2904
  function updateTableCellParagraphText(model, tableIndex, rowIndex, cellIndex, paragraphIndex, text, options) {
2743
- const next = cloneDocModel(model);
2744
- const tableNode = next.nodes[tableIndex];
2745
- if (!tableNode || tableNode.type !== "table") {
2746
- return next;
2905
+ const sourceTable = model.nodes[tableIndex];
2906
+ if (!sourceTable || sourceTable.type !== "table") {
2907
+ return { ...model, nodes: [...model.nodes] };
2747
2908
  }
2909
+ const tableNode = cloneTableNode(sourceTable);
2748
2910
  const row = tableNode.rows[rowIndex];
2749
2911
  const cell = row?.cells[cellIndex];
2750
2912
  const paragraph = cell?.nodes.filter((node) => node.type === "paragraph")[paragraphIndex];
2751
2913
  if (!cell || !paragraph) {
2752
- return next;
2914
+ return { ...model, nodes: [...model.nodes] };
2753
2915
  }
2754
2916
  paragraph.children = distributeTextAcrossParagraphChildren(paragraph, text, options);
2755
2917
  paragraph.sourceXml = void 0;
2756
2918
  tableNode.sourceXml = void 0;
2757
- return next;
2919
+ const nextNodes = [...model.nodes];
2920
+ nextNodes[tableIndex] = tableNode;
2921
+ return { ...model, nodes: nextNodes };
2758
2922
  }
2759
2923
  function updateTableCellParagraphTextRecursive(model, tableIndex, rowIndex, cellIndex, paragraphIndex, text, options) {
2760
2924
  const next = cloneDocModel(model);
@@ -3074,6 +3238,222 @@ async function serializeDocx(model, basePackage) {
3074
3238
  return wasmSerializeDocx(model, basePackage ? mapsToWasmPackage(basePackage) : void 0);
3075
3239
  }
3076
3240
 
3241
+ // src/editing-intents.ts
3242
+ init_cjs_shims();
3243
+ function resolveEditingIntent(source) {
3244
+ const insertedText = source.data ?? source.dataTransferText ?? "";
3245
+ const transferredText = source.dataTransferText ?? source.data ?? "";
3246
+ switch (source.inputType) {
3247
+ case "insertCompositionText":
3248
+ case "deleteCompositionText":
3249
+ return void 0;
3250
+ case "insertText":
3251
+ case "insertFromYank":
3252
+ case "insertFromPasteAsQuotation":
3253
+ return { kind: "insertText", text: insertedText };
3254
+ case "insertFromPaste":
3255
+ case "insertFromDrop":
3256
+ return { kind: "insertText", text: transferredText };
3257
+ case "insertReplacementText":
3258
+ case "insertTranspose":
3259
+ return { kind: "replaceText", text: insertedText };
3260
+ case "insertParagraph":
3261
+ return { kind: "insertParagraph" };
3262
+ case "insertLineBreak":
3263
+ return { kind: "insertLineBreak" };
3264
+ case "deleteContentBackward":
3265
+ return { kind: "deleteContent", direction: "backward", unit: "character" };
3266
+ case "deleteContentForward":
3267
+ return { kind: "deleteContent", direction: "forward", unit: "character" };
3268
+ case "deleteWordBackward":
3269
+ return { kind: "deleteContent", direction: "backward", unit: "word" };
3270
+ case "deleteWordForward":
3271
+ return { kind: "deleteContent", direction: "forward", unit: "word" };
3272
+ case "deleteSoftLineBackward":
3273
+ case "deleteHardLineBackward":
3274
+ return { kind: "deleteContent", direction: "backward", unit: "line" };
3275
+ case "deleteSoftLineForward":
3276
+ case "deleteHardLineForward":
3277
+ return { kind: "deleteContent", direction: "forward", unit: "line" };
3278
+ case "deleteEntireSoftLine":
3279
+ return {
3280
+ kind: "deleteContent",
3281
+ direction: "backward",
3282
+ unit: "entire-line"
3283
+ };
3284
+ case "deleteContent":
3285
+ case "deleteByCut":
3286
+ case "deleteByDrag":
3287
+ return { kind: "deleteRange" };
3288
+ case "historyUndo":
3289
+ return { kind: "historyUndo" };
3290
+ case "historyRedo":
3291
+ return { kind: "historyRedo" };
3292
+ default:
3293
+ return { kind: "blocked" };
3294
+ }
3295
+ }
3296
+ function editingIntentCoalesceClass(intent) {
3297
+ switch (intent.kind) {
3298
+ case "insertText":
3299
+ case "insertLineBreak":
3300
+ case "replaceText":
3301
+ return "insert";
3302
+ case "deleteContent":
3303
+ case "deleteRange":
3304
+ return "delete";
3305
+ default:
3306
+ return void 0;
3307
+ }
3308
+ }
3309
+ function isWhitespaceChar(char) {
3310
+ return /\s/.test(char);
3311
+ }
3312
+ function codePointLengthBefore(text, offset) {
3313
+ if (offset >= 2) {
3314
+ const codePoint = text.codePointAt(offset - 2);
3315
+ if (codePoint !== void 0 && codePoint > 65535) {
3316
+ return 2;
3317
+ }
3318
+ }
3319
+ return offset > 0 ? 1 : 0;
3320
+ }
3321
+ function codePointLengthAt(text, offset) {
3322
+ if (offset >= text.length) {
3323
+ return 0;
3324
+ }
3325
+ const codePoint = text.codePointAt(offset);
3326
+ return codePoint !== void 0 && codePoint > 65535 ? 2 : 1;
3327
+ }
3328
+ function wordDeleteStartBefore(text, offset) {
3329
+ let index = offset;
3330
+ while (index > 0 && isWhitespaceChar(text[index - 1])) {
3331
+ index -= 1;
3332
+ }
3333
+ while (index > 0 && !isWhitespaceChar(text[index - 1])) {
3334
+ index -= 1;
3335
+ }
3336
+ return index;
3337
+ }
3338
+ function wordDeleteEndAfter(text, offset) {
3339
+ let index = offset;
3340
+ while (index < text.length && isWhitespaceChar(text[index])) {
3341
+ index += 1;
3342
+ }
3343
+ while (index < text.length && !isWhitespaceChar(text[index])) {
3344
+ index += 1;
3345
+ }
3346
+ return index;
3347
+ }
3348
+ function lineStartBefore(text, offset) {
3349
+ const newlineIndex = text.lastIndexOf("\n", Math.max(0, offset - 1));
3350
+ return newlineIndex < 0 ? 0 : newlineIndex + 1;
3351
+ }
3352
+ function lineEndAfter(text, offset) {
3353
+ const newlineIndex = text.indexOf("\n", offset);
3354
+ if (newlineIndex < 0) {
3355
+ return text.length;
3356
+ }
3357
+ return newlineIndex === offset ? offset + 1 : newlineIndex;
3358
+ }
3359
+ function replaceRange(text, start, end, replacement) {
3360
+ return {
3361
+ text: `${text.slice(0, start)}${replacement}${text.slice(end)}`,
3362
+ caret: start + replacement.length
3363
+ };
3364
+ }
3365
+ function applyTextEditingIntent(text, selectionStart, selectionEnd, intent) {
3366
+ const start = Math.max(0, Math.min(Math.round(selectionStart), text.length));
3367
+ const end = Math.max(
3368
+ start,
3369
+ Math.min(Math.round(selectionEnd), text.length)
3370
+ );
3371
+ switch (intent.kind) {
3372
+ case "insertText":
3373
+ case "replaceText": {
3374
+ const replacement = intent.text.replace(/\r\n?/g, "\n");
3375
+ if (replacement.length === 0 && start === end) {
3376
+ return void 0;
3377
+ }
3378
+ return replaceRange(text, start, end, replacement);
3379
+ }
3380
+ case "insertLineBreak":
3381
+ return replaceRange(text, start, end, "\n");
3382
+ case "deleteRange":
3383
+ if (start === end) {
3384
+ return void 0;
3385
+ }
3386
+ return replaceRange(text, start, end, "");
3387
+ case "deleteContent": {
3388
+ if (start !== end) {
3389
+ return replaceRange(text, start, end, "");
3390
+ }
3391
+ if (intent.direction === "backward") {
3392
+ if (intent.unit === "entire-line") {
3393
+ const lineStart = lineStartBefore(text, start);
3394
+ const newlineIndex = text.indexOf("\n", start);
3395
+ const lineEnd = newlineIndex < 0 ? text.length : newlineIndex;
3396
+ if (lineStart === lineEnd) {
3397
+ return void 0;
3398
+ }
3399
+ return replaceRange(text, lineStart, lineEnd, "");
3400
+ }
3401
+ if (start === 0) {
3402
+ return void 0;
3403
+ }
3404
+ const deleteFrom = intent.unit === "character" ? start - codePointLengthBefore(text, start) : intent.unit === "word" ? wordDeleteStartBefore(text, start) : lineStartBefore(text, start);
3405
+ if (deleteFrom >= start) {
3406
+ return void 0;
3407
+ }
3408
+ return replaceRange(text, deleteFrom, start, "");
3409
+ }
3410
+ if (start >= text.length) {
3411
+ return void 0;
3412
+ }
3413
+ const deleteTo = intent.unit === "character" ? start + codePointLengthAt(text, start) : intent.unit === "word" ? wordDeleteEndAfter(text, start) : lineEndAfter(text, start);
3414
+ if (deleteTo <= start) {
3415
+ return void 0;
3416
+ }
3417
+ return replaceRange(text, start, deleteTo, "");
3418
+ }
3419
+ default:
3420
+ return void 0;
3421
+ }
3422
+ }
3423
+ function shouldCoalesceTextCommit(previous, next, windowMs = 1e3) {
3424
+ return Boolean(
3425
+ previous && previous.key === next.key && next.at >= previous.at && next.at - previous.at <= windowMs && previous.caretAfter === next.caretBefore
3426
+ );
3427
+ }
3428
+ function mergeCellParagraphTexts(paragraphTexts, boundaryParagraphIndex) {
3429
+ if (boundaryParagraphIndex <= 0 || boundaryParagraphIndex >= paragraphTexts.length) {
3430
+ return void 0;
3431
+ }
3432
+ const mergedTexts = [
3433
+ ...paragraphTexts.slice(0, boundaryParagraphIndex - 1),
3434
+ `${paragraphTexts[boundaryParagraphIndex - 1]}${paragraphTexts[boundaryParagraphIndex]}`,
3435
+ ...paragraphTexts.slice(boundaryParagraphIndex + 1)
3436
+ ];
3437
+ const cellText = mergedTexts.join("\n");
3438
+ let caretGlobalOffset = 0;
3439
+ for (let index = 0; index < boundaryParagraphIndex - 1; index += 1) {
3440
+ caretGlobalOffset += paragraphTexts[index].length + 1;
3441
+ }
3442
+ caretGlobalOffset += paragraphTexts[boundaryParagraphIndex - 1].length;
3443
+ const parts = cellText.split("\n");
3444
+ let remaining = caretGlobalOffset;
3445
+ let caretParagraphIndex = 0;
3446
+ while (caretParagraphIndex < parts.length - 1 && remaining > parts[caretParagraphIndex].length) {
3447
+ remaining -= parts[caretParagraphIndex].length + 1;
3448
+ caretParagraphIndex += 1;
3449
+ }
3450
+ return {
3451
+ cellText,
3452
+ caretParagraphIndex,
3453
+ caretOffset: Math.max(0, Math.min(remaining, parts[caretParagraphIndex].length))
3454
+ };
3455
+ }
3456
+
3077
3457
  // src/pagination-breaks.ts
3078
3458
  init_cjs_shims();
3079
3459
  var PAGE_BREAK_XML_PATTERN = /<w:br\b[^>]*w:type="page"[^>]*\/?>/i;
@@ -3286,6 +3666,55 @@ function resolveMeasuredBodyFooterOverlapLatchState(options) {
3286
3666
  shouldLatch: consecutivePasses >= stabilityThreshold
3287
3667
  };
3288
3668
  }
3669
+ function createEstimatedPagesBuildMemo(build) {
3670
+ const entries = [];
3671
+ return (measuredTableRowHeightsByNodeIndex, measuredPageContentHeightsPxByPageIndex, strictLastRenderedParagraphStartBreaks) => {
3672
+ const cached = entries.find(
3673
+ (entry) => entry.measuredTableRowHeightsByNodeIndex === measuredTableRowHeightsByNodeIndex && entry.measuredPageContentHeightsPxByPageIndex === measuredPageContentHeightsPxByPageIndex && entry.strictLastRenderedParagraphStartBreaks === strictLastRenderedParagraphStartBreaks
3674
+ );
3675
+ if (cached) {
3676
+ return cached.pages;
3677
+ }
3678
+ const pages = build(
3679
+ measuredTableRowHeightsByNodeIndex,
3680
+ measuredPageContentHeightsPxByPageIndex,
3681
+ strictLastRenderedParagraphStartBreaks
3682
+ );
3683
+ entries.push({
3684
+ measuredTableRowHeightsByNodeIndex,
3685
+ measuredPageContentHeightsPxByPageIndex,
3686
+ strictLastRenderedParagraphStartBreaks,
3687
+ pages
3688
+ });
3689
+ return pages;
3690
+ };
3691
+ }
3692
+ function resolveMeasuredSplitParagraphPageComparison(options) {
3693
+ if (options.canUndo || options.canRedo || !options.hasMeasuredPageContentHeights) {
3694
+ return {
3695
+ pages: options.measuredEstimatedPages,
3696
+ usedPureEstimatedPages: false
3697
+ };
3698
+ }
3699
+ const measuredPagesAreOnlySplitParagraphs = options.measuredEstimatedPages.length > 0 && options.measuredEstimatedPages.every(
3700
+ options.pageContainsOnlySplitParagraphSegments
3701
+ );
3702
+ if (!measuredPagesAreOnlySplitParagraphs) {
3703
+ return {
3704
+ pages: options.measuredEstimatedPages,
3705
+ usedPureEstimatedPages: false
3706
+ };
3707
+ }
3708
+ const pureEstimatedPages = options.buildPureEstimatedPages();
3709
+ const purePagesAreOnlySplitParagraphs = pureEstimatedPages.length > 0 && pureEstimatedPages.every(options.pageContainsOnlySplitParagraphSegments);
3710
+ if (purePagesAreOnlySplitParagraphs && pureEstimatedPages.length < options.measuredEstimatedPages.length) {
3711
+ return { pages: pureEstimatedPages, usedPureEstimatedPages: true };
3712
+ }
3713
+ return {
3714
+ pages: options.measuredEstimatedPages,
3715
+ usedPureEstimatedPages: false
3716
+ };
3717
+ }
3289
3718
  function isBetterCandidate(candidate, incumbent, targetPageCount) {
3290
3719
  const candidateDifference = Math.abs(candidate.pageCount - targetPageCount);
3291
3720
  const incumbentDifference = Math.abs(incumbent.pageCount - targetPageCount);
@@ -5437,7 +5866,6 @@ var TABLE_ROW_HEIGHT_PAGINATION_ESTIMATE_PADDING_RATIO = 1.08;
5437
5866
  var TABLE_ROW_HEIGHT_PAGINATION_ESTIMATE_PADDING_MIN_ROWS = 15;
5438
5867
  var MIN_TABLE_ROW_SLICE_REMAINING_HEIGHT_PX = MIN_PARAGRAPH_LINE_HEIGHT_PX * 2;
5439
5868
  var TABLE_ROW_SLICE_BOUNDARY_TOLERANCE_PX = 2;
5440
- var TOP_AND_BOTTOM_VERTICAL_DRAG_SNAP_PX = 10;
5441
5869
  var HEADER_FOOTER_INACTIVE_OPACITY = 0.5;
5442
5870
  var LETTERHEAD_INDENT_MIN_TWIPS = 900;
5443
5871
  var LETTERHEAD_INDENT_MAX_TWIPS = 4200;
@@ -5910,7 +6338,7 @@ function reconcileMeasuredTableRowHeightsForImportPagination(table, measuredRowH
5910
6338
  );
5911
6339
  });
5912
6340
  }
5913
- function resolveTableMeasuredRowHeightsForPagination(nodes, tableMeasuredRowHeights, options) {
6341
+ function resolveTableMeasuredRowHeightsForPagination(nodes, tableMeasuredRowHeightsByBlockId, options) {
5914
6342
  const activeTableIndexes = /* @__PURE__ */ new Set();
5915
6343
  (options?.activeDraftKeys ?? []).forEach((draftKey) => {
5916
6344
  const [tableIndexText] = draftKey.split(":");
@@ -5920,37 +6348,114 @@ function resolveTableMeasuredRowHeightsForPagination(nodes, tableMeasuredRowHeig
5920
6348
  }
5921
6349
  });
5922
6350
  const includeOnlyActiveTables = activeTableIndexes.size > 0;
5923
- if (includeOnlyActiveTables === false && options?.allowMeasuredImportPagination !== true) {
6351
+ if (includeOnlyActiveTables === false && options?.allowMeasuredImportPagination !== true && options?.allowContentSignatureValidatedTables !== true) {
5924
6352
  return void 0;
5925
6353
  }
5926
6354
  const next = {};
5927
- Object.entries(tableMeasuredRowHeights).forEach(
5928
- ([tableIndexText, measuredRowHeights]) => {
5929
- const tableIndex = Number.parseInt(tableIndexText, 10);
5930
- const tableNode = nodes[tableIndex];
5931
- if (!Number.isFinite(tableIndex) || !tableNode || tableNode.type !== "table" || !Array.isArray(measuredRowHeights) || measuredRowHeights.length !== tableNode.rows.length) {
5932
- return;
5933
- }
5934
- if (includeOnlyActiveTables && !activeTableIndexes.has(tableIndex)) {
6355
+ nodes.forEach((tableNode, tableIndex) => {
6356
+ if (tableNode.type !== "table" || !tableNode.blockId) {
6357
+ return;
6358
+ }
6359
+ const entry = tableMeasuredRowHeightsByBlockId[tableNode.blockId];
6360
+ if (!entry || !Array.isArray(entry.rowHeightsPx) || entry.rowHeightsPx.length !== tableNode.rows.length) {
6361
+ return;
6362
+ }
6363
+ const measuredRowHeights = entry.rowHeightsPx;
6364
+ if (includeOnlyActiveTables) {
6365
+ if (!activeTableIndexes.has(tableIndex)) {
5935
6366
  return;
5936
6367
  }
5937
- const nextHeights = includeOnlyActiveTables ? measuredRowHeights.map(
5938
- (heightPx) => normalizeMeasuredTableRowHeightPx(heightPx)
5939
- ) : reconcileMeasuredTableRowHeightsForImportPagination(
5940
- tableNode,
5941
- measuredRowHeights,
5942
- options?.pageContentWidthPxByNodeIndex?.get(tableIndex),
5943
- options?.pageContentHeightPxByNodeIndex?.get(tableIndex),
5944
- options?.numberingDefinitions,
5945
- options?.docGridLinePitchPxByNodeIndex?.get(tableIndex)
5946
- ) ?? measuredRowHeights.map(
6368
+ next[tableIndex] = measuredRowHeights.map(
5947
6369
  (heightPx) => normalizeMeasuredTableRowHeightPx(heightPx)
5948
6370
  );
5949
- next[tableIndex] = nextHeights;
6371
+ return;
5950
6372
  }
5951
- );
6373
+ if (options?.allowMeasuredImportPagination !== true && entry.contentSignature !== docNodeContentSignature(tableNode)) {
6374
+ return;
6375
+ }
6376
+ next[tableIndex] = reconcileMeasuredTableRowHeightsForImportPagination(
6377
+ tableNode,
6378
+ measuredRowHeights,
6379
+ options?.pageContentWidthPxByNodeIndex?.get(tableIndex),
6380
+ options?.pageContentHeightPxByNodeIndex?.get(tableIndex),
6381
+ options?.numberingDefinitions,
6382
+ options?.docGridLinePitchPxByNodeIndex?.get(tableIndex)
6383
+ ) ?? measuredRowHeights.map(
6384
+ (heightPx) => normalizeMeasuredTableRowHeightPx(heightPx)
6385
+ );
6386
+ });
5952
6387
  return Object.keys(next).length > 0 ? next : void 0;
5953
6388
  }
6389
+ function buildMeasuredPageContentValidationForPageSegments(pageSegments, nodes, contextSignature) {
6390
+ const blocks = [];
6391
+ let previousNodeIndex;
6392
+ for (const segment of pageSegments) {
6393
+ if (segment.nodeIndex === previousNodeIndex) {
6394
+ continue;
6395
+ }
6396
+ previousNodeIndex = segment.nodeIndex;
6397
+ const node = nodes[segment.nodeIndex];
6398
+ blocks.push({
6399
+ blockId: node?.blockId,
6400
+ contentSignature: node ? docNodeContentSignature(node) : ""
6401
+ });
6402
+ }
6403
+ return { contextSignature, blocks };
6404
+ }
6405
+ function measuredPageContentValidationsEqual(left, right) {
6406
+ if (left === right) {
6407
+ return true;
6408
+ }
6409
+ if (!left || !right) {
6410
+ return false;
6411
+ }
6412
+ if (left.contextSignature !== right.contextSignature || left.blocks.length !== right.blocks.length) {
6413
+ return false;
6414
+ }
6415
+ for (let index = 0; index < left.blocks.length; index += 1) {
6416
+ if (left.blocks[index].blockId !== right.blocks[index].blockId || left.blocks[index].contentSignature !== right.blocks[index].contentSignature) {
6417
+ return false;
6418
+ }
6419
+ }
6420
+ return true;
6421
+ }
6422
+ function resolveMeasuredPageContentHeightsPxForEditedModel(nodes, measuredPageContentHeightsPxByPageIndex, validationByPageIndex, contextSignature) {
6423
+ let cursor = 0;
6424
+ let previousPageLastBlockId;
6425
+ let validPageCount = 0;
6426
+ for (let pageIndex = 0; pageIndex < measuredPageContentHeightsPxByPageIndex.length; pageIndex += 1) {
6427
+ const validation = validationByPageIndex[pageIndex];
6428
+ if (!validation || validation.contextSignature !== contextSignature || validation.blocks.length === 0) {
6429
+ break;
6430
+ }
6431
+ let pageIsValid = true;
6432
+ for (let blockIndex = 0; blockIndex < validation.blocks.length; blockIndex += 1) {
6433
+ const block = validation.blocks[blockIndex];
6434
+ if (!block.blockId) {
6435
+ pageIsValid = false;
6436
+ break;
6437
+ }
6438
+ if (blockIndex === 0 && block.blockId === previousPageLastBlockId) {
6439
+ continue;
6440
+ }
6441
+ const node = nodes[cursor];
6442
+ if (!node || node.blockId !== block.blockId || docNodeContentSignature(node) !== block.contentSignature) {
6443
+ pageIsValid = false;
6444
+ break;
6445
+ }
6446
+ cursor += 1;
6447
+ }
6448
+ if (!pageIsValid) {
6449
+ break;
6450
+ }
6451
+ previousPageLastBlockId = validation.blocks[validation.blocks.length - 1]?.blockId;
6452
+ validPageCount += 1;
6453
+ }
6454
+ if (validPageCount === 0) {
6455
+ return void 0;
6456
+ }
6457
+ return validPageCount >= measuredPageContentHeightsPxByPageIndex.length ? measuredPageContentHeightsPxByPageIndex : measuredPageContentHeightsPxByPageIndex.slice(0, validPageCount);
6458
+ }
5954
6459
  function placeCaretInsideElementDom(element) {
5955
6460
  const selection = window.getSelection();
5956
6461
  if (!selection) {
@@ -5995,6 +6500,34 @@ function selectionOffsetsWithinElementDom(element) {
5995
6500
  return void 0;
5996
6501
  }
5997
6502
  }
6503
+ function staticRangeOffsetsWithinElementDom(element, staticRange) {
6504
+ if (!element.contains(staticRange.startContainer) || !element.contains(staticRange.endContainer)) {
6505
+ return void 0;
6506
+ }
6507
+ try {
6508
+ const textLengthWithoutNumberingLabels = (range) => {
6509
+ const fragment = range.cloneContents();
6510
+ fragment.querySelectorAll("[data-docx-numbering-label='true']").forEach((label) => {
6511
+ label.remove();
6512
+ });
6513
+ return fragment.textContent?.length ?? 0;
6514
+ };
6515
+ const startRange = document.createRange();
6516
+ startRange.setStart(element, 0);
6517
+ startRange.setEnd(staticRange.startContainer, staticRange.startOffset);
6518
+ const endRange = document.createRange();
6519
+ endRange.setStart(element, 0);
6520
+ endRange.setEnd(staticRange.endContainer, staticRange.endOffset);
6521
+ const startOffset = textLengthWithoutNumberingLabels(startRange);
6522
+ const endOffset = textLengthWithoutNumberingLabels(endRange);
6523
+ return {
6524
+ start: Math.min(startOffset, endOffset),
6525
+ end: Math.max(startOffset, endOffset)
6526
+ };
6527
+ } catch {
6528
+ return void 0;
6529
+ }
6530
+ }
5998
6531
  function setSelectionWithinElementByTextOffsetsDom(element, startOffset, endOffset) {
5999
6532
  const selection = window.getSelection();
6000
6533
  if (!selection) {
@@ -7448,8 +7981,11 @@ var defaultStarterModel = {
7448
7981
  defaultParagraphStyleId: "Normal"
7449
7982
  }
7450
7983
  };
7984
+ function cloneDocModelWithBlockIds(model) {
7985
+ return ensureDocModelBlockIds(cloneDocModel(model));
7986
+ }
7451
7987
  function createBlankDocumentModel() {
7452
- return cloneDocModel(defaultStarterModel);
7988
+ return cloneDocModelWithBlockIds(defaultStarterModel);
7453
7989
  }
7454
7990
  function textRuns2(paragraph) {
7455
7991
  return paragraph.children.filter(
@@ -8115,6 +8651,8 @@ function paragraphLooksLikeCheckboxChoiceRow(paragraph) {
8115
8651
  }
8116
8652
  var KEEP_ALL_SCRIPT_RE = /[\p{Script=Han}\p{Script=Hiragana}\p{Script=Katakana}\p{Script=Hangul}]/u;
8117
8653
  var MIN_DUAL_WRAPPED_INTERIOR_BAND_PX = 72;
8654
+ var WRAP_BAND_RECONCILE_TOLERANCE_PX = 2;
8655
+ var WRAP_BAND_RECONCILE_MAX_PASSES = 24;
8118
8656
  function resolveDualWrapParagraphRenderBlockHeightPx(layout, geometries) {
8119
8657
  const fullHeightPx = wrappedPretextParagraphBlockHeightPx(layout);
8120
8658
  const textBottomPx = pretextLayoutContentBottomPx(layout);
@@ -8131,10 +8669,27 @@ function resolveDualWrapParagraphRenderBlockHeightPx(layout, geometries) {
8131
8669
  }
8132
8670
  return fullHeightPx;
8133
8671
  }
8672
+ function resolveDragPreviewAwareWrapBlockHeightPx(layout, geometries, foreignExclusions) {
8673
+ const baseHeightPx = resolveDualWrapParagraphRenderBlockHeightPx(
8674
+ layout,
8675
+ geometries
8676
+ );
8677
+ if (!foreignExclusions?.some((exclusion) => exclusion.fromDragPreview)) {
8678
+ return baseHeightPx;
8679
+ }
8680
+ const lineHeightPx = Math.max(1, Math.round(layout.lineHeightPx ?? 1));
8681
+ const staticBottomPx = Math.max(
8682
+ lineHeightPx,
8683
+ pretextLayoutContentBottomPx(layout),
8684
+ ...geometries.map((geometry) => geometry.exclusion.bottom),
8685
+ ...foreignExclusions.filter((exclusion) => !exclusion.fromDragPreview).map((exclusion) => exclusion.bottom)
8686
+ );
8687
+ return Math.min(baseHeightPx, Math.max(1, Math.round(staticBottomPx)));
8688
+ }
8134
8689
  function resolveForeignWrapExclusionsForFlowRange(obstacles, sourceNodeIndex, pageFlowTopPx, pageFlowBottomPx) {
8135
8690
  const foreignExclusions = [];
8136
8691
  for (const obstacle of obstacles) {
8137
- if (obstacle.sourceNodeIndex === sourceNodeIndex) {
8692
+ if (obstacle.sourceNodeIndex === sourceNodeIndex && !obstacle.appliesToSourceNode) {
8138
8693
  continue;
8139
8694
  }
8140
8695
  if (obstacle.bottom <= pageFlowTopPx || obstacle.top >= pageFlowBottomPx) {
@@ -8190,7 +8745,8 @@ function collectPageFlowWrapObstaclesForParagraph(paragraph, nodeIndex, pageFlow
8190
8745
  paragraphTopPx: options?.paragraphTopPx,
8191
8746
  pageMarginTopPx: options?.pageMarginTopPx,
8192
8747
  movePreviewByImageIndex,
8193
- allowNegativeImageTop: movePreviewByImageIndex.size > 0
8748
+ allowNegativeImageTop: movePreviewByImageIndex.size > 0,
8749
+ foreignExclusions: options?.foreignExclusions
8194
8750
  }
8195
8751
  );
8196
8752
  const coveredImageIndexes = /* @__PURE__ */ new Set();
@@ -8268,18 +8824,28 @@ function resolveParagraphForeignOnlyWrappedTextLayout(paragraph, containerWidthP
8268
8824
  };
8269
8825
  }
8270
8826
  function precomputePageSegmentForeignWrapExclusions(segments, model, availableWidthPx, numberingDefinitions, docGridLinePitchPxByNodeIndex, pageContentWidthPxByNodeIndex, pageLayout, interaction) {
8271
- const flowTopPxBySegmentIndex = [];
8272
- const flowHeightPxBySegmentIndex = [];
8273
- let pageFlowTopPx = 0;
8274
- for (const segment of segments) {
8275
- flowTopPxBySegmentIndex.push(pageFlowTopPx);
8827
+ const segmentWidthPxAt = (nodeIndex) => pageContentWidthPxByNodeIndex.get(nodeIndex) ?? availableWidthPx;
8828
+ const measuredWrapBands = interaction?.measuredWrapBands;
8829
+ const measuredBandAt = (key) => {
8830
+ const band = measuredWrapBands?.get(key);
8831
+ return band && band.bottomPx > band.topPx && band.rightPx > band.leftPx ? band : void 0;
8832
+ };
8833
+ const flowTopsFromHeights = (heights) => {
8834
+ const flowTops = [];
8835
+ let pageFlowTopPx = 0;
8836
+ for (const heightPx of heights) {
8837
+ flowTops.push(pageFlowTopPx);
8838
+ pageFlowTopPx += heightPx;
8839
+ }
8840
+ return flowTops;
8841
+ };
8842
+ const baseFlowHeightPxBySegmentIndex = segments.map((segment) => {
8276
8843
  const node = model.nodes[segment.nodeIndex];
8277
- const segmentWidthPx = pageContentWidthPxByNodeIndex.get(segment.nodeIndex) ?? availableWidthPx;
8278
- const segmentHeightPx = estimateRenderedPageSegmentHeightPx(
8844
+ return estimateRenderedPageSegmentHeightPx(
8279
8845
  node,
8280
8846
  segment,
8281
8847
  model,
8282
- segmentWidthPx,
8848
+ segmentWidthPxAt(segment.nodeIndex),
8283
8849
  numberingDefinitions,
8284
8850
  docGridLinePitchPxByNodeIndex.get(segment.nodeIndex),
8285
8851
  // For the wrap-exclusion flow simulation, a square/tight-wrapped float
@@ -8289,54 +8855,313 @@ function precomputePageSegmentForeignWrapExclusions(segments, model, availableWi
8289
8855
  // the float's exclusion rect to overlap and indent them.
8290
8856
  { excludeWrappedFloatingImageFootprint: true }
8291
8857
  );
8292
- flowHeightPxBySegmentIndex.push(segmentHeightPx);
8293
- pageFlowTopPx += segmentHeightPx;
8294
- }
8295
- const obstacles = [];
8296
- for (let segmentIndex = 0; segmentIndex < segments.length; segmentIndex += 1) {
8297
- const segment = segments[segmentIndex];
8298
- const node = model.nodes[segment.nodeIndex];
8299
- if (node?.type !== "paragraph") {
8300
- continue;
8301
- }
8302
- const segmentWidthPx = pageContentWidthPxByNodeIndex.get(segment.nodeIndex) ?? availableWidthPx;
8303
- const paragraphRenderTextWidthPx = paragraphAvailableTextWidthPx(
8304
- node,
8305
- segmentWidthPx,
8306
- numberingDefinitions
8307
- );
8308
- obstacles.push(
8309
- ...collectPageFlowWrapObstaclesForParagraph(
8858
+ });
8859
+ const collectObstacles = (flowTopPxBySegmentIndex2, flowHeightPxBySegmentIndex2, previousObstacles) => {
8860
+ const obstacles2 = [];
8861
+ for (let segmentIndex = 0; segmentIndex < segments.length; segmentIndex += 1) {
8862
+ const segment = segments[segmentIndex];
8863
+ const node = model.nodes[segment.nodeIndex];
8864
+ if (node?.type === "table" && node.style?.floating && !segment.tableRowRange) {
8865
+ const tableContainerWidthPx = segmentWidthPxAt(segment.nodeIndex);
8866
+ const tableFlowTopPx = flowTopPxBySegmentIndex2[segmentIndex] ?? 0;
8867
+ const measuredTableBand = measuredBandAt(`tbl:${segment.nodeIndex}`);
8868
+ if (measuredTableBand) {
8869
+ const floating = node.style.floating;
8870
+ const distLPx = twipsToPixels(floating.leftFromTextTwips) ?? 0;
8871
+ const distRPx = twipsToPixels(floating.rightFromTextTwips) ?? 0;
8872
+ const distTPx = twipsToPixels(floating.topFromTextTwips) ?? 0;
8873
+ const distBPx = twipsToPixels(floating.bottomFromTextTwips) ?? 0;
8874
+ let exclusionLeftPx = Math.max(0, measuredTableBand.leftPx - distLPx);
8875
+ let exclusionRightPx = Math.min(
8876
+ tableContainerWidthPx,
8877
+ measuredTableBand.rightPx + distRPx
8878
+ );
8879
+ if (exclusionLeftPx > 0 && exclusionLeftPx < MIN_DUAL_WRAPPED_INTERIOR_BAND_PX) {
8880
+ exclusionLeftPx = 0;
8881
+ }
8882
+ if (exclusionRightPx < tableContainerWidthPx && tableContainerWidthPx - exclusionRightPx < MIN_DUAL_WRAPPED_INTERIOR_BAND_PX) {
8883
+ exclusionRightPx = tableContainerWidthPx;
8884
+ }
8885
+ obstacles2.push({
8886
+ sourceNodeIndex: segment.nodeIndex,
8887
+ left: exclusionLeftPx,
8888
+ right: exclusionRightPx,
8889
+ top: measuredTableBand.topPx - distTPx,
8890
+ bottom: measuredTableBand.bottomPx + distBPx
8891
+ });
8892
+ continue;
8893
+ }
8894
+ const geometry = resolveFloatingTableGeometry(
8895
+ node,
8896
+ tableContainerWidthPx,
8897
+ {
8898
+ tableWidthPx: estimateFloatingTableWidthPx(
8899
+ node,
8900
+ tableContainerWidthPx
8901
+ ),
8902
+ tableHeightPx: estimateTableHeightPx(
8903
+ node,
8904
+ tableContainerWidthPx,
8905
+ numberingDefinitions,
8906
+ docGridLinePitchPxByNodeIndex.get(segment.nodeIndex)
8907
+ ),
8908
+ indentPx: twipsToSignedPixels(node.style?.indentTwips) ?? 0,
8909
+ flowTopPx: tableFlowTopPx,
8910
+ pageMarginTopPx: pageLayout.marginsPx.top,
8911
+ pageMarginLeftPx: pageLayout.marginsPx.left
8912
+ }
8913
+ );
8914
+ if (geometry) {
8915
+ obstacles2.push({
8916
+ sourceNodeIndex: segment.nodeIndex,
8917
+ left: geometry.exclusion.left,
8918
+ right: geometry.exclusion.right,
8919
+ top: tableFlowTopPx + geometry.exclusion.top,
8920
+ bottom: tableFlowTopPx + geometry.exclusion.bottom
8921
+ });
8922
+ }
8923
+ continue;
8924
+ }
8925
+ if (node?.type !== "paragraph") {
8926
+ continue;
8927
+ }
8928
+ const paragraphRenderTextWidthPx = paragraphAvailableTextWidthPx(
8310
8929
  node,
8311
- segment.nodeIndex,
8312
- flowTopPxBySegmentIndex[segmentIndex] ?? 0,
8313
- paragraphRenderTextWidthPx,
8314
- estimateParagraphLineHeightPx(
8930
+ segmentWidthPxAt(segment.nodeIndex),
8931
+ numberingDefinitions
8932
+ );
8933
+ node.children.forEach((child, childIndex) => {
8934
+ if (child.type !== "image" || !child.floating?.wrapType || child.floating.wrapType === "none" || child.floating.behindDocument === true || shouldRenderWrappedFloatingImage(child)) {
8935
+ return;
8936
+ }
8937
+ const band = measuredBandAt(
8938
+ `img:p:${segment.nodeIndex}:${childIndex}`
8939
+ );
8940
+ if (!band) {
8941
+ return;
8942
+ }
8943
+ const floating = child.floating;
8944
+ const containerWidthPx = segmentWidthPxAt(segment.nodeIndex);
8945
+ const fullWidthWrap = floating.wrapType === "topAndBottom";
8946
+ let exclusionLeftPx = fullWidthWrap ? 0 : Math.max(0, band.leftPx - (floating.distLPx ?? 0));
8947
+ let exclusionRightPx = fullWidthWrap ? containerWidthPx : Math.min(containerWidthPx, band.rightPx + (floating.distRPx ?? 0));
8948
+ if (exclusionLeftPx > 0 && exclusionLeftPx < MIN_DUAL_WRAPPED_INTERIOR_BAND_PX) {
8949
+ exclusionLeftPx = 0;
8950
+ }
8951
+ if (exclusionRightPx < containerWidthPx && containerWidthPx - exclusionRightPx < MIN_DUAL_WRAPPED_INTERIOR_BAND_PX) {
8952
+ exclusionRightPx = containerWidthPx;
8953
+ }
8954
+ if (exclusionRightPx <= exclusionLeftPx) {
8955
+ return;
8956
+ }
8957
+ obstacles2.push({
8958
+ sourceNodeIndex: segment.nodeIndex,
8959
+ appliesToSourceNode: true,
8960
+ left: exclusionLeftPx,
8961
+ right: exclusionRightPx,
8962
+ top: band.topPx - (floating.distTPx ?? 0),
8963
+ bottom: band.bottomPx + (floating.distBPx ?? 0)
8964
+ });
8965
+ });
8966
+ const flowTopPx = measuredBandAt(`para:${segment.nodeIndex}`)?.topPx ?? flowTopPxBySegmentIndex2[segmentIndex] ?? 0;
8967
+ obstacles2.push(
8968
+ ...collectPageFlowWrapObstaclesForParagraph(
8315
8969
  node,
8316
- docGridLinePitchPxByNodeIndex.get(segment.nodeIndex)
8317
- ),
8318
- {
8319
- paragraphTopPx: flowTopPxBySegmentIndex[segmentIndex] ?? 0,
8320
- pageMarginTopPx: pageLayout.marginsPx.top,
8321
- location: {
8322
- kind: "paragraph",
8323
- nodeIndex: segment.nodeIndex
8324
- },
8325
- floatingMovePreview: interaction?.floatingMovePreview,
8326
- resizePreview: interaction?.resizePreview
8970
+ segment.nodeIndex,
8971
+ flowTopPx,
8972
+ paragraphRenderTextWidthPx,
8973
+ estimateParagraphLineHeightPx(
8974
+ node,
8975
+ docGridLinePitchPxByNodeIndex.get(segment.nodeIndex)
8976
+ ),
8977
+ {
8978
+ paragraphTopPx: flowTopPx,
8979
+ pageMarginTopPx: pageLayout.marginsPx.top,
8980
+ location: {
8981
+ kind: "paragraph",
8982
+ nodeIndex: segment.nodeIndex
8983
+ },
8984
+ floatingMovePreview: interaction?.floatingMovePreview,
8985
+ resizePreview: interaction?.resizePreview,
8986
+ foreignExclusions: previousObstacles ? resolveForeignWrapExclusionsForFlowRange(
8987
+ previousObstacles,
8988
+ segment.nodeIndex,
8989
+ flowTopPx,
8990
+ flowTopPx + (flowHeightPxBySegmentIndex2[segmentIndex] ?? 0)
8991
+ ) : void 0
8992
+ }
8993
+ )
8994
+ );
8995
+ }
8996
+ return obstacles2;
8997
+ };
8998
+ const baseFlowTopPxBySegmentIndex = flowTopsFromHeights(
8999
+ baseFlowHeightPxBySegmentIndex
9000
+ );
9001
+ const firstPassObstacles = collectObstacles(
9002
+ baseFlowTopPxBySegmentIndex,
9003
+ baseFlowHeightPxBySegmentIndex
9004
+ );
9005
+ let flowTopPxBySegmentIndex = baseFlowTopPxBySegmentIndex;
9006
+ let flowHeightPxBySegmentIndex = baseFlowHeightPxBySegmentIndex;
9007
+ let obstacles = firstPassObstacles;
9008
+ const hasInteractionPreview = Boolean(
9009
+ interaction?.floatingMovePreview || interaction?.resizePreview
9010
+ );
9011
+ const hasFloatingTableObstacle = segments.some((segment) => {
9012
+ const node = model.nodes[segment.nodeIndex];
9013
+ return node?.type === "table" && Boolean(node.style?.floating) && !segment.tableRowRange;
9014
+ });
9015
+ if ((hasInteractionPreview || hasFloatingTableObstacle) && firstPassObstacles.length > 0) {
9016
+ const reflowHeightPxBySegmentIndex = segments.map(
9017
+ (segment, segmentIndex) => {
9018
+ const baseHeightPx = baseFlowHeightPxBySegmentIndex[segmentIndex] ?? 0;
9019
+ const node = model.nodes[segment.nodeIndex];
9020
+ if (node?.type !== "paragraph" || segment.tableRowRange || segment.tableRowSlice || segment.paragraphLineRange) {
9021
+ return baseHeightPx;
9022
+ }
9023
+ if (node.children.some(
9024
+ (child) => child.type === "image" && shouldRenderWrappedFloatingImage(child)
9025
+ )) {
9026
+ return baseHeightPx;
9027
+ }
9028
+ const flowTopPx = baseFlowTopPxBySegmentIndex[segmentIndex] ?? 0;
9029
+ const foreignExclusions = resolveForeignWrapExclusionsForFlowRange(
9030
+ firstPassObstacles,
9031
+ segment.nodeIndex,
9032
+ flowTopPx,
9033
+ flowTopPx + baseHeightPx
9034
+ );
9035
+ if (foreignExclusions.length === 0) {
9036
+ return baseHeightPx;
8327
9037
  }
8328
- )
9038
+ const source = buildParagraphPretextLayoutSource(node);
9039
+ if (!source) {
9040
+ return baseHeightPx;
9041
+ }
9042
+ const textWidthPx = paragraphAvailableTextWidthPx(
9043
+ node,
9044
+ segmentWidthPxAt(segment.nodeIndex),
9045
+ numberingDefinitions
9046
+ );
9047
+ const lineHeightPx = Math.max(
9048
+ 1,
9049
+ Math.round(
9050
+ estimateParagraphLineHeightPx(
9051
+ node,
9052
+ docGridLinePitchPxByNodeIndex.get(segment.nodeIndex)
9053
+ )
9054
+ )
9055
+ );
9056
+ const unexcludedLayout = layoutParagraphPretextSource(
9057
+ node,
9058
+ source,
9059
+ textWidthPx,
9060
+ lineHeightPx,
9061
+ []
9062
+ );
9063
+ const excludedLayout = layoutParagraphPretextSource(
9064
+ node,
9065
+ source,
9066
+ textWidthPx,
9067
+ lineHeightPx,
9068
+ foreignExclusions
9069
+ );
9070
+ if (!unexcludedLayout || !excludedLayout) {
9071
+ return baseHeightPx;
9072
+ }
9073
+ const lineExtentPx = (layout) => layout.lines.length > 0 ? (layout.lines[layout.lines.length - 1]?.y ?? 0) + lineHeightPx : 0;
9074
+ return baseHeightPx + Math.max(
9075
+ 0,
9076
+ lineExtentPx(excludedLayout) - lineExtentPx(unexcludedLayout)
9077
+ );
9078
+ }
9079
+ );
9080
+ flowHeightPxBySegmentIndex = reflowHeightPxBySegmentIndex;
9081
+ flowTopPxBySegmentIndex = flowTopsFromHeights(reflowHeightPxBySegmentIndex);
9082
+ obstacles = collectObstacles(
9083
+ flowTopPxBySegmentIndex,
9084
+ flowHeightPxBySegmentIndex,
9085
+ firstPassObstacles
8329
9086
  );
8330
9087
  }
8331
- const result = segments.map(
8332
- (segment, segmentIndex) => resolveForeignWrapExclusionsForFlowRange(
9088
+ const result = segments.map((segment, segmentIndex) => {
9089
+ const segmentLineRange = segment.paragraphLineRange;
9090
+ const segmentCoversWholeParagraph = !segmentLineRange || segmentLineRange.startLineIndex === 0 && segmentLineRange.endLineIndex >= segmentLineRange.totalLineCount;
9091
+ const measuredParagraphBand = segmentCoversWholeParagraph ? measuredBandAt(`para:${segment.nodeIndex}`) : void 0;
9092
+ const flowTopPx = measuredParagraphBand?.topPx ?? flowTopPxBySegmentIndex[segmentIndex] ?? 0;
9093
+ const flowBottomPx = measuredParagraphBand?.bottomPx ?? flowTopPx + (flowHeightPxBySegmentIndex[segmentIndex] ?? 0);
9094
+ return resolveForeignWrapExclusionsForFlowRange(
8333
9095
  obstacles,
8334
9096
  segment.nodeIndex,
8335
- flowTopPxBySegmentIndex[segmentIndex] ?? 0,
8336
- (flowTopPxBySegmentIndex[segmentIndex] ?? 0) + (flowHeightPxBySegmentIndex[segmentIndex] ?? 0)
8337
- )
9097
+ flowTopPx,
9098
+ flowBottomPx
9099
+ );
9100
+ });
9101
+ const measuredBands = interaction?.floatingMovePreview?.measuredBands;
9102
+ const draggedAnchorNodeIndex = (() => {
9103
+ const key = interaction?.floatingMovePreview?.imageKey;
9104
+ const match = key ? /^p:(\d+):/.exec(key) : null;
9105
+ return match ? Number.parseInt(match[1], 10) : void 0;
9106
+ })();
9107
+ if (!measuredBands || draggedAnchorNodeIndex === void 0) {
9108
+ return result;
9109
+ }
9110
+ const measuredFlowBandAt = (nodeIndex) => {
9111
+ const band = measuredBands.hostByNodeIndex[nodeIndex];
9112
+ if (!band) {
9113
+ return void 0;
9114
+ }
9115
+ return {
9116
+ top: band.topPx - pageLayout.marginsPx.top,
9117
+ bottom: band.bottomPx - pageLayout.marginsPx.top
9118
+ };
9119
+ };
9120
+ const anchorSegmentIndex = segments.findIndex(
9121
+ (segment) => segment.nodeIndex === draggedAnchorNodeIndex
8338
9122
  );
8339
- return result;
9123
+ const anchorMeasuredBand = measuredFlowBandAt(draggedAnchorNodeIndex);
9124
+ if (anchorSegmentIndex < 0 || !anchorMeasuredBand) {
9125
+ return result;
9126
+ }
9127
+ const anchorEstimatedFlowTopPx = flowTopPxBySegmentIndex[anchorSegmentIndex] ?? 0;
9128
+ const draggedObstacles = [];
9129
+ const otherObstacles = [];
9130
+ for (const obstacle of obstacles) {
9131
+ if (obstacle.sourceNodeIndex === draggedAnchorNodeIndex) {
9132
+ draggedObstacles.push({
9133
+ ...obstacle,
9134
+ top: obstacle.top - anchorEstimatedFlowTopPx + anchorMeasuredBand.top,
9135
+ bottom: obstacle.bottom - anchorEstimatedFlowTopPx + anchorMeasuredBand.top
9136
+ });
9137
+ } else {
9138
+ otherObstacles.push(obstacle);
9139
+ }
9140
+ }
9141
+ if (draggedObstacles.length === 0) {
9142
+ return result;
9143
+ }
9144
+ return segments.map((segment, segmentIndex) => {
9145
+ const node = model.nodes[segment.nodeIndex];
9146
+ const measuredBand = measuredFlowBandAt(segment.nodeIndex);
9147
+ if (node?.type !== "paragraph" || segment.nodeIndex === draggedAnchorNodeIndex || !measuredBand) {
9148
+ return result[segmentIndex] ?? [];
9149
+ }
9150
+ return [
9151
+ ...resolveForeignWrapExclusionsForFlowRange(
9152
+ otherObstacles,
9153
+ segment.nodeIndex,
9154
+ flowTopPxBySegmentIndex[segmentIndex] ?? 0,
9155
+ (flowTopPxBySegmentIndex[segmentIndex] ?? 0) + (flowHeightPxBySegmentIndex[segmentIndex] ?? 0)
9156
+ ),
9157
+ ...resolveForeignWrapExclusionsForFlowRange(
9158
+ draggedObstacles,
9159
+ segment.nodeIndex,
9160
+ measuredBand.top,
9161
+ measuredBand.bottom
9162
+ ).map((exclusion) => ({ ...exclusion, fromDragPreview: true }))
9163
+ ];
9164
+ });
8340
9165
  }
8341
9166
  function applyWrappedFloatingInteractionPreviewToParagraph(paragraph, location, paragraphRenderTextWidthPx, options) {
8342
9167
  const hasInteractionPreview = Boolean(
@@ -8955,12 +9780,27 @@ function layoutParagraphPretextSource(paragraph, source, containerWidthPx, lineH
8955
9780
  );
8956
9781
  const wordBreak = pretextWordBreakModeForText(source.text);
8957
9782
  const items = buildParagraphPretextLayoutItems(paragraph, source);
9783
+ const firstLineIndentPx = twipsToSignedPixels(
9784
+ paragraph.style?.indent?.firstLineTwips
9785
+ );
9786
+ const layoutExclusions = Number.isFinite(firstLineIndentPx) && firstLineIndentPx > 0 ? [
9787
+ ...exclusions ?? [],
9788
+ {
9789
+ left: 0,
9790
+ right: Math.min(
9791
+ Math.max(1, Math.round(containerWidthPx)),
9792
+ Math.round(firstLineIndentPx)
9793
+ ),
9794
+ top: 0,
9795
+ bottom: 1
9796
+ }
9797
+ ] : exclusions;
8958
9798
  const richLayout = items.length > 0 ? layoutItemsWithPretextAroundExclusions(
8959
9799
  source.text,
8960
9800
  items,
8961
9801
  containerWidthPx,
8962
9802
  lineHeightPx,
8963
- exclusions,
9803
+ layoutExclusions,
8964
9804
  fallbackFont
8965
9805
  ) : void 0;
8966
9806
  if (richLayout) {
@@ -8971,7 +9811,7 @@ function layoutParagraphPretextSource(paragraph, source, containerWidthPx, lineH
8971
9811
  fallbackFont,
8972
9812
  containerWidthPx,
8973
9813
  lineHeightPx,
8974
- exclusions,
9814
+ layoutExclusions,
8975
9815
  {
8976
9816
  wordBreak
8977
9817
  }
@@ -9098,6 +9938,7 @@ function resolveDualWrappedFloatingImageGeometry(image, containerWidthPx, option
9098
9938
  const rawImageTopPx = (hasExplicitBaseTopPx ? baseTopPx : paragraphLocalBaseTopPx + (isInlinePreview ? 0 : distTPx)) + deltaY;
9099
9939
  const modelAllowsNegativeTop = Number.isFinite(floating?.yPx) && floating?.yPx < 0;
9100
9940
  const imageTopPx = options?.allowNegativeImageTop || modelAllowsNegativeTop ? Math.round(rawImageTopPx) : Math.max(0, Math.round(rawImageTopPx));
9941
+ const horizontalAlignIsOperative = !hasExplicitBaseLeftPx && !Number.isFinite(floating?.xPx);
9101
9942
  let exclusionLeftPx = Math.max(0, imageLeftPx - distLPx);
9102
9943
  let exclusionRightPx = Math.min(
9103
9944
  safeContainerWidthPx,
@@ -9106,9 +9947,9 @@ function resolveDualWrappedFloatingImageGeometry(image, containerWidthPx, option
9106
9947
  if (wrapType === "topAndBottom") {
9107
9948
  exclusionLeftPx = 0;
9108
9949
  exclusionRightPx = safeContainerWidthPx;
9109
- } else if (horizontalAlign === "left" || horizontalAlign === "inside") {
9950
+ } else if (horizontalAlignIsOperative && (horizontalAlign === "left" || horizontalAlign === "inside")) {
9110
9951
  exclusionLeftPx = 0;
9111
- } else if (horizontalAlign === "right" || horizontalAlign === "outside") {
9952
+ } else if (horizontalAlignIsOperative && (horizontalAlign === "right" || horizontalAlign === "outside")) {
9112
9953
  exclusionRightPx = safeContainerWidthPx;
9113
9954
  }
9114
9955
  if (!isInlinePreview && wrapType !== "topAndBottom") {
@@ -12010,6 +12851,9 @@ function estimateRenderedPageSegmentHeightPx(node, segment, model, availableWidt
12010
12851
  )
12011
12852
  );
12012
12853
  }
12854
+ if (node.type === "table" && node.style?.floating) {
12855
+ return 0;
12856
+ }
12013
12857
  return Math.max(
12014
12858
  MIN_PARAGRAPH_LINE_HEIGHT_PX,
12015
12859
  estimateTableHeightPx(
@@ -12338,7 +13182,7 @@ function buildDocumentPageNodeSegments(model, pageContentHeightPx, pageContentWi
12338
13182
  const preferLastRenderedParagraphStartBreaks = options?.preferLastRenderedParagraphStartBreaks ?? false;
12339
13183
  const strictLastRenderedParagraphStartBreaks = options?.strictLastRenderedParagraphStartBreaks ?? false;
12340
13184
  const hardBreakStartNodeIndexes = collectDocxHardPageBreakStartNodeIndexes(model);
12341
- const paginationNumberingLabels = buildParagraphNumberingLabels(model);
13185
+ const paginationNumberingLabels = options?.precomputedNumberingLabels ?? buildParagraphNumberingLabels(model);
12342
13186
  const sectionStartPageBreakNodeIndexes = collectDocxSectionStartPageBreakNodeIndexes(model);
12343
13187
  const nextHardBreakStartNodeIndexByNodeIndex = buildNextHardBreakStartNodeIndexLookup(
12344
13188
  model.nodes.length,
@@ -12910,6 +13754,11 @@ function buildDocumentPageNodeSegments(model, pageContentHeightPx, pageContentWi
12910
13754
  previousParagraphAfterPx = afterSpacingPx;
12911
13755
  continue;
12912
13756
  }
13757
+ if (node.style?.floating) {
13758
+ currentPageSegments.push({ nodeIndex });
13759
+ previousParagraphAfterPx = 0;
13760
+ continue;
13761
+ }
12913
13762
  const measuredRowHeightsPxRaw = options?.measuredTableRowHeightsByNodeIndex?.[nodeIndex];
12914
13763
  const measuredRowHeightsPx = measuredRowHeightsPxRaw && measuredRowHeightsPxRaw.length === node.rows.length ? measuredRowHeightsPxRaw.map(
12915
13764
  (heightPx) => Math.max(
@@ -13444,6 +14293,22 @@ function absoluteFloatingImageStyle(image, options) {
13444
14293
  }
13445
14294
  return style;
13446
14295
  }
14296
+ function normalizeFloatingDragDeltaForZoom(screenDeltaPx, zoomScale) {
14297
+ const safeScale = Number.isFinite(zoomScale) && zoomScale > 0 ? zoomScale : 1;
14298
+ return screenDeltaPx / safeScale;
14299
+ }
14300
+ function normalizeFloatingDropRectForZoom(rect, zoomScale) {
14301
+ const safeScale = Number.isFinite(zoomScale) && zoomScale > 0 ? zoomScale : 1;
14302
+ if (safeScale === 1) {
14303
+ return rect;
14304
+ }
14305
+ return {
14306
+ left: rect.left / safeScale,
14307
+ top: rect.top / safeScale,
14308
+ ...Number.isFinite(rect.width) ? { width: rect.width / safeScale } : void 0,
14309
+ ...Number.isFinite(rect.height) ? { height: rect.height / safeScale } : void 0
14310
+ };
14311
+ }
13447
14312
  function resolveAbsoluteFloatingImageDropPatch(floating, layout, options) {
13448
14313
  const nextLeftPx = options.wrapperRect.left + Math.round(options.deltaX);
13449
14314
  const nextTopPx = options.wrapperRect.top + Math.round(options.deltaY);
@@ -13515,11 +14380,9 @@ function resolveWrappedFloatingImageDropPatch(image, hostWidth, movedLeft, moved
13515
14380
  }
13516
14381
  );
13517
14382
  const previewUsesSideFloat = previewGeometry === void 0 || previewGeometry.exclusion.left <= 0 || previewGeometry.exclusion.right >= hostWidth;
13518
- const rawExplicitTopPx = Math.round(
14383
+ const explicitTopPx = Math.round(
13519
14384
  movedTop - Math.round(baseFloating.distTPx ?? 0)
13520
14385
  );
13521
- const currentTopPx = Math.round(baseFloating.yPx ?? 0);
13522
- const explicitTopPx = wrapType.trim().toLowerCase() === "topandbottom" && Math.abs(rawExplicitTopPx - currentTopPx) < TOP_AND_BOTTOM_VERTICAL_DRAG_SNAP_PX ? currentTopPx : rawExplicitTopPx;
13523
14386
  return {
13524
14387
  wrapType,
13525
14388
  wrapText,
@@ -13535,6 +14398,47 @@ function resolveWrappedFloatingImageDropPatch(image, hostWidth, movedLeft, moved
13535
14398
  behindDocument: false
13536
14399
  };
13537
14400
  }
14401
+ function resolveWrappedDropAnchorParagraphHost(wrapperElement, droppedTopScreenPx, droppedLeftScreenPx) {
14402
+ const viewerRoot = wrapperElement.closest("[data-testid='docx-editor-viewer']") ?? wrapperElement.ownerDocument;
14403
+ if (!viewerRoot) {
14404
+ return void 0;
14405
+ }
14406
+ const hosts = Array.from(
14407
+ viewerRoot.querySelectorAll(
14408
+ "[data-docx-paragraph-host='true'][data-docx-paragraph-kind='paragraph'][data-docx-paragraph-node-index]"
14409
+ )
14410
+ );
14411
+ let best;
14412
+ let bestDistance = Number.POSITIVE_INFINITY;
14413
+ for (const host of hosts) {
14414
+ const nodeIndex = Number.parseInt(
14415
+ host.getAttribute("data-docx-paragraph-node-index") ?? "",
14416
+ 10
14417
+ );
14418
+ if (!Number.isFinite(nodeIndex)) {
14419
+ continue;
14420
+ }
14421
+ const rect = host.getBoundingClientRect();
14422
+ if (rect.width <= 0 && rect.height <= 0) {
14423
+ continue;
14424
+ }
14425
+ const verticalDistance = droppedTopScreenPx < rect.top ? rect.top - droppedTopScreenPx : droppedTopScreenPx >= rect.bottom ? droppedTopScreenPx - rect.bottom : 0;
14426
+ const horizontalDistance = droppedLeftScreenPx < rect.left ? rect.left - droppedLeftScreenPx : droppedLeftScreenPx > rect.right ? droppedLeftScreenPx - rect.right : 0;
14427
+ const distance = verticalDistance * 4 + horizontalDistance;
14428
+ if (distance < bestDistance) {
14429
+ bestDistance = distance;
14430
+ best = { host, nodeIndex, rect };
14431
+ }
14432
+ }
14433
+ return best;
14434
+ }
14435
+ function wrappedDragCanReanchorToParagraph(floating) {
14436
+ if (!floatingImageMovesWithText(floating)) {
14437
+ return true;
14438
+ }
14439
+ const verticalRelativeTo = floating.verticalRelativeTo?.trim().toLowerCase() ?? "";
14440
+ return verticalRelativeTo === "" || verticalRelativeTo === "paragraph" || verticalRelativeTo === "line";
14441
+ }
13538
14442
  function resolvePageSpanningAbsoluteFloatingDimensions(image, widthPx, heightPx, floatingPageOriginPx) {
13539
14443
  const floating = image.floating;
13540
14444
  const pageWidthPx = Number.isFinite(floatingPageOriginPx?.pageWidth) ? Math.max(1, Math.round(floatingPageOriginPx?.pageWidth)) : void 0;
@@ -17498,6 +18402,7 @@ function createEmptyParagraphFromTemplate(template) {
17498
18402
  const nextTextStyle = cloneTextStyle2(firstRunStyle(template));
17499
18403
  return {
17500
18404
  type: "paragraph",
18405
+ blockId: allocateBlockId(),
17501
18406
  style: cloneParagraphStyle2(template?.style),
17502
18407
  children: [
17503
18408
  {
@@ -17648,6 +18553,65 @@ function resolveFloatingTableSide(table) {
17648
18553
  }
17649
18554
  return "left";
17650
18555
  }
18556
+ function estimateFloatingTableWidthPx(table, containerWidthPx) {
18557
+ const explicitWidthPx = twipsToPixels(table.style?.widthTwips);
18558
+ const columnWidthsTwips = table.style?.columnWidthsTwips;
18559
+ const columnsWidthPx = columnWidthsTwips && columnWidthsTwips.length > 0 ? columnWidthsTwips.reduce(
18560
+ (total, widthTwips) => total + (twipsToPixels(widthTwips) ?? 0),
18561
+ 0
18562
+ ) : void 0;
18563
+ return Math.max(
18564
+ 24,
18565
+ Math.min(
18566
+ Math.max(1, Math.round(containerWidthPx)),
18567
+ Math.round(explicitWidthPx ?? columnsWidthPx ?? containerWidthPx)
18568
+ )
18569
+ );
18570
+ }
18571
+ function resolveFloatingTableGeometry(table, containerWidthPx, options) {
18572
+ const floating = table.style?.floating;
18573
+ if (!floating) {
18574
+ return void 0;
18575
+ }
18576
+ const safeContainerWidthPx = Math.max(1, Math.round(containerWidthPx));
18577
+ const tableWidthPx = Math.max(1, Math.round(options.tableWidthPx));
18578
+ const tableHeightPx = Math.max(0, Math.round(options.tableHeightPx));
18579
+ const distLPx = twipsToPixels(floating.leftFromTextTwips) ?? 0;
18580
+ const distRPx = twipsToPixels(floating.rightFromTextTwips) ?? 0;
18581
+ const distTPx = twipsToPixels(floating.topFromTextTwips) ?? 0;
18582
+ const distBPx = twipsToPixels(floating.bottomFromTextTwips) ?? 0;
18583
+ const xPx = twipsToSignedPixels(floating.xTwips);
18584
+ const yPx = twipsToSignedPixels(floating.yTwips);
18585
+ const horizontalAnchor = floating.horizontalAnchor?.trim().toLowerCase();
18586
+ const verticalAnchor = floating.verticalAnchor?.trim().toLowerCase();
18587
+ const horizontalAlign = floating.horizontalAlign?.trim().toLowerCase();
18588
+ const flowTopPx = Math.round(options.flowTopPx ?? 0);
18589
+ const deltaX = Math.round(options.deltaX ?? 0);
18590
+ const deltaY = Math.round(options.deltaY ?? 0);
18591
+ 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;
18592
+ const topPx = (yPx !== void 0 ? verticalAnchor === "margin" ? yPx - flowTopPx : verticalAnchor === "page" ? yPx - Math.round(options.pageMarginTopPx ?? 0) - flowTopPx : yPx : 0) + deltaY;
18593
+ let exclusionLeftPx = Math.max(0, leftPx - distLPx);
18594
+ let exclusionRightPx = Math.min(
18595
+ safeContainerWidthPx,
18596
+ leftPx + tableWidthPx + distRPx
18597
+ );
18598
+ if (exclusionLeftPx > 0 && exclusionLeftPx < MIN_DUAL_WRAPPED_INTERIOR_BAND_PX) {
18599
+ exclusionLeftPx = 0;
18600
+ }
18601
+ if (exclusionRightPx < safeContainerWidthPx && safeContainerWidthPx - exclusionRightPx < MIN_DUAL_WRAPPED_INTERIOR_BAND_PX) {
18602
+ exclusionRightPx = safeContainerWidthPx;
18603
+ }
18604
+ return {
18605
+ leftPx,
18606
+ topPx,
18607
+ exclusion: {
18608
+ left: exclusionLeftPx,
18609
+ right: exclusionRightPx,
18610
+ top: topPx - distTPx,
18611
+ bottom: topPx + tableHeightPx + distBPx
18612
+ }
18613
+ };
18614
+ }
17651
18615
  function tableWrapperStyle(table, indentPx) {
17652
18616
  const floating = table.style?.floating;
17653
18617
  if (!floating) {
@@ -20182,6 +21146,22 @@ function shouldReissueDomSelectionRestore(options) {
20182
21146
  }
20183
21147
  return options.modelChanged;
20184
21148
  }
21149
+ function stableInnerHtmlProp(cache, key, html) {
21150
+ const cached = cache.get(key);
21151
+ if (cached && cached.__html === html) {
21152
+ return cached;
21153
+ }
21154
+ const next = { __html: html };
21155
+ cache.set(key, next);
21156
+ return next;
21157
+ }
21158
+ function isCompositionKeyboardEvent(event) {
21159
+ const nativeKeyboardEvent = event.nativeEvent;
21160
+ if (nativeKeyboardEvent?.isComposing) {
21161
+ return true;
21162
+ }
21163
+ return event.keyCode === 229;
21164
+ }
20185
21165
  function shouldSyncActiveRangeOnKeyUp(event) {
20186
21166
  const nativeKeyboardEvent = event.nativeEvent;
20187
21167
  if (nativeKeyboardEvent?.isComposing) {
@@ -20726,12 +21706,14 @@ function updateSectionImageFloatingAtLocation(model, location, patch) {
20726
21706
  });
20727
21707
  return changed ? next : model;
20728
21708
  }
21709
+ var NO_TRACKED_CHANGES = [];
21710
+ var NO_COMMENTS = [];
20729
21711
  function useDocxEditor(options = {}) {
20730
21712
  const starterTemplateRef = React.useRef(
20731
- cloneDocModel(options.starterModel ?? defaultStarterModel)
21713
+ cloneDocModelWithBlockIds(options.starterModel ?? defaultStarterModel)
20732
21714
  );
20733
21715
  const [model, setModel] = React.useState(
20734
- () => cloneDocModel(starterTemplateRef.current)
21716
+ () => cloneDocModelWithBlockIds(starterTemplateRef.current)
20735
21717
  );
20736
21718
  const [basePackage, setBasePackage] = React.useState();
20737
21719
  const [documentLoadNonce, setDocumentLoadNonce] = React.useState(0);
@@ -20775,6 +21757,9 @@ function useDocxEditor(options = {}) {
20775
21757
  pendingRunStyle
20776
21758
  );
20777
21759
  const suppressNextDomSelectionRestoreRef = React.useRef(false);
21760
+ const textCommitBurstRef = React.useRef(
21761
+ void 0
21762
+ );
20778
21763
  const domSelectionRestoreModelRef = React.useRef(model);
20779
21764
  const selectionSessionRef = React.useRef("idle");
20780
21765
  const selectionSessionTimeoutRef = React.useRef(null);
@@ -20786,6 +21771,17 @@ function useDocxEditor(options = {}) {
20786
21771
  React.useEffect(() => {
20787
21772
  modelRef.current = model;
20788
21773
  }, [model]);
21774
+ React.useEffect(() => {
21775
+ if (typeof process === "undefined" || process.env?.NODE_ENV === "production") {
21776
+ return;
21777
+ }
21778
+ const duplicateBlockIds = collectDuplicateDocModelBlockIds(model);
21779
+ if (duplicateBlockIds.length > 0) {
21780
+ console.error(
21781
+ `Duplicate doc-model block ids detected (an op copied a node without allocating a fresh id): ${duplicateBlockIds.join(", ")}`
21782
+ );
21783
+ }
21784
+ }, [model]);
20789
21785
  React.useEffect(() => {
20790
21786
  selectionRef.current = selection;
20791
21787
  }, [selection]);
@@ -21067,12 +22063,13 @@ function useDocxEditor(options = {}) {
21067
22063
  }, [activeTextRange, selectedParagraph, selectedParagraphLocation]);
21068
22064
  const selectedListType = selectedParagraph ? paragraphListType(selectedParagraph, model.metadata.numberingDefinitions) : void 0;
21069
22065
  const trackedChanges = React.useMemo(
21070
- () => collectTrackedChangesFromModel(model),
21071
- [model]
22066
+ () => showTrackedChanges ? collectTrackedChangesFromModel(model) : NO_TRACKED_CHANGES,
22067
+ [model, showTrackedChanges]
22068
+ );
22069
+ const comments = React.useMemo(
22070
+ () => showComments ? collectCommentsFromModel(model) : NO_COMMENTS,
22071
+ [model, showComments]
21072
22072
  );
21073
- const comments = React.useMemo(() => collectCommentsFromModel(model), [
21074
- model
21075
- ]);
21076
22073
  const hasUnorderedList = selectedListType === "unordered";
21077
22074
  const hasOrderedList = selectedListType === "ordered";
21078
22075
  const canUndo = history.past.length > 0;
@@ -21395,7 +22392,7 @@ function useDocxEditor(options = {}) {
21395
22392
  activeImportAbortControllerRef.current?.abort();
21396
22393
  activeImportAbortControllerRef.current = void 0;
21397
22394
  unloadEmbeddedFonts();
21398
- setModel(cloneDocModel(starterTemplateRef.current));
22395
+ setModel(cloneDocModelWithBlockIds(starterTemplateRef.current));
21399
22396
  setDocumentLoadNonce((current) => current + 1);
21400
22397
  setBasePackage(void 0);
21401
22398
  setFileName("(new document)");
@@ -21432,6 +22429,7 @@ function useDocxEditor(options = {}) {
21432
22429
  setStatus("Exported DOCX");
21433
22430
  }, [basePackage, fileName]);
21434
22431
  const undo = React.useCallback(() => {
22432
+ textCommitBurstRef.current = void 0;
21435
22433
  setHistory((currentHistory) => {
21436
22434
  const previousSnapshot = currentHistory.past[currentHistory.past.length - 1];
21437
22435
  const previous = previousSnapshot?.model;
@@ -21471,6 +22469,7 @@ function useDocxEditor(options = {}) {
21471
22469
  });
21472
22470
  }, []);
21473
22471
  const redo = React.useCallback(() => {
22472
+ textCommitBurstRef.current = void 0;
21474
22473
  setHistory((currentHistory) => {
21475
22474
  const nextSnapshot = currentHistory.future[0];
21476
22475
  const next = nextSnapshot?.model;
@@ -22023,6 +23022,7 @@ function useDocxEditor(options = {}) {
22023
23022
  next.nodes = [
22024
23023
  {
22025
23024
  type: "paragraph",
23025
+ blockId: allocateBlockId(),
22026
23026
  children: [
22027
23027
  {
22028
23028
  type: "text",
@@ -22222,6 +23222,7 @@ function useDocxEditor(options = {}) {
22222
23222
  next.nodes = [
22223
23223
  {
22224
23224
  type: "paragraph",
23225
+ blockId: allocateBlockId(),
22225
23226
  children: [{ type: "text", text: "" }]
22226
23227
  }
22227
23228
  ];
@@ -22261,6 +23262,7 @@ function useDocxEditor(options = {}) {
22261
23262
  next.nodes = [
22262
23263
  {
22263
23264
  type: "paragraph",
23265
+ blockId: allocateBlockId(),
22264
23266
  children: [{ type: "text", text: "" }]
22265
23267
  }
22266
23268
  ];
@@ -23000,6 +24002,7 @@ function useDocxEditor(options = {}) {
23000
24002
  paragraphNode.sourceXml = void 0;
23001
24003
  next.nodes.splice(insertionIndex, 0, {
23002
24004
  type: "paragraph",
24005
+ blockId: allocateBlockId(),
23003
24006
  style: cloneParagraphStyle2(paragraphNode.style),
23004
24007
  children: [
23005
24008
  {
@@ -23096,6 +24099,7 @@ function useDocxEditor(options = {}) {
23096
24099
  paragraphNode.sourceXml = void 0;
23097
24100
  next.nodes.splice(insertionIndex, 0, {
23098
24101
  type: "paragraph",
24102
+ blockId: allocateBlockId(),
23099
24103
  style: cloneParagraphStyle2(splitParagraphStyle),
23100
24104
  children: splitChildren.afterChildren
23101
24105
  });
@@ -23142,6 +24146,7 @@ function useDocxEditor(options = {}) {
23142
24146
  0,
23143
24147
  {
23144
24148
  type: "table",
24149
+ blockId: allocateBlockId(),
23145
24150
  style: {
23146
24151
  borders: createDefaultEditorTableBorders()
23147
24152
  },
@@ -23155,6 +24160,7 @@ function useDocxEditor(options = {}) {
23155
24160
  nodes: [
23156
24161
  {
23157
24162
  type: "paragraph",
24163
+ blockId: allocateBlockId(),
23158
24164
  children: [
23159
24165
  {
23160
24166
  type: "text",
@@ -23170,6 +24176,7 @@ function useDocxEditor(options = {}) {
23170
24176
  nodes: [
23171
24177
  {
23172
24178
  type: "paragraph",
24179
+ blockId: allocateBlockId(),
23173
24180
  children: [
23174
24181
  {
23175
24182
  type: "text",
@@ -23190,6 +24197,7 @@ function useDocxEditor(options = {}) {
23190
24197
  nodes: [
23191
24198
  {
23192
24199
  type: "paragraph",
24200
+ blockId: allocateBlockId(),
23193
24201
  children: [{ type: "text", text: "Value 1" }]
23194
24202
  }
23195
24203
  ]
@@ -23199,6 +24207,7 @@ function useDocxEditor(options = {}) {
23199
24207
  nodes: [
23200
24208
  {
23201
24209
  type: "paragraph",
24210
+ blockId: allocateBlockId(),
23202
24211
  children: [{ type: "text", text: "Value 2" }]
23203
24212
  }
23204
24213
  ]
@@ -23268,6 +24277,7 @@ function useDocxEditor(options = {}) {
23268
24277
  const next = cloneDocModel(current);
23269
24278
  next.nodes.push({
23270
24279
  type: "paragraph",
24280
+ blockId: allocateBlockId(),
23271
24281
  children: [{ type: "text", text }]
23272
24282
  });
23273
24283
  return next;
@@ -23383,7 +24393,7 @@ function useDocxEditor(options = {}) {
23383
24393
  [applyModelChange]
23384
24394
  );
23385
24395
  const moveFloatingImage = React.useCallback(
23386
- (location, patch) => {
24396
+ (location, patch, options2) => {
23387
24397
  applyModelChange((current) => {
23388
24398
  const next = cloneDocModel(current);
23389
24399
  const { paragraph, tableNode } = getParagraphAtLocation(
@@ -23401,6 +24411,16 @@ function useDocxEditor(options = {}) {
23401
24411
  ...child.floating ?? {},
23402
24412
  ...patch
23403
24413
  };
24414
+ const reparentNodeIndex = options2?.reparentToParagraphNodeIndex;
24415
+ const reparentTarget = reparentNodeIndex !== void 0 ? next.nodes[reparentNodeIndex] : void 0;
24416
+ if (reparentTarget && reparentTarget.type === "paragraph" && reparentTarget !== paragraph) {
24417
+ paragraph.children.splice(location.childIndex, 1);
24418
+ if (paragraph.children.length === 0) {
24419
+ paragraph.children.push({ type: "text", text: "" });
24420
+ }
24421
+ reparentTarget.children.unshift(child);
24422
+ reparentTarget.sourceXml = void 0;
24423
+ }
23404
24424
  paragraph.sourceXml = void 0;
23405
24425
  if (tableNode) {
23406
24426
  tableNode.sourceXml = void 0;
@@ -23660,6 +24680,7 @@ function useDocxEditor(options = {}) {
23660
24680
  const firstParagraph = paragraphs[0];
23661
24681
  const nextParagraph = {
23662
24682
  type: "paragraph",
24683
+ blockId: allocateBlockId(),
23663
24684
  style: cloneParagraphStyle2(firstParagraph?.style),
23664
24685
  children: [
23665
24686
  {
@@ -23751,6 +24772,7 @@ function useDocxEditor(options = {}) {
23751
24772
  if (next.nodes.length === 0) {
23752
24773
  next.nodes.push({
23753
24774
  type: "paragraph",
24775
+ blockId: allocateBlockId(),
23754
24776
  children: [{ type: "text", text: "" }]
23755
24777
  });
23756
24778
  nextSelection = { kind: "paragraph", nodeIndex: 0 };
@@ -23822,6 +24844,51 @@ function useDocxEditor(options = {}) {
23822
24844
  },
23823
24845
  [applyModelChange]
23824
24846
  );
24847
+ const setTableFloating = React.useCallback(
24848
+ (tableIndex, patch, options2) => {
24849
+ applyModelChange((current) => {
24850
+ const tableNode = current.nodes[tableIndex];
24851
+ if (!tableNode || tableNode.type !== "table") {
24852
+ return current;
24853
+ }
24854
+ const next = cloneDocModel(current);
24855
+ const nextTable = next.nodes[tableIndex];
24856
+ if (!nextTable || nextTable.type !== "table") {
24857
+ return current;
24858
+ }
24859
+ nextTable.style = {
24860
+ ...nextTable.style ?? {},
24861
+ floating: {
24862
+ ...nextTable.style?.floating ?? {},
24863
+ ...patch
24864
+ }
24865
+ };
24866
+ nextTable.sourceXml = void 0;
24867
+ const moveToNodeIndex = options2?.moveToNodeIndex;
24868
+ if (moveToNodeIndex !== void 0 && moveToNodeIndex !== tableIndex && moveToNodeIndex !== tableIndex + 1) {
24869
+ const clampedTarget = clampNumber(
24870
+ moveToNodeIndex,
24871
+ 0,
24872
+ next.nodes.length
24873
+ );
24874
+ const extracted = next.nodes.splice(tableIndex, 1)[0];
24875
+ if (extracted) {
24876
+ next.nodes.splice(
24877
+ clampNumber(
24878
+ clampedTarget > tableIndex ? clampedTarget - 1 : clampedTarget,
24879
+ 0,
24880
+ next.nodes.length
24881
+ ),
24882
+ 0,
24883
+ extracted
24884
+ );
24885
+ }
24886
+ }
24887
+ return next;
24888
+ }, "Moved table");
24889
+ },
24890
+ [applyModelChange]
24891
+ );
23825
24892
  const moveEmbeddedTableToBody = React.useCallback(
23826
24893
  (tableRuntimeKey, targetNodeIndex) => {
23827
24894
  const runtimeLocation = parseEmbeddedTableRuntimeKey(tableRuntimeKey);
@@ -24275,6 +25342,100 @@ function useDocxEditor(options = {}) {
24275
25342
  },
24276
25343
  [applyModelChange]
24277
25344
  );
25345
+ const commitParagraphTextAtRange = React.useCallback(
25346
+ (location, text, caret, options2) => {
25347
+ const now = Date.now();
25348
+ return dispatchEditorTransaction((current) => {
25349
+ const paragraph = getParagraphAtLocation(
25350
+ current.model,
25351
+ location
25352
+ ).paragraph;
25353
+ if (!paragraph) {
25354
+ return void 0;
25355
+ }
25356
+ const insertionOffset = options2?.insertionOffset ?? caret.start;
25357
+ const insertedStyle = cloneTextStyle2(current.pendingRunStyle) ?? firstTextStyleAtOffset(paragraph, insertionOffset, false);
25358
+ const nextModel = paragraphText(paragraph) === text ? current.model : updateParagraphTextAtLocation(current.model, location, text, {
25359
+ insertedStyle
25360
+ });
25361
+ const coalesce = options2?.coalesceKey !== void 0 && shouldCoalesceTextCommit(textCommitBurstRef.current, {
25362
+ key: options2.coalesceKey,
25363
+ caretBefore: insertionOffset,
25364
+ at: now
25365
+ });
25366
+ textCommitBurstRef.current = options2?.coalesceKey !== void 0 ? { key: options2.coalesceKey, caretAfter: caret.end, at: now } : void 0;
25367
+ return {
25368
+ model: nextModel,
25369
+ selection: selectionFromTextRangeLocation(location),
25370
+ activeTextRange: {
25371
+ start: {
25372
+ location: cloneTextRangeLocation(location),
25373
+ offset: caret.start
25374
+ },
25375
+ end: {
25376
+ location: cloneTextRangeLocation(location),
25377
+ offset: caret.end
25378
+ }
25379
+ },
25380
+ pushHistory: !coalesce,
25381
+ clearSelectedFormField: true
25382
+ };
25383
+ });
25384
+ },
25385
+ [dispatchEditorTransaction]
25386
+ );
25387
+ const commitTableCellTextAtRange = React.useCallback(
25388
+ (tableIndex, rowIndex, cellIndex, text, caret) => {
25389
+ textCommitBurstRef.current = void 0;
25390
+ return dispatchEditorTransaction((current) => {
25391
+ const tableNode = current.model.nodes[tableIndex];
25392
+ if (!tableNode || tableNode.type !== "table") {
25393
+ return void 0;
25394
+ }
25395
+ if (!tableNode.rows[rowIndex]?.cells[cellIndex]) {
25396
+ return void 0;
25397
+ }
25398
+ const caretLocation = {
25399
+ kind: "table-cell",
25400
+ tableIndex,
25401
+ rowIndex,
25402
+ cellIndex,
25403
+ paragraphIndex: caret.paragraphIndex
25404
+ };
25405
+ const caretParagraph = getParagraphAtLocation(
25406
+ current.model,
25407
+ caretLocation
25408
+ ).paragraph;
25409
+ const insertedStyle = cloneTextStyle2(current.pendingRunStyle) ?? (caretParagraph ? firstTextStyleAtOffset(caretParagraph, caret.start, false) : void 0);
25410
+ const nextModel = updateTableCellText(
25411
+ current.model,
25412
+ tableIndex,
25413
+ rowIndex,
25414
+ cellIndex,
25415
+ text,
25416
+ {
25417
+ insertedStyle
25418
+ }
25419
+ );
25420
+ return {
25421
+ model: nextModel,
25422
+ selection: selectionFromTextRangeLocation(caretLocation),
25423
+ activeTextRange: {
25424
+ start: {
25425
+ location: cloneTextRangeLocation(caretLocation),
25426
+ offset: caret.start
25427
+ },
25428
+ end: {
25429
+ location: cloneTextRangeLocation(caretLocation),
25430
+ offset: caret.end
25431
+ }
25432
+ },
25433
+ clearSelectedFormField: true
25434
+ };
25435
+ });
25436
+ },
25437
+ [dispatchEditorTransaction]
25438
+ );
24278
25439
  const commitSectionParagraphText = React.useCallback(
24279
25440
  (location, text) => {
24280
25441
  applyModelChange(
@@ -24403,12 +25564,15 @@ function useDocxEditor(options = {}) {
24403
25564
  deleteTableColumn,
24404
25565
  deleteTable,
24405
25566
  moveTable,
25567
+ setTableFloating,
24406
25568
  moveEmbeddedTableToBody,
24407
25569
  replaceExpandedSelection,
24408
25570
  deleteExpandedSelection,
24409
25571
  commitParagraphText,
24410
25572
  commitTableCellText,
24411
25573
  commitTableCellParagraphTextRecursive,
25574
+ commitParagraphTextAtRange,
25575
+ commitTableCellTextAtRange,
24412
25576
  commitSectionParagraphText
24413
25577
  };
24414
25578
  }
@@ -26836,8 +28000,9 @@ function DocxEditorViewer({
26836
28000
  ]
26837
28001
  );
26838
28002
  const viewerRootRef = React.useRef(null);
26839
- const paragraphDraftsRef = React.useRef(/* @__PURE__ */ new Map());
26840
28003
  const tableCellDraftsRef = React.useRef(/* @__PURE__ */ new Map());
28004
+ const editableParagraphHtmlPropsRef = React.useRef(/* @__PURE__ */ new Map());
28005
+ const editableTableCellHtmlPropsRef = React.useRef(/* @__PURE__ */ new Map());
26841
28006
  const tableCellParagraphDraftsRef = React.useRef(
26842
28007
  /* @__PURE__ */ new Map()
26843
28008
  );
@@ -26850,9 +28015,27 @@ function DocxEditorViewer({
26850
28015
  /* @__PURE__ */ new Map()
26851
28016
  );
26852
28017
  const [
26853
- measuredParagraphOuterHeightsPxByNodeIndex,
26854
- setMeasuredParagraphOuterHeightsPxByNodeIndex
28018
+ measuredParagraphOuterHeightsPxByBlockId,
28019
+ setMeasuredParagraphOuterHeightsPxByBlockId
26855
28020
  ] = React.useState(() => /* @__PURE__ */ new Map());
28021
+ const measuredParagraphOuterHeightsPxByNodeIndex = React.useMemo(() => {
28022
+ const byNodeIndex = /* @__PURE__ */ new Map();
28023
+ if (measuredParagraphOuterHeightsPxByBlockId.size === 0) {
28024
+ return byNodeIndex;
28025
+ }
28026
+ editor.model.nodes.forEach((node, nodeIndex) => {
28027
+ if (node.type !== "paragraph" || !node.blockId) {
28028
+ return;
28029
+ }
28030
+ const outerHeightPx = measuredParagraphOuterHeightsPxByBlockId.get(
28031
+ node.blockId
28032
+ );
28033
+ if (outerHeightPx !== void 0) {
28034
+ byNodeIndex.set(nodeIndex, outerHeightPx);
28035
+ }
28036
+ });
28037
+ return byNodeIndex;
28038
+ }, [editor.model.nodes, measuredParagraphOuterHeightsPxByBlockId]);
26856
28039
  const tableCellEditorElementsRef = React.useRef(
26857
28040
  /* @__PURE__ */ new Map()
26858
28041
  );
@@ -26891,6 +28074,8 @@ function DocxEditorViewer({
26891
28074
  const tableDraftLayoutRefreshRafRef = React.useRef(null);
26892
28075
  const activeRangeFlushFrameRef = React.useRef(null);
26893
28076
  const pendingEditableCaretRef = React.useRef(null);
28077
+ const editingIntentContinuationRef = React.useRef(void 0);
28078
+ const compositionActiveRef = React.useRef(false);
26894
28079
  const pointerSelectionDragRef = React.useRef({ down: false, moved: false });
26895
28080
  const deferredCollapsedSelectionSyncTimeoutRef = React.useRef(
26896
28081
  null
@@ -26975,6 +28160,10 @@ function DocxEditorViewer({
26975
28160
  measuredPageContentIdentityKeysByIndex,
26976
28161
  setMeasuredPageContentIdentityKeysByIndex
26977
28162
  ] = React.useState([]);
28163
+ const [
28164
+ measuredPageContentValidationByIndex,
28165
+ setMeasuredPageContentValidationByIndex
28166
+ ] = React.useState([]);
26978
28167
  const [hasMeasuredBodyFooterOverlap, setHasMeasuredBodyFooterOverlap] = React.useState(false);
26979
28168
  const measuredBodyFooterOverlapCandidateRef = React.useRef({
26980
28169
  signature: void 0,
@@ -27034,6 +28223,7 @@ function DocxEditorViewer({
27034
28223
  React.useEffect(() => {
27035
28224
  setMeasuredPageContentHeightByIndex([]);
27036
28225
  setMeasuredPageContentIdentityKeysByIndex([]);
28226
+ setMeasuredPageContentValidationByIndex([]);
27037
28227
  setHasMeasuredBodyFooterOverlap(false);
27038
28228
  measuredBodyFooterOverlapCandidateRef.current = {
27039
28229
  signature: void 0,
@@ -27056,7 +28246,7 @@ function DocxEditorViewer({
27056
28246
  setActiveDropTarget(void 0);
27057
28247
  setIsDraggingImage(false);
27058
28248
  setActiveHeaderFooterEdit(void 0);
27059
- paragraphDraftsRef.current.clear();
28249
+ editingIntentContinuationRef.current = void 0;
27060
28250
  tableCellDraftsRef.current.clear();
27061
28251
  tableCellParagraphDraftsRef.current.clear();
27062
28252
  sectionParagraphDraftsRef.current.clear();
@@ -27104,6 +28294,7 @@ function DocxEditorViewer({
27104
28294
  const suppressNextTableCellClickRef = React.useRef(false);
27105
28295
  const [tableCellSelectionRange, setTableCellSelectionRange] = React.useState();
27106
28296
  const [tableMoveDropPreview, setTableMoveDropPreview] = React.useState();
28297
+ const [tableFloatingDragPreview, setTableFloatingDragPreview] = React.useState();
27107
28298
  const [tableContextMenuState, setTableContextMenuState] = React.useState();
27108
28299
  const [contextMenuState, setContextMenuState] = React.useState();
27109
28300
  const [activeHeaderFooterEdit, setActiveHeaderFooterEdit] = React.useState();
@@ -27113,13 +28304,36 @@ function DocxEditorViewer({
27113
28304
  );
27114
28305
  const [paragraphStructureEpoch, bumpParagraphStructureEpoch] = React.useReducer((value) => value + 1, 0);
27115
28306
  const [paginationMeasurementEpoch, bumpPaginationMeasurementEpoch] = React.useReducer((value) => value + 1, 0);
28307
+ const [measuredWrapBands, setMeasuredWrapBands] = React.useState(() => /* @__PURE__ */ new Map());
28308
+ const wrapBandReconcileModelRef = React.useRef(void 0);
28309
+ const wrapBandReconcilePassCountRef = React.useRef(0);
27116
28310
  const paginationMeasurementSuspendUntilRef = React.useRef(0);
27117
28311
  const paginationMeasurementResumeTimeoutRef = React.useRef(
27118
28312
  null
27119
28313
  );
27120
28314
  React.useLayoutEffect(() => {
27121
- setMeasuredParagraphOuterHeightsPxByNodeIndex(/* @__PURE__ */ new Map());
27122
- }, [editor.documentLoadNonce, paragraphStructureEpoch]);
28315
+ setMeasuredParagraphOuterHeightsPxByBlockId(/* @__PURE__ */ new Map());
28316
+ }, [editor.documentLoadNonce]);
28317
+ React.useEffect(() => {
28318
+ setMeasuredParagraphOuterHeightsPxByBlockId((current) => {
28319
+ if (current.size === 0) {
28320
+ return current;
28321
+ }
28322
+ const liveBlockIds = /* @__PURE__ */ new Set();
28323
+ for (const node of editor.model.nodes) {
28324
+ if (node.blockId) {
28325
+ liveBlockIds.add(node.blockId);
28326
+ }
28327
+ }
28328
+ let next;
28329
+ current.forEach((_, blockId) => {
28330
+ if (!liveBlockIds.has(blockId)) {
28331
+ (next ??= new Map(current)).delete(blockId);
28332
+ }
28333
+ });
28334
+ return next ?? current;
28335
+ });
28336
+ }, [editor.model.nodes]);
27123
28337
  const schedulePaginationMeasurementResume = React.useCallback(
27124
28338
  (delayMs) => {
27125
28339
  if (typeof window === "undefined") {
@@ -27215,6 +28429,7 @@ function DocxEditorViewer({
27215
28429
  setHoveredEmbeddedTableKey(void 0);
27216
28430
  setFocusedEmbeddedTableKey(void 0);
27217
28431
  setTableMoveDropPreview(void 0);
28432
+ setTableFloatingDragPreview(void 0);
27218
28433
  tableMoveDragRef.current = void 0;
27219
28434
  setTableContextMenuState(void 0);
27220
28435
  setContextMenuState(void 0);
@@ -27269,18 +28484,12 @@ function DocxEditorViewer({
27269
28484
  const nextNodeCount = editor.model.nodes.length;
27270
28485
  const structureChanged = previousNodeCount !== nextNodeCount;
27271
28486
  if (structureChanged) {
27272
- paragraphDraftsRef.current.clear();
28487
+ editingIntentContinuationRef.current = void 0;
27273
28488
  tableCellDraftsRef.current.clear();
27274
28489
  tableCellParagraphDraftsRef.current.clear();
27275
28490
  pendingTableCellFocusRef.current = void 0;
27276
28491
  bumpParagraphStructureEpoch();
27277
28492
  }
27278
- paragraphDraftsRef.current.forEach((_, nodeIndex) => {
27279
- const node = editor.model.nodes[nodeIndex];
27280
- if (!node || node.type !== "paragraph") {
27281
- paragraphDraftsRef.current.delete(nodeIndex);
27282
- }
27283
- });
27284
28493
  tableCellDraftsRef.current.forEach((_, draftKey) => {
27285
28494
  const [tableIndexRaw, rowIndexRaw, cellIndexRaw] = draftKey.split(":");
27286
28495
  const tableIndex = Number.parseInt(tableIndexRaw ?? "", 10);
@@ -27332,6 +28541,27 @@ function DocxEditorViewer({
27332
28541
  () => buildPaginationSectionMetrics(documentSections, documentLayout),
27333
28542
  [documentLayout, documentSections]
27334
28543
  );
28544
+ const paginationMeasurementContextSignature = React.useMemo(
28545
+ () => [
28546
+ Math.round(documentLayout.pageWidthPx),
28547
+ Math.round(documentLayout.pageHeightPx),
28548
+ Math.round(documentLayout.marginsPx.top),
28549
+ Math.round(documentLayout.marginsPx.bottom),
28550
+ Math.round(documentLayout.marginsPx.left),
28551
+ Math.round(documentLayout.marginsPx.right),
28552
+ trackedChangesEnabled ? "tc1" : "tc0",
28553
+ docNodeContentSignature(paginationSectionMetrics)
28554
+ ].join("|"),
28555
+ [documentLayout, paginationSectionMetrics, trackedChangesEnabled]
28556
+ );
28557
+ React.useEffect(() => {
28558
+ setMeasuredParagraphOuterHeightsPxByBlockId(
28559
+ (current) => current.size === 0 ? current : /* @__PURE__ */ new Map()
28560
+ );
28561
+ setTableMeasuredRowHeights(
28562
+ (current) => Object.keys(current).length === 0 ? current : {}
28563
+ );
28564
+ }, [paginationMeasurementContextSignature]);
27335
28565
  const {
27336
28566
  docGridLinePitchPxByNodeIndex,
27337
28567
  pageContentWidthPxByNodeIndex,
@@ -27429,6 +28659,7 @@ function DocxEditorViewer({
27429
28659
  tableMeasuredRowHeights,
27430
28660
  {
27431
28661
  allowMeasuredImportPagination,
28662
+ allowContentSignatureValidatedTables: !disableMeasuredImportPagination,
27432
28663
  activeDraftKeys,
27433
28664
  numberingDefinitions: editor.model.metadata.numberingDefinitions,
27434
28665
  pageContentWidthPxByNodeIndex,
@@ -27459,36 +28690,52 @@ function DocxEditorViewer({
27459
28690
  );
27460
28691
  const suppressSpacingBeforeAfterPageBreak = editor.model.metadata.compatibility?.suppressSpacingBeforeAfterPageBreak === true;
27461
28692
  const preferLastRenderedParagraphStartBreaks = !editor.canUndo && !editor.canRedo;
27462
- const canUseMeasuredPageContentHeights = !editor.canUndo && !editor.canRedo && !disableMeasuredImportPagination && !floatingMovePreview && !dropCapMovePreview && (measuredPageContentHeightByIndex?.length ?? 0) > 0;
28693
+ const measuredPageContentHeightsPxForPagination = (measuredPageContentHeightByIndex?.length ?? 0) === 0 ? void 0 : !editor.canUndo && !editor.canRedo ? measuredPageContentHeightByIndex : resolveMeasuredPageContentHeightsPxForEditedModel(
28694
+ editor.model.nodes,
28695
+ measuredPageContentHeightByIndex,
28696
+ measuredPageContentValidationByIndex,
28697
+ paginationMeasurementContextSignature
28698
+ );
28699
+ const canUseMeasuredPageContentHeights = !disableMeasuredImportPagination && !floatingMovePreview && !dropCapMovePreview && (measuredPageContentHeightsPxForPagination?.length ?? 0) > 0;
28700
+ const buildEstimatedPagesForInputs = createEstimatedPagesBuildMemo(
28701
+ (measuredTableRowHeightsByNodeIndex, measuredPageContentHeightsPx, strictLastRenderedParagraphStartBreaks) => {
28702
+ const buildPagesWithHeights = (resolvedPageContentHeights) => buildDocumentPageNodeSegments(
28703
+ editor.model,
28704
+ pageContentHeightPx,
28705
+ pageContentWidthPx,
28706
+ editor.model.metadata.numberingDefinitions,
28707
+ paginationSectionMetrics,
28708
+ {
28709
+ allowParagraphLineSplitting: true,
28710
+ suppressSpacingBeforeAfterPageBreak,
28711
+ preferLastRenderedParagraphStartBreaks,
28712
+ strictLastRenderedParagraphStartBreaks,
28713
+ measuredTableRowHeightsByNodeIndex,
28714
+ measuredPageContentHeightsPxByPageIndex: resolvedPageContentHeights,
28715
+ measuredParagraphOuterHeightsPxByNodeIndex,
28716
+ precomputedNumberingLabels: paragraphNumberingLabels
28717
+ }
28718
+ );
28719
+ const basePages = buildPagesWithHeights(measuredPageContentHeightsPx);
28720
+ return applyEstimatedFootnoteReserveToPages(
28721
+ editor.model,
28722
+ basePages,
28723
+ pageContentHeightPx,
28724
+ pageContentWidthPx,
28725
+ paginationSectionMetrics,
28726
+ editor.model.metadata.numberingDefinitions,
28727
+ editor.model.metadata.footnotes ?? [],
28728
+ (pageContentHeightsOverride) => buildPagesWithHeights(pageContentHeightsOverride)
28729
+ );
28730
+ }
28731
+ );
27463
28732
  const buildEstimatedPages = (measuredTableRowHeightsByNodeIndex, measuredPageContentHeightsOverride, paginationOptions) => {
27464
- const allowMeasuredPageContentHeights = !editor.canUndo && !editor.canRedo && !disableMeasuredImportPagination && !floatingMovePreview && !dropCapMovePreview;
27465
- const baseMeasuredHeights = !allowMeasuredPageContentHeights || measuredPageContentHeightsOverride === null ? void 0 : measuredPageContentHeightsOverride ?? measuredPageContentHeightByIndex;
27466
- const buildPagesWithHeights = (resolvedPageContentHeights) => buildDocumentPageNodeSegments(
27467
- editor.model,
27468
- pageContentHeightPx,
27469
- pageContentWidthPx,
27470
- editor.model.metadata.numberingDefinitions,
27471
- paginationSectionMetrics,
27472
- {
27473
- allowParagraphLineSplitting: true,
27474
- suppressSpacingBeforeAfterPageBreak,
27475
- preferLastRenderedParagraphStartBreaks,
27476
- strictLastRenderedParagraphStartBreaks: paginationOptions?.strictLastRenderedParagraphStartBreaks ?? false,
27477
- measuredTableRowHeightsByNodeIndex,
27478
- measuredPageContentHeightsPxByPageIndex: resolvedPageContentHeights,
27479
- measuredParagraphOuterHeightsPxByNodeIndex
27480
- }
27481
- );
27482
- const basePages = buildPagesWithHeights(baseMeasuredHeights);
27483
- return applyEstimatedFootnoteReserveToPages(
27484
- editor.model,
27485
- basePages,
27486
- pageContentHeightPx,
27487
- pageContentWidthPx,
27488
- paginationSectionMetrics,
27489
- editor.model.metadata.numberingDefinitions,
27490
- editor.model.metadata.footnotes ?? [],
27491
- (pageContentHeightsOverride) => buildPagesWithHeights(pageContentHeightsOverride)
28733
+ const allowMeasuredPageContentHeights = !disableMeasuredImportPagination && !floatingMovePreview && !dropCapMovePreview;
28734
+ const baseMeasuredHeights = !allowMeasuredPageContentHeights || measuredPageContentHeightsOverride === null ? void 0 : measuredPageContentHeightsOverride ?? measuredPageContentHeightsPxForPagination;
28735
+ return buildEstimatedPagesForInputs(
28736
+ measuredTableRowHeightsByNodeIndex,
28737
+ baseMeasuredHeights,
28738
+ paginationOptions?.strictLastRenderedParagraphStartBreaks ?? false
27492
28739
  );
27493
28740
  };
27494
28741
  const storedDocumentPageCount2 = editor.model.metadata.documentPageCount;
@@ -27527,7 +28774,7 @@ function DocxEditorViewer({
27527
28774
  tableMeasuredRowHeightsForPagination
27528
28775
  );
27529
28776
  let estimatedPagesUseMeasuredPageContentHeightsForRender = canUseMeasuredPageContentHeights;
27530
- let estimatedRenderMeasuredPageContentHeightsPxByPageIndex = canUseMeasuredPageContentHeights ? measuredPageContentHeightByIndex : void 0;
28777
+ let estimatedRenderMeasuredPageContentHeightsPxByPageIndex = canUseMeasuredPageContentHeights ? measuredPageContentHeightsPxForPagination : void 0;
27531
28778
  let estimatedRenderPageContentHeightScale = void 0;
27532
28779
  const deferExpensiveInitialPaginationReconciliation = deferInitialPaginationPaint && !initialPaginationBackgroundRefinementUnlocked;
27533
28780
  if (deferExpensiveInitialPaginationReconciliation) {
@@ -27538,23 +28785,21 @@ function DocxEditorViewer({
27538
28785
  renderPageContentHeightScale: estimatedRenderPageContentHeightScale
27539
28786
  };
27540
28787
  }
27541
- if (measuredPageContentHeightByIndex && measuredPageContentHeightByIndex.length > 0) {
27542
- const pureEstimatedPages = buildEstimatedPages(
27543
- tableMeasuredRowHeightsForPagination,
27544
- null
27545
- );
27546
- const measuredPagesAreOnlySplitParagraphs = estimatedPages.length > 0 && estimatedPages.every(
27547
- (pageSegments) => documentPageContainsOnlySplitParagraphSegments(pageSegments)
27548
- );
27549
- const purePagesAreOnlySplitParagraphs = pureEstimatedPages.length > 0 && pureEstimatedPages.every(
27550
- (pageSegments) => documentPageContainsOnlySplitParagraphSegments(pageSegments)
27551
- );
27552
- if (measuredPagesAreOnlySplitParagraphs && purePagesAreOnlySplitParagraphs && pureEstimatedPages.length < estimatedPages.length) {
27553
- estimatedPages = pureEstimatedPages;
27554
- estimatedPagesUseMeasuredPageContentHeightsForRender = false;
27555
- estimatedRenderMeasuredPageContentHeightsPxByPageIndex = void 0;
27556
- estimatedRenderPageContentHeightScale = void 0;
28788
+ const splitParagraphComparison = resolveMeasuredSplitParagraphPageComparison(
28789
+ {
28790
+ canUndo: editor.canUndo,
28791
+ canRedo: editor.canRedo,
28792
+ hasMeasuredPageContentHeights: (measuredPageContentHeightsPxForPagination?.length ?? 0) > 0,
28793
+ measuredEstimatedPages: estimatedPages,
28794
+ buildPureEstimatedPages: () => buildEstimatedPages(tableMeasuredRowHeightsForPagination, null),
28795
+ pageContainsOnlySplitParagraphSegments: documentPageContainsOnlySplitParagraphSegments
27557
28796
  }
28797
+ );
28798
+ if (splitParagraphComparison.usedPureEstimatedPages) {
28799
+ estimatedPages = splitParagraphComparison.pages;
28800
+ estimatedPagesUseMeasuredPageContentHeightsForRender = false;
28801
+ estimatedRenderMeasuredPageContentHeightsPxByPageIndex = void 0;
28802
+ estimatedRenderPageContentHeightScale = void 0;
27558
28803
  }
27559
28804
  if (!editor.canUndo && !editor.canRedo && targetPageCount !== void 0 && tableMeasuredRowHeightsForPagination && !hasMultiColumnRenderedPageBreakHints) {
27560
28805
  const candidatePages = [
@@ -27567,7 +28812,7 @@ function DocxEditorViewer({
27567
28812
  {
27568
28813
  pages: buildEstimatedPages(void 0),
27569
28814
  useMeasuredPageContentHeightsForRender: canUseMeasuredPageContentHeights,
27570
- renderMeasuredPageContentHeightsPxByPageIndex: canUseMeasuredPageContentHeights ? measuredPageContentHeightByIndex : void 0,
28815
+ renderMeasuredPageContentHeightsPxByPageIndex: canUseMeasuredPageContentHeights ? measuredPageContentHeightsPxForPagination : void 0,
27571
28816
  renderPageContentHeightScale: void 0
27572
28817
  },
27573
28818
  {
@@ -27598,7 +28843,7 @@ function DocxEditorViewer({
27598
28843
  }
27599
28844
  }
27600
28845
  const measuredPageHeightOverridesReduceContent = !editor.canUndo && !editor.canRedo && !floatingMovePreview && !dropCapMovePreview && estimatedPages.some((segments, pageIndex) => {
27601
- const measuredHeightPx = measuredPageContentHeightByIndex?.[pageIndex];
28846
+ const measuredHeightPx = measuredPageContentHeightsPxForPagination?.[pageIndex];
27602
28847
  if (!Number.isFinite(measuredHeightPx)) {
27603
28848
  return false;
27604
28849
  }
@@ -27708,7 +28953,7 @@ function DocxEditorViewer({
27708
28953
  return {
27709
28954
  pages: hintAlignedPages,
27710
28955
  useMeasuredPageContentHeightsForRender: canUseMeasuredPageContentHeights,
27711
- renderMeasuredPageContentHeightsPxByPageIndex: canUseMeasuredPageContentHeights ? measuredPageContentHeightByIndex : void 0,
28956
+ renderMeasuredPageContentHeightsPxByPageIndex: canUseMeasuredPageContentHeights ? measuredPageContentHeightsPxForPagination : void 0,
27712
28957
  renderPageContentHeightScale: void 0
27713
28958
  };
27714
28959
  }
@@ -27750,22 +28995,23 @@ function DocxEditorViewer({
27750
28995
  preferLastRenderedParagraphStartBreaks,
27751
28996
  measuredTableRowHeightsByNodeIndex,
27752
28997
  measuredPageContentHeightsPxByPageIndex: measuredPageContentHeightsOverride === null ? void 0 : scaleMeasuredPageContentHeights(
27753
- measuredPageContentHeightsOverride ?? measuredPageContentHeightByIndex,
28998
+ measuredPageContentHeightsOverride ?? measuredPageContentHeightsPxForPagination,
27754
28999
  heightScale
27755
29000
  ),
27756
- measuredParagraphOuterHeightsPxByNodeIndex
29001
+ measuredParagraphOuterHeightsPxByNodeIndex,
29002
+ precomputedNumberingLabels: paragraphNumberingLabels
27757
29003
  }
27758
29004
  )
27759
29005
  });
27760
29006
  let reconciledCandidate = reconcileCandidatePages(
27761
29007
  estimatedPages,
27762
29008
  tableMeasuredRowHeightsForPagination,
27763
- estimatedPagesUseMeasuredPageContentHeightsForRender ? measuredPageContentHeightByIndex : null
29009
+ estimatedPagesUseMeasuredPageContentHeightsForRender ? measuredPageContentHeightsPxForPagination : null
27764
29010
  );
27765
29011
  let reconciledPages = reconciledCandidate.pages;
27766
29012
  let reconciledPagesUseMeasuredPageContentHeightsForRender = estimatedPagesUseMeasuredPageContentHeightsForRender;
27767
29013
  let reconciledRenderMeasuredPageContentHeightsPxByPageIndex = reconciledPagesUseMeasuredPageContentHeightsForRender ? scaleMeasuredPageContentHeights(
27768
- measuredPageContentHeightByIndex,
29014
+ measuredPageContentHeightsPxForPagination,
27769
29015
  reconciledCandidate.scale
27770
29016
  ) : void 0;
27771
29017
  let reconciledRenderPageContentHeightScale = void 0;
@@ -27826,7 +29072,10 @@ function DocxEditorViewer({
27826
29072
  hasMeasuredBodyFooterOverlap,
27827
29073
  initialPaginationBackgroundRefinementUnlocked,
27828
29074
  measuredPageContentHeightByIndex,
29075
+ measuredPageContentValidationByIndex,
27829
29076
  measuredParagraphOuterHeightsPxByNodeIndex,
29077
+ paginationMeasurementContextSignature,
29078
+ paragraphNumberingLabels,
27830
29079
  tableMeasuredRowHeightsForPagination
27831
29080
  ]);
27832
29081
  const pageNodeSegmentsByPage = pageSegmentationPlan.pages;
@@ -28259,6 +29508,132 @@ function DocxEditorViewer({
28259
29508
  },
28260
29509
  [explicitPageVirtualizationZoomScale]
28261
29510
  );
29511
+ React.useEffect(() => {
29512
+ if (floatingMovePreview || resizePreview || tableFloatingDragPreview || tableMoveDragRef.current) {
29513
+ return;
29514
+ }
29515
+ const modelChanged = wrapBandReconcileModelRef.current !== editor.model;
29516
+ if (modelChanged) {
29517
+ wrapBandReconcileModelRef.current = editor.model;
29518
+ wrapBandReconcilePassCountRef.current = 0;
29519
+ }
29520
+ if (wrapBandReconcilePassCountRef.current >= WRAP_BAND_RECONCILE_MAX_PASSES) {
29521
+ return;
29522
+ }
29523
+ const fresh = /* @__PURE__ */ new Map();
29524
+ pageBodyElementsRef.current.forEach((bodyElement) => {
29525
+ if (!bodyElement.isConnected) {
29526
+ return;
29527
+ }
29528
+ const origin = bodyElement.getBoundingClientRect();
29529
+ if (origin.width <= 0) {
29530
+ return;
29531
+ }
29532
+ const zoomScale = resolveViewerMeasurementZoomScale(bodyElement, 1);
29533
+ const toBand = (rect) => ({
29534
+ topPx: (rect.top - origin.top) / zoomScale,
29535
+ bottomPx: (rect.bottom - origin.top) / zoomScale,
29536
+ leftPx: (rect.left - origin.left) / zoomScale,
29537
+ rightPx: (rect.right - origin.left) / zoomScale
29538
+ });
29539
+ let pageHasFloatingObject = false;
29540
+ tableElementsRef.current.forEach((element, nodeIndex) => {
29541
+ if (!element.isConnected || !bodyElement.contains(element)) {
29542
+ return;
29543
+ }
29544
+ const node = editor.model.nodes[nodeIndex];
29545
+ if (node?.type !== "table" || !node.style?.floating) {
29546
+ return;
29547
+ }
29548
+ pageHasFloatingObject = true;
29549
+ fresh.set(`tbl:${nodeIndex}`, toBand(element.getBoundingClientRect()));
29550
+ });
29551
+ bodyElement.querySelectorAll("[data-docx-image-location]").forEach((span) => {
29552
+ if (!(span instanceof HTMLElement)) {
29553
+ return;
29554
+ }
29555
+ const location = span.getAttribute("data-docx-image-location") ?? "";
29556
+ const match = /^p:(\d+):(\d+)$/.exec(location);
29557
+ if (!match) {
29558
+ return;
29559
+ }
29560
+ const nodeIndex = Number.parseInt(match[1] ?? "", 10);
29561
+ const childIndex = Number.parseInt(match[2] ?? "", 10);
29562
+ const node = editor.model.nodes[nodeIndex];
29563
+ const child = node?.type === "paragraph" ? node.children[childIndex] : void 0;
29564
+ if (!child || child.type !== "image" || !child.floating?.wrapType || child.floating.wrapType === "none" || child.floating.behindDocument === true || shouldRenderWrappedFloatingImage(child)) {
29565
+ return;
29566
+ }
29567
+ if (getComputedStyle(span).position !== "absolute") {
29568
+ return;
29569
+ }
29570
+ pageHasFloatingObject = true;
29571
+ fresh.set(`img:${location}`, toBand(span.getBoundingClientRect()));
29572
+ });
29573
+ if (!pageHasFloatingObject) {
29574
+ let hasInFlowWrappedFloat = false;
29575
+ paragraphElementsRef.current.forEach((element, nodeIndex) => {
29576
+ if (hasInFlowWrappedFloat || !element.isConnected || !bodyElement.contains(element)) {
29577
+ return;
29578
+ }
29579
+ const candidate = editor.model.nodes[nodeIndex];
29580
+ if (candidate?.type === "paragraph" && candidate.children.some(
29581
+ (child) => child.type === "image" && shouldRenderWrappedFloatingImage(child)
29582
+ )) {
29583
+ hasInFlowWrappedFloat = true;
29584
+ }
29585
+ });
29586
+ if (!hasInFlowWrappedFloat) {
29587
+ return;
29588
+ }
29589
+ }
29590
+ paragraphElementsRef.current.forEach((element, nodeIndex) => {
29591
+ if (!element.isConnected || !bodyElement.contains(element)) {
29592
+ return;
29593
+ }
29594
+ const rect = element.getBoundingClientRect();
29595
+ if (rect.height <= 0) {
29596
+ return;
29597
+ }
29598
+ fresh.set(`para:${nodeIndex}`, toBand(rect));
29599
+ });
29600
+ });
29601
+ 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;
29602
+ const next = /* @__PURE__ */ new Map();
29603
+ if (!modelChanged) {
29604
+ measuredWrapBands.forEach((band, key) => {
29605
+ next.set(key, band);
29606
+ });
29607
+ }
29608
+ let modifiedExistingBand = false;
29609
+ fresh.forEach((band, key) => {
29610
+ const previous = measuredWrapBands.get(key);
29611
+ if (previous && withinTolerance(previous, band)) {
29612
+ next.set(key, previous);
29613
+ return;
29614
+ }
29615
+ if (previous && !modelChanged) {
29616
+ modifiedExistingBand = true;
29617
+ }
29618
+ next.set(key, band);
29619
+ });
29620
+ let changed = next.size !== measuredWrapBands.size;
29621
+ if (!changed) {
29622
+ for (const [key, band] of next) {
29623
+ if (measuredWrapBands.get(key) !== band) {
29624
+ changed = true;
29625
+ break;
29626
+ }
29627
+ }
29628
+ }
29629
+ if (!changed) {
29630
+ return;
29631
+ }
29632
+ if (modifiedExistingBand) {
29633
+ wrapBandReconcilePassCountRef.current += 1;
29634
+ }
29635
+ setMeasuredWrapBands(next);
29636
+ });
28262
29637
  React.useEffect(() => {
28263
29638
  setDeferInternalPageVirtualization(!hasLargeTableLayoutSurface);
28264
29639
  }, [editor.documentLoadNonce, hasLargeTableLayoutSurface]);
@@ -28738,12 +30113,16 @@ function DocxEditorViewer({
28738
30113
  if (Date.now() < paginationMeasurementSuspendUntilRef.current) {
28739
30114
  return;
28740
30115
  }
28741
- setMeasuredParagraphOuterHeightsPxByNodeIndex((current) => {
30116
+ setMeasuredParagraphOuterHeightsPxByBlockId((current) => {
28742
30117
  const next = new Map(current);
28743
30118
  let changed = false;
28744
30119
  const rootElement = viewerRootRef.current;
28745
30120
  const zoomScale = resolveViewerMeasurementZoomScale(rootElement, 1);
28746
30121
  paragraphElementsRef.current.forEach((element, nodeIndex) => {
30122
+ const node = editor.model.nodes[nodeIndex];
30123
+ if (node?.type !== "paragraph" || !node.blockId) {
30124
+ return;
30125
+ }
28747
30126
  if (!element.isConnected || element.dataset.docxParagraphPartialLineRange === "true" || element.closest('[data-docx-header-footer-region="footer"]') || element.closest('[data-docx-header-footer-region="header"]')) {
28748
30127
  return;
28749
30128
  }
@@ -28760,9 +30139,9 @@ function DocxEditorViewer({
28760
30139
  rect.height / zoomScale + (Number.isFinite(marginTop) ? marginTop : 0) + (Number.isFinite(marginBottom) ? marginBottom : 0)
28761
30140
  )
28762
30141
  );
28763
- const previousHeightPx = next.get(nodeIndex);
30142
+ const previousHeightPx = next.get(node.blockId);
28764
30143
  if (previousHeightPx === void 0 || Math.abs(previousHeightPx - outerHeightPx) > 1) {
28765
- next.set(nodeIndex, outerHeightPx);
30144
+ next.set(node.blockId, outerHeightPx);
28766
30145
  changed = true;
28767
30146
  }
28768
30147
  });
@@ -28770,7 +30149,9 @@ function DocxEditorViewer({
28770
30149
  });
28771
30150
  }, [
28772
30151
  editor.documentLoadNonce,
30152
+ editor.model.nodes,
28773
30153
  pageNodeSegmentIdentityKeysByPage,
30154
+ paginationMeasurementEpoch,
28774
30155
  resolveViewerMeasurementZoomScale,
28775
30156
  visiblePageEndIndex,
28776
30157
  visiblePageStartIndex
@@ -28833,7 +30214,7 @@ function DocxEditorViewer({
28833
30214
  if (segment.tableRowSlice) {
28834
30215
  continue;
28835
30216
  }
28836
- const measuredHeights = tableMeasuredRowHeights[segment.nodeIndex];
30217
+ const measuredHeights = tableNode.blockId ? tableMeasuredRowHeights[tableNode.blockId]?.rowHeightsPx : void 0;
28837
30218
  if (!measuredHeights || measuredHeights.length !== tableNode.rows.length) {
28838
30219
  return true;
28839
30220
  }
@@ -29397,6 +30778,9 @@ function DocxEditorViewer({
29397
30778
  setMeasuredPageContentIdentityKeysByIndex(
29398
30779
  (current) => current.length === 0 ? current : []
29399
30780
  );
30781
+ setMeasuredPageContentValidationByIndex(
30782
+ (current) => current.length === 0 ? current : []
30783
+ );
29400
30784
  return;
29401
30785
  }
29402
30786
  if (!paginationMeasurementEnabled) {
@@ -29410,6 +30794,9 @@ function DocxEditorViewer({
29410
30794
  setMeasuredPageContentIdentityKeysByIndex(
29411
30795
  (current) => current.length === 0 ? current : []
29412
30796
  );
30797
+ setMeasuredPageContentValidationByIndex(
30798
+ (current) => current.length === 0 ? current : []
30799
+ );
29413
30800
  return;
29414
30801
  }
29415
30802
  if (Date.now() < paginationMeasurementSuspendUntilRef.current) {
@@ -29543,6 +30930,19 @@ function DocxEditorViewer({
29543
30930
  const nextMeasuredHeights = nextMeasuredPageDiagnostics.map(
29544
30931
  (diagnostics) => diagnostics.heightPx
29545
30932
  );
30933
+ const nextMeasuredPageValidation = pageNodeSegmentsByPage.map(
30934
+ (pageSegments, pageIndex) => {
30935
+ const pageIsVisible = pageIndex >= visiblePageStartIndex && pageIndex <= visiblePageEndIndex;
30936
+ if (!pageIsVisible || !pageElementsRef.current.get(pageIndex)) {
30937
+ return void 0;
30938
+ }
30939
+ return buildMeasuredPageContentValidationForPageSegments(
30940
+ pageSegments,
30941
+ editor.model.nodes,
30942
+ paginationMeasurementContextSignature
30943
+ );
30944
+ }
30945
+ );
29546
30946
  const overlappingPageIndexes = nextMeasuredPageDiagnostics.reduce(
29547
30947
  (indexes, diagnostics, pageIndex) => {
29548
30948
  if (diagnostics.bodyOverrunsFooter) {
@@ -29613,6 +31013,27 @@ function DocxEditorViewer({
29613
31013
  }
29614
31014
  return nextMeasuredPageIdentityKeys;
29615
31015
  });
31016
+ setMeasuredPageContentValidationByIndex((current) => {
31017
+ const merged = nextMeasuredPageValidation.map(
31018
+ (validation, pageIndex) => validation ?? current[pageIndex]
31019
+ );
31020
+ if (current.length === merged.length) {
31021
+ let equal = true;
31022
+ for (let pageIndex = 0; pageIndex < merged.length; pageIndex += 1) {
31023
+ if (!measuredPageContentValidationsEqual(
31024
+ current[pageIndex],
31025
+ merged[pageIndex]
31026
+ )) {
31027
+ equal = false;
31028
+ break;
31029
+ }
31030
+ }
31031
+ if (equal) {
31032
+ return current;
31033
+ }
31034
+ }
31035
+ return merged;
31036
+ });
29616
31037
  });
29617
31038
  return () => {
29618
31039
  window.cancelAnimationFrame(frameId);
@@ -29620,8 +31041,10 @@ function DocxEditorViewer({
29620
31041
  }, [
29621
31042
  disableMeasuredImportPagination,
29622
31043
  documentLayout,
31044
+ editor.model.nodes,
29623
31045
  measuredPageContentHeightByIndex,
29624
31046
  measuredPageContentIdentityKeysByIndex,
31047
+ paginationMeasurementContextSignature,
29625
31048
  paginationMeasurementEnabled,
29626
31049
  paginationMeasurementEpoch,
29627
31050
  pageCount,
@@ -29654,6 +31077,7 @@ function DocxEditorViewer({
29654
31077
  initialPaginationStableSignatureRef.current = void 0;
29655
31078
  setDisableMeasuredImportPagination(true);
29656
31079
  setMeasuredPageContentHeightByIndex([]);
31080
+ setMeasuredPageContentValidationByIndex([]);
29657
31081
  setTableMeasuredRowHeights({});
29658
31082
  }, [
29659
31083
  deferInitialPaginationPaint,
@@ -29737,7 +31161,8 @@ function DocxEditorViewer({
29737
31161
  (pageIndex) => (pageNodeSegmentsByPage[pageIndex] ?? []).filter(
29738
31162
  (segment) => editor.model.nodes[segment.nodeIndex]?.type === "table"
29739
31163
  ).map((segment) => {
29740
- const measuredHeights = tableMeasuredRowHeights[segment.nodeIndex] ?? [];
31164
+ const tableNode = editor.model.nodes[segment.nodeIndex];
31165
+ const measuredHeights = (tableNode?.blockId ? tableMeasuredRowHeights[tableNode.blockId]?.rowHeightsPx : void 0) ?? [];
29741
31166
  return `${segment.nodeIndex}:${measuredHeights.join(",")}`;
29742
31167
  }).join(";")
29743
31168
  ).join("|");
@@ -29992,22 +31417,29 @@ function DocxEditorViewer({
29992
31417
  startY: event.clientY,
29993
31418
  hasMoved: false
29994
31419
  };
31420
+ const zoomScale = resolveViewerMeasurementZoomScale(
31421
+ viewerRootRef.current,
31422
+ 1
31423
+ );
31424
+ const tableElementAtStart = tableElementsRef.current.get(tableIndex);
31425
+ const tableRectAtStart = tableElementAtStart?.getBoundingClientRect();
31426
+ const floatingHostRectAtStart = tableElementAtStart?.closest("[data-docx-floating-table-host]")?.getBoundingClientRect();
29995
31427
  const onPointerMove = (pointerMoveEvent) => {
29996
31428
  const dragState = tableMoveDragRef.current;
29997
31429
  if (!dragState || pointerMoveEvent.pointerId !== dragState.pointerId) {
29998
31430
  return;
29999
31431
  }
30000
- const deltaX = Math.abs(pointerMoveEvent.clientX - dragState.startX);
30001
- const deltaY = Math.abs(pointerMoveEvent.clientY - dragState.startY);
30002
- if (deltaX + deltaY < TABLE_MOVE_DRAG_THRESHOLD_PX) {
31432
+ const movedX = pointerMoveEvent.clientX - dragState.startX;
31433
+ const movedY = pointerMoveEvent.clientY - dragState.startY;
31434
+ if (!dragState.hasMoved && Math.abs(movedX) + Math.abs(movedY) < TABLE_MOVE_DRAG_THRESHOLD_PX) {
30003
31435
  return;
30004
31436
  }
30005
31437
  dragState.hasMoved = true;
30006
- const target = resolveTableMoveDropTarget(dragState.tableIndex, {
30007
- x: pointerMoveEvent.clientX,
30008
- y: pointerMoveEvent.clientY
31438
+ setTableFloatingDragPreview({
31439
+ tableIndex: dragState.tableIndex,
31440
+ deltaX: normalizeFloatingDragDeltaForZoom(movedX, zoomScale),
31441
+ deltaY: normalizeFloatingDragDeltaForZoom(movedY, zoomScale)
30009
31442
  });
30010
- setTableMoveDropPreview(target?.preview);
30011
31443
  pointerMoveEvent.preventDefault();
30012
31444
  };
30013
31445
  const onPointerUp = (pointerUpEvent) => {
@@ -30030,18 +31462,57 @@ function DocxEditorViewer({
30030
31462
  setHoveredTableHandleTableIndex(
30031
31463
  pointerStillOverTable ? dragState.tableIndex : void 0
30032
31464
  );
30033
- const target = resolveTableMoveDropTarget(dragState.tableIndex, {
30034
- x: pointerUpEvent.clientX,
30035
- y: pointerUpEvent.clientY
30036
- });
30037
- setTableMoveDropPreview(void 0);
30038
- if (!dragState.hasMoved) {
31465
+ setTableFloatingDragPreview(void 0);
31466
+ if (!dragState.hasMoved || !tableRectAtStart) {
30039
31467
  return;
30040
31468
  }
30041
- if (!target) {
31469
+ const deltaX = normalizeFloatingDragDeltaForZoom(
31470
+ pointerUpEvent.clientX - dragState.startX,
31471
+ zoomScale
31472
+ );
31473
+ const deltaY = normalizeFloatingDragDeltaForZoom(
31474
+ pointerUpEvent.clientY - dragState.startY,
31475
+ zoomScale
31476
+ );
31477
+ const tableNode = editor.model.nodes[dragState.tableIndex];
31478
+ if (!tableNode || tableNode.type !== "table") {
30042
31479
  return;
30043
31480
  }
30044
- editor.moveTable(dragState.tableIndex, target.targetNodeIndex);
31481
+ const currentFloating = tableNode.style?.floating;
31482
+ const baseLeftPx = floatingHostRectAtStart ? (tableRectAtStart.left - floatingHostRectAtStart.left) / zoomScale : twipsToSignedPixels(tableNode.style?.indentTwips) ?? 0;
31483
+ const baseTopPx = floatingHostRectAtStart ? (tableRectAtStart.top - floatingHostRectAtStart.top) / zoomScale : 0;
31484
+ const dropTarget = resolveTableMoveDropTarget(dragState.tableIndex, {
31485
+ x: pointerUpEvent.clientX,
31486
+ y: pointerUpEvent.clientY
31487
+ });
31488
+ const rootRect = viewerRootRef.current?.getBoundingClientRect();
31489
+ const shouldReanchor = dropTarget !== void 0 && rootRect !== void 0 && dropTarget.targetNodeIndex !== dragState.tableIndex && dropTarget.targetNodeIndex !== dragState.tableIndex + 1;
31490
+ let committedTopPx = baseTopPx + deltaY;
31491
+ if (shouldReanchor && dropTarget && rootRect) {
31492
+ let targetScreenTop = rootRect.top + dropTarget.preview.top;
31493
+ if (!floatingHostRectAtStart && dropTarget.targetNodeIndex > dragState.tableIndex) {
31494
+ targetScreenTop -= tableRectAtStart.height;
31495
+ }
31496
+ const droppedTopScreenPx = tableRectAtStart.top + (pointerUpEvent.clientY - dragState.startY);
31497
+ committedTopPx = (droppedTopScreenPx - targetScreenTop) / zoomScale;
31498
+ }
31499
+ committedTopPx = Math.max(0, committedTopPx);
31500
+ editor.setTableFloating(
31501
+ dragState.tableIndex,
31502
+ {
31503
+ xTwips: pixelsToTwips(baseLeftPx + deltaX),
31504
+ yTwips: pixelsToTwips(committedTopPx),
31505
+ horizontalAnchor: "margin",
31506
+ verticalAnchor: "text",
31507
+ horizontalAlign: void 0,
31508
+ verticalAlign: void 0,
31509
+ leftFromTextTwips: currentFloating?.leftFromTextTwips ?? 187,
31510
+ rightFromTextTwips: currentFloating?.rightFromTextTwips ?? 187,
31511
+ topFromTextTwips: currentFloating?.topFromTextTwips ?? 0,
31512
+ bottomFromTextTwips: currentFloating?.bottomFromTextTwips ?? 0
31513
+ },
31514
+ shouldReanchor && dropTarget ? { moveToNodeIndex: dropTarget.targetNodeIndex } : void 0
31515
+ );
30045
31516
  };
30046
31517
  window.addEventListener("pointermove", onPointerMove);
30047
31518
  window.addEventListener("pointerup", onPointerUp, { once: true });
@@ -31190,7 +32661,7 @@ function DocxEditorViewer({
31190
32661
  editorHasFocus && (!liveSelection || liveSelection.rangeCount === 0)
31191
32662
  );
31192
32663
  if (collapsedElementAnchor || selectionDropped) {
31193
- if (session === "keyboard" || session === "composition") {
32664
+ if (session === "keyboard" || session === "composition" || compositionActiveRef.current) {
31194
32665
  return;
31195
32666
  }
31196
32667
  const anchorElement = anchorNode instanceof Element ? anchorNode : anchorNode?.parentElement ?? null;
@@ -31249,7 +32720,7 @@ function DocxEditorViewer({
31249
32720
  return;
31250
32721
  }
31251
32722
  const session = editor.selectionSessionKind;
31252
- if (pointerSelectionDragRef.current.moved || session === "composition") {
32723
+ if (pointerSelectionDragRef.current.moved || session === "composition" || compositionActiveRef.current) {
31253
32724
  return;
31254
32725
  }
31255
32726
  const rootElement = viewerRootRef.current;
@@ -31628,7 +33099,7 @@ function DocxEditorViewer({
31628
33099
  appliedHistoryRestoreNonceRef.current = restoreRequest.nonce;
31629
33100
  const selectionIntentNonce = beginSelectionIntent();
31630
33101
  editor.beginSelectionSession("history-restore", { settleAfterMs: 180 });
31631
- paragraphDraftsRef.current.clear();
33102
+ editingIntentContinuationRef.current = void 0;
31632
33103
  tableCellDraftsRef.current.clear();
31633
33104
  tableCellParagraphDraftsRef.current.clear();
31634
33105
  sectionParagraphDraftsRef.current.clear();
@@ -32304,7 +33775,7 @@ function DocxEditorViewer({
32304
33775
  normalizedActiveRange
32305
33776
  );
32306
33777
  if (collapsedRange) {
32307
- paragraphDraftsRef.current.clear();
33778
+ editingIntentContinuationRef.current = void 0;
32308
33779
  tableCellDraftsRef.current.clear();
32309
33780
  tableCellParagraphDraftsRef.current.clear();
32310
33781
  syncSelectionFromDocxRange(collapsedRange);
@@ -32405,7 +33876,7 @@ function DocxEditorViewer({
32405
33876
  normalizedActiveRange
32406
33877
  );
32407
33878
  if (collapsedRange) {
32408
- paragraphDraftsRef.current.clear();
33879
+ editingIntentContinuationRef.current = void 0;
32409
33880
  tableCellDraftsRef.current.clear();
32410
33881
  tableCellParagraphDraftsRef.current.clear();
32411
33882
  syncSelectionFromDocxRange(collapsedRange);
@@ -32463,7 +33934,7 @@ function DocxEditorViewer({
32463
33934
  if (!collapsedRange) {
32464
33935
  return false;
32465
33936
  }
32466
- paragraphDraftsRef.current.clear();
33937
+ editingIntentContinuationRef.current = void 0;
32467
33938
  tableCellDraftsRef.current.clear();
32468
33939
  tableCellParagraphDraftsRef.current.clear();
32469
33940
  syncSelectionFromDocxRange(collapsedRange);
@@ -32618,7 +34089,7 @@ function DocxEditorViewer({
32618
34089
  return true;
32619
34090
  };
32620
34091
  const clearDraftsAndSetSelection = (range) => {
32621
- paragraphDraftsRef.current.clear();
34092
+ editingIntentContinuationRef.current = void 0;
32622
34093
  tableCellDraftsRef.current.clear();
32623
34094
  tableCellParagraphDraftsRef.current.clear();
32624
34095
  syncSelectionFromDocxRange(range);
@@ -33111,7 +34582,7 @@ function DocxEditorViewer({
33111
34582
  if (!collapsedRange) {
33112
34583
  return;
33113
34584
  }
33114
- paragraphDraftsRef.current.clear();
34585
+ editingIntentContinuationRef.current = void 0;
33115
34586
  tableCellDraftsRef.current.clear();
33116
34587
  tableCellParagraphDraftsRef.current.clear();
33117
34588
  syncSelectionFromDocxRange(collapsedRange);
@@ -33552,20 +35023,6 @@ function DocxEditorViewer({
33552
35023
  },
33553
35024
  [clearTableCellSelection, editor, selectionOffsetsWithinElement]
33554
35025
  );
33555
- const commitParagraphDraftFromElement = React.useCallback(
33556
- (nodeIndex, paragraph, element) => {
33557
- const nextText = editableTextFromElement(element);
33558
- const nextHtml = element.innerHTML;
33559
- if (nextText === paragraphText(paragraph)) {
33560
- paragraphDraftsRef.current.delete(nodeIndex);
33561
- return;
33562
- }
33563
- paragraphDraftsRef.current.set(nodeIndex, nextHtml);
33564
- editor.suppressNextDomSelectionRestore();
33565
- editor.commitParagraphText(nodeIndex, nextText);
33566
- },
33567
- [editor]
33568
- );
33569
35026
  const commitTableCellDraftFromElement = React.useCallback(
33570
35027
  (tableIndex, rowIndex, cellIndex, cellParagraphs, draftKey, element) => {
33571
35028
  const nextText = editableTextFromTableCellElement(element);
@@ -33782,33 +35239,14 @@ function DocxEditorViewer({
33782
35239
  }
33783
35240
  React.useEffect(() => {
33784
35241
  const flushPendingDraftsForExport = (currentModel) => {
33785
- if (paragraphDraftsRef.current.size === 0 && tableCellDraftsRef.current.size === 0 && tableCellParagraphDraftsRef.current.size === 0 && sectionParagraphDraftsRef.current.size === 0) {
35242
+ if (tableCellDraftsRef.current.size === 0 && tableCellParagraphDraftsRef.current.size === 0 && sectionParagraphDraftsRef.current.size === 0) {
33786
35243
  return currentModel;
33787
35244
  }
33788
35245
  let nextModel = currentModel;
33789
35246
  const insertedStyle = cloneTextStyle2(editor.pendingRunStyle);
33790
- const consumedParagraphDraftIndexes = [];
33791
35247
  const consumedTableDraftKeys = [];
33792
35248
  const consumedTableParagraphDraftKeys = [];
33793
35249
  const consumedSectionDraftKeys = [];
33794
- paragraphDraftsRef.current.forEach((draftHtml, nodeIndex) => {
33795
- const element = paragraphElementsRef.current.get(nodeIndex);
33796
- if (!element && typeof draftHtml !== "string") {
33797
- return;
33798
- }
33799
- consumedParagraphDraftIndexes.push(nodeIndex);
33800
- const paragraph = nextModel.nodes[nodeIndex];
33801
- if (!paragraph || paragraph.type !== "paragraph") {
33802
- return;
33803
- }
33804
- const nextText = element ? editableTextFromElement(element) : editableTextFromDraftHtml(draftHtml);
33805
- if (nextText === paragraphText(paragraph)) {
33806
- return;
33807
- }
33808
- nextModel = updateParagraphText(nextModel, nodeIndex, nextText, {
33809
- insertedStyle
33810
- });
33811
- });
33812
35250
  tableCellParagraphDraftsRef.current.forEach((draftHtml, draftKey) => {
33813
35251
  const element = tableCellParagraphElementsRef.current.get(draftKey);
33814
35252
  if (!element && typeof draftHtml !== "string") {
@@ -33905,9 +35343,6 @@ function DocxEditorViewer({
33905
35343
  }
33906
35344
  );
33907
35345
  });
33908
- consumedParagraphDraftIndexes.forEach((nodeIndex) => {
33909
- paragraphDraftsRef.current.delete(nodeIndex);
33910
- });
33911
35346
  consumedTableDraftKeys.forEach((draftKey) => {
33912
35347
  tableCellDraftsRef.current.delete(draftKey);
33913
35348
  });
@@ -33949,6 +35384,430 @@ function DocxEditorViewer({
33949
35384
  },
33950
35385
  [editor]
33951
35386
  );
35387
+ const handleEditableHostBeforeInput = React.useCallback(
35388
+ (event) => {
35389
+ if (isReadOnly) {
35390
+ return;
35391
+ }
35392
+ if (event.isComposing || compositionActiveRef.current) {
35393
+ return;
35394
+ }
35395
+ const targetElement = event.target instanceof Element ? event.target : event.target instanceof Node ? event.target.parentElement : null;
35396
+ if (!targetElement) {
35397
+ return;
35398
+ }
35399
+ if (targetElement.closest("textarea, input") || targetElement.closest("[data-docx-header-footer-region]")) {
35400
+ return;
35401
+ }
35402
+ const intent = resolveEditingIntent({
35403
+ inputType: event.inputType,
35404
+ data: event.data,
35405
+ dataTransferText: event.dataTransfer?.getData("text/plain")
35406
+ });
35407
+ if (!intent) {
35408
+ return;
35409
+ }
35410
+ const resolveTargetRangeOffsets = (element) => {
35411
+ const targetRange = typeof event.getTargetRanges === "function" ? event.getTargetRanges()[0] : void 0;
35412
+ return targetRange ? staticRangeOffsetsWithinElementDom(element, targetRange) : void 0;
35413
+ };
35414
+ const paragraphHost = targetElement.closest(
35415
+ "[data-docx-paragraph-host='true'][data-docx-paragraph-kind='paragraph']"
35416
+ );
35417
+ if (paragraphHost) {
35418
+ if (!paragraphHost.isContentEditable) {
35419
+ return;
35420
+ }
35421
+ const nodeIndexAttr = paragraphHost.getAttribute(
35422
+ "data-docx-paragraph-node-index"
35423
+ );
35424
+ const nodeIndex = nodeIndexAttr != null ? Number.parseInt(nodeIndexAttr, 10) : Number.NaN;
35425
+ const node = Number.isFinite(nodeIndex) ? editor.model.nodes[nodeIndex] : void 0;
35426
+ if (!node || node.type !== "paragraph") {
35427
+ return;
35428
+ }
35429
+ event.preventDefault();
35430
+ cancelPendingPointerSelectionReconcile();
35431
+ if (intent.kind === "blocked") {
35432
+ return;
35433
+ }
35434
+ if (intent.kind === "historyUndo") {
35435
+ editor.undo();
35436
+ return;
35437
+ }
35438
+ if (intent.kind === "historyRedo") {
35439
+ editor.redo();
35440
+ return;
35441
+ }
35442
+ const location = { kind: "paragraph", nodeIndex };
35443
+ const continuationKey = `p:${nodeIndex}`;
35444
+ const domText = editableTextFromElement(paragraphHost);
35445
+ const continuation2 = editingIntentContinuationRef.current;
35446
+ const continuationActive2 = Boolean(
35447
+ continuation2 && continuation2.key === continuationKey && continuation2.text !== domText
35448
+ );
35449
+ const currentText2 = continuationActive2 && continuation2 ? continuation2.text : domText;
35450
+ let selectionOffsets2 = continuationActive2 && continuation2 ? { start: continuation2.caret, end: continuation2.caret } : selectionOffsetsWithinElement(paragraphHost);
35451
+ if (!selectionOffsets2) {
35452
+ const activeRange = editor.activeTextRange ? normalizeTextRange(editor.activeTextRange) : void 0;
35453
+ if (activeRange && sameParagraphLocation(activeRange.start.location, location) && sameParagraphLocation(activeRange.end.location, location)) {
35454
+ const safeStart = Math.max(
35455
+ 0,
35456
+ Math.min(
35457
+ Math.round(activeRange.start.offset),
35458
+ currentText2.length
35459
+ )
35460
+ );
35461
+ selectionOffsets2 = {
35462
+ start: safeStart,
35463
+ end: Math.max(
35464
+ safeStart,
35465
+ Math.min(
35466
+ Math.round(activeRange.end.offset),
35467
+ currentText2.length
35468
+ )
35469
+ )
35470
+ };
35471
+ }
35472
+ }
35473
+ if (!selectionOffsets2) {
35474
+ selectionOffsets2 = {
35475
+ start: currentText2.length,
35476
+ end: currentText2.length
35477
+ };
35478
+ }
35479
+ if (intent.kind === "insertParagraph") {
35480
+ editingIntentContinuationRef.current = void 0;
35481
+ const start = Math.max(
35482
+ 0,
35483
+ Math.min(selectionOffsets2.start, currentText2.length)
35484
+ );
35485
+ const end = Math.max(
35486
+ start,
35487
+ Math.min(selectionOffsets2.end, currentText2.length)
35488
+ );
35489
+ tableCellDraftsRef.current.clear();
35490
+ tableCellParagraphDraftsRef.current.clear();
35491
+ if (paragraphIsList(node, currentText2)) {
35492
+ const insertedListItem = editor.insertListItemAfterSelection(
35493
+ currentText2,
35494
+ start,
35495
+ end,
35496
+ location
35497
+ );
35498
+ if (insertedListItem !== void 0) {
35499
+ focusParagraphAtOffset(
35500
+ insertedListItem.paragraphIndex,
35501
+ insertedListItem.caretOffset
35502
+ );
35503
+ }
35504
+ return;
35505
+ }
35506
+ const splitParagraph = editor.splitParagraphAtSelection(
35507
+ currentText2,
35508
+ start,
35509
+ end,
35510
+ location
35511
+ );
35512
+ if (splitParagraph !== void 0) {
35513
+ focusParagraphAtOffset(
35514
+ splitParagraph.paragraphIndex,
35515
+ splitParagraph.caretOffset
35516
+ );
35517
+ }
35518
+ return;
35519
+ }
35520
+ if (intent.kind === "deleteContent" || intent.kind === "deleteRange") {
35521
+ const activeRange = editor.activeTextRange ? normalizeTextRange(editor.activeTextRange) : void 0;
35522
+ const expandedBeyondParagraph = Boolean(
35523
+ activeRange && compareTextRangeBoundaries(activeRange.start, activeRange.end) < 0 && !(sameParagraphLocation(activeRange.start.location, location) && sameParagraphLocation(activeRange.end.location, location))
35524
+ );
35525
+ if (expandedBeyondParagraph && activeRange) {
35526
+ editingIntentContinuationRef.current = void 0;
35527
+ const collapsedRange = editor.deleteExpandedSelection(activeRange);
35528
+ if (collapsedRange) {
35529
+ tableCellDraftsRef.current.clear();
35530
+ tableCellParagraphDraftsRef.current.clear();
35531
+ syncSelectionFromDocxRange(collapsedRange);
35532
+ }
35533
+ return;
35534
+ }
35535
+ }
35536
+ const rangeOffsets2 = !continuationActive2 && (intent.kind === "insertText" || intent.kind === "replaceText" || intent.kind === "insertLineBreak" || intent.kind === "deleteContent" || intent.kind === "deleteRange") ? resolveTargetRangeOffsets(paragraphHost) ?? selectionOffsets2 : selectionOffsets2;
35537
+ const applied2 = applyTextEditingIntent(
35538
+ currentText2,
35539
+ rangeOffsets2.start,
35540
+ rangeOffsets2.end,
35541
+ intent
35542
+ );
35543
+ if (!applied2) {
35544
+ if (intent.kind === "deleteContent" && rangeOffsets2.start === rangeOffsets2.end) {
35545
+ if (intent.direction === "backward" && rangeOffsets2.start === 0) {
35546
+ editingIntentContinuationRef.current = void 0;
35547
+ let previousLocation;
35548
+ for (let scanNodeIndex = nodeIndex - 1; scanNodeIndex >= 0; scanNodeIndex -= 1) {
35549
+ const candidate = lastParagraphLocationInNode(
35550
+ editor.model,
35551
+ scanNodeIndex
35552
+ );
35553
+ if (candidate) {
35554
+ previousLocation = candidate;
35555
+ break;
35556
+ }
35557
+ }
35558
+ const previousParagraph = previousLocation ? getParagraphAtLocation(editor.model, previousLocation).paragraph : void 0;
35559
+ if (previousLocation && previousParagraph) {
35560
+ const collapsedRange = editor.deleteExpandedSelection({
35561
+ start: {
35562
+ location: cloneTextRangeLocation(previousLocation),
35563
+ offset: paragraphText(previousParagraph).length
35564
+ },
35565
+ end: {
35566
+ location: cloneTextRangeLocation(location),
35567
+ offset: 0
35568
+ }
35569
+ });
35570
+ if (collapsedRange) {
35571
+ syncSelectionFromDocxRange(collapsedRange);
35572
+ }
35573
+ }
35574
+ return;
35575
+ }
35576
+ if (intent.direction === "forward" && rangeOffsets2.start >= currentText2.length) {
35577
+ editingIntentContinuationRef.current = void 0;
35578
+ const nextLocation = nextParagraphLocation(
35579
+ editor.model,
35580
+ location
35581
+ );
35582
+ const nextParagraph = nextLocation ? getParagraphAtLocation(editor.model, nextLocation).paragraph : void 0;
35583
+ if (nextLocation && nextParagraph) {
35584
+ const collapsedRange = editor.deleteExpandedSelection({
35585
+ start: {
35586
+ location: cloneTextRangeLocation(location),
35587
+ offset: currentText2.length
35588
+ },
35589
+ end: {
35590
+ location: cloneTextRangeLocation(nextLocation),
35591
+ offset: 0
35592
+ }
35593
+ });
35594
+ if (collapsedRange) {
35595
+ syncSelectionFromDocxRange(collapsedRange);
35596
+ }
35597
+ }
35598
+ return;
35599
+ }
35600
+ }
35601
+ return;
35602
+ }
35603
+ const coalesceClass2 = editingIntentCoalesceClass(intent);
35604
+ editor.commitParagraphTextAtRange(
35605
+ location,
35606
+ applied2.text,
35607
+ { start: applied2.caret, end: applied2.caret },
35608
+ {
35609
+ insertionOffset: rangeOffsets2.start,
35610
+ ...coalesceClass2 ? { coalesceKey: `p:${nodeIndex}:${coalesceClass2}` } : void 0
35611
+ }
35612
+ );
35613
+ editingIntentContinuationRef.current = {
35614
+ key: continuationKey,
35615
+ text: applied2.text,
35616
+ caret: applied2.caret
35617
+ };
35618
+ pendingEditableCaretRef.current = {
35619
+ nodeIndex,
35620
+ start: applied2.caret,
35621
+ end: applied2.caret
35622
+ };
35623
+ schedulePaginationMeasurementResume();
35624
+ return;
35625
+ }
35626
+ const cellHost = targetElement.closest(
35627
+ "[data-docx-cell-key]"
35628
+ );
35629
+ if (!cellHost || !cellHost.isContentEditable) {
35630
+ return;
35631
+ }
35632
+ const cellKeyMatch = /^cell-(\d+)-(\d+)-(\d+)$/.exec(
35633
+ cellHost.getAttribute("data-docx-cell-key") ?? ""
35634
+ );
35635
+ if (!cellKeyMatch) {
35636
+ return;
35637
+ }
35638
+ const tableIndex = Number.parseInt(cellKeyMatch[1], 10);
35639
+ const rowIndex = Number.parseInt(cellKeyMatch[2], 10);
35640
+ const cellIndex = Number.parseInt(cellKeyMatch[3], 10);
35641
+ const tableNode = editor.model.nodes[tableIndex];
35642
+ if (!tableNode || tableNode.type !== "table") {
35643
+ return;
35644
+ }
35645
+ const cell = tableNode.rows[rowIndex]?.cells[cellIndex];
35646
+ if (!cell) {
35647
+ return;
35648
+ }
35649
+ if (cell.nodes.some((cellContent) => cellContent.type === "table")) {
35650
+ return;
35651
+ }
35652
+ event.preventDefault();
35653
+ cancelPendingPointerSelectionReconcile();
35654
+ if (intent.kind === "blocked") {
35655
+ return;
35656
+ }
35657
+ if (intent.kind === "historyUndo") {
35658
+ editor.undo();
35659
+ return;
35660
+ }
35661
+ if (intent.kind === "historyRedo") {
35662
+ editor.redo();
35663
+ return;
35664
+ }
35665
+ const cellParagraphNodes = tableCellParagraphs(cell.nodes);
35666
+ const context = activeTableCellParagraphContext(cellHost);
35667
+ const continuation = editingIntentContinuationRef.current;
35668
+ const continuationPrefix = `c:${tableIndex}:${rowIndex}:${cellIndex}:`;
35669
+ let continuationActive = false;
35670
+ let paragraphIndex = context?.paragraphIndex;
35671
+ let paragraphElement = context?.paragraphElement;
35672
+ if (continuation && continuation.key.startsWith(continuationPrefix)) {
35673
+ const continuationParagraphIndex = Number.parseInt(
35674
+ continuation.key.slice(continuationPrefix.length),
35675
+ 10
35676
+ );
35677
+ const continuationElement = Number.isFinite(continuationParagraphIndex) ? cellHost.querySelector(
35678
+ `[data-docx-table-paragraph-index='${continuationParagraphIndex}']`
35679
+ ) ?? void 0 : void 0;
35680
+ if (continuationElement && continuation.text !== editableTextFromElement(continuationElement)) {
35681
+ continuationActive = true;
35682
+ paragraphIndex = continuationParagraphIndex;
35683
+ paragraphElement = continuationElement;
35684
+ }
35685
+ }
35686
+ let rangeSelectionOffsets;
35687
+ if (paragraphIndex === void 0 || !paragraphElement) {
35688
+ const activeRange = editor.activeTextRange ? normalizeTextRange(editor.activeTextRange) : void 0;
35689
+ const startLocation = activeRange?.start.location;
35690
+ if (activeRange && startLocation && startLocation.kind === "table-cell" && startLocation.tableIndex === tableIndex && startLocation.rowIndex === rowIndex && startLocation.cellIndex === cellIndex && sameParagraphLocation(startLocation, activeRange.end.location)) {
35691
+ const rangeParagraphElement = cellHost.querySelector(
35692
+ `[data-docx-table-paragraph-index='${startLocation.paragraphIndex}']`
35693
+ ) ?? void 0;
35694
+ if (rangeParagraphElement) {
35695
+ paragraphIndex = startLocation.paragraphIndex;
35696
+ paragraphElement = rangeParagraphElement;
35697
+ rangeSelectionOffsets = {
35698
+ start: Math.max(0, Math.round(activeRange.start.offset)),
35699
+ end: Math.max(0, Math.round(activeRange.end.offset))
35700
+ };
35701
+ }
35702
+ }
35703
+ }
35704
+ if (paragraphIndex === void 0 || !paragraphElement || !cellParagraphNodes[paragraphIndex]) {
35705
+ return;
35706
+ }
35707
+ const cellLocation = {
35708
+ kind: "table-cell",
35709
+ tableIndex,
35710
+ rowIndex,
35711
+ cellIndex,
35712
+ paragraphIndex
35713
+ };
35714
+ const currentText = continuationActive && continuation ? continuation.text : editableTextFromElement(paragraphElement);
35715
+ const selectionOffsets = continuationActive && continuation ? { start: continuation.caret, end: continuation.caret } : rangeSelectionOffsets ?? selectionOffsetsWithinElement(paragraphElement) ?? {
35716
+ start: currentText.length,
35717
+ end: currentText.length
35718
+ };
35719
+ if (intent.kind === "deleteContent" || intent.kind === "deleteRange") {
35720
+ const activeRange = editor.activeTextRange ? normalizeTextRange(editor.activeTextRange) : void 0;
35721
+ const expandedBeyondParagraph = Boolean(
35722
+ activeRange && compareTextRangeBoundaries(activeRange.start, activeRange.end) < 0 && !(sameParagraphLocation(activeRange.start.location, cellLocation) && sameParagraphLocation(activeRange.end.location, cellLocation))
35723
+ );
35724
+ if (expandedBeyondParagraph && activeRange) {
35725
+ editingIntentContinuationRef.current = void 0;
35726
+ const collapsedRange = editor.deleteExpandedSelection(activeRange);
35727
+ if (collapsedRange) {
35728
+ tableCellDraftsRef.current.clear();
35729
+ tableCellParagraphDraftsRef.current.clear();
35730
+ syncSelectionFromDocxRange(collapsedRange);
35731
+ }
35732
+ return;
35733
+ }
35734
+ }
35735
+ const effectiveIntent = intent.kind === "insertParagraph" ? { kind: "insertLineBreak" } : intent;
35736
+ const rangeOffsets = !continuationActive && (effectiveIntent.kind === "insertText" || effectiveIntent.kind === "replaceText" || effectiveIntent.kind === "insertLineBreak" || effectiveIntent.kind === "deleteContent" || effectiveIntent.kind === "deleteRange") ? resolveTargetRangeOffsets(paragraphElement) ?? selectionOffsets : selectionOffsets;
35737
+ const applied = applyTextEditingIntent(
35738
+ currentText,
35739
+ rangeOffsets.start,
35740
+ rangeOffsets.end,
35741
+ effectiveIntent
35742
+ );
35743
+ if (!applied) {
35744
+ if (effectiveIntent.kind === "deleteContent" && rangeOffsets.start === rangeOffsets.end) {
35745
+ const paragraphTexts = cellParagraphNodes.map(
35746
+ (cellParagraph, cellParagraphIndex) => cellParagraphIndex === paragraphIndex ? currentText : paragraphText(cellParagraph)
35747
+ );
35748
+ const mergeBoundaryIndex = effectiveIntent.direction === "backward" && rangeOffsets.start === 0 ? paragraphIndex : effectiveIntent.direction === "forward" && rangeOffsets.start >= currentText.length ? paragraphIndex + 1 : void 0;
35749
+ const merged = mergeBoundaryIndex !== void 0 ? mergeCellParagraphTexts(paragraphTexts, mergeBoundaryIndex) : void 0;
35750
+ if (merged) {
35751
+ editingIntentContinuationRef.current = void 0;
35752
+ editor.commitTableCellTextAtRange(
35753
+ tableIndex,
35754
+ rowIndex,
35755
+ cellIndex,
35756
+ merged.cellText,
35757
+ {
35758
+ paragraphIndex: merged.caretParagraphIndex,
35759
+ start: merged.caretOffset,
35760
+ end: merged.caretOffset
35761
+ }
35762
+ );
35763
+ schedulePaginationMeasurementResume();
35764
+ }
35765
+ }
35766
+ return;
35767
+ }
35768
+ const coalesceClass = editingIntentCoalesceClass(effectiveIntent);
35769
+ editor.commitParagraphTextAtRange(
35770
+ cellLocation,
35771
+ applied.text,
35772
+ { start: applied.caret, end: applied.caret },
35773
+ {
35774
+ insertionOffset: rangeOffsets.start,
35775
+ ...coalesceClass ? {
35776
+ coalesceKey: `${continuationPrefix}${paragraphIndex}:${coalesceClass}`
35777
+ } : void 0
35778
+ }
35779
+ );
35780
+ editingIntentContinuationRef.current = {
35781
+ key: `${continuationPrefix}${paragraphIndex}`,
35782
+ text: applied.text,
35783
+ caret: applied.caret
35784
+ };
35785
+ schedulePaginationMeasurementResume();
35786
+ },
35787
+ [
35788
+ activeTableCellParagraphContext,
35789
+ cancelPendingPointerSelectionReconcile,
35790
+ editor,
35791
+ focusParagraphAtOffset,
35792
+ isReadOnly,
35793
+ schedulePaginationMeasurementResume,
35794
+ selectionOffsetsWithinElement,
35795
+ syncSelectionFromDocxRange
35796
+ ]
35797
+ );
35798
+ React.useEffect(() => {
35799
+ const rootElement = viewerRootRef.current;
35800
+ if (!rootElement) {
35801
+ return;
35802
+ }
35803
+ const handleBeforeInput = (event) => {
35804
+ handleEditableHostBeforeInput(event);
35805
+ };
35806
+ rootElement.addEventListener("beforeinput", handleBeforeInput);
35807
+ return () => {
35808
+ rootElement.removeEventListener("beforeinput", handleBeforeInput);
35809
+ };
35810
+ }, [handleEditableHostBeforeInput]);
33952
35811
  const resolveTableColumnWidths = React.useCallback(
33953
35812
  (tableIndex, table, tableWidthPx) => {
33954
35813
  const columnCount = tableColumnCount(table);
@@ -34150,7 +36009,7 @@ function DocxEditorViewer({
34150
36009
  docGridLinePitchPxByNodeIndex.get(nodeIndex),
34151
36010
  pageContentHeightPxByNodeIndex.get(nodeIndex)
34152
36011
  );
34153
- const previousMeasuredRowHeights = tableMeasuredRowHeights[nodeIndex];
36012
+ const previousMeasuredRowHeights = node.blockId ? tableMeasuredRowHeights[node.blockId]?.rowHeightsPx : void 0;
34154
36013
  const measuredHeights = node.rows.map((_, rowIndex) => {
34155
36014
  const measuredHeight = measuredByRowIndex.get(rowIndex);
34156
36015
  if (measuredHeight !== void 0) {
@@ -34169,35 +36028,46 @@ function DocxEditorViewer({
34169
36028
  setTableMeasuredRowHeights((current) => {
34170
36029
  let changed = false;
34171
36030
  const next = {};
34172
- Object.entries(current).forEach(([tableIndexText, heights]) => {
34173
- const tableIndex = Number.parseInt(tableIndexText, 10);
34174
- const tableNode = editor.model.nodes[tableIndex];
34175
- if (!tableNode || tableNode.type !== "table") {
34176
- changed = true;
34177
- return;
36031
+ const tableNodesByBlockId = /* @__PURE__ */ new Map();
36032
+ const tableBlockIdsByNodeIndex = /* @__PURE__ */ new Map();
36033
+ editor.model.nodes.forEach((node, nodeIndex) => {
36034
+ if (node.type === "table" && node.blockId) {
36035
+ tableNodesByBlockId.set(node.blockId, node);
36036
+ tableBlockIdsByNodeIndex.set(nodeIndex, node.blockId);
34178
36037
  }
34179
- if (!Array.isArray(heights) || heights.length !== tableNode.rows.length) {
36038
+ });
36039
+ Object.entries(current).forEach(([blockId, entry]) => {
36040
+ const tableNode = tableNodesByBlockId.get(blockId);
36041
+ if (!tableNode || !Array.isArray(entry.rowHeightsPx) || entry.rowHeightsPx.length !== tableNode.rows.length) {
34180
36042
  changed = true;
34181
36043
  return;
34182
36044
  }
34183
- next[tableIndex] = heights;
36045
+ next[blockId] = entry;
34184
36046
  });
34185
36047
  Object.entries(nextMeasuredHeights).forEach(
34186
36048
  ([tableIndexText, measuredHeights]) => {
34187
36049
  const tableIndex = Number.parseInt(tableIndexText, 10);
34188
- const currentHeights = next[tableIndex] ?? [];
34189
- if (currentHeights.length !== measuredHeights.length) {
34190
- next[tableIndex] = measuredHeights;
34191
- changed = true;
36050
+ const blockId = tableBlockIdsByNodeIndex.get(tableIndex);
36051
+ const tableNode = blockId ? tableNodesByBlockId.get(blockId) : void 0;
36052
+ if (!blockId || !tableNode) {
34192
36053
  return;
34193
36054
  }
34194
- for (let index = 0; index < measuredHeights.length; index += 1) {
34195
- if (currentHeights[index] !== measuredHeights[index]) {
34196
- next[tableIndex] = measuredHeights;
34197
- changed = true;
34198
- return;
36055
+ const contentSignature = docNodeContentSignature(tableNode);
36056
+ const currentEntry = next[blockId];
36057
+ const currentHeights = currentEntry?.rowHeightsPx ?? [];
36058
+ let heightsChanged = currentHeights.length !== measuredHeights.length;
36059
+ if (!heightsChanged) {
36060
+ for (let index = 0; index < measuredHeights.length; index += 1) {
36061
+ if (currentHeights[index] !== measuredHeights[index]) {
36062
+ heightsChanged = true;
36063
+ break;
36064
+ }
34199
36065
  }
34200
36066
  }
36067
+ if (heightsChanged || currentEntry?.contentSignature !== contentSignature) {
36068
+ next[blockId] = { rowHeightsPx: measuredHeights, contentSignature };
36069
+ changed = true;
36070
+ }
34201
36071
  }
34202
36072
  );
34203
36073
  return changed ? next : current;
@@ -34708,27 +36578,72 @@ function DocxEditorViewer({
34708
36578
  "[data-docx-paragraph-host='true']"
34709
36579
  );
34710
36580
  const paragraphRect = paragraphHost?.getBoundingClientRect();
36581
+ const zoomScale = resolveViewerMeasurementZoomScale(wrapperElement, 1);
34711
36582
  const baseFloating = image.floating ? { ...image.floating } : {};
36583
+ const dragStartAnchor = isWrappedFloatingImage && location.kind === "paragraph" ? resolveWrappedDropAnchorParagraphHost(
36584
+ wrapperElement,
36585
+ wrapperRect.top,
36586
+ wrapperRect.left
36587
+ ) : void 0;
34712
36588
  let latestDeltaX = 0;
34713
36589
  let latestDeltaY = 0;
34714
36590
  let frameId;
34715
36591
  let inlineDragActivated = false;
34716
36592
  let latestInlineDropTarget;
34717
36593
  let latestInlineDropTargetKey;
36594
+ const measuredBands = (() => {
36595
+ if (!isWrappedFloatingImage || !pageSurface || !pageSurfaceRect) {
36596
+ return void 0;
36597
+ }
36598
+ const hostByNodeIndex = {};
36599
+ for (const host of Array.from(
36600
+ pageSurface.querySelectorAll(
36601
+ "[data-docx-paragraph-host='true'][data-docx-paragraph-kind='paragraph'][data-docx-paragraph-node-index]"
36602
+ )
36603
+ )) {
36604
+ const nodeIndex = Number.parseInt(
36605
+ host.getAttribute("data-docx-paragraph-node-index") ?? "",
36606
+ 10
36607
+ );
36608
+ if (!Number.isFinite(nodeIndex)) {
36609
+ continue;
36610
+ }
36611
+ const rect = host.getBoundingClientRect();
36612
+ if (rect.height <= 0) {
36613
+ continue;
36614
+ }
36615
+ hostByNodeIndex[nodeIndex] = {
36616
+ topPx: (rect.top - pageSurfaceRect.top) / zoomScale,
36617
+ bottomPx: (rect.bottom - pageSurfaceRect.top) / zoomScale
36618
+ };
36619
+ }
36620
+ return Object.keys(hostByNodeIndex).length > 0 ? { hostByNodeIndex } : void 0;
36621
+ })();
34718
36622
  const updatePreview = () => {
34719
36623
  setFloatingMovePreview({
34720
36624
  imageKey,
34721
36625
  deltaX: latestDeltaX,
34722
36626
  deltaY: latestDeltaY,
36627
+ measuredBands,
34723
36628
  ...paragraphRect ? {
34724
- baseLeftPx: Math.round(wrapperRect.left - paragraphRect.left),
34725
- baseTopPx: Math.round(wrapperRect.top - paragraphRect.top)
36629
+ baseLeftPx: Math.round(
36630
+ (wrapperRect.left - paragraphRect.left) / zoomScale
36631
+ ),
36632
+ baseTopPx: Math.round(
36633
+ (wrapperRect.top - paragraphRect.top) / zoomScale
36634
+ )
34726
36635
  } : void 0
34727
36636
  });
34728
36637
  };
34729
36638
  const onPointerMove = (pointerEvent) => {
34730
- latestDeltaX = pointerEvent.clientX - startX;
34731
- latestDeltaY = pointerEvent.clientY - startY;
36639
+ latestDeltaX = normalizeFloatingDragDeltaForZoom(
36640
+ pointerEvent.clientX - startX,
36641
+ zoomScale
36642
+ );
36643
+ latestDeltaY = normalizeFloatingDragDeltaForZoom(
36644
+ pointerEvent.clientY - startY,
36645
+ zoomScale
36646
+ );
34732
36647
  if (isInlineImage) {
34733
36648
  if (!inlineDragActivated) {
34734
36649
  const movementDistancePx = Math.abs(latestDeltaX) + Math.abs(latestDeltaY);
@@ -34805,9 +36720,9 @@ function DocxEditorViewer({
34805
36720
  return;
34806
36721
  }
34807
36722
  if (isWrappedFloatingImage) {
34808
- const hostWidth = paragraphRect?.width ?? DEFAULT_DOC_PAGE_WIDTH;
34809
- const imageWidth = image.widthPx ?? Math.max(24, Math.round(wrapperRect.width));
34810
- const imageHeight = image.heightPx ?? Math.max(24, Math.round(wrapperRect.height));
36723
+ const hostWidth = paragraphRect ? paragraphRect.width / zoomScale : DEFAULT_DOC_PAGE_WIDTH;
36724
+ const imageWidth = image.widthPx ?? Math.max(24, Math.round(wrapperRect.width / zoomScale));
36725
+ const imageHeight = image.heightPx ?? Math.max(24, Math.round(wrapperRect.height / zoomScale));
34811
36726
  const baseGeometry = resolveDualWrappedFloatingImageGeometry(
34812
36727
  image,
34813
36728
  hostWidth,
@@ -34816,9 +36731,11 @@ function DocxEditorViewer({
34816
36731
  heightPx: imageHeight,
34817
36732
  ...paragraphRect ? {
34818
36733
  baseLeftPx: Math.round(
34819
- wrapperRect.left - paragraphRect.left
36734
+ (wrapperRect.left - paragraphRect.left) / zoomScale
34820
36735
  ),
34821
- baseTopPx: Math.round(wrapperRect.top - paragraphRect.top)
36736
+ baseTopPx: Math.round(
36737
+ (wrapperRect.top - paragraphRect.top) / zoomScale
36738
+ )
34822
36739
  } : void 0
34823
36740
  }
34824
36741
  );
@@ -34830,6 +36747,46 @@ function DocxEditorViewer({
34830
36747
  const movedTop = Math.round(
34831
36748
  (baseGeometry?.imageTopPx ?? 0) + latestDeltaY
34832
36749
  );
36750
+ const droppedTopScreenPx = wrapperRect.top + latestDeltaY * zoomScale;
36751
+ const droppedLeftScreenPx = wrapperRect.left + latestDeltaX * zoomScale;
36752
+ const dropAnchor = location.kind === "paragraph" && wrappedDragCanReanchorToParagraph(baseFloating) ? resolveWrappedDropAnchorParagraphHost(
36753
+ wrapperElement,
36754
+ droppedTopScreenPx,
36755
+ droppedLeftScreenPx
36756
+ ) : void 0;
36757
+ if (dropAnchor && location.kind === "paragraph" && dropAnchor.nodeIndex !== location.nodeIndex && dropAnchor.nodeIndex !== dragStartAnchor?.nodeIndex) {
36758
+ const targetHostWidth = dropAnchor.rect.width / zoomScale;
36759
+ const targetMovedLeft = clampNumber(
36760
+ Math.round(
36761
+ (droppedLeftScreenPx - dropAnchor.rect.left) / zoomScale
36762
+ ),
36763
+ 0,
36764
+ Math.max(0, targetHostWidth - imageWidth)
36765
+ );
36766
+ const targetMovedTop = Math.round(
36767
+ (droppedTopScreenPx - dropAnchor.rect.top) / zoomScale
36768
+ );
36769
+ editor.moveFloatingImage(
36770
+ location,
36771
+ resolveWrappedFloatingImageDropPatch(
36772
+ image,
36773
+ targetHostWidth,
36774
+ targetMovedLeft,
36775
+ targetMovedTop,
36776
+ {
36777
+ widthPx: imageWidth,
36778
+ heightPx: imageHeight
36779
+ }
36780
+ ),
36781
+ { reparentToParagraphNodeIndex: dropAnchor.nodeIndex }
36782
+ );
36783
+ setSelectedImage({
36784
+ kind: "paragraph",
36785
+ nodeIndex: dropAnchor.nodeIndex,
36786
+ childIndex: 0
36787
+ });
36788
+ return;
36789
+ }
34833
36790
  editor.moveFloatingImage(
34834
36791
  location,
34835
36792
  resolveWrappedFloatingImageDropPatch(
@@ -34846,14 +36803,21 @@ function DocxEditorViewer({
34846
36803
  return;
34847
36804
  }
34848
36805
  if (isAbsoluteFloatingImage) {
36806
+ const dropPageSurfaceRect = pageSurface && pageSurface.isConnected ? pageSurface.getBoundingClientRect() : pageSurfaceRect;
34849
36807
  editor.moveFloatingImage(
34850
36808
  location,
34851
36809
  resolveAbsoluteFloatingImageDropPatch(
34852
36810
  baseFloating,
34853
36811
  documentLayout,
34854
36812
  {
34855
- wrapperRect,
34856
- pageSurfaceRect,
36813
+ wrapperRect: normalizeFloatingDropRectForZoom(
36814
+ wrapperRect,
36815
+ zoomScale
36816
+ ),
36817
+ pageSurfaceRect: dropPageSurfaceRect ? normalizeFloatingDropRectForZoom(
36818
+ dropPageSurfaceRect,
36819
+ zoomScale
36820
+ ) : void 0,
34857
36821
  deltaX: latestDeltaX,
34858
36822
  deltaY: latestDeltaY
34859
36823
  }
@@ -34866,7 +36830,7 @@ function DocxEditorViewer({
34866
36830
  window.addEventListener("pointerup", onPointerUp, { once: true });
34867
36831
  window.addEventListener("pointercancel", onPointerUp, { once: true });
34868
36832
  },
34869
- [documentLayout, editor, isReadOnly]
36833
+ [documentLayout, editor, isReadOnly, resolveViewerMeasurementZoomScale]
34870
36834
  );
34871
36835
  const beginDropCapMove = React.useCallback(
34872
36836
  (event, nodeIndex, dropCap) => {
@@ -35003,6 +36967,7 @@ function DocxEditorViewer({
35003
36967
  "[data-docx-section-paragraph-host='true']"
35004
36968
  );
35005
36969
  const paragraphRect = paragraphHost?.getBoundingClientRect();
36970
+ const zoomScale = resolveViewerMeasurementZoomScale(wrapperElement, 1);
35006
36971
  const baseFloating = image.floating ? { ...image.floating } : {};
35007
36972
  let latestDeltaX = 0;
35008
36973
  let latestDeltaY = 0;
@@ -35013,14 +36978,24 @@ function DocxEditorViewer({
35013
36978
  deltaX: latestDeltaX,
35014
36979
  deltaY: latestDeltaY,
35015
36980
  ...paragraphRect ? {
35016
- baseLeftPx: Math.round(wrapperRect.left - paragraphRect.left),
35017
- baseTopPx: Math.round(wrapperRect.top - paragraphRect.top)
36981
+ baseLeftPx: Math.round(
36982
+ (wrapperRect.left - paragraphRect.left) / zoomScale
36983
+ ),
36984
+ baseTopPx: Math.round(
36985
+ (wrapperRect.top - paragraphRect.top) / zoomScale
36986
+ )
35018
36987
  } : void 0
35019
36988
  });
35020
36989
  };
35021
36990
  const onPointerMove = (pointerEvent) => {
35022
- latestDeltaX = pointerEvent.clientX - startX;
35023
- latestDeltaY = pointerEvent.clientY - startY;
36991
+ latestDeltaX = normalizeFloatingDragDeltaForZoom(
36992
+ pointerEvent.clientX - startX,
36993
+ zoomScale
36994
+ );
36995
+ latestDeltaY = normalizeFloatingDragDeltaForZoom(
36996
+ pointerEvent.clientY - startY,
36997
+ zoomScale
36998
+ );
35024
36999
  if (frameId !== void 0) {
35025
37000
  window.cancelAnimationFrame(frameId);
35026
37001
  }
@@ -35038,9 +37013,9 @@ function DocxEditorViewer({
35038
37013
  return;
35039
37014
  }
35040
37015
  if (isWrappedFloatingImage) {
35041
- const hostWidth = paragraphRect?.width ?? documentLayout.pageWidthPx;
35042
- const imageWidth = image.widthPx ?? Math.max(24, Math.round(wrapperRect.width));
35043
- const imageHeight = image.heightPx ?? Math.max(24, Math.round(wrapperRect.height));
37016
+ const hostWidth = paragraphRect ? paragraphRect.width / zoomScale : documentLayout.pageWidthPx;
37017
+ const imageWidth = image.widthPx ?? Math.max(24, Math.round(wrapperRect.width / zoomScale));
37018
+ const imageHeight = image.heightPx ?? Math.max(24, Math.round(wrapperRect.height / zoomScale));
35044
37019
  const baseGeometry = resolveDualWrappedFloatingImageGeometry(
35045
37020
  image,
35046
37021
  hostWidth,
@@ -35049,9 +37024,11 @@ function DocxEditorViewer({
35049
37024
  heightPx: imageHeight,
35050
37025
  ...paragraphRect ? {
35051
37026
  baseLeftPx: Math.round(
35052
- wrapperRect.left - paragraphRect.left
37027
+ (wrapperRect.left - paragraphRect.left) / zoomScale
35053
37028
  ),
35054
- baseTopPx: Math.round(wrapperRect.top - paragraphRect.top)
37029
+ baseTopPx: Math.round(
37030
+ (wrapperRect.top - paragraphRect.top) / zoomScale
37031
+ )
35055
37032
  } : void 0
35056
37033
  }
35057
37034
  );
@@ -35081,14 +37058,21 @@ function DocxEditorViewer({
35081
37058
  return;
35082
37059
  }
35083
37060
  if (isAbsoluteFloatingImage) {
37061
+ const dropPageSurfaceRect = pageSurface && pageSurface.isConnected ? pageSurface.getBoundingClientRect() : pageSurfaceRect;
35084
37062
  editor.moveSectionFloatingImage(
35085
37063
  location,
35086
37064
  resolveAbsoluteFloatingImageDropPatch(
35087
37065
  baseFloating,
35088
37066
  documentLayout,
35089
37067
  {
35090
- wrapperRect,
35091
- pageSurfaceRect,
37068
+ wrapperRect: normalizeFloatingDropRectForZoom(
37069
+ wrapperRect,
37070
+ zoomScale
37071
+ ),
37072
+ pageSurfaceRect: dropPageSurfaceRect ? normalizeFloatingDropRectForZoom(
37073
+ dropPageSurfaceRect,
37074
+ zoomScale
37075
+ ) : void 0,
35092
37076
  deltaX: latestDeltaX,
35093
37077
  deltaY: latestDeltaY
35094
37078
  }
@@ -35100,7 +37084,13 @@ function DocxEditorViewer({
35100
37084
  window.addEventListener("pointerup", onPointerUp, { once: true });
35101
37085
  window.addEventListener("pointercancel", onPointerUp, { once: true });
35102
37086
  },
35103
- [activeHeaderFooterEdit, documentLayout, editor, isReadOnly]
37087
+ [
37088
+ activeHeaderFooterEdit,
37089
+ documentLayout,
37090
+ editor,
37091
+ isReadOnly,
37092
+ resolveViewerMeasurementZoomScale
37093
+ ]
35104
37094
  );
35105
37095
  const onSectionImageClick = React.useCallback(
35106
37096
  (location) => {
@@ -35767,6 +37757,10 @@ function DocxEditorViewer({
35767
37757
  display: "inline-block",
35768
37758
  whiteSpace: "pre",
35769
37759
  lineHeight: `${lineHeightPx}px`,
37760
+ // Each fragment is its own block, so an inherited paragraph
37761
+ // text-indent would shift every fragment past its computed
37762
+ // interval; the layout reserves first-line indent itself.
37763
+ textIndent: 0,
35770
37764
  pointerEvents: activeSession ? "none" : void 0
35771
37765
  },
35772
37766
  children: pieces
@@ -36013,15 +38007,24 @@ function DocxEditorViewer({
36013
38007
  "aria-label": "Wrapped paragraph text",
36014
38008
  onChange: (event) => {
36015
38009
  cancelPendingPointerSelectionReconcile();
36016
- editor.beginSelectionSession("keyboard", {
36017
- settleAfterMs: 220
36018
- });
36019
38010
  const nextText = event.currentTarget.value.replace(
36020
38011
  /\r\n?/g,
36021
38012
  "\n"
36022
38013
  );
36023
38014
  const nextStart = event.currentTarget.selectionStart ?? nextText.length;
36024
38015
  const nextEnd = event.currentTarget.selectionEnd ?? nextStart;
38016
+ const nativeInputEvent = event.nativeEvent;
38017
+ if (nativeInputEvent?.isComposing || compositionActiveRef.current) {
38018
+ editor.beginSelectionSession("composition");
38019
+ syncWrappedParagraphRange(location, nextStart, nextEnd, {
38020
+ textOverride: nextText,
38021
+ textLength: nextText.length
38022
+ });
38023
+ return;
38024
+ }
38025
+ editor.beginSelectionSession("keyboard", {
38026
+ settleAfterMs: 220
38027
+ });
36025
38028
  syncWrappedParagraphRange(location, nextStart, nextEnd, {
36026
38029
  textOverride: nextText,
36027
38030
  textLength: nextText.length
@@ -36039,12 +38042,14 @@ function DocxEditorViewer({
36039
38042
  });
36040
38043
  },
36041
38044
  onCompositionStart: () => {
38045
+ compositionActiveRef.current = true;
36042
38046
  editor.beginSelectionSession("composition");
36043
38047
  setActiveWrappedParagraphSession(
36044
38048
  (current) => current && current.locationKey === locationKey ? { ...current, isComposing: true } : current
36045
38049
  );
36046
38050
  },
36047
38051
  onCompositionEnd: (event) => {
38052
+ compositionActiveRef.current = false;
36048
38053
  editor.beginSelectionSession("keyboard", {
36049
38054
  settleAfterMs: 260
36050
38055
  });
@@ -36054,18 +38059,20 @@ function DocxEditorViewer({
36054
38059
  );
36055
38060
  const nextStart = event.currentTarget.selectionStart ?? nextText.length;
36056
38061
  const nextEnd = event.currentTarget.selectionEnd ?? nextStart;
36057
- setActiveWrappedParagraphSession(
36058
- (current) => current && current.locationKey === locationKey ? {
36059
- ...current,
36060
- isComposing: false,
36061
- text: nextText,
36062
- selectionStart: nextStart,
36063
- selectionEnd: nextEnd
36064
- } : current
36065
- );
38062
+ syncWrappedParagraphRange(location, nextStart, nextEnd, {
38063
+ textOverride: nextText,
38064
+ textLength: nextText.length,
38065
+ isComposing: false
38066
+ });
38067
+ commitWrappedParagraphTextAtLocation(location, nextText);
38068
+ schedulePaginationMeasurementResume();
36066
38069
  },
36067
38070
  onKeyDown: (event) => {
36068
38071
  cancelPendingPointerSelectionReconcile();
38072
+ if (isCompositionKeyboardEvent(event)) {
38073
+ editor.beginSelectionSession("composition");
38074
+ return;
38075
+ }
36069
38076
  editor.beginSelectionSession("keyboard", {
36070
38077
  settleAfterMs: 220
36071
38078
  });
@@ -36188,6 +38195,13 @@ function DocxEditorViewer({
36188
38195
  }
36189
38196
  },
36190
38197
  onBlur: (event) => {
38198
+ if (compositionActiveRef.current) {
38199
+ compositionActiveRef.current = false;
38200
+ commitWrappedParagraphTextAtLocation(
38201
+ location,
38202
+ event.currentTarget.value.replace(/\r\n?/g, "\n")
38203
+ );
38204
+ }
36191
38205
  const currentTarget = event.currentTarget;
36192
38206
  const wrappedParagraphRoot = currentTarget.closest(
36193
38207
  "[data-docx-wrapped-paragraph-root='true']"
@@ -36545,7 +38559,8 @@ function DocxEditorViewer({
36545
38559
  top: activeDualWrappedLayout.layout.lines[lineIndex]?.y ?? 0,
36546
38560
  display: "inline-block",
36547
38561
  whiteSpace: "pre",
36548
- lineHeight: `${activeDualWrappedLayout.lineHeightPx}px`
38562
+ lineHeight: `${activeDualWrappedLayout.lineHeightPx}px`,
38563
+ textIndent: 0
36549
38564
  },
36550
38565
  children: pieces
36551
38566
  },
@@ -37267,9 +39282,10 @@ function DocxEditorViewer({
37267
39282
  source: activeWrappedSource,
37268
39283
  layout: activeWrappedLayout,
37269
39284
  lineHeightPx: activeDualWrappedLayout.lineHeightPx,
37270
- blockHeightPx: resolveDualWrapParagraphRenderBlockHeightPx(
39285
+ blockHeightPx: resolveDragPreviewAwareWrapBlockHeightPx(
37271
39286
  activeWrappedLayout,
37272
- activeDualWrappedLayout.geometries
39287
+ activeDualWrappedLayout.geometries,
39288
+ options?.pageFlowForeignExclusions
37273
39289
  ),
37274
39290
  obstacleNodes: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
37275
39291
  activeDualWrappedLayout.geometries.map(
@@ -38883,6 +40899,9 @@ function DocxEditorViewer({
38883
40899
  ),
38884
40900
  top: 0,
38885
40901
  marginRight: 0,
40902
+ // Left-align the glyph in its hanging box (see body-paragraph twin)
40903
+ // so a split list item's marker doesn't overlap the body text.
40904
+ justifyContent: "flex-start",
38886
40905
  zIndex: 1,
38887
40906
  pointerEvents: "none"
38888
40907
  },
@@ -38921,7 +40940,11 @@ function DocxEditorViewer({
38921
40940
  ...baseParagraphStyle,
38922
40941
  ...hasPartialLineRange ? {
38923
40942
  marginTop: paragraphSegmentStartLine === 0 ? baseParagraphStyle.marginTop : 0,
38924
- marginBottom: paragraphSegmentEndLine >= paragraphSegmentTotalLines ? baseParagraphStyle.marginBottom : 0
40943
+ marginBottom: paragraphSegmentEndLine >= paragraphSegmentTotalLines ? baseParagraphStyle.marginBottom : 0,
40944
+ // See body-paragraph twin: the pretext split path positions
40945
+ // everything absolutely, so drop the block hanging text-indent that
40946
+ // would otherwise shift the segment left by the hanging amount.
40947
+ ...shouldRenderParagraphSegmentWithPretext ? { textIndent: 0 } : void 0
38925
40948
  } : void 0,
38926
40949
  outline: "none"
38927
40950
  };
@@ -39110,6 +41133,11 @@ function DocxEditorViewer({
39110
41133
  ),
39111
41134
  top: 0,
39112
41135
  marginRight: 0,
41136
+ // Left-align the marker glyph within its hanging-indent box so it
41137
+ // sits at the number position with a gap before the text, instead
41138
+ // of flex-end pinning it against the body text (which starts at
41139
+ // the box's right edge) and overlapping it on split paragraphs.
41140
+ justifyContent: "flex-start",
39113
41141
  zIndex: 1,
39114
41142
  pointerEvents: "none"
39115
41143
  },
@@ -39212,7 +41240,14 @@ function DocxEditorViewer({
39212
41240
  ...baseParagraphStyle,
39213
41241
  ...hasPartialLineRange ? {
39214
41242
  marginTop: paragraphSegmentStartLine === 0 ? resolvedBeforeSpacingPx ?? beforeSpacingPx : 0,
39215
- marginBottom: paragraphSegmentEndLine >= paragraphSegmentTotalLines ? resolvedAfterSpacingPx ?? afterSpacingPx : 0
41243
+ marginBottom: paragraphSegmentEndLine >= paragraphSegmentTotalLines ? resolvedAfterSpacingPx ?? afterSpacingPx : 0,
41244
+ // The pretext split path positions the marker and every line
41245
+ // fragment absolutely, so it does not want the block hanging
41246
+ // `text-indent: -hanging` (which otherwise shifts the whole
41247
+ // absolutely-positioned segment left by the hanging amount,
41248
+ // dropping the paragraph's left indent). The clip-fallback path
41249
+ // still renders inline and keeps the text-indent.
41250
+ ...shouldRenderParagraphSegmentWithPretext ? { textIndent: 0 } : void 0
39216
41251
  } : resolvedBeforeSpacingPx !== void 0 || resolvedAfterSpacingPx !== void 0 ? {
39217
41252
  ...resolvedBeforeSpacingPx !== void 0 ? { marginTop: resolvedBeforeSpacingPx } : void 0,
39218
41253
  ...resolvedAfterSpacingPx !== void 0 ? { marginBottom: resolvedAfterSpacingPx } : void 0
@@ -39312,8 +41347,9 @@ function DocxEditorViewer({
39312
41347
  )
39313
41348
  }
39314
41349
  ) : getFallbackParagraphRuns();
39315
- const paragraphDraftHtml = paragraphDraftsRef.current.get(nodeIndex);
39316
- const renderedEditableParagraphHtml = typeof paragraphDraftHtml === "string" ? paragraphDraftHtml : renderStaticHtml(renderedInteractiveParagraphContent);
41350
+ const renderedEditableParagraphHtml = renderStaticHtml(
41351
+ renderedInteractiveParagraphContent
41352
+ );
39317
41353
  return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
39318
41354
  "div",
39319
41355
  {
@@ -39324,9 +41360,11 @@ function DocxEditorViewer({
39324
41360
  "data-docx-paragraph-end-line": paragraphSegmentEndLine,
39325
41361
  "data-docx-paragraph-partial-line-range": hasPartialLineRange ? "true" : void 0,
39326
41362
  style: paragraphStyle,
39327
- dangerouslySetInnerHTML: editable ? {
39328
- __html: renderedEditableParagraphHtml
39329
- } : void 0,
41363
+ dangerouslySetInnerHTML: editable ? stableInnerHtmlProp(
41364
+ editableParagraphHtmlPropsRef.current,
41365
+ nodeIndex,
41366
+ renderedEditableParagraphHtml
41367
+ ) : void 0,
39330
41368
  ref: (element) => {
39331
41369
  if (shouldTrackParagraphElement) {
39332
41370
  if (element) {
@@ -39356,49 +41394,6 @@ function DocxEditorViewer({
39356
41394
  }
39357
41395
  });
39358
41396
  }
39359
- const draft = paragraphDraftsRef.current.get(nodeIndex);
39360
- if (typeof draft === "string") {
39361
- const draftHtml = draft;
39362
- scheduleDomWrite(() => {
39363
- if (!element.isConnected) {
39364
- return;
39365
- }
39366
- const latestDraft = paragraphDraftsRef.current.get(nodeIndex);
39367
- if (latestDraft !== draftHtml) {
39368
- return;
39369
- }
39370
- if (element.innerHTML !== draftHtml) {
39371
- const activeElement = document.activeElement;
39372
- const shouldRestoreSelection = activeElement === element || activeElement instanceof Element && element.contains(activeElement);
39373
- const selectionOffsets = shouldRestoreSelection ? selectionOffsetsWithinElement(element) : void 0;
39374
- element.innerHTML = draftHtml;
39375
- if (shouldRestoreSelection) {
39376
- if (selectionOffsets) {
39377
- const textLength = editableTextFromElement(element).length;
39378
- const safeStart = Math.max(
39379
- 0,
39380
- Math.min(selectionOffsets.start, textLength)
39381
- );
39382
- const safeEnd = Math.max(
39383
- safeStart,
39384
- Math.min(selectionOffsets.end, textLength)
39385
- );
39386
- setSelectionWithinElementByTextOffsets(
39387
- element,
39388
- safeStart,
39389
- safeEnd
39390
- );
39391
- } else {
39392
- placeCaretInsideElement(element);
39393
- }
39394
- }
39395
- }
39396
- const latestParagraph = editor.model.nodes[nodeIndex];
39397
- if (latestParagraph && latestParagraph.type === "paragraph" && editableTextFromElement(element) === paragraphText(latestParagraph)) {
39398
- paragraphDraftsRef.current.delete(nodeIndex);
39399
- }
39400
- });
39401
- }
39402
41397
  },
39403
41398
  onPointerDown: (event) => {
39404
41399
  if (eventTargetIsInteractiveControl(event.target) || !editable) {
@@ -39516,36 +41511,78 @@ function DocxEditorViewer({
39516
41511
  return;
39517
41512
  }
39518
41513
  cancelPendingPointerSelectionReconcile();
39519
- editor.beginSelectionSession("keyboard", { settleAfterMs: 220 });
39520
- if (hasPartialLineRange) {
39521
- activateEditableParagraphSegment(nodeIndex, paragraphLineRange);
41514
+ const nativeInputEvent = event.nativeEvent;
41515
+ if (nativeInputEvent?.isComposing || compositionActiveRef.current) {
41516
+ editor.beginSelectionSession("composition");
41517
+ return;
41518
+ }
41519
+ const domText = editableTextFromElement(event.currentTarget);
41520
+ const latestParagraph = editor.model.nodes[nodeIndex];
41521
+ if (!latestParagraph || latestParagraph.type !== "paragraph" || domText === paragraphText(latestParagraph)) {
41522
+ return;
39522
41523
  }
41524
+ const continuation = editingIntentContinuationRef.current;
41525
+ if (continuation && continuation.key === `p:${nodeIndex}` && continuation.text !== domText) {
41526
+ return;
41527
+ }
41528
+ editor.beginSelectionSession("keyboard", { settleAfterMs: 220 });
39523
41529
  schedulePaginationMeasurementResume();
39524
- paragraphDraftsRef.current.set(
39525
- nodeIndex,
39526
- event.currentTarget.innerHTML
39527
- );
39528
41530
  const typedOffsets = selectionOffsetsWithinElement(
39529
41531
  event.currentTarget
39530
41532
  );
39531
- pendingEditableCaretRef.current = typedOffsets ? {
39532
- nodeIndex,
39533
- start: typedOffsets.start,
39534
- end: typedOffsets.end
39535
- } : null;
41533
+ const caretOffset = typedOffsets?.end ?? domText.length;
41534
+ editor.commitParagraphTextAtRange(
41535
+ { kind: "paragraph", nodeIndex },
41536
+ domText,
41537
+ {
41538
+ start: typedOffsets?.start ?? caretOffset,
41539
+ end: caretOffset
41540
+ }
41541
+ );
41542
+ editingIntentContinuationRef.current = {
41543
+ key: `p:${nodeIndex}`,
41544
+ text: domText,
41545
+ caret: caretOffset
41546
+ };
39536
41547
  },
39537
41548
  onCompositionStart: () => {
39538
41549
  if (!editable) {
39539
41550
  return;
39540
41551
  }
39541
41552
  cancelPendingPointerSelectionReconcile();
41553
+ compositionActiveRef.current = true;
39542
41554
  editor.beginSelectionSession("composition");
39543
41555
  },
39544
- onCompositionEnd: () => {
41556
+ onCompositionEnd: (event) => {
39545
41557
  if (!editable) {
39546
41558
  return;
39547
41559
  }
41560
+ compositionActiveRef.current = false;
39548
41561
  editor.beginSelectionSession("keyboard", { settleAfterMs: 260 });
41562
+ schedulePaginationMeasurementResume();
41563
+ const composedText = editableTextFromElement(event.currentTarget);
41564
+ const composedOffsets = selectionOffsetsWithinElement(
41565
+ event.currentTarget
41566
+ );
41567
+ const caretEnd = composedOffsets?.end ?? composedText.length;
41568
+ editor.commitParagraphTextAtRange(
41569
+ { kind: "paragraph", nodeIndex },
41570
+ composedText,
41571
+ {
41572
+ start: composedOffsets?.start ?? caretEnd,
41573
+ end: caretEnd
41574
+ }
41575
+ );
41576
+ editingIntentContinuationRef.current = {
41577
+ key: `p:${nodeIndex}`,
41578
+ text: composedText,
41579
+ caret: caretEnd
41580
+ };
41581
+ pendingEditableCaretRef.current = composedOffsets ? {
41582
+ nodeIndex,
41583
+ start: composedOffsets.start,
41584
+ end: composedOffsets.end
41585
+ } : null;
39549
41586
  },
39550
41587
  onPaste: (event) => {
39551
41588
  const pastedText = event.clipboardData.getData("text/plain");
@@ -39558,13 +41595,16 @@ function DocxEditorViewer({
39558
41595
  }
39559
41596
  event.preventDefault();
39560
41597
  event.stopPropagation();
39561
- paragraphDraftsRef.current.delete(nodeIndex);
39562
41598
  },
39563
41599
  onKeyDown: (event) => {
39564
41600
  if (!editable) {
39565
41601
  return;
39566
41602
  }
39567
41603
  cancelPendingPointerSelectionReconcile();
41604
+ if (isCompositionKeyboardEvent(event)) {
41605
+ editor.beginSelectionSession("composition");
41606
+ return;
41607
+ }
39568
41608
  editor.beginSelectionSession("keyboard", { settleAfterMs: 220 });
39569
41609
  if (hasPartialLineRange) {
39570
41610
  activateEditableParagraphSegment(nodeIndex, paragraphLineRange);
@@ -39578,11 +41618,6 @@ function DocxEditorViewer({
39578
41618
  const handledHistoryShortcut = handleEditorHistoryShortcut(
39579
41619
  event,
39580
41620
  () => {
39581
- commitParagraphDraftFromElement(
39582
- nodeIndex,
39583
- node,
39584
- event.currentTarget
39585
- );
39586
41621
  }
39587
41622
  );
39588
41623
  if (handledHistoryShortcut) {
@@ -39594,7 +41629,6 @@ function DocxEditorViewer({
39594
41629
  if (replaced) {
39595
41630
  event.preventDefault();
39596
41631
  event.stopPropagation();
39597
- paragraphDraftsRef.current.delete(nodeIndex);
39598
41632
  return;
39599
41633
  }
39600
41634
  }
@@ -39604,7 +41638,6 @@ function DocxEditorViewer({
39604
41638
  if (replaced) {
39605
41639
  event.preventDefault();
39606
41640
  event.stopPropagation();
39607
- paragraphDraftsRef.current.delete(nodeIndex);
39608
41641
  return;
39609
41642
  }
39610
41643
  }
@@ -39666,7 +41699,7 @@ function DocxEditorViewer({
39666
41699
  if (previousLocation && previousParagraph) {
39667
41700
  event.preventDefault();
39668
41701
  event.stopPropagation();
39669
- paragraphDraftsRef.current.delete(nodeIndex);
41702
+ editingIntentContinuationRef.current = void 0;
39670
41703
  const caretClientPoint = collapsedCaretClientPointWithinElement(event.currentTarget);
39671
41704
  if (caretClientPoint && focusParagraphLocationAtClientPoint(
39672
41705
  previousLocation,
@@ -39688,7 +41721,7 @@ function DocxEditorViewer({
39688
41721
  if (nextLocation && nextParagraph) {
39689
41722
  event.preventDefault();
39690
41723
  event.stopPropagation();
39691
- paragraphDraftsRef.current.delete(nodeIndex);
41724
+ editingIntentContinuationRef.current = void 0;
39692
41725
  const caretClientPoint = collapsedCaretClientPointWithinElement(event.currentTarget);
39693
41726
  const fallbackOffset = paragraphText(nextParagraph).length;
39694
41727
  if (caretClientPoint && focusParagraphLocationAtClientPoint(
@@ -39723,7 +41756,7 @@ function DocxEditorViewer({
39723
41756
  if (previousLocation && previousParagraph) {
39724
41757
  event.preventDefault();
39725
41758
  event.stopPropagation();
39726
- paragraphDraftsRef.current.delete(nodeIndex);
41759
+ editingIntentContinuationRef.current = void 0;
39727
41760
  const collapsedRange = editor.deleteExpandedSelection({
39728
41761
  start: {
39729
41762
  location: cloneTextRangeLocation(previousLocation),
@@ -39749,7 +41782,7 @@ function DocxEditorViewer({
39749
41782
  if (nextLocation && nextParagraph) {
39750
41783
  event.preventDefault();
39751
41784
  event.stopPropagation();
39752
- paragraphDraftsRef.current.delete(nodeIndex);
41785
+ editingIntentContinuationRef.current = void 0;
39753
41786
  const collapsedRange = editor.deleteExpandedSelection({
39754
41787
  start: {
39755
41788
  location: cloneTextRangeLocation(currentLocation),
@@ -39786,7 +41819,7 @@ function DocxEditorViewer({
39786
41819
  if (handledBackspace) {
39787
41820
  event.preventDefault();
39788
41821
  event.stopPropagation();
39789
- paragraphDraftsRef.current.delete(nodeIndex);
41822
+ editingIntentContinuationRef.current = void 0;
39790
41823
  focusParagraphAtOffset(nodeIndex, 0);
39791
41824
  return;
39792
41825
  }
@@ -39810,7 +41843,7 @@ function DocxEditorViewer({
39810
41843
  start
39811
41844
  )}
39812
41845
  ${currentText.slice(end)}`;
39813
- paragraphDraftsRef.current.delete(nodeIndex);
41846
+ editingIntentContinuationRef.current = void 0;
39814
41847
  editor.commitParagraphText(nodeIndex, nextText);
39815
41848
  focusParagraphAtOffset(nodeIndex, start + 1);
39816
41849
  return;
@@ -39822,7 +41855,7 @@ ${currentText.slice(end)}`;
39822
41855
  currentText
39823
41856
  );
39824
41857
  if (listDepthChanged) {
39825
- paragraphDraftsRef.current.delete(nodeIndex);
41858
+ editingIntentContinuationRef.current = void 0;
39826
41859
  const targetOffset = selectionOffsets?.end ?? currentText.length;
39827
41860
  focusParagraphAtOffset(nodeIndex, targetOffset);
39828
41861
  }
@@ -39833,7 +41866,7 @@ ${currentText.slice(end)}`;
39833
41866
  event.stopPropagation();
39834
41867
  const start = selectionOffsets?.start ?? currentText.length;
39835
41868
  const end = selectionOffsets?.end ?? start;
39836
- paragraphDraftsRef.current.clear();
41869
+ editingIntentContinuationRef.current = void 0;
39837
41870
  tableCellDraftsRef.current.clear();
39838
41871
  tableCellParagraphDraftsRef.current.clear();
39839
41872
  const insertedListItem = editor.insertListItemAfterSelection(
@@ -39867,7 +41900,7 @@ ${currentText.slice(end)}`;
39867
41900
  start,
39868
41901
  Math.min(selectionOffsets?.end ?? start, currentText.length)
39869
41902
  );
39870
- paragraphDraftsRef.current.clear();
41903
+ editingIntentContinuationRef.current = void 0;
39871
41904
  tableCellDraftsRef.current.clear();
39872
41905
  tableCellParagraphDraftsRef.current.clear();
39873
41906
  const splitParagraph = editor.splitParagraphAtSelection(
@@ -39892,14 +41925,16 @@ ${currentText.slice(end)}`;
39892
41925
  if (!editable) {
39893
41926
  return;
39894
41927
  }
39895
- if (!paragraphDraftsRef.current.has(nodeIndex)) {
39896
- return;
41928
+ if (compositionActiveRef.current) {
41929
+ compositionActiveRef.current = false;
41930
+ const composedText = editableTextFromElement(
41931
+ event.currentTarget
41932
+ );
41933
+ if (composedText !== paragraphText(node)) {
41934
+ editor.suppressNextDomSelectionRestore();
41935
+ editor.commitParagraphText(nodeIndex, composedText);
41936
+ }
39897
41937
  }
39898
- commitParagraphDraftFromElement(
39899
- nodeIndex,
39900
- node,
39901
- event.currentTarget
39902
- );
39903
41938
  },
39904
41939
  children: !editable ? renderedInteractiveParagraphContent : null
39905
41940
  },
@@ -39909,7 +41944,19 @@ ${currentText.slice(end)}`;
39909
41944
  const tableRowSliceOffsetPxForWrapper = tableRowSlice ? Math.max(0, Math.round(tableRowSlice.startOffsetPx)) : 0;
39910
41945
  const tableRowSliceTopBleedPxForWrapper = tableRowSlice && tableRowSliceOffsetPxForWrapper > 0 ? TABLE_ROW_SLICE_VISUAL_BLEED_PX : 0;
39911
41946
  const tableRowSliceBottomBleedPxForWrapper = tableRowSlice ? TABLE_ROW_SLICE_VISUAL_BLEED_PX : 0;
39912
- return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
41947
+ const floatingTablePageLayout = options?.pageLayout ?? documentLayout;
41948
+ const floatingTableGeometry = node.style?.floating && !tableRowRange && !tableRowSlice ? resolveFloatingTableGeometry(node, nodeContentWidthPx, {
41949
+ tableWidthPx: estimateFloatingTableWidthPx(
41950
+ node,
41951
+ nodeContentWidthPx
41952
+ ),
41953
+ tableHeightPx: 0,
41954
+ indentPx: twipsToSignedPixels(node.style?.indentTwips) ?? 0,
41955
+ flowTopPx: options?.pageFlowTopPx ?? 0,
41956
+ pageMarginTopPx: floatingTablePageLayout.marginsPx.top,
41957
+ pageMarginLeftPx: floatingTablePageLayout.marginsPx.left
41958
+ }) : void 0;
41959
+ const renderedTableBlock = /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
39913
41960
  "div",
39914
41961
  {
39915
41962
  ref: (element) => {
@@ -39924,10 +41971,21 @@ ${currentText.slice(end)}`;
39924
41971
  }
39925
41972
  },
39926
41973
  style: {
39927
- ...tableWrapperStyle(
41974
+ ...floatingTableGeometry ? {
41975
+ position: "absolute",
41976
+ left: floatingTableGeometry.leftPx,
41977
+ top: floatingTableGeometry.topPx,
41978
+ maxWidth: nodeContentWidthPx,
41979
+ zIndex: 2
41980
+ } : tableWrapperStyle(
39928
41981
  node,
39929
41982
  twipsToSignedPixels(node.style?.indentTwips) ?? 0
39930
41983
  ),
41984
+ ...tableFloatingDragPreview?.tableIndex === nodeIndex ? {
41985
+ transform: `translate(${tableFloatingDragPreview.deltaX}px, ${tableFloatingDragPreview.deltaY}px)`,
41986
+ zIndex: 30,
41987
+ opacity: 0.9
41988
+ } : void 0,
39931
41989
  ...tableRowSlice ? {
39932
41990
  height: Math.max(
39933
41991
  MIN_PARAGRAPH_LINE_HEIGHT_PX,
@@ -40035,7 +42093,7 @@ ${currentText.slice(end)}`;
40035
42093
  const normalizedRowHeightsPx = rowHeightsPx.map(
40036
42094
  (value) => Number.isFinite(value) && value > 0 ? Math.max(24, value) : 24
40037
42095
  );
40038
- const measuredRowHeightsPx = tableMeasuredRowHeights[nodeIndex];
42096
+ const measuredRowHeightsPx = node.blockId ? tableMeasuredRowHeights[node.blockId]?.rowHeightsPx : void 0;
40039
42097
  const rowBoundarySourceHeightsPx = measuredRowHeightsPx && measuredRowHeightsPx.length === node.rows.length ? measuredRowHeightsPx.map(
40040
42098
  (value) => Number.isFinite(value) && value > 0 ? Math.max(24, value) : 24
40041
42099
  ) : normalizedRowHeightsPx;
@@ -40263,6 +42321,9 @@ ${currentText.slice(end)}`;
40263
42321
  } : void 0;
40264
42322
  const cellDraftKey = `${nodeIndex}:${rowIndex}:${cellIndex}`;
40265
42323
  const cellElementKey = `cell-${nodeIndex}-${rowIndex}-${cellIndex}`;
42324
+ const cellUsesLegacyDraftEditing = cell.nodes.some(
42325
+ (cellContent) => cellContent.type === "table"
42326
+ );
40266
42327
  const colSpanValue = cell.style?.gridSpan && cell.style.gridSpan > 1 ? cell.style.gridSpan : 1;
40267
42328
  const rowSpanValue = cell.style?.rowSpan && cell.style.rowSpan > 1 ? cell.style.rowSpan : 1;
40268
42329
  const colSpan = colSpanValue > 1 ? colSpanValue : void 0;
@@ -40771,9 +42832,11 @@ ${currentText.slice(end)}`;
40771
42832
  overflowWrap: "break-word",
40772
42833
  wordBreak: "break-word"
40773
42834
  },
40774
- dangerouslySetInnerHTML: renderedEditableCellHtml ? {
40775
- __html: renderedEditableCellHtml
40776
- } : void 0,
42835
+ dangerouslySetInnerHTML: renderedEditableCellHtml ? stableInnerHtmlProp(
42836
+ editableTableCellHtmlPropsRef.current,
42837
+ cellDraftKey,
42838
+ renderedEditableCellHtml
42839
+ ) : void 0,
40777
42840
  ref: (element) => {
40778
42841
  if (element) {
40779
42842
  tableCellEditorElementsRef.current.set(
@@ -40791,10 +42854,10 @@ ${currentText.slice(end)}`;
40791
42854
  const draft = tableCellDraftsRef.current.get(
40792
42855
  cellDraftKey
40793
42856
  );
40794
- if (typeof draft === "string") {
42857
+ if (!compositionActiveRef.current && typeof draft === "string") {
40795
42858
  const draftHtml = draft;
40796
42859
  scheduleDomWrite(() => {
40797
- if (!element.isConnected) {
42860
+ if (!element.isConnected || compositionActiveRef.current) {
40798
42861
  return;
40799
42862
  }
40800
42863
  const latestDraft = tableCellDraftsRef.current.get(
@@ -40916,28 +42979,6 @@ ${currentText.slice(end)}`;
40916
42979
  boundary,
40917
42980
  boundary
40918
42981
  );
40919
- const verifyBoundaryRestore = (attempt) => {
40920
- window.requestAnimationFrame(() => {
40921
- if (!element.isConnected) {
40922
- return;
40923
- }
40924
- const selection = window.getSelection();
40925
- const range = selection && selection.rangeCount > 0 ? selection.getRangeAt(0) : null;
40926
- const degenerate = !range || selection?.isCollapsed === true && range.startContainer === element && range.startOffset === 0;
40927
- if (degenerate) {
40928
- setSelectionFromDocxBoundaries(
40929
- boundary,
40930
- boundary
40931
- );
40932
- }
40933
- if (attempt < 6) {
40934
- verifyBoundaryRestore(
40935
- attempt + 1
40936
- );
40937
- }
40938
- });
40939
- };
40940
- verifyBoundaryRestore(0);
40941
42982
  } else if (paragraphElement) {
40942
42983
  placeCaretInsideElement(
40943
42984
  paragraphElement,
@@ -40963,24 +43004,130 @@ ${currentText.slice(end)}`;
40963
43004
  },
40964
43005
  onInput: (event) => {
40965
43006
  cancelPendingPointerSelectionReconcile();
43007
+ const nativeInputEvent = event.nativeEvent;
43008
+ if (nativeInputEvent?.isComposing || compositionActiveRef.current) {
43009
+ editor.beginSelectionSession(
43010
+ "composition"
43011
+ );
43012
+ return;
43013
+ }
43014
+ if (cellUsesLegacyDraftEditing) {
43015
+ editor.beginSelectionSession("keyboard", {
43016
+ settleAfterMs: 220
43017
+ });
43018
+ schedulePaginationMeasurementResume();
43019
+ tableCellDraftsRef.current.set(
43020
+ cellDraftKey,
43021
+ event.currentTarget.innerHTML
43022
+ );
43023
+ requestTableDraftLayoutRefresh();
43024
+ return;
43025
+ }
43026
+ const context = activeTableCellParagraphContext(
43027
+ event.currentTarget
43028
+ );
43029
+ const contextParagraph = context ? cellParagraphs[context.paragraphIndex] : void 0;
43030
+ if (!context || !contextParagraph) {
43031
+ return;
43032
+ }
43033
+ const domText = editableTextFromElement(
43034
+ context.paragraphElement
43035
+ );
43036
+ if (domText === paragraphText(contextParagraph)) {
43037
+ return;
43038
+ }
43039
+ const continuationKey = `c:${nodeIndex}:${rowIndex}:${cellIndex}:${context.paragraphIndex}`;
43040
+ const continuation = editingIntentContinuationRef.current;
43041
+ if (continuation && continuation.key === continuationKey && continuation.text !== domText) {
43042
+ return;
43043
+ }
40966
43044
  editor.beginSelectionSession("keyboard", {
40967
43045
  settleAfterMs: 220
40968
43046
  });
40969
43047
  schedulePaginationMeasurementResume();
40970
- tableCellDraftsRef.current.set(
40971
- cellDraftKey,
40972
- event.currentTarget.innerHTML
43048
+ const typedOffsets = selectionOffsetsWithinElement(
43049
+ context.paragraphElement
40973
43050
  );
40974
- requestTableDraftLayoutRefresh();
43051
+ const caretOffset = typedOffsets?.end ?? domText.length;
43052
+ editor.commitParagraphTextAtRange(
43053
+ {
43054
+ kind: "table-cell",
43055
+ tableIndex: nodeIndex,
43056
+ rowIndex,
43057
+ cellIndex,
43058
+ paragraphIndex: context.paragraphIndex
43059
+ },
43060
+ domText,
43061
+ {
43062
+ start: typedOffsets?.start ?? caretOffset,
43063
+ end: caretOffset
43064
+ }
43065
+ );
43066
+ editingIntentContinuationRef.current = {
43067
+ key: continuationKey,
43068
+ text: domText,
43069
+ caret: caretOffset
43070
+ };
40975
43071
  },
40976
43072
  onCompositionStart: () => {
40977
43073
  cancelPendingPointerSelectionReconcile();
43074
+ compositionActiveRef.current = true;
40978
43075
  editor.beginSelectionSession("composition");
40979
43076
  },
40980
- onCompositionEnd: () => {
43077
+ onCompositionEnd: (event) => {
43078
+ compositionActiveRef.current = false;
40981
43079
  editor.beginSelectionSession("keyboard", {
40982
43080
  settleAfterMs: 260
40983
43081
  });
43082
+ schedulePaginationMeasurementResume();
43083
+ if (cellUsesLegacyDraftEditing) {
43084
+ tableCellDraftsRef.current.set(
43085
+ cellDraftKey,
43086
+ event.currentTarget.innerHTML
43087
+ );
43088
+ requestTableDraftLayoutRefresh();
43089
+ return;
43090
+ }
43091
+ const context = activeTableCellParagraphContext(
43092
+ event.currentTarget
43093
+ );
43094
+ if (context && cellParagraphs[context.paragraphIndex]) {
43095
+ const composedText = editableTextFromElement(
43096
+ context.paragraphElement
43097
+ );
43098
+ const composedOffsets = selectionOffsetsWithinElement(
43099
+ context.paragraphElement
43100
+ );
43101
+ const caretEnd = composedOffsets?.end ?? composedText.length;
43102
+ editor.commitParagraphTextAtRange(
43103
+ {
43104
+ kind: "table-cell",
43105
+ tableIndex: nodeIndex,
43106
+ rowIndex,
43107
+ cellIndex,
43108
+ paragraphIndex: context.paragraphIndex
43109
+ },
43110
+ composedText,
43111
+ {
43112
+ start: composedOffsets?.start ?? caretEnd,
43113
+ end: caretEnd
43114
+ }
43115
+ );
43116
+ editingIntentContinuationRef.current = {
43117
+ key: `c:${nodeIndex}:${rowIndex}:${cellIndex}:${context.paragraphIndex}`,
43118
+ text: composedText,
43119
+ caret: caretEnd
43120
+ };
43121
+ return;
43122
+ }
43123
+ editor.commitTableCellText(
43124
+ nodeIndex,
43125
+ rowIndex,
43126
+ cellIndex,
43127
+ editableTextFromTableCellElement(
43128
+ event.currentTarget
43129
+ )
43130
+ );
40984
43131
  },
40985
43132
  onClick: (event) => {
40986
43133
  if (eventTargetIsInteractiveControl(
@@ -41155,6 +43302,12 @@ ${currentText.slice(end)}`;
41155
43302
  },
41156
43303
  onKeyDown: (event) => {
41157
43304
  cancelPendingPointerSelectionReconcile();
43305
+ if (isCompositionKeyboardEvent(event)) {
43306
+ editor.beginSelectionSession(
43307
+ "composition"
43308
+ );
43309
+ return;
43310
+ }
41158
43311
  editor.beginSelectionSession("keyboard", {
41159
43312
  settleAfterMs: 220
41160
43313
  });
@@ -41167,6 +43320,9 @@ ${currentText.slice(end)}`;
41167
43320
  return;
41168
43321
  }
41169
43322
  const handledHistoryShortcut = handleEditorHistoryShortcut(event, () => {
43323
+ if (!cellUsesLegacyDraftEditing) {
43324
+ return;
43325
+ }
41170
43326
  commitTableCellDraftFromElement(
41171
43327
  nodeIndex,
41172
43328
  rowIndex,
@@ -41246,6 +43402,7 @@ ${currentText.slice(end)}`;
41246
43402
  start
41247
43403
  )}
41248
43404
  ${currentText.slice(end)}`;
43405
+ editingIntentContinuationRef.current = void 0;
41249
43406
  tableCellDraftsRef.current.delete(
41250
43407
  cellDraftKey
41251
43408
  );
@@ -41290,6 +43447,7 @@ ${currentText.slice(end)}`;
41290
43447
  if (handledBackspace) {
41291
43448
  event.preventDefault();
41292
43449
  event.stopPropagation();
43450
+ editingIntentContinuationRef.current = void 0;
41293
43451
  tableCellDraftsRef.current.delete(
41294
43452
  cellDraftKey
41295
43453
  );
@@ -41308,6 +43466,7 @@ ${currentText.slice(end)}`;
41308
43466
  currentText
41309
43467
  );
41310
43468
  if (listDepthChanged) {
43469
+ editingIntentContinuationRef.current = void 0;
41311
43470
  tableCellDraftsRef.current.delete(
41312
43471
  cellDraftKey
41313
43472
  );
@@ -41321,6 +43480,31 @@ ${currentText.slice(end)}`;
41321
43480
  }
41322
43481
  },
41323
43482
  onBlur: (event) => {
43483
+ if (!cellUsesLegacyDraftEditing) {
43484
+ if (compositionActiveRef.current) {
43485
+ compositionActiveRef.current = false;
43486
+ const composedText = editableTextFromTableCellElement(
43487
+ event.currentTarget
43488
+ );
43489
+ if (composedText !== tableCellText(cellParagraphs)) {
43490
+ editor.suppressNextDomSelectionRestore();
43491
+ editor.commitTableCellText(
43492
+ nodeIndex,
43493
+ rowIndex,
43494
+ cellIndex,
43495
+ composedText
43496
+ );
43497
+ }
43498
+ }
43499
+ return;
43500
+ }
43501
+ if (compositionActiveRef.current) {
43502
+ compositionActiveRef.current = false;
43503
+ tableCellDraftsRef.current.set(
43504
+ cellDraftKey,
43505
+ event.currentTarget.innerHTML
43506
+ );
43507
+ }
41324
43508
  if (!tableCellDraftsRef.current.has(
41325
43509
  cellDraftKey
41326
43510
  )) {
@@ -41728,6 +43912,18 @@ ${currentText.slice(end)}`;
41728
43912
  Math.round(tableRowSlice.sliceHeightPx)
41729
43913
  )}` : ""}` : `node-${nodeIndex}`
41730
43914
  );
43915
+ if (floatingTableGeometry) {
43916
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
43917
+ "div",
43918
+ {
43919
+ "data-docx-floating-table-host": "true",
43920
+ style: { height: 0, position: "relative", overflow: "visible" },
43921
+ children: renderedTableBlock
43922
+ },
43923
+ `floating-table-host-${nodeIndex}`
43924
+ );
43925
+ }
43926
+ return renderedTableBlock;
41731
43927
  };
41732
43928
  const renderNodeSegments = React.useCallback(
41733
43929
  (nodeSegments, options) => {
@@ -41744,7 +43940,8 @@ ${currentText.slice(end)}`;
41744
43940
  resolvedPageLayout,
41745
43941
  {
41746
43942
  floatingMovePreview,
41747
- resizePreview
43943
+ resizePreview,
43944
+ measuredWrapBands
41748
43945
  }
41749
43946
  );
41750
43947
  for (let offset = 0; offset < nodeSegments.length; offset += 1) {
@@ -42397,6 +44594,8 @@ ${currentText.slice(end)}`;
42397
44594
  continue;
42398
44595
  }
42399
44596
  }
44597
+ const segmentParagraphLineRange = segment.paragraphLineRange;
44598
+ const measuredSegmentFlowTopPx = node.type === "paragraph" && (!segmentParagraphLineRange || segmentParagraphLineRange.startLineIndex === 0 && segmentParagraphLineRange.endLineIndex >= segmentParagraphLineRange.totalLineCount) ? measuredWrapBands.get(`para:${nodeIndex}`)?.topPx : void 0;
42400
44599
  rendered.push(
42401
44600
  renderDocumentNode(
42402
44601
  node,
@@ -42406,7 +44605,7 @@ ${currentText.slice(end)}`;
42406
44605
  segment.paragraphLineRange,
42407
44606
  {
42408
44607
  pageLayout: options?.pageLayout,
42409
- pageFlowTopPx,
44608
+ pageFlowTopPx: measuredSegmentFlowTopPx ?? pageFlowTopPx,
42410
44609
  pageFlowForeignExclusions: foreignWrapExclusionsBySegmentIndex[offset],
42411
44610
  suppressLikelyFullPageCoverImageKeys: options?.suppressLikelyFullPageCoverImageKeys
42412
44611
  }
@@ -42438,6 +44637,7 @@ ${currentText.slice(end)}`;
42438
44637
  focusDropCapWrappedParagraph,
42439
44638
  hoveredDropCapNodeIndex,
42440
44639
  isReadOnly,
44640
+ measuredWrapBands,
42441
44641
  pageContentWidthPxByNodeIndex,
42442
44642
  renderDocumentNode,
42443
44643
  resizePreview,
@@ -46523,6 +48723,7 @@ function ReactDocxViewer({
46523
48723
  DEFAULT_PAGE_OVERFLOW_TOLERANCE_PX,
46524
48724
  DocxEditorViewer,
46525
48725
  ReactDocxViewer,
48726
+ allocateBlockId,
46526
48727
  applyRunStyle,
46527
48728
  buildDocModel,
46528
48729
  buildDocModelFromBytes,
@@ -46530,15 +48731,20 @@ function ReactDocxViewer({
46530
48731
  buildDocumentPageRanges,
46531
48732
  buildLayoutSnapshot,
46532
48733
  cloneDocModel,
48734
+ cloneParagraphNode,
48735
+ cloneTableNode,
46533
48736
  collectDocxEstimatedOverflowBreakStartNodeIndexes,
46534
48737
  collectDocxHardPageBreakStartNodeIndexes,
46535
48738
  collectDocxLastRenderedPageBreakStartNodeIndexes,
48739
+ collectDuplicateDocModelBlockIds,
46536
48740
  collectTableExplicitPageBreakInfo,
46537
48741
  collectTopLevelExplicitPageBreakStartNodeIndexes,
46538
48742
  copyParagraphs,
46539
48743
  createMinimalDocxPackage,
48744
+ deepFreezeDocModel,
46540
48745
  defaultStarterModel,
46541
48746
  duplicateParagraph,
48747
+ ensureDocModelBlockIds,
46542
48748
  getPart,
46543
48749
  initWasm,
46544
48750
  insertParagraph,