Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Add logical border radius implementation #35572

Conversation

gabrieldonadel
Copy link
Collaborator

@gabrieldonadel gabrieldonadel commented Dec 6, 2022

Summary

This PR implements logical border-radius as requested on #34425. This implementation includes the addition of the following style properties

  • borderEndEndRadius, equivalent to borderBottomEndRadius.
  • borderEndStartRadius, equivalent to borderBottomStartRadius.
  • borderStartEndRadius, equivalent to borderTopEndRadius.
  • borderStartStartRadius, equivalent to borderTopStartRadius.

Changelog

[GENERAL] [ADDED] - Add logical border-radius implementation

Test Plan

  1. Open the RNTester app and navigate to the RTLExample page
  2. Test the new style properties through the Logical Border Radii Start/End section
Screen.Recording.2022-12-09.at.01.24.01.mov

@facebook-github-bot facebook-github-bot added the CLA Signed This label is managed by the Facebook bot. Authors need to sign the CLA before a PR can be reviewed. label Dec 6, 2022
@gabrieldonadel
Copy link
Collaborator Author

@NickGerleman quick question, on #35342 you used CompactValue for all new props but here I need to assign this to a CGFloat, do you know what's the easiest way to achieve that?

@NickGerleman
Copy link
Contributor

NickGerleman commented Dec 6, 2022

I think this change might need to take a different approach. borderRadius isn't used by or forwarded to Yoga, so I would think this change will no-op. I think if we wanted to do this in native we would need to do it in the separate iOS and Android view managers.

@NickGerleman
Copy link
Contributor

I think what controls this on Android for both Paper and Fabric are all of the setBorderRadius functions in ReactAndroid bound to ViewProps.BORDER_RADIUS and similar.

The layout props are reused between all views/platforms in Fabric, which is why we can get away with an easy native implementation for it. But for props that control style different from positioning/sizing, the implementation gets a bit more involved.

@gabrieldonadel
Copy link
Collaborator Author

Thanks for the explanation @NickGerleman! I'll update this PR so we use this other approach

@gabrieldonadel gabrieldonadel changed the title feat: Add Fabric logical border radius implementation feat: Add logical border radius implementation Dec 8, 2022
@analysis-bot
Copy link

analysis-bot commented Dec 8, 2022

Platform Engine Arch Size (bytes) Diff
ios - universal n/a --

Base commit: a3c47d3
Branch: main

@analysis-bot
Copy link

analysis-bot commented Dec 8, 2022

Platform Engine Arch Size (bytes) Diff
android hermes arm64-v8a 7,778,726 +1,923
android hermes armeabi-v7a 7,098,626 +2,033
android hermes x86 8,253,461 +1,756
android hermes x86_64 8,111,220 +2,139
android jsc arm64-v8a 8,971,312 +1,693
android jsc armeabi-v7a 7,704,507 +1,805
android jsc x86 9,035,307 +1,540
android jsc x86_64 9,512,632 +1,917

Base commit: a3c47d3
Branch: main

@pull-bot
Copy link

pull-bot commented Dec 8, 2022

PR build artifact for 9bafd39 is ready.
To use, download tarball from "Artifacts" tab in this CircleCI job then run yarn add <path to tarball> in your React Native project.

@gabrieldonadel
Copy link
Collaborator Author

Hi @NickGerleman I managed to get this working on iOS on both Fabric and Paper, do you mind taking a look at this PR to check if I'm going in the right direction? I am not too familiar with Yoga so I could have implemented something totally off by accident

@pull-bot
Copy link

pull-bot commented Dec 9, 2022

PR build artifact for 47972c0 is ready.
To use, download tarball from "Artifacts" tab in this CircleCI job then run yarn add <path to tarball> in your React Native project.

@pull-bot
Copy link

PR build artifact for dae78fd is ready.
To use, download tarball from "Artifacts" tab in this CircleCI job then run yarn add <path to tarball> in your React Native project.

@gabrieldonadel gabrieldonadel marked this pull request as ready for review December 12, 2022 12:32
@pull-bot
Copy link

