@stll/folio-core 0.53.0 → 0.54.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.
Files changed (148) hide show
  1. package/dist/ai-edits/apply.js +390 -166
  2. package/dist/ai-edits/batch-claims.d.ts +21 -6
  3. package/dist/ai-edits/batch-claims.js +47 -16
  4. package/dist/ai-edits/headless.d.ts +20 -0
  5. package/dist/ai-edits/headless.js +140 -11
  6. package/dist/ai-edits/pending-suggestions.js +1 -1
  7. package/dist/ai-edits/read.d.ts +5 -3
  8. package/dist/ai-edits/read.js +97 -47
  9. package/dist/ai-edits/revisionStretches.d.ts +17 -0
  10. package/dist/ai-edits/revisionStretches.js +80 -0
  11. package/dist/ai-edits/snapshot.js +3 -2
  12. package/dist/ai-edits/table-cell-mutations.d.ts +3 -1
  13. package/dist/ai-edits/table-cell-mutations.js +2 -1
  14. package/dist/ai-edits/table-row-column-mutations.d.ts +6 -1
  15. package/dist/ai-edits/table-row-column-mutations.js +27 -10
  16. package/dist/compare/content-alignment.d.ts +5 -1
  17. package/dist/compare/content-alignment.js +39 -32
  18. package/dist/compare/inline-provenance.js +1 -1
  19. package/dist/controller/layoutPipeline.js +3 -2
  20. package/dist/docx/archiveInflation.d.ts +127 -0
  21. package/dist/docx/archiveInflation.js +181 -0
  22. package/dist/docx/metadataPrivacy.js +24 -1
  23. package/dist/docx/noteReferenceMark.d.ts +15 -0
  24. package/dist/docx/noteReferenceMark.js +48 -0
  25. package/dist/docx/paragraphParser.js +5 -3
  26. package/dist/docx/paragraphPropertySource.d.ts +1 -1
  27. package/dist/docx/paragraphPropertySource.js +3 -1
  28. package/dist/docx/parser.js +2 -2
  29. package/dist/docx/rezip.js +4 -2
  30. package/dist/docx/selectiveXmlPatch.d.ts +3 -1
  31. package/dist/docx/selectiveXmlPatch.js +81 -3
  32. package/dist/docx/server/boundedArchive.d.ts +8 -13
  33. package/dist/docx/server/boundedArchive.js +70 -59
  34. package/dist/docx/server/extractDocxText.d.ts +8 -2
  35. package/dist/docx/server/extractDocxText.js +2 -2
  36. package/dist/docx/server/validateDocxConformance.d.ts +1 -1
  37. package/dist/docx/server/validateDocxConformance.js +1 -0
  38. package/dist/docx/unzip.d.ts +19 -2
  39. package/dist/docx/unzip.js +135 -24
  40. package/dist/fonts/embeddedFonts.js +1 -1
  41. package/dist/i18n/messages/catalogs.gen.d.ts +34 -34
  42. package/dist/i18n/messages/catalogs.gen.js +34 -34
  43. package/dist/i18n/messages/messages.gen.d.ts +2 -2
  44. package/dist/internal/wholeStoryRevisionResolution.js +95 -25
  45. package/dist/layout-engine/measure/measureParagraph.js +2 -2
  46. package/dist/layout-engine/measure/paragraphMeasureShared.d.ts +12 -1
  47. package/dist/layout-engine/measure/paragraphMeasureShared.js +14 -1
  48. package/dist/markdown/escape.d.ts +2 -2
  49. package/dist/markdown/escape.js +4 -5
  50. package/dist/markdown/renderBlock.js +91 -25
  51. package/dist/markdown/renderRuns.d.ts +10 -1
  52. package/dist/markdown/renderRuns.js +320 -59
  53. package/dist/prosemirror/clearRunColor.d.ts +6 -0
  54. package/dist/prosemirror/clearRunColor.js +46 -0
  55. package/dist/prosemirror/commands/comments.js +56 -21
  56. package/dist/prosemirror/commands/formatPainter.js +1 -1
  57. package/dist/prosemirror/commands/hyperlink.js +2 -1
  58. package/dist/prosemirror/commands/propertyChangeScope.d.ts +3 -2
  59. package/dist/prosemirror/commands/propertyChangeScope.js +24 -3
  60. package/dist/prosemirror/commands/resolveAllTableChanges.js +46 -41
  61. package/dist/prosemirror/commands/resolveParagraphProperties.js +20 -6
  62. package/dist/prosemirror/commands/tableCellMergeResolution.d.ts +8 -1
  63. package/dist/prosemirror/commands/tableCellMergeResolution.js +23 -7
  64. package/dist/prosemirror/containerFinalParagraph.d.ts +11 -5
  65. package/dist/prosemirror/containerFinalParagraph.js +7 -6
  66. package/dist/prosemirror/conversion/fromProseDoc.d.ts +2 -13
  67. package/dist/prosemirror/conversion/fromProseDoc.js +12 -590
  68. package/dist/prosemirror/conversion/toProseDoc.d.ts +4 -11
  69. package/dist/prosemirror/conversion/toProseDoc.js +31 -150
  70. package/dist/prosemirror/documentSchema.d.ts +8 -0
  71. package/dist/prosemirror/documentSchema.js +18 -0
  72. package/dist/prosemirror/extensions/StarterKit.js +2 -0
  73. package/dist/prosemirror/extensions/core/ParagraphExtension.js +104 -63
  74. package/dist/prosemirror/extensions/features/BaseKeymapExtension.js +1 -1
  75. package/dist/prosemirror/extensions/features/EmptyParagraphFormatExtension.js +24 -3
  76. package/dist/prosemirror/extensions/features/JoinedRunStyleExtension.d.ts +20 -0
  77. package/dist/prosemirror/extensions/features/JoinedRunStyleExtension.js +43 -0
  78. package/dist/prosemirror/extensions/features/ListExtension.js +10 -9
  79. package/dist/prosemirror/extensions/features/pastedHeadingStyles.js +1 -1
  80. package/dist/prosemirror/extensions/features/pastedHtmlLists.js +2 -4
  81. package/dist/prosemirror/extensions/marks/FootnoteRefExtension.js +14 -8
  82. package/dist/prosemirror/extensions/marks/HyperlinkExtension.js +8 -4
  83. package/dist/prosemirror/extensions/marks/StrikeExtension.js +2 -2
  84. package/dist/prosemirror/extensions/marks/SubscriptExtension.js +2 -2
  85. package/dist/prosemirror/extensions/marks/SuperscriptExtension.js +2 -2
  86. package/dist/prosemirror/extensions/marks/TextColorExtension.js +4 -3
  87. package/dist/prosemirror/extensions/marks/markUtils.d.ts +8 -6
  88. package/dist/prosemirror/extensions/marks/markUtils.js +17 -8
  89. package/dist/prosemirror/extensions/marks/noteReferenceDeletion.d.ts +3 -1
  90. package/dist/prosemirror/extensions/marks/noteReferenceDeletion.js +12 -1
  91. package/dist/prosemirror/extensions/nodes/CommentReferenceExtension.js +2 -2
  92. package/dist/prosemirror/extensions/nodes/HardBreakExtension.js +5 -3
  93. package/dist/prosemirror/extensions/nodes/TableExtension.js +104 -210
  94. package/dist/prosemirror/extensions/types.d.ts +7 -0
  95. package/dist/prosemirror/hyperlinkRemoval.d.ts +9 -0
  96. package/dist/prosemirror/hyperlinkRemoval.js +129 -0
  97. package/dist/prosemirror/index.d.ts +2 -1
  98. package/dist/prosemirror/index.js +2 -1
  99. package/dist/prosemirror/listNumbering.d.ts +3 -21
  100. package/dist/prosemirror/listNumbering.js +10 -25
  101. package/dist/prosemirror/listRendering.d.ts +27 -0
  102. package/dist/prosemirror/listRendering.js +27 -0
  103. package/dist/prosemirror/markupViewNotes.d.ts +8 -0
  104. package/dist/prosemirror/markupViewNotes.js +49 -0
  105. package/dist/prosemirror/markupViewProjection.d.ts +3 -1
  106. package/dist/prosemirror/markupViewProjection.js +7 -2
  107. package/dist/prosemirror/noteReferenceReview.d.ts +77 -0
  108. package/dist/prosemirror/noteReferenceReview.js +332 -0
  109. package/dist/prosemirror/paragraphIndentation.js +5 -2
  110. package/dist/prosemirror/paragraphMarkJoin.d.ts +6 -4
  111. package/dist/prosemirror/paragraphMarkJoin.js +21 -19
  112. package/dist/prosemirror/paragraphPropertyCarry.d.ts +64 -0
  113. package/dist/prosemirror/paragraphPropertyCarry.js +158 -0
  114. package/dist/prosemirror/plugins/documentStyleState.d.ts +26 -0
  115. package/dist/prosemirror/plugins/documentStyleState.js +32 -0
  116. package/dist/prosemirror/plugins/documentStyles.d.ts +2 -21
  117. package/dist/prosemirror/plugins/documentStyles.js +66 -29
  118. package/dist/prosemirror/plugins/index.d.ts +2 -1
  119. package/dist/prosemirror/plugins/index.js +2 -1
  120. package/dist/prosemirror/plugins/paragraphStyleResolution.d.ts +15 -0
  121. package/dist/prosemirror/plugins/paragraphStyleResolution.js +230 -0
  122. package/dist/prosemirror/plugins/suggestionMode.d.ts +12 -2
  123. package/dist/prosemirror/plugins/suggestionMode.js +391 -28
  124. package/dist/prosemirror/rebaseParagraphRunFormatting.d.ts +22 -2
  125. package/dist/prosemirror/rebaseParagraphRunFormatting.js +39 -13
  126. package/dist/prosemirror/rebaseParagraphRuns.d.ts +36 -0
  127. package/dist/prosemirror/rebaseParagraphRuns.js +99 -0
  128. package/dist/prosemirror/runFormattingFromMarks.d.ts +18 -0
  129. package/dist/prosemirror/runFormattingFromMarks.js +567 -0
  130. package/dist/prosemirror/runFormattingReconciliation.js +10 -9
  131. package/dist/prosemirror/schema/nodes.d.ts +2 -0
  132. package/dist/prosemirror/styles/paragraphStyleCascade.d.ts +59 -0
  133. package/dist/prosemirror/styles/paragraphStyleCascade.js +145 -0
  134. package/dist/prosemirror/styles/resolvedStyleAttrs.d.ts +21 -2
  135. package/dist/prosemirror/styles/resolvedStyleAttrs.js +38 -1
  136. package/dist/prosemirror/styles/tableStyleRegions.d.ts +31 -0
  137. package/dist/prosemirror/styles/tableStyleRegions.js +55 -0
  138. package/dist/prosemirror/tableCellPaste.d.ts +74 -0
  139. package/dist/prosemirror/tableCellPaste.js +525 -0
  140. package/dist/prosemirror/tableGridMutation.d.ts +53 -14
  141. package/dist/prosemirror/tableGridMutation.js +166 -18
  142. package/dist/prosemirror/tableRunIn.d.ts +51 -0
  143. package/dist/prosemirror/tableRunIn.js +165 -0
  144. package/dist/prosemirror/textInput.js +11 -2
  145. package/dist/prosemirror/trackedRevisionPath.d.ts +17 -0
  146. package/dist/prosemirror/trackedRevisionPath.js +32 -0
  147. package/dist/server.d.ts +2 -2
  148. package/package.json +5 -5
@@ -0,0 +1,6 @@
1
+ import { Command } from "prosemirror-state";
2
+ //#region src/prosemirror/clearRunColor.d.ts
3
+ /** Clearing direct color reveals the run's character/paragraph style color. */
4
+ declare const clearRunColor: () => Command;
5
+ //#endregion
6
+ export { clearRunColor };
@@ -0,0 +1,46 @@
1
+ import { getDocumentStyleResolver } from "./plugins/documentStyleState.js";
2
+ import { applyMarksToRunFormattingRepresentation, selectRunFormattingCarrierRepresentations } from "./runFormattingInlineCarriers.js";
3
+ import { readAuthoredRunFormatting, reconcileRunFormattingMarks } from "./runFormattingReconciliation.js";
4
+ import { paragraphRunStyleContextAt } from "./runStyleFormatting.js";
5
+ //#region src/prosemirror/clearRunColor.ts
6
+ /** Clearing direct color reveals the run's character/paragraph style color. */
7
+ const clearRunColor = () => (state, dispatch) => {
8
+ if (!dispatch) return true;
9
+ const styleResolver = getDocumentStyleResolver(state);
10
+ const tr = state.tr;
11
+ const { from, to, empty } = state.selection;
12
+ const clearedMarks = (node, position) => {
13
+ const context = paragraphRunStyleContextAt({
14
+ doc: state.doc,
15
+ pos: position,
16
+ styleResolver
17
+ });
18
+ const { color: _color, ...authoredFormatting } = readAuthoredRunFormatting({
19
+ context,
20
+ marks: node.marks,
21
+ styleResolver
22
+ });
23
+ return reconcileRunFormattingMarks({
24
+ authoredFormatting,
25
+ context,
26
+ node,
27
+ styleResolver
28
+ });
29
+ };
30
+ if (empty) {
31
+ const node = state.schema.text(" ", state.storedMarks ?? state.selection.$from.marks());
32
+ tr.setStoredMarks(clearedMarks(node, from));
33
+ } else for (const representation of selectRunFormattingCarrierRepresentations({
34
+ doc: state.doc,
35
+ from,
36
+ to
37
+ })) applyMarksToRunFormattingRepresentation({
38
+ tr,
39
+ representation,
40
+ marks: clearedMarks(representation.node, representation.position)
41
+ });
42
+ dispatch(tr.scrollIntoView());
43
+ return true;
44
+ };
45
+ //#endregion
46
+ export { clearRunColor };
@@ -7,21 +7,23 @@ import { expectFieldAttrs, expectParagraphAttrs, expectRunPropertyChangeMarkAttr
7
7
  import { addedBreakCarrierBefore, finalParagraphsOf, paragraphEndsItsContainer } from "../containerFinalParagraph.js";
8
8
  import { enclosingRevisionIds, resolutionRemovesControl, withoutResolvedEnclosures } from "../contentControlRevisions.js";
9
9
  import { resolveEmptyFieldResultRuns } from "../emptyFieldResultRuns.js";
10
+ import { JOINED_RUNS_RESTYLED_META } from "../extensions/features/JoinedRunStyleExtension.js";
10
11
  import { markChangedParagraphRanges, markStructuralChange, markTrackedSectionEndpointRemoval } from "../extensions/features/ParagraphChangeTrackerExtension.js";
11
12
  import "../extensions/nodes/SdtExtension.js";
12
13
  import { resolveStateStory } from "../markupViewProjection.js";
13
14
  import { joinAtParagraphMark } from "../paragraphMarkJoin.js";
14
15
  import { getDocumentNumbering } from "../plugins/documentNumbering.js";
15
- import { getDocumentStyleResolver } from "../plugins/documentStyles.js";
16
- import { setParagraphAttrsWithRebasedRunFormatting } from "../rebaseParagraphRunFormatting.js";
16
+ import { getDocumentStyleResolver } from "../plugins/documentStyleState.js";
17
+ import { rebaseParagraphRuns, setParagraphAttrsWithRebasedRunFormatting } from "../rebaseParagraphRunFormatting.js";
17
18
  import { rejoinRunsAt } from "../rejoinRunCarriers.js";
18
19
  import { getFolioNodeRevisionCarriers, nodePropertyRevisionSites } from "../revisionCarriers.js";
19
20
  import { RUN_FORMATTING_MARK_NAMES } from "../runFormattingMarkNames.js";
20
21
  import { reconstructRejectedRunFormattingMarks } from "../runPropertyChangeResolution.js";
21
- import { paragraphRunStyleContextAt } from "../runStyleFormatting.js";
22
+ import { paragraphRunStyleContext, paragraphRunStyleContextAt } from "../runStyleFormatting.js";
22
23
  import { getTableCellMergeChange } from "../tableCellMergeRevision.js";
23
24
  import { isTableCellRetainedInReviewView } from "../tableCellRevisionVisibility.js";
24
- import { reconcileTableGridAfterColumnRemoval, removeRowsWithoutCells, removeTableRow } from "../tableGridMutation.js";
25
+ import { markRowEmptiedInBatch, reconcileTableGridAfterColumnRemoval, removeRowsWithoutCellsAfterBatch, removeTableRow } from "../tableGridMutation.js";
26
+ import { runInCellPending, runParagraphIntoTable } from "../tableRunIn.js";
25
27
  import { holdsNoContent } from "../zeroWidthAnchors.js";
26
28
  import { inlineBookmarksForParagraphJoin } from "./paragraphBookmarkJoin.js";
27
29
  import { hasSerializableParagraphPropertyChange, paragraphPropertiesSnapshot } from "./propertyChangeScope.js";
@@ -106,6 +108,7 @@ function resolveChange(from, to, mode, revisionIds) {
106
108
  const matchesRevision = (mark) => revisionSet === null || typeof mark.attrs["revisionId"] === "number" && revisionSet.has(mark.attrs["revisionId"]);
107
109
  if (dispatch) {
108
110
  const tr = state.tr;
111
+ tr.setMeta(JOINED_RUNS_RESTYLED_META, true);
109
112
  const deleteRanges = [];
110
113
  /** Where resolved inline content began and ended, in `state.doc`. */
111
114
  const resolvedBoundaries = [];
@@ -278,7 +281,7 @@ function resolveChange(from, to, mode, revisionIds) {
278
281
  tableCellStructuralOps.sort((left, right) => right.cellPos - left.cellPos);
279
282
  let resolvedTableCellStructure = false;
280
283
  let failedTableCellMergeResolution = false;
281
- const emptiedTables = [];
284
+ const emptiedTables = { pending: false };
282
285
  for (const op of tableCellStructuralOps) {
283
286
  const mappedPos = tr.mapping.map(op.cellPos);
284
287
  const cell = tr.doc.nodeAt(mappedPos);
@@ -301,9 +304,15 @@ function resolveChange(from, to, mode, revisionIds) {
301
304
  resolvedTableCellStructure = true;
302
305
  }
303
306
  if (failedTableCellMergeResolution) return false;
304
- for (const { position, mapFrom } of emptiedTables) removeRowsWithoutCells(tr, tr.mapping.slice(mapFrom).map(position));
307
+ removeRowsWithoutCellsAfterBatch(tr, emptiedTables);
305
308
  if (resolvedTableCellStructure) markStructuralChange(tr);
306
309
  pPrMarkOps.sort((a, b) => b.paragraphPos - a.paragraphPos);
310
+ const pendingTables = [];
311
+ state.doc.descendants((node, position) => {
312
+ if (node.type.spec["tableRole"] === "table" && runInCellPending(node)) pendingTables.push(position);
313
+ return !node.isTextblock;
314
+ });
315
+ const joinSeams = [];
307
316
  for (const op of pPrMarkOps) {
308
317
  const mappedPos = tr.mapping.map(op.paragraphPos);
309
318
  const paragraph = tr.doc.nodeAt(mappedPos);
@@ -323,7 +332,18 @@ function resolveChange(from, to, mode, revisionIds) {
323
332
  nextPos += boundary.nodeSize;
324
333
  }
325
334
  const nextNode = nextPos < tr.doc.content.size ? tr.doc.nodeAt(nextPos) : null;
326
- if (!(nextNode?.type.name === paragraph.type.name)) {
335
+ const joinable = nextNode?.type.name === paragraph.type.name;
336
+ const ranIn = nextNode?.type.spec["tableRole"] === "table" && boundaries.length === 0 && !pendingTables.some((position) => tr.mapping.map(position) === nextPos) ? runParagraphIntoTable({
337
+ tr,
338
+ paragraphPos: mappedPos,
339
+ styleResolver
340
+ }) : null;
341
+ if (ranIn) {
342
+ tr.setMeta(JOINED_RUNS_RESTYLED_META, true);
343
+ markParagraphPropertySourceTransfers(tr, [ranIn.transfer]);
344
+ continue;
345
+ }
346
+ if (!joinable) {
327
347
  const resolved = tr.doc.resolve(mappedPos);
328
348
  const endsItsContainer = paragraphEndsItsContainer(resolved, paragraph.type.name);
329
349
  const canGo = op.markWasAdded || !endsItsContainer;
@@ -340,12 +360,6 @@ function resolveChange(from, to, mode, revisionIds) {
340
360
  }
341
361
  try {
342
362
  if (boundaries.length > 0) {
343
- const emptyFirstParagraph = holdsNoContent(paragraph);
344
- const joinedAttrs = {
345
- ...(emptyFirstParagraph ? nextNode : paragraph).attrs,
346
- pPrMark: nextNode.attrs["pPrMark"],
347
- _sectionProperties: nextNode.attrs["_sectionProperties"]
348
- };
349
363
  const leftToken = getProseParagraphPropertySourceToken(paragraph);
350
364
  const rightToken = getProseParagraphPropertySourceToken(nextNode);
351
365
  const inlineBookmarks = inlineBookmarksForParagraphJoin({
@@ -355,16 +369,31 @@ function resolveChange(from, to, mode, revisionIds) {
355
369
  });
356
370
  if (!inlineBookmarks) continue;
357
371
  tr.replaceWith(joinPos - 1, nextPos + 1, inlineBookmarks);
358
- tr.setNodeMarkup(mappedPos, void 0, joinedAttrs);
359
- if (emptyFirstParagraph) markParagraphPropertySourceTransfers(tr, [{
372
+ tr.setNodeMarkup(mappedPos, void 0, nextNode.attrs);
373
+ markParagraphPropertySourceTransfers(tr, [{
360
374
  displacedToken: typeof leftToken === "string" ? leftToken : null,
361
375
  selectedToken: typeof rightToken === "string" ? rightToken : null
362
376
  }]);
377
+ if (styleResolver && paragraph.content.size > 0) rebaseParagraphRuns({
378
+ previousContext: paragraphRunStyleContext(paragraph, styleResolver),
379
+ paragraphPosition: mappedPos,
380
+ range: {
381
+ from: 0,
382
+ to: paragraph.content.size
383
+ },
384
+ styleResolver,
385
+ tr
386
+ });
363
387
  } else joinAtParagraphMark({
364
388
  tr,
365
389
  paragraphPos: mappedPos,
366
390
  paragraph,
367
- next: nextNode
391
+ next: nextNode,
392
+ styleResolver
393
+ });
394
+ joinSeams.push({
395
+ position: mappedPos + 1 + paragraph.content.size,
396
+ step: tr.steps.length
368
397
  });
369
398
  if (ownsSectionEndpoint(paragraph)) {
370
399
  removedSectionEndpointCount++;
@@ -378,9 +407,10 @@ function resolveChange(from, to, mode, revisionIds) {
378
407
  removedReferences: removedSectionReferences
379
408
  });
380
409
  if (!terminalTableDeletionIsPending(tr)) resolveTerminalTableReviewCarrier(tr, mode);
410
+ const seams = new Set(joinSeams.map(({ position, step }) => tr.mapping.slice(step).map(position)));
381
411
  rejoinRunsAt({
382
412
  tr,
383
- boundaries: resolvedBoundaries.map((position) => tr.mapping.map(position)),
413
+ boundaries: resolvedBoundaries.map((position) => tr.mapping.map(position)).filter((position) => !seams.has(position)),
384
414
  styleResolver
385
415
  });
386
416
  if (tr.steps.length > 0) dispatch(tr);
@@ -559,6 +589,7 @@ function isTableCellRevisionAttr(value) {
559
589
  const info = value.info;
560
590
  return typeof info === "object" && info !== null && "revisionId" in info && typeof info.revisionId === "number";
561
591
  }
592
+ /** Record rows for a final sweep after every cell revision has resolved. */
562
593
  function deleteTableCellAt(tr, cellPos, emptied) {
563
594
  const cell = tr.doc.nodeAt(cellPos);
564
595
  if (!cell || cell.type.name !== "tableCell" && cell.type.name !== "tableHeader") return;
@@ -573,9 +604,10 @@ function deleteTableCellAt(tr, cellPos, emptied) {
573
604
  const removedColumn = TableMap.get(table).findCell(cellOffset).left;
574
605
  const spansDown = Number(cell.attrs["rowspan"]) > 1;
575
606
  if (row.childCount > 1 || spansDown) {
576
- if (row.childCount === 1) emptied.push({
577
- position: tablePosition,
578
- mapFrom: tr.mapping.maps.length
607
+ if (row.childCount === 1) markRowEmptiedInBatch({
608
+ tr,
609
+ rowPosition: resolved.start() - 1,
610
+ emptied
579
611
  });
580
612
  tr.delete(cellPos, cellPos + cell.nodeSize);
581
613
  reconcileTableGridAfterColumnRemoval({
@@ -1336,7 +1368,10 @@ const shiftAddedParagraphBreakBefore = ({ tr, paragraphPosition, mark, fallbackA
1336
1368
  const paragraph = tr.doc.nodeAt(paragraphPosition);
1337
1369
  if (!paragraph || paragraph.type.name !== "paragraph") return false;
1338
1370
  const resolved = tr.doc.resolve(paragraphPosition);
1339
- const carrier = addedBreakCarrierBefore(resolved, paragraph.type.name);
1371
+ const carrier = addedBreakCarrierBefore({
1372
+ at: resolved,
1373
+ paragraphTypeName: paragraph.type.name
1374
+ });
1340
1375
  if (!carrier) return false;
1341
1376
  const path = [{
1342
1377
  node: paragraph,
@@ -1,6 +1,6 @@
1
1
  import { mergeTextFormatting } from "../../utils/textFormattingMerge.js";
2
2
  import { expectCharacterStyleMarkAttrs } from "../attrs/index.js";
3
- import { getDocumentStyleResolver } from "../plugins/documentStyles.js";
3
+ import { getDocumentStyleResolver } from "../plugins/documentStyleState.js";
4
4
  import { readAuthoredRunFormatting, reconcileRunFormattingMarks } from "../runFormattingReconciliation.js";
5
5
  import { paragraphFormattingForRun, paragraphRunStyleContext, paragraphRunStyleContextAt, resolveEffectiveRunStyleFormatting } from "../runStyleFormatting.js";
6
6
  //#region src/prosemirror/commands/formatPainter.ts
@@ -1,5 +1,6 @@
1
1
  import { normalizeUserUrl } from "../../utils/urlSecurity.js";
2
2
  import { expectHyperlinkMarkAttrs } from "../attrs/index.js";
3
+ import { removeHyperlinkInRange } from "../hyperlinkRemoval.js";
3
4
  //#region src/prosemirror/commands/hyperlink.ts
4
5
  const hyperlinkHref = (mark) => expectHyperlinkMarkAttrs(mark).href;
5
6
  /**
@@ -87,7 +88,7 @@ const removeHyperlinkAtCursor = (view, { popupHref }) => {
87
88
  const ranges = collectHyperlinkRanges($from.parent, $from.start(), hlType, hyperlinkHref(linkMark));
88
89
  const targetRange = rangeAtCursor(ranges, $from.pos);
89
90
  if (!targetRange) return false;
90
- const tr = view.state.tr.removeMark(targetRange.start, targetRange.end, hlType);
91
+ const tr = removeHyperlinkInRange(view.state, view.state.tr, targetRange.start, targetRange.end);
91
92
  view.dispatch(tr.scrollIntoView());
92
93
  return true;
93
94
  };
@@ -48,8 +48,9 @@ declare const PPR_CHANGE_SCOPED_ATTR_KEYS: readonly ["styleId", "numPr", "alignm
48
48
  declare const paragraphPropertiesSnapshot: (node: Node) => ParagraphPropertySnapshot;
49
49
  /**
50
50
  * Build the attr patch that rejecting one pPrChange applies to a paragraph:
51
- * every in-scope key set to the stored previous value, or reset to `null`
52
- * when the stored old pPr does not carry it. Keys the record captured beyond
51
+ * every in-scope key set to the stored previous value, or to what the style
52
+ * (`inheritedFormatting`) supplies when the stored old pPr does not carry it,
53
+ * `null` when neither does. Keys the record captured beyond
53
54
  * the scoped set (editor-created list suggestions snapshot list-rendering
54
55
  * bookkeeping attrs) merge through 1:1 so their pre-change values restore too.
55
56
  */
@@ -2,7 +2,9 @@ import { expectParagraphAttrs } from "../attrs/index.js";
2
2
  import { readParagraphNumberingAttr } from "../numberingAttr.js";
3
3
  import { directParagraphAlignment } from "../paragraphAlignment.js";
4
4
  import { directionFromBidi } from "../paragraphDirection.js";
5
+ import { PARAGRAPH_FORMATTING_WRITE_BACK, STYLE_RESOLVED_PARAGRAPH_FIELDS } from "../paragraphFormattingProvenance.js";
5
6
  import { directParagraphSpacing, paragraphSpacingAttrPatch, paragraphSpacingFromFormatting } from "../paragraphSpacing.js";
7
+ import { sameFormattingValue } from "../runFormattingFromMarks.js";
6
8
  //#region src/prosemirror/commands/propertyChangeScope.ts
7
9
  /** Editor-only suggestions are rebased away before save; every other entry emits `w:pPrChange`. */
8
10
  const hasSerializableParagraphPropertyChange = (changes) => changes?.some(({ info }) => info.provenance !== "suggested") === true;
@@ -106,12 +108,27 @@ const PPR_SPACING_ATTR_KEYS = /* @__PURE__ */ new Set([
106
108
  "spacingExplicit",
107
109
  "_autospacingBase"
108
110
  ]);
111
+ /**
112
+ * Whether the attr holds only what the paragraph's style resolves to: the
113
+ * paragraph does not state it (its source `w:pPr` has no such field) and the
114
+ * value is the style's. The same test a save applies before writing it.
115
+ */
116
+ const styleSuppliedParagraphValue = (attrs, key) => {
117
+ if (!STYLE_RESOLVED_ATTR_FIELDS.has(key)) return false;
118
+ const field = key;
119
+ const inherited = attrs._resolvedFormatting?.[field];
120
+ return attrs._originalFormatting?.[field] === void 0 && inherited !== void 0 && inherited !== null && sameFormattingValue(Reflect.get(attrs, key), inherited);
121
+ };
122
+ /** Fields whose attr carries the style-resolved value under the field's own name. */
123
+ const STYLE_RESOLVED_ATTR_FIELDS = new Set(STYLE_RESOLVED_PARAGRAPH_FIELDS.filter((field) => PARAGRAPH_FORMATTING_WRITE_BACK[field].attr === field));
109
124
  /** The in-scope paragraph properties as they stand, for a `w:pPrChange` record. */
110
125
  const paragraphPropertiesSnapshot = (node) => {
111
126
  const attrs = expectParagraphAttrs(node);
112
127
  const snapshot = {};
113
128
  for (const key of PPR_CHANGE_SCOPED_ATTR_KEYS) {
114
129
  if (key === "alignment" || PPR_SPACING_ATTR_KEYS.has(key)) continue;
130
+ if (styleSuppliedParagraphValue(attrs, key)) continue;
131
+ if (key === "hangingIndent" && styleSuppliedParagraphValue(attrs, "indentFirstLine")) continue;
115
132
  const value = attrs[key];
116
133
  if (key === "hangingIndent" && value === false && attrs._originalFormatting?.hangingIndent === void 0) continue;
117
134
  if (value !== null && value !== void 0) snapshot[key] = value;
@@ -177,15 +194,19 @@ const PPR_CHANGE_SCOPED_FORMATTING_KEYS = [
177
194
  ];
178
195
  /**
179
196
  * Build the attr patch that rejecting one pPrChange applies to a paragraph:
180
- * every in-scope key set to the stored previous value, or reset to `null`
181
- * when the stored old pPr does not carry it. Keys the record captured beyond
197
+ * every in-scope key set to the stored previous value, or to what the style
198
+ * (`inheritedFormatting`) supplies when the stored old pPr does not carry it,
199
+ * `null` when neither does. Keys the record captured beyond
182
200
  * the scoped set (editor-created list suggestions snapshot list-rendering
183
201
  * bookkeeping attrs) merge through 1:1 so their pre-change values restore too.
184
202
  */
185
203
  function paragraphRejectAttrPatch(previousFormatting, inheritedFormatting) {
186
204
  const prev = previousFormatting ?? {};
187
205
  const patch = {};
188
- for (const key of PPR_CHANGE_SCOPED_ATTR_KEYS) patch[key] = Object.hasOwn(prev, key) ? prev[key] ?? null : null;
206
+ for (const key of PPR_CHANGE_SCOPED_ATTR_KEYS) if (Object.hasOwn(prev, key)) patch[key] = prev[key] ?? null;
207
+ else if (STYLE_RESOLVED_ATTR_FIELDS.has(key)) patch[key] = Reflect.get(inheritedFormatting ?? {}, key) ?? null;
208
+ else patch[key] = null;
209
+ if (!Object.hasOwn(prev, "indentFirstLine") && !Object.hasOwn(prev, "hangingIndent")) patch["hangingIndent"] = inheritedFormatting?.hangingIndent ?? null;
189
210
  if (!Object.hasOwn(prev, "alignment")) patch["alignment"] = inheritedFormatting?.alignment ?? null;
190
211
  patch["alignmentFromStyle"] = inheritedFormatting?.alignment;
191
212
  const directSpacing = paragraphSpacingFromFormatting(prev);
@@ -5,7 +5,7 @@ import { nodePropertyRevisionSites, propertyRevisionRecords } from "../revisionC
5
5
  import { getTableCellMergeChange } from "../tableCellMergeRevision.js";
6
6
  import { isTableCellRetainedInReviewView } from "../tableCellRevisionVisibility.js";
7
7
  import { resolveAllNodePropertyChangeAttrs } from "./resolveNodePropertyChangeAttrs.js";
8
- import { createRestoredTableCell, hasMatchingCollapsedTableCellMerge, tableCellContinuationCells, tableCellContinuationFromNode, tableCellContinuationPayload } from "./tableCellMergeResolution.js";
8
+ import { acceptedMergeFoldsIntoCellAbove, createRestoredTableCell, hasMatchingCollapsedTableCellMerge, tableCellContinuationCells, tableCellContinuationFromNode, tableCellContinuationPayload } from "./tableCellMergeResolution.js";
9
9
  import { panic } from "better-result";
10
10
  import { TableMap } from "prosemirror-tables";
11
11
  import { StepMap } from "prosemirror-transform";
@@ -131,10 +131,12 @@ const cellRevisionMarker = (cell) => {
131
131
  const marker = cell.attrs["cellMarker"];
132
132
  if (typeof marker !== "object" || marker === null || !("kind" in marker) || marker.kind !== "ins" && marker.kind !== "del" && marker.kind !== "merge" || !("info" in marker) || typeof marker.info !== "object" || marker.info === null || !("revisionId" in marker.info) || typeof marker.info.revisionId !== "number") return null;
133
133
  const verticalMergeOriginal = "verticalMergeOriginal" in marker && isTableCellMergeRevisionValue(marker.verticalMergeOriginal) ? marker.verticalMergeOriginal : void 0;
134
+ const verticalMerge = "verticalMerge" in marker && isTableCellMergeRevisionValue(marker.verticalMerge) ? marker.verticalMerge : void 0;
134
135
  return {
135
136
  kind: marker.kind,
136
137
  info: { revisionId: marker.info.revisionId },
137
- ...verticalMergeOriginal ? { verticalMergeOriginal } : {}
138
+ ...verticalMergeOriginal ? { verticalMergeOriginal } : {},
139
+ ...verticalMerge ? { verticalMerge } : {}
138
140
  };
139
141
  };
140
142
  /**
@@ -435,46 +437,49 @@ const resolvePureTableMerges = ({ table, mode, rowMetadata, tablePropertyTouched
435
437
  count: previousWidth - currentWidth
436
438
  });
437
439
  }
438
- } else if (marker?.kind === "merge") if (mode === "accept") {
439
- entry.touched = true;
440
- entry.node = entry.node.type.create({
441
- ...entry.node.attrs,
442
- cellMarker: null
443
- }, entry.node.content, entry.node.marks);
444
- } else if (!isTableCellMergeRevisionContinuation(marker.verticalMergeOriginal)) {
445
- entry.touched = true;
446
- const original = entry.node.attrs["_originalFormatting"];
447
- let formatting = original;
448
- if (typeof original === "object" && original !== null) {
449
- const copy = { ...original };
450
- delete copy["vMerge"];
451
- formatting = copy;
440
+ } else if (marker?.kind === "merge") {
441
+ const joinsAbove = mode === "accept" ? isTableCellMergeRevisionContinuation(marker.verticalMerge) && acceptedMergeFoldsIntoCellAbove(entry.node) : isTableCellMergeRevisionContinuation(marker.verticalMergeOriginal);
442
+ if (mode === "accept" && !joinsAbove) {
443
+ entry.touched = true;
444
+ entry.node = entry.node.type.create({
445
+ ...entry.node.attrs,
446
+ cellMarker: null
447
+ }, entry.node.content, entry.node.marks);
448
+ } else if (!joinsAbove) {
449
+ entry.touched = true;
450
+ const original = entry.node.attrs["_originalFormatting"];
451
+ let formatting = original;
452
+ if (typeof original === "object" && original !== null) {
453
+ const copy = { ...original };
454
+ delete copy["vMerge"];
455
+ formatting = copy;
456
+ }
457
+ entry.node = entry.node.type.create({
458
+ ...entry.node.attrs,
459
+ cellMarker: null,
460
+ _originalFormatting: formatting
461
+ }, entry.node.content, entry.node.marks);
462
+ } else {
463
+ const rectangle = cellRectangle(entry.position);
464
+ if (rectangle.top === 0) return failedTableResolution(table);
465
+ const abovePosition = map.map[(rectangle.top - 1) * map.width + rectangle.left];
466
+ if (abovePosition === void 0) return failedTableResolution(table);
467
+ const aboveRectangle = cellRectangle(abovePosition);
468
+ const above = byPosition.get(abovePosition);
469
+ if (!above || !elementAt(rowCells, above.row).has(above.left) || aboveRectangle.left !== rectangle.left || aboveRectangle.right !== rectangle.right || aboveRectangle.bottom !== rectangle.top) return failedTableResolution(table);
470
+ const aboveRowspan = above.node.attrs["rowspan"];
471
+ const cellRowspan = entry.node.attrs["rowspan"];
472
+ if (typeof aboveRowspan !== "number" || typeof cellRowspan !== "number" || aboveRowspan < 1 || cellRowspan < 1) return failedTableResolution(table);
473
+ above.continuation ??= continuationSequence(tableCellContinuationCells(above.node, aboveRowspan));
474
+ appendContinuation(above.continuation, tableCellContinuationFromNode(entry.node));
475
+ const nested = entry.continuation ?? continuationSequence(tableCellContinuationPayload(entry.node)?.cells ?? []);
476
+ appendContinuationSequence(above.continuation, nested);
477
+ above.node = above.node.type.create({
478
+ ...above.node.attrs,
479
+ rowspan: aboveRowspan + cellRowspan
480
+ }, above.node.content, above.node.marks);
481
+ elementAt(rowCells, entry.row).delete(entry.left);
452
482
  }
453
- entry.node = entry.node.type.create({
454
- ...entry.node.attrs,
455
- cellMarker: null,
456
- _originalFormatting: formatting
457
- }, entry.node.content, entry.node.marks);
458
- } else {
459
- const rectangle = cellRectangle(entry.position);
460
- if (rectangle.top === 0) return failedTableResolution(table);
461
- const abovePosition = map.map[(rectangle.top - 1) * map.width + rectangle.left];
462
- if (abovePosition === void 0) return failedTableResolution(table);
463
- const aboveRectangle = cellRectangle(abovePosition);
464
- const above = byPosition.get(abovePosition);
465
- if (!above || !elementAt(rowCells, above.row).has(above.left) || aboveRectangle.left !== rectangle.left || aboveRectangle.right !== rectangle.right || aboveRectangle.bottom !== rectangle.top) return failedTableResolution(table);
466
- const aboveRowspan = above.node.attrs["rowspan"];
467
- const cellRowspan = entry.node.attrs["rowspan"];
468
- if (typeof aboveRowspan !== "number" || typeof cellRowspan !== "number" || aboveRowspan < 1 || cellRowspan < 1) return failedTableResolution(table);
469
- above.continuation ??= continuationSequence(tableCellContinuationCells(above.node, aboveRowspan));
470
- appendContinuation(above.continuation, tableCellContinuationFromNode(entry.node));
471
- const nested = entry.continuation ?? continuationSequence(tableCellContinuationPayload(entry.node)?.cells ?? []);
472
- appendContinuationSequence(above.continuation, nested);
473
- above.node = above.node.type.create({
474
- ...above.node.attrs,
475
- rowspan: aboveRowspan + cellRowspan
476
- }, above.node.content, above.node.marks);
477
- elementAt(rowCells, entry.row).delete(entry.left);
478
483
  }
479
484
  if (!elementAt(rowCells, entry.row).has(entry.left)) continue;
480
485
  if (!tableCellContinuationPayload(entry.node)?.cells.some((cell) => getTableCellMergeChange(cell) !== null)) continue;
@@ -1,6 +1,7 @@
1
1
  import { expectParagraphAttrs } from "../attrs/index.js";
2
- import { resolveParagraphDefaultTextFormatting } from "../conversion/toProseDoc.js";
3
- import { rejectedListRenderingPatch } from "../listNumbering.js";
2
+ import { rejectedListRenderingPatch } from "../listRendering.js";
3
+ import { styleResolvedParagraphFormatting } from "../paragraphFormattingProvenance.js";
4
+ import { resolveParagraphDefaultTextFormatting } from "../styles/paragraphStyleCascade.js";
4
5
  import { paragraphRejectAttrPatch, paragraphRejectOriginalFormatting, removeParagraphPropertyChanges, sectionRejectProperties } from "./propertyChangeScope.js";
5
6
  //#region src/prosemirror/commands/resolveParagraphProperties.ts
6
7
  /** Resolve paragraph and section property records before resolving their inline content. */
@@ -20,11 +21,24 @@ const resolveParagraphChangeAttrs = ({ node, boundaryCovered, mode, revisionSet,
20
21
  _propertyChanges: remaining.length > 0 ? remaining : null
21
22
  };
22
23
  if (rejection?.type === "restore-previous") {
23
- const inheritedAlignment = expectParagraphAttrs(node).alignmentFromStyle;
24
+ const currentAttrs = expectParagraphAttrs(node);
25
+ const inheritedAlignment = currentAttrs.alignmentFromStyle;
26
+ const restoredStyleId = rejection.previousFormatting?.styleId ?? void 0;
27
+ const sameStyle = restoredStyleId === (currentAttrs.styleId ?? void 0);
24
28
  let previousFormattingFromStyle;
25
- if (styleResolver) previousFormattingFromStyle = styleResolver.resolveParagraphStyle(rejection.previousFormatting?.styleId).paragraphFormatting;
26
- else if (inheritedAlignment !== void 0) previousFormattingFromStyle = { alignment: inheritedAlignment };
27
- Object.assign(nextAttrs, paragraphRejectAttrPatch(rejection.previousFormatting, previousFormattingFromStyle), rejectedListRenderingPatch({
29
+ let resolvedFromStyle = sameStyle ? currentAttrs._resolvedFormatting : void 0;
30
+ if (styleResolver) {
31
+ previousFormattingFromStyle = styleResolver.resolveParagraphStyle(restoredStyleId).paragraphFormatting;
32
+ if (!sameStyle) {
33
+ resolvedFromStyle = styleResolvedParagraphFormatting(previousFormattingFromStyle);
34
+ nextAttrs["_resolvedFormatting"] = resolvedFromStyle;
35
+ }
36
+ } else if (inheritedAlignment !== void 0) previousFormattingFromStyle = { alignment: inheritedAlignment };
37
+ const inheritedFormatting = previousFormattingFromStyle === void 0 && resolvedFromStyle === void 0 ? void 0 : {
38
+ ...previousFormattingFromStyle,
39
+ ...resolvedFromStyle
40
+ };
41
+ Object.assign(nextAttrs, paragraphRejectAttrPatch(rejection.previousFormatting, inheritedFormatting), rejectedListRenderingPatch({
28
42
  current: expectParagraphAttrs(node),
29
43
  previousFormatting: rejection.previousFormatting,
30
44
  numbering
@@ -5,10 +5,17 @@ import { Transaction } from "prosemirror-state";
5
5
  //#region src/prosemirror/commands/tableCellMergeResolution.d.ts
6
6
  declare const tableCellContinuationPayload: (node: Node) => DecodedTableCellParagraphSourcePayload | null;
7
7
  declare const hasMatchingCollapsedTableCellMerge: (node: Node, revisionSet: Set<number> | null) => boolean;
8
+ /**
9
+ * Whether accepting a pending vertical merge folds the cell into the one above.
10
+ * The saved `w:vMerge` continuation is read back as its own cell when it carries
11
+ * content, so accepting such a merge keeps the cell standing; folding it would
12
+ * hide text that reappears when the document is reopened.
13
+ */
14
+ declare const acceptedMergeFoldsIntoCellAbove: (cell: Node) => boolean;
8
15
  declare const resolveVisibleTableCellMerge: (tr: Transaction, cellPos: number, mode: "accept" | "reject") => boolean;
9
16
  declare const tableCellContinuationCells: (cell: Node, rowspan: number) => document_d_exports.TableCell[];
10
17
  declare const tableCellContinuationFromNode: (cell: Node) => document_d_exports.TableCell;
11
18
  declare const resolveCollapsedTableCellMerge: (tr: Transaction, cellPos: number, mode: "accept" | "reject", revisionSet: Set<number> | null) => boolean;
12
19
  declare const createRestoredTableCell: (origin: Node, source: document_d_exports.TableCell) => Node | null;
13
20
  //#endregion
14
- export { createRestoredTableCell, hasMatchingCollapsedTableCellMerge, resolveCollapsedTableCellMerge, resolveVisibleTableCellMerge, tableCellContinuationCells, tableCellContinuationFromNode, tableCellContinuationPayload };
21
+ export { acceptedMergeFoldsIntoCellAbove, createRestoredTableCell, hasMatchingCollapsedTableCellMerge, resolveCollapsedTableCellMerge, resolveVisibleTableCellMerge, tableCellContinuationCells, tableCellContinuationFromNode, tableCellContinuationPayload };
@@ -1,8 +1,10 @@
1
1
  import { decodeTableCellParagraphSourcePayload, restoreTableCellsWithParagraphPropertySources, transportTableCellsWithParagraphPropertySources } from "../../docx/paragraphPropertySource.js";
2
+ import { isTableCellMergeRevisionContinuation } from "../../docx/tableParser.js";
2
3
  import { standaloneTableCellFromProseMirror } from "../conversion/fromProseDoc.js";
3
- import { standaloneTableCellToProseMirror } from "../conversion/toProseDoc.js";
4
+ import { standaloneTableCellToProseMirror, tableCellHasMeaningfulContent } from "../conversion/toProseDoc.js";
4
5
  import { getTableCellMergeChange } from "../tableCellMergeRevision.js";
5
- import { Result } from "better-result";
6
+ import { removeRowsWithoutCellsInRange } from "../tableGridMutation.js";
7
+ import { Result, panic } from "better-result";
6
8
  import { TableMap } from "prosemirror-tables";
7
9
  //#region src/prosemirror/commands/tableCellMergeResolution.ts
8
10
  const tableCellContinuationPayload = (node) => {
@@ -35,15 +37,22 @@ const tableCellContext = (doc, cellPos) => {
35
37
  }
36
38
  return null;
37
39
  };
40
+ /**
41
+ * Whether accepting a pending vertical merge folds the cell into the one above.
42
+ * The saved `w:vMerge` continuation is read back as its own cell when it carries
43
+ * content, so accepting such a merge keeps the cell standing; folding it would
44
+ * hide text that reappears when the document is reopened.
45
+ */
46
+ const acceptedMergeFoldsIntoCellAbove = (cell) => !tableCellHasMeaningfulContent(standaloneTableCellFromProseMirror(cell));
38
47
  const resolveVisibleTableCellMerge = (tr, cellPos, mode) => {
39
48
  const cell = tr.doc.nodeAt(cellPos);
40
49
  const marker = cell?.attrs["cellMarker"];
41
50
  if (!cell || !isTableCellMergeRevisionAttr(marker)) return false;
51
+ if (mode === "accept" ? isTableCellMergeRevisionContinuation(marker.verticalMerge) && acceptedMergeFoldsIntoCellAbove(cell) : isTableCellMergeRevisionContinuation(marker.verticalMergeOriginal)) return mergeTableCellWithCellAbove(tr, cellPos);
42
52
  if (mode === "accept") {
43
53
  tr.setNodeAttribute(cellPos, "cellMarker", null);
44
54
  return true;
45
55
  }
46
- if ((marker.verticalMergeOriginal ?? "rest") === "continue") return mergeTableCellWithCellAbove(tr, cellPos);
47
56
  const originalFormatting = cell.attrs["_originalFormatting"];
48
57
  let nextOriginalFormatting = originalFormatting;
49
58
  if (typeof originalFormatting === "object" && originalFormatting !== null) {
@@ -73,11 +82,18 @@ const mergeTableCellWithCellAbove = (tr, cellPos) => {
73
82
  const aboveRowspan = aboveCell?.attrs["rowspan"];
74
83
  const cellRowspan = cell.attrs["rowspan"];
75
84
  if (!aboveCell || typeof aboveRowspan !== "number" || typeof cellRowspan !== "number" || aboveRowspan < 1 || cellRowspan < 1) return false;
85
+ removeRowsWithoutCellsInRange({
86
+ tr,
87
+ from: cellPos + 1,
88
+ to: cellPos + cell.nodeSize - 1
89
+ });
90
+ const capturedCell = tr.doc.nodeAt(cellPos);
91
+ if (!capturedCell) panic("Nested table cleanup removed its owning cell");
76
92
  const continuationCells = tableCellContinuationCells(aboveCell, aboveRowspan);
77
- continuationCells.push(tableCellContinuationFromNode(cell));
78
- const nestedPayload = tableCellContinuationPayload(cell);
93
+ continuationCells.push(tableCellContinuationFromNode(capturedCell));
94
+ const nestedPayload = tableCellContinuationPayload(capturedCell);
79
95
  if (nestedPayload) continuationCells.push(...nestedPayload.cells);
80
- tr.delete(cellPos, cellPos + cell.nodeSize);
96
+ tr.delete(cellPos, cellPos + capturedCell.nodeSize);
81
97
  tr.setNodeMarkup(abovePos, void 0, {
82
98
  ...aboveCell.attrs,
83
99
  rowspan: aboveRowspan + cellRowspan,
@@ -185,4 +201,4 @@ const createRestoredTableCell = (origin, source) => {
185
201
  return Result.try(() => origin.type.schema.nodeFromJSON(restored.toJSON())).unwrapOr(null);
186
202
  };
187
203
  //#endregion
188
- export { createRestoredTableCell, hasMatchingCollapsedTableCellMerge, resolveCollapsedTableCellMerge, resolveVisibleTableCellMerge, tableCellContinuationCells, tableCellContinuationFromNode, tableCellContinuationPayload };
204
+ export { acceptedMergeFoldsIntoCellAbove, createRestoredTableCell, hasMatchingCollapsedTableCellMerge, resolveCollapsedTableCellMerge, resolveVisibleTableCellMerge, tableCellContinuationCells, tableCellContinuationFromNode, tableCellContinuationPayload };
@@ -28,18 +28,24 @@ declare const finalParagraphsOf: (doc: Node, paragraphTypeName: string) => {
28
28
  position: number;
29
29
  node: Node;
30
30
  }[];
31
+ type AddedBreakCarrierBeforeOptions = {
32
+ at: ResolvedPos;
33
+ paragraphTypeName: string;
34
+ canCrossTable?: (table: Node) => boolean;
35
+ };
31
36
  /**
32
37
  * The paragraph an added break can rotate BACK onto from the one at `at`: the
33
38
  * paragraph the run of inserted ones was appended after.
34
39
  *
35
40
  * The walk crosses the inserted paragraphs — their own marks stay where they
36
41
  * are, and only which paragraph is left markless changes — and stops at the
37
- * first one whose mark is free. `null` when there is none: a table in between,
38
- * which no mark joins across; a paragraph whose mark says something else,
39
- * which the rotation must not overwrite; or a container whose every paragraph
40
- * is new.
42
+ * first one whose mark is free. A table blocks the walk unless the caller
43
+ * authorizes a wholly inserted table: rejecting it removes that barrier too.
44
+ * `null` when there is no carrier: a table the caller cannot cross, a
45
+ * paragraph whose mark the rotation must not overwrite, or a container whose
46
+ * every paragraph is new.
41
47
  */
42
- declare const addedBreakCarrierBefore: (at: ResolvedPos, paragraphTypeName: string) => {
48
+ declare const addedBreakCarrierBefore: ({ at, paragraphTypeName, canCrossTable }: AddedBreakCarrierBeforeOptions) => {
43
49
  position: number;
44
50
  node: Node;
45
51
  } | null;
@@ -66,18 +66,19 @@ const marksAnAddedBreak = (node) => {
66
66
  *
67
67
  * The walk crosses the inserted paragraphs — their own marks stay where they
68
68
  * are, and only which paragraph is left markless changes — and stops at the
69
- * first one whose mark is free. `null` when there is none: a table in between,
70
- * which no mark joins across; a paragraph whose mark says something else,
71
- * which the rotation must not overwrite; or a container whose every paragraph
72
- * is new.
69
+ * first one whose mark is free. A table blocks the walk unless the caller
70
+ * authorizes a wholly inserted table: rejecting it removes that barrier too.
71
+ * `null` when there is no carrier: a table the caller cannot cross, a
72
+ * paragraph whose mark the rotation must not overwrite, or a container whose
73
+ * every paragraph is new.
73
74
  */
74
- const addedBreakCarrierBefore = (at, paragraphTypeName) => {
75
+ const addedBreakCarrierBefore = ({ at, paragraphTypeName, canCrossTable }) => {
75
76
  let position = at.pos;
76
77
  for (let index = at.index() - 1; index >= 0; index--) {
77
78
  const sibling = at.parent.child(index);
78
79
  position -= sibling.nodeSize;
79
80
  if (sibling.type.name !== paragraphTypeName) {
80
- if (isAContainerChild(sibling, paragraphTypeName)) return null;
81
+ if (isAContainerChild(sibling, paragraphTypeName) && !canCrossTable?.(sibling)) return null;
81
82
  continue;
82
83
  }
83
84
  if (sibling.attrs["pPrMark"] == null) return {