import $ from 'jquery';
import responsiveCutoff from 'vj/breakpoints.json';
import DOMAttachedObject from 'vj/components/DOMAttachedObject';
import { isBelow } from 'vj/utils/mediaQuery';
const navHeight = isBelow(responsiveCutoff.mobile)
? 0
: $('.nav').height();
export default class StyledTable extends DOMAttachedObject {
static DOMAttachKey = 'vjStyledTableInstance';
static DOMAttachSelector = '.data-table';
constructor($dom) {
if ($dom.closest('.section__body').length === 0) {
super(null);
return;
}
super($dom);
// Sentinel to detect when header becomes stuck
this.$sentinel = $('
').css({ height: 0, margin: 0, padding: 0 });
// Header sits outside the scroll container so sticky works against viewport
this.$header = $('
');
this.$header.attr('class', `${this.$dom.attr('class')} section__table-header`);
this.$header.css({
position: 'sticky',
top: `${navHeight}px`,
});
// Scroll container only wraps the data table
this.$container = $('').addClass('section__table-container');
this.$sentinel.insertBefore(this.$dom);
this.$header.insertBefore(this.$dom);
this.$container.insertBefore(this.$dom);
this.$container.append(this.$dom);
this.$header.empty();
this.$dom.children('colgroup').clone().appendTo(this.$header);
this.$dom.children('thead').appendTo(this.$header);
// Sync horizontal scroll between header and body
this.$container.on('scroll', () => {
this.$header.css('transform', `translateX(-${this.$container.scrollLeft()}px)`);
});
// Detect sticky state via IntersectionObserver
const header = this.$header[0];
const sentinel = this.$sentinel[0];
if (window.IntersectionObserver) {
this._observer = new IntersectionObserver(
([entry]) => {
if (entry.isIntersecting) {
header.classList.remove('is_stuck');
} else {
header.classList.add('is_stuck');
}
},
{ threshold: [0], rootMargin: `-${navHeight}px 0px 0px 0px` },
);
this._observer.observe(sentinel);
}
}
detach() {
if (this._observer) this._observer.disconnect();
super.detach();
}
}