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

Introduces TextVisitor to consolidate text traversal algorithms #8454

Merged
merged 9 commits into from
Sep 17, 2021

Conversation

rozele
Copy link
Collaborator

@rozele rozele commented Aug 20, 2021

The main motivation for this PR is to ensure each of the tree traversal algorithms we use inside RN Core Text supports 3rd party TextElements (e.g., Hyperlink). Right now, the logic is spread across a number of functions and each function would need to be checked individually to ensure it supports recursion through non-core TextElement view managers. Using visitor patterns, we can ensure that the base class appropriately handles recursion.

We have 3 different features that require a DFS traversal of the text tree:

  • The textTransform algorithm needs to recurse the undefined paths of the Text sub-tree where the prop value changes to update.
  • The backgroundColor algorithm needs to recurse the entire text tree to re-calculate highlighters any time the text changes or backgroundColor / foregroundColor props change within the tree.
  • The WIP hit test algorithm needs to recurse the text tree to identify which span is pressed (not yet merged to PR since blocked on this one, see Issue5151 visitor rozele/react-native-windows#8)

Additionally, we have 4 "upward" traversal algorithms:

  • When a RCTRawText changes it's text prop, we need to send an accessibility notification and update fast text.
  • When a RCTRawText changes, we need to re-apply text transforms.
  • When a background or foregroundColor changes, we need to notify each parent that it may require a highlighter for an optimization that skips calculating highlighters for text trees without foreground or background colors.
  • In the WIP hit test algorithm, we need to notify parent nodes that a nested Text component is pressable for the optimization that selectively skips traversal of non-pressable sub-trees (not yet merged to PR since blocked on this one, see Issue5151 visitor rozele/react-native-windows#8)

Each of these algorithms follow the same pattern, so to reduce the potential for bugs, I'd like to consolidate these algorithms to use a visitor pattern.

While working on this diff, I discovered a bug in the textTransform logic where when we update the prop to null / undefined or add a child to a RCTVirtualText node with null / undefined, it should still attempt to inherit from ancestors.

Fixes #8460

Microsoft Reviewers: Open in CodeFlow

We have 3 different features that require a DFS traversal of the text
tree:
1. The textTransform algorithm needs to recurse the undefined paths of
the Text sub-tree where the prop value changes to update.
2. The backgroundColor algorithm needs to recurse the entire text tree
to re-calculate highlighters any time the text changes or
backgroundColor / foregroundColor props change within the tree.
3. The WIP hit test algorithm needs to recurse the text tree to identify
which span is pressed.

Additionally, we have 4 "upward" traversal algorithms:
1. When a RCTRawText changes it's text prop, we need to send an
accessibility notification
2. When a RCTRawText changes, we need to re-apply text transforms.
3. When a background or foregroundColor changes, we need to notify each
parent that it may require a highlighter for an optimization that skips
calculating highlighters for text trees without foreground or
background colors.
4. In the WIP hit test algorithm, we need to notify parent nodes that a
nested Text component is pressable for the optimization that selectively
skips traversal of non-pressable sub-trees

Each of these algorithms follow the same pattern, so reduce the
potential for bugs, I'd like to consolidate these algorithms to use a
visitor pattern.
@rozele rozele requested a review from a team as a code owner August 20, 2021 19:31
Previously, if the child of a virtual text node with undefined
textTransform was appended, and that virtual text node had a parent with
a defined textTransform, the textTransform value would not inherit
properly. Similarly, if a virtual text node switched from defined to
undefined for textTransform prop, it would not inherit the correct value
and update children accordingly either.

Fixes microsoft#8460
@rozele rozele changed the title Initial implementation of TextVisitor Introduces TextVisitor to consolidate text traversal algorithms Aug 23, 2021
@rozele rozele force-pushed the textVisitor branch 3 times, most recently from a0fab31 to 2e4403c Compare August 24, 2021 20:45
Copy link
Contributor

@chiaramooney chiaramooney left a comment

Choose a reason for hiding this comment

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

Looks good to me, but will have to wait on another dev to look over the architecture decisions overall. One q, we filed an issue recently because textTransform style prop changes haven't been updating during Fast Refresh. With this overhaul change to Text, does that behavior now work?

@acoates-ms acoates-ms merged commit 485f0ff into microsoft:main Sep 17, 2021
chrisglein pushed a commit to chrisglein/react-native-windows that referenced this pull request Sep 22, 2021
…osoft#8454)

* Initial implementation of TextVisitor

We have 3 different features that require a DFS traversal of the text
tree:
1. The textTransform algorithm needs to recurse the undefined paths of
the Text sub-tree where the prop value changes to update.
2. The backgroundColor algorithm needs to recurse the entire text tree
to re-calculate highlighters any time the text changes or
backgroundColor / foregroundColor props change within the tree.
3. The WIP hit test algorithm needs to recurse the text tree to identify
which span is pressed.

Additionally, we have 4 "upward" traversal algorithms:
1. When a RCTRawText changes it's text prop, we need to send an
accessibility notification
2. When a RCTRawText changes, we need to re-apply text transforms.
3. When a background or foregroundColor changes, we need to notify each
parent that it may require a highlighter for an optimization that skips
calculating highlighters for text trees without foreground or
background colors.
4. In the WIP hit test algorithm, we need to notify parent nodes that a
nested Text component is pressable for the optimization that selectively
skips traversal of non-pressable sub-trees

Each of these algorithms follow the same pattern, so reduce the
potential for bugs, I'd like to consolidate these algorithms to use a
visitor pattern.

* Change files

* Move highlighter logic to visitor pattern

* Fixes a couple bugs and adds VisitChildren method to share logic

* Split text visitors into individual files

* Fixes issue with inherited text transforms

Previously, if the child of a virtual text node with undefined
textTransform was appended, and that virtual text node had a parent with
a defined textTransform, the textTransform value would not inherit
properly. Similarly, if a virtual text node switched from defined to
undefined for textTransform prop, it would not inherit the correct value
and update children accordingly either.

Fixes microsoft#8460

* Adds TextPropertyChangedParentVisitor for Text tree traversals when text or highlights are updated

* Removes irrelevant headers and fixes namespaces

* Refactor TextVisitor to eliminate need for `VisitExtensionText'
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Dynamic changes to text do not search ancestors for inherited textTransform
4 participants