@atlaskit/editor-plugin-table 1.2.0 → 1.2.2

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 (107) hide show
  1. package/CHANGELOG.md +26 -0
  2. package/dist/cjs/i18n/en.js +43 -0
  3. package/dist/cjs/i18n/en_GB.js +43 -0
  4. package/dist/cjs/plugins/table/index.js +2 -1
  5. package/dist/cjs/plugins/table/nodeviews/OverflowShadowsObserver.js +13 -26
  6. package/dist/cjs/plugins/table/nodeviews/TableComponent.js +18 -3
  7. package/dist/cjs/plugins/table/nodeviews/table.js +7 -0
  8. package/dist/cjs/plugins/table/pm-plugins/sticky-headers/nodeviews/tableRow.js +32 -17
  9. package/dist/cjs/plugins/table/pm-plugins/table-resizing/event-handlers.js +1 -5
  10. package/dist/cjs/plugins/table/pm-plugins/table-resizing/utils/misc.js +3 -38
  11. package/dist/cjs/plugins/table/transforms/delete-rows.js +1 -1
  12. package/dist/cjs/plugins/table/transforms/index.js +3 -3
  13. package/dist/cjs/plugins/table/transforms/merge.js +39 -54
  14. package/dist/cjs/plugins/table/ui/FloatingContextualMenu/ContextualMenu.js +16 -3
  15. package/dist/cjs/plugins/table/ui/FloatingContextualMenu/index.js +6 -3
  16. package/dist/cjs/plugins/table/ui/common-styles.js +2 -2
  17. package/dist/cjs/plugins/table/utils/row-controls.js +3 -2
  18. package/dist/cjs/types/i18n.js +5 -0
  19. package/dist/cjs/version.json +1 -1
  20. package/dist/es2019/i18n/en.js +36 -0
  21. package/dist/es2019/i18n/en_GB.js +36 -0
  22. package/dist/es2019/plugins/table/index.js +2 -1
  23. package/dist/es2019/plugins/table/nodeviews/OverflowShadowsObserver.js +13 -26
  24. package/dist/es2019/plugins/table/nodeviews/TableComponent.js +22 -3
  25. package/dist/es2019/plugins/table/nodeviews/table.js +7 -0
  26. package/dist/es2019/plugins/table/pm-plugins/sticky-headers/nodeviews/tableRow.js +32 -17
  27. package/dist/es2019/plugins/table/pm-plugins/table-resizing/event-handlers.js +1 -5
  28. package/dist/es2019/plugins/table/pm-plugins/table-resizing/utils/misc.js +1 -37
  29. package/dist/es2019/plugins/table/transforms/delete-rows.js +2 -2
  30. package/dist/es2019/plugins/table/transforms/index.js +1 -1
  31. package/dist/es2019/plugins/table/transforms/merge.js +39 -43
  32. package/dist/es2019/plugins/table/ui/FloatingContextualMenu/ContextualMenu.js +18 -4
  33. package/dist/es2019/plugins/table/ui/FloatingContextualMenu/index.js +6 -3
  34. package/dist/es2019/plugins/table/ui/common-styles.js +21 -1
  35. package/dist/es2019/plugins/table/utils/row-controls.js +3 -2
  36. package/dist/es2019/types/i18n.js +1 -0
  37. package/dist/es2019/version.json +1 -1
  38. package/dist/esm/i18n/en.js +36 -0
  39. package/dist/esm/i18n/en_GB.js +36 -0
  40. package/dist/esm/plugins/table/index.js +2 -1
  41. package/dist/esm/plugins/table/nodeviews/OverflowShadowsObserver.js +13 -26
  42. package/dist/esm/plugins/table/nodeviews/TableComponent.js +18 -3
  43. package/dist/esm/plugins/table/nodeviews/table.js +7 -0
  44. package/dist/esm/plugins/table/pm-plugins/sticky-headers/nodeviews/tableRow.js +32 -17
  45. package/dist/esm/plugins/table/pm-plugins/table-resizing/event-handlers.js +1 -5
  46. package/dist/esm/plugins/table/pm-plugins/table-resizing/utils/misc.js +1 -35
  47. package/dist/esm/plugins/table/transforms/delete-rows.js +2 -2
  48. package/dist/esm/plugins/table/transforms/index.js +1 -1
  49. package/dist/esm/plugins/table/transforms/merge.js +38 -53
  50. package/dist/esm/plugins/table/ui/FloatingContextualMenu/ContextualMenu.js +17 -4
  51. package/dist/esm/plugins/table/ui/FloatingContextualMenu/index.js +6 -3
  52. package/dist/esm/plugins/table/ui/common-styles.js +2 -2
  53. package/dist/esm/plugins/table/utils/row-controls.js +3 -2
  54. package/dist/esm/types/i18n.js +1 -0
  55. package/dist/esm/version.json +1 -1
  56. package/dist/types/i18n/en.d.ts +35 -0
  57. package/dist/types/i18n/en_GB.d.ts +35 -0
  58. package/dist/types/plugins/table/nodeviews/OverflowShadowsObserver.d.ts +4 -5
  59. package/dist/types/plugins/table/nodeviews/TableComponent.d.ts +1 -0
  60. package/dist/types/plugins/table/nodeviews/__mocks__/OverflowShadowsObserver.d.ts +3 -3
  61. package/dist/types/plugins/table/pm-plugins/sticky-headers/nodeviews/tableRow.d.ts +2 -2
  62. package/dist/types/plugins/table/pm-plugins/table-resizing/utils/misc.d.ts +1 -2
  63. package/dist/types/plugins/table/transforms/index.d.ts +1 -1
  64. package/dist/types/plugins/table/transforms/merge.d.ts +1 -1
  65. package/dist/types/plugins/table/types.d.ts +2 -0
  66. package/dist/types/plugins/table/ui/FloatingContextualMenu/ContextualMenu.d.ts +2 -1
  67. package/dist/types/plugins/table/ui/FloatingContextualMenu/index.d.ts +3 -2
  68. package/dist/types/types/i18n.d.ts +5 -0
  69. package/package.json +10 -9
  70. package/src/__tests__/integration/__fixtures__/table-and-paragraph-adf.ts +130 -0
  71. package/src/__tests__/integration/horizontal-scroll-shadows.ts +199 -0
  72. package/src/__tests__/integration/horizontal-scroll.ts +4 -9
  73. package/src/__tests__/integration/meta-arrowup-cursor-in-first-row.ts +4 -2
  74. package/src/__tests__/integration/sticky-header.ts +61 -1
  75. package/src/__tests__/unit/commands/insert.ts +8 -8
  76. package/src/__tests__/unit/commands/sort.ts +4 -0
  77. package/src/__tests__/unit/commands.ts +2 -0
  78. package/src/__tests__/unit/index.ts +2 -0
  79. package/src/__tests__/unit/keymap.ts +4 -2
  80. package/src/__tests__/unit/layout.ts +2 -0
  81. package/src/__tests__/unit/nodeviews/OverflowShadowsObserver.ts +20 -11
  82. package/src/__tests__/unit/nodeviews/cell.ts +14 -0
  83. package/src/__tests__/unit/pm-plugins/main-with-allow-collapse.ts +2 -0
  84. package/src/__tests__/unit/pm-plugins/sticky-headers/tableRow.tsx +2 -2
  85. package/src/__tests__/unit/transforms/delete-rows.ts +45 -0
  86. package/src/__tests__/unit/ui/ContextualMenu.tsx +2 -0
  87. package/src/__tests__/unit/ui/FloatingContextualMenu.tsx +1 -0
  88. package/src/__tests__/unit/utils/collapse.ts +4 -1
  89. package/src/i18n/en.ts +36 -0
  90. package/src/i18n/en_GB.ts +36 -0
  91. package/src/plugins/table/index.tsx +4 -0
  92. package/src/plugins/table/nodeviews/OverflowShadowsObserver.ts +24 -40
  93. package/src/plugins/table/nodeviews/TableComponent.tsx +20 -4
  94. package/src/plugins/table/nodeviews/__mocks__/OverflowShadowsObserver.ts +3 -3
  95. package/src/plugins/table/nodeviews/table.tsx +12 -0
  96. package/src/plugins/table/pm-plugins/sticky-headers/nodeviews/tableRow.ts +40 -23
  97. package/src/plugins/table/pm-plugins/table-resizing/event-handlers.ts +1 -9
  98. package/src/plugins/table/pm-plugins/table-resizing/utils/misc.ts +1 -57
  99. package/src/plugins/table/transforms/delete-rows.ts +2 -2
  100. package/src/plugins/table/transforms/index.ts +1 -1
  101. package/src/plugins/table/transforms/merge.ts +41 -43
  102. package/src/plugins/table/ui/FloatingContextualMenu/ContextualMenu.tsx +21 -2
  103. package/src/plugins/table/ui/FloatingContextualMenu/index.tsx +8 -1
  104. package/src/plugins/table/ui/common-styles.ts +21 -0
  105. package/src/plugins/table/utils/row-controls.ts +3 -2
  106. package/src/types/i18n.ts +5 -0
  107. package/src/__tests__/integration/__fixtures__/table-and-paragraph-adf.json +0 -130
