ComponentBuilder 5.0.0
See the version list below for details.
dotnet add package ComponentBuilder --version 5.0.0
NuGet\Install-Package ComponentBuilder -Version 5.0.0
<PackageReference Include="ComponentBuilder" Version="5.0.0" />
paket add ComponentBuilder --version 5.0.0
#r "nuget: ComponentBuilder, 5.0.0"
// Install ComponentBuilder as a Cake Addin #addin nuget:?package=ComponentBuilder&version=5.0.0 // Install ComponentBuilder as a Cake Tool #tool nuget:?package=ComponentBuilder&version=5.0.0
ComponentBuilder
The best automation framework for RCL(Razor Component Library) to help you easy and quickly building your own Razor Component Library
中文介绍 | Quick Start | Document
v4.x supports
v5.x supports
✨ Features
- OOP mindset creating component
- Attribute first, easy define CSS from parameters
- Easy to associate with components via Attributes
- Cusomization CSS and attributes of component by coding logic
- Support
Pre-definition
for components with simular parameters - New lifecycle definition of Component with interceptor design pattern
- Renderer pipeline pattern to regonize dynamic render of components
🌈 Quick Start
Only change ComponentBase
to BlazorComponetBase
for derived component class
- Sample to create a button component with C# class:
[HtmlTag("button")] //define HTML element tag
[CssClass("btn")] //define component necessary CSS class
public class Button : BlazorComponentBase, IHasChildContent, IHasOnClick
{
[Parameter][CssClass("active")]public bool Active { get; set; }
[Parameter][CssClass("btn-")]public Color? Color { get; set; }
[Parameter]public RenderFragment? ChildContent { get; set; }
[Parameter][HtmlData("tooltip")]public string? Tooltip { get; set; }
[Parameter][HtmlAttribute("onclick")]public EventCallback<ClickEventArgs> OnClick { get; set;
[Parameter][HtmlAttribute]public string? Title { get; set; }
}
public enum Color
{
Primary,
Secondary,
[CssClass("info")]Information,
}
OR you also can define most part of automation features in razor file:
@inherits BlazorComponentBase
<button @attributes="@GetAttributes()">
@ChildContent
</button>
@code{
[CssClass("btn")]
public Button()
{
}
[Parameter][CssClass("active")]public bool Active { get; set; }
[Parameter][CssClass("btn-")]public Color? Color { get; set; }
[Parameter]public RenderFragment? ChildContent { get; set; }
[Parameter][HtmlData("tooltip")]public string? Tooltip { get; set; }
[Parameter][HtmlAttribute("onclick")]public EventCallback<ClickEventArgs> OnClick { get; set; }
[Parameter][HtmlAttribute]public string? Title { get; set; }
public enum Color
{
Primary,
Secondary,
[CssClass("info")]Information,
}
}
- Use component
<Button Color="Color.Primary">Submit</Button>
<button class="btn btn-primary">Submit</button>
<Button Active Tooltip="active button" Color="Color.Information" Title="click me">Active Button</Button>
<button class="btn btn-info active" data-tooltip="active button" title="click me">Active Button</button>
ℹ️ Logical CSS/Style/Attributes
- Using different logic for groups creates code with OOP mindset
protected override void BuildCssClass(ICssClassBuilder builder)
{
if(builder.Contains("annotation-enter"))
{
builder.Remove("annotation-exist");
}
else
{
builder.Append("annotation-enter").Append("annotation-exist");
}
}
protected override void BuildStyle(IStyleBuilder builder)
{
if(Height.HasValue)
{
builder.Append($"height:{Height}px");
}
}
protected override void BuildAttributes(IDictionary<string, object> attributes)
{
if(attrbutes.ContainKey("data-toggle"))
{
attributes["data-toggle"] = "collapse";
}
}
🚸 Parent/Child component
Easy to create parent/child pair components using ParentComponentAttribute
and ChildComponentAttribute<TParent>
- For
List
component class
[ParentComponent] //auto creating the cascading parameter for current
[HtmlTag("ul")]
public class List : BlazorComponentBase, IHasChildContent
{
}
- For
ListItem
component class
[ChildComponent<List>] //Strong association with List
[HtmlTag("li")]
public class ListItem : BlazorComponentBase, IHasChildContent
{
[CascadingParameter]public List? CascadedList { get; set; }//Auto getting the instance of cascading parameter
[Parameter] public RenderFragment? ChildContent { get; set; }
}
Use in blazor
<List>
<ListItem>...</ListItem>
</List>
<ListItem />
In .razor file
In razor file component, you should create cascading parameter by yourself
List.razor
:
<ul @attributes="@GetAttributes()">
<CascadingValue Value="this">
@ChildContent
</CascadingValue>
</ul>
ListItem.razor
:
<li @attributes="GetAttributes()">@ChildContent</li>
@code{
[ChildComponent<List>]
public ListItem()
{
}
[CascadingParameter] public List? CascadedList { get; set; }
[Parameter] public RenderFragment? ChildContent { get; set; }
}
😄 Other extensions
- Extensions for
RenderTreeBuilder
It's very useful for dynamic component creating using OOP mindset
builder.CreateElement(0, "div","any text", new { @class="main" });
//<div class="main">any text</div>
builder.CreateComponent<MyComponent>(attributes: new { Visible = true });
//<MyComponent Visible />
builder.CreateCascadingValue<T>(value);
//<CascadingValue Value="this"></CascadingValue>
- FluentRenderTreeBuilder
Write RenderTreeBuilder as fluent API
//import namespace
using ComponentBuilder.FluentRenderTree;
builder.Element("p", "default-class") // create <p> element with default class
.Class("hover", Hoverable) // append class if Hoverable parameter is true
.Attribute("disabled", Disabled) // add HTML attribute if Disabled is true
.Data("trigger", "string") // add data-trigger="string" HTML attribute if String parameter not empty
.Callback<MouseEventArgs>("onmouseover", this, e => MyHandler()) // add event named 'onmouseover' with a event handler code
.Content("content text") // add inner text for this element
.Close()
//HTML element generate like:
<p class="default-class hover" data-trigger="string" disabled>content text</p>
// normally in razor file:
<p class="default-class @(Hoverable?"hover":"")" disabled="@Disabled" data-trigger="string" @onmouseover="@(e => MyHandler())">content text</p>
builder.Component<MyComponent>()
.Parameter(m => m.Disabled, true)
.Parameter(m => Size, 5)
.ChildContent("My name is hello world")
.Close();
- Create dynamic Class/Style/Callback
//import namespace
using ComponentBuilder.JSInterop
//create dynamic css class string
HtmlHelper.Class.Append("class1").Append("disabled", Disabled).ToString();
//create dynamic style string
HtmlHelper.Style.Append($"width:{Width}px").Append($"height:{Height}px", Height.HasValue).ToString();
//create dynamic EventCallback
HtmlHelper.Callback.Create(this, ()=>{ //action for callback });
- ComponentBuilder.JSInterop
Interactive with C# and JS
export function sayHello(){
//...
}
export function getClient(){
//..
return name;
}
@inject IJSRuntime JS
var module = JS.ImportAsync("./module.js"); //Import js module
await module.Module.InvokeVoidAsync("sayHello");
var name = await module.Module.InvokeAsync<string>("getClient");
⚔️ Interceptors
You can intercept the lifecycle of component
- Define an interceptor
public class LogInterceptor : ComponentInterceptorBase
{
private readonly ILogger<LogInterceptor> _logger;
public LogInterceptor(ILogger<LogInterceptor> logger)
{
_logger = logger;
}
//Run in SetParameterAsync method is called
public override void InterceptSetParameters(IBlazorComponent component, ParameterView parameters)
{
foreach(var item in parameters)
{
_logger.LogDebug($"Key:{item.Name}, Value:{item.Value}");
}
}
}
- Register interceptor
builder.Services.AddComponentBuilder(configure => {
configure.Interceptors.Add<LogInterceptor>();
})
Why interceptors?
Follow SOLID pricipal when designing a component. So you no need break the lifecycle or using override any protected method such as OnParameterSet
to create new HTML attribute whatever you want.
♻️ Renderer Pipeline
Recognize special case to render specified component
public class NavLinkComponentRender : IComponentRender
{
public bool Render(IBlazorComponent component, RenderTreeBuilder builder)
{
if ( component is IHasNavLink navLink )
{
builder.OpenComponent<NavLink>(0);
builder.AddAttribute(1, nameof(NavLink.Match), navLink.Match);
builder.AddAttribute(2, nameof(NavLink.ActiveClass), navLink.ActiveCssClass);
builder.AddAttribute(3, nameof(NavLink.ChildContent), navLink.ChildContent);
builder.AddMultipleAttributes(4, component.GetAttributes());
builder.CloseComponent();
return false;
}
return true;
}
}
- Register renderer in configuration
builder.Services.AddComponentBuilder(configure => {
configure.Renderers.Add<NavLinkComponentRenderer>();
});
📘 Installation Guide
- Install from
Nuget.org
Install-Package ComponentBuilder
- Register service
builder.Services.AddComponentBuilder();
//configure costomization such as Interceptors
builder.Services.AddComponentBuilder(configure => {
//...
})
Read document for more informations
📝 Component Library Solution Template
Use ComponentBuilder.Templates
to generate a razor component library solution and online demo site
dotnet new install ComponentBuilder.Templates
dotnet new blazor-sln -n {YourRazorLibraryName}
More information see templates
Product | Versions Compatible and additional computed target framework versions. |
---|---|
.NET | net8.0 is compatible. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. |
-
net8.0
- Microsoft.AspNetCore.Components.Web (>= 8.0.0)
NuGet packages (5)
Showing the top 5 NuGet packages that depend on ComponentBuilder:
Package | Downloads |
---|---|
TDesign
基于腾讯 TDesign 的 Blazor 企业级组件库。腾讯 TDesign 官方地址:https://tdesign.tencent.com/ |
|
BlamanticUI
The css framework from Semantic-UI for blazor without jQuery. |
|
ComponentBuilder.FluentRenderTree
用链式编程的方式简化 RenderTreeBuilder 的操作。 示例: builder.Element("div").Content("hello").Close(); builder.Component<Button>().Content("Button").Close(); builder.Div(Id is not null).Content(content => content.Component<Icon>().Attribute(m => m.Name, "user").Close()).Close(); |
|
ComponentBuilder.Interceptors.Diagnostics.Console
在控制台中用于组件生命周期诊断的拦截器,该拦截器可以用于调试阶段的生命周期运行的输出。 |
|
ComponentBuilder.Resolvers.FluentClass
组件参数支持 IFluentClassProvider 自动解析成 CSS 类。 [Parameter]public IFluentClassProvider Parameter{ get; set; } <Component Parameter="Provider.Is3.FromTop.HasSmall" /> |
GitHub repositories (1)
Showing the top 1 popular GitHub repositories that depend on ComponentBuilder:
Repository | Stars |
---|---|
tdesign-blazor/TDesignBlazor
基于腾讯 TDesign 的 Blazor 组件库
|
Version | Downloads | Last updated |
---|---|---|
5.1.0 | 135 | 3/7/2024 |
5.0.0 | 190 | 12/21/2023 |
5.0.0-beta-1 | 157 | 11/16/2023 |
4.1.2 | 1,015 | 7/17/2023 |
4.1.1 | 204 | 7/17/2023 |
4.1.0 | 747 | 6/4/2023 |
4.0.0 | 483 | 5/30/2023 |
4.0.0-beta-3 | 259 | 5/22/2023 |
4.0.0-beta-2 | 140 | 5/19/2023 |
4.0.0-beta-1 | 145 | 5/17/2023 |
3.1.4 | 533 | 3/17/2023 |
3.1.3 | 200 | 3/16/2023 |
3.1.0 | 217 | 3/10/2023 |
3.0.0 | 741 | 2/24/2023 |
3.0.0-beta-0217 | 102 | 2/16/2023 |
3.0.0-beta-0206 | 185 | 2/6/2023 |
3.0.0-beta-0130 | 112 | 1/30/2023 |
3.0.0-beta-0114 | 119 | 1/13/2023 |
2.3.0 | 301 | 12/28/2022 |
2.2.0 | 297 | 12/13/2022 |
2.1.0 | 1,456 | 11/24/2022 |
2.0.0 | 367 | 10/28/2022 |
1.5.0.4 | 379 | 10/18/2022 |
1.5.0.3 | 397 | 10/13/2022 |
1.5.0.2 | 1,225 | 10/5/2022 |
1.5.0.1 | 399 | 10/3/2022 |
1.5.0 | 406 | 10/1/2022 |
1.4.1.1 | 672 | 9/19/2022 |
1.4.1 | 410 | 9/16/2022 |
1.4.0 | 424 | 9/15/2022 |
1.3.0 | 419 | 8/29/2022 |
1.2.1 | 581 | 7/12/2022 |
1.2.0 | 417 | 7/11/2022 |
1.1.0 | 561 | 5/22/2022 |
1.0.0 | 616 | 3/23/2022 |
0.7.0 | 444 | 3/11/2022 |
0.6.0 | 442 | 2/9/2022 |
0.5.0 | 276 | 1/6/2022 |
0.4.0 | 286 | 12/23/2021 |
0.3.0 | 299 | 12/16/2021 |
0.2.0 | 306 | 12/7/2021 |
0.1.0 | 6,152 | 11/24/2021 |