From dc142d7499f864120dca517a6ebac16b6e9fb159 Mon Sep 17 00:00:00 2001 From: Alec Larson Date: Mon, 19 Aug 2019 15:06:28 -0400 Subject: [PATCH 1/2] fix(ts): avoid 2^111 materialization of Ref in @types/react This is a bug in TypeScript that manifests in @types/react. This commit is temporary pain relief for #613. The "ref" prop is no longer typed. More info here: https://github.com/microsoft/TypeScript/issues/29949 --- targets/web/src/animated.ts | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/targets/web/src/animated.ts b/targets/web/src/animated.ts index 86a503307a..8283af19c3 100644 --- a/targets/web/src/animated.ts +++ b/targets/web/src/animated.ts @@ -1,8 +1,15 @@ import { withAnimated, extendAnimated } from '@react-spring/animated' import { CSSProperties, ForwardRefExoticComponent } from 'react' -import { SpringValue, ElementType, ComponentPropsWithRef, Merge } from 'shared' +import { SpringValue, ElementType, Merge } from 'shared' import { elements, JSXElements } from './elements' +// Avoid https://github.com/microsoft/TypeScript/issues/29949 +type ComponentPropsWithRef< + T extends ElementType +> = T extends React.ComponentClass + ? React.PropsWithoutRef

