UNPKG

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