@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
@@ -0,0 +1,47 @@
1
+ /**
2
+ * Keeps every display value of the document current: the ones an edit moved, after that edit, and
3
+ * every one at once when the document snapshot the values are resolved against is replaced.
4
+ *
5
+ * The derivers are registered here and run through the one walk `schema/displayDerivation`
6
+ * defines. What a node maps back to is settled here as well, from the mapping of the transactions
7
+ * that changed the document: a node whose content survived those transactions is the node that
8
+ * stood where its opening maps back to, and one whose content did not is new. A node rewritten
9
+ * where it stands (`setNodeMarkup`) therefore still maps back to itself, which is what lets a
10
+ * table resized or a paragraph re-aligned be told from a table or a paragraph put in.
11
+ *
12
+ * The transaction this appends carries the display-only pass (`schema/guards`), since it changes
13
+ * nothing a lock or a protection answers for, and goes to the history as part of the edit it
14
+ * follows, so that one undo takes the edit and its values back together. The re-derivation after
15
+ * a snapshot change follows no edit and goes to the history not at all: the values follow the
16
+ * snapshot, and undoing whatever replaced the snapshot derives them again.
17
+ */
18
+ import type { Node as PMNode } from "prosemirror-model";
19
+ import { Plugin } from "prosemirror-state";
20
+ import { type DisplayDeriver } from "../../schema/displayDerivation";
21
+ import { type EditorDocument } from "../editorDocument";
22
+ /** What a deriver of this editor resolves against */
23
+ export interface DerivationContext {
24
+ readonly document: EditorDocument;
25
+ /**
26
+ * Where the composition the browser holds open stands, which a deriver leaves alone: rewriting
27
+ * the node it stands in redraws it, and a redraw under an open composition is what the browser
28
+ * answers by taking the composition down. Null while nothing is being composed, and while every
29
+ * value is being worked out again from nothing, when nothing may be left standing.
30
+ */
31
+ readonly composingAt: number | null;
32
+ }
33
+ export type DocumentDeriver = DisplayDeriver<DerivationContext>;
34
+ export declare const DISPLAY_DERIVERS: readonly DocumentDeriver[];
35
+ /**
36
+ * The document with every display value worked out against this snapshot, which is what a state
37
+ * is built over: the values a document arrived with were worked out against whatever opened it.
38
+ */
39
+ export declare function withDerivedDisplay(doc: PMNode, document: EditorDocument, derivers?: readonly DocumentDeriver[]): PMNode;
40
+ /**
41
+ * Derives the display values again after every change: for the nodes an edit moved, and for every
42
+ * node when the snapshot was replaced.
43
+ *
44
+ * An appended transaction is handed nothing but states, so the view an open composition is read
45
+ * from is the one the plugin is given when it mounts.
46
+ */
47
+ export declare function displayDerivation(derivers?: readonly DocumentDeriver[]): Plugin;
@@ -0,0 +1,78 @@
1
+ // src/editor/plugins/displayDerivation.ts
2
+ import { Plugin } from "prosemirror-state";
3
+ import { Mapping, Transform } from "prosemirror-transform";
4
+ import {
5
+ deriveDisplay,
6
+ displayOnly
7
+ } from "../../schema/displayDerivation.js";
8
+ import { documentOf } from "../editorDocument.js";
9
+ import { paragraphDisplay } from "./paragraphDisplay.js";
10
+ import { tableDisplay } from "./tableDisplay.js";
11
+ var DISPLAY_DERIVERS = [
12
+ tableDisplay,
13
+ paragraphDisplay
14
+ ];
15
+ var nothingBefore = () => null;
16
+ function withDerivedDisplay(doc, document, derivers = DISPLAY_DERIVERS) {
17
+ const transform = new Transform(doc);
18
+ deriveDisplay(
19
+ transform,
20
+ { document, composingAt: null },
21
+ derivers,
22
+ nothingBefore
23
+ );
24
+ return transform.doc;
25
+ }
26
+ function previousIn(before, transactions) {
27
+ const mapping = new Mapping();
28
+ for (const transaction of transactions) {
29
+ mapping.appendMapping(transaction.mapping);
30
+ }
31
+ const back = mapping.invert();
32
+ return (node, pos) => {
33
+ const inside = node.isLeaf ? pos : pos + 1;
34
+ if (back.mapResult(inside, 1).deleted) return null;
35
+ const was = before.nodeAt(back.map(pos, 1));
36
+ return was !== null && was.type === node.type ? was : null;
37
+ };
38
+ }
39
+ function composingAt(view, state) {
40
+ return view?.composing === true ? state.selection.from : null;
41
+ }
42
+ function displayDerivation(derivers = DISPLAY_DERIVERS) {
43
+ let live = null;
44
+ return new Plugin({
45
+ view(view) {
46
+ live = view;
47
+ return {
48
+ destroy() {
49
+ live = null;
50
+ }
51
+ };
52
+ },
53
+ appendTransaction(transactions, oldState, newState) {
54
+ const document = documentOf(newState);
55
+ const replaced = document !== documentOf(oldState);
56
+ if (!replaced && !transactions.some((transaction) => transaction.docChanged)) {
57
+ return null;
58
+ }
59
+ const tr = newState.tr.setMeta(displayOnly, true);
60
+ if (replaced) tr.setMeta("addToHistory", false);
61
+ deriveDisplay(
62
+ tr,
63
+ {
64
+ document,
65
+ composingAt: replaced ? null : composingAt(live, newState)
66
+ },
67
+ derivers,
68
+ replaced ? nothingBefore : previousIn(oldState.doc, transactions)
69
+ );
70
+ return tr.docChanged ? tr : null;
71
+ }
72
+ });
73
+ }
74
+ export {
75
+ DISPLAY_DERIVERS,
76
+ displayDerivation,
77
+ withDerivedDisplay
78
+ };
@@ -2,14 +2,13 @@
2
2
  import { isHistoryTransaction } from "prosemirror-history";
