|
|
|
|
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; }
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// The color of the component.
|
|
|
|
|
/// </summary>
|
|
|
|
|
[Parameter]
|
|
|
|
|
[Category(CategoryTypes.Chip.Appearance)]
|
|
|
|
|
public ThemeColor Color { get; set; } = ThemeColor.Default;
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// The size of the button. small is equivalent to the dense button styling.
|
|
|
|
|
/// </summary>
|
|
|
|
|
[Parameter]
|
|
|
|
|
[Category(CategoryTypes.Chip.Appearance)]
|
|
|
|
|
public Size Size { get; set; } = Size.Medium;
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// The variant to use.
|
|
|
|
|
/// </summary>
|
|
|
|
|
[Parameter]
|
|
|
|
|
[Category(CategoryTypes.Chip.Appearance)]
|
|
|
|
|
public Variant Variant { get; set; } = Variant.Filled;
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// The selected color to use when selected, only works together with ChipSet, Color.Inherit for default value.
|
|
|
|
|
/// </summary>
|
|
|
|
|
[Parameter]
|
|
|
|
|
[Category(CategoryTypes.Chip.Appearance)]
|
|
|
|
|
public ThemeColor SelectedColor { get; set; } = ThemeColor.Inherit;
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Avatar Icon, Overrides the regular Icon if set.
|
|
|
|
|
/// </summary>
|
|
|
|
|
[Parameter]
|
|
|
|
|
[Category(CategoryTypes.Chip.Behavior)]
|
|
|
|
|
public string Avatar { get; set; }
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Avatar CSS Class, appends to Chips default avatar classes.
|
|
|
|
|
/// </summary>
|
|
|
|
|
[Parameter]
|
|
|
|
|
[Category(CategoryTypes.Chip.Appearance)]
|
|
|
|
|
public string AvatarClass { get; set; }
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Removes circle edges and applies theme default.
|
|
|
|
|
/// </summary>
|
|
|
|
|
[Parameter]
|
|
|
|
|
[Category(CategoryTypes.Chip.Appearance)]
|
|
|
|
|
public bool Label { get; set; }
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// If true, the chip will be displayed in disabled state and no events possible.
|
|
|
|
|
/// </summary>
|
|
|
|
|
[Parameter]
|
|
|
|
|
[Category(CategoryTypes.Chip.Behavior)]
|
|
|
|
|
public bool Disabled { get; set; }
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Sets the Icon to use.
|
|
|
|
|
/// </summary>
|
|
|
|
|
[Parameter]
|
|
|
|
|
[Category(CategoryTypes.Chip.Behavior)]
|
|
|
|
|
public string Icon { get; set; }
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Custom checked icon.
|
|
|
|
|
/// </summary>
|
|
|
|
|
[Parameter]
|
|
|
|
|
[Category(CategoryTypes.Chip.Appearance)]
|
|
|
|
|
public string CheckedIcon { get; set; } = Icons.Material.Filled.Check;
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// The color of the icon.
|
|
|
|
|
/// </summary>
|
|
|
|
|
[Parameter]
|
|
|
|
|
[Category(CategoryTypes.Chip.Appearance)]
|
|
|
|
|
public ThemeColor IconColor { get; set; } = ThemeColor.Inherit;
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Overrides the default close icon, only shown if OnClose is set.
|
|
|
|
|
/// </summary>
|
|
|
|
|
[Parameter]
|
|
|
|
|
[Category(CategoryTypes.Chip.Appearance)]
|
|
|
|
|
public string CloseIcon { get; set; }
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// If true, disables ripple effect, ripple effect is only applied to clickable chips.
|
|
|
|
|
/// </summary>
|
|
|
|
|
[Parameter]
|
|
|
|
|
[Category(CategoryTypes.Chip.Appearance)]
|
|
|
|
|
public bool DisableRipple { get; set; }
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Child content of component.
|
|
|
|
|
/// </summary>
|
|
|
|
|
[Parameter]
|
|
|
|
|
[Category(CategoryTypes.Chip.Behavior)]
|
|
|
|
|
public RenderFragment ChildContent { get; set; }
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// If set to a URL, clicking the button will open the referenced document. Use Target to specify where (Obsolete replaced by Href)
|
|
|
|
|
/// </summary>
|
|
|
|
|
[Obsolete("Use Href Instead.", false)]
|
|
|
|
|
[Parameter]
|
|
|
|
|
[Category(CategoryTypes.Chip.ClickAction)]
|
|
|
|
|
public string Link
|
|
|
|
|
{
|
|
|
|
|
get => Href;
|
|
|
|
|
set => Href = value;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// If set to a URL, clicking the button will open the referenced document. Use Target to specify where
|
|
|
|
|
/// </summary>
|
|
|
|
|
[Parameter]
|
|
|
|
|
[Category(CategoryTypes.Chip.ClickAction)]
|
|
|
|
|
public string Href { get; set; }
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// The target attribute specifies where to open the link, if Href is specified. Possible values: _blank | _self | _parent | _top | <i>framename</i>
|
|
|
|
|
/// </summary>
|
|
|
|
|
[Parameter]
|
|
|
|
|
[Category(CategoryTypes.Chip.ClickAction)]
|
|
|
|
|
public string Target { get; set; }
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// A string you want to associate with the chip. If the ChildContent is not set this will be shown as chip text.
|
|
|
|
|
/// </summary>
|
|
|
|
|
[Parameter]
|
|
|
|
|
[Category(CategoryTypes.Chip.Behavior)]
|
|
|
|
|
public string Text { get; set; }
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// A value that should be managed in the SelectedValues collection.
|
|
|
|
|
/// Note: do not change the value during the chip's lifetime
|
|
|
|
|
/// </summary>
|
|
|
|
|
[Parameter]
|
|
|
|
|
[Category(CategoryTypes.Chip.Behavior)]
|
|
|
|
|
public object Value { get; set; }
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// If true, force browser to redirect outside component router-space.
|
|
|
|
|
/// </summary>
|
|
|
|
|
[Parameter]
|
|
|
|
|
[Category(CategoryTypes.Chip.ClickAction)]
|
|
|
|
|
public bool ForceLoad { get; set; }
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// If true, this chip is selected by default if used in a ChipSet.
|
|
|
|
|
/// </summary>
|
|
|
|
|
[Parameter]
|
|
|
|
|
[Category(CategoryTypes.Chip.Behavior)]
|
|
|
|
|
public bool? Default { get; set; }
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Command executed when the user clicks on an element.
|
|
|
|
|
/// </summary>
|
|
|
|
|
[Parameter]
|
|
|
|
|
[Category(CategoryTypes.Chip.ClickAction)]
|
|
|
|
|
public ICommand Command { get; set; }
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Command parameter.
|
|
|
|
|
/// </summary>
|
|
|
|
|
[Parameter]
|
|
|
|
|
[Category(CategoryTypes.Chip.ClickAction)]
|
|
|
|
|
public object CommandParameter { get; set; }
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Chip click event, if set the chip focus, hover and click effects are applied.
|
|
|
|
|
/// </summary>
|
|
|
|
|
[Parameter] public EventCallback<MouseEventArgs> OnClick { get; set; }
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Chip delete event, if set the delete icon will be visible.
|
|
|
|
|
/// </summary>
|
|
|
|
|
[Parameter] public EventCallback<Chip> OnClose { get; set; }
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Set by MudChipSet
|
|
|
|
|
/// </summary>
|
|
|
|
|
public bool IsChecked
|
|
|
|
|
{
|
|
|
|
|
get => _isSelected && ChipSet?.Filter == true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// If false, this chip has not been seen before
|
|
|
|
|
/// </summary>
|
|
|
|
|
public bool DefaultProcessed { get; set; }
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Set by MudChipSet
|
|
|
|
|
/// </summary>
|
|
|
|
|
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 <a> 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! */
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|