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

feat(split): support pane collapsible #4138

Merged
merged 44 commits into from
Aug 27, 2024
Merged
Show file tree
Hide file tree
Changes from 11 commits
Commits
Show all changes
44 commits
Select commit Hold shift + click to select a range
5d79993
feat(split): support pane collapsible
izanhzh Aug 24, 2024
0c57ea3
modify css
izanhzh Aug 24, 2024
2e69acc
modify css
izanhzh Aug 24, 2024
fb279e4
Merge branch 'main' into feat(split)-support-pane-collapsible
izanhzh Aug 25, 2024
66373b5
beautify and fix bugs
izanhzh Aug 26, 2024
550eacc
adjust parameter
izanhzh Aug 26, 2024
18ad13b
modify unit tests
izanhzh Aug 26, 2024
858d919
modify unit tests
izanhzh Aug 26, 2024
26cae06
coverage
izanhzh Aug 26, 2024
df7d827
modify css
izanhzh Aug 26, 2024
f81d948
Merge branch 'main' into feat(split)-support-pane-collapsible
ArgoZhang Aug 26, 2024
2df26c6
fix bugs
izanhzh Aug 27, 2024
00052af
Merge branch 'feat(split)-support-pane-collapsible' of https://github…
izanhzh Aug 27, 2024
f078604
Merge branch 'dotnetcore:main' into feat(split)-support-pane-collapsible
izanhzh Aug 27, 2024
a14cf04
wip: test modify PR
ArgoZhang Aug 27, 2024
2d55fdf
Merge branch 'main' into feat(split)-support-pane-collapsible
ArgoZhang Aug 27, 2024
6299652
add document
izanhzh Aug 27, 2024
870c374
Merge branch 'feat(split)-support-pane-collapsible' of https://github…
izanhzh Aug 27, 2024
ad1cea0
fix bugs
izanhzh Aug 27, 2024
f00a709
Merge branch 'main' into feat(split)-support-pane-collapsible
izanhzh Aug 27, 2024
295267f
modify some description
izanhzh Aug 27, 2024
18afe78
fix bugs
izanhzh Aug 27, 2024
50f1248
refactor: 调整 bar 样式
ArgoZhang Aug 27, 2024
42daec4
style: 调整垂直样式
ArgoZhang Aug 27, 2024
1688767
style: 增加垂直布局样式
ArgoZhang Aug 27, 2024
93440ad
style: 增加 handler 样式
ArgoZhang Aug 27, 2024
fc5be8b
style: 更新垂直布局样式
ArgoZhang Aug 27, 2024
3bce1c9
refactor: 增加 IsCollapsible 参数
ArgoZhang Aug 27, 2024
8450e10
refactor: 增加按钮支持
ArgoZhang Aug 27, 2024
652441e
style: 微调样式
ArgoZhang Aug 27, 2024
d53b825
doc: 精简 dom 结构
ArgoZhang Aug 27, 2024
547bbe1
style: 微调样式适配收起动画
ArgoZhang Aug 27, 2024
c08a02c
feat: 更新脚本实现收起展开动画特效
ArgoZhang Aug 27, 2024
6cd659c
style: 颜色变量化
ArgoZhang Aug 27, 2024
d01c042
style: 增加动画效果
ArgoZhang Aug 27, 2024
dc89a46
doc: 更新文档说明
ArgoZhang Aug 27, 2024
da0eceb
test: 更新单元测试
ArgoZhang Aug 27, 2024
5f24e28
feat: 增加 OnCollapsedAsync 回调方法
ArgoZhang Aug 27, 2024
25d8184
feat: 实现 OnCollapsedAsync 逻辑
ArgoZhang Aug 27, 2024
a674272
test: 增加单元测试
ArgoZhang Aug 27, 2024
86c483e
doc: 移除不需要的本地化设置
ArgoZhang Aug 27, 2024
d38bd16
chore: bump version 8.8.5-beta03
ArgoZhang Aug 27, 2024
d5d3851
style: 增加暗黑主题颜色
ArgoZhang Aug 27, 2024
39756e9
style: 更正暗黑主题变量
ArgoZhang Aug 27, 2024
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
33 changes: 22 additions & 11 deletions src/BootstrapBlazor/Components/Split/Split.razor
Original file line number Diff line number Diff line change
Expand Up @@ -3,21 +3,32 @@
@attribute [BootstrapModuleAutoLoader]

