@@ -39,6 +39,12 @@ struct ModalHostView : public winrt::implements<ModalHostView, winrt::Windows::F
39
39
m_reactNativeIsland.Island ().Close ();
40
40
}
41
41
42
+ // Add AppWindow closing token cleanup
43
+ if (m_appWindow && m_appWindowClosingToken) {
44
+ m_appWindow.Closing (m_appWindowClosingToken);
45
+ m_appWindowClosingToken.value = 0 ;
46
+ }
47
+
42
48
if (m_popUp) {
43
49
if (m_departFocusToken && !m_popUp.IsClosed ()) {
44
50
// WASDK BUG: InputFocusNavigationHost::GetForSiteBridge fails on a DesktopPopupSiteBridge
@@ -68,7 +74,13 @@ struct ModalHostView : public winrt::implements<ModalHostView, winrt::Windows::F
68
74
const winrt::Microsoft::ReactNative::ComponentView &view,
69
75
const winrt::com_ptr<::Microsoft::ReactNativeSpecs::ModalHostViewProps> &newProps,
70
76
const winrt::com_ptr<::Microsoft::ReactNativeSpecs::ModalHostViewProps> &oldProps) noexcept override {
71
- if (!oldProps || newProps->visible != oldProps->visible ) {
77
+ // Store the props locally
78
+ m_localProps = newProps;
79
+
80
+ const auto &oldViewProps = *oldProps;
81
+ const auto &newViewProps = *newProps;
82
+
83
+ if (!oldProps || newViewProps.visible != oldViewProps.visible ) {
72
84
if (newProps->visible .value_or (true )) {
73
85
m_visible = true ;
74
86
// We do not immediately show the window, since we want to resize/position
@@ -79,6 +91,15 @@ struct ModalHostView : public winrt::implements<ModalHostView, winrt::Windows::F
79
91
CloseWindow ();
80
92
}
81
93
}
94
+
95
+ // Update Title if changed and AppWindow exists
96
+ if (m_appWindow && (!oldProps || newViewProps.title != oldViewProps.title )) {
97
+ // Use empty string if title is not set
98
+ winrt::hstring titleValue =
99
+ newViewProps.title .has_value () ? winrt::to_hstring (newViewProps.title .value ()) : winrt::hstring ();
100
+ m_appWindow.Title (titleValue);
101
+ }
102
+
82
103
::Microsoft::ReactNativeSpecs::BaseModalHostView<ModalHostView>::UpdateProps (view, newProps, oldProps);
83
104
}
84
105
@@ -142,28 +163,34 @@ struct ModalHostView : public winrt::implements<ModalHostView, winrt::Windows::F
142
163
}
143
164
144
165
void AdjustWindowSize (const winrt::Microsoft::ReactNative::LayoutMetrics &layoutMetrics) noexcept {
145
- if (!m_popUp ) {
166
+ if (!m_appWindow ) {
146
167
return ;
147
168
}
148
169
149
170
if (layoutMetrics.Frame .Width == 0 && layoutMetrics.Frame .Height == 0 ) {
150
171
return ;
151
172
}
152
173
153
- // get Modal's position based on parent
174
+ // Calculate physical pixels from DIPs
175
+ int32_t clientWidthPx = static_cast <int32_t >(layoutMetrics.Frame .Width * layoutMetrics.PointScaleFactor );
176
+ int32_t clientHeightPx = static_cast <int32_t >(layoutMetrics.Frame .Height * layoutMetrics.PointScaleFactor );
177
+
178
+ // Ensure minimum size for the window
179
+ clientWidthPx = std::max (100 , clientWidthPx);
180
+ clientHeightPx = std::max (100 , clientHeightPx);
181
+
182
+ // Size the client area directly
183
+ m_appWindow.ResizeClient ({clientWidthPx, clientHeightPx});
184
+
185
+ // Center the window on its parent
154
186
RECT parentRC;
155
187
GetWindowRect (m_parentHwnd, &parentRC);
156
- int32_t xCor = static_cast <int32_t >(
157
- (parentRC.left + parentRC.right - layoutMetrics.Frame .Width * layoutMetrics.PointScaleFactor ) / 2 );
158
- int32_t yCor = static_cast <int32_t >(
159
- (parentRC.top + parentRC.bottom - layoutMetrics.Frame .Height * layoutMetrics.PointScaleFactor ) / 2 );
160
-
161
- winrt::Windows::Graphics::RectInt32 rect2{
162
- (int )xCor,
163
- (int )yCor,
164
- static_cast <int32_t >(layoutMetrics.Frame .Width * (layoutMetrics.PointScaleFactor )),
165
- static_cast <int32_t >(layoutMetrics.Frame .Height * (layoutMetrics.PointScaleFactor ))};
166
- m_popUp.MoveAndResize (rect2);
188
+ auto outerSize = m_appWindow.Size ();
189
+
190
+ int32_t xCor = parentRC.left + (parentRC.right - parentRC.left - outerSize.Width ) / 2 ;
191
+ int32_t yCor = parentRC.top + (parentRC.bottom - parentRC.top - outerSize.Height ) / 2 ;
192
+
193
+ m_appWindow.Move ({xCor, yCor});
167
194
};
168
195
169
196
void ShowOnUIThread (const winrt::Microsoft::ReactNative::ComponentView &view) {
@@ -199,6 +226,12 @@ struct ModalHostView : public winrt::implements<ModalHostView, winrt::Windows::F
199
226
m_popUp.Hide ();
200
227
}
201
228
229
+ // Unregister closing event handler
230
+ if (m_appWindow && m_appWindowClosingToken) {
231
+ m_appWindow.Closing (m_appWindowClosingToken);
232
+ m_appWindowClosingToken.value = 0 ;
233
+ }
234
+
202
235
// dispatch onDismiss event
203
236
if (auto eventEmitter = EventEmitter ()) {
204
237
::Microsoft::ReactNativeSpecs::ModalHostViewEventEmitter::OnDismiss eventArgs;
@@ -237,6 +270,42 @@ struct ModalHostView : public winrt::implements<ModalHostView, winrt::Windows::F
237
270
.Island ());
238
271
m_popUp.Connect (contentIsland);
239
272
273
+ // Get AppWindow and configure presenter
274
+ m_appWindow = winrt::Microsoft::UI::Windowing::AppWindow::GetFromWindowId (m_popUp.WindowId ());
275
+ if (m_appWindow) {
276
+ auto overlappedPresenter = winrt::Microsoft::UI::Windowing::OverlappedPresenter::Create ();
277
+
278
+ // Configure presenter for modal behavior
279
+ overlappedPresenter.IsModal (true );
280
+ overlappedPresenter.SetBorderAndTitleBar (true , true );
281
+
282
+ // Apply the presenter to the window
283
+ m_appWindow.SetPresenter (overlappedPresenter);
284
+
285
+ // Set initial title using the stored local props
286
+ if (m_localProps && m_localProps->title .has_value ()) {
287
+ winrt::hstring titleValue = winrt::to_hstring (m_localProps->title .value ());
288
+ m_appWindow.Title (titleValue);
289
+ } else {
290
+ m_appWindow.Title (L" " ); // Empty title if not provided
291
+ }
292
+
293
+ // Handle close request ('X' button)
294
+ m_appWindowClosingToken =
295
+ m_appWindow.Closing ([wkThis = get_weak ()](
296
+ const winrt::Microsoft::UI::Windowing::AppWindow & /* sender*/ ,
297
+ const winrt::Microsoft::UI::Windowing::AppWindowClosingEventArgs &args) {
298
+ args.Cancel (true ); // Prevent default close
299
+ if (auto strongThis = wkThis.get ()) {
300
+ // Dispatch onRequestClose event
301
+ if (auto eventEmitter = strongThis->EventEmitter ()) {
302
+ ::Microsoft::ReactNativeSpecs::ModalHostViewEventEmitter::OnRequestClose eventArgs;
303
+ eventEmitter->onRequestClose (eventArgs);
304
+ }
305
+ }
306
+ });
307
+ }
308
+
240
309
// set the top-level windows as the new hwnd
241
310
winrt::Microsoft::ReactNative::ReactCoreInjection::SetTopLevelWindowId (
242
311
view.ReactContext ().Properties (),
@@ -320,6 +389,9 @@ struct ModalHostView : public winrt::implements<ModalHostView, winrt::Windows::F
320
389
winrt::Microsoft::ReactNative::IComponentState m_state{nullptr };
321
390
winrt::Microsoft::ReactNative::ReactNativeIsland m_reactNativeIsland{nullptr };
322
391
winrt::Microsoft::UI::Content::DesktopPopupSiteBridge m_popUp{nullptr };
392
+ winrt::Microsoft::UI::Windowing::AppWindow m_appWindow{nullptr };
393
+ winrt::event_token m_appWindowClosingToken;
394
+ winrt::com_ptr<::Microsoft::ReactNativeSpecs::ModalHostViewProps> m_localProps{nullptr };
323
395
};
324
396
325
397
void RegisterWindowsModalHostNativeComponent (
0 commit comments