Skip to content

Instantly share code, notes, and snippets.

@tkh44
Last active November 22, 2018 18:13
Show Gist options
  • Save tkh44/8db9f056451f2b81b54d73e4890c7bf3 to your computer and use it in GitHub Desktop.
Save tkh44/8db9f056451f2b81b54d73e4890c7bf3 to your computer and use it in GitHub Desktop.
Helper for react motion to stagger animation mounting with TransitionMotion component. Props to https://github.com/maisano/react-router-transition for the idea
import { createElement, cloneElement, Children } from 'react';
import { TransitionMotion, spring, presets } from 'react-motion';
import compose from 'recompose/compose';
import defaultProps from 'recompose/defaultProps';
import withHandlers from 'recompose/withHandlers';
import toClass from 'recompose/toClass';
const TransitionGroup = compose(
defaultProps({
component: 'div',
className: '',
style: {},
leaveImmediate: false,
stagger: false,
atEnter: {
scale: 0.8,
opacity: 0
},
atLeave: {
scale: spring(0.8, { stiffness: 360, damping: 25 }),
opacity: spring(0, { stiffness: 360, damping: 25 })
},
atActive: {
scale: spring(1, { stiffness: 360, damping: 25 }),
opacity: 1
},
mapStyles(styles) {
return {
opacity: styles.opacity,
transform: `scale(${styles.scale})`
};
}
}),
withHandlers({
getDefaultStyles: ({ children, atEnter }) => {
return () => {
if (!children) {
return [];
}
return Children.toArray(children).filter(Boolean).map((child, i) => {
return {
key: child.key || i,
data: child,
style: atEnter
};
});
};
},
getStyles: ({ children, atActive, stagger }) => {
return () => {
if (!children) {
return [];
}
if (stagger) {
return (prevStyles) => {
return Children.map(children, (child, i) => {
if (!child) {
return;
}
if (i === 0 || !prevStyles[i - 1]) {
return {
key: child.key || i,
data: child,
style: atActive
};
}
return {
key: child.key,
data: child,
style: prevStyles[i - 1].style
};
});
};
}
return Children.map(children, (child, i) => {
if (!child) {
return;
}
return {
key: child.key || i,
data: child,
style: atActive
};
});
};
},
willEnter: ({ atEnter }) => () => atEnter,
willLeave: ({ atLeave, leaveImmediate }) => {
return () => {
if (leaveImmediate) {
return null;
}
return atLeave;
};
}
}),
toClass
)(({ component, className, style, getDefaultStyles, getStyles, willEnter, willLeave, mapStyles }) => {
return createElement(
TransitionMotion,
{
defaultStyles: getDefaultStyles(),
styles: getStyles(),
willEnter,
willLeave,
children: (interpolatedStyles) => {
return createElement(
component,
{
className,
style,
children: interpolatedStyles.map((config) => {
return cloneElement(
config.data,
{
key: config.key,
style: mapStyles(config.style)
}
);
})
}
);
}
}
);
});
export default TransitionGroup;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment