From 8f8c16437b239fb7a2d311eccfc7a907c2b9b969 Mon Sep 17 00:00:00 2001 From: Anupriya Verma <54227869+anupriya13@users.noreply.github.com> Date: Mon, 29 Sep 2025 08:43:52 +0530 Subject: [PATCH 1/3] Revert "[Fabric] Implement snapToAlignment property for ScrollView (#14841)" This reverts commit 6bd0793c1a9e2afd31ac1f00d3b0eb5bb8138e1f. --- .../CompositionSwitcher.idl | 9 +---- .../Composition/CompositionContextHelper.cpp | 23 +------------ .../Composition/ScrollViewComponentView.cpp | 34 ++++++------------- .../Composition/ScrollViewComponentView.h | 3 -- 4 files changed, 12 insertions(+), 57 deletions(-) diff --git a/vnext/Microsoft.ReactNative/CompositionSwitcher.idl b/vnext/Microsoft.ReactNative/CompositionSwitcher.idl index 88d5084aec8..f6fb8fffe01 100644 --- a/vnext/Microsoft.ReactNative/CompositionSwitcher.idl +++ b/vnext/Microsoft.ReactNative/CompositionSwitcher.idl @@ -31,13 +31,6 @@ namespace Microsoft.ReactNative.Composition.Experimental SwitchThumb, }; - enum SnapAlignment - { - Start, - Center, - End, - }; - [webhosthidden] [uuid("172def51-9e1a-4e3c-841a-e5a470065acc")] // uuid needed for empty interfaces [version(0)] @@ -129,7 +122,7 @@ namespace Microsoft.ReactNative.Composition.Experimental void SetMaximumZoomScale(Single maximumZoomScale); void SetMinimumZoomScale(Single minimumZoomScale); Boolean Horizontal; - void SetSnapPoints(Boolean snapToStart, Boolean snapToEnd, Windows.Foundation.Collections.IVectorView offsets, SnapAlignment snapToAlignment); + void SetSnapPoints(Boolean snapToStart, Boolean snapToEnd, Windows.Foundation.Collections.IVectorView offsets); } [webhosthidden] diff --git a/vnext/Microsoft.ReactNative/Fabric/Composition/CompositionContextHelper.cpp b/vnext/Microsoft.ReactNative/Fabric/Composition/CompositionContextHelper.cpp index 38bd02ba907..592375815d2 100644 --- a/vnext/Microsoft.ReactNative/Fabric/Composition/CompositionContextHelper.cpp +++ b/vnext/Microsoft.ReactNative/Fabric/Composition/CompositionContextHelper.cpp @@ -27,8 +27,6 @@ namespace Microsoft::ReactNative::Composition::Experimental { -using namespace winrt::Microsoft::ReactNative::Composition::Experimental; - template struct CompositionTypeTraits {}; @@ -903,11 +901,9 @@ struct CompScrollerVisual : winrt::implements< void SetSnapPoints( bool snapToStart, bool snapToEnd, - winrt::Windows::Foundation::Collections::IVectorView const &offsets, - SnapAlignment snapToAlignment) noexcept { + winrt::Windows::Foundation::Collections::IVectorView const &offsets) noexcept { m_snapToStart = snapToStart; m_snapToEnd = snapToEnd; - m_snapToAlignment = snapToAlignment; m_snapToOffsets.clear(); if (offsets) { for (auto const &offset : offsets) { @@ -1164,22 +1160,6 @@ struct CompScrollerVisual : winrt::implements< } snapPositions.insert(snapPositions.end(), m_snapToOffsets.begin(), m_snapToOffsets.end()); - - // Adjust snap positions based on alignment - const float viewportSize = m_horizontal ? visualSize.x : visualSize.y; - if (m_snapToAlignment == SnapAlignment::Center) { - // For center alignment, offset snap positions by half the viewport size - for (auto &position : snapPositions) { - position = std::max(0.0f, position - viewportSize / 2.0f); - } - } else if (m_snapToAlignment == SnapAlignment::End) { - // For end alignment, offset snap positions by the full viewport size - for (auto &position : snapPositions) { - position = std::max(0.0f, position - viewportSize); - } - } - // For Start alignment, no adjustment needed - std::sort(snapPositions.begin(), snapPositions.end()); snapPositions.erase(std::unique(snapPositions.begin(), snapPositions.end()), snapPositions.end()); @@ -1307,7 +1287,6 @@ struct CompScrollerVisual : winrt::implements< bool m_snapToStart{true}; bool m_snapToEnd{true}; std::vector m_snapToOffsets; - SnapAlignment m_snapToAlignment{SnapAlignment::Start}; bool m_inertia{false}; bool m_custom{false}; bool m_interacting{false}; diff --git a/vnext/Microsoft.ReactNative/Fabric/Composition/ScrollViewComponentView.cpp b/vnext/Microsoft.ReactNative/Fabric/Composition/ScrollViewComponentView.cpp index 41946935277..e47b2d7198f 100644 --- a/vnext/Microsoft.ReactNative/Fabric/Composition/ScrollViewComponentView.cpp +++ b/vnext/Microsoft.ReactNative/Fabric/Composition/ScrollViewComponentView.cpp @@ -817,13 +817,16 @@ void ScrollViewComponentView::updateProps( } if (oldViewProps.snapToStart != newViewProps.snapToStart || oldViewProps.snapToEnd != newViewProps.snapToEnd || - oldViewProps.snapToOffsets != newViewProps.snapToOffsets) { - if (oldViewProps.snapToInterval != newViewProps.snapToInterval) { + oldViewProps.snapToOffsets != newViewProps.snapToOffsets || + oldViewProps.snapToInterval != newViewProps.snapToInterval) { + if ((newViewProps.snapToInterval > 0 || oldViewProps.snapToInterval != newViewProps.snapToInterval) && + (newViewProps.decelerationRate >= 0.99)) { + // Use the comprehensive updateSnapPoints method when snapToInterval is involved + // Typically used in combination with snapToAlignment and decelerationRate="fast". updateSnapPoints(); } else { - const auto snapToOffsets = CreateSnapToOffsets(newViewProps.snapToOffsets); - m_scrollVisual.SetSnapPoints( - newViewProps.snapToStart, newViewProps.snapToEnd, snapToOffsets.GetView(), SnapAlignment::Center); + auto snapToOffsets = CreateSnapToOffsets(newViewProps.snapToOffsets); + m_scrollVisual.SetSnapPoints(newViewProps.snapToStart, newViewProps.snapToEnd, snapToOffsets.GetView()); } } } @@ -1477,29 +1480,12 @@ void ScrollViewComponentView::updateDecelerationRate(float value) noexcept { m_scrollVisual.SetDecelerationRate({value, value, value}); } -SnapAlignment ScrollViewComponentView::convertSnapToAlignment( - facebook::react::ScrollViewSnapToAlignment alignment) noexcept { - switch (alignment) { - case facebook::react::ScrollViewSnapToAlignment::Center: - return SnapAlignment::Center; - case facebook::react::ScrollViewSnapToAlignment::End: - return SnapAlignment::End; - case facebook::react::ScrollViewSnapToAlignment::Start: - default: - return SnapAlignment::Start; - } -} - void ScrollViewComponentView::updateSnapPoints() noexcept { const auto &viewProps = *std::static_pointer_cast(this->viewProps()); const auto snapToOffsets = CreateSnapToOffsets(viewProps.snapToOffsets); - // Typically used in combination with snapToAlignment and decelerationRate="fast" - auto snapAlignment = SnapAlignment::Center; - auto decelerationRate = viewProps.decelerationRate; // snapToOffsets has priority over snapToInterval (matches React Native behavior) - if (viewProps.snapToInterval > 0 && decelerationRate >= 0.99) { - snapAlignment = convertSnapToAlignment(viewProps.snapToAlignment); + if (viewProps.snapToInterval > 0) { // Generate snap points based on interval // Calculate the content size to determine how many intervals to create float contentLength = viewProps.horizontal @@ -1520,6 +1506,6 @@ void ScrollViewComponentView::updateSnapPoints() noexcept { } } - m_scrollVisual.SetSnapPoints(viewProps.snapToStart, viewProps.snapToEnd, snapToOffsets.GetView(), snapAlignment); + m_scrollVisual.SetSnapPoints(viewProps.snapToStart, viewProps.snapToEnd, snapToOffsets.GetView()); } } // namespace winrt::Microsoft::ReactNative::Composition::implementation diff --git a/vnext/Microsoft.ReactNative/Fabric/Composition/ScrollViewComponentView.h b/vnext/Microsoft.ReactNative/Fabric/Composition/ScrollViewComponentView.h index 12bdd6c009b..d3efe720bae 100644 --- a/vnext/Microsoft.ReactNative/Fabric/Composition/ScrollViewComponentView.h +++ b/vnext/Microsoft.ReactNative/Fabric/Composition/ScrollViewComponentView.h @@ -18,8 +18,6 @@ namespace winrt::Microsoft::ReactNative::Composition::implementation { -using namespace Microsoft::ReactNative::Composition::Experimental; - struct ScrollBarComponent; struct ScrollViewComponentView : ScrollViewComponentViewT { @@ -137,7 +135,6 @@ struct ScrollInteractionTrackerOwner : public winrt::implements< winrt::Microsoft::ReactNative::Composition::Experimental::IScrollPositionChangedArgs const &args) noexcept; void updateShowsHorizontalScrollIndicator(bool value) noexcept; void updateShowsVerticalScrollIndicator(bool value) noexcept; - SnapAlignment convertSnapToAlignment(facebook::react::ScrollViewSnapToAlignment alignment) noexcept; winrt::Windows::Foundation::Collections::IVector CreateSnapToOffsets(const std::vector &offsets); facebook::react::Size m_contentSize; From ef9a869890a34672ae6c16935467c0de3e6e88d0 Mon Sep 17 00:00:00 2001 From: Anupriya Verma <54227869+anupriya13@users.noreply.github.com> Date: Mon, 29 Sep 2025 08:44:16 +0530 Subject: [PATCH 2/3] Revert "[Fabric] Implement snapToInterval property for ScrollView (#14847)" This reverts commit 2cde3f11b7c67db52b6b56203cc3df560ac48ea7. --- .../Composition/ScrollViewComponentView.cpp | 57 ++----------------- .../Composition/ScrollViewComponentView.h | 2 - 2 files changed, 5 insertions(+), 54 deletions(-) diff --git a/vnext/Microsoft.ReactNative/Fabric/Composition/ScrollViewComponentView.cpp b/vnext/Microsoft.ReactNative/Fabric/Composition/ScrollViewComponentView.cpp index e47b2d7198f..3915bfd78d4 100644 --- a/vnext/Microsoft.ReactNative/Fabric/Composition/ScrollViewComponentView.cpp +++ b/vnext/Microsoft.ReactNative/Fabric/Composition/ScrollViewComponentView.cpp @@ -27,7 +27,6 @@ namespace winrt::Microsoft::ReactNative::Composition::implementation { constexpr float c_scrollerLineDelta = 16.0f; -constexpr auto c_maxSnapPoints = 1000; enum class ScrollbarHitRegion : int { Unknown = -1, @@ -741,15 +740,6 @@ void ScrollViewComponentView::updateBackgroundColor(const facebook::react::Share } } -winrt::Windows::Foundation::Collections::IVector ScrollViewComponentView::CreateSnapToOffsets( - const std::vector &offsets) { - auto snapToOffsets = winrt::single_threaded_vector(); - for (const auto &offset : offsets) { - snapToOffsets.Append(offset); - } - return snapToOffsets; -} - void ScrollViewComponentView::updateProps( facebook::react::Props::Shared const &props, facebook::react::Props::Shared const &oldProps) noexcept { @@ -817,17 +807,12 @@ void ScrollViewComponentView::updateProps( } if (oldViewProps.snapToStart != newViewProps.snapToStart || oldViewProps.snapToEnd != newViewProps.snapToEnd || - oldViewProps.snapToOffsets != newViewProps.snapToOffsets || - oldViewProps.snapToInterval != newViewProps.snapToInterval) { - if ((newViewProps.snapToInterval > 0 || oldViewProps.snapToInterval != newViewProps.snapToInterval) && - (newViewProps.decelerationRate >= 0.99)) { - // Use the comprehensive updateSnapPoints method when snapToInterval is involved - // Typically used in combination with snapToAlignment and decelerationRate="fast". - updateSnapPoints(); - } else { - auto snapToOffsets = CreateSnapToOffsets(newViewProps.snapToOffsets); - m_scrollVisual.SetSnapPoints(newViewProps.snapToStart, newViewProps.snapToEnd, snapToOffsets.GetView()); + oldViewProps.snapToOffsets != newViewProps.snapToOffsets) { + const auto snapToOffsets = winrt::single_threaded_vector(); + for (const auto &offset : newViewProps.snapToOffsets) { + snapToOffsets.Append(static_cast(offset)); } + m_scrollVisual.SetSnapPoints(newViewProps.snapToStart, newViewProps.snapToEnd, snapToOffsets.GetView()); } } @@ -878,9 +863,6 @@ void ScrollViewComponentView::updateContentVisualSize() noexcept { m_verticalScrollbarComponent->ContentSize(contentSize); m_horizontalScrollbarComponent->ContentSize(contentSize); m_scrollVisual.ContentSize(contentSize); - - // Update snap points if snapToInterval is being used, as content size affects the number of snap points - updateSnapPoints(); } void ScrollViewComponentView::prepareForRecycle() noexcept {} @@ -1479,33 +1461,4 @@ void ScrollViewComponentView::updateShowsVerticalScrollIndicator(bool value) noe void ScrollViewComponentView::updateDecelerationRate(float value) noexcept { m_scrollVisual.SetDecelerationRate({value, value, value}); } - -void ScrollViewComponentView::updateSnapPoints() noexcept { - const auto &viewProps = *std::static_pointer_cast(this->viewProps()); - const auto snapToOffsets = CreateSnapToOffsets(viewProps.snapToOffsets); - - // snapToOffsets has priority over snapToInterval (matches React Native behavior) - if (viewProps.snapToInterval > 0) { - // Generate snap points based on interval - // Calculate the content size to determine how many intervals to create - float contentLength = viewProps.horizontal - ? std::max(m_contentSize.width, m_layoutMetrics.frame.size.width) * m_layoutMetrics.pointScaleFactor - : std::max(m_contentSize.height, m_layoutMetrics.frame.size.height) * m_layoutMetrics.pointScaleFactor; - - float interval = static_cast(viewProps.snapToInterval) * m_layoutMetrics.pointScaleFactor; - - // Ensure we have a reasonable minimum interval to avoid infinite loops or excessive memory usage - if (interval >= 1.0f && contentLength > 0) { - // Generate offsets at each interval, but limit the number of snap points to avoid excessive memory usage - int snapPointCount = 0; - - for (float offset = 0; offset <= contentLength && snapPointCount < c_maxSnapPoints; offset += interval) { - snapToOffsets.Append(offset); - snapPointCount++; - } - } - } - - m_scrollVisual.SetSnapPoints(viewProps.snapToStart, viewProps.snapToEnd, snapToOffsets.GetView()); -} } // namespace winrt::Microsoft::ReactNative::Composition::implementation diff --git a/vnext/Microsoft.ReactNative/Fabric/Composition/ScrollViewComponentView.h b/vnext/Microsoft.ReactNative/Fabric/Composition/ScrollViewComponentView.h index d3efe720bae..495f0a1e2c4 100644 --- a/vnext/Microsoft.ReactNative/Fabric/Composition/ScrollViewComponentView.h +++ b/vnext/Microsoft.ReactNative/Fabric/Composition/ScrollViewComponentView.h @@ -121,7 +121,6 @@ struct ScrollInteractionTrackerOwner : public winrt::implements< private: void updateDecelerationRate(float value) noexcept; void updateContentVisualSize() noexcept; - void updateSnapPoints() noexcept; bool scrollToEnd(bool animate) noexcept; bool scrollToStart(bool animate) noexcept; bool scrollDown(float delta, bool animate) noexcept; @@ -135,7 +134,6 @@ struct ScrollInteractionTrackerOwner : public winrt::implements< winrt::Microsoft::ReactNative::Composition::Experimental::IScrollPositionChangedArgs const &args) noexcept; void updateShowsHorizontalScrollIndicator(bool value) noexcept; void updateShowsVerticalScrollIndicator(bool value) noexcept; - winrt::Windows::Foundation::Collections::IVector CreateSnapToOffsets(const std::vector &offsets); facebook::react::Size m_contentSize; winrt::Microsoft::ReactNative::Composition::Experimental::IScrollVisual m_scrollVisual{nullptr}; From 278023ad6e1b68ee5e5ed4f230c85848eac54e87 Mon Sep 17 00:00:00 2001 From: Anupriya Verma <54227869+anupriya13@users.noreply.github.com> Date: Mon, 29 Sep 2025 08:50:39 +0530 Subject: [PATCH 3/3] Change files --- ...ative-windows-fcafad1a-9c58-416e-9736-36b0bd838c3c.json | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 change/react-native-windows-fcafad1a-9c58-416e-9736-36b0bd838c3c.json diff --git a/change/react-native-windows-fcafad1a-9c58-416e-9736-36b0bd838c3c.json b/change/react-native-windows-fcafad1a-9c58-416e-9736-36b0bd838c3c.json new file mode 100644 index 00000000000..3b09fecbf70 --- /dev/null +++ b/change/react-native-windows-fcafad1a-9c58-416e-9736-36b0bd838c3c.json @@ -0,0 +1,7 @@ +{ + "type": "prerelease", + "comment": "Revert \"[Fabric] Implement snapToInterval property for ScrollView (#14847)\"", + "packageName": "react-native-windows", + "email": "54227869+anupriya13@users.noreply.github.com", + "dependentChangeType": "patch" +}