@@ -172,7 +172,7 @@ export class TableRowNodeView {
172
172
  syncStickyRowToTable(tree.table);
173
173
  }, 0);
174
174
  });
175
- _defineProperty(this, "onWidthPluginState", () => {
175
+ _defineProperty(this, "updateStickyHeaderWidth", () => {
176
176
  // table width might have changed, sync that back to sticky row
177
177
  const tree = this.tree;
178
178
  if (!tree) {
@@ -206,7 +206,7 @@ export class TableRowNodeView {
206
206
  // otherwise make it non-sticky
207
207
  return false;
208
208
  });
209
- _defineProperty(this, "makeHeaderRowSticky", tree => {
209
+ _defineProperty(this, "makeHeaderRowSticky", (tree, scrollTop) => {
210
210
  var _tbody$firstChild;
211
211
  // If header row height is more than 50% of viewport height don't do this
212
212
  if (this.stickyRowHeight && this.stickyRowHeight > window.innerHeight / 2) {
@@ -223,7 +223,10 @@ export class TableRowNodeView {
223
223
  return;
224
224
  }
225
225
  const currentTableTop = this.getCurrentTableTop(tree);
226
- const domTop = currentTableTop > 0 ? this.topPosEditorElement : this.topPosEditorElement + currentTableTop;
226
+ if (!scrollTop) {
227
+ scrollTop = getTop(this.editorScrollableElement);
228
+ }
229
+ const domTop = currentTableTop > 0 ? scrollTop : scrollTop + currentTableTop;
227
230
  if (!this.isSticky) {
228
231
  syncStickyRowToTable(table);
229
232
  this.dom.classList.add('sticky');
@@ -315,7 +318,7 @@ export class TableRowNodeView {
315
318
  }
316
319
  this.topPosEditorElement = getTop(this.editorScrollableElement);
317
320
  }
318
- this.eventDispatcher.on('widthPlugin', this.onWidthPluginState);
321
+ this.eventDispatcher.on('widthPlugin', this.updateStickyHeaderWidth);
319
322
  this.eventDispatcher.on(tablePluginKey.key, this.onTablePluginState);
320
323
  this.listening = true;
321
324
  this.dom.addEventListener('wheel', this.headerRowMouseScroll.bind(this));
@@ -341,7 +344,7 @@ export class TableRowNodeView {
341
344
  if (this.editorScrollableElement && !this.stickyHeadersOptimization) {
342
345
  this.editorScrollableElement.removeEventListener('scroll', this.onScroll);
343
346
  }
344
- this.eventDispatcher.off('widthPlugin', this.onWidthPluginState);
347
+ this.eventDispatcher.off('widthPlugin', this.updateStickyHeaderWidth);
345
348
  this.eventDispatcher.off(tablePluginKey.key, this.onTablePluginState);
346
349
  this.listening = false;
347
350
  this.dom.removeEventListener('wheel', this.headerRowMouseScroll);
@@ -360,6 +363,9 @@ export class TableRowNodeView {
360
363
  return;
361
364
  }
362
365
  this.resizeObserver.observe(this.dom);
366
+ if (this.editorScrollableElement) {
367
+ this.resizeObserver.observe(this.editorScrollableElement);
368
+ }
363
369
  window.requestAnimationFrame(() => {
364
370
  var _this$tree;
365
371
  // we expect tree to be defined after animation frame
@@ -389,14 +395,21 @@ export class TableRowNodeView {
389
395
  table
390
396
  } = this.tree;
391
397
  entries.forEach(entry => {
392
- const newHeight = entry.contentRect ? entry.contentRect.height : entry.target.offsetHeight;
393
- if (this.sentinels.bottom &&
394
- // When the table header is sticky, it would be taller by a 1px (border-bottom),
395
- // So we adding this check to allow a 1px difference.
396
- Math.abs(newHeight - (this.stickyRowHeight || 0)) > stickyHeaderBorderBottomWidth) {
397
- this.stickyRowHeight = newHeight;
398
- this.sentinels.bottom.style.bottom = `${tableScrollbarOffset + stickyRowOffsetTop + newHeight}px`;
399
- updateTableMargin(table);
398
+ var _this$editorScrollabl;
399
+ // On resize of the parent scroll element we need to adjust the width
400
+ // of the sticky header
401
+ if (entry.target.className === ((_this$editorScrollabl = this.editorScrollableElement) === null || _this$editorScrollabl === void 0 ? void 0 : _this$editorScrollabl.className)) {
402
+ this.updateStickyHeaderWidth();
403
+ } else {
404
+ const newHeight = entry.contentRect ? entry.contentRect.height : entry.target.offsetHeight;
405
+ if (this.sentinels.bottom &&
406
+ // When the table header is sticky, it would be taller by a 1px (border-bottom),
407
+ // So we adding this check to allow a 1px difference.
408
+ Math.abs(newHeight - (this.stickyRowHeight || 0)) > stickyHeaderBorderBottomWidth) {
409
+ this.stickyRowHeight = newHeight;
410
+ this.sentinels.bottom.style.bottom = `${tableScrollbarOffset + stickyRowOffsetTop + newHeight}px`;
411
+ updateTableMargin(table);
412
+ }
400
413
  }
401
414
  });
402
415
  });
@@ -421,18 +434,20 @@ export class TableRowNodeView {
421
434
  var _entry$rootBounds2;
422
435
  const sentinelIsBelowScrollArea = (((_entry$rootBounds2 = entry.rootBounds) === null || _entry$rootBounds2 === void 0 ? void 0 : _entry$rootBounds2.bottom) || 0) < entry.boundingClientRect.bottom;
423
436
  if (!entry.isIntersecting && !sentinelIsBelowScrollArea) {
424
- this.tree && this.makeHeaderRowSticky(this.tree);
437
+ var _entry$rootBounds3;
438
+ this.tree && this.makeHeaderRowSticky(this.tree, (_entry$rootBounds3 = entry.rootBounds) === null || _entry$rootBounds3 === void 0 ? void 0 : _entry$rootBounds3.top);
425
439
  } else {
426
440
  table && this.makeRowHeaderNotSticky(table);
427
441
  }
428
442
  }
429
443
  if (target.classList.contains(ClassName.TABLE_STICKY_SENTINEL_BOTTOM)) {
430
- var _entry$rootBounds3;
431
- const sentinelIsAboveScrollArea = entry.boundingClientRect.top - this.dom.offsetHeight < (((_entry$rootBounds3 = entry.rootBounds) === null || _entry$rootBounds3 === void 0 ? void 0 : _entry$rootBounds3.top) || 0);
444
+ var _entry$rootBounds4;
445
+ const sentinelIsAboveScrollArea = entry.boundingClientRect.top - this.dom.offsetHeight < (((_entry$rootBounds4 = entry.rootBounds) === null || _entry$rootBounds4 === void 0 ? void 0 : _entry$rootBounds4.top) || 0);
432
446
  if (table && !entry.isIntersecting && sentinelIsAboveScrollArea) {
433
447
  this.makeRowHeaderNotSticky(table);
434
448
  } else if (entry.isIntersecting && sentinelIsAboveScrollArea) {
435
- this.tree && this.makeHeaderRowSticky(this.tree);
449
+ var _entry$rootBounds5;
450
+ this.tree && this.makeHeaderRowSticky(this.tree, entry === null || entry === void 0 ? void 0 : (_entry$rootBounds5 = entry.rootBounds) === null || _entry$rootBounds5 === void 0 ? void 0 : _entry$rootBounds5.top);
436
451
  }
437
452
  }
438
453
  });
@@ -9,7 +9,6 @@ import { evenColumns, setDragging, stopResizing } from './commands';
9
9
  import { getPluginState } from './plugin-factory';
10
10
  import { currentColWidth, getLayoutSize, getResizeState, pointsAtCell, resizeColumn, updateControls } from './utils';
11
11
  import { ACTION_SUBJECT, EVENT_TYPE, TABLE_ACTION } from '@atlaskit/editor-common/analytics';
12
- import { getParentWidthWithoutPadding } from './utils/misc';
13
12
  export const handleMouseDown = (view, event, localResizeHandlePos, getEditorContainerWidth, getEditorFeatureFlags, editorAnalyticsAPI) => {
14
13
  const {
15
14
  state,
@@ -32,10 +31,7 @@ export const handleMouseDown = (view, event, localResizeHandlePos, getEditorCont
32
31
  }
33
32
  const containerWidth = getEditorContainerWidth();
34
33
  const parentWidth = getParentNodeWidth(start, state, containerWidth);
35
-
36
- // TODO - refactor this logic into getParentNodeWidth() in editor-common [ED-16718]
37
- const parentActualWidth = getParentWidthWithoutPadding(parentWidth, start, state);
38
- let maxSize = parentActualWidth || getLayoutSize(dom.getAttribute('data-layout'), containerWidth.width, {});
34
+ let maxSize = parentWidth || getLayoutSize(dom.getAttribute('data-layout'), containerWidth.width, {});
39
35
  if (originalTable.attrs.isNumberColumnEnabled) {
40
36
  maxSize -= akEditorTableNumberColumnWidth;
41
37
  }
@@ -3,8 +3,6 @@ import { getBreakpoint, mapBreakpointToLayoutMaxWidth } from '@atlaskit/editor-c
3
3
  import { akEditorDefaultLayoutWidth, akEditorFullWidthLayoutWidth, akEditorGutterPadding, akEditorWideLayoutWidth, akEditorTableNumberColumnWidth } from '@atlaskit/editor-shared-styles';
4
4
  import { containsClassName } from '@atlaskit/editor-common/utils';
5
5
  import { getParentNodeWidth } from '@atlaskit/editor-common/node-width';
6
- import { gridSize } from '@atlaskit/theme/constants';
7
- import { findParentNodeOfTypeClosestToPos } from 'prosemirror-utils';
8
6
  export const tableLayoutToSize = {
9
7
  default: akEditorDefaultLayoutWidth,
10
8
  wide: akEditorWideLayoutWidth,
@@ -73,43 +71,9 @@ export const getTableMaxWidth = ({
73
71
  }) => {
74
72
  const containerWidth = getEditorContainerWidth();
75
73
  const parentWidth = getParentNodeWidth(tableStart, state, containerWidth);
76
-
77
- // TODO - refactor this logic into getParentNodeWidth() in editor-common [ED-16718]
78
- const parentActualWidth = getParentWidthWithoutPadding(parentWidth, tableStart, state);
79
- let maxWidth = parentActualWidth || getLayoutSize(layout, containerWidth.width, {});
74
+ let maxWidth = parentWidth || getLayoutSize(layout, containerWidth.width, {});
80
75
  if (table.attrs.isNumberColumnEnabled) {
81
76
  maxWidth -= akEditorTableNumberColumnWidth;
82
77
  }
83
78
  return maxWidth;
84
- };
85
- export const getParentWidthWithoutPadding = (parentWidth, tableStartPos, state) => {
86
- const node = getNestedParentNode(tableStartPos, state);
87
- if (!node) {
88
- return;
89
- }
90
- const {
91
- schema
92
- } = state;
93
- if (node.type === schema.nodes.expand) {
94
- // padding
95
- parentWidth -= gridSize() * 2;
96
- // gutter offset
97
- parentWidth += gridSize() * 1.5 * 2;
98
- // padding right
99
- parentWidth -= gridSize();
100
- // padding left
101
- parentWidth -= gridSize() * 4 - gridSize() / 2;
102
- }
103
- return parentWidth;
104
- };
105
-
106
- // copy of getNestedParentNode() from packages/editor/editor-common/src/node-width/index.ts
107
- // to be removed later when we will move getParentWidthWithoutPadding() logic to editor-common
108
- const getNestedParentNode = (tablePos, state) => {
109
- if (tablePos === undefined) {
110
- return null;
111
- }
112
- const $pos = state.doc.resolve(tablePos);
113
- const parent = findParentNodeOfTypeClosestToPos($pos, [state.schema.nodes.bodiedExtension, state.schema.nodes.layoutSection, state.schema.nodes.expand]);
114
- return parent ? parent.node : null;
115
79
  };
@@ -1,7 +1,7 @@
1
1
  import { Selection } from 'prosemirror-state';
2
2
  import { TableMap } from '@atlaskit/editor-tables/table-map';
3
3
  import { findTable } from '@atlaskit/editor-tables/utils';
4
- import { removeEmptyColumns } from './merge';
4
+ import { mergeEmptyColumns } from './merge';
5
5
  import { setMeta } from './metadata';
6
6
  export const deleteRows = (rect, isHeaderRowRequired = false) => tr => {
7
7
  const table = findTable(tr.selection);
@@ -96,7 +96,7 @@ export const deleteRows = (rect, isHeaderRowRequired = false) => tr => {
96
96
  })(tr);
97
97
  }
98
98
  const newTable = table.node.type.createChecked(table.node.attrs, rows, table.node.marks);
99
- const fixedTable = removeEmptyColumns(newTable);
99
+ const fixedTable = mergeEmptyColumns(newTable);
100
100
  if (fixedTable === null) {
101
101
  return setMeta({
102
102
  type: 'DELETE_ROWS',
@@ -1,5 +1,5 @@
1
- export { mergeCells, canMergeCells, removeEmptyColumns } from './merge';
2
1
  export { fireAnalytics, fixTables, fixAutoSizedTable } from './fix-tables';
2
+ export { mergeCells, canMergeCells, mergeEmptyColumns } from './merge';
3
3
  export { deleteColumns } from './delete-columns';
4
4
  export { deleteRows } from './delete-rows';
5
5
  export { updateColumnWidths } from './column-width';
@@ -113,7 +113,7 @@ export function mergeCells(tr) {
113
113
  })(tr);
114
114
  }
115
115
  const newTable = table.node.type.createChecked(table.node.attrs, rows, table.node.marks);
116
- const fixedTable = removeEmptyColumns(newTable);
116
+ const fixedTable = mergeEmptyColumns(newTable);
117
117
  if (fixedTable === null) {
118
118
  return setMeta({
119
119
  type: 'MERGE_CELLS',
@@ -188,70 +188,66 @@ function cellsOverlapRectangle({
188
188
  }
189
189
 
190
190
  // returns an array of numbers, each number indicates the minimum colSpan in each column
191
- function getMinColSpans(table) {
191
+ function getEmptyColumnIndexes(table) {
192
192
  const map = TableMap.get(table);
193
- const minColspans = [];
194
- for (let colIndex = map.width - 1; colIndex >= 0; colIndex--) {
195
- const cellsPositions = map.cellsInRect({
193
+ const emptyColumnIndexes = new Set();
194
+
195
+ // Loop throuh each column
196
+ for (let colIndex = 0; colIndex < map.width; colIndex++) {
197
+ // Get the cells in each row for this column
198
+ const cellPositions = map.cellsInRect({
196
199
  left: colIndex,
197
200
  right: colIndex + 1,
198
201
  top: 0,
199
202
  bottom: map.height
200
203
  });
201
- if (cellsPositions.length) {
202
- const colspans = cellsPositions.map(cellPos => {
203
- const cell = table.nodeAt(cellPos);
204
- if (cell) {
205
- return cell.attrs.colspan;
206
- }
207
- });
208
- const minColspan = Math.min(...colspans);
209
- // only care about the case when the next column is invisible
210
- if (!minColspans[colIndex + 1]) {
211
- minColspans[colIndex] = minColspan;
212
- } else {
213
- minColspans[colIndex] = 1;
214
- }
204
+
205
+ // If no cells exist in that column it is empty
206
+ if (!cellPositions.length) {
207
+ emptyColumnIndexes.add(colIndex);
215
208
  }
216
209
  }
217
- return minColspans;
210
+ return emptyColumnIndexes;
218
211
  }
219
- export function removeEmptyColumns(table) {
212
+ export function mergeEmptyColumns(table) {
213
+ const rows = [];
220
214
  const map = TableMap.get(table);
221
- const minColSpans = getMinColSpans(table);
222
- if (!minColSpans.some(colspan => colspan > 1)) {
215
+ const emptyColumnIndexes = getEmptyColumnIndexes(table);
216
+
217
+ // We don't need to remove any so return early.
218
+ if (emptyColumnIndexes.size === 0) {
223
219
  return table;
224
220
  }
225
- const rows = [];
226
221
  for (let rowIndex = 0; rowIndex < map.height; rowIndex++) {
227
222
  const cellsByCols = {};
228
- const cols = Object.keys(minColSpans).map(Number);
229
- for (let idx in cols) {
230
- const colIndex = cols[idx];
223
+
224
+ // Work backwards so that calculating colwidths is easier with Array.slice
225
+ for (let colIndex = map.width - 1; colIndex >= 0; colIndex--) {
231
226
  const cellPos = map.map[colIndex + rowIndex * map.width];
232
227
  const rect = map.findCell(cellPos);
233
- const cell = cellsByCols[rect.left] || table.nodeAt(cellPos);
234
- if (cell && rect.top === rowIndex) {
235
- if (minColSpans[colIndex] > 1) {
236
- const colspan = cell.attrs.colspan - minColSpans[colIndex] + 1;
237
- if (colspan < 1) {
238
- return null;
239
- }
240
- const {
241
- colwidth
242
- } = cell.attrs;
243
- const newCell = cell.type.createChecked({
228
+ let cell = cellsByCols[rect.left] || table.nodeAt(cellPos);
229
+ if (rect.top !== rowIndex) {
230
+ continue;
231
+ }
232
+
233
+ // If this column is empty, we want to decrement the colspan of its corresponding
234
+ // cell as this column is being "merged"
235
+ if (emptyColumnIndexes.has(colIndex)) {
236
+ const {
237
+ colspan,
238
+ colwidth
239
+ } = cell.attrs;
240
+ if (colspan > 1) {
241
+ cell = cell.type.createChecked({
244
242
  ...cell.attrs,
245
- colspan,
243
+ colspan: colspan - 1,
246
244
  colwidth: colwidth ? colwidth.slice(0, colspan) : null
247
245
  }, cell.content, cell.marks);
248
- cellsByCols[rect.left] = newCell;
249
- } else {
250
- cellsByCols[rect.left] = cell;
251
246
  }
252
247
  }
248
+ cellsByCols[rect.left] = cell;
253
249
  }
254
- const rowCells = Object.keys(cellsByCols).map(col => cellsByCols[col]);
250
+ const rowCells = Object.values(cellsByCols);
255
251
  const row = table.child(rowIndex);
256
252
  if (row) {
257
253
  rows.push(row.type.createChecked(row.attrs, rowCells, row.marks));
@@ -5,7 +5,7 @@ import { jsx } from '@emotion/react';
5
5
  import { splitCell } from '@atlaskit/editor-tables/utils';
6
6
  import { defineMessages, injectIntl } from 'react-intl-next';
7
7
  import { addColumnAfter, addRowAfter, backspace, tooltip } from '@atlaskit/editor-common/keymaps';
8
- import { ColorPalette, cellBackgroundColorPalette } from '@atlaskit/editor-common/ui-color';
8
+ import { ColorPalette, backgroundPaletteTooltipMessages, cellBackgroundColorPalette } from '@atlaskit/editor-common/ui-color';
9
9
  import { DropdownMenuSharedCssClassName } from '@atlaskit/editor-common/styles';
10
10
  import { ArrowKeyNavigationType, DropdownMenu } from '@atlaskit/editor-common/ui-menu';
11
11
  import { shortcutStyle } from '@atlaskit/editor-shared-styles/shortcut';
@@ -94,12 +94,16 @@ export class ContextualMenu extends Component {
94
94
  intl: {
95
95
  formatMessage
96
96
  },
97
- editorView
97
+ editorView,
98
+ getEditorFeatureFlags
98
99
  } = this.props;
99
100
  const items = [];
100
101
  const {
101
102
  isSubmenuOpen
102
103
  } = this.state;
104
+ const {
105
+ useSomewhatSemanticTextColorNames
106
+ } = getEditorFeatureFlags();
103
107
  // TargetCellPosition could be outdated: https://product-fabric.atlassian.net/browse/ED-8129
104
108
  const {
105
109
  targetCellPosition,
@@ -126,9 +130,19 @@ export class ContextualMenu extends Component {
126
130
  ref: this.handleSubMenuRef
127
131
  }, jsx(ColorPalette, {
128
132
  cols: 7,
129
- palette: cellBackgroundColorPalette,
130
133
  onClick: this.setColor,
131
- selectedColor: background
134
+ selectedColor: background,
135
+ paletteOptions: {
136
+ palette: cellBackgroundColorPalette,
137
+ paletteColorTooltipMessages: backgroundPaletteTooltipMessages,
138
+ // We did not want to create new FF or update
139
+ // useSomewhatSemanticTextColorNames name
140
+ // because it is temporary and require extra work.
141
+ // So even though it says text color names,
142
+ // we are going to use for all color pickers
143
+ // such as text, background and table charts.
144
+ showSomewhatSemanticTooltips: useSomewhatSemanticTextColorNames
145
+ }
132
146
  })))
133
147
  });
134
148
  }
@@ -34,7 +34,8 @@ const FloatingContextualMenu = ({
34
34
  isOpen,
35
35
  pluginConfig,
36
36
  editorAnalyticsAPI,
37
- getEditorContainerWidth
37
+ getEditorContainerWidth,
38
+ getEditorFeatureFlags
38
39
  }) => {
39
40
  // TargetCellPosition could be outdated: https://product-fabric.atlassian.net/browse/ED-8129
40
41
  const {
@@ -69,7 +70,8 @@ const FloatingContextualMenu = ({
69
70
  ,
70
71
  zIndex: akEditorFloatingOverlapPanelZIndex,
71
72
  forcePlacement: true,
72
- offset: [-7, 0]
73
+ offset: [-7, 0],
74
+ stick: true
73
75
  }, jsx("div", {
74
76
  css: tablePopupStyles
75
77
  }, jsx(ContextualMenu, {
@@ -83,7 +85,8 @@ const FloatingContextualMenu = ({
83
85
  selectionRect: selectionRect,
84
86
  boundariesElement: boundariesElement,
85
87
  editorAnalyticsAPI: editorAnalyticsAPI,
86
- getEditorContainerWidth: getEditorContainerWidth
88
+ getEditorContainerWidth: getEditorContainerWidth,
89
+ getEditorFeatureFlags: getEditorFeatureFlags
87
90
  })));
88
91
  };
89
92
  FloatingContextualMenu.displayName = 'FloatingContextualMenu';
@@ -47,7 +47,22 @@ const sentinelStyles = `.${ClassName.TABLE_CONTAINER} {
47
47
  }
48
48
  }
49
49
  }`;
50
-
50
+ const shadowSentinelStyles = `
51
+ .${ClassName.TABLE_SHADOW_SENTINEL_LEFT},
52
+ .${ClassName.TABLE_SHADOW_SENTINEL_RIGHT} {
53
+ position: absolute;
54
+ top: 0;
55
+ height: 100%;
56
+ width: 1px;
57
+ visibility: hidden;
58
+ }
59
+ .${ClassName.TABLE_SHADOW_SENTINEL_LEFT} {
60
+ left: 0;
61
+ }
62
+ .${ClassName.TABLE_SHADOW_SENTINEL_RIGHT} {
63
+ right: 0;
64
+ }
65
+ `;
51
66
  // previous styles to add spacing to numbered lists with
52
67
  // large item markers (e.g. 101, 102, ...) when nested inside tables
53
68
  const listLargeNumericMarkersOldStyles = `
@@ -532,6 +547,8 @@ export const tableStyles = props => {
532
547
  border-top: none;
533
548
  // 1px border width offset added here to prevent unwanted overflow and scolling - ED-16212
534
549
  margin-right: -1px;
550
+ // Allows better positioning for the shadow sentinels - ED-16668
551
+ position: relative;
535
552
 
536
553
  > tbody > tr {
537
554
  white-space: pre-wrap;
@@ -625,6 +642,7 @@ export const tableStyles = props => {
625
642
  padding-bottom: 0px;
626
643
  /* fixes gap cursor height */
627
644
  overflow: auto;
645
+ overflow-y: hidden;
628
646
  position: relative;
629
647
  }
630
648
  }
@@ -646,6 +664,8 @@ export const tableStyles = props => {
646
664
  throw away the older table-specific styles here.
647
665
  */
648
666
  ${props !== null && props !== void 0 && (_props$featureFlags2 = props.featureFlags) !== null && _props$featureFlags2 !== void 0 && _props$featureFlags2.restartNumberedLists ? `` : listLargeNumericMarkersOldStyles}
667
+
668
+ ${shadowSentinelStyles}
649
669
  `;
650
670
  };
651
671
  export const tableFullPageEditorStyles = css`
@@ -7,8 +7,9 @@ import { TableCssClassName as ClassName } from '../types';
7
7
  import { tableDeleteButtonSize } from '../ui/consts';
8
8
  export const getRowHeights = tableRef => {
9
9
  const heights = [];
10
- if (tableRef.lastChild) {
11
- const rows = tableRef.lastChild.childNodes;
10
+ const tableBody = tableRef.querySelector('tbody');
11
+ if (tableBody) {
12
+ const rows = tableBody.childNodes;
12
13
  for (let i = 0, count = rows.length; i < count; i++) {
13
14
  const row = rows[i];
14
15
  heights[i] = row.getBoundingClientRect().height + 1;
@@ -0,0 +1 @@
1
+ export {};
@@ -1,5 +1,5 @@
1
1
  {
2
2
  "name": "@atlaskit/editor-plugin-table",
3
- "version": "1.2.0",
3
+ "version": "1.2.2",
4
4
  "sideEffects": false
5
5
  }
@@ -0,0 +1,36 @@
1
+ /* prettier-ignore */
2
+ /**
3
+ * NOTE:
4
+ *
5
+ * This file is automatically generated by Traduki 2.0.
6
+ * DO NOT CHANGE IT BY HAND or your changes will be lost.
7
+ */
8
+ //
9
+ export default {
10
+ 'fabric.editor.canNotSortTable': "⚠️ You can't sort a table with merged cells",
11
+ 'fabric.editor.cellBackground': 'Cell background',
12
+ 'fabric.editor.cellOptions': 'Cell options',
13
+ 'fabric.editor.clearCells': 'Clear {0, plural, one {cell} other {cells}}',
14
+ 'fabric.editor.collapseTable': 'Collapse table',
15
+ 'fabric.editor.cornerControl': 'Highlight table',
16
+ 'fabric.editor.distributeColumns': 'Distribute columns',
17
+ 'fabric.editor.extension.confirmDeleteLinkedModalMessagePrefix': 'Deleting',
18
+ 'fabric.editor.extension.deleteElementTitle': 'Delete element',
19
+ 'fabric.editor.extension.sourceNoTitledName': 'this element',
20
+ 'fabric.editor.floatingToolbar.confirmModalCheckboxLabel': 'Also delete connected elements',
21
+ 'fabric.editor.headerColumn': 'Header column',
22
+ 'fabric.editor.headerRow': 'Header row',
23
+ 'fabric.editor.insertColumn': 'Insert column right',
24
+ 'fabric.editor.insertRow': 'Insert row below',
25
+ 'fabric.editor.mergeCells': 'Merge cells',
26
+ 'fabric.editor.numberedColumn': 'Numbered column',
27
+ 'fabric.editor.removeColumns': 'Delete {0, plural, one {column} other {columns}}',
28
+ 'fabric.editor.removeRows': 'Delete {0, plural, one {row} other {rows}}',
29
+ 'fabric.editor.rowControl': 'Highlight row',
30
+ 'fabric.editor.sortColumnASC': 'Sort column A → Z',
31
+ 'fabric.editor.sortColumnDESC': 'Sort column Z → A',
32
+ 'fabric.editor.splitCell': 'Split cell',
33
+ 'fabric.editor.tableOptions': 'Table options',
34
+ 'fabric.editor.tables.confirmDeleteLinkedModalMessage': 'Deleting {nodeName} will break anything connected to it.',
35
+ 'fabric.editor.tables.confirmDeleteLinkedModalOKButton': 'Delete'
36
+ };
@@ -0,0 +1,36 @@
1
+ /* prettier-ignore */
2
+ /**
3
+ * NOTE:
4
+ *
5
+ * This file is automatically generated by Traduki 2.0.
6
+ * DO NOT CHANGE IT BY HAND or your changes will be lost.
7
+ */
8
+ //English (United Kingdom)
9
+ export default {
10
+ 'fabric.editor.canNotSortTable': "⚠️ You can't sort a table with merged cells",
11
+ 'fabric.editor.cellBackground': 'Cell background',
12
+ 'fabric.editor.cellOptions': 'Cell options',
13
+ 'fabric.editor.clearCells': 'Clear {0, plural, one {cell} other {cells}}',
14
+ 'fabric.editor.collapseTable': 'Collapse table',
15
+ 'fabric.editor.cornerControl': 'Highlight table',
16
+ 'fabric.editor.distributeColumns': 'Distribute columns',
17
+ 'fabric.editor.extension.confirmDeleteLinkedModalMessagePrefix': 'Deleting',
18
+ 'fabric.editor.extension.deleteElementTitle': 'Delete element',
19
+ 'fabric.editor.extension.sourceNoTitledName': 'this element',
20
+ 'fabric.editor.floatingToolbar.confirmModalCheckboxLabel': 'Also delete connected elements',
21
+ 'fabric.editor.headerColumn': 'Header column',
22
+ 'fabric.editor.headerRow': 'Header row',
23
+ 'fabric.editor.insertColumn': 'Insert column right',
24
+ 'fabric.editor.insertRow': 'Insert row below',
25
+ 'fabric.editor.mergeCells': 'Merge cells',
26
+ 'fabric.editor.numberedColumn': 'Numbered column',
27
+ 'fabric.editor.removeColumns': 'Delete {0, plural, one {column} other {columns}}',
28
+ 'fabric.editor.removeRows': 'Delete {0, plural, one {row} other {rows}}',
29
+ 'fabric.editor.rowControl': 'Highlight row',
30
+ 'fabric.editor.sortColumnASC': 'Sort column A → Z',
31
+ 'fabric.editor.sortColumnDESC': 'Sort column Z → A',
32
+ 'fabric.editor.splitCell': 'Split cell',
33
+ 'fabric.editor.tableOptions': 'Table options',
34
+ 'fabric.editor.tables.confirmDeleteLinkedModalMessage': 'Deleting {nodeName} will break anything connected to it.',
35
+ 'fabric.editor.tables.confirmDeleteLinkedModalOKButton': 'Delete'
36
+ };
@@ -266,7 +266,8 @@ var tablesPlugin = function tablesPlugin(options) {
266
266
  isOpen: Boolean(isContextualMenuOpen),
267
267
  pluginConfig: pluginConfig,
268
268
  editorAnalyticsAPI: options === null || options === void 0 ? void 0 : options.editorAnalyticsAPI,
269
- getEditorContainerWidth: defaultGetEditorContainerWidth
269
+ getEditorContainerWidth: defaultGetEditorContainerWidth,
270
+ getEditorFeatureFlags: (options === null || options === void 0 ? void 0 : options.getEditorFeatureFlags) || defaultGetEditorFeatureFlags
270
271
  }), allowControls && /*#__PURE__*/React.createElement(FloatingDeleteButton, {
271
272
  editorView: editorView,
272
273
  selection: editorView.state.selection,
@@ -9,16 +9,9 @@ export var OverflowShadowsObserver = /*#__PURE__*/function () {
9
9
  function OverflowShadowsObserver(updateShadowState, _table, wrapper) {
10
10
  var _this = this;
11
11
  _classCallCheck(this, OverflowShadowsObserver);
12
- _defineProperty(this, "firstCell", null);
13
- _defineProperty(this, "lastCell", null);
14
- _defineProperty(this, "getFirstCell", function (isSticky, hasHeaderRow) {
15
- var _this$table;
16
- return (_this$table = _this.table) === null || _this$table === void 0 ? void 0 : _this$table.querySelector(isSticky || !hasHeaderRow ? 'table tbody tr td' : 'table tbody tr th');
17
- });
18
- _defineProperty(this, "getLastCell", function (isSticky, hasHeaderRow) {
19
- var _this$table2;
20
- return (_this$table2 = _this.table) === null || _this$table2 === void 0 ? void 0 : _this$table2.querySelector(isSticky || !hasHeaderRow ? 'table tbody tr td:last-child' : 'table tbody tr th:last-child');
21
- });
12
+ _defineProperty(this, "leftShadowSentinel", null);
13
+ _defineProperty(this, "rightShadowSentinel", null);
14
+ _defineProperty(this, "shadowsObserved", false);
22
15
  _defineProperty(this, "isSticky", false);
23
16
  _defineProperty(this, "stickyRowHeight", 0);
24
17
  _defineProperty(this, "init", function () {
@@ -32,11 +25,11 @@ export var OverflowShadowsObserver = /*#__PURE__*/function () {
32
25
  if (!((_entry$rootBounds = entry.rootBounds) !== null && _entry$rootBounds !== void 0 && _entry$rootBounds.height) && !((_entry$rootBounds2 = entry.rootBounds) !== null && _entry$rootBounds2 !== void 0 && _entry$rootBounds2.width)) {
33
26
  return;
34
27
  }
35
- if (entry.target !== _this.firstCell && entry.target !== _this.lastCell) {
28
+ if (entry.target !== _this.leftShadowSentinel && entry.target !== _this.rightShadowSentinel) {
36
29
  return;
37
30
  }
38
31
  _this.updateStickyShadowsHeightIfChanged();
39
- _this.checkIntersectionEvent(entry, _this.firstCell === entry.target ? ShadowEvent.SHOW_BEFORE_SHADOW : ShadowEvent.SHOW_AFTER_SHADOW);
32
+ _this.checkIntersectionEvent(entry, _this.leftShadowSentinel === entry.target ? ShadowEvent.SHOW_BEFORE_SHADOW : ShadowEvent.SHOW_AFTER_SHADOW);
40
33
  };
41
34
  _this.tableIntersectionObserver = new IntersectionObserver(function (entries, _) {
42
35
  entries.forEach(function (entry) {
@@ -61,25 +54,19 @@ export var OverflowShadowsObserver = /*#__PURE__*/function () {
61
54
  _this.updateShadowState(shadowKey, true);
62
55
  }
63
56
  });
64
- _defineProperty(this, "observeCells", function (isSticky, hasHeaderRow) {
65
- var stickyChanged = !!isSticky !== _this.isSticky;
57
+ _defineProperty(this, "observeShadowSentinels", function (isSticky) {
58
+ var _this$table, _this$table2;
66
59
  _this.isSticky = !!isSticky;
67
60
 
68
61
  // update sticky shadows
69
62
  _this.updateStickyShadowsHeightIfChanged();
70
- if (!stickyChanged) {
71
- var firstCell = _this.getFirstCell(isSticky, hasHeaderRow);
72
- var lastCell = _this.getLastCell(isSticky, hasHeaderRow);
73
- if (!firstCell || !lastCell || firstCell === _this.firstCell && lastCell === _this.lastCell) {
74
- return;
75
- }
76
- }
77
- _this.firstCell = _this.getFirstCell(isSticky, hasHeaderRow);
78
- _this.lastCell = _this.getLastCell(isSticky, hasHeaderRow);
79
- if (_this.tableIntersectionObserver && _this.firstCell && _this.lastCell) {
63
+ _this.leftShadowSentinel = (_this$table = _this.table) === null || _this$table === void 0 ? void 0 : _this$table.querySelector(".".concat(ClassName.TABLE_SHADOW_SENTINEL_LEFT));
64
+ _this.rightShadowSentinel = (_this$table2 = _this.table) === null || _this$table2 === void 0 ? void 0 : _this$table2.querySelector(".".concat(ClassName.TABLE_SHADOW_SENTINEL_RIGHT));
65
+ if (_this.tableIntersectionObserver && _this.leftShadowSentinel && _this.rightShadowSentinel && !_this.shadowsObserved) {
80
66
  _this.tableIntersectionObserver.disconnect();
81
- _this.tableIntersectionObserver.observe(_this.firstCell);
82
- _this.tableIntersectionObserver.observe(_this.lastCell);
67
+ _this.tableIntersectionObserver.observe(_this.leftShadowSentinel);
68
+ _this.tableIntersectionObserver.observe(_this.rightShadowSentinel);
69
+ _this.shadowsObserved = true;
83
70
  }
84
71
  });
85
72
  _defineProperty(this, "updateStickyShadows", function (stickyRowHeight) {