PR build artifact for b0dcb5a is ready.
To use, download tarball from "Artifacts" tab in this CircleCI job then run yarn add <path to tarball> in your React Native project.

@gabrieldonadel
Copy link
Collaborator Author

@necolas just FYI this is now ready for review

Copy link
Contributor

@NickGerleman NickGerleman left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is great work! I know this sort of change is a lot of pattern matching, so I will mostly defer to that this has been validated for the Matrix of iOS/Android Paper/Fabric, since this touches each of those slices.

I left a couple comments on the implementation, with the main one around how we should give precedence to cardinal directions over flow relative directions for consistency with the resolution of existing props.

Ideally we would add some UI tests with this change to validate it, but the infra to do that from OSS isn't really there yet. Though @necolas or I could potentially followup since there is some Meta internal infrastructure to do visual similarity (screenshot) testing of specific views inside RNTester.

const CGFloat topEndRadius = RCTDefaultIfNegativeTo(_borderTopRightRadius, _borderTopEndRadius);
const CGFloat bottomStartRadius = RCTDefaultIfNegativeTo(_borderBottomLeftRadius, _borderBottomStartRadius);
const CGFloat bottomEndRadius = RCTDefaultIfNegativeTo(_borderBottomRightRadius, _borderBottomEndRadius);
const CGFloat topStartRadius = RCTDefaultIfNegativeTo(_borderTopLeftRadius, _borderStartStartRadius > 0 ? _borderStartStartRadius: _borderTopStartRadius);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think > 0 is the correct check, since it would mean we would ignore something setting the value to 0. On this line it looks like RCTDefaultIfNegativeTo is also already being used to set precedence, so mixing it with a ternary doing the same is a little confusing.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah good point, I guess we could check for > -1 as all _border**Radius variables are initialized using -1, but I've refactored this a bit to remove the ternaries and now everything is using RCTDefaultIfNegativeTo

