UNPKG

6.9 kBJavaScriptView Raw
1import _extends from "@babel/runtime/helpers/esm/extends";
2import _objectWithoutPropertiesLoose from "@babel/runtime/helpers/esm/objectWithoutPropertiesLoose";
3import * as React from 'react';
4import PropTypes from 'prop-types';
5import { Transition } from 'react-transition-group';
6import useTheme from '../styles/useTheme';
7import { reflow, getTransitionProps } from '../transitions/utils';
8import useForkRef from '../utils/useForkRef';
9
10function getScale(value) {
11 return `scale(${value}, ${value ** 2})`;
12}
13
14const styles = {
15 entering: {
16 opacity: 1,
17 transform: getScale(1)
18 },
19 entered: {
20 opacity: 1,
21 transform: 'none'
22 }
23};
24/**
25 * The Grow transition is used by the [Tooltip](/components/tooltips/) and
26 * [Popover](/components/popover/) components.
27 * It uses [react-transition-group](https://github.com/reactjs/react-transition-group) internally.
28 */
29
30const Grow = /*#__PURE__*/React.forwardRef(function Grow(props, ref) {
31 const {
32 children,
33 disableStrictModeCompat = false,
34 in: inProp,
35 onEnter,
36 onEntered,
37 onEntering,
38 onExit,
39 onExited,
40 onExiting,
41 style,
42 timeout = 'auto',
43 // eslint-disable-next-line react/prop-types
44 TransitionComponent = Transition
45 } = props,
46 other = _objectWithoutPropertiesLoose(props, ["children", "disableStrictModeCompat", "in", "onEnter", "onEntered", "onEntering", "onExit", "onExited", "onExiting", "style", "timeout", "TransitionComponent"]);
47
48 const timer = React.useRef();
49 const autoTimeout = React.useRef();
50 const theme = useTheme();
51 const enableStrictModeCompat = theme.unstable_strictMode && !disableStrictModeCompat;
52 const nodeRef = React.useRef(null);
53 const foreignRef = useForkRef(children.ref, ref);
54 const handleRef = useForkRef(enableStrictModeCompat ? nodeRef : undefined, foreignRef);
55
56 const normalizedTransitionCallback = callback => (nodeOrAppearing, maybeAppearing) => {
57 if (callback) {
58 const [node, isAppearing] = enableStrictModeCompat ? [nodeRef.current, nodeOrAppearing] : [nodeOrAppearing, maybeAppearing]; // onEnterXxx and onExitXxx callbacks have a different arguments.length value.
59
60 if (isAppearing === undefined) {
61 callback(node);
62 } else {
63 callback(node, isAppearing);
64 }
65 }
66 };
67
68 const handleEntering = normalizedTransitionCallback(onEntering);
69 const handleEnter = normalizedTransitionCallback((node, isAppearing) => {
70 reflow(node); // So the animation always start from the start.
71
72 const {
73 duration: transitionDuration,
74 delay
75 } = getTransitionProps({
76 style,
77 timeout
78 }, {
79 mode: 'enter'
80 });
81 let duration;
82
83 if (timeout === 'auto') {
84 duration = theme.transitions.getAutoHeightDuration(node.clientHeight);
85 autoTimeout.current = duration;
86 } else {
87 duration = transitionDuration;
88 }
89
90 node.style.transition = [theme.transitions.create('opacity', {
91 duration,
92 delay
93 }), theme.transitions.create('transform', {
94 duration: duration * 0.666,
95 delay
96 })].join(',');
97
98 if (onEnter) {
99 onEnter(node, isAppearing);
100 }
101 });
102 const handleEntered = normalizedTransitionCallback(onEntered);
103 const handleExiting = normalizedTransitionCallback(onExiting);
104 const handleExit = normalizedTransitionCallback(node => {
105 const {
106 duration: transitionDuration,
107 delay
108 } = getTransitionProps({
109 style,
110 timeout
111 }, {
112 mode: 'exit'
113 });
114 let duration;
115
116 if (timeout === 'auto') {
117 duration = theme.transitions.getAutoHeightDuration(node.clientHeight);
118 autoTimeout.current = duration;
119 } else {
120 duration = transitionDuration;
121 }
122
123 node.style.transition = [theme.transitions.create('opacity', {
124 duration,
125 delay
126 }), theme.transitions.create('transform', {
127 duration: duration * 0.666,
128 delay: delay || duration * 0.333
129 })].join(',');
130 node.style.opacity = '0';
131 node.style.transform = getScale(0.75);
132
133 if (onExit) {
134 onExit(node);
135 }
136 });
137 const handleExited = normalizedTransitionCallback(onExited);
138
139 const addEndListener = (nodeOrNext, maybeNext) => {
140 const next = enableStrictModeCompat ? nodeOrNext : maybeNext;
141
142 if (timeout === 'auto') {
143 timer.current = setTimeout(next, autoTimeout.current || 0);
144 }
145 };
146
147 React.useEffect(() => {
148 return () => {
149 clearTimeout(timer.current);
150 };
151 }, []);
152 return /*#__PURE__*/React.createElement(TransitionComponent, _extends({
153 appear: true,
154 in: inProp,
155 nodeRef: enableStrictModeCompat ? nodeRef : undefined,
156 onEnter: handleEnter,
157 onEntered: handleEntered,
158 onEntering: handleEntering,
159 onExit: handleExit,
160 onExited: handleExited,
161 onExiting: handleExiting,
162 addEndListener: addEndListener,
163 timeout: timeout === 'auto' ? null : timeout
164 }, other), (state, childProps) => {
165 return /*#__PURE__*/React.cloneElement(children, _extends({
166 style: _extends({
167 opacity: 0,
168 transform: getScale(0.75),
169 visibility: state === 'exited' && !inProp ? 'hidden' : undefined
170 }, styles[state], style, children.props.style),
171 ref: handleRef
172 }, childProps));
173 });
174});
175process.env.NODE_ENV !== "production" ? Grow.propTypes = {
176 // ----------------------------- Warning --------------------------------
177 // | These PropTypes are generated from the TypeScript type definitions |
178 // | To update them edit the d.ts file and run "yarn proptypes" |
179 // ----------------------------------------------------------------------
180
181 /**
182 * A single child content element.
183 */
184 children: PropTypes.element,
185
186 /**
187 * Enable this prop if you encounter 'Function components cannot be given refs',
188 * use `unstable_createStrictModeTheme`,
189 * and can't forward the ref in the child component.
190 */
191 disableStrictModeCompat: PropTypes.bool,
192
193 /**
194 * If `true`, show the component; triggers the enter or exit animation.
195 */
196 in: PropTypes.bool,
197
198 /**
199 * @ignore
200 */
201 onEnter: PropTypes.func,
202
203 /**
204 * @ignore
205 */
206 onEntered: PropTypes.func,
207
208 /**
209 * @ignore
210 */
211 onEntering: PropTypes.func,
212
213 /**
214 * @ignore
215 */
216 onExit: PropTypes.func,
217
218 /**
219 * @ignore
220 */
221 onExited: PropTypes.func,
222
223 /**
224 * @ignore
225 */
226 onExiting: PropTypes.func,
227
228 /**
229 * @ignore
230 */
231 style: PropTypes.object,
232
233 /**
234 * The duration for the transition, in milliseconds.
235 * You may specify a single timeout for all transitions, or individually with an object.
236 *
237 * Set to 'auto' to automatically calculate transition time based on height.
238 */
239 timeout: PropTypes.oneOfType([PropTypes.oneOf(['auto']), PropTypes.number, PropTypes.shape({
240 appear: PropTypes.number,
241 enter: PropTypes.number,
242 exit: PropTypes.number
243 })])
244} : void 0;
245Grow.muiSupportAuto = true;
246export default Grow;
\No newline at end of file