using Microsoft.AspNetCore.Components.Rendering; using Sandbox.UI.Navigation; namespace Sandbox.UI; /// /// A simple button . /// [Library( "Button" )] public class Button : Panel, INavigationEvent { /// /// The that displays . /// protected Label TextLabel; /// /// The that displays . /// protected IconPanel IconPanel; /// /// The that displays . /// protected Label HelpLabel; /// /// The column on the right, holding the label and help /// protected Panel RightColumn; /// /// The target link, if set /// [Parameter] public string Href { get; set; } /// /// Used for selection status in things like ButtonGroup /// public virtual object Value { get; set; } /// /// More button options underneath the main button content. /// [Parameter] public RenderFragment HoverMenu { get; set; } public Button() { AddClass( "button" ); IconPanel = AddChild( new IconPanel( "people", "icon" ) ); IconPanel.Style.Display = DisplayMode.None; RightColumn = AddChild( new Panel( this, "button-right-column" ) ); RightColumn.Style.Display = DisplayMode.None; TextLabel = RightColumn.AddChild( new Label( "Empty Label", "button-label button-text" ) ); TextLabel.Style.Display = DisplayMode.None; HelpLabel ??= RightColumn.AddChild( new Label( "", "button-help" ) ); HelpLabel.Style.Display = DisplayMode.None; } public Button( string text, Action action = default ) : this() { if ( text != null ) Text = text; if ( action != null ) AddEventListener( "onclick", action ); } public Button( string text, string icon ) : this() { if ( icon != null ) Icon = icon; if ( text != null ) Text = text; } /// /// The button is disabled for some reason /// [Parameter] public bool Disabled { get => HasClass( "disabled" ); set => SetClass( "disabled", value ); } /// /// Allow external factors to force the active state /// [Parameter] public bool Active { get; set; } public Button( string text, string icon, Action onClick ) : this( text, icon ) { AddEventListener( "onclick", onClick ); } public Button( string text, string icon, string className, Action onClick ) : this( text, icon, onClick ) { AddClass( className ); } /// /// Text for the button. /// [Parameter] public string Text { get => TextLabel?.Text; set { if ( string.IsNullOrEmpty( value ) ) { TextLabel.Style.Display = DisplayMode.None; TextLabel.Text = ""; return; } TextLabel.Style.Display = DisplayMode.Flex; RightColumn.Style.Display = DisplayMode.Flex; TextLabel.Text = value; } } /// /// Help for the button. /// [Parameter] public string Help { get => HelpLabel?.Text; set { if ( string.IsNullOrEmpty( value ) ) { HelpLabel.Style.Display = DisplayMode.None; HelpLabel.Text = ""; return; } HelpLabel.Style.Display = DisplayMode.Flex; RightColumn.Style.Display = DisplayMode.Flex; HelpLabel.Text = value; } } /// /// Deletes the . /// public void DeleteText() { if ( !TextLabel.IsValid() ) return; TextLabel?.Delete(); TextLabel = null; } /// /// Icon for the button. /// [Parameter] public string Icon { get => IconPanel?.Text; set { if ( string.IsNullOrEmpty( value ) ) { IconPanel.Style.Display = DisplayMode.None; return; } IconPanel.Style.Display = DisplayMode.Flex; IconPanel.Text = value; SetClass( "has-icon", IconPanel.IsValid() ); } } /// /// Deletes the . /// public void DeleteIcon() { IconPanel.Style.Display = DisplayMode.None; } /// /// Set the text for the button. Calls Text = value /// public virtual void SetText( string text ) { Text = text; } /// /// Imitate the button being clicked. /// public void Click() { CreateEvent( new MousePanelEvent( "onclick", this, "mouseleft" ) ); } public override void SetProperty( string name, string value ) { switch ( name ) { case "text": { SetText( value ); return; } case "html": { SetText( value ); return; } case "icon": { Icon = value; return; } case "href": { Href = value; return; } case "active": { SetClass( "active", value.ToBool() ); return; } } base.SetProperty( name, value ); } public override void SetContent( string value ) { SetText( value?.Trim() ?? "" ); } NavigationHost _navigatorCache; public override void Tick() { base.Tick(); UpdateActiveState(); } protected void UpdateActiveState() { if ( Active ) { SetClass( "active", true ); return; } if ( string.IsNullOrWhiteSpace( Href ) ) { SetClass( "active", false ); return; } _navigatorCache ??= Ancestors.OfType().FirstOrDefault(); var active = (_navigatorCache?.CurrentUrlMatches( Href ) ?? false); SetClass( "active", active ); } protected override void OnMouseDown( MousePanelEvent e ) { base.OnMouseDown( e ); if ( !string.IsNullOrWhiteSpace( Href ) ) { this.Navigate( Href ); e.StopPropagation(); } } protected override void BuildRenderTree( RenderTreeBuilder tree ) { if ( HoverMenu != null ) { var classes = "button-hover-menu"; if ( !HasHovered ) classes += " hidden"; tree.OpenElement( 0 ); tree.AddAttribute( 1, "class", classes ); HoverMenu?.Invoke( tree ); tree.CloseElement(); } } protected override int BuildHash() => HashCode.Combine( HoverMenu, HasHovered ); protected override string GetRenderTreeChecksum() => $"{BuildHash()}"; void INavigationEvent.OnNavigated( string url ) { UpdateActiveState(); } }