@rafaelaugusto/jolt 0.1.0-beta.1 → 0.1.0-beta.10
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 +367 -18
- package/dist/animate.d.ts +19 -3
- package/dist/animate.d.ts.map +1 -1
- package/dist/animate.js +186 -14
- 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/config.d.ts +31 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +73 -0
- package/dist/config.js.map +1 -0
- package/dist/decay.d.ts +11 -0
- package/dist/decay.d.ts.map +1 -0
- package/dist/decay.js +22 -0
- package/dist/decay.js.map +1 -0
- package/dist/decoration.d.ts +18 -0
- package/dist/decoration.d.ts.map +1 -0
- package/dist/decoration.js +155 -0
- package/dist/decoration.js.map +1 -0
- package/dist/drag-input.d.ts +15 -0
- package/dist/drag-input.d.ts.map +1 -0
- package/dist/drag-input.js +66 -0
- package/dist/drag-input.js.map +1 -0
- package/dist/drag-physics.d.ts +20 -0
- package/dist/drag-physics.d.ts.map +1 -0
- package/dist/drag-physics.js +75 -0
- package/dist/drag-physics.js.map +1 -0
- package/dist/drag.d.ts +58 -0
- package/dist/drag.d.ts.map +1 -0
- package/dist/drag.js +324 -0
- package/dist/drag.js.map +1 -0
- package/dist/driver/android-color.d.ts +20 -0
- package/dist/driver/android-color.d.ts.map +1 -0
- package/dist/driver/android-color.js +136 -0
- package/dist/driver/android-color.js.map +1 -0
- package/dist/driver/android-decoration.d.ts +22 -0
- package/dist/driver/android-decoration.d.ts.map +1 -0
- package/dist/driver/android-decoration.js +139 -0
- package/dist/driver/android-decoration.js.map +1 -0
- package/dist/driver/android-playback.d.ts +13 -0
- package/dist/driver/android-playback.d.ts.map +1 -0
- package/dist/driver/android-playback.js +141 -0
- package/dist/driver/android-playback.js.map +1 -0
- package/dist/driver/android.d.ts +1 -1
- package/dist/driver/android.d.ts.map +1 -1
- package/dist/driver/android.js +165 -13
- package/dist/driver/android.js.map +1 -1
- package/dist/driver/index.d.ts +25 -2
- package/dist/driver/index.d.ts.map +1 -1
- package/dist/driver/index.js.map +1 -1
- package/dist/driver/ios-color.d.ts +16 -0
- package/dist/driver/ios-color.d.ts.map +1 -0
- package/dist/driver/ios-color.js +392 -0
- package/dist/driver/ios-color.js.map +1 -0
- package/dist/driver/ios-decoration.d.ts +17 -0
- package/dist/driver/ios-decoration.d.ts.map +1 -0
- package/dist/driver/ios-decoration.js +271 -0
- package/dist/driver/ios-decoration.js.map +1 -0
- package/dist/driver/ios-layout.d.ts +9 -0
- package/dist/driver/ios-layout.d.ts.map +1 -0
- package/dist/driver/ios-layout.js +52 -0
- package/dist/driver/ios-layout.js.map +1 -0
- package/dist/driver/ios-playback.d.ts +10 -0
- package/dist/driver/ios-playback.d.ts.map +1 -0
- package/dist/driver/ios-playback.js +47 -0
- package/dist/driver/ios-playback.js.map +1 -0
- package/dist/driver/ios-shadow.d.ts +6 -0
- package/dist/driver/ios-shadow.d.ts.map +1 -0
- package/dist/driver/ios-shadow.js +52 -0
- package/dist/driver/ios-shadow.js.map +1 -0
- package/dist/driver/ios.d.ts.map +1 -1
- package/dist/driver/ios.js +163 -28
- package/dist/driver/ios.js.map +1 -1
- package/dist/engine.d.ts +75 -5
- package/dist/engine.d.ts.map +1 -1
- package/dist/engine.js +293 -23
- package/dist/engine.js.map +1 -1
- package/dist/haptics.d.ts +21 -0
- package/dist/haptics.d.ts.map +1 -0
- package/dist/haptics.js +120 -0
- package/dist/haptics.js.map +1 -0
- package/dist/image-effect-native.d.ts +26 -0
- package/dist/image-effect-native.d.ts.map +1 -0
- package/dist/image-effect-native.js +73 -0
- package/dist/image-effect-native.js.map +1 -0
- package/dist/image-effect.d.ts +50 -0
- package/dist/image-effect.d.ts.map +1 -0
- package/dist/image-effect.js +290 -0
- package/dist/image-effect.js.map +1 -0
- package/dist/image-owner.d.ts +3 -0
- package/dist/image-owner.d.ts.map +1 -0
- package/dist/image-owner.js +11 -0
- package/dist/image-owner.js.map +1 -0
- package/dist/index.d.ts +43 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +20 -1
- package/dist/index.js.map +1 -1
- package/dist/interaction-surface.d.ts +12 -0
- package/dist/interaction-surface.d.ts.map +1 -0
- package/dist/interaction-surface.js +36 -0
- package/dist/interaction-surface.js.map +1 -0
- package/dist/items.d.ts +20 -0
- package/dist/items.d.ts.map +1 -0
- package/dist/items.js +109 -0
- package/dist/items.js.map +1 -0
- package/dist/keyboard.d.ts +41 -0
- package/dist/keyboard.d.ts.map +1 -0
- package/dist/keyboard.js +256 -0
- package/dist/keyboard.js.map +1 -0
- package/dist/label.d.ts +7 -0
- package/dist/label.d.ts.map +1 -0
- package/dist/label.js +60 -0
- package/dist/label.js.map +1 -0
- package/dist/layout.d.ts +13 -0
- package/dist/layout.d.ts.map +1 -0
- package/dist/layout.js +348 -0
- package/dist/layout.js.map +1 -0
- 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 +234 -0
- package/dist/liquid.js.map +1 -0
- package/dist/loader.d.ts +19 -0
- package/dist/loader.d.ts.map +1 -0
- package/dist/loader.js +173 -0
- package/dist/loader.js.map +1 -0
- package/dist/motion-scope.d.ts +39 -0
- package/dist/motion-scope.d.ts.map +1 -0
- package/dist/motion-scope.js +238 -0
- package/dist/motion-scope.js.map +1 -0
- package/dist/motion-states.d.ts +36 -0
- package/dist/motion-states.d.ts.map +1 -0
- package/dist/motion-states.js +165 -0
- package/dist/motion-states.js.map +1 -0
- package/dist/particles.d.ts +39 -0
- package/dist/particles.d.ts.map +1 -0
- package/dist/particles.js +265 -0
- package/dist/particles.js.map +1 -0
- package/dist/path.d.ts +12 -0
- package/dist/path.d.ts.map +1 -0
- package/dist/path.js +90 -0
- package/dist/path.js.map +1 -0
- package/dist/playback-group.d.ts +6 -0
- package/dist/playback-group.d.ts.map +1 -0
- package/dist/playback-group.js +141 -0
- package/dist/playback-group.js.map +1 -0
- package/dist/playback.d.ts +25 -0
- package/dist/playback.d.ts.map +1 -0
- package/dist/playback.js +35 -0
- package/dist/playback.js.map +1 -0
- package/dist/press.d.ts.map +1 -1
- package/dist/press.js +23 -7
- package/dist/press.js.map +1 -1
- package/dist/properties.d.ts +6 -3
- package/dist/properties.d.ts.map +1 -1
- package/dist/properties.js +26 -2
- package/dist/properties.js.map +1 -1
- package/dist/reveal.d.ts +25 -0
- package/dist/reveal.d.ts.map +1 -0
- package/dist/reveal.js +294 -0
- package/dist/reveal.js.map +1 -0
- package/dist/roll-diff.d.ts +22 -0
- package/dist/roll-diff.d.ts.map +1 -0
- package/dist/roll-diff.js +36 -0
- package/dist/roll-diff.js.map +1 -0
- package/dist/roll.d.ts +29 -0
- package/dist/roll.d.ts.map +1 -0
- package/dist/roll.js +442 -0
- package/dist/roll.js.map +1 -0
- package/dist/scroll-linked.d.ts +10 -0
- package/dist/scroll-linked.d.ts.map +1 -0
- package/dist/scroll-linked.js +58 -0
- package/dist/scroll-linked.js.map +1 -0
- package/dist/sequence.d.ts +10 -5
- package/dist/sequence.d.ts.map +1 -1
- package/dist/sequence.js +208 -14
- package/dist/sequence.js.map +1 -1
- package/dist/shimmer.d.ts +12 -0
- package/dist/shimmer.d.ts.map +1 -0
- package/dist/shimmer.js +161 -0
- package/dist/shimmer.js.map +1 -0
- package/dist/svg-path.d.ts +14 -0
- package/dist/svg-path.d.ts.map +1 -0
- package/dist/svg-path.js +281 -0
- package/dist/svg-path.js.map +1 -0
- package/dist/symbol-effect.d.ts +23 -0
- package/dist/symbol-effect.d.ts.map +1 -0
- package/dist/symbol-effect.js +187 -0
- package/dist/symbol-effect.js.map +1 -0
- package/dist/text-layout.d.ts +30 -0
- package/dist/text-layout.d.ts.map +1 -0
- package/dist/text-layout.js +185 -0
- package/dist/text-layout.js.map +1 -0
- package/dist/text.d.ts +17 -0
- package/dist/text.d.ts.map +1 -0
- package/dist/text.js +263 -0
- package/dist/text.js.map +1 -0
- package/dist/track.d.ts +3 -1
- package/dist/track.d.ts.map +1 -1
- package/dist/track.js +266 -13
- package/dist/track.js.map +1 -1
- package/dist/transition.d.ts +17 -1
- package/dist/transition.d.ts.map +1 -1
- package/dist/transition.js +41 -6
- package/dist/transition.js.map +1 -1
- package/dist/types.d.ts +48 -1
- package/dist/types.d.ts.map +1 -1
- package/dist/vue/index.d.ts +95 -0
- package/dist/vue/index.d.ts.map +1 -0
- package/dist/vue/index.js +163 -0
- package/dist/vue/index.js.map +1 -0
- package/dist/zoom-native.d.ts +30 -0
- package/dist/zoom-native.d.ts.map +1 -0
- package/dist/zoom-native.js +56 -0
- package/dist/zoom-native.js.map +1 -0
- package/dist/zoomable.d.ts +48 -0
- package/dist/zoomable.d.ts.map +1 -0
- package/dist/zoomable.js +249 -0
- package/dist/zoomable.js.map +1 -0
- package/package.json +29 -5
- package/platforms/android/include.gradle +7 -0
- package/platforms/android/java/org/rafaelaugusto/jolt/ColorTarget.java +102 -0
- package/platforms/android/java/org/rafaelaugusto/jolt/DecorationTarget.java +154 -0
- package/platforms/android/java/org/rafaelaugusto/jolt/ImageEffect.java +288 -0
- package/platforms/android/java/org/rafaelaugusto/jolt/KeyboardFollower.java +91 -0
- package/platforms/android/java/org/rafaelaugusto/jolt/KeyboardObserver.java +97 -0
- package/platforms/android/java/org/rafaelaugusto/jolt/NumberRoll.java +190 -0
- package/platforms/android/java/org/rafaelaugusto/jolt/PhotoZoom.java +250 -0
- package/platforms/android/java/org/rafaelaugusto/jolt/TextReveal.java +180 -0
- package/platforms/android/proguard-rules.pro +19 -0
- package/platforms/ios/build.xcconfig +1 -0
- package/platforms/ios/src/JoltImageEffect.h +25 -0
- package/platforms/ios/src/JoltImageEffect.mm +242 -0
- package/platforms/ios/src/JoltInteractiveAnimation.h +18 -0
- package/platforms/ios/src/JoltInteractiveAnimation.m +123 -0
- package/platforms/ios/src/JoltPhotoZoom.h +23 -0
- package/platforms/ios/src/JoltPhotoZoom.m +229 -0
- package/platforms/ios/src/module.modulemap +6 -0
- package/src/android-plugin.d.ts +155 -0
- package/src/animate.ts +249 -36
- package/src/color.ts +101 -0
- package/src/config.ts +84 -0
- package/src/decay.ts +45 -0
- package/src/decoration.ts +180 -0
- package/src/drag-input.ts +74 -0
- package/src/drag-physics.ts +110 -0
- package/src/drag.ts +395 -0
- package/src/driver/android-color.ts +170 -0
- package/src/driver/android-decoration.ts +182 -0
- package/src/driver/android-playback.ts +157 -0
- package/src/driver/android.ts +208 -20
- package/src/driver/index.ts +37 -2
- package/src/driver/ios-color.ts +441 -0
- package/src/driver/ios-decoration.ts +332 -0
- package/src/driver/ios-layout.ts +63 -0
- package/src/driver/ios-playback.ts +51 -0
- package/src/driver/ios-shadow.ts +50 -0
- package/src/driver/ios.ts +193 -33
- package/src/engine.ts +321 -27
- package/src/haptics.ts +148 -0
- package/src/image-effect-native.ts +129 -0
- package/src/image-effect.ts +336 -0
- package/src/image-owner.ts +12 -0
- package/src/index.ts +59 -2
- package/src/interaction-surface.ts +41 -0
- package/src/ios-plugin.d.ts +81 -0
- package/src/items.ts +140 -0
- package/src/keyboard.ts +291 -0
- package/src/label.ts +76 -0
- package/src/layout.ts +408 -0
- package/src/liquid-grid.ts +28 -0
- package/src/liquid.ts +287 -0
- package/src/loader.ts +202 -0
- package/src/motion-scope.ts +279 -0
- package/src/motion-states.ts +215 -0
- package/src/particles.ts +323 -0
- package/src/path.ts +124 -0
- package/src/playback-group.ts +143 -0
- package/src/playback.ts +62 -0
- package/src/press.ts +26 -10
- package/src/properties.ts +32 -6
- package/src/reveal.ts +374 -0
- package/src/roll-diff.ts +57 -0
- package/src/roll.ts +515 -0
- package/src/scroll-linked.ts +73 -0
- package/src/sequence.ts +204 -14
- package/src/shimmer.ts +180 -0
- package/src/svg-path.ts +355 -0
- package/src/symbol-effect.ts +226 -0
- package/src/text-layout.ts +228 -0
- package/src/text.ts +279 -0
- package/src/track.ts +347 -12
- package/src/transition.ts +63 -6
- package/src/types.ts +49 -1
- package/src/vue/index.ts +231 -0
- package/src/zoom-native.ts +124 -0
- package/src/zoomable.ts +330 -0
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
declare namespace org.rafaelaugusto.jolt {
|
|
2
|
+
class PhotoZoom {
|
|
3
|
+
constructor(
|
|
4
|
+
image: android.widget.ImageView,
|
|
5
|
+
viewport: android.view.View,
|
|
6
|
+
bitmapWidth: number,
|
|
7
|
+
bitmapHeight: number,
|
|
8
|
+
minimum: number,
|
|
9
|
+
maximum: number,
|
|
10
|
+
doubleTap: number,
|
|
11
|
+
dismiss: boolean,
|
|
12
|
+
reduced: boolean,
|
|
13
|
+
backdrop: android.view.View | null,
|
|
14
|
+
chrome: android.view.View | null,
|
|
15
|
+
previousTouch: android.view.View.OnTouchListener | null,
|
|
16
|
+
previousImageTouch: android.view.View.OnTouchListener | null,
|
|
17
|
+
listener: PhotoZoom.Listener,
|
|
18
|
+
)
|
|
19
|
+
getX(): number
|
|
20
|
+
getY(): number
|
|
21
|
+
getScale(): number
|
|
22
|
+
getDismissProgress(): number
|
|
23
|
+
isDismissPending(): boolean
|
|
24
|
+
zoom(scale: number, x: number, y: number, animated: boolean): void
|
|
25
|
+
reset(animated: boolean): void
|
|
26
|
+
requestDismiss(): void
|
|
27
|
+
setReduced(value: boolean): void
|
|
28
|
+
setActive(value: boolean): void
|
|
29
|
+
stop(): void
|
|
30
|
+
}
|
|
31
|
+
namespace PhotoZoom {
|
|
32
|
+
class Listener {
|
|
33
|
+
constructor(implementation: {
|
|
34
|
+
onDismiss(
|
|
35
|
+
x: number,
|
|
36
|
+
y: number,
|
|
37
|
+
scale: number,
|
|
38
|
+
velocity: number,
|
|
39
|
+
progress: number,
|
|
40
|
+
): void
|
|
41
|
+
onSettled(x: number, y: number, scale: number): void
|
|
42
|
+
})
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
class ImageEffect {
|
|
46
|
+
constructor(
|
|
47
|
+
image: android.widget.ImageView,
|
|
48
|
+
source: android.graphics.Bitmap | null,
|
|
49
|
+
destination: android.graphics.Bitmap | null,
|
|
50
|
+
geometry: androidNative.Array<number>,
|
|
51
|
+
mode: number,
|
|
52
|
+
x: number,
|
|
53
|
+
y: number,
|
|
54
|
+
amplitude: number,
|
|
55
|
+
radius: number,
|
|
56
|
+
duration: number,
|
|
57
|
+
seed: number,
|
|
58
|
+
previousTouch: android.view.View.OnTouchListener | null,
|
|
59
|
+
listener: ImageEffect.Listener,
|
|
60
|
+
)
|
|
61
|
+
isSupported(): boolean
|
|
62
|
+
getFailureReason(): string
|
|
63
|
+
getProgress(): number
|
|
64
|
+
getFrames(): number
|
|
65
|
+
getTextureBytes(): number
|
|
66
|
+
getLongestFrameNanos(): number
|
|
67
|
+
play(endpoint: number): void
|
|
68
|
+
pause(): void
|
|
69
|
+
resume(): void
|
|
70
|
+
seek(progress: number): void
|
|
71
|
+
finish(endpoint: number): void
|
|
72
|
+
stop(): void
|
|
73
|
+
stopPreservingImage(): void
|
|
74
|
+
}
|
|
75
|
+
namespace ImageEffect {
|
|
76
|
+
class Listener {
|
|
77
|
+
constructor(implementation: { onEnd(completed: boolean, progress: number): void })
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
class KeyboardFollower {
|
|
81
|
+
constructor(
|
|
82
|
+
view: android.view.View,
|
|
83
|
+
offset: number,
|
|
84
|
+
listener: KeyboardFollower.Listener,
|
|
85
|
+
)
|
|
86
|
+
attach(): void
|
|
87
|
+
detach(): void
|
|
88
|
+
}
|
|
89
|
+
namespace KeyboardFollower {
|
|
90
|
+
class Listener {
|
|
91
|
+
constructor(implementation: {
|
|
92
|
+
onStart(): void
|
|
93
|
+
onSettled(translation: number): void
|
|
94
|
+
})
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
class KeyboardObserver {
|
|
98
|
+
constructor(root: android.view.View, listener: KeyboardObserver.Listener)
|
|
99
|
+
attach(): void
|
|
100
|
+
detach(): void
|
|
101
|
+
height(): number
|
|
102
|
+
}
|
|
103
|
+
namespace KeyboardObserver {
|
|
104
|
+
class Listener {
|
|
105
|
+
constructor(implementation: {
|
|
106
|
+
onChange(height: number, duration: number, curve: ArrayLike<number> | null): void
|
|
107
|
+
})
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
class TextReveal {
|
|
111
|
+
constructor(
|
|
112
|
+
view: android.widget.TextView,
|
|
113
|
+
byWord: boolean,
|
|
114
|
+
duration: number,
|
|
115
|
+
stagger: number,
|
|
116
|
+
delay: number,
|
|
117
|
+
offset: number,
|
|
118
|
+
callback: TextReveal.Callback,
|
|
119
|
+
)
|
|
120
|
+
isSupported(): boolean
|
|
121
|
+
start(): void
|
|
122
|
+
cancel(): void
|
|
123
|
+
}
|
|
124
|
+
namespace TextReveal {
|
|
125
|
+
class Callback {
|
|
126
|
+
constructor(implementation: { onEnd(finished: boolean): void })
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
class NumberRoll {
|
|
130
|
+
constructor(
|
|
131
|
+
view: android.widget.TextView,
|
|
132
|
+
starts: androidNative.Array<number>,
|
|
133
|
+
ends: androidNative.Array<number>,
|
|
134
|
+
previous: androidNative.Array<string>,
|
|
135
|
+
direction: number,
|
|
136
|
+
times: androidNative.Array<number>,
|
|
137
|
+
values: androidNative.Array<number>,
|
|
138
|
+
duration: number,
|
|
139
|
+
delay: number,
|
|
140
|
+
stagger: number,
|
|
141
|
+
shift: number,
|
|
142
|
+
fade: number,
|
|
143
|
+
tabular: boolean,
|
|
144
|
+
callback: NumberRoll.Callback,
|
|
145
|
+
)
|
|
146
|
+
isSupported(): boolean
|
|
147
|
+
start(): void
|
|
148
|
+
cancel(): void
|
|
149
|
+
}
|
|
150
|
+
namespace NumberRoll {
|
|
151
|
+
class Callback {
|
|
152
|
+
constructor(implementation: { onEnd(finished: boolean): void })
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
}
|
package/src/animate.ts
CHANGED
|
@@ -1,4 +1,19 @@
|
|
|
1
|
+
import {
|
|
2
|
+
isDecorationProperty,
|
|
3
|
+
validateDecorationTarget,
|
|
4
|
+
validateDecorationFrames,
|
|
5
|
+
} from './decoration.js'
|
|
6
|
+
import { playbackGroup } from './playback-group.js'
|
|
7
|
+
import type { PlaybackAnimation } from './playback.js'
|
|
8
|
+
import { preparePath, type PreparedPath } from './path.js'
|
|
1
9
|
import { View } from '@nativescript/core'
|
|
10
|
+
import {
|
|
11
|
+
isColorProperty,
|
|
12
|
+
parseColor,
|
|
13
|
+
validateColorTarget,
|
|
14
|
+
type ColorKeyframes,
|
|
15
|
+
} from './color.js'
|
|
16
|
+
import { DEFAULT_FRICTION, solveDecay } from './decay.js'
|
|
2
17
|
import {
|
|
3
18
|
arrivalOf,
|
|
4
19
|
setArrival,
|
|
@@ -8,7 +23,8 @@ import {
|
|
|
8
23
|
type Plan,
|
|
9
24
|
} from './engine.js'
|
|
10
25
|
import { getPreset, type PresetName } from './presets.js'
|
|
11
|
-
import {
|
|
26
|
+
import { resolveHaptic, type Haptic } from './haptics.js'
|
|
27
|
+
import { isProperty, precision, type Property } from './properties.js'
|
|
12
28
|
import {
|
|
13
29
|
hasCurve,
|
|
14
30
|
mergeTransitions,
|
|
@@ -19,17 +35,22 @@ import {
|
|
|
19
35
|
} from './transition.js'
|
|
20
36
|
import type {
|
|
21
37
|
AnimateOptions,
|
|
38
|
+
DecayOptions,
|
|
39
|
+
DecayVelocity,
|
|
22
40
|
Keyframes,
|
|
23
41
|
KeyframeValue,
|
|
42
|
+
KeyframeProperty,
|
|
24
43
|
Stagger,
|
|
25
44
|
Target,
|
|
45
|
+
Values,
|
|
26
46
|
} from './types.js'
|
|
27
47
|
|
|
28
48
|
interface Options {
|
|
29
49
|
base: Transition
|
|
30
|
-
overrides: Partial<Record<
|
|
50
|
+
overrides: Partial<Record<KeyframeProperty | 'path', Transition>>
|
|
31
51
|
stagger: number | Stagger | undefined
|
|
32
52
|
relative: boolean | undefined
|
|
53
|
+
haptic: Haptic | undefined
|
|
33
54
|
}
|
|
34
55
|
|
|
35
56
|
/**
|
|
@@ -46,38 +67,129 @@ export function animate(
|
|
|
46
67
|
target: Target | readonly Target[],
|
|
47
68
|
animation: Keyframes | PresetName,
|
|
48
69
|
options?: AnimateOptions | SpringName,
|
|
49
|
-
):
|
|
50
|
-
|
|
70
|
+
): PlaybackAnimation {
|
|
71
|
+
return prepareAnimation(target, animation, options)()
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/** Validate and snapshot a complete animation before changing any view ownership. */
|
|
75
|
+
export function prepareAnimation(
|
|
76
|
+
target: Target | readonly Target[],
|
|
77
|
+
animation: Keyframes | PresetName,
|
|
78
|
+
options?: AnimateOptions | SpringName,
|
|
79
|
+
): () => PlaybackAnimation {
|
|
80
|
+
const { keyframes, base, overrides, stagger, relative, haptic, path } = prepare(
|
|
81
|
+
animation,
|
|
82
|
+
options,
|
|
83
|
+
)
|
|
84
|
+
const feedback = resolveHaptic(haptic)
|
|
51
85
|
|
|
52
86
|
if (!isList(target)) {
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
87
|
+
const view = toView(target)
|
|
88
|
+
for (const property of Object.keys(keyframes))
|
|
89
|
+
if (isColorProperty(property)) validateColorTarget(view, property)
|
|
90
|
+
else if (isDecorationProperty(property)) validateDecorationTarget(view, property)
|
|
91
|
+
const plans = plan(keyframes, base, overrides, 0, relative, path)
|
|
92
|
+
return () => new ViewAnimation(view, plans, feedback)
|
|
57
93
|
}
|
|
58
94
|
|
|
59
95
|
const views = target.map(toView)
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
(view,
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
),
|
|
96
|
+
for (const view of views)
|
|
97
|
+
for (const property of Object.keys(keyframes))
|
|
98
|
+
if (isColorProperty(property)) validateColorTarget(view, property)
|
|
99
|
+
else if (isDecorationProperty(property)) validateDecorationTarget(view, property)
|
|
100
|
+
const plans = views.map((_, index) =>
|
|
101
|
+
plan(
|
|
102
|
+
keyframes,
|
|
103
|
+
base,
|
|
104
|
+
overrides,
|
|
105
|
+
staggerDelay(stagger, index, views.length),
|
|
106
|
+
relative,
|
|
107
|
+
path,
|
|
73
108
|
),
|
|
74
109
|
)
|
|
110
|
+
return () =>
|
|
111
|
+
playbackGroup(
|
|
112
|
+
views.map((view, index) => new ViewAnimation(view, plans[index]!, feedback, true)),
|
|
113
|
+
)
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
/** Starts at the current translation and slows down from a velocity in DIPs per second. */
|
|
117
|
+
export function decay(
|
|
118
|
+
target: Target | readonly Target[],
|
|
119
|
+
velocity: DecayVelocity,
|
|
120
|
+
options: DecayOptions = {},
|
|
121
|
+
): PlaybackAnimation {
|
|
122
|
+
const friction = options.friction ?? DEFAULT_FRICTION
|
|
123
|
+
if (!Number.isFinite(friction) || friction <= 0 || friction >= 1) {
|
|
124
|
+
throw new RangeError('Decay friction must be between 0 and 1 exclusively.')
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
const stops = (values: readonly number[] | undefined) => {
|
|
128
|
+
if (values === undefined) return undefined
|
|
129
|
+
if (
|
|
130
|
+
!Array.isArray(values) ||
|
|
131
|
+
values.length === 0 ||
|
|
132
|
+
![...values].every(Number.isFinite)
|
|
133
|
+
) {
|
|
134
|
+
throw new RangeError('Decay snap needs a nonempty array of finite positions.')
|
|
135
|
+
}
|
|
136
|
+
return [...values]
|
|
137
|
+
}
|
|
138
|
+
const snap = options.snap
|
|
139
|
+
if (
|
|
140
|
+
snap !== undefined &&
|
|
141
|
+
!Array.isArray(snap) &&
|
|
142
|
+
(snap === null ||
|
|
143
|
+
typeof snap !== 'object' ||
|
|
144
|
+
Object.keys(snap).some((key) => key !== 'x' && key !== 'y'))
|
|
145
|
+
) {
|
|
146
|
+
throw new TypeError('Decay snap must be an array or an object with x and y stops.')
|
|
147
|
+
}
|
|
148
|
+
const shared = Array.isArray(snap)
|
|
149
|
+
const perAxis = snap as { x?: readonly number[]; y?: readonly number[] } | undefined
|
|
150
|
+
const snapped = shared ? stops(snap) : undefined
|
|
151
|
+
const snapX = shared ? snapped : stops(perAxis?.x)
|
|
152
|
+
const snapY = shared ? snapped : stops(perAxis?.y)
|
|
153
|
+
|
|
154
|
+
const plans = Object.entries(velocity).flatMap<Plan>(([property, value]) => {
|
|
155
|
+
if (property !== 'x' && property !== 'y') {
|
|
156
|
+
throw new Error(`Can't decay "${property}". Use x or y.`)
|
|
157
|
+
}
|
|
158
|
+
if (value === undefined) return []
|
|
159
|
+
if (!Number.isFinite(value)) {
|
|
160
|
+
throw new RangeError(`Invalid decay velocity for "${property}".`)
|
|
161
|
+
}
|
|
162
|
+
// Validate every axis before handing any plans to the engine.
|
|
163
|
+
solveDecay(0, value, friction, precision[property])
|
|
164
|
+
return [
|
|
165
|
+
{
|
|
166
|
+
property,
|
|
167
|
+
keyframes: [null, null],
|
|
168
|
+
transition: {
|
|
169
|
+
curve: {
|
|
170
|
+
type: 'decay',
|
|
171
|
+
friction,
|
|
172
|
+
velocity: value,
|
|
173
|
+
snap: property === 'x' ? snapX : snapY,
|
|
174
|
+
},
|
|
175
|
+
delay: 0,
|
|
176
|
+
repeat: 0,
|
|
177
|
+
reverse: false,
|
|
178
|
+
},
|
|
179
|
+
},
|
|
180
|
+
]
|
|
181
|
+
})
|
|
182
|
+
const views = toViews(target)
|
|
183
|
+
if (plans.length === 0) return playbackGroup([])
|
|
184
|
+
return playbackGroup(
|
|
185
|
+
views.map((view) => new ViewAnimation(view, plans, undefined, true)),
|
|
186
|
+
)
|
|
75
187
|
}
|
|
76
188
|
|
|
77
189
|
/** Stops all or selected properties at their current values. `scale` stops both axes. */
|
|
78
190
|
export function stop(
|
|
79
191
|
target: Target | readonly Target[],
|
|
80
|
-
properties?: readonly
|
|
192
|
+
properties?: readonly KeyframeProperty[],
|
|
81
193
|
) {
|
|
82
194
|
const expanded = properties?.flatMap<Property>((property) =>
|
|
83
195
|
property === 'scale' ? ['scaleX', 'scaleY'] : [property],
|
|
@@ -85,6 +197,30 @@ export function stop(
|
|
|
85
197
|
for (const view of toViews(target)) stopView(view, expanded)
|
|
86
198
|
}
|
|
87
199
|
|
|
200
|
+
/**
|
|
201
|
+
* Applies values at once, stopping whatever animates those properties.
|
|
202
|
+
* `scale` sets both axes. A view that isn't loaded yet gets them right away.
|
|
203
|
+
*
|
|
204
|
+
* ```ts
|
|
205
|
+
* set(logo, { opacity: 1, scale: 1, y: 0 })
|
|
206
|
+
* ```
|
|
207
|
+
*/
|
|
208
|
+
export function set(target: Target | readonly Target[], values: Values): void {
|
|
209
|
+
if (values === null || typeof values !== 'object' || Array.isArray(values))
|
|
210
|
+
throw new TypeError('set() takes an object of values.')
|
|
211
|
+
const keyframes: Record<string, unknown> = {}
|
|
212
|
+
for (const [key, value] of Object.entries(values)) {
|
|
213
|
+
if (value === undefined) continue
|
|
214
|
+
if (key !== 'scale' && !isProperty(key)) throw new Error(`Can't set "${key}".`)
|
|
215
|
+
if (value === null || Array.isArray(value))
|
|
216
|
+
throw new TypeError(
|
|
217
|
+
`set() takes one value per property, got ${String(value)} for "${key}".`,
|
|
218
|
+
)
|
|
219
|
+
keyframes[key] = [value, value]
|
|
220
|
+
}
|
|
221
|
+
animate(target, keyframes as Keyframes, { duration: 0 })
|
|
222
|
+
}
|
|
223
|
+
|
|
88
224
|
/** Plays several animations as one: finished once they all are, and stopped together. */
|
|
89
225
|
export function group(animations: readonly Animation[]): Animation {
|
|
90
226
|
const finished = Promise.all(animations.map((animation) => animation.finished)).then(
|
|
@@ -119,6 +255,17 @@ function isList<T>(target: T | readonly T[]): target is readonly T[] {
|
|
|
119
255
|
function prepare(
|
|
120
256
|
animation: Keyframes | PresetName,
|
|
121
257
|
options?: AnimateOptions | SpringName,
|
|
258
|
+
) {
|
|
259
|
+
const prepared = resolveAnimation(animation, options)
|
|
260
|
+
return {
|
|
261
|
+
...prepared,
|
|
262
|
+
path: preparePath(prepared.keyframes, prepared.base, prepared.overrides),
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
function resolveAnimation(
|
|
267
|
+
animation: Keyframes | PresetName,
|
|
268
|
+
options?: AnimateOptions | SpringName,
|
|
122
269
|
) {
|
|
123
270
|
const user = normalize(options)
|
|
124
271
|
if (typeof animation !== 'string') return { keyframes: animation, ...user }
|
|
@@ -133,33 +280,43 @@ function prepare(
|
|
|
133
280
|
: { ...own.overrides, ...user.overrides },
|
|
134
281
|
stagger: user.stagger ?? own.stagger,
|
|
135
282
|
relative: user.relative ?? own.relative,
|
|
283
|
+
haptic: user.haptic ?? own.haptic,
|
|
136
284
|
}
|
|
137
285
|
}
|
|
138
286
|
|
|
139
287
|
function normalize(options: AnimateOptions | SpringName | undefined): Options {
|
|
140
288
|
if (options === undefined)
|
|
141
|
-
return {
|
|
289
|
+
return {
|
|
290
|
+
base: {},
|
|
291
|
+
overrides: {},
|
|
292
|
+
stagger: undefined,
|
|
293
|
+
relative: undefined,
|
|
294
|
+
haptic: undefined,
|
|
295
|
+
}
|
|
142
296
|
if (typeof options === 'string')
|
|
143
297
|
return {
|
|
144
298
|
base: spring(options),
|
|
145
299
|
overrides: {},
|
|
146
300
|
stagger: undefined,
|
|
147
301
|
relative: undefined,
|
|
302
|
+
haptic: undefined,
|
|
148
303
|
}
|
|
149
304
|
|
|
150
305
|
const base: Record<string, unknown> = {}
|
|
151
306
|
const overrides: Options['overrides'] = {}
|
|
152
307
|
let stagger: Options['stagger']
|
|
153
308
|
let relative: Options['relative']
|
|
309
|
+
let haptic: Options['haptic']
|
|
154
310
|
for (const [key, value] of Object.entries(options)) {
|
|
155
311
|
if (value === undefined) continue
|
|
156
312
|
if (key === 'stagger') stagger = value as Options['stagger']
|
|
157
313
|
else if (key === 'relative') relative = value as Options['relative']
|
|
158
|
-
else if (key === '
|
|
314
|
+
else if (key === 'haptic') haptic = value as Options['haptic']
|
|
315
|
+
else if (key === 'path' || key === 'scale' || isProperty(key)) {
|
|
159
316
|
overrides[key] = typeof value === 'string' ? spring(value as SpringName) : value
|
|
160
317
|
} else base[key] = value
|
|
161
318
|
}
|
|
162
|
-
return { base, overrides, stagger, relative }
|
|
319
|
+
return { base, overrides, stagger, relative, haptic }
|
|
163
320
|
}
|
|
164
321
|
|
|
165
322
|
function plan(
|
|
@@ -168,8 +325,25 @@ function plan(
|
|
|
168
325
|
overrides: Options['overrides'],
|
|
169
326
|
offset: number,
|
|
170
327
|
relative = false,
|
|
328
|
+
path?: PreparedPath,
|
|
171
329
|
): Plan[] {
|
|
172
|
-
return expand(keyframes).map(([property, frames]) => {
|
|
330
|
+
return expand(keyframes, path).map(([property, frames]) => {
|
|
331
|
+
if (path?.properties.includes(property as 'x' | 'y' | 'rotate')) {
|
|
332
|
+
if (
|
|
333
|
+
!Number.isFinite(path.transition.delay + offset) ||
|
|
334
|
+
path.transition.delay + offset < 0
|
|
335
|
+
)
|
|
336
|
+
throw new RangeError(
|
|
337
|
+
'Path delays, including stagger, must be finite and nonnegative.',
|
|
338
|
+
)
|
|
339
|
+
return {
|
|
340
|
+
property,
|
|
341
|
+
keyframes: frames,
|
|
342
|
+
transition: { ...path.transition, delay: path.transition.delay + offset },
|
|
343
|
+
relative,
|
|
344
|
+
path,
|
|
345
|
+
}
|
|
346
|
+
}
|
|
173
347
|
const override =
|
|
174
348
|
overrides[property] ?? (property.startsWith('scale') ? overrides.scale : undefined)
|
|
175
349
|
const transition = resolveTransition(
|
|
@@ -187,32 +361,70 @@ export function startingValues(
|
|
|
187
361
|
animation: Keyframes | PresetName,
|
|
188
362
|
options?: AnimateOptions | SpringName,
|
|
189
363
|
) {
|
|
190
|
-
const { keyframes, relative } = prepare(animation, options)
|
|
364
|
+
const { keyframes, relative, path } = prepare(animation, options)
|
|
191
365
|
if (!keyframes) throw new Error(`Unknown preset "${animation}".`)
|
|
192
366
|
return new Map(
|
|
193
|
-
expand(keyframes).map(([property, [first]]) => [
|
|
367
|
+
expand(keyframes, path).map(([property, [first]]) => [
|
|
368
|
+
property,
|
|
369
|
+
relative && !isColorProperty(property) ? null : first!,
|
|
370
|
+
]),
|
|
371
|
+
)
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
/** Each property the animation touches, with the value it leaves behind when that is known up front. */
|
|
375
|
+
export function endingValues(
|
|
376
|
+
animation: Keyframes | PresetName,
|
|
377
|
+
options?: AnimateOptions | SpringName,
|
|
378
|
+
) {
|
|
379
|
+
const { keyframes, base, overrides, relative, path } = prepare(animation, options)
|
|
380
|
+
return new Map(
|
|
381
|
+
plan(keyframes, base, overrides, 0, relative, path).map(
|
|
382
|
+
({ property, keyframes: frames, transition, path: owned }) => {
|
|
383
|
+
const finite = Number.isFinite(transition.repeat)
|
|
384
|
+
const backwards = transition.reverse && finite && transition.repeat % 2 === 1
|
|
385
|
+
const unknown = owned !== undefined || (relative && !isColorProperty(property))
|
|
386
|
+
const frame = !finite || backwards ? frames[0] : frames.at(-1)
|
|
387
|
+
return [property, unknown ? null : frame!]
|
|
388
|
+
},
|
|
389
|
+
),
|
|
194
390
|
)
|
|
195
391
|
}
|
|
196
392
|
|
|
197
|
-
function expand(
|
|
393
|
+
function expand(
|
|
394
|
+
keyframes: Keyframes,
|
|
395
|
+
path?: PreparedPath,
|
|
396
|
+
): [Property, (number | null)[]][] {
|
|
198
397
|
const expanded: [Property, (number | null)[]][] = []
|
|
199
|
-
for (const [key, value] of Object.entries(keyframes)
|
|
200
|
-
|
|
201
|
-
KeyframeValue | undefined,
|
|
202
|
-
][]) {
|
|
203
|
-
if (value === undefined) continue
|
|
398
|
+
for (const [key, value] of Object.entries(keyframes)) {
|
|
399
|
+
if (value === undefined || key === 'path' || key === 'orient') continue
|
|
204
400
|
if (key !== 'scale' && !isProperty(key)) throw new Error(`Can't animate "${key}".`)
|
|
205
401
|
|
|
206
402
|
const properties: Property[] = key === 'scale' ? ['scaleX', 'scaleY'] : [key]
|
|
207
403
|
for (const property of properties) {
|
|
208
404
|
if (key === 'scale' && keyframes[property] !== undefined) continue
|
|
209
|
-
expanded.push([
|
|
405
|
+
expanded.push([
|
|
406
|
+
property,
|
|
407
|
+
toKeyframes(property, value as KeyframeValue | ColorKeyframes),
|
|
408
|
+
])
|
|
210
409
|
}
|
|
211
410
|
}
|
|
411
|
+
for (const [property, value] of path?.starts ?? [])
|
|
412
|
+
expanded.push([property, [value, value]])
|
|
212
413
|
return expanded
|
|
213
414
|
}
|
|
214
415
|
|
|
215
|
-
function toKeyframes(
|
|
416
|
+
function toKeyframes(
|
|
417
|
+
property: Property,
|
|
418
|
+
value: KeyframeValue | ColorKeyframes,
|
|
419
|
+
): (number | null)[] {
|
|
420
|
+
if (isColorProperty(property)) {
|
|
421
|
+
const frames = Array.isArray(value) ? [...value] : [null, value]
|
|
422
|
+
if (!frames.length) throw new TypeError(`Empty color keyframes for "${property}".`)
|
|
423
|
+
if (frames.length === 1) frames.unshift(null)
|
|
424
|
+
return frames.map((frame) => (frame === null ? null : parseColor(frame)))
|
|
425
|
+
}
|
|
426
|
+
if (typeof value !== 'number' && !Array.isArray(value))
|
|
427
|
+
throw new TypeError(`Invalid numeric keyframes for "${property}".`)
|
|
216
428
|
const frames = typeof value === 'number' ? [null, value] : [...value]
|
|
217
429
|
if (frames.length === 1) frames.unshift(null)
|
|
218
430
|
if (
|
|
@@ -221,6 +433,7 @@ function toKeyframes(property: Property, value: KeyframeValue): (number | null)[
|
|
|
221
433
|
) {
|
|
222
434
|
throw new Error(`Invalid keyframes for "${property}": ${JSON.stringify(value)}.`)
|
|
223
435
|
}
|
|
436
|
+
if (isDecorationProperty(property)) validateDecorationFrames(property, frames)
|
|
224
437
|
return frames
|
|
225
438
|
}
|
|
226
439
|
|
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
|
+
}
|