@atlaskit/editor-plugin-table 5.5.4 → 5.5.5

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,12 @@
1
1
  # @atlaskit/editor-plugin-table
2
2
 
3
+ ## 5.5.5
4
+
5
+ ### Patch Changes
6
+
7
+ - [#59951](https://stash.atlassian.com/projects/CONFCLOUD/repos/confluence-frontend/pull-requests/59951) [`a42a17e8af1b`](https://stash.atlassian.com/projects/CONFCLOUD/repos/confluence-frontend/commits/a42a17e8af1b) - ED-21106: Remove nonPrivacySafeAttributes from editor operational events
8
+ - [#59453](https://stash.atlassian.com/projects/CONFCLOUD/repos/confluence-frontend/pull-requests/59453) [`e23de3e96559`](https://stash.atlassian.com/projects/CONFCLOUD/repos/confluence-frontend/commits/e23de3e96559) - Fix drop table row/column next to merged cells
9
+
3
10
  ## 5.5.4
4
11
 
5
12
  ### Patch Changes
@@ -13,7 +13,6 @@ var _cellSelection = require("@atlaskit/editor-tables/cell-selection");
13
13
  var _utils = require("@atlaskit/editor-tables/utils");
14
14
  var _element = require("@atlaskit/pragmatic-drag-and-drop/adapter/element");
15
15
  var _utils2 = require("../../utils");
16
- var _mergedCells = require("../../utils/merged-cells");
17
16
  var _pluginFactory = require("../plugin-factory");
18
17
  var _pluginKey = require("../plugin-key");
19
18
  var _actions = require("./actions");
@@ -182,8 +181,7 @@ var createPlugin = exports.createPlugin = function createPlugin(dispatch, eventD
182
181
  }
183
182
 
184
183
  // If the drop target index contains merged cells then we should not allow the drop to occur.
185
- var hasMergedCells = sourceType === 'table-row' ? _mergedCells.hasMergedCellsInRow : _mergedCells.hasMergedCellsInColumn;
186
- if (hasMergedCells(targetAdjustedIndex)(editorView.state.selection)) {
184
+ if ((0, _utils2.hasMergedCellsInBetween)([targetAdjustedIndex - 1, targetAdjustedIndex], sourceType === 'table-row' ? _consts.DropTargetType.ROW : _consts.DropTargetType.COLUMN)(editorView.state.selection)) {
187
185
  (0, _commands.clearDropTarget)(tr)(editorView.state, editorView.dispatch);
188
186
  return;
189
187
  }
@@ -105,9 +105,6 @@ var FloatingInsertButton = exports.FloatingInsertButton = /*#__PURE__*/function
105
105
  position: pos,
106
106
  docSize: editorView.state.doc.nodeSize,
107
107
  error: error === null || error === void 0 ? void 0 : error.toString()
108
- },
109
- nonPrivacySafeAttributes: {
110
- errorStack: error.stack || undefined
111
108
  }
112
109
  };
113
110
  dispatchAnalyticsEvent(payload);
@@ -213,6 +213,12 @@ Object.defineProperty(exports, "getTableWidth", {
213
213
  return _nodes.getTableWidth;
214
214
  }
215
215
  });
216
+ Object.defineProperty(exports, "hasMergedCellsInBetween", {
217
+ enumerable: true,
218
+ get: function get() {
219
+ return _mergedCells.hasMergedCellsInBetween;
220
+ }
221
+ });
216
222
  Object.defineProperty(exports, "hasMergedCellsInColumn", {
217
223
  enumerable: true,
218
224
  get: function get() {
@@ -1,9 +1,11 @@
1
1
  "use strict";
2
2
 
3
+ var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
3
4
  Object.defineProperty(exports, "__esModule", {
4
5
  value: true
5
6
  });
6
- exports.hasMergedCellsInRow = exports.hasMergedCellsInColumn = void 0;
7
+ exports.hasMergedCellsInRow = exports.hasMergedCellsInColumn = exports.hasMergedCellsInBetween = void 0;
8
+ var _toConsumableArray2 = _interopRequireDefault(require("@babel/runtime/helpers/toConsumableArray"));
7
9
  var _editorTables = require("@atlaskit/editor-tables");
8
10
  var hasMergedCells = function hasMergedCells(indexes, normalizeRect) {
9
11
  return function (selection) {
@@ -63,4 +65,76 @@ var hasMergedCellsInRow = exports.hasMergedCellsInRow = function hasMergedCellsI
63
65
  bottom: y === index ? y + 1 : y
64
66
  };
65
67
  });
68
+ };
69
+ var getRect = function getRect(index, type, map) {
70
+ if (type === 'column') {
71
+ var x = Math.max(Math.min(index, map.width - 1), 0); // clamped index
72
+ return {
73
+ left: x,
74
+ right: x === index ? x + 1 : x,
75
+ top: 0,
76
+ bottom: map.height
77
+ };
78
+ } else {
79
+ var y = Math.max(Math.min(index, map.height - 1), 0); // clamped index
80
+ return {
81
+ left: 0,
82
+ right: map.width,
83
+ top: y,
84
+ bottom: y === index ? y + 1 : y
85
+ };
86
+ }
87
+ };
88
+ var hasMergedCellsInBetween = exports.hasMergedCellsInBetween = function hasMergedCellsInBetween(indexes, type) {
89
+ return function (selection) {
90
+ var table = (0, _editorTables.findTable)(selection);
91
+ if (!table) {
92
+ return false;
93
+ }
94
+ var map = _editorTables.TableMap.get(table.node);
95
+ var cellPositions = new Set();
96
+ var mergedCells = new Set();
97
+ map.map.forEach(function (value) {
98
+ if (cellPositions.has(value)) {
99
+ mergedCells.add(value);
100
+ } else {
101
+ cellPositions.add(value);
102
+ }
103
+ });
104
+ if (!mergedCells.size) {
105
+ return false;
106
+ }
107
+ var getMergedCellsInRect = function getMergedCellsInRect(index, type) {
108
+ var rect = getRect(index, type, map);
109
+ var isValidRectangle = rect.left < rect.right && rect.top < rect.bottom;
110
+ if (!isValidRectangle) {
111
+ return [];
112
+ }
113
+ var cells = map.cellsInRect(rect);
114
+ var allCellsInRect = [];
115
+ if (type === 'column') {
116
+ allCellsInRect = map.map.filter(function (_, key) {
117
+ return key % map.width === index;
118
+ });
119
+ } else {
120
+ allCellsInRect = map.map.filter(function (_, key) {
121
+ return Math.floor(key / map.width) === index;
122
+ });
123
+ }
124
+ var mergedCell = allCellsInRect.filter(function (nodePos) {
125
+ return !cells.includes(nodePos) // cell exists in Rect but not show in the map.cellsInRect list => merged cell
126
+ ? true : mergedCells.has(nodePos); // cell includes in mergedCells => merged cell
127
+ });
128
+
129
+ return (0, _toConsumableArray2.default)(new Set(mergedCell));
130
+ };
131
+ var mergedCellsInRectArr = indexes.map(function (index) {
132
+ return getMergedCellsInRect(index, type);
133
+ });
134
+
135
+ // Currently only support 2 indexes, but we can extend this to support more indexes in the future.
136
+ return mergedCellsInRectArr[0].some(function (cell) {
137
+ return mergedCellsInRectArr[1].includes(cell);
138
+ });
139
+ };
66
140
  };
@@ -3,8 +3,7 @@ import { DecorationSet } from '@atlaskit/editor-prosemirror/view';
3
3
  import { CellSelection } from '@atlaskit/editor-tables/cell-selection';
4
4
  import { getCellsInRow } from '@atlaskit/editor-tables/utils';
5
5
  import { monitorForElements } from '@atlaskit/pragmatic-drag-and-drop/adapter/element';
6
- import { findNearestCellIndexToPoint } from '../../utils';
7
- import { hasMergedCellsInColumn, hasMergedCellsInRow } from '../../utils/merged-cells';
6
+ import { findNearestCellIndexToPoint, hasMergedCellsInBetween } from '../../utils';
8
7
  import { getPluginState as getTablePluginState } from '../plugin-factory';
9
8
  import { pluginKey as tablePluginKey } from '../plugin-key';
10
9
  import { DragAndDropActionType } from './actions';
@@ -184,8 +183,7 @@ export const createPlugin = (dispatch, eventDispatcher) => {
184
183
  }
185
184
 
186
185
  // If the drop target index contains merged cells then we should not allow the drop to occur.
187
- const hasMergedCells = sourceType === 'table-row' ? hasMergedCellsInRow : hasMergedCellsInColumn;
188
- if (hasMergedCells(targetAdjustedIndex)(editorView.state.selection)) {
186
+ if (hasMergedCellsInBetween([targetAdjustedIndex - 1, targetAdjustedIndex], sourceType === 'table-row' ? DropTargetType.ROW : DropTargetType.COLUMN)(editorView.state.selection)) {
189
187
  clearDropTarget(tr)(editorView.state, editorView.dispatch);
190
188
  return;
191
189
  }
@@ -85,9 +85,6 @@ export class FloatingInsertButton extends React.Component {
85
85
  position: pos,
86
86
  docSize: editorView.state.doc.nodeSize,
87
87
  error: error === null || error === void 0 ? void 0 : error.toString()
88
- },
89
- nonPrivacySafeAttributes: {
90
- errorStack: error.stack || undefined
91
88
  }
92
89
  };
93
90
  dispatchAnalyticsEvent(payload);
@@ -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 } from './merged-cells';
11
+ export { hasMergedCellsInColumn, hasMergedCellsInRow, hasMergedCellsInBetween } from './merged-cells';
@@ -45,4 +45,66 @@ export const hasMergedCellsInRow = rowIndexes => hasMergedCells(rowIndexes, (ind
45
45
  top: y,
46
46
  bottom: y === index ? y + 1 : y
47
47
  };
48
- });
48
+ });
49
+ const getRect = (index, type, map) => {
50
+ if (type === 'column') {
51
+ const x = Math.max(Math.min(index, map.width - 1), 0); // clamped index
52
+ return {
53
+ left: x,
54
+ right: x === index ? x + 1 : x,
55
+ top: 0,
56
+ bottom: map.height
57
+ };
58
+ } else {
59
+ const y = Math.max(Math.min(index, map.height - 1), 0); // clamped index
60
+ return {
61
+ left: 0,
62
+ right: map.width,
63
+ top: y,
64
+ bottom: y === index ? y + 1 : y
65
+ };
66
+ }
67
+ };
68
+ export const hasMergedCellsInBetween = (indexes, type) => selection => {
69
+ const table = findTable(selection);
70
+ if (!table) {
71
+ return false;
72
+ }
73
+ const map = TableMap.get(table.node);
74
+ const cellPositions = new Set();
75
+ const mergedCells = new Set();
76
+ map.map.forEach(value => {
77
+ if (cellPositions.has(value)) {
78
+ mergedCells.add(value);
79
+ } else {
80
+ cellPositions.add(value);
81
+ }
82
+ });
83
+ if (!mergedCells.size) {
84
+ return false;
85
+ }
86
+ const getMergedCellsInRect = (index, type) => {
87
+ const rect = getRect(index, type, map);
88
+ const isValidRectangle = rect.left < rect.right && rect.top < rect.bottom;
89
+ if (!isValidRectangle) {
90
+ return [];
91
+ }
92
+ const cells = map.cellsInRect(rect);
93
+ let allCellsInRect = [];
94
+ if (type === 'column') {
95
+ allCellsInRect = map.map.filter((_, key) => key % map.width === index);
96
+ } else {
97
+ allCellsInRect = map.map.filter((_, key) => Math.floor(key / map.width) === index);
98
+ }
99
+ const mergedCell = allCellsInRect.filter(nodePos => {
100
+ return !cells.includes(nodePos) // cell exists in Rect but not show in the map.cellsInRect list => merged cell
101
+ ? true : mergedCells.has(nodePos); // cell includes in mergedCells => merged cell
102
+ });
103
+
104
+ return [...new Set(mergedCell)];
105
+ };
106
+ const mergedCellsInRectArr = indexes.map(index => getMergedCellsInRect(index, type));
107
+
108
+ // Currently only support 2 indexes, but we can extend this to support more indexes in the future.
109
+ return mergedCellsInRectArr[0].some(cell => mergedCellsInRectArr[1].includes(cell));
110
+ };
@@ -7,8 +7,7 @@ import { DecorationSet } from '@atlaskit/editor-prosemirror/view';
7
7
  import { CellSelection } from '@atlaskit/editor-tables/cell-selection';
