@stll/folio-core 0.47.7 → 0.49.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 (213) hide show
  1. package/dist/ai-edits/apply.js +565 -121
  2. package/dist/ai-edits/minimal-replacement.d.ts +64 -0
  3. package/dist/ai-edits/minimal-replacement.js +282 -0
  4. package/dist/controller/fontReadiness.js +3 -3
  5. package/dist/controller/hyphenationReadiness.d.ts +19 -0
  6. package/dist/controller/hyphenationReadiness.js +47 -0
  7. package/dist/controller/layoutPipeline.d.ts +3 -0
  8. package/dist/controller/layoutPipeline.js +70 -18
  9. package/dist/display-list/build/buildDisplayList.js +39 -12
  10. package/dist/display-list/build/pageFurniture.d.ts +7 -1
  11. package/dist/display-list/build/pageFurniture.js +21 -8
  12. package/dist/display-list/build/paragraphPrimitives.js +68 -11
  13. package/dist/display-list/build/tablePrimitives.js +10 -6
  14. package/dist/display-list/build/textBoxPrimitives.js +1 -1
  15. package/dist/display-list/build/unsupported.d.ts +2 -2
  16. package/dist/display-list/build/unsupported.js +0 -0
  17. package/dist/display-list/dom/renderDisplayListToDom.js +0 -1
  18. package/dist/docx/attributeRemainder.js +10 -2
  19. package/dist/docx/blockContentParser.d.ts +2 -0
  20. package/dist/docx/blockContentParser.js +79 -64
  21. package/dist/docx/bulletMarkers.d.ts +18 -2
  22. package/dist/docx/bulletMarkers.js +27 -2
  23. package/dist/docx/commentParser.d.ts +2 -1
  24. package/dist/docx/commentParser.js +57 -45
  25. package/dist/docx/containerChildren.d.ts +21 -8
  26. package/dist/docx/containerChildren.js +39 -9
  27. package/dist/docx/documentParser.d.ts +5 -1
  28. package/dist/docx/documentParser.js +8 -5
  29. package/dist/docx/documentSectionFacts.d.ts +22 -0
  30. package/dist/docx/documentSectionFacts.js +43 -0
  31. package/dist/docx/drawingGroupChildren.d.ts +60 -0
  32. package/dist/docx/drawingGroupChildren.js +176 -0
  33. package/dist/docx/drawingUtils.js +3 -0
  34. package/dist/docx/fieldParser.d.ts +8 -1
  35. package/dist/docx/fieldParser.js +47 -3
  36. package/dist/docx/fontTableParser.js +34 -27
  37. package/dist/docx/footnoteParser.d.ts +3 -2
  38. package/dist/docx/footnoteParser.js +15 -12
  39. package/dist/docx/groupDrawingParser.d.ts +9 -2
  40. package/dist/docx/groupDrawingParser.js +125 -37
  41. package/dist/docx/headerFooterParser.d.ts +7 -2
  42. package/dist/docx/headerFooterParser.js +15 -5
  43. package/dist/docx/hyperlinkParser.d.ts +48 -36
  44. package/dist/docx/hyperlinkParser.js +97 -82
  45. package/dist/docx/numberingParser.js +108 -84
  46. package/dist/docx/packageParts.d.ts +45 -1
  47. package/dist/docx/packageParts.js +93 -2
  48. package/dist/docx/paraIdAttribute.d.ts +3 -2
  49. package/dist/docx/paragraphParser.d.ts +5 -1
  50. package/dist/docx/paragraphParser.js +468 -365
  51. package/dist/docx/paragraphProperties.js +123 -109
  52. package/dist/docx/paragraphPropertySource.d.ts +6 -1
  53. package/dist/docx/paragraphPropertySource.js +9 -1
  54. package/dist/docx/paragraphTextBoxEnrichment.d.ts +2 -1
  55. package/dist/docx/paragraphTextBoxEnrichment.js +143 -10
  56. package/dist/docx/parser.d.ts +7 -1
  57. package/dist/docx/parser.js +33 -16
  58. package/dist/docx/previewBudget.d.ts +55 -33
  59. package/dist/docx/previewBudget.js +59 -65
  60. package/dist/docx/rezip.js +41 -58
  61. package/dist/docx/runParser.d.ts +4 -1
  62. package/dist/docx/runParser.js +182 -184
  63. package/dist/docx/sdtProperties.js +87 -84
  64. package/dist/docx/sectionParser.js +169 -160
  65. package/dist/docx/selectiveSaveFlags.d.ts +10 -3
  66. package/dist/docx/selectiveSaveFlags.js +1 -1
  67. package/dist/docx/selectiveXmlPatch.d.ts +56 -34
  68. package/dist/docx/selectiveXmlPatch.js +222 -115
  69. package/dist/docx/serializer/groupTextBoxWriteBack.d.ts +12 -0
  70. package/dist/docx/serializer/groupTextBoxWriteBack.js +101 -0
  71. package/dist/docx/serializer/paragraphSerializer.js +47 -42
  72. package/dist/docx/serializer/runSerializer.d.ts +5 -1
  73. package/dist/docx/serializer/runSerializer.js +4 -3
  74. package/dist/docx/serializer/settingsSerializer.js +19 -1
  75. package/dist/docx/settingsParser.js +8 -0
  76. package/dist/docx/shapeAlternateContent.d.ts +25 -0
  77. package/dist/docx/shapeAlternateContent.js +52 -0
  78. package/dist/docx/streamingXmlParser.d.ts +6 -2
  79. package/dist/docx/streamingXmlParser.js +12 -7
  80. package/dist/docx/styleParser.js +34 -8
  81. package/dist/docx/tableParser.d.ts +21 -12
  82. package/dist/docx/tableParser.js +518 -441
  83. package/dist/docx/textBoxParser.d.ts +18 -5
  84. package/dist/docx/textBoxParser.js +12 -6
  85. package/dist/docx/verbatimCapture.d.ts +10 -8
  86. package/dist/docx/verbatimCapture.js +45 -2
  87. package/dist/docx/vmlImageParser.d.ts +15 -13
  88. package/dist/docx/vmlImageParser.js +75 -60
  89. package/dist/docx/vmlPreview.d.ts +3 -3
  90. package/dist/docx/vmlPreview.js +3 -4
  91. package/dist/docx/xmlNamespaceContext.d.ts +9 -0
  92. package/dist/docx/xmlNamespaceContext.js +54 -0
  93. package/dist/docx/xmlParser.d.ts +6 -3
  94. package/dist/docx/xmlParser.js +11 -41
  95. package/dist/docx/xmlResourceLimits.d.ts +2 -1
  96. package/dist/docx/xmlResourceLimits.js +4 -1
  97. package/dist/fonts/headlessMeasure.js +0 -0
  98. package/dist/headless-layout.d.ts +11 -2
  99. package/dist/headless-layout.js +153 -107
  100. package/dist/internal/headlessRevisionResolution.js +50 -13
  101. package/dist/internal/paragraphFormattingSerialization.js +3 -3
  102. package/dist/layout-bridge/convert/endnoteLayout.d.ts +65 -0
  103. package/dist/layout-bridge/convert/endnoteLayout.js +227 -0
  104. package/dist/layout-bridge/convert/footnoteLayout.d.ts +19 -3
  105. package/dist/layout-bridge/convert/footnoteLayout.js +40 -31
  106. package/dist/layout-bridge/convert/headerFooterLayout.d.ts +1 -7
  107. package/dist/layout-bridge/convert/headerFooterLayout.js +5 -20
  108. package/dist/layout-bridge/convert/paragraphMarkFormatting.d.ts +10 -0
  109. package/dist/layout-bridge/convert/paragraphMarkFormatting.js +59 -0
  110. package/dist/layout-bridge/convert/toFlowBlocks.d.ts +29 -1
  111. package/dist/layout-bridge/convert/toFlowBlocks.js +284 -39
  112. package/dist/layout-bridge/engine/hitTest.js +5 -3
  113. package/dist/layout-bridge/engine/selectionRects.js +5 -3
  114. package/dist/layout-engine/anchorLayoutInCellCompatibility.d.ts +10 -0
  115. package/dist/layout-engine/anchorLayoutInCellCompatibility.js +22 -0
  116. package/dist/layout-engine/index.d.ts +2 -2
  117. package/dist/layout-engine/index.js +102 -14
  118. package/dist/layout-engine/justificationCompatibility.d.ts +1 -1
  119. package/dist/layout-engine/justificationCompatibility.js +9 -5
  120. package/dist/layout-engine/keep-together.d.ts +15 -6
  121. package/dist/layout-engine/keep-together.js +43 -16
  122. package/dist/layout-engine/layoutInstrumentation.d.ts +8 -2
  123. package/dist/layout-engine/layoutInstrumentation.js +8 -1
  124. package/dist/layout-engine/measure/advanceComposition.js +50 -7
  125. package/dist/layout-engine/measure/hyphenationDictionaries.d.ts +74 -0
  126. package/dist/layout-engine/measure/hyphenationDictionaries.js +138 -0
  127. package/dist/layout-engine/measure/hyphenationPreload.d.ts +11 -0
  128. package/dist/layout-engine/measure/hyphenationPreload.js +24 -0
  129. package/dist/layout-engine/measure/lineBreakProvider.d.ts +12 -2
  130. package/dist/layout-engine/measure/lineBreakProvider.js +30 -30
  131. package/dist/layout-engine/measure/lineBreaks.d.ts +6 -1
  132. package/dist/layout-engine/measure/lineBreaks.js +10 -3
  133. package/dist/layout-engine/measure/listMarkerWidth.d.ts +9 -6
  134. package/dist/layout-engine/measure/listMarkerWidth.js +20 -22
  135. package/dist/layout-engine/measure/measureBlocks.js +46 -10
  136. package/dist/layout-engine/measure/measureContainer.js +51 -8
  137. package/dist/layout-engine/measure/measureHelpers.d.ts +15 -3
  138. package/dist/layout-engine/measure/measureHelpers.js +34 -8
  139. package/dist/layout-engine/measure/measureParagraph.js +143 -101
  140. package/dist/layout-engine/measure/measureTypes.d.ts +5 -0
  141. package/dist/layout-engine/measure/smallCapsCasing.d.ts +56 -0
  142. package/dist/layout-engine/measure/smallCapsCasing.js +88 -0
  143. package/dist/layout-engine/measure/tabCalculator.d.ts +2 -0
  144. package/dist/layout-engine/measure/tabCalculator.js +2 -1
  145. package/dist/layout-engine/measure/tableCellFloating.d.ts +2 -0
  146. package/dist/layout-engine/measure/tableCellFloating.js +51 -19
  147. package/dist/layout-engine/measure/tableCellGrid.d.ts +28 -3
  148. package/dist/layout-engine/measure/tableCellGrid.js +45 -5
  149. package/dist/layout-engine/measure/tableFragmentBorderGeometry.js +2 -1
  150. package/dist/layout-engine/noteAreaFlow.d.ts +19 -0
  151. package/dist/layout-engine/noteAreaFlow.js +83 -0
  152. package/dist/layout-engine/paginator.d.ts +12 -1
  153. package/dist/layout-engine/paginator.js +18 -2
  154. package/dist/layout-engine/paragraphSpacing.d.ts +4 -2
  155. package/dist/layout-engine/paragraphSpacing.js +2 -1
  156. package/dist/layout-engine/tableRowBreak.d.ts +8 -1
  157. package/dist/layout-engine/tableRowBreak.js +25 -2
  158. package/dist/layout-engine/types.d.ts +108 -3
  159. package/dist/layout-engine/types.js +96 -1
  160. package/dist/layout-painter/index.d.ts +3 -0
  161. package/dist/layout-painter/renderPage.js +32 -83
  162. package/dist/layout-painter/renderParagraph.d.ts +6 -1
  163. package/dist/layout-painter/renderParagraph.js +75 -26
  164. package/dist/layout-painter/renderTable.js +26 -13
  165. package/dist/layout-painter/renderTextBox.d.ts +12 -2
  166. package/dist/layout-painter/renderTextBox.js +26 -2
  167. package/dist/prosemirror/alternateContentAttrs.d.ts +9 -0
  168. package/dist/prosemirror/alternateContentAttrs.js +35 -0
  169. package/dist/prosemirror/attrs/index.d.ts +9 -9
  170. package/dist/prosemirror/attrs/index.js +133 -11
  171. package/dist/prosemirror/commands/comments.js +51 -41
  172. package/dist/prosemirror/contentControlRevisions.d.ts +43 -0
  173. package/dist/prosemirror/contentControlRevisions.js +84 -0
  174. package/dist/prosemirror/conversion/fromProseDoc.js +54 -23
  175. package/dist/prosemirror/conversion/markInterner.d.ts +21 -0
  176. package/dist/prosemirror/conversion/markInterner.js +90 -0
  177. package/dist/prosemirror/conversion/toProseDoc.js +117 -58
  178. package/dist/prosemirror/extensions/core/DocExtension.js +2 -1
  179. package/dist/prosemirror/extensions/core/ParagraphExtension.js +1 -0
  180. package/dist/prosemirror/extensions/features/AutoBidiDetectionExtension.d.ts +7 -7
  181. package/dist/prosemirror/extensions/features/AutoBidiDetectionExtension.js +7 -7
  182. package/dist/prosemirror/extensions/marks/markUtils.d.ts +6 -2
  183. package/dist/prosemirror/extensions/marks/markUtils.js +39 -51
  184. package/dist/prosemirror/extensions/nodes/FieldExtension.js +6 -3
  185. package/dist/prosemirror/extensions/nodes/SdtExtension.js +9 -2
  186. package/dist/prosemirror/extensions/nodes/ShapeExtension.js +1 -0
  187. package/dist/prosemirror/extensions/nodes/TextBoxExtension.js +5 -1
  188. package/dist/prosemirror/listMarker.d.ts +1 -0
  189. package/dist/prosemirror/listMarker.js +4 -2
  190. package/dist/prosemirror/listRenderingAttrs.d.ts +1 -0
  191. package/dist/prosemirror/listRenderingAttrs.js +3 -0
  192. package/dist/prosemirror/paragraphDirection.d.ts +29 -2
  193. package/dist/prosemirror/paragraphDirection.js +21 -2
  194. package/dist/prosemirror/plugins/suggestionMode.js +37 -8
  195. package/dist/prosemirror/rejoinRunCarriers.d.ts +27 -0
  196. package/dist/prosemirror/rejoinRunCarriers.js +66 -0
  197. package/dist/prosemirror/runIdentityAcrossRevisions.d.ts +10 -0
  198. package/dist/prosemirror/runIdentityAcrossRevisions.js +90 -0
  199. package/dist/prosemirror/schema/nodes.d.ts +50 -6
  200. package/dist/prosemirror/textBoxHostParagraph.d.ts +13 -0
  201. package/dist/prosemirror/textBoxHostParagraph.js +21 -0
  202. package/dist/prosemirror/validation.js +91 -80
  203. package/dist/types/content.d.ts +2 -2
  204. package/dist/utils/createDocument.js +10 -1
  205. package/dist/utils/scriptSegments.d.ts +33 -4
  206. package/dist/utils/scriptSegments.js +39 -6
  207. package/dist/utils/textFormattingMerge.d.ts +17 -3
  208. package/dist/utils/textFormattingMerge.js +18 -12
  209. package/dist/utils/trailingText.d.ts +22 -0
  210. package/dist/utils/trailingText.js +32 -0
  211. package/package.json +2 -2
  212. package/dist/layout-engine/justifiedLineFit.d.ts +0 -7
  213. package/dist/layout-engine/justifiedLineFit.js +0 -6
