Skip to content

Commit 8ef099d

Browse files
authored
SplitView component (#1283)
* Add SplitView component with customizable features and documentation - Implemented SplitView component with primary and secondary panes. - Added support for customizable colors, minimum pane sizes, and orientation. - Introduced events for resize actions: OnResizeStarted, OnResized, and OnResizeEnded. - Created multiple demo pages showcasing various SplitView configurations. - Developed comprehensive documentation covering parameters, events, and usage examples. - Included enums for SplitViewColor and SplitViewOrientation to enhance customization. * Enhance SplitView component to handle parameter changes more effectively * Remove unnecessary padding classes from SplitView demo items for cleaner layout * Refactor code structure for improved readability and maintainability
1 parent f68ca7b commit 8ef099d

30 files changed

Lines changed: 1655 additions & 1 deletion

BlazorBootstrap.Demo.RCL/Components/Layout/DemosMainLayout.razor.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,7 @@ internal override IEnumerable<NavItem> GetNavItems()
8383
new (){ Id = "522", Text = "Script Loader", Href = DemoRouteConstants.Demos_URL_ScriptLoader, IconName = IconName.CodeSlash, ParentId = "5" },
8484
new (){ Id = "523", Text = "Sidebar", Href = DemoRouteConstants.Demos_URL_Sidebar, IconName = IconName.LayoutSidebar, ParentId = "5" },
8585
new (){ Id = "524", Text = "Sidebar 2", Href = DemoRouteConstants.Demos_URL_Sidebar2, IconName = IconName.ListNested, ParentId = "5" },
86+
new (){ Id = "5245", Text = "Split View", Href = DemoRouteConstants.Demos_URL_SplitView, IconName = IconName.LayoutSplit, ParentId = "5" },
8687
new (){ Id = "525", Text = "Sortable List", Href = DemoRouteConstants.Demos_URL_SortableList, IconName = IconName.ArrowsMove, ParentId = "5" },
8788
new (){ Id = "526", Text = "Spinner", Href = DemoRouteConstants.Demos_URL_Spinners, IconName = IconName.ArrowRepeat, ParentId = "5" },
8889
new (){ Id = "527", Text = "Tabs", Href = DemoRouteConstants.Demos_URL_Tabs, IconName = IconName.WindowPlus, ParentId = "5" },

BlazorBootstrap.Demo.RCL/Components/Layout/DocsMainLayout.razor.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@ internal override IEnumerable<NavItem> GetNavItems()
5959
new (){ Id = "522", Text = "Script Loader", Href = DemoRouteConstants.Docs_URL_ScriptLoader, IconName = IconName.CodeSlash, ParentId = "5" },
6060
new (){ Id = "523", Text = "Sidebar", Href = DemoRouteConstants.Docs_URL_Sidebar, IconName = IconName.LayoutSidebar, ParentId = "5" },
6161
new (){ Id = "524", Text = "Sidebar 2", Href = DemoRouteConstants.Docs_URL_Sidebar2, IconName = IconName.ListNested, ParentId = "5" },
62+
new (){ Id = "5245", Text = "Split View", Href = DemoRouteConstants.Docs_URL_SplitView, IconName = IconName.LayoutSplit, ParentId = "5" },
6263
new (){ Id = "525", Text = "Sortable List", Href = DemoRouteConstants.Docs_URL_SortableList, IconName = IconName.ArrowsMove, ParentId = "5" },
6364
new (){ Id = "526", Text = "Spinner", Href = DemoRouteConstants.Docs_URL_Spinners, IconName = IconName.ArrowRepeat, ParentId = "5" },
6465
new (){ Id = "527", Text = "Tabs", Href = DemoRouteConstants.Docs_URL_Tabs, IconName = IconName.WindowPlus, ParentId = "5" },

BlazorBootstrap.Demo.RCL/Components/Layout/MainLayout.razor.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,7 @@ internal override IEnumerable<NavItem> GetNavItems()
8282
new (){ Id = "522", Text = "Script Loader", Href = DemoRouteConstants.Demos_URL_ScriptLoader, IconName = IconName.CodeSlash, ParentId = "5" },
8383
new (){ Id = "523", Text = "Sidebar", Href = DemoRouteConstants.Demos_URL_Sidebar, IconName = IconName.LayoutSidebar, ParentId = "5" },
8484
new (){ Id = "524", Text = "Sidebar 2", Href = DemoRouteConstants.Demos_URL_Sidebar2, IconName = IconName.ListNested, ParentId = "5" },
85+
new (){ Id = "5245", Text = "Split View", Href = DemoRouteConstants.Demos_URL_SplitView, IconName = IconName.LayoutSplit, ParentId = "5" },
8586
new (){ Id = "525", Text = "Sortable List", Href = DemoRouteConstants.Demos_URL_SortableList, IconName = IconName.ArrowsMove, ParentId = "5" },
8687
new (){ Id = "526", Text = "Spinner", Href = DemoRouteConstants.Demos_URL_Spinners, IconName = IconName.ArrowRepeat, ParentId = "5" },
8788
new (){ Id = "527", Text = "Tabs", Href = DemoRouteConstants.Demos_URL_Tabs, IconName = IconName.WindowPlus, ParentId = "5" },
Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
@attribute [Route(pageUrl)]
2+
@layout DemosMainLayout
3+
4+
<DemosPageHeadSection PageUrl="@pageUrl"
5+
PageTitle="@pageTitle"
6+
PageDescription="@pageDescription"
7+
MetaTitle="@metaTitle"
8+
MetaDescription="@metaDescription"
9+
ImageUrl="@imageUrl" />
10+
11+
<DocsLink Href="@DemoRouteConstants.Docs_URL_SplitView" />
12+
13+
<Section Size="HeadingSize.H2" Name="Pane Content" PageUrl="@pageUrl" Link="pane-content">
14+
<div class="mb-3">
15+
<code>Pane1</code> and <code>Pane2</code> are the required content regions for SplitView.
16+
</div>
17+
<Demo Type="typeof(SplitView_Demo_01_Pane_Content)" Tabs="true" />
18+
</Section>
19+
20+
<Section Size="HeadingSize.H2" Name="Orientation" PageUrl="@pageUrl" Link="orientation">
21+
<div class="mb-3">
22+
Set <code>Orientation="SplitViewOrientation.Vertical"</code> to stack panes top to bottom with a horizontal divider.
23+
</div>
24+
<Demo Type="typeof(SplitView_Demo_02_Orientation)" Tabs="true" />
25+
</Section>
26+
27+
<Section Size="HeadingSize.H2" Name="Primary Pane Size" PageUrl="@pageUrl" Link="primary-pane-size">
28+
<div class="mb-3">
29+
Use <code>PrimaryPaneSize</code> to set the initial percentage allocated to the primary pane.
30+
</div>
31+
<Demo Type="typeof(SplitView_Demo_03_Primary_Pane_Size)" Tabs="true" />
32+
</Section>
33+
34+
<Section Size="HeadingSize.H2" Name="Primary Pane Size Changed" PageUrl="@pageUrl" Link="primary-pane-size-changed">
35+
<div class="mb-3">
36+
Use <code>@@bind-PrimaryPaneSize</code> or <code>PrimaryPaneSizeChanged</code> to react to live divider movement.
37+
</div>
38+
<Demo Type="typeof(SplitView_Demo_04_Primary_Pane_Size_Changed)" Tabs="true" />
39+
</Section>
40+
41+
<Section Size="HeadingSize.H2" Name="Minimum Pane Size" PageUrl="@pageUrl" Link="minimum-pane-size">
42+
<div class="mb-3">
43+
<code>MinimumPaneSize</code> clamps both panes so one side cannot fully collapse while dragging.
44+
</div>
45+
<Demo Type="typeof(SplitView_Demo_05_Minimum_Pane_Size)" Tabs="true" />
46+
</Section>
47+
48+
<Section Size="HeadingSize.H2" Name="Disabled State" PageUrl="@pageUrl" Link="disabled-state">
49+
<div class="mb-3">
50+
Set <code>IsDisabled="true"</code> to keep the layout visible while preventing pointer-based resizing.
51+
</div>
52+
<Demo Type="typeof(SplitView_Demo_06_Is_Disabled)" Tabs="true" />
53+
</Section>
54+
55+
<Section Size="HeadingSize.H2" Name="Semantic Color" PageUrl="@pageUrl" Link="semantic-color">
56+
<div class="mb-3">
57+
The <code>Color</code> parameter uses the <code>SplitViewColor</code> enum and maps to shared Bootstrap-backed CSS variables.
58+
</div>
59+
<Demo Type="typeof(SplitView_Demo_07_Color)" Tabs="true" />
60+
</Section>
61+
62+
<Section Size="HeadingSize.H2" Name="Custom Color" PageUrl="@pageUrl" Link="custom-color">
63+
<div class="mb-3">
64+
Use <code>CustomColor</code> when you want to pass a CSS color expression such as <code>var(...)</code> or <code>rgba(...)</code>.
65+
</div>
66+
<Demo Type="typeof(SplitView_Demo_08_Custom_Color)" Tabs="true" />
67+
</Section>
68+
69+
<Section Size="HeadingSize.H2" Name="OnResizeStarted" PageUrl="@pageUrl" Link="onresizestarted">
70+
<div class="mb-3">
71+
<code>OnResizeStarted</code> fires once when the pointer first captures the divider.
72+
</div>
73+
<Demo Type="typeof(SplitView_Demo_09_On_Resize_Started)" Tabs="true" />
74+
</Section>
75+
76+
<Section Size="HeadingSize.H2" Name="OnResized" PageUrl="@pageUrl" Link="onresized">
77+
<div class="mb-3">
78+
<code>OnResized</code> streams live primary and secondary pane percentages during drag.
79+
</div>
80+
<Demo Type="typeof(SplitView_Demo_10_On_Resized)" Tabs="true" />
81+
</Section>
82+
83+
<Section Size="HeadingSize.H2" Name="OnResizeEnded" PageUrl="@pageUrl" Link="onresizeended">
84+
<div class="mb-3">
85+
<code>OnResizeEnded</code> is useful when you only want to persist the final pane sizes after dragging stops.
86+
</div>
87+
<Demo Type="typeof(SplitView_Demo_11_On_Resize_Ended)" Tabs="true" />
88+
</Section>
89+
90+
<Section Size="HeadingSize.H2" Name="Nested Layouts" PageUrl="@pageUrl" Link="nested-layouts">
91+
<div class="mb-3">
92+
SplitView supports nested layouts, enabling IDE-style and dashboard-style workspaces.
93+
</div>
94+
<Demo Type="typeof(SplitView_Demo_12_Nested_Layouts)" Tabs="true" />
95+
</Section>
96+
97+
@code {
98+
private const string pageUrl = DemoRouteConstants.Demos_URL_SplitView;
99+
private const string pageTitle = "Blazor Split View";
100+
private const string pageDescription = "The Blazor Split View component arranges two resizable panes horizontally or vertically with live drag updates, Bootstrap color theming, and focused parameter demos.";
101+
private const string metaTitle = "Blazor Split View Component";
102+
private const string metaDescription = "The Blazor Split View component arranges two resizable panes horizontally or vertically with live drag updates, Bootstrap color theming, and focused parameter demos.";
103+
private const string imageUrl = DemoScreenshotSrcConstants.Demos_URL_SplitView;
104+
}
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
<SplitView Class="border rounded shadow-sm"
2+
Style="height: 360px;">
3+
<Pane1>
4+
<div class="h-100 p-4 bg-body-tertiary">
5+
<div class="small text-uppercase text-secondary mb-2">Pane1</div>
6+
<h5 class="mb-3">Navigation</h5>
7+
<div class="list-group list-group-flush">
8+
<div class="list-group-item">Overview</div>
9+
<div class="list-group-item">Customers</div>
10+
<div class="list-group-item">Orders</div>
11+
<div class="list-group-item">Reports</div>
12+
</div>
13+
</div>
14+
</Pane1>
15+
<Pane2>
16+
<div class="h-100 p-4 bg-body">
17+
<div class="small text-uppercase text-secondary mb-2">Pane2</div>
18+
<h4 class="mb-3">Workspace</h4>
19+
<p class="text-secondary mb-0">Use the two required pane templates to define the resizable primary and secondary regions.</p>
20+
</div>
21+
</Pane2>
22+
</SplitView>
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
<div class="small text-uppercase text-secondary mb-2">Horizontal Orientation</div>
2+
<SplitView Class="border rounded shadow-sm mb-4"
3+
Style="height: 320px;"
4+
PrimaryPaneSize="32">
5+
<Pane1>
6+
<div class="h-100 p-4 bg-body-tertiary">
7+
<div class="small text-uppercase text-secondary mb-2">Left Pane</div>
8+
<h5 class="mb-3">Navigation</h5>
9+
<p class="mb-0">The default horizontal orientation places panes side by side with a vertical divider.</p>
10+
</div>
11+
</Pane1>
12+
<Pane2>
13+
<div class="h-100 p-4 bg-body">
14+
<div class="small text-uppercase text-secondary mb-2">Right Pane</div>
15+
<h5 class="mb-3">Workspace</h5>
16+
<ul class="mb-0">
17+
<li>Dashboard widgets</li>
18+
<li>Tables and forms</li>
19+
<li>Contextual details</li>
20+
</ul>
21+
</div>
22+
</Pane2>
23+
</SplitView>
24+
25+
<div class="small text-uppercase text-secondary mb-2">Vertical Orientation</div>
26+
<SplitView Class="border rounded shadow-sm"
27+
Style="height: 420px;"
28+
Orientation="SplitViewOrientation.Vertical"
29+
PrimaryPaneSize="35">
30+
<Pane1>
31+
<div class="h-100 p-4 bg-body-tertiary">
32+
<div class="small text-uppercase text-secondary mb-2">Top Pane</div>
33+
<h5 class="mb-3">Summary</h5>
34+
<p class="mb-0">Vertical orientation stacks panes and changes the divider to horizontal dragging.</p>
35+
</div>
36+
</Pane1>
37+
<Pane2>
38+
<div class="h-100 p-4 bg-body">
39+
<div class="small text-uppercase text-secondary mb-2">Bottom Pane</div>
40+
<h5 class="mb-3">Details</h5>
41+
<ul class="mb-0">
42+
<li>Release notes</li>
43+
<li>Deployment checklist</li>
44+
<li>Preview output</li>
45+
</ul>
46+
</div>
47+
</Pane2>
48+
</SplitView>
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
<SplitView Class="border rounded shadow-sm"
2+
Style="height: 320px;"
3+
PrimaryPaneSize="30">
4+
<Pane1>
5+
<div class="h-100 p-4 bg-body-tertiary">
6+
<div class="small text-uppercase text-secondary mb-2">Primary Pane</div>
7+
<h5 class="mb-3">30%</h5>
8+
<p class="mb-0">Set <code>PrimaryPaneSize</code> when you want the initial layout to favor one pane.</p>
9+
</div>
10+
</Pane1>
11+
<Pane2>
12+
<div class="h-100 p-4 bg-body">
13+
<div class="small text-uppercase text-secondary mb-2">Secondary Pane</div>
14+
<h5 class="mb-3">70%</h5>
15+
<p class="mb-0">The remaining space is automatically assigned to the secondary pane.</p>
16+
</div>
17+
</Pane2>
18+
</SplitView>
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
<div class="d-flex flex-wrap gap-2 mb-3">
2+
<button class="btn btn-outline-secondary btn-sm" @onclick='() => primaryPaneSize = 25'>25%</button>
3+
<button class="btn btn-outline-secondary btn-sm" @onclick='() => primaryPaneSize = 40'>40%</button>
4+
<button class="btn btn-outline-secondary btn-sm" @onclick='() => primaryPaneSize = 60'>60%</button>
5+
<div class="small text-secondary align-self-center">Bound primary pane size: <strong>@primaryPaneSize.ToString("0.##")%</strong></div>
6+
</div>
7+
8+
<SplitView Class="border rounded shadow-sm"
9+
Style="height: 340px;"
10+
MinimumPaneSize="15"
11+
@bind-PrimaryPaneSize="primaryPaneSize">
12+
<Pane1>
13+
<div class="h-100 p-4 bg-body-tertiary">
14+
<div class="small text-uppercase text-secondary mb-2">Primary Pane</div>
15+
<h5 class="mb-3">Two-way Binding</h5>
16+
<p class="mb-0">Drag the divider or use the buttons above to update the same bound value.</p>
17+
</div>
18+
</Pane1>
19+
<Pane2>
20+
<div class="h-100 p-4 bg-body">
21+
<div class="small text-uppercase text-secondary mb-2">Secondary Pane</div>
22+
<h5 class="mb-3">Live Value</h5>
23+
<p class="mb-0">The parent component stays synchronized through <code>PrimaryPaneSizeChanged</code>.</p>
24+
</div>
25+
</Pane2>
26+
</SplitView>
27+
28+
@code {
29+
private double primaryPaneSize = 40;
30+
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
<SplitView Class="border rounded shadow-sm"
2+
Style="height: 340px;"
3+
PrimaryPaneSize="35"
4+
MinimumPaneSize="25">
5+
<Pane1>
6+
<div class="h-100 p-4 bg-body-tertiary">
7+
<div class="small text-uppercase text-secondary mb-2">MinimumPaneSize</div>
8+
<h5 class="mb-3">25%</h5>
9+
<p class="mb-0">The divider cannot move past the 25% threshold, so the primary pane always remains usable.</p>
10+
</div>
11+
</Pane1>
12+
<Pane2>
13+
<div class="h-100 p-4 bg-body">
14+
<div class="small text-uppercase text-secondary mb-2">Secondary Pane</div>
15+
<h5 class="mb-3">Protected Layout</h5>
16+
<p class="mb-0">The same minimum is enforced from the opposite side, keeping both panes visible.</p>
17+
</div>
18+
</Pane2>
19+
</SplitView>
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
<SplitView Class="border rounded shadow-sm"
2+
Style="height: 320px;"
3+
PrimaryPaneSize="40"
4+
Color="SplitViewColor.Secondary"
5+
IsDisabled="true">
6+
<Pane1>
7+
<div class="h-100 p-4 bg-body-tertiary">
8+
<div class="small text-uppercase text-secondary mb-2">Disabled Divider</div>
9+
<h5 class="mb-3">Pinned Pane</h5>
10+
<p class="mb-0">The layout remains visible, but pointer dragging and hover states are disabled.</p>
11+
</div>
12+
</Pane1>
13+
<Pane2>
14+
<div class="h-100 p-4 bg-body">
15+
<div class="small text-uppercase text-secondary mb-2">Secondary Pane</div>
16+
<h5 class="mb-3">Static Layout</h5>
17+
<p class="mb-0">Programmatic updates to <code>PrimaryPaneSize</code> still work even when interaction is disabled.</p>
18+
</div>
19+
</Pane2>
20+
</SplitView>

0 commit comments

Comments
 (0)