@beyondwork/docx-react-component 1.0.135 → 1.0.137

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.
Files changed (62) hide show
  1. package/dist/api/public-types.d.cts +2 -2
  2. package/dist/api/public-types.d.ts +2 -2
  3. package/dist/api/v3.cjs +827 -59
  4. package/dist/api/v3.d.cts +3 -3
  5. package/dist/api/v3.d.ts +3 -3
  6. package/dist/api/v3.js +2 -2
  7. package/dist/{canonical-document-CfZIc-fC.d.cts → canonical-document-COmM7v11.d.cts} +1 -1
  8. package/dist/{canonical-document-CfZIc-fC.d.ts → canonical-document-COmM7v11.d.ts} +1 -1
  9. package/dist/{chunk-EPFVMUKF.js → chunk-M3AEVSKU.js} +793 -56
  10. package/dist/{chunk-5CCYF333.js → chunk-NYIMPM3Z.js} +143 -1
  11. package/dist/{chunk-GIFXKIM5.js → chunk-SMBDQV73.js} +688 -57
  12. package/dist/compare.d.cts +1 -1
  13. package/dist/compare.d.ts +1 -1
  14. package/dist/core/commands/formatting-commands.d.cts +2 -2
  15. package/dist/core/commands/formatting-commands.d.ts +2 -2
  16. package/dist/core/commands/image-commands.d.cts +2 -2
  17. package/dist/core/commands/image-commands.d.ts +2 -2
  18. package/dist/core/commands/section-layout-commands.d.cts +2 -2
  19. package/dist/core/commands/section-layout-commands.d.ts +2 -2
  20. package/dist/core/commands/style-commands.d.cts +2 -2
  21. package/dist/core/commands/style-commands.d.ts +2 -2
  22. package/dist/core/commands/table-structure-commands.d.cts +2 -2
  23. package/dist/core/commands/table-structure-commands.d.ts +2 -2
  24. package/dist/core/commands/text-commands.d.cts +2 -2
  25. package/dist/core/commands/text-commands.d.ts +2 -2
  26. package/dist/core/selection/mapping.d.cts +2 -2
  27. package/dist/core/selection/mapping.d.ts +2 -2
  28. package/dist/core/state/editor-state.d.cts +2 -2
  29. package/dist/core/state/editor-state.d.ts +2 -2
  30. package/dist/index.cjs +1808 -190
  31. package/dist/index.d.cts +5 -5
  32. package/dist/index.d.ts +5 -5
  33. package/dist/index.js +144 -32
  34. package/dist/io/docx-session.d.cts +4 -4
  35. package/dist/io/docx-session.d.ts +4 -4
  36. package/dist/legal.d.cts +1 -1
  37. package/dist/legal.d.ts +1 -1
  38. package/dist/{loader-BQ7AB-0v.d.cts → loader-BB7tRkY2.d.cts} +3 -3
  39. package/dist/{loader-Cy6OYBfn.d.ts → loader-DGPbaboy.d.ts} +3 -3
  40. package/dist/{public-types-D31xKNGc.d.cts → public-types-CIvw1GQa.d.cts} +142 -9
  41. package/dist/{public-types-DqYt8GdP.d.ts → public-types-COCDrgVX.d.ts} +142 -9
  42. package/dist/public-types.d.cts +2 -2
  43. package/dist/public-types.d.ts +2 -2
  44. package/dist/runtime/collab.d.cts +3 -3
  45. package/dist/runtime/collab.d.ts +3 -3
  46. package/dist/runtime/document-runtime.cjs +825 -54
  47. package/dist/runtime/document-runtime.d.cts +2 -2
  48. package/dist/runtime/document-runtime.d.ts +2 -2
  49. package/dist/runtime/document-runtime.js +2 -2
  50. package/dist/{session-DA-F2fCw.d.cts → session-CVU-rtCd.d.cts} +3 -3
  51. package/dist/{session-DqL8H0oZ.d.ts → session-DOqy1-Lf.d.ts} +3 -3
  52. package/dist/session.d.cts +5 -5
  53. package/dist/session.d.ts +5 -5
  54. package/dist/tailwind.d.cts +2 -2
  55. package/dist/tailwind.d.ts +2 -2
  56. package/dist/{types-SllbCtGs.d.ts → types-CB_tOnVp.d.ts} +2 -2
  57. package/dist/{types-B2y94n5t.d.cts → types-CZAll7OS.d.cts} +2 -2
  58. package/dist/ui-tailwind/editor-surface/search-plugin.d.cts +3 -3
  59. package/dist/ui-tailwind/editor-surface/search-plugin.d.ts +3 -3
  60. package/dist/ui-tailwind.d.cts +3 -3
  61. package/dist/ui-tailwind.d.ts +3 -3
  62. package/package.json +1 -1
@@ -72,6 +72,7 @@ import {
72
72
  findTextWithStyleMatches,
73
73
  getListKind,
74
74
  inlineLengthForScopeCoordinates,
75
+ mergeFragmentNumberingCatalog,
75
76
  rebuildFieldRegistry,
76
77
  removeScopeMarkersFromBlockList,
77
78
  replaceParagraphChildrenAtPath,
@@ -83,7 +84,7 @@ import {
83
84
  sameScopeParagraphPath,
84
85
  serializeFragmentToWordML,
85
86
  setStartOverride
86
- } from "./chunk-5CCYF333.js";
87
+ } from "./chunk-NYIMPM3Z.js";
87
88
  import {
88
89
  ISSUE_METADATA_ID,
89
90
  LAYOUT_ENGINE_VERSION,
@@ -1195,7 +1196,7 @@ function splitListParagraph(document, paragraphIndex, paragraphIsEmpty, context,
1195
1196
  action: "split"
1196
1197
  };
1197
1198
  }
