UNPKG

@hitachivantara/uikit-react-core

Version:

Core React components for the NEXT Design System.

132 lines (131 loc) 4.93 kB
"use strict"; 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;