react-native-windows 0.74.32 → 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.
- package/Libraries/Modal/Modal.windows.js +4 -1
- package/Microsoft.ReactNative/Fabric/AbiPortalShadowNode.cpp +97 -0
- package/Microsoft.ReactNative/Fabric/AbiPortalShadowNode.h +53 -0
- package/Microsoft.ReactNative/Fabric/AbiViewComponentDescriptor.h +161 -17
- package/Microsoft.ReactNative/Fabric/Composition/CompositionDynamicAutomationProvider.cpp +18 -0
- package/Microsoft.ReactNative/Fabric/Composition/CompositionDynamicAutomationProvider.h +10 -0
- package/Microsoft.ReactNative/Fabric/Composition/CompositionViewComponentView.cpp +74 -42
- package/Microsoft.ReactNative/Fabric/Composition/CompositionViewComponentView.h +2 -0
- package/Microsoft.ReactNative/Fabric/Composition/ContentIslandComponentView.cpp +152 -1
- package/Microsoft.ReactNative/Fabric/Composition/ContentIslandComponentView.h +16 -0
- package/Microsoft.ReactNative/Fabric/Composition/FocusManager.cpp +4 -2
- package/Microsoft.ReactNative/Fabric/Composition/FocusManager.h +9 -1
- package/Microsoft.ReactNative/Fabric/Composition/Modal/WindowsModalHostViewComponentView.cpp +179 -12
- package/Microsoft.ReactNative/Fabric/Composition/PortalComponentView.cpp +12 -0
- package/Microsoft.ReactNative/Fabric/Composition/ReactCompositionViewComponentBuilder.cpp +2 -1
- package/Microsoft.ReactNative/Fabric/Composition/ReactCompositionViewComponentBuilder.h +0 -1
- package/Microsoft.ReactNative/Fabric/Composition/ReactNativeIsland.cpp +16 -14
- package/Microsoft.ReactNative/Fabric/Composition/RootComponentView.cpp +6 -4
- package/Microsoft.ReactNative/Fabric/Composition/RootComponentView.h +3 -1
- package/Microsoft.ReactNative/Fabric/Composition/Theme.cpp +5 -0
- package/Microsoft.ReactNative/Fabric/platform/react/renderer/graphics/PlatformColorParser.h +1 -1
- package/Microsoft.ReactNative/IReactCompositionViewComponentBuilder.idl +10 -1
- package/Microsoft.ReactNative/Modules/ClipboardModule.cpp +1 -1
- package/Microsoft.ReactNative/Modules/ClipboardModule.h +1 -1
- package/Microsoft.ReactNative.Cxx/NativeModules.h +20 -0
- package/PropertySheets/Generated/PackageVersion.g.props +3 -3
- package/Shared/Shared.vcxitems +3 -3
- package/Shared/Shared.vcxitems.filters +1 -1
- package/codegen/react/components/rnwcore/ActivityIndicatorView.g.h +1 -1
- package/codegen/react/components/rnwcore/AndroidDrawerLayout.g.h +1 -1
- package/codegen/react/components/rnwcore/AndroidHorizontalScrollContentView.g.h +1 -1
- package/codegen/react/components/rnwcore/AndroidProgressBar.g.h +1 -1
- package/codegen/react/components/rnwcore/AndroidSwipeRefreshLayout.g.h +1 -1
- package/codegen/react/components/rnwcore/AndroidSwitch.g.h +1 -1
- package/codegen/react/components/rnwcore/DebuggingOverlay.g.h +1 -1
- package/codegen/react/components/rnwcore/InputAccessory.g.h +1 -1
- package/codegen/react/components/rnwcore/ModalHostView.g.h +1 -1
- package/codegen/react/components/rnwcore/PullToRefreshView.g.h +1 -1
- package/codegen/react/components/rnwcore/SafeAreaView.g.h +1 -1
- package/codegen/react/components/rnwcore/Switch.g.h +1 -1
- package/codegen/react/components/rnwcore/UnimplementedNativeView.g.h +1 -1
- package/package.json +3 -3
- 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(
|
|
18
|
-
|
|
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(
|
|
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
|
package/Microsoft.ReactNative/Fabric/Composition/Modal/WindowsModalHostViewComponentView.cpp
CHANGED
|
@@ -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
|
|
69
|
-
const winrt::Microsoft::ReactNative::ComponentView &view
|
|
70
|
-
const winrt::Microsoft::ReactNative::
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
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
|
-
|
|
208
|
-
|
|
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::
|
|
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
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
pThis
|
|
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
|
-
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
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;
|