@portone/docx-editor 0.2.1 → 0.4.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 (253) hide show
  1. package/CHANGELOG.md +155 -0
  2. package/CONTRIBUTING.md +5 -1
  3. package/dist/DocxEditor.d.ts +6 -0
  4. package/dist/DocxEditor.js +13 -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 +59 -112
  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 +88 -74
  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 +45 -0
  33. package/dist/docx/formatting/attrs.js +86 -0
  34. package/dist/docx/formatting/context.d.ts +39 -0
  35. package/dist/docx/formatting/context.js +60 -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 +51 -0
  39. package/dist/docx/formatting/resolve.js +160 -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.d.ts +25 -2
  43. package/dist/docx/formatting/styles.js +87 -6
  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 +6 -13
  48. package/dist/docx/hyperlink.d.ts +14 -4
  49. package/dist/docx/hyperlink.js +4 -1
  50. package/dist/docx/identities.d.ts +67 -0
  51. package/dist/docx/identities.js +174 -0
  52. package/dist/docx/importDocx.d.ts +12 -1
  53. package/dist/docx/importDocx.js +90 -88
  54. package/dist/docx/importParagraph.d.ts +1 -1
  55. package/dist/docx/importParagraph.js +4 -3
  56. package/dist/docx/importTable.d.ts +2 -2
  57. package/dist/docx/importTable.js +69 -56
  58. package/dist/docx/invariants.d.ts +33 -0
  59. package/dist/docx/invariants.js +269 -0
  60. package/dist/docx/media.d.ts +6 -4
  61. package/dist/docx/media.js +6 -37
  62. package/dist/docx/newLists.d.ts +50 -0
  63. package/dist/docx/newLists.js +59 -0
  64. package/dist/docx/notes.js +3 -7
  65. package/dist/docx/numberingPlanner.d.ts +11 -0
  66. package/dist/docx/numberingPlanner.js +50 -0
  67. package/dist/docx/packageParts.d.ts +42 -0
  68. package/dist/docx/packageParts.js +135 -0
  69. package/dist/docx/pageGeometry.d.ts +2 -0
  70. package/dist/docx/pageGeometry.js +18 -9
  71. package/dist/docx/paraProps.d.ts +10 -22
  72. package/dist/docx/paraProps.js +47 -76
  73. package/dist/docx/partPlan.d.ts +36 -0
  74. package/dist/docx/partPlan.js +59 -0
  75. package/dist/docx/protectionPolicy.d.ts +127 -0
  76. package/dist/docx/protectionPolicy.js +169 -0
  77. package/dist/docx/relationships.d.ts +1 -1
  78. package/dist/docx/relationships.js +8 -13
  79. package/dist/docx/runProps.d.ts +9 -22
  80. package/dist/docx/runProps.js +15 -168
  81. package/dist/docx/scan.js +20 -52
  82. package/dist/docx/sdt.js +9 -34
  83. package/dist/docx/sdtProps.d.ts +8 -1
  84. package/dist/docx/sdtProps.js +10 -0
  85. package/dist/docx/serializeBlock.d.ts +2 -0
  86. package/dist/docx/serializeBlock.js +8 -5
  87. package/dist/docx/serializeTable.js +32 -15
  88. package/dist/docx/session.d.ts +42 -14
  89. package/dist/docx/session.js +53 -17
  90. package/dist/docx/tableFormatting/conditions.d.ts +76 -0
  91. package/dist/docx/tableFormatting/conditions.js +196 -0
  92. package/dist/docx/tableFormatting/editing.d.ts +7 -3
  93. package/dist/docx/tableFormatting/editing.js +111 -143
  94. package/dist/docx/tableFormatting/reading.d.ts +63 -23
  95. package/dist/docx/tableFormatting/reading.js +132 -38
  96. package/dist/docx/tableFormatting.d.ts +1 -0
  97. package/dist/docx/tableFormatting.js +1 -0
  98. package/dist/docx/tableTemplate.js +30 -19
  99. package/dist/download.d.ts +8 -5
  100. package/dist/download.js +2 -0
  101. package/dist/editor/clipboard/inlineFormatting.js +19 -30
  102. package/dist/editor/commands/comments/editing.d.ts +6 -2
  103. package/dist/editor/commands/comments/editing.js +19 -31
  104. package/dist/editor/commands/exportQueries.d.ts +15 -0
  105. package/dist/editor/commands/exportQueries.js +14 -0
  106. package/dist/editor/commands/fidelityQueries.d.ts +12 -0
  107. package/dist/editor/commands/fidelityQueries.js +8 -0
  108. package/dist/editor/commands/formatting/editing.d.ts +2 -2
  109. package/dist/editor/commands/formatting/editing.js +26 -108
  110. package/dist/editor/commands/formatting/propertyCommands.d.ts +21 -0
  111. package/dist/editor/commands/formatting/propertyCommands.js +108 -0
  112. package/dist/editor/commands/formatting/shared.d.ts +3 -3
  113. package/dist/editor/commands/formatting/shared.js +5 -2
  114. package/dist/editor/commands/indentCommands.js +5 -4
  115. package/dist/editor/commands/index.d.ts +11 -0
  116. package/dist/editor/commands/index.js +5 -0
  117. package/dist/editor/commands/linkCommands.js +5 -6
  118. package/dist/editor/commands/listCommands.d.ts +6 -3
  119. package/dist/editor/commands/listCommands.js +73 -30
  120. package/dist/editor/commands/lockCommands.d.ts +7 -1
  121. package/dist/editor/commands/lockCommands.js +35 -46
  122. package/dist/editor/commands/paragraphCommands.js +33 -31
  123. package/dist/editor/commands/spacingCommands.js +1 -1
  124. package/dist/editor/createEditor.d.ts +17 -29
  125. package/dist/editor/createEditor.js +58 -58
  126. package/dist/editor/documentStyles.d.ts +11 -35
  127. package/dist/editor/documentStyles.js +9 -52
  128. package/dist/editor/editorDocument.d.ts +57 -0
  129. package/dist/editor/editorDocument.js +86 -0
  130. package/dist/editor/externalClipboard.d.ts +13 -2
  131. package/dist/editor/externalClipboard.js +76 -75
  132. package/dist/editor/insertTable.js +4 -3
  133. package/dist/editor/paragraphEdits.d.ts +27 -19
  134. package/dist/editor/paragraphEdits.js +18 -19
  135. package/dist/editor/paragraphPlacement.d.ts +11 -0
  136. package/dist/editor/paragraphPlacement.js +18 -0
  137. package/dist/editor/plugins/displayDerivation.d.ts +47 -0
  138. package/dist/editor/plugins/displayDerivation.js +78 -0
  139. package/dist/editor/plugins/imagePaste.js +11 -7
  140. package/dist/editor/plugins/keymap.js +18 -3
  141. package/dist/editor/plugins/numberingDecorations.d.ts +14 -14
  142. package/dist/editor/plugins/numberingDecorations.js +50 -19
  143. package/dist/editor/plugins/paragraphDisplay.d.ts +7 -0
  144. package/dist/editor/plugins/paragraphDisplay.js +57 -0
  145. package/dist/editor/plugins/tabLayout.js +1 -1
  146. package/dist/editor/plugins/tableDisplay.d.ts +6 -0
  147. package/dist/editor/plugins/tableDisplay.js +30 -0
  148. package/dist/index.d.ts +2 -0
  149. package/dist/model/format.d.ts +80 -8
  150. package/dist/model/format.js +100 -22
  151. package/dist/model/tabStops.d.ts +9 -0
  152. package/dist/model/tabStops.js +18 -0
  153. package/dist/numbering/listRegistry.d.ts +37 -0
  154. package/dist/numbering/listRegistry.js +112 -0
  155. package/dist/numbering/listTemplate.d.ts +26 -17
  156. package/dist/numbering/listTemplate.js +88 -25
  157. package/dist/numbering/markers.d.ts +15 -6
  158. package/dist/numbering/markers.js +26 -59
  159. package/dist/numbering/parseNumbering.d.ts +84 -6
  160. package/dist/numbering/parseNumbering.js +131 -44
  161. package/dist/numbering/spellers.d.ts +15 -0
  162. package/dist/numbering/spellers.js +96 -0
  163. package/dist/numbering/writeNumbering.d.ts +8 -7
  164. package/dist/numbering/writeNumbering.js +28 -39
  165. package/dist/ooxml/childOrder.d.ts +34 -0
  166. package/dist/ooxml/childOrder.js +496 -0
  167. package/dist/ooxml/conformance.d.ts +28 -0
  168. package/dist/ooxml/conformance.js +20 -0
  169. package/dist/ooxml/element.d.ts +24 -11
  170. package/dist/ooxml/element.js +31 -12
  171. package/dist/ooxml/errors.d.ts +6 -5
  172. package/dist/ooxml/image.d.ts +4 -0
  173. package/dist/ooxml/image.js +2 -5
  174. package/dist/ooxml/names.d.ts +9 -0
  175. package/dist/ooxml/names.js +8 -1
  176. package/dist/ooxml/partSplice.d.ts +67 -0
  177. package/dist/ooxml/partSplice.js +176 -0
  178. package/dist/ooxml/props.d.ts +112 -0
  179. package/dist/{docx/propsXml.js → ooxml/props.js} +72 -200
  180. package/dist/ooxml/simpleTypes.d.ts +103 -0
  181. package/dist/ooxml/simpleTypes.js +182 -0
  182. package/dist/ooxml/tabStops.js +8 -27
  183. package/dist/ooxml/tagScan.d.ts +34 -0
  184. package/dist/ooxml/tagScan.js +108 -0
  185. package/dist/ooxml/units.d.ts +25 -13
  186. package/dist/ooxml/units.js +65 -31
  187. package/dist/ooxml/xml.d.ts +35 -15
  188. package/dist/ooxml/xml.js +43 -11
  189. package/dist/page/PageGuides.d.ts +1 -1
  190. package/dist/page/PageGuides.js +0 -13
  191. package/dist/page/blockKinds.d.ts +61 -0
  192. package/dist/page/blockKinds.js +11 -0
  193. package/dist/page/kinds/index.d.ts +6 -0
  194. package/dist/page/kinds/index.js +10 -0
  195. package/dist/page/kinds/paragraphKind.d.ts +10 -0
  196. package/dist/page/kinds/paragraphKind.js +71 -0
  197. package/dist/page/kinds/tableKind.d.ts +10 -0
  198. package/dist/page/kinds/tableKind.js +178 -0
  199. package/dist/page/measureBlocks.d.ts +3 -14
  200. package/dist/page/measureBlocks.js +24 -45
  201. package/dist/page/pageDecorations.d.ts +27 -44
  202. package/dist/page/pageDecorations.js +70 -152
  203. package/dist/page/pageLayout.d.ts +2 -29
  204. package/dist/page/pageLayout.js +39 -16
  205. package/dist/page/usePageLayout.d.ts +2 -24
  206. package/dist/page/usePageLayout.js +5 -48
  207. package/dist/schema/attrRoles.d.ts +25 -18
  208. package/dist/schema/attrRoles.js +110 -68
  209. package/dist/schema/displayDerivation.d.ts +82 -0
  210. package/dist/schema/displayDerivation.js +130 -0
  211. package/dist/schema/docxSchema.d.ts +3 -0
  212. package/dist/schema/docxSchema.js +58 -17
  213. package/dist/schema/editGuard.d.ts +1 -1
  214. package/dist/schema/guards.d.ts +37 -14
  215. package/dist/schema/guards.js +29 -3
  216. package/dist/schema/index.d.ts +2 -0
  217. package/dist/schema/index.js +2 -0
  218. package/dist/schema/locks.d.ts +11 -44
  219. package/dist/schema/locks.js +0 -9
  220. package/dist/schema/preservedGuards.d.ts +26 -6
  221. package/dist/schema/preservedGuards.js +31 -1
  222. package/dist/schema/protection.d.ts +7 -1
  223. package/dist/schema/protection.js +2 -1
  224. package/dist/schema/sourceEquality.d.ts +1 -9
  225. package/dist/schema/sourceEquality.js +1 -27
  226. package/dist/styles/classNames.d.ts +13 -2
  227. package/dist/styles/classNames.js +13 -2
  228. package/dist/styles/inlineStyle.js +15 -6
  229. package/dist/styles.css +16 -18
  230. package/dist/table/cellFormatting.d.ts +8 -1
  231. package/dist/table/cellFormatting.js +11 -20
  232. package/dist/table/commands.js +20 -18
  233. package/dist/table/format.d.ts +3 -0
  234. package/dist/table/format.js +3 -9
  235. package/dist/table/gridBorders.d.ts +24 -30
  236. package/dist/table/gridBorders.js +35 -59
  237. package/dist/table/merge.d.ts +2 -6
  238. package/dist/table/merge.js +5 -5
  239. package/package.json +7 -3
  240. package/dist/docx/comments/contentTypes.d.ts +0 -7
  241. package/dist/docx/comments/contentTypes.js +0 -38
  242. package/dist/docx/comments/verifying.js +0 -206
  243. package/dist/docx/formatting/effectiveParagraph.d.ts +0 -15
  244. package/dist/docx/formatting/effectiveParagraph.js +0 -81
  245. package/dist/docx/propsXml.d.ts +0 -67
  246. package/dist/docx/uniqueControls.d.ts +0 -14
  247. package/dist/docx/uniqueControls.js +0 -62
  248. package/dist/editor/plugins/commentReservations.d.ts +0 -5
  249. package/dist/editor/plugins/commentReservations.js +0 -26
  250. package/dist/editor/plugins/styledParagraphs.d.ts +0 -15
  251. package/dist/editor/plugins/styledParagraphs.js +0 -65
  252. package/dist/page/tableMeasurements.d.ts +0 -18
  253. package/dist/page/tableMeasurements.js +0 -119
@@ -1,21 +1,25 @@
1
1
  // src/docx/tableFormatting/editing.ts
2
- import { attrPairs, elementXml } from "../../ooxml/element.js";
2
+ import { elementXml, wAttrValue } from "../../ooxml/element.js";
3
3
  import { wName } from "../../ooxml/names.js";
4
4
  import { setAttr } from "../../ooxml/precedence.js";
5
- import { normalizeHex, wAttr } from "../../ooxml/units.js";
6
- import { childByLocalName } from "../../ooxml/xml.js";
7
5
  import {
6
+ childElement,
7
+ editChild,
8
8
  parseProps,
9
9
  parsePropsXml,
10
10
  propsChild,
11
11
  renderProps,
12
- setPropsChild,
13
- TC_PR_ORDER,
14
- TR_PR_ORDER
15
- } from "../propsXml.js";
12
+ setChild,
13
+ withAttrs
14
+ } from "../../ooxml/props.js";
16
15
  import {
17
- NO_BORDER_DEFAULTS,
18
- NO_CELL_MARGINS,
16
+ ST_EighthPointMeasure,
17
+ ST_TwipsMeasure,
18
+ TWIPS_PER_PT
19
+ } from "../../ooxml/simpleTypes.js";
20
+ import { normalizeHex } from "../../ooxml/units.js";
21
+ import {
22
+ NO_CELL_DEFAULTS,
19
23
  readCellProps,
20
24
  readRowFormat
21
25
  } from "./reading.js";
