@rafaelaugusto/jolt 0.1.0-beta.0 → 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 +441 -25
- package/dist/animate.d.ts +21 -5
- package/dist/animate.d.ts.map +1 -1
- package/dist/animate.js +205 -25
- 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 +164 -20
- package/dist/driver/ios.js.map +1 -1
- package/dist/engine.d.ts +76 -5
- package/dist/engine.d.ts.map +1 -1
- package/dist/engine.js +303 -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 +45 -4
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +21 -2
- 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/presets.d.ts +16 -1
- package/dist/presets.d.ts.map +1 -1
- package/dist/presets.js +24 -6
- package/dist/presets.js.map +1 -1
- package/dist/press.d.ts.map +1 -1
- package/dist/press.js +25 -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 +13 -7
- package/dist/sequence.d.ts.map +1 -1
- package/dist/sequence.js +214 -19
- 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 +50 -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 +33 -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 +278 -38
- 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 +194 -25
- package/src/engine.ts +329 -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 +61 -4
- 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/presets.ts +31 -7
- package/src/press.ts +32 -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 +212 -19
- 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 +51 -1
- package/src/vue/index.ts +231 -0
- package/src/zoom-native.ts +124 -0
- package/src/zoomable.ts +330 -0
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
import { Utils, isAndroid, isIOS, type Image, type ImageSource } from '@nativescript/core'
|
|
2
|
+
|
|
3
|
+
export interface ImageEffectSettings {
|
|
4
|
+
mode: number
|
|
5
|
+
x: number
|
|
6
|
+
y: number
|
|
7
|
+
amplitude: number
|
|
8
|
+
radius: number
|
|
9
|
+
duration: number
|
|
10
|
+
seed: number
|
|
11
|
+
to?: ImageSource
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export interface ImageRenderer {
|
|
15
|
+
readonly backend: 'metal' | 'agsl'
|
|
16
|
+
readonly progress: number
|
|
17
|
+
readonly frames: number
|
|
18
|
+
readonly textureBytes: number
|
|
19
|
+
readonly longestFrameMs: number
|
|
20
|
+
play(endpoint: number): void
|
|
21
|
+
pause(): void
|
|
22
|
+
resume(): void
|
|
23
|
+
seek(progress: number): void
|
|
24
|
+
finish(endpoint: number): void
|
|
25
|
+
stop(preserveImage?: boolean): void
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export function createImageRenderer(
|
|
29
|
+
image: Image,
|
|
30
|
+
settings: ImageEffectSettings,
|
|
31
|
+
ended: (completed: boolean, progress: number) => void,
|
|
32
|
+
): ImageRenderer | undefined {
|
|
33
|
+
const { mode, x, y, amplitude, radius, duration, seed, to } = settings
|
|
34
|
+
if (isIOS && typeof JoltImageEffect !== 'undefined') {
|
|
35
|
+
const native =
|
|
36
|
+
JoltImageEffect.createWithViewDestinationModeOriginXOriginYAmplitudeRadiusDurationSeedListener(
|
|
37
|
+
image.nativeViewProtected,
|
|
38
|
+
to?.ios ?? null,
|
|
39
|
+
mode,
|
|
40
|
+
x,
|
|
41
|
+
y,
|
|
42
|
+
amplitude,
|
|
43
|
+
radius,
|
|
44
|
+
duration,
|
|
45
|
+
seed,
|
|
46
|
+
ended,
|
|
47
|
+
)
|
|
48
|
+
if (!native) return undefined
|
|
49
|
+
return {
|
|
50
|
+
backend: 'metal',
|
|
51
|
+
get progress() {
|
|
52
|
+
return native.progress
|
|
53
|
+
},
|
|
54
|
+
get frames() {
|
|
55
|
+
return native.frames
|
|
56
|
+
},
|
|
57
|
+
get textureBytes() {
|
|
58
|
+
return native.textureBytes
|
|
59
|
+
},
|
|
60
|
+
get longestFrameMs() {
|
|
61
|
+
return native.longestFrame * 1000
|
|
62
|
+
},
|
|
63
|
+
play: (p) => native.play(p),
|
|
64
|
+
pause: () => native.pause(),
|
|
65
|
+
resume: () => native.resume(),
|
|
66
|
+
seek: (p) => native.seek(p),
|
|
67
|
+
finish: (p) => native.finish(p),
|
|
68
|
+
stop: (preserveImage) =>
|
|
69
|
+
preserveImage ? native.stopPreservingImage() : native.stop(),
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
if (isAndroid && android.os.Build.VERSION.SDK_INT >= 33) {
|
|
73
|
+
const density = Utils.layout.getDisplayDensity()
|
|
74
|
+
const background = image.nativeViewProtected.getBackground()
|
|
75
|
+
// NativeScript draws bitmap pixels itself: ImageView.getImageMatrix() does
|
|
76
|
+
// not describe its stretch, EXIF rotation or inner border clipping.
|
|
77
|
+
const geometry = Array.create('float', 6)
|
|
78
|
+
geometry[0] = image.imageSource?.rotationAngle ?? 0
|
|
79
|
+
geometry[1] = to?.rotationAngle ?? 0
|
|
80
|
+
const corners = ['TopLeft', 'TopRight', 'BottomRight', 'BottomLeft']
|
|
81
|
+
corners.forEach((corner, i) => {
|
|
82
|
+
geometry[i + 2] = background?.[`getBorder${corner}Radius`]?.() ?? 0
|
|
83
|
+
})
|
|
84
|
+
const native = new org.rafaelaugusto.jolt.ImageEffect(
|
|
85
|
+
image.nativeViewProtected,
|
|
86
|
+
image.imageSource?.android ?? null,
|
|
87
|
+
to?.android ?? null,
|
|
88
|
+
geometry,
|
|
89
|
+
mode,
|
|
90
|
+
x * density,
|
|
91
|
+
y * density,
|
|
92
|
+
amplitude * density,
|
|
93
|
+
radius * density,
|
|
94
|
+
duration,
|
|
95
|
+
seed,
|
|
96
|
+
(image as Image & { touchListener?: android.view.View.OnTouchListener })
|
|
97
|
+
.touchListener ?? null,
|
|
98
|
+
new org.rafaelaugusto.jolt.ImageEffect.Listener({ onEnd: ended }),
|
|
99
|
+
)
|
|
100
|
+
if (!native.isSupported()) {
|
|
101
|
+
const reason = native.getFailureReason()
|
|
102
|
+
native.stop()
|
|
103
|
+
throw new Error(reason)
|
|
104
|
+
}
|
|
105
|
+
return {
|
|
106
|
+
backend: 'agsl',
|
|
107
|
+
get progress() {
|
|
108
|
+
return native.getProgress()
|
|
109
|
+
},
|
|
110
|
+
get frames() {
|
|
111
|
+
return native.getFrames()
|
|
112
|
+
},
|
|
113
|
+
get textureBytes() {
|
|
114
|
+
return native.getTextureBytes()
|
|
115
|
+
},
|
|
116
|
+
get longestFrameMs() {
|
|
117
|
+
return native.getLongestFrameNanos() / 1e6
|
|
118
|
+
},
|
|
119
|
+
play: (p) => native.play(p),
|
|
120
|
+
pause: () => native.pause(),
|
|
121
|
+
resume: () => native.resume(),
|
|
122
|
+
seek: (p) => native.seek(p),
|
|
123
|
+
finish: (p) => native.finish(p),
|
|
124
|
+
stop: (preserveImage) =>
|
|
125
|
+
preserveImage ? native.stopPreservingImage() : native.stop(),
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
return undefined
|
|
129
|
+
}
|
|
@@ -0,0 +1,336 @@
|
|
|
1
|
+
import {
|
|
2
|
+
Application,
|
|
3
|
+
Image,
|
|
4
|
+
ImageSource,
|
|
5
|
+
isIOS,
|
|
6
|
+
type EventData,
|
|
7
|
+
} from '@nativescript/core'
|
|
8
|
+
import { toView } from './animate.js'
|
|
9
|
+
import { reducedMotion, timeScale } from './config.js'
|
|
10
|
+
import type { Animation } from './engine.js'
|
|
11
|
+
import { ownImage } from './image-owner.js'
|
|
12
|
+
import { createImageRenderer, type ImageRenderer } from './image-effect-native.js'
|
|
13
|
+
import type { Target } from './types.js'
|
|
14
|
+
|
|
15
|
+
export type ImageEffectName = 'ripple' | 'distortion' | 'dissolve'
|
|
16
|
+
export interface ImageEffectOptions {
|
|
17
|
+
/** Origin in target-local DIPs; defaults to the center. */
|
|
18
|
+
origin?: { x: number; y: number }
|
|
19
|
+
/** Maximum displacement in DIPs, 0..64. Defaults to 8. */
|
|
20
|
+
amplitude?: number
|
|
21
|
+
/** Influence radius in DIPs, greater than zero. Defaults to 96. */
|
|
22
|
+
radius?: number
|
|
23
|
+
/** Milliseconds for a finite effect (or drag release). Defaults to 650. */
|
|
24
|
+
duration?: number
|
|
25
|
+
/** Deterministic dissolve noise seed, 0..65535. Defaults to 1. */
|
|
26
|
+
seed?: number
|
|
27
|
+
/** Loaded destination raster for dissolve. */
|
|
28
|
+
to?: ImageSource
|
|
29
|
+
/** Prepare at progress zero without starting. */
|
|
30
|
+
paused?: boolean
|
|
31
|
+
}
|
|
32
|
+
export interface ImageEffectDiagnostics {
|
|
33
|
+
backend: 'waiting' | 'metal' | 'agsl' | 'fallback'
|
|
34
|
+
reason?: 'reduced-motion' | 'unsupported' | 'not-visible'
|
|
35
|
+
/** Native setup error, when available. Intended for developer diagnostics. */
|
|
36
|
+
detail?: string
|
|
37
|
+
frames: number
|
|
38
|
+
textureBytes: number
|
|
39
|
+
peakTextureBytes: number
|
|
40
|
+
preparationMs: number
|
|
41
|
+
longestFrameMs: number
|
|
42
|
+
}
|
|
43
|
+
export interface ImageEffect extends Animation {
|
|
44
|
+
readonly effect: ImageEffectName
|
|
45
|
+
readonly paused: boolean
|
|
46
|
+
/** Finite progress; distortion rejects seeking because it follows native touch input. */
|
|
47
|
+
progress: number
|
|
48
|
+
readonly diagnostics: Readonly<ImageEffectDiagnostics>
|
|
49
|
+
pause(): void
|
|
50
|
+
play(): void
|
|
51
|
+
/** Reverse a finite effect from its current pixels. Terminal handles remain terminal. */
|
|
52
|
+
reverse(): void
|
|
53
|
+
/** Complete immediately at the current direction's endpoint. */
|
|
54
|
+
finish(): void
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
const names: readonly ImageEffectName[] = ['ripple', 'distortion', 'dissolve']
|
|
58
|
+
const surfaceChanges = [
|
|
59
|
+
'tintColorChange',
|
|
60
|
+
...['TopLeft', 'TopRight', 'BottomRight', 'BottomLeft'].map(
|
|
61
|
+
(corner) => `border${corner}RadiusChange`,
|
|
62
|
+
),
|
|
63
|
+
...['Top', 'Right', 'Bottom', 'Left'].flatMap((edge) => [
|
|
64
|
+
`padding${edge}Change`,
|
|
65
|
+
`border${edge}WidthChange`,
|
|
66
|
+
]),
|
|
67
|
+
]
|
|
68
|
+
|
|
69
|
+
/** Optional native image effects. Stop restores the source; dissolve completion commits its destination. */
|
|
70
|
+
export function imageEffect(
|
|
71
|
+
target: Target,
|
|
72
|
+
effect: ImageEffectName,
|
|
73
|
+
options: ImageEffectOptions = {},
|
|
74
|
+
): ImageEffect {
|
|
75
|
+
const image = toView(target)
|
|
76
|
+
if (!(image instanceof Image))
|
|
77
|
+
throw new TypeError('imageEffect() expects a NativeScript Image.')
|
|
78
|
+
if (!names.includes(effect))
|
|
79
|
+
throw new TypeError(`Unknown image effect: ${String(effect)}.`)
|
|
80
|
+
if (!options || typeof options !== 'object')
|
|
81
|
+
throw new TypeError('Image effect options must be an object.')
|
|
82
|
+
const amplitude = options.amplitude ?? 8,
|
|
83
|
+
radius = options.radius ?? 96
|
|
84
|
+
const duration = options.duration ?? 650,
|
|
85
|
+
seed = options.seed ?? 1
|
|
86
|
+
if (!Number.isFinite(amplitude) || amplitude < 0 || amplitude > 64)
|
|
87
|
+
throw new RangeError('Image displacement must be between 0 and 64 DIPs.')
|
|
88
|
+
if (
|
|
89
|
+
!Number.isFinite(radius) ||
|
|
90
|
+
radius <= 0 ||
|
|
91
|
+
!Number.isFinite(duration) ||
|
|
92
|
+
duration <= 0
|
|
93
|
+
)
|
|
94
|
+
throw new RangeError('Image radius and duration must be positive finite numbers.')
|
|
95
|
+
if (!Number.isInteger(seed) || seed < 0 || seed > 65535)
|
|
96
|
+
throw new RangeError('Image seed must be an integer between 0 and 65535.')
|
|
97
|
+
if (
|
|
98
|
+
options.origin &&
|
|
99
|
+
(!Number.isFinite(options.origin.x) || !Number.isFinite(options.origin.y))
|
|
100
|
+
)
|
|
101
|
+
throw new RangeError('Image origin must contain finite local coordinates.')
|
|
102
|
+
if (options.paused !== undefined && typeof options.paused !== 'boolean')
|
|
103
|
+
throw new TypeError('paused must be a boolean.')
|
|
104
|
+
if (
|
|
105
|
+
effect === 'dissolve' &&
|
|
106
|
+
(!(options.to instanceof ImageSource) ||
|
|
107
|
+
!Number.isFinite(options.to.width) ||
|
|
108
|
+
!Number.isFinite(options.to.height) ||
|
|
109
|
+
options.to.width <= 0 ||
|
|
110
|
+
options.to.height <= 0)
|
|
111
|
+
)
|
|
112
|
+
throw new TypeError('Dissolve requires a loaded destination ImageSource.')
|
|
113
|
+
return new Effect(image, effect, {
|
|
114
|
+
...options,
|
|
115
|
+
amplitude,
|
|
116
|
+
radius,
|
|
117
|
+
duration: duration / timeScale(),
|
|
118
|
+
seed,
|
|
119
|
+
})
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
class Effect implements ImageEffect {
|
|
123
|
+
readonly finished: Promise<boolean>
|
|
124
|
+
private resolve!: (completed: boolean) => void
|
|
125
|
+
private renderer: ImageRenderer | undefined
|
|
126
|
+
private releaseOwnership: () => void = () => {}
|
|
127
|
+
private terminal = false
|
|
128
|
+
private queued = false
|
|
129
|
+
private committing = false
|
|
130
|
+
private userPaused: boolean
|
|
131
|
+
private suspended = false
|
|
132
|
+
private position = 0
|
|
133
|
+
private direction: 0 | 1 = 1
|
|
134
|
+
private dimensions = ''
|
|
135
|
+
private stats: ImageEffectDiagnostics = {
|
|
136
|
+
backend: 'waiting',
|
|
137
|
+
frames: 0,
|
|
138
|
+
textureBytes: 0,
|
|
139
|
+
peakTextureBytes: 0,
|
|
140
|
+
preparationMs: 0,
|
|
141
|
+
longestFrameMs: 0,
|
|
142
|
+
}
|
|
143
|
+
private reduceObserver:
|
|
144
|
+
ReturnType<typeof Application.ios.addNotificationObserver> | undefined
|
|
145
|
+
|
|
146
|
+
constructor(
|
|
147
|
+
private readonly image: Image,
|
|
148
|
+
readonly effect: ImageEffectName,
|
|
149
|
+
private readonly options: ImageEffectOptions &
|
|
150
|
+
Required<Pick<ImageEffectOptions, 'amplitude' | 'radius' | 'duration' | 'seed'>>,
|
|
151
|
+
) {
|
|
152
|
+
this.userPaused = options.paused ?? false
|
|
153
|
+
this.finished = new Promise((resolve) => {
|
|
154
|
+
this.resolve = resolve
|
|
155
|
+
})
|
|
156
|
+
this.releaseOwnership = ownImage(image, this.stop)
|
|
157
|
+
for (const event of ['loaded', 'layoutChanged']) image.on(event, this.schedule)
|
|
158
|
+
for (const event of ['imageSourceChange', 'stretchChange'])
|
|
159
|
+
image.on(event, this.changed)
|
|
160
|
+
image.on('unloaded', this.stop)
|
|
161
|
+
image.style.on('visibilityChange', this.visible)
|
|
162
|
+
for (const event of surfaceChanges) image.style.on(event, this.changed)
|
|
163
|
+
Application.on(Application.suspendEvent, this.suspend)
|
|
164
|
+
Application.on(Application.resumeEvent, this.resume)
|
|
165
|
+
if (isIOS)
|
|
166
|
+
this.reduceObserver = Application.ios.addNotificationObserver(
|
|
167
|
+
UIAccessibilityReduceMotionStatusDidChangeNotification,
|
|
168
|
+
this.preferences,
|
|
169
|
+
)
|
|
170
|
+
this.schedule()
|
|
171
|
+
}
|
|
172
|
+
then<TResult1 = boolean, TResult2 = never>(
|
|
173
|
+
fulfilled?: ((value: boolean) => TResult1 | PromiseLike<TResult1>) | null,
|
|
174
|
+
rejected?: ((reason: unknown) => TResult2 | PromiseLike<TResult2>) | null,
|
|
175
|
+
): PromiseLike<TResult1 | TResult2> {
|
|
176
|
+
return this.finished.then(fulfilled, rejected)
|
|
177
|
+
}
|
|
178
|
+
get paused() {
|
|
179
|
+
return this.userPaused
|
|
180
|
+
}
|
|
181
|
+
get progress() {
|
|
182
|
+
return this.renderer?.progress ?? this.position
|
|
183
|
+
}
|
|
184
|
+
set progress(value: number) {
|
|
185
|
+
if (this.effect === 'distortion')
|
|
186
|
+
throw new TypeError('Distortion follows touch input and cannot be scrubbed.')
|
|
187
|
+
if (!Number.isFinite(value) || value < 0 || value > 1)
|
|
188
|
+
throw new RangeError('Image progress must be between 0 and 1.')
|
|
189
|
+
if (this.terminal) return
|
|
190
|
+
this.position = value
|
|
191
|
+
this.renderer?.seek(value)
|
|
192
|
+
}
|
|
193
|
+
get diagnostics(): Readonly<ImageEffectDiagnostics> {
|
|
194
|
+
return {
|
|
195
|
+
...this.stats,
|
|
196
|
+
...(this.renderer
|
|
197
|
+
? {
|
|
198
|
+
frames: this.renderer.frames,
|
|
199
|
+
textureBytes: this.renderer.textureBytes,
|
|
200
|
+
longestFrameMs: this.renderer.longestFrameMs,
|
|
201
|
+
}
|
|
202
|
+
: {}),
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
pause = () => {
|
|
206
|
+
if (this.terminal) return
|
|
207
|
+
this.userPaused = true
|
|
208
|
+
this.renderer?.pause()
|
|
209
|
+
}
|
|
210
|
+
play = () => {
|
|
211
|
+
if (this.terminal) return
|
|
212
|
+
this.userPaused = false
|
|
213
|
+
if (this.suspended) return
|
|
214
|
+
if (this.renderer) {
|
|
215
|
+
if (this.effect === 'distortion') this.renderer.resume()
|
|
216
|
+
else this.renderer.play(this.direction)
|
|
217
|
+
} else this.schedule()
|
|
218
|
+
}
|
|
219
|
+
reverse = () => {
|
|
220
|
+
if (this.effect === 'distortion')
|
|
221
|
+
throw new TypeError('Distortion has no finite playback direction.')
|
|
222
|
+
if (this.terminal) return
|
|
223
|
+
this.direction = this.direction === 1 ? 0 : 1
|
|
224
|
+
this.play()
|
|
225
|
+
}
|
|
226
|
+
finish = () => {
|
|
227
|
+
if (this.terminal) return
|
|
228
|
+
if (this.effect === 'distortion') return this.stop()
|
|
229
|
+
this.complete(true, this.direction)
|
|
230
|
+
}
|
|
231
|
+
stop = () => this.complete(false, this.progress)
|
|
232
|
+
private complete = (completed: boolean, position: number, preserveImage = false) => {
|
|
233
|
+
if (this.terminal) return
|
|
234
|
+
this.terminal = true
|
|
235
|
+
this.position = position
|
|
236
|
+
this.stats = { ...this.diagnostics, textureBytes: 0 }
|
|
237
|
+
this.renderer?.stop(preserveImage)
|
|
238
|
+
this.renderer = undefined
|
|
239
|
+
this.releaseOwnership()
|
|
240
|
+
for (const event of ['loaded', 'layoutChanged']) this.image.off(event, this.schedule)
|
|
241
|
+
for (const event of ['imageSourceChange', 'stretchChange'])
|
|
242
|
+
this.image.off(event, this.changed)
|
|
243
|
+
this.image.off('unloaded', this.stop)
|
|
244
|
+
this.image.style.off('visibilityChange', this.visible)
|
|
245
|
+
for (const event of surfaceChanges) this.image.style.off(event, this.changed)
|
|
246
|
+
Application.off(Application.suspendEvent, this.suspend)
|
|
247
|
+
Application.off(Application.resumeEvent, this.resume)
|
|
248
|
+
if (this.reduceObserver)
|
|
249
|
+
Application.ios.removeNotificationObserver(
|
|
250
|
+
this.reduceObserver,
|
|
251
|
+
UIAccessibilityReduceMotionStatusDidChangeNotification,
|
|
252
|
+
)
|
|
253
|
+
this.reduceObserver = undefined
|
|
254
|
+
if (completed && this.effect === 'dissolve' && position === 1) {
|
|
255
|
+
this.committing = true
|
|
256
|
+
// The view may clear its ImageSource on disposal. Keep the caller's
|
|
257
|
+
// destination reusable by giving the view its own wrapper.
|
|
258
|
+
const destination = new ImageSource(this.options.to!.getNativeSource())
|
|
259
|
+
destination.rotationAngle = this.options.to!.rotationAngle
|
|
260
|
+
this.image.imageSource = destination
|
|
261
|
+
this.committing = false
|
|
262
|
+
}
|
|
263
|
+
this.resolve(completed)
|
|
264
|
+
}
|
|
265
|
+
private changed = (event?: EventData) => {
|
|
266
|
+
if (this.committing) return
|
|
267
|
+
if (this.renderer)
|
|
268
|
+
this.complete(false, this.progress, event?.eventName === 'imageSourceChange')
|
|
269
|
+
else this.schedule()
|
|
270
|
+
}
|
|
271
|
+
private suspend = () => {
|
|
272
|
+
this.suspended = true
|
|
273
|
+
this.renderer?.pause()
|
|
274
|
+
}
|
|
275
|
+
private resume = () => {
|
|
276
|
+
this.suspended = false
|
|
277
|
+
this.schedule()
|
|
278
|
+
if (!this.userPaused) this.play()
|
|
279
|
+
}
|
|
280
|
+
private visible = () => {
|
|
281
|
+
if (this.image.visibility !== 'visible') this.stop()
|
|
282
|
+
}
|
|
283
|
+
private preferences = () => {
|
|
284
|
+
if (reducedMotion()) this.fallback('reduced-motion')
|
|
285
|
+
}
|
|
286
|
+
private fallback(reason: ImageEffectDiagnostics['reason']) {
|
|
287
|
+
this.stats = { ...this.stats, backend: 'fallback', reason }
|
|
288
|
+
// Reduced/unsupported rendering still performs a requested content change.
|
|
289
|
+
if (this.effect === 'dissolve' && this.direction === 1) {
|
|
290
|
+
this.complete(true, 1)
|
|
291
|
+
} else this.complete(false, 0)
|
|
292
|
+
}
|
|
293
|
+
private schedule = () => {
|
|
294
|
+
if (this.queued || this.terminal) return
|
|
295
|
+
this.queued = true
|
|
296
|
+
void Promise.resolve().then(() => {
|
|
297
|
+
this.queued = false
|
|
298
|
+
if (this.terminal || this.suspended || !this.image.isLoaded) return
|
|
299
|
+
if (reducedMotion()) return this.fallback('reduced-motion')
|
|
300
|
+
if (this.image.visibility !== 'visible') return this.fallback('not-visible')
|
|
301
|
+
const { width, height } = this.image.getActualSize()
|
|
302
|
+
if (width <= 0 || height <= 0) return
|
|
303
|
+
const dimensions = `${width}:${height}`
|
|
304
|
+
if (this.renderer) {
|
|
305
|
+
if (this.dimensions !== dimensions) this.stop()
|
|
306
|
+
return
|
|
307
|
+
}
|
|
308
|
+
if (!this.image.imageSource) return
|
|
309
|
+
this.dimensions = dimensions
|
|
310
|
+
const started = Date.now()
|
|
311
|
+
try {
|
|
312
|
+
this.renderer = createImageRenderer(
|
|
313
|
+
this.image,
|
|
314
|
+
{
|
|
315
|
+
...this.options,
|
|
316
|
+
mode: names.indexOf(this.effect),
|
|
317
|
+
x: this.options.origin?.x ?? width / 2,
|
|
318
|
+
y: this.options.origin?.y ?? height / 2,
|
|
319
|
+
},
|
|
320
|
+
this.complete,
|
|
321
|
+
)
|
|
322
|
+
} catch (error) {
|
|
323
|
+
this.stats.preparationMs = Date.now() - started
|
|
324
|
+
this.stats.detail = String(error)
|
|
325
|
+
return this.fallback('unsupported')
|
|
326
|
+
}
|
|
327
|
+
if (!this.renderer) return this.fallback('unsupported')
|
|
328
|
+
this.stats.backend = this.renderer.backend
|
|
329
|
+
this.stats.preparationMs = Date.now() - started
|
|
330
|
+
this.stats.peakTextureBytes = this.renderer.textureBytes
|
|
331
|
+
this.renderer.pause()
|
|
332
|
+
if (this.position) this.renderer.seek(this.position)
|
|
333
|
+
if (!this.userPaused && !this.suspended) this.play()
|
|
334
|
+
})
|
|
335
|
+
}
|
|
336
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { Image } from '@nativescript/core'
|
|
2
|
+
|
|
3
|
+
/** Rendering effects share one image surface; ordinary view transforms stay independent. */
|
|
4
|
+
const owners = new WeakMap<Image, () => void>()
|
|
5
|
+
|
|
6
|
+
export function ownImage(image: Image, stop: () => void): () => void {
|
|
7
|
+
owners.get(image)?.()
|
|
8
|
+
owners.set(image, stop)
|
|
9
|
+
return () => {
|
|
10
|
+
if (owners.get(image) === stop) owners.delete(image)
|
|
11
|
+
}
|
|
12
|
+
}
|
package/src/index.ts
CHANGED
|
@@ -1,12 +1,69 @@
|
|
|
1
|
-
export { animate, stop } from './animate.js'
|
|
1
|
+
export { animate, decay, set, stop } from './animate.js'
|
|
2
2
|
export { sequence } from './sequence.js'
|
|
3
|
-
export type { Step } from './sequence.js'
|
|
3
|
+
export type { Step, SequenceOptions, SequencePosition } from './sequence.js'
|
|
4
4
|
export { press } from './press.js'
|
|
5
|
-
export {
|
|
6
|
-
export type {
|
|
5
|
+
export { interactionSurface } from './interaction-surface.js'
|
|
6
|
+
export type { InteractionSurface } from './interaction-surface.js'
|
|
7
|
+
export { drag } from './drag.js'
|
|
8
|
+
export type { Drag, DragOptions, DragPoint, DragEvent, DragRelease } from './drag.js'
|
|
9
|
+
export { scrollLinked } from './scroll-linked.js'
|
|
10
|
+
export type { ScrollLinkedOptions } from './scroll-linked.js'
|
|
11
|
+
export { animateItems } from './items.js'
|
|
12
|
+
export type { ItemsOptions } from './items.js'
|
|
13
|
+
export { followKeyboard, onKeyboard } from './keyboard.js'
|
|
14
|
+
export type { KeyboardOptions, KeyboardState } from './keyboard.js'
|
|
15
|
+
export type { Haptic, HapticOptions, HapticStyle } from './haptics.js'
|
|
16
|
+
export { confetti, particles } from './particles.js'
|
|
17
|
+
export type { ConfettiOptions, ParticleOptions } from './particles.js'
|
|
18
|
+
export { shimmer } from './shimmer.js'
|
|
19
|
+
export type { ShimmerOptions } from './shimmer.js'
|
|
20
|
+
export { liquid } from './liquid.js'
|
|
21
|
+
export type { LiquidOptions, LiquidEffect } from './liquid.js'
|
|
22
|
+
export { imageEffect } from './image-effect.js'
|
|
23
|
+
export type {
|
|
24
|
+
ImageEffect,
|
|
25
|
+
ImageEffectName,
|
|
26
|
+
ImageEffectOptions,
|
|
27
|
+
ImageEffectDiagnostics,
|
|
28
|
+
} from './image-effect.js'
|
|
29
|
+
export { zoomable } from './zoomable.js'
|
|
30
|
+
export type { Zoomable, ZoomableOptions, ZoomState, PhotoDismissal } from './zoomable.js'
|
|
31
|
+
export { loader } from './loader.js'
|
|
32
|
+
export type { LoaderOptions, LoaderStyle } from './loader.js'
|
|
33
|
+
export { reveal, conceal } from './reveal.js'
|
|
34
|
+
export type { RevealOptions, ConcealOptions } from './reveal.js'
|
|
35
|
+
export { animateText } from './text.js'
|
|
36
|
+
export type { TextOptions } from './text.js'
|
|
37
|
+
export { rollTo } from './roll.js'
|
|
38
|
+
export type { RollOptions } from './roll.js'
|
|
39
|
+
export { symbolEffect } from './symbol-effect.js'
|
|
40
|
+
export type {
|
|
41
|
+
SymbolEffect,
|
|
42
|
+
SymbolEffectName,
|
|
43
|
+
SymbolEffectOptions,
|
|
44
|
+
} from './symbol-effect.js'
|
|
45
|
+
export { configure, onReducedMotion, reducedMotion } from './config.js'
|
|
46
|
+
export type { JoltConfig } from './config.js'
|
|
47
|
+
export { definePreset, presets } from './presets.js'
|
|
48
|
+
export type { Preset, PresetName, Presets } from './presets.js'
|
|
7
49
|
export { springs } from './transition.js'
|
|
8
50
|
export type { Spring, SpringName, Timing, Transition, Tween } from './transition.js'
|
|
9
51
|
export { cubicBezier } from './easing.js'
|
|
10
52
|
export type { CubicBezier, Easing, EasingFunction, EasingName } from './easing.js'
|
|
53
|
+
export type { PlaybackAnimation } from './playback.js'
|
|
11
54
|
export type { Animation } from './engine.js'
|
|
55
|
+
export type { ColorValue, ColorKeyframes } from './color.js'
|
|
12
56
|
export type * from './types.js'
|
|
57
|
+
export { motionScope } from './motion-scope.js'
|
|
58
|
+
export type { MotionScope, MotionResource } from './motion-scope.js'
|
|
59
|
+
export { motionStates } from './motion-states.js'
|
|
60
|
+
export type {
|
|
61
|
+
MotionStates,
|
|
62
|
+
MotionStatesOptions,
|
|
63
|
+
MotionState,
|
|
64
|
+
MotionValues,
|
|
65
|
+
StateTransition,
|
|
66
|
+
} from './motion-states.js'
|
|
67
|
+
|
|
68
|
+
export { animateLayout } from './layout.js'
|
|
69
|
+
export type { LayoutOptions } from './layout.js'
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import type { View, ViewBase } from '@nativescript/core'
|
|
2
|
+
import { toView } from './animate.js'
|
|
3
|
+
import type { Target } from './types.js'
|
|
4
|
+
|
|
5
|
+
const surfaces = new WeakMap<ViewBase, Set<object>>()
|
|
6
|
+
export interface InteractionSurface {
|
|
7
|
+
readonly disposed: boolean
|
|
8
|
+
/** Existing animations retain their driver until they end. Disables future opt-in. */
|
|
9
|
+
dispose(): void
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
/** Opt a view/subtree into native geometry updates before starting its animations. */
|
|
13
|
+
export function interactionSurface(target: Target): InteractionSurface {
|
|
14
|
+
const view = toView(target)
|
|
15
|
+
let tokens = surfaces.get(view)
|
|
16
|
+
if (!tokens) surfaces.set(view, (tokens = new Set()))
|
|
17
|
+
const token = {}
|
|
18
|
+
tokens.add(token)
|
|
19
|
+
let disposed = false
|
|
20
|
+
return {
|
|
21
|
+
get disposed() {
|
|
22
|
+
return disposed
|
|
23
|
+
},
|
|
24
|
+
dispose() {
|
|
25
|
+
if (disposed) return
|
|
26
|
+
disposed = true
|
|
27
|
+
tokens.delete(token)
|
|
28
|
+
if (!tokens.size) surfaces.delete(view)
|
|
29
|
+
},
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/** Evaluated at animation start; no per-frame JS traversal. */
|
|
34
|
+
export function hasInteractionSurface(view: View): boolean {
|
|
35
|
+
let current: ViewBase | undefined = view
|
|
36
|
+
while (current) {
|
|
37
|
+
if (surfaces.get(current)?.size) return true
|
|
38
|
+
current = current.parent
|
|
39
|
+
}
|
|
40
|
+
return false
|
|
41
|
+
}
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
declare class JoltInteractiveAnimation extends NSObject {
|
|
2
|
+
static startViewLayersKeyPathValuesTimesDurationDelayRepeatReverseFinalValueStartedAtCompletion(
|
|
3
|
+
view: UIView,
|
|
4
|
+
layers: NSArray<CALayer>,
|
|
5
|
+
keyPath: string,
|
|
6
|
+
values: NSArray<number>,
|
|
7
|
+
times: NSArray<number>,
|
|
8
|
+
duration: number,
|
|
9
|
+
delay: number,
|
|
10
|
+
repeat: number,
|
|
11
|
+
reverse: boolean,
|
|
12
|
+
finalValue: number,
|
|
13
|
+
startedAt: number,
|
|
14
|
+
completion: (completed: boolean) => void,
|
|
15
|
+
): JoltInteractiveAnimation
|
|
16
|
+
static syncViewExcluding(view: UIView, keyPath: string | null): void
|
|
17
|
+
static valueForViewKeyPath(view: UIView, keyPath: string): number | null
|
|
18
|
+
static activeCount(): number
|
|
19
|
+
readonly elapsed: number
|
|
20
|
+
controlPaused(elapsed: number, paused: boolean): void
|
|
21
|
+
cancel(): void
|
|
22
|
+
}
|
|
23
|
+
declare class JoltImageEffect extends NSObject {
|
|
24
|
+
stopPreservingImage(): void
|
|
25
|
+
static createWithViewDestinationModeOriginXOriginYAmplitudeRadiusDurationSeedListener(
|
|
26
|
+
image: UIImageView,
|
|
27
|
+
destination: UIImage | null,
|
|
28
|
+
mode: number,
|
|
29
|
+
x: number,
|
|
30
|
+
y: number,
|
|
31
|
+
amplitude: number,
|
|
32
|
+
radius: number,
|
|
33
|
+
duration: number,
|
|
34
|
+
seed: number,
|
|
35
|
+
listener: (completed: boolean, progress: number) => void,
|
|
36
|
+
): JoltImageEffect | null
|
|
37
|
+
readonly progress: number
|
|
38
|
+
readonly paused: boolean
|
|
39
|
+
readonly frames: number
|
|
40
|
+
readonly longestFrame: number
|
|
41
|
+
readonly textureBytes: number
|
|
42
|
+
play(endpoint: number): void
|
|
43
|
+
pause(): void
|
|
44
|
+
resume(): void
|
|
45
|
+
seek(progress: number): void
|
|
46
|
+
finish(endpoint: number): void
|
|
47
|
+
stop(): void
|
|
48
|
+
}
|
|
49
|
+
declare class JoltPhotoZoom extends NSObject {
|
|
50
|
+
static attachImageViewportMinimumMaximumDoubleTapDismissReducedBackdropChromeOnDismissOnSettled(
|
|
51
|
+
image: UIImageView,
|
|
52
|
+
viewport: UIView,
|
|
53
|
+
minimum: number,
|
|
54
|
+
maximum: number,
|
|
55
|
+
doubleTap: number,
|
|
56
|
+
dismiss: boolean,
|
|
57
|
+
reduced: boolean,
|
|
58
|
+
backdrop: UIView | null,
|
|
59
|
+
chrome: UIView | null,
|
|
60
|
+
onDismiss: (
|
|
61
|
+
x: number,
|
|
62
|
+
y: number,
|
|
63
|
+
scale: number,
|
|
64
|
+
velocity: number,
|
|
65
|
+
progress: number,
|
|
66
|
+
) => void,
|
|
67
|
+
onSettled: (x: number, y: number, scale: number) => void,
|
|
68
|
+
): JoltPhotoZoom
|
|
69
|
+
readonly x: number
|
|
70
|
+
readonly y: number
|
|
71
|
+
readonly scale: number
|
|
72
|
+
readonly dismissProgress: number
|
|
73
|
+
readonly dismissPending: boolean
|
|
74
|
+
zoomFocusXFocusYAnimated(scale: number, x: number, y: number, animated: boolean): void
|
|
75
|
+
reset(animated: boolean): void
|
|
76
|
+
requestDismiss(): void
|
|
77
|
+
setReduced(value: boolean): void
|
|
78
|
+
setActive(value: boolean): void
|
|
79
|
+
layout(): void
|
|
80
|
+
stop(): void
|
|
81
|
+
}
|