UNPKG

react-bootstrap

Version:

Bootstrap 3 components build with React

128 lines (102 loc) 3.32 kB
import React from 'react'; import domUtils from './utils/domUtils'; import EventListener from './utils/EventListener'; const AffixMixin = { propTypes: { offset: React.PropTypes.number, offsetTop: React.PropTypes.number, offsetBottom: React.PropTypes.number }, getInitialState() { return { affixClass: 'affix-top' }; }, getPinnedOffset(DOMNode) { if (this.pinnedOffset) { return this.pinnedOffset; } DOMNode.className = DOMNode.className.replace(/affix-top|affix-bottom|affix/, ''); DOMNode.className += DOMNode.className.length ? ' affix' : 'affix'; this.pinnedOffset = domUtils.getOffset(DOMNode).top - window.pageYOffset; return this.pinnedOffset; }, checkPosition() { let DOMNode, scrollHeight, scrollTop, position, offsetTop, offsetBottom, affix, affixType, affixPositionTop; // TODO: or not visible if (!this.isMounted()) { return; } DOMNode = React.findDOMNode(this); scrollHeight = document.documentElement.offsetHeight; scrollTop = window.pageYOffset; position = domUtils.getOffset(DOMNode); if (this.affixed === 'top') { position.top += scrollTop; } offsetTop = this.props.offsetTop != null ? this.props.offsetTop : this.props.offset; offsetBottom = this.props.offsetBottom != null ? this.props.offsetBottom : this.props.offset; if (offsetTop == null && offsetBottom == null) { return; } if (offsetTop == null) { offsetTop = 0; } if (offsetBottom == null) { offsetBottom = 0; } if (this.unpin != null && (scrollTop + this.unpin <= position.top)) { affix = false; } else if (offsetBottom != null && (position.top + DOMNode.offsetHeight >= scrollHeight - offsetBottom)) { affix = 'bottom'; } else if (offsetTop != null && (scrollTop <= offsetTop)) { affix = 'top'; } else { affix = false; } if (this.affixed === affix) { return; } if (this.unpin != null) { DOMNode.style.top = ''; } affixType = 'affix' + (affix ? '-' + affix : ''); this.affixed = affix; this.unpin = affix === 'bottom' ? this.getPinnedOffset(DOMNode) : null; if (affix === 'bottom') { DOMNode.className = DOMNode.className.replace(/affix-top|affix-bottom|affix/, 'affix-bottom'); affixPositionTop = scrollHeight - offsetBottom - DOMNode.offsetHeight - domUtils.getOffset(DOMNode).top; } this.setState({ affixClass: affixType, affixPositionTop }); }, checkPositionWithEventLoop() { setTimeout(this.checkPosition, 0); }, componentDidMount() { this._onWindowScrollListener = EventListener.listen(window, 'scroll', this.checkPosition); this._onDocumentClickListener = EventListener.listen(domUtils.ownerDocument(this), 'click', this.checkPositionWithEventLoop); }, componentWillUnmount() { if (this._onWindowScrollListener) { this._onWindowScrollListener.remove(); } if (this._onDocumentClickListener) { this._onDocumentClickListener.remove(); } }, componentDidUpdate(prevProps, prevState) { if (prevState.affixClass === this.state.affixClass) { this.checkPositionWithEventLoop(); } } }; export default AffixMixin;