@atlaskit/editor-plugin-table 7.5.5 → 7.5.7

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 (100) hide show
  1. package/CHANGELOG.md +13 -0
  2. package/dist/cjs/commands/selection.js +23 -1
  3. package/dist/cjs/event-handlers.js +25 -9
  4. package/dist/cjs/nodeviews/OverflowShadowsObserver.js +24 -15
  5. package/dist/cjs/nodeviews/TableCell.js +5 -30
  6. package/dist/cjs/nodeviews/TableComponent.js +96 -41
  7. package/dist/cjs/nodeviews/TableContainer.js +19 -17
  8. package/dist/cjs/nodeviews/TableResizer.js +1 -1
  9. package/dist/cjs/plugin.js +2 -3
  10. package/dist/cjs/pm-plugins/main.js +3 -18
  11. package/dist/cjs/pm-plugins/sticky-headers/types.js +1 -5
  12. package/dist/cjs/pm-plugins/table-resizing/utils/colgroup.js +3 -7
  13. package/dist/cjs/pm-plugins/table-resizing/utils/misc.js +11 -1
  14. package/dist/cjs/pm-plugins/table-resizing/utils/resize-state.js +22 -23
  15. package/dist/cjs/pm-plugins/table-resizing/utils/scale-table.js +2 -2
  16. package/dist/cjs/pm-plugins/table-selection-keymap.js +3 -0
  17. package/dist/cjs/ui/TableFloatingColumnControls/index.js +8 -48
  18. package/dist/cjs/ui/TableFloatingControls/index.js +113 -223
  19. package/dist/cjs/utils/column-controls.js +5 -5
  20. package/dist/cjs/utils/dom.js +13 -15
  21. package/dist/es2019/commands/selection.js +22 -0
  22. package/dist/es2019/event-handlers.js +25 -9
  23. package/dist/es2019/nodeviews/OverflowShadowsObserver.js +24 -15
  24. package/dist/es2019/nodeviews/TableCell.js +1 -24
  25. package/dist/es2019/nodeviews/TableComponent.js +69 -31
  26. package/dist/es2019/nodeviews/TableContainer.js +16 -18
  27. package/dist/es2019/nodeviews/TableResizer.js +1 -1
  28. package/dist/es2019/plugin.js +2 -3
  29. package/dist/es2019/pm-plugins/main.js +3 -18
  30. package/dist/es2019/pm-plugins/sticky-headers/types.js +0 -1
  31. package/dist/es2019/pm-plugins/table-resizing/utils/colgroup.js +3 -7
  32. package/dist/es2019/pm-plugins/table-resizing/utils/misc.js +10 -0
  33. package/dist/es2019/pm-plugins/table-resizing/utils/resize-state.js +21 -22
  34. package/dist/es2019/pm-plugins/table-resizing/utils/scale-table.js +2 -2
  35. package/dist/es2019/pm-plugins/table-selection-keymap.js +5 -2
  36. package/dist/es2019/ui/TableFloatingColumnControls/index.js +5 -27
  37. package/dist/es2019/ui/TableFloatingControls/index.js +119 -193
  38. package/dist/es2019/utils/column-controls.js +6 -6
  39. package/dist/es2019/utils/dom.js +13 -15
  40. package/dist/esm/commands/selection.js +22 -0
  41. package/dist/esm/event-handlers.js +25 -9
  42. package/dist/esm/nodeviews/OverflowShadowsObserver.js +24 -15
  43. package/dist/esm/nodeviews/TableCell.js +5 -30
  44. package/dist/esm/nodeviews/TableComponent.js +96 -41
  45. package/dist/esm/nodeviews/TableContainer.js +20 -18
  46. package/dist/esm/nodeviews/TableResizer.js +1 -1
  47. package/dist/esm/plugin.js +2 -3
  48. package/dist/esm/pm-plugins/main.js +3 -18
  49. package/dist/esm/pm-plugins/sticky-headers/types.js +0 -1
  50. package/dist/esm/pm-plugins/table-resizing/utils/colgroup.js +3 -7
  51. package/dist/esm/pm-plugins/table-resizing/utils/misc.js +10 -0
  52. package/dist/esm/pm-plugins/table-resizing/utils/resize-state.js +23 -24
  53. package/dist/esm/pm-plugins/table-resizing/utils/scale-table.js +2 -2
  54. package/dist/esm/pm-plugins/table-selection-keymap.js +5 -2
  55. package/dist/esm/ui/TableFloatingColumnControls/index.js +8 -48
  56. package/dist/esm/ui/TableFloatingControls/index.js +113 -224
  57. package/dist/esm/utils/column-controls.js +6 -6
  58. package/dist/esm/utils/dom.js +13 -15
  59. package/dist/types/commands/selection.d.ts +1 -0
  60. package/dist/types/event-handlers.d.ts +3 -4
  61. package/dist/types/nodeviews/OverflowShadowsObserver.d.ts +3 -1
  62. package/dist/types/nodeviews/TableCell.d.ts +1 -5
  63. package/dist/types/nodeviews/TableComponent.d.ts +4 -0
  64. package/dist/types/nodeviews/TableContainer.d.ts +4 -2
  65. package/dist/types/pm-plugins/table-resizing/utils/misc.d.ts +1 -0
  66. package/dist/types/types.d.ts +0 -3
  67. package/dist/types/ui/TableFloatingColumnControls/index.d.ts +2 -1
  68. package/dist/types/ui/TableFloatingControls/index.d.ts +5 -22
  69. package/dist/types/utils/dom.d.ts +10 -2
  70. package/dist/types-ts4.5/commands/selection.d.ts +1 -0
  71. package/dist/types-ts4.5/event-handlers.d.ts +3 -4
  72. package/dist/types-ts4.5/nodeviews/OverflowShadowsObserver.d.ts +3 -1
  73. package/dist/types-ts4.5/nodeviews/TableCell.d.ts +1 -5
  74. package/dist/types-ts4.5/nodeviews/TableComponent.d.ts +4 -0
  75. package/dist/types-ts4.5/nodeviews/TableContainer.d.ts +4 -2
  76. package/dist/types-ts4.5/pm-plugins/table-resizing/utils/misc.d.ts +1 -0
  77. package/dist/types-ts4.5/types.d.ts +0 -3
  78. package/dist/types-ts4.5/ui/TableFloatingColumnControls/index.d.ts +2 -1
  79. package/dist/types-ts4.5/ui/TableFloatingControls/index.d.ts +5 -22
  80. package/dist/types-ts4.5/utils/dom.d.ts +10 -2
  81. package/package.json +8 -6
  82. package/src/commands/selection.ts +33 -0
  83. package/src/event-handlers.ts +105 -103
  84. package/src/nodeviews/OverflowShadowsObserver.ts +32 -21
  85. package/src/nodeviews/TableCell.ts +0 -26
  86. package/src/nodeviews/TableComponent.tsx +81 -34
  87. package/src/nodeviews/TableContainer.tsx +19 -25
  88. package/src/nodeviews/TableResizer.tsx +1 -4
  89. package/src/plugin.tsx +5 -4
  90. package/src/pm-plugins/main.ts +3 -22
  91. package/src/pm-plugins/table-resizing/utils/colgroup.ts +3 -6
  92. package/src/pm-plugins/table-resizing/utils/misc.ts +13 -0
  93. package/src/pm-plugins/table-resizing/utils/resize-state.ts +22 -28
  94. package/src/pm-plugins/table-resizing/utils/scale-table.ts +3 -10
  95. package/src/pm-plugins/table-selection-keymap.ts +10 -0
  96. package/src/types.ts +0 -4
  97. package/src/ui/TableFloatingColumnControls/index.tsx +5 -29
  98. package/src/ui/TableFloatingControls/index.tsx +155 -241
  99. package/src/utils/column-controls.ts +5 -6
  100. package/src/utils/dom.ts +12 -19
