Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

⚡ (Tabs): use js interop to calculate and set the position of slider #2040

Merged
merged 2 commits into from
Jul 16, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 35 additions & 0 deletions src/Masa.Blazor.JS/src/interop.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1592,3 +1592,38 @@ export function unregisterTableScrollEvent(wrapper: HTMLElement) {
delete wrapper["_m_table_scroll_event"]
}
}

export function updateTabSlider(
sliderWrapper: HTMLElement,
tab: HTMLElement,
sliderSize: number,
vertical: boolean,
isReversed: boolean
) {
if (!sliderWrapper) {
console.warn('[MTab] the element of slider wrapper is not found')
return;
}

if (!tab) {
console.warn('[MTab] the element of tab to be activated is not found')
return;
}

const height = !vertical ? sliderSize : tab.scrollHeight;
const left = vertical ? 0 : tab.offsetLeft;
const right = vertical ? 0 : tab.offsetLeft + tab.offsetWidth;
const top = tab.offsetTop;
const width = vertical ? sliderSize : tab.clientWidth;
sliderWrapper.style.width = `${width}px`;
sliderWrapper.style.height = `${height}px`;
if (!isReversed) {
sliderWrapper.style.left = `${left}px`;
}
if (isReversed) {
sliderWrapper.style.right = `${right}px`;
}
if (vertical) {
sliderWrapper.style.top = `${top}px`;
}
}
Empty file.
Empty file.
6 changes: 3 additions & 3 deletions src/Masa.Blazor/Components/ItemGroup/MGroupable.cs
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@ protected override async Task OnInitializedAsync()

if (this is IGroupable item)
{
ItemGroup!.Register(item);
await ItemGroup!.Register(item);
}

await base.OnInitializedAsync();
Expand Down Expand Up @@ -132,10 +132,9 @@ public async Task RefreshState()
if (!Matched || HasRoutableAncestor) return;

await SetInternalIsActive(ValueMatched);
StateHasChanged();
}

protected virtual async Task ToggleAsync()
protected async Task ToggleAsync()
{
if (!Matched) return;

Expand All @@ -149,6 +148,7 @@ protected async Task SetInternalIsActive(bool val, bool force = false)
if (InternalIsActive != val || force)
{
InternalIsActive = val;
StateHasChanged();
}
}
else
Expand Down
39 changes: 19 additions & 20 deletions src/Masa.Blazor/Components/ItemGroup/MItemGroupBase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,10 @@ internal List<StringNumber?> InternalValues
set => SetValue(value);
}

protected StringNumber? InternalValue => InternalValues?.LastOrDefault();
protected StringNumber? InternalValue => InternalValues.LastOrDefault();

private HashSet<StringNumber?> _prevInternalValues = [];
private CancellationTokenSource? _cts;

protected override void OnParametersSet()
{
Expand All @@ -64,10 +67,14 @@ protected override void OnParametersSet()
GroupType = TargetGroup.Value;
}

RefreshItemsState();
if (!_prevInternalValues.SetEquals(InternalValues))
{
_prevInternalValues = [..InternalValues];
RefreshItemsState();
}
}

private void RefreshItemsState()
protected virtual void RefreshItemsState()
{
Items.ForEach(item => item.RefreshState());
}
Expand All @@ -77,7 +84,7 @@ protected StringNumber InitDefaultItemValue()
return _registeredItemsIndex++;
}

internal virtual void Register(IGroupable item)
internal virtual async Task Register(IGroupable item)
{
item.Value ??= InitDefaultItemValue();

Expand All @@ -89,26 +96,22 @@ internal virtual void Register(IGroupable item)
{
if (InternalValues.Count == 0)
{
InternalValues = new List<StringNumber?>() { item.Value };
InternalValues = [item.Value];

if (Multiple)
{
if (ValuesChanged.HasDelegate)
{
ValuesChanged.InvokeAsync(InternalValues.ToList());
}
await ValuesChanged.InvokeAsync(InternalValues.ToList());
}
else
{
if (ValueChanged.HasDelegate)
{
ValueChanged.InvokeAsync(item.Value);
}
await ValueChanged.InvokeAsync(item.Value);
}
}
}

RefreshItemsState();
_cts?.Cancel();
_cts = new CancellationTokenSource();
await RunTaskInMicrosecondsAsync(RefreshItemsState, 16, _cts.Token);
}