8
8
  import { getCellsInRow } from '@atlaskit/editor-tables/utils';
9
9
  import { monitorForElements } from '@atlaskit/pragmatic-drag-and-drop/adapter/element';
10
- import { findNearestCellIndexToPoint } from '../../utils';
11
- import { hasMergedCellsInColumn, hasMergedCellsInRow } from '../../utils/merged-cells';
10
+ import { findNearestCellIndexToPoint, hasMergedCellsInBetween } from '../../utils';
12
11
  import { getPluginState as getTablePluginState } from '../plugin-factory';
13
12
  import { pluginKey as tablePluginKey } from '../plugin-key';
14
13
  import { DragAndDropActionType } from './actions';
@@ -175,8 +174,7 @@ export var createPlugin = function createPlugin(dispatch, eventDispatcher) {
175
174
  }
176
175
 
177
176
  // If the drop target index contains merged cells then we should not allow the drop to occur.
178
- var hasMergedCells = sourceType === 'table-row' ? hasMergedCellsInRow : hasMergedCellsInColumn;
179
- if (hasMergedCells(targetAdjustedIndex)(editorView.state.selection)) {
177
+ if (hasMergedCellsInBetween([targetAdjustedIndex - 1, targetAdjustedIndex], sourceType === 'table-row' ? DropTargetType.ROW : DropTargetType.COLUMN)(editorView.state.selection)) {
180
178
  clearDropTarget(tr)(editorView.state, editorView.dispatch);
181
179
  return;
182
180
  }
@@ -95,9 +95,6 @@ export var FloatingInsertButton = /*#__PURE__*/function (_React$Component) {
95
95
  position: pos,
96
96
  docSize: editorView.state.doc.nodeSize,
97
97
  error: error === null || error === void 0 ? void 0 : error.toString()
98
- },
99
- nonPrivacySafeAttributes: {
100
- errorStack: error.stack || undefined
101
98
  }
102
99
  };