@@ -0,0 +1,90 @@
1
+ import { expectRunIdentityMarkAttrs } from "./attrs/index.js";
2
+ import "./extensions/nodes/SdtExtension.js";
3
+ import { RUN_IDENTITY_MARK_NAME } from "./runIdentity.js";
4
+ import { Fragment, Mark } from "prosemirror-model";
5
+ //#region src/prosemirror/runIdentityAcrossRevisions.ts
6
+ /**
7
+ * One run identity for the pieces of a `w:r` a tracked change cut.
8
+ *
9
+ * A revision inside a run splits it: `<w:r a>Sel</w:r><w:del><w:r a>ler</w:r></w:del>`,
10
+ * `<w:r a>Sel</w:r><w:ins>…</w:ins><w:r a>ler</w:r>`, or a `w:rPrChange` on
11
+ * one piece of the run only. Read back, each
12
+ * `w:r` is its own authored run, so resolving the revision would leave two
13
+ * runs where the source had one. The package cannot say whether the two were
14
+ * one run, but runs that carry the same attributes and that only revised
15
+ * content holds apart are what such a cut writes, so the later piece takes the
16
+ * earlier one's identity. The pieces stay separate runs while the revision
17
+ * holds them apart, and become one run once it is resolved and they state the
18
+ * same properties again (a run joins its owner only then, see `fromProseDoc`).
19
+ *
20
+ * Runs the package writes side by side under the same revision state keep
21
+ * their own identities.
22
+ */
23
+ const REVISION_MARK_NAMES = /* @__PURE__ */ new Set([
24
+ "insertion",
25
+ "deletion",
26
+ "runPropertyChange"
27
+ ]);
28
+ const identityOf = (node) => node.marks.find((mark) => mark.type.name === RUN_IDENTITY_MARK_NAME);
29
+ const revisionMarksOf = (node) => node.marks.filter((mark) => REVISION_MARK_NAMES.has(mark.type.name));
30
+ /** The identity's attrs without the id: what the run carries. */
31
+ const payloadKey = (identity) => JSON.stringify({
32
+ ...expectRunIdentityMarkAttrs(identity),
33
+ id: 0
34
+ });
35
+ /** Whether `right` continues `left`'s run across a revision boundary. */
36
+ const continuesRun = ({ left, right, bridged }) => {
37
+ const leftIdentity = identityOf(left);
38
+ const rightIdentity = identityOf(right);
39
+ if (!leftIdentity || !rightIdentity || leftIdentity.eq(rightIdentity)) return false;
40
+ return (bridged || !Mark.sameSet(revisionMarksOf(left), revisionMarksOf(right))) && payloadKey(leftIdentity) === payloadKey(rightIdentity);
41
+ };
42
+ /**
43
+ * `nodes`, one inline container's content, with each run a revision cut given
44
+ * the identity of the run it was cut from. A control is a container of its
45
+ * own. `nodes` itself comes back when nothing changes.
46
+ */
47
+ const continueRunIdentitiesAcrossRevisions = (nodes) => {
48
+ const renamed = /* @__PURE__ */ new Map();
49
+ /** The last run with an identity, while only revised content follows it. */
50
+ let anchor;
51
+ let bridged = false;
52
+ let changed = false;
53
+ const result = nodes.map((node) => {
54
+ if (node.type.name === "sdt") {
55
+ anchor = void 0;
56
+ const children = [];
57
+ node.forEach((child) => {
58
+ children.push(child);
59
+ });
60
+ const continued = continueRunIdentitiesAcrossRevisions(children);
61
+ if (continued === children) return node;
62
+ changed = true;
63
+ return node.copy(Fragment.fromArray([...continued]));
64
+ }
65
+ const identity = identityOf(node);
66
+ if (!identity) {
67
+ if (anchor && revisionMarksOf(node).length > 0) bridged = true;
68
+ else anchor = void 0;
69
+ return node;
70
+ }
71
+ const id = expectRunIdentityMarkAttrs(identity).id;
72
+ let replacement = renamed.get(id);
73
+ if (!replacement && anchor && continuesRun({
74
+ left: anchor,
75
+ right: node,
76
+ bridged
77
+ })) {
78
+ replacement = identityOf(anchor);
79
+ if (replacement) renamed.set(id, replacement);
80
+ }
81
+ const next = replacement ? node.mark(replacement.addToSet(node.marks)) : node;
82
+ changed ||= next !== node;
83
+ anchor = next;
84
+ bridged = false;
85
+ return next;
86
+ });
87
+ return changed ? result : nodes;
88
+ };
89
+ //#endregion
90
+ export { continueRunIdentitiesAcrossRevisions };
@@ -167,6 +167,8 @@ type ParagraphAttrs = {
167
167
  listLevelNumFmts?: document_d_exports.CounterFormat[];
168
168
  /** Initial counter for each level used by multi-level marker templates. */
169
169
  listLevelStarts?: number[];
170
+ /** Custom tab stops of the numbering level (`w:lvl/w:pPr/w:tabs`). */
171
+ listLevelTabs?: document_d_exports.TabStop[];
170
172
  /** Abstract numbering ID shared by numbering instances. */
171
173
  listAbstractNumId?: number;
172
174
  /** Numbering start override for this numId/level. */
@@ -200,10 +202,12 @@ type ParagraphAttrs = {
200
202
  /** Internal table-style run overlay, used to resolve body-run provenance. */
201
203
  _tableRunFormatting?: document_d_exports.TextFormatting;
202
204
  /**
203
- * Base text direction as a discriminated union (undecided when absent). Maps
204
- * to the serialized OOXML `w:bidi` tri-state via `directionToBidi`; the
205
- * `source` discriminates an authoritative manual/import decision from a
206
- * re-evaluable auto-detected one. See `paragraphDirection.ts`.
205
+ * Base text direction as a discriminated union (undecided when absent).
206
+ * Maps to the OOXML `w:bidi` tri-state via `directionToBidi` (layout) or
207
+ * `directionToAuthoredBidi` (serialization); the `source` discriminates an
208
+ * authoritative manual/import decision — the only one that is ever
209
+ * serialized — from a re-evaluable, view-only auto-detected one. See
210
+ * `paragraphDirection.ts`.
207
211
  */
208
212
  direction?: ParagraphDirection | null;
209
213
  /** The stated `w:outlineLvl`, style-resolved: a heading level or body text. */
@@ -325,7 +329,7 @@ type ParagraphPropertyChangeAttrs = Omit<document_d_exports.ParagraphPropertyCha
325
329
  };
326
330
  previousFormatting?: Omit<document_d_exports.ParagraphFormatting, "numPr"> & {
327
331
  numPr?: ParagraphAttrs["numPr"] | null;
328
- } & Partial<Pick<ParagraphAttrs, "listIsBullet" | "listIsLegal" | "listNumFmt" | "listMarker" | "listMarkerTemplate" | "listMarkerHidden" | "listMarkerFormatting" | "listMarkerAlignment" | "listMarkerSuffix" | "listMarkerAllCaps" | "listImplicitChildLevelAdvances" | "listMarkerSecondSlotOffsetTwips" | "listLevelNumFmts" | "listLevelStarts" | "listAbstractNumId" | "listStartOverride" | "lineSpacingExplicit" | "direction" | "_autospacingBase">>;
332
+ } & Partial<Pick<ParagraphAttrs, "listIsBullet" | "listIsLegal" | "listNumFmt" | "listMarker" | "listMarkerTemplate" | "listMarkerHidden" | "listMarkerFormatting" | "listMarkerAlignment" | "listMarkerSuffix" | "listMarkerAllCaps" | "listImplicitChildLevelAdvances" | "listMarkerSecondSlotOffsetTwips" | "listLevelNumFmts" | "listLevelStarts" | "listLevelTabs" | "listAbstractNumId" | "listStartOverride" | "lineSpacingExplicit" | "direction" | "_autospacingBase">>;
329
333
  currentFormatting?: document_d_exports.ParagraphFormatting;
