react / react/yoga

Unexpected Yoga calculation results when using min/max sizes for top/bottom or left/right nodes

Open
#674 6 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Algorithm
Dominant language
C++
Stars
18.9k
Forks
1.6k
Avg merge
1m
Merged PRs (30d)
1

Description

Report

Issues and Steps to Reproduce

I've tried to create three rows and three columns on second row.
All rows should be stretched to root node size.
All columns (in second row) should stretch to row size.
Left and right columns should have different min/max width.
Top and bottom row should have different min/max height.

Expected Behavior

There should not be empty space between stretched nodes.

Actual Behavior

There is empty space between stretched nodes.
animation

Link to Code

I am using java bindings and here is code:

    private Vector2f minTop = new Vector2f(200, 20);
    private Vector2f minBottom = new Vector2f(200, 20);
    private Vector2f minLeft = new Vector2f(100, 20);
    private Vector2f minRight = new Vector2f(120, 20);
    private Vector2f minCenter = new Vector2f(50, 50);

    private Vector2f maxTop = new Vector2f(Float.MAX_VALUE, 120);
    private Vector2f maxBottom = new Vector2f(Float.MAX_VALUE, 80);
    private Vector2f maxLeft = new Vector2f(300, Float.MAX_VALUE);
    private Vector2f maxRight = new Vector2f(200, Float.MAX_VALUE);
    private Vector2f maxCenter = new Vector2f(Float.MAX_VALUE, Float.MAX_VALUE);

    private Vector4f midRow = new Vector4f();
    private Vector4f top = new Vector4f();
    private Vector4f bottom = new Vector4f();
    private Vector4f left = new Vector4f();
    private Vector4f center = new Vector4f();
    private Vector4f right = new Vector4f();

    private Vector2f size = new Vector2f();

    protected void update() {
        long rootNode = Yoga.YGNodeNew();

        long mNode = Yoga.YGNodeNew();

        long tNode = Yoga.YGNodeNew();
        long lNode = Yoga.YGNodeNew();
        long cNode = Yoga.YGNodeNew();
        long rNode = Yoga.YGNodeNew();
        long bNode = Yoga.YGNodeNew();

        Yoga.YGNodeInsertChild(rootNode, tNode, 0);
        Yoga.YGNodeInsertChild(rootNode, mNode, 1);
        Yoga.YGNodeInsertChild(rootNode, bNode, 2);

        Yoga.YGNodeInsertChild(mNode, lNode, 0);
        Yoga.YGNodeInsertChild(mNode, cNode, 1);
        Yoga.YGNodeInsertChild(mNode, rNode, 2);

        Yoga.YGNodeStyleSetFlexDirection(rootNode, Yoga.YGFlexDirectionColumn);
        Yoga.YGNodeStyleSetAlignItems(rootNode, Yoga.YGAlignStretch);
        Yoga.YGNodeStyleSetJustifyContent(rootNode, Yoga.YGJustifySpaceBetween);

        Yoga.YGNodeStyleSetFlexDirection(mNode, Yoga.YGFlexDirectionRow);
        Yoga.YGNodeStyleSetAlignItems(mNode, Yoga.YGAlignStretch);
        Yoga.YGNodeStyleSetJustifyContent(mNode, Yoga.YGJustifySpaceBetween);

        float midMaxOfMin = Math.max(Math.max(minLeft.y, minCenter.y), minRight.y);
        Yoga.YGNodeStyleSetMinHeight(mNode, midMaxOfMin);
        Yoga.YGNodeStyleSetMaxHeight(mNode, Float.MAX_VALUE);

        Yoga.YGNodeStyleSetWidth(mNode, size.x);

        Yoga.YGNodeStyleSetFlexGrow(mNode, 1);
        Yoga.YGNodeStyleSetFlexShrink(mNode, 1);

        Yoga.YGNodeStyleSetMaxWidth(tNode, maxTop.x);
        Yoga.YGNodeStyleSetMaxHeight(tNode, maxTop.y);
        Yoga.YGNodeStyleSetMinWidth(tNode, minTop.x);
        Yoga.YGNodeStyleSetMinHeight(tNode, minTop.y);
        Yoga.YGNodeStyleSetFlexGrow(tNode, 1);
        Yoga.YGNodeStyleSetFlexShrink(tNode, 1);
        Yoga.YGNodeStyleSetWidth(tNode, size.x);

        Yoga.YGNodeStyleSetMaxWidth(bNode, maxBottom.x);
        Yoga.YGNodeStyleSetMaxHeight(bNode, maxBottom.y);
        Yoga.YGNodeStyleSetMinWidth(bNode, minBottom.x);
        Yoga.YGNodeStyleSetMinHeight(bNode, minBottom.y);
        Yoga.YGNodeStyleSetFlexGrow(bNode, 1);
        Yoga.YGNodeStyleSetFlexShrink(bNode, 1);
        Yoga.YGNodeStyleSetWidth(bNode, size.x);

        Yoga.YGNodeStyleSetMaxWidth(lNode, maxLeft.x);
        Yoga.YGNodeStyleSetMaxHeight(lNode, maxLeft.y);
        Yoga.YGNodeStyleSetMinWidth(lNode, minLeft.x);
        Yoga.YGNodeStyleSetMinHeight(lNode, minLeft.y);
        Yoga.YGNodeStyleSetFlexGrow(lNode, 1);
        Yoga.YGNodeStyleSetFlexShrink(lNode, 1);
        Yoga.YGNodeStyleSetMinHeight(lNode, midMaxOfMin);

        Yoga.YGNodeStyleSetMaxWidth(cNode, maxCenter.x);
        Yoga.YGNodeStyleSetMaxHeight(cNode, maxCenter.y);
        Yoga.YGNodeStyleSetMinWidth(cNode, minCenter.x);
        Yoga.YGNodeStyleSetMinHeight(cNode, minCenter.y);
        Yoga.YGNodeStyleSetFlexGrow(cNode, 1);
        Yoga.YGNodeStyleSetFlexShrink(cNode, 1);
        Yoga.YGNodeStyleSetMinHeight(cNode, midMaxOfMin);

        Yoga.YGNodeStyleSetMaxWidth(rNode, maxRight.x);
        Yoga.YGNodeStyleSetMaxHeight(rNode, maxRight.y);
        Yoga.YGNodeStyleSetMinWidth(rNode, minRight.x);
        Yoga.YGNodeStyleSetMinHeight(rNode, minRight.y);
        Yoga.YGNodeStyleSetFlexGrow(rNode, 1);
        Yoga.YGNodeStyleSetFlexShrink(rNode, 1);
        Yoga.YGNodeStyleSetMinHeight(rNode, midMaxOfMin);

        Yoga.nYGNodeCalculateLayout(rootNode, size.x, size.y, Yoga.YGDirectionLTR);

        Vector2f d = new Vector2f(Yoga.YGNodeLayoutGetLeft(mNode), Yoga.YGNodeLayoutGetTop(mNode));

        midRow.set(Yoga.YGNodeLayoutGetLeft(mNode), Yoga.YGNodeLayoutGetTop(mNode), Yoga.YGNodeLayoutGetWidth(mNode), Yoga.YGNodeLayoutGetHeight(mNode));
        top.set(Yoga.YGNodeLayoutGetLeft(tNode), Yoga.YGNodeLayoutGetTop(tNode), Yoga.YGNodeLayoutGetWidth(tNode), Yoga.YGNodeLayoutGetHeight(tNode));
        bottom.set(Yoga.YGNodeLayoutGetLeft(bNode), Yoga.YGNodeLayoutGetTop(bNode), Yoga.YGNodeLayoutGetWidth(bNode), Yoga.YGNodeLayoutGetHeight(bNode));
        left.set(Yoga.YGNodeLayoutGetLeft(lNode) + d.x, Yoga.YGNodeLayoutGetTop(lNode) + d.y, Yoga.YGNodeLayoutGetWidth(lNode), Yoga.YGNodeLayoutGetHeight(lNode));
        right.set(Yoga.YGNodeLayoutGetLeft(rNode) + d.x, Yoga.YGNodeLayoutGetTop(rNode) + d.y, Yoga.YGNodeLayoutGetWidth(rNode), Yoga.YGNodeLayoutGetHeight(rNode));
        center.set(Yoga.YGNodeLayoutGetLeft(cNode) + d.x, Yoga.YGNodeLayoutGetTop(cNode) + d.y, Yoga.YGNodeLayoutGetWidth(cNode), Yoga.YGNodeLayoutGetHeight(cNode));

        Yoga.YGNodeFree(rootNode);
        Yoga.YGNodeFree(mNode);
        Yoga.YGNodeFree(tNode);
        Yoga.YGNodeFree(lNode);
        Yoga.YGNodeFree(cNode);
        Yoga.YGNodeFree(rNode);
        Yoga.YGNodeFree(bNode);
}

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start with the update() method and the YGNodeCalculateLayout call, then inspect the calculated rectangles for rootNode, mNode, and its children under the stated min/max constraints. Done means the reproduced layout no longer contains the reported empty gaps between stretched nodes and the expected behavior is covered by a regression case.

Written by the indexing model from the issue text.

Assessment

Tech stack
cpp, java
Domain
frontend
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.