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

Support textDecorationLine on <Text> components (#709) #1056

Merged
merged 17 commits into from Apr 7, 2017
Merged

Support textDecorationLine on <Text> components (#709) #1056

merged 17 commits into from Apr 7, 2017

Conversation

ymusiychuk-lohika
Copy link
Contributor

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.

/// Text is both Underlined and Stroke out.
/// </summary>
[EnumMember(Value = "underline line-through")]
UnderlineLineThrough
Copy link
Collaborator

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.

Copy link
Collaborator

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)

Copy link
Collaborator

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)

Copy link
Contributor Author

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.

Copy link
Collaborator

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)

Copy link
Contributor Author

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);
Copy link
Collaborator

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?

Copy link
Contributor Author

@ymusiychuk-lohika ymusiychuk-lohika Mar 9, 2017

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)
Copy link
Collaborator

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.

Copy link
Contributor Author

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)
Copy link
Collaborator

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).

Copy link
Contributor Author

@ymusiychuk-lohika ymusiychuk-lohika Mar 9, 2017

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>
Copy link
Collaborator

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.

Copy link
Contributor

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.

Copy link
Contributor Author

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);

Copy link
Collaborator

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.

Copy link
Contributor Author

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.

Copy link
Collaborator

@rozele rozele Mar 9, 2017

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.

Copy link
Contributor Author

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

Copy link
Collaborator

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.

@rozele
Copy link
Collaborator

rozele commented Mar 8, 2017

🕐

@rozele
Copy link
Collaborator

rozele commented Mar 9, 2017

Closing and reopening to trigger CLA bot

@rozele rozele closed this Mar 9, 2017
@rozele rozele reopened this Mar 9, 2017
@msftclas
Copy link

msftclas commented Mar 9, 2017

@ymusiychuk-lohika,
Thanks for having already signed the Contribution License Agreement. Your agreement was validated by Microsoft. We will now review your pull request.
Thanks,
Microsoft Pull Request Bot

@ymusiychuk-lohika
Copy link
Contributor Author

I've put TextDecorationLine logic into ReactTextViewManager and ReactSpanViewManager. Now it supports inline decoration.
To add, I don't like all the #if WINDOWS_UWP stuff. I think, it should be changed by, maybe, creating base abstract classes in ReactNative.Shared and inheriting them in UWP and Net46 separately. But, most likely it should be done as a seprate task/PR.

@codecov-io
Copy link

Codecov Report

Merging #1056 into master will decrease coverage by 0.06%.
The diff coverage is 0%.

Impacted file tree graph

@@            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
Impacted Files Coverage Δ
...actNative.Net46/Views/Text/ReactTextViewManager.cs 0% <0%> (ø) ⬆️
...ndows/ReactNative.Shared/Reflection/EnumHelpers.cs 0% <0%> (ø) ⬆️
...ctNative.Shared/Views/Text/ReactSpanViewManager.cs 0% <0%> (ø) ⬆️

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 2b81a76...4850e9c. Read the comment docs.

@matthargett matthargett merged commit 22083ae into microsoft:master Apr 7, 2017
@matthargett matthargett deleted the textDecorationLine-support-709 branch April 7, 2017 01:34
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants