react-native-smooth-clip-view 0.2.9 → 0.3.0
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 +60 -21
- package/android/build.gradle +6 -2
- package/android/proguard-rules.pro +3 -3
- package/android/src/main/cpp/SmoothClipAndroid.h +10 -0
- package/android/src/main/cpp/SmoothClipBindings.cpp +890 -4
- package/android/src/main/cpp/SmoothClipRegistry.cpp +1056 -44
- package/android/src/main/java/com/smoothclipview/ClipGeometryNormalizer.kt +265 -0
- package/android/src/main/java/com/smoothclipview/SmoothClipBindings.kt +21 -0
- package/android/src/main/java/com/smoothclipview/SmoothClipModule.kt +283 -0
- package/android/src/main/java/com/smoothclipview/SmoothClipView.kt +371 -18
- package/android/src/main/java/com/smoothclipview/SmoothClipViewManager.kt +138 -24
- package/cpp/SmoothClipAnimationCurve.h +151 -122
- package/cpp/SmoothClipRegistry.h +95 -3
- package/cpp/SmoothClipSharedGeometry.h +146 -7
- package/cpp/SmoothClipVelocityTracker.h +13 -9
- package/ios/SmoothClipGeometry.h +184 -6
- package/ios/SmoothClipRegistry.mm +1028 -22
- package/ios/SmoothClipRegistrySnapshot.h +13 -0
- package/ios/SmoothClipTurboModule.cpp +857 -2
- package/ios/SmoothClipTurboModule.h +310 -0
- package/ios/SmoothClipView.mm +714 -183
- package/ios/SmoothClipViewRegistry.h +1 -0
- package/ios/reactnativesmoothclipview.xcodeproj/project.xcworkspace/contents.xcworkspacedata +7 -0
- package/ios/reactnativesmoothclipview.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist +8 -0
- package/lib/module/NativeSmoothClipModule.js.map +1 -1
- package/lib/module/SmoothClipView.ios.js +22 -6
- package/lib/module/SmoothClipView.ios.js.map +1 -1
- package/lib/module/SmoothClipView.js +1 -46
- package/lib/module/SmoothClipView.js.map +1 -1
- package/lib/module/SmoothClipViewNativeComponent.ts +27 -1
- package/lib/module/capabilities.js +4 -0
- package/lib/module/capabilities.js.map +1 -0
- package/lib/module/capabilities.native.js +36 -0
- package/lib/module/capabilities.native.js.map +1 -0
- package/lib/module/capabilityTypes.js +11 -0
- package/lib/module/capabilityTypes.js.map +1 -0
- package/lib/module/driverState.js +0 -28
- package/lib/module/driverState.js.map +1 -1
- package/lib/module/drivers.js +1 -281
- package/lib/module/drivers.js.map +1 -1
- package/lib/module/drivers.native.js +263 -63
- package/lib/module/drivers.native.js.map +1 -1
- package/lib/module/geometry.js +147 -17
- package/lib/module/geometry.js.map +1 -1
- package/lib/module/groupDriverTypes.js +4 -0
- package/lib/module/groupDriverTypes.js.map +1 -0
- package/lib/module/groupDrivers.android.js +4 -0
- package/lib/module/groupDrivers.android.js.map +1 -0
- package/lib/module/groupDrivers.ios.js +4 -0
- package/lib/module/groupDrivers.ios.js.map +1 -0
- package/lib/module/groupDrivers.js +4 -0
- package/lib/module/groupDrivers.js.map +1 -0
- package/lib/module/groupDrivers.native.js +799 -0
- package/lib/module/groupDrivers.native.js.map +1 -0
- package/lib/module/index.js +3 -2
- package/lib/module/index.js.map +1 -1
- package/lib/module/presentationProtocol.js +15 -0
- package/lib/module/presentationProtocol.js.map +1 -0
- package/lib/typescript/src/NativeSmoothClipModule.d.ts +25 -0
- package/lib/typescript/src/NativeSmoothClipModule.d.ts.map +1 -1
- package/lib/typescript/src/SmoothClipView.d.ts +2 -10
- package/lib/typescript/src/SmoothClipView.d.ts.map +1 -1
- package/lib/typescript/src/SmoothClipView.ios.d.ts +133 -2
- package/lib/typescript/src/SmoothClipView.ios.d.ts.map +1 -1
- package/lib/typescript/src/SmoothClipViewNativeComponent.d.ts +8 -0
- package/lib/typescript/src/SmoothClipViewNativeComponent.d.ts.map +1 -1
- package/lib/typescript/src/capabilities.d.ts +3 -0
- package/lib/typescript/src/capabilities.d.ts.map +1 -0
- package/lib/typescript/src/capabilities.native.d.ts +3 -0
- package/lib/typescript/src/capabilities.native.d.ts.map +1 -0
- package/lib/typescript/src/capabilityTypes.d.ts +10 -0
- package/lib/typescript/src/capabilityTypes.d.ts.map +1 -0
- package/lib/typescript/src/driverState.d.ts +1 -6
- package/lib/typescript/src/driverState.d.ts.map +1 -1
- package/lib/typescript/src/driverTypes.d.ts +25 -11
- package/lib/typescript/src/driverTypes.d.ts.map +1 -1
- package/lib/typescript/src/drivers.d.ts +2 -4
- package/lib/typescript/src/drivers.d.ts.map +1 -1
- package/lib/typescript/src/drivers.native.d.ts.map +1 -1
- package/lib/typescript/src/geometry.d.ts +36 -2
- package/lib/typescript/src/geometry.d.ts.map +1 -1
- package/lib/typescript/src/groupDriverTypes.d.ts +66 -0
- package/lib/typescript/src/groupDriverTypes.d.ts.map +1 -0
- package/lib/typescript/src/groupDrivers.android.d.ts +2 -0
- package/lib/typescript/src/groupDrivers.android.d.ts.map +1 -0
- package/lib/typescript/src/groupDrivers.d.ts +2 -0
- package/lib/typescript/src/groupDrivers.d.ts.map +1 -0
- package/lib/typescript/src/groupDrivers.ios.d.ts +2 -0
- package/lib/typescript/src/groupDrivers.ios.d.ts.map +1 -0
- package/lib/typescript/src/groupDrivers.native.d.ts +4 -0
- package/lib/typescript/src/groupDrivers.native.d.ts.map +1 -0
- package/lib/typescript/src/index.d.ts +6 -3
- package/lib/typescript/src/index.d.ts.map +1 -1
- package/lib/typescript/src/presentationProtocol.d.ts +4 -0
- package/lib/typescript/src/presentationProtocol.d.ts.map +1 -0
- package/package.json +10 -11
- package/src/NativeSmoothClipModule.ts +275 -0
- package/src/SmoothClipView.ios.tsx +30 -11
- package/src/SmoothClipView.tsx +2 -76
- package/src/SmoothClipViewNativeComponent.ts +27 -1
- package/src/capabilities.native.ts +69 -0
- package/src/capabilities.ts +2 -0
- package/src/capabilityTypes.ts +17 -0
- package/src/driverState.ts +1 -41
- package/src/driverTypes.ts +42 -11
- package/src/drivers.native.ts +824 -124
- package/src/drivers.ts +2 -423
- package/src/geometry.ts +231 -27
- package/src/groupDriverTypes.ts +117 -0
- package/src/groupDrivers.android.ts +1 -0
- package/src/groupDrivers.ios.ts +1 -0
- package/src/groupDrivers.native.ts +1189 -0
- package/src/groupDrivers.ts +1 -0
- package/src/index.ts +30 -2
- package/src/presentationProtocol.ts +28 -0
- package/lib/module/SmoothClipView.web.js +0 -54
- package/lib/module/SmoothClipView.web.js.map +0 -1
- package/lib/module/index.web.js +0 -8
- package/lib/module/index.web.js.map +0 -1
- package/lib/module/webClipPath.js +0 -25
- package/lib/module/webClipPath.js.map +0 -1
- package/lib/typescript/src/SmoothClipView.web.d.ts +0 -10
- package/lib/typescript/src/SmoothClipView.web.d.ts.map +0 -1
- package/lib/typescript/src/index.web.d.ts +0 -9
- package/lib/typescript/src/index.web.d.ts.map +0 -1
- package/lib/typescript/src/webClipPath.d.ts +0 -7
- package/lib/typescript/src/webClipPath.d.ts.map +0 -1
- package/src/SmoothClipView.web.tsx +0 -66
- package/src/index.web.ts +0 -23
- package/src/webClipPath.ts +0 -30
package/src/drivers.native.ts
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
|
-
// The shared
|
|
1
|
+
// The shared native driver: iOS and Android both execute this file, via the
|
|
2
2
|
// one-line re-exports in drivers.ios.ts / drivers.android.ts that Metro's
|
|
3
3
|
// platform resolution picks up from index.ts's `./drivers` import. Only the
|
|
4
|
-
// `./smoothClipNative` import below is platform-split.
|
|
5
|
-
// suffix) is the web/Reanimated fallback, not this driver's sibling.
|
|
4
|
+
// `./smoothClipNative` import below is platform-split.
|
|
6
5
|
import { useEffect, useRef } from 'react';
|
|
7
6
|
import { Platform } from 'react-native';
|
|
8
7
|
import { useSharedValue, type SharedValue } from 'react-native-reanimated';
|
|
9
8
|
import { isRNRuntime, scheduleOnRN, scheduleOnUI } from 'react-native-worklets';
|
|
10
9
|
import NativeSmoothClipModule from './smoothClipNative';
|
|
10
|
+
import { getSmoothClipCapabilities } from './capabilities';
|
|
11
11
|
import type {
|
|
12
12
|
ClipReduceMotion,
|
|
13
13
|
KeyframedClipAnimation,
|
|
@@ -30,9 +30,11 @@ import {
|
|
|
30
30
|
synchronizeNativeCompletion,
|
|
31
31
|
} from './nativeCompletion';
|
|
32
32
|
import {
|
|
33
|
+
canonicalizeClipPresentation,
|
|
33
34
|
clipPresentationEquals,
|
|
34
35
|
createClipPresentation,
|
|
35
36
|
isFiniteClipPresentation,
|
|
37
|
+
type CanonicalSmoothClipPresentation,
|
|
36
38
|
type ClipGeometry,
|
|
37
39
|
type SmoothClipPresentation,
|
|
38
40
|
} from './geometry';
|
|
@@ -51,6 +53,45 @@ const NATIVE = 1;
|
|
|
51
53
|
// stamp there is a wasted native _getAnimationTimestamp() call per animateTo.
|
|
52
54
|
// Resolved once at module scope; the worklet captures the primitive.
|
|
53
55
|
const NEEDS_START_STAMP = Platform.OS === 'android';
|
|
56
|
+
const PRESENTATION_PROTOCOL_VERSION =
|
|
57
|
+
getSmoothClipCapabilities().presentationProtocolVersion;
|
|
58
|
+
|
|
59
|
+
type NativeV2HostFunctions = Readonly<{
|
|
60
|
+
setClipPresentationV2(
|
|
61
|
+
driverId: number,
|
|
62
|
+
x: number,
|
|
63
|
+
y: number,
|
|
64
|
+
width: number,
|
|
65
|
+
height: number,
|
|
66
|
+
topLeftRadius: number,
|
|
67
|
+
topRightRadius: number,
|
|
68
|
+
bottomRightRadius: number,
|
|
69
|
+
bottomLeftRadius: number,
|
|
70
|
+
curveCode: number,
|
|
71
|
+
contentTranslateX: number,
|
|
72
|
+
contentTranslateY: number,
|
|
73
|
+
contentScale: number,
|
|
74
|
+
takeOwnership: boolean,
|
|
75
|
+
overridePendingAnimation: boolean,
|
|
76
|
+
recordVelocity?: boolean
|
|
77
|
+
): void;
|
|
78
|
+
beginInteractionV2(driverId: number): readonly number[];
|
|
79
|
+
snapshotCurrentV2(driverId: number): readonly number[];
|
|
80
|
+
animateTimingV2(...args: readonly unknown[]): number;
|
|
81
|
+
animateSpringV2(...args: readonly unknown[]): number;
|
|
82
|
+
animateKeyframesV2(...args: readonly unknown[]): number;
|
|
83
|
+
animateTimingFromV2(...args: readonly unknown[]): number;
|
|
84
|
+
animateSpringFromV2(...args: readonly unknown[]): number;
|
|
85
|
+
animateKeyframesFromV2(...args: readonly unknown[]): number;
|
|
86
|
+
cancelAnimationV2(
|
|
87
|
+
driverId: number,
|
|
88
|
+
animationId: number,
|
|
89
|
+
behavior: number
|
|
90
|
+
): readonly number[];
|
|
91
|
+
}>;
|
|
92
|
+
|
|
93
|
+
const NativeSmoothClipModuleV2 =
|
|
94
|
+
NativeSmoothClipModule as unknown as Partial<NativeV2HostFunctions>;
|
|
54
95
|
|
|
55
96
|
// Widened like the animate* functions below: one trailing argument beyond the
|
|
56
97
|
// TurboModule spec — whether this write should record an `'inherit'` velocity
|
|
@@ -86,15 +127,35 @@ const animateKeyframesHostFunction: WithStartStamp<
|
|
|
86
127
|
const rejectAnimationHostFunction = NativeSmoothClipModule.rejectAnimation;
|
|
87
128
|
const cancelAnimationHostFunction = NativeSmoothClipModule.cancelAnimation;
|
|
88
129
|
const destroyDriverHostFunction = NativeSmoothClipModule.destroyDriver;
|
|
130
|
+
const setPresentationV2HostFunction =
|
|
131
|
+
NativeSmoothClipModuleV2.setClipPresentationV2;
|
|
132
|
+
const beginInteractionV2HostFunction =
|
|
133
|
+
NativeSmoothClipModuleV2.beginInteractionV2;
|
|
134
|
+
const snapshotCurrentV2HostFunction =
|
|
135
|
+
NativeSmoothClipModuleV2.snapshotCurrentV2;
|
|
136
|
+
const animateTimingV2HostFunction = NativeSmoothClipModuleV2.animateTimingV2;
|
|
137
|
+
const animateSpringV2HostFunction = NativeSmoothClipModuleV2.animateSpringV2;
|
|
138
|
+
const animateKeyframesV2HostFunction =
|
|
139
|
+
NativeSmoothClipModuleV2.animateKeyframesV2;
|
|
140
|
+
const animateTimingFromV2HostFunction =
|
|
141
|
+
NativeSmoothClipModuleV2.animateTimingFromV2;
|
|
142
|
+
const animateSpringFromV2HostFunction =
|
|
143
|
+
NativeSmoothClipModuleV2.animateSpringFromV2;
|
|
144
|
+
const animateKeyframesFromV2HostFunction =
|
|
145
|
+
NativeSmoothClipModuleV2.animateKeyframesFromV2;
|
|
146
|
+
const cancelAnimationV2HostFunction =
|
|
147
|
+
NativeSmoothClipModuleV2.cancelAnimationV2;
|
|
89
148
|
|
|
90
|
-
// Workaround for react-native-worklets 0.10
|
|
149
|
+
// Workaround for react-native-worklets 0.10.0 (fixed upstream in >=0.10.1,
|
|
150
|
+
// which drops the registry/proxy design; kept while the peer range still
|
|
151
|
+
// allows 0.10.0 consumers): the RN-side serialization cache
|
|
91
152
|
// hands out one remote-function registry id per function forever, but the
|
|
92
153
|
// registry entry is deleted as soon as any transient UI-side proxy of that
|
|
93
154
|
// function is garbage collected. A later scheduleOnRN for the same function
|
|
94
155
|
// then reads `undefined` from the registry and aborts in Value::getObject.
|
|
95
156
|
// Pinning one UI-side reference for the app lifetime keeps the proxy — and
|
|
96
|
-
// with it the registry entry — alive. Remove once
|
|
97
|
-
//
|
|
157
|
+
// with it the registry entry — alive. Remove once the peer range requires
|
|
158
|
+
// worklets >=0.10.1.
|
|
98
159
|
scheduleOnUI((resolver: typeof resolveReactRequest) => {
|
|
99
160
|
'worklet';
|
|
100
161
|
(globalThis as Record<string, unknown>).__smoothClipPinnedResolver = resolver;
|
|
@@ -111,7 +172,10 @@ function reduceMotionCode(value: ClipReduceMotion): number {
|
|
|
111
172
|
}
|
|
112
173
|
}
|
|
113
174
|
|
|
114
|
-
function animationIsFinite(
|
|
175
|
+
function animationIsFinite(
|
|
176
|
+
animation: SmoothClipAnimation,
|
|
177
|
+
strictV2: boolean
|
|
178
|
+
): boolean {
|
|
115
179
|
'worklet';
|
|
116
180
|
if (
|
|
117
181
|
animation.from !== undefined &&
|
|
@@ -125,44 +189,67 @@ function animationIsFinite(animation: SmoothClipAnimation): boolean {
|
|
|
125
189
|
const [x1, , x2] = animation.controlPoints;
|
|
126
190
|
return (
|
|
127
191
|
Number.isFinite(animation.duration) &&
|
|
192
|
+
(!strictV2 || animation.duration >= 0) &&
|
|
128
193
|
animation.controlPoints.every(Number.isFinite) &&
|
|
129
194
|
// A cubic-bezier easing is only defined for x within [0,1] (the CSS /
|
|
130
195
|
// CoreAnimation / Reanimated Easing.bezier contract). Out-of-range x
|
|
131
196
|
// makes the Android parameter solve meaningless while CoreAnimation
|
|
132
197
|
// silently clamps — reject like any other invalid input instead of
|
|
133
198
|
// diverging per platform.
|
|
134
|
-
x1 >= 0 &&
|
|
135
|
-
x1 <= 1 &&
|
|
136
|
-
x2 >= 0 &&
|
|
137
|
-
x2 <= 1
|
|
199
|
+
(!strictV2 || (x1 >= 0 && x1 <= 1 && x2 >= 0 && x2 <= 1))
|
|
138
200
|
);
|
|
139
201
|
}
|
|
140
202
|
if (animation.type === 'spring') {
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
203
|
+
const mass = animation.mass ?? 1;
|
|
204
|
+
const stiffness = animation.stiffness ?? 100;
|
|
205
|
+
const damping = animation.damping ?? 10;
|
|
206
|
+
const initialVelocity =
|
|
145
207
|
animation.initialVelocity === 'inherit'
|
|
146
208
|
? 0
|
|
147
|
-
: (animation.initialVelocity ?? 0)
|
|
148
|
-
|
|
209
|
+
: (animation.initialVelocity ?? 0);
|
|
210
|
+
return (
|
|
211
|
+
[mass, stiffness, damping, initialVelocity].every(Number.isFinite) &&
|
|
212
|
+
(!strictV2 || (mass > 0 && stiffness > 0 && damping >= 0))
|
|
213
|
+
);
|
|
149
214
|
}
|
|
150
215
|
// Keyframe frames validate inside flattenFiniteKeyframes — one traversal
|
|
151
216
|
// both checks and flattens, instead of walking every frame twice. The type
|
|
152
217
|
// check is statically always-true for the TS union but load-bearing for JS
|
|
153
218
|
// callers: an unrecognized type must reject here, or it would skip the
|
|
154
219
|
// keyframe gate entirely and hand native a null frames array.
|
|
155
|
-
return
|
|
220
|
+
return (
|
|
221
|
+
animation.type === 'keyframes' && (!strictV2 || animation.duration >= 0)
|
|
222
|
+
);
|
|
156
223
|
}
|
|
157
224
|
|
|
158
225
|
function presentationFromNative(
|
|
159
226
|
values: ReadonlyArray<number>,
|
|
160
|
-
fallback:
|
|
227
|
+
fallback: CanonicalSmoothClipPresentation,
|
|
161
228
|
offset = 0
|
|
162
|
-
):
|
|
229
|
+
): CanonicalSmoothClipPresentation {
|
|
163
230
|
'worklet';
|
|
231
|
+
if (values.length >= offset + 12) {
|
|
232
|
+
const presentation = canonicalizeClipPresentation({
|
|
233
|
+
clip: {
|
|
234
|
+
x: values[offset] as number,
|
|
235
|
+
y: values[offset + 1] as number,
|
|
236
|
+
width: values[offset + 2] as number,
|
|
237
|
+
height: values[offset + 3] as number,
|
|
238
|
+
radius: 0,
|
|
239
|
+
topLeftRadius: values[offset + 4] as number,
|
|
240
|
+
topRightRadius: values[offset + 5] as number,
|
|
241
|
+
bottomRightRadius: values[offset + 6] as number,
|
|
242
|
+
bottomLeftRadius: values[offset + 7] as number,
|
|
243
|
+
curve: values[offset + 8] === 1 ? 'continuous' : 'circular',
|
|
244
|
+
},
|
|
245
|
+
contentTranslateX: values[offset + 9] as number,
|
|
246
|
+
contentTranslateY: values[offset + 10] as number,
|
|
247
|
+
contentScale: values[offset + 11] as number,
|
|
248
|
+
});
|
|
249
|
+
return presentation ?? fallback;
|
|
250
|
+
}
|
|
164
251
|
if (values.length < offset + 7) return fallback;
|
|
165
|
-
const presentation = {
|
|
252
|
+
const presentation = canonicalizeClipPresentation({
|
|
166
253
|
clip: {
|
|
167
254
|
x: values[offset] as number,
|
|
168
255
|
y: values[offset + 1] as number,
|
|
@@ -172,8 +259,48 @@ function presentationFromNative(
|
|
|
172
259
|
},
|
|
173
260
|
contentTranslateX: values[offset + 5] as number,
|
|
174
261
|
contentTranslateY: values[offset + 6] as number,
|
|
175
|
-
};
|
|
176
|
-
return
|
|
262
|
+
});
|
|
263
|
+
return presentation ?? fallback;
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
function curveCode(presentation: CanonicalSmoothClipPresentation): number {
|
|
267
|
+
'worklet';
|
|
268
|
+
return presentation.clip.curve === 'continuous' ? 1 : 0;
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
function isV1Compatible(
|
|
272
|
+
presentation: CanonicalSmoothClipPresentation
|
|
273
|
+
): boolean {
|
|
274
|
+
'worklet';
|
|
275
|
+
const clip = presentation.clip;
|
|
276
|
+
return (
|
|
277
|
+
clip.curve === 'circular' &&
|
|
278
|
+
clip.topLeftRadius === clip.radius &&
|
|
279
|
+
clip.topRightRadius === clip.radius &&
|
|
280
|
+
clip.bottomRightRadius === clip.radius &&
|
|
281
|
+
clip.bottomLeftRadius === clip.radius &&
|
|
282
|
+
presentation.contentScale === 1
|
|
283
|
+
);
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
function springScaleIsProvablyPositive(
|
|
287
|
+
start: CanonicalSmoothClipPresentation,
|
|
288
|
+
target: CanonicalSmoothClipPresentation,
|
|
289
|
+
animation: SpringClipAnimation
|
|
290
|
+
): boolean {
|
|
291
|
+
'worklet';
|
|
292
|
+
if (start.contentScale === target.contentScale) return true;
|
|
293
|
+
|
|
294
|
+
// A zero-velocity critically/over-damped step is monotonic, so its sampled
|
|
295
|
+
// scale remains between two already-positive endpoints. Inherited or
|
|
296
|
+
// under-damped configurations can overshoot; callers must compile those
|
|
297
|
+
// plans to exact keyframes instead of risking a non-positive transform.
|
|
298
|
+
const mass = animation.mass ?? 1;
|
|
299
|
+
const stiffness = animation.stiffness ?? 100;
|
|
300
|
+
const damping = animation.damping ?? 10;
|
|
301
|
+
return (
|
|
302
|
+
animation.initialVelocity === 0 && damping * damping >= 4 * mass * stiffness
|
|
303
|
+
);
|
|
177
304
|
}
|
|
178
305
|
|
|
179
306
|
// Validates and flattens the keyframe list in one traversal (the flat number
|
|
@@ -181,49 +308,86 @@ function presentationFromNative(
|
|
|
181
308
|
// null when any frame is invalid — same rejection contract the two-pass
|
|
182
309
|
// validate-then-flatten had.
|
|
183
310
|
function flattenFiniteKeyframes(
|
|
184
|
-
target:
|
|
311
|
+
target: CanonicalSmoothClipPresentation,
|
|
185
312
|
animation: KeyframedClipAnimation
|
|
186
|
-
):
|
|
313
|
+
): {
|
|
314
|
+
frames: number[];
|
|
315
|
+
canonicalFrames: CanonicalSmoothClipPresentation[];
|
|
316
|
+
} | null {
|
|
187
317
|
'worklet';
|
|
188
318
|
if (!Number.isFinite(animation.duration) || animation.frames.length < 2) {
|
|
189
319
|
return null;
|
|
190
320
|
}
|
|
191
321
|
const values: number[] = [];
|
|
322
|
+
const canonicalFrames: CanonicalSmoothClipPresentation[] = [];
|
|
192
323
|
let previousOffset = -1;
|
|
193
324
|
for (const frame of animation.frames) {
|
|
194
|
-
const { offset
|
|
325
|
+
const { offset } = frame;
|
|
326
|
+
const presentation = canonicalizeClipPresentation(frame.presentation);
|
|
195
327
|
if (
|
|
196
328
|
!Number.isFinite(offset) ||
|
|
197
329
|
offset < 0 ||
|
|
198
330
|
offset > 1 ||
|
|
199
331
|
offset <= previousOffset ||
|
|
200
|
-
|
|
332
|
+
presentation === null ||
|
|
333
|
+
presentation.clip.curve !== target.clip.curve
|
|
201
334
|
) {
|
|
202
335
|
return null;
|
|
203
336
|
}
|
|
204
337
|
previousOffset = offset;
|
|
205
|
-
|
|
338
|
+
canonicalFrames.push(presentation);
|
|
339
|
+
const { clip, contentTranslateX, contentTranslateY, contentScale } =
|
|
340
|
+
presentation;
|
|
206
341
|
values.push(
|
|
207
342
|
offset,
|
|
208
343
|
clip.x,
|
|
209
344
|
clip.y,
|
|
210
345
|
clip.width,
|
|
211
346
|
clip.height,
|
|
212
|
-
clip.
|
|
347
|
+
clip.topLeftRadius,
|
|
348
|
+
clip.topRightRadius,
|
|
349
|
+
clip.bottomRightRadius,
|
|
350
|
+
clip.bottomLeftRadius,
|
|
351
|
+
curveCode(presentation),
|
|
213
352
|
contentTranslateX,
|
|
214
|
-
contentTranslateY
|
|
353
|
+
contentTranslateY,
|
|
354
|
+
contentScale
|
|
215
355
|
);
|
|
216
356
|
}
|
|
217
357
|
if (
|
|
218
358
|
animation.frames[0]?.offset !== 0 ||
|
|
219
359
|
previousOffset !== 1 ||
|
|
220
360
|
!clipPresentationEquals(
|
|
221
|
-
|
|
361
|
+
canonicalFrames[canonicalFrames.length - 1] ?? null,
|
|
222
362
|
target
|
|
223
363
|
)
|
|
224
364
|
) {
|
|
225
365
|
return null;
|
|
226
366
|
}
|
|
367
|
+
return { frames: values, canonicalFrames };
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
function flattenV1Keyframes(
|
|
371
|
+
frames: readonly CanonicalSmoothClipPresentation[],
|
|
372
|
+
offsets: readonly number[]
|
|
373
|
+
): number[] {
|
|
374
|
+
'worklet';
|
|
375
|
+
const values: number[] = [];
|
|
376
|
+
for (let index = 0; index < frames.length; index += 1) {
|
|
377
|
+
const presentation = frames[index];
|
|
378
|
+
const offset = offsets[index];
|
|
379
|
+
if (presentation === undefined || offset === undefined) continue;
|
|
380
|
+
values.push(
|
|
381
|
+
offset,
|
|
382
|
+
presentation.clip.x,
|
|
383
|
+
presentation.clip.y,
|
|
384
|
+
presentation.clip.width,
|
|
385
|
+
presentation.clip.height,
|
|
386
|
+
presentation.clip.radius,
|
|
387
|
+
presentation.contentTranslateX,
|
|
388
|
+
presentation.contentTranslateY
|
|
389
|
+
);
|
|
390
|
+
}
|
|
227
391
|
return values;
|
|
228
392
|
}
|
|
229
393
|
|
|
@@ -238,11 +402,18 @@ export function useSmoothClipDriver(
|
|
|
238
402
|
initialValue: ClipGeometry | SmoothClipPresentation,
|
|
239
403
|
options: SmoothClipDriverOptions = {}
|
|
240
404
|
): SmoothClipDriver {
|
|
241
|
-
const
|
|
405
|
+
const requestedInitialPresentation =
|
|
242
406
|
'clip' in initialValue
|
|
243
407
|
? initialValue
|
|
244
408
|
: createClipPresentation(initialValue);
|
|
245
|
-
const
|
|
409
|
+
const initialPresentation = canonicalizeClipPresentation(
|
|
410
|
+
requestedInitialPresentation
|
|
411
|
+
);
|
|
412
|
+
if (initialPresentation === null) {
|
|
413
|
+
throw new Error('[SmoothClipView] Initial presentation must be finite.');
|
|
414
|
+
}
|
|
415
|
+
const presentation =
|
|
416
|
+
useSharedValue<SmoothClipPresentation>(initialPresentation);
|
|
246
417
|
const ownership = useSharedValue(INTERACTIVE);
|
|
247
418
|
const suppressDeliveries = useSharedValue(0);
|
|
248
419
|
const activeAnimationId = useSharedValue(0);
|
|
@@ -270,7 +441,7 @@ export function useSmoothClipDriver(
|
|
|
270
441
|
// declarative deliveries always record, so every once-per-call channel
|
|
271
442
|
// keeps its pre-flag 'inherit' behavior.
|
|
272
443
|
const velocityTracking = options.velocityTracking === true;
|
|
273
|
-
const seedPresentation = (next:
|
|
444
|
+
const seedPresentation = (next: CanonicalSmoothClipPresentation) => {
|
|
274
445
|
'worklet';
|
|
275
446
|
if (clipPresentationEquals(presentation.value, next)) return;
|
|
276
447
|
suppressDeliveries.value += 1;
|
|
@@ -284,12 +455,16 @@ export function useSmoothClipDriver(
|
|
|
284
455
|
if (suppressDeliveries.value > 0) suppressDeliveries.value -= 1;
|
|
285
456
|
};
|
|
286
457
|
|
|
287
|
-
const beginOnUI = ():
|
|
458
|
+
const beginOnUI = (): CanonicalSmoothClipPresentation => {
|
|
288
459
|
'worklet';
|
|
289
|
-
|
|
460
|
+
const fallback =
|
|
461
|
+
canonicalizeClipPresentation(presentation.value) ?? initialPresentation;
|
|
462
|
+
if (disposed.value !== 0) return fallback;
|
|
290
463
|
const current = presentationFromNative(
|
|
291
|
-
|
|
292
|
-
|
|
464
|
+
PRESENTATION_PROTOCOL_VERSION === 2 && beginInteractionV2HostFunction
|
|
465
|
+
? beginInteractionV2HostFunction(driverId)
|
|
466
|
+
: beginInteractionHostFunction(driverId),
|
|
467
|
+
fallback
|
|
293
468
|
);
|
|
294
469
|
activeAnimationId.value = 0;
|
|
295
470
|
ownership.value = INTERACTIVE;
|
|
@@ -300,27 +475,55 @@ export function useSmoothClipDriver(
|
|
|
300
475
|
|
|
301
476
|
const setOnUI = (next: SmoothClipPresentation): void => {
|
|
302
477
|
'worklet';
|
|
303
|
-
|
|
478
|
+
const canonical = canonicalizeClipPresentation(next);
|
|
479
|
+
if (disposed.value !== 0 || canonical === null) return;
|
|
304
480
|
activeAnimationId.value = 0;
|
|
305
481
|
ownership.value = INTERACTIVE;
|
|
306
482
|
scalarsStale.value = 0;
|
|
307
|
-
const { clip, contentTranslateX, contentTranslateY } =
|
|
483
|
+
const { clip, contentTranslateX, contentTranslateY, contentScale } =
|
|
484
|
+
canonical;
|
|
308
485
|
// Always records: only the per-frame setScalars hot path is gated by
|
|
309
486
|
// velocityTracking. set() already pays full validation and a SharedValue
|
|
310
487
|
// seed per call, so the sample recording is noise here.
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
488
|
+
if (
|
|
489
|
+
PRESENTATION_PROTOCOL_VERSION === 2 &&
|
|
490
|
+
setPresentationV2HostFunction
|
|
491
|
+
) {
|
|
492
|
+
setPresentationV2HostFunction(
|
|
493
|
+
driverId,
|
|
494
|
+
clip.x,
|
|
495
|
+
clip.y,
|
|
496
|
+
clip.width,
|
|
497
|
+
clip.height,
|
|
498
|
+
clip.topLeftRadius,
|
|
499
|
+
clip.topRightRadius,
|
|
500
|
+
clip.bottomRightRadius,
|
|
501
|
+
clip.bottomLeftRadius,
|
|
502
|
+
curveCode(canonical),
|
|
503
|
+
contentTranslateX,
|
|
504
|
+
contentTranslateY,
|
|
505
|
+
contentScale,
|
|
506
|
+
true,
|
|
507
|
+
false,
|
|
508
|
+
true
|
|
509
|
+
);
|
|
510
|
+
} else if (isV1Compatible(canonical)) {
|
|
511
|
+
setPresentationHostFunction(
|
|
512
|
+
driverId,
|
|
513
|
+
clip.x,
|
|
514
|
+
clip.y,
|
|
515
|
+
clip.width,
|
|
516
|
+
clip.height,
|
|
517
|
+
clip.radius,
|
|
518
|
+
contentTranslateX,
|
|
519
|
+
contentTranslateY,
|
|
520
|
+
true,
|
|
521
|
+
false
|
|
522
|
+
);
|
|
523
|
+
} else {
|
|
524
|
+
return;
|
|
525
|
+
}
|
|
526
|
+
seedPresentation(canonical);
|
|
324
527
|
};
|
|
325
528
|
|
|
326
529
|
const setScalarsOnUI = (
|
|
@@ -379,6 +582,94 @@ export function useSmoothClipDriver(
|
|
|
379
582
|
);
|
|
380
583
|
};
|
|
381
584
|
|
|
585
|
+
const setPresentationScalarsOnUI = (
|
|
586
|
+
x: number,
|
|
587
|
+
y: number,
|
|
588
|
+
width: number,
|
|
589
|
+
height: number,
|
|
590
|
+
topLeftRadius: number,
|
|
591
|
+
topRightRadius: number,
|
|
592
|
+
bottomRightRadius: number,
|
|
593
|
+
bottomLeftRadius: number,
|
|
594
|
+
nextCurveCode: number,
|
|
595
|
+
contentTranslateX: number,
|
|
596
|
+
contentTranslateY: number,
|
|
597
|
+
contentScale: number,
|
|
598
|
+
overridePendingAnimation = false,
|
|
599
|
+
forceRecordVelocity = false
|
|
600
|
+
): void => {
|
|
601
|
+
'worklet';
|
|
602
|
+
const values = [
|
|
603
|
+
x,
|
|
604
|
+
y,
|
|
605
|
+
width,
|
|
606
|
+
height,
|
|
607
|
+
topLeftRadius,
|
|
608
|
+
topRightRadius,
|
|
609
|
+
bottomRightRadius,
|
|
610
|
+
bottomLeftRadius,
|
|
611
|
+
nextCurveCode,
|
|
612
|
+
contentTranslateX,
|
|
613
|
+
contentTranslateY,
|
|
614
|
+
contentScale,
|
|
615
|
+
];
|
|
616
|
+
if (
|
|
617
|
+
disposed.value !== 0 ||
|
|
618
|
+
!values.every(Number.isFinite) ||
|
|
619
|
+
(nextCurveCode !== 0 && nextCurveCode !== 1) ||
|
|
620
|
+
contentScale <= 0
|
|
621
|
+
) {
|
|
622
|
+
return;
|
|
623
|
+
}
|
|
624
|
+
const recordVelocity = forceRecordVelocity || velocityTracking;
|
|
625
|
+
if (
|
|
626
|
+
PRESENTATION_PROTOCOL_VERSION !== 2 ||
|
|
627
|
+
!setPresentationV2HostFunction
|
|
628
|
+
) {
|
|
629
|
+
if (
|
|
630
|
+
nextCurveCode === 0 &&
|
|
631
|
+
contentScale === 1 &&
|
|
632
|
+
topLeftRadius === topRightRadius &&
|
|
633
|
+
topLeftRadius === bottomRightRadius &&
|
|
634
|
+
topLeftRadius === bottomLeftRadius
|
|
635
|
+
) {
|
|
636
|
+
setScalarsOnUI(
|
|
637
|
+
x,
|
|
638
|
+
y,
|
|
639
|
+
width,
|
|
640
|
+
height,
|
|
641
|
+
topLeftRadius,
|
|
642
|
+
contentTranslateX,
|
|
643
|
+
contentTranslateY,
|
|
644
|
+
overridePendingAnimation,
|
|
645
|
+
forceRecordVelocity
|
|
646
|
+
);
|
|
647
|
+
}
|
|
648
|
+
return;
|
|
649
|
+
}
|
|
650
|
+
if (activeAnimationId.value !== 0) activeAnimationId.value = 0;
|
|
651
|
+
if (ownership.value !== INTERACTIVE) ownership.value = INTERACTIVE;
|
|
652
|
+
if (scalarsStale.value === 0) scalarsStale.value = 1;
|
|
653
|
+
setPresentationV2HostFunction(
|
|
654
|
+
driverId,
|
|
655
|
+
x,
|
|
656
|
+
y,
|
|
657
|
+
width,
|
|
658
|
+
height,
|
|
659
|
+
topLeftRadius,
|
|
660
|
+
topRightRadius,
|
|
661
|
+
bottomRightRadius,
|
|
662
|
+
bottomLeftRadius,
|
|
663
|
+
nextCurveCode,
|
|
664
|
+
contentTranslateX,
|
|
665
|
+
contentTranslateY,
|
|
666
|
+
contentScale,
|
|
667
|
+
true,
|
|
668
|
+
overridePendingAnimation,
|
|
669
|
+
recordVelocity
|
|
670
|
+
);
|
|
671
|
+
};
|
|
672
|
+
|
|
382
673
|
const animateOnUI = (
|
|
383
674
|
target: SmoothClipPresentation,
|
|
384
675
|
animation: SmoothClipAnimation
|
|
@@ -388,14 +679,89 @@ export function useSmoothClipDriver(
|
|
|
388
679
|
// invalid stale call cannot mint a native rejection id/completion against
|
|
389
680
|
// a driver whose listener and registry entry are already gone.
|
|
390
681
|
if (disposed.value !== 0) return 0;
|
|
391
|
-
const
|
|
682
|
+
const canonicalTarget = canonicalizeClipPresentation(target);
|
|
683
|
+
const canonicalFrom =
|
|
684
|
+
animation.from === undefined
|
|
685
|
+
? undefined
|
|
686
|
+
: canonicalizeClipPresentation(animation.from);
|
|
687
|
+
const keyframeResult =
|
|
392
688
|
animation.type === 'keyframes'
|
|
393
|
-
?
|
|
689
|
+
? canonicalTarget === null
|
|
690
|
+
? null
|
|
691
|
+
: flattenFiniteKeyframes(canonicalTarget, animation)
|
|
394
692
|
: null;
|
|
395
693
|
if (
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
(animation.type === 'keyframes' &&
|
|
694
|
+
canonicalTarget === null ||
|
|
695
|
+
(animation.from !== undefined && canonicalFrom === null) ||
|
|
696
|
+
(animation.type === 'keyframes' && keyframeResult === null)
|
|
697
|
+
) {
|
|
698
|
+
return rejectAnimationHostFunction(driverId);
|
|
699
|
+
}
|
|
700
|
+
const resolvedFrom = canonicalFrom ?? undefined;
|
|
701
|
+
const v1Compatible =
|
|
702
|
+
isV1Compatible(canonicalTarget) &&
|
|
703
|
+
(resolvedFrom === undefined || isV1Compatible(resolvedFrom)) &&
|
|
704
|
+
(animation.type !== 'keyframes' ||
|
|
705
|
+
(keyframeResult?.canonicalFrames.every(isV1Compatible) ?? false));
|
|
706
|
+
// V1-representable plans deliberately stay on the original seven-scalar
|
|
707
|
+
// bridge even when V2 is installed. Besides preserving bridge shape,
|
|
708
|
+
// this retains V1's finite-value/clamping and host-normalization rules.
|
|
709
|
+
const useV2 = !v1Compatible;
|
|
710
|
+
if (!animationIsFinite(animation, useV2)) {
|
|
711
|
+
return rejectAnimationHostFunction(driverId);
|
|
712
|
+
}
|
|
713
|
+
const hasV2Protocol =
|
|
714
|
+
PRESENTATION_PROTOCOL_VERSION === 2 &&
|
|
715
|
+
snapshotCurrentV2HostFunction !== undefined &&
|
|
716
|
+
animateTimingV2HostFunction !== undefined &&
|
|
717
|
+
animateSpringV2HostFunction !== undefined &&
|
|
718
|
+
animateKeyframesV2HostFunction !== undefined;
|
|
719
|
+
const hasAtomicFromMethod =
|
|
720
|
+
resolvedFrom === undefined ||
|
|
721
|
+
(animation.type === 'timing'
|
|
722
|
+
? animateTimingFromV2HostFunction !== undefined
|
|
723
|
+
: animation.type === 'spring'
|
|
724
|
+
? animateSpringFromV2HostFunction !== undefined
|
|
725
|
+
: animateKeyframesFromV2HostFunction !== undefined);
|
|
726
|
+
// This is intentionally before sampling or any ownership/group/
|
|
727
|
+
// presentation mutation. New JS against old native must fail closed,
|
|
728
|
+
// and an explicit V2 start must never degrade to set()+animate().
|
|
729
|
+
if (useV2 && (!hasV2Protocol || !hasAtomicFromMethod)) {
|
|
730
|
+
return rejectAnimationHostFunction(driverId);
|
|
731
|
+
}
|
|
732
|
+
if (
|
|
733
|
+
useV2 &&
|
|
734
|
+
resolvedFrom !== undefined &&
|
|
735
|
+
animation.type === 'keyframes' &&
|
|
736
|
+
!clipPresentationEquals(
|
|
737
|
+
keyframeResult?.canonicalFrames[0] ?? null,
|
|
738
|
+
resolvedFrom
|
|
739
|
+
)
|
|
740
|
+
) {
|
|
741
|
+
return rejectAnimationHostFunction(driverId);
|
|
742
|
+
}
|
|
743
|
+
const currentPresentation =
|
|
744
|
+
canonicalizeClipPresentation(presentation.value) ?? initialPresentation;
|
|
745
|
+
const sampledStart =
|
|
746
|
+
resolvedFrom ??
|
|
747
|
+
(useV2
|
|
748
|
+
? presentationFromNative(
|
|
749
|
+
snapshotCurrentV2HostFunction!(driverId),
|
|
750
|
+
currentPresentation
|
|
751
|
+
)
|
|
752
|
+
: currentPresentation);
|
|
753
|
+
// setPresentationScalars intentionally leaves the public SharedValue
|
|
754
|
+
// stale to keep the hot path allocation-free. Validate an implicit
|
|
755
|
+
// retarget against the sampled native-visible start, not that stale JS
|
|
756
|
+
// value; otherwise a streamed curve transition cannot settle natively on
|
|
757
|
+
// its new (now stable) curve.
|
|
758
|
+
if (canonicalTarget.clip.curve !== sampledStart.clip.curve) {
|
|
759
|
+
return rejectAnimationHostFunction(driverId);
|
|
760
|
+
}
|
|
761
|
+
if (
|
|
762
|
+
useV2 &&
|
|
763
|
+
animation.type === 'spring' &&
|
|
764
|
+
!springScaleIsProvablyPositive(sampledStart, canonicalTarget, animation)
|
|
399
765
|
) {
|
|
400
766
|
return rejectAnimationHostFunction(driverId);
|
|
401
767
|
}
|
|
@@ -405,8 +771,8 @@ export function useSmoothClipDriver(
|
|
|
405
771
|
// rejectAnimation, which would mint an id and a completion for a driver
|
|
406
772
|
// whose JS state is already detached. This is the "unsupported dispatch"
|
|
407
773
|
// arm of the documented 0 contract.
|
|
408
|
-
const from =
|
|
409
|
-
if (from !== undefined) {
|
|
774
|
+
const from = resolvedFrom;
|
|
775
|
+
if (from !== undefined && !useV2) {
|
|
410
776
|
// Fused hot write: exactly setScalars(from…) issued immediately
|
|
411
777
|
// before the handoff, so native's latest value — the animation
|
|
412
778
|
// start below — is the caller's explicit presentation. Also
|
|
@@ -437,12 +803,18 @@ export function useSmoothClipDriver(
|
|
|
437
803
|
const scalarsWereStale = scalarsStale.value !== 0;
|
|
438
804
|
const hasInteractiveStart =
|
|
439
805
|
ownership.value === INTERACTIVE && !scalarsWereStale;
|
|
440
|
-
const start =
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
806
|
+
const start =
|
|
807
|
+
canonicalizeClipPresentation(presentation.value) ?? initialPresentation;
|
|
808
|
+
// V1 preserves the old optimistic SharedValue ownership transition.
|
|
809
|
+
// V2 commits it only after native has atomically accepted the plan.
|
|
810
|
+
if (!useV2) {
|
|
811
|
+
ownership.value = NATIVE;
|
|
812
|
+
presentation.value = canonicalTarget;
|
|
813
|
+
scalarsStale.value = 0;
|
|
814
|
+
}
|
|
815
|
+
const dispatchStart = useV2 && from !== undefined ? from : start;
|
|
816
|
+
const startClip = dispatchStart.clip;
|
|
817
|
+
const targetClip = canonicalTarget.clip;
|
|
446
818
|
// Reanimated stamps a parallel animation's t0 on this same runtime as
|
|
447
819
|
// `__frameTimestamp || _getAnimationTimestamp()` (valueSetter.ts).
|
|
448
820
|
// Capturing the identical value here and handing it to the integrator
|
|
@@ -468,7 +840,80 @@ export function useSmoothClipDriver(
|
|
|
468
840
|
: Number.NaN);
|
|
469
841
|
let animationId: number;
|
|
470
842
|
|
|
471
|
-
if (animation.type === 'timing') {
|
|
843
|
+
if (animation.type === 'timing' && useV2) {
|
|
844
|
+
const [x1, y1, x2, y2] = animation.controlPoints;
|
|
845
|
+
animationId =
|
|
846
|
+
from !== undefined
|
|
847
|
+
? animateTimingFromV2HostFunction!(
|
|
848
|
+
driverId,
|
|
849
|
+
startClip.x,
|
|
850
|
+
startClip.y,
|
|
851
|
+
startClip.width,
|
|
852
|
+
startClip.height,
|
|
853
|
+
startClip.topLeftRadius,
|
|
854
|
+
startClip.topRightRadius,
|
|
855
|
+
startClip.bottomRightRadius,
|
|
856
|
+
startClip.bottomLeftRadius,
|
|
857
|
+
curveCode(dispatchStart),
|
|
858
|
+
dispatchStart.contentTranslateX,
|
|
859
|
+
dispatchStart.contentTranslateY,
|
|
860
|
+
dispatchStart.contentScale,
|
|
861
|
+
targetClip.x,
|
|
862
|
+
targetClip.y,
|
|
863
|
+
targetClip.width,
|
|
864
|
+
targetClip.height,
|
|
865
|
+
targetClip.topLeftRadius,
|
|
866
|
+
targetClip.topRightRadius,
|
|
867
|
+
targetClip.bottomRightRadius,
|
|
868
|
+
targetClip.bottomLeftRadius,
|
|
869
|
+
curveCode(canonicalTarget),
|
|
870
|
+
canonicalTarget.contentTranslateX,
|
|
871
|
+
canonicalTarget.contentTranslateY,
|
|
872
|
+
canonicalTarget.contentScale,
|
|
873
|
+
animation.duration,
|
|
874
|
+
x1,
|
|
875
|
+
y1,
|
|
876
|
+
x2,
|
|
877
|
+
y2,
|
|
878
|
+
reduceMotion,
|
|
879
|
+
startedAtMs
|
|
880
|
+
)
|
|
881
|
+
: animateTimingV2HostFunction!(
|
|
882
|
+
driverId,
|
|
883
|
+
hasInteractiveStart,
|
|
884
|
+
startClip.x,
|
|
885
|
+
startClip.y,
|
|
886
|
+
startClip.width,
|
|
887
|
+
startClip.height,
|
|
888
|
+
startClip.topLeftRadius,
|
|
889
|
+
startClip.topRightRadius,
|
|
890
|
+
startClip.bottomRightRadius,
|
|
891
|
+
startClip.bottomLeftRadius,
|
|
892
|
+
curveCode(dispatchStart),
|
|
893
|
+
dispatchStart.contentTranslateX,
|
|
894
|
+
dispatchStart.contentTranslateY,
|
|
895
|
+
dispatchStart.contentScale,
|
|
896
|
+
targetClip.x,
|
|
897
|
+
targetClip.y,
|
|
898
|
+
targetClip.width,
|
|
899
|
+
targetClip.height,
|
|
900
|
+
targetClip.topLeftRadius,
|
|
901
|
+
targetClip.topRightRadius,
|
|
902
|
+
targetClip.bottomRightRadius,
|
|
903
|
+
targetClip.bottomLeftRadius,
|
|
904
|
+
curveCode(canonicalTarget),
|
|
905
|
+
canonicalTarget.contentTranslateX,
|
|
906
|
+
canonicalTarget.contentTranslateY,
|
|
907
|
+
canonicalTarget.contentScale,
|
|
908
|
+
animation.duration,
|
|
909
|
+
x1,
|
|
910
|
+
y1,
|
|
911
|
+
x2,
|
|
912
|
+
y2,
|
|
913
|
+
reduceMotion,
|
|
914
|
+
startedAtMs
|
|
915
|
+
);
|
|
916
|
+
} else if (animation.type === 'timing') {
|
|
472
917
|
const [x1, y1, x2, y2] = animation.controlPoints;
|
|
473
918
|
animationId = animateTimingHostFunction(
|
|
474
919
|
driverId,
|
|
@@ -485,8 +930,8 @@ export function useSmoothClipDriver(
|
|
|
485
930
|
targetClip.width,
|
|
486
931
|
targetClip.height,
|
|
487
932
|
targetClip.radius,
|
|
488
|
-
|
|
489
|
-
|
|
933
|
+
canonicalTarget.contentTranslateX,
|
|
934
|
+
canonicalTarget.contentTranslateY,
|
|
490
935
|
Math.max(0, animation.duration),
|
|
491
936
|
x1,
|
|
492
937
|
y1,
|
|
@@ -495,6 +940,87 @@ export function useSmoothClipDriver(
|
|
|
495
940
|
reduceMotion,
|
|
496
941
|
startedAtMs
|
|
497
942
|
);
|
|
943
|
+
} else if (animation.type === 'spring' && useV2) {
|
|
944
|
+
const inheritVelocity =
|
|
945
|
+
animation.initialVelocity === undefined ||
|
|
946
|
+
animation.initialVelocity === 'inherit';
|
|
947
|
+
const mass = animation.mass ?? 1;
|
|
948
|
+
const stiffness = animation.stiffness ?? 100;
|
|
949
|
+
const damping = animation.damping ?? 10;
|
|
950
|
+
const initialVelocity = inheritVelocity
|
|
951
|
+
? 0
|
|
952
|
+
: (animation.initialVelocity as number);
|
|
953
|
+
animationId =
|
|
954
|
+
from !== undefined
|
|
955
|
+
? animateSpringFromV2HostFunction!(
|
|
956
|
+
driverId,
|
|
957
|
+
startClip.x,
|
|
958
|
+
startClip.y,
|
|
959
|
+
startClip.width,
|
|
960
|
+
startClip.height,
|
|
961
|
+
startClip.topLeftRadius,
|
|
962
|
+
startClip.topRightRadius,
|
|
963
|
+
startClip.bottomRightRadius,
|
|
964
|
+
startClip.bottomLeftRadius,
|
|
965
|
+
curveCode(dispatchStart),
|
|
966
|
+
dispatchStart.contentTranslateX,
|
|
967
|
+
dispatchStart.contentTranslateY,
|
|
968
|
+
dispatchStart.contentScale,
|
|
969
|
+
targetClip.x,
|
|
970
|
+
targetClip.y,
|
|
971
|
+
targetClip.width,
|
|
972
|
+
targetClip.height,
|
|
973
|
+
targetClip.topLeftRadius,
|
|
974
|
+
targetClip.topRightRadius,
|
|
975
|
+
targetClip.bottomRightRadius,
|
|
976
|
+
targetClip.bottomLeftRadius,
|
|
977
|
+
curveCode(canonicalTarget),
|
|
978
|
+
canonicalTarget.contentTranslateX,
|
|
979
|
+
canonicalTarget.contentTranslateY,
|
|
980
|
+
canonicalTarget.contentScale,
|
|
981
|
+
mass,
|
|
982
|
+
stiffness,
|
|
983
|
+
damping,
|
|
984
|
+
initialVelocity,
|
|
985
|
+
inheritVelocity,
|
|
986
|
+
reduceMotion,
|
|
987
|
+
startedAtMs
|
|
988
|
+
)
|
|
989
|
+
: animateSpringV2HostFunction!(
|
|
990
|
+
driverId,
|
|
991
|
+
hasInteractiveStart,
|
|
992
|
+
startClip.x,
|
|
993
|
+
startClip.y,
|
|
994
|
+
startClip.width,
|
|
995
|
+
startClip.height,
|
|
996
|
+
startClip.topLeftRadius,
|
|
997
|
+
startClip.topRightRadius,
|
|
998
|
+
startClip.bottomRightRadius,
|
|
999
|
+
startClip.bottomLeftRadius,
|
|
1000
|
+
curveCode(dispatchStart),
|
|
1001
|
+
dispatchStart.contentTranslateX,
|
|
1002
|
+
dispatchStart.contentTranslateY,
|
|
1003
|
+
dispatchStart.contentScale,
|
|
1004
|
+
targetClip.x,
|
|
1005
|
+
targetClip.y,
|
|
1006
|
+
targetClip.width,
|
|
1007
|
+
targetClip.height,
|
|
1008
|
+
targetClip.topLeftRadius,
|
|
1009
|
+
targetClip.topRightRadius,
|
|
1010
|
+
targetClip.bottomRightRadius,
|
|
1011
|
+
targetClip.bottomLeftRadius,
|
|
1012
|
+
curveCode(canonicalTarget),
|
|
1013
|
+
canonicalTarget.contentTranslateX,
|
|
1014
|
+
canonicalTarget.contentTranslateY,
|
|
1015
|
+
canonicalTarget.contentScale,
|
|
1016
|
+
mass,
|
|
1017
|
+
stiffness,
|
|
1018
|
+
damping,
|
|
1019
|
+
initialVelocity,
|
|
1020
|
+
inheritVelocity,
|
|
1021
|
+
reduceMotion,
|
|
1022
|
+
startedAtMs
|
|
1023
|
+
);
|
|
498
1024
|
} else if (animation.type === 'spring') {
|
|
499
1025
|
const inheritVelocity =
|
|
500
1026
|
animation.initialVelocity === undefined ||
|
|
@@ -514,8 +1040,8 @@ export function useSmoothClipDriver(
|
|
|
514
1040
|
targetClip.width,
|
|
515
1041
|
targetClip.height,
|
|
516
1042
|
targetClip.radius,
|
|
517
|
-
|
|
518
|
-
|
|
1043
|
+
canonicalTarget.contentTranslateX,
|
|
1044
|
+
canonicalTarget.contentTranslateY,
|
|
519
1045
|
Math.max(0.0001, animation.mass ?? 1),
|
|
520
1046
|
Math.max(0.0001, animation.stiffness ?? 100),
|
|
521
1047
|
Math.max(0, animation.damping ?? 10),
|
|
@@ -524,6 +1050,74 @@ export function useSmoothClipDriver(
|
|
|
524
1050
|
reduceMotion,
|
|
525
1051
|
startedAtMs
|
|
526
1052
|
);
|
|
1053
|
+
} else if (useV2) {
|
|
1054
|
+
const frames = (keyframeResult as NonNullable<typeof keyframeResult>)
|
|
1055
|
+
.frames;
|
|
1056
|
+
animationId =
|
|
1057
|
+
from !== undefined
|
|
1058
|
+
? animateKeyframesFromV2HostFunction!(
|
|
1059
|
+
driverId,
|
|
1060
|
+
startClip.x,
|
|
1061
|
+
startClip.y,
|
|
1062
|
+
startClip.width,
|
|
1063
|
+
startClip.height,
|
|
1064
|
+
startClip.topLeftRadius,
|
|
1065
|
+
startClip.topRightRadius,
|
|
1066
|
+
startClip.bottomRightRadius,
|
|
1067
|
+
startClip.bottomLeftRadius,
|
|
1068
|
+
curveCode(dispatchStart),
|
|
1069
|
+
dispatchStart.contentTranslateX,
|
|
1070
|
+
dispatchStart.contentTranslateY,
|
|
1071
|
+
dispatchStart.contentScale,
|
|
1072
|
+
targetClip.x,
|
|
1073
|
+
targetClip.y,
|
|
1074
|
+
targetClip.width,
|
|
1075
|
+
targetClip.height,
|
|
1076
|
+
targetClip.topLeftRadius,
|
|
1077
|
+
targetClip.topRightRadius,
|
|
1078
|
+
targetClip.bottomRightRadius,
|
|
1079
|
+
targetClip.bottomLeftRadius,
|
|
1080
|
+
curveCode(canonicalTarget),
|
|
1081
|
+
canonicalTarget.contentTranslateX,
|
|
1082
|
+
canonicalTarget.contentTranslateY,
|
|
1083
|
+
canonicalTarget.contentScale,
|
|
1084
|
+
animation.duration,
|
|
1085
|
+
frames,
|
|
1086
|
+
reduceMotion,
|
|
1087
|
+
startedAtMs
|
|
1088
|
+
)
|
|
1089
|
+
: animateKeyframesV2HostFunction!(
|
|
1090
|
+
driverId,
|
|
1091
|
+
hasInteractiveStart,
|
|
1092
|
+
startClip.x,
|
|
1093
|
+
startClip.y,
|
|
1094
|
+
startClip.width,
|
|
1095
|
+
startClip.height,
|
|
1096
|
+
startClip.topLeftRadius,
|
|
1097
|
+
startClip.topRightRadius,
|
|
1098
|
+
startClip.bottomRightRadius,
|
|
1099
|
+
startClip.bottomLeftRadius,
|
|
1100
|
+
curveCode(dispatchStart),
|
|
1101
|
+
dispatchStart.contentTranslateX,
|
|
1102
|
+
dispatchStart.contentTranslateY,
|
|
1103
|
+
dispatchStart.contentScale,
|
|
1104
|
+
targetClip.x,
|
|
1105
|
+
targetClip.y,
|
|
1106
|
+
targetClip.width,
|
|
1107
|
+
targetClip.height,
|
|
1108
|
+
targetClip.topLeftRadius,
|
|
1109
|
+
targetClip.topRightRadius,
|
|
1110
|
+
targetClip.bottomRightRadius,
|
|
1111
|
+
targetClip.bottomLeftRadius,
|
|
1112
|
+
curveCode(canonicalTarget),
|
|
1113
|
+
canonicalTarget.contentTranslateX,
|
|
1114
|
+
canonicalTarget.contentTranslateY,
|
|
1115
|
+
canonicalTarget.contentScale,
|
|
1116
|
+
animation.duration,
|
|
1117
|
+
frames,
|
|
1118
|
+
reduceMotion,
|
|
1119
|
+
startedAtMs
|
|
1120
|
+
);
|
|
527
1121
|
} else {
|
|
528
1122
|
animationId = animateKeyframesHostFunction(
|
|
529
1123
|
driverId,
|
|
@@ -540,12 +1134,16 @@ export function useSmoothClipDriver(
|
|
|
540
1134
|
targetClip.width,
|
|
541
1135
|
targetClip.height,
|
|
542
1136
|
targetClip.radius,
|
|
543
|
-
|
|
544
|
-
|
|
1137
|
+
canonicalTarget.contentTranslateX,
|
|
1138
|
+
canonicalTarget.contentTranslateY,
|
|
545
1139
|
Math.max(0, animation.duration),
|
|
546
1140
|
// Non-null here: the validation gate above rejected null before any
|
|
547
1141
|
// side effect.
|
|
548
|
-
|
|
1142
|
+
flattenV1Keyframes(
|
|
1143
|
+
(keyframeResult as NonNullable<typeof keyframeResult>)
|
|
1144
|
+
.canonicalFrames,
|
|
1145
|
+
animation.frames.map((frame) => frame.offset)
|
|
1146
|
+
),
|
|
549
1147
|
reduceMotion,
|
|
550
1148
|
startedAtMs
|
|
551
1149
|
);
|
|
@@ -559,12 +1157,19 @@ export function useSmoothClipDriver(
|
|
|
559
1157
|
// effect, with a fresh id and one finished:false completion once the
|
|
560
1158
|
// native entry exists — in the pre-seed window rejectAnimation has no
|
|
561
1159
|
// entry and returns the bare 0 sentinel with no completion instead.
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
1160
|
+
if (!useV2) {
|
|
1161
|
+
ownership.value = INTERACTIVE;
|
|
1162
|
+
presentation.value = start;
|
|
1163
|
+
if (scalarsWereStale) scalarsStale.value = 1;
|
|
1164
|
+
activeAnimationId.value = 0;
|
|
1165
|
+
}
|
|
566
1166
|
return rejectAnimationHostFunction(driverId);
|
|
567
1167
|
}
|
|
1168
|
+
if (useV2) {
|
|
1169
|
+
ownership.value = NATIVE;
|
|
1170
|
+
presentation.value = canonicalTarget;
|
|
1171
|
+
scalarsStale.value = 0;
|
|
1172
|
+
}
|
|
568
1173
|
activeAnimationId.value = animationId;
|
|
569
1174
|
return animationId;
|
|
570
1175
|
};
|
|
@@ -572,19 +1177,28 @@ export function useSmoothClipDriver(
|
|
|
572
1177
|
const cancelOnUI = (
|
|
573
1178
|
animationId = 0,
|
|
574
1179
|
behavior: 'current' | 'target' = 'current'
|
|
575
|
-
):
|
|
1180
|
+
): CanonicalSmoothClipPresentation => {
|
|
576
1181
|
'worklet';
|
|
577
1182
|
// Past the hook's cleanup the native entry is gone; the call would fail
|
|
578
1183
|
// defined (handled=false) but it is the last driver.ui path that still
|
|
579
1184
|
// crosses into native after the tombstone. Guard it like the rest.
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
1185
|
+
const fallback =
|
|
1186
|
+
canonicalizeClipPresentation(presentation.value) ?? initialPresentation;
|
|
1187
|
+
if (disposed.value !== 0) return fallback;
|
|
1188
|
+
const values =
|
|
1189
|
+
PRESENTATION_PROTOCOL_VERSION === 2 && cancelAnimationV2HostFunction
|
|
1190
|
+
? cancelAnimationV2HostFunction(
|
|
1191
|
+
driverId,
|
|
1192
|
+
animationId,
|
|
1193
|
+
behavior === 'target' ? 1 : 0
|
|
1194
|
+
)
|
|
1195
|
+
: cancelAnimationHostFunction(
|
|
1196
|
+
driverId,
|
|
1197
|
+
animationId,
|
|
1198
|
+
behavior === 'target' ? 1 : 0
|
|
1199
|
+
);
|
|
1200
|
+
if (values.length < 8 || values[0] !== 1) return fallback;
|
|
1201
|
+
const current = presentationFromNative(values, fallback, 1);
|
|
588
1202
|
activeAnimationId.value = 0;
|
|
589
1203
|
ownership.value = INTERACTIVE;
|
|
590
1204
|
scalarsStale.value = 0;
|
|
@@ -627,6 +1241,37 @@ export function useSmoothClipDriver(
|
|
|
627
1241
|
contentTranslateY
|
|
628
1242
|
);
|
|
629
1243
|
},
|
|
1244
|
+
setPresentationScalars(
|
|
1245
|
+
x,
|
|
1246
|
+
y,
|
|
1247
|
+
width,
|
|
1248
|
+
height,
|
|
1249
|
+
topLeftRadius,
|
|
1250
|
+
topRightRadius,
|
|
1251
|
+
bottomRightRadius,
|
|
1252
|
+
bottomLeftRadius,
|
|
1253
|
+
nextCurveCode,
|
|
1254
|
+
contentTranslateX,
|
|
1255
|
+
contentTranslateY,
|
|
1256
|
+
contentScale
|
|
1257
|
+
) {
|
|
1258
|
+
'worklet';
|
|
1259
|
+
if (isRNRuntime()) return uiOnly();
|
|
1260
|
+
setPresentationScalarsOnUI(
|
|
1261
|
+
x,
|
|
1262
|
+
y,
|
|
1263
|
+
width,
|
|
1264
|
+
height,
|
|
1265
|
+
topLeftRadius,
|
|
1266
|
+
topRightRadius,
|
|
1267
|
+
bottomRightRadius,
|
|
1268
|
+
bottomLeftRadius,
|
|
1269
|
+
nextCurveCode,
|
|
1270
|
+
contentTranslateX,
|
|
1271
|
+
contentTranslateY,
|
|
1272
|
+
contentScale
|
|
1273
|
+
);
|
|
1274
|
+
},
|
|
630
1275
|
animateTo(target, animation) {
|
|
631
1276
|
'worklet';
|
|
632
1277
|
if (isRNRuntime()) return uiOnly();
|
|
@@ -641,7 +1286,7 @@ export function useSmoothClipDriver(
|
|
|
641
1286
|
react: {
|
|
642
1287
|
beginInteraction() {
|
|
643
1288
|
const { requestId, promise } =
|
|
644
|
-
createReactRequest<
|
|
1289
|
+
createReactRequest<CanonicalSmoothClipPresentation>(driverId);
|
|
645
1290
|
scheduleOnUI(() => {
|
|
646
1291
|
'worklet';
|
|
647
1292
|
const result = beginOnUI();
|
|
@@ -688,7 +1333,7 @@ export function useSmoothClipDriver(
|
|
|
688
1333
|
},
|
|
689
1334
|
cancel(animationId = 0, behavior = 'current') {
|
|
690
1335
|
const { requestId, promise } =
|
|
691
|
-
createReactRequest<
|
|
1336
|
+
createReactRequest<CanonicalSmoothClipPresentation>(driverId, true);
|
|
692
1337
|
scheduleOnUI(() => {
|
|
693
1338
|
'worklet';
|
|
694
1339
|
const result = cancelOnUI(animationId, behavior);
|
|
@@ -703,6 +1348,13 @@ export function useSmoothClipDriver(
|
|
|
703
1348
|
return promise;
|
|
704
1349
|
},
|
|
705
1350
|
},
|
|
1351
|
+
__smoothClipHandle: {
|
|
1352
|
+
driverId,
|
|
1353
|
+
presentation,
|
|
1354
|
+
ownership,
|
|
1355
|
+
activeAnimationId,
|
|
1356
|
+
disposed,
|
|
1357
|
+
},
|
|
706
1358
|
};
|
|
707
1359
|
|
|
708
1360
|
setDriverState(
|
|
@@ -754,7 +1406,9 @@ export function useSmoothClipDriver(
|
|
|
754
1406
|
active: SharedValue<number>,
|
|
755
1407
|
stale: SharedValue<number>,
|
|
756
1408
|
gone: SharedValue<number>,
|
|
757
|
-
setter: typeof setPresentationHostFunction
|
|
1409
|
+
setter: typeof setPresentationHostFunction,
|
|
1410
|
+
setterV2: typeof setPresentationV2HostFunction,
|
|
1411
|
+
protocolVersion: number
|
|
758
1412
|
) => {
|
|
759
1413
|
'worklet';
|
|
760
1414
|
// First, before the listener or the seed: this effect run owns the
|
|
@@ -763,10 +1417,8 @@ export function useSmoothClipDriver(
|
|
|
763
1417
|
gone.value = 0;
|
|
764
1418
|
let last: SmoothClipPresentation | null = null;
|
|
765
1419
|
const deliver = (next: SmoothClipPresentation) => {
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
clipPresentationEquals(last, next)
|
|
769
|
-
) {
|
|
1420
|
+
const canonical = canonicalizeClipPresentation(next);
|
|
1421
|
+
if (canonical === null || clipPresentationEquals(last, canonical)) {
|
|
770
1422
|
return;
|
|
771
1423
|
}
|
|
772
1424
|
// Record `last` only for values native has actually observed:
|
|
@@ -775,26 +1427,51 @@ export function useSmoothClipDriver(
|
|
|
775
1427
|
if (owner.value !== INTERACTIVE) return;
|
|
776
1428
|
if (suppressed.value > 0) {
|
|
777
1429
|
suppressed.value -= 1;
|
|
778
|
-
last =
|
|
1430
|
+
last = canonical;
|
|
1431
|
+
return;
|
|
1432
|
+
}
|
|
1433
|
+
if (protocolVersion !== 2 && !isV1Compatible(canonical)) {
|
|
779
1434
|
return;
|
|
780
1435
|
}
|
|
781
|
-
last =
|
|
1436
|
+
last = canonical;
|
|
782
1437
|
if (stale.value !== 0) stale.value = 0;
|
|
783
|
-
const { clip, contentTranslateX, contentTranslateY } =
|
|
1438
|
+
const { clip, contentTranslateX, contentTranslateY, contentScale } =
|
|
1439
|
+
canonical;
|
|
784
1440
|
// Declarative deliveries always record velocity samples — only the
|
|
785
1441
|
// setScalars hot path is gated by the velocityTracking option.
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
1442
|
+
if (protocolVersion === 2 && setterV2) {
|
|
1443
|
+
setterV2(
|
|
1444
|
+
nativeDriverId,
|
|
1445
|
+
clip.x,
|
|
1446
|
+
clip.y,
|
|
1447
|
+
clip.width,
|
|
1448
|
+
clip.height,
|
|
1449
|
+
clip.topLeftRadius,
|
|
1450
|
+
clip.topRightRadius,
|
|
1451
|
+
clip.bottomRightRadius,
|
|
1452
|
+
clip.bottomLeftRadius,
|
|
1453
|
+
curveCode(canonical),
|
|
1454
|
+
contentTranslateX,
|
|
1455
|
+
contentTranslateY,
|
|
1456
|
+
contentScale,
|
|
1457
|
+
false,
|
|
1458
|
+
false,
|
|
1459
|
+
true
|
|
1460
|
+
);
|
|
1461
|
+
} else {
|
|
1462
|
+
setter(
|
|
1463
|
+
nativeDriverId,
|
|
1464
|
+
clip.x,
|
|
1465
|
+
clip.y,
|
|
1466
|
+
clip.width,
|
|
1467
|
+
clip.height,
|
|
1468
|
+
clip.radius,
|
|
1469
|
+
contentTranslateX,
|
|
1470
|
+
contentTranslateY,
|
|
1471
|
+
false,
|
|
1472
|
+
false
|
|
1473
|
+
);
|
|
1474
|
+
}
|
|
798
1475
|
};
|
|
799
1476
|
source.addListener(listenerId, deliver);
|
|
800
1477
|
// Authoritative take-ownership seed. Creates the native entry before
|
|
@@ -803,24 +1480,45 @@ export function useSmoothClipDriver(
|
|
|
803
1480
|
// An animation worklet can win the scheduling race and create a latch
|
|
804
1481
|
// first; Native ownership then marks that intent as newer, so this
|
|
805
1482
|
// passive seed must not clear its active id or replay the target value.
|
|
806
|
-
const current = source.value;
|
|
807
|
-
if (owner.value === INTERACTIVE &&
|
|
1483
|
+
const current = canonicalizeClipPresentation(source.value);
|
|
1484
|
+
if (owner.value === INTERACTIVE && current !== null) {
|
|
808
1485
|
active.value = 0;
|
|
809
1486
|
owner.value = INTERACTIVE;
|
|
810
1487
|
stale.value = 0;
|
|
811
1488
|
last = current;
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
1489
|
+
if (protocolVersion === 2 && setterV2) {
|
|
1490
|
+
setterV2(
|
|
1491
|
+
nativeDriverId,
|
|
1492
|
+
current.clip.x,
|
|
1493
|
+
current.clip.y,
|
|
1494
|
+
current.clip.width,
|
|
1495
|
+
current.clip.height,
|
|
1496
|
+
current.clip.topLeftRadius,
|
|
1497
|
+
current.clip.topRightRadius,
|
|
1498
|
+
current.clip.bottomRightRadius,
|
|
1499
|
+
current.clip.bottomLeftRadius,
|
|
1500
|
+
curveCode(current),
|
|
1501
|
+
current.contentTranslateX,
|
|
1502
|
+
current.contentTranslateY,
|
|
1503
|
+
current.contentScale,
|
|
1504
|
+
true,
|
|
1505
|
+
false,
|
|
1506
|
+
true
|
|
1507
|
+
);
|
|
1508
|
+
} else if (isV1Compatible(current)) {
|
|
1509
|
+
setter(
|
|
1510
|
+
nativeDriverId,
|
|
1511
|
+
current.clip.x,
|
|
1512
|
+
current.clip.y,
|
|
1513
|
+
current.clip.width,
|
|
1514
|
+
current.clip.height,
|
|
1515
|
+
current.clip.radius,
|
|
1516
|
+
current.contentTranslateX,
|
|
1517
|
+
current.contentTranslateY,
|
|
1518
|
+
true,
|
|
1519
|
+
false
|
|
1520
|
+
);
|
|
1521
|
+
}
|
|
824
1522
|
}
|
|
825
1523
|
},
|
|
826
1524
|
presentation,
|
|
@@ -831,7 +1529,9 @@ export function useSmoothClipDriver(
|
|
|
831
1529
|
activeAnimationId,
|
|
832
1530
|
scalarsStale,
|
|
833
1531
|
disposed,
|
|
834
|
-
setPresentationHostFunction
|
|
1532
|
+
setPresentationHostFunction,
|
|
1533
|
+
setPresentationV2HostFunction,
|
|
1534
|
+
PRESENTATION_PROTOCOL_VERSION
|
|
835
1535
|
);
|
|
836
1536
|
|
|
837
1537
|
return () => {
|