@portone/docx-editor 0.2.1 → 0.3.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 (225) hide show
  1. package/CHANGELOG.md +109 -0
  2. package/CONTRIBUTING.md +5 -1
  3. package/dist/DocxEditor.d.ts +6 -0
  4. package/dist/DocxEditor.js +12 -29
  5. package/dist/core.d.ts +23 -8
  6. package/dist/core.js +9 -4
  7. package/dist/docx/cloning.d.ts +38 -0
  8. package/dist/docx/cloning.js +74 -0
  9. package/dist/docx/commentOnlyChange.d.ts +12 -7
  10. package/dist/docx/commentOnlyChange.js +9 -156
  11. package/dist/docx/comments/constants.d.ts +0 -1
  12. package/dist/docx/comments/constants.js +0 -2
  13. package/dist/docx/comments/grammar.d.ts +10 -4
  14. package/dist/docx/comments/grammar.js +12 -2
  15. package/dist/docx/comments/{verifying.d.ts → parts.d.ts} +26 -18
  16. package/dist/docx/comments/parts.js +279 -0
  17. package/dist/docx/comments/people.d.ts +11 -2
  18. package/dist/docx/comments/people.js +16 -92
  19. package/dist/docx/comments/policy.d.ts +7 -0
  20. package/dist/docx/comments/policy.js +43 -0
  21. package/dist/docx/comments/reading.js +8 -10
  22. package/dist/docx/comments/writing.d.ts +19 -7
  23. package/dist/docx/comments/writing.js +52 -111
  24. package/dist/docx/documentSettings.d.ts +7 -0
  25. package/dist/docx/documentSettings.js +10 -2
  26. package/dist/docx/exportDocx.d.ts +40 -5
  27. package/dist/docx/exportDocx.js +69 -71
  28. package/dist/docx/exportRefs.d.ts +5 -2
  29. package/dist/docx/exportRefs.js +3 -1
  30. package/dist/docx/fidelity.d.ts +43 -0
  31. package/dist/docx/fidelity.js +64 -0
  32. package/dist/docx/formatting/attrs.d.ts +27 -0
  33. package/dist/docx/formatting/attrs.js +31 -0
  34. package/dist/docx/formatting/context.d.ts +31 -0
  35. package/dist/docx/formatting/context.js +42 -0
  36. package/dist/docx/formatting/direct.d.ts +6 -5
  37. package/dist/docx/formatting/direct.js +52 -78
  38. package/dist/docx/formatting/resolve.d.ts +45 -0
  39. package/dist/docx/formatting/resolve.js +140 -0
  40. package/dist/docx/formatting/runProperties.d.ts +93 -0
  41. package/dist/docx/formatting/runProperties.js +316 -0
  42. package/dist/docx/formatting/styles.js +3 -3
  43. package/dist/docx/formatting/tabStops.js +7 -22
  44. package/dist/docx/formatting.d.ts +4 -1
  45. package/dist/docx/formatting.js +4 -1
  46. package/dist/docx/headersFooters.js +6 -13
  47. package/dist/docx/identities.d.ts +67 -0
  48. package/dist/docx/identities.js +174 -0
  49. package/dist/docx/importDocx.d.ts +12 -1
  50. package/dist/docx/importDocx.js +72 -79
  51. package/dist/docx/importParagraph.d.ts +1 -1
  52. package/dist/docx/importParagraph.js +4 -3
  53. package/dist/docx/importTable.d.ts +1 -1
  54. package/dist/docx/importTable.js +17 -1
  55. package/dist/docx/invariants.d.ts +33 -0
  56. package/dist/docx/invariants.js +256 -0
  57. package/dist/docx/media.d.ts +6 -4
  58. package/dist/docx/media.js +6 -37
  59. package/dist/docx/newLists.d.ts +20 -0
  60. package/dist/docx/newLists.js +36 -0
  61. package/dist/docx/notes.js +3 -7
  62. package/dist/docx/numberingPlanner.d.ts +8 -0
  63. package/dist/docx/numberingPlanner.js +19 -0
  64. package/dist/docx/packageParts.d.ts +42 -0
  65. package/dist/docx/packageParts.js +135 -0
  66. package/dist/docx/pageGeometry.d.ts +2 -0
  67. package/dist/docx/pageGeometry.js +18 -9
  68. package/dist/docx/paraProps.d.ts +10 -22
  69. package/dist/docx/paraProps.js +47 -76
  70. package/dist/docx/partPlan.d.ts +36 -0
  71. package/dist/docx/partPlan.js +59 -0
  72. package/dist/docx/protectionPolicy.d.ts +127 -0
  73. package/dist/docx/protectionPolicy.js +169 -0
  74. package/dist/docx/relationships.d.ts +1 -1
  75. package/dist/docx/relationships.js +8 -13
  76. package/dist/docx/runProps.d.ts +9 -22
  77. package/dist/docx/runProps.js +15 -168
  78. package/dist/docx/scan.js +20 -52
  79. package/dist/docx/sdt.js +9 -34
  80. package/dist/docx/sdtProps.d.ts +8 -1
  81. package/dist/docx/sdtProps.js +10 -0
  82. package/dist/docx/serializeBlock.d.ts +2 -0
  83. package/dist/docx/serializeBlock.js +8 -5
  84. package/dist/docx/serializeTable.js +32 -15
  85. package/dist/docx/session.d.ts +42 -14
  86. package/dist/docx/session.js +43 -17
  87. package/dist/docx/tableFormatting/editing.js +108 -139
  88. package/dist/docx/tableFormatting/reading.d.ts +16 -6
  89. package/dist/docx/tableFormatting/reading.js +40 -20
  90. package/dist/docx/tableTemplate.js +18 -7
  91. package/dist/download.d.ts +8 -5
  92. package/dist/download.js +2 -0
  93. package/dist/editor/clipboard/inlineFormatting.js +19 -30
  94. package/dist/editor/commands/comments/editing.d.ts +6 -2
  95. package/dist/editor/commands/comments/editing.js +19 -31
  96. package/dist/editor/commands/exportQueries.d.ts +15 -0
  97. package/dist/editor/commands/exportQueries.js +14 -0
  98. package/dist/editor/commands/fidelityQueries.d.ts +12 -0
  99. package/dist/editor/commands/fidelityQueries.js +8 -0
  100. package/dist/editor/commands/formatting/editing.d.ts +2 -2
  101. package/dist/editor/commands/formatting/editing.js +26 -108
  102. package/dist/editor/commands/formatting/propertyCommands.d.ts +21 -0
  103. package/dist/editor/commands/formatting/propertyCommands.js +103 -0
  104. package/dist/editor/commands/formatting/shared.d.ts +3 -3
  105. package/dist/editor/commands/formatting/shared.js +5 -2
  106. package/dist/editor/commands/indentCommands.js +5 -4
  107. package/dist/editor/commands/index.d.ts +11 -0
  108. package/dist/editor/commands/index.js +5 -0
  109. package/dist/editor/commands/linkCommands.js +5 -6
  110. package/dist/editor/commands/listCommands.js +8 -10
  111. package/dist/editor/commands/lockCommands.d.ts +7 -1
  112. package/dist/editor/commands/lockCommands.js +35 -46
  113. package/dist/editor/commands/paragraphCommands.js +28 -31
  114. package/dist/editor/commands/spacingCommands.js +1 -1
  115. package/dist/editor/createEditor.d.ts +17 -29
  116. package/dist/editor/createEditor.js +58 -58
  117. package/dist/editor/documentStyles.d.ts +11 -35
  118. package/dist/editor/documentStyles.js +9 -52
  119. package/dist/editor/editorDocument.d.ts +56 -0
  120. package/dist/editor/editorDocument.js +74 -0
  121. package/dist/editor/externalClipboard.js +16 -45
  122. package/dist/editor/insertTable.js +4 -3
  123. package/dist/editor/paragraphEdits.d.ts +11 -18
  124. package/dist/editor/paragraphEdits.js +7 -16
  125. package/dist/editor/plugins/displayDerivation.d.ts +47 -0
  126. package/dist/editor/plugins/displayDerivation.js +78 -0
  127. package/dist/editor/plugins/imagePaste.js +4 -3
  128. package/dist/editor/plugins/keymap.js +18 -3
  129. package/dist/editor/plugins/numberingDecorations.d.ts +5 -11
  130. package/dist/editor/plugins/numberingDecorations.js +7 -17
  131. package/dist/editor/plugins/paragraphDisplay.d.ts +7 -0
  132. package/dist/editor/plugins/paragraphDisplay.js +51 -0
  133. package/dist/editor/plugins/tabLayout.js +1 -1
  134. package/dist/editor/plugins/tableDisplay.d.ts +6 -0
  135. package/dist/editor/plugins/tableDisplay.js +16 -0
  136. package/dist/index.d.ts +2 -0
  137. package/dist/model/format.d.ts +30 -8
  138. package/dist/model/format.js +35 -22
  139. package/dist/model/tabStops.d.ts +9 -0
  140. package/dist/model/tabStops.js +18 -0
  141. package/dist/numbering/listTemplate.js +24 -7
  142. package/dist/numbering/parseNumbering.d.ts +14 -1
  143. package/dist/numbering/parseNumbering.js +35 -22
  144. package/dist/numbering/writeNumbering.d.ts +3 -4
  145. package/dist/numbering/writeNumbering.js +14 -25
  146. package/dist/ooxml/childOrder.d.ts +34 -0
  147. package/dist/ooxml/childOrder.js +496 -0
  148. package/dist/ooxml/element.d.ts +24 -11
  149. package/dist/ooxml/element.js +31 -12
  150. package/dist/ooxml/errors.d.ts +3 -2
  151. package/dist/ooxml/image.d.ts +4 -0
  152. package/dist/ooxml/image.js +2 -5
  153. package/dist/ooxml/partSplice.d.ts +67 -0
  154. package/dist/ooxml/partSplice.js +169 -0
  155. package/dist/ooxml/props.d.ts +112 -0
  156. package/dist/{docx/propsXml.js → ooxml/props.js} +72 -200
  157. package/dist/ooxml/simpleTypes.d.ts +103 -0
  158. package/dist/ooxml/simpleTypes.js +182 -0
  159. package/dist/ooxml/tabStops.js +8 -27
  160. package/dist/ooxml/tagScan.d.ts +34 -0
  161. package/dist/ooxml/tagScan.js +108 -0
  162. package/dist/ooxml/units.d.ts +25 -13
  163. package/dist/ooxml/units.js +65 -31
  164. package/dist/ooxml/xml.d.ts +27 -6
  165. package/dist/ooxml/xml.js +37 -5
  166. package/dist/page/blockKinds.d.ts +61 -0
  167. package/dist/page/blockKinds.js +11 -0
  168. package/dist/page/kinds/index.d.ts +6 -0
  169. package/dist/page/kinds/index.js +10 -0
  170. package/dist/page/kinds/paragraphKind.d.ts +10 -0
  171. package/dist/page/kinds/paragraphKind.js +71 -0
  172. package/dist/page/kinds/tableKind.d.ts +10 -0
  173. package/dist/page/kinds/tableKind.js +178 -0
  174. package/dist/page/measureBlocks.d.ts +3 -14
  175. package/dist/page/measureBlocks.js +24 -45
  176. package/dist/page/pageDecorations.d.ts +27 -44
  177. package/dist/page/pageDecorations.js +70 -152
  178. package/dist/page/pageLayout.d.ts +2 -19
  179. package/dist/page/pageLayout.js +36 -6
  180. package/dist/page/usePageLayout.d.ts +2 -17
  181. package/dist/page/usePageLayout.js +3 -39
  182. package/dist/schema/attrRoles.d.ts +25 -18
  183. package/dist/schema/attrRoles.js +102 -67
  184. package/dist/schema/displayDerivation.d.ts +82 -0
  185. package/dist/schema/displayDerivation.js +130 -0
  186. package/dist/schema/docxSchema.d.ts +3 -0
  187. package/dist/schema/docxSchema.js +26 -14
  188. package/dist/schema/editGuard.d.ts +1 -1
  189. package/dist/schema/guards.d.ts +37 -14
  190. package/dist/schema/guards.js +29 -3
  191. package/dist/schema/index.d.ts +2 -0
  192. package/dist/schema/index.js +2 -0
  193. package/dist/schema/locks.d.ts +11 -44
  194. package/dist/schema/locks.js +0 -9
  195. package/dist/schema/preservedGuards.d.ts +26 -6
  196. package/dist/schema/preservedGuards.js +31 -1
  197. package/dist/schema/protection.d.ts +7 -1
  198. package/dist/schema/protection.js +2 -1
  199. package/dist/schema/sourceEquality.d.ts +1 -9
  200. package/dist/schema/sourceEquality.js +1 -27
  201. package/dist/styles/inlineStyle.js +15 -6
  202. package/dist/table/cellFormatting.d.ts +8 -1
  203. package/dist/table/cellFormatting.js +10 -18
  204. package/dist/table/commands.js +20 -18
  205. package/dist/table/format.d.ts +3 -0
  206. package/dist/table/format.js +3 -9
  207. package/dist/table/gridBorders.d.ts +14 -16
  208. package/dist/table/gridBorders.js +3 -41
  209. package/dist/table/merge.d.ts +2 -6
  210. package/dist/table/merge.js +5 -5
  211. package/package.json +7 -3
  212. package/dist/docx/comments/contentTypes.d.ts +0 -7
  213. package/dist/docx/comments/contentTypes.js +0 -38
  214. package/dist/docx/comments/verifying.js +0 -206
  215. package/dist/docx/formatting/effectiveParagraph.d.ts +0 -15
  216. package/dist/docx/formatting/effectiveParagraph.js +0 -81
  217. package/dist/docx/propsXml.d.ts +0 -67
  218. package/dist/docx/uniqueControls.d.ts +0 -14
  219. package/dist/docx/uniqueControls.js +0 -62
  220. package/dist/editor/plugins/commentReservations.d.ts +0 -5
  221. package/dist/editor/plugins/commentReservations.js +0 -26
  222. package/dist/editor/plugins/styledParagraphs.d.ts +0 -15
  223. package/dist/editor/plugins/styledParagraphs.js +0 -65
  224. package/dist/page/tableMeasurements.d.ts +0 -18
  225. package/dist/page/tableMeasurements.js +0 -119
@@ -1,56 +1,27 @@
1
1
  // src/docx/formatting/direct.ts
2
2
  import {
3
- isHighlightName,
4
- isUnderlineKind
3
+ RUN_FORMAT_KEYS
5
4
  } from "../../model/format.js";
6
- import { overridingAttrs } from "../../ooxml/precedence.js";
5
+ import {
6
+ ST_DecimalNumber,
7
+ ST_SignedTwipsMeasure,
8
+ ST_TwipsMeasure,
9
+ TWIPS_PER_PT
10
+ } from "../../ooxml/simpleTypes.js";
7
11
  import { readTabStopDirectives } from "../../ooxml/tabStops.js";
8
12
  import {
9
13
  ALIGN_BY_JC,
10
14
  borderSide,
11
15
  childValue,
12
- halfPointsToPt,
13
16
  isOn,
14
17
  round,
15
18
  shadingOf,
16
- toHexColor,
17
- toNumber,
18
19
  twipsToPt,
19
20
  wAttr
20
21
  } from "../../ooxml/units.js";
21
22
  import { childByLocalName } from "../../ooxml/xml.js";
22
- import { NO_THEME_FONTS, themeFontName } from "../theme.js";
23
- var VERTICAL_ALIGN_BY_VAL = {
24
- superscript: "superscript",
25
- subscript: "subscript"
26
- };
27
- function fontNamesOf(cssNames) {
28
- if (!cssNames) return [];
29
- return cssNames.split(",").map((name) => name.trim().replace(/^"|"$/g, "")).filter((name) => name.length > 0);
30
- }
31
- var FONT_SLOTS = ["ascii", "eastAsia", "hAnsi", "cs"];
32
- function slotFontName(rFonts, slot, themeFonts) {
33
- const written = wAttr(rFonts, slot);
34
- if (written !== null) return written;
35
- for (const attr of overridingAttrs("rFonts", slot)) {
36
- const resolved = themeFontName(themeFonts, wAttr(rFonts, attr));
37
- if (resolved !== null) return resolved;
38
- }
39
- return null;
40
- }
41
- function fontFamilyOf(rFonts, themeFonts) {
42
- const names = FONT_SLOTS.map((slot) => slotFontName(rFonts, slot, themeFonts)).filter((name) => name !== null).filter((name) => name.length > 0 && !/["';\\]/.test(name));
43
- const unique = Array.from(new Set(names));
44
- return unique.length > 0 ? unique.map((name) => `"${name}"`).join(",") : null;
45
- }
46
- function langOf(rPr) {
47
- const lang = childByLocalName(rPr, "lang");
48
- if (!lang) return null;
49
- const eastAsia = wAttr(lang, "eastAsia");
50
- if (eastAsia !== null && eastAsia.length > 0) return eastAsia;
51
- const value = wAttr(lang, "val");
52
- return value !== null && value.length > 0 ? value : null;
53
- }
23
+ import { NO_THEME_FONTS } from "../theme.js";
24
+ import { RUN_PROPERTIES } from "./runProperties.js";
54
25
  function drawnBorder(pBdr, side) {
55
26
  const css = borderSide(pBdr, side);
56
27
  return css === "none" ? null : css;
@@ -73,33 +44,39 @@ function readIndent(pPr) {
73
44
  const ind = childByLocalName(pPr, "ind");
74
45
  if (!ind) return {};
75
46
  const format = {};
76
- const start = twipsToPt(wAttr(ind, "start") ?? wAttr(ind, "left"));
47
+ const start = twipsToPt(
48
+ ST_SignedTwipsMeasure.parse(wAttr(ind, "start") ?? wAttr(ind, "left"))
49
+ );
77
50
  if (start !== null) format.indentStartPt = start;
78
- const end = twipsToPt(wAttr(ind, "end") ?? wAttr(ind, "right"));
51
+ const end = twipsToPt(
52
+ ST_SignedTwipsMeasure.parse(wAttr(ind, "end") ?? wAttr(ind, "right"))
53
+ );
79
54
  if (end !== null) format.indentEndPt = end;
80
- const hanging = twipsToPt(wAttr(ind, "hanging"));
81
- const firstLine = twipsToPt(wAttr(ind, "firstLine"));
55
+ const hanging = twipsToPt(ST_TwipsMeasure.parse(wAttr(ind, "hanging")));
56
+ const firstLine = twipsToPt(ST_TwipsMeasure.parse(wAttr(ind, "firstLine")));
82
57
  if (hanging !== null) format.textIndentPt = -hanging;
83
58
  else if (firstLine !== null) format.textIndentPt = firstLine;
84
59
  return format;
85
60
  }
61
+ var LINE_UNITS_PER_LINE = 240;
86
62
  function readLineSpacing(pPr) {
87
63
  const spacing = childByLocalName(pPr, "spacing");
88
64
  if (!spacing) return null;
89
- const line = toNumber(wAttr(spacing, "line"));
65
+ const line = ST_SignedTwipsMeasure.parse(wAttr(spacing, "line"));
90
66
  if (line === null) return null;
91
67
  const rule = wAttr(spacing, "lineRule");
92
- if (rule === "exact") return { rule: "exact", pt: round(line / 20) };
93
- if (rule === "atLeast") return { rule: "atLeast", pt: round(line / 20) };
94
- return { rule: "auto", lines: round(line / 240) };
68
+ const pt = round(line / TWIPS_PER_PT);
69
+ if (rule === "exact") return { rule: "exact", pt };
70
+ if (rule === "atLeast") return { rule: "atLeast", pt };
71
+ return { rule: "auto", lines: round(line / LINE_UNITS_PER_LINE) };
95
72
  }
96
73
  function readSpacing(pPr) {
97
74
  const spacing = childByLocalName(pPr, "spacing");
98
75
  if (!spacing) return {};
99
76
  const format = {};
100
- const before = twipsToPt(wAttr(spacing, "before"));
77
+ const before = twipsToPt(ST_TwipsMeasure.parse(wAttr(spacing, "before")));
101
78
  if (before !== null) format.spaceBeforePt = before;
102
- const after = twipsToPt(wAttr(spacing, "after"));
79
+ const after = twipsToPt(ST_TwipsMeasure.parse(wAttr(spacing, "after")));
103
80
  if (after !== null) format.spaceAfterPt = after;
104
81
  const lineSpacing = readLineSpacing(pPr);
105
82
  if (lineSpacing) format.lineSpacing = lineSpacing;
@@ -108,13 +85,13 @@ function readSpacing(pPr) {
108
85
  function readNumbering(pPr) {
109
86
  const numPr = childByLocalName(pPr, "numPr");
110
87
  if (!numPr) return {};
111
- const numId = toNumber(childValue(numPr, "numId"));
88
+ const numId = ST_DecimalNumber.parse(childValue(numPr, "numId"));
112
89
  if (numId === 0) return { numbering: null };
113
90
  if (numId === null || numId < 0) return {};
114
91
  return {
115
92
  numbering: {
116
- numId: Math.trunc(numId),
117
- ilvl: Math.trunc(toNumber(childValue(numPr, "ilvl")) ?? 0)
93
+ numId,
94
+ ilvl: ST_DecimalNumber.parse(childValue(numPr, "ilvl")) ?? 0
118
95
  }
119
96
  };
120
97
  }
@@ -134,34 +111,23 @@ function readParagraphFormat(pPr) {
134
111
  format.direction = isOn(pPr, "bidi") ? "rtl" : "ltr";
135
112
  }
136
113
  if (isOn(pPr, "pageBreakBefore")) format.pageBreakBefore = true;
114
+ if (childByLocalName(pPr, "keepNext")) {
115
+ format.keepNext = isOn(pPr, "keepNext");
116
+ }
137
117
  const background = shadingOf(pPr);
138
118
  if (background) format.background = background;
139
119
  return format;
140
120
  }
121
+ function readRunProperty(format, key, rPr, themeFonts) {
122
+ const value = RUN_PROPERTIES[key].read(rPr, themeFonts);
123
+ if (value !== void 0) format[key] = value;
124
+ }
141
125
  function readRunFormat(rPr, themeFonts = NO_THEME_FONTS) {
142
126
  if (!rPr) return null;
143
127
  const format = {};
144
- if (isOn(rPr, "b")) format.bold = true;
145
- if (isOn(rPr, "i")) format.italic = true;
146
- if (isOn(rPr, "strike")) format.strike = true;
147
- if (isOn(rPr, "smallCaps")) format.smallCaps = true;
148
- const underline = childValue(rPr, "u");
149
- if (isUnderlineKind(underline)) format.underline = underline;
150
- const fontSizePt = halfPointsToPt(childValue(rPr, "sz"));
151
- if (fontSizePt !== null) format.fontSizePt = fontSizePt;
152
- const rFonts = childByLocalName(rPr, "rFonts");
153
- const fontFamily = rFonts ? fontFamilyOf(rFonts, themeFonts) : null;
154
- if (fontFamily) format.fontFamily = fontFamily;
155
- const color = toHexColor(childValue(rPr, "color"));
156
- if (color) format.color = color;
157
- const highlight = childValue(rPr, "highlight");
158
- if (isHighlightName(highlight)) format.highlight = highlight;
159
- const background = shadingOf(rPr);
160
- if (background) format.background = background;
161
- const verticalAlign = VERTICAL_ALIGN_BY_VAL[childValue(rPr, "vertAlign") ?? ""];
162
- if (verticalAlign) format.verticalAlign = verticalAlign;
163
- const lang = langOf(rPr);
164
- if (lang) format.lang = lang;
128
+ for (const key of RUN_FORMAT_KEYS) {
129
+ readRunProperty(format, key, rPr, themeFonts);
130
+ }
165
131
  return format;
166
132
  }
167
133
  var NO_DOCUMENT_DEFAULTS = {
@@ -177,22 +143,30 @@ function defaultProperties(styles, slot, name) {
177
143
  function readDefaultParagraphFormat(styles) {
178
144
  return readParagraphFormat(defaultProperties(styles, "pPrDefault", "pPr")) ?? {};
179
145
  }
146
+ function readRunDefaults(styles, themeFonts = NO_THEME_FONTS) {
147
+ return readRunFormat(defaultProperties(styles, "rPrDefault", "rPr"), themeFonts) ?? {};
148
+ }
149
+ function runStyleIdOf(rPr) {
150
+ const id = rPr ? childValue(rPr, "rStyle") : null;
151
+ return id !== null && id.length > 0 ? id : null;
152
+ }
180
153
  function readDocumentDefaults(styles, themeFonts = NO_THEME_FONTS) {
181
- const rPr = defaultProperties(styles, "rPrDefault", "rPr");
154
+ const run = readRunDefaults(styles, themeFonts);
182
155
  const pPr = defaultProperties(styles, "pPrDefault", "pPr");
183
- const rFonts = rPr ? childByLocalName(rPr, "rFonts") : null;
184
156
  return {
185
- fontSizePt: rPr ? halfPointsToPt(childValue(rPr, "sz")) : null,
186
- fontFamily: rFonts ? fontFamilyOf(rFonts, themeFonts) : null,
157
+ fontSizePt: run.fontSizePt ?? null,
158
+ fontFamily: run.fontFamily ?? null,
187
159
  lineSpacing: pPr ? readLineSpacing(pPr) : null
188
160
  };
189
161
  }
190
162
  export {
163
+ LINE_UNITS_PER_LINE,
191
164
  NO_DOCUMENT_DEFAULTS,
192
- fontNamesOf,
193
165
  readDefaultParagraphFormat,
194
166
  readDocumentDefaults,
195
167
  readLineSpacing,
196
168
  readParagraphFormat,
197
- readRunFormat
169
+ readRunDefaults,
170
+ readRunFormat,
171
+ runStyleIdOf
198
172
  };
@@ -0,0 +1,45 @@
1
+ /**
2
+ * Resolves the §17.7.2 hierarchy for one paragraph and for the runs inside it.
3
+ *
4
+ * The layers are put in order here and nowhere else, so a paragraph's display values are the
5
+ * same whichever path asked for them: opening the document, an edit, a paste, or a paragraph an
6
+ * edit built from nothing.
7
+ */
8
+ import { type ParagraphFormat, type RunFormat } from "../../model/format";
9
+ import type { TabStop } from "../../model/tabStops";
10
+ import type { TableStyleOverrideType } from "../tableFormatting";
11
+ import type { FormattingContext } from "./context";
12
+ /** Where a paragraph sits when it is inside a table cell. null for body text */
13
+ export interface ParagraphPlacement {
14
+ tableStyleId: string | null;
15
+ /**
16
+ * The conditional formats the cell takes, lowest first. Not read yet: a table style
17
+ * contributes the values it lays down for the whole table alone
18
+ */
19
+ conditions: readonly TableStyleOverrideType[];
20
+ }
21
+ /**
22
+ * The layer of the hierarchy a tab stop came from. Removing an inherited stop means writing a
23
+ * `clear` over it, while a direct one is deleted from the paragraph's own list, which is what a
24
+ * ruler needs to tell apart. The document defaults and a table style count as `style`, since a
25
+ * stop from either is taken away the same way
26
+ */
27
+ export type TabStopLayer = "numbering" | "style" | "direct" | "implicit";
28
+ export interface LayeredTabStop extends TabStop {
29
+ layer: TabStopLayer;
30
+ }
31
+ export interface ResolvedParagraph {
32
+ /** `format` in `schema`: docDefaults < table style < numbering level < paragraph style < direct */
33
+ format: ParagraphFormat | null;
34
+ /** `styleRun` in `schema`: run defaults < table style rPr < paragraph style rPr. Default font and size stay in CSS variables */
35
+ styleRun: RunFormat | null;
36
+ /** Everything below a run's own formatting, docDefaults included. What a removed run property falls back to */
37
+ inheritedRun: RunFormat;
38
+ /** The stops `format.tabStops` holds, each with the layer that laid it down */
39
+ tabStops: readonly LayeredTabStop[];
40
+ }
41
+ export declare function resolveParagraph(pPr: string | null, context: FormattingContext, placement?: ParagraphPlacement | null): ResolvedParagraph;
42
+ /** `format` on a run mark: paragraph.styleRun < character style < the run's own rPr */
43
+ export declare function resolveRun(rPr: string | null, paragraph: ResolvedParagraph, context: FormattingContext): RunFormat | null;
44
+ /** paragraph.inheritedRun < character style. What a run property taken out of the rPr falls back to */
45
+ export declare function inheritedRunFormat(rPr: string | null, paragraph: ResolvedParagraph, context: FormattingContext): RunFormat;
@@ -0,0 +1,140 @@
1
+ // src/docx/formatting/resolve.ts
2
+ import {
3
+ toParagraphFormat
4
+ } from "../../model/format.js";
5
+ import {
6
+ levelIndentPt
7
+ } from "../../numbering/parseNumbering.js";
8
+ import { parsePropsXml } from "../../ooxml/props.js";
9
+ import { readParagraphFormat, readRunFormat, runStyleIdOf } from "./direct.js";
10
+ import {
11
+ layerRunFormat,
12
+ paragraphStyleFormat
13
+ } from "./styles.js";
14
+ function directLayer(pPr) {
15
+ return pPr === null ? {} : readParagraphFormat(parsePropsXml(pPr)) ?? {};
16
+ }
17
+ function tableStyleOf(placement, context) {
18
+ const id = placement?.tableStyleId ?? null;
19
+ return id === null ? void 0 : context.styles.get(id);
20
+ }
21
+ function numberingLevelOf(layers, context) {
22
+ const ref = layers.reduce(
23
+ (found, layer) => layer.numbering === void 0 ? found : layer.numbering,
24
+ void 0
25
+ );
26
+ if (!ref) return void 0;
27
+ return context.numbering.lists.get(ref.numId)?.levels.get(ref.ilvl);
28
+ }
29
+ function numberingLayer(level) {
30
+ return level?.tabStops ? { tabStops: level.tabStops } : {};
31
+ }
32
+ function layerValues(base, over) {
33
+ const { tabStops: _stops, ...values } = over;
34
+ return { ...base, ...values };
35
+ }
36
+ function byPosition(left, right) {
37
+ return left.positionPt - right.positionPt;
38
+ }
39
+ function explicitStops(layers) {
40
+ const spoken = /* @__PURE__ */ new Map();
41
+ for (const { values, stops } of layers) {
42
+ for (const stop of values.tabStops ?? []) {
43
+ spoken.set(stop.positionPt, { stop, layer: stops });
44
+ }
45
+ }
46
+ return [...spoken.values()].flatMap(
47
+ ({ stop, layer }) => stop.align === "clear" ? [] : [{ ...stop, layer }]
48
+ ).sort(byPosition);
49
+ }
50
+ function hangingStopPt(values, level) {
51
+ const leading = values.indentStartPt ?? values.indentLeftPt ?? level.startPt;
52
+ const textIndent = values.textIndentPt ?? level.textIndentPt;
53
+ return leading !== null && textIndent !== null && textIndent < 0 ? leading : null;
54
+ }
55
+ function withImplicitStop(stops, positionPt) {
56
+ if (positionPt === null) return stops;
57
+ if (stops.some((stop) => stop.positionPt === positionPt)) return stops;
58
+ const implicit = {
59
+ positionPt,
60
+ align: "start",
61
+ layer: "implicit"
62
+ };
63
+ return [...stops, implicit].sort(byPosition);
64
+ }
65
+ function orNull(values) {
66
+ return Object.keys(values).length === 0 ? null : values;
67
+ }
68
+ function resolveParagraph(pPr, context, placement = null) {
69
+ const tableStyle = tableStyleOf(placement, context);
70
+ const style = paragraphStyleFormat(
71
+ pPr,
72
+ context.styles,
73
+ context.defaultParagraphStyleId
74
+ );
75
+ const direct = directLayer(pPr);
76
+ const explicit = [
77
+ { values: context.paragraphDefaults, stops: "style" },
78
+ { values: tableStyle?.paragraph ?? {}, stops: "style" },
79
+ { values: style?.paragraph ?? {}, stops: "style" },
80
+ { values: direct, stops: "direct" }
81
+ ];
82
+ const level = numberingLevelOf(
83
+ explicit.map((layer) => layer.values),
84
+ context
85
+ );
86
+ const layers = [
87
+ ...explicit.slice(0, 2),
88
+ { values: numberingLayer(level), stops: "numbering" },
89
+ ...explicit.slice(2)
90
+ ];
91
+ const values = layers.reduce(
92
+ (base, layer) => layerValues(base, layer.values),
93
+ {}
94
+ );
95
+ const stops = explicitStops(layers);
96
+ const tabStops = context.compat.noTabHangInd ? stops : withImplicitStop(
97
+ stops,
98
+ hangingStopPt(values, levelIndentPt(level?.indent ?? null))
99
+ );
100
+ const format = toParagraphFormat(values) ?? {};
101
+ if (tabStops.length > 0) {
102
+ format.tabStops = tabStops.map(({ layer: _layer, ...stop }) => stop);
103
+ }
104
+ const {
105
+ fontSizePt: _size,
106
+ fontFamily: _font,
107
+ ...displayDefaults
108
+ } = context.runDefaults;
109
+ const styleRun = {
110
+ ...displayDefaults,
111
+ ...tableStyle?.run,
112
+ ...style?.run
113
+ };
114
+ return {
115
+ format: orNull(format),
116
+ styleRun: orNull(styleRun),
117
+ inheritedRun: { ...context.runDefaults, ...styleRun },
118
+ tabStops
119
+ };
120
+ }
121
+ function characterStyleRun(rPr, context) {
122
+ const id = runStyleIdOf(rPr);
123
+ return id === null ? {} : context.styles.get(id)?.run ?? {};
124
+ }
125
+ function resolveRun(rPr, paragraph, context) {
126
+ const el = rPr === null ? null : parsePropsXml(rPr);
127
+ return layerRunFormat(
128
+ { ...paragraph.styleRun, ...characterStyleRun(el, context) },
129
+ readRunFormat(el, context.themeFonts)
130
+ );
131
+ }
132
+ function inheritedRunFormat(rPr, paragraph, context) {
133
+ const el = rPr === null ? null : parsePropsXml(rPr);
134
+ return { ...paragraph.inheritedRun, ...characterStyleRun(el, context) };
135
+ }
136
+ export {
137
+ inheritedRunFormat,
138
+ resolveParagraph,
139
+ resolveRun
140
+ };
@@ -0,0 +1,93 @@
1
+ /**
2
+ * One row per run property: what it reads out of an rPr, what it writes into one, and whether
3
+ * text already carries a value.
4
+ *
5
+ * Reading, writing and comparing used to be three hand-kept copies of the same vocabulary, so a
6
+ * property could be read under one name and written under another. Here each is one row, and the
7
+ * readers and writers below walk the table, so anything else that has to speak for a run
8
+ * property - a tracked change's `w:rPrChange` snapshot, a style's `w:rPr` - asks the same row.
9
+ *
10
+ * The values read are for display only. What goes back into the document is the rPr string, and
11
+ * a write is a list of children swapped into it (`ooxml/props`), never a tree serialized again.
12
+ */
13
+ import { type RunFormat } from "../../model/format";
14
+ import { type Props } from "../../ooxml/props";
15
+ import { type ThemeFonts } from "../theme";
16
+ /** What text one child of the rPr is to be changed to. A null xml removes that child */
17
+ export type ChildEdit = readonly [name: string, xml: string | null];
18
+ /** What an edit is written against: the rPr as it stands, and everything the layers below the run lay down */
19
+ export interface RunEditContext {
20
+ rPr: Props;
21
+ inherited: RunFormat;
22
+ }
23
+ type Read<K extends keyof RunFormat> = NonNullable<RunFormat[K]>;
24
+ /**
25
+ * The value an edit sets. An off - `false`, an underline of `none` - is not one: it is spelled
26
+ * as null, the withdrawal, and pinned into the rPr only where the layers below would otherwise
27
+ * show through.
28
+ */
29
+ export type RunSetting<K extends keyof RunFormat> = Exclude<Read<K>, false | "none">;
30
+ /** A run property as it is read and compared. `R` is the value read, `S` the value an edit sets */
31
+ export interface RunProperty<R, S> {
32
+ /**
33
+ * The rPr children the property owns, in the order CT_RPr lays them down. A `w:rPrChange`
34
+ * snapshot of the property is exactly these
35
+ */
36
+ readonly children: readonly string[];
37
+ read(rPr: Element, themeFonts: ThemeFonts): R | undefined;
38
+ /** Whether the display values switch or paint the property on, which is what a withdrawal has to undo */
39
+ isOn(format: RunFormat): boolean;
40
+ /** Whether the display values already carry the value, so that writing it would change nothing */
41
+ matches(format: RunFormat, value: S): boolean;
42
+ }
43
+ /** A run property an edit may write as well */
44
+ export interface EditableRunProperty<R, S> extends RunProperty<R, S> {
45
+ /** The children that make the run say the value. null for a value the document cannot record */
46
+ write(value: S, context: RunEditContext): ChildEdit[] | null;
47
+ /** The children that take the run's own say away, pinned off where the layers below would otherwise show through */
48
+ off(context: RunEditContext): ChildEdit[];
49
+ }
50
+ /** The properties read for display alone. Nothing writes them, so no edit names them */
51
+ declare const DISPLAY_ONLY_RUN_KEYS: readonly ["lang"];
52
+ type DisplayOnlyRunKey = (typeof DISPLAY_ONLY_RUN_KEYS)[number];
53
+ export type EditableRunKey = Exclude<keyof RunFormat, DisplayOnlyRunKey>;
54
+ /**
55
+ * A job that changes one run property. A null value withdraws the run's own setting: the layers
56
+ * below stand again, except where they would switch or paint the property on, in which case the
57
+ * off is pinned into the run.
58
+ */
59
+ export type RunEdit<K extends EditableRunKey = EditableRunKey> = {
60
+ [P in K]: {
61
+ key: P;
62
+ value: RunSetting<P> | null;
63
+ };
64
+ }[K];
65
+ /** The settings an rPr built from nothing records */
66
+ export type RunSettings = {
67
+ [K in EditableRunKey]?: RunSetting<K>;
68
+ };
69
+ /** The editable properties, in the order they are read */
70
+ export declare const EDITABLE_RUN_KEYS: readonly EditableRunKey[];
71
+ /**
72
+ * The font names held in a display value.
73
+ * Splits the CSS name list `fontFamilyOf` produced back into individual names.
74
+ */
75
+ export declare function fontNamesOf(cssNames: string | undefined | null): string[];
76
+ export declare const RUN_PROPERTIES: {
77
+ [K in keyof Required<RunFormat>]: RunProperty<Read<K>, RunSetting<K>>;
78
+ };
79
+ /** Which children of the rPr one job changes and how. null for a value whose meaning cannot be made out */
80
+ export declare function runChildEdits<K extends EditableRunKey>(edit: RunEdit<K>, context: RunEditContext): ChildEdit[] | null;
81
+ /** Whether this text is already in the state the job wants. If it already is, we leave it untouched */
82
+ export declare function matchesRunEdit<K extends EditableRunKey>(format: RunFormat | null, edit: RunEdit<K>): boolean;
83
+ /** The rPr with these children swapped in */
84
+ export declare function withChildEdits(rPr: Props, edits: readonly ChildEdit[]): Props;
85
+ /** Turning formatting on for a run with no formatting creates a minimal rPr from scratch */
86
+ export declare const EMPTY_RUN_PROPS: Props;
87
+ /**
88
+ * A whole rPr recording these settings, built from nothing, and null where they record nothing.
89
+ * A setting the document cannot record is left out, the way an edit refusing it leaves the run
90
+ * as it was.
91
+ */
92
+ export declare function rPrOf(settings: RunSettings): string | null;
93
+ export {};