diff --git a/packages/ui-default/components/sticky/sticky.page.js b/packages/ui-default/components/sticky/sticky.page.js index ba41385c2..3ea559873 100644 --- a/packages/ui-default/components/sticky/sticky.page.js +++ b/packages/ui-default/components/sticky/sticky.page.js @@ -1,5 +1,3 @@ -import 'sticky-kit/dist/sticky-kit'; - import $ from 'jquery'; import _ from 'lodash'; import responsiveCutoff from 'vj/breakpoints.json'; @@ -10,38 +8,24 @@ const navHeight = isBelow(responsiveCutoff.mobile) ? 0 : $('.nav').height(); -function updateStickies($stickies) { - $stickies.get().forEach((element) => { - const $sticky = $(element); - const shouldEnableSticky = (isAbove($sticky.data('sticky-cutoff-min'))); - const stickyEnabled = $sticky.data('sticky-enabled'); - if (shouldEnableSticky && !stickyEnabled) { - const stickyOptions = {}; - const $stickyParent = $sticky.closest('[data-sticky-parent]'); - if ($stickyParent.length > 0) { - stickyOptions.parent = $stickyParent; - } - stickyOptions.offset_top = 10 + navHeight; - $sticky.stick_in_parent(stickyOptions); - $sticky.data('sticky-enabled', true); - } else if (!shouldEnableSticky && stickyEnabled) { - $sticky.trigger('sticky_kit:detach'); - $sticky.data('sticky-enabled', false); - } - }); -} - function getCutoff(str) { - if (str === 'medium') { - return responsiveCutoff.mobile; - } if (str === 'large') { - return responsiveCutoff.desktop; - } + if (str === 'medium') return responsiveCutoff.mobile; + if (str === 'large') return responsiveCutoff.desktop; return 0; } -function stickyRelayout() { - $('body').trigger('sticky_kit:recalc'); +function updateStickies($stickies) { + $stickies.get().forEach((element) => { + const $sticky = $(element); + const shouldEnableSticky = isAbove($sticky.data('sticky-cutoff-min')); + if (shouldEnableSticky) { + element.style.position = 'sticky'; + element.style.top = `${10 + navHeight}px`; + } else { + element.style.position = ''; + element.style.top = ''; + } + }); } const stickyPage = new AutoloadPage('stickyPage', () => { @@ -54,13 +38,11 @@ const stickyPage = new AutoloadPage('stickyPage', () => { shouldListenResize = true; } $sticky.data('sticky-cutoff-min', getCutoff(minEnabledSize)); - $sticky.data('sticky-enabled', false); }); updateStickies($stickies); if (shouldListenResize) { $(window).on('resize', _.throttle(() => updateStickies($stickies), 300)); } - $(document).on('vjLayout', _.throttle(stickyRelayout, 100)); }); export default stickyPage; diff --git a/packages/ui-default/components/sticky/sticky.page.styl b/packages/ui-default/components/sticky/sticky.page.styl new file mode 100644 index 000000000..8814ec861 --- /dev/null +++ b/packages/ui-default/components/sticky/sticky.page.styl @@ -0,0 +1,11 @@ +[data-sticky-parent] + display: flex + flex-wrap: wrap + + &::before, + &::after + display: none + + > .columns, + > .column + float: none diff --git a/packages/ui-default/components/table/StyledTable.js b/packages/ui-default/components/table/StyledTable.js index 6b06781d1..6e9baeaff 100644 --- a/packages/ui-default/components/table/StyledTable.js +++ b/packages/ui-default/components/table/StyledTable.js @@ -1,7 +1,4 @@ -import 'sticky-kit/dist/sticky-kit'; - import $ from 'jquery'; -import _ from 'lodash'; import responsiveCutoff from 'vj/breakpoints.json'; import DOMAttachedObject from 'vj/components/DOMAttachedObject'; import { isBelow } from 'vj/utils/mediaQuery'; @@ -23,29 +20,53 @@ export default class StyledTable extends DOMAttachedObject { super($dom); - this.$container = $('
').addClass('section__table-container'); - this.$container.insertBefore(this.$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`, + }); - this.$container - .append(this.$header) - .append(this.$dom); + // 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); - const stickyOptions = { - parent: this.$container, - offset_top: navHeight, - }; - _.defer(() => this.$header.stick_in_parent(stickyOptions)); + // 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(); - this.$header.trigger('sticky_kit:detach'); } } diff --git a/packages/ui-default/components/table/table.page.styl b/packages/ui-default/components/table/table.page.styl index fe6d1f007..590db36f6 100644 --- a/packages/ui-default/components/table/table.page.styl +++ b/packages/ui-default/components/table/table.page.styl @@ -46,22 +46,21 @@ font-size: rem($font-size-small) .section__table-container - overflow: hidden overflow-x: auto .section__table-header background: $table-header-bg-color box-shadow: $table-header-shadow - position: relative z-index: 100 + overflow: hidden transition: box-shadow .2s linear - thead > tr - border-bottom: 0 - &.is_stuck box-shadow: $table-header-shadow-floating + thead > tr + border-bottom: 0 + .section__table-container, .section__body & > .data-table diff --git a/packages/ui-default/package.json b/packages/ui-default/package.json index 33df5e87b..954d87213 100644 --- a/packages/ui-default/package.json +++ b/packages/ui-default/package.json @@ -105,7 +105,6 @@ "sass-loader": "^16.0.7", "schemastery": "^3.18.0", "shorty.js": "^1.0.1", - "sticky-kit": "^1.1.3", "style-loader": "^4.0.0", "stylus": "^0.64.0", "stylus-loader": "7.1.2",