react-motion
Advanced tools
Comparing version 0.1.0 to 0.2.0
Legend: | ||
- [I]: improvement | ||
- [F]: fix | ||
- [B]: fix | ||
- [B]: Breaking | ||
- [F]: Fix | ||
- [I]: Improvement | ||
### 0.2.0 (July 22th 2015) | ||
- [B] `willLeave` returning `false` will now keep the key. Only `null` and `undefined` will serve as a signal to kill the disappeared key. | ||
- [B] `willLeave` previously failed to expose the second argument `correspondingValueOfKeyThatJustLeft`. It's now exposed correctly. | ||
- [F] Definitively fix the previous problem of mis-detecting React Element as object. | ||
- [F] `willLeave` is now called only once per disappearing key. It was called more than once previously as a implementation detail. Though you should never have put side-effects in `willLeave`. It's still discouraged now. | ||
- [F] If you have some `this.props.handlerThatSetStateAndUnmountsSpringInOwnerRender()` in `Spring`'s `endValue`, Spring's already scheduled `requestAnimationFrame` will no longer cause an extra `setState` since it's unmounted. But in general, _please_ don't put side-effect in `endValue`. | ||
- [I] Stabilize the spring algorithm. No more erratic behavior with a big amount of animated items or tab switching (which usually slows down `requestAnimationFrame`). #57 | ||
- [I] Partial (total?) support for IE9 by using a `requestAnimationFrame` polyfill. | ||
### 0.1.0 (July 14th 2015) | ||
- [B] Breaking API: `TransitionSpring`'s `willEnter`'s callback signature is now `(keyThatEnters, correspondingValue, endValueYouJustSpecified, currentInterpolatedValue, currentSpeed)` (added `correspondingValue` as the second argument). Same for `willLeave`. | ||
- [B] `Spring` is now no longer exposed as a default, but simply as "Spring": `require('react-motion').Spring`. Or `import {Spring} from 'react-motion'`. | ||
@@ -9,0 +19,0 @@ - [B] `Spring` and `TransitionSpring`'s `children` function now expect a ReactElement. The components will no longer wrap the return value in a `div` for you. #44 #20 |
@@ -5,2 +5,8 @@ 'use strict'; | ||
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } | ||
var _reorderKeys = require('./reorderKeys'); | ||
var _reorderKeys2 = _interopRequireDefault(_reorderKeys); | ||
var _Spring = require('./Spring'); | ||
@@ -10,2 +16,5 @@ | ||
exports.TransitionSpring = _Spring.TransitionSpring; | ||
exports.utils = _Spring.utils; | ||
var utils = { | ||
reorderKeys: _reorderKeys2['default'] | ||
}; | ||
exports.utils = utils; |
'use strict'; | ||
exports.__esModule = true; | ||
exports.updateCurrVals = updateCurrVals; | ||
exports.updateCurrV = updateCurrV; | ||
exports.noSpeed = noSpeed; | ||
exports.updateCurrValue = updateCurrValue; | ||
exports.updateCurrVelocity = updateCurrVelocity; | ||
@@ -14,4 +13,10 @@ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } | ||
var _utils = require('./utils'); | ||
var _mapTree = require('./mapTree'); | ||
var _mapTree2 = _interopRequireDefault(_mapTree); | ||
var _lodashIsPlainObject = require('lodash.isPlainObject'); | ||
var _lodashIsPlainObject2 = _interopRequireDefault(_lodashIsPlainObject); | ||
var _stepper = require('./stepper'); | ||
@@ -21,4 +26,23 @@ | ||
var FRAME_RATE = 1 / 60; | ||
var _noVelocity = require('./noVelocity'); | ||
var _noVelocity2 = _interopRequireDefault(_noVelocity); | ||
var _mergeDiff = require('./mergeDiff'); | ||
var _mergeDiff2 = _interopRequireDefault(_mergeDiff); | ||
var _animationLoop = require('./animationLoop'); | ||
var _animationLoop2 = _interopRequireDefault(_animationLoop); | ||
var animationLoop = _animationLoop2['default']({ | ||
// Fixed time step in seconds. | ||
timeStep: 1 / 60, | ||
// Slow-mo anyone? Give 0.1 a try. | ||
timeScale: 1, | ||
// Pause if we have more than this many steps worth of accumulated time. | ||
maxSteps: 10 | ||
}); | ||
function zero() { | ||
@@ -28,93 +52,43 @@ return 0; | ||
// TODO: test | ||
function mergeDiff(_x, _x2, _x3, _x4) { | ||
var _again = true; | ||
_function: while (_again) { | ||
var collA = _x, | ||
collB = _x2, | ||
onRemove = _x3, | ||
accum = _x4; | ||
a = aa = b = bb = undefined; | ||
_again = false; | ||
var a = collA[0]; | ||
var aa = collA.slice(1); | ||
var b = collB[0]; | ||
var bb = collB.slice(1); | ||
if (collA.length === 0 && collB.length === 0) { | ||
return accum; | ||
// TODO: refactor common logic with updateCurrValue and updateCurrVelocity | ||
function interpolateValue(alpha, nextValue, prevValue) { | ||
if (nextValue === null) { | ||
return null; | ||
} | ||
if (prevValue == null) { | ||
return nextValue; | ||
} | ||
if (typeof nextValue === 'number') { | ||
// https://github.com/chenglou/react-motion/pull/57#issuecomment-121924628 | ||
return nextValue * alpha + prevValue * (1 - alpha); | ||
} | ||
if (nextValue.val != null && nextValue.config && nextValue.config.length === 0) { | ||
return nextValue; | ||
} | ||
if (nextValue.val != null) { | ||
var ret = { | ||
val: interpolateValue(alpha, nextValue.val, prevValue.val) | ||
}; | ||
if (nextValue.config) { | ||
ret.config = nextValue.config; | ||
} | ||
if (collA.length === 0) { | ||
return accum.concat(collB); | ||
} | ||
if (collB.length === 0) { | ||
if (onRemove(a)) { | ||
_x = aa; | ||
_x2 = collB; | ||
_x3 = onRemove; | ||
_x4 = accum; | ||
_again = true; | ||
continue _function; | ||
} | ||
_x = aa; | ||
_x2 = collB; | ||
_x3 = onRemove; | ||
_x4 = accum.concat(a); | ||
_again = true; | ||
continue _function; | ||
} | ||
if (a === b) { | ||
// fails for ([undefined], [], () => true). but don't do that | ||
_x = aa; | ||
_x2 = bb; | ||
_x3 = onRemove; | ||
_x4 = accum.concat(a); | ||
_again = true; | ||
continue _function; | ||
} | ||
if (collB.indexOf(a) === -1) { | ||
if (onRemove(a)) { | ||
_x = aa; | ||
_x2 = collB; | ||
_x3 = onRemove; | ||
_x4 = accum; | ||
_again = true; | ||
continue _function; | ||
} | ||
_x = aa; | ||
_x2 = collB; | ||
_x3 = onRemove; | ||
_x4 = accum.concat(a); | ||
_again = true; | ||
continue _function; | ||
} | ||
_x = aa; | ||
_x2 = collB; | ||
_x3 = onRemove; | ||
_x4 = accum; | ||
_again = true; | ||
continue _function; | ||
return ret; | ||
} | ||
if (Array.isArray(nextValue)) { | ||
return nextValue.map(function (_, i) { | ||
return interpolateValue(alpha, nextValue[i], prevValue[i]); | ||
}); | ||
} | ||
if (_lodashIsPlainObject2['default'](nextValue)) { | ||
return Object.keys(nextValue).reduce(function (ret, key) { | ||
ret[key] = interpolateValue(alpha, nextValue[key], prevValue[key]); | ||
return ret; | ||
}, {}); | ||
} | ||
return nextValue; | ||
} | ||
function mergeDiffObj(a, b, onRemove) { | ||
var keys = mergeDiff(Object.keys(a), Object.keys(b), function (_a) { | ||
return !onRemove(_a); | ||
}, []); | ||
var ret = {}; | ||
keys.forEach(function (key) { | ||
if (b.hasOwnProperty(key)) { | ||
ret[key] = b[key]; | ||
} else { | ||
ret[key] = onRemove(key); | ||
} | ||
}); | ||
// TODO: refactor common logic with updateCurrVelocity | ||
return ret; | ||
} | ||
// TODO: refactor common logic with updateCurrV | ||
function updateCurrVals(frameRate, currVals, currV, endValue, k, b) { | ||
function updateCurrValue(frameRate, currValue, currVelocity, endValue, k, b) { | ||
if (endValue === null) { | ||
@@ -128,3 +102,3 @@ return null; | ||
// TODO: do something to stepper to make this not allocate (2 steppers?) | ||
return _stepper2['default'](frameRate, currVals, currV, endValue, k, b)[0]; | ||
return _stepper2['default'](frameRate, currValue, currVelocity, endValue, k, b)[0]; | ||
} | ||
@@ -141,3 +115,3 @@ if (endValue.val != null && endValue.config && endValue.config.length === 0) { | ||
var ret = { | ||
val: updateCurrVals(frameRate, currVals.val, currV.val, endValue.val, _k, _b) | ||
val: updateCurrValue(frameRate, currValue.val, currVelocity.val, endValue.val, _k, _b) | ||
}; | ||
@@ -151,17 +125,10 @@ if (endValue.config) { | ||
return endValue.map(function (_, i) { | ||
return updateCurrVals(frameRate, currVals[i], currV[i], endValue[i], k, b); | ||
return updateCurrValue(frameRate, currValue[i], currVelocity[i], endValue[i], k, b); | ||
}); | ||
} | ||
if (_utils.isPlainObject(endValue)) { | ||
var _ret = (function () { | ||
var ret = {}; | ||
Object.keys(endValue).forEach(function (key) { | ||
ret[key] = updateCurrVals(frameRate, currVals[key], currV[key], endValue[key], k, b); | ||
}); | ||
return { | ||
v: ret | ||
}; | ||
})(); | ||
if (typeof _ret === 'object') return _ret.v; | ||
if (_lodashIsPlainObject2['default'](endValue)) { | ||
return Object.keys(endValue).reduce(function (ret, key) { | ||
ret[key] = updateCurrValue(frameRate, currValue[key], currVelocity[key], endValue[key], k, b); | ||
return ret; | ||
}, {}); | ||
} | ||
@@ -171,3 +138,3 @@ return endValue; | ||
function updateCurrV(frameRate, currVals, currV, endValue, k, b) { | ||
function updateCurrVelocity(frameRate, currValue, currVelocity, endValue, k, b) { | ||
if (endValue === null) { | ||
@@ -178,9 +145,9 @@ return null; | ||
if (k == null || b == null) { | ||
return _utils.mapTree(zero, currV); | ||
return _mapTree2['default'](zero, currVelocity); | ||
} | ||
// TODO: do something to stepper to make this not allocate (2 steppers?) | ||
return _stepper2['default'](frameRate, currVals, currV, endValue, k, b)[1]; | ||
return _stepper2['default'](frameRate, currValue, currVelocity, endValue, k, b)[1]; | ||
} | ||
if (endValue.val != null && endValue.config && endValue.config.length === 0) { | ||
return _utils.mapTree(zero, currV); | ||
return _mapTree2['default'](zero, currVelocity); | ||
} | ||
@@ -194,3 +161,3 @@ if (endValue.val != null) { | ||
var ret = { | ||
val: updateCurrV(frameRate, currVals.val, currV.val, endValue.val, _k, _b) | ||
val: updateCurrVelocity(frameRate, currValue.val, currVelocity.val, endValue.val, _k, _b) | ||
}; | ||
@@ -204,33 +171,14 @@ if (endValue.config) { | ||
return endValue.map(function (_, i) { | ||
return updateCurrV(frameRate, currVals[i], currV[i], endValue[i], k, b); | ||
return updateCurrVelocity(frameRate, currValue[i], currVelocity[i], endValue[i], k, b); | ||
}); | ||
} | ||
if (_utils.isPlainObject(endValue)) { | ||
var _ret2 = (function () { | ||
var ret = {}; | ||
Object.keys(endValue).forEach(function (key) { | ||
ret[key] = updateCurrV(frameRate, currVals[key], currV[key], endValue[key], k, b); | ||
}); | ||
return { | ||
v: ret | ||
}; | ||
})(); | ||
if (typeof _ret2 === 'object') return _ret2.v; | ||
if (_lodashIsPlainObject2['default'](endValue)) { | ||
return Object.keys(endValue).reduce(function (ret, key) { | ||
ret[key] = updateCurrVelocity(frameRate, currValue[key], currVelocity[key], endValue[key], k, b); | ||
return ret; | ||
}, {}); | ||
} | ||
return _utils.mapTree(zero, currV); | ||
return _mapTree2['default'](zero, currVelocity); | ||
} | ||
function noSpeed(coll) { | ||
if (Array.isArray(coll)) { | ||
return coll.every(noSpeed); | ||
} | ||
if (_utils.isPlainObject(coll)) { | ||
return Object.keys(coll).every(function (key) { | ||
return key === 'config' ? true : noSpeed(coll[key]); | ||
}); | ||
} | ||
return typeof coll === 'number' ? coll === 0 : true; | ||
} | ||
var Spring = _react2['default'].createClass({ | ||
@@ -248,8 +196,8 @@ displayName: 'Spring', | ||
if (typeof endValue === 'function') { | ||
// TODO: provide warning for failing to provide base case | ||
endValue = endValue(); | ||
} | ||
return { | ||
currVals: endValue, | ||
currV: _utils.mapTree(zero, endValue), | ||
now: null | ||
currValue: endValue, | ||
currVelocity: _mapTree2['default'](zero, endValue) | ||
}; | ||
@@ -259,70 +207,73 @@ }, | ||
componentDidMount: function componentDidMount() { | ||
this.raf(true, false); | ||
this.startAnimating(); | ||
}, | ||
componentWillReceiveProps: function componentWillReceiveProps() { | ||
this.raf(true, false); | ||
this.startAnimating(); | ||
}, | ||
unsubscribeAnimation: null, | ||
// used in animationRender | ||
hasUnmounted: false, | ||
componentWillUnmount: function componentWillUnmount() { | ||
cancelAnimationFrame(this._rafID); | ||
if (this.unsubscribeAnimation) { | ||
this.unsubscribeAnimation(); | ||
this.unsubscribeAnimation = null; | ||
} | ||
this.hasUnmounted = true; | ||
}, | ||
_rafID: null, | ||
startAnimating: function startAnimating() { | ||
if (!this.unsubscribeAnimation) { | ||
// means we're not animating | ||
this.unsubscribeAnimation = animationLoop.subscribe(this.animationStep, this.animationRender, this.state); | ||
animationLoop.start(); | ||
} | ||
}, | ||
raf: function raf(justStarted, isLastRaf) { | ||
var _this = this; | ||
animationStep: function animationStep(timeStep, state) { | ||
var currValue = state.currValue; | ||
var currVelocity = state.currVelocity; | ||
var endValue = this.props.endValue; | ||
if (justStarted && this._rafID != null) { | ||
// already rafing | ||
return; | ||
if (typeof endValue === 'function') { | ||
endValue = endValue(currValue); | ||
} | ||
this._rafID = requestAnimationFrame(function () { | ||
var _state = _this.state; | ||
var currVals = _state.currVals; | ||
var currV = _state.currV; | ||
var now = _state.now; | ||
var endValue = _this.props.endValue; | ||
if (typeof endValue === 'function') { | ||
endValue = endValue(currVals); | ||
var newCurrValue = updateCurrValue(timeStep, currValue, currVelocity, endValue); | ||
var newCurrVelocity = updateCurrVelocity(timeStep, currValue, currVelocity, endValue); | ||
if (_noVelocity2['default'](currVelocity) && _noVelocity2['default'](newCurrVelocity)) { | ||
// check explanation in `animationRender` | ||
if (!this.hasUnmounted) { | ||
this.unsubscribeAnimation(); | ||
this.unsubscribeAnimation = null; | ||
} | ||
var frameRate = now && !justStarted ? (Date.now() - now) / 1000 : FRAME_RATE; | ||
} | ||
var newCurrVals = updateCurrVals(frameRate, currVals, currV, endValue); | ||
var newCurrV = updateCurrV(frameRate, currVals, currV, endValue); | ||
return { | ||
currValue: newCurrValue, | ||
currVelocity: newCurrVelocity | ||
}; | ||
}, | ||
_this.setState(function () { | ||
return { | ||
currVals: newCurrVals, | ||
currV: newCurrV, | ||
now: Date.now() | ||
}; | ||
animationRender: function animationRender(alpha, nextState, prevState) { | ||
// `this.hasUnmounted` might be true in the following condition: | ||
// user does some checks in `endValue` and calls an owner handler | ||
// owner sets state in the callback, triggering a re-render | ||
// re-render unmounts the Spring | ||
if (!this.hasUnmounted) { | ||
this.setState({ | ||
currValue: interpolateValue(alpha, nextState.currValue, prevState.currValue), | ||
currVelocity: nextState.currVelocity | ||
}); | ||
var stop = noSpeed(newCurrV); | ||
if (stop && !justStarted) { | ||
// this flag is necessary, because in `endValue` callback, the user | ||
// might check that the current value has reached the destination, and | ||
// decide to return a new destination value. However, since s/he's | ||
// accessing the last tick's current value, and if we stop rafing after | ||
// speed is 0, the next `endValue` is never called and we never detect | ||
// the new chained animation. isLastRaf ensures that we raf a single | ||
// more time in case the user wants to chain another animation at the | ||
// end of this one | ||
if (isLastRaf) { | ||
_this._rafID = null; | ||
} else { | ||
_this.raf(false, true); | ||
} | ||
} else { | ||
_this.raf(false, false); | ||
} | ||
}); | ||
} | ||
}, | ||
render: function render() { | ||
var currVals = this.state.currVals; | ||
var currValue = this.state.currValue; | ||
return _react2['default'].Children.only(this.props.children(currVals)); | ||
return _react2['default'].Children.only(this.props.children(currValue)); | ||
} | ||
@@ -336,5 +287,20 @@ }); | ||
propTypes: { | ||
endValue: _react.PropTypes.oneOfType([_react.PropTypes.func, _react.PropTypes.object]).isRequired, | ||
willLeave: _react.PropTypes.oneOfType([_react.PropTypes.func, _react.PropTypes.object, _react.PropTypes.array]), | ||
willEnter: _react.PropTypes.oneOfType([_react.PropTypes.func, _react.PropTypes.object, _react.PropTypes.array]), | ||
endValue: _react.PropTypes.oneOfType([_react.PropTypes.func, _react.PropTypes.objectOf({ | ||
key: _react.PropTypes.any.isRequired | ||
})]). | ||
// coming soon | ||
// PropTypes.arrayOf(PropTypes.shape({ | ||
// key: PropTypes.any.isRequired, | ||
// })), | ||
// PropTypes.arrayOf(PropTypes.element), | ||
isRequired, | ||
willLeave: _react.PropTypes.oneOfType([_react.PropTypes.func]), | ||
// PropTypes.object, | ||
// PropTypes.array, | ||
// TODO: numbers? strings? | ||
willEnter: _react.PropTypes.oneOfType([_react.PropTypes.func]), | ||
// PropTypes.object, | ||
// PropTypes.array, | ||
children: _react.PropTypes.func.isRequired | ||
@@ -361,5 +327,4 @@ }, | ||
return { | ||
currVals: endValue, | ||
currV: _utils.mapTree(zero, endValue), | ||
now: null | ||
currValue: endValue, | ||
currVelocity: _mapTree2['default'](zero, endValue) | ||
}; | ||
@@ -369,148 +334,92 @@ }, | ||
componentDidMount: function componentDidMount() { | ||
this.raf(true, false); | ||
this.startAnimating(); | ||
}, | ||
componentWillReceiveProps: function componentWillReceiveProps() { | ||
this.raf(true, false); | ||
this.startAnimating(); | ||
}, | ||
unsubscribeAnimation: null, | ||
// used in animationRender | ||
hasUnmounted: false, | ||
componentWillUnmount: function componentWillUnmount() { | ||
cancelAnimationFrame(this._rafID); | ||
if (this.unsubscribeAnimation) { | ||
this.unsubscribeAnimation(); | ||
this.unsubscribeAnimation = undefined; | ||
} | ||
}, | ||
_rafID: null, | ||
startAnimating: function startAnimating() { | ||
if (!this.unsubscribeAnimation) { | ||
this.unsubscribeAnimation = animationLoop.subscribe(this.animationStep, this.animationRender, this.state); | ||
animationLoop.start(); | ||
} | ||
}, | ||
raf: function raf(justStarted, isLastRaf) { | ||
var _this2 = this; | ||
animationStep: function animationStep(timeStep, state) { | ||
var currValue = state.currValue; | ||
var currVelocity = state.currVelocity; | ||
var endValue = this.props.endValue; | ||
var _props = this.props; | ||
var willEnter = _props.willEnter; | ||
var willLeave = _props.willLeave; | ||
if (justStarted && this._rafID != null) { | ||
// already rafing | ||
return; | ||
if (typeof endValue === 'function') { | ||
endValue = endValue(currValue); | ||
} | ||
this._rafID = requestAnimationFrame(function () { | ||
var _state2 = _this2.state; | ||
var currVals = _state2.currVals; | ||
var currV = _state2.currV; | ||
var now = _this2.state.now; | ||
var endValue = _this2.props.endValue; | ||
var _props = _this2.props; | ||
var willEnter = _props.willEnter; | ||
var willLeave = _props.willLeave; | ||
if (typeof endValue === 'function') { | ||
endValue = endValue(currVals); | ||
} | ||
var mergedValue = undefined; | ||
// only other option is obj | ||
mergedValue = _mergeDiff2['default'](currValue, endValue, | ||
// TODO: stop allocating like crazy in this whole code path | ||
function (key) { | ||
return willLeave(key, currValue[key], endValue, currValue, currVelocity); | ||
}); | ||
var mergedVals = undefined; | ||
if (Array.isArray(endValue)) { | ||
(function () { | ||
var currValsObj = {}; | ||
currVals.forEach(function (objWithKey) { | ||
currValsObj[objWithKey.key] = objWithKey; | ||
}); | ||
var hasNewKey = false; | ||
Object.keys(mergedValue).filter(function (key) { | ||
return !currValue.hasOwnProperty(key); | ||
}).forEach(function (key) { | ||
hasNewKey = true; | ||
var enterValue = willEnter(key, mergedValue[key], endValue, currValue, currVelocity); | ||
currValue[key] = enterValue; | ||
mergedValue[key] = enterValue; | ||
currVelocity[key] = _mapTree2['default'](zero, currValue[key]); | ||
}); | ||
var endValueObj = {}; | ||
endValue.forEach(function (objWithKey) { | ||
endValueObj[objWithKey.key] = objWithKey; | ||
}); | ||
var currVObj = {}; | ||
endValue.forEach(function (objWithKey) { | ||
currVObj[objWithKey.key] = objWithKey; | ||
}); | ||
var newCurrValue = updateCurrValue(timeStep, currValue, currVelocity, mergedValue); | ||
var newCurrVelocity = updateCurrVelocity(timeStep, currValue, currVelocity, mergedValue); | ||
var mergedValsObj = mergeDiffObj(currValsObj, endValueObj, function (key) { | ||
return willLeave(key, endValue, currVals, currV); | ||
}); | ||
var mergedValsKeys = Object.keys(mergedValsObj); | ||
mergedVals = mergedValsKeys.map(function (key) { | ||
return mergedValsObj[key]; | ||
}); | ||
mergedValsKeys.filter(function (key) { | ||
return !currValsObj.hasOwnProperty(key); | ||
}).forEach(function (key) { | ||
currValsObj[key] = willEnter(key, mergedValsObj[key], endValue, currVals, currV); | ||
currVObj[key] = _utils.mapTree(zero, currValsObj[key]); | ||
}); | ||
currVals = Object.keys(currValsObj).map(function (key) { | ||
return currValsObj[key]; | ||
}); | ||
currV = Object.keys(currVObj).map(function (key) { | ||
return currVObj[key]; | ||
}); | ||
})(); | ||
} else { | ||
// only other option is obj | ||
mergedVals = mergeDiffObj(currVals, endValue, | ||
// TODO: stop allocating like crazy in this whole code path | ||
function (key) { | ||
return willLeave(key, endValue, currVals, currV); | ||
}); | ||
// TODO: check if this is necessary | ||
currVals = _utils.clone(currVals); | ||
currV = _utils.clone(currV); | ||
Object.keys(mergedVals).filter(function (key) { | ||
return !currVals.hasOwnProperty(key); | ||
}).forEach(function (key) { | ||
// TODO: param format changed, check other demos | ||
currVals[key] = willEnter(key, mergedVals[key], endValue, currVals, currV); | ||
currV[key] = _utils.mapTree(zero, currVals[key]); | ||
}); | ||
if (_noVelocity2['default'](currVelocity) && _noVelocity2['default'](newCurrVelocity) && !hasNewKey) { | ||
// check explanation in `Spring.animationRender` | ||
if (!this.hasUnmounted) { | ||
this.unsubscribeAnimation(); | ||
this.unsubscribeAnimation = undefined; | ||
} | ||
} | ||
var frameRate = now && !justStarted ? (Date.now() - now) / 1000 : FRAME_RATE; | ||
return { | ||
currValue: newCurrValue, | ||
currVelocity: newCurrVelocity | ||
}; | ||
}, | ||
var newCurrVals = updateCurrVals(frameRate, currVals, currV, mergedVals); | ||
var newCurrV = updateCurrV(frameRate, currVals, currV, mergedVals); | ||
_this2.setState(function () { | ||
return { | ||
currVals: newCurrVals, | ||
currV: newCurrV, | ||
now: Date.now() | ||
}; | ||
animationRender: function animationRender(alpha, nextState, prevState) { | ||
// See comment in Spring. | ||
if (!this.hasUnmounted) { | ||
this.setState({ | ||
currValue: interpolateValue(alpha, nextState.currValue, prevState.currValue), | ||
currVelocity: nextState.currVelocity | ||
}); | ||
var stop = noSpeed(newCurrV); | ||
if (stop && !justStarted) { | ||
if (isLastRaf) { | ||
_this2._rafID = null; | ||
} else { | ||
_this2.raf(false, true); | ||
} | ||
} else { | ||
_this2.raf(false, false); | ||
} | ||
}); | ||
} | ||
}, | ||
render: function render() { | ||
var currVals = this.state.currVals; | ||
var currValue = this.state.currValue; | ||
return _react2['default'].Children.only(this.props.children(currVals)); | ||
return _react2['default'].Children.only(this.props.children(currValue)); | ||
} | ||
}); | ||
exports.TransitionSpring = TransitionSpring; | ||
function reorderKeys(obj, f) { | ||
var ret = {}; | ||
f(Object.keys(obj)).forEach(function (key) { | ||
ret[key] = obj[key]; | ||
}); | ||
return ret; | ||
} | ||
var utils = { | ||
reorderKeys: reorderKeys | ||
}; | ||
exports.utils = utils; | ||
// coming soon | ||
// PropTypes.arrayOf(PropTypes.shape({ | ||
// key: PropTypes.any.isRequired, | ||
// })), | ||
// PropTypes.arrayOf(PropTypes.element), | ||
// TODO: numbers? strings? | ||
exports.TransitionSpring = TransitionSpring; |
{ | ||
"name": "react-motion", | ||
"version": "0.1.0", | ||
"version": "0.2.0", | ||
"description": "A spring that solves your animation problems.", | ||
@@ -20,2 +20,3 @@ "main": "lib/react-motion.js", | ||
"isparta": "^3.0.3", | ||
"lodash.range": "^3.0.1", | ||
"mocha": "^2.2.5", | ||
@@ -52,3 +53,8 @@ "react-hot-loader": "^1.2.8", | ||
"author": "chenglou", | ||
"license": "MIT" | ||
"license": "MIT", | ||
"dependencies": { | ||
"lodash.isplainobject": "^3.2.0", | ||
"performance-now": "^0.2.0", | ||
"raf": "^3.1.0" | ||
} | ||
} |
@@ -25,3 +25,3 @@ # React-Motion | ||
[Check](https://cdn.rawgit.com/chenglou/react-motion/cffb3894f42e4825178d9c7c0313b2f4e9e65ab2/demo0/index.html) [Out](https://cdn.rawgit.com/chenglou/react-motion/cffb3894f42e4825178d9c7c0313b2f4e9e65ab2/demo1/index.html) [The](https://cdn.rawgit.com/chenglou/react-motion/cffb3894f42e4825178d9c7c0313b2f4e9e65ab2/demo2/index.html) [Cool](https://cdn.rawgit.com/chenglou/react-motion/cffb3894f42e4825178d9c7c0313b2f4e9e65ab2/demo3/index.html) [Demos](https://cdn.rawgit.com/chenglou/react-motion/072fef7b84b2d57187643baa4156ee2a7374655f/demo4/index.html). | ||
[Check](https://cdn.rawgit.com/chenglou/react-motion/3b5be548cd08630a836562a053576ff91f94b93f/demo0/index.html) [Out](https://cdn.rawgit.com/chenglou/react-motion/3b5be548cd08630a836562a053576ff91f94b93f/demo1/index.html) [The](https://cdn.rawgit.com/chenglou/react-motion/3b5be548cd08630a836562a053576ff91f94b93f/demo2/index.html) [Cool](https://cdn.rawgit.com/chenglou/react-motion/3b5be548cd08630a836562a053576ff91f94b93f/demo3/index.html) [Demos](https://cdn.rawgit.com/chenglou/react-motion/3b5be548cd08630a836562a053576ff91f94b93f/demo4/index.html). | ||
@@ -67,3 +67,3 @@ ## What does this library try to solve? | ||
The library exports a default `Spring`, a `TransitionSpring` and `utils`. | ||
The library exports a `Spring`, a `TransitionSpring` and `utils`. | ||
@@ -189,9 +189,9 @@ ### <Spring /> | ||
### <TransitionSpring /> | ||
Like `Spring`, but can takes two other props: `willEnter` and `willLeave`. Throughout this section, please remember that "" | ||
Like `Spring`, but can take two other props: `willEnter` and `willLeave`. Throughout this section, please remember that | ||
`endValue`: now constrained to an object of the shape `{key => yourStuff}` (the data is constrained to this shape, but that doesn't mean the way you use your interpolated value has to be). When your the `endValue` provide differs from the current interpolated value by an added/removed key: | ||
`endValue`: now constrained to an object (or a callback `currentValue -> object`) of the shape `{key => yourStuff}` (the data is constrained to this shape, but that doesn't mean the way you use your interpolated value has to be). When `endValue` differs from the current interpolated value by an added/removed key: | ||
`willEnter`: a callback that's called **once** and is passed `(keyThatEnters, endValueYouJustSpecified, currentInterpolatedValue, currentSpeed)`. Return an object/array configuration that'll serve as the starting value of that new key. That configuration will be merged into `endValue`. The default value of `willEnter` is `(key, endValue) => endValue[key]`. It returns the same configuration as the one you just specified in `endValue`. In other words, the start and end are the same: no animation. | ||
`willEnter`: a callback that's called **once** and is passed `(keyThatEnters, correspondingValueOfKey, endValueYouJustSpecified, currentInterpolatedValue, currentSpeed)`. Return an object/array configuration that'll serve as the starting value of that new key. That configuration will be merged into `endValue`. The default value of `willEnter` is `(key, endValue) => endValue[key]`. It returns the same configuration as the one you just specified in `endValue`. In other words, the start and end are the same: no animation. | ||
`willLeave`: a callback that's called **many** times and is passed `(keyThatLeaves, endValueYouJustSpecified, currentInterpolatedValue, currentSpeed)`. Return an object/array configuration (which will serve as the new `endValue[keyThatLeaves]` and merged into `endValue`) to indicate you still want to keep the item around. Otherwise, return `null`. | ||
`willLeave`: a callback that's called **many** times and is passed `(keyThatLeaves, correspondingValueOfKeyThatJustLeft, endValueYouJustSpecified, currentInterpolatedValue, currentSpeed)`. Return an object/array configuration (which will serve as the new `endValue[keyThatLeaves]` and merged into `endValue`) to indicate you still want to keep the item around. Otherwise, return `null`. | ||
@@ -234,3 +234,3 @@ #### Sample Usage | ||
willLeave(key, endValue, currentValue, currentSpeed) { | ||
willLeave(key, value, endValue, currentValue, currentSpeed) { | ||
if (currentValue[key].opacity.val === 0 && currentSpeed[key].opacity.val === 0) { | ||
@@ -270,4 +270,5 @@ return null; // kill component when opacity reaches 0 | ||
); | ||
})}} | ||
})} | ||
</div> | ||
} | ||
</TransitionSpring> | ||
@@ -274,0 +275,0 @@ ); |
@@ -6,2 +6,3 @@ var webpack = require('webpack'); | ||
var config = { | ||
devtool: 'sourcemap', | ||
entry: { | ||
@@ -8,0 +9,0 @@ index: './src/react-motion.js' |
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
16
285
38244
4
15
693
+ Addedlodash.isplainobject@^3.2.0
+ Addedperformance-now@^0.2.0
+ Addedraf@^3.1.0
+ Addedlodash._basefor@3.0.3(transitive)
+ Addedlodash.isarguments@3.1.0(transitive)
+ Addedlodash.isarray@3.0.4(transitive)
+ Addedlodash.isplainobject@3.2.0(transitive)
+ Addedlodash.keysin@3.0.8(transitive)
+ Addedperformance-now@0.2.02.1.0(transitive)
+ Addedraf@3.4.1(transitive)