@portone/docx-editor 0.2.0 → 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 (256) hide show
  1. package/CHANGELOG.md +174 -0
  2. package/CONTRIBUTING.md +9 -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 +14 -7
  10. package/dist/docx/commentOnlyChange.js +9 -139
  11. package/dist/docx/comments/constants.d.ts +3 -4
  12. package/dist/docx/comments/constants.js +4 -5
  13. package/dist/docx/comments/grammar.d.ts +86 -0
  14. package/dist/docx/comments/grammar.js +223 -0
  15. package/dist/docx/comments/parts.d.ts +52 -0
  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 +28 -106
  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.d.ts +5 -3
  22. package/dist/docx/comments/reading.js +30 -29
  23. package/dist/docx/comments/writing.d.ts +19 -7
  24. package/dist/docx/comments/writing.js +105 -137
  25. package/dist/docx/documentSettings.d.ts +7 -0
  26. package/dist/docx/documentSettings.js +10 -2
  27. package/dist/docx/exportDocx.d.ts +40 -5
  28. package/dist/docx/exportDocx.js +71 -72
  29. package/dist/docx/exportRefs.d.ts +5 -2
  30. package/dist/docx/exportRefs.js +3 -1
  31. package/dist/docx/fidelity.d.ts +43 -0
  32. package/dist/docx/fidelity.js +64 -0
  33. package/dist/docx/formatting/attrs.d.ts +27 -0
  34. package/dist/docx/formatting/attrs.js +31 -0
  35. package/dist/docx/formatting/context.d.ts +31 -0
  36. package/dist/docx/formatting/context.js +42 -0
  37. package/dist/docx/formatting/direct.d.ts +6 -5
  38. package/dist/docx/formatting/direct.js +52 -81
  39. package/dist/docx/formatting/resolve.d.ts +45 -0
  40. package/dist/docx/formatting/resolve.js +140 -0
  41. package/dist/docx/formatting/runProperties.d.ts +93 -0
  42. package/dist/docx/formatting/runProperties.js +316 -0
  43. package/dist/docx/formatting/styles.js +3 -3
  44. package/dist/docx/formatting/tabStops.js +7 -22
  45. package/dist/docx/formatting.d.ts +4 -1
  46. package/dist/docx/formatting.js +4 -1
  47. package/dist/docx/headersFooters.js +13 -22
  48. package/dist/docx/identities.d.ts +67 -0
  49. package/dist/docx/identities.js +174 -0
  50. package/dist/docx/importDocx.d.ts +12 -1
  51. package/dist/docx/importDocx.js +72 -79
  52. package/dist/docx/importParagraph.d.ts +1 -1
  53. package/dist/docx/importParagraph.js +4 -3
  54. package/dist/docx/importTable.d.ts +1 -1
  55. package/dist/docx/importTable.js +17 -1
  56. package/dist/docx/invariants.d.ts +33 -0
  57. package/dist/docx/invariants.js +256 -0
  58. package/dist/docx/media.d.ts +6 -4
  59. package/dist/docx/media.js +6 -37
  60. package/dist/docx/newLists.d.ts +20 -0
  61. package/dist/docx/newLists.js +36 -0
  62. package/dist/docx/notes.js +6 -12
  63. package/dist/docx/numberingPlanner.d.ts +8 -0
  64. package/dist/docx/numberingPlanner.js +19 -0
  65. package/dist/docx/packageParts.d.ts +42 -0
  66. package/dist/docx/packageParts.js +135 -0
  67. package/dist/docx/pageGeometry.d.ts +2 -0
  68. package/dist/docx/pageGeometry.js +18 -9
  69. package/dist/docx/paraProps.d.ts +10 -22
  70. package/dist/docx/paraProps.js +75 -99
  71. package/dist/docx/partPlan.d.ts +36 -0
  72. package/dist/docx/partPlan.js +59 -0
  73. package/dist/docx/protectionPolicy.d.ts +127 -0
  74. package/dist/docx/protectionPolicy.js +169 -0
  75. package/dist/docx/relationships.d.ts +1 -1
  76. package/dist/docx/relationships.js +15 -15
  77. package/dist/docx/runProps.d.ts +9 -22
  78. package/dist/docx/runProps.js +15 -168
  79. package/dist/docx/scan.js +20 -52
  80. package/dist/docx/sdt.js +14 -37
  81. package/dist/docx/sdtProps.d.ts +8 -1
  82. package/dist/docx/sdtProps.js +10 -0
  83. package/dist/docx/serializeBlock.d.ts +2 -0
  84. package/dist/docx/serializeBlock.js +9 -7
  85. package/dist/docx/serializeParagraph.d.ts +2 -1
  86. package/dist/docx/serializeParagraph.js +25 -14
  87. package/dist/docx/serializeTable.js +63 -32
  88. package/dist/docx/session.d.ts +42 -14
  89. package/dist/docx/session.js +43 -17
  90. package/dist/docx/storyProjection.d.ts +36 -0
  91. package/dist/docx/storyProjection.js +23 -0
  92. package/dist/docx/tableFormatting/editing.js +130 -185
  93. package/dist/docx/tableFormatting/reading.d.ts +16 -6
  94. package/dist/docx/tableFormatting/reading.js +40 -20
  95. package/dist/docx/tableTemplate.js +37 -5
  96. package/dist/docx/theme.d.ts +0 -6
  97. package/dist/docx/theme.js +0 -8
  98. package/dist/download.d.ts +8 -5
  99. package/dist/download.js +2 -0
  100. package/dist/editor/clipboard/images.js +17 -3
  101. package/dist/editor/clipboard/inlineFormatting.d.ts +7 -0
  102. package/dist/editor/clipboard/inlineFormatting.js +20 -30
  103. package/dist/editor/commands/breakCommands.js +4 -3
  104. package/dist/editor/commands/canRunCommand.d.ts +2 -2
  105. package/dist/editor/commands/canRunCommand.js +1 -1
  106. package/dist/editor/commands/comments/editing.d.ts +6 -2
  107. package/dist/editor/commands/comments/editing.js +21 -36
  108. package/dist/editor/commands/exportQueries.d.ts +15 -0
  109. package/dist/editor/commands/exportQueries.js +14 -0
  110. package/dist/editor/commands/fidelityQueries.d.ts +12 -0
  111. package/dist/editor/commands/fidelityQueries.js +8 -0
  112. package/dist/editor/commands/formatting/editing.d.ts +2 -2
  113. package/dist/editor/commands/formatting/editing.js +26 -108
  114. package/dist/editor/commands/formatting/propertyCommands.d.ts +21 -0
  115. package/dist/editor/commands/formatting/propertyCommands.js +103 -0
  116. package/dist/editor/commands/formatting/shared.d.ts +3 -3
  117. package/dist/editor/commands/formatting/shared.js +5 -2
  118. package/dist/editor/commands/historyCommands.js +2 -1
  119. package/dist/editor/commands/indentCommands.js +5 -4
  120. package/dist/editor/commands/index.d.ts +11 -0
  121. package/dist/editor/commands/index.js +5 -0
  122. package/dist/editor/commands/linkCommands.js +5 -6
  123. package/dist/editor/commands/listCommands.js +8 -10
  124. package/dist/editor/commands/lockCommands.d.ts +7 -1
  125. package/dist/editor/commands/lockCommands.js +35 -37
  126. package/dist/editor/commands/paragraphCommands.js +28 -31
  127. package/dist/editor/commands/spacingCommands.js +1 -1
  128. package/dist/editor/commands/tabCommands.js +4 -3
  129. package/dist/editor/createEditor.d.ts +17 -29
  130. package/dist/editor/createEditor.js +61 -67
  131. package/dist/editor/documentStyles.d.ts +11 -35
  132. package/dist/editor/documentStyles.js +9 -52
  133. package/dist/editor/editorDocument.d.ts +56 -0
  134. package/dist/editor/editorDocument.js +74 -0
  135. package/dist/editor/externalClipboard.js +166 -33
  136. package/dist/editor/insertImage.js +4 -3
  137. package/dist/editor/insertTable.js +4 -3
  138. package/dist/editor/paragraphEdits.d.ts +11 -18
  139. package/dist/editor/paragraphEdits.js +7 -16
  140. package/dist/editor/plugins/displayDerivation.d.ts +47 -0
  141. package/dist/editor/plugins/displayDerivation.js +78 -0
  142. package/dist/editor/plugins/documentProtection.d.ts +3 -3
  143. package/dist/editor/plugins/imagePaste.js +4 -3
  144. package/dist/editor/plugins/keymap.js +18 -3
  145. package/dist/editor/plugins/lockedContent.d.ts +4 -4
  146. package/dist/editor/plugins/lockedContent.js +1 -1
  147. package/dist/editor/plugins/numberingDecorations.d.ts +5 -11
  148. package/dist/editor/plugins/numberingDecorations.js +7 -17
  149. package/dist/editor/plugins/paragraphDisplay.d.ts +7 -0
  150. package/dist/editor/plugins/paragraphDisplay.js +51 -0
  151. package/dist/editor/plugins/tabLayout.js +1 -1
  152. package/dist/editor/plugins/tableDisplay.d.ts +6 -0
  153. package/dist/editor/plugins/tableDisplay.js +16 -0
  154. package/dist/index.d.ts +2 -0
  155. package/dist/model/format.d.ts +30 -8
  156. package/dist/model/format.js +35 -22
  157. package/dist/model/tabStops.d.ts +9 -0
  158. package/dist/model/tabStops.js +18 -0
  159. package/dist/numbering/listTemplate.js +49 -10
  160. package/dist/numbering/parseNumbering.d.ts +14 -1
  161. package/dist/numbering/parseNumbering.js +35 -22
  162. package/dist/numbering/writeNumbering.d.ts +3 -4
  163. package/dist/numbering/writeNumbering.js +14 -25
  164. package/dist/ooxml/childOrder.d.ts +34 -0
  165. package/dist/ooxml/childOrder.js +496 -0
  166. package/dist/ooxml/element.d.ts +65 -0
  167. package/dist/ooxml/element.js +68 -0
  168. package/dist/ooxml/errors.d.ts +3 -2
  169. package/dist/ooxml/fragment.d.ts +53 -0
  170. package/dist/ooxml/fragment.js +76 -0
  171. package/dist/ooxml/image.d.ts +4 -0
  172. package/dist/ooxml/image.js +3 -5
  173. package/dist/ooxml/names.d.ts +27 -0
  174. package/dist/ooxml/names.js +29 -0
  175. package/dist/ooxml/partSplice.d.ts +67 -0
  176. package/dist/ooxml/partSplice.js +169 -0
  177. package/dist/ooxml/precedence.d.ts +31 -0
  178. package/dist/ooxml/precedence.js +51 -0
  179. package/dist/ooxml/props.d.ts +112 -0
  180. package/dist/ooxml/props.js +214 -0
  181. package/dist/ooxml/simpleTypes.d.ts +103 -0
  182. package/dist/ooxml/simpleTypes.js +182 -0
  183. package/dist/ooxml/tabStops.js +8 -27
  184. package/dist/ooxml/tagScan.d.ts +34 -0
  185. package/dist/ooxml/tagScan.js +108 -0
  186. package/dist/ooxml/units.d.ts +25 -13
  187. package/dist/ooxml/units.js +65 -31
  188. package/dist/ooxml/xml.d.ts +52 -0
  189. package/dist/ooxml/xml.js +64 -5
  190. package/dist/page/blockKinds.d.ts +103 -0
  191. package/dist/page/blockKinds.js +11 -0
  192. package/dist/page/kinds/index.d.ts +6 -0
  193. package/dist/page/kinds/index.js +10 -0
  194. package/dist/page/kinds/paragraphKind.d.ts +10 -0
  195. package/dist/page/kinds/paragraphKind.js +71 -0
  196. package/dist/page/kinds/tableKind.d.ts +10 -0
  197. package/dist/page/kinds/tableKind.js +178 -0
  198. package/dist/page/measureBlocks.d.ts +3 -1
  199. package/dist/page/measureBlocks.js +24 -25
  200. package/dist/page/pageDecorations.d.ts +27 -28
  201. package/dist/page/pageDecorations.js +70 -151
  202. package/dist/page/pageLayout.d.ts +10 -62
  203. package/dist/page/pageLayout.js +60 -53
  204. package/dist/page/usePageLayout.d.ts +2 -2
  205. package/dist/page/usePageLayout.js +3 -11
  206. package/dist/schema/attrRoles.d.ts +42 -0
  207. package/dist/schema/attrRoles.js +141 -0
  208. package/dist/schema/displayDerivation.d.ts +82 -0
  209. package/dist/schema/displayDerivation.js +130 -0
  210. package/dist/schema/docxSchema.d.ts +9 -0
  211. package/dist/schema/docxSchema.js +237 -114
  212. package/dist/schema/editGuard.d.ts +99 -0
  213. package/dist/schema/editGuard.js +43 -0
  214. package/dist/schema/guards.d.ts +91 -0
  215. package/dist/schema/guards.js +108 -0
  216. package/dist/schema/index.d.ts +2 -0
  217. package/dist/schema/index.js +2 -0
  218. package/dist/schema/locks.d.ts +17 -77
  219. package/dist/schema/locks.js +26 -70
  220. package/dist/schema/preservedGuards.d.ts +50 -0
  221. package/dist/schema/preservedGuards.js +80 -0
  222. package/dist/schema/protection.d.ts +17 -4
  223. package/dist/schema/protection.js +4 -2
  224. package/dist/schema/sourceEquality.d.ts +19 -0
  225. package/dist/schema/sourceEquality.js +39 -0
  226. package/dist/styles/inlineStyle.js +15 -6
  227. package/dist/table/cellFormatting.d.ts +8 -1
  228. package/dist/table/cellFormatting.js +10 -17
  229. package/dist/table/commands.d.ts +2 -2
  230. package/dist/table/commands.js +20 -18
  231. package/dist/table/format.d.ts +3 -0
  232. package/dist/table/format.js +3 -9
  233. package/dist/table/gridBorders.d.ts +14 -16
  234. package/dist/table/gridBorders.js +3 -41
  235. package/dist/table/index.d.ts +2 -2
  236. package/dist/table/merge.d.ts +4 -8
  237. package/dist/table/merge.js +5 -5
  238. package/package.json +10 -3
  239. package/dist/docx/comments/contentTypes.d.ts +0 -7
  240. package/dist/docx/comments/contentTypes.js +0 -38
  241. package/dist/docx/formatting/effectiveParagraph.d.ts +0 -15
  242. package/dist/docx/formatting/effectiveParagraph.js +0 -81
  243. package/dist/docx/propsXml.d.ts +0 -49
  244. package/dist/docx/propsXml.js +0 -302
  245. package/dist/docx/uniqueControls.d.ts +0 -14
  246. package/dist/docx/uniqueControls.js +0 -62
  247. package/dist/editor/plugins/bookmarkProtection.d.ts +0 -3
  248. package/dist/editor/plugins/bookmarkProtection.js +0 -28
  249. package/dist/editor/plugins/commentReservations.d.ts +0 -5
  250. package/dist/editor/plugins/commentReservations.js +0 -26
  251. package/dist/editor/plugins/noteProtection.d.ts +0 -3
  252. package/dist/editor/plugins/noteProtection.js +0 -25
  253. package/dist/editor/plugins/styledParagraphs.d.ts +0 -15
  254. package/dist/editor/plugins/styledParagraphs.js +0 -65
  255. package/dist/page/tableMeasurements.d.ts +0 -10
  256. package/dist/page/tableMeasurements.js +0 -115
@@ -0,0 +1,316 @@
1
+ // src/docx/formatting/runProperties.ts
2
+ import {
3
+ isHighlightName,
4
+ isUnderlineKind,
5
+ NO_FILL,
6
+ RUN_FORMAT_KEYS
7
+ } from "../../model/format.js";
8
+ import { elementXml, wAttrValue } from "../../ooxml/element.js";
9
+ import { wName } from "../../ooxml/names.js";
10
+ import { overridingAttrs, setAttr } from "../../ooxml/precedence.js";
11
+ import {
12
+ attrsOf,
13
+ parseProps,
14
+ propsChild,
15
+ renderProps,
16
+ setChild
17
+ } from "../../ooxml/props.js";
18
+ import {
19
+ HALF_POINTS_PER_PT,
20
+ ST_HpsMeasure,
21
+ ST_SignedTwipsMeasure,
22
+ TWIPS_PER_PT
23
+ } from "../../ooxml/simpleTypes.js";
24
+ import {
25
+ childValue,
26
+ halfPointsToPt,
27
+ isOnElement,
28
+ normalizeHex,
29
+ shadingOf,
30
+ toHexColor,
31
+ twipsToPt,
32
+ wAttr
33
+ } from "../../ooxml/units.js";
34
+ import { childByLocalName } from "../../ooxml/xml.js";
35
+ import { isEastAsianFontName } from "../../styles/fontStack.js";
36
+ import { themeFontName } from "../theme.js";
37
+ var DISPLAY_ONLY_RUN_KEYS = ["lang"];
38
+ function isEditableRunKey(key) {
39
+ return !DISPLAY_ONLY_RUN_KEYS.some((display) => display === key);
40
+ }
41
+ var EDITABLE_RUN_KEYS = RUN_FORMAT_KEYS.filter(isEditableRunKey);
42
+ function valXml(name, value) {
43
+ return elementXml(wName(name), value === null ? [] : [[wName("val"), value]]);
44
+ }
45
+ function shadingXml(fill) {
46
+ return elementXml(wName("shd"), [
47
+ [wName("val"), "clear"],
48
+ [wName("color"), "auto"],
49
+ [wName("fill"), fill]
50
+ ]);
51
+ }
52
+ function toggleState(rPr, name) {
53
+ const toggle2 = childByLocalName(rPr, name);
54
+ return toggle2 ? isOnElement(toggle2) : null;
55
+ }
56
+ function fontNamesOf(cssNames) {
57
+ if (!cssNames) return [];
58
+ return cssNames.split(",").map((name) => name.trim().replace(/^"|"$/g, "")).filter((name) => name.length > 0);
59
+ }
60
+ var FONT_SLOTS = ["ascii", "eastAsia", "hAnsi", "cs"];
61
+ function slotFontName(rFonts, slot, themeFonts) {
62
+ const written2 = wAttr(rFonts, slot);
63
+ if (written2 !== null) return written2;
64
+ for (const attr of overridingAttrs("rFonts", slot)) {
65
+ const resolved = themeFontName(themeFonts, wAttr(rFonts, attr));
66
+ if (resolved !== null) return resolved;
67
+ }
68
+ return null;
69
+ }
70
+ function fontFamilyOf(rFonts, themeFonts) {
71
+ const names = FONT_SLOTS.map((slot) => slotFontName(rFonts, slot, themeFonts)).filter((name) => name !== null).filter((name) => name.length > 0 && !/["';\\]/.test(name));
72
+ const unique = Array.from(new Set(names));
73
+ return unique.length > 0 ? unique.map((name) => `"${name}"`).join(",") : null;
74
+ }
75
+ var LATIN_SLOTS = ["ascii", "hAnsi"];
76
+ var EAST_ASIAN_SLOTS = [...LATIN_SLOTS, "eastAsia"];
77
+ function fontSlots(name, hasComplexScript) {
78
+ const slots = isEastAsianFontName(name) ? EAST_ASIAN_SLOTS : LATIN_SLOTS;
79
+ return hasComplexScript ? [...slots, "cs"] : slots;
80
+ }
81
+ function fontName(value) {
82
+ const name = value.trim();
83
+ return name.length > 0 && !/["';<>&]/.test(name) ? name : null;
84
+ }
85
+ function rFontsXml(current, name) {
86
+ const props = current === null ? null : parseProps(current);
87
+ const attrs = props === null ? [] : attrsOf(props);
88
+ if (current !== null && props === null || attrs === null) return null;
89
+ const slots = fontSlots(name, wAttrValue(attrs, "cs") !== null);
90
+ const kept = slots.reduce(
91
+ (rest, slot) => setAttr(rest, "rFonts", slot, null),
92
+ attrs
93
+ );
94
+ return elementXml(wName("rFonts"), [
95
+ ...slots.map((slot) => [wName(slot), name]),
96
+ ...kept
97
+ ]);
98
+ }
99
+ function langOf(rPr) {
100
+ const lang = childByLocalName(rPr, "lang");
101
+ if (!lang) return null;
102
+ const eastAsia = wAttr(lang, "eastAsia");
103
+ if (eastAsia !== null && eastAsia.length > 0) return eastAsia;
104
+ const value = wAttr(lang, "val");
105
+ return value !== null && value.length > 0 ? value : null;
106
+ }
107
+ var VERTICAL_ALIGN_BY_VAL = {
108
+ superscript: "superscript",
109
+ subscript: "subscript"
110
+ };
111
+ function removed(children) {
112
+ return children.map((name) => [name, null]);
113
+ }
114
+ function toggle(key, name, ...twins) {
115
+ const children = [name, ...twins];
116
+ const isOn = (format) => format[key] === true;
117
+ return {
118
+ children,
119
+ read: (rPr) => toggleState(rPr, name) ?? void 0,
120
+ isOn,
121
+ matches: isOn,
122
+ write: () => children.map((child) => [child, valXml(child, null)]),
123
+ off: ({ inherited }) => isOn(inherited) ? children.map((child) => [child, valXml(child, "0")]) : removed(children)
124
+ };
125
+ }
126
+ var UNDERLINE = {
127
+ children: ["u"],
128
+ read: (rPr) => {
129
+ const kind = childValue(rPr, "u");
130
+ return isUnderlineKind(kind) || kind === "none" ? kind : void 0;
131
+ },
132
+ isOn: (format) => format.underline !== void 0 && format.underline !== "none",
133
+ matches: (format, kind) => format.underline === kind,
134
+ write: (kind) => [["u", valXml("u", kind)]],
135
+ off: ({ inherited }) => [
136
+ ["u", UNDERLINE.isOn(inherited) ? valXml("u", "none") : null]
137
+ ]
138
+ };
139
+ var FONT_SIZE = {
140
+ children: ["sz", "szCs"],
141
+ read: (rPr) => halfPointsToPt(ST_HpsMeasure.parse(childValue(rPr, "sz"))) ?? void 0,
142
+ isOn: (format) => format.fontSizePt !== void 0,
143
+ matches: (format, pt) => format.fontSizePt === pt,
144
+ write: (pt) => {
145
+ const half = ST_HpsMeasure.format(pt * HALF_POINTS_PER_PT);
146
+ return half === null ? null : [
147
+ ["sz", valXml("sz", half)],
148
+ ["szCs", valXml("szCs", half)]
149
+ ];
150
+ },
151
+ off: () => removed(FONT_SIZE.children)
152
+ };
153
+ var CHARACTER_SPACING = {
154
+ children: ["spacing"],
155
+ read: (rPr) => twipsToPt(ST_SignedTwipsMeasure.parse(childValue(rPr, "spacing"))) ?? void 0,
156
+ isOn: (format) => format.characterSpacingPt !== void 0,
157
+ matches: (format, pt) => format.characterSpacingPt === pt,
158
+ write: (pt) => {
159
+ const twips = ST_SignedTwipsMeasure.format(Math.round(pt * TWIPS_PER_PT));
160
+ return twips === null ? null : [["spacing", valXml("spacing", twips)]];
161
+ },
162
+ off: () => removed(CHARACTER_SPACING.children)
163
+ };
164
+ var FONT_FAMILY = {
165
+ children: ["rFonts"],
166
+ read: (rPr, themeFonts) => {
167
+ const rFonts = childByLocalName(rPr, "rFonts");
168
+ return rFonts ? fontFamilyOf(rFonts, themeFonts) ?? void 0 : void 0;
169
+ },
170
+ isOn: (format) => fontNamesOf(format.fontFamily).length > 0,
171
+ matches: (format, name) => {
172
+ const names = fontNamesOf(format.fontFamily);
173
+ return names.length === 1 && names[0] === fontName(name);
174
+ },
175
+ write: (name, { rPr }) => {
176
+ const clean = fontName(name);
177
+ if (clean === null) return null;
178
+ const xml = rFontsXml(
179
+ propsChild(rPr.children, "rFonts")?.xml ?? null,
180
+ clean
181
+ );
182
+ return xml === null ? null : [["rFonts", xml]];
183
+ },
184
+ off: () => removed(FONT_FAMILY.children)
185
+ };
186
+ var COLOR = {
187
+ children: ["color"],
188
+ read: (rPr) => toHexColor(childValue(rPr, "color")) ?? void 0,
189
+ isOn: (format) => format.color !== void 0,
190
+ // Colors differing only in capitalization are the same color
191
+ matches: (format, hex) => format.color !== void 0 && normalizeHex(format.color) === normalizeHex(hex),
192
+ write: (hex) => {
193
+ const value = normalizeHex(hex);
194
+ return value === null ? null : [["color", valXml("color", value)]];
195
+ },
196
+ off: ({ inherited }) => [
197
+ ["color", inherited.color === void 0 ? null : valXml("color", "auto")]
198
+ ]
199
+ };
200
+ var HIGHLIGHT = {
201
+ children: ["highlight"],
202
+ read: (rPr) => {
203
+ const name = childValue(rPr, "highlight");
204
+ return isHighlightName(name) ? name : void 0;
205
+ },
206
+ isOn: (format) => format.highlight !== void 0,
207
+ matches: (format, name) => format.highlight === name,
208
+ write: (name) => [["highlight", valXml("highlight", name)]],
209
+ off: ({ inherited }) => [
210
+ [
211
+ "highlight",
212
+ inherited.highlight === void 0 ? null : valXml("highlight", "none")
213
+ ]
214
+ ]
215
+ };
216
+ var BACKGROUND = {
217
+ children: ["highlight", "shd"],
218
+ read: (rPr) => shadingOf(rPr) ?? void 0,
219
+ isOn: (format) => format.highlight !== void 0 || format.background !== void 0 && format.background !== NO_FILL,
220
+ matches: (format, hex) => {
221
+ const fill = normalizeHex(hex);
222
+ return fill !== null && format.highlight === void 0 && format.background !== void 0 && normalizeHex(format.background) === fill;
223
+ },
224
+ write: (hex, context) => {
225
+ const fill = normalizeHex(hex);
226
+ return fill === null ? null : [["shd", shadingXml(fill)], ...HIGHLIGHT.off(context)];
227
+ },
228
+ off: (context) => {
229
+ const painted = context.inherited.background !== void 0 && context.inherited.background !== NO_FILL;
230
+ return [
231
+ ["shd", painted ? shadingXml("auto") : null],
232
+ ...HIGHLIGHT.off(context)
233
+ ];
234
+ }
235
+ };
236
+ var VERTICAL_ALIGN = {
237
+ children: ["vertAlign"],
238
+ read: (rPr) => VERTICAL_ALIGN_BY_VAL[childValue(rPr, "vertAlign") ?? ""],
239
+ isOn: (format) => format.verticalAlign !== void 0,
240
+ matches: (format, align) => format.verticalAlign === align,
241
+ write: (align) => [["vertAlign", valXml("vertAlign", align)]],
242
+ off: ({ inherited }) => [
243
+ [
244
+ "vertAlign",
245
+ inherited.verticalAlign === void 0 ? null : valXml("vertAlign", "baseline")
246
+ ]
247
+ ]
248
+ };
249
+ var LANG = {
250
+ children: ["lang"],
251
+ read: (rPr) => langOf(rPr) ?? void 0,
252
+ isOn: (format) => format.lang !== void 0,
253
+ matches: (format, tag) => format.lang === tag
254
+ };
255
+ var EDITABLE_RUN_PROPERTIES = {
256
+ bold: toggle("bold", "b", "bCs"),
257
+ italic: toggle("italic", "i", "iCs"),
258
+ strike: toggle("strike", "strike"),
259
+ doubleStrike: toggle("doubleStrike", "dstrike"),
260
+ smallCaps: toggle("smallCaps", "smallCaps"),
261
+ caps: toggle("caps", "caps"),
262
+ underline: UNDERLINE,
263
+ fontSizePt: FONT_SIZE,
264
+ characterSpacingPt: CHARACTER_SPACING,
265
+ fontFamily: FONT_FAMILY,
266
+ color: COLOR,
267
+ highlight: HIGHLIGHT,
268
+ background: BACKGROUND,
269
+ verticalAlign: VERTICAL_ALIGN
270
+ };
271
+ var DISPLAY_ONLY_RUN_PROPERTIES = { lang: LANG };
272
+ var RUN_PROPERTIES = { ...EDITABLE_RUN_PROPERTIES, ...DISPLAY_ONLY_RUN_PROPERTIES };
273
+ function runChildEdits(edit, context) {
274
+ const property = EDITABLE_RUN_PROPERTIES[edit.key];
275
+ return edit.value === null ? property.off(context) : property.write(edit.value, context);
276
+ }
277
+ function matchesRunEdit(format, edit) {
278
+ const property = RUN_PROPERTIES[edit.key];
279
+ const values = format ?? {};
280
+ return edit.value === null ? !property.isOn(values) : property.matches(values, edit.value);
281
+ }
282
+ function withChildEdits(rPr, edits) {
283
+ return edits.reduce((kept, [name, xml]) => setChild(kept, name, xml), rPr);
284
+ }
285
+ var EMPTY_RUN_PROPS = {
286
+ tag: wName("rPr"),
287
+ attrs: null,
288
+ children: []
289
+ };
290
+ function written(rPr, key, value) {
291
+ if (value === void 0) return rPr;
292
+ const edits = EDITABLE_RUN_PROPERTIES[key].write(value, {
293
+ rPr,
294
+ inherited: {}
295
+ });
296
+ return edits === null ? rPr : withChildEdits(rPr, edits);
297
+ }
298
+ function rPrOf(settings) {
299
+ const rPr = renderProps(
300
+ EDITABLE_RUN_KEYS.reduce(
301
+ (kept, key) => written(kept, key, settings[key]),
302
+ EMPTY_RUN_PROPS
303
+ )
304
+ );
305
+ return rPr === "" ? null : rPr;
306
+ }
307
+ export {
308
+ EDITABLE_RUN_KEYS,
309
+ EMPTY_RUN_PROPS,
310
+ RUN_PROPERTIES,
311
+ fontNamesOf,
312
+ matchesRunEdit,
313
+ rPrOf,
314
+ runChildEdits,
315
+ withChildEdits
316
+ };
@@ -4,9 +4,10 @@ import {
4
4
  toRunFormat,
5
5
  toTableFormat
6
6
  } from "../../model/format.js";
7
+ import { parsePropsXml } from "../../ooxml/props.js";
8
+ import { ST_OnOff } from "../../ooxml/simpleTypes.js";
7
9
  import { childValue, isOn, wAttr } from "../../ooxml/units.js";
8
10
  import { childByLocalName, elementChildren } from "../../ooxml/xml.js";
9
- import { parsePropsXml } from "../propsXml.js";
10
11
  import {
11
12
  layerCellMargins,
12
13
  layerInsideBorders,
@@ -84,8 +85,7 @@ function readStyles(styles, themeFonts = NO_THEME_FONTS) {
84
85
  return table;
85
86
  }
86
87
  function isDefaultStyle(el) {
87
- const value = wAttr(el, "default");
88
- return value === "1" || value === "true";
88
+ return ST_OnOff.parse(wAttr(el, "default")) === true;
89
89
  }
90
90
  function defaultStyleIdOf(styles, type) {
91
91
  let found = null;
@@ -3,39 +3,24 @@ import { toParagraphFormat } from "../../model/format.js";
3
3
  import {
4
4
  layerTabStopDirectives
5
5
  } from "../../model/tabStops.js";
6
+ import { ST_TabJc, ST_TabTlc } from "../../ooxml/simpleTypes.js";
6
7
  function isRecord(value) {
7
8
  return typeof value === "object" && value !== null && !Array.isArray(value);
8
9
  }
9
- var ALIGNMENTS = /* @__PURE__ */ new Set([
10
- "start",
11
- "center",
12
- "end",
13
- "decimal",
14
- "num",
15
- "bar",
16
- "clear"
17
- ]);
18
- var LEADERS = /* @__PURE__ */ new Set([
19
- "none",
20
- "dot",
21
- "hyphen",
22
- "underscore",
23
- "heavy",
24
- "middleDot"
25
- ]);
26
10
  function toTabStopDirective(value) {
27
- if (!isRecord(value) || typeof value.positionPt !== "number" || !Number.isFinite(value.positionPt) || typeof value.align !== "string" || !ALIGNMENTS.has(value.align)) {
11
+ if (!isRecord(value) || typeof value.positionPt !== "number" || !Number.isFinite(value.positionPt)) {
28
12
  return null;
29
13
  }
30
- if (value.align === "clear") {
14
+ const align = typeof value.align === "string" ? ST_TabJc.parse(value.align) : null;
15
+ if (align === null) return null;
16
+ if (align === "clear") {
31
17
  return { positionPt: value.positionPt, align: "clear" };
32
18
  }
33
- const align = value.align;
34
- const leader = typeof value.leader === "string" && LEADERS.has(value.leader) ? value.leader : void 0;
19
+ const leader = typeof value.leader === "string" ? ST_TabTlc.parse(value.leader) : null;
35
20
  return {
36
21
  positionPt: value.positionPt,
37
22
  align,
38
- ...leader === void 0 ? {} : { leader }
23
+ ...leader === null ? {} : { leader }
39
24
  };
40
25
  }
41
26
  function toParagraphFormatLayer(value) {
@@ -1,4 +1,7 @@
1
+ export * from "./formatting/attrs";
2
+ export * from "./formatting/context";
1
3
  export * from "./formatting/direct";
2
- export * from "./formatting/effectiveParagraph";
4
+ export * from "./formatting/resolve";
5
+ export * from "./formatting/runProperties";
3
6
  export * from "./formatting/styles";
4
7
  export type { ParagraphFormatLayer } from "./formatting/tabStops";
@@ -1,4 +1,7 @@
1
1
  // src/docx/formatting.ts
2
+ export * from "./formatting/attrs.js";
3
+ export * from "./formatting/context.js";
2
4
  export * from "./formatting/direct.js";
3
- export * from "./formatting/effectiveParagraph.js";
5
+ export * from "./formatting/resolve.js";
6
+ export * from "./formatting/runProperties.js";
4
7
  export * from "./formatting/styles.js";
@@ -1,12 +1,14 @@
1
1
  // src/docx/headersFooters.ts
2
- import { ALIGN_BY_JC } from "../ooxml/units.js";
2
+ import { ALIGN_BY_JC, isOnElement } from "../ooxml/units.js";
3
3
  import {
4
+ attributeByLocalName,
4
5
  decodeUtf8,
5
6
  elementChildren,
6
7
  parseXml,
7
8
  R_NS,
8
9
  W_NS
9
10
  } from "../ooxml/xml.js";
11
+ import { relatedPartPath } from "./packageParts.js";
10
12
  import { readRelationships, relsPathOf, resolveTarget } from "./relationships.js";
11
13
  var EMPTY_VARIANTS = {
12
14
  default: null,
@@ -20,14 +22,6 @@ var NO_HEADERS_FOOTERS = {
20
22
  evenAndOdd: false,
21
23
  pageNumberStart: 1
22
24
  };
23
- function attribute(el, localName) {
24
- return Array.from(el.attributes).find((entry) => entry.localName === localName)?.value ?? null;
25
- }
26
- function isOn(el) {
27
- if (!el) return false;
28
- const value = attribute(el, "val")?.toLowerCase();
29
- return value !== "0" && value !== "false" && value !== "off";
30
- }
31
25
  function firstSectPrIn(root) {
32
26
  const namespaced = root.getElementsByTagNameNS(W_NS, "sectPr").item(0);
33
27
  if (namespaced) return namespaced;
@@ -58,13 +52,13 @@ function paragraphSegments(paragraph) {
58
52
  return;
59
53
  }
60
54
  if (el.namespaceURI === W_NS && el.localName === "fldSimple") {
61
- const field = pageField(attribute(el, "instr") ?? "");
55
+ const field = pageField(attributeByLocalName(el, "instr") ?? "");
62
56
  if (field) dynamic(field);
63
57
  else for (const child of elementChildren(el)) visit(child);
64
58
  return;
65
59
  }
66
60
  if (el.namespaceURI === W_NS && el.localName === "fldChar") {
67
- const kind = attribute(el, "fldCharType");
61
+ const kind = attributeByLocalName(el, "fldCharType");
68
62
  if (kind === "begin") {
69
63
  fields.push({ instruction: "", separated: false, field: null });
70
64
  } else if (kind === "separate") {
@@ -129,19 +123,16 @@ function readContent(bytes) {
129
123
  ) : void 0;
130
124
  return {
131
125
  segments,
132
- align: jc ? ALIGN_BY_JC[attribute(jc, "val") ?? ""] ?? null : null
126
+ align: jc ? ALIGN_BY_JC[attributeByLocalName(jc, "val") ?? ""] ?? null : null
133
127
  };
134
128
  }
135
129
  function settingsEvenAndOdd(parts, mainPartPath) {
136
- const relationship = readRelationships(parts, relsPathOf(mainPartPath)).find(
137
- (entry) => entry.type === `${R_NS}/settings` && !entry.external
138
- );
139
- if (!relationship) return false;
140
- const bytes = parts.get(resolveTarget(mainPartPath, relationship.target));
130
+ const path = relatedPartPath(parts, mainPartPath, `${R_NS}/settings`);
131
+ const bytes = path === null ? void 0 : parts.get(path);
141
132
  if (!bytes) return false;
142
133
  const root = parseXml(decodeUtf8(bytes).text).documentElement;
143
134
  const setting = root.getElementsByTagNameNS(W_NS, "evenAndOddHeaders").item(0);
144
- return isOn(setting);
135
+ return isOnElement(setting);
145
136
  }
146
137
  function readVariants(parts, mainPartPath, sectPr, kind) {
147
138
  const relationships = new Map(
@@ -153,9 +144,9 @@ function readVariants(parts, mainPartPath, sectPr, kind) {
153
144
  const variants = { ...EMPTY_VARIANTS };
154
145
  for (const reference of elementChildren(sectPr)) {
155
146
  if (reference.localName !== `${kind}Reference`) continue;
156
- const type = attribute(reference, "type") ?? "default";
147
+ const type = attributeByLocalName(reference, "type") ?? "default";
157
148
  if (type !== "default" && type !== "first" && type !== "even") continue;
158
- const id = reference.getAttributeNS(R_NS, "id") ?? attribute(reference, "id");
149
+ const id = reference.getAttributeNS(R_NS, "id") ?? attributeByLocalName(reference, "id");
159
150
  if (!id) continue;
160
151
  const relationship = relationships.get(id);
161
152
  if (!relationship || relationship.external || relationship.type !== `${R_NS}/${kind}`) {
@@ -170,7 +161,7 @@ function pageNumberStart(sectPr) {
170
161
  const pgNumType = elementChildren(sectPr).find(
171
162
  (child) => child.localName === "pgNumType"
172
163
  );
173
- const declared = pgNumType ? attribute(pgNumType, "start") : null;
164
+ const declared = pgNumType ? attributeByLocalName(pgNumType, "start") : null;
174
165
  if (declared === null) return 1;
175
166
  const start = Number(declared);
176
167
  return Number.isSafeInteger(start) && start >= 0 ? start : 1;
@@ -181,7 +172,7 @@ function readHeadersFooters(parts, mainPartPath, body) {
181
172
  return {
182
173
  headers: readVariants(parts, mainPartPath, sectPr, "header"),
183
174
  footers: readVariants(parts, mainPartPath, sectPr, "footer"),
184
- firstPageDifferent: isOn(
175
+ firstPageDifferent: isOnElement(
185
176
  elementChildren(sectPr).find((child) => child.localName === "titlePg") ?? null
186
177
  ),
187
178
  evenAndOdd: settingsEvenAndOdd(parts, mainPartPath),
@@ -0,0 +1,67 @@
1
+ /**
2
+ * Settling, just before export, every name that may be held by one node only.
3
+ *
4
+ * An edit can leave one name standing in two places: splitting a paragraph inside a content
5
+ * control leaves that control in both halves, and dropping a copy of a paragraph carries the
6
+ * original's identifiers along with it. Each name a document must keep unique is one rule here,
7
+ * and the pass walks the blocks once in document order, so the first node to claim a name keeps it
8
+ * and every later claimant gives it up.
9
+ *
10
+ * A document nobody broke apart comes back node for node as it was, which is what keeps an
11
+ * unedited block going out as its original XML.
12
+ *
13
+ * The one walk answers two callers: `withUniqueIdentities` hands the writer the settled document
14
+ * and throws over a block that cannot yield, and `identityProblems` runs the same walk for
15
+ * `docx/invariants` and lists those blocks instead, so what the query reports and what the write
16
+ * refuses cannot come apart.
17
+ */
18
+ import { type Node as PMNode } from "prosemirror-model";
19
+ import { type DocxExportErrorCode } from "../ooxml/errors";
20
+ export interface IdentityRule {
21
+ readonly name: string;
22
+ /**
23
+ * The block to write in place of `block`, with every name it claims that `written` already holds
24
+ * given up, and the names it keeps added to `written`. Returns `block` itself when nothing
25
+ * changes. null means the block cannot yield and the export must refuse. A block's children are
26
+ * not visited here; the walker visits them after this call.
27
+ */
28
+ visit(block: PMNode, written: Set<string>): PMNode | null;
29
+ }
30
+ /**
31
+ * The block a node was opened from, which `docx/exportDocx` writes the original bytes back for.
32
+ * A second node claiming the same block is written from its own attrs instead, and a block that
33
+ * exists only as its original XML has nothing to be written from, so it cannot yield.
34
+ */
35
+ export declare const sourceBlockRule: IdentityRule;
36
+ /**
37
+ * A later paragraph carrying an identifier already written goes out without one, and without its
38
+ * `w14:textId` too, which may not stand without a `w14:paraId` beside it. The walker reaches the
39
+ * paragraphs inside a table, so the rule reads the one block it is handed.
40
+ */
41
+ export declare const paragraphIdRule: IdentityRule;
42
+ /**
43
+ * A content control cannot cross a paragraph, so splitting a paragraph in the middle of one leaves
44
+ * that same control standing in two, and dropping unmarked text into the middle of one breaks it
45
+ * in two within the paragraph. Each piece after the first opens as a copy with a `w:id` of its
46
+ * own (see `docx/sdt` for what a copy must not carry along).
47
+ */
48
+ export declare const controlRule: IdentityRule;
49
+ /**
50
+ * In the order they apply to one block: the source rule first, so that a second claimant of a
51
+ * block is already a rebuilt paragraph by the time the paragraph rule takes its identifier away.
52
+ */
53
+ export declare const IDENTITY_RULES: readonly IdentityRule[];
54
+ /** A block that cannot yield: what the export refuses it with, and where it stands in the document */
55
+ export interface IdentityProblem {
56
+ readonly code: DocxExportErrorCode;
57
+ readonly message: string;
58
+ readonly pos: number;
59
+ }
60
+ /** The document with every later claimant of a name released, in document order */
61
+ export declare function withUniqueIdentities(doc: PMNode, rules?: readonly IdentityRule[]): PMNode;
62
+ /**
63
+ * Every block `withUniqueIdentities` would refuse over, in document order, each where it stands;
64
+ * empty when the pass would go through. The pass is run as the export runs it and its settled
65
+ * document is dropped, so a caller asking ahead of the write reads the same refusal it would throw.
66
+ */
67
+ export declare function identityProblems(doc: PMNode, rules?: readonly IdentityRule[]): readonly IdentityProblem[];