Last active
February 27, 2017 23:26
-
-
Save tkh44/8db3dcd0161e7209fec116047cf3d392 to your computer and use it in GitHub Desktop.
Attempting to simplify react-motion's TransitionMotion component api
This file contains hidden or 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
| import { cloneElement, createElement as h, PropTypes, PureComponent } from 'react' | |
| import { TransitionMotion } from 'react-motion' | |
| export default class Eccentric extends PureComponent { | |
| static defaultProps = { | |
| component: h('div'), | |
| data: [] | |
| }; | |
| static propTypes = { | |
| // wrapper element ex: <div/> | |
| component: PropTypes.element, | |
| // array of data | |
| data: PropTypes.array, | |
| // (key, data, style) => ReactElement | |
| // called once render for each item in `data` with the key from `getKey`, `data` from `data[index]`, and | |
| // `style`, the result of: `onComponentMount`, `onRender`, `onRemount`, or `onUnmount` | |
| // | |
| // If an array is provided it will render the resulting elements in order. | |
| // This is useful for creating animated layers. | |
| render: PropTypes.oneOf([PropTypes.func, PropTypes.arrayOf(PropTypes.func)]), | |
| // (data, i) => string | |
| // help identify which items have been changed, added, or are removed | |
| // https://facebook.github.io/react/docs/lists-and-keys.html | |
| getKey: PropTypes.func, | |
| // (data, i) => Style object | |
| // data === props.data[i] | |
| // called when `component` mounts | |
| // do not wrap values in springs | |
| onComponentMount: PropTypes.func, | |
| // (data, i) => Style object | |
| // data === props.data[i] | |
| // called when `component` mounts | |
| // do not wrap values in springs | |
| onRender: PropTypes.func, | |
| // (data, i) => Style object | |
| // data === props.data[i] | |
| // do not wrap values in springs | |
| onRemount: PropTypes.func, | |
| // (data, i) => Style object | |
| // data === props.data[i] | |
| // do not wrap values in springs | |
| onUnmount: PropTypes.func | |
| } | |
| render () { | |
| return h(TransitionMotion, { | |
| defaultStyles: this.getDefaultStyles(), | |
| styles: this.getStyles(), | |
| willEnter: this.willEnter, | |
| willLeave: this.willLeave, | |
| children: this.renderCurrentStyles | |
| }) | |
| } | |
| renderCurrentStyles = currentStyles => { | |
| const { component, render } = this.props | |
| let children | |
| if (Array.isArray(render)) { | |
| // If render is an array, children becomes and array of arrays. | |
| // This is useful if you want to create layers of animation | |
| children = new Array(render.length) | |
| for (let i = 0; i < render.length; ++i) { | |
| children[i] = new Array(currentStyles.length) | |
| for (let j = 0; j < currentStyles.length; ++j) { | |
| const { key, data, style } = currentStyles[j] | |
| children[i][j] = render[i](key, data, style, j) | |
| } | |
| } | |
| } else { | |
| children = new Array(currentStyles.length) | |
| for (let j = 0; j < currentStyles.length; ++j) { | |
| const { key, data, style } = currentStyles[j] | |
| children[j] = render(key, data, style, j) | |
| } | |
| } | |
| return cloneElement(component, { children }) | |
| }; | |
| getDefaultStyles = () => { | |
| const { | |
| getKey, | |
| onComponentMount, | |
| data | |
| } = this.props | |
| let mappedData = new Array(data.length) | |
| for (let i = 0; i < data.length; ++i) { | |
| mappedData[i] = { | |
| key: getKey(data[i], i), | |
| data: data[i], | |
| style: onComponentMount(data[i], i) | |
| } | |
| } | |
| return mappedData | |
| }; | |
| getStyles = () => { | |
| const { | |
| getKey, | |
| onRender, | |
| data | |
| } = this.props | |
| let mappedData = new Array(data.length) | |
| for (let i = 0; i < data.length; ++i) { | |
| mappedData[i] = { | |
| key: getKey(data[i], i), | |
| data: data[i], | |
| style: onRender(data[i], i) | |
| } | |
| } | |
| return mappedData | |
| }; | |
| willEnter = config => this.props.onRemount(config); | |
| willLeave = config => this.props.onUnmount(config); | |
| } |
This file contains hidden or 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
| import { createElement as h, PureComponent } from 'react' | |
| import { spring } from 'react-motion' | |
| import Eccentric from 'ui/Eccentric' | |
| export default class TimestampBarContainer extends PureComponent { | |
| render () { | |
| return h(Eccentric, { | |
| data: this.props.data, | |
| component: <ul />, | |
| getKey: data => { | |
| return data.name | |
| }, | |
| onComponentMount: data => { | |
| // no springs | |
| return { | |
| top: data.top, | |
| left: data.left, | |
| opacity: data.top > 500 ? 0 : 1, | |
| translateY: data.offsetY | |
| } | |
| }, | |
| onRender: (data, i) => { | |
| // springs | |
| return { | |
| top: spring(i * data.top), | |
| left: spring(data.left), | |
| opacity: data.top > 500 ? 0 : 1, // you don't have to use them, | |
| translateY: spring(data.offsetY) | |
| } | |
| }, | |
| onRemount: ({ key, data, style }) => { | |
| // no springs | |
| // key, data, style come from the config generated by `onRender`. | |
| // When the piece of data is remounted this function is called to override the initial position of the rendered element | |
| // We are creating a starting point to our animation here | |
| // *from* onRemount styles *to* onRender styles | |
| // be careful using values from `style` they will be `spring` objects | |
| return { | |
| top: data.top, | |
| left: data.left, | |
| opacity: data.top > 500 ? 0 : 1, | |
| translateY: data.offsetY | |
| } | |
| }, | |
| onUnmount: ({ key, data, style }) => { | |
| // springs | |
| // Where to animate *to* when removing this data item | |
| return { | |
| top: spring(data.top), | |
| left: spring(data.left), | |
| opacity: data.top > 500 ? 0 : 1, // you don't have to use them, | |
| translateY: spring(data.offsetY) | |
| } | |
| }, | |
| render: (key, data, style) => { | |
| // called for each data item with its key, data and style | |
| return ( | |
| <li | |
| key={key} | |
| style={{ | |
| position: 'absolute', | |
| top: style.top, | |
| left: style.left, | |
| opacity: style.opacity, | |
| transform: `translateY(${style.translateY})` | |
| }} | |
| onClick={this.handleClick.bind(this, key, data, style)} | |
| > | |
| {data.name} | { data.username} | |
| </li> | |
| ) | |
| } | |
| }) | |
| } | |
| handleClick = (key, data, style, evt) => { | |
| console.log(key, data, style) | |
| } | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment