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 ListItem : UIComponent, IDisposable
{
protected string Classname =>
new CssBuilder("mud-list-item")
.AddClass("mud-list-item-dense", (Dense ?? List?.Dense) ?? false)
.AddClass("mud-list-item-gutters", !DisableGutters && !(List?.DisableGutters == true))
.AddClass("mud-list-item-clickable", List?.Clickable)
.AddClass("mud-ripple", List?.Clickable == true && !DisableRipple && !Disabled)
.AddClass($"mud-selected-item mud-{List?.Color.ToDescriptionString()}-text mud-{List?.Color.ToDescriptionString()}-hover", _selected && !Disabled)
.AddClass("mud-list-item-disabled", Disabled)
.AddClass(Class)
.Build();
[Inject] protected NavigationManager UriHelper { get; set; }
[CascadingParameter] protected List List { get; set; }
private bool _onClickHandlerPreventDefault = false;
///
/// The text to display
///
[Parameter]
[Category(CategoryTypes.List.Behavior)]
public string Text { get; set; }
[Parameter]
[Category(CategoryTypes.List.Selecting)]
public object Value { get; set; }
///
/// Avatar to use if set.
///
[Parameter]
[Category(CategoryTypes.List.Behavior)]
public string Avatar { get; set; }
///
/// Link to a URL when clicked.
///
[Parameter]
[Category(CategoryTypes.List.ClickAction)]
public string Href { get; set; }
///
/// If true, force browser to redirect outside component router-space.
///
[Parameter]
[Category(CategoryTypes.List.ClickAction)]
public bool ForceLoad { get; set; }
///
/// Avatar CSS Class to apply if Avatar is set.
///
[Parameter]
[Category(CategoryTypes.List.Appearance)]
public string AvatarClass { get; set; }
private bool _disabled;
///
/// If true, will disable the list item if it has onclick.
/// The value can be overridden by the parent list.
///
[Parameter]
[Category(CategoryTypes.List.Behavior)]
public bool Disabled
{
get => _disabled || (List?.Disabled ?? false);
set => _disabled = value;
}
///
/// If true, disables ripple effect.
///
[Parameter]
[Category(CategoryTypes.List.Appearance)]
public bool DisableRipple { get; set; }
///
/// Icon to use if set.
///
[Parameter]
[Category(CategoryTypes.List.Behavior)]
public string Icon { get; set; }
///
/// The color of the icon.
///
[Parameter]
[Category(CategoryTypes.List.Appearance)]
public ThemeColor IconColor { get; set; } = ThemeColor.Inherit;
///
/// Sets the Icon Size.
///
[Parameter]
[Category(CategoryTypes.List.Appearance)]
public Size IconSize { get; set; } = Size.Medium;
///
/// The color of the adornment if used. It supports the theme colors.
///
[Parameter]
[Category(CategoryTypes.List.Expanding)]
public ThemeColor AdornmentColor { get; set; } = ThemeColor.Default;
///
/// Custom expand less icon.
///
[Parameter]
[Category(CategoryTypes.List.Expanding)]
public string ExpandLessIcon { get; set; } = Icons.Material.Filled.ExpandLess;
///
/// Custom expand more icon.
///
[Parameter]
[Category(CategoryTypes.List.Expanding)]
public string ExpandMoreIcon { get; set; } = Icons.Material.Filled.ExpandMore;
///
/// If true, the List Subheader will be indented.
///
[Parameter]
[Category(CategoryTypes.List.Appearance)]
public bool Inset { get; set; }
///
/// If true, compact vertical padding will be used.
///
[Parameter]
[Category(CategoryTypes.List.Appearance)]
public bool? Dense { get; set; }
///
/// If true, the left and right padding is removed.
///
[Parameter]
[Category(CategoryTypes.List.Appearance)]
public bool DisableGutters { get; set; }
///
/// Expand or collapse nested list. Two-way bindable. Note: if you directly set this to
/// true or false (instead of using two-way binding) it will force the nested list's expansion state.
///
[Parameter]
[Category(CategoryTypes.List.Expanding)]
public bool Expanded
{
get => _expanded;
set
{
if (_expanded == value)
return;
_expanded = value;
_ = ExpandedChanged.InvokeAsync(value);
}
}
private bool _expanded;
[Parameter]
public EventCallback ExpandedChanged { get; set; }
///
/// If true, expands the nested list on first display
///
[Parameter]
[Category(CategoryTypes.List.Expanding)]
public bool InitiallyExpanded { get; set; }
///
/// Command parameter.
///
[Parameter]
[Category(CategoryTypes.List.ClickAction)]
public object CommandParameter { get; set; }
///
/// Command executed when the user clicks on an element.
///
[Parameter]
[Category(CategoryTypes.List.ClickAction)]
public ICommand Command { get; set; }
///
/// Display content of this list item. If set, this overrides Text
///
[Parameter]
[Category(CategoryTypes.List.Behavior)]
public RenderFragment ChildContent { get; set; }
[Parameter]
[Category(CategoryTypes.List.Behavior)]
public bool OnClickHandlerPreventDefault
{
get => _onClickHandlerPreventDefault;
set => _onClickHandlerPreventDefault = value;
}
///
/// Add child list items here to create a nested list.
///
[Parameter]
[Category(CategoryTypes.List.Behavior)]
public RenderFragment NestedList { get; set; }
///
/// List click event.
///
[Parameter]
public EventCallback OnClick { get; set; }
protected void OnClickHandler(MouseEventArgs ev)
{
if (Disabled)
return;
if (!_onClickHandlerPreventDefault)
{
if (NestedList != null)
{
Expanded = !Expanded;
}
else if (Href != null)
{
List?.SetSelectedValue(this.Value);
OnClick.InvokeAsync(ev);
UriHelper.NavigateTo(Href, ForceLoad);
}
else
{
List?.SetSelectedValue(this.Value);
OnClick.InvokeAsync(ev);
if (Command?.CanExecute(CommandParameter) ?? false)
{
Command.Execute(CommandParameter);
}
}
}
else
{
OnClick.InvokeAsync(ev);
}
}
protected override void OnInitialized()
{
_expanded = InitiallyExpanded;
if (List != null)
{
List.Register(this);
OnListParametersChanged();
List.ParametersChanged += OnListParametersChanged;
}
}
private Typo _textTypo;
private void OnListParametersChanged()
{
if ((Dense ?? List?.Dense) ?? false)
{
_textTypo = Typo.body2;
}
else if (!((Dense ?? List?.Dense) ?? false))
{
_textTypo = Typo.body1;
}
StateHasChanged();
}
private bool _selected;
internal void SetSelected(bool selected)
{
if (Disabled)
return;
if (_selected == selected)
return;
_selected = selected;
StateHasChanged();
}
public void Dispose()
{
try
{
if (List == null)
return;
List.ParametersChanged -= OnListParametersChanged;
List.Unregister(this);
}
catch (Exception) { /*ignore*/ }
}
}