react-native-morph-card 0.2.8 → 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.
Files changed (36) hide show
  1. package/README.md +6 -4
  2. package/android/src/main/java/com/melivalesca/morphcard/MorphCardSourceManager.kt +8 -0
  3. package/android/src/main/java/com/melivalesca/morphcard/MorphCardSourceView.kt +49 -3
  4. package/android/src/main/java/com/melivalesca/morphcard/MorphCardTargetView.kt +41 -1
  5. package/ios/Fabric/RNCMorphCardSourceComponentView.mm +111 -10
  6. package/ios/Fabric/RNCMorphCardTargetComponentView.h +1 -0
  7. package/ios/Fabric/RNCMorphCardTargetComponentView.mm +21 -0
  8. package/lib/commonjs/MorphCardSource.js +29 -2
  9. package/lib/commonjs/MorphCardSource.js.map +1 -1
  10. package/lib/commonjs/MorphCardTarget.js +31 -7
  11. package/lib/commonjs/MorphCardTarget.js.map +1 -1
  12. package/lib/commonjs/MorphChildrenRegistry.js +34 -0
  13. package/lib/commonjs/MorphChildrenRegistry.js.map +1 -0
  14. package/lib/commonjs/specs/NativeMorphCardSource.js.map +1 -1
  15. package/lib/module/MorphCardSource.js +29 -2
  16. package/lib/module/MorphCardSource.js.map +1 -1
  17. package/lib/module/MorphCardTarget.js +31 -7
  18. package/lib/module/MorphCardTarget.js.map +1 -1
  19. package/lib/module/MorphChildrenRegistry.js +27 -0
  20. package/lib/module/MorphChildrenRegistry.js.map +1 -0
  21. package/lib/module/specs/NativeMorphCardSource.js.map +1 -1
  22. package/lib/typescript/src/MorphCardSource.d.ts +8 -4
  23. package/lib/typescript/src/MorphCardSource.d.ts.map +1 -1
  24. package/lib/typescript/src/MorphCardTarget.d.ts.map +1 -1
  25. package/lib/typescript/src/MorphChildrenRegistry.d.ts +13 -0
  26. package/lib/typescript/src/MorphChildrenRegistry.d.ts.map +1 -0
  27. package/lib/typescript/src/index.d.ts +1 -1
  28. package/lib/typescript/src/index.d.ts.map +1 -1
  29. package/lib/typescript/src/specs/NativeMorphCardSource.d.ts +2 -0
  30. package/lib/typescript/src/specs/NativeMorphCardSource.d.ts.map +1 -1
  31. package/package.json +1 -1
  32. package/src/MorphCardSource.tsx +33 -5
  33. package/src/MorphCardTarget.tsx +44 -9
  34. package/src/MorphChildrenRegistry.ts +43 -0
  35. package/src/index.tsx +1 -1
  36. package/src/specs/NativeMorphCardSource.ts +2 -0
package/README.md CHANGED
@@ -46,7 +46,7 @@ No additional steps required.
46
46
 
47
47
  Wrap your card content in `MorphCardSource`. On the detail screen, use `MorphCardTarget` where the card should land. Use `useMorphTarget` for easy collapse handling.
48
48
 
