@kerebron/extension-tables 0.0.1

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 (65) hide show
  1. package/LICENSE +23 -0
  2. package/README.md +34 -0
  3. package/assets/tables.css +48 -0
  4. package/esm/ExtensionTables.d.ts +10 -0
  5. package/esm/ExtensionTables.d.ts.map +1 -0
  6. package/esm/ExtensionTables.js +27 -0
  7. package/esm/NodeTable.d.ts +24 -0
  8. package/esm/NodeTable.d.ts.map +1 -0
  9. package/esm/NodeTable.js +115 -0
  10. package/esm/NodeTableCell.d.ts +16 -0
  11. package/esm/NodeTableCell.d.ts.map +1 -0
  12. package/esm/NodeTableCell.js +77 -0
  13. package/esm/NodeTableHeader.d.ts +16 -0
  14. package/esm/NodeTableHeader.d.ts.map +1 -0
  15. package/esm/NodeTableHeader.js +75 -0
  16. package/esm/NodeTableRow.d.ts +16 -0
  17. package/esm/NodeTableRow.d.ts.map +1 -0
  18. package/esm/NodeTableRow.js +47 -0
  19. package/esm/_dnt.shims.d.ts +6 -0
  20. package/esm/_dnt.shims.d.ts.map +1 -0
  21. package/esm/_dnt.shims.js +61 -0
  22. package/esm/package.json +3 -0
  23. package/esm/utilities/CellSelection.d.ts +53 -0
  24. package/esm/utilities/CellSelection.d.ts.map +1 -0
  25. package/esm/utilities/CellSelection.js +382 -0
  26. package/esm/utilities/TableMap.d.ts +92 -0
  27. package/esm/utilities/TableMap.d.ts.map +1 -0
  28. package/esm/utilities/TableMap.js +335 -0
  29. package/esm/utilities/TableView.d.ts +21 -0
  30. package/esm/utilities/TableView.d.ts.map +1 -0
  31. package/esm/utilities/TableView.js +108 -0
  32. package/esm/utilities/columnResizing.d.ts +50 -0
  33. package/esm/utilities/columnResizing.d.ts.map +1 -0
  34. package/esm/utilities/columnResizing.js +307 -0
  35. package/esm/utilities/commands.d.ts +166 -0
  36. package/esm/utilities/commands.d.ts.map +1 -0
  37. package/esm/utilities/commands.js +702 -0
  38. package/esm/utilities/copypaste.d.ts +35 -0
  39. package/esm/utilities/copypaste.d.ts.map +1 -0
  40. package/esm/utilities/copypaste.js +283 -0
  41. package/esm/utilities/createCell.d.ts +3 -0
  42. package/esm/utilities/createCell.d.ts.map +1 -0
  43. package/esm/utilities/createCell.js +6 -0
  44. package/esm/utilities/createTable.d.ts +3 -0
  45. package/esm/utilities/createTable.d.ts.map +1 -0
  46. package/esm/utilities/createTable.js +30 -0
  47. package/esm/utilities/fixTables.d.ts +18 -0
  48. package/esm/utilities/fixTables.d.ts.map +1 -0
  49. package/esm/utilities/fixTables.js +146 -0
  50. package/esm/utilities/getTableNodeTypes.d.ts +5 -0
  51. package/esm/utilities/getTableNodeTypes.d.ts.map +1 -0
  52. package/esm/utilities/getTableNodeTypes.js +14 -0
  53. package/esm/utilities/input.d.ts +21 -0
  54. package/esm/utilities/input.d.ts.map +1 -0
  55. package/esm/utilities/input.js +241 -0
  56. package/esm/utilities/tableEditing.d.ts +23 -0
  57. package/esm/utilities/tableEditing.d.ts.map +1 -0
  58. package/esm/utilities/tableEditing.js +63 -0
  59. package/esm/utilities/tableNodeTypes.d.ts +14 -0
  60. package/esm/utilities/tableNodeTypes.d.ts.map +1 -0
  61. package/esm/utilities/tableNodeTypes.js +16 -0
  62. package/esm/utilities/util.d.ts +73 -0
  63. package/esm/utilities/util.d.ts.map +1 -0
  64. package/esm/utilities/util.js +155 -0
  65. package/package.json +30 -0
