@atlaskit/editor-plugin-table 5.4.13 → 5.4.15

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 (119) hide show
  1. package/CHANGELOG.md +16 -0
  2. package/afm-cc/tsconfig.json +70 -0
  3. package/dist/cjs/plugins/table/commands/hover.js +26 -6
  4. package/dist/cjs/plugins/table/commands/index.js +6 -0
  5. package/dist/cjs/plugins/table/commands/misc.js +8 -3
  6. package/dist/cjs/plugins/table/event-handlers.js +56 -34
  7. package/dist/cjs/plugins/table/nodeviews/TableComponent.js +4 -1
  8. package/dist/cjs/plugins/table/pm-plugins/drag-and-drop/commands.js +7 -6
  9. package/dist/cjs/plugins/table/pm-plugins/drag-and-drop/plugin.js +39 -7
  10. package/dist/cjs/plugins/table/pm-plugins/main.js +5 -3
  11. package/dist/cjs/plugins/table/reducer.js +1 -0
  12. package/dist/cjs/plugins/table/toolbar.js +6 -3
  13. package/dist/cjs/plugins/table/ui/ColumnResizeWidget/index.js +6 -3
  14. package/dist/cjs/plugins/table/ui/DragHandle/index.js +7 -5
  15. package/dist/cjs/plugins/table/ui/DragPreview/index.js +0 -2
  16. package/dist/cjs/plugins/table/ui/FloatingContextualButton/index.js +10 -7
  17. package/dist/cjs/plugins/table/ui/FloatingContextualMenu/ContextualMenu.js +11 -10
  18. package/dist/cjs/plugins/table/ui/FloatingContextualMenu/index.js +6 -3
  19. package/dist/cjs/plugins/table/ui/FloatingDragMenu/DragMenu.js +7 -4
  20. package/dist/cjs/plugins/table/ui/TableFloatingColumnControls/ColumnControls/index.js +18 -8
  21. package/dist/cjs/plugins/table/ui/TableFloatingColumnControls/index.js +3 -1
  22. package/dist/cjs/plugins/table/ui/TableFloatingControls/RowControls/DragControls.js +2 -1
  23. package/dist/cjs/plugins/table/ui/TableFloatingControls/index.js +12 -8
  24. package/dist/cjs/plugins/table/ui/common-styles.js +1 -1
  25. package/dist/cjs/plugins/table/utils/dom.js +16 -1
  26. package/dist/cjs/plugins/table/utils/index.js +6 -0
  27. package/dist/es2019/plugins/table/commands/hover.js +22 -5
  28. package/dist/es2019/plugins/table/commands/index.js +1 -1
  29. package/dist/es2019/plugins/table/commands/misc.js +8 -3
  30. package/dist/es2019/plugins/table/event-handlers.js +45 -20
  31. package/dist/es2019/plugins/table/nodeviews/TableComponent.js +4 -1
  32. package/dist/es2019/plugins/table/pm-plugins/drag-and-drop/commands.js +7 -6
  33. package/dist/es2019/plugins/table/pm-plugins/drag-and-drop/plugin.js +36 -3
  34. package/dist/es2019/plugins/table/pm-plugins/main.js +6 -4
  35. package/dist/es2019/plugins/table/reducer.js +1 -0
  36. package/dist/es2019/plugins/table/toolbar.js +5 -3
  37. package/dist/es2019/plugins/table/ui/ColumnResizeWidget/index.js +5 -3
  38. package/dist/es2019/plugins/table/ui/DragHandle/index.js +8 -6
  39. package/dist/es2019/plugins/table/ui/DragPreview/index.js +0 -2
  40. package/dist/es2019/plugins/table/ui/FloatingContextualButton/index.js +9 -7
  41. package/dist/es2019/plugins/table/ui/FloatingContextualMenu/ContextualMenu.js +11 -9
  42. package/dist/es2019/plugins/table/ui/FloatingContextualMenu/index.js +5 -3
  43. package/dist/es2019/plugins/table/ui/FloatingDragMenu/DragMenu.js +6 -4
  44. package/dist/es2019/plugins/table/ui/TableFloatingColumnControls/ColumnControls/index.js +16 -8
  45. package/dist/es2019/plugins/table/ui/TableFloatingColumnControls/index.js +3 -1
  46. package/dist/es2019/plugins/table/ui/TableFloatingControls/RowControls/DragControls.js +2 -1
  47. package/dist/es2019/plugins/table/ui/TableFloatingControls/index.js +12 -9
  48. package/dist/es2019/plugins/table/ui/common-styles.js +6 -4
  49. package/dist/es2019/plugins/table/utils/dom.js +13 -0
  50. package/dist/es2019/plugins/table/utils/index.js +1 -1
  51. package/dist/esm/plugins/table/commands/hover.js +25 -5
  52. package/dist/esm/plugins/table/commands/index.js +1 -1
  53. package/dist/esm/plugins/table/commands/misc.js +8 -3
  54. package/dist/esm/plugins/table/event-handlers.js +55 -33
  55. package/dist/esm/plugins/table/nodeviews/TableComponent.js +4 -1
  56. package/dist/esm/plugins/table/pm-plugins/drag-and-drop/commands.js +7 -6
  57. package/dist/esm/plugins/table/pm-plugins/drag-and-drop/plugin.js +35 -3
  58. package/dist/esm/plugins/table/pm-plugins/main.js +6 -4
  59. package/dist/esm/plugins/table/reducer.js +1 -0
  60. package/dist/esm/plugins/table/toolbar.js +5 -3
  61. package/dist/esm/plugins/table/ui/ColumnResizeWidget/index.js +5 -3
  62. package/dist/esm/plugins/table/ui/DragHandle/index.js +7 -5
  63. package/dist/esm/plugins/table/ui/DragPreview/index.js +0 -2
  64. package/dist/esm/plugins/table/ui/FloatingContextualButton/index.js +9 -7
  65. package/dist/esm/plugins/table/ui/FloatingContextualMenu/ContextualMenu.js +11 -9
  66. package/dist/esm/plugins/table/ui/FloatingContextualMenu/index.js +5 -3
  67. package/dist/esm/plugins/table/ui/FloatingDragMenu/DragMenu.js +6 -4
  68. package/dist/esm/plugins/table/ui/TableFloatingColumnControls/ColumnControls/index.js +18 -8
  69. package/dist/esm/plugins/table/ui/TableFloatingColumnControls/index.js +3 -1
  70. package/dist/esm/plugins/table/ui/TableFloatingControls/RowControls/DragControls.js +2 -1
  71. package/dist/esm/plugins/table/ui/TableFloatingControls/index.js +12 -8
  72. package/dist/esm/plugins/table/ui/common-styles.js +1 -1
  73. package/dist/esm/plugins/table/utils/dom.js +15 -0
  74. package/dist/esm/plugins/table/utils/index.js +1 -1
  75. package/dist/types/plugins/table/commands/hover.d.ts +2 -1
  76. package/dist/types/plugins/table/commands/index.d.ts +1 -1
  77. package/dist/types/plugins/table/commands/misc.d.ts +1 -1
  78. package/dist/types/plugins/table/event-handlers.d.ts +2 -0
  79. package/dist/types/plugins/table/pm-plugins/drag-and-drop/commands.d.ts +1 -1
  80. package/dist/types/plugins/table/types.d.ts +6 -2
  81. package/dist/types/plugins/table/ui/TableFloatingColumnControls/ColumnControls/index.d.ts +2 -1
  82. package/dist/types/plugins/table/ui/TableFloatingColumnControls/index.d.ts +1 -0
  83. package/dist/types/plugins/table/ui/TableFloatingControls/RowControls/DragControls.d.ts +1 -0
  84. package/dist/types/plugins/table/ui/TableFloatingControls/index.d.ts +1 -0
  85. package/dist/types/plugins/table/utils/dom.d.ts +4 -0
  86. package/dist/types/plugins/table/utils/index.d.ts +1 -1
  87. package/dist/types-ts4.5/plugins/table/commands/hover.d.ts +2 -1
  88. package/dist/types-ts4.5/plugins/table/commands/index.d.ts +1 -1
  89. package/dist/types-ts4.5/plugins/table/commands/misc.d.ts +1 -1
  90. package/dist/types-ts4.5/plugins/table/event-handlers.d.ts +2 -0
  91. package/dist/types-ts4.5/plugins/table/pm-plugins/drag-and-drop/commands.d.ts +1 -1
  92. package/dist/types-ts4.5/plugins/table/types.d.ts +6 -2
  93. package/dist/types-ts4.5/plugins/table/ui/TableFloatingColumnControls/ColumnControls/index.d.ts +2 -1
  94. package/dist/types-ts4.5/plugins/table/ui/TableFloatingColumnControls/index.d.ts +1 -0
  95. package/dist/types-ts4.5/plugins/table/ui/TableFloatingControls/RowControls/DragControls.d.ts +1 -0
  96. package/dist/types-ts4.5/plugins/table/ui/TableFloatingControls/index.d.ts +1 -0
  97. package/dist/types-ts4.5/plugins/table/utils/dom.d.ts +4 -0
  98. package/dist/types-ts4.5/plugins/table/utils/index.d.ts +1 -1
  99. package/package.json +2 -2
  100. package/src/__tests__/unit/event-handlers.ts +2 -2
  101. package/src/__tests__/unit/ui/RowDragControls.tsx +1 -0
  102. package/src/plugins/table/commands/hover.ts +37 -7
  103. package/src/plugins/table/commands/index.ts +1 -0
  104. package/src/plugins/table/commands/misc.ts +9 -3
  105. package/src/plugins/table/event-handlers.ts +47 -29
  106. package/src/plugins/table/nodeviews/TableComponent.tsx +4 -1
  107. package/src/plugins/table/pm-plugins/drag-and-drop/commands.ts +7 -5
  108. package/src/plugins/table/pm-plugins/drag-and-drop/plugin.ts +37 -2
  109. package/src/plugins/table/pm-plugins/main.ts +6 -3
  110. package/src/plugins/table/reducer.ts +1 -0
  111. package/src/plugins/table/types.ts +7 -2
  112. package/src/plugins/table/ui/DragHandle/index.tsx +7 -7
  113. package/src/plugins/table/ui/TableFloatingColumnControls/ColumnControls/index.tsx +16 -5
  114. package/src/plugins/table/ui/TableFloatingColumnControls/index.tsx +3 -0
  115. package/src/plugins/table/ui/TableFloatingControls/RowControls/DragControls.tsx +3 -1
  116. package/src/plugins/table/ui/TableFloatingControls/index.tsx +12 -5
  117. package/src/plugins/table/ui/common-styles.ts +6 -4
  118. package/src/plugins/table/utils/dom.ts +22 -0
  119. package/src/plugins/table/utils/index.ts +1 -0
@@ -37,6 +37,7 @@ import {
37
37
  hoverColumns,
38
38
  selectColumn,
39
39
  setEditorFocus,
40
+ setTableHovered,
40
41
  showInsertColumnButton,
41
42
  showInsertRowButton,
42
43
  showResizeHandleLine,
@@ -193,7 +194,7 @@ export const handleMouseOver = (
193
194
  }
194
195
  const { state, dispatch } = view;
195
196
  const target = mouseEvent.target;
196
- const { insertColumnButtonIndex, insertRowButtonIndex } =
197
+ const { insertColumnButtonIndex, insertRowButtonIndex, isTableHovered } =
197
198
  getPluginState(state);
198
199
 
199
200
  if (isInsertRowButton(target)) {
@@ -230,6 +231,10 @@ export const handleMouseOver = (
230
231
  );
231
232
  }
232
233
 
234
+ if (!isTableHovered) {
235
+ return setTableHovered(true)(state, dispatch);
236
+ }
237
+
233
238
  return false;
234
239
  };
235
240
 
@@ -284,6 +289,21 @@ export const handleMouseOut = (
284
289
  return false;
285
290
  };
286
291
 
292
+ export const handleMouseEnter = (
293
+ view: EditorView,
294
+ mouseEvent: Event,
295
+ ): boolean => {
296
+ const { state, dispatch } = view;
297
+
298
+ const { isTableHovered } = getPluginState(state);
299
+
300
+ if (!isTableHovered) {
301
+ return setTableHovered(true)(state, dispatch);
302
+ }
303
+
304
+ return false;
305
+ };
306
+
287
307
  export const handleMouseLeave = (view: EditorView, event: Event): boolean => {
288
308
  if (!(event.target instanceof HTMLElement)) {
289
309
  return false;
@@ -294,17 +314,27 @@ export const handleMouseLeave = (view: EditorView, event: Event): boolean => {
294
314
  insertColumnButtonIndex,
295
315
  insertRowButtonIndex,
296
316
  isDragAndDropEnabled,
317
+ isTableHovered,
297
318
  } = getPluginState(state);
298
319
 
299
- const target = event.target;
300
- if (isTableControlsButton(target)) {
320
+ if (isTableHovered) {
321
+ if (isDragAndDropEnabled) {
322
+ const { isDragMenuOpen } = getDragDropPluginState(state);
323
+ !isDragMenuOpen && setTableHovered(false)(state, dispatch);
324
+ } else {
325
+ setTableHovered(false)(state, dispatch);
326
+ }
301
327
  return true;
302
328
  }
303
329
 
304
- if (isDragAndDropEnabled) {
305
- const { isDragMenuOpen } = getDragDropPluginState(state);
306
- // Only set hoveredCell colIndex and rowIndex to undefined if the drag menu is not open
307
- !isDragMenuOpen && hoverCell()(state, dispatch);
330
+ // If this table doesn't have focus then we want to skip everything after this.
331
+ if (!isTableInFocus(view)) {
332
+ return false;
333
+ }
334
+
335
+ const target = event.target;
336
+ if (isTableControlsButton(target)) {
337
+ return true;
308
338
  }
309
339
 
310
340
  if (
@@ -509,6 +539,13 @@ export const handleCut = (
509
539
  return tr;
510
540
  };
511
541
 
542
+ export const isTableInFocus = (view: EditorView) => {
543
+ return (
544
+ !!getPluginState(view.state)?.tableNode &&
545
+ !getResizePluginState(view.state)?.dragging
546
+ );
547
+ };
548
+
512
549
  export const whenTableInFocus =
513
550
  (
514
551
  eventHandler: (
@@ -519,10 +556,7 @@ export const whenTableInFocus =
519
556
  elementContentRects?: ElementContentRects,
520
557
  ) =>
521
558
  (view: EditorView, mouseEvent: Event): boolean => {
522
- if (
523
- !getPluginState(view.state)?.tableNode ||
524
- !!getResizePluginState(view.state)?.dragging
525
- ) {
559
+ if (!isTableInFocus(view)) {
526
560
  return false;
527
561
  }
528
562
 
@@ -534,8 +568,7 @@ const trackCellLocation = (view: EditorView, mouseEvent: Event) => {
534
568
  const maybeTableCell = isElementInTableCell(
535
569
  target as HTMLElement,
536
570
  ) as HTMLTableCellElement | null;
537
- const tableRef = getPluginState(view.state).tableRef;
538
- const { hoveredCell, tableNode } = getPluginState(view.state);
571
+ const { tableNode, tableRef } = getPluginState(view.state);
539
572
 
540
573
  const tableElement = closestElement(
541
574
  target as HTMLElement,
@@ -561,9 +594,6 @@ const trackCellLocation = (view: EditorView, mouseEvent: Event) => {
561
594
  ) as HTMLTableRowElement;
562
595
  const htmlRowIndex = rowElement && rowElement.rowIndex;
563
596
 
564
- const colHeight = tableRef.offsetHeight;
565
- const colWidth = maybeTableCell.offsetWidth;
566
-
567
597
  const tableMap = tableNode && TableMap.get(tableNode);
568
598
  let colIndex = htmlColIndex;
569
599
  if (tableMap) {
@@ -580,19 +610,7 @@ const trackCellLocation = (view: EditorView, mouseEvent: Event) => {
580
610
  );
581
611
  }
582
612
 
583
- if (
584
- hoveredCell.colIndex !== colIndex ||
585
- hoveredCell.rowIndex !== htmlRowIndex ||
586
- hoveredCell.colWidth !== colWidth ||
587
- hoveredCell.colHeight !== colHeight
588
- ) {
589
- hoverCell(
590
- htmlRowIndex,
591
- colIndex,
592
- colWidth,
593
- colHeight,
594
- )(view.state, view.dispatch);
595
- }
613
+ hoverCell(htmlRowIndex, colIndex)(view.state, view.dispatch);
596
614
  };
597
615
 
598
616
  export const withCellTracking =
@@ -474,7 +474,8 @@ class TableComponent extends React.Component<ComponentProps, TableState> {
474
474
  const { showBeforeShadow, showAfterShadow } = this.state;
475
475
  const node = getNode();
476
476
  // doesn't work well with WithPluginState
477
- const { isInDanger, hoveredRows, hoveredCell } = getPluginState(view.state);
477
+ const { isInDanger, hoveredRows, hoveredCell, isTableHovered } =
478
+ getPluginState(view.state);
478
479
 
479
480
  const tableRef = this.table || undefined;
480
481
  const headerRow = tableRef
@@ -490,6 +491,7 @@ class TableComponent extends React.Component<ComponentProps, TableState> {
490
491
  tableActive={tableActive}
491
492
  hoveredRows={hoveredRows}
492
493
  hoveredCell={hoveredCell}
494
+ isTableHovered={isTableHovered}
493
495
  isInDanger={isInDanger}
494
496
  isResizing={isResizing}
495
497
  isNumberColumnEnabled={node.attrs.isNumberColumnEnabled}
@@ -514,6 +516,7 @@ class TableComponent extends React.Component<ComponentProps, TableState> {
514
516
  isInDanger={isInDanger}
515
517
  hoveredRows={hoveredRows}
516
518
  hoveredCell={hoveredCell}
519
+ isTableHovered={isTableHovered}
517
520
  isResizing={isResizing}
518
521
  ordering={ordering}
519
522
  hasHeaderRow={hasHeaderRow}
@@ -101,6 +101,7 @@ export const moveSource = (
101
101
  sourceType: DraggableType,
102
102
  sourceIndex: number,
103
103
  targetIndex: number,
104
+ tr?: Transaction,
104
105
  ) =>
105
106
  createCommand(
106
107
  (state) => {
@@ -111,12 +112,13 @@ export const moveSource = (
111
112
  },
112
113
  };
113
114
  },
114
- (tr: Transaction) => {
115
+ (originalTr: Transaction) => {
116
+ const nextTr = tr || originalTr;
115
117
  if (sourceIndex === targetIndex) {
116
- return tr.setMeta('addToHistory', false);
118
+ return nextTr.setMeta('addToHistory', false);
117
119
  }
118
120
 
119
- const anchor = tr.selection.anchor;
121
+ const anchor = nextTr.selection.anchor;
120
122
  const selectStartOfTable = (newTr: Transaction) =>
121
123
  newTr.setSelection(TextSelection.create(newTr.doc, anchor));
122
124
 
@@ -129,7 +131,7 @@ export const moveSource = (
129
131
  selectStartOfTable,
130
132
  selectRow(targetIndex),
131
133
  ],
132
- tr,
134
+ nextTr,
133
135
  );
134
136
  }
135
137
 
@@ -139,7 +141,7 @@ export const moveSource = (
139
141
  selectStartOfTable,
140
142
  selectColumn(targetIndex),
141
143
  ],
142
- tr,
144
+ nextTr,
143
145
  );
144
146
  },
145
147
  );
@@ -10,11 +10,13 @@ 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';
13
14
  import {
14
15
  hasMergedCellsInColumn,
15
16
  hasMergedCellsInRow,
16
17
  } from '../../utils/merged-cells';
17
18
  import { getPluginState as getTablePluginState } from '../plugin-factory';
19
+ import { pluginKey as tablePluginKey } from '../plugin-key';
18
20
 
19
21
  import { DragAndDropActionType } from './actions';
20
22
  import {
@@ -135,19 +137,51 @@ export const createPlugin = (
135
137
  onDrop(event) {
136
138
  const data = getDraggableDataFromEvent(event);
137
139
 
140
+ // On Drop we need to update the table main plugin hoveredCell value with the current row/col that the mouse is
141
+ // over. This is so the drag handles update their positions to correctly align with the users mouse. Unfortunately
142
+ // at this point in time and during the drag opertation, the drop targets are eating all the mouse events so
143
+ // it's not possible to know what row/col the mouse is over (via mouse events). This attempts to locate the nearest cell and
144
+ // then tries to update the main table hoveredCell value by piggy-backing the transaction onto the command
145
+ // triggered by this on drop event.
146
+ const { hoveredCell } = getTablePluginState(editorView.state);
147
+
148
+ const cell = findNearestCellIndexToPoint(
149
+ event.location.current.input.clientX,
150
+ event.location.current.input.clientY,
151
+ );
152
+ const tr = editorView.state.tr;
153
+ const action = {
154
+ type: 'HOVER_CELL',
155
+ data: {
156
+ hoveredCell: {
157
+ rowIndex: cell?.row ?? hoveredCell.rowIndex,
158
+ colIndex: cell?.col ?? hoveredCell.colIndex,
159
+ },
160
+ },
161
+ };
162
+ tr.setMeta(tablePluginKey, action);
163
+
138
164
  // If no data can be found then it's most like we do not want to perform any drop action
139
165
  if (!data) {
140
- clearDropTarget()(editorView.state, editorView.dispatch);
166
+ clearDropTarget(tr)(editorView.state, editorView.dispatch);
141
167
  return;
142
168
  }
143
169
 
144
170
  const {
145
171
  sourceType,
146
172
  sourceIndexes,
173
+ targetIndex,
147
174
  targetAdjustedIndex,
148
175
  direction,
149
176
  } = data;
150
177
 
178
+ // When we drop on a target we will know the targets row/col index for certain,
179
+ if (sourceType === 'table-row') {
180
+ action.data.hoveredCell.rowIndex = targetIndex;
181
+ } else {
182
+ action.data.hoveredCell.colIndex = targetIndex;
183
+ }
184
+
151
185
  // If the drop target index contains merged cells then we should not allow the drop to occur.
152
186
  const hasMergedCells =
153
187
  sourceType === 'table-row'
@@ -156,7 +190,7 @@ export const createPlugin = (
156
190
  if (
157
191
  hasMergedCells(targetAdjustedIndex)(editorView.state.selection)
158
192
  ) {
159
- clearDropTarget()(editorView.state, editorView.dispatch);
193
+ clearDropTarget(tr)(editorView.state, editorView.dispatch);
160
194
  return;
161
195
  }
162
196
 
@@ -167,6 +201,7 @@ export const createPlugin = (
167
201
  sourceType,
168
202
  sourceIndex,
169
203
  targetAdjustedIndex + (direction === -1 ? 0 : -1),
204
+ tr,
170
205
  )(editorView.state, editorView.dispatch);
171
206
  });
172
207
  },
@@ -57,6 +57,7 @@ import {
57
57
  handleCut,
58
58
  handleFocus,
59
59
  handleMouseDown,
60
+ handleMouseEnter,
60
61
  handleMouseLeave,
61
62
  handleMouseMove,
62
63
  handleMouseOut,
@@ -112,6 +113,7 @@ export const createPlugin = (
112
113
  ) => {
113
114
  const state = createPluginState(dispatch, {
114
115
  pluginConfig,
116
+ isTableHovered: false,
115
117
  insertColumnButtonIndex: undefined,
116
118
  insertRowButtonIndex: undefined,
117
119
  isFullWidthModeEnabled: fullWidthModeEnabled,
@@ -382,11 +384,12 @@ export const createPlugin = (
382
384
  focus: handleFocus,
383
385
  blur: handleBlur,
384
386
  mousedown: withCellTracking(handleMouseDown),
385
- mouseover: whenTableInFocus(withCellTracking(handleMouseOver)),
386
- mouseleave: whenTableInFocus(handleMouseLeave),
387
+ mouseover: withCellTracking(whenTableInFocus(handleMouseOver)),
388
+ mouseleave: handleMouseLeave,
387
389
  mouseout: whenTableInFocus(handleMouseOut),
388
390
  mousemove: whenTableInFocus(handleMouseMove, elementContentRects),
389
- click: whenTableInFocus(handleClick),
391
+ mouseenter: handleMouseEnter,
392
+ click: withCellTracking(whenTableInFocus(handleClick)),
390
393
  },
391
394
 
392
395
  handleTripleClick,
@@ -145,6 +145,7 @@ export default (
145
145
  case 'HOVER_ROWS':
146
146
  case 'HOVER_COLUMNS':
147
147
  case 'HOVER_TABLE':
148
+ case 'TABLE_HOVERED':
148
149
  case 'HOVER_MERGED_CELLS':
149
150
  case 'HOVER_CELL':
150
151
  case 'SHOW_RESIZE_HANDLE_LINE':
@@ -88,8 +88,6 @@ export type CellColumnPositioning = Pick<Rect, 'right' | 'left'>;
88
88
  export interface CellHoverMeta {
89
89
  colIndex?: number;
90
90
  rowIndex?: number;
91
- colWidth?: number;
92
- colHeight?: number;
93
91
  }
94
92
 
95
93
  export interface TablePluginState {
@@ -130,6 +128,7 @@ export interface TablePluginState {
130
128
  wasFullWidthModeEnabled?: boolean;
131
129
  isTableResizingEnabled?: boolean;
132
130
  isDragAndDropEnabled?: boolean;
131
+ isTableHovered?: boolean;
133
132
  }
134
133
 
135
134
  export type TablePluginAction =
@@ -210,6 +209,12 @@ export type TablePluginAction =
210
209
  hoveredCell: CellHoverMeta;
211
210
  };
212
211
  }
212
+ | {
213
+ type: 'TABLE_HOVERED';
214
+ data: {
215
+ isTableHovered: boolean;
216
+ };
217
+ }
213
218
  | { type: 'SET_TARGET_CELL_POSITION'; data: { targetCellPosition?: number } }
214
219
  | {
215
220
  type: 'SELECT_COLUMN';
@@ -50,8 +50,9 @@ export const DragHandle = ({
50
50
  const [previewContainer, setPreviewContainer] = useState<HTMLElement | null>(
51
51
  null,
52
52
  );
53
- const { isDragAndDropEnabled, hoveredColumns, hoveredRows, hoveredCell } =
54
- getPluginState(editorView.state);
53
+ const { hoveredColumns, hoveredRows, hoveredCell } = getPluginState(
54
+ editorView.state,
55
+ );
55
56
 
56
57
  const { dragMenuDirection, isDragMenuOpen, dragMenuIndex } =
57
58
  getDragDropPluginState(editorView.state);
@@ -138,17 +139,14 @@ export const DragHandle = ({
138
139
  <button
139
140
  className={classnames(
140
141
  ClassName.DRAG_HANDLE_BUTTON_CONTAINER,
141
- ClassName.CONTROLS_BUTTON,
142
142
  appearance,
143
143
  {
144
- [ClassName.DRAG_HANDLE_DISABLED]:
145
- isDragAndDropEnabled && hasMergedCells,
144
+ [ClassName.DRAG_HANDLE_DISABLED]: hasMergedCells,
146
145
  },
147
146
  )}
148
147
  ref={dragHandleDivRef}
149
148
  style={{
150
149
  transform: direction === 'column' ? 'none' : 'rotate(90deg)',
151
- pointerEvents: 'auto',
152
150
  }}
153
151
  data-testid="table-floating-column-controls-drag-handle"
154
152
  onMouseOver={onMouseOver}
@@ -161,7 +159,9 @@ export const DragHandle = ({
161
159
  }}
162
160
  onClick={onClick}
163
161
  >
164
- <HandleIconComponent {...handleIconProps} />
162
+ <span style={{ pointerEvents: 'none' }}>
163
+ <HandleIconComponent {...handleIconProps} />
164
+ </span>
165
165
  </button>
166
166
  {previewContainer &&
167
167
  previewWidth !== undefined &&
@@ -30,6 +30,7 @@ export interface ColumnControlsProps {
30
30
  rowHeights?: number[];
31
31
  colWidths?: (number | undefined)[];
32
32
  hasHeaderColumn?: boolean;
33
+ isTableHovered?: boolean;
33
34
  }
34
35
 
35
36
  const getSelectedColumns = (selection: Selection) => {
@@ -55,6 +56,7 @@ export const ColumnControls = ({
55
56
  rowHeights,
56
57
  colWidths,
57
58
  hasHeaderColumn,
59
+ isTableHovered,
58
60
  }: ColumnControlsProps) => {
59
61
  const widths =
60
62
  colWidths?.map((width) => (width ? `${width - 1}px` : '0px')).join(' ') ??
@@ -109,11 +111,15 @@ export const ColumnControls = ({
109
111
 
110
112
  // update hovered cell location
111
113
  const { state, dispatch } = editorView;
112
- if (tableActive && hoveredCell?.colIndex !== Number(colIndex)) {
113
- hoverCell(hoveredCell?.rowIndex, Number(colIndex))(state, dispatch);
114
+ if (tableActive) {
115
+ // For context: Whenever we mouse over a column or row drag handle, we will ALWAYS be hovering over the 0 index
116
+ // of the opposite dimension. For example; here when we mouse over the column drag handle then we're technically
117
+ // also hovering over row 0 index. And vice-versa with rows. This means we don't need to worry about knowing the
118
+ // current row index. We can just force it to 0.
119
+ hoverCell(0, Number(colIndex))(state, dispatch);
114
120
  }
115
121
  },
116
- [editorView, hoveredCell?.colIndex, hoveredCell?.rowIndex, tableActive],
122
+ [editorView, tableActive],
117
123
  );
118
124
 
119
125
  const handleMouseOut = useCallback(() => {
@@ -132,6 +138,8 @@ export const ColumnControls = ({
132
138
  return [colIndex!];
133
139
  }, [colIndex]);
134
140
 
141
+ const previewHeight = rowHeights?.reduce((sum, cur) => sum + cur, 0) ?? 0;
142
+
135
143
  return (
136
144
  <div
137
145
  className={ClassName.DRAG_COLUMN_CONTROLS}
@@ -175,6 +183,7 @@ export const ColumnControls = ({
175
183
  ))}
176
184
  {tableActive &&
177
185
  !isResizing &&
186
+ isTableHovered &&
178
187
  !!hoveredCell &&
179
188
  Number.isFinite(hoveredCell.colIndex) && (
180
189
  <div
@@ -183,6 +192,8 @@ export const ColumnControls = ({
183
192
  display: 'flex',
184
193
  justifyContent: 'center',
185
194
  alignItems: 'center',
195
+ height: 'fit-content',
196
+ placeSelf: 'center',
186
197
  zIndex: 99,
187
198
  }}
188
199
  data-column-control-index={hoveredCell.colIndex}
@@ -192,8 +203,8 @@ export const ColumnControls = ({
192
203
  direction="column"
193
204
  tableLocalId={localId || ''}
194
205
  indexes={colIndexes}
195
- previewWidth={hoveredCell.colWidth}
196
- previewHeight={hoveredCell.colHeight}
206
+ previewWidth={colWidths?.[colIndex!] ?? 48}
207
+ previewHeight={previewHeight}
197
208
  appearance={
198
209
  selectedColIndexes.includes(hoveredCell.colIndex!)
199
210
  ? isInDanger
@@ -34,6 +34,7 @@ export interface Props {
34
34
  isResizing?: boolean;
35
35
  ordering?: TableColumnOrdering;
36
36
  stickyHeader?: RowStickyState;
37
+ isTableHovered?: boolean;
37
38
  }
38
39
 
39
40
  export const TableFloatingColumnControls: React.FC<Props> = ({
@@ -47,6 +48,7 @@ export const TableFloatingColumnControls: React.FC<Props> = ({
47
48
  stickyHeader,
48
49
  selection,
49
50
  isInDanger,
51
+ isTableHovered,
50
52
  }) => {
51
53
  const [tableRect, setTableRect] = useState<{ width: number; height: number }>(
52
54
  { width: 0, height: 0 },
@@ -130,6 +132,7 @@ export const TableFloatingColumnControls: React.FC<Props> = ({
130
132
  tableRef={tableRef}
131
133
  isResizing={isResizing}
132
134
  tableActive={tableActive}
135
+ isTableHovered={isTableHovered}
133
136
  stickyTop={tableActive ? stickyTop : undefined}
134
137
  localId={currentNodeLocalId}
135
138
  isInDanger={isInDanger}
@@ -41,6 +41,7 @@ type DragControlsProps = {
41
41
  hoveredCell?: CellHoverMeta;
42
42
  isInDanger?: boolean;
43
43
  isResizing?: boolean;
44
+ isTableHovered?: boolean;
44
45
  hoverRows: (rows: number[], danger?: boolean) => void;
45
46
  selectRow: (row: number, expand: boolean) => void;
46
47
  updateCellHoverLocation: (rowIndex: number) => void;
@@ -66,6 +67,7 @@ const DragControlsComponent = ({
66
67
  editorView,
67
68
  isInDanger,
68
69
  isResizing,
70
+ isTableHovered,
69
71
  hoverRows,
70
72
  selectRow,
71
73
  updateCellHoverLocation,
@@ -217,7 +219,7 @@ const DragControlsComponent = ({
217
219
  )}
218
220
  </Fragment>
219
221
  ))}
220
- {!isResizing && Number.isFinite(rowIndex) && (
222
+ {!isResizing && isTableHovered && Number.isFinite(rowIndex) && (
221
223
  <div
222
224
  style={{
223
225
  gridRow: gridRowPosition,
@@ -7,7 +7,6 @@ import type { Selection } from '@atlaskit/editor-prosemirror/state';
7
7
  import type { EditorView } from '@atlaskit/editor-prosemirror/view';
8
8
 
9
9
  import { hoverCell, hoverRows, selectRow } from '../../commands';
10
- import { getPluginState } from '../../pm-plugins/plugin-factory';
11
10
  import type { RowStickyState } from '../../pm-plugins/sticky-headers';
12
11
  import { TableCssClassName as ClassName } from '../../types';
13
12
  import type { CellHoverMeta } from '../../types';
@@ -24,6 +23,7 @@ export interface Props {
24
23
  tableNode?: PmNode;
25
24
  tableActive?: boolean;
26
25
  isInDanger?: boolean;
26
+ isTableHovered?: boolean;
27
27
  isResizing?: boolean;
28
28
  isHeaderRowEnabled?: boolean;
29
29
  isHeaderColumnEnabled?: boolean;
@@ -105,6 +105,7 @@ export default class TableFloatingControls extends Component<Props, State> {
105
105
  headerRowHeight,
106
106
  stickyHeader,
107
107
  hoveredCell,
108
+ isTableHovered,
108
109
  } = this.props;
109
110
  return (
110
111
  this.state.tableWrapperWidth !== nextState.tableWrapperWidth ||
@@ -121,7 +122,8 @@ export default class TableFloatingControls extends Component<Props, State> {
121
122
  isSelectionUpdated(selection!, nextProps.selection) ||
122
123
  headerRowHeight !== nextProps.headerRowHeight ||
123
124
  stickyHeader !== nextProps.stickyHeader ||
124
- hoveredCell !== nextProps.hoveredCell
125
+ hoveredCell !== nextProps.hoveredCell ||
126
+ isTableHovered !== nextProps.isTableHovered
125
127
  );
126
128
  }
127
129
 
@@ -147,6 +149,7 @@ export default class TableFloatingControls extends Component<Props, State> {
147
149
  stickyHeader,
148
150
  isDragAndDropEnabled,
149
151
  hoveredCell,
152
+ isTableHovered,
150
153
  } = this.props;
151
154
 
152
155
  if (!tableRef) {
@@ -196,6 +199,7 @@ export default class TableFloatingControls extends Component<Props, State> {
196
199
  tableRef={tableRef}
197
200
  tableNode={tableNode}
198
201
  hoveredCell={hoveredCell}
202
+ isTableHovered={isTableHovered}
199
203
  editorView={editorView}
200
204
  tableActive={tableActive}
201
205
  isInDanger={isInDanger}
@@ -256,10 +260,13 @@ export default class TableFloatingControls extends Component<Props, State> {
256
260
  private updateCellHoverLocation = (rowIndex: number) => {
257
261
  const { editorView, tableActive } = this.props;
258
262
  const { state, dispatch } = editorView;
259
- const { hoveredCell } = getPluginState(state);
260
263
 
261
- if (tableActive && hoveredCell.rowIndex !== rowIndex) {
262
- hoverCell(rowIndex, hoveredCell.colIndex)(state, dispatch);
264
+ if (tableActive) {
265
+ // For context: Whenever we mouse over a column or row drag handle, we will ALWAYS be hovering over the 0 index
266
+ // of the opposite dimension. For example; here when we mouse over the row drag handle then we're technically
267
+ // also hovering over column 0 index. And vice-versa with columns. This means we don't need to worry about knowing the
268
+ // current column index. We can just force it to 0.
269
+ hoverCell(rowIndex, 0)(state, dispatch);
263
270
  }
264
271
  };
265
272
  }
@@ -766,19 +766,21 @@ export const tableStyles = (
766
766
 
767
767
  .${ClassName.DRAG_HANDLE_BUTTON_CONTAINER} {
768
768
  cursor: grab;
769
- padding: 0;
769
+ pointer-events: auto;
770
770
 
771
+ line-height: 0;
772
+ padding: 0;
771
773
  border-radius: 6px;
772
774
  width: max-content;
773
- height: max-content;
774
775
  border: 2px solid ${token('elevation.surface', N0)};
776
+
775
777
  display: flex;
776
778
  justify-content: center;
777
779
  align-items: center;
778
780
  outline: none !important;
779
781
 
780
782
  &.${ClassName.DRAG_HANDLE_DISABLED} {
781
- & > svg {
783
+ & svg {
782
784
  & > rect.${ClassName.DRAG_HANDLE_MINIMISED} {
783
785
  fill: ${token('color.background.accent.gray.subtler', '#DCDFE4')};
784
786
  }
@@ -792,7 +794,7 @@ export const tableStyles = (
792
794
  }
793
795
 
794
796
  &:not(.${ClassName.DRAG_HANDLE_DISABLED}) {
795
- & > svg {
797
+ & svg {
796
798
  rect {
797
799
  fill: ${token('color.background.accent.gray.subtler', '#DCDFE4')};
798
800
  }
@@ -264,3 +264,25 @@ export const getTop = (element: HTMLElement | Window | undefined): number => {
264
264
 
265
265
  return element?.getBoundingClientRect?.()?.top ?? 0;
266
266
  };
267
+
268
+ export const findNearestCellIndexToPoint = (
269
+ x: number,
270
+ y: number,
271
+ ): { row: number; col: number } | undefined => {
272
+ const elements = document.elementsFromPoint(x, y);
273
+ const cell = elements.find(
274
+ (el) =>
275
+ el.nodeName.toUpperCase() === 'TD' || el.nodeName.toUpperCase() === 'TH',
276
+ ) as HTMLTableCellElement | undefined;
277
+ const row = (cell?.parentElement ?? undefined) as
278
+ | HTMLTableRowElement
279
+ | undefined;
280
+
281
+ if (!Number.isFinite(row?.rowIndex) || !Number.isFinite(cell?.cellIndex)) {
282
+ return undefined;
283
+ }
284
+ return {
285
+ row: row!.rowIndex,
286
+ col: cell!.cellIndex,
287
+ };
288
+ };
@@ -57,6 +57,7 @@ export {
57
57
  updateResizeHandles,
58
58
  isResizeHandleDecoration,
59
59
  hasResizeHandler,
60
+ findNearestCellIndexToPoint,
60
61
  } from './dom';
61
62
  export {
62
63
  convertHTMLCellIndexToColumnIndex,