@atlaskit/editor-plugin-table 9.3.4 → 9.3.5

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,13 @@
1
1
  # @atlaskit/editor-plugin-table
2
2
 
3
+ ## 9.3.5
4
+
5
+ ### Patch Changes
6
+
7
+ - [#108813](https://stash.atlassian.com/projects/CONFCLOUD/repos/confluence-frontend/pull-requests/108813)
8
+ [`123953f8b2006`](https://stash.atlassian.com/projects/CONFCLOUD/repos/confluence-frontend/commits/123953f8b2006) -
9
+ [ux] ED-26075 Unwrap content from nested table text block slices on paste
10
+
3
11
  ## 9.3.4
4
12
 
5
13
  ### Patch Changes
@@ -172,12 +172,58 @@ var transformSliceToFixHardBreakProblemOnCopyFromCell = exports.transformSliceTo
172
172
  }
173
173
  return slice;
174
174
  };
175
+ var isNodeSingleCellTable = function isNodeSingleCellTable(node, schema) {
176
+ var _node$firstChild, _node$firstChild$firs, _node$firstChild$firs2;
177
+ return node.childCount === 1 && ((_node$firstChild = node.firstChild) === null || _node$firstChild === void 0 ? void 0 : _node$firstChild.type) === schema.nodes.tableRow && node.firstChild.childCount === 1 && (((_node$firstChild$firs = node.firstChild.firstChild) === null || _node$firstChild$firs === void 0 ? void 0 : _node$firstChild$firs.type) === schema.nodes.tableCell || ((_node$firstChild$firs2 = node.firstChild.firstChild) === null || _node$firstChild$firs2 === void 0 ? void 0 : _node$firstChild$firs2.type) === schema.nodes.tableHeader);
178
+ };
179
+ var isFragmentSingleCellTable = function isFragmentSingleCellTable(fragment, schema) {
180
+ return fragment.childCount === 1 && fragment.firstChild !== null && isNodeSingleCellTable(fragment.firstChild, schema);
181
+ };
182
+ var containsTextBlockChildren = function containsTextBlockChildren(fragment, schema) {
183
+ var containsTextBlock = false;
184
+ fragment.forEach(function (node) {
185
+ if (node.isTextblock) {
186
+ containsTextBlock = true;
187
+ }
188
+ });
189
+ return containsTextBlock;
190
+ };
175
191
  var transformSliceToRemoveOpenTable = exports.transformSliceToRemoveOpenTable = function transformSliceToRemoveOpenTable(slice, schema) {
176
- var _slice$content$firstC3;
177
- // we're removing the table, tableRow and tableCell reducing the open depth by 3
178
- var depthDecrement = 3;
192
+ var _slice$content$firstC4;
193
+ if ((0, _platformFeatureFlags.fg)('platform_editor_nested_tables_paste_wrap_fix')) {
194
+ // Case 1: A slice of a textblock selection inside a nested table
195
+ // Prosemirror wraps nested textblock selections in their respective tables
196
+ // We are using `safeInsert` to paste nested tables, so we do not want to preserve this wrapping
197
+
198
+ // slice starts and ends inside a nested table at the same depth
199
+ if (slice.openStart >= 7 && slice.openEnd >= 7 && slice.openStart === slice.openEnd) {
200
+ var cleaned = slice;
201
+ var descendedDepth = 0;
202
+ var tableDepthDecrement = 2;
179
203
 
180
- // Case 1: A slice entirely within a single CELL
204
+ // if the slice is a single cell table and contains cells with single cell tables, descend into it until we find textblock children
205
+ if (isFragmentSingleCellTable(slice.content, schema)) {
206
+ var _slice$content$firstC2;
207
+ (_slice$content$firstC2 = slice.content.firstChild) === null || _slice$content$firstC2 === void 0 || _slice$content$firstC2.descendants(function (node, _pos, parent) {
208
+ if (isNodeSingleCellTable(node, schema)) {
209
+ descendedDepth += tableDepthDecrement;
210
+ } else if (node.type === schema.nodes.table) {
211
+ return false;
212
+ } else if (containsTextBlockChildren(node.content, schema)) {
213
+ descendedDepth += tableDepthDecrement;
214
+ // create a new slice with the content of the textblock children and the depth of the nested tables subtracted
215
+ cleaned = new _model.Slice(node.content, slice.openStart - descendedDepth - tableDepthDecrement, slice.openEnd - descendedDepth - tableDepthDecrement);
216
+ return false;
217
+ }
218
+ });
219
+ }
220
+ if (!cleaned.eq(slice)) {
221
+ return cleaned;
222
+ }
223
+ }
224
+ }
225
+
226
+ // Case 2: A slice entirely within a single CELL
181
227
  if (
182
228
  // starts and ends inside of a cell
183
229
  slice.openStart >= 4 && slice.openEnd >= 4 &&
@@ -186,25 +232,28 @@ var transformSliceToRemoveOpenTable = exports.transformSliceToRemoveOpenTable =
186
232
  // Ignored via go/ees005
187
233
  // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
188
234
  slice.content.firstChild.type === schema.nodes.table) {
189
- var _slice$content$firstC2;
235
+ var _slice$content$firstC3;
236
+ // we're removing the table, tableRow and tableCell reducing the open depth by 3
237
+ var depthDecrement = 3;
238
+
190
239
  // prosemirror-view has a bug that it duplicates table entry when selecting multiple paragraphs in a table cell.
191
240
  // https://github.com/ProseMirror/prosemirror/issues/1270
192
241
  // The structure becomes
193
242
  // table(genuine) > tableRow(genuine) > table(duplicated) > tableRow(duplicated) > tableCell/tableHeader(genuine) > contents(genuine)
194
243
  // As we are removing wrapping table anyway, we keep duplicated table and tableRow for simplicity
195
- var cleaned = slice;
196
- if (((_slice$content$firstC2 = slice.content.firstChild) === null || _slice$content$firstC2 === void 0 || (_slice$content$firstC2 = _slice$content$firstC2.content) === null || _slice$content$firstC2 === void 0 || (_slice$content$firstC2 = _slice$content$firstC2.firstChild) === null || _slice$content$firstC2 === void 0 || (_slice$content$firstC2 = _slice$content$firstC2.content) === null || _slice$content$firstC2 === void 0 || (_slice$content$firstC2 = _slice$content$firstC2.firstChild) === null || _slice$content$firstC2 === void 0 ? void 0 : _slice$content$firstC2.type) === schema.nodes.table) {
197
- cleaned = new _model.Slice(slice.content.firstChild.content.firstChild.content, slice.openStart - 2, slice.openEnd - 2);
244
+ var _cleaned = slice;
245
+ if (((_slice$content$firstC3 = slice.content.firstChild) === null || _slice$content$firstC3 === void 0 || (_slice$content$firstC3 = _slice$content$firstC3.content) === null || _slice$content$firstC3 === void 0 || (_slice$content$firstC3 = _slice$content$firstC3.firstChild) === null || _slice$content$firstC3 === void 0 || (_slice$content$firstC3 = _slice$content$firstC3.content) === null || _slice$content$firstC3 === void 0 || (_slice$content$firstC3 = _slice$content$firstC3.firstChild) === null || _slice$content$firstC3 === void 0 ? void 0 : _slice$content$firstC3.type) === schema.nodes.table) {
246
+ _cleaned = new _model.Slice(slice.content.firstChild.content.firstChild.content, slice.openStart - 2, slice.openEnd - 2);
198
247
  }
199
- return new _model.Slice((0, _utils.flatmap)(cleaned.content, unwrapContentFromTable), cleaned.openStart - depthDecrement, cleaned.openEnd - depthDecrement);
248
+ return new _model.Slice((0, _utils.flatmap)(_cleaned.content, unwrapContentFromTable), _cleaned.openStart - depthDecrement, _cleaned.openEnd - depthDecrement);
200
249
  }
201
250
 
202
- // Case 2: A slice starting within a CELL and ending outside the table
251
+ // Case 3: A slice starting within a CELL and ending outside the table
203
252
  if (
204
253
  // starts inside of a cell but ends outside of the starting table
205
254
  slice.openStart >= 4 &&
206
255
  // slice starts from a table node (and spans across more than one node)
207
- slice.content.childCount > 1 && ((_slice$content$firstC3 = slice.content.firstChild) === null || _slice$content$firstC3 === void 0 ? void 0 : _slice$content$firstC3.type) === schema.nodes.table) {
256
+ slice.content.childCount > 1 && ((_slice$content$firstC4 = slice.content.firstChild) === null || _slice$content$firstC4 === void 0 ? void 0 : _slice$content$firstC4.type) === schema.nodes.table) {
208
257
  // repoint the slice's cutting depth so that cell content where the slice starts
209
258
  // does not get lifted out of the cell on paste
210
259
  return new _model.Slice(slice.content, 1, slice.openEnd);
@@ -163,12 +163,58 @@ export const transformSliceToFixHardBreakProblemOnCopyFromCell = (slice, schema)
163
163
  }
164
164
  return slice;
165
165
  };
166
+ const isNodeSingleCellTable = (node, schema) => {
167
+ var _node$firstChild, _node$firstChild$firs, _node$firstChild$firs2;
168
+ return node.childCount === 1 && ((_node$firstChild = node.firstChild) === null || _node$firstChild === void 0 ? void 0 : _node$firstChild.type) === schema.nodes.tableRow && node.firstChild.childCount === 1 && (((_node$firstChild$firs = node.firstChild.firstChild) === null || _node$firstChild$firs === void 0 ? void 0 : _node$firstChild$firs.type) === schema.nodes.tableCell || ((_node$firstChild$firs2 = node.firstChild.firstChild) === null || _node$firstChild$firs2 === void 0 ? void 0 : _node$firstChild$firs2.type) === schema.nodes.tableHeader);
169
+ };
170
+ const isFragmentSingleCellTable = (fragment, schema) => {
171
+ return fragment.childCount === 1 && fragment.firstChild !== null && isNodeSingleCellTable(fragment.firstChild, schema);
172
+ };
173
+ const containsTextBlockChildren = (fragment, schema) => {
174
+ let containsTextBlock = false;
175
+ fragment.forEach(node => {
176
+ if (node.isTextblock) {
177
+ containsTextBlock = true;
178
+ }
179
+ });
180
+ return containsTextBlock;
181
+ };
166
182
  export const transformSliceToRemoveOpenTable = (slice, schema) => {
167
- var _slice$content$firstC7;
168
- // we're removing the table, tableRow and tableCell reducing the open depth by 3
169
- const depthDecrement = 3;
183
+ var _slice$content$firstC8;
184
+ if (fg('platform_editor_nested_tables_paste_wrap_fix')) {
185
+ // Case 1: A slice of a textblock selection inside a nested table
186
+ // Prosemirror wraps nested textblock selections in their respective tables
187
+ // We are using `safeInsert` to paste nested tables, so we do not want to preserve this wrapping
188
+
189
+ // slice starts and ends inside a nested table at the same depth
190
+ if (slice.openStart >= 7 && slice.openEnd >= 7 && slice.openStart === slice.openEnd) {
191
+ let cleaned = slice;
192
+ let descendedDepth = 0;
193
+ const tableDepthDecrement = 2;
170
194
 
171
- // Case 1: A slice entirely within a single CELL
195
+ // if the slice is a single cell table and contains cells with single cell tables, descend into it until we find textblock children
196
+ if (isFragmentSingleCellTable(slice.content, schema)) {
197
+ var _slice$content$firstC2;
198
+ (_slice$content$firstC2 = slice.content.firstChild) === null || _slice$content$firstC2 === void 0 ? void 0 : _slice$content$firstC2.descendants((node, _pos, parent) => {
199
+ if (isNodeSingleCellTable(node, schema)) {
200
+ descendedDepth += tableDepthDecrement;
201
+ } else if (node.type === schema.nodes.table) {
202
+ return false;
203
+ } else if (containsTextBlockChildren(node.content, schema)) {
204
+ descendedDepth += tableDepthDecrement;
205
+ // create a new slice with the content of the textblock children and the depth of the nested tables subtracted
206
+ cleaned = new Slice(node.content, slice.openStart - descendedDepth - tableDepthDecrement, slice.openEnd - descendedDepth - tableDepthDecrement);
207
+ return false;
208
+ }
209
+ });
210
+ }
211
+ if (!cleaned.eq(slice)) {
212
+ return cleaned;
213
+ }
214
+ }
215
+ }
216
+
217
+ // Case 2: A slice entirely within a single CELL
172
218
  if (
173
219
  // starts and ends inside of a cell
174
220
  slice.openStart >= 4 && slice.openEnd >= 4 &&
@@ -177,25 +223,28 @@ export const transformSliceToRemoveOpenTable = (slice, schema) => {
177
223
  // Ignored via go/ees005
178
224
  // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
179
225
  slice.content.firstChild.type === schema.nodes.table) {
180
- var _slice$content$firstC2, _slice$content$firstC3, _slice$content$firstC4, _slice$content$firstC5, _slice$content$firstC6;
226
+ var _slice$content$firstC3, _slice$content$firstC4, _slice$content$firstC5, _slice$content$firstC6, _slice$content$firstC7;
227
+ // we're removing the table, tableRow and tableCell reducing the open depth by 3
228
+ const depthDecrement = 3;
229
+
181
230
  // prosemirror-view has a bug that it duplicates table entry when selecting multiple paragraphs in a table cell.
182
231
  // https://github.com/ProseMirror/prosemirror/issues/1270
183
232
  // The structure becomes
184
233
  // table(genuine) > tableRow(genuine) > table(duplicated) > tableRow(duplicated) > tableCell/tableHeader(genuine) > contents(genuine)
185
234
  // As we are removing wrapping table anyway, we keep duplicated table and tableRow for simplicity
186
235
  let cleaned = slice;
187
- if (((_slice$content$firstC2 = slice.content.firstChild) === null || _slice$content$firstC2 === void 0 ? void 0 : (_slice$content$firstC3 = _slice$content$firstC2.content) === null || _slice$content$firstC3 === void 0 ? void 0 : (_slice$content$firstC4 = _slice$content$firstC3.firstChild) === null || _slice$content$firstC4 === void 0 ? void 0 : (_slice$content$firstC5 = _slice$content$firstC4.content) === null || _slice$content$firstC5 === void 0 ? void 0 : (_slice$content$firstC6 = _slice$content$firstC5.firstChild) === null || _slice$content$firstC6 === void 0 ? void 0 : _slice$content$firstC6.type) === schema.nodes.table) {
236
+ if (((_slice$content$firstC3 = slice.content.firstChild) === null || _slice$content$firstC3 === void 0 ? void 0 : (_slice$content$firstC4 = _slice$content$firstC3.content) === null || _slice$content$firstC4 === void 0 ? void 0 : (_slice$content$firstC5 = _slice$content$firstC4.firstChild) === null || _slice$content$firstC5 === void 0 ? void 0 : (_slice$content$firstC6 = _slice$content$firstC5.content) === null || _slice$content$firstC6 === void 0 ? void 0 : (_slice$content$firstC7 = _slice$content$firstC6.firstChild) === null || _slice$content$firstC7 === void 0 ? void 0 : _slice$content$firstC7.type) === schema.nodes.table) {
188
237
  cleaned = new Slice(slice.content.firstChild.content.firstChild.content, slice.openStart - 2, slice.openEnd - 2);
189
238
  }
190
239
  return new Slice(flatmap(cleaned.content, unwrapContentFromTable), cleaned.openStart - depthDecrement, cleaned.openEnd - depthDecrement);
191
240
  }
192
241
 
193
- // Case 2: A slice starting within a CELL and ending outside the table
242
+ // Case 3: A slice starting within a CELL and ending outside the table
194
243
  if (
195
244
  // starts inside of a cell but ends outside of the starting table
196
245
  slice.openStart >= 4 &&
197
246
  // slice starts from a table node (and spans across more than one node)
198
- slice.content.childCount > 1 && ((_slice$content$firstC7 = slice.content.firstChild) === null || _slice$content$firstC7 === void 0 ? void 0 : _slice$content$firstC7.type) === schema.nodes.table) {
247
+ slice.content.childCount > 1 && ((_slice$content$firstC8 = slice.content.firstChild) === null || _slice$content$firstC8 === void 0 ? void 0 : _slice$content$firstC8.type) === schema.nodes.table) {
199
248
  // repoint the slice's cutting depth so that cell content where the slice starts
200
249
  // does not get lifted out of the cell on paste
201
250
  return new Slice(slice.content, 1, slice.openEnd);
@@ -165,12 +165,58 @@ export var transformSliceToFixHardBreakProblemOnCopyFromCell = function transfor
165
165
  }
166
166
  return slice;
167
167
  };
168
+ var isNodeSingleCellTable = function isNodeSingleCellTable(node, schema) {
169
+ var _node$firstChild, _node$firstChild$firs, _node$firstChild$firs2;
170
+ return node.childCount === 1 && ((_node$firstChild = node.firstChild) === null || _node$firstChild === void 0 ? void 0 : _node$firstChild.type) === schema.nodes.tableRow && node.firstChild.childCount === 1 && (((_node$firstChild$firs = node.firstChild.firstChild) === null || _node$firstChild$firs === void 0 ? void 0 : _node$firstChild$firs.type) === schema.nodes.tableCell || ((_node$firstChild$firs2 = node.firstChild.firstChild) === null || _node$firstChild$firs2 === void 0 ? void 0 : _node$firstChild$firs2.type) === schema.nodes.tableHeader);
171
+ };
172
+ var isFragmentSingleCellTable = function isFragmentSingleCellTable(fragment, schema) {
173
+ return fragment.childCount === 1 && fragment.firstChild !== null && isNodeSingleCellTable(fragment.firstChild, schema);
174
+ };
175
+ var containsTextBlockChildren = function containsTextBlockChildren(fragment, schema) {
176
+ var containsTextBlock = false;
177
+ fragment.forEach(function (node) {
178
+ if (node.isTextblock) {
179
+ containsTextBlock = true;
180
+ }
181
+ });
182
+ return containsTextBlock;
183
+ };
168
184
  export var transformSliceToRemoveOpenTable = function transformSliceToRemoveOpenTable(slice, schema) {
169
- var _slice$content$firstC3;
170
- // we're removing the table, tableRow and tableCell reducing the open depth by 3
171
- var depthDecrement = 3;
185
+ var _slice$content$firstC4;
186
+ if (fg('platform_editor_nested_tables_paste_wrap_fix')) {
187
+ // Case 1: A slice of a textblock selection inside a nested table
188
+ // Prosemirror wraps nested textblock selections in their respective tables
189
+ // We are using `safeInsert` to paste nested tables, so we do not want to preserve this wrapping
190
+
191
+ // slice starts and ends inside a nested table at the same depth
192
+ if (slice.openStart >= 7 && slice.openEnd >= 7 && slice.openStart === slice.openEnd) {
193
+ var cleaned = slice;
194
+ var descendedDepth = 0;
195
+ var tableDepthDecrement = 2;
172
196
 
173
- // Case 1: A slice entirely within a single CELL
197
+ // if the slice is a single cell table and contains cells with single cell tables, descend into it until we find textblock children
198
+ if (isFragmentSingleCellTable(slice.content, schema)) {
199
+ var _slice$content$firstC2;
200
+ (_slice$content$firstC2 = slice.content.firstChild) === null || _slice$content$firstC2 === void 0 || _slice$content$firstC2.descendants(function (node, _pos, parent) {
201
+ if (isNodeSingleCellTable(node, schema)) {
202
+ descendedDepth += tableDepthDecrement;
203
+ } else if (node.type === schema.nodes.table) {
204
+ return false;
205
+ } else if (containsTextBlockChildren(node.content, schema)) {
206
+ descendedDepth += tableDepthDecrement;
207
+ // create a new slice with the content of the textblock children and the depth of the nested tables subtracted
208
+ cleaned = new Slice(node.content, slice.openStart - descendedDepth - tableDepthDecrement, slice.openEnd - descendedDepth - tableDepthDecrement);
209
+ return false;
210
+ }
211
+ });
212
+ }
213
+ if (!cleaned.eq(slice)) {
214
+ return cleaned;
215
+ }
216
+ }
217
+ }
218
+
219
+ // Case 2: A slice entirely within a single CELL
174
220
  if (
175
221
  // starts and ends inside of a cell
176
222
  slice.openStart >= 4 && slice.openEnd >= 4 &&
@@ -179,25 +225,28 @@ export var transformSliceToRemoveOpenTable = function transformSliceToRemoveOpen
179
225
  // Ignored via go/ees005
180
226
  // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
181
227
  slice.content.firstChild.type === schema.nodes.table) {
182
- var _slice$content$firstC2;
228
+ var _slice$content$firstC3;
229
+ // we're removing the table, tableRow and tableCell reducing the open depth by 3
230
+ var depthDecrement = 3;
231
+
183
232
  // prosemirror-view has a bug that it duplicates table entry when selecting multiple paragraphs in a table cell.
184
233
  // https://github.com/ProseMirror/prosemirror/issues/1270
185
234
  // The structure becomes
186
235
  // table(genuine) > tableRow(genuine) > table(duplicated) > tableRow(duplicated) > tableCell/tableHeader(genuine) > contents(genuine)
187
236
  // As we are removing wrapping table anyway, we keep duplicated table and tableRow for simplicity
188
- var cleaned = slice;
189
- if (((_slice$content$firstC2 = slice.content.firstChild) === null || _slice$content$firstC2 === void 0 || (_slice$content$firstC2 = _slice$content$firstC2.content) === null || _slice$content$firstC2 === void 0 || (_slice$content$firstC2 = _slice$content$firstC2.firstChild) === null || _slice$content$firstC2 === void 0 || (_slice$content$firstC2 = _slice$content$firstC2.content) === null || _slice$content$firstC2 === void 0 || (_slice$content$firstC2 = _slice$content$firstC2.firstChild) === null || _slice$content$firstC2 === void 0 ? void 0 : _slice$content$firstC2.type) === schema.nodes.table) {
190
- cleaned = new Slice(slice.content.firstChild.content.firstChild.content, slice.openStart - 2, slice.openEnd - 2);
237
+ var _cleaned = slice;
238
+ if (((_slice$content$firstC3 = slice.content.firstChild) === null || _slice$content$firstC3 === void 0 || (_slice$content$firstC3 = _slice$content$firstC3.content) === null || _slice$content$firstC3 === void 0 || (_slice$content$firstC3 = _slice$content$firstC3.firstChild) === null || _slice$content$firstC3 === void 0 || (_slice$content$firstC3 = _slice$content$firstC3.content) === null || _slice$content$firstC3 === void 0 || (_slice$content$firstC3 = _slice$content$firstC3.firstChild) === null || _slice$content$firstC3 === void 0 ? void 0 : _slice$content$firstC3.type) === schema.nodes.table) {
239
+ _cleaned = new Slice(slice.content.firstChild.content.firstChild.content, slice.openStart - 2, slice.openEnd - 2);
191
240
  }
192
- return new Slice(flatmap(cleaned.content, unwrapContentFromTable), cleaned.openStart - depthDecrement, cleaned.openEnd - depthDecrement);
241
+ return new Slice(flatmap(_cleaned.content, unwrapContentFromTable), _cleaned.openStart - depthDecrement, _cleaned.openEnd - depthDecrement);
193
242
  }
194
243
 
195
- // Case 2: A slice starting within a CELL and ending outside the table
244
+ // Case 3: A slice starting within a CELL and ending outside the table
196
245
  if (
197
246
  // starts inside of a cell but ends outside of the starting table
198
247
  slice.openStart >= 4 &&
199
248
  // slice starts from a table node (and spans across more than one node)
200
- slice.content.childCount > 1 && ((_slice$content$firstC3 = slice.content.firstChild) === null || _slice$content$firstC3 === void 0 ? void 0 : _slice$content$firstC3.type) === schema.nodes.table) {
249
+ slice.content.childCount > 1 && ((_slice$content$firstC4 = slice.content.firstChild) === null || _slice$content$firstC4 === void 0 ? void 0 : _slice$content$firstC4.type) === schema.nodes.table) {
201
250
  // repoint the slice's cutting depth so that cell content where the slice starts
202
251
  // does not get lifted out of the cell on paste
203
252
  return new Slice(slice.content, 1, slice.openEnd);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@atlaskit/editor-plugin-table",
3
- "version": "9.3.4",
3
+ "version": "9.3.5",
4
4
  "description": "Table plugin for the @atlaskit/editor",
5
5
  "publishConfig": {
6
6
  "registry": "https://registry.npmjs.org/"
@@ -30,7 +30,7 @@
30
30
  "@atlaskit/adf-schema": "^46.1.0",
31
31
  "@atlaskit/button": "^20.5.0",
32
32
  "@atlaskit/custom-steps": "^0.9.0",
33
- "@atlaskit/editor-common": "^99.8.0",
33
+ "@atlaskit/editor-common": "^99.9.0",
34
34
  "@atlaskit/editor-palette": "1.7.0",
35
35
  "@atlaskit/editor-plugin-accessibility-utils": "^1.3.0",
36
36
  "@atlaskit/editor-plugin-analytics": "^1.11.0",
@@ -43,7 +43,7 @@
43
43
  "@atlaskit/editor-prosemirror": "6.2.1",
44
44
  "@atlaskit/editor-shared-styles": "^3.2.0",
45
45
  "@atlaskit/editor-tables": "^2.8.0",
46
- "@atlaskit/icon": "^23.6.0",
46
+ "@atlaskit/icon": "^23.7.0",
47
47
  "@atlaskit/menu": "^2.14.0",
48
48
  "@atlaskit/platform-feature-flags": "^1.0.0",
49
49
  "@atlaskit/pragmatic-drag-and-drop": "^1.5.0",
@@ -51,7 +51,7 @@
51
51
  "@atlaskit/pragmatic-drag-and-drop-hitbox": "^1.0.0",
52
52
  "@atlaskit/primitives": "^13.4.0",
53
53
  "@atlaskit/theme": "^14.1.0",
54
- "@atlaskit/tmp-editor-statsig": "^2.42.0",
54
+ "@atlaskit/tmp-editor-statsig": "^2.43.0",
55
55
  "@atlaskit/toggle": "^14.1.0",
56
56
  "@atlaskit/tokens": "^3.3.0",
57
57
  "@atlaskit/tooltip": "^19.1.0",
@@ -144,6 +144,9 @@
144
144
  "platform_editor_nested_tables_resizing": {
145
145
  "type": "boolean"
146
146
  },
147
+ "platform_editor_nested_tables_paste_wrap_fix": {
148
+ "type": "boolean"
149
+ },
147
150
  "platform_editor_table_layout_shift_fix": {
148
151
  "type": "boolean"
149
152
  }
@@ -145,7 +145,9 @@ export const tableNodeSpecWithFixedToDOM = (config: Config): NodeSpec => {
145
145
  '--ak-editor-table-min-width': `${tableMinWidth}px`,
146
146
  minWidth: 'var(--ak-editor-table-min-width)',
147
147
  maxWidth: `min(calc(100cqw - var(--ak-editor-table-gutter-padding)), var(--ak-editor-table-max-width))`,
148
- width: fg('platform_editor_table_layout_shift_fix') ? `min(calc(100cqw - var(--ak-editor-table-gutter-padding)), ${node.attrs.width}px)` : `min(calc(100cqw - var(--ak-editor-table-gutter-padding)), ${node.attrs.width})`,
148
+ width: fg('platform_editor_table_layout_shift_fix')
149
+ ? `min(calc(100cqw - var(--ak-editor-table-gutter-padding)), ${node.attrs.width}px)`
150
+ : `min(calc(100cqw - var(--ak-editor-table-gutter-padding)), ${node.attrs.width})`,
149
151
  }),
150
152
  },
151
153
  [
@@ -211,11 +211,75 @@ export const transformSliceToFixHardBreakProblemOnCopyFromCell = (
211
211
  return slice;
212
212
  };
213
213
 
214
+ const isNodeSingleCellTable = (node: PMNode, schema: Schema): boolean => {
215
+ return (
216
+ node.childCount === 1 &&
217
+ node.firstChild?.type === schema.nodes.tableRow &&
218
+ node.firstChild.childCount === 1 &&
219
+ (node.firstChild.firstChild?.type === schema.nodes.tableCell ||
220
+ node.firstChild.firstChild?.type === schema.nodes.tableHeader)
221
+ );
222
+ };
223
+
224
+ const isFragmentSingleCellTable = (fragment: Fragment, schema: Schema): boolean => {
225
+ return (
226
+ fragment.childCount === 1 &&
227
+ fragment.firstChild !== null &&
228
+ isNodeSingleCellTable(fragment.firstChild, schema)
229
+ );
230
+ };
231
+
232
+ const containsTextBlockChildren = (fragment: Fragment, schema: Schema): boolean => {
233
+ let containsTextBlock = false;
234
+
235
+ fragment.forEach((node) => {
236
+ if (node.isTextblock) {
237
+ containsTextBlock = true;
238
+ }
239
+ });
240
+
241
+ return containsTextBlock;
242
+ };
243
+
214
244
  export const transformSliceToRemoveOpenTable = (slice: Slice, schema: Schema): Slice => {
215
- // we're removing the table, tableRow and tableCell reducing the open depth by 3
216
- const depthDecrement = 3;
245
+ if (fg('platform_editor_nested_tables_paste_wrap_fix')) {
246
+ // Case 1: A slice of a textblock selection inside a nested table
247
+ // Prosemirror wraps nested textblock selections in their respective tables
248
+ // We are using `safeInsert` to paste nested tables, so we do not want to preserve this wrapping
249
+
250
+ // slice starts and ends inside a nested table at the same depth
251
+ if (slice.openStart >= 7 && slice.openEnd >= 7 && slice.openStart === slice.openEnd) {
252
+ let cleaned = slice;
253
+ let descendedDepth = 0;
254
+ const tableDepthDecrement = 2;
255
+
256
+ // if the slice is a single cell table and contains cells with single cell tables, descend into it until we find textblock children
257
+ if (isFragmentSingleCellTable(slice.content, schema)) {
258
+ slice.content.firstChild?.descendants((node, _pos, parent) => {
259
+ if (isNodeSingleCellTable(node, schema)) {
260
+ descendedDepth += tableDepthDecrement;
261
+ } else if (node.type === schema.nodes.table) {
262
+ return false;
263
+ } else if (containsTextBlockChildren(node.content, schema)) {
264
+ descendedDepth += tableDepthDecrement;
265
+ // create a new slice with the content of the textblock children and the depth of the nested tables subtracted
266
+ cleaned = new Slice(
267
+ node.content,
268
+ slice.openStart - descendedDepth - tableDepthDecrement,
269
+ slice.openEnd - descendedDepth - tableDepthDecrement,
270
+ );
271
+ return false;
272
+ }
273
+ });
274
+ }
275
+
276
+ if (!cleaned.eq(slice)) {
277
+ return cleaned;
278
+ }
279
+ }
280
+ }
217
281
 
218
- // Case 1: A slice entirely within a single CELL
282
+ // Case 2: A slice entirely within a single CELL
219
283
  if (
220
284
  // starts and ends inside of a cell
221
285
  slice.openStart >= 4 &&
@@ -226,6 +290,9 @@ export const transformSliceToRemoveOpenTable = (slice: Slice, schema: Schema): S
226
290
  // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
227
291
  slice.content.firstChild!.type === schema.nodes.table
228
292
  ) {
293
+ // we're removing the table, tableRow and tableCell reducing the open depth by 3
294
+ const depthDecrement = 3;
295
+
229
296
  // prosemirror-view has a bug that it duplicates table entry when selecting multiple paragraphs in a table cell.
230
297
  // https://github.com/ProseMirror/prosemirror/issues/1270
231
298
  // The structure becomes
@@ -250,7 +317,7 @@ export const transformSliceToRemoveOpenTable = (slice: Slice, schema: Schema): S
250
317
  );
251
318
  }
252
319
 
253
- // Case 2: A slice starting within a CELL and ending outside the table
320
+ // Case 3: A slice starting within a CELL and ending outside the table
254
321
  if (
255
322
  // starts inside of a cell but ends outside of the starting table
256
323
  slice.openStart >= 4 &&