Skip to content

Commit 8518bf8

Browse files
authored
feat(Tab): add TabStyle parameter (#5640)
* feat: 增加 IsChromeStyle 参数 * refactor: 调整禁用逻辑禁用后不允许 active 样式 * style: 重构样式 * refactor: 增加 tabs-chrome 样式 * refactor: 调整样式 * doc: 增加示例文档 * refactor: 增加 TabStyle 参数 * doc: 更新文档 * doc: 更新参数文档 * test: 更新单元测试 * refactor: 增加 Placement 参数限制 * doc: 更新文档 * test: 更新单元测试 * doc: 更新示例 * style: 调整样式 * style: 更新样式 * style: 更新样式 * style: 更新样式
1 parent ab74cb4 commit 8518bf8

File tree

10 files changed

+313
-38
lines changed

10 files changed

+313
-38
lines changed

src/BootstrapBlazor.Server/Components/Layout/ComponentLayout.razor

+1-1
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@
3030
</div>
3131

3232
<div class="tabs-coms">
33-
<Tab IsBorderCard="true" IsLazyLoadTabItem="true" ShowFullScreen="true" @ref="Tab">
33+
<Tab IsBorderCard="true" IsLazyLoadTabItem="true" ShowFullScreen="true" TabStyle="TabStyle.Chrome" @ref="Tab">
3434
<TabItem Text="Example" Icon="fa-solid fa-desktop">
3535
<CascadingValue Value="@RazorFileName" Name="RazorFileName">
3636
@Body

src/BootstrapBlazor.Server/Components/Samples/Tabs.razor

+17
Original file line numberDiff line numberDiff line change
@@ -436,6 +436,23 @@ private void Navigation()
436436
</Tab>
437437
</DemoBlock>
438438

439+
<DemoBlock Title="@Localizer["TabsChromeStyleTitle"]" Introduction="@Localizer["TabsChromeStyleIntro"]" Name="TabStyle">
440+
<Tab IsCard="true" ShowClose="true" TabStyle="TabStyle.Chrome">
441+
<TabItem Text="@Localizer["TabItem1Text"]" Icon="fa-solid fa-user">
442+
<div>@Localizer["TabItem1Content"]</div>
443+
</TabItem>
444+
<TabItem Text="@Localizer["TabItem2Text"]" Icon="fa-solid fa-gauge-high">
445+
<div>@Localizer["TabItem2Content"]</div>
446+
</TabItem>
447+
<TabItem Text="@Localizer["TabItem3Text"]" Icon="fa-solid fa-sitemap">
448+
<div>@Localizer["TabItem3Content"]</div>
449+
</TabItem>
450+
<TabItem Text="@Localizer["TabItem4Text"]" Icon="fa-solid fa-building-columns">
451+
<div>@Localizer["TabItem4Content"]</div>
452+
</TabItem>
453+
</Tab>
454+
</DemoBlock>
455+
439456
<AttributeTable Items="@GetAttributes()" Title="@Localizer["AttTitle"]" />
440457

441458
<MethodTable Items="@GetMethods()" Title="@Localizer["MethodTitle"]" />

src/BootstrapBlazor.Server/Components/Samples/Tabs.razor.cs

+14-6
Original file line numberDiff line numberDiff line change
@@ -204,7 +204,7 @@ private AttributeItem[] GetAttributes() =>
204204
new()
205205
{
206206
Name = "IsLazyLoadTabItem",
207-
Description = Localizer["AttributeIsLazyLoadTabItem"].Value,
207+
Description = Localizer["TabAttIsLazyLoadTabItem"].Value,
208208
Type = "boolean",
209209
ValueList = "true/false",
210210
DefaultValue = "false"
@@ -222,21 +222,21 @@ private AttributeItem[] GetAttributes() =>
222222
Name = "ShowExtendButtons",
223223
Description = Localizer["TabAtt5ShowExtendButtons"].Value,
224224
Type = "boolean",
225-
ValueList = "",
225+
ValueList = "true|false",
226226
DefaultValue = "false"
227227
},
228228
new()
229229
{
230-
Name = "ShowExtendButtons",
231-
Description = Localizer["TabAttrShowNavigatorButtons"].Value,
230+
Name = "ShowNavigatorButtons",
231+
Description = Localizer["TabAttShowNavigatorButtons"].Value,
232232
Type = "boolean",
233233
ValueList = "true|false",
234234
DefaultValue = "true"
235235
},
236236
new()
237237
{
238-
Name = "ShowExtendButtons",
239-
Description = Localizer["TabAttrShowActiveBar"].Value,
238+
Name = "ShowActiveBar",
239+
Description = Localizer["TabAttShowActiveBar"].Value,
240240
Type = "boolean",
241241
ValueList = "true|false",
242242
DefaultValue = "true"
@@ -250,6 +250,14 @@ private AttributeItem[] GetAttributes() =>
250250
DefaultValue = "false"
251251
},
252252
new()
253+
{
254+
Name = "TabStyle",
255+
Description = Localizer["TabAtt2TabStyle"].Value,
256+
Type = "TabStyle",
257+
ValueList = "Default|Chrome",
258+
DefaultValue = "Default"
259+
},
260+
new()
253261
{
254262
Name = "Placement",
255263
Description = Localizer["TabAtt7Placement"].Value,

src/BootstrapBlazor.Server/Locales/en-US.json

+5-1
Original file line numberDiff line numberDiff line change
@@ -2083,6 +2083,7 @@
20832083
"TabAtt5ShowExtendButtons": "Whether to display the extension button",
20842084
"TabAttShowNavigatorButtons": "Whether to display the previous and next navigation buttons",
20852085
"TabAttShowActiveBar": "Whether to display active bar",
2086+
"TabAttIsLazyLoadTabItem": "Whether lazy load tab item",
20862087
"TabAtt6ClickTabToNavigation": "Whether to navigate when you click on the title",
20872088
"TabAtt7Placement": "Set the label position",
20882089
"TabAtt8Height": "Set the label height",
@@ -2116,7 +2117,10 @@
21162117
"AttributeExcludeUrls": "Exclude address support for wildcards",
21172118
"AttributeButtonTemplate": "The template for Buttons",
21182119
"TabsDisabledTitle": "Disabled",
2119-
"TabsDisabledIntro": "Disable the current <code>TabItem</code> by setting <code>IsDisabled=\"true\"</code> to prohibit click, drag, close etc."
2120+
"TabsDisabledIntro": "Disable the current <code>TabItem</code> by setting <code>IsDisabled=\"true\"</code> to prohibit click, drag, close etc.",
2121+
"TabsChromeStyleTitle": "Chrome Style",
2122+
"TabsChromeStyleIntro": "Set the Chrome browser tab style by setting <code>TabStyle=\"TabStyle.Chrome\"</code>. Currently only supports <code>Placement=\"Placement.Top\"</code> mode",
2123+
"TabAtt2TabStyle": "Set the tab style"
21202124
},
21212125
"BootstrapBlazor.Server.Components.Components.DemoTabItem": {
21222126
"Info": "Reset the title of this <code>TabItem</code> by click the button",

src/BootstrapBlazor.Server/Locales/zh-CN.json

+5-1
Original file line numberDiff line numberDiff line change
@@ -2083,6 +2083,7 @@
20832083
"TabAtt5ShowExtendButtons": "是否显示扩展按钮",
20842084
"TabAttShowNavigatorButtons": "是否显示前后导航按钮",
20852085
"TabAttShowActiveBar": "是否显示活动标签",
2086+
"TabAttIsLazyLoadTabItem": "是否延时加载标签内容",
20862087
"TabAtt6ClickTabToNavigation": "点击标题时是否导航",
20872088
"TabAtt7Placement": "设置标签位置",
20882089
"TabAtt8Height": "设置标签高度",
@@ -2116,7 +2117,10 @@
21162117
"AttributeExcludeUrls": "排除地址支持通配符",
21172118
"AttributeButtonTemplate": "按钮模板",
21182119
"TabsDisabledTitle": "禁用",
2119-
"TabsDisabledIntro": "通过设置 <code>IsDisabled=\"true\"</code> 禁用当前 <code>TabItem</code> 禁止点击、拖动、关闭等操作"
2120+
"TabsDisabledIntro": "通过设置 <code>IsDisabled=\"true\"</code> 禁用当前 <code>TabItem</code> 禁止点击、拖动、关闭等操作",
2121+
"TabsChromeStyleTitle": "Chrome 样式",
2122+
"TabsChromeStyleIntro": "通过设置 <code>TabStyle=\"TabStyle.Chrome\"</code> 设置 Chrome 浏览器标签页样式,目前仅支持 <code>Placement=\"Placement.Top\"</code> 模式",
2123+
"TabAtt2TabStyle": "设置标签页样式"
21202124
},
21212125
"BootstrapBlazor.Server.Components.Components.DemoTabItem": {
21222126
"Info": "点击下方按钮,本 <code>TabItem</code> 标题更改为当前分钟与秒",

src/BootstrapBlazor/Components/Tab/Tab.razor

+53-25
Original file line numberDiff line numberDiff line change
@@ -45,39 +45,17 @@ else
4545
}
4646
@foreach (var item in Items)
4747
{
48-
if (item.HeaderTemplate != null)
48+
@if (item.HeaderTemplate != null)
4949
{
5050
@item.HeaderTemplate(item)
5151
}
5252
else if (item.IsDisabled)
5353
{
54-
<div role="tab" class="@GetClassString(item)">
55-
@if (!string.IsNullOrEmpty(item.Icon))
56-
{
57-
<i class="@GetIconClassString(item.Icon)"></i>
58-
}
59-
<span class="tabs-item-text">@item.Text</span>
60-
</div>
54+
@RenderDisabledHeaderByStyle(item)
6155
}
6256
else
6357
{
64-
<a @key="item" href="@item.Url" role="tab" tabindex="-1" class="@GetClassString(item)" @onclick="@(() => OnClickTabItem(item))" @onclick:preventDefault="@(!ClickTabToNavigation)" draggable="@DraggableString">
65-
@if (!string.IsNullOrEmpty(item.Icon))
66-
{
67-
<i class="@GetIconClassString(item.Icon)"></i>
68-
}
69-
<span class="tabs-item-text">@item.Text</span>
70-
@if (ShowFullScreen && item.ShowFullScreen)
71-
{
72-
<FullScreenButton TargetId="@GetIdByTabItem(item)"></FullScreenButton>
73-
}
74-
@if (ShowClose && item.Closable)
75-
{
76-
<span class="tabs-item-close" @onclick:stopPropagation @onclick:preventDefault @onclick="() => RemoveTab(item)">
77-
<i class="@CloseIcon"></i>
78-
</span>
79-
}
80-
</a>
58+
@RenderHeaderByStyle(item)
8159
}
8260
}
8361
@if (IsCard || IsBorderCard)
@@ -145,4 +123,54 @@ else
145123
@<CascadingValue Value="item" IsFixed="true">
146124
@RenderTabItemContent(item)
147125
</CascadingValue>;
126+
127+
RenderFragment RenderChromeDisabledHeader(TabItem item) =>
128+
@<div @key="@item" class="@GetItemWrapClassString(item)">
129+
<div role="tab" class="@GetClassString(item)">
130+
@RenderHeaderContent(item)
131+
</div>
132+
<i class="tab-corner tab-corner-left"></i>
133+
<i class="tab-corner tab-corner-right"></i>
134+
</div>;
135+
136+
RenderFragment RenderDefaultDisabledHeader(TabItem item) =>
137+
@<div @key="item" role="tab" class="@GetClassString(item)">
138+
@RenderHeaderContent(item)
139+
</div>;
140+
141+
RenderFragment RenderChromeHeader(TabItem item) =>
142+
@<div @key="@item" class="@GetItemWrapClassString(item)">
143+
<a href="@item.Url" role="tab" tabindex="-1" class="@GetClassString(item)" @onclick="@(() => OnClickTabItem(item))" @onclick:preventDefault="@(!ClickTabToNavigation)" draggable="@DraggableString">
144+
@RenderHeaderContent(item)
145+
</a>
146+
<i class="tab-corner tab-corner-left"></i>
147+
<i class="tab-corner tab-corner-right"></i>
148+
</div>;
149+
150+
RenderFragment RenderDefaultHeader(TabItem item) =>
151+
@<a @key="item" href="@item.Url" role="tab" tabindex="-1" class="@GetClassString(item)" @onclick="@(() => OnClickTabItem(item))" @onclick:preventDefault="@(!ClickTabToNavigation)" draggable="@DraggableString">
152+
@RenderHeaderContent(item)
153+
</a>;
154+
155+
RenderFragment RenderHeaderContent(TabItem item) =>
156+
@<div class="tabs-item-body">
157+
@if (!string.IsNullOrEmpty(item.Icon))
158+
{
159+
<i class="@GetIconClassString(item.Icon)"></i>
160+
}
161+
<span class="tabs-item-text">@item.Text</span>
162+
@if (!item.IsDisabled)
163+
{
164+
@if (ShowFullScreen && item.ShowFullScreen)
165+
{
166+
<FullScreenButton TargetId="@GetIdByTabItem(item)"></FullScreenButton>
167+
}
168+
@if (ShowClose && item.Closable)
169+
{
170+
<span class="tabs-item-close" @onclick:stopPropagation @onclick:preventDefault @onclick="() => RemoveTab(item)">
171+
<i class="@CloseIcon"></i>
172+
</span>
173+
}
174+
}
175+
</div>;
148176
}

