2020-05-19 11:43:42 +03:00

201 lines
6.0 KiB
JavaScript

import _classCallCheck from 'babel-runtime/helpers/classCallCheck';
import _createClass from 'babel-runtime/helpers/createClass';
import _possibleConstructorReturn from 'babel-runtime/helpers/possibleConstructorReturn';
import _inherits from 'babel-runtime/helpers/inherits';
import React, { Component } from 'react';
import PropTypes from 'prop-types';
import ReactDOM from 'react-dom';
import { alignElement, alignPoint } from 'dom-align';
import addEventListener from 'rc-util/es/Dom/addEventListener';
import { isWindow, buffer, isSamePoint, isSimilarValue, restoreFocus } from './util';
function getElement(func) {
if (typeof func !== 'function' || !func) return null;
return func();
}
function getPoint(point) {
if (typeof point !== 'object' || !point) return null;
return point;
}
var Align = function (_Component) {
_inherits(Align, _Component);
function Align() {
var _ref;
var _temp, _this, _ret;
_classCallCheck(this, Align);
for (var _len = arguments.length, args = Array(_len), _key = 0; _key < _len; _key++) {
args[_key] = arguments[_key];
}
return _ret = (_temp = (_this = _possibleConstructorReturn(this, (_ref = Align.__proto__ || Object.getPrototypeOf(Align)).call.apply(_ref, [this].concat(args))), _this), _this.forceAlign = function () {
var _this$props = _this.props,
disabled = _this$props.disabled,
target = _this$props.target,
align = _this$props.align,
onAlign = _this$props.onAlign;
if (!disabled && target) {
var source = ReactDOM.findDOMNode(_this);
var result = void 0;
var element = getElement(target);
var point = getPoint(target);
// IE lose focus after element realign
// We should record activeElement and restore later
var activeElement = document.activeElement;
if (element) {
result = alignElement(source, element, align);
} else if (point) {
result = alignPoint(source, point, align);
}
restoreFocus(activeElement, source);
if (onAlign) {
onAlign(source, result);
}
}
}, _temp), _possibleConstructorReturn(_this, _ret);
}
_createClass(Align, [{
key: 'componentDidMount',
value: function componentDidMount() {
var props = this.props;
// if parent ref not attached .... use document.getElementById
this.forceAlign();
if (!props.disabled && props.monitorWindowResize) {
this.startMonitorWindowResize();
}
}
}, {
key: 'componentDidUpdate',
value: function componentDidUpdate(prevProps) {
var reAlign = false;
var props = this.props;
if (!props.disabled) {
var source = ReactDOM.findDOMNode(this);
var sourceRect = source ? source.getBoundingClientRect() : null;
if (prevProps.disabled) {
reAlign = true;
} else {
var lastElement = getElement(prevProps.target);
var currentElement = getElement(props.target);
var lastPoint = getPoint(prevProps.target);
var currentPoint = getPoint(props.target);
if (isWindow(lastElement) && isWindow(currentElement)) {
// Skip if is window
reAlign = false;
} else if (lastElement !== currentElement || // Element change
lastElement && !currentElement && currentPoint || // Change from element to point
lastPoint && currentPoint && currentElement || // Change from point to element
currentPoint && !isSamePoint(lastPoint, currentPoint)) {
reAlign = true;
}
// If source element size changed
var preRect = this.sourceRect || {};
if (!reAlign && source && (!isSimilarValue(preRect.width, sourceRect.width) || !isSimilarValue(preRect.height, sourceRect.height))) {
reAlign = true;
}
}
this.sourceRect = sourceRect;
}
if (reAlign) {
this.forceAlign();
}
if (props.monitorWindowResize && !props.disabled) {
this.startMonitorWindowResize();
} else {
this.stopMonitorWindowResize();
}
}
}, {
key: 'componentWillUnmount',
value: function componentWillUnmount() {
this.stopMonitorWindowResize();
}
}, {
key: 'startMonitorWindowResize',
value: function startMonitorWindowResize() {
if (!this.resizeHandler) {
this.bufferMonitor = buffer(this.forceAlign, this.props.monitorBufferTime);
this.resizeHandler = addEventListener(window, 'resize', this.bufferMonitor);
}
}
}, {
key: 'stopMonitorWindowResize',
value: function stopMonitorWindowResize() {
if (this.resizeHandler) {
this.bufferMonitor.clear();
this.resizeHandler.remove();
this.resizeHandler = null;
}
}
}, {
key: 'render',
value: function render() {
var _this2 = this;
var _props = this.props,
childrenProps = _props.childrenProps,
children = _props.children;
var child = React.Children.only(children);
if (childrenProps) {
var newProps = {};
var propList = Object.keys(childrenProps);
propList.forEach(function (prop) {
newProps[prop] = _this2.props[childrenProps[prop]];
});
return React.cloneElement(child, newProps);
}
return child;
}
}]);
return Align;
}(Component);
Align.propTypes = {
childrenProps: PropTypes.object,
align: PropTypes.object.isRequired,
target: PropTypes.oneOfType([PropTypes.func, PropTypes.shape({
clientX: PropTypes.number,
clientY: PropTypes.number,
pageX: PropTypes.number,
pageY: PropTypes.number
})]),
onAlign: PropTypes.func,
monitorBufferTime: PropTypes.number,
monitorWindowResize: PropTypes.bool,
disabled: PropTypes.bool,
children: PropTypes.any
};
Align.defaultProps = {
target: function target() {
return window;
},
monitorBufferTime: 50,
monitorWindowResize: false,
disabled: false
};
export default Align;