@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
@@ -1,130 +1,48 @@
1
1
  // src/editor/commands/formatting/editing.ts
2
- import {
3
- editRunProps,
4
- isRunToggleOn,
5
- matchesRunEdit
6
- } from "../../../docx/runProps.js";
7
- import { docxSchema } from "../../../schema/index.js";
8
- import {
9
- insertionInsideLocked,
10
- rangeTouchesLocked
11
- } from "../../../schema/locks.js";
12
- import { editsShut } from "../../../schema/protectionState.js";
13
- import {
14
- activePieces,
15
- caretPiece,
16
- text,
17
- textPieces
18
- } from "./shared.js";
19
- function editedMark(target, edit) {
20
- const next = editRunProps(
21
- { rPr: text(target.mark?.attrs.rPr), format: target.format },
22
- target.pPr,
23
- edit
24
- );
25
- if (!next) return null;
26
- return docxSchema.marks.run.create({
27
- ...target.mark?.attrs,
28
- rPr: next.rPr,
29
- format: next.format
30
- });
31
- }
32
- function planChanges(pieces, edit) {
33
- const changes = [];
34
- for (const target of pieces) {
35
- const mark = editedMark(target, edit);
36
- if (!mark) return null;
37
- changes.push({ from: target.from, to: target.to, mark });
38
- }
39
- return changes;
40
- }
41
- function applyToSelection(state, dispatch, edit) {
42
- const pieces = textPieces(state).filter(
43
- (target) => (
44
- // Text already in the desired state is left untouched, so its original XML survives
45
- !matchesRunEdit(target.format, edit) && // A locked stretch is left out rather than refused: the guard turns down the whole
46
- // transaction, so asking for it would leave the rest of the selection unformatted too
47
- !rangeTouchesLocked(state.doc, target.from, target.to)
48
- )
49
- );
50
- const changes = pieces.length > 0 ? planChanges(pieces, edit) : null;
51
- if (!changes) return false;
52
- if (dispatch) {
53
- const tr = state.tr;
54
- for (const change of changes) {
55
- tr.addMark(change.from, change.to, change.mark);
56
- }
57
- dispatch(tr);
58
- }
59
- return true;
60
- }
61
- function applyToCaret(state, dispatch, edit) {
62
- const target = caretPiece(state);
63
- if (matchesRunEdit(target.format, edit)) return false;
64
- const mark = editedMark(target, edit);
65
- if (!mark) return false;
66
- if (dispatch) {
67
- const marks = state.storedMarks ?? state.selection.$from.marks();
68
- dispatch(state.tr.setStoredMarks(mark.addToSet(marks)));
69
- }
70
- return true;
71
- }
72
- function runEditCommand(edit) {
73
- return (state, dispatch) => {
74
- if (editsShut(state)) return false;
75
- return state.selection.empty ? applyToCaret(state, dispatch, edit) : applyToSelection(state, dispatch, edit);
76
- };
77
- }
2
+ import { editShut, openStretches } from "../../../schema/guards.js";
3
+ import { runPropertyCommands } from "./propertyCommands.js";
4
+ import { textPieces } from "./shared.js";
78
5
  function canFormatText(state) {
79
- if (editsShut(state)) return false;
80
6
  if (state.selection.empty) {
81
- return !insertionInsideLocked(state.doc, state.selection.from);
7
+ return !editShut(state, { kind: "insert", at: state.selection.from });
82
8
  }
83
- return textPieces(state).some(
84
- (target) => !rangeTouchesLocked(state.doc, target.from, target.to)
85
- );
86
- }
87
- function isToggleActive(state, toggle) {
88
- const pieces = activePieces(state);
89
- return pieces.length > 0 && pieces.every((target) => isRunToggleOn(target.format, toggle));
90
- }
91
- function toggleCommand(toggle) {
92
- return (state, dispatch) => {
93
- const edit = {
94
- kind: "toggle",
95
- toggle,
96
- on: !isToggleActive(state, toggle)
97
- };
98
- return runEditCommand(edit)(state, dispatch);
99
- };
100
- }
101
- var toggleBold = toggleCommand("bold");
102
- var toggleItalic = toggleCommand("italic");
103
- var toggleUnderline = toggleCommand("underline");
104
- var toggleStrike = toggleCommand("strike");
9
+ return openStretches(state, textPieces(state), "mark").length > 0;
10
+ }
11
+ var bold = runPropertyCommands("bold");
12
+ var italic = runPropertyCommands("italic");
13
+ var underline = runPropertyCommands("underline");
14
+ var strike = runPropertyCommands("strike");
15
+ var fontSize = runPropertyCommands("fontSizePt");
16
+ var fontFamily = runPropertyCommands("fontFamily");
17
+ var textColor = runPropertyCommands("color");
18
+ var textBackground = runPropertyCommands("background");
19
+ var toggleBold = bold.toggle(true);
20
+ var toggleItalic = italic.toggle(true);
21
+ var toggleUnderline = underline.toggle("single");
22
+ var toggleStrike = strike.toggle(true);
105
23
  function setFontSize(pt) {
106
- return runEditCommand({ kind: "fontSize", pt });
24
+ return fontSize.set(pt);
107
25
  }
