UNPKG

7.89 kBJavaScriptView Raw
1'use client';
2
3import * as React from 'react';
4import PropTypes from 'prop-types';
5import useTimeout from '@mui/utils/useTimeout';
6import elementAcceptingRef from '@mui/utils/elementAcceptingRef';
7import getReactElementRef from '@mui/utils/getReactElementRef';
8import { Transition } from 'react-transition-group';
9import { useTheme } from "../zero-styled/index.js";
10import { getTransitionProps, reflow } from "../transitions/utils.js";
11import useForkRef from "../utils/useForkRef.js";
12import { jsx as _jsx } from "react/jsx-runtime";
13function getScale(value) {
14 return `scale(${value}, ${value ** 2})`;
15}
16const styles = {
17 entering: {
18 opacity: 1,
19 transform: getScale(1)
20 },
21 entered: {
22 opacity: 1,
23 transform: 'none'
24 }
25};
26
27/*
28 TODO v6: remove
29 Conditionally apply a workaround for the CSS transition bug in Safari 15.4 / WebKit browsers.
30 */
31const isWebKit154 = typeof navigator !== 'undefined' && /^((?!chrome|android).)*(safari|mobile)/i.test(navigator.userAgent) && /(os |version\/)15(.|_)4/i.test(navigator.userAgent);
32
33/**
34 * The Grow transition is used by the [Tooltip](/material-ui/react-tooltip/) and
35 * [Popover](/material-ui/react-popover/) components.
36 * It uses [react-transition-group](https://github.com/reactjs/react-transition-group) internally.
37 */
38const Grow = /*#__PURE__*/React.forwardRef(function Grow(props, ref) {
39 const {
40 addEndListener,
41 appear = true,
42 children,
43 easing,
44 in: inProp,
45 onEnter,
46 onEntered,
47 onEntering,
48 onExit,
49 onExited,
50 onExiting,
51 style,
52 timeout = 'auto',
53 // eslint-disable-next-line react/prop-types
54 TransitionComponent = Transition,
55 ...other
56 } = props;
57 const timer = useTimeout();
58 const autoTimeout = React.useRef();
59 const theme = useTheme();
60 const nodeRef = React.useRef(null);
61 const handleRef = useForkRef(nodeRef, getReactElementRef(children), ref);
62 const normalizedTransitionCallback = callback => maybeIsAppearing => {
63 if (callback) {
64 const node = nodeRef.current;
65
66 // onEnterXxx and onExitXxx callbacks have a different arguments.length value.
67 if (maybeIsAppearing === undefined) {
68 callback(node);
69 } else {
70 callback(node, maybeIsAppearing);
71 }
72 }
73 };
74 const handleEntering = normalizedTransitionCallback(onEntering);
75 const handleEnter = normalizedTransitionCallback((node, isAppearing) => {
76 reflow(node); // So the animation always start from the start.
77
78 const {
79 duration: transitionDuration,
80 delay,
81 easing: transitionTimingFunction
82 } = getTransitionProps({
83 style,
84 timeout,
85 easing
86 }, {
87 mode: 'enter'
88 });
89 let duration;
90 if (timeout === 'auto') {
91 duration = theme.transitions.getAutoHeightDuration(node.clientHeight);
92 autoTimeout.current = duration;
93 } else {
94 duration = transitionDuration;
95 }
96 node.style.transition = [theme.transitions.create('opacity', {
97 duration,
98 delay
99 }), theme.transitions.create('transform', {
100 duration: isWebKit154 ? duration : duration * 0.666,
101 delay,
102 easing: transitionTimingFunction
103 })].join(',');
104 if (onEnter) {
105 onEnter(node, isAppearing);
106 }
107 });
108 const handleEntered = normalizedTransitionCallback(onEntered);
109 const handleExiting = normalizedTransitionCallback(onExiting);
110 const handleExit = normalizedTransitionCallback(node => {
111 const {
112 duration: transitionDuration,
113 delay,
114 easing: transitionTimingFunction
115 } = getTransitionProps({
116 style,
117 timeout,
118 easing
119 }, {
120 mode: 'exit'
121 });
122 let duration;
123 if (timeout === 'auto') {
124 duration = theme.transitions.getAutoHeightDuration(node.clientHeight);
125 autoTimeout.current = duration;
126 } else {
127 duration = transitionDuration;
128 }
129 node.style.transition = [theme.transitions.create('opacity', {
130 duration,
131 delay
132 }), theme.transitions.create('transform', {
133 duration: isWebKit154 ? duration : duration * 0.666,
134 delay: isWebKit154 ? delay : delay || duration * 0.333,
135 easing: transitionTimingFunction
136 })].join(',');
137 node.style.opacity = 0;
138 node.style.transform = getScale(0.75);
139 if (onExit) {
140 onExit(node);
141 }
142 });
143 const handleExited = normalizedTransitionCallback(onExited);
144 const handleAddEndListener = next => {
145 if (timeout === 'auto') {
146 timer.start(autoTimeout.current || 0, next);
147 }
148 if (addEndListener) {
149 // Old call signature before `react-transition-group` implemented `nodeRef`
150 addEndListener(nodeRef.current, next);
151 }
152 };
153 return /*#__PURE__*/_jsx(TransitionComponent, {
154 appear: appear,
155 in: inProp,
156 nodeRef: nodeRef,
157 onEnter: handleEnter,
158 onEntered: handleEntered,
159 onEntering: handleEntering,
160 onExit: handleExit,
161 onExited: handleExited,
162 onExiting: handleExiting,
163 addEndListener: handleAddEndListener,
164 timeout: timeout === 'auto' ? null : timeout,
165 ...other,
166 children: (state, childProps) => {
167 return /*#__PURE__*/React.cloneElement(children, {
168 style: {
169 opacity: 0,
170 transform: getScale(0.75),
171 visibility: state === 'exited' && !inProp ? 'hidden' : undefined,
172 ...styles[state],
173 ...style,
174 ...children.props.style
175 },
176 ref: handleRef,
177 ...childProps
178 });
179 }
180 });
181});
182process.env.NODE_ENV !== "production" ? Grow.propTypes /* remove-proptypes */ = {
183 // ┌────────────────────────────── Warning ──────────────────────────────┐
184 // │ These PropTypes are generated from the TypeScript type definitions. │
185 // │ To update them, edit the d.ts file and run `pnpm proptypes`. │
186 // └─────────────────────────────────────────────────────────────────────┘
187 /**
188 * Add a custom transition end trigger. Called with the transitioning DOM
189 * node and a done callback. Allows for more fine grained transition end
190 * logic. Note: Timeouts are still used as a fallback if provided.
191 */
192 addEndListener: PropTypes.func,
193 /**
194 * Perform the enter transition when it first mounts if `in` is also `true`.
195 * Set this to `false` to disable this behavior.
196 * @default true
197 */
198 appear: PropTypes.bool,
199 /**
200 * A single child content element.
201 */
202 children: elementAcceptingRef.isRequired,
203 /**
204 * The transition timing function.
205 * You may specify a single easing or a object containing enter and exit values.
206 */
207 easing: PropTypes.oneOfType([PropTypes.shape({
208 enter: PropTypes.string,
209 exit: PropTypes.string
210 }), PropTypes.string]),
211 /**
212 * If `true`, the component will transition in.
213 */
214 in: PropTypes.bool,
215 /**
216 * @ignore
217 */
218 onEnter: PropTypes.func,
219 /**
220 * @ignore
221 */
222 onEntered: PropTypes.func,
223 /**
224 * @ignore
225 */
226 onEntering: PropTypes.func,
227 /**
228 * @ignore
229 */
230 onExit: PropTypes.func,
231 /**
232 * @ignore
233 */
234 onExited: PropTypes.func,
235 /**
236 * @ignore
237 */
238 onExiting: PropTypes.func,
239 /**
240 * @ignore
241 */
242 style: PropTypes.object,
243 /**
244 * The duration for the transition, in milliseconds.
245 * You may specify a single timeout for all transitions, or individually with an object.
246 *
247 * Set to 'auto' to automatically calculate transition time based on height.
248 * @default 'auto'
249 */
250 timeout: PropTypes.oneOfType([PropTypes.oneOf(['auto']), PropTypes.number, PropTypes.shape({
251 appear: PropTypes.number,
252 enter: PropTypes.number,
253 exit: PropTypes.number
254 })])
255} : void 0;
256if (Grow) {
257 Grow.muiSupportAuto = true;
258}
259export default Grow;
\No newline at end of file