1198
- const target = paragraphs[resolvedParagraphIndex];
1199
+ const target = paragraphs[resolvedParagraphIndex]?.paragraph;
1199
1200
  if (!target?.numbering) {
1200
1201
  return {
1201
1202
  document: working,
@@ -1247,7 +1248,7 @@ function backspaceAtListStart(document, paragraphIndex, context, options = {}) {
1247
1248
  handled: false
1248
1249
  };
1249
1250
  }
1250
- const target = paragraphs[resolvedParagraphIndex];
1251
+ const target = paragraphs[resolvedParagraphIndex]?.paragraph;
1251
1252
  if (!target?.numbering) {
1252
1253
  return {
1253
1254
  document: working,
@@ -1293,7 +1294,7 @@ function restartNumbering(document, paragraphIndex, context, startAt = 1, option
1293
1294
  affectedParagraphIndexes: []
1294
1295
  };
1295
1296
  }
1296
- const target = paragraphs[resolvedParagraphIndex];
1297
+ const target = paragraphs[resolvedParagraphIndex]?.paragraph;
1297
1298
  if (!target?.numbering) {
1298
1299
  return {
1299
1300
  document: working,
@@ -1315,8 +1316,13 @@ function restartNumbering(document, paragraphIndex, context, startAt = 1, option
1315
1316
  );
1316
1317
  setStartOverride(catalog, numberingInstanceId, target.numbering.level, startAt);
1317
1318
  const affectedParagraphIndexes = [];
1319
+ const targetStoryKey = paragraphs[resolvedParagraphIndex]?.storyKey;
1318
1320
  for (let index = resolvedParagraphIndex; index < paragraphs.length; index += 1) {
1319
- const paragraph = paragraphs[index];
1321
+ const entry = paragraphs[index];
1322
+ if (entry?.storyKey !== targetStoryKey) {
1323
+ break;
1324
+ }
1325
+ const paragraph = entry.paragraph;
1320
1326
  if (!paragraph?.numbering) {
1321
1327
  break;
1322
1328
  }
@@ -1360,7 +1366,7 @@ function continueNumbering(document, paragraphIndex, context, options = {}) {
1360
1366
  affectedParagraphIndexes: []
1361
1367
  };
1362
1368
  }
1363
- const target = paragraphs[resolvedParagraphIndex];
1369
+ const target = paragraphs[resolvedParagraphIndex]?.paragraph;
1364
1370
  if (!target?.numbering) {
1365
1371
  return {
1366
1372
  document: working,
@@ -1389,8 +1395,13 @@ function continueNumbering(document, paragraphIndex, context, options = {}) {
1389
1395
  };
1390
1396
  }
1391
1397
  const affectedParagraphIndexes = [];
1398
+ const targetStoryKey = paragraphs[resolvedParagraphIndex]?.storyKey;
1392
1399
  for (let index = resolvedParagraphIndex; index < paragraphs.length; index += 1) {
1393
- const paragraph = paragraphs[index];
1400
+ const entry = paragraphs[index];
1401
+ if (entry?.storyKey !== targetStoryKey) {
1402
+ break;
1403
+ }
1404
+ const paragraph = entry.paragraph;
1394
1405
  if (!paragraph?.numbering) {
1395
1406
  break;
1396
1407
  }
@@ -1436,12 +1447,13 @@ function toggleListKind(document, paragraphIndexes, kind, context, options) {
1436
1447
  }
1437
1448
  const catalog = cloneNumberingCatalog(working.numbering);
1438
1449
  const allAlreadyKind = normalizedIndexes.every((index) => {
1439
- const paragraph = paragraphs[index];
1440
- return paragraph.numbering ? getListKind(catalog, paragraph.numbering.numberingInstanceId) === kind : false;
1450
+ const paragraph = paragraphs[index]?.paragraph;
1451
+ return paragraph?.numbering ? getListKind(catalog, paragraph.numbering.numberingInstanceId) === kind : false;
1441
1452
  });
1442
1453
  if (allAlreadyKind) {
1443
1454
  for (const index of normalizedIndexes) {
1444
- delete paragraphs[index].numbering;
1455
+ const paragraph = paragraphs[index]?.paragraph;
1456
+ if (paragraph) delete paragraph.numbering;
1445
1457
  }
1446
1458
  working.numbering = catalog;
1447
1459
  return {
@@ -1451,7 +1463,8 @@ function toggleListKind(document, paragraphIndexes, kind, context, options) {
1451
1463
  }
1452
1464
  const numberingInstanceId = findAdjacentCompatibleInstance(paragraphs, catalog, normalizedIndexes[0], kind) ?? ensureDefaultListInstance(catalog, kind);
1453
1465
  for (const index of normalizedIndexes) {
1454
- const paragraph = paragraphs[index];
1466
+ const paragraph = paragraphs[index]?.paragraph;
1467
+ if (!paragraph) continue;
1455
1468
  paragraph.numbering = {
1456
1469
  numberingInstanceId,
1457
1470
  level: clampLevel(paragraph.numbering?.level ?? 0)
@@ -1482,10 +1495,11 @@ function adjustListLevels(document, paragraphIndexes, delta, context, options) {
1482
1495
  };
1483
1496
  }
1484
1497
  const affectedParagraphIndexes = resolved.paragraphIndexes.filter(
1485
- (index) => Boolean(paragraphs[index]?.numbering)
1498
+ (index) => Boolean(paragraphs[index]?.paragraph.numbering)
1486
1499
  );
1487
1500
  for (const index of affectedParagraphIndexes) {
1488
- const paragraph = paragraphs[index];
1501
+ const paragraph = paragraphs[index]?.paragraph;
1502
+ if (!paragraph) continue;
1489
1503
  if (!paragraph.numbering) {
1490
1504
  continue;
1491
1505
  }
@@ -1505,17 +1519,21 @@ function normalizeListCommandTargets(options) {
1505
1519
  }
1506
1520
  function resolveListCommandParagraphIndexes(document, paragraphs, paragraphIndexes, context, editableTargets) {
1507
1521
  if (editableTargets.length === 0) {
1508
- return { paragraphIndexes: normalizeParagraphIndexes(paragraphs, paragraphIndexes) };
1522
+ return {
1523
+ paragraphIndexes: normalizeParagraphIndexesForStory(
1524
+ paragraphs,
1525
+ paragraphIndexes,
1526
+ context.activeStoryKey
1527
+ )
1528
+ };
1509
1529
  }
1510
1530
  const currentTargets = collectEditableTargetRefs(document, context.editableTargetCache);
1511
- const paragraphIndexByTargetKey = /* @__PURE__ */ new Map();
1512
- let paragraphIndex = 0;
1513
- for (const target of currentTargets) {
1514
- if (!isParagraphTextTarget(target)) continue;
1515
- if (!paragraphIndexByTargetKey.has(target.targetKey)) {
1516
- paragraphIndexByTargetKey.set(target.targetKey, paragraphIndex);
1517
- paragraphIndex += 1;
1518
- }
1531
+ const paragraphIndexByAddress = /* @__PURE__ */ new Map();
1532
+ for (let index = 0; index < paragraphs.length; index += 1) {
1533
+ const entry = paragraphs[index];
1534
+ if (!entry) continue;
1535
+ paragraphIndexByAddress.set(`${entry.storyKey}
1536
+ ${entry.blockPath}`, index);
1519
1537
  }
1520
1538
  const resolvedIndexes = [];
1521
1539
  for (const target of editableTargets) {
@@ -1540,7 +1558,8 @@ function resolveListCommandParagraphIndexes(document, paragraphs, paragraphIndex
1540
1558
  }
1541
1559
  };
1542
1560
  }
1543
- const currentIndex = paragraphIndexByTargetKey.get(current.targetKey);
1561
+ const currentIndex = paragraphIndexByAddress.get(`${current.storyKey}
1562
+ ${current.blockPath}`);
1544
1563
  if (currentIndex === void 0) {
1545
1564
  return {
1546
1565
  paragraphIndexes: [],
@@ -1615,18 +1634,28 @@ function sortJson(value) {
1615
1634
  return value;
1616
1635
  }
1617
1636
  function findAdjacentCompatibleInstance(paragraphs, catalog, fromIndex, kind) {
1637
+ const current = paragraphs[fromIndex];
1618
1638
  const previous = paragraphs[fromIndex - 1];
1619
- if (previous?.numbering) {
1620
- const previousKind = getListKind(catalog, previous.numbering.numberingInstanceId);
1639
+ if (previous?.storyKey !== current?.storyKey) {
1640
+ return void 0;
1641
+ }
1642
+ const previousParagraph = previous?.paragraph;
1643
+ if (previousParagraph?.numbering) {
1644
+ const previousKind = getListKind(catalog, previousParagraph.numbering.numberingInstanceId);
1621
1645
  if (previousKind === kind) {
1622
- return previous.numbering.numberingInstanceId;
1646
+ return previousParagraph.numbering.numberingInstanceId;
1623
1647
  }
1624
1648
  }
1625
1649
  return void 0;
1626
1650
  }
1627
1651
  function findPreviousCompatibleInstance(paragraphs, catalog, fromIndex, kind) {
1652
+ const storyKey = paragraphs[fromIndex]?.storyKey;
1628
1653
  for (let index = fromIndex - 1; index >= 0; index -= 1) {
1629
- const paragraph = paragraphs[index];
1654
+ const entry = paragraphs[index];
1655
+ if (entry?.storyKey !== storyKey) {
1656
+ break;
1657
+ }
1658
+ const paragraph = entry.paragraph;
1630
1659
  if (!paragraph?.numbering) {
1631
1660
  continue;
1632
1661
  }
@@ -1645,7 +1674,14 @@ function cloneEnvelope(document, timestamp) {
1645
1674
  function captureEditableParagraphs(document) {
1646
1675
  if (isDocumentRoot(document.content)) {
1647
1676
  const paragraphs = [];
1648
- collectEditableParagraphs(document.content.children, paragraphs);
1677
+ for (const context of collectStoryBlockContexts(document)) {
1678
+ collectEditableParagraphs(
1679
+ context.blocks,
1680
+ paragraphs,
1681
+ context.storyKey,
1682
+ context.basePath
1683
+ );
1684
+ }
1649
1685
  return paragraphs;
1650
1686
  }
1651
1687
  const fallback = {
@@ -1653,23 +1689,39 @@ function captureEditableParagraphs(document) {
1653
1689
  children: [{ type: "paragraph", children: [] }]
1654
1690
  };
1655
1691
  document.content = fallback;
1656
- return fallback.children;
1657
- }
1658
- function collectEditableParagraphs(blocks, output) {
1659
- for (const block of blocks) {
1692
+ return [{
1693
+ paragraph: fallback.children[0],
1694
+ storyKey: "main",
1695
+ blockPath: "main/block[0]"
1696
+ }];
1697
+ }
1698
+ function collectEditableParagraphs(blocks, output, storyKey, basePath) {
1699
+ for (let blockIndex = 0; blockIndex < blocks.length; blockIndex += 1) {
1700
+ const block = blocks[blockIndex];
1701
+ if (!block) continue;
1702
+ const blockPath = `${basePath}/block[${blockIndex}]`;
1660
1703
  switch (block.type) {
1661
1704
  case "paragraph":
1662
- output.push(block);
1705
+ output.push({ paragraph: block, storyKey, blockPath });
1663
1706
  break;
1664
1707
  case "table":
1665
- for (const row2 of block.rows) {
1666
- for (const cell of row2.cells) {
1667
- collectEditableParagraphs(cell.children, output);
1708
+ for (let rowIndex = 0; rowIndex < block.rows.length; rowIndex += 1) {
1709
+ const row2 = block.rows[rowIndex];
1710
+ if (!row2) continue;
1711
+ for (let cellIndex = 0; cellIndex < row2.cells.length; cellIndex += 1) {
1712
+ const cell = row2.cells[cellIndex];
1713
+ if (!cell) continue;
1714
+ collectEditableParagraphs(
1715
+ cell.children,
1716
+ output,
1717
+ storyKey,
1718
+ `${blockPath}/row[${rowIndex}]/cell[${cellIndex}]`
1719
+ );
1668
1720
  }
1669
1721
  }
1670
1722
  break;
1671
1723
  case "sdt":
1672
- collectEditableParagraphs(block.children, output);
1724
+ collectEditableParagraphs(block.children, output, storyKey, blockPath);
1673
1725
  break;
1674
1726
  case "custom_xml":
1675
1727
  break;
@@ -1681,6 +1733,18 @@ function collectEditableParagraphs(blocks, output) {
1681
1733
  function normalizeParagraphIndexes(paragraphs, paragraphIndexes) {
1682
1734
  return [...new Set(paragraphIndexes)].filter((index) => Number.isInteger(index) && index >= 0 && index < paragraphs.length).sort((left, right) => left - right);
1683
1735
  }
1736
+ function normalizeParagraphIndexesForStory(paragraphs, paragraphIndexes, storyKey) {
1737
+ if (storyKey === void 0) {
1738
+ return normalizeParagraphIndexes(paragraphs, paragraphIndexes);
1739
+ }
1740
+ const storyParagraphIndexes = [];
1741
+ for (let index = 0; index < paragraphs.length; index += 1) {
1742
+ if (paragraphs[index]?.storyKey === storyKey) {
1743
+ storyParagraphIndexes.push(index);
1744
+ }
1745
+ }
1746
+ return [...new Set(paragraphIndexes)].filter((index) => Number.isInteger(index) && index >= 0 && index < storyParagraphIndexes.length).map((index) => storyParagraphIndexes[index]).sort((left, right) => left - right);
1747
+ }
1684
1748
  function clampLevel(level) {
1685
1749
  return Math.max(0, Math.min(8, level));
1686
1750
  }
@@ -1825,8 +1889,9 @@ function applyFragmentInsert(document, selection, fragment, context) {
1825
1889
  workingDocument = collapseResult.document;
1826
1890
  workingSelection = collapseResult.selection;
1827
1891
  if (context.textTarget?.kind === "table-paragraph" || context.textTarget?.kind === "text-leaf") {
1892
+ const { precomputedSurface: _precomputedSurface, ...contextWithoutPrecomputedSurface } = context;
1828
1893
  workingContext = {
1829
- ...context,
1894
+ ...contextWithoutPrecomputedSurface,
1830
1895
  textTarget: {
1831
1896
  ...context.textTarget,
1832
1897
  paragraphEnd: Math.max(
@@ -1838,7 +1903,11 @@ function applyFragmentInsert(document, selection, fragment, context) {
1838
1903
  }
1839
1904
  }
1840
1905
  const splitResult = splitParagraph(workingDocument, workingSelection, workingContext);
1841
- const splitRoot = splitResult.document.content;
1906
+ const preparedFragment = prepareFragmentNumberingForInsertion(
1907
+ splitResult.document,
1908
+ fragment
1909
+ );
1910
+ const splitRoot = preparedFragment.document.content;
1842
1911
  if (!splitRoot || splitRoot.type !== "doc") {
1843
1912
  return {
1844
1913
  changed: false,
@@ -1849,9 +1918,9 @@ function applyFragmentInsert(document, selection, fragment, context) {
1849
1918
  const targetedBlockPath = workingContext.textTarget?.kind === "table-paragraph" || workingContext.textTarget?.kind === "text-leaf" ? workingContext.textTarget.blockPath : void 0;
1850
1919
  if (targetedBlockPath) {
1851
1920
  const targeted = insertFragmentBlocksAfterPath(
1852
- splitResult.document,
1921
+ preparedFragment.document,
1853
1922
  targetedBlockPath,
1854
- fragment.blocks
1923
+ preparedFragment.blocks
1855
1924
  );
1856
1925
  if (targeted) {
1857
1926
  return {
@@ -1883,7 +1952,7 @@ function applyFragmentInsert(document, selection, fragment, context) {
1883
1952
  const rightHalfIndex = scope.blockIndex + 1;
1884
1953
  const splicedChildren = [
1885
1954
  ...splitRoot.children.slice(0, rightHalfIndex),
1886
- ...fragment.blocks.map((block) => cloneBlock(block)),
1955
+ ...preparedFragment.blocks.map((block) => cloneBlock(block)),
1887
1956
  ...splitRoot.children.slice(rightHalfIndex)
1888
1957
  ];
1889
1958
  const nextRoot = {
@@ -1891,7 +1960,7 @@ function applyFragmentInsert(document, selection, fragment, context) {
1891
1960
  children: splicedChildren
1892
1961
  };
1893
1962
  const nextDocument = {
1894
- ...splitResult.document,
1963
+ ...preparedFragment.document,
1895
1964
  updatedAt: context.timestamp,
1896
1965
  content: nextRoot
1897
1966
  };
@@ -1903,14 +1972,47 @@ function applyFragmentInsert(document, selection, fragment, context) {
1903
1972
  mapping: createEmptyMapping()
1904
1973
  };
1905
1974
  }
1906
- function cloneBlock(block) {
1907
- if (block.type === "paragraph") {
1908
- return {
1909
- ...block,
1910
- children: block.children.map((child) => ({ ...child }))
1975
+ function prepareFragmentNumberingForInsertion(document, fragment) {
1976
+ if (!fragment.numbering) {
1977
+ return { document, blocks: fragment.blocks };
1978
+ }
1979
+ const merged = mergeFragmentNumberingCatalog(document.numbering, fragment.numbering);
1980
+ return {
1981
+ document: {
1982
+ ...document,
1983
+ numbering: merged.catalog
1984
+ },
1985
+ blocks: fragment.blocks.map((block) => cloneBlock(block, merged.instanceIdMap))
1986
+ };
1987
+ }
1988
+ function cloneBlock(block, numberingInstanceIdMap) {
1989
+ const cloned = structuredClone(block);
1990
+ remapNumberingReferences(cloned, numberingInstanceIdMap);
1991
+ return cloned;
1992
+ }
1993
+ function remapNumberingReferences(value, numberingInstanceIdMap) {
1994
+ if (!numberingInstanceIdMap?.size || !value || typeof value !== "object") {
1995
+ return;
1996
+ }
1997
+ if (Array.isArray(value)) {
1998
+ for (const entry of value) {
1999
+ remapNumberingReferences(entry, numberingInstanceIdMap);
2000
+ }
2001
+ return;
2002
+ }
2003
+ const record = value;
2004
+ if (record.numbering?.numberingInstanceId) {
2005
+ const mappedId = numberingInstanceIdMap.get(record.numbering.numberingInstanceId) ?? record.numbering.numberingInstanceId;
2006
+ record.numbering = {
2007
+ ...record.numbering,
2008
+ numberingInstanceId: mappedId
1911
2009
  };
1912
2010
  }
1913
- return JSON.parse(JSON.stringify(block));
2011
+ remapNumberingReferences(record.children, numberingInstanceIdMap);
2012
+ remapNumberingReferences(record.rows, numberingInstanceIdMap);
2013
+ remapNumberingReferences(record.cells, numberingInstanceIdMap);
2014
+ remapNumberingReferences(record.txbxBlocks, numberingInstanceIdMap);
2015
+ remapNumberingReferences(record.content, numberingInstanceIdMap);
1914
2016
  }
1915
2017
  function insertFragmentBlocksAfterPath(document, blockPath, fragmentBlocks) {
1916
2018
  const tokens = parseCanonicalBlockPath(blockPath);
@@ -7402,6 +7504,16 @@ function coerceIssueValue(value) {
7402
7504
  function insertScopeMarkers(document, params) {
7403
7505
  const { scopeId } = params;
7404
7506
  const root = document.content;
7507
+ if (!Number.isFinite(params.from) || !Number.isFinite(params.to)) {
7508
+ const from = Number.isFinite(params.from) ? params.from : 0;
7509
+ const to = Number.isFinite(params.to) ? params.to : from;
7510
+ return {
7511
+ status: "non-finite-range",
7512
+ scopeId,
7513
+ from,
7514
+ to
7515
+ };
7516
+ }
7405
7517
  const normalizedFrom = Math.min(params.from, params.to);
7406
7518
  const normalizedTo = Math.max(params.from, params.to);
7407
7519
  if (!root || root.type !== "doc" || root.children.length === 0) {
@@ -7854,6 +7966,14 @@ function isRecord(value) {
7854
7966
  }
7855
7967
 
7856
7968
  // src/runtime/workflow/coordinator.ts
7969
+ function createScopeMarkerMutationMapping() {
7970
+ return {
7971
+ steps: [],
7972
+ metadata: {
7973
+ layoutNeutralScopeMarkers: true
7974
+ }
7975
+ };
7976
+ }
7857
7977
  var MODE_RESTRICTIVENESS = {
7858
7978
  edit: 0,
7859
7979
  suggest: 1,
@@ -8161,6 +8281,60 @@ function createWorkflowCoordinator(deps) {
8161
8281
  activeStory: deps.getActiveStory()
8162
8282
  };
8163
8283
  }
8284
+ function createPlantFailureResult(input) {
8285
+ const { scopeId, anchor, assoc, plantResult } = input;
8286
+ return {
8287
+ scopeId: "",
8288
+ anchor: {
8289
+ kind: "range",
8290
+ from: anchor.from,
8291
+ to: anchor.to,
8292
+ assoc
8293
+ },
8294
+ plantStatus: {
8295
+ planted: false,
8296
+ reason: plantResult.status,
8297
+ ...plantResult.status === "non-paragraph-target" ? {
8298
+ blockIndex: plantResult.blockIndex,
8299
+ blockKind: plantResult.blockKind
8300
+ } : {},
8301
+ ...plantResult.status === "range-out-of-bounds" ? { storyLength: plantResult.storyLength } : {},
8302
+ requestedFrom: plantResult.from,
8303
+ requestedTo: plantResult.to
8304
+ }
8305
+ };
8306
+ }
8307
+ function buildWorkflowScope(input) {
8308
+ const { params, scopeId, publicAnchor } = input;
8309
+ return {
8310
+ scopeId,
8311
+ mode: params.mode ?? "comment",
8312
+ anchor: publicAnchor,
8313
+ ...params.storyTarget ? { storyTarget: params.storyTarget } : {},
8314
+ ...params.label ? { label: params.label } : {},
8315
+ ...params.visibility ? { visibility: params.visibility } : {},
8316
+ ...params.guardPolicy ? { guardPolicy: params.guardPolicy } : {},
8317
+ ...params.scopeMetadataFields && params.scopeMetadataFields.length > 0 ? { metadata: [...params.scopeMetadataFields] } : {}
8318
+ };
8319
+ }
8320
+ function buildWorkflowMetadataEntry(input) {
8321
+ const { params, scopeId, publicAnchor } = input;
8322
+ if (!params.persistence || params.persistence === "runtime-only") return null;
8323
+ const requestedMetadata = params.metadata ?? {};
8324
+ const entryPersistence = requestedMetadata.metadataPersistence ?? (params.persistence === "session" ? "external" : "internal");
8325
+ return {
8326
+ entryId: requestedMetadata.entryId ?? `scope-metadata-${scopeId}`,
8327
+ metadataId: requestedMetadata.metadataId ?? "workflow.scope",
8328
+ anchor: publicAnchor,
8329
+ ...params.storyTarget ? { storyTarget: params.storyTarget } : {},
8330
+ scopeId,
8331
+ ...requestedMetadata.workItemId ? { workItemId: requestedMetadata.workItemId } : {},
8332
+ ...requestedMetadata.value !== void 0 ? { value: requestedMetadata.value } : params.persistence === "document-metadata" && params.label ? { value: { label: params.label } } : {},
8333
+ metadataPersistence: entryPersistence,
8334
+ ...requestedMetadata.storageRef !== void 0 ? { storageRef: requestedMetadata.storageRef } : {},
8335
+ ...requestedMetadata.metadataVersion !== void 0 ? { metadataVersion: requestedMetadata.metadataVersion } : {}
8336
+ };
8337
+ }
8164
8338
  function addScope(params) {
8165
8339
  const state = deps.getState();
8166
8340
  const scopeId = params.scopeId ?? `scope-${clock().replace(/[^0-9]/gu, "")}-${Math.floor(Math.random() * 1e6)}`;
@@ -8203,6 +8377,7 @@ function createWorkflowCoordinator(deps) {
8203
8377
  deps.dispatch({
8204
8378
  type: "document.replace",
8205
8379
  document: nextDocument,
8380
+ mapping: createScopeMarkerMutationMapping(),
8206
8381
  origin: { source: "api", at: clock() }
8207
8382
  });
8208
8383
  const callerAssoc = params.anchor.kind === "range" ? params.anchor.assoc : { start: -1, end: 1 };
@@ -8259,6 +8434,86 @@ function createWorkflowCoordinator(deps) {
8259
8434
  }
8260
8435
  return { scopeId, anchor: publicAnchor };
8261
8436
  }
8437
+ function addScopes(paramsList) {
8438
+ if (paramsList.length === 0) return [];
8439
+ return deps.runInRuntimeBatch("workflow.addScopes", () => {
8440
+ let nextDocument = deps.getDocument();
8441
+ let documentChanged = false;
8442
+ const results = [];
8443
+ const scopesToAdd = [];
8444
+ const metadataEntriesToAdd = [];
8445
+ const newScopeIds = /* @__PURE__ */ new Set();
8446
+ for (const params of paramsList) {
8447
+ const scopeId = params.scopeId ?? `scope-${clock().replace(/[^0-9]/gu, "")}-${Math.floor(Math.random() * 1e6)}`;
8448
+ const anchor = params.anchor.kind === "range" ? { from: params.anchor.from, to: params.anchor.to } : null;
8449
+ if (!anchor) {
8450
+ results.push({ scopeId, anchor: params.anchor });
8451
+ continue;
8452
+ }
8453
+ const callerAssoc = params.anchor.kind === "range" ? params.anchor.assoc : { start: -1, end: 1 };
8454
+ const plantResult = insertScopeMarkers(nextDocument, {
8455
+ scopeId,
8456
+ from: anchor.from,
8457
+ to: anchor.to
8458
+ });
8459
+ if (plantResult.status !== "planted") {
8460
+ results.push(
8461
+ createPlantFailureResult({
8462
+ scopeId,
8463
+ anchor,
8464
+ assoc: callerAssoc,
8465
+ plantResult
8466
+ })
8467
+ );
8468
+ continue;
8469
+ }
8470
+ nextDocument = plantResult.document;
8471
+ documentChanged = true;
8472
+ const publicAnchor = {
8473
+ kind: "range",
8474
+ from: plantResult.plantedRange.from,
8475
+ to: plantResult.plantedRange.to,
8476
+ assoc: callerAssoc
8477
+ };
8478
+ newScopeIds.add(scopeId);
8479
+ scopesToAdd.push(buildWorkflowScope({ params, scopeId, publicAnchor }));
8480
+ const entry = buildWorkflowMetadataEntry({ params, scopeId, publicAnchor });
8481
+ if (entry) metadataEntriesToAdd.push(entry);
8482
+ results.push({ scopeId, anchor: publicAnchor });
8483
+ }
8484
+ if (documentChanged) {
8485
+ deps.dispatch({
8486
+ type: "document.replace",
8487
+ document: nextDocument,
8488
+ mapping: createScopeMarkerMutationMapping(),
8489
+ origin: { source: "api", at: clock() }
8490
+ });
8491
+ }
8492
+ if (scopesToAdd.length > 0) {
8493
+ const currentOverlay = overlayStore.getOverlay() ?? {
8494
+ overlayVersion: "workflow-overlay/1",
8495
+ scopes: []
8496
+ };
8497
+ const existingScopes = currentOverlay.scopes.filter(
8498
+ (existing) => !newScopeIds.has(existing.scopeId)
8499
+ );
8500
+ deps.dispatch({
8501
+ type: "workflow.set-overlay",
8502
+ overlay: { ...currentOverlay, scopes: [...existingScopes, ...scopesToAdd] },
8503
+ origin: { source: "api", at: clock() }
8504
+ });
8505
+ }
8506
+ if (metadataEntriesToAdd.length > 0) {
8507
+ const priorEntries = overlayStore.getMetadataEntries();
8508
+ deps.dispatch({
8509
+ type: "workflow.set-metadata-entries",
8510
+ entries: [...priorEntries, ...metadataEntriesToAdd],
8511
+ origin: { source: "api", at: clock() }
8512
+ });
8513
+ }
8514
+ return results;
8515
+ });
8516
+ }
8262
8517
  function removeScope(scopeId) {
8263
8518
  const overlay = overlayStore.getOverlay();
8264
8519
  if (overlay) {
@@ -8276,6 +8531,7 @@ function createWorkflowCoordinator(deps) {
8276
8531
  deps.dispatch({
8277
8532
  type: "document.replace",
8278
8533
  document: nextDocument,
8534
+ mapping: createScopeMarkerMutationMapping(),
8279
8535
  origin: { source: "api", at: clock() }
8280
8536
  });
8281
8537
  }
@@ -8669,6 +8925,7 @@ function createWorkflowCoordinator(deps) {
8669
8925
  }
8670
8926
  return {
8671
8927
  addScope,
8928
+ addScopes,
8672
8929
  removeScope,
8673
8930
  addInvisibleScope,
8674
8931
  setScopeVisibility,
@@ -12707,6 +12964,10 @@ function createDocumentRuntime(options) {
12707
12964
  const sessionId = createSessionId(options.documentId, clock());
12708
12965
  const listeners = /* @__PURE__ */ new Set();
12709
12966
  const eventListeners = /* @__PURE__ */ new Set();
12967
+ let runtimeNotificationBatchDepth = 0;
12968
+ let pendingRuntimeListenerNotify = false;
12969
+ let pendingRenderSnapshotRefresh = false;
12970
+ const pendingRuntimeEvents = [];
12710
12971
  const loadScheduler = options.loadScheduler ?? createLoadScheduler({ backendOverride: "sync" });
12711
12972
  let effectiveMarkupModeProvider;
12712
12973
  const perfCounters = new PerfCounters();
@@ -13918,6 +14179,7 @@ function createDocumentRuntime(options) {
13918
14179
  deriveOpaqueWorkflowBlockedReason,
13919
14180
  isBlockedByProtection,
13920
14181
  dispatch: (command) => dispatchToRuntime(command),
14182
+ runInRuntimeBatch: runRuntimeNotificationBatch,
13921
14183
  emitEvent: (event) => emit(event),
13922
14184
  editorStateChannel,
13923
14185
  suggestingUnsupportedCommands: SUGGESTING_UNSUPPORTED_COMMANDS
@@ -14267,9 +14529,7 @@ function createDocumentRuntime(options) {
14267
14529
  ...cachedRenderSnapshot,
14268
14530
  surface: newSurface
14269
14531
  };
14270
- for (const listener of listeners) {
14271
- listener();
14272
- }
14532
+ notifyRuntimeListeners();
14273
14533
  }
14274
14534
  function maybeRefreshSurfaceForViewport() {
14275
14535
  const fingerprint = `${storyTargetKey(activeStory)}|${viewportRangesKey}|${String(state.selection.anchor)}:${String(state.selection.head)}`;
@@ -14871,6 +15131,17 @@ function createDocumentRuntime(options) {
14871
15131
  };
14872
15132
  resolvedReplayTextTarget = prepared.textTarget;
14873
15133
  } else {
15134
+ const listBoundaryJoinCommand = createListItemBoundaryJoinReplayCommand({
15135
+ command,
15136
+ document: replayState.document,
15137
+ selection: replayState.selection,
15138
+ surface: replaySnapshot.surface?.blocks ?? [],
15139
+ storyTarget: replayStory,
15140
+ timestamp: context.timestamp
15141
+ });
15142
+ if (listBoundaryJoinCommand) {
15143
+ executableCommand = listBoundaryJoinCommand;
15144
+ }
14874
15145
  const selectedListItemDeleteCommand = createSelectedListItemDeleteReplayCommand({
14875
15146
  command,
14876
15147
  document: replayState.document,
@@ -15028,6 +15299,17 @@ function createDocumentRuntime(options) {
15028
15299
  };
15029
15300
  resolvedReplayTextTarget = prepared.textTarget;
15030
15301
  } else {
15302
+ const listBoundaryJoinCommand = createListItemBoundaryJoinReplayCommand({
15303
+ command,
15304
+ document: stateForCommand.document,
15305
+ selection: stateForCommand.selection,
15306
+ surface: snapshotForCommand.surface?.blocks ?? [],
15307
+ storyTarget: replayStory,
15308
+ timestamp: context.timestamp
15309
+ });
15310
+ if (listBoundaryJoinCommand) {
15311
+ executableCommand = listBoundaryJoinCommand;
15312
+ }
15031
15313
  const selectedListItemDeleteCommand = createSelectedListItemDeleteReplayCommand({
15032
15314
  command,
15033
15315
  document: stateForCommand.document,
@@ -16057,6 +16339,9 @@ function createDocumentRuntime(options) {
16057
16339
  addScope(params) {
16058
16340
  return workflowCoordinator.addScope(params);
16059
16341
  },
16342
+ addScopes(params) {
16343
+ return workflowCoordinator.addScopes(params);
16344
+ },
16060
16345
  getScope(scopeId) {
16061
16346
  return workflowCoordinator.getScope(scopeId);
16062
16347
  },
@@ -17040,6 +17325,9 @@ function createDocumentRuntime(options) {
17040
17325
  if (transaction.mapping.metadata?.scopeTagTouches) return false;
17041
17326
  return getLocalTextPatchMetadata(transaction.mapping) !== null;
17042
17327
  }
17328
+ function isLayoutNeutralScopeMarkerCommit(previous, next, transaction) {
17329
+ return transaction.markDirty && previous.document !== next.document && transaction.mapping.steps.length === 0 && transaction.mapping.metadata?.layoutNeutralScopeMarkers === true;
17330
+ }
17043
17331
  function applyTransactionToState(transaction, options2 = {}) {
17044
17332
  const effects = transaction.effects;
17045
17333
  const selectionUnchanged = transaction.nextState.selection === state.selection;
@@ -17068,6 +17356,11 @@ function createDocumentRuntime(options) {
17068
17356
  transaction,
17069
17357
  transaction.effects
17070
17358
  );
17359
+ const layoutNeutralScopeMarkerCommit = isLayoutNeutralScopeMarkerCommit(
17360
+ previous,
17361
+ state,
17362
+ transaction
17363
+ );
17071
17364
  perfCounters.increment("commit.refreshClassify.us", Math.round((performance.now() - tClassify0) * 1e3));
17072
17365
  const tOverlay0 = performance.now();
17073
17366
  const skipOverlaySync = useLocalTextCommitSnapshot && canSkipOverlaySyncForLocalText(transaction);
@@ -17116,9 +17409,12 @@ function createDocumentRuntime(options) {
17116
17409
  ...detachedWorkflowScopeWarnings.cleared
17117
17410
  ]
17118
17411
  };
17119
- if (!useLocalTextCommitSnapshot && transaction.markDirty && previous.document !== state.document) {
17412
+ if (!useLocalTextCommitSnapshot && !layoutNeutralScopeMarkerCommit && transaction.markDirty && previous.document !== state.document) {
17120
17413
  applyViewportRanges(getSelectionCorridorViewportRanges(cachedRenderSnapshot.surface));
17121
17414
  }
17415
+ if (layoutNeutralScopeMarkerCommit && viewportBlockRanges !== null) {
17416
+ getCachedFullSurface(state.document, activeStory);
17417
+ }
17122
17418
  const tValidation0 = performance.now();
17123
17419
  const patchSourceSurface = getReusableCachedFullSurface(previous.document, activeStory) ?? cachedRenderSnapshot.surface;
17124
17420
  const patchedFullLocalTextSurface = useLocalTextCommitSnapshot ? tryPatchLocalTextSurface(patchSourceSurface, transaction.mapping) : null;
@@ -17366,9 +17662,7 @@ function createDocumentRuntime(options) {
17366
17662
  code: cleared.code
17367
17663
  });
17368
17664
  }
17369
- for (const listener of listeners) {
17370
- listener();
17371
- }
17665
+ notifyRuntimeListeners();
17372
17666
  }
17373
17667
  function applyTextCommandInActiveStory(command, textOptions = {}) {
17374
17668
  emitStageToken(telemetryBus, "command", "command.dispatch.start", {
@@ -17487,6 +17781,39 @@ function createDocumentRuntime(options) {
17487
17781
  const preSelection = selection;
17488
17782
  const preActiveStory = activeStory;
17489
17783
  const priorDocument = state.document;
17784
+ const listBoundaryJoin = createListItemBoundaryJoinReplacement({
17785
+ command: commandForDispatch,
17786
+ document: state.document,
17787
+ editableTarget,
17788
+ selection,
17789
+ storyTarget: activeStory,
17790
+ targetResolution,
17791
+ timestamp
17792
+ });
17793
+ if (listBoundaryJoin && context.documentMode !== "suggesting") {
17794
+ const replacementCommand = {
17795
+ type: "document.replace",
17796
+ document: listBoundaryJoin.document,
17797
+ selection: listBoundaryJoin.selection,
17798
+ mapping: listBoundaryJoin.mapping,
17799
+ protectionSelection: selection,
17800
+ origin: commandForDispatch.origin
17801
+ };
17802
+ const transaction = executeEditorCommand(baseState, replacementCommand, context);
17803
+ commit(transaction);
17804
+ options.onCommandApplied?.(commandForDispatch, transaction, context, {
17805
+ preSelection,
17806
+ activeStory: preActiveStory,
17807
+ priorDocument
17808
+ });
17809
+ return completeDispatch(classifyAck({
17810
+ command: commandForDispatch,
17811
+ opId,
17812
+ priorState: baseState,
17813
+ transaction,
17814
+ newRevisionToken: state.revisionToken
17815
+ }));
17816
+ }
17490
17817
  const selectedListItemDelete = createSelectedListItemDeleteReplacement({
17491
17818
  command: commandForDispatch,
17492
17819
  document: state.document,
@@ -17928,7 +18255,7 @@ function createDocumentRuntime(options) {
17928
18255
  const warningDelta = workflowCoordinator.applyOverlayCommand(
17929
18256
  command,
17930
18257
  () => {
17931
- cachedRenderSnapshot = refreshRenderSnapshot();
18258
+ requestRuntimeRenderSnapshotRefresh();
17932
18259
  }
17933
18260
  );
17934
18261
  if (warningDelta) {
@@ -17986,11 +18313,69 @@ function createDocumentRuntime(options) {
17986
18313
  });
17987
18314
  }
17988
18315
  }
18316
+ notifyRuntimeListeners();
18317
+ }
18318
+ function runRuntimeNotificationBatch(label, fn) {
18319
+ runtimeNotificationBatchDepth += 1;
18320
+ perfCounters.increment(`runtime.notificationBatch.${label}.calls`);
18321
+ try {
18322
+ return fn();
18323
+ } finally {
18324
+ runtimeNotificationBatchDepth -= 1;
18325
+ if (runtimeNotificationBatchDepth === 0) {
18326
+ flushRuntimeNotificationBatch();
18327
+ }
18328
+ }
18329
+ }
18330
+ function requestRuntimeRenderSnapshotRefresh() {
18331
+ if (runtimeNotificationBatchDepth > 0) {
18332
+ pendingRenderSnapshotRefresh = true;
18333
+ perfCounters.increment("runtime.notificationBatch.renderRefreshDeferred");
18334
+ return;
18335
+ }
18336
+ cachedRenderSnapshot = refreshRenderSnapshot();
18337
+ }
18338
+ function notifyRuntimeListeners() {
18339
+ if (runtimeNotificationBatchDepth > 0) {
18340
+ pendingRuntimeListenerNotify = true;
18341
+ perfCounters.increment("runtime.notificationBatch.listenerNotifyDeferred");
18342
+ return;
18343
+ }
18344
+ notifyRuntimeListenersNow();
18345
+ }
18346
+ function notifyRuntimeListenersNow() {
17989
18347
  for (const listener of listeners) {
17990
18348
  listener();
17991
18349
  }
17992
18350
  }
18351
+ function flushRuntimeNotificationBatch() {
18352
+ if (pendingRenderSnapshotRefresh) {
18353
+ pendingRenderSnapshotRefresh = false;
18354
+ cachedRenderSnapshot = refreshRenderSnapshot();
18355
+ perfCounters.increment("runtime.notificationBatch.renderRefreshFlushed");
18356
+ }
18357
+ if (pendingRuntimeEvents.length > 0) {
18358
+ const queuedEvents = pendingRuntimeEvents.splice(0);
18359
+ perfCounters.increment("runtime.notificationBatch.eventsFlushed", queuedEvents.length);
18360
+ for (const event of queuedEvents) {
18361
+ emitInternalNow(event);
18362
+ }
18363
+ }
18364
+ if (pendingRuntimeListenerNotify) {
18365
+ pendingRuntimeListenerNotify = false;
18366
+ perfCounters.increment("runtime.notificationBatch.listenerNotifyFlushed");
18367
+ notifyRuntimeListenersNow();
18368
+ }
18369
+ }
17993
18370
  function emitInternal(event) {
18371
+ if (runtimeNotificationBatchDepth > 0) {
18372
+ pendingRuntimeEvents.push(event);
18373
+ perfCounters.increment("runtime.notificationBatch.eventsQueued");
18374
+ return;
18375
+ }
18376
+ emitInternalNow(event);
18377
+ }
18378
+ function emitInternalNow(event) {
17994
18379
  options.onEvent?.(event);
17995
18380
  for (const listener of eventListeners) {
17996
18381
  listener(event);
@@ -20403,6 +20788,56 @@ function stripStoryTarget(selection) {
20403
20788
  function isTopLevelMainStoryBlockPath(blockPath) {
20404
20789
  return typeof blockPath === "string" && /^main\/block\[\d+\]$/u.test(blockPath);
20405
20790
  }
20791
+ function createListItemBoundaryJoinReplacement(input) {
20792
+ const { command, document, editableTarget, selection, storyTarget, targetResolution, timestamp } = input;
20793
+ const direction = listItemBoundaryJoinDirection(command, selection, targetResolution);
20794
+ if (!direction || editableTarget?.listAddress?.operationScope !== "list-text" || targetResolution?.kind !== "accepted") {
20795
+ return null;
20796
+ }
20797
+ const storyBlocks = getStoryBlocks(document, storyTarget);
20798
+ const replacement = joinNumberedParagraphAtStoryPath(
20799
+ storyBlocks,
20800
+ editableTarget.blockPath,
20801
+ storyTarget,
20802
+ direction
20803
+ );
20804
+ if (!replacement) {
20805
+ return null;
20806
+ }
20807
+ const nextDocument = replaceStoryBlocks({
20808
+ ...document,
20809
+ updatedAt: timestamp
20810
+ }, storyTarget, replacement.blocks);
20811
+ const deletedFrom = direction === "backward" ? Math.max(0, selection.anchor - 1) : selection.anchor;
20812
+ const deletedTo = direction === "backward" ? selection.anchor : selection.anchor + 1;
20813
+ const nextAnchor = direction === "backward" ? deletedFrom : selection.anchor;
20814
+ return {
20815
+ document: nextDocument,
20816
+ selection: createSelectionSnapshot(nextAnchor, nextAnchor),
20817
+ mapping: {
20818
+ steps: [{
20819
+ from: deletedFrom,
20820
+ to: deletedTo,
20821
+ insertSize: 0
20822
+ }],
20823
+ metadata: {
20824
+ invalidatesStructures: true
20825
+ }
20826
+ }
20827
+ };
20828
+ }
20829
+ function listItemBoundaryJoinDirection(command, selection, targetResolution) {
20830
+ if (selection.isCollapsed !== true || targetResolution?.kind !== "accepted") {
20831
+ return null;
20832
+ }
20833
+ if (command.type === "text.delete-backward" && selection.anchor === targetResolution.range.from) {
20834
+ return "backward";
20835
+ }
20836
+ if (command.type === "text.delete-forward" && selection.anchor === targetResolution.range.to) {
20837
+ return "forward";
20838
+ }
20839
+ return null;
20840
+ }
20406
20841
  function createSelectedListItemDeleteReplacement(input) {
20407
20842
  const { command, document, editableTarget, selection, storyTarget, targetResolution, timestamp } = input;
20408
20843
  if (command.type !== "text.delete-backward" && command.type !== "text.delete-forward") {
@@ -20450,6 +20885,152 @@ function removeNumberedParagraphAtStoryPath(blocks, blockPath, storyTarget) {
20450
20885
  if (!tokens) return null;
20451
20886
  return removeNumberedParagraphFromBlocks(blocks, tokens);
20452
20887
  }
20888
+ function joinNumberedParagraphAtStoryPath(blocks, blockPath, storyTarget, direction) {
20889
+ const tokens = parseStoryBlockPathTokens(blockPath, storyTarget);
20890
+ if (!tokens) return null;
20891
+ return joinNumberedParagraphFromBlocks(blocks, tokens, direction);
20892
+ }
20893
+ function joinNumberedParagraphFromBlocks(blocks, tokens, direction) {
20894
+ const [token, ...rest] = tokens;
20895
+ if (!token || token.kind !== "block") return null;
20896
+ const block = blocks[token.index];
20897
+ if (!block) return null;
20898
+ if (rest.length === 0) {
20899
+ return joinAdjacentNumberedParagraphs(blocks, token.index, direction);
20900
+ }
20901
+ const next = rest[0];
20902
+ if (block.type === "table" && next?.kind === "row") {
20903
+ const updatedTable = joinNumberedParagraphInTable(block, rest, direction);
20904
+ if (!updatedTable) return null;
20905
+ return {
20906
+ blocks: [
20907
+ ...blocks.slice(0, token.index),
20908
+ updatedTable,
20909
+ ...blocks.slice(token.index + 1)
20910
+ ]
20911
+ };
20912
+ }
20913
+ if ((block.type === "sdt" || block.type === "custom_xml") && next?.kind === "block") {
20914
+ const updatedChildren = joinNumberedParagraphFromBlocks(block.children, rest, direction);
20915
+ if (!updatedChildren) return null;
20916
+ return {
20917
+ blocks: [
20918
+ ...blocks.slice(0, token.index),
20919
+ { ...block, children: updatedChildren.blocks },
20920
+ ...blocks.slice(token.index + 1)
20921
+ ]
20922
+ };
20923
+ }
20924
+ if (block.type === "paragraph" && next?.kind === "inline") {
20925
+ const updatedParagraph = joinNumberedParagraphInTextBoxInline(block, rest, direction);
20926
+ if (!updatedParagraph) return null;
20927
+ return {
20928
+ blocks: [
20929
+ ...blocks.slice(0, token.index),
20930
+ updatedParagraph,
20931
+ ...blocks.slice(token.index + 1)
20932
+ ]
20933
+ };
20934
+ }
20935
+ return null;
20936
+ }
20937
+ function joinAdjacentNumberedParagraphs(blocks, targetIndex, direction) {
20938
+ const target = blocks[targetIndex];
20939
+ if (target?.type !== "paragraph" || !target.numbering) {
20940
+ return null;
20941
+ }
20942
+ if (direction === "backward") {
20943
+ const previousIndex = targetIndex - 1;
20944
+ const previous = blocks[previousIndex];
20945
+ if (previous?.type !== "paragraph" || !previous.numbering) {
20946
+ return null;
20947
+ }
20948
+ const merged2 = {
20949
+ ...previous,
20950
+ children: [...previous.children, ...target.children]
20951
+ };
20952
+ return {
20953
+ blocks: [
20954
+ ...blocks.slice(0, previousIndex),
20955
+ merged2,
20956
+ ...blocks.slice(targetIndex + 1)
20957
+ ]
20958
+ };
20959
+ }
20960
+ const nextIndex = targetIndex + 1;
20961
+ const next = blocks[nextIndex];
20962
+ if (next?.type !== "paragraph" || !next.numbering) {
20963
+ return null;
20964
+ }
20965
+ const merged = {
20966
+ ...target,
20967
+ children: [...target.children, ...next.children]
20968
+ };
20969
+ return {
20970
+ blocks: [
20971
+ ...blocks.slice(0, targetIndex),
20972
+ merged,
20973
+ ...blocks.slice(nextIndex + 1)
20974
+ ]
20975
+ };
20976
+ }
20977
+ function joinNumberedParagraphInTable(table, tokens, direction) {
20978
+ const [rowToken, cellToken, ...childTokens] = tokens;
20979
+ if (rowToken?.kind !== "row" || cellToken?.kind !== "cell" || childTokens[0]?.kind !== "block") {
20980
+ return null;
20981
+ }
20982
+ const row2 = table.rows[rowToken.index];
20983
+ const cell = row2?.cells[cellToken.index];
20984
+ if (!row2 || !cell) return null;
20985
+ const updatedChildren = joinNumberedParagraphFromBlocks(cell.children, childTokens, direction);
20986
+ if (!updatedChildren) return null;
20987
+ const nextCells = [
20988
+ ...row2.cells.slice(0, cellToken.index),
20989
+ { ...cell, children: updatedChildren.blocks },
20990
+ ...row2.cells.slice(cellToken.index + 1)
20991
+ ];
20992
+ const nextRows = [
20993
+ ...table.rows.slice(0, rowToken.index),
20994
+ { ...row2, cells: nextCells },
20995
+ ...table.rows.slice(rowToken.index + 1)
20996
+ ];
20997
+ return { ...table, rows: nextRows };
20998
+ }
20999
+ function joinNumberedParagraphInTextBoxInline(paragraph, tokens, direction) {
21000
+ const [inlineToken, textBoxToken, ...childTokens] = tokens;
21001
+ if (inlineToken?.kind !== "inline" || textBoxToken?.kind !== "txbx" || childTokens[0]?.kind !== "block") {
21002
+ return null;
21003
+ }
21004
+ const inline = paragraph.children[inlineToken.index];
21005
+ if (!inline) return null;
21006
+ const updatedInline = joinNumberedParagraphInInlineTextBox(inline, childTokens, direction);
21007
+ if (!updatedInline) return null;
21008
+ return {
21009
+ ...paragraph,
21010
+ children: [
21011
+ ...paragraph.children.slice(0, inlineToken.index),
21012
+ updatedInline,
21013
+ ...paragraph.children.slice(inlineToken.index + 1)
21014
+ ]
21015
+ };
21016
+ }
21017
+ function joinNumberedParagraphInInlineTextBox(inline, tokens, direction) {
21018
+ if (inline.type === "shape" && inline.txbxBlocks) {
21019
+ const updatedBlocks = joinNumberedParagraphFromBlocks(inline.txbxBlocks, tokens, direction);
21020
+ return updatedBlocks ? { ...inline, txbxBlocks: updatedBlocks.blocks } : null;
21021
+ }
21022
+ if (inline.type === "drawing_frame" && inline.content.type === "shape" && inline.content.txbxBlocks) {
21023
+ const updatedBlocks = joinNumberedParagraphFromBlocks(inline.content.txbxBlocks, tokens, direction);
21024
+ return updatedBlocks ? {
21025
+ ...inline,
21026
+ content: {
21027
+ ...inline.content,
21028
+ txbxBlocks: updatedBlocks.blocks
21029
+ }
21030
+ } : null;
21031
+ }
21032
+ return null;
21033
+ }
20453
21034
  function removeNumberedParagraphFromBlocks(blocks, tokens) {
20454
21035
  const [token, ...rest] = tokens;
20455
21036
  if (!token || token.kind !== "block") return null;
@@ -20612,6 +21193,56 @@ function createSelectedListItemDeleteReplayCommand(input) {
20612
21193
  origin: command.origin
20613
21194
  };
20614
21195
  }
21196
+ function createListItemBoundaryJoinReplayCommand(input) {
21197
+ const { command, document, selection, surface, storyTarget, timestamp } = input;
21198
+ if (command.type !== "text.delete-backward" && command.type !== "text.delete-forward") {
21199
+ return null;
21200
+ }
21201
+ const editableTarget = command.editableTarget;
21202
+ if (!editableTarget) {
21203
+ return null;
21204
+ }
21205
+ const targetResolution = resolveEditableTextTarget({
21206
+ document,
21207
+ selection,
21208
+ surface,
21209
+ target: editableTarget,
21210
+ activeStoryKey: canonicalEditableTargetStoryKey(storyTarget)
21211
+ });
21212
+ const resolvedEditableTarget = targetResolution.kind === "accepted" ? editableTarget : storyTarget.kind !== "main" && blockPathBelongsToStoryTarget(editableTarget.blockPath, storyTarget) ? resolveEditableCommandTarget({
21213
+ document,
21214
+ target: editableTarget,
21215
+ activeStoryKey: canonicalEditableTargetStoryKey(storyTarget),
21216
+ commandFamilies: ["text-leaf"]
21217
+ }) : null;
21218
+ const selectedRange = {
21219
+ from: Math.min(selection.anchor, selection.head),
21220
+ to: Math.max(selection.anchor, selection.head)
21221
+ };
21222
+ const replacement = createListItemBoundaryJoinReplacement({
21223
+ command,
21224
+ document,
21225
+ editableTarget: resolvedEditableTarget && resolvedEditableTarget.kind === "accepted" ? resolvedEditableTarget.target : editableTarget,
21226
+ selection,
21227
+ storyTarget,
21228
+ targetResolution: resolvedEditableTarget && resolvedEditableTarget.kind === "accepted" ? {
21229
+ kind: "accepted",
21230
+ range: selectedRange
21231
+ } : targetResolution,
21232
+ timestamp
21233
+ });
21234
+ if (!replacement) {
21235
+ return null;
21236
+ }
21237
+ return {
21238
+ type: "document.replace",
21239
+ document: replacement.document,
21240
+ selection: replacement.selection,
21241
+ mapping: replacement.mapping,
21242
+ protectionSelection: selection,
21243
+ origin: command.origin
21244
+ };
21245
+ }
20615
21246
  function parseStoryBlockPathTokens(blockPath, storyTarget) {
20616
21247
  if (!blockPath) {
20617
21248
  return null;