const CGFloat bottomEndRadius = RCTDefaultIfNegativeTo(_borderBottomRightRadius, _borderBottomEndRadius);
const CGFloat topStartRadius = RCTDefaultIfNegativeTo(_borderTopLeftRadius, _borderStartStartRadius > 0 ? _borderStartStartRadius: _borderTopStartRadius);
const CGFloat topEndRadius = RCTDefaultIfNegativeTo(_borderTopRightRadius, _borderStartEndRadius > 0 ? _borderStartEndRadius: _borderTopEndRadius);
const CGFloat bottomStartRadius = RCTDefaultIfNegativeTo(_borderBottomLeftRadius, _borderEndStartRadius > 0 ? _borderEndStartRadius: _borderBottomStartRadius);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For consistency with other properties here (and Yoga's stylesheet behavior), we should give preference to the cardinal direction over the flow relative one. E.g. Top should be taken instead of Start when both are present.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Makes sense, I've just updated it

@@ -221,6 +221,10 @@ const validAttributesForNonEventProps = {
borderBottomRightRadius: true,
borderBottomStartRadius: true,
borderBottomEndRadius: true,
borderEndEndRadius: true,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

cc @yungsters who recently updated these for prop-types support facebook/react-native-deprecated-modules@5902411

RN's exported prop-types for View aren't enforced by RN itself, like it does for Text or Image. But I suspect we might still want to update ViewPropTypes before RN re-ejects it.

final float directionAwareTopRightRadius = isRTL ? topStartRadius : topEndRadius;
final float directionAwareBottomLeftRadius = isRTL ? bottomEndRadius : bottomStartRadius;
final float directionAwareBottomRightRadius = isRTL ? bottomStartRadius : bottomEndRadius;
final float logicalTopStartRadius = !YogaConstants.isUndefined(startStartRadius) ? startStartRadius : topStartRadius;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same comment as above re reversing the precedence here.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure, updated

Comment on lines 754 to 773
if (props.borderRadii.startEnd.has_value()) {
props.borderRadii.topEnd = props.borderRadii.startEnd;
props.borderRadii.startEnd.reset();
}

if (props.borderRadii.startStart.has_value()) {
props.borderRadii.topStart = props.borderRadii.startStart;
props.borderRadii.startStart.reset();
}

if (props.borderRadii.endEnd.has_value()) {
props.borderRadii.bottomEnd = props.borderRadii.endEnd;
props.borderRadii.endEnd.reset();
}

if (props.borderRadii.endStart.has_value()) {
props.borderRadii.bottomStart = props.borderRadii.endStart;
props.borderRadii.endStart.reset();
}

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looking at the examples below, they are always changing a left-or-right cardinal direction to a flow-relative one. E.g. nothing is done to borderRadii.topStart. But the added code seems to be doing the opposite? E.g. changing start/end to a top-bottom direction.

Are you sure the added code here is needed?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the review @NickGerleman, I did some investigation and actually, this code is not necessary, everything works just fine without it. I've pushed another commit and now all comments should've been addressed

Comment on lines 169 to 171
const auto topLeading = isRTL ? startEnd ? startEnd : topEnd
: startStart ? startStart
: topStart;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same comment as elsewhere about precedence, but this ternary is a bit hard to read as-is. Could we avoid the nested ternary (or maybe this is fine when formatted)?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah that logic was pretty confusing, I've just updated it making things a bit easier to read

@pull-bot
Copy link

PR build artifact for d3d2bd9 is ready.
To use, download tarball from "Artifacts" tab in this CircleCI job then run yarn add <path to tarball> in your React Native project.

@pull-bot
Copy link

PR build artifact for 71fcbdd is ready.
To use, download tarball from "Artifacts" tab in this CircleCI job then run yarn add <path to tarball> in your React Native project.

@facebook-github-bot
Copy link
Contributor

@NickGerleman has imported this pull request. If you are a Meta employee, you can view this diff on Phabricator.

@gabrieldonadel
Copy link
Collaborator Author

Hi @NickGerleman do you mind checking for me what's this Facebook Internal Linter warning about?

@NickGerleman
Copy link
Contributor

Hi @NickGerleman do you mind checking for me what's this Facebook Internal Linter warning about?

It's complaining because there was a CircleCI failure (unrelated to this change). Everything else is passing minus some clang format warnings we can fixup.

@gabrieldonadel
Copy link
Collaborator Author

Hi @NickGerleman, hope you had a great New Year's holiday! I just wanted to follow up on this PR. Is there anything that still needs to be addressed or resolved on my side?

@NickGerleman
Copy link
Contributor

Nothing on your side, this should be imported soon (have a bit of a queue atm).

@facebook-github-bot
Copy link
Contributor

@NickGerleman merged this pull request in 4ae4984.

@gabrieldonadel gabrieldonadel deleted the feat/add-logical-border-radius branch January 6, 2023 14:27
OlimpiaZurek pushed a commit to OlimpiaZurek/react-native that referenced this pull request May 22, 2023
Summary:
This PR implements logical border-radius as requested on facebook#34425. This implementation includes the addition of the following style properties

- `borderEndEndRadius`, equivalent to `borderBottomEndRadius`.
- `borderEndStartRadius`, equivalent to `borderBottomStartRadius`.
- `borderStartEndRadius`, equivalent to `borderTopEndRadius`.
- `borderStartStartRadius`, equivalent to `borderTopStartRadius`.

## Changelog

[GENERAL] [ADDED] - Add logical border-radius implementation

Pull Request resolved: facebook#35572

Test Plan:
1. Open the RNTester app and navigate to the `RTLExample` page
2. Test the new style properties through the `Logical Border Radii Start/End` section

https://user-images.githubusercontent.com/11707729/206623732-6d542347-93f9-40da-be97-f7dcd5f66ca9.mov

Reviewed By: necolas

Differential Revision: D42002043

Pulled By: NickGerleman

fbshipit-source-id: a0aa9783c280398b437aeb7a00c6eb3f767657a5
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
CLA Signed This label is managed by the Facebook bot. Authors need to sign the CLA before a PR can be reviewed. Merged This PR has been merged.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants