using Connected.Annotations; using Connected.Utilities; using Microsoft.AspNetCore.Components; namespace Connected.Components; public partial class List : UIComponent, IDisposable { protected string Classname => new CssBuilder("mud-list") .AddClass("mud-list-padding", !DisablePadding) .AddClass(Class) .Build(); [CascadingParameter] protected List ParentList { get; set; } /// /// The color of the selected List Item. /// [Parameter] [Category(CategoryTypes.List.Appearance)] public ThemeColor Color { get; set; } = ThemeColor.Primary; /// /// Child content of component. /// [Parameter] [Category(CategoryTypes.List.Behavior)] public RenderFragment ChildContent { get; set; } /// /// Set true to make the list items clickable. This is also the precondition for list selection to work. /// [Parameter] [Category(CategoryTypes.List.Selecting)] public bool Clickable { get; set; } /// /// If true, vertical padding will be removed from the list. /// [Parameter] [Category(CategoryTypes.List.Appearance)] public bool DisablePadding { get; set; } /// /// If true, compact vertical padding will be applied to all list items. /// [Parameter] [Category(CategoryTypes.List.Appearance)] public bool Dense { get; set; } /// /// If true, the left and right padding is removed on all list items. /// [Parameter] [Category(CategoryTypes.List.Appearance)] public bool DisableGutters { get; set; } /// /// If true, will disable the list item if it has onclick. /// [Parameter] [Category(CategoryTypes.List.Behavior)] public bool Disabled { get; set; } /// /// The current selected list item. /// Note: make the list Clickable for item selection to work. /// [Parameter] [Category(CategoryTypes.List.Selecting)] public ListItem SelectedItem { get => _selectedItem; set { if (_selectedItem == value) return; SetSelectedValue(_selectedItem?.Value, force: true); } } /// /// Called whenever the selection changed /// [Parameter] public EventCallback SelectedItemChanged { get; set; } /// /// The current selected value. /// Note: make the list Clickable for item selection to work. /// [Parameter] [Category(CategoryTypes.List.Selecting)] public object SelectedValue { get => _selectedValue; set { SetSelectedValue(value, force: true); } } /// /// Called whenever the selection changed /// [Parameter] public EventCallback SelectedValueChanged { get; set; } protected override void OnInitialized() { if (ParentList != null) { ParentList.Register(this); CanSelect = ParentList.CanSelect; } else { CanSelect = SelectedItemChanged.HasDelegate || SelectedValueChanged.HasDelegate || SelectedValue != null; } } internal event Action ParametersChanged; protected override void OnParametersSet() { base.OnParametersSet(); ParametersChanged?.Invoke(); } private HashSet _items = new(); private HashSet _childLists = new(); private ListItem _selectedItem; private object _selectedValue; internal void Register(ListItem item) { _items.Add(item); if (CanSelect && SelectedValue != null && object.Equals(item.Value, SelectedValue)) { item.SetSelected(true); _selectedItem = item; SelectedItemChanged.InvokeAsync(item); } } internal void Unregister(ListItem item) { _items.Remove(item); } internal void Register(List child) { _childLists.Add(child); } internal void Unregister(List child) { _childLists.Remove(child); } internal void SetSelectedValue(object value, bool force = false) { if ((!CanSelect || !Clickable) && !force) return; if (object.Equals(_selectedValue, value)) return; _selectedValue = value; SelectedValueChanged.InvokeAsync(value).AndForget(); _selectedItem = null; // <-- for now, we'll see which item matches the value below foreach (var listItem in _items.ToArray()) { var isSelected = value != null && object.Equals(value, listItem.Value); listItem.SetSelected(isSelected); if (isSelected) _selectedItem = listItem; } foreach (var childList in _childLists.ToArray()) { childList.SetSelectedValue(value); if (childList.SelectedItem != null) _selectedItem = childList.SelectedItem; } SelectedItemChanged.InvokeAsync(_selectedItem).AndForget(); ParentList?.SetSelectedValue(value); } internal bool CanSelect { get; private set; } public void Dispose() { ParametersChanged = null; ParentList?.Unregister(this); } }