@atlaskit/editor-plugin-table 10.6.8 → 10.6.10

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.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,26 @@
1
1
  # @atlaskit/editor-plugin-table
2
2
 
3
+ ## 10.6.10
4
+
5
+ ### Patch Changes
6
+
7
+ - [#134965](https://bitbucket.org/atlassian/atlassian-frontend-monorepo/pull-requests/134965)
8
+ [`6c2982045451c`](https://bitbucket.org/atlassian/atlassian-frontend-monorepo/commits/6c2982045451c) -
9
+ ED-26568: Remove custom toDOM implementation as it was causing flickering of an unstyled table
10
+ node when loading the table with React18 concurrent mode. Add logic to temporarily ignore all
11
+ non-selection DOM mutations during table initialisation in order to prevent unstyled table
12
+ flashing. Restore mutation handler after react has finished applying the style and structure.
13
+
14
+ ## 10.6.9
15
+
16
+ ### Patch Changes
17
+
18
+ - [#139053](https://bitbucket.org/atlassian/atlassian-frontend-monorepo/pull-requests/139053)
19
+ [`c1c6278a78c4a`](https://bitbucket.org/atlassian/atlassian-frontend-monorepo/commits/c1c6278a78c4a) -
20
+ [ux] Adds a new temporary floating toolbar's config option to hide any toolbars when any table's
21
+ menu is opend.
22
+ - Updated dependencies
23
+
3
24
  ## 10.6.8
4
25
 
5
26
  ### Patch Changes
@@ -32,6 +32,7 @@ var _tableWidth = require("../pm-plugins/table-width");
32
32
  var _nodes = require("../pm-plugins/utils/nodes");
33
33
  var _TableComponent = _interopRequireDefault(require("./TableComponent"));
34
34
  var _TableComponentWithSharedState = require("./TableComponentWithSharedState");
35
+ var _toDOM = require("./toDOM");
35
36
  function _callSuper(t, o, e) { return o = (0, _getPrototypeOf2.default)(o), (0, _possibleConstructorReturn2.default)(t, _isNativeReflectConstruct() ? Reflect.construct(o, e || [], (0, _getPrototypeOf2.default)(t).constructor) : o.apply(t, e)); }
36
37
  function _isNativeReflectConstruct() { try { var t = !Boolean.prototype.valueOf.call(Reflect.construct(Boolean, [], function () {})); } catch (t) {} return (_isNativeReflectConstruct = function _isNativeReflectConstruct() { return !!t; })(); }
37
38
  function _superPropGet(t, o, e, r) { var p = (0, _get2.default)((0, _getPrototypeOf2.default)(1 & r ? t.prototype : t), o, e); return 2 & r && "function" == typeof p ? function (t) { return p.apply(e, t); } : p; }
@@ -66,6 +67,8 @@ var handleInlineTableWidth = function handleInlineTableWidth(table, width) {
66
67
  }
67
68
  table.style.setProperty('width', "".concat(width, "px"));
68
69
  };
70
+
71
+ // Leave as a fallback incase the table's NodeSpec.toDOM is not defined.
69
72
  var toDOM = function toDOM(node, props) {
70
73
  var colgroup = '';
71
74
  if (props.allowColumnResizing) {
@@ -86,16 +89,37 @@ var TableView = exports.default = /*#__PURE__*/function (_ReactNodeView) {
86
89
  _this.eventDispatcher = props.eventDispatcher;
87
90
  _this.options = props.options;
88
91
  _this.getEditorFeatureFlags = props.getEditorFeatureFlags;
92
+ if ((0, _platformFeatureFlags.fg)('platform_editor_table_initial_load_fix')) {
93
+ _this.handleRef = function (node) {
94
+ return _this._handleTableRef(node);
95
+ };
96
+ }
89
97
  return _this;
90
98
  }
91
99
  (0, _inherits2.default)(TableView, _ReactNodeView);
92
100
  return (0, _createClass2.default)(TableView, [{
93
101
  key: "getContentDOM",
94
102
  value: function getContentDOM() {
95
- var rendered = _model.DOMSerializer.renderSpec(document, toDOM(this.node, this.reactComponentProps));
103
+ var tableDOMStructure;
104
+ if ((0, _platformFeatureFlags.fg)('platform_editor_table_initial_load_fix')) {
105
+ tableDOMStructure = (0, _toDOM.tableNodeSpecWithFixedToDOM)({
106
+ allowColumnResizing: !!this.reactComponentProps.allowColumnResizing,
107
+ tableResizingEnabled: !!this.reactComponentProps.allowTableResizing,
108
+ getEditorContainerWidth: this.reactComponentProps.getEditorContainerWidth
109
+ }).toDOM(this.node);
110
+ } else {
111
+ tableDOMStructure = toDOM(this.node, this.reactComponentProps);
112
+ }
113
+ var rendered = _model.DOMSerializer.renderSpec(document, tableDOMStructure);
96
114
  if (rendered.dom) {
97
115
  var _this$options, _this$options2, _this$getEditorFeatur;
98
- this.table = rendered.dom;
116
+ if ((0, _platformFeatureFlags.fg)('platform_editor_table_initial_load_fix')) {
117
+ var tableElement = rendered.dom.querySelector('table');
118
+ this.table = tableElement ? tableElement : rendered.dom;
119
+ this.renderedDOM = rendered.dom;
120
+ } else {
121
+ this.table = rendered.dom;
122
+ }
99
123
  if (!((_this$options = this.options) !== null && _this$options !== void 0 && _this$options.isTableScalingEnabled) || (_this$options2 = this.options) !== null && _this$options2 !== void 0 && _this$options2.isTableScalingEnabled && (_this$getEditorFeatur = this.getEditorFeatureFlags) !== null && _this$getEditorFeatur !== void 0 && _this$getEditorFeatur.call(this).tableWithFixedColumnWidthsOption && this.node.attrs.displayMode === 'fixed') {
100
124
  var tableInlineWidth = getInlineWidth(this.node, this.reactComponentProps.options, this.reactComponentProps.view.state, this.reactComponentProps.getPos(), this.reactComponentProps.allowTableResizing);
101
125
  if (tableInlineWidth) {
@@ -105,10 +129,79 @@ var TableView = exports.default = /*#__PURE__*/function (_ReactNodeView) {
105
129
  }
106
130
  return rendered;
107
131
  }
132
+
133
+ /**
134
+ * Handles moving the table from ProseMirror's DOM structure into a React-rendered table node.
135
+ * Temporarily disables mutation observers (except for selection changes) during the move,
136
+ * preserves selection state, and restores it afterwards if mutations occurred and cursor
137
+ * wasn't at start of node. This prevents duplicate tables and maintains editor state during
138
+ * the DOM manipulation.
139
+ */
140
+ }, {
141
+ key: "_handleTableRef",
142
+ value: function _handleTableRef(node) {
143
+ var _this2 = this;
144
+ var oldIgnoreMutation;
145
+ var selectionBookmark;
146
+ var parentOffset = 0;
147
+ var mutationsIgnored = false;
148
+
149
+ // Only proceed if we have both a node and table, and the table isn't already inside the node
150
+ if (node && this.table && !node.contains(this.table)) {
151
+ var _this$view$state$sele;
152
+ // Store the current ignoreMutation handler so we can restore it later
153
+ oldIgnoreMutation = this.ignoreMutation;
154
+
155
+ // Set up a temporary mutation handler that:
156
+ // - Ignores all DOM mutations except selection changes
157
+ // - Tracks when mutations have been ignored via mutationsIgnored flag
158
+ this.ignoreMutation = function (m) {
159
+ var isSelectionMutation = m.target instanceof Selection;
160
+ if (!isSelectionMutation) {
161
+ mutationsIgnored = true;
162
+ }
163
+ return !isSelectionMutation;
164
+ };
165
+
166
+ // Store the current selection state if there is a visible selection
167
+ // This lets us restore it after DOM changes
168
+ if (this.view.state.selection.visible) {
169
+ selectionBookmark = this.view.state.selection.getBookmark();
170
+ }
171
+
172
+ // Store the current cursor position within the parent node
173
+ // Used to determine if we need to restore selection later
174
+ if (((_this$view$state$sele = this.view.state.selection) === null || _this$view$state$sele === void 0 ? void 0 : _this$view$state$sele.ranges.length) > 0) {
175
+ var _this$view$state$sele2, _this$view$state$sele3;
176
+ parentOffset = (_this$view$state$sele2 = (_this$view$state$sele3 = this.view.state.selection) === null || _this$view$state$sele3 === void 0 || (_this$view$state$sele3 = _this$view$state$sele3.ranges[0].$from) === null || _this$view$state$sele3 === void 0 ? void 0 : _this$view$state$sele3.parentOffset) !== null && _this$view$state$sele2 !== void 0 ? _this$view$state$sele2 : 0;
177
+ }
178
+
179
+ // Remove the ProseMirror table DOM structure to avoid duplication, as it's replaced with the React table node.
180
+ if (this.renderedDOM) {
181
+ this.dom.removeChild(this.renderedDOM);
182
+ }
183
+ // Move the table from the ProseMirror table structure into the React rendered table node.
184
+ node.appendChild(this.table);
185
+
186
+ // After the next frame:
187
+ requestAnimationFrame(function () {
188
+ // Restore the original mutation handler
189
+ _this2.ignoreMutation = oldIgnoreMutation;
190
+
191
+ // Restore the selection only if:
192
+ // - We have a selection bookmark
193
+ // - Mutations were ignored during the table move
194
+ // - The cursor wasn't at the start of the node
195
+ if (selectionBookmark && mutationsIgnored && parentOffset > 0) {
196
+ _this2.view.dispatch(_this2.view.state.tr.setSelection(selectionBookmark.resolve(_this2.view.state.tr.doc)));
197
+ }
198
+ });
199
+ }
200
+ }
108
201
  }, {
109
202
  key: "setDomAttrs",
110
203
  value: function setDomAttrs(node) {
111
- var _this2 = this,
204
+ var _this3 = this,
112
205
  _this$options3,
113
206
  _this$options4,
114
207
  _this$getEditorFeatur2;
@@ -119,7 +212,7 @@ var TableView = exports.default = /*#__PURE__*/function (_ReactNodeView) {
119
212
  Object.keys(attrs).forEach(function (attr) {
120
213
  // Ignored via go/ees005
121
214
  // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
122
- _this2.table.setAttribute(attr, attrs[attr]);
215
+ _this3.table.setAttribute(attr, attrs[attr]);
123
216
  });
124
217
 
125
218
  // Preserve Table Width cannot have inline width set on the table
@@ -136,7 +229,7 @@ var TableView = exports.default = /*#__PURE__*/function (_ReactNodeView) {
136
229
  }, {
137
230
  key: "render",
138
231
  value: function render(props, forwardRef) {
139
- var _this3 = this;
232
+ var _this4 = this;
140
233
  if ((0, _platformFeatureFlags.fg)('platform_editor_table_use_shared_state_hook_fg')) {
141
234
  return /*#__PURE__*/_react.default.createElement(_TableComponentWithSharedState.TableComponentWithSharedState, {
142
235
  forwardRef: forwardRef,
@@ -154,7 +247,6 @@ var TableView = exports.default = /*#__PURE__*/function (_ReactNodeView) {
154
247
  dispatchAnalyticsEvent: props.dispatchAnalyticsEvent
155
248
  });
156
249
  }
157
-
158
250
  // Please, do not copy or use this kind of code below
159
251
  // @ts-ignore
160
252
  var fakePluginKey = {
@@ -246,7 +338,7 @@ var TableView = exports.default = /*#__PURE__*/function (_ReactNodeView) {
246
338
  ,
247
339
  ordering: pluginState.ordering,
248
340
  isResizing: isResizing,
249
- getNode: _this3.getNode
341
+ getNode: _this4.getNode
250
342
  // Ignored via go/ees005
251
343
  // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
252
344
  ,
@@ -610,7 +610,7 @@ var tablesPlugin = function tablesPlugin(_ref) {
610
610
  }
611
611
  }];
612
612
  },
613
- floatingToolbar: (0, _toolbar.getToolbarConfig)(defaultGetEditorContainerWidth, api, editorAnalyticsAPI, (options === null || options === void 0 ? void 0 : options.getEditorFeatureFlags) || defaultGetEditorFeatureFlags, function () {
613
+ floatingToolbar: (0, _toolbar.getToolbarConfig)(defaultGetEditorContainerWidth, api, editorAnalyticsAPI, function () {
614
614
  return editorViewRef.current;
615
615
  }, options, isTableFixedColumnWidthsOptionEnabled, shouldUseIncreasedScalingPercent)((0, _createPluginConfig.pluginConfig)(options === null || options === void 0 ? void 0 : options.tableOptions))
616
616
  },
@@ -37,7 +37,8 @@ var _platformFeatureFlags = require("@atlaskit/platform-feature-flags");
37
37
  var _experiments = require("@atlaskit/tmp-editor-statsig/experiments");
38
38
  var _commands = require("../pm-plugins/commands");
39
39
  var _commandsWithAnalytics = require("../pm-plugins/commands/commands-with-analytics");
40
- var _pluginFactory = require("../pm-plugins/plugin-factory");
40
+ var _pluginFactory = require("../pm-plugins/drag-and-drop/plugin-factory");
41
+ var _pluginFactory2 = require("../pm-plugins/plugin-factory");
41
42
  var _pluginKey = require("../pm-plugins/table-resizing/plugin-key");
42
43
  var _misc = require("../pm-plugins/table-resizing/utils/misc");
43
44
  var _resizeState = require("../pm-plugins/table-resizing/utils/resize-state");
@@ -155,7 +156,7 @@ var getToolbarCellOptionsConfig = exports.getToolbarCellOptionsConfig = function
155
156
  left = initialSelectionRect.left;
156
157
  var numberOfColumns = right - left;
157
158
  var numberOfRows = bottom - top;
158
- var pluginState = (0, _pluginFactory.getPluginState)(editorState);
159
+ var pluginState = (0, _pluginFactory2.getPluginState)(editorState);
159
160
  var options = [{
160
161
  id: 'editor.table.insertColumn',
161
162
  title: formatMessage(_messages.tableMessages.insertColumn),
@@ -318,7 +319,7 @@ var getToolbarCellOptionsConfig = exports.getToolbarCellOptionsConfig = function
318
319
  0: Math.max(numberOfColumns, numberOfRows)
319
320
  }),
320
321
  onClick: function onClick(state, dispatch) {
321
- var _getPluginState = (0, _pluginFactory.getPluginState)(state),
322
+ var _getPluginState = (0, _pluginFactory2.getPluginState)(state),
322
323
  targetCellPosition = _getPluginState.targetCellPosition;
323
324
  (0, _commandsWithAnalytics.emptyMultipleCellsWithAnalytics)(editorAnalyticsAPI)(_analytics.INPUT_METHOD.FLOATING_TB, targetCellPosition)(state, dispatch);
324
325
  return true;
@@ -361,21 +362,48 @@ var getClosestSelectionOrTableRect = function getClosestSelectionOrTableRect(sta
361
362
  // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
362
363
  return (0, _utils3.isSelectionType)(selection, 'cell') ? (0, _utils3.getSelectionRect)(selection) : tableRect;
363
364
  };
364
- var getToolbarConfig = exports.getToolbarConfig = function getToolbarConfig(getEditorContainerWidth, api, editorAnalyticsAPI, getEditorFeatureFlags, getEditorView, options) {
365
- var isTableFixedColumnWidthsOptionEnabled = arguments.length > 6 && arguments[6] !== undefined ? arguments[6] : false;
366
- var shouldUseIncreasedScalingPercent = arguments.length > 7 && arguments[7] !== undefined ? arguments[7] : false;
365
+ var getToolbarConfig = exports.getToolbarConfig = function getToolbarConfig(getEditorContainerWidth, api, editorAnalyticsAPI, getEditorView, options) {
366
+ var isTableFixedColumnWidthsOptionEnabled = arguments.length > 5 && arguments[5] !== undefined ? arguments[5] : false;
367
+ var shouldUseIncreasedScalingPercent = arguments.length > 6 && arguments[6] !== undefined ? arguments[6] : false;
367
368
  return function (config) {
368
369
  return function (state, intl) {
369
370
  var tableObject = (0, _utils3.findTable)(state.selection);
370
- var pluginState = (0, _pluginFactory.getPluginState)(state);
371
+ var pluginState = (0, _pluginFactory2.getPluginState)(state);
371
372
  var resizeState = _pluginKey.pluginKey.getState(state);
372
373
  var tableWidthState = _tableWidth.pluginKey.getState(state);
373
374
  var isTableScalingEnabled = (options === null || options === void 0 ? void 0 : options.isTableScalingEnabled) || false;
375
+ var nodeType = state.schema.nodes.table;
376
+ var toolbarTitle = 'Table floating controls';
377
+ if ((0, _experiments.editorExperiment)('platform_editor_controls', 'variant1') && (0, _platformFeatureFlags.fg)('platform_editor_controls_patch_4')) {
378
+ var _api$editorViewMode;
379
+ var isDragHandleMenuOpened = false;
380
+ var isTableRowOrColumnDragged = false;
381
+ if (options !== null && options !== void 0 && options.dragAndDropEnabled) {
382
+ var _getDragDropPluginSta = (0, _pluginFactory.getPluginState)(state),
383
+ _getDragDropPluginSta2 = _getDragDropPluginSta.isDragMenuOpen,
384
+ isDragMenuOpen = _getDragDropPluginSta2 === void 0 ? false : _getDragDropPluginSta2,
385
+ _getDragDropPluginSta3 = _getDragDropPluginSta.isDragging,
386
+ isDragging = _getDragDropPluginSta3 === void 0 ? false : _getDragDropPluginSta3;
387
+ isDragHandleMenuOpened = isDragMenuOpen;
388
+ isTableRowOrColumnDragged = isDragging;
389
+ }
390
+ var isTableOrColumnResizing = !!(resizeState !== null && resizeState !== void 0 && resizeState.dragging || tableWidthState !== null && tableWidthState !== void 0 && tableWidthState.resizing);
391
+ var isTableMenuOpened = pluginState.isContextualMenuOpen || isDragHandleMenuOpened;
392
+ var isViewMode = (api === null || api === void 0 || (_api$editorViewMode = api.editorViewMode) === null || _api$editorViewMode === void 0 || (_api$editorViewMode = _api$editorViewMode.sharedState.currentState()) === null || _api$editorViewMode === void 0 ? void 0 : _api$editorViewMode.mode) === 'view';
393
+ var shouldSuppressAllToolbars = !pluginState.editorHasFocus && !isViewMode || isTableMenuOpened || isTableOrColumnResizing || isTableRowOrColumnDragged;
394
+ if (shouldSuppressAllToolbars) {
395
+ return {
396
+ title: toolbarTitle,
397
+ items: [],
398
+ nodeType: nodeType,
399
+ __suppressAllToolbars: true
400
+ };
401
+ }
402
+ }
374
403
 
375
404
  // We don't want to show floating toolbar while resizing the table
376
405
  var isWidthResizing = tableWidthState === null || tableWidthState === void 0 ? void 0 : tableWidthState.resizing;
377
406
  if (tableObject && pluginState.editorHasFocus && !isWidthResizing) {
378
- var nodeType = state.schema.nodes.table;
379
407
  var isNested = pluginState.tablePos && (0, _nodes.isTableNested)(state, pluginState.tablePos);
380
408
  var isTableScalingWithFixedColumnWidthsOptionShown = isTableScalingEnabled && isTableFixedColumnWidthsOptionEnabled && !isNested;
381
409
  var areTableColumWidthsFixed = tableObject.node.attrs.displayMode === 'fixed';
@@ -463,7 +491,7 @@ var getToolbarConfig = exports.getToolbarConfig = function getToolbarConfig(getE
463
491
  } : undefined;
464
492
  };
465
493
  return {
466
- title: 'Table floating controls',
494
+ title: toolbarTitle,
467
495
  getDomRef: getDomRef,
468
496
  nodeType: nodeType,
469
497
  offset: [0, 18],
@@ -581,7 +609,7 @@ var getColumnSettingItems = function getColumnSettingItems(editorState, editorVi
581
609
  var isTableScalingEnabled = arguments.length > 6 && arguments[6] !== undefined ? arguments[6] : false;
582
610
  var isTableFixedColumnWidthsOptionEnabled = arguments.length > 7 && arguments[7] !== undefined ? arguments[7] : false;
583
611
  var isCommentEditor = arguments.length > 8 && arguments[8] !== undefined ? arguments[8] : false;
584
- var pluginState = (0, _pluginFactory.getPluginState)(editorState);
612
+ var pluginState = (0, _pluginFactory2.getPluginState)(editorState);
585
613
  var selectionOrTableRect = getClosestSelectionOrTableRect(editorState);
586
614
  if (!selectionOrTableRect || !editorView) {
587
615
  return [];
@@ -617,7 +645,7 @@ var getColumnSettingItems = function getColumnSettingItems(editorState, editorVi
617
645
  var getColorPicker = function getColorPicker(state, menu, _ref5, editorAnalyticsAPI, getEditorView) {
618
646
  var _node$attrs;
619
647
  var formatMessage = _ref5.formatMessage;
620
- var _getPluginState2 = (0, _pluginFactory.getPluginState)(state),
648
+ var _getPluginState2 = (0, _pluginFactory2.getPluginState)(state),
621
649
  targetCellPosition = _getPluginState2.targetCellPosition,
622
650
  pluginConfig = _getPluginState2.pluginConfig;
623
651
  if (!pluginConfig.allowBackgroundColor) {
@@ -17,6 +17,7 @@ import { pluginKey as tableWidthPluginKey } from '../pm-plugins/table-width';
17
17
  import { isTableNested } from '../pm-plugins/utils/nodes';
18
18
  import TableComponent from './TableComponent';
19
19
  import { TableComponentWithSharedState } from './TableComponentWithSharedState';
20
+ import { tableNodeSpecWithFixedToDOM } from './toDOM';
20
21
  const tableAttributes = node => {
21
22
  return {
22
23
  'data-number-column': node.attrs.isNumberColumnEnabled,
@@ -48,6 +49,8 @@ const handleInlineTableWidth = (table, width) => {
48
49
  }
49
50
  table.style.setProperty('width', `${width}px`);
50
51
  };
52
+
53
+ // Leave as a fallback incase the table's NodeSpec.toDOM is not defined.
51
54
  const toDOM = (node, props) => {
52
55
  let colgroup = '';
53
56
  if (props.allowColumnResizing) {
@@ -66,12 +69,31 @@ export default class TableView extends ReactNodeView {
66
69
  this.eventDispatcher = props.eventDispatcher;
67
70
  this.options = props.options;
68
71
  this.getEditorFeatureFlags = props.getEditorFeatureFlags;
72
+ if (fg('platform_editor_table_initial_load_fix')) {
73
+ this.handleRef = node => this._handleTableRef(node);
74
+ }
69
75
  }
70
76
  getContentDOM() {
71
- const rendered = DOMSerializer.renderSpec(document, toDOM(this.node, this.reactComponentProps));
77
+ let tableDOMStructure;
78
+ if (fg('platform_editor_table_initial_load_fix')) {
79
+ tableDOMStructure = tableNodeSpecWithFixedToDOM({
80
+ allowColumnResizing: !!this.reactComponentProps.allowColumnResizing,
81
+ tableResizingEnabled: !!this.reactComponentProps.allowTableResizing,
82
+ getEditorContainerWidth: this.reactComponentProps.getEditorContainerWidth
83
+ }).toDOM(this.node);
84
+ } else {
85
+ tableDOMStructure = toDOM(this.node, this.reactComponentProps);
86
+ }
87
+ const rendered = DOMSerializer.renderSpec(document, tableDOMStructure);
72
88
  if (rendered.dom) {
73
89
  var _this$options, _this$options2, _this$getEditorFeatur;
74
- this.table = rendered.dom;
90
+ if (fg('platform_editor_table_initial_load_fix')) {
91
+ const tableElement = rendered.dom.querySelector('table');
92
+ this.table = tableElement ? tableElement : rendered.dom;
93
+ this.renderedDOM = rendered.dom;
94
+ } else {
95
+ this.table = rendered.dom;
96
+ }
75
97
  if (!((_this$options = this.options) !== null && _this$options !== void 0 && _this$options.isTableScalingEnabled) || (_this$options2 = this.options) !== null && _this$options2 !== void 0 && _this$options2.isTableScalingEnabled && (_this$getEditorFeatur = this.getEditorFeatureFlags) !== null && _this$getEditorFeatur !== void 0 && _this$getEditorFeatur.call(this).tableWithFixedColumnWidthsOption && this.node.attrs.displayMode === 'fixed') {
76
98
  const tableInlineWidth = getInlineWidth(this.node, this.reactComponentProps.options, this.reactComponentProps.view.state, this.reactComponentProps.getPos(), this.reactComponentProps.allowTableResizing);
77
99
  if (tableInlineWidth) {
@@ -81,6 +103,72 @@ export default class TableView extends ReactNodeView {
81
103
  }
82
104
  return rendered;
83
105
  }
106
+
107
+ /**
108
+ * Handles moving the table from ProseMirror's DOM structure into a React-rendered table node.
109
+ * Temporarily disables mutation observers (except for selection changes) during the move,
110
+ * preserves selection state, and restores it afterwards if mutations occurred and cursor
111
+ * wasn't at start of node. This prevents duplicate tables and maintains editor state during
112
+ * the DOM manipulation.
113
+ */
114
+ _handleTableRef(node) {
115
+ let oldIgnoreMutation;
116
+ let selectionBookmark;
117
+ let parentOffset = 0;
118
+ let mutationsIgnored = false;
119
+
120
+ // Only proceed if we have both a node and table, and the table isn't already inside the node
121
+ if (node && this.table && !node.contains(this.table)) {
122
+ var _this$view$state$sele;
123
+ // Store the current ignoreMutation handler so we can restore it later
124
+ oldIgnoreMutation = this.ignoreMutation;
125
+
126
+ // Set up a temporary mutation handler that:
127
+ // - Ignores all DOM mutations except selection changes
128
+ // - Tracks when mutations have been ignored via mutationsIgnored flag
129
+ this.ignoreMutation = m => {
130
+ const isSelectionMutation = m.target instanceof Selection;
131
+ if (!isSelectionMutation) {
132
+ mutationsIgnored = true;
133
+ }
134
+ return !isSelectionMutation;
135
+ };
136
+
137
+ // Store the current selection state if there is a visible selection
138
+ // This lets us restore it after DOM changes
139
+ if (this.view.state.selection.visible) {
140
+ selectionBookmark = this.view.state.selection.getBookmark();
141
+ }
142
+
143
+ // Store the current cursor position within the parent node
144
+ // Used to determine if we need to restore selection later
145
+ if (((_this$view$state$sele = this.view.state.selection) === null || _this$view$state$sele === void 0 ? void 0 : _this$view$state$sele.ranges.length) > 0) {
146
+ var _this$view$state$sele2, _this$view$state$sele3, _this$view$state$sele4;
147
+ parentOffset = (_this$view$state$sele2 = (_this$view$state$sele3 = this.view.state.selection) === null || _this$view$state$sele3 === void 0 ? void 0 : (_this$view$state$sele4 = _this$view$state$sele3.ranges[0].$from) === null || _this$view$state$sele4 === void 0 ? void 0 : _this$view$state$sele4.parentOffset) !== null && _this$view$state$sele2 !== void 0 ? _this$view$state$sele2 : 0;
148
+ }
149
+
150
+ // Remove the ProseMirror table DOM structure to avoid duplication, as it's replaced with the React table node.
151
+ if (this.renderedDOM) {
152
+ this.dom.removeChild(this.renderedDOM);
153
+ }
154
+ // Move the table from the ProseMirror table structure into the React rendered table node.
155
+ node.appendChild(this.table);
156
+
157
+ // After the next frame:
158
+ requestAnimationFrame(() => {
159
+ // Restore the original mutation handler
160
+ this.ignoreMutation = oldIgnoreMutation;
161
+
162
+ // Restore the selection only if:
163
+ // - We have a selection bookmark
164
+ // - Mutations were ignored during the table move
165
+ // - The cursor wasn't at the start of the node
166
+ if (selectionBookmark && mutationsIgnored && parentOffset > 0) {
167
+ this.view.dispatch(this.view.state.tr.setSelection(selectionBookmark.resolve(this.view.state.tr.doc)));
168
+ }
169
+ });
170
+ }
171
+ }
84
172
  setDomAttrs(node) {
85
173
  var _this$options3, _this$options4, _this$getEditorFeatur2;
86
174
  if (!this.table) {
@@ -122,7 +210,6 @@ export default class TableView extends ReactNodeView {
122
210
  dispatchAnalyticsEvent: props.dispatchAnalyticsEvent
123
211
  });
124
212
  }
125
-
126
213
  // Please, do not copy or use this kind of code below
127
214
  // @ts-ignore
128
215
  const fakePluginKey = {
@@ -605,7 +605,7 @@ const tablesPlugin = ({
605
605
  return tr;
606
606
  }
607
607
  }],
608
- floatingToolbar: getToolbarConfig(defaultGetEditorContainerWidth, api, editorAnalyticsAPI, (options === null || options === void 0 ? void 0 : options.getEditorFeatureFlags) || defaultGetEditorFeatureFlags, () => editorViewRef.current, options, isTableFixedColumnWidthsOptionEnabled, shouldUseIncreasedScalingPercent)(pluginConfig(options === null || options === void 0 ? void 0 : options.tableOptions))
608
+ floatingToolbar: getToolbarConfig(defaultGetEditorContainerWidth, api, editorAnalyticsAPI, () => editorViewRef.current, options, isTableFixedColumnWidthsOptionEnabled, shouldUseIncreasedScalingPercent)(pluginConfig(options === null || options === void 0 ? void 0 : options.tableOptions))
609
609
  },
610
610
  usePluginHook({
611
611
  editorView
@@ -32,6 +32,7 @@ import { fg } from '@atlaskit/platform-feature-flags';
32
32
  import { editorExperiment } from '@atlaskit/tmp-editor-statsig/experiments';
33
33
  import { clearHoverSelection, hoverColumns, hoverMergedCells, hoverRows, hoverTable, removeDescendantNodes } from '../pm-plugins/commands';
34
34
  import { deleteColumnsWithAnalytics, deleteRowsWithAnalytics, deleteTableWithAnalytics, distributeColumnsWidthsWithAnalytics, emptyMultipleCellsWithAnalytics, insertColumnWithAnalytics, insertRowWithAnalytics, mergeCellsWithAnalytics, setColorWithAnalytics, setTableAlignmentWithAnalytics, sortColumnWithAnalytics, splitCellWithAnalytics, toggleFixedColumnWidthsOptionAnalytics, toggleHeaderColumnWithAnalytics, toggleHeaderRowWithAnalytics, toggleNumberColumnWithAnalytics, wrapTableInExpandWithAnalytics } from '../pm-plugins/commands/commands-with-analytics';
35
+ import { getPluginState as getDragDropPluginState } from '../pm-plugins/drag-and-drop/plugin-factory';
35
36
  import { getPluginState } from '../pm-plugins/plugin-factory';
36
37
  import { pluginKey as tableResizingPluginKey } from '../pm-plugins/table-resizing/plugin-key';
37
38
  import { getStaticTableScalingPercent } from '../pm-plugins/table-resizing/utils/misc';
@@ -344,17 +345,43 @@ const getClosestSelectionOrTableRect = state => {
344
345
  // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
345
346
  return isSelectionType(selection, 'cell') ? getSelectionRect(selection) : tableRect;
346
347
  };
347
- export const getToolbarConfig = (getEditorContainerWidth, api, editorAnalyticsAPI, getEditorFeatureFlags, getEditorView, options, isTableFixedColumnWidthsOptionEnabled = false, shouldUseIncreasedScalingPercent = false) => config => (state, intl) => {
348
+ export const getToolbarConfig = (getEditorContainerWidth, api, editorAnalyticsAPI, getEditorView, options, isTableFixedColumnWidthsOptionEnabled = false, shouldUseIncreasedScalingPercent = false) => config => (state, intl) => {
348
349
  const tableObject = findTable(state.selection);
349
350
  const pluginState = getPluginState(state);
350
351
  const resizeState = tableResizingPluginKey.getState(state);
351
352
  const tableWidthState = tableWidthPluginKey.getState(state);
352
353
  const isTableScalingEnabled = (options === null || options === void 0 ? void 0 : options.isTableScalingEnabled) || false;
354
+ const nodeType = state.schema.nodes.table;
355
+ const toolbarTitle = 'Table floating controls';
356
+ if (editorExperiment('platform_editor_controls', 'variant1') && fg('platform_editor_controls_patch_4')) {
357
+ var _api$editorViewMode, _api$editorViewMode$s;
358
+ let isDragHandleMenuOpened = false;
359
+ let isTableRowOrColumnDragged = false;
360
+ if (options !== null && options !== void 0 && options.dragAndDropEnabled) {
361
+ const {
362
+ isDragMenuOpen = false,
363
+ isDragging = false
364
+ } = getDragDropPluginState(state);
365
+ isDragHandleMenuOpened = isDragMenuOpen;
366
+ isTableRowOrColumnDragged = isDragging;
367
+ }
368
+ const isTableOrColumnResizing = !!(resizeState !== null && resizeState !== void 0 && resizeState.dragging || tableWidthState !== null && tableWidthState !== void 0 && tableWidthState.resizing);
369
+ const isTableMenuOpened = pluginState.isContextualMenuOpen || isDragHandleMenuOpened;
370
+ const isViewMode = (api === null || api === void 0 ? void 0 : (_api$editorViewMode = api.editorViewMode) === null || _api$editorViewMode === void 0 ? void 0 : (_api$editorViewMode$s = _api$editorViewMode.sharedState.currentState()) === null || _api$editorViewMode$s === void 0 ? void 0 : _api$editorViewMode$s.mode) === 'view';
371
+ const shouldSuppressAllToolbars = !pluginState.editorHasFocus && !isViewMode || isTableMenuOpened || isTableOrColumnResizing || isTableRowOrColumnDragged;
372
+ if (shouldSuppressAllToolbars) {
373
+ return {
374
+ title: toolbarTitle,
375
+ items: [],
376
+ nodeType,
377
+ __suppressAllToolbars: true
378
+ };
379
+ }
380
+ }
353
381
 
354
382
  // We don't want to show floating toolbar while resizing the table
355
383
  const isWidthResizing = tableWidthState === null || tableWidthState === void 0 ? void 0 : tableWidthState.resizing;
356
384
  if (tableObject && pluginState.editorHasFocus && !isWidthResizing) {
357
- const nodeType = state.schema.nodes.table;
358
385
  const isNested = pluginState.tablePos && isTableNested(state, pluginState.tablePos);
359
386
  const isTableScalingWithFixedColumnWidthsOptionShown = isTableScalingEnabled && isTableFixedColumnWidthsOptionEnabled && !isNested;
360
387
  const areTableColumWidthsFixed = tableObject.node.attrs.displayMode === 'fixed';
@@ -433,7 +460,7 @@ export const getToolbarConfig = (getEditorContainerWidth, api, editorAnalyticsAP
433
460
  onBlur: clearHoverSelection()
434
461
  } : undefined;
435
462
  return {
436
- title: 'Table floating controls',
463
+ title: toolbarTitle,
437
464
  getDomRef,
438
465
  nodeType,
439
466
  offset: [0, 18],
@@ -28,6 +28,7 @@ import { pluginKey as tableWidthPluginKey } from '../pm-plugins/table-width';
28
28
  import { isTableNested } from '../pm-plugins/utils/nodes';
29
29
  import TableComponent from './TableComponent';
30
30
  import { TableComponentWithSharedState } from './TableComponentWithSharedState';
31
+ import { tableNodeSpecWithFixedToDOM } from './toDOM';
31
32
  var tableAttributes = function tableAttributes(node) {
32
33
  return {
33
34
  'data-number-column': node.attrs.isNumberColumnEnabled,
@@ -59,6 +60,8 @@ var handleInlineTableWidth = function handleInlineTableWidth(table, width) {
59
60
  }
60
61
  table.style.setProperty('width', "".concat(width, "px"));
61
62
  };
63
+
64
+ // Leave as a fallback incase the table's NodeSpec.toDOM is not defined.
62
65
  var toDOM = function toDOM(node, props) {
63
66
  var colgroup = '';
64
67
  if (props.allowColumnResizing) {
@@ -79,16 +82,37 @@ var TableView = /*#__PURE__*/function (_ReactNodeView) {
79
82
  _this.eventDispatcher = props.eventDispatcher;
80
83
  _this.options = props.options;
81
84
  _this.getEditorFeatureFlags = props.getEditorFeatureFlags;
85
+ if (fg('platform_editor_table_initial_load_fix')) {
86
+ _this.handleRef = function (node) {
87
+ return _this._handleTableRef(node);
88
+ };
89
+ }
82
90
  return _this;
83
91
  }
84
92
  _inherits(TableView, _ReactNodeView);
85
93
  return _createClass(TableView, [{
86
94
  key: "getContentDOM",
87
95
  value: function getContentDOM() {
88
- var rendered = DOMSerializer.renderSpec(document, toDOM(this.node, this.reactComponentProps));
96
+ var tableDOMStructure;
97
+ if (fg('platform_editor_table_initial_load_fix')) {
98
+ tableDOMStructure = tableNodeSpecWithFixedToDOM({
99
+ allowColumnResizing: !!this.reactComponentProps.allowColumnResizing,
100
+ tableResizingEnabled: !!this.reactComponentProps.allowTableResizing,
101
+ getEditorContainerWidth: this.reactComponentProps.getEditorContainerWidth
102
+ }).toDOM(this.node);
103
+ } else {
104
+ tableDOMStructure = toDOM(this.node, this.reactComponentProps);
105
+ }
106
+ var rendered = DOMSerializer.renderSpec(document, tableDOMStructure);
89
107
  if (rendered.dom) {
90
108
  var _this$options, _this$options2, _this$getEditorFeatur;
91
- this.table = rendered.dom;
109
+ if (fg('platform_editor_table_initial_load_fix')) {
110
+ var tableElement = rendered.dom.querySelector('table');
111
+ this.table = tableElement ? tableElement : rendered.dom;
112
+ this.renderedDOM = rendered.dom;
113
+ } else {
114
+ this.table = rendered.dom;
115
+ }
92
116
  if (!((_this$options = this.options) !== null && _this$options !== void 0 && _this$options.isTableScalingEnabled) || (_this$options2 = this.options) !== null && _this$options2 !== void 0 && _this$options2.isTableScalingEnabled && (_this$getEditorFeatur = this.getEditorFeatureFlags) !== null && _this$getEditorFeatur !== void 0 && _this$getEditorFeatur.call(this).tableWithFixedColumnWidthsOption && this.node.attrs.displayMode === 'fixed') {
93
117
  var tableInlineWidth = getInlineWidth(this.node, this.reactComponentProps.options, this.reactComponentProps.view.state, this.reactComponentProps.getPos(), this.reactComponentProps.allowTableResizing);
94
118
  if (tableInlineWidth) {
@@ -98,10 +122,79 @@ var TableView = /*#__PURE__*/function (_ReactNodeView) {
98
122
  }
99
123
  return rendered;
100
124
  }
125
+
126
+ /**
127
+ * Handles moving the table from ProseMirror's DOM structure into a React-rendered table node.
128
+ * Temporarily disables mutation observers (except for selection changes) during the move,
129
+ * preserves selection state, and restores it afterwards if mutations occurred and cursor
130
+ * wasn't at start of node. This prevents duplicate tables and maintains editor state during
131
+ * the DOM manipulation.
132
+ */
133
+ }, {
134
+ key: "_handleTableRef",
135
+ value: function _handleTableRef(node) {
136
+ var _this2 = this;
137
+ var oldIgnoreMutation;
138
+ var selectionBookmark;
139
+ var parentOffset = 0;
140
+ var mutationsIgnored = false;
141
+
142
+ // Only proceed if we have both a node and table, and the table isn't already inside the node
143
+ if (node && this.table && !node.contains(this.table)) {
144
+ var _this$view$state$sele;
145
+ // Store the current ignoreMutation handler so we can restore it later
146
+ oldIgnoreMutation = this.ignoreMutation;
147
+
148
+ // Set up a temporary mutation handler that:
149
+ // - Ignores all DOM mutations except selection changes
150
+ // - Tracks when mutations have been ignored via mutationsIgnored flag
151
+ this.ignoreMutation = function (m) {
152
+ var isSelectionMutation = m.target instanceof Selection;
153
+ if (!isSelectionMutation) {
154
+ mutationsIgnored = true;
155
+ }
156
+ return !isSelectionMutation;
157
+ };
158
+
159
+ // Store the current selection state if there is a visible selection
160
+ // This lets us restore it after DOM changes
161
+ if (this.view.state.selection.visible) {
162
+ selectionBookmark = this.view.state.selection.getBookmark();
163
+ }
164
+
165
+ // Store the current cursor position within the parent node
166
+ // Used to determine if we need to restore selection later
167
+ if (((_this$view$state$sele = this.view.state.selection) === null || _this$view$state$sele === void 0 ? void 0 : _this$view$state$sele.ranges.length) > 0) {
168
+ var _this$view$state$sele2, _this$view$state$sele3;
169
+ parentOffset = (_this$view$state$sele2 = (_this$view$state$sele3 = this.view.state.selection) === null || _this$view$state$sele3 === void 0 || (_this$view$state$sele3 = _this$view$state$sele3.ranges[0].$from) === null || _this$view$state$sele3 === void 0 ? void 0 : _this$view$state$sele3.parentOffset) !== null && _this$view$state$sele2 !== void 0 ? _this$view$state$sele2 : 0;
170
+ }
171
+
172
+ // Remove the ProseMirror table DOM structure to avoid duplication, as it's replaced with the React table node.
173
+ if (this.renderedDOM) {
174
+ this.dom.removeChild(this.renderedDOM);
175
+ }
176
+ // Move the table from the ProseMirror table structure into the React rendered table node.
177
+ node.appendChild(this.table);
178
+
179
+ // After the next frame:
180
+ requestAnimationFrame(function () {
181
+ // Restore the original mutation handler
182
+ _this2.ignoreMutation = oldIgnoreMutation;
183
+
184
+ // Restore the selection only if:
185
+ // - We have a selection bookmark
186
+ // - Mutations were ignored during the table move
187
+ // - The cursor wasn't at the start of the node
188
+ if (selectionBookmark && mutationsIgnored && parentOffset > 0) {
189
+ _this2.view.dispatch(_this2.view.state.tr.setSelection(selectionBookmark.resolve(_this2.view.state.tr.doc)));
190
+ }
191
+ });
192
+ }
193
+ }
101
194
  }, {
102
195
  key: "setDomAttrs",
103
196
  value: function setDomAttrs(node) {
104
- var _this2 = this,
197
+ var _this3 = this,
105
198
  _this$options3,
106
199
  _this$options4,
107
200
  _this$getEditorFeatur2;
@@ -112,7 +205,7 @@ var TableView = /*#__PURE__*/function (_ReactNodeView) {
112
205
  Object.keys(attrs).forEach(function (attr) {
113
206
  // Ignored via go/ees005
114
207
  // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
115
- _this2.table.setAttribute(attr, attrs[attr]);
208
+ _this3.table.setAttribute(attr, attrs[attr]);
116
209
  });
117
210
 
118
211
  // Preserve Table Width cannot have inline width set on the table
@@ -129,7 +222,7 @@ var TableView = /*#__PURE__*/function (_ReactNodeView) {
129
222
  }, {
130
223
  key: "render",
131
224
  value: function render(props, forwardRef) {
132
- var _this3 = this;
225
+ var _this4 = this;
133
226
  if (fg('platform_editor_table_use_shared_state_hook_fg')) {
134
227
  return /*#__PURE__*/React.createElement(TableComponentWithSharedState, {
135
228
  forwardRef: forwardRef,
@@ -147,7 +240,6 @@ var TableView = /*#__PURE__*/function (_ReactNodeView) {
147
240
  dispatchAnalyticsEvent: props.dispatchAnalyticsEvent
148
241
  });
149
242
  }
150
-
151
243
  // Please, do not copy or use this kind of code below
152
244
  // @ts-ignore
153
245
  var fakePluginKey = {
@@ -239,7 +331,7 @@ var TableView = /*#__PURE__*/function (_ReactNodeView) {
239
331
  ,
240
332
  ordering: pluginState.ordering,
241
333
  isResizing: isResizing,
242
- getNode: _this3.getNode
334
+ getNode: _this4.getNode
243
335
  // Ignored via go/ees005
244
336
  // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
245
337
  ,
@@ -601,7 +601,7 @@ var tablesPlugin = function tablesPlugin(_ref) {
601
601
  }
602
602
  }];
603
603
  },
604
- floatingToolbar: getToolbarConfig(defaultGetEditorContainerWidth, api, editorAnalyticsAPI, (options === null || options === void 0 ? void 0 : options.getEditorFeatureFlags) || defaultGetEditorFeatureFlags, function () {
604
+ floatingToolbar: getToolbarConfig(defaultGetEditorContainerWidth, api, editorAnalyticsAPI, function () {
605
605
  return editorViewRef.current;
606
606
  }, options, isTableFixedColumnWidthsOptionEnabled, shouldUseIncreasedScalingPercent)(pluginConfig(options === null || options === void 0 ? void 0 : options.tableOptions))
607
607
  },
@@ -36,6 +36,7 @@ import { fg } from '@atlaskit/platform-feature-flags';
36
36
  import { editorExperiment } from '@atlaskit/tmp-editor-statsig/experiments';
37
37
  import { clearHoverSelection, hoverColumns, hoverMergedCells, hoverRows, hoverTable, removeDescendantNodes } from '../pm-plugins/commands';
38
38
  import { deleteColumnsWithAnalytics, deleteRowsWithAnalytics, deleteTableWithAnalytics, distributeColumnsWidthsWithAnalytics, emptyMultipleCellsWithAnalytics, insertColumnWithAnalytics, insertRowWithAnalytics, mergeCellsWithAnalytics, setColorWithAnalytics, setTableAlignmentWithAnalytics, sortColumnWithAnalytics, splitCellWithAnalytics, toggleFixedColumnWidthsOptionAnalytics, toggleHeaderColumnWithAnalytics, toggleHeaderRowWithAnalytics, toggleNumberColumnWithAnalytics, wrapTableInExpandWithAnalytics } from '../pm-plugins/commands/commands-with-analytics';
39
+ import { getPluginState as getDragDropPluginState } from '../pm-plugins/drag-and-drop/plugin-factory';
39
40
  import { getPluginState } from '../pm-plugins/plugin-factory';
40
41
  import { pluginKey as tableResizingPluginKey } from '../pm-plugins/table-resizing/plugin-key';
41
42
  import { getStaticTableScalingPercent } from '../pm-plugins/table-resizing/utils/misc';
@@ -353,9 +354,9 @@ var getClosestSelectionOrTableRect = function getClosestSelectionOrTableRect(sta
353
354
  // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
354
355
  return isSelectionType(selection, 'cell') ? getSelectionRect(selection) : tableRect;
355
356
  };
356
- export var getToolbarConfig = function getToolbarConfig(getEditorContainerWidth, api, editorAnalyticsAPI, getEditorFeatureFlags, getEditorView, options) {
357
- var isTableFixedColumnWidthsOptionEnabled = arguments.length > 6 && arguments[6] !== undefined ? arguments[6] : false;
358
- var shouldUseIncreasedScalingPercent = arguments.length > 7 && arguments[7] !== undefined ? arguments[7] : false;
357
+ export var getToolbarConfig = function getToolbarConfig(getEditorContainerWidth, api, editorAnalyticsAPI, getEditorView, options) {
358
+ var isTableFixedColumnWidthsOptionEnabled = arguments.length > 5 && arguments[5] !== undefined ? arguments[5] : false;
359
+ var shouldUseIncreasedScalingPercent = arguments.length > 6 && arguments[6] !== undefined ? arguments[6] : false;
359
360
  return function (config) {
360
361
  return function (state, intl) {
361
362
  var tableObject = findTable(state.selection);
@@ -363,11 +364,38 @@ export var getToolbarConfig = function getToolbarConfig(getEditorContainerWidth,
363
364
  var resizeState = tableResizingPluginKey.getState(state);
364
365
  var tableWidthState = tableWidthPluginKey.getState(state);
365
366
  var isTableScalingEnabled = (options === null || options === void 0 ? void 0 : options.isTableScalingEnabled) || false;
367
+ var nodeType = state.schema.nodes.table;
368
+ var toolbarTitle = 'Table floating controls';
369
+ if (editorExperiment('platform_editor_controls', 'variant1') && fg('platform_editor_controls_patch_4')) {
370
+ var _api$editorViewMode;
371
+ var isDragHandleMenuOpened = false;
372
+ var isTableRowOrColumnDragged = false;
373
+ if (options !== null && options !== void 0 && options.dragAndDropEnabled) {
374
+ var _getDragDropPluginSta = getDragDropPluginState(state),
375
+ _getDragDropPluginSta2 = _getDragDropPluginSta.isDragMenuOpen,
376
+ isDragMenuOpen = _getDragDropPluginSta2 === void 0 ? false : _getDragDropPluginSta2,
377
+ _getDragDropPluginSta3 = _getDragDropPluginSta.isDragging,
378
+ isDragging = _getDragDropPluginSta3 === void 0 ? false : _getDragDropPluginSta3;
379
+ isDragHandleMenuOpened = isDragMenuOpen;
380
+ isTableRowOrColumnDragged = isDragging;
381
+ }
382
+ var isTableOrColumnResizing = !!(resizeState !== null && resizeState !== void 0 && resizeState.dragging || tableWidthState !== null && tableWidthState !== void 0 && tableWidthState.resizing);
383
+ var isTableMenuOpened = pluginState.isContextualMenuOpen || isDragHandleMenuOpened;
384
+ var isViewMode = (api === null || api === void 0 || (_api$editorViewMode = api.editorViewMode) === null || _api$editorViewMode === void 0 || (_api$editorViewMode = _api$editorViewMode.sharedState.currentState()) === null || _api$editorViewMode === void 0 ? void 0 : _api$editorViewMode.mode) === 'view';
385
+ var shouldSuppressAllToolbars = !pluginState.editorHasFocus && !isViewMode || isTableMenuOpened || isTableOrColumnResizing || isTableRowOrColumnDragged;
386
+ if (shouldSuppressAllToolbars) {
387
+ return {
388
+ title: toolbarTitle,
389
+ items: [],
390
+ nodeType: nodeType,
391
+ __suppressAllToolbars: true
392
+ };
393
+ }
394
+ }
366
395
 
367
396
  // We don't want to show floating toolbar while resizing the table
368
397
  var isWidthResizing = tableWidthState === null || tableWidthState === void 0 ? void 0 : tableWidthState.resizing;
369
398
  if (tableObject && pluginState.editorHasFocus && !isWidthResizing) {
370
- var nodeType = state.schema.nodes.table;
371
399
  var isNested = pluginState.tablePos && isTableNested(state, pluginState.tablePos);
372
400
  var isTableScalingWithFixedColumnWidthsOptionShown = isTableScalingEnabled && isTableFixedColumnWidthsOptionEnabled && !isNested;
373
401
  var areTableColumWidthsFixed = tableObject.node.attrs.displayMode === 'fixed';
@@ -455,7 +483,7 @@ export var getToolbarConfig = function getToolbarConfig(getEditorContainerWidth,
455
483
  } : undefined;
456
484
  };
457
485
  return {
458
- title: 'Table floating controls',
486
+ title: toolbarTitle,
459
487
  getDomRef: getDomRef,
460
488
  nodeType: nodeType,
461
489
  offset: [0, 18],
@@ -11,6 +11,7 @@ import type { Props } from './types';
11
11
  type ForwardRef = (node: HTMLElement | null) => void;
12
12
  export default class TableView extends ReactNodeView<Props> {
13
13
  private table;
14
+ private renderedDOM?;
14
15
  private resizeObserver?;
15
16
  eventDispatcher?: EventDispatcher;
16
17
  getPos: getPosHandlerNode;
@@ -21,6 +22,14 @@ export default class TableView extends ReactNodeView<Props> {
21
22
  dom: HTMLElement;
22
23
  contentDOM?: HTMLElement | undefined;
23
24
  };
25
+ /**
26
+ * Handles moving the table from ProseMirror's DOM structure into a React-rendered table node.
27
+ * Temporarily disables mutation observers (except for selection changes) during the move,
28
+ * preserves selection state, and restores it afterwards if mutations occurred and cursor
29
+ * wasn't at start of node. This prevents duplicate tables and maintains editor state during
30
+ * the DOM manipulation.
31
+ */
32
+ private _handleTableRef;
24
33
  setDomAttrs(node: PmNode): void;
25
34
  getNode: () => PmNode;
26
35
  render(props: Props, forwardRef: ForwardRef): React.JSX.Element;
@@ -1,10 +1,12 @@
1
1
  import type { GetEditorContainerWidth } from '@atlaskit/editor-common/types';
2
- import type { NodeSpec } from '@atlaskit/editor-prosemirror/model';
2
+ import type { DOMOutputSpec, NodeSpec, Node as PMNode } from '@atlaskit/editor-prosemirror/model';
3
3
  type Config = {
4
4
  allowColumnResizing: boolean;
5
5
  tableResizingEnabled: boolean;
6
6
  getEditorContainerWidth: GetEditorContainerWidth;
7
7
  isNestingSupported?: boolean;
8
8
  };
9
- export declare const tableNodeSpecWithFixedToDOM: (config: Config) => NodeSpec;
9
+ export declare const tableNodeSpecWithFixedToDOM: (config: Config) => NodeSpec & {
10
+ toDOM: (node: PMNode) => DOMOutputSpec;
11
+ };
10
12
  export {};
@@ -1,5 +1,5 @@
1
1
  import type { EditorAnalyticsAPI } from '@atlaskit/editor-common/analytics';
2
- import type { Command, FloatingToolbarDropdown, FloatingToolbarHandler, FloatingToolbarItem, GetEditorContainerWidth, GetEditorFeatureFlags } from '@atlaskit/editor-common/types';
2
+ import type { Command, FloatingToolbarDropdown, FloatingToolbarHandler, FloatingToolbarItem, GetEditorContainerWidth } from '@atlaskit/editor-common/types';
3
3
  import type { EditorState } from '@atlaskit/editor-prosemirror/state';
4
4
  import type { EditorView } from '@atlaskit/editor-prosemirror/view';
5
5
  import { Rect } from '@atlaskit/editor-tables/table-map';
@@ -8,4 +8,4 @@ import type { PluginConfig, PluginInjectionAPI, ToolbarMenuConfig, ToolbarMenuCo
8
8
  export declare const getToolbarMenuConfig: (config: ToolbarMenuConfig, state: ToolbarMenuState, { formatMessage }: ToolbarMenuContext, editorAnalyticsAPI: EditorAnalyticsAPI | undefined | null, isTableScalingWithFixedColumnWidthsOptionShown?: boolean, areTableColumnWidthsFixed?: boolean) => FloatingToolbarItem<Command>;
9
9
  export declare const getToolbarCellOptionsConfig: (editorState: EditorState, editorView: EditorView | undefined | null, initialSelectionRect: Rect, { formatMessage }: ToolbarMenuContext, getEditorContainerWidth: GetEditorContainerWidth, api: PluginInjectionAPI | undefined | null, editorAnalyticsAPI: EditorAnalyticsAPI | undefined | null, isTableScalingEnabled?: boolean, isTableFixedColumnWidthsOptionEnabled?: boolean, shouldUseIncreasedScalingPercent?: boolean, isCommentEditor?: boolean) => FloatingToolbarDropdown<Command>;
10
10
  export declare const getClosestSelectionRect: (state: EditorState) => Rect | undefined;
11
- export declare const getToolbarConfig: (getEditorContainerWidth: GetEditorContainerWidth, api: PluginInjectionAPI | undefined | null, editorAnalyticsAPI: EditorAnalyticsAPI | undefined | null, getEditorFeatureFlags: GetEditorFeatureFlags, getEditorView: () => EditorView | null, options?: TablePluginOptions, isTableFixedColumnWidthsOptionEnabled?: boolean, shouldUseIncreasedScalingPercent?: boolean) => (config: PluginConfig) => FloatingToolbarHandler;
11
+ export declare const getToolbarConfig: (getEditorContainerWidth: GetEditorContainerWidth, api: PluginInjectionAPI | undefined | null, editorAnalyticsAPI: EditorAnalyticsAPI | undefined | null, getEditorView: () => EditorView | null, options?: TablePluginOptions, isTableFixedColumnWidthsOptionEnabled?: boolean, shouldUseIncreasedScalingPercent?: boolean) => (config: PluginConfig) => FloatingToolbarHandler;
@@ -11,6 +11,7 @@ import type { Props } from './types';
11
11
  type ForwardRef = (node: HTMLElement | null) => void;
12
12
  export default class TableView extends ReactNodeView<Props> {
13
13
  private table;
14
+ private renderedDOM?;
14
15
  private resizeObserver?;
15
16
  eventDispatcher?: EventDispatcher;
16
17
  getPos: getPosHandlerNode;
@@ -21,6 +22,14 @@ export default class TableView extends ReactNodeView<Props> {
21
22
  dom: HTMLElement;
22
23
  contentDOM?: HTMLElement | undefined;
23
24
  };
25
+ /**
26
+ * Handles moving the table from ProseMirror's DOM structure into a React-rendered table node.
27
+ * Temporarily disables mutation observers (except for selection changes) during the move,
28
+ * preserves selection state, and restores it afterwards if mutations occurred and cursor
29
+ * wasn't at start of node. This prevents duplicate tables and maintains editor state during
30
+ * the DOM manipulation.
31
+ */
32
+ private _handleTableRef;
24
33
  setDomAttrs(node: PmNode): void;
25
34
  getNode: () => PmNode;
26
35
  render(props: Props, forwardRef: ForwardRef): React.JSX.Element;
@@ -1,10 +1,12 @@
1
1
  import type { GetEditorContainerWidth } from '@atlaskit/editor-common/types';
2
- import type { NodeSpec } from '@atlaskit/editor-prosemirror/model';
2
+ import type { DOMOutputSpec, NodeSpec, Node as PMNode } from '@atlaskit/editor-prosemirror/model';
3
3
  type Config = {
4
4
  allowColumnResizing: boolean;
5
5
  tableResizingEnabled: boolean;
6
6
  getEditorContainerWidth: GetEditorContainerWidth;
7
7
  isNestingSupported?: boolean;
8
8
  };
9
- export declare const tableNodeSpecWithFixedToDOM: (config: Config) => NodeSpec;
9
+ export declare const tableNodeSpecWithFixedToDOM: (config: Config) => NodeSpec & {
10
+ toDOM: (node: PMNode) => DOMOutputSpec;
11
+ };
10
12
  export {};
@@ -1,5 +1,5 @@
1
1
  import type { EditorAnalyticsAPI } from '@atlaskit/editor-common/analytics';
2
- import type { Command, FloatingToolbarDropdown, FloatingToolbarHandler, FloatingToolbarItem, GetEditorContainerWidth, GetEditorFeatureFlags } from '@atlaskit/editor-common/types';
2
+ import type { Command, FloatingToolbarDropdown, FloatingToolbarHandler, FloatingToolbarItem, GetEditorContainerWidth } from '@atlaskit/editor-common/types';
3
3
  import type { EditorState } from '@atlaskit/editor-prosemirror/state';
4
4
  import type { EditorView } from '@atlaskit/editor-prosemirror/view';
5
5
  import { Rect } from '@atlaskit/editor-tables/table-map';
@@ -8,4 +8,4 @@ import type { PluginConfig, PluginInjectionAPI, ToolbarMenuConfig, ToolbarMenuCo
8
8
  export declare const getToolbarMenuConfig: (config: ToolbarMenuConfig, state: ToolbarMenuState, { formatMessage }: ToolbarMenuContext, editorAnalyticsAPI: EditorAnalyticsAPI | undefined | null, isTableScalingWithFixedColumnWidthsOptionShown?: boolean, areTableColumnWidthsFixed?: boolean) => FloatingToolbarItem<Command>;
9
9
  export declare const getToolbarCellOptionsConfig: (editorState: EditorState, editorView: EditorView | undefined | null, initialSelectionRect: Rect, { formatMessage }: ToolbarMenuContext, getEditorContainerWidth: GetEditorContainerWidth, api: PluginInjectionAPI | undefined | null, editorAnalyticsAPI: EditorAnalyticsAPI | undefined | null, isTableScalingEnabled?: boolean, isTableFixedColumnWidthsOptionEnabled?: boolean, shouldUseIncreasedScalingPercent?: boolean, isCommentEditor?: boolean) => FloatingToolbarDropdown<Command>;
10
10
  export declare const getClosestSelectionRect: (state: EditorState) => Rect | undefined;
11
- export declare const getToolbarConfig: (getEditorContainerWidth: GetEditorContainerWidth, api: PluginInjectionAPI | undefined | null, editorAnalyticsAPI: EditorAnalyticsAPI | undefined | null, getEditorFeatureFlags: GetEditorFeatureFlags, getEditorView: () => EditorView | null, options?: TablePluginOptions, isTableFixedColumnWidthsOptionEnabled?: boolean, shouldUseIncreasedScalingPercent?: boolean) => (config: PluginConfig) => FloatingToolbarHandler;
11
+ export declare const getToolbarConfig: (getEditorContainerWidth: GetEditorContainerWidth, api: PluginInjectionAPI | undefined | null, editorAnalyticsAPI: EditorAnalyticsAPI | undefined | null, getEditorView: () => EditorView | null, options?: TablePluginOptions, isTableFixedColumnWidthsOptionEnabled?: boolean, shouldUseIncreasedScalingPercent?: boolean) => (config: PluginConfig) => FloatingToolbarHandler;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@atlaskit/editor-plugin-table",
3
- "version": "10.6.8",
3
+ "version": "10.6.10",
4
4
  "description": "Table plugin for the @atlaskit/editor",
5
5
  "publishConfig": {
6
6
  "registry": "https://registry.npmjs.org/"
@@ -32,7 +32,7 @@
32
32
  "@atlaskit/adf-schema": "^47.6.0",
33
33
  "@atlaskit/button": "^23.0.0",
34
34
  "@atlaskit/custom-steps": "^0.11.0",
35
- "@atlaskit/editor-common": "^103.1.0",
35
+ "@atlaskit/editor-common": "^103.3.0",
36
36
  "@atlaskit/editor-palette": "^2.1.0",
37
37
  "@atlaskit/editor-plugin-accessibility-utils": "^2.0.0",
38
38
  "@atlaskit/editor-plugin-analytics": "^2.2.0",
@@ -123,6 +123,9 @@
123
123
  "type": "boolean",
124
124
  "referenceOnly": true
125
125
  },
126
+ "platform_editor_table_initial_load_fix": {
127
+ "type": "boolean"
128
+ },
126
129
  "platform_editor_table_overflow_in_full_width_fix": {
127
130
  "type": "boolean"
128
131
  },
@@ -197,6 +200,9 @@
197
200
  },
198
201
  "platform_editor_controls_patch_2": {
199
202
  "type": "boolean"
203
+ },
204
+ "platform_editor_controls_patch_4": {
205
+ "type": "boolean"
200
206
  }
201
207
  }
202
208
  }
@@ -1033,6 +1033,7 @@ class TableComponent extends React.Component<ComponentProps, TableState> {
1033
1033
  if (elem) {
1034
1034
  this.props.contentDOM(elem);
1035
1035
  const tableElement = elem.querySelector('table');
1036
+
1036
1037
  if (tableElement !== this.table) {
1037
1038
  this.table = tableElement;
1038
1039
  this.createShadowSentinels(this.table);
@@ -15,7 +15,7 @@ import type {
15
15
  import { WithPluginState } from '@atlaskit/editor-common/with-plugin-state';
16
16
  import type { DOMOutputSpec, Node as PmNode } from '@atlaskit/editor-prosemirror/model';
17
17
  import { DOMSerializer } from '@atlaskit/editor-prosemirror/model';
18
- import type { EditorState, PluginKey } from '@atlaskit/editor-prosemirror/state';
18
+ import type { EditorState, PluginKey, SelectionBookmark } from '@atlaskit/editor-prosemirror/state';
19
19
  import type { EditorView, NodeView } from '@atlaskit/editor-prosemirror/view';
20
20
  import { akEditorTableNumberColumnWidth } from '@atlaskit/editor-shared-styles';
21
21
  import { TableMap } from '@atlaskit/editor-tables/table-map';
@@ -33,6 +33,7 @@ import type { PluginInjectionAPI } from '../types';
33
33
 
34
34
  import TableComponent from './TableComponent';
35
35
  import { TableComponentWithSharedState } from './TableComponentWithSharedState';
36
+ import { tableNodeSpecWithFixedToDOM } from './toDOM';
36
37
  import type { Props } from './types';
37
38
 
38
39
  type ForwardRef = (node: HTMLElement | null) => void;
@@ -80,18 +81,18 @@ const handleInlineTableWidth = (table: HTMLElement, width: number | undefined) =
80
81
  table.style.setProperty('width', `${width}px`);
81
82
  };
82
83
 
84
+ // Leave as a fallback incase the table's NodeSpec.toDOM is not defined.
83
85
  const toDOM = (node: PmNode, props: Props) => {
84
86
  let colgroup: DOMOutputSpec = '';
85
-
86
87
  if (props.allowColumnResizing) {
87
88
  colgroup = ['colgroup', {}, ...generateColgroup(node)];
88
89
  }
89
-
90
90
  return ['table', tableAttributes(node), colgroup, ['tbody', 0]] as DOMOutputSpec;
91
91
  };
92
92
 
93
93
  export default class TableView extends ReactNodeView<Props> {
94
94
  private table: HTMLElement | undefined;
95
+ private renderedDOM?: HTMLElement;
95
96
  private resizeObserver?: ResizeObserver;
96
97
  eventDispatcher?: EventDispatcher;
97
98
  getPos: getPosHandlerNode;
@@ -111,19 +112,37 @@ export default class TableView extends ReactNodeView<Props> {
111
112
  this.eventDispatcher = props.eventDispatcher;
112
113
  this.options = props.options;
113
114
  this.getEditorFeatureFlags = props.getEditorFeatureFlags;
115
+
116
+ if (fg('platform_editor_table_initial_load_fix')) {
117
+ this.handleRef = (node: HTMLElement | null) => this._handleTableRef(node);
118
+ }
114
119
  }
115
120
 
116
121
  getContentDOM() {
117
- const rendered = DOMSerializer.renderSpec(
118
- document,
119
- toDOM(this.node, this.reactComponentProps as Props),
120
- ) as {
122
+ let tableDOMStructure;
123
+ if (fg('platform_editor_table_initial_load_fix')) {
124
+ tableDOMStructure = tableNodeSpecWithFixedToDOM({
125
+ allowColumnResizing: !!this.reactComponentProps.allowColumnResizing,
126
+ tableResizingEnabled: !!this.reactComponentProps.allowTableResizing,
127
+ getEditorContainerWidth: this.reactComponentProps.getEditorContainerWidth,
128
+ }).toDOM(this.node);
129
+ } else {
130
+ tableDOMStructure = toDOM(this.node, this.reactComponentProps as Props);
131
+ }
132
+
133
+ const rendered = DOMSerializer.renderSpec(document, tableDOMStructure) as {
121
134
  dom: HTMLElement;
122
135
  contentDOM?: HTMLElement;
123
136
  };
124
137
 
125
138
  if (rendered.dom) {
126
- this.table = rendered.dom;
139
+ if (fg('platform_editor_table_initial_load_fix')) {
140
+ const tableElement = rendered.dom.querySelector('table');
141
+ this.table = tableElement ? tableElement : rendered.dom;
142
+ this.renderedDOM = rendered.dom;
143
+ } else {
144
+ this.table = rendered.dom;
145
+ }
127
146
 
128
147
  if (
129
148
  !this.options?.isTableScalingEnabled ||
@@ -147,6 +166,73 @@ export default class TableView extends ReactNodeView<Props> {
147
166
  return rendered;
148
167
  }
149
168
 
169
+ /**
170
+ * Handles moving the table from ProseMirror's DOM structure into a React-rendered table node.
171
+ * Temporarily disables mutation observers (except for selection changes) during the move,
172
+ * preserves selection state, and restores it afterwards if mutations occurred and cursor
173
+ * wasn't at start of node. This prevents duplicate tables and maintains editor state during
174
+ * the DOM manipulation.
175
+ */
176
+ private _handleTableRef(node: HTMLElement | null) {
177
+ let oldIgnoreMutation: (mutation: MutationRecord) => boolean;
178
+
179
+ let selectionBookmark: SelectionBookmark;
180
+ let parentOffset = 0;
181
+ let mutationsIgnored = false;
182
+
183
+ // Only proceed if we have both a node and table, and the table isn't already inside the node
184
+ if (node && this.table && !node.contains(this.table)) {
185
+ // Store the current ignoreMutation handler so we can restore it later
186
+ oldIgnoreMutation = this.ignoreMutation;
187
+
188
+ // Set up a temporary mutation handler that:
189
+ // - Ignores all DOM mutations except selection changes
190
+ // - Tracks when mutations have been ignored via mutationsIgnored flag
191
+ this.ignoreMutation = (m: MutationRecord) => {
192
+ const isSelectionMutation = m.target instanceof Selection;
193
+ if (!isSelectionMutation) {
194
+ mutationsIgnored = true;
195
+ }
196
+ return !isSelectionMutation;
197
+ };
198
+
199
+ // Store the current selection state if there is a visible selection
200
+ // This lets us restore it after DOM changes
201
+ if (this.view.state.selection.visible) {
202
+ selectionBookmark = this.view.state.selection.getBookmark();
203
+ }
204
+
205
+ // Store the current cursor position within the parent node
206
+ // Used to determine if we need to restore selection later
207
+ if (this.view.state.selection?.ranges.length > 0) {
208
+ parentOffset = this.view.state.selection?.ranges[0].$from?.parentOffset ?? 0;
209
+ }
210
+
211
+ // Remove the ProseMirror table DOM structure to avoid duplication, as it's replaced with the React table node.
212
+ if (this.renderedDOM) {
213
+ this.dom.removeChild(this.renderedDOM);
214
+ }
215
+ // Move the table from the ProseMirror table structure into the React rendered table node.
216
+ node.appendChild(this.table);
217
+
218
+ // After the next frame:
219
+ requestAnimationFrame(() => {
220
+ // Restore the original mutation handler
221
+ this.ignoreMutation = oldIgnoreMutation;
222
+
223
+ // Restore the selection only if:
224
+ // - We have a selection bookmark
225
+ // - Mutations were ignored during the table move
226
+ // - The cursor wasn't at the start of the node
227
+ if (selectionBookmark && mutationsIgnored && parentOffset > 0) {
228
+ this.view.dispatch(
229
+ this.view.state.tr.setSelection(selectionBookmark.resolve(this.view.state.tr.doc)),
230
+ );
231
+ }
232
+ });
233
+ }
234
+ }
235
+
150
236
  setDomAttrs(node: PmNode) {
151
237
  if (!this.table) {
152
238
  return;
@@ -206,7 +292,6 @@ export default class TableView extends ReactNodeView<Props> {
206
292
  />
207
293
  );
208
294
  }
209
-
210
295
  // Please, do not copy or use this kind of code below
211
296
  // @ts-ignore
212
297
  const fakePluginKey = {
@@ -17,7 +17,9 @@ type Config = {
17
17
  getEditorContainerWidth: GetEditorContainerWidth;
18
18
  isNestingSupported?: boolean;
19
19
  };
20
- export const tableNodeSpecWithFixedToDOM = (config: Config): NodeSpec => {
20
+ export const tableNodeSpecWithFixedToDOM = (
21
+ config: Config,
22
+ ): NodeSpec & { toDOM: (node: PMNode) => DOMOutputSpec } => {
21
23
  const tableNode = config.isNestingSupported ? tableWithNestedTable : table;
22
24
 
23
25
  return {
@@ -768,7 +768,6 @@ const tablesPlugin: TablePlugin = ({ config: options, api }) => {
768
768
  defaultGetEditorContainerWidth,
769
769
  api,
770
770
  editorAnalyticsAPI,
771
- options?.getEditorFeatureFlags || defaultGetEditorFeatureFlags,
772
771
  () => editorViewRef.current,
773
772
  options,
774
773
  isTableFixedColumnWidthsOptionEnabled,
@@ -23,7 +23,6 @@ import type {
23
23
  FloatingToolbarHandler,
24
24
  FloatingToolbarItem,
25
25
  GetEditorContainerWidth,
26
- GetEditorFeatureFlags,
27
26
  Icon,
28
27
  typeOption,
29
28
  } from '@atlaskit/editor-common/types';
@@ -87,6 +86,7 @@ import {
87
86
  toggleNumberColumnWithAnalytics,
88
87
  wrapTableInExpandWithAnalytics,
89
88
  } from '../pm-plugins/commands/commands-with-analytics';
89
+ import { getPluginState as getDragDropPluginState } from '../pm-plugins/drag-and-drop/plugin-factory';
90
90
  import { getPluginState } from '../pm-plugins/plugin-factory';
91
91
  import { pluginKey as tableResizingPluginKey } from '../pm-plugins/table-resizing/plugin-key';
92
92
  import { getStaticTableScalingPercent } from '../pm-plugins/table-resizing/utils/misc';
@@ -479,7 +479,6 @@ export const getToolbarConfig =
479
479
  getEditorContainerWidth: GetEditorContainerWidth,
480
480
  api: PluginInjectionAPI | undefined | null,
481
481
  editorAnalyticsAPI: EditorAnalyticsAPI | undefined | null,
482
- getEditorFeatureFlags: GetEditorFeatureFlags,
483
482
  getEditorView: () => EditorView | null,
484
483
  options?: TablePluginOptions,
485
484
  isTableFixedColumnWidthsOptionEnabled = false,
@@ -492,12 +491,45 @@ export const getToolbarConfig =
492
491
  const resizeState = tableResizingPluginKey.getState(state);
493
492
  const tableWidthState = tableWidthPluginKey.getState(state);
494
493
  const isTableScalingEnabled = options?.isTableScalingEnabled || false;
494
+ const nodeType = state.schema.nodes.table;
495
+ const toolbarTitle = 'Table floating controls';
496
+
497
+ if (
498
+ editorExperiment('platform_editor_controls', 'variant1') &&
499
+ fg('platform_editor_controls_patch_4')
500
+ ) {
501
+ let isDragHandleMenuOpened = false;
502
+ let isTableRowOrColumnDragged = false;
503
+ if (options?.dragAndDropEnabled) {
504
+ const { isDragMenuOpen = false, isDragging = false } = getDragDropPluginState(state);
505
+ isDragHandleMenuOpened = isDragMenuOpen;
506
+ isTableRowOrColumnDragged = isDragging;
507
+ }
508
+
509
+ const isTableOrColumnResizing = !!(resizeState?.dragging || tableWidthState?.resizing);
510
+ const isTableMenuOpened = pluginState.isContextualMenuOpen || isDragHandleMenuOpened;
511
+ const isViewMode = api?.editorViewMode?.sharedState.currentState()?.mode === 'view';
512
+
513
+ const shouldSuppressAllToolbars =
514
+ (!pluginState.editorHasFocus && !isViewMode) ||
515
+ isTableMenuOpened ||
516
+ isTableOrColumnResizing ||
517
+ isTableRowOrColumnDragged;
518
+
519
+ if (shouldSuppressAllToolbars) {
520
+ return {
521
+ title: toolbarTitle,
522
+ items: [],
523
+ nodeType,
524
+ __suppressAllToolbars: true,
525
+ };
526
+ }
527
+ }
495
528
 
496
529
  // We don't want to show floating toolbar while resizing the table
497
530
  const isWidthResizing = tableWidthState?.resizing;
498
531
 
499
532
  if (tableObject && pluginState.editorHasFocus && !isWidthResizing) {
500
- const nodeType = state.schema.nodes.table;
501
533
  const isNested = pluginState.tablePos && isTableNested(state, pluginState.tablePos);
502
534
  const isTableScalingWithFixedColumnWidthsOptionShown =
503
535
  isTableScalingEnabled && isTableFixedColumnWidthsOptionEnabled && !isNested;
@@ -645,7 +677,7 @@ export const getToolbarConfig =
645
677
  : undefined;
646
678
 
647
679
  return {
648
- title: 'Table floating controls',
680
+ title: toolbarTitle,
649
681
  getDomRef,
650
682
  nodeType,
651
683
  offset: [0, 18],