A UI Razor component for a modal dialog panel. It renders an overlay with optional header, body and footer regions, supports a close button and scrim click dismissal, and exposes properties and callbacks to control visibility and content.
@namespace Sunless.Libraries.UI
@using Sandbox
@using Sandbox.UI
@attribute [StyleSheet]
@inherits Panel
<root class="modal-overlay @(IsOpen ? "is-open" : "") @ExtraClass">
@if ( IsOpen )
{
<div class="modal-scrim" @onclick=@HandleScrimClick></div>
<div class="modal-dialog" style=@DialogStyle>
@if ( Header is not null || !string.IsNullOrEmpty( Title ) || ShowClose )
{
<div class="modal-header">
@if ( Header is not null )
{
@Header
}
else
{
<div class="modal-title">@Title</div>
}
@if ( ShowClose )
{
<div class="modal-close" @onclick=@HandleClose>X</div>
}
</div>
}
@if ( Body is not null )
{
<div class="modal-body">@Body</div>
}
@if ( Footer is not null )
{
<div class="modal-footer">@Footer</div>
}
</div>
}
</root>
@code
{
public bool IsOpen { get; set; }
public string Title { get; set; }
public bool ShowClose { get; set; } = true;
public bool DismissOnScrim { get; set; } = true;
public string ExtraClass { get; set; }
public string DialogStyle { get; set; }
public Action OnClose { get; set; }
public RenderFragment Header { get; set; }
public RenderFragment Body { get; set; }
public RenderFragment Footer { get; set; }
void HandleClose()
{
try { OnClose?.Invoke(); } catch ( Exception e ) { Log.Warning( $"[Modal] OnClose threw: {e.Message}" ); }
}
void HandleScrimClick()
{
if ( !DismissOnScrim ) return;
HandleClose();
}
protected override int BuildHash() => HashCode.Combine( IsOpen, Title, ShowClose, ExtraClass, DialogStyle );
}