3
3
  import { Plugin, PluginKey } from "prosemirror-state";
4
4
  import { Decoration, DecorationSet } from "prosemirror-view";
5
- import { replacementShut } from "../../schema/locks.js";
6
- import { editsShut } from "../../schema/protectionState.js";
5
+ import { editShut, selectionIntents } from "../../schema/guards.js";
7
6
  import {
8
7
  hasResolvableClipboardImages,
9
8
  resolveClipboardImages
10
9
  } from "../clipboard/images.js";
11
10
  import { documentBodyHeightPx, documentBodyWidthPx } from "../documentStyles.js";
12
- import { richHtmlSlice } from "../externalClipboard.js";
11
+ import { richHtmlSlice, withPastedContent } from "../externalClipboard.js";
13
12
  import { insertPlainTextAt } from "../plainText.js";
14
13
  var LOAD_TIMEOUT_MS = 15e3;
15
14
  var imagePasteKey = new PluginKey("docxImagePaste");
@@ -88,15 +87,18 @@ function imagePaste() {
88
87
  if (!range) return;
89
88
  removeMarker(task);
90
89
  if (task.view.isDestroyed) return;
91
- const slice = resolved === null || resolved.images.size === 0 ? null : richHtmlSlice(
90
+ const content = resolved === null || resolved.images.size === 0 ? null : richHtmlSlice(
92
91
  task.view.state,
93
92
  task.view.dom.ownerDocument,
94
93
  resolved.source,
95
94
  resolved.images
96
95
  );
97
- if (slice !== null) {
96
+ if (content !== null) {
98
97
  task.view.dispatch(
99
- task.view.state.tr.replaceRange(range.from, range.to, slice).scrollIntoView()
98
+ withPastedContent(
99
+ task.view.state.tr.replaceRange(range.from, range.to, content.slice),
100
+ content
101
+ ).scrollIntoView()
100
102
  );
101
103
  } else {
102
104
  insertPlainTextAt(task.view, task.text, range.from, range.to);
@@ -223,7 +225,9 @@ function imagePaste() {
223
225
  props: {
224
226
  decorations: (state) => imagePasteKey.getState(state)?.decorations,
225
227
  handlePaste(view, event) {
226
- if (editsShut(view.state) || replacementShut(view.state.selection, view.state.doc)) {
228
+ if (selectionIntents(view.state.selection, "replace").some(
229
+ (intent) => editShut(view.state, intent)
230
+ )) {
227
231
  return false;
228
232
  }
229
233
  if (view.state.selection.ranges.length > 1) return false;
@@ -5,6 +5,7 @@ import { keydownHandler } from "prosemirror-keymap";
5
5
  import { Plugin } from "prosemirror-state";
6
6
  import { goToNextCell } from "prosemirror-tables";
7
7
  import { canSplit } from "prosemirror-transform";
8
+ import { splitParagraphAttrs } from "../../docx/cloning.js";
8
9
  import { toParagraphFormat } from "../../model/format.js";
9
10
  import { docxSchema } from "../../schema/index.js";
10
11
  import { insertLineBreak, insertPageBreak } from "../commands/breakCommands.js";
@@ -42,13 +43,27 @@ var splitParagraph = (state, dispatch) => {
42
43
  const tr = state.tr;
43
44
  if (!state.selection.empty) tr.deleteSelection();
44
45
  const at = tr.mapping.map(state.selection.$from.pos);
45
- const parent = tr.doc.resolve(at).parent;
46
+ const $at = tr.doc.resolve(at);
47
+ const parent = $at.parent;
46
48
  if (parent.type !== docxSchema.nodes.paragraph) return false;
47
- const types = [{ type: docxSchema.nodes.paragraph, attrs: parent.attrs }];
49
+ const { before, after } = splitParagraphAttrs(parent);
50
+ const types = [{ type: docxSchema.nodes.paragraph, attrs: after }];
48
51
  if (!canSplit(tr.doc, at, 1, types)) return false;
49
- if (dispatch) dispatch(tr.split(at, 1, types).scrollIntoView());
52
+ if (dispatch) {
53
+ const beforePos = $at.before();
54
+ tr.split(at, 1, types);
55
+ if (!keptEveryAttr(parent, before)) {
56
+ tr.setNodeMarkup(beforePos, null, before);
57
+ }
58
+ dispatch(tr.scrollIntoView());
59
+ }
50
60
  return true;
51
61
  };
62
+ function keptEveryAttr(paragraph, attrs) {
63
+ return Object.keys(paragraph.attrs).every(
64
+ (name) => attrs[name] === paragraph.attrs[name]
65
+ );
66
+ }
52
67
  var preserveTableFollowingParagraph = (state) => {
53
68
  const { $from } = state.selection;
54
69
  if (!state.selection.empty || $from.depth !== 1 || $from.parent.type !== docxSchema.nodes.paragraph || $from.parent.content.size !== 0 || $from.parentOffset !== 0) {
@@ -1,11 +1,13 @@
1
1
  /**
2
2
  * Draws list markers and inherited indentation as decorations so display-only values never create
3
- * new OOXML on export. The plugin also exposes numbering definitions to list commands.
3
+ * new OOXML on export. The definitions the markers are drawn from belong to the document
4
+ * snapshot, and the readers list commands ask stand here beside the drawing.
4
5
  */
5
6
  import type { Node as PMNode } from "prosemirror-model";
6
7
  import { type EditorState, Plugin } from "prosemirror-state";
7
8
  import { DecorationSet } from "prosemirror-view";
8
- import { type Numbering } from "../../numbering/parseNumbering";
9
+ import { type RunFormat } from "../../model/format";
10
+ import type { LevelAlign, LevelSuffix, Numbering } from "../../numbering/parseNumbering";
9
11
  /** A number to draw on screen and the paragraph position it attaches to */
10
12
  export interface PlacedMarker {
11
13
  from: number;
@@ -18,25 +20,23 @@ export interface PlacedMarker {
18
20
  indentEndPt: number | null;
19
21
  /** The first-line indentation, under the same rule */
20
22
  textIndentPt: number | null;
23
+ /** What the level puts between the number and the text (`w:suff`) */
24
+ suffix: LevelSuffix;
25
+ /** Where the number sits inside the width kept for it (`w:lvlJc`) */
26
+ align: LevelAlign;
27
+ /** The formatting the level puts on the number alone (`lvl/rPr`) */
28
+ run: RunFormat | null;
21
29
  }
22
30
  /** Walks a document to find the paragraphs that get numbers and what those numbers are */
23
31
  export declare function paragraphMarkers(doc: PMNode, numbering: Numbering): PlacedMarker[];
24
32
  export declare function markerDecorations(doc: PMNode, numbering: Numbering): DecorationSet;
25
- /** What the plugin holds: the document's list definitions and the numbers to draw right now */
26
- interface NumberingState {
27
- numbering: Numbering;
28
- /** Whether the document has a place (numbering.xml) to write the definition of a new list */
29
- canStartNewList: boolean;
30
- decorations: DecorationSet;
31
- }
32
33
  /** This document's list definitions. Empty when the editor does not know them */
33
34
  export declare function documentNumbering(state: EditorState): Numbering;
34
35
  /**
35
36
  * Whether a new list can be started in this document.
36
- * A document without numbering.xml has nowhere to write a new definition, so it would be
37
- * blocked at export time. In such a document the commands that start a list do not apply
38
- * in the first place.
37
+ * A document with nowhere to write a new definition would be blocked at export time, so in such
38
+ * a document the commands that start a list do not apply in the first place.
39
39
  */
40
40
  export declare function canStartNewList(state: EditorState): boolean;
41
- export declare function numberingMarkers(numbering?: Numbering, canStartNewList?: boolean): Plugin<NumberingState>;
42
- export {};
41
+ /** Draws the numbers this document's lists put in front of their paragraphs */
42
+ export declare function numberingMarkers(): Plugin<DecorationSet>;
@@ -1,12 +1,12 @@
1
1
  // src/editor/plugins/numberingDecorations.ts
2
2
  import { Plugin, PluginKey } from "prosemirror-state";
3
3
  import { Decoration, DecorationSet } from "prosemirror-view";
4
- import { toParagraphFormat } from "../../model/format.js";
5
- import { computeMarkers } from "../../numbering/markers.js";
6
4
  import {
7
- EMPTY_NUMBERING
8
- } from "../../numbering/parseNumbering.js";
5
+ toParagraphFormat
6
+ } from "../../model/format.js";
7
+ import { computeMarkers } from "../../numbering/markers.js";
9
8
  import { editorAttributes, editorCssVariables } from "../../styles/classNames.js";
9
+ import { documentOf } from "../editorDocument.js";
10
10
  var FALLBACK_MARKER_WIDTH_PT = 18;
11
11
  function paragraphSpots(doc) {
12
12
  const spots = [];
@@ -47,13 +47,52 @@ function paragraphMarkers(doc, numbering) {
47
47
  from: spot.pos,
48
48
  to: spot.pos + spot.nodeSize,
49
49
  text: marker.text,
50
+ suffix: marker.suffix,
51
+ align: marker.align,
52
+ run: marker.run,
50
53
  ...markerPlacement(spot.format, marker.indent)
51
54
  }
52
55
  ];
53
56
  });
54
57
  }
58
+ function markerSpacing(marker) {
59
+ if (marker.suffix === "tab") {
60
+ return [`${editorCssVariables.markerWidth}:${marker.widthPt}pt`];
61
+ }
62
+ return [
63
+ `${editorCssVariables.markerWidth}:0`,
64
+ `${editorCssVariables.markerGap}:0`
65
+ ];
66
+ }
67
+ function markerFormat(run) {
68
+ if (!run) return [];
69
+ const css = [];
70
+ if (run.bold !== void 0) {
71
+ css.push(
72
+ `${editorCssVariables.markerFontWeight}:${run.bold ? "bold" : "normal"}`
73
+ );
74
+ }
75
+ if (run.italic !== void 0) {
76
+ css.push(
77
+ `${editorCssVariables.markerFontStyle}:${run.italic ? "italic" : "normal"}`
78
+ );
79
+ }
80
+ if (run.color !== void 0) {
81
+ css.push(`${editorCssVariables.markerColor}:${run.color}`);
82
+ }
83
+ if (run.fontSizePt !== void 0) {
84
+ css.push(`${editorCssVariables.markerFontSize}:${run.fontSizePt}pt`);
85
+ }
86
+ if (run.fontFamily !== void 0) {
87
+ css.push(`${editorCssVariables.markerFontFamily}:${run.fontFamily}`);
88
+ }
89
+ return css;
90
+ }
55
91
  function markerStyle(marker) {
56
- const css = [`${editorCssVariables.markerWidth}:${marker.widthPt}pt`];
92
+ const css = [...markerSpacing(marker), ...markerFormat(marker.run)];
93
+ if (marker.align !== "left") {
94
+ css.push(`${editorCssVariables.markerAlign}:${marker.align}`);
95
+ }
57
96
  if (marker.indentStartPt !== null) {
58
97
  css.push(`margin-inline-start:${marker.indentStartPt}pt`);
59
98
  }
@@ -76,28 +115,20 @@ function markerDecorations(doc, numbering) {
76
115
  }
77
116
  var numberingKey = new PluginKey("docxEditorNumbering");
78
117
  function documentNumbering(state) {
79
- return numberingKey.getState(state)?.numbering ?? EMPTY_NUMBERING;
118
+ return documentOf(state).formatting.numbering;
80
119
  }
81
120
  function canStartNewList(state) {
82
- return numberingKey.getState(state)?.canStartNewList ?? true;
121
+ return documentOf(state).canStartNewList;
83
122
  }
84
- function numberingMarkers(numbering = EMPTY_NUMBERING, canStartNewList2 = true) {
123
+ function numberingMarkers() {
85
124
  return new Plugin({
86
125
  key: numberingKey,
87
126
  state: {
88
- init: (_config, state) => ({
89
- numbering,
90
- canStartNewList: canStartNewList2,
91
- decorations: markerDecorations(state.doc, numbering)
92
- }),
93
- apply: (tr, current) => tr.docChanged ? {
94
- numbering,
95
- canStartNewList: canStartNewList2,
96
- decorations: markerDecorations(tr.doc, numbering)
97
- } : current
127
+ init: (_config, state) => markerDecorations(state.doc, documentOf(state).formatting.numbering),
128
+ apply: (tr, current, _old, state) => tr.docChanged ? markerDecorations(tr.doc, documentOf(state).formatting.numbering) : current
98
129
  },
99
130
  props: {
100
- decorations: (state) => numberingKey.getState(state)?.decorations
131
+ decorations: (state) => numberingKey.getState(state)
101
132
  }
102
133
  });
103
134
  }
@@ -0,0 +1,7 @@
1
+ /**
2
+ * The values a paragraph draws with, read out of the document's styles along the same path the
3
+ * import takes (`docx/formatting`), so that a paragraph an edit built, one it re-aligned and one
4
+ * the file arrived with all carry the same values for the same properties.
5
+ */
6
+ import type { DocumentDeriver } from "./displayDerivation";
7
+ export declare const paragraphDisplay: DocumentDeriver;
@@ -0,0 +1,57 @@
1
+ // src/editor/plugins/paragraphDisplay.ts
2
+ import {
3
+ paragraphAttrsOf,
4
+ resolveParagraph,
5
+ resolveRun
6
+ } from "../../docx/formatting.js";
7
+ import { docxSchema } from "../../schema/index.js";
8
+ import { paragraphPPr } from "../paragraphEdits.js";
9
+ import { paragraphPlacementAt } from "../paragraphPlacement.js";
10
+ function carriesNothing(node) {
11
+ return node.attrs.format === null && node.attrs.styleRun === null;
12
+ }
13
+ function stands(node, previous) {
14
+ return previous !== null && previous.attrs.pPr === node.attrs.pPr && !carriesNothing(node);
15
+ }
16
+ function holdsComposition(node, pos, composing) {
17
+ return composing !== null && composing >= pos && composing <= pos + node.nodeSize;
18
+ }
19
+ var paragraphDisplay = {
20
+ name: "paragraph",
21
+ nodeTypes: ["paragraph"],
22
+ derive(node, pos, doc, context, previous) {
23
+ const placement = paragraphPlacementAt(doc, pos);
24
+ if (placement === null && stands(node, previous) || holdsComposition(node, pos, context.composingAt)) {
25
+ return [];
26
+ }
27
+ const formatting = context.document.formatting;
28
+ const paragraph = resolveParagraph(
29
+ paragraphPPr(node),
30
+ formatting,
31
+ placement
32
+ );
33
+ const derived = [
34
+ { pos, attrs: paragraphAttrsOf(paragraph) }
35
+ ];
36
+ node.forEach((child, offset) => {
37
+ const mark = docxSchema.marks.run.isInSet(child.marks);
38
+ if (!mark) return;
39
+ const rPr = mark.attrs.rPr;
40
+ derived.push({
41
+ pos: pos + 1 + offset,
42
+ mark: { type: mark.type, to: pos + 1 + offset + child.nodeSize },
43
+ attrs: {
44
+ format: resolveRun(
45
+ typeof rPr === "string" ? rPr : null,
46
+ paragraph,
47
+ formatting
48
+ )
49
+ }
50
+ });
51
+ });
52
+ return derived;
53
+ }
54
+ };
55
+ export {
56
+ paragraphDisplay
57
+ };
@@ -1,12 +1,12 @@
1
1
  // src/editor/plugins/tabLayout.ts
2
2
  import { Plugin } from "prosemirror-state";
3
3
  import { DEFAULT_TAB_STOP_PT } from "../../docx/documentSettings.js";
4
+ import { PX_PER_PT } from "../../docx/pageGeometry.js";
4
5
  import { toParagraphFormat } from "../../model/format.js";
5
6
  import { docxSchema } from "../../schema/index.js";
6
7
  import { editorClassNames, editorCssVariables } from "../../styles/classNames.js";
7
8
  import { documentDefaultTabStopPt } from "../documentStyles.js";
8
9
  import { setTabWidths, tabWidths } from "./tabDecorations.js";
9
- var PX_PER_PT = 96 / 72;
10
10
  var POSITION_EPSILON_PT = 0.01;
11
11
  var WIDTH_EPSILON_PX = 0.1;
12
12
  var NATURAL_WIDTH_PX = 1e5;
@@ -0,0 +1,6 @@
1
+ /**
2
+ * The lines a table's cells draw because of where they sit in the grid (`table/gridBorders`),
3
+ * derived again once the grid or the border inputs of the table moved.
4
+ */
5
+ import type { DocumentDeriver } from "./displayDerivation";
6
+ export declare const tableDisplay: DocumentDeriver;
@@ -0,0 +1,30 @@
1
+ // src/editor/plugins/tableDisplay.ts
2
+ import { tableStyleAttrs } from "../../docx/formatting.js";
3
+ import { parsePropsXml } from "../../ooxml/props.js";
4
+ import { cellFixes, sameFormattingInputs } from "../../table/gridBorders.js";
5
+ var tableDisplay = {
6
+ name: "table",
7
+ nodeTypes: ["table"],
8
+ derive(table, pos, _doc, context, previous) {
9
+ if (previous !== null && sameFormattingInputs(previous, table)) return [];
10
+ const tblPr = table.attrs.tblPr;
11
+ const attrs = {
12
+ ...table.attrs,
13
+ ...tableStyleAttrs(
14
+ typeof tblPr === "string" ? parsePropsXml(tblPr) : null,
15
+ context.document.formatting
16
+ )
17
+ };
18
+ const current = table.hasMarkup(table.type, attrs, table.marks) ? table : table.type.create(attrs, table.content, table.marks);
19
+ return [
20
+ { pos, attrs },
21
+ ...cellFixes(current).map((fix) => ({
22
+ pos: pos + 1 + fix.pos,
23
+ attrs: fix.attrs
24
+ }))
25
+ ];
26
+ }
27
+ };
28
+ export {
29
+ tableDisplay
30
+ };
package/dist/index.d.ts CHANGED
@@ -15,6 +15,8 @@ export { EditorView } from "prosemirror-view";
15
15
  export type { DocxEditorHandle, DocxEditorMode, DocxEditorProps, } from "./DocxEditor";
16
16
  export { DocxEditor } from "./DocxEditor";
17
17
  export type { DocxBytes, DocxSource } from "./docx/importDocx";
18
+ /** What the handle and a `blocked` download report: each reason the document cannot be written, under the code `DocxExportError` would throw it with */
19
+ export type { ExportProblem } from "./docx/invariants";
18
20
  export type { DownloadDocxOptions, DownloadDocxResult, } from "./download";
19
21
  export { downloadDocx } from "./download";
20
22
  export type { CommentAuthor } from "./editor/commands/commentCommands";
@@ -11,7 +11,7 @@
11
11
  * declaration, the checks that let through only the shapes the read functions produce
12
12
  * live here alongside them.
13
13
  */
14
- import type { TabStop } from "./tabStops";
14
+ import { type TabStop } from "./tabStops";
15
15
  declare const ALIGNS: readonly ["left", "center", "right", "justify"];
16
16
  export type ParagraphAlign = (typeof ALIGNS)[number];
17
17
  declare const VERTICAL_ALIGNS: readonly ["superscript", "subscript"];
@@ -103,6 +103,11 @@ export interface ParagraphFormat {
103
103
  * page boundary guides
104
104
  */
105
105
  pageBreakBefore?: true;
106
+ /**
107
+ * Set when the document asks for this paragraph to stand on the same page as the start of the
108
+ * block after it (`w:keepNext`). Read by the page boundary guides
109
+ */
110
+ keepNext?: boolean;
106
111
  /** A CSS border in the form `1pt solid #000000` */
107
112
  borderTop?: string;
108
113
  borderBottom?: string;
@@ -110,15 +115,26 @@ export interface ParagraphFormat {
110
115
  borderRight?: string;
111
116
  background?: string;
112
117
  }
113
- /** The character formatting to render on screen */
118
+ /**
119
+ * The character formatting to render on screen.
120
+ *
121
+ * A toggle the run switches off outright (`w:val="0"`) is false rather than absent: absent means
122
+ * the run says nothing and what the style laid down stands, false is the run beating that style.
123
+ */
114
124
  export interface RunFormat {
115
- bold?: true;
116
- italic?: true;
117
- /** The underline kind. Absent entirely when there is no underline */
118
- underline?: UnderlineKind;
119
- strike?: true;
120
- smallCaps?: true;
125
+ bold?: boolean;
126
+ italic?: boolean;
127
+ /** The underline kind, or `none` for an underline switched off outright. Absent when the run says nothing */
128
+ underline?: UnderlineKind | "none";
129
+ strike?: boolean;
130
+ /** Two lines through the text (`w:dstrike`). Read from the document and not drawn or edited yet */
131
+ doubleStrike?: boolean;
132
+ smallCaps?: boolean;
133
+ /** Every letter drawn as a capital (`w:caps`). Read from the document and not drawn or edited yet */
134
+ caps?: boolean;
121
135
  fontSizePt?: number;
136
+ /** The room added between characters (`w:spacing`), below zero where they are drawn closer. Read from the document and not drawn or edited yet */
137
+ characterSpacingPt?: number;
122
138
  /** A CSS font name list in the form `"맑은 고딕","Malgun Gothic"` */
123
139
  fontFamily?: string;
124
140
  color?: string;
@@ -133,6 +149,12 @@ export interface RunFormat {
133
149
  */
134
150
  lang?: string;
135
151
  }
152
+ /**
153
+ * Every key of `RunFormat`, in the order a run's properties are read. The run property table
154
+ * (`docx/formatting/runProperties`) walks this list, which lives here because `model` imports
155
+ * nothing above it.
156
+ */
157
+ export declare const RUN_FORMAT_KEYS: readonly ["bold", "italic", "strike", "doubleStrike", "smallCaps", "caps", "underline", "fontSizePt", "characterSpacingPt", "fontFamily", "color", "highlight", "background", "verticalAlign", "lang"];
136
158
  /**
137
159
  * The table formatting to render on screen. The inner lines between cells are folded
138
160
  * into the cell formatting
@@ -166,6 +188,45 @@ export interface CellMargins {
166
188
  bottomPt: number | null;
167
189
  leftPt: number | null;
168
190
  }
191
+ /**
192
+ * The parts of a table a table style formats conditionally (`w:tblStylePr/@w:type`,
193
+ * ST_TblStyleOverrideType), in the order ECMA-376 Part 1 §17.7.6 applies them: a format standing
194
+ * later in this list is laid over one standing earlier.
195
+ */
196
+ export declare const TABLE_STYLE_CONDITIONS: readonly ["wholeTable", "band1Vert", "band2Vert", "band1Horz", "band2Horz", "firstRow", "lastRow", "firstCol", "lastCol", "nwCell", "neCell", "swCell", "seCell"];
197
+ export type TableStyleOverrideType = (typeof TABLE_STYLE_CONDITIONS)[number];
198
+ /**
199
+ * How many rows one row band and how many columns one column band are made of
200
+ * (`w:tblStyleRowBandSize`, `w:tblStyleColBandSize`). A style that says nothing leaves the side
201
+ * null, and its bands are then one row or one column wide.
202
+ */
203
+ export interface BandSizes {
204
+ row: number | null;
205
+ col: number | null;
206
+ }
207
+ /** The lines one conditional format draws around the region it covers. A side it says nothing about is null */
208
+ export interface CellStyleBorders {
209
+ top: string | null;
210
+ bottom: string | null;
211
+ left: string | null;
212
+ right: string | null;
213
+ }
214
+ /**
215
+ * What one conditional format of a table style lays down for the cells it covers.
216
+ *
217
+ * Its lines are those of the region: `borders` is drawn where a cell lies on the edge of the
218
+ * region and `inside` between the cells within it, the same way a table's own lines are drawn
219
+ * around and between its cells.
220
+ */
221
+ export interface CellStyleFormat {
222
+ background: string | null;
223
+ borders: CellStyleBorders;
224
+ inside: InsideBorders;
225
+ margins: CellMargins;
226
+ verticalAlign: CellVerticalAlign | null;
227
+ }
228
+ /** The conditional formats a table style lays down for its cells, by the part of the table each covers */
229
+ export type TableStyleConditions = Readonly<Partial<Record<TableStyleOverrideType, CellStyleFormat>>>;
169
230
  /**
170
231
  * How high a row stands, in points.
171
232
  * `atLeast` is a floor the row grows past when its text needs the room, and `exact` pins
@@ -229,6 +290,17 @@ export declare function toInsideBorders(value: unknown): InsideBorders | null;
229
290
  * there at all, so it is null.
230
291
  */
231
292
  export declare function toCellMargins(value: unknown): CellMargins | null;
293
+ /**
294
+ * The band sizes a table style laid down, as they come back in from `data-style-bands`.
295
+ * A style that said nothing about either is the same as the attribute not being there at all.
296
+ */
297
+ export declare function toBandSizes(value: unknown): BandSizes | null;
298
+ /**
299
+ * The conditional formats a table style laid down for its cells, as they come back in from
300
+ * `data-style-conditions`. A part no table has is not one this editor draws, so it is dropped;
301
+ * a table whose style dresses no part at all is the same as the attribute not being there.
302
+ */
303
+ export declare function toTableStyleConditions(value: unknown): TableStyleConditions | null;
232
304
  export declare function toRowFormat(value: unknown): RowFormat | null;
233
305
  export declare function toCellFormat(value: unknown): CellFormat | null;
234
306
  /**