103
100
  dispatchAnalyticsEvent(payload);
@@ -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 } from './merged-cells';
11
+ export { hasMergedCellsInColumn, hasMergedCellsInRow, hasMergedCellsInBetween } from './merged-cells';
@@ -1,3 +1,4 @@
1
+ import _toConsumableArray from "@babel/runtime/helpers/toConsumableArray";
1
2
  import { findTable, TableMap } from '@atlaskit/editor-tables';
2
3
  var hasMergedCells = function hasMergedCells(indexes, normalizeRect) {
3
4
  return function (selection) {
@@ -57,4 +58,76 @@ export var hasMergedCellsInRow = function hasMergedCellsInRow(rowIndexes) {
57
58
  bottom: y === index ? y + 1 : y
58
59
  };
59
60
  });
61
+ };
62
+ var getRect = function getRect(index, type, map) {
63
+ if (type === 'column') {
64
+ var x = Math.max(Math.min(index, map.width - 1), 0); // clamped index
65
+ return {
66
+ left: x,
67
+ right: x === index ? x + 1 : x,
68
+ top: 0,
69
+ bottom: map.height
70
+ };
71
+ } else {
72
+ var y = Math.max(Math.min(index, map.height - 1), 0); // clamped index
73
+ return {
74
+ left: 0,
75
+ right: map.width,
76
+ top: y,
77
+ bottom: y === index ? y + 1 : y
78
+ };
79
+ }
80
+ };
81
+ export var hasMergedCellsInBetween = function hasMergedCellsInBetween(indexes, type) {
82
+ return function (selection) {
83
+ var table = findTable(selection);
84
+ if (!table) {
85
+ return false;
86
+ }
87
+ var map = TableMap.get(table.node);
88
+ var cellPositions = new Set();
89
+ var mergedCells = new Set();
90
+ map.map.forEach(function (value) {
91
+ if (cellPositions.has(value)) {
92
+ mergedCells.add(value);
93
+ } else {
94
+ cellPositions.add(value);
95
+ }
96
+ });
97
+ if (!mergedCells.size) {
98
+ return false;
99
+ }
100
+ var getMergedCellsInRect = function getMergedCellsInRect(index, type) {
101
+ var rect = getRect(index, type, map);
102
+ var isValidRectangle = rect.left < rect.right && rect.top < rect.bottom;
103
+ if (!isValidRectangle) {
104
+ return [];
105
+ }
106
+ var cells = map.cellsInRect(rect);
107
+ var allCellsInRect = [];
108
+ if (type === 'column') {
109
+ allCellsInRect = map.map.filter(function (_, key) {
110
+ return key % map.width === index;
111
+ });
112
+ } else {
113
+ allCellsInRect = map.map.filter(function (_, key) {
114
+ return Math.floor(key / map.width) === index;
115
+ });
116
+ }
117
+ var mergedCell = allCellsInRect.filter(function (nodePos) {
118
+ return !cells.includes(nodePos) // cell exists in Rect but not show in the map.cellsInRect list => merged cell
119
+ ? true : mergedCells.has(nodePos); // cell includes in mergedCells => merged cell
120
+ });
121
+
122
+ return _toConsumableArray(new Set(mergedCell));
123
+ };
124
+ var mergedCellsInRectArr = indexes.map(function (index) {
125
+ return getMergedCellsInRect(index, type);
126
+ });
127
+
128
+ // Currently only support 2 indexes, but we can extend this to support more indexes in the future.
129
+ return mergedCellsInRectArr[0].some(function (cell) {
130
+ return mergedCellsInRectArr[1].includes(cell);
131
+ });
132
+ };
60
133
  };
