Skip to content

Commit

Permalink
[0.74] Allow portals to have independent layout constraints and scale…
Browse files Browse the repository at this point in the history
… factor (#14318)

* Fix crash when currently focused element gets marked as enableFocusRing=false (#14306)

* Fix crash when currently focused element gets marked as enableFocusRing=false

* Change files

* [Fabric] Use PopupWindowSiteBridge for Modal when USE_EXPERIMENTAL_WINUI3 is true (#14284)

* add modal implementation with PopupWindowSiteBridge

* Change files

* add conditional

* feedback

* Initial support for UIA and tab navigation for a child Island (#14305)

* Basic support for stitching the UIA tree for a ContentIslandComponentView's child

* Updated comment

* Change files

* Support shift+tab, and move Automation event handlers to ContentIslandComponentView

* Allow portals to have independent layout constraints and scale factor (#14315)

* Allow portals to have independent layout constraints and scale factor

* format

* change files

* fix

* Round Focus visuals by default, fix nudge rendering (#14312)

* Round Focus visuals by default, fix nudge rendering

* Change files

* change files

* fix

* fix

* fix

---------

Co-authored-by: Tatiana Kapos <[email protected]>
Co-authored-by: JesseCol <[email protected]>
  • Loading branch information
3 people authored Jan 31, 2025
1 parent 8d61583 commit 1b4cbdc
Show file tree
Hide file tree
Showing 44 changed files with 889 additions and 308 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"type": "patch",
"comment": "Fix UpdateState on generated base class",
"packageName": "@react-native-windows/codegen",
"email": "[email protected]",
"dependentChangeType": "patch"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"type": "patch",
"comment": "Allow portals to have independent layout constraints and scale factor",
"packageName": "react-native-windows",
"email": "[email protected]",
"dependentChangeType": "patch"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"type": "patch",
"comment": "add modal implementation with PopupWindowSiteBridge",
"packageName": "react-native-windows",
"email": "[email protected]",
"dependentChangeType": "patch"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"type": "patch",
"comment": "Basic support for stitching the UIA tree for a ContentIslandComponentView's child",
"packageName": "react-native-windows",
"email": "email not defined",
"dependentChangeType": "patch"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"type": "patch",
"comment": "Fix crash when currently focused element gets marked as enableFocusRing=false",
"packageName": "react-native-windows",
"email": "[email protected]",
"dependentChangeType": "patch"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"type": "patch",
"comment": "Round Focus visuals by default, fix nudge rendering",
"packageName": "react-native-windows",
"email": "[email protected]",
"dependentChangeType": "patch"
}
Original file line number Diff line number Diff line change
Expand Up @@ -196,7 +196,7 @@ void Register::_COMPONENT_NAME_::NativeComponent(
builder.SetUpdateStateHandler([](const winrt::Microsoft::ReactNative::ComponentView &view,
const winrt::Microsoft::ReactNative::IComponentState &newState) noexcept {
auto userData = view.UserData().as<TUserData>();
userData->member(view, newState);
userData->UpdateState(view, newState);
});
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -293,7 +293,7 @@ const styles = StyleSheet.create({
marginTop: 6,
},
modalContainer: {
flex: 1,
//flex: 1, // [Windows] - This will cause the modal to stretch to be as tall as the availiable space given to it.
justifyContent: 'center',
padding: 20,
},
Expand Down
97 changes: 97 additions & 0 deletions vnext/Microsoft.ReactNative/Fabric/AbiPortalShadowNode.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.

#include "AbiPortalShadowNode.h"

#include <Fabric/Composition/ReactCompositionViewComponentBuilder.h>
#include <react/debug/react_native_assert.h>
#include <react/renderer/core/LayoutConstraints.h>
#include <react/renderer/core/LayoutContext.h>
#include <react/renderer/core/conversions.h>

#include <utility>

namespace Microsoft::ReactNative {

extern const char AbiPortalComponentName[] = "AbiPortal";

facebook::react::Size AbiPortalShadowNode::measureContent(
const facebook::react::LayoutContext &layoutContext,
const facebook::react::LayoutConstraints &layoutConstraints) const {
return {0, 0}; // The portal placeholder node shouldn't take up any space
}

void AbiPortalShadowNode::layout(facebook::react::LayoutContext layoutContext) {
ensureUnsealed();
auto layoutMetrics = getLayoutMetrics();

auto portalOwningShadowNode = ShadowNode::Unshared{};

if (getChildren().empty()) {
return;
}

// A Portal should only have a single child
react_native_assert(getChildren().size() == 1);

const auto &childNode = getChildren()[0];

auto clonedShadowNode = ShadowNode::Unshared{};

portalOwningShadowNode = cloneTree(childNode->getFamily(), [&](const ShadowNode &oldShadowNode) {
clonedShadowNode = oldShadowNode.clone({});
return clonedShadowNode;
});
auto portalShadowNode = static_cast<AbiPortalShadowNode *>(portalOwningShadowNode.get());

auto &layoutableShadowNode = dynamic_cast<LayoutableShadowNode &>(*clonedShadowNode);

auto &state = getStateData();

facebook::react::LayoutConstraints layoutConstraints;
layoutConstraints.layoutDirection = layoutMetrics.layoutDirection;

if (state.userdata) {
// If the portal component set a state of type IPortalStateData,
// extract constraint information from it, and use that for layout
if (auto portalState = state.userdata.try_as<winrt::Microsoft::ReactNative::Composition::IPortalStateData>()) {
auto stateConstraints = portalState.LayoutConstraints();

layoutConstraints.minimumSize = {stateConstraints.MinimumSize.Width, stateConstraints.MinimumSize.Height};
layoutConstraints.maximumSize = {stateConstraints.MaximumSize.Width, stateConstraints.MaximumSize.Height};
if (stateConstraints.LayoutDirection == winrt::Microsoft::ReactNative::LayoutDirection::LeftToRight) {
layoutConstraints.layoutDirection = facebook::react::LayoutDirection::LeftToRight;
} else if (stateConstraints.LayoutDirection == winrt::Microsoft::ReactNative::LayoutDirection::RightToLeft) {
layoutConstraints.layoutDirection = facebook::react::LayoutDirection::RightToLeft;
}
}
}

// Laying out the `ShadowNode` and the subtree starting from it.
layoutableShadowNode.layoutTree(layoutContext, layoutConstraints);

auto childLayoutMetrics = layoutableShadowNode.getLayoutMetrics();
childLayoutMetrics.frame.origin = {0, 0};
layoutableShadowNode.setLayoutMetrics(childLayoutMetrics);

// Update the list of children to reflect the changes that we made.
this->children_ = static_cast<AbiPortalShadowNode *>(portalOwningShadowNode.get())->children_;
}

void AbiPortalShadowNode::Builder(winrt::Microsoft::ReactNative::IReactViewComponentBuilder builder) noexcept {
m_builder = builder;
}

winrt::Microsoft::ReactNative::IReactViewComponentBuilder AbiPortalShadowNode::Builder() const noexcept {
return m_builder;
}

void AbiPortalShadowNode::Proxy(winrt::Microsoft::ReactNative::ShadowNode proxy) noexcept {
m_proxy = proxy;
}

winrt::Microsoft::ReactNative::ShadowNode AbiPortalShadowNode::Proxy() const noexcept {
return m_proxy;
}

} // namespace Microsoft::ReactNative
53 changes: 53 additions & 0 deletions vnext/Microsoft.ReactNative/Fabric/AbiPortalShadowNode.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.

#pragma once

#include <react/components/rnwcore/EventEmitters.h>
#include <unordered_map>
#include "AbiShadowNode.h"
#include "AbiState.h"
#include "AbiViewProps.h"

#include <react/renderer/components/view/ConcreteViewShadowNode.h>
#include <react/renderer/core/LayoutContext.h>

namespace Microsoft::ReactNative {

extern const char AbiPortalComponentName[];

class AbiPortalShadowNode final : public facebook::react::ConcreteViewShadowNode<
AbiPortalComponentName,
AbiViewProps,
facebook::react::ViewEventEmitter,
Microsoft::ReactNative::AbiStateData> {
public:
using ConcreteViewShadowNode::ConcreteViewShadowNode;

static facebook::react::ShadowNodeTraits BaseTraits() {
auto traits = facebook::react::ShadowNode::BaseTraits();
traits.set(facebook::react::ShadowNodeTraits::Trait::FormsStackingContext);
traits.set(facebook::react::ShadowNodeTraits::Trait::FormsView);
traits.set(facebook::react::ShadowNodeTraits::Trait::RootNodeKind);
traits.set(facebook::react::ShadowNodeTraits::Trait::LeafYogaNode);
traits.set(facebook::react::ShadowNodeTraits::Trait::MeasurableYogaNode);
return traits;
}

facebook::react::Size measureContent(
const facebook::react::LayoutContext &layoutContext,
const facebook::react::LayoutConstraints &layoutConstraints) const override;
void layout(facebook::react::LayoutContext layoutContext) override;

void OnClone(const facebook::react::ShadowNode &sourceShadowNode) noexcept;
void Builder(winrt::Microsoft::ReactNative::IReactViewComponentBuilder builder) noexcept;
winrt::Microsoft::ReactNative::IReactViewComponentBuilder Builder() const noexcept;
void Proxy(winrt::Microsoft::ReactNative::ShadowNode handle) noexcept;
winrt::Microsoft::ReactNative::ShadowNode Proxy() const noexcept;

private:
winrt::Microsoft::ReactNative::ShadowNode m_proxy{nullptr};
winrt::Microsoft::ReactNative::IReactViewComponentBuilder m_builder{nullptr};
};

} // namespace Microsoft::ReactNative
Loading

0 comments on commit 1b4cbdc

Please sign in to comment.