@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,106 +1,148 @@
1
1
  // src/schema/attrRoles.ts
2
2
  import { NodeType } from "prosemirror-model";
3
3
  var NODE_ATTR_ROLES = {
4
+ doc: {
5
+ // The definitions of the lists started while editing. The export writes numbering.xml from
6
+ // them and nothing derives them again, so they are a source value the document node holds
7
+ newLists: { role: "source", class: "model" }
8
+ },
4
9
  paragraph: {
5
- srcId: "session",
6
- pAttrs: "source",
7
- pPr: "source",
8
- format: "display",
9
- styleRun: "display"
10
+ srcId: { role: "session", class: "identity" },
11
+ pAttrs: { role: "source", class: "preserved" },
12
+ pPr: { role: "source", class: "preserved" },
13
+ format: { role: "display", class: "derived" },
14
+ styleRun: { role: "display", class: "derived" }
10
15
  },
11
16
  table: {
12
- srcId: "session",
13
- tblAttrs: "source",
14
- tblPr: "source",
15
- tblW: "source",
16
- gridCols: "source",
17
- format: "display",
18
- styleInside: "display",
19
- styleCellMargins: "display"
17
+ srcId: { role: "session", class: "identity" },
18
+ tblAttrs: { role: "source", class: "preserved" },
19
+ tblPr: { role: "source", class: "preserved" },
20
+ tblW: { role: "source", class: "model" },
21
+ gridCols: { role: "source", class: "model" },
22
+ // The grid the table had before it was last revised, carried as it arrived
23
+ gridChange: { role: "source", class: "preserved" },
24
+ format: { role: "display", class: "derived" },
25
+ styleInside: { role: "display", class: "derived" },
26
+ styleCellMargins: { role: "display", class: "derived" },
27
+ styleConditions: { role: "display", class: "derived" },
28
+ styleBands: { role: "display", class: "derived" }
20
29
  },
21
30
  tableRow: {
22
- trAttrs: "source",
23
- tblPrEx: "source",
24
- trPr: "source",
25
- format: "display"
31
+ trAttrs: { role: "source", class: "preserved" },
32
+ tblPrEx: { role: "source", class: "preserved" },
33
+ trPr: { role: "source", class: "preserved" },
34
+ format: { role: "display", class: "derived" }
26
35
  },
27
36
  tableCell: {
28
- colspan: "source",
29
- rowspan: "source",
37
+ colspan: { role: "source", class: "model" },
38
+ rowspan: { role: "source", class: "model" },
30
39
  // prosemirror-tables' own attr. Import writes null, the writer never reads it, and the table
31
40
  // commands only carry it from one cell to another; a real column resize moves `gridCols`
32
- colwidth: "display",
33
- tcAttrs: "source",
34
- tcPr: "source",
35
- tcW: "source",
36
- format: "display",
41
+ colwidth: { role: "display", class: "derived" },
42
+ tcAttrs: { role: "source", class: "preserved" },
43
+ tcPr: { role: "source", class: "preserved" },
44
+ tcW: { role: "source", class: "model" },
45
+ format: { role: "display", class: "derived" },
37
46
  // Read from `sdtPrefix` rather than from the file, but a lock is not a display value: leaving
38
47
  // it out of the comparison would let a step that unlocks a cell pass as a re-derivation
39
- sdtPrefix: "source",
40
- sdtContentsLocked: "source",
41
- sdtDeletionLocked: "source"
42
- },
43
- rawBlock: { xml: "source", name: "source" },
44
- docxRaw: { srcId: "session", name: "session" },
45
- bookmarkBlock: { srcId: "session", name: "session" },
46
- hardBreak: { brAttrs: "source" },
47
- image: { src: "source", extent: "source", alt: "source", xml: "source" },
48
- commentStart: { id: "source", xml: "source" },
49
- commentEnd: { id: "source", xml: "source" },
48
+ sdtPrefix: { role: "source", class: "preserved" },
49
+ sdtContentsLocked: { role: "source", class: "derived" },
50
+ sdtDeletionLocked: { role: "source", class: "derived" }
51
+ },
52
+ rawBlock: {
53
+ xml: { role: "source", class: "preserved" },
54
+ name: { role: "source", class: "identity" }
55
+ },
56
+ docxRaw: {
57
+ srcId: { role: "session", class: "identity" },
58
+ name: { role: "session", class: "identity" }
59
+ },
60
+ bookmarkBlock: {
61
+ srcId: { role: "session", class: "identity" },
62
+ name: { role: "session", class: "identity" }
63
+ },
64
+ hardBreak: { brAttrs: { role: "source", class: "preserved" } },
65
+ image: {
66
+ // The bytes themselves, as a data URL the editor makes when an image is inserted
67
+ src: { role: "source", class: "model" },
68
+ extent: { role: "source", class: "model" },
69
+ alt: { role: "source", class: "model" },
70
+ xml: { role: "source", class: "preserved" }
71
+ },
72
+ commentStart: {
73
+ id: { role: "source", class: "identity" },
74
+ xml: { role: "source", class: "preserved" }
75
+ },
76
+ commentEnd: {
77
+ id: { role: "source", class: "identity" },
78
+ xml: { role: "source", class: "preserved" }
79
+ },
50
80
  commentReference: {
51
- id: "source",
52
- referenceXml: "source",
53
- author: "source",
54
- authorId: "source",
55
- initials: "source",
56
- date: "source",
57
- text: "source",
58
- commentXml: "source",
59
- paraId: "source",
60
- resolved: "source",
61
- extensionXml: "source",
62
- replies: "source",
81
+ id: { role: "source", class: "identity" },
82
+ referenceXml: { role: "source", class: "preserved" },
83
+ author: { role: "source", class: "model" },
84
+ authorId: { role: "source", class: "model" },
85
+ initials: { role: "source", class: "model" },
86
+ date: { role: "source", class: "model" },
87
+ text: { role: "source", class: "model" },
88
+ commentXml: { role: "source", class: "preserved" },
89
+ paraId: { role: "source", class: "identity" },
90
+ resolved: { role: "source", class: "model" },
91
+ extensionXml: { role: "source", class: "preserved" },
92
+ replies: { role: "source", class: "model" },
63
93
  // Read to decide whether the comment parts are rewritten at all; neither is written
64
- imported: "session",
65
- threadImported: "session"
94
+ imported: { role: "session", class: "derived" },
95
+ threadImported: { role: "session", class: "derived" }
66
96
  },
