Code/Suspense.razor.cs
using System;
using Sandbox.Diagnostics;
using Sandbox.Razor;

namespace BetterUI;

/// <summary>
/// A panel that displays a waiting render fragment if the loading function
/// returns true, or a completed render fragment if it returns false.
/// </summary>
/// <remarks>
/// This is a simple way to implement a loading state into a panel.
/// </remarks>
public sealed partial class Suspense : Panel
{
	/// <summary>
	/// The unique identifier for the suspense panel.
	/// </summary>
	public new string Id { get; set; } = Guid.NewGuid().ToString();

	/// <summary>
	/// The function that is called to check if the panel is loading.
	/// </summary>
	/// <returns>True if the panel is loading, false otherwise.</returns>
	public Func<bool> IsLoading { get; set; } = null!;

	/// <summary>
	/// The render fragment that is displayed while the panel is loading.
	/// </summary>
	public RenderFragment? Loading { get; set; }

	/// <summary>
	/// The render fragment that is displayed when the panel is not loading.
	/// </summary>
	public RenderFragment? Completed { get; set; }

	/// <inheritdoc />
	protected override void OnAfterTreeRender( bool firstTime )
	{
		Assert.NotNull( Id, "Suspense must have an Id" );
		Assert.NotNull( IsLoading, "Loader must have a loading function" );
	}

	/// <inheritdoc />
	public override void Tick()
	{
		BindClass( "suspense", () => IsLoading.Invoke() );
	}

	/// <inheritdoc />
	protected override int BuildHash() => HashCode.Combine( IsLoading.Invoke() );
}