@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,31 +1,46 @@
1
1
  // src/docx/tableFormatting/reading.ts
2
+ import {
3
+ TABLE_STYLE_CONDITIONS
4
+ } from "../../model/format.js";
5
+ import { parsePropsXml } from "../../ooxml/props.js";
6
+ import {
7
+ ST_DecimalNumber,
8
+ ST_MeasurementOrPercent,
9
+ ST_SignedTwipsMeasure,
10
+ ST_TwipsMeasure
11
+ } from "../../ooxml/simpleTypes.js";
2
12
  import {
3
13
  ALIGN_BY_JC,
14
+ borderLineCss,
4
15
  borderSide,
5
16
  childValue,
6
17
  isOn,
7
18
  shadingOf,
8
- toNumber,
9
19
  twipsToPt,
10
20
  wAttr
11
21
  } from "../../ooxml/units.js";
12
22
  import { childByLocalName } from "../../ooxml/xml.js";
13
- import { parsePropsXml } from "../propsXml.js";
23
+ var FIFTIETHS_PER_PERCENT = 50;
14
24
  function readTableWidth(parent, name) {
15
25
  const el = parent ? childByLocalName(parent, name) : null;
16
26
  if (!el) return null;
17
27
  const type = wAttr(el, "type") ?? "dxa";
28
+ const width = ST_MeasurementOrPercent.parse(wAttr(el, "w"));
29
+ if (width?.kind === "percent") {
30
+ const fiftieths = Math.round(width.value * FIFTIETHS_PER_PERCENT);
31
+ return Number.isFinite(fiftieths) ? { type: "pct", fiftieths } : null;
32
+ }
18
33
  if (type === "auto") return { type: "auto" };
19
34
  if (type === "nil") return { type: "nil" };
20
- const raw = wAttr(el, "w");
21
- const value = toNumber(raw);
22
- if (value === null) return null;
23
- if (type === "dxa") return { type: "dxa", twips: value };
35
+ if (width === null) return null;
36
+ if (type === "dxa") {
37
+ return { type: "dxa", twips: width.value };
38
+ }
24
39
  if (type === "pct") {
25
- const isPercentText = raw?.endsWith("%") === true;
40
+ if (width.kind === "twips") return null;
26
41
  return {
27
42
  type: "pct",
28
- fiftieths: isPercentText ? Math.round(value * 50) : value
43
+ fiftieths: width.value
29
44
  };
30
45
  }
31
46
  return null;
@@ -35,7 +50,7 @@ function readGridCols(tblGrid) {
35
50
  const cols = [];
36
51
  for (const child of Array.from(tblGrid.children)) {
37
52
  if (child.localName !== "gridCol") continue;
38
- const w = toNumber(wAttr(child, "w"));
53
+ const w = ST_TwipsMeasure.parse(wAttr(child, "w"));
39
54
  if (w !== null) cols.push(w);
40
55
  }
41
56
  return cols;
@@ -69,7 +84,7 @@ function marginSide(margins, names) {
69
84
  if (!el) continue;
70
85
  const type = wAttr(el, "type") ?? "dxa";
71
86
  if (type === "nil") return 0;
72
- return type === "dxa" ? twipsToPt(wAttr(el, "w")) : null;
87
+ return type === "dxa" ? twipsToPt(ST_TwipsMeasure.parse(wAttr(el, "w"))) : null;
73
88
  }
74
89
  return null;
75
90
  }
@@ -97,22 +112,89 @@ var NO_BORDER_DEFAULTS = {
97
112
  left: null,
98
113
  right: null
99
114
  };
100
- function gridEdgesOf(rect, grid) {
115
+ var NO_CELL_DEFAULTS = {
116
+ borders: NO_BORDER_DEFAULTS,
117
+ margins: NO_CELL_MARGINS,
118
+ background: null,
119
+ verticalAlign: null,
120
+ placement: { tableStyleId: null, conditions: [] }
121
+ };
122
+ var NO_BAND_SIZES = { row: null, col: null };
123
+ function bandSize(tblPr, name) {
124
+ const count = ST_DecimalNumber.parse(childValue(tblPr, name));
125
+ return count !== null && count > 0 ? count : null;
126
+ }
127
+ function readBandSizes(tblPr) {
128
+ if (!tblPr) return NO_BAND_SIZES;
129
+ return {
130
+ row: bandSize(tblPr, "tblStyleRowBandSize"),
131
+ col: bandSize(tblPr, "tblStyleColBandSize")
132
+ };
133
+ }
134
+ function layerBandSizes(style, over) {
135
+ return { row: over.row ?? style.row, col: over.col ?? style.col };
136
+ }
137
+ var NO_CELL_STYLE_BORDERS = {
138
+ top: null,
139
+ bottom: null,
140
+ left: null,
141
+ right: null
142
+ };
143
+ var NO_CELL_STYLE_FORMAT = {
144
+ background: null,
145
+ borders: NO_CELL_STYLE_BORDERS,
146
+ inside: NO_INSIDE_BORDERS,
147
+ margins: NO_CELL_MARGINS,
148
+ verticalAlign: null
149
+ };
150
+ var NO_TABLE_STYLE_CONDITIONS = {};
151
+ function conditionBorders(tcBorders, table) {
152
+ return {
153
+ top: borderSide(tcBorders, "top") ?? table.borderTop ?? null,
154
+ bottom: borderSide(tcBorders, "bottom") ?? table.borderBottom ?? null,
155
+ left: borderSide(tcBorders, "left") ?? borderSide(tcBorders, "start") ?? table.borderLeft ?? null,
156
+ right: borderSide(tcBorders, "right") ?? borderSide(tcBorders, "end") ?? table.borderRight ?? null
157
+ };
158
+ }
159
+ function readCellStyleFormat(tcPr, tblPr) {
160
+ const table = readTableFormat(tblPr) ?? {};
161
+ const tcBorders = tcPr ? childByLocalName(tcPr, "tcBorders") : null;
162
+ return {
163
+ background: (tcPr ? shadingOf(tcPr) : null) ?? table.background ?? null,
164
+ borders: conditionBorders(tcBorders, table),
165
+ inside: layerInsideBorders(readInsideBorders(tblPr), {
166
+ horizontal: borderSide(tcBorders, "insideH"),
167
+ vertical: borderSide(tcBorders, "insideV")
168
+ }),
169
+ margins: readCellMarginsOf(tcPr, "tcMar"),
170
+ verticalAlign: tcPr ? cellVerticalAlignOf(tcPr) : null
171
+ };
172
+ }
173
+ function layerCellStyleBorders(base, over) {
101
174
  return {
102
- top: rect.top === 0,
103
- bottom: rect.bottom === grid.rows,
104
- left: rect.left === 0,
105
- right: rect.right === grid.cols
175
+ top: over.top ?? base.top,
176
+ bottom: over.bottom ?? base.bottom,
177
+ left: over.left ?? base.left,
178
+ right: over.right ?? base.right
106
179
  };
107
180
  }
108
- function cellBorderDefaults(edges, outer, inside) {
181
+ function layerCellStyleFormat(base, over) {
109
182
  return {
110
- top: edges.top ? outer?.borderTop ?? null : inside.horizontal,
111
- bottom: edges.bottom ? outer?.borderBottom ?? null : inside.horizontal,
112
- left: edges.left ? outer?.borderLeft ?? null : inside.vertical,
113
- right: edges.right ? outer?.borderRight ?? null : inside.vertical
183
+ background: over.background ?? base.background,
184
+ borders: layerCellStyleBorders(base.borders, over.borders),
185
+ inside: layerInsideBorders(base.inside, over.inside),
186
+ margins: layerCellMargins(base.margins, over.margins),
187
+ verticalAlign: over.verticalAlign ?? base.verticalAlign
114
188
  };
115
189
  }
190
+ function cellConditionsOf(conditions) {
191
+ const cells = {};
192
+ for (const type of TABLE_STYLE_CONDITIONS) {
193
+ const format = conditions[type];
194
+ if (format) cells[type] = format.cell;
195
+ }
196
+ return cells;
197
+ }
116
198
  function tblStyleIdOf(tblPr) {
117
199
  return tblPr ? childValue(tblPr, "tblStyle") : null;
118
200
  }
@@ -133,12 +215,12 @@ function readTableFormat(tblPr) {
133
215
  const align = ALIGN_BY_JC[childValue(tblPr, "jc") ?? ""];
134
216
  if (align) format.align = align;
135
217
  const tblInd = childByLocalName(tblPr, "tblInd");
136
- const indentLeftPt = tblInd ? twipsToPt(wAttr(tblInd, "w")) : null;
218
+ const indentLeftPt = tblInd ? twipsToPt(ST_SignedTwipsMeasure.parse(wAttr(tblInd, "w"))) : null;
137
219
  if (indentLeftPt !== null) format.indentLeftPt = indentLeftPt;
138
220
  return format;
139
221
  }
140
222
  function readRowHeight(trHeight) {
141
- const pt = twipsToPt(wAttr(trHeight, "val"));
223
+ const pt = twipsToPt(ST_TwipsMeasure.parse(wAttr(trHeight, "val")));
142
224
  if (pt === null || pt <= 0) return null;
143
225
  const rule = wAttr(trHeight, "hRule") === "exact" ? "exact" : "atLeast";
144
226
  return { rule, pt };
@@ -158,6 +240,9 @@ var CELL_VERTICAL_ALIGN_BY_VAL = {
158
240
  center: "center",
159
241
  bottom: "bottom"
160
242
  };
243
+ function cellVerticalAlignOf(tcPr) {
244
+ return CELL_VERTICAL_ALIGN_BY_VAL[childValue(tcPr, "vAlign") ?? ""] ?? null;
245
+ }
161
246
  function readCellPadding(tcPr, margins) {
162
247
  const padding = layerCellMargins(margins, readCellMarginsOf(tcPr, "tcMar"));
163
248
  const format = {};
@@ -167,24 +252,26 @@ function readCellPadding(tcPr, margins) {
167
252
  if (padding.leftPt !== null) format.paddingLeftPt = padding.leftPt;
168
253
  return format;
169
254
  }
170
- function readCellFormat(tcPr, defaults, margins = NO_CELL_MARGINS) {
255
+ function readCellFormat(tcPr, defaults = NO_CELL_DEFAULTS) {
171
256
  const borders = tcPr ? childByLocalName(tcPr, "tcBorders") : null;
257
+ const lines = defaults.borders;
172
258
  const format = {};
173
- const top = borderSide(borders, "top") ?? defaults.top;
259
+ const top = borderSide(borders, "top") ?? borderLineCss(lines.top);
174
260
  if (top) format.borderTop = top;
175
- const bottom = borderSide(borders, "bottom") ?? defaults.bottom;
261
+ const bottom = borderSide(borders, "bottom") ?? borderLineCss(lines.bottom);
176
262
  if (bottom) format.borderBottom = bottom;
177
- const left = borderSide(borders, "left") ?? borderSide(borders, "start") ?? defaults.left;
263
+ const left = borderSide(borders, "left") ?? borderSide(borders, "start") ?? borderLineCss(lines.left);
178
264
  if (left) format.borderLeft = left;
179
- const right = borderSide(borders, "right") ?? borderSide(borders, "end") ?? defaults.right;
265
+ const right = borderSide(borders, "right") ?? borderSide(borders, "end") ?? borderLineCss(lines.right);
180
266
  if (right) format.borderRight = right;
181
- if (tcPr) {
182
- const background = shadingOf(tcPr);
183
- if (background) format.background = background;
184
- const verticalAlign = CELL_VERTICAL_ALIGN_BY_VAL[childValue(tcPr, "vAlign") ?? ""];
185
- if (verticalAlign) format.verticalAlign = verticalAlign;
186
- }
187
- const padded = { ...format, ...readCellPadding(tcPr, margins) };
267
+ const background = (tcPr ? shadingOf(tcPr) : null) ?? defaults.background;
268
+ if (background) format.background = background;
269
+ const verticalAlign = (tcPr ? cellVerticalAlignOf(tcPr) : null) ?? defaults.verticalAlign;
270
+ if (verticalAlign) format.verticalAlign = verticalAlign;
271
+ const padded = {
272
+ ...format,
273
+ ...readCellPadding(tcPr, defaults.margins)
274
+ };
188
275
  return Object.keys(padded).length > 0 ? padded : null;
189
276
  }
190
277
  function insideBordersOf(tblPr) {
@@ -195,23 +282,30 @@ function cellMarginsOf(tblPr) {
195
282
  const el = tblPr === null ? null : parsePropsXml(tblPr);
196
283
  return readCellMarginsOf(el, "tblCellMar");
197
284
  }
198
- function readCellProps(tcPr, defaults, margins = NO_CELL_MARGINS) {
285
+ function readCellProps(tcPr, defaults = NO_CELL_DEFAULTS) {
199
286
  const el = tcPr === null ? null : parsePropsXml(tcPr);
200
- return readCellFormat(el, defaults, margins);
287
+ return readCellFormat(el, defaults);
201
288
  }
202
289
  export {
290
+ NO_BAND_SIZES,
203
291
  NO_BORDER_DEFAULTS,
292
+ NO_CELL_DEFAULTS,
204
293
  NO_CELL_MARGINS,
294
+ NO_CELL_STYLE_FORMAT,
205
295
  NO_INSIDE_BORDERS,
206
- cellBorderDefaults,
296
+ NO_TABLE_STYLE_CONDITIONS,
297
+ cellConditionsOf,
207
298
  cellMarginsOf,
208
- gridEdgesOf,
209
299
  insideBordersOf,
300
+ layerBandSizes,
210
301
  layerCellMargins,
302
+ layerCellStyleFormat,
211
303
  layerInsideBorders,
304
+ readBandSizes,
212
305
  readCellFormat,
213
306
  readCellMarginsOf,
214
307
  readCellProps,
308
+ readCellStyleFormat,
215
309
  readGridCols,
216
310
  readInsideBorders,
217
311
  readRowFormat,
@@ -1,2 +1,3 @@
1
+ export * from "./tableFormatting/conditions";
1
2
  export * from "./tableFormatting/editing";
2
3
  export * from "./tableFormatting/reading";
@@ -1,3 +1,4 @@
1
1
  // src/docx/tableFormatting.ts
2
+ export * from "./tableFormatting/conditions.js";
2
3
  export * from "./tableFormatting/editing.js";
3
4
  export * from "./tableFormatting/reading.js";
@@ -1,13 +1,12 @@
1
1
  // src/docx/tableTemplate.ts
2
2
  import { elementXml } from "../ooxml/element.js";
3
3
  import { wName } from "../ooxml/names.js";
4
+ import { orderedElement, parsePropsXml } from "../ooxml/props.js";
4
5
  import { docxSchema } from "../schema/index.js";
5
6
  import { A4_PORTRAIT, bodyWidth } from "./pageGeometry.js";
6
- import { parsePropsXml } from "./propsXml.js";
7
7
  import {
8
- cellBorderDefaults,
9
- gridEdgesOf,
10
- NO_CELL_MARGINS,
8
+ cellDefaultsFor,
9
+ NO_CELL_SOURCES,
11
10
  readCellFormat,
12
11
  readInsideBorders,
13
12
  readTableFormat,
@@ -35,14 +34,21 @@ function borderXml(side) {
35
34
  ]);
36
35
  }
37
36
  function tablePropsXml(width) {
38
- const borders = BORDER_SIDES.map(borderXml).join("");
39
- return elementXml(
37
+ const borders = orderedElement(
38
+ wName("tblBorders"),
39
+ [],
40
+ BORDER_SIDES.map((side) => ({ name: side, xml: borderXml(side) }))
41
+ );
42
+ return orderedElement(
40
43
  wName("tblPr"),
41
44
  [],
42
45
  [
43
- widthXml("tblW", width),
44
- elementXml(wName("tblBorders"), [], [borders]),
45
- elementXml(wName("tblLayout"), [[wName("type"), "fixed"]])
46
+ { name: "tblW", xml: widthXml("tblW", width) },
47
+ { name: "tblBorders", xml: borders },
48
+ {
49
+ name: "tblLayout",
50
+ xml: elementXml(wName("tblLayout"), [[wName("type"), "fixed"]])
51
+ }
46
52
  ]
47
53
  );
48
54
  }
@@ -53,7 +59,11 @@ function widthXml(name, width) {
53
59
  ]);
54
60
  }
55
61
  function cellPropsXml(width) {
56
- return elementXml(wName("tcPr"), [], [widthXml("tcW", width)]);
62
+ return orderedElement(
63
+ wName("tcPr"),
64
+ [],
65
+ [{ name: "tcW", xml: widthXml("tcW", width) }]
66
+ );
57
67
  }
58
68
  function evenGridCols(cols, total) {
59
69
  const base = Math.floor(total / cols);
@@ -70,7 +80,7 @@ function cellTemplate(width, defaults) {
70
80
  tcPr,
71
81
  tcW: readTableWidth(el, "tcW"),
72
82
  // A new table writes no `tblCellMar`, so its cells take their padding from the stylesheet
73
- format: readCellFormat(el, defaults, NO_CELL_MARGINS)
83
+ format: readCellFormat(el, defaults)
74
84
  };
75
85
  }
76
86
  function cellNode(props) {
@@ -98,17 +108,18 @@ function createTableNode(rows, cols, geometry = A4_PORTRAIT) {
98
108
  const gridCols = evenGridCols(cols, total);
99
109
  const tblPr = tablePropsXml(total);
100
110
  const tblPrEl = parsePropsXml(tblPr);
101
- const inside = readInsideBorders(tblPrEl);
102
111
  const outer = readTableFormat(tblPrEl);
112
+ const sources = {
113
+ ...NO_CELL_SOURCES,
114
+ outer,
115
+ inside: readInsideBorders(tblPrEl)
116
+ };
103
117
  const cellAt = (row, col) => cellTemplate(
104
118
  gridCols[col],
105
- cellBorderDefaults(
106
- gridEdgesOf(
107
- { top: row, bottom: row + 1, left: col, right: col + 1 },
108
- { rows, cols }
109
- ),
110
- outer,
111
- inside
119
+ cellDefaultsFor(
120
+ { top: row, bottom: row + 1, left: col, right: col + 1 },
121
+ { rows, cols },
122
+ sources
112
123
  )
113
124
  );
114
125
  return docxSchema.nodes.table.create(
@@ -6,6 +6,7 @@
6
6
  */
7
7
  import type { Node as PMNode } from "prosemirror-model";
8
8
  import type { DocxEditorHandle } from "./DocxEditor";
9
+ import type { ExportProblem } from "./docx/invariants";
9
10
  export declare const DOCX_MIME_TYPE = "application/vnd.openxmlformats-officedocument.wordprocessingml.document";
10
11
  export interface DownloadDocxOptions {
11
12
  /** The name to save under. The `.docx` suffix may be there or not */
@@ -19,6 +20,9 @@ export type DownloadDocxResult = {
19
20
  status: "unavailable";
20
21
  } | {
21
22
  status: "empty";
23
+ } | {
24
+ status: "blocked";
25
+ problems: readonly ExportProblem[];
22
26
  };
23
27
  /** Settles the end of the name on exactly one `.docx` */
24
28
  export declare function withDocxExtension(fileName: string): string;
@@ -48,10 +52,9 @@ export declare function hasExportableContent(doc: PMNode): boolean;
48
52
  * Downloads the edited document as a docx file.
49
53
  *
50
54
  * `unavailable` when the editor is not mounted yet or the document could not be
51
- * opened, `empty` when there is nothing to export, and `exported` once a file has
52
- * gone out.
53
- * If writing the document back is blocked (a new list in a document without
54
- * numbering.xml, and the like), it is not passed over silently: `DocxExportError`
55
- * is rethrown as is.
55
+ * opened, `empty` when there is nothing to export, `blocked` with every reason
56
+ * when the document cannot be written back (a new list in a document without
57
+ * numbering.xml, and the like), and `exported` once a file has gone out.
58
+ * A refusal the check did not foresee is still thrown as `DocxExportError`.
56
59
  */
57
60
  export declare function downloadDocx(editor: DocxEditorHandle | null | undefined, options: DownloadDocxOptions): DownloadDocxResult;
package/dist/download.js CHANGED
@@ -29,6 +29,8 @@ function hasExportableContent(doc) {
29
29
  function downloadDocx(editor, options) {
30
30
  if (!editor) return { status: "unavailable" };
31
31
  if (!hasExportableContent(editor.view.state.doc)) return { status: "empty" };
32
+ const problems = editor.exportProblems();
33
+ if (problems.length > 0) return { status: "blocked", problems };
32
34
  const bytes = editor.exportBytes();
33
35
  const fileName = withDocxExtension(options.fileName);
34
36
  downloadBlob(createDocxBlob(bytes), fileName);
@@ -1,5 +1,7 @@
1
1
  // src/editor/clipboard/inlineFormatting.ts
2
- import { editRunProps } from "../../docx/runProps.js";
2
+ import { rPrOf } from "../../docx/formatting.js";
3
+ import { readRunProps } from "../../docx/runProps.js";
4
+ import { HALF_POINTS_PER_PT, ST_HpsMeasure } from "../../ooxml/simpleTypes.js";
3
5
  import { docxSchema } from "../../schema/index.js";
4
6
  import { editorClassNames } from "../../styles/classNames.js";
5
7
  var IGNORED_TAGS = /* @__PURE__ */ new Set([
@@ -76,8 +78,8 @@ function fontSizePt(value) {
76
78
  const amount = Number.parseFloat(match[1] ?? "");
77
79
  if (!Number.isFinite(amount) || amount <= 0) return null;
78
80
  const points = match[2]?.toLowerCase() === "px" ? amount * 0.75 : amount;
79
- const rounded = Math.round(points * 2) / 2;
80
- return rounded > 0 && rounded <= 819 ? rounded : null;
81
+ const half = Math.round(points * HALF_POINTS_PER_PT);
82
+ return ST_HpsMeasure.format(half) === null ? null : half / HALF_POINTS_PER_PT;
81
83
  }
82
84
  function legacyFontSize(value) {
83
85
  const sizes = [8, 10, 12, 14, 18, 24, 36];
@@ -150,34 +152,21 @@ function contextFor(parent, element, readElementStyle = true) {
150
152
  function withInlineStyle(context, style) {
151
153
  return { ...context, style: { ...context.style, ...style } };
152
154
  }
155
+ function settingsOf(style) {
156
+ const settings = {};
157
+ if (style.bold) settings.bold = true;
158
+ if (style.italic) settings.italic = true;
159
+ if (style.underline) settings.underline = "single";
160
+ if (style.strike) settings.strike = true;
161
+ if (style.fontSizePt !== void 0) settings.fontSizePt = style.fontSizePt;
162
+ if (style.fontFamily !== void 0) settings.fontFamily = style.fontFamily;
163
+ if (style.color !== void 0) settings.color = style.color;
164
+ if (style.background !== void 0) settings.background = style.background;
165
+ return settings;
166
+ }
153
167
  function runMark(style) {
154
- const edits = [];
155
- if (style.bold) edits.push({ kind: "toggle", toggle: "bold", on: true });
156
- if (style.italic) edits.push({ kind: "toggle", toggle: "italic", on: true });
157
- if (style.underline) {
158
- edits.push({ kind: "toggle", toggle: "underline", on: true });
159
- }
160
- if (style.strike) edits.push({ kind: "toggle", toggle: "strike", on: true });
161
- if (style.fontSizePt !== void 0) {
162
- edits.push({ kind: "fontSize", pt: style.fontSizePt });
163
- }
164
- if (style.fontFamily !== void 0) {
165
- edits.push({ kind: "fontFamily", name: style.fontFamily });
166
- }
167
- if (style.color !== void 0)
168
- edits.push({ kind: "color", hex: style.color });
169
- if (style.background !== void 0) {
170
- edits.push({ kind: "background", hex: style.background });
171
- }
172
- let props = {
173
- rPr: null,
174
- format: null
175
- };
176
- for (const edit of edits) {
177
- const next = editRunProps(props, null, edit);
178
- if (next) props = next;
179
- }
180
- return props.rPr === null ? null : docxSchema.marks.run.create({ rPr: props.rPr, format: props.format });
168
+ const rPr = rPrOf(settingsOf(style));
169
+ return rPr === null ? null : docxSchema.marks.run.create({ rPr, format: readRunProps(rPr) });
181
170
  }
182
171
  function marksFor(context) {
183
172
  const marks = [];
@@ -1,10 +1,14 @@
1
1
  /** Edits Word comments through their range markers and reference nodes. */
2
2
  import { type Command, type EditorState } from "prosemirror-state";
3
3
  import type { NewComment } from "./model";
4
- /** Whether a non-empty selection in one paragraph can receive a comment. */
5
- export declare function canAddComment(state: EditorState): boolean;
6
4
  /** Adds a plain-text comment to the current text selection. */
7
5
  export declare function addComment(comment: NewComment): Command;
6
+ /**
7
+ * Whether a non-empty selection in one paragraph can receive a comment.
8
+ * This is the command itself asked without a dispatch, over a comment standing in for the one the
9
+ * user would write, so the button and the click cannot answer differently.
10
+ */
11
+ export declare function canAddComment(state: EditorState): boolean;
8
12
  /** Replaces the plain-text body of one comment, retaining its author and anchor. */
9
13
  export declare function updateComment(id: string, text: string): Command;
10
14
  /** Marks a comment thread resolved or open without deleting it. */
@@ -4,11 +4,11 @@ import {
4
4
  } from "prosemirror-state";
5
5
  import { commentParaId } from "../../../docx/comments.js";
6
6
  import { docxSchema } from "../../../schema/index.js";
7
- import { transactionAllowed } from "../../../schema/guards.js";
7
+ import { guardedCommand } from "../../../schema/guards.js";
8
8
  import {
9
9
  reservedCommentIds,
10
10
  reservedCommentParaIds
11
- } from "../../plugins/commentReservations.js";
11
+ } from "../../editorDocument.js";
12
12
  import { documentComments, repliesAttr, stringAttr } from "./reading.js";
13
13
  function validCommentSelection(state) {
14
14
  const { selection } = state;
@@ -113,27 +113,21 @@ function addCommentTransaction(state, comment) {
113
113
  null,
114
114
  startMarks
115
115
  );
116
- const transaction = state.tr.insert(to, end).insert(to + 1, reference).insert(from, start);
117
- return transactionAllowed(transaction, state) ? transaction : null;
116
+ return state.tr.insert(to, end).insert(to + 1, reference).insert(from, start);
117
+ }
118
+ function addComment(comment) {
119
+ return guardedCommand((state) => addCommentTransaction(state, comment));
118
120
  }
119
121
  function canAddComment(state) {
120
- return addCommentTransaction(state, {
122
+ return addComment({
121
123
  text: "comment",
122
124
  author: "Author",
123
125
  date: "1970-01-01T00:00:00.000Z"
124
- }) !== null;
125
- }
126
- function addComment(comment) {
127
- return (state, dispatch) => {
128
- const transaction = addCommentTransaction(state, comment);
129
- if (!transaction) return false;
130
- dispatch?.(transaction);
131
- return true;
132
- };
126
+ })(state);
133
127
  }
134
128
  function updateComment(id, text) {
135
- return (state, dispatch) => {
136
- if (text.trim().length === 0) return false;
129
+ return guardedCommand((state) => {
130
+ if (text.trim().length === 0) return null;
137
131
  let transaction = state.tr;
138
132
  let changed = false;
139
133
  state.doc.descendants((node, pos) => {
@@ -148,13 +142,11 @@ function updateComment(id, text) {
148
142
  }
149
143
  return true;
150
144
  });
151
- if (!changed || !transactionAllowed(transaction, state)) return false;
152
- dispatch?.(transaction);
153
- return true;
154
- };
145
+ return changed ? transaction : null;
146
+ });
155
147
  }
156
148
  function updateReference(id, change) {
157
- return (state, dispatch) => {
149
+ return guardedCommand((state) => {
158
150
  let transaction = state.tr;
159
151
  let changed = false;
160
152
  state.doc.descendants((node, pos) => {
@@ -168,10 +160,8 @@ function updateReference(id, change) {
168
160
  }
169
161
  return false;
170
162
  });
171
- if (!changed || !transactionAllowed(transaction, state)) return false;
172
- dispatch?.(transaction);
173
- return true;
174
- };
163
+ return changed ? transaction : null;
164
+ });
175
165
  }
176
166
  function setCommentResolved(id, resolved) {
177
167
  return (state, dispatch) => updateReference(id, (node) => {
@@ -261,7 +251,7 @@ function removeCommentReply(commentId, replyId) {
261
251
  });
262
252
  }
263
253
  function removeComment(id) {
264
- return (state, dispatch) => {
254
+ return guardedCommand((state) => {
265
255
  const positions = [];
266
256
  state.doc.descendants((node, pos) => {
267
257
  if ((node.type.name === "commentStart" || node.type.name === "commentEnd" || node.type.name === "commentReference") && stringAttr(node.attrs.id) === id) {
@@ -269,15 +259,13 @@ function removeComment(id) {
269
259
  }
270
260
  return true;
271
261
  });
272
- if (positions.length === 0) return false;
262
+ if (positions.length === 0) return null;
273
263
  const transaction = state.tr;
274
264
  for (const marker of positions.sort((a, b) => b.pos - a.pos)) {
275
265
  transaction.delete(marker.pos, marker.pos + marker.size);
276
266
  }
277
- if (!transactionAllowed(transaction, state)) return false;
278
- dispatch?.(transaction);
279
- return true;
280
- };
267
+ return transaction;
268
+ });
281
269
  }
282
270
  function selectComment(id) {
283
271
  return (state, dispatch) => {
@@ -0,0 +1,15 @@
1
+ /** Document-level readers for whether the document as it stands can be written back. */
2
+ import type { EditorState } from "prosemirror-state";
3
+ import { type ExportProblem } from "../../docx/invariants";
4
+ export type { ExportProblem } from "../../docx/invariants";
5
+ /**
6
+ * Every reason writing the document back would be refused, in the order `exportDocx` would raise
7
+ * them, each with the code and message the refusal would carry and the position in the document
8
+ * where there is one. Empty when the file would be written.
9
+ *
10
+ * A state built without an opened document has no file to write back into, so nothing about it
11
+ * can be refused and it reports no problem.
12
+ */
13
+ export declare function documentExportProblems(state: EditorState): readonly ExportProblem[];
14
+ /** Whether the document as it stands can be written back, which is what an export control is drawn from */
15
+ export declare function canExport(state: EditorState): boolean;
@@ -0,0 +1,14 @@
1
+ // src/editor/commands/exportQueries.ts
2
+ import { exportProblems } from "../../docx/invariants.js";
3
+ import { documentOf } from "../editorDocument.js";
4
+ function documentExportProblems(state) {
5
+ const { session } = documentOf(state);
6
+ return session === null ? [] : exportProblems(state.doc, session);
7
+ }
8
+ function canExport(state) {
9
+ return documentExportProblems(state).length === 0;
10
+ }
11
+ export {
12
+ canExport,
13
+ documentExportProblems
14
+ };
@@ -0,0 +1,12 @@
1
+ /** Document-level reader for what the open document holds that the editor cannot model. */
2
+ import type { EditorState } from "prosemirror-state";
3
+ import { type FidelityNote } from "../../docx/fidelity";
4
+ export type { FidelityCode, FidelityNote, FidelitySeverity, } from "../../docx/fidelity";
5
+ /**
6
+ * What the document standing in the editor hides, stands a placeholder in front of, or approximates.
7
+ *
8
+ * The notes are read off the document as it is now, so a note goes away as soon as an edit removes
9
+ * what it was about. `part` is null: an editor state carries the document and not the file it came
10
+ * from, and `importDocx` is where a note can name the part it belongs to.
11
+ */
12
+ export declare function documentFidelity(state: EditorState): readonly FidelityNote[];
@@ -0,0 +1,8 @@
1
+ // src/editor/commands/fidelityQueries.ts
2
+ import { fidelityNotesOf } from "../../docx/fidelity.js";
3
+ function documentFidelity(state) {
4
+ return fidelityNotesOf(state.doc, null);
5
+ }
6
+ export {
7
+ documentFidelity
8
+ };