Skip to content

Commit 12696b2

Browse files
committed
feat: calc support
1 parent 81a65d2 commit 12696b2

27 files changed

Lines changed: 1806 additions & 208 deletions

packages/react-native/React/Views/RCTLayout.m

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,8 @@ CGFloat RCTCoreGraphicsFloatFromYogaValue(YGValue value, CGFloat baseFloatValue)
8787
case YGUnitFitContent:
8888
case YGUnitStretch:
8989
return baseFloatValue;
90+
case YGUnitDynamic:
91+
return RCTCoreGraphicsFloatFromYogaFloat(YGUndefined);
9092
}
9193
}
9294

packages/react-native/ReactAndroid/src/main/java/com/facebook/yoga/YogaUnit.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,8 @@ public enum YogaUnit {
1616
AUTO(3),
1717
MAX_CONTENT(4),
1818
FIT_CONTENT(5),
19-
STRETCH(6);
19+
STRETCH(6),
20+
DYNAMIC(7);
2021

2122
private final int mIntValue;
2223

@@ -37,6 +38,7 @@ public static YogaUnit fromInt(int value) {
3738
case 4: return MAX_CONTENT;
3839
case 5: return FIT_CONTENT;
3940
case 6: return STRETCH;
41+
case 7: return DYNAMIC;
4042
default: throw new IllegalArgumentException("Unknown enum value: " + value);
4143
}
4244
}

packages/react-native/ReactCommon/react/renderer/components/view/YogaLayoutableShadowNode.cpp

Lines changed: 33 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -143,7 +143,9 @@ YogaLayoutableShadowNode::YogaLayoutableShadowNode(
143143
}
144144

145145
if (fragment.props) {
146-
updateYogaProps();
146+
auto& sourceProps =
147+
static_cast<const YogaStylableProps&>(*sourceShadowNode.getProps());
148+
updateYogaProps(sourceProps.calcExpressions);
147149
}
148150

