react-sticky-node
Version:
Sticky react component
218 lines (185 loc) • 7.39 kB
JavaScript
'use strict';
Object.defineProperty(exports, "__esModule", {
value: true
});
var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; };
var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
var _react = require('react');
var _react2 = _interopRequireDefault(_react);
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }
function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }
// TODO Remove calculations from render. Add possibility to handle callbacks.
var StickyNode = function (_Component) {
_inherits(StickyNode, _Component);
function StickyNode(props) {
_classCallCheck(this, StickyNode);
var _this = _possibleConstructorReturn(this, (StickyNode.__proto__ || Object.getPrototypeOf(StickyNode)).call(this, props));
_this.state = {};
return _this;
}
_createClass(StickyNode, [{
key: 'componentDidMount',
value: function componentDidMount() {
var restrictorNode = this.props.restrictorNode;
if (restrictorNode) {
this.adjustPosition(restrictorNode);
}
}
}, {
key: 'componentWillUnmount',
value: function componentWillUnmount() {
this.cancelAdjustPosition();
}
}, {
key: 'componentWillReceiveProps',
value: function componentWillReceiveProps(nextProps) {
var restrictorNode = nextProps.restrictorNode;
this.cancelAdjustPosition();
if (restrictorNode) {
this.adjustPosition(restrictorNode);
}
}
}, {
key: 'adjustPosition',
value: function adjustPosition(restrictorNode) {
var _this2 = this;
var rect = restrictorNode.getBoundingClientRect() || {};
if (rect.width !== this.state.rectWidth) {
this.setState({ rectWidth: rect.width });
}
if (rect.height !== this.state.rectHeight) {
this.setState({ rectHeight: rect.height });
}
if (rect.left !== this.state.rectLeft) {
this.setState({ rectLeft: rect.left });
}
if (rect.right !== this.state.rectRight) {
this.setState({ rectRight: rect.right });
}
if (rect.top !== this.state.rectTop) {
this.setState({ rectTop: rect.top });
}
if (rect.bottom !== this.state.rectBottom) {
this.setState({ rectBottom: rect.bottom });
}
var ref = this._ref.getBoundingClientRect() || {};
if (ref.width !== this.state.refWidth) {
this.setState({ refWidth: ref.width });
}
if (ref.height !== this.state.refHeight) {
this.setState({ refHeight: ref.height });
}
if (ref.left !== this.state.refLeft) {
this.setState({ refLeft: ref.left });
}
if (ref.right !== this.state.refRight) {
this.setState({ refRight: ref.right });
}
if (ref.top !== this.state.refTop) {
this.setState({ refTop: ref.top });
}
if (ref.bottom !== this.state.refBottom) {
this.setState({ refBottom: ref.bottom });
}
this._animationFrame = window.requestAnimationFrame(function () {
return _this2.adjustPosition(restrictorNode);
});
}
}, {
key: 'cancelAdjustPosition',
value: function cancelAdjustPosition() {
if (this._animationFrame) {
cancelAnimationFrame(this._animationFrame);
}
}
}, {
key: 'render',
value: function render() {
var _this3 = this;
var _props = this.props,
className = _props.className,
style = _props.style,
onMaxWidth = _props.onMaxWidth,
onMaxHeight = _props.onMaxHeight,
restrictorNode = _props.restrictorNode;
var _state = this.state,
rectWidth = _state.rectWidth,
rectHeight = _state.rectHeight,
rectLeft = _state.rectLeft,
rectRight = _state.rectRight,
rectTop = _state.rectTop,
rectBottom = _state.rectBottom,
refWidth = _state.refWidth,
refHeight = _state.refHeight,
refLeft = _state.refLeft,
refRight = _state.refRight,
refTop = _state.refTop,
refBottom = _state.refBottom;
var rightOverflow = refRight - rectRight;
var leftOverflow = rectLeft - refLeft;
var topOverflow = rectTop - refTop;
var bottomOverflow = refBottom - rectBottom;
var maxWidth = 'none';
if (refWidth >= rectWidth) {
maxWidth = rectWidth + 'px';
}
var maxHeight = 'none';
if (refHeight >= rectHeight) {
maxHeight = rectHeight + 'px';
}
var styles = {
maxWidth: maxWidth,
maxHeight: maxHeight,
position: 'absolute'
};
var left = 0;
if (leftOverflow > 0) {
left = leftOverflow + 'px';
}
if (rightOverflow > 0) {
left = -rightOverflow + 'px';
}
var top = 0;
if (topOverflow > 0) {
top = topOverflow + 'px';
}
if (bottomOverflow > 0) {
top = -bottomOverflow + 'px';
}
return _react2.default.createElement(
'div',
{
ref: function ref(_ref) {
return _this3._ref = _ref;
},
className: className,
style: _extends({}, styles, style)
},
_react2.default.createElement(
'div',
{ style: {
position: 'relative',
left: left,
top: top
} },
this.props.children
)
);
}
}]);
return StickyNode;
}(_react.Component);
exports.default = StickyNode;
StickyNode.propTypes = {
className: _react.PropTypes.string,
restrictorNode: _react.PropTypes.object,
// onMaxHeight: PropTypes.func, // TODO
// onMaxWidth: PropTypes.func, // TODO
style: _react.PropTypes.object
};
StickyNode.defaultProps = {
restrictorNode: document.body,
style: {}
};