@rafaelaugusto/jolt 0.1.0-rc.2 → 0.1.0-rc.3
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 +4 -4
- package/dist/animate.d.ts.map +1 -1
- package/dist/animate.js +20 -5
- package/dist/animate.js.map +1 -1
- package/dist/driver/android.d.ts.map +1 -1
- package/dist/driver/android.js +15 -7
- package/dist/driver/android.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/interactive-navigation/index.d.ts +2 -0
- package/dist/interactive-navigation/index.d.ts.map +1 -1
- package/dist/interactive-navigation/index.js +1 -0
- package/dist/interactive-navigation/index.js.map +1 -1
- package/dist/interactive-navigation/modal.d.ts +34 -0
- package/dist/interactive-navigation/modal.d.ts.map +1 -0
- package/dist/interactive-navigation/modal.js +253 -0
- package/dist/interactive-navigation/modal.js.map +1 -0
- package/dist/scroll-header/geometry.d.ts +1 -1
- package/dist/scroll-header/geometry.d.ts.map +1 -1
- package/dist/scroll-header/geometry.js +7 -2
- package/dist/scroll-header/geometry.js.map +1 -1
- package/dist/scroll-header/index.d.ts.map +1 -1
- package/dist/scroll-header/index.js +13 -0
- package/dist/scroll-header/index.js.map +1 -1
- package/dist/shapes/index.d.ts +1 -1
- package/dist/shapes/index.d.ts.map +1 -1
- package/dist/shapes/index.js +23 -9
- package/dist/shapes/index.js.map +1 -1
- package/dist/types.d.ts +5 -1
- package/dist/types.d.ts.map +1 -1
- package/package.json +1 -1
- package/platforms/android/java/org/rafaelaugusto/jolt/KeyframeFactory.java +26 -0
- package/platforms/android/java/org/rafaelaugusto/jolt/ScrollHeader.java +3 -2
- package/platforms/android/proguard-rules.pro +1 -0
- package/platforms/ios/src/JoltInteractiveModal.h +16 -0
- package/platforms/ios/src/JoltInteractiveModal.m +178 -0
- package/platforms/ios/src/module.modulemap +1 -0
- package/src/android-plugin.d.ts +9 -0
- package/src/animate.ts +23 -5
- package/src/driver/android.ts +31 -14
- package/src/index.ts +1 -1
- package/src/interactive-navigation/index.ts +7 -0
- package/src/interactive-navigation/modal.ts +306 -0
- package/src/ios-plugin.d.ts +22 -0
- package/src/scroll-header/geometry.ts +7 -2
- package/src/scroll-header/index.ts +12 -0
- package/src/shapes/index.ts +20 -9
- package/src/types.ts +5 -2
package/package.json
CHANGED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
package org.rafaelaugusto.jolt;
|
|
2
|
+
|
|
3
|
+
import android.animation.Keyframe;
|
|
4
|
+
import android.animation.ObjectAnimator;
|
|
5
|
+
import android.animation.PropertyValuesHolder;
|
|
6
|
+
import android.util.Property;
|
|
7
|
+
import android.view.View;
|
|
8
|
+
|
|
9
|
+
/** Builds a numeric track without creating a JavaScript proxy for every keyframe. */
|
|
10
|
+
public final class KeyframeFactory {
|
|
11
|
+
private KeyframeFactory() {}
|
|
12
|
+
|
|
13
|
+
public static ObjectAnimator create(View view, Property<View, Float> property,
|
|
14
|
+
double[] times, double[] values, double unit) {
|
|
15
|
+
if (times.length != values.length || values.length < 2) {
|
|
16
|
+
throw new IllegalArgumentException("A track needs matching times and at least two values");
|
|
17
|
+
}
|
|
18
|
+
Keyframe[] frames = new Keyframe[values.length];
|
|
19
|
+
for (int i = 0; i < values.length; i++) {
|
|
20
|
+
// Scale in double precision before the same float conversion as Keyframe.ofFloat.
|
|
21
|
+
frames[i] = Keyframe.ofFloat((float) times[i], (float) (values[i] * unit));
|
|
22
|
+
}
|
|
23
|
+
return ObjectAnimator.ofPropertyValuesHolder(view,
|
|
24
|
+
PropertyValuesHolder.ofKeyframe(property, frames));
|
|
25
|
+
}
|
|
26
|
+
}
|
|
@@ -68,12 +68,13 @@ public final class ScrollHeader implements ViewTreeObserver.OnScrollChangedListe
|
|
|
68
68
|
public void scroll(double target,boolean animated) {
|
|
69
69
|
if(disposed || !Double.isFinite(target))return;
|
|
70
70
|
target=Math.max(0,target);
|
|
71
|
-
if(animated){list.smoothScrollBy((int)Math.round((target-current())*density),300);return;}
|
|
72
71
|
double divider=list.getDividerHeight()/density, stride=rowHeight+divider;
|
|
73
72
|
int index=target<spacer+divider?0:1+(int)Math.floor((target-spacer-divider)/stride);
|
|
74
73
|
index=Math.max(0,Math.min(list.getCount()-1,index));
|
|
75
74
|
double start=index==0?0:spacer+divider+(index-1)*stride;
|
|
76
|
-
|
|
75
|
+
int top=(int)Math.round((start-target)*density);
|
|
76
|
+
if(animated){list.smoothScrollToPositionFromTop(index,top,300);return;}
|
|
77
|
+
list.setSelectionFromTop(index,top);
|
|
77
78
|
list.post(new Runnable(){public void run(){if(!disposed)update(true);}});
|
|
78
79
|
}
|
|
79
80
|
public void dispose() {
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
-keep class org.rafaelaugusto.jolt.ColorTarget { *; }
|
|
2
|
+
-keep class org.rafaelaugusto.jolt.KeyframeFactory { *; }
|
|
2
3
|
-keep class org.rafaelaugusto.jolt.CircleWorld { *; }
|
|
3
4
|
-keep class org.rafaelaugusto.jolt.CircleWorld$* { *; }
|
|
4
5
|
-keep class org.rafaelaugusto.jolt.MotionProbe { *; }
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
#import <UIKit/UIKit.h>
|
|
2
|
+
NS_ASSUME_NONNULL_BEGIN
|
|
3
|
+
|
|
4
|
+
/** Animator supplied through Core's modal transition delegate. No delegate replacement. */
|
|
5
|
+
@interface JoltInteractiveModal : NSObject <UIViewControllerAnimatedTransitioning, UIViewControllerInteractiveTransitioning, UIGestureRecognizerDelegate>
|
|
6
|
+
+ (instancetype)attach:(UIViewController *)controller stiffness:(double)stiffness damping:(double)damping mass:(double)mass shouldBegin:(BOOL (^)(void))shouldBegin onEvent:(void (^)(NSInteger))onEvent;
|
|
7
|
+
+ (NSUInteger)activeCount;
|
|
8
|
+
+ (NSUInteger)recognizerCount;
|
|
9
|
+
@property(nonatomic, readonly) BOOL interactive;
|
|
10
|
+
@property(nonatomic, readonly) double progress;
|
|
11
|
+
@property(nonatomic, readonly) double velocity;
|
|
12
|
+
- (void)preparePresenting:(BOOL)presenting reduced:(BOOL)reduced timeScale:(double)timeScale;
|
|
13
|
+
- (void)cancel;
|
|
14
|
+
- (void)dispose;
|
|
15
|
+
@end
|
|
16
|
+
NS_ASSUME_NONNULL_END
|
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
#import "JoltInteractiveModal.h"
|
|
2
|
+
#import "JoltSpringState.h"
|
|
3
|
+
|
|
4
|
+
@interface JoltInteractiveModal () {
|
|
5
|
+
JoltSpringState _spring;
|
|
6
|
+
}
|
|
7
|
+
@property(nonatomic, weak) UIViewController *controller;
|
|
8
|
+
@property(nonatomic) UIPanGestureRecognizer *pan;
|
|
9
|
+
@property(nonatomic, copy) BOOL (^shouldBegin)(void);
|
|
10
|
+
@property(nonatomic, copy) void (^onEvent)(NSInteger);
|
|
11
|
+
@property(nonatomic) id<UIViewControllerContextTransitioning> context;
|
|
12
|
+
@property(nonatomic) UIView *moving;
|
|
13
|
+
@property(nonatomic) CGAffineTransform originalTransform;
|
|
14
|
+
@property(nonatomic) CGRect bounds;
|
|
15
|
+
@property(nonatomic) CADisplayLink *link;
|
|
16
|
+
@property(nonatomic) double stiffness, damping, mass, previous, started, target, timeScale;
|
|
17
|
+
@property(nonatomic) NSNumber *pendingEnd;
|
|
18
|
+
@property(nonatomic, readwrite) BOOL interactive;
|
|
19
|
+
@property(nonatomic) BOOL presenting, reduced, settling, committed, disposed;
|
|
20
|
+
@end
|
|
21
|
+
|
|
22
|
+
@implementation JoltInteractiveModal
|
|
23
|
+
static NSUInteger active = 0, recognizers = 0;
|
|
24
|
+
+ (NSUInteger)activeCount { return active; }
|
|
25
|
+
+ (NSUInteger)recognizerCount { return recognizers; }
|
|
26
|
+
+ (instancetype)attach:(UIViewController *)controller stiffness:(double)stiffness damping:(double)damping mass:(double)mass shouldBegin:(BOOL (^)(void))shouldBegin onEvent:(void (^)(NSInteger))onEvent {
|
|
27
|
+
JoltInteractiveModal *owner = [self new];
|
|
28
|
+
owner.controller = controller;
|
|
29
|
+
owner.stiffness = stiffness; owner.damping = damping; owner.mass = mass;
|
|
30
|
+
owner.timeScale = 1;
|
|
31
|
+
owner.shouldBegin = shouldBegin; owner.onEvent = onEvent;
|
|
32
|
+
owner.pan = [[UIPanGestureRecognizer alloc] initWithTarget:owner action:@selector(pan:)];
|
|
33
|
+
owner.pan.maximumNumberOfTouches = 1;
|
|
34
|
+
owner.pan.delegate = owner;
|
|
35
|
+
[controller.view addGestureRecognizer:owner.pan]; recognizers++;
|
|
36
|
+
[[NSNotificationCenter defaultCenter] addObserver:owner selector:@selector(cancel) name:UIApplicationWillResignActiveNotification object:nil];
|
|
37
|
+
return owner;
|
|
38
|
+
}
|
|
39
|
+
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)recognizer shouldReceiveTouch:(UITouch *)touch {
|
|
40
|
+
// Scrolling content and native controls keep their own interaction. A modal
|
|
41
|
+
// can expose an ordinary, non-scrolling header as its dismissal surface.
|
|
42
|
+
for (UIView *view = touch.view; view; view = view.superview) {
|
|
43
|
+
if ([view isKindOfClass:UIControl.class] || [view isKindOfClass:UIScrollView.class]) return NO;
|
|
44
|
+
if (view == self.controller.view) break;
|
|
45
|
+
}
|
|
46
|
+
return YES;
|
|
47
|
+
}
|
|
48
|
+
- (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)recognizer {
|
|
49
|
+
UIViewController *controller = self.controller;
|
|
50
|
+
CGPoint velocity = [self.pan velocityInView:controller.view];
|
|
51
|
+
return !self.disposed && !self.context && controller.presentingViewController &&
|
|
52
|
+
!controller.presentedViewController && !controller.transitionCoordinator && !controller.modalInPresentation &&
|
|
53
|
+
velocity.y > fabs(velocity.x) && self.shouldBegin && self.shouldBegin();
|
|
54
|
+
}
|
|
55
|
+
- (void)preparePresenting:(BOOL)presenting reduced:(BOOL)reduced timeScale:(double)timeScale {
|
|
56
|
+
self.presenting = presenting; self.reduced = reduced; self.timeScale = timeScale;
|
|
57
|
+
}
|
|
58
|
+
- (void)pan:(UIPanGestureRecognizer *)pan {
|
|
59
|
+
if (pan.state == UIGestureRecognizerStateBegan) {
|
|
60
|
+
self.pendingEnd = nil; self.interactive = YES;
|
|
61
|
+
_spring = (JoltSpringState){0, 0};
|
|
62
|
+
if (self.onEvent) self.onEvent(2);
|
|
63
|
+
}
|
|
64
|
+
if (!self.interactive || self.settling) return;
|
|
65
|
+
double height = MAX(1, self.context ? self.bounds.size.height : self.controller.view.bounds.size.height);
|
|
66
|
+
double progress = MAX(0, MIN(1, [pan translationInView:self.controller.view].y / height));
|
|
67
|
+
double velocity = [pan velocityInView:self.controller.view].y / height;
|
|
68
|
+
_spring = (JoltSpringState){progress, velocity};
|
|
69
|
+
if (self.context) { [self render:progress]; [self.context updateInteractiveTransition:progress]; }
|
|
70
|
+
if (pan.state == UIGestureRecognizerStateEnded || pan.state == UIGestureRecognizerStateCancelled || pan.state == UIGestureRecognizerStateFailed) {
|
|
71
|
+
BOOL finish = pan.state == UIGestureRecognizerStateEnded && progress + velocity * .16 > .5;
|
|
72
|
+
if (self.context) [self settle:finish velocity:velocity];
|
|
73
|
+
else self.pendingEnd = @(finish);
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
- (NSTimeInterval)transitionDuration:(id<UIViewControllerContextTransitioning>)context { return self.reduced ? 0 : .55; }
|
|
77
|
+
- (BOOL)wantsInteractiveStart { return self.interactive; }
|
|
78
|
+
- (CGFloat)completionSpeed { return 1; }
|
|
79
|
+
- (UIViewAnimationCurve)completionCurve { return UIViewAnimationCurveLinear; }
|
|
80
|
+
- (double)progress { return _spring.position; }
|
|
81
|
+
- (double)velocity { return _spring.velocity; }
|
|
82
|
+
- (void)prepare:(id<UIViewControllerContextTransitioning>)context {
|
|
83
|
+
self.context = context; active++;
|
|
84
|
+
UIViewController *controller = [context viewControllerForKey:self.presenting ? UITransitionContextToViewControllerKey : UITransitionContextFromViewControllerKey];
|
|
85
|
+
self.moving = [context viewForKey:self.presenting ? UITransitionContextToViewKey : UITransitionContextFromViewKey] ?: controller.view;
|
|
86
|
+
self.originalTransform = self.moving.transform;
|
|
87
|
+
if (self.presenting) {
|
|
88
|
+
self.moving.frame = [context finalFrameForViewController:controller];
|
|
89
|
+
[context.containerView addSubview:self.moving];
|
|
90
|
+
}
|
|
91
|
+
[self.moving setNeedsLayout]; [self.moving layoutIfNeeded];
|
|
92
|
+
self.bounds = context.containerView.bounds;
|
|
93
|
+
_spring = (JoltSpringState){0, 0};
|
|
94
|
+
[self render:0];
|
|
95
|
+
}
|
|
96
|
+
- (void)startInteractiveTransition:(id<UIViewControllerContextTransitioning>)context {
|
|
97
|
+
JoltSpringState held = _spring;
|
|
98
|
+
[self prepare:context]; _spring = held;
|
|
99
|
+
[self render:_spring.position]; [context updateInteractiveTransition:_spring.position];
|
|
100
|
+
[self startLink];
|
|
101
|
+
if (self.pendingEnd || self.disposed) {
|
|
102
|
+
[self settle:!self.disposed && self.pendingEnd.boolValue velocity:_spring.velocity];
|
|
103
|
+
self.pendingEnd = nil;
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
- (void)animateTransition:(id<UIViewControllerContextTransitioning>)context {
|
|
107
|
+
[self prepare:context];
|
|
108
|
+
if (self.onEvent) self.onEvent(0);
|
|
109
|
+
[self settle:YES velocity:0];
|
|
110
|
+
}
|
|
111
|
+
- (void)render:(double)progress {
|
|
112
|
+
double p = MAX(0, MIN(1, progress));
|
|
113
|
+
double translation = self.bounds.size.height * (self.presenting ? 1 - p : p);
|
|
114
|
+
[CATransaction begin]; [CATransaction setDisableActions:YES];
|
|
115
|
+
self.moving.transform = CGAffineTransformConcat(self.originalTransform, CGAffineTransformMakeTranslation(0, translation));
|
|
116
|
+
[CATransaction commit];
|
|
117
|
+
}
|
|
118
|
+
- (void)startLink {
|
|
119
|
+
if (self.link || !self.context) return;
|
|
120
|
+
self.previous = CACurrentMediaTime();
|
|
121
|
+
self.link = [CADisplayLink displayLinkWithTarget:self selector:@selector(tick:)];
|
|
122
|
+
if (@available(iOS 15.0, *)) {
|
|
123
|
+
float maximum = MIN(120, UIScreen.mainScreen.maximumFramesPerSecond);
|
|
124
|
+
self.link.preferredFrameRateRange = CAFrameRateRangeMake(MIN(80, maximum), maximum, maximum);
|
|
125
|
+
}
|
|
126
|
+
[self.link addToRunLoop:NSRunLoop.mainRunLoop forMode:NSRunLoopCommonModes];
|
|
127
|
+
}
|
|
128
|
+
- (void)settle:(BOOL)finish velocity:(double)velocity {
|
|
129
|
+
if (!self.context || self.settling) return;
|
|
130
|
+
self.committed = finish; self.settling = YES; self.target = finish ? 1 : 0;
|
|
131
|
+
_spring.velocity = velocity;
|
|
132
|
+
if (self.interactive) {
|
|
133
|
+
// Core must know cancellation BEFORE UIKit executes dismissal completion.
|
|
134
|
+
if (self.onEvent) self.onEvent(finish ? 3 : 4);
|
|
135
|
+
if (!self.context) return;
|
|
136
|
+
if (finish) [self.context finishInteractiveTransition]; else [self.context cancelInteractiveTransition];
|
|
137
|
+
}
|
|
138
|
+
self.started = CACurrentMediaTime(); self.previous = self.started;
|
|
139
|
+
if (self.reduced || self.disposed) { [self finish]; return; }
|
|
140
|
+
[self startLink];
|
|
141
|
+
}
|
|
142
|
+
- (void)tick:(CADisplayLink *)link {
|
|
143
|
+
if (!CGRectEqualToRect(self.bounds, self.context.containerView.bounds) || !self.context.containerView.window) { [self cancel]; return; }
|
|
144
|
+
if (!self.settling) return;
|
|
145
|
+
double now = CACurrentMediaTime(), seconds = MAX(0, now - self.previous); self.previous = now;
|
|
146
|
+
_spring = JoltSpringAdvance(_spring, self.target, self.stiffness*self.timeScale*self.timeScale, self.damping*self.timeScale, self.mass, seconds);
|
|
147
|
+
if (!isfinite(_spring.position) || !isfinite(_spring.velocity)) { [self finish]; return; }
|
|
148
|
+
[self render:_spring.position];
|
|
149
|
+
if ((fabs(_spring.position-self.target)<.0005 && fabs(_spring.velocity)<.005) || now-self.started>=3) [self finish];
|
|
150
|
+
}
|
|
151
|
+
- (void)finish {
|
|
152
|
+
if (!self.context) return;
|
|
153
|
+
[self.link invalidate]; self.link = nil;
|
|
154
|
+
BOOL completed = self.committed, presenting = self.presenting;
|
|
155
|
+
_spring = (JoltSpringState){completed ? 1 : 0, 0}; [self render:_spring.position];
|
|
156
|
+
self.moving.transform = self.originalTransform;
|
|
157
|
+
id<UIViewControllerContextTransitioning> context = self.context;
|
|
158
|
+
self.context = nil; self.moving = nil; self.settling = NO; self.interactive = NO; active--;
|
|
159
|
+
[context completeTransition:completed];
|
|
160
|
+
if (self.onEvent) self.onEvent(presenting ? 1 : completed ? 5 : 6);
|
|
161
|
+
}
|
|
162
|
+
- (void)cancel {
|
|
163
|
+
if (!self.context) { if (self.interactive) self.pendingEnd = @NO; return; }
|
|
164
|
+
if (!self.settling) [self settle:!self.interactive velocity:0];
|
|
165
|
+
[self finish];
|
|
166
|
+
}
|
|
167
|
+
- (void)dispose {
|
|
168
|
+
if (self.disposed) return;
|
|
169
|
+
self.disposed = YES;
|
|
170
|
+
[self cancel];
|
|
171
|
+
[self.pan.view removeGestureRecognizer:self.pan];
|
|
172
|
+
self.pan.delegate = nil;
|
|
173
|
+
if (self.pan) recognizers--;
|
|
174
|
+
self.pan = nil;
|
|
175
|
+
[[NSNotificationCenter defaultCenter] removeObserver:self];
|
|
176
|
+
self.shouldBegin = nil; self.onEvent = nil;
|
|
177
|
+
}
|
|
178
|
+
@end
|
package/src/android-plugin.d.ts
CHANGED
|
@@ -1,4 +1,13 @@
|
|
|
1
1
|
declare namespace org.rafaelaugusto.jolt {
|
|
2
|
+
class KeyframeFactory {
|
|
3
|
+
static create(
|
|
4
|
+
view: android.view.View,
|
|
5
|
+
property: android.util.Property<android.view.View, java.lang.Float>,
|
|
6
|
+
times: readonly number[],
|
|
7
|
+
values: readonly number[],
|
|
8
|
+
unit: number,
|
|
9
|
+
): android.animation.ObjectAnimator
|
|
10
|
+
}
|
|
2
11
|
class ShapeLayer extends android.graphics.drawable.Drawable {
|
|
3
12
|
constructor(options: string)
|
|
4
13
|
static liveCount(): number
|
package/src/animate.ts
CHANGED
|
@@ -308,12 +308,30 @@ export function group(animations: readonly Animation[]): Animation {
|
|
|
308
308
|
}
|
|
309
309
|
|
|
310
310
|
export function toView(target: Target): View {
|
|
311
|
-
|
|
312
|
-
const view =
|
|
313
|
-
(target as { nativeView?: unknown } | null)?.nativeView ??
|
|
314
|
-
(target as { nativeElement?: unknown } | null)?.nativeElement
|
|
311
|
+
const view = unwrap(target)
|
|
315
312
|
if (view instanceof View) return view
|
|
316
|
-
throw new TypeError(`Expected a NativeScript view, got ${
|
|
313
|
+
throw new TypeError(`Expected a NativeScript view, got ${describe(target)}.`)
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
function unwrap(target: unknown, nested = false): unknown {
|
|
317
|
+
if (target instanceof View || target === null || typeof target !== 'object')
|
|
318
|
+
return target
|
|
319
|
+
const holder = target as {
|
|
320
|
+
nativeView?: unknown
|
|
321
|
+
nativeElement?: unknown
|
|
322
|
+
$el?: unknown
|
|
323
|
+
}
|
|
324
|
+
if (!nested && '$el' in holder) return unwrap(holder.$el, true)
|
|
325
|
+
return holder.nativeView ?? holder.nativeElement
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
function describe(target: unknown) {
|
|
329
|
+
if (target === null || typeof target !== 'object')
|
|
330
|
+
return typeof target === 'function' ? 'a function' : String(target)
|
|
331
|
+
if (Array.isArray(target)) return 'an array'
|
|
332
|
+
if ('$el' in target) return 'a component instance without a root view'
|
|
333
|
+
const name = Object.getPrototypeOf(target)?.constructor?.name
|
|
334
|
+
return name && name !== 'Object' ? `a ${name}` : 'an object without a view'
|
|
317
335
|
}
|
|
318
336
|
|
|
319
337
|
export function toViews(target: Target | readonly Target[]): View[] {
|
package/src/driver/android.ts
CHANGED
|
@@ -130,20 +130,37 @@ export function createAndroidDriver(): Driver {
|
|
|
130
130
|
)
|
|
131
131
|
}
|
|
132
132
|
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
133
|
+
let animator: android.animation.ObjectAnimator
|
|
134
|
+
if (
|
|
135
|
+
typeof org !== 'undefined' &&
|
|
136
|
+
typeof org.rafaelaugusto?.jolt?.KeyframeFactory === 'function'
|
|
137
|
+
) {
|
|
138
|
+
animator = org.rafaelaugusto.jolt.KeyframeFactory.create(
|
|
139
|
+
nativeView,
|
|
140
|
+
nativeProperties[track.property],
|
|
141
|
+
track.times,
|
|
142
|
+
track.values,
|
|
143
|
+
scale,
|
|
144
|
+
)
|
|
145
|
+
} else {
|
|
146
|
+
// Keep JS-only updates working with an app binary built before the factory.
|
|
147
|
+
const keyframes = Array.create(android.animation.Keyframe, track.values.length)
|
|
148
|
+
track.values.forEach((value, i) => {
|
|
149
|
+
keyframes[i] = android.animation.Keyframe.ofFloat(
|
|
150
|
+
track.times[i]!,
|
|
151
|
+
value * scale,
|
|
152
|
+
)
|
|
153
|
+
})
|
|
154
|
+
const holders = Array.create(android.animation.PropertyValuesHolder, 1)
|
|
155
|
+
holders[0] = android.animation.PropertyValuesHolder.ofKeyframe(
|
|
156
|
+
nativeProperties[track.property],
|
|
157
|
+
keyframes,
|
|
158
|
+
)
|
|
159
|
+
animator = android.animation.ObjectAnimator.ofPropertyValuesHolder(
|
|
160
|
+
nativeView,
|
|
161
|
+
holders,
|
|
162
|
+
)
|
|
163
|
+
}
|
|
147
164
|
let restoreLayer: (() => void) | undefined
|
|
148
165
|
const releaseLayer = () => {
|
|
149
166
|
restoreLayer?.()
|
package/src/index.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
export { timeline } from './sequence.js'
|
|
2
2
|
export type { TimelineAnimation, TimelineStep, PlayableAnimation } from './sequence.js'
|
|
3
3
|
export { playbackProgress } from './motion-value.js'
|
|
4
|
-
export { animate, decay, set, stop } from './animate.js'
|
|
4
|
+
export { animate, decay, set, stop, toView } from './animate.js'
|
|
5
5
|
export { bind, motionValue, scrollValue, springValue } from './motion-value.js'
|
|
6
6
|
export type {
|
|
7
7
|
Bindings,
|
|
@@ -1,4 +1,11 @@
|
|
|
1
1
|
import { ReturnScope } from '../shared-navigation/return-signal.js'
|
|
2
|
+
export { interactiveModal } from './modal.js'
|
|
3
|
+
export type {
|
|
4
|
+
InteractiveModal,
|
|
5
|
+
InteractiveModalEvent,
|
|
6
|
+
InteractiveModalOptions,
|
|
7
|
+
InteractiveModalState,
|
|
8
|
+
} from './modal.js'
|
|
2
9
|
import {
|
|
3
10
|
Application,
|
|
4
11
|
Image,
|