Skip to content

feat: add "getGoalValue" method to animated #789

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions packages/animated/src/Animated.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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<AnimatedValue> {
return this.payload!
Expand Down
4 changes: 4 additions & 0 deletions packages/animated/src/AnimatedArray.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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)) {
Expand Down
7 changes: 7 additions & 0 deletions packages/animated/src/AnimatedInterpolation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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<T extends Animatable>(...args: InterpolatorArgs<Out, T>): SpringValue<T> {
return new AnimatedInterpolation(this, args as any)
}
Expand Down
12 changes: 12 additions & 0 deletions packages/animated/src/AnimatedObject.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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) => {
Expand Down
6 changes: 6 additions & 0 deletions packages/animated/src/AnimatedValue.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ export class AnimatedValue<T = unknown> extends Animated
private views = new Set<AnimatedProps>()

value: T
goalValue: T
startPosition!: number
lastPosition!: number
lastVelocity?: number
Expand All @@ -21,6 +22,7 @@ export class AnimatedValue<T = unknown> extends Animated
constructor(value: T) {
super()
this.value = value
this.goalValue = value
this.payload = new Set([this])
if (is.num(value)) {
this.startPosition = value
Expand All @@ -32,6 +34,10 @@ export class AnimatedValue<T = unknown> extends Animated
return this.value
}

getGoalValue() {
return this.goalValue
}

setValue(value: T, flush?: boolean) {
this.value = value
if (flush !== false) {
Expand Down
13 changes: 13 additions & 0 deletions packages/core/src/Controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -620,6 +620,8 @@ export class Controller<State extends Indexable = any> {
}
}

updateGoalValue(animated, goalValue)

// Only change the "config" of updated animations.
const config: SpringConfig =
callProp(props.config, key) ||
Expand Down Expand Up @@ -716,6 +718,7 @@ export class Controller<State extends Indexable = any> {
// 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
}
Expand Down Expand Up @@ -802,6 +805,16 @@ function computeGoalValue<T>(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)) {
Expand Down
4 changes: 4 additions & 0 deletions packages/shared/src/types/animated.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,10 @@ export interface SpringValue<T = any> {
* 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.
Expand Down
10 changes: 10 additions & 0 deletions targets/native/src/AnimatedTransform.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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) => {
Expand Down
19 changes: 14 additions & 5 deletions targets/web/src/animated.ts
Original file line number Diff line number Diff line change
@@ -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<infer P>
? React.PropsWithoutRef<P> & { ref?: any }
: React.PropsWithRef<React.ComponentProps<T>>

type DOMComponents = {
[Tag in JSXElements]: AnimatedComponent<Tag>
}
Expand All @@ -23,10 +30,12 @@ export { animated as a }
export type AnimatedComponent<
T extends ElementType
> = ForwardRefExoticComponent<
AnimatedProps<Merge<ComponentPropsWithRef<T>, { style?: StyleProps }>> & {
scrollTop?: SpringValue<number> | number
scrollLeft?: SpringValue<number> | number
}
AnimatedProps<
Merge<
ComponentPropsWithRef<T>,
{ style?: StyleProps; scrollTop?: number; scrollLeft?: number }
>
>
>

/** The props of an `animated()` component */
Expand Down