@atlaskit/editor-plugin-table 7.4.2 → 7.4.3

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 (28) hide show
  1. package/CHANGELOG.md +6 -0
  2. package/dist/cjs/ui/DragHandle/index.js +34 -2
  3. package/dist/cjs/ui/TableFloatingColumnControls/ColumnControls/index.js +1 -0
  4. package/dist/cjs/ui/TableFloatingControls/RowControls/DragControls.js +1 -0
  5. package/dist/cjs/utils/index.js +18 -0
  6. package/dist/cjs/utils/merged-cells.js +95 -1
  7. package/dist/es2019/ui/DragHandle/index.js +36 -2
  8. package/dist/es2019/ui/TableFloatingColumnControls/ColumnControls/index.js +1 -0
  9. package/dist/es2019/ui/TableFloatingControls/RowControls/DragControls.js +1 -0
  10. package/dist/es2019/utils/index.js +1 -1
  11. package/dist/es2019/utils/merged-cells.js +91 -0
  12. package/dist/esm/ui/DragHandle/index.js +35 -3
  13. package/dist/esm/ui/TableFloatingColumnControls/ColumnControls/index.js +1 -0
  14. package/dist/esm/ui/TableFloatingControls/RowControls/DragControls.js +1 -0
  15. package/dist/esm/utils/index.js +1 -1
  16. package/dist/esm/utils/merged-cells.js +94 -0
  17. package/dist/types/ui/DragHandle/index.d.ts +2 -1
  18. package/dist/types/utils/index.d.ts +1 -1
  19. package/dist/types/utils/merged-cells.d.ts +28 -0
  20. package/dist/types-ts4.5/ui/DragHandle/index.d.ts +2 -1
  21. package/dist/types-ts4.5/utils/index.d.ts +1 -1
  22. package/dist/types-ts4.5/utils/merged-cells.d.ts +28 -0
  23. package/package.json +1 -1
  24. package/src/ui/DragHandle/index.tsx +64 -9
  25. package/src/ui/TableFloatingColumnControls/ColumnControls/index.tsx +1 -0
  26. package/src/ui/TableFloatingControls/RowControls/DragControls.tsx +1 -0
  27. package/src/utils/index.ts +3 -0
  28. package/src/utils/merged-cells.ts +104 -0
package/CHANGELOG.md CHANGED
@@ -1,5 +1,11 @@
1
1
  # @atlaskit/editor-plugin-table
2
2
 
3
+ ## 7.4.3
4
+
5
+ ### Patch Changes
6
+
7
+ - [#72037](https://stash.atlassian.com/projects/CONFCLOUD/repos/confluence-frontend/pull-requests/72037) [`e59f0b7a9115`](https://stash.atlassian.com/projects/CONFCLOUD/repos/confluence-frontend/commits/e59f0b7a9115) - [ux] add flexiable to make merged cells detection allow to detect edge merged cells
8
+
3
9
  ## 7.4.2
4
10
 
5
11
  ### Patch Changes
@@ -14,6 +14,8 @@ var _reactDom = _interopRequireDefault(require("react-dom"));
14
14
  var _reactIntlNext = require("react-intl-next");
15
15
  var _messages = require("@atlaskit/editor-common/messages");
16
16
  var _utils = require("@atlaskit/editor-common/utils");
17
+ var _state = require("@atlaskit/editor-prosemirror/state");
18
+ var _editorTables = require("@atlaskit/editor-tables");
17
19
  var _adapter = require("@atlaskit/pragmatic-drag-and-drop/element/adapter");
18
20
  var _setCustomNativeDragPreview = require("@atlaskit/pragmatic-drag-and-drop/element/set-custom-native-drag-preview");
19
21
  var _pluginFactory = require("../../pm-plugins/drag-and-drop/plugin-factory");
@@ -40,6 +42,7 @@ var DragHandleComponent = function DragHandleComponent(_ref) {
40
42
  onMouseOver = _ref.onMouseOver,
41
43
  onMouseOut = _ref.onMouseOut,
42
44
  toggleDragMenu = _ref.toggleDragMenu,
45
+ hoveredCell = _ref.hoveredCell,
43
46
  onClick = _ref.onClick,
44
47
  editorView = _ref.editorView,
45
48
  formatMessage = _ref.intl.formatMessage;
@@ -60,8 +63,37 @@ var DragHandleComponent = function DragHandleComponent(_ref) {
60
63
  var isRowHandleHovered = isRow && hoveredRows.length > 0;
61
64
  var isColumnHandleHovered = isColumn && hoveredColumns.length > 0;
62
65
  var hasMergedCells = (0, _react.useMemo)(function () {
63
- return isRow ? (0, _utils2.hasMergedCellsInRow)(indexes[0])(selection) : (0, _utils2.hasMergedCellsInColumn)(indexes[0])(selection);
64
- }, [indexes, isRow, selection]);
66
+ var table = (0, _editorTables.findTable)(selection);
67
+ if (!table) {
68
+ return false;
69
+ }
70
+ var map = _editorTables.TableMap.get(table === null || table === void 0 ? void 0 : table.node);
71
+ if (!map.hasMergedCells() || indexes.length < 1) {
72
+ return false;
73
+ }
74
+ var mapByColumn = map.mapByColumn,
75
+ mapByRow = map.mapByRow;
76
+
77
+ // this handle when hover to first column or row which has merged cells.
78
+ if (hoveredCell && hoveredCell.rowIndex !== undefined && hoveredCell.colIndex !== undefined && selection instanceof _state.TextSelection) {
79
+ var rowIndex = hoveredCell.rowIndex,
80
+ colIndex = hoveredCell.colIndex;
81
+ var mergedPositionInRow = (0, _utils2.findDuplicatePosition)(mapByRow[rowIndex]);
82
+ var mergedPositionInCol = (0, _utils2.findDuplicatePosition)(mapByColumn[colIndex]);
83
+ var hasMergedCellsInFirstRowOrColumn = direction === 'column' ? mergedPositionInRow.includes(mapByRow[0][colIndex]) : mergedPositionInCol.includes(mapByColumn[0][rowIndex]);
84
+ var isHoveredOnFirstRowOrColumn = direction === 'column' ? hoveredCell.rowIndex === 0 && hasMergedCellsInFirstRowOrColumn : hoveredCell.colIndex === 0 && hasMergedCellsInFirstRowOrColumn;
85
+ if (isHoveredOnFirstRowOrColumn) {
86
+ var mergedSizes = direction === 'column' ? mapByRow[0].filter(function (el) {
87
+ return el === mapByRow[0][colIndex];
88
+ }).length : mapByColumn[0].filter(function (el) {
89
+ return el === mapByColumn[0][rowIndex];
90
+ }).length;
91
+ var mergedSelection = (0, _utils2.hasMergedCellsInSelection)(direction === 'column' ? [colIndex, colIndex + mergedSizes - 1] : [rowIndex, rowIndex + mergedSizes - 1], direction)(selection);
92
+ return mergedSelection;
93
+ }
94
+ }
95
+ return (0, _utils2.hasMergedCellsInSelection)(indexes, direction)(selection);
96
+ }, [indexes, selection, direction, hoveredCell]);
65
97
  var handleIconProps = {
66
98
  forceDefaultHandle: forceDefaultHandle,
67
99
  isHandleHovered: isColumnHandleHovered || isRowHandleHovered,
@@ -148,6 +148,7 @@ var ColumnControls = exports.ColumnControls = function ColumnControls(_ref) {
148
148
  direction: "column",
149
149
  tableLocalId: localId || '',
150
150
  indexes: indexes,
151
+ hoveredCell: hoveredCell,
151
152
  previewWidth: previewWidth,
152
153
  forceDefaultHandle: !isHover,
153
154
  previewHeight: previewHeight,
@@ -151,6 +151,7 @@ var DragControlsComponent = function DragControlsComponent(_ref) {
151
151
  previewWidth: tableWidth,
152
152
  previewHeight: previewHeight,
153
153
  appearance: appearance,
154
+ hoveredCell: hoveredCell,
154
155
  onClick: handleClick,
155
156
  onMouseOver: handleMouseOver,
156
157
  onMouseOut: handleMouseOut,
@@ -9,6 +9,12 @@ Object.defineProperty(exports, "anyChildCellMergedAcrossRow", {
9
9
  return _nodes.anyChildCellMergedAcrossRow;
10
10
  }
11
11
  });
12
+ Object.defineProperty(exports, "checkEdgeHasMergedCells", {
13
+ enumerable: true,
14
+ get: function get() {
15
+ return _mergedCells.checkEdgeHasMergedCells;
16
+ }
17
+ });
12
18
  Object.defineProperty(exports, "checkIfHeaderColumnEnabled", {
13
19
  enumerable: true,
14
20
  get: function get() {
@@ -105,6 +111,12 @@ Object.defineProperty(exports, "findControlsHoverDecoration", {
105
111
  return _decoration.findControlsHoverDecoration;
106
112
  }
107
113
  });
114
+ Object.defineProperty(exports, "findDuplicatePosition", {
115
+ enumerable: true,
116
+ get: function get() {
117
+ return _mergedCells.findDuplicatePosition;
118
+ }
119
+ });
108
120
  Object.defineProperty(exports, "findNearestCellIndexToPoint", {
109
121
  enumerable: true,
110
122
  get: function get() {
@@ -231,6 +243,12 @@ Object.defineProperty(exports, "hasMergedCellsInRow", {
231
243
  return _mergedCells.hasMergedCellsInRow;
232
244
  }
233
245
  });
246
+ Object.defineProperty(exports, "hasMergedCellsInSelection", {
247
+ enumerable: true,
248
+ get: function get() {
249
+ return _mergedCells.hasMergedCellsInSelection;
250
+ }
251
+ });
234
252
  Object.defineProperty(exports, "hasResizeHandler", {
235
253
  enumerable: true,
236
254
  get: function get() {
@@ -4,7 +4,7 @@ var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefau
4
4
  Object.defineProperty(exports, "__esModule", {
5
5
  value: true
6
6
  });
7
- exports.hasMergedCellsWithRowNextToRowIndex = exports.hasMergedCellsWithColumnNextToColumnIndex = exports.hasMergedCellsInRow = exports.hasMergedCellsInColumn = exports.hasMergedCellsInBetween = void 0;
7
+ exports.hasMergedCellsWithRowNextToRowIndex = exports.hasMergedCellsWithColumnNextToColumnIndex = exports.hasMergedCellsInSelection = exports.hasMergedCellsInRow = exports.hasMergedCellsInColumn = exports.hasMergedCellsInBetween = exports.getTableMapByRowOrColumn = exports.findDuplicatePosition = exports.checkEdgeHasMergedCells = void 0;
8
8
  var _toConsumableArray2 = _interopRequireDefault(require("@babel/runtime/helpers/toConsumableArray"));
9
9
  var _editorTables = require("@atlaskit/editor-tables");
10
10
  var hasMergedCells = function hasMergedCells(indexes, normalizeRect) {
@@ -202,4 +202,98 @@ var hasMergedCellsWithRowNextToRowIndex = exports.hasMergedCellsWithRowNextToRow
202
202
  }
203
203
  }
204
204
  return false;
205
+ };
206
+ var hasMergedCellsInSelection = exports.hasMergedCellsInSelection = function hasMergedCellsInSelection(indexes, type) {
207
+ return function (selection) {
208
+ var table = (0, _editorTables.findTable)(selection);
209
+ if (!table) {
210
+ return false;
211
+ }
212
+ var map = _editorTables.TableMap.get(table.node);
213
+ if (!map.hasMergedCells()) {
214
+ return false;
215
+ }
216
+ return checkEdgeHasMergedCells(indexes, map, type);
217
+ };
218
+ };
219
+
220
+ /**
221
+ * handle table map by preprocess table's map row or column.
222
+ *
223
+ * @param map TableMap
224
+ * @returns object including mapByRow and mapByColumn
225
+ */
226
+ var getTableMapByRowOrColumn = exports.getTableMapByRowOrColumn = function getTableMapByRowOrColumn(map) {
227
+ var mapByRow = Array(map.height);
228
+ var mapByColumn = Array(map.width);
229
+ var mapCopy = (0, _toConsumableArray2.default)(map.map);
230
+ for (var i = 0; i < mapCopy.length; i++) {
231
+ var _mapByColumn$columnIn, _mapByRow$rowIndex;
232
+ var columnIndex = i % map.width;
233
+ mapByColumn[columnIndex] = [].concat((0, _toConsumableArray2.default)((_mapByColumn$columnIn = mapByColumn[columnIndex]) !== null && _mapByColumn$columnIn !== void 0 ? _mapByColumn$columnIn : []), [mapCopy[i]]);
234
+ var rowIndex = Math.trunc(i / map.width);
235
+ mapByRow[rowIndex] = [].concat((0, _toConsumableArray2.default)((_mapByRow$rowIndex = mapByRow[rowIndex]) !== null && _mapByRow$rowIndex !== void 0 ? _mapByRow$rowIndex : []), [mapCopy[i]]);
236
+ }
237
+ return {
238
+ mapByRow: mapByRow,
239
+ mapByColumn: mapByColumn
240
+ };
241
+ };
242
+
243
+ /**
244
+ * this check the selection has merged cells with previous/next col or row.
245
+ *
246
+ * @param indexes - this get the indexes of the selection,e.g. [0,1] for selecting first two rows or columns.
247
+ * @param tableMap - this return a TableMap object.
248
+ * @param direction - check selection is selected by row or column
249
+ * @returns boolean
250
+ */
251
+ var checkEdgeHasMergedCells = exports.checkEdgeHasMergedCells = function checkEdgeHasMergedCells(indexes, tableMap, direction) {
252
+ var _getTableMapByRowOrCo = getTableMapByRowOrColumn(tableMap),
253
+ mapByRow = _getTableMapByRowOrCo.mapByRow,
254
+ mapByColumn = _getTableMapByRowOrCo.mapByColumn;
255
+ var map = 'row' === direction ? mapByRow : mapByColumn;
256
+ var lengthLimiter = direction === 'row' ? tableMap.width : tableMap.height;
257
+ var minIndex = Math.min.apply(Math, (0, _toConsumableArray2.default)(indexes));
258
+ var maxIndex = Math.max.apply(Math, (0, _toConsumableArray2.default)(indexes));
259
+ var isTopSideHaveMergedCells = false;
260
+ var isBottomSideHaveMergedCells = false;
261
+ var isOldMinIndex = !map[minIndex - 1] && !map[minIndex];
262
+ var isOldMaxIndex = !map[maxIndex + 1] && !map[maxIndex];
263
+ if (minIndex > 0 && !isOldMinIndex) {
264
+ var prevSelectionSet = map[minIndex - 1];
265
+ var minSelectionSet = map[minIndex];
266
+ for (var i = 0; i < lengthLimiter; i++) {
267
+ if (prevSelectionSet[i] === minSelectionSet[i]) {
268
+ isTopSideHaveMergedCells = true;
269
+ break;
270
+ }
271
+ }
272
+ }
273
+ if (maxIndex < map.length - 1 && !isOldMaxIndex) {
274
+ var afterSelectionSet = map[maxIndex + 1];
275
+ var maxSelectionSet = map[maxIndex];
276
+ for (var _i = 0; _i < lengthLimiter; _i++) {
277
+ if (afterSelectionSet[_i] === maxSelectionSet[_i]) {
278
+ isBottomSideHaveMergedCells = true;
279
+ break;
280
+ }
281
+ }
282
+ }
283
+ return isTopSideHaveMergedCells || isBottomSideHaveMergedCells;
284
+ };
285
+
286
+ /**
287
+ * this function will find the duplicate position in the array(table map position array).
288
+ *
289
+ * @param array this usually be the array including positions of the table map.
290
+ * @returns []
291
+ */
292
+ var findDuplicatePosition = exports.findDuplicatePosition = function findDuplicatePosition(array) {
293
+ if (!array) {
294
+ return [];
295
+ }
296
+ return array.filter(function (item, index) {
297
+ return array.indexOf(item) !== index;
298
+ });
205
299
  };
@@ -4,12 +4,14 @@ import ReactDOM from 'react-dom';
4
4
  import { injectIntl } from 'react-intl-next';
5
5
  import { tableMessages as messages } from '@atlaskit/editor-common/messages';
6
6
  import { browser } from '@atlaskit/editor-common/utils';
7
+ import { TextSelection } from '@atlaskit/editor-prosemirror/state';
8
+ import { findTable, TableMap } from '@atlaskit/editor-tables';
7
9
  import { draggable } from '@atlaskit/pragmatic-drag-and-drop/element/adapter';
8
10
  import { setCustomNativeDragPreview } from '@atlaskit/pragmatic-drag-and-drop/element/set-custom-native-drag-preview';
9
11
  import { getPluginState as getDnDPluginState } from '../../pm-plugins/drag-and-drop/plugin-factory';
10
12
  import { getPluginState } from '../../pm-plugins/plugin-factory';
11
13
  import { TableCssClassName as ClassName } from '../../types';
12
- import { hasMergedCellsInColumn, hasMergedCellsInRow } from '../../utils';
14
+ import { findDuplicatePosition, hasMergedCellsInSelection } from '../../utils';
13
15
  import { dragTableInsertColumnButtonSize } from '../consts';
14
16
  import { DragPreview } from '../DragPreview';
15
17
  import { HandleIconComponent } from './HandleIconComponent';
@@ -25,6 +27,7 @@ const DragHandleComponent = ({
25
27
  onMouseOver,
26
28
  onMouseOut,
27
29
  toggleDragMenu,
30
+ hoveredCell,
28
31
  onClick,
29
32
  editorView,
30
33
  intl: {
@@ -50,7 +53,38 @@ const DragHandleComponent = ({
50
53
  const isColumn = direction === 'column';
51
54
  const isRowHandleHovered = isRow && hoveredRows.length > 0;
52
55
  const isColumnHandleHovered = isColumn && hoveredColumns.length > 0;
53
- const hasMergedCells = useMemo(() => isRow ? hasMergedCellsInRow(indexes[0])(selection) : hasMergedCellsInColumn(indexes[0])(selection), [indexes, isRow, selection]);
56
+ const hasMergedCells = useMemo(() => {
57
+ const table = findTable(selection);
58
+ if (!table) {
59
+ return false;
60
+ }
61
+ const map = TableMap.get(table === null || table === void 0 ? void 0 : table.node);
62
+ if (!map.hasMergedCells() || indexes.length < 1) {
63
+ return false;
64
+ }
65
+ const {
66
+ mapByColumn,
67
+ mapByRow
68
+ } = map;
69
+
70
+ // this handle when hover to first column or row which has merged cells.
71
+ if (hoveredCell && hoveredCell.rowIndex !== undefined && hoveredCell.colIndex !== undefined && selection instanceof TextSelection) {
72
+ const {
73
+ rowIndex,
74
+ colIndex
75
+ } = hoveredCell;
76
+ const mergedPositionInRow = findDuplicatePosition(mapByRow[rowIndex]);
77
+ const mergedPositionInCol = findDuplicatePosition(mapByColumn[colIndex]);
78
+ const hasMergedCellsInFirstRowOrColumn = direction === 'column' ? mergedPositionInRow.includes(mapByRow[0][colIndex]) : mergedPositionInCol.includes(mapByColumn[0][rowIndex]);
79
+ const isHoveredOnFirstRowOrColumn = direction === 'column' ? hoveredCell.rowIndex === 0 && hasMergedCellsInFirstRowOrColumn : hoveredCell.colIndex === 0 && hasMergedCellsInFirstRowOrColumn;
80
+ if (isHoveredOnFirstRowOrColumn) {
81
+ const mergedSizes = direction === 'column' ? mapByRow[0].filter(el => el === mapByRow[0][colIndex]).length : mapByColumn[0].filter(el => el === mapByColumn[0][rowIndex]).length;
82
+ const mergedSelection = hasMergedCellsInSelection(direction === 'column' ? [colIndex, colIndex + mergedSizes - 1] : [rowIndex, rowIndex + mergedSizes - 1], direction)(selection);
83
+ return mergedSelection;
84
+ }
85
+ }
86
+ return hasMergedCellsInSelection(indexes, direction)(selection);
87
+ }, [indexes, selection, direction, hoveredCell]);
54
88
  const handleIconProps = {
55
89
  forceDefaultHandle,
56
90
  isHandleHovered: isColumnHandleHovered || isRowHandleHovered,
@@ -143,6 +143,7 @@ export const ColumnControls = ({
143
143
  direction: "column",
144
144
  tableLocalId: localId || '',
145
145
  indexes: indexes,
146
+ hoveredCell: hoveredCell,
146
147
  previewWidth: previewWidth,
147
148
  forceDefaultHandle: !isHover,
148
149
  previewHeight: previewHeight,
@@ -139,6 +139,7 @@ const DragControlsComponent = ({
139
139
  previewWidth: tableWidth,
140
140
  previewHeight: previewHeight,
141
141
  appearance: appearance,
142
+ hoveredCell: hoveredCell,
142
143
  onClick: handleClick,
143
144
  onMouseOver: handleMouseOver,
144
145
  onMouseOut: handleMouseOut,
@@ -8,4 +8,4 @@ export { getRowHeights, isRowDeleteButtonVisible, getRowDeleteButtonParams, getR
8
8
  export { getSelectedTableInfo, getSelectedCellInfo } from './analytics';
9
9
  export { getMergedCellsPositions } from './table';
10
10
  export { updatePluginStateDecorations } from './update-plugin-state-decorations';
11
- export { hasMergedCellsInColumn, hasMergedCellsInRow, hasMergedCellsInBetween } from './merged-cells';
11
+ export { hasMergedCellsInColumn, hasMergedCellsInRow, hasMergedCellsInBetween, hasMergedCellsInSelection, findDuplicatePosition, checkEdgeHasMergedCells } from './merged-cells';
@@ -180,4 +180,95 @@ export const hasMergedCellsWithRowNextToRowIndex = (rowIndex, selection) => {
180
180
  }
181
181
  }
182
182
  return false;
183
+ };
184
+ export const hasMergedCellsInSelection = (indexes, type) => selection => {
185
+ const table = findTable(selection);
186
+ if (!table) {
187
+ return false;
188
+ }
189
+ const map = TableMap.get(table.node);
190
+ if (!map.hasMergedCells()) {
191
+ return false;
192
+ }
193
+ return checkEdgeHasMergedCells(indexes, map, type);
194
+ };
195
+
196
+ /**
197
+ * handle table map by preprocess table's map row or column.
198
+ *
199
+ * @param map TableMap
200
+ * @returns object including mapByRow and mapByColumn
201
+ */
202
+ export const getTableMapByRowOrColumn = map => {
203
+ let mapByRow = Array(map.height);
204
+ let mapByColumn = Array(map.width);
205
+ const mapCopy = [...map.map];
206
+ for (let i = 0; i < mapCopy.length; i++) {
207
+ var _mapByColumn$columnIn, _mapByRow$rowIndex;
208
+ const columnIndex = i % map.width;
209
+ mapByColumn[columnIndex] = [...((_mapByColumn$columnIn = mapByColumn[columnIndex]) !== null && _mapByColumn$columnIn !== void 0 ? _mapByColumn$columnIn : []), mapCopy[i]];
210
+ const rowIndex = Math.trunc(i / map.width);
211
+ mapByRow[rowIndex] = [...((_mapByRow$rowIndex = mapByRow[rowIndex]) !== null && _mapByRow$rowIndex !== void 0 ? _mapByRow$rowIndex : []), mapCopy[i]];
212
+ }
213
+ return {
214
+ mapByRow,
215
+ mapByColumn
216
+ };
217
+ };
218
+
219
+ /**
220
+ * this check the selection has merged cells with previous/next col or row.
221
+ *
222
+ * @param indexes - this get the indexes of the selection,e.g. [0,1] for selecting first two rows or columns.
223
+ * @param tableMap - this return a TableMap object.
224
+ * @param direction - check selection is selected by row or column
225
+ * @returns boolean
226
+ */
227
+ export const checkEdgeHasMergedCells = (indexes, tableMap, direction) => {
228
+ const {
229
+ mapByRow,
230
+ mapByColumn
231
+ } = getTableMapByRowOrColumn(tableMap);
232
+ const map = 'row' === direction ? mapByRow : mapByColumn;
233
+ const lengthLimiter = direction === 'row' ? tableMap.width : tableMap.height;
234
+ let minIndex = Math.min(...indexes);
235
+ let maxIndex = Math.max(...indexes);
236
+ let isTopSideHaveMergedCells = false;
237
+ let isBottomSideHaveMergedCells = false;
238
+ let isOldMinIndex = !map[minIndex - 1] && !map[minIndex];
239
+ let isOldMaxIndex = !map[maxIndex + 1] && !map[maxIndex];
240
+ if (minIndex > 0 && !isOldMinIndex) {
241
+ const prevSelectionSet = map[minIndex - 1];
242
+ const minSelectionSet = map[minIndex];
243
+ for (let i = 0; i < lengthLimiter; i++) {
244
+ if (prevSelectionSet[i] === minSelectionSet[i]) {
245
+ isTopSideHaveMergedCells = true;
246
+ break;
247
+ }
248
+ }
249
+ }
250
+ if (maxIndex < map.length - 1 && !isOldMaxIndex) {
251
+ const afterSelectionSet = map[maxIndex + 1];
252
+ const maxSelectionSet = map[maxIndex];
253
+ for (let i = 0; i < lengthLimiter; i++) {
254
+ if (afterSelectionSet[i] === maxSelectionSet[i]) {
255
+ isBottomSideHaveMergedCells = true;
256
+ break;
257
+ }
258
+ }
259
+ }
260
+ return isTopSideHaveMergedCells || isBottomSideHaveMergedCells;
261
+ };
262
+
263
+ /**
264
+ * this function will find the duplicate position in the array(table map position array).
265
+ *
266
+ * @param array this usually be the array including positions of the table map.
267
+ * @returns []
268
+ */
269
+ export const findDuplicatePosition = array => {
270
+ if (!array) {
271
+ return [];
272
+ }
273
+ return array.filter((item, index) => array.indexOf(item) !== index);
183
274
  };
@@ -6,12 +6,14 @@ import ReactDOM from 'react-dom';
6
6
  import { injectIntl } from 'react-intl-next';
7
7
  import { tableMessages as messages } from '@atlaskit/editor-common/messages';
8
8
  import { browser } from '@atlaskit/editor-common/utils';
9
+ import { TextSelection } from '@atlaskit/editor-prosemirror/state';
10
+ import { findTable, TableMap } from '@atlaskit/editor-tables';
9
11
  import { draggable } from '@atlaskit/pragmatic-drag-and-drop/element/adapter';
10
12
  import { setCustomNativeDragPreview } from '@atlaskit/pragmatic-drag-and-drop/element/set-custom-native-drag-preview';
11
13
  import { getPluginState as getDnDPluginState } from '../../pm-plugins/drag-and-drop/plugin-factory';
12
14
  import { getPluginState } from '../../pm-plugins/plugin-factory';
13
15
  import { TableCssClassName as ClassName } from '../../types';
14
- import { hasMergedCellsInColumn, hasMergedCellsInRow } from '../../utils';
16
+ import { findDuplicatePosition, hasMergedCellsInSelection } from '../../utils';
15
17
  import { dragTableInsertColumnButtonSize } from '../consts';
16
18
  import { DragPreview } from '../DragPreview';
17
19
  import { HandleIconComponent } from './HandleIconComponent';
@@ -30,6 +32,7 @@ var DragHandleComponent = function DragHandleComponent(_ref) {
30
32
  onMouseOver = _ref.onMouseOver,
31
33
  onMouseOut = _ref.onMouseOut,
32
34
  toggleDragMenu = _ref.toggleDragMenu,
35
+ hoveredCell = _ref.hoveredCell,
33
36
  onClick = _ref.onClick,
34
37
  editorView = _ref.editorView,
35
38
  formatMessage = _ref.intl.formatMessage;
@@ -50,8 +53,37 @@ var DragHandleComponent = function DragHandleComponent(_ref) {
50
53
  var isRowHandleHovered = isRow && hoveredRows.length > 0;
51
54
  var isColumnHandleHovered = isColumn && hoveredColumns.length > 0;
52
55
  var hasMergedCells = useMemo(function () {
53
- return isRow ? hasMergedCellsInRow(indexes[0])(selection) : hasMergedCellsInColumn(indexes[0])(selection);
54
- }, [indexes, isRow, selection]);
56
+ var table = findTable(selection);
57
+ if (!table) {
58
+ return false;
59
+ }
60
+ var map = TableMap.get(table === null || table === void 0 ? void 0 : table.node);
61
+ if (!map.hasMergedCells() || indexes.length < 1) {
62
+ return false;
63
+ }
64
+ var mapByColumn = map.mapByColumn,
65
+ mapByRow = map.mapByRow;
66
+
67
+ // this handle when hover to first column or row which has merged cells.
68
+ if (hoveredCell && hoveredCell.rowIndex !== undefined && hoveredCell.colIndex !== undefined && selection instanceof TextSelection) {
69
+ var rowIndex = hoveredCell.rowIndex,
70
+ colIndex = hoveredCell.colIndex;
71
+ var mergedPositionInRow = findDuplicatePosition(mapByRow[rowIndex]);
72
+ var mergedPositionInCol = findDuplicatePosition(mapByColumn[colIndex]);
73
+ var hasMergedCellsInFirstRowOrColumn = direction === 'column' ? mergedPositionInRow.includes(mapByRow[0][colIndex]) : mergedPositionInCol.includes(mapByColumn[0][rowIndex]);
74
+ var isHoveredOnFirstRowOrColumn = direction === 'column' ? hoveredCell.rowIndex === 0 && hasMergedCellsInFirstRowOrColumn : hoveredCell.colIndex === 0 && hasMergedCellsInFirstRowOrColumn;
75
+ if (isHoveredOnFirstRowOrColumn) {
76
+ var mergedSizes = direction === 'column' ? mapByRow[0].filter(function (el) {
77
+ return el === mapByRow[0][colIndex];
78
+ }).length : mapByColumn[0].filter(function (el) {
79
+ return el === mapByColumn[0][rowIndex];
80
+ }).length;
81
+ var mergedSelection = hasMergedCellsInSelection(direction === 'column' ? [colIndex, colIndex + mergedSizes - 1] : [rowIndex, rowIndex + mergedSizes - 1], direction)(selection);
82
+ return mergedSelection;
83
+ }
84
+ }
85
+ return hasMergedCellsInSelection(indexes, direction)(selection);
86
+ }, [indexes, selection, direction, hoveredCell]);
55
87
  var handleIconProps = {
56
88
  forceDefaultHandle: forceDefaultHandle,
57
89
  isHandleHovered: isColumnHandleHovered || isRowHandleHovered,
@@ -139,6 +139,7 @@ export var ColumnControls = function ColumnControls(_ref) {
139
139
  direction: "column",
140
140
  tableLocalId: localId || '',
141
141
  indexes: indexes,
142
+ hoveredCell: hoveredCell,
142
143
  previewWidth: previewWidth,
143
144
  forceDefaultHandle: !isHover,
144
145
  previewHeight: previewHeight,
@@ -141,6 +141,7 @@ var DragControlsComponent = function DragControlsComponent(_ref) {
141
141
  previewWidth: tableWidth,
142
142
  previewHeight: previewHeight,
143
143
  appearance: appearance,
144
+ hoveredCell: hoveredCell,
144
145
  onClick: handleClick,
145
146
  onMouseOver: handleMouseOver,
146
147
  onMouseOut: handleMouseOut,
@@ -8,4 +8,4 @@ export { getRowHeights, isRowDeleteButtonVisible, getRowDeleteButtonParams, getR
8
8
  export { getSelectedTableInfo, getSelectedCellInfo } from './analytics';
9
9
  export { getMergedCellsPositions } from './table';
10
10
  export { updatePluginStateDecorations } from './update-plugin-state-decorations';
11
- export { hasMergedCellsInColumn, hasMergedCellsInRow, hasMergedCellsInBetween } from './merged-cells';
11
+ export { hasMergedCellsInColumn, hasMergedCellsInRow, hasMergedCellsInBetween, hasMergedCellsInSelection, findDuplicatePosition, checkEdgeHasMergedCells } from './merged-cells';
@@ -195,4 +195,98 @@ export var hasMergedCellsWithRowNextToRowIndex = function hasMergedCellsWithRowN
195
195
  }
196
196
  }
197
197
  return false;
198
+ };
199
+ export var hasMergedCellsInSelection = function hasMergedCellsInSelection(indexes, type) {
200
+ return function (selection) {
201
+ var table = findTable(selection);
202
+ if (!table) {
203
+ return false;
204
+ }
205
+ var map = TableMap.get(table.node);
206
+ if (!map.hasMergedCells()) {
207
+ return false;
208
+ }
209
+ return checkEdgeHasMergedCells(indexes, map, type);
210
+ };
211
+ };
212
+
213
+ /**
214
+ * handle table map by preprocess table's map row or column.
215
+ *
216
+ * @param map TableMap
217
+ * @returns object including mapByRow and mapByColumn
218
+ */
219
+ export var getTableMapByRowOrColumn = function getTableMapByRowOrColumn(map) {
220
+ var mapByRow = Array(map.height);
221
+ var mapByColumn = Array(map.width);
222
+ var mapCopy = _toConsumableArray(map.map);
223
+ for (var i = 0; i < mapCopy.length; i++) {
224
+ var _mapByColumn$columnIn, _mapByRow$rowIndex;
225
+ var columnIndex = i % map.width;
226
+ mapByColumn[columnIndex] = [].concat(_toConsumableArray((_mapByColumn$columnIn = mapByColumn[columnIndex]) !== null && _mapByColumn$columnIn !== void 0 ? _mapByColumn$columnIn : []), [mapCopy[i]]);
227
+ var rowIndex = Math.trunc(i / map.width);
228
+ mapByRow[rowIndex] = [].concat(_toConsumableArray((_mapByRow$rowIndex = mapByRow[rowIndex]) !== null && _mapByRow$rowIndex !== void 0 ? _mapByRow$rowIndex : []), [mapCopy[i]]);
229
+ }
230
+ return {
231
+ mapByRow: mapByRow,
232
+ mapByColumn: mapByColumn
233
+ };
234
+ };
235
+
236
+ /**
237
+ * this check the selection has merged cells with previous/next col or row.
238
+ *
239
+ * @param indexes - this get the indexes of the selection,e.g. [0,1] for selecting first two rows or columns.
240
+ * @param tableMap - this return a TableMap object.
241
+ * @param direction - check selection is selected by row or column
242
+ * @returns boolean
243
+ */
244
+ export var checkEdgeHasMergedCells = function checkEdgeHasMergedCells(indexes, tableMap, direction) {
245
+ var _getTableMapByRowOrCo = getTableMapByRowOrColumn(tableMap),
246
+ mapByRow = _getTableMapByRowOrCo.mapByRow,
247
+ mapByColumn = _getTableMapByRowOrCo.mapByColumn;
248
+ var map = 'row' === direction ? mapByRow : mapByColumn;
249
+ var lengthLimiter = direction === 'row' ? tableMap.width : tableMap.height;
250
+ var minIndex = Math.min.apply(Math, _toConsumableArray(indexes));
251
+ var maxIndex = Math.max.apply(Math, _toConsumableArray(indexes));
252
+ var isTopSideHaveMergedCells = false;
253
+ var isBottomSideHaveMergedCells = false;
254
+ var isOldMinIndex = !map[minIndex - 1] && !map[minIndex];
255
+ var isOldMaxIndex = !map[maxIndex + 1] && !map[maxIndex];
256
+ if (minIndex > 0 && !isOldMinIndex) {
257
+ var prevSelectionSet = map[minIndex - 1];
258
+ var minSelectionSet = map[minIndex];
259
+ for (var i = 0; i < lengthLimiter; i++) {
260
+ if (prevSelectionSet[i] === minSelectionSet[i]) {
261
+ isTopSideHaveMergedCells = true;
262
+ break;
263
+ }
264
+ }
265
+ }
266
+ if (maxIndex < map.length - 1 && !isOldMaxIndex) {
267
+ var afterSelectionSet = map[maxIndex + 1];
268
+ var maxSelectionSet = map[maxIndex];
269
+ for (var _i = 0; _i < lengthLimiter; _i++) {
270
+ if (afterSelectionSet[_i] === maxSelectionSet[_i]) {
271
+ isBottomSideHaveMergedCells = true;
272
+ break;
273
+ }
274
+ }
275
+ }
276
+ return isTopSideHaveMergedCells || isBottomSideHaveMergedCells;
277
+ };
278
+
279
+ /**
280
+ * this function will find the duplicate position in the array(table map position array).
281
+ *
282
+ * @param array this usually be the array including positions of the table map.
283
+ * @returns []
284
+ */
285
+ export var findDuplicatePosition = function findDuplicatePosition(array) {
286
+ if (!array) {
287
+ return [];
288
+ }
289
+ return array.filter(function (item, index) {
290
+ return array.indexOf(item) !== index;
291
+ });
198
292
  };
@@ -3,7 +3,7 @@ import React from 'react';
3
3
  import type { WrappedComponentProps } from 'react-intl-next';
4
4
  import type { EditorView } from '@atlaskit/editor-prosemirror/view';
5
5
  import type { TriggerType } from '../../pm-plugins/drag-and-drop/types';
6
- import type { TableDirection } from '../../types';
6
+ import type { CellHoverMeta, TableDirection } from '../../types';
7
7
  export type DragHandleAppearance = 'default' | 'selected' | 'disabled' | 'danger' | 'placeholder';
8
8
  type DragHandleProps = {
9
9
  tableLocalId: string;
@@ -11,6 +11,7 @@ type DragHandleProps = {
11
11
  forceDefaultHandle?: boolean;
12
12
  previewWidth?: number;
13
13
  previewHeight?: number;
14
+ hoveredCell?: CellHoverMeta;
14
15
  direction?: TableDirection;
15
16
  appearance?: DragHandleAppearance;
16
17
  onClick?: MouseEventHandler;
@@ -9,4 +9,4 @@ export type { RowParams } from './row-controls';
9
9
  export { getSelectedTableInfo, getSelectedCellInfo } from './analytics';
10
10
  export { getMergedCellsPositions } from './table';
11
11
  export { updatePluginStateDecorations } from './update-plugin-state-decorations';
12
- export { hasMergedCellsInColumn, hasMergedCellsInRow, hasMergedCellsInBetween, } from './merged-cells';
12
+ export { hasMergedCellsInColumn, hasMergedCellsInRow, hasMergedCellsInBetween, hasMergedCellsInSelection, findDuplicatePosition, checkEdgeHasMergedCells, } from './merged-cells';
@@ -1,8 +1,36 @@
1
1
  import type { Selection } from '@atlaskit/editor-prosemirror/state';
2
+ import { TableMap } from '@atlaskit/editor-tables';
2
3
  type MergeType = 'row' | 'column';
3
4
  export declare const hasMergedCellsInColumn: (columnIndexes: number | number[]) => (selection: Selection) => boolean;
4
5
  export declare const hasMergedCellsInRow: (rowIndexes: number | number[]) => (selection: Selection) => boolean;
5
6
  export declare const hasMergedCellsInBetween: (indexes: number[], type: MergeType) => (selection: Selection) => boolean;
6
7
  export declare const hasMergedCellsWithColumnNextToColumnIndex: (colIndex: number, selection: Selection) => boolean;
7
8
  export declare const hasMergedCellsWithRowNextToRowIndex: (rowIndex: number, selection: Selection) => boolean;
9
+ export declare const hasMergedCellsInSelection: (indexes: number[], type: MergeType) => (selection: Selection) => boolean;
10
+ /**
11
+ * handle table map by preprocess table's map row or column.
12
+ *
13
+ * @param map TableMap
14
+ * @returns object including mapByRow and mapByColumn
15
+ */
16
+ export declare const getTableMapByRowOrColumn: (map: TableMap) => {
17
+ mapByRow: any[];
18
+ mapByColumn: any[];
19
+ };
20
+ /**
21
+ * this check the selection has merged cells with previous/next col or row.
22
+ *
23
+ * @param indexes - this get the indexes of the selection,e.g. [0,1] for selecting first two rows or columns.
24
+ * @param tableMap - this return a TableMap object.
25
+ * @param direction - check selection is selected by row or column
26
+ * @returns boolean
27
+ */
28
+ export declare const checkEdgeHasMergedCells: (indexes: number[], tableMap: TableMap, direction: 'row' | 'column') => boolean;
29
+ /**
30
+ * this function will find the duplicate position in the array(table map position array).
31
+ *
32
+ * @param array this usually be the array including positions of the table map.
33
+ * @returns []
34
+ */
35
+ export declare const findDuplicatePosition: (array: number[]) => number[];
8
36
  export {};
@@ -3,7 +3,7 @@ import React from 'react';
3
3
  import type { WrappedComponentProps } from 'react-intl-next';
4
4
  import type { EditorView } from '@atlaskit/editor-prosemirror/view';
5
5
  import type { TriggerType } from '../../pm-plugins/drag-and-drop/types';
6
- import type { TableDirection } from '../../types';
6
+ import type { CellHoverMeta, TableDirection } from '../../types';
7
7
  export type DragHandleAppearance = 'default' | 'selected' | 'disabled' | 'danger' | 'placeholder';
8
8
  type DragHandleProps = {
9
9
  tableLocalId: string;
@@ -11,6 +11,7 @@ type DragHandleProps = {
11
11
  forceDefaultHandle?: boolean;
12
12
  previewWidth?: number;
13
13
  previewHeight?: number;
14
+ hoveredCell?: CellHoverMeta;
14
15
  direction?: TableDirection;
15
16
  appearance?: DragHandleAppearance;
16
17
  onClick?: MouseEventHandler;
@@ -9,4 +9,4 @@ export type { RowParams } from './row-controls';
9
9
  export { getSelectedTableInfo, getSelectedCellInfo } from './analytics';
10
10
  export { getMergedCellsPositions } from './table';
11
11
  export { updatePluginStateDecorations } from './update-plugin-state-decorations';
12
- export { hasMergedCellsInColumn, hasMergedCellsInRow, hasMergedCellsInBetween, } from './merged-cells';
12
+ export { hasMergedCellsInColumn, hasMergedCellsInRow, hasMergedCellsInBetween, hasMergedCellsInSelection, findDuplicatePosition, checkEdgeHasMergedCells, } from './merged-cells';
@@ -1,8 +1,36 @@
1
1
  import type { Selection } from '@atlaskit/editor-prosemirror/state';
2
+ import { TableMap } from '@atlaskit/editor-tables';
2
3
  type MergeType = 'row' | 'column';
3
4
  export declare const hasMergedCellsInColumn: (columnIndexes: number | number[]) => (selection: Selection) => boolean;
4
5
  export declare const hasMergedCellsInRow: (rowIndexes: number | number[]) => (selection: Selection) => boolean;
5
6
  export declare const hasMergedCellsInBetween: (indexes: number[], type: MergeType) => (selection: Selection) => boolean;
6
7
  export declare const hasMergedCellsWithColumnNextToColumnIndex: (colIndex: number, selection: Selection) => boolean;
7
8
  export declare const hasMergedCellsWithRowNextToRowIndex: (rowIndex: number, selection: Selection) => boolean;
9
+ export declare const hasMergedCellsInSelection: (indexes: number[], type: MergeType) => (selection: Selection) => boolean;
10
+ /**
11
+ * handle table map by preprocess table's map row or column.
12
+ *
13
+ * @param map TableMap
14
+ * @returns object including mapByRow and mapByColumn
15
+ */
16
+ export declare const getTableMapByRowOrColumn: (map: TableMap) => {
17
+ mapByRow: any[];
18
+ mapByColumn: any[];
19
+ };
20
+ /**
21
+ * this check the selection has merged cells with previous/next col or row.
22
+ *
23
+ * @param indexes - this get the indexes of the selection,e.g. [0,1] for selecting first two rows or columns.
24
+ * @param tableMap - this return a TableMap object.
25
+ * @param direction - check selection is selected by row or column
26
+ * @returns boolean
27
+ */
28
+ export declare const checkEdgeHasMergedCells: (indexes: number[], tableMap: TableMap, direction: 'row' | 'column') => boolean;
29
+ /**
30
+ * this function will find the duplicate position in the array(table map position array).
31
+ *
32
+ * @param array this usually be the array including positions of the table map.
33
+ * @returns []
34
+ */
35
+ export declare const findDuplicatePosition: (array: number[]) => number[];
8
36
  export {};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@atlaskit/editor-plugin-table",
3
- "version": "7.4.2",
3
+ "version": "7.4.3",
4
4
  "description": "Table plugin for the @atlaskit/editor",
5
5
  "publishConfig": {
6
6
  "registry": "https://registry.npmjs.org/"
@@ -8,7 +8,9 @@ import { injectIntl } from 'react-intl-next';
8
8
 
9
9
  import { tableMessages as messages } from '@atlaskit/editor-common/messages';
10
10
  import { browser } from '@atlaskit/editor-common/utils';
11
+ import { TextSelection } from '@atlaskit/editor-prosemirror/state';
11
12
  import type { EditorView } from '@atlaskit/editor-prosemirror/view';
13
+ import { findTable, TableMap } from '@atlaskit/editor-tables';
12
14
  import { draggable } from '@atlaskit/pragmatic-drag-and-drop/element/adapter';
13
15
  import { setCustomNativeDragPreview } from '@atlaskit/pragmatic-drag-and-drop/element/set-custom-native-drag-preview';
14
16
  import { token } from '@atlaskit/tokens';
@@ -16,9 +18,9 @@ import { token } from '@atlaskit/tokens';
16
18
  import { getPluginState as getDnDPluginState } from '../../pm-plugins/drag-and-drop/plugin-factory';
17
19
  import type { TriggerType } from '../../pm-plugins/drag-and-drop/types';
18
20
  import { getPluginState } from '../../pm-plugins/plugin-factory';
19
- import type { TableDirection } from '../../types';
20
21
  import { TableCssClassName as ClassName } from '../../types';
21
- import { hasMergedCellsInColumn, hasMergedCellsInRow } from '../../utils';
22
+ import type { CellHoverMeta, TableDirection } from '../../types';
23
+ import { findDuplicatePosition, hasMergedCellsInSelection } from '../../utils';
22
24
  import { dragTableInsertColumnButtonSize } from '../consts';
23
25
  import { DragPreview } from '../DragPreview';
24
26
 
@@ -37,6 +39,7 @@ type DragHandleProps = {
37
39
  forceDefaultHandle?: boolean;
38
40
  previewWidth?: number;
39
41
  previewHeight?: number;
42
+ hoveredCell?: CellHoverMeta;
40
43
  direction?: TableDirection;
41
44
  appearance?: DragHandleAppearance;
42
45
  onClick?: MouseEventHandler;
@@ -62,6 +65,7 @@ const DragHandleComponent = ({
62
65
  onMouseOver,
63
66
  onMouseOut,
64
67
  toggleDragMenu,
68
+ hoveredCell,
65
69
  onClick,
66
70
  editorView,
67
71
  intl: { formatMessage },
@@ -83,13 +87,64 @@ const DragHandleComponent = ({
83
87
  const isRowHandleHovered = isRow && hoveredRows.length > 0;
84
88
  const isColumnHandleHovered = isColumn && hoveredColumns.length > 0;
85
89
 
86
- const hasMergedCells = useMemo(
87
- () =>
88
- isRow
89
- ? hasMergedCellsInRow(indexes[0])(selection)
90
- : hasMergedCellsInColumn(indexes[0])(selection),
91
- [indexes, isRow, selection],
92
- );
90
+ const hasMergedCells = useMemo(() => {
91
+ const table = findTable(selection);
92
+ if (!table) {
93
+ return false;
94
+ }
95
+
96
+ const map = TableMap.get(table?.node);
97
+
98
+ if (!map.hasMergedCells() || indexes.length < 1) {
99
+ return false;
100
+ }
101
+
102
+ const { mapByColumn, mapByRow } = map;
103
+
104
+ // this handle when hover to first column or row which has merged cells.
105
+ if (
106
+ hoveredCell &&
107
+ hoveredCell.rowIndex !== undefined &&
108
+ hoveredCell.colIndex !== undefined &&
109
+ selection instanceof TextSelection
110
+ ) {
111
+ const { rowIndex, colIndex } = hoveredCell;
112
+
113
+ const mergedPositionInRow = findDuplicatePosition(mapByRow[rowIndex]);
114
+ const mergedPositionInCol = findDuplicatePosition(mapByColumn[colIndex]);
115
+
116
+ const hasMergedCellsInFirstRowOrColumn =
117
+ direction === 'column'
118
+ ? mergedPositionInRow.includes(mapByRow[0][colIndex])
119
+ : mergedPositionInCol.includes(mapByColumn[0][rowIndex]);
120
+
121
+ const isHoveredOnFirstRowOrColumn =
122
+ direction === 'column'
123
+ ? hoveredCell.rowIndex === 0 && hasMergedCellsInFirstRowOrColumn
124
+ : hoveredCell.colIndex === 0 && hasMergedCellsInFirstRowOrColumn;
125
+
126
+ if (isHoveredOnFirstRowOrColumn) {
127
+ const mergedSizes =
128
+ direction === 'column'
129
+ ? mapByRow[0].filter((el: number) => el === mapByRow[0][colIndex])
130
+ .length
131
+ : mapByColumn[0].filter(
132
+ (el: number) => el === mapByColumn[0][rowIndex],
133
+ ).length;
134
+
135
+ const mergedSelection = hasMergedCellsInSelection(
136
+ direction === 'column'
137
+ ? [colIndex, colIndex + mergedSizes - 1]
138
+ : [rowIndex, rowIndex + mergedSizes - 1],
139
+ direction,
140
+ )(selection);
141
+
142
+ return mergedSelection;
143
+ }
144
+ }
145
+
146
+ return hasMergedCellsInSelection(indexes, direction)(selection);
147
+ }, [indexes, selection, direction, hoveredCell]);
93
148
 
94
149
  const handleIconProps = {
95
150
  forceDefaultHandle,
@@ -217,6 +217,7 @@ export const ColumnControls = ({
217
217
  direction="column"
218
218
  tableLocalId={localId || ''}
219
219
  indexes={indexes}
220
+ hoveredCell={hoveredCell}
220
221
  previewWidth={previewWidth}
221
222
  forceDefaultHandle={!isHover}
222
223
  previewHeight={previewHeight}
@@ -227,6 +227,7 @@ const DragControlsComponent = ({
227
227
  previewWidth={tableWidth}
228
228
  previewHeight={previewHeight}
229
229
  appearance={appearance}
230
+ hoveredCell={hoveredCell}
230
231
  onClick={handleClick}
231
232
  onMouseOver={handleMouseOver}
232
233
  onMouseOut={handleMouseOut}
@@ -82,4 +82,7 @@ export {
82
82
  hasMergedCellsInColumn,
83
83
  hasMergedCellsInRow,
84
84
  hasMergedCellsInBetween,
85
+ hasMergedCellsInSelection,
86
+ findDuplicatePosition,
87
+ checkEdgeHasMergedCells,
85
88
  } from './merged-cells';
@@ -225,3 +225,107 @@ export const hasMergedCellsWithRowNextToRowIndex = (
225
225
 
226
226
  return false;
227
227
  };
228
+
229
+ export const hasMergedCellsInSelection =
230
+ (indexes: number[], type: MergeType) =>
231
+ (selection: Selection): boolean => {
232
+ const table = findTable(selection);
233
+ if (!table) {
234
+ return false;
235
+ }
236
+
237
+ const map = TableMap.get(table.node);
238
+
239
+ if (!map.hasMergedCells()) {
240
+ return false;
241
+ }
242
+
243
+ return checkEdgeHasMergedCells(indexes, map, type);
244
+ };
245
+
246
+ /**
247
+ * handle table map by preprocess table's map row or column.
248
+ *
249
+ * @param map TableMap
250
+ * @returns object including mapByRow and mapByColumn
251
+ */
252
+ export const getTableMapByRowOrColumn = (map: TableMap) => {
253
+ let mapByRow = Array(map.height);
254
+ let mapByColumn = Array(map.width);
255
+
256
+ const mapCopy = [...map.map];
257
+
258
+ for (let i = 0; i < mapCopy.length; i++) {
259
+ const columnIndex = i % map.width;
260
+ mapByColumn[columnIndex] = [
261
+ ...(mapByColumn[columnIndex] ?? []),
262
+ mapCopy[i],
263
+ ];
264
+ const rowIndex = Math.trunc(i / map.width);
265
+ mapByRow[rowIndex] = [...(mapByRow[rowIndex] ?? []), mapCopy[i]];
266
+ }
267
+
268
+ return { mapByRow, mapByColumn };
269
+ };
270
+
271
+ /**
272
+ * this check the selection has merged cells with previous/next col or row.
273
+ *
274
+ * @param indexes - this get the indexes of the selection,e.g. [0,1] for selecting first two rows or columns.
275
+ * @param tableMap - this return a TableMap object.
276
+ * @param direction - check selection is selected by row or column
277
+ * @returns boolean
278
+ */
279
+ export const checkEdgeHasMergedCells = (
280
+ indexes: number[],
281
+ tableMap: TableMap,
282
+ direction: 'row' | 'column',
283
+ ): boolean => {
284
+ const { mapByRow, mapByColumn } = getTableMapByRowOrColumn(tableMap);
285
+ const map = 'row' === direction ? mapByRow : mapByColumn;
286
+ const lengthLimiter = direction === 'row' ? tableMap.width : tableMap.height;
287
+
288
+ let minIndex = Math.min(...indexes);
289
+ let maxIndex = Math.max(...indexes);
290
+ let isTopSideHaveMergedCells = false;
291
+ let isBottomSideHaveMergedCells = false;
292
+ let isOldMinIndex = !map[minIndex - 1] && !map[minIndex];
293
+ let isOldMaxIndex = !map[maxIndex + 1] && !map[maxIndex];
294
+
295
+ if (minIndex > 0 && !isOldMinIndex) {
296
+ const prevSelectionSet = map[minIndex - 1];
297
+ const minSelectionSet = map[minIndex];
298
+ for (let i = 0; i < lengthLimiter; i++) {
299
+ if (prevSelectionSet[i] === minSelectionSet[i]) {
300
+ isTopSideHaveMergedCells = true;
301
+ break;
302
+ }
303
+ }
304
+ }
305
+
306
+ if (maxIndex < map.length - 1 && !isOldMaxIndex) {
307
+ const afterSelectionSet = map[maxIndex + 1];
308
+ const maxSelectionSet = map[maxIndex];
309
+
310
+ for (let i = 0; i < lengthLimiter; i++) {
311
+ if (afterSelectionSet[i] === maxSelectionSet[i]) {
312
+ isBottomSideHaveMergedCells = true;
313
+ break;
314
+ }
315
+ }
316
+ }
317
+ return isTopSideHaveMergedCells || isBottomSideHaveMergedCells;
318
+ };
319
+
320
+ /**
321
+ * this function will find the duplicate position in the array(table map position array).
322
+ *
323
+ * @param array this usually be the array including positions of the table map.
324
+ * @returns []
325
+ */
326
+ export const findDuplicatePosition = (array: number[]): number[] => {
327
+ if (!array) {
328
+ return [];
329
+ }
330
+ return array.filter((item, index) => array.indexOf(item) !== index);
331
+ };