Skip to content
This repository was archived by the owner on Jun 5, 2019. It is now read-only.

Commit 3fd95eb

Browse files
authored
Merge pull request #43 from skellock/use-popmotion
Use popmotion for animations.
2 parents 3875b39 + 51f498e commit 3fd95eb

File tree

11 files changed

+261
-5
lines changed

11 files changed

+261
-5
lines changed

docs/stack.md

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,6 @@ Can't imagine doing web differently to be honest. I'm sure we will soon, but for
2929

3030
I like `preact` as well. I feel like the switching over will be pretty simple and I probably will.
3131

32-
3332
## Component Styling ##
3433

3534
> **glamor**
@@ -73,6 +72,17 @@ Start your app only when your gut says, "You'll fuck this up long before your st
7372
`glamor` gives me that vibe. 💃
7473

7574

75+
## Animations
76+
77+
**react-transition-group**
78+
79+
Brings enter + leave lifecycle events for animations.
80+
81+
**popmotion**
82+
83+
Power animation & tweening library.
84+
85+
7686
## State Management
7787

7888
> **mobx**, **mobx-react**

package-lock.json

Lines changed: 64 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,9 +46,11 @@
4646
"mobx": "3.2.2",
4747
"mobx-react": "4.2.2",
4848
"mousetrap": "1.6.1",
49+
"popmotion-react": "^1.1.0",
4950
"ramda": "0.24.1",
5051
"react": "15.6.1",
51-
"react-dom": "15.6.1"
52+
"react-dom": "15.6.1",
53+
"react-transition-group": "^2.2.0"
5254
},
5355
"description": "An electron starter project.",
5456
"devDependencies": {

src/renderer/features/example-using-tabs/dog-tab/dog-tab.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,8 @@ export class DogTab extends React.PureComponent<DogTabProps, {}> {
1616
render() {
1717
return (
1818
<CenteredContent style={this.props.style}>
19+
<Text style={TEXT_STYLE}>Do a barrel roll.</Text>
1920
<FunDog />
20-
<Text style={TEXT_STYLE}>Wake up and smell the electrons.</Text>
2121
<Logo />
2222
</CenteredContent>
2323
)

src/renderer/features/example-using-tabs/fun-dog/fun-dog.tsx

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import * as React from 'react'
22
import dogImage from './fun-dog.jpg'
3-
import { cssProps, colors } from '../../../platform'
3+
import { cssProps, colors, SpinAnimation } from '../../../platform'
44
import { css } from 'glamor'
55

66
const ROOT = cssProps({
@@ -12,5 +12,9 @@ const ROOT = cssProps({
1212
})
1313

1414
export function FunDog() {
15-
return <img draggable={false} src={dogImage} {...css(ROOT)} />
15+
return (
16+
<SpinAnimation>
17+
<img draggable={false} src={dogImage} {...css(ROOT)} />
18+
</SpinAnimation>
19+
)
1620
}

src/renderer/platform/components/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,3 +3,4 @@ export * from './scrollable-content'
33
export * from './centered-content'
44
export * from './tab'
55
export * from './enter-animation'
6+
export * from './spin-animation'
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export * from './spin-animation'
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
import { StateChangeEvent, MotionStates, MotionStateProps } from 'popmotion-react'
2+
import { tween } from 'popmotion'
3+
4+
const DEFAULT_DURATION = 500
5+
const DEFAULT_REVOLUTIONS = 1
6+
7+
export interface SpinAnimationStateProps {
8+
/** How long does the animation take in milliseconds. (default: 1000) */
9+
duration?: number
10+
/** How many spins. (default: 1) */
11+
revolutions?: number
12+
}
13+
14+
/**
15+
* Creates the animation states.
16+
*/
17+
export function createSpinStates(props: SpinAnimationStateProps): MotionStates {
18+
const duration = props.duration || DEFAULT_DURATION
19+
const forwardAngle = 360 * (props.revolutions || DEFAULT_REVOLUTIONS)
20+
21+
// a helper function to create the 2 states
22+
const createState = (to: number) => (e: StateChangeEvent) =>
23+
tween({
24+
from: e.value.get(),
25+
to,
26+
duration,
27+
onUpdate: e.value,
28+
}).start()
29+
30+
return {
31+
forward: createState(forwardAngle),
32+
back: createState(0),
33+
}
34+
}
35+
36+
/**
37+
* The function that goes to the next state.
38+
*
39+
* @param current The current state.
40+
*/
41+
export function next(current: MotionStateProps) {
42+
return current.state === 'forward' ? current.setStateTo.back : current.setStateTo.forward
43+
}
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
import * as React from 'react'
2+
import { MotionValue, MotionStates, MotionStateProps } from 'popmotion-react'
3+
import { SpinAnimationStateProps, createSpinStates, next } from './spin-animation-state'
4+
5+
/**
6+
* Provides a container which will do a barrel roll when clicked.
7+
*/
8+
export class SpinAnimation extends React.PureComponent<SpinAnimationStateProps, {}> {
9+
animationStates: MotionStates
10+
11+
componentWillMount() {
12+
this.animationStates = createSpinStates(this.props)
13+
}
14+
15+
componentWillReceiveProps(newProps: SpinAnimationStateProps) {
16+
this.animationStates = createSpinStates(newProps)
17+
}
18+
19+
render() {
20+
// the view to spin
21+
// NOTE: This is a function and not a component due to popmotion-react.
22+
const spinWrapper = (motionState: MotionStateProps) => {
23+
const props = {
24+
style: { transform: `rotate(${motionState.v}deg)`, cursor: 'pointer' },
25+
onClick: next(motionState),
26+
children: this.props.children,
27+
}
28+
29+
return <div {...props} />
30+
}
31+
32+
return <MotionValue onStateChange={this.animationStates} children={spinWrapper} />
33+
}
34+
}

types/popmotion-react.d.ts

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
declare module 'popmotion-react' {
2+
import { Component } from 'react'
3+
4+
export interface StateChangeValue {
5+
[name: string]: any
6+
}
7+
8+
export interface SetStateFunctions {
9+
[name: string]: () => void
10+
}
11+
12+
export interface MotionStateProps {
13+
/** The current numerical value, or object of named values. */
14+
v: number | StateChangeValue
15+
16+
/** Current velocity, or object of named velocities. */
17+
velocity: number
18+
19+
/** Current state name. */
20+
state: string
21+
22+
/** Object of setter functions, generated from the states defined in onStateChange (each optionally accepts an Event). */
23+
setStateTo: SetStateFunctions
24+
25+
/** Provides onStateChange setters a ref attribute for an escape hatch to the DOM (for instance attaching/removing events). */
26+
setRef(ref: React.ReactNode): void
27+
}
28+
29+
export interface StateChangeEvent {
30+
/** The popmotion value object. */
31+
value: any
32+
/** State before current state change. */
33+
previousState: string
34+
/** Object of state setters (each optionally accepts an Event). */
35+
setStateTo: any
36+
/** : A reference to the mounted React component, if a component was provided setRef. */
37+
ref: React.ReactNode
38+
/** The triggering event, if a state setter was called with one. */
39+
e: Event
40+
/** When hooking into TransitionGroup lifecycle events componentWillEnter, componentWillAppear and componentWillLeave, this callback is provided and required. */
41+
onComplete?: () => void
42+
}
43+
44+
export interface MotionStates {
45+
[stateName: string]: (onStateChange: StateChangeEvent) => void
46+
}
47+
48+
export interface MotionValueProps {
49+
/**
50+
* The initial state to start in.
51+
*/
52+
initialState?: string
53+
54+
/**
55+
* A state machine mapping state names to action states.
56+
*/
57+
onStateChange?: MotionStates
58+
}
59+
60+
export class MotionValue extends Component<MotionValueProps, {}> {
61+
constructor()
62+
}
63+
}

0 commit comments

Comments
 (0)