-
Notifications
You must be signed in to change notification settings - Fork 1.1k
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
Support textDecorationLine on <Text> components (#709) #1056
Conversation
/// Text is both Underlined and Stroke out. | ||
/// </summary> | ||
[EnumMember(Value = "underline line-through")] | ||
UnderlineLineThrough |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is cool, this is compatible with the existing EnumHelpers class? We should re-write all the other enums to use this where possible. Ideally we could get rid of that reflection hack.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We actually don't need this enum, you can just as easily switch case on the string itself.
In reply to: 104831419 [](ancestors = 104831419)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That will avoid the dependency on System.Runtime.Serialization, and avoid the reflection driven changes to EnumHelpers
In reply to: 104832645 [](ancestors = 104832645,104831419)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I personally vote for enum instead of string, if there is a limited number of variants, because it
makes corresponding code strongly-typed.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
While I tend to agree that strong typing is usually good, I don't like that we have to add yet another dependency and pay an attribute reflection penalty for all enums across the framework just to support this strong typing.
In reply to: 105130501 [](ancestors = 105130501)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
When making decision on changing EnumHelpers I was looking onto "textAlign". Logically it is same as "textDecorationLine" and they both should be treated in same way. But "textDecorationLine" contains single value with space in it, which makes it impossible to use existing approach. So, either it must be an exceptional enum, treated differently (How many such enums can we possibly have?) or the approach should be changed. I've chosen the latter.
I am not against "switch" so if you insist, that's ok. But, please note, Reflection does not have "that" bad impact on performance if it happens once. Yes, if we have 100 000 of enums, then we will see the difference, but currently we have ~20 total and maybe it will grow up to 100 or 200 at most.
var enumMemberAttribute = type.GetField(name).GetCustomAttributes(typeof(EnumMemberAttribute), true).SingleOrDefault(); | ||
if (enumMemberAttribute != null) | ||
{ | ||
result.Add(Normalize(((EnumMemberAttribute)enumMemberAttribute).Value), value); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
EnumMemberAttribute [](start = 43, length = 19)
Just curious, does the serialization behavior of EnumMemberAttribute
only work in one direction? I.e., is the value only used to serialize to string, or is there some tool that can be used for parsing as well?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It works both ways. For example,
Newtonsoft.Json.JsonConvert.SerializeObject(TextDecorationLine.UnderlineLineThrough, new StringEnumConverter())
will respect the EnumMemberAttribute (notice the StringEnumConverter. Without it, enum is serialized as int)
result.Add(Normalize(name), value); | ||
|
||
var enumMemberAttribute = type.GetField(name).GetCustomAttributes(typeof(EnumMemberAttribute), true).SingleOrDefault(); | ||
if (enumMemberAttribute != null) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's unfortunate that we now have to pay a reflection penalty for all other enums where this does not exist. I know this only occurs once, but its a potential performance hit nonetheless.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That's true that Reflection brings in an overhead, but in this case, due to the fact that this method is called only once per enum, I think it's too small to have a significant impact on performance.
/// /// <param name="view">The view.</param> | ||
/// <param name="textDecorationLineValue">The TextDecorationLine value.</param> | ||
[ReactProp(ViewProps.TextDecorationLine)] | ||
public void SetTextDecorationLine(RichTextBlock view, string textDecorationLineValue) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
SetTextDecorationLine [](start = 20, length = 21)
I think it would be better to ignore this prop for now than to provide an incomplete implementation. The textDecorationLine
should be applicable to virtual text nodes (i.e., those that correspond to the inline instances as well).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Rolled back
@@ -38,6 +41,40 @@ public ReactTextShadowNode() | |||
} | |||
|
|||
/// <summary> | |||
/// Sets the TextDecorationLine for the node. | |||
/// </summary> | |||
/// <param name="textDecorationLineValue">The TextDecorationLine value.</param> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
TextDecorationLine [](start = 54, length = 18)
autodocs do not have great grammar.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is a case where I wish we could leave the tag empty since the argument name is self-documenting.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Agree with @matthargett. I've just tried to have autodocs style seem like other similar properties, like FontStyle and LineHeight
@@ -238,6 +275,7 @@ private void UpdateTextBlockCore(TextBlock textBlock, bool measureOnly) | |||
textBlock.FontSize = _fontSize ?? 15; | |||
textBlock.FontStyle = _fontStyle ?? new FontStyle(); | |||
textBlock.FontWeight = _fontWeight ?? FontWeights.Normal; | |||
textBlock.TextDecorations = new TextDecorationCollection(TextDecorationCollection); | |||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Again, this only solves the problem at the root level of the text node. React Native supports text decoration on the inlines / virtual text nodes.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I can be wrong, but from what I see, node is the lowest-level possible for creating styled text components. I cannot see a way to apply a style to a raw text. It would be great if you can come up with any example to understand the problem.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This would be supported on Android and iOS:
<Text>
Here is some regular text <Text style={{textDecorationLine: 'underline'}}>and here is some underlined virtual text</Text>.
</Text>
However, this scenario would not supported by this PR.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nice one. Didn't even got in mind to try this. I'll check how can I implement it this way
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
My guess would be you may need to create virtual node types and control all this by checking for presence of the prop in JavaScript. I.e., in JavaScript, you might check:
if (this.props.textDecorationLine === 'underline') {
this.props.children = (<UnderlinedText>{this.props.children}</UnderlinedText>);
}
or something along these lines. I'm sure my syntax is a bit off.
🕐 |
This reverts commit 5de9c8e. # Conflicts: # ReactWindows/ReactNative/Views/Text/ReactTextViewManager.cs
Closing and reopening to trigger CLA bot |
@ymusiychuk-lohika, |
…anager, support decoration of inlines
I've put TextDecorationLine logic into ReactTextViewManager and ReactSpanViewManager. Now it supports inline decoration. |
Codecov Report
@@ Coverage Diff @@
## master #1056 +/- ##
==========================================
- Coverage 31.68% 31.62% -0.07%
==========================================
Files 253 253
Lines 17976 18013 +37
Branches 1507 1513 +6
==========================================
Hits 5696 5696
- Misses 12126 12163 +37
Partials 154 154
Continue to review full report at Codecov.
|
WPF supports both Underline and Strike-through
UWP supports only Underline. The idea behind this approach was to add an Underline directly to a Paragraph of RichTextBlock, because we know that there is always one Paragraph and thus there should be at most one Underline.