@stll/folio-core 0.53.0 → 0.54.1

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 (155) hide show
  1. package/dist/ai-edits/apply.js +415 -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 +4 -2
  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/docx/verticalMergeProjection.d.ts +17 -0
  41. package/dist/docx/verticalMergeProjection.js +120 -0
  42. package/dist/fonts/embeddedFonts.js +1 -1
  43. package/dist/i18n/messages/catalogs.gen.d.ts +34 -34
  44. package/dist/i18n/messages/catalogs.gen.js +34 -34
  45. package/dist/i18n/messages/messages.gen.d.ts +2 -2
  46. package/dist/internal/wholeStoryRevisionResolution.js +95 -25
  47. package/dist/layout-engine/measure/measureParagraph.js +2 -2
  48. package/dist/layout-engine/measure/paragraphMeasureShared.d.ts +12 -1
  49. package/dist/layout-engine/measure/paragraphMeasureShared.js +14 -1
  50. package/dist/markdown/escape.d.ts +2 -2
  51. package/dist/markdown/escape.js +4 -5
  52. package/dist/markdown/renderBlock.js +91 -25
  53. package/dist/markdown/renderRuns.d.ts +10 -1
  54. package/dist/markdown/renderRuns.js +320 -59
  55. package/dist/prosemirror/clearRunColor.d.ts +6 -0
  56. package/dist/prosemirror/clearRunColor.js +46 -0
  57. package/dist/prosemirror/commands/comments.js +62 -22
  58. package/dist/prosemirror/commands/formatPainter.js +1 -1
  59. package/dist/prosemirror/commands/hyperlink.js +2 -1
  60. package/dist/prosemirror/commands/propertyChangeScope.d.ts +3 -2
  61. package/dist/prosemirror/commands/propertyChangeScope.js +28 -4
  62. package/dist/prosemirror/commands/resolveAllTableChanges.js +40 -41
  63. package/dist/prosemirror/commands/resolveParagraphProperties.js +33 -8
  64. package/dist/prosemirror/commands/tableCellMergeResolution.d.ts +7 -1
  65. package/dist/prosemirror/commands/tableCellMergeResolution.js +39 -20
  66. package/dist/prosemirror/commands/tableMergeFoldDecisions.d.ts +61 -0
  67. package/dist/prosemirror/commands/tableMergeFoldDecisions.js +79 -0
  68. package/dist/prosemirror/containerFinalParagraph.d.ts +11 -5
  69. package/dist/prosemirror/containerFinalParagraph.js +7 -6
  70. package/dist/prosemirror/conversion/fromProseDoc.d.ts +2 -13
  71. package/dist/prosemirror/conversion/fromProseDoc.js +12 -590
  72. package/dist/prosemirror/conversion/toProseDoc.d.ts +1 -13
  73. package/dist/prosemirror/conversion/toProseDoc.js +28 -262
  74. package/dist/prosemirror/documentSchema.d.ts +8 -0
  75. package/dist/prosemirror/documentSchema.js +18 -0
  76. package/dist/prosemirror/extensions/StarterKit.js +2 -0
  77. package/dist/prosemirror/extensions/core/ParagraphExtension.js +104 -63
  78. package/dist/prosemirror/extensions/features/BaseKeymapExtension.js +1 -1
  79. package/dist/prosemirror/extensions/features/EmptyParagraphFormatExtension.js +24 -3
  80. package/dist/prosemirror/extensions/features/JoinedRunStyleExtension.d.ts +20 -0
  81. package/dist/prosemirror/extensions/features/JoinedRunStyleExtension.js +43 -0
  82. package/dist/prosemirror/extensions/features/ListExtension.js +10 -9
  83. package/dist/prosemirror/extensions/features/pastedHeadingStyles.js +1 -1
  84. package/dist/prosemirror/extensions/features/pastedHtmlLists.js +2 -4
  85. package/dist/prosemirror/extensions/marks/FootnoteRefExtension.js +14 -8
  86. package/dist/prosemirror/extensions/marks/HyperlinkExtension.js +8 -4
  87. package/dist/prosemirror/extensions/marks/StrikeExtension.js +2 -2
  88. package/dist/prosemirror/extensions/marks/SubscriptExtension.js +2 -2
  89. package/dist/prosemirror/extensions/marks/SuperscriptExtension.js +2 -2
  90. package/dist/prosemirror/extensions/marks/TextColorExtension.js +4 -3
  91. package/dist/prosemirror/extensions/marks/markUtils.d.ts +8 -6
  92. package/dist/prosemirror/extensions/marks/markUtils.js +17 -8
  93. package/dist/prosemirror/extensions/marks/noteReferenceDeletion.d.ts +3 -1
  94. package/dist/prosemirror/extensions/marks/noteReferenceDeletion.js +12 -1
  95. package/dist/prosemirror/extensions/nodes/CommentReferenceExtension.js +2 -2
  96. package/dist/prosemirror/extensions/nodes/HardBreakExtension.js +5 -3
  97. package/dist/prosemirror/extensions/nodes/TableExtension.js +104 -210
  98. package/dist/prosemirror/extensions/types.d.ts +7 -0
  99. package/dist/prosemirror/hyperlinkRemoval.d.ts +9 -0
  100. package/dist/prosemirror/hyperlinkRemoval.js +129 -0
  101. package/dist/prosemirror/index.d.ts +2 -1
  102. package/dist/prosemirror/index.js +2 -1
  103. package/dist/prosemirror/listNumbering.d.ts +3 -21
  104. package/dist/prosemirror/listNumbering.js +24 -39
  105. package/dist/prosemirror/listRendering.d.ts +29 -0
  106. package/dist/prosemirror/listRendering.js +26 -0
  107. package/dist/prosemirror/markupViewNotes.d.ts +8 -0
  108. package/dist/prosemirror/markupViewNotes.js +49 -0
  109. package/dist/prosemirror/markupViewProjection.d.ts +3 -1
  110. package/dist/prosemirror/markupViewProjection.js +7 -2
  111. package/dist/prosemirror/noteReferenceReview.d.ts +77 -0
  112. package/dist/prosemirror/noteReferenceReview.js +332 -0
  113. package/dist/prosemirror/paragraphIndentation.js +5 -2
  114. package/dist/prosemirror/paragraphMarkJoin.d.ts +6 -4
  115. package/dist/prosemirror/paragraphMarkJoin.js +21 -19
  116. package/dist/prosemirror/paragraphPropertyCarry.d.ts +64 -0
  117. package/dist/prosemirror/paragraphPropertyCarry.js +155 -0
  118. package/dist/prosemirror/plugins/documentStyleState.d.ts +26 -0
  119. package/dist/prosemirror/plugins/documentStyleState.js +32 -0
  120. package/dist/prosemirror/plugins/documentStyles.d.ts +2 -21
  121. package/dist/prosemirror/plugins/documentStyles.js +66 -29
  122. package/dist/prosemirror/plugins/index.d.ts +2 -1
  123. package/dist/prosemirror/plugins/index.js +2 -1
  124. package/dist/prosemirror/plugins/paragraphStyleResolution.d.ts +15 -0
  125. package/dist/prosemirror/plugins/paragraphStyleResolution.js +230 -0
  126. package/dist/prosemirror/plugins/suggestionMode.d.ts +12 -2
  127. package/dist/prosemirror/plugins/suggestionMode.js +387 -28
  128. package/dist/prosemirror/plugins/templateDirectives.d.ts +6 -0
  129. package/dist/prosemirror/plugins/templateDirectives.js +21 -7
  130. package/dist/prosemirror/plugins/templatePreviewValues.js +14 -21
  131. package/dist/prosemirror/rebaseParagraphRunFormatting.d.ts +22 -2
  132. package/dist/prosemirror/rebaseParagraphRunFormatting.js +39 -13
  133. package/dist/prosemirror/rebaseParagraphRuns.d.ts +36 -0
  134. package/dist/prosemirror/rebaseParagraphRuns.js +99 -0
  135. package/dist/prosemirror/runFormattingFromMarks.d.ts +18 -0
  136. package/dist/prosemirror/runFormattingFromMarks.js +567 -0
  137. package/dist/prosemirror/runFormattingReconciliation.js +10 -9
  138. package/dist/prosemirror/schema/nodes.d.ts +2 -0
  139. package/dist/prosemirror/styles/paragraphStyleCascade.d.ts +59 -0
  140. package/dist/prosemirror/styles/paragraphStyleCascade.js +145 -0
  141. package/dist/prosemirror/styles/resolvedStyleAttrs.d.ts +21 -2
  142. package/dist/prosemirror/styles/resolvedStyleAttrs.js +38 -1
  143. package/dist/prosemirror/styles/tableStyleRegions.d.ts +31 -0
  144. package/dist/prosemirror/styles/tableStyleRegions.js +55 -0
  145. package/dist/prosemirror/tableCellPaste.d.ts +74 -0
  146. package/dist/prosemirror/tableCellPaste.js +525 -0
  147. package/dist/prosemirror/tableGridMutation.d.ts +53 -14
  148. package/dist/prosemirror/tableGridMutation.js +166 -18
  149. package/dist/prosemirror/tableRunIn.d.ts +51 -0
  150. package/dist/prosemirror/tableRunIn.js +165 -0
  151. package/dist/prosemirror/textInput.js +11 -2
  152. package/dist/prosemirror/trackedRevisionPath.d.ts +17 -0
  153. package/dist/prosemirror/trackedRevisionPath.js +32 -0
  154. package/dist/server.d.ts +2 -2
  155. package/package.json +6 -6
