UI/DragDrop/DragHandler.razor

A UI Razor component that shows a drag visual while dragging UI items. It stores current DragData statically, renders an icon or title, updates position each frame, and exposes StartDragging/StopDragging methods.

File Access
@using Sandbox;
@using Sandbox.UI;
@inherits PanelComponent
@namespace Sandbox

<root>

	@if ( Current is not null )
	{
		var iconStyle = string.IsNullOrEmpty( Current.Icon ) ? "" : $"background-image: url({Current.Icon})";
		<div class="dragging" style="@iconStyle" @ref="DragVisual">
			@if ( string.IsNullOrEmpty( Current.Icon ) )
			{
				<div class="drag-title">@Current.Title</div>
			}
		</div>
	}

</root>

@code
{
    public static DragHandler Instance { get; private set; }

    /// <summary>
    /// The data currently being dragged, or null.
    /// </summary>
    public static DragData Current { get; private set; }

    /// <summary>
    /// True if something is actively being dragged.
    /// </summary>
    public static bool IsDragging => Current is not null;

    Panel DragVisual { get; set; }

    protected override void OnStart()
    {
        Instance = this;
    }

    protected override void OnDestroy()
    {
        if ( Instance == this )
            Instance = null;
    }

    /// <summary>
    /// Start dragging with the given data.
    /// </summary>
    public static void StartDragging( DragData data )
    {
        Current = data;
        data.Source.UserData = data;

        Instance?.StateHasChanged();
    }

    /// <summary>
    /// Stop dragging and clear all state.
    /// </summary>
    public static void StopDragging()
    {
        if (!IsDragging) return;

		Current = null;
		Instance?.StateHasChanged();
	}

	protected override void OnUpdate()
	{
		if ( !IsDragging ) return;

		if ( DragVisual is not null )
		{
			var mouse = Mouse.Position;
			DragVisual.Style.Left = Length.Pixels( mouse.x * Panel.ScaleFromScreen - 32 );
			DragVisual.Style.Top = Length.Pixels( mouse.y * Panel.ScaleFromScreen - 32 );
		}
	}

	protected override int BuildHash() => HashCode.Combine( Current );
}