UNPKG

11.8 kBJavaScriptView Raw
1"use strict";
2
3var _interopRequireWildcard = require("@babel/runtime/helpers/interopRequireWildcard");
4
5var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
6
7Object.defineProperty(exports, "__esModule", {
8 value: true
9});
10exports.default = void 0;
11
12var _extends2 = _interopRequireDefault(require("@babel/runtime/helpers/extends"));
13
14var _objectWithoutProperties2 = _interopRequireDefault(require("@babel/runtime/helpers/objectWithoutProperties"));
15
16var React = _interopRequireWildcard(require("react"));
17
18var _propTypes = _interopRequireDefault(require("prop-types"));
19
20var _popper = _interopRequireDefault(require("popper.js"));
21
22var _utils = require("@material-ui/utils");
23
24var _styles = require("@material-ui/styles");
25
26var _Portal = _interopRequireDefault(require("../Portal"));
27
28var _createChainedFunction = _interopRequireDefault(require("../utils/createChainedFunction"));
29
30var _setRef = _interopRequireDefault(require("../utils/setRef"));
31
32var _useForkRef = _interopRequireDefault(require("../utils/useForkRef"));
33
34function flipPlacement(placement, theme) {
35 var direction = theme && theme.direction || 'ltr';
36
37 if (direction === 'ltr') {
38 return placement;
39 }
40
41 switch (placement) {
42 case 'bottom-end':
43 return 'bottom-start';
44
45 case 'bottom-start':
46 return 'bottom-end';
47
48 case 'top-end':
49 return 'top-start';
50
51 case 'top-start':
52 return 'top-end';
53
54 default:
55 return placement;
56 }
57}
58
59function getAnchorEl(anchorEl) {
60 return typeof anchorEl === 'function' ? anchorEl() : anchorEl;
61}
62
63var useEnhancedEffect = typeof window !== 'undefined' ? React.useLayoutEffect : React.useEffect;
64var defaultPopperOptions = {};
65/**
66 * Poppers rely on the 3rd party library [Popper.js](https://popper.js.org/docs/v1/) for positioning.
67 */
68
69var Popper = /*#__PURE__*/React.forwardRef(function Popper(props, ref) {
70 var anchorEl = props.anchorEl,
71 children = props.children,
72 container = props.container,
73 _props$disablePortal = props.disablePortal,
74 disablePortal = _props$disablePortal === void 0 ? false : _props$disablePortal,
75 _props$keepMounted = props.keepMounted,
76 keepMounted = _props$keepMounted === void 0 ? false : _props$keepMounted,
77 modifiers = props.modifiers,
78 open = props.open,
79 _props$placement = props.placement,
80 initialPlacement = _props$placement === void 0 ? 'bottom' : _props$placement,
81 _props$popperOptions = props.popperOptions,
82 popperOptions = _props$popperOptions === void 0 ? defaultPopperOptions : _props$popperOptions,
83 popperRefProp = props.popperRef,
84 style = props.style,
85 _props$transition = props.transition,
86 transition = _props$transition === void 0 ? false : _props$transition,
87 other = (0, _objectWithoutProperties2.default)(props, ["anchorEl", "children", "container", "disablePortal", "keepMounted", "modifiers", "open", "placement", "popperOptions", "popperRef", "style", "transition"]);
88 var tooltipRef = React.useRef(null);
89 var ownRef = (0, _useForkRef.default)(tooltipRef, ref);
90 var popperRef = React.useRef(null);
91 var handlePopperRef = (0, _useForkRef.default)(popperRef, popperRefProp);
92 var handlePopperRefRef = React.useRef(handlePopperRef);
93 useEnhancedEffect(function () {
94 handlePopperRefRef.current = handlePopperRef;
95 }, [handlePopperRef]);
96 React.useImperativeHandle(popperRefProp, function () {
97 return popperRef.current;
98 }, []);
99
100 var _React$useState = React.useState(true),
101 exited = _React$useState[0],
102 setExited = _React$useState[1];
103
104 var theme = (0, _styles.useTheme)();
105 var rtlPlacement = flipPlacement(initialPlacement, theme);
106 /**
107 * placement initialized from prop but can change during lifetime if modifiers.flip.
108 * modifiers.flip is essentially a flip for controlled/uncontrolled behavior
109 */
110
111 var _React$useState2 = React.useState(rtlPlacement),
112 placement = _React$useState2[0],
113 setPlacement = _React$useState2[1];
114
115 React.useEffect(function () {
116 if (popperRef.current) {
117 popperRef.current.update();
118 }
119 });
120 var handleOpen = React.useCallback(function () {
121 if (!tooltipRef.current || !anchorEl || !open) {
122 return;
123 }
124
125 if (popperRef.current) {
126 popperRef.current.destroy();
127 handlePopperRefRef.current(null);
128 }
129
130 var handlePopperUpdate = function handlePopperUpdate(data) {
131 setPlacement(data.placement);
132 };
133
134 var resolvedAnchorEl = getAnchorEl(anchorEl);
135
136 if (process.env.NODE_ENV !== 'production') {
137 if (resolvedAnchorEl && resolvedAnchorEl.nodeType === 1) {
138 var box = resolvedAnchorEl.getBoundingClientRect();
139
140 if (process.env.NODE_ENV !== 'test' && box.top === 0 && box.left === 0 && box.right === 0 && box.bottom === 0) {
141 console.warn(['Material-UI: The `anchorEl` prop provided to the component is invalid.', 'The anchor element should be part of the document layout.', "Make sure the element is present in the document or that it's not display none."].join('\n'));
142 }
143 }
144 }
145
146 var popper = new _popper.default(getAnchorEl(anchorEl), tooltipRef.current, (0, _extends2.default)({
147 placement: rtlPlacement
148 }, popperOptions, {
149 modifiers: (0, _extends2.default)({}, disablePortal ? {} : {
150 // It's using scrollParent by default, we can use the viewport when using a portal.
151 preventOverflow: {
152 boundariesElement: 'window'
153 }
154 }, modifiers, popperOptions.modifiers),
155 // We could have been using a custom modifier like react-popper is doing.
156 // But it seems this is the best public API for this use case.
157 onCreate: (0, _createChainedFunction.default)(handlePopperUpdate, popperOptions.onCreate),
158 onUpdate: (0, _createChainedFunction.default)(handlePopperUpdate, popperOptions.onUpdate)
159 }));
160 handlePopperRefRef.current(popper);
161 }, [anchorEl, disablePortal, modifiers, open, rtlPlacement, popperOptions]);
162 var handleRef = React.useCallback(function (node) {
163 (0, _setRef.default)(ownRef, node);
164 handleOpen();
165 }, [ownRef, handleOpen]);
166
167 var handleEnter = function handleEnter() {
168 setExited(false);
169 };
170
171 var handleClose = function handleClose() {
172 if (!popperRef.current) {
173 return;
174 }
175
176 popperRef.current.destroy();
177 handlePopperRefRef.current(null);
178 };
179
180 var handleExited = function handleExited() {
181 setExited(true);
182 handleClose();
183 };
184
185 React.useEffect(function () {
186 return function () {
187 handleClose();
188 };
189 }, []);
190 React.useEffect(function () {
191 if (!open && !transition) {
192 // Otherwise handleExited will call this.
193 handleClose();
194 }
195 }, [open, transition]);
196
197 if (!keepMounted && !open && (!transition || exited)) {
198 return null;
199 }
200
201 var childProps = {
202 placement: placement
203 };
204
205 if (transition) {
206 childProps.TransitionProps = {
207 in: open,
208 onEnter: handleEnter,
209 onExited: handleExited
210 };
211 }
212
213 return /*#__PURE__*/React.createElement(_Portal.default, {
214 disablePortal: disablePortal,
215 container: container
216 }, /*#__PURE__*/React.createElement("div", (0, _extends2.default)({
217 ref: handleRef,
218 role: "tooltip"
219 }, other, {
220 style: (0, _extends2.default)({
221 // Prevents scroll issue, waiting for Popper.js to add this style once initiated.
222 position: 'fixed',
223 // Fix Popper.js display issue
224 top: 0,
225 left: 0,
226 display: !open && keepMounted && !transition ? 'none' : null
227 }, style)
228 }), typeof children === 'function' ? children(childProps) : children));
229});
230process.env.NODE_ENV !== "production" ? Popper.propTypes = {
231 // ----------------------------- Warning --------------------------------
232 // | These PropTypes are generated from the TypeScript type definitions |
233 // | To update them edit the d.ts file and run "yarn proptypes" |
234 // ----------------------------------------------------------------------
235
236 /**
237 * A HTML element, [referenceObject](https://popper.js.org/docs/v1/#referenceObject),
238 * or a function that returns either.
239 * It's used to set the position of the popper.
240 * The return value will passed as the reference object of the Popper instance.
241 */
242 anchorEl: (0, _utils.chainPropTypes)(_propTypes.default.oneOfType([_utils.HTMLElementType, _propTypes.default.object, _propTypes.default.func]), function (props) {
243 if (props.open) {
244 var resolvedAnchorEl = getAnchorEl(props.anchorEl);
245
246 if (resolvedAnchorEl && resolvedAnchorEl.nodeType === 1) {
247 var box = resolvedAnchorEl.getBoundingClientRect();
248
249 if (process.env.NODE_ENV !== 'test' && box.top === 0 && box.left === 0 && box.right === 0 && box.bottom === 0) {
250 return new Error(['Material-UI: The `anchorEl` prop provided to the component is invalid.', 'The anchor element should be part of the document layout.', "Make sure the element is present in the document or that it's not display none."].join('\n'));
251 }
252 } else if (!resolvedAnchorEl || typeof resolvedAnchorEl.clientWidth !== 'number' || typeof resolvedAnchorEl.clientHeight !== 'number' || typeof resolvedAnchorEl.getBoundingClientRect !== 'function') {
253 return new Error(['Material-UI: The `anchorEl` prop provided to the component is invalid.', 'It should be an HTML element instance or a referenceObject ', '(https://popper.js.org/docs/v1/#referenceObject).'].join('\n'));
254 }
255 }
256
257 return null;
258 }),
259
260 /**
261 * Popper render function or node.
262 */
263 children: _propTypes.default
264 /* @typescript-to-proptypes-ignore */
265 .oneOfType([_propTypes.default.node, _propTypes.default.func]).isRequired,
266
267 /**
268 * A HTML element, component instance, or function that returns either.
269 * The `container` will have the portal children appended to it.
270 *
271 * By default, it uses the body of the top-level document object,
272 * so it's simply `document.body` most of the time.
273 */
274 container: _propTypes.default
275 /* @typescript-to-proptypes-ignore */
276 .oneOfType([_utils.HTMLElementType, _propTypes.default.instanceOf(React.Component), _propTypes.default.func]),
277
278 /**
279 * Disable the portal behavior.
280 * The children stay within it's parent DOM hierarchy.
281 */
282 disablePortal: _propTypes.default.bool,
283
284 /**
285 * Always keep the children in the DOM.
286 * This prop can be useful in SEO situation or
287 * when you want to maximize the responsiveness of the Popper.
288 */
289 keepMounted: _propTypes.default.bool,
290
291 /**
292 * Popper.js is based on a "plugin-like" architecture,
293 * most of its features are fully encapsulated "modifiers".
294 *
295 * A modifier is a function that is called each time Popper.js needs to
296 * compute the position of the popper.
297 * For this reason, modifiers should be very performant to avoid bottlenecks.
298 * To learn how to create a modifier, [read the modifiers documentation](https://popper.js.org/docs/v1/#modifiers).
299 */
300 modifiers: _propTypes.default.object,
301
302 /**
303 * If `true`, the popper is visible.
304 */
305 open: _propTypes.default.bool.isRequired,
306
307 /**
308 * Popper placement.
309 */
310 placement: _propTypes.default.oneOf(['bottom-end', 'bottom-start', 'bottom', 'left-end', 'left-start', 'left', 'right-end', 'right-start', 'right', 'top-end', 'top-start', 'top']),
311
312 /**
313 * Options provided to the [`popper.js`](https://popper.js.org/docs/v1/) instance.
314 */
315 popperOptions: _propTypes.default.object,
316
317 /**
318 * A ref that points to the used popper instance.
319 */
320 popperRef: _utils.refType,
321
322 /**
323 * @ignore
324 */
325 style: _propTypes.default.object,
326
327 /**
328 * Help supporting a react-transition-group/Transition component.
329 */
330 transition: _propTypes.default.bool
331} : void 0;
332var _default = Popper;
333exports.default = _default;
\No newline at end of file