@rafaelaugusto/jolt 0.0.0-stage → 0.1.0-beta.1
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/LICENSE +21 -0
- package/README.md +323 -2
- package/dist/animate.d.ts +26 -0
- package/dist/animate.d.ts.map +1 -0
- package/dist/animate.js +161 -0
- package/dist/animate.js.map +1 -0
- package/dist/driver/android.d.ts +3 -0
- package/dist/driver/android.d.ts.map +1 -0
- package/dist/driver/android.js +73 -0
- package/dist/driver/android.js.map +1 -0
- package/dist/driver/index.d.ts +18 -0
- package/dist/driver/index.d.ts.map +1 -0
- package/dist/driver/index.js +15 -0
- package/dist/driver/index.js.map +1 -0
- package/dist/driver/ios.d.ts +3 -0
- package/dist/driver/ios.d.ts.map +1 -0
- package/dist/driver/ios.js +77 -0
- package/dist/driver/ios.js.map +1 -0
- package/dist/easing.d.ts +8 -0
- package/dist/easing.d.ts.map +1 -0
- package/dist/easing.js +71 -0
- package/dist/easing.js.map +1 -0
- package/dist/engine.d.ts +48 -0
- package/dist/engine.d.ts.map +1 -0
- package/dist/engine.js +178 -0
- package/dist/engine.js.map +1 -0
- package/dist/index.d.ts +13 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +7 -0
- package/dist/index.js.map +1 -0
- package/dist/presets.d.ts +310 -0
- package/dist/presets.d.ts.map +1 -0
- package/dist/presets.js +141 -0
- package/dist/presets.js.map +1 -0
- package/dist/press.d.ts +13 -0
- package/dist/press.d.ts.map +1 -0
- package/dist/press.js +34 -0
- package/dist/press.js.map +1 -0
- package/dist/properties.d.ts +8 -0
- package/dist/properties.d.ts.map +1 -0
- package/dist/properties.js +42 -0
- package/dist/properties.js.map +1 -0
- package/dist/sequence.d.ts +26 -0
- package/dist/sequence.d.ts.map +1 -0
- package/dist/sequence.js +69 -0
- package/dist/sequence.js.map +1 -0
- package/dist/spring.d.ts +22 -0
- package/dist/spring.d.ts.map +1 -0
- package/dist/spring.js +54 -0
- package/dist/spring.js.map +1 -0
- package/dist/track.d.ts +28 -0
- package/dist/track.d.ts.map +1 -0
- package/dist/track.js +103 -0
- package/dist/track.js.map +1 -0
- package/dist/transition.d.ts +58 -0
- package/dist/transition.d.ts.map +1 -0
- package/dist/transition.js +82 -0
- package/dist/transition.js.map +1 -0
- package/dist/types.d.ts +40 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/package.json +67 -4
- package/src/animate.ts +246 -0
- package/src/driver/android.ts +101 -0
- package/src/driver/index.ts +32 -0
- package/src/driver/ios.ts +97 -0
- package/src/easing.ts +100 -0
- package/src/engine.ts +216 -0
- package/src/index.ts +12 -0
- package/src/presets.ts +158 -0
- package/src/press.ts +49 -0
- package/src/properties.ts +51 -0
- package/src/sequence.ts +88 -0
- package/src/spring.ts +95 -0
- package/src/track.ts +163 -0
- package/src/transition.ts +160 -0
- package/src/types.ts +41 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Rafael Augusto
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -1,3 +1,324 @@
|
|
|
1
|
-
|
|
1
|
+
<p align="center">
|
|
2
|
+
<picture>
|
|
3
|
+
<source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/rafaelaugustos/jolt/main/.github/assets/logo-dark.png">
|
|
4
|
+
<img src="https://raw.githubusercontent.com/rafaelaugustos/jolt/main/.github/assets/logo.png" alt="Jolt" width="280">
|
|
5
|
+
</picture>
|
|
6
|
+
</p>
|
|
2
7
|
|
|
3
|
-
|
|
8
|
+
<p align="center">
|
|
9
|
+
Native animations for <a href="https://nativescript.org">NativeScript</a>: presets, springs, keyframes and stagger, one call each.
|
|
10
|
+
</p>
|
|
11
|
+
|
|
12
|
+
<p align="center">
|
|
13
|
+
<a href="https://www.npmjs.com/package/@rafaelaugusto/jolt"><img src="https://img.shields.io/npm/v/@rafaelaugusto/jolt/next?label=npm%40next" alt="npm"></a>
|
|
14
|
+
<a href="https://github.com/rafaelaugustos/jolt/actions/workflows/ci.yml"><img src="https://github.com/rafaelaugustos/jolt/actions/workflows/ci.yml/badge.svg" alt="CI"></a>
|
|
15
|
+
<a href="https://github.com/rafaelaugustos/jolt/blob/main/LICENSE"><img src="https://img.shields.io/npm/l/@rafaelaugusto/jolt" alt="MIT license"></a>
|
|
16
|
+
</p>
|
|
17
|
+
|
|
18
|
+
<p align="center">
|
|
19
|
+
<a href="https://jolt.rafaelaugusto.dev">Documentation</a> · <a href="https://jolt.rafaelaugusto.dev/pt-BR/">Documentação em português</a>
|
|
20
|
+
</p>
|
|
21
|
+
|
|
22
|
+
```ts
|
|
23
|
+
import { animate } from '@rafaelaugusto/jolt'
|
|
24
|
+
|
|
25
|
+
animate(card, 'fadeInUp')
|
|
26
|
+
animate(button, { scale: 1.1 }, 'bouncy')
|
|
27
|
+
animate(rows, 'fadeInUp', { stagger: 40 })
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
NativeScript's `view.animate()` covers the basics and stops there: one curve for every property, a `spring` curve with no settings, no keyframes, and a promise that rejects when the animation is cancelled. Anything richer ends up as platform code.
|
|
31
|
+
|
|
32
|
+
Jolt computes the motion once, in JavaScript, when the animation starts, and hands it to the platform as keyframes: Core Animation on iOS, `ObjectAnimator` on Android. Nothing runs in JavaScript while it plays. Springs follow real physics, and an animation that interrupts another one starts from where the view is, at the speed it was going.
|
|
33
|
+
|
|
34
|
+
## Features
|
|
35
|
+
|
|
36
|
+
- [25 presets](#presets) to enter, exit and draw attention: `fadeInUp`, `popIn`, `shake`, `heartbeat`...
|
|
37
|
+
- [Springs](#springs) described by feel (`bouncy`), by `bounce` and `duration`, or by stiffness, damping and mass.
|
|
38
|
+
- [Keyframes and tweens](#tweens) with an easing per segment and exact keyframe times.
|
|
39
|
+
- [Stagger](#several-views) across several views, from the first, the last or the center.
|
|
40
|
+
- [Sequences](#sequences) that start each step once the previous one looks done.
|
|
41
|
+
- [Press effects](#press) that follow the finger and let go when a scroll takes over.
|
|
42
|
+
- [Interruptions](#interrupting-and-stopping) that pick up the value and velocity on screen, with no jump.
|
|
43
|
+
- [Native playback](#how-it-works): Core Animation on iOS, `ObjectAnimator` on Android, nothing in JavaScript while it plays.
|
|
44
|
+
|
|
45
|
+
## Install
|
|
46
|
+
|
|
47
|
+
```sh
|
|
48
|
+
npm install @rafaelaugusto/jolt@next
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
It's in beta for now, published under the `next` tag. Requires `@nativescript/core` 8.9 or later. It doesn't depend on a framework: it takes a view, or an element that holds one.
|
|
52
|
+
|
|
53
|
+
## Animating
|
|
54
|
+
|
|
55
|
+
`animate(target, keyframes, transition?)` takes a view and where to take it:
|
|
56
|
+
|
|
57
|
+
```ts
|
|
58
|
+
animate(card, { opacity: 0.5, y: -20 })
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
| Property | Unit |
|
|
62
|
+
| -------------------- | ---------------------------------------- |
|
|
63
|
+
| `opacity` | |
|
|
64
|
+
| `x`, `y` | DIPs, same as `translateX`, `translateY` |
|
|
65
|
+
| `scale` | sets `scaleX` and `scaleY` together |
|
|
66
|
+
| `scaleX`, `scaleY` | |
|
|
67
|
+
| `rotate` | degrees |
|
|
68
|
+
| `rotateX`, `rotateY` | degrees, with perspective |
|
|
69
|
+
|
|
70
|
+
A single value animates from wherever the view is. An array is a list of keyframes, and `null` stands for the current value:
|
|
71
|
+
|
|
72
|
+
```ts
|
|
73
|
+
animate(card, { x: [0, 100] }) // from 0, whatever x is now
|
|
74
|
+
animate(card, { x: [null, 20, -20, null] }) // out and back to where it was
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
With `relative: true`, translation and rotation keyframes are offsets from the current value. Scale and opacity keyframes multiply it instead. Each scale axis keeps its own base, and `null` still means the current value.
|
|
78
|
+
|
|
79
|
+
```ts
|
|
80
|
+
animate(card, { x: [0, -10, 10, 0] }, { relative: true }) // shake around its current x
|
|
81
|
+
animate(card, { scale: [1, 1.06, 1] }, { relative: true }) // grow by 6% and return
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
The base is captured once when the view is ready and its tracks are created, before any delay or stagger. Repeats reuse that base. A relative step in a sequence resolves when the step starts; an unloaded view waits until it loads.
|
|
85
|
+
|
|
86
|
+
The target can be a view, or anything that holds one: a NativeScript-Vue template ref, an Angular `ElementRef`.
|
|
87
|
+
|
|
88
|
+
```vue
|
|
89
|
+
<script setup lang="ts">
|
|
90
|
+
const card = ref()
|
|
91
|
+
const open = () => animate(card.value, 'popIn')
|
|
92
|
+
</script>
|
|
93
|
+
|
|
94
|
+
<template>
|
|
95
|
+
<GridLayout ref="card" @tap="open" />
|
|
96
|
+
</template>
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
A view that isn't loaded yet takes its first absolute keyframe right away and plays once it's on screen. Calling `animate(title, 'fadeInUp')` in `onMounted` doesn't flash the title before it fades in. Relative animations leave the view's values alone until it loads.
|
|
100
|
+
|
|
101
|
+
## Transitions
|
|
102
|
+
|
|
103
|
+
The third argument says how to get there. Without one, transforms move with a spring and `opacity` eases over 300ms. Keyframes tween.
|
|
104
|
+
|
|
105
|
+
### Springs
|
|
106
|
+
|
|
107
|
+
```ts
|
|
108
|
+
animate(card, { scale: 1.2 }, 'bouncy')
|
|
109
|
+
animate(card, { y: 0 }, { bounce: 0.3, duration: 600 })
|
|
110
|
+
animate(card, { y: 0 }, { stiffness: 300, damping: 20, mass: 1 })
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
| Spring | Feel |
|
|
114
|
+
| -------- | ------------------------------------- |
|
|
115
|
+
| `smooth` | no overshoot |
|
|
116
|
+
| `snappy` | quick, barely overshoots. The default |
|
|
117
|
+
| `bouncy` | overshoots and settles with a bounce |
|
|
118
|
+
|
|
119
|
+
`bounce` goes from -1 to 1: 0 settles without overshooting, higher values bounce more, negative values settle more slowly. `duration` is how long the spring feels, the same model as SwiftUI. Or describe it with `stiffness`, `damping` and `mass`. A spring starts with the velocity of the animation it interrupts, unless you pass `velocity` (units per second).
|
|
120
|
+
|
|
121
|
+
### Tweens
|
|
122
|
+
|
|
123
|
+
```ts
|
|
124
|
+
animate(card, { opacity: 0 }, { duration: 200, ease: 'easeIn' })
|
|
125
|
+
animate(
|
|
126
|
+
card,
|
|
127
|
+
{ x: [0, 100, 50] },
|
|
128
|
+
{ duration: 600, ease: ['easeOut', 'easeIn'], times: [0, 0.3, 1] },
|
|
129
|
+
)
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
Tweens take 300ms and `easeOut` unless told otherwise. `ease` takes `linear`, `ease`, `easeIn`, `easeOut`, `easeInOut`, `circIn`, `circOut`, `circInOut`, `backIn`, `backOut`, `backInOut`, `anticipate`, a cubic bezier (`[0.2, 0, 0, 1]`) or any function from 0..1 to a value. With keyframes, pass one per segment. `times` places each keyframe between 0 and 1.
|
|
133
|
+
|
|
134
|
+
Custom easing functions run once, when the animation starts, like springs do. They don't cost anything per frame.
|
|
135
|
+
|
|
136
|
+
### Per property
|
|
137
|
+
|
|
138
|
+
```ts
|
|
139
|
+
animate(
|
|
140
|
+
card,
|
|
141
|
+
{ y: 0, opacity: 1 },
|
|
142
|
+
{ type: 'spring', bounce: 0.3, opacity: { duration: 150 } },
|
|
143
|
+
)
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
A property's transition replaces the curve, and keeps the timing (`delay`, `repeat`) of the main one unless it sets its own.
|
|
147
|
+
|
|
148
|
+
### Timing
|
|
149
|
+
|
|
150
|
+
```ts
|
|
151
|
+
animate(
|
|
152
|
+
badge,
|
|
153
|
+
{ scale: [1, 1.2] },
|
|
154
|
+
{ delay: 300, repeat: Infinity, repeatType: 'reverse' },
|
|
155
|
+
)
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
`delay` is in milliseconds, and the view takes the first keyframe during it. `repeat` is how many more times to play, `Infinity` until stopped. `repeatType: 'reverse'` plays every other repeat backwards. Repeats play natively too.
|
|
159
|
+
|
|
160
|
+
## Presets
|
|
161
|
+
|
|
162
|
+
```ts
|
|
163
|
+
animate(card, 'popIn')
|
|
164
|
+
animate(card, 'shake', { delay: 200 })
|
|
165
|
+
animate(spinner, 'spin', { repeat: Infinity })
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
| | |
|
|
169
|
+
| --------- | -------------------------------------------------------------------------------------------------------- |
|
|
170
|
+
| Enter | `fadeIn`, `fadeInUp`, `fadeInDown`, `fadeInLeft`, `fadeInRight`, `zoomIn`, `popIn`, `flipInX`, `flipInY` |
|
|
171
|
+
| Exit | `fadeOut`, `fadeOutUp`, `fadeOutDown`, `fadeOutLeft`, `fadeOutRight`, `zoomOut`, `popOut` |
|
|
172
|
+
| Attention | `pulse`, `bounce`, `shake`, `wiggle`, `heartbeat`, `jelly`, `flash`, `tada`, `spin` |
|
|
173
|
+
|
|
174
|
+
Directions follow animate.css: `fadeInUp` comes up from below, `fadeOutUp` leaves upwards. Each built-in preset is plain keyframes and a transition, listed in [`src/presets.ts`](./src/presets.ts) and exported as `presets`.
|
|
175
|
+
|
|
176
|
+
Attention presets use `relative: true`: `shake` around `x: 40` returns to 40, `pulse` preserves the current scale, and `flash` returns to the current opacity. `spin` adds a full turn to the current rotation. Pass `{ relative: false }` to use their absolute keyframes instead. Enter and exit presets remain absolute.
|
|
177
|
+
|
|
178
|
+
Options with timing only (`delay`, `repeat`, `stagger`) keep the preset's curves. Options with a curve (`duration`, `ease`, a spring) replace them:
|
|
179
|
+
|
|
180
|
+
```ts
|
|
181
|
+
animate(card, 'fadeInUp', { delay: 100 }) // the preset's spring, 100ms later
|
|
182
|
+
animate(card, 'fadeInUp', { duration: 600 }) // a 600ms tween instead
|
|
183
|
+
animate(card, 'fadeInUp', 'bouncy') // a bouncy spring instead
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
Register your own keyframes and transition with `definePreset`:
|
|
187
|
+
|
|
188
|
+
```ts
|
|
189
|
+
import { animate, definePreset } from '@rafaelaugusto/jolt'
|
|
190
|
+
|
|
191
|
+
declare module '@rafaelaugusto/jolt' {
|
|
192
|
+
interface Presets {
|
|
193
|
+
cardIn: true
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
definePreset('cardIn', {
|
|
198
|
+
keyframes: { opacity: [0, 1], y: [40, 0] },
|
|
199
|
+
transition: { type: 'spring', bounce: 0.2, opacity: { duration: 150 } },
|
|
200
|
+
})
|
|
201
|
+
|
|
202
|
+
animate(card, 'cardIn')
|
|
203
|
+
```
|
|
204
|
+
|
|
205
|
+
Register presets during app startup, before using them in `animate()` or `sequence()`. The `Presets` declaration adds the name to TypeScript; it does not register anything at runtime. Custom presets follow the same timing and curve overrides as built-ins, including per-property options and `stagger`.
|
|
206
|
+
|
|
207
|
+
Registering a custom name again replaces its definition for future animations. Built-in names cannot be replaced through `definePreset`, and the exported `presets` object continues to contain only the built-ins.
|
|
208
|
+
|
|
209
|
+
## Several views
|
|
210
|
+
|
|
211
|
+
Pass an array to animate them together, and `stagger` to start them one after another:
|
|
212
|
+
|
|
213
|
+
```ts
|
|
214
|
+
animate(rows, 'fadeInUp', { stagger: 40 })
|
|
215
|
+
animate(tiles, 'popIn', { stagger: { each: 30, from: 'center' } })
|
|
216
|
+
```
|
|
217
|
+
|
|
218
|
+
`from` is `'first'` (the default), `'last'`, `'center'` or an index.
|
|
219
|
+
|
|
220
|
+
## Sequences
|
|
221
|
+
|
|
222
|
+
```ts
|
|
223
|
+
await sequence([
|
|
224
|
+
[logo, 'popIn'],
|
|
225
|
+
[[title, subtitle], 'fadeInUp', { stagger: 80 }],
|
|
226
|
+
() => animate(button, 'fadeIn'),
|
|
227
|
+
])
|
|
228
|
+
```
|
|
229
|
+
|
|
230
|
+
Each step takes the same arguments as `animate`, or is a function that starts an animation. A step starts once the previous one looks done: a spring that's close to its target and staying there counts, even if it's still settling, so steps don't wait on the last pixel. The whole sequence finishes once every step has.
|
|
231
|
+
|
|
232
|
+
Views in later steps take their first absolute keyframe when the sequence starts, so the title above stays hidden until its turn instead of showing up and disappearing. Relative steps and `null` keyframes wait until their step starts to read the current value.
|
|
233
|
+
|
|
234
|
+
## Press
|
|
235
|
+
|
|
236
|
+
```ts
|
|
237
|
+
const remove = press(button) // scales to 0.96 while pressed
|
|
238
|
+
press(card, { scale: 0.97, opacity: 0.8 })
|
|
239
|
+
press(tile, { scale: 0.9, rotate: -4 }, 'bouncy')
|
|
240
|
+
```
|
|
241
|
+
|
|
242
|
+
Animates to the given values while a finger is down, and back to where the view was once it lifts, or once the touch is cancelled by a scroll taking over. Views with `isEnabled` set to `false` don't react. It returns a function that removes the effect.
|
|
243
|
+
|
|
244
|
+
## Interrupting and stopping
|
|
245
|
+
|
|
246
|
+
Starting an animation on a property that's already animating takes it over: the new one starts from the value on screen, with the same velocity, so a card can change its mind halfway without a jump. Other properties of the previous animation keep going.
|
|
247
|
+
|
|
248
|
+
`animate()` returns an animation you can `await`. It resolves with `true` when it played to the end, and `false` when it was stopped or taken over. It never rejects.
|
|
249
|
+
|
|
250
|
+
```ts
|
|
251
|
+
const animation = animate(card, { x: 300 })
|
|
252
|
+
animation.stop() // the card stays where it is
|
|
253
|
+
|
|
254
|
+
stop(card) // stops everything running on the card
|
|
255
|
+
stop(card, ['x', 'scale']) // stops translation on x and both scale axes
|
|
256
|
+
```
|
|
257
|
+
|
|
258
|
+
Selected properties stay at their current values; the others keep animating. `scaleX` and `scaleY` can also be stopped separately. Pass an empty array to stop nothing, or omit it to stop everything. This works with arrays of targets too.
|
|
259
|
+
|
|
260
|
+
If part of an animation is stopped, its `finished` promise resolves with `false` once its remaining properties finish.
|
|
261
|
+
|
|
262
|
+
## How it works
|
|
263
|
+
|
|
264
|
+
When an animation starts, Jolt resolves where each property starts from (the value on screen, or the keyframes you gave), and computes the whole curve: easing, keyframes, spring physics. It samples the curve 60 times per second of motion, and keeps keyframe times exact. Linear segments aren't sampled at all.
|
|
265
|
+
|
|
266
|
+
The samples go to the platform in one go:
|
|
267
|
+
|
|
268
|
+
- **iOS**: a `CAKeyframeAnimation` per property on the view's layer (`opacity`, `transform.translation.x`, `transform.scale.y`, `transform.rotation.z`...). Core Animation composes them, so `x` and `scale` can belong to different animations, and plays them in the render server.
|
|
269
|
+
- **Android**: an `ObjectAnimator` per property with `Keyframe`s and a linear interpolator, on the view's `alpha`, `translationX`, `scaleY`, `rotation`...
|
|
270
|
+
|
|
271
|
+
Before playing, the final values are set on the NativeScript view, like `view.animate()` does, so `view.translateX` already holds the target while the animation runs. Stopping writes back the values on screen.
|
|
272
|
+
|
|
273
|
+
Each running property remembers its curve and start time, so Jolt knows the value and velocity of any property at any moment without asking the platform. That's what lets an interruption pick up the motion where it was. On Android, where an animator starts on the next frame, it reads the value on screen instead.
|
|
274
|
+
|
|
275
|
+
## Not there yet
|
|
276
|
+
|
|
277
|
+
- Only transforms and opacity. Colors ([#12](https://github.com/rafaelaugustos/jolt/issues/12)), borders and shadows ([#13](https://github.com/rafaelaugustos/jolt/issues/13)), size and layout changes ([#21](https://github.com/rafaelaugustos/jolt/issues/21)) aren't animated yet.
|
|
278
|
+
- No gestures: dragging something and letting it fly with its velocity is next ([#23](https://github.com/rafaelaugustos/jolt/issues/23)).
|
|
279
|
+
- No layout or shared element transitions ([#21](https://github.com/rafaelaugustos/jolt/issues/21), [#24](https://github.com/rafaelaugustos/jolt/issues/24)).
|
|
280
|
+
|
|
281
|
+
## API
|
|
282
|
+
|
|
283
|
+
**Animating**: `animate(target, keyframes | preset, transition?)`, `stop(target, properties?)`, `sequence(steps)`, `press(target, pressed?, transition?)`.
|
|
284
|
+
|
|
285
|
+
**Animations** returned by them: `await`, `finished`, `stop()`.
|
|
286
|
+
|
|
287
|
+
**Helpers**: `definePreset`, `presets`, `springs`, `cubicBezier`, plus the types (`Keyframes`, `Transition`, `Spring`, `Tween`, `Preset`, `Presets`, `PresetName`, `SpringName`, `Easing`, `Animation`, `Target`...).
|
|
288
|
+
|
|
289
|
+
## Demo
|
|
290
|
+
|
|
291
|
+
[`demo/`](./demo) is a NativeScript-Vue app with every preset, the three springs on a ball you can interrupt, stagger, press effects, loops and a sequence on launch.
|
|
292
|
+
|
|
293
|
+
With the [NativeScript CLI](https://docs.nativescript.org/setup/) installed:
|
|
294
|
+
|
|
295
|
+
```sh
|
|
296
|
+
npm install
|
|
297
|
+
npm run dev # builds Jolt in watch mode
|
|
298
|
+
|
|
299
|
+
cd demo
|
|
300
|
+
npm install
|
|
301
|
+
ns run ios # or: ns run android
|
|
302
|
+
```
|
|
303
|
+
|
|
304
|
+
## Development
|
|
305
|
+
|
|
306
|
+
```sh
|
|
307
|
+
npm test # unit tests
|
|
308
|
+
npm run typecheck # including the iOS and Android drivers, against the platform typings
|
|
309
|
+
npm run build
|
|
310
|
+
```
|
|
311
|
+
|
|
312
|
+
The tests run the engine against a fake platform driver ([`test/helpers.ts`](./test/helpers.ts)) with its own clock: it records the keyframes it would play and ends them when the clock passes their end.
|
|
313
|
+
|
|
314
|
+
### Releasing
|
|
315
|
+
|
|
316
|
+
1. Bump `version` in `package.json` (`npm version <version> --no-git-tag-version`) and move the changes under it in `CHANGELOG.md`.
|
|
317
|
+
2. Merge that into `main`.
|
|
318
|
+
3. Publish a GitHub release tagged `v<version>`. The [release workflow](./.github/workflows/release.yml) checks the tag against `package.json`, runs the tests and publishes to npm: under `next` when the release is marked as a pre-release, under `latest` otherwise.
|
|
319
|
+
|
|
320
|
+
Publishing authenticates with the `NPM_TOKEN` secret, or with [trusted publishing](https://docs.npmjs.com/trusted-publishers) once it's set up for the package on npm.
|
|
321
|
+
|
|
322
|
+
## License
|
|
323
|
+
|
|
324
|
+
[MIT](./LICENSE)
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { View } from '@nativescript/core';
|
|
2
|
+
import { type Animation } from './engine.js';
|
|
3
|
+
import { type PresetName } from './presets.js';
|
|
4
|
+
import { type Property } from './properties.js';
|
|
5
|
+
import { type SpringName } from './transition.js';
|
|
6
|
+
import type { AnimateOptions, Keyframes, Target } from './types.js';
|
|
7
|
+
/**
|
|
8
|
+
* Animates one view, or several. Takes keyframes or the name of a preset,
|
|
9
|
+
* and a transition or the name of a spring.
|
|
10
|
+
*
|
|
11
|
+
* ```ts
|
|
12
|
+
* animate(card, 'fadeInUp')
|
|
13
|
+
* animate(card, { scale: 1.1, rotate: [0, 90] }, 'bouncy')
|
|
14
|
+
* animate(rows, 'fadeInUp', { stagger: 40 })
|
|
15
|
+
* ```
|
|
16
|
+
*/
|
|
17
|
+
export declare function animate(target: Target | readonly Target[], animation: Keyframes | PresetName, options?: AnimateOptions | SpringName): Animation;
|
|
18
|
+
/** Stops all or selected properties at their current values. `scale` stops both axes. */
|
|
19
|
+
export declare function stop(target: Target | readonly Target[], properties?: readonly (keyof Keyframes)[]): void;
|
|
20
|
+
/** Plays several animations as one: finished once they all are, and stopped together. */
|
|
21
|
+
export declare function group(animations: readonly Animation[]): Animation;
|
|
22
|
+
export declare function toView(target: Target): View;
|
|
23
|
+
export declare function toViews(target: Target | readonly Target[]): View[];
|
|
24
|
+
/** Each property the animation touches, with the value it starts from when it sets one. */
|
|
25
|
+
export declare function startingValues(animation: Keyframes | PresetName, options?: AnimateOptions | SpringName): Map<Property, number | null>;
|
|
26
|
+
//# sourceMappingURL=animate.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"animate.d.ts","sourceRoot":"","sources":["../src/animate.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,oBAAoB,CAAA;AACzC,OAAO,EAKL,KAAK,SAAS,EAEf,MAAM,aAAa,CAAA;AACpB,OAAO,EAAa,KAAK,UAAU,EAAE,MAAM,cAAc,CAAA;AACzD,OAAO,EAAc,KAAK,QAAQ,EAAE,MAAM,iBAAiB,CAAA;AAC3D,OAAO,EAKL,KAAK,UAAU,EAEhB,MAAM,iBAAiB,CAAA;AACxB,OAAO,KAAK,EACV,cAAc,EACd,SAAS,EAGT,MAAM,EACP,MAAM,YAAY,CAAA;AASnB;;;;;;;;;GASG;AACH,wBAAgB,OAAO,CACrB,MAAM,EAAE,MAAM,GAAG,SAAS,MAAM,EAAE,EAClC,SAAS,EAAE,SAAS,GAAG,UAAU,EACjC,OAAO,CAAC,EAAE,cAAc,GAAG,UAAU,GACpC,SAAS,CA0BX;AAED,yFAAyF;AACzF,wBAAgB,IAAI,CAClB,MAAM,EAAE,MAAM,GAAG,SAAS,MAAM,EAAE,EAClC,UAAU,CAAC,EAAE,SAAS,CAAC,MAAM,SAAS,CAAC,EAAE,QAM1C;AAED,yFAAyF;AACzF,wBAAgB,KAAK,CAAC,UAAU,EAAE,SAAS,SAAS,EAAE,GAAG,SAAS,CAWjE;AAED,wBAAgB,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAO3C;AAED,wBAAgB,OAAO,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,MAAM,EAAE,GAAG,IAAI,EAAE,CAElE;AAwED,2FAA2F;AAC3F,wBAAgB,cAAc,CAC5B,SAAS,EAAE,SAAS,GAAG,UAAU,EACjC,OAAO,CAAC,EAAE,cAAc,GAAG,UAAU,gCAOtC"}
|
package/dist/animate.js
ADDED
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
import { View } from '@nativescript/core';
|
|
2
|
+
import { arrivalOf, setArrival, stopView, ViewAnimation, } from './engine.js';
|
|
3
|
+
import { getPreset } from './presets.js';
|
|
4
|
+
import { isProperty } from './properties.js';
|
|
5
|
+
import { hasCurve, mergeTransitions, resolveTransition, springs, } from './transition.js';
|
|
6
|
+
/**
|
|
7
|
+
* Animates one view, or several. Takes keyframes or the name of a preset,
|
|
8
|
+
* and a transition or the name of a spring.
|
|
9
|
+
*
|
|
10
|
+
* ```ts
|
|
11
|
+
* animate(card, 'fadeInUp')
|
|
12
|
+
* animate(card, { scale: 1.1, rotate: [0, 90] }, 'bouncy')
|
|
13
|
+
* animate(rows, 'fadeInUp', { stagger: 40 })
|
|
14
|
+
* ```
|
|
15
|
+
*/
|
|
16
|
+
export function animate(target, animation, options) {
|
|
17
|
+
const { keyframes, base, overrides, stagger, relative } = prepare(animation, options);
|
|
18
|
+
if (!isList(target)) {
|
|
19
|
+
return new ViewAnimation(toView(target), plan(keyframes, base, overrides, 0, relative));
|
|
20
|
+
}
|
|
21
|
+
const views = target.map(toView);
|
|
22
|
+
return group(views.map((view, index) => new ViewAnimation(view, plan(keyframes, base, overrides, staggerDelay(stagger, index, views.length), relative))));
|
|
23
|
+
}
|
|
24
|
+
/** Stops all or selected properties at their current values. `scale` stops both axes. */
|
|
25
|
+
export function stop(target, properties) {
|
|
26
|
+
const expanded = properties?.flatMap((property) => property === 'scale' ? ['scaleX', 'scaleY'] : [property]);
|
|
27
|
+
for (const view of toViews(target))
|
|
28
|
+
stopView(view, expanded);
|
|
29
|
+
}
|
|
30
|
+
/** Plays several animations as one: finished once they all are, and stopped together. */
|
|
31
|
+
export function group(animations) {
|
|
32
|
+
const finished = Promise.all(animations.map((animation) => animation.finished)).then((results) => results.every(Boolean));
|
|
33
|
+
const animation = {
|
|
34
|
+
finished,
|
|
35
|
+
stop: () => animations.forEach((animation) => animation.stop()),
|
|
36
|
+
then: (onfulfilled, onrejected) => finished.then(onfulfilled, onrejected),
|
|
37
|
+
};
|
|
38
|
+
setArrival(animation, Promise.all(animations.map(arrivalOf)));
|
|
39
|
+
return animation;
|
|
40
|
+
}
|
|
41
|
+
export function toView(target) {
|
|
42
|
+
if (target instanceof View)
|
|
43
|
+
return target;
|
|
44
|
+
const view = target?.nativeView ??
|
|
45
|
+
target?.nativeElement;
|
|
46
|
+
if (view instanceof View)
|
|
47
|
+
return view;
|
|
48
|
+
throw new TypeError(`Expected a NativeScript view, got ${String(target)}.`);
|
|
49
|
+
}
|
|
50
|
+
export function toViews(target) {
|
|
51
|
+
return isList(target) ? target.map(toView) : [toView(target)];
|
|
52
|
+
}
|
|
53
|
+
function isList(target) {
|
|
54
|
+
return Array.isArray(target);
|
|
55
|
+
}
|
|
56
|
+
function prepare(animation, options) {
|
|
57
|
+
const user = normalize(options);
|
|
58
|
+
if (typeof animation !== 'string')
|
|
59
|
+
return { keyframes: animation, ...user };
|
|
60
|
+
const preset = getPreset(animation);
|
|
61
|
+
const own = normalize(preset.transition);
|
|
62
|
+
return {
|
|
63
|
+
keyframes: preset.keyframes,
|
|
64
|
+
base: mergeTransitions(own.base, user.base),
|
|
65
|
+
overrides: hasCurve(user.base)
|
|
66
|
+
? user.overrides
|
|
67
|
+
: { ...own.overrides, ...user.overrides },
|
|
68
|
+
stagger: user.stagger ?? own.stagger,
|
|
69
|
+
relative: user.relative ?? own.relative,
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
function normalize(options) {
|
|
73
|
+
if (options === undefined)
|
|
74
|
+
return { base: {}, overrides: {}, stagger: undefined, relative: undefined };
|
|
75
|
+
if (typeof options === 'string')
|
|
76
|
+
return {
|
|
77
|
+
base: spring(options),
|
|
78
|
+
overrides: {},
|
|
79
|
+
stagger: undefined,
|
|
80
|
+
relative: undefined,
|
|
81
|
+
};
|
|
82
|
+
const base = {};
|
|
83
|
+
const overrides = {};
|
|
84
|
+
let stagger;
|
|
85
|
+
let relative;
|
|
86
|
+
for (const [key, value] of Object.entries(options)) {
|
|
87
|
+
if (value === undefined)
|
|
88
|
+
continue;
|
|
89
|
+
if (key === 'stagger')
|
|
90
|
+
stagger = value;
|
|
91
|
+
else if (key === 'relative')
|
|
92
|
+
relative = value;
|
|
93
|
+
else if (key === 'scale' || isProperty(key)) {
|
|
94
|
+
overrides[key] = typeof value === 'string' ? spring(value) : value;
|
|
95
|
+
}
|
|
96
|
+
else
|
|
97
|
+
base[key] = value;
|
|
98
|
+
}
|
|
99
|
+
return { base, overrides, stagger, relative };
|
|
100
|
+
}
|
|
101
|
+
function plan(keyframes, base, overrides, offset, relative = false) {
|
|
102
|
+
return expand(keyframes).map(([property, frames]) => {
|
|
103
|
+
const override = overrides[property] ?? (property.startsWith('scale') ? overrides.scale : undefined);
|
|
104
|
+
const transition = resolveTransition(override ? mergeTransitions(base, override) : base, property, frames.length);
|
|
105
|
+
transition.delay += offset;
|
|
106
|
+
return { property, keyframes: frames, transition, relative };
|
|
107
|
+
});
|
|
108
|
+
}
|
|
109
|
+
/** Each property the animation touches, with the value it starts from when it sets one. */
|
|
110
|
+
export function startingValues(animation, options) {
|
|
111
|
+
const { keyframes, relative } = prepare(animation, options);
|
|
112
|
+
if (!keyframes)
|
|
113
|
+
throw new Error(`Unknown preset "${animation}".`);
|
|
114
|
+
return new Map(expand(keyframes).map(([property, [first]]) => [property, relative ? null : first]));
|
|
115
|
+
}
|
|
116
|
+
function expand(keyframes) {
|
|
117
|
+
const expanded = [];
|
|
118
|
+
for (const [key, value] of Object.entries(keyframes)) {
|
|
119
|
+
if (value === undefined)
|
|
120
|
+
continue;
|
|
121
|
+
if (key !== 'scale' && !isProperty(key))
|
|
122
|
+
throw new Error(`Can't animate "${key}".`);
|
|
123
|
+
const properties = key === 'scale' ? ['scaleX', 'scaleY'] : [key];
|
|
124
|
+
for (const property of properties) {
|
|
125
|
+
if (key === 'scale' && keyframes[property] !== undefined)
|
|
126
|
+
continue;
|
|
127
|
+
expanded.push([property, toKeyframes(property, value)]);
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
return expanded;
|
|
131
|
+
}
|
|
132
|
+
function toKeyframes(property, value) {
|
|
133
|
+
const frames = typeof value === 'number' ? [null, value] : [...value];
|
|
134
|
+
if (frames.length === 1)
|
|
135
|
+
frames.unshift(null);
|
|
136
|
+
if (frames.length === 0 ||
|
|
137
|
+
frames.some((frame) => frame !== null && !Number.isFinite(frame))) {
|
|
138
|
+
throw new Error(`Invalid keyframes for "${property}": ${JSON.stringify(value)}.`);
|
|
139
|
+
}
|
|
140
|
+
return frames;
|
|
141
|
+
}
|
|
142
|
+
function staggerDelay(stagger, index, count) {
|
|
143
|
+
if (stagger === undefined)
|
|
144
|
+
return 0;
|
|
145
|
+
const { each, from = 'first' } = typeof stagger === 'number' ? { each: stagger } : stagger;
|
|
146
|
+
const origin = from === 'first'
|
|
147
|
+
? 0
|
|
148
|
+
: from === 'last'
|
|
149
|
+
? count - 1
|
|
150
|
+
: from === 'center'
|
|
151
|
+
? (count - 1) / 2
|
|
152
|
+
: from;
|
|
153
|
+
return each * Math.abs(index - origin);
|
|
154
|
+
}
|
|
155
|
+
function spring(name) {
|
|
156
|
+
const transition = springs[name];
|
|
157
|
+
if (!transition)
|
|
158
|
+
throw new Error(`Unknown spring "${name}".`);
|
|
159
|
+
return transition;
|
|
160
|
+
}
|
|
161
|
+
//# sourceMappingURL=animate.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"animate.js","sourceRoot":"","sources":["../src/animate.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"android.d.ts","sourceRoot":"","sources":["../../src/driver/android.ts"],"names":[],"mappings":"AAEA,OAAO,EAAS,KAAK,MAAM,EAAE,MAAM,YAAY,CAAA;AAqB/C,wBAAgB,mBAAmB,IAAI,MAAM,CA6E5C"}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import { Utils } from '@nativescript/core';
|
|
2
|
+
import { after } from './index.js';
|
|
3
|
+
const accessors = {
|
|
4
|
+
opacity: { get: (v) => v.getAlpha(), set: (v, value) => v.setAlpha(value) },
|
|
5
|
+
x: { get: (v) => v.getTranslationX(), set: (v, value) => v.setTranslationX(value) },
|
|
6
|
+
y: { get: (v) => v.getTranslationY(), set: (v, value) => v.setTranslationY(value) },
|
|
7
|
+
scaleX: { get: (v) => v.getScaleX(), set: (v, value) => v.setScaleX(value) },
|
|
8
|
+
scaleY: { get: (v) => v.getScaleY(), set: (v, value) => v.setScaleY(value) },
|
|
9
|
+
rotate: { get: (v) => v.getRotation(), set: (v, value) => v.setRotation(value) },
|
|
10
|
+
rotateX: { get: (v) => v.getRotationX(), set: (v, value) => v.setRotationX(value) },
|
|
11
|
+
rotateY: { get: (v) => v.getRotationY(), set: (v, value) => v.setRotationY(value) },
|
|
12
|
+
};
|
|
13
|
+
const unit = (property) => property === 'x' || property === 'y' ? Utils.layout.getDisplayDensity() : 1;
|
|
14
|
+
export function createAndroidDriver() {
|
|
15
|
+
const { View } = android.view;
|
|
16
|
+
const nativeProperties = {
|
|
17
|
+
opacity: View.ALPHA,
|
|
18
|
+
x: View.TRANSLATION_X,
|
|
19
|
+
y: View.TRANSLATION_Y,
|
|
20
|
+
scaleX: View.SCALE_X,
|
|
21
|
+
scaleY: View.SCALE_Y,
|
|
22
|
+
rotate: View.ROTATION,
|
|
23
|
+
rotateX: View.ROTATION_X,
|
|
24
|
+
rotateY: View.ROTATION_Y,
|
|
25
|
+
};
|
|
26
|
+
const interpolator = new android.view.animation.LinearInterpolator();
|
|
27
|
+
return {
|
|
28
|
+
now: () => android.os.SystemClock.uptimeMillis(),
|
|
29
|
+
play(view, track, _startedAt, onEnd) {
|
|
30
|
+
const nativeView = view.nativeViewProtected;
|
|
31
|
+
const scale = unit(track.property);
|
|
32
|
+
const keyframes = Array.create(android.animation.Keyframe, track.values.length);
|
|
33
|
+
track.values.forEach((value, i) => {
|
|
34
|
+
keyframes[i] = android.animation.Keyframe.ofFloat(track.times[i], value * scale);
|
|
35
|
+
});
|
|
36
|
+
const holders = Array.create(android.animation.PropertyValuesHolder, 1);
|
|
37
|
+
holders[0] = android.animation.PropertyValuesHolder.ofKeyframe(nativeProperties[track.property], keyframes);
|
|
38
|
+
const animator = android.animation.ObjectAnimator.ofPropertyValuesHolder(nativeView, holders);
|
|
39
|
+
animator.setDuration(Math.max(track.duration, 1));
|
|
40
|
+
animator.setStartDelay(track.delay);
|
|
41
|
+
animator.setInterpolator(interpolator);
|
|
42
|
+
if (track.repeat > 0) {
|
|
43
|
+
animator.setRepeatCount(Number.isFinite(track.repeat)
|
|
44
|
+
? track.repeat
|
|
45
|
+
: android.animation.ValueAnimator.INFINITE);
|
|
46
|
+
animator.setRepeatMode(track.reverse
|
|
47
|
+
? android.animation.ValueAnimator.REVERSE
|
|
48
|
+
: android.animation.ValueAnimator.RESTART);
|
|
49
|
+
}
|
|
50
|
+
animator.addListener(new android.animation.Animator.AnimatorListener({
|
|
51
|
+
onAnimationStart() { },
|
|
52
|
+
onAnimationRepeat() { },
|
|
53
|
+
onAnimationCancel() { },
|
|
54
|
+
onAnimationEnd() {
|
|
55
|
+
onEnd();
|
|
56
|
+
},
|
|
57
|
+
}));
|
|
58
|
+
accessors[track.property].set(nativeView, track.values[0] * scale);
|
|
59
|
+
animator.start();
|
|
60
|
+
return animator;
|
|
61
|
+
},
|
|
62
|
+
stop(_view, handle) {
|
|
63
|
+
;
|
|
64
|
+
handle.cancel();
|
|
65
|
+
},
|
|
66
|
+
presented(view, property) {
|
|
67
|
+
const nativeView = view.nativeViewProtected;
|
|
68
|
+
return nativeView ? accessors[property].get(nativeView) / unit(property) : undefined;
|
|
69
|
+
},
|
|
70
|
+
after,
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
//# sourceMappingURL=android.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"android.js","sourceRoot":"","sources":["../../src/driver/android.ts"],"names":[],"mappings":"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"}
|