@xtia/timeline 1.0.4 → 1.0.6
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 +3 -2
- package/internal/emitters.d.ts +42 -6
- package/internal/emitters.js +22 -32
- package/internal/utils.d.ts +2 -0
- package/internal/utils.js +8 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -93,7 +93,7 @@ eased.listen(
|
|
|
93
93
|
const frames = eased
|
|
94
94
|
.tween(0, 30)
|
|
95
95
|
.map(Math.floor)
|
|
96
|
-
.
|
|
96
|
+
.dedupe()
|
|
97
97
|
.tap(n => console.log("Showing frame #", n))
|
|
98
98
|
.map(n => `animation-frame-${n}.png`)
|
|
99
99
|
.listen(filename => img.src = filename);
|
|
@@ -164,7 +164,6 @@ Tween emitters can interpolate numbers, arrays of numbers, strings, and objects
|
|
|
164
164
|
|
|
165
165
|
```ts
|
|
166
166
|
// tween four values in a CSS string
|
|
167
|
-
// see this live: https://codepen.io/xtaltia/pen/PwZYbKY
|
|
168
167
|
timeline
|
|
169
168
|
.range(0, 2000)
|
|
170
169
|
.ease("elastic")
|
|
@@ -178,6 +177,8 @@ timeline
|
|
|
178
177
|
.listen(v => document.title = v);
|
|
179
178
|
```
|
|
180
179
|
|
|
180
|
+
You can try out the [shadow tweening example at StackBlitz](https://stackblitz.com/edit/timeline-string-tween?file=src%2Fmain.ts)
|
|
181
|
+
|
|
181
182
|
## Autoplay and Looping Strategies
|
|
182
183
|
|
|
183
184
|
To create a Timeline that immediately starts playing, pass `true` to its constructor:
|
package/internal/emitters.d.ts
CHANGED
|
@@ -1,13 +1,14 @@
|
|
|
1
1
|
import { Easer, easers } from "./easing";
|
|
2
2
|
import { Blendable } from "./tween";
|
|
3
|
+
import { OptionalIfKeyIn } from "./utils";
|
|
3
4
|
/** @internal */
|
|
4
5
|
export declare function createEmitter<T>(listen: ListenFunc<T>): Emitter<T>;
|
|
5
6
|
/** @internal */
|
|
6
|
-
export declare function createEmitter<T, API extends object>(onListen: ListenFunc<T>, api:
|
|
7
|
+
export declare function createEmitter<T, API extends object>(onListen: ListenFunc<T>, api: OptionalIfKeyIn<API, Emitter<T>>): Emitter<T> & API;
|
|
7
8
|
/** @internal */
|
|
8
|
-
export declare function createProgressEmitter<API extends object>(
|
|
9
|
+
export declare function createProgressEmitter<API extends object>(listen: ListenFunc<number>, api: Omit<API, keyof RangeProgression>): RangeProgression & API;
|
|
9
10
|
/** @internal */
|
|
10
|
-
export declare function createProgressEmitter(
|
|
11
|
+
export declare function createProgressEmitter(listen: ListenFunc<number>): RangeProgression;
|
|
11
12
|
type Handler<T> = (value: T) => void;
|
|
12
13
|
type ListenFunc<T> = (handler: Handler<T>) => UnsubscribeFunc;
|
|
13
14
|
export type UnsubscribeFunc = () => void;
|
|
@@ -37,7 +38,7 @@ export interface Emitter<T> {
|
|
|
37
38
|
* If no `compare` function is provided, values will be compared via `===`
|
|
38
39
|
* @returns Listenable: emits non-repeating values
|
|
39
40
|
*/
|
|
40
|
-
|
|
41
|
+
dedupe(compare?: (a: T, b: T) => boolean): Emitter<T>;
|
|
41
42
|
/**
|
|
42
43
|
* Creates a chainable emitter that mirrors emissions from the parent emitter, invoking the provided callback `cb` as a side effect for each emission.
|
|
43
44
|
*
|
|
@@ -50,6 +51,25 @@ export interface Emitter<T> {
|
|
|
50
51
|
* @returns A new emitter that forwards all values from the parent, invoking `cb` as a side effect.
|
|
51
52
|
*/
|
|
52
53
|
tap(cb: Handler<T>): Emitter<T>;
|
|
54
|
+
/**
|
|
55
|
+
* Immediately passes this emitter to a callback and returns this emitter
|
|
56
|
+
*
|
|
57
|
+
* Allows branching without breaking a composition chain
|
|
58
|
+
*
|
|
59
|
+
* @example
|
|
60
|
+
* ```ts
|
|
61
|
+
* range
|
|
62
|
+
* .tween("0%", "100%")
|
|
63
|
+
* .fork(branch => {
|
|
64
|
+
* branch
|
|
65
|
+
* .map(s => `Loading: ${s}`)
|
|
66
|
+
* .listen(s => document.title = s)
|
|
67
|
+
* })
|
|
68
|
+
* .listen(v => progressBar.style.width = v);
|
|
69
|
+
* ```
|
|
70
|
+
* @param cb
|
|
71
|
+
*/
|
|
72
|
+
fork(cb: (branch: Emitter<T>) => void): Emitter<T>;
|
|
53
73
|
}
|
|
54
74
|
export interface RangeProgression extends Emitter<number> {
|
|
55
75
|
/**
|
|
@@ -124,7 +144,21 @@ export interface RangeProgression extends Emitter<number> {
|
|
|
124
144
|
clamp(min?: number, max?: number): RangeProgression;
|
|
125
145
|
/**
|
|
126
146
|
* Creates a chainable progress emitter that maps incoming values to a repeating linear scale
|
|
147
|
+
*
|
|
148
|
+
* ```plain
|
|
149
|
+
* count=2
|
|
150
|
+
* 1
|
|
151
|
+
* | / /
|
|
152
|
+
* o| / /
|
|
153
|
+
* u| / /
|
|
154
|
+
* t| / /
|
|
155
|
+
* | / /
|
|
156
|
+
* |/_____/_____
|
|
157
|
+
* 0 in 1
|
|
158
|
+
* ```
|
|
159
|
+
*
|
|
127
160
|
* @param count Number of repetitions
|
|
161
|
+
* @returns Listenable: emits scaled and repeating values
|
|
128
162
|
*/
|
|
129
163
|
repeat(count: number): RangeProgression;
|
|
130
164
|
/**
|
|
@@ -149,9 +183,9 @@ export interface RangeProgression extends Emitter<number> {
|
|
|
149
183
|
* Creates a chainable progress emitter that discards emitted values that are the same as the last value emitted by the new emitter
|
|
150
184
|
* @returns Listenable: emits non-repeating values
|
|
151
185
|
*/
|
|
152
|
-
|
|
186
|
+
dedupe(): RangeProgression;
|
|
153
187
|
/**
|
|
154
|
-
* Creates a chainable progress emitter that offsets its parent's values by the given delta, wrapping
|
|
188
|
+
* Creates a chainable progress emitter that offsets its parent's values by the given delta, wrapping at 1
|
|
155
189
|
*
|
|
156
190
|
* ```plain
|
|
157
191
|
* 1
|
|
@@ -165,7 +199,9 @@ export interface RangeProgression extends Emitter<number> {
|
|
|
165
199
|
* ```
|
|
166
200
|
*
|
|
167
201
|
* @param delta
|
|
202
|
+
* @returns Listenable: emits offset values
|
|
168
203
|
*/
|
|
169
204
|
offset(delta: number): RangeProgression;
|
|
205
|
+
fork(cb: (branch: RangeProgression) => void): RangeProgression;
|
|
170
206
|
}
|
|
171
207
|
export {};
|
package/internal/emitters.js
CHANGED
|
@@ -7,7 +7,7 @@ const tween_1 = require("./tween");
|
|
|
7
7
|
const utils_1 = require("./utils");
|
|
8
8
|
/** @internal */
|
|
9
9
|
function createEmitter(listen, api) {
|
|
10
|
-
const
|
|
10
|
+
const methods = {
|
|
11
11
|
listen: (handler) => listen((value) => {
|
|
12
12
|
handler(value);
|
|
13
13
|
}),
|
|
@@ -18,7 +18,7 @@ function createEmitter(listen, api) {
|
|
|
18
18
|
if (filterFunc(value))
|
|
19
19
|
handler(value);
|
|
20
20
|
})),
|
|
21
|
-
|
|
21
|
+
dedupe: (compare) => {
|
|
22
22
|
let previous = null;
|
|
23
23
|
return createEmitter(handler => {
|
|
24
24
|
const filteredHandler = (value) => {
|
|
@@ -30,18 +30,20 @@ function createEmitter(listen, api) {
|
|
|
30
30
|
}
|
|
31
31
|
};
|
|
32
32
|
return listen(filteredHandler);
|
|
33
|
-
});
|
|
33
|
+
}, api ?? {});
|
|
34
34
|
},
|
|
35
|
-
tap: (cb) => createTap(
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
35
|
+
tap: (cb) => createTap((createEmitter), listen, cb),
|
|
36
|
+
fork: (cb) => {
|
|
37
|
+
cb(emitter);
|
|
38
|
+
return emitter;
|
|
39
|
+
}
|
|
40
|
+
};
|
|
41
|
+
const emitter = (0, utils_1.prototypify)(methods, api ?? {});
|
|
42
|
+
return emitter;
|
|
41
43
|
}
|
|
42
44
|
/** @internal */
|
|
43
|
-
function createProgressEmitter(listen, api
|
|
44
|
-
const
|
|
45
|
+
function createProgressEmitter(listen, api) {
|
|
46
|
+
const methods = {
|
|
45
47
|
ease: (easer) => {
|
|
46
48
|
const easerFunc = typeof easer == "string"
|
|
47
49
|
? easing_1.easers[easer]
|
|
@@ -71,37 +73,25 @@ function createProgressEmitter(listen, api = {}) {
|
|
|
71
73
|
handler(out);
|
|
72
74
|
}));
|
|
73
75
|
},
|
|
74
|
-
tap: (cb) => createTap(
|
|
76
|
+
tap: (cb) => createTap(createProgressEmitter, listen, cb),
|
|
75
77
|
filter: (filterFunc) => createProgressEmitter(handler => listen((value) => {
|
|
76
78
|
if (filterFunc(value))
|
|
77
79
|
handler(value);
|
|
78
80
|
})),
|
|
79
|
-
noRepeat: () => {
|
|
80
|
-
let previous = null;
|
|
81
|
-
return createProgressEmitter(handler => {
|
|
82
|
-
return listen((value) => {
|
|
83
|
-
if (!previous || (previous.value !== value)) {
|
|
84
|
-
handler(value);
|
|
85
|
-
previous = { value };
|
|
86
|
-
}
|
|
87
|
-
});
|
|
88
|
-
});
|
|
89
|
-
},
|
|
90
81
|
offset: (delta) => createProgressEmitter(handler => listen(value => handler((value + delta) % 1))),
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
return Object.create(api ?? {}, propertyDescriptor);
|
|
82
|
+
};
|
|
83
|
+
const baseEmitter = createEmitter(listen, methods);
|
|
84
|
+
const emitter = (0, utils_1.prototypify)(baseEmitter, api ?? {});
|
|
85
|
+
return emitter;
|
|
96
86
|
}
|
|
97
|
-
function createTap(
|
|
87
|
+
function createTap(create, parentListen, cb) {
|
|
98
88
|
const listeners = [];
|
|
99
89
|
let parentUnsubscribe = null;
|
|
100
|
-
const
|
|
90
|
+
const tappedListen = (handler) => {
|
|
101
91
|
listeners.push(handler);
|
|
102
92
|
if (listeners.length === 1) {
|
|
103
93
|
parentUnsubscribe = parentListen(value => {
|
|
104
|
-
|
|
94
|
+
cb(value);
|
|
105
95
|
listeners.slice().forEach(fn => fn(value));
|
|
106
96
|
});
|
|
107
97
|
}
|
|
@@ -114,5 +104,5 @@ function createTap(callback, create, parentListen) {
|
|
|
114
104
|
}
|
|
115
105
|
};
|
|
116
106
|
};
|
|
117
|
-
return create(
|
|
107
|
+
return create(tappedListen);
|
|
118
108
|
}
|
package/internal/utils.d.ts
CHANGED
|
@@ -2,3 +2,5 @@
|
|
|
2
2
|
export declare const clamp: (value: number, min: number, max: number) => number;
|
|
3
3
|
/** @internal */
|
|
4
4
|
export type Widen<T> = T extends number ? number : T extends string ? string : T;
|
|
5
|
+
export type OptionalIfKeyIn<T, U> = Omit<T, keyof U> & Partial<Pick<T, Extract<keyof T, keyof U>>>;
|
|
6
|
+
export declare function prototypify<Prototype extends object, Members extends object>(proto: Prototype, members: Members): Prototype & Members;
|
package/internal/utils.js
CHANGED
|
@@ -1,6 +1,14 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.clamp = void 0;
|
|
4
|
+
exports.prototypify = prototypify;
|
|
4
5
|
/** @internal */
|
|
5
6
|
const clamp = (value, min, max) => Math.min(Math.max(value, min), max);
|
|
6
7
|
exports.clamp = clamp;
|
|
8
|
+
function prototypify(proto, members) {
|
|
9
|
+
const propertyDescriptor = Object.fromEntries(Object.entries(members).map(([key, value]) => [
|
|
10
|
+
key,
|
|
11
|
+
{ value }
|
|
12
|
+
]));
|
|
13
|
+
return Object.create(proto, propertyDescriptor);
|
|
14
|
+
}
|