fix: remove gap if its last element in line #1188
Reference in New Issue
Block a user
No description provided.
Delete Branch "fix/remove-gap-last-element"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Fixes - https://github.com/facebook/react-native/issues/35553
Approach
We're using
betweenMainDim
to add gap between items in main axis. This is resulting in increased main axis dimension of the container as it gets added even for the last element. One solution is to keep using it and subtract the gap when last element is reached.Aside
Mutating this value feels weird, but I think
betweenMainDim
gets initialized for every line so should be fine? I did some manual tests to verify. I tried running tests but I'll have to downgrade the java version. Let me know if anything fails. Thanks! 🙏@@ -2540,6 +2540,11 @@ static void YGJustifyMainAxis(
const YGNodeRef child = node->getChild(i);
This is a good catch! I was looking for ages what the culprit might be.
I'm still trying to fully grok this step - but my feeling is the
betweenMainDim
should never be applied on the first child. I.e. on these lines:-60dd791dd8/yoga/Yoga.cpp (L2593-L2601)
I think there was always a bug here, and
collectedFlexItemsValues.mainDim
would be too large in the case any sort of justification. It would include one morebetweenMainDim
than it should have.However, I think we got away with it because either justification is only going to do something (i.e. set
betweenMainDim
to something bigger than zero) when the container has its size defined - and when its size is defined, we probably don't usecollectedFlexItemsValues.mainDim
.So in the case you did
justify-content: space-between
and the container only gets sized by its contents, the children wouldn't be justified, andbetweenMainDim
would be zero.In the case it had an explicit size and
betweenMainDim
was not zero, the explicit size was used instead, so it never really mattered that themainDim
was too large.Maybe we could do
const float appliedBetweenMainDim = i != 0 ? betweenMainDim : 0
@@ -2540,6 +2540,11 @@ static void YGJustifyMainAxis(
const YGNodeRef child = node->getChild(i);
@NickGerleman does that make sense to you?
@intergalacticspacehighway or @NickGerleman Can you please also add test case for this scenario (mentioned here https://github.com/facebook/react-native/issues/35553#issuecomment-1342582700 ) ?
@@ -2540,6 +2540,11 @@ static void YGJustifyMainAxis(
const YGNodeRef child = node->getChild(i);
@jacobp100 that makes sense to me!
But
collectedFlexItemsValues.mainDim
is also used to layout child items here. If we don't addbetweenMainDim
for the first item, there won't be a gap between first and second child. Also, verified by testing it.I am trying to run tests but getting below error on running buck test //:yoga
No build file at BUCK when resolving target //:yoga.
@@ -2540,6 +2540,11 @@ static void YGJustifyMainAxis(
const YGNodeRef child = node->getChild(i);
Ah yeah - that makes sense. Maybe here (before the child is moved) we could add:-
Then remove that from the
mainDim
calculations belowThere's an issue around this code where
auto
margins turn negative. But assuming the fix gets merged, we need to be careful that if you have a gap and an auto margin, the gap is still applied. I.e. these two views should never be less than 10px apart@@ -2540,6 +2540,11 @@ static void YGJustifyMainAxis(
const YGNodeRef child = node->getChild(i);
okay, yeah. Just wanted to try a simple fix without touching too many things 😅. Should be easier to make changes once we have tests running. Do you think there's an issue with the approach of removing the gap for the last item?
@@ -2540,6 +2540,11 @@ static void YGJustifyMainAxis(
const YGNodeRef child = node->getChild(i);
Just added https://github.com/facebook/yoga/pull/1189 - I really just wanna see what happens after running on CI
Did the stuff I said about the how we were always over-shooting the
mainDim
make sense? Assuming it doesn't cause extra issues to fix, it'd be nice to fix so we're less likely to see regressions laterSorry for the delays here. I will look through this today. Though +1 for adding more fixtures which cover this scenario. The test generator should work in OSS (just... not the running the UTs part).
@@ -2540,6 +2540,11 @@ static void YGJustifyMainAxis(
const YGNodeRef child = node->getChild(i);
Reading through this, is this a correct summary?
betweenMainDim
controls space between items (both gap, and justifications which add space between children)We can run through an example, where a container has size 100px, we have two children of size 25px, no gap, and
YGJustifySpaceEvenly
. We would expect spacing to take a total of 50px extra in total then. Per-item, we would addleadingMainDim
andbetweenMainDim
of the following:So I am seeing the same issue where we are over-counting
betweenMainDim
during justification.Separately, if we have
YGJustifyCenter
, we undercount by quite a bit since we only sum the leading gap, but never the trailing gap.In the block @intergalacticspacehighway mentions, we position the item based on the accumulated offset, and the leading space for the current item. So, positioning the second item correctly would assume
betweenMainDim
, has already been added.So I agree that omitting it for the first child does not seem to be correct.edit: I see, we are adding to the main dim before positioning in the proposed change.I think fixing up this logic to be more consistently correct would be worth doing, but also I think it might be a little risky unless we can super-conclusively determine the incorrect
collectedFlexItemsValues.mainDim
would never come into place during justification. And given the current timing around the holidays, I would be weary to make that sort of change at this specific moment.So, I think instead, we should stick with the fix @intergalacticspacehighway has for now of not adding gap to
betweenMainDim
when we are the last item. Though, as a matter of style, I agree with the note in the description that mutating the value is a bit unclear. So I think it would be better to instead have separate variables for justification gap, and gap derived gap, so that we could declarebetweenMainDim
once in the inner scope.The UTs are broken in OSS. The BUCK logic for the Java ones kept on breaking, and Buck in OSS in general hasn't gone well. But this week I will be adding a way to run the C++ UTs via the CMake/GTest build which should hopefully be relatively pain-free (and would test the same things, minus the JNI bindings).
Okay, I left a giant dump of information in the one of the threads, but plan of action-wise, I would propose:
YGJustifyCenter
would still be wrong after@@ -2540,6 +2540,11 @@ static void YGJustifyMainAxis(
const YGNodeRef child = node->getChild(i);
@NickGerleman My understanding is:-
Previously,
betweenMainDim
acted as a gap, but was only used for justification purposesWe were adding we were adding a total
betweenMainDim * children.length
tomainDim
- but since this is a distance between children, we should add a totalbetweenMainDim * (children.length - 1)
.I believe this was never noticed this bug because for justification to do anything - meaning
betweenMainDim != 0
- the container needs an explicit main axis size. So even thoughmainDim
was too big, it was just ignoredWhen the container did not have an explicit axis size,
betweenMainDim
was0
, so adding one too manybetweenMainDim
s, did not have an effectThe
gap
property leveragedbetweenMainDim
, so now in the case that a container does not have an explicit axis size, it's possible forbetweenMainDim
to be greater than zero, and suddenly it does matterI think the real fix is to not include
betweenMainDim
for the last child at all - not just subtract thegap
portion ofbetweenMainDim
for the last childHope that makes sense 😅
Going to import this and see if I can add some tests, then later today I will work on exposing the GTest UTs to OSS.
@NickGerleman has imported this pull request. If you are a Meta employee, you can view this diff on Phabricator.
@NickGerleman merged this pull request in facebook/yoga@ba27f9d1ec.
Pull request closed