@atlaskit/editor-tables 2.2.2 → 2.2.4
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/CHANGELOG.md +14 -0
- package/dist/cjs/cell-selection.js +17 -1
- package/dist/cjs/pm-plugins/input.js +15 -0
- package/dist/cjs/table-map.js +32 -0
- package/dist/cjs/utils/copy-paste.js +64 -2
- package/dist/cjs/utils/toggle-header.js +1 -0
- package/dist/cjs/version.json +1 -1
- package/dist/es2019/cell-selection.js +16 -1
- package/dist/es2019/pm-plugins/input.js +16 -0
- package/dist/es2019/table-map.js +27 -0
- package/dist/es2019/utils/copy-paste.js +63 -3
- package/dist/es2019/utils/toggle-header.js +1 -3
- package/dist/es2019/version.json +1 -1
- package/dist/esm/cell-selection.js +16 -1
- package/dist/esm/pm-plugins/input.js +15 -0
- package/dist/esm/table-map.js +32 -0
- package/dist/esm/utils/copy-paste.js +63 -3
- package/dist/esm/utils/toggle-header.js +1 -3
- package/dist/esm/version.json +1 -1
- package/dist/types/table-map.d.ts +4 -1
- package/dist/types/utils/toggle-header.d.ts +3 -0
- package/package.json +4 -4
- package/report.api.md +18 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,19 @@
|
|
|
1
1
|
# @atlaskit/editor-tables
|
|
2
2
|
|
|
3
|
+
## 2.2.4
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- [`4080eb013ef`](https://bitbucket.org/atlassian/atlassian-frontend/commits/4080eb013ef) - [ux] Fix bug where pasting inside a table did not respect the table's headers. Pasted cells are formatted based on the table they are being pasted into.
|
|
8
|
+
- [`4f6a895f1d5`](https://bitbucket.org/atlassian/atlassian-frontend/commits/4f6a895f1d5) - Set selectable property for selectable nodes
|
|
9
|
+
- [`4f6a895f1d5`](https://bitbucket.org/atlassian/atlassian-frontend/commits/4f6a895f1d5) - Fix arrow shift selection coming from outside of the table
|
|
10
|
+
|
|
11
|
+
## 2.2.3
|
|
12
|
+
|
|
13
|
+
### Patch Changes
|
|
14
|
+
|
|
15
|
+
- [`dbef481f7df`](https://bitbucket.org/atlassian/atlassian-frontend/commits/dbef481f7df) - [ux] ED-15724: fix the merged row(2nd row or later) cannot been recongnized as row selection and cannot be deleted.
|
|
16
|
+
|
|
3
17
|
## 2.2.2
|
|
4
18
|
|
|
5
19
|
### Patch Changes
|
|
@@ -265,9 +265,25 @@ var CellSelection = /*#__PURE__*/function (_Selection) {
|
|
|
265
265
|
return false;
|
|
266
266
|
}
|
|
267
267
|
|
|
268
|
+
var start = this.$anchorCell.start(-1);
|
|
269
|
+
|
|
268
270
|
var map = _tableMap.TableMap.get(this.$anchorCell.node(-1));
|
|
269
271
|
|
|
270
|
-
var
|
|
272
|
+
var rowAtAnchorCell = map.rowCount(this.$anchorCell.pos - start);
|
|
273
|
+
var rowAtHeadCell = map.rowCount(this.$headCell.pos - start);
|
|
274
|
+
var isSelectionSameRow = rowAtAnchorCell === rowAtHeadCell; // if anchor and head in the same line, counting how many cells
|
|
275
|
+
// should be in the row except merged cell
|
|
276
|
+
|
|
277
|
+
var maxColumnInSelectedRow = map.getMaxColInRow(this.$anchorCell); // if selected cells less than table max column amount, and
|
|
278
|
+
// the anchor/head not in a merged cell
|
|
279
|
+
// it should be select maxColumnInSelectedRow to be TRUE
|
|
280
|
+
|
|
281
|
+
if (isSelectionSameRow && this.ranges.length <= map.width && !map.isPosMerged(this.$anchorCell.pos - start) && !map.isPosMerged(this.$headCell.pos - start)) {
|
|
282
|
+
return this.ranges.length === maxColumnInSelectedRow;
|
|
283
|
+
} // If anchor and head in different row, it should be always in first and
|
|
284
|
+
// last column to select the whole row.
|
|
285
|
+
|
|
286
|
+
|
|
271
287
|
var anchorLeft = map.colCount(this.$anchorCell.pos - start);
|
|
272
288
|
var headLeft = map.colCount(this.$headCell.pos - start);
|
|
273
289
|
|
|
@@ -100,12 +100,27 @@ function shiftArrow(axis, dir) {
|
|
|
100
100
|
var sel = state.selection;
|
|
101
101
|
|
|
102
102
|
if (!(sel instanceof _cellSelection.CellSelection)) {
|
|
103
|
+
var _maybeTableCell$paren;
|
|
104
|
+
|
|
103
105
|
var end = view ? atEndOfCell(view, axis, dir) : null;
|
|
104
106
|
|
|
105
107
|
if (end === null) {
|
|
106
108
|
return false;
|
|
107
109
|
}
|
|
108
110
|
|
|
111
|
+
var _state$selection = state.selection,
|
|
112
|
+
_$head = _state$selection.$head,
|
|
113
|
+
$anchor = _state$selection.$anchor;
|
|
114
|
+
|
|
115
|
+
var maybeTableCell = _$head.blockRange($anchor); // Make sure the selection is coming from the same cell
|
|
116
|
+
|
|
117
|
+
|
|
118
|
+
var sameCell = ['tableCell', 'tableHeader'].includes((maybeTableCell === null || maybeTableCell === void 0 ? void 0 : (_maybeTableCell$paren = maybeTableCell.parent) === null || _maybeTableCell$paren === void 0 ? void 0 : _maybeTableCell$paren.type.name) || '');
|
|
119
|
+
|
|
120
|
+
if (!sameCell) {
|
|
121
|
+
return false;
|
|
122
|
+
}
|
|
123
|
+
|
|
109
124
|
sel = new _cellSelection.CellSelection(state.doc.resolve(end));
|
|
110
125
|
}
|
|
111
126
|
|
package/dist/cjs/table-map.js
CHANGED
|
@@ -143,6 +143,29 @@ var TableMap = /*#__PURE__*/function () {
|
|
|
143
143
|
}
|
|
144
144
|
|
|
145
145
|
throw new RangeError('No cell with offset ' + pos + ' found');
|
|
146
|
+
} // Find the top side of the cell at the given position.
|
|
147
|
+
|
|
148
|
+
}, {
|
|
149
|
+
key: "rowCount",
|
|
150
|
+
value: function rowCount(pos) {
|
|
151
|
+
if (this.width <= 0) {
|
|
152
|
+
throw new RangeError('Wrong table width found');
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
for (var i = 0; i < this.map.length; i++) {
|
|
156
|
+
if (this.map[i] === pos) {
|
|
157
|
+
return Math.floor(i / this.width);
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
throw new RangeError('No cell with offset ' + pos + ' found');
|
|
162
|
+
}
|
|
163
|
+
}, {
|
|
164
|
+
key: "isPosMerged",
|
|
165
|
+
value: function isPosMerged(pos) {
|
|
166
|
+
return this.map.filter(function (cellPos) {
|
|
167
|
+
return cellPos === pos;
|
|
168
|
+
}).length > 1;
|
|
146
169
|
} // :: (number, string, number) → ?number
|
|
147
170
|
// Find the next cell in the given direction, starting from the cell
|
|
148
171
|
// at `pos`, if any.
|
|
@@ -239,6 +262,15 @@ var TableMap = /*#__PURE__*/function () {
|
|
|
239
262
|
|
|
240
263
|
rowStart = rowEnd;
|
|
241
264
|
}
|
|
265
|
+
}
|
|
266
|
+
}, {
|
|
267
|
+
key: "getMaxColInRow",
|
|
268
|
+
value: function getMaxColInRow(pos) {
|
|
269
|
+
var parentRowNode = pos.parent;
|
|
270
|
+
|
|
271
|
+
if (parentRowNode.type.name === 'tableRow') {
|
|
272
|
+
return parentRowNode.childCount;
|
|
273
|
+
}
|
|
242
274
|
} // :: (Node) → TableMap
|
|
243
275
|
// Find the table map for the given table node.
|
|
244
276
|
|
|
@@ -22,16 +22,41 @@ var _tableMap = require("../table-map");
|
|
|
22
22
|
|
|
23
23
|
var _colspan = require("./colspan");
|
|
24
24
|
|
|
25
|
+
var _selectionRect = require("./selection-rect");
|
|
26
|
+
|
|
25
27
|
var _tableNodeTypes = require("./table-node-types");
|
|
26
28
|
|
|
29
|
+
var _toggleHeader = require("./toggle-header");
|
|
30
|
+
|
|
27
31
|
function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); enumerableOnly && (symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; })), keys.push.apply(keys, symbols); } return keys; }
|
|
28
32
|
|
|
29
33
|
function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = null != arguments[i] ? arguments[i] : {}; i % 2 ? ownKeys(Object(source), !0).forEach(function (key) { (0, _defineProperty2.default)(target, key, source[key]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)) : ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } return target; }
|
|
30
34
|
|
|
31
35
|
// Utilities to help with copying and pasting table cells
|
|
32
|
-
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Replace any header cells with table cells.
|
|
39
|
+
*
|
|
40
|
+
* @param schema
|
|
41
|
+
* @param cells
|
|
42
|
+
* @returns Fragment with header cells converted to table cells
|
|
43
|
+
*/
|
|
44
|
+
function stripHeaderType(schema, cells) {
|
|
45
|
+
var newCells = [];
|
|
46
|
+
cells.forEach(function (cell) {
|
|
47
|
+
var _cellNodeType$createA;
|
|
48
|
+
|
|
49
|
+
// Convert to cell type if not already
|
|
50
|
+
var cellNodeType = (0, _tableNodeTypes.tableNodeTypes)(schema).cell;
|
|
51
|
+
var tableCell = cell.type === cellNodeType ? cell : (_cellNodeType$createA = cellNodeType.createAndFill(cell.attrs, cell.content, cell.marks)) !== null && _cellNodeType$createA !== void 0 ? _cellNodeType$createA : cell;
|
|
52
|
+
newCells.push(tableCell);
|
|
53
|
+
});
|
|
54
|
+
return _prosemirrorModel.Fragment.from(newCells);
|
|
55
|
+
} // : (Slice) → ?{width: number, height: number, rows: [Fragment]}
|
|
33
56
|
// Get a rectangular area of cells from a slice, or null if the outer
|
|
34
57
|
// nodes of the slice aren't table cells or rows.
|
|
58
|
+
|
|
59
|
+
|
|
35
60
|
function pastedCells(slice) {
|
|
36
61
|
if (!slice.size) {
|
|
37
62
|
return null;
|
|
@@ -78,7 +103,10 @@ function pastedCells(slice) {
|
|
|
78
103
|
return null;
|
|
79
104
|
}
|
|
80
105
|
|
|
81
|
-
|
|
106
|
+
var rowsWithoutHeaders = rows.map(function (row) {
|
|
107
|
+
return stripHeaderType(schema, row);
|
|
108
|
+
});
|
|
109
|
+
return ensureRectangular(schema, rowsWithoutHeaders);
|
|
82
110
|
} // : (Schema, [Fragment]) → {width: number, height: number, rows: [Fragment]}
|
|
83
111
|
// Compute the width and height of a set of cells, and make sure each
|
|
84
112
|
// row has the same number of cells.
|
|
@@ -364,12 +392,45 @@ function isolateVertical(tr, map, table, start, top, bottom, left, mapFrom) {
|
|
|
364
392
|
}
|
|
365
393
|
|
|
366
394
|
return found;
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
function applyHeaderCells(tr, tableMap, state, tableStart, table, headerRowEnabled, headerColumnEnabled) {
|
|
398
|
+
var schema = state.schema;
|
|
399
|
+
|
|
400
|
+
var setMarkup = function setMarkup(tr, row, col, headerEnabled) {
|
|
401
|
+
var cellPos = tableStart + tableMap.positionAt(row, col, table);
|
|
402
|
+
var cell = tr.doc.nodeAt(cellPos);
|
|
403
|
+
var newType = headerEnabled ? schema.nodes.tableHeader : schema.nodes.tableCell;
|
|
404
|
+
var isCellTypeChanged = newType !== (cell === null || cell === void 0 ? void 0 : cell.type);
|
|
405
|
+
var isCellTypeValid = [schema.nodes.tableCell, schema.nodes.tableHeader].includes(cell === null || cell === void 0 ? void 0 : cell.type);
|
|
406
|
+
|
|
407
|
+
if (isCellTypeChanged && isCellTypeValid) {
|
|
408
|
+
tr.setNodeMarkup(cellPos, newType, cell === null || cell === void 0 ? void 0 : cell.attrs, cell === null || cell === void 0 ? void 0 : cell.marks);
|
|
409
|
+
}
|
|
410
|
+
}; // For row === 0 && col === 0 it is enabled if either are enabled
|
|
411
|
+
|
|
412
|
+
|
|
413
|
+
setMarkup(tr, 0, 0, headerColumnEnabled || headerRowEnabled); // Header Column
|
|
414
|
+
|
|
415
|
+
for (var col = 1; col < tableMap.width; col++) {
|
|
416
|
+
setMarkup(tr, 0, col, headerRowEnabled);
|
|
417
|
+
} // Header Row
|
|
418
|
+
|
|
419
|
+
|
|
420
|
+
for (var row = 1; row < tableMap.height; row++) {
|
|
421
|
+
setMarkup(tr, row, 0, headerColumnEnabled);
|
|
422
|
+
}
|
|
367
423
|
} // Insert the given set of cells (as returned by `pastedCells`) into a
|
|
368
424
|
// table, at the position pointed at by rect.
|
|
369
425
|
|
|
370
426
|
|
|
371
427
|
function insertCells(state, dispatch, tableStart, rect, cells) {
|
|
372
428
|
var table = state.doc;
|
|
429
|
+
var newRect = (0, _selectionRect.selectedRect)(state);
|
|
430
|
+
var types = (0, _tableNodeTypes.tableNodeTypes)(state.schema); // Get if the header row and column are enabled on the original table
|
|
431
|
+
|
|
432
|
+
var headerRowEnabled = (0, _toggleHeader.isHeaderEnabledByType)('row', newRect, types);
|
|
433
|
+
var headerColumnEnabled = (0, _toggleHeader.isHeaderEnabledByType)('column', newRect, types);
|
|
373
434
|
|
|
374
435
|
if (tableStart) {
|
|
375
436
|
table = state.doc.nodeAt(tableStart - 1);
|
|
@@ -425,6 +486,7 @@ function insertCells(state, dispatch, tableStart, rect, cells) {
|
|
|
425
486
|
}
|
|
426
487
|
|
|
427
488
|
recomp();
|
|
489
|
+
applyHeaderCells(tr, map, state, tableStart, table, headerRowEnabled, headerColumnEnabled);
|
|
428
490
|
tr.setSelection(new _cellSelection.CellSelection(tr.doc.resolve(tableStart + map.positionAt(top, left, table)), tr.doc.resolve(tableStart + map.positionAt(bottom - 1, right - 1, table))));
|
|
429
491
|
dispatch(tr);
|
|
430
492
|
}
|
package/dist/cjs/version.json
CHANGED
|
@@ -245,8 +245,23 @@ export class CellSelection extends Selection {
|
|
|
245
245
|
return false;
|
|
246
246
|
}
|
|
247
247
|
|
|
248
|
-
const map = TableMap.get(this.$anchorCell.node(-1));
|
|
249
248
|
const start = this.$anchorCell.start(-1);
|
|
249
|
+
const map = TableMap.get(this.$anchorCell.node(-1));
|
|
250
|
+
const rowAtAnchorCell = map.rowCount(this.$anchorCell.pos - start);
|
|
251
|
+
const rowAtHeadCell = map.rowCount(this.$headCell.pos - start);
|
|
252
|
+
const isSelectionSameRow = rowAtAnchorCell === rowAtHeadCell; // if anchor and head in the same line, counting how many cells
|
|
253
|
+
// should be in the row except merged cell
|
|
254
|
+
|
|
255
|
+
let maxColumnInSelectedRow = map.getMaxColInRow(this.$anchorCell); // if selected cells less than table max column amount, and
|
|
256
|
+
// the anchor/head not in a merged cell
|
|
257
|
+
// it should be select maxColumnInSelectedRow to be TRUE
|
|
258
|
+
|
|
259
|
+
if (isSelectionSameRow && this.ranges.length <= map.width && !map.isPosMerged(this.$anchorCell.pos - start) && !map.isPosMerged(this.$headCell.pos - start)) {
|
|
260
|
+
return this.ranges.length === maxColumnInSelectedRow;
|
|
261
|
+
} // If anchor and head in different row, it should be always in first and
|
|
262
|
+
// last column to select the whole row.
|
|
263
|
+
|
|
264
|
+
|
|
250
265
|
const anchorLeft = map.colCount(this.$anchorCell.pos - start);
|
|
251
266
|
const headLeft = map.colCount(this.$headCell.pos - start);
|
|
252
267
|
|
|
@@ -82,12 +82,28 @@ function shiftArrow(axis, dir) {
|
|
|
82
82
|
let sel = state.selection;
|
|
83
83
|
|
|
84
84
|
if (!(sel instanceof CellSelection)) {
|
|
85
|
+
var _maybeTableCell$paren;
|
|
86
|
+
|
|
85
87
|
const end = view ? atEndOfCell(view, axis, dir) : null;
|
|
86
88
|
|
|
87
89
|
if (end === null) {
|
|
88
90
|
return false;
|
|
89
91
|
}
|
|
90
92
|
|
|
93
|
+
const {
|
|
94
|
+
selection: {
|
|
95
|
+
$head,
|
|
96
|
+
$anchor
|
|
97
|
+
}
|
|
98
|
+
} = state;
|
|
99
|
+
const maybeTableCell = $head.blockRange($anchor); // Make sure the selection is coming from the same cell
|
|
100
|
+
|
|
101
|
+
const sameCell = ['tableCell', 'tableHeader'].includes((maybeTableCell === null || maybeTableCell === void 0 ? void 0 : (_maybeTableCell$paren = maybeTableCell.parent) === null || _maybeTableCell$paren === void 0 ? void 0 : _maybeTableCell$paren.type.name) || '');
|
|
102
|
+
|
|
103
|
+
if (!sameCell) {
|
|
104
|
+
return false;
|
|
105
|
+
}
|
|
106
|
+
|
|
91
107
|
sel = new CellSelection(state.doc.resolve(end));
|
|
92
108
|
}
|
|
93
109
|
|
package/dist/es2019/table-map.js
CHANGED
|
@@ -122,6 +122,25 @@ export class TableMap {
|
|
|
122
122
|
}
|
|
123
123
|
|
|
124
124
|
throw new RangeError('No cell with offset ' + pos + ' found');
|
|
125
|
+
} // Find the top side of the cell at the given position.
|
|
126
|
+
|
|
127
|
+
|
|
128
|
+
rowCount(pos) {
|
|
129
|
+
if (this.width <= 0) {
|
|
130
|
+
throw new RangeError('Wrong table width found');
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
for (let i = 0; i < this.map.length; i++) {
|
|
134
|
+
if (this.map[i] === pos) {
|
|
135
|
+
return Math.floor(i / this.width);
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
throw new RangeError('No cell with offset ' + pos + ' found');
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
isPosMerged(pos) {
|
|
143
|
+
return this.map.filter(cellPos => cellPos === pos).length > 1;
|
|
125
144
|
} // :: (number, string, number) → ?number
|
|
126
145
|
// Find the next cell in the given direction, starting from the cell
|
|
127
146
|
// at `pos`, if any.
|
|
@@ -215,6 +234,14 @@ export class TableMap {
|
|
|
215
234
|
|
|
216
235
|
rowStart = rowEnd;
|
|
217
236
|
}
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
getMaxColInRow(pos) {
|
|
240
|
+
let parentRowNode = pos.parent;
|
|
241
|
+
|
|
242
|
+
if (parentRowNode.type.name === 'tableRow') {
|
|
243
|
+
return parentRowNode.childCount;
|
|
244
|
+
}
|
|
218
245
|
} // :: (Node) → TableMap
|
|
219
246
|
// Find the table map for the given table node.
|
|
220
247
|
|
|
@@ -14,11 +14,34 @@ import { Transform } from 'prosemirror-transform';
|
|
|
14
14
|
import { CellSelection } from '../cell-selection';
|
|
15
15
|
import { TableMap } from '../table-map';
|
|
16
16
|
import { removeColSpan } from './colspan';
|
|
17
|
-
import {
|
|
18
|
-
|
|
17
|
+
import { selectedRect } from './selection-rect';
|
|
18
|
+
import { tableNodeTypes } from './table-node-types';
|
|
19
|
+
import { isHeaderEnabledByType } from './toggle-header'; // Utilities to help with copying and pasting table cells
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Replace any header cells with table cells.
|
|
23
|
+
*
|
|
24
|
+
* @param schema
|
|
25
|
+
* @param cells
|
|
26
|
+
* @returns Fragment with header cells converted to table cells
|
|
27
|
+
*/
|
|
28
|
+
|
|
29
|
+
function stripHeaderType(schema, cells) {
|
|
30
|
+
const newCells = [];
|
|
31
|
+
cells.forEach(cell => {
|
|
32
|
+
var _cellNodeType$createA;
|
|
33
|
+
|
|
34
|
+
// Convert to cell type if not already
|
|
35
|
+
const cellNodeType = tableNodeTypes(schema).cell;
|
|
36
|
+
const tableCell = cell.type === cellNodeType ? cell : (_cellNodeType$createA = cellNodeType.createAndFill(cell.attrs, cell.content, cell.marks)) !== null && _cellNodeType$createA !== void 0 ? _cellNodeType$createA : cell;
|
|
37
|
+
newCells.push(tableCell);
|
|
38
|
+
});
|
|
39
|
+
return Fragment.from(newCells);
|
|
40
|
+
} // : (Slice) → ?{width: number, height: number, rows: [Fragment]}
|
|
19
41
|
// Get a rectangular area of cells from a slice, or null if the outer
|
|
20
42
|
// nodes of the slice aren't table cells or rows.
|
|
21
43
|
|
|
44
|
+
|
|
22
45
|
export function pastedCells(slice) {
|
|
23
46
|
if (!slice.size) {
|
|
24
47
|
return null;
|
|
@@ -69,7 +92,8 @@ export function pastedCells(slice) {
|
|
|
69
92
|
return null;
|
|
70
93
|
}
|
|
71
94
|
|
|
72
|
-
|
|
95
|
+
const rowsWithoutHeaders = rows.map(row => stripHeaderType(schema, row));
|
|
96
|
+
return ensureRectangular(schema, rowsWithoutHeaders);
|
|
73
97
|
} // : (Schema, [Fragment]) → {width: number, height: number, rows: [Fragment]}
|
|
74
98
|
// Compute the width and height of a set of cells, and make sure each
|
|
75
99
|
// row has the same number of cells.
|
|
@@ -356,12 +380,47 @@ function isolateVertical(tr, map, table, start, top, bottom, left, mapFrom) {
|
|
|
356
380
|
}
|
|
357
381
|
|
|
358
382
|
return found;
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
function applyHeaderCells(tr, tableMap, state, tableStart, table, headerRowEnabled, headerColumnEnabled) {
|
|
386
|
+
const {
|
|
387
|
+
schema
|
|
388
|
+
} = state;
|
|
389
|
+
|
|
390
|
+
const setMarkup = (tr, row, col, headerEnabled) => {
|
|
391
|
+
const cellPos = tableStart + tableMap.positionAt(row, col, table);
|
|
392
|
+
const cell = tr.doc.nodeAt(cellPos);
|
|
393
|
+
const newType = headerEnabled ? schema.nodes.tableHeader : schema.nodes.tableCell;
|
|
394
|
+
const isCellTypeChanged = newType !== (cell === null || cell === void 0 ? void 0 : cell.type);
|
|
395
|
+
const isCellTypeValid = [schema.nodes.tableCell, schema.nodes.tableHeader].includes(cell === null || cell === void 0 ? void 0 : cell.type);
|
|
396
|
+
|
|
397
|
+
if (isCellTypeChanged && isCellTypeValid) {
|
|
398
|
+
tr.setNodeMarkup(cellPos, newType, cell === null || cell === void 0 ? void 0 : cell.attrs, cell === null || cell === void 0 ? void 0 : cell.marks);
|
|
399
|
+
}
|
|
400
|
+
}; // For row === 0 && col === 0 it is enabled if either are enabled
|
|
401
|
+
|
|
402
|
+
|
|
403
|
+
setMarkup(tr, 0, 0, headerColumnEnabled || headerRowEnabled); // Header Column
|
|
404
|
+
|
|
405
|
+
for (let col = 1; col < tableMap.width; col++) {
|
|
406
|
+
setMarkup(tr, 0, col, headerRowEnabled);
|
|
407
|
+
} // Header Row
|
|
408
|
+
|
|
409
|
+
|
|
410
|
+
for (let row = 1; row < tableMap.height; row++) {
|
|
411
|
+
setMarkup(tr, row, 0, headerColumnEnabled);
|
|
412
|
+
}
|
|
359
413
|
} // Insert the given set of cells (as returned by `pastedCells`) into a
|
|
360
414
|
// table, at the position pointed at by rect.
|
|
361
415
|
|
|
362
416
|
|
|
363
417
|
export function insertCells(state, dispatch, tableStart, rect, cells) {
|
|
364
418
|
let table = state.doc;
|
|
419
|
+
const newRect = selectedRect(state);
|
|
420
|
+
const types = tableNodeTypes(state.schema); // Get if the header row and column are enabled on the original table
|
|
421
|
+
|
|
422
|
+
const headerRowEnabled = isHeaderEnabledByType('row', newRect, types);
|
|
423
|
+
const headerColumnEnabled = isHeaderEnabledByType('column', newRect, types);
|
|
365
424
|
|
|
366
425
|
if (tableStart) {
|
|
367
426
|
table = state.doc.nodeAt(tableStart - 1);
|
|
@@ -420,6 +479,7 @@ export function insertCells(state, dispatch, tableStart, rect, cells) {
|
|
|
420
479
|
}
|
|
421
480
|
|
|
422
481
|
recomp();
|
|
482
|
+
applyHeaderCells(tr, map, state, tableStart, table, headerRowEnabled, headerColumnEnabled);
|
|
423
483
|
tr.setSelection(new CellSelection(tr.doc.resolve(tableStart + map.positionAt(top, left, table)), tr.doc.resolve(tableStart + map.positionAt(bottom - 1, right - 1, table))));
|
|
424
484
|
dispatch(tr);
|
|
425
485
|
}
|
|
@@ -2,8 +2,7 @@ import { Rect } from '../table-map';
|
|
|
2
2
|
import { selectedRect } from './selection-rect';
|
|
3
3
|
import { tableNodeTypes } from './table-node-types';
|
|
4
4
|
import { isInTable } from './tables';
|
|
5
|
-
|
|
6
|
-
function isHeaderEnabledByType(type, rect, types) {
|
|
5
|
+
export function isHeaderEnabledByType(type, rect, types) {
|
|
7
6
|
// Get cell positions for first row or first column
|
|
8
7
|
const cellPositions = rect.map.cellsInRect({
|
|
9
8
|
left: 0,
|
|
@@ -23,7 +22,6 @@ function isHeaderEnabledByType(type, rect, types) {
|
|
|
23
22
|
return true;
|
|
24
23
|
} // Toggles between row/column header and normal cells (Only applies to first row/column).
|
|
25
24
|
|
|
26
|
-
|
|
27
25
|
export function toggleHeader(type) {
|
|
28
26
|
return function (state, dispatch) {
|
|
29
27
|
if (!isInTable(state)) {
|
package/dist/es2019/version.json
CHANGED
|
@@ -246,8 +246,23 @@ export var CellSelection = /*#__PURE__*/function (_Selection) {
|
|
|
246
246
|
return false;
|
|
247
247
|
}
|
|
248
248
|
|
|
249
|
-
var map = TableMap.get(this.$anchorCell.node(-1));
|
|
250
249
|
var start = this.$anchorCell.start(-1);
|
|
250
|
+
var map = TableMap.get(this.$anchorCell.node(-1));
|
|
251
|
+
var rowAtAnchorCell = map.rowCount(this.$anchorCell.pos - start);
|
|
252
|
+
var rowAtHeadCell = map.rowCount(this.$headCell.pos - start);
|
|
253
|
+
var isSelectionSameRow = rowAtAnchorCell === rowAtHeadCell; // if anchor and head in the same line, counting how many cells
|
|
254
|
+
// should be in the row except merged cell
|
|
255
|
+
|
|
256
|
+
var maxColumnInSelectedRow = map.getMaxColInRow(this.$anchorCell); // if selected cells less than table max column amount, and
|
|
257
|
+
// the anchor/head not in a merged cell
|
|
258
|
+
// it should be select maxColumnInSelectedRow to be TRUE
|
|
259
|
+
|
|
260
|
+
if (isSelectionSameRow && this.ranges.length <= map.width && !map.isPosMerged(this.$anchorCell.pos - start) && !map.isPosMerged(this.$headCell.pos - start)) {
|
|
261
|
+
return this.ranges.length === maxColumnInSelectedRow;
|
|
262
|
+
} // If anchor and head in different row, it should be always in first and
|
|
263
|
+
// last column to select the whole row.
|
|
264
|
+
|
|
265
|
+
|
|
251
266
|
var anchorLeft = map.colCount(this.$anchorCell.pos - start);
|
|
252
267
|
var headLeft = map.colCount(this.$headCell.pos - start);
|
|
253
268
|
|
|
@@ -82,12 +82,27 @@ function shiftArrow(axis, dir) {
|
|
|
82
82
|
var sel = state.selection;
|
|
83
83
|
|
|
84
84
|
if (!(sel instanceof CellSelection)) {
|
|
85
|
+
var _maybeTableCell$paren;
|
|
86
|
+
|
|
85
87
|
var end = view ? atEndOfCell(view, axis, dir) : null;
|
|
86
88
|
|
|
87
89
|
if (end === null) {
|
|
88
90
|
return false;
|
|
89
91
|
}
|
|
90
92
|
|
|
93
|
+
var _state$selection = state.selection,
|
|
94
|
+
_$head = _state$selection.$head,
|
|
95
|
+
$anchor = _state$selection.$anchor;
|
|
96
|
+
|
|
97
|
+
var maybeTableCell = _$head.blockRange($anchor); // Make sure the selection is coming from the same cell
|
|
98
|
+
|
|
99
|
+
|
|
100
|
+
var sameCell = ['tableCell', 'tableHeader'].includes((maybeTableCell === null || maybeTableCell === void 0 ? void 0 : (_maybeTableCell$paren = maybeTableCell.parent) === null || _maybeTableCell$paren === void 0 ? void 0 : _maybeTableCell$paren.type.name) || '');
|
|
101
|
+
|
|
102
|
+
if (!sameCell) {
|
|
103
|
+
return false;
|
|
104
|
+
}
|
|
105
|
+
|
|
91
106
|
sel = new CellSelection(state.doc.resolve(end));
|
|
92
107
|
}
|
|
93
108
|
|
package/dist/esm/table-map.js
CHANGED
|
@@ -130,6 +130,29 @@ export var TableMap = /*#__PURE__*/function () {
|
|
|
130
130
|
}
|
|
131
131
|
|
|
132
132
|
throw new RangeError('No cell with offset ' + pos + ' found');
|
|
133
|
+
} // Find the top side of the cell at the given position.
|
|
134
|
+
|
|
135
|
+
}, {
|
|
136
|
+
key: "rowCount",
|
|
137
|
+
value: function rowCount(pos) {
|
|
138
|
+
if (this.width <= 0) {
|
|
139
|
+
throw new RangeError('Wrong table width found');
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
for (var i = 0; i < this.map.length; i++) {
|
|
143
|
+
if (this.map[i] === pos) {
|
|
144
|
+
return Math.floor(i / this.width);
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
throw new RangeError('No cell with offset ' + pos + ' found');
|
|
149
|
+
}
|
|
150
|
+
}, {
|
|
151
|
+
key: "isPosMerged",
|
|
152
|
+
value: function isPosMerged(pos) {
|
|
153
|
+
return this.map.filter(function (cellPos) {
|
|
154
|
+
return cellPos === pos;
|
|
155
|
+
}).length > 1;
|
|
133
156
|
} // :: (number, string, number) → ?number
|
|
134
157
|
// Find the next cell in the given direction, starting from the cell
|
|
135
158
|
// at `pos`, if any.
|
|
@@ -226,6 +249,15 @@ export var TableMap = /*#__PURE__*/function () {
|
|
|
226
249
|
|
|
227
250
|
rowStart = rowEnd;
|
|
228
251
|
}
|
|
252
|
+
}
|
|
253
|
+
}, {
|
|
254
|
+
key: "getMaxColInRow",
|
|
255
|
+
value: function getMaxColInRow(pos) {
|
|
256
|
+
var parentRowNode = pos.parent;
|
|
257
|
+
|
|
258
|
+
if (parentRowNode.type.name === 'tableRow') {
|
|
259
|
+
return parentRowNode.childCount;
|
|
260
|
+
}
|
|
229
261
|
} // :: (Node) → TableMap
|
|
230
262
|
// Find the table map for the given table node.
|
|
231
263
|
|
|
@@ -20,11 +20,34 @@ import { Transform } from 'prosemirror-transform';
|
|
|
20
20
|
import { CellSelection } from '../cell-selection';
|
|
21
21
|
import { TableMap } from '../table-map';
|
|
22
22
|
import { removeColSpan } from './colspan';
|
|
23
|
-
import {
|
|
24
|
-
|
|
23
|
+
import { selectedRect } from './selection-rect';
|
|
24
|
+
import { tableNodeTypes } from './table-node-types';
|
|
25
|
+
import { isHeaderEnabledByType } from './toggle-header'; // Utilities to help with copying and pasting table cells
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Replace any header cells with table cells.
|
|
29
|
+
*
|
|
30
|
+
* @param schema
|
|
31
|
+
* @param cells
|
|
32
|
+
* @returns Fragment with header cells converted to table cells
|
|
33
|
+
*/
|
|
34
|
+
|
|
35
|
+
function stripHeaderType(schema, cells) {
|
|
36
|
+
var newCells = [];
|
|
37
|
+
cells.forEach(function (cell) {
|
|
38
|
+
var _cellNodeType$createA;
|
|
39
|
+
|
|
40
|
+
// Convert to cell type if not already
|
|
41
|
+
var cellNodeType = tableNodeTypes(schema).cell;
|
|
42
|
+
var tableCell = cell.type === cellNodeType ? cell : (_cellNodeType$createA = cellNodeType.createAndFill(cell.attrs, cell.content, cell.marks)) !== null && _cellNodeType$createA !== void 0 ? _cellNodeType$createA : cell;
|
|
43
|
+
newCells.push(tableCell);
|
|
44
|
+
});
|
|
45
|
+
return Fragment.from(newCells);
|
|
46
|
+
} // : (Slice) → ?{width: number, height: number, rows: [Fragment]}
|
|
25
47
|
// Get a rectangular area of cells from a slice, or null if the outer
|
|
26
48
|
// nodes of the slice aren't table cells or rows.
|
|
27
49
|
|
|
50
|
+
|
|
28
51
|
export function pastedCells(slice) {
|
|
29
52
|
if (!slice.size) {
|
|
30
53
|
return null;
|
|
@@ -71,7 +94,10 @@ export function pastedCells(slice) {
|
|
|
71
94
|
return null;
|
|
72
95
|
}
|
|
73
96
|
|
|
74
|
-
|
|
97
|
+
var rowsWithoutHeaders = rows.map(function (row) {
|
|
98
|
+
return stripHeaderType(schema, row);
|
|
99
|
+
});
|
|
100
|
+
return ensureRectangular(schema, rowsWithoutHeaders);
|
|
75
101
|
} // : (Schema, [Fragment]) → {width: number, height: number, rows: [Fragment]}
|
|
76
102
|
// Compute the width and height of a set of cells, and make sure each
|
|
77
103
|
// row has the same number of cells.
|
|
@@ -354,12 +380,45 @@ function isolateVertical(tr, map, table, start, top, bottom, left, mapFrom) {
|
|
|
354
380
|
}
|
|
355
381
|
|
|
356
382
|
return found;
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
function applyHeaderCells(tr, tableMap, state, tableStart, table, headerRowEnabled, headerColumnEnabled) {
|
|
386
|
+
var schema = state.schema;
|
|
387
|
+
|
|
388
|
+
var setMarkup = function setMarkup(tr, row, col, headerEnabled) {
|
|
389
|
+
var cellPos = tableStart + tableMap.positionAt(row, col, table);
|
|
390
|
+
var cell = tr.doc.nodeAt(cellPos);
|
|
391
|
+
var newType = headerEnabled ? schema.nodes.tableHeader : schema.nodes.tableCell;
|
|
392
|
+
var isCellTypeChanged = newType !== (cell === null || cell === void 0 ? void 0 : cell.type);
|
|
393
|
+
var isCellTypeValid = [schema.nodes.tableCell, schema.nodes.tableHeader].includes(cell === null || cell === void 0 ? void 0 : cell.type);
|
|
394
|
+
|
|
395
|
+
if (isCellTypeChanged && isCellTypeValid) {
|
|
396
|
+
tr.setNodeMarkup(cellPos, newType, cell === null || cell === void 0 ? void 0 : cell.attrs, cell === null || cell === void 0 ? void 0 : cell.marks);
|
|
397
|
+
}
|
|
398
|
+
}; // For row === 0 && col === 0 it is enabled if either are enabled
|
|
399
|
+
|
|
400
|
+
|
|
401
|
+
setMarkup(tr, 0, 0, headerColumnEnabled || headerRowEnabled); // Header Column
|
|
402
|
+
|
|
403
|
+
for (var col = 1; col < tableMap.width; col++) {
|
|
404
|
+
setMarkup(tr, 0, col, headerRowEnabled);
|
|
405
|
+
} // Header Row
|
|
406
|
+
|
|
407
|
+
|
|
408
|
+
for (var row = 1; row < tableMap.height; row++) {
|
|
409
|
+
setMarkup(tr, row, 0, headerColumnEnabled);
|
|
410
|
+
}
|
|
357
411
|
} // Insert the given set of cells (as returned by `pastedCells`) into a
|
|
358
412
|
// table, at the position pointed at by rect.
|
|
359
413
|
|
|
360
414
|
|
|
361
415
|
export function insertCells(state, dispatch, tableStart, rect, cells) {
|
|
362
416
|
var table = state.doc;
|
|
417
|
+
var newRect = selectedRect(state);
|
|
418
|
+
var types = tableNodeTypes(state.schema); // Get if the header row and column are enabled on the original table
|
|
419
|
+
|
|
420
|
+
var headerRowEnabled = isHeaderEnabledByType('row', newRect, types);
|
|
421
|
+
var headerColumnEnabled = isHeaderEnabledByType('column', newRect, types);
|
|
363
422
|
|
|
364
423
|
if (tableStart) {
|
|
365
424
|
table = state.doc.nodeAt(tableStart - 1);
|
|
@@ -414,6 +473,7 @@ export function insertCells(state, dispatch, tableStart, rect, cells) {
|
|
|
414
473
|
}
|
|
415
474
|
|
|
416
475
|
recomp();
|
|
476
|
+
applyHeaderCells(tr, map, state, tableStart, table, headerRowEnabled, headerColumnEnabled);
|
|
417
477
|
tr.setSelection(new CellSelection(tr.doc.resolve(tableStart + map.positionAt(top, left, table)), tr.doc.resolve(tableStart + map.positionAt(bottom - 1, right - 1, table))));
|
|
418
478
|
dispatch(tr);
|
|
419
479
|
}
|
|
@@ -2,8 +2,7 @@ import { Rect } from '../table-map';
|
|
|
2
2
|
import { selectedRect } from './selection-rect';
|
|
3
3
|
import { tableNodeTypes } from './table-node-types';
|
|
4
4
|
import { isInTable } from './tables';
|
|
5
|
-
|
|
6
|
-
function isHeaderEnabledByType(type, rect, types) {
|
|
5
|
+
export function isHeaderEnabledByType(type, rect, types) {
|
|
7
6
|
// Get cell positions for first row or first column
|
|
8
7
|
var cellPositions = rect.map.cellsInRect({
|
|
9
8
|
left: 0,
|
|
@@ -23,7 +22,6 @@ function isHeaderEnabledByType(type, rect, types) {
|
|
|
23
22
|
return true;
|
|
24
23
|
} // Toggles between row/column header and normal cells (Only applies to first row/column).
|
|
25
24
|
|
|
26
|
-
|
|
27
25
|
export function toggleHeader(type) {
|
|
28
26
|
return function (state, dispatch) {
|
|
29
27
|
if (!isInTable(state)) {
|
package/dist/esm/version.json
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Node as PMNode } from 'prosemirror-model';
|
|
1
|
+
import { Node as PMNode, ResolvedPos } from 'prosemirror-model';
|
|
2
2
|
import { Axis } from './types';
|
|
3
3
|
export declare class Rect {
|
|
4
4
|
left: number;
|
|
@@ -54,9 +54,12 @@ export declare class TableMap {
|
|
|
54
54
|
constructor(width: number, height: number, map: number[], problems?: TableProblem[] | null);
|
|
55
55
|
findCell(pos: number): Rect;
|
|
56
56
|
colCount(pos: number): number;
|
|
57
|
+
rowCount(pos: number): number;
|
|
58
|
+
isPosMerged(pos: number): boolean;
|
|
57
59
|
nextCell(pos: number, axis: Axis, dir: number): number | null;
|
|
58
60
|
rectBetween(a: number, b: number): Rect;
|
|
59
61
|
cellsInRect(rect: Rect): number[];
|
|
60
62
|
positionAt(row: number, col: number, table: PMNode): number;
|
|
63
|
+
getMaxColInRow(pos: ResolvedPos): number | undefined;
|
|
61
64
|
static get(table: PMNode): TableMap;
|
|
62
65
|
}
|
|
@@ -1,3 +1,6 @@
|
|
|
1
1
|
import { Command } from '../types';
|
|
2
|
+
import { SelectionRect } from './selection-rect';
|
|
3
|
+
import { TableNodeCache } from './table-node-types';
|
|
2
4
|
export declare type ToggleType = 'column' | 'row';
|
|
5
|
+
export declare function isHeaderEnabledByType(type: ToggleType, rect: SelectionRect, types: TableNodeCache): boolean;
|
|
3
6
|
export declare function toggleHeader(type: ToggleType): Command;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@atlaskit/editor-tables",
|
|
3
|
-
"version": "2.2.
|
|
3
|
+
"version": "2.2.4",
|
|
4
4
|
"description": "A package that contains common classes and utility functions for editor tables",
|
|
5
5
|
"publishConfig": {
|
|
6
6
|
"registry": "https://registry.npmjs.org/"
|
|
@@ -29,8 +29,8 @@
|
|
|
29
29
|
"prosemirror-view": "1.23.2"
|
|
30
30
|
},
|
|
31
31
|
"devDependencies": {
|
|
32
|
-
"@atlaskit/adf-schema": "^
|
|
33
|
-
"@atlaskit/editor-test-helpers": "^
|
|
32
|
+
"@atlaskit/adf-schema": "^25.1.0",
|
|
33
|
+
"@atlaskit/editor-test-helpers": "^18.0.0",
|
|
34
34
|
"@atlassian/atlassian-frontend-prettier-config-1.0.1": "npm:@atlassian/atlassian-frontend-prettier-config@1.0.1"
|
|
35
35
|
},
|
|
36
36
|
"techstack": {
|
|
@@ -49,4 +49,4 @@
|
|
|
49
49
|
}
|
|
50
50
|
},
|
|
51
51
|
"prettier": "@atlassian/atlassian-frontend-prettier-config-1.0.1"
|
|
52
|
-
}
|
|
52
|
+
}
|
package/report.api.md
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
<!-- API Report Version: 2.
|
|
1
|
+
<!-- API Report Version: 2.3 -->
|
|
2
2
|
|
|
3
3
|
## API Report File for "@atlaskit/editor-tables"
|
|
4
4
|
|
|
@@ -8,6 +8,7 @@
|
|
|
8
8
|
### Table of contents
|
|
9
9
|
|
|
10
10
|
- [Main Entry Types](#main-entry-types)
|
|
11
|
+
- [Peer Dependencies](#peer-dependencies)
|
|
11
12
|
|
|
12
13
|
### Main Entry Types
|
|
13
14
|
|
|
@@ -132,8 +133,12 @@ export class TableMap {
|
|
|
132
133
|
// (undocumented)
|
|
133
134
|
static get(table: Node_2): TableMap;
|
|
134
135
|
// (undocumented)
|
|
136
|
+
getMaxColInRow(pos: ResolvedPos): number | undefined;
|
|
137
|
+
// (undocumented)
|
|
135
138
|
height: number;
|
|
136
139
|
// (undocumented)
|
|
140
|
+
isPosMerged(pos: number): boolean;
|
|
141
|
+
// (undocumented)
|
|
137
142
|
map: number[];
|
|
138
143
|
// (undocumented)
|
|
139
144
|
nextCell(pos: number, axis: Axis, dir: number): null | number;
|
|
@@ -144,6 +149,8 @@ export class TableMap {
|
|
|
144
149
|
// (undocumented)
|
|
145
150
|
rectBetween(a: number, b: number): Rect;
|
|
146
151
|
// (undocumented)
|
|
152
|
+
rowCount(pos: number): number;
|
|
153
|
+
// (undocumented)
|
|
147
154
|
width: number;
|
|
148
155
|
}
|
|
149
156
|
|
|
@@ -205,3 +212,13 @@ export const uuid: {
|
|
|
205
212
|
```
|
|
206
213
|
|
|
207
214
|
<!--SECTION END: Main Entry Types-->
|
|
215
|
+
|
|
216
|
+
### Peer Dependencies
|
|
217
|
+
|
|
218
|
+
<!--SECTION START: Peer Dependencies-->
|
|
219
|
+
|
|
220
|
+
```json
|
|
221
|
+
{}
|
|
222
|
+
```
|
|
223
|
+
|
|
224
|
+
<!--SECTION END: Peer Dependencies-->
|