@portone/docx-editor 0.2.1 → 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 (225) hide show
  1. package/CHANGELOG.md +109 -0
  2. package/CONTRIBUTING.md +5 -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 +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 +52 -111
  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 +69 -71
  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 +27 -0
  33. package/dist/docx/formatting/attrs.js +31 -0
  34. package/dist/docx/formatting/context.d.ts +31 -0
  35. package/dist/docx/formatting/context.js +42 -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 +45 -0
  39. package/dist/docx/formatting/resolve.js +140 -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.js +3 -3
  43. package/dist/docx/formatting/tabStops.js +7 -22
  44. package/dist/docx/formatting.d.ts +4 -1
  45. package/dist/docx/formatting.js +4 -1
  46. package/dist/docx/headersFooters.js +6 -13
  47. package/dist/docx/identities.d.ts +67 -0
  48. package/dist/docx/identities.js +174 -0
  49. package/dist/docx/importDocx.d.ts +12 -1
  50. package/dist/docx/importDocx.js +72 -79
  51. package/dist/docx/importParagraph.d.ts +1 -1
  52. package/dist/docx/importParagraph.js +4 -3
  53. package/dist/docx/importTable.d.ts +1 -1
  54. package/dist/docx/importTable.js +17 -1
  55. package/dist/docx/invariants.d.ts +33 -0
  56. package/dist/docx/invariants.js +256 -0
  57. package/dist/docx/media.d.ts +6 -4
  58. package/dist/docx/media.js +6 -37
  59. package/dist/docx/newLists.d.ts +20 -0
  60. package/dist/docx/newLists.js +36 -0
  61. package/dist/docx/notes.js +3 -7
  62. package/dist/docx/numberingPlanner.d.ts +8 -0
  63. package/dist/docx/numberingPlanner.js +19 -0
  64. package/dist/docx/packageParts.d.ts +42 -0
  65. package/dist/docx/packageParts.js +135 -0
  66. package/dist/docx/pageGeometry.d.ts +2 -0
  67. package/dist/docx/pageGeometry.js +18 -9
  68. package/dist/docx/paraProps.d.ts +10 -22
  69. package/dist/docx/paraProps.js +47 -76
  70. package/dist/docx/partPlan.d.ts +36 -0
  71. package/dist/docx/partPlan.js +59 -0
  72. package/dist/docx/protectionPolicy.d.ts +127 -0
  73. package/dist/docx/protectionPolicy.js +169 -0
  74. package/dist/docx/relationships.d.ts +1 -1
  75. package/dist/docx/relationships.js +8 -13
  76. package/dist/docx/runProps.d.ts +9 -22
  77. package/dist/docx/runProps.js +15 -168
  78. package/dist/docx/scan.js +20 -52
  79. package/dist/docx/sdt.js +9 -34
  80. package/dist/docx/sdtProps.d.ts +8 -1
  81. package/dist/docx/sdtProps.js +10 -0
  82. package/dist/docx/serializeBlock.d.ts +2 -0
  83. package/dist/docx/serializeBlock.js +8 -5
  84. package/dist/docx/serializeTable.js +32 -15
  85. package/dist/docx/session.d.ts +42 -14
  86. package/dist/docx/session.js +43 -17
  87. package/dist/docx/tableFormatting/editing.js +108 -139
  88. package/dist/docx/tableFormatting/reading.d.ts +16 -6
  89. package/dist/docx/tableFormatting/reading.js +40 -20
  90. package/dist/docx/tableTemplate.js +18 -7
  91. package/dist/download.d.ts +8 -5
  92. package/dist/download.js +2 -0
  93. package/dist/editor/clipboard/inlineFormatting.js +19 -30
  94. package/dist/editor/commands/comments/editing.d.ts +6 -2
  95. package/dist/editor/commands/comments/editing.js +19 -31
  96. package/dist/editor/commands/exportQueries.d.ts +15 -0
  97. package/dist/editor/commands/exportQueries.js +14 -0
  98. package/dist/editor/commands/fidelityQueries.d.ts +12 -0
  99. package/dist/editor/commands/fidelityQueries.js +8 -0
  100. package/dist/editor/commands/formatting/editing.d.ts +2 -2
  101. package/dist/editor/commands/formatting/editing.js +26 -108
  102. package/dist/editor/commands/formatting/propertyCommands.d.ts +21 -0
  103. package/dist/editor/commands/formatting/propertyCommands.js +103 -0
  104. package/dist/editor/commands/formatting/shared.d.ts +3 -3
  105. package/dist/editor/commands/formatting/shared.js +5 -2
  106. package/dist/editor/commands/indentCommands.js +5 -4
  107. package/dist/editor/commands/index.d.ts +11 -0
  108. package/dist/editor/commands/index.js +5 -0
  109. package/dist/editor/commands/linkCommands.js +5 -6
  110. package/dist/editor/commands/listCommands.js +8 -10
  111. package/dist/editor/commands/lockCommands.d.ts +7 -1
  112. package/dist/editor/commands/lockCommands.js +35 -46
  113. package/dist/editor/commands/paragraphCommands.js +28 -31
  114. package/dist/editor/commands/spacingCommands.js +1 -1
  115. package/dist/editor/createEditor.d.ts +17 -29
  116. package/dist/editor/createEditor.js +58 -58
  117. package/dist/editor/documentStyles.d.ts +11 -35
  118. package/dist/editor/documentStyles.js +9 -52
  119. package/dist/editor/editorDocument.d.ts +56 -0
  120. package/dist/editor/editorDocument.js +74 -0
  121. package/dist/editor/externalClipboard.js +16 -45
  122. package/dist/editor/insertTable.js +4 -3
  123. package/dist/editor/paragraphEdits.d.ts +11 -18
  124. package/dist/editor/paragraphEdits.js +7 -16
  125. package/dist/editor/plugins/displayDerivation.d.ts +47 -0
  126. package/dist/editor/plugins/displayDerivation.js +78 -0
  127. package/dist/editor/plugins/imagePaste.js +4 -3
  128. package/dist/editor/plugins/keymap.js +18 -3
  129. package/dist/editor/plugins/numberingDecorations.d.ts +5 -11
  130. package/dist/editor/plugins/numberingDecorations.js +7 -17
  131. package/dist/editor/plugins/paragraphDisplay.d.ts +7 -0
  132. package/dist/editor/plugins/paragraphDisplay.js +51 -0
  133. package/dist/editor/plugins/tabLayout.js +1 -1
  134. package/dist/editor/plugins/tableDisplay.d.ts +6 -0
  135. package/dist/editor/plugins/tableDisplay.js +16 -0
  136. package/dist/index.d.ts +2 -0
  137. package/dist/model/format.d.ts +30 -8
  138. package/dist/model/format.js +35 -22
  139. package/dist/model/tabStops.d.ts +9 -0
  140. package/dist/model/tabStops.js +18 -0
  141. package/dist/numbering/listTemplate.js +24 -7
  142. package/dist/numbering/parseNumbering.d.ts +14 -1
  143. package/dist/numbering/parseNumbering.js +35 -22
  144. package/dist/numbering/writeNumbering.d.ts +3 -4
  145. package/dist/numbering/writeNumbering.js +14 -25
  146. package/dist/ooxml/childOrder.d.ts +34 -0
  147. package/dist/ooxml/childOrder.js +496 -0
  148. package/dist/ooxml/element.d.ts +24 -11
  149. package/dist/ooxml/element.js +31 -12
  150. package/dist/ooxml/errors.d.ts +3 -2
  151. package/dist/ooxml/image.d.ts +4 -0
  152. package/dist/ooxml/image.js +2 -5
  153. package/dist/ooxml/partSplice.d.ts +67 -0
  154. package/dist/ooxml/partSplice.js +169 -0
  155. package/dist/ooxml/props.d.ts +112 -0
  156. package/dist/{docx/propsXml.js → ooxml/props.js} +72 -200
  157. package/dist/ooxml/simpleTypes.d.ts +103 -0
  158. package/dist/ooxml/simpleTypes.js +182 -0
  159. package/dist/ooxml/tabStops.js +8 -27
  160. package/dist/ooxml/tagScan.d.ts +34 -0
  161. package/dist/ooxml/tagScan.js +108 -0
  162. package/dist/ooxml/units.d.ts +25 -13
  163. package/dist/ooxml/units.js +65 -31
  164. package/dist/ooxml/xml.d.ts +27 -6
  165. package/dist/ooxml/xml.js +37 -5
  166. package/dist/page/blockKinds.d.ts +61 -0
  167. package/dist/page/blockKinds.js +11 -0
  168. package/dist/page/kinds/index.d.ts +6 -0
  169. package/dist/page/kinds/index.js +10 -0
  170. package/dist/page/kinds/paragraphKind.d.ts +10 -0
  171. package/dist/page/kinds/paragraphKind.js +71 -0
  172. package/dist/page/kinds/tableKind.d.ts +10 -0
  173. package/dist/page/kinds/tableKind.js +178 -0
  174. package/dist/page/measureBlocks.d.ts +3 -14
  175. package/dist/page/measureBlocks.js +24 -45
  176. package/dist/page/pageDecorations.d.ts +27 -44
  177. package/dist/page/pageDecorations.js +70 -152
  178. package/dist/page/pageLayout.d.ts +2 -19
  179. package/dist/page/pageLayout.js +36 -6
  180. package/dist/page/usePageLayout.d.ts +2 -17
  181. package/dist/page/usePageLayout.js +3 -39
  182. package/dist/schema/attrRoles.d.ts +25 -18
  183. package/dist/schema/attrRoles.js +102 -67
  184. package/dist/schema/displayDerivation.d.ts +82 -0
  185. package/dist/schema/displayDerivation.js +130 -0
  186. package/dist/schema/docxSchema.d.ts +3 -0
  187. package/dist/schema/docxSchema.js +26 -14
  188. package/dist/schema/editGuard.d.ts +1 -1
  189. package/dist/schema/guards.d.ts +37 -14
  190. package/dist/schema/guards.js +29 -3
  191. package/dist/schema/index.d.ts +2 -0
  192. package/dist/schema/index.js +2 -0
  193. package/dist/schema/locks.d.ts +11 -44
  194. package/dist/schema/locks.js +0 -9
  195. package/dist/schema/preservedGuards.d.ts +26 -6
  196. package/dist/schema/preservedGuards.js +31 -1
  197. package/dist/schema/protection.d.ts +7 -1
  198. package/dist/schema/protection.js +2 -1
  199. package/dist/schema/sourceEquality.d.ts +1 -9
  200. package/dist/schema/sourceEquality.js +1 -27
  201. package/dist/styles/inlineStyle.js +15 -6
  202. package/dist/table/cellFormatting.d.ts +8 -1
  203. package/dist/table/cellFormatting.js +10 -18
  204. package/dist/table/commands.js +20 -18
  205. package/dist/table/format.d.ts +3 -0
  206. package/dist/table/format.js +3 -9
  207. package/dist/table/gridBorders.d.ts +14 -16
  208. package/dist/table/gridBorders.js +3 -41
  209. package/dist/table/merge.d.ts +2 -6
  210. package/dist/table/merge.js +5 -5
  211. package/package.json +7 -3
  212. package/dist/docx/comments/contentTypes.d.ts +0 -7
  213. package/dist/docx/comments/contentTypes.js +0 -38
  214. package/dist/docx/comments/verifying.js +0 -206
  215. package/dist/docx/formatting/effectiveParagraph.d.ts +0 -15
  216. package/dist/docx/formatting/effectiveParagraph.js +0 -81
  217. package/dist/docx/propsXml.d.ts +0 -67
  218. package/dist/docx/uniqueControls.d.ts +0 -14
  219. package/dist/docx/uniqueControls.js +0 -62
  220. package/dist/editor/plugins/commentReservations.d.ts +0 -5
  221. package/dist/editor/plugins/commentReservations.js +0 -26
  222. package/dist/editor/plugins/styledParagraphs.d.ts +0 -15
  223. package/dist/editor/plugins/styledParagraphs.js +0 -65
  224. package/dist/page/tableMeasurements.d.ts +0 -18
  225. package/dist/page/tableMeasurements.js +0 -119
