diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/yoga/YogaNative.java b/packages/react-native/ReactAndroid/src/main/java/com/facebook/yoga/YogaNative.java index 9be9edcf8742c5..363e85f5842989 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/yoga/YogaNative.java +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/yoga/YogaNative.java @@ -108,6 +108,7 @@ public class YogaNative { static native void jni_YGNodeStyleSetAspectRatioJNI(long nativePointer, float aspectRatio); static native float jni_YGNodeStyleGetGapJNI(long nativePointer, int gutter); static native void jni_YGNodeStyleSetGapJNI(long nativePointer, int gutter, float gapLength); + static native void jni_YGNodeStyleSetGapPercentJNI(long nativePointer, int gutter, float gapLength); static native void jni_YGNodeSetHasMeasureFuncJNI(long nativePointer, boolean hasMeasureFunc); static native void jni_YGNodeSetHasBaselineFuncJNI(long nativePointer, boolean hasMeasureFunc); static native void jni_YGNodeSetStyleInputsJNI(long nativePointer, float[] styleInputsArray, int size); diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/yoga/YogaNode.java b/packages/react-native/ReactAndroid/src/main/java/com/facebook/yoga/YogaNode.java index 4875ac3e8ca2a0..97ad8ac2c257d1 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/yoga/YogaNode.java +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/yoga/YogaNode.java @@ -192,6 +192,8 @@ public interface Inputs { public abstract void setGap(YogaGutter gutter, float gapLength); + public abstract void setGapPercent(YogaGutter gutter, float gapLength); + public abstract float getLayoutX(); public abstract float getLayoutY(); diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/yoga/YogaNodeJNIBase.java b/packages/react-native/ReactAndroid/src/main/java/com/facebook/yoga/YogaNodeJNIBase.java index df958df1666afb..2f3c446c34ca9d 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/yoga/YogaNodeJNIBase.java +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/yoga/YogaNodeJNIBase.java @@ -721,4 +721,9 @@ public float getGap(YogaGutter gutter) { public void setGap(YogaGutter gutter, float gapLength) { YogaNative.jni_YGNodeStyleSetGapJNI(mNativePointer, gutter.intValue(), gapLength); } + + @Override + public void setGapPercent(YogaGutter gutter, float gapLength) { + YogaNative.jni_YGNodeStyleSetGapPercentJNI(mNativePointer, gutter.intValue(), gapLength); + } } diff --git a/packages/react-native/ReactAndroid/src/main/jni/first-party/yogajni/jni/YGJNIVanilla.cpp b/packages/react-native/ReactAndroid/src/main/jni/first-party/yogajni/jni/YGJNIVanilla.cpp index 82e0dc17b1350e..4d017037b465f9 100644 --- a/packages/react-native/ReactAndroid/src/main/jni/first-party/yogajni/jni/YGJNIVanilla.cpp +++ b/packages/react-native/ReactAndroid/src/main/jni/first-party/yogajni/jni/YGJNIVanilla.cpp @@ -715,6 +715,18 @@ static void jni_YGNodeStyleSetGapJNI( static_cast(gapLength)); } +static void jni_YGNodeStyleSetGapPercentJNI( + JNIEnv* /*env*/, + jobject /*obj*/, + jlong nativePointer, + jint gutter, + jfloat gapLength) { + YGNodeStyleSetGapPercent( + _jlong2YGNodeRef(nativePointer), + static_cast(gutter), + static_cast(gapLength)); +} + // Yoga specific properties, not compatible with flexbox specification YG_NODE_JNI_STYLE_PROP(jfloat, float, AspectRatio); @@ -944,6 +956,9 @@ static JNINativeMethod methods[] = { (void*)jni_YGNodeSetHasMeasureFuncJNI}, {"jni_YGNodeStyleGetGapJNI", "(JI)F", (void*)jni_YGNodeStyleGetGapJNI}, {"jni_YGNodeStyleSetGapJNI", "(JIF)V", (void*)jni_YGNodeStyleSetGapJNI}, + {"jni_YGNodeStyleSetGapPercentJNI", + "(JIF)V", + (void*)jni_YGNodeStyleSetGapPercentJNI}, {"jni_YGNodeSetHasBaselineFuncJNI", "(JZ)V", (void*)jni_YGNodeSetHasBaselineFuncJNI}, diff --git a/packages/react-native/ReactAndroid/src/test/java/com/facebook/testutils/fakes/FakeYogaNode.kt b/packages/react-native/ReactAndroid/src/test/java/com/facebook/testutils/fakes/FakeYogaNode.kt index b063ae1ace16b0..5f29a58b660c69 100644 --- a/packages/react-native/ReactAndroid/src/test/java/com/facebook/testutils/fakes/FakeYogaNode.kt +++ b/packages/react-native/ReactAndroid/src/test/java/com/facebook/testutils/fakes/FakeYogaNode.kt @@ -217,6 +217,10 @@ class FakeYogaNode : YogaNode() { // no-op } + override fun setGapPercent(gutter: YogaGutter?, gapLength: Float) { + // no-op + } + override fun getLayoutX(): Float = 0f override fun getLayoutY(): Float = 0f diff --git a/packages/react-native/ReactCommon/yoga/yoga/YGNodeStyle.cpp b/packages/react-native/ReactCommon/yoga/yoga/YGNodeStyle.cpp index d8454053dee558..d14d70930f4fbf 100644 --- a/packages/react-native/ReactCommon/yoga/yoga/YGNodeStyle.cpp +++ b/packages/react-native/ReactCommon/yoga/yoga/YGNodeStyle.cpp @@ -267,6 +267,11 @@ void YGNodeStyleSetGap( node, scopedEnum(gutter), value::points(gapLength)); } +void YGNodeStyleSetGapPercent(YGNodeRef node, YGGutter gutter, float percent) { + updateStyle<&Style::gap, &Style::setGap>( + node, scopedEnum(gutter), value::percent(percent)); +} + float YGNodeStyleGetGap(const YGNodeConstRef node, const YGGutter gutter) { auto gapLength = resolveRef(node)->style().gap(scopedEnum(gutter)); if (gapLength.isUndefined() || gapLength.isAuto()) { diff --git a/packages/react-native/ReactCommon/yoga/yoga/YGNodeStyle.h b/packages/react-native/ReactCommon/yoga/yoga/YGNodeStyle.h index 09727087ba4ef8..2934194f85ccc0 100644 --- a/packages/react-native/ReactCommon/yoga/yoga/YGNodeStyle.h +++ b/packages/react-native/ReactCommon/yoga/yoga/YGNodeStyle.h @@ -89,6 +89,8 @@ YG_EXPORT float YGNodeStyleGetBorder(YGNodeConstRef node, YGEdge edge); YG_EXPORT void YGNodeStyleSetGap(YGNodeRef node, YGGutter gutter, float gapLength); +YG_EXPORT void +YGNodeStyleSetGapPercent(YGNodeRef node, YGGutter gutter, float gapLength); YG_EXPORT float YGNodeStyleGetGap(YGNodeConstRef node, YGGutter gutter); YG_EXPORT void YGNodeStyleSetWidth(YGNodeRef node, float width); diff --git a/packages/react-native/ReactCommon/yoga/yoga/algorithm/CalculateLayout.cpp b/packages/react-native/ReactCommon/yoga/yoga/algorithm/CalculateLayout.cpp index 19cf4a23592be2..62d8a24b769671 100644 --- a/packages/react-native/ReactCommon/yoga/yoga/algorithm/CalculateLayout.cpp +++ b/packages/react-native/ReactCommon/yoga/yoga/algorithm/CalculateLayout.cpp @@ -929,7 +929,8 @@ static void justifyMainAxis( node->style().computeFlexEndPaddingAndBorder( mainAxis, direction, ownerWidth); - const float gap = node->style().computeGapForAxis(mainAxis); + const float gap = + node->style().computeGapForAxis(mainAxis, availableInnerMainDim); // If we are using "at most" rules in the main axis, make sure that // remainingFreeSpace is 0 when min main dimension is not given if (sizingModeMainDim == SizingMode::FitContent && @@ -1380,7 +1381,8 @@ static void calculateLayoutImpl( generationCount); if (childCount > 1) { - totalMainDim += node->style().computeGapForAxis(mainAxis) * + totalMainDim += + node->style().computeGapForAxis(mainAxis, availableInnerMainDim) * static_cast(childCount - 1); } @@ -1404,7 +1406,8 @@ static void calculateLayoutImpl( // Accumulated cross dimensions of all lines so far. float totalLineCrossDim = 0; - const float crossAxisGap = node->style().computeGapForAxis(crossAxis); + const float crossAxisGap = + node->style().computeGapForAxis(crossAxis, availableInnerCrossDim); // Max main dimension of all the lines. float maxLineMainDim = 0; diff --git a/packages/react-native/ReactCommon/yoga/yoga/algorithm/FlexLine.cpp b/packages/react-native/ReactCommon/yoga/yoga/algorithm/FlexLine.cpp index 1fe3e486926f62..50cd6f0abe1bb5 100644 --- a/packages/react-native/ReactCommon/yoga/yoga/algorithm/FlexLine.cpp +++ b/packages/react-native/ReactCommon/yoga/yoga/algorithm/FlexLine.cpp @@ -34,7 +34,8 @@ FlexLine calculateFlexLine( const FlexDirection mainAxis = resolveDirection( node->style().flexDirection(), node->resolveDirection(ownerDirection)); const bool isNodeFlexWrap = node->style().flexWrap() != Wrap::NoWrap; - const float gap = node->style().computeGapForAxis(mainAxis); + const float gap = + node->style().computeGapForAxis(mainAxis, availableInnerMainDim); // Add items to the current line until it's full or we run out of items. for (; endOfLineIndex < node->getChildren().size(); endOfLineIndex++) { diff --git a/packages/react-native/ReactCommon/yoga/yoga/style/Style.h b/packages/react-native/ReactCommon/yoga/yoga/style/Style.h index 113a8e1df16570..ac769f1d76d7ba 100644 --- a/packages/react-native/ReactCommon/yoga/yoga/style/Style.h +++ b/packages/react-native/ReactCommon/yoga/yoga/style/Style.h @@ -428,11 +428,9 @@ class YG_EXPORT Style { computeInlineEndMargin(axis, Direction::LTR, widthSize); } - float computeGapForAxis(FlexDirection axis) const { + float computeGapForAxis(FlexDirection axis, float ownerSize) const { auto gap = isRow(axis) ? computeColumnGap() : computeRowGap(); - // TODO: Validate percentage gap, and expose ability to set percentage to - // public API - return maxOrDefined(gap.resolve(0.0f /*ownerSize*/).unwrap(), 0.0f); + return maxOrDefined(gap.resolve(ownerSize).unwrap(), 0.0f); } bool flexStartMarginIsAuto(FlexDirection axis, Direction direction) const {