react-native-smooth-clip-view 0.3.0 → 0.4.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 +132 -388
- package/android/build.gradle +3 -3
- package/android/proguard-rules.pro +2 -2
- package/android/src/main/cpp/SmoothClipAndroid.h +9 -12
- package/android/src/main/cpp/SmoothClipBindings.cpp +300 -704
- package/android/src/main/cpp/SmoothClipRegistry.cpp +348 -594
- package/android/src/main/java/com/smoothclipview/ClipGeometryNormalizer.kt +36 -227
- package/android/src/main/java/com/smoothclipview/SmoothClipBindings.kt +16 -19
- package/android/src/main/java/com/smoothclipview/SmoothClipModule.kt +36 -294
- package/android/src/main/java/com/smoothclipview/SmoothClipView.kt +344 -488
- package/android/src/main/java/com/smoothclipview/SmoothClipViewManager.kt +75 -77
- package/cpp/SmoothClipAnimationCurve.h +237 -346
- package/cpp/SmoothClipRegistry.h +24 -52
- package/cpp/SmoothClipSharedGeometry.h +64 -94
- package/cpp/SmoothClipVelocityTracker.h +5 -5
- package/ios/SmoothClipGeometry.h +23 -34
- package/ios/SmoothClipRegistry.mm +206 -711
- package/ios/SmoothClipTurboModule.cpp +217 -715
- package/ios/SmoothClipTurboModule.h +54 -297
- package/ios/SmoothClipView.mm +599 -505
- package/ios/SmoothClipViewRegistry.h +2 -7
- package/lib/module/NativeSmoothClipModule.js.map +1 -1
- package/lib/module/SmoothClipView.ios.js +84 -17
- package/lib/module/SmoothClipView.ios.js.map +1 -1
- package/lib/module/SmoothClipView.js +1 -1
- package/lib/module/SmoothClipView.js.map +1 -1
- package/lib/module/SmoothClipViewNativeComponent.ts +20 -26
- package/lib/module/capabilities.native.js +1 -19
- package/lib/module/capabilities.native.js.map +1 -1
- package/lib/module/capabilityTypes.js +0 -9
- package/lib/module/capabilityTypes.js.map +1 -1
- package/lib/module/controllerInternals.js +28 -0
- package/lib/module/controllerInternals.js.map +1 -0
- package/lib/module/controllerLifecycle.js +9 -0
- package/lib/module/controllerLifecycle.js.map +1 -0
- package/lib/module/controllerTypes.js +4 -0
- package/lib/module/controllerTypes.js.map +1 -0
- package/lib/module/controllers.android.js +4 -0
- package/lib/module/controllers.android.js.map +1 -0
- package/lib/module/controllers.ios.js +4 -0
- package/lib/module/controllers.ios.js.map +1 -0
- package/lib/module/controllers.js +4 -0
- package/lib/module/controllers.js.map +1 -0
- package/lib/module/controllers.native.js +89 -0
- package/lib/module/controllers.native.js.map +1 -0
- package/lib/module/geometry.js +71 -51
- package/lib/module/geometry.js.map +1 -1
- package/lib/module/groupTypes.js +4 -0
- package/lib/module/{groupDriverTypes.js.map → groupTypes.js.map} +1 -1
- package/lib/module/groups.android.js +4 -0
- package/lib/module/groups.android.js.map +1 -0
- package/lib/module/groups.ios.js +4 -0
- package/lib/module/groups.ios.js.map +1 -0
- package/lib/module/groups.js +4 -0
- package/lib/module/groups.js.map +1 -0
- package/lib/module/groups.native.js +399 -0
- package/lib/module/groups.native.js.map +1 -0
- package/lib/module/ids.js +8 -0
- package/lib/module/ids.js.map +1 -0
- package/lib/module/index.js +3 -3
- package/lib/module/index.js.map +1 -1
- package/lib/module/nativeCompletion.js +37 -16
- package/lib/module/nativeCompletion.js.map +1 -1
- package/lib/module/presentationCodec.js +81 -0
- package/lib/module/presentationCodec.js.map +1 -0
- package/lib/typescript/src/NativeSmoothClipModule.d.ts +14 -23
- package/lib/typescript/src/NativeSmoothClipModule.d.ts.map +1 -1
- package/lib/typescript/src/SmoothClipView.d.ts +1 -1
- package/lib/typescript/src/SmoothClipView.d.ts.map +1 -1
- package/lib/typescript/src/SmoothClipView.ios.d.ts +18 -14
- package/lib/typescript/src/SmoothClipView.ios.d.ts.map +1 -1
- package/lib/typescript/src/SmoothClipViewNativeComponent.d.ts +10 -5
- package/lib/typescript/src/SmoothClipViewNativeComponent.d.ts.map +1 -1
- package/lib/typescript/src/capabilities.native.d.ts +1 -1
- package/lib/typescript/src/capabilities.native.d.ts.map +1 -1
- package/lib/typescript/src/capabilityTypes.d.ts +0 -6
- package/lib/typescript/src/capabilityTypes.d.ts.map +1 -1
- package/lib/typescript/src/controllerInternals.d.ts +14 -0
- package/lib/typescript/src/controllerInternals.d.ts.map +1 -0
- package/lib/typescript/src/controllerLifecycle.d.ts +3 -0
- package/lib/typescript/src/controllerLifecycle.d.ts.map +1 -0
- package/lib/typescript/src/controllerTypes.d.ts +62 -0
- package/lib/typescript/src/controllerTypes.d.ts.map +1 -0
- package/lib/typescript/src/controllers.android.d.ts +2 -0
- package/lib/typescript/src/controllers.android.d.ts.map +1 -0
- package/lib/typescript/src/controllers.d.ts +2 -0
- package/lib/typescript/src/controllers.d.ts.map +1 -0
- package/lib/typescript/src/controllers.ios.d.ts +2 -0
- package/lib/typescript/src/controllers.ios.d.ts.map +1 -0
- package/lib/typescript/src/controllers.native.d.ts +3 -0
- package/lib/typescript/src/controllers.native.d.ts.map +1 -0
- package/lib/typescript/src/geometry.d.ts +22 -12
- package/lib/typescript/src/geometry.d.ts.map +1 -1
- package/lib/typescript/src/groupTypes.d.ts +31 -0
- package/lib/typescript/src/groupTypes.d.ts.map +1 -0
- package/lib/typescript/src/groups.android.d.ts +2 -0
- package/lib/typescript/src/groups.android.d.ts.map +1 -0
- package/lib/typescript/src/groups.d.ts +2 -0
- package/lib/typescript/src/groups.d.ts.map +1 -0
- package/lib/typescript/src/groups.ios.d.ts +2 -0
- package/lib/typescript/src/groups.ios.d.ts.map +1 -0
- package/lib/typescript/src/groups.native.d.ts +3 -0
- package/lib/typescript/src/groups.native.d.ts.map +1 -0
- package/lib/typescript/src/ids.d.ts +2 -0
- package/lib/typescript/src/ids.d.ts.map +1 -0
- package/lib/typescript/src/index.d.ts +6 -6
- package/lib/typescript/src/index.d.ts.map +1 -1
- package/lib/typescript/src/nativeCompletion.d.ts +16 -6
- package/lib/typescript/src/nativeCompletion.d.ts.map +1 -1
- package/lib/typescript/src/presentationCodec.d.ts +10 -0
- package/lib/typescript/src/presentationCodec.d.ts.map +1 -0
- package/package.json +8 -3
- package/src/NativeSmoothClipModule.ts +41 -292
- package/src/SmoothClipView.ios.tsx +130 -23
- package/src/SmoothClipView.tsx +5 -1
- package/src/SmoothClipViewNativeComponent.ts +20 -26
- package/src/capabilities.native.ts +2 -52
- package/src/capabilityTypes.ts +0 -14
- package/src/controllerInternals.ts +52 -0
- package/src/controllerLifecycle.ts +6 -0
- package/src/controllerTypes.ts +87 -0
- package/src/controllers.android.ts +1 -0
- package/src/controllers.ios.ts +1 -0
- package/src/controllers.native.ts +104 -0
- package/src/controllers.ts +1 -0
- package/src/geometry.ts +118 -74
- package/src/groupTypes.ts +53 -0
- package/src/groups.android.ts +1 -0
- package/src/groups.ios.ts +1 -0
- package/src/groups.native.ts +604 -0
- package/src/groups.ts +1 -0
- package/src/ids.ts +6 -0
- package/src/index.ts +20 -28
- package/src/nativeCompletion.ts +67 -32
- package/src/presentationCodec.ts +134 -0
- package/lib/module/driverState.js +0 -82
- package/lib/module/driverState.js.map +0 -1
- package/lib/module/driverTypes.js +0 -4
- package/lib/module/driverTypes.js.map +0 -1
- package/lib/module/drivers.android.js +0 -6
- package/lib/module/drivers.android.js.map +0 -1
- package/lib/module/drivers.ios.js +0 -6
- package/lib/module/drivers.ios.js.map +0 -1
- package/lib/module/drivers.js +0 -4
- package/lib/module/drivers.js.map +0 -1
- package/lib/module/drivers.native.js +0 -756
- package/lib/module/drivers.native.js.map +0 -1
- package/lib/module/groupDriverTypes.js +0 -4
- package/lib/module/groupDrivers.android.js +0 -4
- package/lib/module/groupDrivers.android.js.map +0 -1
- package/lib/module/groupDrivers.ios.js +0 -4
- package/lib/module/groupDrivers.ios.js.map +0 -1
- package/lib/module/groupDrivers.js +0 -4
- package/lib/module/groupDrivers.js.map +0 -1
- package/lib/module/groupDrivers.native.js +0 -799
- package/lib/module/groupDrivers.native.js.map +0 -1
- package/lib/module/presentationProtocol.js +0 -15
- package/lib/module/presentationProtocol.js.map +0 -1
- package/lib/module/reactRequests.js +0 -56
- package/lib/module/reactRequests.js.map +0 -1
- package/lib/typescript/src/driverState.d.ts +0 -26
- package/lib/typescript/src/driverState.d.ts.map +0 -1
- package/lib/typescript/src/driverTypes.d.ts +0 -121
- package/lib/typescript/src/driverTypes.d.ts.map +0 -1
- package/lib/typescript/src/drivers.android.d.ts +0 -3
- package/lib/typescript/src/drivers.android.d.ts.map +0 -1
- package/lib/typescript/src/drivers.d.ts +0 -3
- package/lib/typescript/src/drivers.d.ts.map +0 -1
- package/lib/typescript/src/drivers.ios.d.ts +0 -3
- package/lib/typescript/src/drivers.ios.d.ts.map +0 -1
- package/lib/typescript/src/drivers.native.d.ts +0 -5
- package/lib/typescript/src/drivers.native.d.ts.map +0 -1
- package/lib/typescript/src/groupDriverTypes.d.ts +0 -66
- package/lib/typescript/src/groupDriverTypes.d.ts.map +0 -1
- package/lib/typescript/src/groupDrivers.android.d.ts +0 -2
- package/lib/typescript/src/groupDrivers.android.d.ts.map +0 -1
- package/lib/typescript/src/groupDrivers.d.ts +0 -2
- package/lib/typescript/src/groupDrivers.d.ts.map +0 -1
- package/lib/typescript/src/groupDrivers.ios.d.ts +0 -2
- package/lib/typescript/src/groupDrivers.ios.d.ts.map +0 -1
- package/lib/typescript/src/groupDrivers.native.d.ts +0 -4
- package/lib/typescript/src/groupDrivers.native.d.ts.map +0 -1
- package/lib/typescript/src/presentationProtocol.d.ts +0 -4
- package/lib/typescript/src/presentationProtocol.d.ts.map +0 -1
- package/lib/typescript/src/reactRequests.d.ts +0 -9
- package/lib/typescript/src/reactRequests.d.ts.map +0 -1
- package/src/driverState.ts +0 -118
- package/src/driverTypes.ts +0 -171
- package/src/drivers.android.ts +0 -8
- package/src/drivers.ios.ts +0 -8
- package/src/drivers.native.ts +0 -1599
- package/src/drivers.ts +0 -6
- package/src/groupDriverTypes.ts +0 -117
- package/src/groupDrivers.android.ts +0 -1
- package/src/groupDrivers.ios.ts +0 -1
- package/src/groupDrivers.native.ts +0 -1189
- package/src/groupDrivers.ts +0 -1
- package/src/presentationProtocol.ts +0 -28
- package/src/reactRequests.ts +0 -76
|
@@ -1,799 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
|
|
3
|
-
import { useEffect, useRef } from 'react';
|
|
4
|
-
import { Platform } from 'react-native';
|
|
5
|
-
import { useSharedValue } from 'react-native-reanimated';
|
|
6
|
-
import { isRNRuntime, scheduleOnRN, scheduleOnUI } from 'react-native-worklets';
|
|
7
|
-
import NativeSmoothClipModule from './smoothClipNative';
|
|
8
|
-
import { getSmoothClipCapabilities } from './capabilities';
|
|
9
|
-
import { allocateDriverId } from "./driverState.js";
|
|
10
|
-
import { canonicalizeClipPresentation, clipPresentationEquals } from "./geometry.js";
|
|
11
|
-
const INTERACTIVE = 0;
|
|
12
|
-
const NATIVE = 1;
|
|
13
|
-
const PRESENTATION_STRIDE = 12;
|
|
14
|
-
const SNAPSHOT_STRIDE = 13;
|
|
15
|
-
const MOTION_ENTRY_STRIDE = 26;
|
|
16
|
-
const NEEDS_START_STAMP = Platform.OS === 'android';
|
|
17
|
-
const GROUPS_SUPPORTED = getSmoothClipCapabilities().groups;
|
|
18
|
-
const nativeGroups = NativeSmoothClipModule;
|
|
19
|
-
const beginGroupInteractionV2HostFunction = nativeGroups.beginGroupInteractionV2;
|
|
20
|
-
const snapshotGroupV2HostFunction = nativeGroups.snapshotGroupV2;
|
|
21
|
-
const setClipPresentationBatchV2HostFunction = nativeGroups.setClipPresentationBatchV2;
|
|
22
|
-
const animateTimingGroupV2HostFunction = nativeGroups.animateTimingGroupV2;
|
|
23
|
-
const animateSpringGroupV2HostFunction = nativeGroups.animateSpringGroupV2;
|
|
24
|
-
const animateKeyframesGroupV2HostFunction = nativeGroups.animateKeyframesGroupV2;
|
|
25
|
-
const cancelAnimationGroupV2HostFunction = nativeGroups.cancelAnimationGroupV2;
|
|
26
|
-
const nativeGroupDriverStates = new Map();
|
|
27
|
-
function deliverNativeGroupCompletion(controllerId, groupId, finished) {
|
|
28
|
-
const state = nativeGroupDriverStates.get(controllerId);
|
|
29
|
-
if (!state) return;
|
|
30
|
-
const result = {
|
|
31
|
-
groupId,
|
|
32
|
-
finished
|
|
33
|
-
};
|
|
34
|
-
if (state.completionDeferrals > 0) {
|
|
35
|
-
state.deferredCompletions.push(result);
|
|
36
|
-
return;
|
|
37
|
-
}
|
|
38
|
-
state.callbackRef.current?.(result);
|
|
39
|
-
}
|
|
40
|
-
function deferNativeGroupCompletions(controllerId) {
|
|
41
|
-
const state = nativeGroupDriverStates.get(controllerId);
|
|
42
|
-
if (state) state.completionDeferrals += 1;
|
|
43
|
-
}
|
|
44
|
-
function releaseNativeGroupCompletions(controllerId) {
|
|
45
|
-
const state = nativeGroupDriverStates.get(controllerId);
|
|
46
|
-
if (!state || state.completionDeferrals === 0) return;
|
|
47
|
-
state.completionDeferrals -= 1;
|
|
48
|
-
if (state.completionDeferrals !== 0) return;
|
|
49
|
-
const deferred = state.deferredCompletions.splice(0);
|
|
50
|
-
for (const result of deferred) state.callbackRef.current?.(result);
|
|
51
|
-
}
|
|
52
|
-
function runtimeGroupRecords() {
|
|
53
|
-
'worklet';
|
|
54
|
-
|
|
55
|
-
const runtime = globalThis;
|
|
56
|
-
runtime.__smoothClipGroupRecords ??= {};
|
|
57
|
-
return runtime.__smoothClipGroupRecords;
|
|
58
|
-
}
|
|
59
|
-
function fail(message) {
|
|
60
|
-
'worklet';
|
|
61
|
-
|
|
62
|
-
throw new Error(`[SmoothClipView] ${message}`);
|
|
63
|
-
}
|
|
64
|
-
function uiOnly() {
|
|
65
|
-
'worklet';
|
|
66
|
-
|
|
67
|
-
return fail('group.ui methods must run on the UI runtime. Use group.react from React code.');
|
|
68
|
-
}
|
|
69
|
-
function curveCode(presentation) {
|
|
70
|
-
'worklet';
|
|
71
|
-
|
|
72
|
-
return presentation.clip.curve === 'continuous' ? 1 : 0;
|
|
73
|
-
}
|
|
74
|
-
function appendPresentation(values, presentation) {
|
|
75
|
-
'worklet';
|
|
76
|
-
|
|
77
|
-
const {
|
|
78
|
-
clip,
|
|
79
|
-
contentTranslateX,
|
|
80
|
-
contentTranslateY,
|
|
81
|
-
contentScale
|
|
82
|
-
} = presentation;
|
|
83
|
-
values.push(clip.x, clip.y, clip.width, clip.height, clip.topLeftRadius, clip.topRightRadius, clip.bottomRightRadius, clip.bottomLeftRadius, curveCode(presentation), contentTranslateX, contentTranslateY, contentScale);
|
|
84
|
-
}
|
|
85
|
-
function presentationFromValues(values, offset) {
|
|
86
|
-
'worklet';
|
|
87
|
-
|
|
88
|
-
if (values.length < offset + PRESENTATION_STRIDE) return null;
|
|
89
|
-
return canonicalizeClipPresentation({
|
|
90
|
-
clip: {
|
|
91
|
-
x: values[offset],
|
|
92
|
-
y: values[offset + 1],
|
|
93
|
-
width: values[offset + 2],
|
|
94
|
-
height: values[offset + 3],
|
|
95
|
-
radius: 0,
|
|
96
|
-
topLeftRadius: values[offset + 4],
|
|
97
|
-
topRightRadius: values[offset + 5],
|
|
98
|
-
bottomRightRadius: values[offset + 6],
|
|
99
|
-
bottomLeftRadius: values[offset + 7],
|
|
100
|
-
curve: values[offset + 8] === 1 ? 'continuous' : 'circular'
|
|
101
|
-
},
|
|
102
|
-
contentTranslateX: values[offset + 9],
|
|
103
|
-
contentTranslateY: values[offset + 10],
|
|
104
|
-
contentScale: values[offset + 11]
|
|
105
|
-
});
|
|
106
|
-
}
|
|
107
|
-
function validateDrivers(drivers) {
|
|
108
|
-
'worklet';
|
|
109
|
-
|
|
110
|
-
if (drivers.length === 0) return fail('A group must contain a driver.');
|
|
111
|
-
const seen = {};
|
|
112
|
-
const result = [];
|
|
113
|
-
for (const driver of drivers) {
|
|
114
|
-
const handle = driver.__smoothClipHandle;
|
|
115
|
-
if (driver.kind !== 'hybrid' || handle === undefined || !Number.isSafeInteger(handle.driverId) || handle.driverId <= 0 || handle.disposed.value !== 0) {
|
|
116
|
-
return fail('Every group participant must be a live SmoothClip driver.');
|
|
117
|
-
}
|
|
118
|
-
const key = String(handle.driverId);
|
|
119
|
-
if (seen[key]) return fail('A group cannot contain duplicate drivers.');
|
|
120
|
-
seen[key] = true;
|
|
121
|
-
result.push({
|
|
122
|
-
driver,
|
|
123
|
-
handle
|
|
124
|
-
});
|
|
125
|
-
}
|
|
126
|
-
return result;
|
|
127
|
-
}
|
|
128
|
-
function requireNativeGroups() {
|
|
129
|
-
'worklet';
|
|
130
|
-
|
|
131
|
-
if (!GROUPS_SUPPORTED || beginGroupInteractionV2HostFunction === undefined || snapshotGroupV2HostFunction === undefined || setClipPresentationBatchV2HostFunction === undefined || animateTimingGroupV2HostFunction === undefined || animateSpringGroupV2HostFunction === undefined || animateKeyframesGroupV2HostFunction === undefined || cancelAnimationGroupV2HostFunction === undefined) {
|
|
132
|
-
return fail('Native grouped presentation protocol V2 is unavailable.');
|
|
133
|
-
}
|
|
134
|
-
return {
|
|
135
|
-
beginGroupInteractionV2: beginGroupInteractionV2HostFunction,
|
|
136
|
-
snapshotGroupV2: snapshotGroupV2HostFunction,
|
|
137
|
-
setClipPresentationBatchV2: setClipPresentationBatchV2HostFunction,
|
|
138
|
-
animateTimingGroupV2: animateTimingGroupV2HostFunction,
|
|
139
|
-
animateSpringGroupV2: animateSpringGroupV2HostFunction,
|
|
140
|
-
animateKeyframesGroupV2: animateKeyframesGroupV2HostFunction,
|
|
141
|
-
cancelAnimationGroupV2: cancelAnimationGroupV2HostFunction
|
|
142
|
-
};
|
|
143
|
-
}
|
|
144
|
-
function parseSnapshots(drivers, values) {
|
|
145
|
-
'worklet';
|
|
146
|
-
|
|
147
|
-
if (values.length !== drivers.length * SNAPSHOT_STRIDE) {
|
|
148
|
-
return fail('Native returned an invalid group snapshot.');
|
|
149
|
-
}
|
|
150
|
-
const snapshots = [];
|
|
151
|
-
let unavailable = false;
|
|
152
|
-
for (let index = 0; index < drivers.length; index += 1) {
|
|
153
|
-
const offset = index * SNAPSHOT_STRIDE;
|
|
154
|
-
const readyCode = values[offset];
|
|
155
|
-
let presentation = presentationFromValues(values, offset + 1);
|
|
156
|
-
if (readyCode !== 0 && readyCode !== 1) {
|
|
157
|
-
return fail('Native returned an invalid group snapshot.');
|
|
158
|
-
}
|
|
159
|
-
if (presentation === null && readyCode === 0) {
|
|
160
|
-
presentation = canonicalizeClipPresentation(drivers[index]?.__smoothClipHandle?.presentation.value);
|
|
161
|
-
unavailable = true;
|
|
162
|
-
}
|
|
163
|
-
if (presentation === null) {
|
|
164
|
-
return fail('Native returned an invalid group snapshot.');
|
|
165
|
-
}
|
|
166
|
-
snapshots.push({
|
|
167
|
-
driver: drivers[index],
|
|
168
|
-
presentation,
|
|
169
|
-
ready: readyCode === 1
|
|
170
|
-
});
|
|
171
|
-
}
|
|
172
|
-
return {
|
|
173
|
-
snapshots,
|
|
174
|
-
unavailable
|
|
175
|
-
};
|
|
176
|
-
}
|
|
177
|
-
function applyInteractiveSnapshots(snapshots) {
|
|
178
|
-
'worklet';
|
|
179
|
-
|
|
180
|
-
// Keep individual driver listeners from re-emitting a transaction that the
|
|
181
|
-
// group engine has already committed atomically.
|
|
182
|
-
for (const snapshot of snapshots) {
|
|
183
|
-
const handle = snapshot.driver.__smoothClipHandle;
|
|
184
|
-
if (handle) handle.ownership.value = NATIVE;
|
|
185
|
-
}
|
|
186
|
-
for (const snapshot of snapshots) {
|
|
187
|
-
const handle = snapshot.driver.__smoothClipHandle;
|
|
188
|
-
if (!handle) continue;
|
|
189
|
-
handle.activeAnimationId.value = 0;
|
|
190
|
-
handle.presentation.value = snapshot.presentation;
|
|
191
|
-
handle.ownership.value = INTERACTIVE;
|
|
192
|
-
}
|
|
193
|
-
}
|
|
194
|
-
function suspensionPolicyCode(value) {
|
|
195
|
-
'worklet';
|
|
196
|
-
|
|
197
|
-
return value === 'finish' ? 1 : 0;
|
|
198
|
-
}
|
|
199
|
-
function reduceMotionCode(value) {
|
|
200
|
-
'worklet';
|
|
201
|
-
|
|
202
|
-
if (value === 'always') return 1;
|
|
203
|
-
if (value === 'never') return 2;
|
|
204
|
-
return 0;
|
|
205
|
-
}
|
|
206
|
-
function animationStartTimestamp() {
|
|
207
|
-
'worklet';
|
|
208
|
-
|
|
209
|
-
if (!NEEDS_START_STAMP) return Number.NaN;
|
|
210
|
-
const runtime = globalThis;
|
|
211
|
-
return runtime.__frameTimestamp || (typeof runtime._getAnimationTimestamp === 'function' ? runtime._getAnimationTimestamp() : Number.NaN);
|
|
212
|
-
}
|
|
213
|
-
function animationIsFinite(animation) {
|
|
214
|
-
'worklet';
|
|
215
|
-
|
|
216
|
-
if (animation.suspensionPolicy !== undefined && animation.suspensionPolicy !== 'pause' && animation.suspensionPolicy !== 'finish') {
|
|
217
|
-
return false;
|
|
218
|
-
}
|
|
219
|
-
if (animation.type === 'timing') {
|
|
220
|
-
if (!Array.isArray(animation.controlPoints) || animation.controlPoints.length !== 4) {
|
|
221
|
-
return false;
|
|
222
|
-
}
|
|
223
|
-
const [x1, y1, x2, y2] = animation.controlPoints;
|
|
224
|
-
return Number.isFinite(animation.duration) && animation.duration >= 0 && [x1, y1, x2, y2].every(Number.isFinite) && x1 >= 0 && x1 <= 1 && x2 >= 0 && x2 <= 1;
|
|
225
|
-
}
|
|
226
|
-
if (animation.type === 'spring') {
|
|
227
|
-
const initialVelocity = animation.initialVelocity === 'inherit' || animation.initialVelocity === undefined ? 0 : animation.initialVelocity;
|
|
228
|
-
return [animation.mass ?? 1, animation.stiffness ?? 100, animation.damping ?? 10, initialVelocity].every(Number.isFinite) && (animation.mass ?? 1) > 0 && (animation.stiffness ?? 100) > 0 && (animation.damping ?? 10) >= 0;
|
|
229
|
-
}
|
|
230
|
-
return animation.type === 'keyframes' && Number.isFinite(animation.duration) && animation.duration >= 0;
|
|
231
|
-
}
|
|
232
|
-
function springScaleIsProvablyPositive(starts, targets, animation) {
|
|
233
|
-
'worklet';
|
|
234
|
-
|
|
235
|
-
let changesScale = false;
|
|
236
|
-
for (let index = 0; index < starts.length; index += 1) {
|
|
237
|
-
if (starts[index]?.contentScale !== targets[index]?.contentScale) {
|
|
238
|
-
changesScale = true;
|
|
239
|
-
break;
|
|
240
|
-
}
|
|
241
|
-
}
|
|
242
|
-
if (!changesScale) return true;
|
|
243
|
-
|
|
244
|
-
// A zero-velocity critically/over-damped unit-step response is monotonic,
|
|
245
|
-
// so interpolation stays between two already-positive endpoints. Other
|
|
246
|
-
// configurations may overshoot; callers can compile those to keyframes.
|
|
247
|
-
const mass = animation.mass ?? 1;
|
|
248
|
-
const stiffness = animation.stiffness ?? 100;
|
|
249
|
-
const damping = animation.damping ?? 10;
|
|
250
|
-
return animation.initialVelocity === 0 && damping * damping >= 4 * mass * stiffness;
|
|
251
|
-
}
|
|
252
|
-
function snapshotsForMotionStarts(validDrivers, entries) {
|
|
253
|
-
'worklet';
|
|
254
|
-
|
|
255
|
-
const missingFrom = entries.some(entry => entry.from === undefined);
|
|
256
|
-
const sampled = missingFrom ? parseSnapshots(validDrivers.map(entry => entry.driver), requireNativeGroups().snapshotGroupV2(validDrivers.map(entry => entry.handle.driverId))).snapshots : [];
|
|
257
|
-
const starts = [];
|
|
258
|
-
for (let index = 0; index < entries.length; index += 1) {
|
|
259
|
-
const explicit = entries[index]?.from;
|
|
260
|
-
const presentation = explicit === undefined ? sampled[index]?.presentation ?? null : canonicalizeClipPresentation(explicit);
|
|
261
|
-
if (presentation === null) return fail('A group start is invalid.');
|
|
262
|
-
starts.push(presentation);
|
|
263
|
-
}
|
|
264
|
-
return starts;
|
|
265
|
-
}
|
|
266
|
-
function registerNativeGroup(controllerId, groupId, drivers, targets) {
|
|
267
|
-
'worklet';
|
|
268
|
-
|
|
269
|
-
const records = runtimeGroupRecords();
|
|
270
|
-
records[String(groupId)] = {
|
|
271
|
-
controllerId,
|
|
272
|
-
drivers
|
|
273
|
-
};
|
|
274
|
-
for (let index = 0; index < drivers.length; index += 1) {
|
|
275
|
-
const handle = drivers[index]?.__smoothClipHandle;
|
|
276
|
-
const target = targets[index];
|
|
277
|
-
if (!handle || !target) continue;
|
|
278
|
-
handle.ownership.value = NATIVE;
|
|
279
|
-
handle.activeAnimationId.value = groupId;
|
|
280
|
-
handle.presentation.value = target;
|
|
281
|
-
}
|
|
282
|
-
}
|
|
283
|
-
function synchronizeGroupCompletionOnUI(controllerId, groupId, finished, driverIds) {
|
|
284
|
-
'worklet';
|
|
285
|
-
|
|
286
|
-
const records = runtimeGroupRecords();
|
|
287
|
-
const record = records[String(groupId)];
|
|
288
|
-
if (!record || record.controllerId !== controllerId || record.drivers.length !== driverIds.length) {
|
|
289
|
-
return;
|
|
290
|
-
}
|
|
291
|
-
for (let index = 0; index < record.drivers.length; index += 1) {
|
|
292
|
-
if (record.drivers[index]?.__smoothClipHandle?.driverId !== driverIds[index]) {
|
|
293
|
-
return;
|
|
294
|
-
}
|
|
295
|
-
}
|
|
296
|
-
let snapshots = [];
|
|
297
|
-
if (!finished) {
|
|
298
|
-
try {
|
|
299
|
-
snapshots = parseSnapshots(record.drivers, requireNativeGroups().snapshotGroupV2(record.drivers.map(driver => driver.__smoothClipHandle?.driverId ?? 0))).snapshots;
|
|
300
|
-
} catch {
|
|
301
|
-
snapshots = [];
|
|
302
|
-
}
|
|
303
|
-
}
|
|
304
|
-
for (let index = 0; index < record.drivers.length; index += 1) {
|
|
305
|
-
const driver = record.drivers[index];
|
|
306
|
-
if (driver === undefined) continue;
|
|
307
|
-
const handle = driver.__smoothClipHandle;
|
|
308
|
-
if (handle === undefined || handle.activeAnimationId.value !== groupId) {
|
|
309
|
-
continue;
|
|
310
|
-
}
|
|
311
|
-
const snapshot = snapshots[index];
|
|
312
|
-
if (snapshot) handle.presentation.value = snapshot.presentation;
|
|
313
|
-
handle.activeAnimationId.value = 0;
|
|
314
|
-
handle.ownership.value = INTERACTIVE;
|
|
315
|
-
}
|
|
316
|
-
delete records[String(groupId)];
|
|
317
|
-
}
|
|
318
|
-
const pendingGroupRequests = new Map();
|
|
319
|
-
const requestIdsByController = new Map();
|
|
320
|
-
let nextGroupRequestId = 0;
|
|
321
|
-
function createGroupRequest(controllerId, teardownResolution, deferCompletions = false) {
|
|
322
|
-
nextGroupRequestId = nextGroupRequestId % 0x7ffffffe + 1;
|
|
323
|
-
const requestId = nextGroupRequestId;
|
|
324
|
-
let resolveRequest;
|
|
325
|
-
let rejectRequest;
|
|
326
|
-
const promise = new Promise((resolve, reject) => {
|
|
327
|
-
resolveRequest = resolve;
|
|
328
|
-
rejectRequest = reject;
|
|
329
|
-
});
|
|
330
|
-
pendingGroupRequests.set(requestId, {
|
|
331
|
-
resolve: resolveRequest,
|
|
332
|
-
reject: rejectRequest,
|
|
333
|
-
...(teardownResolution === undefined ? {} : {
|
|
334
|
-
teardownValue: teardownResolution.value
|
|
335
|
-
}),
|
|
336
|
-
...(deferCompletions ? {
|
|
337
|
-
releasesCompletions: true
|
|
338
|
-
} : {})
|
|
339
|
-
});
|
|
340
|
-
const ids = requestIdsByController.get(controllerId) ?? new Set();
|
|
341
|
-
ids.add(requestId);
|
|
342
|
-
requestIdsByController.set(controllerId, ids);
|
|
343
|
-
if (deferCompletions) deferNativeGroupCompletions(controllerId);
|
|
344
|
-
return {
|
|
345
|
-
requestId,
|
|
346
|
-
promise
|
|
347
|
-
};
|
|
348
|
-
}
|
|
349
|
-
function settleGroupRequest(controllerId, requestId, succeeded, value, message) {
|
|
350
|
-
const request = pendingGroupRequests.get(requestId);
|
|
351
|
-
pendingGroupRequests.delete(requestId);
|
|
352
|
-
const ids = requestIdsByController.get(controllerId);
|
|
353
|
-
ids?.delete(requestId);
|
|
354
|
-
if (ids?.size === 0) requestIdsByController.delete(controllerId);
|
|
355
|
-
if (!request) return;
|
|
356
|
-
if (succeeded) request.resolve(value);else request.reject(new Error(message));
|
|
357
|
-
if (request.releasesCompletions) {
|
|
358
|
-
// One turn resolves the Promise; the second lets reactions already
|
|
359
|
-
// attached to that Promise observe settlement before callbacks run.
|
|
360
|
-
queueMicrotask(() => {
|
|
361
|
-
queueMicrotask(() => releaseNativeGroupCompletions(controllerId));
|
|
362
|
-
});
|
|
363
|
-
}
|
|
364
|
-
}
|
|
365
|
-
function rejectGroupRequests(controllerId) {
|
|
366
|
-
const ids = requestIdsByController.get(controllerId);
|
|
367
|
-
if (ids) {
|
|
368
|
-
for (const requestId of ids) {
|
|
369
|
-
const request = pendingGroupRequests.get(requestId);
|
|
370
|
-
pendingGroupRequests.delete(requestId);
|
|
371
|
-
if (!request) continue;
|
|
372
|
-
if ('teardownValue' in request) request.resolve(request.teardownValue);else request.reject(new Error('[SmoothClipView] Group driver was destroyed.'));
|
|
373
|
-
}
|
|
374
|
-
requestIdsByController.delete(controllerId);
|
|
375
|
-
}
|
|
376
|
-
const state = nativeGroupDriverStates.get(controllerId);
|
|
377
|
-
if (state) state.completionDeferrals = 0;
|
|
378
|
-
}
|
|
379
|
-
function detachNativeGroupDriverState(controllerId, state) {
|
|
380
|
-
state.completionDeferrals = 0;
|
|
381
|
-
const deferred = state.deferredCompletions.splice(0);
|
|
382
|
-
if (nativeGroupDriverStates.get(controllerId) === state) {
|
|
383
|
-
nativeGroupDriverStates.delete(controllerId);
|
|
384
|
-
}
|
|
385
|
-
if (deferred.length === 0) return;
|
|
386
|
-
queueMicrotask(() => {
|
|
387
|
-
queueMicrotask(() => {
|
|
388
|
-
for (const result of deferred) state.callbackRef.current?.(result);
|
|
389
|
-
});
|
|
390
|
-
});
|
|
391
|
-
}
|
|
392
|
-
function queueNativeTeardownCompletion(controllerId, groupId) {
|
|
393
|
-
const state = nativeGroupDriverStates.get(controllerId);
|
|
394
|
-
if (!state) return;
|
|
395
|
-
queueMicrotask(() => {
|
|
396
|
-
queueMicrotask(() => {
|
|
397
|
-
state.callbackRef.current?.({
|
|
398
|
-
groupId,
|
|
399
|
-
finished: false
|
|
400
|
-
});
|
|
401
|
-
});
|
|
402
|
-
});
|
|
403
|
-
}
|
|
404
|
-
function finalizeNativeGroupDriverTeardown(controllerId, effectGeneration) {
|
|
405
|
-
const state = nativeGroupDriverStates.get(controllerId);
|
|
406
|
-
if (!state || state.effectGeneration !== effectGeneration) return;
|
|
407
|
-
detachNativeGroupDriverState(controllerId, state);
|
|
408
|
-
}
|
|
409
|
-
function errorMessage(error) {
|
|
410
|
-
'worklet';
|
|
411
|
-
|
|
412
|
-
return error instanceof Error ? error.message : '[SmoothClipView] Group operation failed.';
|
|
413
|
-
}
|
|
414
|
-
export function useSmoothClipGroupDriver(options = {}) {
|
|
415
|
-
const callbackRef = useRef(options.onAnimationComplete);
|
|
416
|
-
const stateRef = useRef(null);
|
|
417
|
-
const groupRef = useRef(null);
|
|
418
|
-
const disposed = useSharedValue(0);
|
|
419
|
-
callbackRef.current = options.onAnimationComplete;
|
|
420
|
-
if (stateRef.current === null) {
|
|
421
|
-
stateRef.current = {
|
|
422
|
-
callbackRef,
|
|
423
|
-
completionDeferrals: 0,
|
|
424
|
-
deferredCompletions: [],
|
|
425
|
-
effectGeneration: 0
|
|
426
|
-
};
|
|
427
|
-
}
|
|
428
|
-
if (groupRef.current === null) {
|
|
429
|
-
const controllerId = allocateDriverId();
|
|
430
|
-
const reduceMotion = reduceMotionCode(options.reduceMotion ?? 'system');
|
|
431
|
-
const beginOnUI = drivers => {
|
|
432
|
-
'worklet';
|
|
433
|
-
|
|
434
|
-
if (disposed.value !== 0) return fail('Group driver was destroyed.');
|
|
435
|
-
const valid = validateDrivers(drivers);
|
|
436
|
-
const values = requireNativeGroups().beginGroupInteractionV2(valid.map(entry => entry.handle.driverId));
|
|
437
|
-
const parsed = parseSnapshots(drivers, values);
|
|
438
|
-
// An unavailable wire presentation means native rejected the atomic
|
|
439
|
-
// interaction preflight. Return readiness without changing JS ownership.
|
|
440
|
-
if (!parsed.unavailable) applyInteractiveSnapshots(parsed.snapshots);
|
|
441
|
-
return parsed.snapshots;
|
|
442
|
-
};
|
|
443
|
-
const snapshotOnUI = drivers => {
|
|
444
|
-
'worklet';
|
|
445
|
-
|
|
446
|
-
if (disposed.value !== 0) return fail('Group driver was destroyed.');
|
|
447
|
-
const valid = validateDrivers(drivers);
|
|
448
|
-
return parseSnapshots(drivers, requireNativeGroups().snapshotGroupV2(valid.map(entry => entry.handle.driverId))).snapshots;
|
|
449
|
-
};
|
|
450
|
-
const setBatchOnUI = entries => {
|
|
451
|
-
'worklet';
|
|
452
|
-
|
|
453
|
-
if (disposed.value !== 0) return fail('Group driver was destroyed.');
|
|
454
|
-
const valid = validateDrivers(entries.map(entry => entry.driver));
|
|
455
|
-
const canonical = [];
|
|
456
|
-
const values = [];
|
|
457
|
-
for (let index = 0; index < entries.length; index += 1) {
|
|
458
|
-
const presentation = canonicalizeClipPresentation(entries[index]?.presentation);
|
|
459
|
-
if (presentation === null) return fail('A batch presentation is invalid.');
|
|
460
|
-
canonical.push(presentation);
|
|
461
|
-
values.push(valid[index]?.handle.driverId);
|
|
462
|
-
appendPresentation(values, presentation);
|
|
463
|
-
}
|
|
464
|
-
if (!requireNativeGroups().setClipPresentationBatchV2(values)) {
|
|
465
|
-
return fail('Native rejected the complete presentation batch.');
|
|
466
|
-
}
|
|
467
|
-
for (const entry of valid) entry.handle.ownership.value = NATIVE;
|
|
468
|
-
for (let index = 0; index < valid.length; index += 1) {
|
|
469
|
-
const handle = valid[index]?.handle;
|
|
470
|
-
const presentation = canonical[index];
|
|
471
|
-
if (!handle || !presentation) continue;
|
|
472
|
-
handle.activeAnimationId.value = 0;
|
|
473
|
-
handle.presentation.value = presentation;
|
|
474
|
-
handle.ownership.value = INTERACTIVE;
|
|
475
|
-
}
|
|
476
|
-
};
|
|
477
|
-
const animateOnUI = (entries, animation) => {
|
|
478
|
-
'worklet';
|
|
479
|
-
|
|
480
|
-
if (disposed.value !== 0) return fail('Group driver was destroyed.');
|
|
481
|
-
if (!animationIsFinite(animation)) return fail('Group animation is invalid.');
|
|
482
|
-
const drivers = entries.map(entry => entry.driver);
|
|
483
|
-
const valid = validateDrivers(drivers);
|
|
484
|
-
const targets = [];
|
|
485
|
-
for (const entry of entries) {
|
|
486
|
-
const target = canonicalizeClipPresentation(entry.target);
|
|
487
|
-
if (target === null) return fail('A group target is invalid.');
|
|
488
|
-
targets.push(target);
|
|
489
|
-
}
|
|
490
|
-
const starts = snapshotsForMotionStarts(valid, entries);
|
|
491
|
-
for (let index = 0; index < starts.length; index += 1) {
|
|
492
|
-
if (starts[index]?.clip.curve !== targets[index]?.clip.curve) {
|
|
493
|
-
return fail('Curve-changing animations must use streamed rendering.');
|
|
494
|
-
}
|
|
495
|
-
}
|
|
496
|
-
const native = requireNativeGroups();
|
|
497
|
-
const values = [];
|
|
498
|
-
let groupId = 0;
|
|
499
|
-
if (animation.type === 'keyframes') {
|
|
500
|
-
for (let index = 0; index < entries.length; index += 1) {
|
|
501
|
-
const entry = entries[index];
|
|
502
|
-
const target = targets[index];
|
|
503
|
-
const start = starts[index];
|
|
504
|
-
const frames = [];
|
|
505
|
-
let previousOffset = -1;
|
|
506
|
-
for (const frame of entry.frames) {
|
|
507
|
-
const canonical = canonicalizeClipPresentation(frame.presentation);
|
|
508
|
-
const presentation = frames.length === 0 && entry.from === undefined ? start : canonical;
|
|
509
|
-
if (canonical === null || presentation === null || !Number.isFinite(frame.offset) || frame.offset <= previousOffset || frame.offset < 0 || frame.offset > 1 || presentation.clip.curve !== target.clip.curve) {
|
|
510
|
-
return fail('Group keyframes are inconsistent.');
|
|
511
|
-
}
|
|
512
|
-
previousOffset = frame.offset;
|
|
513
|
-
frames.push({
|
|
514
|
-
offset: frame.offset,
|
|
515
|
-
presentation
|
|
516
|
-
});
|
|
517
|
-
}
|
|
518
|
-
if (frames.length < 2 || frames[0]?.offset !== 0 || frames[frames.length - 1]?.offset !== 1 || !clipPresentationEquals(frames[frames.length - 1]?.presentation ?? null, target) || entry.from !== undefined && !clipPresentationEquals(frames[0]?.presentation ?? null, start)) {
|
|
519
|
-
return fail('Group keyframes are inconsistent.');
|
|
520
|
-
}
|
|
521
|
-
values.push(valid[index]?.handle.driverId);
|
|
522
|
-
values.push(entry.from === undefined ? 0 : 1);
|
|
523
|
-
appendPresentation(values, start);
|
|
524
|
-
appendPresentation(values, target);
|
|
525
|
-
values.push(frames.length);
|
|
526
|
-
for (const frame of frames) {
|
|
527
|
-
values.push(frame.offset);
|
|
528
|
-
appendPresentation(values, frame.presentation);
|
|
529
|
-
}
|
|
530
|
-
}
|
|
531
|
-
groupId = native.animateKeyframesGroupV2(controllerId, values, animation.duration, reduceMotion, suspensionPolicyCode(animation.suspensionPolicy), animationStartTimestamp());
|
|
532
|
-
} else {
|
|
533
|
-
for (let index = 0; index < entries.length; index += 1) {
|
|
534
|
-
const entry = entries[index];
|
|
535
|
-
values.push(valid[index]?.handle.driverId);
|
|
536
|
-
values.push(entry.from === undefined ? 0 : 1);
|
|
537
|
-
appendPresentation(values, starts[index]);
|
|
538
|
-
appendPresentation(values, targets[index]);
|
|
539
|
-
}
|
|
540
|
-
if (values.length !== entries.length * MOTION_ENTRY_STRIDE) {
|
|
541
|
-
return fail('Internal group wire encoding failed.');
|
|
542
|
-
}
|
|
543
|
-
if (animation.type === 'timing') {
|
|
544
|
-
const [x1, y1, x2, y2] = animation.controlPoints;
|
|
545
|
-
groupId = native.animateTimingGroupV2(controllerId, values, animation.duration, x1, y1, x2, y2, reduceMotion, suspensionPolicyCode(animation.suspensionPolicy), animationStartTimestamp());
|
|
546
|
-
} else {
|
|
547
|
-
if (!springScaleIsProvablyPositive(starts, targets, animation)) {
|
|
548
|
-
return fail('This scale-changing spring is not provably positive; compile it to keyframes.');
|
|
549
|
-
}
|
|
550
|
-
const inheritVelocity = animation.initialVelocity === undefined || animation.initialVelocity === 'inherit';
|
|
551
|
-
groupId = native.animateSpringGroupV2(controllerId, values, animation.mass ?? 1, animation.stiffness ?? 100, animation.damping ?? 10, inheritVelocity ? 0 : animation.initialVelocity, inheritVelocity, reduceMotion, suspensionPolicyCode(animation.suspensionPolicy), animationStartTimestamp());
|
|
552
|
-
}
|
|
553
|
-
}
|
|
554
|
-
if (!Number.isInteger(groupId) || groupId <= 0) {
|
|
555
|
-
return fail('Native rejected the complete group animation.');
|
|
556
|
-
}
|
|
557
|
-
registerNativeGroup(controllerId, groupId, drivers, targets);
|
|
558
|
-
return groupId;
|
|
559
|
-
};
|
|
560
|
-
const cancelOnUI = (groupId, behavior = 'freeze') => {
|
|
561
|
-
'worklet';
|
|
562
|
-
|
|
563
|
-
if (disposed.value !== 0) return fail('Group driver was destroyed.');
|
|
564
|
-
if (!Number.isSafeInteger(groupId) || groupId <= 0) {
|
|
565
|
-
return fail('A group ID must be a positive integer.');
|
|
566
|
-
}
|
|
567
|
-
if (behavior !== 'freeze' && behavior !== 'finish') {
|
|
568
|
-
return fail('Group cancel behavior is invalid.');
|
|
569
|
-
}
|
|
570
|
-
const records = runtimeGroupRecords();
|
|
571
|
-
const record = records[String(groupId)];
|
|
572
|
-
if (!record || record.controllerId !== controllerId) return [];
|
|
573
|
-
const values = requireNativeGroups().cancelAnimationGroupV2(groupId, behavior === 'finish' ? 1 : 0);
|
|
574
|
-
if (values.length === 0) {
|
|
575
|
-
for (const driver of record.drivers) {
|
|
576
|
-
const handle = driver.__smoothClipHandle;
|
|
577
|
-
if (!handle || handle.activeAnimationId.value !== groupId) continue;
|
|
578
|
-
handle.activeAnimationId.value = 0;
|
|
579
|
-
handle.ownership.value = INTERACTIVE;
|
|
580
|
-
}
|
|
581
|
-
delete records[String(groupId)];
|
|
582
|
-
return [];
|
|
583
|
-
}
|
|
584
|
-
const snapshots = parseSnapshots(record.drivers, values).snapshots;
|
|
585
|
-
applyInteractiveSnapshots(snapshots);
|
|
586
|
-
delete records[String(groupId)];
|
|
587
|
-
return snapshots;
|
|
588
|
-
};
|
|
589
|
-
const group = {
|
|
590
|
-
kind: 'group',
|
|
591
|
-
ui: {
|
|
592
|
-
beginInteraction(drivers) {
|
|
593
|
-
'worklet';
|
|
594
|
-
|
|
595
|
-
if (isRNRuntime()) return uiOnly();
|
|
596
|
-
return beginOnUI(drivers);
|
|
597
|
-
},
|
|
598
|
-
snapshotCurrent(drivers) {
|
|
599
|
-
'worklet';
|
|
600
|
-
|
|
601
|
-
if (isRNRuntime()) return uiOnly();
|
|
602
|
-
return snapshotOnUI(drivers);
|
|
603
|
-
},
|
|
604
|
-
setBatch(entries) {
|
|
605
|
-
'worklet';
|
|
606
|
-
|
|
607
|
-
if (isRNRuntime()) return uiOnly();
|
|
608
|
-
setBatchOnUI(entries);
|
|
609
|
-
},
|
|
610
|
-
animateTo(entries, animation) {
|
|
611
|
-
'worklet';
|
|
612
|
-
|
|
613
|
-
if (isRNRuntime()) return uiOnly();
|
|
614
|
-
return animateOnUI(entries, animation);
|
|
615
|
-
},
|
|
616
|
-
cancel(groupId, behavior = 'freeze') {
|
|
617
|
-
'worklet';
|
|
618
|
-
|
|
619
|
-
if (isRNRuntime()) return uiOnly();
|
|
620
|
-
return cancelOnUI(groupId, behavior);
|
|
621
|
-
}
|
|
622
|
-
},
|
|
623
|
-
react: {
|
|
624
|
-
beginInteraction(drivers) {
|
|
625
|
-
const {
|
|
626
|
-
requestId,
|
|
627
|
-
promise
|
|
628
|
-
} = createGroupRequest(controllerId, undefined, true);
|
|
629
|
-
scheduleOnUI(() => {
|
|
630
|
-
'worklet';
|
|
631
|
-
|
|
632
|
-
try {
|
|
633
|
-
const result = beginOnUI(drivers);
|
|
634
|
-
scheduleOnRN(settleGroupRequest, controllerId, requestId, true, result, '');
|
|
635
|
-
} catch (error) {
|
|
636
|
-
scheduleOnRN(settleGroupRequest, controllerId, requestId, false, undefined, errorMessage(error));
|
|
637
|
-
}
|
|
638
|
-
});
|
|
639
|
-
return promise;
|
|
640
|
-
},
|
|
641
|
-
snapshotCurrent(drivers) {
|
|
642
|
-
const {
|
|
643
|
-
requestId,
|
|
644
|
-
promise
|
|
645
|
-
} = createGroupRequest(controllerId);
|
|
646
|
-
scheduleOnUI(() => {
|
|
647
|
-
'worklet';
|
|
648
|
-
|
|
649
|
-
try {
|
|
650
|
-
const result = snapshotOnUI(drivers);
|
|
651
|
-
scheduleOnRN(settleGroupRequest, controllerId, requestId, true, result, '');
|
|
652
|
-
} catch (error) {
|
|
653
|
-
scheduleOnRN(settleGroupRequest, controllerId, requestId, false, undefined, errorMessage(error));
|
|
654
|
-
}
|
|
655
|
-
});
|
|
656
|
-
return promise;
|
|
657
|
-
},
|
|
658
|
-
setBatch(entries) {
|
|
659
|
-
const {
|
|
660
|
-
requestId,
|
|
661
|
-
promise
|
|
662
|
-
} = createGroupRequest(controllerId, {
|
|
663
|
-
value: undefined
|
|
664
|
-
}, true);
|
|
665
|
-
scheduleOnUI(() => {
|
|
666
|
-
'worklet';
|
|
667
|
-
|
|
668
|
-
try {
|
|
669
|
-
setBatchOnUI(entries);
|
|
670
|
-
scheduleOnRN(settleGroupRequest, controllerId, requestId, true, undefined, '');
|
|
671
|
-
} catch (error) {
|
|
672
|
-
scheduleOnRN(settleGroupRequest, controllerId, requestId, false, undefined, errorMessage(error));
|
|
673
|
-
}
|
|
674
|
-
});
|
|
675
|
-
return promise;
|
|
676
|
-
},
|
|
677
|
-
animateTo(entries, animation) {
|
|
678
|
-
const {
|
|
679
|
-
requestId,
|
|
680
|
-
promise
|
|
681
|
-
} = createGroupRequest(controllerId, {
|
|
682
|
-
value: 0
|
|
683
|
-
}, true);
|
|
684
|
-
scheduleOnUI(() => {
|
|
685
|
-
'worklet';
|
|
686
|
-
|
|
687
|
-
try {
|
|
688
|
-
const result = animateOnUI(entries, animation);
|
|
689
|
-
scheduleOnRN(settleGroupRequest, controllerId, requestId, true, result, '');
|
|
690
|
-
} catch (error) {
|
|
691
|
-
scheduleOnRN(settleGroupRequest, controllerId, requestId, false, undefined, errorMessage(error));
|
|
692
|
-
}
|
|
693
|
-
});
|
|
694
|
-
return promise;
|
|
695
|
-
},
|
|
696
|
-
cancel(groupId, behavior = 'freeze') {
|
|
697
|
-
const {
|
|
698
|
-
requestId,
|
|
699
|
-
promise
|
|
700
|
-
} = createGroupRequest(controllerId, undefined, true);
|
|
701
|
-
scheduleOnUI(() => {
|
|
702
|
-
'worklet';
|
|
703
|
-
|
|
704
|
-
try {
|
|
705
|
-
const result = cancelOnUI(groupId, behavior);
|
|
706
|
-
scheduleOnRN(settleGroupRequest, controllerId, requestId, true, result, '');
|
|
707
|
-
} catch (error) {
|
|
708
|
-
scheduleOnRN(settleGroupRequest, controllerId, requestId, false, undefined, errorMessage(error));
|
|
709
|
-
}
|
|
710
|
-
});
|
|
711
|
-
return promise;
|
|
712
|
-
}
|
|
713
|
-
}
|
|
714
|
-
};
|
|
715
|
-
controllerIds.set(group, controllerId);
|
|
716
|
-
groupRef.current = group;
|
|
717
|
-
}
|
|
718
|
-
useEffect(() => {
|
|
719
|
-
disposed.value = 0;
|
|
720
|
-
const controllerId = controllerIdFor(groupRef.current);
|
|
721
|
-
const state = stateRef.current;
|
|
722
|
-
if (state === null) return undefined;
|
|
723
|
-
state.effectGeneration += 1;
|
|
724
|
-
const effectGeneration = state.effectGeneration;
|
|
725
|
-
nativeGroupDriverStates.set(controllerId, state);
|
|
726
|
-
let subscription;
|
|
727
|
-
if (GROUPS_SUPPORTED) {
|
|
728
|
-
try {
|
|
729
|
-
subscription = nativeGroups.onClipGroupAnimationComplete?.(result => {
|
|
730
|
-
if (result.controllerId !== controllerId) return;
|
|
731
|
-
scheduleOnUI(synchronizeGroupCompletionOnUI, result.controllerId, result.groupId, result.finished, result.driverIds);
|
|
732
|
-
deliverNativeGroupCompletion(controllerId, result.groupId, result.finished);
|
|
733
|
-
});
|
|
734
|
-
} catch {
|
|
735
|
-
// A V1 native module may expose neither the event hook nor a compatible
|
|
736
|
-
// emitter facade. Unsupported setup is a no-op; UI methods still report
|
|
737
|
-
// the normal capability error when invoked.
|
|
738
|
-
}
|
|
739
|
-
}
|
|
740
|
-
return () => {
|
|
741
|
-
try {
|
|
742
|
-
subscription?.remove();
|
|
743
|
-
} catch {
|
|
744
|
-
// Older native event subscriptions are not guaranteed to support V2
|
|
745
|
-
// teardown. Cleanup must remain safe across a new-JS/V1-native pair.
|
|
746
|
-
}
|
|
747
|
-
rejectGroupRequests(controllerId);
|
|
748
|
-
scheduleOnUI((ownerId, generation, gone) => {
|
|
749
|
-
'worklet';
|
|
750
|
-
|
|
751
|
-
gone.value = 1;
|
|
752
|
-
const records = runtimeGroupRecords();
|
|
753
|
-
const native = GROUPS_SUPPORTED ? requireNativeGroups() : null;
|
|
754
|
-
for (const key of Object.keys(records)) {
|
|
755
|
-
const record = records[key];
|
|
756
|
-
if (record?.controllerId !== ownerId) continue;
|
|
757
|
-
const groupId = Number(key);
|
|
758
|
-
const values = native?.cancelAnimationGroupV2(groupId, 0) ?? [];
|
|
759
|
-
let snapshots = [];
|
|
760
|
-
if (values.length !== 0) {
|
|
761
|
-
try {
|
|
762
|
-
snapshots = parseSnapshots(record.drivers, values).snapshots;
|
|
763
|
-
} catch {
|
|
764
|
-
snapshots = [];
|
|
765
|
-
}
|
|
766
|
-
}
|
|
767
|
-
for (let index = 0; index < record.drivers.length; index += 1) {
|
|
768
|
-
const handle = record.drivers[index]?.__smoothClipHandle;
|
|
769
|
-
if (!handle || handle.activeAnimationId.value !== groupId) continue;
|
|
770
|
-
const snapshot = snapshots[index];
|
|
771
|
-
if (snapshot) handle.presentation.value = snapshot.presentation;
|
|
772
|
-
handle.activeAnimationId.value = 0;
|
|
773
|
-
handle.ownership.value = INTERACTIVE;
|
|
774
|
-
}
|
|
775
|
-
delete records[key];
|
|
776
|
-
if (values.length !== 0) {
|
|
777
|
-
scheduleOnRN(queueNativeTeardownCompletion, ownerId, groupId);
|
|
778
|
-
}
|
|
779
|
-
}
|
|
780
|
-
scheduleOnRN(finalizeNativeGroupDriverTeardown, ownerId, generation);
|
|
781
|
-
}, controllerId, effectGeneration, disposed);
|
|
782
|
-
};
|
|
783
|
-
}, [disposed]);
|
|
784
|
-
return groupRef.current;
|
|
785
|
-
}
|
|
786
|
-
|
|
787
|
-
// The public object intentionally has no internal fields. Keeping the
|
|
788
|
-
// controller association in a WeakMap preserves that surface while allowing
|
|
789
|
-
// StrictMode effect replays to reuse the same native callback owner.
|
|
790
|
-
const controllerIds = new WeakMap();
|
|
791
|
-
function controllerIdFor(group) {
|
|
792
|
-
if (group === null) return 0;
|
|
793
|
-
const existing = controllerIds.get(group);
|
|
794
|
-
if (existing !== undefined) return existing;
|
|
795
|
-
const id = allocateDriverId();
|
|
796
|
-
controllerIds.set(group, id);
|
|
797
|
-
return id;
|
|
798
|
-
}
|
|
799
|
-
//# sourceMappingURL=groupDrivers.native.js.map
|