public virtual void Unregister(IGroupable item)
Expand Down Expand Up @@ -153,8 +156,6 @@ public async Task ToggleAsync(StringNumber? key)
{
InternalValues = Values.ToList();
}

StateHasChanged();
}
}
else
Expand All @@ -170,8 +171,6 @@ public async Task ToggleAsync(StringNumber? key)
{
InternalValues = new List<StringNumber?>() { Value };
}

StateHasChanged();
}
}

Expand All @@ -184,13 +183,13 @@ private void InitOrUpdateInternalValues()
{
if (!IsDirtyParameter(nameof(Values))) return;

InternalValues = Values == null ? new List<StringNumber?>() : Values.ToList();
InternalValues = Values == null ? [] : Values.ToList();
}
else
{
if (!IsDirtyParameter(nameof(Value))) return;

InternalValues = Value == null ? new List<StringNumber?>() : new List<StringNumber?>() { Value };
InternalValues = Value == null ? [] : [Value];
}
}

Expand Down
16 changes: 9 additions & 7 deletions src/Masa.Blazor/Components/Tabs/MTab.razor
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,13 @@
@inherits MRoutableGroupItem<MItemGroupBase>

<MElement Tag="@Tag"
Class="@GetClass()"
Style="@GetStyle()"
ReferenceCaptureAction="r => Ref = r"
id="@Id"
@onclick="HandleOnClick"
@attributes="@Attributes">
@ChildContent
Class="@GetClass()"
Style="@GetStyle()"
ReferenceCaptureAction="r => Ref = r"
id="@Id"
@onclick="HandleOnClick"
@attributes="@Attributes">
<MShouldRender Value="InternalIsActive">
@ChildContent
</MShouldRender>
</MElement>
12 changes: 2 additions & 10 deletions src/Masa.Blazor/Components/Tabs/MTabs.razor
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
PrevIcon="@PrevIcon"
ShowArrows="@ShowArrows"
Value="@Value"
ValueChanged="@ValueChanged"
ValueChanged="@OnValueChanged"
Color="@Color"
ActiveClass="@ActiveClass"
CenterActive="@CenterActive"
Expand Down Expand Up @@ -54,16 +54,8 @@

private RenderFragment GenSlider() => __builder =>
{
var style = StyleBuilder.Create()
.AddWidth(Slider.width)
.AddHeight(Slider.height)
.AddIf("left", Slider.left.ToUnit(), !IsReversed)
.AddIf("right", Slider.right.ToUnit(), IsReversed)
.AddIf("top", Slider.top.ToUnit(), Vertical)
.AddIf("transition", "none", Slider.left == null);

<div class="m-tabs-slider-wrapper"
style="@style">
@ref="@_sliderWrapperRef">
<div class="@GetClass("m-tabs-slider", CssClassUtils.GetBackgroundColor(SliderColor))"
style="@(StyleBuilder.Create().AddBackgroundColor(SliderColor))">
</div>
Expand Down
94 changes: 27 additions & 67 deletions src/Masa.Blazor/Components/Tabs/MTabs.razor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -47,25 +47,9 @@ public partial class MTabs : MasaComponentBase, IThemeable
[Parameter] public string? SliderColor { get; set; }

[Parameter] [MasaApiParameter(2)] public StringNumber SliderSize { get; set; } = 2;

[Parameter] public StringNumber? Value { get; set; }

private EventCallback<StringNumber>? _valueChanged;

[Parameter]
public EventCallback<StringNumber> ValueChanged
{
get
{
if (_valueChanged.HasValue)
{
return _valueChanged.Value;
}

return EventCallback.Factory.Create<StringNumber>(this, (v) => Value = v);
}
set => _valueChanged = value;
}
[Parameter] public EventCallback<StringNumber?> ValueChanged { get; set; }

[Parameter] public bool Vertical { get; set; }

Expand All @@ -80,10 +64,10 @@ public EventCallback<StringNumber> ValueChanged
[Parameter] public bool Dark { get; set; }

[Parameter] public bool Light { get; set; }
private StringNumber? _prevValue;
private int _registeredTabItemsIndex;
private bool _callSliderOnAfterRender;
private CancellationTokenSource? _callSliderCts;
private ElementReference _sliderWrapperRef;
private bool _isFirstRender = true;

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

Expand Down Expand Up @@ -132,17 +116,7 @@ protected override async Task OnAfterRenderAsync(bool firstRender)
{
await ResizeJSModule.ObserverAsync(Ref, OnResize);
await IntersectJSModule.ObserverAsync(Ref, OnIntersectAsync);
_callSliderOnAfterRender = true;
}
else if (_prevValue != Value)
{
_prevValue = Value;
_callSliderOnAfterRender = true;
}

if (_callSliderOnAfterRender)
{
_callSliderOnAfterRender = false;
_isFirstRender = false;
await CallSlider();
}
}
Expand All @@ -158,7 +132,7 @@ protected override void OnParametersSet()
if (MasaBlazor.IsSsr && !IndependentTheme)
{
CascadingIsDark = MasaBlazor.Theme.Dark;
}
}
}
#endif