49
- > **Important:** `MorphCardSource` can wrap any React Native component (images, views, text, etc.), but during the animation the content is captured as a **bitmap snapshot**. This means dynamic or observable values (timers, animated values, live data) will freeze at the moment of capture. Design your card content with this in mind.
49
+ > **Important:** `MorphCardSource` can wrap any React Native component (images, views, text, etc.). During the animation, the content is captured as a **bitmap snapshot** — but once the animation completes, the snapshot fades out and the source's children are automatically cloned into `MorphCardTarget` as live React components. The cloned children are rendered at the source card's original layout dimensions, so your component layout stays consistent. This means observable values (timers, animated values, live data) will update in real time after the transition finishes. If you use `resizeMode`, the bitmap is kept instead (native image scaling doesn't apply to React components).
50
50
 
51
51
  ```tsx
52
52
  import React from 'react';
@@ -110,12 +110,14 @@ Wraps the card content on the list/grid screen. Captures a snapshot and drives t
110
110
  | `backgroundColor` | `string` | — | Background color (enables "wrapper mode" where the background expands separately from the content) |
111
111
  | `duration` | `number` | `300` | Default animation duration in ms (used for both expand and collapse if specific durations are not set) |
112
112
  | `expandDuration` | `number` | — | Duration of the expand animation in ms. Overrides `duration` for expand. |
113
- | `scaleMode` | `'aspectFill' \| 'aspectFit' \| 'stretch'` | `'aspectFill'` | How the snapshot scales during no-wrapper mode animation |
113
+ | `resizeMode` | `'cover' \| 'contain' \| 'stretch'` | `'cover'` | How the snapshot scales during animation. When set, the bitmap is kept after expand (no live children). **Recommended when wrapping an `<Image>` — without it, the image may not scale properly during the animation.** |
114
+ | `rotations` | `number` | `0` | Number of full 360° rotations during the expand animation |
115
+ | `rotationEndAngle`| `number` | `0` | Final rotation angle in degrees after expand (e.g. `45` to end tilted). Collapse reverses it back to 0 |
114
116
  | `onPress` | `(sourceTag: number) => void` | — | Called on tap with the native view tag. Use this to navigate to the detail screen. |
115
117
 
116
118
  ### `<MorphCardTarget>`
117
119
 
118
- Placed on the detail screen where the card should land. Triggers the expand animation on mount.
120
+ Placed on the detail screen where the card should land. Triggers the expand animation on mount. After the animation, the source's children are automatically cloned here as live React components.
119
121
 
120
122
  | Prop | Type | Default | Description |
121
123
  | ------------------ | ---------------- | ------------- | -------------------------------------------------------------------------------- |
@@ -161,7 +163,7 @@ await morphCollapse(sourceTag);
161
163
  const tag = getViewTag(viewRef);
162
164
  ```
163
165
 
164
- ````
166
+ ```
165
167
 
166
168
  ## Running the example app
167
169
 
@@ -38,6 +38,14 @@ class MorphCardSourceManager :
38
38
  view.borderRadiusDp = value.toFloat()
39
39
  }
40
40
 
41
+ override fun setRotations(view: MorphCardSourceView, value: Double) {
42
+ view.rotations = value
43
+ }
44
+
45
+ override fun setRotationEndAngle(view: MorphCardSourceView, value: Double) {
46
+ view.rotationEndAngle = value
47
+ }
48
+
41
49
  companion object {
42
50
  const val REACT_CLASS = "RNCMorphCardSource"
43
51
  }
@@ -33,6 +33,8 @@ class MorphCardSourceView(context: Context) : ReactViewGroup(context) {
33
33
  var expandDuration: Double = 0.0
34
34
  var scaleMode: String = "aspectFill"
35
35
  var borderRadiusDp: Float = 0f
36
+ var rotations: Double = 0.0
37
+ var rotationEndAngle: Double = 0.0
36
38
 
37
39
  // ── Target config (set by module, in dp from JS) ──
38
40
  var pendingTargetWidth: Float = 0f
@@ -527,6 +529,8 @@ class MorphCardSourceView(context: Context) : ReactViewGroup(context) {
527
529
  imageFrameForScaleMode(scaleMode, cardWidth, cardHeight, targetWidthPx, targetHeightPx)
528
530
  } else null
529
531
 
532
+ val totalAngle = (rotations * 360.0 + rotationEndAngle).toFloat()
533
+
530
534
  val animator = ValueAnimator.ofFloat(0f, 1f)
531
535
  animator.duration = dur
532
536
  animator.interpolator = springInterpolator
@@ -541,6 +545,7 @@ class MorphCardSourceView(context: Context) : ReactViewGroup(context) {
541
545
  lp.height = lerp(cardHeight, targetHeightPx, t).toInt()
542
546
  cardWrapper.layoutParams = lp
543
547
  setRoundedCorners(cardWrapper, lerp(cardCornerRadiusPx, targetCornerRadiusPx, t))
548
+ cardWrapper.rotation = lerp(0f, totalAngle, t)
544
549
 
545
550
  if (content != null) {
546
551
  if (hasWrapper) {
@@ -591,6 +596,11 @@ class MorphCardSourceView(context: Context) : ReactViewGroup(context) {
591
596
  }
592
597
  this@MorphCardSourceView.alpha = 1f
593
598
 
599
+ // Apply end rotation to target view
600
+ if (rotationEndAngle != 0.0) {
601
+ targetView?.rotation = rotationEndAngle.toFloat()
602
+ }
603
+
594
604
  transferSnapshotToTarget(decorView, wrapper, targetView,
595
605
  targetWidthPx, targetHeightPx, targetCornerRadiusPx, 200L)
596
606
 
@@ -655,6 +665,8 @@ class MorphCardSourceView(context: Context) : ReactViewGroup(context) {
655
665
 
656
666
  target.showSnapshot(bitmap, frame, cornerRadius, null)
657
667
  Log.d(TAG, "transferSnapshot: handed snapshot to MorphCardTargetView")
668
+ // Crossfade snapshot out to reveal live React children underneath
669
+ mainHandler.postDelayed({ target.fadeOutSnapshot() }, 50)
658
670
  }
659
671
 
660
672
  val fadeOut = ValueAnimator.ofFloat(1f, 0f)
@@ -716,6 +728,7 @@ class MorphCardSourceView(context: Context) : ReactViewGroup(context) {
716
728
  var wrapper = overlayContainer
717
729
  if (wrapper == null) {
718
730
  val target = targetView as? MorphCardTargetView
731
+ // Read position BEFORE clearing rotation — visual position depends on rotation
719
732
  val targetLoc = if (targetView != null) getLocationInWindow(targetView) else intArrayOf(cardLeft.toInt(), cardTop.toInt())
720
733
  val twPx = if (pendingTargetWidth > 0) pendingTargetWidth * d else cardWidth
721
734
  val thPx = if (pendingTargetHeight > 0) pendingTargetHeight * d else cardHeight
@@ -726,11 +739,15 @@ class MorphCardSourceView(context: Context) : ReactViewGroup(context) {
726
739
  val cardImage = captureSnapshot()
727
740
  alpha = 0f
728
741
 
729
- // Clear the snapshot from the target view
742
+ // Clear the snapshot from the target
730
743
  target?.clearSnapshot()
731
744
 
745
+ // Use target view's actual size if available for exact match
746
+ val wrapW = if (targetView != null && targetView.width > 0) targetView.width.toFloat() else twPx
747
+ val wrapH = if (targetView != null && targetView.height > 0) targetView.height.toFloat() else thPx
748
+
732
749
  wrapper = FrameLayout(context)
733
- wrapper.layoutParams = FrameLayout.LayoutParams(twPx.toInt(), thPx.toInt())
750
+ wrapper.layoutParams = FrameLayout.LayoutParams(wrapW.toInt(), wrapH.toInt())
734
751
  wrapper.x = targetLoc[0].toFloat()
735
752
  wrapper.y = targetLoc[1].toFloat()
736
753
  wrapper.clipChildren = true
@@ -760,8 +777,23 @@ class MorphCardSourceView(context: Context) : ReactViewGroup(context) {
760
777
  }
761
778
 
762
779
  wrapper.addView(content)
780
+ wrapper.translationZ = 1000f
781
+
782
+ // Match the target's exact rotation center by reading its actual size
783
+ val actualW = targetView?.width?.toFloat() ?: wrapW
784
+ val actualH = targetView?.height?.toFloat() ?: wrapH
785
+ // Clear target rotation first so getLocationInWindow gives un-rotated pos
786
+ // then position wrapper at same un-rotated pos with same rotation
787
+ targetView?.rotation = 0f
788
+ val unrotatedLoc = if (targetView != null) getLocationInWindow(targetView) else targetLoc
789
+ wrapper.x = unrotatedLoc[0].toFloat()
790
+ wrapper.y = unrotatedLoc[1].toFloat()
791
+ wrapper.layoutParams = FrameLayout.LayoutParams(actualW.toInt(), actualH.toInt())
792
+ wrapper.rotation = rotationEndAngle.toFloat()
793
+
763
794
  decorView.addView(wrapper)
764
795
  overlayContainer = wrapper
796
+ targetView?.visibility = View.INVISIBLE
765
797
  }
766
798
 
767
799
  // Show source screen underneath
@@ -782,9 +814,18 @@ class MorphCardSourceView(context: Context) : ReactViewGroup(context) {
782
814
  val startImgW = content?.layoutParams?.width?.toFloat() ?: cardWidth
783
815
  val startImgH = content?.layoutParams?.height?.toFloat() ?: cardHeight
784
816
 
817
+ // Lock pivot to center so rotation stays stable as size changes
818
+ if (rotationEndAngle != 0.0) {
819
+ wrapper.pivotX = startWidth / 2f
820
+ wrapper.pivotY = startHeight / 2f
821
+ }
822
+
823
+ // Match iOS collapse curve: cubic bezier (0.25, 1.0, 0.5, 1.0)
824
+ val collapseInterpolator = PathInterpolator(0.25f, 1.0f, 0.5f, 1.0f)
825
+
785
826
  val animator = ValueAnimator.ofFloat(0f, 1f)
786
827
  animator.duration = dur
787
- animator.interpolator = springInterpolator
828
+ animator.interpolator = collapseInterpolator
788
829
 
789
830
  animator.addUpdateListener { anim ->
790
831
  val t = anim.animatedValue as Float
@@ -795,6 +836,11 @@ class MorphCardSourceView(context: Context) : ReactViewGroup(context) {
795
836
  lp.height = lerp(startHeight, cardHeight, t).toInt()
796
837
  wrapper.layoutParams = lp
797
838
  setRoundedCorners(wrapper, lerp(startCr, cardCornerRadiusPx, t))
839
+ if (rotationEndAngle != 0.0) {
840
+ wrapper.rotation = lerp(rotationEndAngle.toFloat(), 0f, t)
841
+ wrapper.pivotX = lp.width / 2f
842
+ wrapper.pivotY = lp.height / 2f
843
+ }
798
844
 
799
845
  if (content != null) {
800
846
  if (hasWrapper) {
@@ -1,5 +1,6 @@
1
1
  package com.melivalesca.morphcard
2
2
 
3
+ import android.animation.ValueAnimator
3
4
  import android.content.Context
4
5
  import android.graphics.Bitmap
5
6
  import android.graphics.Canvas
@@ -21,6 +22,7 @@ class MorphCardTargetView(context: Context) : ReactViewGroup(context) {
21
22
  private var snapshotFrame: RectF? = null
22
23
  private var snapshotCornerRadius: Float = 0f
23
24
  private var snapshotBgColor: Int? = null
25
+ private var snapshotAlpha: Float = 1f
24
26
  private val snapshotPaint = Paint(Paint.ANTI_ALIAS_FLAG or Paint.FILTER_BITMAP_FLAG)
25
27
  private val bgPaint = Paint(Paint.ANTI_ALIAS_FLAG)
26
28
 
@@ -38,6 +40,8 @@ class MorphCardTargetView(context: Context) : ReactViewGroup(context) {
38
40
  screenContainer.visibility = View.INVISIBLE
39
41
  Log.d(TAG, "TargetView: set screen INVISIBLE")
40
42
  }
43
+ // Hide children until snapshot is in place to avoid flash of un-rotated content
44
+ hideChildren()
41
45
  }
42
46
  }
43
47
 
@@ -58,7 +62,9 @@ class MorphCardTargetView(context: Context) : ReactViewGroup(context) {
58
62
  override fun dispatchDraw(canvas: Canvas) {
59
63
  val bmp = snapshotBitmap
60
64
  val frame = snapshotFrame
61
- if (bmp != null && frame != null) {
65
+ if (bmp != null && frame != null && snapshotAlpha > 0f) {
66
+ snapshotPaint.alpha = (snapshotAlpha * 255).toInt()
67
+ bgPaint.alpha = (snapshotAlpha * 255).toInt()
62
68
  val radiusPx = snapshotCornerRadius
63
69
 
64
70
  // Clip to rounded rect if needed
@@ -114,6 +120,40 @@ class MorphCardTargetView(context: Context) : ReactViewGroup(context) {
114
120
  invalidate()
115
121
  }
116
122
 
123
+ fun showChildren() {
124
+ for (i in 0 until childCount) {
125
+ getChildAt(i).alpha = 1f
126
+ }
127
+ }
128
+
129
+ fun hideChildren() {
130
+ for (i in 0 until childCount) {
131
+ getChildAt(i).alpha = 0f
132
+ }
133
+ }
134
+
135
+ fun fadeOutSnapshot() {
136
+ if (snapshotBitmap == null) return
137
+ // Only fade out if there are React children underneath to reveal.
138
+ // If no children (scaleMode bitmap-only), keep the snapshot.
139
+ if (childCount == 0) return
140
+ val anim = ValueAnimator.ofFloat(1f, 0f)
141
+ anim.duration = 150
142
+ anim.addUpdateListener {
143
+ snapshotAlpha = it.animatedValue as Float
144
+ invalidate()
145
+ }
146
+ // Show children before snapshot fades so they're visible underneath
147
+ showChildren()
148
+ anim.addListener(object : android.animation.AnimatorListenerAdapter() {
149
+ override fun onAnimationEnd(animation: android.animation.Animator) {
150
+ clearSnapshot()
151
+ snapshotAlpha = 1f
152
+ }
153
+ })
154
+ anim.start()
155
+ }
156
+
117
157
  fun clearSnapshot() {
118
158
  if (snapshotBitmap != null) {
119
159
  Log.d(TAG, "clearSnapshot: clearing bitmap")
@@ -92,6 +92,8 @@ static CGRect imageFrameForScaleMode(UIViewContentMode mode,
92
92
  __weak UIView *_targetView;
93
93
  __weak UIView *_sourceScreenContainer;
94
94
  __weak UIView *_targetScreenContainer;
95
+ CGFloat _rotations;
96
+ CGFloat _rotationEndAngle;
95
97
  UIView *_wrapperView;
96
98
  UIImageView *_snapshot;
97
99
  }
@@ -124,6 +126,8 @@ static CGRect imageFrameForScaleMode(UIViewContentMode mode,
124
126
  } else {
125
127
  _scaleMode = UIViewContentModeScaleAspectFill;
126
128
  }
129
+ _rotations = newProps.rotations;
130
+ _rotationEndAngle = newProps.rotationEndAngle;
127
131
  [super updateProps:props oldProps:oldProps];
128
132
  }
129
133
 
@@ -293,17 +297,37 @@ static CGRect imageFrameForScaleMode(UIViewContentMode mode,
293
297
  ? (targetFrame.size.height - contentSize.height) / 2.0
294
298
  : contentOffsetY;
295
299
 
300
+ // Use bounds/center instead of frame so rotation transforms work correctly
301
+ CGFloat totalAngleDeg = _rotations * 360.0 + _rotationEndAngle;
302
+ CGFloat totalAngleRad = totalAngleDeg * M_PI / 180.0;
303
+ wrapper.bounds = CGRectMake(0, 0, _cardFrame.size.width, _cardFrame.size.height);
304
+ wrapper.center = CGPointMake(CGRectGetMidX(_cardFrame), CGRectGetMidY(_cardFrame));
305
+
296
306
  UIViewPropertyAnimator *animator = [[UIViewPropertyAnimator alloc]
297
307
  initWithDuration:dur
298
308
  dampingRatio:0.85
299
309
  animations:^{
300
- wrapper.frame = targetFrame;
310
+ wrapper.bounds = CGRectMake(0, 0, targetFrame.size.width, targetFrame.size.height);
311
+ wrapper.center = CGPointMake(CGRectGetMidX(targetFrame), CGRectGetMidY(targetFrame));
301
312
  wrapper.layer.cornerRadius = targetCornerRadius;
302
313
  content.frame = CGRectMake(targetCx, targetCy,
303
314
  contentSize.width,
304
315
  contentSize.height);
305
316
  }];
306
317
 
318
+ // Use CABasicAnimation for rotation — UIViewPropertyAnimator takes the
319
+ // shortest path and can't do multiple full spins.
320
+ if (totalAngleRad != 0) {
321
+ CABasicAnimation *rotAnim = [CABasicAnimation animationWithKeyPath:@"transform.rotation.z"];
322
+ rotAnim.fromValue = @(0);
323
+ rotAnim.toValue = @(totalAngleRad);
324
+ rotAnim.duration = dur;
325
+ rotAnim.timingFunction = [CAMediaTimingFunction functionWithControlPoints:0.25 :1.0 :0.5 :1.0];
326
+ rotAnim.fillMode = kCAFillModeForwards;
327
+ rotAnim.removedOnCompletion = NO;
328
+ [wrapper.layer addAnimation:rotAnim forKey:@"morphRotation"];
329
+ }
330
+
307
331
  // Hide the target view itself so it doesn't double-render over the morph overlay.
308
332
  if (targetView) {
309
333
  targetView.hidden = YES;
@@ -338,8 +362,20 @@ static CGRect imageFrameForScaleMode(UIViewContentMode mode,
338
362
  cornerRadius:targetCornerRadius
339
363
  backgroundColor:wrapperBg];
340
364
  }
365
+ // Crossfade snapshot out to reveal live React children underneath
366
+ dispatch_after(
367
+ dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.05 * NSEC_PER_SEC)),
368
+ dispatch_get_main_queue(), ^{
369
+ [target fadeOutSnapshot];
370
+ });
371
+ }
372
+ if (targetView) {
373
+ targetView.hidden = NO;
374
+ CGFloat endAngleRad = self->_rotationEndAngle * M_PI / 180.0;
375
+ if (endAngleRad != 0) {
376
+ targetView.transform = CGAffineTransformMakeRotation(endAngleRad);
377
+ }
341
378
  }
342
- if (targetView) { targetView.hidden = NO; }
343
379
  self.alpha = 1;
344
380
  UIView *ts = self->_targetScreenContainer;
345
381
  if (ts) { ts.alpha = 1; }
@@ -357,7 +393,9 @@ static CGRect imageFrameForScaleMode(UIViewContentMode mode,
357
393
  UIViewContentMode scaleMode = _scaleMode;
358
394
  CGSize imageSize = cardImage.size;
359
395
 
360
- UIView *container = [[UIView alloc] initWithFrame:_cardFrame];
396
+ UIView *container = [[UIView alloc] initWithFrame:CGRectZero];
397
+ container.bounds = CGRectMake(0, 0, _cardFrame.size.width, _cardFrame.size.height);
398
+ container.center = CGPointMake(CGRectGetMidX(_cardFrame), CGRectGetMidY(_cardFrame));
361
399
  container.clipsToBounds = YES;
362
400
  container.layer.cornerRadius = _cardCornerRadius;
363
401
 
@@ -382,15 +420,31 @@ static CGRect imageFrameForScaleMode(UIViewContentMode mode,
382
420
  CGRect targetImageFrame = imageFrameForScaleMode(
383
421
  scaleMode, imageSize, targetFrame.size);
384
422
 
423
+ CGFloat totalAngleDegNoWrap = _rotations * 360.0 + _rotationEndAngle;
424
+ CGFloat totalAngleRadNoWrap = totalAngleDegNoWrap * M_PI / 180.0;
425
+
385
426
  UIViewPropertyAnimator *animator = [[UIViewPropertyAnimator alloc]
386
427
  initWithDuration:dur
387
428
  dampingRatio:0.85
388
429
  animations:^{
389
- container.frame = targetFrame;
430
+ container.bounds = CGRectMake(0, 0, targetFrame.size.width, targetFrame.size.height);
431
+ container.center = CGPointMake(CGRectGetMidX(targetFrame), CGRectGetMidY(targetFrame));
390
432
  container.layer.cornerRadius = targetCornerRadius;
391
433
  snapshot.frame = targetImageFrame;
392
434
  }];
393
435
 
436
+ // Use CABasicAnimation for rotation — supports multiple full spins
437
+ if (totalAngleRadNoWrap != 0) {
438
+ CABasicAnimation *rotAnim = [CABasicAnimation animationWithKeyPath:@"transform.rotation.z"];
439
+ rotAnim.fromValue = @(0);
440
+ rotAnim.toValue = @(totalAngleRadNoWrap);
441
+ rotAnim.duration = dur;
442
+ rotAnim.timingFunction = [CAMediaTimingFunction functionWithControlPoints:0.25 :1.0 :0.5 :1.0];
443
+ rotAnim.fillMode = kCAFillModeForwards;
444
+ rotAnim.removedOnCompletion = NO;
445
+ [container.layer addAnimation:rotAnim forKey:@"morphRotation"];
446
+ }
447
+
394
448
  // Start fading in screen content early (at 15% of the animation).
395
449
  __weak RNCMorphCardSourceComponentView *weakSelf2 = self;
396
450
  dispatch_after(
@@ -414,8 +468,20 @@ static CGRect imageFrameForScaleMode(UIViewContentMode mode,
414
468
  frame:target.bounds
415
469
  cornerRadius:targetCornerRadius
416
470
  backgroundColor:nil];
471
+ // Crossfade snapshot out to reveal live React children underneath
472
+ dispatch_after(
473
+ dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.05 * NSEC_PER_SEC)),
474
+ dispatch_get_main_queue(), ^{
475
+ [target fadeOutSnapshot];
476
+ });
477
+ }
478
+ if (targetView) {
479
+ targetView.hidden = NO;
480
+ CGFloat endAngleRad = self->_rotationEndAngle * M_PI / 180.0;
481
+ if (endAngleRad != 0) {
482
+ targetView.transform = CGAffineTransformMakeRotation(endAngleRad);
483
+ }
417
484
  }
418
- if (targetView) { targetView.hidden = NO; }
419
485
  self.alpha = 1;
420
486
  UIView *ts = self->_targetScreenContainer;
421
487
  if (ts) { ts.alpha = 1; }
@@ -447,9 +513,12 @@ static CGRect imageFrameForScaleMode(UIViewContentMode mode,
447
513
  UIView *targetScreen = _targetScreenContainer;
448
514
  UIView *sourceScreen = _sourceScreenContainer;
449
515
 
450
- // Clear the snapshot from the target view before re-creating the overlay
516
+ // Clear the snapshot and hide the target view so live children
517
+ // don't show behind the animating collapse overlay
451
518
  if (targetView && [targetView isKindOfClass:[RNCMorphCardTargetComponentView class]]) {
452
519
  [(RNCMorphCardTargetComponentView *)targetView clearSnapshot];
520
+ targetView.hidden = YES;
521
+ targetView.transform = CGAffineTransformIdentity;
453
522
  }
454
523
 
455
524
  CGFloat collapseDur = 0;
@@ -479,7 +548,9 @@ static CGRect imageFrameForScaleMode(UIViewContentMode mode,
479
548
  ? (targetFrame.size.height - contentSize.height) / 2.0
480
549
  : contentOffsetY;
481
550
 
482
- wrapper = [[UIView alloc] initWithFrame:targetFrame];
551
+ wrapper = [[UIView alloc] initWithFrame:CGRectZero];
552
+ wrapper.bounds = CGRectMake(0, 0, targetFrame.size.width, targetFrame.size.height);
553
+ wrapper.center = CGPointMake(CGRectGetMidX(targetFrame), CGRectGetMidY(targetFrame));
483
554
  wrapper.backgroundColor = self.backgroundColor;
484
555
  wrapper.layer.cornerRadius = targetCornerRadius;
485
556
  wrapper.clipsToBounds = YES;
@@ -508,13 +579,27 @@ static CGRect imageFrameForScaleMode(UIViewContentMode mode,
508
579
  initWithDuration:dur
509
580
  timingParameters:timing];
510
581
  [animator addAnimations:^{
511
- wrapper.frame = self->_cardFrame;
582
+ wrapper.bounds = CGRectMake(0, 0, self->_cardFrame.size.width, self->_cardFrame.size.height);
583
+ wrapper.center = CGPointMake(CGRectGetMidX(self->_cardFrame), CGRectGetMidY(self->_cardFrame));
512
584
  wrapper.layer.cornerRadius = self->_cardCornerRadius;
513
585
  if (content) {
514
586
  content.frame = (CGRect){CGPointZero, content.frame.size};
515
587
  }
516
588
  }];
517
589
 
590
+ // Animate rotation back to 0
591
+ CGFloat collapseStartAngle = _rotationEndAngle * M_PI / 180.0;
592
+ if (collapseStartAngle != 0) {
593
+ CABasicAnimation *rotAnim = [CABasicAnimation animationWithKeyPath:@"transform.rotation.z"];
594
+ rotAnim.fromValue = @(collapseStartAngle);
595
+ rotAnim.toValue = @(0);
596
+ rotAnim.duration = dur;
597
+ rotAnim.timingFunction = [CAMediaTimingFunction functionWithControlPoints:0.25 :1.0 :0.5 :1.0];
598
+ rotAnim.fillMode = kCAFillModeForwards;
599
+ rotAnim.removedOnCompletion = NO;
600
+ [wrapper.layer addAnimation:rotAnim forKey:@"morphRotation"];
601
+ }
602
+
518
603
  // Fade out target screen
519
604
  [self scheduleScreenFadeOut:targetScreen duration:dur];
520
605
 
@@ -542,7 +627,9 @@ static CGRect imageFrameForScaleMode(UIViewContentMode mode,
542
627
  CGRect imageFrame = imageFrameForScaleMode(
543
628
  _scaleMode, imageSize, targetFrame.size);
544
629
 
545
- container = [[UIView alloc] initWithFrame:targetFrame];
630
+ container = [[UIView alloc] initWithFrame:CGRectZero];
631
+ container.bounds = CGRectMake(0, 0, targetFrame.size.width, targetFrame.size.height);
632
+ container.center = CGPointMake(CGRectGetMidX(targetFrame), CGRectGetMidY(targetFrame));
546
633
  container.clipsToBounds = YES;
547
634
  container.layer.cornerRadius = targetCornerRadius;
548
635
 
@@ -568,11 +655,25 @@ static CGRect imageFrameForScaleMode(UIViewContentMode mode,
568
655
  initWithDuration:dur
569
656
  timingParameters:timing];
570
657
  [animator addAnimations:^{
571
- container.frame = self->_cardFrame;
658
+ container.bounds = CGRectMake(0, 0, self->_cardFrame.size.width, self->_cardFrame.size.height);
659
+ container.center = CGPointMake(CGRectGetMidX(self->_cardFrame), CGRectGetMidY(self->_cardFrame));
572
660
  container.layer.cornerRadius = self->_cardCornerRadius;
573
661
  snapshot.frame = (CGRect){CGPointZero, self->_cardFrame.size};
574
662
  }];
575
663
 
664
+ // Animate rotation back to 0
665
+ CGFloat collapseStartAngleNW = _rotationEndAngle * M_PI / 180.0;
666
+ if (collapseStartAngleNW != 0) {
667
+ CABasicAnimation *rotAnim = [CABasicAnimation animationWithKeyPath:@"transform.rotation.z"];
668
+ rotAnim.fromValue = @(collapseStartAngleNW);
669
+ rotAnim.toValue = @(0);
670
+ rotAnim.duration = dur;
671
+ rotAnim.timingFunction = [CAMediaTimingFunction functionWithControlPoints:0.25 :1.0 :0.5 :1.0];
672
+ rotAnim.fillMode = kCAFillModeForwards;
673
+ rotAnim.removedOnCompletion = NO;
674
+ [container.layer addAnimation:rotAnim forKey:@"morphRotation"];
675
+ }
676
+
576
677
  // Fade out target screen
577
678
  [self scheduleScreenFadeOut:targetScreen duration:dur];
578
679
 
@@ -14,6 +14,7 @@ NS_ASSUME_NONNULL_BEGIN
14
14
  frame:(CGRect)frame
15
15
  cornerRadius:(CGFloat)cornerRadius
16
16
  backgroundColor:(nullable UIColor *)bgColor;
17
+ - (void)fadeOutSnapshot;
17
18
  - (void)clearSnapshot;
18
19
 
19
20
  @end
@@ -72,6 +72,27 @@ extern UIView *RNCMorphCardFindScreenContainer(UIView *view);
72
72
  _snapshotContainer = container;
73
73
  }
74
74
 
75
+ - (void)fadeOutSnapshot {
76
+ UIView *snap = _snapshotContainer;
77
+ if (!snap) return;
78
+ // Only fade out if there are React children underneath to reveal.
79
+ // If no children (scaleMode bitmap-only), keep the snapshot.
80
+ BOOL hasReactChildren = NO;
81
+ for (UIView *child in self.subviews) {
82
+ if (child != _snapshotContainer) { hasReactChildren = YES; break; }
83
+ }
84
+ if (!hasReactChildren) return;
85
+
86
+ [UIView animateWithDuration:0.15
87
+ animations:^{ snap.alpha = 0; }
88
+ completion:^(BOOL finished) {
89
+ [snap removeFromSuperview];
90
+ if (self->_snapshotContainer == snap) {
91
+ self->_snapshotContainer = nil;
92
+ }
93
+ }];
94
+ }
95
+
75
96
  - (void)clearSnapshot {
76
97
  if (_snapshotContainer) {
77
98
  [_snapshotContainer removeFromSuperview];
@@ -11,6 +11,7 @@ var React = _interopRequireWildcard(require("react"));
11
11
  var _reactNative = require("react-native");
12
12
  var _NativeMorphCardModule = _interopRequireDefault(require("./specs/NativeMorphCardModule"));
13
13
  var _NativeMorphCardSource = _interopRequireDefault(require("./specs/NativeMorphCardSource"));
14
+ var _MorphChildrenRegistry = require("./MorphChildrenRegistry");
14
15
  var _jsxRuntime = require("react/jsx-runtime");
15
16
  function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
16
17
  function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r = new WeakMap(), n = new WeakMap(); return (_interopRequireWildcard = function (e, t) { if (!t && e && e.__esModule) return e; var o, i, f = { __proto__: null, default: e }; if (null === e || "object" != typeof e && "function" != typeof e) return f; if (o = t ? n : r) { if (o.has(e)) return o.get(e); o.set(e, f); } for (const t in e) "default" !== t && {}.hasOwnProperty.call(e, t) && ((i = (o = Object.defineProperty) && Object.getOwnPropertyDescriptor(e, t)) && (i.get || i.set) ? o(f, t, i) : f[t] = e[t]); return f; })(e, t); }
@@ -23,12 +24,25 @@ const MorphCardSource = ({
23
24
  height,
24
25
  borderRadius,
25
26
  backgroundColor,
26
- scaleMode,
27
+ resizeMode,
28
+ rotations,
29
+ rotationEndAngle,
27
30
  onPress,
28
31
  ref
29
32
  }) => {
30
33
  const nativeRef = React.useRef(null);
31
34
  React.useImperativeHandle(ref, () => nativeRef.current);
35
+
36
+ // Store children in shared registry so MorphCardTarget can clone them
37
+ React.useEffect(() => {
38
+ const tag = (0, _reactNative.findNodeHandle)(nativeRef.current);
39
+ if (tag != null) {
40
+ (0, _MorphChildrenRegistry.setSourceEntry)(tag, children, backgroundColor, resizeMode);
41
+ }
42
+ return () => {
43
+ if (tag != null) (0, _MorphChildrenRegistry.clearSourceEntry)(tag);
44
+ };
45
+ }, [children, backgroundColor, resizeMode]);
32
46
  const style = {};
33
47
  if (width != null) style.width = width;
34
48
  if (height != null) style.height = height;
@@ -37,6 +51,16 @@ const MorphCardSource = ({
37
51
  style.overflow = 'hidden';
38
52
  }
39
53
  if (backgroundColor != null) style.backgroundColor = backgroundColor;
54
+ const handleLayout = React.useCallback(e => {
55
+ const tag = (0, _reactNative.findNodeHandle)(nativeRef.current);
56
+ if (tag != null) {
57
+ const {
58
+ width: lw,
59
+ height: lh
60
+ } = e.nativeEvent.layout;
61
+ (0, _MorphChildrenRegistry.setSourceLayout)(tag, lw, lh);
62
+ }
63
+ }, []);
40
64
  const handlePress = React.useCallback(() => {
41
65
  if (!onPress) return;
42
66
  const tag = (0, _reactNative.findNodeHandle)(nativeRef.current);
@@ -52,9 +76,12 @@ const MorphCardSource = ({
52
76
  ref: nativeRef,
53
77
  duration: duration,
54
78
  expandDuration: expandDuration,
55
- scaleMode: scaleMode,
79
+ scaleMode: resizeMode === 'contain' ? 'aspectFit' : resizeMode === 'stretch' ? 'stretch' : 'aspectFill',
56
80
  cardBorderRadius: borderRadius,
81
+ rotations: rotations,
82
+ rotationEndAngle: rotationEndAngle,
57
83
  style: style,
84
+ onLayout: handleLayout,
58
85
  children: children
59
86
  });
60
87
  if (onPress) {
@@ -1 +1 @@
1
- {"version":3,"names":["React","_interopRequireWildcard","require","_reactNative","_NativeMorphCardModule","_interopRequireDefault","_NativeMorphCardSource","_jsxRuntime","e","__esModule","default","t","WeakMap","r","n","o","i","f","__proto__","has","get","set","hasOwnProperty","call","Object","defineProperty","getOwnPropertyDescriptor","NativeSourceView","NativeSourceViewSpec","View","MorphCardSource","children","duration","expandDuration","width","height","borderRadius","backgroundColor","scaleMode","onPress","ref","nativeRef","useRef","useImperativeHandle","current","style","overflow","handlePress","useCallback","tag","findNodeHandle","NativeMorphCardModule","prepareExpand","requestAnimationFrame","content","jsx","cardBorderRadius","Pressable","exports","getViewTag","viewRef","morphExpand","sourceRef","targetRef","sourceTag","targetTag","expand","morphCollapse","collapse"],"sourceRoot":"../../src","sources":["MorphCardSource.tsx"],"mappings":"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","ignoreList":[]}
1
+ {"version":3,"names":["React","_interopRequireWildcard","require","_reactNative","_NativeMorphCardModule","_interopRequireDefault","_NativeMorphCardSource","_MorphChildrenRegistry","_jsxRuntime","e","__esModule","default","t","WeakMap","r","n","o","i","f","__proto__","has","get","set","hasOwnProperty","call","Object","defineProperty","getOwnPropertyDescriptor","NativeSourceView","NativeSourceViewSpec","View","MorphCardSource","children","duration","expandDuration","width","height","borderRadius","backgroundColor","resizeMode","rotations","rotationEndAngle","onPress","ref","nativeRef","useRef","useImperativeHandle","current","useEffect","tag","findNodeHandle","setSourceEntry","clearSourceEntry","style","overflow","handleLayout","useCallback","lw","lh","nativeEvent","layout","setSourceLayout","handlePress","NativeMorphCardModule","prepareExpand","requestAnimationFrame","content","jsx","scaleMode","cardBorderRadius","onLayout","Pressable","exports","getViewTag","viewRef","morphExpand","sourceRef","targetRef","sourceTag","targetTag","expand","morphCollapse","collapse"],"sourceRoot":"../../src","sources":["MorphCardSource.tsx"],"mappings":"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","ignoreList":[]}