@@ -1,3 +1,5 @@
1
+ import rafSchedule from 'raf-schd';
2
+
1
3
  import { getBooleanFF } from '@atlaskit/platform-feature-flags';
2
4
 
3
5
  import { TableCssClassName as ClassName, ShadowEvent } from '../types';
@@ -82,11 +84,8 @@ export class OverflowShadowsObserver {
82
84
  if (!stickyCell) {
83
85
  return;
84
86
  }
85
- const newStickyRowHeight = stickyCell.clientHeight + 1;
86
- if (newStickyRowHeight! === this.stickyRowHeight) {
87
- this.stickyRowHeight = newStickyRowHeight;
88
- this.updateStickyShadows(this.stickyRowHeight);
89
- }
87
+
88
+ this.updateStickyShadows();
90
89
  }
91
90
 
92
91
  private getStickyCell() {
@@ -96,8 +95,14 @@ export class OverflowShadowsObserver {
96
95
  }
97
96
 
98
97
  observeShadowSentinels = (isSticky?: boolean) => {
98
+ if (this.isSticky === isSticky) {
99
+ return;
100
+ }
101
+
99
102
  this.isSticky = !!isSticky;
100
103
 
104
+ // reset height
105
+ this.stickyRowHeight = 0;
101
106
  // update sticky shadows
102
107
  this.updateStickyShadowsHeightIfChanged();
103
108
 
@@ -126,7 +131,7 @@ export class OverflowShadowsObserver {
126
131
  * e.g. bounds on an IntersectionObserverEntry, otherwise proceed with
127
132
  * reading it from sticky cell
128
133
  */
129
- updateStickyShadows = (stickyRowHeight?: number) => {
134
+ updateStickyShadows = rafSchedule((stickyRowHeight?: number) => {
130
135
  if (!this.isSticky) {
131
136
  return;
132
137
  }
@@ -134,21 +139,27 @@ export class OverflowShadowsObserver {
134
139
  if (!stickyCell || !this.wrapper?.parentElement) {
135
140
  return;
136
141
  }
137
- const heightStyleOrCompute = `${
138
- stickyRowHeight || stickyCell.clientHeight + 1
139
- }px`;
140
- // Use getElementsByClassName here for a live node list to capture
141
- // sticky shadows
142
- const liveRightShadows =
143
- this.wrapper?.parentElement?.getElementsByClassName(
144
- `${ClassName.TABLE_RIGHT_SHADOW}`,
145
- );
146
- const liveLeftShadows = this.wrapper?.parentElement?.getElementsByClassName(
147
- `${ClassName.TABLE_LEFT_SHADOW}`,
148
- );
149
- updateShadowListForStickyStyles(heightStyleOrCompute, liveLeftShadows);
150
- updateShadowListForStickyStyles(heightStyleOrCompute, liveRightShadows);
151
- };
142
+
143
+ // Reflow Warning! - stickyCell.clientHeight
144
+ const newStickyRowHeight = stickyRowHeight || stickyCell.clientHeight + 1;
145
+
146
+ if (newStickyRowHeight !== this.stickyRowHeight) {
147
+ this.stickyRowHeight = newStickyRowHeight;
148
+ const heightStyleOrCompute = `${newStickyRowHeight}px`;
149
+ // Use getElementsByClassName here for a live node list to capture
150
+ // sticky shadows
151
+ const liveRightShadows =
152
+ this.wrapper?.parentElement?.getElementsByClassName(
153
+ `${ClassName.TABLE_RIGHT_SHADOW}`,
154
+ );
155
+ const liveLeftShadows =
156
+ this.wrapper?.parentElement?.getElementsByClassName(
157
+ `${ClassName.TABLE_LEFT_SHADOW}`,
158
+ );
159
+ updateShadowListForStickyStyles(heightStyleOrCompute, liveLeftShadows);
160
+ updateShadowListForStickyStyles(heightStyleOrCompute, liveRightShadows);
161
+ }
162
+ });
152
163
 
153
164
  dispose() {
154
165
  if (this.tableIntersectionObserver) {
@@ -1,13 +1,9 @@
1
- import uuid from 'uuid';
2
-
3
1
  import type { CellDomAttrs } from '@atlaskit/adf-schema';
4
2
  import { getCellAttrs, getCellDomAttrs } from '@atlaskit/adf-schema';
5
3
  import type { EventDispatcher } from '@atlaskit/editor-common/event-dispatcher';
6
4
  import type { Node as PMNode } from '@atlaskit/editor-prosemirror/model';
7
5
  import type { EditorView, NodeView } from '@atlaskit/editor-prosemirror/view';
8
6
 
9
- import { getPluginState } from '../pm-plugins/plugin-factory';
10
-
11
7
  import TableNodeView from './TableNodeViewBase';
12
8
 
13
9
  const DEFAULT_COL_SPAN = 1;
@@ -22,26 +18,10 @@ export default class TableCell
22
18
  view: EditorView,
23
19
  getPos: () => number | undefined,
24
20
  eventDispatcher: EventDispatcher,
25
- private readonly observer?: ResizeObserver,
26
21
  ) {
27
22
  super(node, view, getPos, eventDispatcher);
28
-
29
- const { pluginConfig, isDragAndDropEnabled } = getPluginState(view.state);
30
-
31
- this.isStickyHeaderEnabled = !!pluginConfig.stickyHeaders;
32
- this.isDragAndDropEnabled = !!isDragAndDropEnabled;
33
-
34
- if (observer) {
35
- this.contentDOM.id = uuid();
36
- observer.observe(this.contentDOM);
37
- }
38
23
  }
39
24
 
40
- // @ts-ignore
41
- private isStickyHeaderEnabled: boolean;
42
- // @ts-ignore
43
- private isDragAndDropEnabled: boolean;
44
-
45
25
  update(node: PMNode) {
46
26
  const didUpdate = this.updateNodeView(node);
47
27
  if (didUpdate) {
@@ -50,12 +30,6 @@ export default class TableCell
50
30
  return didUpdate;
51
31
  }
52
32
 
53
- destroy() {
54
- if (this.observer) {
55
- this.observer.unobserve(this.contentDOM);
56
- }
57
- }
58
-
59
33
  private updateNodeView(node: PMNode) {
60
34
  if (this.node.type !== node.type) {
61
35
  return false;
@@ -84,6 +84,12 @@ const isIE11 = browser.ie_version === 11;
84
84
  // To make sure we capture the last update, we use setTimeout.
85
85
  const initialOverflowCaptureTimeroutDelay = 300;
86
86
 
87
+ // This is a hard switch for controlling whether the overflow analytics should be dispatched. There has been 6months of data
88
+ // already collected which we could use but have not. This has been disabled rather then removed entirely in the event that
89
+ // the current collected data becomes stale and we want to start collecting fresh data again in future.
90
+ // PLEASE NOTE: that the current way this alaytics has been configured WILL cause reflows to occur. This is why the has been disabled.
91
+ const isOverflowAnalyticsEnabled = false;
92
+
87
93
  export interface ComponentProps {
88
94
  view: EditorView;
89
95
  getNode: () => PmNode;
@@ -114,6 +120,8 @@ interface TableState {
114
120
  stickyHeader?: RowStickyState;
115
121
  [ShadowEvent.SHOW_BEFORE_SHADOW]: boolean;
116
122
  [ShadowEvent.SHOW_AFTER_SHADOW]: boolean;
123
+ tableWrapperWidth?: number;
124
+ tableWrapperHeight?: number;
117
125
  }
118
126
 
119
127
  class TableComponent extends React.Component<ComponentProps, TableState> {
@@ -124,6 +132,8 @@ class TableComponent extends React.Component<ComponentProps, TableState> {
124
132
  parentWidth: undefined,
125
133
  [ShadowEvent.SHOW_BEFORE_SHADOW]: false,
126
134
  [ShadowEvent.SHOW_AFTER_SHADOW]: false,
135
+ tableWrapperWidth: undefined,
136
+ tableWrapperHeight: undefined,
127
137
  };
128
138
 
129
139
  private wrapper?: HTMLDivElement | null;
@@ -136,6 +146,7 @@ class TableComponent extends React.Component<ComponentProps, TableState> {
136
146
 
137
147
  private isInitialOverflowSent: boolean;
138
148
  private initialOverflowCaptureTimerId?: ReturnType<typeof setTimeout>;
149
+ private resizeObserver?: ResizeObserver;
139
150
 
140
151
  private dragAndDropCleanupFn?: CleanupFn;
141
152
 
@@ -158,6 +169,21 @@ class TableComponent extends React.Component<ComponentProps, TableState> {
158
169
  },
159
170
  );
160
171
 
172
+ this.resizeObserver = new ResizeObserver((entries) => {
173
+ for (let entry of entries) {
174
+ this.setState((prev) => {
175
+ return prev?.tableWrapperWidth === entry.contentRect?.width &&
176
+ prev?.tableWrapperHeight === entry.contentRect?.height
177
+ ? prev
178
+ : {
179
+ ...prev,
180
+ tableWrapperWidth: entry.contentRect.width,
181
+ tableWrapperHeight: entry.contentRect.height,
182
+ };
183
+ });
184
+ }
185
+ });
186
+
161
187
  // Disable inline table editing and resizing controls in Firefox
162
188
  // https://github.com/ProseMirror/prosemirror/issues/432
163
189
  if ('execCommand' in document) {
@@ -231,11 +257,13 @@ class TableComponent extends React.Component<ComponentProps, TableState> {
231
257
 
232
258
  eventDispatcher.on((stickyHeadersPluginKey as any).key, this.onStickyState);
233
259
 
234
- const initialIsOveflowing =
235
- this.state[ShadowEvent.SHOW_BEFORE_SHADOW] ||
236
- this.state[ShadowEvent.SHOW_AFTER_SHADOW];
260
+ if (isOverflowAnalyticsEnabled) {
261
+ const initialIsOveflowing =
262
+ this.state[ShadowEvent.SHOW_BEFORE_SHADOW] ||
263
+ this.state[ShadowEvent.SHOW_AFTER_SHADOW];
237
264
 
238
- this.setTimerToSendInitialOverflowCaptured(initialIsOveflowing);
265
+ this.setTimerToSendInitialOverflowCaptured(initialIsOveflowing);
266
+ }
239
267
  }
240
268
 
241
269
  componentWillUnmount() {
@@ -254,6 +282,8 @@ class TableComponent extends React.Component<ComponentProps, TableState> {
254
282
  this.dragAndDropCleanupFn();
255
283
  }
256
284
 
285
+ this.resizeObserver?.disconnect();
286
+
257
287
  const { stickyScrollbar } = getEditorFeatureFlags();
258
288
 
259
289
  if (stickyScrollbar) {
@@ -308,7 +338,7 @@ class TableComponent extends React.Component<ComponentProps, TableState> {
308
338
  return;
309
339
  }
310
340
 
311
- const { width: tableNodeWidth } = tableNode.attrs;
341
+ const tableNodeWidth = getTableContainerWidth(tableNode);
312
342
  const shouldTableScale = tableRenderWidth < tableNodeWidth;
313
343
 
314
344
  const { width: containerWidthValue } = containerWidth;
@@ -325,7 +355,10 @@ class TableComponent extends React.Component<ComponentProps, TableState> {
325
355
  isTableScalingEnabled: true,
326
356
  });
327
357
 
328
- updateColgroup(resizeState, this.table!, tableNode, true);
358
+ // Request animation frame required for Firefox
359
+ requestAnimationFrame(() => {
360
+ updateColgroup(resizeState, this.table!, tableNode, true);
361
+ });
329
362
  }
330
363
  this.containerWidth = containerWidth;
331
364
  }
@@ -418,38 +451,42 @@ class TableComponent extends React.Component<ComponentProps, TableState> {
418
451
 
419
452
  this.handleTableResizingDebounced();
420
453
  }
454
+ if (isOverflowAnalyticsEnabled) {
455
+ const newIsOverflowing =
456
+ this.state[ShadowEvent.SHOW_BEFORE_SHADOW] ||
457
+ this.state[ShadowEvent.SHOW_AFTER_SHADOW];
421
458
 
422
- const newIsOverflowing =
423
- this.state[ShadowEvent.SHOW_BEFORE_SHADOW] ||
424
- this.state[ShadowEvent.SHOW_AFTER_SHADOW];
425
-
426
- const prevIsOverflowing =
427
- prevState[ShadowEvent.SHOW_BEFORE_SHADOW] ||
428
- prevState[ShadowEvent.SHOW_AFTER_SHADOW];
459
+ const prevIsOverflowing =
460
+ prevState[ShadowEvent.SHOW_BEFORE_SHADOW] ||
461
+ prevState[ShadowEvent.SHOW_AFTER_SHADOW];
429
462
 
430
- if (this.initialOverflowCaptureTimerId) {
431
- clearTimeout(this.initialOverflowCaptureTimerId);
432
- }
433
-
434
- if (!this.isInitialOverflowSent) {
435
- this.setTimerToSendInitialOverflowCaptured(newIsOverflowing);
436
- }
463
+ if (this.initialOverflowCaptureTimerId) {
464
+ clearTimeout(this.initialOverflowCaptureTimerId);
465
+ }
437
466
 
438
- if (this.isInitialOverflowSent && prevIsOverflowing !== newIsOverflowing) {
439
- const {
440
- dispatch,
441
- state: { tr },
442
- } = this.props.view;
467
+ if (!this.isInitialOverflowSent) {
468
+ this.setTimerToSendInitialOverflowCaptured(newIsOverflowing);
469
+ }
443
470
 
444
- dispatch(
445
- tr.setMeta(META_KEYS.OVERFLOW_STATE_CHANGED, {
446
- isOverflowing: newIsOverflowing,
447
- wasOverflowing: prevIsOverflowing,
448
- editorWidth: this.props.containerWidth.width || 0,
449
- width: this.node.attrs.width || 0,
450
- parentWidth: this.state?.parentWidth || 0,
451
- }),
452
- );
471
+ if (
472
+ this.isInitialOverflowSent &&
473
+ prevIsOverflowing !== newIsOverflowing
474
+ ) {
475
+ const {
476
+ dispatch,
477
+ state: { tr },
478
+ } = this.props.view;
479
+
480
+ dispatch(
481
+ tr.setMeta(META_KEYS.OVERFLOW_STATE_CHANGED, {
482
+ isOverflowing: newIsOverflowing,
483
+ wasOverflowing: prevIsOverflowing,
484
+ editorWidth: this.props.containerWidth.width || 0,
485
+ width: this.node.attrs.width || 0,
486
+ parentWidth: this.state?.parentWidth || 0,
487
+ }),
488
+ );
489
+ }
453
490
  }
454
491
  }
455
492
 
@@ -471,6 +508,12 @@ class TableComponent extends React.Component<ComponentProps, TableState> {
471
508
  }
472
509
  };
473
510
 
511
+ private observeTable(table: HTMLTableElement | null) {
512
+ if (table) {
513
+ this.resizeObserver?.observe(table);
514
+ }
515
+ }
516
+
474
517
  onStickyState = (state: StickyPluginState) => {
475
518
  const pos = this.props.getPos();
476
519
  if (!isValidPosition(pos, this.props.view.state)) {
@@ -539,6 +582,7 @@ class TableComponent extends React.Component<ComponentProps, TableState> {
539
582
  selection={view.state.selection}
540
583
  headerRowHeight={headerRow ? headerRow.offsetHeight : undefined}
541
584
  stickyHeader={this.state.stickyHeader}
585
+ tableWrapperWidth={this.state.tableWrapperWidth}
542
586
  />
543
587
  );
544
588
  const tableContainerWidth = getTableContainerWidth(node);
@@ -563,6 +607,7 @@ class TableComponent extends React.Component<ComponentProps, TableState> {
563
607
  tableContainerWidth={tableContainerWidth}
564
608
  isNumberColumnEnabled={node.attrs.isNumberColumnEnabled}
565
609
  getScrollOffset={() => this.wrapper?.scrollLeft || 0}
610
+ tableWrapperHeight={this.state.tableWrapperHeight}
566
611
  />
567
612
  ) : null;
568
613
 
@@ -615,6 +660,7 @@ class TableComponent extends React.Component<ComponentProps, TableState> {
615
660
  isBreakoutEnabled={options?.isBreakoutEnabled}
616
661
  isNested={isNested}
617
662
  pluginInjectionApi={pluginInjectionApi}
663
+ tableWrapperHeight={this.state.tableWrapperHeight}
618
664
  isTableResizingEnabled={options?.isTableResizingEnabled}
619
665
  isResizing={isResizing}
620
666
  isTableScalingEnabled={isTableScalingEnabled}
@@ -668,6 +714,7 @@ class TableComponent extends React.Component<ComponentProps, TableState> {
668
714
  if (tableElement !== this.table) {
669
715
  this.table = tableElement;
670
716
  this.createShadowSentinels(this.table);
717
+ this.observeTable(this.table);
671
718
  }
672
719
  }
673
720
  }}
@@ -1,5 +1,5 @@
1
1
  import type { PropsWithChildren } from 'react';
2
- import React, { forwardRef, useCallback, useRef } from 'react';
2
+ import React, { forwardRef, useCallback, useRef, useState } from 'react';
3
3
 
4
4
  import classNames from 'classnames';
5
5
 
@@ -78,6 +78,7 @@ type ResizableTableContainerProps = {
78
78
  isResizing?: boolean;
79
79
  pluginInjectionApi?: PluginInjectionAPI;
80
80
  isTableScalingEnabled?: boolean;
81
+ tableWrapperHeight?: number;
81
82
  };
82
83
 
83
84
  export const ResizableTableContainer = React.memo(
@@ -92,9 +93,11 @@ export const ResizableTableContainer = React.memo(
92
93
  isResizing,
93
94
  pluginInjectionApi,
94
95
  isTableScalingEnabled,
96
+ tableWrapperHeight,
95
97
  }: PropsWithChildren<ResizableTableContainerProps>) => {
96
98
  const containerRef = useRef<HTMLDivElement | null>(null);
97
99
  const tableWidthRef = useRef<number>(akEditorDefaultLayoutWidth);
100
+ const [resizing, setIsResizing] = useState(false);
98
101
 
99
102
  const updateContainerHeight = useCallback((height: number | 'auto') => {
100
103
  // current StickyHeader State is not stable to be fetch.
@@ -108,41 +111,26 @@ export const ResizableTableContainer = React.memo(
108
111
  // 1px is border width but collapse make it 0.5.
109
112
  // -- When sticky header appear, we should add first row height but reduce
110
113
  // collapsed border
111
- containerRef.current?.style.setProperty(
112
- 'height',
113
- typeof height === 'number' ? `${height + 40.5}px` : 'auto',
114
- );
114
+ return typeof height === 'number' ? `${height + 40.5}px` : 'auto';
115
115
  } else {
116
116
  const stickyHeaderHeight =
117
117
  containerRef.current
118
118
  ?.getElementsByTagName('th')[0]
119
119
  .getBoundingClientRect().height || 0;
120
- containerRef.current?.style.setProperty(
121
- 'height',
122
- typeof height === 'number'
123
- ? `${height + stickyHeaderHeight + 39.5}px`
124
- : 'auto',
125
- );
120
+
121
+ return typeof height === 'number'
122
+ ? `${height + stickyHeaderHeight + 39.5}px`
123
+ : 'auto';
126
124
  }
127
125
  }, []);
128
126
 
129
- const resizeObserverRef = useRef(
130
- new ResizeObserver((entries) => {
131
- updateContainerHeight(entries[entries.length - 1].contentRect.height);
132
- }),
133
- );
134
-
135
127
  const onResizeStart = useCallback(() => {
136
- if (tableRef) {
137
- resizeObserverRef.current.observe(tableRef);
138
- }
139
- }, [tableRef]);
128
+ setIsResizing(true);
129
+ }, []);
140
130
 
141
131
  const onResizeStop = useCallback(() => {
142
- updateContainerHeight('auto');
143
-
144
- resizeObserverRef.current.disconnect();
145
- }, [updateContainerHeight]);
132
+ setIsResizing(false);
133
+ }, []);
146
134
 
147
135
  const updateWidth = useCallback((width: number) => {
148
136
  if (!containerRef.current) {
@@ -239,6 +227,9 @@ export const ResizableTableContainer = React.memo(
239
227
  <div
240
228
  style={{
241
229
  width: tableWidthRef.current,
230
+ height: resizing
231
+ ? updateContainerHeight(tableWrapperHeight ?? 'auto')
232
+ : 'auto',
242
233
  }}
243
234
  className={ClassName.TABLE_RESIZER_CONTAINER}
244
235
  ref={containerRef}
@@ -267,6 +258,7 @@ type TableContainerProps = {
267
258
  isResizing?: boolean;
268
259
  pluginInjectionApi?: PluginInjectionAPI;
269
260
  isTableScalingEnabled?: boolean;
261
+ tableWrapperHeight?: number;
270
262
  };
271
263
 
272
264
  export const TableContainer = ({
@@ -280,6 +272,7 @@ export const TableContainer = ({
280
272
  getPos,
281
273
  tableRef,
282
274
  isNested,
275
+ tableWrapperHeight,
283
276
  isResizing,
284
277
  pluginInjectionApi,
285
278
  isTableScalingEnabled,
@@ -293,6 +286,7 @@ export const TableContainer = ({
293
286
  editorView={editorView}
294
287
  getPos={getPos}
295
288
  tableRef={tableRef}
289
+ tableWrapperHeight={tableWrapperHeight}
296
290
  isResizing={isResizing}
297
291
  pluginInjectionApi={pluginInjectionApi}
298
292
  isTableScalingEnabled={isTableScalingEnabled}
@@ -125,10 +125,7 @@ const getResizerHandleHeight = (
125
125
 
126
126
  const getResizerMinWidth = (node: PMNode) => {
127
127
  const currentColumnCount = getColgroupChildrenLength(node);
128
- const minColumnWidth =
129
- currentColumnCount <= 3
130
- ? currentColumnCount * COLUMN_MIN_WIDTH
131
- : 3 * COLUMN_MIN_WIDTH;
128
+ const minColumnWidth = Math.min(3, currentColumnCount) * COLUMN_MIN_WIDTH;
132
129
  // add an extra pixel as the scale table logic will scale columns to be tableContainerWidth - 1
133
130
  // the table can't scale past its min-width, so instead restrict table container min width to avoid that situation
134
131
  return minColumnWidth + 1;
package/src/plugin.tsx CHANGED
@@ -135,10 +135,11 @@ export type TablePlugin = NextEditorPlugin<
135
135
  const tablesPlugin: TablePlugin = ({ config: options, api }) => {
136
136
  const editorViewRef: Record<'current', EditorView | null> = { current: null };
137
137
  const defaultGetEditorContainerWidth: GetEditorContainerWidth = () => {
138
- const defaultState = {
139
- width: document?.body?.offsetWidth ?? 500,
140
- };
141
- return api?.width?.sharedState.currentState() ?? defaultState;
138
+ return (
139
+ api?.width?.sharedState.currentState() ?? {
140
+ width: document?.body?.offsetWidth ?? 500,
141
+ }
142
+ );
142
143
  };
143
144
  const editorAnalyticsAPI = api?.analytics?.actions;
144
145
 
@@ -77,7 +77,6 @@ import TableRow from '../nodeviews/TableRow';
77
77
  import { pluginKey as decorationsPluginKey } from '../pm-plugins/decorations/plugin';
78
78
  import { fixTables, replaceSelectedTable } from '../transforms';
79
79
  import type {
80
- ElementContentRects,
81
80
  InvalidNodeAttr,
82
81
  PluginConfig,
83
82
  PluginInjectionAPI,
@@ -134,19 +133,6 @@ export const createPlugin = (
134
133
  getIntl,
135
134
  });
136
135
 
137
- let elementContentRects: ElementContentRects = {};
138
-
139
- const observer = window?.ResizeObserver
140
- ? new ResizeObserver((entries) => {
141
- entries.forEach((entry) => {
142
- if (!entry.target.id) {
143
- return;
144
- }
145
- elementContentRects[entry.target.id] = entry.contentRect;
146
- });
147
- })
148
- : undefined;
149
-
150
136
  // Used to prevent invalid table cell spans being reported more than once per editor/document
151
137
  const invalidTableIds: string[] = [];
152
138
  let editorViewRef: EditorView | null = null;
@@ -282,11 +268,6 @@ export const createPlugin = (
282
268
  removeResizeHandleDecorations()(state, dispatch);
283
269
  }
284
270
  },
285
- destroy: () => {
286
- if (observer) {
287
- observer.disconnect();
288
- }
289
- },
290
271
  };
291
272
  },
292
273
  props: {
@@ -417,9 +398,9 @@ export const createPlugin = (
417
398
  tableRow: (node, view, getPos) =>
418
399
  new TableRow(node, view, getPos, eventDispatcher),
419
400
  tableCell: (node, view, getPos) =>
420
- new TableCell(node, view, getPos, eventDispatcher, observer),
401
+ new TableCell(node, view, getPos, eventDispatcher),
421
402
  tableHeader: (node, view, getPos) =>
422
- new TableCell(node, view, getPos, eventDispatcher, observer),
403
+ new TableCell(node, view, getPos, eventDispatcher),
423
404
  },
424
405
  handleDOMEvents: {
425
406
  focus: handleFocus,
@@ -428,7 +409,7 @@ export const createPlugin = (
428
409
  mouseover: withCellTracking(whenTableInFocus(handleMouseOver)),
429
410
  mouseleave: handleMouseLeave,
430
411
  mouseout: whenTableInFocus(handleMouseOut),
431
- mousemove: whenTableInFocus(handleMouseMove, elementContentRects),
412
+ mousemove: whenTableInFocus(handleMouseMove),
432
413
  mouseenter: handleMouseEnter,
433
414
  mouseup: whenTableInFocus(handleMouseUp),
434
415
  click: withCellTracking(whenTableInFocus(handleClick)),
@@ -5,7 +5,7 @@ import { DOMSerializer } from '@atlaskit/editor-prosemirror/model';
5
5
  import { TableMap } from '@atlaskit/editor-tables/table-map';
6
6
  import { getBooleanFF } from '@atlaskit/platform-feature-flags';
7
7
 
8
- import { MAX_SCALING_PERCENT } from './consts';
8
+ import { getTableScalingPercent } from './misc';
9
9
 
10
10
  type Col = Array<string | { [name: string]: string }>;
11
11
 
@@ -29,13 +29,10 @@ export const generateColgroup = (table: PmNode, tableRef?: HTMLElement) => {
29
29
  // We slice here to guard against our colwidth array having more entries
30
30
  // Than the we actually span. We'll patch the document at a later point.
31
31
  if (tableRef) {
32
- const tableWidth = table.attrs && table.attrs.width;
33
- let renderWidth = tableRef.parentElement?.clientWidth || 760;
34
- let scalePercent = renderWidth / tableWidth;
35
- scalePercent = Math.max(scalePercent, 1 - MAX_SCALING_PERCENT);
32
+ const scalePercent = getTableScalingPercent(table, tableRef);
36
33
  cell.attrs.colwidth.slice(0, colspan).forEach((width) => {
37
34
  const fixedColWidth = getColWidthFix(width, map.width);
38
- const scaledWidth = fixedColWidth * Math.min(scalePercent, 1);
35
+ const scaledWidth = fixedColWidth * scalePercent;
39
36
  const finalWidth = Math.max(scaledWidth, tableCellMinWidth);
40
37
  cols.push([
41
38
  'col',
@@ -31,6 +31,7 @@ import { getBooleanFF } from '@atlaskit/platform-feature-flags';
31
31
  import type { TableOptions } from '../../../nodeviews/types';
32
32
 
33
33
  import { hasTableBeenResized } from './colgroup';
34
+ import { MAX_SCALING_PERCENT } from './consts';
34
35
 
35
36
  // Translates named layouts in number values.
36
37
  export function getLayoutSize(
@@ -156,3 +157,15 @@ export const getTableElementWidth = (table: PMNode) => {
156
157
  export const getTableContainerElementWidth = (table: PMNode) => {
157
158
  return getTableContainerWidth(table);
158
159
  };
160
+
161
+ export const getTableScalingPercent = (
162
+ table: PMNode,
163
+ tableRef: HTMLElement,
164
+ ) => {
165
+ const tableWidth = getTableContainerElementWidth(table);
166
+ let renderWidth = tableRef.parentElement?.clientWidth || tableWidth;
167
+ // minus 1 here to avoid any 1px scroll in Firefox
168
+ let scalePercent = (renderWidth - 1) / tableWidth;
169
+ scalePercent = Math.max(scalePercent, 1 - MAX_SCALING_PERCENT);
170
+ return Math.min(scalePercent, 1);
171
+ };