330
334
  };
331
335
  /**
@@ -537,6 +541,13 @@ type FieldAttrs = {
537
541
  fldLock?: boolean;
538
542
  /** Field is dirty and should be recalculated by the host application */
539
543
  dirty?: boolean;
544
+ /**
545
+ * `displayText` is a rendering fallback folio synthesized (e.g. a legacy
546
+ * `FORMCHECKBOX` with no cached result run), not authored content. A save
547
+ * omits it from the field's result so an unedited field keeps its
548
+ * original, resultless bytes. See `ComplexField.fieldResultIsFallback`.
549
+ */
550
+ fieldResultIsFallback?: boolean;
540
551
  };
541
552
  /**
542
553
  * Math equation node attributes
@@ -638,10 +649,21 @@ type BlockSdtAttrs = {
638
649
  /** Verbatim XML for sdt siblings after sdtContent (range markers). */
639
650
  rawSdtChildrenAfterContent?: string;
640
651
  };
652
+ /**
653
+ * The `mc:AlternateContent` a shape or text box was read from, with a
654
+ * fingerprint of the node it was attached to. `fromProseDoc` hands the element
655
+ * back to the model only while the node still matches the fingerprint.
656
+ */
657
+ type AlternateContentAttrs = {
658
+ xml: string;
659
+ fingerprint: string;
660
+ };
641
661
  /**
642
662
  * Shape node attributes
643
663
  */
