diff --git a/src/Uno.UI.RuntimeTests/Tests/Windows_UI_Xaml_Controls/Given_TextBox.cs b/src/Uno.UI.RuntimeTests/Tests/Windows_UI_Xaml_Controls/Given_TextBox.cs index a25f8b786c71..a34dd21378a8 100644 --- a/src/Uno.UI.RuntimeTests/Tests/Windows_UI_Xaml_Controls/Given_TextBox.cs +++ b/src/Uno.UI.RuntimeTests/Tests/Windows_UI_Xaml_Controls/Given_TextBox.cs @@ -28,6 +28,7 @@ using Windows.UI.Input.Preview.Injection; using Windows.Foundation; using System.Collections.Generic; +using Uno.Extensions; #if WINAPPSDK @@ -1124,6 +1125,44 @@ static FrameworkElement GetSCP(TextBox tb) } #endif +#if HAS_UNO + [TestMethod] + [UnoWorkItem("https://github.com/unoplatform/uno/issues/18790")] +#if !HAS_INPUT_INJECTOR + [Ignore("InputInjector is not supported on this platform.")] +#endif + public async Task When_Clicked_In_Popup() + { + TextBox tb; + var btn = new Button + { + Flyout = new Flyout + { + Content = tb = new TextBox() + } + }; + + await UITestHelper.Load(btn); + + var injector = InputInjector.TryCreate() ?? throw new InvalidOperationException("Failed to init the InputInjector"); + using var mouse = injector.GetMouse(); + + mouse.Press(btn.GetAbsoluteBoundsRect().GetCenter()); + await UITestHelper.WaitForIdle(); + mouse.Release(); + await UITestHelper.WaitForIdle(); + + Assert.IsTrue(btn.Flyout.IsOpen); + + mouse.Press(tb.GetAbsoluteBoundsRect().GetCenter()); + await UITestHelper.WaitForIdle(); + mouse.Release(); + await UITestHelper.WaitForIdle(); + + Assert.AreEqual(tb, FocusManager.GetFocusedElement(WindowHelper.XamlRoot)); + } +#endif + private static async Task LoadZeroSizeTextBoxAsync(Style style) { var loaded = false; diff --git a/src/Uno.UI/UI/Xaml/Controls/ScrollViewer/ScrollViewer.MuxInternal.cs b/src/Uno.UI/UI/Xaml/Controls/ScrollViewer/ScrollViewer.MuxInternal.cs index da055cd0aa8a..f46d339ba603 100644 --- a/src/Uno.UI/UI/Xaml/Controls/ScrollViewer/ScrollViewer.MuxInternal.cs +++ b/src/Uno.UI/UI/Xaml/Controls/ScrollViewer/ScrollViewer.MuxInternal.cs @@ -179,6 +179,13 @@ protected override void OnPointerReleased(PointerRoutedEventArgs args) private static bool ScrollContentControl_SetFocusOnFlyoutLightDismissPopupByPointer(UIElement pScrollContentControl) { +#if __WASM__ + if ((pScrollContentControl as ScrollViewer)?.DisableSetFocusOnPopupByPointer ?? false) + { + return false; + } +#endif + PopupRoot? pPopupRoot = null; Popup? pPopup = null; diff --git a/src/Uno.UI/UI/Xaml/Controls/ScrollViewer/ScrollViewer.wasm.cs b/src/Uno.UI/UI/Xaml/Controls/ScrollViewer/ScrollViewer.wasm.cs index e709cb5ac605..185369d583cd 100644 --- a/src/Uno.UI/UI/Xaml/Controls/ScrollViewer/ScrollViewer.wasm.cs +++ b/src/Uno.UI/UI/Xaml/Controls/ScrollViewer/ScrollViewer.wasm.cs @@ -11,6 +11,15 @@ namespace Microsoft.UI.Xaml.Controls { partial class ScrollViewer { + /// + /// This is specifically added for ScrollViewers inside TextBoxes and specifically for WASM + /// On WASM, a click on a TextBox inside a popup shifts focus to the Popup instead of the TextBox + /// as a result of ScrollContentControl_SetFocusOnFlyoutLightDismissPopupByPointer. + /// This is only a problem on WASM because we don't capture the pointer when pressing inside a TextBox + /// . + /// + internal bool DisableSetFocusOnPopupByPointer { get; set; } + internal bool CancelNextNativeScroll { get; private set; } internal Size ScrollBarSize => (_presenter as ScrollContentPresenter)?.ScrollBarSize ?? default; diff --git a/src/Uno.UI/UI/Xaml/Controls/TextBox/TextBox.Uno.cs b/src/Uno.UI/UI/Xaml/Controls/TextBox/TextBox.Uno.cs index f2d61ea1b0f1..d4ae5cc37679 100644 --- a/src/Uno.UI/UI/Xaml/Controls/TextBox/TextBox.Uno.cs +++ b/src/Uno.UI/UI/Xaml/Controls/TextBox/TextBox.Uno.cs @@ -28,6 +28,16 @@ public bool IsPointerCaptureRequired new FrameworkPropertyMetadata( // We should not capture the pointer on WASM by default because it would prevent the user from scrolling through text on selection. // See https://github.com/unoplatform/uno/pull/16982, https://issues.chromium.org/issues/344491566 - false)); + false +#if __WASM__ + , static (dO, args) => + { + if (((TextBox)dO)._contentElement is ScrollViewer sv) + { + sv.DisableSetFocusOnPopupByPointer = !(bool)args.NewValue; + } + } +#endif + )); #endif } diff --git a/src/Uno.UI/UI/Xaml/Controls/TextBox/TextBox.cs b/src/Uno.UI/UI/Xaml/Controls/TextBox/TextBox.cs index a9b8d293542e..4a75b90b7dec 100644 --- a/src/Uno.UI/UI/Xaml/Controls/TextBox/TextBox.cs +++ b/src/Uno.UI/UI/Xaml/Controls/TextBox/TextBox.cs @@ -169,6 +169,10 @@ private protected override void OnLoaded() scrollViewer.HorizontalScrollBarVisibility = ScrollBarVisibility.Disabled; // The template sets this to Hidden scrollViewer.VerticalScrollBarVisibility = ScrollBarVisibility.Auto; // The template sets this to Hidden } + +#if __WASM__ + scrollViewer.DisableSetFocusOnPopupByPointer = !IsPointerCaptureRequired; +#endif #endif } }