@atlaskit/editor-plugin-table 7.2.1 → 7.2.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 (124) hide show
  1. package/CHANGELOG.md +14 -0
  2. package/dist/cjs/nodeviews/TableComponent.js +11 -7
  3. package/dist/cjs/pm-plugins/drag-and-drop/commands-with-analytics.js +3 -19
  4. package/dist/cjs/ui/TableFloatingColumnControls/ColumnControls/index.js +11 -25
  5. package/dist/cjs/ui/TableFloatingColumnControls/ColumnDropTargets/index.js +13 -3
  6. package/dist/cjs/ui/TableFloatingColumnControls/index.js +7 -3
  7. package/dist/cjs/utils/drag-menu.js +37 -23
  8. package/dist/cjs/utils/merged-cells.js +66 -1
  9. package/dist/es2019/nodeviews/TableComponent.js +9 -5
  10. package/dist/es2019/pm-plugins/drag-and-drop/commands-with-analytics.js +4 -20
  11. package/dist/es2019/ui/TableFloatingColumnControls/ColumnControls/index.js +7 -21
  12. package/dist/es2019/ui/TableFloatingColumnControls/ColumnDropTargets/index.js +10 -2
  13. package/dist/es2019/ui/TableFloatingColumnControls/index.js +7 -3
  14. package/dist/es2019/utils/drag-menu.js +38 -14
  15. package/dist/es2019/utils/merged-cells.js +73 -0
  16. package/dist/esm/nodeviews/TableComponent.js +11 -7
  17. package/dist/esm/pm-plugins/drag-and-drop/commands-with-analytics.js +4 -20
  18. package/dist/esm/ui/TableFloatingColumnControls/ColumnControls/index.js +7 -21
  19. package/dist/esm/ui/TableFloatingColumnControls/ColumnDropTargets/index.js +10 -2
  20. package/dist/esm/ui/TableFloatingColumnControls/index.js +7 -3
  21. package/dist/esm/utils/drag-menu.js +36 -22
  22. package/dist/esm/utils/merged-cells.js +65 -0
  23. package/dist/types/ui/TableFloatingColumnControls/ColumnControls/index.d.ts +2 -1
  24. package/dist/types/ui/TableFloatingColumnControls/ColumnDropTargets/index.d.ts +2 -0
  25. package/dist/types/ui/TableFloatingColumnControls/index.d.ts +1 -0
  26. package/dist/types/utils/drag-menu.d.ts +4 -1
  27. package/dist/types/utils/merged-cells.d.ts +2 -0
  28. package/dist/types-ts4.5/ui/TableFloatingColumnControls/ColumnControls/index.d.ts +2 -1
  29. package/dist/types-ts4.5/ui/TableFloatingColumnControls/ColumnDropTargets/index.d.ts +2 -0
  30. package/dist/types-ts4.5/ui/TableFloatingColumnControls/index.d.ts +1 -0
  31. package/dist/types-ts4.5/utils/drag-menu.d.ts +4 -1
  32. package/dist/types-ts4.5/utils/merged-cells.d.ts +2 -0
  33. package/package.json +9 -16
  34. package/src/nodeviews/TableComponent.tsx +1 -0
  35. package/src/pm-plugins/drag-and-drop/commands-with-analytics.ts +11 -32
  36. package/src/ui/TableFloatingColumnControls/ColumnControls/index.tsx +6 -27
  37. package/src/ui/TableFloatingColumnControls/ColumnDropTargets/index.tsx +12 -1
  38. package/src/ui/TableFloatingColumnControls/index.tsx +5 -0
  39. package/src/utils/drag-menu.ts +94 -20
  40. package/src/utils/merged-cells.ts +78 -0
  41. package/tsconfig.dev.json +0 -69
  42. package/tsconfig.json +2 -871
  43. package/examples/99-testing.tsx +0 -140
  44. package/examples/config.jsonc +0 -14
  45. package/src/__tests__/unit/analytics.ts +0 -888
  46. package/src/__tests__/unit/collab.ts +0 -93
  47. package/src/__tests__/unit/commands/go-to-next-cell.ts +0 -173
  48. package/src/__tests__/unit/commands/insert.ts +0 -137
  49. package/src/__tests__/unit/commands/misc.ts +0 -185
  50. package/src/__tests__/unit/commands/sort.ts +0 -128
  51. package/src/__tests__/unit/commands.ts +0 -745
  52. package/src/__tests__/unit/copy-button.ts +0 -22
  53. package/src/__tests__/unit/copy-paste.ts +0 -677
  54. package/src/__tests__/unit/event-handlers/index.ts +0 -125
  55. package/src/__tests__/unit/event-handlers.ts +0 -296
  56. package/src/__tests__/unit/fix-tables.ts +0 -164
  57. package/src/__tests__/unit/get-toolbar-config.ts +0 -127
  58. package/src/__tests__/unit/handlers.ts +0 -98
  59. package/src/__tests__/unit/hover-selection.ts +0 -230
  60. package/src/__tests__/unit/index-with-fake-timers.ts +0 -111
  61. package/src/__tests__/unit/index.ts +0 -912
  62. package/src/__tests__/unit/layout.ts +0 -146
  63. package/src/__tests__/unit/nodeviews/OverflowShadowsObserver.ts +0 -162
  64. package/src/__tests__/unit/nodeviews/TableComponent.tsx +0 -280
  65. package/src/__tests__/unit/nodeviews/TableContainer.tsx +0 -525
  66. package/src/__tests__/unit/nodeviews/cell.ts +0 -132
  67. package/src/__tests__/unit/nodeviews/table.ts +0 -129
  68. package/src/__tests__/unit/pm-plugins/analytics.ts +0 -327
  69. package/src/__tests__/unit/pm-plugins/decorations/column-controls.ts +0 -94
  70. package/src/__tests__/unit/pm-plugins/decorations/column-resizing.ts +0 -176
  71. package/src/__tests__/unit/pm-plugins/decorations/plugin.ts +0 -211
  72. package/src/__tests__/unit/pm-plugins/main.ts +0 -214
  73. package/src/__tests__/unit/pm-plugins/safari-delete-composition-text-issue-workaround.ts +0 -101
  74. package/src/__tests__/unit/pm-plugins/sticky-headers/tableRow.tsx +0 -562
  75. package/src/__tests__/unit/pm-plugins/table-local-id.ts +0 -507
  76. package/src/__tests__/unit/pm-plugins/table-resizing/colgroup.ts +0 -269
  77. package/src/__tests__/unit/pm-plugins/table-resizing/event-handlers.ts +0 -192
  78. package/src/__tests__/unit/pm-plugins/table-resizing/utils/resize-state.ts +0 -33
  79. package/src/__tests__/unit/pm-plugins/table-width.ts +0 -292
  80. package/src/__tests__/unit/sort-column.ts +0 -399
  81. package/src/__tests__/unit/toolbar.ts +0 -512
  82. package/src/__tests__/unit/transforms/delete-columns.ts +0 -597
  83. package/src/__tests__/unit/transforms/delete-rows.ts +0 -620
  84. package/src/__tests__/unit/transforms/merging.ts +0 -392
  85. package/src/__tests__/unit/ui/ContextualMenu.tsx +0 -71
  86. package/src/__tests__/unit/ui/CornerControls.tsx +0 -99
  87. package/src/__tests__/unit/ui/DeleteButton.tsx +0 -38
  88. package/src/__tests__/unit/ui/FixedButton.tsx +0 -217
  89. package/src/__tests__/unit/ui/FloatingContextualButton.tsx +0 -123
  90. package/src/__tests__/unit/ui/FloatingContextualMenu.tsx +0 -68
  91. package/src/__tests__/unit/ui/FloatingDeleteButton.tsx +0 -178
  92. package/src/__tests__/unit/ui/FloatingDragMenu.tsx +0 -511
  93. package/src/__tests__/unit/ui/FloatingInsertButton.tsx +0 -322
  94. package/src/__tests__/unit/ui/NumberColumn.tsx +0 -146
  95. package/src/__tests__/unit/ui/RowControls.tsx +0 -294
  96. package/src/__tests__/unit/ui/RowDragControls.tsx +0 -129
  97. package/src/__tests__/unit/ui/TableFloatingColumnControls.tsx +0 -189
  98. package/src/__tests__/unit/ui/TableFloatingControls.tsx +0 -118
  99. package/src/__tests__/unit/undo-redo.ts +0 -220
  100. package/src/__tests__/unit/utils/analytics.ts +0 -98
  101. package/src/__tests__/unit/utils/collapse.ts +0 -57
  102. package/src/__tests__/unit/utils/column-controls.ts +0 -205
  103. package/src/__tests__/unit/utils/dom.ts +0 -180
  104. package/src/__tests__/unit/utils/merged-cells.ts +0 -156
  105. package/src/__tests__/unit/utils/nodes.ts +0 -79
  106. package/src/__tests__/unit/utils/row-controls.ts +0 -195
  107. package/src/__tests__/unit/utils/table.ts +0 -96
  108. package/src/__tests__/unit/utils.ts +0 -670
  109. package/src/__tests__/visual-regression/__fixtures__/sticky-header-with-horizontal-scroll.json +0 -5228
  110. package/src/__tests__/visual-regression/__fixtures__/table-with-100-numbered-list-items.json +0 -20272
  111. package/src/__tests__/visual-regression/__image_snapshots__/cell-options-menu-ts-table-cell-options-menu-delete-column-menu-item-should-remove-the-table-column-on-click-1-snap.png +0 -3
  112. package/src/__tests__/visual-regression/__image_snapshots__/cell-options-menu-ts-table-cell-options-menu-delete-column-menu-item-visual-hints-should-be-added-to-the-table-column-on-hover-1-snap.png +0 -3
  113. package/src/__tests__/visual-regression/__image_snapshots__/cell-options-menu-ts-table-cell-options-menu-delete-row-menu-item-should-remove-the-table-row-on-click-1-snap.png +0 -3
  114. package/src/__tests__/visual-regression/__image_snapshots__/cell-options-menu-ts-table-cell-options-menu-delete-row-menu-item-visual-hints-should-be-added-to-the-table-row-on-hover-1-snap.png +0 -3
  115. package/src/__tests__/visual-regression/__image_snapshots__/copy-button-ts-floating-toolbar-copy-button-table-target-node-displays-blue-border-when-copy-button-is-hovered-1-snap.png +0 -3
  116. package/src/__tests__/visual-regression/__image_snapshots__/index-ts-snapshot-test-table-numbered-list-should-not-overflow-table-cell-when-there-are-more-than-100-ordered-list-items-1-snap.png +0 -3
  117. package/src/__tests__/visual-regression/__image_snapshots__/index-ts-snapshot-test-table-numbered-list-should-not-overflow-table-cell-when-there-are-more-than-100-ordered-list-items-2-snap.png +0 -3
  118. package/src/__tests__/visual-regression/__image_snapshots__/index-ts-snapshot-test-table-numbered-list-should-not-overflow-table-cell-when-there-are-more-than-100-ordered-list-items-3-snap.png +0 -3
  119. package/src/__tests__/visual-regression/__image_snapshots__/sticky-header-ts-snapshot-test-table-sticky-header-should-align-with-table-cell-when-active-1-snap.png +0 -3
  120. package/src/__tests__/visual-regression/__image_snapshots__/sticky-header-ts-snapshot-test-table-sticky-header-should-align-with-table-cell-when-active-2-snap.png +0 -3
  121. package/src/__tests__/visual-regression/cell-options-menu.ts +0 -101
  122. package/src/__tests__/visual-regression/copy-button.ts +0 -181
  123. package/src/__tests__/visual-regression/index.ts +0 -62
  124. package/src/__tests__/visual-regression/sticky-header.ts +0 -61
@@ -1,9 +1,12 @@
1
1
  /// <reference types="react" />
2
2
  import type { EditorAnalyticsAPI } from '@atlaskit/editor-common/analytics';
3
3
  import type { Command, DropdownOptionT, GetEditorContainerWidth, IconProps } from '@atlaskit/editor-common/types';
4
+ import type { Selection } from '@atlaskit/editor-prosemirror/state';
4
5
  import type { EditorView } from '@atlaskit/editor-prosemirror/view';
5
6
  import type { Rect, TableMap } from '@atlaskit/editor-tables/table-map';
6
- import type { TableDirection } from '../types';
7
+ import type { DraggableData, DraggableType, TableDirection } from '../types';
8
+ export declare const getTargetIndex: (selectedIndexes: number[], direction: DraggableData['direction']) => number;
9
+ export declare const canMove: (sourceType: DraggableType, direction: DraggableData['direction'], totalItemsOfSourceTypeCount: number, selection: Selection, selectionRect?: Rect) => boolean;
7
10
  export type DragMenuOptionIdType = 'add_row_above' | 'add_row_below' | 'add_column_left' | 'add_column_right' | 'distribute_columns' | 'clear_cells' | 'delete_row' | 'delete_column' | 'move_column_left' | 'move_column_right' | 'move_row_up' | 'move_row_down' | 'sort_column_asc' | 'sort_column_desc';
8
11
  export interface DragMenuConfig extends DropdownOptionT<Command> {
9
12
  id: DragMenuOptionIdType;
@@ -3,4 +3,6 @@ type MergeType = 'row' | 'column';
3
3
  export declare const hasMergedCellsInColumn: (columnIndexes: number | number[]) => (selection: Selection) => boolean;
4
4
  export declare const hasMergedCellsInRow: (rowIndexes: number | number[]) => (selection: Selection) => boolean;
5
5
  export declare const hasMergedCellsInBetween: (indexes: number[], type: MergeType) => (selection: Selection) => boolean;
6
+ export declare const hasMergedCellsWithColumnNextToColumnIndex: (colIndex: number, selection: Selection) => boolean;
7
+ export declare const hasMergedCellsWithRowNextToRowIndex: (rowIndex: number, selection: Selection) => boolean;
6
8
  export {};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@atlaskit/editor-plugin-table",
3
- "version": "7.2.1",
3
+ "version": "7.2.3",
4
4
  "description": "Table plugin for the @atlaskit/editor",
5
5
  "publishConfig": {
6
6
  "registry": "https://registry.npmjs.org/"
@@ -29,15 +29,15 @@
29
29
  },
30
30
  "dependencies": {
31
31
  "@atlaskit/adf-schema": "^35.5.1",
32
- "@atlaskit/custom-steps": "^0.0.12",
33
- "@atlaskit/editor-common": "^77.2.0",
32
+ "@atlaskit/custom-steps": "^0.0.13",
33
+ "@atlaskit/editor-common": "^77.3.0",
34
34
  "@atlaskit/editor-palette": "1.5.2",
35
35
  "@atlaskit/editor-plugin-analytics": "^0.4.0",
36
36
  "@atlaskit/editor-plugin-content-insertion": "^0.1.0",
37
37
  "@atlaskit/editor-plugin-guideline": "^0.5.0",
38
38
  "@atlaskit/editor-plugin-selection": "^0.2.0",
39
39
  "@atlaskit/editor-plugin-width": "^0.2.0",
40
- "@atlaskit/editor-prosemirror": "1.1.0",
40
+ "@atlaskit/editor-prosemirror": "3.0.0",
41
41
  "@atlaskit/editor-shared-styles": "^2.9.0",
42
42
  "@atlaskit/editor-tables": "^2.5.0",
43
43
  "@atlaskit/icon": "^22.0.0",
@@ -64,19 +64,7 @@
64
64
  "react-intl-next": "npm:react-intl@^5.18.1"
65
65
  },
66
66
  "devDependencies": {
67
- "@atlaskit/analytics-next": "^9.2.0",
68
- "@atlaskit/editor-plugin-decorations": "^0.2.0",
69
- "@atlaskit/editor-plugin-feature-flags": "^1.0.0",
70
- "@atlaskit/editor-plugin-grid": "^0.3.0",
71
- "@atlaskit/editor-plugin-hyperlink": "^0.8.0",
72
- "@atlaskit/editor-test-helpers": "^18.15.0",
73
- "@atlaskit/visual-regression": "*",
74
67
  "@atlassian/atlassian-frontend-prettier-config-1.0.1": "npm:@atlassian/atlassian-frontend-prettier-config@1.0.1",
75
- "@atlassian/feature-flags-test-utils": "^0.2.0",
76
- "@testing-library/dom": "^8.17.1",
77
- "@testing-library/react": "^12.1.5",
78
- "@testing-library/react-hooks": "^8.0.1",
79
- "raf-stub": "^2.0.1",
80
68
  "typescript": "~4.9.5"
81
69
  },
82
70
  "af:exports": {
@@ -107,6 +95,11 @@
107
95
  ]
108
96
  }
109
97
  },
98
+ "stricter": {
99
+ "no-unused-dependencies": {
100
+ "checkDevDependencies": true
101
+ }
102
+ },
110
103
  "platform-feature-flags": {
111
104
  "platform.editor.custom-table-width": {
112
105
  "type": "boolean"
@@ -500,6 +500,7 @@ class TableComponent extends React.Component<ComponentProps, TableState> {
500
500
  getEditorFeatureFlags={getEditorFeatureFlags}
501
501
  tableContainerWidth={tableContainerWidth}
502
502
  isNumberColumnEnabled={node.attrs.isNumberColumnEnabled}
503
+ getScrollOffset={() => this.wrapper?.scrollLeft || 0}
503
504
  />
504
505
  ) : null;
505
506
 
@@ -22,10 +22,9 @@ import {
22
22
  getSelectedColumnIndexes,
23
23
  getSelectedRowIndexes,
24
24
  getSelectedTableInfo,
25
- hasMergedCellsInColumn,
26
- hasMergedCellsInRow,
27
25
  } from '../../utils';
28
26
  import { withEditorAnalyticsAPI } from '../../utils/analytics';
27
+ import { canMove, getTargetIndex } from '../../utils/drag-menu';
29
28
 
30
29
  import { clearDropTarget, moveSource } from './commands';
31
30
 
@@ -132,44 +131,24 @@ export const moveSourceWithAnalyticsViaShortcut =
132
131
  const selectedIndexes = isRow
133
132
  ? getSelectedRowIndexes(selectionRect)
134
133
  : getSelectedColumnIndexes(selectionRect);
135
-
136
134
  if (selectedIndexes.length === 0) {
137
135
  return false;
138
136
  }
139
137
 
140
- // const sourceIndex = selectedIndexes[0];
141
- // we can move only by one row/column
142
- // 'direction' can only be 1 (for right or down) or -1 (for left or up)
143
- const targetIndex =
144
- Math[direction < 0 ? 'min' : 'max'](...selectedIndexes) + direction;
145
-
146
- // We can move only if targetIndex is a positive number and is not higher than the total number of rows/columns.
147
138
  const { totalRowCount, totalColumnCount } = getSelectedTableInfo(selection);
148
- const isValidTargetIndex =
149
- targetIndex < 0
150
- ? false
151
- : isRow
152
- ? targetIndex <= totalRowCount - 1
153
- : targetIndex <= totalColumnCount - 1;
154
-
155
- if (!isValidTargetIndex) {
156
- return false;
157
- }
158
-
159
- // We can move only if there are no merged cells in the source or target row/column
160
- const hasMergedCellsInSource = isRow
161
- ? hasMergedCellsInRow(selectedIndexes)(selection)
162
- : hasMergedCellsInColumn(selectedIndexes)(selection);
163
- if (hasMergedCellsInSource) {
139
+ if (
140
+ !canMove(
141
+ sourceType,
142
+ direction,
143
+ isRow ? totalRowCount : totalColumnCount,
144
+ selection,
145
+ selectionRect,
146
+ )
147
+ ) {
164
148
  return false;
165
149
  }
166
150
 
167
- const hasMergedCellsInTarget = isRow
168
- ? hasMergedCellsInRow(targetIndex)(selection)
169
- : hasMergedCellsInColumn(targetIndex)(selection);
170
- if (hasMergedCellsInTarget) {
171
- return false;
172
- }
151
+ const targetIndex = getTargetIndex(selectedIndexes, direction);
173
152
 
174
153
  return moveSourceWithAnalytics(editorAnalyticsAPI)(
175
154
  INPUT_METHOD.SHORTCUT,
@@ -1,9 +1,8 @@
1
1
  /* eslint-disable @atlaskit/design-system/prefer-primitives */
2
2
  import type { MouseEvent } from 'react';
3
- import React, { useCallback, useEffect, useMemo, useRef } from 'react';
3
+ import React, { useCallback, useMemo, useRef } from 'react';
4
4
 
5
5
  import { tableCellMinWidth } from '@atlaskit/editor-common/styles';
6
- import { closestElement } from '@atlaskit/editor-common/utils';
7
6
  import type { Selection } from '@atlaskit/editor-prosemirror/state';
8
7
  import type { EditorView } from '@atlaskit/editor-prosemirror/view';
9
8
  import { akEditorTableNumberColumnWidth } from '@atlaskit/editor-shared-styles';
@@ -39,6 +38,7 @@ export interface ColumnControlsProps {
39
38
  tableContainerWidth?: number;
40
39
  isNumberColumnEnabled?: boolean;
41
40
  isDragging?: boolean;
41
+ getScrollOffset?: () => number;
42
42
  }
43
43
 
44
44
  const getSelectedColumns = (selection: Selection) => {
@@ -68,6 +68,7 @@ export const ColumnControls = ({
68
68
  tableContainerWidth,
69
69
  isNumberColumnEnabled,
70
70
  isDragging,
71
+ getScrollOffset,
71
72
  }: ColumnControlsProps) => {
72
73
  const columnControlsRef = useRef<HTMLDivElement>(null);
73
74
  const widths =
@@ -172,32 +173,10 @@ export const ColumnControls = ({
172
173
  const colIndexes = useMemo(() => {
173
174
  return [colIndex!];
174
175
  }, [colIndex]);
175
- const tableWrapper = closestElement(
176
- tableRef,
177
- `.${ClassName.TABLE_NODE_WRAPPER}`,
178
- );
179
- const handleScroll = useCallback(
180
- (event?: Event) => {
181
- if (stickyTop) {
182
- if (columnControlsRef && columnControlsRef.current) {
183
- columnControlsRef.current.scrollLeft = tableWrapper?.scrollLeft ?? 0;
184
- }
185
- }
186
- },
187
- [stickyTop, tableWrapper],
188
- );
189
176
 
190
- useEffect(() => {
191
- handleScroll();
192
- }, [handleScroll]);
193
-
194
- useEffect(() => {
195
- tableWrapper?.addEventListener('scroll', handleScroll);
196
-
197
- return () => {
198
- tableWrapper?.removeEventListener('scroll', handleScroll);
199
- };
200
- }, [tableWrapper, handleScroll]);
177
+ if (stickyTop && columnControlsRef.current) {
178
+ columnControlsRef.current.scrollLeft = getScrollOffset?.() ?? 0;
179
+ }
201
180
 
202
181
  const generateHandleByType = (type: HandleTypes): JSX.Element | null => {
203
182
  if (!hoveredCell || !colWidths?.length) {
@@ -1,4 +1,4 @@
1
- import React from 'react';
1
+ import React, { useRef } from 'react';
2
2
 
3
3
  import { TableCssClassName as ClassName } from '../../../types';
4
4
 
@@ -9,6 +9,8 @@ export interface Props {
9
9
  tableHeight?: number;
10
10
  localId?: string;
11
11
  colWidths?: (number | undefined)[];
12
+ isHeaderSticky?: boolean;
13
+ getScrollOffset?: () => number;
12
14
  }
13
15
 
14
16
  export const ColumnDropTargets: React.FC<Props> = ({
@@ -16,13 +18,22 @@ export const ColumnDropTargets: React.FC<Props> = ({
16
18
  tableHeight,
17
19
  localId,
18
20
  colWidths,
21
+ isHeaderSticky,
22
+ getScrollOffset,
19
23
  }) => {
24
+ const dropTargetRef = useRef<HTMLDivElement>(null);
25
+
20
26
  if (!tableRef) {
21
27
  return null;
22
28
  }
23
29
 
30
+ if (isHeaderSticky && dropTargetRef.current) {
31
+ dropTargetRef.current.style.marginLeft = `-${getScrollOffset?.() ?? 0}px`;
32
+ }
33
+
24
34
  return (
25
35
  <div
36
+ ref={dropTargetRef}
26
37
  className={ClassName.DRAG_COLUMN_DROP_TARGET_CONTROLS}
27
38
  contentEditable={false}
28
39
  >
@@ -37,6 +37,7 @@ export interface Props {
37
37
  isTableHovered?: boolean;
38
38
  tableContainerWidth?: number;
39
39
  isNumberColumnEnabled?: boolean;
40
+ getScrollOffset?: () => number;
40
41
  }
41
42
 
42
43
  export const TableFloatingColumnControls: React.FC<Props> = ({
@@ -53,6 +54,7 @@ export const TableFloatingColumnControls: React.FC<Props> = ({
53
54
  isTableHovered,
54
55
  tableContainerWidth,
55
56
  isNumberColumnEnabled,
57
+ getScrollOffset,
56
58
  }) => {
57
59
  const [tableRect, setTableRect] = useState<{ width: number; height: number }>(
58
60
  { width: 0, height: 0 },
@@ -158,13 +160,16 @@ export const TableFloatingColumnControls: React.FC<Props> = ({
158
160
  tableContainerWidth={tableContainerWidth}
159
161
  isNumberColumnEnabled={isNumberColumnEnabled}
160
162
  isDragging={isDragging}
163
+ getScrollOffset={getScrollOffset}
161
164
  />
162
165
  {isDragging && (
163
166
  <ColumnDropTargets
164
167
  tableRef={tableRef}
168
+ isHeaderSticky={stickyHeader?.sticky && hasHeaderRow}
165
169
  tableHeight={tableRect.height}
166
170
  localId={currentNodeLocalId}
167
171
  colWidths={colWidths}
172
+ getScrollOffset={getScrollOffset}
168
173
  />
169
174
  )}
170
175
  </div>
@@ -22,7 +22,10 @@ import type {
22
22
  GetEditorContainerWidth,
23
23
  IconProps,
24
24
  } from '@atlaskit/editor-common/types';
25
- import type { EditorState } from '@atlaskit/editor-prosemirror/state';
25
+ import type {
26
+ EditorState,
27
+ Selection,
28
+ } from '@atlaskit/editor-prosemirror/state';
26
29
  import type { EditorView } from '@atlaskit/editor-prosemirror/view';
27
30
  import type { Rect, TableMap } from '@atlaskit/editor-tables/table-map';
28
31
  import ArrowDownIcon from '@atlaskit/icon/glyph/arrow-down';
@@ -47,7 +50,7 @@ import { distributeColumnsWidths } from '../pm-plugins/table-resizing/commands';
47
50
  import { getNewResizeStateFromSelectedColumns } from '../pm-plugins/table-resizing/utils/resize-state';
48
51
  import { getClosestSelectionRect } from '../toolbar';
49
52
  import { deleteRows } from '../transforms';
50
- import type { TableDirection } from '../types';
53
+ import type { DraggableData, DraggableType, TableDirection } from '../types';
51
54
  import {
52
55
  AddColLeftIcon,
53
56
  AddColRightIcon,
@@ -55,12 +58,61 @@ import {
55
58
  AddRowBelowIcon,
56
59
  } from '../ui/icons';
57
60
 
61
+ import {
62
+ hasMergedCellsInColumn,
63
+ hasMergedCellsInRow,
64
+ hasMergedCellsWithColumnNextToColumnIndex,
65
+ hasMergedCellsWithRowNextToRowIndex,
66
+ } from './merged-cells';
58
67
  import { getSelectedColumnIndexes, getSelectedRowIndexes } from './selection';
59
68
 
60
- const canDecrease = (index?: number, min: number = 0) =>
61
- index !== undefined && index > min;
62
- const canIncrease = (index?: number, max: number = 0) =>
63
- index !== undefined && index < max;
69
+ export const getTargetIndex = (
70
+ selectedIndexes: number[],
71
+ direction: DraggableData['direction'],
72
+ ) => Math[direction < 0 ? 'min' : 'max'](...selectedIndexes) + direction;
73
+
74
+ export const canMove = (
75
+ sourceType: DraggableType,
76
+ direction: DraggableData['direction'],
77
+ totalItemsOfSourceTypeCount: number,
78
+ selection: Selection,
79
+ selectionRect?: Rect,
80
+ ) => {
81
+ if (!selectionRect) {
82
+ return false;
83
+ }
84
+
85
+ const isRow = sourceType === 'table-row';
86
+ const selectedIndexes = isRow
87
+ ? getSelectedRowIndexes(selectionRect)
88
+ : getSelectedColumnIndexes(selectionRect);
89
+ const targetIndex = getTargetIndex(selectedIndexes, direction);
90
+
91
+ const isValidTargetIndex =
92
+ targetIndex >= 0 && targetIndex < totalItemsOfSourceTypeCount;
93
+ if (!isValidTargetIndex) {
94
+ return false;
95
+ }
96
+
97
+ // We can't move column when target has merges with other columns
98
+ // We can't move row when target has merges with other rows
99
+ const hasMergedCellsInTarget = isRow
100
+ ? hasMergedCellsWithRowNextToRowIndex(targetIndex, selection)
101
+ : hasMergedCellsWithColumnNextToColumnIndex(targetIndex, selection);
102
+ if (hasMergedCellsInTarget) {
103
+ return false;
104
+ }
105
+
106
+ // Currently we can't move in any direction if there are merged cells in the source
107
+ const hasMergedCellsInSource = isRow
108
+ ? hasMergedCellsInRow(selectedIndexes)(selection)
109
+ : hasMergedCellsInColumn(selectedIndexes)(selection);
110
+ if (hasMergedCellsInSource) {
111
+ return false;
112
+ }
113
+
114
+ return true;
115
+ };
64
116
 
65
117
  const isDistributeColumnsEnabled = (state: EditorState) => {
66
118
  const rect = getClosestSelectionRect(state);
@@ -135,6 +187,8 @@ export const getDragMenuConfig = (
135
187
  keymap: addColumnAfter,
136
188
  },
137
189
  ];
190
+
191
+ const { selection } = editorView.state;
138
192
  const moveOptions =
139
193
  direction === 'row'
140
194
  ? [
@@ -142,8 +196,15 @@ export const getDragMenuConfig = (
142
196
  label: 'up',
143
197
  icon: ArrowUpIcon,
144
198
  keymap: moveRowUp,
145
- canMove: (selectionRect?: Rect) =>
146
- canDrag && canDecrease(selectionRect?.top),
199
+ canMove:
200
+ canDrag &&
201
+ canMove(
202
+ 'table-row',
203
+ -1,
204
+ tableMap?.height ?? 0,
205
+ selection,
206
+ selectionRect,
207
+ ),
147
208
  getOriginIndexes: getSelectedRowIndexes,
148
209
  getTargetIndex: (selectionRect: Rect) => selectionRect.top - 1,
149
210
  },
@@ -151,11 +212,14 @@ export const getDragMenuConfig = (
151
212
  label: 'down',
152
213
  icon: ArrowDownIcon,
153
214
  keymap: moveRowDown,
154
- canMove: (selectionRect?: Rect) =>
215
+ canMove:
155
216
  canDrag &&
156
- canIncrease(
157
- (selectionRect?.bottom ?? 0) - 1,
158
- (tableMap?.height ?? 0) - 1,
217
+ canMove(
218
+ 'table-row',
219
+ 1,
220
+ tableMap?.height ?? 0,
221
+ selection,
222
+ selectionRect,
159
223
  ),
160
224
  getOriginIndexes: getSelectedRowIndexes,
161
225
  getTargetIndex: (selectionRect: Rect) => selectionRect.bottom,
@@ -166,8 +230,15 @@ export const getDragMenuConfig = (
166
230
  label: 'left',
167
231
  icon: ArrowLeftIcon,
168
232
  keymap: moveColumnLeft,
169
- canMove: (selectionRect?: Rect) =>
170
- canDrag && canDecrease(selectionRect?.left),
233
+ canMove:
234
+ canDrag &&
235
+ canMove(
236
+ 'table-column',
237
+ -1,
238
+ tableMap?.width ?? 0,
239
+ selection,
240
+ selectionRect,
241
+ ),
171
242
  getOriginIndexes: getSelectedColumnIndexes,
172
243
  getTargetIndex: (selectionRect: Rect) => selectionRect.left - 1,
173
244
  },
@@ -175,11 +246,14 @@ export const getDragMenuConfig = (
175
246
  label: 'right',
176
247
  icon: ArrowRightIcon,
177
248
  keymap: moveColumnRight,
178
- canMove: (selectionRect?: Rect) =>
249
+ canMove:
179
250
  canDrag &&
180
- canIncrease(
181
- (selectionRect?.right ?? 0) - 1,
182
- (tableMap?.width ?? 0) - 1,
251
+ canMove(
252
+ 'table-column',
253
+ 1,
254
+ tableMap?.width ?? 0,
255
+ selection,
256
+ selectionRect,
183
257
  ),
184
258
  getOriginIndexes: getSelectedColumnIndexes,
185
259
  getTargetIndex: (selectionRect: Rect) => selectionRect.right,
@@ -275,10 +349,10 @@ export const getDragMenuConfig = (
275
349
  ({ label, canMove, icon, keymap, getOriginIndexes, getTargetIndex }) => ({
276
350
  id: `move_${direction}_${label}`,
277
351
  title: `Move ${direction} ${label}`,
278
- disabled: !canMove(selectionRect),
352
+ disabled: !canMove,
279
353
  icon,
280
354
  onClick: (state: EditorState, dispatch?: CommandDispatch) => {
281
- if (canMove(selectionRect)) {
355
+ if (canMove) {
282
356
  requestAnimationFrame(() => {
283
357
  moveSourceWithAnalytics(editorAnalyticsAPI)(
284
358
  INPUT_METHOD.TABLE_CONTEXT_MENU,
@@ -147,3 +147,81 @@ export const hasMergedCellsInBetween =
147
147
  mergedCellsInRectArr[1].includes(cell),
148
148
  );
149
149
  };
150
+
151
+ // Checks if any cell in the column with colIndex is merged with a cell in a column to the left or to the right of it.
152
+ // colIndex is a logical index of the column. It starts at 0 and goes up to tableMap.width - 1.
153
+ export const hasMergedCellsWithColumnNextToColumnIndex = (
154
+ colIndex: number,
155
+ selection: Selection,
156
+ ) => {
157
+ const table = findTable(selection);
158
+ if (!table) {
159
+ return false;
160
+ }
161
+
162
+ const tableMap = TableMap.get(table.node);
163
+ const { width } = tableMap;
164
+ if (width <= 1) {
165
+ return false;
166
+ }
167
+
168
+ if (colIndex < 0 || colIndex > width - 1) {
169
+ return false;
170
+ }
171
+
172
+ const { map } = tableMap;
173
+ // j is an index in the tableMap.map array. tableMap.map is a flat array.
174
+ // Each item of this array contains a number.
175
+ // The number represents the position of the corresponding cell in the tableMap. It exists for each cell.
176
+ // If there are merged cells, their positions will be represented by the same number.
177
+ const isFirstColumn = colIndex === 0;
178
+ const isLastColumn = colIndex === width - 1;
179
+ for (let j = colIndex; j < map.length; j += width) {
180
+ if (
181
+ (!isFirstColumn && map[j] === map[j - 1]) || // compare with a cell in the column on the left
182
+ (!isLastColumn && map[j] === map[j + 1]) // compare with a cell in the column on the right
183
+ ) {
184
+ return true;
185
+ }
186
+ }
187
+
188
+ return false;
189
+ };
190
+
191
+ // Checks if any cell in the row with rowIndex is merged with a cell in a row above or below it.
192
+ export const hasMergedCellsWithRowNextToRowIndex = (
193
+ rowIndex: number, // logical row index in the table. It starts at 0 and goes up to tableMap.height - 1.
194
+ selection: Selection,
195
+ ) => {
196
+ const table = findTable(selection);
197
+ if (!table) {
198
+ return false;
199
+ }
200
+
201
+ const tableMap = TableMap.get(table.node);
202
+ const { height } = tableMap;
203
+ if (height <= 1) {
204
+ return false;
205
+ }
206
+
207
+ if (rowIndex < 0 || rowIndex > height - 1) {
208
+ return false;
209
+ }
210
+
211
+ const { map, width } = tableMap; // map is a flat array representing position of each cell in the table.
212
+ const indexOfFirstCellInTheRow = rowIndex * width;
213
+ const indexOfLastCellInTheRow = indexOfFirstCellInTheRow + width - 1;
214
+ const isFirstRow = rowIndex === 0;
215
+ const isLastRow = rowIndex === height - 1;
216
+ // j is an index of a cell in a row
217
+ for (let j = indexOfFirstCellInTheRow; j <= indexOfLastCellInTheRow; j++) {
218
+ if (
219
+ (!isFirstRow && map[j] === map[j - width]) || // compare with a cell in the row above
220
+ (!isLastRow && map[j] === map[j + width]) // compare with a cell in the row below
221
+ ) {
222
+ return true;
223
+ }
224
+ }
225
+
226
+ return false;
227
+ };
package/tsconfig.dev.json CHANGED
@@ -36,83 +36,14 @@
36
36
  {
37
37
  "path": "tsconfig.app.json"
38
38
  },
39
- {
40
- "path": "../../analytics/analytics-next/tsconfig.app.json"
41
- },
42
- {
43
- "path": "../../design-system/button/tsconfig.app.json"
44
- },
45
- {
46
- "path": "../custom-steps/tsconfig.app.json"
47
- },
48
39
  {
49
40
  "path": "../../../build/website/docs/tsconfig.app.json"
50
41
  },
51
- {
52
- "path": "../editor-common/tsconfig.app.json"
53
- },
54
42
  {
55
43
  "path": "../editor-core/tsconfig.app.json"
56
44
  },
57
- {
58
- "path": "../editor-plugin-analytics/tsconfig.app.json"
59
- },
60
- {
61
- "path": "../editor-plugin-content-insertion/tsconfig.app.json"
62
- },
63
- {
64
- "path": "../editor-plugin-decorations/tsconfig.app.json"
65
- },
66
- {
67
- "path": "../editor-plugin-feature-flags/tsconfig.app.json"
68
- },
69
- {
70
- "path": "../editor-plugin-grid/tsconfig.app.json"
71
- },
72
- {
73
- "path": "../editor-plugin-guideline/tsconfig.app.json"
74
- },
75
- {
76
- "path": "../editor-plugin-selection/tsconfig.app.json"
77
- },
78
- {
79
- "path": "../editor-plugin-width/tsconfig.app.json"
80
- },
81
- {
82
- "path": "../editor-shared-styles/tsconfig.app.json"
83
- },
84
- {
85
- "path": "../editor-tables/tsconfig.app.json"
86
- },
87
- {
88
- "path": "../editor-test-helpers/tsconfig.app.json"
89
- },
90
- {
91
- "path": "../../linking-platform/link-provider/tsconfig.app.json"
92
- },
93
- {
94
- "path": "../../design-system/logo/tsconfig.app.json"
95
- },
96
- {
97
- "path": "../../media/media-integration-test-helpers/tsconfig.app.json"
98
- },
99
- {
100
- "path": "../../platform/feature-flags/tsconfig.app.json"
101
- },
102
- {
103
- "path": "../synchrony-test-helpers/tsconfig.app.json"
104
- },
105
- {
106
- "path": "../../design-system/theme/tsconfig.app.json"
107
- },
108
45
  {
109
46
  "path": "../../design-system/tokens/tsconfig.app.json"
110
- },
111
- {
112
- "path": "../../../build/test-tooling/visual-regression/tsconfig.app.json"
113
- },
114
- {
115
- "path": "../../platform/feature-flags-test-utils/tsconfig.app.json"
116
47
  }
117
48
  ]
118
49
  }