644
664
  type ShapeAttrs = {
665
+ /** The source `mc:AlternateContent`; see {@link AlternateContentAttrs}. */
666
+ _docxAlternateContent?: AlternateContentAttrs;
645
667
  /** Shape type preset */
646
668
  shapeType?: string;
647
669
  /** Preset geometry adjustments serialized as JSON. */
@@ -781,6 +803,11 @@ type TextBoxAttrs = {
781
803
  title?: string;
782
804
  /** Fill color as CSS color */
783
805
  fillColor?: string;
806
+ /**
807
+ * The authored gradient fill, carried whole: `fillColor` cannot state a
808
+ * gradient, so the box paints and saves from this instead.
809
+ */
810
+ gradientFill?: document_d_exports.ShapeFill;
784
811
  /** Outline width in pixels */
785
812
  outlineWidth?: number;
786
813
  /** Outline color as CSS color */
@@ -839,12 +866,19 @@ type TextBoxAttrs = {
839
866
  wrapEffectExtentSlots?: document_d_exports.EffectExtentSlots;
840
867
  /** `wp:wrapPolygon` as authored, in the path's own units. */
841
868
  wrapPolygon?: document_d_exports.ImageWrapPolygon;
869
+ /** The source `mc:AlternateContent`; see {@link AlternateContentAttrs}. */
870
+ _docxAlternateContent?: AlternateContentAttrs;
842
871
  /** Original DOCX placement hint for save-path reconstruction. */
843
872
  _docxPlacement?: "standalone" | "inlineWithPrevious";
844
873
  /** Original DOCX paragraph group for standalone text-box reconstruction. */
845
874
  _docxGroupId?: string;
846
875
  /** Inline anchor linking this block node to its source run position. */
847
876
  _docxAnchorId?: string;
877
+ /**
878
+ * The DrawingML group child this text box was read from; the writer puts its
879
+ * text back into the group rather than writing a drawing of its own.
880
+ */
881
+ _docxGroupChild?: document_d_exports.DrawingGroupChild;
848
882
  /**
849
883
  * Ownership of the schema-required placeholder paragraph. A source text
850
884
  * body with no children needs one paragraph while it is editable, but that
@@ -878,6 +912,16 @@ type TextBoxAttrs = {
878
912
  * itself and keeps its own.
879
913
  */
880
914
  _preservedAttributes?: document_d_exports.PreservedAttribute[];
915
+ /**
916
+ * The paragraph properties of the `w:p` this node was lifted out of.
917
+ *
918
+ * An inline drawing is run content of its paragraph, so that paragraph's
919
+ * spacing, indentation and alignment still place the box and must be
920
+ * written back around it. Only a `"standalone"` placement has a host to
921
+ * speak for. The host's identity (`paraId`, source token, attribute
922
+ * remainder) is not carried here: a copied node must not duplicate it.
923
+ */
924
+ _docxHostParagraph?: Omit<ParagraphAttrs, "paraId" | "textId" | "_preservedAttributes">;
881
925
  };
882
926
  /** Internal inline position marker for an extracted text box block. */
883
927
  type TextBoxAnchorAttrs = {
@@ -1181,4 +1225,4 @@ type TableCellAttrs = {
1181
1225
  _docxVMergeContinuationCells?: unknown;
1182
1226
  };
1183
1227
  //#endregion
1184
- export { AuthoredEmuAttrs, BlockSdtAttrs, BookmarkBoundaryAttrs, CommentReferenceAttrs, FieldAttrs, HardBreakAttrs, ImageAttrs, ImagePositionAttrs, MathAttrs, PRESERVED_XML_LEVELS, PageBreakRunAttrs, ParagraphAttrs, ParagraphAttrsPatch, ParagraphPropertyChangeAttrs, PreservedBlockAttrs, PreservedXmlAttrs, PreservedXmlLevel, SdtAttrs, ShapeAttrs, SuggestedStructuralMarker, SymbolAttrs, TEXT_BOX_TEXT_BODY_CONTENT_STATE_TYPES, TabAttrs, TableAttrs, TableCellAttrs, TableRowAttrs, TextBoxAnchorAttrs, TextBoxAttrs, TextBoxTextBodyContentState };
1228
+ export { AlternateContentAttrs, AuthoredEmuAttrs, BlockSdtAttrs, BookmarkBoundaryAttrs, CommentReferenceAttrs, FieldAttrs, HardBreakAttrs, ImageAttrs, ImagePositionAttrs, MathAttrs, PRESERVED_XML_LEVELS, PageBreakRunAttrs, ParagraphAttrs, ParagraphAttrsPatch, ParagraphPropertyChangeAttrs, PreservedBlockAttrs, PreservedXmlAttrs, PreservedXmlLevel, SdtAttrs, ShapeAttrs, SuggestedStructuralMarker, SymbolAttrs, TEXT_BOX_TEXT_BODY_CONTENT_STATE_TYPES, TabAttrs, TableAttrs, TableCellAttrs, TableRowAttrs, TextBoxAnchorAttrs, TextBoxAttrs, TextBoxTextBodyContentState };
@@ -0,0 +1,13 @@
1
+ import { Node } from "prosemirror-model";
2
+ //#region src/prosemirror/textBoxHostParagraph.d.ts
3
+ /**
4
+ * The `w:p` a standalone text box was lifted out of, as a childless paragraph
5
+ * node over the host's paragraph attributes, or `undefined` when the box
6
+ * carries none.
7
+ *
8
+ * Building the node runs the carried attributes through the paragraph schema,
9
+ * so every consumer reads them with the validation any paragraph's get.
10
+ */
11
+ declare const textBoxHostParagraph: (textBox: Node) => Node | undefined;
12
+ //#endregion
13
+ export { textBoxHostParagraph };
@@ -0,0 +1,21 @@
1
+ import { expectTextBoxAttrs } from "./attrs/index.js";
2
+ //#region src/prosemirror/textBoxHostParagraph.ts
3
+ const hostParagraphs = /* @__PURE__ */ new WeakMap();
4
+ /**
5
+ * The `w:p` a standalone text box was lifted out of, as a childless paragraph
6
+ * node over the host's paragraph attributes, or `undefined` when the box
7
+ * carries none.
8
+ *
9
+ * Building the node runs the carried attributes through the paragraph schema,
10
+ * so every consumer reads them with the validation any paragraph's get.
11
+ */
12
+ const textBoxHostParagraph = (textBox) => {
13
+ const cached = hostParagraphs.get(textBox);
14
+ if (cached !== void 0) return cached ?? void 0;
15
+ const host = expectTextBoxAttrs(textBox)._docxHostParagraph;
16
+ const paragraph = host ? textBox.type.schema.nodes["paragraph"]?.create(host) : void 0;
17
+ hostParagraphs.set(textBox, paragraph ?? null);
18
+ return paragraph;
19
+ };
20
+ //#endregion
21
+ export { textBoxHostParagraph };
@@ -303,88 +303,99 @@ const validateNodeAttrs = (node, path, issues) => {
303
303
  });
304
304
  }
305
305
  };
