@atlaskit/editor-plugin-table 0.2.2 → 0.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 (80) hide show
  1. package/CHANGELOG.md +20 -0
  2. package/dist/cjs/plugins/table/commands/hover.js +2 -1
  3. package/dist/cjs/plugins/table/event-handlers.js +5 -12
  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 +5 -11
  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 +5 -12
  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/consts.d.ts +2 -2
  56. package/package.json +4 -4
  57. package/src/__tests__/integration/__snapshots__/floating-toolbar.ts.snap +321 -0
  58. package/src/__tests__/integration/delete-last-column-in-full-width.ts +6 -5
  59. package/src/__tests__/integration/floating-toolbar.ts +169 -0
  60. package/src/__tests__/unit/get-toolbar-config.ts +1 -0
  61. package/src/__tests__/unit/nodeviews/TableComponent.tsx +146 -4
  62. package/src/__tests__/unit/pm-plugins/table-resizing/event-handlers.ts +82 -31
  63. package/src/__tests__/unit/toolbar.ts +165 -4
  64. 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
  65. package/src/plugins/table/commands/hover.ts +1 -0
  66. package/src/plugins/table/event-handlers.ts +3 -16
  67. package/src/plugins/table/index.tsx +1 -0
  68. package/src/plugins/table/nodeviews/TableComponent.tsx +10 -2
  69. package/src/plugins/table/nodeviews/tableCell.tsx +1 -1
  70. package/src/plugins/table/pm-plugins/default-table-selection.ts +0 -1
  71. package/src/plugins/table/pm-plugins/main.ts +26 -28
  72. package/src/plugins/table/pm-plugins/sticky-headers/nodeviews/tableRow.ts +44 -9
  73. package/src/plugins/table/pm-plugins/table-resizing/utils/resize-logic.ts +1 -1
  74. package/src/plugins/table/toolbar.tsx +60 -13
  75. package/src/plugins/table/ui/FloatingContextualButton/index.tsx +12 -2
  76. package/src/plugins/table/ui/FloatingContextualButton/styles.ts +51 -7
  77. package/src/plugins/table/ui/FloatingContextualMenu/ContextualMenu.tsx +3 -0
  78. package/src/plugins/table/ui/common-styles.ts +24 -9
  79. package/src/plugins/table/ui/consts.ts +7 -5
  80. package/src/plugins/table/ui/ui-styles.ts +20 -5
@@ -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
 
@@ -298,7 +298,6 @@ export const handleMouseMove =
298
298
  (
299
299
  view: EditorView,
300
300
  event: Event,
301
- tableCellOptimization?: boolean,
302
301
  elementContentRects?: ElementContentRects,
303
302
  ) => {
304
303
  if (!(event.target instanceof HTMLElement)) {
@@ -314,7 +313,7 @@ export const handleMouseMove =
314
313
  const positionColumn =
315
314
  getMousePositionHorizontalRelativeByElement(
316
315
  event as MouseEvent,
317
- tableCellOptimization,
316
+ false,
318
317
  elementContentRects,
319
318
  ) === 'right'
320
319
  ? endIndex
@@ -342,15 +341,11 @@ export const handleMouseMove =
342
341
  }
343
342
 
344
343
  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
344
 
350
345
  if (!isResizeHandleDecoration(element) && isCell(element)) {
351
346
  const positionColumn = getMousePositionHorizontalRelativeByElement(
352
347
  event as MouseEvent,
353
- useMouseMoveOptimisation,
348
+ mouseMoveOptimization,
354
349
  elementContentRects,
355
350
  RESIZE_HANDLE_AREA_DECORATION_GAP,
356
351
  );
@@ -487,7 +482,6 @@ export const whenTableInFocus =
487
482
  eventHandler: (
488
483
  view: EditorView,
489
484
  mouseEvent: Event,
490
- tableCellOptimization?: boolean,
491
485
  elementContentRects?: ElementContentRects,
492
486
  ) => boolean,
493
487
  elementContentRects?: ElementContentRects,
@@ -498,17 +492,10 @@ export const whenTableInFocus =
498
492
  const isDragging =
499
493
  tableResizePluginState && !!tableResizePluginState.dragging;
500
494
  const hasTableNode = tablePluginState && tablePluginState.tableNode;
501
- const tableCellOptimization =
502
- tablePluginState?.pluginConfig?.tableCellOptimization;
503
495
 
504
496
  if (!hasTableNode || isDragging) {
505
497
  return false;
506
498
  }
507
499
 
508
- return eventHandler(
509
- view,
510
- mouseEvent,
511
- tableCellOptimization,
512
- elementContentRects,
513
- );
500
+ return eventHandler(view, mouseEvent, elementContentRects);
514
501
  };
@@ -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();
@@ -53,7 +53,7 @@ export default class TableCellNodeView implements NodeView {
53
53
  }
54
54
  }
55
55
 
