UNPKG

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