src/BootstrapBlazor/Components/Tab/Tab.razor.cs

+30-2
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,12 @@ public partial class Tab : IHandlerException
2424
.AddClass("extend", ShouldShowExtendButtons())
2525
.Build();
2626

27+
private static string? GetItemWrapClassString(TabItem item) => CssBuilder.Default("tabs-item-wrap")
28+
.AddClass("active", item.IsActive && !item.IsDisabled)
29+
.Build();
30+
2731
private string? GetClassString(TabItem item) => CssBuilder.Default("tabs-item")
28-
.AddClass("active", item.IsActive)
32+
.AddClass("active", TabStyle == TabStyle.Default && item.IsActive && !item.IsDisabled)
2933
.AddClass("disabled", item.IsDisabled)
3034
.AddClass(item.CssClass)
3135
.AddClass("is-closeable", ShowClose)
@@ -39,7 +43,8 @@ public partial class Tab : IHandlerException
3943
.AddClass("tabs-card", IsCard)
4044
.AddClass("tabs-border-card", IsBorderCard)
4145
.AddClass($"tabs-{Placement.ToDescriptionString()}", Placement == Placement.Top || Placement == Placement.Right || Placement == Placement.Bottom || Placement == Placement.Left)
42-
.AddClass($"tabs-vertical", Placement == Placement.Left || Placement == Placement.Right)
46+
.AddClass("tabs-vertical", Placement == Placement.Left || Placement == Placement.Right)
47+
.AddClass("tabs-chrome", TabStyle == TabStyle.Chrome)
4348
.AddClassFromAttributes(AdditionalAttributes)
4449
.Build();
4550

@@ -283,6 +288,12 @@ public partial class Tab : IHandlerException
283288
[Parameter]
284289
public Func<TabItem, Task>? OnDragItemEndAsync { get; set; }
285290

291+
/// <summary>
292+
/// Gets or sets the tab style. Default is <see cref="TabStyle.Default"/>.
293+
/// </summary>
294+
[Parameter]
295+
public TabStyle TabStyle { get; set; }
296+
286297
[CascadingParameter]
287298
private Layout? Layout { get; set; }
288299

@@ -352,6 +363,11 @@ protected override void OnParametersSet()
352363

353364
AdditionalAssemblies ??= new[] { Assembly.GetEntryAssembly()! };
354365

366+
if (Placement != Placement.Top && TabStyle == TabStyle.Chrome)
367+
{
368+
TabStyle = TabStyle.Default;
369+
}
370+
355371
if (ClickTabToNavigation)
356372
{
357373
if (!HandlerNavigation)
@@ -783,6 +799,14 @@ private void ActiveTabItem(TabItem item)
783799
public void SetDisabledItem(TabItem item, bool disabled)
784800
{
785801
item.SetDisabledWithoutRender(disabled);
802+
if (disabled)
803+
{
804+
item.SetActive(false);
805+
}
806+
if (TabItems.Any(i => i.IsActive) == false)
807+
{
808+
TabItems.Where(i => !i.IsDisabled).FirstOrDefault()?.SetActive(true);
809+
}
786810
StateHasChanged();
787811
}
788812

@@ -854,6 +878,10 @@ public async Task DragItemCallback(int originIndex, int currentIndex)
854878

855879
private string? GetIdByTabItem(TabItem item) => (ShowFullScreen && item.ShowFullScreen) ? ComponentIdGenerator.Generate(item) : null;
856880

881+
private RenderFragment RenderDisabledHeaderByStyle(TabItem item) => TabStyle == TabStyle.Chrome ? RenderChromeDisabledHeader(item) : RenderDefaultDisabledHeader(item);
882+
883+
private RenderFragment RenderHeaderByStyle(TabItem item) => TabStyle == TabStyle.Chrome ? RenderChromeHeader(item) : RenderDefaultHeader(item);
884+
857885
/// <summary>
858886
/// <inheritdoc/>
859887
/// </summary>

0 commit comments

Comments
 (0)