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.
Files changed (130) hide show
  1. package/README.md +60 -21
  2. package/android/build.gradle +6 -2
  3. package/android/proguard-rules.pro +3 -3
  4. package/android/src/main/cpp/SmoothClipAndroid.h +10 -0
  5. package/android/src/main/cpp/SmoothClipBindings.cpp +890 -4
  6. package/android/src/main/cpp/SmoothClipRegistry.cpp +1056 -44
  7. package/android/src/main/java/com/smoothclipview/ClipGeometryNormalizer.kt +265 -0
  8. package/android/src/main/java/com/smoothclipview/SmoothClipBindings.kt +21 -0
  9. package/android/src/main/java/com/smoothclipview/SmoothClipModule.kt +283 -0
  10. package/android/src/main/java/com/smoothclipview/SmoothClipView.kt +371 -18
  11. package/android/src/main/java/com/smoothclipview/SmoothClipViewManager.kt +138 -24
  12. package/cpp/SmoothClipAnimationCurve.h +151 -122
  13. package/cpp/SmoothClipRegistry.h +95 -3
  14. package/cpp/SmoothClipSharedGeometry.h +146 -7
  15. package/cpp/SmoothClipVelocityTracker.h +13 -9
  16. package/ios/SmoothClipGeometry.h +184 -6
  17. package/ios/SmoothClipRegistry.mm +1028 -22
  18. package/ios/SmoothClipRegistrySnapshot.h +13 -0
  19. package/ios/SmoothClipTurboModule.cpp +857 -2
  20. package/ios/SmoothClipTurboModule.h +310 -0
  21. package/ios/SmoothClipView.mm +714 -183
  22. package/ios/SmoothClipViewRegistry.h +1 -0
  23. package/ios/reactnativesmoothclipview.xcodeproj/project.xcworkspace/contents.xcworkspacedata +7 -0
  24. package/ios/reactnativesmoothclipview.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist +8 -0
  25. package/lib/module/NativeSmoothClipModule.js.map +1 -1
  26. package/lib/module/SmoothClipView.ios.js +22 -6
  27. package/lib/module/SmoothClipView.ios.js.map +1 -1
  28. package/lib/module/SmoothClipView.js +1 -46
  29. package/lib/module/SmoothClipView.js.map +1 -1
  30. package/lib/module/SmoothClipViewNativeComponent.ts +27 -1
  31. package/lib/module/capabilities.js +4 -0
  32. package/lib/module/capabilities.js.map +1 -0
  33. package/lib/module/capabilities.native.js +36 -0
  34. package/lib/module/capabilities.native.js.map +1 -0
  35. package/lib/module/capabilityTypes.js +11 -0
  36. package/lib/module/capabilityTypes.js.map +1 -0
  37. package/lib/module/driverState.js +0 -28
  38. package/lib/module/driverState.js.map +1 -1
  39. package/lib/module/drivers.js +1 -281
  40. package/lib/module/drivers.js.map +1 -1
  41. package/lib/module/drivers.native.js +263 -63
  42. package/lib/module/drivers.native.js.map +1 -1
  43. package/lib/module/geometry.js +147 -17
  44. package/lib/module/geometry.js.map +1 -1
  45. package/lib/module/groupDriverTypes.js +4 -0
  46. package/lib/module/groupDriverTypes.js.map +1 -0
  47. package/lib/module/groupDrivers.android.js +4 -0
  48. package/lib/module/groupDrivers.android.js.map +1 -0
  49. package/lib/module/groupDrivers.ios.js +4 -0
  50. package/lib/module/groupDrivers.ios.js.map +1 -0
  51. package/lib/module/groupDrivers.js +4 -0
  52. package/lib/module/groupDrivers.js.map +1 -0
  53. package/lib/module/groupDrivers.native.js +799 -0
  54. package/lib/module/groupDrivers.native.js.map +1 -0
  55. package/lib/module/index.js +3 -2
  56. package/lib/module/index.js.map +1 -1
  57. package/lib/module/presentationProtocol.js +15 -0
  58. package/lib/module/presentationProtocol.js.map +1 -0
  59. package/lib/typescript/src/NativeSmoothClipModule.d.ts +25 -0
  60. package/lib/typescript/src/NativeSmoothClipModule.d.ts.map +1 -1
  61. package/lib/typescript/src/SmoothClipView.d.ts +2 -10
  62. package/lib/typescript/src/SmoothClipView.d.ts.map +1 -1
  63. package/lib/typescript/src/SmoothClipView.ios.d.ts +133 -2
  64. package/lib/typescript/src/SmoothClipView.ios.d.ts.map +1 -1
  65. package/lib/typescript/src/SmoothClipViewNativeComponent.d.ts +8 -0
  66. package/lib/typescript/src/SmoothClipViewNativeComponent.d.ts.map +1 -1
  67. package/lib/typescript/src/capabilities.d.ts +3 -0
  68. package/lib/typescript/src/capabilities.d.ts.map +1 -0
  69. package/lib/typescript/src/capabilities.native.d.ts +3 -0
  70. package/lib/typescript/src/capabilities.native.d.ts.map +1 -0
  71. package/lib/typescript/src/capabilityTypes.d.ts +10 -0
  72. package/lib/typescript/src/capabilityTypes.d.ts.map +1 -0
  73. package/lib/typescript/src/driverState.d.ts +1 -6
  74. package/lib/typescript/src/driverState.d.ts.map +1 -1
  75. package/lib/typescript/src/driverTypes.d.ts +25 -11
  76. package/lib/typescript/src/driverTypes.d.ts.map +1 -1
  77. package/lib/typescript/src/drivers.d.ts +2 -4
  78. package/lib/typescript/src/drivers.d.ts.map +1 -1
  79. package/lib/typescript/src/drivers.native.d.ts.map +1 -1
  80. package/lib/typescript/src/geometry.d.ts +36 -2
  81. package/lib/typescript/src/geometry.d.ts.map +1 -1
  82. package/lib/typescript/src/groupDriverTypes.d.ts +66 -0
  83. package/lib/typescript/src/groupDriverTypes.d.ts.map +1 -0
  84. package/lib/typescript/src/groupDrivers.android.d.ts +2 -0
  85. package/lib/typescript/src/groupDrivers.android.d.ts.map +1 -0
  86. package/lib/typescript/src/groupDrivers.d.ts +2 -0
  87. package/lib/typescript/src/groupDrivers.d.ts.map +1 -0
  88. package/lib/typescript/src/groupDrivers.ios.d.ts +2 -0
  89. package/lib/typescript/src/groupDrivers.ios.d.ts.map +1 -0
  90. package/lib/typescript/src/groupDrivers.native.d.ts +4 -0
  91. package/lib/typescript/src/groupDrivers.native.d.ts.map +1 -0
  92. package/lib/typescript/src/index.d.ts +6 -3
  93. package/lib/typescript/src/index.d.ts.map +1 -1
  94. package/lib/typescript/src/presentationProtocol.d.ts +4 -0
  95. package/lib/typescript/src/presentationProtocol.d.ts.map +1 -0
  96. package/package.json +10 -11
  97. package/src/NativeSmoothClipModule.ts +275 -0
  98. package/src/SmoothClipView.ios.tsx +30 -11
  99. package/src/SmoothClipView.tsx +2 -76
  100. package/src/SmoothClipViewNativeComponent.ts +27 -1
  101. package/src/capabilities.native.ts +69 -0
  102. package/src/capabilities.ts +2 -0
  103. package/src/capabilityTypes.ts +17 -0
  104. package/src/driverState.ts +1 -41
  105. package/src/driverTypes.ts +42 -11
  106. package/src/drivers.native.ts +824 -124
  107. package/src/drivers.ts +2 -423
  108. package/src/geometry.ts +231 -27
  109. package/src/groupDriverTypes.ts +117 -0
  110. package/src/groupDrivers.android.ts +1 -0
  111. package/src/groupDrivers.ios.ts +1 -0
  112. package/src/groupDrivers.native.ts +1189 -0
  113. package/src/groupDrivers.ts +1 -0
  114. package/src/index.ts +30 -2
  115. package/src/presentationProtocol.ts +28 -0
  116. package/lib/module/SmoothClipView.web.js +0 -54
  117. package/lib/module/SmoothClipView.web.js.map +0 -1
  118. package/lib/module/index.web.js +0 -8
  119. package/lib/module/index.web.js.map +0 -1
  120. package/lib/module/webClipPath.js +0 -25
  121. package/lib/module/webClipPath.js.map +0 -1
  122. package/lib/typescript/src/SmoothClipView.web.d.ts +0 -10
  123. package/lib/typescript/src/SmoothClipView.web.d.ts.map +0 -1
  124. package/lib/typescript/src/index.web.d.ts +0 -9
  125. package/lib/typescript/src/index.web.d.ts.map +0 -1
  126. package/lib/typescript/src/webClipPath.d.ts +0 -7
  127. package/lib/typescript/src/webClipPath.d.ts.map +0 -1
  128. package/src/SmoothClipView.web.tsx +0 -66
  129. package/src/index.web.ts +0 -23
  130. package/src/webClipPath.ts +0 -30
