UNPKG

organism-react-scroll-nav

Version:
172 lines (164 loc) 4.28 kB
import _objectSpread from "reshow-runtime/es/helpers/objectSpread2"; import _objectWithoutProperties from "reshow-runtime/es/helpers/objectWithoutProperties"; var _excluded = ["targetId", "scrollRefLoc", "scrollRefId", "scrollMargin", "style", "preventDefault", "noDelay", "onClick"]; // @ts-check import * as React from "react"; var { useEffect, useState, useCallback, useRef } = React; import smoothScrollTo from "smooth-scroll-to"; import getOffset, { OffsetType } from "getoffset"; import callfunc from "call-func"; import { doc } from "win-doc"; import { getAnchorPath } from "anchor-lib"; import { ScrollReceiver } from "../../index.mjs"; import scrollStore from "../../stores/scrollStore.mjs"; import fastScrollStore from "../../stores/fastScrollStore.mjs"; import { jsx as _jsx } from "react/jsx-runtime"; var scollTimer = null; var resetTimer = function resetTimer() { if (scollTimer) { clearTimeout(scollTimer); scollTimer = null; } }; /** * @typedef {object} SmoothScrollLinkProps */ /** * @param {SmoothScrollLinkProps} props */ var useSmoothScrollLink = function useSmoothScrollLink(props) { var { targetId, scrollRefLoc = "bottom", scrollRefId = "", scrollMargin, style, preventDefault = true, noDelay = false, onClick } = props, restProps = _objectWithoutProperties(props, _excluded); /** * @type {[scrollRefElement, setScrollRefElement]} */ var [scrollRefElement, setScrollRefElement] = useState(); /** @type {any} */ var lastScroll = useRef(null); /** * @param {number=} duringTime */ var _scrollTo = function scrollTo(duringTime) { var getStore = function getStore() { return noDelay ? fastScrollStore : scrollStore; }; var offset = getStore().scroller.getOffset(targetId); if (offset) { var margin = getMargin(); var to = offset.top - margin; /** * Let user could cancel scroll with different direction. */ if (lastScroll.current === to) { return; } setTimeout(function () { return lastScroll.current = to; }); smoothScrollTo(to, duringTime, undefined, function () { resetTimer(); scollTimer = setTimeout(function () { return _scrollTo(duringTime); }, 800); }); } }; useEffect(function () { var dom = doc().getElementById(scrollRefId); if (dom) { setScrollRefElement(dom); } if (getAnchorPath().anchor.substring(1) === targetId) { setTimeout(function () { return _scrollTo(1); }); } return function () { resetTimer(); }; }, []); /** * When modify getMargin number, should also take care store isActive logic. * * https://github.com/react-atomic/organism-react-scroll-nav/blob/main/src/stores/scrollStore.js#L119 */ var getMargin = useCallback(function () { var margin = 0; if (scrollRefElement) { var refOffset = /**@type OffsetType*/getOffset(scrollRefElement); switch (scrollRefLoc) { case "bottom": margin += refOffset.bottom - refOffset.top; break; default: case "top": break; } } if (!isNaN(scrollMargin)) { margin += scrollMargin; } margin -= 2; return margin; }, [scrollRefLoc, scrollMargin, scrollRefElement]); var handler = { /** * @param {object} e */ click: function click(e) { lastScroll.current = null; if (preventDefault) { e.preventDefault(); } callfunc(onClick); _scrollTo(); } }; return { restProps, handler, targetId, margin: getMargin(), style }; }; /** * @param {SmoothScrollLinkProps} props */ var SmoothScrollLink = function SmoothScrollLink(props) { var { restProps, handler, margin, style, targetId } = useSmoothScrollLink(props); return /*#__PURE__*/_jsx(ScrollReceiver, _objectSpread(_objectSpread({ atom: "a" }, restProps), {}, { targetId: targetId, scrollMargin: margin, style: _objectSpread(_objectSpread({}, Styles.link), style), onClick: handler.click })); }; export default SmoothScrollLink; var Styles = { link: { cursor: "pointer" } };