Skip to content

Commit

Permalink
passing current and velocity to dynamic poses
Browse files Browse the repository at this point in the history
  • Loading branch information
mattgperry committed Nov 20, 2018
1 parent ad6deda commit 90a8b02
Show file tree
Hide file tree
Showing 8 changed files with 82 additions and 30 deletions.
3 changes: 3 additions & 0 deletions TODO.md
Expand Up @@ -4,6 +4,9 @@
- Add Rollup for production bundle generation (will save multiple kb)

## Features
- Fix prop types on `motion`
- Add intelligent defaults
- Add velocity tracking
- Coordination across children (ie `staggerChildren`)
- Gestures
- `setPose.cycle`
23 changes: 23 additions & 0 deletions dev/examples/dynamic-pose.tsx
@@ -0,0 +1,23 @@
import * as React from 'react';
import { motion, usePose } from '@framer';
import { Box } from '../styled';
import useInterval from '../inc/use-interval';

const MotionBox = motion(Box)({
ping: {
x: 100,
y: '0vh',
transition: { duration: 100 }
},
pong: ({ target }) => ({ x: target, y: '0vh' })
});

export const App = () => {
const [pose, setPose] = usePose('ping');

useInterval(() => {
setPose(pose.get() === 'ping' ? 'pong' : 'ping');
}, 1000);

return <MotionBox pose={pose} target={-100} />;
};
7 changes: 6 additions & 1 deletion src/hooks/use-pose-resolver.ts
Expand Up @@ -2,6 +2,7 @@ import { useRef, useEffect, MutableRefObject } from 'react';
import { invariant } from 'hey-listen';
import getTransition from '../utils/transitions';
import { poseToArray } from '../utils/pose-resolvers';
import { resolveCurrent, resolveVelocity } from '../utils/resolve-values';
import { MotionValue } from '../motion-value';
import { PoseConfig, MotionProps, PoseResolver, Pose } from '../motion/types';

Expand All @@ -20,7 +21,11 @@ const createPoseResolver = (

const pose: Pose =
typeof config[poseKey] === 'function'
? (config[poseKey] as PoseResolver)(props)
? (config[poseKey] as PoseResolver)(
props,
resolveCurrent(values),
resolveVelocity(values)
)
: (config[poseKey] as Pose);

const { transition, ...thisPose } = pose;
Expand Down
2 changes: 1 addition & 1 deletion src/hooks/use-posed-values.ts
Expand Up @@ -37,7 +37,7 @@ export default (
if (!poseDef) return;

const initialPose =
typeof poseDef === 'function' ? poseDef(props) : poseDef;
typeof poseDef === 'function' ? poseDef(props, {}, {}) : poseDef;

// We'll need to filter out options like staggerChildren etc
Object.keys(initialPose).forEach(valueKey => {
Expand Down
15 changes: 7 additions & 8 deletions src/hooks/use-style-attr.ts
@@ -1,17 +1,16 @@
import { useMemo, CSSProperties } from 'react';
import { buildStyleProperty } from 'stylefire';
import { MotionValue } from '../motion-value';
import { resolveCurrent } from '../utils/resolve-values';

export default (
values: Map<string, MotionValue>,
styles?: CSSProperties
): CSSProperties =>
useMemo(() => {
const resolvedValues = {};
values.forEach((value, key) => (resolvedValues[key] = value.get()));

return {
useMemo(
() => ({
...styles,
...buildStyleProperty(resolvedValues)
};
}, []);
...buildStyleProperty(resolveCurrent(values))
}),
[]
);
37 changes: 20 additions & 17 deletions src/motion/types.ts
Expand Up @@ -25,6 +25,8 @@ export type MotionProps = {

export type EasingFunction = (v: number) => number;

export type CubicBezier = [number, number, number, number];

export type Easing =
| CubicBezier
| 'linear'
Expand All @@ -40,10 +42,14 @@ export type Easing =
| 'anticipate'
| EasingFunction;

export type Tween = {
type?: 'tween';
export type BaseTransition = {
from?: number | string;
to?: number | string;
velocity?: number;
};

export type Tween = BaseTransition & {
type?: 'tween';
duration?: number;
ease?: Easing;
elapsed?: number;
Expand All @@ -52,31 +58,24 @@ export type Tween = {
yoyo?: number;
};

export type Spring = {
export type Spring = BaseTransition & {
type: 'spring';
from?: number | string;
to?: number | string;
stiffness?: number;
damping?: number;
mass?: number;
velocity?: number;
restSpeed?: number;
restDelta?: number;
};

export type Decay = {
export type Decay = BaseTransition & {
type: 'decay';
velocity?: number;
from?: number | string;
modifyTarget?: (v: number) => number;
power?: number;
timeConstant?: number;
restDelta?: number;
};

export type CubicBezier = [number, number, number, number];

export type Keyframes = {
export type Keyframes = BaseTransition & {
type: 'keyframes';
values: number[] | string[];
easings?: Easing[];
Expand All @@ -88,14 +87,11 @@ export type Keyframes = {
yoyo?: number;
};

export type Physics = {
export type Physics = BaseTransition & {
type: 'physics';
from?: number | string;
acceleration?: number;
friction?: number;
velocity?: number;
restSpeed?: number | false;
to?: number | string;
};

export type Transition = Tween | Spring | Decay | Keyframes | Physics;
Expand Down Expand Up @@ -175,6 +171,9 @@ export type Pose = {
fill?: string;
stroke?: string;

// Misc
backgroundImage?: string;

// SVG
d?: string;
pathLength?: number;
Expand All @@ -186,4 +185,8 @@ export type Pose = {
staggerChildren?: number;
};

export type PoseResolver = (props: { [key: string]: any }) => Pose;
export type PoseResolver = (
props: { [key: string]: any },
current: { [key: string]: number | string },
velocity: { [key: string]: number | false }
) => Pose;
16 changes: 16 additions & 0 deletions src/utils/resolve-values.ts
@@ -0,0 +1,16 @@
import { MotionValue } from '../motion-value';

export type Resolver = (value: MotionValue) => any;

const createValueResolver = (resolver: Resolver) => (
values: Map<string, MotionValue>
) => {
const resolvedValues = {};
values.forEach((value, key) => (resolvedValues[key] = resolver(value)));
return resolvedValues;
};

export const resolveCurrent = createValueResolver(value => value.get());
export const resolveVelocity = createValueResolver(value =>
value.getVelocity()
);
9 changes: 6 additions & 3 deletions src/utils/transitions.ts
@@ -1,5 +1,5 @@
import { tween, spring, keyframes, decay, physics, easing } from 'popmotion';
import { Transition, TransitionMap, Tween } from '../motion/types';
import { Transition, TransitionMap, Tween, Keyframes } from '../motion/types';
import { invariant } from 'hey-listen';

const transitions = { tween, spring, keyframes, decay, physics };
Expand Down Expand Up @@ -39,7 +39,7 @@ const easingLookup: { [key: string]: (num: number) => number } = {
};

const transitionOptionParser = {
tween: (opts: Tween) => {
tween: (opts: Tween): Tween => {
const { ease } = opts;

if (Array.isArray(ease)) {
Expand All @@ -59,7 +59,10 @@ const transitionOptionParser = {
);
opts.ease = easingLookup[ease];
}
}

return opts;
},
keyframes: ({ from, to, ...opts }: Keyframes) => opts
};

const preprocessOptions = (
Expand Down

0 comments on commit 90a8b02

Please sign in to comment.