yantd
Version:
React component library
188 lines (187 loc) • 7.69 kB
JavaScript
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;
}