UNPKG

15.3 kBJavaScriptView Raw
1import _extends from 'babel-runtime/helpers/extends';
2import _objectWithoutProperties from 'babel-runtime/helpers/objectWithoutProperties';
3import _classCallCheck from 'babel-runtime/helpers/classCallCheck';
4import _possibleConstructorReturn from 'babel-runtime/helpers/possibleConstructorReturn';
5import _inherits from 'babel-runtime/helpers/inherits';
6
7var _class, _temp;
8
9import React from 'react';
10import PropTypes from 'prop-types';
11import { polyfill } from 'react-lifecycles-compat';
12import Overlay from '../overlay';
13import { func, obj, log } from '../util';
14import BalloonInner from './inner';
15import { normalMap, edgeMap } from './alignMap';
16import { getDisabledCompatibleTrigger } from './util';
17
18var noop = func.noop;
19var Popup = Overlay.Popup;
20
21
22var alignList = ['t', 'r', 'b', 'l', 'tl', 'tr', 'bl', 'br', 'lt', 'lb', 'rt', 'rb'];
23
24var alignMap = normalMap;
25
26/** Balloon */
27var Balloon = (_temp = _class = function (_React$Component) {
28 _inherits(Balloon, _React$Component);
29
30 function Balloon(props, context) {
31 _classCallCheck(this, Balloon);
32
33 var _this = _possibleConstructorReturn(this, _React$Component.call(this, props, context));
34
35 _this.beforePosition = function (result, obj) {
36 var placement = result.config.placement;
37
38 if (placement !== _this.state.align) {
39 _this.setState({
40 align: placement,
41 innerAlign: true
42 });
43 }
44
45 if (_this.props.arrowPointToCenter) {
46 var _obj$target = obj.target,
47 width = _obj$target.width,
48 height = _obj$target.height;
49
50 if (placement.length === 2) {
51 var offset = normalMap[placement].offset;
52 switch (placement[0]) {
53 case 'b':
54 case 't':
55 {
56 var plus = offset[0] > 0 ? 1 : -1;
57 result.style.left = result.style.left + plus * width / 2 - offset[0];
58 }
59 break;
60 case 'l':
61 case 'r':
62 {
63 var _plus = offset[0] > 0 ? 1 : -1;
64 result.style.top = result.style.top + _plus * height / 2 - offset[1];
65 }
66 break;
67 }
68 }
69 }
70
71 return result;
72 };
73
74 _this.state = {
75 align: alignList.includes(props.align) ? props.align : 'b',
76 visible: 'visible' in props ? props.visible : props.defaultVisible
77 };
78 _this._onClose = _this._onClose.bind(_this);
79 _this._onPosition = _this._onPosition.bind(_this);
80 _this._onVisibleChange = _this._onVisibleChange.bind(_this);
81 return _this;
82 }
83
84 Balloon.getDerivedStateFromProps = function getDerivedStateFromProps(nextProps, prevState) {
85 var nextState = {};
86 if ('visible' in nextProps) {
87 nextState.visible = nextProps.visible;
88 }
89
90 if (!prevState.innerAlign && 'align' in nextProps && alignList.includes(nextProps.align) && nextProps.align !== prevState.align) {
91 nextState.align = nextProps.align;
92 nextState.innerAlign = false;
93 }
94
95 return nextState;
96 };
97
98 Balloon.prototype._onVisibleChange = function _onVisibleChange(visible, trigger) {
99 // Not Controlled
100 if (!('visible' in this.props)) {
101 this.setState({
102 visible: visible
103 });
104 }
105
106 this.props.onVisibleChange(visible, trigger);
107
108 if (!visible) {
109 this.props.onClose();
110 }
111 };
112
113 Balloon.prototype._onClose = function _onClose(e) {
114 this._onVisibleChange(false, 'closeClick');
115
116 //必须加上preventDefault,否则单测IE下报错,出现full page reload 异常
117 e.preventDefault();
118 };
119
120 Balloon.prototype._onPosition = function _onPosition(res) {
121 var rtl = this.props.rtl;
122
123 alignMap = this.props.alignEdge ? edgeMap : normalMap;
124 var newAlign = res.align.join(' ');
125 var resAlign = void 0;
126
127 var alignKey = 'align';
128 if (rtl) {
129 alignKey = 'rtlAlign';
130 }
131
132 for (var key in alignMap) {
133 if (alignMap[key][alignKey] === newAlign) {
134 resAlign = key;
135
136 break;
137 }
138 }
139
140 resAlign = resAlign || this.state.align;
141 if (resAlign !== this.state.align) {
142 this.setState({
143 align: resAlign,
144 innerAlign: true
145 });
146 }
147 };
148
149 Balloon.prototype.render = function render() {
150 var _props = this.props,
151 id = _props.id,
152 type = _props.type,
153 prefix = _props.prefix,
154 className = _props.className,
155 title = _props.title,
156 alignEdge = _props.alignEdge,
157 trigger = _props.trigger,
158 triggerType = _props.triggerType,
159 children = _props.children,
160 closable = _props.closable,
161 shouldUpdatePosition = _props.shouldUpdatePosition,
162 delay = _props.delay,
163 needAdjust = _props.needAdjust,
164 autoAdjust = _props.autoAdjust,
165 safeId = _props.safeId,
166 autoFocus = _props.autoFocus,
167 safeNode = _props.safeNode,
168 onClick = _props.onClick,
169 onHover = _props.onHover,
170 animation = _props.animation,
171 offset = _props.offset,
172 style = _props.style,
173 container = _props.container,
174 popupContainer = _props.popupContainer,
175 cache = _props.cache,
176 popupStyle = _props.popupStyle,
177 popupClassName = _props.popupClassName,
178 popupProps = _props.popupProps,
179 followTrigger = _props.followTrigger,
180 rtl = _props.rtl,
181 v2 = _props.v2,
182 arrowPointToCenter = _props.arrowPointToCenter,
183 _props$placementOffse = _props.placementOffset,
184 placementOffset = _props$placementOffse === undefined ? 0 : _props$placementOffse,
185 others = _objectWithoutProperties(_props, ['id', 'type', 'prefix', 'className', 'title', 'alignEdge', 'trigger', 'triggerType', 'children', 'closable', 'shouldUpdatePosition', 'delay', 'needAdjust', 'autoAdjust', 'safeId', 'autoFocus', 'safeNode', 'onClick', 'onHover', 'animation', 'offset', 'style', 'container', 'popupContainer', 'cache', 'popupStyle', 'popupClassName', 'popupProps', 'followTrigger', 'rtl', 'v2', 'arrowPointToCenter', 'placementOffset']);
186
187 if (container) {
188 log.deprecated('container', 'popupContainer', 'Balloon');
189 }
190
191 var align = this.state.align;
192
193
194 alignMap = alignEdge || v2 ? edgeMap : normalMap;
195 var _prefix = this.context.prefix || prefix;
196
197 var trOrigin = 'trOrigin';
198 if (rtl) {
199 trOrigin = 'rtlTrOrigin';
200 }
201
202 var _offset = [alignMap[align].offset[0] + offset[0], alignMap[align].offset[1] + offset[1]];
203 var transformOrigin = alignMap[align][trOrigin];
204 var _style = _extends({ transformOrigin: transformOrigin }, style);
205
206 var content = React.createElement(
207 BalloonInner,
208 _extends({}, obj.pickOthers(Object.keys(Balloon.propTypes), others), {
209 id: id,
210 title: title,
211 prefix: _prefix,
212 closable: closable,
213 onClose: this._onClose,
214 className: className,
215 style: _style,
216 align: align,
217 type: type,
218 rtl: rtl,
219 alignEdge: alignEdge,
220 v2: v2
221 }),
222 children
223 );
224
225 var triggerProps = {};
226 triggerProps['aria-describedby'] = id;
227 triggerProps.tabIndex = '0';
228
229 var ariaTrigger = id ? React.cloneElement(trigger, triggerProps) : trigger;
230
231 var newTrigger = getDisabledCompatibleTrigger(React.isValidElement(ariaTrigger) ? ariaTrigger : React.createElement(
232 'span',
233 null,
234 ariaTrigger
235 ));
236
237 var otherProps = {
238 delay: delay,
239 shouldUpdatePosition: shouldUpdatePosition,
240 needAdjust: needAdjust,
241 align: alignMap[align].align,
242 offset: _offset,
243 safeId: safeId,
244 onHover: onHover,
245 onPosition: this._onPosition
246 };
247
248 if (v2) {
249 delete otherProps.align;
250 delete otherProps.shouldUpdatePosition;
251 delete otherProps.needAdjust;
252 delete otherProps.offset;
253 delete otherProps.safeId;
254 delete otherProps.onHover;
255 delete otherProps.onPosition;
256
257 _extends(otherProps, {
258 placement: align,
259 placementOffset: placementOffset + 12,
260 v2: true,
261 beforePosition: this.beforePosition,
262 autoAdjust: autoAdjust
263 });
264 }
265
266 return React.createElement(
267 Popup,
268 _extends({}, popupProps, {
269 followTrigger: followTrigger,
270 trigger: newTrigger,
271 cache: cache,
272 triggerType: triggerType,
273 visible: this.state.visible,
274 onClick: onClick,
275 afterClose: this.props.afterClose,
276 onVisibleChange: this._onVisibleChange,
277 animation: animation,
278 autoFocus: triggerType === 'focus' ? false : autoFocus,
279 safeNode: safeNode,
280 container: popupContainer || container,
281 className: popupClassName,
282 style: popupStyle,
283 rtl: rtl
284 }, otherProps),
285 content
286 );
287 };
288
289 return Balloon;
290}(React.Component), _class.contextTypes = {
291 prefix: PropTypes.string
292}, _class.propTypes = {
293 prefix: PropTypes.string,
294 pure: PropTypes.bool,
295 rtl: PropTypes.bool,
296 /**
297 * 自定义类名
298 */
299 className: PropTypes.string,
300 /**
301 * 自定义内敛样式
302 */
303 style: PropTypes.object,
304 /**
305 * 浮层的内容
306 */
307 children: PropTypes.any,
308 size: PropTypes.string,
309 /**
310 * 样式类型
311 */
312 type: PropTypes.oneOf(['normal', 'primary']),
313 /**
314 * 标题
315 * @version 1.23
316 */
317 title: PropTypes.node,
318 /**
319 * 弹层当前显示的状态
320 */
321 visible: PropTypes.bool,
322 /**
323 * 弹层默认显示的状态
324 */
325 defaultVisible: PropTypes.bool,
326 /**
327 * 弹层在显示和隐藏触发的事件
328 * @param {Boolean} visible 弹层是否隐藏和显示
329 * @param {String} type 触发弹层显示或隐藏的来源, closeClick 表示由自带的关闭按钮触发; fromTrigger 表示由trigger的点击触发; docClick 表示由document的点击触发
330 */
331 onVisibleChange: PropTypes.func,
332 alignEdge: PropTypes.bool,
333 /**
334 * 开启 v2 版本
335 * @version 1.25
336 */
337 v2: PropTypes.bool,
338 /**
339 * [v2] 箭头是否指向目标元素的中心
340 * @version 1.25
341 */
342 arrowPointToCenter: PropTypes.bool,
343 /**
344 * [v2] 弹层偏离触发元素的像素值
345 */
346 placementOffset: PropTypes.number,
347 /**
348 * 是否显示关闭按钮
349 */
350 closable: PropTypes.bool,
351 /**
352 * 弹出层位置
353 * @enumdesc 上, 右, 下, 左, 上左, 上右, 下左, 下右, 左上, 左下, 右上, 右下
354 */
355 align: PropTypes.oneOf(alignList),
356 /**
357 * 弹层相对于trigger的定位的微调, 接收数组[hoz, ver], 表示弹层在 left / top 上的增量
358 * e.g. [100, 100] 表示往右(RTL 模式下是往左) 、下分布偏移100px
359 */
360 offset: PropTypes.array,
361 /**
362 * 触发元素
363 */
364 trigger: PropTypes.any,
365 /**
366 * 触发行为
367 * 鼠标悬浮, 鼠标点击('hover','click')或者它们组成的数组,如 ['hover', 'click'], 强烈不建议使用'focus',若弹窗内容有复杂交互请使用click
368 */
369 triggerType: PropTypes.oneOfType([PropTypes.string, PropTypes.array]),
370
371 onClick: PropTypes.func,
372 /**
373 * 任何visible为false时会触发的事件
374 */
375 onClose: PropTypes.func,
376 onHover: PropTypes.func,
377 /**
378 * [v2] 是否进行自动位置调整,默认自动开启。
379 * @version 1.25
380 */
381 autoAdjust: PropTypes.bool,
382 needAdjust: PropTypes.bool,
383 /**
384 * 弹层在触发以后的延时显示, 单位毫秒 ms
385 */
386 delay: PropTypes.number,
387 /**
388 * 浮层关闭后触发的事件, 如果有动画,则在动画结束后触发
389 */
390 afterClose: PropTypes.func,
391 shouldUpdatePosition: PropTypes.bool,
392 /**
393 * 弹层出现后是否自动focus到内部第一个元素
394 */
395 autoFocus: PropTypes.bool,
396 /**
397 * 安全节点:对于triggetType为click的浮层,会在点击除了浮层外的其它区域时关闭浮层.safeNode用于添加不触发关闭的节点, 值可以是dom节点的id或者是节点的dom对象
398 */
399 safeNode: PropTypes.string,
400 /**
401 * 用来指定safeNode节点的id,和safeNode配合使用
402 */
403 safeId: PropTypes.string,
404 /**
405 * 配置动画的播放方式,格式是{in: '', out: ''}, 常用的动画class请查看Animate组件文档
406 * @param {String} in 进场动画
407 * @param {String} out 出场动画
408 */
409 animation: PropTypes.oneOfType([PropTypes.object, PropTypes.bool]),
410
411 /**
412 * 弹层的dom节点关闭时是否删除
413 */
414 cache: PropTypes.bool,
415 /**
416 * 指定浮层渲染的父节点, 可以为节点id的字符串,也可以返回节点的函数。
417 */
418 popupContainer: PropTypes.any,
419 container: PropTypes.any,
420 /**
421 * 弹层组件style,透传给Popup
422 */
423 popupStyle: PropTypes.object,
424 /**
425 * 弹层组件className,透传给Popup
426 */
427 popupClassName: PropTypes.string,
428 /**
429 * 弹层组件属性,透传给Popup
430 */
431 popupProps: PropTypes.object,
432 /**
433 * 是否跟随滚动
434 */
435 followTrigger: PropTypes.bool,
436 /**
437 * 弹层id, 传入值才会支持无障碍
438 */
439 id: PropTypes.string
440}, _class.defaultProps = {
441 prefix: 'next-',
442 pure: false,
443 type: 'normal',
444 closable: true,
445 defaultVisible: false,
446 size: 'medium',
447 alignEdge: false,
448 arrowPointToCenter: false,
449 align: 'b',
450 offset: [0, 0],
451 trigger: React.createElement('span', null),
452 onClose: noop,
453 afterClose: noop,
454 onVisibleChange: noop,
455 needAdjust: false,
456 triggerType: 'hover',
457 safeNode: undefined,
458 safeId: null,
459 autoFocus: true,
460 animation: {
461 in: 'zoomIn zoomInBig',
462 out: 'zoomOut zoomOutBig'
463 },
464 cache: false,
465 popupStyle: {},
466 popupClassName: '',
467 popupProps: {}
468}, _temp);
469Balloon.displayName = 'Balloon';
470
471
472export default polyfill(Balloon);
\No newline at end of file