From c841c34d1037e6b00a9f425e17782ccfbdb92a12 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Osadnik?= Date: Thu, 25 Apr 2019 10:49:54 +0200 Subject: [PATCH] Remove dependencies' cycles (#187) The main problems were with setValue and interpolate so I made them not available internally and exposed it with addition class. In internal operation InternalAnimatedValue is used and it's not causing dependencies' cycles. Changed logic of exposing nodes. Now there's no need to import whole base.js for wrapped nodes. --- src/animations/DecayAnimation.js | 2 +- src/animations/SpringAnimation.js | 2 +- src/animations/TimingAnimation.js | 2 +- src/animations/spring.js | 2 +- src/base.js | 127 ++++-------------------------- src/core/AnimatedAlways.js | 6 +- src/core/AnimatedBezier.js | 2 +- src/core/AnimatedBlock.js | 26 +++++- src/core/AnimatedCall.js | 8 +- src/core/AnimatedClock.js | 6 +- src/core/AnimatedClockTest.js | 6 +- src/core/AnimatedCode.js | 4 +- src/core/AnimatedConcat.js | 7 +- src/core/AnimatedCond.js | 13 ++- src/core/AnimatedDebug.js | 30 ++++++- src/core/AnimatedEvent.js | 16 ++-- src/core/AnimatedOperator.js | 9 ++- src/core/AnimatedSet.js | 9 ++- src/core/AnimatedStartClock.js | 6 +- src/core/AnimatedStopClock.js | 6 +- src/core/AnimatedValue.js | 56 ++----------- src/core/InternalAnimatedValue.js | 54 +++++++++++++ src/derived/acc.js | 2 +- src/derived/diff.js | 2 +- src/derived/diffClamp.js | 2 +- src/derived/evaluateOnce.js | 8 +- src/derived/interpolate.js | 5 +- src/derived/max.js | 2 +- src/derived/min.js | 2 +- src/derived/onChange.js | 2 +- src/operators.js | 29 +++++++ src/utils.js | 24 ------ src/val.js | 3 + 33 files changed, 251 insertions(+), 229 deletions(-) create mode 100644 src/core/InternalAnimatedValue.js create mode 100644 src/operators.js delete mode 100644 src/utils.js create mode 100644 src/val.js diff --git a/src/animations/DecayAnimation.js b/src/animations/DecayAnimation.js index 80eed20..a28ffe8 100644 --- a/src/animations/DecayAnimation.js +++ b/src/animations/DecayAnimation.js @@ -3,7 +3,7 @@ import Animation from './Animation'; import decay from './decay'; import { block, clockRunning, startClock, stopClock, cond } from '../base'; import Clock from '../core/AnimatedClock'; -import AnimatedValue from '../core/AnimatedValue'; +import AnimatedValue from '../core/InternalAnimatedValue'; class DecayAnimation extends Animation { constructor(config) { diff --git a/src/animations/SpringAnimation.js b/src/animations/SpringAnimation.js index b73eec8..2cde1c7 100644 --- a/src/animations/SpringAnimation.js +++ b/src/animations/SpringAnimation.js @@ -1,4 +1,4 @@ -import AnimatedValue from '../core/AnimatedValue'; +import AnimatedValue from '../core/InternalAnimatedValue'; import Animation from './Animation'; import SpringConfig from '../SpringConfig'; import spring from './spring'; diff --git a/src/animations/TimingAnimation.js b/src/animations/TimingAnimation.js index f18f608..369736e 100644 --- a/src/animations/TimingAnimation.js +++ b/src/animations/TimingAnimation.js @@ -1,4 +1,4 @@ -import AnimatedValue from '../core/AnimatedValue'; +import AnimatedValue from '../core/InternalAnimatedValue'; import timing from './timing'; import { block, clockRunning, startClock, stopClock, cond } from '../base'; import Clock from '../core/AnimatedClock'; diff --git a/src/animations/spring.js b/src/animations/spring.js index 6770d51..d27b345 100644 --- a/src/animations/spring.js +++ b/src/animations/spring.js @@ -18,7 +18,7 @@ import { greaterThan, } from '../base'; import { min, abs } from '../derived'; -import AnimatedValue from '../core/AnimatedValue'; +import AnimatedValue from '../core/InternalAnimatedValue'; const MAX_STEPS_MS = 64; diff --git a/src/base.js b/src/base.js index 921b7a9..17e6bfe 100644 --- a/src/base.js +++ b/src/base.js @@ -1,111 +1,16 @@ -import AnimatedCond from './core/AnimatedCond'; -import AnimatedSet from './core/AnimatedSet'; -import AnimatedOperator from './core/AnimatedOperator'; -import AnimatedStartClock from './core/AnimatedStartClock'; -import AnimatedStopClock from './core/AnimatedStopClock'; -import AnimatedClockTest from './core/AnimatedClockTest'; -import AnimatedDebug from './core/AnimatedDebug'; -import AnimatedCall from './core/AnimatedCall'; -import AnimatedEvent from './core/AnimatedEvent'; -import AnimatedAlways from './core/AnimatedAlways'; -import AnimatedConcat from './core/AnimatedConcat'; - -import { adapt } from './utils'; - -function operator(name) { - return (...args) => new AnimatedOperator(name, args.map(adapt)); -} - -export const add = operator('add'); -export const sub = operator('sub'); -export const multiply = operator('multiply'); -export const divide = operator('divide'); -export const pow = operator('pow'); -export const modulo = operator('modulo'); -export const sqrt = operator('sqrt'); -export const sin = operator('sin'); -export const cos = operator('cos'); -export const tan = operator('tan'); -export const acos = operator('acos'); -export const asin = operator('asin'); -export const atan = operator('atan'); -export const exp = operator('exp'); -export const round = operator('round'); -export const lessThan = operator('lessThan'); -export const eq = operator('eq'); -export const greaterThan = operator('greaterThan'); -export const lessOrEq = operator('lessOrEq'); -export const greaterOrEq = operator('greaterOrEq'); -export const neq = operator('neq'); -export const and = operator('and'); -export const or = operator('or'); -export const defined = operator('defined'); -export const not = operator('not'); - -export const set = function(what, value) { - return new AnimatedSet(what, adapt(value)); -}; - -export const cond = function(cond, ifBlock, elseBlock) { - return new AnimatedCond( - adapt(cond), - adapt(ifBlock), - elseBlock === undefined ? undefined : adapt(elseBlock) - ); -}; - -export const block = function(items) { - return adapt(items); -}; - -export const call = function(args, func) { - return new AnimatedCall(args, func); -}; - -export const debug = function(message, value) { - if (__DEV__) { - const runningInRemoteDebugger = typeof atob !== 'undefined'; - // hack to detect if app is running in remote debugger - // https://stackoverflow.com/questions/39022216 - - const runningInExpoShell = - global.Expo && global.Expo.Constants.appOwnership !== 'standalone'; - - if (runningInRemoteDebugger || runningInExpoShell) { - // When running in expo or remote debugger we use JS console.log to output variables - // otherwise we output to the native console using native debug node - return block([ - call([value], ([a]) => console.log(`${message} ${a}`)), - value, - ]); - } else { - return new AnimatedDebug(message, adapt(value)); - } - } - // Debugging is disabled in PROD - return value; -}; - -export const startClock = function(clock) { - return new AnimatedStartClock(clock); -}; - -export const always = function(item) { - return new AnimatedAlways(item); -}; - -export const concat = function(...args) { - return new AnimatedConcat(args.map(adapt)); -}; - -export const stopClock = function(clock) { - return new AnimatedStopClock(clock); -}; - -export const clockRunning = function(clock) { - return new AnimatedClockTest(clock); -}; - -export const event = function(argMapping, config) { - return new AnimatedEvent(argMapping, config); -}; +export { createAnimatedCond as cond } from './core/AnimatedCond'; +export { createAnimatedSet as set } from './core/AnimatedSet'; +export { + createAnimatedStartClock as startClock, +} from './core/AnimatedStartClock'; +export { createAnimatedStopClock as stopClock } from './core/AnimatedStopClock'; +export { + createAnimatedClockTest as clockRunning, +} from './core/AnimatedClockTest'; +export { createAnimatedDebug as debug } from './core/AnimatedDebug'; +export { createAnimatedCall as call } from './core/AnimatedCall'; +export { createAnimatedEvent as event } from './core/AnimatedEvent'; +export { createAnimatedAlways as always } from './core/AnimatedAlways'; +export { createAnimatedConcat as concat } from './core/AnimatedConcat'; +export { createAnimatedBlock as block, adapt } from './core/AnimatedBlock'; +export * from './operators'; diff --git a/src/core/AnimatedAlways.js b/src/core/AnimatedAlways.js index f92975e..0043096 100644 --- a/src/core/AnimatedAlways.js +++ b/src/core/AnimatedAlways.js @@ -1,6 +1,6 @@ import AnimatedNode from './AnimatedNode'; -export default class AnimatedAlways extends AnimatedNode { +class AnimatedAlways extends AnimatedNode { _what; constructor(what) { @@ -12,3 +12,7 @@ export default class AnimatedAlways extends AnimatedNode { return 0; } } + +export function createAnimatedAlways(item) { + return new AnimatedAlways(item); +} diff --git a/src/core/AnimatedBezier.js b/src/core/AnimatedBezier.js index 301ca46..ea64eb0 100644 --- a/src/core/AnimatedBezier.js +++ b/src/core/AnimatedBezier.js @@ -1,4 +1,4 @@ -import { val } from '../utils'; +import { val } from '../val'; import AnimatedNode from './AnimatedNode'; // These values are established by empiricism with tests (tradeoff: performance VS precision) diff --git a/src/core/AnimatedBlock.js b/src/core/AnimatedBlock.js index 9eee4e3..70b8aca 100644 --- a/src/core/AnimatedBlock.js +++ b/src/core/AnimatedBlock.js @@ -1,7 +1,8 @@ import AnimatedNode from './AnimatedNode'; -import { val } from '../utils'; +import { val } from '../val'; +import InternalAnimatedValue from './InternalAnimatedValue'; -export default class AnimatedBlock extends AnimatedNode { +class AnimatedBlock extends AnimatedNode { _array; constructor(array) { @@ -17,3 +18,24 @@ export default class AnimatedBlock extends AnimatedNode { return result; } } + +export function createAnimatedBlock(items) { + return adapt(items); +} + +function nodify(v) { + if (typeof v === 'object' && v.__isProxy) { + if (!v.__val) { + v.__val = new InternalAnimatedValue(0); + } + return v.__val; + } + // TODO: cache some typical static values (e.g. 0, 1, -1) + return v instanceof AnimatedNode ? v : new InternalAnimatedValue(v); +} + +export function adapt(v) { + return Array.isArray(v) + ? new AnimatedBlock(v.map(node => adapt(node))) + : nodify(v); +} diff --git a/src/core/AnimatedCall.js b/src/core/AnimatedCall.js index 5f9a98b..21ba3d6 100644 --- a/src/core/AnimatedCall.js +++ b/src/core/AnimatedCall.js @@ -1,5 +1,5 @@ import ReanimatedEventEmitter from '../ReanimatedEventEmitter'; -import { val } from '../utils'; +import { val } from '../val'; import AnimatedNode from './AnimatedNode'; const NODE_MAPPING = new Map(); @@ -9,7 +9,7 @@ function listener(data) { node && node._callback(data.args); } -export default class AnimatedCall extends AnimatedNode { +class AnimatedCall extends AnimatedNode { _callback; _args; @@ -40,3 +40,7 @@ export default class AnimatedCall extends AnimatedNode { return 0; } } + +export function createAnimatedCall(args, func) { + return new AnimatedCall(args, func); +} diff --git a/src/core/AnimatedClock.js b/src/core/AnimatedClock.js index a892784..e681d27 100644 --- a/src/core/AnimatedClock.js +++ b/src/core/AnimatedClock.js @@ -1,8 +1,8 @@ -import AnimatedValue from './AnimatedValue'; +import InternalAnimatedValue from './AnimatedValue'; import AnimatedNode from './AnimatedNode'; -import { val } from '../utils'; +import { val } from '../val'; -class AnimatedMainClock extends AnimatedValue { +class AnimatedMainClock extends InternalAnimatedValue { _frameCallback; constructor() { diff --git a/src/core/AnimatedClockTest.js b/src/core/AnimatedClockTest.js index fe07979..59e42de 100644 --- a/src/core/AnimatedClockTest.js +++ b/src/core/AnimatedClockTest.js @@ -2,7 +2,7 @@ import AnimatedNode from './AnimatedNode'; import AnimatedClock from './AnimatedClock'; import invariant from 'fbjs/lib/invariant'; -export default class AnimatedClockTest extends AnimatedNode { +class AnimatedClockTest extends AnimatedNode { _clockNode; constructor(clockNode) { @@ -18,3 +18,7 @@ export default class AnimatedClockTest extends AnimatedNode { return this._clockNode.isStarted() ? 1 : 0; } } + +export function createAnimatedClockTest(clock) { + return new AnimatedClockTest(clock); +} diff --git a/src/core/AnimatedCode.js b/src/core/AnimatedCode.js index 42250c2..7eb7d5b 100644 --- a/src/core/AnimatedCode.js +++ b/src/core/AnimatedCode.js @@ -1,5 +1,5 @@ import React from 'react'; -import AnimatedAlways from './AnimatedAlways'; +import { createAnimatedAlways } from './AnimatedAlways'; import AnimatedNode from './AnimatedNode'; class Code extends React.Component { @@ -33,7 +33,7 @@ class Code extends React.Component { ); } - this.always = new AnimatedAlways(nodeExec || nodeChildren); + this.always = createAnimatedAlways(nodeExec || nodeChildren); this.always.__attach(); } diff --git a/src/core/AnimatedConcat.js b/src/core/AnimatedConcat.js index 1201655..f875106 100644 --- a/src/core/AnimatedConcat.js +++ b/src/core/AnimatedConcat.js @@ -1,7 +1,12 @@ import AnimatedNode from './AnimatedNode'; +import { adapt } from '../core/AnimatedBlock'; -export default class AnimatedConcat extends AnimatedNode { +class AnimatedConcat extends AnimatedNode { constructor(input) { super({ type: 'concat', input: input.map(n => n.__nodeID) }, input); } } + +export function createAnimatedConcat(...args) { + return new AnimatedConcat(args.map(adapt)); +} diff --git a/src/core/AnimatedCond.js b/src/core/AnimatedCond.js index 295c00d..475b2ad 100644 --- a/src/core/AnimatedCond.js +++ b/src/core/AnimatedCond.js @@ -1,7 +1,8 @@ -import { val } from '../utils'; +import { val } from '../val'; import AnimatedNode from './AnimatedNode'; +import { adapt } from '../core/AnimatedBlock'; -export default class AnimatedCond extends AnimatedNode { +class AnimatedCond extends AnimatedNode { _condition; _ifBlock; _elseBlock; @@ -29,3 +30,11 @@ export default class AnimatedCond extends AnimatedNode { } } } + +export function createAnimatedCond(cond, ifBlock, elseBlock) { + return new AnimatedCond( + adapt(cond), + adapt(ifBlock), + elseBlock === undefined ? undefined : adapt(elseBlock) + ); +} diff --git a/src/core/AnimatedDebug.js b/src/core/AnimatedDebug.js index 2344a9a..a37dad3 100644 --- a/src/core/AnimatedDebug.js +++ b/src/core/AnimatedDebug.js @@ -1,7 +1,9 @@ -import { val } from '../utils'; +import { val } from '../val'; import AnimatedNode from './AnimatedNode'; +import { createAnimatedBlock as block, adapt } from './AnimatedBlock'; +import { createAnimatedCall as call } from './AnimatedCall'; -export default class AnimatedDebug extends AnimatedNode { +class AnimatedDebug extends AnimatedNode { _message; _value; @@ -17,3 +19,27 @@ export default class AnimatedDebug extends AnimatedNode { return value; } } + +export function createAnimatedDebug(message, value) { + if (__DEV__) { + const runningInRemoteDebugger = typeof atob !== 'undefined'; + // hack to detect if app is running in remote debugger + // https://stackoverflow.com/questions/39022216 + + const runningInExpoShell = + global.Expo && global.Expo.Constants.appOwnership !== 'standalone'; + + if (runningInRemoteDebugger || runningInExpoShell) { + // When running in expo or remote debugger we use JS console.log to output variables + // otherwise we output to the native console using native debug node + return block([ + call([value], ([a]) => console.log(`${message} ${a}`)), + value, + ]); + } else { + return new AnimatedDebug(message, adapt(value)); + } + } + // Debugging is disabled in PROD + return value; +} diff --git a/src/core/AnimatedEvent.js b/src/core/AnimatedEvent.js index 9623e57..5f60d66 100644 --- a/src/core/AnimatedEvent.js +++ b/src/core/AnimatedEvent.js @@ -2,8 +2,8 @@ import { findNodeHandle } from 'react-native'; import ReanimatedModule from '../ReanimatedModule'; import AnimatedNode from './AnimatedNode'; -import AnimatedValue from './AnimatedValue'; -import AnimatedAlways from './AnimatedAlways'; +import InternalAnimatedValue from './AnimatedValue'; +import { createAnimatedAlways } from './AnimatedAlways'; import invariant from 'fbjs/lib/invariant'; import createEventObjectProxyPolyfill from './createEventObjectProxyPolyfill'; @@ -15,13 +15,13 @@ function sanitizeArgMapping(argMapping) { const alwaysNodes = []; const traverse = (value, path) => { - if (value instanceof AnimatedValue) { + if (value instanceof InternalAnimatedValue) { eventMappings.push(path.concat(value.__nodeID)); } else if (typeof value === 'object' && value.__val) { eventMappings.push(path.concat(value.__val.__nodeID)); } else if (typeof value === 'function') { - const node = new AnimatedValue(0); - alwaysNodes.push(new AnimatedAlways(value(node))); + const node = new InternalAnimatedValue(0); + alwaysNodes.push(createAnimatedAlways(value(node))); eventMappings.push(path.concat(node.__nodeID)); } else if (typeof value === 'object') { for (const key in value) { @@ -61,7 +61,7 @@ function sanitizeArgMapping(argMapping) { typeof Proxy === 'function' ? new Proxy({}, proxyHandler) : createEventObjectProxyPolyfill(); - alwaysNodes.push(new AnimatedAlways(ev(proxy))); + alwaysNodes.push(createAnimatedAlways(ev(proxy))); traverse(proxy, []); } @@ -99,3 +99,7 @@ export default class AnimatedEvent extends AnimatedNode { this.__detach(); } } + +export function createAnimatedEvent(argMapping, config) { + return new AnimatedEvent(argMapping, config); +} diff --git a/src/core/AnimatedOperator.js b/src/core/AnimatedOperator.js index ad30fe1..90c47f8 100644 --- a/src/core/AnimatedOperator.js +++ b/src/core/AnimatedOperator.js @@ -1,7 +1,8 @@ import AnimatedNode from './AnimatedNode'; -import { val } from '../utils'; +import { val } from '../val'; import invariant from 'fbjs/lib/invariant'; +import { adapt } from '../core/AnimatedBlock'; function reduce(fn) { return input => input.reduce((a, b) => fn(val(a), val(b))); @@ -53,7 +54,7 @@ const OPERATIONS = { neq: infix((a, b) => a != b), }; -export default class AnimatedOperator extends AnimatedNode { +class AnimatedOperator extends AnimatedNode { _input; _op; _operation; @@ -75,3 +76,7 @@ export default class AnimatedOperator extends AnimatedNode { return this._operation(this._input); } } + +export function createAnimatedOperator(name) { + return (...args) => new AnimatedOperator(name, args.map(adapt)); +} diff --git a/src/core/AnimatedSet.js b/src/core/AnimatedSet.js index 0983776..ad1a7c7 100644 --- a/src/core/AnimatedSet.js +++ b/src/core/AnimatedSet.js @@ -1,7 +1,8 @@ import AnimatedNode from './AnimatedNode'; -import { val } from '../utils'; +import { val } from '../val'; +import { adapt } from '../core/AnimatedBlock'; -export default class AnimatedSet extends AnimatedNode { +class AnimatedSet extends AnimatedNode { _what; _value; @@ -17,3 +18,7 @@ export default class AnimatedSet extends AnimatedNode { return newValue; } } + +export function createAnimatedSet(what, value) { + return new AnimatedSet(what, adapt(value)); +} diff --git a/src/core/AnimatedStartClock.js b/src/core/AnimatedStartClock.js index 7d273fd..3b4f4de 100644 --- a/src/core/AnimatedStartClock.js +++ b/src/core/AnimatedStartClock.js @@ -2,7 +2,7 @@ import AnimatedNode from './AnimatedNode'; import AnimatedClock from './AnimatedClock'; import invariant from 'fbjs/lib/invariant'; -export default class AnimatedStartClock extends AnimatedNode { +class AnimatedStartClock extends AnimatedNode { _clockNode; constructor(clockNode) { @@ -19,3 +19,7 @@ export default class AnimatedStartClock extends AnimatedNode { return 0; } } + +export function createAnimatedStartClock(clock) { + return new AnimatedStartClock(clock); +} diff --git a/src/core/AnimatedStopClock.js b/src/core/AnimatedStopClock.js index af87ecd..d4f5aa6 100644 --- a/src/core/AnimatedStopClock.js +++ b/src/core/AnimatedStopClock.js @@ -2,7 +2,7 @@ import AnimatedNode from './AnimatedNode'; import AnimatedClock from './AnimatedClock'; import invariant from 'fbjs/lib/invariant'; -export default class AnimatedStopClock extends AnimatedNode { +class AnimatedStopClock extends AnimatedNode { _clockNode; constructor(clockNode) { @@ -19,3 +19,7 @@ export default class AnimatedStopClock extends AnimatedNode { return 0; } } + +export function createAnimatedStopClock(clock) { + return new AnimatedStopClock(clock); +} diff --git a/src/core/AnimatedValue.js b/src/core/AnimatedValue.js index 768d09a..2b98d3b 100644 --- a/src/core/AnimatedValue.js +++ b/src/core/AnimatedValue.js @@ -1,56 +1,10 @@ -import AnimatedNode from './AnimatedNode'; -import { set } from '../base'; -import { val } from '../utils'; -import { evaluateOnce } from '../derived/evaluateOnce'; +import { createAnimatedSet as set } from '../core/AnimatedSet'; import interpolate from '../derived/interpolate'; -import ReanimatedModule from '../ReanimatedModule'; - -function sanitizeValue(value) { - return value === null || value === undefined || typeof value === 'string' - ? value - : Number(value); -} - -export default class AnimatedValue extends AnimatedNode { - constructor(value) { - super({ type: 'value', value: sanitizeValue(value) }); - this._startingValue = this._value = value; - this._animation = null; - } - - __detach() { - ReanimatedModule.getValue( - this.__nodeID, - val => (this.__nodeConfig.value = val) - ); - this.__detachAnimation(this._animation); - super.__detach(); - } - - __detachAnimation(animation) { - animation && animation.__detach(); - if (this._animation === animation) { - this._animation = null; - } - } - - __attachAnimation(animation) { - this.__detachAnimation(this._animation); - this._animation = animation; - } - - __onEvaluate() { - if (this.__inputNodes && this.__inputNodes.length) { - this.__inputNodes.forEach(val); - } - return this._value + this._offset; - } - - _updateValue(value) { - this._value = value; - this.__forceUpdateCache(value); - } +import InternalAnimatedValue from './InternalAnimatedValue'; +import { evaluateOnce } from '../derived/evaluateOnce'; +// Animated value wrapped with extra methods for omit cycle of dependencies +export default class AnimatedValue extends InternalAnimatedValue { setValue(value) { this.__detachAnimation(this._animation); evaluateOnce(set(this, value), this); diff --git a/src/core/InternalAnimatedValue.js b/src/core/InternalAnimatedValue.js new file mode 100644 index 0000000..c4a56d9 --- /dev/null +++ b/src/core/InternalAnimatedValue.js @@ -0,0 +1,54 @@ +import AnimatedNode from './AnimatedNode'; +import { val } from '../val'; +import ReanimatedModule from '../ReanimatedModule'; + +function sanitizeValue(value) { + return value === null || value === undefined || typeof value === 'string' + ? value + : Number(value); +} + +/** + * This class has been made internal in order to omit dependencies' cycles which + * were caused by imperative setValue and interpolate – they are currently exposed with AnimatedValue.js + */ +export default class InternalAnimatedValue extends AnimatedNode { + constructor(value) { + super({ type: 'value', value: sanitizeValue(value) }); + this._startingValue = this._value = value; + this._animation = null; + } + + __detach() { + ReanimatedModule.getValue( + this.__nodeID, + val => (this.__nodeConfig.value = val) + ); + this.__detachAnimation(this._animation); + super.__detach(); + } + + __detachAnimation(animation) { + animation && animation.__detach(); + if (this._animation === animation) { + this._animation = null; + } + } + + __attachAnimation(animation) { + this.__detachAnimation(this._animation); + this._animation = animation; + } + + __onEvaluate() { + if (this.__inputNodes && this.__inputNodes.length) { + this.__inputNodes.forEach(val); + } + return this._value + this._offset; + } + + _updateValue(value) { + this._value = value; + this.__forceUpdateCache(value); + } +} diff --git a/src/derived/acc.js b/src/derived/acc.js index 6c2f2fe..6d4975a 100644 --- a/src/derived/acc.js +++ b/src/derived/acc.js @@ -1,5 +1,5 @@ import { set, add } from '../base'; -import AnimatedValue from '../core/AnimatedValue'; +import AnimatedValue from '../core/InternalAnimatedValue'; export default function acc(v) { const acc = new AnimatedValue(0); diff --git a/src/derived/diff.js b/src/derived/diff.js index ce54d38..25fdf98 100644 --- a/src/derived/diff.js +++ b/src/derived/diff.js @@ -1,5 +1,5 @@ import { cond, block, defined, sub, set } from '../base'; -import AnimatedValue from '../core/AnimatedValue'; +import AnimatedValue from '../core/InternalAnimatedValue'; export default function diff(v) { const stash = new AnimatedValue(0); diff --git a/src/derived/diffClamp.js b/src/derived/diffClamp.js index ed94057..32802b5 100644 --- a/src/derived/diffClamp.js +++ b/src/derived/diffClamp.js @@ -1,5 +1,5 @@ import { cond, defined, set, add } from '../base'; -import AnimatedValue from '../core/AnimatedValue'; +import AnimatedValue from '../core/InternalAnimatedValue'; import min from './min'; import max from './max'; import diff from './diff'; diff --git a/src/derived/evaluateOnce.js b/src/derived/evaluateOnce.js index ac4c7ee..8e81b37 100644 --- a/src/derived/evaluateOnce.js +++ b/src/derived/evaluateOnce.js @@ -1,5 +1,8 @@ -import AnimatedValue from '../core/AnimatedValue'; -import { call, always, cond, set } from '../base'; +import AnimatedValue from '../core/InternalAnimatedValue'; +import { createAnimatedSet as set } from '../core/AnimatedSet'; +import { createAnimatedCall as call } from '../core/AnimatedCall'; +import { createAnimatedAlways as always } from '../core/AnimatedAlways'; +import { createAnimatedCond as cond } from '../core/AnimatedCond'; /** * evaluate given node and notify children @@ -7,6 +10,7 @@ import { call, always, cond, set } from '../base'; * @param input - nodes (or one node) representing values which states input for node. * @param callback - after callback */ + export function evaluateOnce(node, input = [], callback) { if (!Array.isArray(input)) { input = [input]; diff --git a/src/derived/interpolate.js b/src/derived/interpolate.js index 616be80..d673a5d 100644 --- a/src/derived/interpolate.js +++ b/src/derived/interpolate.js @@ -1,12 +1,13 @@ import { - cond, lessThan, multiply, sub, add, divide, greaterThan, -} from '../base'; +} from '../operators'; + +import { createAnimatedCond as cond } from '../core/AnimatedCond'; import invariant from 'fbjs/lib/invariant'; import AnimatedNode from '../core/AnimatedNode'; diff --git a/src/derived/max.js b/src/derived/max.js index bec8d47..88d889f 100644 --- a/src/derived/max.js +++ b/src/derived/max.js @@ -1,5 +1,5 @@ import { cond, lessThan } from '../base'; -import { adapt } from '../utils'; +import { adapt } from '../core/AnimatedBlock'; export default function max(a, b) { a = adapt(a); diff --git a/src/derived/min.js b/src/derived/min.js index 84651d7..81ebfb2 100644 --- a/src/derived/min.js +++ b/src/derived/min.js @@ -1,5 +1,5 @@ import { cond, lessThan } from '../base'; -import { adapt } from '../utils'; +import { adapt } from '../core/AnimatedBlock'; export default function min(a, b) { a = adapt(a); diff --git a/src/derived/onChange.js b/src/derived/onChange.js index b25abbe..53468de 100644 --- a/src/derived/onChange.js +++ b/src/derived/onChange.js @@ -1,5 +1,5 @@ import { block, cond, defined, neq, not, set } from '../base'; -import AnimatedValue from '../core/AnimatedValue'; +import AnimatedValue from '../core/InternalAnimatedValue'; export default function onChange(value, action) { const prevValue = new AnimatedValue(); diff --git a/src/operators.js b/src/operators.js new file mode 100644 index 0000000..44ac71f --- /dev/null +++ b/src/operators.js @@ -0,0 +1,29 @@ +import { createAnimatedOperator } from './core/AnimatedOperator'; + +const operator = createAnimatedOperator; + +export const add = operator('add'); +export const sub = operator('sub'); +export const multiply = operator('multiply'); +export const divide = operator('divide'); +export const pow = operator('pow'); +export const modulo = operator('modulo'); +export const sqrt = operator('sqrt'); +export const sin = operator('sin'); +export const cos = operator('cos'); +export const exp = operator('exp'); +export const round = operator('round'); +export const lessThan = operator('lessThan'); +export const eq = operator('eq'); +export const greaterThan = operator('greaterThan'); +export const lessOrEq = operator('lessOrEq'); +export const greaterOrEq = operator('greaterOrEq'); +export const neq = operator('neq'); +export const and = operator('and'); +export const or = operator('or'); +export const defined = operator('defined'); +export const not = operator('not'); +export const tan = operator('tan'); +export const acos = operator('acos'); +export const asin = operator('asin'); +export const atan = operator('atan'); diff --git a/src/utils.js b/src/utils.js deleted file mode 100644 index 52d56da..0000000 --- a/src/utils.js +++ /dev/null @@ -1,24 +0,0 @@ -import AnimatedBlock from './core/AnimatedBlock'; -import AnimatedNode from './core/AnimatedNode'; -import AnimatedValue from './core/AnimatedValue'; - -function nodify(v) { - if (typeof v === 'object' && v.__isProxy) { - if (!v.__val) { - v.__val = new AnimatedValue(0); - } - return v.__val; - } - // TODO: cache some typical static values (e.g. 0, 1, -1) - return v instanceof AnimatedNode ? v : new AnimatedValue(v); -} - -export function adapt(v) { - return Array.isArray(v) - ? new AnimatedBlock(v.map(node => adapt(node))) - : nodify(v); -} - -export function val(v) { - return v && v.__getValue ? v.__getValue() : v || 0; -} diff --git a/src/val.js b/src/val.js new file mode 100644 index 0000000..13ed220 --- /dev/null +++ b/src/val.js @@ -0,0 +1,3 @@ +export function val(v) { + return v && v.__getValue ? v.__getValue() : v || 0; +}