-
Notifications
You must be signed in to change notification settings - Fork 160
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
🐛 (ExpansionPanels): unexpected IsActive paramter; ActiveClass is not…
… working (#2142)
- Loading branch information
Showing
6 changed files
with
215 additions
and
201 deletions.
There are no files selected for viewing
2 changes: 1 addition & 1 deletion
2
src/Masa.Blazor/Components/ExpansionPanels/MExpansionPanel.razor
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,5 +1,4 @@ | ||
using Masa.Blazor.Components.ItemGroup; | ||
using Masa.Blazor.Mixins; | ||
|
||
namespace Masa.Blazor; | ||
|
||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,201 +1,25 @@ | ||
namespace Masa.Blazor.Components.ItemGroup; | ||
|
||
public abstract class MGroupable<TGroup> : MasaComponentBase, IGroupable | ||
/// <summary> | ||
/// The base class for groupable components. | ||
/// The active state can be controlled by its parent group component or IsActive property. | ||
/// </summary> | ||
/// <typeparam name="TGroup"></typeparam> | ||
public abstract class MGroupable<TGroup> : MGroupableBase<TGroup>, IGroupable | ||
where TGroup : MItemGroupBase | ||
{ | ||
[CascadingParameter] | ||
public TGroup? ItemGroup { get; set; } | ||
|
||
[Parameter] | ||
public string? ActiveClass { get; set; } | ||
|
||
[Parameter] | ||
public virtual bool Disabled { get; set; } | ||
|
||
// TODO: use Value instead of IsActive | ||
[Parameter] | ||
public bool IsActive | ||
{ | ||
get => _isActive ?? false; | ||
set => _isActive = value; | ||
} | ||
|
||
[Parameter] | ||
public StringNumber? Value | ||
{ | ||
get => _value; | ||
set | ||
{ | ||
if (value == null) return; | ||
|
||
_value = value; | ||
} | ||
} | ||
|
||
/// <summary> | ||
/// whether to enable bootable. | ||
/// </summary> | ||
private readonly bool _bootable; | ||
|
||
/// <summary> | ||
/// the <see cref="GroupType"/> of the groupable component. | ||
/// </summary> | ||
private readonly GroupType _groupType; | ||
|
||
private bool? _isActive; | ||
private StringNumber? _value; | ||
private bool _firstRenderAfterBooting; | ||
|
||
/// <summary> | ||
/// Initializes a base component <see cref="MGroupable{TGroup}"/> with the <see cref="GroupType"/>. | ||
/// </summary> | ||
/// <param name="groupType">the <see cref="GroupType"/> of the groupable component.</param> | ||
protected MGroupable(GroupType groupType) | ||
{ | ||
_groupType = groupType; | ||
} | ||
|
||
/// <summary> | ||
/// Initializes a base component <see cref="MGroupable{TGroup}"/> with the <see cref="GroupType"/> | ||
/// and specifies whether to bootable. | ||
/// </summary> | ||
/// <param name="groupType">the <see cref="GroupType"/> of the groupable component.</param> | ||
/// <param name="bootable">determines whether bootable is enabled or not.</param> | ||
protected MGroupable(GroupType groupType, bool bootable) : this(groupType) | ||
{ | ||
_bootable = bootable; | ||
} | ||
|
||
protected string? ComputedActiveClass => ActiveClass ?? ItemGroup?.ActiveClass; | ||
|
||
/// <summary> | ||
/// Determines whether the component has a routable ancestor component. | ||
/// </summary> | ||
protected virtual bool HasRoutableAncestor => ItemGroup is IAncestorRoutable { Routable: true }; | ||
|
||
/// <summary> | ||
/// The routable ancestor. | ||
/// </summary> | ||
protected IAncestorRoutable? RoutableAncestor => HasRoutableAncestor ? (IAncestorRoutable)ItemGroup! : null; | ||
|
||
protected bool Matched => ItemGroup != null && (ItemGroup.GroupType == _groupType); | ||
|
||
protected bool ValueMatched => Matched && ItemGroup!.InternalValues.Contains(Value); | ||
|
||
public bool InternalIsActive { get; private set; } | ||
|
||
/// <summary> | ||
/// Determines whether the component has been booted. | ||
/// </summary> | ||
protected bool IsBooted { get; private set; } | ||
|
||
protected virtual bool IsEager { get; } = false; | ||
|
||
protected virtual bool HasTransition { get; } = false; | ||
|
||
protected override async Task OnInitializedAsync() | ||
protected MGroupable(GroupType groupType) : base(groupType) | ||
{ | ||
if (!Matched) return; | ||
|
||
if (this is IGroupable item) | ||
{ | ||
await ItemGroup!.Register(item); | ||
} | ||
|
||
await base.OnInitializedAsync(); | ||
} | ||
|
||
protected override async Task OnParametersSetAsync() | ||
protected MGroupable(GroupType groupType, bool bootable) : base(groupType, bootable) | ||
{ | ||
if (_isActive.HasValue) // if setting by [Parameter]IsActive, Matched is not required. | ||
{ | ||
await SetInternalIsActive(_isActive.Value); | ||
} | ||
} | ||
|
||
protected override async Task OnAfterRenderAsync(bool firstRender) | ||
{ | ||
await base.OnAfterRenderAsync(firstRender); | ||
|
||
if (_firstRenderAfterBooting) | ||
{ | ||
await Task.Delay(16); | ||
_firstRenderAfterBooting = false; | ||
|
||
InternalIsActive = true; | ||
StateHasChanged(); | ||
} | ||
} | ||
|
||
public async Task RefreshState() | ||
{ | ||
if (!Matched || HasRoutableAncestor) return; | ||
|
||
await SetInternalIsActive(ValueMatched); | ||
} | ||
|
||
protected async Task ToggleAsync() | ||
{ | ||
if (!Matched) return; | ||
|
||
await ItemGroup!.ToggleAsync(Value); | ||
} | ||
|
||
protected async Task SetInternalIsActive(bool val, bool force = false) | ||
{ | ||
if (IsEager) | ||
{ | ||
if (InternalIsActive != val || force) | ||
{ | ||
InternalIsActive = val; | ||
StateHasChanged(); | ||
} | ||
} | ||
else | ||
{ | ||
if (!IsBooted) | ||
{ | ||
if (val) | ||
{ | ||
IsBooted = true; | ||
|
||
if (HasTransition) | ||
{ | ||
_firstRenderAfterBooting = true; | ||
|
||
await Task.Delay(16); | ||
} | ||
else | ||
{ | ||
InternalIsActive = true; | ||
} | ||
|
||
StateHasChanged(); | ||
} | ||
} | ||
else if (InternalIsActive != val || force) | ||
{ | ||
if (_firstRenderAfterBooting) | ||
{ | ||
// waiting for one frame(16ms) to make sure the element has been rendered, | ||
// and then set the InternalIsActive to be true to invoke transition. | ||
await Task.Delay(16); | ||
_firstRenderAfterBooting = false; | ||
} | ||
|
||
InternalIsActive = val; | ||
StateHasChanged(); | ||
} | ||
} | ||
} | ||
|
||
protected override async ValueTask DisposeAsyncCore() | ||
[Parameter] | ||
public bool IsActive | ||
{ | ||
if (Matched && this is IGroupable item) | ||
{ | ||
ItemGroup!.Unregister(item); | ||
} | ||
|
||
await base.DisposeAsyncCore(); | ||
get => UserActive ?? false; | ||
set => UserActive = value; | ||
} | ||
} |
Oops, something went wrong.