1 | import _objectWithoutProperties from 'babel-runtime/helpers/objectWithoutProperties';
|
2 | import _classCallCheck from 'babel-runtime/helpers/classCallCheck';
|
3 | import _possibleConstructorReturn from 'babel-runtime/helpers/possibleConstructorReturn';
|
4 | import _inherits from 'babel-runtime/helpers/inherits';
|
5 | import _extends from 'babel-runtime/helpers/extends';
|
6 | import contains from 'dom-helpers/query/contains';
|
7 | import React, { cloneElement } from 'react';
|
8 | import PropTypes from 'prop-types';
|
9 | import ReactDOM from 'react-dom';
|
10 | import warning from 'warning';
|
11 |
|
12 | import Overlay from './Overlay';
|
13 |
|
14 | import createChainedFunction from './utils/createChainedFunction';
|
15 |
|
16 |
|
17 |
|
18 |
|
19 |
|
20 |
|
21 |
|
22 |
|
23 | function isOneOf(one, of) {
|
24 | if (Array.isArray(of)) {
|
25 | return of.indexOf(one) >= 0;
|
26 | }
|
27 | return one === of;
|
28 | }
|
29 |
|
30 | var triggerType = PropTypes.oneOf(['click', 'hover', 'focus']);
|
31 |
|
32 | var propTypes = _extends({}, Overlay.propTypes, {
|
33 |
|
34 | |
35 |
|
36 |
|
37 | trigger: PropTypes.oneOfType([triggerType, PropTypes.arrayOf(triggerType)]),
|
38 |
|
39 | |
40 |
|
41 |
|
42 | delay: PropTypes.number,
|
43 | |
44 |
|
45 |
|
46 | delayShow: PropTypes.number,
|
47 | |
48 |
|
49 |
|
50 | delayHide: PropTypes.number,
|
51 |
|
52 |
|
53 | |
54 |
|
55 |
|
56 |
|
57 | defaultOverlayShown: PropTypes.bool,
|
58 |
|
59 | |
60 |
|
61 |
|
62 | overlay: PropTypes.node.isRequired,
|
63 |
|
64 | |
65 |
|
66 |
|
67 | onBlur: PropTypes.func,
|
68 | |
69 |
|
70 |
|
71 | onClick: PropTypes.func,
|
72 | |
73 |
|
74 |
|
75 | onFocus: PropTypes.func,
|
76 | |
77 |
|
78 |
|
79 | onMouseOut: PropTypes.func,
|
80 | |
81 |
|
82 |
|
83 | onMouseOver: PropTypes.func,
|
84 |
|
85 |
|
86 | |
87 |
|
88 |
|
89 | target: PropTypes.oneOf([null]),
|
90 | |
91 |
|
92 |
|
93 | onHide: PropTypes.oneOf([null]),
|
94 | |
95 |
|
96 |
|
97 | show: PropTypes.oneOf([null])
|
98 | });
|
99 |
|
100 | var defaultProps = {
|
101 | defaultOverlayShown: false,
|
102 | trigger: ['hover', 'focus']
|
103 | };
|
104 |
|
105 | var OverlayTrigger = function (_React$Component) {
|
106 | _inherits(OverlayTrigger, _React$Component);
|
107 |
|
108 | function OverlayTrigger(props, context) {
|
109 | _classCallCheck(this, OverlayTrigger);
|
110 |
|
111 | var _this = _possibleConstructorReturn(this, _React$Component.call(this, props, context));
|
112 |
|
113 | _this.handleToggle = _this.handleToggle.bind(_this);
|
114 | _this.handleDelayedShow = _this.handleDelayedShow.bind(_this);
|
115 | _this.handleDelayedHide = _this.handleDelayedHide.bind(_this);
|
116 | _this.handleHide = _this.handleHide.bind(_this);
|
117 |
|
118 | _this.handleMouseOver = function (e) {
|
119 | return _this.handleMouseOverOut(_this.handleDelayedShow, e, 'fromElement');
|
120 | };
|
121 | _this.handleMouseOut = function (e) {
|
122 | return _this.handleMouseOverOut(_this.handleDelayedHide, e, 'toElement');
|
123 | };
|
124 |
|
125 | _this._mountNode = null;
|
126 |
|
127 | _this.state = {
|
128 | show: props.defaultOverlayShown
|
129 | };
|
130 | return _this;
|
131 | }
|
132 |
|
133 | OverlayTrigger.prototype.componentDidMount = function componentDidMount() {
|
134 | this._mountNode = document.createElement('div');
|
135 | this.renderOverlay();
|
136 | };
|
137 |
|
138 | OverlayTrigger.prototype.componentDidUpdate = function componentDidUpdate() {
|
139 | this.renderOverlay();
|
140 | };
|
141 |
|
142 | OverlayTrigger.prototype.componentWillUnmount = function componentWillUnmount() {
|
143 | ReactDOM.unmountComponentAtNode(this._mountNode);
|
144 | this._mountNode = null;
|
145 |
|
146 | clearTimeout(this._hoverShowDelay);
|
147 | clearTimeout(this._hoverHideDelay);
|
148 | };
|
149 |
|
150 | OverlayTrigger.prototype.handleDelayedHide = function handleDelayedHide() {
|
151 | var _this2 = this;
|
152 |
|
153 | if (this._hoverShowDelay != null) {
|
154 | clearTimeout(this._hoverShowDelay);
|
155 | this._hoverShowDelay = null;
|
156 | return;
|
157 | }
|
158 |
|
159 | if (!this.state.show || this._hoverHideDelay != null) {
|
160 | return;
|
161 | }
|
162 |
|
163 | var delay = this.props.delayHide != null ? this.props.delayHide : this.props.delay;
|
164 |
|
165 | if (!delay) {
|
166 | this.hide();
|
167 | return;
|
168 | }
|
169 |
|
170 | this._hoverHideDelay = setTimeout(function () {
|
171 | _this2._hoverHideDelay = null;
|
172 | _this2.hide();
|
173 | }, delay);
|
174 | };
|
175 |
|
176 | OverlayTrigger.prototype.handleDelayedShow = function handleDelayedShow() {
|
177 | var _this3 = this;
|
178 |
|
179 | if (this._hoverHideDelay != null) {
|
180 | clearTimeout(this._hoverHideDelay);
|
181 | this._hoverHideDelay = null;
|
182 | return;
|
183 | }
|
184 |
|
185 | if (this.state.show || this._hoverShowDelay != null) {
|
186 | return;
|
187 | }
|
188 |
|
189 | var delay = this.props.delayShow != null ? this.props.delayShow : this.props.delay;
|
190 |
|
191 | if (!delay) {
|
192 | this.show();
|
193 | return;
|
194 | }
|
195 |
|
196 | this._hoverShowDelay = setTimeout(function () {
|
197 | _this3._hoverShowDelay = null;
|
198 | _this3.show();
|
199 | }, delay);
|
200 | };
|
201 |
|
202 | OverlayTrigger.prototype.handleHide = function handleHide() {
|
203 | this.hide();
|
204 | };
|
205 |
|
206 |
|
207 |
|
208 |
|
209 |
|
210 |
|
211 |
|
212 | OverlayTrigger.prototype.handleMouseOverOut = function handleMouseOverOut(handler, e, relatedNative) {
|
213 | var target = e.currentTarget;
|
214 | var related = e.relatedTarget || e.nativeEvent[relatedNative];
|
215 |
|
216 | if ((!related || related !== target) && !contains(target, related)) {
|
217 | handler(e);
|
218 | }
|
219 | };
|
220 |
|
221 | OverlayTrigger.prototype.handleToggle = function handleToggle() {
|
222 | if (this.state.show) {
|
223 | this.hide();
|
224 | } else {
|
225 | this.show();
|
226 | }
|
227 | };
|
228 |
|
229 | OverlayTrigger.prototype.hide = function hide() {
|
230 | this.setState({ show: false });
|
231 | };
|
232 |
|
233 | OverlayTrigger.prototype.makeOverlay = function makeOverlay(overlay, props) {
|
234 | return React.createElement(
|
235 | Overlay,
|
236 | _extends({}, props, {
|
237 | show: this.state.show,
|
238 | onHide: this.handleHide,
|
239 | target: this
|
240 | }),
|
241 | overlay
|
242 | );
|
243 | };
|
244 |
|
245 | OverlayTrigger.prototype.show = function show() {
|
246 | this.setState({ show: true });
|
247 | };
|
248 |
|
249 | OverlayTrigger.prototype.renderOverlay = function renderOverlay() {
|
250 | ReactDOM.unstable_renderSubtreeIntoContainer(this, this._overlay, this._mountNode);
|
251 | };
|
252 |
|
253 | OverlayTrigger.prototype.render = function render() {
|
254 | var _props = this.props,
|
255 | trigger = _props.trigger,
|
256 | overlay = _props.overlay,
|
257 | children = _props.children,
|
258 | onBlur = _props.onBlur,
|
259 | onClick = _props.onClick,
|
260 | onFocus = _props.onFocus,
|
261 | onMouseOut = _props.onMouseOut,
|
262 | onMouseOver = _props.onMouseOver,
|
263 | props = _objectWithoutProperties(_props, ['trigger', 'overlay', 'children', 'onBlur', 'onClick', 'onFocus', 'onMouseOut', 'onMouseOver']);
|
264 |
|
265 | delete props.delay;
|
266 | delete props.delayShow;
|
267 | delete props.delayHide;
|
268 | delete props.defaultOverlayShown;
|
269 |
|
270 | var child = React.Children.only(children);
|
271 | var childProps = child.props;
|
272 | var triggerProps = {};
|
273 |
|
274 | if (this.state.show) {
|
275 | triggerProps['aria-describedby'] = overlay.props.id;
|
276 | }
|
277 |
|
278 |
|
279 |
|
280 |
|
281 | triggerProps.onClick = createChainedFunction(childProps.onClick, onClick);
|
282 |
|
283 | if (isOneOf('click', trigger)) {
|
284 | triggerProps.onClick = createChainedFunction(triggerProps.onClick, this.handleToggle);
|
285 | }
|
286 |
|
287 | if (isOneOf('hover', trigger)) {
|
288 | process.env.NODE_ENV !== 'production' ? warning(!(trigger === 'hover'), '[react-bootstrap] Specifying only the `"hover"` trigger limits the ' + 'visibility of the overlay to just mouse users. Consider also ' + 'including the `"focus"` trigger so that touch and keyboard only ' + 'users can see the overlay as well.') : void 0;
|
289 |
|
290 | triggerProps.onMouseOver = createChainedFunction(childProps.onMouseOver, onMouseOver, this.handleMouseOver);
|
291 | triggerProps.onMouseOut = createChainedFunction(childProps.onMouseOut, onMouseOut, this.handleMouseOut);
|
292 | }
|
293 |
|
294 | if (isOneOf('focus', trigger)) {
|
295 | triggerProps.onFocus = createChainedFunction(childProps.onFocus, onFocus, this.handleDelayedShow);
|
296 | triggerProps.onBlur = createChainedFunction(childProps.onBlur, onBlur, this.handleDelayedHide);
|
297 | }
|
298 |
|
299 | this._overlay = this.makeOverlay(overlay, props);
|
300 |
|
301 | return cloneElement(child, triggerProps);
|
302 | };
|
303 |
|
304 | return OverlayTrigger;
|
305 | }(React.Component);
|
306 |
|
307 | OverlayTrigger.propTypes = propTypes;
|
308 | OverlayTrigger.defaultProps = defaultProps;
|
309 |
|
310 | export default OverlayTrigger; |
\ | No newline at end of file |