react-native-windows 0.74.33 → 0.74.34

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (43) hide show
  1. package/Libraries/Modal/Modal.windows.js +4 -1
  2. package/Microsoft.ReactNative/Fabric/AbiPortalShadowNode.cpp +97 -0
  3. package/Microsoft.ReactNative/Fabric/AbiPortalShadowNode.h +53 -0
  4. package/Microsoft.ReactNative/Fabric/AbiViewComponentDescriptor.h +161 -17
  5. package/Microsoft.ReactNative/Fabric/Composition/CompositionDynamicAutomationProvider.cpp +18 -0
  6. package/Microsoft.ReactNative/Fabric/Composition/CompositionDynamicAutomationProvider.h +10 -0
  7. package/Microsoft.ReactNative/Fabric/Composition/CompositionViewComponentView.cpp +74 -42
  8. package/Microsoft.ReactNative/Fabric/Composition/CompositionViewComponentView.h +2 -0
  9. package/Microsoft.ReactNative/Fabric/Composition/ContentIslandComponentView.cpp +152 -1
  10. package/Microsoft.ReactNative/Fabric/Composition/ContentIslandComponentView.h +16 -0
  11. package/Microsoft.ReactNative/Fabric/Composition/FocusManager.cpp +4 -2
  12. package/Microsoft.ReactNative/Fabric/Composition/FocusManager.h +9 -1
  13. package/Microsoft.ReactNative/Fabric/Composition/Modal/WindowsModalHostViewComponentView.cpp +179 -12
  14. package/Microsoft.ReactNative/Fabric/Composition/PortalComponentView.cpp +12 -0
  15. package/Microsoft.ReactNative/Fabric/Composition/ReactCompositionViewComponentBuilder.cpp +2 -1
  16. package/Microsoft.ReactNative/Fabric/Composition/ReactCompositionViewComponentBuilder.h +0 -1
  17. package/Microsoft.ReactNative/Fabric/Composition/ReactNativeIsland.cpp +16 -14
  18. package/Microsoft.ReactNative/Fabric/Composition/RootComponentView.cpp +6 -4
  19. package/Microsoft.ReactNative/Fabric/Composition/RootComponentView.h +3 -1
  20. package/Microsoft.ReactNative/Fabric/Composition/Theme.cpp +5 -0
  21. package/Microsoft.ReactNative/Fabric/platform/react/renderer/graphics/PlatformColorParser.h +1 -1
  22. package/Microsoft.ReactNative/IReactCompositionViewComponentBuilder.idl +10 -1
  23. package/Microsoft.ReactNative/Modules/ClipboardModule.cpp +1 -1
  24. package/Microsoft.ReactNative/Modules/ClipboardModule.h +1 -1
  25. package/Microsoft.ReactNative.Cxx/NativeModules.h +20 -0
  26. package/PropertySheets/Generated/PackageVersion.g.props +3 -3
  27. package/Shared/Shared.vcxitems +3 -3
  28. package/Shared/Shared.vcxitems.filters +1 -1
  29. package/codegen/react/components/rnwcore/ActivityIndicatorView.g.h +1 -1
  30. package/codegen/react/components/rnwcore/AndroidDrawerLayout.g.h +1 -1
  31. package/codegen/react/components/rnwcore/AndroidHorizontalScrollContentView.g.h +1 -1
  32. package/codegen/react/components/rnwcore/AndroidProgressBar.g.h +1 -1
  33. package/codegen/react/components/rnwcore/AndroidSwipeRefreshLayout.g.h +1 -1
  34. package/codegen/react/components/rnwcore/AndroidSwitch.g.h +1 -1
  35. package/codegen/react/components/rnwcore/DebuggingOverlay.g.h +1 -1
  36. package/codegen/react/components/rnwcore/InputAccessory.g.h +1 -1
  37. package/codegen/react/components/rnwcore/ModalHostView.g.h +1 -1
  38. package/codegen/react/components/rnwcore/PullToRefreshView.g.h +1 -1
  39. package/codegen/react/components/rnwcore/SafeAreaView.g.h +1 -1
  40. package/codegen/react/components/rnwcore/Switch.g.h +1 -1
  41. package/codegen/react/components/rnwcore/UnimplementedNativeView.g.h +1 -1
  42. package/package.json +3 -3
  43. package/Microsoft.ReactNative/Fabric/AbiViewComponentDescriptor.cpp +0 -191
@@ -11,12 +11,15 @@
11
11
  #include <UI.Xaml.Controls.h>
12
12
  #include <Utils/ValueUtils.h>
13
13
  #include <winrt/Microsoft.UI.Content.h>
14
+ #include <winrt/Microsoft.UI.Input.h>
14
15
  #include <winrt/Windows.UI.Composition.h>
15
16
  #include "CompositionContextHelper.h"
16
17
  #include "RootComponentView.h"
17
18
 
18
19
  #include "Composition.ContentIslandComponentView.g.cpp"
19
20
 
