using Connected.Annotations; using Connected.Utilities; using Microsoft.AspNetCore.Components; namespace Connected.Components; public partial class ExpansionPanel : UIComponent, IDisposable { private bool _nextPanelExpanded; private bool _isExpanded; private bool _collapseIsExpanded; [CascadingParameter] private ExpansionPanels Parent { get; set; } protected string Classname => new CssBuilder("mud-expand-panel") .AddClass("mud-panel-expanded", IsExpanded) .AddClass("mud-panel-next-expanded", NextPanelExpanded) .AddClass("mud-disabled", Disabled) .AddClass($"mud-elevation-{Parent?.Elevation.ToString()}") .AddClass($"mud-expand-panel-border", Parent?.DisableBorders != true) .AddClass(Class) .Build(); protected string PanelContentClassname => new CssBuilder("mud-expand-panel-content") .AddClass("mud-expand-panel-gutters", DisableGutters || Parent?.DisableGutters == true) .AddClass("mud-expand-panel-dense", Dense || Parent?.Dense == true) .Build(); /// /// Explicitly sets the height for the Collapse element to override the css default. /// [Parameter] [Category(CategoryTypes.ExpansionPanel.Appearance)] public int? MaxHeight { get; set; } /// /// RenderFragment to be displayed in the expansion panel which will override header text if defined. /// [Parameter] [Category(CategoryTypes.ExpansionPanel.Behavior)] public RenderFragment TitleContent { get; set; } /// /// The text to be displayed in the expansion panel. /// [Parameter] [Category(CategoryTypes.ExpansionPanel.Behavior)] public string Text { get; set; } /// /// If true, expand icon will not show /// [Parameter] [Category(CategoryTypes.ExpansionPanel.Appearance)] public bool HideIcon { get; set; } /// /// Custom hide icon. /// [Parameter] [Category(CategoryTypes.ExpansionPanel.Appearance)] public string Icon { get; set; } = Icons.Material.Filled.ExpandMore; /// /// If true, removes vertical padding from childcontent. /// [Parameter] [Category(CategoryTypes.ExpansionPanel.Appearance)] public bool Dense { get; set; } /// /// If true, the left and right padding is removed from childcontent. /// [Parameter] [Category(CategoryTypes.ExpansionPanel.Appearance)] public bool DisableGutters { get; set; } /// /// Raised when IsExpanded changes. /// [Parameter] public EventCallback IsExpandedChanged { get; set; } internal event Action NotifyIsExpandedChanged; /// /// Expansion state of the panel (two-way bindable) /// [Parameter] [Category(CategoryTypes.ExpansionPanel.Behavior)] public bool IsExpanded { get => _isExpanded; set { if (_isExpanded == value) return; _isExpanded = value; NotifyIsExpandedChanged?.Invoke(this); IsExpandedChanged.InvokeAsync(_isExpanded).ContinueWith(t => { if (_collapseIsExpanded != _isExpanded) { _collapseIsExpanded = _isExpanded; InvokeAsync(() => StateHasChanged()); } }); } } /// /// Sets the initial expansion state. Do not use in combination with IsExpanded. /// Combine with MultiExpansion to have more than one panel start open. /// [Parameter] [Category(CategoryTypes.ExpansionPanel.Behavior)] public bool IsInitiallyExpanded { get; set; } /// /// If true, the component will be disabled. /// [Parameter] [Category(CategoryTypes.ExpansionPanel.Behavior)] public bool Disabled { get; set; } /// /// Child content of component. /// [Parameter] [Category(CategoryTypes.ExpansionPanel.Behavior)] public RenderFragment ChildContent { get; set; } public bool NextPanelExpanded { get => _nextPanelExpanded; set { if (_nextPanelExpanded == value) return; _nextPanelExpanded = value; //InvokeAsync(StateHasChanged); } } public void ToggleExpansion() { if (Disabled) { return; } IsExpanded = !IsExpanded; } public void Expand(bool update_parent = true) { if (update_parent) IsExpanded = true; else { _isExpanded = true; _collapseIsExpanded = true; IsExpandedChanged.InvokeAsync(_isExpanded); } } public void Collapse(bool update_parent = true) { if (update_parent) IsExpanded = false; else { _isExpanded = false; _collapseIsExpanded = false; IsExpandedChanged.InvokeAsync(_isExpanded); } } protected override void OnInitialized() { // NOTE: we can't throw here because we need to be able to instanciate the type for the API Docs to infer default values //if (Parent == null) // throw new ArgumentNullException(nameof(Parent), "ExpansionPanel must exist within a ExpansionPanels component"); base.OnInitialized(); if (!IsExpanded && IsInitiallyExpanded) { _isExpanded = true; _collapseIsExpanded = true; } Parent?.AddPanel(this); } public void Dispose() { Parent?.RemovePanel(this); } }