UNPKG

@fpxfd/next

Version:

A configurable component library for web built on React.

350 lines (313 loc) 13.7 kB
import _extends from 'babel-runtime/helpers/extends'; import _classCallCheck from 'babel-runtime/helpers/classCallCheck'; import _possibleConstructorReturn from 'babel-runtime/helpers/possibleConstructorReturn'; import _inherits from 'babel-runtime/helpers/inherits'; var _class, _temp2; import classNames from 'classnames'; import PropTypes from 'prop-types'; import React, { Component } from 'react'; import { polyfill } from 'react-lifecycles-compat'; import Affix from '../affix'; import ConfigProvider from '../config-provider'; import { events } from '../util'; import AnchorLink from './anchor-link'; import AnchorContext from './context'; import getScroll from './getScroll'; import scrollTo from './scrollTo'; 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 scrollTimeout = void 0; /** * Anchor */ var Anchor = (_temp2 = _class = function (_Component) { _inherits(Anchor, _Component); function Anchor() { var _temp, _this, _ret; _classCallCheck(this, Anchor); for (var _len = arguments.length, args = Array(_len), _key = 0; _key < _len; _key++) { args[_key] = arguments[_key]; } return _ret = (_temp = (_this = _possibleConstructorReturn(this, _Component.call.apply(_Component, [this].concat(args))), _this), _this.state = { activeLink: null, isOpen: _this.props.open }, _this.wrapperRef = React.createRef(), _this.links = [], _this.registerLink = function (link) { if (!_this.links.includes(link)) { _this.links.push(link); } }, _this.unregisterLink = function (link) { var index = _this.links.indexOf(link); if (index !== -1) { _this.links.splice(index, 1); } }, _this.getContainer = function () { var getContainer = _this.props.getContainer; var getFunc = getContainer || getDefaultContainer; return getFunc(); }, _this.handleScrollTo = function (link) { var _this$props = _this.props, offsetTop = _this$props.offsetTop, targetOffset = _this$props.targetOffset; _this.setCurrentActiveLink(link); var container = _this.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; _this.animating = true; scrollTo(y, { callback: function callback() { _this.animating = false; }, getContainer: _this.getContainer }); }, _this.setCurrentActiveLink = function (link) { var activeLink = _this.state.activeLink; var _this$props2 = _this.props, onChange = _this$props2.onChange, getCurrentAnchor = _this$props2.getCurrentAnchor; if (activeLink === link) { return; } _this.setState({ isOpen: !_this.props.allowFold, activeLink: typeof getCurrentAnchor === 'function' ? getCurrentAnchor(link) : link }); onChange && onChange(link); }, _this.handleScroll = function () { if (_this.animating) { return; } var _this$props3 = _this.props, offsetTop = _this$props3.offsetTop, bounds = _this$props3.bounds, targetOffset = _this$props3.targetOffset, allowFold = _this$props3.allowFold; var currentActiveLink = _this.getCurrentAnchor(targetOffset !== undefined ? targetOffset : offsetTop || 0, bounds); _this.setCurrentActiveLink(currentActiveLink); if (allowFold) { clearTimeout(scrollTimeout); scrollTimeout = setTimeout(function () { // 滚动停止后,展开anchor _this.setState({ isOpen: true }); clearTimeout(scrollTimeout); }, 300); } }, _this.handlerOpen = function () { _this.setState({ isOpen: !_this.state.isOpen }); }, _this.getMemoizedContextValue = function (link, onClickFn) { return { registerLink: _this.registerLink, unregisterLink: _this.unregisterLink, scrollTo: _this.handleScrollTo, activeLink: link, onClick: onClickFn }; }, _temp), _possibleConstructorReturn(_this, _ret); } // scroll scope's container Anchor.prototype.componentDidMount = function componentDidMount() { this.scrollContainer = this.getContainer(); events.on(this.scrollContainer, 'scroll', this.handleScroll); if (this.links) { this.setState({ activeLink: this.links[0] }); } }; Anchor.prototype.componentDidUpdate = function componentDidUpdate() { events.off(this.scrollContainer, 'scroll', this.handleScroll); events.on(this.scrollContainer, 'scroll', this.handleScroll); }; Anchor.prototype.componentWillUnmount = function componentWillUnmount() { events.off(this.scrollContainer, 'scroll', this.handleScroll); }; Anchor.prototype.getCurrentAnchor = function getCurrentAnchor() { var offsetTop = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 0; var bounds = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 5; var linkSections = []; var container = this.getContainer(); this.links.forEach(function (link) { var sharpLinkMatch = sharpMatcherRegx.exec(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 ''; }; Anchor.prototype.render = function render() { var _classNames, _classNames2, _this2 = this; var direction = this.context.direction; var _props = this.props, prefix = _props.prefix, _props$className = _props.className, className = _props$className === undefined ? '' : _props$className, style = _props.style, offsetTop = _props.offsetTop, affix = _props.affix, dataSource = _props.dataSource, allowFold = _props.allowFold, onClick = _props.onClick; var _state = this.state, activeLink = _state.activeLink, isOpen = _state.isOpen; var wrapperClass = classNames((allowFold ? prefix + '-wrapper ' + prefix + '-wrapper-allowFold' : prefix + '-wrapper') + ' ', (_classNames = {}, _classNames[prefix + '-rtl'] = direction === 'rtl', _classNames), className); var anchorClass = classNames(prefix, (_classNames2 = {}, _classNames2[prefix + '-fixed'] = !affix, _classNames2)); var wrapperStyle = _extends({ maxHeight: offsetTop ? 'calc(100vh - ' + offsetTop + 'px)' : '100vh' }, style); var anchorContent = React.createElement( 'div', { ref: this.wrapperRef, className: wrapperClass, style: wrapperStyle }, React.createElement( 'div', { className: '' + (allowFold ? anchorClass + ' ' + anchorClass + '-allowFold' : anchorClass) }, dataSource && dataSource.map(function (item, index) { var props = { href: item.href, title: item.title, allowFold: allowFold, isOpen: isOpen }; if (item.children) { return React.createElement( 'div', { key: item.href + '-' + index }, isOpen ? React.createElement(AnchorLink, _extends({}, props, { isParent: true, style: { marginBottom: 0, borderLeftColor: '#DADFE8', color: '#151F28' } })) : null, item.children.map(function (g) { var props = { href: g.href, title: g.title, allowFold: allowFold, isOpen: isOpen, isSub: true }; return React.createElement(AnchorLink, _extends({}, props, { key: g.href })); }) ); } else { return React.createElement(AnchorLink, _extends({}, props, { key: item.href })); } }) ), allowFold ? React.createElement( 'div', { className: prefix + '-fold', onClick: function onClick() { return _this2.handlerOpen(); } }, React.createElement( 'span', null, isOpen ? React.createElement( 'svg', { viewBox: '0 0 1024 1024', version: '1.1', xmlns: 'http://www.w3.org/2000/svg', 'p-id': '8015' }, React.createElement('path', { d: 'M448 672c-6.4 0-19.2 0-25.6-6.4-12.8-12.8-12.8-32 0-44.8L531.2 512 422.4 409.6c-12.8-12.8-12.8-32 0-44.8s32-12.8 44.8 0l128 128c12.8 12.8 12.8 32 0 44.8l-128 128C467.2 672 454.4 672 448 672z', 'p-id': '8016' }) ) : React.createElement( 'svg', { viewBox: '0 0 1024 1024', version: '1.1', xmlns: 'http://www.w3.org/2000/svg', 'p-id': '8747' }, React.createElement('path', { d: 'M576 672c-6.4 0-19.2 0-25.6-6.4l-128-128c-12.8-12.8-12.8-32 0-44.8l128-128c12.8-12.8 32-12.8 44.8 0s12.8 32 0 44.8L492.8 512l102.4 102.4c12.8 12.8 12.8 32 0 44.8C595.2 672 582.4 672 576 672z', 'p-id': '8748' }) ) ) ) : null ); var contextValue = this.getMemoizedContextValue(activeLink, onClick); return React.createElement( AnchorContext.Provider, { value: contextValue }, !affix ? anchorContent : React.createElement( Affix, { useAbsolute: true, offsetTop: offsetTop, target: this.getContainer }, anchorContent ) ); }; return Anchor; }(Component), _class.propTypes = { prefix: PropTypes.string, className: PropTypes.string, style: PropTypes.any, dataSource: PropTypes.array, allowFold: PropTypes.bool, open: PropTypes.bool, children: PropTypes.any, offsetTop: PropTypes.number, bounds: PropTypes.number, affix: PropTypes.bool, getContainer: PropTypes.func, /** Return customize highlight anchor */ getCurrentAnchor: PropTypes.func, onClick: function onClick(e, link) { return PropTypes.void; }, /** Scroll to target offset value, if none, it's offsetTop prop value or 0. */ targetOffset: PropTypes.number, /** Listening event when scrolling change active link */ onChange: function onChange(currentActiveLink) { return PropTypes.void; } }, _class.defaultProps = { prefix: 'next-anchor', affix: true, allowFold: false, open: false }, _temp2); Anchor.displayName = 'Anchor'; export default ConfigProvider.config(polyfill(Anchor));