@stll/folio-core 0.35.1 → 0.37.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 (236) hide show
  1. package/README.md +59 -1
  2. package/dist/ai-edits/apply.js +878 -377
  3. package/dist/ai-edits/block-identity.d.ts +4 -1
  4. package/dist/ai-edits/block-identity.js +4 -1
  5. package/dist/ai-edits/blockRange.js +14 -14
  6. package/dist/ai-edits/clean-text.d.ts +40 -1
  7. package/dist/ai-edits/clean-text.js +52 -2
  8. package/dist/ai-edits/headless.d.ts +3 -1
  9. package/dist/ai-edits/headless.js +141 -73
  10. package/dist/ai-edits/index.d.ts +3 -3
  11. package/dist/ai-edits/index.js +2 -2
  12. package/dist/ai-edits/read.js +38 -20
  13. package/dist/ai-edits/snapshot.d.ts +14 -6
  14. package/dist/ai-edits/snapshot.js +105 -20
  15. package/dist/ai-edits/table-cell-mutations.js +1 -1
  16. package/dist/ai-edits/table-row-column-mutations.js +7 -0
  17. package/dist/ai-edits/table-template.d.ts +11 -1
  18. package/dist/ai-edits/table-template.js +49 -17
  19. package/dist/ai-edits/types.d.ts +62 -61
  20. package/dist/ai-edits/word-diff.d.ts +18 -3
  21. package/dist/ai-edits/word-diff.js +556 -67
  22. package/dist/ai-suggestions/conflict.js +1 -4
  23. package/dist/ai-suggestions/text-positions.d.ts +8 -0
  24. package/dist/ai-suggestions/text-positions.js +27 -5
  25. package/dist/compare/__fixtures__/body-sequence.js +3 -4
  26. package/dist/compare/column-alignment.d.ts +13 -13
  27. package/dist/compare/column-alignment.js +78 -39
  28. package/dist/compare/compare.d.ts +4 -3
  29. package/dist/compare/compare.js +48 -21
  30. package/dist/compare/content-alignment.d.ts +95 -0
  31. package/dist/compare/content-alignment.js +1450 -0
  32. package/dist/compare/content-types.d.ts +100 -0
  33. package/dist/compare/content-types.js +0 -0
  34. package/dist/compare/content.d.ts +209 -0
  35. package/dist/compare/content.js +885 -0
  36. package/dist/compare/formatting.d.ts +5 -5
  37. package/dist/compare/formatting.js +6 -4
  38. package/dist/compare/plan.d.ts +6 -1
  39. package/dist/compare/plan.js +171 -566
  40. package/dist/compare/scenario.d.ts +2 -2
  41. package/dist/compare/types.d.ts +3 -3
  42. package/dist/compare/verification.d.ts +8 -9
  43. package/dist/compare/verification.js +72 -50
  44. package/dist/compat/eigenpal.d.ts +5 -3
  45. package/dist/compat/eigenpal.js +3 -2
  46. package/dist/controller/headerFooterEditorManager.js +18 -10
  47. package/dist/controller/hiddenEditorApi.js +1 -1
  48. package/dist/controller/hiddenEditorManager.d.ts +7 -2
  49. package/dist/controller/hiddenEditorManager.js +15 -6
  50. package/dist/controller/layoutPipeline.js +5 -3
  51. package/dist/controller/noteEditorManager.js +12 -7
  52. package/dist/display-list/build/headerFooterPrimitives.js +1 -0
  53. package/dist/display-list/build/storyPrimitives.d.ts +5 -2
  54. package/dist/display-list/build/storyPrimitives.js +60 -3
  55. package/dist/display-list/build/tablePrimitives.js +30 -0
  56. package/dist/display-list/primitives.d.ts +1 -1
  57. package/dist/document-operations.d.ts +8 -4
  58. package/dist/document-operations.js +104 -12
  59. package/dist/docx/blockContentParser.js +6 -27
  60. package/dist/docx/commentParser.js +2 -4
  61. package/dist/docx/commentRangeIntegrity.js +2 -4
  62. package/dist/docx/documentClone.d.ts +2 -0
  63. package/dist/docx/documentClone.js +2 -0
  64. package/dist/docx/ensureParaIds.js +9 -4
  65. package/dist/docx/headerFooterParser.js +2 -4
  66. package/dist/docx/normalizeBaseDirection.js +5 -7
  67. package/dist/docx/numberingParser.d.ts +3 -1
  68. package/dist/docx/numberingParser.js +4 -1
  69. package/dist/docx/paragraphParser.js +34 -35
  70. package/dist/docx/paragraphPropertySource.d.ts +49 -0
  71. package/dist/docx/paragraphPropertySource.js +113 -0
  72. package/dist/docx/paragraphTraversal.js +30 -34
  73. package/dist/docx/rezip.d.ts +0 -8
  74. package/dist/docx/rezip.js +41 -16
  75. package/dist/docx/runConsolidator.js +2 -4
  76. package/dist/docx/runParser.js +6 -17
  77. package/dist/docx/sectionParser.js +1 -15
  78. package/dist/docx/serializer/paragraphSerializer.js +289 -30
  79. package/dist/docx/serializer/runSerializer.js +6 -12
  80. package/dist/docx/serializer/sectionPropertiesSerializer.js +2 -10
  81. package/dist/docx/serializer/tableSerializer.js +4 -23
  82. package/dist/docx/serializer/trackedChangeAttributes.d.ts +11 -0
  83. package/dist/docx/serializer/trackedChangeAttributes.js +31 -0
  84. package/dist/docx/server/build.d.ts +1 -1
  85. package/dist/docx/server/createBilingualDocument.js +8 -10
  86. package/dist/docx/server/evaluateDocxXmlPatchProposal.js +22 -13
  87. package/dist/docx/server/validateDocxConformance.js +17 -13
  88. package/dist/docx/tableParser.js +1 -37
  89. package/dist/docx/trackedChangeInfo.d.ts +11 -0
  90. package/dist/docx/trackedChangeInfo.js +38 -0
  91. package/dist/docx/verbatimCapture.d.ts +20 -9
  92. package/dist/docx/verbatimCapture.js +208 -8
  93. package/dist/docx/xmlParser.d.ts +3 -1
  94. package/dist/docx/xmlParser.js +6 -1
  95. package/dist/docx/xmlSafety.d.ts +1 -1
  96. package/dist/docx/xmlSafety.js +157 -0
  97. package/dist/headless-layout.js +5 -4
  98. package/dist/index.d.ts +5 -3
  99. package/dist/index.js +3 -2
  100. package/dist/internal/headlessRevisionResolution.d.ts +23 -0
  101. package/dist/internal/headlessRevisionResolution.js +155 -0
  102. package/dist/internal/headlessRevisionResolutionGuard.d.ts +12 -0
  103. package/dist/internal/headlessRevisionResolutionGuard.js +28 -0
  104. package/dist/internal/pageBreakRunDescendantIndex.d.ts +9 -0
  105. package/dist/internal/pageBreakRunDescendantIndex.js +27 -0
  106. package/dist/internal/pageBreakRunPartition.d.ts +26 -0
  107. package/dist/internal/pageBreakRunPartition.js +35 -0
  108. package/dist/internal/pageBreakRunSourceDescendantIndex.d.ts +15 -0
  109. package/dist/internal/pageBreakRunSourceDescendantIndex.js +126 -0
  110. package/dist/internal/sectionEndpointResolution.d.ts +32 -0
  111. package/dist/internal/sectionEndpointResolution.js +38 -0
  112. package/dist/layout-bridge/convert/footnoteLayout.js +1 -0
  113. package/dist/layout-bridge/convert/headerFooterLayout.d.ts +16 -4
  114. package/dist/layout-bridge/convert/headerFooterLayout.js +52 -9
  115. package/dist/layout-bridge/convert/toFlowBlocks.d.ts +4 -0
  116. package/dist/layout-bridge/convert/toFlowBlocks.js +391 -82
  117. package/dist/layout-bridge/dom/clickToPositionDom.d.ts +8 -1
  118. package/dist/layout-bridge/dom/clickToPositionDom.js +114 -40
  119. package/dist/layout-bridge/dom/textStreamDom.d.ts +24 -0
  120. package/dist/layout-bridge/dom/textStreamDom.js +75 -0
  121. package/dist/layout-bridge/headerFooterLayout.js +16 -30
  122. package/dist/layout-engine/index.js +12 -3
  123. package/dist/layout-engine/measure/tableFragmentBorderGeometry.d.ts +17 -0
  124. package/dist/layout-engine/measure/tableFragmentBorderGeometry.js +24 -0
  125. package/dist/layout-engine/renderedBreakReconciliation.js +1 -1
  126. package/dist/layout-engine/types.d.ts +7 -0
  127. package/dist/layout-painter/imageLayout.d.ts +1 -1
  128. package/dist/layout-painter/renderTable.js +20 -0
  129. package/dist/markdown/renderBlock.js +7 -10
  130. package/dist/model.d.ts +1 -1
  131. package/dist/paged-layout/rangeProjection.js +6 -9
  132. package/dist/paged-layout/transactionDirtyRange.d.ts +3 -1
  133. package/dist/paged-layout/transactionDirtyRange.js +23 -1
  134. package/dist/prosemirror/attrs/index.d.ts +7 -3
  135. package/dist/prosemirror/attrs/index.js +128 -7
  136. package/dist/prosemirror/bookmarkBoundaryIntegrity.d.ts +9 -0
  137. package/dist/prosemirror/bookmarkBoundaryIntegrity.js +22 -0
  138. package/dist/prosemirror/commands/comments.d.ts +10 -1
  139. package/dist/prosemirror/commands/comments.js +551 -87
  140. package/dist/prosemirror/commands/formatPainter.d.ts +45 -10
  141. package/dist/prosemirror/commands/formatPainter.js +319 -63
  142. package/dist/prosemirror/commands/index.d.ts +2 -2
  143. package/dist/prosemirror/commands/pageBreak.d.ts +5 -2
  144. package/dist/prosemirror/commands/pageBreak.js +18 -36
  145. package/dist/prosemirror/commands/propertyChangeScope.d.ts +27 -3
  146. package/dist/prosemirror/commands/propertyChangeScope.js +85 -14
  147. package/dist/prosemirror/conversion/fromProseDoc.d.ts +8 -5
  148. package/dist/prosemirror/conversion/fromProseDoc.js +935 -223
  149. package/dist/prosemirror/conversion/runShadingMark.js +2 -2
  150. package/dist/prosemirror/conversion/toProseDoc.d.ts +26 -1
  151. package/dist/prosemirror/conversion/toProseDoc.js +439 -291
  152. package/dist/prosemirror/extensions/StarterKit.js +4 -0
  153. package/dist/prosemirror/extensions/core/ParagraphExtension.js +54 -6
  154. package/dist/prosemirror/extensions/features/AutoBidiDetectionExtension.js +7 -1
  155. package/dist/prosemirror/extensions/features/ListExtension.js +95 -123
  156. package/dist/prosemirror/extensions/features/ParaIdAllocatorExtension.js +19 -6
  157. package/dist/prosemirror/extensions/features/ParagraphChangeTrackerExtension.d.ts +27 -1
  158. package/dist/prosemirror/extensions/features/ParagraphChangeTrackerExtension.js +134 -30
  159. package/dist/prosemirror/extensions/features/pasteCleanup.js +9 -15
  160. package/dist/prosemirror/extensions/marks/BoldExtension.js +4 -3
  161. package/dist/prosemirror/extensions/marks/CharacterStyleExtension.d.ts +4 -7
  162. package/dist/prosemirror/extensions/marks/CharacterStyleExtension.js +5 -11
  163. package/dist/prosemirror/extensions/marks/FontSizeExtension.js +3 -3
  164. package/dist/prosemirror/extensions/marks/ItalicExtension.js +4 -3
  165. package/dist/prosemirror/extensions/marks/PageBreakRunOwnerExtension.d.ts +13 -0
  166. package/dist/prosemirror/extensions/marks/PageBreakRunOwnerExtension.js +39 -0
  167. package/dist/prosemirror/extensions/marks/RunFormattingOverrideExtension.d.ts +7 -1
  168. package/dist/prosemirror/extensions/marks/RunFormattingOverrideExtension.js +67 -21
  169. package/dist/prosemirror/extensions/marks/TrackedChangeExtensions.js +2 -0
  170. package/dist/prosemirror/extensions/marks/markUtils.d.ts +8 -1
  171. package/dist/prosemirror/extensions/marks/markUtils.js +88 -2
  172. package/dist/prosemirror/extensions/nodes/BookmarkBoundaryExtension.js +44 -3
  173. package/dist/prosemirror/extensions/nodes/FieldExtension.js +1 -1
  174. package/dist/prosemirror/extensions/nodes/HardBreakExtension.js +15 -4
  175. package/dist/prosemirror/extensions/nodes/PageBreakExtension.d.ts +6 -0
  176. package/dist/prosemirror/extensions/nodes/PageBreakExtension.js +6 -0
  177. package/dist/prosemirror/extensions/nodes/PageBreakRunExtension.d.ts +6 -0
  178. package/dist/prosemirror/extensions/nodes/PageBreakRunExtension.js +36 -0
  179. package/dist/prosemirror/findReplaceSelection.js +8 -3
  180. package/dist/prosemirror/index.d.ts +3 -3
  181. package/dist/prosemirror/listMarker.d.ts +26 -1
  182. package/dist/prosemirror/listMarker.js +108 -14
  183. package/dist/prosemirror/pageBreakRunProjection.d.ts +28 -0
  184. package/dist/prosemirror/pageBreakRunProjection.js +47 -0
  185. package/dist/prosemirror/paraText.js +6 -0
  186. package/dist/prosemirror/paragraphAlignment.d.ts +12 -0
  187. package/dist/prosemirror/paragraphAlignment.js +13 -0
  188. package/dist/prosemirror/paragraphSpacing.d.ts +29 -0
  189. package/dist/prosemirror/paragraphSpacing.js +125 -0
  190. package/dist/prosemirror/plugins/documentNumbering.d.ts +8 -0
  191. package/dist/prosemirror/plugins/documentNumbering.js +18 -0
  192. package/dist/prosemirror/plugins/pmTextScan.d.ts +3 -2
  193. package/dist/prosemirror/plugins/pmTextScan.js +14 -4
  194. package/dist/prosemirror/plugins/suggestionMode.js +9 -11
  195. package/dist/prosemirror/rebaseParagraphRunFormatting.d.ts +16 -0
  196. package/dist/prosemirror/rebaseParagraphRunFormatting.js +61 -0
  197. package/dist/prosemirror/runFormattingInlineCarriers.d.ts +64 -0
  198. package/dist/prosemirror/runFormattingInlineCarriers.js +121 -0
  199. package/dist/prosemirror/runFormattingProvenance.d.ts +12 -0
  200. package/dist/prosemirror/runFormattingProvenance.js +48 -0
  201. package/dist/prosemirror/runFormattingReconciliation.d.ts +25 -0
  202. package/dist/prosemirror/runFormattingReconciliation.js +54 -0
  203. package/dist/prosemirror/runPropertyChangeResolution.d.ts +18 -0
  204. package/dist/prosemirror/runPropertyChangeResolution.js +18 -0
  205. package/dist/prosemirror/runStyleFormatting.d.ts +50 -0
  206. package/dist/prosemirror/runStyleFormatting.js +105 -0
  207. package/dist/prosemirror/schema/index.d.ts +3 -3
  208. package/dist/prosemirror/schema/marks.d.ts +84 -9
  209. package/dist/prosemirror/schema/marks.js +73 -1
  210. package/dist/prosemirror/schema/nodes.d.ts +30 -6
  211. package/dist/prosemirror/styles/resolvedStyleAttrs.d.ts +14 -2
  212. package/dist/prosemirror/styles/resolvedStyleAttrs.js +45 -23
  213. package/dist/prosemirror/styles/styleResolver.d.ts +10 -13
  214. package/dist/prosemirror/styles/styleResolver.js +3 -3
  215. package/dist/prosemirror/styles/styleToggleCascade.d.ts +8 -1
  216. package/dist/prosemirror/styles/styleToggleCascade.js +24 -1
  217. package/dist/prosemirror/tableGridMutation.d.ts +20 -0
  218. package/dist/prosemirror/tableGridMutation.js +30 -0
  219. package/dist/prosemirror/trackedRunInlineAtoms.d.ts +31 -0
  220. package/dist/prosemirror/trackedRunInlineAtoms.js +39 -0
  221. package/dist/prosemirror/utils/visualLineNavigation.js +27 -31
  222. package/dist/prosemirror/validation.js +23 -4
  223. package/dist/redline.js +4 -1
  224. package/dist/render-dom/HeaderFooterSelectionOverlay.js +20 -20
  225. package/dist/render-dom/RenderedDomContext.js +17 -34
  226. package/dist/server.d.ts +4 -4
  227. package/dist/server.js +2 -2
  228. package/dist/style-engine/styleEngine.d.ts +1 -1
  229. package/dist/utils/clipboard.js +1 -1
  230. package/dist/utils/findReplace.js +38 -21
  231. package/dist/utils/mergeDocumentContent.js +3 -3
  232. package/dist/utils/replaceText.js +2 -1
  233. package/dist/version-comparison.d.ts +38 -44
  234. package/dist/version-comparison.js +270 -399
  235. package/dist/watermark/index.js +2 -4
  236. package/package.json +8 -2
