react-native-windows 0.77.7 → 0.77.8

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 (54) hide show
  1. package/Libraries/Modal/Modal.windows.js +4 -1
  2. package/Microsoft.ReactNative/CompositionComponentView.idl +13 -1
  3. package/Microsoft.ReactNative/Fabric/AbiPortalShadowNode.cpp +97 -0
  4. package/Microsoft.ReactNative/Fabric/AbiPortalShadowNode.h +53 -0
  5. package/Microsoft.ReactNative/Fabric/AbiViewComponentDescriptor.h +160 -17
  6. package/Microsoft.ReactNative/Fabric/ComponentView.cpp +0 -1
  7. package/Microsoft.ReactNative/Fabric/Composition/ComponentViewRegistry.cpp +0 -5
  8. package/Microsoft.ReactNative/Fabric/Composition/CompositionDynamicAutomationProvider.cpp +0 -2
  9. package/Microsoft.ReactNative/Fabric/Composition/CompositionEventHandler.cpp +13 -32
  10. package/Microsoft.ReactNative/Fabric/Composition/CompositionEventHandler.h +1 -3
  11. package/Microsoft.ReactNative/Fabric/Composition/CompositionRootAutomationProvider.cpp +1 -1
  12. package/Microsoft.ReactNative/Fabric/Composition/CompositionRootAutomationProvider.h +2 -1
  13. package/Microsoft.ReactNative/Fabric/Composition/CompositionViewComponentView.cpp +25 -20
  14. package/Microsoft.ReactNative/Fabric/Composition/Modal/WindowsModalHostViewComponentView.cpp +313 -319
  15. package/Microsoft.ReactNative/Fabric/Composition/Modal/WindowsModalHostViewComponentView.h +3 -61
  16. package/Microsoft.ReactNative/Fabric/Composition/PortalComponentView.cpp +78 -0
  17. package/Microsoft.ReactNative/Fabric/Composition/PortalComponentView.h +52 -0
  18. package/Microsoft.ReactNative/Fabric/Composition/ReactCompositionViewComponentBuilder.cpp +22 -0
  19. package/Microsoft.ReactNative/Fabric/Composition/ReactCompositionViewComponentBuilder.h +7 -5
  20. package/Microsoft.ReactNative/Fabric/Composition/ReactNativeIsland.cpp +79 -19
  21. package/Microsoft.ReactNative/Fabric/Composition/ReactNativeIsland.h +12 -6
  22. package/Microsoft.ReactNative/Fabric/Composition/RootComponentView.cpp +73 -19
  23. package/Microsoft.ReactNative/Fabric/Composition/RootComponentView.h +16 -0
  24. package/Microsoft.ReactNative/Fabric/Composition/TextInput/WindowsTextInputComponentView.cpp +2 -2
  25. package/Microsoft.ReactNative/Fabric/Composition/UiaHelpers.cpp +38 -23
  26. package/Microsoft.ReactNative/Fabric/FabricUIManagerModule.cpp +1 -6
  27. package/Microsoft.ReactNative/Fabric/FabricUIManagerModule.h +0 -3
  28. package/Microsoft.ReactNative/Fabric/WindowsComponentDescriptorRegistry.cpp +0 -2
  29. package/Microsoft.ReactNative/IReactCompositionViewComponentBuilder.idl +15 -1
  30. package/Microsoft.ReactNative/ReactNativeHost.cpp +5 -0
  31. package/Microsoft.ReactNative/ReactNativeIsland.idl +5 -1
  32. package/PropertySheets/Generated/PackageVersion.g.props +3 -3
  33. package/Shared/Networking/WinRTWebSocketResource.cpp +5 -0
  34. package/Shared/Shared.vcxitems +6 -5
  35. package/Shared/Shared.vcxitems.filters +3 -4
  36. package/codegen/react/components/rnwcore/ActivityIndicatorView.g.h +212 -0
  37. package/codegen/react/components/rnwcore/AndroidDrawerLayout.g.h +295 -0
  38. package/codegen/react/components/rnwcore/AndroidHorizontalScrollContentView.g.h +200 -0
  39. package/codegen/react/components/rnwcore/AndroidProgressBar.g.h +224 -0
  40. package/codegen/react/components/rnwcore/AndroidSwipeRefreshLayout.g.h +250 -0
  41. package/codegen/react/components/rnwcore/AndroidSwitch.g.h +267 -0
  42. package/codegen/react/components/rnwcore/DebuggingOverlay.g.h +234 -0
  43. package/codegen/react/components/rnwcore/InputAccessory.g.h +200 -0
  44. package/codegen/react/components/rnwcore/ModalHostView.g.h +283 -0
  45. package/codegen/react/components/rnwcore/PullToRefreshView.g.h +246 -0
  46. package/codegen/react/components/rnwcore/SafeAreaView.g.h +197 -0
  47. package/codegen/react/components/rnwcore/Switch.g.h +263 -0
  48. package/codegen/react/components/rnwcore/UnimplementedNativeView.g.h +200 -0
  49. package/just-task.js +1 -1
  50. package/package.json +3 -3
  51. package/Microsoft.ReactNative/Fabric/AbiViewComponentDescriptor.cpp +0 -191
  52. package/Microsoft.ReactNative/Fabric/Composition/Modal/WindowsModalHostViewComponentDescriptor.h +0 -39
  53. package/Microsoft.ReactNative/Fabric/Composition/Modal/WindowsModalHostViewShadowNode.cpp +0 -18
  54. package/Microsoft.ReactNative/Fabric/Composition/Modal/WindowsModalHostViewShadowNode.h +0 -39
@@ -5,379 +5,373 @@
5
5
 
6
6
  #include "WindowsModalHostViewComponentView.h"
7
7
 
8
- #include <AutoDraw.h>
9
- #include <Fabric/DWriteHelpers.h>
10
- #include "../CompositionDynamicAutomationProvider.h"
11
- #include "Unicode.h"
12
-
13
- #include <DispatcherQueue.h>
14
- #include <Fabric/ComponentView.h>
15
- #include <Fabric/Composition/CompositionContextHelper.h>
16
- #include <Fabric/Composition/CompositionUIService.h>
17
- #include <Fabric/Composition/ReactNativeIsland.h>
18
- #include <windows.ui.composition.interop.h>
19
- #include <winrt/Microsoft.ReactNative.Composition.Experimental.h>
8
+ #include "../../../codegen/react/components/rnwcore/ModalHostView.g.h"
9
+ #include <ComponentView.Experimental.interop.h>
20
10
  #include <winrt/Microsoft.UI.Content.h>
11
+ #include <winrt/Microsoft.UI.Input.h>
12
+ #include <winrt/Microsoft.UI.Windowing.h>
21
13
  #include <winrt/Microsoft.UI.interop.h>
22
- #include <winrt/Windows.UI.Composition.Desktop.h>
23
- #include <winrt/Windows.UI.Composition.h>
24
- #include "IReactContext.h"
25
- #include "ReactHost/ReactInstanceWin.h"
26
- #include "ReactNativeHost.h"
27
- #include "WindowsModalHostViewShadowNode.h"
28
14
 
29
15
  namespace winrt::Microsoft::ReactNative::Composition::implementation {
30
- WindowsModalHostComponentView::WindowsModalHostComponentView(
31
- const winrt::Microsoft::ReactNative::Composition::Experimental::ICompositionContext &compContext,
32
- facebook::react::Tag tag,
33
- winrt::Microsoft::ReactNative::ReactContext const &reactContext)
34
- : Super(compContext, tag, reactContext) {}
35
-
36
- WindowsModalHostComponentView::~WindowsModalHostComponentView() {
37
- // dispatch onDismiss event
38
- auto emitter = std::static_pointer_cast<const facebook::react::ModalHostViewEventEmitter>(m_eventEmitter);
39
- facebook::react::ModalHostViewEventEmitter::OnDismiss onDismissArgs;
40
- emitter->onDismiss(onDismissArgs);
41
-
42
- // reset the topWindowID
43
- if (m_prevWindowID) {
44
- auto host =
45
- winrt::Microsoft::ReactNative::implementation::ReactNativeHost::GetReactNativeHost(m_reactContext.Properties());
46
- winrt::Microsoft::ReactNative::ReactCoreInjection::SetTopLevelWindowId(
47
- host.InstanceSettings().Properties(), m_prevWindowID);
48
- m_prevWindowID = 0;
49
- }
50
16
 
51
- // enable input to parent
52
- EnableWindow(m_parentHwnd, true);
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) {}
53
21
 
54
- // Check if the window handle (m_hwnd) exists and destroy it if necessary
55
- if (m_hwnd) {
56
- // Close/Destroy the modal window
57
- SendMessage(m_hwnd, WM_DESTROY, 0, 0);
58
- m_hwnd = nullptr;
22
+ winrt::Microsoft::ReactNative::LayoutConstraints LayoutConstraints() const noexcept {
23
+ return m_layoutConstraints;
59
24
  }
60
- }
61
-
62
- winrt::Microsoft::ReactNative::ComponentView WindowsModalHostComponentView::Create(
63
- const winrt::Microsoft::ReactNative::Composition::Experimental::ICompositionContext &compContext,
64
- facebook::react::Tag tag,
65
- winrt::Microsoft::ReactNative::ReactContext const &reactContext) noexcept {
66
- return winrt::make<WindowsModalHostComponentView>(compContext, tag, reactContext);
67
- }
68
-
69
- // constants for creating a new windows
70
- constexpr PCWSTR c_modalWindowClassName = L"MS_REACTNATIVE_MODAL";
71
- constexpr auto CompHostProperty = L"CompHost";
72
- const int MODAL_MIN_WIDTH = 50;
73
- const int MODAL_MIN_HEIGHT = 50;
74
-
75
- float ScaleFactor(HWND hwnd) noexcept {
76
- return GetDpiForWindow(hwnd) / static_cast<float>(USER_DEFAULT_SCREEN_DPI);
77
- }
78
25
 
79
- // creates a new modal window
80
- void WindowsModalHostComponentView::EnsureModalCreated() {
81
- auto host =
82
- winrt::Microsoft::ReactNative::implementation::ReactNativeHost::GetReactNativeHost(m_reactContext.Properties());
83
-
84
- // return if hwnd already exists
85
- if (!host || m_hwnd) {
86
- return;
26
+ float PointScaleFactor() const noexcept {
27
+ return m_pointScaleFactor;
87
28
  }
88
29
 
89
- RegisterWndClass();
30
+ private:
31
+ float m_pointScaleFactor{1.0f};
32
+ winrt::Microsoft::ReactNative::LayoutConstraints m_layoutConstraints;
33
+ };
90
34
 
91
- HINSTANCE hInstance = GetModuleHandle(NULL);
92
- winrt::com_ptr<::IUnknown> spunk;
35
+ struct ModalHostView : public winrt::implements<ModalHostView, winrt::Windows::Foundation::IInspectable>,
36
+ ::Microsoft::ReactNativeSpecs::BaseModalHostView<ModalHostView> {
37
+ ~ModalHostView() {
38
+ if (m_window && m_window.IsVisible()) {
39
+ CloseWindow();
40
+ }
93
41
 
94
- // get the root hwnd
95
- m_prevWindowID =
96
- winrt::Microsoft::ReactNative::ReactCoreInjection::GetTopLevelWindowId(m_reactContext.Properties().Handle());
42
+ if (m_reactNativeIsland) {
43
+ m_reactNativeIsland.Island().Close();
44
+ }
97
45
 
98
- m_parentHwnd = GetHwndForParenting();
46
+ if (m_bridge) {
47
+ if (m_departFocusToken && !m_bridge.IsClosed()) {
48
+ auto navHost = winrt::Microsoft::UI::Input::InputFocusNavigationHost::GetForSiteBridge(m_bridge);
49
+ navHost.DepartFocusRequested(m_departFocusToken);
50
+ }
51
+ m_bridge.Close();
52
+ }
99
53
 
100
- auto windowsStyle = m_showTitleBar ? WS_OVERLAPPEDWINDOW : WS_POPUP;
54
+ if (m_window) {
55
+ m_window.Destroy();
56
+ m_window = nullptr;
57
+ }
58
+ }
101
59
 
102
- m_hwnd = CreateWindow(
103
- c_modalWindowClassName,
104
- L"React-Native Modal",
105
- windowsStyle,
106
- CW_USEDEFAULT,
107
- CW_USEDEFAULT,
108
- MODAL_MIN_WIDTH,
109
- MODAL_MIN_HEIGHT,
110
- m_parentHwnd, // parent
111
- nullptr,
112
- hInstance,
113
- spunk.get());
60
+ void InitializePortalViewComponent(
61
+ const winrt::Microsoft::ReactNative::Composition::PortalComponentView &portalComponentView) noexcept {
62
+ m_reactContext = portalComponentView.ReactContext();
114
63
 
115
- // Check if window creation succeeded
116
- if (!m_hwnd) {
117
- throw std::exception("Failed to create new hwnd for Modal: " + GetLastError());
64
+ portalComponentView.Mounted(
65
+ [](const auto & /*sender*/, const auto &view) { view.UserData().as<ModalHostView>()->OnMounted(view); });
66
+ portalComponentView.Unmounted(
67
+ [](const auto & /*sender*/, const auto &view) { view.UserData().as<ModalHostView>()->OnUnmounted(view); });
118
68
  }
119
69
 
120
- // Disable user sizing of the hwnd
121
- ::SetWindowLong(m_hwnd, GWL_STYLE, GetWindowLong(m_hwnd, GWL_STYLE) & ~WS_SIZEBOX);
122
-
123
- // set the top-level windows as the new hwnd
124
- winrt::Microsoft::ReactNative::ReactCoreInjection::SetTopLevelWindowId(
125
- host.InstanceSettings().Properties(), reinterpret_cast<uint64_t>(m_hwnd));
126
-
127
- // get current compositor - handles the creation/manipulation of visual objects
128
- auto compositionContext = CompositionContext();
129
- auto compositor =
130
- winrt::Microsoft::ReactNative::Composition::Experimental::MicrosoftCompositionContextHelper::InnerCompositor(
131
- compositionContext);
132
-
133
- // create a react native island - code taken from CompositionHwndHost
134
- auto bridge = winrt::Microsoft::UI::Content::DesktopChildSiteBridge::Create(
135
- compositor, winrt::Microsoft::UI::GetWindowIdFromWindow(m_hwnd));
136
- m_reactNativeIsland = winrt::Microsoft::ReactNative::ReactNativeIsland(compositor, m_reactContext.Handle(), *this);
137
- auto contentIsland = m_reactNativeIsland.Island();
138
- bridge.Connect(contentIsland);
139
- bridge.Show();
140
-
141
- // set ScaleFactor
142
- ScaleFactor(m_hwnd);
143
-
144
- // set layout contraints
145
- winrt::Microsoft::ReactNative::LayoutConstraints constraints;
146
- constraints.LayoutDirection = winrt::Microsoft::ReactNative::LayoutDirection::Undefined;
147
-
148
- RECT rc;
149
- GetClientRect(m_parentHwnd, &rc);
150
- // Maximum size is set to size of parent hwnd
151
- constraints.MaximumSize = {(rc.right - rc.left) * ScaleFactor(m_hwnd), (rc.bottom - rc.top) / ScaleFactor(m_hwnd)};
152
- constraints.MinimumSize = {MODAL_MIN_WIDTH * ScaleFactor(m_hwnd), MODAL_MIN_HEIGHT * ScaleFactor(m_hwnd)};
153
- m_reactNativeIsland.Arrange(constraints, {0, 0});
154
- bridge.ResizePolicy(winrt::Microsoft::UI::Content::ContentSizePolicy::ResizeContentToParentWindow);
155
-
156
- spunk.detach();
157
- }
158
-
159
- void WindowsModalHostComponentView::ShowOnUIThread() {
160
- if (m_hwnd && !IsWindowVisible(m_hwnd)) {
161
- ShowWindow(m_hwnd, SW_NORMAL);
162
- BringWindowToTop(m_hwnd);
163
- SetFocus(m_hwnd);
70
+ void UpdateProps(
71
+ const winrt::Microsoft::ReactNative::ComponentView &view,
72
+ const winrt::com_ptr<::Microsoft::ReactNativeSpecs::ModalHostViewProps> &newProps,
73
+ const winrt::com_ptr<::Microsoft::ReactNativeSpecs::ModalHostViewProps> &oldProps) noexcept override {
74
+ if (!oldProps || newProps->visible != oldProps->visible) {
75
+ if (newProps->visible.value_or(true)) {
76
+ // We do not immediately show the window, since we want to resize/position
77
+ // the window based on the layout metrics before we show it
78
+ m_showQueued = true;
79
+ } else {
80
+ CloseWindow();
81
+ }
82
+ }
83
+ ::Microsoft::ReactNativeSpecs::BaseModalHostView<ModalHostView>::UpdateProps(view, newProps, oldProps);
84
+ }
164
85
 
165
- // disable input to parent
166
- EnableWindow(m_parentHwnd, false);
86
+ void UpdateState(
87
+ const winrt::Microsoft::ReactNative::ComponentView & /*view*/,
88
+ const winrt::Microsoft::ReactNative::IComponentState &newState) noexcept override {
89
+ m_state = newState;
90
+ }
167
91
 
168
- // dispatch onShow event
169
- auto emitter = std::static_pointer_cast<const facebook::react::ModalHostViewEventEmitter>(m_eventEmitter);
170
- facebook::react::ModalHostViewEventEmitter::OnShow onShowArgs;
171
- emitter->onShow(onShowArgs);
92
+ void MountChildComponentView(
93
+ const winrt::Microsoft::ReactNative::ComponentView & /*view*/,
94
+ const winrt::Microsoft::ReactNative::MountChildComponentViewArgs &args) noexcept override {
95
+ AdjustWindowSize(args.Child().LayoutMetrics());
96
+ assert(!m_childLayoutMetricsToken);
97
+ m_childLayoutMetricsToken = args.Child().LayoutMetricsChanged(
98
+ [wkThis = get_weak()](
99
+ auto &sender, const winrt::Microsoft::ReactNative::LayoutMetricsChangedArgs &layoutMetricsChangedArgs) {
100
+ if (auto strongThis = wkThis.get()) {
101
+ strongThis->AdjustWindowSize(layoutMetricsChangedArgs.NewLayoutMetrics());
102
+ }
103
+ });
172
104
  }
173
- }
174
105
 
175
- void WindowsModalHostComponentView::HideOnUIThread() noexcept {
176
- if (m_hwnd) {
177
- SendMessage(m_hwnd, WM_CLOSE, 0, 0);
106
+ void UnmountChildComponentView(
107
+ const winrt::Microsoft::ReactNative::ComponentView & /*view*/,
108
+ const winrt::Microsoft::ReactNative::UnmountChildComponentViewArgs &args) noexcept override {
109
+ assert(m_childLayoutMetricsToken);
110
+ args.Child().LayoutMetricsChanged(m_childLayoutMetricsToken);
111
+ m_childLayoutMetricsToken.value = 0;
178
112
  }
179
113
 
180
- // dispatch onDismiss event
181
- auto emitter = std::static_pointer_cast<const facebook::react::ModalHostViewEventEmitter>(m_eventEmitter);
182
- facebook::react::ModalHostViewEventEmitter::OnDismiss onDismissArgs;
183
- emitter->onDismiss(onDismissArgs);
114
+ void FinalizeUpdate(
115
+ const winrt::Microsoft::ReactNative::ComponentView &view,
116
+ winrt::Microsoft::ReactNative::ComponentViewUpdateMask /*mask*/) noexcept override {
117
+ if (m_showQueued) {
118
+ ShowOnUIThread(view);
119
+ }
120
+ }
184
121
 
185
- // enable input to parent
186
- EnableWindow(m_parentHwnd, true);
122
+ private:
123
+ void OnMounted(const winrt::Microsoft::ReactNative::ComponentView &view) noexcept {
124
+ m_mounted = true;
187
125
 
188
- // reset the topWindowID
189
- if (m_prevWindowID) {
190
- auto host =
191
- winrt::Microsoft::ReactNative::implementation::ReactNativeHost::GetReactNativeHost(m_reactContext.Properties());
192
- winrt::Microsoft::ReactNative::ReactCoreInjection::SetTopLevelWindowId(
193
- host.InstanceSettings().Properties(), m_prevWindowID);
194
- m_prevWindowID = 0;
126
+ if (m_showQueued) {
127
+ ShowOnUIThread(view);
128
+ }
195
129
  }
196
- }
197
130
 
198
- // Windows Procedure - callback function used for handling all messages (generated by NTUser or manual calls to
199
- // SendMessage)
200
- LRESULT CALLBACK ModalBoxWndProc(HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam) noexcept {
201
- auto data = reinterpret_cast<::IUnknown *>(GetProp(
202
- hwnd,
203
- CompHostProperty)); // gets data handle from the property list of specified window (ie the window we want to make)
204
- winrt::Microsoft::ReactNative::CompositionHwndHost host{nullptr};
205
-
206
- if (data) {
207
- winrt::check_hresult(data->QueryInterface(
208
- winrt::guid_of<winrt::Microsoft::ReactNative::CompositionHwndHost>(),
209
- winrt::put_abi(host))); // look into the data for a CompositionHwndHost and store it in host
210
- auto result = static_cast<LRESULT>(host.TranslateMessage(message, wparam, lparam));
211
- if (result) {
212
- return result;
213
- }
131
+ void OnUnmounted(const winrt::Microsoft::ReactNative::ComponentView & /*view*/) noexcept {
132
+ m_mounted = false;
214
133
  }
215
134
 
216
- switch (message) {
217
- case WM_NCCREATE: { // called before WM_CREATE, lparam should be identical to members of CreateWindowEx
218
- auto createStruct = reinterpret_cast<CREATESTRUCT *>(lparam); // CreateStruct
219
- data = static_cast<::IUnknown *>(createStruct->lpCreateParams);
220
- SetProp(hwnd, CompHostProperty, data); // adds new properties to window
221
- break;
135
+ void AdjustWindowSize(const winrt::Microsoft::ReactNative::LayoutMetrics &layoutMetrics) noexcept {
136
+ #ifdef USE_EXPERIMENTAL_WINUI3
137
+ if (!m_popUp) {
138
+ #else
139
+ if (!m_window) {
140
+ #endif
141
+ return;
222
142
  }
223
- case WM_CLOSE: {
224
- // Just hide the window instead of destroying it
225
- ::ShowWindow(hwnd, SW_HIDE);
226
- return 0;
143
+
144
+ if (layoutMetrics.Frame.Width == 0 && layoutMetrics.Frame.Height == 0) {
145
+ return;
227
146
  }
228
- case WM_DESTROY: { // called when we want to destroy the window
229
- ::ShowWindow(hwnd, SW_HIDE);
230
- if (data) {
231
- data->Release();
147
+
148
+ // get Modal's position based on parent
149
+ RECT parentRC;
150
+ GetWindowRect(m_parentHwnd, &parentRC);
151
+ int32_t xCor = static_cast<int32_t>(
152
+ (parentRC.left + parentRC.right - layoutMetrics.Frame.Width * layoutMetrics.PointScaleFactor) / 2);
153
+ int32_t yCor = static_cast<int32_t>(
154
+ (parentRC.top + parentRC.bottom - layoutMetrics.Frame.Height * layoutMetrics.PointScaleFactor) / 2);
155
+
156
+ #ifdef USE_EXPERIMENTAL_WINUI3
157
+ winrt::Windows::Graphics::RectInt32 rect2{
158
+ (int)xCor,
159
+ (int)yCor,
160
+ static_cast<int32_t>(layoutMetrics.Frame.Width * (layoutMetrics.PointScaleFactor)),
161
+ static_cast<int32_t>(layoutMetrics.Frame.Height * (layoutMetrics.PointScaleFactor))};
162
+ m_popUp.MoveAndResize(rect2);
163
+ #else
164
+ // Fix for https://github.com/microsoft/microsoft-ui-xaml/issues/9529
165
+ auto titleBarHeight = m_window.TitleBar().Height();
166
+
167
+ // Adjust window position and size
168
+ m_window.ResizeClient(
169
+ {static_cast<int32_t>(layoutMetrics.Frame.Width * (layoutMetrics.PointScaleFactor)),
170
+ static_cast<int32_t>(layoutMetrics.Frame.Height * (layoutMetrics.PointScaleFactor)) - titleBarHeight});
171
+ m_window.Move({xCor, yCor});
172
+ #endif
173
+ };
174
+
175
+ void ShowOnUIThread(const winrt::Microsoft::ReactNative::ComponentView &view) {
176
+ if (!m_mounted)
177
+ return;
178
+
179
+ m_showQueued = false;
180
+ EnsureModalCreated(view);
181
+
182
+ if (m_window && !m_window.IsVisible()) {
183
+ m_bridge.Enable();
184
+ m_window.Show(true);
185
+
186
+ auto navHost = winrt::Microsoft::UI::Input::InputFocusNavigationHost::GetForSiteBridge(m_bridge);
187
+ auto result = navHost.NavigateFocus(winrt::Microsoft::UI::Input::FocusNavigationRequest::Create(
188
+ winrt::Microsoft::UI::Input::FocusNavigationReason::First));
189
+
190
+ // dispatch onShow event
191
+ if (auto eventEmitter = EventEmitter()) {
192
+ ::Microsoft::ReactNativeSpecs::ModalHostViewEventEmitter::OnShow eventArgs;
193
+ eventEmitter->onShow(eventArgs);
232
194
  }
233
- SetProp(hwnd, CompHostProperty, nullptr);
234
- break;
235
195
  }
236
196
  }
237
197
 
238
- return DefWindowProc(hwnd, message, wparam, lparam);
239
- }
240
-
241
- // Creates and Register a new window class
242
- void WindowsModalHostComponentView::RegisterWndClass() noexcept {
243
- static bool registered = false;
244
- if (registered) {
245
- return;
246
- }
247
-
248
- HINSTANCE hInstance =
249
- GetModuleHandle(NULL); // returns a handle to the file used to create the calling process (.exe file)
250
-
251
- WNDCLASSEX wcex = {}; // contains window class information
252
- wcex.cbSize = sizeof(wcex); // size of windows class (bytes)
253
- wcex.style = CS_HREDRAW | CS_VREDRAW; // class style (redraw window on size adjustment)
254
- wcex.lpfnWndProc = &ModalBoxWndProc; // pointer to windows procedure
255
- wcex.cbClsExtra = DLGWINDOWEXTRA; // extra bytes to allocate
256
- wcex.cbWndExtra =
257
- sizeof(winrt::impl::abi<winrt::Microsoft::ReactNative::ICompositionHwndHost>::type *); // extra bytes to allocate
258
- wcex.hInstance = hInstance;
259
- wcex.hCursor = LoadCursor(nullptr, IDC_ARROW); // handle to class cursor
260
- wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1); // background color
261
- wcex.lpszClassName = c_modalWindowClassName; // specify resource name
262
- ATOM classId = RegisterClassEx(&wcex); // register new windows class
263
- WINRT_VERIFY(classId); // 0 = fail
264
- winrt::check_win32(!classId);
265
-
266
- registered = true;
267
- }
268
-
269
- winrt::Microsoft::ReactNative::Composition::Experimental::IVisual
270
- WindowsModalHostComponentView::VisualToMountChildrenInto() noexcept {
271
- return m_reactNativeIsland
272
- .as<winrt::Microsoft::ReactNative::Composition::Experimental::IInternalCompositionRootView>()
273
- .InternalRootVisual();
274
- }
198
+ void CloseWindow() noexcept {
199
+ // enable input to parent before closing the modal window, so focus can return back to the parent window
200
+ EnableWindow(m_parentHwnd, true);
275
201
 
276
- // childComponentView - reference to the child component view
277
- // index - the position in which the childComponentView should be mounted
278
- void WindowsModalHostComponentView::MountChildComponentView(
279
- const winrt::Microsoft::ReactNative::ComponentView &childComponentView,
280
- uint32_t index) noexcept {
281
- EnsureModalCreated();
282
- base_type::MountChildComponentView(childComponentView, index);
283
- }
202
+ if (m_window) {
203
+ m_window.Hide();
204
+ }
284
205
 
285
- void WindowsModalHostComponentView::UnmountChildComponentView(
286
- const winrt::Microsoft::ReactNative::ComponentView &childComponentView,
287
- uint32_t index) noexcept {
288
- base_type::UnmountChildComponentView(childComponentView, index);
289
- }
206
+ // dispatch onDismiss event
207
+ if (auto eventEmitter = EventEmitter()) {
208
+ ::Microsoft::ReactNativeSpecs::ModalHostViewEventEmitter::OnDismiss eventArgs;
209
+ eventEmitter->onDismiss(eventArgs);
210
+ }
290
211
 
291
- void WindowsModalHostComponentView::updateLayoutMetrics(
292
- facebook::react::LayoutMetrics const &layoutMetrics,
293
- facebook::react::LayoutMetrics const &oldLayoutMetrics) noexcept {
294
- base_type::updateLayoutMetrics(layoutMetrics, oldLayoutMetrics);
295
- if (m_hwnd) {
296
- EnsureModalCreated();
297
- AdjustWindowSize();
298
- ShowOnUIThread();
299
- }
300
- }
212
+ // reset the topWindowID
213
+ if (m_prevWindowID) {
214
+ winrt::Microsoft::ReactNative::ReactCoreInjection::SetTopLevelWindowId(
215
+ m_reactContext.Properties().Handle(), m_prevWindowID);
216
+ m_prevWindowID = 0;
217
+ }
301
218
 
302
- void WindowsModalHostComponentView::AdjustWindowSize() noexcept {
303
- if (m_layoutMetrics.overflowInset.right == 0 && m_layoutMetrics.overflowInset.bottom == 0) {
304
- return;
219
+ m_bridge.Disable();
305
220
  }
306
221
 
307
- // Modal's size is based on it's children, use the overflow to calculate the width/height
308
- float xPos = (-m_layoutMetrics.overflowInset.right * (m_layoutMetrics.pointScaleFactor));
309
- float yPos = (-m_layoutMetrics.overflowInset.bottom * (m_layoutMetrics.pointScaleFactor));
310
- RECT rc;
311
- GetClientRect(m_hwnd, &rc);
312
- RECT rect = {0, 0, (int)xPos, (int)yPos};
222
+ // creates a new modal window
223
+ void EnsureModalCreated(const winrt::Microsoft::ReactNative::ComponentView &view) {
224
+ if (m_window) {
225
+ return;
226
+ }
313
227
 
314
- if (m_showTitleBar) {
315
- AdjustWindowRect(&rect, WS_OVERLAPPEDWINDOW, FALSE); // Adjust for title bar and borders
316
- }
228
+ // get the root hwnd
229
+ m_prevWindowID =
230
+ winrt::Microsoft::ReactNative::ReactCoreInjection::GetTopLevelWindowId(view.ReactContext().Properties());
317
231
 
318
- // set the layoutMetrics
319
- m_layoutMetrics.frame.size = {(float)rect.right - rect.left, (float)rect.bottom - rect.top};
320
- m_layoutMetrics.overflowInset.right = 0;
321
- m_layoutMetrics.overflowInset.bottom = 0;
232
+ m_parentHwnd =
233
+ view.as<::Microsoft::ReactNative::Composition::Experimental::IComponentViewInterop>()->GetHwndForParenting();
322
234
 
323
- // get Modal's position based on parent
324
- RECT parentRC;
325
- GetWindowRect(m_parentHwnd, &parentRC);
326
- float xCor = (parentRC.left + parentRC.right - m_layoutMetrics.frame.size.width) / 2; // midpointx - width / 2
327
- float yCor = (parentRC.top + parentRC.bottom - m_layoutMetrics.frame.size.height) / 2; // midpointy - height / 2
235
+ auto portal = view.as<winrt::Microsoft::ReactNative::Composition::PortalComponentView>();
328
236
 
329
- // Adjust window position and size
330
- MoveWindow(m_hwnd, (int)xCor, (int)yCor, (int)(rect.right - rect.left), (int)(rect.bottom - rect.top), true);
237
+ #ifdef USE_EXPERIMENTAL_WINUI3
238
+ m_bridge = winrt::Microsoft::UI::Content::DesktopChildSiteBridge::Create(
239
+ view.Parent().as<winrt::Microsoft::ReactNative::Composition::ComponentView>().Compositor(),
240
+ winrt::Microsoft::UI::GetWindowIdFromWindow(m_parentHwnd));
241
+ m_reactNativeIsland = winrt::Microsoft::ReactNative::ReactNativeIsland::CreatePortal(portal);
242
+ auto contentIsland = m_reactNativeIsland.Island();
331
243
 
332
- // Let RNWIsland know that Modal's size has changed
333
- winrt::get_self<winrt::Microsoft::ReactNative::implementation::ReactNativeIsland>(m_reactNativeIsland)
334
- ->NotifySizeChanged();
335
- };
244
+ m_popUp = m_bridge.TryCreatePopupSiteBridge();
245
+ m_popUp.Connect(contentIsland);
336
246
 
337
- void WindowsModalHostComponentView::updateProps(
338
- facebook::react::Props::Shared const &props,
339
- facebook::react::Props::Shared const &oldProps) noexcept {
340
- const auto &oldModalProps =
341
- *std::static_pointer_cast<const facebook::react::ModalHostViewProps>(oldProps ? oldProps : viewProps());
342
- const auto &newModalProps = *std::static_pointer_cast<const facebook::react::ModalHostViewProps>(props);
343
- newModalProps.visible ? m_isVisible = true : m_isVisible = false;
344
- if (!m_isVisible) {
345
- HideOnUIThread();
247
+ // set the top-level windows as the new hwnd
248
+ winrt::Microsoft::ReactNative::ReactCoreInjection::SetTopLevelWindowId(
249
+ view.ReactContext().Properties(),
250
+ reinterpret_cast<uint64_t>(winrt::Microsoft::UI::GetWindowFromWindowId(m_popUp.WindowId())));
251
+
252
+ auto navHost = winrt::Microsoft::UI::Input::InputFocusNavigationHost::GetForSiteBridge(
253
+ m_popUp.as<winrt::Microsoft::UI::Content::IContentSiteBridge>());
254
+ m_departFocusToken = navHost.DepartFocusRequested(
255
+ [wkView = winrt::make_weak(view)](
256
+ const auto &sender, const winrt::Microsoft::UI::Input::FocusNavigationRequestEventArgs &args) {
257
+ if (auto strongView = wkView.get()) {
258
+ TrySetFocus(strongView.Parent());
259
+ }
260
+ });
261
+
262
+ #else
263
+ auto presenter = winrt::Microsoft::UI::Windowing::OverlappedPresenter::CreateForDialog();
264
+ presenter.SetBorderAndTitleBar(true, false);
265
+ presenter.IsModal(true);
266
+
267
+ m_window = winrt::Microsoft::UI::Windowing::AppWindow::Create(
268
+ presenter, winrt::Microsoft::UI::GetWindowIdFromWindow(m_parentHwnd));
269
+
270
+ // set the top-level windows as the new hwnd
271
+ winrt::Microsoft::ReactNative::ReactCoreInjection::SetTopLevelWindowId(
272
+ view.ReactContext().Properties(),
273
+ reinterpret_cast<uint64_t>(winrt::Microsoft::UI::GetWindowFromWindowId(m_window.Id())));
274
+
275
+ // create a react native island - code taken from CompositionHwndHost
276
+ m_bridge = winrt::Microsoft::UI::Content::DesktopChildSiteBridge::Create(
277
+ view.Parent().as<winrt::Microsoft::ReactNative::Composition::ComponentView>().Compositor(), m_window.Id());
278
+ m_reactNativeIsland = winrt::Microsoft::ReactNative::ReactNativeIsland::CreatePortal(portal);
279
+ auto contentIsland = m_reactNativeIsland.Island();
280
+
281
+ auto navHost = winrt::Microsoft::UI::Input::InputFocusNavigationHost::GetForSiteBridge(m_bridge);
282
+ m_departFocusToken = navHost.DepartFocusRequested(
283
+ [wkView = winrt::make_weak(view)](
284
+ const auto &sender, const winrt::Microsoft::UI::Input::FocusNavigationRequestEventArgs &args) {
285
+ if (auto strongView = wkView.get()) {
286
+ TrySetFocus(strongView.Parent());
287
+ }
288
+ });
289
+ m_bridge.Connect(contentIsland);
290
+
291
+ #endif
292
+
293
+ m_bridge.ResizePolicy(winrt::Microsoft::UI::Content::ContentSizePolicy::ResizeContentToParentWindow);
294
+
295
+ m_islandStateChangedToken =
296
+ contentIsland.StateChanged([weakThis = get_weak()](
297
+ winrt::Microsoft::UI::Content::ContentIsland const &island,
298
+ winrt::Microsoft::UI::Content::ContentIslandStateChangedEventArgs const &args) {
299
+ if (auto pThis = weakThis.get()) {
300
+ if (args.DidRasterizationScaleChange() || args.DidLayoutDirectionChange()) {
301
+ pThis->UpdateConstraints();
302
+ }
303
+ }
304
+ });
305
+
306
+ UpdateConstraints();
307
+
308
+ if (portal.ContentRoot().Children().Size()) {
309
+ AdjustWindowSize(portal.ContentRoot().Children().GetAt(0).LayoutMetrics());
310
+ }
311
+ m_bridge.Show();
346
312
  }
347
- base_type::updateProps(props, oldProps);
348
- }
349
313
 
350
- facebook::react::SharedViewProps WindowsModalHostComponentView::defaultProps() noexcept {
351
- static auto const defaultProps = std::make_shared<facebook::react::ModalHostViewProps const>();
352
- return defaultProps;
353
- }
354
- const facebook::react::ModalHostViewProps &WindowsModalHostComponentView::modalHostViewProps() const noexcept {
355
- return *std::static_pointer_cast<const facebook::react::ModalHostViewProps>(viewProps());
356
- }
357
-
358
- facebook::react::Tag WindowsModalHostComponentView::hitTest(
359
- facebook::react::Point pt,
360
- facebook::react::Point &localPt,
361
- bool ignorePointerEvents) const noexcept {
362
- facebook::react::Point ptLocal{pt.x - m_layoutMetrics.frame.origin.x, pt.y - m_layoutMetrics.frame.origin.y};
363
-
364
- if ((ignorePointerEvents || viewProps()->pointerEvents == facebook::react::PointerEventsMode::Auto ||
365
- viewProps()->pointerEvents == facebook::react::PointerEventsMode::BoxOnly) &&
366
- ptLocal.x >= 0 && ptLocal.x <= m_layoutMetrics.frame.size.width && ptLocal.y >= 0 &&
367
- ptLocal.y <= m_layoutMetrics.frame.size.height) {
368
- localPt = ptLocal;
369
- return Tag();
314
+ void UpdateConstraints() noexcept {
315
+ auto displayArea = winrt::Microsoft::UI::Windowing::DisplayArea::GetFromDisplayId(
316
+ m_bridge.SiteView().EnvironmentView().DisplayId());
317
+ auto workArea = displayArea.WorkArea();
318
+
319
+ float scale = m_reactNativeIsland.Island().RasterizationScale();
320
+
321
+ winrt::Microsoft::ReactNative::LayoutConstraints constraints;
322
+ constraints.MinimumSize = {0, 0};
323
+ // Constrain the size of the modal to 90% of the screen size
324
+ constraints.MaximumSize = {
325
+ static_cast<float>((workArea.Width / scale) * 0.9), static_cast<float>((workArea.Height / scale) * 0.9)};
326
+ constraints.LayoutDirection = winrt::Microsoft::ReactNative::LayoutDirection::Undefined;
327
+
328
+ auto layoutDirection = m_reactNativeIsland.Island().LayoutDirection();
329
+ if (layoutDirection == winrt::Microsoft::UI::Content::ContentLayoutDirection::LeftToRight)
330
+ constraints.LayoutDirection = winrt::Microsoft::ReactNative::LayoutDirection::LeftToRight;
331
+ else if (layoutDirection == winrt::Microsoft::UI::Content::ContentLayoutDirection::RightToLeft)
332
+ constraints.LayoutDirection = winrt::Microsoft::ReactNative::LayoutDirection::RightToLeft;
333
+
334
+ // By setting a custom contraint here the behavior of the modal slightly changes.
335
+ // When no constraint is set (maxSize is std::numeric_limits<Float>::infinity()), yoga will layout the content to a
336
+ // desired size If we provide a specific max size, then contents with a flex:1 will expand to fill that size. We
337
+ // might want to provide a windows specific property to control this behavior.
338
+ m_state.UpdateState(winrt::make<ModalHostState>(constraints, m_reactNativeIsland.Island().RasterizationScale()));
370
339
  }
371
340
 
372
- return -1;
373
- }
341
+ static void TrySetFocus(const winrt::Microsoft::ReactNative::ComponentView &view) {
342
+ auto focusController = winrt::Microsoft::UI::Input::InputFocusController::GetForIsland(
343
+ view.as<winrt::Microsoft::ReactNative::Composition::ComponentView>().Root().ReactNativeIsland().Island());
344
+ focusController.TrySetFocus();
345
+ }
374
346
 
375
- bool WindowsModalHostComponentView::focusable() const noexcept {
376
- return false;
377
- }
347
+ ReactContext m_reactContext{nullptr};
348
+ HWND m_parentHwnd{nullptr};
349
+ winrt::Microsoft::UI::Windowing::AppWindow m_window{nullptr};
350
+ uint64_t m_prevWindowID;
351
+ bool m_showTitleBar{false};
352
+ bool m_showQueued{false};
353
+ bool m_mounted{false};
354
+ winrt::event_token m_islandStateChangedToken;
355
+ winrt::Microsoft::UI::Input::InputFocusNavigationHost::DepartFocusRequested_revoker m_departFocusRevoker;
356
+ winrt::event_token m_departFocusToken;
357
+ winrt::event_token m_childLayoutMetricsToken;
358
+ winrt::Microsoft::ReactNative::IComponentState m_state{nullptr};
359
+ winrt::Microsoft::UI::Content::DesktopChildSiteBridge m_bridge{nullptr};
360
+ winrt::Microsoft::ReactNative::ReactNativeIsland m_reactNativeIsland{nullptr};
361
+ };
378
362
 
379
- std::string WindowsModalHostComponentView::DefaultControlType() const noexcept {
380
- return "modal";
363
+ void RegisterWindowsModalHostNativeComponent(
364
+ winrt::Microsoft::ReactNative::IReactPackageBuilder const &packageBuilder) noexcept {
365
+ ::Microsoft::ReactNativeSpecs::RegisterModalHostViewNativeComponent<ModalHostView>(
366
+ packageBuilder,
367
+ [](const winrt::Microsoft::ReactNative::Composition::IReactCompositionViewComponentBuilder &builder) {
368
+ builder.SetPortalComponentViewInitializer(
369
+ [](const winrt::Microsoft::ReactNative::Composition::PortalComponentView &portalComponentView) noexcept {
370
+ auto userData = winrt::make_self<ModalHostView>();
371
+ userData->InitializePortalViewComponent(portalComponentView);
372
+ portalComponentView.UserData(*userData);
373
+ });
374
+ });
381
375
  }
382
376
 
383
377
  } // namespace winrt::Microsoft::ReactNative::Composition::implementation