<div @attributes="@AdditionalAttributes" id="@Id" class="@ClassString" role="group">
<div class="@WrapperClassString">
<div class="@WrapperClassString" status="@GetPaneClassStatus()">
<div class="split-pane split-left" style="@StyleString">
@FirstPaneTemplate
</div>
<div class="split-pane split-bar">
<div class="split-trigger">
<i class="split-trigger-bar"></i>
<i class="split-trigger-bar"></i>
<i class="split-trigger-bar"></i>
<i class="split-trigger-bar"></i>
<i class="split-trigger-bar"></i>
<i class="split-trigger-bar"></i>
<i class="split-trigger-bar"></i>
<i class="split-trigger-bar"></i>
</div>
@if (IsShowFirstPaneCollapseSwitch)
{
<span class="split-first-pane-collapse-switch" onclick="@(()=>PaneCollapseSwitch(FirstPane))"></span>
}
@if (IsResizable && !IsCollapsed)
{
<div class="split-trigger">
<i class="split-trigger-bar"></i>
<i class="split-trigger-bar"></i>
<i class="split-trigger-bar"></i>
<i class="split-trigger-bar"></i>
<i class="split-trigger-bar"></i>
<i class="split-trigger-bar"></i>
<i class="split-trigger-bar"></i>
<i class="split-trigger-bar"></i>
</div>
}
@if (IsShowSecondPaneCollapseSwitch)
{
<span class="split-second-pane-collapse-switch" onclick="@(()=>PaneCollapseSwitch(SecondPane))"></span>
}
</div>
<div class="split-pane split-right" style="flex: 1;">
@SecondPaneTemplate
Expand Down
82 changes: 82 additions & 0 deletions src/BootstrapBlazor/Components/Split/Split.razor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,21 @@
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
// Website: https://www.blazor.zone or https://argozhang.github.io/

using System.ComponentModel;

namespace BootstrapBlazor.Components;

