@portone/docx-editor 0.3.0 → 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 (90) hide show
  1. package/CHANGELOG.md +46 -0
  2. package/dist/DocxEditor.js +1 -0
  3. package/dist/core.d.ts +1 -1
  4. package/dist/docx/comments/writing.js +14 -8
  5. package/dist/docx/exportDocx.js +20 -4
  6. package/dist/docx/formatting/attrs.d.ts +20 -2
  7. package/dist/docx/formatting/attrs.js +57 -2
  8. package/dist/docx/formatting/context.d.ts +10 -2
  9. package/dist/docx/formatting/context.js +23 -5
  10. package/dist/docx/formatting/resolve.d.ts +10 -4
  11. package/dist/docx/formatting/resolve.js +31 -11
  12. package/dist/docx/formatting/styles.d.ts +25 -2
  13. package/dist/docx/formatting/styles.js +84 -3
  14. package/dist/docx/hyperlink.d.ts +14 -4
  15. package/dist/docx/hyperlink.js +4 -1
  16. package/dist/docx/importDocx.js +46 -37
  17. package/dist/docx/importTable.d.ts +2 -2
  18. package/dist/docx/importTable.js +52 -55
  19. package/dist/docx/invariants.js +26 -13
  20. package/dist/docx/newLists.d.ts +30 -0
  21. package/dist/docx/newLists.js +24 -1
  22. package/dist/docx/numberingPlanner.d.ts +6 -3
  23. package/dist/docx/numberingPlanner.js +38 -7
  24. package/dist/docx/session.d.ts +1 -1
  25. package/dist/docx/session.js +11 -1
  26. package/dist/docx/tableFormatting/conditions.d.ts +76 -0
  27. package/dist/docx/tableFormatting/conditions.js +196 -0
  28. package/dist/docx/tableFormatting/editing.d.ts +7 -3
  29. package/dist/docx/tableFormatting/editing.js +4 -5
  30. package/dist/docx/tableFormatting/reading.d.ts +49 -19
  31. package/dist/docx/tableFormatting/reading.js +109 -35
  32. package/dist/docx/tableFormatting.d.ts +1 -0
  33. package/dist/docx/tableFormatting.js +1 -0
  34. package/dist/docx/tableTemplate.js +12 -12
  35. package/dist/editor/commands/formatting/propertyCommands.js +6 -1
  36. package/dist/editor/commands/listCommands.d.ts +6 -3
  37. package/dist/editor/commands/listCommands.js +73 -28
  38. package/dist/editor/commands/paragraphCommands.js +6 -1
  39. package/dist/editor/createEditor.js +1 -1
  40. package/dist/editor/editorDocument.d.ts +7 -6
  41. package/dist/editor/editorDocument.js +18 -6
  42. package/dist/editor/externalClipboard.d.ts +13 -2
  43. package/dist/editor/externalClipboard.js +64 -34
  44. package/dist/editor/paragraphEdits.d.ts +16 -1
  45. package/dist/editor/paragraphEdits.js +13 -5
  46. package/dist/editor/paragraphPlacement.d.ts +11 -0
  47. package/dist/editor/paragraphPlacement.js +18 -0
  48. package/dist/editor/plugins/imagePaste.js +7 -4
  49. package/dist/editor/plugins/numberingDecorations.d.ts +10 -4
  50. package/dist/editor/plugins/numberingDecorations.js +43 -2
  51. package/dist/editor/plugins/paragraphDisplay.js +9 -3
  52. package/dist/editor/plugins/tableDisplay.js +19 -5
  53. package/dist/model/format.d.ts +50 -0
  54. package/dist/model/format.js +65 -0
  55. package/dist/numbering/listRegistry.d.ts +37 -0
  56. package/dist/numbering/listRegistry.js +112 -0
  57. package/dist/numbering/listTemplate.d.ts +26 -17
  58. package/dist/numbering/listTemplate.js +66 -20
  59. package/dist/numbering/markers.d.ts +15 -6
  60. package/dist/numbering/markers.js +26 -59
  61. package/dist/numbering/parseNumbering.d.ts +70 -5
  62. package/dist/numbering/parseNumbering.js +100 -26
  63. package/dist/numbering/spellers.d.ts +15 -0
  64. package/dist/numbering/spellers.js +96 -0
  65. package/dist/numbering/writeNumbering.d.ts +5 -3
  66. package/dist/numbering/writeNumbering.js +15 -15
  67. package/dist/ooxml/conformance.d.ts +28 -0
  68. package/dist/ooxml/conformance.js +20 -0
  69. package/dist/ooxml/errors.d.ts +5 -5
  70. package/dist/ooxml/names.d.ts +9 -0
  71. package/dist/ooxml/names.js +8 -1
  72. package/dist/ooxml/partSplice.d.ts +1 -1
  73. package/dist/ooxml/partSplice.js +10 -3
  74. package/dist/ooxml/xml.d.ts +8 -9
  75. package/dist/ooxml/xml.js +6 -6
  76. package/dist/page/PageGuides.d.ts +1 -1
  77. package/dist/page/PageGuides.js +0 -13
  78. package/dist/page/pageLayout.d.ts +0 -10
  79. package/dist/page/pageLayout.js +3 -10
  80. package/dist/page/usePageLayout.d.ts +0 -7
  81. package/dist/page/usePageLayout.js +2 -9
  82. package/dist/schema/attrRoles.js +8 -1
  83. package/dist/schema/docxSchema.js +32 -3
  84. package/dist/styles/classNames.d.ts +13 -2
  85. package/dist/styles/classNames.js +13 -2
  86. package/dist/styles.css +16 -18
  87. package/dist/table/cellFormatting.js +1 -2
  88. package/dist/table/gridBorders.d.ts +11 -15
  89. package/dist/table/gridBorders.js +32 -18
  90. package/package.json +1 -1