21
+ #include "CompositionDynamicAutomationProvider.h"
22
+
20
23
  namespace winrt::Microsoft::ReactNative::Composition::implementation {
21
24
 
22
25
  ContentIslandComponentView::ContentIslandComponentView(
@@ -47,6 +50,22 @@ void ContentIslandComponentView::OnMounted() noexcept {
47
50
  winrt::Microsoft::ReactNative::Composition::Experimental::CompositionContextHelper::InnerVisual(Visual())
48
51
  .as<winrt::Microsoft::UI::Composition::ContainerVisual>());
49
52
  m_childSiteLink.ActualSize({m_layoutMetrics.frame.size.width, m_layoutMetrics.frame.size.height});
53
+
54
+ m_navigationHost = winrt::Microsoft::UI::Input::InputFocusNavigationHost::GetForSiteLink(m_childSiteLink);
55
+
56
+ m_navigationHostDepartFocusRequestedToken =
57
+ m_navigationHost.DepartFocusRequested([wkThis = get_weak()](const auto &, const auto &args) {
58
+ if (auto strongThis = wkThis.get()) {
59
+ const bool next = (args.Request().Reason() != winrt::Microsoft::UI::Input::FocusNavigationReason::Last);
60
+ strongThis->rootComponentView()->TryMoveFocus(next);
61
+ args.Result(winrt::Microsoft::UI::Input::FocusNavigationResult::Moved);
62
+ }
63
+ });
64
+
65
+ // We configure automation even if there's no UIA client at this point, because it's possible the first UIA
66
+ // request we'll get will be for a child of this island calling upward in the UIA tree.
67
+ ConfigureChildSiteLinkAutomation();
68
+
50
69
  if (m_islandToConnect) {
51
70
  m_childSiteLink.Connect(m_islandToConnect);
52
71
  m_islandToConnect = nullptr;
@@ -70,6 +89,12 @@ void ContentIslandComponentView::OnMounted() noexcept {
70
89
 
71
90
  void ContentIslandComponentView::OnUnmounted() noexcept {
72
91
  m_layoutMetricChangedRevokers.clear();
92
+ #ifdef USE_EXPERIMENTAL_WINUI3
93
+ if (m_navigationHostDepartFocusRequestedToken && m_navigationHost) {
94
+ m_navigationHost.DepartFocusRequested(m_navigationHostDepartFocusRequestedToken);
95
+ m_navigationHostDepartFocusRequestedToken = {};
96
+ }
97
+ #endif
73
98
  }
74
99
 
75
100
  void ContentIslandComponentView::ParentLayoutChanged() noexcept {
@@ -92,7 +117,79 @@ void ContentIslandComponentView::ParentLayoutChanged() noexcept {
92
117
  #endif
93
118
  }
94
119
 
120
+ winrt::IInspectable ContentIslandComponentView::EnsureUiaProvider() noexcept {
121
+ #ifdef USE_EXPERIMENTAL_WINUI3
122
+ if (m_uiaProvider == nullptr) {
123
+ m_uiaProvider = winrt::make<winrt::Microsoft::ReactNative::implementation::CompositionDynamicAutomationProvider>(
124
+ *get_strong(), m_childSiteLink);
125
+ }
126
+ return m_uiaProvider;
127
+ #else
128
+ return Super::EnsureUiaProvider();
129
+ #endif
130
+ }
131
+
132
+ bool ContentIslandComponentView::focusable() const noexcept {
133
+ #ifdef USE_EXPERIMENTAL_WINUI3
134
+ // We don't have a way to check to see if the ContentIsland has focusable content,
135
+ // so we'll always return true. We'll have to handle the case where the content doesn't have
136
+ // focusable content in the OnGotFocus handler.
137
+ return true;
138
+ #else
139
+ return Super::focusable();
140
+ #endif
141
+ }
142
+
143
+ // Helper to convert a FocusNavigationDirection to a FocusNavigationReason.
144
+ winrt::Microsoft::UI::Input::FocusNavigationReason GetFocusNavigationReason(
145
+ winrt::Microsoft::ReactNative::FocusNavigationDirection direction) noexcept {
146
+ switch (direction) {
147
+ case winrt::Microsoft::ReactNative::FocusNavigationDirection::First:
148
+ case winrt::Microsoft::ReactNative::FocusNavigationDirection::Next:
149
+ return winrt::Microsoft::UI::Input::FocusNavigationReason::First;
150
+ case winrt::Microsoft::ReactNative::FocusNavigationDirection::Last:
151
+ case winrt::Microsoft::ReactNative::FocusNavigationDirection::Previous:
152
+ return winrt::Microsoft::UI::Input::FocusNavigationReason::Last;
153
+ }
154
+ return winrt::Microsoft::UI::Input::FocusNavigationReason::Restore;
155
+ }
156
+
157
+ void ContentIslandComponentView::onGotFocus(
158
+ const winrt::Microsoft::ReactNative::Composition::Input::RoutedEventArgs &args) noexcept {
159
+ #ifdef USE_EXPERIMENTAL_WINUI3
160
+ auto gotFocusEventArgs = args.as<winrt::Microsoft::ReactNative::implementation::GotFocusEventArgs>();
161
+ const auto navigationReason = GetFocusNavigationReason(gotFocusEventArgs->Direction());
162
+ m_navigationHost.NavigateFocus(winrt::Microsoft::UI::Input::FocusNavigationRequest::Create(navigationReason));
163
+ #else
164
+ return Super::onGotFocus(args);
165
+ #endif // USE_EXPERIMENTAL_WINUI3
166
+ }
167
+
95
168
  ContentIslandComponentView::~ContentIslandComponentView() noexcept {
169
+ #ifdef USE_EXPERIMENTAL_WINUI3
170
+ if (m_navigationHostDepartFocusRequestedToken && m_navigationHost) {
171
+ m_navigationHost.DepartFocusRequested(m_navigationHostDepartFocusRequestedToken);
172
+ m_navigationHostDepartFocusRequestedToken = {};
173
+ }
174
+ if (m_childSiteLink) {
175
+ if (m_fragmentRootAutomationProviderRequestedToken) {
176
+ m_childSiteLink.FragmentRootAutomationProviderRequested(m_fragmentRootAutomationProviderRequestedToken);
177
+ m_fragmentRootAutomationProviderRequestedToken = {};
178
+ }
179
+ if (m_parentAutomationProviderRequestedToken) {
180
+ m_childSiteLink.ParentAutomationProviderRequested(m_parentAutomationProviderRequestedToken);
181
+ m_parentAutomationProviderRequestedToken = {};
182
+ }
183
+ if (m_nextSiblingAutomationProviderRequestedToken) {
184
+ m_childSiteLink.NextSiblingAutomationProviderRequested(m_nextSiblingAutomationProviderRequestedToken);
185
+ m_nextSiblingAutomationProviderRequestedToken = {};
186
+ }
187
+ if (m_previousSiblingAutomationProviderRequestedToken) {
188
+ m_childSiteLink.PreviousSiblingAutomationProviderRequested(m_previousSiblingAutomationProviderRequestedToken);
189
+ m_previousSiblingAutomationProviderRequestedToken = {};
190
+ }
191
+ }
192
+ #endif // USE_EXPERIMENTAL_WINUI3
96
193
  if (m_islandToConnect) {
97
194
  m_islandToConnect.Close();
98
195
  }
@@ -132,11 +229,65 @@ void ContentIslandComponentView::Connect(const winrt::Microsoft::UI::Content::Co
132
229
  } else {
133
230
  m_islandToConnect = contentIsland;
134
231
  }
135
- #endif
232
+ #endif // USE_EXPERIMENTAL_WINUI3
136
233
  }
137
234
 
138
235
  void ContentIslandComponentView::prepareForRecycle() noexcept {
139
236
  Super::prepareForRecycle();
140
237
  }
141
238
 
239
+ #ifdef USE_EXPERIMENTAL_WINUI3
240
+ void ContentIslandComponentView::ConfigureChildSiteLinkAutomation() noexcept {
241
+ // This automation mode must be set before connecting the child ContentIsland.
242
+ // It puts the child content into a mode where it won't own its own framework root. Instead, the child island's
243
+ // automation peers will use the same framework root as the automation peer of this ContentIslandComponentView.
244
+ m_childSiteLink.AutomationTreeOption(winrt::Microsoft::UI::Content::AutomationTreeOptions::FragmentBased);
245
+
246
+ // These events are raised in response to the child ContentIsland asking for providers.
247
+ // For example, the ContentIsland.FragmentRootAutomationProvider property will return
248
+ // the provider we provide here in FragmentRootAutomationProviderRequested.
249
+
250
+ // We capture "this" as a raw pointer because ContentIslandComponentView doesn't currently support weak ptrs.
251
+ // It's safe because we disconnect these events in the destructor.
252
+
253
+ m_fragmentRootAutomationProviderRequestedToken = m_childSiteLink.FragmentRootAutomationProviderRequested(
254
+ [this](
255
+ const winrt::Microsoft::UI::Content::IContentSiteAutomation &,
256
+ const winrt::Microsoft::UI::Content::ContentSiteAutomationProviderRequestedEventArgs &args) {
257
+ // The child island's fragment tree doesn't have its own fragment root.
258
+ // Here's how we can provide the correct fragment root to the child's UIA logic.
259
+ winrt::com_ptr<IRawElementProviderFragmentRoot> fragmentRoot{nullptr};
260
+ auto uiaProvider = this->EnsureUiaProvider();
261
+ uiaProvider.as<IRawElementProviderFragment>()->get_FragmentRoot(fragmentRoot.put());
262
+ args.AutomationProvider(fragmentRoot.as<IInspectable>());
263
+ args.Handled(true);
264
+ });
265
+
266
+ m_parentAutomationProviderRequestedToken = m_childSiteLink.ParentAutomationProviderRequested(
267
+ [this](
268
+ const winrt::Microsoft::UI::Content::IContentSiteAutomation &,
269
+ const winrt::Microsoft::UI::Content::ContentSiteAutomationProviderRequestedEventArgs &args) {
270
+ auto uiaProvider = this->EnsureUiaProvider();
271
+ args.AutomationProvider(uiaProvider);
272
+ args.Handled(true);
273
+ });
274
+
275
+ m_nextSiblingAutomationProviderRequestedToken = m_childSiteLink.NextSiblingAutomationProviderRequested(
276
+ [](const winrt::Microsoft::UI::Content::IContentSiteAutomation &,
277
+ const winrt::Microsoft::UI::Content::ContentSiteAutomationProviderRequestedEventArgs &args) {
278
+ // The ContentIsland will always be the one and only child of this node, so it won't have siblings.
279
+ args.AutomationProvider(nullptr);
280
+ args.Handled(true);
281
+ });
282
+
283
+ m_previousSiblingAutomationProviderRequestedToken = m_childSiteLink.PreviousSiblingAutomationProviderRequested(
284
+ [](const winrt::Microsoft::UI::Content::IContentSiteAutomation &,
285
+ const winrt::Microsoft::UI::Content::ContentSiteAutomationProviderRequestedEventArgs &args) {
286
+ // The ContentIsland will always be the one and only child of this node, so it won't have siblings.
287
+ args.AutomationProvider(nullptr);
288
+ args.Handled(true);
289
+ });
290
+ }
291
+ #endif // USE_EXPERIMENTAL_WINUI3
292
+
142
293
  } // namespace winrt::Microsoft::ReactNative::Composition::implementation
@@ -8,6 +8,7 @@
8
8
 
9
9
  #include <Microsoft.ReactNative.Cxx/ReactContext.h>
10
10
  #include <winrt/Microsoft.UI.Content.h>
11
+ #include <winrt/Microsoft.UI.Input.h>
11
12
  #include <winrt/Windows.UI.Composition.h>
12
13
  #include "CompositionHelpers.h"
13
14
  #include "CompositionViewComponentView.h"
@@ -37,6 +38,12 @@ struct ContentIslandComponentView : ContentIslandComponentViewT<ContentIslandCom
37
38
 
38
39
  void prepareForRecycle() noexcept override;
39
40
 
41
+ bool focusable() const noexcept override;
42
+
43
+ winrt::IInspectable EnsureUiaProvider() noexcept override;
44
+
45
+ void onGotFocus(const winrt::Microsoft::ReactNative::Composition::Input::RoutedEventArgs &args) noexcept override;
46
+
40
47
  ContentIslandComponentView(
41
48
  const winrt::Microsoft::ReactNative::Composition::Experimental::ICompositionContext &compContext,
42
49
  facebook::react::Tag tag,
@@ -56,6 +63,15 @@ struct ContentIslandComponentView : ContentIslandComponentViewT<ContentIslandCom
56
63
  std::vector<winrt::Microsoft::ReactNative::ComponentView::LayoutMetricsChanged_revoker> m_layoutMetricChangedRevokers;
57
64
  #ifdef USE_EXPERIMENTAL_WINUI3
58
65
  winrt::Microsoft::UI::Content::ChildSiteLink m_childSiteLink{nullptr};
66
+ winrt::Microsoft::UI::Input::InputFocusNavigationHost m_navigationHost{nullptr};
67
+ winrt::event_token m_navigationHostDepartFocusRequestedToken{};
68
+
69
+ // Automation
70
+ void ConfigureChildSiteLinkAutomation() noexcept;
71
+ winrt::event_token m_fragmentRootAutomationProviderRequestedToken{};
72
+ winrt::event_token m_parentAutomationProviderRequestedToken{};
73
+ winrt::event_token m_nextSiblingAutomationProviderRequestedToken{};
74
+ winrt::event_token m_previousSiblingAutomationProviderRequestedToken{};
59
75
  #endif
60
76
  };
61
77
 
@@ -14,8 +14,10 @@ int32_t LostFocusEventArgs::OriginalSource() noexcept {
14
14
  return m_originalSource;
15
15
  }
16
16
 
17
- GotFocusEventArgs::GotFocusEventArgs(const winrt::Microsoft::ReactNative::ComponentView &originalSource)
18
- : m_originalSource(originalSource ? originalSource.Tag() : -1) {}
17
+ GotFocusEventArgs::GotFocusEventArgs(
18
+ const winrt::Microsoft::ReactNative::ComponentView &originalSource,
19
+ winrt::Microsoft::ReactNative::FocusNavigationDirection direction)
20
+ : m_originalSource(originalSource ? originalSource.Tag() : -1), m_direction(direction) {}
19
21
  int32_t GotFocusEventArgs::OriginalSource() noexcept {
20
22
  return m_originalSource;
21
23
  }
@@ -21,11 +21,19 @@ struct LostFocusEventArgs
21
21
 
22
22
  struct GotFocusEventArgs
23
23
  : winrt::implements<GotFocusEventArgs, winrt::Microsoft::ReactNative::Composition::Input::RoutedEventArgs> {
24
- GotFocusEventArgs(const winrt::Microsoft::ReactNative::ComponentView &originalSource);
24
+ GotFocusEventArgs(
25
+ const winrt::Microsoft::ReactNative::ComponentView &originalSource,
26
+ winrt::Microsoft::ReactNative::FocusNavigationDirection direction);
25
27
  int32_t OriginalSource() noexcept;
26
28
 
29
+ winrt::Microsoft::ReactNative::FocusNavigationDirection Direction() const noexcept {
30
+ return m_direction;
31
+ }
32
+
27
33
  private:
28
34
  const int32_t m_originalSource;
35
+ winrt::Microsoft::ReactNative::FocusNavigationDirection m_direction{
36
+ winrt::Microsoft::ReactNative::FocusNavigationDirection::None};
29
37
  };
30
38
 
31
39
  struct LosingFocusEventArgs
@@ -14,6 +14,24 @@
14
14
 
15
15
  namespace winrt::Microsoft::ReactNative::Composition::implementation {
16
16
 
17
+ struct ModalHostState
18
+ : winrt::implements<ModalHostState, winrt::Microsoft::ReactNative::Composition::IPortalStateData> {
19
+ ModalHostState(winrt::Microsoft::ReactNative::LayoutConstraints layoutConstraints, float scaleFactor)
20
+ : m_layoutConstraints(layoutConstraints), m_pointScaleFactor(scaleFactor) {}
21
+
22
+ winrt::Microsoft::ReactNative::LayoutConstraints LayoutConstraints() const noexcept {
23
+ return m_layoutConstraints;
24
+ }
25
+
26
+ float PointScaleFactor() const noexcept {
27
+ return m_pointScaleFactor;
28
+ }
29
+
30
+ private:
31
+ float m_pointScaleFactor{1.0f};
32
+ winrt::Microsoft::ReactNative::LayoutConstraints m_layoutConstraints;
33
+ };
34
+
17
35
  struct ModalHostView : public winrt::implements<ModalHostView, winrt::Windows::Foundation::IInspectable>,
18
36
  ::Microsoft::ReactNativeSpecs::BaseModalHostView<ModalHostView> {
19
37
  ~ModalHostView() {
@@ -37,6 +55,13 @@ struct ModalHostView : public winrt::implements<ModalHostView, winrt::Windows::F
37
55
  m_window.Destroy();
38
56
  m_window = nullptr;
39
57
  }
58
+
59
+ #ifdef USE_EXPERIMENTAL_WINUI3
60
+ if (m_popUp) {
61
+ m_popUp.Close();
62
+ m_popUp = nullptr;
63
+ }
64
+ #endif
40
65
  }
41
66
 
42
67
  void InitializePortalViewComponent(
@@ -65,13 +90,32 @@ struct ModalHostView : public winrt::implements<ModalHostView, winrt::Windows::F
65
90
  ::Microsoft::ReactNativeSpecs::BaseModalHostView<ModalHostView>::UpdateProps(view, newProps, oldProps);
66
91
  }
67
92
 
68
- void UpdateLayoutMetrics(
69
- const winrt::Microsoft::ReactNative::ComponentView &view,
70
- const winrt::Microsoft::ReactNative::LayoutMetrics &newLayoutMetrics,
71
- const winrt::Microsoft::ReactNative::LayoutMetrics & /*oldLayoutMetrics*/) noexcept override {
72
- if (m_window) {
73
- AdjustWindowSize(newLayoutMetrics);
74
- }
93
+ void UpdateState(
94
+ const winrt::Microsoft::ReactNative::ComponentView & /*view*/,
95
+ const winrt::Microsoft::ReactNative::IComponentState &newState) noexcept override {
96
+ m_state = newState;
97
+ }
98
+
99
+ void MountChildComponentView(
100
+ const winrt::Microsoft::ReactNative::ComponentView & /*view*/,
101
+ const winrt::Microsoft::ReactNative::MountChildComponentViewArgs &args) noexcept override {
102
+ AdjustWindowSize(args.Child().LayoutMetrics());
103
+ assert(!m_childLayoutMetricsToken);
104
+ m_childLayoutMetricsToken = args.Child().LayoutMetricsChanged(
105
+ [wkThis = get_weak()](
106
+ auto &sender, const winrt::Microsoft::ReactNative::LayoutMetricsChangedArgs &layoutMetricsChangedArgs) {
107
+ if (auto strongThis = wkThis.get()) {
108
+ strongThis->AdjustWindowSize(layoutMetricsChangedArgs.NewLayoutMetrics());
109
+ }
110
+ });
111
+ }
112
+
113
+ void UnmountChildComponentView(
114
+ const winrt::Microsoft::ReactNative::ComponentView & /*view*/,
115
+ const winrt::Microsoft::ReactNative::UnmountChildComponentViewArgs &args) noexcept override {
116
+ assert(m_childLayoutMetricsToken);
117
+ args.Child().LayoutMetricsChanged(m_childLayoutMetricsToken);
118
+ m_childLayoutMetricsToken.value = 0;
75
119
  }
76
120
 
77
121
  void FinalizeUpdate(
@@ -85,7 +129,6 @@ struct ModalHostView : public winrt::implements<ModalHostView, winrt::Windows::F
85
129
  private:
86
130
  void OnMounted(const winrt::Microsoft::ReactNative::ComponentView &view) noexcept {
87
131
  m_mounted = true;
88
-
89
132
  if (m_showQueued) {
90
133
  ShowOnUIThread(view);
91
134
  }
@@ -96,6 +139,14 @@ struct ModalHostView : public winrt::implements<ModalHostView, winrt::Windows::F
96
139
  }
97
140
 
98
141
  void AdjustWindowSize(const winrt::Microsoft::ReactNative::LayoutMetrics &layoutMetrics) noexcept {
142
+ #ifdef USE_EXPERIMENTAL_WINUI3
143
+ if (!m_popUp) {
144
+ #else
145
+ if (!m_window) {
146
+ #endif
147
+ return;
148
+ }
149
+
99
150
  if (layoutMetrics.Frame.Width == 0 && layoutMetrics.Frame.Height == 0) {
100
151
  return;
101
152
  }
@@ -108,11 +159,20 @@ struct ModalHostView : public winrt::implements<ModalHostView, winrt::Windows::F
108
159
  int32_t yCor = static_cast<int32_t>(
109
160
  (parentRC.top + parentRC.bottom - layoutMetrics.Frame.Height * layoutMetrics.PointScaleFactor) / 2);
110
161
 
162
+ #ifdef USE_EXPERIMENTAL_WINUI3
163
+ winrt::Windows::Graphics::RectInt32 rect2{
164
+ (int)xCor,
165
+ (int)yCor,
166
+ static_cast<int32_t>(layoutMetrics.Frame.Width * (layoutMetrics.PointScaleFactor)),
167
+ static_cast<int32_t>(layoutMetrics.Frame.Height * (layoutMetrics.PointScaleFactor))};
168
+ m_popUp.MoveAndResize(rect2);
169
+ #else
111
170
  // Adjust window position and size
112
171
  m_window.ResizeClient(
113
172
  {static_cast<int32_t>(layoutMetrics.Frame.Width * (layoutMetrics.PointScaleFactor)),
114
173
  static_cast<int32_t>(layoutMetrics.Frame.Height * (layoutMetrics.PointScaleFactor))});
115
174
  m_window.Move({xCor, yCor});
175
+ #endif
116
176
  };
117
177
 
118
178
  void ShowOnUIThread(const winrt::Microsoft::ReactNative::ComponentView &view) {
@@ -122,6 +182,24 @@ struct ModalHostView : public winrt::implements<ModalHostView, winrt::Windows::F
122
182
  m_showQueued = false;
123
183
  EnsureModalCreated(view);
124
184
 
185
+ #ifdef USE_EXPERIMENTAL_WINUI3
186
+ if (m_popUp) {
187
+ m_bridge.Enable();
188
+ m_popUp.Show();
189
+
190
+ auto navHost = winrt::Microsoft::UI::Input::InputFocusNavigationHost::GetForSiteBridge(
191
+ m_popUp.as<winrt::Microsoft::UI::Content::IContentSiteBridge>());
192
+ auto result = navHost.NavigateFocus(winrt::Microsoft::UI::Input::FocusNavigationRequest::Create(
193
+ winrt::Microsoft::UI::Input::FocusNavigationReason::First));
194
+
195
+ // dispatch onShow event
196
+ if (auto eventEmitter = EventEmitter()) {
197
+ ::Microsoft::ReactNativeSpecs::ModalHostViewEventEmitter::OnShow eventArgs;
198
+ eventEmitter->onShow(eventArgs);
199
+ }
200
+ }
201
+ #endif
202
+
125
203
  if (m_window && !m_window.IsVisible()) {
126
204
  m_bridge.Enable();
127
205
  m_window.Show(true);
@@ -146,6 +224,12 @@ struct ModalHostView : public winrt::implements<ModalHostView, winrt::Windows::F
146
224
  m_window.Hide();
147
225
  }
148
226
 
227
+ #ifdef USE_EXPERIMENTAL_WINUI3
228
+ if (m_popUp) {
229
+ m_popUp.Hide();
230
+ }
231
+ #endif
232
+
149
233
  // dispatch onDismiss event
150
234
  if (auto eventEmitter = EventEmitter()) {
151
235
  ::Microsoft::ReactNativeSpecs::ModalHostViewEventEmitter::OnDismiss eventArgs;
@@ -168,6 +252,11 @@ struct ModalHostView : public winrt::implements<ModalHostView, winrt::Windows::F
168
252
  return;
169
253
  }
170
254
 
255
+ #ifdef USE_EXPERIMENTAL_WINUI3
256
+ if (m_popUp) {
257
+ return;
258
+ }
259
+ #endif
171
260
  // get the root hwnd
172
261
  m_prevWindowID =
173
262
  winrt::Microsoft::ReactNative::ReactCoreInjection::GetTopLevelWindowId(view.ReactContext().Properties());
@@ -175,6 +264,34 @@ struct ModalHostView : public winrt::implements<ModalHostView, winrt::Windows::F
175
264
  m_parentHwnd =
176
265
  view.as<::Microsoft::ReactNative::Composition::Experimental::IComponentViewInterop>()->GetHwndForParenting();
177
266
 
267
+ auto portal = view.as<winrt::Microsoft::ReactNative::Composition::PortalComponentView>();
268
+
269
+ #ifdef USE_EXPERIMENTAL_WINUI3
270
+ m_bridge = winrt::Microsoft::UI::Content::DesktopChildSiteBridge::Create(
271
+ view.Parent().as<winrt::Microsoft::ReactNative::Composition::ComponentView>().Compositor(),
272
+ winrt::Microsoft::UI::GetWindowIdFromWindow(m_parentHwnd));
273
+ m_reactNativeIsland = winrt::Microsoft::ReactNative::ReactNativeIsland::CreatePortal(portal);
274
+ auto contentIsland = m_reactNativeIsland.Island();
275
+
276
+ m_popUp = m_bridge.TryCreatePopupSiteBridge();
277
+ m_popUp.Connect(contentIsland);
278
+
279
+ // set the top-level windows as the new hwnd
280
+ winrt::Microsoft::ReactNative::ReactCoreInjection::SetTopLevelWindowId(
281
+ view.ReactContext().Properties(),
282
+ reinterpret_cast<uint64_t>(winrt::Microsoft::UI::GetWindowFromWindowId(m_popUp.WindowId())));
283
+
284
+ auto navHost = winrt::Microsoft::UI::Input::InputFocusNavigationHost::GetForSiteBridge(
285
+ m_popUp.as<winrt::Microsoft::UI::Content::IContentSiteBridge>());
286
+ m_departFocusToken = navHost.DepartFocusRequested(
287
+ [wkView = winrt::make_weak(view)](
288
+ const auto &sender, const winrt::Microsoft::UI::Input::FocusNavigationRequestEventArgs &args) {
289
+ if (auto strongView = wkView.get()) {
290
+ TrySetFocus(strongView.Parent());
291
+ }
292
+ });
293
+
294
+ #else
178
295
  auto presenter = winrt::Microsoft::UI::Windowing::OverlappedPresenter::CreateForDialog();
179
296
  presenter.SetBorderAndTitleBar(true, false);
180
297
  presenter.IsModal(true);
@@ -190,8 +307,7 @@ struct ModalHostView : public winrt::implements<ModalHostView, winrt::Windows::F
190
307
  // create a react native island - code taken from CompositionHwndHost
191
308
  m_bridge = winrt::Microsoft::UI::Content::DesktopChildSiteBridge::Create(
192
309
  view.Parent().as<winrt::Microsoft::ReactNative::Composition::ComponentView>().Compositor(), m_window.Id());
193
- m_reactNativeIsland = winrt::Microsoft::ReactNative::ReactNativeIsland::CreatePortal(
194
- view.as<winrt::Microsoft::ReactNative::Composition::PortalComponentView>());
310
+ m_reactNativeIsland = winrt::Microsoft::ReactNative::ReactNativeIsland::CreatePortal(portal);
195
311
  auto contentIsland = m_reactNativeIsland.Island();
196
312
 
197
313
  auto navHost = winrt::Microsoft::UI::Input::InputFocusNavigationHost::GetForSiteBridge(m_bridge);
@@ -202,13 +318,58 @@ struct ModalHostView : public winrt::implements<ModalHostView, winrt::Windows::F
202
318
  TrySetFocus(strongView.Parent());
203
319
  }
204
320
  });
321
+ m_bridge.Connect(contentIsland);
322
+
323
+ #endif
205
324
 
206
325
  m_bridge.ResizePolicy(winrt::Microsoft::UI::Content::ContentSizePolicy::ResizeContentToParentWindow);
207
- m_bridge.Connect(contentIsland);
208
- AdjustWindowSize(view.LayoutMetrics());
326
+
327
+ m_islandStateChangedToken =
328
+ contentIsland.StateChanged([weakThis = get_weak()](
329
+ winrt::Microsoft::UI::Content::ContentIsland const &island,
330
+ winrt::Microsoft::UI::Content::ContentIslandStateChangedEventArgs const &args) {
331
+ if (auto pThis = weakThis.get()) {
332
+ if (args.DidRasterizationScaleChange() || args.DidLayoutDirectionChange()) {
333
+ pThis->UpdateConstraints();
334
+ }
335
+ }
336
+ });
337
+
338
+ UpdateConstraints();
339
+
340
+ if (portal.ContentRoot().Children().Size()) {
341
+ AdjustWindowSize(portal.ContentRoot().Children().GetAt(0).LayoutMetrics());
342
+ }
209
343
  m_bridge.Show();
210
344
  }
211
345
 
346
+ void UpdateConstraints() noexcept {
347
+ auto displayArea = winrt::Microsoft::UI::Windowing::DisplayArea::GetFromDisplayId(
348
+ m_bridge.SiteView().EnvironmentView().DisplayId());
349
+ auto workArea = displayArea.WorkArea();
350
+
351
+ float scale = m_reactNativeIsland.Island().RasterizationScale();
352
+
353
+ winrt::Microsoft::ReactNative::LayoutConstraints constraints;
354
+ constraints.MinimumSize = {0, 0};
355
+ // Constrain the size of the modal to 90% of the screen size
356
+ constraints.MaximumSize = {
357
+ static_cast<float>((workArea.Width / scale) * 0.9), static_cast<float>((workArea.Height / scale) * 0.9)};
358
+ constraints.LayoutDirection = winrt::Microsoft::ReactNative::LayoutDirection::Undefined;
359
+
360
+ auto layoutDirection = m_reactNativeIsland.Island().LayoutDirection();
361
+ if (layoutDirection == winrt::Microsoft::UI::Content::ContentLayoutDirection::LeftToRight)
362
+ constraints.LayoutDirection = winrt::Microsoft::ReactNative::LayoutDirection::LeftToRight;
363
+ else if (layoutDirection == winrt::Microsoft::UI::Content::ContentLayoutDirection::RightToLeft)
364
+ constraints.LayoutDirection = winrt::Microsoft::ReactNative::LayoutDirection::RightToLeft;
365
+
366
+ // By setting a custom contraint here the behavior of the modal slightly changes.
367
+ // When no constraint is set (maxSize is std::numeric_limits<Float>::infinity()), yoga will layout the content to a
368
+ // desired size If we provide a specific max size, then contents with a flex:1 will expand to fill that size. We
369
+ // might want to provide a windows specific property to control this behavior.
370
+ m_state.UpdateState(winrt::make<ModalHostState>(constraints, m_reactNativeIsland.Island().RasterizationScale()));
371
+ }
372
+
212
373
  static void TrySetFocus(const winrt::Microsoft::ReactNative::ComponentView &view) {
213
374
  auto focusController = winrt::Microsoft::UI::Input::InputFocusController::GetForIsland(
214
375
  view.as<winrt::Microsoft::ReactNative::Composition::ComponentView>().Root().ReactNativeIsland().Island());
@@ -222,10 +383,16 @@ struct ModalHostView : public winrt::implements<ModalHostView, winrt::Windows::F
222
383
  bool m_showTitleBar{false};
223
384
  bool m_showQueued{false};
224
385
  bool m_mounted{false};
386
+ winrt::event_token m_islandStateChangedToken;
225
387
  winrt::Microsoft::UI::Input::InputFocusNavigationHost::DepartFocusRequested_revoker m_departFocusRevoker;
226
388
  winrt::event_token m_departFocusToken;
389
+ winrt::event_token m_childLayoutMetricsToken;
390
+ winrt::Microsoft::ReactNative::IComponentState m_state{nullptr};
227
391
  winrt::Microsoft::UI::Content::DesktopChildSiteBridge m_bridge{nullptr};
228
392
  winrt::Microsoft::ReactNative::ReactNativeIsland m_reactNativeIsland{nullptr};
393
+ #ifdef USE_EXPERIMENTAL_WINUI3
394
+ winrt::Microsoft::UI::Content::PopupWindowSiteBridge m_popUp{nullptr};
395
+ #endif
229
396
  };
230
397
 
231
398
  void RegisterWindowsModalHostNativeComponent(
@@ -30,11 +30,23 @@ void PortalComponentView::MountChildComponentView(
30
30
  const winrt::Microsoft::ReactNative::ComponentView &childComponentView,
31
31
  uint32_t index) noexcept {
32
32
  m_rootComponentView->MountChildComponentView(childComponentView, index);
33
+ if (m_builder && m_builder->MountChildComponentViewHandler()) {
34
+ m_builder->MountChildComponentViewHandler()(
35
+ *this,
36
+ winrt::make<winrt::Microsoft::ReactNative::implementation::MountChildComponentViewArgs>(
37
+ childComponentView, index));
38
+ }
33
39
  }
34
40
 
35
41
  void PortalComponentView::UnmountChildComponentView(
36
42
  const winrt::Microsoft::ReactNative::ComponentView &childComponentView,
37
43
  uint32_t index) noexcept {
44
+ if (m_builder && m_builder->UnmountChildComponentViewHandler()) {
45
+ m_builder->UnmountChildComponentViewHandler()(
46
+ *this,
47
+ winrt::make<winrt::Microsoft::ReactNative::implementation::UnmountChildComponentViewArgs>(
48
+ childComponentView, index));
49
+ }
38
50
  m_rootComponentView->UnmountChildComponentView(childComponentView, index);
39
51
  }
40
52
 
@@ -3,6 +3,7 @@
3
3
 
4
4
  #include "pch.h"
5
5
  #include "ReactCompositionViewComponentBuilder.h"
6
+ #include <Fabric/AbiViewComponentDescriptor.h>
6
7
  #include <Fabric/Composition/CompositionViewComponentView.h>
7
8
  #include <Fabric/Composition/ContentIslandComponentView.h>
8
9
  #include <Fabric/Composition/PortalComponentView.h>
@@ -128,7 +129,7 @@ void ReactCompositionViewComponentBuilder::SetPortalComponentViewInitializer(
128
129
  };
129
130
  m_descriptorConstructorFactory = []() {
130
131
  return &facebook::react::concreteComponentDescriptorConstructor<
131
- ::Microsoft::ReactNative::AbiViewComponentDescriptor>;
132
+ ::Microsoft::ReactNative::AbiPortalComponentDescriptor>;
132
133
  };
133
134
  }
134
135
 
@@ -3,7 +3,6 @@
3
3
  // Licensed under the MIT License.
4
4
 
5
5
  #include <Fabric/AbiComponentDescriptor.h>
6
- #include <Fabric/AbiViewComponentDescriptor.h>
7
6
  #include <react/renderer/componentregistry/ComponentDescriptorProvider.h>
8
7
  #include <react/renderer/core/ReactPrimitives.h>
9
8
  #include "winrt/Microsoft.ReactNative.Composition.Experimental.h"
@@ -906,21 +906,23 @@ winrt::Microsoft::UI::Content::ContentIsland ReactNativeIsland::Island() {
906
906
  }
907
907
  });
908
908
  #ifdef USE_EXPERIMENTAL_WINUI3
909
- m_islandConnectedToken = m_island.Connected(
910
- [weakThis = get_weak()](
911
- winrt::IInspectable const &, winrt::Microsoft::UI::Content::ContentIsland const &island) {
912
- if (auto pThis = weakThis.get()) {
913
- pThis->OnMounted();
914
- }
915
- });
909
+ if (!m_isFragment) {
910
+ m_islandConnectedToken = m_island.Connected(
911
+ [weakThis = get_weak()](
912
+ winrt::IInspectable const &, winrt::Microsoft::UI::Content::ContentIsland const &island) {
913
+ if (auto pThis = weakThis.get()) {
914
+ pThis->OnMounted();
915
+ }
916
+ });
916
917
 
917
- m_islandDisconnectedToken = m_island.Disconnected(
918
- [weakThis = get_weak()](
919
- winrt::IInspectable const &, winrt::Microsoft::UI::Content::ContentIsland const &island) {
920
- if (auto pThis = weakThis.get()) {
921
- pThis->OnUnmounted();
922
- }
923
- });
918
+ m_islandDisconnectedToken = m_island.Disconnected(
919
+ [weakThis = get_weak()](
920
+ winrt::IInspectable const &, winrt::Microsoft::UI::Content::ContentIsland const &island) {
921
+ if (auto pThis = weakThis.get()) {
922
+ pThis->OnUnmounted();
923
+ }
924
+ });
925
+ }
924
926
  #endif
925
927
  }
926
928
  return m_island;