Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"type": "prerelease",
"comment": "Implement overflow property support for Fabric architecture",
"packageName": "react-native-windows",
"email": "nitchaudhary@microsoft.com",
"dependentChangeType": "patch"
}
Original file line number Diff line number Diff line change
Expand Up @@ -1070,6 +1070,12 @@ void ViewComponentView::ensureVisual() noexcept {
}
OuterVisual().InsertAt(m_visual, 0);
}

// Create m_contentVisual as a child of m_visual if not already created
if (!m_contentVisual) {
m_contentVisual = m_compContext.CreateSpriteVisual();
m_visual.InsertAt(m_contentVisual, 0); // Insert at index 0 so it's below border visuals
}
}

winrt::Microsoft::ReactNative::ComponentView ViewComponentView::Create(
Expand All @@ -1084,7 +1090,8 @@ winrt::Microsoft::ReactNative::Composition::Experimental::IVisual
ViewComponentView::VisualToMountChildrenInto() noexcept {
if (m_builder && m_builder->VisualToMountChildrenIntoHandler())
return m_builder->VisualToMountChildrenIntoHandler()(*this);
return Visual();
// Mount children into m_contentVisual
return m_contentVisual ? m_contentVisual : Visual();
}

void ViewComponentView::MountChildComponentView(
Expand Down Expand Up @@ -1140,6 +1147,21 @@ void ViewComponentView::updateProps(
// update BaseComponentView props
updateAccessibilityProps(oldViewProps, newViewProps);
updateTransformProps(oldViewProps, newViewProps, Visual());

// Handle overflow property changes
if (oldViewProps.yogaStyle.overflow() != newViewProps.yogaStyle.overflow()) {
auto compVisual =
winrt::Microsoft::ReactNative::Composition::Experimental::MicrosoftCompositionContextHelper::InnerVisual(
Visual());
if (compVisual) {
if (newViewProps.yogaStyle.overflow() == facebook::yoga::Overflow::Hidden) {
compVisual.Clip(Compositor().CreateInsetClip(0.0f, 0.0f, 0.0f, 0.0f));
} else {
compVisual.Clip(nullptr);
}
}
}

base_type::updateProps(props, oldProps);

m_props = std::static_pointer_cast<facebook::react::ViewProps const>(props);
Expand Down Expand Up @@ -1317,6 +1339,48 @@ void ViewComponentView::updateLayoutMetrics(
Visual().Size(
{layoutMetrics.frame.size.width * layoutMetrics.pointScaleFactor,
layoutMetrics.frame.size.height * layoutMetrics.pointScaleFactor});

// Size and offset m_contentVisual to match the content area, excluding borders
if (m_contentVisual && m_props) {
auto borderMetrics = BorderPrimitive::resolveAndAlignBorderMetrics(layoutMetrics, *m_props);
float borderLeft = borderMetrics.borderWidths.left;
float borderTop = borderMetrics.borderWidths.top;
float borderRight = borderMetrics.borderWidths.right;
float borderBottom = borderMetrics.borderWidths.bottom;
float scale = layoutMetrics.pointScaleFactor;
float contentWidth = layoutMetrics.frame.size.width * scale - borderLeft - borderRight;
float contentHeight = layoutMetrics.frame.size.height * scale - borderTop - borderBottom;
m_contentVisual.Offset({borderLeft, borderTop, 0});
m_contentVisual.Size({std::max(0.f, contentWidth), std::max(0.f, contentHeight)});

// Apply clipping to m_contentVisual for overflow: hidden
if (m_props->getClipsContentToBounds()) {
// Calculate inner border radii for clipping (0 for rectangular clip)
facebook::react::RectangleCorners<facebook::react::CornerRadii> innerRadii;
innerRadii.topLeft = {
std::max(0.f, borderMetrics.borderRadii.topLeft.horizontal - borderLeft),
std::max(0.f, borderMetrics.borderRadii.topLeft.vertical - borderTop)};
innerRadii.topRight = {
std::max(0.f, borderMetrics.borderRadii.topRight.horizontal - borderRight),
std::max(0.f, borderMetrics.borderRadii.topRight.vertical - borderTop)};
innerRadii.bottomLeft = {
std::max(0.f, borderMetrics.borderRadii.bottomLeft.horizontal - borderLeft),
std::max(0.f, borderMetrics.borderRadii.bottomLeft.vertical - borderBottom)};
innerRadii.bottomRight = {
std::max(0.f, borderMetrics.borderRadii.bottomRight.horizontal - borderRight),
std::max(0.f, borderMetrics.borderRadii.bottomRight.vertical - borderBottom)};

winrt::com_ptr<ID2D1PathGeometry> pathGeometry = BorderPrimitive::GenerateRoundedRectPathGeometry(
m_compContext, innerRadii, {0, 0, 0, 0}, {0, 0, std::max(0.f, contentWidth), std::max(0.f, contentHeight)});

m_contentVisual.as<::Microsoft::ReactNative::Composition::Experimental::IVisualInterop>()->SetClippingPath(
pathGeometry.get());
} else {
// Clear any existing clip
m_contentVisual.as<::Microsoft::ReactNative::Composition::Experimental::IVisualInterop>()->SetClippingPath(
nullptr);
}
}
}

void ViewComponentView::prepareForRecycle() noexcept {}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -231,6 +231,7 @@ struct ViewComponentView : public ViewComponentViewT<
bool m_hasNonVisualChildren{false};
facebook::react::SharedViewProps m_props;
winrt::Microsoft::ReactNative::Composition::Experimental::IVisual m_visual{nullptr};
winrt::Microsoft::ReactNative::Composition::Experimental::IVisual m_contentVisual{nullptr};
winrt::Microsoft::ReactNative::Composition::Experimental::CreateInternalVisualDelegate m_createInternalVisualHandler{
nullptr};
};
Expand Down
Loading