@hitachivantara/uikit-react-core
Version:
Core React components for the NEXT Design System.
132 lines (131 loc) • 4.93 kB
JavaScript
;
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
const React = require("react");
const scroll = require("../utils/scroll.cjs");
const useScrollTo = (selectedIndexProp = 0, scrollElementId = void 0, navigationMode = "push", relativeLinks = false, offset = 0, options = [], onChange = void 0, direction = "column") => {
const RETRY_MAX = 5;
const [selectedIndex, setSelectedIndex] = React.useState(selectedIndexProp);
const scrollEle = React.useRef(
typeof window !== "undefined" ? window : null
);
const requestedAnimationFrame = React.useRef(0);
const lastContainerScrollTop = React.useRef(0);
const selectedIndexRef = React.useRef(selectedIndex);
React.useEffect(() => {
selectedIndexRef.current = selectedIndex;
}, [selectedIndex]);
React.useEffect(() => {
if (typeof window !== "undefined") {
scrollEle.current = scrollElementId && document.getElementById(scrollElementId) || window;
lastContainerScrollTop.current = scroll.verticalScrollOffset(scrollEle.current);
}
}, [scrollElementId]);
const checkScroll = React.useCallback(
(event) => {
if (requestedAnimationFrame.current === 0 && window?.requestAnimationFrame) {
requestedAnimationFrame.current = window.requestAnimationFrame(() => {
requestedAnimationFrame.current = 0;
const firstVisibleElementIndex = scroll.findFirstVisibleElement(
scrollEle.current,
options,
offset
);
let newSelectedIndex = firstVisibleElementIndex;
if (firstVisibleElementIndex < 0) {
newSelectedIndex = 0;
}
if (newSelectedIndex < options.length - 1 && scroll.isScrolledToTheBottom(scrollEle.current)) {
newSelectedIndex += 1;
}
const containerScrollTop = scroll.getScrollTop(scrollEle.current);
const isScrollingDown = containerScrollTop > lastContainerScrollTop.current;
lastContainerScrollTop.current = containerScrollTop;
if (isScrollingDown) {
if (newSelectedIndex < selectedIndexRef.current) {
newSelectedIndex = selectedIndexRef.current;
}
} else if (newSelectedIndex > selectedIndexRef.current) {
newSelectedIndex = selectedIndexRef.current;
}
setSelectedIndex(newSelectedIndex);
onChange?.(event, newSelectedIndex);
});
}
},
[offset, options, onChange]
);
React.useEffect(() => {
if (scrollEle.current) {
scrollEle.current.addEventListener("scroll", checkScroll, false);
}
return () => {
if (scrollEle.current) {
scrollEle.current.removeEventListener("scroll", checkScroll);
}
if (requestedAnimationFrame.current !== 0) {
window.cancelAnimationFrame(requestedAnimationFrame.current);
requestedAnimationFrame.current = 0;
}
};
}, [checkScroll]);
React.useEffect(() => {
let checkRenderedInterval;
if (navigationMode !== "none") {
const hashValue = document.location.hash.split("#")[1] || "";
const option = options.find((o) => o.value === hashValue);
if (option) {
let retry = 0;
checkRenderedInterval = setInterval(() => {
const ele = document.getElementById(option.value);
if (ele) {
scroll.scrollElement(ele, scrollEle.current, option.offset || offset);
clearInterval(checkRenderedInterval);
} else {
retry += 1;
if (retry === RETRY_MAX) {
clearInterval(checkRenderedInterval);
}
}
}, 1e3);
}
}
return () => {
clearInterval(checkRenderedInterval);
};
}, []);
const baseUrl = relativeLinks || typeof window === "undefined" || window == null ? "" : window.location.href.split("#")[0];
const elements = React.useMemo(
() => options.map((o) => ({
...o,
href: `${baseUrl}#${o.value}`
})),
[options, baseUrl]
);
const setScrollTo = React.useCallback(
(event, id, index, wrappedOnChange) => {
const option = elements.find((o) => o.value === id);
if (option) {
const ele = document.getElementById(id);
if (ele) {
scroll.scrollElement(
ele,
scrollEle.current,
option.offset || offset,
direction
);
}
if (navigationMode === "push") {
window.history.pushState({}, "", option.href);
} else if (navigationMode === "replace") {
window.history.replaceState({}, "", option.href);
}
setSelectedIndex(index);
wrappedOnChange?.(index);
selectedIndexRef.current = index;
}
},
[elements, navigationMode, direction, offset]
);
return [selectedIndex, setScrollTo, elements];
};
exports.useScrollTo = useScrollTo;