1 | 'use client';
|
2 |
|
3 | import * as React from 'react';
|
4 | import { chainPropTypes, HTMLElementType, refType, unstable_ownerDocument as ownerDocument, unstable_useEnhancedEffect as useEnhancedEffect, unstable_useForkRef as useForkRef } from '@mui/utils';
|
5 | import { createPopper } from '@popperjs/core';
|
6 | import PropTypes from 'prop-types';
|
7 | import composeClasses from '@mui/utils/composeClasses';
|
8 | import useSlotProps from '@mui/utils/useSlotProps';
|
9 | import Portal from "../Portal/index.js";
|
10 | import { getPopperUtilityClass } from "./popperClasses.js";
|
11 | import { jsx as _jsx } from "react/jsx-runtime";
|
12 | function flipPlacement(placement, direction) {
|
13 | if (direction === 'ltr') {
|
14 | return placement;
|
15 | }
|
16 | switch (placement) {
|
17 | case 'bottom-end':
|
18 | return 'bottom-start';
|
19 | case 'bottom-start':
|
20 | return 'bottom-end';
|
21 | case 'top-end':
|
22 | return 'top-start';
|
23 | case 'top-start':
|
24 | return 'top-end';
|
25 | default:
|
26 | return placement;
|
27 | }
|
28 | }
|
29 | function resolveAnchorEl(anchorEl) {
|
30 | return typeof anchorEl === 'function' ? anchorEl() : anchorEl;
|
31 | }
|
32 | function isHTMLElement(element) {
|
33 | return element.nodeType !== undefined;
|
34 | }
|
35 | function isVirtualElement(element) {
|
36 | return !isHTMLElement(element);
|
37 | }
|
38 | const useUtilityClasses = ownerState => {
|
39 | const {
|
40 | classes
|
41 | } = ownerState;
|
42 | const slots = {
|
43 | root: ['root']
|
44 | };
|
45 | return composeClasses(slots, getPopperUtilityClass, classes);
|
46 | };
|
47 | const defaultPopperOptions = {};
|
48 | const PopperTooltip = React.forwardRef(function PopperTooltip(props, forwardedRef) {
|
49 | const {
|
50 | anchorEl,
|
51 | children,
|
52 | direction,
|
53 | disablePortal,
|
54 | modifiers,
|
55 | open,
|
56 | placement: initialPlacement,
|
57 | popperOptions,
|
58 | popperRef: popperRefProp,
|
59 | slotProps = {},
|
60 | slots = {},
|
61 | TransitionProps,
|
62 |
|
63 | ownerState: ownerStateProp,
|
64 |
|
65 | ...other
|
66 | } = props;
|
67 | const tooltipRef = React.useRef(null);
|
68 | const ownRef = useForkRef(tooltipRef, forwardedRef);
|
69 | const popperRef = React.useRef(null);
|
70 | const handlePopperRef = useForkRef(popperRef, popperRefProp);
|
71 | const handlePopperRefRef = React.useRef(handlePopperRef);
|
72 | useEnhancedEffect(() => {
|
73 | handlePopperRefRef.current = handlePopperRef;
|
74 | }, [handlePopperRef]);
|
75 | React.useImperativeHandle(popperRefProp, () => popperRef.current, []);
|
76 | const rtlPlacement = flipPlacement(initialPlacement, direction);
|
77 | |
78 |
|
79 |
|
80 |
|
81 | const [placement, setPlacement] = React.useState(rtlPlacement);
|
82 | const [resolvedAnchorElement, setResolvedAnchorElement] = React.useState(resolveAnchorEl(anchorEl));
|
83 | React.useEffect(() => {
|
84 | if (popperRef.current) {
|
85 | popperRef.current.forceUpdate();
|
86 | }
|
87 | });
|
88 | React.useEffect(() => {
|
89 | if (anchorEl) {
|
90 | setResolvedAnchorElement(resolveAnchorEl(anchorEl));
|
91 | }
|
92 | }, [anchorEl]);
|
93 | useEnhancedEffect(() => {
|
94 | if (!resolvedAnchorElement || !open) {
|
95 | return undefined;
|
96 | }
|
97 | const handlePopperUpdate = data => {
|
98 | setPlacement(data.placement);
|
99 | };
|
100 | if (process.env.NODE_ENV !== 'production') {
|
101 | if (resolvedAnchorElement && isHTMLElement(resolvedAnchorElement) && resolvedAnchorElement.nodeType === 1) {
|
102 | const box = resolvedAnchorElement.getBoundingClientRect();
|
103 | if (process.env.NODE_ENV !== 'test' && box.top === 0 && box.left === 0 && box.right === 0 && box.bottom === 0) {
|
104 | console.warn(['MUI: 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'));
|
105 | }
|
106 | }
|
107 | }
|
108 | let popperModifiers = [{
|
109 | name: 'preventOverflow',
|
110 | options: {
|
111 | altBoundary: disablePortal
|
112 | }
|
113 | }, {
|
114 | name: 'flip',
|
115 | options: {
|
116 | altBoundary: disablePortal
|
117 | }
|
118 | }, {
|
119 | name: 'onUpdate',
|
120 | enabled: true,
|
121 | phase: 'afterWrite',
|
122 | fn: ({
|
123 | state
|
124 | }) => {
|
125 | handlePopperUpdate(state);
|
126 | }
|
127 | }];
|
128 | if (modifiers != null) {
|
129 | popperModifiers = popperModifiers.concat(modifiers);
|
130 | }
|
131 | if (popperOptions && popperOptions.modifiers != null) {
|
132 | popperModifiers = popperModifiers.concat(popperOptions.modifiers);
|
133 | }
|
134 | const popper = createPopper(resolvedAnchorElement, tooltipRef.current, {
|
135 | placement: rtlPlacement,
|
136 | ...popperOptions,
|
137 | modifiers: popperModifiers
|
138 | });
|
139 | handlePopperRefRef.current(popper);
|
140 | return () => {
|
141 | popper.destroy();
|
142 | handlePopperRefRef.current(null);
|
143 | };
|
144 | }, [resolvedAnchorElement, disablePortal, modifiers, open, popperOptions, rtlPlacement]);
|
145 | const childProps = {
|
146 | placement: placement
|
147 | };
|
148 | if (TransitionProps !== null) {
|
149 | childProps.TransitionProps = TransitionProps;
|
150 | }
|
151 | const classes = useUtilityClasses(props);
|
152 | const Root = slots.root ?? 'div';
|
153 | const rootProps = useSlotProps({
|
154 | elementType: Root,
|
155 | externalSlotProps: slotProps.root,
|
156 | externalForwardedProps: other,
|
157 | additionalProps: {
|
158 | role: 'tooltip',
|
159 | ref: ownRef
|
160 | },
|
161 | ownerState: props,
|
162 | className: classes.root
|
163 | });
|
164 | return _jsx(Root, {
|
165 | ...rootProps,
|
166 | children: typeof children === 'function' ? children(childProps) : children
|
167 | });
|
168 | });
|
169 |
|
170 |
|
171 |
|
172 |
|
173 | const Popper = React.forwardRef(function Popper(props, forwardedRef) {
|
174 | const {
|
175 | anchorEl,
|
176 | children,
|
177 | container: containerProp,
|
178 | direction = 'ltr',
|
179 | disablePortal = false,
|
180 | keepMounted = false,
|
181 | modifiers,
|
182 | open,
|
183 | placement = 'bottom',
|
184 | popperOptions = defaultPopperOptions,
|
185 | popperRef,
|
186 | style,
|
187 | transition = false,
|
188 | slotProps = {},
|
189 | slots = {},
|
190 | ...other
|
191 | } = props;
|
192 | const [exited, setExited] = React.useState(true);
|
193 | const handleEnter = () => {
|
194 | setExited(false);
|
195 | };
|
196 | const handleExited = () => {
|
197 | setExited(true);
|
198 | };
|
199 | if (!keepMounted && !open && (!transition || exited)) {
|
200 | return null;
|
201 | }
|
202 |
|
203 |
|
204 |
|
205 |
|
206 | let container;
|
207 | if (containerProp) {
|
208 | container = containerProp;
|
209 | } else if (anchorEl) {
|
210 | const resolvedAnchorEl = resolveAnchorEl(anchorEl);
|
211 | container = resolvedAnchorEl && isHTMLElement(resolvedAnchorEl) ? ownerDocument(resolvedAnchorEl).body : ownerDocument(null).body;
|
212 | }
|
213 | const display = !open && keepMounted && (!transition || exited) ? 'none' : undefined;
|
214 | const transitionProps = transition ? {
|
215 | in: open,
|
216 | onEnter: handleEnter,
|
217 | onExited: handleExited
|
218 | } : undefined;
|
219 | return _jsx(Portal, {
|
220 | disablePortal: disablePortal,
|
221 | container: container,
|
222 | children: _jsx(PopperTooltip, {
|
223 | anchorEl: anchorEl,
|
224 | direction: direction,
|
225 | disablePortal: disablePortal,
|
226 | modifiers: modifiers,
|
227 | ref: forwardedRef,
|
228 | open: transition ? !exited : open,
|
229 | placement: placement,
|
230 | popperOptions: popperOptions,
|
231 | popperRef: popperRef,
|
232 | slotProps: slotProps,
|
233 | slots: slots,
|
234 | ...other,
|
235 | style: {
|
236 |
|
237 | position: 'fixed',
|
238 |
|
239 | top: 0,
|
240 | left: 0,
|
241 | display,
|
242 | ...style
|
243 | },
|
244 | TransitionProps: transitionProps,
|
245 | children: children
|
246 | })
|
247 | });
|
248 | });
|
249 | process.env.NODE_ENV !== "production" ? Popper.propTypes = {
|
250 |
|
251 |
|
252 |
|
253 |
|
254 | |
255 |
|
256 |
|
257 |
|
258 |
|
259 |
|
260 | anchorEl: chainPropTypes(PropTypes.oneOfType([HTMLElementType, PropTypes.object, PropTypes.func]), props => {
|
261 | if (props.open) {
|
262 | const resolvedAnchorEl = resolveAnchorEl(props.anchorEl);
|
263 | if (resolvedAnchorEl && isHTMLElement(resolvedAnchorEl) && resolvedAnchorEl.nodeType === 1) {
|
264 | const box = resolvedAnchorEl.getBoundingClientRect();
|
265 | if (process.env.NODE_ENV !== 'test' && box.top === 0 && box.left === 0 && box.right === 0 && box.bottom === 0) {
|
266 | return new Error(['MUI: 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'));
|
267 | }
|
268 | } else if (!resolvedAnchorEl || typeof resolvedAnchorEl.getBoundingClientRect !== 'function' || isVirtualElement(resolvedAnchorEl) && resolvedAnchorEl.contextElement != null && resolvedAnchorEl.contextElement.nodeType !== 1) {
|
269 | return new Error(['MUI: The `anchorEl` prop provided to the component is invalid.', 'It should be an HTML element instance or a virtualElement ', '(https://popper.js.org/docs/v2/virtual-elements/).'].join('\n'));
|
270 | }
|
271 | }
|
272 | return null;
|
273 | }),
|
274 | |
275 |
|
276 |
|
277 | children: PropTypes .oneOfType([PropTypes.node, PropTypes.func]),
|
278 | |
279 |
|
280 |
|
281 |
|
282 |
|
283 |
|
284 |
|
285 |
|
286 |
|
287 |
|
288 | container: PropTypes .oneOfType([HTMLElementType, PropTypes.func]),
|
289 | |
290 |
|
291 |
|
292 |
|
293 | direction: PropTypes.oneOf(['ltr', 'rtl']),
|
294 | |
295 |
|
296 |
|
297 |
|
298 | disablePortal: PropTypes.bool,
|
299 | |
300 |
|
301 |
|
302 |
|
303 |
|
304 |
|
305 | keepMounted: PropTypes.bool,
|
306 | |
307 |
|
308 |
|
309 |
|
310 |
|
311 |
|
312 |
|
313 |
|
314 |
|
315 | modifiers: PropTypes.arrayOf(PropTypes.shape({
|
316 | data: PropTypes.object,
|
317 | effect: PropTypes.func,
|
318 | enabled: PropTypes.bool,
|
319 | fn: PropTypes.func,
|
320 | name: PropTypes.any,
|
321 | options: PropTypes.object,
|
322 | phase: PropTypes.oneOf(['afterMain', 'afterRead', 'afterWrite', 'beforeMain', 'beforeRead', 'beforeWrite', 'main', 'read', 'write']),
|
323 | requires: PropTypes.arrayOf(PropTypes.string),
|
324 | requiresIfExists: PropTypes.arrayOf(PropTypes.string)
|
325 | })),
|
326 | |
327 |
|
328 |
|
329 | open: PropTypes.bool.isRequired,
|
330 | |
331 |
|
332 |
|
333 |
|
334 | placement: PropTypes.oneOf(['auto-end', 'auto-start', 'auto', 'bottom-end', 'bottom-start', 'bottom', 'left-end', 'left-start', 'left', 'right-end', 'right-start', 'right', 'top-end', 'top-start', 'top']),
|
335 | |
336 |
|
337 |
|
338 |
|
339 | popperOptions: PropTypes.shape({
|
340 | modifiers: PropTypes.array,
|
341 | onFirstUpdate: PropTypes.func,
|
342 | placement: PropTypes.oneOf(['auto-end', 'auto-start', 'auto', 'bottom-end', 'bottom-start', 'bottom', 'left-end', 'left-start', 'left', 'right-end', 'right-start', 'right', 'top-end', 'top-start', 'top']),
|
343 | strategy: PropTypes.oneOf(['absolute', 'fixed'])
|
344 | }),
|
345 | |
346 |
|
347 |
|
348 | popperRef: refType,
|
349 | |
350 |
|
351 |
|
352 |
|
353 | slotProps: PropTypes.shape({
|
354 | root: PropTypes.oneOfType([PropTypes.func, PropTypes.object])
|
355 | }),
|
356 | |
357 |
|
358 |
|
359 |
|
360 |
|
361 | slots: PropTypes.shape({
|
362 | root: PropTypes.elementType
|
363 | }),
|
364 | |
365 |
|
366 |
|
367 |
|
368 | transition: PropTypes.bool
|
369 | } : void 0;
|
370 | export default Popper; |
\ | No newline at end of file |