UNPKG

linkmore-design

Version:

🌈 πŸš€lmη»„δ»ΆεΊ“γ€‚πŸš€

220 lines (217 loc) β€’ 7.62 kB
"use strict"; var _interopRequireWildcard = require("@babel/runtime/helpers/interopRequireWildcard").default; var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault").default; Object.defineProperty(exports, "__esModule", { value: true }); exports.default = void 0; var _extends2 = _interopRequireDefault(require("@babel/runtime/helpers/extends")); var _classnames = _interopRequireDefault(require("classnames")); var _addEventListener = _interopRequireDefault(require("rc-util/lib/Dom/addEventListener")); var React = _interopRequireWildcard(require("react")); var _affix = _interopRequireDefault(require("../affix")); var _configProvider = require("../config-provider"); var _getScroll = _interopRequireDefault(require("../_util/getScroll")); var _scrollTo = _interopRequireDefault(require("../_util/scrollTo")); var _context = _interopRequireDefault(require("./context")); function getDefaultContainer() { return window; } function getOffsetTop(element, container) { if (!element.getClientRects().length) { return 0; } const rect = element.getBoundingClientRect(); if (rect.width || rect.height) { if (container === window) { container = element.ownerDocument.documentElement; return rect.top - container.clientTop; } return rect.top - container.getBoundingClientRect().top; } return rect.top; } const sharpMatcherRegx = /#([\S ]+)$/; const AnchorContent = props => { const { anchorPrefixCls: prefixCls, className = '', style, offsetTop, affix = true, showInkInFixed = false, children, bounds, targetOffset, onClick, onChange, getContainer, getCurrentAnchor } = props; const [links, setLinks] = React.useState([]); const [activeLink, setActiveLink] = React.useState(null); const activeLinkRef = React.useRef(activeLink); const wrapperRef = React.useRef(null); const spanLinkNode = React.useRef(null); const animating = React.useRef(false); const { direction, getTargetContainer } = React.useContext(_configProvider.ConfigContext); const getCurrentContainer = getContainer ?? getTargetContainer ?? getDefaultContainer; const dependencyListItem = JSON.stringify(links); const registerLink = React.useCallback(link => { if (!links.includes(link)) { setLinks(prev => [...prev, link]); } }, [dependencyListItem]); const unregisterLink = React.useCallback(link => { if (links.includes(link)) { setLinks(prev => prev.filter(i => i !== link)); } }, [dependencyListItem]); const updateInk = () => { const linkNode = wrapperRef.current?.querySelector(`.${prefixCls}-link-title-active`); if (linkNode && spanLinkNode.current) { spanLinkNode.current.style.top = `${linkNode.offsetTop + linkNode.clientHeight / 2 - 4.5}px`; } }; const getInternalCurrentAnchor = (_links, _offsetTop = 0, _bounds = 5) => { const linkSections = []; const container = getCurrentContainer(); _links.forEach(link => { const sharpLinkMatch = sharpMatcherRegx.exec(link?.toString()); if (!sharpLinkMatch) { return; } const target = document.getElementById(sharpLinkMatch[1]); if (target) { const top = getOffsetTop(target, container); if (top < _offsetTop + _bounds) { linkSections.push({ link, top }); } } }); if (linkSections.length) { const maxSection = linkSections.reduce((prev, curr) => curr.top > prev.top ? curr : prev); return maxSection.link; } return ''; }; const setCurrentActiveLink = link => { if (activeLinkRef.current === link) { return; } // https://github.com/ant-design/ant-design/issues/30584 const newLink = typeof getCurrentAnchor === 'function' ? getCurrentAnchor(link) : link; setActiveLink(newLink); activeLinkRef.current = newLink; // onChange should respect the original link (which may caused by // window scroll or user click), not the new link onChange?.(link); }; const handleScroll = React.useCallback(() => { if (animating.current) { return; } if (typeof getCurrentAnchor === 'function') { return; } const currentActiveLink = getInternalCurrentAnchor(links, targetOffset !== undefined ? targetOffset : offsetTop || 0, bounds); setCurrentActiveLink(currentActiveLink); }, [dependencyListItem, targetOffset, offsetTop]); const handleScrollTo = React.useCallback(link => { setCurrentActiveLink(link); const container = getCurrentContainer(); const scrollTop = (0, _getScroll.default)(container, true); const sharpLinkMatch = sharpMatcherRegx.exec(link); if (!sharpLinkMatch) { return; } const targetElement = document.getElementById(sharpLinkMatch[1]); if (!targetElement) { return; } const eleOffsetTop = getOffsetTop(targetElement, container); let y = scrollTop + eleOffsetTop; y -= targetOffset !== undefined ? targetOffset : offsetTop || 0; animating.current = true; (0, _scrollTo.default)(y, { getContainer: getCurrentContainer, callback() { animating.current = false; } }); }, [targetOffset, offsetTop]); const inkClass = (0, _classnames.default)({ [`${prefixCls}-ink-ball-visible`]: activeLink }, `${prefixCls}-ink-ball`); const wrapperClass = (0, _classnames.default)(`${prefixCls}-wrapper`, { [`${prefixCls}-rtl`]: direction === 'rtl' }, className); const anchorClass = (0, _classnames.default)(prefixCls, { [`${prefixCls}-fixed`]: !affix && !showInkInFixed }); const wrapperStyle = { maxHeight: offsetTop ? `calc(100vh - ${offsetTop}px)` : '100vh', ...style }; const anchorContent = /*#__PURE__*/React.createElement("div", { ref: wrapperRef, className: wrapperClass, style: wrapperStyle }, /*#__PURE__*/React.createElement("div", { className: anchorClass }, /*#__PURE__*/React.createElement("div", { className: `${prefixCls}-ink` }, /*#__PURE__*/React.createElement("span", { className: inkClass, ref: spanLinkNode })), children)); React.useEffect(() => { const scrollContainer = getCurrentContainer(); const scrollEvent = (0, _addEventListener.default)(scrollContainer, 'scroll', handleScroll); handleScroll(); return () => { scrollEvent?.remove(); }; }, [dependencyListItem]); React.useEffect(() => { if (typeof getCurrentAnchor === 'function') { setCurrentActiveLink(getCurrentAnchor(activeLinkRef.current || '')); } }, [getCurrentAnchor]); React.useEffect(() => { updateInk(); }, [getCurrentAnchor, dependencyListItem, activeLink]); const memoizedContextValue = React.useMemo(() => ({ registerLink, unregisterLink, scrollTo: handleScrollTo, activeLink, onClick }), [activeLink, onClick, handleScrollTo]); return /*#__PURE__*/React.createElement(_context.default.Provider, { value: memoizedContextValue }, affix ? /*#__PURE__*/React.createElement(_affix.default, { offsetTop: offsetTop, target: getCurrentContainer }, anchorContent) : anchorContent); }; const Anchor = props => { const { prefixCls: customizePrefixCls } = props; const { getPrefixCls } = React.useContext(_configProvider.ConfigContext); const anchorPrefixCls = getPrefixCls('anchor', customizePrefixCls); return /*#__PURE__*/React.createElement(AnchorContent, (0, _extends2.default)({}, props, { anchorPrefixCls: anchorPrefixCls })); }; var _default = Anchor; exports.default = _default;