UI/Components/RangeField/RangeField.razor

A UI Razor component for a numeric range field with a label, current value display, and a SliderControl. It exposes properties for Label, Value, Min, Max, Step, display Format, a Setter callback invoked on value change, and an optional OnLimitHit callback when the slider first reaches min or max.

@namespace Sunless.Libraries.UI
@using Sandbox
@using Sandbox.UI
@attribute [StyleSheet]
@inherits Panel

<root class="field">
	<div class="field-label"><label>@Label</label> <span class="val">@Value.ToString( Format )</span></div>
	<SliderControl Value="@Value" Min="@Min" Max="@Max" Step="@Step" OnValueChanged="@HandleChanged" />
</root>

@code
{
	public string Label { get; set; } = "";
	public float Value { get; set; }
	public float Min { get; set; }
	public float Max { get; set; } = 1f;
	public float Step { get; set; } = 1f;
	public string Format { get; set; } = "0";
	public Action<float> Setter { get; set; }

	// Fires once when the slider first hits min OR max. Hook a sound or
	// haptic here; library doesn't ship one. Null = no callback.
	public Action OnLimitHit { get; set; }

	bool _wasAtLimit;

	void HandleChanged( float v )
	{
		Value = v;
		Setter?.Invoke( v );

		var atLimit = v <= Min || v >= Max;
		if ( atLimit && !_wasAtLimit ) OnLimitHit?.Invoke();
		_wasAtLimit = atLimit;
	}

	protected override int BuildHash() => HashCode.Combine( Label, Value, Min, Max, Step, Format );
}