@atlaskit/editor-plugin-table 9.4.1 → 9.5.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.
@@ -2,6 +2,8 @@ import _defineProperty from "@babel/runtime/helpers/defineProperty";
2
2
  import debounce from 'lodash/debounce';
3
3
  import throttle from 'lodash/throttle';
4
4
  import { findOverflowScrollParent } from '@atlaskit/editor-common/ui';
5
+ import { findParentNodeClosestToPos } from '@atlaskit/editor-prosemirror/utils';
6
+ import { fg } from '@atlaskit/platform-feature-flags';
5
7
  import { getPluginState } from '../pm-plugins/plugin-factory';
6
8
  import { pluginKey as tablePluginKey } from '../pm-plugins/plugin-key';
7
9
  import { updateStickyState } from '../pm-plugins/sticky-headers/commands';
@@ -218,21 +220,62 @@ export default class TableRow extends TableNodeView {
218
220
  // we expect tree to be defined after animation frame
219
221
  const tableContainer = (_getTree = getTree(this.dom)) === null || _getTree === void 0 ? void 0 : _getTree.wrapper.closest(`.${TableCssClassName.NODEVIEW_WRAPPER}`);
220
222
  if (tableContainer) {
223
+ const getSentinelTop = () =>
221
224
  // Ignored via go/ees005
222
225
  // eslint-disable-next-line @atlaskit/editor/no-as-casting
223
- this.sentinels.top = tableContainer.getElementsByClassName(ClassName.TABLE_STICKY_SENTINEL_TOP).item(0);
224
- // Ignored via go/ees005
225
- // eslint-disable-next-line @atlaskit/editor/no-as-casting
226
- this.sentinels.bottom = tableContainer.getElementsByClassName(ClassName.TABLE_STICKY_SENTINEL_BOTTOM).item(0);
227
- [this.sentinels.top, this.sentinels.bottom].forEach(el => {
228
- // skip if already observed for another row on this table
229
- if (el && !el.dataset.isObserved) {
230
- el.dataset.isObserved = 'true';
231
- // Ignored via go/ees005
232
- // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
233
- this.intersectionObserver.observe(el);
226
+ tableContainer.getElementsByClassName(ClassName.TABLE_STICKY_SENTINEL_TOP).item(0);
227
+ const getSentinelBottom = () => {
228
+ // Multiple bottom sentinels may be found if there are nested tables.
229
+ // We need to make sure we get the last one which will belong to the parent table.
230
+ const bottomSentinels = tableContainer.getElementsByClassName(ClassName.TABLE_STICKY_SENTINEL_BOTTOM);
231
+ // Ignored via go/ees005
232
+ // eslint-disable-next-line @atlaskit/editor/no-as-casting
233
+ return fg('platform_editor_nested_tables_bottom_sentinel') ?
234
+ // eslint-disable-next-line @atlaskit/editor/no-as-casting
235
+ bottomSentinels.item(bottomSentinels.length - 1) :
236
+ // eslint-disable-next-line @atlaskit/editor/no-as-casting
237
+ tableContainer.getElementsByClassName(ClassName.TABLE_STICKY_SENTINEL_BOTTOM).item(0);
238
+ };
239
+ const sentinelsInDom = () => getSentinelTop() !== null && getSentinelBottom() !== null;
240
+ const observeStickySentinels = () => {
241
+ this.sentinels.top = getSentinelTop();
242
+ this.sentinels.bottom = getSentinelBottom();
243
+ [this.sentinels.top, this.sentinels.bottom].forEach(el => {
244
+ // skip if already observed for another row on this table
245
+ if (el && !el.dataset.isObserved) {
246
+ el.dataset.isObserved = 'true';
247
+ // Ignored via go/ees005
248
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
249
+ this.intersectionObserver.observe(el);
250
+ }
251
+ });
252
+ };
253
+ if (fg('platform_editor_react18_stickyheaders_fix')) {
254
+ if (sentinelsInDom()) {
255
+ // great - DOM ready, observe as normal
256
+ observeStickySentinels();
257
+ } else {
258
+ // concurrent loading issue - here TableRow is too eager trying to
259
+ // observe sentinels before they are in the DOM, use MutationObserver
260
+ // to wait for sentinels to be added to the parent Table node DOM
261
+ // then attach the IntersectionObserver
262
+ const tableContainerObserver = new MutationObserver(() => {
263
+ if (sentinelsInDom()) {
264
+ observeStickySentinels();
265
+ tableContainerObserver.disconnect();
266
+ }
267
+ });
268
+ const mutatingNode = tableContainer;
269
+ if (mutatingNode) {
270
+ tableContainerObserver.observe(mutatingNode, {
271
+ subtree: true,
272
+ childList: true
273
+ });
274
+ }
234
275
  }
235
- });
276
+ } else {
277
+ observeStickySentinels();
278
+ }
236
279
  }
237
280
  });
238
281
  }
@@ -311,7 +354,7 @@ export default class TableRow extends TableNodeView {
311
354
  const {
312
355
  table
313
356
  } = tree;
314
- const shouldStick = this.isHeaderSticky();
357
+ const shouldStick = this.shouldSticky();
315
358
  if (this.isSticky !== shouldStick) {
316
359
  if (shouldStick) {
317
360
  var _this$sentinelData$to;
@@ -323,6 +366,28 @@ export default class TableRow extends TableNodeView {
323
366
  }
324
367
  }
325
368
  }
369
+ shouldSticky() {
370
+ if (
371
+ // is Safari
372
+ navigator.userAgent.includes('AppleWebKit') && !navigator.userAgent.includes('Chrome') && fg('platform_editor_advanced_layouts_post_fix_patch_4')) {
373
+ const pos = this.getPos();
374
+ if (typeof pos === 'number') {
375
+ const $tableRowPos = this.view.state.doc.resolve(pos);
376
+
377
+ // layout -> layout column -> table -> table row
378
+ if ($tableRowPos.depth >= 3) {
379
+ var _findParentNodeCloses;
380
+ const isInsideLayout = (_findParentNodeCloses = findParentNodeClosestToPos($tableRowPos, node => {
381
+ return node.type.name === 'layoutColumn';
382
+ })) === null || _findParentNodeCloses === void 0 ? void 0 : _findParentNodeCloses.node;
383
+ if (isInsideLayout) {
384
+ return false;
385
+ }
386
+ }
387
+ }
388
+ }
389
+ return this.isHeaderSticky();
390
+ }
326
391
  isHeaderSticky() {
327
392
  var _sentinelTop$rootBoun;
328
393
  /*
@@ -1,5 +1,6 @@
1
1
  import _defineProperty from "@babel/runtime/helpers/defineProperty";
2
2
  import { findOverflowScrollParent } from '@atlaskit/editor-common/ui';
3
+ import { fg } from '@atlaskit/platform-feature-flags';
3
4
  import { editorExperiment } from '@atlaskit/tmp-editor-statsig/experiments';
4
5
  import { TableCssClassName as ClassName } from '../types';
5
6
  export class TableStickyScrollbar {
@@ -50,7 +51,7 @@ export class TableStickyScrollbar {
50
51
  this.createIntersectionObserver();
51
52
  }
52
53
  createIntersectionObserver() {
53
- var _this$wrapper, _this$wrapper$parentE2, _this$wrapper$parentE3, _this$wrapper2, _this$wrapper2$parent, _this$wrapper2$parent2;
54
+ var _this$wrapper, _this$wrapper$parentE2, _this$wrapper2, _this$wrapper2$parent, _this$wrapper2$parent2, _this$wrapper3, _this$wrapper3$parent, _this$wrapper3$parent2;
54
55
  this.editorScrollableElement =
55
56
  // Ignored via go/ees005
56
57
  // eslint-disable-next-line @atlaskit/editor/no-as-casting
@@ -82,13 +83,15 @@ export class TableStickyScrollbar {
82
83
  root: this.editorScrollableElement
83
84
  });
84
85
 
85
- // Ignored via go/ees005
86
- // eslint-disable-next-line @atlaskit/editor/no-as-casting
87
- this.sentinels.bottom = (_this$wrapper = this.wrapper) === null || _this$wrapper === void 0 ? void 0 : (_this$wrapper$parentE2 = _this$wrapper.parentElement) === null || _this$wrapper$parentE2 === void 0 ? void 0 : (_this$wrapper$parentE3 = _this$wrapper$parentE2.getElementsByClassName(ClassName.TABLE_STICKY_SCROLLBAR_SENTINEL_BOTTOM)) === null || _this$wrapper$parentE3 === void 0 ? void 0 : _this$wrapper$parentE3.item(0);
86
+ // Multiple bottom sentinels may be found if there are nested tables. We need to make sure we get the last one which will belong to the parent table.
87
+ const bottomSentinels = (_this$wrapper = this.wrapper) === null || _this$wrapper === void 0 ? void 0 : (_this$wrapper$parentE2 = _this$wrapper.parentElement) === null || _this$wrapper$parentE2 === void 0 ? void 0 : _this$wrapper$parentE2.getElementsByClassName(ClassName.TABLE_STICKY_SCROLLBAR_SENTINEL_BOTTOM);
88
+ this.sentinels.bottom = fg('platform_editor_nested_tables_bottom_sentinel') ? // eslint-disable-next-line @atlaskit/editor/no-as-casting
89
+ bottomSentinels === null || bottomSentinels === void 0 ? void 0 : bottomSentinels.item(bottomSentinels.length - 1) : // eslint-disable-next-line @atlaskit/editor/no-as-casting
90
+ (_this$wrapper2 = this.wrapper) === null || _this$wrapper2 === void 0 ? void 0 : (_this$wrapper2$parent = _this$wrapper2.parentElement) === null || _this$wrapper2$parent === void 0 ? void 0 : (_this$wrapper2$parent2 = _this$wrapper2$parent.getElementsByClassName(ClassName.TABLE_STICKY_SCROLLBAR_SENTINEL_BOTTOM)) === null || _this$wrapper2$parent2 === void 0 ? void 0 : _this$wrapper2$parent2.item(0);
88
91
 
89
92
  // Ignored via go/ees005
90
93
  // eslint-disable-next-line @atlaskit/editor/no-as-casting
91
- this.sentinels.top = (_this$wrapper2 = this.wrapper) === null || _this$wrapper2 === void 0 ? void 0 : (_this$wrapper2$parent = _this$wrapper2.parentElement) === null || _this$wrapper2$parent === void 0 ? void 0 : (_this$wrapper2$parent2 = _this$wrapper2$parent.getElementsByClassName(ClassName.TABLE_STICKY_SCROLLBAR_SENTINEL_TOP)) === null || _this$wrapper2$parent2 === void 0 ? void 0 : _this$wrapper2$parent2.item(0);
94
+ this.sentinels.top = (_this$wrapper3 = this.wrapper) === null || _this$wrapper3 === void 0 ? void 0 : (_this$wrapper3$parent = _this$wrapper3.parentElement) === null || _this$wrapper3$parent === void 0 ? void 0 : (_this$wrapper3$parent2 = _this$wrapper3$parent.getElementsByClassName(ClassName.TABLE_STICKY_SCROLLBAR_SENTINEL_TOP)) === null || _this$wrapper3$parent2 === void 0 ? void 0 : _this$wrapper3$parent2.item(0);
92
95
  [this.sentinels.bottom, this.sentinels.top].forEach(el =>
93
96
  // Ignored via go/ees005
94
97
  // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
@@ -1,11 +1,13 @@
1
1
  import { withLazyLoading } from '@atlaskit/editor-common/lazy-node-view';
2
+ import { fg } from '@atlaskit/platform-feature-flags';
2
3
  import { editorExperiment } from '@atlaskit/tmp-editor-statsig/experiments';
3
4
  // TODO: Clean up ED-23976
4
5
  import { createTableView } from './table';
5
6
  import TableCell from './TableCell';
6
7
  import TableRow from './TableRow';
7
8
  export const lazyTableView = options => {
8
- if (editorExperiment('platform_editor_exp_lazy_node_views', false)) {
9
+ // LNV tables are broken in concurrent mode - temporarily disable to unblock concurrent mode
10
+ if (editorExperiment('platform_editor_exp_lazy_node_views', false) || fg('platform_editor_disable_table_lnv')) {
9
11
  return (node, view, getPos) => {
10
12
  return createTableView(node, view, getPos, options.portalProviderAPI, options.eventDispatcher, options.getEditorContainerWidth, options.getEditorFeatureFlags, options.dispatchAnalyticsEvent, options.pluginInjectionApi, options.isCommentEditor, options.isChromelessEditor);
11
13
  };
@@ -38,7 +40,8 @@ export const lazyTableView = options => {
38
40
  });
39
41
  };
40
42
  export const lazyTableCellView = options => {
41
- if (editorExperiment('platform_editor_exp_lazy_node_views', false)) {
43
+ // LNV tables are broken in concurrent mode - temporarily disable to unblock concurrent mode
44
+ if (editorExperiment('platform_editor_exp_lazy_node_views', false) || fg('platform_editor_disable_table_lnv')) {
42
45
  return (node, view, getPos) => {
43
46
  var _options$pluginInject, _options$pluginInject2;
44
47
  return new TableCell(node, view, getPos, options.eventDispatcher, (_options$pluginInject = options.pluginInjectionApi) === null || _options$pluginInject === void 0 ? void 0 : (_options$pluginInject2 = _options$pluginInject.analytics) === null || _options$pluginInject2 === void 0 ? void 0 : _options$pluginInject2.actions);
@@ -67,7 +70,8 @@ export const lazyTableCellView = options => {
67
70
  });
68
71
  };
69
72
  export const lazyTableHeaderView = options => {
70
- if (editorExperiment('platform_editor_exp_lazy_node_views', false)) {
73
+ // LNV tables are broken in concurrent mode - temporarily disable to unblock concurrent mode
74
+ if (editorExperiment('platform_editor_exp_lazy_node_views', false) || fg('platform_editor_disable_table_lnv')) {
71
75
  return (node, view, getPos) => {
72
76
  var _options$pluginInject3, _options$pluginInject4;
73
77
  return new TableCell(node, view, getPos, options.eventDispatcher, (_options$pluginInject3 = options.pluginInjectionApi) === null || _options$pluginInject3 === void 0 ? void 0 : (_options$pluginInject4 = _options$pluginInject3.analytics) === null || _options$pluginInject4 === void 0 ? void 0 : _options$pluginInject4.actions);
@@ -96,7 +100,8 @@ export const lazyTableHeaderView = options => {
96
100
  });
97
101
  };
98
102
  export const lazyTableRowView = options => {
99
- if (editorExperiment('platform_editor_exp_lazy_node_views', false)) {
103
+ // LNV tables are broken in concurrent mode - temporarily disable to unblock concurrent mode
104
+ if (editorExperiment('platform_editor_exp_lazy_node_views', false) || fg('platform_editor_disable_table_lnv')) {
100
105
  return (node, view, getPos) => {
101
106
  return new TableRow(node, view, getPos, options.eventDispatcher);
102
107
  };
@@ -170,14 +170,19 @@ const isNodeSingleCellTable = (node, schema) => {
170
170
  const isFragmentSingleCellTable = (fragment, schema) => {
171
171
  return fragment.childCount === 1 && fragment.firstChild !== null && isNodeSingleCellTable(fragment.firstChild, schema);
172
172
  };
173
- const containsTextBlockChildren = (fragment, schema) => {
174
- let containsTextBlock = false;
173
+ const containsNonTableBlockChildren = (fragment, schema) => {
174
+ let containsNonTableBlock = false;
175
+ const {
176
+ table,
177
+ tableCell,
178
+ tableHeader
179
+ } = schema.nodes;
175
180
  fragment.forEach(node => {
176
- if (node.isTextblock) {
177
- containsTextBlock = true;
181
+ if (node.isBlock && ![table, tableCell, tableHeader].includes(node.type)) {
182
+ containsNonTableBlock = true;
178
183
  }
179
184
  });
180
- return containsTextBlock;
185
+ return containsNonTableBlock;
181
186
  };
182
187
  export const transformSliceToRemoveOpenTable = (slice, schema) => {
183
188
  var _slice$content$firstC8;
@@ -187,7 +192,7 @@ export const transformSliceToRemoveOpenTable = (slice, schema) => {
187
192
  // We are using `safeInsert` to paste nested tables, so we do not want to preserve this wrapping
188
193
 
189
194
  // slice starts and ends inside a nested table at the same depth
190
- if (slice.openStart >= 7 && slice.openEnd >= 7 && slice.openStart === slice.openEnd) {
195
+ if (slice.openStart >= 7 && slice.openEnd >= 7) {
191
196
  let cleaned = slice;
192
197
  let descendedDepth = 0;
193
198
  const tableDepthDecrement = 2;
@@ -200,9 +205,9 @@ export const transformSliceToRemoveOpenTable = (slice, schema) => {
200
205
  descendedDepth += tableDepthDecrement;
201
206
  } else if (node.type === schema.nodes.table) {
202
207
  return false;
203
- } else if (containsTextBlockChildren(node.content, schema)) {
208
+ } else if (containsNonTableBlockChildren(node.content, schema)) {
204
209
  descendedDepth += tableDepthDecrement;
205
- // create a new slice with the content of the textblock children and the depth of the nested tables subtracted
210
+ // create a new slice with the content of non-table block children and the depth of the nested tables subtracted
206
211
  cleaned = new Slice(node.content, slice.openStart - descendedDepth - tableDepthDecrement, slice.openEnd - descendedDepth - tableDepthDecrement);
207
212
  return false;
208
213
  }
@@ -10,6 +10,7 @@ import { tableMarginTop, tableSharedStyle } from '@atlaskit/editor-common/styles
10
10
  import { SORTABLE_COLUMN_ICON_CLASSNAME } from '@atlaskit/editor-common/table';
11
11
  import { akEditorSelectedNodeClassName, akEditorSmallZIndex, akEditorStickyHeaderZIndex, akEditorTableCellOnStickyHeaderZIndex, akEditorTableNumberColumnWidth, akEditorTableToolbarSize, akEditorUnitZIndex, getSelectionStyles, MAX_BROWSER_SCROLLBAR_HEIGHT, relativeFontSizeToBase16, SelectionStyle } from '@atlaskit/editor-shared-styles';
12
12
  import { scrollbarStyles } from '@atlaskit/editor-shared-styles/scrollbar';
13
+ import { fg } from '@atlaskit/platform-feature-flags';
13
14
  import { N0, N40A, R500 } from '@atlaskit/theme/colors';
14
15
  import { editorExperiment } from '@atlaskit/tmp-editor-statsig/experiments';
15
16
  import { SORTING_ICON_CLASS_NAME } from '../pm-plugins/view-mode-sort/consts';
@@ -124,34 +125,65 @@ const breakoutWidthStyling = () => {
124
125
  `;
125
126
  };
126
127
  const viewModeSortStyles = () => {
127
- return css`
128
- th {
129
- .${SORTING_ICON_CLASS_NAME} {
130
- + p {
131
- margin-top: 0 !important;
132
- }
133
- }
128
+ return fg('platform_editor_nested_tables_view_mode_sort') ? css`
129
+ // new styles
130
+ th {
131
+ .${SORTING_ICON_CLASS_NAME} {
132
+ + p {
133
+ margin-top: 0 !important;
134
+ }
135
+ }
134
136
 
135
- &:has(.is-active) {
136
- .${SORTABLE_COLUMN_ICON_CLASSNAME} {
137
- opacity: 1;
138
- }
139
- }
137
+ &:has(.is-active) {
138
+ .${SORTABLE_COLUMN_ICON_CLASSNAME} {
139
+ opacity: 1;
140
+ }
141
+ }
142
+
143
+ .${SORTABLE_COLUMN_ICON_CLASSNAME} {
144
+ opacity: 0;
145
+ &:focus {
146
+ opacity: 1;
147
+ }
148
+ }
140
149
 
141
- .${SORTABLE_COLUMN_ICON_CLASSNAME} {
142
- opacity: 0;
143
- &:focus {
144
- opacity: 1;
150
+ &:hover:not(:has(.${ClassName.TABLE_CONTAINER}:hover)) {
151
+ > .${SORTING_ICON_CLASS_NAME} {
152
+ .${SORTABLE_COLUMN_ICON_CLASSNAME} {
153
+ opacity: 1;
154
+ }
155
+ }
156
+ }
145
157
  }
146
- }
158
+ ` : css`
159
+ // old styles
160
+ th {
161
+ .${SORTING_ICON_CLASS_NAME} {
162
+ + p {
163
+ margin-top: 0 !important;
164
+ }
165
+ }
147
166
 
148
- &:hover {
149
- .${SORTABLE_COLUMN_ICON_CLASSNAME} {
150
- opacity: 1;
167
+ &:has(.is-active) {
168
+ .${SORTABLE_COLUMN_ICON_CLASSNAME} {
169
+ opacity: 1;
170
+ }
171
+ }
172
+
173
+ .${SORTABLE_COLUMN_ICON_CLASSNAME} {
174
+ opacity: 0;
175
+ &:focus {
176
+ opacity: 1;
177
+ }
178
+ }
179
+
180
+ &:hover {
181
+ .${SORTABLE_COLUMN_ICON_CLASSNAME} {
182
+ opacity: 1;
183
+ }
184
+ }
151
185
  }
152
- }
153
- }
154
- `;
186
+ `;
155
187
  };
156
188
  const tableBorderStyles = () => {
157
189
  return `border-color: ${tableBorderDeleteColor}`;
@@ -9,6 +9,8 @@ function _isNativeReflectConstruct() { try { var t = !Boolean.prototype.valueOf.
9
9
  import debounce from 'lodash/debounce';
10
10
  import throttle from 'lodash/throttle';
11
11
  import { findOverflowScrollParent } from '@atlaskit/editor-common/ui';
12
+ import { findParentNodeClosestToPos } from '@atlaskit/editor-prosemirror/utils';
13
+ import { fg } from '@atlaskit/platform-feature-flags';
12
14
  import { getPluginState } from '../pm-plugins/plugin-factory';
13
15
  import { pluginKey as tablePluginKey } from '../pm-plugins/plugin-key';
14
16
  import { updateStickyState } from '../pm-plugins/sticky-headers/commands';
@@ -241,21 +243,67 @@ var TableRow = /*#__PURE__*/function (_TableNodeView) {
241
243
  // we expect tree to be defined after animation frame
242
244
  var tableContainer = (_getTree = getTree(_this2.dom)) === null || _getTree === void 0 ? void 0 : _getTree.wrapper.closest(".".concat(TableCssClassName.NODEVIEW_WRAPPER));
243
245
  if (tableContainer) {
244
- // Ignored via go/ees005
245
- // eslint-disable-next-line @atlaskit/editor/no-as-casting
246
- _this2.sentinels.top = tableContainer.getElementsByClassName(ClassName.TABLE_STICKY_SENTINEL_TOP).item(0);
247
- // Ignored via go/ees005
248
- // eslint-disable-next-line @atlaskit/editor/no-as-casting
249
- _this2.sentinels.bottom = tableContainer.getElementsByClassName(ClassName.TABLE_STICKY_SENTINEL_BOTTOM).item(0);
250
- [_this2.sentinels.top, _this2.sentinels.bottom].forEach(function (el) {
251
- // skip if already observed for another row on this table
252
- if (el && !el.dataset.isObserved) {
253
- el.dataset.isObserved = 'true';
246
+ var getSentinelTop = function getSentinelTop() {
247
+ return (
254
248
  // Ignored via go/ees005
255
- // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
256
- _this2.intersectionObserver.observe(el);
249
+ // eslint-disable-next-line @atlaskit/editor/no-as-casting
250
+ tableContainer.getElementsByClassName(ClassName.TABLE_STICKY_SENTINEL_TOP).item(0)
251
+ );
252
+ };
253
+ var getSentinelBottom = function getSentinelBottom() {
254
+ // Multiple bottom sentinels may be found if there are nested tables.
255
+ // We need to make sure we get the last one which will belong to the parent table.
256
+ var bottomSentinels = tableContainer.getElementsByClassName(ClassName.TABLE_STICKY_SENTINEL_BOTTOM);
257
+ // Ignored via go/ees005
258
+ // eslint-disable-next-line @atlaskit/editor/no-as-casting
259
+ return fg('platform_editor_nested_tables_bottom_sentinel') ?
260
+ // eslint-disable-next-line @atlaskit/editor/no-as-casting
261
+ bottomSentinels.item(bottomSentinels.length - 1) :
262
+ // eslint-disable-next-line @atlaskit/editor/no-as-casting
263
+ tableContainer.getElementsByClassName(ClassName.TABLE_STICKY_SENTINEL_BOTTOM).item(0);
264
+ };
265
+ var sentinelsInDom = function sentinelsInDom() {
266
+ return getSentinelTop() !== null && getSentinelBottom() !== null;
267
+ };
268
+ var observeStickySentinels = function observeStickySentinels() {
269
+ _this2.sentinels.top = getSentinelTop();
270
+ _this2.sentinels.bottom = getSentinelBottom();
271
+ [_this2.sentinels.top, _this2.sentinels.bottom].forEach(function (el) {
272
+ // skip if already observed for another row on this table
273
+ if (el && !el.dataset.isObserved) {
274
+ el.dataset.isObserved = 'true';
275
+ // Ignored via go/ees005
276
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
277
+ _this2.intersectionObserver.observe(el);
278
+ }
279
+ });
280
+ };
281
+ if (fg('platform_editor_react18_stickyheaders_fix')) {
282
+ if (sentinelsInDom()) {
283
+ // great - DOM ready, observe as normal
284
+ observeStickySentinels();
285
+ } else {
286
+ // concurrent loading issue - here TableRow is too eager trying to
287
+ // observe sentinels before they are in the DOM, use MutationObserver
288
+ // to wait for sentinels to be added to the parent Table node DOM
289
+ // then attach the IntersectionObserver
290
+ var tableContainerObserver = new MutationObserver(function () {
291
+ if (sentinelsInDom()) {
292
+ observeStickySentinels();
293
+ tableContainerObserver.disconnect();
294
+ }
295
+ });
296
+ var mutatingNode = tableContainer;
297
+ if (mutatingNode) {
298
+ tableContainerObserver.observe(mutatingNode, {
299
+ subtree: true,
300
+ childList: true
301
+ });
302
+ }
257
303
  }
258
- });
304
+ } else {
305
+ observeStickySentinels();
306
+ }
259
307
  }
260
308
  });
261
309
  }
@@ -336,7 +384,7 @@ var TableRow = /*#__PURE__*/function (_TableNodeView) {
336
384
  return;
337
385
  }
338
386
  var table = tree.table;
339
- var shouldStick = this.isHeaderSticky();
387
+ var shouldStick = this.shouldSticky();
340
388
  if (this.isSticky !== shouldStick) {
341
389
  if (shouldStick) {
342
390
  var _this$sentinelData$to;
@@ -348,6 +396,30 @@ var TableRow = /*#__PURE__*/function (_TableNodeView) {
348
396
  }
349
397
  }
350
398
  }
399
+ }, {
400
+ key: "shouldSticky",
401
+ value: function shouldSticky() {
402
+ if (
403
+ // is Safari
404
+ navigator.userAgent.includes('AppleWebKit') && !navigator.userAgent.includes('Chrome') && fg('platform_editor_advanced_layouts_post_fix_patch_4')) {
405
+ var pos = this.getPos();
406
+ if (typeof pos === 'number') {
407
+ var $tableRowPos = this.view.state.doc.resolve(pos);
408
+
409
+ // layout -> layout column -> table -> table row
410
+ if ($tableRowPos.depth >= 3) {
411
+ var _findParentNodeCloses;
412
+ var isInsideLayout = (_findParentNodeCloses = findParentNodeClosestToPos($tableRowPos, function (node) {
413
+ return node.type.name === 'layoutColumn';
414
+ })) === null || _findParentNodeCloses === void 0 ? void 0 : _findParentNodeCloses.node;
415
+ if (isInsideLayout) {
416
+ return false;
417
+ }
418
+ }
419
+ }
420
+ }
421
+ return this.isHeaderSticky();
422
+ }
351
423
  }, {
352
424
  key: "isHeaderSticky",
353
425
  value: function isHeaderSticky() {
@@ -2,6 +2,7 @@ import _classCallCheck from "@babel/runtime/helpers/classCallCheck";
2
2
  import _createClass from "@babel/runtime/helpers/createClass";
3
3
  import _defineProperty from "@babel/runtime/helpers/defineProperty";
4
4
  import { findOverflowScrollParent } from '@atlaskit/editor-common/ui';
5
+ import { fg } from '@atlaskit/platform-feature-flags';
5
6
  import { editorExperiment } from '@atlaskit/tmp-editor-statsig/experiments';
6
7
  import { TableCssClassName as ClassName } from '../types';
7
8
  export var TableStickyScrollbar = /*#__PURE__*/function () {
@@ -64,7 +65,8 @@ export var TableStickyScrollbar = /*#__PURE__*/function () {
64
65
  value: function createIntersectionObserver() {
65
66
  var _this2 = this,
66
67
  _this$wrapper,
67
- _this$wrapper2;
68
+ _this$wrapper2,
69
+ _this$wrapper3;
68
70
  this.editorScrollableElement =
69
71
  // Ignored via go/ees005
70
72
  // eslint-disable-next-line @atlaskit/editor/no-as-casting
@@ -96,13 +98,15 @@ export var TableStickyScrollbar = /*#__PURE__*/function () {
96
98
  root: this.editorScrollableElement
97
99
  });
98
100
 
99
- // Ignored via go/ees005
100
- // eslint-disable-next-line @atlaskit/editor/no-as-casting
101
- this.sentinels.bottom = (_this$wrapper = this.wrapper) === null || _this$wrapper === void 0 || (_this$wrapper = _this$wrapper.parentElement) === null || _this$wrapper === void 0 || (_this$wrapper = _this$wrapper.getElementsByClassName(ClassName.TABLE_STICKY_SCROLLBAR_SENTINEL_BOTTOM)) === null || _this$wrapper === void 0 ? void 0 : _this$wrapper.item(0);
101
+ // Multiple bottom sentinels may be found if there are nested tables. We need to make sure we get the last one which will belong to the parent table.
102
+ var bottomSentinels = (_this$wrapper = this.wrapper) === null || _this$wrapper === void 0 || (_this$wrapper = _this$wrapper.parentElement) === null || _this$wrapper === void 0 ? void 0 : _this$wrapper.getElementsByClassName(ClassName.TABLE_STICKY_SCROLLBAR_SENTINEL_BOTTOM);
103
+ this.sentinels.bottom = fg('platform_editor_nested_tables_bottom_sentinel') ? // eslint-disable-next-line @atlaskit/editor/no-as-casting
104
+ bottomSentinels === null || bottomSentinels === void 0 ? void 0 : bottomSentinels.item(bottomSentinels.length - 1) : // eslint-disable-next-line @atlaskit/editor/no-as-casting
105
+ (_this$wrapper2 = this.wrapper) === null || _this$wrapper2 === void 0 || (_this$wrapper2 = _this$wrapper2.parentElement) === null || _this$wrapper2 === void 0 || (_this$wrapper2 = _this$wrapper2.getElementsByClassName(ClassName.TABLE_STICKY_SCROLLBAR_SENTINEL_BOTTOM)) === null || _this$wrapper2 === void 0 ? void 0 : _this$wrapper2.item(0);
102
106
 
103
107
  // Ignored via go/ees005
104
108
  // eslint-disable-next-line @atlaskit/editor/no-as-casting
105
- this.sentinels.top = (_this$wrapper2 = this.wrapper) === null || _this$wrapper2 === void 0 || (_this$wrapper2 = _this$wrapper2.parentElement) === null || _this$wrapper2 === void 0 || (_this$wrapper2 = _this$wrapper2.getElementsByClassName(ClassName.TABLE_STICKY_SCROLLBAR_SENTINEL_TOP)) === null || _this$wrapper2 === void 0 ? void 0 : _this$wrapper2.item(0);
109
+ this.sentinels.top = (_this$wrapper3 = this.wrapper) === null || _this$wrapper3 === void 0 || (_this$wrapper3 = _this$wrapper3.parentElement) === null || _this$wrapper3 === void 0 || (_this$wrapper3 = _this$wrapper3.getElementsByClassName(ClassName.TABLE_STICKY_SCROLLBAR_SENTINEL_TOP)) === null || _this$wrapper3 === void 0 ? void 0 : _this$wrapper3.item(0);
106
110
  [this.sentinels.bottom, this.sentinels.top].forEach(function (el) {
107
111
  return (
108
112
  // Ignored via go/ees005
@@ -1,11 +1,13 @@
1
1
  import { withLazyLoading } from '@atlaskit/editor-common/lazy-node-view';
2
+ import { fg } from '@atlaskit/platform-feature-flags';
2
3
  import { editorExperiment } from '@atlaskit/tmp-editor-statsig/experiments';
3
4
  // TODO: Clean up ED-23976
4
5
  import { createTableView } from './table';
5
6
  import TableCell from './TableCell';
6
7
  import TableRow from './TableRow';
7
8
  export var lazyTableView = function lazyTableView(options) {
8
- if (editorExperiment('platform_editor_exp_lazy_node_views', false)) {
9
+ // LNV tables are broken in concurrent mode - temporarily disable to unblock concurrent mode
10
+ if (editorExperiment('platform_editor_exp_lazy_node_views', false) || fg('platform_editor_disable_table_lnv')) {
9
11
  return function (node, view, getPos) {
10
12
  return createTableView(node, view, getPos, options.portalProviderAPI, options.eventDispatcher, options.getEditorContainerWidth, options.getEditorFeatureFlags, options.dispatchAnalyticsEvent, options.pluginInjectionApi, options.isCommentEditor, options.isChromelessEditor);
11
13
  };
@@ -38,7 +40,8 @@ export var lazyTableView = function lazyTableView(options) {
38
40
  });
39
41
  };
40
42
  export var lazyTableCellView = function lazyTableCellView(options) {
41
- if (editorExperiment('platform_editor_exp_lazy_node_views', false)) {
43
+ // LNV tables are broken in concurrent mode - temporarily disable to unblock concurrent mode
44
+ if (editorExperiment('platform_editor_exp_lazy_node_views', false) || fg('platform_editor_disable_table_lnv')) {
42
45
  return function (node, view, getPos) {
43
46
  var _options$pluginInject;
44
47
  return new TableCell(node, view, getPos, options.eventDispatcher, (_options$pluginInject = options.pluginInjectionApi) === null || _options$pluginInject === void 0 || (_options$pluginInject = _options$pluginInject.analytics) === null || _options$pluginInject === void 0 ? void 0 : _options$pluginInject.actions);
@@ -67,7 +70,8 @@ export var lazyTableCellView = function lazyTableCellView(options) {
67
70
  });
68
71
  };
69
72
  export var lazyTableHeaderView = function lazyTableHeaderView(options) {
70
- if (editorExperiment('platform_editor_exp_lazy_node_views', false)) {
73
+ // LNV tables are broken in concurrent mode - temporarily disable to unblock concurrent mode
74
+ if (editorExperiment('platform_editor_exp_lazy_node_views', false) || fg('platform_editor_disable_table_lnv')) {
71
75
  return function (node, view, getPos) {
72
76
  var _options$pluginInject2;
73
77
  return new TableCell(node, view, getPos, options.eventDispatcher, (_options$pluginInject2 = options.pluginInjectionApi) === null || _options$pluginInject2 === void 0 || (_options$pluginInject2 = _options$pluginInject2.analytics) === null || _options$pluginInject2 === void 0 ? void 0 : _options$pluginInject2.actions);
@@ -96,7 +100,8 @@ export var lazyTableHeaderView = function lazyTableHeaderView(options) {
96
100
  });
97
101
  };
98
102
  export var lazyTableRowView = function lazyTableRowView(options) {
99
- if (editorExperiment('platform_editor_exp_lazy_node_views', false)) {
103
+ // LNV tables are broken in concurrent mode - temporarily disable to unblock concurrent mode
104
+ if (editorExperiment('platform_editor_exp_lazy_node_views', false) || fg('platform_editor_disable_table_lnv')) {
100
105
  return function (node, view, getPos) {
101
106
  return new TableRow(node, view, getPos, options.eventDispatcher);
102
107
  };
@@ -172,14 +172,18 @@ var isNodeSingleCellTable = function isNodeSingleCellTable(node, schema) {
172
172
  var isFragmentSingleCellTable = function isFragmentSingleCellTable(fragment, schema) {
173
173
  return fragment.childCount === 1 && fragment.firstChild !== null && isNodeSingleCellTable(fragment.firstChild, schema);
174
174
  };
175
- var containsTextBlockChildren = function containsTextBlockChildren(fragment, schema) {
176
- var containsTextBlock = false;
175
+ var containsNonTableBlockChildren = function containsNonTableBlockChildren(fragment, schema) {
176
+ var containsNonTableBlock = false;
177
+ var _schema$nodes4 = schema.nodes,
178
+ table = _schema$nodes4.table,
179
+ tableCell = _schema$nodes4.tableCell,
180
+ tableHeader = _schema$nodes4.tableHeader;
177
181
  fragment.forEach(function (node) {
178
- if (node.isTextblock) {
179
- containsTextBlock = true;
182
+ if (node.isBlock && ![table, tableCell, tableHeader].includes(node.type)) {
183
+ containsNonTableBlock = true;
180
184
  }
181
185
  });
182
- return containsTextBlock;
186
+ return containsNonTableBlock;
183
187
  };
184
188
  export var transformSliceToRemoveOpenTable = function transformSliceToRemoveOpenTable(slice, schema) {
185
189
  var _slice$content$firstC4;
@@ -189,7 +193,7 @@ export var transformSliceToRemoveOpenTable = function transformSliceToRemoveOpen
189
193
  // We are using `safeInsert` to paste nested tables, so we do not want to preserve this wrapping
190
194
 
191
195
  // slice starts and ends inside a nested table at the same depth
192
- if (slice.openStart >= 7 && slice.openEnd >= 7 && slice.openStart === slice.openEnd) {
196
+ if (slice.openStart >= 7 && slice.openEnd >= 7) {
193
197
  var cleaned = slice;
194
198
  var descendedDepth = 0;
195
199
  var tableDepthDecrement = 2;
@@ -202,9 +206,9 @@ export var transformSliceToRemoveOpenTable = function transformSliceToRemoveOpen
202
206
  descendedDepth += tableDepthDecrement;
203
207
  } else if (node.type === schema.nodes.table) {
204
208
  return false;
205
- } else if (containsTextBlockChildren(node.content, schema)) {
209
+ } else if (containsNonTableBlockChildren(node.content, schema)) {
206
210
  descendedDepth += tableDepthDecrement;
207
- // create a new slice with the content of the textblock children and the depth of the nested tables subtracted
211
+ // create a new slice with the content of non-table block children and the depth of the nested tables subtracted
208
212
  cleaned = new Slice(node.content, slice.openStart - descendedDepth - tableDepthDecrement, slice.openEnd - descendedDepth - tableDepthDecrement);
209
213
  return false;
210
214
  }
@@ -254,9 +258,9 @@ export var transformSliceToRemoveOpenTable = function transformSliceToRemoveOpen
254
258
  return slice;
255
259
  };
256
260
  export var transformSliceToCorrectEmptyTableCells = function transformSliceToCorrectEmptyTableCells(slice, schema) {
257
- var _schema$nodes4 = schema.nodes,
258
- tableCell = _schema$nodes4.tableCell,
259
- tableHeader = _schema$nodes4.tableHeader;
261
+ var _schema$nodes5 = schema.nodes,
262
+ tableCell = _schema$nodes5.tableCell,
263
+ tableHeader = _schema$nodes5.tableHeader;
260
264
  return mapSlice(slice, function (node) {
261
265
  if (node && (node.type === tableCell || node.type === tableHeader) && !node.content.childCount) {
262
266
  return node.type.createAndFill(node.attrs) || node;