Skip to content

Draft: Implement Modal having a titlebar and moveable #14598

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 3 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,23 @@ struct ModalHostView : public winrt::implements<ModalHostView, winrt::Windows::F
const winrt::Microsoft::ReactNative::ComponentView &view,
const winrt::com_ptr<::Microsoft::ReactNativeSpecs::ModalHostViewProps> &newProps,
const winrt::com_ptr<::Microsoft::ReactNativeSpecs::ModalHostViewProps> &oldProps) noexcept override {
// Set title from props if available, otherwise use default
if (newProps && newProps->title.has_value()) {
m_pendingTitle = newProps->title.value();
OutputDebugString(
(L"UpdateProps: Setting title from props: '" + winrt::to_hstring(m_pendingTitle) + L"'.\n").c_str());
} else {
m_pendingTitle = "Modal Title Default"; // Fallback title
OutputDebugString(L"UpdateProps: Using default title 'Modal Title'.\n");
}

m_showTitleBar = true;

// Debug log for m_window
if (!oldProps || newProps->visible != oldProps->visible) {
OutputDebugString(L"UpdateProps: visible prop has changed.\n");
}

if (!oldProps || newProps->visible != oldProps->visible) {
if (newProps->visible.value_or(true)) {
m_visible = true;
Expand All @@ -79,6 +96,21 @@ struct ModalHostView : public winrt::implements<ModalHostView, winrt::Windows::F
CloseWindow();
}
}

std::wostringstream debugStream;
debugStream << L"m_window is " << (m_window ? L"initialized" : L"null") << L"\n";
OutputDebugString(debugStream.str().c_str());

// Apply title immediately if window exists
if (m_window) {
try {
m_window.Title(winrt::to_hstring(m_pendingTitle));
OutputDebugString(L"Applied title to window immediately in UpdateProps.\n");
} catch (...) {
OutputDebugString(L"Failed to apply title to window in UpdateProps.\n");
}
}

::Microsoft::ReactNativeSpecs::BaseModalHostView<ModalHostView>::UpdateProps(view, newProps, oldProps);
}

Expand Down Expand Up @@ -184,6 +216,21 @@ struct ModalHostView : public winrt::implements<ModalHostView, winrt::Windows::F
winrt::Microsoft::UI::Input::FocusNavigationReason::First));
*/

if (m_window) {
try {
// Use the title that was set from props
m_window.Title(winrt::to_hstring(m_pendingTitle));
OutputDebugString(L"EnsureModalCreated: Applied pending title to window.\n");

// Also set border and title bar explicitly
auto presenter = m_window.Presenter().as<winrt::Microsoft::UI::Windowing::OverlappedPresenter>();
presenter.SetBorderAndTitleBar(true, true);
OutputDebugString(L"EnsureModalCreated: Set border and title bar explicitly.\n");
} catch (...) {
OutputDebugString(L"EnsureModalCreated: Failed to apply title to window.\n");
}
}

// dispatch onShow event
if (auto eventEmitter = EventEmitter()) {
::Microsoft::ReactNativeSpecs::ModalHostViewEventEmitter::OnShow eventArgs;
Expand Down Expand Up @@ -215,6 +262,13 @@ struct ModalHostView : public winrt::implements<ModalHostView, winrt::Windows::F

// creates a new modal window
void EnsureModalCreated(const winrt::Microsoft::ReactNative::ComponentView &view) {
if (m_window) {
OutputDebugString(L"EnsureModalCreated: m_window already initialized.\n");
return;
}
OutputDebugString(L"EnsureModalCreated: Attempting to create m_window.\n");

#ifdef USE_EXPERIMENTAL_WINUI3
if (m_popUp) {
return;
}
Expand Down Expand Up @@ -255,8 +309,61 @@ struct ModalHostView : public winrt::implements<ModalHostView, winrt::Windows::F
TrySetFocus(strongView.Parent());
}
});


#else
auto presenter = winrt::Microsoft::UI::Windowing::OverlappedPresenter::CreateForDialog();
presenter.SetBorderAndTitleBar(true, true);
presenter.IsModal(true);
presenter.IsResizable(true);

m_window = winrt::Microsoft::UI::Windowing::AppWindow::Create(
presenter, winrt::Microsoft::UI::GetWindowIdFromWindow(m_parentHwnd));

// set the top-level windows as the new hwnd
winrt::Microsoft::ReactNative::ReactCoreInjection::SetTopLevelWindowId(
view.ReactContext().Properties(),
reinterpret_cast<uint64_t>(winrt::Microsoft::UI::GetWindowFromWindowId(m_window.Id())));