56
- private updateNodeView(node: Node): boolean {
56
+ private updateNodeView(node: Node) {
57
57
  if (this.node.type !== node.type) {
58
58
  return false;
59
59
  }
@@ -1,5 +1,4 @@
1
1
  export const defaultTableSelection = {
2
2
  hoveredColumns: [],
3
3
  hoveredRows: [],
4
- isInDanger: false,
5
4
  };
@@ -125,34 +125,32 @@ export const createPlugin = (
125
125
  })
126
126
  : undefined;
127
127
 
128
- const tableCellNodeview = pluginConfig.tableCellOptimization
129
- ? {
130
- tableCell: (
131
- node: ProseMirrorNode,
132
- view: EditorView,
133
- getPos: getPosHandler,
134
- ) =>
135
- new TableCellNodeView(
136
- node,
137
- view,
138
- getPos,
139
- getEditorFeatureFlags,
140
- observer,
141
- ),
142
- tableHeader: (
143
- node: ProseMirrorNode,
144
- view: EditorView,
145
- getPos: getPosHandler,
146
- ) =>
147
- new TableCellNodeView(
148
- node,
149
- view,
150
- getPos,
151
- getEditorFeatureFlags,
152
- observer,
153
- ),
154
- }
155
- : {};
128
+ const tableCellNodeview = {
129
+ tableCell: (
130
+ node: ProseMirrorNode,
131
+ view: EditorView,
132
+ getPos: getPosHandler,
133
+ ) =>
134
+ new TableCellNodeView(
135
+ node,
136
+ view,
137
+ getPos,
138
+ getEditorFeatureFlags,
139
+ observer,
140
+ ),
141
+ tableHeader: (
142
+ node: ProseMirrorNode,
143
+ view: EditorView,
144
+ getPos: getPosHandler,
145
+ ) =>
146
+ new TableCellNodeView(
147
+ node,
148
+ view,
149
+ getPos,
150
+ getEditorFeatureFlags,
151
+ observer,
152
+ ),
153
+ };
156
154
 
157
155
  // Used to prevent invalid table cell spans being reported more than once per editor/document
158
156
  const invalidTableIds: string[] = [];
@@ -33,19 +33,51 @@ import throttle from 'lodash/throttle';
33
33
  const HEADER_ROW_SCROLL_THROTTLE_TIMEOUT = 200;
34
34
 
35
35
  // timeout for resetting the scroll class - if it’s too long then users won’t be able to click on the header cells,
36
- // if too short it would trigger too many dom udpates.
36
+ // if too short it would trigger too many dom updates.
37
37
  const HEADER_ROW_SCROLL_RESET_DEBOUNCE_TIMEOUT = 400;
38
38
 
39
+ const anyChildCellMergedAcrossRow = (node: PmNode) =>
40
+ mapChildren(node, (child) => child.attrs.rowspan || 0).some(
41
+ (rowspan) => rowspan > 1,
42
+ );
43
+
44
+ /**
45
+ * Compare two table row nodes and return true if the two table rows have a
46
+ * different number of table cells or if table cell row spans are different
47
+ */
48
+ const rowHasDifferentMergedCells = (prevNode: PmNode, incomingNode: PmNode) => {
49
+ const incomingNodeChildrenRowSpan = mapChildren(
50
+ prevNode,
51
+ (child) => child.attrs.rowspan || 0,
52
+ );
53
+ const currentNodeChildrenRowSpan = mapChildren(
54
+ incomingNode,
55
+ (child) => child.attrs.rowspan || 0,
56
+ );
57
+
58
+ return (
59
+ incomingNodeChildrenRowSpan.length !== currentNodeChildrenRowSpan.length ||
60
+ currentNodeChildrenRowSpan.some(
61
+ (child, index) => child !== incomingNodeChildrenRowSpan[index],
62
+ )
63
+ );
64
+ };
65
+
66
+ /**
67
+ * Check if a given node is a header row with this definition:
68
+ * - all children are tableHeader cells
69
+ * - no table cells have been have merged with other table row cells
70
+ *
71
+ * @param node ProseMirror node
72
+ * @return boolean if it meets definition
73
+ */
39
74
  export const supportedHeaderRow = (node: PmNode) => {
40
75
  const allHeaders = mapChildren(
41
76
  node,
42
77
  (child) => child.type.name === 'tableHeader',
43
78
  ).every(Boolean);
44
79
 
45
- const someMerged = mapChildren(
46
- node,
47
- (child) => child.attrs.rowspan || 0,
48
- ).some((rowspan) => rowspan > 1);
80
+ const someMerged = anyChildCellMergedAcrossRow(node);
49
81
 
50
82
  return allHeaders && !someMerged;
51
83
  };
@@ -297,8 +329,8 @@ export class TableRowNodeView implements NodeView {
297
329
  { root: this.editorScrollableElement as Element },
298
330
  );
299
331
  }
300
- /* paint/update loop */
301
332
 
333
+ /* paint/update loop */
302
334
  previousDomTop: number | undefined;
303
335
  previousPadding: number | undefined;
304
336
 
@@ -367,7 +399,6 @@ export class TableRowNodeView implements NodeView {
367
399
  };
368
400
 
369
401
  /* nodeview lifecycle */
370
-
371
402
  update(node: PmNode, ..._args: any[]) {
372
403
  // do nothing if nodes were identical
373
404
  if (node === this.node) {
@@ -376,11 +407,15 @@ export class TableRowNodeView implements NodeView {
376
407
 
377
408
  // see if we're changing into a header row or
378
409
  // changing away from one
379
- const newNodeisHeaderRow = supportedHeaderRow(node);
380
- if (this.isHeaderRow !== newNodeisHeaderRow) {
410
+ const newNodeIsHeaderRow = supportedHeaderRow(node);
411
+ if (this.isHeaderRow !== newNodeIsHeaderRow) {
381
412
  return false; // re-create nodeview
382
413
  }
383
414
 
415
+ if (rowHasDifferentMergedCells(this.node, node)) {
416
+ return false;
417
+ }
418
+
384
419
  // node is different but no need to re-create nodeview
385
420
  this.node = node;
386
421
 
@@ -33,7 +33,7 @@ export const shrinkColumn = (
33
33
  selectedColumns?: number[],
34
34
  ): ResizeState => {
35
35
  // can't shrink if columns don't exist
36
- if (!state.cols[colIndex] || !state.cols[colIndex + 1]) {
36
+ if (!state.cols[colIndex]) {
37
37
  return state;
38
38
  }
39
39
  // try to shrink dragging column by giving from the column to the right first