@xtia/timeline 1.1.4 → 1.1.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +20 -0
- package/internal/emitters.d.ts +6 -3
- package/internal/emitters.js +31 -22
- package/internal/range.d.ts +9 -7
- package/internal/range.js +15 -14
- package/internal/timeline.d.ts +6 -4
- package/internal/timeline.js +71 -76
- package/internal/tween.js +8 -5
- package/package.json +3 -2
package/README.md
CHANGED
|
@@ -464,6 +464,26 @@ timeline
|
|
|
464
464
|
|
|
465
465
|
Returns a [`ChainingInterface`](#chaininginterface-interface) representing the point at which the tween ends.
|
|
466
466
|
|
|
467
|
+
##### `apply(handler)`
|
|
468
|
+
|
|
469
|
+
Registers a handler to be invoked on every seek, after points and ranges are applied.
|
|
470
|
+
|
|
471
|
+
This is useful for systems that use Timeline's point and range emissions to manipulate state that is to be applied *at once* to another system.
|
|
472
|
+
|
|
473
|
+
```ts
|
|
474
|
+
// don't wastefully render the scene for every entity update
|
|
475
|
+
timeline
|
|
476
|
+
.range(0, 1000)
|
|
477
|
+
.tween(10, 30)
|
|
478
|
+
.apply(v => scene.hero.x = v);
|
|
479
|
+
timeline
|
|
480
|
+
.range(500, 1000)
|
|
481
|
+
.tween(15, 50)
|
|
482
|
+
.apply(v => scene.monster.x = v);
|
|
483
|
+
// render when all updates for a frame are done:
|
|
484
|
+
timeline.apply(() => renderScene(scene));
|
|
485
|
+
```
|
|
486
|
+
|
|
467
487
|
##### `tween<T>(start, end, apply, from, to, easer?): `[`ChainingInterface`](#chaininginterface-interface)
|
|
468
488
|
|
|
469
489
|
As above, but if the second argument is a [`TimelinePoint`](#timelinepoint-class), it will specify when on the Timeline the tween will *end*.
|
package/internal/emitters.d.ts
CHANGED
|
@@ -68,11 +68,10 @@ export declare class Emitter<T> {
|
|
|
68
68
|
* ```ts
|
|
69
69
|
* range
|
|
70
70
|
* .tween("0%", "100%")
|
|
71
|
-
* .fork(branch =>
|
|
72
|
-
* branch
|
|
71
|
+
* .fork(branch => branch
|
|
73
72
|
* .map(s => `Loading: ${s}`)
|
|
74
73
|
* .apply(s => document.title = s)
|
|
75
|
-
*
|
|
74
|
+
* )
|
|
76
75
|
* .apply(v => progressBar.style.width = v);
|
|
77
76
|
* ```
|
|
78
77
|
* @param cb
|
|
@@ -216,4 +215,8 @@ export declare class RangeProgression extends Emitter<number> {
|
|
|
216
215
|
*/
|
|
217
216
|
offset(delta: number): RangeProgression;
|
|
218
217
|
}
|
|
218
|
+
export declare function createListenable<T>(onAddFirst?: () => void, onRemoveLast?: () => void): {
|
|
219
|
+
listen: (fn: (v: T) => void) => UnsubscribeFunc;
|
|
220
|
+
emit: (value: T) => void;
|
|
221
|
+
};
|
|
219
222
|
export {};
|
package/internal/emitters.js
CHANGED
|
@@ -90,26 +90,15 @@ export class Emitter {
|
|
|
90
90
|
* @returns A new emitter that forwards all values from the parent, invoking `cb` as a side effect.
|
|
91
91
|
*/
|
|
92
92
|
tap(cb) {
|
|
93
|
-
const listeners = [];
|
|
94
93
|
let parentUnsubscribe = null;
|
|
95
|
-
const
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
return () => {
|
|
104
|
-
const idx = listeners.indexOf(handler);
|
|
105
|
-
listeners.splice(idx, 1);
|
|
106
|
-
if (listeners.length === 0 && parentUnsubscribe) {
|
|
107
|
-
parentUnsubscribe();
|
|
108
|
-
parentUnsubscribe = null;
|
|
109
|
-
}
|
|
110
|
-
};
|
|
111
|
-
};
|
|
112
|
-
return this.redirect(tappedListen);
|
|
94
|
+
const { emit, listen } = createListenable(() => parentUnsubscribe = this.onListen(value => {
|
|
95
|
+
cb(value);
|
|
96
|
+
emit(value);
|
|
97
|
+
}), () => {
|
|
98
|
+
parentUnsubscribe();
|
|
99
|
+
parentUnsubscribe = null;
|
|
100
|
+
});
|
|
101
|
+
return this.redirect(listen);
|
|
113
102
|
}
|
|
114
103
|
/**
|
|
115
104
|
* Immediately passes this emitter to a callback and returns this emitter
|
|
@@ -120,11 +109,10 @@ export class Emitter {
|
|
|
120
109
|
* ```ts
|
|
121
110
|
* range
|
|
122
111
|
* .tween("0%", "100%")
|
|
123
|
-
* .fork(branch =>
|
|
124
|
-
* branch
|
|
112
|
+
* .fork(branch => branch
|
|
125
113
|
* .map(s => `Loading: ${s}`)
|
|
126
114
|
* .apply(s => document.title = s)
|
|
127
|
-
*
|
|
115
|
+
* )
|
|
128
116
|
* .apply(v => progressBar.style.width = v);
|
|
129
117
|
* ```
|
|
130
118
|
* @param cb
|
|
@@ -280,3 +268,24 @@ export class RangeProgression extends Emitter {
|
|
|
280
268
|
return new RangeProgression(handler => this.onListen(value => handler((value + delta) % 1)));
|
|
281
269
|
}
|
|
282
270
|
}
|
|
271
|
+
export function createListenable(onAddFirst, onRemoveLast) {
|
|
272
|
+
const handlers = [];
|
|
273
|
+
const addListener = (fn) => {
|
|
274
|
+
const unique = (v) => fn(v);
|
|
275
|
+
handlers.push(unique);
|
|
276
|
+
if (onAddFirst && handlers.length == 1)
|
|
277
|
+
onAddFirst();
|
|
278
|
+
return () => {
|
|
279
|
+
const idx = handlers.indexOf(unique);
|
|
280
|
+
if (idx === -1)
|
|
281
|
+
throw new Error("Handler already unsubscribed");
|
|
282
|
+
handlers.splice(idx, 1);
|
|
283
|
+
if (onRemoveLast && handlers.length == 0)
|
|
284
|
+
onRemoveLast();
|
|
285
|
+
};
|
|
286
|
+
};
|
|
287
|
+
return {
|
|
288
|
+
listen: addListener,
|
|
289
|
+
emit: (value) => handlers.forEach(h => h(value)),
|
|
290
|
+
};
|
|
291
|
+
}
|
package/internal/range.d.ts
CHANGED
|
@@ -4,18 +4,20 @@ import { TimelinePoint } from "./point";
|
|
|
4
4
|
import { Timeline } from "./timeline";
|
|
5
5
|
export declare class TimelineRange extends RangeProgression {
|
|
6
6
|
private timeline;
|
|
7
|
-
private startPosition;
|
|
8
|
-
/** The duration of this range */
|
|
9
|
-
readonly duration: number;
|
|
10
|
-
private endPosition;
|
|
11
7
|
/** The point on the Timeline at which this range begins */
|
|
12
8
|
readonly start: TimelinePoint;
|
|
13
9
|
/** The point on the Timeline at which this range ends */
|
|
14
10
|
readonly end: TimelinePoint;
|
|
15
|
-
|
|
16
|
-
|
|
11
|
+
private startPosition;
|
|
12
|
+
private endPosition;
|
|
17
13
|
/** The duration of this range */
|
|
18
|
-
duration: number
|
|
14
|
+
readonly duration: number;
|
|
15
|
+
/** @internal Manual construction of RangeProgression is outside of the API contract and subject to undocumented change */
|
|
16
|
+
constructor(onListen: ListenFunc<number>, timeline: Timeline,
|
|
17
|
+
/** The point on the Timeline at which this range begins */
|
|
18
|
+
start: TimelinePoint,
|
|
19
|
+
/** The point on the Timeline at which this range ends */
|
|
20
|
+
end: TimelinePoint);
|
|
19
21
|
protected redirect(listen: ListenFunc<number>): TimelineRange;
|
|
20
22
|
/**
|
|
21
23
|
* Creates two ranges by seperating one at a given point
|
package/internal/range.js
CHANGED
|
@@ -2,23 +2,21 @@ import { RangeProgression } from "./emitters";
|
|
|
2
2
|
import { TimelinePoint } from "./point";
|
|
3
3
|
export class TimelineRange extends RangeProgression {
|
|
4
4
|
/** @internal Manual construction of RangeProgression is outside of the API contract and subject to undocumented change */
|
|
5
|
-
constructor(onListen, timeline,
|
|
6
|
-
/** The
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
}
|
|
12
|
-
: onListen);
|
|
5
|
+
constructor(onListen, timeline,
|
|
6
|
+
/** The point on the Timeline at which this range begins */
|
|
7
|
+
start,
|
|
8
|
+
/** The point on the Timeline at which this range ends */
|
|
9
|
+
end) {
|
|
10
|
+
super(onListen);
|
|
13
11
|
this.timeline = timeline;
|
|
14
|
-
this.
|
|
15
|
-
this.
|
|
16
|
-
this.
|
|
17
|
-
this.
|
|
18
|
-
this.
|
|
12
|
+
this.start = start;
|
|
13
|
+
this.end = end;
|
|
14
|
+
this.startPosition = start.position;
|
|
15
|
+
this.endPosition = end.position;
|
|
16
|
+
this.duration = this.endPosition - this.startPosition;
|
|
19
17
|
}
|
|
20
18
|
redirect(listen) {
|
|
21
|
-
return new TimelineRange(listen, this.timeline, this.
|
|
19
|
+
return new TimelineRange(listen, this.timeline, this.start, this.end);
|
|
22
20
|
}
|
|
23
21
|
/**
|
|
24
22
|
* Creates two ranges by seperating one at a given point
|
|
@@ -28,6 +26,9 @@ export class TimelineRange extends RangeProgression {
|
|
|
28
26
|
* @returns Tuple of two ranges
|
|
29
27
|
*/
|
|
30
28
|
bisect(position = this.duration / 2) {
|
|
29
|
+
if (position >= this.endPosition) {
|
|
30
|
+
throw new RangeError("Bisection position is beyond end of range");
|
|
31
|
+
}
|
|
31
32
|
return [
|
|
32
33
|
this.timeline.range(this.startPosition, position),
|
|
33
34
|
this.timeline.range(position + this.startPosition, this.duration - position),
|
package/internal/timeline.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Easer, easers } from "./easing";
|
|
2
|
-
import { RangeProgression } from "./emitters";
|
|
2
|
+
import { RangeProgression, UnsubscribeFunc } from "./emitters";
|
|
3
3
|
import { TimelinePoint } from "./point";
|
|
4
4
|
import { TimelineRange } from "./range";
|
|
5
5
|
import { Tweenable } from "./tween";
|
|
@@ -41,13 +41,15 @@ export declare class Timeline {
|
|
|
41
41
|
private smoothSeeker;
|
|
42
42
|
private seeking;
|
|
43
43
|
readonly start: TimelinePoint;
|
|
44
|
-
private
|
|
44
|
+
private _frameEvents;
|
|
45
|
+
/**
|
|
46
|
+
* Registers a handler to be invoked on every seek, after points and ranges are applied
|
|
47
|
+
*/
|
|
48
|
+
apply(handler: () => void): UnsubscribeFunc;
|
|
45
49
|
private _progression;
|
|
46
50
|
/**
|
|
47
51
|
* Listenable: emits a progression value (0..1) when the Timeline's internal
|
|
48
52
|
* position changes, and when the Timeline's total duration is extended
|
|
49
|
-
*
|
|
50
|
-
* **Experimental**
|
|
51
53
|
*/
|
|
52
54
|
get progression(): RangeProgression;
|
|
53
55
|
constructor();
|
package/internal/timeline.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { RangeProgression } from "./emitters";
|
|
1
|
+
import { createListenable, RangeProgression } from "./emitters";
|
|
2
2
|
import { TimelinePoint } from "./point";
|
|
3
3
|
import { TimelineRange } from "./range";
|
|
4
4
|
import { clamp } from "./utils";
|
|
@@ -26,16 +26,32 @@ export class Timeline {
|
|
|
26
26
|
get end() {
|
|
27
27
|
return this.point(this._endPosition);
|
|
28
28
|
}
|
|
29
|
+
/**
|
|
30
|
+
* Registers a handler to be invoked on every seek, after points and ranges are applied
|
|
31
|
+
*/
|
|
32
|
+
apply(handler) {
|
|
33
|
+
if (this._frameEvents === null) {
|
|
34
|
+
const { emit, listen } = createListenable();
|
|
35
|
+
this._frameEvents = {
|
|
36
|
+
listen,
|
|
37
|
+
emit,
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
return this._frameEvents.listen(handler);
|
|
41
|
+
}
|
|
29
42
|
/**
|
|
30
43
|
* Listenable: emits a progression value (0..1) when the Timeline's internal
|
|
31
44
|
* position changes, and when the Timeline's total duration is extended
|
|
32
|
-
*
|
|
33
|
-
* **Experimental**
|
|
34
45
|
*/
|
|
35
46
|
get progression() {
|
|
36
|
-
if (this._progression === null)
|
|
37
|
-
|
|
38
|
-
|
|
47
|
+
if (this._progression === null) {
|
|
48
|
+
const { emit, listen } = createListenable();
|
|
49
|
+
this._progression = {
|
|
50
|
+
emitter: new TimelineProgressionEmitter(listen),
|
|
51
|
+
emit,
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
return this._progression.emitter;
|
|
39
55
|
}
|
|
40
56
|
constructor(autoplay = false, endAction = "pause") {
|
|
41
57
|
/**
|
|
@@ -53,7 +69,7 @@ export class Timeline {
|
|
|
53
69
|
this.smoothSeeker = null;
|
|
54
70
|
this.seeking = false;
|
|
55
71
|
this.start = this.point(0);
|
|
56
|
-
this.
|
|
72
|
+
this._frameEvents = null;
|
|
57
73
|
this._progression = null;
|
|
58
74
|
if (endAction == "loop")
|
|
59
75
|
endAction = "restart";
|
|
@@ -91,32 +107,25 @@ export class Timeline {
|
|
|
91
107
|
point(position) {
|
|
92
108
|
if (position > this._endPosition) {
|
|
93
109
|
this._endPosition = position;
|
|
94
|
-
this.
|
|
110
|
+
this._progression?.emit(this._currentTime / position);
|
|
95
111
|
}
|
|
96
|
-
const
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
};
|
|
112
|
+
const { emit, listen } = createListenable(() => this.points.push(data), () => {
|
|
113
|
+
const idx = this.points.indexOf(data);
|
|
114
|
+
this.points.splice(idx, 1);
|
|
115
|
+
});
|
|
101
116
|
const addHandler = (handler) => {
|
|
102
117
|
if (this.seeking)
|
|
103
118
|
throw new Error("Can't add a listener while seeking");
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
119
|
+
if (position == this._currentTime) {
|
|
120
|
+
emit({
|
|
121
|
+
direction: 1
|
|
122
|
+
});
|
|
108
123
|
}
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
handlers.splice(idx, 1);
|
|
115
|
-
if (handlers.length == 0) {
|
|
116
|
-
const idx = this.points.indexOf(data);
|
|
117
|
-
this.points.splice(idx, 1);
|
|
118
|
-
}
|
|
119
|
-
};
|
|
124
|
+
return listen(handler);
|
|
125
|
+
};
|
|
126
|
+
const data = {
|
|
127
|
+
emit,
|
|
128
|
+
position,
|
|
120
129
|
};
|
|
121
130
|
return new TimelinePoint(addHandler, this, position);
|
|
122
131
|
}
|
|
@@ -126,40 +135,30 @@ export class Timeline {
|
|
|
126
135
|
: start;
|
|
127
136
|
const startPosition = startPoint.position;
|
|
128
137
|
const duration = optionalDuration ?? this._endPosition - startPosition;
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
138
|
+
const endPoint = this.point(startPosition + duration);
|
|
139
|
+
const { emit, listen } = createListenable(() => this.ranges.push(rangeData), () => {
|
|
140
|
+
const idx = this.ranges.indexOf(rangeData);
|
|
141
|
+
this.ranges.splice(idx, 1);
|
|
142
|
+
});
|
|
133
143
|
const rangeData = {
|
|
134
144
|
position: startPosition,
|
|
135
145
|
duration,
|
|
136
|
-
|
|
146
|
+
emit,
|
|
137
147
|
};
|
|
138
|
-
const addHandler =
|
|
139
|
-
|
|
140
|
-
throw new Error("
|
|
141
|
-
if (handlers.length == 0) {
|
|
142
|
-
this.ranges.push(rangeData);
|
|
143
|
-
this.currentSortDirection = 0;
|
|
144
|
-
}
|
|
145
|
-
handlers.push(handler);
|
|
146
|
-
// if currentTime is in this range, apply immediately
|
|
147
|
-
if (range.contains(this._currentTime)) {
|
|
148
|
-
let progress = clamp((this._currentTime - startPosition) / duration, 0, 1);
|
|
149
|
-
handler(progress);
|
|
148
|
+
const addHandler = duration == 0
|
|
149
|
+
? () => {
|
|
150
|
+
throw new Error("Zero-duration ranges may not be listened");
|
|
150
151
|
}
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
const idx = this.ranges.indexOf(rangeData);
|
|
158
|
-
this.ranges.splice(idx, 1);
|
|
152
|
+
: (handler) => {
|
|
153
|
+
if (this.seeking)
|
|
154
|
+
throw new Error("Can't add a listener while seeking");
|
|
155
|
+
if (range.contains(this._currentTime)) {
|
|
156
|
+
let progress = clamp((this._currentTime - startPosition) / duration, 0, 1);
|
|
157
|
+
handler(progress);
|
|
159
158
|
}
|
|
159
|
+
return listen(handler);
|
|
160
160
|
};
|
|
161
|
-
|
|
162
|
-
const range = new TimelineRange(addHandler, this, startPosition, duration);
|
|
161
|
+
const range = new TimelineRange(addHandler, this, startPoint, endPoint);
|
|
163
162
|
return range;
|
|
164
163
|
}
|
|
165
164
|
getWrappedPosition(n) {
|
|
@@ -178,10 +177,10 @@ export class Timeline {
|
|
|
178
177
|
const remainder = overflow % segment;
|
|
179
178
|
return loopStart + remainder;
|
|
180
179
|
}
|
|
181
|
-
seek(to, duration
|
|
182
|
-
const durationMs = typeof duration == "
|
|
183
|
-
? duration
|
|
184
|
-
: duration
|
|
180
|
+
seek(to, duration, easer) {
|
|
181
|
+
const durationMs = typeof duration == "object"
|
|
182
|
+
? duration.asMilliseconds
|
|
183
|
+
: duration;
|
|
185
184
|
const toPosition = typeof to == "number"
|
|
186
185
|
? to
|
|
187
186
|
: to.position;
|
|
@@ -192,21 +191,24 @@ export class Timeline {
|
|
|
192
191
|
this.smoothSeeker.pause();
|
|
193
192
|
// ensure any awaits are resolved for the interrupted seek
|
|
194
193
|
const interruptPosition = this._currentTime;
|
|
195
|
-
this.smoothSeeker.
|
|
194
|
+
this.smoothSeeker.seekDirect(this.smoothSeeker.end.position);
|
|
196
195
|
this.smoothSeeker = null;
|
|
197
196
|
// and jump back to where we were interrupted
|
|
198
|
-
this.
|
|
197
|
+
this.seekDirect(interruptPosition);
|
|
199
198
|
}
|
|
200
|
-
if (durationMs
|
|
199
|
+
if (!durationMs) {
|
|
200
|
+
const fromTime = this._currentTime;
|
|
201
201
|
this.seekDirect(toPosition);
|
|
202
|
-
|
|
202
|
+
this._frameEvents?.emit();
|
|
203
|
+
// only add Promise overhead if duration is explicitly 0
|
|
204
|
+
return durationMs === 0 ? Promise.resolve() : undefined;
|
|
203
205
|
}
|
|
204
206
|
const seeker = new Timeline(true);
|
|
205
207
|
this.smoothSeeker = seeker;
|
|
206
208
|
seeker
|
|
207
209
|
.range(0, durationMs)
|
|
208
210
|
.ease(easer)
|
|
209
|
-
.tween(this.
|
|
211
|
+
.tween(this._currentTime, toPosition)
|
|
210
212
|
.apply(v => this.seekDirect(v));
|
|
211
213
|
return seeker.end.promise();
|
|
212
214
|
}
|
|
@@ -252,7 +254,7 @@ export class Timeline {
|
|
|
252
254
|
pointsBetween.slice().forEach(p => {
|
|
253
255
|
this.seekRanges(p.position);
|
|
254
256
|
this._currentTime = p.position;
|
|
255
|
-
p.
|
|
257
|
+
p.emit(eventData);
|
|
256
258
|
});
|
|
257
259
|
}
|
|
258
260
|
seekRanges(to) {
|
|
@@ -265,10 +267,10 @@ export class Timeline {
|
|
|
265
267
|
const overlaps = fromTime <= rangeEnd && toTime >= range.position;
|
|
266
268
|
if (overlaps) {
|
|
267
269
|
let progress = clamp((to - range.position) / range.duration, 0, 1);
|
|
268
|
-
range.
|
|
270
|
+
range.emit(progress);
|
|
269
271
|
}
|
|
270
272
|
});
|
|
271
|
-
this.
|
|
273
|
+
this._progression?.emit(toTime / this._endPosition);
|
|
272
274
|
}
|
|
273
275
|
sortEntries(direction) {
|
|
274
276
|
this.currentSortDirection = direction;
|
|
@@ -391,15 +393,8 @@ export class Timeline {
|
|
|
391
393
|
}
|
|
392
394
|
}
|
|
393
395
|
class TimelineProgressionEmitter extends RangeProgression {
|
|
394
|
-
constructor(
|
|
395
|
-
super(
|
|
396
|
-
const unique = (n) => handler(n);
|
|
397
|
-
handlers.push(unique);
|
|
398
|
-
return () => {
|
|
399
|
-
const idx = handlers.indexOf(unique);
|
|
400
|
-
handlers.splice(idx, 1);
|
|
401
|
-
};
|
|
402
|
-
});
|
|
396
|
+
constructor(listen) {
|
|
397
|
+
super(listen);
|
|
403
398
|
}
|
|
404
399
|
}
|
|
405
400
|
const sortEvents = (a, b) => {
|
package/internal/tween.js
CHANGED
|
@@ -19,8 +19,11 @@ export function createTween(from, to) {
|
|
|
19
19
|
switch (typeof from) {
|
|
20
20
|
case "number": return progress => blendNumbers(from, to, progress);
|
|
21
21
|
case "object": {
|
|
22
|
-
if (from instanceof Date)
|
|
23
|
-
|
|
22
|
+
if (from instanceof Date) {
|
|
23
|
+
const fromStamp = from.getTime();
|
|
24
|
+
const toStamp = to.getTime();
|
|
25
|
+
return progress => new Date(blendNumbers(fromStamp, toStamp, progress));
|
|
26
|
+
}
|
|
24
27
|
return progress => from.blend(to, progress);
|
|
25
28
|
}
|
|
26
29
|
case "string": return createStringTween(from, to);
|
|
@@ -30,9 +33,9 @@ export function createTween(from, to) {
|
|
|
30
33
|
function createStringTween(from, to) {
|
|
31
34
|
const fromChunks = tokenise(from);
|
|
32
35
|
const toChunks = tokenise(to);
|
|
33
|
-
const tokenCount = fromChunks.
|
|
34
|
-
// where
|
|
35
|
-
if (tokenCount !== toChunks.
|
|
36
|
+
const tokenCount = fromChunks.length;
|
|
37
|
+
// where token count mismatch, use merging
|
|
38
|
+
if (tokenCount !== toChunks.length) {
|
|
36
39
|
return createStringMerge(from, to);
|
|
37
40
|
}
|
|
38
41
|
// where token prefix/type mismatch, use merging
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@xtia/timeline",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.5",
|
|
4
4
|
"repository": {
|
|
5
5
|
"url": "https://github.com/tiadrop/timeline",
|
|
6
6
|
"type": "github"
|
|
@@ -22,7 +22,8 @@
|
|
|
22
22
|
},
|
|
23
23
|
"keywords": [
|
|
24
24
|
"animation",
|
|
25
|
-
"timeline"
|
|
25
|
+
"timeline",
|
|
26
|
+
"choreography"
|
|
26
27
|
],
|
|
27
28
|
"author": "Aleta Lovelace",
|
|
28
29
|
"license": "MIT"
|