You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

201 lines
6.0 KiB

  1. import _classCallCheck from 'babel-runtime/helpers/classCallCheck';
  2. import _createClass from 'babel-runtime/helpers/createClass';
  3. import _possibleConstructorReturn from 'babel-runtime/helpers/possibleConstructorReturn';
  4. import _inherits from 'babel-runtime/helpers/inherits';
  5. import React, { Component } from 'react';
  6. import PropTypes from 'prop-types';
  7. import ReactDOM from 'react-dom';
  8. import { alignElement, alignPoint } from 'dom-align';
  9. import addEventListener from 'rc-util/es/Dom/addEventListener';
  10. import { isWindow, buffer, isSamePoint, isSimilarValue, restoreFocus } from './util';
  11. function getElement(func) {
  12. if (typeof func !== 'function' || !func) return null;
  13. return func();
  14. }
  15. function getPoint(point) {
  16. if (typeof point !== 'object' || !point) return null;
  17. return point;
  18. }
  19. var Align = function (_Component) {
  20. _inherits(Align, _Component);
  21. function Align() {
  22. var _ref;
  23. var _temp, _this, _ret;
  24. _classCallCheck(this, Align);
  25. for (var _len = arguments.length, args = Array(_len), _key = 0; _key < _len; _key++) {
  26. args[_key] = arguments[_key];
  27. }
  28. return _ret = (_temp = (_this = _possibleConstructorReturn(this, (_ref = Align.__proto__ || Object.getPrototypeOf(Align)).call.apply(_ref, [this].concat(args))), _this), _this.forceAlign = function () {
  29. var _this$props = _this.props,
  30. disabled = _this$props.disabled,
  31. target = _this$props.target,
  32. align = _this$props.align,
  33. onAlign = _this$props.onAlign;
  34. if (!disabled && target) {
  35. var source = ReactDOM.findDOMNode(_this);
  36. var result = void 0;
  37. var element = getElement(target);
  38. var point = getPoint(target);
  39. // IE lose focus after element realign
  40. // We should record activeElement and restore later
  41. var activeElement = document.activeElement;
  42. if (element) {
  43. result = alignElement(source, element, align);
  44. } else if (point) {
  45. result = alignPoint(source, point, align);
  46. }
  47. restoreFocus(activeElement, source);
  48. if (onAlign) {
  49. onAlign(source, result);
  50. }
  51. }
  52. }, _temp), _possibleConstructorReturn(_this, _ret);
  53. }
  54. _createClass(Align, [{
  55. key: 'componentDidMount',
  56. value: function componentDidMount() {
  57. var props = this.props;
  58. // if parent ref not attached .... use document.getElementById
  59. this.forceAlign();
  60. if (!props.disabled && props.monitorWindowResize) {
  61. this.startMonitorWindowResize();
  62. }
  63. }
  64. }, {
  65. key: 'componentDidUpdate',
  66. value: function componentDidUpdate(prevProps) {
  67. var reAlign = false;
  68. var props = this.props;
  69. if (!props.disabled) {
  70. var source = ReactDOM.findDOMNode(this);
  71. var sourceRect = source ? source.getBoundingClientRect() : null;
  72. if (prevProps.disabled) {
  73. reAlign = true;
  74. } else {
  75. var lastElement = getElement(prevProps.target);
  76. var currentElement = getElement(props.target);
  77. var lastPoint = getPoint(prevProps.target);
  78. var currentPoint = getPoint(props.target);
  79. if (isWindow(lastElement) && isWindow(currentElement)) {
  80. // Skip if is window
  81. reAlign = false;
  82. } else if (lastElement !== currentElement || // Element change
  83. lastElement && !currentElement && currentPoint || // Change from element to point
  84. lastPoint && currentPoint && currentElement || // Change from point to element
  85. currentPoint && !isSamePoint(lastPoint, currentPoint)) {
  86. reAlign = true;
  87. }
  88. // If source element size changed
  89. var preRect = this.sourceRect || {};
  90. if (!reAlign && source && (!isSimilarValue(preRect.width, sourceRect.width) || !isSimilarValue(preRect.height, sourceRect.height))) {
  91. reAlign = true;
  92. }
  93. }
  94. this.sourceRect = sourceRect;
  95. }
  96. if (reAlign) {
  97. this.forceAlign();
  98. }
  99. if (props.monitorWindowResize && !props.disabled) {
  100. this.startMonitorWindowResize();
  101. } else {
  102. this.stopMonitorWindowResize();
  103. }
  104. }
  105. }, {
  106. key: 'componentWillUnmount',
  107. value: function componentWillUnmount() {
  108. this.stopMonitorWindowResize();
  109. }
  110. }, {
  111. key: 'startMonitorWindowResize',
  112. value: function startMonitorWindowResize() {
  113. if (!this.resizeHandler) {
  114. this.bufferMonitor = buffer(this.forceAlign, this.props.monitorBufferTime);
  115. this.resizeHandler = addEventListener(window, 'resize', this.bufferMonitor);
  116. }
  117. }
  118. }, {
  119. key: 'stopMonitorWindowResize',
  120. value: function stopMonitorWindowResize() {
  121. if (this.resizeHandler) {
  122. this.bufferMonitor.clear();
  123. this.resizeHandler.remove();
  124. this.resizeHandler = null;
  125. }
  126. }
  127. }, {
  128. key: 'render',
  129. value: function render() {
  130. var _this2 = this;
  131. var _props = this.props,
  132. childrenProps = _props.childrenProps,
  133. children = _props.children;
  134. var child = React.Children.only(children);
  135. if (childrenProps) {
  136. var newProps = {};
  137. var propList = Object.keys(childrenProps);
  138. propList.forEach(function (prop) {
  139. newProps[prop] = _this2.props[childrenProps[prop]];
  140. });
  141. return React.cloneElement(child, newProps);
  142. }
  143. return child;
  144. }
  145. }]);
  146. return Align;
  147. }(Component);
  148. Align.propTypes = {
  149. childrenProps: PropTypes.object,
  150. align: PropTypes.object.isRequired,
  151. target: PropTypes.oneOfType([PropTypes.func, PropTypes.shape({
  152. clientX: PropTypes.number,
  153. clientY: PropTypes.number,
  154. pageX: PropTypes.number,
  155. pageY: PropTypes.number
  156. })]),
  157. onAlign: PropTypes.func,
  158. monitorBufferTime: PropTypes.number,
  159. monitorWindowResize: PropTypes.bool,
  160. disabled: PropTypes.bool,
  161. children: PropTypes.any
  162. };
  163. Align.defaultProps = {
  164. target: function target() {
  165. return window;
  166. },
  167. monitorBufferTime: 50,
  168. monitorWindowResize: false,
  169. disabled: false
  170. };
  171. export default Align;