// create a react native island - code taken from CompositionHwndHost
m_bridge = winrt::Microsoft::UI::Content::DesktopChildSiteBridge::Create(
view.Parent().as<winrt::Microsoft::ReactNative::Composition::ComponentView>().Compositor(), m_window.Id());
m_reactNativeIsland = winrt::Microsoft::ReactNative::ReactNativeIsland::CreatePortal(portal);
auto contentIsland = m_reactNativeIsland.Island();

auto navHost = winrt::Microsoft::UI::Input::InputFocusNavigationHost::GetForSiteBridge(m_bridge);
m_departFocusToken = navHost.DepartFocusRequested(
[wkView = winrt::make_weak(view)](
const auto &sender, const winrt::Microsoft::UI::Input::FocusNavigationRequestEventArgs &args) {
if (auto strongView = wkView.get()) {
TrySetFocus(strongView.Parent());
}
});
m_bridge.Connect(contentIsland);

if (m_window) {
try {
// Force a title even if m_pendingTitle is empty
std::string titleToApply = m_pendingTitle.empty() ? "Modal Title" : m_pendingTitle;
m_window.Title(winrt::to_hstring(titleToApply));
OutputDebugString(L"EnsureModalCreated: Applied pending title to window.\n");

// Also set border and title bar explicitly
auto presenter = m_window.Presenter().as<winrt::Microsoft::UI::Windowing::OverlappedPresenter>();
presenter.SetBorderAndTitleBar(true, true);
OutputDebugString(L"EnsureModalCreated: Set border and title bar explicitly.\n");
} catch (...) {
OutputDebugString(L"EnsureModalCreated: Failed to apply title to window.\n");
}
}

#endif

m_bridge.ResizePolicy(winrt::Microsoft::UI::Content::ContentSizePolicy::ResizeContentToParentWindow);
=======
*/


m_islandStateChangedToken =
contentIsland.StateChanged([weakThis = get_weak()](
winrt::Microsoft::UI::Content::ContentIsland const &island,
Expand All @@ -273,6 +380,15 @@ struct ModalHostView : public winrt::implements<ModalHostView, winrt::Windows::F
if (portal.ContentRoot().Children().Size()) {
AdjustWindowSize(portal.ContentRoot().Children().GetAt(0).LayoutMetrics());
}

m_bridge.Show();

if (m_window) {
OutputDebugString(L"EnsureModalCreated: m_window successfully created.\n");
} else {
OutputDebugString(L"EnsureModalCreated: Failed to create m_window.\n");
}

}

void UpdateConstraints() noexcept {
Expand Down Expand Up @@ -314,6 +430,7 @@ struct ModalHostView : public winrt::implements<ModalHostView, winrt::Windows::F
bool m_showQueued{false};
bool m_visible{false};
bool m_mounted{false};
std::string m_pendingTitle;
winrt::event_token m_islandStateChangedToken;
winrt::Microsoft::UI::Input::InputFocusNavigationHost::DepartFocusRequested_revoker m_departFocusRevoker;
winrt::event_token m_departFocusToken;
Expand Down
11 changes: 11 additions & 0 deletions vnext/src-win/Libraries/Modal/Modal.windows.js
Original file line number Diff line number Diff line change
Expand Up @@ -174,6 +174,11 @@ export type Props = $ReadOnly<{|
* Defaults to `white` if not provided and transparent is `false`. Ignored if `transparent` is `true`.
*/
backdropColor?: ?string,

/*
title for modal , windows only
*/
title?: ?string,
|}>;

function confirmProps(props: Props) {
Expand Down Expand Up @@ -269,6 +274,11 @@ class Modal extends React.Component<Props, State> {
}

render(): React.Node {
// Add this near the beginning of the render method
if (__DEV__ && this.props.title) {
console.log('Modal: title prop is being passed:', this.props.title);
}

if (!this._shouldShowModal()) {
return null;
}
Expand Down Expand Up @@ -325,6 +335,7 @@ class Modal extends React.Component<Props, State> {
navigationBarTranslucent={this.props.navigationBarTranslucent}
identifier={this._identifier}
style={styles.modal}
title={this.props.title}
// $FlowFixMe[method-unbinding] added when improving typing for this parameters
onStartShouldSetResponder={this._shouldSetResponder}
supportedOrientations={this.props.supportedOrientations}
Expand Down
Loading