fix(module: tabs): update the style of ink after tab title is changed (#3978)
* fix(module: tabs): update the style of ink after tab title is changed * fix test * fix test * fix test * fix test * fix tests
This commit is contained in:
Родитель
2695c105a1
Коммит
2286639039
|
@ -48,5 +48,17 @@ namespace AntDesign.JsInterop
|
|||
|
||||
[JsonPropertyName("selectionStart")]
|
||||
public decimal SelectionStart { get; set; }
|
||||
|
||||
[JsonPropertyName("marginTop")]
|
||||
public decimal MarginTop { get; set; }
|
||||
|
||||
[JsonPropertyName("marginBottom")]
|
||||
public decimal MarginBottom { get; set; }
|
||||
|
||||
[JsonPropertyName("marginLeft")]
|
||||
public decimal MarginLeft { get; set; }
|
||||
|
||||
[JsonPropertyName("marginRight")]
|
||||
public decimal MarginRight { get; set; }
|
||||
}
|
||||
}
|
||||
|
|
|
@ -28,6 +28,7 @@ export class infoHelper {
|
|||
domElement = {};
|
||||
}
|
||||
const absolutePosition = this.getElementAbsolutePos(domElement);
|
||||
const style = window.getComputedStyle(domElement);
|
||||
const result: domTypes.domInfo = {
|
||||
offsetTop: domElement.offsetTop || 0,
|
||||
offsetLeft: domElement.offsetLeft || 0,
|
||||
|
@ -43,7 +44,11 @@ export class infoHelper {
|
|||
clientWidth: domElement.clientWidth || 0,
|
||||
selectionStart: domElement.selectionStart || 0,
|
||||
absoluteTop: Math.round(absolutePosition.y),
|
||||
absoluteLeft: Math.round(absolutePosition.x)
|
||||
absoluteLeft: Math.round(absolutePosition.x),
|
||||
marginTop: parseFloat(style.marginTop),
|
||||
marginBottom: parseFloat(style.marginBottom),
|
||||
marginLeft: parseFloat(style.marginLeft),
|
||||
marginRight: parseFloat(style.marginRight)
|
||||
};
|
||||
return result;
|
||||
}
|
||||
|
|
|
@ -13,7 +13,11 @@
|
|||
clientWidth: number,
|
||||
selectionStart: number,
|
||||
absoluteTop: number,
|
||||
absoluteLeft: number
|
||||
absoluteLeft: number,
|
||||
marginTop: number,
|
||||
marginBottom: number,
|
||||
marginLeft: number,
|
||||
marginRight: number,
|
||||
}
|
||||
|
||||
export type position = {
|
||||
|
|
|
@ -71,7 +71,7 @@ namespace AntDesign
|
|||
}
|
||||
base.OnInitialized();
|
||||
ReuseTabsService.Init(true);
|
||||
ReuseTabsService.OnStateHasChanged += OnStateHasChanged;
|
||||
ReuseTabsService.OnStateHasChanged += InvokeStateHasChanged;
|
||||
|
||||
if (RouteData != null)
|
||||
{
|
||||
|
@ -89,7 +89,7 @@ namespace AntDesign
|
|||
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
ReuseTabsService.OnStateHasChanged -= OnStateHasChanged;
|
||||
ReuseTabsService.OnStateHasChanged -= InvokeStateHasChanged;
|
||||
Navmgr.LocationChanged -= OnLocationChanged;
|
||||
base.Dispose(disposing);
|
||||
}
|
||||
|
@ -113,12 +113,7 @@ namespace AntDesign
|
|||
ReuseTabsService.TrySetRouteData(ReuseTabsRouteData.RouteData, true);
|
||||
}
|
||||
|
||||
StateHasChanged();
|
||||
}
|
||||
|
||||
private void OnStateHasChanged()
|
||||
{
|
||||
_ = InvokeStateHasChangedAsync();
|
||||
InvokeStateHasChanged();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -20,7 +20,7 @@
|
|||
@ondrop="@(_ => Parent.HandleDrop(this))"
|
||||
class="@ClassMapper.Class"
|
||||
draggable="@Parent.Draggable.ToString()"
|
||||
id="@($"rc-tabs-{Id}-tab-{Key}")"
|
||||
id="@TabId"
|
||||
ondragover="event.preventDefault();">
|
||||
<div @onkeydown="@HandleKeydown"
|
||||
@ref="_tabBtnRef"
|
||||
|
|
|
@ -61,6 +61,8 @@ namespace AntDesign
|
|||
|
||||
internal ElementReference TabRef => _tabRef;
|
||||
|
||||
internal string TabId => $"rc-tabs-{Id}-tab-{Key}";
|
||||
|
||||
internal ElementReference TabBtnRef => _tabBtnRef;
|
||||
|
||||
private ClassMapper _tabPaneClassMapper = new();
|
||||
|
@ -95,6 +97,16 @@ namespace AntDesign
|
|||
}
|
||||
}
|
||||
|
||||
public override async Task SetParametersAsync(ParameterView parameters)
|
||||
{
|
||||
if (parameters.IsParameterChanged(nameof(Tab), Tab))
|
||||
{
|
||||
Parent?.UpdateTabsPosition();
|
||||
}
|
||||
|
||||
await base.SetParametersAsync(parameters);
|
||||
}
|
||||
|
||||
private void SetClass()
|
||||
{
|
||||
ClassMapper
|
||||
|
|
|
@ -13,8 +13,8 @@
|
|||
</div>
|
||||
}
|
||||
|
||||
<div class="@_tabsNavWarpPingClassMapper.Class" @ref="@_navWarpRef">
|
||||
<div class="ant-tabs-nav-list" style="@_navListStyle" @ref="@_navListRef">
|
||||
<div class="@_tabsNavWarpPingClassMapper.Class" @ref="@_navWarpRef" id="@(Id)-nav-warpper">
|
||||
<div class="ant-tabs-nav-list" style="@_navListStyle" @ref="@_navListRef" id="@(Id)-nav-list">
|
||||
<CascadingValue Value="true" Name="IsTab" IsFixed="true">
|
||||
@ChildContent
|
||||
</CascadingValue>
|
||||
|
|
|
@ -161,6 +161,7 @@ namespace AntDesign
|
|||
private TabPane _activePane;
|
||||
private TabPane _activeTab;
|
||||
private HtmlElement _activeTabElement;
|
||||
private Dictionary<string, HtmlElement> _itemRefs;
|
||||
|
||||
private string _activeKey;
|
||||
private TabPane _renderedActivePane;
|
||||
|
@ -192,6 +193,7 @@ namespace AntDesign
|
|||
private readonly List<TabPane> _tabs = new List<TabPane>();
|
||||
private List<TabPane> _invisibleTabs = new List<TabPane>();
|
||||
|
||||
|
||||
private bool NavWrapPingLeft => _scrollOffset > 0;
|
||||
private bool NavWrapPingRight => _scrollListWidth - _wrapperWidth - _scrollOffset > 0;
|
||||
|
||||
|
@ -441,14 +443,11 @@ namespace AntDesign
|
|||
}
|
||||
|
||||
_activeKey = _activePane.Key;
|
||||
|
||||
TryRenderInk();
|
||||
}
|
||||
|
||||
Card?.SetBody(_activePane.ChildContent);
|
||||
|
||||
_needUpdateScrollListPosition = true;
|
||||
|
||||
_shouldRender = true;
|
||||
InvokeAsync(StateHasChanged);
|
||||
}
|
||||
|
||||
protected override async Task OnAfterRenderAsync(bool firstRender)
|
||||
|
@ -478,15 +477,18 @@ namespace AntDesign
|
|||
|
||||
private async Task ResetSizes()
|
||||
{
|
||||
var navList = await JsInvokeAsync<HtmlElement>(JSInteropConstants.GetDomInfo, _navListRef);
|
||||
var navWarp = await JsInvokeAsync<HtmlElement>(JSInteropConstants.GetDomInfo, _navWarpRef);
|
||||
|
||||
_activeTabElement = await JsInvokeAsync<HtmlElement>(JSInteropConstants.GetDomInfo, _activeTab.TabRef);
|
||||
ElementReference[] refs = [_navListRef, _navWarpRef, .. _tabs.Select(x => x.TabRef).ToArray()];
|
||||
_itemRefs = await JsInvokeAsync<Dictionary<string, HtmlElement>>(JSInteropConstants.GetElementsDomInfo, refs);
|
||||
var navList = _itemRefs[Id + "-nav-list"];
|
||||
var navWarp = _itemRefs[Id + "-nav-warpper"];
|
||||
|
||||
_scrollListWidth = navList.ClientWidth;
|
||||
_scrollListHeight = navList.ClientHeight;
|
||||
_wrapperWidth = navWarp.ClientWidth;
|
||||
_wrapperHeight = navWarp.ClientHeight;
|
||||
|
||||
_itemRefs.Remove(Id + "-nav-list");
|
||||
_itemRefs.Remove(Id + "-nav-warpper");
|
||||
}
|
||||
|
||||
private void UpdateScrollListPosition()
|
||||
|
@ -571,6 +573,19 @@ namespace AntDesign
|
|||
|
||||
private void TryRenderInk()
|
||||
{
|
||||
if (!_afterFirstRender)
|
||||
{
|
||||
_needUpdateScrollListPosition = true;
|
||||
StateHasChanged();
|
||||
return;
|
||||
}
|
||||
|
||||
if (_itemRefs is not { Count: > 0 })
|
||||
{
|
||||
return;
|
||||
}
|
||||
_activeTabElement = _itemRefs[_activeTab.TabId];
|
||||
|
||||
if (IsHorizontal)
|
||||
{
|
||||
_inkStyle = $"left: {_activeTabElement.OffsetLeft}px; width: {_activeTabElement.ClientWidth}px";
|
||||
|
@ -608,6 +623,7 @@ namespace AntDesign
|
|||
}
|
||||
}
|
||||
|
||||
_shouldRender = true;
|
||||
StateHasChanged();
|
||||
_renderedActivePane = _activePane;
|
||||
}
|
||||
|
@ -617,6 +633,12 @@ namespace AntDesign
|
|||
return _shouldRender || _renderedActivePane != _activePane;
|
||||
}
|
||||
|
||||
internal void UpdateTabsPosition()
|
||||
{
|
||||
_needUpdateScrollListPosition = true;
|
||||
_shouldRender = true;
|
||||
}
|
||||
|
||||
private void OnVisibleChange(bool visible)
|
||||
{
|
||||
if (!visible)
|
||||
|
@ -626,24 +648,37 @@ namespace AntDesign
|
|||
}
|
||||
|
||||
int invisibleHeadCount;
|
||||
decimal tabSize, visibleCount;
|
||||
int visibleCount;
|
||||
|
||||
if (IsHorizontal)
|
||||
{
|
||||
tabSize = _scrollListWidth / _tabs.Count;
|
||||
visibleCount = Math.Ceiling(_wrapperWidth / tabSize);
|
||||
var tabWidths = _itemRefs.Values.Select(x => x.OffsetWidth + x.MarginLeft + x.MarginRight).ToArray();
|
||||
invisibleHeadCount = GetOverflowCount(_scrollOffset, tabWidths);
|
||||
visibleCount = GetOverflowCount(_scrollOffset + _wrapperWidth, tabWidths, true) - invisibleHeadCount;
|
||||
}
|
||||
else
|
||||
{
|
||||
tabSize = _scrollListHeight / _tabs.Count;
|
||||
visibleCount = Math.Ceiling(_wrapperHeight / tabSize);
|
||||
var tabHeights = _itemRefs.Values.Select(x => x.ClientHeight + x.MarginTop + x.MarginBottom).ToArray();
|
||||
invisibleHeadCount = GetOverflowCount(_scrollOffset, tabHeights);
|
||||
visibleCount = GetOverflowCount(_scrollOffset + _wrapperHeight, tabHeights, true) - invisibleHeadCount;
|
||||
}
|
||||
|
||||
invisibleHeadCount = (int)Math.Ceiling(_scrollOffset / tabSize);
|
||||
visibleCount = Math.Min(visibleCount, _tabs.Count - invisibleHeadCount);
|
||||
|
||||
_invisibleTabs = _tabs.ToList();
|
||||
_invisibleTabs.RemoveRange(invisibleHeadCount, (int)visibleCount);
|
||||
_invisibleTabs.RemoveRange(invisibleHeadCount, visibleCount);
|
||||
}
|
||||
|
||||
private static int GetOverflowCount(decimal maxLength, decimal[] lengths, bool isRight = false)
|
||||
{
|
||||
var sum = 0m;
|
||||
for (var i = 0; i < lengths.Length; i++)
|
||||
{
|
||||
sum += lengths[i];
|
||||
if (sum - maxLength >= lengths[i] * (isRight ? 0.2m : 0.6m))
|
||||
{
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return lengths.Length;
|
||||
}
|
||||
|
||||
#region DRAG & DROP
|
||||
|
|
|
@ -1,18 +1,32 @@
|
|||
<Tabs @bind-ActiveKey="@activeKey" OnChange="OnTabChange" Animated>
|
||||
<TabPane Tab="Tab 1" Key="1">
|
||||
Content of Tab Pane 1
|
||||
<TabPane Key="1">
|
||||
<TabTemplate>
|
||||
@tab
|
||||
</TabTemplate>
|
||||
<ChildContent>
|
||||
Content of Tab Pane 1
|
||||
</ChildContent>
|
||||
</TabPane>
|
||||
<TabPane Tab="Tab 2" Key="2">
|
||||
Content of Tab Pane 2
|
||||
Content of Tab Pane 2
|
||||
</TabPane>
|
||||
<TabPane Tab="Tab 3" Key="3">
|
||||
Content of Tab Pane 3
|
||||
</TabPane>
|
||||
</Tabs>
|
||||
|
||||
<Button OnClick="OnClick">Click</Button>
|
||||
|
||||
@code{
|
||||
string activeKey { get; set; } = "1";
|
||||
|
||||
string tab = "tab1";
|
||||
|
||||
void OnClick()
|
||||
{
|
||||
tab += tab;
|
||||
}
|
||||
|
||||
void OnTabChange(string key)
|
||||
{
|
||||
Console.WriteLine($"tab change:{key}");
|
||||
|
|
|
@ -28,7 +28,11 @@ const domInfoDefaults: domInfo = {
|
|||
clientWidth: 0,
|
||||
selectionStart: 0,
|
||||
absoluteTop: 0,
|
||||
absoluteLeft: 0
|
||||
absoluteLeft: 0,
|
||||
marginTop: 0,
|
||||
marginBottom: 0,
|
||||
marginLeft: 0,
|
||||
marginRight: 0,
|
||||
}
|
||||
|
||||
type cooridnates = {
|
||||
|
|
|
@ -92,6 +92,7 @@
|
|||
//Arrange
|
||||
JSInterop.SetupVoid(JSInteropConstants.StyleHelper.AddCls, _ => true).SetVoidResult();
|
||||
JSInterop.Setup<HtmlElement>(JSInteropConstants.DomInfoHelper.GetInfo, _ => true).SetResult(new());
|
||||
JSInterop.Setup<Dictionary<string, HtmlElement>>("AntDesign.interop.domInfoHelper.getElementsInfo", _ => true);
|
||||
var cut = Render<AntDesign.Card>(
|
||||
@<Card Title=@("Card title")>
|
||||
<CardTabs>
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
.SetResult(new AntDesign.JsInterop.Window());
|
||||
JSInterop.SetupVoid("AntDesign.interop.styleHelper.addCls", _ => true);
|
||||
JSInterop.Setup<HtmlElement>("AntDesign.interop.domInfoHelper.getInfo", _ => true);
|
||||
JSInterop.Setup<Dictionary<string, HtmlElement>>("AntDesign.interop.domInfoHelper.getElementsInfo", _ => true);
|
||||
var model = new Model
|
||||
{
|
||||
Text = "test"
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using AntDesign.JsInterop;
|
||||
using Bunit;
|
||||
using Microsoft.AspNetCore.Components;
|
||||
|
@ -21,11 +22,18 @@ namespace AntDesign.Tests.Tabs
|
|||
var jsRuntime = new Mock<IJSRuntime>();
|
||||
jsRuntime.Setup(u => u.InvokeAsync<HtmlElement>(JSInteropConstants.GetDomInfo, It.IsAny<object[]>()))
|
||||
.ReturnsAsync(new HtmlElement());
|
||||
jsRuntime.Setup(u => u.InvokeAsync<Dictionary<string, HtmlElement>>(JSInteropConstants.GetElementsDomInfo, It.IsAny<object[]>()))
|
||||
.ReturnsAsync(new Dictionary<string, HtmlElement>() {
|
||||
["1-nav-list"] = new HtmlElement() { },
|
||||
["1-nav-warpper"] = new HtmlElement() { },
|
||||
["rc-tabs-2-tab-2"] = new HtmlElement() { },
|
||||
});
|
||||
|
||||
Context.Services.AddScoped(_ => jsRuntime.Object);
|
||||
|
||||
var cut = Context.RenderComponent<AntDesign.Tabs>(tabs => tabs
|
||||
.Add(x => x.DefaultActiveKey, "2")
|
||||
.Add(x => x.Id, "1")
|
||||
.Add(b => b.ChildContent, b => childContent(b))
|
||||
);
|
||||
|
||||
|
@ -36,6 +44,7 @@ namespace AntDesign.Tests.Tabs
|
|||
{
|
||||
var tabPane1Builder = new ComponentParameterCollectionBuilder<TabPane>()
|
||||
.Add(x => x.Key, key)
|
||||
.Add(x => x.Id, key)
|
||||
.Add(x => x.Tab, $"Tab {key}")
|
||||
.Add(x => x.ChildContent, $"Content {key}".ToRenderFragment());
|
||||
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
{
|
||||
JSInterop.Setup<HtmlElement>(JSInteropConstants.GetDomInfo, _ => true)
|
||||
.SetResult(new HtmlElement());
|
||||
|
||||
JSInterop.Setup<Dictionary<string, HtmlElement>>("AntDesign.interop.domInfoHelper.getElementsInfo", _ => true);
|
||||
JSInterop.SetupVoid(JSInteropConstants.StyleHelper.AddClsToFirstChild, _ => true);
|
||||
JSInterop.SetupVoid(JSInteropConstants.StyleHelper.AddCls, _ => true);
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче