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/README.md
CHANGED
|
@@ -2,6 +2,10 @@
|
|
|
2
2
|
|
|
3
3
|
[](https://www.npmjs.com/package/react-native-smooth-clip-view)
|
|
4
4
|
|
|
5
|
+
https://github.com/user-attachments/assets/899235b3-de69-46d7-b6db-61bc54d80df8
|
|
6
|
+
|
|
7
|
+
<sub>Card zoom and shared-element gallery transitions, captured at 60fps — [direct clip](https://github.com/kbrattli/react-native-smooth-clip-view/blob/main/docs/media/smooth-clip-demo.mp4).</sub>
|
|
8
|
+
|
|
5
9
|
## High-performance geometry animations for React Native
|
|
6
10
|
|
|
7
11
|
`react-native-smooth-clip-view` lets you animate `x`, `y`, `width`, `height`, and `borderRadius` with Reanimated without triggering expensive layout work on every frame.
|
|
@@ -16,10 +20,11 @@ Use it for transitions that previously struggled with performance when animating
|
|
|
16
20
|
- React Native Reanimated 4.5 or newer
|
|
17
21
|
- React Native Worklets 0.10 or newer
|
|
18
22
|
- iOS 16.4 or newer
|
|
19
|
-
- Android API
|
|
23
|
+
- Android API 33 or newer
|
|
20
24
|
|
|
21
|
-
The package supports iOS
|
|
22
|
-
|
|
25
|
+
The package supports iOS and Android. React Native Web and the legacy Paper
|
|
26
|
+
architecture are not supported; keep imports and rendered usage behind native
|
|
27
|
+
platform boundaries.
|
|
23
28
|
|
|
24
29
|
## Installation
|
|
25
30
|
|
|
@@ -97,8 +102,9 @@ const styles = StyleSheet.create({
|
|
|
97
102
|
```
|
|
98
103
|
|
|
99
104
|
The same driver can be passed to multiple hosts. One native registry update
|
|
100
|
-
fans the
|
|
101
|
-
|
|
105
|
+
fans the presentation out to all mounted hosts. The original seven-scalar V1
|
|
106
|
+
protocol remains unchanged; V2 adds per-corner radii, continuous curves, and
|
|
107
|
+
centered content scale. Interactive updates avoid Yoga and ShadowTree commits.
|
|
102
108
|
|
|
103
109
|
For transitions whose endpoint is known, let Core Animation interpolate on the
|
|
104
110
|
render server:
|
|
@@ -211,13 +217,18 @@ puts on screen, which is the property worth keeping identical.
|
|
|
211
217
|
as `animation.from` — `animateTo` then performs the hot write and the
|
|
212
218
|
handoff in one call. Do not interleave `setScalars` with
|
|
213
219
|
`presentation.value` writes on the same driver.
|
|
220
|
+
- `driver.ui.setPresentationScalars(x, y, width, height, topLeft, topRight,
|
|
221
|
+
bottomRight, bottomLeft, curveCode, tx, ty, scale)` is the V2 hot path.
|
|
222
|
+
`curveCode` is `0` for circular and `1` for continuous. V2 values are
|
|
223
|
+
validated as one transaction; widened values are never silently downgraded
|
|
224
|
+
onto a V1 native binary.
|
|
214
225
|
- Spring `initialVelocity` is one normalized scalar along the current-to-target
|
|
215
226
|
trajectory, in units of the remaining distance per second (`1` covers the
|
|
216
227
|
remaining distance in one second). Every geometry channel continues with the
|
|
217
228
|
same normalized rate, so grab/release preserves the felt direction and
|
|
218
229
|
speed. `'inherit'` (the default) estimates the scalar from the last two
|
|
219
|
-
interactive samples on iOS and Android
|
|
220
|
-
|
|
230
|
+
interactive samples on iOS and Android. On Android, sampling on the
|
|
231
|
+
`setScalars` hot path is **opt-in**: pass
|
|
221
232
|
`velocityTracking: true` to `useSmoothClipDriver` or `'inherit'` inherits
|
|
222
233
|
zero after a hot-write drag (a dev-mode warning flags this). **Behavior
|
|
223
234
|
change:** earlier releases always recorded on Android, so an existing
|
|
@@ -261,10 +272,9 @@ puts on screen, which is the property worth keeping identical.
|
|
|
261
272
|
starts the replacement from that native value. Passive hook seeds and public
|
|
262
273
|
`set`/`setScalars` writes still leave a held latch intact. `from` behaves the
|
|
263
274
|
same on both platforms (it is driver-layer, not native): on iOS the seed
|
|
264
|
-
stops any running Core Animation
|
|
265
|
-
|
|
266
|
-
the
|
|
267
|
-
`from` — identical to the explicit two-call pattern.
|
|
275
|
+
stops any running Core Animation, applies `from` to the model layer, and
|
|
276
|
+
installs timing, spring, or keyframe playback from that exact presentation in
|
|
277
|
+
the same start transaction.
|
|
268
278
|
- `cancel()` freezes visible presentation by default. Pass `'target'` as its
|
|
269
279
|
behavior to jump to the requested endpoint.
|
|
270
280
|
- `options.onAnimationComplete` fires exactly once per animation with its ID
|
|
@@ -326,6 +336,30 @@ bounds, so a clip that extended beyond the host comes back clamped. Start
|
|
|
326
336
|
gestures with `beginInteraction()`: interactive writes issued while native
|
|
327
337
|
still owns rendering are dropped.
|
|
328
338
|
|
|
339
|
+
### Group driver
|
|
340
|
+
|
|
341
|
+
`useSmoothClipGroupDriver({ reduceMotion, onAnimationComplete })` coordinates
|
|
342
|
+
multiple drivers with one native group ID and one completion. Its worklet-safe
|
|
343
|
+
`ui` and Promise-based `react` interfaces expose:
|
|
344
|
+
|
|
345
|
+
- `beginInteraction(drivers)` to freeze every overlapping group atomically and
|
|
346
|
+
return canonical visible snapshots in input order.
|
|
347
|
+
- `snapshotCurrent(drivers)` to sample presentation and readiness without
|
|
348
|
+
changing ownership.
|
|
349
|
+
- `setBatch(entries)` to validate every entry before committing one native
|
|
350
|
+
transaction.
|
|
351
|
+
- `animateTo(entries, animation)` for shared timing, spring, or linear
|
|
352
|
+
keyframe progress. Membership is immutable for that group ID; a replacement
|
|
353
|
+
is a new atomically installed group.
|
|
354
|
+
- `cancel(groupId, 'freeze' | 'finish')` to return every participant snapshot.
|
|
355
|
+
|
|
356
|
+
Groups wait until all participants have a visible, attached, laid-out,
|
|
357
|
+
positive-size host. The default `suspensionPolicy: 'pause'` freezes and
|
|
358
|
+
re-latches the whole group if any participant loses readiness; `'finish'`
|
|
359
|
+
applies every target. Complex-path native settlement is capability-gated—use
|
|
360
|
+
`getSmoothClipCapabilities()` and keep streaming with `setBatch` when
|
|
361
|
+
`autonomousComplexPathAnimation` is false.
|
|
362
|
+
|
|
329
363
|
### `SmoothClipPresentation`
|
|
330
364
|
|
|
331
365
|
```ts
|
|
@@ -333,6 +367,7 @@ type SmoothClipPresentation = Readonly<{
|
|
|
333
367
|
clip: ClipGeometry;
|
|
334
368
|
contentTranslateX: number;
|
|
335
369
|
contentTranslateY: number;
|
|
370
|
+
contentScale?: number;
|
|
336
371
|
}>;
|
|
337
372
|
```
|
|
338
373
|
|
|
@@ -349,12 +384,19 @@ type ClipGeometry = Readonly<{
|
|
|
349
384
|
width: number;
|
|
350
385
|
height: number;
|
|
351
386
|
radius: number;
|
|
387
|
+
topLeftRadius?: number;
|
|
388
|
+
topRightRadius?: number;
|
|
389
|
+
bottomRightRadius?: number;
|
|
390
|
+
bottomLeftRadius?: number;
|
|
391
|
+
curve?: 'circular' | 'continuous';
|
|
352
392
|
}>;
|
|
353
393
|
```
|
|
354
394
|
|
|
355
395
|
Values use React Native points/DIPs. Native code rejects non-finite updates,
|
|
356
396
|
intersects the requested rectangle with the actual host bounds, prevents
|
|
357
|
-
negative sizes, and
|
|
397
|
+
negative sizes, and proportionally scales overlapping corners with the CSS
|
|
398
|
+
corner-normalization rule. Content scale is centered on the native content
|
|
399
|
+
container; translation is independent and is not multiplied by scale.
|
|
358
400
|
|
|
359
401
|
### `normalizeClipGeometry`
|
|
360
402
|
|
|
@@ -376,23 +418,21 @@ pass it as the `driver` prop, and move per-frame updates from the
|
|
|
376
418
|
- Give the host its fixed maximum `width` and `height`; clipping never changes
|
|
377
419
|
Yoga layout.
|
|
378
420
|
- Put visual backgrounds inside `SmoothClipView`.
|
|
379
|
-
-
|
|
380
|
-
|
|
381
|
-
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
maximum footprint.
|
|
421
|
+
- Keep borders, shadows, rotation, and anisotropic transforms on an outer
|
|
422
|
+
visual carrier rather than the clip host.
|
|
423
|
+
- Uniform circular corners use platform fast paths. Unequal or continuous
|
|
424
|
+
corners use a fixed-topology portable path; Android intentionally does not
|
|
425
|
+
claim pixel identity with Apple's proprietary continuous curve.
|
|
385
426
|
|
|
386
427
|
## Example and development
|
|
387
428
|
|
|
388
429
|
The [`example`](./example) workspace is an Expo SDK 57 app that exercises the
|
|
389
|
-
package through its public import on iOS
|
|
430
|
+
package through its public import on iOS and Android.
|
|
390
431
|
|
|
391
432
|
```sh
|
|
392
433
|
npm install
|
|
393
434
|
npm run example -- ios
|
|
394
435
|
npm run example -- android
|
|
395
|
-
npm run example -- web
|
|
396
436
|
```
|
|
397
437
|
|
|
398
438
|
Run the repository checks with:
|
|
@@ -402,7 +442,6 @@ npm run lint
|
|
|
402
442
|
npm run typecheck
|
|
403
443
|
npm test
|
|
404
444
|
npm run prepare
|
|
405
|
-
npm run example -- build:web
|
|
406
445
|
```
|
|
407
446
|
|
|
408
447
|
## License
|
package/android/build.gradle
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
buildscript {
|
|
2
2
|
ext.SmoothClipView = [
|
|
3
3
|
kotlinVersion: "2.0.21",
|
|
4
|
-
minSdkVersion:
|
|
4
|
+
minSdkVersion: 33,
|
|
5
5
|
compileSdkVersion: 36,
|
|
6
6
|
targetSdkVersion: 36
|
|
7
7
|
]
|
|
@@ -76,7 +76,11 @@ android {
|
|
|
76
76
|
}
|
|
77
77
|
|
|
78
78
|
defaultConfig {
|
|
79
|
-
|
|
79
|
+
// Outline.setPath only guarantees arbitrary path clipping from API 33.
|
|
80
|
+
// Keep this as a hard library floor: allowing a consuming root project to
|
|
81
|
+
// override it lower would make the V2 per-corner/continuous path silently
|
|
82
|
+
// unsupported at runtime.
|
|
83
|
+
minSdkVersion SmoothClipView.minSdkVersion
|
|
80
84
|
targetSdkVersion getExtOrDefault("targetSdkVersion")
|
|
81
85
|
// C++ resolves SmoothClipView by name and calls setClipPresentationDip via
|
|
82
86
|
// a cached jmethodID; consumer minification must not rename or strip them.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# SmoothClipView is resolved from C++ by name (fbjni findClassStatic) and its
|
|
2
|
-
#
|
|
3
|
-
# jmethodIDs; SmoothClipBindings registers native methods by name. None
|
|
4
|
-
# may be renamed or stripped in consumer release builds.
|
|
2
|
+
# V1/V2 setClipPresentation*Dip / setClipPresentation*Px are invoked through
|
|
3
|
+
# cached jmethodIDs; SmoothClipBindings registers native methods by name. None
|
|
4
|
+
# of them may be renamed or stripped in consumer release builds.
|
|
5
5
|
-keep class com.smoothclipview.SmoothClipView { *; }
|
|
6
6
|
-keep class com.smoothclipview.SmoothClipBindings { *; }
|
|
@@ -18,10 +18,16 @@ struct JSmoothClipView : facebook::jni::JavaClass<JSmoothClipView> {
|
|
|
18
18
|
static constexpr auto kJavaDescriptor = "Lcom/smoothclipview/SmoothClipView;";
|
|
19
19
|
|
|
20
20
|
void applyClip(const Presentation &presentation) const;
|
|
21
|
+
void applyClipV2(const Presentation &presentation) const;
|
|
21
22
|
void applyClipPx(
|
|
22
23
|
const NormalizedClip &clip,
|
|
23
24
|
double contentTranslateXPx,
|
|
24
25
|
double contentTranslateYPx) const;
|
|
26
|
+
void applyClipV2Px(
|
|
27
|
+
const NormalizedClip &clip,
|
|
28
|
+
double contentTranslateXPx,
|
|
29
|
+
double contentTranslateYPx,
|
|
30
|
+
double contentScale) const;
|
|
25
31
|
};
|
|
26
32
|
|
|
27
33
|
// Called from Kotlin (SmoothClipViewManager) on the UI thread when a Fabric
|
|
@@ -57,6 +63,10 @@ void setViewLifecycleVisibilityAndroid(
|
|
|
57
63
|
// seconds; never lets a failure unwind back into doFrame.
|
|
58
64
|
void onFrameAndroid(double frameTimeS);
|
|
59
65
|
|
|
66
|
+
// Non-destructive V2 snapshot for the public snapshotCurrentV2 binding.
|
|
67
|
+
// beginInteraction remains the explicit ownership-taking/cancelling operation.
|
|
68
|
+
Presentation snapshotCurrentAndroid(uint64_t driverId);
|
|
69
|
+
|
|
60
70
|
// Installs `global.__SmoothClipView` (worklet-callable host functions) into the
|
|
61
71
|
// JS runtime and wires native animation completion delivery through the
|
|
62
72
|
// CallInvoker. Invoked by the TurboModule BindingsInstaller.
|