@@ -1,6 +1,10 @@
1
1
  // src/docx/tableFormatting/reading.ts
2
+ import {
3
+ TABLE_STYLE_CONDITIONS
4
+ } from "../../model/format.js";
2
5
  import { parsePropsXml } from "../../ooxml/props.js";
3
6
  import {
7
+ ST_DecimalNumber,
4
8
  ST_MeasurementOrPercent,
5
9
  ST_SignedTwipsMeasure,
6
10
  ST_TwipsMeasure
@@ -8,7 +12,6 @@ import {
8
12
  import {
9
13
  ALIGN_BY_JC,
10
14
  borderLineCss,
11
- borderLineOfCss,
12
15
  borderSide,
13
16
  childValue,
14
17
  isOn,
@@ -109,30 +112,89 @@ var NO_BORDER_DEFAULTS = {
109
112
  left: null,
110
113
  right: null
111
114
  };
112
- function gridEdgesOf(rect, grid) {
115
+ var NO_CELL_DEFAULTS = {
116
+ borders: NO_BORDER_DEFAULTS,
117
+ margins: NO_CELL_MARGINS,
118
+ background: null,
119
+ verticalAlign: null,
120
+ placement: { tableStyleId: null, conditions: [] }
121
+ };
122
+ var NO_BAND_SIZES = { row: null, col: null };
123
+ function bandSize(tblPr, name) {
124
+ const count = ST_DecimalNumber.parse(childValue(tblPr, name));
125
+ return count !== null && count > 0 ? count : null;
126
+ }
127
+ function readBandSizes(tblPr) {
128
+ if (!tblPr) return NO_BAND_SIZES;
129
+ return {
130
+ row: bandSize(tblPr, "tblStyleRowBandSize"),
131
+ col: bandSize(tblPr, "tblStyleColBandSize")
132
+ };
133
+ }
134
+ function layerBandSizes(style, over) {
135
+ return { row: over.row ?? style.row, col: over.col ?? style.col };
136
+ }
137
+ var NO_CELL_STYLE_BORDERS = {
138
+ top: null,
139
+ bottom: null,
140
+ left: null,
141
+ right: null
142
+ };
143
+ var NO_CELL_STYLE_FORMAT = {
144
+ background: null,
145
+ borders: NO_CELL_STYLE_BORDERS,
146
+ inside: NO_INSIDE_BORDERS,
147
+ margins: NO_CELL_MARGINS,
148
+ verticalAlign: null
149
+ };
150
+ var NO_TABLE_STYLE_CONDITIONS = {};
151
+ function conditionBorders(tcBorders, table) {
113
152
  return {
114
- top: rect.top === 0,
115
- bottom: rect.bottom === grid.rows,
116
- left: rect.left === 0,
117
- right: rect.right === grid.cols
153
+ top: borderSide(tcBorders, "top") ?? table.borderTop ?? null,
154
+ bottom: borderSide(tcBorders, "bottom") ?? table.borderBottom ?? null,
155
+ left: borderSide(tcBorders, "left") ?? borderSide(tcBorders, "start") ?? table.borderLeft ?? null,
156
+ right: borderSide(tcBorders, "right") ?? borderSide(tcBorders, "end") ?? table.borderRight ?? null
118
157
  };
119
158
  }
120
- function cellBorderDefaults(edges, outer, inside) {
159
+ function readCellStyleFormat(tcPr, tblPr) {
160
+ const table = readTableFormat(tblPr) ?? {};
161
+ const tcBorders = tcPr ? childByLocalName(tcPr, "tcBorders") : null;
121
162
  return {
122
- top: borderLineOfCss(
123
- edges.top ? outer?.borderTop ?? null : inside.horizontal
124
- ),
125
- bottom: borderLineOfCss(
126
- edges.bottom ? outer?.borderBottom ?? null : inside.horizontal
127
- ),
128
- left: borderLineOfCss(
129
- edges.left ? outer?.borderLeft ?? null : inside.vertical
130
- ),
131
- right: borderLineOfCss(
132
- edges.right ? outer?.borderRight ?? null : inside.vertical
133
- )
163
+ background: (tcPr ? shadingOf(tcPr) : null) ?? table.background ?? null,
164
+ borders: conditionBorders(tcBorders, table),
165
+ inside: layerInsideBorders(readInsideBorders(tblPr), {
166
+ horizontal: borderSide(tcBorders, "insideH"),
167
+ vertical: borderSide(tcBorders, "insideV")
168
+ }),
169
+ margins: readCellMarginsOf(tcPr, "tcMar"),
170
+ verticalAlign: tcPr ? cellVerticalAlignOf(tcPr) : null
134
171
  };
135
172
  }
173
+ function layerCellStyleBorders(base, over) {
174
+ return {
175
+ top: over.top ?? base.top,
176
+ bottom: over.bottom ?? base.bottom,
177
+ left: over.left ?? base.left,
178
+ right: over.right ?? base.right
179
+ };
180
+ }
181
+ function layerCellStyleFormat(base, over) {
182
+ return {
183
+ background: over.background ?? base.background,
184
+ borders: layerCellStyleBorders(base.borders, over.borders),
185
+ inside: layerInsideBorders(base.inside, over.inside),
186
+ margins: layerCellMargins(base.margins, over.margins),
187
+ verticalAlign: over.verticalAlign ?? base.verticalAlign
188
+ };
189
+ }
190
+ function cellConditionsOf(conditions) {
191
+ const cells = {};
192
+ for (const type of TABLE_STYLE_CONDITIONS) {
193
+ const format = conditions[type];
194
+ if (format) cells[type] = format.cell;
195
+ }
196
+ return cells;
197
+ }
136
198
  function tblStyleIdOf(tblPr) {
137
199
  return tblPr ? childValue(tblPr, "tblStyle") : null;
138
200
  }
@@ -178,6 +240,9 @@ var CELL_VERTICAL_ALIGN_BY_VAL = {
178
240
  center: "center",
179
241
  bottom: "bottom"
180
242
  };
243
+ function cellVerticalAlignOf(tcPr) {
244
+ return CELL_VERTICAL_ALIGN_BY_VAL[childValue(tcPr, "vAlign") ?? ""] ?? null;
245
+ }
181
246
  function readCellPadding(tcPr, margins) {
182
247
  const padding = layerCellMargins(margins, readCellMarginsOf(tcPr, "tcMar"));
183
248
  const format = {};
@@ -187,24 +252,26 @@ function readCellPadding(tcPr, margins) {
187
252
  if (padding.leftPt !== null) format.paddingLeftPt = padding.leftPt;
188
253
  return format;
189
254
  }
190
- function readCellFormat(tcPr, defaults, margins = NO_CELL_MARGINS) {
255
+ function readCellFormat(tcPr, defaults = NO_CELL_DEFAULTS) {
191
256
  const borders = tcPr ? childByLocalName(tcPr, "tcBorders") : null;
257
+ const lines = defaults.borders;
192
258
  const format = {};
193
- const top = borderSide(borders, "top") ?? borderLineCss(defaults.top);
259
+ const top = borderSide(borders, "top") ?? borderLineCss(lines.top);
194
260
  if (top) format.borderTop = top;
195
- const bottom = borderSide(borders, "bottom") ?? borderLineCss(defaults.bottom);
261
+ const bottom = borderSide(borders, "bottom") ?? borderLineCss(lines.bottom);
196
262
  if (bottom) format.borderBottom = bottom;
197
- const left = borderSide(borders, "left") ?? borderSide(borders, "start") ?? borderLineCss(defaults.left);
263
+ const left = borderSide(borders, "left") ?? borderSide(borders, "start") ?? borderLineCss(lines.left);
198
264
  if (left) format.borderLeft = left;
199
- const right = borderSide(borders, "right") ?? borderSide(borders, "end") ?? borderLineCss(defaults.right);
265
+ const right = borderSide(borders, "right") ?? borderSide(borders, "end") ?? borderLineCss(lines.right);
200
266
  if (right) format.borderRight = right;
201
- if (tcPr) {
202
- const background = shadingOf(tcPr);
203
- if (background) format.background = background;
204
- const verticalAlign = CELL_VERTICAL_ALIGN_BY_VAL[childValue(tcPr, "vAlign") ?? ""];
205
- if (verticalAlign) format.verticalAlign = verticalAlign;
206
- }
207
- const padded = { ...format, ...readCellPadding(tcPr, margins) };
267
+ const background = (tcPr ? shadingOf(tcPr) : null) ?? defaults.background;
268
+ if (background) format.background = background;
269
+ const verticalAlign = (tcPr ? cellVerticalAlignOf(tcPr) : null) ?? defaults.verticalAlign;
270
+ if (verticalAlign) format.verticalAlign = verticalAlign;
271
+ const padded = {
272
+ ...format,
273
+ ...readCellPadding(tcPr, defaults.margins)
274
+ };
208
275
  return Object.keys(padded).length > 0 ? padded : null;
209
276
  }
210
277
  function insideBordersOf(tblPr) {
@@ -215,23 +282,30 @@ function cellMarginsOf(tblPr) {
215
282
  const el = tblPr === null ? null : parsePropsXml(tblPr);
216
283
  return readCellMarginsOf(el, "tblCellMar");
217
284
  }
218
- function readCellProps(tcPr, defaults, margins = NO_CELL_MARGINS) {
285
+ function readCellProps(tcPr, defaults = NO_CELL_DEFAULTS) {
219
286
  const el = tcPr === null ? null : parsePropsXml(tcPr);
220
- return readCellFormat(el, defaults, margins);
287
+ return readCellFormat(el, defaults);
221
288
  }
222
289
  export {
290
+ NO_BAND_SIZES,
223
291
  NO_BORDER_DEFAULTS,
292
+ NO_CELL_DEFAULTS,
224
293
  NO_CELL_MARGINS,
294
+ NO_CELL_STYLE_FORMAT,
225
295
  NO_INSIDE_BORDERS,
226
- cellBorderDefaults,
296
+ NO_TABLE_STYLE_CONDITIONS,
297
+ cellConditionsOf,
227
298
  cellMarginsOf,
228
- gridEdgesOf,
229
299
  insideBordersOf,
300
+ layerBandSizes,
230
301
  layerCellMargins,
302
+ layerCellStyleFormat,
231
303
  layerInsideBorders,
304
+ readBandSizes,
232
305
  readCellFormat,
233
306
  readCellMarginsOf,
234
307
  readCellProps,
308
+ readCellStyleFormat,
235
309
  readGridCols,
236
310
  readInsideBorders,
237
311
  readRowFormat,
@@ -1,2 +1,3 @@
1
+ export * from "./tableFormatting/conditions";
1
2
  export * from "./tableFormatting/editing";
2
3
  export * from "./tableFormatting/reading";
@@ -1,3 +1,4 @@
1
1
  // src/docx/tableFormatting.ts
2
+ export * from "./tableFormatting/conditions.js";
2
3
  export * from "./tableFormatting/editing.js";
3
4
  export * from "./tableFormatting/reading.js";
@@ -5,9 +5,8 @@ import { orderedElement, parsePropsXml } from "../ooxml/props.js";
5
5
  import { docxSchema } from "../schema/index.js";
6
6
  import { A4_PORTRAIT, bodyWidth } from "./pageGeometry.js";
7
7
  import {
8
- cellBorderDefaults,
9
- gridEdgesOf,
10
- NO_CELL_MARGINS,
8
+ cellDefaultsFor,
9
+ NO_CELL_SOURCES,
11
10
  readCellFormat,
12
11
  readInsideBorders,
13
12
  readTableFormat,
@@ -81,7 +80,7 @@ function cellTemplate(width, defaults) {
81
80
  tcPr,
82
81
  tcW: readTableWidth(el, "tcW"),
83
82
  // A new table writes no `tblCellMar`, so its cells take their padding from the stylesheet
84
- format: readCellFormat(el, defaults, NO_CELL_MARGINS)
83
+ format: readCellFormat(el, defaults)
85
84
  };
86
85
  }
87
86
  function cellNode(props) {
@@ -109,17 +108,18 @@ function createTableNode(rows, cols, geometry = A4_PORTRAIT) {
109
108
  const gridCols = evenGridCols(cols, total);
110
109
  const tblPr = tablePropsXml(total);
111
110
  const tblPrEl = parsePropsXml(tblPr);
112
- const inside = readInsideBorders(tblPrEl);
113
111
  const outer = readTableFormat(tblPrEl);
112
+ const sources = {
113
+ ...NO_CELL_SOURCES,
114
+ outer,
115
+ inside: readInsideBorders(tblPrEl)
116
+ };
114
117
  const cellAt = (row, col) => cellTemplate(
115
118
  gridCols[col],
116
- cellBorderDefaults(
117
- gridEdgesOf(
118
- { top: row, bottom: row + 1, left: col, right: col + 1 },
119
- { rows, cols }
120
- ),
121
- outer,
122
- inside
119
+ cellDefaultsFor(
120
+ { top: row, bottom: row + 1, left: col, right: col + 1 },
121
+ { rows, cols },
122
+ sources
123
123
  )
124
124
  );
125
125
  return docxSchema.nodes.table.create(
@@ -12,6 +12,7 @@ import {
12
12
  import { docxSchema } from "../../../schema/index.js";
13
13
  import { editShut, openStretches } from "../../../schema/guards.js";
14
14
  import { documentFormatting } from "../../documentStyles.js";
15
+ import { paragraphPlacementAt } from "../../paragraphPlacement.js";
15
16
  import {
16
17
  activePieces,
17
18
  caretPiece,
@@ -21,7 +22,11 @@ import {
21
22
  function editedMark(state, target, edit) {
22
23
  const context = documentFormatting(state);
23
24
  const rPr = text(target.mark?.attrs.rPr);
24
- const paragraph = resolveParagraph(target.pPr, context);
25
+ const paragraph = resolveParagraph(
26
+ target.pPr,
27
+ context,
28
+ paragraphPlacementAt(state.doc, target.from)
29
+ );
25
30
  const next = editRunProps(
26
31
  { rPr, format: target.format },
27
32
  inheritedRunFormat(rPr, paragraph, context),
@@ -4,7 +4,8 @@
4
4
  * All they do is change a paragraph's place in a list (its numbering id and level).
5
5
  * Editing the formatting fragments belongs to `docx/paraProps`, and the list's appearance
6
6
  * belongs to `numbering/`.
7
- * The definition of a new list is not put into the document; numbering.xml picks it up on export.
7
+ * Starting a list records its definition on the document node in the same transaction, and the
8
+ * export writes that definition into numbering.xml.
8
9
  */
9
10
  import type { Node as PMNode } from "prosemirror-model";
10
11
  import type { Command, EditorState } from "prosemirror-state";
@@ -24,6 +25,8 @@ export declare function listLevelChange(numbering: Numbering, node: PMNode, delt
24
25
  export declare const increaseListLevel: Command;
25
26
  /** Moves a list item one level back up, which is not the paragraph's own indent. What Shift+Tab does */
26
27
  export declare const decreaseListLevel: Command;
28
+ /** Every numbering id a paragraph of this document wears */
29
+ export declare function numIdsIn(doc: PMNode): Set<number>;
27
30
  /**
28
31
  * Takes the selected paragraphs out of the list.
29
32
  * Only the hanging indentation the marker sat in goes with it; an indentation the paragraph had
@@ -31,8 +34,8 @@ export declare const decreaseListLevel: Command;
31
34
  */
32
35
  export declare const removeFromList: Command;
33
36
  /**
34
- * The kind of list the selected paragraphs belong to. Null when they are not a list or the kinds
35
- * are mixed.
37
+ * The kind of list the selected paragraphs belong to. Null when they are not a list, when nothing
38
+ * defines the list they are in, or when the kinds are mixed.
36
39
  * It reads the paragraphs a lock leaves open, the same ones `editParagraphs` writes to: counting a
37
40
  * locked paragraph that stays out of the list would keep the answer mixed, so the button would make
38
41
  * a list a second time instead of taking it off.
@@ -5,12 +5,18 @@ import {
5
5
  } from "../../docx/paraProps.js";
6
6
  import { toParagraphFormat } from "../../model/format.js";
7
7
  import {
8
+ listsWorn,
9
+ NEW_LISTS_ATTR,
10
+ newListsValue
11
+ } from "../../numbering/listRegistry.js";
12
+ import {
13
+ allocateList,
8
14
  listFor,
9
- listKindOf,
10
15
  MAX_ILVL,
11
- nextNumId
16
+ templateList
12
17
  } from "../../numbering/listTemplate.js";
13
18
  import { docxSchema } from "../../schema/index.js";
19
+ import { documentFormatting } from "../documentStyles.js";
14
20
  import {
15
21
  editableParagraphs,
16
22
  editParagraphs,
@@ -24,18 +30,25 @@ import {
24
30
  function listRefOf(node) {
25
31
  return toParagraphFormat(node.attrs.format)?.numbering ?? null;
26
32
  }
27
- function changeParagraphs(state, dispatch, plan) {
28
- return editParagraphs(state, dispatch, (node) => {
29
- const change = plan(node);
30
- return change && withListNumbering(paragraphPPr(node), change);
31
- });
33
+ function changeParagraphs(state, dispatch, plan, extras = {
34
+ alongside: pruneLists(documentNumbering(state).added)
35
+ }) {
36
+ return editParagraphs(
37
+ state,
38
+ dispatch,
39
+ (node) => {
40
+ const change = plan(node);
41
+ return change && withListNumbering(paragraphPPr(node), change);
42
+ },
43
+ extras
44
+ );
32
45
  }
33
46
  function indentForLevel(numbering, node, ref) {
34
47
  const format = toParagraphFormat(node.attrs.format);
35
48
  if (format?.indentStartPt === void 0 && format?.indentLeftPt === void 0) {
36
49
  return { kind: "keep" };
37
50
  }
38
- const indent = listFor(numbering, ref.numId).levels.get(ref.ilvl)?.indent;
51
+ const indent = listFor(numbering, ref.numId)?.levels.get(ref.ilvl)?.indent;
39
52
  return indent ? { kind: "level", indent } : { kind: "keep" };
40
53
  }
41
54
  function listLevelChange(numbering, node, delta) {
@@ -58,24 +71,50 @@ function levelShift(delta) {
58
71
  }
59
72
  var increaseListLevel = levelShift(1);
60
73
  var decreaseListLevel = levelShift(-1);
61
- function usedNumIds(state, numbering) {
62
- const used = new Set(numbering.lists.keys());
63
- state.doc.descendants((node) => {
74
+ function numIdsIn(doc) {
75
+ const worn = /* @__PURE__ */ new Set();
76
+ doc.descendants((node) => {
64
77
  if (node.type !== docxSchema.nodes.paragraph) return true;
65
78
  const ref = listRefOf(node);
66
- if (ref) used.add(ref.numId);
79
+ if (ref) worn.add(ref.numId);
67
80
  return false;
68
81
  });
69
- return used;
82
+ return worn;
83
+ }
84
+ function recordLists(tr, lists) {
85
+ tr.setDocAttribute(
86
+ NEW_LISTS_ATTR,
87
+ newListsValue(listsWorn(lists, numIdsIn(tr.doc)))
88
+ );
89
+ }
90
+ function pruneLists(lists) {
91
+ return (tr) => {
92
+ if (listsWorn(lists, numIdsIn(tr.doc)) !== lists) recordLists(tr, lists);
93
+ };
70
94
  }
71
95
  function startList(kind) {
72
96
  return (state, dispatch) => {
73
97
  if (!canStartNewList(state)) return false;
74
- const numId = nextNumId(usedNumIds(state, documentNumbering(state)), kind);
75
- return changeParagraphs(state, dispatch, (node) => ({
76
- numbering: { numId, ilvl: listRefOf(node)?.ilvl ?? 0 },
77
- indent: { kind: "keep" }
78
- }));
98
+ const started = allocateList(
99
+ documentNumbering(state),
100
+ numIdsIn(state.doc),
101
+ templateList(kind)
102
+ );
103
+ return changeParagraphs(
104
+ state,
105
+ dispatch,
106
+ (node) => ({
107
+ numbering: { numId: started.numId, ilvl: listRefOf(node)?.ilvl ?? 0 },
108
+ indent: { kind: "keep" }
109
+ }),
110
+ {
111
+ formatting: {
112
+ ...documentFormatting(state),
113
+ numbering: started.numbering
114
+ },
115
+ alongside: (tr) => recordLists(tr, started.numbering.added)
116
+ }
117
+ );
79
118
  };
80
119
  }
81
120
  var removeFromList = (state, dispatch) => changeParagraphs(
@@ -84,8 +123,8 @@ var removeFromList = (state, dispatch) => changeParagraphs(
84
123
  (node) => listRefOf(node) ? { numbering: null, indent: { kind: "clearHanging" } } : null
85
124
  );
86
125
  function kindOf(numbering, ref) {
87
- const level = listFor(numbering, ref.numId).levels.get(ref.ilvl);
88
- if (!level) return listKindOf(ref.numId);
126
+ const level = listFor(numbering, ref.numId)?.levels.get(ref.ilvl);
127
+ if (!level) return null;
89
128
  return level.format === "bullet" ? "bullet" : "numbered";
90
129
  }
91
130
  function activeListKind(state) {
@@ -107,14 +146,19 @@ function isInList(state) {
107
146
  (spot) => listRefOf(spot.node) !== null
108
147
  );
109
148
  }
110
- var leaveListAtLineStart = (state, dispatch) => editParagraphs(state, dispatch, (node) => {
111
- if (!listRefOf(node)) return null;
112
- const unlisted = withListNumbering(paragraphPPr(node), {
113
- numbering: null,
114
- indent: { kind: "clearHanging" }
115
- });
116
- return unlisted && withLeftIndent(unlisted.pPr, 0);
117
- });
149
+ var leaveListAtLineStart = (state, dispatch) => editParagraphs(
150
+ state,
151
+ dispatch,
152
+ (node) => {
153
+ if (!listRefOf(node)) return null;
154
+ const unlisted = withListNumbering(paragraphPPr(node), {
155
+ numbering: null,
156
+ indent: { kind: "clearHanging" }
157
+ });
158
+ return unlisted && withLeftIndent(unlisted.pPr, 0);
159
+ },
160
+ { alongside: pruneLists(documentNumbering(state).added) }
161
+ );
118
162
  var leaveEmptyListItem = (state, dispatch) => {
119
163
  const { empty, $from } = state.selection;
120
164
  const paragraph = $from.parent;
@@ -132,6 +176,7 @@ export {
132
176
  leaveEmptyListItem,
133
177
  listLevelChange,
134
178
  listRefOf,
179
+ numIdsIn,
135
180
  removeFromList,
136
181
  toggleBulletList,
137
182
  toggleNumberedList
@@ -19,6 +19,7 @@ import {
19
19
  paragraphPPr,
20
20
  selectedParagraphs
21
21
  } from "../paragraphEdits.js";
22
+ import { paragraphPlacementAt } from "../paragraphPlacement.js";
22
23
  function alignOf(node) {
23
24
  return toParagraphFormat(node.attrs.format)?.align ?? "left";
24
25
  }
@@ -78,7 +79,11 @@ function setParagraphStyle(styleId) {
78
79
  if (styleIdOf(pPr) === styleId) return [];
79
80
  const props = withParagraphStyle(pPr, styleId);
80
81
  if (!props) return [];
81
- const paragraph = resolveParagraph(props.pPr, context);
82
+ const paragraph = resolveParagraph(
83
+ props.pPr,
84
+ context,
85
+ paragraphPlacementAt(state.doc, spot.pos)
86
+ );
82
87
  return [
83
88
  {
84
89
  spot,
@@ -112,7 +112,7 @@ function createEditorState(doc, options = {}) {
112
112
  function editorStateForSession(opened, options = {}) {
113
113
  return createEditorState(opened.doc, {
114
114
  ...options,
115
- document: editorDocumentOf(opened.session)
115
+ document: editorDocumentOf(opened.session, opened.doc)
116
116
  });
117
117
  }
118
118
  var sheetStyles = /* @__PURE__ */ new WeakMap();
@@ -7,6 +7,7 @@
7
7
  * behalf, and `editorDocumentOf` is the one place a session is read into editor values: a screen
8
8
  * and a test that open the same document hold the same values.
9
9
  */
10
+ import type { Node as PMNode } from "prosemirror-model";
10
11
  import { type EditorState, Plugin } from "prosemirror-state";
11
12
  import { type FormattingContext, type ParagraphStyleOption } from "../docx/formatting";
12
13
  import { type PageGeometry } from "../docx/pageGeometry";
@@ -22,8 +23,8 @@ export interface EditorDocument {
22
23
  /** The styles the document defines for the style picker to offer */
23
24
  readonly paragraphStyles: ParagraphStyleOption[];
24
25
  /**
25
- * Whether the document has a place (numbering.xml) to write the definition of a new list.
26
- * A state built without opening a document assumes that place exists and behaves as every
26
+ * Whether the definition of a new list has somewhere to go, which is what the commands that
27
+ * start one ask. A state built without opening a document assumes it has and behaves as every
27
28
  * state did before the question was asked.
28
29
  */
29
30
  readonly canStartNewList: boolean;
@@ -39,15 +40,15 @@ export interface EditorDocument {
39
40
  /** What a state built without an opened document answers: the same as nothing being written down */
40
41
  export declare const NO_DOCUMENT: EditorDocument;
41
42
  /** The one place an opened document is read into the values the editor holds */
42
- export declare function editorDocumentOf(session: SessionStore): EditorDocument;
43
+ export declare function editorDocumentOf(session: SessionStore, doc: PMNode): EditorDocument;
43
44
  /** The document the state was built for. `NO_DOCUMENT` for a state built without one */
44
45
  export declare function documentOf(state: EditorState): EditorDocument;
45
46
  /**
46
47
  * Holds the snapshot for the lifetime of the state.
47
48
  *
48
- * It is derived again only where a document-level edit could have been recorded, so an ordinary
49
- * edit and a selection move both leave the same object behind, allowing the sheet's style to be
50
- * cached against that identity.
49
+ * It is derived again only where a document-level edit could have been recorded - the attrs of the
50
+ * document node, which is where such an edit is written - so an ordinary edit and a selection move
51
+ * both leave the same object behind, allowing the sheet's style to be cached against that identity.
51
52
  */
52
53
  export declare function editorDocument(document: EditorDocument): Plugin<EditorDocument>;
53
54
  /** The comment ids the opened document already spent, which a new comment may not take */
@@ -5,7 +5,9 @@ import {
5
5
  NO_DOCUMENT_DEFAULTS,
6
6
  NO_FORMATTING
7
7
  } from "../docx/formatting.js";
8
+ import { canDefineNewList } from "../docx/newLists.js";
8
9
  import { A4_PORTRAIT } from "../docx/pageGeometry.js";
10
+ import { NEW_LISTS_ATTR, newListsOf } from "../numbering/listRegistry.js";
9
11
  var NO_IDS = /* @__PURE__ */ new Set();
10
12
  var NO_PARAGRAPH_STYLES = [];
11
13
  var NO_DOCUMENT = {
@@ -29,13 +31,20 @@ function reservedParaIds(session) {
29
31
  }
30
32
  return paraIds;
31
33
  }
32
- function editorDocumentOf(session) {
34
+ function formattingWithNewLists(formatting, doc) {
35
+ const added = newListsOf(doc.attrs[NEW_LISTS_ATTR]);
36
+ if (added.size === 0 && formatting.numbering.added.size === 0) {
37
+ return formatting;
38
+ }
39
+ return { ...formatting, numbering: { ...formatting.numbering, added } };
40
+ }
41
+ function editorDocumentOf(session, doc) {
33
42
  return {
34
43
  session,
35
- formatting: session.formatting,
44
+ formatting: formattingWithNewLists(session.formatting, doc),
36
45
  defaults: session.defaults,
37
46
  paragraphStyles: session.paragraphStyles,
38
- canStartNewList: session.numberingPartPath !== null,
47
+ canStartNewList: canDefineNewList(session),
39
48
  geometry: session.geometry,
40
49
  defaultTabStopPt: session.defaultTabStopPt,
41
50
  reservedCommentIds: new Set(session.comments.byId.keys()),
@@ -46,15 +55,18 @@ var editorDocumentKey = new PluginKey("docxEditorDocument");
46
55
  function documentOf(state) {
47
56
  return editorDocumentKey.getState(state) ?? NO_DOCUMENT;
48
57
  }
49
- function derive(session, _doc) {
50
- return editorDocumentOf(session);
58
+ function derived(current, doc) {
59
+ return current.session === null ? {
60
+ ...current,
61
+ formatting: formattingWithNewLists(current.formatting, doc)
62
+ } : editorDocumentOf(current.session, doc);
51
63
  }
52
64
  function editorDocument(document) {
53
65
  return new Plugin({
54
66
  key: editorDocumentKey,
55
67
  state: {
56
68
  init: () => document,
57
- apply: (tr, current, old) => current.session === null || tr.doc.attrs === old.doc.attrs ? current : derive(current.session, tr.doc)
69
+ apply: (tr, current, old) => tr.doc.attrs === old.doc.attrs ? current : derived(current, tr.doc)
58
70
  }
59
71
  });
60
72
  }
@@ -1,8 +1,19 @@
1
1
  import { Slice } from "prosemirror-model";
2
- import { type EditorState, Plugin } from "prosemirror-state";
2
+ import { type EditorState, Plugin, type Transaction } from "prosemirror-state";
3
3
  import type { EditorView } from "prosemirror-view";
4
+ import { type NewLists } from "../numbering/listRegistry";
4
5
  import type { ImageToInsert } from "./insertImage";
5
- export declare function richHtmlSlice(state: EditorState, document: Document, source: string, images?: ReadonlyMap<string, ImageToInsert>): Slice | null;
6
+ /** What a paste puts in: the content, and the definitions of the lists it started */
7
+ export interface PastedContent {
8
+ slice: Slice;
9
+ newLists: NewLists;
10
+ }
11
+ export declare function richHtmlSlice(state: EditorState, document: Document, source: string, images?: ReadonlyMap<string, ImageToInsert>): PastedContent | null;
12
+ /**
13
+ * The transaction a paste is put in with: the content, and the definitions of the lists it started
14
+ * recorded on the document node so that the export writes them out and undo takes them back.
15
+ */
16
+ export declare function withPastedContent(tr: Transaction, content: PastedContent): Transaction;
6
17
  export declare function insertRichHtml(view: EditorView, source: string): boolean;
7
18
  export declare function insertClipboardData(view: EditorView, data: {
8
19
  html?: string;