@@ -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 } from './merged-cells';
12
+ export { hasMergedCellsInColumn, hasMergedCellsInRow, hasMergedCellsInBetween, } from './merged-cells';
@@ -1,3 +1,6 @@
1
1
  import type { Selection } from '@atlaskit/editor-prosemirror/state';
2
+ type MergeType = 'row' | 'column';
2
3
  export declare const hasMergedCellsInColumn: (columnIndexes: number | number[]) => (selection: Selection) => boolean;
3
4
  export declare const hasMergedCellsInRow: (rowIndexes: number | number[]) => (selection: Selection) => boolean;
5
+ export declare const hasMergedCellsInBetween: (indexes: number[], type: MergeType) => (selection: Selection) => boolean;
6
+ export {};
@@ -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 } from './merged-cells';
12
+ export { hasMergedCellsInColumn, hasMergedCellsInRow, hasMergedCellsInBetween, } from './merged-cells';
@@ -1,3 +1,6 @@
1
1
  import type { Selection } from '@atlaskit/editor-prosemirror/state';
2
+ type MergeType = 'row' | 'column';
2
3
  export declare const hasMergedCellsInColumn: (columnIndexes: number | number[]) => (selection: Selection) => boolean;
3
4
  export declare const hasMergedCellsInRow: (rowIndexes: number | number[]) => (selection: Selection) => boolean;
5
+ export declare const hasMergedCellsInBetween: (indexes: number[], type: MergeType) => (selection: Selection) => boolean;
6
+ export {};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@atlaskit/editor-plugin-table",
3
- "version": "5.5.4",
3
+ "version": "5.5.5",
4
4
  "description": "Table plugin for the @atlaskit/editor",
5
5
  "publishConfig": {
6
6
  "registry": "https://registry.npmjs.org/"
@@ -144,9 +144,9 @@ describe('Floating Insert Button when findDomRefAtPos fails', () => {
144
144
  docSize: 46,
145
145
  error: 'Error: Error message from mock',
146
146
  }),
147
- nonPrivacySafeAttributes: expect.objectContaining({
148
- errorStack: 'stack trace',
149
- }),
147
+ });
148
+ expect(createAnalyticsEvent).not.toHaveBeenCalledWith({
149
+ nonPrivacySafeAttributes: expect.any(Object),
150
150
  });
151
151
  });
152
152
 