@@ -0,0 +1,35 @@
1
+ import { Fragment, Node, NodeType, Slice } from 'prosemirror-model';
2
+ import { EditorState, Transaction } from 'prosemirror-state';
3
+ import { Rect } from './TableMap.js';
4
+ /**
5
+ * @internal
6
+ */
7
+ export type Area = {
8
+ width: number;
9
+ height: number;
10
+ rows: Fragment[];
11
+ };
12
+ /**
13
+ * Get a rectangular area of cells from a slice, or null if the outer
14
+ * nodes of the slice aren't table cells or rows.
15
+ *
16
+ * @internal
17
+ */
18
+ export declare function pastedCells(slice: Slice): Area | null;
19
+ export declare function fitSlice(nodeType: NodeType, slice: Slice): Node;
20
+ /**
21
+ * Clip or extend (repeat) the given set of cells to cover the given
22
+ * width and height. Will clip rowspan/colspan cells at the edges when
23
+ * they stick out.
24
+ *
25
+ * @internal
26
+ */
27
+ export declare function clipCells({ width, height, rows }: Area, newWidth: number, newHeight: number): Area;
28
+ /**
29
+ * Insert the given set of cells (as returned by `pastedCells`) into a
30
+ * table, at the position pointed at by rect.
31
+ *
32
+ * @internal
33
+ */
34
+ export declare function insertCells(state: EditorState, dispatch: (tr: Transaction) => void, tableStart: number, rect: Rect, cells: Area): void;
35
+ //# sourceMappingURL=copypaste.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"copypaste.d.ts","sourceRoot":"","sources":["../../src/utilities/copypaste.ts"],"names":[],"mappings":"AAYA,OAAO,EAAE,QAAQ,EAAE,IAAI,EAAE,QAAQ,EAAU,KAAK,EAAE,MAAM,mBAAmB,CAAC;AAG5E,OAAO,EAAE,WAAW,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAG7D,OAAO,EAAa,IAAI,EAAY,MAAM,eAAe,CAAC;AAG1D;;GAEG;AACH,MAAM,MAAM,IAAI,GAAG;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,QAAQ,EAAE,CAAA;CAAE,CAAC;AAIvE;;;;;GAKG;AACH,wBAAgB,WAAW,CAAC,KAAK,EAAE,KAAK,GAAG,IAAI,GAAG,IAAI,CA0CrD;AA+BD,wBAAgB,QAAQ,CAAC,QAAQ,EAAE,QAAQ,EAAE,KAAK,EAAE,KAAK,GAAG,IAAI,CAI/D;AAED;;;;;;GAMG;AACH,wBAAgB,SAAS,CACvB,EAAE,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,EAAE,IAAI,EAC7B,QAAQ,EAAE,MAAM,EAChB,SAAS,EAAE,MAAM,GAChB,IAAI,CAwDN;AA2ID;;;;;GAKG;AACH,wBAAgB,WAAW,CACzB,KAAK,EAAE,WAAW,EAClB,QAAQ,EAAE,CAAC,EAAE,EAAE,WAAW,KAAK,IAAI,EACnC,UAAU,EAAE,MAAM,EAClB,IAAI,EAAE,IAAI,EACV,KAAK,EAAE,IAAI,GACV,IAAI,CA8DN"}
@@ -0,0 +1,283 @@
1
+ // Utilities used for copy/paste handling.
2
+ //
3
+ // This module handles pasting cell content into tables, or pasting
4
+ // anything into a cell selection, as replacing a block of cells with
5
+ // the content of the selection. When pasting cells into a cell, that
6
+ // involves placing the block of pasted content so that its top left
7
+ // aligns with the selection cell, optionally extending the table to
8
+ // the right or bottom to make sure it is large enough. Pasting into a
9
+ // cell selection is different, here the cells in the selection are
10
+ // clipped to the selection's rectangle, optionally repeating the
11
+ // pasted cells when they are smaller than the selection.
12
+ import { Fragment, Slice } from 'prosemirror-model';
13
+ import { Transform } from 'prosemirror-transform';
14
+ import { CellSelection } from './CellSelection.js';
15
+ import { tableNodeTypes } from './tableNodeTypes.js';
16
+ import { TableMap } from './TableMap.js';
17
+ import { removeColSpan } from './util.js';
18
+ // Utilities to help with copying and pasting table cells
19
+ /**
20
+ * Get a rectangular area of cells from a slice, or null if the outer
21
+ * nodes of the slice aren't table cells or rows.
22
+ *
23
+ * @internal
24
+ */
25
+ export function pastedCells(slice) {
26
+ if (!slice.size)
27
+ return null;
28
+ let { content, openStart, openEnd } = slice;
29
+ while (content.childCount == 1 &&
30
+ ((openStart > 0 && openEnd > 0) ||
31
+ content.child(0).type.spec.tableRole == 'table')) {
32
+ openStart--;
33
+ openEnd--;
34
+ content = content.child(0).content;
35
+ }
36
+ const first = content.child(0);
37
+ const role = first.type.spec.tableRole;
38
+ const schema = first.type.schema, rows = [];
39
+ if (role == 'row') {
40
+ for (let i = 0; i < content.childCount; i++) {
41
+ let cells = content.child(i).content;
42
+ const left = i ? 0 : Math.max(0, openStart - 1);
43
+ const right = i < content.childCount - 1 ? 0 : Math.max(0, openEnd - 1);
44
+ if (left || right) {
45
+ cells = fitSlice(tableNodeTypes(schema).row, new Slice(cells, left, right)).content;
46
+ }
47
+ rows.push(cells);
48
+ }
49
+ }
50
+ else if (role == 'cell' || role == 'header_cell') {
51
+ rows.push(openStart || openEnd
52
+ ? fitSlice(tableNodeTypes(schema).row, new Slice(content, openStart, openEnd)).content
53
+ : content);
54
+ }
55
+ else {
56
+ return null;
57
+ }
58
+ return ensureRectangular(schema, rows);
59
+ }
60
+ // Compute the width and height of a set of cells, and make sure each
61
+ // row has the same number of cells.
62
+ function ensureRectangular(schema, rows) {
63
+ const widths = [];
64
+ for (let i = 0; i < rows.length; i++) {
65
+ const row = rows[i];
66
+ for (let j = row.childCount - 1; j >= 0; j--) {
67
+ const { rowspan, colspan } = row.child(j).attrs;
68
+ for (let r = i; r < i + rowspan; r++) {
69
+ widths[r] = (widths[r] || 0) + colspan;
70
+ }
71
+ }
72
+ }
73
+ let width = 0;
74
+ for (let r = 0; r < widths.length; r++)
75
+ width = Math.max(width, widths[r]);
76
+ for (let r = 0; r < widths.length; r++) {
77
+ if (r >= rows.length)
78
+ rows.push(Fragment.empty);
79
+ if (widths[r] < width) {
80
+ const empty = tableNodeTypes(schema).cell.createAndFill();
81
+ const cells = [];
82
+ for (let i = widths[r]; i < width; i++) {
83
+ cells.push(empty);
84
+ }
85
+ rows[r] = rows[r].append(Fragment.from(cells));
86
+ }
87
+ }
88
+ return { height: rows.length, width, rows };
89
+ }
90
+ export function fitSlice(nodeType, slice) {
91
+ const node = nodeType.createAndFill();
92
+ const tr = new Transform(node).replace(0, node.content.size, slice);
93
+ return tr.doc;
94
+ }
95
+ /**
96
+ * Clip or extend (repeat) the given set of cells to cover the given
97
+ * width and height. Will clip rowspan/colspan cells at the edges when
98
+ * they stick out.
99
+ *
100
+ * @internal
101
+ */
102
+ export function clipCells({ width, height, rows }, newWidth, newHeight) {
103
+ if (width != newWidth) {
104
+ const added = [];
105
+ const newRows = [];
106
+ for (let row = 0; row < rows.length; row++) {
107
+ const frag = rows[row], cells = [];
108
+ for (let col = added[row] || 0, i = 0; col < newWidth; i++) {
109
+ let cell = frag.child(i % frag.childCount);
110
+ if (col + cell.attrs.colspan > newWidth) {
111
+ cell = cell.type.createChecked(removeColSpan(cell.attrs, cell.attrs.colspan, col + cell.attrs.colspan - newWidth), cell.content);
112
+ }
113
+ cells.push(cell);
114
+ col += cell.attrs.colspan;
115
+ for (let j = 1; j < cell.attrs.rowspan; j++) {
116
+ added[row + j] = (added[row + j] || 0) + cell.attrs.colspan;
117
+ }
118
+ }
119
+ newRows.push(Fragment.from(cells));
120
+ }
121
+ rows = newRows;
122
+ width = newWidth;
123
+ }
124
+ if (height != newHeight) {
125
+ const newRows = [];
126
+ for (let row = 0, i = 0; row < newHeight; row++, i++) {
127
+ const cells = [], source = rows[i % height];
128
+ for (let j = 0; j < source.childCount; j++) {
129
+ let cell = source.child(j);
130
+ if (row + cell.attrs.rowspan > newHeight) {
131
+ cell = cell.type.create({
132
+ ...cell.attrs,
133
+ rowspan: Math.max(1, newHeight - cell.attrs.rowspan),
134
+ }, cell.content);
135
+ }
136
+ cells.push(cell);
137
+ }
138
+ newRows.push(Fragment.from(cells));
139
+ }
140
+ rows = newRows;
141
+ height = newHeight;
142
+ }
143
+ return { width, height, rows };
144
+ }
145
+ // Make sure a table has at least the given width and height. Return
146
+ // true if something was changed.
147
+ function growTable(tr, map, table, start, width, height, mapFrom) {
148
+ const schema = tr.doc.type.schema;
149
+ const types = tableNodeTypes(schema);
150
+ let empty;
151
+ let emptyHead;
152
+ if (width > map.width) {
153
+ for (let row = 0, rowEnd = 0; row < map.height; row++) {
154
+ const rowNode = table.child(row);
155
+ rowEnd += rowNode.nodeSize;
156
+ const cells = [];
157
+ let add;
158
+ if (rowNode.lastChild == null || rowNode.lastChild.type == types.cell) {
159
+ add = empty || (empty = types.cell.createAndFill());
160
+ }
161
+ else {
162
+ add = emptyHead ||
163
+ (emptyHead = types.header_cell.createAndFill());
164
+ }
165
+ for (let i = map.width; i < width; i++)
166
+ cells.push(add);
167
+ tr.insert(tr.mapping.slice(mapFrom).map(rowEnd - 1 + start), cells);
168
+ }
169
+ }
170
+ if (height > map.height) {
171
+ const cells = [];
172
+ for (let i = 0, start = (map.height - 1) * map.width; i < Math.max(map.width, width); i++) {
173
+ const header = i >= map.width
174
+ ? false
175
+ : table.nodeAt(map.map[start + i]).type == types.header_cell;
176
+ cells.push(header
177
+ ? emptyHead || (emptyHead = types.header_cell.createAndFill())
178
+ : empty || (empty = types.cell.createAndFill()));
179
+ }
180
+ const emptyRow = types.row.create(null, Fragment.from(cells)), rows = [];
181
+ for (let i = map.height; i < height; i++)
182
+ rows.push(emptyRow);
183
+ tr.insert(tr.mapping.slice(mapFrom).map(start + table.nodeSize - 2), rows);
184
+ }
185
+ return !!(empty || emptyHead);
186
+ }
187
+ // Make sure the given line (left, top) to (right, top) doesn't cross
188
+ // any rowspan cells by splitting cells that cross it. Return true if
189
+ // something changed.
190
+ function isolateHorizontal(tr, map, table, start, left, right, top, mapFrom) {
191
+ if (top == 0 || top == map.height)
192
+ return false;
193
+ let found = false;
194
+ for (let col = left; col < right; col++) {
195
+ const index = top * map.width + col, pos = map.map[index];
196
+ if (map.map[index - map.width] == pos) {
197
+ found = true;
198
+ const cell = table.nodeAt(pos);
199
+ const { top: cellTop, left: cellLeft } = map.findCell(pos);
200
+ tr.setNodeMarkup(tr.mapping.slice(mapFrom).map(pos + start), null, {
201
+ ...cell.attrs,
202
+ rowspan: top - cellTop,
203
+ });
204
+ tr.insert(tr.mapping.slice(mapFrom).map(map.positionAt(top, cellLeft, table)), cell.type.createAndFill({
205
+ ...cell.attrs,
206
+ rowspan: cellTop + cell.attrs.rowspan - top,
207
+ }));
208
+ col += cell.attrs.colspan - 1;
209
+ }
210
+ }
211
+ return found;
212
+ }
213
+ // Make sure the given line (left, top) to (left, bottom) doesn't
214
+ // cross any colspan cells by splitting cells that cross it. Return
215
+ // true if something changed.
216
+ function isolateVertical(tr, map, table, start, top, bottom, left, mapFrom) {
217
+ if (left == 0 || left == map.width)
218
+ return false;
219
+ let found = false;
220
+ for (let row = top; row < bottom; row++) {
221
+ const index = row * map.width + left, pos = map.map[index];
222
+ if (map.map[index - 1] == pos) {
223
+ found = true;
224
+ const cell = table.nodeAt(pos);
225
+ const cellLeft = map.colCount(pos);
226
+ const updatePos = tr.mapping.slice(mapFrom).map(pos + start);
227
+ tr.setNodeMarkup(updatePos, null, removeColSpan(cell.attrs, left - cellLeft, cell.attrs.colspan - (left - cellLeft)));
228
+ tr.insert(updatePos + cell.nodeSize, cell.type.createAndFill(removeColSpan(cell.attrs, 0, left - cellLeft)));
229
+ row += cell.attrs.rowspan - 1;
230
+ }
231
+ }
232
+ return found;
233
+ }
234
+ /**
235
+ * Insert the given set of cells (as returned by `pastedCells`) into a
236
+ * table, at the position pointed at by rect.
237
+ *
238
+ * @internal
239
+ */
240
+ export function insertCells(state, dispatch, tableStart, rect, cells) {
241
+ let table = tableStart ? state.doc.nodeAt(tableStart - 1) : state.doc;
242
+ if (!table) {
243
+ throw new Error('No table found');
244
+ }
245
+ let map = TableMap.get(table);
246
+ const { top, left } = rect;
247
+ const right = left + cells.width, bottom = top + cells.height;
248
+ const tr = state.tr;
249
+ let mapFrom = 0;
250
+ function recomp() {
251
+ table = tableStart ? tr.doc.nodeAt(tableStart - 1) : tr.doc;
252
+ if (!table) {
253
+ throw new Error('No table found');
254
+ }
255
+ map = TableMap.get(table);
256
+ mapFrom = tr.mapping.maps.length;
257
+ }
258
+ // Prepare the table to be large enough and not have any cells
259
+ // crossing the boundaries of the rectangle that we want to
260
+ // insert into. If anything about it changes, recompute the table
261
+ // map so that subsequent operations can see the current shape.
262
+ if (growTable(tr, map, table, tableStart, right, bottom, mapFrom))
263
+ recomp();
264
+ if (isolateHorizontal(tr, map, table, tableStart, left, right, top, mapFrom)) {
265
+ recomp();
266
+ }
267
+ if (isolateHorizontal(tr, map, table, tableStart, left, right, bottom, mapFrom)) {
268
+ recomp();
269
+ }
270
+ if (isolateVertical(tr, map, table, tableStart, top, bottom, left, mapFrom)) {
271
+ recomp();
272
+ }
273
+ if (isolateVertical(tr, map, table, tableStart, top, bottom, right, mapFrom)) {
274
+ recomp();
275
+ }
276
+ for (let row = top; row < bottom; row++) {
277
+ const from = map.positionAt(row, left, table), to = map.positionAt(row, right, table);
278
+ tr.replace(tr.mapping.slice(mapFrom).map(from + tableStart), tr.mapping.slice(mapFrom).map(to + tableStart), new Slice(cells.rows[row - top], 0, 0));
279
+ }
280
+ recomp();
281
+ tr.setSelection(new CellSelection(tr.doc.resolve(tableStart + map.positionAt(top, left, table)), tr.doc.resolve(tableStart + map.positionAt(bottom - 1, right - 1, table))));
282
+ dispatch(tr);
283
+ }
@@ -0,0 +1,3 @@
1
+ import { Fragment, Node as ProsemirrorNode, NodeType } from 'prosemirror-model';
2
+ export declare function createCell(cellType: NodeType, cellContent?: Fragment | ProsemirrorNode | Array<ProsemirrorNode>): ProsemirrorNode | null | undefined;
3
+ //# sourceMappingURL=createCell.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"createCell.d.ts","sourceRoot":"","sources":["../../src/utilities/createCell.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,IAAI,IAAI,eAAe,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AAEhF,wBAAgB,UAAU,CACxB,QAAQ,EAAE,QAAQ,EAClB,WAAW,CAAC,EAAE,QAAQ,GAAG,eAAe,GAAG,KAAK,CAAC,eAAe,CAAC,GAChE,eAAe,GAAG,IAAI,GAAG,SAAS,CAMpC"}
@@ -0,0 +1,6 @@
1
+ export function createCell(cellType, cellContent) {
2
+ if (cellContent) {
3
+ return cellType.createChecked(null, cellContent);
4
+ }
5
+ return cellType.createAndFill();
6
+ }
@@ -0,0 +1,3 @@
1
+ import { Fragment, Node as ProsemirrorNode, Schema } from 'prosemirror-model';
2
+ export declare function createTable(schema: Schema, rowsCount: number, colsCount: number, withHeaderRow: boolean, cellContent?: Fragment | ProsemirrorNode | Array<ProsemirrorNode>): ProsemirrorNode;
3
+ //# sourceMappingURL=createTable.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"createTable.d.ts","sourceRoot":"","sources":["../../src/utilities/createTable.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,IAAI,IAAI,eAAe,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAC;AAK9E,wBAAgB,WAAW,CACzB,MAAM,EAAE,MAAM,EACd,SAAS,EAAE,MAAM,EACjB,SAAS,EAAE,MAAM,EACjB,aAAa,EAAE,OAAO,EACtB,WAAW,CAAC,EAAE,QAAQ,GAAG,eAAe,GAAG,KAAK,CAAC,eAAe,CAAC,GAChE,eAAe,CAwCjB"}
@@ -0,0 +1,30 @@
1
+ import { createCell } from './createCell.js';
2
+ import { getTableNodeTypes } from './getTableNodeTypes.js';
3
+ export function createTable(schema, rowsCount, colsCount, withHeaderRow, cellContent) {
4
+ const types = getTableNodeTypes(schema);
5
+ const headerCells = [];
6
+ const cells = [];
7
+ for (let index = 0; index < colsCount; index += 1) {
8
+ const cell = createCell(types.cell, cellContent);
9
+ if (cell) {
10
+ cells.push(cell);
11
+ }
12
+ if (withHeaderRow) {
13
+ const headerCell = createCell(types.header_cell, cellContent);
14
+ if (headerCell) {
15
+ headerCells.push(headerCell);
16
+ }
17
+ }
18
+ }
19
+ const rows = [];
20
+ for (let index = 0; index < rowsCount; index += 1) {
21
+ rows.push(types.row.createChecked(null, withHeaderRow && index === 0 ? headerCells : cells));
22
+ }
23
+ const attrs = {};
24
+ for (const [key, attrSpec] of Object.entries(types.table.attrs)) {
25
+ if ('undefined' !== typeof attrSpec.default) {
26
+ attrs[key] = attrSpec.default;
27
+ }
28
+ }
29
+ return types.table.createChecked(attrs, rows);
30
+ }
@@ -0,0 +1,18 @@
1
+ import { Node } from 'prosemirror-model';
2
+ import { EditorState, Transaction } from 'prosemirror-state';
3
+ /**
4
+ * @public
5
+ */
6
+ export declare const fixTablesKey: any;
7
+ /**
8
+ * Inspect all tables in the given state's document and return a
9
+ * transaction that fixes them, if necessary. If `oldState` was
10
+ * provided, that is assumed to hold a previous, known-good state,
11
+ * which will be used to avoid re-scanning unchanged parts of the
12
+ * document.
13
+ *
14
+ * @public
15
+ */
16
+ export declare function fixTables(state: EditorState, oldState?: EditorState): Transaction | undefined;
17
+ export declare function fixTable(state: EditorState, table: Node, tablePos: number, tr: Transaction | undefined): Transaction | undefined;
18
+ //# sourceMappingURL=fixTables.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fixTables.d.ts","sourceRoot":"","sources":["../../src/utilities/fixTables.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,IAAI,EAAE,MAAM,mBAAmB,CAAC;AACzC,OAAO,EAAE,WAAW,EAAa,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAKxE;;GAEG;AACH,eAAO,MAAM,YAAY,KAAsD,CAAC;AAkChF;;;;;;;;GAQG;AACH,wBAAgB,SAAS,CACvB,KAAK,EAAE,WAAW,EAClB,QAAQ,CAAC,EAAE,WAAW,GACrB,WAAW,GAAG,SAAS,CAYzB;AAID,wBAAgB,QAAQ,CACtB,KAAK,EAAE,WAAW,EAClB,KAAK,EAAE,IAAI,EACX,QAAQ,EAAE,MAAM,EAChB,EAAE,EAAE,WAAW,GAAG,SAAS,GAC1B,WAAW,GAAG,SAAS,CA0EzB"}
@@ -0,0 +1,146 @@
1
+ // This file defines helpers for normalizing tables, making sure no
2
+ // cells overlap (which can happen, if you have the wrong col- and
3
+ // rowspans) and that each row has the same width. Uses the problems
4
+ // reported by `TableMap`.
5
+ import { PluginKey } from 'prosemirror-state';
6
+ import { tableNodeTypes } from './tableNodeTypes.js';
7
+ import { TableMap } from './TableMap.js';
8
+ import { removeColSpan } from './util.js';
9
+ /**
10
+ * @public
11
+ */
12
+ export const fixTablesKey = new PluginKey('fix-tables');
13
+ /**
14
+ * Helper for iterating through the nodes in a document that changed
15
+ * compared to the given previous document. Useful for avoiding
16
+ * duplicate work on each transaction.
17
+ *
18
+ * @public
19
+ */
20
+ function changedDescendants(old, cur, offset, f) {
21
+ const oldSize = old.childCount, curSize = cur.childCount;
22
+ outer: for (let i = 0, j = 0; i < curSize; i++) {
23
+ const child = cur.child(i);
24
+ for (let scan = j, e = Math.min(oldSize, i + 3); scan < e; scan++) {
25
+ if (old.child(scan) == child) {
26
+ j = scan + 1;
27
+ offset += child.nodeSize;
28
+ continue outer;
29
+ }
30
+ }
31
+ f(child, offset);
32
+ if (j < oldSize && old.child(j).sameMarkup(child)) {
33
+ changedDescendants(old.child(j), child, offset + 1, f);
34
+ }
35
+ else
36
+ child.nodesBetween(0, child.content.size, f, offset + 1);
37
+ offset += child.nodeSize;
38
+ }
39
+ }
40
+ /**
41
+ * Inspect all tables in the given state's document and return a
42
+ * transaction that fixes them, if necessary. If `oldState` was
43
+ * provided, that is assumed to hold a previous, known-good state,
44
+ * which will be used to avoid re-scanning unchanged parts of the
45
+ * document.
46
+ *
47
+ * @public
48
+ */
49
+ export function fixTables(state, oldState) {
50
+ let tr;
51
+ const check = (node, pos) => {
52
+ if (node.type.spec.tableRole == 'table') {
53
+ tr = fixTable(state, node, pos, tr);
54
+ }
55
+ };
56
+ if (!oldState)
57
+ state.doc.descendants(check);
58
+ else if (oldState.doc != state.doc) {
59
+ changedDescendants(oldState.doc, state.doc, 0, check);
60
+ }
61
+ return tr;
62
+ }
63
+ // Fix the given table, if necessary. Will append to the transaction
64
+ // it was given, if non-null, or create a new one if necessary.
65
+ export function fixTable(state, table, tablePos, tr) {
66
+ const map = TableMap.get(table);
67
+ if (!map.problems)
68
+ return tr;
69
+ if (!tr)
70
+ tr = state.tr;
71
+ // Track which rows we must add cells to, so that we can adjust that
72
+ // when fixing collisions.
73
+ const mustAdd = [];
74
+ for (let i = 0; i < map.height; i++)
75
+ mustAdd.push(0);
76
+ for (let i = 0; i < map.problems.length; i++) {
77
+ const prob = map.problems[i];
78
+ if (prob.type == 'collision') {
79
+ const cell = table.nodeAt(prob.pos);
80
+ if (!cell)
81
+ continue;
82
+ const attrs = cell.attrs;
83
+ for (let j = 0; j < attrs.rowspan; j++)
84
+ mustAdd[prob.row + j] += prob.n;
85
+ tr.setNodeMarkup(tr.mapping.map(tablePos + 1 + prob.pos), null, removeColSpan(attrs, attrs.colspan - prob.n, prob.n));
86
+ }
87
+ else if (prob.type == 'missing') {
88
+ mustAdd[prob.row] += prob.n;
89
+ }
90
+ else if (prob.type == 'overlong_rowspan') {
91
+ const cell = table.nodeAt(prob.pos);
92
+ if (!cell)
93
+ continue;
94
+ tr.setNodeMarkup(tr.mapping.map(tablePos + 1 + prob.pos), null, {
95
+ ...cell.attrs,
96
+ rowspan: cell.attrs.rowspan - prob.n,
97
+ });
98
+ }
99
+ else if (prob.type == 'colwidth mismatch') {
100
+ const cell = table.nodeAt(prob.pos);
101
+ if (!cell)
102
+ continue;
103
+ tr.setNodeMarkup(tr.mapping.map(tablePos + 1 + prob.pos), null, {
104
+ ...cell.attrs,
105
+ colwidth: prob.colwidth,
106
+ });
107
+ }
108
+ else if (prob.type == 'zero_sized') {
109
+ const pos = tr.mapping.map(tablePos);
110
+ tr.delete(pos, pos + table.nodeSize);
111
+ }
112
+ }
113
+ let first, last;
114
+ for (let i = 0; i < mustAdd.length; i++) {
115
+ if (mustAdd[i]) {
116
+ if (first == null)
117
+ first = i;
118
+ last = i;
119
+ }
120
+ }
121
+ // Add the necessary cells, using a heuristic for whether to add the
122
+ // cells at the start or end of the rows (if it looks like a 'bite'
123
+ // was taken out of the table, add cells at the start of the row
124
+ // after the bite. Otherwise add them at the end).
125
+ for (let i = 0, pos = tablePos + 1; i < map.height; i++) {
126
+ const row = table.child(i);
127
+ const end = pos + row.nodeSize;
128
+ const add = mustAdd[i];
129
+ if (add > 0) {
130
+ let role = 'cell';
131
+ if (row.firstChild) {
132
+ role = row.firstChild.type.spec.tableRole;
133
+ }
134
+ const nodes = [];
135
+ for (let j = 0; j < add; j++) {
136
+ const node = tableNodeTypes(state.schema)[role].createAndFill();
137
+ if (node)
138
+ nodes.push(node);
139
+ }
140
+ const side = (i == 0 || first == i - 1) && last == i ? pos + 1 : end - 1;
141
+ tr.insert(tr.mapping.map(side), nodes);
142
+ }
143
+ pos = end;
144
+ }
145
+ return tr.setMeta(fixTablesKey, { fixTables: true });
146
+ }
@@ -0,0 +1,5 @@
1
+ import { NodeType, Schema } from 'prosemirror-model';
2
+ export declare function getTableNodeTypes(schema: Schema): {
3
+ [key: string]: NodeType;
4
+ };
5
+ //# sourceMappingURL=getTableNodeTypes.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"getTableNodeTypes.d.ts","sourceRoot":"","sources":["../../src/utilities/getTableNodeTypes.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAC;AAErD,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,MAAM,GAAG;IAAE,CAAC,GAAG,EAAE,MAAM,GAAG,QAAQ,CAAA;CAAE,CAkB7E"}
@@ -0,0 +1,14 @@
1
+ export function getTableNodeTypes(schema) {
2
+ if (schema.cached.tableNodeTypes) {
3
+ return schema.cached.tableNodeTypes;
4
+ }
5
+ const roles = {};
6
+ Object.keys(schema.nodes).forEach((type) => {
7
+ const nodeType = schema.nodes[type];
8
+ if (nodeType.spec.tableRole) {
9
+ roles[nodeType.spec.tableRole] = nodeType;
10
+ }
11
+ });
12
+ schema.cached.tableNodeTypes = roles;
13
+ return roles;
14
+ }
@@ -0,0 +1,21 @@
1
+ import { Slice } from 'prosemirror-model';
2
+ import { Command } from 'prosemirror-state';
3
+ import { EditorView } from 'prosemirror-view';
4
+ type Axis = 'horiz' | 'vert';
5
+ /**
6
+ * @public
7
+ */
8
+ export type Direction = -1 | 1;
9
+ export declare const handleKeyDown: any;
10
+ /**
11
+ * @internal
12
+ */
13
+ export declare function arrow(axis: Axis, dir: Direction): Command;
14
+ export declare function handleTripleClick(view: EditorView, pos: number): boolean;
15
+ /**
16
+ * @public
17
+ */
18
+ export declare function handlePaste(view: EditorView, _: ClipboardEvent, slice: Slice): boolean;
19
+ export declare function handleMouseDown(view: EditorView, startEvent: MouseEvent): void;
20
+ export {};
21
+ //# sourceMappingURL=input.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"input.d.ts","sourceRoot":"","sources":["../../src/utilities/input.ts"],"names":[],"mappings":"AAIA,OAAO,EAAyB,KAAK,EAAE,MAAM,mBAAmB,CAAC;AACjE,OAAO,EACL,OAAO,EAKR,MAAM,mBAAmB,CAAC;AAE3B,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAe9C,KAAK,IAAI,GAAG,OAAO,GAAG,MAAM,CAAC;AAE7B;;GAEG;AACH,MAAM,MAAM,SAAS,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC;AAE/B,eAAO,MAAM,aAAa,KAexB,CAAC;AAYH;;GAEG;AACH,wBAAgB,KAAK,CAAC,IAAI,EAAE,IAAI,EAAE,GAAG,EAAE,SAAS,GAAG,OAAO,CA+BzD;AAyBD,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,UAAU,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAMxE;AAED;;GAEG;AACH,wBAAgB,WAAW,CACzB,IAAI,EAAE,UAAU,EAChB,CAAC,EAAE,cAAc,EACjB,KAAK,EAAE,KAAK,GACX,OAAO,CAuCT;AAED,wBAAgB,eAAe,CAC7B,IAAI,EAAE,UAAU,EAChB,UAAU,EAAE,UAAU,GACrB,IAAI,CAqEN"}