@atlaskit/editor-plugin-table 0.2.2 → 0.2.4

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 (83) hide show
  1. package/CHANGELOG.md +26 -0
  2. package/dist/cjs/plugins/table/commands/hover.js +2 -1
  3. package/dist/cjs/plugins/table/event-handlers.js +9 -13
  4. package/dist/cjs/plugins/table/index.js +3 -1
  5. package/dist/cjs/plugins/table/nodeviews/TableComponent.js +15 -5
  6. package/dist/cjs/plugins/table/pm-plugins/default-table-selection.js +1 -2
  7. package/dist/cjs/plugins/table/pm-plugins/main.js +2 -2
  8. package/dist/cjs/plugins/table/pm-plugins/sticky-headers/nodeviews/tableRow.js +42 -8
  9. package/dist/cjs/plugins/table/pm-plugins/table-resizing/utils/resize-logic.js +1 -1
  10. package/dist/cjs/plugins/table/toolbar.js +42 -10
  11. package/dist/cjs/plugins/table/ui/FloatingContextualButton/index.js +7 -1
  12. package/dist/cjs/plugins/table/ui/FloatingContextualButton/styles.js +34 -6
  13. package/dist/cjs/plugins/table/ui/FloatingContextualMenu/ContextualMenu.js +4 -1
  14. package/dist/cjs/plugins/table/ui/common-styles.js +1 -1
  15. package/dist/cjs/plugins/table/ui/consts.js +4 -4
  16. package/dist/cjs/plugins/table/ui/ui-styles.js +5 -5
  17. package/dist/cjs/version.json +1 -1
  18. package/dist/es2019/plugins/table/commands/hover.js +2 -1
  19. package/dist/es2019/plugins/table/event-handlers.js +10 -13
  20. package/dist/es2019/plugins/table/index.js +1 -1
  21. package/dist/es2019/plugins/table/nodeviews/TableComponent.js +12 -1
  22. package/dist/es2019/plugins/table/pm-plugins/default-table-selection.js +1 -2
  23. package/dist/es2019/plugins/table/pm-plugins/main.js +2 -2
  24. package/dist/es2019/plugins/table/pm-plugins/sticky-headers/nodeviews/tableRow.js +31 -4
  25. package/dist/es2019/plugins/table/pm-plugins/table-resizing/utils/resize-logic.js +1 -1
  26. package/dist/es2019/plugins/table/toolbar.js +43 -12
  27. package/dist/es2019/plugins/table/ui/FloatingContextualButton/index.js +6 -2
  28. package/dist/es2019/plugins/table/ui/FloatingContextualButton/styles.js +47 -8
  29. package/dist/es2019/plugins/table/ui/FloatingContextualMenu/ContextualMenu.js +4 -1
  30. package/dist/es2019/plugins/table/ui/common-styles.js +9 -9
  31. package/dist/es2019/plugins/table/ui/consts.js +5 -5
  32. package/dist/es2019/plugins/table/ui/ui-styles.js +5 -5
  33. package/dist/es2019/version.json +1 -1
  34. package/dist/esm/plugins/table/commands/hover.js +2 -1
  35. package/dist/esm/plugins/table/event-handlers.js +10 -14
  36. package/dist/esm/plugins/table/index.js +3 -1
  37. package/dist/esm/plugins/table/nodeviews/TableComponent.js +17 -6
  38. package/dist/esm/plugins/table/pm-plugins/default-table-selection.js +1 -2
  39. package/dist/esm/plugins/table/pm-plugins/main.js +2 -2
  40. package/dist/esm/plugins/table/pm-plugins/sticky-headers/nodeviews/tableRow.js +43 -8
  41. package/dist/esm/plugins/table/pm-plugins/table-resizing/utils/resize-logic.js +1 -1
  42. package/dist/esm/plugins/table/toolbar.js +43 -12
  43. package/dist/esm/plugins/table/ui/FloatingContextualButton/index.js +8 -2
  44. package/dist/esm/plugins/table/ui/FloatingContextualButton/styles.js +28 -5
  45. package/dist/esm/plugins/table/ui/FloatingContextualMenu/ContextualMenu.js +4 -1
  46. package/dist/esm/plugins/table/ui/common-styles.js +1 -1
  47. package/dist/esm/plugins/table/ui/consts.js +5 -5
  48. package/dist/esm/plugins/table/ui/ui-styles.js +5 -5
  49. package/dist/esm/version.json +1 -1
  50. package/dist/types/plugins/table/event-handlers.d.ts +2 -2
  51. package/dist/types/plugins/table/pm-plugins/default-table-selection.d.ts +0 -1
  52. package/dist/types/plugins/table/pm-plugins/sticky-headers/nodeviews/tableRow.d.ts +8 -0
  53. package/dist/types/plugins/table/toolbar.d.ts +3 -2
  54. package/dist/types/plugins/table/ui/FloatingContextualButton/styles.d.ts +3 -1
  55. package/dist/types/plugins/table/ui/FloatingContextualMenu/styles.d.ts +2 -2
  56. package/dist/types/plugins/table/ui/common-styles.d.ts +3 -3
  57. package/dist/types/plugins/table/ui/consts.d.ts +2 -2
  58. package/dist/types/plugins/table/ui/ui-styles.d.ts +14 -14
  59. package/package.json +4 -4
  60. package/src/__tests__/integration/__snapshots__/floating-toolbar.ts.snap +321 -0
  61. package/src/__tests__/integration/delete-last-column-in-full-width.ts +6 -5
  62. package/src/__tests__/integration/floating-toolbar.ts +169 -0
  63. package/src/__tests__/unit/get-toolbar-config.ts +1 -0
  64. package/src/__tests__/unit/nodeviews/TableComponent.tsx +146 -4
  65. package/src/__tests__/unit/pm-plugins/table-resizing/event-handlers.ts +82 -31
  66. package/src/__tests__/unit/toolbar.ts +165 -4
  67. 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 +2 -2
  68. package/src/plugins/table/commands/hover.ts +1 -0
  69. package/src/plugins/table/event-handlers.ts +6 -17
  70. package/src/plugins/table/index.tsx +1 -0
  71. package/src/plugins/table/nodeviews/TableComponent.tsx +10 -2
  72. package/src/plugins/table/nodeviews/tableCell.tsx +1 -1
  73. package/src/plugins/table/pm-plugins/default-table-selection.ts +0 -1
  74. package/src/plugins/table/pm-plugins/main.ts +26 -28
  75. package/src/plugins/table/pm-plugins/sticky-headers/nodeviews/tableRow.ts +44 -9
  76. package/src/plugins/table/pm-plugins/table-resizing/utils/resize-logic.ts +1 -1
  77. package/src/plugins/table/toolbar.tsx +60 -13
  78. package/src/plugins/table/ui/FloatingContextualButton/index.tsx +12 -2
  79. package/src/plugins/table/ui/FloatingContextualButton/styles.ts +51 -7
  80. package/src/plugins/table/ui/FloatingContextualMenu/ContextualMenu.tsx +3 -0
  81. package/src/plugins/table/ui/common-styles.ts +24 -9
  82. package/src/plugins/table/ui/consts.ts +7 -5
  83. package/src/plugins/table/ui/ui-styles.ts +20 -5