@@ -0,0 +1,156 @@
1
+ import type { DocBuilder } from '@atlaskit/editor-common/types';
2
+ // eslint-disable-next-line import/no-extraneous-dependencies -- Removed import for fixing circular dependencies
3
+ import { analyticsPlugin } from '@atlaskit/editor-plugin-analytics';
4
+ import { contentInsertionPlugin } from '@atlaskit/editor-plugin-content-insertion';
5
+ import { guidelinePlugin } from '@atlaskit/editor-plugin-guideline';
6
+ import { selectionPlugin } from '@atlaskit/editor-plugin-selection';
7
+ import { widthPlugin } from '@atlaskit/editor-plugin-width';
8
+ // eslint-disable-next-line import/no-extraneous-dependencies
9
+ import type { LightEditorPlugin } from '@atlaskit/editor-test-helpers/create-prosemirror-editor';
10
+ // eslint-disable-next-line import/no-extraneous-dependencies -- Removed import for fixing circular dependencies
11
+ import {
12
+ createProsemirrorEditorFactory,
13
+ Preset,
14
+ } from '@atlaskit/editor-test-helpers/create-prosemirror-editor';
15
+ // eslint-disable-next-line import/no-extraneous-dependencies -- Removed import for fixing circular dependencies
16
+ import {
17
+ doc,
18
+ p,
19
+ table,
20
+ td,
21
+ tdEmpty,
22
+ tr,
23
+ } from '@atlaskit/editor-test-helpers/doc-builder';
24
+
25
+ import tablePlugin from '../../../plugins/table-plugin';
26
+ import { pluginKey } from '../../../plugins/table/pm-plugins/plugin-key';
27
+ import { hasMergedCellsInBetween } from '../../../plugins/table/utils';
28
+
29
+ describe('table merge cells logic', () => {
30
+ const createEditor = createProsemirrorEditorFactory();
31
+
32
+ const editor = (doc: DocBuilder) =>
33
+ createEditor({
34
+ doc,
35
+ preset: new Preset<LightEditorPlugin>()
36
+ .add([analyticsPlugin, {}])
37
+ .add(contentInsertionPlugin)
38
+ .add(widthPlugin)
39
+ .add(guidelinePlugin)
40
+ .add(selectionPlugin)
41
+ .add(tablePlugin),
42
+ pluginKey,
43
+ });
44
+
45
+ describe('#hasMergedCellsInBetween', () => {
46
+ describe('when first and second columns are merged', () => {
47
+ const { editorView } = editor(
48
+ doc(
49
+ table()(
50
+ tr(td({ colspan: 2 })(p('')), tdEmpty, tdEmpty),
51
+ tr(tdEmpty, tdEmpty, tdEmpty, tdEmpty),
52
+ tr(tdEmpty, tdEmpty, tdEmpty, tdEmpty),
53
+ ),
54
+ ),
55
+ );
56
+
57
+ it('should return false when pass indexs [-1, 0]', () => {
58
+ expect(
59
+ hasMergedCellsInBetween(
60
+ [-1, 0],
61
+ 'column',
62
+ )(editorView.state.selection),
63
+ ).toEqual(false);
64
+ });
65
+
66
+ it('should return true when pass indexs [0,1]', () => {
67
+ expect(
68
+ hasMergedCellsInBetween([0, 1], 'column')(editorView.state.selection),
69
+ ).toEqual(true);
70
+ });
71
+
72
+ it('should return false when pass indexs [1,2]', () => {
73
+ expect(
74
+ hasMergedCellsInBetween([1, 2], 'column')(editorView.state.selection),
75
+ ).toEqual(false);
76
+ });
77
+ });
78
+
79
+ describe('when second and third columns are merged', () => {
80
+ const { editorView } = editor(
81
+ doc(
82
+ table()(
83
+ tr(tdEmpty, td({ colspan: 2 })(p('')), tdEmpty),
84
+ tr(tdEmpty, tdEmpty, tdEmpty, tdEmpty),
85
+ tr(tdEmpty, tdEmpty, tdEmpty, tdEmpty),
86
+ ),
87
+ ),
88
+ );
89
+ it('should return false when pass indexs [0,1]', () => {
90
+ expect(
91
+ hasMergedCellsInBetween([0, 1], 'column')(editorView.state.selection),
92
+ ).toEqual(false);
93
+ });
94
+
95
+ it('should return true when pass indexs [1,2]', () => {
96
+ expect(
97
+ hasMergedCellsInBetween([1, 2], 'column')(editorView.state.selection),
98
+ ).toEqual(true);
99
+ });
100
+ });
101
+
102
+ describe('when first and second rows are merged', () => {
103
+ const { editorView } = editor(
104
+ doc(
105
+ table()(
106
+ tr(td({ rowspan: 2 })(p('')), tdEmpty, tdEmpty, tdEmpty),
107
+ tr(tdEmpty, tdEmpty, tdEmpty),
108
+ tr(tdEmpty, tdEmpty, tdEmpty, tdEmpty),
109
+ ),
110
+ ),
111
+ );
112
+
113
+ it('should return false when pass indexs [-1, 0]', () => {
114
+ expect(
115
+ hasMergedCellsInBetween([-1, 0], 'row')(editorView.state.selection),
116
+ ).toEqual(false);
117
+ });
118
+
119
+ it('should return true when pass indexs [0,1]', () => {
120
+ expect(
121
+ hasMergedCellsInBetween([0, 1], 'row')(editorView.state.selection),
122
+ ).toEqual(true);
123
+ });
124
+
125
+ it('should return false when pass indexs [1,2]', () => {
126
+ expect(
127
+ hasMergedCellsInBetween([1, 2], 'row')(editorView.state.selection),
128
+ ).toEqual(false);
129
+ });
130
+ });
131
+
132
+ describe('when second and third rows are merged', () => {
133
+ const { editorView } = editor(
134
+ doc(
135
+ table()(
136
+ tr(tdEmpty, tdEmpty, tdEmpty, tdEmpty),
137
+ tr(td({ rowspan: 2 })(p('')), tdEmpty, tdEmpty),
138
+ tr(tdEmpty, tdEmpty, tdEmpty, tdEmpty),
139
+ ),
140
+ ),
141
+ );
142
+
143
+ it('should return false when pass indexs [0,1]', () => {
144
+ expect(
145
+ hasMergedCellsInBetween([0, 1], 'row')(editorView.state.selection),
146
+ ).toEqual(false);
147
+ });
148
+
149
+ it('should return true when pass indexs [1,2]', () => {
150
+ expect(
151
+ hasMergedCellsInBetween([1, 2], 'row')(editorView.state.selection),
152
+ ).toEqual(true);
153
+ });
154
+ });
155
+ });
156
+ });
@@ -10,11 +10,10 @@ import { getCellsInRow } from '@atlaskit/editor-tables/utils';
10
10
  import { monitorForElements } from '@atlaskit/pragmatic-drag-and-drop/adapter/element';
