organism-react-scroll-nav
Version:
A React scroll spy library with flux
172 lines (164 loc) • 4.28 kB
JavaScript
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"
}
};