@atlaskit/editor-plugin-table 3.2.0 → 3.2.1

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,11 @@
1
1
  # @atlaskit/editor-plugin-table
2
2
 
3
+ ## 3.2.1
4
+
5
+ ### Patch Changes
6
+
7
+ - [`b1a93f61747`](https://bitbucket.org/atlassian/atlassian-frontend/commits/b1a93f61747) - [ED-20091] add logic to refire intersection observers and prevent detached table sticky headers
8
+
3
9
  ## 3.2.0
4
10
 
5
11
  ### Minor Changes
@@ -149,10 +149,24 @@ var TableRowNodeView = /*#__PURE__*/function () {
149
149
  // otherwise make it non-sticky
150
150
  return false;
151
151
  });
152
+ /**
153
+ * Manually refire the intersection observers.
154
+ * Useful when the header may have detached from the table.
155
+ */
156
+ (0, _defineProperty2.default)(this, "refireIntersectionObservers", function () {
157
+ if (_this.isSticky) {
158
+ [_this.sentinels.top, _this.sentinels.bottom].forEach(function (el) {
159
+ if (el && _this.intersectionObserver) {
160
+ _this.intersectionObserver.unobserve(el);
161
+ _this.intersectionObserver.observe(el);
162
+ }
163
+ });
164
+ }
165
+ });
152
166
  (0, _defineProperty2.default)(this, "makeHeaderRowSticky", function (tree, scrollTop) {
153
167
  var _tbody$firstChild;
154
168
  // If header row height is more than 50% of viewport height don't do this
155
- if (_this.stickyRowHeight && _this.stickyRowHeight > window.innerHeight / 2) {
169
+ if (_this.isSticky || _this.stickyRowHeight && _this.stickyRowHeight > window.innerHeight / 2) {
156
170
  return;
157
171
  }
158
172
  var table = tree.table,
@@ -170,10 +184,25 @@ var TableRowNodeView = /*#__PURE__*/function () {
170
184
  }
171
185
  var domTop = currentTableTop > 0 ? scrollTop : scrollTop + currentTableTop;
172
186
  if (!_this.isSticky) {
187
+ var _this$editorScrollabl;
173
188
  (0, _dom.syncStickyRowToTable)(table);
174
189
  _this.dom.classList.add('sticky');
175
190
  table.classList.add(_types.TableCssClassName.TABLE_STICKY);
176
191
  _this.isSticky = true;
192
+
193
+ /**
194
+ * The logic below is not desirable, but acts as a fail safe for scenarios where the sticky header
195
+ * detaches from the table. This typically happens during a fast scroll by the user which causes
196
+ * the intersection observer logic to not fire as expected.
197
+ */
198
+ (_this$editorScrollabl = _this.editorScrollableElement) === null || _this$editorScrollabl === void 0 ? void 0 : _this$editorScrollabl.addEventListener('scrollend', _this.refireIntersectionObservers, {
199
+ passive: true,
200
+ once: true
201
+ });
202
+ var fastScrollThresholdMs = 500;
203
+ setTimeout(function () {
204
+ _this.refireIntersectionObservers();
205
+ }, fastScrollThresholdMs);
177
206
  }
178
207
  _this.dom.style.top = "".concat(domTop, "px");
179
208
  (0, _dom.updateStickyMargins)(table);
@@ -270,8 +299,12 @@ var TableRowNodeView = /*#__PURE__*/function () {
270
299
  this.eventDispatcher.on('widthPlugin', this.updateStickyHeaderWidth);
271
300
  this.eventDispatcher.on(_pluginKey.pluginKey.key, this.onTablePluginState);
272
301
  this.listening = true;
273
- this.dom.addEventListener('wheel', this.headerRowMouseScroll.bind(this));
274
- this.dom.addEventListener('touchmove', this.headerRowMouseScroll.bind(this));
302
+ this.dom.addEventListener('wheel', this.headerRowMouseScroll.bind(this), {
303
+ passive: true
304
+ });
305
+ this.dom.addEventListener('touchmove', this.headerRowMouseScroll.bind(this), {
306
+ passive: true
307
+ });
275
308
  }
276
309
  }, {
277
310
  key: "unsubscribe",
@@ -282,7 +315,7 @@ var TableRowNodeView = /*#__PURE__*/function () {
282
315
  if (this.intersectionObserver) {
283
316
  this.intersectionObserver.disconnect();
284
317
  // ED-16211 Once intersection observer is disconnected, we need to remove the isObserved from the sentinels
285
- // Otherwise when new intersection observer is created it will not observe because it thinks its already being observed
318
+ // Otherwise when newer intersection observer is created it will not observe because it thinks its already being observed
286
319
  [this.sentinels.top, this.sentinels.bottom].forEach(function (el) {
287
320
  if (el) {
288
321
  delete el.dataset.isObserved;
@@ -137,10 +137,24 @@ export class TableRowNodeView {
137
137
  // otherwise make it non-sticky
138
138
  return false;
139
139
  });
140
+ /**
141
+ * Manually refire the intersection observers.
142
+ * Useful when the header may have detached from the table.
143
+ */
144
+ _defineProperty(this, "refireIntersectionObservers", () => {
145
+ if (this.isSticky) {
146
+ [this.sentinels.top, this.sentinels.bottom].forEach(el => {
147
+ if (el && this.intersectionObserver) {
148
+ this.intersectionObserver.unobserve(el);
149
+ this.intersectionObserver.observe(el);
150
+ }
151
+ });
152
+ }
153
+ });
140
154
  _defineProperty(this, "makeHeaderRowSticky", (tree, scrollTop) => {
141
155
  var _tbody$firstChild;
142
156
  // If header row height is more than 50% of viewport height don't do this
143
- if (this.stickyRowHeight && this.stickyRowHeight > window.innerHeight / 2) {
157
+ if (this.isSticky || this.stickyRowHeight && this.stickyRowHeight > window.innerHeight / 2) {
144
158
  return;
145
159
  }
146
160
  const {
@@ -160,10 +174,25 @@ export class TableRowNodeView {
160
174
  }
161
175
  const domTop = currentTableTop > 0 ? scrollTop : scrollTop + currentTableTop;
162
176
  if (!this.isSticky) {
177
+ var _this$editorScrollabl;
163
178
  syncStickyRowToTable(table);
164
179
  this.dom.classList.add('sticky');
165
180
  table.classList.add(ClassName.TABLE_STICKY);
166
181
  this.isSticky = true;
182
+
183
+ /**
184
+ * The logic below is not desirable, but acts as a fail safe for scenarios where the sticky header
185
+ * detaches from the table. This typically happens during a fast scroll by the user which causes
186
+ * the intersection observer logic to not fire as expected.
187
+ */
188
+ (_this$editorScrollabl = this.editorScrollableElement) === null || _this$editorScrollabl === void 0 ? void 0 : _this$editorScrollabl.addEventListener('scrollend', this.refireIntersectionObservers, {
189
+ passive: true,
190
+ once: true
191
+ });
192
+ const fastScrollThresholdMs = 500;
193
+ setTimeout(() => {
194
+ this.refireIntersectionObservers();
195
+ }, fastScrollThresholdMs);
167
196
  }
168
197
  this.dom.style.top = `${domTop}px`;
169
198
  updateTableMargin(table);
@@ -245,8 +274,12 @@ export class TableRowNodeView {
245
274
  this.eventDispatcher.on('widthPlugin', this.updateStickyHeaderWidth);
246
275
  this.eventDispatcher.on(tablePluginKey.key, this.onTablePluginState);
247
276
  this.listening = true;
248
- this.dom.addEventListener('wheel', this.headerRowMouseScroll.bind(this));
249
- this.dom.addEventListener('touchmove', this.headerRowMouseScroll.bind(this));
277
+ this.dom.addEventListener('wheel', this.headerRowMouseScroll.bind(this), {
278
+ passive: true
279
+ });
280
+ this.dom.addEventListener('touchmove', this.headerRowMouseScroll.bind(this), {
281
+ passive: true
282
+ });
250
283
  }
251
284
  unsubscribe() {
252
285
  if (!this.listening) {
@@ -255,7 +288,7 @@ export class TableRowNodeView {
255
288
  if (this.intersectionObserver) {
256
289
  this.intersectionObserver.disconnect();
257
290
  // ED-16211 Once intersection observer is disconnected, we need to remove the isObserved from the sentinels
258
- // Otherwise when new intersection observer is created it will not observe because it thinks its already being observed
291
+ // Otherwise when newer intersection observer is created it will not observe because it thinks its already being observed
259
292
  [this.sentinels.top, this.sentinels.bottom].forEach(el => {
260
293
  if (el) {
261
294
  delete el.dataset.isObserved;
@@ -316,10 +349,10 @@ export class TableRowNodeView {
316
349
  table
317
350
  } = this.tree;
318
351
  entries.forEach(entry => {
319
- var _this$editorScrollabl;
352
+ var _this$editorScrollabl2;
320
353
  // On resize of the parent scroll element we need to adjust the width
321
354
  // of the sticky header
322
- if (entry.target.className === ((_this$editorScrollabl = this.editorScrollableElement) === null || _this$editorScrollabl === void 0 ? void 0 : _this$editorScrollabl.className)) {
355
+ if (entry.target.className === ((_this$editorScrollabl2 = this.editorScrollableElement) === null || _this$editorScrollabl2 === void 0 ? void 0 : _this$editorScrollabl2.className)) {
323
356
  this.updateStickyHeaderWidth();
324
357
  } else {
325
358
  const newHeight = entry.contentRect ? entry.contentRect.height : entry.target.offsetHeight;
@@ -142,10 +142,24 @@ export var TableRowNodeView = /*#__PURE__*/function () {
142
142
  // otherwise make it non-sticky
143
143
  return false;
144
144
  });
145
+ /**
146
+ * Manually refire the intersection observers.
147
+ * Useful when the header may have detached from the table.
148
+ */
149
+ _defineProperty(this, "refireIntersectionObservers", function () {
150
+ if (_this.isSticky) {
151
+ [_this.sentinels.top, _this.sentinels.bottom].forEach(function (el) {
152
+ if (el && _this.intersectionObserver) {
153
+ _this.intersectionObserver.unobserve(el);
154
+ _this.intersectionObserver.observe(el);
155
+ }
156
+ });
157
+ }
158
+ });
145
159
  _defineProperty(this, "makeHeaderRowSticky", function (tree, scrollTop) {
146
160
  var _tbody$firstChild;
147
161
  // If header row height is more than 50% of viewport height don't do this
148
- if (_this.stickyRowHeight && _this.stickyRowHeight > window.innerHeight / 2) {
162
+ if (_this.isSticky || _this.stickyRowHeight && _this.stickyRowHeight > window.innerHeight / 2) {
149
163
  return;
150
164
  }
151
165
  var table = tree.table,
@@ -163,10 +177,25 @@ export var TableRowNodeView = /*#__PURE__*/function () {
163
177
  }
164
178
  var domTop = currentTableTop > 0 ? scrollTop : scrollTop + currentTableTop;
165
179
  if (!_this.isSticky) {
180
+ var _this$editorScrollabl;
166
181
  syncStickyRowToTable(table);
167
182
  _this.dom.classList.add('sticky');
168
183
  table.classList.add(ClassName.TABLE_STICKY);
169
184
  _this.isSticky = true;
185
+
186
+ /**
187
+ * The logic below is not desirable, but acts as a fail safe for scenarios where the sticky header
188
+ * detaches from the table. This typically happens during a fast scroll by the user which causes
189
+ * the intersection observer logic to not fire as expected.
190
+ */
191
+ (_this$editorScrollabl = _this.editorScrollableElement) === null || _this$editorScrollabl === void 0 ? void 0 : _this$editorScrollabl.addEventListener('scrollend', _this.refireIntersectionObservers, {
192
+ passive: true,
193
+ once: true
194
+ });
195
+ var fastScrollThresholdMs = 500;
196
+ setTimeout(function () {
197
+ _this.refireIntersectionObservers();
198
+ }, fastScrollThresholdMs);
170
199
  }
171
200
  _this.dom.style.top = "".concat(domTop, "px");
172
201
  updateTableMargin(table);
@@ -263,8 +292,12 @@ export var TableRowNodeView = /*#__PURE__*/function () {
263
292
  this.eventDispatcher.on('widthPlugin', this.updateStickyHeaderWidth);
264
293
  this.eventDispatcher.on(tablePluginKey.key, this.onTablePluginState);
265
294
  this.listening = true;
266
- this.dom.addEventListener('wheel', this.headerRowMouseScroll.bind(this));
267
- this.dom.addEventListener('touchmove', this.headerRowMouseScroll.bind(this));
295
+ this.dom.addEventListener('wheel', this.headerRowMouseScroll.bind(this), {
296
+ passive: true
297
+ });
298
+ this.dom.addEventListener('touchmove', this.headerRowMouseScroll.bind(this), {
299
+ passive: true
300
+ });
268
301
  }
269
302
  }, {
270
303
  key: "unsubscribe",
@@ -275,7 +308,7 @@ export var TableRowNodeView = /*#__PURE__*/function () {
275
308
  if (this.intersectionObserver) {
276
309
  this.intersectionObserver.disconnect();
277
310
  // ED-16211 Once intersection observer is disconnected, we need to remove the isObserved from the sentinels
278
- // Otherwise when new intersection observer is created it will not observe because it thinks its already being observed
311
+ // Otherwise when newer intersection observer is created it will not observe because it thinks its already being observed
279
312
  [this.sentinels.top, this.sentinels.bottom].forEach(function (el) {
280
313
  if (el) {
281
314
  delete el.dataset.isObserved;
@@ -55,6 +55,11 @@ export declare class TableRowNodeView implements NodeView {
55
55
  onTablePluginState: (state: TablePluginState) => void;
56
56
  updateStickyHeaderWidth: () => void;
57
57
  shouldHeaderStick: (tree: TableDOMElements) => boolean;
58
+ /**
59
+ * Manually refire the intersection observers.
60
+ * Useful when the header may have detached from the table.
61
+ */
62
+ refireIntersectionObservers: () => void;
58
63
  makeHeaderRowSticky: (tree: TableDOMElements, scrollTop?: number) => void;
59
64
  makeRowHeaderNotSticky: (table: HTMLElement, isEditorDestroyed?: boolean) => void;
60
65
  getWrapperoffset: (inverse?: boolean) => number;
@@ -55,6 +55,11 @@ export declare class TableRowNodeView implements NodeView {
55
55
  onTablePluginState: (state: TablePluginState) => void;
56
56
  updateStickyHeaderWidth: () => void;
57
57
  shouldHeaderStick: (tree: TableDOMElements) => boolean;
58
+ /**
59
+ * Manually refire the intersection observers.
60
+ * Useful when the header may have detached from the table.
61
+ */
62
+ refireIntersectionObservers: () => void;
58
63
  makeHeaderRowSticky: (tree: TableDOMElements, scrollTop?: number) => void;
59
64
  makeRowHeaderNotSticky: (table: HTMLElement, isEditorDestroyed?: boolean) => void;
60
65
  getWrapperoffset: (inverse?: boolean) => number;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@atlaskit/editor-plugin-table",
3
- "version": "3.2.0",
3
+ "version": "3.2.1",
4
4
  "description": "Table plugin for the @atlaskit/editor",
5
5
  "publishConfig": {
6
6
  "registry": "https://registry.npmjs.org/"
@@ -150,10 +150,13 @@ export class TableRowNodeView implements NodeView {
150
150
 
151
151
  this.listening = true;
152
152
 
153
- this.dom.addEventListener('wheel', this.headerRowMouseScroll.bind(this));
153
+ this.dom.addEventListener('wheel', this.headerRowMouseScroll.bind(this), {
154
+ passive: true,
155
+ });
154
156
  this.dom.addEventListener(
155
157
  'touchmove',
156
158
  this.headerRowMouseScroll.bind(this),
159
+ { passive: true },
157
160
  );
158
161
  }
159
162
 
@@ -164,7 +167,7 @@ export class TableRowNodeView implements NodeView {
164
167
  if (this.intersectionObserver) {
165
168
  this.intersectionObserver.disconnect();
166
169
  // ED-16211 Once intersection observer is disconnected, we need to remove the isObserved from the sentinels
167
- // Otherwise when new intersection observer is created it will not observe because it thinks its already being observed
170
+ // Otherwise when newer intersection observer is created it will not observe because it thinks its already being observed
168
171
  [this.sentinels.top, this.sentinels.bottom].forEach((el) => {
169
172
  if (el) {
170
173
  delete el.dataset.isObserved;
@@ -522,9 +525,27 @@ export class TableRowNodeView implements NodeView {
522
525
  return false;
523
526
  };
524
527
 
528
+ /**
529
+ * Manually refire the intersection observers.
530
+ * Useful when the header may have detached from the table.
531
+ */
532
+ refireIntersectionObservers = () => {
533
+ if (this.isSticky) {
534
+ [this.sentinels.top, this.sentinels.bottom].forEach((el) => {
535
+ if (el && this.intersectionObserver) {
536
+ this.intersectionObserver.unobserve(el);
537
+ this.intersectionObserver.observe(el);
538
+ }
539
+ });
540
+ }
541
+ };
542
+
525
543
  makeHeaderRowSticky = (tree: TableDOMElements, scrollTop?: number) => {
526
544
  // If header row height is more than 50% of viewport height don't do this
527
- if (this.stickyRowHeight && this.stickyRowHeight > window.innerHeight / 2) {
545
+ if (
546
+ this.isSticky ||
547
+ (this.stickyRowHeight && this.stickyRowHeight > window.innerHeight / 2)
548
+ ) {
528
549
  return;
529
550
  }
530
551
 
@@ -552,6 +573,22 @@ export class TableRowNodeView implements NodeView {
552
573
  table.classList.add(ClassName.TABLE_STICKY);
553
574
 
554
575
  this.isSticky = true;
576
+
577
+ /**
578
+ * The logic below is not desirable, but acts as a fail safe for scenarios where the sticky header
579
+ * detaches from the table. This typically happens during a fast scroll by the user which causes
580
+ * the intersection observer logic to not fire as expected.
581
+ */
582
+ this.editorScrollableElement?.addEventListener(
583
+ 'scrollend',
584
+ this.refireIntersectionObservers,
585
+ { passive: true, once: true },
586
+ );
587
+
588
+ const fastScrollThresholdMs = 500;
589
+ setTimeout(() => {
590
+ this.refireIntersectionObservers();
591
+ }, fastScrollThresholdMs);
555
592
  }
556
593
 
557
594
  this.dom.style.top = `${domTop}px`;