From 0f63e5ae2baa36e00254d1f7f838fc5e0db5f797 Mon Sep 17 00:00:00 2001 From: Nick Gerleman Date: Sun, 22 Feb 2026 03:08:06 -0800 Subject: [PATCH] CSS Grid 1/9: Grid style types and public API (#55665) Summary: X-link: https://github.com/facebook/yoga/pull/1879 Add the foundational data types, enums, style properties, and C API for expressing CSS Grid layouts in Yoga. Includes: - Grid style types (GridLine.h, GridTrack.h, GridTrackType.h) - Updated enums (Display::Grid, Align::Start/End, Justify::Auto/Stretch/Start/End) - Grid event (LayoutPassReason::kGridLayout) - Style property accessors and member variables - Public C API (YGGridTrackList.h/cpp, YGNodeStyle grid setters/getters) - Layout helpers updated for new enum values (Align.h, AbsoluteLayout.cpp, CalculateLayout.cpp/h partial) - Node.h: relativePosition made public - Website playground grid property support - React Native mirror of all C++ changes Differential Revision: D93946262 --- packages/react-native/React/Views/RCTLayout.m | 9 +- .../java/com/facebook/yoga/YogaAlign.java | 6 +- .../java/com/facebook/yoga/YogaDisplay.java | 4 +- .../com/facebook/yoga/YogaGridTrackType.java | 39 ++++ .../java/com/facebook/yoga/YogaJustify.java | 32 ++-- .../renderer/components/view/conversions.h | 2 + .../react/renderer/core/LayoutPrimitives.h | 1 + .../react/renderer/core/conversions.h | 4 + .../ReactCommon/yoga/yoga/YGEnums.cpp | 30 +++ .../ReactCommon/yoga/yoga/YGEnums.h | 21 +- .../ReactCommon/yoga/yoga/YGGridTrackList.cpp | 179 ++++++++++++++++++ .../ReactCommon/yoga/yoga/YGGridTrackList.h | 96 ++++++++++ .../ReactCommon/yoga/yoga/YGNodeStyle.cpp | 100 ++++++++++ .../ReactCommon/yoga/yoga/YGNodeStyle.h | 32 +++- .../react-native/ReactCommon/yoga/yoga/Yoga.h | 1 + .../yoga/yoga/algorithm/AbsoluteLayout.cpp | 48 ++++- .../ReactCommon/yoga/yoga/algorithm/Align.h | 13 +- .../yoga/yoga/algorithm/CalculateLayout.cpp | 24 ++- .../yoga/yoga/algorithm/CalculateLayout.h | 22 +++ .../ReactCommon/yoga/yoga/enums/Align.h | 4 +- .../ReactCommon/yoga/yoga/enums/Display.h | 3 +- .../yoga/yoga/enums/GridTrackType.h | 43 +++++ .../ReactCommon/yoga/yoga/enums/Justify.h | 6 +- .../ReactCommon/yoga/yoga/event/event.cpp | 2 + .../ReactCommon/yoga/yoga/event/event.h | 1 + .../ReactCommon/yoga/yoga/node/Node.h | 8 +- .../ReactCommon/yoga/yoga/style/GridLine.h | 61 ++++++ .../ReactCommon/yoga/yoga/style/GridTrack.h | 65 +++++++ .../ReactCommon/yoga/yoga/style/Style.h | 112 ++++++++++- .../yoga/yoga/style/StyleSizeLength.h | 8 +- 30 files changed, 930 insertions(+), 46 deletions(-) create mode 100644 packages/react-native/ReactAndroid/src/main/java/com/facebook/yoga/YogaGridTrackType.java create mode 100644 packages/react-native/ReactCommon/yoga/yoga/YGGridTrackList.cpp create mode 100644 packages/react-native/ReactCommon/yoga/yoga/YGGridTrackList.h create mode 100644 packages/react-native/ReactCommon/yoga/yoga/enums/GridTrackType.h create mode 100644 packages/react-native/ReactCommon/yoga/yoga/style/GridLine.h create mode 100644 packages/react-native/ReactCommon/yoga/yoga/style/GridTrack.h diff --git a/packages/react-native/React/Views/RCTLayout.m b/packages/react-native/React/Views/RCTLayout.m index 944b728684c5..53b524ce5f02 100644 --- a/packages/react-native/React/Views/RCTLayout.m +++ b/packages/react-native/React/Views/RCTLayout.m @@ -114,10 +114,10 @@ UIUserInterfaceLayoutDirection RCTUIKitLayoutDirectionFromYogaLayoutDirection(YG YGDisplay RCTYogaDisplayTypeFromReactDisplayType(RCTDisplayType displayType) { switch (displayType) { - case RCTDisplayTypeNone: - return YGDisplayNone; case RCTDisplayTypeFlex: return YGDisplayFlex; + case RCTDisplayTypeNone: + return YGDisplayNone; case RCTDisplayTypeInline: RCTAssert(NO, @"RCTDisplayTypeInline cannot be converted to YGDisplay value."); return YGDisplayNone; @@ -128,11 +128,10 @@ RCTDisplayType RCTReactDisplayTypeFromYogaDisplayType(YGDisplay displayType) { switch (displayType) { case YGDisplayFlex: + case YGDisplayContents: + case YGDisplayGrid: return RCTDisplayTypeFlex; case YGDisplayNone: return RCTDisplayTypeNone; - case YGDisplayContents: - RCTAssert(NO, @"YGDisplayContents cannot be converted to RCTDisplayType value."); - return RCTDisplayTypeNone; } } diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/yoga/YogaAlign.java b/packages/react-native/ReactAndroid/src/main/java/com/facebook/yoga/YogaAlign.java index 00535154fca1..6f1c4565818c 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/yoga/YogaAlign.java +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/yoga/YogaAlign.java @@ -18,7 +18,9 @@ public enum YogaAlign { BASELINE(5), SPACE_BETWEEN(6), SPACE_AROUND(7), - SPACE_EVENLY(8); + SPACE_EVENLY(8), + START(9), + END(10); private final int mIntValue; @@ -41,6 +43,8 @@ public static YogaAlign fromInt(int value) { case 6: return SPACE_BETWEEN; case 7: return SPACE_AROUND; case 8: return SPACE_EVENLY; + case 9: return START; + case 10: return END; default: throw new IllegalArgumentException("Unknown enum value: " + value); } } diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/yoga/YogaDisplay.java b/packages/react-native/ReactAndroid/src/main/java/com/facebook/yoga/YogaDisplay.java index 4dae871936e6..8e7e0f83cd9c 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/yoga/YogaDisplay.java +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/yoga/YogaDisplay.java @@ -12,7 +12,8 @@ public enum YogaDisplay { FLEX(0), NONE(1), - CONTENTS(2); + CONTENTS(2), + GRID(3); private final int mIntValue; @@ -29,6 +30,7 @@ public static YogaDisplay fromInt(int value) { case 0: return FLEX; case 1: return NONE; case 2: return CONTENTS; + case 3: return GRID; default: throw new IllegalArgumentException("Unknown enum value: " + value); } } diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/yoga/YogaGridTrackType.java b/packages/react-native/ReactAndroid/src/main/java/com/facebook/yoga/YogaGridTrackType.java new file mode 100644 index 000000000000..e3d22d25be3f --- /dev/null +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/yoga/YogaGridTrackType.java @@ -0,0 +1,39 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +// @generated by enums.py + +package com.facebook.yoga; + +public enum YogaGridTrackType { + AUTO(0), + POINTS(1), + PERCENT(2), + FR(3), + MINMAX(4); + + private final int mIntValue; + + YogaGridTrackType(int intValue) { + mIntValue = intValue; + } + + public int intValue() { + return mIntValue; + } + + public static YogaGridTrackType fromInt(int value) { + switch (value) { + case 0: return AUTO; + case 1: return POINTS; + case 2: return PERCENT; + case 3: return FR; + case 4: return MINMAX; + default: throw new IllegalArgumentException("Unknown enum value: " + value); + } + } +} diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/yoga/YogaJustify.java b/packages/react-native/ReactAndroid/src/main/java/com/facebook/yoga/YogaJustify.java index 4be1ed71d39d..778238ec6636 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/yoga/YogaJustify.java +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/yoga/YogaJustify.java @@ -10,12 +10,16 @@ package com.facebook.yoga; public enum YogaJustify { - FLEX_START(0), - CENTER(1), - FLEX_END(2), - SPACE_BETWEEN(3), - SPACE_AROUND(4), - SPACE_EVENLY(5); + AUTO(0), + FLEX_START(1), + CENTER(2), + FLEX_END(3), + SPACE_BETWEEN(4), + SPACE_AROUND(5), + SPACE_EVENLY(6), + STRETCH(7), + START(8), + END(9); private final int mIntValue; @@ -29,12 +33,16 @@ public int intValue() { public static YogaJustify fromInt(int value) { switch (value) { - case 0: return FLEX_START; - case 1: return CENTER; - case 2: return FLEX_END; - case 3: return SPACE_BETWEEN; - case 4: return SPACE_AROUND; - case 5: return SPACE_EVENLY; + case 0: return AUTO; + case 1: return FLEX_START; + case 2: return CENTER; + case 3: return FLEX_END; + case 4: return SPACE_BETWEEN; + case 5: return SPACE_AROUND; + case 6: return SPACE_EVENLY; + case 7: return STRETCH; + case 8: return START; + case 9: return END; default: throw new IllegalArgumentException("Unknown enum value: " + value); } } diff --git a/packages/react-native/ReactCommon/react/renderer/components/view/conversions.h b/packages/react-native/ReactCommon/react/renderer/components/view/conversions.h index b39e27fe4a8c..e8618bda2dd3 100644 --- a/packages/react-native/ReactCommon/react/renderer/components/view/conversions.h +++ b/packages/react-native/ReactCommon/react/renderer/components/view/conversions.h @@ -129,6 +129,8 @@ inline DisplayType displayTypeFromYGDisplay(YGDisplay display) return DisplayType::Contents; case YGDisplayFlex: return DisplayType::Flex; + case YGDisplayGrid: + return DisplayType::Grid; } } diff --git a/packages/react-native/ReactCommon/react/renderer/core/LayoutPrimitives.h b/packages/react-native/ReactCommon/react/renderer/core/LayoutPrimitives.h index d2e50ff73553..f5ac9f04f09c 100644 --- a/packages/react-native/ReactCommon/react/renderer/core/LayoutPrimitives.h +++ b/packages/react-native/ReactCommon/react/renderer/core/LayoutPrimitives.h @@ -20,6 +20,7 @@ enum class DisplayType { None = 0, Flex = 1, Contents = 2, + Grid = 3, }; enum class PositionType { diff --git a/packages/react-native/ReactCommon/react/renderer/core/conversions.h b/packages/react-native/ReactCommon/react/renderer/core/conversions.h index 74796174353a..d40427c40ded 100644 --- a/packages/react-native/ReactCommon/react/renderer/core/conversions.h +++ b/packages/react-native/ReactCommon/react/renderer/core/conversions.h @@ -44,6 +44,8 @@ inline int toInt(const DisplayType &displayType) return 1; case DisplayType::Contents: return 2; + case DisplayType::Grid: + return 3; } } @@ -56,6 +58,8 @@ inline std::string toString(const DisplayType &displayType) return "flex"; case DisplayType::Contents: return "contents"; + case DisplayType::Grid: + return "grid"; } } diff --git a/packages/react-native/ReactCommon/yoga/yoga/YGEnums.cpp b/packages/react-native/ReactCommon/yoga/yoga/YGEnums.cpp index 4bdace6b7a5e..9fc4a83a82da 100644 --- a/packages/react-native/ReactCommon/yoga/yoga/YGEnums.cpp +++ b/packages/react-native/ReactCommon/yoga/yoga/YGEnums.cpp @@ -29,6 +29,10 @@ const char* YGAlignToString(const YGAlign value) { return "space-around"; case YGAlignSpaceEvenly: return "space-evenly"; + case YGAlignStart: + return "start"; + case YGAlignEnd: + return "end"; } return "unknown"; } @@ -73,6 +77,8 @@ const char* YGDisplayToString(const YGDisplay value) { return "none"; case YGDisplayContents: return "contents"; + case YGDisplayGrid: + return "grid"; } return "unknown"; } @@ -141,6 +147,22 @@ const char* YGFlexDirectionToString(const YGFlexDirection value) { return "unknown"; } +const char* YGGridTrackTypeToString(const YGGridTrackType value) { + switch (value) { + case YGGridTrackTypeAuto: + return "auto"; + case YGGridTrackTypePoints: + return "points"; + case YGGridTrackTypePercent: + return "percent"; + case YGGridTrackTypeFr: + return "fr"; + case YGGridTrackTypeMinmax: + return "minmax"; + } + return "unknown"; +} + const char* YGGutterToString(const YGGutter value) { switch (value) { case YGGutterColumn: @@ -155,6 +177,8 @@ const char* YGGutterToString(const YGGutter value) { const char* YGJustifyToString(const YGJustify value) { switch (value) { + case YGJustifyAuto: + return "auto"; case YGJustifyFlexStart: return "flex-start"; case YGJustifyCenter: @@ -167,6 +191,12 @@ const char* YGJustifyToString(const YGJustify value) { return "space-around"; case YGJustifySpaceEvenly: return "space-evenly"; + case YGJustifyStretch: + return "stretch"; + case YGJustifyStart: + return "start"; + case YGJustifyEnd: + return "end"; } return "unknown"; } diff --git a/packages/react-native/ReactCommon/yoga/yoga/YGEnums.h b/packages/react-native/ReactCommon/yoga/yoga/YGEnums.h index bb83bcfac949..1b69f0931861 100644 --- a/packages/react-native/ReactCommon/yoga/yoga/YGEnums.h +++ b/packages/react-native/ReactCommon/yoga/yoga/YGEnums.h @@ -22,7 +22,9 @@ YG_ENUM_DECL( YGAlignBaseline, YGAlignSpaceBetween, YGAlignSpaceAround, - YGAlignSpaceEvenly) + YGAlignSpaceEvenly, + YGAlignStart, + YGAlignEnd) YG_ENUM_DECL( YGBoxSizing, @@ -44,7 +46,8 @@ YG_ENUM_DECL( YGDisplay, YGDisplayFlex, YGDisplayNone, - YGDisplayContents) + YGDisplayContents, + YGDisplayGrid) YG_ENUM_DECL( YGEdge, @@ -79,6 +82,14 @@ YG_ENUM_DECL( YGFlexDirectionRow, YGFlexDirectionRowReverse) +YG_ENUM_DECL( + YGGridTrackType, + YGGridTrackTypeAuto, + YGGridTrackTypePoints, + YGGridTrackTypePercent, + YGGridTrackTypeFr, + YGGridTrackTypeMinmax) + YG_ENUM_DECL( YGGutter, YGGutterColumn, @@ -87,12 +98,16 @@ YG_ENUM_DECL( YG_ENUM_DECL( YGJustify, + YGJustifyAuto, YGJustifyFlexStart, YGJustifyCenter, YGJustifyFlexEnd, YGJustifySpaceBetween, YGJustifySpaceAround, - YGJustifySpaceEvenly) + YGJustifySpaceEvenly, + YGJustifyStretch, + YGJustifyStart, + YGJustifyEnd) YG_ENUM_DECL( YGLogLevel, diff --git a/packages/react-native/ReactCommon/yoga/yoga/YGGridTrackList.cpp b/packages/react-native/ReactCommon/yoga/yoga/YGGridTrackList.cpp new file mode 100644 index 000000000000..74176567582b --- /dev/null +++ b/packages/react-native/ReactCommon/yoga/yoga/YGGridTrackList.cpp @@ -0,0 +1,179 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +#include +#include +#include +#include +#include + +using namespace facebook::yoga; + +// Internal representation of a grid track value +struct YGGridTrackValue { + enum class Type { Points, Percent, Fr, Auto, MinMax }; + + Type type; + float value; + YGGridTrackValue* minValue; + YGGridTrackValue* maxValue; + + YGGridTrackValue(Type t, float v = 0.0f) + : type(t), value(v), minValue(nullptr), maxValue(nullptr) {} + + YGGridTrackValue(YGGridTrackValue* min, YGGridTrackValue* max) + : type(Type::MinMax), value(0.0f), minValue(min), maxValue(max) {} + + ~YGGridTrackValue() { + // MinMax owns its min/max values + if (type == Type::MinMax) { + delete minValue; + delete maxValue; + } + } + + StyleSizeLength toStyleSizeLength() const { + switch (type) { + case Type::Points: + return StyleSizeLength::points(value); + case Type::Percent: + return StyleSizeLength::percent(value); + case Type::Fr: + return StyleSizeLength::stretch(value); + case Type::Auto: + return StyleSizeLength::ofAuto(); + case Type::MinMax: + // MinMax should not call this, it needs special handling + return StyleSizeLength::ofAuto(); + } + return StyleSizeLength::ofAuto(); + } +}; + +// Internal representation of a grid track list +struct YGGridTrackList { + std::vector tracks; + + YGGridTrackList() = default; + YGGridTrackList(const YGGridTrackList&) = delete; + YGGridTrackList& operator=(const YGGridTrackList&) = delete; + YGGridTrackList(YGGridTrackList&&) = delete; + YGGridTrackList& operator=(YGGridTrackList&&) = delete; + + ~YGGridTrackList() { + for (auto* track : tracks) { + delete track; + } + } + + GridTrackList toGridTrackList() const { + GridTrackList result; + result.reserve(tracks.size()); + + for (auto* track : tracks) { + if (track->type == YGGridTrackValue::Type::MinMax) { + auto min = track->minValue->toStyleSizeLength(); + auto max = track->maxValue->toStyleSizeLength(); + result.push_back(GridTrackSize::minmax(min, max)); + } else { + switch (track->type) { + case YGGridTrackValue::Type::Points: + result.push_back(GridTrackSize::length(track->value)); + break; + case YGGridTrackValue::Type::Percent: + result.push_back(GridTrackSize::percent(track->value)); + break; + case YGGridTrackValue::Type::Fr: + result.push_back(GridTrackSize::fr(track->value)); + break; + case YGGridTrackValue::Type::Auto: + result.push_back(GridTrackSize::auto_()); + break; + case YGGridTrackValue::Type::MinMax: + // Already handled above + break; + } + } + } + + return result; + } +}; + +YGGridTrackListRef YGGridTrackListCreate() { + return new YGGridTrackList(); +} + +void YGGridTrackListFree(YGGridTrackListRef list) { + delete list; +} + +void YGGridTrackListAddTrack( + YGGridTrackListRef list, + YGGridTrackValueRef trackValue) { + if (list && trackValue) { + list->tracks.push_back(trackValue); + } +} + +YGGridTrackValueRef YGPoints(float points) { + return new YGGridTrackValue(YGGridTrackValue::Type::Points, points); +} + +YGGridTrackValueRef YGPercent(float percent) { + return new YGGridTrackValue(YGGridTrackValue::Type::Percent, percent); +} + +YGGridTrackValueRef YGFr(float fr) { + return new YGGridTrackValue(YGGridTrackValue::Type::Fr, fr); +} + +YGGridTrackValueRef YGAuto() { + return new YGGridTrackValue(YGGridTrackValue::Type::Auto); +} + +YGGridTrackValueRef YGMinMax(YGGridTrackValueRef min, YGGridTrackValueRef max) { + return new YGGridTrackValue(min, max); +} + +void YGNodeStyleSetGridTemplateRows( + YGNodeRef node, + YGGridTrackListRef trackList) { + if (node && trackList) { + auto* n = resolveRef(node); + n->style().setGridTemplateRows(trackList->toGridTrackList()); + n->markDirtyAndPropagate(); + } +} + +void YGNodeStyleSetGridTemplateColumns( + YGNodeRef node, + YGGridTrackListRef trackList) { + if (node && trackList) { + auto* n = resolveRef(node); + n->style().setGridTemplateColumns(trackList->toGridTrackList()); + n->markDirtyAndPropagate(); + } +} + +void YGNodeStyleSetGridAutoRows(YGNodeRef node, YGGridTrackListRef trackList) { + if (node && trackList) { + auto* n = resolveRef(node); + n->style().setGridAutoRows(trackList->toGridTrackList()); + n->markDirtyAndPropagate(); + } +} + +void YGNodeStyleSetGridAutoColumns( + YGNodeRef node, + YGGridTrackListRef trackList) { + if (node && trackList) { + auto* n = resolveRef(node); + n->style().setGridAutoColumns(trackList->toGridTrackList()); + n->markDirtyAndPropagate(); + } +} diff --git a/packages/react-native/ReactCommon/yoga/yoga/YGGridTrackList.h b/packages/react-native/ReactCommon/yoga/yoga/YGGridTrackList.h new file mode 100644 index 000000000000..a89e92cca672 --- /dev/null +++ b/packages/react-native/ReactCommon/yoga/yoga/YGGridTrackList.h @@ -0,0 +1,96 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +#pragma once + +#include +#include + +YG_EXTERN_C_BEGIN + +/** + * Opaque handle to a grid track list for building grid-template-rows/columns. + */ +typedef struct YGGridTrackList* YGGridTrackListRef; + +/** + * Opaque handle to a grid track value. + */ +typedef struct YGGridTrackValue* YGGridTrackValueRef; + +/** + * Create a new grid track list. + */ +YG_EXPORT YGGridTrackListRef YGGridTrackListCreate(void); + +/** + * Free a grid track list. + */ +YG_EXPORT void YGGridTrackListFree(YGGridTrackListRef list); + +/** + * Add a track to the grid track list. + */ +YG_EXPORT void YGGridTrackListAddTrack( + YGGridTrackListRef list, + YGGridTrackValueRef trackValue); + +/** + * Create a grid track value with a points (px) length. + */ +YG_EXPORT YGGridTrackValueRef YGPoints(float points); + +/** + * Create a grid track value with a percentage length. + */ +YG_EXPORT YGGridTrackValueRef YGPercent(float percent); + +/** + * Create a grid track value with a flexible (fr) length. + */ +YG_EXPORT YGGridTrackValueRef YGFr(float fr); + +/** + * Create a grid track value with auto sizing. + */ +YG_EXPORT YGGridTrackValueRef YGAuto(void); + +/** + * Create a grid track value with minmax(min, max) sizing. + */ +YG_EXPORT YGGridTrackValueRef +YGMinMax(YGGridTrackValueRef min, YGGridTrackValueRef max); + +/** + * Set the grid-template-rows property on a node. + */ +YG_EXPORT void YGNodeStyleSetGridTemplateRows( + YGNodeRef node, + YGGridTrackListRef trackList); + +/** + * Set the grid-template-columns property on a node. + */ +YG_EXPORT void YGNodeStyleSetGridTemplateColumns( + YGNodeRef node, + YGGridTrackListRef trackList); + +/** + * Set the grid-auto-rows property on a node. + */ +YG_EXPORT void YGNodeStyleSetGridAutoRows( + YGNodeRef node, + YGGridTrackListRef trackList); + +/** + * Set the grid-auto-columns property on a node. + */ +YG_EXPORT void YGNodeStyleSetGridAutoColumns( + YGNodeRef node, + YGGridTrackListRef trackList); + +YG_EXTERN_C_END diff --git a/packages/react-native/ReactCommon/yoga/yoga/YGNodeStyle.cpp b/packages/react-native/ReactCommon/yoga/yoga/YGNodeStyle.cpp index 4e77405b6c7d..f859c8427a97 100644 --- a/packages/react-native/ReactCommon/yoga/yoga/YGNodeStyle.cpp +++ b/packages/react-native/ReactCommon/yoga/yoga/YGNodeStyle.cpp @@ -74,6 +74,24 @@ YGJustify YGNodeStyleGetJustifyContent(const YGNodeConstRef node) { return unscopedEnum(resolveRef(node)->style().justifyContent()); } +void YGNodeStyleSetJustifyItems(YGNodeRef node, const YGJustify justifyItems) { + updateStyle<&Style::justifyItems, &Style::setJustifyItems>( + node, scopedEnum(justifyItems)); +} + +YGJustify YGNodeStyleGetJustifyItems(const YGNodeConstRef node) { + return unscopedEnum(resolveRef(node)->style().justifyItems()); +} + +void YGNodeStyleSetJustifySelf(YGNodeRef node, const YGJustify justifySelf) { + updateStyle<&Style::justifySelf, &Style::setJustifySelf>( + node, scopedEnum(justifySelf)); +} + +YGJustify YGNodeStyleGetJustifySelf(const YGNodeConstRef node) { + return unscopedEnum(resolveRef(node)->style().justifySelf()); +} + void YGNodeStyleSetAlignContent( const YGNodeRef node, const YGAlign alignContent) { @@ -503,3 +521,85 @@ void YGNodeStyleSetMaxHeightStretch(const YGNodeRef node) { YGValue YGNodeStyleGetMaxHeight(const YGNodeConstRef node) { return (YGValue)resolveRef(node)->style().maxDimension(Dimension::Height); } + +// Grid Item Placement Properties + +void YGNodeStyleSetGridColumnStart(YGNodeRef node, int32_t gridColumnStart) { + updateStyle<&Style::gridColumnStart, &Style::setGridColumnStart>( + node, GridLine::fromInteger(gridColumnStart)); +} + +void YGNodeStyleSetGridColumnStartAuto(YGNodeRef node) { + updateStyle<&Style::gridColumnStart, &Style::setGridColumnStart>( + node, GridLine::auto_()); +} + +void YGNodeStyleSetGridColumnStartSpan(YGNodeRef node, int32_t span) { + updateStyle<&Style::gridColumnStart, &Style::setGridColumnStart>( + node, GridLine::span(span)); +} + +int32_t YGNodeStyleGetGridColumnStart(YGNodeConstRef node) { + const auto& gridLine = resolveRef(node)->style().gridColumnStart(); + return gridLine.isInteger() ? gridLine.integer : 0; +} + +void YGNodeStyleSetGridColumnEnd(YGNodeRef node, int32_t gridColumnEnd) { + updateStyle<&Style::gridColumnEnd, &Style::setGridColumnEnd>( + node, GridLine::fromInteger(gridColumnEnd)); +} + +void YGNodeStyleSetGridColumnEndAuto(YGNodeRef node) { + updateStyle<&Style::gridColumnEnd, &Style::setGridColumnEnd>( + node, GridLine::auto_()); +} + +void YGNodeStyleSetGridColumnEndSpan(YGNodeRef node, int32_t span) { + updateStyle<&Style::gridColumnEnd, &Style::setGridColumnEnd>( + node, GridLine::span(span)); +} + +int32_t YGNodeStyleGetGridColumnEnd(YGNodeConstRef node) { + const auto& gridLine = resolveRef(node)->style().gridColumnEnd(); + return gridLine.isInteger() ? gridLine.integer : 0; +} + +void YGNodeStyleSetGridRowStart(YGNodeRef node, int32_t gridRowStart) { + updateStyle<&Style::gridRowStart, &Style::setGridRowStart>( + node, GridLine::fromInteger(gridRowStart)); +} + +void YGNodeStyleSetGridRowStartAuto(YGNodeRef node) { + updateStyle<&Style::gridRowStart, &Style::setGridRowStart>( + node, GridLine::auto_()); +} + +void YGNodeStyleSetGridRowStartSpan(YGNodeRef node, int32_t span) { + updateStyle<&Style::gridRowStart, &Style::setGridRowStart>( + node, GridLine::span(span)); +} + +int32_t YGNodeStyleGetGridRowStart(YGNodeConstRef node) { + const auto& gridLine = resolveRef(node)->style().gridRowStart(); + return gridLine.isInteger() ? gridLine.integer : 0; +} + +void YGNodeStyleSetGridRowEnd(YGNodeRef node, int32_t gridRowEnd) { + updateStyle<&Style::gridRowEnd, &Style::setGridRowEnd>( + node, GridLine::fromInteger(gridRowEnd)); +} + +void YGNodeStyleSetGridRowEndAuto(YGNodeRef node) { + updateStyle<&Style::gridRowEnd, &Style::setGridRowEnd>( + node, GridLine::auto_()); +} + +void YGNodeStyleSetGridRowEndSpan(YGNodeRef node, int32_t span) { + updateStyle<&Style::gridRowEnd, &Style::setGridRowEnd>( + node, GridLine::span(span)); +} + +int32_t YGNodeStyleGetGridRowEnd(YGNodeConstRef node) { + const auto& gridLine = resolveRef(node)->style().gridRowEnd(); + return gridLine.isInteger() ? gridLine.integer : 0; +} diff --git a/packages/react-native/ReactCommon/yoga/yoga/YGNodeStyle.h b/packages/react-native/ReactCommon/yoga/yoga/YGNodeStyle.h index 21b8326d8546..d1afd5c8aeeb 100644 --- a/packages/react-native/ReactCommon/yoga/yoga/YGNodeStyle.h +++ b/packages/react-native/ReactCommon/yoga/yoga/YGNodeStyle.h @@ -8,7 +8,6 @@ #pragma once #include - #include #include @@ -29,6 +28,14 @@ YG_EXPORT void YGNodeStyleSetJustifyContent( YGJustify justifyContent); YG_EXPORT YGJustify YGNodeStyleGetJustifyContent(YGNodeConstRef node); +YG_EXPORT void YGNodeStyleSetJustifyItems( + YGNodeRef node, + YGJustify justifyItems); +YG_EXPORT YGJustify YGNodeStyleGetJustifyItems(YGNodeConstRef node); + +YG_EXPORT void YGNodeStyleSetJustifySelf(YGNodeRef node, YGJustify justifySelf); +YG_EXPORT YGJustify YGNodeStyleGetJustifySelf(YGNodeConstRef node); + YG_EXPORT void YGNodeStyleSetAlignContent(YGNodeRef node, YGAlign alignContent); YG_EXPORT YGAlign YGNodeStyleGetAlignContent(YGNodeConstRef node); @@ -148,4 +155,27 @@ YG_EXPORT YGValue YGNodeStyleGetMaxHeight(YGNodeConstRef node); YG_EXPORT void YGNodeStyleSetAspectRatio(YGNodeRef node, float aspectRatio); YG_EXPORT float YGNodeStyleGetAspectRatio(YGNodeConstRef node); +// Grid Item Properties +YG_EXPORT void YGNodeStyleSetGridColumnStart( + YGNodeRef node, + int gridColumnStart); +YG_EXPORT void YGNodeStyleSetGridColumnStartAuto(YGNodeRef node); +YG_EXPORT void YGNodeStyleSetGridColumnStartSpan(YGNodeRef node, int span); +YG_EXPORT int YGNodeStyleGetGridColumnStart(YGNodeConstRef node); + +YG_EXPORT void YGNodeStyleSetGridColumnEnd(YGNodeRef node, int gridColumnEnd); +YG_EXPORT void YGNodeStyleSetGridColumnEndAuto(YGNodeRef node); +YG_EXPORT void YGNodeStyleSetGridColumnEndSpan(YGNodeRef node, int span); +YG_EXPORT int YGNodeStyleGetGridColumnEnd(YGNodeConstRef node); + +YG_EXPORT void YGNodeStyleSetGridRowStart(YGNodeRef node, int gridRowStart); +YG_EXPORT void YGNodeStyleSetGridRowStartAuto(YGNodeRef node); +YG_EXPORT void YGNodeStyleSetGridRowStartSpan(YGNodeRef node, int span); +YG_EXPORT int YGNodeStyleGetGridRowStart(YGNodeConstRef node); + +YG_EXPORT void YGNodeStyleSetGridRowEnd(YGNodeRef node, int gridRowEnd); +YG_EXPORT void YGNodeStyleSetGridRowEndAuto(YGNodeRef node); +YG_EXPORT void YGNodeStyleSetGridRowEndSpan(YGNodeRef node, int span); +YG_EXPORT int YGNodeStyleGetGridRowEnd(YGNodeConstRef node); + YG_EXTERN_C_END diff --git a/packages/react-native/ReactCommon/yoga/yoga/Yoga.h b/packages/react-native/ReactCommon/yoga/yoga/Yoga.h index 97f05ed3eade..25b7a8e83c8d 100644 --- a/packages/react-native/ReactCommon/yoga/yoga/Yoga.h +++ b/packages/react-native/ReactCommon/yoga/yoga/Yoga.h @@ -13,6 +13,7 @@ #include // IWYU pragma: export #include // IWYU pragma: export +#include // IWYU pragma: export #include // IWYU pragma: export #include // IWYU pragma: export #include // IWYU pragma: export diff --git a/packages/react-native/ReactCommon/yoga/yoga/algorithm/AbsoluteLayout.cpp b/packages/react-native/ReactCommon/yoga/yoga/algorithm/AbsoluteLayout.cpp index b2d8d8dbefcd..181dfcb1b0de 100644 --- a/packages/react-native/ReactCommon/yoga/yoga/algorithm/AbsoluteLayout.cpp +++ b/packages/react-native/ReactCommon/yoga/yoga/algorithm/AbsoluteLayout.cpp @@ -23,7 +23,11 @@ static inline void setFlexStartLayoutPosition( axis, direction, containingBlockWidth) + parent->getLayout().border(flexStartEdge(axis)); - if (!child->hasErrata(Errata::AbsolutePositionWithoutInsetsExcludesPadding)) { + // https://www.w3.org/TR/css-grid-1/#abspos + // absolute positioned grid items are positioned relative to the padding edge + // of the grid container + if (!child->hasErrata(Errata::AbsolutePositionWithoutInsetsExcludesPadding) && + parent->style().display() != Display::Grid) { position += parent->getLayout().padding(flexStartEdge(axis)); } @@ -40,7 +44,11 @@ static inline void setFlexEndLayoutPosition( child->style().computeFlexEndMargin( axis, direction, containingBlockWidth); - if (!child->hasErrata(Errata::AbsolutePositionWithoutInsetsExcludesPadding)) { + // https://www.w3.org/TR/css-grid-1/#abspos + // absolute positioned grid items are positioned relative to the padding edge + // of the grid container + if (!child->hasErrata(Errata::AbsolutePositionWithoutInsetsExcludesPadding) && + parent->style().display() != Display::Grid) { flexEndPosition += parent->getLayout().padding(flexEndEdge(axis)); } @@ -60,7 +68,11 @@ static inline void setCenterLayoutPosition( parent->getLayout().border(flexStartEdge(axis)) - parent->getLayout().border(flexEndEdge(axis)); - if (!child->hasErrata(Errata::AbsolutePositionWithoutInsetsExcludesPadding)) { + // https://www.w3.org/TR/css-grid-1/#abspos + // absolute positioned grid items are positioned relative to the padding edge + // of the grid container + if (!child->hasErrata(Errata::AbsolutePositionWithoutInsetsExcludesPadding) && + parent->style().display() != Display::Grid) { parentContentBoxSize -= parent->getLayout().padding(flexStartEdge(axis)); parentContentBoxSize -= parent->getLayout().padding(flexEndEdge(axis)); } @@ -74,7 +86,11 @@ static inline void setCenterLayoutPosition( child->style().computeFlexStartMargin( axis, direction, containingBlockWidth); - if (!child->hasErrata(Errata::AbsolutePositionWithoutInsetsExcludesPadding)) { + // https://www.w3.org/TR/css-grid-1/#abspos + // absolute positioned grid items are positioned relative to the padding edge + // of the grid container + if (!child->hasErrata(Errata::AbsolutePositionWithoutInsetsExcludesPadding) && + parent->style().display() != Display::Grid) { position += parent->getLayout().padding(flexStartEdge(axis)); } @@ -87,13 +103,19 @@ static void justifyAbsoluteChild( const Direction direction, const FlexDirection mainAxis, const float containingBlockWidth) { - const Justify parentJustifyContent = parent->style().justifyContent(); - switch (parentJustifyContent) { + const Justify justify = parent->style().display() == Display::Grid + ? resolveChildJustification(parent, child) + : parent->style().justifyContent(); + switch (justify) { + case Justify::Start: + case Justify::Auto: + case Justify::Stretch: case Justify::FlexStart: case Justify::SpaceBetween: setFlexStartLayoutPosition( parent, child, direction, mainAxis, containingBlockWidth); break; + case Justify::End: case Justify::FlexEnd: setFlexEndLayoutPosition( parent, child, direction, mainAxis, containingBlockWidth); @@ -124,6 +146,7 @@ static void alignAbsoluteChild( } switch (itemAlign) { + case Align::Start: case Align::Auto: case Align::FlexStart: case Align::Baseline: @@ -134,6 +157,7 @@ static void alignAbsoluteChild( setFlexStartLayoutPosition( parent, child, direction, crossAxis, containingBlockWidth); break; + case Align::End: case Align::FlexEnd: setFlexEndLayoutPosition( parent, child, direction, crossAxis, containingBlockWidth); @@ -234,9 +258,15 @@ void layoutAbsoluteChild( LayoutData& layoutMarkerData, const uint32_t depth, const uint32_t generationCount) { - const FlexDirection mainAxis = - resolveDirection(node->style().flexDirection(), direction); - const FlexDirection crossAxis = resolveCrossDirection(mainAxis, direction); + // For grid containers, use inline (Row) and block (Column) axes for + // positioning, since grid alignment properties (justify-self, align-self) + // operate on inline/block axes, not main/cross axes based on flex-direction. + const FlexDirection mainAxis = node->style().display() == Display::Grid + ? resolveDirection(FlexDirection::Row, direction) + : resolveDirection(node->style().flexDirection(), direction); + const FlexDirection crossAxis = node->style().display() == Display::Grid + ? FlexDirection::Column + : resolveCrossDirection(mainAxis, direction); const bool isMainAxisRow = isRow(mainAxis); float childWidth = YGUndefined; diff --git a/packages/react-native/ReactCommon/yoga/yoga/algorithm/Align.h b/packages/react-native/ReactCommon/yoga/yoga/algorithm/Align.h index bb21fe5dcaf0..b12ae7fd532b 100644 --- a/packages/react-native/ReactCommon/yoga/yoga/algorithm/Align.h +++ b/packages/react-native/ReactCommon/yoga/yoga/algorithm/Align.h @@ -20,12 +20,23 @@ inline Align resolveChildAlignment( const Align align = child->style().alignSelf() == Align::Auto ? node->style().alignItems() : child->style().alignSelf(); - if (align == Align::Baseline && isColumn(node->style().flexDirection())) { + + if (node->style().display() == Display::Flex && align == Align::Baseline && + isColumn(node->style().flexDirection())) { return Align::FlexStart; } + return align; } +inline Justify resolveChildJustification( + const yoga::Node* node, + const yoga::Node* child) { + return child->style().justifySelf() == Justify::Auto + ? node->style().justifyItems() + : child->style().justifySelf(); +} + /** * Fallback alignment to use on overflow * https://www.w3.org/TR/css-align-3/#distribution-values diff --git a/packages/react-native/ReactCommon/yoga/yoga/algorithm/CalculateLayout.cpp b/packages/react-native/ReactCommon/yoga/yoga/algorithm/CalculateLayout.cpp index 81a5f3b8a0b6..95a2ba513bed 100644 --- a/packages/react-native/ReactCommon/yoga/yoga/algorithm/CalculateLayout.cpp +++ b/packages/react-native/ReactCommon/yoga/yoga/algorithm/CalculateLayout.cpp @@ -35,7 +35,7 @@ namespace facebook::yoga { std::atomic gCurrentGenerationCount(0); -static void constrainMaxSizeForMode( +void constrainMaxSizeForMode( const yoga::Node* node, Direction direction, FlexDirection axis, @@ -468,7 +468,7 @@ static bool measureNodeWithFixedSize( return false; } -static void zeroOutLayoutRecursively(yoga::Node* const node) { +void zeroOutLayoutRecursively(yoga::Node* const node) { node->getLayout() = {}; node->setLayoutDimension(0, Dimension::Width); node->setLayoutDimension(0, Dimension::Height); @@ -480,7 +480,7 @@ static void zeroOutLayoutRecursively(yoga::Node* const node) { } } -static void cleanupContentsNodesRecursively(yoga::Node* const node) { +void cleanupContentsNodesRecursively(yoga::Node* const node) { if (node->hasContentsChildren()) [[unlikely]] { node->cloneContentsChildrenIfNeeded(); for (auto child : node->getChildren()) { @@ -498,7 +498,7 @@ static void cleanupContentsNodesRecursively(yoga::Node* const node) { } } -static float calculateAvailableInnerDimension( +float calculateAvailableInnerDimension( const yoga::Node* const node, const Direction direction, const Dimension dimension, @@ -1046,6 +1046,14 @@ static void justifyMainAxis( if (flexLine.numberOfAutoMargins == 0) { switch (justifyContent) { + case Justify::Start: + case Justify::End: + case Justify::Auto: + // No-Op + break; + case Justify::Stretch: + // No-Op + break; case Justify::Center: leadingMainDim = flexLine.layout.remainingFreeSpace / 2; break; @@ -1799,6 +1807,10 @@ static void calculateLayoutImpl( : fallbackAlignment(node->style().alignContent()); switch (alignContent) { + case Align::Start: + case Align::End: + // No-Op + break; case Align::FlexEnd: currentLead += remainingAlignContentDim; break; @@ -1886,6 +1898,10 @@ static void calculateLayoutImpl( } if (child->style().positionType() != PositionType::Absolute) { switch (resolveChildAlignment(node, child)) { + case Align::Start: + case Align::End: + // No-Op + break; case Align::FlexStart: { child->setLayoutPosition( currentLead + diff --git a/packages/react-native/ReactCommon/yoga/yoga/algorithm/CalculateLayout.h b/packages/react-native/ReactCommon/yoga/yoga/algorithm/CalculateLayout.h index 5e6884ec1a49..86b3c61afe1f 100644 --- a/packages/react-native/ReactCommon/yoga/yoga/algorithm/CalculateLayout.h +++ b/packages/react-native/ReactCommon/yoga/yoga/algorithm/CalculateLayout.h @@ -35,4 +35,26 @@ bool calculateLayoutInternal( uint32_t depth, uint32_t generationCount); +void constrainMaxSizeForMode( + const yoga::Node* node, + Direction direction, + FlexDirection axis, + float ownerAxisSize, + float ownerWidth, + /*in_out*/ SizingMode* mode, + /*in_out*/ float* size); + +float calculateAvailableInnerDimension( + const yoga::Node* const node, + const Direction direction, + const Dimension dimension, + const float availableDim, + const float paddingAndBorder, + const float ownerDim, + const float ownerWidth); + +void zeroOutLayoutRecursively(yoga::Node* const node); + +void cleanupContentsNodesRecursively(yoga::Node* const node); + } // namespace facebook::yoga diff --git a/packages/react-native/ReactCommon/yoga/yoga/enums/Align.h b/packages/react-native/ReactCommon/yoga/yoga/enums/Align.h index 3896fe2b8b1d..e1b8b29bd74e 100644 --- a/packages/react-native/ReactCommon/yoga/yoga/enums/Align.h +++ b/packages/react-native/ReactCommon/yoga/yoga/enums/Align.h @@ -25,11 +25,13 @@ enum class Align : uint8_t { SpaceBetween = YGAlignSpaceBetween, SpaceAround = YGAlignSpaceAround, SpaceEvenly = YGAlignSpaceEvenly, + Start = YGAlignStart, + End = YGAlignEnd, }; template <> constexpr int32_t ordinalCount() { - return 9; + return 11; } constexpr Align scopedEnum(YGAlign unscoped) { diff --git a/packages/react-native/ReactCommon/yoga/yoga/enums/Display.h b/packages/react-native/ReactCommon/yoga/yoga/enums/Display.h index 9bf23c0ac7bd..9edbee80b591 100644 --- a/packages/react-native/ReactCommon/yoga/yoga/enums/Display.h +++ b/packages/react-native/ReactCommon/yoga/yoga/enums/Display.h @@ -19,11 +19,12 @@ enum class Display : uint8_t { Flex = YGDisplayFlex, None = YGDisplayNone, Contents = YGDisplayContents, + Grid = YGDisplayGrid, }; template <> constexpr int32_t ordinalCount() { - return 3; + return 4; } constexpr Display scopedEnum(YGDisplay unscoped) { diff --git a/packages/react-native/ReactCommon/yoga/yoga/enums/GridTrackType.h b/packages/react-native/ReactCommon/yoga/yoga/enums/GridTrackType.h new file mode 100644 index 000000000000..eb6e8332bc9d --- /dev/null +++ b/packages/react-native/ReactCommon/yoga/yoga/enums/GridTrackType.h @@ -0,0 +1,43 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +// @generated by enums.py +// clang-format off +#pragma once + +#include +#include +#include + +namespace facebook::yoga { + +enum class GridTrackType : uint8_t { + Auto = YGGridTrackTypeAuto, + Points = YGGridTrackTypePoints, + Percent = YGGridTrackTypePercent, + Fr = YGGridTrackTypeFr, + Minmax = YGGridTrackTypeMinmax, +}; + +template <> +constexpr int32_t ordinalCount() { + return 5; +} + +constexpr GridTrackType scopedEnum(YGGridTrackType unscoped) { + return static_cast(unscoped); +} + +constexpr YGGridTrackType unscopedEnum(GridTrackType scoped) { + return static_cast(scoped); +} + +inline const char* toString(GridTrackType e) { + return YGGridTrackTypeToString(unscopedEnum(e)); +} + +} // namespace facebook::yoga diff --git a/packages/react-native/ReactCommon/yoga/yoga/enums/Justify.h b/packages/react-native/ReactCommon/yoga/yoga/enums/Justify.h index 255baa6e27d8..db4afece9aa5 100644 --- a/packages/react-native/ReactCommon/yoga/yoga/enums/Justify.h +++ b/packages/react-native/ReactCommon/yoga/yoga/enums/Justify.h @@ -16,17 +16,21 @@ namespace facebook::yoga { enum class Justify : uint8_t { + Auto = YGJustifyAuto, FlexStart = YGJustifyFlexStart, Center = YGJustifyCenter, FlexEnd = YGJustifyFlexEnd, SpaceBetween = YGJustifySpaceBetween, SpaceAround = YGJustifySpaceAround, SpaceEvenly = YGJustifySpaceEvenly, + Stretch = YGJustifyStretch, + Start = YGJustifyStart, + End = YGJustifyEnd, }; template <> constexpr int32_t ordinalCount() { - return 6; + return 10; } constexpr Justify scopedEnum(YGJustify unscoped) { diff --git a/packages/react-native/ReactCommon/yoga/yoga/event/event.cpp b/packages/react-native/ReactCommon/yoga/yoga/event/event.cpp index e286ded0555c..ac6735d6d44b 100644 --- a/packages/react-native/ReactCommon/yoga/yoga/event/event.cpp +++ b/packages/react-native/ReactCommon/yoga/yoga/event/event.cpp @@ -29,6 +29,8 @@ const char* LayoutPassReasonToString(const LayoutPassReason value) { return "abs_measure"; case LayoutPassReason::kFlexMeasure: return "flex_measure"; + case LayoutPassReason::kGridLayout: + return "grid_layout"; default: return "unknown"; } diff --git a/packages/react-native/ReactCommon/yoga/yoga/event/event.h b/packages/react-native/ReactCommon/yoga/yoga/event/event.h index 587c1cd06367..0d032240dd94 100644 --- a/packages/react-native/ReactCommon/yoga/yoga/event/event.h +++ b/packages/react-native/ReactCommon/yoga/yoga/event/event.h @@ -32,6 +32,7 @@ enum struct LayoutPassReason : int { kMeasureChild = 5, kAbsMeasureChild = 6, kFlexMeasure = 7, + kGridLayout = 8, COUNT }; diff --git a/packages/react-native/ReactCommon/yoga/yoga/node/Node.h b/packages/react-native/ReactCommon/yoga/yoga/node/Node.h index 8068c8149731..d22c4c1ef040 100644 --- a/packages/react-native/ReactCommon/yoga/yoga/node/Node.h +++ b/packages/react-native/ReactCommon/yoga/yoga/node/Node.h @@ -294,15 +294,15 @@ class YG_EXPORT Node : public ::YGNode { bool isNodeFlexible(); void reset(); - private: - // Used to allow resetting the node - Node& operator=(Node&&) noexcept = default; - float relativePosition( FlexDirection axis, Direction direction, float axisSize) const; + private: + // Used to allow resetting the node + Node& operator=(Node&&) noexcept = default; + void useWebDefaults() { style_.setFlexDirection(FlexDirection::Row); style_.setAlignContent(Align::Stretch); diff --git a/packages/react-native/ReactCommon/yoga/yoga/style/GridLine.h b/packages/react-native/ReactCommon/yoga/yoga/style/GridLine.h new file mode 100644 index 000000000000..a330fe1b0294 --- /dev/null +++ b/packages/react-native/ReactCommon/yoga/yoga/style/GridLine.h @@ -0,0 +1,61 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +#pragma once + +#include +#include +#include + +namespace facebook::yoga { + +// https://www.w3.org/TR/css-grid-1/#typedef-grid-row-start-grid-line +enum class GridLineType : uint8_t { + Auto, + Integer, + Span, +}; + +struct GridLine { + GridLineType type; + // Line position (1, 2, -1, -2, etc) + int32_t integer; + + static GridLine auto_() { + return GridLine{GridLineType::Auto, 0}; + } + + static GridLine fromInteger(int32_t value) { + return GridLine{GridLineType::Integer, value}; + } + + static GridLine span(int32_t value) { + return GridLine{GridLineType::Span, value}; + } + + bool isAuto() const { + return type == GridLineType::Auto; + } + + bool isInteger() const { + return type == GridLineType::Integer; + } + + bool isSpan() const { + return type == GridLineType::Span; + } + + bool operator==(const GridLine& other) const { + return type == other.type && integer == other.integer; + } + + bool operator!=(const GridLine& other) const { + return !(*this == other); + } +}; + +} // namespace facebook::yoga diff --git a/packages/react-native/ReactCommon/yoga/yoga/style/GridTrack.h b/packages/react-native/ReactCommon/yoga/yoga/style/GridTrack.h new file mode 100644 index 000000000000..4b4c1c1a19d5 --- /dev/null +++ b/packages/react-native/ReactCommon/yoga/yoga/style/GridTrack.h @@ -0,0 +1,65 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +#pragma once + +#include +#include + +namespace facebook::yoga { +// https://www.w3.org/TR/css-grid-1/#typedef-track-size +struct GridTrackSize { + StyleSizeLength minSizingFunction; + StyleSizeLength maxSizingFunction; + + // These are used in the grid layout algorithm when distributing spaces among + // tracks + // TODO: maybe move them to TrackSizing since these are track states + float baseSize = 0.0f; + float growthLimit = 0.0f; + bool infinitelyGrowable = false; + + // Static factory methods for common cases + static GridTrackSize auto_() { + return GridTrackSize{StyleSizeLength::ofAuto(), StyleSizeLength::ofAuto()}; + } + + static GridTrackSize length(float points) { + auto len = StyleSizeLength::points(points); + return GridTrackSize{len, len}; + } + + static GridTrackSize fr(float fraction) { + // Flex sizing function is always a max sizing function + return GridTrackSize{ + StyleSizeLength::ofAuto(), StyleSizeLength::stretch(fraction)}; + } + + static GridTrackSize percent(float percentage) { + return GridTrackSize{ + StyleSizeLength::percent(percentage), + StyleSizeLength::percent(percentage)}; + } + + static GridTrackSize minmax(StyleSizeLength min, StyleSizeLength max) { + return GridTrackSize{min, max}; + } + + bool operator==(const GridTrackSize& other) const { + return minSizingFunction == other.minSizingFunction && + maxSizingFunction == other.maxSizingFunction; + } + + bool operator!=(const GridTrackSize& other) const { + return !(*this == other); + } +}; + +// Grid track list for grid-template-rows/columns properties +using GridTrackList = std::vector; + +} // namespace facebook::yoga diff --git a/packages/react-native/ReactCommon/yoga/yoga/style/Style.h b/packages/react-native/ReactCommon/yoga/yoga/style/Style.h index 566b6934e699..728cc283b247 100644 --- a/packages/react-native/ReactCommon/yoga/yoga/style/Style.h +++ b/packages/react-native/ReactCommon/yoga/yoga/style/Style.h @@ -29,6 +29,8 @@ #include #include #include +#include +#include #include #include #include @@ -65,6 +67,20 @@ class YG_EXPORT Style { justifyContent_ = value; } + Justify justifyItems() const { + return justifyItems_; + } + void setJustifyItems(Justify value) { + justifyItems_ = value; + } + + Justify justifySelf() const { + return justifySelf_; + } + void setJustifySelf(Justify value) { + justifySelf_ = value; + } + Align alignContent() const { return alignContent_; } @@ -191,6 +207,64 @@ class YG_EXPORT Style { pool_.store(minDimensions_[yoga::to_underlying(axis)], value); } + // Grid Container Properties + const GridTrackList& gridTemplateColumns() const { + return gridTemplateColumns_; + } + void setGridTemplateColumns(GridTrackList value) { + gridTemplateColumns_ = std::move(value); + } + + const GridTrackList& gridTemplateRows() const { + return gridTemplateRows_; + } + void setGridTemplateRows(GridTrackList value) { + gridTemplateRows_ = std::move(value); + } + + const GridTrackList& gridAutoColumns() const { + return gridAutoColumns_; + } + void setGridAutoColumns(GridTrackList value) { + gridAutoColumns_ = std::move(value); + } + + const GridTrackList& gridAutoRows() const { + return gridAutoRows_; + } + void setGridAutoRows(GridTrackList value) { + gridAutoRows_ = std::move(value); + } + + // Grid Item Properties + const GridLine& gridColumnStart() const { + return gridColumnStart_; + } + void setGridColumnStart(GridLine value) { + gridColumnStart_ = std::move(value); + } + + const GridLine& gridColumnEnd() const { + return gridColumnEnd_; + } + void setGridColumnEnd(GridLine value) { + gridColumnEnd_ = std::move(value); + } + + const GridLine& gridRowStart() const { + return gridRowStart_; + } + void setGridRowStart(GridLine value) { + gridRowStart_ = std::move(value); + } + + const GridLine& gridRowEnd() const { + return gridRowEnd_; + } + void setGridRowEnd(GridLine value) { + gridRowEnd_ = std::move(value); + } + FloatOptional resolvedMinDimension( Direction direction, Dimension axis, @@ -515,6 +589,12 @@ class YG_EXPORT Style { return maxOrDefined(gap.resolve(ownerSize).unwrap(), 0.0f); } + float computeGapForDimension(Dimension dimension, float ownerSize) const { + auto gap = + dimension == Dimension::Width ? computeColumnGap() : computeRowGap(); + return maxOrDefined(gap.resolve(ownerSize).unwrap(), 0.0f); + } + bool flexStartMarginIsAuto(FlexDirection axis, Direction direction) const { return computeMargin(flexStartEdge(axis), direction).isAuto(); } @@ -523,10 +603,20 @@ class YG_EXPORT Style { return computeMargin(flexEndEdge(axis), direction).isAuto(); } + bool inlineStartMarginIsAuto(FlexDirection axis, Direction direction) const { + return computeMargin(inlineStartEdge(axis, direction), direction).isAuto(); + } + + bool inlineEndMarginIsAuto(FlexDirection axis, Direction direction) const { + return computeMargin(inlineEndEdge(axis, direction), direction).isAuto(); + } + bool operator==(const Style& other) const { return direction_ == other.direction_ && flexDirection_ == other.flexDirection_ && justifyContent_ == other.justifyContent_ && + justifyItems_ == other.justifyItems_ && + justifySelf_ == other.justifySelf_ && alignContent_ == other.alignContent_ && alignItems_ == other.alignItems_ && alignSelf_ == other.alignSelf_ && positionType_ == other.positionType_ && flexWrap_ == other.flexWrap_ && @@ -545,7 +635,15 @@ class YG_EXPORT Style { minDimensions_, pool_, other.minDimensions_, other.pool_) && lengthsEqual( maxDimensions_, pool_, other.maxDimensions_, other.pool_) && - numbersEqual(aspectRatio_, pool_, other.aspectRatio_, other.pool_); + numbersEqual(aspectRatio_, pool_, other.aspectRatio_, other.pool_) && + gridTemplateColumns_ == other.gridTemplateColumns_ && + gridTemplateRows_ == other.gridTemplateRows_ && + gridAutoColumns_ == other.gridAutoColumns_ && + gridAutoRows_ == other.gridAutoRows_ && + gridColumnStart_ == other.gridColumnStart_ && + gridColumnEnd_ == other.gridColumnEnd_ && + gridRowStart_ == other.gridRowStart_ && + gridRowEnd_ == other.gridRowEnd_; } bool operator!=(const Style& other) const { @@ -727,6 +825,8 @@ class YG_EXPORT Style { FlexDirection flexDirection_ : bitCount() = FlexDirection::Column; Justify justifyContent_ : bitCount() = Justify::FlexStart; + Justify justifyItems_ : bitCount() = Justify::Stretch; + Justify justifySelf_ : bitCount() = Justify::Auto; Align alignContent_ : bitCount() = Align::FlexStart; Align alignItems_ : bitCount() = Align::Stretch; Align alignSelf_ : bitCount() = Align::Auto; @@ -753,6 +853,16 @@ class YG_EXPORT Style { Dimensions maxDimensions_{}; StyleValueHandle aspectRatio_{}; + // Grid properties + GridTrackList gridTemplateColumns_{}; + GridTrackList gridTemplateRows_{}; + GridTrackList gridAutoColumns_{}; + GridTrackList gridAutoRows_{}; + GridLine gridColumnStart_{}; + GridLine gridColumnEnd_{}; + GridLine gridRowStart_{}; + GridLine gridRowEnd_{}; + StyleValuePool pool_; }; diff --git a/packages/react-native/ReactCommon/yoga/yoga/style/StyleSizeLength.h b/packages/react-native/ReactCommon/yoga/yoga/style/StyleSizeLength.h index fc4d371e421b..76e079b2da58 100644 --- a/packages/react-native/ReactCommon/yoga/yoga/style/StyleSizeLength.h +++ b/packages/react-native/ReactCommon/yoga/yoga/style/StyleSizeLength.h @@ -42,6 +42,12 @@ class StyleSizeLength { : StyleSizeLength{FloatOptional{value}, Unit::Percent}; } + constexpr static StyleSizeLength stretch(float fraction) { + return yoga::isUndefined(fraction) || yoga::isinf(fraction) + ? undefined() + : StyleSizeLength{FloatOptional{fraction}, Unit::Stretch}; + } + constexpr static StyleSizeLength ofAuto() { return StyleSizeLength{{}, Unit::Auto}; } @@ -98,7 +104,7 @@ class StyleSizeLength { return value_; } - constexpr FloatOptional resolve(float referenceLength) { + constexpr FloatOptional resolve(float referenceLength) const { #ifdef __clang__ #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wswitch-enum"