Skip to content

Commit 1a243a1

Browse files
committed
fix merge commits
2 parents 6fc9982 + 0ebbf23 commit 1a243a1

File tree

16 files changed

+1754
-238
lines changed

16 files changed

+1754
-238
lines changed

package.json

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,7 @@
7070
"@babel/preset-react": "7.0.0",
7171
"@babel/preset-typescript": "^7.1.0",
7272
"@types/jest": "^24.0.0",
73+
"@types/mock-raf": "^1.0.2",
7374
"@types/react": "16.8.2",
7475
"babel-core": "7.0.0-bridge.0",
7576
"babel-jest": "24.1.0",
@@ -89,6 +90,7 @@
8990
"react": "16.8.1",
9091
"react-dom": "16.8.1",
9192
"react-konva": "^16.8.0",
93+
"react-native": "^0.58.4",
9294
"react-test-renderer": "16.8.1",
9395
"react-testing-library": "5.6.1",
9496
"rimraf": "2.6.3",
@@ -127,7 +129,9 @@
127129
"src/**/*.js",
128130
"!test/"
129131
],
130-
"setupFilesAfterEnv": ["<rootDir>/setupTests.js"]
132+
"setupFilesAfterEnv": [
133+
"<rootDir>/setupTests.js"
134+
]
131135
},
132136
"collective": {
133137
"type": "opencollective",

rollup.config.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ const getBabelOptions = ({ useESModules }, targets) => ({
2929
function createConfig(entry, out) {
3030
return [
3131
{
32-
input: `./src/${entry}/index.js`,
32+
input: `./src/${entry}/index`,
3333
output: { file: `dist/${out}.js`, format: 'esm' },
3434
external,
3535
plugins: [
@@ -44,7 +44,7 @@ function createConfig(entry, out) {
4444
],
4545
},
4646
{
47-
input: `./src/${entry}/index.js`,
47+
input: `./src/${entry}/index`,
4848
output: { file: `dist/${out}.cjs.js`, format: 'cjs' },
4949
external,
5050
plugins: [

src/animated/Animated.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,10 @@
1+
/**
2+
* The public API for Animated classes.
3+
*/
4+
export interface SpringValue<T> {
5+
getValue: () => T
6+
}
7+
18
export default abstract class Animated {
29
abstract addChild(child: Animated): void
310
abstract removeChild(child: Animated): void

src/animated/Controller.test.ts

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
import createMockRaf from 'mock-raf'
2+
import Controller from '../animated/Controller'
3+
import { Globals } from '../targets/web'
4+
5+
test('update simple value', () => {
6+
const mockRaf = createMockRaf()
7+
Globals.injectFrame(mockRaf.raf, mockRaf.cancel)
8+
Globals.injectNow(mockRaf.now)
9+
10+
const ctrl = new Controller<{ x: number; y?: number }>()
11+
ctrl.update({ x: 0 })
12+
ctrl.start()
13+
expect(ctrl.getValues().x.getValue()).toBe(0)
14+
15+
ctrl.update({ x: 100, y: 50 })
16+
expect(ctrl.getValues().x.getValue()).toBe(0)
17+
18+
ctrl.start()
19+
20+
mockRaf.step({ count: 10 })
21+
expect(ctrl.getValues().x.getValue()).toBeCloseTo(56.4)
22+
23+
mockRaf.step({ count: 100 })
24+
expect(ctrl.getValues().x.getValue()).toBe(100)
25+
})
26+
27+
test('update array value', () => {
28+
const mockRaf = createMockRaf()
29+
Globals.injectFrame(mockRaf.raf, mockRaf.cancel)
30+
Globals.injectNow(mockRaf.now)
31+
32+
const ctrl = new Controller<{ x: number[] }>()
33+
ctrl.update({ x: [0, 0] })
34+
ctrl.start()
35+
expect(ctrl.getValues().x.getValue()).toEqual([0, 0])
36+
37+
ctrl.update({ x: [10, 20] })
38+
expect(ctrl.getValues().x.getValue()).toEqual([0, 0])
39+
40+
ctrl.start()
41+
42+
mockRaf.step({ count: 10 })
43+
expect(ctrl.getValues().x.getValue()[0]).toBeCloseTo(5.64)
44+
expect(ctrl.getValues().x.getValue()[1]).toBeCloseTo(11.28)
45+
46+
mockRaf.step({ count: 100 })
47+
expect(ctrl.getValues().x.getValue()).toEqual([10, 20])
48+
})

src/animated/Controller.js renamed to src/animated/Controller.ts

Lines changed: 73 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -1,56 +1,64 @@
1-
import Animated from './Animated'
2-
import AnimatedValue from './AnimatedValue'
3-
import AnimatedArray from './AnimatedArray'
4-
import Interpolation from './Interpolation'
5-
import {
6-
interpolation as interp,
7-
now,
8-
colorNames,
9-
requestFrame as raf,
10-
} from './Globals'
11-
import { start } from './FrameLoop'
121
import {
13-
interpolateTo,
14-
withDefault,
15-
toArray,
162
callProp,
3+
interpolateTo,
174
is,
5+
toArray,
6+
withDefault,
187
} from '../shared/helpers'
8+
import AnimatedArray from './AnimatedArray'
9+
import AnimatedValue from './AnimatedValue'
10+
import { start } from './FrameLoop'
11+
import { colorNames, interpolation as interp, now } from './Globals'
12+
13+
type FinishedCallback = (finished?: boolean) => void
14+
15+
type AnimationsFor<P> = { [Key in keyof P]: any }
16+
17+
type ValuesFor<P> = { [Key in keyof P]: any }
18+
19+
type InterpolationsFor<P> = {
20+
[Key in keyof P]: P[Key] extends ArrayLike<any>
21+
? AnimatedArray
22+
: AnimatedValue
23+
}
1924

2025
let G = 0
21-
export default class Controller {
22-
constructor(props) {
26+
class Controller<P extends any = {}> {
27+
id: number
28+
29+
idle = true
30+
hasChanged = false
31+
guid = 0
32+
local = 0
33+
props: P = {} as P
34+
merged: any = {}
35+
animations = {} as AnimationsFor<P>
36+
interpolations = {} as InterpolationsFor<P>
37+
values = {} as ValuesFor<P>
38+
configs: any = []
39+
listeners: FinishedCallback[] = []
40+
queue: any[] = []
41+
localQueue?: any[]
42+
43+
constructor() {
2344
this.id = G++
24-
this.idle = true
25-
this.hasChanged = false
26-
this.guid = 0
27-
this.local = 0
28-
this.props = {}
29-
this.merged = {}
30-
this.animations = {}
31-
this.interpolations = {}
32-
this.values = {}
33-
this.configs = []
34-
this.listeners = []
35-
this.queue = []
36-
if (props) this.update(props)
3745
}
3846

3947
/** update(props)
4048
* This function filters input props and creates an array of tasks which are executed in .start()
4149
* Each task is allowed to carry a delay, which means it can execute asnychroneously */
42-
update(args) {
50+
update(args?: P) {
4351
//this._id = n + this.id
4452

4553
if (!args) return this
4654
// Extract delay and the to-prop from props
47-
const { delay = 0, to, ...props } = interpolateTo(args)
55+
const { delay = 0, to, ...props } = interpolateTo(args) as any
4856
if (is.arr(to) || is.fun(to)) {
4957
// If config is either a function or an array queue it up as is
5058
this.queue.push({ ...props, delay, to })
5159
} else if (to) {
5260
// Otherwise go through each key since it could be delayed individually
53-
let merge = {}
61+
let merge: any = {}
5462
Object.entries(to).forEach(([k, v]) => {
5563
// Fetch delay and create an entry, consisting of the to-props, the delay, and basic props
5664
const entry = { to: { [k]: v }, delay: callProp(delay, k), ...props }
@@ -71,7 +79,7 @@ export default class Controller {
7179

7280
/** start(onEnd)
7381
* This function either executes a queue, if present, or starts the frameloop, which animates */
74-
start(onEnd) {
82+
start(onEnd?: FinishedCallback) {
7583
// If a queue is present we must excecute it
7684
if (this.queue.length) {
7785
this.idle = false
@@ -92,7 +100,7 @@ export default class Controller {
92100

93101
// Go through each entry and execute it
94102
queue.forEach(({ delay, ...props }, index) => {
95-
const cb = finished => {
103+
const cb: FinishedCallback = finished => {
96104
if (index === queue.length - 1 && local === this.guid && finished) {
97105
this.idle = true
98106
if (this.props.onRest) this.props.onRest(this.merged)
@@ -122,43 +130,45 @@ export default class Controller {
122130
return this
123131
}
124132

125-
stop(finished) {
133+
stop(finished?: boolean) {
126134
this.listeners.forEach(onEnd => onEnd(finished))
127135
this.listeners = []
128136
return this
129137
}
130138

131-
runAsync({ delay, ...props }, onEnd) {
139+
runAsync({ delay, ...props }: P, onEnd: FinishedCallback) {
132140
const local = this.local
133141
// If "to" is either a function or an array it will be processed async, therefor "to" should be empty right now
134142
// If the view relies on certain values "from" has to be present
135-
let queue = Promise.resolve()
143+
let queue = Promise.resolve(undefined)
136144
if (is.arr(props.to)) {
137145
for (let i = 0; i < props.to.length; i++) {
138146
const index = i
139-
const last = index === props.to.length - 1
140147
const fresh = { ...props, to: props.to[index] }
141148
if (is.arr(fresh.config)) fresh.config = fresh.config[index]
142-
queue = queue.then(() => {
143-
//this.stop()
144-
if (local === this.guid)
145-
return new Promise(r => this.diff(interpolateTo(fresh)).start(r))
146-
})
149+
queue = queue.then(
150+
(): Promise<any> | void => {
151+
//this.stop()
152+
if (local === this.guid)
153+
return new Promise(r => this.diff(interpolateTo(fresh)).start(r))
154+
}
155+
)
147156
}
148157
} else if (is.fun(props.to)) {
149158
let index = 0
150-
let last = undefined
159+
let last: Promise<any>
151160
queue = queue.then(() =>
152161
props
153162
.to(
154163
// next(props)
155-
p => {
164+
(p: P) => {
156165
const fresh = { ...props, ...interpolateTo(p) }
157166
if (is.arr(fresh.config)) fresh.config = fresh.config[index]
158167
index++
159168
//this.stop()
160169
if (local === this.guid)
161170
return (last = new Promise(r => this.diff(fresh).start(r)))
171+
return
162172
},
163173
// cancel()
164174
(finished = true) => this.stop(finished)
@@ -169,7 +179,7 @@ export default class Controller {
169179
queue.then(onEnd)
170180
}
171181

172-
diff(props) {
182+
diff(props: any) {
173183
this.props = { ...this.props, ...props }
174184
let {
175185
from = {},
@@ -179,7 +189,6 @@ export default class Controller {
179189
attach,
180190
reset,
181191
immediate,
182-
ref,
183192
} = this.props
184193

185194
// Reverse values when requested
@@ -195,8 +204,8 @@ export default class Controller {
195204
let target = attach && attach(this)
196205

197206
// Reduces input { name: value } pairs into animated values
198-
this.animations = Object.entries(this.merged).reduce(
199-
(acc, [name, value], i) => {
207+
this.animations = Object.entries<any>(this.merged).reduce(
208+
(acc, [name, value]) => {
200209
// Issue cached entries, except on reset
201210
let entry = acc[name] || {}
202211

@@ -222,12 +231,16 @@ export default class Controller {
222231

223232
let newValue = value
224233
if (isInterpolation)
225-
newValue = interp({ range: [0, 1], output: [value, value] })(1)
234+
newValue = interp({
235+
range: [0, 1],
236+
output: [value as string, value as string],
237+
})(1)
226238
let currentValue = interpolation && interpolation.getValue()
227239

228240
// Change detection flags
229241
const isFirst = is.und(parent)
230-
const isActive = !isFirst && entry.animatedValues.some(v => !v.done)
242+
const isActive =
243+
!isFirst && entry.animatedValues.some((v: AnimatedValue) => !v.done)
231244
const currentValueDiffersFromGoal = !is.equ(newValue, currentValue)
232245
const hasNewGoal = !is.equ(newValue, entry.previous)
233246
const hasNewConfig = !is.equ(toConfig, entry.config)
@@ -301,7 +314,7 @@ export default class Controller {
301314
friction: withDefault(toConfig.friction, 26),
302315
mass: withDefault(toConfig.mass, 1),
303316
duration: toConfig.duration,
304-
easing: withDefault(toConfig.easing, t => t),
317+
easing: withDefault(toConfig.easing, (t: number) => t),
305318
decay: toConfig.decay,
306319
},
307320
}
@@ -329,8 +342,8 @@ export default class Controller {
329342
if (this.hasChanged) {
330343
// Make animations available to frameloop
331344
this.configs = Object.values(this.animations)
332-
this.values = {}
333-
this.interpolations = {}
345+
this.values = {} as ValuesFor<P>
346+
this.interpolations = {} as InterpolationsFor<P>
334347
for (let key in this.animations) {
335348
this.interpolations[key] = this.animations[key].interpolation
336349
this.values[key] = this.animations[key].interpolation.getValue()
@@ -341,14 +354,16 @@ export default class Controller {
341354

342355
destroy() {
343356
this.stop()
344-
this.props = {}
357+
this.props = {} as P
345358
this.merged = {}
346-
this.animations = {}
347-
this.interpolations = {}
348-
this.values = {}
359+
this.animations = {} as AnimationsFor<P>
360+
this.interpolations = {} as InterpolationsFor<P>
361+
this.values = {} as ValuesFor<P>
349362
this.configs = []
350363
this.local = 0
351364
}
352365

353366
getValues = () => this.interpolations
354367
}
368+
369+
export default Controller

src/animated/FrameLoop.js renamed to src/animated/FrameLoop.ts

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import Animated from './Animated'
2+
import Controller from './Controller'
23
import { now, requestFrame } from './Globals'
34

45
let active = false
@@ -15,7 +16,7 @@ const frameLoop = () => {
1516
configIdx++
1617
) {
1718
let config = controller.configs[configIdx]
18-
let endOfAnimation, lastTime, velocity
19+
let endOfAnimation, lastTime
1920
for (let valIdx = 0; valIdx < config.animatedValues.length; valIdx++) {
2021
let animation = config.animatedValues[valIdx]
2122

@@ -129,14 +130,12 @@ const frameLoop = () => {
129130
else active = false
130131
}
131132

132-
const start = controller => {
133+
const start = (controller: Controller) => {
133134
if (!controllers.has(controller)) {
134135
controllers.add(controller)
135136
if (!active) requestFrame(frameLoop)
136137
active = true
137138
}
138139
}
139140

140-
const isActive = controller => active && controllers.has(controller)
141-
142141
export { start }

0 commit comments

Comments
 (0)