@@ -5,21 +5,30 @@ import { inlineBookmarksOf } from "../prosemirror/commands/paragraphBookmarkJoin
5
5
  import { resolveAllTableChanges } from "../prosemirror/commands/resolveAllTableChanges.js";
6
6
  import { resolveAllNodePropertyChangeAttrs } from "../prosemirror/commands/resolveNodePropertyChangeAttrs.js";
7
7
  import { resolveParagraphChangeAttrs } from "../prosemirror/commands/resolveParagraphProperties.js";
8
+ import { rebaseParagraphRunContent } from "../prosemirror/rebaseParagraphRuns.js";
8
9
  import { expandRunFormattingCarrier } from "../prosemirror/runFormattingInlineCarriers.js";
9
10
  import { readAuthoredRunFormatting, reconcileRunFormattingMarks } from "../prosemirror/runFormattingReconciliation.js";
10
11
  import { paragraphRunStyleContext } from "../prosemirror/runStyleFormatting.js";
12
+ import { runParagraphsIntoTables, runsIntoFollowingTable } from "../prosemirror/tableRunIn.js";
11
13
  import { holdsNoContent } from "../prosemirror/zeroWidthAnchors.js";
12
14
  import { recordNodeResolution } from "./revisionResolutionEdits.js";
13
15
  import { resolveInlineRevisions } from "./revisionResolutionInline.js";
14
16
  import { composeRevisionResolutionMaps } from "./revisionResolutionStep.js";
15
17
  import { REVIEW_CARRIERS } from "@stll/docx-core/model";
16
18
  import { Fragment, Slice } from "prosemirror-model";
17
- import { Mapping, ReplaceStep, StepMap } from "prosemirror-transform";
19
+ import { Mapping, ReplaceStep, StepMap, Transform } from "prosemirror-transform";
18
20
  //#region src/internal/wholeStoryRevisionResolution.ts
19
21
  const resolveProperties = ({ doc, mode, styleResolver, numbering, steps, changedRanges }) => {
20
22
  let structural = false;
23
+ let runsIntoTable = false;
21
24
  const walk = (node, position) => {
22
25
  if (node.isText) return node;
26
+ if (!runsIntoTable && !node.isTextblock) {
27
+ for (let index = 0; index + 1 < node.childCount; index++) if (runsIntoFollowingTable(node.child(index), node.child(index + 1), mode)) {
28
+ runsIntoTable = true;
29
+ break;
30
+ }
31
+ }
23
32
  const nextAttrs = node.type.name === "paragraph" ? resolveParagraphChangeAttrs({
24
33
  node,
25
34
  mode,
@@ -94,7 +103,8 @@ const resolveProperties = ({ doc, mode, styleResolver, numbering, steps, changed
94
103
  };
95
104
  return {
96
105
  resolved: walk(doc, -1),
97
- structural
106
+ structural,
107
+ runsIntoTable
98
108
  };
99
109
  };
100
110
  const structuralReplacementMap = ({ replacements, tables, bookmarkJoins, origin }) => {
@@ -157,11 +167,14 @@ const structuralReplacementMap = ({ replacements, tables, bookmarkJoins, origin
157
167
  const last = ranges.length - 3;
158
168
  const previousStart = ranges.at(last);
159
169
  const previousOldSize = ranges.at(last + 1);
160
- if (last >= 0 && previousStart !== void 0 && previousOldSize !== void 0 && ranges.at(last + 2) === 0 && newEnd === newStart && previousStart + previousOldSize === oldStart) {
170
+ const previousNewSize = ranges.at(last + 2);
171
+ const newSize = newEnd - newStart;
172
+ if (last >= 0 && previousStart !== void 0 && previousOldSize !== void 0 && previousNewSize !== void 0 && (previousNewSize === 0 || newSize === 0) && previousStart + previousOldSize === oldStart) {
161
173
  ranges[last + 1] = previousOldSize + oldEnd - oldStart;
174
+ ranges[last + 2] = previousNewSize + newSize;
162
175
  return;
163
176
  }
164
- ranges.push(oldStart, oldEnd - oldStart, newEnd - newStart);
177
+ ranges.push(oldStart, oldEnd - oldStart, newSize);
165
178
  });
166
179
  };
167
180
  for (const replacement of replacements) {
@@ -228,7 +241,24 @@ const resolveStructure = ({ node, position, context }) => {
228
241
  let final = chain.node;
229
242
  if (chain.chunks.length > 1) {
230
243
  const children = [];
231
- for (let index = chain.chunks.length - 1; index >= 0; index--) chain.chunks[index]?.forEach((child) => children.push(child));
244
+ for (let index = chain.chunks.length - 1; index >= 0; index--) {
245
+ const chunk = chain.chunks[index];
246
+ if (!chunk) continue;
247
+ let content = chunk.type === "paragraph" ? chunk.source.content : chunk.content;
248
+ if (chunk.type === "paragraph" && chunk.position !== chain.formattingOwnerPosition) content = rebaseParagraphRunContent({
249
+ paragraph: chunk.source,
250
+ target: chain.node,
251
+ position: chunk.position,
252
+ styleResolver: context.styleResolver,
253
+ onRebased: ({ before, after, position: runPosition }) => recordNodeResolution({
254
+ before,
255
+ after,
256
+ position: runPosition,
257
+ steps: context.steps
258
+ })
259
+ });
260
+ content.forEach((child) => children.push(child));
261
+ }
232
262
  final = recreateProseNodeWithParagraphPropertySource(chain.node, { content: Fragment.fromArray(children) });
233
263
  }
234
264
  if (!chain.before.sameMarkup(final)) context.changedRanges.push({
@@ -313,26 +343,23 @@ const resolveStructure = ({ node, position, context }) => {
313
343
  return null;
314
344
  }
315
345
  bookmarks = Fragment.fromArray(inline);
316
- chain.chunks.push(bookmarks);
317
- pendingBookmarks = [];
318
- }
319
- const empty = holdsNoContent(paragraph);
320
- const owner = empty ? chain.node : paragraph;
321
- const next = chain.node;
322
- if (empty) {
323
- const displacedToken = getProseParagraphPropertySourceToken(paragraph);
324
- const selectedToken = getProseParagraphPropertySourceToken(next);
325
- context.transfers.push({
326
- displacedToken: typeof displacedToken === "string" ? displacedToken : null,
327
- selectedToken: typeof selectedToken === "string" ? selectedToken : null
346
+ chain.chunks.push({
347
+ type: "bookmarks",
348
+ content: bookmarks
328
349
  });
350
+ pendingBookmarks = [];
329
351
  }
330
- chain.node = recreateProseNodeWithParagraphPropertySource(owner, { attrs: {
331
- ...owner.attrs,
332
- pPrMark: next.attrs["pPrMark"],
333
- _sectionProperties: next.attrs["_sectionProperties"]
334
- } });
335
- chain.chunks.push(paragraph.content);
352
+ const displacedToken = getProseParagraphPropertySourceToken(paragraph);
353
+ const selectedToken = getProseParagraphPropertySourceToken(chain.node);
354
+ context.transfers.push({
355
+ displacedToken: typeof displacedToken === "string" ? displacedToken : null,
356
+ selectedToken: typeof selectedToken === "string" ? selectedToken : null
357
+ });
358
+ chain.chunks.push({
359
+ type: "paragraph",
360
+ source: paragraph,
361
+ position: entry.position
362
+ });
336
363
  chain.position = entry.position;
337
364
  chain.before = paragraph;
338
365
  chain.joinBoundaries.push({
@@ -357,7 +384,12 @@ const resolveStructure = ({ node, position, context }) => {
357
384
  } }) : paragraph;
358
385
  chain = {
359
386
  node: resolved,
360
- chunks: [resolved.content],
387
+ formattingOwnerPosition: entry.position,
388
+ chunks: [{
389
+ type: "paragraph",
390
+ source: resolved,
391
+ position: entry.position
392
+ }],
361
393
  position: entry.position,
362
394
  before: paragraph,
363
395
  joinBoundaries: []
@@ -456,6 +488,42 @@ const resolveStructure = ({ node, position, context }) => {
456
488
  return final;
457
489
  };
458
490
  const resolveWholeStory = ({ doc, mode, styleResolver, numbering }) => {
491
+ const { runsIntoTable, ...direct } = resolveStoryRevisions({
492
+ doc,
493
+ mode,
494
+ styleResolver,
495
+ numbering
496
+ });
497
+ if (!runsIntoTable) return direct;
498
+ const runIn = new Transform(doc);
499
+ const { targets, maps, transfers } = runParagraphsIntoTables(runIn, mode, styleResolver);
500
+ if (!runIn.docChanged) return direct;
501
+ const { runsIntoTable: _rerun, ...result } = resolveStoryRevisions({
502
+ doc: runIn.doc,
503
+ mode,
504
+ styleResolver,
505
+ numbering
506
+ });
507
+ for (const { position, step } of targets) {
508
+ const from = runIn.mapping.slice(step).map(position);
509
+ const target = runIn.doc.nodeAt(from);
510
+ if (target) result.changedRanges.push({
511
+ from,
512
+ to: from + target.nodeSize
513
+ });
514
+ }
515
+ let runInMap = StepMap.empty;
516
+ for (const map of maps) runInMap = composeRevisionResolutionMaps(runInMap, map);
517
+ const positionMap = composeRevisionResolutionMaps(runInMap, result.positionMap);
518
+ return {
519
+ ...result,
520
+ steps: [...runIn.steps, ...result.steps],
521
+ positionMap,
522
+ mapping: new Mapping([positionMap]),
523
+ transfers: [...transfers, ...result.transfers]
524
+ };
525
+ };
526
+ const resolveStoryRevisions = ({ doc, mode, styleResolver, numbering }) => {
459
527
  const steps = [];
460
528
  const propertyRanges = [];
461
529
  const propertyResult = resolveProperties({
@@ -476,6 +544,7 @@ const resolveWholeStory = ({ doc, mode, styleResolver, numbering }) => {
476
544
  });
477
545
  const context = {
478
546
  mode,
547
+ styleResolver,
479
548
  steps: [],
480
549
  changedRanges: [],
481
550
  deleted: [],
@@ -523,7 +592,8 @@ const resolveWholeStory = ({ doc, mode, styleResolver, numbering }) => {
523
592
  structural: context.structural,
524
593
  failed: context.failed,
525
594
  removedEndpointCount: context.removedEndpointCount,
526
- removedReferences: context.removedReferences
595
+ removedReferences: context.removedReferences,
596
+ runsIntoTable: propertyResult.runsIntoTable
527
597
  };
528
598
  };
529
599
  //#endregion
@@ -15,7 +15,7 @@ import { applyDocumentGrid, calculateEmptyParagraphMetrics, calculateTypographyM
15
15
  import { getListMarkerInlineWidth } from "./listMarkerWidth.js";
16
16
  import { DEFAULT_FONT_FAMILY, buildRunFontStyle, ptToPx } from "./measureHelpers.js";
17
17
  import { getFontMetrics, measureRun, measureTextWidth } from "./measureProvider.js";
18
- import { WIDTH_TOLERANCE, fieldMeasureText, isEmptyTextRun, isFieldRun, isImageRun, isLineBreakRun, isMathRun, isTabRun, isTextRun, runToFontStyle } from "./paragraphMeasureShared.js";
18
+ import { WIDTH_TOLERANCE, canonicalLineWidth, fieldMeasureText, isEmptyTextRun, isFieldRun, isImageRun, isLineBreakRun, isMathRun, isTabRun, isTextRun, runToFontStyle } from "./paragraphMeasureShared.js";
19
19
  import { canClampTabToRightEdge, hasFollowingTabOnLine, hasPriorTabOnLine, measureDecimalPrefixWidthAfterTab, measureInlineWidthAfterTab } from "./paragraphTabs.js";
20
20
  import { calculateTabWidth, pixelsToTwips } from "./tabCalculator.js";
21
21
  //#region src/layout-engine/measure/measureParagraph.ts
@@ -215,7 +215,7 @@ function measureParagraph(block, maxWidth, options) {
215
215
  fromChar: currentLine.fromChar,
216
216
  toRun: currentLine.toRun,
217
217
  toChar: currentLine.toChar,
218
- width: Math.max(0, currentLine.width - currentLine.trailingWhitespaceWidth),
218
+ width: canonicalLineWidth(currentLine.width - currentLine.trailingWhitespaceWidth),
219
219
  ...finalTypography,
220
220
  ...currentLine.justificationPaint !== void 0 ? { justificationPaint: currentLine.justificationPaint } : {},
221
221
  ...currentLine.discretionaryHyphen ? { discretionaryHyphen: currentLine.discretionaryHyphen } : {},
@@ -5,6 +5,17 @@ import { FloatingLineSegmentZone } from "./floatingZones.js";
5
5
  declare const DEFAULT_FONT_SIZE = 11;
6
6
  declare const DEFAULT_LINE_HEIGHT_MULTIPLIER = 1;
7
7
  declare const WIDTH_TOLERANCE = 0.5;
8
+ /**
9
+ * The width a finished line reports. A line's width is a floating-point sum
10
+ * of per-token measurements, and the same text can reach it through different
11
+ * token groupings, e.g. a run split where a hidden revision sat measures
12
+ * "confirm" + "ation" where the resolved text measures "confirmation". Those
13
+ * sums agree only up to the last few bits, so the result snaps to a
14
+ * binary-exact 1/1024 px grid (under 0.0005 px, far below a device pixel):
15
+ * the same text yields the same width whichever grouping summed it, and the
16
+ * alignment offsets derived from it agree too.
17
+ */
18
+ declare const canonicalLineWidth: (width: number) => number;
8
19
  /**
9
20
  * Typography metrics for a line
10
21
  */
@@ -106,4 +117,4 @@ declare function isEmptyTextRun(run: TextRun): boolean;
106
117
  declare function isBlockLayoutImageRun(run: ImageRun): boolean;
107
118
  declare function isSpaceOrTab(char: string | undefined): boolean;
108
119
  //#endregion
109
- export { DEFAULT_FONT_SIZE, DEFAULT_LINE_HEIGHT_MULTIPLIER, LineState, LineTypography, WIDTH_TOLERANCE, fieldMeasureText, isBlockLayoutImageRun, isEmptyTextRun, isFieldRun, isImageRun, isLineBreakRun, isMathRun, isSpaceOrTab, isTabRun, isTextRun, runToFontStyle };
120
+ export { DEFAULT_FONT_SIZE, DEFAULT_LINE_HEIGHT_MULTIPLIER, LineState, LineTypography, WIDTH_TOLERANCE, canonicalLineWidth, fieldMeasureText, isBlockLayoutImageRun, isEmptyTextRun, isFieldRun, isImageRun, isLineBreakRun, isMathRun, isSpaceOrTab, isTabRun, isTextRun, runToFontStyle };
@@ -4,6 +4,19 @@ import { DEFAULT_FONT_FAMILY, buildRunFontStyle } from "./measureHelpers.js";
4
4
  const DEFAULT_FONT_SIZE = 11;
5
5
  const DEFAULT_LINE_HEIGHT_MULTIPLIER = 1;
6
6
  const WIDTH_TOLERANCE = .5;
7
+ /** Grid a finished line's width snaps to: 1/1024 px, exact in binary floating point. */
8
+ const LINE_WIDTH_GRID = 1024;
9
+ /**
10
+ * The width a finished line reports. A line's width is a floating-point sum
11
+ * of per-token measurements, and the same text can reach it through different
12
+ * token groupings, e.g. a run split where a hidden revision sat measures
13
+ * "confirm" + "ation" where the resolved text measures "confirmation". Those
14
+ * sums agree only up to the last few bits, so the result snaps to a
15
+ * binary-exact 1/1024 px grid (under 0.0005 px, far below a device pixel):
16
+ * the same text yields the same width whichever grouping summed it, and the
17
+ * alignment offsets derived from it agree too.
18
+ */
19
+ const canonicalLineWidth = (width) => Math.round(Math.max(0, width) * LINE_WIDTH_GRID) / LINE_WIDTH_GRID;
7
20
  /**
8
21
  * Extract FontStyle from a run that carries RunFormatting (text, tab, or
9
22
  * field). All three share the same formatting shape, so they measure the
@@ -79,4 +92,4 @@ function isSpaceOrTab(char) {
79
92
  return char === " " || char === " ";
80
93
  }
81
94
  //#endregion
82
- export { DEFAULT_FONT_SIZE, DEFAULT_LINE_HEIGHT_MULTIPLIER, WIDTH_TOLERANCE, fieldMeasureText, isBlockLayoutImageRun, isEmptyTextRun, isFieldRun, isImageRun, isLineBreakRun, isMathRun, isSpaceOrTab, isTabRun, isTextRun, runToFontStyle };
95
+ export { DEFAULT_FONT_SIZE, DEFAULT_LINE_HEIGHT_MULTIPLIER, WIDTH_TOLERANCE, canonicalLineWidth, fieldMeasureText, isBlockLayoutImageRun, isEmptyTextRun, isFieldRun, isImageRun, isLineBreakRun, isMathRun, isSpaceOrTab, isTabRun, isTextRun, runToFontStyle };
@@ -7,8 +7,8 @@
7
7
  */
8
8
  /**
9
9
  * Escape only characters that would change markdown structure mid-text:
10
- * - backslash, backtick, asterisk, brackets (always)
11
- * - underscore: only at word boundaries (emphasis trigger)
10
+ * - backslash, backtick, asterisk, brackets, tilde (always)
11
+ * - underscore: unless between two letters or digits (emphasis trigger)
12
12
  * - angle brackets: only when they look like a tag/autolink
13
13
  *
14
14
  * Characters like `.` `-` `+` `#` `(` `)` `!` are only meaningful at line
@@ -7,8 +7,8 @@
7
7
  */
8
8
  /**
9
9
  * Escape only characters that would change markdown structure mid-text:
10
- * - backslash, backtick, asterisk, brackets (always)
11
- * - underscore: only at word boundaries (emphasis trigger)
10
+ * - backslash, backtick, asterisk, brackets, tilde (always)
11
+ * - underscore: unless between two letters or digits (emphasis trigger)
12
12
  * - angle brackets: only when they look like a tag/autolink
13
13
  *
14
14
  * Characters like `.` `-` `+` `#` `(` `)` `!` are only meaningful at line
@@ -16,9 +16,8 @@
16
16
  * when to escape those.
17
17
  */
18
18
  function escapeInline(text) {
19
- let out = text.replace(/(?<ch>[\\`*[\]])/gu, "\\$<ch>");
20
- out = out.replace(/(?<pre>^|\s)_/gu, "$<pre>\\_");
21
- out = out.replace(/_(?<post>\s|$)/gu, "\\_$<post>");
19
+ let out = text.replace(/(?<ch>[\\`*[\]~])/gu, "\\$<ch>");
20
+ out = out.replace(/(?<![\p{L}\p{N}])_|_(?![\p{L}\p{N}])/gu, "\\_");
22
21
  out = out.replace(/<(?<tag>\/?[A-Za-z][\w-]*)(?=[\s/>])/gu, "\\<$<tag>");
23
22
  return out;
24
23
  }
@@ -11,37 +11,103 @@ import { panic } from "better-result";
11
11
  * of the same list. Ported from eigenpal/docx-editor PR #595.
12
12
  */
13
13
  /**
14
- * In `trackedChanges: "clean"` mode every change is accepted. A paragraph whose
15
- * end-of-paragraph mark is a pending deletion (`pPrMark.kind === "del"`) loses
16
- * its break on accept and merges with the following paragraph. Word's join
17
- * keeps the FIRST paragraph's properties (style, list) and drops the resolved
18
- * mark; the surviving break is the next paragraph's, so a run of consecutive
19
- * deletions collapses into one paragraph. A first paragraph with nothing left
20
- * once its deletions are accepted (a whole deleted paragraph) contributes only
21
- * the join, so the NEXT paragraph keeps its own properties, as the editor's
22
- * accept does. A non-paragraph next block (table, SDT) is structurally
23
- * incompatible and stays unmerged, matching the editor's accept-change join
24
- * guard (`commands/comments.ts`).
14
+ * In `trackedChanges: "clean"` mode every change is accepted, as the editor's
15
+ * accept-all resolves the story (`internal/wholeStoryRevisionResolution.ts`).
16
+ *
17
+ * A paragraph whose mark is pending deletion loses its break on accept and
18
+ * runs on into the paragraph after it, which is the paragraph left: its mark
19
+ * ends the joined text, and a paragraph's properties (style, list) live on its
20
+ * mark. A run of consecutive deletions collapses into that last paragraph.
21
+ *
22
+ * With a table right after it, its words run on into the table's first cell
23
+ * and lead that cell's first paragraph (`prosemirror/tableRunIn.ts`), unless
24
+ * it ends a section, keeps nothing once accepted, or that cell is pending.
25
+ * Otherwise a paragraph that cannot join keeps its place, or goes when it
26
+ * keeps nothing and something follows it.
25
27
  */
26
28
  function mergeAcceptedParagraphBreaks(blocks) {
27
- const merged = [];
28
- for (const block of blocks) {
29
- const prev = merged.at(-1);
30
- if (prev?.type === "paragraph" && prev.pPrMark?.kind === "del" && block.type === "paragraph") {
31
- const next = block.pPrMark;
32
- const content = [...prev.content, ...block.content];
33
- const joined = cloneParagraphWithoutPropertySource(holdsNothingOnAccept(prev) ? block : prev, {
34
- content,
35
- ...next ? { pPrMark: next } : {}
36
- });
37
- if (!next) Reflect.deleteProperty(joined, "pPrMark");
38
- merged[merged.length - 1] = joined;
29
+ const reversed = [];
30
+ let survivor = null;
31
+ let tableFollows = false;
32
+ let followed = false;
33
+ const flush = () => {
34
+ if (survivor) reversed.push(survivor);
35
+ survivor = null;
36
+ };
37
+ for (let index = blocks.length - 1; index >= 0; index--) {
38
+ const block = blocks[index];
39
+ if (!block) continue;
40
+ if (block.type !== "paragraph") {
41
+ flush();
42
+ reversed.push(block);
43
+ tableFollows = block.type === "table";
44
+ followed ||= tableFollows;
39
45
  continue;
40
46
  }
41
- merged.push(block);
47
+ const goes = block.pPrMark?.kind === "del" || block.pPrMark?.kind === "moveFrom";
48
+ if (goes && survivor) {
49
+ survivor = cloneParagraphWithoutPropertySource(survivor, { content: [...block.content, ...survivor.content] });
50
+ continue;
51
+ }
52
+ const table = reversed.at(-1);
53
+ if (goes && tableFollows && table?.type === "table") {
54
+ const ranIn = tableWithParagraphRunIn(table, block);
55
+ if (ranIn) {
56
+ reversed[reversed.length - 1] = ranIn;
57
+ continue;
58
+ }
59
+ }
60
+ flush();
61
+ tableFollows = false;
62
+ if (goes && holdsNothingOnAccept(block) && followed && index + reversed.length > 0) continue;
63
+ survivor = block;
64
+ followed = true;
42
65
  }
43
- return merged;
66
+ flush();
67
+ return reversed.reverse();
44
68
  }
69
+ /**
70
+ * Whether the cell a paragraph's words would run into is itself pending (its
71
+ * row or the cell, through nested tables' first cells), as
72
+ * `prosemirror/tableRunIn.ts` reads it.
73
+ */
74
+ const runInCellPending = (table) => {
75
+ const row = table.rows[0];
76
+ const cell = row?.cells[0];
77
+ if (!row || !cell) return false;
78
+ if (row.structuralChange !== void 0 || cell.structuralChange !== void 0) return true;
79
+ const first = cell.content[0];
80
+ return first?.type === "table" && runInCellPending(first);
81
+ };
82
+ /**
83
+ * `table` with `paragraph`'s words leading its first cell's first paragraph,
84
+ * descending into nested tables, or null when the paragraph keeps its place.
85
+ */
86
+ const tableWithParagraphRunIn = (table, paragraph) => {
87
+ if (paragraph.sectionProperties !== void 0 || holdsNothingOnAccept(paragraph)) return null;
88
+ if (runInCellPending(table)) return null;
89
+ const runIn = (current) => {
90
+ const [row, ...rows] = current.rows;
91
+ const [cell, ...cells] = row?.cells ?? [];
92
+ const [first, ...rest] = cell?.content ?? [];
93
+ if (!row || !cell || !first) return null;
94
+ let led = null;
95
+ if (first.type === "paragraph") led = cloneParagraphWithoutPropertySource(first, { content: [...paragraph.content, ...first.content] });
96
+ else if (first.type === "table") led = runIn(first);
97
+ if (!led) return null;
98
+ return {
99
+ ...current,
100
+ rows: [{
101
+ ...row,
102
+ cells: [{
103
+ ...cell,
104
+ content: [led, ...rest]
105
+ }, ...cells]
106
+ }, ...rows]
107
+ };
108
+ };
109
+ return runIn(table);
110
+ };
45
111
  /** Paragraph content that shows nothing: range boundaries and anchors. */
46
112
  const ZERO_WIDTH_CONTENT = /* @__PURE__ */ new Set([
47
113
  "bookmarkStart",
@@ -1,10 +1,19 @@
1
1
  import { document_d_exports } from "../types/document.js";
2
2
  import { RenderContext } from "./types.js";
3
3
  //#region src/markdown/renderRuns.d.ts
4
+ /**
5
+ * The character beside a run's delimiters: `""` at the paragraph's edge,
6
+ * `undefined` when it cannot be told (read as a letter, the strictest case).
7
+ */
8
+ type Neighbor = string | undefined;
9
+ type RunNeighbors = {
10
+ before: Neighbor;
11
+ after: Neighbor;
12
+ };
4
13
  /**
5
14
  * Render the full inline content of a paragraph, tracking comment-range
6
15
  * boundaries to apply the configured wrapper.
7
16
  */
8
- declare function renderParagraphInline(ctx: RenderContext, pkg: document_d_exports.DocxPackage | undefined, content: readonly document_d_exports.ParagraphContent[], paraId: string | undefined): string;
17
+ declare function renderParagraphInline(ctx: RenderContext, pkg: document_d_exports.DocxPackage | undefined, content: readonly document_d_exports.ParagraphContent[], paraId: string | undefined, edges?: RunNeighbors): string;
9
18
  //#endregion
10
19
  export { renderParagraphInline };