Skip to content

Commit da8d480

Browse files
authored
πŸ†• feat(Tabs): re-render slider when a tab is removed(unregister) (#605)
* β™» refactor(Tabs): add support for custom the default item value in sub classes * ⚰ refactor: remove unnecessary code * πŸ†• feat(Tabs): Add CallSliderAfterRender public method
1 parent f369aa4 commit da8d480

5 files changed

Lines changed: 63 additions & 31 deletions

File tree

β€Žsrc/Component/BlazorComponent/Components/ItemGroup/BRoutableGroupItem.razor.csβ€Ž

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -82,14 +82,11 @@ private async Task<bool> UpdateActiveForRoutable()
8282
if (matched && ItemGroup is not null && !isActive)
8383
{
8484
await ItemGroup.ToggleAsync(Value);
85-
await OnActiveUpdatedForRoutable();
8685
}
8786

8887
return isActive != matched;
8988
}
9089

91-
protected virtual Task OnActiveUpdatedForRoutable() => Task.CompletedTask;
92-
9390
protected override ValueTask DisposeAsyncCore()
9491
{
9592
NavigationManager.LocationChanged -= OnLocationChanged;

β€Žsrc/Component/BlazorComponent/Components/ItemGroup/ItemGroupBase.csβ€Ž

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -72,9 +72,14 @@ private void RefreshItemsState()
7272
Items.ForEach(item => item.RefreshState());
7373
}
7474

75-
public virtual void Register(IGroupable item)
75+
protected virtual StringNumber InitDefaultItemValue()
7676
{
77-
item.Value ??= _registeredItemsIndex++;
77+
return _registeredItemsIndex++;
78+
}
79+
80+
internal virtual void Register(IGroupable item)
81+
{
82+
item.Value ??= InitDefaultItemValue();
7883

7984
Items.Add(item);
8085

@@ -109,7 +114,11 @@ public virtual void Register(IGroupable item)
109114
public virtual void Unregister(IGroupable item)
110115
{
111116
Items.Remove(item);
112-
_registeredItemsIndex--;
117+
118+
if (_registeredItemsIndex > 0)
119+
{
120+
_registeredItemsIndex--;
121+
}
113122
}
114123

115124
private async Task UpdateMandatoryAsync(bool last = false)

β€Žsrc/Component/BlazorComponent/Components/Tabs/BTab.razor.csβ€Ž

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -13,13 +13,6 @@ public BTab() : base(GroupType.SlideGroup)
1313

1414
protected override bool IsRoutable => Href != null && HasRoutableAncestor;
1515

16-
protected override async Task OnActiveUpdatedForRoutable()
17-
{
18-
if (Tabs == null) return;
19-
20-
await Tabs.CallSlider();
21-
}
22-
2316
protected override bool AfterHandleEventShouldRender() => false;
2417

2518
private async Task HandleOnClick(MouseEventArgs args)

β€Žsrc/Component/BlazorComponent/Components/Tabs/BTabs.razor.csβ€Ž

Lines changed: 50 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,8 @@ public EventCallback<StringNumber> ValueChanged
7070

7171
private StringNumber? _prevValue;
7272
private int _registeredTabItemsIndex;
73+
private bool _callSliderOnAfterRender;
74+
private CancellationTokenSource? _callSliderCts;
7375

7476
private List<ITabItem> TabItems { get; set; } = new();
7577

@@ -98,20 +100,25 @@ public bool IsDark
98100
}
99101

100102
List<ITabItem> ITabs.TabItems => TabItems;
101-
103+
102104
protected override async Task OnAfterRenderAsync(bool firstRender)
103105
{
104106
await base.OnAfterRenderAsync(firstRender);
105107

106108
if (firstRender)
107109
{
108110
await ResizeJSModule.ObserverAsync(Ref, OnResize);
109-
110-
await CallSlider();
111+
_callSliderOnAfterRender = true;
111112
}
112113
else if (_prevValue != Value)
113114
{
114115
_prevValue = Value;
116+
_callSliderOnAfterRender = true;
117+
}
118+
119+
if (_callSliderOnAfterRender)
120+
{
121+
_callSliderOnAfterRender = false;
115122
await CallSlider();
116123
}
117124
}
@@ -134,28 +141,45 @@ public void UnregisterTabItem(ITabItem tabItem)
134141
TabItems.Remove(tabItem);
135142
}
136143

144+
/// <summary>
145+
/// Re-render slider immediately. For the case of deleting tabs,
146+
/// it is recommended to use <see cref="CallSliderAfterRender"/>.
147+
/// </summary>
148+
[MasaApiPublicMethod]
137149
public async Task CallSlider()
138150
{
139151
if (HideSlider) return;
140152

141-
var item = Instance?.Items?.FirstOrDefault(item => item.Value == Instance.Value);
142-
if (item?.Ref.Context == null)
143-
{
144-
Slider = (0, 0, 0, 0, 0);
145-
}
146-
else
153+
_callSliderCts?.Cancel();
154+
_callSliderCts = new();
155+
156+
try
147157
{
148-
var el = await JsInvokeAsync<Web.Element>(JsInteropConstants.GetDomInfo, item.Ref);
149-
var height = !Vertical ? SliderSize.TryGetNumber().number : el.ScrollHeight;
150-
var left = Vertical ? 0 : el.OffsetLeft;
151-
var right = Vertical ? 0 : el.OffsetLeft + el.OffsetWidth;
152-
var top = el.OffsetTop;
158+
await Task.Delay(16, _callSliderCts.Token);
159+
160+
var item = Instance?.Items?.FirstOrDefault(item => item.Value == Instance.Value);
161+
if (item?.Ref.Context == null)
162+
{
163+
Slider = (0, 0, 0, 0, 0);
164+
}
165+
else
166+
{
167+
var el = await JsInvokeAsync<Web.Element>(JsInteropConstants.GetDomInfo, item.Ref);
168+
var height = !Vertical ? SliderSize.TryGetNumber().number : el.ScrollHeight;
169+
var left = Vertical ? 0 : el.OffsetLeft;
170+
var right = Vertical ? 0 : el.OffsetLeft + el.OffsetWidth;
171+
var top = el.OffsetTop;
153172
var width = Vertical ? SliderSize.TryGetNumber().number : el.ClientWidth; // REVIEW: el.ScrollWidth was used in Vuetify2
154173

155-
Slider = (height, left, right, top, width);
156-
}
174+
Slider = (height, left, right, top, width);
175+
}
157176

158-
StateHasChanged();
177+
StateHasChanged();
178+
}
179+
catch (TaskCanceledException)
180+
{
181+
// ignored
182+
}
159183
}
160184

161185
private async Task OnResize()
@@ -168,6 +192,15 @@ private async Task OnResize()
168192
await CallSlider();
169193
}
170194

195+
/// <summary>
196+
/// Re-render slider in <see cref="OnAfterRenderAsync"/>
197+
/// </summary>
198+
[MasaApiPublicMethod]
199+
public void CallSliderAfterRender()
200+
{
201+
_callSliderOnAfterRender = true;
202+
}
203+
171204
protected override async ValueTask DisposeAsyncCore()
172205
{
173206
await ResizeJSModule.UnobserveAsync(Ref);

β€Žsrc/Component/BlazorComponent/Components/Window/BWindow.razor.csβ€Ž

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ protected override void RegisterWatchers(PropertyWatcher watcher)
6868
true);
6969
}
7070

71-
public override void Register(IGroupable item)
71+
internal override void Register(IGroupable item)
7272
{
7373
base.Register(item);
7474

0 commit comments

Comments
Β (0)