@atlaskit/editor-plugin-table
Version:
Table plugin for the @atlaskit/editor
142 lines (139 loc) • 6.93 kB
JavaScript
import _defineProperty from "@babel/runtime/helpers/defineProperty";
import { findOverflowScrollParent } from '@atlaskit/editor-common/ui';
import { editorExperiment } from '@atlaskit/tmp-editor-statsig/experiments';
import { TableCssClassName as ClassName } from '../types';
export class TableStickyScrollbar {
constructor(wrapper, view) {
_defineProperty(this, "sentinels", {});
_defineProperty(this, "handleScroll", event => {
if (!this.stickyScrollbarContainerElement || !this.wrapper || event.target !== this.stickyScrollbarContainerElement) {
return;
}
this.wrapper.scrollLeft = this.stickyScrollbarContainerElement.scrollLeft;
});
this.wrapper = wrapper;
this.view = view;
if (editorExperiment('platform_editor_exp_lazy_node_views', true)) {
requestAnimationFrame(() => {
this.init();
});
} else {
this.init();
}
}
dispose() {
if (this.stickyScrollbarContainerElement) {
// Ignored via go/ees005
// eslint-disable-next-line @repo/internal/dom-events/no-unsafe-event-listeners
this.stickyScrollbarContainerElement.removeEventListener('scroll', this.handleScroll);
}
this.deleteIntersectionObserver();
}
scrollLeft(left) {
if (this.stickyScrollbarContainerElement) {
this.stickyScrollbarContainerElement.scrollLeft = left;
}
}
init() {
var _this$wrapper$parentE;
if (!this.wrapper) {
return;
}
this.stickyScrollbarContainerElement = (_this$wrapper$parentE = this.wrapper.parentElement) === null || _this$wrapper$parentE === void 0 ? void 0 : _this$wrapper$parentE.querySelector(`.${ClassName.TABLE_STICKY_SCROLLBAR_CONTAINER}`);
if (this.stickyScrollbarContainerElement) {
// Ignored via go/ees005
// eslint-disable-next-line @repo/internal/dom-events/no-unsafe-event-listeners
this.stickyScrollbarContainerElement.addEventListener('scroll', this.handleScroll, {
passive: true
});
}
this.createIntersectionObserver();
}
createIntersectionObserver() {
var _this$wrapper, _this$wrapper$parentE2, _this$wrapper2, _this$wrapper2$parent, _this$wrapper2$parent2;
this.editorScrollableElement =
// Ignored via go/ees005
// eslint-disable-next-line @atlaskit/editor/no-as-casting
findOverflowScrollParent(this.view.dom) || window.document;
if (!this.editorScrollableElement || !this.wrapper) {
return;
}
this.intersectionObserver = new IntersectionObserver((entries, _) => {
if (!this.stickyScrollbarContainerElement) {
return;
}
entries.forEach(entry => {
var _entry$rootBounds;
// Ignored via go/ees005
// eslint-disable-next-line @atlaskit/editor/no-as-casting
const target = entry.target;
// if the rootBounds has 0 height, e.g. confluence preview mode, we do nothing.
if (((_entry$rootBounds = entry.rootBounds) === null || _entry$rootBounds === void 0 ? void 0 : _entry$rootBounds.height) === 0) {
return;
}
if (target.classList.contains(ClassName.TABLE_STICKY_SCROLLBAR_SENTINEL_BOTTOM)) {
this.sentinelBottomCallback(entry);
}
if (target.classList.contains(ClassName.TABLE_STICKY_SCROLLBAR_SENTINEL_TOP)) {
this.sentinelTopCallback(entry);
}
});
}, {
root: this.editorScrollableElement
});
// 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.
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);
// eslint-disable-next-line @atlaskit/editor/no-as-casting
this.sentinels.bottom = bottomSentinels === null || bottomSentinels === void 0 ? void 0 : bottomSentinels.item(bottomSentinels.length - 1);
// Ignored via go/ees005
// eslint-disable-next-line @atlaskit/editor/no-as-casting
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);
[this.sentinels.bottom, this.sentinels.top].forEach(el => {
if (el !== null && this.intersectionObserver) {
this.intersectionObserver.observe(el);
}
});
}
deleteIntersectionObserver() {
if (this.intersectionObserver) {
if (this.sentinels.bottom) {
this.intersectionObserver.unobserve(this.sentinels.bottom);
}
this.intersectionObserver.disconnect();
}
}
sentinelBottomCallback(entry) {
var _entry$rootBounds2, _entry$rootBounds3;
const sentinelIsAboveScrollArea = entry.boundingClientRect.top < (((_entry$rootBounds2 = entry.rootBounds) === null || _entry$rootBounds2 === void 0 ? void 0 : _entry$rootBounds2.top) || 0) ||
// When editorScrollableElement is the root document or inside modal,
// so the boundingClientRect.top will never be less than the rootBounds.top,
// so we need to check if the boundingClientRect.top is less than 20% of the rootBounds.height
// to determine if the bottom sentinel is above the scroll area
entry.boundingClientRect.top < (((_entry$rootBounds3 = entry.rootBounds) === null || _entry$rootBounds3 === void 0 ? void 0 : _entry$rootBounds3.height) || 0) * 0.2;
this.bottomSentinelState = sentinelIsAboveScrollArea ? 'above' : entry.isIntersecting ? 'visible' : 'below';
this.toggle();
}
sentinelTopCallback(entry) {
var _entry$rootBounds4;
const sentinelIsBelowScrollArea = (((_entry$rootBounds4 = entry.rootBounds) === null || _entry$rootBounds4 === void 0 ? void 0 : _entry$rootBounds4.bottom) || 0) < entry.boundingClientRect.top;
this.topSentinelState = sentinelIsBelowScrollArea ? 'below' : entry.isIntersecting ? 'visible' : 'above';
this.toggle();
}
toggle() {
if ((this.topSentinelState === 'visible' || this.topSentinelState === 'above') && this.bottomSentinelState === 'below') {
this.show();
} else {
this.hide();
}
}
hide() {
if (this.stickyScrollbarContainerElement && this.stickyScrollbarContainerElement.style.display !== 'none') {
this.stickyScrollbarContainerElement.style.display = 'none';
}
}
show() {
if (this.stickyScrollbarContainerElement && this.stickyScrollbarContainerElement.style.display !== 'block') {
this.stickyScrollbarContainerElement.style.display = 'block';
}
}
}