@rafaelaugusto/jolt 0.1.0-beta.3 → 0.1.0-beta.4
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 +55 -13
- package/dist/animate.d.ts.map +1 -1
- package/dist/animate.js +24 -2
- package/dist/animate.js.map +1 -1
- package/dist/color.d.ts +11 -0
- package/dist/color.d.ts.map +1 -0
- package/dist/color.js +73 -0
- package/dist/color.js.map +1 -0
- package/dist/driver/android-color.d.ts +17 -0
- package/dist/driver/android-color.d.ts.map +1 -0
- package/dist/driver/android-color.js +134 -0
- package/dist/driver/android-color.js.map +1 -0
- package/dist/driver/android.d.ts.map +1 -1
- package/dist/driver/android.js +6 -0
- package/dist/driver/android.js.map +1 -1
- package/dist/driver/index.d.ts +1 -1
- package/dist/driver/index.d.ts.map +1 -1
- package/dist/driver/index.js.map +1 -1
- package/dist/driver/ios-color.d.ts +14 -0
- package/dist/driver/ios-color.d.ts.map +1 -0
- package/dist/driver/ios-color.js +381 -0
- package/dist/driver/ios-color.js.map +1 -0
- package/dist/driver/ios.d.ts.map +1 -1
- package/dist/driver/ios.js +9 -1
- package/dist/driver/ios.js.map +1 -1
- package/dist/engine.d.ts.map +1 -1
- package/dist/engine.js +9 -5
- package/dist/engine.js.map +1 -1
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/liquid-grid.d.ts +3 -0
- package/dist/liquid-grid.d.ts.map +1 -0
- package/dist/liquid-grid.js +24 -0
- package/dist/liquid-grid.js.map +1 -0
- package/dist/liquid.d.ts +18 -0
- package/dist/liquid.d.ts.map +1 -0
- package/dist/liquid.js +229 -0
- package/dist/liquid.js.map +1 -0
- package/dist/press.d.ts.map +1 -1
- package/dist/press.js +6 -1
- package/dist/press.js.map +1 -1
- package/dist/properties.d.ts +4 -2
- package/dist/properties.d.ts.map +1 -1
- package/dist/properties.js +12 -1
- package/dist/properties.js.map +1 -1
- package/dist/text.d.ts.map +1 -1
- package/dist/text.js +3 -0
- package/dist/text.js.map +1 -1
- package/dist/track.d.ts +1 -1
- package/dist/track.d.ts.map +1 -1
- package/dist/track.js +38 -2
- package/dist/track.js.map +1 -1
- package/dist/transition.d.ts.map +1 -1
- package/dist/transition.js +8 -2
- package/dist/transition.js.map +1 -1
- package/dist/types.d.ts +5 -0
- package/dist/types.d.ts.map +1 -1
- package/package.json +11 -2
- package/platforms/android/include.gradle +7 -0
- package/platforms/android/java/org/rafaelaugusto/jolt/ColorTarget.java +102 -0
- package/platforms/android/proguard-rules.pro +6 -0
- package/src/animate.ts +30 -4
- package/src/color.ts +101 -0
- package/src/driver/android-color.ts +168 -0
- package/src/driver/android.ts +8 -4
- package/src/driver/index.ts +6 -1
- package/src/driver/ios-color.ts +432 -0
- package/src/driver/ios.ts +13 -3
- package/src/engine.ts +9 -5
- package/src/index.ts +3 -0
- package/src/liquid-grid.ts +28 -0
- package/src/liquid.ts +282 -0
- package/src/press.ts +8 -2
- package/src/properties.ts +15 -5
- package/src/text.ts +2 -0
- package/src/track.ts +63 -2
- package/src/transition.ts +10 -2
- package/src/types.ts +5 -0
package/dist/transition.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { resolveEasing } from './easing.js';
|
|
2
|
+
import { isColorProperty } from './color.js';
|
|
2
3
|
import { springPhysics } from './spring.js';
|
|
3
4
|
export const springs = {
|
|
4
5
|
smooth: { type: 'spring', duration: 500, bounce: 0 },
|
|
@@ -30,7 +31,10 @@ export function resolveTransition(transition, property, keyframes) {
|
|
|
30
31
|
const type = transition.type ??
|
|
31
32
|
(springKeys.some((key) => transition[key] !== undefined)
|
|
32
33
|
? 'spring'
|
|
33
|
-
: hasCurve(transition) ||
|
|
34
|
+
: hasCurve(transition) ||
|
|
35
|
+
property === 'opacity' ||
|
|
36
|
+
isColorProperty(property) ||
|
|
37
|
+
keyframes > 2
|
|
34
38
|
? 'tween'
|
|
35
39
|
: 'spring');
|
|
36
40
|
const delay = transition.delay ?? 0;
|
|
@@ -52,7 +56,9 @@ export function resolveTransition(transition, property, keyframes) {
|
|
|
52
56
|
}
|
|
53
57
|
const tween = transition;
|
|
54
58
|
const duration = tween.duration ?? DEFAULT_DURATION;
|
|
55
|
-
if (duration < 0 ||
|
|
59
|
+
if (duration < 0 ||
|
|
60
|
+
Number.isNaN(duration) ||
|
|
61
|
+
(isColorProperty(property) && !Number.isFinite(duration))) {
|
|
56
62
|
throw new RangeError(`Invalid duration: ${duration}.`);
|
|
57
63
|
}
|
|
58
64
|
const segments = keyframes - 1;
|
package/dist/transition.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"transition.js","sourceRoot":"","sources":["../src/transition.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAoC,MAAM,aAAa,CAAA;AAE7E,OAAO,EAAE,aAAa,EAAsB,MAAM,aAAa,CAAA;AAsC/D,MAAM,CAAC,MAAM,OAAO,GAA+B;IACjD,MAAM,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,QAAQ,EAAE,GAAG,EAAE,MAAM,EAAE,CAAC,EAAE;IACpD,MAAM,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,QAAQ,EAAE,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE;IACvD,MAAM,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,QAAQ,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE;CACvD,CAAA;AAwBD,MAAM,UAAU,GAAG,CAAC,WAAW,EAAE,SAAS,EAAE,MAAM,EAAE,QAAQ,EAAE,UAAU,CAAU,CAAA;AAClF,MAAM,SAAS,GAAG,CAAC,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,OAAO,EAAE,GAAG,UAAU,CAAU,CAAA;AAC/E,MAAM,UAAU,GAAG,CAAC,OAAO,EAAE,QAAQ,EAAE,YAAY,CAAU,CAAA;AAE7D,MAAM,CAAC,MAAM,gBAAgB,GAAG,GAAG,CAAA;AAEnC,MAAM,UAAU,QAAQ,CAAC,UAAsB;IAC7C,OAAO,SAAS,CAAC,IAAI,CACnB,CAAC,GAAG,EAAE,EAAE,CAAE,UAAsC,CAAC,GAAG,CAAC,KAAK,SAAS,CACpE,CAAA;AACH,CAAC;AAED,MAAM,UAAU,QAAQ,CAAC,UAAsB;IAC7C,MAAM,MAAM,GAA4B,EAAE,CAAA;IAC1C,KAAK,MAAM,GAAG,IAAI,UAAU,EAAE,CAAC;QAC7B,IAAI,UAAU,CAAC,GAAG,CAAC,KAAK,SAAS;YAAE,MAAM,CAAC,GAAG,CAAC,GAAG,UAAU,CAAC,GAAG,CAAC,CAAA;IAClE,CAAC;IACD,OAAO,MAAM,CAAA;AACf,CAAC;AAED,sFAAsF;AACtF,MAAM,UAAU,gBAAgB,CAAC,IAAgB,EAAE,QAAoB;IACrE,OAAO,QAAQ,CAAC,QAAQ,CAAC;QACvB,CAAC,CAAC,EAAE,GAAG,QAAQ,CAAC,IAAI,CAAC,EAAE,GAAG,QAAQ,EAAE;QACpC,CAAC,CAAC,EAAE,GAAG,IAAI,EAAE,GAAG,QAAQ,CAAC,QAAQ,CAAC,EAAE,CAAA;AACxC,CAAC;AAED,MAAM,UAAU,iBAAiB,CAC/B,UAAsB,EACtB,QAAkB,EAClB,SAAiB;IAEjB,MAAM,IAAI,GACR,UAAU,CAAC,IAAI;QACf,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC,GAAG,EAAE,EAAE,CAAE,UAAqB,CAAC,GAAG,CAAC,KAAK,SAAS,CAAC;YAClE,CAAC,CAAC,QAAQ;YACV,CAAC,CAAC,QAAQ,CAAC,UAAU,CAAC,
|
|
1
|
+
{"version":3,"file":"transition.js","sourceRoot":"","sources":["../src/transition.ts"],"names":[],"mappings":"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"}
|
package/dist/types.d.ts
CHANGED
|
@@ -1,9 +1,14 @@
|
|
|
1
1
|
import type { View } from '@nativescript/core';
|
|
2
2
|
import type { Haptic } from './haptics.js';
|
|
3
3
|
import type { SpringName, Transition } from './transition.js';
|
|
4
|
+
import type { ColorKeyframes } from './color.js';
|
|
4
5
|
/** A value to animate to, or keyframes. `null` stands for the value the view has when the animation starts. */
|
|
5
6
|
export type KeyframeValue = number | readonly (number | null)[];
|
|
6
7
|
export interface Keyframes {
|
|
8
|
+
backgroundColor?: ColorKeyframes;
|
|
9
|
+
/** Uniform starting edge colors; widths and radii may differ. */
|
|
10
|
+
borderColor?: ColorKeyframes;
|
|
11
|
+
color?: ColorKeyframes;
|
|
7
12
|
opacity?: KeyframeValue;
|
|
8
13
|
/** Same as `translateX`, in DIPs. */
|
|
9
14
|
x?: KeyframeValue;
|
package/dist/types.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,oBAAoB,CAAA;AAC9C,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,cAAc,CAAA;AAC1C,OAAO,KAAK,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAA;
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,oBAAoB,CAAA;AAC9C,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,cAAc,CAAA;AAC1C,OAAO,KAAK,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAA;AAC7D,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,YAAY,CAAA;AAEhD,+GAA+G;AAC/G,MAAM,MAAM,aAAa,GAAG,MAAM,GAAG,SAAS,CAAC,MAAM,GAAG,IAAI,CAAC,EAAE,CAAA;AAE/D,MAAM,WAAW,SAAS;IACxB,eAAe,CAAC,EAAE,cAAc,CAAA;IAChC,iEAAiE;IACjE,WAAW,CAAC,EAAE,cAAc,CAAA;IAC5B,KAAK,CAAC,EAAE,cAAc,CAAA;IACtB,OAAO,CAAC,EAAE,aAAa,CAAA;IACvB,qCAAqC;IACrC,CAAC,CAAC,EAAE,aAAa,CAAA;IACjB,qCAAqC;IACrC,CAAC,CAAC,EAAE,aAAa,CAAA;IACjB,2CAA2C;IAC3C,KAAK,CAAC,EAAE,aAAa,CAAA;IACrB,MAAM,CAAC,EAAE,aAAa,CAAA;IACtB,MAAM,CAAC,EAAE,aAAa,CAAA;IACtB,eAAe;IACf,MAAM,CAAC,EAAE,aAAa,CAAA;IACtB,OAAO,CAAC,EAAE,aAAa,CAAA;IACvB,OAAO,CAAC,EAAE,aAAa,CAAA;CACxB;AAED,+FAA+F;AAC/F,MAAM,MAAM,MAAM,GAChB,IAAI,GAAG;IAAE,QAAQ,CAAC,UAAU,EAAE,IAAI,CAAA;CAAE,GAAG;IAAE,QAAQ,CAAC,aAAa,EAAE,IAAI,CAAA;CAAE,CAAA;AAEzE,yFAAyF;AACzF,MAAM,WAAW,aAAa;IAC5B,CAAC,CAAC,EAAE,MAAM,CAAA;IACV,CAAC,CAAC,EAAE,MAAM,CAAA;CACX;AAED,MAAM,WAAW,YAAY;IAC3B,2FAA2F;IAC3F,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,mFAAmF;IACnF,IAAI,CAAC,EAAE,SAAS,MAAM,EAAE,GAAG;QAAE,CAAC,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;QAAC,CAAC,CAAC,EAAE,SAAS,MAAM,EAAE,CAAA;KAAE,CAAA;CAC5E;AAED,MAAM,WAAW,OAAO;IACtB,oDAAoD;IACpD,IAAI,EAAE,MAAM,CAAA;IACZ,iCAAiC;IACjC,IAAI,CAAC,EAAE,OAAO,GAAG,MAAM,GAAG,QAAQ,GAAG,MAAM,CAAA;CAC5C;AAED,MAAM,MAAM,cAAc,GAAG,UAAU,GAAG;KACvC,CAAC,IAAI,MAAM,SAAS,CAAC,CAAC,EAAE,UAAU,GAAG,UAAU;CACjD,GAAG;IACF,6FAA6F;IAC7F,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB,iFAAiF;IACjF,OAAO,CAAC,EAAE,MAAM,GAAG,OAAO,CAAA;IAC1B,mFAAmF;IACnF,MAAM,CAAC,EAAE,MAAM,CAAA;CAChB,CAAA"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@rafaelaugusto/jolt",
|
|
3
|
-
"version": "0.1.0-beta.
|
|
3
|
+
"version": "0.1.0-beta.4",
|
|
4
4
|
"description": "Native animations for NativeScript: presets, springs, keyframes and stagger in one call.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"nativescript",
|
|
@@ -32,7 +32,10 @@
|
|
|
32
32
|
},
|
|
33
33
|
"files": [
|
|
34
34
|
"dist",
|
|
35
|
-
"src"
|
|
35
|
+
"src",
|
|
36
|
+
"platforms/android/java",
|
|
37
|
+
"platforms/android/include.gradle",
|
|
38
|
+
"platforms/android/proguard-rules.pro"
|
|
36
39
|
],
|
|
37
40
|
"sideEffects": false,
|
|
38
41
|
"scripts": {
|
|
@@ -66,5 +69,11 @@
|
|
|
66
69
|
},
|
|
67
70
|
"publishConfig": {
|
|
68
71
|
"access": "public"
|
|
72
|
+
},
|
|
73
|
+
"nativescript": {
|
|
74
|
+
"platforms": {
|
|
75
|
+
"android": "8.9.0",
|
|
76
|
+
"ios": "8.9.0"
|
|
77
|
+
}
|
|
69
78
|
}
|
|
70
79
|
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
// Applied by the NativeScript app. Preserve fields used by the native color target.
|
|
2
|
+
def joltDependency = nativescriptDependencies.find { it.name == '@rafaelaugusto/jolt' }
|
|
3
|
+
if (joltDependency != null) {
|
|
4
|
+
android.buildTypes.all {
|
|
5
|
+
proguardFile new File(rootDir, "${joltDependency.directory}/platforms/android/proguard-rules.pro")
|
|
6
|
+
}
|
|
7
|
+
}
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
package org.rafaelaugusto.jolt;
|
|
2
|
+
|
|
3
|
+
import android.graphics.PorterDuff;
|
|
4
|
+
import android.graphics.drawable.ColorDrawable;
|
|
5
|
+
import android.graphics.drawable.Drawable;
|
|
6
|
+
import android.view.View;
|
|
7
|
+
import android.widget.TextView;
|
|
8
|
+
import java.lang.ref.WeakReference;
|
|
9
|
+
import java.lang.reflect.Field;
|
|
10
|
+
import java.lang.reflect.Method;
|
|
11
|
+
|
|
12
|
+
/** ObjectAnimator target. All frame updates stay in native code. */
|
|
13
|
+
public final class ColorTarget {
|
|
14
|
+
private static final String BORDER = "org.nativescript.widgets.BorderDrawable";
|
|
15
|
+
private static final Field[] FIELDS = fields();
|
|
16
|
+
private static final String SHADOW = "org.nativescript.widgets.BoxShadowDrawable";
|
|
17
|
+
private static final Method UNWRAP = unwrapMethod();
|
|
18
|
+
private final WeakReference<View> view;
|
|
19
|
+
private final int property;
|
|
20
|
+
private int color;
|
|
21
|
+
|
|
22
|
+
// 0 = background, 1 = uniform border, 2 = text.
|
|
23
|
+
public ColorTarget(View view, int property, int initialColor) {
|
|
24
|
+
this.view = new WeakReference<>(view);
|
|
25
|
+
this.property = property;
|
|
26
|
+
this.color = initialColor;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
private static Field[] fields() {
|
|
30
|
+
try {
|
|
31
|
+
Class<?> type = Class.forName(BORDER);
|
|
32
|
+
String[] names = {"backgroundColor", "borderTopColor", "borderRightColor", "borderBottomColor", "borderLeftColor"};
|
|
33
|
+
Field[] result = new Field[names.length];
|
|
34
|
+
for (int i = 0; i < names.length; i++) {
|
|
35
|
+
result[i] = type.getDeclaredField(names[i]);
|
|
36
|
+
result[i].setAccessible(true);
|
|
37
|
+
}
|
|
38
|
+
return result;
|
|
39
|
+
} catch (ReflectiveOperationException | SecurityException exception) {
|
|
40
|
+
return null;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
private static Method unwrapMethod() {
|
|
45
|
+
try {
|
|
46
|
+
return Class.forName(SHADOW).getMethod("getWrappedDrawable");
|
|
47
|
+
} catch (ReflectiveOperationException exception) {
|
|
48
|
+
return null;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
private Drawable background(View nativeView) {
|
|
53
|
+
Drawable drawable = nativeView.getBackground();
|
|
54
|
+
// Avoid reflective method lookups and exceptions in the frame loop.
|
|
55
|
+
if (drawable != null && drawable.getClass().getName().equals(SHADOW) && UNWRAP != null) {
|
|
56
|
+
try {
|
|
57
|
+
return (Drawable) UNWRAP.invoke(drawable);
|
|
58
|
+
} catch (ReflectiveOperationException exception) {
|
|
59
|
+
return drawable;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
return drawable;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
public boolean isSupported() {
|
|
66
|
+
View nativeView = view.get();
|
|
67
|
+
if (nativeView == null) return false;
|
|
68
|
+
if (property == 2) return nativeView instanceof TextView;
|
|
69
|
+
Drawable drawable = background(nativeView);
|
|
70
|
+
if (drawable == null) return true;
|
|
71
|
+
if (drawable.getClass().getName().equals(SHADOW)) return false;
|
|
72
|
+
return !drawable.getClass().getName().equals(BORDER) || FIELDS != null;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
public int getColor() { return color; }
|
|
76
|
+
|
|
77
|
+
public void setColor(int value) {
|
|
78
|
+
View nativeView = view.get();
|
|
79
|
+
if (nativeView == null) return;
|
|
80
|
+
color = value;
|
|
81
|
+
if (property == 2) {
|
|
82
|
+
((TextView) nativeView).setTextColor(value);
|
|
83
|
+
return;
|
|
84
|
+
}
|
|
85
|
+
// Resolve on every frame: a Core style update may replace the drawable.
|
|
86
|
+
Drawable drawable = background(nativeView);
|
|
87
|
+
if (drawable == null || drawable.getClass().getName().equals(SHADOW)) return;
|
|
88
|
+
if (drawable.getClass().getName().equals(BORDER)) {
|
|
89
|
+
if (FIELDS == null) return;
|
|
90
|
+
try {
|
|
91
|
+
if (property == 0) FIELDS[0].setInt(drawable, value);
|
|
92
|
+
else for (int i = 1; i < FIELDS.length; i++) FIELDS[i].setInt(drawable, value);
|
|
93
|
+
drawable.invalidateSelf();
|
|
94
|
+
} catch (IllegalAccessException exception) {
|
|
95
|
+
// Unsupported Core versions keep the final model color.
|
|
96
|
+
}
|
|
97
|
+
} else if (property == 0) {
|
|
98
|
+
if (drawable instanceof ColorDrawable) ((ColorDrawable) drawable).setColor(value);
|
|
99
|
+
else drawable.setColorFilter(value, PorterDuff.Mode.SRC_IN);
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
-keep class org.rafaelaugusto.jolt.ColorTarget { *; }
|
|
2
|
+
-keep class org.nativescript.widgets.BorderDrawable { *; }
|
|
3
|
+
-keepnames class org.nativescript.widgets.BoxShadowDrawable
|
|
4
|
+
-keepclassmembers class org.nativescript.widgets.BoxShadowDrawable {
|
|
5
|
+
public android.graphics.drawable.Drawable getWrappedDrawable();
|
|
6
|
+
}
|
package/src/animate.ts
CHANGED
|
@@ -1,4 +1,10 @@
|
|
|
1
1
|
import { View } from '@nativescript/core'
|
|
2
|
+
import {
|
|
3
|
+
isColorProperty,
|
|
4
|
+
parseColor,
|
|
5
|
+
validateColorTarget,
|
|
6
|
+
type ColorKeyframes,
|
|
7
|
+
} from './color.js'
|
|
2
8
|
import { DEFAULT_FRICTION, solveDecay } from './decay.js'
|
|
3
9
|
import {
|
|
4
10
|
arrivalOf,
|
|
@@ -59,14 +65,20 @@ export function animate(
|
|
|
59
65
|
const feedback = resolveHaptic(haptic)
|
|
60
66
|
|
|
61
67
|
if (!isList(target)) {
|
|
68
|
+
const view = toView(target)
|
|
69
|
+
for (const property of Object.keys(keyframes))
|
|
70
|
+
if (isColorProperty(property)) validateColorTarget(view, property)
|
|
62
71
|
return new ViewAnimation(
|
|
63
|
-
|
|
72
|
+
view,
|
|
64
73
|
plan(keyframes, base, overrides, 0, relative),
|
|
65
74
|
feedback,
|
|
66
75
|
)
|
|
67
76
|
}
|
|
68
77
|
|
|
69
78
|
const views = target.map(toView)
|
|
79
|
+
for (const view of views)
|
|
80
|
+
for (const property of Object.keys(keyframes))
|
|
81
|
+
if (isColorProperty(property)) validateColorTarget(view, property)
|
|
70
82
|
return group(
|
|
71
83
|
views.map(
|
|
72
84
|
(view, index) =>
|
|
@@ -282,7 +294,10 @@ export function startingValues(
|
|
|
282
294
|
const { keyframes, relative } = prepare(animation, options)
|
|
283
295
|
if (!keyframes) throw new Error(`Unknown preset "${animation}".`)
|
|
284
296
|
return new Map(
|
|
285
|
-
expand(keyframes).map(([property, [first]]) => [
|
|
297
|
+
expand(keyframes).map(([property, [first]]) => [
|
|
298
|
+
property,
|
|
299
|
+
relative && !isColorProperty(property) ? null : first!,
|
|
300
|
+
]),
|
|
286
301
|
)
|
|
287
302
|
}
|
|
288
303
|
|
|
@@ -290,7 +305,7 @@ function expand(keyframes: Keyframes): [Property, (number | null)[]][] {
|
|
|
290
305
|
const expanded: [Property, (number | null)[]][] = []
|
|
291
306
|
for (const [key, value] of Object.entries(keyframes) as [
|
|
292
307
|
keyof Keyframes,
|
|
293
|
-
KeyframeValue | undefined,
|
|
308
|
+
KeyframeValue | ColorKeyframes | undefined,
|
|
294
309
|
][]) {
|
|
295
310
|
if (value === undefined) continue
|
|
296
311
|
if (key !== 'scale' && !isProperty(key)) throw new Error(`Can't animate "${key}".`)
|
|
@@ -304,7 +319,18 @@ function expand(keyframes: Keyframes): [Property, (number | null)[]][] {
|
|
|
304
319
|
return expanded
|
|
305
320
|
}
|
|
306
321
|
|
|
307
|
-
function toKeyframes(
|
|
322
|
+
function toKeyframes(
|
|
323
|
+
property: Property,
|
|
324
|
+
value: KeyframeValue | ColorKeyframes,
|
|
325
|
+
): (number | null)[] {
|
|
326
|
+
if (isColorProperty(property)) {
|
|
327
|
+
const frames = Array.isArray(value) ? [...value] : [null, value]
|
|
328
|
+
if (!frames.length) throw new TypeError(`Empty color keyframes for "${property}".`)
|
|
329
|
+
if (frames.length === 1) frames.unshift(null)
|
|
330
|
+
return frames.map((frame) => (frame === null ? null : parseColor(frame)))
|
|
331
|
+
}
|
|
332
|
+
if (typeof value !== 'number' && !Array.isArray(value))
|
|
333
|
+
throw new TypeError(`Invalid numeric keyframes for "${property}".`)
|
|
308
334
|
const frames = typeof value === 'number' ? [null, value] : [...value]
|
|
309
335
|
if (frames.length === 1) frames.unshift(null)
|
|
310
336
|
if (
|
package/src/color.ts
ADDED
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
import { Button, Color, Label, TextBase, isIOS, type View } from '@nativescript/core'
|
|
2
|
+
|
|
3
|
+
export type ColorProperty = 'backgroundColor' | 'borderColor' | 'color'
|
|
4
|
+
export type ColorValue = string | Color
|
|
5
|
+
export type ColorKeyframes = ColorValue | readonly (ColorValue | null)[]
|
|
6
|
+
export const isColorProperty = (property: string): property is ColorProperty =>
|
|
7
|
+
property === 'backgroundColor' || property === 'borderColor' || property === 'color'
|
|
8
|
+
|
|
9
|
+
export function parseColor(value: unknown): number {
|
|
10
|
+
if (value instanceof Color) return value.argb >>> 0
|
|
11
|
+
if (typeof value !== 'string' || !Color.isValid(value))
|
|
12
|
+
throw new TypeError(`Invalid animation color: ${String(value)}.`)
|
|
13
|
+
return new Color(value).argb >>> 0
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export function readColor(view: View, property: ColorProperty): number {
|
|
17
|
+
const value = property === 'borderColor' ? view.borderTopColor : view[property]
|
|
18
|
+
return value instanceof Color
|
|
19
|
+
? value.argb >>> 0
|
|
20
|
+
: property === 'backgroundColor'
|
|
21
|
+
? 0
|
|
22
|
+
: 0xff000000
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export function validateColorTarget(view: View, property: ColorProperty) {
|
|
26
|
+
if (
|
|
27
|
+
property === 'color' &&
|
|
28
|
+
!(isIOS ? view instanceof Label || view instanceof Button : view instanceof TextBase)
|
|
29
|
+
)
|
|
30
|
+
throw new TypeError(
|
|
31
|
+
'Text color animation requires a Label or Button on iOS, or a TextBase on Android.',
|
|
32
|
+
)
|
|
33
|
+
if (property === 'borderColor') {
|
|
34
|
+
const colors = [
|
|
35
|
+
view.borderTopColor,
|
|
36
|
+
view.borderRightColor,
|
|
37
|
+
view.borderBottomColor,
|
|
38
|
+
view.borderLeftColor,
|
|
39
|
+
]
|
|
40
|
+
if (
|
|
41
|
+
colors.some(
|
|
42
|
+
(color) => (color?.argb ?? 0xff000000) !== (colors[0]?.argb ?? 0xff000000),
|
|
43
|
+
)
|
|
44
|
+
)
|
|
45
|
+
throw new TypeError(
|
|
46
|
+
'borderColor animation requires the same starting color on every edge.',
|
|
47
|
+
)
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
const clamp = (value: number) => Math.max(0, Math.min(1, value))
|
|
52
|
+
const linear = (channel: number) =>
|
|
53
|
+
channel <= 0.04045 ? channel / 12.92 : ((channel + 0.055) / 1.055) ** 2.4
|
|
54
|
+
const encoded = (channel: number) =>
|
|
55
|
+
channel <= 0.0031308 ? 12.92 * channel : 1.055 * channel ** (1 / 2.4) - 0.055
|
|
56
|
+
|
|
57
|
+
function lab(value: number) {
|
|
58
|
+
const r = linear(((value >>> 16) & 255) / 255)
|
|
59
|
+
const g = linear(((value >>> 8) & 255) / 255)
|
|
60
|
+
const b = linear((value & 255) / 255)
|
|
61
|
+
const l = Math.cbrt(0.4122214708 * r + 0.5363325363 * g + 0.0514459929 * b)
|
|
62
|
+
const m = Math.cbrt(0.2119034982 * r + 0.6806995451 * g + 0.1073969566 * b)
|
|
63
|
+
const s = Math.cbrt(0.0883024619 * r + 0.2817188376 * g + 0.6299787005 * b)
|
|
64
|
+
return [
|
|
65
|
+
0.2104542553 * l + 0.793617785 * m - 0.0040720468 * s,
|
|
66
|
+
1.9779984951 * l - 2.428592205 * m + 0.4505937099 * s,
|
|
67
|
+
0.0259040371 * l + 0.7827717662 * m - 0.808675766 * s,
|
|
68
|
+
] as const
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/** Premultiplied OKLab interpolation, clipped to the sRGB output gamut. */
|
|
72
|
+
export function colorMixer(from: number, to: number): (progress: number) => number {
|
|
73
|
+
const a = lab(from),
|
|
74
|
+
b = lab(to)
|
|
75
|
+
const alphaA = (from >>> 24) / 255,
|
|
76
|
+
alphaB = (to >>> 24) / 255
|
|
77
|
+
return (progress) => {
|
|
78
|
+
const p = clamp(progress)
|
|
79
|
+
if (p === 0) return from
|
|
80
|
+
if (p === 1) return to
|
|
81
|
+
const alpha = alphaA + (alphaB - alphaA) * p
|
|
82
|
+
if (alpha <= 0) return 0
|
|
83
|
+
const channel = (i: number) => (a[i]! * alphaA * (1 - p) + b[i]! * alphaB * p) / alpha
|
|
84
|
+
const L = channel(0),
|
|
85
|
+
A = channel(1),
|
|
86
|
+
B = channel(2)
|
|
87
|
+
const l = (L + 0.3963377774 * A + 0.2158037573 * B) ** 3
|
|
88
|
+
const m = (L - 0.1055613458 * A - 0.0638541728 * B) ** 3
|
|
89
|
+
const s = (L - 0.0894841775 * A - 1.291485548 * B) ** 3
|
|
90
|
+
const r = Math.round(
|
|
91
|
+
clamp(encoded(4.0767416621 * l - 3.3077115913 * m + 0.2309699292 * s)) * 255,
|
|
92
|
+
)
|
|
93
|
+
const g = Math.round(
|
|
94
|
+
clamp(encoded(-1.2684380046 * l + 2.6097574011 * m - 0.3413193965 * s)) * 255,
|
|
95
|
+
)
|
|
96
|
+
const blue = Math.round(
|
|
97
|
+
clamp(encoded(-0.0041960863 * l - 0.7034186147 * m + 1.707614701 * s)) * 255,
|
|
98
|
+
)
|
|
99
|
+
return ((Math.round(alpha * 255) << 24) | (r << 16) | (g << 8) | blue) >>> 0
|
|
100
|
+
}
|
|
101
|
+
}
|
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
import { type View } from '@nativescript/core'
|
|
2
|
+
import { readColor, type ColorProperty } from '../color.js'
|
|
3
|
+
import type { Track } from '../track.js'
|
|
4
|
+
|
|
5
|
+
interface NativeTarget {
|
|
6
|
+
getColor(): number
|
|
7
|
+
setColor(value: number): void
|
|
8
|
+
isSupported(): boolean
|
|
9
|
+
}
|
|
10
|
+
interface ColorHandle {
|
|
11
|
+
cancel(): void
|
|
12
|
+
elapsed(): number
|
|
13
|
+
target: NativeTarget
|
|
14
|
+
}
|
|
15
|
+
const playing = new WeakMap<View, Map<ColorProperty, ColorHandle>>()
|
|
16
|
+
|
|
17
|
+
export function presentedAndroidColor(view: View, property: ColorProperty): number {
|
|
18
|
+
const active = playing.get(view)?.get(property)
|
|
19
|
+
if (active) return active.target.getColor() >>> 0
|
|
20
|
+
if (property === 'color' && view.nativeViewProtected instanceof android.widget.TextView)
|
|
21
|
+
return view.nativeViewProtected.getCurrentTextColor() >>> 0
|
|
22
|
+
return readColor(view, property)
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export function playAndroidColor(
|
|
26
|
+
view: View,
|
|
27
|
+
track: Track,
|
|
28
|
+
onEnd: (finished?: boolean) => void,
|
|
29
|
+
): ColorHandle {
|
|
30
|
+
const property = track.property as ColorProperty
|
|
31
|
+
const changes =
|
|
32
|
+
property === 'borderColor'
|
|
33
|
+
? [
|
|
34
|
+
'borderTopColorChange',
|
|
35
|
+
'borderRightColorChange',
|
|
36
|
+
'borderBottomColorChange',
|
|
37
|
+
'borderLeftColorChange',
|
|
38
|
+
]
|
|
39
|
+
: [`${property}Change`]
|
|
40
|
+
const bridge = globalThis as unknown as {
|
|
41
|
+
org: {
|
|
42
|
+
rafaelaugusto: {
|
|
43
|
+
jolt: {
|
|
44
|
+
ColorTarget: new (
|
|
45
|
+
view: android.view.View,
|
|
46
|
+
property: number,
|
|
47
|
+
color: number,
|
|
48
|
+
) => NativeTarget
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
let target: NativeTarget
|
|
54
|
+
try {
|
|
55
|
+
target = new bridge.org.rafaelaugusto.jolt.ColorTarget(
|
|
56
|
+
view.nativeViewProtected,
|
|
57
|
+
property === 'backgroundColor' ? 0 : property === 'borderColor' ? 1 : 2,
|
|
58
|
+
track.values[0]! | 0,
|
|
59
|
+
)
|
|
60
|
+
} catch {
|
|
61
|
+
// A JS-only update cannot install the native plugin. Keep the final model.
|
|
62
|
+
onEnd(false)
|
|
63
|
+
return {
|
|
64
|
+
cancel() {},
|
|
65
|
+
elapsed: () => 0,
|
|
66
|
+
target: {
|
|
67
|
+
getColor: () => readColor(view, property),
|
|
68
|
+
setColor() {},
|
|
69
|
+
isSupported: () => false,
|
|
70
|
+
},
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
const frames = Array.create(android.animation.Keyframe, track.values.length)
|
|
74
|
+
track.values.forEach((value, index) => {
|
|
75
|
+
frames[index] = android.animation.Keyframe.ofInt(track.times[index]!, value | 0)
|
|
76
|
+
})
|
|
77
|
+
const holder = android.animation.PropertyValuesHolder.ofKeyframe('color', frames)
|
|
78
|
+
holder.setEvaluator(new android.animation.ArgbEvaluator())
|
|
79
|
+
const holders = Array.create(android.animation.PropertyValuesHolder, 1)
|
|
80
|
+
holders[0] = holder
|
|
81
|
+
const animator = android.animation.ObjectAnimator.ofPropertyValuesHolder(
|
|
82
|
+
target as unknown as java.lang.Object,
|
|
83
|
+
holders,
|
|
84
|
+
)
|
|
85
|
+
animator.setDuration(Math.max(track.duration, 1))
|
|
86
|
+
animator.setStartDelay(track.delay)
|
|
87
|
+
animator.setInterpolator(new android.view.animation.LinearInterpolator())
|
|
88
|
+
if (track.repeat > 0) {
|
|
89
|
+
animator.setRepeatCount(
|
|
90
|
+
Number.isFinite(track.repeat)
|
|
91
|
+
? track.repeat
|
|
92
|
+
: android.animation.ValueAnimator.INFINITE,
|
|
93
|
+
)
|
|
94
|
+
animator.setRepeatMode(
|
|
95
|
+
track.reverse
|
|
96
|
+
? android.animation.ValueAnimator.REVERSE
|
|
97
|
+
: android.animation.ValueAnimator.RESTART,
|
|
98
|
+
)
|
|
99
|
+
}
|
|
100
|
+
let stopped = false,
|
|
101
|
+
started = false,
|
|
102
|
+
queued = false
|
|
103
|
+
const cleanup = () => {
|
|
104
|
+
if (stopped) return
|
|
105
|
+
stopped = true
|
|
106
|
+
view.off('unloaded', cancel)
|
|
107
|
+
if (property === 'color') {
|
|
108
|
+
view.off('textChange', invalidate)
|
|
109
|
+
view.off('formattedTextChange', invalidate)
|
|
110
|
+
}
|
|
111
|
+
for (const name of changes) view.style.off(name, invalidate)
|
|
112
|
+
if (playing.get(view)?.get(property) === handle) playing.get(view)?.delete(property)
|
|
113
|
+
}
|
|
114
|
+
const cancel = () => {
|
|
115
|
+
if (stopped) return
|
|
116
|
+
cleanup()
|
|
117
|
+
animator.cancel()
|
|
118
|
+
onEnd(false)
|
|
119
|
+
}
|
|
120
|
+
const invalidate = () => {
|
|
121
|
+
if (stopped || queued) return
|
|
122
|
+
queued = true
|
|
123
|
+
void Promise.resolve().then(() => {
|
|
124
|
+
queued = false
|
|
125
|
+
if (!stopped) cancel()
|
|
126
|
+
})
|
|
127
|
+
}
|
|
128
|
+
const handle: ColorHandle = {
|
|
129
|
+
target,
|
|
130
|
+
elapsed: () => (started ? track.delay + animator.getCurrentPlayTime() : 0),
|
|
131
|
+
cancel() {
|
|
132
|
+
cleanup()
|
|
133
|
+
animator.cancel()
|
|
134
|
+
},
|
|
135
|
+
}
|
|
136
|
+
let entries = playing.get(view)
|
|
137
|
+
if (!entries) playing.set(view, (entries = new Map()))
|
|
138
|
+
entries.set(property, handle)
|
|
139
|
+
animator.addListener(
|
|
140
|
+
new android.animation.Animator.AnimatorListener({
|
|
141
|
+
onAnimationStart() {
|
|
142
|
+
started = true
|
|
143
|
+
},
|
|
144
|
+
onAnimationRepeat() {},
|
|
145
|
+
onAnimationCancel() {},
|
|
146
|
+
onAnimationEnd() {
|
|
147
|
+
if (!stopped) {
|
|
148
|
+
cleanup()
|
|
149
|
+
onEnd()
|
|
150
|
+
}
|
|
151
|
+
},
|
|
152
|
+
}),
|
|
153
|
+
)
|
|
154
|
+
view.on('unloaded', cancel)
|
|
155
|
+
if (property === 'color') {
|
|
156
|
+
view.on('textChange', invalidate)
|
|
157
|
+
view.on('formattedTextChange', invalidate)
|
|
158
|
+
}
|
|
159
|
+
for (const name of changes) view.style.on(name, invalidate)
|
|
160
|
+
if (target.isSupported()) {
|
|
161
|
+
target.setColor(track.values[0]! | 0)
|
|
162
|
+
animator.start()
|
|
163
|
+
} else {
|
|
164
|
+
cleanup()
|
|
165
|
+
onEnd(false)
|
|
166
|
+
}
|
|
167
|
+
return handle
|
|
168
|
+
}
|
package/src/driver/android.ts
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import { Utils, type View } from '@nativescript/core'
|
|
2
|
-
import type {
|
|
2
|
+
import type { NumericProperty } from '../properties.js'
|
|
3
3
|
import type { Driver } from './index.js'
|
|
4
|
+
import { isColorProperty } from '../color.js'
|
|
5
|
+
import { playAndroidColor, presentedAndroidColor } from './android-color.js'
|
|
4
6
|
|
|
5
7
|
type NativeView = android.view.View
|
|
6
8
|
|
|
@@ -44,7 +46,7 @@ function fadeLayer(view: View, nativeView: NativeView): (() => void) | undefined
|
|
|
44
46
|
}
|
|
45
47
|
|
|
46
48
|
const accessors: Record<
|
|
47
|
-
|
|
49
|
+
NumericProperty,
|
|
48
50
|
{ get(view: NativeView): number; set(view: NativeView, value: number): void }
|
|
49
51
|
> = {
|
|
50
52
|
opacity: { get: (v) => v.getAlpha(), set: (v, value) => v.setAlpha(value) },
|
|
@@ -57,7 +59,7 @@ const accessors: Record<
|
|
|
57
59
|
rotateY: { get: (v) => v.getRotationY(), set: (v, value) => v.setRotationY(value) },
|
|
58
60
|
}
|
|
59
61
|
|
|
60
|
-
const unit = (property:
|
|
62
|
+
const unit = (property: NumericProperty) =>
|
|
61
63
|
property === 'x' || property === 'y' ? Utils.layout.getDisplayDensity() : 1
|
|
62
64
|
|
|
63
65
|
export function createAndroidDriver(): Driver {
|
|
@@ -71,13 +73,14 @@ export function createAndroidDriver(): Driver {
|
|
|
71
73
|
rotate: View.ROTATION,
|
|
72
74
|
rotateX: View.ROTATION_X,
|
|
73
75
|
rotateY: View.ROTATION_Y,
|
|
74
|
-
} satisfies Record<
|
|
76
|
+
} satisfies Record<NumericProperty, unknown>
|
|
75
77
|
const interpolator = new android.view.animation.LinearInterpolator()
|
|
76
78
|
|
|
77
79
|
return {
|
|
78
80
|
now: () => android.os.SystemClock.uptimeMillis(),
|
|
79
81
|
|
|
80
82
|
play(view, track, _startedAt, onEnd) {
|
|
83
|
+
if (isColorProperty(track.property)) return playAndroidColor(view, track, onEnd)
|
|
81
84
|
const nativeView = view.nativeViewProtected as NativeView
|
|
82
85
|
const scale = unit(track.property)
|
|
83
86
|
|
|
@@ -170,6 +173,7 @@ export function createAndroidDriver(): Driver {
|
|
|
170
173
|
elapsed: (handle) => (handle as Handle).elapsed(),
|
|
171
174
|
|
|
172
175
|
presented(view, property) {
|
|
176
|
+
if (isColorProperty(property)) return presentedAndroidColor(view, property)
|
|
173
177
|
const nativeView = view.nativeViewProtected as NativeView | undefined
|
|
174
178
|
return nativeView ? accessors[property].get(nativeView) / unit(property) : undefined
|
|
175
179
|
},
|
package/src/driver/index.ts
CHANGED
|
@@ -8,7 +8,12 @@ export interface Driver {
|
|
|
8
8
|
/** Milliseconds, on the clock the platform's animations run on. */
|
|
9
9
|
now(): number
|
|
10
10
|
/** Starts the track at `startedAt + track.delay` and calls `onEnd` once, however it ends. */
|
|
11
|
-
play(
|
|
11
|
+
play(
|
|
12
|
+
view: View,
|
|
13
|
+
track: Track,
|
|
14
|
+
startedAt: number,
|
|
15
|
+
onEnd: (finished?: boolean) => void,
|
|
16
|
+
): unknown
|
|
12
17
|
stop(view: View, handle: unknown): void
|
|
13
18
|
/** Track time, including its delay, when the native clock differs from `now()`. */
|
|
14
19
|
elapsed?(handle: unknown): number
|