@@ -6,7 +6,13 @@ import { SpacingExplicit } from "../../types/formatting.js";
6
6
  import { ParagraphDirection } from "../paragraphDirection.js";
7
7
  //#region src/prosemirror/schema/nodes.d.ts
8
8
  type HardBreakAttrs = {
9
- breakType?: "column";
9
+ /** Absent means the source `w:br` omitted `w:type`. */
10
+ breakType?: "column" | "textWrapping";
11
+ clear?: "none" | "left" | "right" | "all";
12
+ };
13
+ /** Attributes preserved from an authored `<w:br w:type="page"/>`. */
14
+ type PageBreakRunAttrs = {
15
+ clear?: "none" | "left" | "right" | "all";
10
16
  };
11
17
  type TabAttrs = {
12
18
  positional?: document_d_exports.PositionalTab;
@@ -32,6 +38,8 @@ type ParagraphAttrs = {
32
38
  paraId?: string;
33
39
  textId?: string;
34
40
  alignment?: document_d_exports.ParagraphAlignment;
41
+ /** Effective inherited alignment beneath any direct `w:jc` override. */
42
+ alignmentFromStyle?: document_d_exports.ParagraphAlignment;
35
43
  /** Effective East Asian line-edge policy (`w:kinsoku`). */
36
44
  kinsoku?: boolean;
37
45
  /** Effective hanging-punctuation policy (`w:overflowPunct`). */
@@ -42,12 +50,17 @@ type ParagraphAttrs = {
42
50
  spaceAfter?: number;
43
51
  lineSpacing?: number;
44
52
  lineSpacingRule?: document_d_exports.LineSpacingRule;
45
- lineSpacingExplicit?: boolean;
53
+ /**
54
+ * Which line-spacing attributes came from this paragraph's own `w:spacing`.
55
+ * `true` is accepted for editor states written before provenance became
56
+ * field-specific; newly created state uses the exact discriminator.
57
+ */
58
+ lineSpacingExplicit?: boolean | "value" | "rule" | "both";
46
59
  snapToGrid?: boolean;
47
60
  spacingExplicit?: SpacingExplicit;
48
61
  /** Layout provenance: document defaults survive on empty paragraphs. */
49
62
  spacingFromDocDefaults?: SpacingExplicit;
50
- /** Layout provenance: implicit default-style spacing survives on empty paragraphs. */
63
+ /** Layout provenance: resolved paragraph/table-style spacing survives on empty paragraphs. */
51
64
  spacingFromImplicitDefaultStyle?: SpacingExplicit;
52
65
  indentLeft?: number;
53
66
  indentRight?: number;
@@ -77,6 +90,8 @@ type ParagraphAttrs = {
77
90
  listIsLegal?: boolean;
78
91
  /** Computed list marker text (e.g., "1.", "1.1.", "•") */
79
92
  listMarker?: string;
93
+ /** Source numbering pattern used to compute markers for inserted list siblings. */
94
+ listMarkerTemplate?: string;
80
95
  /** Whether the list marker is hidden (w:vanish on numbering level rPr) */
81
96
  listMarkerHidden?: boolean;
82
97
  /** Canonical numbering-level marker typography, in OOXML units. */
@@ -205,10 +220,15 @@ type ParagraphAttrs = {
205
220
  * snapshot fields alongside the canonical paragraph formatting fields.
206
221
  * Keeping that shape typed here lets layout consume validated attrs directly.
207
222
  */
208
- type ParagraphPropertyChangeAttrs = Omit<document_d_exports.ParagraphPropertyChange, "previousFormatting" | "currentFormatting"> & {
223
+ type ParagraphPropertyChangeAttrs = Omit<document_d_exports.ParagraphPropertyChange, "info" | "previousFormatting" | "currentFormatting"> & {
224
+ info: document_d_exports.ParagraphPropertyChange["info"] & {
225
+ /** Editor-only proposal provenance; stripped or re-authored before OOXML serialization. */
226
+ provenance?: TrackedChangeProvenance;
227
+ suggestionId?: string | null;
228
+ };
209
229
  previousFormatting?: Omit<document_d_exports.ParagraphFormatting, "numPr"> & {
210
230
  numPr?: document_d_exports.ParagraphFormatting["numPr"] | null;
211
- } & Partial<Pick<ParagraphAttrs, "listIsBullet" | "listIsLegal" | "listNumFmt" | "listMarker" | "listMarkerHidden" | "listMarkerFormatting" | "listMarkerAlignment" | "listMarkerSuffix" | "listLevelNumFmts" | "listLevelStarts" | "listAbstractNumId" | "listStartOverride" | "lineSpacingExplicit" | "direction" | "_autospacingBase">>;
231
+ } & Partial<Pick<ParagraphAttrs, "listIsBullet" | "listIsLegal" | "listNumFmt" | "listMarker" | "listMarkerTemplate" | "listMarkerHidden" | "listMarkerFormatting" | "listMarkerAlignment" | "listMarkerSuffix" | "listMarkerAllCaps" | "listImplicitChildLevelAdvances" | "listMarkerSecondSlotOffsetTwips" | "listLevelNumFmts" | "listLevelStarts" | "listAbstractNumId" | "listStartOverride" | "lineSpacingExplicit" | "direction" | "_autospacingBase">>;
212
232
  currentFormatting?: document_d_exports.ParagraphFormatting;
213
233
  };
214
234
  /**
@@ -622,6 +642,7 @@ type TableRowAttrs = {
622
642
  revisionId: number;
623
643
  author: string;
624
644
  date?: string | null;
645
+ utcDate?: string | null;
625
646
  initials?: string | null;
626
647
  provenance?: TrackedChangeProvenance;
627
648
  suggestionId?: string | null;
@@ -634,6 +655,7 @@ type TableRowAttrs = {
634
655
  revisionId: number;
635
656
  author: string;
636
657
  date?: string | null;
658
+ utcDate?: string | null;
637
659
  initials?: string | null;
638
660
  provenance?: TrackedChangeProvenance;
639
661
  suggestionId?: string | null;
@@ -717,6 +739,7 @@ type TableCellAttrs = {
717
739
  revisionId: number;
718
740
  author: string;
719
741
  date?: string | null;
742
+ utcDate?: string | null;
720
743
  initials?: string | null;
721
744
  /** `"suggested"` marks this as an AI proposal (stripped until accepted). */
722
745
  provenance?: TrackedChangeProvenance;
@@ -733,6 +756,7 @@ type TableCellAttrs = {
733
756
  revisionId: number;
734
757
  author: string;
735
758
  date?: string | null;
759
+ utcDate?: string | null;
736
760
  initials?: string | null;
737
761
  };
738
762
  verticalMerge?: "continue" | "rest";
@@ -744,4 +768,4 @@ type TableCellAttrs = {
744
768
  _docxVMergeContinuationCells?: document_d_exports.TableCell[];
745
769
  };
746
770
  //#endregion
747
- export { BlockSdtAttrs, BookmarkBoundaryAttrs, FieldAttrs, HardBreakAttrs, ImageAttrs, ImagePositionAttrs, MathAttrs, ParagraphAttrs, ParagraphPropertyChangeAttrs, SdtAttrs, ShapeAttrs, SuggestedStructuralMarker, SymbolAttrs, TabAttrs, TableAttrs, TableCellAttrs, TableRowAttrs, TextBoxAnchorAttrs, TextBoxAttrs };
771
+ export { BlockSdtAttrs, BookmarkBoundaryAttrs, FieldAttrs, HardBreakAttrs, ImageAttrs, ImagePositionAttrs, MathAttrs, PageBreakRunAttrs, ParagraphAttrs, ParagraphPropertyChangeAttrs, SdtAttrs, ShapeAttrs, SuggestedStructuralMarker, SymbolAttrs, TabAttrs, TableAttrs, TableCellAttrs, TableRowAttrs, TextBoxAnchorAttrs, TextBoxAttrs };
@@ -1,5 +1,5 @@
1
- import { NumberingMap } from "../../docx/numberingParser.js";
2
1
  import { ResolvedParagraphStyle } from "./styleResolver.js";
2
+ import { NumberingMap } from "../../docx/numberingParser.js";
3
3
  //#region src/prosemirror/styles/resolvedStyleAttrs.d.ts
4
4
  type ResolvedStyleIdentity = {
5
5
  styleId: string;
@@ -31,5 +31,17 @@ declare function paragraphAttrsFromResolvedStyle(resolved: ResolvedParagraphStyl
31
31
  * subsequent save + reload re-derives them from the document content.
32
32
  */
33
33
  declare function listAttrsFromResolvedStyle(resolved: ResolvedParagraphStyle, numbering: NumberingMap | null | undefined): Record<string, unknown> | null;
34
+ /** Project one resolved numbering level into the complete editor attr group. */
35
+ declare function listAttrsFromNumbering(numPr: {
36
+ numId: number;
37
+ ilvl: number;
38
+ }, numbering: NumberingMap | null | undefined): Record<string, unknown>;
39
+ /** Recompute every level-dependent attr when a paragraph changes list level. */
40
+ declare function listLevelAttrPatch(attrs: {
41
+ listImplicitChildLevelAdvances?: number | null;
42
+ }, numPr: {
43
+ numId: number;
44
+ ilvl: number;
45
+ }, numbering: NumberingMap | null | undefined): Record<string, unknown>;
34
46
  //#endregion
35
- export { listAttrsFromResolvedStyle, paragraphAttrsFromResolvedStyle };
47
+ export { listAttrsFromNumbering, listAttrsFromResolvedStyle, listLevelAttrPatch, paragraphAttrsFromResolvedStyle };
@@ -1,6 +1,7 @@
1
- import { computeListRendering } from "../../docx/numberingParser.js";
1
+ import { computeListRendering, numberingLevelHasMarkerSlot } from "../../docx/numberingParser.js";
2
2
  import { tableOfContentsStyleLevel } from "../../utils/tableOfContentsStyle.js";
3
3
  import { setAutospacingBaseValue } from "../autospacingBase.js";
4
+ import { CLEARED_LIST_RENDERING_ATTRS } from "../listMarker.js";
4
5
  //#region src/prosemirror/styles/resolvedStyleAttrs.ts
5
6
  /**
6
7
  * Shared helper for projecting a resolved paragraph style onto ProseMirror
@@ -24,6 +25,7 @@ function paragraphAttrsFromResolvedStyle(resolved, identity) {
24
25
  const hasRunFormatting = !!runFormatting && Object.keys(runFormatting).length > 0;
25
26
  return {
26
27
  alignment: ppr?.alignment ?? null,
28
+ alignmentFromStyle: ppr?.alignment,
27
29
  spaceBefore: ppr?.spaceBefore ?? null,
28
30
  spaceAfter: ppr?.spaceAfter ?? null,
29
31
  lineSpacing: ppr?.lineSpacing ?? null,
@@ -72,42 +74,62 @@ function autospacingBaseFromResolvedParagraphFormatting(ppr) {
72
74
  function listAttrsFromResolvedStyle(resolved, numbering) {
73
75
  const numPr = resolved.paragraphFormatting?.numPr;
74
76
  if (!numPr || numPr.numId === void 0 || numPr.numId === 0) return null;
75
- const rendering = numbering ? computeListRendering(numPr, numbering) : null;
77
+ const attrs = listAttrsFromNumbering({
78
+ numId: numPr.numId,
79
+ ilvl: numPr.ilvl ?? 0
80
+ }, numbering);
76
81
  const level = numbering?.getLevel(numPr.numId, numPr.ilvl ?? 0);
77
- const attrs = {
78
- numPr: {
79
- numId: numPr.numId,
80
- ilvl: numPr.ilvl ?? 0
81
- },
82
- numPrFromStyle: {
83
- numId: numPr.numId,
84
- ilvl: numPr.ilvl ?? 0
85
- },
82
+ attrs["numPrFromStyle"] = {
83
+ numId: numPr.numId,
84
+ ilvl: numPr.ilvl ?? 0
85
+ };
86
+ const ppr = resolved.paragraphFormatting;
87
+ if (level?.pPr) {
88
+ if (ppr?.indentLeft === void 0 && level.pPr.indentLeft !== void 0) attrs["indentLeft"] = level.pPr.indentLeft;
89
+ if (!(ppr?.indentFirstLine !== void 0 || ppr?.hangingIndent !== void 0) && numberingLevelHasMarkerSlot(level)) {
90
+ if (level.pPr.indentFirstLine !== void 0) attrs["indentFirstLine"] = level.pPr.indentFirstLine;
91
+ if (level.pPr.hangingIndent !== void 0) attrs["hangingIndent"] = level.pPr.hangingIndent;
92
+ }
93
+ }
94
+ return attrs;
95
+ }
96
+ /** Project one resolved numbering level into the complete editor attr group. */
97
+ function listAttrsFromNumbering(numPr, numbering) {
98
+ const targetNumPr = {
99
+ numId: numPr.numId,
100
+ ilvl: numPr.ilvl
101
+ };
102
+ const rendering = numbering ? computeListRendering(targetNumPr, numbering) : null;
103
+ return {
104
+ ...CLEARED_LIST_RENDERING_ATTRS,
105
+ numPr: targetNumPr,
86
106
  listNumFmt: rendering?.numFmt ?? null,
87
107
  listIsBullet: rendering?.isBullet ?? null,
88
108
  listIsLegal: rendering?.isLegal ?? null,
89
109
  listMarker: rendering?.marker ?? null,
110
+ listMarkerTemplate: rendering?.markerTemplate ?? null,
90
111
  listMarkerHidden: rendering?.markerHidden ?? null,
91
112
  listMarkerFormatting: rendering?.markerFormatting ?? null,
92
113
  listMarkerAlignment: rendering?.markerAlignment ?? null,
93
114
  listMarkerSuffix: rendering?.markerSuffix ?? null,
94
115
  listMarkerAllCaps: rendering?.markerAllCaps ?? null,
95
- listImplicitChildLevelAdvances: null,
96
- listMarkerSecondSlotOffsetTwips: null,
97
116
  listLevelNumFmts: rendering?.levelNumFmts ?? null,
98
117
  listLevelStarts: rendering?.levelStarts ?? null,
99
118
  listAbstractNumId: rendering?.abstractNumId ?? null,
100
119
  listStartOverride: rendering?.startOverride ?? null
101
120
  };
102
- const ppr = resolved.paragraphFormatting;
103
- if (level?.pPr) {
104
- if (ppr?.indentLeft === void 0 && level.pPr.indentLeft !== void 0) attrs["indentLeft"] = level.pPr.indentLeft;
105
- if (!(ppr?.indentFirstLine !== void 0 || ppr?.hangingIndent !== void 0)) {
106
- if (level.pPr.indentFirstLine !== void 0) attrs["indentFirstLine"] = level.pPr.indentFirstLine;
107
- if (level.pPr.hangingIndent !== void 0) attrs["hangingIndent"] = level.pPr.hangingIndent;
108
- }
109
- }
110
- return attrs;
121
+ }
122
+ /** Recompute every level-dependent attr when a paragraph changes list level. */
123
+ function listLevelAttrPatch(attrs, numPr, numbering) {
124
+ const level = numbering?.getLevel(numPr.numId, numPr.ilvl);
125
+ const hasMarkerSlot = level ? numberingLevelHasMarkerSlot(level) : false;
126
+ return {
127
+ ...listAttrsFromNumbering(numPr, numbering),
128
+ listImplicitChildLevelAdvances: attrs.listImplicitChildLevelAdvances ?? null,
129
+ indentLeft: level?.pPr?.indentLeft ?? null,
130
+ indentFirstLine: hasMarkerSlot ? level?.pPr?.indentFirstLine ?? null : null,
131
+ hangingIndent: hasMarkerSlot ? level?.pPr?.hangingIndent ?? null : null
132
+ };
111
133
  }
112
134
  //#endregion
113
- export { listAttrsFromResolvedStyle, paragraphAttrsFromResolvedStyle };
135
+ export { listAttrsFromNumbering, listAttrsFromResolvedStyle, listLevelAttrPatch, paragraphAttrsFromResolvedStyle };
@@ -10,21 +10,18 @@ type ResolvedParagraphStyle = {
10
10
  runFormatting?: document_d_exports.TextFormatting;
11
11
  };
12
12
  /**
13
- * Paragraph-spacing fields sourced from the table style enclosing a cell
14
- * paragraph: the table style's own `w:pPr`, then the applicable
13
+ * Paragraph fields sourced from the table style enclosing a cell paragraph:
14
+ * the table style's own `w:pPr`, then the applicable
15
15
  * `w:tblStylePr` conditional region's `w:pPr` layered on top (already merged
16
16
  * by the caller — see `resolveTableBaseStyle`/`resolveTableStyleConditional`
17
17
  * in toProseDoc.ts).
18
18
  *
19
- * Deliberately narrower than the full {@link ParagraphFormatting}: this is
20
- * the layer-2 overlay described on {@link StyleResolver.resolveParagraphStyleInTable}
21
- * and is scoped to the spacing fields responsible for folio's table-row
22
- * height bug (table styles like Word's `TableGrid` zero these out relative
23
- * to `docDefaults`). Alignment, indentation, borders, etc. are out of scope
24
- * here — applying the whole `pPr` would risk regressing unrelated cell
25
- * layout that isn't part of this fix.
19
+ * Deliberately narrower than the full {@link ParagraphFormatting}: spacing
20
+ * affects table-row height, while `frame` participates in lossless page-break
21
+ * ownership checks. Other fields remain out of scope until their table-style
22
+ * projection is modeled end to end.
26
23
  */
27
- type TableCellParagraphSpacingOverlay = Pick<document_d_exports.ParagraphFormatting, "spaceBefore" | "spaceAfter" | "lineSpacing" | "lineSpacingRule" | "contextualSpacing">;
24
+ type TableCellParagraphSpacingOverlay = Pick<document_d_exports.ParagraphFormatting, "spaceBefore" | "spaceAfter" | "lineSpacing" | "lineSpacingRule" | "contextualSpacing" | "frame">;
28
25
  /**
29
26
  * StyleResolver provides efficient access to resolved style properties
30
27
  */
@@ -52,7 +49,7 @@ declare class StyleResolver {
52
49
  resolveParagraphStyle(styleId: string | undefined | null): ResolvedParagraphStyle;
53
50
  /**
54
51
  * Resolve paragraph style properties for a paragraph inside a table cell,
55
- * layering the enclosing table style's paragraph-spacing fields into the
52
+ * layering the modeled enclosing-table paragraph fields into the
56
53
  * cascade between docDefaults and the paragraph's own style chain.
57
54
  *
58
55
  * Per ECMA-376 §17.7.2, a cell paragraph's properties resolve in this
@@ -68,10 +65,10 @@ declare class StyleResolver {
68
65
  * paragraph style still wins over the table for any field it sets.
69
66
  *
70
67
  * @param styleId - The paragraph's style ID (e.g., 'Heading1', 'Normal')
71
- * @param tableParagraphOverlay - Paragraph-spacing fields from the
68
+ * @param tableParagraphOverlay - Modeled paragraph fields from the
72
69
  * enclosing table style (base `pPr` merged with the applicable
73
70
  * conditional region), or `undefined` when the paragraph isn't in a
74
- * table cell, the table has no style, or the style sets no spacing.
71
+ * table cell, the table has no style, or the style sets none of them.
75
72
  * @returns Resolved paragraph and run formatting
76
73
  */
77
74
  resolveParagraphStyleInTable(styleId: string | undefined | null, tableParagraphOverlay: TableCellParagraphSpacingOverlay | undefined): ResolvedParagraphStyle;
@@ -74,7 +74,7 @@ var StyleResolver = class {
74
74
  }
75
75
  /**
76
76
  * Resolve paragraph style properties for a paragraph inside a table cell,
77
- * layering the enclosing table style's paragraph-spacing fields into the
77
+ * layering the modeled enclosing-table paragraph fields into the
78
78
  * cascade between docDefaults and the paragraph's own style chain.
79
79
  *
80
80
  * Per ECMA-376 §17.7.2, a cell paragraph's properties resolve in this
@@ -90,10 +90,10 @@ var StyleResolver = class {
90
90
  * paragraph style still wins over the table for any field it sets.
91
91
  *
92
92
  * @param styleId - The paragraph's style ID (e.g., 'Heading1', 'Normal')
93
- * @param tableParagraphOverlay - Paragraph-spacing fields from the
93
+ * @param tableParagraphOverlay - Modeled paragraph fields from the
94
94
  * enclosing table style (base `pPr` merged with the applicable
95
95
  * conditional region), or `undefined` when the paragraph isn't in a
96
- * table cell, the table has no style, or the style sets no spacing.
96
+ * table cell, the table has no style, or the style sets none of them.
97
97
  * @returns Resolved paragraph and run formatting
98
98
  */
99
99
  resolveParagraphStyleInTable(styleId, tableParagraphOverlay) {
@@ -23,6 +23,13 @@ type StyleToggleCascadeOptions = {
23
23
  /** Existing ordinary-property merge whose toggle fields this cascade replaces. */
24
24
  ordinaryFormatting: document_d_exports.TextFormatting | undefined;
25
25
  };
26
+ type CascadeStyleFromResolvedBaseOptions = {
27
+ baseFormatting: document_d_exports.TextFormatting | undefined;
28
+ defaultsActiveProperties: readonly StyleToggleKey[] | undefined;
29
+ styleFormatting: document_d_exports.TextFormatting | undefined;
30
+ };
31
+ /** Continue a style cascade from a compact resolved paragraph snapshot. */
32
+ declare const cascadeStyleFromResolvedBase: ({ baseFormatting, defaultsActiveProperties, styleFormatting }: CascadeStyleFromResolvedBaseOptions) => document_d_exports.TextFormatting | undefined;
26
33
  /**
27
34
  * Resolve run formatting across OOXML style hierarchy levels.
28
35
  *
@@ -34,4 +41,4 @@ type StyleToggleCascadeOptions = {
34
41
  */
35
42
  declare function cascadeStyleTextFormatting(levels: readonly StyleToggleLevel[], options?: StyleToggleCascadeOptions): StyleTextFormattingCascade;
36
43
  //#endregion
37
- export { cascadeStyleTextFormatting };
44
+ export { StyleToggleKey, cascadeStyleFromResolvedBase, cascadeStyleTextFormatting };
@@ -1,5 +1,28 @@
1
1
  import { STYLE_TOGGLE_KEYS, mergeTextFormatting } from "../../utils/textFormattingMerge.js";
2
2
  //#region src/prosemirror/styles/styleToggleCascade.ts
3
+ /** Continue a style cascade from a compact resolved paragraph snapshot. */
4
+ const cascadeStyleFromResolvedBase = ({ baseFormatting, defaultsActiveProperties, styleFormatting }) => {
5
+ const defaultsActive = new Set(defaultsActiveProperties);
6
+ const toggleStates = /* @__PURE__ */ new Map();
7
+ for (const key of STYLE_TOGGLE_KEYS) {
8
+ const value = baseFormatting?.[key];
9
+ if (value !== void 0) toggleStates.set(key, {
10
+ value,
11
+ defaultsActive: defaultsActive.has(key)
12
+ });
13
+ }
14
+ return cascadeStyleTextFormatting([{
15
+ cascade: {
16
+ formatting: baseFormatting,
17
+ toggleStates,
18
+ type: "styleToggleCascade"
19
+ },
20
+ type: "carried"
21
+ }, {
22
+ formatting: styleFormatting,
23
+ type: "style"
24
+ }]).formatting;
25
+ };
3
26
  /**
4
27
  * Resolve run formatting across OOXML style hierarchy levels.
5
28
  *
@@ -49,4 +72,4 @@ function cascadeStyleTextFormatting(levels, options) {
49
72
  };
50
73
  }
51
74
  //#endregion
52
- export { cascadeStyleTextFormatting };
75
+ export { cascadeStyleFromResolvedBase, cascadeStyleTextFormatting };
@@ -0,0 +1,20 @@
1
+ import { Transaction } from "prosemirror-state";
2
+ import { Node } from "prosemirror-model";
3
+ //#region src/prosemirror/tableGridMutation.d.ts
4
+ type ReconcileTableGridAfterColumnRemovalOptions = {
5
+ tr: Transaction;
6
+ tablePosition: number;
7
+ previousTable: Node;
8
+ removedColumn: number;
9
+ };
10
+ /**
11
+ * Keep the editable table grid aligned with a physical column removal.
12
+ *
13
+ * `prosemirror-tables` owns cell topology, but Folio separately retains the
14
+ * authored `w:tblGrid` widths and source XML on the table node. A topology
15
+ * edit that leaves those attrs untouched serializes a new row shape against
16
+ * the old grid; reopening then has to interpret surviving cells as spans.
17
+ */
18
+ declare const reconcileTableGridAfterColumnRemoval: ({ tr, tablePosition, previousTable, removedColumn }: ReconcileTableGridAfterColumnRemovalOptions) => void;
19
+ //#endregion
20
+ export { reconcileTableGridAfterColumnRemoval };
@@ -0,0 +1,30 @@
1
+ import { expectTableAttrs, mergeTableAttrs } from "./attrs/index.js";
2
+ import { TableMap } from "prosemirror-tables";
3
+ //#region src/prosemirror/tableGridMutation.ts
4
+ /**
5
+ * Keep the editable table grid aligned with a physical column removal.
6
+ *
7
+ * `prosemirror-tables` owns cell topology, but Folio separately retains the
8
+ * authored `w:tblGrid` widths and source XML on the table node. A topology
9
+ * edit that leaves those attrs untouched serializes a new row shape against
10
+ * the old grid; reopening then has to interpret surviving cells as spans.
11
+ */
12
+ const reconcileTableGridAfterColumnRemoval = ({ tr, tablePosition, previousTable, removedColumn }) => {
13
+ const previousColumnCount = TableMap.get(previousTable).width;
14
+ const table = tr.doc.nodeAt(tablePosition);
15
+ if (!table || table.type.spec["tableRole"] !== "table") return;
16
+ const columnCount = TableMap.get(table).width;
17
+ if (columnCount >= previousColumnCount) return;
18
+ const removedColumnCount = previousColumnCount - columnCount;
19
+ const previousWidths = expectTableAttrs(previousTable).columnWidths;
20
+ const columnWidths = previousWidths?.length === previousColumnCount ? previousWidths.toSpliced(removedColumn, removedColumnCount) : void 0;
21
+ const formatting = expectTableAttrs(table)._originalFormatting;
22
+ const originalFormatting = formatting ? { ...formatting } : void 0;
23
+ if (originalFormatting) delete originalFormatting.gridSourceXml;
24
+ tr.setNodeMarkup(tablePosition, void 0, mergeTableAttrs(table, {
25
+ columnWidths: columnWidths?.length === columnCount ? columnWidths : void 0,
26
+ _originalFormatting: originalFormatting
27
+ }));
28
+ };
29
+ //#endregion
30
+ export { reconcileTableGridAfterColumnRemoval };
@@ -0,0 +1,31 @@
1
+ import { Node } from "prosemirror-model";
2
+ //#region src/prosemirror/trackedRunInlineAtoms.d.ts
3
+ type TrackedRunInlineAtomDisposition = "carry" | "field-carrier" | "outside-wrapper" | "page-break-carrier" | "text-carrier" | "transparent";
4
+ /**
5
+ * How every inline atom in the editor schema participates in an OOXML
6
+ * run-level tracked-change wrapper.
7
+ *
8
+ * The schema is assembled at runtime, so the fixed-point test binds this map
9
+ * to its complete inline-atom set. The lookup also panics on a missing entry:
10
+ * a new atom cannot silently lose revision ownership before that test runs.
11
+ */
12
+ declare const TRACKED_RUN_INLINE_ATOM_DISPOSITIONS: Readonly<{
13
+ readonly bookmarkBoundary: "carry";
14
+ readonly field: "field-carrier";
15
+ readonly hardBreak: "carry";
16
+ readonly image: "carry";
17
+ readonly math: "outside-wrapper";
18
+ readonly pageBreakRun: "page-break-carrier";
19
+ readonly renderedPageBreak: "transparent";
20
+ readonly shape: "carry";
21
+ readonly structuredField: "carry";
22
+ readonly symbol: "carry";
23
+ readonly tab: "carry";
24
+ readonly text: "text-carrier";
25
+ readonly textBoxAnchor: "carry";
26
+ }>;
27
+ declare const trackedRunInlineAtomDisposition: (node: Node) => TrackedRunInlineAtomDisposition | null;
28
+ /** Whether an editor node can own an insertion/deletion mark as one run carrier. */
29
+ declare const canCarryTrackedRunMark: (node: Node) => boolean;
30
+ //#endregion
31
+ export { TRACKED_RUN_INLINE_ATOM_DISPOSITIONS, TrackedRunInlineAtomDisposition, canCarryTrackedRunMark, trackedRunInlineAtomDisposition };
@@ -0,0 +1,39 @@
1
+ import { panic } from "better-result";
2
+ //#region src/prosemirror/trackedRunInlineAtoms.ts
3
+ /**
4
+ * How every inline atom in the editor schema participates in an OOXML
5
+ * run-level tracked-change wrapper.
6
+ *
7
+ * The schema is assembled at runtime, so the fixed-point test binds this map
8
+ * to its complete inline-atom set. The lookup also panics on a missing entry:
9
+ * a new atom cannot silently lose revision ownership before that test runs.
10
+ */
11
+ const TRACKED_RUN_INLINE_ATOM_DISPOSITIONS = Object.freeze({
12
+ bookmarkBoundary: "carry",
13
+ field: "field-carrier",
14
+ hardBreak: "carry",
15
+ image: "carry",
16
+ math: "outside-wrapper",
17
+ pageBreakRun: "page-break-carrier",
18
+ renderedPageBreak: "transparent",
19
+ shape: "carry",
20
+ structuredField: "carry",
21
+ symbol: "carry",
22
+ tab: "carry",
23
+ text: "text-carrier",
24
+ textBoxAnchor: "carry"
25
+ });
26
+ const dispositionsByName = new Map(Object.entries(TRACKED_RUN_INLINE_ATOM_DISPOSITIONS));
27
+ const trackedRunInlineAtomDisposition = (node) => {
28
+ if (!node.isInline || !node.isAtom) return null;
29
+ const disposition = dispositionsByName.get(node.type.name);
30
+ if (!disposition) panic(`Inline atom ${JSON.stringify(node.type.name)} has no tracked-run disposition`);
31
+ return disposition;
32
+ };
33
+ /** Whether an editor node can own an insertion/deletion mark as one run carrier. */
34
+ const canCarryTrackedRunMark = (node) => {
35
+ const disposition = trackedRunInlineAtomDisposition(node);
36
+ return disposition === "carry" || disposition === "field-carrier" || disposition === "text-carrier" || disposition === "page-break-carrier";
37
+ };
38
+ //#endregion
39
+ export { TRACKED_RUN_INLINE_ATOM_DISPOSITIONS, canCarryTrackedRunMark, trackedRunInlineAtomDisposition };
@@ -1,3 +1,5 @@
1
+ import { findBodyEmptyRuns, findBodyPmSpans } from "../../layout-bridge/dom/findBodyPmSpans.js";
2
+ import { createTextStreamRange, descendantTextNodes, totalTextLength } from "../../layout-bridge/dom/textStreamDom.js";
1
3
  import { findVerticalScrollParent } from "../../utils/findVerticalScrollParent.js";
2
4
  import { TextSelection } from "prosemirror-state";
3
5
  //#region src/prosemirror/utils/visualLineNavigation.ts
@@ -33,28 +35,21 @@ function scrollIntoViewIfNeeded(el) {
33
35
  }
34
36
  /** @internal */
35
37
  function getCaretClientX(container, pmPos) {
36
- const spans = container.querySelectorAll("span[data-pm-start][data-pm-end]");
37
- for (const span of Array.from(spans)) {
38
- const spanEl = span;
38
+ for (const spanEl of findBodyPmSpans(container)) {
39
39
  const pmStart = Number(spanEl.dataset["pmStart"]);
40
40
  const pmEnd = Number(spanEl.dataset["pmEnd"]);
41
41
  if (spanEl.classList.contains("layout-run-tab")) {
42
42
  if (pmPos >= pmStart && pmPos < pmEnd) return spanEl.getBoundingClientRect().left;
43
43
  continue;
44
44
  }
45
- if (pmPos >= pmStart && pmPos <= pmEnd && span.firstChild?.nodeType === Node.TEXT_NODE) {
46
- const textNode = span.firstChild;
47
- const charIndex = Math.min(pmPos - pmStart, textNode.length);
48
- const ownerDoc = spanEl.ownerDocument;
49
- if (!ownerDoc) continue;
50
- const range = ownerDoc.createRange();
51
- range.setStart(textNode, charIndex);
52
- range.setEnd(textNode, charIndex);
53
- return range.getBoundingClientRect().left;
45
+ if (pmPos >= pmStart && pmPos <= pmEnd) {
46
+ const textNodes = descendantTextNodes(spanEl);
47
+ const charIndex = Math.min(pmPos - pmStart, totalTextLength(textNodes));
48
+ const range = createTextStreamRange(spanEl, charIndex, charIndex);
49
+ if (range) return range.getBoundingClientRect().left;
54
50
  }
55
51
  }
56
- const emptyRuns = container.querySelectorAll(".layout-empty-run");
57
- for (const emptyRun of Array.from(emptyRuns)) {
52
+ for (const emptyRun of findBodyEmptyRuns(container)) {
58
53
  const paragraph = emptyRun.closest(".layout-paragraph");
59
54
  if (!paragraph) continue;
60
55
  const pmStart = Number(paragraph.dataset["pmStart"]);
@@ -91,6 +86,13 @@ function findLineElementAtPosition(container, pmPos) {
91
86
  /** @internal */
92
87
  function findPositionOnLineAtClientX(lineEl, clientX) {
93
88
  const spans = lineEl.querySelectorAll("span[data-pm-start][data-pm-end]");
89
+ const emptyRun = lineEl.querySelector(".layout-empty-run");
90
+ if (emptyRun) {
91
+ const emptyRunStart = emptyRun.dataset["pmStart"];
92
+ if (emptyRunStart !== void 0) return Number(emptyRunStart);
93
+ const paragraphStart = emptyRun.closest(".layout-paragraph")?.dataset["pmStart"];
94
+ return paragraphStart === void 0 ? null : Number(paragraphStart) + 1;
95
+ }
94
96
  if (spans.length === 0) {
95
97
  const paragraph = lineEl.closest(".layout-paragraph");
96
98
  if (paragraph?.dataset["pmStart"]) return Number(paragraph.dataset["pmStart"]) + 1;
@@ -106,29 +108,23 @@ function findPositionOnLineAtClientX(lineEl, clientX) {
106
108
  continue;
107
109
  }
108
110
  if (clientX >= rect.left && clientX <= rect.right) {
109
- const textNode = spanEl.firstChild;
110
- if (!textNode || textNode.nodeType !== Node.TEXT_NODE) return pmStart;
111
- const text = textNode;
112
- const ownerDoc = spanEl.ownerDocument;
113
- if (!ownerDoc) return pmStart;
111
+ const textLength = totalTextLength(descendantTextNodes(spanEl));
112
+ if (textLength === 0) return pmStart;
114
113
  let lo = 0;
115
- let hi = text.length;
114
+ let hi = textLength;
116
115
  while (lo < hi) {
117
116
  const mid = Math.floor((lo + hi) / 2);
118
- const r = ownerDoc.createRange();
119
- r.setStart(text, mid);
120
- r.setEnd(text, mid);
117
+ const r = createTextStreamRange(spanEl, mid, mid);
118
+ if (!r) return pmStart;
121
119
  if (clientX < r.getBoundingClientRect().left) hi = mid;
122
120
  else lo = mid + 1;
123
121
  }
124
- if (lo > 0 && lo <= text.length) {
125
- const r = ownerDoc.createRange();
126
- r.setStart(text, lo - 1);
127
- r.setEnd(text, lo - 1);
128
- const leftX = r.getBoundingClientRect().left;
129
- r.setStart(text, Math.min(lo, text.length));
130
- r.setEnd(text, Math.min(lo, text.length));
131
- const rightX = r.getBoundingClientRect().left;
122
+ if (lo > 0 && lo <= textLength) {
123
+ const left = createTextStreamRange(spanEl, lo - 1, lo - 1);
124
+ const right = createTextStreamRange(spanEl, Math.min(lo, textLength), Math.min(lo, textLength));
125
+ if (!left || !right) return pmStart;
126
+ const leftX = left.getBoundingClientRect().left;
127
+ const rightX = right.getBoundingClientRect().left;
132
128
  if (Math.abs(clientX - leftX) < Math.abs(clientX - rightX)) return pmStart + (lo - 1);
133
129
  }
134
130
  return pmStart + Math.min(lo, pmEnd - pmStart);