306
+ /**
307
+ * Marks already validated with no issues. A mark's attrs never change, and a
308
+ * conversion shares one instance per distinct mark across thousands of runs,
309
+ * so each distinct mark is validated once.
310
+ */
311
+ const validMarks = /* @__PURE__ */ new WeakSet();
306
312
  const validateMarks = (marks, path, issues) => {
307
313
  for (const [index, mark] of marks.entries()) {
308
- const markPath = `${path}.marks[${index}]`;
309
- switch (mark.type.name) {
310
- case "bold":
311
- case "italic":
312
- case "subscript":
313
- case "superscript":
314
- case "allCaps":
315
- case "smallCaps":
316
- case "emboss":
317
- case "imprint":
318
- case "hidden":
319
- case "textShadow":
320
- case "textOutline":
321
- case "rtl": continue;
322
- case "textEffect":
323
- appendAttrIssues(markPath, readTextEffectMarkAttrs(mark), issues);
324
- continue;
325
- case "underline":
326
- appendAttrIssues(markPath, readUnderlineMarkAttrs(mark), issues);
327
- continue;
328
- case "strike":
329
- appendAttrIssues(markPath, readStrikeMarkAttrs(mark), issues);
330
- continue;
331
- case "textColor":
332
- appendAttrIssues(markPath, readTextColorMarkAttrs(mark), issues);
333
- continue;
334
- case "highlight":
335
- appendAttrIssues(markPath, readHighlightMarkAttrs(mark), issues);
336
- continue;
337
- case "runShading":
338
- appendAttrIssues(markPath, readRunShadingMarkAttrs(mark), issues);
339
- continue;
340
- case "fontSize":
341
- appendAttrIssues(markPath, readFontSizeMarkAttrs(mark), issues);
342
- continue;
343
- case "fontFamily":
344
- appendAttrIssues(markPath, readFontFamilyMarkAttrs(mark), issues);
345
- continue;
346
- case "language":
347
- appendAttrIssues(markPath, readLanguageMarkAttrs(mark), issues);
348
- continue;
349
- case "characterSpacing":
350
- appendAttrIssues(markPath, readCharacterSpacingMarkAttrs(mark), issues);
351
- continue;
352
- case "characterStyle":
353
- appendAttrIssues(markPath, readCharacterStyleMarkAttrs(mark), issues);
354
- continue;
355
- case "emphasisMark":
356
- appendAttrIssues(markPath, readEmphasisMarkAttrs(mark), issues);
357
- continue;
358
- case "footnoteRef":
359
- appendAttrIssues(markPath, readFootnoteRefMarkAttrs(mark), issues);
360
- continue;
361
- case "comment":
362
- appendAttrIssues(markPath, readCommentMarkAttrs(mark), issues);
363
- continue;
364
- case "insertion":
365
- case "deletion":
366
- appendAttrIssues(markPath, readTrackedChangeMarkAttrs(mark), issues);
367
- continue;
368
- case "runPropertyChange":
369
- appendAttrIssues(markPath, readRunPropertyChangeMarkAttrs(mark), issues);
370
- continue;
371
- case "runIdentity":
372
- appendAttrIssues(markPath, readRunIdentityMarkAttrs(mark), issues);
373
- continue;
374
- case "runFormattingOverride":
375
- appendAttrIssues(markPath, readRunFormattingOverrideMarkAttrs(mark), issues);
376
- continue;
377
- case "hyperlink":
378
- appendAttrIssues(markPath, readHyperlinkMarkAttrs(mark), issues);
379
- continue;
380
- case "inlineWrapper":
381
- appendAttrIssues(markPath, readInlineWrapperMarkAttrs(mark), issues);
382
- continue;
383
- default: issues.push({
384
- path: `${markPath}.type.name`,
385
- message: `Unsupported ProseMirror mark type ${mark.type.name}.`
386
- });
387
- }
314
+ if (validMarks.has(mark)) continue;
315
+ const issueCount = issues.length;
316
+ validateMark(mark, `${path}.marks[${index}]`, issues);
317
+ if (issues.length === issueCount) validMarks.add(mark);
318
+ }
319
+ };
320
+ const validateMark = (mark, markPath, issues) => {
321
+ switch (mark.type.name) {
322
+ case "bold":
323
+ case "italic":
324
+ case "subscript":
325
+ case "superscript":
326
+ case "allCaps":
327
+ case "smallCaps":
328
+ case "emboss":
329
+ case "imprint":
330
+ case "hidden":
331
+ case "textShadow":
332
+ case "textOutline":
333
+ case "rtl": return;
334
+ case "textEffect":
335
+ appendAttrIssues(markPath, readTextEffectMarkAttrs(mark), issues);
336
+ return;
337
+ case "underline":
338
+ appendAttrIssues(markPath, readUnderlineMarkAttrs(mark), issues);
339
+ return;
340
+ case "strike":
341
+ appendAttrIssues(markPath, readStrikeMarkAttrs(mark), issues);
342
+ return;
343
+ case "textColor":
344
+ appendAttrIssues(markPath, readTextColorMarkAttrs(mark), issues);
345
+ return;
346
+ case "highlight":
347
+ appendAttrIssues(markPath, readHighlightMarkAttrs(mark), issues);
348
+ return;
349
+ case "runShading":
350
+ appendAttrIssues(markPath, readRunShadingMarkAttrs(mark), issues);
351
+ return;
352
+ case "fontSize":
353
+ appendAttrIssues(markPath, readFontSizeMarkAttrs(mark), issues);
354
+ return;
355
+ case "fontFamily":
356
+ appendAttrIssues(markPath, readFontFamilyMarkAttrs(mark), issues);
357
+ return;
358
+ case "language":
359
+ appendAttrIssues(markPath, readLanguageMarkAttrs(mark), issues);
360
+ return;
361
+ case "characterSpacing":
362
+ appendAttrIssues(markPath, readCharacterSpacingMarkAttrs(mark), issues);
363
+ return;
364
+ case "characterStyle":
365
+ appendAttrIssues(markPath, readCharacterStyleMarkAttrs(mark), issues);
366
+ return;
367
+ case "emphasisMark":
368
+ appendAttrIssues(markPath, readEmphasisMarkAttrs(mark), issues);
369
+ return;
370
+ case "footnoteRef":
371
+ appendAttrIssues(markPath, readFootnoteRefMarkAttrs(mark), issues);
372
+ return;
373
+ case "comment":
374
+ appendAttrIssues(markPath, readCommentMarkAttrs(mark), issues);
375
+ return;
376
+ case "insertion":
377
+ case "deletion":
378
+ appendAttrIssues(markPath, readTrackedChangeMarkAttrs(mark), issues);
379
+ return;
380
+ case "runPropertyChange":
381
+ appendAttrIssues(markPath, readRunPropertyChangeMarkAttrs(mark), issues);
382
+ return;
383
+ case "runIdentity":
384
+ appendAttrIssues(markPath, readRunIdentityMarkAttrs(mark), issues);
385
+ return;
386
+ case "runFormattingOverride":
387
+ appendAttrIssues(markPath, readRunFormattingOverrideMarkAttrs(mark), issues);
388
+ return;
389
+ case "hyperlink":
390
+ appendAttrIssues(markPath, readHyperlinkMarkAttrs(mark), issues);
391
+ return;
392
+ case "inlineWrapper":
393
+ appendAttrIssues(markPath, readInlineWrapperMarkAttrs(mark), issues);
394
+ return;
395
+ default: issues.push({
396
+ path: `${markPath}.type.name`,
397
+ message: `Unsupported ProseMirror mark type ${mark.type.name}.`
398
+ });
388
399
  }
389
400
  };