11
11
 
12
12
  import type { DraggableSourceData } from '../../types';
13
- import { findNearestCellIndexToPoint } from '../../utils';
14
13
  import {
15
- hasMergedCellsInColumn,
16
- hasMergedCellsInRow,
17
- } from '../../utils/merged-cells';
14
+ findNearestCellIndexToPoint,
15
+ hasMergedCellsInBetween,
16
+ } from '../../utils';
18
17
  import { getPluginState as getTablePluginState } from '../plugin-factory';
19
18
  import { pluginKey as tablePluginKey } from '../plugin-key';
20
19
 
@@ -215,12 +214,13 @@ export const createPlugin = (
215
214
  }
216
215
 
217
216
  // If the drop target index contains merged cells then we should not allow the drop to occur.
218
- const hasMergedCells =
219
- sourceType === 'table-row'
220
- ? hasMergedCellsInRow
221
- : hasMergedCellsInColumn;
222
217
  if (
223
- hasMergedCells(targetAdjustedIndex)(editorView.state.selection)
218
+ hasMergedCellsInBetween(
219
+ [targetAdjustedIndex - 1, targetAdjustedIndex],
220
+ sourceType === 'table-row'
221
+ ? DropTargetType.ROW
222
+ : DropTargetType.COLUMN,
223
+ )(editorView.state.selection)
224
224
  ) {
225
225
  clearDropTarget(tr)(editorView.state, editorView.dispatch);
226
226
  return;
@@ -153,9 +153,6 @@ export class FloatingInsertButton extends React.Component<
153
153
  docSize: editorView.state.doc.nodeSize,
154
154
  error: (error as any)?.toString(),
155
155
  },
156
- nonPrivacySafeAttributes: {
157
- errorStack: (error as any).stack || undefined,
158
- },
159
156
  };
