@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 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 start = this.$anchorCell.start(-1);
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
 
@@ -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
- // : (Slice) → ?{width: number, height: number, rows: [Fragment]}
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
- return ensureRectangular(schema, rows);
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
  }
@@ -3,6 +3,7 @@
3
3
  Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
+ exports.isHeaderEnabledByType = isHeaderEnabledByType;
6
7
  exports.toggleHeader = toggleHeader;
7
8
 
8
9
  var _tableMap = require("../table-map");
@@ -1,5 +1,5 @@
1
1
  {
2
2
  "name": "@atlaskit/editor-tables",
3
- "version": "2.2.2",
3
+ "version": "2.2.4",
4
4
  "sideEffects": false
5
5
  }
@@ -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
 
@@ -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 { tableNodeTypes } from './table-node-types'; // Utilities to help with copying and pasting table cells
18
- // : (Slice) → ?{width: number, height: number, rows: [Fragment]}
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
- return ensureRectangular(schema, rows);
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)) {
@@ -1,5 +1,5 @@
1
1
  {
2
2
  "name": "@atlaskit/editor-tables",
3
- "version": "2.2.2",
3
+ "version": "2.2.4",
4
4
  "sideEffects": false
5
5
  }
@@ -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
 
@@ -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 { tableNodeTypes } from './table-node-types'; // Utilities to help with copying and pasting table cells
24
- // : (Slice) → ?{width: number, height: number, rows: [Fragment]}
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
- return ensureRectangular(schema, rows);
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)) {
@@ -1,5 +1,5 @@
1
1
  {
2
2
  "name": "@atlaskit/editor-tables",
3
- "version": "2.2.2",
3
+ "version": "2.2.4",
4
4
  "sideEffects": false
5
5
  }
@@ -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.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": "^24.0.0",
33
- "@atlaskit/editor-test-helpers": "^17.2.0",
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.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-->