/// <summary>
///
/// </summary>
public sealed partial class Split
{
private const string FirstPane = "FirstPane";
private const string SecondPane = "SecondPane";
private const string FirstPaneCollapsed = "first-pane-collapsed";
private const string SecondPaneCollapsed = "second-pane-collapsed";
private const string BothPaneExpand = "both-pane-expand";

/// <summary>
/// 获得 组件样式
/// </summary>
Expand All @@ -30,6 +38,26 @@ public sealed partial class Split
.AddClass($"flex-basis: {Basis.ConvertToPercentString()};")
.Build();

/// <summary>
/// 获取/设置 当前折叠的窗格(FirstPane/SecondPane)
/// </summary>
private string? CollapsedPane { get; set; }

/// <summary>
/// 获取 是否显示第一个窗格的折叠/展开按钮
/// </summary>
private bool IsShowFirstPaneCollapseSwitch => FirstPaneCollapsible && CollapsedPane != SecondPane;

/// <summary>
/// 获取 是否显示第二个窗格的折叠/展开按钮
/// </summary>
private bool IsShowSecondPaneCollapseSwitch => SecondPaneCollapsible && CollapsedPane != FirstPane;

/// <summary>
/// 获取 是否处于折叠状态
/// </summary>
private bool IsCollapsed => !string.IsNullOrEmpty(CollapsedPane);

/// <summary>
/// 获得/设置 是否垂直分割
/// </summary>
Expand All @@ -53,4 +81,58 @@ public sealed partial class Split
/// </summary>
[Parameter]
public RenderFragment? SecondPaneTemplate { get; set; }

/// <summary>
/// 获取/设置 是否可以拖动改变大小
/// </summary>
[Parameter]
public bool IsResizable { get; set; } = true;

/// <summary>
/// 获取/设置 第一个窗格是否可关闭
/// </summary>
[Parameter]
public bool FirstPaneCollapsible { get; set; }

/// <summary>
/// 获取/设置 第二个窗格是否可关闭
/// </summary>
[Parameter]
public bool SecondPaneCollapsible { get; set; }

/// <summary>
/// 折叠/展开窗格
/// </summary>
/// <param name="pane"></param>
private void PaneCollapseSwitch(string pane)
{
if (CollapsedPane == pane)
{
CollapsedPane = null;
}
else
{
CollapsedPane = pane;
}
}

/// <summary>
/// 获取窗格状态
/// </summary>
/// <returns></returns>
private string GetPaneClassStatus()
{
if (CollapsedPane == FirstPane)
{
return FirstPaneCollapsed;
}
else if (CollapsedPane == SecondPane)
{
return SecondPaneCollapsed;
}
else
{
return BothPaneExpand;
}
}
}
8 changes: 8 additions & 0 deletions src/BootstrapBlazor/Components/Split/Split.razor.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,10 @@ export function init(id) {
split.splitBar = splitBar;
Drag.drag(splitBar,
e => {
const isResizable = el.getElementsByClassName('split-trigger').length > 0;
if (isResizable === false) {
return;
}
splitWidth = el.offsetWidth
splitHeight = el.offsetHeight
if (isVertical) {
Expand All @@ -40,6 +44,10 @@ export function init(id) {
showMask(splitLeft, splitRight);
},
e => {
const isResizable = el.getElementsByClassName('split-trigger').length > 0;
if (isResizable === false) {
return;
}
if (isVertical) {
const eventY = e.clientY || e.changedTouches[0].clientY
newVal = Math.ceil((eventY - originY) * 100 / splitHeight) + curVal
Expand Down
73 changes: 73 additions & 0 deletions src/BootstrapBlazor/Components/Split/Split.razor.scss
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,56 @@
background-color: var(--bs-body-bg);
}

.split-wrapper .split-first-pane-collapse-switch,
.split-wrapper .split-second-pane-collapse-switch {
cursor: pointer;
color: var(--bs-border-color);
font-size: 8px;
margin-left: 3px;
margin-top: 3px;
}

.split-wrapper.is-horizontal .split-first-pane-collapse-switch,
.split-wrapper.is-horizontal .split-second-pane-collapse-switch {
cursor: pointer;
color: var(--bs-border-color);
font-size: 8px;
margin-left: 0;
margin-top: 3px;
}

.split-wrapper .split-first-pane-collapse-switch:before {
content: '\025B2';
}

.split-wrapper[status="first-pane-collapsed"] .split-first-pane-collapse-switch:before {
content: '\025BC';
}

.split-wrapper .split-second-pane-collapse-switch:before {
content: '\025BC';
}

.split-wrapper[status="second-pane-collapsed"] .split-second-pane-collapse-switch:before {
content: '\025B2';
}

.split-wrapper.is-horizontal .split-first-pane-collapse-switch:before {
content: '\025C0';
}

.split-wrapper.is-horizontal[status="first-pane-collapsed"] .split-first-pane-collapse-switch:before {
content: '\025B6';
}

.split-wrapper.is-horizontal .split-second-pane-collapse-switch:before {
content: '\025B6';
}

.split-wrapper.is-horizontal[status="second-pane-collapsed"] .split-second-pane-collapse-switch:before {
content: '\025C0';
}

.split-trigger {
font-size: 0;
display: inline-block;
Expand All @@ -66,6 +116,7 @@
}

.split-wrapper.is-horizontal > .split-bar {
flex-direction: column;
width: 6px;
height: 100%;
border: 1px solid var(--bs-border-color);
Expand All @@ -80,4 +131,26 @@
margin-top: 3px;
}
}

.split-wrapper[status="first-pane-collapsed"] .split-bar:hover, &.dragging > .split-wrapper[status="first-pane-collapsed"] > .split-bar,
.split-wrapper[status="second-pane-collapsed"] .split-bar:hover, &.dragging > .split-wrapper[status="second-pane-collapsed"] > .split-bar {
background-color: transparent;
cursor: default;
}

.split-wrapper[status="first-pane-collapsed"] .split-left {
flex: 0 1 0% !important;
overflow: hidden !important;
display: block !important;
}

.split-wrapper[status="second-pane-collapsed"] .split-left {
flex: 1 !important;
}

.split-wrapper[status="second-pane-collapsed"] .split-right {
flex: 0 1 0% !important;
overflow: hidden !important;
display: block !important;
}
}
55 changes: 50 additions & 5 deletions test/UnitTest/Components/SplitTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,9 @@ public void SplitStyle_Ok()
pb.Add(b => b.FirstPaneTemplate, BuildeComponent("I am Pane1"));
pb.Add(b => b.SecondPaneTemplate, BuildeComponent("I am Pane2"));
pb.Add(b => b.IsVertical, true);
pb.Add(b => b.IsResizable, true);
pb.Add(b => b.FirstPaneCollapsible, true);
pb.Add(b => b.SecondPaneCollapsible, true);
});
Assert.Contains("I am Pane1", cut.Markup);
Assert.Contains("I am Pane2", cut.Markup);
Expand All @@ -30,12 +33,54 @@ public void SplitStyle_Ok()
pb.Add(b => b.AdditionalAttributes, new Dictionary<string, object>() { ["tag"] = "tagok" });
});
Assert.Contains("tagok", cut.Markup);
}

