From 3d99dfe121042057d97214dadbd6036c6d236607 Mon Sep 17 00:00:00 2001 From: Andrew Coates <30809111+acoates-ms@users.noreply.github.com> Date: Tue, 7 Mar 2023 12:30:50 -0800 Subject: [PATCH] [Fabric] add support for enableFocusRing (#11323) * [Fabric] add support for enableFocusRing * Change files * format * fix * fixes --- ...-dbb905be-476d-45bd-9f45-1196b92ce512.json | 7 + .../CompositionSwitcher.idl | 10 ++ .../Composition/CompositionContextHelper.cpp | 60 +++++++++ .../CompositionViewComponentView.cpp | 121 +++++++++++++----- .../CompositionViewComponentView.h | 8 ++ .../Fabric/Composition/ImageComponentView.cpp | 8 +- .../Composition/ParagraphComponentView.cpp | 11 +- .../Composition/ScrollViewComponentView.cpp | 46 ++++--- .../Composition/ScrollViewComponentView.h | 3 +- .../Composition/SwitchComponentView.cpp | 10 +- .../WindowsTextInputComponentView.cpp | 8 +- .../Fabric/FabricUIManagerModule.cpp | 2 +- .../renderer/components/view/ViewProps.cpp | 8 ++ .../renderer/components/view/ViewProps.h | 1 + 14 files changed, 225 insertions(+), 78 deletions(-) create mode 100644 change/react-native-windows-dbb905be-476d-45bd-9f45-1196b92ce512.json diff --git a/change/react-native-windows-dbb905be-476d-45bd-9f45-1196b92ce512.json b/change/react-native-windows-dbb905be-476d-45bd-9f45-1196b92ce512.json new file mode 100644 index 00000000000..053078132e1 --- /dev/null +++ b/change/react-native-windows-dbb905be-476d-45bd-9f45-1196b92ce512.json @@ -0,0 +1,7 @@ +{ + "type": "prerelease", + "comment": "[Fabric] add support for enableFocusRing", + "packageName": "react-native-windows", + "email": "30809111+acoates-ms@users.noreply.github.com", + "dependentChangeType": "patch" +} diff --git a/vnext/Microsoft.ReactNative/CompositionSwitcher.idl b/vnext/Microsoft.ReactNative/CompositionSwitcher.idl index 79386bcb86f..fe30cef3e44 100644 --- a/vnext/Microsoft.ReactNative/CompositionSwitcher.idl +++ b/vnext/Microsoft.ReactNative/CompositionSwitcher.idl @@ -101,6 +101,15 @@ namespace Microsoft.ReactNative.Composition Boolean IsVisible { get; set; }; } + [webhosthidden] + [experimental] + interface IFocusVisual + { + IVisual InnerVisual { get; }; + Boolean IsFocused { get; set; }; + Single ScaleFactor { get; set; }; + } + [webhosthidden] [experimental] interface ICompositionContext @@ -112,6 +121,7 @@ namespace Microsoft.ReactNative.Composition SpriteVisual CreateSpriteVisual(); ScrollVisual CreateScrollerVisual(); ICaretVisual CreateCaretVisual(); + IFocusVisual CreateFocusVisual(); IDropShadow CreateDropShadow(); IBrush CreateColorBrush(Windows.UI.Color color); SurfaceBrush CreateSurfaceBrush(ICompositionDrawingSurface surface); diff --git a/vnext/Microsoft.ReactNative/Fabric/Composition/CompositionContextHelper.cpp b/vnext/Microsoft.ReactNative/Fabric/Composition/CompositionContextHelper.cpp index 8047a99944c..1966b2a08de 100644 --- a/vnext/Microsoft.ReactNative/Fabric/Composition/CompositionContextHelper.cpp +++ b/vnext/Microsoft.ReactNative/Fabric/Composition/CompositionContextHelper.cpp @@ -192,6 +192,10 @@ struct CompVisual : public winrt::implements< } void SetClippingPath(ID2D1Geometry *clippingPath) noexcept { + if (!clippingPath) { + m_visual.Clip(nullptr); + return; + } auto geometry = winrt::make(clippingPath); auto path = winrt::Windows::UI::Composition::CompositionPath(geometry); auto pathgeo = m_visual.Compositor().CreatePathGeometry(path); @@ -512,6 +516,10 @@ struct CompScrollerVisual : winrt::Microsoft::ReactNative::Composition::implemen } void SetClippingPath(ID2D1Geometry *clippingPath) noexcept { + if (!clippingPath) { + m_visual.Clip(nullptr); + return; + } auto geometry = winrt::make(clippingPath); auto path = winrt::Windows::UI::Composition::CompositionPath(geometry); auto pathgeo = m_visual.Compositor().CreatePathGeometry(path); @@ -628,6 +636,54 @@ struct CompCaretVisual : winrt::implements { + CompFocusVisual(winrt::Windows::UI::Composition::Compositor const &compositor) + : m_compVisual(compositor.CreateSpriteVisual()), m_brush(compositor.CreateNineGridBrush()) { + m_visual = winrt::make(m_compVisual); + + m_compVisual.Opacity(1.0f); + m_compVisual.RelativeSizeAdjustment({1, 1}); + + m_brush.Source(compositor.CreateColorBrush(winrt::Windows::UI::Colors::Black())); + m_brush.IsCenterHollow(true); + } + + winrt::Microsoft::ReactNative::Composition::IVisual InnerVisual() const noexcept { + return m_visual; + } + + bool IsFocused() const noexcept { + return m_compVisual.Brush() != nullptr; + } + + void IsFocused(bool value) noexcept { + if (value) { + m_compVisual.Brush(m_brush); + } else { + m_compVisual.Brush(nullptr); + } + } + + float ScaleFactor() const noexcept { + return m_scaleFactor; + } + + void ScaleFactor(float scaleFactor) noexcept { + if (m_scaleFactor == scaleFactor) { + return; + } + m_scaleFactor = scaleFactor; + auto inset = 2 * scaleFactor; + m_brush.SetInsets(inset, inset, inset, inset); + } + + private: + float m_scaleFactor{0}; + const winrt::Windows::UI::Composition::CompositionNineGridBrush m_brush; + const winrt::Windows::UI::Composition::SpriteVisual m_compVisual; + winrt::Microsoft::ReactNative::Composition::IVisual m_visual{nullptr}; +}; + struct CompContext : winrt::implements< CompContext, winrt::Microsoft::ReactNative::Composition::ICompositionContext, @@ -736,6 +792,10 @@ struct CompContext : winrt::implements< return winrt::make(m_compositor); } + winrt::Microsoft::ReactNative::Composition::IFocusVisual CreateFocusVisual() noexcept { + return winrt::make(m_compositor); + } + winrt::Windows::UI::Composition::CompositionGraphicsDevice CompositionGraphicsDevice() noexcept { if (!m_compositionGraphicsDevice) { // To create a composition graphics device, we need to QI for another interface diff --git a/vnext/Microsoft.ReactNative/Fabric/Composition/CompositionViewComponentView.cpp b/vnext/Microsoft.ReactNative/Fabric/Composition/CompositionViewComponentView.cpp index 0b2e1f381b3..78253242945 100644 --- a/vnext/Microsoft.ReactNative/Fabric/Composition/CompositionViewComponentView.cpp +++ b/vnext/Microsoft.ReactNative/Fabric/Composition/CompositionViewComponentView.cpp @@ -21,7 +21,12 @@ namespace Microsoft::ReactNative { CompositionBaseComponentView::CompositionBaseComponentView( const winrt::Microsoft::ReactNative::Composition::ICompositionContext &compContext, facebook::react::Tag tag) - : m_tag(tag), m_compContext(compContext) {} + : m_tag(tag), m_compContext(compContext) { + m_outerVisual = compContext.CreateSpriteVisual(); // TODO could be a raw ContainerVisual if we had a + // CreateContainerVisual in ICompositionContext + m_focusVisual = compContext.CreateFocusVisual(); + m_outerVisual.InsertAt(m_focusVisual.InnerVisual(), 0); +} facebook::react::Tag CompositionBaseComponentView::tag() const noexcept { return m_tag; @@ -71,10 +76,14 @@ bool CompositionBaseComponentView::runOnChildren(bool forward, Mso::FunctoronBlur(); + showFocusVisual(false); } void CompositionBaseComponentView::onFocusGained() noexcept { m_eventEmitter->onFocus(); + if (m_enableFocusVisual) { + showFocusVisual(true); + } } void CompositionBaseComponentView::updateEventEmitter( @@ -83,6 +92,18 @@ void CompositionBaseComponentView::updateEventEmitter( } void CompositionBaseComponentView::handleCommand(std::string const &commandName, folly::dynamic const &arg) noexcept { + if (commandName == "focus") { + if (auto root = rootComponentView()) { + root->SetFocusedComponent(this); + } + return; + } + if (commandName == "blur") { + if (auto root = rootComponentView()) { + root->SetFocusedComponent(nullptr); // Todo store this component as previously focused element + } + return; + } assert(false); // Unhandled command } @@ -980,6 +1001,19 @@ void CompositionBaseComponentView::UpdateSpecialBorderLayers( } } +winrt::Microsoft::ReactNative::Composition::IVisual CompositionBaseComponentView::OuterVisual() const noexcept { + return m_outerVisual ? m_outerVisual : Visual(); +} + +void CompositionBaseComponentView::showFocusVisual(bool show) noexcept { + if (show) { + assert(m_enableFocusVisual); + m_focusVisual.IsFocused(true); + } else { + m_focusVisual.IsFocused(false); + } +} + void CompositionBaseComponentView::updateBorderProps( const facebook::react::ViewProps &oldViewProps, const facebook::react::ViewProps &newViewProps) noexcept { @@ -988,6 +1022,11 @@ void CompositionBaseComponentView::updateBorderProps( oldViewProps.borderStyles != newViewProps.borderStyles) { m_needsBorderUpdate = true; } + + m_enableFocusVisual = newViewProps.enableFocusRing; + if (!m_enableFocusVisual) { + showFocusVisual(false); + } } void CompositionBaseComponentView::updateBorderLayoutMetrics( @@ -1014,6 +1053,16 @@ void CompositionBaseComponentView::updateBorderLayoutMetrics( if (m_layoutMetrics != layoutMetrics) { m_needsBorderUpdate = true; } + + m_focusVisual.ScaleFactor(layoutMetrics.pointScaleFactor); + OuterVisual().Size( + {layoutMetrics.frame.size.width * layoutMetrics.pointScaleFactor, + layoutMetrics.frame.size.height * layoutMetrics.pointScaleFactor}); + OuterVisual().Offset({ + layoutMetrics.frame.origin.x * layoutMetrics.pointScaleFactor, + layoutMetrics.frame.origin.y * layoutMetrics.pointScaleFactor, + 0.0f, + }); } void CompositionBaseComponentView::indexOffsetForBorder(uint32_t &index) const noexcept { @@ -1077,7 +1126,7 @@ void CompositionBaseComponentView::EnsureTransformMatrixFacade() noexcept { .CreateExpressionAnimation( L"Matrix4x4.CreateFromScale(PS.dpiScale3Inv) * Matrix4x4.CreateFromTranslation(PS.translation) * PS.transform * Matrix4x4.CreateFromScale(PS.dpiScale3)"); expression.SetReferenceParameter(L"PS", centerPointPropSet); - winrt::Microsoft::ReactNative::Composition::implementation::CompositionContextHelper::InnerVisual(Visual()) + winrt::Microsoft::ReactNative::Composition::implementation::CompositionContextHelper::InnerVisual(OuterVisual()) .StartAnimation(L"TransformMatrix", expression); } @@ -1101,6 +1150,7 @@ CompositionViewComponentView::CompositionViewComponentView( static auto const defaultProps = std::make_shared(); m_props = defaultProps; m_visual = m_compContext.CreateSpriteVisual(); + OuterVisual().InsertAt(m_visual, 0); } std::vector @@ -1117,7 +1167,7 @@ void CompositionViewComponentView::mountChildComponentView( childComponentView.parent(this); - m_visual.InsertAt(static_cast(childComponentView).Visual(), index); + m_visual.InsertAt(static_cast(childComponentView).OuterVisual(), index); } void CompositionViewComponentView::unmountChildComponentView( @@ -1128,7 +1178,7 @@ void CompositionViewComponentView::unmountChildComponentView( indexOffsetForBorder(index); childComponentView.parent(nullptr); - m_visual.Remove(static_cast(childComponentView).Visual()); + m_visual.Remove(static_cast(childComponentView).OuterVisual()); } void CompositionViewComponentView::updateProps( @@ -1240,7 +1290,7 @@ void CompositionViewComponentView::updateLayoutMetrics( facebook::react::LayoutMetrics const &oldLayoutMetrics) noexcept { // Set Position & Size Properties if ((layoutMetrics.displayType != m_layoutMetrics.displayType)) { - m_visual.IsVisible(layoutMetrics.displayType != facebook::react::DisplayType::None); + OuterVisual().IsVisible(layoutMetrics.displayType != facebook::react::DisplayType::None); } updateBorderLayoutMetrics(layoutMetrics, *m_props); @@ -1251,11 +1301,6 @@ void CompositionViewComponentView::updateLayoutMetrics( m_visual.Size( {layoutMetrics.frame.size.width * layoutMetrics.pointScaleFactor, layoutMetrics.frame.size.height * layoutMetrics.pointScaleFactor}); - m_visual.Offset({ - layoutMetrics.frame.origin.x * layoutMetrics.pointScaleFactor, - layoutMetrics.frame.origin.y * layoutMetrics.pointScaleFactor, - 0.0f, - }); } void CompositionViewComponentView::finalizeUpdates(RNComponentViewUpdateMask updateMask) noexcept { @@ -1278,6 +1323,19 @@ bool CompositionViewComponentView::focusable() const noexcept { return m_props->focusable; } +IComponentView *lastDeepChild(IComponentView &view) noexcept { + auto current = &view; + while (current) { + auto children = current->children(); + auto itLastChild = children.rbegin(); + if (itLastChild == children.rend()) { + break; + } + current = *itLastChild; + } + return current; +} + bool walkTree(IComponentView &view, bool forward, Mso::Functor &fn) noexcept { if (forward) { if (fn(view)) { @@ -1289,40 +1347,41 @@ bool walkTree(IComponentView &view, bool forward, Mso::Functorparent(); + while (parent) { auto &parentsChildren = parent->children(); - auto itNextView = std::find(parentsChildren.begin(), parentsChildren.end(), &view); + auto itNextView = std::find(parentsChildren.begin(), parentsChildren.end(), current); assert(itNextView != parentsChildren.end()); - auto index = std::distance(parentsChildren.begin(), itNextView); - for (auto it = parentsChildren.begin() + index + 1; it != parentsChildren.end(); ++it) { - if (walkTree(**it, true, fn)) - return true; + ++itNextView; + if (itNextView != parentsChildren.end()) { + return walkTree(**itNextView, true, fn); } + current = parent; + parent = current->parent(); } } else { - auto parent = view.parent(); - if (parent) { + auto current = &view; + auto parent = current->parent(); + while (parent) { auto &parentsChildren = parent->children(); - auto itNextView = std::find(parentsChildren.rbegin(), parentsChildren.rend(), &view); + auto itNextView = std::find(parentsChildren.rbegin(), parentsChildren.rend(), current); assert(itNextView != parentsChildren.rend()); auto index = std::distance(parentsChildren.rbegin(), itNextView); - for (auto it = parentsChildren.rbegin() + index + 1; it != parentsChildren.rend(); ++it) { - if (fn(**it)) - return true; - if (walkTree(**it, false, fn)) + ++itNextView; + if (itNextView != parentsChildren.rend()) { + auto lastChild = lastDeepChild(**itNextView); + if (fn(*lastChild)) return true; + return walkTree(*lastChild, false, fn); } - } - for (auto it = view.children().rbegin(); it != view.children().rend(); ++it) { - if (fn(**it)) + if (fn(*parent)) { return true; - } - - if (fn(view)) { - return true; + } + current = parent; + parent = current->parent(); } } return false; diff --git a/vnext/Microsoft.ReactNative/Fabric/Composition/CompositionViewComponentView.h b/vnext/Microsoft.ReactNative/Fabric/Composition/CompositionViewComponentView.h index fe05842b210..a2ca9de3e03 100644 --- a/vnext/Microsoft.ReactNative/Fabric/Composition/CompositionViewComponentView.h +++ b/vnext/Microsoft.ReactNative/Fabric/Composition/CompositionViewComponentView.h @@ -22,6 +22,8 @@ struct CompositionBaseComponentView : public IComponentView { facebook::react::Tag tag); virtual winrt::Microsoft::ReactNative::Composition::IVisual Visual() const noexcept = 0; + // Visual that should be parented to this ComponentView's parent + virtual winrt::Microsoft::ReactNative::Composition::IVisual OuterVisual() const noexcept; void updateEventEmitter(facebook::react::EventEmitter::Shared const &eventEmitter) noexcept override; const facebook::react::SharedViewEventEmitter &GetEventEmitter() const noexcept; void handleCommand(std::string const &commandName, folly::dynamic const &arg) noexcept override; @@ -75,7 +77,13 @@ struct CompositionBaseComponentView : public IComponentView { facebook::react::LayoutMetrics m_layoutMetrics; bool m_needsBorderUpdate{false}; bool m_hasTransformMatrixFacade{false}; + bool m_enableFocusVisual{false}; uint8_t m_numBorderVisuals{0}; + + private: + void showFocusVisual(bool show) noexcept; + winrt::Microsoft::ReactNative::Composition::IFocusVisual m_focusVisual{nullptr}; + winrt::Microsoft::ReactNative::Composition::IVisual m_outerVisual{nullptr}; }; struct CompositionViewComponentView : public CompositionBaseComponentView { diff --git a/vnext/Microsoft.ReactNative/Fabric/Composition/ImageComponentView.cpp b/vnext/Microsoft.ReactNative/Fabric/Composition/ImageComponentView.cpp index db354aefd0a..c0f4405478a 100644 --- a/vnext/Microsoft.ReactNative/Fabric/Composition/ImageComponentView.cpp +++ b/vnext/Microsoft.ReactNative/Fabric/Composition/ImageComponentView.cpp @@ -174,7 +174,7 @@ void ImageComponentView::updateLayoutMetrics( // Set Position & Size Properties if ((layoutMetrics.displayType != m_layoutMetrics.displayType)) { - m_visual.IsVisible(layoutMetrics.displayType != facebook::react::DisplayType::None); + OuterVisual().IsVisible(layoutMetrics.displayType != facebook::react::DisplayType::None); } updateBorderLayoutMetrics(layoutMetrics, *m_props); @@ -185,11 +185,6 @@ void ImageComponentView::updateLayoutMetrics( m_visual.Size( {layoutMetrics.frame.size.width * layoutMetrics.pointScaleFactor, layoutMetrics.frame.size.height * layoutMetrics.pointScaleFactor}); - m_visual.Offset({ - layoutMetrics.frame.origin.x * layoutMetrics.pointScaleFactor, - layoutMetrics.frame.origin.y * layoutMetrics.pointScaleFactor, - 0.0f, - }); } void ImageComponentView::finalizeUpdates(RNComponentViewUpdateMask updateMask) noexcept {} @@ -399,6 +394,7 @@ facebook::react::Tag ImageComponentView::hitTest(facebook::react::Point pt, face void ImageComponentView::ensureVisual() noexcept { if (!m_visual) { m_visual = m_compContext.CreateSpriteVisual(); + OuterVisual().InsertAt(m_visual, 0); } } diff --git a/vnext/Microsoft.ReactNative/Fabric/Composition/ParagraphComponentView.cpp b/vnext/Microsoft.ReactNative/Fabric/Composition/ParagraphComponentView.cpp index ed6e48f6711..a7ef45790b5 100644 --- a/vnext/Microsoft.ReactNative/Fabric/Composition/ParagraphComponentView.cpp +++ b/vnext/Microsoft.ReactNative/Fabric/Composition/ParagraphComponentView.cpp @@ -56,6 +56,8 @@ void ParagraphComponentView::updateProps( updateTextAlignment(newViewProps.textAttributes.alignment); } + updateBorderProps(oldViewProps, newViewProps); + m_props = std::static_pointer_cast(props); } @@ -81,20 +83,16 @@ void ParagraphComponentView::updateLayoutMetrics( ensureVisual(); if ((layoutMetrics.displayType != m_layoutMetrics.displayType)) { - m_visual.IsVisible(layoutMetrics.displayType != facebook::react::DisplayType::None); + OuterVisual().IsVisible(layoutMetrics.displayType != facebook::react::DisplayType::None); } + updateBorderLayoutMetrics(layoutMetrics, *m_props); m_layoutMetrics = layoutMetrics; UpdateCenterPropertySet(); m_visual.Size( {layoutMetrics.frame.size.width * layoutMetrics.pointScaleFactor, layoutMetrics.frame.size.height * layoutMetrics.pointScaleFactor}); - m_visual.Offset({ - layoutMetrics.frame.origin.x * layoutMetrics.pointScaleFactor, - layoutMetrics.frame.origin.y * layoutMetrics.pointScaleFactor, - 0.0f, - }); } void ParagraphComponentView::finalizeUpdates(RNComponentViewUpdateMask updateMask) noexcept { ensureVisual(); @@ -158,6 +156,7 @@ facebook::react::SharedTouchEventEmitter ParagraphComponentView::touchEventEmitt void ParagraphComponentView::ensureVisual() noexcept { if (!m_visual) { m_visual = m_compContext.CreateSpriteVisual(); + OuterVisual().InsertAt(m_visual, 0); } } diff --git a/vnext/Microsoft.ReactNative/Fabric/Composition/ScrollViewComponentView.cpp b/vnext/Microsoft.ReactNative/Fabric/Composition/ScrollViewComponentView.cpp index 9c9f0e77456..8a3085ec5ed 100644 --- a/vnext/Microsoft.ReactNative/Fabric/Composition/ScrollViewComponentView.cpp +++ b/vnext/Microsoft.ReactNative/Fabric/Composition/ScrollViewComponentView.cpp @@ -24,8 +24,8 @@ ScrollViewComponentView::ScrollViewComponentView( const winrt::Microsoft::ReactNative::Composition::ICompositionContext &compContext, facebook::react::Tag tag) : Super(compContext, tag) { - // static auto const defaultProps = std::make_shared(); - // m_props = defaultProps; + static auto const defaultProps = std::make_shared(); + m_props = defaultProps; // m_element.Content(m_contentPanel); @@ -127,13 +127,13 @@ void ScrollViewComponentView::mountChildComponentView(IComponentView &childCompo m_children.insert(std::next(m_children.begin(), index), &childComponentView); childComponentView.parent(this); - m_visual.InsertAt(static_cast(childComponentView).Visual(), index); + m_scrollVisual.InsertAt(static_cast(childComponentView).OuterVisual(), index); } void ScrollViewComponentView::unmountChildComponentView(IComponentView &childComponentView, uint32_t index) noexcept { m_children.erase(std::next(m_children.begin(), index)); - m_visual.Remove(static_cast(childComponentView).Visual()); + m_scrollVisual.Remove(static_cast(childComponentView).OuterVisual()); childComponentView.parent(nullptr); } @@ -141,15 +141,15 @@ void ScrollViewComponentView::updateProps( facebook::react::Props::Shared const &props, facebook::react::Props::Shared const &oldProps) noexcept { const auto &newViewProps = *std::static_pointer_cast(props); - const auto &oldViewProps = *std::static_pointer_cast(oldProps); + const auto &oldViewProps = *std::static_pointer_cast(m_props); ensureVisual(); if (!oldProps || oldViewProps.backgroundColor != newViewProps.backgroundColor) { if (newViewProps.backgroundColor) { - m_visual.Brush(m_compContext.CreateColorBrush((*newViewProps.backgroundColor).m_color)); + m_scrollVisual.Brush(m_compContext.CreateColorBrush((*newViewProps.backgroundColor).m_color)); } else { - m_visual.Brush(m_compContext.CreateColorBrush({0, 0, 0, 0})); + m_scrollVisual.Brush(m_compContext.CreateColorBrush({0, 0, 0, 0})); } } @@ -166,6 +166,8 @@ void ScrollViewComponentView::updateProps( m_needsBorderUpdate = true; } */ + + updateBorderProps(oldViewProps, newViewProps); m_props = std::static_pointer_cast(props); } @@ -187,26 +189,25 @@ void ScrollViewComponentView::updateLayoutMetrics( ensureVisual(); if ((layoutMetrics.displayType != m_layoutMetrics.displayType)) { - m_visual.IsVisible(layoutMetrics.displayType != facebook::react::DisplayType::None); + OuterVisual().IsVisible(layoutMetrics.displayType != facebook::react::DisplayType::None); } // m_needsBorderUpdate = true; + updateBorderLayoutMetrics(layoutMetrics, *m_props); m_layoutMetrics = layoutMetrics; UpdateCenterPropertySet(); m_visual.Size( {layoutMetrics.frame.size.width * layoutMetrics.pointScaleFactor, layoutMetrics.frame.size.height * layoutMetrics.pointScaleFactor}); - m_visual.Offset({ - layoutMetrics.frame.origin.x * layoutMetrics.pointScaleFactor, - layoutMetrics.frame.origin.y * layoutMetrics.pointScaleFactor, - 0.0f, - }); + m_scrollVisual.Size( + {layoutMetrics.frame.size.width * layoutMetrics.pointScaleFactor, + layoutMetrics.frame.size.height * layoutMetrics.pointScaleFactor}); updateContentVisualSize(); } void ScrollViewComponentView::updateContentVisualSize() noexcept { - m_visual.ContentSize( + m_scrollVisual.ContentSize( {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}); } @@ -269,8 +270,8 @@ bool ScrollViewComponentView::ScrollWheel(facebook::react::Point pt, int32_t del facebook::react::Point ptViewport{pt.x - m_layoutMetrics.frame.origin.x, pt.y - m_layoutMetrics.frame.origin.y}; facebook::react::Point ptContent{ - ptViewport.x + m_visual.ScrollPosition().x / m_layoutMetrics.pointScaleFactor, - ptViewport.y + m_visual.ScrollPosition().y / m_layoutMetrics.pointScaleFactor}; + ptViewport.x + m_scrollVisual.ScrollPosition().x / m_layoutMetrics.pointScaleFactor, + ptViewport.y + m_scrollVisual.ScrollPosition().y / m_layoutMetrics.pointScaleFactor}; if (std::any_of(m_children.rbegin(), m_children.rend(), [ptContent, delta](auto child) { return const_cast(static_cast(child)) @@ -280,7 +281,7 @@ bool ScrollViewComponentView::ScrollWheel(facebook::react::Point pt, int32_t del if (ptViewport.x >= 0 && ptViewport.x <= m_layoutMetrics.frame.size.width && ptViewport.y >= 0 && ptViewport.y <= m_layoutMetrics.frame.size.height) { - m_visual.ScrollBy({0, static_cast(-delta), 0}); + m_scrollVisual.ScrollBy({0, static_cast(-delta), 0}); return true; } @@ -289,8 +290,10 @@ bool ScrollViewComponentView::ScrollWheel(facebook::react::Point pt, int32_t del void ScrollViewComponentView::ensureVisual() noexcept { if (!m_visual) { - m_visual = m_compContext.CreateScrollerVisual(); - m_scrollPositionChangedRevoker = m_visual.ScrollPositionChanged( + m_visual = m_compContext.CreateSpriteVisual(); + m_scrollVisual = m_compContext.CreateScrollerVisual(); + m_visual.InsertAt(m_scrollVisual, 0); + m_scrollPositionChangedRevoker = m_scrollVisual.ScrollPositionChanged( winrt::auto_revoke, [this]( winrt::IInspectable const & /*sender*/, @@ -309,6 +312,7 @@ void ScrollViewComponentView::ensureVisual() noexcept { ->onScroll(scrollMetrics); } }); + OuterVisual().InsertAt(m_visual, 0); } } @@ -317,8 +321,8 @@ facebook::react::Tag ScrollViewComponentView::hitTest(facebook::react::Point pt, facebook::react::Point ptViewport{pt.x - m_layoutMetrics.frame.origin.x, pt.y - m_layoutMetrics.frame.origin.y}; facebook::react::Point ptContent{ - ptViewport.x + m_visual.ScrollPosition().x / m_layoutMetrics.pointScaleFactor, - ptViewport.y + m_visual.ScrollPosition().y / m_layoutMetrics.pointScaleFactor}; + ptViewport.x + m_scrollVisual.ScrollPosition().x / m_layoutMetrics.pointScaleFactor, + ptViewport.y + m_scrollVisual.ScrollPosition().y / m_layoutMetrics.pointScaleFactor}; facebook::react::Tag targetTag; if ((m_props->pointerEvents == facebook::react::PointerEventsMode::Auto || diff --git a/vnext/Microsoft.ReactNative/Fabric/Composition/ScrollViewComponentView.h b/vnext/Microsoft.ReactNative/Fabric/Composition/ScrollViewComponentView.h index da63cc86838..db935ab919f 100644 --- a/vnext/Microsoft.ReactNative/Fabric/Composition/ScrollViewComponentView.h +++ b/vnext/Microsoft.ReactNative/Fabric/Composition/ScrollViewComponentView.h @@ -82,7 +82,8 @@ struct ScrollInteractionTrackerOwner : public winrt::implements< void updateContentVisualSize() noexcept; facebook::react::Size m_contentSize; - winrt::Microsoft::ReactNative::Composition::ScrollVisual m_visual{nullptr}; + winrt::Microsoft::ReactNative::Composition::IVisual m_visual{nullptr}; + winrt::Microsoft::ReactNative::Composition::ScrollVisual m_scrollVisual{nullptr}; winrt::Microsoft::ReactNative::Composition::ScrollVisual::ScrollPositionChanged_revoker m_scrollPositionChangedRevoker{}; diff --git a/vnext/Microsoft.ReactNative/Fabric/Composition/SwitchComponentView.cpp b/vnext/Microsoft.ReactNative/Fabric/Composition/SwitchComponentView.cpp index ddc3dcaafbf..c44c046350b 100644 --- a/vnext/Microsoft.ReactNative/Fabric/Composition/SwitchComponentView.cpp +++ b/vnext/Microsoft.ReactNative/Fabric/Composition/SwitchComponentView.cpp @@ -52,6 +52,7 @@ void SwitchComponentView::updateProps( m_drawingSurface = nullptr; } + updateBorderProps(oldViewProps, newViewProps); m_props = std::static_pointer_cast(props); } @@ -66,20 +67,16 @@ void SwitchComponentView::updateLayoutMetrics( ensureVisual(); if ((layoutMetrics.displayType != m_layoutMetrics.displayType)) { - m_visual.IsVisible(layoutMetrics.displayType != facebook::react::DisplayType::None); + OuterVisual().IsVisible(layoutMetrics.displayType != facebook::react::DisplayType::None); } + updateBorderLayoutMetrics(layoutMetrics, *m_props); m_layoutMetrics = layoutMetrics; UpdateCenterPropertySet(); m_visual.Size( {layoutMetrics.frame.size.width * layoutMetrics.pointScaleFactor, layoutMetrics.frame.size.height * layoutMetrics.pointScaleFactor}); - m_visual.Offset({ - layoutMetrics.frame.origin.x * layoutMetrics.pointScaleFactor, - layoutMetrics.frame.origin.y * layoutMetrics.pointScaleFactor, - 0.0f, - }); } void SwitchComponentView::finalizeUpdates(RNComponentViewUpdateMask updateMask) noexcept { @@ -178,6 +175,7 @@ facebook::react::Props::Shared SwitchComponentView::props() noexcept { void SwitchComponentView::ensureVisual() noexcept { if (!m_visual) { m_visual = m_compContext.CreateSpriteVisual(); + OuterVisual().InsertAt(m_visual, 0); } } diff --git a/vnext/Microsoft.ReactNative/Fabric/Composition/TextInput/WindowsTextInputComponentView.cpp b/vnext/Microsoft.ReactNative/Fabric/Composition/TextInput/WindowsTextInputComponentView.cpp index e774ef50da4..7bfcdfb4e86 100644 --- a/vnext/Microsoft.ReactNative/Fabric/Composition/TextInput/WindowsTextInputComponentView.cpp +++ b/vnext/Microsoft.ReactNative/Fabric/Composition/TextInput/WindowsTextInputComponentView.cpp @@ -752,7 +752,7 @@ void WindowsTextInputComponentView::updateLayoutMetrics( // Set Position & Size Properties if ((layoutMetrics.displayType != m_layoutMetrics.displayType)) { - m_visual.IsVisible(layoutMetrics.displayType != facebook::react::DisplayType::None); + OuterVisual().IsVisible(layoutMetrics.displayType != facebook::react::DisplayType::None); } if ((layoutMetrics.pointScaleFactor != m_layoutMetrics.pointScaleFactor)) { @@ -783,11 +783,6 @@ void WindowsTextInputComponentView::updateLayoutMetrics( m_visual.Size( {layoutMetrics.frame.size.width * layoutMetrics.pointScaleFactor, layoutMetrics.frame.size.height * layoutMetrics.pointScaleFactor}); - m_visual.Offset({ - layoutMetrics.frame.origin.x * layoutMetrics.pointScaleFactor, - layoutMetrics.frame.origin.y * layoutMetrics.pointScaleFactor, - 0.0f, - }); } // When we are notified by RichEdit that the text changed, we need to notify JS @@ -1053,6 +1048,7 @@ void WindowsTextInputComponentView::ensureVisual() noexcept { winrt::com_ptr spUnk; winrt::check_hresult(g_pfnCreateTextServices(nullptr, m_textHost.get(), spUnk.put())); spUnk.as(m_textServices); + OuterVisual().InsertAt(m_visual, 0); } if (!m_caretVisual) { diff --git a/vnext/Microsoft.ReactNative/Fabric/FabricUIManagerModule.cpp b/vnext/Microsoft.ReactNative/Fabric/FabricUIManagerModule.cpp index 57c9f27679d..164876824ce 100644 --- a/vnext/Microsoft.ReactNative/Fabric/FabricUIManagerModule.cpp +++ b/vnext/Microsoft.ReactNative/Fabric/FabricUIManagerModule.cpp @@ -209,7 +209,7 @@ void FabricUIManager::startSurface( facebook::react::RootShadowNode::Handle(), surfaceId, self->m_compContext); self->m_surfaceRegistry.at(surfaceId).rootVisual.InsertAt( - static_cast(*rootComponentViewDescriptor.view).Visual(), 0); + static_cast(*rootComponentViewDescriptor.view).OuterVisual(), 0); }); facebook::react::LayoutContext context; diff --git a/vnext/ReactCommon/TEMP_UntilReactCommonUpdate/react/renderer/components/view/ViewProps.cpp b/vnext/ReactCommon/TEMP_UntilReactCommonUpdate/react/renderer/components/view/ViewProps.cpp index 0d64e19285b..676426f196e 100644 --- a/vnext/ReactCommon/TEMP_UntilReactCommonUpdate/react/renderer/components/view/ViewProps.cpp +++ b/vnext/ReactCommon/TEMP_UntilReactCommonUpdate/react/renderer/components/view/ViewProps.cpp @@ -183,6 +183,14 @@ ViewProps::ViewProps( CoreFeatures::enablePropIteratorSetter ? sourceProps.events : convertRawProp(context, rawProps, sourceProps.events, {})), + enableFocusRing( + CoreFeatures::enablePropIteratorSetter ? sourceProps.enableFocusRing + : convertRawProp( + context, + rawProps, + "enableFocusRing", + sourceProps.enableFocusRing, + true)), collapsable( CoreFeatures::enablePropIteratorSetter ? sourceProps.collapsable : convertRawProp( diff --git a/vnext/ReactCommon/TEMP_UntilReactCommonUpdate/react/renderer/components/view/ViewProps.h b/vnext/ReactCommon/TEMP_UntilReactCommonUpdate/react/renderer/components/view/ViewProps.h index cc3eac1d92f..0b46b7ab60a 100644 --- a/vnext/ReactCommon/TEMP_UntilReactCommonUpdate/react/renderer/components/view/ViewProps.h +++ b/vnext/ReactCommon/TEMP_UntilReactCommonUpdate/react/renderer/components/view/ViewProps.h @@ -78,6 +78,7 @@ class ViewProps : public YogaStylableProps, public AccessibilityProps { ViewEvents events{}; HostPlatformViewEvents platformEvents{}; // [Windows] + bool enableFocusRing{true}; // [Windows] bool collapsable{true};