UNPKG

antd

Version:

An enterprise-class UI design language and React components implementation

222 lines 8.9 kB
import _extends from "@babel/runtime/helpers/esm/extends"; import _defineProperty from "@babel/runtime/helpers/esm/defineProperty"; import _toConsumableArray from "@babel/runtime/helpers/esm/toConsumableArray"; import _slicedToArray from "@babel/runtime/helpers/esm/slicedToArray"; import classNames from 'classnames'; import addEventListener from "rc-util/es/Dom/addEventListener"; import * as React from 'react'; import Affix from '../affix'; import { ConfigContext } from '../config-provider'; import getScroll from '../_util/getScroll'; import scrollTo from '../_util/scrollTo'; import AnchorContext from './context'; function getDefaultContainer() { return window; } function getOffsetTop(element, container) { if (!element.getClientRects().length) { return 0; } var 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; } var sharpMatcherRegx = /#([\S ]+)$/; var AnchorContent = function AnchorContent(props) { var _a; var prefixCls = props.anchorPrefixCls, _props$className = props.className, className = _props$className === void 0 ? '' : _props$className, style = props.style, offsetTop = props.offsetTop, _props$affix = props.affix, affix = _props$affix === void 0 ? true : _props$affix, _props$showInkInFixed = props.showInkInFixed, showInkInFixed = _props$showInkInFixed === void 0 ? false : _props$showInkInFixed, children = props.children, bounds = props.bounds, targetOffset = props.targetOffset, onClick = props.onClick, onChange = props.onChange, getContainer = props.getContainer, getCurrentAnchor = props.getCurrentAnchor; var _React$useState = React.useState([]), _React$useState2 = _slicedToArray(_React$useState, 2), links = _React$useState2[0], setLinks = _React$useState2[1]; var _React$useState3 = React.useState(null), _React$useState4 = _slicedToArray(_React$useState3, 2), activeLink = _React$useState4[0], setActiveLink = _React$useState4[1]; var activeLinkRef = React.useRef(activeLink); var wrapperRef = React.useRef(null); var spanLinkNode = React.useRef(null); var animating = React.useRef(false); var _React$useContext = React.useContext(ConfigContext), direction = _React$useContext.direction, getTargetContainer = _React$useContext.getTargetContainer; var getCurrentContainer = (_a = getContainer !== null && getContainer !== void 0 ? getContainer : getTargetContainer) !== null && _a !== void 0 ? _a : getDefaultContainer; var dependencyListItem = JSON.stringify(links); var registerLink = React.useCallback(function (link) { if (!links.includes(link)) { setLinks(function (prev) { return [].concat(_toConsumableArray(prev), [link]); }); } }, [dependencyListItem]); var unregisterLink = React.useCallback(function (link) { if (links.includes(link)) { setLinks(function (prev) { return prev.filter(function (i) { return i !== link; }); }); } }, [dependencyListItem]); var updateInk = function updateInk() { var _a; var linkNode = (_a = wrapperRef.current) === null || _a === void 0 ? void 0 : _a.querySelector(".".concat(prefixCls, "-link-title-active")); if (linkNode && spanLinkNode.current) { spanLinkNode.current.style.top = "".concat(linkNode.offsetTop + linkNode.clientHeight / 2 - 4.5, "px"); } }; var getInternalCurrentAnchor = function getInternalCurrentAnchor(_links) { var _offsetTop = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 0; var _bounds = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 5; var linkSections = []; var container = getCurrentContainer(); _links.forEach(function (link) { var sharpLinkMatch = sharpMatcherRegx.exec(link === null || link === void 0 ? void 0 : link.toString()); if (!sharpLinkMatch) { return; } var target = document.getElementById(sharpLinkMatch[1]); if (target) { var top = getOffsetTop(target, container); if (top < _offsetTop + _bounds) { linkSections.push({ link: link, top: top }); } } }); if (linkSections.length) { var maxSection = linkSections.reduce(function (prev, curr) { return curr.top > prev.top ? curr : prev; }); return maxSection.link; } return ''; }; var setCurrentActiveLink = function setCurrentActiveLink(link) { if (activeLinkRef.current === link) { return; } // https://github.com/ant-design/ant-design/issues/30584 var 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 === null || onChange === void 0 ? void 0 : onChange(link); }; var handleScroll = React.useCallback(function () { if (animating.current) { return; } if (typeof getCurrentAnchor === 'function') { return; } var currentActiveLink = getInternalCurrentAnchor(links, targetOffset !== undefined ? targetOffset : offsetTop || 0, bounds); setCurrentActiveLink(currentActiveLink); }, [dependencyListItem, targetOffset, offsetTop]); var handleScrollTo = React.useCallback(function (link) { setCurrentActiveLink(link); var container = getCurrentContainer(); var scrollTop = getScroll(container, true); var sharpLinkMatch = sharpMatcherRegx.exec(link); if (!sharpLinkMatch) { return; } var targetElement = document.getElementById(sharpLinkMatch[1]); if (!targetElement) { return; } var eleOffsetTop = getOffsetTop(targetElement, container); var y = scrollTop + eleOffsetTop; y -= targetOffset !== undefined ? targetOffset : offsetTop || 0; animating.current = true; scrollTo(y, { getContainer: getCurrentContainer, callback: function callback() { animating.current = false; } }); }, [targetOffset, offsetTop]); var inkClass = classNames(_defineProperty({}, "".concat(prefixCls, "-ink-ball-visible"), activeLink), "".concat(prefixCls, "-ink-ball")); var wrapperClass = classNames("".concat(prefixCls, "-wrapper"), _defineProperty({}, "".concat(prefixCls, "-rtl"), direction === 'rtl'), className); var anchorClass = classNames(prefixCls, _defineProperty({}, "".concat(prefixCls, "-fixed"), !affix && !showInkInFixed)); var wrapperStyle = _extends({ maxHeight: offsetTop ? "calc(100vh - ".concat(offsetTop, "px)") : '100vh' }, style); var anchorContent = /*#__PURE__*/React.createElement("div", { ref: wrapperRef, className: wrapperClass, style: wrapperStyle }, /*#__PURE__*/React.createElement("div", { className: anchorClass }, /*#__PURE__*/React.createElement("div", { className: "".concat(prefixCls, "-ink") }, /*#__PURE__*/React.createElement("span", { className: inkClass, ref: spanLinkNode })), children)); React.useEffect(function () { var scrollContainer = getCurrentContainer(); var scrollEvent = addEventListener(scrollContainer, 'scroll', handleScroll); handleScroll(); return function () { scrollEvent === null || scrollEvent === void 0 ? void 0 : scrollEvent.remove(); }; }, [dependencyListItem]); React.useEffect(function () { if (typeof getCurrentAnchor === 'function') { setCurrentActiveLink(getCurrentAnchor(activeLinkRef.current || '')); } }, [getCurrentAnchor]); React.useEffect(function () { updateInk(); }, [getCurrentAnchor, dependencyListItem, activeLink]); var memoizedContextValue = React.useMemo(function () { return { registerLink: registerLink, unregisterLink: unregisterLink, scrollTo: handleScrollTo, activeLink: activeLink, onClick: onClick }; }, [activeLink, onClick, handleScrollTo]); return /*#__PURE__*/React.createElement(AnchorContext.Provider, { value: memoizedContextValue }, affix ? /*#__PURE__*/React.createElement(Affix, { offsetTop: offsetTop, target: getCurrentContainer }, anchorContent) : anchorContent); }; var Anchor = function Anchor(props) { var customizePrefixCls = props.prefixCls; var _React$useContext2 = React.useContext(ConfigContext), getPrefixCls = _React$useContext2.getPrefixCls; var anchorPrefixCls = getPrefixCls('anchor', customizePrefixCls); return /*#__PURE__*/React.createElement(AnchorContent, _extends({}, props, { anchorPrefixCls: anchorPrefixCls })); }; export default Anchor;