108
26
  function setFontFamily(name) {
109
- return runEditCommand({ kind: "fontFamily", name });
27
+ return fontFamily.set(name);
110
28
  }
111
29
  function setTextColor(hex) {
112
- return runEditCommand({ kind: "color", hex });
30
+ return textColor.set(hex);
113
31
  }
114
32
  function setTextBackground(hex) {
115
- return runEditCommand({ kind: "background", hex });
33
+ return textBackground.set(hex);
116
34
  }
117
35
  function isBoldActive(state) {
118
- return isToggleActive(state, "bold");
36
+ return bold.isActive(state);
119
37
  }
120
38
  function isItalicActive(state) {
121
- return isToggleActive(state, "italic");
39
+ return italic.isActive(state);
122
40
  }
123
41
  function isUnderlineActive(state) {
124
- return isToggleActive(state, "underline");
42
+ return underline.isActive(state);
125
43
  }
126
44
  function isStrikeActive(state) {
127
- return isToggleActive(state, "strike");
45
+ return strike.isActive(state);
128
46
  }
129
47
  export {
130
48
  canFormatText,
@@ -0,0 +1,21 @@
1
+ /**
2
+ * The commands and the query one run property is edited and read through, built from the
3
+ * property's row in the run property table.
4
+ *
5
+ * Each edit preserves the run's untouched XML: the row says which children of the rPr change,
6
+ * and the mark keeps every other attr it wore.
7
+ */
8
+ import type { Command, EditorState } from "prosemirror-state";
9
+ import { type EditableRunKey, type RunSetting } from "../../../docx/formatting";
10
+ export interface RunPropertyCommands<K extends EditableRunKey> {
11
+ /** Writes the value into the selection. Null withdraws the run's own setting, so the layers below decide again */
12
+ set(value: RunSetting<K> | null): Command;
13
+ /** Whether the property is on where the selection stands. It counts as on only when it is on everywhere */
14
+ isActive(state: EditorState): boolean;
15
+ /**
16
+ * The same toggle convention as Word: if every character in the selection is already on, turn
17
+ * them all off; otherwise switch them all on as `on`.
18
+ */
19
+ toggle(on: RunSetting<K>): Command;
20
+ }
21
+ export declare function runPropertyCommands<K extends EditableRunKey>(key: K): RunPropertyCommands<K>;
@@ -0,0 +1,103 @@
1
+ // src/editor/commands/formatting/propertyCommands.ts
2
+ import {
3
+ inheritedRunFormat,
4
+ RUN_PROPERTIES,
5
+ resolveParagraph,
6
+ resolveRun
7
+ } from "../../../docx/formatting.js";
8
+ import {
9
+ editRunProps,
10
+ matchesRunEdit
11
+ } from "../../../docx/runProps.js";
12
+ import { docxSchema } from "../../../schema/index.js";
13
+ import { editShut, openStretches } from "../../../schema/guards.js";
14
+ import { documentFormatting } from "../../documentStyles.js";
15
+ import {
16
+ activePieces,
17
+ caretPiece,
18
+ text,
19
+ textPieces
20
+ } from "./shared.js";
21
+ function editedMark(state, target, edit) {
22
+ const context = documentFormatting(state);
23
+ const rPr = text(target.mark?.attrs.rPr);
24
+ const paragraph = resolveParagraph(target.pPr, context);
25
+ const next = editRunProps(
26
+ { rPr, format: target.format },
27
+ inheritedRunFormat(rPr, paragraph, context),
28
+ edit
29
+ );
30
+ if (!next) return null;
31
+ return docxSchema.marks.run.create({
32
+ ...target.mark?.attrs,
33
+ rPr: next.rPr,
34
+ format: resolveRun(next.rPr, paragraph, context)
35
+ });
36
+ }
37
+ function planChanges(state, pieces, edit) {
38
+ const changes = [];
39
+ for (const target of pieces) {
40
+ const mark = editedMark(state, target, edit);
41
+ if (!mark) return null;
42
+ changes.push({ from: target.from, to: target.to, mark });
43
+ }
44
+ return changes;
45
+ }
46
+ function applyToSelection(state, dispatch, edit) {
47
+ const pieces = openStretches(
48
+ state,
49
+ // Text already in the desired state is left untouched, so its original XML survives
50
+ textPieces(state).filter((target) => !matchesRunEdit(target.format, edit)),
51
+ "mark"
52
+ );
53
+ const changes = pieces.length > 0 ? planChanges(state, pieces, edit) : null;
54
+ if (!changes) return false;
55
+ if (dispatch) {
56
+ const tr = state.tr;
57
+ for (const change of changes) {
58
+ tr.addMark(change.from, change.to, change.mark);
59
+ }
60
+ dispatch(tr);
61
+ }
62
+ return true;
63
+ }
64
+ function applyToCaret(state, dispatch, edit) {
65
+ if (editShut(state, { kind: "insert", at: state.selection.from })) {
66
+ return false;
67
+ }
68
+ const target = caretPiece(state);
69
+ if (matchesRunEdit(target.format, edit)) return false;
70
+ const mark = editedMark(state, target, edit);
71
+ if (!mark) return false;
72
+ if (dispatch) {
73
+ const marks = state.storedMarks ?? state.selection.$from.marks();
74
+ dispatch(state.tr.setStoredMarks(mark.addToSet(marks)));
75
+ }
76
+ return true;
77
+ }
78
+ function runEditCommand(edit) {
79
+ return (state, dispatch) => state.selection.empty ? applyToCaret(state, dispatch, edit) : applyToSelection(state, dispatch, edit);
80
+ }
81
+ function runPropertyCommands(key) {
82
+ const property = RUN_PROPERTIES[key];
83
+ const isOn = (target) => property.isOn(target.format ?? {});
84
+ const set = (value) => runEditCommand({ key, value });
85
+ return {
86
+ set,
87
+ isActive: (state) => {
88
+ const pieces = activePieces(state);
89
+ return pieces.length > 0 && pieces.every(isOn);
90
+ },
91
+ toggle: (on) => (state, dispatch) => {
92
+ const pieces = openStretches(
93
+ state,
94
+ state.selection.empty ? [caretPiece(state)] : textPieces(state),
95
+ "mark"
96
+ );
97
+ return set(pieces.every(isOn) ? null : on)(state, dispatch);
98
+ }
99
+ };
100
+ }
101
+ export {
102
+ runPropertyCommands
103
+ };
@@ -25,8 +25,8 @@ export declare function textPieces(state: EditorState): TextPiece[];
25
25
  /** When the selection is collapsed, the formatting that text typed next will follow */
26
26
  export declare function caretPiece(state: EditorState): TextPiece;
27
27
  /**
28
- * The places formatting currently applies to: a single caret, or the text pieces of the selection
29
- * a lock leaves open. It has to leave out what `applyToSelection` leaves out, or a toggle reads off
30
- * for text that is already on and can never turn it off.
28
+ * The formatting a toolbar reads, excluding locked text as it does during editing.
29
+ * Document protection prevents edits, but must not hide the selected text's actual formatting.
30
+ * Commands separately ask all guards before deciding what they can change.
31
31
  */
32
32
  export declare function activePieces(state: EditorState): TextPiece[];
@@ -1,7 +1,7 @@
1
1
  // src/editor/commands/formatting/shared.ts
2
2
  import { toRunFormat } from "../../../model/format.js";
3
3
  import { docxSchema } from "../../../schema/index.js";
4
- import { rangeTouchesLocked } from "../../../schema/locks.js";
4
+ import { lockGuard } from "../../../schema/locks.js";
5
5
  function text(value) {
6
6
  return typeof value === "string" ? value : null;
7
7
  }
@@ -41,7 +41,10 @@ function caretPiece(state) {
41
41
  function activePieces(state) {
42
42
  if (state.selection.empty) return [caretPiece(state)];
43
43
  return textPieces(state).filter(
44
- (target) => !rangeTouchesLocked(state.doc, target.from, target.to)
44
+ (target) => !lockGuard.shuts(
45
+ { kind: "mark", from: target.from, to: target.to },
46
+ state
47
+ )
45
48
  );
46
49
  }
47
50
  export {
@@ -1,6 +1,7 @@
1
1
  // src/editor/commands/historyCommands.ts
2
2
  import { redo as historyRedo, undo as historyUndo } from "prosemirror-history";
3
- import { historyReplay, transactionAllowed } from "../../schema/locks.js";
3
+ import { transactionAllowed } from "../../schema/guards.js";
4
+ import { historyReplay } from "../../schema/locks.js";
4
5
  function replaying(command) {
5
6
  return (state, dispatch, view) => {
6
7
  const built = [];
@@ -1,6 +1,7 @@
1
1
  // src/editor/commands/indentCommands.ts
2
2
  import { withLeftIndent, withListNumbering } from "../../docx/paraProps.js";
3
3
  import { toParagraphFormat } from "../../model/format.js";
4
+ import { TWIPS_PER_PT } from "../../ooxml/simpleTypes.js";
4
5
  import { editParagraphs, paragraphPPr } from "../paragraphEdits.js";
5
6
  import { documentNumbering } from "../plugins/numberingDecorations.js";
6
7
  import { listLevelChange, listRefOf } from "./listCommands.js";
@@ -8,7 +9,7 @@ var STEP_TWIPS = 720;
8
9
  function leftIndentTwips(node) {
9
10
  const format = toParagraphFormat(node.attrs.format);
10
11
  const pt = format?.indentStartPt ?? format?.indentLeftPt ?? 0;
11
- return Math.round(pt * 20);
12
+ return Math.round(pt * TWIPS_PER_PT);
12
13
  }
13
14
  function steppedLeftTwips(node, delta) {
14
15
  const left = leftIndentTwips(node);
@@ -18,13 +19,13 @@ function steppedLeftTwips(node, delta) {
18
19
  function indentStep(delta) {
19
20
  return (state, dispatch) => {
20
21
  const numbering = documentNumbering(state);
21
- return editParagraphs(state, dispatch, (node, styles, defaultStyleId) => {
22
+ return editParagraphs(state, dispatch, (node) => {
22
23
  if (listRefOf(node)) {
23
24
  const change = listLevelChange(numbering, node, delta);
24
- return change && withListNumbering(paragraphPPr(node), change, styles, defaultStyleId);
25
+ return change && withListNumbering(paragraphPPr(node), change);
25
26
  }
26
27
  const left = steppedLeftTwips(node, delta);
27
- return left === null ? null : withLeftIndent(paragraphPPr(node), left, styles, defaultStyleId);
28
+ return left === null ? null : withLeftIndent(paragraphPPr(node), left);
28
29
  });
29
30
  };
30
31
  }
@@ -13,6 +13,8 @@ export type { ParagraphStyleOption } from "../../docx/formatting";
13
13
  export type { RunToggle } from "../../docx/runProps";
14
14
  export type { LineSpacing, ParagraphAlign } from "../../model/format";
15
15
  export type { ListKind } from "../../numbering/listTemplate";
16
+ /** The codes a problem below is reported under, which are the ones `DocxExportError` is thrown with */
17
+ export type { DocxExportErrorCode } from "../../ooxml/errors";
16
18
  /** The size an image is shown at, which the insert command asks for */
17
19
  export type { ImageExtent } from "../../ooxml/image";
18
20
  /**
@@ -56,6 +58,15 @@ export { insertLineBreak, insertPageBreak } from "./breakCommands";
56
58
  export { canRunCommand } from "./canRunCommand";
57
59
  export type { CommentAuthor, DocumentComment, DocumentCommentReply, NewComment, } from "./commentCommands";
58
60
  export { addComment, addCommentReply, canAddComment, canEditComment, documentComments, removeComment, removeCommentReply, selectComment, setCommentResolved, updateComment, updateCommentReply, } from "./commentCommands";
61
+ /**
62
+ * Whether the document as it stands can be written back, and every reason it could not, each
63
+ * with the code `exportDocx` would throw it under. `canExport` is what an export control is
64
+ * drawn from, and `downloadDocx` answers `blocked` with the same list.
65
+ */
66
+ export type { ExportProblem } from "./exportQueries";
67
+ export { canExport, documentExportProblems } from "./exportQueries";
68
+ export type { FidelityCode, FidelityNote, FidelitySeverity, } from "./fidelityQueries";
69
+ export { documentFidelity } from "./fidelityQueries";
59
70
  export type { ActiveFontFamily, ActiveFontSize, } from "./formattingCommands";
60
71
  export { activeFontFamily, activeFontSize, activeTextBackground, activeTextColor, canFormatText, documentFontNames, isBoldActive, isItalicActive, isStrikeActive, isUnderlineActive, setFontFamily, setFontSize, setTextBackground, setTextColor, toggleBold, toggleItalic, toggleStrike, toggleUnderline, } from "./formattingCommands";
61
72
  /**
@@ -29,6 +29,8 @@ import {
29
29
  updateComment,
30
30
  updateCommentReply
31
31
  } from "./commentCommands.js";
32
+ import { canExport, documentExportProblems } from "./exportQueries.js";
33
+ import { documentFidelity } from "./fidelityQueries.js";
32
34
  import {
33
35
  activeFontFamily,
34
36
  activeFontSize,
@@ -111,6 +113,7 @@ export {
111
113
  canAddComment,
112
114
  canDecreaseIndent,
113
115
  canEditComment,
116
+ canExport,
114
117
  canFormatText,
115
118
  canIncreaseIndent,
116
119
  canInsertImage,
@@ -124,6 +127,8 @@ export {
124
127
  documentBodyWidthPx,
125
128
  documentComments,
126
129
  documentDefaults,
130
+ documentExportProblems,
131
+ documentFidelity,
127
132
  documentFontNames,
128
133
  documentHasLocked,
129
134
  documentNotes,
@@ -1,7 +1,6 @@
1
1
  // src/editor/commands/linkCommands.ts
2
2
  import { docxSchema } from "../../schema/index.js";
3
- import { rangeTouchesLocked } from "../../schema/locks.js";
4
- import { editsShut } from "../../schema/protectionState.js";
3
+ import { openStretches } from "../../schema/guards.js";
5
4
  var linkType = docxSchema.marks.link;
6
5
  function text(value) {
7
6
  return typeof value === "string" ? value : null;
@@ -75,10 +74,10 @@ function linkSpansTouching(doc, from, to) {
75
74
  return spans;
76
75
  }
77
76
  function openPieces(state) {
78
- if (editsShut(state)) return [];
79
- const found = state.selection.empty ? caretPieces(state) : selectionPieces(state);
80
- return found.filter(
81
- (piece) => !rangeTouchesLocked(state.doc, piece.from, piece.to)
77
+ return openStretches(
78
+ state,
79
+ state.selection.empty ? caretPieces(state) : selectionPieces(state),
80
+ "mark"
82
81
  );
83
82
  }
84
83
  function caretPieces(state) {
@@ -25,9 +25,9 @@ function listRefOf(node) {
25
25
  return toParagraphFormat(node.attrs.format)?.numbering ?? null;
26
26
  }
27
27
  function changeParagraphs(state, dispatch, plan) {
28
- return editParagraphs(state, dispatch, (node, styles, defaultStyleId) => {
28
+ return editParagraphs(state, dispatch, (node) => {
29
29
  const change = plan(node);
30
- return change && withListNumbering(paragraphPPr(node), change, styles, defaultStyleId);
30
+ return change && withListNumbering(paragraphPPr(node), change);
31
31
  });
32
32
  }
33
33
  function indentForLevel(numbering, node, ref) {
@@ -107,15 +107,13 @@ function isInList(state) {
107
107
  (spot) => listRefOf(spot.node) !== null
108
108
  );
109
109
  }
110
- var leaveListAtLineStart = (state, dispatch) => editParagraphs(state, dispatch, (node, styles, defaultStyleId) => {
110
+ var leaveListAtLineStart = (state, dispatch) => editParagraphs(state, dispatch, (node) => {
111
111
  if (!listRefOf(node)) return null;
112
- const unlisted = withListNumbering(
113
- paragraphPPr(node),
114
- { numbering: null, indent: { kind: "clearHanging" } },
115
- styles,
116
- defaultStyleId
117
- );
118
- return unlisted && withLeftIndent(unlisted.pPr, 0, styles, defaultStyleId);
112
+ const unlisted = withListNumbering(paragraphPPr(node), {
113
+ numbering: null,
114
+ indent: { kind: "clearHanging" }
115
+ });
116
+ return unlisted && withLeftIndent(unlisted.pPr, 0);
119
117
  });
120
118
  var leaveEmptyListItem = (state, dispatch) => {
121
119
  const { empty, $from } = state.selection;
@@ -25,7 +25,13 @@ export declare function selectionLock(state: EditorState): SelectionLock;
25
25
  * A selection that also reaches a lock still locks what that lock leaves open.
26
26
  */
27
27
  export declare const lockSelection: Command;
28
- /** Lifts the lock off every control the selection reaches, over that control's whole stretch */
28
+ /**
29
+ * Lifts the lock off every control the selection reaches, over that control's whole stretch.
30
+ *
31
+ * The transaction carries the pass that lets it reach past the very locks it lifts, which is the
32
+ * one thing the pass is for; every other guard still has its say, so lifting a lock stays shut
33
+ * under a protection that shuts the body (`schema/guards`).
34
+ */
29
35
  export declare const unlockSelection: Command;
30
36
  /**
31
37
  * Whether editing where the selection stands is shut.
@@ -3,20 +3,20 @@ import {
3
3
  TextSelection
4
4
  } from "prosemirror-state";
5
5
  import { namesNothing, newControlId } from "../../docx/sdt.js";
6
- import { withContentLock } from "../../docx/sdtProps.js";
6
+ import { lockedControlPrefix, withContentLock } from "../../docx/sdtProps.js";
7
7
  import { docxSchema } from "../../schema/index.js";
8
+ import { guardedCommand, openStretches } from "../../schema/guards.js";
8
9
  import {
9
10
  carriesLock,
10
11
  controlSpans,
11
12
  isLockedCell,
12
- rangeTouchesLocked,
13
13
  selectionShut,
14
14
  unlockAllowed
15
15
  } from "../../schema/locks.js";
16
16
  import { editsShut } from "../../schema/protectionState.js";
17
17
  function lockedControlMark(id) {
18
18
  return docxSchema.marks.sdt.create({
19
- sdtPrefix: `<w:sdt><w:sdtPr><w:id w:val="${id}"/><w:lock w:val="sdtContentLocked"/></w:sdtPr>`,
19
+ sdtPrefix: lockedControlPrefix(id),
20
20
  contentsLocked: true,
21
21
  deletionLocked: true
22
22
  });
@@ -67,29 +67,33 @@ function takeover(met, stretch, open) {
67
67
  if (!only || isLocked(only.mark) || !prefix || !namesNothing(prefix)) {
68
68
  return null;
69
69
  }
70
- const mark = open(stretch) ? withLock(only.mark, true) : null;
70
+ const mark = open ? withLock(only.mark, true) : null;
71
71
  return mark ? {
72
72
  from: Math.min(stretch.from, only.from),
73
73
  to: Math.max(stretch.to, only.to),
74
74
  mark
75
75
  } : null;
76
76
  }
77
- function blockLockEdits(doc, block, spans, reach) {
77
+ function blockLockEdits(state, block, spans, reach) {
78
78
  const stretch = stretchIn(block, reach);
79
79
  if (!stretch) return [];
80
- const open = (at) => !rangeTouchesLocked(doc, at.from, at.to);
80
+ const open = (of) => openStretches(state, of, "mark");
81
81
  const met = spans.filter((span) => overlaps(span, stretch));
82
- const taken = takeover(met, stretch, open);
82
+ const taken = takeover(met, stretch, open([stretch]).length > 0);
83
83
  if (taken) return [taken];
84
- const shut = met.filter((span) => !isLocked(span.mark) && open(span)).flatMap((span) => {
85
- const mark = withLock(span.mark, true);
86
- return mark ? [{ from: span.from, to: span.to, mark }] : [];
87
- });
88
- const fresh = gapsIn(stretch, spans).filter(open).map((gap) => ({ ...gap, mark: lockedControlMark(newControlId()) }));
84
+ const shut = open(met.filter((span) => !isLocked(span.mark))).flatMap(
85
+ (span) => {
86
+ const mark = withLock(span.mark, true);
87
+ return mark ? [{ from: span.from, to: span.to, mark }] : [];
88
+ }
89
+ );
90
+ const fresh = open(gapsIn(stretch, spans)).map((gap) => ({
91
+ ...gap,
92
+ mark: lockedControlMark(newControlId())
93
+ }));
89
94
  return [...shut, ...fresh];
90
95
  }
91
96
  function selectionLockDetail(state) {
92
- if (editsShut(state)) return { kind: "none" };
93
97
  const selection = state.selection;
94
98
  const locking = !selection.empty && selection instanceof TextSelection;
95
99
  const edits = [];
@@ -106,7 +110,7 @@ function selectionLockDetail(state) {
106
110
  if (isLocked(span.mark) && reaches(span, reach)) spans.push(span);
107
111
  }
108
112
  if (locking) {
109
- edits.push(...blockLockEdits(state.doc, block, controls, reach));
113
+ edits.push(...blockLockEdits(state, block, controls, reach));
110
114
  }
111
115
  return false;
112
116
  });
@@ -122,7 +126,7 @@ function selectionLockDetail(state) {
122
126
  return anyLocked ? { kind: "mixed", edits, ...locked } : { kind: "lockable", edits };
123
127
  }
124
128
  function selectionLock(state) {
125
- return selectionLockDetail(state).kind;
129
+ return editsShut(state) ? "none" : selectionLockDetail(state).kind;
126
130
  }
127
131
  function lockEditsOf(lock) {
128
132
  switch (lock.kind) {
@@ -145,16 +149,13 @@ function lockedOf(lock) {
145
149
  return NOTHING_LOCKED;
146
150
  }
147
151
  }
148
- var lockSelection = (state, dispatch) => {
152
+ var lockSelection = guardedCommand((state) => {
149
153
  const edits = lockEditsOf(selectionLockDetail(state));
150
- if (edits.length === 0) return false;
151
- if (dispatch) {
152
- const tr = state.tr;
153
- for (const edit of edits) tr.addMark(edit.from, edit.to, edit.mark);
154
- dispatch(tr);
155
- }
156
- return true;
157
- };
154
+ if (edits.length === 0) return null;
155
+ const tr = state.tr;
156
+ for (const edit of edits) tr.addMark(edit.from, edit.to, edit.mark);
157
+ return tr;
158
+ });
158
159
  function unlockCell(tr, cell) {
159
160
  const prefix = prefixOf(cell.node.attrs);
160
161
  tr.setNodeMarkup(cell.pos, null, {
@@ -164,21 +165,18 @@ function unlockCell(tr, cell) {
164
165
  sdtDeletionLocked: false
165
166
  });
166
167
  }
167
- var unlockSelection = (state, dispatch) => {
168
+ var unlockSelection = guardedCommand((state) => {
168
169
  const { spans, cells } = lockedOf(selectionLockDetail(state));
169
- if (spans.length === 0 && cells.length === 0) return false;
170
- if (dispatch) {
171
- const tr = state.tr.setMeta(unlockAllowed, true);
172
- for (const span of spans) {
173
- const opened = withLock(span.mark, false);
174
- if (opened) tr.addMark(span.from, span.to, opened);
175
- else tr.removeMark(span.from, span.to, span.mark);
176
- }
177
- for (const cell of cells) unlockCell(tr, cell);
178
- dispatch(tr);
170
+ if (spans.length === 0 && cells.length === 0) return null;
171
+ const tr = state.tr.setMeta(unlockAllowed, true);
172
+ for (const span of spans) {
173
+ const opened = withLock(span.mark, false);
174
+ if (opened) tr.addMark(span.from, span.to, opened);
175
+ else tr.removeMark(span.from, span.to, span.mark);
179
176
  }
180
- return true;
181
- };
177
+ for (const cell of cells) unlockCell(tr, cell);
178
+ return tr;
179
+ });
182
180
  function selectionTouchesLocked(state) {
183
181
  return selectionShut(state.selection, state.doc);
184
182
  }