This commit is contained in:
@@ -0,0 +1,221 @@
|
||||
# SbAccordion
|
||||
|
||||
A collapsible accordion component for organizing content into expandable sections.
|
||||
|
||||
## Parameters
|
||||
|
||||
| Parameter | Type | Default | Description |
|
||||
|-----------|------|---------|-------------|
|
||||
| Multiple | bool | false | Whether multiple items can be expanded simultaneously |
|
||||
| Class | string? | null | Additional CSS classes |
|
||||
|
||||
## Events
|
||||
|
||||
| Event | Type | Description |
|
||||
|-------|------|-------------|
|
||||
| OnExpandedChanged | EventCallback\<HashSet\<SbAccordionItem\>\> | Fired when expanded items change |
|
||||
|
||||
## Templates / Slots
|
||||
|
||||
| Slot | Type | Description |
|
||||
|------|------|-------------|
|
||||
| ChildContent | RenderFragment | Accordion items (SbAccordionItem components) |
|
||||
|
||||
## CSS Classes
|
||||
|
||||
- `sb-accordion` - Base class
|
||||
|
||||
When an item is expanded, its header uses a distinct background (`sb-accordion-item--expanded .sb-accordion-item__header`) so it is visually separated from the content area.
|
||||
|
||||
## Examples
|
||||
|
||||
### Basic Usage
|
||||
|
||||
```razor
|
||||
<SbAccordion>
|
||||
<SbAccordionItem Title="Section 1">
|
||||
<p>Content for section 1</p>
|
||||
</SbAccordionItem>
|
||||
<SbAccordionItem Title="Section 2">
|
||||
<p>Content for section 2</p>
|
||||
</SbAccordionItem>
|
||||
<SbAccordionItem Title="Section 3">
|
||||
<p>Content for section 3</p>
|
||||
</SbAccordionItem>
|
||||
</SbAccordion>
|
||||
```
|
||||
|
||||
### Multiple Expanded
|
||||
|
||||
```razor
|
||||
<SbAccordion Multiple="true">
|
||||
<SbAccordionItem Title="General Information" DefaultExpanded="true">
|
||||
<p>General info content...</p>
|
||||
</SbAccordionItem>
|
||||
<SbAccordionItem Title="Technical Details" DefaultExpanded="true">
|
||||
<p>Technical details content...</p>
|
||||
</SbAccordionItem>
|
||||
<SbAccordionItem Title="Support">
|
||||
<p>Support content...</p>
|
||||
</SbAccordionItem>
|
||||
</SbAccordion>
|
||||
```
|
||||
|
||||
### FAQ Style
|
||||
|
||||
```razor
|
||||
<SbAccordion>
|
||||
@foreach (var faq in faqs)
|
||||
{
|
||||
<SbAccordionItem Title="@faq.Question">
|
||||
<p>@faq.Answer</p>
|
||||
</SbAccordionItem>
|
||||
}
|
||||
</SbAccordion>
|
||||
|
||||
@code {
|
||||
private List<FAQ> faqs = new()
|
||||
{
|
||||
new("What is your return policy?", "We offer 30-day returns..."),
|
||||
new("How do I track my order?", "You can track your order..."),
|
||||
new("Do you ship internationally?", "Yes, we ship to over 100 countries...")
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
### Default Expanded
|
||||
|
||||
Use `DefaultExpanded="true"` on an item to have it expanded when the page loads. When `Multiple` is false (default), only one item can be expanded at a time.
|
||||
|
||||
```razor
|
||||
<SbAccordion>
|
||||
<SbAccordionItem Title="Introduction" DefaultExpanded="true">
|
||||
<p>This section is expanded by default when the page loads.</p>
|
||||
</SbAccordionItem>
|
||||
<SbAccordionItem Title="Details">
|
||||
<p>This section starts collapsed.</p>
|
||||
</SbAccordionItem>
|
||||
<SbAccordionItem Title="Conclusion">
|
||||
<p>Final section.</p>
|
||||
</SbAccordionItem>
|
||||
</SbAccordion>
|
||||
```
|
||||
|
||||
### With Subtitles
|
||||
|
||||
Use the `Subtitle` slot on `SbAccordionItem` to show a short description below the title. Title and subtitle are stacked vertically in the header.
|
||||
|
||||
```razor
|
||||
<SbAccordion>
|
||||
<SbAccordionItem Title="Profile">
|
||||
<Subtitle>
|
||||
<SbText Size="SbSize.Sm" Color="SbColor.Muted">Manage your personal information</SbText>
|
||||
</Subtitle>
|
||||
<ChildContent>
|
||||
<SbText>Update your profile details.</SbText>
|
||||
</ChildContent>
|
||||
</SbAccordionItem>
|
||||
<SbAccordionItem Title="Notifications">
|
||||
<Subtitle>
|
||||
<SbText Size="SbSize.Sm" Color="SbColor.Muted">Configure notification preferences</SbText>
|
||||
</Subtitle>
|
||||
<ChildContent>
|
||||
<SbText>Choose which notifications you want to receive.</SbText>
|
||||
</ChildContent>
|
||||
</SbAccordionItem>
|
||||
</SbAccordion>
|
||||
```
|
||||
|
||||
### With Icons
|
||||
|
||||
```razor
|
||||
<SbAccordion>
|
||||
<SbAccordionItem Title="Account Settings">
|
||||
<Icon><SbIcon Name="user" /></Icon>
|
||||
<ChildContent>
|
||||
<SbStack Gap="3">
|
||||
<SbTextField Label="Username" />
|
||||
<SbTextField Label="Email" />
|
||||
</SbStack>
|
||||
</ChildContent>
|
||||
</SbAccordionItem>
|
||||
<SbAccordionItem Title="Security">
|
||||
<Icon><SbIcon Name="shield" /></Icon>
|
||||
<ChildContent>
|
||||
<SbStack Gap="3">
|
||||
<SbTextField Label="Current Password" Type="password" />
|
||||
<SbTextField Label="New Password" Type="password" />
|
||||
</SbStack>
|
||||
</ChildContent>
|
||||
</SbAccordionItem>
|
||||
<SbAccordionItem Title="Notifications">
|
||||
<Icon><SbIcon Name="bell" /></Icon>
|
||||
<ChildContent>
|
||||
<SbSwitch Label="Email notifications" />
|
||||
<SbSwitch Label="Push notifications" />
|
||||
</ChildContent>
|
||||
</SbAccordionItem>
|
||||
</SbAccordion>
|
||||
```
|
||||
|
||||
### Product Specifications
|
||||
|
||||
```razor
|
||||
<SbAccordion>
|
||||
<SbAccordionItem Title="Product Description" DefaultExpanded="true">
|
||||
<p>@product.Description</p>
|
||||
</SbAccordionItem>
|
||||
<SbAccordionItem Title="Specifications">
|
||||
<SbTable>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Property</th>
|
||||
<th>Value</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@foreach (var spec in product.Specifications)
|
||||
{
|
||||
<tr>
|
||||
<td>@spec.Key</td>
|
||||
<td>@spec.Value</td>
|
||||
</tr>
|
||||
}
|
||||
</tbody>
|
||||
</SbTable>
|
||||
</SbAccordionItem>
|
||||
<SbAccordionItem Title="Reviews (@product.ReviewCount)">
|
||||
@foreach (var review in product.Reviews)
|
||||
{
|
||||
<SbCard>
|
||||
<strong>@review.Author</strong> - @review.Rating/5
|
||||
<p>@review.Comment</p>
|
||||
</SbCard>
|
||||
}
|
||||
</SbAccordionItem>
|
||||
</SbAccordion>
|
||||
```
|
||||
|
||||
### Tracking Expanded State
|
||||
|
||||
```razor
|
||||
<SbAccordion OnExpandedChanged="HandleExpansionChange">
|
||||
<SbAccordionItem Title="Step 1: Basic Info">
|
||||
<SbTextField Label="Name" @bind-Value="name" />
|
||||
</SbAccordionItem>
|
||||
<SbAccordionItem Title="Step 2: Details">
|
||||
<SbTextArea Label="Description" @bind-Value="description" />
|
||||
</SbAccordionItem>
|
||||
</SbAccordion>
|
||||
|
||||
<SbText>Expanded sections: @expandedCount</SbText>
|
||||
|
||||
@code {
|
||||
private int expandedCount = 0;
|
||||
|
||||
private void HandleExpansionChange(HashSet<SbAccordionItem> expanded)
|
||||
{
|
||||
expandedCount = expanded.Count;
|
||||
}
|
||||
}
|
||||
```
|
||||
@@ -0,0 +1,195 @@
|
||||
# SbAccordionItem
|
||||
|
||||
A single collapsible item used within SbAccordion.
|
||||
|
||||
## Parameters
|
||||
|
||||
| Parameter | Type | Default | Description |
|
||||
|-----------|------|---------|-------------|
|
||||
| Title | string | "" | Item title displayed in the header |
|
||||
| Disabled | bool | false | Whether the item is disabled |
|
||||
| DefaultExpanded | bool | false | Whether the item is initially expanded |
|
||||
|
||||
## Templates / Slots
|
||||
|
||||
| Slot | Type | Description |
|
||||
|------|------|-------------|
|
||||
| Icon | RenderFragment | Icon displayed before the title |
|
||||
| Subtitle | RenderFragment | Subtitle displayed below the title (stacked vertically in the header) |
|
||||
| ChildContent | RenderFragment | Collapsible content |
|
||||
|
||||
## Cascading Parameters
|
||||
|
||||
| Parameter | Type | Description |
|
||||
|-----------|------|-------------|
|
||||
| Parent | SbAccordion | Parent accordion container |
|
||||
|
||||
## CSS Classes
|
||||
|
||||
- `sb-accordion-item` - Base class
|
||||
- `sb-accordion-item--expanded` - When item is expanded
|
||||
- `sb-accordion-item--disabled` - When item is disabled
|
||||
- `sb-accordion-item__header` - Header button
|
||||
- `sb-accordion-item__header-start` - Header start section
|
||||
- `sb-accordion-item__icon` - Icon container
|
||||
- `sb-accordion-item__title` - Title text
|
||||
- `sb-accordion-item__subtitle` - Subtitle text
|
||||
- `sb-accordion-item__chevron` - Expand/collapse indicator
|
||||
- `sb-accordion-item__content` - Content wrapper
|
||||
- `sb-accordion-item__content--expanded` - Expanded content
|
||||
- `sb-accordion-item__body` - Inner content container
|
||||
|
||||
## Accessibility
|
||||
|
||||
- Uses `aria-expanded` to indicate expansion state
|
||||
- Uses `aria-controls` to link button to content
|
||||
- Content uses `hidden` attribute when collapsed
|
||||
|
||||
## Examples
|
||||
|
||||
### Basic Usage
|
||||
|
||||
```razor
|
||||
<SbAccordion>
|
||||
<SbAccordionItem Title="Click to expand">
|
||||
<p>This content is revealed when expanded.</p>
|
||||
</SbAccordionItem>
|
||||
</SbAccordion>
|
||||
```
|
||||
|
||||
### Initially Expanded
|
||||
|
||||
```razor
|
||||
<SbAccordion>
|
||||
<SbAccordionItem Title="Important Information" DefaultExpanded="true">
|
||||
<p>This content is visible by default.</p>
|
||||
</SbAccordionItem>
|
||||
<SbAccordionItem Title="Additional Details">
|
||||
<p>This is collapsed by default.</p>
|
||||
</SbAccordionItem>
|
||||
</SbAccordion>
|
||||
```
|
||||
|
||||
### With Icon
|
||||
|
||||
```razor
|
||||
<SbAccordionItem Title="Account Settings">
|
||||
<Icon>
|
||||
<SbIcon Name="user" Size="SbSize.Sm" />
|
||||
</Icon>
|
||||
<ChildContent>
|
||||
<SbTextField Label="Display Name" />
|
||||
<SbTextField Label="Email" />
|
||||
</ChildContent>
|
||||
</SbAccordionItem>
|
||||
```
|
||||
|
||||
### With Subtitle
|
||||
|
||||
```razor
|
||||
<SbAccordionItem Title="Payment Method">
|
||||
<Subtitle>
|
||||
<SbText Size="sm" Color="muted">Visa ending in 4242</SbText>
|
||||
</Subtitle>
|
||||
<ChildContent>
|
||||
<SbButton>Update Payment Method</SbButton>
|
||||
</ChildContent>
|
||||
</SbAccordionItem>
|
||||
```
|
||||
|
||||
### Disabled Item
|
||||
|
||||
```razor
|
||||
<SbAccordion>
|
||||
<SbAccordionItem Title="Free Plan">
|
||||
<p>Basic features included.</p>
|
||||
</SbAccordionItem>
|
||||
<SbAccordionItem Title="Premium Features" Disabled="@(!isPremium)">
|
||||
<Subtitle>
|
||||
<SbText Size="sm" Color="muted">Requires premium subscription</SbText>
|
||||
</Subtitle>
|
||||
<ChildContent>
|
||||
<p>Advanced features content...</p>
|
||||
</ChildContent>
|
||||
</SbAccordionItem>
|
||||
</SbAccordion>
|
||||
|
||||
@code {
|
||||
private bool isPremium = false;
|
||||
}
|
||||
```
|
||||
|
||||
### Complex Content
|
||||
|
||||
```razor
|
||||
<SbAccordionItem Title="Order Details">
|
||||
<Icon><SbIcon Name="shopping-cart" /></Icon>
|
||||
<Subtitle>
|
||||
<SbStack Direction="SbStackDirection.Row" Gap="2">
|
||||
<SbBadge>3 items</SbBadge>
|
||||
<SbText Size="sm">$129.99</SbText>
|
||||
</SbStack>
|
||||
</Subtitle>
|
||||
<ChildContent>
|
||||
<SbTable>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Item</th>
|
||||
<th>Qty</th>
|
||||
<th>Price</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@foreach (var item in orderItems)
|
||||
{
|
||||
<tr>
|
||||
<td>@item.Name</td>
|
||||
<td>@item.Quantity</td>
|
||||
<td>@item.Price.ToString("C")</td>
|
||||
</tr>
|
||||
}
|
||||
</tbody>
|
||||
</SbTable>
|
||||
</ChildContent>
|
||||
</SbAccordionItem>
|
||||
```
|
||||
|
||||
### Settings Panel
|
||||
|
||||
```razor
|
||||
<SbAccordion Multiple="true">
|
||||
<SbAccordionItem Title="General" DefaultExpanded="true">
|
||||
<Icon><SbIcon Name="settings" /></Icon>
|
||||
<ChildContent>
|
||||
<SbStack Gap="3">
|
||||
<SbTextField Label="Site Name" @bind-Value="siteName" />
|
||||
<SbTextField Label="Site URL" @bind-Value="siteUrl" />
|
||||
<SbSelect Label="Language" @bind-Value="language">
|
||||
<SbSelectOption Value="en">English</SbSelectOption>
|
||||
<SbSelectOption Value="es">Spanish</SbSelectOption>
|
||||
</SbSelect>
|
||||
</SbStack>
|
||||
</ChildContent>
|
||||
</SbAccordionItem>
|
||||
|
||||
<SbAccordionItem Title="Appearance">
|
||||
<Icon><SbIcon Name="palette" /></Icon>
|
||||
<ChildContent>
|
||||
<SbStack Gap="3">
|
||||
<SbColorPicker Label="Primary Color" @bind-Value="primaryColor" />
|
||||
<SbSwitch Label="Dark Mode" @bind-Value="darkMode" />
|
||||
</SbStack>
|
||||
</ChildContent>
|
||||
</SbAccordionItem>
|
||||
|
||||
<SbAccordionItem Title="Advanced">
|
||||
<Icon><SbIcon Name="code" /></Icon>
|
||||
<Subtitle>
|
||||
<SbText Size="xs" Color="warning">For developers only</SbText>
|
||||
</Subtitle>
|
||||
<ChildContent>
|
||||
<SbTextArea Label="Custom CSS" @bind-Value="customCss" Rows="10" />
|
||||
</ChildContent>
|
||||
</SbAccordionItem>
|
||||
</SbAccordion>
|
||||
```
|
||||
@@ -0,0 +1,200 @@
|
||||
# SbBreadcrumb
|
||||
|
||||
A breadcrumb navigation component showing the current page location within a hierarchy.
|
||||
|
||||
## Parameters
|
||||
|
||||
| Parameter | Type | Default | Description |
|
||||
|-----------|------|---------|-------------|
|
||||
| Items | List\<SbBreadcrumbItem\> | new() | List of breadcrumb items |
|
||||
| Separator | string | "/" | Separator character between items |
|
||||
| Class | string? | null | Additional CSS classes |
|
||||
|
||||
## SbBreadcrumbItem Class
|
||||
|
||||
Each item has `Text`, optional `Href` (null = current page, not a link), and optional `Icon`. The `Icon` value is rendered as text before the label (e.g. an icon name or character); for full icon components you would extend the item type or use a custom template.
|
||||
|
||||
```csharp
|
||||
public class SbBreadcrumbItem
|
||||
{
|
||||
public string Text { get; set; } = "";
|
||||
public string? Href { get; set; }
|
||||
public string? Icon { get; set; }
|
||||
|
||||
public SbBreadcrumbItem() { }
|
||||
public SbBreadcrumbItem(string text, string? href = null) { }
|
||||
}
|
||||
```
|
||||
|
||||
## CSS Classes
|
||||
|
||||
- `sb-breadcrumb` - Base class
|
||||
- `sb-breadcrumb__list` - Ordered list container
|
||||
- `sb-breadcrumb__item` - Individual breadcrumb item
|
||||
- `sb-breadcrumb__item--current` - Current/last item
|
||||
- `sb-breadcrumb__link` - Clickable link
|
||||
- `sb-breadcrumb__text` - Non-clickable text
|
||||
- `sb-breadcrumb__icon` - Icon container
|
||||
- `sb-breadcrumb__separator` - Separator element
|
||||
|
||||
## Accessibility
|
||||
|
||||
- Uses `nav` element with `aria-label="Breadcrumb"`
|
||||
- Uses `ol` (ordered list) for proper semantics
|
||||
- Last item has `aria-current="page"`
|
||||
- Separators have `aria-hidden="true"`
|
||||
|
||||
## Examples
|
||||
|
||||
### Basic Usage
|
||||
|
||||
```razor
|
||||
<SbBreadcrumb Items="@breadcrumbs" />
|
||||
|
||||
@code {
|
||||
private List<SbBreadcrumbItem> breadcrumbs = new()
|
||||
{
|
||||
new("Home", "/"),
|
||||
new("Products", "/products"),
|
||||
new("Electronics", "/products/electronics"),
|
||||
new("Laptops") // Current page - no href
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
### With Custom Separator
|
||||
|
||||
```razor
|
||||
<SbBreadcrumb Items="@items" Separator=">" />
|
||||
<SbBreadcrumb Items="@items" Separator="→" />
|
||||
<SbBreadcrumb Items="@items" Separator="•" />
|
||||
```
|
||||
|
||||
### With Icons
|
||||
|
||||
```razor
|
||||
@code {
|
||||
private List<SbBreadcrumbItem> breadcrumbs = new()
|
||||
{
|
||||
new SbBreadcrumbItem { Text = "Home", Href = "/", Icon = "home" },
|
||||
new SbBreadcrumbItem { Text = "Users", Href = "/users", Icon = "users" },
|
||||
new SbBreadcrumbItem { Text = "John Doe", Icon = "user" }
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
### Dynamic Breadcrumbs
|
||||
|
||||
```razor
|
||||
<SbBreadcrumb Items="@BuildBreadcrumbs()" />
|
||||
|
||||
@code {
|
||||
private Category currentCategory;
|
||||
|
||||
private List<SbBreadcrumbItem> BuildBreadcrumbs()
|
||||
{
|
||||
var items = new List<SbBreadcrumbItem>
|
||||
{
|
||||
new("Home", "/"),
|
||||
new("Categories", "/categories")
|
||||
};
|
||||
|
||||
// Add parent categories
|
||||
var parent = currentCategory?.Parent;
|
||||
var ancestors = new List<Category>();
|
||||
while (parent != null)
|
||||
{
|
||||
ancestors.Insert(0, parent);
|
||||
parent = parent.Parent;
|
||||
}
|
||||
|
||||
foreach (var ancestor in ancestors)
|
||||
{
|
||||
items.Add(new(ancestor.Name, $"/categories/{ancestor.Id}"));
|
||||
}
|
||||
|
||||
// Add current category (no href)
|
||||
items.Add(new(currentCategory.Name));
|
||||
|
||||
return items;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### In Page Layout
|
||||
|
||||
Breadcrumbs are typically rendered in the layout's top bar (e.g. Wish theme's `WishTopBar`). Content area example:
|
||||
|
||||
```razor
|
||||
<SbContainer>
|
||||
<SbStack Gap="4">
|
||||
<SbBreadcrumb Items="@breadcrumbs" />
|
||||
<h1>Page Content</h1>
|
||||
</SbStack>
|
||||
</SbContainer>
|
||||
```
|
||||
|
||||
### Admin Panel Style
|
||||
|
||||
```razor
|
||||
<SbContainer>
|
||||
<SbStack Gap="4">
|
||||
<SbBreadcrumb Items="@new List<SbBreadcrumbItem>
|
||||
{
|
||||
new(\"Dashboard\", \"/admin\"),
|
||||
new(\"Content\", \"/admin/content\"),
|
||||
new(\"Articles\", \"/admin/content/articles\"),
|
||||
new(\"Edit Article\")
|
||||
}" />
|
||||
|
||||
<SbCard>
|
||||
<SbHeading Level="1">Edit Article</SbHeading>
|
||||
<!-- Form content -->
|
||||
</SbCard>
|
||||
</SbStack>
|
||||
</SbContainer>
|
||||
```
|
||||
|
||||
### E-Commerce Category Navigation
|
||||
|
||||
```razor
|
||||
@page "/products/{**path}"
|
||||
|
||||
<SbBreadcrumb Items="@BuildCategoryPath()" Separator="›" />
|
||||
|
||||
<SbGrid Columns="4" Gap="4">
|
||||
@foreach (var product in products)
|
||||
{
|
||||
<SbCard>
|
||||
<img src="@product.Image" alt="@product.Name" />
|
||||
<SbHeading Level="4">@product.Name</SbHeading>
|
||||
<SbText>@product.Price.ToString("C")</SbText>
|
||||
</SbCard>
|
||||
}
|
||||
</SbGrid>
|
||||
|
||||
@code {
|
||||
[Parameter] public string? Path { get; set; }
|
||||
|
||||
private List<SbBreadcrumbItem> BuildCategoryPath()
|
||||
{
|
||||
var items = new List<SbBreadcrumbItem> { new("Shop", "/products") };
|
||||
|
||||
if (!string.IsNullOrEmpty(Path))
|
||||
{
|
||||
var segments = Path.Split('/');
|
||||
var currentPath = "/products";
|
||||
|
||||
for (int i = 0; i < segments.Length; i++)
|
||||
{
|
||||
currentPath += "/" + segments[i];
|
||||
var isLast = i == segments.Length - 1;
|
||||
items.Add(new(segments[i].Replace("-", " ").ToTitleCase(),
|
||||
isLast ? null : currentPath));
|
||||
}
|
||||
}
|
||||
|
||||
return items;
|
||||
}
|
||||
}
|
||||
```
|
||||
@@ -0,0 +1,167 @@
|
||||
# SbNavItem
|
||||
|
||||
A navigation link item component with active state detection.
|
||||
|
||||
## Parameters
|
||||
|
||||
| Parameter | Type | Default | Description |
|
||||
|-----------|------|---------|-------------|
|
||||
| Href | string? | null | Navigation URL |
|
||||
| Text | string? | null | Navigation text |
|
||||
| Match | NavLinkMatch | Prefix | URL matching behavior (All or Prefix) |
|
||||
| Disabled | bool | false | Whether the item is disabled |
|
||||
| Class | string? | null | Additional CSS classes |
|
||||
| Style | string? | null | Inline styles |
|
||||
| AdditionalAttributes | Dictionary\<string, object\>? | null | Additional HTML attributes |
|
||||
|
||||
## Templates / Slots
|
||||
|
||||
| Slot | Type | Description |
|
||||
|------|------|-------------|
|
||||
| Icon | RenderFragment | Icon content displayed before text |
|
||||
| Badge | RenderFragment | Badge content displayed after text |
|
||||
|
||||
## CSS Classes
|
||||
|
||||
- `sb-nav-item` - Base class
|
||||
- `sb-nav-item--active` - When the current URL matches
|
||||
- `sb-nav-item--disabled` - When item is disabled
|
||||
- `sb-nav-item__icon` - Icon container
|
||||
- `sb-nav-item__text` - Text container
|
||||
- `sb-nav-item__badge` - Badge container
|
||||
|
||||
## URL Matching
|
||||
|
||||
- **Prefix** (default): Item is active if current URL starts with `Href`
|
||||
- **All**: Item is active only if current URL exactly matches `Href`
|
||||
|
||||
## Examples
|
||||
|
||||
### Basic Usage
|
||||
|
||||
```razor
|
||||
<SbNavItem Href="/dashboard" Text="Dashboard" />
|
||||
```
|
||||
|
||||
### With Icon
|
||||
|
||||
```razor
|
||||
<SbNavItem Href="/users" Text="Users">
|
||||
<Icon>
|
||||
<SbIcon Name="users" Size="SbSize.Sm" />
|
||||
</Icon>
|
||||
</SbNavItem>
|
||||
```
|
||||
|
||||
### With Badge
|
||||
|
||||
```razor
|
||||
<SbNavItem Href="/inbox" Text="Inbox">
|
||||
<Icon><SbIcon Name="inbox" /></Icon>
|
||||
<Badge><SbBadge Value="5" Color="SbColor.Primary" /></Badge>
|
||||
</SbNavItem>
|
||||
```
|
||||
|
||||
### Exact URL Match
|
||||
|
||||
```razor
|
||||
@* Only active when URL is exactly "/" *@
|
||||
<SbNavItem Href="/" Text="Home" Match="NavLinkMatch.All">
|
||||
<Icon><SbIcon Name="home" /></Icon>
|
||||
</SbNavItem>
|
||||
|
||||
@* Active when URL starts with "/users" (e.g., /users, /users/123) *@
|
||||
<SbNavItem Href="/users" Text="Users" Match="NavLinkMatch.Prefix">
|
||||
<Icon><SbIcon Name="users" /></Icon>
|
||||
</SbNavItem>
|
||||
```
|
||||
|
||||
### Disabled Item
|
||||
|
||||
```razor
|
||||
<SbNavItem Href="/premium" Text="Premium Features" Disabled="@(!isPremiumUser)">
|
||||
<Icon><SbIcon Name="star" /></Icon>
|
||||
</SbNavItem>
|
||||
|
||||
@code {
|
||||
private bool isPremiumUser = false;
|
||||
}
|
||||
```
|
||||
|
||||
### Navigation Menu Example
|
||||
|
||||
```razor
|
||||
<SbNavMenu>
|
||||
<SbNavItem Href="/" Text="Dashboard" Match="NavLinkMatch.All">
|
||||
<Icon><SbIcon Name="layout" /></Icon>
|
||||
</SbNavItem>
|
||||
<SbNavItem Href="/projects" Text="Projects">
|
||||
<Icon><SbIcon Name="folder" /></Icon>
|
||||
<Badge><SbBadge Value="3" /></Badge>
|
||||
</SbNavItem>
|
||||
<SbNavItem Href="/team" Text="Team">
|
||||
<Icon><SbIcon Name="users" /></Icon>
|
||||
</SbNavItem>
|
||||
<SbNavItem Href="/reports" Text="Reports">
|
||||
<Icon><SbIcon Name="bar-chart" /></Icon>
|
||||
</SbNavItem>
|
||||
|
||||
<SbSpacer Grow="true" />
|
||||
|
||||
<SbNavItem Href="/settings" Text="Settings">
|
||||
<Icon><SbIcon Name="settings" /></Icon>
|
||||
</SbNavItem>
|
||||
<SbNavItem Href="/help" Text="Help & Support">
|
||||
<Icon><SbIcon Name="help-circle" /></Icon>
|
||||
</SbNavItem>
|
||||
</SbNavMenu>
|
||||
```
|
||||
|
||||
### Icon-Only (for collapsed sidebar)
|
||||
|
||||
```razor
|
||||
<SbNavItem Href="/home">
|
||||
<Icon>
|
||||
<SbTooltip Text="Home" Placement="right">
|
||||
<SbIcon Name="home" />
|
||||
</SbTooltip>
|
||||
</Icon>
|
||||
</SbNavItem>
|
||||
```
|
||||
|
||||
### With Custom Styling
|
||||
|
||||
```razor
|
||||
<SbNavItem Href="/important"
|
||||
Text="Important"
|
||||
Class="nav-item-highlight"
|
||||
Style="font-weight: bold;">
|
||||
<Icon><SbIcon Name="alert-circle" Color="SbColor.Warning" /></Icon>
|
||||
</SbNavItem>
|
||||
```
|
||||
|
||||
### Dynamic Navigation
|
||||
|
||||
```razor
|
||||
@foreach (var item in navigationItems)
|
||||
{
|
||||
<SbNavItem Href="@item.Url"
|
||||
Text="@item.Title"
|
||||
Disabled="@(!item.HasAccess)">
|
||||
<Icon><SbIcon Name="@item.Icon" /></Icon>
|
||||
@if (item.BadgeCount > 0)
|
||||
{
|
||||
<Badge><SbBadge Value="@item.BadgeCount" /></Badge>
|
||||
}
|
||||
</SbNavItem>
|
||||
}
|
||||
|
||||
@code {
|
||||
private List<NavItem> navigationItems = new()
|
||||
{
|
||||
new() { Url = "/", Title = "Home", Icon = "home", HasAccess = true },
|
||||
new() { Url = "/users", Title = "Users", Icon = "users", HasAccess = true, BadgeCount = 5 },
|
||||
new() { Url = "/admin", Title = "Admin", Icon = "shield", HasAccess = isAdmin }
|
||||
};
|
||||
}
|
||||
```
|
||||
@@ -0,0 +1,187 @@
|
||||
# SbNavMenu
|
||||
|
||||
A navigation menu container component for organizing navigation items.
|
||||
|
||||
## Parameters
|
||||
|
||||
| Parameter | Type | Default | Description |
|
||||
|-----------|------|---------|-------------|
|
||||
| Collapsed | bool | false | Whether the menu is collapsed |
|
||||
| AriaLabel | string | "Navigation" | Accessible label for the navigation |
|
||||
| Class | string? | null | Additional CSS classes |
|
||||
| Style | string? | null | Inline styles |
|
||||
| AdditionalAttributes | Dictionary\<string, object\>? | null | Additional HTML attributes |
|
||||
|
||||
## Events
|
||||
|
||||
| Event | Type | Description |
|
||||
|-------|------|-------------|
|
||||
| CollapsedChanged | EventCallback\<bool\> | Fired when collapsed state changes |
|
||||
|
||||
## Templates / Slots
|
||||
|
||||
| Slot | Type | Description |
|
||||
|------|------|-------------|
|
||||
| ChildContent | RenderFragment | Navigation content. Use SbNavItem components, or any markup (e.g. ul/li with links). |
|
||||
|
||||
## Methods
|
||||
|
||||
| Method | Return Type | Description |
|
||||
|--------|-------------|-------------|
|
||||
| ToggleAsync() | Task | Toggle the collapsed state |
|
||||
|
||||
## CSS Classes
|
||||
|
||||
- `sb-nav-menu` - Base class
|
||||
- `sb-nav-menu--collapsed` - When menu is collapsed
|
||||
|
||||
## Examples
|
||||
|
||||
### Basic Usage
|
||||
|
||||
```razor
|
||||
<SbNavMenu>
|
||||
<SbNavItem Href="/" Text="Home">
|
||||
<Icon><SbIcon Name="home" /></Icon>
|
||||
</SbNavItem>
|
||||
<SbNavItem Href="/about" Text="About">
|
||||
<Icon><SbIcon Name="info" /></Icon>
|
||||
</SbNavItem>
|
||||
<SbNavItem Href="/contact" Text="Contact">
|
||||
<Icon><SbIcon Name="mail" /></Icon>
|
||||
</SbNavItem>
|
||||
</SbNavMenu>
|
||||
```
|
||||
|
||||
### Inside a layout sidebar
|
||||
|
||||
Use `SbNavMenu` inside the Wish theme's sidebar (e.g. `WishSidebar` or `WishExpandPanel`):
|
||||
|
||||
```razor
|
||||
<SbNavMenu>
|
||||
<SbNavItem Href="/" Text="Dashboard">
|
||||
<Icon><SbIcon Name="layout" /></Icon>
|
||||
</SbNavItem>
|
||||
<SbNavItem Href="/users" Text="Users">
|
||||
<Icon><SbIcon Name="users" /></Icon>
|
||||
</SbNavItem>
|
||||
<SbNavItem Href="/settings" Text="Settings">
|
||||
<Icon><SbIcon Name="settings" /></Icon>
|
||||
</SbNavItem>
|
||||
</SbNavMenu>
|
||||
```
|
||||
|
||||
### Collapsible Menu
|
||||
|
||||
```razor
|
||||
<SbNavMenu @bind-Collapsed="isCollapsed">
|
||||
<SbNavItem Href="/" Text="Home">
|
||||
<Icon><SbIcon Name="home" /></Icon>
|
||||
</SbNavItem>
|
||||
<SbNavItem Href="/projects" Text="Projects">
|
||||
<Icon><SbIcon Name="folder" /></Icon>
|
||||
</SbNavItem>
|
||||
</SbNavMenu>
|
||||
|
||||
<SbButton OnClick="() => isCollapsed = !isCollapsed">
|
||||
Toggle Menu
|
||||
</SbButton>
|
||||
|
||||
@code {
|
||||
private bool isCollapsed = false;
|
||||
}
|
||||
```
|
||||
|
||||
### With Grouped Sections
|
||||
|
||||
```razor
|
||||
<SbNavMenu AriaLabel="Main Navigation">
|
||||
<SbText Size="xs" Color="muted" Class="nav-section-label">Main</SbText>
|
||||
<SbNavItem Href="/" Text="Dashboard">
|
||||
<Icon><SbIcon Name="layout" /></Icon>
|
||||
</SbNavItem>
|
||||
<SbNavItem Href="/analytics" Text="Analytics">
|
||||
<Icon><SbIcon Name="bar-chart" /></Icon>
|
||||
</SbNavItem>
|
||||
|
||||
<SbSpacer Size="SbSpacerSize.Small" />
|
||||
|
||||
<SbText Size="xs" Color="muted" Class="nav-section-label">Content</SbText>
|
||||
<SbNavItem Href="/posts" Text="Posts">
|
||||
<Icon><SbIcon Name="file-text" /></Icon>
|
||||
</SbNavItem>
|
||||
<SbNavItem Href="/media" Text="Media">
|
||||
<Icon><SbIcon Name="image" /></Icon>
|
||||
</SbNavItem>
|
||||
|
||||
<SbSpacer Size="SbSpacerSize.Small" />
|
||||
|
||||
<SbText Size="xs" Color="muted" Class="nav-section-label">System</SbText>
|
||||
<SbNavItem Href="/users" Text="Users">
|
||||
<Icon><SbIcon Name="users" /></Icon>
|
||||
</SbNavItem>
|
||||
<SbNavItem Href="/settings" Text="Settings">
|
||||
<Icon><SbIcon Name="settings" /></Icon>
|
||||
</SbNavItem>
|
||||
</SbNavMenu>
|
||||
```
|
||||
|
||||
### With Badges
|
||||
|
||||
```razor
|
||||
<SbNavMenu>
|
||||
<SbNavItem Href="/inbox" Text="Inbox">
|
||||
<Icon><SbIcon Name="inbox" /></Icon>
|
||||
<Badge><SbBadge Value="5" Color="SbColor.Primary" /></Badge>
|
||||
</SbNavItem>
|
||||
<SbNavItem Href="/notifications" Text="Notifications">
|
||||
<Icon><SbIcon Name="bell" /></Icon>
|
||||
<Badge><SbBadge Value="12" Color="SbColor.Danger" /></Badge>
|
||||
</SbNavItem>
|
||||
<SbNavItem Href="/tasks" Text="Tasks">
|
||||
<Icon><SbIcon Name="check-square" /></Icon>
|
||||
<Badge><SbBadge Value="3" Color="SbColor.Warning" /></Badge>
|
||||
</SbNavItem>
|
||||
</SbNavMenu>
|
||||
```
|
||||
|
||||
### Admin Panel Navigation
|
||||
|
||||
```razor
|
||||
<SbNavMenu AriaLabel="Admin Navigation">
|
||||
@* Main navigation items *@
|
||||
<SbNavItem Href="/admin" Text="Dashboard" Match="NavLinkMatch.All">
|
||||
<Icon><SbIcon Name="layout" /></Icon>
|
||||
</SbNavItem>
|
||||
|
||||
@* Content management *@
|
||||
<SbAccordion>
|
||||
<SbAccordionItem Title="Content">
|
||||
<Icon><SbIcon Name="file-text" /></Icon>
|
||||
<ChildContent>
|
||||
<SbNavItem Href="/admin/posts" Text="Posts" />
|
||||
<SbNavItem Href="/admin/pages" Text="Pages" />
|
||||
<SbNavItem Href="/admin/media" Text="Media" />
|
||||
</ChildContent>
|
||||
</SbAccordionItem>
|
||||
<SbAccordionItem Title="Users">
|
||||
<Icon><SbIcon Name="users" /></Icon>
|
||||
<ChildContent>
|
||||
<SbNavItem Href="/admin/users" Text="All Users" />
|
||||
<SbNavItem Href="/admin/roles" Text="Roles" />
|
||||
<SbNavItem Href="/admin/permissions" Text="Permissions" />
|
||||
</ChildContent>
|
||||
</SbAccordionItem>
|
||||
</SbAccordion>
|
||||
|
||||
<SbSpacer Grow="true" />
|
||||
|
||||
@* Bottom items *@
|
||||
<SbNavItem Href="/admin/settings" Text="Settings">
|
||||
<Icon><SbIcon Name="settings" /></Icon>
|
||||
</SbNavItem>
|
||||
<SbNavItem Href="/admin/help" Text="Help">
|
||||
<Icon><SbIcon Name="help-circle" /></Icon>
|
||||
</SbNavItem>
|
||||
</SbNavMenu>
|
||||
```
|
||||
@@ -0,0 +1,180 @@
|
||||
# SbStep
|
||||
|
||||
A single step component used within SbStepper.
|
||||
|
||||
## Parameters
|
||||
|
||||
| Parameter | Type | Default | Description |
|
||||
|-----------|------|---------|-------------|
|
||||
| Label | string | "" | Step label text |
|
||||
| Description | string? | null | Step description text |
|
||||
| Optional | bool | false | Whether the step is optional |
|
||||
|
||||
## Templates / Slots
|
||||
|
||||
| Slot | Type | Description |
|
||||
|------|------|-------------|
|
||||
| Icon | RenderFragment | Custom icon for the step indicator |
|
||||
| ChildContent | RenderFragment | Step content |
|
||||
|
||||
## Cascading Parameters
|
||||
|
||||
| Parameter | Type | Description |
|
||||
|-----------|------|-------------|
|
||||
| Parent | SbStepper | Parent stepper container |
|
||||
|
||||
## CSS Classes
|
||||
|
||||
- `sb-step-content` - Step content wrapper
|
||||
|
||||
## Examples
|
||||
|
||||
### Basic Usage
|
||||
|
||||
```razor
|
||||
<SbStepper>
|
||||
<SbStep Label="Step 1">
|
||||
<p>Content for step 1</p>
|
||||
</SbStep>
|
||||
<SbStep Label="Step 2">
|
||||
<p>Content for step 2</p>
|
||||
</SbStep>
|
||||
</SbStepper>
|
||||
```
|
||||
|
||||
### With Description
|
||||
|
||||
```razor
|
||||
<SbStep Label="Account Setup" Description="Create your account credentials">
|
||||
<SbStack Gap="4">
|
||||
<SbTextField Label="Email" @bind-Value="email" />
|
||||
<SbTextField Label="Password" Type="password" @bind-Value="password" />
|
||||
</SbStack>
|
||||
</SbStep>
|
||||
```
|
||||
|
||||
### With Custom Icon
|
||||
|
||||
```razor
|
||||
<SbStep Label="Shipping">
|
||||
<Icon>
|
||||
<SbIcon Name="truck" Size="SbSize.Sm" />
|
||||
</Icon>
|
||||
<ChildContent>
|
||||
<p>Enter your shipping details</p>
|
||||
</ChildContent>
|
||||
</SbStep>
|
||||
```
|
||||
|
||||
### Optional Step
|
||||
|
||||
```razor
|
||||
<SbStepper>
|
||||
<SbStep Label="Required Info">
|
||||
<p>This step is required</p>
|
||||
</SbStep>
|
||||
<SbStep Label="Additional Details" Optional="true">
|
||||
<p>This step can be skipped</p>
|
||||
</SbStep>
|
||||
<SbStep Label="Confirmation">
|
||||
<p>Review and confirm</p>
|
||||
</SbStep>
|
||||
</SbStepper>
|
||||
```
|
||||
|
||||
### Form Wizard Example
|
||||
|
||||
```razor
|
||||
<SbStepper @bind-ActiveIndex="step">
|
||||
<SbStep Label="Personal Info" Description="Your basic information">
|
||||
<Icon><SbIcon Name="user" /></Icon>
|
||||
<ChildContent>
|
||||
<SbGrid Columns="2" Gap="4">
|
||||
<SbTextField Label="First Name" @bind-Value="firstName" Required="true" />
|
||||
<SbTextField Label="Last Name" @bind-Value="lastName" Required="true" />
|
||||
<SbGridItem Span="2">
|
||||
<SbTextField Label="Email" @bind-Value="email" Required="true" />
|
||||
</SbGridItem>
|
||||
<SbTextField Label="Phone" @bind-Value="phone" />
|
||||
</SbGrid>
|
||||
</ChildContent>
|
||||
</SbStep>
|
||||
|
||||
<SbStep Label="Address" Description="Where should we deliver?">
|
||||
<Icon><SbIcon Name="map-pin" /></Icon>
|
||||
<ChildContent>
|
||||
<SbStack Gap="4">
|
||||
<SbTextField Label="Street Address" @bind-Value="address" />
|
||||
<SbGrid Columns="3" Gap="4">
|
||||
<SbTextField Label="City" @bind-Value="city" />
|
||||
<SbTextField Label="State" @bind-Value="state" />
|
||||
<SbTextField Label="Zip" @bind-Value="zip" />
|
||||
</SbGrid>
|
||||
</SbStack>
|
||||
</ChildContent>
|
||||
</SbStep>
|
||||
|
||||
<SbStep Label="Preferences" Description="Customize your experience" Optional="true">
|
||||
<Icon><SbIcon Name="settings" /></Icon>
|
||||
<ChildContent>
|
||||
<SbStack Gap="3">
|
||||
<SbSwitch Label="Receive promotional emails" @bind-Value="promoEmails" />
|
||||
<SbSwitch Label="Enable SMS notifications" @bind-Value="smsNotifications" />
|
||||
<SbSelect Label="Preferred Language" @bind-Value="language">
|
||||
<SbSelectOption Value="en">English</SbSelectOption>
|
||||
<SbSelectOption Value="es">Spanish</SbSelectOption>
|
||||
<SbSelectOption Value="fr">French</SbSelectOption>
|
||||
</SbSelect>
|
||||
</SbStack>
|
||||
</ChildContent>
|
||||
</SbStep>
|
||||
|
||||
<SbStep Label="Review" Description="Confirm your details">
|
||||
<Icon><SbIcon Name="check-circle" /></Icon>
|
||||
<ChildContent>
|
||||
<SbCard>
|
||||
<SbStack Gap="2">
|
||||
<SbHeading Level="4">Personal Information</SbHeading>
|
||||
<SbText>@firstName @lastName</SbText>
|
||||
<SbText>@email</SbText>
|
||||
|
||||
<SbDivider />
|
||||
|
||||
<SbHeading Level="4">Shipping Address</SbHeading>
|
||||
<SbText>@address</SbText>
|
||||
<SbText>@city, @state @zip</SbText>
|
||||
</SbStack>
|
||||
</SbCard>
|
||||
</ChildContent>
|
||||
</SbStep>
|
||||
</SbStepper>
|
||||
```
|
||||
|
||||
### With Validation
|
||||
|
||||
```razor
|
||||
<SbStep Label="Account">
|
||||
<ChildContent>
|
||||
<SbForm Model="@accountModel" OnValidSubmit="GoToNextStep">
|
||||
<SbStack Gap="4">
|
||||
<SbTextField Label="Username" @bind-Value="accountModel.Username" />
|
||||
<SbFieldError Field="Username" />
|
||||
|
||||
<SbTextField Label="Password" Type="password" @bind-Value="accountModel.Password" />
|
||||
<SbFieldError Field="Password" />
|
||||
|
||||
<SbButton Type="submit">Continue</SbButton>
|
||||
</SbStack>
|
||||
</SbForm>
|
||||
</ChildContent>
|
||||
</SbStep>
|
||||
|
||||
@code {
|
||||
private AccountModel accountModel = new();
|
||||
|
||||
private void GoToNextStep()
|
||||
{
|
||||
currentStep++;
|
||||
}
|
||||
}
|
||||
```
|
||||
@@ -0,0 +1,286 @@
|
||||
# SbStepper
|
||||
|
||||
A multi-step wizard component for guiding users through a sequential process.
|
||||
|
||||
## Parameters
|
||||
|
||||
| Parameter | Type | Default | Description |
|
||||
|-----------|------|---------|-------------|
|
||||
| ActiveIndex | int | 0 | Current active step index (0-based) |
|
||||
| Linear | bool | true | Whether steps must be completed in order |
|
||||
| Orientation | SbStepperOrientation | Horizontal | Stepper orientation |
|
||||
| ShowNavigation | bool | true | Whether to show navigation buttons |
|
||||
| BackText | string? | null | Text for the Back button; when null, uses localized default (e.g. "Previous") |
|
||||
| NextText | string? | null | Text for the Next button; when null, uses localized default |
|
||||
| FinishText | string? | null | Text for the Finish button; when null, uses localized default |
|
||||
| OptionalText | string? | null | Text for optional step label; when null, uses localized default |
|
||||
| Class | string? | null | Additional CSS classes |
|
||||
|
||||
## Events
|
||||
|
||||
| Event | Type | Description |
|
||||
|-------|------|-------------|
|
||||
| ActiveIndexChanged | EventCallback\<int\> | Fired when active step changes |
|
||||
| OnFinish | EventCallback | Fired when stepper is completed |
|
||||
|
||||
## Templates / Slots
|
||||
|
||||
| Slot | Type | Description |
|
||||
|------|------|-------------|
|
||||
| ChildContent | RenderFragment | Step content (SbStep components) |
|
||||
|
||||
## SbStep Parameters
|
||||
|
||||
Use `SbStep` inside `SbStepper` to define each step.
|
||||
|
||||
| Parameter | Type | Default | Description |
|
||||
|-----------|------|---------|-------------|
|
||||
| Label | string | "" | Step label shown in the header |
|
||||
| Description | string? | null | Optional description below the label |
|
||||
| Optional | bool | false | When true, step is marked as optional (e.g. "Optional" label) |
|
||||
| Icon | RenderFragment? | null | Custom icon for the step indicator (replaces the default number); completed steps still show a checkmark |
|
||||
| ChildContent | RenderFragment? | null | Content shown when the step is active |
|
||||
|
||||
## SbStepperOrientation Enum
|
||||
|
||||
```csharp
|
||||
public enum SbStepperOrientation
|
||||
{
|
||||
Horizontal,
|
||||
Vertical
|
||||
}
|
||||
```
|
||||
|
||||
## CSS Classes
|
||||
|
||||
- `sb-stepper` - Base class
|
||||
- `sb-stepper--horizontal` - Horizontal orientation
|
||||
- `sb-stepper--vertical` - Vertical orientation
|
||||
- `sb-stepper__steps` - Steps container
|
||||
- `sb-stepper__step` - Individual step
|
||||
- `sb-stepper__step--completed` - Completed step
|
||||
- `sb-stepper__step--active` - Active step
|
||||
- `sb-stepper__step--pending` - Pending step
|
||||
- `sb-stepper__step--optional` - Optional step
|
||||
- `sb-stepper__step-button` - Step button
|
||||
- `sb-stepper__step-indicator` - Step number/icon indicator
|
||||
- `sb-stepper__step-labels` - Step label container
|
||||
- `sb-stepper__step-label` - Step label text
|
||||
- `sb-stepper__step-description` - Step description
|
||||
- `sb-stepper__step-optional` - Optional text label
|
||||
- `sb-stepper__connector` - Connector line between steps
|
||||
- `sb-stepper__connector--completed` - Completed connector
|
||||
- `sb-stepper__content` - Content container
|
||||
- `sb-stepper__navigation` - Navigation buttons container
|
||||
- `sb-stepper__back` - Back button
|
||||
- `sb-stepper__next` - Next button
|
||||
- `sb-stepper__finish` - Finish button
|
||||
|
||||
## Examples
|
||||
|
||||
### Basic Usage
|
||||
|
||||
```razor
|
||||
<SbStepper @bind-ActiveIndex="currentStep" OnFinish="HandleFinish">
|
||||
<SbStep Label="Account">
|
||||
<SbStack Gap="4">
|
||||
<SbTextField Label="Email" @bind-Value="email" />
|
||||
<SbTextField Label="Password" Type="password" @bind-Value="password" />
|
||||
</SbStack>
|
||||
</SbStep>
|
||||
<SbStep Label="Profile">
|
||||
<SbStack Gap="4">
|
||||
<SbTextField Label="First Name" @bind-Value="firstName" />
|
||||
<SbTextField Label="Last Name" @bind-Value="lastName" />
|
||||
</SbStack>
|
||||
</SbStep>
|
||||
<SbStep Label="Confirm">
|
||||
<SbStack Gap="2">
|
||||
<SbText>Email: @email</SbText>
|
||||
<SbText>Name: @firstName @lastName</SbText>
|
||||
</SbStack>
|
||||
</SbStep>
|
||||
</SbStepper>
|
||||
|
||||
@code {
|
||||
private int currentStep = 0;
|
||||
private string email, password, firstName, lastName;
|
||||
|
||||
private async Task HandleFinish()
|
||||
{
|
||||
// Submit the form
|
||||
await SaveUser();
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### With Step Descriptions
|
||||
|
||||
Use the `Description` parameter on `SbStep` to show a subtitle under each step label.
|
||||
|
||||
```razor
|
||||
<SbStepper @bind-ActiveIndex="step">
|
||||
<SbStep Label="Account Information" Description="Enter your personal details">
|
||||
<SbStack Gap="4">
|
||||
<SbTextField Label="Full Name" @bind-Value="fullName" />
|
||||
<SbTextField Label="Email" @bind-Value="email" />
|
||||
</SbStack>
|
||||
</SbStep>
|
||||
<SbStep Label="Address" Description="Provide your shipping address">
|
||||
<SbStack Gap="4">
|
||||
<SbTextField Label="Street" @bind-Value="street" />
|
||||
<SbTextField Label="City" @bind-Value="city" />
|
||||
</SbStack>
|
||||
</SbStep>
|
||||
<SbStep Label="Review" Description="Confirm your information">
|
||||
<SbText>Review and submit.</SbText>
|
||||
</SbStep>
|
||||
</SbStepper>
|
||||
```
|
||||
|
||||
### Vertical Orientation
|
||||
|
||||
```razor
|
||||
<SbStepper Orientation="SbStepperOrientation.Vertical" @bind-ActiveIndex="step">
|
||||
<SbStep Label="Step 1" Description="Enter basic information">
|
||||
Content for step 1
|
||||
</SbStep>
|
||||
<SbStep Label="Step 2" Description="Configure settings">
|
||||
Content for step 2
|
||||
</SbStep>
|
||||
<SbStep Label="Step 3" Description="Review and submit">
|
||||
Content for step 3
|
||||
</SbStep>
|
||||
</SbStepper>
|
||||
```
|
||||
|
||||
### With Optional Steps
|
||||
|
||||
```razor
|
||||
<SbStepper @bind-ActiveIndex="step">
|
||||
<SbStep Label="Required Info">
|
||||
Required step content
|
||||
</SbStep>
|
||||
<SbStep Label="Additional Info" Optional="true">
|
||||
Optional step content - can be skipped
|
||||
</SbStep>
|
||||
<SbStep Label="Confirmation">
|
||||
Final step content
|
||||
</SbStep>
|
||||
</SbStepper>
|
||||
```
|
||||
|
||||
### Non-Linear Navigation
|
||||
|
||||
```razor
|
||||
<SbStepper Linear="false" @bind-ActiveIndex="step">
|
||||
<SbStep Label="General">
|
||||
General settings
|
||||
</SbStep>
|
||||
<SbStep Label="Advanced">
|
||||
Advanced settings
|
||||
</SbStep>
|
||||
<SbStep Label="Review">
|
||||
Review settings
|
||||
</SbStep>
|
||||
</SbStepper>
|
||||
```
|
||||
|
||||
### Custom Button Text
|
||||
|
||||
```razor
|
||||
<SbStepper
|
||||
BackText="Previous"
|
||||
NextText="Continue"
|
||||
FinishText="Complete Setup"
|
||||
OptionalText="(Optional)"
|
||||
@bind-ActiveIndex="step">
|
||||
<SbStep Label="Step 1">Content 1</SbStep>
|
||||
<SbStep Label="Step 2" Optional="true">Content 2</SbStep>
|
||||
<SbStep Label="Step 3">Content 3</SbStep>
|
||||
</SbStepper>
|
||||
```
|
||||
|
||||
### Without Built-in Navigation
|
||||
|
||||
```razor
|
||||
<SbStepper ShowNavigation="false" @bind-ActiveIndex="step">
|
||||
<SbStep Label="Step 1">
|
||||
<SbStack Gap="4">
|
||||
<p>Step 1 content</p>
|
||||
<SbButton OnClick="() => step++">Continue</SbButton>
|
||||
</SbStack>
|
||||
</SbStep>
|
||||
<SbStep Label="Step 2">
|
||||
<SbStack Gap="4">
|
||||
<p>Step 2 content</p>
|
||||
<SbStack Direction="SbStackDirection.Row" Gap="2">
|
||||
<SbButton Variant="SbButtonVariant.Outline" OnClick="() => step--">Back</SbButton>
|
||||
<SbButton OnClick="() => step++">Continue</SbButton>
|
||||
</SbStack>
|
||||
</SbStack>
|
||||
</SbStep>
|
||||
</SbStepper>
|
||||
|
||||
@code {
|
||||
private int step = 0;
|
||||
}
|
||||
```
|
||||
|
||||
### Checkout Flow
|
||||
|
||||
```razor
|
||||
<SbStepper @bind-ActiveIndex="checkoutStep" OnFinish="PlaceOrder">
|
||||
<SbStep Label="Cart" Description="Review your items">
|
||||
<Icon><SbIcon Name="shopping-cart" /></Icon>
|
||||
<ChildContent>
|
||||
<SbStack Gap="4">
|
||||
@foreach (var item in cartItems)
|
||||
{
|
||||
<SbCard>
|
||||
<SbStack Direction="SbStackDirection.Row" Justify="SbJustify.SpaceBetween">
|
||||
<span>@item.Name</span>
|
||||
<span>@item.Price.ToString("C")</span>
|
||||
</SbStack>
|
||||
</SbCard>
|
||||
}
|
||||
<SbText Weight="semibold">Total: @cartTotal.ToString("C")</SbText>
|
||||
</SbStack>
|
||||
</ChildContent>
|
||||
</SbStep>
|
||||
<SbStep Label="Shipping" Description="Enter shipping address">
|
||||
<Icon><SbIcon Name="truck" /></Icon>
|
||||
<ChildContent>
|
||||
<SbGrid Columns="2" Gap="4">
|
||||
<SbTextField Label="First Name" @bind-Value="shipping.FirstName" />
|
||||
<SbTextField Label="Last Name" @bind-Value="shipping.LastName" />
|
||||
<SbGridItem Span="2">
|
||||
<SbTextField Label="Address" @bind-Value="shipping.Address" />
|
||||
</SbGridItem>
|
||||
<SbTextField Label="City" @bind-Value="shipping.City" />
|
||||
<SbTextField Label="Zip Code" @bind-Value="shipping.ZipCode" />
|
||||
</SbGrid>
|
||||
</ChildContent>
|
||||
</SbStep>
|
||||
<SbStep Label="Payment" Description="Enter payment details">
|
||||
<Icon><SbIcon Name="credit-card" /></Icon>
|
||||
<ChildContent>
|
||||
<SbStack Gap="4">
|
||||
<SbTextField Label="Card Number" @bind-Value="payment.CardNumber" />
|
||||
<SbGrid Columns="2" Gap="4">
|
||||
<SbTextField Label="Expiry" Placeholder="MM/YY" @bind-Value="payment.Expiry" />
|
||||
<SbTextField Label="CVC" @bind-Value="payment.CVC" />
|
||||
</SbGrid>
|
||||
</SbStack>
|
||||
</ChildContent>
|
||||
</SbStep>
|
||||
<SbStep Label="Confirm" Description="Review your order">
|
||||
<Icon><SbIcon Name="check-circle" /></Icon>
|
||||
<ChildContent>
|
||||
<SbAlert Severity="SbAlertSeverity.Success">
|
||||
Order ready to be placed!
|
||||
</SbAlert>
|
||||
</ChildContent>
|
||||
</SbStep>
|
||||
</SbStepper>
|
||||
```
|
||||
@@ -0,0 +1,164 @@
|
||||
# SbTab
|
||||
|
||||
A single tab panel component used within SbTabs.
|
||||
|
||||
## Parameters
|
||||
|
||||
| Parameter | Type | Default | Description |
|
||||
|-----------|------|---------|-------------|
|
||||
| Id | string? | null | Unique identifier for ID-based tab selection |
|
||||
| Label | string | "" | Tab label text displayed in the tab button |
|
||||
| Disabled | bool | false | Whether the tab is disabled |
|
||||
|
||||
## Templates / Slots
|
||||
|
||||
| Slot | Type | Description |
|
||||
|------|------|-------------|
|
||||
| Icon | RenderFragment | Icon content displayed in the tab button |
|
||||
| Badge | RenderFragment | Badge content displayed in the tab button |
|
||||
| ChildContent | RenderFragment | Tab panel content |
|
||||
|
||||
## Cascading Parameters
|
||||
|
||||
| Parameter | Type | Description |
|
||||
|-----------|------|-------------|
|
||||
| Parent | SbTabs | Parent tabs container |
|
||||
|
||||
## CSS Classes
|
||||
|
||||
- `sb-tab-panel` - Base class for panel
|
||||
- `sb-tab-panel--active` - When panel is active
|
||||
- `sb-tabs__panel` - Tabs panel container class
|
||||
|
||||
## Examples
|
||||
|
||||
### Basic Usage
|
||||
|
||||
```razor
|
||||
<SbTabs>
|
||||
<SbTab Label="First Tab">
|
||||
<p>Content for the first tab</p>
|
||||
</SbTab>
|
||||
<SbTab Label="Second Tab">
|
||||
<p>Content for the second tab</p>
|
||||
</SbTab>
|
||||
</SbTabs>
|
||||
```
|
||||
|
||||
### With ID for Controlled Selection
|
||||
|
||||
```razor
|
||||
<SbTabs @bind-ActiveTab="activeTabId">
|
||||
<SbTab Id="overview" Label="Overview">
|
||||
Overview content
|
||||
</SbTab>
|
||||
<SbTab Id="details" Label="Details">
|
||||
Details content
|
||||
</SbTab>
|
||||
<SbTab Id="history" Label="History">
|
||||
History content
|
||||
</SbTab>
|
||||
</SbTabs>
|
||||
|
||||
@code {
|
||||
private string? activeTabId = "overview";
|
||||
|
||||
private void GoToHistory() => activeTabId = "history";
|
||||
}
|
||||
```
|
||||
|
||||
### With Icon
|
||||
|
||||
```razor
|
||||
<SbTab Label="Settings">
|
||||
<Icon>
|
||||
<SbIcon Name="settings" Size="SbSize.Sm" />
|
||||
</Icon>
|
||||
<ChildContent>
|
||||
<p>Settings content goes here</p>
|
||||
</ChildContent>
|
||||
</SbTab>
|
||||
```
|
||||
|
||||
### With Badge
|
||||
|
||||
```razor
|
||||
<SbTab Label="Messages">
|
||||
<Badge>
|
||||
<SbBadge Value="3" Color="SbColor.Primary" />
|
||||
</Badge>
|
||||
<ChildContent>
|
||||
<p>You have 3 new messages</p>
|
||||
</ChildContent>
|
||||
</SbTab>
|
||||
```
|
||||
|
||||
### Icon and Badge Combined
|
||||
|
||||
```razor
|
||||
<SbTab Label="Notifications">
|
||||
<Icon>
|
||||
<SbIcon Name="bell" Size="SbSize.Sm" />
|
||||
</Icon>
|
||||
<Badge>
|
||||
<SbBadge Value="12" Color="SbColor.Danger" />
|
||||
</Badge>
|
||||
<ChildContent>
|
||||
<ul>
|
||||
@foreach (var notification in notifications)
|
||||
{
|
||||
<li>@notification.Message</li>
|
||||
}
|
||||
</ul>
|
||||
</ChildContent>
|
||||
</SbTab>
|
||||
```
|
||||
|
||||
### Disabled Tab
|
||||
|
||||
```razor
|
||||
<SbTabs>
|
||||
<SbTab Label="Available">
|
||||
This tab is available
|
||||
</SbTab>
|
||||
<SbTab Label="Premium" Disabled="@(!isPremiumUser)">
|
||||
Premium content - upgrade to access
|
||||
</SbTab>
|
||||
</SbTabs>
|
||||
|
||||
@code {
|
||||
private bool isPremiumUser = false;
|
||||
}
|
||||
```
|
||||
|
||||
### Complex Tab Content
|
||||
|
||||
```razor
|
||||
<SbTabs>
|
||||
<SbTab Label="Users">
|
||||
<SbStack Gap="4">
|
||||
<SbStack Direction="SbStackDirection.Row" Justify="SbJustify.SpaceBetween">
|
||||
<SbHeading Level="3">Users List</SbHeading>
|
||||
<SbButton>Add User</SbButton>
|
||||
</SbStack>
|
||||
<SbDataGrid Items="@users">
|
||||
<SbColumn Field="Name" Title="Name" />
|
||||
<SbColumn Field="Email" Title="Email" />
|
||||
<SbColumn Field="Role" Title="Role" />
|
||||
</SbDataGrid>
|
||||
</SbStack>
|
||||
</SbTab>
|
||||
<SbTab Label="Roles">
|
||||
<SbStack Gap="4">
|
||||
<SbHeading Level="3">Role Management</SbHeading>
|
||||
@foreach (var role in roles)
|
||||
{
|
||||
<SbCard>
|
||||
<strong>@role.Name</strong>
|
||||
<p>@role.Description</p>
|
||||
</SbCard>
|
||||
}
|
||||
</SbStack>
|
||||
</SbTab>
|
||||
</SbTabs>
|
||||
```
|
||||
@@ -0,0 +1,194 @@
|
||||
# SbTabs
|
||||
|
||||
A tabbed navigation component for switching between different content panels.
|
||||
|
||||
## Parameters
|
||||
|
||||
| Parameter | Type | Default | Description |
|
||||
|-----------|------|---------|-------------|
|
||||
| ActiveIndex | int | 0 | The active tab index (0-based) |
|
||||
| ActiveTab | string? | null | The active tab ID (string-based selection) |
|
||||
| LazyLoad | bool | false | Whether to lazy-load tab content |
|
||||
| Vertical | bool | false | When true, tabs are vertical (side-by-side with content) |
|
||||
| Class | string? | null | Additional CSS classes |
|
||||
|
||||
## Events
|
||||
|
||||
| Event | Type | Description |
|
||||
|-------|------|-------------|
|
||||
| ActiveIndexChanged | EventCallback\<int\> | Fired when active tab index changes |
|
||||
| ActiveTabChanged | EventCallback\<string?\> | Fired when active tab ID changes |
|
||||
|
||||
## Templates / Slots
|
||||
|
||||
| Slot | Type | Description |
|
||||
|------|------|-------------|
|
||||
| ChildContent | RenderFragment | Tab content (SbTab components) |
|
||||
|
||||
## CSS Classes
|
||||
|
||||
- `sb-tabs` - Base class
|
||||
- `sb-tabs--vertical` - Vertical layout (tabs on side, content adjacent). Applied when `Vertical="true"`.
|
||||
- `sb-tabs__list` - Tab list container
|
||||
- `sb-tabs__tab` - Individual tab button
|
||||
- `sb-tabs__tab--active` - Active tab
|
||||
- `sb-tabs__tab--disabled` - Disabled tab
|
||||
- `sb-tabs__tab-icon` - Tab icon
|
||||
- `sb-tabs__tab-label` - Tab label text
|
||||
- `sb-tabs__tab-badge` - Tab badge
|
||||
- `sb-tabs__content` - Content container
|
||||
|
||||
## Accessibility
|
||||
|
||||
- Uses `role="tablist"` and `role="tab"` for tab buttons
|
||||
- Uses `role="tabpanel"` for content panels
|
||||
- Supports `aria-selected`, `aria-controls`, and `hidden` attributes
|
||||
|
||||
## Examples
|
||||
|
||||
### Basic Usage
|
||||
|
||||
```razor
|
||||
<SbTabs>
|
||||
<SbTab Label="General">
|
||||
<p>General settings content</p>
|
||||
</SbTab>
|
||||
<SbTab Label="Security">
|
||||
<p>Security settings content</p>
|
||||
</SbTab>
|
||||
<SbTab Label="Notifications">
|
||||
<p>Notification settings content</p>
|
||||
</SbTab>
|
||||
</SbTabs>
|
||||
```
|
||||
|
||||
### With Icons
|
||||
|
||||
```razor
|
||||
<SbTabs>
|
||||
<SbTab Label="Home">
|
||||
<Icon><SbIcon Name="home" /></Icon>
|
||||
<ChildContent>Home content</ChildContent>
|
||||
</SbTab>
|
||||
<SbTab Label="Profile">
|
||||
<Icon><SbIcon Name="user" /></Icon>
|
||||
<ChildContent>Profile content</ChildContent>
|
||||
</SbTab>
|
||||
<SbTab Label="Settings">
|
||||
<Icon><SbIcon Name="settings" /></Icon>
|
||||
<ChildContent>Settings content</ChildContent>
|
||||
</SbTab>
|
||||
</SbTabs>
|
||||
```
|
||||
|
||||
### With Badges
|
||||
|
||||
```razor
|
||||
<SbTabs>
|
||||
<SbTab Label="Inbox">
|
||||
<Badge><SbBadge Value="5" /></Badge>
|
||||
<ChildContent>Inbox messages</ChildContent>
|
||||
</SbTab>
|
||||
<SbTab Label="Sent">
|
||||
<ChildContent>Sent messages</ChildContent>
|
||||
</SbTab>
|
||||
<SbTab Label="Drafts">
|
||||
<Badge><SbBadge Value="2" /></Badge>
|
||||
<ChildContent>Draft messages</ChildContent>
|
||||
</SbTab>
|
||||
</SbTabs>
|
||||
```
|
||||
|
||||
### Controlled Tabs (Index-based)
|
||||
|
||||
```razor
|
||||
<SbTabs @bind-ActiveIndex="activeTab">
|
||||
<SbTab Label="Tab 1">Content 1</SbTab>
|
||||
<SbTab Label="Tab 2">Content 2</SbTab>
|
||||
<SbTab Label="Tab 3">Content 3</SbTab>
|
||||
</SbTabs>
|
||||
|
||||
@code {
|
||||
private int activeTab = 0;
|
||||
}
|
||||
```
|
||||
|
||||
### Controlled Tabs (ID-based)
|
||||
|
||||
```razor
|
||||
<SbTabs @bind-ActiveTab="activeTabId">
|
||||
<SbTab Id="general" Label="General">General content</SbTab>
|
||||
<SbTab Id="advanced" Label="Advanced">Advanced content</SbTab>
|
||||
<SbTab Id="about" Label="About">About content</SbTab>
|
||||
</SbTabs>
|
||||
|
||||
@code {
|
||||
private string? activeTabId = "general";
|
||||
}
|
||||
```
|
||||
|
||||
### Vertical Tabs (sidebar layout)
|
||||
|
||||
```razor
|
||||
<SbTabs Vertical="true" @bind-ActiveTab="activeTabId">
|
||||
<SbTab Id="general" Label="General">General settings</SbTab>
|
||||
<SbTab Id="security" Label="Security">Security settings</SbTab>
|
||||
</SbTabs>
|
||||
```
|
||||
|
||||
### With Disabled Tab
|
||||
|
||||
```razor
|
||||
<SbTabs>
|
||||
<SbTab Label="Active">Active tab content</SbTab>
|
||||
<SbTab Label="Another">Another tab content</SbTab>
|
||||
<SbTab Label="Disabled" Disabled="true">
|
||||
This content is inaccessible
|
||||
</SbTab>
|
||||
</SbTabs>
|
||||
```
|
||||
|
||||
### Lazy Loading
|
||||
|
||||
```razor
|
||||
<SbTabs LazyLoad="true">
|
||||
<SbTab Label="Basic">
|
||||
<p>Basic info (loaded immediately)</p>
|
||||
</SbTab>
|
||||
<SbTab Label="Heavy Content">
|
||||
@* This content is only rendered when tab is first activated *@
|
||||
<ExpensiveComponent />
|
||||
</SbTab>
|
||||
</SbTabs>
|
||||
```
|
||||
|
||||
### Settings Page Layout
|
||||
|
||||
```razor
|
||||
<SbCard>
|
||||
<SbTabs>
|
||||
<SbTab Label="Profile">
|
||||
<SbStack Gap="4" Class="p-4">
|
||||
<SbTextField Label="Name" @bind-Value="name" />
|
||||
<SbTextField Label="Email" @bind-Value="email" />
|
||||
<SbButton>Save Profile</SbButton>
|
||||
</SbStack>
|
||||
</SbTab>
|
||||
<SbTab Label="Password">
|
||||
<SbStack Gap="4" Class="p-4">
|
||||
<SbTextField Label="Current Password" Type="password" />
|
||||
<SbTextField Label="New Password" Type="password" />
|
||||
<SbTextField Label="Confirm Password" Type="password" />
|
||||
<SbButton>Update Password</SbButton>
|
||||
</SbStack>
|
||||
</SbTab>
|
||||
<SbTab Label="Preferences">
|
||||
<SbStack Gap="4" Class="p-4">
|
||||
<SbSwitch Label="Dark Mode" @bind-Value="darkMode" />
|
||||
<SbSwitch Label="Email Notifications" @bind-Value="emailNotifications" />
|
||||
<SbButton>Save Preferences</SbButton>
|
||||
</SbStack>
|
||||
</SbTab>
|
||||
</SbTabs>
|
||||
</SbCard>
|
||||
```
|
||||
@@ -0,0 +1,242 @@
|
||||
# SbTreeView
|
||||
|
||||
A hierarchical tree view component for displaying nested data structures.
|
||||
|
||||
## Type Parameters
|
||||
|
||||
| Parameter | Description |
|
||||
|-----------|-------------|
|
||||
| TItem | The type of items in the tree |
|
||||
|
||||
## Parameters
|
||||
|
||||
| Parameter | Type | Default | Description |
|
||||
|-----------|------|---------|-------------|
|
||||
| Items | IEnumerable\<TItem\> | Empty | Root items |
|
||||
| ChildSelector | Func\<TItem, IEnumerable\<TItem\>\> | Returns empty | Function to get child items |
|
||||
| TextSelector | Func\<TItem, string\> | ToString() | Function to get item display text |
|
||||
| IconSelector | Func\<TItem, string?\>? | null | Function to get item icon name |
|
||||
| IsExpandedSelector | Func\<TItem, bool\>? | null | Function to check if item is expanded |
|
||||
| IsSelectedSelector | Func\<TItem, bool\>? | null | Function to check if item is selected |
|
||||
| SelectedItem | TItem? | null | Currently selected item |
|
||||
| ShowCheckboxes | bool | false | Whether to show checkboxes |
|
||||
| CheckedItems | HashSet\<TItem\> | new() | Set of checked items |
|
||||
| Class | string? | null | Additional CSS classes |
|
||||
|
||||
## Events
|
||||
|
||||
| Event | Type | Description |
|
||||
|-------|------|-------------|
|
||||
| SelectedItemChanged | EventCallback\<TItem\> | Fired when item is selected |
|
||||
| OnToggle | EventCallback\<TItem\> | Fired when item is expanded/collapsed |
|
||||
| CheckedItemsChanged | EventCallback\<HashSet\<TItem\>\> | Fired when checked items change |
|
||||
|
||||
## CSS Classes
|
||||
|
||||
- `sb-treeview` - Base class
|
||||
|
||||
## Accessibility
|
||||
|
||||
- Uses `role="tree"` for the container
|
||||
- Uses `role="treeitem"` for items
|
||||
- Uses `role="group"` for child containers
|
||||
- Uses `aria-level` for nesting depth
|
||||
- Uses `aria-expanded` for expandable items
|
||||
|
||||
## Examples
|
||||
|
||||
### Basic Usage
|
||||
|
||||
```razor
|
||||
<SbTreeView TItem="TreeNode"
|
||||
Items="@rootNodes"
|
||||
ChildSelector="@(n => n.Children)"
|
||||
TextSelector="@(n => n.Name)" />
|
||||
|
||||
@code {
|
||||
private List<TreeNode> rootNodes = new()
|
||||
{
|
||||
new TreeNode("Documents", new[]
|
||||
{
|
||||
new TreeNode("Work"),
|
||||
new TreeNode("Personal")
|
||||
}),
|
||||
new TreeNode("Pictures"),
|
||||
new TreeNode("Music")
|
||||
};
|
||||
|
||||
public class TreeNode
|
||||
{
|
||||
public string Name { get; set; }
|
||||
public List<TreeNode> Children { get; set; } = new();
|
||||
|
||||
public TreeNode(string name, IEnumerable<TreeNode>? children = null)
|
||||
{
|
||||
Name = name;
|
||||
Children = children?.ToList() ?? new();
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### With Icons
|
||||
|
||||
```razor
|
||||
<SbTreeView TItem="FileNode"
|
||||
Items="@files"
|
||||
ChildSelector="@(n => n.Children)"
|
||||
TextSelector="@(n => n.Name)"
|
||||
IconSelector="@(n => n.IsFolder ? "folder" : "file")" />
|
||||
|
||||
@code {
|
||||
private List<FileNode> files = new()
|
||||
{
|
||||
new FileNode("src", isFolder: true, children: new[]
|
||||
{
|
||||
new FileNode("components", isFolder: true),
|
||||
new FileNode("App.razor"),
|
||||
new FileNode("Program.cs")
|
||||
}),
|
||||
new FileNode("README.md")
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
### Selectable Tree
|
||||
|
||||
```razor
|
||||
<SbTreeView TItem="Category"
|
||||
Items="@categories"
|
||||
ChildSelector="@(c => c.SubCategories)"
|
||||
TextSelector="@(c => c.Name)"
|
||||
@bind-SelectedItem="selectedCategory" />
|
||||
|
||||
<SbText>Selected: @(selectedCategory?.Name ?? "None")</SbText>
|
||||
|
||||
@code {
|
||||
private Category? selectedCategory;
|
||||
private List<Category> categories = /* ... */;
|
||||
}
|
||||
```
|
||||
|
||||
### With Checkboxes
|
||||
|
||||
```razor
|
||||
<SbTreeView TItem="Permission"
|
||||
Items="@permissions"
|
||||
ChildSelector="@(p => p.Children)"
|
||||
TextSelector="@(p => p.Name)"
|
||||
ShowCheckboxes="true"
|
||||
@bind-CheckedItems="checkedPermissions" />
|
||||
|
||||
<SbButton OnClick="SavePermissions">
|
||||
Save (@checkedPermissions.Count selected)
|
||||
</SbButton>
|
||||
|
||||
@code {
|
||||
private HashSet<Permission> checkedPermissions = new();
|
||||
private List<Permission> permissions = new()
|
||||
{
|
||||
new Permission("Users", new[]
|
||||
{
|
||||
new Permission("View"),
|
||||
new Permission("Create"),
|
||||
new Permission("Edit"),
|
||||
new Permission("Delete")
|
||||
}),
|
||||
new Permission("Reports", new[]
|
||||
{
|
||||
new Permission("View"),
|
||||
new Permission("Export")
|
||||
})
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
### Controlled Expansion
|
||||
|
||||
```razor
|
||||
<SbTreeView TItem="TreeNode"
|
||||
Items="@nodes"
|
||||
ChildSelector="@(n => n.Children)"
|
||||
TextSelector="@(n => n.Name)"
|
||||
IsExpandedSelector="@(n => expandedNodes.Contains(n.Id))"
|
||||
OnToggle="HandleToggle" />
|
||||
|
||||
@code {
|
||||
private HashSet<int> expandedNodes = new() { 1, 2 };
|
||||
|
||||
private void HandleToggle(TreeNode node)
|
||||
{
|
||||
if (expandedNodes.Contains(node.Id))
|
||||
expandedNodes.Remove(node.Id);
|
||||
else
|
||||
expandedNodes.Add(node.Id);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### File Explorer
|
||||
|
||||
```razor
|
||||
<SbTreeView TItem="FileSystemItem"
|
||||
Items="@fileSystem"
|
||||
ChildSelector="@(f => f.Children)"
|
||||
TextSelector="@(f => f.Name)"
|
||||
IconSelector="@GetIcon"
|
||||
@bind-SelectedItem="selectedFile"
|
||||
OnToggle="LoadChildren" />
|
||||
|
||||
@code {
|
||||
private List<FileSystemItem> fileSystem;
|
||||
private FileSystemItem? selectedFile;
|
||||
|
||||
private string? GetIcon(FileSystemItem item) => item.Type switch
|
||||
{
|
||||
FileType.Folder => "folder",
|
||||
FileType.File => GetFileIcon(item.Extension),
|
||||
_ => null
|
||||
};
|
||||
|
||||
private string GetFileIcon(string? ext) => ext switch
|
||||
{
|
||||
".cs" => "file-code",
|
||||
".json" => "file-json",
|
||||
".md" => "file-text",
|
||||
".jpg" or ".png" => "image",
|
||||
_ => "file"
|
||||
};
|
||||
|
||||
private async Task LoadChildren(FileSystemItem folder)
|
||||
{
|
||||
if (folder.Type == FileType.Folder && !folder.ChildrenLoaded)
|
||||
{
|
||||
folder.Children = await LoadFromDisk(folder.Path);
|
||||
folder.ChildrenLoaded = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Organization Hierarchy
|
||||
|
||||
```razor
|
||||
<SbTreeView TItem="Employee"
|
||||
Items="@executives"
|
||||
ChildSelector="@(e => e.DirectReports)"
|
||||
TextSelector="@(e => $"{e.Name} - {e.Title}")"
|
||||
IconSelector="@(_ => "user")"
|
||||
@bind-SelectedItem="selectedEmployee" />
|
||||
|
||||
@if (selectedEmployee != null)
|
||||
{
|
||||
<SbCard Class="mt-4">
|
||||
<SbStack Gap="2">
|
||||
<SbHeading Level="3">@selectedEmployee.Name</SbHeading>
|
||||
<SbText Color="muted">@selectedEmployee.Title</SbText>
|
||||
<SbText>@selectedEmployee.Email</SbText>
|
||||
<SbText>Direct Reports: @selectedEmployee.DirectReports.Count</SbText>
|
||||
</SbStack>
|
||||
</SbCard>
|
||||
}
|
||||
```
|
||||
@@ -0,0 +1,146 @@
|
||||
# SbTreeViewNode
|
||||
|
||||
An individual node component used internally by SbTreeView to render tree items recursively.
|
||||
|
||||
## Type Parameters
|
||||
|
||||
| Parameter | Description |
|
||||
|-----------|-------------|
|
||||
| TItem | The type of item in the tree |
|
||||
|
||||
## Parameters
|
||||
|
||||
| Parameter | Type | Default | Description |
|
||||
|-----------|------|---------|-------------|
|
||||
| Item | TItem | required | The item to display |
|
||||
| Level | int | 0 | Nesting level (0 for root) |
|
||||
| ChildSelector | Func\<TItem, IEnumerable\<TItem\>\> | Returns empty | Function to get child items |
|
||||
| TextSelector | Func\<TItem, string\> | ToString() | Function to get item display text |
|
||||
| IconSelector | Func\<TItem, string?\>? | null | Function to get item icon name |
|
||||
| IsExpandedSelector | Func\<TItem, bool\>? | null | Function to check expansion state |
|
||||
| IsSelectedSelector | Func\<TItem, bool\>? | null | Function to check selection state |
|
||||
|
||||
## Cascading Parameters
|
||||
|
||||
| Parameter | Type | Description |
|
||||
|-----------|------|-------------|
|
||||
| Parent | SbTreeView\<TItem\> | Parent tree view component |
|
||||
|
||||
## CSS Classes
|
||||
|
||||
- `sb-treeview-node` - Base class
|
||||
- `sb-treeview-node--expanded` - When node is expanded
|
||||
- `sb-treeview-node__content` - Content container
|
||||
- `sb-treeview-node__content--selected` - When node is selected
|
||||
- `sb-treeview-node__toggle` - Expand/collapse button
|
||||
- `sb-treeview-node__spacer` - Spacer for leaf nodes
|
||||
- `sb-treeview-node__checkbox` - Checkbox element
|
||||
- `sb-treeview-node__icon` - Icon container
|
||||
- `sb-treeview-node__text` - Text content
|
||||
- `sb-treeview-node__chevron` - Expand indicator chevron
|
||||
- `sb-treeview-node__children` - Children container
|
||||
|
||||
## Notes
|
||||
|
||||
This component is typically not used directly. It's automatically created by SbTreeView for each item in the tree. However, understanding its structure helps with custom styling.
|
||||
|
||||
## Internal Behavior
|
||||
|
||||
- Indentation is calculated based on `Level * 20 + 8` pixels
|
||||
- Toggle button only appears for nodes with children
|
||||
- Checkbox state is managed by the parent SbTreeView
|
||||
- Selection click triggers parent's `SelectItem` method
|
||||
- Toggle click triggers parent's `ToggleItem` method
|
||||
|
||||
## Styling Examples
|
||||
|
||||
### Custom Node Styling
|
||||
|
||||
```css
|
||||
/* Highlight selected nodes */
|
||||
.sb-treeview-node__content--selected {
|
||||
background-color: var(--sb-color-primary-light);
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
/* Custom hover effect */
|
||||
.sb-treeview-node__content:hover {
|
||||
background-color: var(--sb-color-surface-hover);
|
||||
}
|
||||
|
||||
/* Increase indentation */
|
||||
.sb-treeview-node__content {
|
||||
padding-left: calc(var(--level) * 24px + 12px);
|
||||
}
|
||||
|
||||
/* Style the expand icon */
|
||||
.sb-treeview-node__chevron {
|
||||
transition: transform 0.2s ease;
|
||||
}
|
||||
|
||||
.sb-treeview-node--expanded .sb-treeview-node__chevron {
|
||||
transform: rotate(90deg);
|
||||
}
|
||||
|
||||
/* Style icons by type */
|
||||
.sb-treeview-node[data-type="folder"] .sb-treeview-node__icon {
|
||||
color: var(--sb-color-warning);
|
||||
}
|
||||
|
||||
.sb-treeview-node[data-type="file"] .sb-treeview-node__icon {
|
||||
color: var(--sb-color-muted);
|
||||
}
|
||||
```
|
||||
|
||||
### Animation for Expand/Collapse
|
||||
|
||||
```css
|
||||
.sb-treeview-node__children {
|
||||
overflow: hidden;
|
||||
animation: expandChildren 0.2s ease-out;
|
||||
}
|
||||
|
||||
@keyframes expandChildren {
|
||||
from {
|
||||
opacity: 0;
|
||||
max-height: 0;
|
||||
}
|
||||
to {
|
||||
opacity: 1;
|
||||
max-height: 1000px;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Usage Context
|
||||
|
||||
Since SbTreeViewNode is used internally, here's how it fits into the tree rendering:
|
||||
|
||||
```razor
|
||||
@* This is how SbTreeView uses SbTreeViewNode internally *@
|
||||
<div class="sb-treeview">
|
||||
@foreach (var item in Items)
|
||||
{
|
||||
<SbTreeViewNode TItem="TItem"
|
||||
Item="item"
|
||||
Level="0"
|
||||
ChildSelector="ChildSelector"
|
||||
TextSelector="TextSelector"
|
||||
IconSelector="IconSelector"
|
||||
IsExpandedSelector="IsExpandedSelector"
|
||||
IsSelectedSelector="IsSelectedSelector" />
|
||||
}
|
||||
</div>
|
||||
|
||||
@* SbTreeViewNode then recursively renders children *@
|
||||
<div class="sb-treeview-node">
|
||||
<div class="sb-treeview-node__content">
|
||||
<button class="sb-treeview-node__toggle">▶</button>
|
||||
<span class="sb-treeview-node__icon">📁</span>
|
||||
<span class="sb-treeview-node__text">Item Name</span>
|
||||
</div>
|
||||
<div class="sb-treeview-node__children">
|
||||
@* Recursive SbTreeViewNode for each child *@
|
||||
</div>
|
||||
</div>
|
||||
```
|
||||
Reference in New Issue
Block a user