zent
Version:
一套前端设计语言和基于React的实现
353 lines (278 loc) • 11.6 kB
JavaScript
Object.defineProperty(exports, "__esModule", {
value: true
});
exports['default'] = exports.PopoverContextType = undefined;
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 _class, _temp, _initialiseProps; /**
* 设计:
*
* Popover组件只是一个壳子,负责组装Trigger和Content。
*
* 弹层实际的打开/关闭都是Content完成的,而什么情况打开弹层是Trigger控制的。
*/
var _react = require('react');
var _react2 = _interopRequireDefault(_react);
var _reactDom = require('react-dom');
var _reactDom2 = _interopRequireDefault(_reactDom);
var _classnames = require('zent-utils/classnames');
var _classnames2 = _interopRequireDefault(_classnames);
var _noop = require('zent-utils/lodash/noop');
var _noop2 = _interopRequireDefault(_noop);
var _uniqueId = require('zent-utils/lodash/uniqueId');
var _uniqueId2 = _interopRequireDefault(_uniqueId);
var _isFunction = require('zent-utils/lodash/isFunction');
var _isFunction2 = _interopRequireDefault(_isFunction);
var _isBoolean = require('zent-utils/lodash/isBoolean');
var _isBoolean2 = _interopRequireDefault(_isBoolean);
var _isPromise = require('zent-utils/isPromise');
var _isPromise2 = _interopRequireDefault(_isPromise);
var _Content = require('./Content');
var _Content2 = _interopRequireDefault(_Content);
var _Trigger = require('./trigger/Trigger');
var _Trigger2 = _interopRequireDefault(_Trigger);
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; }
var SKIPPED = function SKIPPED() {};
function instanceOf(MaybeDerive, Base) {
return MaybeDerive === Base || MaybeDerive.prototype instanceof Base;
}
function handleBeforeHook(beforeFn, arity, continuation) {
// 有参数,传入continuation,由外部去控制何时调用
if (arity >= 1) {
return beforeFn(continuation);
}
// 无参数,如果返回Promise那么resolve后调用continuation;如果返回不是Promise,直接调用Promise
var mayBePromise = beforeFn();
if (!(0, _isPromise2['default'])(mayBePromise) && mayBePromise !== SKIPPED) {
return continuation();
}
mayBePromise.then(continuation);
}
var PopoverContextType = exports.PopoverContextType = {
popover: _react.PropTypes.shape({
close: _react.PropTypes.func.isRequired,
open: _react.PropTypes.func.isRequired,
getContentNode: _react.PropTypes.func.isRequired,
getTriggerNode: _react.PropTypes.func.isRequired
})
};
var Popover = (_temp = _class = function (_Component) {
_inherits(Popover, _Component);
_createClass(Popover, [{
key: 'getChildContext',
value: function getChildContext() {
return {
popover: {
close: this.close,
open: this.open,
getContentNode: this.getPopoverNode,
getTriggerNode: this.getTriggerNode
}
};
}
}]);
function Popover(props) {
_classCallCheck(this, Popover);
// id用来唯一标识popover实例
var _this = _possibleConstructorReturn(this, (Popover.__proto__ || Object.getPrototypeOf(Popover)).call(this, props));
_initialiseProps.call(_this);
_this.id = (0, _uniqueId2['default'])(props.prefix + '-popover-internal-id-');
if (!_this.isVisibilityControlled(props)) {
_this.state = {
visible: false
};
}
return _this;
}
_createClass(Popover, [{
key: 'isVisibilityControlled',
value: function isVisibilityControlled(props) {
var _ref = props || this.props,
visible = _ref.visible,
onVisibleChange = _ref.onVisibleChange;
var hasOnChange = (0, _isFunction2['default'])(onVisibleChange);
var hasVisible = (0, _isBoolean2['default'])(visible);
if (hasVisible && !hasOnChange || hasOnChange && !hasVisible) {
throw new Error('visible and onVisibleChange must be used together');
}
return hasVisible && hasOnChange;
}
}, {
key: 'validateChildren',
value: function validateChildren() {
var children = this.props.children;
var childArray = _react.Children.toArray(children);
if (childArray.length !== 2) {
throw new Error('There must be one and only one trigger and content in Popover');
}
var _childArray$reduce = childArray.reduce(function (state, c) {
var type = c.type;
if (instanceOf(type, _Trigger2['default'])) {
state.trigger = c;
} else if (instanceOf(type, _Content2['default'])) {
state.content = c;
}
return state;
}, { trigger: null, content: null }),
trigger = _childArray$reduce.trigger,
content = _childArray$reduce.content;
if (!trigger) {
throw new Error('Missing trigger in Popover');
}
if (!content) {
throw new Error('Missing content in Popover');
}
return { trigger: trigger, content: content };
}
}, {
key: 'componentDidMount',
value: function componentDidMount() {
if (this.isVisibilityControlled() && this.props.visible) {
this.props.onShow();
}
}
}, {
key: 'componentDidUpdate',
value: function componentDidUpdate(prevProps, prevState) {
var visible = this.getVisible();
if (visible !== this.getVisible(prevProps, prevState)) {
var afterHook = visible ? this.props.onShow : this.props.onClose;
afterHook();
}
}
}, {
key: 'render',
value: function render() {
var _validateChildren = this.validateChildren(),
trigger = _validateChildren.trigger,
content = _validateChildren.content;
var _props = this.props,
display = _props.display,
prefix = _props.prefix,
className = _props.className,
wrapperClassName = _props.wrapperClassName,
containerSelector = _props.containerSelector,
position = _props.position,
cushion = _props.cushion;
var visible = this.getVisible();
return _react2['default'].createElement(
'div',
{ style: { display: display }, className: (0, _classnames2['default'])(prefix + '-popover-wrapper', wrapperClassName) },
_react2['default'].cloneElement(trigger, {
prefix: prefix,
contentVisible: visible,
onTriggerRefChange: this.onTriggerRefChange,
getTriggerNode: this.getTriggerNode,
getContentNode: this.getPopoverNode,
open: this.open,
close: this.close
}),
_react2['default'].cloneElement(content, {
prefix: prefix,
className: className,
id: this.id,
getContentNode: this.getPopoverNode,
getAnchor: this.getTriggerNode,
visible: visible,
cushion: cushion,
containerSelector: containerSelector,
placement: position
})
);
}
}]);
return Popover;
}(_react.Component), _class.propTypes = {
prefix: _react.PropTypes.string,
className: _react.PropTypes.string,
// custom classname for trigger wrapper
wrapperClassName: _react.PropTypes.string,
// container的display属性
display: _react.PropTypes.string,
// position strategy
position: _react.PropTypes.func.isRequired,
// 定位时的偏移量
cushion: _react.PropTypes.number,
// 只有用户触发的打开/关闭才会触发这两个毁掉
onBeforeClose: _react.PropTypes.func,
onBeforeShow: _react.PropTypes.func,
// 不管打开/关闭时如何触发的都会被调用
onClose: _react.PropTypes.func,
onShow: _react.PropTypes.func,
// defaults to body
containerSelector: _react.PropTypes.string,
children: _react.PropTypes.node.isRequired,
// 两个必须一起出现
visible: _react.PropTypes.bool,
onVisibleChange: _react.PropTypes.func
}, _class.defaultProps = {
prefix: 'zent',
className: '',
wrapperClassName: '',
display: 'block',
onBeforeClose: _noop2['default'],
onBeforeShow: _noop2['default'],
onClose: _noop2['default'],
onShow: _noop2['default'],
cushion: 0,
containerSelector: 'body'
}, _class.childContextTypes = PopoverContextType, _initialiseProps = function _initialiseProps() {
var _this2 = this;
this.getVisible = function (props, state) {
if (_this2.isVisibilityControlled(props)) {
props = props || _this2.props;
return props.visible;
}
state = state || _this2.state;
return state.visible;
};
this.setVisible = function (visible, props, state) {
props = props || _this2.props;
state = state || _this2.state;
var beforeHook = visible ? props.onBeforeShow : props.onBeforeClose;
var onBefore = function onBefore() {
// 确保pending的时候不会触发多次beforeHook
if (_this2.pendingOnBeforeHook) {
return SKIPPED;
}
_this2.pendingOnBeforeHook = true;
return beforeHook.apply(undefined, arguments);
};
if (_this2.isVisibilityControlled(props)) {
if (_this2.pendingOnBeforeHook || props.visible === visible) {
return;
}
handleBeforeHook(onBefore, beforeHook.length, function () {
props.onVisibleChange(visible);
_this2.pendingOnBeforeHook = false;
});
} else {
if (_this2.pendingOnBeforeHook || state.visible === visible) {
return;
}
handleBeforeHook(onBefore, beforeHook.length, function () {
_this2.setState({ visible: visible });
_this2.pendingOnBeforeHook = false;
});
}
};
this.getPopoverNode = function () {
return document.querySelector('.' + _this2.id);
};
this.onTriggerRefChange = function (triggerInstance) {
_this2.triggerNode = _reactDom2['default'].findDOMNode(triggerInstance);
};
this.getTriggerNode = function () {
return _this2.triggerNode;
};
this.open = function () {
_this2.setVisible(true);
};
this.close = function () {
_this2.setVisible(false);
};
}, _temp);
exports['default'] = Popover;
;