@@ -25,18 +29,6 @@ var ALL_CELL_SIDES = [
25
29
  "left",
26
30
  "right"
27
31
  ];
28
- var TC_BORDERS_ORDER = [
29
- "top",
30
- "start",
31
- "left",
32
- "bottom",
33
- "end",
34
- "right",
35
- "insideH",
36
- "insideV",
37
- "tl2br",
38
- "tr2bl"
39
- ];
40
32
  var SIDE_NAMES = {
41
33
  top: ["top"],
42
34
  bottom: ["bottom"],
@@ -46,22 +38,24 @@ var SIDE_NAMES = {
46
38
  var PRESET_BORDER_EIGHTHS = 4;
47
39
  var EMPTY_TC_PR = { tag: "w:tcPr", attrs: null, children: [] };
48
40
  function drawsLine(side) {
49
- if (!side) return false;
50
- const val = wAttr(side, "val");
41
+ if (side.tag === null) return false;
42
+ const val = wAttrValue(side.attrs, "val");
51
43
  return val !== null && val !== "nil" && val !== "none";
52
44
  }
53
45
  function sideAttrs(name, current, edit, fallback = null) {
54
46
  if (edit.kind === "color") {
55
47
  if (!drawsLine(current)) {
56
- if (current || !fallback || fallback === "none") return null;
48
+ if (current.tag !== null || fallback === null || fallback.val === "none") {
49
+ return null;
50
+ }
57
51
  return inheritedBorderAttrs(fallback, edit.hex);
58
52
  }
59
- return setAttr(attrPairs(current), name, "color", edit.hex ?? "auto");
53
+ return setAttr(current.attrs, name, "color", edit.hex ?? "auto");
60
54
  }
61
55
  if (edit.line === "none") {
62
- return current ? setAttr(attrPairs(current), name, "val", "none") : [[wName("val"), "none"]];
56
+ return current.tag !== null ? setAttr(current.attrs, name, "val", "none") : [[wName("val"), "none"]];
63
57
  }
64
- if (!current) {
58
+ if (current.tag === null) {
65
59
  return [
66
60
  [wName("val"), "single"],
67
61
  [wName("sz"), `${PRESET_BORDER_EIGHTHS}`],
@@ -70,217 +64,191 @@ function sideAttrs(name, current, edit, fallback = null) {
70
64
  ];
71
65
  }
72
66
  return setAttr(
73
- setAttr(attrPairs(current), name, "val", "single"),
67
+ setAttr(current.attrs, name, "val", "single"),
74
68
  name,
75
69
  "sz",
76
70
  `${PRESET_BORDER_EIGHTHS}`
77
71
  );
78
72
  }
79
- var BORDER_VAL_BY_CSS_STYLE = {
80
- solid: "single",
81
- double: "double",
82
- dashed: "dashed",
83
- dotted: "dotted"
84
- };
85
- function inheritedBorderAttrs(border, hex) {
86
- const matched = border.match(
87
- /^(\d+(?:\.\d+)?)pt (solid|double|dashed|dotted) (#[0-9a-f]{6})$/i
88
- );
89
- if (!matched) return null;
90
- const [, widthText, style, currentColor] = matched;
91
- if (hex !== null && normalizeHex(currentColor) === hex) return null;
92
- const eighths = Math.round(Number.parseFloat(widthText) * 8);
93
- if (!Number.isSafeInteger(eighths) || eighths <= 0) return null;
73
+ function inheritedBorderAttrs(line, hex) {
74
+ const current = line.color.kind === "rgb" ? normalizeHex(line.color.hex) : null;
75
+ if (hex !== null && current === hex) return null;
76
+ const thickness = ST_EighthPointMeasure.format(line.eighths);
77
+ if (thickness === null) return null;
94
78
  return [
95
- [wName("val"), BORDER_VAL_BY_CSS_STYLE[style.toLowerCase()]],
96
- [wName("sz"), `${eighths}`],
79
+ [wName("val"), line.val],
80
+ [wName("sz"), thickness],
97
81
  [wName("space"), "0"],
98
82
  [wName("color"), hex ?? "auto"]
99
83
  ];
100
84
  }
101
85
  function sideNames(borders, side) {
102
86
  const [primary, alternate] = SIDE_NAMES[side];
103
- const usesAlternate = alternate !== void 0 && borders !== null && childByLocalName(borders, primary) === null && childByLocalName(borders, alternate) !== null;
87
+ const usesAlternate = alternate !== void 0 && propsChild(borders.children, primary) === void 0 && propsChild(borders.children, alternate) !== void 0;
104
88
  if (usesAlternate) return { write: alternate, drop: null };
105
89
  return { write: primary, drop: alternate ?? null };
106
90
  }
107
- function editedBorders(current, edit, defaults = NO_BORDER_DEFAULTS) {
108
- const props = current === null ? { tag: "w:tcBorders", attrs: null, children: [] } : parseProps(current);
109
- const borders = current === null ? null : parsePropsXml(current);
110
- if (!props || current !== null && !borders) return null;
91
+ function leafElement(tag, attrs) {
92
+ return withAttrs({ tag, attrs: null, children: [] }, attrs);
93
+ }
94
+ function containerOf(props, name) {
95
+ const current = propsChild(props.children, name)?.xml;
96
+ if (current === void 0) {
97
+ return { tag: wName(name), attrs: null, children: [] };
98
+ }
99
+ return parseProps(current);
100
+ }
101
+ function editedBorders(props, edit, defaults) {
102
+ const borders = containerOf(props, "tcBorders");
103
+ if (!borders) return null;
111
104
  const sides = edit.kind === "line" ? edit.sides : ALL_CELL_SIDES;
112
- const edited = sides.reduce((kept, side) => {
105
+ return sides.reduce((kept, side) => {
106
+ if (kept === null) return null;
113
107
  const { write, drop } = sideNames(borders, side);
114
- const currentSide = borders ? childByLocalName(borders, write) : null;
108
+ const currentSide = childElement(borders, write);
109
+ if (!currentSide) return null;
115
110
  const attrs = sideAttrs(write, currentSide, edit, defaults[side]);
116
111
  if (!attrs) return kept;
117
- const tag = currentSide?.nodeName ?? wName(write);
118
- const written = setPropsChild(
112
+ const written = editChild(
119
113
  kept,
120
- write,
121
- elementXml(tag, attrs),
122
- TC_BORDERS_ORDER
114
+ ["tcBorders", write],
115
+ () => leafElement(currentSide.tag ?? wName(write), attrs)
123
116
  );
124
- return drop === null ? written : setPropsChild(written, drop, null, TC_BORDERS_ORDER);
117
+ if (written === null || drop === null) return written;
118
+ return editChild(written, ["tcBorders", drop], () => null);
125
119
  }, props);
126
- const xml = renderProps(edited);
127
- return { xml: xml === "" ? null : xml };
128
120
  }
129
121
  function hasPattern(shd) {
130
- const val = shd ? wAttr(shd, "val") : null;
122
+ const val = wAttrValue(shd.attrs, "val");
131
123
  return val !== null && val !== "clear" && val !== "nil";
132
124
  }
133
125
  function editedShading(current, fill) {
134
- const tag = current?.nodeName ?? wName("shd");
126
+ const tag = current.tag ?? wName("shd");
135
127
  if (fill === null) {
136
128
  if (!hasPattern(current)) return null;
137
- return elementXml(tag, setAttr(attrPairs(current), "shd", "fill", "auto"));
129
+ return elementXml(tag, setAttr(current.attrs, "shd", "fill", "auto"));
138
130
  }
139
- if (!current) {
131
+ if (current.tag === null) {
140
132
  return elementXml(tag, [
141
133
  [wName("val"), "clear"],
142
134
  [wName("color"), "auto"],
143
135
  [wName("fill"), fill]
144
136
  ]);
145
137
  }
146
- const painting = hasPattern(current) ? attrPairs(current) : setAttr(attrPairs(current), "shd", "val", "clear");
138
+ const painting = hasPattern(current) ? current.attrs : setAttr(current.attrs, "shd", "val", "clear");
147
139
  return elementXml(tag, setAttr(painting, "shd", "fill", fill));
148
140
  }
149
- function bordersChange(props, edit, defaults) {
150
- const current = propsChild(props.children, "tcBorders")?.xml ?? null;
151
- const edited = editedBorders(current, edit, defaults);
152
- return edited === null ? null : { name: "tcBorders", xml: edited.xml };
153
- }
154
- var TC_MAR_ORDER = [
155
- "top",
156
- "start",
157
- "left",
158
- "bottom",
159
- "end",
160
- "right"
161
- ];
162
141
  var MARGIN_SIDE_NAMES = {
163
142
  top: ["top"],
164
143
  right: ["end", "right"],
165
144
  bottom: ["bottom"],
166
145
  left: ["start", "left"]
167
146
  };
168
- function paddingChange(props, values) {
169
- const current = propsChild(props.children, "tcMar")?.xml ?? null;
170
- const margins = current === null ? null : parsePropsXml(current);
171
- const parsed = current === null ? { tag: "w:tcMar", attrs: null, children: [] } : parseProps(current);
172
- if (!parsed || current !== null && !margins) return null;
173
- let edited = parsed;
147
+ function editedPadding(props, values) {
148
+ const margins = containerOf(props, "tcMar");
149
+ if (!margins) return null;
150
+ let edited = props;
174
151
  let wrote = false;
175
152
  for (const side of ALL_CELL_SIDES) {
176
153
  const points = values[side];
177
154
  if (points === void 0) continue;
178
- const twips = Math.round(points * 20);
179
- if (!Number.isFinite(points) || points < 0 || !Number.isSafeInteger(twips)) {
180
- return null;
181
- }
182
- const existing = margins ? MARGIN_SIDE_NAMES[side].map((name2) => childByLocalName(margins, name2)).find((element) => element !== null) ?? null : null;
183
- const name = existing?.localName ?? side;
155
+ if (points < 0) return null;
156
+ const twips = ST_TwipsMeasure.format(Math.round(points * TWIPS_PER_PT));
157
+ if (twips === null) return null;
158
+ const name = MARGIN_SIDE_NAMES[side].find(
159
+ (spelling) => propsChild(margins.children, spelling) !== void 0
160
+ ) ?? side;
161
+ const existing = childElement(margins, name);
162
+ if (existing === null || edited === null) return null;
184
163
  const attrs = setAttr(
185
- setAttr(attrPairs(existing), name, "w", `${twips}`),
164
+ setAttr(existing.attrs, name, "w", twips),
186
165
  name,
187
166
  "type",
188
167
  "dxa"
189
168
  );
190
- edited = setPropsChild(
169
+ edited = editChild(
191
170
  edited,
192
- name,
193
- elementXml(existing?.nodeName ?? wName(side), attrs),
194
- TC_MAR_ORDER
171
+ ["tcMar", name],
172
+ () => leafElement(existing.tag ?? wName(side), attrs)
195
173
  );
196
174
  wrote = true;
197
175
  }
198
- if (!wrote) return null;
199
- return { name: "tcMar", xml: renderProps(edited) };
176
+ return wrote ? edited : null;
200
177
  }
201
- function childChange(edit, props, defaults) {
178
+ function editedProps(edit, props, defaults) {
202
179
  switch (edit.kind) {
203
180
  case "background": {
204
181
  const fill = edit.hex === null ? null : normalizeHex(edit.hex);
205
182
  if (edit.hex !== null && fill === null) return null;
206
- const current = propsChild(props.children, "shd")?.xml ?? null;
207
- const shd = current === null ? null : parsePropsXml(current);
208
- if (current !== null && !shd) return null;
209
- return { name: "shd", xml: editedShading(shd, fill) };
183
+ const shd = childElement(props, "shd");
184
+ if (!shd) return null;
185
+ return setChild(props, "shd", editedShading(shd, fill));
210
186
  }
211
187
  case "borders":
212
- return bordersChange(
188
+ return editedBorders(
213
189
  props,
214
- {
215
- kind: "line",
216
- line: edit.line,
217
- sides: edit.sides
218
- },
190
+ { kind: "line", line: edit.line, sides: edit.sides },
219
191
  defaults
220
192
  );
221
193
  case "borderColor": {
222
194
  const hex = edit.hex === null ? null : normalizeHex(edit.hex);
223
195
  if (edit.hex !== null && hex === null) return null;
224
- return bordersChange(props, { kind: "color", hex }, defaults);
196
+ return editedBorders(props, { kind: "color", hex }, defaults);
225
197
  }
226
198
  case "verticalAlign": {
227
- const current = propsChild(props.children, "vAlign")?.xml ?? null;
228
- const element = current === null ? null : parsePropsXml(current);
229
- if (current !== null && !element) return null;
230
- return {
231
- name: "vAlign",
232
- xml: elementXml(
233
- element?.nodeName ?? wName("vAlign"),
234
- setAttr(attrPairs(element), "vAlign", "val", edit.align)
199
+ const current = childElement(props, "vAlign");
200
+ if (!current) return null;
201
+ return setChild(
202
+ props,
203
+ "vAlign",
204
+ elementXml(
205
+ current.tag ?? wName("vAlign"),
206
+ setAttr(current.attrs, "vAlign", "val", edit.align)
235
207
  )
236
- };
208
+ );
237
209
  }
238
210
  case "padding":
239
- return paddingChange(props, edit.values);
211
+ return editedPadding(props, edit.values);
240
212
  }
241
213
  }
242
- function editCellProps(tcPr, edit, defaults = NO_BORDER_DEFAULTS, margins = NO_CELL_MARGINS) {
214
+ function editCellProps(tcPr, edit, defaults = NO_CELL_DEFAULTS) {
243
215
  const props = tcPr === null ? EMPTY_TC_PR : parseProps(tcPr);
244
216
  if (!props) return null;
245
- const change = childChange(edit, props, defaults);
246
- if (!change) return null;
247
- const rendered = renderProps(
248
- setPropsChild(props, change.name, change.xml, TC_PR_ORDER)
249
- );
217
+ const edited = editedProps(edit, props, defaults.borders);
218
+ if (!edited) return null;
219
+ const rendered = renderProps(edited);
250
220
  const next = rendered === "" ? null : rendered;
251
221
  if (next === tcPr) return null;
252
- return { tcPr: next, format: readCellProps(next, defaults, margins) };
222
+ return { tcPr: next, format: readCellProps(next, defaults) };
253
223
  }
254
224
  function drawsOwnCellBorder(tcPr) {
255
- const el = tcPr === null ? null : parsePropsXml(tcPr);
256
- const borders = el ? childByLocalName(el, "tcBorders") : null;
225
+ const props = tcPr === null ? null : parseProps(tcPr);
226
+ const borders = props && containerOf(props, "tcBorders");
257
227
  if (!borders) return false;
258
228
  return ALL_CELL_SIDES.some(
259
- (side) => SIDE_NAMES[side].some((name) => drawsLine(childByLocalName(borders, name)))
229
+ (side) => SIDE_NAMES[side].some((name) => {
230
+ const element = childElement(borders, name);
231
+ return element !== null && drawsLine(element);
232
+ })
260
233
  );
261
234
  }
262
235
  function editRowHeight(trPr, heightPt) {
263
- const twips = Math.round(heightPt * 20);
264
- if (!Number.isFinite(heightPt) || heightPt <= 0 || !Number.isSafeInteger(twips)) {
265
- return null;
266
- }
267
- const props = trPr === null ? { tag: "w:trPr", attrs: null, children: [] } : parseProps(trPr);
236
+ const twips = heightPt > 0 ? ST_TwipsMeasure.format(Math.round(heightPt * TWIPS_PER_PT)) : null;
237
+ if (twips === null) return null;
238
+ const props = trPr === null ? { tag: wName("trPr"), attrs: null, children: [] } : parseProps(trPr);
268
239
  if (!props) return null;
269
- const current = propsChild(props.children, "trHeight")?.xml ?? null;
270
- const element = current === null ? null : parsePropsXml(current);
271
- if (current !== null && !element) return null;
272
- const writtenRule = element ? wAttr(element, "hRule") : null;
273
- const attrs = setAttr(attrPairs(element), "trHeight", "val", `${twips}`);
240
+ const current = childElement(props, "trHeight");
241
+ if (!current) return null;
242
+ const writtenRule = wAttrValue(current.attrs, "hRule");
243
+ const attrs = setAttr(current.attrs, "trHeight", "val", twips);
274
244
  const nextAttrs = setAttr(
275
245
  attrs,
276
246
  "trHeight",
277
247
  "hRule",
278
248
  writtenRule === "exact" ? "exact" : "atLeast"
279
249
  );
280
- const child = elementXml(element?.nodeName ?? wName("trHeight"), nextAttrs);
281
- const rendered = renderProps(
282
- setPropsChild(props, "trHeight", child, TR_PR_ORDER)
283
- );
250
+ const child = elementXml(current.tag ?? wName("trHeight"), nextAttrs);
251
+ const rendered = renderProps(setChild(props, "trHeight", child));
284
252
  if (rendered === trPr) return null;
285
253
  const parsed = parsePropsXml(rendered);
286
254
  const format = parsed ? readRowFormat(parsed) : null;
@@ -2,15 +2,20 @@
2
2
  * Reads table formatting for display. Table borders and margins are folded into cell values so CSS
3
3
  * collapsed-border resolution matches OOXML inheritance without changing exported XML.
4
4
  */
5
- import type { CellFormat, CellMargins, InsideBorders, RowFormat, TableFormat, TableWidth } from "../../model/format";
6
- export type { CellMargins, InsideBorders } from "../../model/format";
5
+ import { type BandSizes, type CellFormat, type CellMargins, type CellStyleFormat, type CellVerticalAlign, type InsideBorders, type RowFormat, type RunFormat, type TableFormat, type TableStyleConditions, type TableStyleOverrideType, type TableWidth } from "../../model/format";
6
+ import { type BorderLine } from "../../ooxml/units";
7
+ import type { ParagraphPlacement } from "../formatting/resolve";
8
+ import type { ParagraphFormatLayer } from "../formatting/tabStops";
9
+ export type { BandSizes, CellMargins, CellStyleFormat, InsideBorders, TableStyleConditions, TableStyleOverrideType, } from "../../model/format";
7
10
  /**
8
11
  * The width written down by `<w:tblW>` or `<w:tcW>`.
9
12
  * If we cannot make out what it means it is null, and such a width goes back out unchanged on export.
10
13
  *
11
- * `auto` and `nil` leave the width to the layout, so whatever number stands beside them says nothing.
14
+ * `auto` and `nil` leave the width to the layout unless the value carries an explicit percentage.
12
15
  * A percentage may be written in fiftieths of a percent, as in `w:w="2500"`, or as `w:w="50%"`.
13
16
  * Both have to be gathered into the same unit, or the table collapses into a thin strip on screen.
17
+ * Word lets an explicit `%` override `w:type` (MS-OI29500 §2.1.185(b)); see
18
+ * spec/notes/simpleTypes.md. A universal measure under `pct` remains unreadable here.
14
19
  */
15
20
  export declare function readTableWidth(parent: Element | null, name: "tblW" | "tcW"): TableWidth | null;
16
21
  /** The sequence of column widths (dxa) set by `<w:tblGrid>`. Revision markup (tblGridChange) is skipped */
@@ -32,15 +37,20 @@ export declare function readCellMarginsOf(parent: Element | null, name: "tblCell
32
37
  * their cell padding from.
33
38
  */
34
39
  export declare function layerCellMargins(style: CellMargins, direct: CellMargins): CellMargins;
35
- /** The lines a cell falls back on, one per side, already resolved for its spot in the grid */
40
+ /**
41
+ * The lines a cell falls back on, one per side, already resolved for its spot in the grid.
42
+ *
43
+ * They are held as the markup records them rather than as CSS, because a cell that takes one of
44
+ * them over as a border of its own writes it back into `w:tcBorders`.
45
+ */
36
46
  export interface CellBorderDefaults {
37
- top: string | null;
38
- bottom: string | null;
39
- left: string | null;
40
- right: string | null;
47
+ top: BorderLine | null;
48
+ bottom: BorderLine | null;
49
+ left: BorderLine | null;
50
+ right: BorderLine | null;
41
51
  }
42
52
  export declare const NO_BORDER_DEFAULTS: CellBorderDefaults;
43
- /** Which sides of a cell lie on the edge of the table's grid */
53
+ /** Which sides of a cell lie on the edge of a part of the table */
44
54
  export interface GridEdges {
45
55
  top: boolean;
46
56
  bottom: boolean;
@@ -59,19 +69,48 @@ export interface GridSize {
59
69
  cols: number;
60
70
  }
61
71
  /**
62
- * Which sides of the block a cell covers lie on the edge of the grid, merges included.
63
- * Everything that works out a cell's lines asks this first, whether the cell is being imported,
64
- * created fresh, or looked up again in a table on screen.
72
+ * Everything one cell falls back on for what it did not write down itself, worked out from where
73
+ * it sits in the grid by `cellDefaultsFor`. Everything that reads or edits a cell takes one of
74
+ * these, so the lines a cell draws and the lines an edit measures against are always the same.
65
75
  */
66
- export declare function gridEdgesOf(rect: GridRect, grid: GridSize): GridEdges;
76
+ export interface CellDefaults {
77
+ borders: CellBorderDefaults;
78
+ margins: CellMargins;
79
+ background: string | null;
80
+ verticalAlign: CellVerticalAlign | null;
81
+ /** What the paragraphs inside the cell resolve their formatting against */
82
+ placement: ParagraphPlacement;
83
+ }
84
+ export declare const NO_CELL_DEFAULTS: CellDefaults;
85
+ export declare const NO_BAND_SIZES: BandSizes;
86
+ /** How many rows and columns one band of a table style is made of, read from the style's `w:tblPr` */
87
+ export declare function readBandSizes(tblPr: Element | null): BandSizes;
88
+ export declare function layerBandSizes(style: BandSizes, over: BandSizes): BandSizes;
89
+ export declare const NO_CELL_STYLE_FORMAT: CellStyleFormat;
90
+ export declare const NO_TABLE_STYLE_CONDITIONS: TableStyleConditions;
91
+ /**
92
+ * The formatting one conditional format of a table style lays down (`w:tblStylePr`).
93
+ * Its `w:tblPr` speaks for the region as a whole and its `w:tcPr` for the cells in it, so the
94
+ * cell values are read with the table values underneath them.
95
+ */
96
+ export interface ConditionalTableFormat {
97
+ paragraph: ParagraphFormatLayer;
98
+ run: RunFormat;
99
+ table: TableFormat;
100
+ cell: CellStyleFormat;
101
+ }
67
102
  /**
68
- * The lines the four sides of one cell fall back on.
103
+ * What a conditional format lays down for the cells of its region.
69
104
  *
70
- * A side on the edge of the grid falls on the table's outer border, and one facing another cell on
71
- * the table's inside line. An outer side the document wrote as `none` is passed through as it is:
72
- * the table switched that line off, and nothing is to bring it back.
105
+ * The `w:tcPr` of a conditional format writes the lines of the region rather than of every cell in
106
+ * it: `insideH` and `insideV` are the lines between the cells it covers, which is how the header
107
+ * row of a style with `insideV` set to `nil` is drawn as one unbroken band.
73
108
  */
74
- export declare function cellBorderDefaults(edges: GridEdges, outer: TableFormat | null, inside: InsideBorders): CellBorderDefaults;
109
+ export declare function readCellStyleFormat(tcPr: Element | null, tblPr: Element | null): CellStyleFormat;
110
+ /** Lays one conditional format over the one a style further up the `basedOn` chain wrote for the same part */
111
+ export declare function layerCellStyleFormat(base: CellStyleFormat, over: CellStyleFormat): CellStyleFormat;
112
+ /** The conditions a table style lays down for its cells alone, which is what a table carries for its cells to draw */
113
+ export declare function cellConditionsOf(conditions: Readonly<Partial<Record<TableStyleOverrideType, ConditionalTableFormat>>>): TableStyleConditions;
75
114
  /** The name of the table style `w:tblStyle` points at. null if it points at none */
76
115
  export declare function tblStyleIdOf(tblPr: Element | null): string | null;
77
116
  export declare function readTableFormat(tblPr: Element | null): TableFormat | null;
@@ -79,11 +118,12 @@ export declare function readRowFormat(trPr: Element | null): RowFormat | null;
79
118
  /**
80
119
  * Cell formatting.
81
120
  * A side for which the cell has not written down its own border uses the line that side falls on,
82
- * which is the table's outer border or its inside line depending on where the cell sits.
83
- * The padding works the same way: what the cell wrote down wins, and the table's cell margins lie
84
- * underneath it. null if there is nothing at all to draw.
121
+ * which is the table's outer border, its inside line, or the line a conditional format of its
122
+ * style draws there, depending on where the cell sits.
123
+ * The fill, the vertical alignment and the padding work the same way: what the cell wrote down
124
+ * wins, and what it falls back on lies underneath. null if there is nothing at all to draw.
85
125
  */
86
- export declare function readCellFormat(tcPr: Element | null, defaults: CellBorderDefaults, margins?: CellMargins): CellFormat | null;
126
+ export declare function readCellFormat(tcPr: Element | null, defaults?: CellDefaults): CellFormat | null;
87
127
  /** The inside lines the table lays down, read from the table's own formatting XML */
88
128
  export declare function insideBordersOf(tblPr: string | null): InsideBorders;
89
129
  /** The cell margins the table lays down, read from the table's own formatting XML */
@@ -92,5 +132,5 @@ export declare function cellMarginsOf(tblPr: string | null): CellMargins;
92
132
  * Reads a cell formatting fragment we operated on back into display values, along the same path
93
133
  * the import takes. The same fragment always yields the same display values.
94
134
  */
95
- export declare function readCellProps(tcPr: string | null, defaults: CellBorderDefaults, margins?: CellMargins): CellFormat | null;
135
+ export declare function readCellProps(tcPr: string | null, defaults?: CellDefaults): CellFormat | null;
96
136
  /** The formatting a cell holds. The original XML and the display values read out of it form a pair */