@@ -1,7 +1,5 @@
1
1
  // src/table/gridBorders.ts
2
- import { Plugin } from "prosemirror-state";
3
2
  import { TableMap } from "prosemirror-tables";
4
- import { Transform } from "prosemirror-transform";
5
3
  import {
6
4
  cellBorderDefaults,
7
5
  cellMarginsOf,
@@ -129,14 +127,6 @@ function cellFixes(table) {
129
127
  }
130
128
  return fixes;
131
129
  }
132
- function tablesOf(doc) {
133
- const tables = [];
134
- doc.descendants((node, pos) => {
135
- if (node.type.spec.tableRole === "table") tables.push({ pos, table: node });
136
- return !node.isTextblock;
137
- });
138
- return tables;
139
- }
140
130
  function sameSpans(a, b) {
141
131
  return spanCount(a.attrs.colspan) === spanCount(b.attrs.colspan) && spanCount(a.attrs.rowspan) === spanCount(b.attrs.rowspan);
142
132
  }
@@ -156,37 +146,9 @@ function sameCellFormattingInputs(a, b) {
156
146
  function sameFormattingInputs(a, b) {
157
147
  return sameGrid(a, b) && a.attrs.tblPr === b.attrs.tblPr && a.attrs.format === b.attrs.format && a.attrs.styleInside === b.attrs.styleInside && a.attrs.styleCellMargins === b.attrs.styleCellMargins && sameCellFormattingInputs(a, b);
158
148
  }
159
- function withDerivedGridBorders(doc) {
160
- const transform = new Transform(doc);
161
- for (const { pos, table } of tablesOf(doc)) {
162
- for (const fix of cellFixes(table)) {
163
- transform.setNodeMarkup(pos + 1 + fix.pos, null, fix.attrs);
164
- }
165
- }
166
- return transform.doc;
167
- }
168
- function gridBorders() {
169
- return new Plugin({
170
- appendTransaction(transactions, oldState, newState) {
171
- if (!transactions.some((transaction) => transaction.docChanged)) {
172
- return null;
173
- }
174
- const before = tablesOf(oldState.doc);
175
- const tr = newState.tr;
176
- tablesOf(newState.doc).forEach(({ pos, table }, index) => {
177
- const was = before[index]?.table;
178
- if (was && sameFormattingInputs(was, table)) return;
179
- for (const fix of cellFixes(table)) {
180
- tr.setNodeMarkup(pos + 1 + fix.pos, null, fix.attrs);
181
- }
182
- });
183
- return tr.docChanged ? tr : null;
184
- }
185
- });
186
- }
187
149
  export {
188
150
  cellDefaultsAt,
189
- gridBorders,
190
- tableCellSources,
191
- withDerivedGridBorders
151
+ cellFixes,
152
+ sameFormattingInputs,
153
+ tableCellSources
192
154
  };
@@ -7,17 +7,13 @@ import type { EditorState, Transaction } from "prosemirror-state";
7
7
  * Whether several cells can be merged into one.
8
8
  * The selection has to be a rectangle spanning more than one cell, no merged cell may stick out
9
9
  * past that rectangle, and the guards have to let the merge through: a locked cell may not be
10
- * swallowed by another (`schema/locks`).
11
- *
12
- * The two queries are defined from the very transaction the commands run, so they cannot drift
13
- * from them. They live here rather than beside the commands because `./commands` imports these
14
- * builders, and the other way round would turn that import around.
10
+ * swallowed by another (`schema/guards`).
15
11
  */
16
12
  export declare function canMergeCells(state: EditorState): boolean;
17
13
  /**
18
14
  * Whether a split is possible. The cursor has to sit inside a cell that is merged horizontally or
19
15
  * vertically, and the guards have to let the split through: the cells a split makes would each
20
- * carry the original's lock, which is a lock planted in places it was never put (`schema/locks`).
16
+ * carry the original's lock, which is a lock planted in places it was never put (`schema/guards`).
21
17
  */
22
18
  export declare function canSplitCell(state: EditorState): boolean;
23
19
  /**
@@ -11,7 +11,7 @@ import {
11
11
  widthNumber,
12
12
  withWidthNumber
13
13
  } from "../model/format.js";
14
- import { transactionAllowed } from "../schema/guards.js";
14
+ import { guardedCommand } from "../schema/guards.js";
15
15
  import { inheritCellAttrs } from "./format.js";
16
16
  import { cellWidthForGridCol, gridSpanWidth, tableGridCols } from "./widths.js";
17
17
  function tableAfter(tr, tableStart) {
@@ -24,13 +24,13 @@ function cellAt(rect, row, col) {
24
24
  const pos = rect.map.map[row * rect.map.width + col];
25
25
  return pos == null ? null : rect.table.nodeAt(pos);
26
26
  }
27
+ var merging = guardedCommand(buildMergeCellsTransaction);
28
+ var splitting = guardedCommand(buildSplitCellTransaction);
27
29
  function canMergeCells(state) {
28
- const tr = buildMergeCellsTransaction(state);
29
- return tr !== null && transactionAllowed(tr, state);
30
+ return merging(state);
30
31
  }
31
32
  function canSplitCell(state) {
32
- const tr = buildSplitCellTransaction(state);
33
- return tr !== null && transactionAllowed(tr, state);
33
+ return splitting(state);
34
34
  }
35
35
  function coveredWidthSum(rect, type) {
36
36
  let sum = 0;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@portone/docx-editor",
3
- "version": "0.2.1",
3
+ "version": "0.3.0",
4
4
  "description": "A simple DOCX editor for React, built directly on OOXML.",
5
5
  "license": "Apache-2.0",
6
6
  "type": "module",
@@ -107,17 +107,21 @@
107
107
  "build:demo": "vite build --config demo/vite.config.ts",
108
108
  "dev:site": "pnpm --filter @portone/docx-editor-site dev",
109
109
  "build:site": "pnpm --filter @portone/docx-editor-site build",
110
- "check": "pnpm lint && pnpm typecheck && pnpm test",
110
+ "check": "pnpm lint && pnpm typecheck && pnpm test && pnpm test:fixtures && pnpm test:site-release && pnpm check:demo-library",
111
111
  "typecheck": "tsc --noEmit && tsc --noEmit -p e2e && tsc --noEmit -p demo && pnpm --filter @portone/docx-editor-site typecheck",
112
112
  "lint": "pnpm biome check . --diagnostic-level=error",
113
113
  "test": "vitest run",
114
+ "test:fixtures": "node --test scripts/sanitize-fixture.test.mjs",
114
115
  "test:package": "vitest run --dir packaging --no-file-parallelism",
115
116
  "verify:package": "node scripts/verify-package.mjs",
117
+ "check:demo-library": "node scripts/demo-library-pin.mjs",
118
+ "pin:demo-library": "node scripts/demo-library-pin.mjs --write",
116
119
  "api:update": "pnpm build && node scripts/api-report.mjs --local",
117
120
  "spec": "node scripts/index-ooxml-spec.mjs",
118
121
  "changeset": "changeset",
119
122
  "changeset:version": "changeset version",
120
- "test:e2e": "playwright test"
123
+ "test:e2e": "playwright test",
124
+ "test:site-release": "node --test scripts/site-release.test.mjs"
121
125
  },
122
126
  "types": "./dist/index.d.ts"
123
127
  }
@@ -1,7 +0,0 @@
1
- /** Declares a part an export adds in `[Content_Types].xml`, leaving the original text as it came. */
2
- /**
3
- * The content types part with an override for this part, or null when it already declares one.
4
- * `current` is the part as an earlier addition in the same export left it, so that two additions
5
- * do not each write over the other's declaration.
6
- */
7
- export declare function withContentType(parts: Map<string, Uint8Array>, partPath: string, contentType: string, current: Uint8Array | undefined): Uint8Array | null;
@@ -1,38 +0,0 @@
1
- // src/docx/comments/contentTypes.ts
2
- import { DocxExportError } from "../../ooxml/errors.js";
3
- import { decodeUtf8, encodeUtf8 } from "../../ooxml/xml.js";
4
- import { CONTENT_TYPES_PATH } from "./constants.js";
5
- var TYPES_OPEN_TAG = /<(?:[\w.-]+:)?Types\b[^>]*>/;
6
- function withContentType(parts, partPath, contentType, current) {
7
- const original = current ?? parts.get(CONTENT_TYPES_PATH);
8
- if (!original) {
9
- throw new DocxExportError(
10
- "missing-content-types",
11
- `cannot add a part to a package that has no ${CONTENT_TYPES_PATH}`
12
- );
13
- }
14
- const { text, hadBom } = decodeUtf8(original);
15
- const partName = `/${partPath}`;
16
- if (new RegExp(
17
- `<(?:[\\w.-]+:)?Override[^>]+PartName=["']${partName.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")}["']`,
18
- "i"
19
- ).test(text)) {
20
- return null;
21
- }
22
- const open = TYPES_OPEN_TAG.exec(text);
23
- if (!open) {
24
- throw new DocxExportError(
25
- "malformed-xml",
26
- `${CONTENT_TYPES_PATH} has no Types element`
27
- );
28
- }
29
- const rootName = /^<([^\s>]+)/.exec(open[0])?.[1] ?? "Types";
30
- const separator = rootName.indexOf(":");
31
- const prefix = separator < 0 ? "" : `${rootName.slice(0, separator)}:`;
32
- const declaration = `<${prefix}Override PartName="${partName}" ContentType="${contentType}"/>`;
33
- const at = open.index + open[0].length;
34
- return encodeUtf8(text.slice(0, at) + declaration + text.slice(at), hadBom);
35
- }
36
- export {
37
- withContentType
38
- };
@@ -1,206 +0,0 @@
1
- // src/docx/comments/verifying.ts
2
- import {
3
- attributeByLocalName,
4
- elementChildren,
5
- isElement,
6
- parseXml,
7
- serializeXml,
8
- W_NS
9
- } from "../../ooxml/xml.js";
10
- import { W14_NS, W15_NS } from "./constants.js";
11
- import {
12
- attributesWithin,
13
- COMMENT_ATTRIBUTES,
14
- lastBodyParagraph,
15
- readStrictCommentBody,
16
- recordedIdentity,
17
- wellFormedCommentExtension,
18
- wellFormedPerson
19
- } from "./grammar.js";
20
- import { commentReferencesIn } from "./model.js";
21
- import { commentAuthorId } from "./people.js";
22
- import { lastParagraphId } from "./reading.js";
23
- var COMMENT_IDENTITY = [
24
- "id",
25
- "author",
26
- "date",
27
- "initials"
28
- ];
29
- function sameAttributes(entry, original, names) {
30
- return names.every(
31
- (name) => attributeByLocalName(entry, name) === attributeByLocalName(original, name)
32
- );
33
- }
34
- function arrivedEntries(xml, localName, idAttr) {
35
- const entries = /* @__PURE__ */ new Map();
36
- if (xml === null) return entries;
37
- for (const el of elementChildren(parseXml(xml).documentElement)) {
38
- if (el.localName !== localName) continue;
39
- const id = attributeByLocalName(el, idAttr);
40
- if (id === null || entries.has(id)) continue;
41
- entries.set(id, { el, xml: serializeXml(el) });
42
- }
43
- return entries;
44
- }
45
- function submittedEntries(xml, namespace, localName, idAttr) {
46
- if (xml === null) return [];
47
- const entries = [];
48
- const seen = /* @__PURE__ */ new Set();
49
- for (const el of elementChildren(parseXml(xml).documentElement)) {
50
- if (el.namespaceURI !== namespace || el.localName !== localName)
51
- return null;
52
- const id = attributeByLocalName(el, idAttr);
53
- if (id === null || seen.has(id)) return null;
54
- seen.add(id);
55
- entries.push({ id, el, xml: serializeXml(el) });
56
- }
57
- return entries;
58
- }
59
- function referencedCommentIds(doc) {
60
- const ids = /* @__PURE__ */ new Set();
61
- for (const [id, comment] of commentReferencesIn(doc)) {
62
- ids.add(id);
63
- for (const reply of comment.replies) ids.add(reply.id);
64
- }
65
- return ids;
66
- }
67
- function wellFormedEntry(entry) {
68
- if (entry.namespaceURI === W_NS && entry.localName === "comment") {
69
- return attributesWithin(entry, COMMENT_ATTRIBUTES) && readStrictCommentBody(entry) !== null;
70
- }
71
- if (entry.namespaceURI === W15_NS && entry.localName === "commentEx") {
72
- return wellFormedCommentExtension(entry);
73
- }
74
- if (entry.namespaceURI === W15_NS && entry.localName === "person") {
75
- return wellFormedPerson(entry);
76
- }
77
- return false;
78
- }
79
- function withoutThreadKey(entry) {
80
- const copy = entry.cloneNode(true);
81
- if (!isElement(copy)) return serializeXml(entry);
82
- const last = lastBodyParagraph(copy);
83
- last?.removeAttributeNS(W14_NS, "paraId");
84
- return serializeXml(copy);
85
- }
86
- function threadKeyAlone(entry, original) {
87
- const before = lastParagraphId(original);
88
- const after = lastParagraphId(entry);
89
- const kept = before === null || after === before;
90
- return kept && withoutThreadKey(entry) === withoutThreadKey(original);
91
- }
92
- function entryAllowed(entry, original, authorId, editableComments, people) {
93
- if (entry.namespaceURI === W_NS && entry.localName === "comment") {
94
- const author = attributeByLocalName(entry, "author");
95
- const recorded = author === null ? null : commentAuthorId(people, author);
96
- if (original === null) return recorded === authorId;
97
- const paraId = lastParagraphId(original);
98
- if (!sameAttributes(entry, original, COMMENT_IDENTITY) || paraId !== null && lastParagraphId(entry) !== paraId) {
99
- return false;
100
- }
101
- return editableComments === "all" || recorded === null || recorded === authorId;
102
- }
103
- if (entry.namespaceURI === W15_NS && entry.localName === "commentEx") {
104
- if (original === null) return true;
105
- return sameAttributes(entry, original, ["paraId", "paraIdParent"]);
106
- }
107
- if (entry.namespaceURI === W15_NS && entry.localName === "person") {
108
- return original === null && recordedIdentity(entry) === authorId;
109
- }
110
- return false;
111
- }
112
- function commentEntries(story) {
113
- return Array.from(
114
- arrivedEntries(story.session.comments.xml, "comment", "id").values(),
115
- (entry) => entry.el
116
- );
117
- }
118
- var COMMENT_PARTS = [
119
- {
120
- namespace: W_NS,
121
- localName: "comment",
122
- idAttr: "id",
123
- xmlOf: (story) => story.session.comments.xml,
124
- pathOf: (story) => story.session.comments.partPath,
125
- referents: (story) => referencedCommentIds(story.doc)
126
- },
127
- {
128
- namespace: W15_NS,
129
- localName: "commentEx",
130
- idAttr: "paraId",
131
- xmlOf: (story) => story.session.comments.extendedXml,
132
- pathOf: (story) => story.session.comments.extendedPartPath,
133
- // Thread state stands for a comment, and it is keyed by the comment's own thread key
134
- referents: (story) => new Set(
135
- commentEntries(story).flatMap((el) => {
136
- const key = lastParagraphId(el);
137
- return key === null ? [] : [key];
138
- })
139
- )
140
- },
141
- {
142
- namespace: W15_NS,
143
- localName: "person",
144
- idAttr: "author",
145
- xmlOf: (story) => story.session.comments.people.xml,
146
- pathOf: (story) => story.session.comments.people.partPath,
147
- // An identity stands for a name somebody writes comments under
148
- referents: (story) => new Set(
149
- commentEntries(story).flatMap((el) => {
150
- const author = attributeByLocalName(el, "author");
151
- return author === null ? [] : [author];
152
- })
153
- )
154
- }
155
- ];
156
- function partKept(kind, before, after, authorId, editableComments) {
157
- const arrived = arrivedEntries(
158
- kind.xmlOf(before),
159
- kind.localName,
160
- kind.idAttr
161
- );
162
- const submitted = submittedEntries(
163
- kind.xmlOf(after),
164
- kind.namespace,
165
- kind.localName,
166
- kind.idAttr
167
- );
168
- if (submitted === null) return false;
169
- const stoodBehindNow = kind.referents(after);
170
- const people = after.session.comments.people;
171
- for (const entry of submitted) {
172
- const original = arrived.get(entry.id);
173
- if (original && original.xml === entry.xml) continue;
174
- if (!stoodBehindNow.has(entry.id)) return false;
175
- if (original && threadKeyAlone(entry.el, original.el)) continue;
176
- if (!wellFormedEntry(entry.el) || !entryAllowed(
177
- entry.el,
178
- original?.el ?? null,
179
- authorId,
180
- editableComments,
181
- people
182
- )) {
183
- return false;
184
- }
185
- }
186
- const held = new Set(submitted.map((entry) => entry.id));
187
- const stoodBehindBefore = kind.referents(before);
188
- return Array.from(arrived.keys()).every(
189
- (id) => stoodBehindBefore.has(id) || held.has(id)
190
- );
191
- }
192
- function commentPartsKept(before, after, authorId, editableComments) {
193
- for (const kind of COMMENT_PARTS) {
194
- const path = kind.pathOf(after) ?? kind.pathOf(before);
195
- if (path === null) continue;
196
- if (!partKept(kind, before, after, authorId, editableComments)) {
197
- return { ok: false, reason: "part-changed", part: path };
198
- }
199
- }
200
- return { ok: true };
201
- }
202
- export {
203
- commentPartsKept,
204
- entryAllowed,
205
- wellFormedEntry
206
- };
@@ -1,15 +0,0 @@
1
- import { type ParagraphFormat } from "../../model/format";
2
- import { type Numbering } from "../../numbering/parseNumbering";
3
- import { type StyleFormat, type StyleTable } from "./styles";
4
- import { type ParagraphFormatLayer } from "./tabStops";
5
- export interface ParagraphFormattingContext {
6
- styles: StyleTable;
7
- defaultStyleId: string | null;
8
- defaults: ParagraphFormatLayer;
9
- numbering: Numbering;
10
- }
11
- export declare const NO_PARAGRAPH_FORMATTING: ParagraphFormattingContext;
12
- /** Resolves the effective OOXML paragraph-property hierarchy for display. */
13
- export declare function effectiveParagraphFormat(pPr: unknown, context: ParagraphFormattingContext): ParagraphFormat | null;
14
- /** Resolves the run properties supplied by the paragraph style. */
15
- export declare function effectiveParagraphStyle(pPr: unknown, context: ParagraphFormattingContext): StyleFormat | undefined;
@@ -1,81 +0,0 @@
1
- // src/docx/formatting/effectiveParagraph.ts
2
- import { toParagraphFormat } from "../../model/format.js";
3
- import { mergeTabStops } from "../../model/tabStops.js";
4
- import {
5
- EMPTY_NUMBERING,
6
- levelIndentPt
7
- } from "../../numbering/parseNumbering.js";
8
- import { parsePropsXml } from "../propsXml.js";
9
- import { readParagraphFormat } from "./direct.js";
10
- import {
11
- paragraphStyleFormat
12
- } from "./styles.js";
13
- import { layerParagraphValues } from "./tabStops.js";
14
- var NO_PARAGRAPH_FORMATTING = {
15
- styles: /* @__PURE__ */ new Map(),
16
- defaultStyleId: null,
17
- defaults: {},
18
- numbering: EMPTY_NUMBERING
19
- };
20
- function numberingRef(defaults, style, direct) {
21
- let value = defaults.numbering;
22
- if (style.numbering !== void 0) value = style.numbering;
23
- if (direct.numbering !== void 0) value = direct.numbering;
24
- return value;
25
- }
26
- function numberingLayer(ref, numbering) {
27
- if (!ref) return {};
28
- const level = numbering.lists.get(ref.numId)?.levels.get(ref.ilvl);
29
- if (!level) return {};
30
- const indent = levelIndentPt(level.indent);
31
- const leadingIndentPt = indent.startPt;
32
- const implicitHangingStop = leadingIndentPt !== null && indent.textIndentPt !== null && indent.textIndentPt < 0 ? [{ positionPt: leadingIndentPt, align: "start" }] : [];
33
- return {
34
- tabStops: [...implicitHangingStop, ...level.tabStops ?? []]
35
- };
36
- }
37
- function withImplicitHangingStop(format) {
38
- const leadingIndentPt = format?.indentStartPt ?? format?.indentLeftPt;
39
- if (format?.textIndentPt === void 0 || format.textIndentPt >= 0 || leadingIndentPt === void 0) {
40
- return format;
41
- }
42
- const implicit = {
43
- positionPt: leadingIndentPt,
44
- align: "start"
45
- };
46
- return {
47
- ...format,
48
- tabStops: mergeTabStops([implicit], format.tabStops ?? [])
49
- };
50
- }
51
- function directLayer(pPr) {
52
- if (typeof pPr !== "string") return {};
53
- return readParagraphFormat(parsePropsXml(pPr)) ?? {};
54
- }
55
- function styleFor(pPr, context) {
56
- return paragraphStyleFormat(pPr, context.styles, context.defaultStyleId);
57
- }
58
- function effectiveParagraphFormat(pPr, context) {
59
- const direct = directLayer(pPr);
60
- const style = styleFor(pPr, context)?.paragraph ?? {};
61
- const level = numberingLayer(
62
- numberingRef(context.defaults, style, direct),
63
- context.numbering
64
- );
65
- const layered = [level, style, direct].reduce(
66
- layerParagraphValues,
67
- context.defaults
68
- );
69
- const format = toParagraphFormat(layered);
70
- return withImplicitHangingStop(
71
- format !== null && Object.keys(format).length === 0 ? null : format
72
- );
73
- }
74
- function effectiveParagraphStyle(pPr, context) {
75
- return styleFor(pPr, context);
76
- }
77
- export {
78
- NO_PARAGRAPH_FORMATTING,
79
- effectiveParagraphFormat,
80
- effectiveParagraphStyle
81
- };
@@ -1,67 +0,0 @@
1
- /**
2
- * Handles the XML fragments that carry formatting, such as `<w:rPr>`, `<w:pPr>`, and `<w:tcPr>`.
3
- *
4
- * A fragment is never rebuilt: only the one child a job names is sliced out and swapped, so the
5
- * rest (borders, shading, margins) stays as the original text wrote it. OOXML lays down the order
6
- * of the children, so the spot to insert a child that was not there is found by that same order.
7
- */
8
- export interface PropsChild {
9
- /** The name with its namespace prefix stripped off (e.g. `gridSpan`) */
10
- name: string;
11
- /** This child's original XML fragment exactly as it was */
12
- xml: string;
13
- /**
14
- * Whatever stood between the child before this one and this one: line breaks a producer laid
15
- * out, comments, anything that is not an element. Carried so that rewriting one child does not
16
- * quietly drop the rest of what the fragment said. Absent rather than empty when nothing did.
17
- */
18
- before?: string;
19
- }
20
- export interface Props {
21
- /** The opening tag name exactly as written (e.g. `w:tcPr`) */
22
- tag: string;
23
- attrs: string | null;
24
- children: PropsChild[];
25
- /** The same, for what stood between the last child and the closing tag */
26
- tail?: string;
27
- }
28
- /** The order the children are laid out in under `w:rPr` (CT_RPr) */
29
- export declare const RUN_PR_ORDER: readonly string[];
30
- /** The order the children are laid out in under `w:pPr` (CT_PPr) */
31
- export declare const P_PR_ORDER: readonly string[];
32
- /** The order the children are laid out in under `w:tcPr` (CT_TcPr) */
33
- export declare const TC_PR_ORDER: readonly string[];
34
- /** The conventional order of children under `w:trPr` (CT_TrPr). */
35
- export declare const TR_PR_ORDER: readonly string[];
36
- /** The order the children are laid out in under `w:tblPr` (CT_TblPr) */
37
- export declare const TBL_PR_ORDER: readonly string[];
38
- /**
39
- * What stood inside a single element, and "" for one that stood empty or cannot be made out.
40
- *
41
- * The opening tag is read rather than scanned for, so a `>` inside an attribute value does not
42
- * pass for the end of it.
43
- */
44
- export declare function innerXml(xml: string): string;
45
- /**
46
- * Splits a formatting fragment into its opening tag and its list of children.
47
- * null if its shape cannot be made out (in which case leaving the original untouched is the safe move).
48
- */
49
- export declare function parseProps(xml: string): Props | null;
50
- /**
51
- * With nothing to say, the formatting fragment itself is not written. A fragment holding only
52
- * whitespace says nothing; one holding a comment does, so it is written back.
53
- */
54
- export declare function renderProps(props: Props): string;
55
- /**
56
- * Replaces a single child with new XML.
57
- * A null `xml` removes that child. A child that was not there goes into the spot the order calls for.
58
- */
59
- export declare function setPropsChild(props: Props, name: string, xml: string | null, order: readonly string[]): Props;
60
- export declare function propsChild(children: PropsChild[], name: string): PropsChild | undefined;
61
- /**
62
- * Reads a single formatting fragment into an element.
63
- *
64
- * A fragment carries no namespace declarations, so they are put back on as it is wrapped.
65
- * null if its shape cannot be made out, in which case the caller leaves the display values alone.
66
- */
67
- export declare function parsePropsXml(xml: string): Element | null;
@@ -1,14 +0,0 @@
1
- /**
2
- * Keeping one content control from going out twice under the same name.
3
- *
4
- * A control cannot cross a paragraph, so splitting a paragraph in the middle of one leaves that
5
- * same control standing in two, and dropping unmarked text into the middle of one breaks it in
6
- * two within the paragraph. Each piece then writes a `w:sdt` of its own (see `docx/sdt` for what
7
- * a copy must not carry along).
8
- *
9
- * A document nobody broke apart comes back node for node as it was, which is what keeps an
10
- * unedited block going out as its original XML.
11
- */
12
- import { type Node as PMNode } from "prosemirror-model";
13
- /** The document with every copy of a control opening under a name of its own */
14
- export declare function withUniqueControls(doc: PMNode): PMNode;
@@ -1,62 +0,0 @@
1
- // src/docx/uniqueControls.ts
2
- import { Fragment } from "prosemirror-model";
3
- import { docxSchema } from "../schema/index.js";
4
- import { copiedControlPrefix, newControlId } from "./sdt.js";
5
- function sdtMarkOf(node) {
6
- return node.marks.find((mark) => mark.type === docxSchema.marks.sdt) ?? null;
7
- }
8
- function controlName(mark) {
9
- const key = mark.attrs.sdtKey;
10
- const prefix = mark.attrs.sdtPrefix;
11
- return `${typeof key === "number" ? key : 0} ${typeof prefix === "string" ? prefix : ""}`;
12
- }
13
- function copiedMark(mark) {
14
- const prefix = mark.attrs.sdtPrefix;
15
- if (typeof prefix !== "string") return mark;
16
- return mark.type.create({
17
- ...mark.attrs,
18
- sdtPrefix: copiedControlPrefix(prefix, newControlId())
19
- });
20
- }
21
- function claim(mark, written) {
22
- const name = controlName(mark);
23
- const copy = written.has(name) ? copiedMark(mark) : null;
24
- written.add(name);
25
- return { mark, copy };
26
- }
27
- function rewriteParagraph(paragraph, written) {
28
- const inline = [];
29
- let running = null;
30
- let renamed = false;
31
- paragraph.forEach((child) => {
32
- const mark = sdtMarkOf(child);
33
- if (!mark) {
34
- running = null;
35
- inline.push(child);
36
- return;
37
- }
38
- const control = running?.mark.eq(mark) ? running : claim(mark, written);
39
- running = control;
40
- if (!control.copy) {
41
- inline.push(child);
42
- return;
43
- }
44
- renamed = true;
45
- inline.push(
46
- child.mark(control.copy.addToSet(mark.removeFromSet(child.marks)))
47
- );
48
- });
49
- return renamed ? paragraph.copy(Fragment.fromArray(inline)) : paragraph;
50
- }
51
- function rewriteBlock(node, written) {
52
- if (node.type.name === "paragraph") return rewriteParagraph(node, written);
53
- if (node.childCount === 0) return node;
54
- const children = node.children.map((child) => rewriteBlock(child, written));
55
- return children.every((child, index) => child === node.child(index)) ? node : node.copy(Fragment.fromArray(children));
56
- }
57
- function withUniqueControls(doc) {
58
- return rewriteBlock(doc, /* @__PURE__ */ new Set());
59
- }
60
- export {
61
- withUniqueControls
62
- };
@@ -1,5 +0,0 @@
1
- /** Keeps identifiers from the opened Comments parts reserved for the lifetime of the editor state. */
2
- import { type EditorState, Plugin } from "prosemirror-state";
3
- export declare function commentReservations(ids: Iterable<string>, paraIds: Iterable<string>): Plugin;
4
- export declare function reservedCommentIds(state: EditorState): ReadonlySet<string>;
5
- export declare function reservedCommentParaIds(state: EditorState): ReadonlySet<string>;
@@ -1,26 +0,0 @@
1
- // src/editor/plugins/commentReservations.ts
2
- import { Plugin, PluginKey } from "prosemirror-state";
3
- var commentReservationsKey = new PluginKey(
4
- "docxCommentReservations"
5
- );
6
- function commentReservations(ids, paraIds) {
7
- const reserved = { ids: new Set(ids), paraIds: new Set(paraIds) };
8
- return new Plugin({
9
- key: commentReservationsKey,
10
- state: {
11
- init: () => reserved,
12
- apply: (_transaction, value) => value
13
- }
14
- });
15
- }
16
- function reservedCommentIds(state) {
17
- return commentReservationsKey.getState(state)?.ids ?? /* @__PURE__ */ new Set();
18
- }
19
- function reservedCommentParaIds(state) {
20
- return commentReservationsKey.getState(state)?.paraIds ?? /* @__PURE__ */ new Set();
21
- }
22
- export {
23
- commentReservations,
24
- reservedCommentIds,
25
- reservedCommentParaIds
26
- };