& { ref?: any } + : React.PropsWithRef> + type DOMComponents = { [Tag in JSXElements]: AnimatedComponent } @@ -23,10 +30,12 @@ export { animated as a } export type AnimatedComponent< T extends ElementType > = ForwardRefExoticComponent< - AnimatedProps, { style?: StyleProps }>> & { - scrollTop?: SpringValue | number - scrollLeft?: SpringValue | number - } + AnimatedProps< + Merge< + ComponentPropsWithRef, + { style?: StyleProps; scrollTop?: number; scrollLeft?: number } + > + > > /** The props of an `animated()` component */ From 7b7d9aea28b58663b09d2804659c4b9f6761b4e0 Mon Sep 17 00:00:00 2001 From: Alien Date: Fri, 23 Aug 2019 09:01:45 +0800 Subject: [PATCH 2/2] feat: add "getGoalValue" method to animated Updated the controller to set/update the goal value to each AnimatedValue upon animation starts and stops. --- packages/animated/src/Animated.ts | 3 +++ packages/animated/src/AnimatedArray.ts | 4 ++++ packages/animated/src/AnimatedInterpolation.ts | 7 +++++++ packages/animated/src/AnimatedObject.ts | 12 ++++++++++++ packages/animated/src/AnimatedValue.ts | 6 ++++++ packages/core/src/Controller.ts | 13 +++++++++++++ packages/shared/src/types/animated.ts | 4 ++++ targets/native/src/AnimatedTransform.ts | 10 ++++++++++ 8 files changed, 59 insertions(+) diff --git a/packages/animated/src/Animated.ts b/packages/animated/src/Animated.ts index 583c858d8c..87d8003409 100644 --- a/packages/animated/src/Animated.ts +++ b/packages/animated/src/Animated.ts @@ -12,6 +12,9 @@ export abstract class Animated { /** Returns all values contained by this node. Pass true for only the animated values. */ abstract getValue(animated?: boolean): any + /** Returns all goal values contained by this node. Pass true for only the animated values. */ + abstract getGoalValue(animated?: boolean): any + /** Returns the set of `AnimatedValue` nodes contained by this node. */ getPayload(): ReadonlySet { return this.payload! diff --git a/packages/animated/src/AnimatedArray.ts b/packages/animated/src/AnimatedArray.ts index 575c536fb9..7674008266 100644 --- a/packages/animated/src/AnimatedArray.ts +++ b/packages/animated/src/AnimatedArray.ts @@ -17,6 +17,10 @@ export class AnimatedArray extends AnimatedObject return this.source.map(node => node.getValue(animated)) } + getGoalValue(animated?: boolean) { + return this.source.map(node => node.getGoalValue(animated)) + } + setValue(value: any, flush?: boolean) { const nodes = this.payload if (is.arr(value)) { diff --git a/packages/animated/src/AnimatedInterpolation.ts b/packages/animated/src/AnimatedInterpolation.ts index 895c4c741e..2b177e8870 100644 --- a/packages/animated/src/AnimatedInterpolation.ts +++ b/packages/animated/src/AnimatedInterpolation.ts @@ -34,6 +34,13 @@ export class AnimatedInterpolation< return (this.calc as any)(...args) } + getGoalValue(animated?: boolean): Out { + const args = is.arr(this.source) + ? this.source.map(node => node.getGoalValue(animated)) + : toArray(this.source.getGoalValue(animated)) + return (this.calc as any)(...args) + } + to(...args: InterpolatorArgs): SpringValue { return new AnimatedInterpolation(this, args as any) } diff --git a/packages/animated/src/AnimatedObject.ts b/packages/animated/src/AnimatedObject.ts index 5500cd47e0..c6a3ab2e7c 100644 --- a/packages/animated/src/AnimatedObject.ts +++ b/packages/animated/src/AnimatedObject.ts @@ -21,6 +21,18 @@ export class AnimatedObject extends Animated { return obj } + getGoalValue(animated?: boolean) { + const obj: any = {} + each(this.source, (val, key) => { + if (isAnimated(val)) { + obj[key] = val.getGoalValue(animated) + } else if (!animated) { + obj[key] = val + } + }) + return obj + } + updatePayload(prev: Animated, next: Animated) { const source = { ...this.source } each(source, (val, key) => { diff --git a/packages/animated/src/AnimatedValue.ts b/packages/animated/src/AnimatedValue.ts index d4bb5c5f6d..0b600e21b9 100644 --- a/packages/animated/src/AnimatedValue.ts +++ b/packages/animated/src/AnimatedValue.ts @@ -11,6 +11,7 @@ export class AnimatedValue extends Animated private views = new Set() value: T + goalValue: T startPosition!: number lastPosition!: number lastVelocity?: number @@ -21,6 +22,7 @@ export class AnimatedValue extends Animated constructor(value: T) { super() this.value = value + this.goalValue = value this.payload = new Set([this]) if (is.num(value)) { this.startPosition = value @@ -32,6 +34,10 @@ export class AnimatedValue extends Animated return this.value } + getGoalValue() { + return this.goalValue + } + setValue(value: T, flush?: boolean) { this.value = value if (flush !== false) { diff --git a/packages/core/src/Controller.ts b/packages/core/src/Controller.ts index b1c81f44cc..cf04537a42 100644 --- a/packages/core/src/Controller.ts +++ b/packages/core/src/Controller.ts @@ -620,6 +620,8 @@ export class Controller { } } + updateGoalValue(animated, goalValue) + // Only change the "config" of updated animations. const config: SpringConfig = callProp(props.config, key) || @@ -716,6 +718,7 @@ export class Controller { // The current value becomes the goal value, // which ensures the integrity of the diffing algorithm. const goalValue = animated.getValue() + updateGoalValue(animated, goalValue) if (this.props.to) { this.props.to[key] = goalValue } @@ -802,6 +805,16 @@ function computeGoalValue(value: T): T { : value } +// Update the goal value of animated +function updateGoalValue(animated: Animated, goalValue: any) { + if (animated instanceof AnimatedArray) { + const nodes = animated.getPayload() + each(nodes, node => (node.goalValue = goalValue)) + } else if (animated instanceof AnimatedValue) { + animated.goalValue = goalValue + } +} + // Compare animatable values function isEqual(a: Animatable, b: Animatable) { if (is.arr(a)) { diff --git a/packages/shared/src/types/animated.ts b/packages/shared/src/types/animated.ts index 9ebaa3ce8f..9a64d1b3b3 100644 --- a/packages/shared/src/types/animated.ts +++ b/packages/shared/src/types/animated.ts @@ -23,6 +23,10 @@ export interface SpringValue { * is assigned to a property of an `animated` element. */ getValue(): T + /** + * Get the animated goal value. + */ + getGoalValue(): T /** * Interpolate the value with a custom interpolation function, * a configuration object, or keyframe-like ranges. diff --git a/targets/native/src/AnimatedTransform.ts b/targets/native/src/AnimatedTransform.ts index 5ff8a2bf34..6dfc058a01 100644 --- a/targets/native/src/AnimatedTransform.ts +++ b/targets/native/src/AnimatedTransform.ts @@ -25,6 +25,16 @@ export class AnimatedTransform extends Animated { }) } + getGoalValue() { + return this.source.map(transform => { + const obj: any = {} + each(transform, (val, key) => { + obj[key] = isAnimated(val) ? val.getGoalValue() : val + }) + return obj + }) + } + updatePayload(prev: Animated, next: Animated) { const source = [...this.source] each(source, (transform, i) => {