@atlaskit/editor-plugin-table 5.3.10 → 5.3.12

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 (58) hide show
  1. package/CHANGELOG.md +12 -0
  2. package/dist/cjs/plugins/table/nodeviews/TableComponent.js +3 -2
  3. package/dist/cjs/plugins/table/pm-plugins/drag-and-drop/commands.js +5 -2
  4. package/dist/cjs/plugins/table/ui/DragHandle/index.js +11 -25
  5. package/dist/cjs/plugins/table/ui/TableFloatingColumnControls/ColumnControls/index.js +56 -20
  6. package/dist/cjs/plugins/table/ui/TableFloatingColumnControls/index.js +3 -1
  7. package/dist/cjs/plugins/table/ui/TableFloatingControls/NumberColumn/index.js +15 -27
  8. package/dist/cjs/plugins/table/ui/TableFloatingControls/RowControls/DragControls.js +68 -18
  9. package/dist/cjs/plugins/table/ui/TableFloatingControls/index.js +47 -29
  10. package/dist/cjs/plugins/table/ui/common-styles.js +2 -2
  11. package/dist/cjs/plugins/table/ui/icons/DragHandleIcon.js +11 -52
  12. package/dist/es2019/plugins/table/nodeviews/TableComponent.js +3 -2
  13. package/dist/es2019/plugins/table/pm-plugins/drag-and-drop/commands.js +6 -3
  14. package/dist/es2019/plugins/table/ui/DragHandle/index.js +10 -24
  15. package/dist/es2019/plugins/table/ui/TableFloatingColumnControls/ColumnControls/index.js +57 -15
  16. package/dist/es2019/plugins/table/ui/TableFloatingColumnControls/index.js +3 -1
  17. package/dist/es2019/plugins/table/ui/TableFloatingControls/NumberColumn/index.js +4 -20
  18. package/dist/es2019/plugins/table/ui/TableFloatingControls/RowControls/DragControls.js +69 -17
  19. package/dist/es2019/plugins/table/ui/TableFloatingControls/index.js +24 -2
  20. package/dist/es2019/plugins/table/ui/common-styles.js +64 -4
  21. package/dist/es2019/plugins/table/ui/icons/DragHandleIcon.js +11 -52
  22. package/dist/esm/plugins/table/nodeviews/TableComponent.js +3 -2
  23. package/dist/esm/plugins/table/pm-plugins/drag-and-drop/commands.js +6 -3
  24. package/dist/esm/plugins/table/ui/DragHandle/index.js +11 -25
  25. package/dist/esm/plugins/table/ui/TableFloatingColumnControls/ColumnControls/index.js +53 -19
  26. package/dist/esm/plugins/table/ui/TableFloatingColumnControls/index.js +3 -1
  27. package/dist/esm/plugins/table/ui/TableFloatingControls/NumberColumn/index.js +16 -28
  28. package/dist/esm/plugins/table/ui/TableFloatingControls/RowControls/DragControls.js +67 -19
  29. package/dist/esm/plugins/table/ui/TableFloatingControls/index.js +48 -30
  30. package/dist/esm/plugins/table/ui/common-styles.js +2 -2
  31. package/dist/esm/plugins/table/ui/icons/DragHandleIcon.js +11 -51
  32. package/dist/types/plugins/table/ui/DragHandle/index.d.ts +3 -3
  33. package/dist/types/plugins/table/ui/TableFloatingColumnControls/ColumnControls/index.d.ts +4 -3
  34. package/dist/types/plugins/table/ui/TableFloatingColumnControls/index.d.ts +1 -0
  35. package/dist/types/plugins/table/ui/TableFloatingControls/NumberColumn/index.d.ts +1 -1
  36. package/dist/types/plugins/table/ui/TableFloatingControls/RowControls/DragControls.d.ts +4 -2
  37. package/dist/types/plugins/table/ui/TableFloatingControls/index.d.ts +1 -0
  38. package/dist/types/plugins/table/ui/icons/DragHandleIcon.d.ts +1 -6
  39. package/dist/types-ts4.5/plugins/table/ui/DragHandle/index.d.ts +3 -3
  40. package/dist/types-ts4.5/plugins/table/ui/TableFloatingColumnControls/ColumnControls/index.d.ts +4 -3
  41. package/dist/types-ts4.5/plugins/table/ui/TableFloatingColumnControls/index.d.ts +1 -0
  42. package/dist/types-ts4.5/plugins/table/ui/TableFloatingControls/NumberColumn/index.d.ts +1 -1
  43. package/dist/types-ts4.5/plugins/table/ui/TableFloatingControls/RowControls/DragControls.d.ts +4 -2
  44. package/dist/types-ts4.5/plugins/table/ui/TableFloatingControls/index.d.ts +1 -0
  45. package/dist/types-ts4.5/plugins/table/ui/icons/DragHandleIcon.d.ts +1 -6
  46. package/package.json +2 -2
  47. package/src/__tests__/unit/ui/NumberColumn.tsx +5 -8
  48. package/src/__tests__/unit/ui/RowDragControls.tsx +6 -0
  49. package/src/plugins/table/nodeviews/TableComponent.tsx +3 -2
  50. package/src/plugins/table/pm-plugins/drag-and-drop/commands.ts +11 -3
  51. package/src/plugins/table/ui/DragHandle/index.tsx +10 -26
  52. package/src/plugins/table/ui/TableFloatingColumnControls/ColumnControls/index.tsx +69 -23
  53. package/src/plugins/table/ui/TableFloatingColumnControls/index.tsx +3 -0
  54. package/src/plugins/table/ui/TableFloatingControls/NumberColumn/index.tsx +10 -15
  55. package/src/plugins/table/ui/TableFloatingControls/RowControls/DragControls.tsx +95 -26
  56. package/src/plugins/table/ui/TableFloatingControls/index.tsx +17 -1
  57. package/src/plugins/table/ui/common-styles.ts +67 -4
  58. package/src/plugins/table/ui/icons/DragHandleIcon.tsx +5 -69
@@ -435,12 +435,13 @@ class TableComponent extends React.Component<ComponentProps, TableState> {
435
435
  </div>
436
436
  );
437
437
 
438
- const colControls = (
438
+ const colControls = isDragAndDropEnabled ? (
439
439
  <TableFloatingColumnControls
440
440
  editorView={view}
441
441
  tableRef={tableRef}
442
442
  getNode={getNode}
443
443
  tableActive={tableActive}
444
+ isInDanger={isInDanger}
444
445
  hoveredRows={hoveredRows}
445
446
  hoveredCell={hoveredCell}
446
447
  isResizing={isResizing}
@@ -452,7 +453,7 @@ class TableComponent extends React.Component<ComponentProps, TableState> {
452
453
  stickyHeader={this.state.stickyHeader}
453
454
  getEditorFeatureFlags={this.props.getEditorFeatureFlags}
454
455
  />
455
- );
456
+ ) : null;
456
457
 
457
458
  const shadowPadding =
458
459
  allowControls && tableActive ? -tableToolbarSize : tableMarginSides;
@@ -4,7 +4,12 @@ import type {
4
4
  } from '@atlaskit/editor-prosemirror/state';
5
5
  import type { Decoration } from '@atlaskit/editor-prosemirror/view';
6
6
  import { DecorationSet } from '@atlaskit/editor-prosemirror/view';
7
- import { moveColumn, moveRow } from '@atlaskit/editor-tables/utils';
7
+ import {
8
+ moveColumn,
9
+ moveRow,
10
+ selectColumn,
11
+ selectRow,
12
+ } from '@atlaskit/editor-tables/utils';
8
13
 
9
14
  import type { DraggableType } from '../../types';
10
15
  import { TableDecorations } from '../../types';
@@ -109,7 +114,10 @@ export const moveSource = (
109
114
  return tr.setMeta('addToHistory', false);
110
115
  }
111
116
 
112
- const move = sourceType === 'table-row' ? moveRow : moveColumn;
113
- return move(sourceIndex, targetIndex)(tr);
117
+ const isTableRow = sourceType === 'table-row';
118
+ const move = isTableRow ? moveRow : moveColumn;
119
+ const newTr = move(sourceIndex, targetIndex)(tr);
120
+ const select = isTableRow ? selectRow : selectColumn;
121
+ return select(targetIndex)(newTr);
114
122
  },
115
123
  );
@@ -1,18 +1,17 @@
1
1
  import type { MouseEventHandler } from 'react';
2
2
  import React, { useEffect, useRef, useState } from 'react';
3
3
 
4
+ import classnames from 'classnames';
4
5
  import ReactDOM from 'react-dom';
5
6
 
6
7
  import { draggable } from '@atlaskit/pragmatic-drag-and-drop/adapter/element';
