UNPKG

7.97 kBJavaScriptView Raw
1'use client';
2
3import _extends from "@babel/runtime/helpers/esm/extends";
4import _objectWithoutPropertiesLoose from "@babel/runtime/helpers/esm/objectWithoutPropertiesLoose";
5const _excluded = ["anchor", "children", "container", "disablePortal", "keepMounted", "middleware", "offset", "open", "placement", "slotProps", "slots", "strategy"];
6import * as React from 'react';
7import PropTypes from 'prop-types';
8import { autoUpdate, flip, offset, shift, useFloating } from '@floating-ui/react-dom';
9import { HTMLElementType, unstable_useEnhancedEffect as useEnhancedEffect, unstable_useForkRef as useForkRef } from '@mui/utils';
10import { unstable_composeClasses as composeClasses } from '../composeClasses';
11import { Portal } from '../Portal';
12import { useSlotProps } from '../utils';
13import { useClassNamesOverride } from '../utils/ClassNameConfigurator';
14import { getPopupUtilityClass } from './popupClasses';
15import { useTransitionTrigger, TransitionContext } from '../useTransition';
16import { PopupContext } from './PopupContext';
17import { jsx as _jsx } from "react/jsx-runtime";
18function useUtilityClasses(ownerState) {
19 const {
20 open
21 } = ownerState;
22 const slots = {
23 root: ['root', open && 'open']
24 };
25 return composeClasses(slots, useClassNamesOverride(getPopupUtilityClass));
26}
27function resolveAnchor(anchor) {
28 return typeof anchor === 'function' ? anchor() : anchor;
29}
30
31/**
32 *
33 * Demos:
34 *
35 * - [Popup](https://mui.com/base-ui/react-popup/)
36 *
37 * API:
38 *
39 * - [Popup API](https://mui.com/base-ui/react-popup/components-api/#popup)
40 */
41const Popup = /*#__PURE__*/React.forwardRef(function Popup(props, forwardedRef) {
42 const {
43 anchor: anchorProp,
44 children,
45 container,
46 disablePortal = false,
47 keepMounted = false,
48 middleware,
49 offset: offsetProp = 0,
50 open = false,
51 placement = 'bottom',
52 slotProps = {},
53 slots = {},
54 strategy = 'absolute'
55 } = props,
56 other = _objectWithoutPropertiesLoose(props, _excluded);
57 const {
58 refs,
59 elements,
60 floatingStyles,
61 update,
62 placement: finalPlacement
63 } = useFloating({
64 elements: {
65 reference: resolveAnchor(anchorProp)
66 },
67 open,
68 middleware: middleware ?? [offset(offsetProp ?? 0), flip(), shift()],
69 placement,
70 strategy,
71 whileElementsMounted: !keepMounted ? autoUpdate : undefined
72 });
73 const handleRef = useForkRef(refs.setFloating, forwardedRef);
74 useEnhancedEffect(() => {
75 if (keepMounted && open && elements.reference && elements.floating) {
76 const cleanup = autoUpdate(elements.reference, elements.floating, update);
77 return cleanup;
78 }
79 return undefined;
80 }, [keepMounted, open, elements, update]);
81 const ownerState = _extends({}, props, {
82 disablePortal,
83 keepMounted,
84 offset,
85 open,
86 placement,
87 finalPlacement,
88 strategy
89 });
90 const {
91 contextValue,
92 hasExited: hasTransitionExited
93 } = useTransitionTrigger(open);
94 const visibility = keepMounted && hasTransitionExited ? 'hidden' : undefined;
95 const classes = useUtilityClasses(ownerState);
96 const Root = slots?.root ?? 'div';
97 const rootProps = useSlotProps({
98 elementType: Root,
99 externalSlotProps: slotProps.root,
100 externalForwardedProps: other,
101 ownerState,
102 className: classes.root,
103 additionalProps: {
104 ref: handleRef,
105 role: 'tooltip',
106 style: _extends({}, floatingStyles, {
107 visibility
108 })
109 }
110 });
111 const popupContextValue = React.useMemo(() => ({
112 placement: finalPlacement
113 }), [finalPlacement]);
114 const shouldRender = keepMounted || !hasTransitionExited;
115 if (!shouldRender) {
116 return null;
117 }
118 return /*#__PURE__*/_jsx(Portal, {
119 disablePortal: disablePortal,
120 container: container,
121 children: /*#__PURE__*/_jsx(PopupContext.Provider, {
122 value: popupContextValue,
123 children: /*#__PURE__*/_jsx(TransitionContext.Provider, {
124 value: contextValue,
125 children: /*#__PURE__*/_jsx(Root, _extends({}, rootProps, {
126 children: children
127 }))
128 })
129 })
130 });
131});
132process.env.NODE_ENV !== "production" ? Popup.propTypes /* remove-proptypes */ = {
133 // ┌────────────────────────────── Warning ──────────────────────────────┐
134 // │ These PropTypes are generated from the TypeScript type definitions. │
135 // │ To update them, edit the TypeScript types and run `pnpm proptypes`. │
136 // └─────────────────────────────────────────────────────────────────────┘
137 /**
138 * An HTML element, [virtual element](https://floating-ui.com/docs/virtual-elements),
139 * or a function that returns either.
140 * It's used to set the position of the popup.
141 */
142 anchor: PropTypes /* @typescript-to-proptypes-ignore */.oneOfType([HTMLElementType, PropTypes.object, PropTypes.func]),
143 /**
144 * @ignore
145 */
146 children: PropTypes /* @typescript-to-proptypes-ignore */.oneOfType([PropTypes.node, PropTypes.func]),
147 /**
148 * An HTML element or function that returns one. The container will have the portal children appended to it.
149 * By default, it uses the body of the top-level document object, so it's `document.body` in these cases.
150 */
151 container: PropTypes /* @typescript-to-proptypes-ignore */.oneOfType([HTMLElementType, PropTypes.func]),
152 /**
153 * If `true`, the popup will be rendered where it is defined, without the use of portals.
154 * @default false
155 */
156 disablePortal: PropTypes.bool,
157 /**
158 * If `true`, the popup will exist in the DOM even if it's closed.
159 * Its visibility will be controlled by the `visibility` CSS property.
160 *
161 * Otherwise, a closed popup will be removed from the DOM.
162 *
163 * @default false
164 */
165 keepMounted: PropTypes.bool,
166 /**
167 * Collection of Floating UI middleware to use when positioning the popup.
168 * If not provided, the [`offset`](https://floating-ui.com/docs/offset)
169 * and [`flip`](https://floating-ui.com/docs/flip) functions will be used.
170 *
171 * @see https://floating-ui.com/docs/computePosition#middleware
172 */
173 middleware: PropTypes.arrayOf(PropTypes.oneOfType([PropTypes.oneOf([false]), PropTypes.shape({
174 fn: PropTypes.func.isRequired,
175 name: PropTypes.string.isRequired,
176 options: PropTypes.any
177 })])),
178 /**
179 * Distance between a popup and the trigger element.
180 * This prop is ignored when custom `middleware` is provided.
181 *
182 * @default 0
183 * @see https://floating-ui.com/docs/offset
184 */
185 offset: PropTypes.oneOfType([PropTypes.func, PropTypes.number, PropTypes.shape({
186 alignmentAxis: PropTypes.number,
187 crossAxis: PropTypes.number,
188 mainAxis: PropTypes.number
189 })]),
190 /**
191 * If `true`, the popup is visible.
192 *
193 * @default false
194 */
195 open: PropTypes.bool,
196 /**
197 * Determines where to place the popup relative to the trigger element.
198 *
199 * @default 'bottom'
200 * @see https://floating-ui.com/docs/computePosition#placement
201 */
202 placement: PropTypes.oneOf(['bottom-end', 'bottom-start', 'bottom', 'left-end', 'left-start', 'left', 'right-end', 'right-start', 'right', 'top-end', 'top-start', 'top']),
203 /**
204 * The props used for each slot inside the Popup.
205 *
206 * @default {}
207 */
208 slotProps: PropTypes.shape({
209 root: PropTypes.oneOfType([PropTypes.func, PropTypes.object])
210 }),
211 /**
212 * The components used for each slot inside the Popup.
213 * Either a string to use a HTML element or a component.
214 *
215 * @default {}
216 */
217 slots: PropTypes.shape({
218 root: PropTypes.elementType
219 }),
220 /**
221 * The type of CSS position property to use (absolute or fixed).
222 *
223 * @default 'absolute'
224 * @see https://floating-ui.com/docs/computePosition#strategy
225 */
226 strategy: PropTypes.oneOf(['absolute', 'fixed'])
227} : void 0;
228export { Popup };
\No newline at end of file