RenderFragment BuildeComponent(string name = "I am Pane1") => builder =>
[Fact]
public void SplitCollapsible_Ok()
{
var cut = Context.RenderComponent<Split>(pb =>
{
builder.OpenElement(1, "div");
builder.AddContent(2, name);
builder.CloseElement();
};
pb.Add(b => b.FirstPaneTemplate, BuildeComponent("I am Pane1"));
pb.Add(b => b.SecondPaneTemplate, BuildeComponent("I am Pane2"));
pb.Add(b => b.FirstPaneCollapsible, true);
pb.Add(b => b.SecondPaneCollapsible, true);
});

Assert.Contains("split-first-pane-collapse-switch", cut.Markup);
Assert.Contains("split-trigger", cut.Markup);
Assert.Contains("split-second-pane-collapse-switch", cut.Markup);

cut.Find(".split-first-pane-collapse-switch").Click();
Assert.Contains("first-pane-collapsed", cut.Markup);
cut.Find(".split-first-pane-collapse-switch").Click();
Assert.Contains("both-pane-expand", cut.Markup);

cut.Find(".split-second-pane-collapse-switch").Click();
Assert.Contains("second-pane-collapsed", cut.Markup);
cut.Find(".split-second-pane-collapse-switch").Click();
Assert.Contains("both-pane-expand", cut.Markup);
}

[Fact]
public void SplitFixedPane_Ok()
{
var cut = Context.RenderComponent<Split>(pb =>
{
pb.Add(b => b.FirstPaneTemplate, BuildeComponent("I am Pane1"));
pb.Add(b => b.SecondPaneTemplate, BuildeComponent("I am Pane2"));
pb.Add(b => b.IsResizable, false);
pb.Add(b => b.FirstPaneCollapsible, false);
pb.Add(b => b.SecondPaneCollapsible, false);
});
Assert.DoesNotContain("split-first-pane-collapse-switch", cut.Markup);
Assert.DoesNotContain("split-trigger", cut.Markup);
Assert.DoesNotContain("split-second-pane-collapse-switch", cut.Markup);
}

private static RenderFragment BuildeComponent(string name = "I am Pane1") => builder =>
{
builder.OpenElement(1, "div");
builder.AddContent(2, name);
builder.CloseElement();
};
}