@@ -6,8 +6,9 @@
6
6
  namespace smoothclip {
7
7
 
8
8
  // The two most recent interactive samples used by `initialVelocity: 'inherit'`.
9
- // Channels are the seven presentation scalars (x, y, width, height, radius,
10
- // contentTranslateX, contentTranslateY) but the tracker is value-agnostic:
9
+ // Channels are the eleven continuous V2 presentation scalars. Scale is stored
10
+ // so histories remain coherent but excluded from velocity projection; each of
11
+ // the four radius channels contributes one quarter of the legacy radius weight.
11
12
  // iOS records normalized (host-clamped) geometry, Android raw DIP — the
12
13
  // projection only needs both samples and the target in the same space.
13
14
  // Shared by ios/SmoothClipView.mm and android/.../SmoothClipRegistry.cpp; a
@@ -15,8 +16,8 @@ namespace smoothclip {
15
16
  struct VelocitySampleHistory {
16
17
  bool hasPrevious = false;
17
18
  bool hasLatest = false;
18
- std::array<double, 7> previous{};
19
- std::array<double, 7> latest{};
19
+ std::array<double, 11> previous{};
20
+ std::array<double, 11> latest{};
20
21
  double previousTimeS = 0;
21
22
  double latestTimeS = 0;
22
23
  };
@@ -40,7 +41,7 @@ inline constexpr double kVelocityFullCreditS = 1.0 / 60.0;
40
41
 
41
42
  inline void recordVelocitySample(
42
43
  VelocitySampleHistory &history,
43
- const std::array<double, 7> &channels,
44
+ const std::array<double, 11> &channels,
44
45
  double nowS) {
45
46
  if (history.hasLatest && channels == history.latest) {
46
47
  // Identical re-record (a `from` seed equal to the last interactive
@@ -97,7 +98,7 @@ inline double velocityStalenessCredit(double holdS) {
97
98
  // Android seeds each integrator channel with scalar·displacement.
98
99
  inline double inheritedVelocity(
99
100
  const VelocitySampleHistory &history,
100
- const std::array<double, 7> &target,
101
+ const std::array<double, 11> &target,
101
102
  double nowS) {
102
103
  if (!history.hasPrevious || !history.hasLatest) return 0;
103
104
  const double elapsed = history.latestTimeS - history.previousTimeS;
@@ -107,11 +108,14 @@ inline double inheritedVelocity(
107
108
  }
108
109
  double numerator = 0;
109
110
  double denominator = 0;
110
- for (int index = 0; index < 7; index += 1) {
111
+ for (int index = 0; index < 11; index += 1) {
112
+ const double weight = index >= 4 && index <= 7
113
+ ? 0.25
114
+ : (index == 10 ? 0.0 : 1.0);
111
115
  const double sampleDelta = history.latest[index] - history.previous[index];
112
116
  const double destinationDelta = target[index] - history.latest[index];
113
- numerator += sampleDelta * destinationDelta;
114
- denominator += destinationDelta * destinationDelta;
117
+ numerator += weight * sampleDelta * destinationDelta;
118
+ denominator += weight * destinationDelta * destinationDelta;
115
119
  }
116
120
  if (denominator <= 1e-12) return 0;
117
121
  const double result = numerator / elapsed / denominator * credit;
@@ -2,23 +2,77 @@
2
2
 
3
3
  #include <math.h>
4
4
 
5
+ typedef struct {
6
+ CGFloat topLeft;
7
+ CGFloat topRight;
8
+ CGFloat bottomRight;
9
+ CGFloat bottomLeft;
10
+ } SmoothClipCornerRadii;
11
+
12
+ typedef NS_ENUM(NSInteger, SmoothClipCornerCurve) {
13
+ SmoothClipCornerCurveCircular = 0,
14
+ SmoothClipCornerCurveContinuous = 1,
15
+ };
16
+
5
17
  typedef struct {
6
18
  CGRect rect;
19
+ // Retained for the V1 uniform-radius contract. V2 callers should consume
20
+ // `radii`; this field is zero when the normalized radii are unequal.
7
21
  CGFloat radius;
22
+ SmoothClipCornerRadii radii;
23
+ SmoothClipCornerCurve curve;
8
24
  } SmoothNormalizedClipGeometry;
9
25
 
10
- /** Mirrors the Android and JavaScript geometry contract without allocating. */
11
- NS_INLINE BOOL SmoothClipNormalizeGeometry(
26
+ NS_INLINE BOOL SmoothClipCornerRadiiEqual(
27
+ SmoothClipCornerRadii first,
28
+ SmoothClipCornerRadii second) {
29
+ return first.topLeft == second.topLeft &&
30
+ first.topRight == second.topRight &&
31
+ first.bottomRight == second.bottomRight &&
32
+ first.bottomLeft == second.bottomLeft;
33
+ }
34
+
35
+ NS_INLINE BOOL SmoothClipCornerRadiiAreUniform(
36
+ SmoothClipCornerRadii radii) {
37
+ return radii.topLeft == radii.topRight &&
38
+ radii.topLeft == radii.bottomRight &&
39
+ radii.topLeft == radii.bottomLeft;
40
+ }
41
+
42
+ NS_INLINE CGFloat SmoothClipSafeOverlapFactor(
43
+ CGFloat extent,
44
+ CGFloat firstRadius,
45
+ CGFloat secondRadius) {
46
+ const CGFloat sum = firstRadius + secondRadius;
47
+ return sum > 0 ? extent / sum : 1;
48
+ }
49
+
50
+ /**
51
+ * Normalizes the V2 rectangle and four radii without allocating.
52
+ *
53
+ * The proportional overlap rule matches CSS border radii and the shared
54
+ * Android/C++ contract: all corners use one scale factor, preserving their
55
+ * relative shape while no opposing pair exceeds its edge.
56
+ */
57
+ NS_INLINE BOOL SmoothClipNormalizeGeometryV2(
12
58
  CGFloat x,
13
59
  CGFloat y,
14
60
  CGFloat width,
15
61
  CGFloat height,
16
- CGFloat radius,
62
+ CGFloat topLeftRadius,
63
+ CGFloat topRightRadius,
64
+ CGFloat bottomRightRadius,
65
+ CGFloat bottomLeftRadius,
66
+ NSInteger curveCode,
17
67
  CGSize hostSize,
18
68
  SmoothNormalizedClipGeometry *result) {
19
69
  if (!isfinite(x) || !isfinite(y) || !isfinite(width) ||
20
- !isfinite(height) || !isfinite(radius) ||
21
- !isfinite(hostSize.width) || !isfinite(hostSize.height)) {
70
+ !isfinite(height) || !isfinite(topLeftRadius) ||
71
+ !isfinite(topRightRadius) || !isfinite(bottomRightRadius) ||
72
+ !isfinite(bottomLeftRadius) || !isfinite(hostSize.width) ||
73
+ !isfinite(hostSize.height) ||
74
+ (curveCode != SmoothClipCornerCurveCircular &&
75
+ curveCode != SmoothClipCornerCurveContinuous)) {
22
76
  return NO;
23
77
  }
24
78
 
@@ -35,7 +89,131 @@ NS_INLINE BOOL SmoothClipNormalizeGeometry(
35
89
  const CGFloat visibleWidth = MAX(0, right - left);
36
90
  const CGFloat visibleHeight = MAX(0, bottom - top);
37
91
 
92
+ SmoothClipCornerRadii radii = {
93
+ MAX(0, topLeftRadius),
94
+ MAX(0, topRightRadius),
95
+ MAX(0, bottomRightRadius),
96
+ MAX(0, bottomLeftRadius),
97
+ };
98
+ const CGFloat overlapScale = MIN(
99
+ 1,
100
+ MIN(
101
+ MIN(
102
+ SmoothClipSafeOverlapFactor(
103
+ visibleWidth, radii.topLeft, radii.topRight),
104
+ SmoothClipSafeOverlapFactor(
105
+ visibleWidth, radii.bottomLeft, radii.bottomRight)),
106
+ MIN(
107
+ SmoothClipSafeOverlapFactor(
108
+ visibleHeight, radii.topLeft, radii.bottomLeft),
109
+ SmoothClipSafeOverlapFactor(
110
+ visibleHeight, radii.topRight, radii.bottomRight))));
111
+ radii.topLeft *= overlapScale;
112
+ radii.topRight *= overlapScale;
113
+ radii.bottomRight *= overlapScale;
114
+ radii.bottomLeft *= overlapScale;
115
+
38
116
  result->rect = CGRectMake(left, top, visibleWidth, visibleHeight);
39
- result->radius = MIN(MAX(0, radius), MIN(visibleWidth, visibleHeight) / 2.0);
117
+ result->radii = radii;
118
+ result->radius = SmoothClipCornerRadiiAreUniform(radii)
119
+ ? radii.topLeft
120
+ : 0;
121
+ result->curve = (SmoothClipCornerCurve)curveCode;
40
122
  return YES;
41
123
  }
124
+
125
+ /** Mirrors the Android and JavaScript geometry contract without allocating. */
126
+ NS_INLINE BOOL SmoothClipNormalizeGeometry(
127
+ CGFloat x,
128
+ CGFloat y,
129
+ CGFloat width,
130
+ CGFloat height,
131
+ CGFloat radius,
132
+ CGSize hostSize,
133
+ SmoothNormalizedClipGeometry *result) {
134
+ return SmoothClipNormalizeGeometryV2(
135
+ x,
136
+ y,
137
+ width,
138
+ height,
139
+ radius,
140
+ radius,
141
+ radius,
142
+ radius,
143
+ SmoothClipCornerCurveCircular,
144
+ hostSize,
145
+ result);
146
+ }
147
+
148
+ /**
149
+ * Creates the stable nine-segment rounded-rectangle topology used by the
150
+ * unequal-corner CAShapeLayer mask. Every corner is one cubic, including a
151
+ * zero-radius corner, so Core Animation can interpolate paths without a
152
+ * topology change.
153
+ */
154
+ NS_INLINE CGPathRef SmoothClipCreateRoundedRectPath(
155
+ CGRect rect,
156
+ SmoothClipCornerRadii radii,
157
+ SmoothClipCornerCurve curve) CF_RETURNS_RETAINED {
158
+ const CGFloat minX = CGRectGetMinX(rect);
159
+ const CGFloat minY = CGRectGetMinY(rect);
160
+ const CGFloat maxX = CGRectGetMaxX(rect);
161
+ const CGFloat maxY = CGRectGetMaxY(rect);
162
+ // Circular is the exact cubic-circle coefficient. The portable continuous
163
+ // fallback uses kappa=1 so each cubic joins its straight edges with zero
164
+ // curvature, matching the portable Android path. Hit testing derives
165
+ // from this rendered path rather than maintaining a second curve model.
166
+ // Uniform
167
+ // continuous shapes use CALayer.cornerCurve for Apple's platform-native
168
+ // compositor shape and are intentionally not pixel-identical cross-platform.
169
+ const CGFloat controlFactor =
170
+ curve == SmoothClipCornerCurveContinuous
171
+ ? 1.0
172
+ : 0.5522847498307936;
173
+
174
+ CGMutablePathRef path = CGPathCreateMutable();
175
+ CGPathMoveToPoint(path, NULL, minX + radii.topLeft, minY);
176
+ CGPathAddLineToPoint(path, NULL, maxX - radii.topRight, minY);
177
+ CGPathAddCurveToPoint(
178
+ path,
179
+ NULL,
180
+ maxX - radii.topRight + radii.topRight * controlFactor,
181
+ minY,
182
+ maxX,
183
+ minY + radii.topRight - radii.topRight * controlFactor,
184
+ maxX,
185
+ minY + radii.topRight);
186
+ CGPathAddLineToPoint(path, NULL, maxX, maxY - radii.bottomRight);
187
+ CGPathAddCurveToPoint(
188
+ path,
189
+ NULL,
190
+ maxX,
191
+ maxY - radii.bottomRight + radii.bottomRight * controlFactor,
192
+ maxX - radii.bottomRight +
193
+ radii.bottomRight * controlFactor,
194
+ maxY,
195
+ maxX - radii.bottomRight,
196
+ maxY);
197
+ CGPathAddLineToPoint(path, NULL, minX + radii.bottomLeft, maxY);
198
+ CGPathAddCurveToPoint(
199
+ path,
200
+ NULL,
201
+ minX + radii.bottomLeft - radii.bottomLeft * controlFactor,
202
+ maxY,
203
+ minX,
204
+ maxY - radii.bottomLeft + radii.bottomLeft * controlFactor,
205
+ minX,
206
+ maxY - radii.bottomLeft);
207
+ CGPathAddLineToPoint(path, NULL, minX, minY + radii.topLeft);
208
+ CGPathAddCurveToPoint(
209
+ path,
210
+ NULL,
211
+ minX,
212
+ minY + radii.topLeft - radii.topLeft * controlFactor,
213
+ minX + radii.topLeft - radii.topLeft * controlFactor,
214
+ minY,
215
+ minX + radii.topLeft,
216
+ minY);
217
+ CGPathCloseSubpath(path);
218
+ return path;
219
+ }