149151
if (fragment.children) {
@@ -375,15 +377,18 @@ void YogaLayoutableShadowNode::updateYogaChildren() {
375377
yogaNode_.setDirty(!isClean);
376378
}
377379

378-
void YogaLayoutableShadowNode::updateYogaProps() {
380+
void YogaLayoutableShadowNode::updateYogaProps(
381+
const CalcExpressions& previousCalcExpressions) {
379382
ensureUnsealed();
380383

381384
auto& props = static_cast<const YogaStylableProps&>(*props_);
382385
auto styleResult = applyAliasedProps(props.yogaStyle, props);
383386

384387
// Resetting `dirty` flag only if `yogaStyle` portion of `Props` was
385-
// changed.
386-
if (!YGNodeIsDirty(&yogaNode_) && (styleResult != yogaNode_.style())) {
388+
// changed or calc expressions changed.
389+
if (!YGNodeIsDirty(&yogaNode_) &&
390+
(props.calcExpressions != previousCalcExpressions ||
391+
styleResult != yogaNode_.style())) {
387392
yogaNode_.setDirty(true);
388393
}
389394

@@ -888,6 +893,30 @@ YogaLayoutableShadowNode& YogaLayoutableShadowNode::shadowNodeFromContext(
888893
*static_cast<ShadowNode*>(YGNodeGetContext(yogaNode)));
889894
}
890895

896+
YGValue YogaLayoutableShadowNode::yogaNodeCalcValueResolver(
897+
YGNodeConstRef yogaNode,
898+
YGValueDynamicID id,
899+
YGValueDynamicContext context) {
900+
if (!yogaNode) {
901+
return {};
902+
}
903+
904+
auto& node = shadowNodeFromContext(yogaNode);
905+
auto& props = static_cast<const YogaStylableProps&>(*node.props_);
906+
auto key = static_cast<CalcExpressionPropertyID>(id);
907+
if (!props.calcExpressions.contains(key)) {
908+
return {};
909+
}
910+
911+
auto& calc = props.calcExpressions.at(key);
912+
return YGValue(
913+
calc.resolve(
914+
context.referenceLength,
915+
threadLocalLayoutContext.viewportSize.width,
916+
threadLocalLayoutContext.viewportSize.height),
917+
YGUnitPoint);
918+
};
919+
891920
yoga::Config& YogaLayoutableShadowNode::initializeYogaConfig(
892921
yoga::Config& config,
893922
YGConfigConstRef previousConfig) {

packages/react-native/ReactCommon/react/renderer/components/view/YogaLayoutableShadowNode.h

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ class YogaLayoutableShadowNode : public LayoutableShadowNode {
5353

5454
void updateYogaChildren();
5555

56-
void updateYogaProps();
56+
void updateYogaProps(const CalcExpressions& previousCalcExpressions = {});
5757

5858
/*
5959
* Sets layoutable size of node.
@@ -82,6 +82,11 @@ class YogaLayoutableShadowNode : public LayoutableShadowNode {
8282

8383
Rect getContentBounds() const;
8484

85+
static YGValue yogaNodeCalcValueResolver(
86+
YGNodeConstRef yogaNode,
87+
YGValueDynamicID id,
88+
YGValueDynamicContext context);
89+
8590
protected:
8691
/**
8792
* Subclasses which provide MeasurableYogaNode may override to signal that a

packages/react-native/ReactCommon/react/renderer/components/view/YogaStylableProps.cpp

Lines changed: 339 additions & 0 deletions
Large diffs are not rendered by default.

packages/react-native/ReactCommon/react/renderer/components/view/YogaStylableProps.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,10 @@
99

1010
#include <yoga/style/Style.h>
1111

12+
#include <react/renderer/components/view/primitives.h>
1213
#include <react/renderer/core/Props.h>
1314
#include <react/renderer/core/PropsParserContext.h>
15+
#include <react/renderer/css/CSSCalc.h>
1416
#include <react/renderer/debug/DebugStringConvertible.h>
1517

1618
namespace facebook::react {
@@ -57,6 +59,8 @@ class YogaStylableProps : public Props {
5759
yoga::Style::Length paddingBlockStart;
5860
yoga::Style::Length paddingBlockEnd;
5961

62+
CalcExpressions calcExpressions;
63+
6064
#if RN_DEBUG_STRING_CONVERTIBLE
6165

6266
#pragma mark - DebugStringConvertible (Partial)
@@ -70,6 +74,11 @@ class YogaStylableProps : public Props {
7074
const PropsParserContext &context,
7175
const YogaStylableProps &sourceProps,
7276
const RawProps &rawProps);
77+
78+
CalcExpressions buildCalcExpressions(
79+
const PropsParserContext &context,
80+
const RawProps &rawProps,
81+
const CalcExpressions &defaultValue);
7382
};
7483

7584
} // namespace facebook::react

packages/react-native/ReactCommon/react/renderer/components/view/primitives.h

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77

88
#pragma once
99

10+
#include <react/renderer/css/CSSCalc.h>
1011
#include <react/renderer/graphics/Color.h>
1112
#include <react/renderer/graphics/RectangleCorners.h>
1213
#include <react/renderer/graphics/RectangleEdges.h>
@@ -248,4 +249,46 @@ struct BorderMetrics {
248249
bool operator==(const BorderMetrics &rhs) const = default;
249250
};
250251

252+
enum class CalcExpressionPropertyID : uint8_t {
253+
Width,
254+
Height,
255+
MinWidth,
256+
MinHeight,
257+
MaxWidth,
258+
MaxHeight,
259+
FlexBasis,
260+
RowGap,
261+
ColumnGap,
262+
Gap,
263+
Left,
264+
Top,
265+
Right,
266+
Bottom,
267+
Start,
268+
End,
269+
InsetInline,
270+
InsetBlock,
271+
Inset,
272+
MarginLeft,
273+
MarginTop,
274+
MarginRight,
275+
MarginBottom,
276+
MarginStart,
277+
MarginEnd,
278+
MarginHorizontal,
279+
MarginVertical,
280+
MarginAll,
281+
PaddingLeft,
282+
PaddingTop,
283+
PaddingRight,
284+
PaddingBottom,
285+
PaddingStart,
286+
PaddingEnd,
287+
PaddingHorizontal,
288+
PaddingVertical,
289+
PaddingAll,
290+
};
291+
292+
using CalcExpressions = std::unordered_map<CalcExpressionPropertyID, CSSCalc>;
293+
251294
} // namespace facebook::react

packages/react-native/ReactCommon/react/renderer/core/graphicsConversions.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,10 @@ inline folly::dynamic toDynamic(const YGValue &dimension)
6969
return dimension.value;
7070
case YGUnitPercent:
7171
return std::format("{}%", dimension.value);
72+
case YGUnitDynamic:
73+
// YGValue do not support YGUnitDynamic yet.
74+
// Return placeholder that won't parse as valid calc.
75+
return "calc(dynamic)";
7276
}
7377

7478
return nullptr;

0 commit comments

Comments
 (0)