UNPKG

yantd

Version:

React component library

188 lines (187 loc) 7.69 kB
var __assign = (this && this.__assign) || function () { __assign = Object.assign || function(t) { for (var s, i = 1, n = arguments.length; i < n; i++) { s = arguments[i]; for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) t[p] = s[p]; } return t; }; return __assign.apply(this, arguments); }; import React, { useState, useRef, useContext, useEffect } from "react"; import classNames from 'classnames'; import addEventListener from 'rc-util/lib/Dom/addEventListener'; import { ConfigContext } from '../config-provider'; import AnchorContext from "./context"; import scrollTo from '../_util/scrollTo'; import getScroll from '../_util/getScroll'; var links = []; var sharpMatcherRegx = /#(\S+)$/; var Main = function (props) { var _a; var customizePrefixCls = props.prefixCls, _b = props.className, className = _b === void 0 ? '' : _b, style = props.style, offsetTop = props.offsetTop, affix = props.affix, showInkInFixed = props.showInkInFixed, children = props.children, onChange = props.onChange, Link = props.Link; var _c = useState(null), activeLink = _c[0], setActiveLink = _c[1]; var _d = useState(false), animating = _d[0], setAnimating = _d[1]; var getContainer = function () { var getContainer = props.getContainer; var getFunc = getContainer || getTargetContainer || getDefaultContainer; return getFunc(); }; var handleScroll = function () { if (animating) { return; } var offsetTop = props.offsetTop, bounds = props.bounds, targetOffset = props.targetOffset; var currentActiveLink = getCurrentAnchor(targetOffset !== undefined ? targetOffset : offsetTop || 0, bounds); setCurrentActiveLink(currentActiveLink); }; var _e = useState(getContainer()), scrollContainer = _e[0], setScrollContainer = _e[1]; var _f = useState(addEventListener(scrollContainer, 'scroll', handleScroll)), scrollEvent = _f[0], setScrollEvent = _f[1]; var wrapperRef = useRef(); var _g = useContext(ConfigContext), getPrefixCls = _g.getPrefixCls, direction = _g.direction, getTargetContainer = _g.getTargetContainer; var prefixCls = getPrefixCls('yanchor', customizePrefixCls); var _h = useState(), inkNode = _h[0], setInkNode = _h[1]; var registerLink = function (link) { if (!links.includes(link)) { links.push(link); } }; var unregisterLink = function (link) { var index = links.indexOf(link); if (index !== -1) { links.splice(index, 1); } }; var saveInkNode = function (node) { setInkNode(node); }; var setCurrentActiveLink = function (link) { if (activeLink !== link) { setActiveLink(link); onChange === null || onChange === void 0 ? void 0 : onChange(link); } }; var handleScrollTo = function (link) { var offsetTop = props.offsetTop, targetOffset = props.targetOffset; setCurrentActiveLink(link); var container = getContainer(); 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; setAnimating(true); scrollTo(y, { callback: function () { setAnimating(false); }, getContainer: getContainer }); }; var getCurrentAnchor = function (offsetTop, bounds) { if (offsetTop === void 0) { offsetTop = 0; } if (bounds === void 0) { bounds = 5; } var getCurrentAnchor = props.getCurrentAnchor; if (typeof getCurrentAnchor === 'function') { return getCurrentAnchor(); } var linkSections = []; var container = getContainer(); links.forEach(function (link) { var sharpLinkMatch = sharpMatcherRegx.exec(link.toString()); if (!sharpLinkMatch) { return; } var target = document.getElementById(sharpLinkMatch[1]); if (target) { var top_1 = getOffsetTop(target, container); if (top_1 < offsetTop + bounds) { linkSections.push({ link: link, top: top_1, }); } } }); if (linkSections.length) { var maxSection = linkSections.reduce(function (prev, curr) { return (curr.top > prev.top ? curr : prev); }); return maxSection.link; } return ''; }; var inkClass = classNames(prefixCls + "-ink-ball", { visible: activeLink, }); var wrapperClass = classNames(prefixCls + "-wrapper", (_a = {}, _a[prefixCls + "-rtl"] = direction === 'rtl', _a), className); var wrapperStyle = __assign({ maxHeight: offsetTop ? "calc(100vh - " + offsetTop + "px)" : '100vh' }, style); var anchorClass = classNames(prefixCls, { fixed: !affix && !showInkInFixed, }); var anchorContent = (React.createElement("div", { className: wrapperClass, style: wrapperStyle }, React.createElement("div", { className: anchorClass }, React.createElement("div", { className: prefixCls + "-ink" }, React.createElement("span", { className: inkClass, ref: saveInkNode })), children))); var updateInk = function () { var anchorNode = wrapperRef.current; var linkNode = anchorNode === null || anchorNode === void 0 ? void 0 : anchorNode.getElementsByClassName(prefixCls + "-link-title-active")[0]; if (linkNode && inkNode) { inkNode.style.top = linkNode.offsetTop + linkNode.clientHeight / 2 - 4.5 + "px"; } }; wrapperRef.current = anchorContent; useEffect(function () { handleScroll(); return function () { console.log('组件关闭, 事件移除'); scrollEvent && scrollEvent.remove(); }; }, [scrollEvent]); useEffect(function () { if (scrollEvent) { var currentContainer = getContainer(); if (scrollContainer !== currentContainer) { setScrollContainer(currentContainer); scrollEvent.remove(); setScrollEvent(addEventListener(currentContainer, 'scroll', handleScroll)); handleScroll(); } } updateInk(); }, [scrollContainer]); return (React.createElement(AnchorContext.Provider, { value: { registerLink: registerLink, unregisterLink: unregisterLink, activeLink: activeLink, scrollTo: handleScrollTo, onClick: props.onClick } }, anchorContent)); }; export default Main; 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; }