UNPKG

9.84 kBJavaScriptView Raw
1import _extends from "@babel/runtime/helpers/esm/extends";
2import _objectWithoutPropertiesLoose from "@babel/runtime/helpers/esm/objectWithoutPropertiesLoose";
3import * as React from 'react';
4import clsx from 'clsx';
5import PropTypes from 'prop-types';
6import { chainPropTypes } from '@material-ui/utils';
7import { Transition } from 'react-transition-group';
8import withStyles from '../styles/withStyles';
9import { duration } from '../styles/transitions';
10import deprecatedPropType from '../utils/deprecatedPropType';
11import { getTransitionProps } from '../transitions/utils';
12import useTheme from '../styles/useTheme';
13import { useForkRef } from '../utils';
14export const styles = theme => ({
15 /* Styles applied to the root element. */
16 root: {
17 height: 0,
18 overflow: 'hidden',
19 transition: theme.transitions.create('height')
20 },
21
22 /* Styles applied to the root element when the transition has entered. */
23 entered: {
24 height: 'auto',
25 overflow: 'visible'
26 },
27
28 /* Styles applied to the root element when the transition has exited and `collapsedSize` != 0px. */
29 hidden: {
30 visibility: 'hidden'
31 },
32
33 /* Styles applied to the outer wrapper element. */
34 wrapper: {
35 // Hack to get children with a negative margin to not falsify the height computation.
36 display: 'flex'
37 },
38
39 /* Styles applied to the inner wrapper element. */
40 wrapperInner: {
41 width: '100%'
42 }
43});
44/**
45 * The Collapse transition is used by the
46 * [Vertical Stepper](/components/steppers/#vertical-stepper) StepContent component.
47 * It uses [react-transition-group](https://github.com/reactjs/react-transition-group) internally.
48 */
49
50const Collapse = /*#__PURE__*/React.forwardRef(function Collapse(props, ref) {
51 const {
52 children,
53 classes,
54 className,
55 collapsedHeight,
56 collapsedSize: collapsedSizeProp = '0px',
57 component: Component = 'div',
58 disableStrictModeCompat = false,
59 in: inProp,
60 onEnter,
61 onEntered,
62 onEntering,
63 onExit,
64 onExited,
65 onExiting,
66 style,
67 timeout = duration.standard,
68 // eslint-disable-next-line react/prop-types
69 TransitionComponent = Transition
70 } = props,
71 other = _objectWithoutPropertiesLoose(props, ["children", "classes", "className", "collapsedHeight", "collapsedSize", "component", "disableStrictModeCompat", "in", "onEnter", "onEntered", "onEntering", "onExit", "onExited", "onExiting", "style", "timeout", "TransitionComponent"]);
72
73 const theme = useTheme();
74 const timer = React.useRef();
75 const wrapperRef = React.useRef(null);
76 const autoTransitionDuration = React.useRef();
77 const collapsedSize = typeof (collapsedHeight || collapsedSizeProp) === 'number' ? `${collapsedHeight || collapsedSizeProp}px` : collapsedHeight || collapsedSizeProp;
78 React.useEffect(() => {
79 return () => {
80 clearTimeout(timer.current);
81 };
82 }, []);
83 const enableStrictModeCompat = theme.unstable_strictMode && !disableStrictModeCompat;
84 const nodeRef = React.useRef(null);
85 const handleRef = useForkRef(ref, enableStrictModeCompat ? nodeRef : undefined);
86
87 const normalizedTransitionCallback = callback => (nodeOrAppearing, maybeAppearing) => {
88 if (callback) {
89 const [node, isAppearing] = enableStrictModeCompat ? [nodeRef.current, nodeOrAppearing] : [nodeOrAppearing, maybeAppearing]; // onEnterXxx and onExitXxx callbacks have a different arguments.length value.
90
91 if (isAppearing === undefined) {
92 callback(node);
93 } else {
94 callback(node, isAppearing);
95 }
96 }
97 };
98
99 const handleEnter = normalizedTransitionCallback((node, isAppearing) => {
100 node.style.height = collapsedSize;
101
102 if (onEnter) {
103 onEnter(node, isAppearing);
104 }
105 });
106 const handleEntering = normalizedTransitionCallback((node, isAppearing) => {
107 const wrapperHeight = wrapperRef.current ? wrapperRef.current.clientHeight : 0;
108 const {
109 duration: transitionDuration
110 } = getTransitionProps({
111 style,
112 timeout
113 }, {
114 mode: 'enter'
115 });
116
117 if (timeout === 'auto') {
118 const duration2 = theme.transitions.getAutoHeightDuration(wrapperHeight);
119 node.style.transitionDuration = `${duration2}ms`;
120 autoTransitionDuration.current = duration2;
121 } else {
122 node.style.transitionDuration = typeof transitionDuration === 'string' ? transitionDuration : `${transitionDuration}ms`;
123 }
124
125 node.style.height = `${wrapperHeight}px`;
126
127 if (onEntering) {
128 onEntering(node, isAppearing);
129 }
130 });
131 const handleEntered = normalizedTransitionCallback((node, isAppearing) => {
132 node.style.height = 'auto';
133
134 if (onEntered) {
135 onEntered(node, isAppearing);
136 }
137 });
138 const handleExit = normalizedTransitionCallback(node => {
139 const wrapperHeight = wrapperRef.current ? wrapperRef.current.clientHeight : 0;
140 node.style.height = `${wrapperHeight}px`;
141
142 if (onExit) {
143 onExit(node);
144 }
145 });
146 const handleExited = normalizedTransitionCallback(onExited);
147 const handleExiting = normalizedTransitionCallback(node => {
148 const wrapperHeight = wrapperRef.current ? wrapperRef.current.clientHeight : 0;
149 const {
150 duration: transitionDuration
151 } = getTransitionProps({
152 style,
153 timeout
154 }, {
155 mode: 'exit'
156 });
157
158 if (timeout === 'auto') {
159 const duration2 = theme.transitions.getAutoHeightDuration(wrapperHeight);
160 node.style.transitionDuration = `${duration2}ms`;
161 autoTransitionDuration.current = duration2;
162 } else {
163 node.style.transitionDuration = typeof transitionDuration === 'string' ? transitionDuration : `${transitionDuration}ms`;
164 }
165
166 node.style.height = collapsedSize;
167
168 if (onExiting) {
169 onExiting(node);
170 }
171 });
172
173 const addEndListener = (nodeOrNext, maybeNext) => {
174 const next = enableStrictModeCompat ? nodeOrNext : maybeNext;
175
176 if (timeout === 'auto') {
177 timer.current = setTimeout(next, autoTransitionDuration.current || 0);
178 }
179 };
180
181 return /*#__PURE__*/React.createElement(TransitionComponent, _extends({
182 in: inProp,
183 onEnter: handleEnter,
184 onEntered: handleEntered,
185 onEntering: handleEntering,
186 onExit: handleExit,
187 onExited: handleExited,
188 onExiting: handleExiting,
189 addEndListener: addEndListener,
190 nodeRef: enableStrictModeCompat ? nodeRef : undefined,
191 timeout: timeout === 'auto' ? null : timeout
192 }, other), (state, childProps) => /*#__PURE__*/React.createElement(Component, _extends({
193 className: clsx(classes.root, classes.container, className, {
194 'entered': classes.entered,
195 'exited': !inProp && collapsedSize === '0px' && classes.hidden
196 }[state]),
197 style: _extends({
198 minHeight: collapsedSize
199 }, style),
200 ref: handleRef
201 }, childProps), /*#__PURE__*/React.createElement("div", {
202 className: classes.wrapper,
203 ref: wrapperRef
204 }, /*#__PURE__*/React.createElement("div", {
205 className: classes.wrapperInner
206 }, children))));
207});
208process.env.NODE_ENV !== "production" ? Collapse.propTypes = {
209 // ----------------------------- Warning --------------------------------
210 // | These PropTypes are generated from the TypeScript type definitions |
211 // | To update them edit the d.ts file and run "yarn proptypes" |
212 // ----------------------------------------------------------------------
213
214 /**
215 * The content node to be collapsed.
216 */
217 children: PropTypes.node,
218
219 /**
220 * Override or extend the styles applied to the component.
221 * See [CSS API](#css) below for more details.
222 */
223 classes: chainPropTypes(PropTypes.object, props => {
224 if (props.classes && props.classes.container) {
225 throw new Error(['Material-UI: the classes.container key is deprecated.', 'Use `classes.root` instead', 'The name of the pseudo-class was changed for consistency.'].join('\n'));
226 }
227
228 return null;
229 }),
230
231 /**
232 * @ignore
233 */
234 className: PropTypes.string,
235
236 /**
237 * The height of the container when collapsed.
238 * @deprecated The prop was renamed to support the addition of horizontal orientation, use `collapsedSize` instead.
239 */
240 collapsedHeight: deprecatedPropType(PropTypes.oneOfType([PropTypes.number, PropTypes.string]), 'The prop was renamed to support the vertical orientation, use `collapsedSize` instead'),
241
242 /**
243 * The height of the container when collapsed.
244 */
245 collapsedSize: PropTypes.oneOfType([PropTypes.number, PropTypes.string]),
246
247 /**
248 * The component used for the root node.
249 * Either a string to use a HTML element or a component.
250 */
251 component: PropTypes
252 /* @typescript-to-proptypes-ignore */
253 .elementType,
254
255 /**
256 * Enable this prop if you encounter 'Function components cannot be given refs',
257 * use `unstable_createStrictModeTheme`,
258 * and can't forward the ref in the passed `Component`.
259 */
260 disableStrictModeCompat: PropTypes.bool,
261
262 /**
263 * If `true`, the component will transition in.
264 */
265 in: PropTypes.bool,
266
267 /**
268 * @ignore
269 */
270 onEnter: PropTypes.func,
271
272 /**
273 * @ignore
274 */
275 onEntered: PropTypes.func,
276
277 /**
278 * @ignore
279 */
280 onEntering: PropTypes.func,
281
282 /**
283 * @ignore
284 */
285 onExit: PropTypes.func,
286
287 /**
288 * @ignore
289 */
290 onExited: PropTypes.func,
291
292 /**
293 * @ignore
294 */
295 onExiting: PropTypes.func,
296
297 /**
298 * @ignore
299 */
300 style: PropTypes.object,
301
302 /**
303 * The duration for the transition, in milliseconds.
304 * You may specify a single timeout for all transitions, or individually with an object.
305 *
306 * Set to 'auto' to automatically calculate transition time based on height.
307 */
308 timeout: PropTypes.oneOfType([PropTypes.oneOf(['auto']), PropTypes.number, PropTypes.shape({
309 appear: PropTypes.number,
310 enter: PropTypes.number,
311 exit: PropTypes.number
312 })])
313} : void 0;
314Collapse.muiSupportAuto = true;
315export default withStyles(styles, {
316 name: 'MuiCollapse'
317})(Collapse);
\No newline at end of file