@atlaskit/editor-plugin-table 7.4.1 → 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 (50) hide show
  1. package/CHANGELOG.md +12 -0
  2. package/dist/cjs/nodeviews/TableComponent.js +2 -4
  3. package/dist/cjs/nodeviews/TableContainer.js +5 -10
  4. package/dist/cjs/nodeviews/TableResizer.js +3 -7
  5. package/dist/cjs/ui/DragHandle/index.js +34 -2
  6. package/dist/cjs/ui/TableFloatingColumnControls/ColumnControls/index.js +1 -0
  7. package/dist/cjs/ui/TableFloatingControls/RowControls/DragControls.js +1 -0
  8. package/dist/cjs/utils/analytics.js +1 -2
  9. package/dist/cjs/utils/index.js +18 -0
  10. package/dist/cjs/utils/merged-cells.js +95 -1
  11. package/dist/es2019/nodeviews/TableComponent.js +2 -4
  12. package/dist/es2019/nodeviews/TableContainer.js +5 -10
  13. package/dist/es2019/nodeviews/TableResizer.js +3 -7
  14. package/dist/es2019/ui/DragHandle/index.js +36 -2
  15. package/dist/es2019/ui/TableFloatingColumnControls/ColumnControls/index.js +1 -0
  16. package/dist/es2019/ui/TableFloatingControls/RowControls/DragControls.js +1 -0
  17. package/dist/es2019/utils/analytics.js +1 -2
  18. package/dist/es2019/utils/index.js +1 -1
  19. package/dist/es2019/utils/merged-cells.js +91 -0
  20. package/dist/esm/nodeviews/TableComponent.js +2 -4
  21. package/dist/esm/nodeviews/TableContainer.js +5 -10
  22. package/dist/esm/nodeviews/TableResizer.js +3 -7
  23. package/dist/esm/ui/DragHandle/index.js +35 -3
  24. package/dist/esm/ui/TableFloatingColumnControls/ColumnControls/index.js +1 -0
  25. package/dist/esm/ui/TableFloatingControls/RowControls/DragControls.js +1 -0
  26. package/dist/esm/utils/analytics.js +1 -2
  27. package/dist/esm/utils/index.js +1 -1
  28. package/dist/esm/utils/merged-cells.js +94 -0
  29. package/dist/types/nodeviews/TableContainer.d.ts +2 -4
  30. package/dist/types/nodeviews/TableResizer.d.ts +1 -2
  31. package/dist/types/ui/DragHandle/index.d.ts +2 -1
  32. package/dist/types/utils/analytics.d.ts +0 -1
  33. package/dist/types/utils/index.d.ts +1 -1
  34. package/dist/types/utils/merged-cells.d.ts +28 -0
  35. package/dist/types-ts4.5/nodeviews/TableContainer.d.ts +2 -4
  36. package/dist/types-ts4.5/nodeviews/TableResizer.d.ts +1 -2
  37. package/dist/types-ts4.5/ui/DragHandle/index.d.ts +2 -1
  38. package/dist/types-ts4.5/utils/analytics.d.ts +0 -1
  39. package/dist/types-ts4.5/utils/index.d.ts +1 -1
  40. package/dist/types-ts4.5/utils/merged-cells.d.ts +28 -0
  41. package/package.json +3 -3
  42. package/src/nodeviews/TableComponent.tsx +1 -2
  43. package/src/nodeviews/TableContainer.tsx +0 -9
  44. package/src/nodeviews/TableResizer.tsx +0 -6
  45. package/src/ui/DragHandle/index.tsx +64 -9
  46. package/src/ui/TableFloatingColumnControls/ColumnControls/index.tsx +1 -0
  47. package/src/ui/TableFloatingControls/RowControls/DragControls.tsx +1 -0
  48. package/src/utils/analytics.ts +0 -2
  49. package/src/utils/index.ts +3 -0
  50. package/src/utils/merged-cells.ts +104 -0
@@ -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}
@@ -144,7 +144,6 @@ export const generateResizeFrameRatePayloads = (props: {
144
144
  docSize: number;
145
145
  frameRateSamples: number[];
146
146
  originalNode: PMNode;
147
- experiments?: Record<string, boolean | undefined>;
148
147
  }): TableEventPayload[] => {
149
148
  const reducedResizeFrameRateSamples = reduceResizeFrameRateSamples(
150
149
  props.frameRateSamples,
@@ -158,7 +157,6 @@ export const generateResizeFrameRatePayloads = (props: {
158
157
  nodeSize: props.originalNode.nodeSize,
159
158
  docSize: props.docSize,
160
159
  isInitialSample: index === 0,
161
- experiments: props.experiments,
162
160
  },
163
161
  }));
164
162
  };
@@ -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
+ };