160
157
  dispatchAnalyticsEvent(payload);
161
158
  }
@@ -79,4 +79,8 @@ export type { RowParams } from './row-controls';
79
79
  export { getSelectedTableInfo, getSelectedCellInfo } from './analytics';
80
80
  export { getMergedCellsPositions } from './table';
81
81
  export { updatePluginStateDecorations } from './update-plugin-state-decorations';
82
- export { hasMergedCellsInColumn, hasMergedCellsInRow } from './merged-cells';
82
+ export {
83
+ hasMergedCellsInColumn,
84
+ hasMergedCellsInRow,
85
+ hasMergedCellsInBetween,
86
+ } from './merged-cells';
@@ -2,6 +2,8 @@ import type { Selection } from '@atlaskit/editor-prosemirror/state';
2
2
  import type { Rect } from '@atlaskit/editor-tables';
3
3
  import { findTable, TableMap } from '@atlaskit/editor-tables';
4
4
 
5
+ type MergeType = 'row' | 'column';
6
+
5
7
  const hasMergedCells =
6
8
  (
7
9
  indexes: number | number[],
@@ -65,3 +67,83 @@ export const hasMergedCellsInRow = (rowIndexes: number | number[]) =>
65
67
  bottom: y === index ? y + 1 : y,
66
68
  };
67
69
  });
70
+
71
+ const getRect = (index: number, type: MergeType, map: TableMap) => {
72
+ if (type === 'column') {
73
+ const x = Math.max(Math.min(index, map.width - 1), 0); // clamped index
74
+ return {
75
+ left: x,
76
+ right: x === index ? x + 1 : x,
77
+ top: 0,
78
+ bottom: map.height,
79
+ };
80
+ } else {
81
+ const y = Math.max(Math.min(index, map.height - 1), 0); // clamped index
82
+ return {
83
+ left: 0,
84
+ right: map.width,
85
+ top: y,
86
+ bottom: y === index ? y + 1 : y,
87
+ };
88
+ }
89
+ };
90
+
91
+ export const hasMergedCellsInBetween =
92
+ (indexes: number[], type: MergeType) =>
93
+ (selection: Selection): boolean => {
94
+ const table = findTable(selection);
95
+ if (!table) {
96
+ return false;
97
+ }
98
+
99
+ const map = TableMap.get(table.node);
100
+ const cellPositions = new Set<number>();
101
+ const mergedCells = new Set<number>();
102
+
103
+ map.map.forEach((value) => {
104
+ if (cellPositions.has(value)) {
105
+ mergedCells.add(value);
106
+ } else {
107
+ cellPositions.add(value);
108
+ }
109
+ });
110
+
111
+ if (!mergedCells.size) {
112
+ return false;
113
+ }
114
+
115
+ const getMergedCellsInRect = (index: number, type: MergeType) => {
116
+ const rect = getRect(index, type, map);
117
+ const isValidRectangle = rect.left < rect.right && rect.top < rect.bottom;
118
+ if (!isValidRectangle) {
119
+ return [];
120
+ }
121
+
122
+ const cells = map.cellsInRect(rect);
123
+
124
+ let allCellsInRect = [];
125
+ if (type === 'column') {
126
+ allCellsInRect = map.map.filter((_, key) => key % map.width === index);
127
+ } else {
128
+ allCellsInRect = map.map.filter(
129
+ (_, key) => Math.floor(key / map.width) === index,
130
+ );
131
+ }
132
+ const mergedCell = allCellsInRect.filter((nodePos) => {
133
+ return !cells.includes(nodePos) // cell exists in Rect but not show in the map.cellsInRect list => merged cell
134
+ ? true
135
+ : mergedCells.has(nodePos); // cell includes in mergedCells => merged cell
136
+ });
137
+
138
+ return [...new Set(mergedCell)];
139
+ };
140
+
141
+ const mergedCellsInRectArr = indexes.map((index) =>
142
+ getMergedCellsInRect(index, type),
143
+ );
144
+
145
+ // Currently only support 2 indexes, but we can extend this to support more indexes in the future.
146
+ return mergedCellsInRectArr[0].some((cell) =>
147
+ mergedCellsInRectArr[1].includes(cell),
148
+ );
149
+ };