@atlaskit/editor-plugin-table 4.1.0 → 4.2.0

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 (60) hide show
  1. package/CHANGELOG.md +13 -0
  2. package/dist/cjs/plugins/table/commands/delete.js +18 -0
  3. package/dist/cjs/plugins/table/commands-with-analytics.js +2 -7
  4. package/dist/cjs/plugins/table/event-handlers.js +2 -2
  5. package/dist/cjs/plugins/table/nodeviews/TableContainer.js +27 -9
  6. package/dist/cjs/plugins/table/pm-plugins/main.js +1 -1
  7. package/dist/cjs/plugins/table/transforms/column-width.js +110 -5
  8. package/dist/cjs/plugins/table/transforms/delete-columns.js +16 -6
  9. package/dist/cjs/plugins/table/ui/FloatingContextualMenu/ContextualMenu.js +1 -1
  10. package/dist/cjs/plugins/table/ui/FloatingDeleteButton/index.js +1 -1
  11. package/dist/cjs/plugins/table/ui/common-styles.js +1 -1
  12. package/dist/es2019/plugins/table/commands/delete.js +10 -0
  13. package/dist/es2019/plugins/table/commands-with-analytics.js +3 -8
  14. package/dist/es2019/plugins/table/event-handlers.js +2 -2
  15. package/dist/es2019/plugins/table/nodeviews/TableContainer.js +27 -9
  16. package/dist/es2019/plugins/table/pm-plugins/main.js +1 -1
  17. package/dist/es2019/plugins/table/transforms/column-width.js +105 -5
  18. package/dist/es2019/plugins/table/transforms/delete-columns.js +16 -5
  19. package/dist/es2019/plugins/table/ui/FloatingContextualMenu/ContextualMenu.js +1 -1
  20. package/dist/es2019/plugins/table/ui/FloatingDeleteButton/index.js +1 -1
  21. package/dist/es2019/plugins/table/ui/common-styles.js +0 -1
  22. package/dist/esm/plugins/table/commands/delete.js +12 -0
  23. package/dist/esm/plugins/table/commands-with-analytics.js +3 -8
  24. package/dist/esm/plugins/table/event-handlers.js +2 -2
  25. package/dist/esm/plugins/table/nodeviews/TableContainer.js +27 -9
  26. package/dist/esm/plugins/table/pm-plugins/main.js +1 -1
  27. package/dist/esm/plugins/table/transforms/column-width.js +111 -5
  28. package/dist/esm/plugins/table/transforms/delete-columns.js +16 -6
  29. package/dist/esm/plugins/table/ui/FloatingContextualMenu/ContextualMenu.js +1 -1
  30. package/dist/esm/plugins/table/ui/FloatingDeleteButton/index.js +1 -1
  31. package/dist/esm/plugins/table/ui/common-styles.js +1 -1
  32. package/dist/types/plugins/table/commands/delete.d.ts +3 -0
  33. package/dist/types/plugins/table/event-handlers.d.ts +1 -1
  34. package/dist/types/plugins/table/nodeviews/TableContainer.d.ts +3 -3
  35. package/dist/types/plugins/table/pm-plugins/table-resizing/utils/misc.d.ts +1 -1
  36. package/dist/types/plugins/table/transforms/column-width.d.ts +25 -6
  37. package/dist/types/plugins/table/transforms/delete-columns.d.ts +2 -1
  38. package/dist/types/plugins/table/ui/FloatingDeleteButton/index.d.ts +4 -4
  39. package/dist/types-ts4.5/plugins/table/commands/delete.d.ts +3 -0
  40. package/dist/types-ts4.5/plugins/table/event-handlers.d.ts +1 -1
  41. package/dist/types-ts4.5/plugins/table/nodeviews/TableContainer.d.ts +3 -3
  42. package/dist/types-ts4.5/plugins/table/pm-plugins/table-resizing/utils/misc.d.ts +1 -1
  43. package/dist/types-ts4.5/plugins/table/transforms/column-width.d.ts +25 -6
  44. package/dist/types-ts4.5/plugins/table/transforms/delete-columns.d.ts +2 -1
  45. package/dist/types-ts4.5/plugins/table/ui/FloatingDeleteButton/index.d.ts +4 -4
  46. package/package.json +8 -2
  47. package/src/__tests__/unit/commands.ts +1 -0
  48. package/src/__tests__/unit/transforms/delete-columns.ts +406 -105
  49. package/src/__tests__/unit/undo-redo.ts +1 -1
  50. package/src/plugins/table/commands/delete.ts +20 -0
  51. package/src/plugins/table/commands-with-analytics.ts +3 -10
  52. package/src/plugins/table/event-handlers.ts +6 -1
  53. package/src/plugins/table/nodeviews/TableContainer.tsx +189 -159
  54. package/src/plugins/table/pm-plugins/main.ts +7 -1
  55. package/src/plugins/table/pm-plugins/table-resizing/utils/misc.ts +1 -1
  56. package/src/plugins/table/transforms/column-width.ts +155 -15
  57. package/src/plugins/table/transforms/delete-columns.ts +23 -6
  58. package/src/plugins/table/ui/FloatingContextualMenu/ContextualMenu.tsx +1 -1
  59. package/src/plugins/table/ui/FloatingDeleteButton/index.tsx +7 -6
  60. package/src/plugins/table/ui/common-styles.ts +0 -1
@@ -27,6 +27,7 @@ import {
27
27
 
28
28
  import { clearMultipleCells } from './commands/clear';
29
29
  import { wrapTableInExpand } from './commands/collapse';
30
+ import { deleteColumnsCommand } from './commands/delete';
30
31
  import { insertColumn, insertRow } from './commands/insert';
31
32
  import {
32
33
  deleteTable,
@@ -45,7 +46,7 @@ import {
45
46
  import { getPluginState } from './pm-plugins/plugin-factory';
46
47
  import { distributeColumnsWidths } from './pm-plugins/table-resizing/commands';
47
48
  import type { ResizeStateWithAnalytics } from './pm-plugins/table-resizing/utils';
48
- import { deleteColumns, deleteRows, mergeCells } from './transforms';
49
+ import { deleteRows, mergeCells } from './transforms';
49
50
  import type {
50
51
  InsertRowMethods,
51
52
  InsertRowOptions,
@@ -57,7 +58,6 @@ import {
57
58
  getSelectedTableInfo,
58
59
  } from './utils';
59
60
  import { withEditorAnalyticsAPI } from './utils/analytics';
60
- import { getAllowAddColumnCustomStep } from './utils/get-allow-add-column-custom-step';
61
61
 
62
62
  const TABLE_BREAKOUT_NAME_MAPPING = {
63
63
  default: TABLE_BREAKOUT.NORMAL,
@@ -337,14 +337,7 @@ export const deleteColumnsWithAnalytics =
337
337
  },
338
338
  eventType: EVENT_TYPE.TRACK,
339
339
  };
340
- })(editorAnalyticsAPI)((state, dispatch) => {
341
- if (dispatch) {
342
- dispatch(
343
- deleteColumns(rect, getAllowAddColumnCustomStep(state))(state.tr),
344
- );
345
- }
346
- return true;
347
- });
340
+ })(editorAnalyticsAPI)(deleteColumnsCommand(rect));
348
341
 
349
342
  const getTableDeletedAnalytics = (
350
343
  selection: Selection,
@@ -412,6 +412,7 @@ export const handleCut = (
412
412
  oldState: EditorState,
413
413
  newState: EditorState,
414
414
  editorAnalyticsAPI?: EditorAnalyticsAPI,
415
+ editorView?: EditorView,
415
416
  ): Transaction => {
416
417
  const oldSelection = oldState.tr.selection;
417
418
  let { tr } = newState;
@@ -464,7 +465,11 @@ export const handleCut = (
464
465
  } = getPluginState(newState);
465
466
  tr = deleteRows(rect, isHeaderRowRequired)(tr);
466
467
  } else if (tr.selection.isColSelection()) {
467
- tr = deleteColumns(rect, getAllowAddColumnCustomStep(oldState))(tr);
468
+ tr = deleteColumns(
469
+ rect,
470
+ getAllowAddColumnCustomStep(oldState),
471
+ editorView,
472
+ )(tr);
468
473
  }
469
474
  }
470
475
  }
@@ -23,7 +23,10 @@ import { TableCssClassName as ClassName } from '../types';
23
23
  import { TableResizer } from './TableResizer';
24
24
  import type { TableResizerImprovementProps } from './TableResizer';
25
25
 
26
- const getMarginLeft = (lineLength: number, tableWidth: number | 'inherit') => {
26
+ const getMarginLeft = (
27
+ lineLength: number | undefined,
28
+ tableWidth: number | 'inherit',
29
+ ) => {
27
30
  let marginLeft;
28
31
  if (tableWidth !== 'inherit' && lineLength) {
29
32
  const containerWidth = tableWidth;
@@ -40,7 +43,7 @@ type InnerContainerProps = {
40
43
  className: string;
41
44
  style?: {
42
45
  width: number | 'inherit';
43
- marginLeft: number | undefined;
46
+ marginLeft?: number;
44
47
  };
45
48
  node: PMNode;
46
49
  };
@@ -65,7 +68,7 @@ export const InnerContainer = forwardRef<
65
68
 
66
69
  type ResizableTableContainerProps = {
67
70
  containerWidth: number;
68
- lineLength: number;
71
+ lineLength?: number;
69
72
  node: PMNode;
70
73
  className: string;
71
74
  editorView: EditorView;
@@ -75,178 +78,205 @@ type ResizableTableContainerProps = {
75
78
  pluginInjectionApi?: PluginInjectionAPI;
76
79
  };
77
80
 
78
- export const ResizableTableContainer = ({
79
- children,
80
- className,
81
- node,
82
- lineLength,
83
- containerWidth,
84
- editorView,
85
- getPos,
86
- tableRef,
87
- isResizing,
88
- pluginInjectionApi,
89
- }: PropsWithChildren<ResizableTableContainerProps>) => {
90
- const containerRef = useRef<HTMLDivElement | null>(null);
91
- const marginLeftRef = useRef<number | undefined>(0);
92
- const tableWidthRef = useRef<number>(akEditorDefaultLayoutWidth);
93
-
94
- const updateContainerHeight = useCallback((height: number | 'auto') => {
95
- // current StickyHeader State is not stable to be fetch.
96
- // we need to update stickyHeader plugin to make sure state can be
97
- // consistently fetch and refactor below
98
- const stickyHeaders =
99
- containerRef.current?.getElementsByClassName('pm-table-sticky');
100
- if (!stickyHeaders || stickyHeaders.length < 1) {
101
- // when starting to drag, we need to keep the original space,
102
- // -- When sticky header not appear, margin top(24px) and margin bottom(16px), should be 40px,
103
- // 1px is border width but collapse make it 0.5.
104
- // -- When sticky header appear, we should add first row height but reduce
105
- // collapsed border
106
- containerRef.current?.style.setProperty(
107
- 'height',
108
- typeof height === 'number' ? `${height + 40.5}px` : 'auto',
109
- );
110
- } else {
111
- const stickyHeaderHeight =
112
- containerRef.current
113
- ?.getElementsByTagName('th')[0]
114
- .getBoundingClientRect().height || 0;
115
- containerRef.current?.style.setProperty(
116
- 'height',
117
- typeof height === 'number'
118
- ? `${height + stickyHeaderHeight + 39.5}px`
119
- : 'auto',
120
- );
121
- }
122
- }, []);
123
-
124
- const resizeObserverRef = useRef(
125
- new ResizeObserver((entries) => {
126
- updateContainerHeight(entries[entries.length - 1].contentRect.height);
127
- }),
128
- );
129
-
130
- const onResizeStart = useCallback(() => {
131
- if (tableRef) {
132
- resizeObserverRef.current.observe(tableRef);
133
- }
134
- }, [tableRef]);
135
-
136
- const onResizeStop = useCallback(() => {
137
- updateContainerHeight('auto');
138
-
139
- resizeObserverRef.current.disconnect();
140
- }, [updateContainerHeight]);
141
-
142
- const updateWidth = useCallback(
143
- (width: number) => {
144
- if (!containerRef.current) {
145
- return;
81
+ export const ResizableTableContainer = React.memo(
82
+ ({
83
+ children,
84
+ className,
85
+ node,
86
+ lineLength,
87
+ containerWidth,
88
+ editorView,
89
+ getPos,
90
+ tableRef,
91
+ isResizing,
92
+ pluginInjectionApi,
93
+ }: PropsWithChildren<ResizableTableContainerProps>) => {
94
+ const containerRef = useRef<HTMLDivElement | null>(null);
95
+ const marginLeftRef = useRef<number | undefined>(0);
96
+ const tableWidthRef = useRef<number>(akEditorDefaultLayoutWidth);
97
+
98
+ const updateContainerHeight = useCallback((height: number | 'auto') => {
99
+ // current StickyHeader State is not stable to be fetch.
100
+ // we need to update stickyHeader plugin to make sure state can be
101
+ // consistently fetch and refactor below
102
+ const stickyHeaders =
103
+ containerRef.current?.getElementsByClassName('pm-table-sticky');
104
+ if (!stickyHeaders || stickyHeaders.length < 1) {
105
+ // when starting to drag, we need to keep the original space,
106
+ // -- When sticky header not appear, margin top(24px) and margin bottom(16px), should be 40px,
107
+ // 1px is border width but collapse make it 0.5.
108
+ // -- When sticky header appear, we should add first row height but reduce
109
+ // collapsed border
110
+ containerRef.current?.style.setProperty(
111
+ 'height',
112
+ typeof height === 'number' ? `${height + 40.5}px` : 'auto',
113
+ );
114
+ } else {
115
+ const stickyHeaderHeight =
116
+ containerRef.current
117
+ ?.getElementsByTagName('th')[0]
118
+ .getBoundingClientRect().height || 0;
119
+ containerRef.current?.style.setProperty(
120
+ 'height',
121
+ typeof height === 'number'
122
+ ? `${height + stickyHeaderHeight + 39.5}px`
123
+ : 'auto',
124
+ );
146
125
  }
126
+ }, []);
147
127
 
148
- const marginLeft = getMarginLeft(lineLength, width);
128
+ const resizeObserverRef = useRef(
129
+ new ResizeObserver((entries) => {
130
+ updateContainerHeight(entries[entries.length - 1].contentRect.height);
131
+ }),
132
+ );
149
133
 
150
- // make sure during resizing
151
- // the pm-table-resizer-container width is the same as its child div resizer-item
152
- // otherwise when resize table from wider to narrower , pm-table-resizer-container stays wider
153
- // and cause the fabric-editor-popup-scroll-parent to overflow
154
- if (containerRef.current.style.width !== `${width}px`) {
155
- containerRef.current.style.width = `${width}px`;
134
+ const onResizeStart = useCallback(() => {
135
+ if (tableRef) {
136
+ resizeObserverRef.current.observe(tableRef);
156
137
  }
138
+ }, [tableRef]);
139
+
140
+ const onResizeStop = useCallback(() => {
141
+ updateContainerHeight('auto');
157
142
 
158
- if (marginLeftRef.current !== marginLeft) {
159
- marginLeftRef.current = marginLeft;
143
+ resizeObserverRef.current.disconnect();
144
+ }, [updateContainerHeight]);
160
145
 
161
- if (Number.isFinite(marginLeft)) {
162
- containerRef.current.style.marginLeft = `${marginLeft}px`;
146
+ const updateWidth = useCallback(
147
+ (width: number) => {
148
+ if (!containerRef.current) {
149
+ return;
163
150
  }
164
- }
165
- },
166
- [lineLength],
167
- );
168
151
 
169
- const displayGuideline = useCallback(
170
- (guidelines: GuidelineConfig[]) => {
171
- return (
172
- pluginInjectionApi?.guideline?.actions?.displayGuideline(editorView)({
173
- guidelines,
174
- }) ?? false
175
- );
176
- },
177
- [pluginInjectionApi, editorView],
178
- );
152
+ // make sure during resizing
153
+ // the pm-table-resizer-container width is the same as its child div resizer-item
154
+ // otherwise when resize table from wider to narrower , pm-table-resizer-container stays wider
155
+ // and cause the fabric-editor-popup-scroll-parent to overflow
156
+ if (containerRef.current.style.width !== `${width}px`) {
157
+ containerRef.current.style.width = `${width}px`;
158
+ }
179
159
 
180
- const attachAnalyticsEvent = useCallback(
181
- (payload: TableEventPayload) => {
182
- return pluginInjectionApi?.analytics?.actions.attachAnalyticsEvent(
183
- payload,
184
- );
185
- },
186
- [pluginInjectionApi],
187
- );
160
+ if (
161
+ !getBooleanFF('platform.editor.table.update-table-resizer-styles')
162
+ ) {
163
+ const marginLeft = getMarginLeft(lineLength, width);
164
+ if (marginLeftRef.current !== marginLeft) {
165
+ marginLeftRef.current = marginLeft;
166
+ if (Number.isFinite(marginLeft)) {
167
+ containerRef.current.style.marginLeft = `${marginLeft}px`;
168
+ }
169
+ }
170
+ }
171
+ },
172
+ [lineLength],
173
+ );
188
174
 
189
- const displayGapCursor = useCallback(
190
- (toggle) => {
191
- return (
192
- pluginInjectionApi?.core?.actions.execute(
193
- pluginInjectionApi?.selection?.commands.displayGapCursor(toggle),
194
- ) ?? false
195
- );
196
- },
197
- [pluginInjectionApi],
198
- );
175
+ const displayGuideline = useCallback(
176
+ (guidelines: GuidelineConfig[]) => {
177
+ return (
178
+ pluginInjectionApi?.guideline?.actions?.displayGuideline(editorView)({
179
+ guidelines,
180
+ }) ?? false
181
+ );
182
+ },
183
+ [pluginInjectionApi, editorView],
184
+ );
199
185
 
200
- const tableWidth = getTableContainerWidth(node);
201
- // 76 is currently an accepted padding value considering the spacing for resizer handle
202
- const responsiveContainerWidth = containerWidth - 76;
203
- const width = Math.min(tableWidth, responsiveContainerWidth);
186
+ const attachAnalyticsEvent = useCallback(
187
+ (payload: TableEventPayload) => {
188
+ return pluginInjectionApi?.analytics?.actions.attachAnalyticsEvent(
189
+ payload,
190
+ );
191
+ },
192
+ [pluginInjectionApi],
193
+ );
204
194
 
205
- if (!isResizing) {
206
- tableWidthRef.current = width;
207
- marginLeftRef.current = getMarginLeft(lineLength, width);
208
- }
209
- const maxResizerWidth = Math.min(responsiveContainerWidth, TABLE_MAX_WIDTH);
195
+ const displayGapCursor = useCallback(
196
+ (toggle) => {
197
+ return (
198
+ pluginInjectionApi?.core?.actions.execute(
199
+ pluginInjectionApi?.selection?.commands.displayGapCursor(toggle),
200
+ ) ?? false
201
+ );
202
+ },
203
+ [pluginInjectionApi],
204
+ );
210
205
 
211
- let tableResizerProps: TableResizerImprovementProps = {
212
- width,
213
- maxWidth: maxResizerWidth,
214
- containerWidth,
215
- updateWidth,
216
- editorView,
217
- getPos,
218
- node,
219
- tableRef,
220
- displayGuideline,
221
- attachAnalyticsEvent,
222
- displayGapCursor,
223
- };
206
+ const tableWidth = getTableContainerWidth(node);
207
+ // 76 is currently an accepted padding value considering the spacing for resizer handle
208
+ const responsiveContainerWidth = containerWidth - 76;
209
+ const width = Math.min(tableWidth, responsiveContainerWidth);
224
210
 
225
- if (getBooleanFF('platform.editor.resizing-table-height-improvement')) {
226
- tableResizerProps = {
227
- ...tableResizerProps,
228
- onResizeStart: onResizeStart,
229
- onResizeStop: onResizeStop,
211
+ if (!isResizing) {
212
+ tableWidthRef.current = width;
213
+ if (!getBooleanFF('platform.editor.table.update-table-resizer-styles')) {
214
+ marginLeftRef.current = getMarginLeft(lineLength, width);
215
+ }
216
+ }
217
+ const maxResizerWidth = Math.min(responsiveContainerWidth, TABLE_MAX_WIDTH);
218
+
219
+ let tableResizerProps: TableResizerImprovementProps = {
220
+ width,
221
+ maxWidth: maxResizerWidth,
222
+ containerWidth,
223
+ updateWidth,
224
+ editorView,
225
+ getPos,
226
+ node,
227
+ tableRef,
228
+ displayGuideline,
229
+ attachAnalyticsEvent,
230
+ displayGapCursor,
230
231
  };
231
- }
232
232
 
233
- return (
234
- <div
235
- style={{
236
- marginLeft: marginLeftRef.current,
237
- width: tableWidthRef.current,
238
- }}
239
- className={ClassName.TABLE_RESIZER_CONTAINER}
240
- ref={containerRef}
241
- >
242
- <TableResizer {...tableResizerProps}>
243
- <InnerContainer className={className} node={node}>
244
- {children}
245
- </InnerContainer>
246
- </TableResizer>
247
- </div>
248
- );
249
- };
233
+ if (getBooleanFF('platform.editor.resizing-table-height-improvement')) {
234
+ tableResizerProps = {
235
+ ...tableResizerProps,
236
+ onResizeStart: onResizeStart,
237
+ onResizeStop: onResizeStop,
238
+ };
239
+ }
240
+
241
+ return getBooleanFF('platform.editor.table.update-table-resizer-styles') ? (
242
+ <div
243
+ style={{
244
+ display: 'flex',
245
+ justifyContent: 'center',
246
+ }}
247
+ >
248
+ <div
249
+ style={{
250
+ width: tableWidthRef.current,
251
+ }}
252
+ className={ClassName.TABLE_RESIZER_CONTAINER}
253
+ ref={containerRef}
254
+ >
255
+ <TableResizer {...tableResizerProps}>
256
+ <InnerContainer className={className} node={node}>
257
+ {children}
258
+ </InnerContainer>
259
+ </TableResizer>
260
+ </div>
261
+ </div>
262
+ ) : (
263
+ <div
264
+ style={{
265
+ marginLeft: marginLeftRef.current,
266
+ width: tableWidthRef.current,
267
+ }}
268
+ className={ClassName.TABLE_RESIZER_CONTAINER}
269
+ ref={containerRef}
270
+ >
271
+ <TableResizer {...tableResizerProps}>
272
+ <InnerContainer className={className} node={node}>
273
+ {children}
274
+ </InnerContainer>
275
+ </TableResizer>
276
+ </div>
277
+ );
278
+ },
279
+ );
250
280
 
251
281
  type TableContainerProps = {
252
282
  node: PMNode;
@@ -191,7 +191,13 @@ export const createPlugin = (
191
191
 
192
192
  if (tr) {
193
193
  // "fixTables" removes empty rows as we don't allow that in schema
194
- const updatedTr = handleCut(tr, oldState, newState, editorAnalyticsAPI);
194
+ const updatedTr = handleCut(
195
+ tr,
196
+ oldState,
197
+ newState,
198
+ editorAnalyticsAPI,
199
+ editorViewRef || undefined,
200
+ );
195
201
  return fixTables(updatedTr) || updatedTr;
196
202
  }
197
203
  if (transactions.find((tr) => tr.docChanged)) {
@@ -130,5 +130,5 @@ export const getTableMaxWidth = ({
130
130
  maxWidth -= akEditorTableNumberColumnWidth;
131
131
  }
132
132
 
133
- return maxWidth;
133
+ return maxWidth as number;
134
134
  };
@@ -1,22 +1,20 @@
1
- import { CellAttributes } from '@atlaskit/adf-schema';
1
+ import type { CellAttributes } from '@atlaskit/adf-schema';
2
2
  import { SetAttrsStep } from '@atlaskit/adf-schema/steps';
3
- import {
4
- tableCellMinWidth,
5
- tableNewColumnMinWidth,
6
- } from '@atlaskit/editor-common/styles';
3
+ import { tableCellMinWidth } from '@atlaskit/editor-common/styles';
7
4
  import type { GetEditorContainerWidth } from '@atlaskit/editor-common/types';
8
- import { Node as PMNode } from '@atlaskit/editor-prosemirror/model';
9
- import { Transaction } from '@atlaskit/editor-prosemirror/state';
10
- import { ContentNodeWithPos } from '@atlaskit/editor-prosemirror/utils';
11
- import { EditorView } from '@atlaskit/editor-prosemirror/view';
5
+ import type { Node as PMNode } from '@atlaskit/editor-prosemirror/model';
6
+ import type { Transaction } from '@atlaskit/editor-prosemirror/state';
7
+ import type { ContentNodeWithPos } from '@atlaskit/editor-prosemirror/utils';
8
+ import type { EditorView } from '@atlaskit/editor-prosemirror/view';
12
9
  import { akEditorDefaultLayoutWidth } from '@atlaskit/editor-shared-styles';
13
- import { TableMap } from '@atlaskit/editor-tables/table-map';
10
+ import {
11
+ TableMap,
12
+ tableNewColumnMinWidth,
13
+ } from '@atlaskit/editor-tables/table-map';
14
14
  import { getBooleanFF } from '@atlaskit/platform-feature-flags';
15
15
 
16
- import {
17
- hasTableBeenResized,
18
- ResizeState,
19
- } from '../pm-plugins/table-resizing/utils';
16
+ import type { ResizeState } from '../pm-plugins/table-resizing/utils';
17
+ import { hasTableBeenResized } from '../pm-plugins/table-resizing/utils';
20
18
  import { isMinCellWidthTable } from '../pm-plugins/table-resizing/utils/colgroup';
21
19
  import { getTableMaxWidth } from '../pm-plugins/table-resizing/utils/misc';
22
20
  import {
@@ -26,6 +24,13 @@ import {
26
24
  import { scaleTableTo } from '../pm-plugins/table-resizing/utils/scale-table';
27
25
  import { insertColumnButtonOffset } from '../ui/common-styles';
28
26
 
27
+ /**
28
+ * Given a new ResizeState object, create a transaction that replaces and updates the table node based on new state.
29
+ * @param resizeState
30
+ * @param table
31
+ * @param start
32
+ * @returns
33
+ */
29
34
  export const updateColumnWidths =
30
35
  (resizeState: ResizeState, table: PMNode, start: number) =>
31
36
  (tr: Transaction): Transaction => {
@@ -147,7 +152,129 @@ export const updateColumnWidths =
147
152
  * @param view
148
153
  * @returns Updated transaction with rescaled columns for a given table
149
154
  */
150
- export const rescaleColumns =
155
+ export const rescaleColumnsNew =
156
+ () =>
157
+ (table: ContentNodeWithPos, view: EditorView | undefined) =>
158
+ (tr: Transaction): Transaction => {
159
+ if (!view) {
160
+ return tr;
161
+ }
162
+
163
+ const newTable = tr.doc.nodeAt(table.pos);
164
+ const domAtPos = view.domAtPos.bind(view);
165
+ const maybeTable = domAtPos(table.start).node as HTMLElement;
166
+ const tableRef = maybeTable.closest('table');
167
+
168
+ if (!tableRef || !newTable) {
169
+ return tr;
170
+ }
171
+
172
+ const isResized = hasTableBeenResized(table.node);
173
+ // get current table info
174
+ const previousTableInfo = {
175
+ // when table is resized the tableRef client width will be 1px larger than colGroup, which is used in calculations
176
+ width: isResized ? tableRef.clientWidth - 1 : tableRef.clientWidth,
177
+ /** the is the width the table can reach before overflowing */
178
+ possibleMaxWidth: getBooleanFF('platform.editor.custom-table-width')
179
+ ? tableRef?.parentElement?.clientWidth || 0
180
+ : (tableRef?.parentElement?.clientWidth || 0) -
181
+ insertColumnButtonOffset -
182
+ 1,
183
+ isResized,
184
+ };
185
+
186
+ // determine the new table, based on new width
187
+ const newTableInfo = {
188
+ noOfColumns: TableMap.get(newTable).width,
189
+ };
190
+
191
+ if (!newTableInfo.noOfColumns || newTableInfo.noOfColumns <= 0) {
192
+ return tr;
193
+ }
194
+
195
+ const averageColumnWidth =
196
+ previousTableInfo.width / newTableInfo.noOfColumns;
197
+
198
+ // If the table has not been resized (i.e. all columns will have the same width) and every column width is bigger than the minimum column width
199
+ // we skip updating the size of columns here.
200
+ if (
201
+ !previousTableInfo.isResized &&
202
+ averageColumnWidth > tableCellMinWidth
203
+ ) {
204
+ return tr;
205
+ }
206
+
207
+ const wasTableInOverflow =
208
+ previousTableInfo.width > previousTableInfo.possibleMaxWidth;
209
+
210
+ // If the table has not been resized, and each column width is smaller than the minimum column width
211
+ // Or if the table has been resized, but each column width is either 48px or null
212
+ // we update the table to have 48px for each column
213
+ if (
214
+ (!previousTableInfo.isResized &&
215
+ averageColumnWidth <= tableCellMinWidth) ||
216
+ (previousTableInfo.isResized && isMinCellWidthTable(table.node))
217
+ ) {
218
+ const widths = new Array(newTableInfo.noOfColumns).fill(
219
+ tableCellMinWidth,
220
+ );
221
+ const cols = widths.map((_, index) => ({
222
+ width: tableCellMinWidth,
223
+ minWidth: tableCellMinWidth,
224
+ index,
225
+ }));
226
+
227
+ const minWidthResizeState = {
228
+ cols,
229
+ widths,
230
+ maxSize: previousTableInfo.possibleMaxWidth,
231
+ tableWidth: previousTableInfo.width,
232
+ overflow: wasTableInOverflow,
233
+ };
234
+ return updateColumnWidths(
235
+ minWidthResizeState,
236
+ table.node,
237
+ table.start,
238
+ )(tr);
239
+ }
240
+
241
+ let resizeState = getResizeState({
242
+ minWidth: tableCellMinWidth,
243
+ table: table.node,
244
+ start: table.start,
245
+ tableRef,
246
+ domAtPos,
247
+ maxSize: previousTableInfo.possibleMaxWidth,
248
+ });
249
+
250
+ // Two scenarios that require scaling:
251
+ // 1. If the new table width will result in the table going into overflow
252
+ // we resize the cells to avoid it (e.g. adding a column)
253
+ // 2. If the new table width will be shorter than the parent width, scale columns to fit parent
254
+ if (
255
+ (!wasTableInOverflow && resizeState.overflow) ||
256
+ resizeState.tableWidth < resizeState.maxSize
257
+ ) {
258
+ resizeState = scaleTableTo(
259
+ resizeState,
260
+ previousTableInfo.possibleMaxWidth,
261
+ );
262
+ }
263
+
264
+ return updateColumnWidths(resizeState, table.node, table.start)(tr);
265
+ };
266
+
267
+ /**
268
+ * This function is called when user inserts/deletes a column in a table to;
269
+ * - rescale all columns (if the table did not overflow before the insertion)
270
+ * - and update column widths.
271
+ *
272
+ * This is done manually to avoid a multi-dispatch in TableComponent. See [ED-8288].
273
+ * @param table
274
+ * @param view
275
+ * @returns Updated transaction with rescaled columns for a given table
276
+ */
277
+ export const rescaleColumnsOld =
151
278
  (getEditorContainerWidth: GetEditorContainerWidth) =>
152
279
  (table: ContentNodeWithPos, view: EditorView | undefined) =>
153
280
  (tr: Transaction): Transaction => {
@@ -246,3 +373,16 @@ export const rescaleColumns =
246
373
 
247
374
  return updateColumnWidths(resizeState, table.node, table.start)(tr);
248
375
  };
376
+
377
+ export const rescaleColumns = (
378
+ getEditorContainerWidth?: GetEditorContainerWidth,
379
+ ) => {
380
+ if (
381
+ getBooleanFF(
382
+ 'platform.editor.table-update-colwidths-after-column-is-deleted',
383
+ )
384
+ ) {
385
+ return rescaleColumnsNew();
386
+ }
387
+ return rescaleColumnsOld(getEditorContainerWidth!);
388
+ };