1 | import _extends from "@babel/runtime/helpers/esm/extends";
|
2 | import _objectWithoutPropertiesLoose from "@babel/runtime/helpers/esm/objectWithoutPropertiesLoose";
|
3 | import * as React from 'react';
|
4 | import PropTypes from 'prop-types';
|
5 | import PopperJs from 'popper.js';
|
6 | import { chainPropTypes, refType, HTMLElementType } from '@material-ui/utils';
|
7 | import { useTheme } from '@material-ui/styles';
|
8 | import Portal from '../Portal';
|
9 | import createChainedFunction from '../utils/createChainedFunction';
|
10 | import setRef from '../utils/setRef';
|
11 | import useForkRef from '../utils/useForkRef';
|
12 |
|
13 | function flipPlacement(placement, theme) {
|
14 | const direction = theme && theme.direction || 'ltr';
|
15 |
|
16 | if (direction === 'ltr') {
|
17 | return placement;
|
18 | }
|
19 |
|
20 | switch (placement) {
|
21 | case 'bottom-end':
|
22 | return 'bottom-start';
|
23 |
|
24 | case 'bottom-start':
|
25 | return 'bottom-end';
|
26 |
|
27 | case 'top-end':
|
28 | return 'top-start';
|
29 |
|
30 | case 'top-start':
|
31 | return 'top-end';
|
32 |
|
33 | default:
|
34 | return placement;
|
35 | }
|
36 | }
|
37 |
|
38 | function getAnchorEl(anchorEl) {
|
39 | return typeof anchorEl === 'function' ? anchorEl() : anchorEl;
|
40 | }
|
41 |
|
42 | const useEnhancedEffect = typeof window !== 'undefined' ? React.useLayoutEffect : React.useEffect;
|
43 | const defaultPopperOptions = {};
|
44 |
|
45 |
|
46 |
|
47 |
|
48 | const Popper = React.forwardRef(function Popper(props, ref) {
|
49 | const {
|
50 | anchorEl,
|
51 | children,
|
52 | container,
|
53 | disablePortal = false,
|
54 | keepMounted = false,
|
55 | modifiers,
|
56 | open,
|
57 | placement: initialPlacement = 'bottom',
|
58 | popperOptions = defaultPopperOptions,
|
59 | popperRef: popperRefProp,
|
60 | style,
|
61 | transition = false
|
62 | } = props,
|
63 | other = _objectWithoutPropertiesLoose(props, ["anchorEl", "children", "container", "disablePortal", "keepMounted", "modifiers", "open", "placement", "popperOptions", "popperRef", "style", "transition"]);
|
64 |
|
65 | const tooltipRef = React.useRef(null);
|
66 | const ownRef = useForkRef(tooltipRef, ref);
|
67 | const popperRef = React.useRef(null);
|
68 | const handlePopperRef = useForkRef(popperRef, popperRefProp);
|
69 | const handlePopperRefRef = React.useRef(handlePopperRef);
|
70 | useEnhancedEffect(() => {
|
71 | handlePopperRefRef.current = handlePopperRef;
|
72 | }, [handlePopperRef]);
|
73 | React.useImperativeHandle(popperRefProp, () => popperRef.current, []);
|
74 | const [exited, setExited] = React.useState(true);
|
75 | const theme = useTheme();
|
76 | const rtlPlacement = flipPlacement(initialPlacement, theme);
|
77 | |
78 |
|
79 |
|
80 |
|
81 |
|
82 | const [placement, setPlacement] = React.useState(rtlPlacement);
|
83 | React.useEffect(() => {
|
84 | if (popperRef.current) {
|
85 | popperRef.current.update();
|
86 | }
|
87 | });
|
88 | const handleOpen = React.useCallback(() => {
|
89 | if (!tooltipRef.current || !anchorEl || !open) {
|
90 | return;
|
91 | }
|
92 |
|
93 | if (popperRef.current) {
|
94 | popperRef.current.destroy();
|
95 | handlePopperRefRef.current(null);
|
96 | }
|
97 |
|
98 | const handlePopperUpdate = data => {
|
99 | setPlacement(data.placement);
|
100 | };
|
101 |
|
102 | const resolvedAnchorEl = getAnchorEl(anchorEl);
|
103 |
|
104 | if (process.env.NODE_ENV !== 'production') {
|
105 | if (resolvedAnchorEl && resolvedAnchorEl.nodeType === 1) {
|
106 | const box = resolvedAnchorEl.getBoundingClientRect();
|
107 |
|
108 | if (process.env.NODE_ENV !== 'test' && box.top === 0 && box.left === 0 && box.right === 0 && box.bottom === 0) {
|
109 | 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'));
|
110 | }
|
111 | }
|
112 | }
|
113 |
|
114 | const popper = new PopperJs(getAnchorEl(anchorEl), tooltipRef.current, _extends({
|
115 | placement: rtlPlacement
|
116 | }, popperOptions, {
|
117 | modifiers: _extends({}, disablePortal ? {} : {
|
118 |
|
119 | preventOverflow: {
|
120 | boundariesElement: 'window'
|
121 | }
|
122 | }, modifiers, popperOptions.modifiers),
|
123 |
|
124 |
|
125 | onCreate: createChainedFunction(handlePopperUpdate, popperOptions.onCreate),
|
126 | onUpdate: createChainedFunction(handlePopperUpdate, popperOptions.onUpdate)
|
127 | }));
|
128 | handlePopperRefRef.current(popper);
|
129 | }, [anchorEl, disablePortal, modifiers, open, rtlPlacement, popperOptions]);
|
130 | const handleRef = React.useCallback(node => {
|
131 | setRef(ownRef, node);
|
132 | handleOpen();
|
133 | }, [ownRef, handleOpen]);
|
134 |
|
135 | const handleEnter = () => {
|
136 | setExited(false);
|
137 | };
|
138 |
|
139 | const handleClose = () => {
|
140 | if (!popperRef.current) {
|
141 | return;
|
142 | }
|
143 |
|
144 | popperRef.current.destroy();
|
145 | handlePopperRefRef.current(null);
|
146 | };
|
147 |
|
148 | const handleExited = () => {
|
149 | setExited(true);
|
150 | handleClose();
|
151 | };
|
152 |
|
153 | React.useEffect(() => {
|
154 | return () => {
|
155 | handleClose();
|
156 | };
|
157 | }, []);
|
158 | React.useEffect(() => {
|
159 | if (!open && !transition) {
|
160 |
|
161 | handleClose();
|
162 | }
|
163 | }, [open, transition]);
|
164 |
|
165 | if (!keepMounted && !open && (!transition || exited)) {
|
166 | return null;
|
167 | }
|
168 |
|
169 | const childProps = {
|
170 | placement
|
171 | };
|
172 |
|
173 | if (transition) {
|
174 | childProps.TransitionProps = {
|
175 | in: open,
|
176 | onEnter: handleEnter,
|
177 | onExited: handleExited
|
178 | };
|
179 | }
|
180 |
|
181 | return React.createElement(Portal, {
|
182 | disablePortal: disablePortal,
|
183 | container: container
|
184 | }, React.createElement("div", _extends({
|
185 | ref: handleRef,
|
186 | role: "tooltip"
|
187 | }, other, {
|
188 | style: _extends({
|
189 |
|
190 | position: 'fixed',
|
191 |
|
192 | top: 0,
|
193 | left: 0,
|
194 | display: !open && keepMounted && !transition ? 'none' : null
|
195 | }, style)
|
196 | }), typeof children === 'function' ? children(childProps) : children));
|
197 | });
|
198 | process.env.NODE_ENV !== "production" ? Popper.propTypes = {
|
199 |
|
200 |
|
201 |
|
202 |
|
203 |
|
204 | |
205 |
|
206 |
|
207 |
|
208 |
|
209 |
|
210 | anchorEl: chainPropTypes(PropTypes.oneOfType([HTMLElementType, PropTypes.object, PropTypes.func]), props => {
|
211 | if (props.open) {
|
212 | const resolvedAnchorEl = getAnchorEl(props.anchorEl);
|
213 |
|
214 | if (resolvedAnchorEl && resolvedAnchorEl.nodeType === 1) {
|
215 | const box = resolvedAnchorEl.getBoundingClientRect();
|
216 |
|
217 | if (process.env.NODE_ENV !== 'test' && box.top === 0 && box.left === 0 && box.right === 0 && box.bottom === 0) {
|
218 | 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'));
|
219 | }
|
220 | } else if (!resolvedAnchorEl || typeof resolvedAnchorEl.clientWidth !== 'number' || typeof resolvedAnchorEl.clientHeight !== 'number' || typeof resolvedAnchorEl.getBoundingClientRect !== 'function') {
|
221 | 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'));
|
222 | }
|
223 | }
|
224 |
|
225 | return null;
|
226 | }),
|
227 |
|
228 | |
229 |
|
230 |
|
231 | children: PropTypes
|
232 |
|
233 | .oneOfType([PropTypes.node, PropTypes.func]).isRequired,
|
234 |
|
235 | |
236 |
|
237 |
|
238 |
|
239 |
|
240 |
|
241 |
|
242 | container: PropTypes
|
243 |
|
244 | .oneOfType([HTMLElementType, PropTypes.instanceOf(React.Component), PropTypes.func]),
|
245 |
|
246 | |
247 |
|
248 |
|
249 |
|
250 | disablePortal: PropTypes.bool,
|
251 |
|
252 | |
253 |
|
254 |
|
255 |
|
256 |
|
257 | keepMounted: PropTypes.bool,
|
258 |
|
259 | |
260 |
|
261 |
|
262 |
|
263 |
|
264 |
|
265 |
|
266 |
|
267 |
|
268 | modifiers: PropTypes.object,
|
269 |
|
270 | |
271 |
|
272 |
|
273 | open: PropTypes.bool.isRequired,
|
274 |
|
275 | |
276 |
|
277 |
|
278 | placement: PropTypes.oneOf(['bottom-end', 'bottom-start', 'bottom', 'left-end', 'left-start', 'left', 'right-end', 'right-start', 'right', 'top-end', 'top-start', 'top']),
|
279 |
|
280 | |
281 |
|
282 |
|
283 | popperOptions: PropTypes.object,
|
284 |
|
285 | |
286 |
|
287 |
|
288 | popperRef: refType,
|
289 |
|
290 | |
291 |
|
292 |
|
293 | style: PropTypes.object,
|
294 |
|
295 | |
296 |
|
297 |
|
298 | transition: PropTypes.bool
|
299 | } : void 0;
|
300 | export default Popper; |
\ | No newline at end of file |