@@ -1,7 +1,11 @@
1
1
  import React from 'react';
2
2
  import { replaceRaf } from 'raf-stub';
3
+ import { TextSelection } from 'prosemirror-state';
4
+
5
+ import { Command } from '@atlaskit/editor-common/types';
3
6
  import { render } from '@testing-library/react';
4
7
  import { createEditorFactory } from '@atlaskit/editor-test-helpers/create-editor';
8
+ import { selectTableClosestToPos } from '@atlaskit/editor-tables/src/utils/select-nodes';
5
9
  import tablePlugin from '../../../plugins/table-plugin';
6
10
  import {
7
11
  doc,
@@ -12,8 +16,13 @@ import {
12
16
  tdEmpty,
13
17
  tdCursor,
14
18
  DocBuilder,
19
+ thEmpty,
15
20
  } from '@atlaskit/editor-test-helpers/doc-builder';
16
- import { findTable, selectTable } from '@atlaskit/editor-tables/utils';
21
+ import {
22
+ findTable,
23
+ findTableClosestToPos,
24
+ selectTable,
25
+ } from '@atlaskit/editor-tables/utils';
17
26
  import {
18
27
  TableCssClassName as ClassName,
19
28
  TablePluginState,
@@ -22,7 +31,11 @@ import TableComponent from '../../../plugins/table/nodeviews/TableComponent';
22
31
 
23
32
  import { pluginKey } from '../../../plugins/table/pm-plugins/plugin-key';
24
33
  import type { EventDispatcher } from '@atlaskit/editor-common/event-dispatcher';
25
- import { toggleNumberColumn } from '../../../plugins/table/commands';
34
+ import * as commands from '../../../plugins/table/commands';
35
+ import {
36
+ toggleNumberColumn,
37
+ hoverTable,
38
+ } from '../../../plugins/table/commands';
26
39
 
27
40
  jest.mock('../../../plugins/table/utils/nodes', () =>
28
41
  Object.assign({}, jest.requireActual('../../../plugins/table/utils/nodes'), {
@@ -30,6 +43,12 @@ jest.mock('../../../plugins/table/utils/nodes', () =>
30
43
  }),
31
44
  );
32
45
 
46
+ jest.mock('../../../plugins/table/commands', () =>
47
+ Object.assign({}, jest.requireActual('../../../plugins/table/commands'), {
48
+ clearHoverSelection: jest.fn(),
49
+ }),
50
+ );
51
+
33
52
  replaceRaf();
34
53
  const requestAnimationFrame = window.requestAnimationFrame as any;
35
54
 
@@ -57,8 +76,8 @@ describe('table -> nodeviews -> TableComponent.tsx', () => {
57
76
  jest.clearAllMocks();
58
77
  });
59
78
 
60
- describe('when the table is selected', () => {
61
- it('should add table selected css class', () => {
79
+ describe('when a table is selected', () => {
80
+ it('should add table selected css class to the selected table', () => {
62
81
  const { editorView } = editor(
63
82
  doc(p('text'), table()(tr(tdEmpty, tdEmpty, tdCursor))),
64
83
  {
@@ -78,6 +97,129 @@ describe('table -> nodeviews -> TableComponent.tsx', () => {
78
97
  tableContainer!.classList.contains(ClassName.TABLE_SELECTED),
79
98
  ).toBeTruthy();
80
99
  });
100
+
101
+ it('should not clear the editor state hover selection when changing selection to another table', () => {
102
+ const clearHoverSelectionSpy = jest
103
+ .spyOn(commands, 'clearHoverSelection')
104
+ .mockImplementation(() => (() => {}) as any as Command);
105
+
106
+ const { editorView } = editor(
107
+ doc(
108
+ p('text'),
109
+ table()(tr(thEmpty, thEmpty, thEmpty)),
110
+ table()(tr(thEmpty, thEmpty, thEmpty)),
111
+ ),
112
+ );
113
+ const { state, dispatch } = editorView;
114
+
115
+ const isInDanger = true;
116
+ hoverTable(isInDanger)(state, dispatch);
117
+
118
+ const selectSecondTableTr = selectTableClosestToPos(
119
+ state.tr,
120
+ state.doc.resolve(26),
121
+ );
122
+ dispatch(selectSecondTableTr);
123
+ const secondTable = findTableClosestToPos(state.doc.resolve(26));
124
+
125
+ const selectFirstTableTr = selectTableClosestToPos(
126
+ state.tr,
127
+ state.doc.resolve(8),
128
+ );
129
+ dispatch(selectFirstTableTr);
130
+ const firstTable = findTableClosestToPos(state.doc.resolve(8));
131
+
132
+ const getTableNode = (index: number) => () =>
133
+ index === 1 ? firstTable!.node : secondTable!.node;
134
+
135
+ render(
136
+ <div>
137
+ <TableComponent
138
+ view={editorView}
139
+ eventDispatcher={
140
+ { on: () => {}, off: () => {} } as any as EventDispatcher
141
+ }
142
+ // @ts-ignore
143
+ containerWidth={{}}
144
+ // @ts-ignore
145
+ getNode={getTableNode(1)}
146
+ getEditorFeatureFlags={getEditorFeatureFlags}
147
+ allowControls
148
+ contentDOM={(wrapper: HTMLElement | null) => {
149
+ const node = editorView.dom.getElementsByTagName('table')[0];
150
+ if (!wrapper?.firstChild) {
151
+ wrapper?.appendChild(node);
152
+ }
153
+ }}
154
+ />
155
+ <TableComponent
156
+ view={editorView}
157
+ eventDispatcher={
158
+ { on: () => {}, off: () => {} } as any as EventDispatcher
159
+ }
160
+ // @ts-ignore
161
+ containerWidth={{}}
162
+ // @ts-ignore
163
+ getNode={getTableNode(2)}
164
+ getEditorFeatureFlags={getEditorFeatureFlags}
165
+ allowControls
166
+ contentDOM={(wrapper: HTMLElement | null) => {
167
+ const node = editorView.dom.getElementsByTagName('table')[0];
168
+ if (!wrapper?.firstChild) {
169
+ wrapper?.appendChild(node);
170
+ }
171
+ }}
172
+ />
173
+ ,
174
+ </div>,
175
+ );
176
+ expect(clearHoverSelectionSpy).not.toBeCalled();
177
+ });
178
+ });
179
+
180
+ describe('when there are no tables in selection', () => {
181
+ it('clears the editor state hover selection if the editor state is in danger flag is set', () => {
182
+ const clearHoverSelectionSpy = jest
183
+ .spyOn(commands, 'clearHoverSelection')
184
+ .mockImplementation(() => (() => {}) as any as Command);
185
+
186
+ const { editorView } = editor(
187
+ doc(p('text'), table()(tr(thEmpty, thEmpty, thEmpty))),
188
+ );
189
+ const { state, dispatch } = editorView;
190
+
191
+ const isInDanger = true;
192
+ hoverTable(isInDanger)(state, dispatch);
193
+ dispatch(selectTable(state.tr));
194
+
195
+ const tableF = findTable(state.selection);
196
+ const getNode = () => tableF!.node;
197
+
198
+ const newTr = state.tr.setSelection(TextSelection.create(state.doc, 0));
199
+ dispatch(newTr);
200
+
201
+ render(
202
+ <TableComponent
203
+ view={editorView}
204
+ eventDispatcher={
205
+ { on: () => {}, off: () => {} } as any as EventDispatcher
206
+ }
207
+ // @ts-ignore
208
+ containerWidth={{}}
209
+ // @ts-ignore
210
+ getNode={getNode}
211
+ getEditorFeatureFlags={getEditorFeatureFlags}
212
+ allowControls
213
+ contentDOM={(wrapper: HTMLElement | null) => {
214
+ const node = editorView.dom.getElementsByTagName('table')[0];
215
+ if (!wrapper?.firstChild) {
216
+ wrapper?.appendChild(node);
217
+ }
218
+ }}
219
+ />,
220
+ );
221
+ expect(clearHoverSelectionSpy).toBeCalledTimes(1);
222
+ });
81
223
  });
82
224
 
83
225
  describe('when the numbered column attribute is changed', () => {
@@ -21,10 +21,12 @@ import {
21
21
 
22
22
  import tablePlugin from '../../../../plugins/table';
23
23
  import { pluginKey } from '../../../../plugins/table/pm-plugins/plugin-key';
24
- import { TextSelection, NodeSelection } from 'prosemirror-state';
24
+ import { TextSelection, NodeSelection, EditorState } from 'prosemirror-state';
25
+ import { EditorView } from 'prosemirror-view';
25
26
  import panelPlugin from '@atlaskit/editor-core/src/plugins/panel';
26
27
  import widthPlugin from '@atlaskit/editor-core/src/plugins/width';
27
28
  import type { EditorAnalyticsAPI } from '@atlaskit/editor-common/analytics';
29
+ import { akEditorFullPageMaxWidth } from '@atlaskit/editor-shared-styles/consts';
28
30
 
29
31
  describe('table-resizing/event-handlers', () => {
30
32
  const editorAnalyticsAPIFake: EditorAnalyticsAPI = {
@@ -57,18 +59,7 @@ describe('table-resizing/event-handlers', () => {
57
59
  doc(table()(tr(td()(p('1')), td()(p('2')), td()(p('3{<>}'))))),
58
60
  );
59
61
 
60
- setResizeHandlePos(12)(view.state, view.dispatch);
61
-
62
- const mousedownEvent = new MouseEvent('mousedown', {
63
- clientX: 150,
64
- });
65
-
66
- view.dom.dispatchEvent(mousedownEvent);
67
-
68
- const mouseupEvent = new MouseEvent('mouseup', {
69
- clientX: 250,
70
- });
71
- window.dispatchEvent(mouseupEvent);
62
+ resizeColumn(view, 12, 150, 250);
72
63
 
73
64
  expect(editorAnalyticsAPIFake.attachAnalyticsEvent).toHaveBeenCalledWith(
74
65
  expect.objectContaining({
@@ -85,6 +76,50 @@ describe('table-resizing/event-handlers', () => {
85
76
  );
86
77
  });
87
78
 
79
+ it('should shrink last column until table is no longer overflowing', async () => {
80
+ const { editorView: view } = editor(
81
+ doc(table()(tr(td()(p('1')), td()(p('2')), td()(p('3{<>}'))))),
82
+ );
83
+
84
+ // Increase column to overflow
85
+ resizeColumn(view, 7, 50, 500);
86
+
87
+ expect(getTotalTableWidth(view.state as EditorState)).toBeGreaterThan(
88
+ akEditorFullPageMaxWidth,
89
+ );
90
+
91
+ resizeColumn(view, 12, 3000, 700);
92
+
93
+ // No matter how large we try to resize the result should equal the width (within 1 pt)
94
+ expect(getTotalTableWidth(view.state as EditorState)).toBeLessThanOrEqual(
95
+ akEditorFullPageMaxWidth,
96
+ );
97
+ expect(
98
+ getTotalTableWidth(view.state as EditorState),
99
+ ).toBeGreaterThanOrEqual(akEditorFullPageMaxWidth - 1);
100
+ });
101
+
102
+ it('should not resize the last column to grow', async () => {
103
+ const { editorView: view } = editor(
104
+ doc(table()(tr(td()(p('1')), td()(p('2')), td()(p('3{<>}'))))),
105
+ );
106
+
107
+ // Increase column to overflow
108
+ resizeColumn(view, 7, 50, 500);
109
+
110
+ const overflowingTableWidth = getTotalTableWidth(
111
+ view.state as EditorState,
112
+ );
113
+ expect(overflowingTableWidth).toBeGreaterThan(akEditorFullPageMaxWidth);
114
+
115
+ resizeColumn(view, 12, 400, 3000);
116
+
117
+ // Width should be unchanged
118
+ expect(getTotalTableWidth(view.state as EditorState)).toBe(
119
+ overflowingTableWidth,
120
+ );
121
+ });
122
+
88
123
  it('should restore text selection after replacing the table', async () => {
89
124
  const { editorView: view } = editor(
90
125
  doc(table()(tr(td()(p('1')), td()(p('2')), td()(p('3{<>}'))))),
@@ -94,15 +129,7 @@ describe('table-resizing/event-handlers', () => {
94
129
  expect(currentSelection instanceof TextSelection).toBeTruthy();
95
130
  expect(currentSelection.$cursor.pos).toBe(15);
96
131
 
97
- setResizeHandlePos(12)(view.state, view.dispatch);
98
- const mousedownEvent = new MouseEvent('mousedown', {
99
- clientX: 150,
100
- });
101
- view.dom.dispatchEvent(mousedownEvent);
102
- const mouseupEvent = new MouseEvent('mouseup', {
103
- clientX: 250,
104
- });
105
- window.dispatchEvent(mouseupEvent);
132
+ resizeColumn(view, 12, 150, 250);
106
133
 
107
134
  expect(currentSelection instanceof TextSelection).toBeTruthy();
108
135
  expect(currentSelection.$cursor.pos).toBe(15);
@@ -118,17 +145,41 @@ describe('table-resizing/event-handlers', () => {
118
145
  view.dispatch(_tr);
119
146
  expect(view.state.tr.selection.node.type.name).toBe('panel');
120
147
 
121
- setResizeHandlePos(13)(view.state, view.dispatch);
122
- const mousedownEvent = new MouseEvent('mousedown', {
123
- clientX: 150,
124
- });
125
- view.dom.dispatchEvent(mousedownEvent);
126
- const mouseupEvent = new MouseEvent('mouseup', {
127
- clientX: 250,
128
- });
129
- window.dispatchEvent(mouseupEvent);
148
+ resizeColumn(view, 13, 150, 250);
130
149
 
131
150
  expect(view.state.tr.selection.node.type.name).toBe('panel');
132
151
  });
133
152
  });
134
153
  });
154
+
155
+ function getTotalTableWidth(state: EditorState) {
156
+ let totalWidth = 0;
157
+ state.doc.descendants((node) => {
158
+ if (node.type.name === 'tableCell') {
159
+ totalWidth += node.attrs.colwidth[0];
160
+ return false;
161
+ }
162
+ return true;
163
+ });
164
+ return totalWidth;
165
+ }
166
+
167
+ function resizeColumn(
168
+ view: EditorView,
169
+ pos: number,
170
+ start: number,
171
+ end: number,
172
+ ) {
173
+ setResizeHandlePos(pos)(view.state, view.dispatch);
174
+
175
+ const firstmousedownEvent = new MouseEvent('mousedown', {
176
+ clientX: start,
177
+ });
178
+
179
+ view.dom.dispatchEvent(firstmousedownEvent);
180
+
181
+ const firstmouseupEvent = new MouseEvent('mouseup', {
182
+ clientX: end,
183
+ });
184
+ window.dispatchEvent(firstmouseupEvent);
185
+ }
@@ -25,9 +25,17 @@ import { canMergeCells } from '../../plugins/table/transforms';
25
25
  import { Rect } from '@atlaskit/editor-tables/table-map';
26
26
  import tablePlugin from '../../plugins/table';
27
27
  import { pluginKey } from '../../plugins/table/pm-plugins/plugin-key';
28
+ import { getMergedCellsPositions } from '../../plugins/table/utils';
29
+ import { getNewResizeStateFromSelectedColumns } from '../../plugins/table/pm-plugins/table-resizing/utils/resize-state';
28
30
 
29
31
  jest.mock('@atlaskit/editor-tables/utils');
30
32
  jest.mock('../../plugins/table/transforms');
33
+ jest.mock('../../plugins/table/utils');
34
+ jest.mock('../../plugins/table/pm-plugins/table-resizing/utils/resize-state');
35
+
36
+ (getMergedCellsPositions as Function as jest.Mock<{}>).mockImplementation(
37
+ () => () => [],
38
+ );
31
39
 
32
40
  const formatMessage: (t: unknown) => string = (id) => 'Lorem ipsum';
33
41
  const ctx = { formatMessage };
@@ -138,13 +146,21 @@ describe('getToolbarMenuConfig', () => {
138
146
 
139
147
  describe('getToolbarCellOptionsConfig', () => {
140
148
  const createEditor = createProsemirrorEditorFactory();
141
- const {
142
- editorView: { state },
143
- } = createEditor({
149
+ const { editorView } = createEditor({
144
150
  doc: doc(table()(row(td()(p('1{cursor}'))))),
145
- preset: new Preset<LightEditorPlugin>().add(tablePlugin),
151
+ preset: new Preset<LightEditorPlugin>().add([
152
+ tablePlugin,
153
+ {
154
+ tableOptions: {
155
+ allowDistributeColumns: true,
156
+ allowColumnResizing: true,
157
+ allowColumnSorting: true,
158
+ },
159
+ },
160
+ ]),
146
161
  pluginKey,
147
162
  });
163
+ const { state } = editorView;
148
164
  const getEditorContainerWidth = () => ({ width: 500 });
149
165
 
150
166
  const formatMessage: (t: { id: string }) => string = (message) =>
@@ -152,6 +168,7 @@ describe('getToolbarCellOptionsConfig', () => {
152
168
  const rect = new Rect(1, 1, 1, 1);
153
169
  const cellOptionsMenu = getToolbarCellOptionsConfig(
154
170
  state,
171
+ editorView,
155
172
  rect,
156
173
  {
157
174
  formatMessage,
@@ -193,6 +210,21 @@ describe('getToolbarCellOptionsConfig', () => {
193
210
  disabled: true,
194
211
  });
195
212
  expect(items[6]).toMatchObject({
213
+ title: 'fabric.editor.distributeColumns',
214
+ selected: false,
215
+ disabled: true,
216
+ });
217
+ expect(items[7]).toMatchObject({
218
+ title: 'fabric.editor.sortColumnASC',
219
+ selected: false,
220
+ disabled: false,
221
+ });
222
+ expect(items[8]).toMatchObject({
223
+ title: 'fabric.editor.sortColumnDESC',
224
+ selected: false,
225
+ disabled: false,
226
+ });
227
+ expect(items[9]).toMatchObject({
196
228
  title: 'fabric.editor.clearCells',
197
229
  selected: false,
198
230
  disabled: false,
@@ -206,6 +238,7 @@ describe('getToolbarCellOptionsConfig', () => {
206
238
  //
207
239
  const cellOptionsMenu = getToolbarCellOptionsConfig(
208
240
  state,
241
+ editorView,
209
242
  rect,
210
243
  {
211
244
  formatMessage,
@@ -230,6 +263,7 @@ describe('getToolbarCellOptionsConfig', () => {
230
263
  //
231
264
  const cellOptionsMenu = getToolbarCellOptionsConfig(
232
265
  state,
266
+ editorView,
233
267
  rect,
234
268
  {
235
269
  formatMessage,
@@ -246,4 +280,131 @@ describe('getToolbarCellOptionsConfig', () => {
246
280
  disabled: false,
247
281
  });
248
282
  });
283
+
284
+ it('should disable sorting when merged cells are detected', () => {
285
+ (getMergedCellsPositions as Function as jest.Mock<{}>).mockImplementation(
286
+ () => [1, 2, 3],
287
+ );
288
+
289
+ const cellOptionsMenu = getToolbarCellOptionsConfig(
290
+ state,
291
+ editorView,
292
+ rect,
293
+ {
294
+ formatMessage,
295
+ },
296
+ getEditorContainerWidth,
297
+ undefined,
298
+ );
299
+
300
+ const items = cellOptionsMenu.options as Array<DropdownOptionT<Command>>;
301
+ const sortItems = items.filter((item) =>
302
+ item.id?.startsWith('editor.table.sortColumn'),
303
+ );
304
+
305
+ const isDisabled = sortItems.every((item) => item.disabled);
306
+ const hasTooltip = sortItems.every((item) => item.tooltip);
307
+
308
+ expect(isDisabled).toBeTruthy();
309
+ expect(hasTooltip).toBeTruthy();
310
+ });
311
+
312
+ it('should allow sorting when there are no merged cells detected', () => {
313
+ (getMergedCellsPositions as Function as jest.Mock<{}>).mockImplementation(
314
+ () => [],
315
+ );
316
+
317
+ const cellOptionsMenu = getToolbarCellOptionsConfig(
318
+ state,
319
+ editorView,
320
+ rect,
321
+ {
322
+ formatMessage,
323
+ },
324
+ getEditorContainerWidth,
325
+ undefined,
326
+ );
327
+
328
+ const items = cellOptionsMenu.options as Array<DropdownOptionT<Command>>;
329
+ const sortItems = items.filter((item) =>
330
+ item.id?.startsWith('editor.table.sortColumn'),
331
+ );
332
+
333
+ const isDisabled = sortItems.every((item) => item.disabled);
334
+ const hasTooltip = sortItems.every((item) => item.tooltip);
335
+
336
+ expect(isDisabled).toBeFalsy();
337
+ expect(hasTooltip).toBeFalsy();
338
+ });
339
+
340
+ it('should disable distribute columns when no resize detected', () => {
341
+ (
342
+ getNewResizeStateFromSelectedColumns as Function as jest.Mock<{}>
343
+ ).mockImplementation(() => ({ changed: false }));
344
+
345
+ const cellOptionsMenu = getToolbarCellOptionsConfig(
346
+ state,
347
+ editorView,
348
+ rect,
349
+ {
350
+ formatMessage,
351
+ },
352
+ getEditorContainerWidth,
353
+ undefined,
354
+ );
355
+
356
+ const items = cellOptionsMenu.options as Array<DropdownOptionT<Command>>;
357
+ const distributeColumns = items.filter((item) =>
358
+ item.id?.startsWith('editor.table.distributeColumns'),
359
+ );
360
+
361
+ const isDisabled = distributeColumns.every((item) => item.disabled);
362
+ expect(isDisabled).toBeTruthy();
363
+ });
364
+
365
+ it('should allow distribute columns when resize detected', () => {
366
+ (
367
+ getNewResizeStateFromSelectedColumns as Function as jest.Mock<{}>
368
+ ).mockImplementation(() => ({ changed: true }));
369
+
370
+ const cellOptionsMenu = getToolbarCellOptionsConfig(
371
+ state,
372
+ editorView,
373
+ rect,
374
+ {
375
+ formatMessage,
376
+ },
377
+ getEditorContainerWidth,
378
+ undefined,
379
+ );
380
+
381
+ const items = cellOptionsMenu.options as Array<DropdownOptionT<Command>>;
382
+ const distributeColumns = items.filter((item) =>
383
+ item.id?.startsWith('editor.table.distributeColumns'),
384
+ );
385
+
386
+ const isDisabled = distributeColumns.every((item) => item.disabled);
387
+ expect(isDisabled).toBeFalsy();
388
+ });
389
+
390
+ it('should disable distribute columns when editorView is undefined', () => {
391
+ const cellOptionsMenu = getToolbarCellOptionsConfig(
392
+ state,
393
+ undefined,
394
+ rect,
395
+ {
396
+ formatMessage,
397
+ },
398
+ getEditorContainerWidth,
399
+ undefined,
400
+ );
401
+
402
+ const items = cellOptionsMenu.options as Array<DropdownOptionT<Command>>;
403
+ const distributeColumns = items.filter((item) =>
404
+ item.id?.startsWith('editor.table.distributeColumns'),
405
+ );
406
+
407
+ const isDisabled = distributeColumns.every((item) => item.disabled);
408
+ expect(isDisabled).toBeTruthy();
409
+ });
249
410
  });
@@ -1,3 +1,3 @@
1
1
  version https://git-lfs.github.com/spec/v1
2
- oid sha256:ae2a52bca4841381cd728c6e22d70aebd6a58177ce5123fedb725d5ac2aa80ac
3
- size 13915
2
+ oid sha256:5cd747accdc40bfc52f004ff689a3df00173ee2f27d15c68f3a76172c11050fd
3
+ size 13990
@@ -164,6 +164,7 @@ export const clearHoverSelection = () =>
164
164
  [],
165
165
  TableDecorations.ALL_CONTROLS_HOVER,
166
166
  ),
167
+ isInDanger: false,
167
168
  },
168
169
  }));
169
170
 
@@ -63,6 +63,7 @@ import {
63
63
  isRowControlsButton,
64
64
  isTableControlsButton,
65
65
  isTableContainerOrWrapper,
66
+ hasResizeHandler,
66
67
  } from './utils';
67
68
  import { getAllowAddColumnCustomStep } from './utils/get-allow-add-column-custom-step';
68
69
  import type { GetEditorFeatureFlags } from '@atlaskit/editor-common/types';
@@ -298,7 +299,6 @@ export const handleMouseMove =
298
299
  (
299
300
  view: EditorView,
300
301
  event: Event,
301
- tableCellOptimization?: boolean,
302
302
  elementContentRects?: ElementContentRects,
303
303
  ) => {
304
304
  if (!(event.target instanceof HTMLElement)) {
@@ -314,7 +314,7 @@ export const handleMouseMove =
314
314
  const positionColumn =
315
315
  getMousePositionHorizontalRelativeByElement(
316
316
  event as MouseEvent,
317
- tableCellOptimization,
317
+ false,
318
318
  elementContentRects,
319
319
  ) === 'right'
320
320
  ? endIndex
@@ -342,15 +342,11 @@ export const handleMouseMove =
342
342
  }
343
343
 
344
344
  const { mouseMoveOptimization } = getEditorFeatureFlags();
345
- // we only want to allow mouseMoveOptimisation when tableCellOptimization is enabled
346
- // because it relies on tableCell node view that is added via tableCellOptimization
347
- const useMouseMoveOptimisation =
348
- tableCellOptimization && mouseMoveOptimization;
349
345
 
350
346
  if (!isResizeHandleDecoration(element) && isCell(element)) {
351
347
  const positionColumn = getMousePositionHorizontalRelativeByElement(
352
348
  event as MouseEvent,
353
- useMouseMoveOptimisation,
349
+ mouseMoveOptimization,
354
350
  elementContentRects,
355
351
  RESIZE_HANDLE_AREA_DECORATION_GAP,
356
352
  );
@@ -376,7 +372,8 @@ export const handleMouseMove =
376
372
 
377
373
  if (
378
374
  columnEndIndexTarget !== resizeHandleColumnIndex ||
379
- rowIndexTarget !== resizeHandleRowIndex
375
+ rowIndexTarget !== resizeHandleRowIndex ||
376
+ !hasResizeHandler({ target: element, columnEndIndexTarget })
380
377
  ) {
381
378
  return addResizeHandleDecorations(
382
379
  rowIndexTarget,
@@ -487,7 +484,6 @@ export const whenTableInFocus =
487
484
  eventHandler: (
488
485
  view: EditorView,
489
486
  mouseEvent: Event,
490
- tableCellOptimization?: boolean,
491
487
  elementContentRects?: ElementContentRects,
492
488
  ) => boolean,
493
489
  elementContentRects?: ElementContentRects,
@@ -498,17 +494,10 @@ export const whenTableInFocus =
498
494
  const isDragging =
499
495
  tableResizePluginState && !!tableResizePluginState.dragging;
500
496
  const hasTableNode = tablePluginState && tablePluginState.tableNode;
501
- const tableCellOptimization =
502
- tablePluginState?.pluginConfig?.tableCellOptimization;
503
497
 
504
498
  if (!hasTableNode || isDragging) {
505
499
  return false;
506
500
  }
507
501
 
508
- return eventHandler(
509
- view,
510
- mouseEvent,
511
- tableCellOptimization,
512
- elementContentRects,
513
- );
502
+ return eventHandler(view, mouseEvent, elementContentRects);
514
503
  };
@@ -458,6 +458,7 @@ const tablesPlugin = (options?: TablePluginOptions): EditorPlugin => {
458
458
  defaultGetEditorContainerWidth,
459
459
  options?.editorAnalyticsAPI,
460
460
  options?.getEditorFeatureFlags || defaultGetEditorFeatureFlags,
461
+ () => editorViewRef.current,
461
462
  )(pluginConfig(options?.tableOptions)),
462
463
  },
463
464
  };
@@ -4,6 +4,7 @@ import { Node as PmNode } from 'prosemirror-model';
4
4
  import { isTableSelected } from '@atlaskit/editor-tables/utils';
5
5
  import { EditorView } from 'prosemirror-view';
6
6
  import rafSchedule from 'raf-schd';
7
+ import { findTable } from '@atlaskit/editor-tables/utils';
7
8
 
8
9
  import {
9
10
  calcTableWidth,
@@ -19,7 +20,7 @@ import { getParentNodeWidth } from '@atlaskit/editor-common/node-width';
19
20
  import type { EditorContainerWidth } from '@atlaskit/editor-common/types';
20
21
  import { parsePx } from '@atlaskit/editor-common/utils';
21
22
 
22
- import { autoSizeTable } from '../commands';
23
+ import { autoSizeTable, clearHoverSelection } from '../commands';
23
24
  import { getPluginState } from '../pm-plugins/plugin-factory';
24
25
  import {
25
26
  findStickyHeaderForTable,
@@ -196,7 +197,14 @@ class TableComponent extends React.Component<ComponentProps, TableState> {
196
197
  }
197
198
 
198
199
  componentDidUpdate(prevProps: ComponentProps) {
199
- const { getNode, isMediaFullscreen, allowColumnResizing } = this.props;
200
+ const { view, getNode, isMediaFullscreen, allowColumnResizing } =
201
+ this.props;
202
+ const { isInDanger } = getPluginState(view.state);
203
+ const table = findTable(view.state.selection);
204
+
205
+ if (isInDanger && !table) {
206
+ clearHoverSelection()(view.state, view.dispatch);
207
+ }
200
208
 
201
209
  const { tableOverflowShadowsOptimization } =
202
210
  this.props.getEditorFeatureFlags();