67
97
  noteReference: {
68
- kind: "source",
69
- id: "source",
70
- customMarkFollows: "source",
71
- referenceXml: "source",
98
+ kind: { role: "source", class: "model" },
99
+ id: { role: "source", class: "identity" },
100
+ customMarkFollows: { role: "source", class: "model" },
101
+ referenceXml: { role: "source", class: "preserved" },
72
102
  // Both come from the notes part as the document was opened, and the writer puts back the
73
103
  // reference alone: a note renumbered around an edit is the same reference it was
74
- label: "display",
75
- text: "display"
104
+ label: { role: "display", class: "derived" },
105
+ text: { role: "display", class: "derived" }
76
106
  },
77
- rawInline: { xml: "source" }
107
+ rawInline: { xml: { role: "source", class: "preserved" } }
78
108
  };
79
109
  var MARK_ATTR_ROLES = {
80
- run: { rPr: "source", rAttrs: "source", format: "display" },
110
+ run: {
111
+ rPr: { role: "source", class: "preserved" },
112
+ rAttrs: { role: "source", class: "preserved" },
113
+ format: { role: "display", class: "derived" }
114
+ },
81
115
  sdt: {
82
- sdtPrefix: "source",
116
+ sdtPrefix: { role: "source", class: "preserved" },
83
117
  // Counted through the document as it was opened, to tell one control from the next
84
- sdtKey: "session",
85
- contentsLocked: "source",
86
- deletionLocked: "source"
118
+ sdtKey: { role: "session", class: "identity" },
119
+ contentsLocked: { role: "source", class: "derived" },
120
+ deletionLocked: { role: "source", class: "derived" }
87
121
  },
88
- link: { linkPrefix: "source", href: "source", linkKey: "session" },
89
- tab: { tabAttrs: "source" }
122
+ link: {
123
+ linkPrefix: { role: "source", class: "preserved" },
124
+ href: { role: "source", class: "model" },
125
+ linkKey: { role: "session", class: "identity" }
126
+ },
127
+ tab: { tabAttrs: { role: "source", class: "preserved" } }
90
128
  };
