From 9e621166eda8998edbb2e710908a67903486cb77 Mon Sep 17 00:00:00 2001 From: xiaoy312 Date: Mon, 25 Nov 2024 20:01:36 -0500 Subject: [PATCH] fix(wasm): unwanted preview shown when dragging over existing selection --- src/Uno.UI/Extensions/UIElementExtensions.wasm.cs | 14 +++++++++++++- .../UI/Xaml/Controls/Primitives/Thumb.mux.cs | 5 +++++ src/Uno.UI/UI/Xaml/Controls/ScrollBar/ScrollBar.cs | 5 +++++ src/Uno.UI/UI/Xaml/Controls/Slider/Slider.mux.cs | 5 +++++ .../DragDrop/DragDropExtension.Interop.wasm.cs | 11 ++++++++--- .../DataTransfer/DragAndDropExtension.ts | 10 ++++++++++ 6 files changed, 46 insertions(+), 4 deletions(-) diff --git a/src/Uno.UI/Extensions/UIElementExtensions.wasm.cs b/src/Uno.UI/Extensions/UIElementExtensions.wasm.cs index dced66e647ca..48be84a1ac9f 100644 --- a/src/Uno.UI/Extensions/UIElementExtensions.wasm.cs +++ b/src/Uno.UI/Extensions/UIElementExtensions.wasm.cs @@ -1,4 +1,6 @@ -using Microsoft.UI.Xaml; +using System.Globalization; +using Microsoft.UI.Xaml; +using __Windows.ApplicationModel.DataTransfer.DragDrop.Core; namespace Uno.UI.Extensions { @@ -25,5 +27,15 @@ internal static FrameworkElement GetTopLevelParent(this UIElement view) return current; } + + /// + /// Block native 'dragstart' with preventDefault(). + /// + /// + /// This is used to prevent default browser drag-preview when dragging from this control with existing selection. + public static void PreventNativeDragStart(this UIElement uie) + { + DragDropExtension.NativeMethods.PreventDragStart(uie.HtmlId.ToString(CultureInfo.InvariantCulture)); + } } } diff --git a/src/Uno.UI/UI/Xaml/Controls/Primitives/Thumb.mux.cs b/src/Uno.UI/UI/Xaml/Controls/Primitives/Thumb.mux.cs index ec525a1d01ab..3a14c889b3c0 100644 --- a/src/Uno.UI/UI/Xaml/Controls/Primitives/Thumb.mux.cs +++ b/src/Uno.UI/UI/Xaml/Controls/Primitives/Thumb.mux.cs @@ -9,6 +9,7 @@ using Microsoft.UI.Xaml.Input; using Microsoft.UI.Xaml.Media; using Uno.UI.Xaml.Core; +using Uno.UI.Extensions; namespace Microsoft.UI.Xaml.Controls.Primitives; @@ -36,6 +37,10 @@ public Thumb() // TODO Uno specific: DefaultStyleKey = typeof(Thumb); +#if HAS_UNO && __WASM__ + this.PreventNativeDragStart(); // see remarks +#endif + IgnoreTouchInput = false; m_origin = Point.Zero; m_previousPosition = Point.Zero; diff --git a/src/Uno.UI/UI/Xaml/Controls/ScrollBar/ScrollBar.cs b/src/Uno.UI/UI/Xaml/Controls/ScrollBar/ScrollBar.cs index 530ec7dda4bb..1e76c0cffb56 100644 --- a/src/Uno.UI/UI/Xaml/Controls/ScrollBar/ScrollBar.cs +++ b/src/Uno.UI/UI/Xaml/Controls/ScrollBar/ScrollBar.cs @@ -8,6 +8,7 @@ using Microsoft.UI.Xaml.Controls.Primitives; using Microsoft.UI.Xaml.Input; using DirectUI; +using Uno.UI.Extensions; #if HAS_UNO_WINUI @@ -132,6 +133,10 @@ void Initialize() { DefaultStyleKey = typeof(ScrollBar); +#if HAS_UNO && __WASM__ + this.PreventNativeDragStart(); // see remarks +#endif + SizeChanged += OnSizeChanged; #if !UNO_HAS_ENHANCED_LIFECYCLE LayoutUpdated += OnLayoutUpdated; diff --git a/src/Uno.UI/UI/Xaml/Controls/Slider/Slider.mux.cs b/src/Uno.UI/UI/Xaml/Controls/Slider/Slider.mux.cs index 7119dbc3ccc2..e30076f451ad 100644 --- a/src/Uno.UI/UI/Xaml/Controls/Slider/Slider.mux.cs +++ b/src/Uno.UI/UI/Xaml/Controls/Slider/Slider.mux.cs @@ -21,6 +21,7 @@ using Microsoft.UI.Xaml.Shapes; using static Microsoft/* UWP don't rename */.UI.Xaml.Controls._Tracing; using Uno.UI.Xaml.Core.Scaling; +using Uno.UI.Extensions; namespace Microsoft.UI.Xaml.Controls; @@ -48,6 +49,10 @@ public Slider() PrepareState(); #if HAS_UNO +#if __WASM__ + this.PreventNativeDragStart(); // see remarks +#endif + // Uno specific: Detach and reattach template child events. // Needed to avoid memory leaks on iOS. Loaded += Slider_Loaded; diff --git a/src/Uno.UI/UI/Xaml/DragDrop/DragDropExtension.Interop.wasm.cs b/src/Uno.UI/UI/Xaml/DragDrop/DragDropExtension.Interop.wasm.cs index 70bb473e47c8..4e05b01ca9b5 100644 --- a/src/Uno.UI/UI/Xaml/DragDrop/DragDropExtension.Interop.wasm.cs +++ b/src/Uno.UI/UI/Xaml/DragDrop/DragDropExtension.Interop.wasm.cs @@ -7,14 +7,19 @@ internal partial class DragDropExtension { internal static partial class NativeMethods { - [JSImport("globalThis.Windows.ApplicationModel.DataTransfer.DragDrop.Core.DragDropExtension.registerNoOp")] + private const string JsType = "globalThis.Windows.ApplicationModel.DataTransfer.DragDrop.Core.DragDropExtension"; + + [JSImport($"{JsType}.registerNoOp")] internal static partial void RegisterNoOp(); - [JSImport("globalThis.Windows.ApplicationModel.DataTransfer.DragDrop.Core.DragDropExtension.retrieveFiles")] + [JSImport($"{JsType}.retrieveFiles")] internal static partial Task RetrieveFilesAsync(int[] itemIds); - [JSImport("globalThis.Windows.ApplicationModel.DataTransfer.DragDrop.Core.DragDropExtension.retrieveText")] + [JSImport($"{JsType}.retrieveText")] internal static partial Task RetrieveTextAsync(int itemId); + + [JSImport($"{JsType}.preventDragStart")] + internal static partial void PreventDragStart(string htmlId); } } } diff --git a/src/Uno.UI/ts/Windows/ApplicationModel/DataTransfer/DragAndDropExtension.ts b/src/Uno.UI/ts/Windows/ApplicationModel/DataTransfer/DragAndDropExtension.ts index 422217207683..bd68953fac4d 100644 --- a/src/Uno.UI/ts/Windows/ApplicationModel/DataTransfer/DragAndDropExtension.ts +++ b/src/Uno.UI/ts/Windows/ApplicationModel/DataTransfer/DragAndDropExtension.ts @@ -41,6 +41,16 @@ DragDropExtension._dispatchDragDropArgs = null; } + public static preventDragStart(htmlId: string): void { + const element = document.getElementById(htmlId); + if (element != null) { + // #18854: Prevent the browser default selection drag preview. + // Typically used for controls that uses press - and - hold - drag gesture(pointer based), + // like Thumb, Slider, ScrollBar, where the drag-preview should not occur. + element.addEventListener('dragstart', e => e.preventDefault()); + } + } + constructor() { // Events fired on the drop target // Note: dragenter and dragover events will enable drop on the app