using System.Diagnostics.CodeAnalysis;
using System.Windows.Input;
using Connected.Annotations;
using Connected.Extensions;
using Connected.Utilities;
using Microsoft.AspNetCore.Components;
using Microsoft.AspNetCore.Components.Web;
namespace Connected.Components;
public partial class Chip : UIComponent, IDisposable
{
private bool _isSelected;
[Inject] public NavigationManager UriHelper { get; set; }
[Inject] public IJsApiService JsApiService { get; set; }
protected string Classname =>
new CssBuilder("mud-chip")
.AddClass($"mud-chip-{GetVariant().ToDescriptionString()}")
.AddClass($"mud-chip-size-{Size.ToDescriptionString()}")
.AddClass($"mud-chip-color-{GetColor().ToDescriptionString()}")
.AddClass("mud-clickable", !ChipSet?.ReadOnly ?? OnClick.HasDelegate)
.AddClass("mud-ripple", !ChipSet?.ReadOnly ?? OnClick.HasDelegate && !DisableRipple)
.AddClass("mud-chip-label", Label)
.AddClass("mud-disabled", Disabled)
.AddClass("mud-chip-selected", IsSelected)
.AddClass(Class)
.Build();
//Cannot test the get variant (last line)
[ExcludeFromCodeCoverage]
private Variant GetVariant()
{
return Variant switch
{
Variant.Text => IsSelected ? Variant.Filled : Variant.Text,
Variant.Filled => IsSelected ? Variant.Text : Variant.Filled,
Variant.Outlined => Variant.Outlined,
_ => Variant
};
}
private ThemeColor GetColor()
{
if (IsSelected && SelectedColor != ThemeColor.Inherit)
{
return SelectedColor;
}
else if (IsSelected && SelectedColor == ThemeColor.Inherit)
{
return Color;
}
else
{
return Color;
}
}
[CascadingParameter] ChipSet ChipSet { get; set; }
///
/// The color of the component.
///
[Parameter]
[Category(CategoryTypes.Chip.Appearance)]
public ThemeColor Color { get; set; } = ThemeColor.Default;
///
/// The size of the button. small is equivalent to the dense button styling.
///
[Parameter]
[Category(CategoryTypes.Chip.Appearance)]
public Size Size { get; set; } = Size.Medium;
///
/// The variant to use.
///
[Parameter]
[Category(CategoryTypes.Chip.Appearance)]
public Variant Variant { get; set; } = Variant.Filled;
///
/// The selected color to use when selected, only works together with ChipSet, Color.Inherit for default value.
///
[Parameter]
[Category(CategoryTypes.Chip.Appearance)]
public ThemeColor SelectedColor { get; set; } = ThemeColor.Inherit;
///
/// Avatar Icon, Overrides the regular Icon if set.
///
[Parameter]
[Category(CategoryTypes.Chip.Behavior)]
public string Avatar { get; set; }
///
/// Avatar CSS Class, appends to Chips default avatar classes.
///
[Parameter]
[Category(CategoryTypes.Chip.Appearance)]
public string AvatarClass { get; set; }
///
/// Removes circle edges and applies theme default.
///
[Parameter]
[Category(CategoryTypes.Chip.Appearance)]
public bool Label { get; set; }
///
/// If true, the chip will be displayed in disabled state and no events possible.
///
[Parameter]
[Category(CategoryTypes.Chip.Behavior)]
public bool Disabled { get; set; }
///
/// Sets the Icon to use.
///
[Parameter]
[Category(CategoryTypes.Chip.Behavior)]
public string Icon { get; set; }
///
/// Custom checked icon.
///
[Parameter]
[Category(CategoryTypes.Chip.Appearance)]
public string CheckedIcon { get; set; } = Icons.Material.Filled.Check;
///
/// The color of the icon.
///
[Parameter]
[Category(CategoryTypes.Chip.Appearance)]
public ThemeColor IconColor { get; set; } = ThemeColor.Inherit;
///
/// Overrides the default close icon, only shown if OnClose is set.
///
[Parameter]
[Category(CategoryTypes.Chip.Appearance)]
public string CloseIcon { get; set; }
///
/// If true, disables ripple effect, ripple effect is only applied to clickable chips.
///
[Parameter]
[Category(CategoryTypes.Chip.Appearance)]
public bool DisableRipple { get; set; }
///
/// Child content of component.
///
[Parameter]
[Category(CategoryTypes.Chip.Behavior)]
public RenderFragment ChildContent { get; set; }
///
/// If set to a URL, clicking the button will open the referenced document. Use Target to specify where (Obsolete replaced by Href)
///
[Obsolete("Use Href Instead.", false)]
[Parameter]
[Category(CategoryTypes.Chip.ClickAction)]
public string Link
{
get => Href;
set => Href = value;
}
///
/// If set to a URL, clicking the button will open the referenced document. Use Target to specify where
///
[Parameter]
[Category(CategoryTypes.Chip.ClickAction)]
public string Href { get; set; }
///
/// The target attribute specifies where to open the link, if Href is specified. Possible values: _blank | _self | _parent | _top | framename
///
[Parameter]
[Category(CategoryTypes.Chip.ClickAction)]
public string Target { get; set; }
///
/// A string you want to associate with the chip. If the ChildContent is not set this will be shown as chip text.
///
[Parameter]
[Category(CategoryTypes.Chip.Behavior)]
public string Text { get; set; }
///
/// A value that should be managed in the SelectedValues collection.
/// Note: do not change the value during the chip's lifetime
///
[Parameter]
[Category(CategoryTypes.Chip.Behavior)]
public object Value { get; set; }
///
/// If true, force browser to redirect outside component router-space.
///
[Parameter]
[Category(CategoryTypes.Chip.ClickAction)]
public bool ForceLoad { get; set; }
///
/// If true, this chip is selected by default if used in a ChipSet.
///
[Parameter]
[Category(CategoryTypes.Chip.Behavior)]
public bool? Default { get; set; }
///
/// Command executed when the user clicks on an element.
///
[Parameter]
[Category(CategoryTypes.Chip.ClickAction)]
public ICommand Command { get; set; }
///
/// Command parameter.
///
[Parameter]
[Category(CategoryTypes.Chip.ClickAction)]
public object CommandParameter { get; set; }
///
/// Chip click event, if set the chip focus, hover and click effects are applied.
///
[Parameter] public EventCallback OnClick { get; set; }
///
/// Chip delete event, if set the delete icon will be visible.
///
[Parameter] public EventCallback OnClose { get; set; }
///
/// Set by MudChipSet
///
public bool IsChecked
{
get => _isSelected && ChipSet?.Filter == true;
}
///
/// If false, this chip has not been seen before
///
public bool DefaultProcessed { get; set; }
///
/// Set by MudChipSet
///
public bool IsSelected
{
get => _isSelected;
set
{
if (_isSelected == value)
return;
_isSelected = value;
StateHasChanged();
}
}
protected override void OnInitialized()
{
base.OnInitialized();
if (Value == null)
Value = this;
}
protected internal async Task OnClickHandler(MouseEventArgs ev)
{
if (ChipSet?.ReadOnly == true)
{
return;
}
if (ChipSet != null)
{
_ = ChipSet.OnChipClicked(this);
}
if (Href != null)
{
// TODO: use MudElement to render and this code can be removed. we know that it has potential problems on iOS
if (string.IsNullOrWhiteSpace(Target))
UriHelper.NavigateTo(Href, ForceLoad);
else
await JsApiService.Open(Href, Target);
}
else
{
await OnClick.InvokeAsync(ev);
if (Command?.CanExecute(CommandParameter) ?? false)
{
Command.Execute(CommandParameter);
}
}
}
protected async Task OnCloseHandler(MouseEventArgs ev)
{
if (ChipSet?.ReadOnly == true)
{
return;
}
await OnClose.InvokeAsync(this);
ChipSet?.OnChipDeleted(this);
StateHasChanged();
}
protected override Task OnInitializedAsync()
{
ChipSet?.Add(this);
return base.OnInitializedAsync();
}
internal void ForceRerender() => StateHasChanged();
//Exclude because we don't test to catching exception yet
[ExcludeFromCodeCoverage]
public void Dispose()
{
try
{
ChipSet?.Remove(this);
}
catch (Exception)
{
/* ignore! */
}
}
}