@stll/folio-core 0.53.0 → 0.54.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.
- package/dist/ai-edits/apply.js +390 -166
- package/dist/ai-edits/batch-claims.d.ts +21 -6
- package/dist/ai-edits/batch-claims.js +47 -16
- package/dist/ai-edits/headless.d.ts +20 -0
- package/dist/ai-edits/headless.js +140 -11
- package/dist/ai-edits/pending-suggestions.js +1 -1
- package/dist/ai-edits/read.d.ts +5 -3
- package/dist/ai-edits/read.js +97 -47
- package/dist/ai-edits/revisionStretches.d.ts +17 -0
- package/dist/ai-edits/revisionStretches.js +80 -0
- package/dist/ai-edits/snapshot.js +3 -2
- package/dist/ai-edits/table-cell-mutations.d.ts +3 -1
- package/dist/ai-edits/table-cell-mutations.js +2 -1
- package/dist/ai-edits/table-row-column-mutations.d.ts +6 -1
- package/dist/ai-edits/table-row-column-mutations.js +27 -10
- package/dist/compare/content-alignment.d.ts +5 -1
- package/dist/compare/content-alignment.js +39 -32
- package/dist/compare/inline-provenance.js +1 -1
- package/dist/controller/layoutPipeline.js +3 -2
- package/dist/docx/archiveInflation.d.ts +127 -0
- package/dist/docx/archiveInflation.js +181 -0
- package/dist/docx/metadataPrivacy.js +24 -1
- package/dist/docx/noteReferenceMark.d.ts +15 -0
- package/dist/docx/noteReferenceMark.js +48 -0
- package/dist/docx/paragraphParser.js +5 -3
- package/dist/docx/paragraphPropertySource.d.ts +1 -1
- package/dist/docx/paragraphPropertySource.js +3 -1
- package/dist/docx/parser.js +2 -2
- package/dist/docx/rezip.js +4 -2
- package/dist/docx/selectiveXmlPatch.d.ts +3 -1
- package/dist/docx/selectiveXmlPatch.js +81 -3
- package/dist/docx/server/boundedArchive.d.ts +8 -13
- package/dist/docx/server/boundedArchive.js +70 -59
- package/dist/docx/server/extractDocxText.d.ts +8 -2
- package/dist/docx/server/extractDocxText.js +2 -2
- package/dist/docx/server/validateDocxConformance.d.ts +1 -1
- package/dist/docx/server/validateDocxConformance.js +1 -0
- package/dist/docx/unzip.d.ts +19 -2
- package/dist/docx/unzip.js +135 -24
- package/dist/fonts/embeddedFonts.js +1 -1
- package/dist/i18n/messages/catalogs.gen.d.ts +34 -34
- package/dist/i18n/messages/catalogs.gen.js +34 -34
- package/dist/i18n/messages/messages.gen.d.ts +2 -2
- package/dist/internal/wholeStoryRevisionResolution.js +95 -25
- package/dist/layout-engine/measure/measureParagraph.js +2 -2
- package/dist/layout-engine/measure/paragraphMeasureShared.d.ts +12 -1
- package/dist/layout-engine/measure/paragraphMeasureShared.js +14 -1
- package/dist/markdown/escape.d.ts +2 -2
- package/dist/markdown/escape.js +4 -5
- package/dist/markdown/renderBlock.js +91 -25
- package/dist/markdown/renderRuns.d.ts +10 -1
- package/dist/markdown/renderRuns.js +320 -59
- package/dist/prosemirror/clearRunColor.d.ts +6 -0
- package/dist/prosemirror/clearRunColor.js +46 -0
- package/dist/prosemirror/commands/comments.js +56 -21
- package/dist/prosemirror/commands/formatPainter.js +1 -1
- package/dist/prosemirror/commands/hyperlink.js +2 -1
- package/dist/prosemirror/commands/propertyChangeScope.d.ts +3 -2
- package/dist/prosemirror/commands/propertyChangeScope.js +24 -3
- package/dist/prosemirror/commands/resolveAllTableChanges.js +46 -41
- package/dist/prosemirror/commands/resolveParagraphProperties.js +20 -6
- package/dist/prosemirror/commands/tableCellMergeResolution.d.ts +8 -1
- package/dist/prosemirror/commands/tableCellMergeResolution.js +23 -7
- package/dist/prosemirror/containerFinalParagraph.d.ts +11 -5
- package/dist/prosemirror/containerFinalParagraph.js +7 -6
- package/dist/prosemirror/conversion/fromProseDoc.d.ts +2 -13
- package/dist/prosemirror/conversion/fromProseDoc.js +12 -590
- package/dist/prosemirror/conversion/toProseDoc.d.ts +4 -11
- package/dist/prosemirror/conversion/toProseDoc.js +31 -150
- package/dist/prosemirror/documentSchema.d.ts +8 -0
- package/dist/prosemirror/documentSchema.js +18 -0
- package/dist/prosemirror/extensions/StarterKit.js +2 -0
- package/dist/prosemirror/extensions/core/ParagraphExtension.js +104 -63
- package/dist/prosemirror/extensions/features/BaseKeymapExtension.js +1 -1
- package/dist/prosemirror/extensions/features/EmptyParagraphFormatExtension.js +24 -3
- package/dist/prosemirror/extensions/features/JoinedRunStyleExtension.d.ts +20 -0
- package/dist/prosemirror/extensions/features/JoinedRunStyleExtension.js +43 -0
- package/dist/prosemirror/extensions/features/ListExtension.js +10 -9
- package/dist/prosemirror/extensions/features/pastedHeadingStyles.js +1 -1
- package/dist/prosemirror/extensions/features/pastedHtmlLists.js +2 -4
- package/dist/prosemirror/extensions/marks/FootnoteRefExtension.js +14 -8
- package/dist/prosemirror/extensions/marks/HyperlinkExtension.js +8 -4
- package/dist/prosemirror/extensions/marks/StrikeExtension.js +2 -2
- package/dist/prosemirror/extensions/marks/SubscriptExtension.js +2 -2
- package/dist/prosemirror/extensions/marks/SuperscriptExtension.js +2 -2
- package/dist/prosemirror/extensions/marks/TextColorExtension.js +4 -3
- package/dist/prosemirror/extensions/marks/markUtils.d.ts +8 -6
- package/dist/prosemirror/extensions/marks/markUtils.js +17 -8
- package/dist/prosemirror/extensions/marks/noteReferenceDeletion.d.ts +3 -1
- package/dist/prosemirror/extensions/marks/noteReferenceDeletion.js +12 -1
- package/dist/prosemirror/extensions/nodes/CommentReferenceExtension.js +2 -2
- package/dist/prosemirror/extensions/nodes/HardBreakExtension.js +5 -3
- package/dist/prosemirror/extensions/nodes/TableExtension.js +104 -210
- package/dist/prosemirror/extensions/types.d.ts +7 -0
- package/dist/prosemirror/hyperlinkRemoval.d.ts +9 -0
- package/dist/prosemirror/hyperlinkRemoval.js +129 -0
- package/dist/prosemirror/index.d.ts +2 -1
- package/dist/prosemirror/index.js +2 -1
- package/dist/prosemirror/listNumbering.d.ts +3 -21
- package/dist/prosemirror/listNumbering.js +10 -25
- package/dist/prosemirror/listRendering.d.ts +27 -0
- package/dist/prosemirror/listRendering.js +27 -0
- package/dist/prosemirror/markupViewNotes.d.ts +8 -0
- package/dist/prosemirror/markupViewNotes.js +49 -0
- package/dist/prosemirror/markupViewProjection.d.ts +3 -1
- package/dist/prosemirror/markupViewProjection.js +7 -2
- package/dist/prosemirror/noteReferenceReview.d.ts +77 -0
- package/dist/prosemirror/noteReferenceReview.js +332 -0
- package/dist/prosemirror/paragraphIndentation.js +5 -2
- package/dist/prosemirror/paragraphMarkJoin.d.ts +6 -4
- package/dist/prosemirror/paragraphMarkJoin.js +21 -19
- package/dist/prosemirror/paragraphPropertyCarry.d.ts +64 -0
- package/dist/prosemirror/paragraphPropertyCarry.js +158 -0
- package/dist/prosemirror/plugins/documentStyleState.d.ts +26 -0
- package/dist/prosemirror/plugins/documentStyleState.js +32 -0
- package/dist/prosemirror/plugins/documentStyles.d.ts +2 -21
- package/dist/prosemirror/plugins/documentStyles.js +66 -29
- package/dist/prosemirror/plugins/index.d.ts +2 -1
- package/dist/prosemirror/plugins/index.js +2 -1
- package/dist/prosemirror/plugins/paragraphStyleResolution.d.ts +15 -0
- package/dist/prosemirror/plugins/paragraphStyleResolution.js +230 -0
- package/dist/prosemirror/plugins/suggestionMode.d.ts +12 -2
- package/dist/prosemirror/plugins/suggestionMode.js +391 -28
- package/dist/prosemirror/rebaseParagraphRunFormatting.d.ts +22 -2
- package/dist/prosemirror/rebaseParagraphRunFormatting.js +39 -13
- package/dist/prosemirror/rebaseParagraphRuns.d.ts +36 -0
- package/dist/prosemirror/rebaseParagraphRuns.js +99 -0
- package/dist/prosemirror/runFormattingFromMarks.d.ts +18 -0
- package/dist/prosemirror/runFormattingFromMarks.js +567 -0
- package/dist/prosemirror/runFormattingReconciliation.js +10 -9
- package/dist/prosemirror/schema/nodes.d.ts +2 -0
- package/dist/prosemirror/styles/paragraphStyleCascade.d.ts +59 -0
- package/dist/prosemirror/styles/paragraphStyleCascade.js +145 -0
- package/dist/prosemirror/styles/resolvedStyleAttrs.d.ts +21 -2
- package/dist/prosemirror/styles/resolvedStyleAttrs.js +38 -1
- package/dist/prosemirror/styles/tableStyleRegions.d.ts +31 -0
- package/dist/prosemirror/styles/tableStyleRegions.js +55 -0
- package/dist/prosemirror/tableCellPaste.d.ts +74 -0
- package/dist/prosemirror/tableCellPaste.js +525 -0
- package/dist/prosemirror/tableGridMutation.d.ts +53 -14
- package/dist/prosemirror/tableGridMutation.js +166 -18
- package/dist/prosemirror/tableRunIn.d.ts +51 -0
- package/dist/prosemirror/tableRunIn.js +165 -0
- package/dist/prosemirror/textInput.js +11 -2
- package/dist/prosemirror/trackedRevisionPath.d.ts +17 -0
- package/dist/prosemirror/trackedRevisionPath.js +32 -0
- package/dist/server.d.ts +2 -2
- package/package.json +5 -5
|
@@ -0,0 +1,525 @@
|
|
|
1
|
+
import { decodeTableCellParagraphSourcePayload, transportTableCellsWithParagraphPropertySources } from "../docx/paragraphPropertySource.js";
|
|
2
|
+
import { expectTableAttrs, mergeTableAttrs } from "./attrs/index.js";
|
|
3
|
+
import { Fragment, Slice } from "prosemirror-model";
|
|
4
|
+
import { CellSelection, TableMap, cellAround, tableNodeTypes } from "prosemirror-tables";
|
|
5
|
+
import { Transform } from "prosemirror-transform";
|
|
6
|
+
//#region src/prosemirror/tableCellPaste.ts
|
|
7
|
+
/**
|
|
8
|
+
* Pasting table cells into a table: the pasted cells overwrite the cells they
|
|
9
|
+
* land on, merges the pasted block cuts through are split first, and the table
|
|
10
|
+
* grows when the block reaches past its edge. A paste into a cell selection
|
|
11
|
+
* fills every selected cell instead and leaves the table's shape alone.
|
|
12
|
+
*
|
|
13
|
+
* `prosemirror-tables` ships the same operation as its `handlePaste`, but its
|
|
14
|
+
* merge splitting inserts the lower half of a vertical merge at a position
|
|
15
|
+
* relative to the table rather than to the document, so in any table that does
|
|
16
|
+
* not open the document the new cell lands inside an earlier cell and the
|
|
17
|
+
* paste either throws or leaves rows that no longer tile the grid. Its split
|
|
18
|
+
* halves also copy every attribute of the cell they came from, so both halves
|
|
19
|
+
* claim the same source cell and the same stored merge continuation.
|
|
20
|
+
*
|
|
21
|
+
* With suggestions on, the paste is tracked: each overwritten cell keeps its
|
|
22
|
+
* content as a deletion before the pasted content, a vertical merge the block
|
|
23
|
+
* cuts through is split as a tracked cell merge, and the rows and cells the
|
|
24
|
+
* table grows by are tracked insertions, so rejecting every change gives the
|
|
25
|
+
* table back. A horizontal merge has no tracked split, so one the block cuts
|
|
26
|
+
* through is split directly, as the structural table commands do.
|
|
27
|
+
*/
|
|
28
|
+
const fitSlice = (nodeType, slice) => {
|
|
29
|
+
const node = nodeType.createAndFill();
|
|
30
|
+
if (!node) throw new RangeError(`Cannot create an empty ${nodeType.name}`);
|
|
31
|
+
return new Transform(node).replace(0, node.content.size, slice).doc;
|
|
32
|
+
};
|
|
33
|
+
/**
|
|
34
|
+
* A cell's attributes with `count` of its columns, from the `from`th on, taken
|
|
35
|
+
* out of its span and its column widths.
|
|
36
|
+
*/
|
|
37
|
+
const withoutColumns = (attrs, from, count) => {
|
|
38
|
+
const colwidth = attrs["colwidth"];
|
|
39
|
+
const widths = Array.isArray(colwidth) ? colwidth.toSpliced(from, count) : null;
|
|
40
|
+
return {
|
|
41
|
+
...attrs,
|
|
42
|
+
colspan: Math.max(1, Number(attrs["colspan"]) || 1) - count,
|
|
43
|
+
colwidth: widths?.some((width) => Number(width) > 0) ? widths : null
|
|
44
|
+
};
|
|
45
|
+
};
|
|
46
|
+
const spanOf = (cell, name) => Math.max(1, Number(cell.attrs[name]) || 1);
|
|
47
|
+
/** Pad short rows with empty cells so the block is rectangular. */
|
|
48
|
+
const ensureRectangular = (schema, rows) => {
|
|
49
|
+
const widths = [];
|
|
50
|
+
for (const [index, row] of rows.entries()) for (let child = row.childCount - 1; child >= 0; child--) {
|
|
51
|
+
const cell = row.child(child);
|
|
52
|
+
for (let covered = index; covered < index + spanOf(cell, "rowspan"); covered++) widths[covered] = (widths[covered] ?? 0) + spanOf(cell, "colspan");
|
|
53
|
+
}
|
|
54
|
+
const width = Math.max(0, ...widths.map((value) => value ?? 0));
|
|
55
|
+
for (let index = 0; index < widths.length; index++) {
|
|
56
|
+
if (index >= rows.length) rows.push(Fragment.empty);
|
|
57
|
+
const rowWidth = widths[index] ?? 0;
|
|
58
|
+
if (rowWidth < width) {
|
|
59
|
+
const cells = [];
|
|
60
|
+
for (let column = rowWidth; column < width; column++) {
|
|
61
|
+
const empty = tableNodeTypes(schema).cell.createAndFill();
|
|
62
|
+
if (empty) cells.push(empty);
|
|
63
|
+
}
|
|
64
|
+
rows[index] = (rows[index] ?? Fragment.empty).append(Fragment.from(cells));
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
return {
|
|
68
|
+
height: rows.length,
|
|
69
|
+
width,
|
|
70
|
+
rows
|
|
71
|
+
};
|
|
72
|
+
};
|
|
73
|
+
/**
|
|
74
|
+
* The attributes of a cell made from another one, split off it or pasted from
|
|
75
|
+
* a copy of it: the same formatting, but not the other cell's identity, its
|
|
76
|
+
* revisions, or the continuation cells its merge stored, whose paragraphs
|
|
77
|
+
* belong to the other cell.
|
|
78
|
+
*/
|
|
79
|
+
const newCellAttrs = (attrs) => ({
|
|
80
|
+
...attrs,
|
|
81
|
+
_docxCellId: null,
|
|
82
|
+
cellMarker: null,
|
|
83
|
+
tcPrChange: null,
|
|
84
|
+
_preserveVMergeRestart: null,
|
|
85
|
+
_docxVMergeContinuationCells: null
|
|
86
|
+
});
|
|
87
|
+
const withNewTableCells = (node) => {
|
|
88
|
+
if (node.isTextblock || node.isLeaf) return node;
|
|
89
|
+
const content = withNewTableCellsIn(node.content);
|
|
90
|
+
const role = node.type.spec["tableRole"];
|
|
91
|
+
const isCell = role === "cell" || role === "header_cell";
|
|
92
|
+
return content === node.content && !isCell ? node : node.type.create(isCell ? newCellAttrs(node.attrs) : node.attrs, content, node.marks);
|
|
93
|
+
};
|
|
94
|
+
const withNewTableCellsIn = (fragment) => {
|
|
95
|
+
let changed = false;
|
|
96
|
+
const nodes = [];
|
|
97
|
+
fragment.forEach((node) => {
|
|
98
|
+
const next = withNewTableCells(node);
|
|
99
|
+
changed ||= next !== node;
|
|
100
|
+
nodes.push(next);
|
|
101
|
+
});
|
|
102
|
+
return changed ? Fragment.from(nodes) : fragment;
|
|
103
|
+
};
|
|
104
|
+
/**
|
|
105
|
+
* A pasted slice whose table cells are new cells: a copy of a cell must not
|
|
106
|
+
* claim the source cell's identity, revisions, or the continuation cells its
|
|
107
|
+
* merge stored, whatever the paste lands on.
|
|
108
|
+
*/
|
|
109
|
+
const pastedSliceWithNewTableCells = (slice) => {
|
|
110
|
+
const content = withNewTableCellsIn(slice.content);
|
|
111
|
+
return content === slice.content ? slice : new Slice(content, slice.openStart, slice.openEnd);
|
|
112
|
+
};
|
|
113
|
+
/** The cells a slice holds, or null when it holds none (it is not table content). */
|
|
114
|
+
const pastedCells = (slice) => {
|
|
115
|
+
if (slice.size === 0) return null;
|
|
116
|
+
let { content, openStart, openEnd } = slice;
|
|
117
|
+
while (content.childCount === 1 && (openStart > 0 && openEnd > 0 || content.child(0).type.spec["tableRole"] === "table")) {
|
|
118
|
+
openStart--;
|
|
119
|
+
openEnd--;
|
|
120
|
+
content = content.child(0).content;
|
|
121
|
+
}
|
|
122
|
+
const first = content.firstChild;
|
|
123
|
+
if (!first) return null;
|
|
124
|
+
const role = first.type.spec["tableRole"];
|
|
125
|
+
const { schema } = first.type;
|
|
126
|
+
const rows = [];
|
|
127
|
+
if (role === "row") for (let index = 0; index < content.childCount; index++) {
|
|
128
|
+
let cells = content.child(index).content;
|
|
129
|
+
const left = index ? 0 : Math.max(0, openStart - 1);
|
|
130
|
+
const right = index < content.childCount - 1 ? 0 : Math.max(0, openEnd - 1);
|
|
131
|
+
if (left || right) cells = fitSlice(tableNodeTypes(schema).row, new Slice(cells, left, right)).content;
|
|
132
|
+
rows.push(cells);
|
|
133
|
+
}
|
|
134
|
+
else if (role === "cell" || role === "header_cell") rows.push(openStart || openEnd ? fitSlice(tableNodeTypes(schema).row, new Slice(content, openStart, openEnd)).content : content);
|
|
135
|
+
else return null;
|
|
136
|
+
const newCells = rows.map((row) => {
|
|
137
|
+
const cells = [];
|
|
138
|
+
row.forEach((cell) => {
|
|
139
|
+
cells.push(cell.type.create(newCellAttrs(cell.attrs), cell.content, cell.marks));
|
|
140
|
+
});
|
|
141
|
+
return Fragment.from(cells);
|
|
142
|
+
});
|
|
143
|
+
return ensureRectangular(schema, newCells);
|
|
144
|
+
};
|
|
145
|
+
const readTable = (tr, tableStart) => {
|
|
146
|
+
const table = tr.doc.nodeAt(tableStart - 1);
|
|
147
|
+
if (!table || table.type.spec["tableRole"] !== "table") throw new RangeError("The pasted-into table is gone");
|
|
148
|
+
return {
|
|
149
|
+
table,
|
|
150
|
+
map: TableMap.get(table),
|
|
151
|
+
tableStart,
|
|
152
|
+
mapFrom: tr.mapping.maps.length
|
|
153
|
+
};
|
|
154
|
+
};
|
|
155
|
+
const mapPosition = (tr, context, pos) => tr.mapping.slice(context.mapFrom).map(pos);
|
|
156
|
+
/** A new, empty cell of the same kind as `like`, with nothing that names another cell. */
|
|
157
|
+
const emptyCellLike = (like, schema) => {
|
|
158
|
+
const types = tableNodeTypes(schema);
|
|
159
|
+
const cell = (like?.type === types.header_cell ? types.header_cell : types.cell).createAndFill();
|
|
160
|
+
if (!cell) throw new RangeError("Cannot create an empty table cell");
|
|
161
|
+
return cell;
|
|
162
|
+
};
|
|
163
|
+
const isOmittedGridSlot = (cell) => cell.attrs["_omittedGridSlot"] != null;
|
|
164
|
+
const hasOmittedGridSlots = (table) => {
|
|
165
|
+
let found = false;
|
|
166
|
+
table.forEach((row) => {
|
|
167
|
+
row.forEach((cell) => {
|
|
168
|
+
found ||= isOmittedGridSlot(cell);
|
|
169
|
+
});
|
|
170
|
+
});
|
|
171
|
+
return found;
|
|
172
|
+
};
|
|
173
|
+
/**
|
|
174
|
+
* The `w:vMerge` continuation cells a merged cell stored for the rows below its
|
|
175
|
+
* first, one per row, empty ones standing in for any it did not store.
|
|
176
|
+
*/
|
|
177
|
+
const continuationCells = (cell, rowspan) => {
|
|
178
|
+
const stored = cell.attrs["_docxVMergeContinuationCells"];
|
|
179
|
+
const cells = stored === void 0 || stored === null ? [] : [...decodeTableCellParagraphSourcePayload(stored).cells];
|
|
180
|
+
while (cells.length < rowspan - 1) cells.push({
|
|
181
|
+
type: "tableCell",
|
|
182
|
+
formatting: { vMerge: "continue" },
|
|
183
|
+
content: [{
|
|
184
|
+
type: "paragraph",
|
|
185
|
+
content: []
|
|
186
|
+
}]
|
|
187
|
+
});
|
|
188
|
+
return cells;
|
|
189
|
+
};
|
|
190
|
+
/** Stored continuation cells to carry, or null for none. */
|
|
191
|
+
const continuationAttr = (cells) => cells.length > 0 ? transportTableCellsWithParagraphPropertySources(cells) : null;
|
|
192
|
+
/** Add columns and rows so the table reaches `width` × `height`. */
|
|
193
|
+
const growTable = (tr, context, width, height, revision) => {
|
|
194
|
+
const { table, map, tableStart } = context;
|
|
195
|
+
const { schema } = tr.doc.type;
|
|
196
|
+
let grown = false;
|
|
197
|
+
if (width > map.width) {
|
|
198
|
+
let rowEnd = 0;
|
|
199
|
+
for (let row = 0; row < map.height; row++) {
|
|
200
|
+
const rowNode = table.child(row);
|
|
201
|
+
rowEnd += rowNode.nodeSize;
|
|
202
|
+
const cells = [];
|
|
203
|
+
for (let column = map.width; column < width; column++) {
|
|
204
|
+
const cell = emptyCellLike(rowNode.lastChild, schema);
|
|
205
|
+
cells.push(revision ? cell.type.create({
|
|
206
|
+
...cell.attrs,
|
|
207
|
+
cellMarker: {
|
|
208
|
+
kind: "ins",
|
|
209
|
+
info: { ...revision }
|
|
210
|
+
}
|
|
211
|
+
}, cell.content) : cell);
|
|
212
|
+
}
|
|
213
|
+
tr.insert(mapPosition(tr, context, rowEnd - 1 + tableStart), cells);
|
|
214
|
+
}
|
|
215
|
+
const widths = expectTableAttrs(table).columnWidths;
|
|
216
|
+
const lastWidth = widths?.at(-1);
|
|
217
|
+
tr.setNodeMarkup(mapPosition(tr, context, tableStart - 1), void 0, mergeTableAttrs(table, { columnWidths: widths?.length === map.width && lastWidth !== void 0 ? [...widths, ...Array.from({ length: width - map.width }, () => lastWidth)] : void 0 }));
|
|
218
|
+
grown = true;
|
|
219
|
+
}
|
|
220
|
+
if (height > map.height) {
|
|
221
|
+
const lastRowStart = (map.height - 1) * map.width;
|
|
222
|
+
const cells = [];
|
|
223
|
+
for (let column = 0; column < Math.max(map.width, width); column++) {
|
|
224
|
+
const above = column < map.width ? table.nodeAt(map.map[lastRowStart + column] ?? -1) : null;
|
|
225
|
+
cells.push(emptyCellLike(above ?? null, schema));
|
|
226
|
+
}
|
|
227
|
+
const rowType = tableNodeTypes(schema).row;
|
|
228
|
+
const rows = [];
|
|
229
|
+
for (let row = map.height; row < height; row++) rows.push(rowType.create(revision ? { trIns: { ...revision } } : null, cells));
|
|
230
|
+
tr.insert(mapPosition(tr, context, tableStart + table.nodeSize - 2), rows);
|
|
231
|
+
grown = true;
|
|
232
|
+
}
|
|
233
|
+
return grown;
|
|
234
|
+
};
|
|
235
|
+
/** Split every vertical merge that crosses the line above row `top`, within [left, right). */
|
|
236
|
+
const isolateHorizontal = (tr, context, left, right, top, revision) => {
|
|
237
|
+
const { table, map, tableStart } = context;
|
|
238
|
+
if (top === 0 || top === map.height) return false;
|
|
239
|
+
let found = false;
|
|
240
|
+
for (let column = left; column < right; column++) {
|
|
241
|
+
const index = top * map.width + column;
|
|
242
|
+
const pos = map.map[index];
|
|
243
|
+
if (pos === void 0 || map.map[index - map.width] !== pos) continue;
|
|
244
|
+
found = true;
|
|
245
|
+
const cell = table.nodeAt(pos);
|
|
246
|
+
if (!cell) continue;
|
|
247
|
+
const { top: cellTop, left: cellLeft } = map.findCell(pos);
|
|
248
|
+
const rowspan = spanOf(cell, "rowspan");
|
|
249
|
+
const upperRows = top - cellTop;
|
|
250
|
+
const lowerRows = rowspan - upperRows;
|
|
251
|
+
const continuations = continuationCells(cell, rowspan);
|
|
252
|
+
tr.setNodeMarkup(mapPosition(tr, context, tableStart + pos), null, {
|
|
253
|
+
...cell.attrs,
|
|
254
|
+
rowspan: upperRows,
|
|
255
|
+
_docxVMergeContinuationCells: continuationAttr(continuations.slice(0, upperRows - 1))
|
|
256
|
+
});
|
|
257
|
+
const lower = cell.type.createAndFill({
|
|
258
|
+
...newCellAttrs(cell.attrs),
|
|
259
|
+
rowspan: lowerRows,
|
|
260
|
+
_docxVMergeContinuationCells: continuationAttr(continuations.slice(upperRows)),
|
|
261
|
+
cellMarker: revision ? {
|
|
262
|
+
kind: "merge",
|
|
263
|
+
info: { ...revision },
|
|
264
|
+
verticalMergeOriginal: "continue"
|
|
265
|
+
} : null
|
|
266
|
+
});
|
|
267
|
+
if (!lower) throw new RangeError("Cannot split a merged table cell");
|
|
268
|
+
tr.insert(mapPosition(tr, context, tableStart + map.positionAt(top, cellLeft, table)), lower);
|
|
269
|
+
column += spanOf(cell, "colspan") - 1;
|
|
270
|
+
}
|
|
271
|
+
return found;
|
|
272
|
+
};
|
|
273
|
+
/** Split every horizontal merge that crosses the line left of column `left`, within [top, bottom). */
|
|
274
|
+
const isolateVertical = (tr, context, top, bottom, left) => {
|
|
275
|
+
const { table, map, tableStart } = context;
|
|
276
|
+
if (left === 0 || left === map.width) return false;
|
|
277
|
+
let found = false;
|
|
278
|
+
for (let row = top; row < bottom; row++) {
|
|
279
|
+
const index = row * map.width + left;
|
|
280
|
+
const pos = map.map[index];
|
|
281
|
+
if (pos === void 0 || map.map[index - 1] !== pos) continue;
|
|
282
|
+
found = true;
|
|
283
|
+
const cell = table.nodeAt(pos);
|
|
284
|
+
if (!cell) continue;
|
|
285
|
+
const cellLeft = map.colCount(pos);
|
|
286
|
+
const colspan = spanOf(cell, "colspan");
|
|
287
|
+
const updatePos = mapPosition(tr, context, tableStart + pos);
|
|
288
|
+
tr.setNodeMarkup(updatePos, null, withoutColumns(cell.attrs, left - cellLeft, colspan - (left - cellLeft)));
|
|
289
|
+
const right = cell.type.createAndFill(withoutColumns(newCellAttrs(cell.attrs), 0, left - cellLeft));
|
|
290
|
+
if (!right) throw new RangeError("Cannot split a merged table cell");
|
|
291
|
+
tr.insert(updatePos + cell.nodeSize, right);
|
|
292
|
+
row += spanOf(cell, "rowspan") - 1;
|
|
293
|
+
}
|
|
294
|
+
return found;
|
|
295
|
+
};
|
|
296
|
+
/**
|
|
297
|
+
* The range of a cell's content a paste replaces. A block of whole paragraphs
|
|
298
|
+
* (a pasted cell's content) replaces all of it; open content (text, or
|
|
299
|
+
* paragraphs cut from a longer run) goes from the start of the first paragraph
|
|
300
|
+
* to the end of the last, so it takes on the cell's paragraph formatting the
|
|
301
|
+
* way a paste into a paragraph does.
|
|
302
|
+
*/
|
|
303
|
+
const cellPasteRange = (cell, cellPos, slice) => {
|
|
304
|
+
const from = cellPos + 1;
|
|
305
|
+
const to = cellPos + cell.nodeSize - 1;
|
|
306
|
+
if (slice.openStart === 0 && slice.openEnd === 0 && slice.content.firstChild?.isBlock) return {
|
|
307
|
+
from,
|
|
308
|
+
to
|
|
309
|
+
};
|
|
310
|
+
return {
|
|
311
|
+
from: cell.firstChild?.isTextblock ? from + 1 : from,
|
|
312
|
+
to: cell.lastChild?.isTextblock ? to - 1 : to
|
|
313
|
+
};
|
|
314
|
+
};
|
|
315
|
+
/** Replace a cell's content outright. */
|
|
316
|
+
const replaceCellContentDirectly = (tr, cellPos, slice) => {
|
|
317
|
+
const cell = tr.doc.nodeAt(cellPos);
|
|
318
|
+
if (!cell) throw new RangeError("The pasted-into table cell is gone");
|
|
319
|
+
const { from, to } = cellPasteRange(cell, cellPos, slice);
|
|
320
|
+
tr.replace(from, to, slice);
|
|
321
|
+
};
|
|
322
|
+
/** Keep overwritten cells live until review resolves the pasted vertical merges. */
|
|
323
|
+
const verticalPasteTargets = ({ context: { map, table, tableStart }, cells, placement: { top, left } }) => {
|
|
324
|
+
const targets = [];
|
|
325
|
+
const covered = /* @__PURE__ */ new Set();
|
|
326
|
+
for (const [offset, fragment] of cells.rows.entries()) {
|
|
327
|
+
const row = top + offset;
|
|
328
|
+
let column = left;
|
|
329
|
+
for (let child = 0; child < fragment.childCount; child++) {
|
|
330
|
+
const pasted = fragment.child(child);
|
|
331
|
+
while (covered.has(row * map.width + column)) column++;
|
|
332
|
+
const right = column + spanOf(pasted, "colspan");
|
|
333
|
+
const bottom = row + spanOf(pasted, "rowspan");
|
|
334
|
+
for (let nextRow = row; nextRow < bottom;) {
|
|
335
|
+
const pos = map.map[nextRow * map.width + column];
|
|
336
|
+
const cell = pos === void 0 ? null : table.nodeAt(pos);
|
|
337
|
+
if (pos === void 0 || !cell || cell.attrs["cellMarker"] != null) return null;
|
|
338
|
+
const rect = map.findCell(pos);
|
|
339
|
+
if (rect.top !== nextRow || rect.left !== column || rect.right !== right || rect.bottom > bottom) return null;
|
|
340
|
+
const anchor = nextRow === row;
|
|
341
|
+
targets.push({
|
|
342
|
+
pos: tableStart + pos,
|
|
343
|
+
slice: anchor ? new Slice(pasted.content, 0, 0) : new Slice(Fragment.from(table.type.schema.node("paragraph")), 0, 0),
|
|
344
|
+
merge: anchor ? "anchor" : "continuation"
|
|
345
|
+
});
|
|
346
|
+
nextRow = rect.bottom;
|
|
347
|
+
}
|
|
348
|
+
for (let r = row; r < bottom; r++) for (let c = column; c < right; c++) covered.add(r * map.width + c);
|
|
349
|
+
column = right;
|
|
350
|
+
}
|
|
351
|
+
}
|
|
352
|
+
return targets;
|
|
353
|
+
};
|
|
354
|
+
/**
|
|
355
|
+
* The table cell each pasted cell lands on, when every one lands on a cell of
|
|
356
|
+
* its own shape; null when the block's cells are shaped differently.
|
|
357
|
+
*/
|
|
358
|
+
const matchingCells = ({ map, tableStart }, cells, top, left) => {
|
|
359
|
+
const matches = [];
|
|
360
|
+
const covered = /* @__PURE__ */ new Set();
|
|
361
|
+
for (const [offset, fragment] of cells.rows.entries()) {
|
|
362
|
+
const row = top + offset;
|
|
363
|
+
let column = left;
|
|
364
|
+
for (let child = 0; child < fragment.childCount; child++) {
|
|
365
|
+
const pasted = fragment.child(child);
|
|
366
|
+
while (covered.has(row * map.width + column)) column++;
|
|
367
|
+
const pos = map.map[row * map.width + column];
|
|
368
|
+
if (pos === void 0) return null;
|
|
369
|
+
const rect = map.findCell(pos);
|
|
370
|
+
if (rect.top !== row || rect.left !== column || rect.right - rect.left !== spanOf(pasted, "colspan") || rect.bottom - rect.top !== spanOf(pasted, "rowspan")) return null;
|
|
371
|
+
for (let r = rect.top; r < rect.bottom; r++) for (let c = rect.left; c < rect.right; c++) covered.add(r * map.width + c);
|
|
372
|
+
matches.push({
|
|
373
|
+
pos: tableStart + pos,
|
|
374
|
+
slice: new Slice(pasted.content, 0, 0)
|
|
375
|
+
});
|
|
376
|
+
column = rect.right;
|
|
377
|
+
}
|
|
378
|
+
}
|
|
379
|
+
return matches;
|
|
380
|
+
};
|
|
381
|
+
/** The pasted cell covering (`row`, `column`) of the block, repeating the block past its edge. */
|
|
382
|
+
const pastedCellAt = (cells, row, column) => {
|
|
383
|
+
const wantedRow = row % cells.height;
|
|
384
|
+
const wantedColumn = column % cells.width;
|
|
385
|
+
const covered = [];
|
|
386
|
+
for (const [index, fragment] of cells.rows.entries()) {
|
|
387
|
+
let at = 0;
|
|
388
|
+
for (let child = 0; child < fragment.childCount; child++) {
|
|
389
|
+
const cell = fragment.child(child);
|
|
390
|
+
while (covered[index]?.[at]) at++;
|
|
391
|
+
for (let r = index; r < index + spanOf(cell, "rowspan"); r++) for (let c = at; c < at + spanOf(cell, "colspan"); c++) (covered[r] ??= [])[c] = 1;
|
|
392
|
+
if (wantedRow >= index && wantedRow < index + spanOf(cell, "rowspan") && wantedColumn >= at && wantedColumn < at + spanOf(cell, "colspan")) return cell;
|
|
393
|
+
at += spanOf(cell, "colspan");
|
|
394
|
+
}
|
|
395
|
+
}
|
|
396
|
+
return null;
|
|
397
|
+
};
|
|
398
|
+
/**
|
|
399
|
+
* Every cell of the table touching `rect`, each taking the pasted cell at its
|
|
400
|
+
* place in the block (the block repeating to cover the rectangle), or the
|
|
401
|
+
* pasted content itself when it is not cells. The table's shape is untouched.
|
|
402
|
+
*/
|
|
403
|
+
const fillTargets = ({ map, table, tableStart }, rect, cells, slice) => {
|
|
404
|
+
const targets = [];
|
|
405
|
+
for (const pos of map.cellsInRect(rect)) {
|
|
406
|
+
const cellRect = map.findCell(pos);
|
|
407
|
+
const row = Math.max(cellRect.top, rect.top) - rect.top;
|
|
408
|
+
const column = Math.max(cellRect.left, rect.left) - rect.left;
|
|
409
|
+
const pasted = cells ? pastedCellAt(cells, row, column) : null;
|
|
410
|
+
const cell = table.nodeAt(pos);
|
|
411
|
+
if (cells && !pasted || !cell || isOmittedGridSlot(cell)) continue;
|
|
412
|
+
targets.push({
|
|
413
|
+
pos: tableStart + pos,
|
|
414
|
+
slice: pasted ? new Slice(pasted.content, 0, 0) : slice
|
|
415
|
+
});
|
|
416
|
+
}
|
|
417
|
+
return targets;
|
|
418
|
+
};
|
|
419
|
+
const replaceTargets = (tr, targets, replaceCellContent) => {
|
|
420
|
+
for (const { pos, slice } of targets.toSorted((a, b) => b.pos - a.pos)) replaceCellContent(tr, pos, slice);
|
|
421
|
+
};
|
|
422
|
+
const selectBlock = (tr, tableStart, rect) => {
|
|
423
|
+
const { map, table } = readTable(tr, tableStart);
|
|
424
|
+
tr.setSelection(new CellSelection(tr.doc.resolve(tableStart + map.positionAt(rect.top, rect.left, table)), tr.doc.resolve(tableStart + map.positionAt(rect.bottom - 1, rect.right - 1, table))));
|
|
425
|
+
};
|
|
426
|
+
/**
|
|
427
|
+
* Paste a block of cells into the table at `tableStart` from (`top`, `left`):
|
|
428
|
+
* grow the table to hold it, split the merges its edges cut through, then give
|
|
429
|
+
* each cell the block covers its pasted cell. Where the block's cells have the
|
|
430
|
+
* table's shapes the table keeps its cells, with their formatting and
|
|
431
|
+
* identity, and takes the pasted content; otherwise the block's cells replace
|
|
432
|
+
* them, except in a tracked paste, which keeps the table's shape. Selects the
|
|
433
|
+
* pasted block.
|
|
434
|
+
*/
|
|
435
|
+
const insertTableCells = (tr, tableStart, { top, left }, cells, { revision, replaceCellContent = replaceCellContentDirectly } = {}) => {
|
|
436
|
+
let rect = {
|
|
437
|
+
top,
|
|
438
|
+
left,
|
|
439
|
+
right: left + cells.width,
|
|
440
|
+
bottom: top + cells.height
|
|
441
|
+
};
|
|
442
|
+
let context = readTable(tr, tableStart);
|
|
443
|
+
if (hasOmittedGridSlots(context.table)) {
|
|
444
|
+
rect = {
|
|
445
|
+
...rect,
|
|
446
|
+
right: Math.min(rect.right, context.map.width),
|
|
447
|
+
bottom: Math.min(rect.bottom, context.map.height)
|
|
448
|
+
};
|
|
449
|
+
replaceTargets(tr, fillTargets(context, rect, cells, Slice.empty), replaceCellContent);
|
|
450
|
+
selectBlock(tr, tableStart, rect);
|
|
451
|
+
return tr;
|
|
452
|
+
}
|
|
453
|
+
const recompute = (changed) => {
|
|
454
|
+
if (changed) context = readTable(tr, tableStart);
|
|
455
|
+
};
|
|
456
|
+
recompute(growTable(tr, context, rect.right, rect.bottom, revision));
|
|
457
|
+
recompute(isolateHorizontal(tr, context, rect.left, rect.right, rect.top, revision));
|
|
458
|
+
recompute(isolateHorizontal(tr, context, rect.left, rect.right, rect.bottom, revision));
|
|
459
|
+
recompute(isolateVertical(tr, context, rect.top, rect.bottom, rect.left));
|
|
460
|
+
recompute(isolateVertical(tr, context, rect.top, rect.bottom, rect.right));
|
|
461
|
+
const matches = matchingCells(context, cells, rect.top, rect.left);
|
|
462
|
+
if (matches) replaceTargets(tr, matches, replaceCellContent);
|
|
463
|
+
else if (revision) {
|
|
464
|
+
const vertical = verticalPasteTargets({
|
|
465
|
+
context,
|
|
466
|
+
cells,
|
|
467
|
+
placement: rect
|
|
468
|
+
});
|
|
469
|
+
if (vertical) for (const { pos, slice, merge } of vertical.toSorted((a, b) => b.pos - a.pos)) {
|
|
470
|
+
replaceCellContent(tr, pos, slice);
|
|
471
|
+
if (merge === "continuation") tr.setNodeAttribute(pos, "cellMarker", {
|
|
472
|
+
kind: "merge",
|
|
473
|
+
info: { ...revision },
|
|
474
|
+
verticalMerge: "continue",
|
|
475
|
+
verticalMergeOriginal: "rest"
|
|
476
|
+
});
|
|
477
|
+
}
|
|
478
|
+
else replaceTargets(tr, fillTargets(context, rect, cells, Slice.empty), replaceCellContent);
|
|
479
|
+
} else for (let row = rect.top; row < rect.bottom; row++) {
|
|
480
|
+
const from = context.map.positionAt(row, rect.left, context.table);
|
|
481
|
+
const to = context.map.positionAt(row, rect.right, context.table);
|
|
482
|
+
tr.replace(mapPosition(tr, context, from + tableStart), mapPosition(tr, context, to + tableStart), new Slice(cells.rows[row - rect.top] ?? Fragment.empty, 0, 0));
|
|
483
|
+
}
|
|
484
|
+
selectBlock(tr, tableStart, rect);
|
|
485
|
+
return tr;
|
|
486
|
+
};
|
|
487
|
+
/**
|
|
488
|
+
* Paste into every cell of a cell selection: each takes the pasted cell at its
|
|
489
|
+
* place in the block, the block repeating to cover the selection, or the
|
|
490
|
+
* pasted content itself when it holds no cells. The table keeps its shape.
|
|
491
|
+
*/
|
|
492
|
+
const fillSelectedCells = (tr, selection, slice, { replaceCellContent = replaceCellContentDirectly } = {}) => {
|
|
493
|
+
const tableStart = selection.$anchorCell.start(-1);
|
|
494
|
+
const context = readTable(tr, tableStart);
|
|
495
|
+
const rect = context.map.rectBetween(selection.$anchorCell.pos - tableStart, selection.$headCell.pos - tableStart);
|
|
496
|
+
replaceTargets(tr, fillTargets(context, rect, pastedCells(slice), slice), replaceCellContent);
|
|
497
|
+
const after = readTable(tr, tableStart);
|
|
498
|
+
tr.setSelection(new CellSelection(tr.doc.resolve(tableStart + after.map.positionAt(rect.top, rect.left, after.table)), tr.doc.resolve(tableStart + after.map.positionAt(rect.bottom - 1, rect.right - 1, after.table))));
|
|
499
|
+
return tr;
|
|
500
|
+
};
|
|
501
|
+
/**
|
|
502
|
+
* Paste `slice` into the table the selection is in: into every selected cell
|
|
503
|
+
* of a cell selection, or, when the slice holds cells, as a block of cells
|
|
504
|
+
* from the cell holding the cursor. False otherwise, so the paste falls
|
|
505
|
+
* through to the ordinary one.
|
|
506
|
+
*/
|
|
507
|
+
const pasteTableCells = (state, slice, dispatch, hooks) => {
|
|
508
|
+
const { selection } = state;
|
|
509
|
+
let run = null;
|
|
510
|
+
if (selection instanceof CellSelection) run = (tr) => fillSelectedCells(tr, selection, slice, hooks);
|
|
511
|
+
else {
|
|
512
|
+
const cells = pastedCells(slice);
|
|
513
|
+
const $cell = cells ? cellAround(selection.$head) : null;
|
|
514
|
+
if (cells && $cell) {
|
|
515
|
+
const tableStart = $cell.start(-1);
|
|
516
|
+
const rect = TableMap.get($cell.node(-1)).findCell($cell.pos - tableStart);
|
|
517
|
+
run = (tr) => insertTableCells(tr, tableStart, rect, cells, hooks);
|
|
518
|
+
}
|
|
519
|
+
}
|
|
520
|
+
if (!run) return false;
|
|
521
|
+
if (dispatch) dispatch(run(state.tr).scrollIntoView().setMeta("paste", true).setMeta("uiEvent", "paste"));
|
|
522
|
+
return true;
|
|
523
|
+
};
|
|
524
|
+
//#endregion
|
|
525
|
+
export { cellPasteRange, fillSelectedCells, insertTableCells, pasteTableCells, pastedCells, pastedSliceWithNewTableCells };
|
|
@@ -19,19 +19,35 @@ type RemoveTableRowOptions = {
|
|
|
19
19
|
* and the table is left one row shorter than that merge.
|
|
20
20
|
*/
|
|
21
21
|
declare const removeTableRow: (tr: Transaction, { map, table, tableStart }: RemoveTableRowOptions, row: number) => void;
|
|
22
|
-
/**
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
22
|
+
/** Whether a batch of structural deletions may have emptied rows. */
|
|
23
|
+
type RowsEmptiedInBatch = {
|
|
24
|
+
pending: boolean;
|
|
25
|
+
};
|
|
26
|
+
type MarkRowEmptiedInBatchOptions = {
|
|
27
|
+
tr: Transaction;
|
|
28
|
+
rowPosition: number;
|
|
29
|
+
emptied: RowsEmptiedInBatch;
|
|
30
|
+
};
|
|
31
|
+
/** A transient row attribute follows node moves; conversion never serializes it. */
|
|
32
|
+
declare const markRowEmptiedInBatch: ({ tr, rowPosition, emptied }: MarkRowEmptiedInBatchOptions) => void;
|
|
33
|
+
type MarkRowsEmptiedInBatchOptions = {
|
|
34
|
+
tr: Transaction;
|
|
35
|
+
tablePosition: number;
|
|
36
|
+
previousTable: Node;
|
|
37
|
+
emptied: RowsEmptiedInBatch;
|
|
38
|
+
};
|
|
39
|
+
/** Column removal keeps row indices stable: mark only newly cell-less rows. */
|
|
40
|
+
declare const markRowsEmptiedInBatch: ({ tr, tablePosition, previousTable, emptied }: MarkRowsEmptiedInBatchOptions) => void;
|
|
41
|
+
/** Sweep current tables in reverse so moves cannot invalidate cleanup targets. */
|
|
42
|
+
declare const removeRowsWithoutCellsAfterBatch: (tr: Transaction, emptied: RowsEmptiedInBatch) => void;
|
|
43
|
+
type RemoveRowsWithoutCellsInRangeOptions = {
|
|
44
|
+
tr: Transaction;
|
|
45
|
+
from: number;
|
|
46
|
+
to: number;
|
|
47
|
+
};
|
|
48
|
+
/** Close marked rows before their owning cell is captured into a continuation payload. */
|
|
49
|
+
declare const removeRowsWithoutCellsInRange: ({ tr, from, to }: RemoveRowsWithoutCellsInRangeOptions) => void;
|
|
50
|
+
/** Close all cell-less rows after an immediate structural edit. */
|
|
35
51
|
declare const removeRowsWithoutCells: (tr: Transaction, tablePosition: number) => void;
|
|
36
52
|
type ReconcileTableGridAfterColumnRemovalOptions = {
|
|
37
53
|
tr: Transaction;
|
|
@@ -62,5 +78,28 @@ type ReconcileTableGridAfterColumnInsertionOptions = {
|
|
|
62
78
|
* more than `w:tblGrid` declares.
|
|
63
79
|
*/
|
|
64
80
|
declare const reconcileTableGridAfterColumnInsertion: ({ tr, tablePosition, previousTable, insertedColumn }: ReconcileTableGridAfterColumnInsertionOptions) => void;
|
|
81
|
+
type InsertTableColumnOptions = {
|
|
82
|
+
tr: Transaction;
|
|
83
|
+
tablePosition: number;
|
|
84
|
+
/** The grid column the new column takes; the columns from it on move right. */
|
|
85
|
+
column: number;
|
|
86
|
+
/** The grid column whose cells the new cells copy their formatting from. */
|
|
87
|
+
templateColumn: number;
|
|
88
|
+
/** A new, empty cell shaped after `template`, the row's cell in the template column. */
|
|
89
|
+
createCell: (template: Node | null) => Node;
|
|
90
|
+
};
|
|
91
|
+
/**
|
|
92
|
+
* Insert a grid column, walking the table map: each row gains a cell at the
|
|
93
|
+
* column's place in the grid (after any cell a merge from a row above holds
|
|
94
|
+
* there), a cell merged across that place widens instead, and `w:tblGrid`
|
|
95
|
+
* gains the column.
|
|
96
|
+
*/
|
|
97
|
+
declare const insertTableColumn: ({ tr, tablePosition, column, templateColumn, createCell }: InsertTableColumnOptions) => void;
|
|
98
|
+
/**
|
|
99
|
+
* Remove grid columns [`left`, `right`), walking the table map: a cell only
|
|
100
|
+
* in them goes, a cell merged across them narrows, `w:tblGrid` loses them,
|
|
101
|
+
* and a row left without a cell of its own goes too.
|
|
102
|
+
*/
|
|
103
|
+
declare const removeTableColumns: (tr: Transaction, tablePosition: number, left: number, right: number) => void;
|
|
65
104
|
//#endregion
|
|
66
|
-
export { reconcileTableGridAfterColumnInsertion, reconcileTableGridAfterColumnRemoval, removeRowsWithoutCells, removeTableRow };
|
|
105
|
+
export { RowsEmptiedInBatch, insertTableColumn, markRowEmptiedInBatch, markRowsEmptiedInBatch, reconcileTableGridAfterColumnInsertion, reconcileTableGridAfterColumnRemoval, removeRowsWithoutCells, removeRowsWithoutCellsAfterBatch, removeRowsWithoutCellsInRange, removeTableColumns, removeTableRow };
|