390
401
  const appendAttrIssues = (path, result, issues) => {
@@ -1,2 +1,2 @@
1
- import { BlockContent, BlockSdt, BookmarkEnd, BookmarkStart, BreakContent, Column, Comment, CommentRangeEnd, CommentRangeStart, CommentReference, ComplexField, Deletion, DisplacedByCustomXml, DocumentBackground, DocumentBackgroundDrawing, DocumentBody, DrawingContent, DrawingRawXmlMode, EffectExtentSlots, Endnote, EndnotePosition, EndnoteProperties, Field, FieldCharContent, FieldType, FooterReference, Footnote, FootnotePosition, FootnoteProperties, HeaderFooter, HeaderFooterType, HeaderReference, Hyperlink, Image, ImageCrop, ImagePadding, ImagePosition, ImageSize, ImageTransform, ImageWrap, ImageWrapPolygon, InlineSdt, Insertion, InstrTextContent, LineNumberRestart, MathEquation, MoveFrom, MoveFromRangeEnd, MoveFromRangeStart, MoveTo, MoveToRangeEnd, MoveToRangeStart, NoBreakHyphenContent, NoteNumberRestart, NoteReferenceContent, PageOrientation, Paragraph, ParagraphContent, ParagraphPropertyChange, PositionalTab, PositionedBookmarkMarker, PreservedAttribute, PreservedBlock, PreservedInline, PropertyChangeInfo, Run, RunContent, RunPropertyChange, SdtProperties, SdtType, Section, SectionProperties, SectionStart, Shape, ShapeContent, ShapeFill, ShapeGeometryAdjustment, ShapeOutline, ShapeTextBody, ShapeType, SimpleField, SoftHyphenContent, SymbolContent, TabContent, Table, TableCell, TableCellBlock, TableCellPropertyChange, TableRow, TableRowPropertyChange, TableStructuralChangeInfo, TextBox, TextContent, TrackedChangeInfo, TrackedRunChange, TrackedRunContent, VerticalAlign, WrapDistanceSlots } from "@stll/docx-core/model";
2
- export type { BlockContent, BlockSdt, BookmarkEnd, BookmarkStart, BreakContent, Column, Comment, CommentRangeEnd, CommentRangeStart, CommentReference, ComplexField, Deletion, DisplacedByCustomXml, DocumentBackground, DocumentBackgroundDrawing, DocumentBody, DrawingContent, DrawingRawXmlMode, EffectExtentSlots, Endnote, EndnotePosition, EndnoteProperties, Field, FieldCharContent, FieldType, FooterReference, Footnote, FootnotePosition, FootnoteProperties, HeaderFooter, HeaderFooterType, HeaderReference, Hyperlink, Image, ImageCrop, ImagePadding, ImagePosition, ImageSize, ImageTransform, ImageWrap, ImageWrapPolygon, InlineSdt, Insertion, InstrTextContent, LineNumberRestart, MathEquation, MoveFrom, MoveFromRangeEnd, MoveFromRangeStart, MoveTo, MoveToRangeEnd, MoveToRangeStart, NoBreakHyphenContent, NoteNumberRestart, NoteReferenceContent, PageOrientation, Paragraph, ParagraphContent, ParagraphPropertyChange, PositionalTab, PositionedBookmarkMarker, PreservedAttribute, PreservedBlock, PreservedInline, PropertyChangeInfo, Run, RunContent, RunPropertyChange, SdtProperties, SdtType, Section, SectionProperties, SectionStart, Shape, ShapeContent, ShapeFill, ShapeGeometryAdjustment, ShapeOutline, ShapeTextBody, ShapeType, SimpleField, SoftHyphenContent, SymbolContent, TabContent, Table, TableCell, TableCellBlock, TableCellPropertyChange, TableRow, TableRowPropertyChange, TableStructuralChangeInfo, TextBox, TextContent, TrackedChangeInfo, TrackedRunChange, TrackedRunContent, VerticalAlign, WrapDistanceSlots };
1
+ import { BlockContent, BlockSdt, BookmarkEnd, BookmarkStart, BreakContent, Column, Comment, CommentRangeEnd, CommentRangeStart, CommentReference, ComplexField, Deletion, DisplacedByCustomXml, DocumentBackground, DocumentBackgroundDrawing, DocumentBody, DrawingContent, DrawingGroupChild, DrawingRawXmlMode, EffectExtentSlots, Endnote, EndnotePosition, EndnoteProperties, Field, FieldCharContent, FieldType, FooterReference, Footnote, FootnotePosition, FootnoteProperties, HeaderFooter, HeaderFooterType, HeaderReference, Hyperlink, Image, ImageCrop, ImagePadding, ImagePosition, ImageSize, ImageTransform, ImageWrap, ImageWrapPolygon, InlineSdt, Insertion, InstrTextContent, LineNumberRestart, MathEquation, MoveFrom, MoveFromRangeEnd, MoveFromRangeStart, MoveTo, MoveToRangeEnd, MoveToRangeStart, NoBreakHyphenContent, NoteNumberRestart, NoteReferenceContent, PageOrientation, Paragraph, ParagraphContent, ParagraphPropertyChange, PositionalTab, PositionedBookmarkMarker, PreservedAttribute, PreservedBlock, PreservedInline, PropertyChangeInfo, Run, RunContent, RunPropertyChange, SdtProperties, SdtType, Section, SectionProperties, SectionStart, Shape, ShapeAlternateContent, ShapeContent, ShapeFill, ShapeGeometryAdjustment, ShapeOutline, ShapeTextBody, ShapeType, SimpleField, SoftHyphenContent, SymbolContent, TabContent, Table, TableCell, TableCellBlock, TableCellPropertyChange, TableRow, TableRowPropertyChange, TableStructuralChangeInfo, TextBox, TextContent, TrackedChangeInfo, TrackedRunChange, TrackedRunContent, VerticalAlign, WrapDistanceSlots } from "@stll/docx-core/model";
2
+ export type { BlockContent, BlockSdt, BookmarkEnd, BookmarkStart, BreakContent, Column, Comment, CommentRangeEnd, CommentRangeStart, CommentReference, ComplexField, Deletion, DisplacedByCustomXml, DocumentBackground, DocumentBackgroundDrawing, DocumentBody, DrawingContent, DrawingGroupChild, DrawingRawXmlMode, EffectExtentSlots, Endnote, EndnotePosition, EndnoteProperties, Field, FieldCharContent, FieldType, FooterReference, Footnote, FootnotePosition, FootnoteProperties, HeaderFooter, HeaderFooterType, HeaderReference, Hyperlink, Image, ImageCrop, ImagePadding, ImagePosition, ImageSize, ImageTransform, ImageWrap, ImageWrapPolygon, InlineSdt, Insertion, InstrTextContent, LineNumberRestart, MathEquation, MoveFrom, MoveFromRangeEnd, MoveFromRangeStart, MoveTo, MoveToRangeEnd, MoveToRangeStart, NoBreakHyphenContent, NoteNumberRestart, NoteReferenceContent, PageOrientation, Paragraph, ParagraphContent, ParagraphPropertyChange, PositionalTab, PositionedBookmarkMarker, PreservedAttribute, PreservedBlock, PreservedInline, PropertyChangeInfo, Run, RunContent, RunPropertyChange, SdtProperties, SdtType, Section, SectionProperties, SectionStart, Shape, ShapeAlternateContent, ShapeContent, ShapeFill, ShapeGeometryAdjustment, ShapeOutline, ShapeTextBody, ShapeType, SimpleField, SoftHyphenContent, SymbolContent, TabContent, Table, TableCell, TableCellBlock, TableCellPropertyChange, TableRow, TableRowPropertyChange, TableStructuralChangeInfo, TextBox, TextContent, TrackedChangeInfo, TrackedRunChange, TrackedRunContent, VerticalAlign, WrapDistanceSlots };
@@ -2,6 +2,7 @@ import { BUILT_IN_STYLE_NAME, builtInHeadingStyleName } from "../docx/builtInSty
2
2
  import "../docx/defaultParagraphStyle.js";
3
3
  import { createParseWarningCollector } from "../docx/parseContext.js";
4
4
  import { formatParseWarnings } from "../docx/parseWarningMessage.js";
5
+ import "../docx/settingsParser.js";
5
6
  import { STYLE_SET_PART, normalizeDocumentStyleSet } from "../style-sets/styleSetNormalization.js";
6
7
  import "../style-sets/types.js";
7
8
  import { panic } from "better-result";
@@ -13,6 +14,12 @@ import { DOCX_CONFORMANCE_CLASSES } from "@stll/docx-core/model";
13
14
  * Provides functions to create new documents programmatically.
14
15
  */
15
16
  /**
17
+ * `compatibilityMode` a new document declares, so it is laid out, and read
18
+ * back, with the current rules rather than the oldest ones a package without
19
+ * the setting gets.
20
+ */
21
+ const NEW_DOCUMENT_COMPATIBILITY_MODE = 15;
22
+ /**
16
23
  * Get default paragraph styles (matching Google Docs defaults)
17
24
  *
18
25
  * Font sizes are in half-points (e.g., 22 = 11pt, 40 = 20pt)
@@ -398,7 +405,9 @@ function createEmptyDocument(options = {}) {
398
405
  if (styleSet?.numbering) docxPackage.numbering = structuredClone(styleSet.numbering);
399
406
  if (styleSet?.theme) docxPackage.theme = structuredClone(styleSet.theme);
400
407
  if (styleSet?.fontTable) docxPackage.fontTable = structuredClone(styleSet.fontTable);
401
- if (styleSet?.settings) docxPackage.settings = structuredClone(styleSet.settings);
408
+ const settings = styleSet?.settings ? structuredClone(styleSet.settings) : { defaultTabStop: 720 };
409
+ settings.compatibilityMode ??= NEW_DOCUMENT_COMPATIBILITY_MODE;
410
+ docxPackage.settings = settings;
402
411
  const parseWarnings = styleSetWarnings();
403
412
  const document = {
404
413
  package: docxPackage,
@@ -50,8 +50,31 @@ declare function hasCjk(text: string): boolean;
50
50
  * overlap the presentation forms below.
51
51
  */
52
52
  declare function isComplexScriptCodePoint(cp: number): boolean;
53
- /** Which font slot a single code point selects. CJK wins where ranges meet. */
54
- declare function scriptClassOf(cp: number): ScriptClass;
53
+ /**
54
+ * True when `w:rFonts/@w:hint="eastAsia"` moves a code point from the
55
+ * `w:hAnsi` slot to the `w:eastAsia` slot (ECMA-376 §17.3.2.26): the ranges
56
+ * the font-slot table resolves to the East Asian font whenever the hint is
57
+ * `eastAsia`. Basic Latin never moves, and neither do the accented letters of
58
+ * Latin-1 Supplement and the Latin Extended blocks, whose move the table also
59
+ * conditions on the run's East Asian language.
60
+ */
61
+ declare function isEastAsiaHintCodePoint(cp: number): boolean;
62
+ /**
63
+ * Whether a run's `w:hint="eastAsia"` takes effect. A run under `w:cs` or
64
+ * `w:rtl` formats every character with the complex-script slot, which the
65
+ * hint does not override.
66
+ */
67
+ declare function eastAsiaHintApplies(run: {
68
+ readonly eastAsiaHint?: boolean | undefined;
69
+ readonly forceComplexScript?: boolean | undefined;
70
+ readonly rtl?: boolean | undefined;
71
+ }): boolean;
72
+ /**
73
+ * Which font slot a single code point selects. CJK wins where ranges meet.
74
+ * `eastAsiaHint` is the run's effective `w:hint="eastAsia"`
75
+ * (see {@link eastAsiaHintApplies}).
76
+ */
77
+ declare function scriptClassOf(cp: number, eastAsiaHint?: boolean): ScriptClass;
55
78
  /**
56
79
  * True when the text contains at least one complex-script code point. Callers
57
80
  * use this to skip segmentation entirely on the common all-Latin path.
@@ -68,11 +91,17 @@ declare function isRightToLeftCodePoint(cp: number): boolean;
68
91
  /** True when the text contains at least one right-to-left code point. */
69
92
  declare function hasRightToLeft(text: string): boolean;
70
93
  declare function hasComplexScript(text: string): boolean;
94
+ /**
95
+ * True when some code point of the text selects the `w:eastAsia` slot: a CJK
96
+ * code point, or under an effective `w:hint="eastAsia"` one the hint moves.
97
+ */
98
+ declare function hasEastAsiaSlotText(text: string, eastAsiaHint?: boolean): boolean;
71
99
  /**
72
100
  * Split text into maximal runs of one script class (CJK vs. non-CJK). Iterates
73
101
  * by code point so astral ideographs (surrogate pairs) are never split between
74
102
  * fonts. Empty input yields no segments; single-class input yields one.
103
+ * `eastAsiaHint` is the run's effective `w:hint="eastAsia"`.
75
104
  */
76
- declare function segmentByScript(text: string): ScriptSegment[];
105
+ declare function segmentByScript(text: string, eastAsiaHint?: boolean): ScriptSegment[];
77
106
  //#endregion
78
- export { SCRIPT_CLASS, ScriptClass, ScriptSegment, hasCjk, hasComplexScript, hasRightToLeft, isCjkCodePoint, isComplexScriptCodePoint, isRightToLeftCodePoint, scriptClassOf, segmentByScript };
107
+ export { SCRIPT_CLASS, ScriptClass, ScriptSegment, eastAsiaHintApplies, hasCjk, hasComplexScript, hasEastAsiaSlotText, hasRightToLeft, isCjkCodePoint, isComplexScriptCodePoint, isEastAsiaHintCodePoint, isRightToLeftCodePoint, scriptClassOf, segmentByScript };
@@ -52,9 +52,32 @@ function hasCjk(text) {
52
52
  function isComplexScriptCodePoint(cp) {
53
53
  return cp >= 1424 && cp <= 1535 || cp >= 1536 && cp <= 1791 || cp >= 1792 && cp <= 1871 || cp >= 1872 && cp <= 1919 || cp >= 1920 && cp <= 1983 || cp >= 1984 && cp <= 2047 || cp >= 2048 && cp <= 2111 || cp >= 2112 && cp <= 2143 || cp >= 2144 && cp <= 2159 || cp >= 2160 && cp <= 2207 || cp >= 2208 && cp <= 2303 || cp >= 2304 && cp <= 3455 || cp >= 3456 && cp <= 3583 || cp >= 3584 && cp <= 3711 || cp >= 3712 && cp <= 3839 || cp >= 3840 && cp <= 4095 || cp >= 4096 && cp <= 4255 || cp >= 6016 && cp <= 6143 || cp >= 64285 && cp <= 64335 || cp >= 64336 && cp <= 65023 || cp >= 65136 && cp <= 65279 || cp >= 68864 && cp <= 68927 || cp >= 69312 && cp <= 69375 || cp >= 69424 && cp <= 69487 || cp >= 69488 && cp <= 69551 || cp >= 125184 && cp <= 125279 || cp >= 126464 && cp <= 126719;
54
54
  }
55
- /** Which font slot a single code point selects. CJK wins where ranges meet. */
56
- function scriptClassOf(cp) {
57
- if (isCjkCodePoint(cp)) return SCRIPT_CLASS.eastAsia;
55
+ /**
56
+ * True when `w:rFonts/@w:hint="eastAsia"` moves a code point from the
57
+ * `w:hAnsi` slot to the `w:eastAsia` slot (ECMA-376 §17.3.2.26): the ranges
58
+ * the font-slot table resolves to the East Asian font whenever the hint is
59
+ * `eastAsia`. Basic Latin never moves, and neither do the accented letters of
60
+ * Latin-1 Supplement and the Latin Extended blocks, whose move the table also
61
+ * conditions on the run's East Asian language.
62
+ */
63
+ function isEastAsiaHintCodePoint(cp) {
64
+ return cp === 161 || cp === 164 || cp === 167 || cp === 168 || cp === 170 || cp === 173 || cp === 175 || cp >= 176 && cp <= 180 || cp >= 182 && cp <= 186 || cp >= 188 && cp <= 191 || cp === 215 || cp === 247 || cp >= 688 && cp <= 879 || cp >= 880 && cp <= 1023 || cp >= 1024 && cp <= 1279 || cp >= 8192 && cp <= 10175 || cp >= 57344 && cp <= 63743 || cp >= 64256 && cp <= 64284;
65
+ }
66
+ /**
67
+ * Whether a run's `w:hint="eastAsia"` takes effect. A run under `w:cs` or
68
+ * `w:rtl` formats every character with the complex-script slot, which the
69
+ * hint does not override.
70
+ */
71
+ function eastAsiaHintApplies(run) {
72
+ return run.eastAsiaHint === true && run.forceComplexScript !== true && run.rtl !== true;
73
+ }
74
+ /**
75
+ * Which font slot a single code point selects. CJK wins where ranges meet.
76
+ * `eastAsiaHint` is the run's effective `w:hint="eastAsia"`
77
+ * (see {@link eastAsiaHintApplies}).
78
+ */
79
+ function scriptClassOf(cp, eastAsiaHint = false) {
80
+ if (isCjkCodePoint(cp) || eastAsiaHint && isEastAsiaHintCodePoint(cp)) return SCRIPT_CLASS.eastAsia;
58
81
  if (isComplexScriptCodePoint(cp)) return SCRIPT_CLASS.complex;
59
82
  return SCRIPT_CLASS.western;
60
83
  }
@@ -83,16 +106,26 @@ function hasComplexScript(text) {
83
106
  return false;
84
107
  }
85
108
  /**
109
+ * True when some code point of the text selects the `w:eastAsia` slot: a CJK
110
+ * code point, or under an effective `w:hint="eastAsia"` one the hint moves.
111
+ */
112
+ function hasEastAsiaSlotText(text, eastAsiaHint = false) {
113
+ if (!eastAsiaHint) return hasCjk(text);
114
+ for (const ch of text) if (scriptClassOf(ch.codePointAt(0), true) === SCRIPT_CLASS.eastAsia) return true;
115
+ return false;
116
+ }
117
+ /**
86
118
  * Split text into maximal runs of one script class (CJK vs. non-CJK). Iterates
87
119
  * by code point so astral ideographs (surrogate pairs) are never split between
88
120
  * fonts. Empty input yields no segments; single-class input yields one.
121
+ * `eastAsiaHint` is the run's effective `w:hint="eastAsia"`.
89
122
  */
90
- function segmentByScript(text) {
123
+ function segmentByScript(text, eastAsiaHint = false) {
91
124
  const segments = [];
92
125
  let current = "";
93
126
  let currentScript = SCRIPT_CLASS.western;
94
127
  for (const ch of text) {
95
- const script = scriptClassOf(ch.codePointAt(0));
128
+ const script = scriptClassOf(ch.codePointAt(0), eastAsiaHint);
96
129
  if (current.length === 0) {
97
130
  current = ch;
98
131
  currentScript = script;
@@ -116,4 +149,4 @@ function segmentByScript(text) {
116
149
  return segments;
117
150
  }
118
151
  //#endregion
119
- export { SCRIPT_CLASS, hasCjk, hasComplexScript, hasRightToLeft, isCjkCodePoint, isComplexScriptCodePoint, isRightToLeftCodePoint, scriptClassOf, segmentByScript };
152
+ export { SCRIPT_CLASS, eastAsiaHintApplies, hasCjk, hasComplexScript, hasEastAsiaSlotText, hasRightToLeft, isCjkCodePoint, isComplexScriptCodePoint, isEastAsiaHintCodePoint, isRightToLeftCodePoint, scriptClassOf, segmentByScript };
@@ -2,10 +2,24 @@ import { document_d_exports } from "../types/document.js";
2
2
  //#region src/utils/textFormattingMerge.d.ts
3
3
  declare const STYLE_TOGGLE_KEYS: readonly ["bold", "boldCs", "italic", "italicCs", "allCaps", "emboss", "imprint", "outline", "shadow", "smallCaps", "strike", "hidden"];
4
4
  /**
5
- * Merge the properties exposed by one resolved style definition.
5
+ * Merge one style's own run-formatting declarations onto its already-resolved
6
+ * `w:basedOn` ancestor.
6
7
  *
7
- * A false toggle at a child style level does not cancel the inherited state. The
8
- * ordinary merge remains unchanged for direct formatting and non-toggle properties.
8
+ * ECMA-376 §17.7.3 resolves a toggle property (bold, italic, allCaps, ...) for a
9
+ * single style tier by walking the `basedOn` chain from the style itself towards
10
+ * its root: read the value the style declares; if it declares none, move to the
11
+ * parent and repeat. The first value found — whether an explicit "on" or an
12
+ * explicit "off" — is that tier's value, and it is *not* combined with whatever
13
+ * a weaker ancestor further up the chain happened to say. A style's own
14
+ * `<w:b w:val="0"/>` therefore turns bold off outright, even when its base style
15
+ * is bold; it does not defer to the base.
16
+ *
17
+ * That is exactly last-defined-wins, i.e. `mergeTextFormatting`'s existing
18
+ * behaviour for every other property. The toggle behaviour §17.7.3 is actually
19
+ * known for — combining a table style's, a paragraph style's and a character
20
+ * style's resolved values by Boolean XOR — combines the *outputs* of separate
21
+ * `basedOn` walks like this one; it is not part of resolving a single walk, so
22
+ * it has no place in this function.
9
23
  */
10
24
  declare function mergeStyleTextFormatting(target: document_d_exports.TextFormatting | undefined, source: document_d_exports.TextFormatting | undefined): document_d_exports.TextFormatting | undefined;
11
25
  declare function mergeTextFormatting(target: document_d_exports.TextFormatting | undefined, source: document_d_exports.TextFormatting | undefined): document_d_exports.TextFormatting | undefined;