91
- function rolesOf(type) {
92
- const roles = type instanceof NodeType ? NODE_ATTR_ROLES[type.name] : MARK_ATTR_ROLES[type.name];
93
- return roles ?? {};
129
+ function factsOf(type) {
130
+ const facts = type instanceof NodeType ? NODE_ATTR_ROLES[type.name] : MARK_ATTR_ROLES[type.name];
131
+ return facts ?? {};
94
132
  }
95
133
  function attrRole(type, name) {
96
- return rolesOf(type)[name] ?? "source";
134
+ return factsOf(type)[name]?.role ?? "source";
97
135
  }
98
136
  function displayAttrsOf(type) {
99
- return Object.entries(rolesOf(type)).filter(([, role]) => role === "display").map(([name]) => name);
137
+ return Object.entries(factsOf(type)).filter(([, facts]) => facts.role === "display").map(([name]) => name);
138
+ }
139
+ function attrsOfClass(type, cls) {
140
+ return Object.entries(factsOf(type)).filter(([, facts]) => facts.class === cls).map(([name]) => name);
100
141
  }
101
142
  export {
102
143
  MARK_ATTR_ROLES,
103
144
  NODE_ATTR_ROLES,
104
145
  attrRole,
146
+ attrsOfClass,
105
147
  displayAttrsOf
106
148
  };
@@ -0,0 +1,82 @@
1
+ /**
2
+ * How a display value gets onto a node: who says what it should be, and why the transaction that
3
+ * writes it is no edit.
4
+ *
5
+ * What a node draws with is worked out from its source and the formatting around it
6
+ * (`./attrRoles`), and has to be worked out again whenever either moves: the lines of a table's
7
+ * cells once a row is added, the style values of a paragraph once its own properties change, and
8
+ * every value at once when the formatting the document is resolved against is replaced. A deriver
9
+ * says, for the node types it answers for, what the display attrs of one such node should be, and
10
+ * `deriveDisplay` walks the blocks of a document, asks each owner in turn, and writes one step per
11
+ * node whose attrs would change. Only the display attrs of what a deriver hands back are read, so
12
+ * a deriver cannot write a source attr, and the walk is by construction the kind of transaction
13
+ * `changesOnlyDisplayAttrs` describes.
14
+ *
15
+ * The interface stands here, below `docx` and `editor`, so that a module of either can write a
16
+ * deriver against it. What a deriver resolves against is the caller's own `Context`, which this
17
+ * module never reads; `editor/plugins/displayDerivation` registers the derivers and runs the walk
18
+ * after every edit.
19
+ *
20
+ * A transaction carrying the `displayOnly` pass goes through the guard list whole (`./guards`),
21
+ * provided every step of it is judged, off the role table alone, to change display attrs and
22
+ * nothing else. The pass is a claim rather than a key: a step that rewrites a source attr, a lock
23
+ * flag among them, or that puts content anywhere, fails the claim, and the transaction is then
24
+ * judged as any other edit.
25
+ */
26
+ import { type Attrs, type MarkType, type Node as PMNode, type Schema } from "prosemirror-model";
27
+ import { PluginKey } from "prosemirror-state";
28
+ import { type Step, type Transform } from "prosemirror-transform";
29
+ import type { docxSchema } from "./docxSchema";
30
+ /** The name of a node type of the document schema, which is what a deriver answers for by */
31
+ export type NodeName = typeof docxSchema extends Schema<infer Nodes, string> ? Nodes : never;
32
+ /** The display attrs one node should carry, by the position the node stands at in the document handed to the deriver */
33
+ export interface DisplayAttrs {
34
+ readonly pos: number;
35
+ readonly attrs: Attrs;
36
+ /** Omitted for node attrs. Otherwise updates an existing mark on this inline node. */
37
+ readonly mark?: {
38
+ readonly type: MarkType;
39
+ readonly to: number;
40
+ };
41
+ }
42
+ /**
43
+ * What says, for the node types it answers for, what one node's display attrs should be.
44
+ *
45
+ * `derive` is asked once per such node, in document order, with the node as the derivers before it
46
+ * left it. It hands back the display attrs of that node and of any node inside it, each by
47
+ * position - a table's deriver answers for the cells - or nothing where nothing changes; a source
48
+ * or session attr among what it hands back is not written. `previous` is the node this one maps
49
+ * back to in the document before the change, or null when there is none, or when every value is
50
+ * being worked out again from nothing.
51
+ */
52
+ export interface DisplayDeriver<Context> {
53
+ readonly name: string;
54
+ /**
55
+ * The block node types this deriver answers for. The walk runs over the blocks and never into
56
+ * the inline content of a textblock, since it runs after every keystroke, so an inline type
57
+ * cannot be answered for.
58
+ */
59
+ readonly nodeTypes: readonly NodeName[];
60
+ derive(node: PMNode, pos: number, doc: PMNode, context: Context, previous: PMNode | null): readonly DisplayAttrs[];
61
+ }
62
+ /**
63
+ * Writes the display attrs the derivers hand back, one `setNodeMarkup` per node whose attrs would
64
+ * change, onto the transform. It holds no state of its own: what a node maps back to comes from
65
+ * the caller, who knows what changed.
66
+ *
67
+ * Every step keeps the document the same size, so the positions gathered before the first write
68
+ * still hold, and a deriver asked after another reads the node as that one left it.
69
+ */
70
+ export declare function deriveDisplay<Context>(transform: Transform, context: Context, derivers: readonly DisplayDeriver<Context>[], previousOf: (node: PMNode, pos: number) => PMNode | null): void;
71
+ /**
72
+ * The pass a re-derivation carries. A plugin key is used as the name so that it cannot collide
73
+ * with a consumer's own metadata.
74
+ */
75
+ export declare const displayOnly: PluginKey<boolean>;
76
+ /**
77
+ * Whether the step changes display attrs and nothing else, judged off the role table alone.
78
+ *
79
+ * Node attrs and existing mark attrs may change only their display fields. Adding a mark where
80
+ * that type was absent, changing source attrs, and all other step shapes remain edits.
81
+ */
82
+ export declare function changesOnlyDisplayAttrs(step: Step, doc: PMNode): boolean;
@@ -0,0 +1,130 @@
1
+ // src/schema/displayDerivation.ts
2
+ import {
3
+ Mark
4
+ } from "prosemirror-model";
5
+ import { PluginKey } from "prosemirror-state";
6
+ import {
7
+ AddMarkStep,
8
+ AttrStep,
9
+ ReplaceAroundStep
10
+ } from "prosemirror-transform";
11
+ import { attrRole } from "./attrRoles.js";
12
+ function ownersByType(schema, derivers) {
13
+ const owners = /* @__PURE__ */ new Map();
14
+ for (const deriver of derivers) {
15
+ for (const name of deriver.nodeTypes) {
16
+ const type = schema.nodes[name];
17
+ if (type === void 0 || type.isInline) {
18
+ throw new Error(
19
+ `${deriver.name} answers for ${name}, which the walk over the blocks never reaches`
20
+ );
21
+ }
22
+ const owning = owners.get(name) ?? [];
23
+ owning.push(deriver);
24
+ owners.set(name, owning);
25
+ }
26
+ }
27
+ return owners;
28
+ }
29
+ function displayLaidOver(standing, derived) {
30
+ const attrs = { ...standing.attrs };
31
+ for (const [name, value] of Object.entries(derived)) {
32
+ if (attrRole(standing.type, name) === "display") attrs[name] = value;
33
+ }
34
+ return attrs;
35
+ }
36
+ function nodeStanding(doc, pos) {
37
+ const node = doc.nodeAt(pos);
38
+ if (node === null) throw new Error(`no node stands at ${pos}`);
39
+ return node;
40
+ }
41
+ function deriveDisplay(transform, context, derivers, previousOf) {
42
+ const owners = ownersByType(transform.doc.type.schema, derivers);
43
+ const spots = [];
44
+ transform.doc.descendants((node, pos) => {
45
+ const owning = owners.get(node.type.name);
46
+ if (owning !== void 0) spots.push({ pos, owners: owning });
47
+ return !node.isTextblock;
48
+ });
49
+ for (const spot of spots) {
50
+ for (const deriver of spot.owners) {
51
+ const node = nodeStanding(transform.doc, spot.pos);
52
+ const derived = deriver.derive(
53
+ node,
54
+ spot.pos,
55
+ transform.doc,
56
+ context,
57
+ previousOf(node, spot.pos)
58
+ );
59
+ for (const { pos, attrs, mark: target } of derived) {
60
+ const standing = nodeStanding(transform.doc, pos);
61
+ if (target !== void 0) {
62
+ const mark = target.type.isInSet(standing.marks);
63
+ if (!standing.isInline || mark === void 0) continue;
64
+ const end = pos + standing.nodeSize - transform.doc.resolve(pos).textOffset;
65
+ if (target.to <= pos || target.to > end) {
66
+ throw new Error(
67
+ "a display mark update must stay within its inline node"
68
+ );
69
+ }
70
+ const next2 = target.type.create(displayLaidOver(mark, attrs));
71
+ if (!mark.eq(next2)) {
72
+ transform.step(new AddMarkStep(pos, target.to, next2));
73
+ }
74
+ continue;
75
+ }
76
+ const next = displayLaidOver(standing, attrs);
77
+ if (!standing.hasMarkup(standing.type, next, standing.marks)) {
78
+ transform.setNodeMarkup(pos, null, next);
79
+ }
80
+ }
81
+ }
82
+ }
83
+ }
84
+ var displayOnly = new PluginKey("docxEditorDisplayOnly");
85
+ function sameOutsideDisplay(type, was, now) {
86
+ const names = /* @__PURE__ */ new Set([...Object.keys(was), ...Object.keys(now)]);
87
+ for (const name of names) {
88
+ if (attrRole(type, name) === "display") continue;
89
+ if (was[name] !== now[name]) return false;
90
+ }
91
+ return true;
92
+ }
93
+ function rewrittenNode(step, doc) {
94
+ const was = doc.nodeAt(step.from);
95
+ const now = step.slice.content.firstChild;
96
+ if (was === null || now === null || step.slice.content.childCount !== 1 || step.slice.openStart !== 0 || step.slice.openEnd !== 0 || now.content.size !== 0 || step.insert !== 1 || step.gapFrom !== step.from + 1 || step.to !== step.from + was.nodeSize || step.gapTo !== step.to - 1) {
97
+ return null;
98
+ }
99
+ return { was, now };
100
+ }
101
+ function changesOnlyDisplayAttrs(step, doc) {
102
+ if (step instanceof AddMarkStep) {
103
+ let touched = false;
104
+ let allowed = true;
105
+ doc.nodesBetween(step.from, step.to, (node, _pos, parent) => {
106
+ if (!node.isInline) return true;
107
+ if (!parent?.type.allowsMarkType(step.mark.type)) return false;
108
+ touched = true;
109
+ const previous = step.mark.type.isInSet(node.marks);
110
+ if (!previous || !sameOutsideDisplay(step.mark.type, previous.attrs, step.mark.attrs))
111
+ allowed = false;
112
+ return false;
113
+ });
114
+ return touched && allowed;
115
+ }
116
+ if (step instanceof AttrStep) {
117
+ const node = doc.nodeAt(step.pos);
118
+ return node !== null && attrRole(node.type, step.attr) === "display";
119
+ }
120
+ if (!(step instanceof ReplaceAroundStep)) return false;
121
+ const rewritten = rewrittenNode(step, doc);
122
+ if (rewritten === null) return false;
123
+ const { was, now } = rewritten;
124
+ return was.type === now.type && Mark.sameSet(was.marks, now.marks) && sameOutsideDisplay(was.type, was.attrs, now.attrs);
125
+ }
126
+ export {
127
+ changesOnlyDisplayAttrs,
128
+ deriveDisplay,
129
+ displayOnly
130
+ };
@@ -7,6 +7,9 @@
7
7
  * goes back out as the XML it arrived as. Which of the two a block is decides how it is written
8
8
  * (`docx/serializeBlock`) and how a submitted file is compared against the original
9
9
  * (`docx/storyProjection`), so a new block node has to name one of them.
10
+ *
11
+ * `./attrRoles` declares each attr's provenance and comparison role; `attrClasses.test.ts`
12
+ * checks coverage. The plugin guide defines the supported public surface.
10
13
  */
11
14
  import { Schema } from "prosemirror-model";
12
15
  export { imageNodeSpec, runMarkSpec } from "./rendering";
@@ -2,6 +2,7 @@
2
2
  import { Schema } from "prosemirror-model";
3
3
  import {
4
4
  spanCount,
5
+ toBandSizes,
5
6
  toCellFormat,
6
7
  toCellMargins,
7
8
  toColWidth,
@@ -11,6 +12,7 @@ import {
11
12
  toRowFormat,
12
13
  toRunFormat,
13
14
  toTableFormat,
15
+ toTableStyleConditions,
14
16
  toTableWidth
15
17
  } from "../model/format.js";
16
18
  import {
@@ -69,9 +71,7 @@ function isPageBreak(brAttrs) {
69
71
  }
70
72
  function srcIdOf(dom) {
71
73
  const raw = dom.getAttribute("data-src");
72
- if (raw === null) return null;
73
- const parsed = Number.parseInt(raw, 10);
74
- return Number.isNaN(parsed) ? null : parsed;
74
+ return raw === null || raw === "" ? null : raw;
75
75
  }
76
76
  function repliesHoldTheirXml(value) {
77
77
  if (!Array.isArray(value)) return true;
@@ -114,7 +114,16 @@ var DOCX_RAW_SELECTOR = [
114
114
  ].map((className) => `div[data-src].${className}`).join(", ");
115
115
  var docxSchema = new Schema({
116
116
  nodes: {
117
- doc: { content: "block+" },
117
+ doc: {
118
+ content: "block+",
119
+ attrs: {
120
+ /**
121
+ * The definitions of the lists started while editing, which the export writes into
122
+ * numbering.xml. Read back through `numbering/listRegistry`.
123
+ */
124
+ newLists: { default: null }
125
+ }
126
+ },
118
127
  paragraph: {
119
128
  group: "block modelled",
120
129
  content: "inline*",
@@ -126,13 +135,11 @@ var docxSchema = new Schema({
126
135
  pAttrs: { default: null },
127
136
  /** The whole `<w:pPr>...</w:pPr>` XML. null when there is none */
128
137
  pPr: { default: null },
129
- /** The display values derived from reading pPr */
138
+ /** Derived paragraph formatting; see `./attrRoles`. */
130
139
  format: { default: null },
131
140
  /**
132
- * The character formatting the style this paragraph wears lays down, drawn as the
133
- * paragraph's own CSS so that text carrying no run of its own inherits it.
134
- * It is derived from the style table the same way `format` is, and like `format` it never
135
- * goes back into the document.
141
+ * Derived character formatting drawn on the paragraph so unmarked text inherits it.
142
+ * Its comparison role and provenance are declared in `./attrRoles`.
136
143
  */
137
144
  styleRun: { default: null }
138
145
  },
@@ -144,7 +151,7 @@ var docxSchema = new Schema({
144
151
  {
145
152
  class: editorClassNames.paragraph,
146
153
  style: paragraphStyle(format, styleRun),
147
- "data-src": node.attrs.srcId === null ? void 0 : `${node.attrs.srcId}`,
154
+ "data-src": text(node.attrs.srcId),
148
155
  "data-pattrs": text(node.attrs.pAttrs),
149
156
  "data-ppr": text(node.attrs.pPr),
150
157
  "data-fmt": formatJson(format),
@@ -195,11 +202,26 @@ var docxSchema = new Schema({
195
202
  tblW: { default: null },
196
203
  /** The `w:gridCol` widths (dxa) in order */
197
204
  gridCols: { default: [] },
205
+ /**
206
+ * The whole `<w:tblGridChange>...</w:tblGridChange>` XML, the record of the grid this
207
+ * table had before it was last revised. Carried as it arrived because the grid around it
208
+ * is rebuilt from `gridCols`, and CT_TblGrid takes it after the columns however wide
209
+ * those turn out to be (ECMA-376 Part 1 17.4.48)
210
+ */
211
+ gridChange: { default: null },
198
212
  format: { default: null },
199
213
  /** The lines between cells the table style laid down, so an edit can derive them again */
200
214
  styleInside: { default: null },
201
215
  /** The cell margins the table style laid down, carried along for the same reason */
202
- styleCellMargins: { default: null }
216
+ styleCellMargins: { default: null },
217
+ /**
218
+ * What the table style dresses each part of a table with (`w:tblStylePr`), by the part it
219
+ * covers. Which of them a cell takes is worked out from where it sits and the table's own
220
+ * `w:tblLook`, so an edit that moves the grid derives them again
221
+ */
222
+ styleConditions: { default: null },
223
+ /** How many rows and columns one band of the table style is made of */
224
+ styleBands: { default: null }
203
225
  },
204
226
  toDOM(node) {
205
227
  const format = toTableFormat(node.attrs.format);
@@ -208,18 +230,23 @@ var docxSchema = new Schema({
208
230
  const attrs = {
209
231
  class: editorClassNames.table,
210
232
  style: tableStyle(format, width),
211
- "data-src": node.attrs.srcId === null ? void 0 : `${node.attrs.srcId}`,
233
+ "data-src": text(node.attrs.srcId),
212
234
  "data-tblattrs": text(node.attrs.tblAttrs),
213
235
  "data-tblpr": text(node.attrs.tblPr),
214
236
  "data-tblw": formatJson(width),
215
237
  "data-cols": numberListText(gridCols),
238
+ "data-gridchange": text(node.attrs.gridChange),
216
239
  "data-fmt": formatJson(format),
217
240
  "data-style-inside": formatJson(
218
241
  toInsideBorders(node.attrs.styleInside)
219
242
  ),
220
243
  "data-style-margins": formatJson(
221
244
  toCellMargins(node.attrs.styleCellMargins)
222
- )
245
+ ),
246
+ "data-style-conditions": formatJson(
247
+ toTableStyleConditions(node.attrs.styleConditions)
248
+ ),
249
+ "data-style-bands": formatJson(toBandSizes(node.attrs.styleBands))
223
250
  };
224
251
  const body = ["tbody", 0];
225
252
  if (gridCols.length === 0) return ["table", attrs, body];
@@ -237,19 +264,33 @@ var docxSchema = new Schema({
237
264
  getAttrs: (dom) => {
238
265
  const tblAttrs = rawXml(dom, "data-tblattrs", ATTRIBUTES);
239
266
  const tblPr = rawXml(dom, "data-tblpr", ELEMENT("tblPr"));
240
- if (tblAttrs === false || tblPr === false) return false;
267
+ const gridChange = rawXml(
268
+ dom,
269
+ "data-gridchange",
270
+ ELEMENT("tblGridChange")
271
+ );
272
+ if (tblAttrs === false || tblPr === false || gridChange === false) {
273
+ return false;
274
+ }
241
275
  return {
242
276
  srcId: srcIdOf(dom),
243
277
  tblAttrs,
244
278
  tblPr,
245
279
  tblW: toTableWidth(parseJson(dom.getAttribute("data-tblw"))),
246
280
  gridCols: parseNumberList(dom.getAttribute("data-cols")),
281
+ gridChange,
247
282
  format: toTableFormat(parseJson(dom.getAttribute("data-fmt"))),
248
283
  styleInside: toInsideBorders(
249
284
  parseJson(dom.getAttribute("data-style-inside"))
250
285
  ),
251
286
  styleCellMargins: toCellMargins(
252
287
  parseJson(dom.getAttribute("data-style-margins"))
288
+ ),
289
+ styleConditions: toTableStyleConditions(
290
+ parseJson(dom.getAttribute("data-style-conditions"))
291
+ ),
292
+ styleBands: toBandSizes(
293
+ parseJson(dom.getAttribute("data-style-bands"))
253
294
  )
254
295
  };
255
296
  }
@@ -439,7 +480,7 @@ var docxSchema = new Schema({
439
480
  "div",
440
481
  {
441
482
  class: className,
442
- "data-src": node.attrs.srcId === null ? "" : `${node.attrs.srcId}`,
483
+ "data-src": text(node.attrs.srcId) ?? "",
443
484
  "data-name": text(node.attrs.name)
444
485
  },
445
486
  label
@@ -470,7 +511,7 @@ var docxSchema = new Schema({
470
511
  "div",
471
512
  {
472
513
  class: editorClassNames.bookmarkBlock,
473
- "data-src": node.attrs.srcId === null ? "" : `${node.attrs.srcId}`,
514
+ "data-src": text(node.attrs.srcId) ?? "",
474
515
  "data-name": text(node.attrs.name),
475
516
  hidden: "hidden"
476
517
  }
@@ -923,7 +964,7 @@ var docxSchema = new Schema({
923
964
  attrs: {
924
965
  rPr: { default: null },
925
966
  rAttrs: { default: null },
926
- /** The display values derived from reading rPr */
967
+ /** Derived run formatting; see `./attrRoles`. */
927
968
  format: { default: null }
928
969
  },
929
970
  toDOM(mark) {
@@ -46,7 +46,7 @@ export type EditIntent =
46
46
  * against the places it puts that guard to the test, and a place naming a guard that no longer
47
47
  * stands has to be a mistake the compiler catches rather than an annotation answering for nothing.
48
48
  */
49
- export type EditGuardName = "protection" | "lock" | "bookmark" | "note";
49
+ export type EditGuardName = "protection" | "lock" | "bookmark" | "note" | "section";
50
50
  /** What every guard answers, whichever of the two judgements it is written as */
51
51
  interface GuardCommon {
52
52
  readonly name: EditGuardName;