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

Inconsistent text wrap behavior with flexbox #1730

Closed
1 task done
kzlar opened this issue Oct 25, 2024 · 7 comments
Closed
1 task done

Inconsistent text wrap behavior with flexbox #1730

kzlar opened this issue Oct 25, 2024 · 7 comments

Comments

@kzlar
Copy link

kzlar commented Oct 25, 2024

Report

Issues and Steps to Reproduce

Snack Repro: https://snack.expo.dev/@meata/text-bug?platform=ios
Select the iOS preview.

The gist is this: I have a horizontal stack with two text fields, when the first field gets too long I expect it to wrap and take the minimum width it can. This doesn't seem to be the case, worse, it seems to behave differently depending on the number of letters in the first field. The first section shows the behavior I expect, the second is the weird behavior. With both the total width is the same, only difference is the additional letter.

image

Same issue can be observed on Android but the text needs to be changed a bit to make it work.
On web it at least seems consistent, even though I'm not sure why it does not shrink.

Expected Behavior

Explained above, but generally I expect it to at least behave consistently (either shrink or don't)

Actual Behavior

Explained above, adding a single character changes the layout from shrinking to not shrinking.

Link to Code

https://snack.expo.dev/@meata/text-bug?platform=ios

@NickGerleman
Copy link
Contributor

NickGerleman commented Oct 25, 2024

There are a couple of related things here:

  1. Yoga currently incorrectly measures initial flex-basis using fit-content instead of max-content (apparently very old versions of Safari actually also did this?). So the initial contributions are the size fitting the container, instead of the max size given infinite width.
  2. Yoga asks underlying platform (React Native) the size of text under this constraint (fit-content = YGMeasureModeAtMost). In this case, the answer given by legacy renderer seems potentially wrong (only accounts for max line width).

@kzlar is there any way you could repro this against RN new arch (default in RN 0.76/Expo 52)? It goes through different measurement path.

@NickGerleman
Copy link
Contributor

@s77rt
Copy link

s77rt commented Nov 7, 2024

Problem:

The first text is already too long that it wraps in 2 lines, making the width enough => It won't shrink
The second text will initially fit in one line but since the items exceed the parent width => it will shrink. The calculated width after shrinking is correct but that new width can no longer hold that text in one line, thus it wraps.

In the second text, after the text shrinks the new layout width is calculated with mode Exactly (SizingMode::StretchFit)

Before shrinking After shrinking
Screenshot 2024-11-07 at 3 16 51 PM Screenshot 2024-11-07 at 3 21 39 PM

Solution

If the child shrank, use mode AtMost (SizingMode::FitContent)

iOS Android
Screenshot 2024-11-07 at 3 28 37 PM Screenshot 2024-11-07 at 3 28 36 PM

@delphinebugner
Copy link

Oh wah, thanks @s77rt! I had also looked into @kzlar issue and did not understand why the first text was fitting it's container; now it's clear! It's actually not affected by flexShrink=1 as it's already wrapping in regard to its full parent's width.

Second text is actually the standard, using the Exactly mode as you said.
Regarding your solution, would'nt it be a big breaking change if we start using AtMost for shrinking children?

@s77rt
Copy link

s77rt commented Nov 7, 2024

@delphinebugner Since we are using less width than what we have allocated we may have unfilled space (even with flexGrow). Now I can't get the yellow rectangle to take the remaining space.

@NickGerleman
Copy link
Contributor

NickGerleman commented Nov 8, 2024

@s77rt when I looked at behavior on web, sizing explicitly to fit-content, wrapped paragraph took full available width instead of width of max line. So, when we shrink, we only shrink to amount of space needed to also add inflexible child.

Ie in top example, yellow inflexible child should hug the right.

So I think measure function logic in RN needs to be changed to return available width when text is wrapped, instead of longest line width.

Separately, Yoga should be calculating initial flex basis as max content instead of fit-content, but that’s a gnarlier bug.

@s77rt
Copy link

s77rt commented Nov 8, 2024

Ah I got it. It does make sense in a way and it's consistent with web. Will look into this one then

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 a pull request may close this issue.

4 participants