@adaptabletools/adaptable
Version:
Powerful data-agnostic HTML5 AG Grid extension which provides advanced, cutting-edge functionality to meet all DataGrid requirements
77 lines (76 loc) • 2.67 kB
JavaScript
import { useCallback, useRef } from 'react';
class SectionSelector {
constructor(node) {
this.scrollTop = 0;
this.childrenHeights = [];
this.select = (scrollTop) => {
this.refreshFromDOM();
const relativeCurrentHeight = (scrollTop * this.boxHeight) / this.maxScrollTop;
let heightSum = 0;
for (let i = 0, len = this.childrenHeights.length; i < len; i++) {
heightSum += this.childrenHeights[i];
if (heightSum > relativeCurrentHeight) {
return i;
}
}
return this.childrenHeights.length - 1;
};
this.node = node;
this.refreshFromDOM();
}
refreshFromDOM() {
this.boxHeight = this.node.scrollHeight;
this.childrenHeights = Array.prototype.map.call(this.node.children, (child) => child.offsetHeight);
this.maxScrollTop = this.boxHeight - this.node.offsetHeight;
}
getVisibleRange(scrollTop = this.scrollTop) {
const top = scrollTop;
const height = this.node.offsetHeight;
const bottom = scrollTop + this.node.offsetHeight;
return {
top,
bottom,
height,
};
}
}
export const useContainerScrollObserver = (callback) => {
const containerNodeRef = useRef(null);
const sectionSelectorRef = useRef(null);
const update = useCallback((scrollTop) => {
callback(sectionSelectorRef.current.select(scrollTop));
}, []);
const scrollRafRef = useRef(null);
const onScroll = useCallback(() => {
if (scrollRafRef.current) {
cancelAnimationFrame(scrollRafRef.current);
scrollRafRef.current = null;
}
requestAnimationFrame(() => {
scrollRafRef.current = null;
update(containerNodeRef.current.scrollTop);
});
}, []);
const setupScroll = useCallback((node) => {
if (node) {
containerNodeRef.current = node;
node.addEventListener('scroll', onScroll, { passive: true });
sectionSelectorRef.current = new SectionSelector(node);
}
else {
containerNodeRef.current?.removeEventListener('scroll', onScroll);
sectionSelectorRef.current = null;
}
}, []);
const ref = setupScroll;
return {
ref,
scrollToIndex: useCallback((index) => {
const container = containerNodeRef.current;
const node = container.childNodes[index];
node.scrollIntoView({
behavior: 'smooth',
});
}, []),
};
};