7
8
  import { setCustomNativeDragPreview } from '@atlaskit/pragmatic-drag-and-drop/util/set-custom-native-drag-preview';
8
- import { N200, N700 } from '@atlaskit/theme/colors';
9
- import { token } from '@atlaskit/tokens';
10
9
 
11
10
  import { TableCssClassName as ClassName } from '../../types';
12
11
  import { DragPreview } from '../DragPreview';
13
12
  import { DragHandleIcon } from '../icons';
14
13
 
15
- type DragHandleState = 'default' | 'selected' | 'disabled' | 'danger';
14
+ type DragHandleAppearance = 'default' | 'selected' | 'disabled' | 'danger';
16
15
 
17
16
  type DragHandleProps = {
18
17
  tableLocalId: string;
@@ -20,39 +19,24 @@ type DragHandleProps = {
20
19
  previewWidth?: number;
21
20
  previewHeight?: number;
22
21
  direction?: 'column' | 'row';
23
- state?: DragHandleState;
22
+ appearance?: DragHandleAppearance;
24
23
  onClick?: MouseEventHandler;
25
24
  onMouseOver?: MouseEventHandler;
26
25
  onMouseOut?: MouseEventHandler;
27
26
  };
28
27
 
29
- const mapStateToProps = (state: DragHandleState) => {
30
- switch (state) {
31
- case 'danger':
32
- case 'disabled':
33
- case 'selected':
34
- case 'default':
35
- default:
36
- return {
37
- backgroundColor: token('color.background.accent.gray.subtlest', N200),
38
- foregroundColor: token('color.icon.subtle', N700),
39
- };
40
- }
41
- };
42
-
43
28
  export const DragHandle = ({
44
29
  tableLocalId,
45
30
  direction = 'row',
46
- state = 'default',
31
+ appearance = 'default',
47
32
  indexes,
48
33
  previewWidth,
49
34
  previewHeight,
50
- onClick,
51
35
  onMouseOver,
52
36
  onMouseOut,
37
+ onClick,
53
38
  }: DragHandleProps) => {
54
39
  const dragHandleDivRef = useRef<HTMLButtonElement>(null);
55
- const iconProps = mapStateToProps(state);
56
40
  const [previewContainer, setPreviewContainer] = useState<HTMLElement | null>(
57
41
  null,
58
42
  );
@@ -92,18 +76,18 @@ export const DragHandle = ({
92
76
 
93
77
  return (
94
78
  <button
95
- className={ClassName.DRAG_HANDLE_BUTTON_CONTAINER}
79
+ className={classnames(ClassName.DRAG_HANDLE_BUTTON_CONTAINER, appearance)}
96
80
  ref={dragHandleDivRef}
97
81
  style={{
98
- backgroundColor: `${token('elevation.surface', 'white')}`,
99
- borderRadius: '4px',
100
- border: `2px solid ${token('elevation.surface', 'white')}`,
101
82
  transform: direction === 'column' ? 'none' : 'rotate(90deg)',
102
83
  pointerEvents: 'auto',
103
84
  }}
104
85
  data-testid="table-floating-column-controls-drag-handle"
86
+ onMouseOver={onMouseOver}
87
+ onMouseOut={onMouseOut}
88
+ onClick={onClick}
105
89
  >
106
- <DragHandleIcon {...iconProps} />
90
+ <DragHandleIcon />
107
91
  {previewContainer &&
108
92
  previewWidth !== undefined &&
109
93
  previewHeight !== undefined &&
@@ -1,14 +1,25 @@
1
- import React from 'react';
1
+ import type { MouseEvent } from 'react';
2
+ import React, { useCallback, useMemo } from 'react';
2
3
 
4
+ import type { Selection } from '@atlaskit/editor-prosemirror/state';
3
5
  import type { EditorView } from '@atlaskit/editor-prosemirror/view';
6
+ import { CellSelection } from '@atlaskit/editor-tables';
7
+ import { getSelectionRect } from '@atlaskit/editor-tables/utils';
4
8
 
9
+ import {
10
+ clearHoverSelection,
11
+ hoverColumns,
12
+ selectColumn,
13
+ } from '../../../commands';
5
14
  import type { CellHoverMeta } from '../../../types';
6
15
  import { TableCssClassName as ClassName } from '../../../types';
16
+ import { getSelectedColumnIndexes } from '../../../utils';
7
17
  import { DragHandle } from '../../DragHandle';
8
18
 
9
- export interface Props {
19
+ export interface ColumnControlsProps {
10
20
  editorView: EditorView;
11
21
  tableActive?: boolean;
22
+ isInDanger?: boolean;
12
23
  tableRef: HTMLTableElement;
13
24
  hoveredCell?: CellHoverMeta;
14
25
  isResizing?: boolean;
@@ -18,7 +29,18 @@ export interface Props {
18
29
  colWidths?: (number | undefined)[];
19
30
  }
20
31
 
21
- export const ColumnControls: React.FC<Props> = ({
32
+ const getSelectedColumns = (selection: Selection) => {
33
+ if (selection instanceof CellSelection && selection.isColSelection()) {
34
+ const rect = getSelectionRect(selection);
35
+ if (!rect) {
36
+ return [];
37
+ }
38
+ return getSelectedColumnIndexes(rect);
39
+ }
40
+ return [];
41
+ };
42
+
43
+ export const ColumnControls = ({
22
44
  editorView,
23
45
  tableActive,
24
46
  tableRef,
@@ -26,12 +48,23 @@ export const ColumnControls: React.FC<Props> = ({
26
48
  isResizing,
27
49
  stickyTop,
28
50
  localId,
51
+ isInDanger,
29
52
  rowHeights,
30
53
  colWidths,
31
- }) => {
32
- if (!tableRef) {
33
- return null;
34
- }
54
+ }: ColumnControlsProps) => {
55
+ const widths =
56
+ colWidths?.map((width) => (width ? `${width - 1}px` : '0px')).join(' ') ??
57
+ '0px';
58
+ const colIndex = hoveredCell?.colIndex;
59
+ const selectedColIndexes = getSelectedColumns(editorView.state.selection);
60
+
61
+ const gridColumnPosition = useMemo(() => {
62
+ // if more than one row is selected, ensure the handle spans over the selected range
63
+ if (selectedColIndexes.includes(colIndex!)) {
64
+ return `${selectedColIndexes[0] + 1} / span ${selectedColIndexes.length}`;
65
+ }
66
+ return `${colIndex! + 1} / span 1`;
67
+ }, [colIndex, selectedColIndexes]);
35
68
 
36
69
  const firstRow = tableRef.querySelector('tr');
37
70
  const hasHeaderRow = firstRow
@@ -41,17 +74,25 @@ export const ColumnControls: React.FC<Props> = ({
41
74
  const marginTop =
42
75
  hasHeaderRow && stickyTop !== undefined ? rowHeights?.[0] ?? 0 : 0;
43
76
 
44
- const widths =
45
- colWidths?.map((width) => (width ? `${width - 1}px` : '0px')).join(' ') ??
46
- '0px';
77
+ const handleClick = useCallback(
78
+ (event: MouseEvent) => {
79
+ const { state, dispatch } = editorView;
80
+ selectColumn(colIndex!, event.shiftKey)(state, dispatch);
81
+ },
82
+ [colIndex, editorView],
83
+ );
47
84
 
48
- const onClick = (
49
- index: number,
50
- event: React.MouseEvent<Element, MouseEvent>,
51
- ) => {};
85
+ const handleMouseOver = useCallback(() => {
86
+ const { state, dispatch } = editorView;
87
+ hoverColumns([colIndex!])(state, dispatch);
88
+ }, [colIndex, editorView]);
52
89
 
53
- const onMouseOver = () => {};
54
- const onMouseOut = () => {};
90
+ const handleMouseOut = useCallback(() => {
91
+ if (tableActive) {
92
+ const { state, dispatch } = editorView;
93
+ clearHoverSelection()(state, dispatch);
94
+ }
95
+ }, [editorView, tableActive]);
55
96
 
56
97
  return (
57
98
  <div className={ClassName.COLUMN_CONTROLS_WITH_DRAG}>
@@ -69,7 +110,7 @@ export const ColumnControls: React.FC<Props> = ({
69
110
  Number.isFinite(hoveredCell.colIndex) && (
70
111
  <div
71
112
  style={{
72
- gridColumn: `${(hoveredCell.colIndex as number) + 1} / span 1`,
113
+ gridColumn: gridColumnPosition,
73
114
  marginTop: `-15px`,
74
115
  }}
75
116
  data-column-control-index={hoveredCell.colIndex}
@@ -77,15 +118,20 @@ export const ColumnControls: React.FC<Props> = ({
77
118
  >
78
119
  <DragHandle
79
120
  direction="column"
80
- indexes={[hoveredCell.colIndex!]}
81
- onClick={(event) =>
82
- onClick(hoveredCell.colIndex as number, event)
83
- }
84
- onMouseOver={onMouseOver}
85
- onMouseOut={onMouseOut}
86
121
  tableLocalId={localId || ''}
122
+ indexes={[hoveredCell.colIndex!]}
87
123
  previewWidth={hoveredCell.colWidth}
88
124
  previewHeight={hoveredCell.colHeight}
125
+ appearance={
126
+ selectedColIndexes.includes(hoveredCell.colIndex!)
127
+ ? isInDanger
128
+ ? 'danger'
129
+ : 'selected'
130
+ : 'default'
131
+ }
132
+ onClick={handleClick}
133
+ onMouseOver={handleMouseOver}
134
+ onMouseOut={handleMouseOut}
89
135
  />
90
136
  </div>
91
137
  )}
@@ -24,6 +24,7 @@ export interface Props {
24
24
  tableRef?: HTMLTableElement;
25
25
  getNode: () => PmNode;
26
26
  tableActive?: boolean;
27
+ isInDanger?: boolean;
27
28
  hasHeaderRow?: boolean;
28
29
  headerRowHeight?: number;
29
30
  hoveredRows?: number[];
@@ -43,6 +44,7 @@ export const TableFloatingColumnControls: React.FC<Props> = ({
43
44
  isResizing,
44
45
  stickyHeader,
45
46
  selection,
47
+ isInDanger,
46
48
  }) => {
47
49
  const [tableRect, setTableRect] = useState<{ width: number; height: number }>(
48
50
  { width: 0, height: 0 },
@@ -132,6 +134,7 @@ export const TableFloatingColumnControls: React.FC<Props> = ({
132
134
  tableActive={tableActive}
133
135
  stickyTop={tableActive ? stickyTop : undefined}
134
136
  localId={currentNodeLocalId}
137
+ isInDanger={isInDanger}
135
138
  rowHeights={rowHeights}
136
139
  colWidths={colWidths}
137
140
  />
@@ -6,8 +6,7 @@ import { Selection } from '@atlaskit/editor-prosemirror/state';
6
6
  import type { EditorView } from '@atlaskit/editor-prosemirror/view';
7
7
  import { isRowSelected } from '@atlaskit/editor-tables/utils';
8
8
 
9
- import { clearHoverSelection, hoverCell } from '../../../commands';
10
- import { getPluginState } from '../../../pm-plugins/plugin-factory';
9
+ import { clearHoverSelection } from '../../../commands';
11
10
  import { TableCssClassName as ClassName } from '../../../types';
12
11
  import { getRowHeights } from '../../../utils';
13
12
  import { tableBorderColor } from '../../consts';
@@ -19,6 +18,7 @@ export interface Props {
19
18
  hoverRows: (rows: number[], danger?: boolean) => void;
20
19
  hoveredRows?: number[];
21
20
  selectRow: (row: number, expand: boolean) => void;
21
+ updateCellHoverLocation: (rowIndex: number) => void;
22
22
  hasHeaderRow?: boolean;
23
23
  isInDanger?: boolean;
24
24
  isResizing?: boolean;
@@ -28,8 +28,13 @@ export interface Props {
28
28
 
29
29
  export default class NumberColumn extends Component<Props, any> {
30
30
  render() {
31
- const { tableRef, hasHeaderRow, isDragAndDropEnabled, tableActive } =
32
- this.props;
31
+ const {
32
+ tableRef,
33
+ hasHeaderRow,
34
+ isDragAndDropEnabled,
35
+ tableActive,
36
+ updateCellHoverLocation,
37
+ } = this.props;
33
38
  const rowHeights = getRowHeights(tableRef);
34
39
 
35
40
  return (
@@ -54,7 +59,7 @@ export default class NumberColumn extends Component<Props, any> {
54
59
  className={this.getClassNames(index, true)}
55
60
  data-index={index}
56
61
  style={this.getCellStyles(index, rowHeight)}
57
- onMouseOver={() => this.updateDragHandleLocation(index)}
62
+ onMouseOver={() => updateCellHoverLocation(index)}
58
63
  >
59
64
  {hasHeaderRow ? (index > 0 ? index : null) : index + 1}
60
65
  </div>
@@ -109,16 +114,6 @@ export default class NumberColumn extends Component<Props, any> {
109
114
  }
110
115
  };
111
116
 
112
- private updateDragHandleLocation = (rowIndex: number) => {
113
- const { editorView, tableActive } = this.props;
114
- const { state, dispatch } = editorView;
115
- const { hoveredCell } = getPluginState(state);
116
-
117
- if (tableActive && hoveredCell.rowIndex !== rowIndex) {
118
- hoverCell(rowIndex, hoveredCell.colIndex)(state, dispatch);
119
- }
120
- };
121
-
122
117
  private getCellStyles = (index: number, rowHeight: number) => {
123
118
  const { stickyTop, hasHeaderRow } = this.props;
124
119
  if (stickyTop && hasHeaderRow && index === 0) {
@@ -1,14 +1,18 @@
1
- import React from 'react';
1
+ import type { MouseEvent } from 'react';
2
+ import React, { useCallback, useMemo } from 'react';
2
3
 
3
4
  import { injectIntl } from 'react-intl-next';
4
5
  import type { WrappedComponentProps } from 'react-intl-next';
5
6
 
7
+ import type { Selection } from '@atlaskit/editor-prosemirror/state';
6
8
  import type { EditorView } from '@atlaskit/editor-prosemirror/view';
7
- import { findTable } from '@atlaskit/editor-tables/utils';
9
+ import { CellSelection } from '@atlaskit/editor-tables';
10
+ import { findTable, getSelectionRect } from '@atlaskit/editor-tables/utils';
8
11
 
12
+ import { clearHoverSelection } from '../../../commands';
9
13
  import type { CellHoverMeta } from '../../../types';
10
14
  import { TableCssClassName as ClassName } from '../../../types';
11
- import { getRowHeights } from '../../../utils';
15
+ import { getRowHeights, getSelectedRowIndexes } from '../../../utils';
12
16
  import { DragHandle } from '../../DragHandle';
13
17
 
14
18
  type DragControlsProps = {
@@ -16,61 +20,126 @@ type DragControlsProps = {
16
20
  tableRef: HTMLTableElement;
17
21
  tableActive?: boolean;
18
22
  hoveredCell?: CellHoverMeta;
19
- hoverRows?: (rows: number[], danger?: boolean) => void;
20
- selectRow?: (row: number, expand: boolean) => void;
23
+ isInDanger?: boolean;
24
+ hoverRows: (rows: number[], danger?: boolean) => void;
25
+ selectRow: (row: number, expand: boolean) => void;
26
+ updateCellHoverLocation: (rowIndex: number) => void;
27
+ };
28
+
29
+ const getSelectedRows = (selection: Selection) => {
30
+ if (selection instanceof CellSelection && selection.isRowSelection()) {
31
+ const rect = getSelectionRect(selection);
32
+ if (!rect) {
33
+ return [];
34
+ }
35
+ return getSelectedRowIndexes(rect);
36
+ }
37
+ return [];
21
38
  };
22
39
 
23
40
  const DragControlsComponent = ({
24
41
  tableRef,
25
42
  hoveredCell,
26
- hoverRows,
27
- selectRow,
28
43
  tableActive,
29
44
  editorView,
45
+ isInDanger,
46
+ hoverRows,
47
+ selectRow,
48
+ updateCellHoverLocation,
30
49
  }: DragControlsProps & WrappedComponentProps) => {
31
50
  const rowHeights = getRowHeights(tableRef);
32
- const heights = rowHeights
33
- .map((height, index) => `${height - 1}px`)
34
- .join(' ');
51
+ const heights = rowHeights.map((height) => `${height - 1}px`).join(' ');
52
+ const selectedRowIndexes = getSelectedRows(editorView.state.selection);
35
53
  const rowWidth = tableRef.offsetWidth;
36
-
37
- const onClick = (
38
- index: number,
39
- event: React.MouseEvent<Element, MouseEvent>,
40
- ) => {};
41
-
42
- const onMouseOver = () => {};
43
- const onMouseOut = () => {};
44
-
45
54
  const rowIndex = hoveredCell?.rowIndex;
46
55
 
56
+ const gridRowPosition = useMemo(() => {
57
+ // if more than one row is selected, ensure the handle spans over the selected range
58
+ if (selectedRowIndexes.includes(rowIndex!)) {
59
+ return `${selectedRowIndexes[0] + 1} / span ${selectedRowIndexes.length}`;
60
+ }
61
+ return `${rowIndex! + 1} / span 1`;
62
+ }, [rowIndex, selectedRowIndexes]);
63
+
47
64
  const getLocalId = () => {
48
65
  const tableNode = findTable(editorView.state.selection);
49
66
  return tableNode?.node?.attrs?.localId || '';
50
67
  };
51
68
 
69
+ const handleMouseOut = useCallback(() => {
70
+ if (tableActive) {
71
+ const { state, dispatch } = editorView;
72
+ clearHoverSelection()(state, dispatch);
73
+ }
74
+ }, [editorView, tableActive]);
75
+
76
+ const handleMouseMove = useCallback(
77
+ (e: MouseEvent) => {
78
+ // avoid updating if event target is drag handle
79
+ if (
80
+ !(e.nativeEvent.target as Element).classList.contains(
81
+ ClassName.ROW_CONTROLS_WITH_DRAG,
82
+ )
83
+ ) {
84
+ return;
85
+ }
86
+
87
+ const hoverHeight = e.nativeEvent.offsetY;
88
+ let totalHeight = 0;
89
+ const rowIndex = rowHeights.findIndex((row) => {
90
+ totalHeight += row;
91
+ return hoverHeight <= totalHeight;
92
+ });
93
+
94
+ updateCellHoverLocation(rowIndex);
95
+ },
96
+ [updateCellHoverLocation, rowHeights],
97
+ );
98
+
99
+ const handleMouseOver = useCallback(() => {
100
+ hoverRows([rowIndex!]);
101
+ }, [hoverRows, rowIndex]);
102
+
103
+ const handleClick = useCallback(
104
+ (e: MouseEvent) => {
105
+ selectRow(rowIndex!, e?.shiftKey);
106
+ },
107
+ [rowIndex, selectRow],
108
+ );
109
+
52
110
  return (
53
111
  <div
54
112
  className={ClassName.ROW_CONTROLS_WITH_DRAG}
55
113
  style={{
56
114
  gridTemplateRows: heights,
57
115
  }}
116
+ onMouseMove={handleMouseMove}
58
117
  >
59
- {rowIndex !== undefined && Number.isFinite(rowIndex) && (
118
+ {Number.isFinite(rowIndex) && (
60
119
  <div
61
120
  style={{
62
- gridRow: `${(rowIndex as number) + 1} / span 1`,
121
+ gridRow: gridRowPosition,
63
122
  display: 'flex',
123
+ height: '100%',
124
+ alignItems: 'center',
125
+ justifyContent: 'center',
64
126
  }}
65
127
  >
66
128
  <DragHandle
67
- onClick={(event) => onClick(rowIndex as number, event)}
68
- onMouseOver={onMouseOver}
69
- onMouseOut={onMouseOut}
70
129
  tableLocalId={getLocalId()}
71
- indexes={[rowIndex]}
130
+ indexes={[rowIndex!]}
72
131
  previewWidth={rowWidth}
73
- previewHeight={rowHeights[rowIndex]}
132
+ previewHeight={rowHeights[rowIndex!]}
133
+ appearance={
134
+ selectedRowIndexes.includes(rowIndex!)
135
+ ? isInDanger
136
+ ? 'danger'
137
+ : 'selected'
138
+ : 'default'
139
+ }
140
+ onClick={handleClick}
141
+ onMouseOver={handleMouseOver}
142
+ onMouseOut={handleMouseOut}
74
143
  />
75
144
  </div>
76
145
  )}
@@ -5,7 +5,8 @@ import { browser } from '@atlaskit/editor-common/utils';
5
5
  import type { Selection } from '@atlaskit/editor-prosemirror/state';
6
6
  import type { EditorView } from '@atlaskit/editor-prosemirror/view';
7
7
 
8
- import { hoverRows, selectRow } from '../../commands';
8
+ import { hoverCell, hoverRows, selectRow } from '../../commands';
9
+ import { getPluginState } from '../../pm-plugins/plugin-factory';
9
10
  import type { RowStickyState } from '../../pm-plugins/sticky-headers';
10
11
  import type { CellHoverMeta } from '../../types';
11
12
  import { isSelectionUpdated } from '../../utils';
@@ -145,6 +146,7 @@ export default class TableFloatingControls extends Component<Props, State> {
145
146
  isInDanger={isInDanger}
146
147
  isResizing={isResizing}
147
148
  selectRow={this.selectRow}
149
+ updateCellHoverLocation={this.updateCellHoverLocation}
148
150
  stickyTop={stickyTop}
149
151
  isDragAndDropEnabled={isDragAndDropEnabled}
150
152
  />
@@ -157,8 +159,11 @@ export default class TableFloatingControls extends Component<Props, State> {
157
159
  tableRef={tableRef}
158
160
  hoveredCell={hoveredCell}
159
161
  editorView={editorView}
162
+ tableActive={tableActive}
163
+ isInDanger={isInDanger}
160
164
  hoverRows={this.hoverRows}
161
165
  selectRow={this.selectRow}
166
+ updateCellHoverLocation={this.updateCellHoverLocation}
162
167
  />
163
168
  ) : (
164
169
  <>
@@ -204,4 +209,15 @@ export default class TableFloatingControls extends Component<Props, State> {
204
209
  const { state, dispatch } = this.props.editorView;
205
210
  hoverRows(rows, danger)(state, dispatch);
206
211
  };
212
+
213
+ // re-use across numbered columns and row controls
214
+ private updateCellHoverLocation = (rowIndex: number) => {
215
+ const { editorView, tableActive } = this.props;
216
+ const { state, dispatch } = editorView;
217
+ const { hoveredCell } = getPluginState(state);
218
+
219
+ if (tableActive && hoveredCell.rowIndex !== rowIndex) {
220
+ hoverCell(rowIndex, hoveredCell.colIndex)(state, dispatch);
221
+ }
222
+ };
207
223
  }
@@ -249,7 +249,7 @@ const tableRowControlStyles = () => {
249
249
  position: absolute;
250
250
  margin-top: ${tableMarginTop}px;
251
251
  left: -${tableToolbarSize + 1}px;
252
- z-index: ${rowControlsZIndex};
252
+ z-index: ${rowControlsZIndex + 4};
253
253
  }
254
254
  `
255
255
  : css`
@@ -705,14 +705,77 @@ export const tableStyles = (
705
705
  align-items: center;
706
706
  position: absolute;
707
707
  left: -4px;
708
+ z-index: ${akEditorUnitZIndex};
708
709
  }
709
710
 
710
711
  .${ClassName.DRAG_HANDLE_BUTTON_CONTAINER} {
711
712
  cursor: grab;
712
- width: max-content;
713
713
  padding: 0;
714
- border: none;
715
- background: none;
714
+
715
+ border-radius: 6px;
716
+ width: max-content;
717
+ height: max-content;
718
+ border: 2px solid ${token('elevation.surface', N0)};
719
+ display: flex;
720
+ justify-content: center;
721
+ align-items: center;
722
+
723
+ svg {
724
+ rect {
725
+ //
726
+ fill: ${token('color.background.accent.gray.subtlest', '#F1F2F4')};
727
+ }
728
+ g {
729
+ fill: ${token('color.icon.subtle', '#626F86')};
730
+ }
731
+ }
732
+
733
+ &:hover {
734
+ svg {
735
+ rect {
736
+ fill: ${token('color.background.accent.blue.subtle', '#579DFF')};
737
+ }
738
+ g {
739
+ fill: ${token('color.icon.inverse', '#FFF')};
740
+ }
741
+ }
742
+ }
743
+
744
+ &.selected {
745
+ svg {
746
+ rect {
747
+ fill: ${token('color.background.accent.blue.subtle', '#579DFF')};
748
+ }
749
+ g {
750
+ fill: ${token('color.icon.inverse', '#FFF')};
751
+ }
752
+ }
753
+ }
754
+
755
+ &.danger {
756
+ svg {
757
+ rect {
758
+ fill: ${token(
759
+ 'color.background.accent.red.subtler.pressed',
760
+ '#F87462',
761
+ )};
762
+ }
763
+ g {
764
+ fill: ${token('color.border.inverse', '#FFF')};
765
+ }
766
+ }
767
+ }
768
+
769
+ &.disabled {
770
+ svg {
771
+ rect {
772
+ fill: ${token('color.background.accent.gray.subtlest', '#F1F2F4')};
773
+ }
774
+ g {
775
+ fill: ${token('color.border.inverse', '#FFF')};
776
+ }
777
+ }
778
+ }
716
779
  }
717
780
 
718
781
  ${floatingColumnControls(props)}