Expand Down Expand Up @@ -187,9 +161,19 @@ private async Task OnIntersectAsync(IntersectEventArgs e)
}
}

private async Task OnValueChanged(StringNumber? val)
{
if (Value == val)
{
return;
}
Value = val;
await ValueChanged.InvokeAsync(val);
}

public bool IsReversed => RTL && Vertical;

public MSlideGroup? Instance => TabsBarRef as MSlideGroup;
public MItemGroup? Instance => TabsBarRef as MItemGroup;

public void RegisterTabItem(ITabItem tabItem)
{
Expand All @@ -212,40 +196,16 @@ public void UnregisterTabItem(ITabItem tabItem)
[MasaApiPublicMethod]
public async Task CallSlider()
{
if (HideSlider) return;

_callSliderCts?.Cancel();
_callSliderCts = new();

try
{
await Task.Delay(16, _callSliderCts.Token);

var item = Instance?.Items?.FirstOrDefault(item => item.Value == Instance.Value);
if (item?.Ref.Context == null)
{
Slider = (0, 0, 0, 0, 0);
}
else
{
var el = await Js.InvokeAsync<Masa.Blazor.JSInterop.Element>(JsInteropConstants.GetDomInfo, item.Ref);
var height = !Vertical ? SliderSize.TryGetNumber().number : el.ScrollHeight;
var left = Vertical ? 0 : el.OffsetLeft;
var right = Vertical ? 0 : el.OffsetLeft + el.OffsetWidth;
var top = el.OffsetTop;
var width = Vertical
? SliderSize.TryGetNumber().number
: el.ClientWidth; // REVIEW: el.ScrollWidth was used in Vuetify2

Slider = (height, left, right, top, width);
}

StateHasChanged();
}
catch (TaskCanceledException)
{
// ignored
}
if (HideSlider || _isFirstRender) return;

var item = Instance?.Items.FirstOrDefault(item => item.Value == Value);
await Js.InvokeVoidAsync(
JsInteropConstants.UpdateTabSlider,
_sliderWrapperRef,
item?.Ref,
SliderSize.TryGetNumber().number,
Vertical,
IsReversed);
}

private async Task OnResize()
Expand All @@ -264,7 +224,7 @@ private async Task OnResize()
[MasaApiPublicMethod]
public void CallSliderAfterRender()
{
_callSliderOnAfterRender = true;
NextTick(CallSlider);
}

protected override async ValueTask DisposeAsyncCore()
Expand Down
7 changes: 7 additions & 0 deletions src/Masa.Blazor/Components/Tabs/MTabsBar.cs
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,13 @@ protected override IEnumerable<string> BuildContentClass()
return base.BuildContentClass().Concat(new[] { _block.Element("content").Name });
}

protected override void RefreshItemsState()
{
base.RefreshItemsState();

Tabs?.CallSlider();
}

public override void Unregister(IGroupable item)
{
base.Unregister(item);
Expand Down
7 changes: 0 additions & 7 deletions src/Masa.Blazor/Components/Window/MWindow.razor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -116,13 +116,6 @@ protected override void RegisterWatchers(PropertyWatcher watcher)
watcher.Watch<List<StringNumber?>>(nameof(InternalValues), UpdateInternalIndex);
}

internal override void Register(IGroupable item)
{
base.Register(item);

StateHasChanged();
}

public void RenderState()
{
StateHasChanged();
Expand Down
Loading
Loading