IjzerenHein / IjzerenHein/react-native-shared-element

Incompatible with react-native 0.76 on iOS due to border radii

Open
#125 6 comments 7 reactions 0 assignees View on GitHub
ios needs repro
Dominant language
TypeScript
Stars
2.3k
Forks
113
PR merge metrics
No merged PRs in 30d

Description

There were some changes to RCTCornerRadii in 0.76: https://github.com/facebook/react-native/pull/46009. This causes this package to error during compilation for iOS.

I made a quick patch with [patch-package](https://www.npmjs.com/package/patch-package). I've done some brief tests and it seems to work. This assumes all your border radii are symmetric, so a real PR would need to take asymmetric values into account. Also this patch is not backwards compatible.

`patches/react-native-shared-element+0.8.9.patch`:
```patch
diff --git a/node_modules/react-native-shared-element/ios/RNSharedElementCornerRadii.m b/node_modules/react-native-shared-element/ios/RNSharedElementCornerRadii.m
index 5060067..413281a 100644
--- a/node_modules/react-native-shared-element/ios/RNSharedElementCornerRadii.m
+++ b/node_modules/react-native-shared-element/ios/RNSharedElementCornerRadii.m
@@ -69,8 +69,8 @@ static CGFloat RNSharedElementDefaultIfNegativeTo(CGFloat defaultValue, CGFloat
CALayer *mask = nil;
CGFloat cornerRadius = 0;

- if (RCTCornerRadiiAreEqual(radii)) {
- cornerRadius = radii.topLeft;
+ if (RCTCornerRadiiAreEqualAndSymmetrical(radii)) {
+ cornerRadius = radii.topLeftHorizontal;
} else {
CAShapeLayer *shapeLayer = [CAShapeLayer layer];
RCTCornerInsets cornerInsets = RCTGetCornerInsets(radii, UIEdgeInsetsZero);
@@ -121,36 +121,52 @@ static CGFloat RNSharedElementDefaultIfNegativeTo(CGFloat defaultValue, CGFloat
const CGFloat directionAwareBottomLeftRadius = isRTL ? bottomEndRadius : bottomStartRadius;
const CGFloat directionAwareBottomRightRadius = isRTL ? bottomStartRadius : bottomEndRadius;

- result.topLeft = RNSharedElementDefaultIfNegativeTo(radius, directionAwareTopLeftRadius);
- result.topRight = RNSharedElementDefaultIfNegativeTo(radius, directionAwareTopRightRadius);
- result.bottomLeft = RNSharedElementDefaultIfNegativeTo(radius, directionAwareBottomLeftRadius);
- result.bottomRight = RNSharedElementDefaultIfNegativeTo(radius, directionAwareBottomRightRadius);
+ result.topLeftHorizontal = RNSharedElementDefaultIfNegativeTo(radius, directionAwareTopLeftRadius);
+ result.topRightHorizontal = RNSharedElementDefaultIfNegativeTo(radius, directionAwareTopRightRadius);
+ result.bottomLeftHorizontal = RNSharedElementDefaultIfNegativeTo(radius, directionAwareBottomLeftRadius);
+ result.bottomRightHorizontal = RNSharedElementDefaultIfNegativeTo(radius, directionAwareBottomRightRadius);
+ result.topLeftVertical = RNSharedElementDefaultIfNegativeTo(radius, directionAwareTopLeftRadius);
+ result.topRightVertical = RNSharedElementDefaultIfNegativeTo(radius, directionAwareTopRightRadius);
+ result.bottomLeftVertical = RNSharedElementDefaultIfNegativeTo(radius, directionAwareBottomLeftRadius);
+ result.bottomRightVertical = RNSharedElementDefaultIfNegativeTo(radius, directionAwareBottomRightRadius);
} else {
const CGFloat directionAwareTopLeftRadius = isRTL ? _radii[RNSharedElementCornerTopEnd] : _radii[RNSharedElementCornerTopStart];
const CGFloat directionAwareTopRightRadius = isRTL ? _radii[RNSharedElementCornerTopStart] : _radii[RNSharedElementCornerTopEnd];
const CGFloat directionAwareBottomLeftRadius = isRTL ? _radii[RNSharedElementCornerBottomEnd] : _radii[RNSharedElementCornerBottomStart];
const CGFloat directionAwareBottomRightRadius = isRTL ? _radii[RNSharedElementCornerBottomStart] : _radii[RNSharedElementCornerBottomEnd];

- result.topLeft =
+ result.topLeftHorizontal =
RNSharedElementDefaultIfNegativeTo(radius, RNSharedElementDefaultIfNegativeTo(_radii[RNSharedElementCornerTopLeft], directionAwareTopLeftRadius));
- result.topRight =
+ result.topRightHorizontal =
RNSharedElementDefaultIfNegativeTo(radius, RNSharedElementDefaultIfNegativeTo(_radii[RNSharedElementCornerTopRight], directionAwareTopRightRadius));
- result.bottomLeft =
+ result.bottomLeftHorizontal =
RNSharedElementDefaultIfNegativeTo(radius, RNSharedElementDefaultIfNegativeTo(_radii[RNSharedElementCornerBottomLeft], directionAwareBottomLeftRadius));
- result.bottomRight = RNSharedElementDefaultIfNegativeTo(
+ result.bottomRightHorizontal = RNSharedElementDefaultIfNegativeTo(
+ radius, RNSharedElementDefaultIfNegativeTo(_radii[RNSharedElementCornerBottomRight], directionAwareBottomRightRadius));
+ result.topLeftVertical =
+ RNSharedElementDefaultIfNegativeTo(radius, RNSharedElementDefaultIfNegativeTo(_radii[RNSharedElementCornerTopLeft], directionAwareTopLeftRadius));
+ result.topRightVertical =
+ RNSharedElementDefaultIfNegativeTo(radius, RNSharedElementDefaultIfNegativeTo(_radii[RNSharedElementCornerTopRight], directionAwareTopRightRadius));
+ result.bottomLeftVertical =
+ RNSharedElementDefaultIfNegativeTo(radius, RNSharedElementDefaultIfNegativeTo(_radii[RNSharedElementCornerBottomLeft], directionAwareBottomLeftRadius));
+ result.bottomRightVertical = RNSharedElementDefaultIfNegativeTo(
radius, RNSharedElementDefaultIfNegativeTo(_radii[RNSharedElementCornerBottomRight], directionAwareBottomRightRadius));
}

// Get scale factors required to prevent radii from overlapping
- const CGFloat topScaleFactor = RCTZeroIfNaN(MIN(1, bounds.size.width / (result.topLeft + result.topRight)));
- const CGFloat bottomScaleFactor = RCTZeroIfNaN(MIN(1, bounds.size.width / (result.bottomLeft + result.bottomRight)));
- const CGFloat rightScaleFactor = RCTZeroIfNaN(MIN(1, bounds.size.height / (result.topRight + result.bottomRight)));
- const CGFloat leftScaleFactor = RCTZeroIfNaN(MIN(1, bounds.size.height / (result.topLeft + result.bottomLeft)));
-
- result.topLeft *= MIN(topScaleFactor, leftScaleFactor);
- result.topRight *= MIN(topScaleFactor, rightScaleFactor);
- result.bottomLeft *= MIN(bottomScaleFactor, leftScaleFactor);
- result.bottomRight *= MIN(bottomScaleFactor, rightScaleFactor);
+ const CGFloat topScaleFactor = RCTZeroIfNaN(MIN(1, bounds.size.width / (result.topLeftHorizontal + result.topRightHorizontal)));
+ const CGFloat bottomScaleFactor = RCTZeroIfNaN(MIN(1, bounds.size.width / (result.bottomLeftHorizontal + result.bottomRightHorizontal)));
+ const CGFloat rightScaleFactor = RCTZeroIfNaN(MIN(1, bounds.size.height / (result.topRightHorizontal + result.bottomRightHorizontal)));
+ const CGFloat leftScaleFactor = RCTZeroIfNaN(MIN(1, bounds.size.height / (result.topLeftHorizontal + result.bottomLeftHorizontal)));
+
+ result.topLeftHorizontal *= MIN(topScaleFactor, leftScaleFactor);
+ result.topRightHorizontal *= MIN(topScaleFactor, rightScaleFactor);
+ result.bottomLeftHorizontal *= MIN(bottomScaleFactor, leftScaleFactor);
+ result.bottomRightHorizontal *= MIN(bottomScaleFactor, rightScaleFactor);
+ result.topLeftVertical *= MIN(topScaleFactor, leftScaleFactor);
+ result.topRightVertical *= MIN(topScaleFactor, rightScaleFactor);
+ result.bottomLeftVertical *= MIN(bottomScaleFactor, leftScaleFactor);
+ result.bottomRightVertical *= MIN(bottomScaleFactor, rightScaleFactor);

_cachedBounds = bounds;
_cachedRadii = result;
diff --git a/node_modules/react-native-shared-element/ios/RNSharedElementStyle.m b/node_modules/react-native-shared-element/ios/RNSharedElementStyle.m
index 9f65b9d..6ae25d8 100644
--- a/node_modules/react-native-shared-element/ios/RNSharedElementStyle.m
+++ b/node_modules/react-native-shared-element/ios/RNSharedElementStyle.m
@@ -112,10 +112,10 @@
CGRect radiiRect = CGRectMake(0, 0, 1000000, 1000000);
RCTCornerRadii radii1 = [style1.cornerRadii radiiForBounds:radiiRect];
RCTCornerRadii radii2 = [style2.cornerRadii radiiForBounds:radiiRect];
- [style.cornerRadii setRadius:radii1.topLeft + ((radii2.topLeft - radii1.topLeft) * position) corner:RNSharedElementCornerTopLeft];
- [style.cornerRadii setRadius:radii1.topRight + ((radii2.topRight - radii1.topRight) * position) corner:RNSharedElementCornerTopRight];
- [style.cornerRadii setRadius:radii1.bottomLeft + ((radii2.bottomLeft - radii1.bottomLeft) * position) corner:RNSharedElementCornerBottomLeft];
- [style.cornerRadii setRadius:radii1.bottomRight + ((radii2.bottomRight - radii1.bottomRight) * position) corner:RNSharedElementCornerBottomRight];
+ [style.cornerRadii setRadius:radii1.topLeftHorizontal + ((radii2.topLeftHorizontal - radii1.topLeftHorizontal) * position) corner:RNSharedElementCornerTopLeft];
+ [style.cornerRadii setRadius:radii1.topRightHorizontal + ((radii2.topRightHorizontal - radii1.topRightHorizontal) * position) corner:RNSharedElementCornerTopRight];
+ [style.cornerRadii setRadius:radii1.bottomLeftHorizontal + ((radii2.bottomLeftHorizontal - radii1.bottomLeftHorizontal) * position) corner:RNSharedElementCornerBottomLeft];
+ [style.cornerRadii setRadius:radii1.bottomRightHorizontal + ((radii2.bottomRightHorizontal - radii1.bottomRightHorizontal) * position) corner:RNSharedElementCornerBottomRight];

style.borderWidth = style1.borderWidth + ((style2.borderWidth - style1.borderWidth) * position);
style.borderColor = [RNSharedElementStyle getInterpolatedColor:style1.borderColor color2:style2.borderColor position:position];
diff --git a/node_modules/react-native-shared-element/ios/RNSharedElementTransition.m b/node_modules/react-native-shared-element/ios/RNSharedElementTransition.m
index 97de533..dbd1d66 100644
--- a/node_modules/react-native-shared-element/ios/RNSharedElementTransition.m
+++ b/node_modules/react-native-shared-element/ios/RNSharedElementTransition.m
@@ -388,10 +388,10 @@
},
@"contentType": item.content ? item.content.typeName : @"none",
@"style": @{
- @"borderTopLeftRadius": @(cornerRadii.topLeft),
- @"borderTopRightRadius": @(cornerRadii.topRight),
- @"borderBottomLeftRadius": @(cornerRadii.bottomLeft),
- @"borderBotomRightRadius": @(cornerRadii.bottomRight)
+ @"borderTopLeftRadius": @(cornerRadii.topLeftHorizontal),
+ @"borderTopRightRadius": @(cornerRadii.topRightHorizontal),
+ @"borderBottomLeftRadius": @(cornerRadii.bottomLeftHorizontal),
+ @"borderBotomRightRadius": @(cornerRadii.bottomRightHorizontal)
}
};
self.onMeasureNode(eventData);
```

Contributor guide

No contributing guide indexed for this repository

Research direction

Start by comparing the React Native 0.76 RCTCornerRadii changes with ios/RNSharedElementCornerRadii.m, ios/RNSharedElementStyle.m, and ios/RNSharedElementTransition.m. Verify the iOS package compiles against React Native 0.76 and that the resulting handling covers asymmetric radii without breaking supported versions.

Written by the indexing model from the issue text.

Assessment

Tech stack
objective-c, react-native
Domain
mobile
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
42/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.