-
-
Notifications
You must be signed in to change notification settings - Fork 298
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
a4854e4
commit bc7dc14
Showing
5 changed files
with
719 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,171 @@ | ||
/** | ||
* Credit to MUI team @ https://mui.com | ||
*/ | ||
import * as React from 'react'; | ||
import clsx from 'clsx'; | ||
import { Transition as TransitionComponent } from 'react-transition-group'; | ||
import { TransitionStatus } from 'react-transition-group/Transition'; | ||
import useForkRef from '../utils/useForkRef'; | ||
import { TransitionProps } from '../types'; | ||
import useCallbackNormaliser from './useCallbackNormaliser'; | ||
import { createTransition, getAutoHeightDuration, getTransitionProps } from './util'; | ||
import { ComponentClasses, makeStyles } from '../utils/styles'; | ||
|
||
const classes = makeStyles({ | ||
root: { | ||
height: 0, | ||
}, | ||
entered: { | ||
height: 'auto', | ||
}, | ||
}); | ||
|
||
const collapsedSize = '0px'; | ||
|
||
const Collapse = React.forwardRef<unknown, TransitionProps>((props, ref) => { | ||
const { | ||
children, | ||
style, | ||
timeout = 300, | ||
in: inProp, | ||
onEnter, | ||
onEntered, | ||
onExit, | ||
onExited, | ||
direction, // Take this out since this is a Slide-only prop | ||
...other | ||
} = props; | ||
|
||
const timer = React.useRef<ReturnType<typeof setTimeout>>(); | ||
const wrapperRef = React.useRef(null); | ||
const autoTransitionDuration = React.useRef<number>(); | ||
|
||
React.useEffect(() => () => { | ||
if (timer.current) { | ||
clearTimeout(timer.current); | ||
} | ||
}, []); | ||
|
||
const nodeRef = React.useRef(null); | ||
const handleRef = useForkRef(ref, nodeRef); | ||
|
||
const callbackNormaliser = useCallbackNormaliser(nodeRef); | ||
|
||
const getWrapperSize = () => (wrapperRef.current ? wrapperRef.current.clientHeight : 0); | ||
|
||
const handleEnter = callbackNormaliser((node, isAppearing) => { | ||
node.style.height = collapsedSize; | ||
if (onEnter) { | ||
onEnter(node, isAppearing); | ||
} | ||
}); | ||
|
||
const handleEntering = callbackNormaliser((node) => { | ||
const wrapperSize = getWrapperSize(); | ||
|
||
const { duration: transitionDuration, easing } = getTransitionProps({ | ||
style, timeout, mode: 'enter', | ||
}); | ||
|
||
if (timeout === 'auto') { | ||
const duration2 = getAutoHeightDuration(wrapperSize); | ||
node.style.transitionDuration = `${duration2}ms`; | ||
autoTransitionDuration.current = duration2; | ||
} else { | ||
node.style.transitionDuration = typeof transitionDuration === 'string' ? transitionDuration : `${transitionDuration}ms`; | ||
} | ||
|
||
node.style.height = `${wrapperSize}px`; | ||
node.style.transitionTimingFunction = easing || ''; | ||
}); | ||
|
||
const handleEntered = callbackNormaliser((node, isAppearing) => { | ||
node.style.height = 'auto'; | ||
if (onEntered) { | ||
onEntered(node, isAppearing); | ||
} | ||
}); | ||
|
||
const handleExit = callbackNormaliser((node) => { | ||
node.style.height = `${getWrapperSize()}px`; | ||
if (onExit) { | ||
onExit(node); | ||
} | ||
}); | ||
|
||
const handleExited = callbackNormaliser(onExited); | ||
|
||
const handleExiting = callbackNormaliser((node) => { | ||
const wrapperSize = getWrapperSize(); | ||
const { duration: transitionDuration, easing } = getTransitionProps({ | ||
style, timeout, mode: 'exit', | ||
}); | ||
|
||
if (timeout === 'auto') { | ||
const duration2 = getAutoHeightDuration(wrapperSize); | ||
node.style.transitionDuration = `${duration2}ms`; | ||
autoTransitionDuration.current = duration2; | ||
} else { | ||
node.style.transitionDuration = typeof transitionDuration === 'string' ? transitionDuration : `${transitionDuration}ms`; | ||
} | ||
|
||
node.style.height = collapsedSize; | ||
node.style.transitionTimingFunction = easing || ''; | ||
}); | ||
|
||
const handleAddEndListener = (next: any) => { | ||
if (timeout === 'auto') { | ||
timer.current = setTimeout(next, autoTransitionDuration.current || 0); | ||
} | ||
}; | ||
|
||
return ( | ||
<TransitionComponent | ||
in={inProp} | ||
onEnter={handleEnter} | ||
onEntered={handleEntered} | ||
onEntering={handleEntering} | ||
onExit={handleExit} | ||
onExited={handleExited} | ||
onExiting={handleExiting} | ||
addEndListener={handleAddEndListener} | ||
nodeRef={nodeRef} | ||
timeout={timeout === 'auto' ? null : timeout} | ||
{...other} | ||
> | ||
{(state: TransitionStatus, childProps: Record<string, any>) => ( | ||
<div | ||
ref={handleRef} | ||
className={clsx(classes.root, { [classes.entered]: state === 'entered' })} | ||
style={{ | ||
pointerEvents: 'all', | ||
overflow: 'hidden', | ||
minHeight: collapsedSize, | ||
transition: createTransition('height'), | ||
...(state === 'entered' && { | ||
overflow: 'visible', | ||
}), | ||
...(state === 'exited' && !inProp && { | ||
visibility: 'hidden', | ||
}), | ||
...style, | ||
}} | ||
{...childProps} | ||
> | ||
<div | ||
ref={wrapperRef} | ||
className={ComponentClasses.CollapseWrapper} | ||
// Hack to get children with a negative margin to not falsify the height computation. | ||
style={{ display: 'flex' }} | ||
> | ||
<div style={{ width: '100%' }}> | ||
{children} | ||
</div> | ||
</div> | ||
</div> | ||
)} | ||
</TransitionComponent> | ||
); | ||
}); | ||
|
||
export default Collapse; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,94 @@ | ||
/** | ||
* Credit to MUI team @ https://mui.com | ||
*/ | ||
import * as React from 'react'; | ||
import { Transition as TransitionComponent } from 'react-transition-group'; | ||
import { TransitionStatus } from 'react-transition-group/Transition'; | ||
import useCallbackNormaliser from './useCallbackNormaliser'; | ||
import { TransitionProps } from '../types'; | ||
import useForkRef from '../utils/useForkRef'; | ||
import { createTransition, getTransitionProps, reflow } from './util'; | ||
|
||
const styles: Partial<Record<TransitionStatus, React.CSSProperties>> = { | ||
entering: { | ||
opacity: 1, | ||
}, | ||
entered: { | ||
opacity: 1, | ||
}, | ||
}; | ||
|
||
const Fade = React.forwardRef<unknown, TransitionProps>((props, ref) => { | ||
const { | ||
children, | ||
in: inProp, | ||
timeout = 0, | ||
style, | ||
onEnter, | ||
onEntered, | ||
onExit, | ||
onExited, | ||
direction, // Take this out since this is a Slide-only prop | ||
...other | ||
} = props; | ||
|
||
const nodeRef = React.useRef(null); | ||
const handleRefIntermediary = useForkRef(children.ref, ref); | ||
const handleRef = useForkRef(nodeRef, handleRefIntermediary); | ||
|
||
const callbackNormaliser = useCallbackNormaliser(nodeRef); | ||
|
||
const handleEnter = callbackNormaliser((node, isAppearing) => { | ||
reflow(node); | ||
|
||
const transitionProps = getTransitionProps({ style, timeout, mode: 'enter' }); | ||
node.style.webkitTransition = createTransition('opacity', transitionProps); | ||
node.style.transition = createTransition('opacity', transitionProps); | ||
|
||
if (onEnter) { | ||
onEnter(node, isAppearing); | ||
} | ||
}); | ||
|
||
const handleEntered = callbackNormaliser(onEntered); | ||
|
||
const handleExit = callbackNormaliser((node) => { | ||
const transitionProps = getTransitionProps({ style, timeout, mode: 'exit' }); | ||
node.style.webkitTransition = createTransition('opacity', transitionProps); | ||
node.style.transition = createTransition('opacity', transitionProps); | ||
|
||
if (onExit) { | ||
onExit(node); | ||
} | ||
}); | ||
|
||
const handleExited = callbackNormaliser(onExited); | ||
|
||
return ( | ||
<TransitionComponent | ||
appear | ||
in={inProp} | ||
nodeRef={nodeRef} | ||
onEnter={handleEnter} | ||
onEntered={handleEntered} | ||
onExit={handleExit} | ||
onExited={handleExited} | ||
timeout={timeout} | ||
{...other} | ||
> | ||
{(status: TransitionStatus, childProps: Record<string, any>) => React.cloneElement(children, { | ||
style: { | ||
opacity: 0, | ||
visibility: status === 'exited' && !inProp ? 'hidden' : undefined, | ||
...styles[status], | ||
...style, | ||
...children.props.style, | ||
}, | ||
ref: handleRef, | ||
...childProps, | ||
})} | ||
</TransitionComponent> | ||
); | ||
}); | ||
|
||
export default Fade; |
Oops, something went wrong.