mirror of
https://github.com/github/awesome-copilot.git
synced 2026-08-24 09:56:51 +00:00
chore: publish from main
This commit is contained in:
@@ -697,6 +697,12 @@
|
||||
"description": "Give your AI agent full visibility into Power Automate cloud flows via the FlowStudio MCP server. Connect, debug, build, monitor health, and govern flows at scale — action-level inputs and outputs, not just status codes.",
|
||||
"version": "2.0.0"
|
||||
},
|
||||
{
|
||||
"name": "fluentui-blazor",
|
||||
"source": "plugins/fluentui-blazor",
|
||||
"description": "Build Blazor apps with the Microsoft Fluent UI Blazor library. Bundles the fluentui-blazor skill for correct usage patterns (providers, service registration, icons, dialogs, data grid, theming) with the official Fluent UI Blazor MCP server for live lookup of components, parameters, enums, icons, and documentation, plus v4-to-v5 migration guidance.",
|
||||
"version": "1.0.0"
|
||||
},
|
||||
{
|
||||
"name": "foundation-models",
|
||||
"description": "Helps coding agents write and review Apple Foundation Models code for iOS, macOS, visionOS, and watchOS using the SDK installed on the developer's Mac. It verifies real API signatures and availability, then type-checks the result instead of relying on model memory.",
|
||||
|
||||
@@ -63,6 +63,7 @@ See [CONTRIBUTING.md](../CONTRIBUTING.md#adding-plugins) for guidelines on how t
|
||||
| [feedback-themes](../plugins/feedback-themes/README.md) | Explore grouped customer feedback signals by impact and drill into a theme to guide product next steps. | 1 items | customer-feedback, impact-prioritization, product-insights, signal-grouping, theme-analysis, trend-discovery |
|
||||
| [flight-map-canvas](../plugins/flight-map-canvas/README.md) | A GitHub Copilot canvas that generates a view where Google Maps can be explored using 3D controls, as if a flight simulator. Agents can send the flight anywhere and report what they are working on. | 1 items | copilot-canvas, flight-simulator, geography, google-maps, interactive-canvas, session-breaks, threejs |
|
||||
| [flowstudio-power-automate](../plugins/flowstudio-power-automate/README.md) | Give your AI agent full visibility into Power Automate cloud flows via the FlowStudio MCP server. Connect, debug, build, monitor health, and govern flows at scale — action-level inputs and outputs, not just status codes. | 0 items | power-automate, power-platform, flowstudio, mcp, model-context-protocol, cloud-flows, workflow-automation, monitoring, governance |
|
||||
| [fluentui-blazor](../plugins/fluentui-blazor/README.md) | Build Blazor apps with the Microsoft Fluent UI Blazor library. Bundles the fluentui-blazor skill for correct usage patterns (providers, service registration, icons, dialogs, data grid, theming) with the official Fluent UI Blazor MCP server for live lookup of components, parameters, enums, icons, and documentation, plus v4-to-v5 migration guidance. | 0 items | fluentui, blazor, dotnet, components, aspnetcore, mcp, model-context-protocol, migration, icons, theming |
|
||||
| [frontend-web-dev](../plugins/frontend-web-dev/README.md) | Essential prompts, instructions, and chat modes for modern frontend web development including React, Angular, Vue, TypeScript, and CSS frameworks. | 0 items | frontend, web, react, typescript, javascript, css, html, angular, vue |
|
||||
| [gem-team](../plugins/gem-team/README.md) | Self-Learning Multi-agent orchestration framework for spec-driven development and automated verification. With smarter tool calling and leaner context. | 0 items | multi-agent, orchestration, tdd, testing, e2e, devops, security-audit, code-review, prd, mobile |
|
||||
| [gesture-review](../plugins/gesture-review/README.md) | Review pull requests with a live camera feed and approve or reject using thumbs-up/thumbs-down gestures. | 1 items | camera-input, gesture-control, github-prs, hands-free, mediapipe, pull-request-review |
|
||||
|
||||
@@ -0,0 +1,71 @@
|
||||
# Fluent UI Blazor Plugin
|
||||
|
||||
Everything you need to build Blazor applications with the [Microsoft Fluent UI Blazor](https://www.fluentui-blazor.net) component library, in one install: the `fluentui-blazor` skill for correct usage patterns, and the official Fluent UI Blazor MCP server for live, version-accurate lookup of components, enums, icons, and documentation.
|
||||
|
||||
## Installation
|
||||
|
||||
```bash
|
||||
copilot plugin install fluentui-blazor@awesome-copilot
|
||||
```
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- The [.NET 10 SDK](https://dotnet.microsoft.com/download) or later must be installed and `dnx` available on your `PATH`.
|
||||
- The plugin starts its bundled MCP server by running `dnx Microsoft.FluentUI.AspNetCore.McpServer`. The first launch downloads the package from nuget.org.
|
||||
- The MCP server and the component library are published with the same version number, and the server documents the version it was built against. If your project references a different version, ask the agent to run `check_project_version` — mismatched versions produce documentation that does not match your code.
|
||||
|
||||
## What's Included
|
||||
|
||||
### Skills
|
||||
|
||||
| Skill | Description |
|
||||
|-------|-------------|
|
||||
| `fluentui-blazor` | Guide for using the `Microsoft.FluentUI.AspNetCore.Components` package: mandatory providers, service registration and lifetimes, strongly-typed icons, the `Items`/`OptionText`/`OptionValue` list binding model, the `IDialogService` pattern, toasts, design tokens and theming, and form components. Includes reference files on setup, layout and navigation, data grid, and theming. |
|
||||
|
||||
### MCP server
|
||||
|
||||
This plugin includes the `fluent-ui-blazor` MCP server configured in [`./mcp.json`](./mcp.json), published on NuGet as [`Microsoft.FluentUI.AspNetCore.McpServer`](https://www.nuget.org/packages/Microsoft.FluentUI.AspNetCore.McpServer). If the .NET SDK is unavailable, MCP startup will fail.
|
||||
|
||||
It gives the agent authoritative, version-aware answers instead of guesses:
|
||||
|
||||
| Capability | Tools |
|
||||
|------------|-------|
|
||||
| Components | `list_components`, `search_components`, `get_component_details`, `list_categories` |
|
||||
| Enums | `list_enums`, `get_enum_values`, `get_component_enums` |
|
||||
| Icons | `search_icons`, `list_all_icon_names`, `get_icon_details`, `get_icon_usage` |
|
||||
| Documentation | `list_documentation`, `search_documentation`, `get_documentation_topic` |
|
||||
| Versions | `get_version_info`, `check_project_version` |
|
||||
| v4 → v5 migration | `get_migration_overview`, `get_migration_guide`, `list_component_migrations`, `get_component_migration` |
|
||||
|
||||
### Why the skill and the MCP server together
|
||||
|
||||
They cover different failure modes, and each is weaker alone:
|
||||
|
||||
- The **skill** encodes the patterns that models get wrong from training data — the provider components that fail silently when missing, `ServiceLifetime.Transient` throwing, `FluentSelect` not behaving like `InputSelect`, design tokens needing `OnAfterRenderAsync`. This is judgement, not lookup.
|
||||
- The **MCP server** supplies the facts that go stale — exact parameter names, enum values, the 142+ component surface, and the icon catalog — looked up in documentation generated at package build time rather than recalled from training data. It serves the library version it was built against, which is why matching versions matters (see Prerequisites).
|
||||
|
||||
Installing them as one plugin means a single `copilot plugin install` gets a working Fluent UI Blazor setup, instead of a skill that names components the agent then has to invent parameters for.
|
||||
|
||||
## Example prompts
|
||||
|
||||
```text
|
||||
Add a FluentDataGrid of orders with sorting and pagination to my Blazor app.
|
||||
```
|
||||
|
||||
```text
|
||||
Which Fluent icon should I use for a "save draft" button, and how do I reference it?
|
||||
```
|
||||
|
||||
```text
|
||||
Check what my project is on today, then walk me through migrating this page from Fluent UI Blazor v4 to v5.
|
||||
```
|
||||
|
||||
## Source
|
||||
|
||||
This plugin is part of [Awesome Copilot](https://github.com/github/awesome-copilot), a community-driven collection of GitHub Copilot extensions.
|
||||
|
||||
The bundled MCP server is maintained in [microsoft/fluentui-blazor](https://github.com/microsoft/fluentui-blazor).
|
||||
|
||||
## License
|
||||
|
||||
MIT
|
||||
@@ -0,0 +1,13 @@
|
||||
{
|
||||
"$schema": "https://agent-plugins.org/schemas/1.0.0/mcp.schema.json",
|
||||
"mcpServers": {
|
||||
"fluent-ui-blazor": {
|
||||
"type": "stdio",
|
||||
"command": "dnx",
|
||||
"args": [
|
||||
"Microsoft.FluentUI.AspNetCore.McpServer@5.0.0-rc.5-26219.1",
|
||||
"--yes"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
{
|
||||
"$schema": "https://agent-plugins.org/schemas/1.0.0/plugin.schema.json",
|
||||
"name": "fluentui-blazor",
|
||||
"description": "Build Blazor apps with the Microsoft Fluent UI Blazor library. Bundles the fluentui-blazor skill for correct usage patterns (providers, service registration, icons, dialogs, data grid, theming) with the official Fluent UI Blazor MCP server for live lookup of components, parameters, enums, icons, and documentation, plus v4-to-v5 migration guidance.",
|
||||
"version": "1.0.0",
|
||||
"keywords": [
|
||||
"fluentui",
|
||||
"blazor",
|
||||
"dotnet",
|
||||
"components",
|
||||
"aspnetcore",
|
||||
"mcp",
|
||||
"model-context-protocol",
|
||||
"migration",
|
||||
"icons",
|
||||
"theming"
|
||||
],
|
||||
"author": {
|
||||
"name": "Adrien Clerbois",
|
||||
"url": "https://github.com/AClerbois"
|
||||
},
|
||||
"homepage": "https://www.fluentui-blazor.net",
|
||||
"repository": "https://github.com/github/awesome-copilot",
|
||||
"license": "MIT"
|
||||
}
|
||||
@@ -0,0 +1,231 @@
|
||||
---
|
||||
name: fluentui-blazor
|
||||
description: >
|
||||
Guide for using the Microsoft Fluent UI Blazor component library
|
||||
(Microsoft.FluentUI.AspNetCore.Components NuGet package) in Blazor applications.
|
||||
Use this when the user is building a Blazor app with Fluent UI components,
|
||||
setting up the library, using FluentUI components like FluentButton, FluentDataGrid,
|
||||
FluentDialog, FluentToast, FluentNavMenu, FluentTextField, FluentSelect,
|
||||
FluentAutocomplete, FluentDesignTheme, or any component prefixed with "Fluent".
|
||||
Also use when troubleshooting missing providers, JS interop issues, or theming.
|
||||
---
|
||||
|
||||
# Fluent UI Blazor — Consumer Usage Guide
|
||||
|
||||
This skill teaches how to correctly use the **Microsoft.FluentUI.AspNetCore.Components** (version 4) NuGet package in Blazor applications.
|
||||
|
||||
## Critical Rules
|
||||
|
||||
### 1. No manual `<script>` or `<link>` tags needed
|
||||
|
||||
The library auto-loads all CSS and JS via Blazor's static web assets and JS initializers. **Never tell users to add `<script>` or `<link>` tags for the core library.**
|
||||
|
||||
### 2. Providers are mandatory for service-based components
|
||||
|
||||
These provider components **MUST** be added to the root layout (e.g. `MainLayout.razor`) for their corresponding services to work. Without them, service calls **fail silently** (no error, no UI).
|
||||
|
||||
```razor
|
||||
<FluentToastProvider />
|
||||
<FluentDialogProvider />
|
||||
<FluentMessageBarProvider />
|
||||
<FluentTooltipProvider />
|
||||
<FluentKeyCodeProvider />
|
||||
```
|
||||
|
||||
### 3. Service registration in Program.cs
|
||||
|
||||
```csharp
|
||||
builder.Services.AddFluentUIComponents();
|
||||
|
||||
// Or with configuration:
|
||||
builder.Services.AddFluentUIComponents(options =>
|
||||
{
|
||||
options.UseTooltipServiceProvider = true; // default: true
|
||||
options.ServiceLifetime = ServiceLifetime.Scoped; // default
|
||||
});
|
||||
```
|
||||
|
||||
**ServiceLifetime rules:**
|
||||
- `ServiceLifetime.Scoped` — for Blazor Server / Interactive (default)
|
||||
- `ServiceLifetime.Singleton` — for Blazor WebAssembly standalone
|
||||
- `ServiceLifetime.Transient` — **throws `NotSupportedException`**
|
||||
|
||||
### 4. Icons require a separate NuGet package
|
||||
|
||||
```
|
||||
dotnet add package Microsoft.FluentUI.AspNetCore.Components.Icons
|
||||
```
|
||||
|
||||
Usage with a `@using` alias:
|
||||
|
||||
```razor
|
||||
@using Icons = Microsoft.FluentUI.AspNetCore.Components.Icons
|
||||
|
||||
<FluentIcon Value="@(Icons.Regular.Size24.Save)" />
|
||||
<FluentIcon Value="@(Icons.Filled.Size20.Delete)" Color="@Color.Error" />
|
||||
```
|
||||
|
||||
Pattern: `Icons.[Variant].[Size].[Name]`
|
||||
- Variants: `Regular`, `Filled`
|
||||
- Sizes: `Size12`, `Size16`, `Size20`, `Size24`, `Size28`, `Size32`, `Size48`
|
||||
|
||||
Custom image: `Icon.FromImageUrl("/path/to/image.png")`
|
||||
|
||||
**Never use string-based icon names** — icons are strongly-typed classes.
|
||||
|
||||
### 5. List component binding model
|
||||
|
||||
`FluentSelect<TOption>`, `FluentCombobox<TOption>`, `FluentListbox<TOption>`, and `FluentAutocomplete<TOption>` do NOT work like `<InputSelect>`. They use:
|
||||
|
||||
- `Items` — the data source (`IEnumerable<TOption>`)
|
||||
- `OptionText` — `Func<TOption, string?>` to extract display text
|
||||
- `OptionValue` — `Func<TOption, string?>` to extract the value string
|
||||
- `SelectedOption` / `SelectedOptionChanged` — for single selection binding
|
||||
- `SelectedOptions` / `SelectedOptionsChanged` — for multi-selection binding
|
||||
|
||||
```razor
|
||||
<FluentSelect Items="@countries"
|
||||
OptionText="@(c => c.Name)"
|
||||
OptionValue="@(c => c.Code)"
|
||||
@bind-SelectedOption="@selectedCountry"
|
||||
Label="Country" />
|
||||
```
|
||||
|
||||
**NOT** like this (wrong pattern):
|
||||
```razor
|
||||
@* WRONG — do not use InputSelect pattern *@
|
||||
<FluentSelect @bind-Value="@selectedValue">
|
||||
<option value="1">One</option>
|
||||
</FluentSelect>
|
||||
```
|
||||
|
||||
### 6. FluentAutocomplete specifics
|
||||
|
||||
- Use `ValueText` (NOT `Value` — it's obsolete) for the search input text
|
||||
- `OnOptionsSearch` is the required callback to filter options
|
||||
- Default is `Multiple="true"`
|
||||
|
||||
```razor
|
||||
<FluentAutocomplete TOption="Person"
|
||||
OnOptionsSearch="@OnSearch"
|
||||
OptionText="@(p => p.FullName)"
|
||||
@bind-SelectedOptions="@selectedPeople"
|
||||
Label="Search people" />
|
||||
|
||||
@code {
|
||||
private void OnSearch(OptionsSearchEventArgs<Person> args)
|
||||
{
|
||||
args.Items = allPeople.Where(p =>
|
||||
p.FullName.Contains(args.Text, StringComparison.OrdinalIgnoreCase));
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 7. Dialog service pattern
|
||||
|
||||
**Do NOT toggle visibility of `<FluentDialog>` tags.** The service pattern is:
|
||||
|
||||
1. Create a content component implementing `IDialogContentComponent<TData>`:
|
||||
|
||||
```csharp
|
||||
public partial class EditPersonDialog : IDialogContentComponent<Person>
|
||||
{
|
||||
[Parameter] public Person Content { get; set; } = default!;
|
||||
|
||||
[CascadingParameter] public FluentDialog Dialog { get; set; } = default!;
|
||||
|
||||
private async Task SaveAsync()
|
||||
{
|
||||
await Dialog.CloseAsync(Content);
|
||||
}
|
||||
|
||||
private async Task CancelAsync()
|
||||
{
|
||||
await Dialog.CancelAsync();
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
2. Show the dialog via `IDialogService`:
|
||||
|
||||
```csharp
|
||||
[Inject] private IDialogService DialogService { get; set; } = default!;
|
||||
|
||||
private async Task ShowEditDialog()
|
||||
{
|
||||
var dialog = await DialogService.ShowDialogAsync<EditPersonDialog, Person>(
|
||||
person,
|
||||
new DialogParameters
|
||||
{
|
||||
Title = "Edit Person",
|
||||
PrimaryAction = "Save",
|
||||
SecondaryAction = "Cancel",
|
||||
Width = "500px",
|
||||
PreventDismissOnOverlayClick = true,
|
||||
});
|
||||
|
||||
var result = await dialog.Result;
|
||||
if (!result.Cancelled)
|
||||
{
|
||||
var updatedPerson = result.Data as Person;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
For convenience dialogs:
|
||||
```csharp
|
||||
await DialogService.ShowConfirmationAsync("Are you sure?", "Yes", "No");
|
||||
await DialogService.ShowSuccessAsync("Done!");
|
||||
await DialogService.ShowErrorAsync("Something went wrong.");
|
||||
```
|
||||
|
||||
### 8. Toast notifications
|
||||
|
||||
```csharp
|
||||
[Inject] private IToastService ToastService { get; set; } = default!;
|
||||
|
||||
ToastService.ShowSuccess("Item saved successfully");
|
||||
ToastService.ShowError("Failed to save");
|
||||
ToastService.ShowWarning("Check your input");
|
||||
ToastService.ShowInfo("New update available");
|
||||
```
|
||||
|
||||
`FluentToastProvider` parameters: `Position` (default `TopRight`), `Timeout` (default 7000ms), `MaxToastCount` (default 4).
|
||||
|
||||
### 9. Design tokens and themes work only after render
|
||||
|
||||
Design tokens rely on JS interop. **Never set them in `OnInitialized`** — use `OnAfterRenderAsync`.
|
||||
|
||||
```razor
|
||||
<FluentDesignTheme Mode="DesignThemeModes.System"
|
||||
OfficeColor="OfficeColor.Teams"
|
||||
StorageName="mytheme" />
|
||||
```
|
||||
|
||||
### 10. FluentEditForm vs EditForm
|
||||
|
||||
`FluentEditForm` is only needed inside `FluentWizard` steps (per-step validation). For regular forms, use standard `EditForm` with Fluent form components:
|
||||
|
||||
```razor
|
||||
<EditForm Model="@model" OnValidSubmit="HandleSubmit">
|
||||
<DataAnnotationsValidator />
|
||||
<FluentTextField @bind-Value="@model.Name" Label="Name" Required />
|
||||
<FluentSelect Items="@options"
|
||||
OptionText="@(o => o.Label)"
|
||||
@bind-SelectedOption="@model.Category"
|
||||
Label="Category" />
|
||||
<FluentValidationSummary />
|
||||
<FluentButton Type="ButtonType.Submit" Appearance="Appearance.Accent">Save</FluentButton>
|
||||
</EditForm>
|
||||
```
|
||||
|
||||
Use `FluentValidationMessage` and `FluentValidationSummary` instead of standard Blazor validation components for Fluent styling.
|
||||
|
||||
## Reference files
|
||||
|
||||
For detailed guidance on specific topics, see:
|
||||
|
||||
- [Setup and configuration](references/SETUP.md)
|
||||
- [Layout and navigation](references/LAYOUT-AND-NAVIGATION.md)
|
||||
- [Data grid](references/DATAGRID.md)
|
||||
- [Theming](references/THEMING.md)
|
||||
@@ -0,0 +1,162 @@
|
||||
# FluentDataGrid
|
||||
|
||||
`FluentDataGrid<TGridItem>` is a strongly-typed generic component for displaying tabular data.
|
||||
|
||||
## Basic Usage
|
||||
|
||||
```razor
|
||||
<FluentDataGrid Items="@people" TGridItem="Person">
|
||||
<PropertyColumn Property="@(p => p.Name)" Sortable="true" />
|
||||
<PropertyColumn Property="@(p => p.Email)" />
|
||||
<PropertyColumn Property="@(p => p.BirthDate)" Format="yyyy-MM-dd" />
|
||||
<TemplateColumn Title="Actions">
|
||||
<FluentButton OnClick="@(() => Edit(context))">Edit</FluentButton>
|
||||
</TemplateColumn>
|
||||
</FluentDataGrid>
|
||||
```
|
||||
|
||||
**Critical**: Columns are child components, NOT properties. Use `PropertyColumn`, `TemplateColumn`, and `SelectColumn` within the grid.
|
||||
|
||||
## Column Types
|
||||
|
||||
### PropertyColumn
|
||||
|
||||
Binds to a property expression. Auto-derives title from property name or `[Display]` attribute.
|
||||
|
||||
```razor
|
||||
<PropertyColumn Property="@(p => p.Name)" Sortable="true" />
|
||||
<PropertyColumn Property="@(p => p.Price)" Format="C2" Title="Unit Price" />
|
||||
<PropertyColumn Property="@(p => p.Category)" Comparer="@StringComparer.OrdinalIgnoreCase" />
|
||||
```
|
||||
|
||||
Parameters: `Property` (required), `Format`, `Title`, `Sortable`, `SortBy`, `Comparer`, `IsDefaultSortColumn`, `InitialSortDirection`, `Class`, `Tooltip`.
|
||||
|
||||
### TemplateColumn
|
||||
|
||||
Full custom rendering via render fragment. `context` is the `TGridItem`.
|
||||
|
||||
```razor
|
||||
<TemplateColumn Title="Status" SortBy="@statusSort">
|
||||
<FluentBadge Appearance="Appearance.Accent"
|
||||
BackgroundColor="@(context.IsActive ? "green" : "red")">
|
||||
@(context.IsActive ? "Active" : "Inactive")
|
||||
</FluentBadge>
|
||||
</TemplateColumn>
|
||||
```
|
||||
|
||||
### SelectColumn
|
||||
|
||||
Checkbox selection column.
|
||||
|
||||
```razor
|
||||
<SelectColumn TGridItem="Person"
|
||||
SelectMode="DataGridSelectMode.Multiple"
|
||||
@bind-SelectedItems="@selectedPeople" />
|
||||
```
|
||||
|
||||
Modes: `DataGridSelectMode.Single`, `DataGridSelectMode.Multiple`.
|
||||
|
||||
## Data Sources
|
||||
|
||||
Two mutually exclusive approaches:
|
||||
|
||||
### In-memory (IQueryable)
|
||||
|
||||
```razor
|
||||
<FluentDataGrid Items="@people.AsQueryable()" TGridItem="Person">
|
||||
...
|
||||
</FluentDataGrid>
|
||||
```
|
||||
|
||||
### Server-side / Custom (ItemsProvider)
|
||||
|
||||
```razor
|
||||
<FluentDataGrid ItemsProvider="@peopleProvider" TGridItem="Person">
|
||||
...
|
||||
</FluentDataGrid>
|
||||
|
||||
@code {
|
||||
private GridItemsProvider<Person> peopleProvider = async request =>
|
||||
{
|
||||
var result = await PeopleService.GetPeopleAsync(
|
||||
request.StartIndex,
|
||||
request.Count ?? 50,
|
||||
request.GetSortByProperties().FirstOrDefault());
|
||||
|
||||
return GridItemsProviderResult.From(result.Items, result.TotalCount);
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
### EF Core Adapter
|
||||
|
||||
```csharp
|
||||
// Program.cs
|
||||
builder.Services.AddDataGridEntityFrameworkAdapter();
|
||||
```
|
||||
|
||||
```razor
|
||||
<FluentDataGrid Items="@dbContext.People" TGridItem="Person">
|
||||
...
|
||||
</FluentDataGrid>
|
||||
```
|
||||
|
||||
## Pagination
|
||||
|
||||
```razor
|
||||
<FluentDataGrid Items="@people" Pagination="@pagination" TGridItem="Person">
|
||||
...
|
||||
</FluentDataGrid>
|
||||
|
||||
<FluentPaginator State="@pagination" />
|
||||
|
||||
@code {
|
||||
private PaginationState pagination = new() { ItemsPerPage = 10 };
|
||||
}
|
||||
```
|
||||
|
||||
## Virtualization
|
||||
|
||||
For large datasets, enable virtualization:
|
||||
|
||||
```razor
|
||||
<FluentDataGrid Items="@people" Virtualize="true" ItemSize="46" TGridItem="Person">
|
||||
...
|
||||
</FluentDataGrid>
|
||||
```
|
||||
|
||||
`ItemSize` is the estimated row height in pixels (default varies). Important for scroll position calculations.
|
||||
|
||||
## Key Parameters
|
||||
|
||||
| Parameter | Type | Description |
|
||||
|---|---|---|
|
||||
| `Items` | `IQueryable<TGridItem>?` | In-memory data source |
|
||||
| `ItemsProvider` | `GridItemsProvider<TGridItem>?` | Async data provider |
|
||||
| `Pagination` | `PaginationState?` | Pagination state |
|
||||
| `Virtualize` | `bool` | Enable virtualization |
|
||||
| `ItemSize` | `float` | Estimated row height (px) |
|
||||
| `ItemKey` | `Func<TGridItem, object>?` | Stable key for `@key` |
|
||||
| `ResizableColumns` | `bool` | Enable column resize |
|
||||
| `HeaderCellAsButtonWithMenu` | `bool` | Sortable header UI |
|
||||
| `GridTemplateColumns` | `string?` | CSS grid-template-columns |
|
||||
| `Loading` | `bool` | Show loading indicator |
|
||||
| `ShowHover` | `bool` | Highlight rows on hover |
|
||||
| `OnRowClick` | `EventCallback<FluentDataGridRow<TGridItem>>` | Row click handler |
|
||||
| `OnRowDoubleClick` | `EventCallback<FluentDataGridRow<TGridItem>>` | Row double-click handler |
|
||||
| `OnRowFocus` | `EventCallback<FluentDataGridRow<TGridItem>>` | Row focus handler |
|
||||
|
||||
## Sorting
|
||||
|
||||
```razor
|
||||
<PropertyColumn Property="@(p => p.Name)" Sortable="true" IsDefaultSortColumn="true"
|
||||
InitialSortDirection="SortDirection.Ascending" />
|
||||
```
|
||||
|
||||
Or with a custom sort:
|
||||
|
||||
```razor
|
||||
<TemplateColumn Title="Full Name" SortBy="@(GridSort<Person>.ByAscending(p => p.LastName).ThenAscending(p => p.FirstName))">
|
||||
@context.LastName, @context.FirstName
|
||||
</TemplateColumn>
|
||||
```
|
||||
@@ -0,0 +1,173 @@
|
||||
# Layout and Navigation
|
||||
|
||||
## Layout Components
|
||||
|
||||
### FluentLayout
|
||||
|
||||
Root layout container. Use as the outermost structural component.
|
||||
|
||||
```razor
|
||||
<FluentLayout Orientation="Orientation.Vertical">
|
||||
<FluentHeader>...</FluentHeader>
|
||||
<FluentBodyContent>...</FluentBodyContent>
|
||||
<FluentFooter>...</FluentFooter>
|
||||
</FluentLayout>
|
||||
```
|
||||
|
||||
### FluentHeader / FluentFooter
|
||||
|
||||
Sticky header and footer sections within `FluentLayout`.
|
||||
|
||||
```razor
|
||||
<FluentHeader Height="50">
|
||||
<FluentStack Orientation="Orientation.Horizontal" HorizontalAlignment="HorizontalAlignment.SpaceBetween">
|
||||
<span>App Title</span>
|
||||
<FluentButton>Settings</FluentButton>
|
||||
</FluentStack>
|
||||
</FluentHeader>
|
||||
```
|
||||
|
||||
### FluentBodyContent
|
||||
|
||||
Main scrollable content area within `FluentLayout`.
|
||||
|
||||
### FluentStack
|
||||
|
||||
Flexbox container for horizontal or vertical layouts.
|
||||
|
||||
```razor
|
||||
<FluentStack Orientation="Orientation.Horizontal"
|
||||
HorizontalGap="10"
|
||||
VerticalGap="10"
|
||||
HorizontalAlignment="HorizontalAlignment.Center"
|
||||
VerticalAlignment="VerticalAlignment.Center"
|
||||
Wrap="true"
|
||||
Width="100%">
|
||||
<FluentButton>One</FluentButton>
|
||||
<FluentButton>Two</FluentButton>
|
||||
</FluentStack>
|
||||
```
|
||||
|
||||
Parameters: `Orientation`, `HorizontalGap`, `VerticalGap`, `HorizontalAlignment`, `VerticalAlignment`, `Wrap`, `Width`.
|
||||
|
||||
### FluentGrid / FluentGridItem
|
||||
|
||||
12-column responsive grid system.
|
||||
|
||||
```razor
|
||||
<FluentGrid Spacing="3" Justify="JustifyContent.Center" AdaptiveRendering="true">
|
||||
<FluentGridItem xs="12" sm="6" md="4" lg="3">
|
||||
Card 1
|
||||
</FluentGridItem>
|
||||
<FluentGridItem xs="12" sm="6" md="4" lg="3">
|
||||
Card 2
|
||||
</FluentGridItem>
|
||||
</FluentGrid>
|
||||
```
|
||||
|
||||
Size parameters (`xs`, `sm`, `md`, `lg`, `xl`, `xxl`) represent column spans out of 12. Use `AdaptiveRendering="true"` to hide items that don't fit.
|
||||
|
||||
### FluentMainLayout (convenience)
|
||||
|
||||
Pre-composed layout with header, nav menu, and body area.
|
||||
|
||||
```razor
|
||||
<FluentMainLayout Header="@header"
|
||||
SubHeader="@subheader"
|
||||
NavMenuContent="@navMenu"
|
||||
Body="@body"
|
||||
HeaderHeight="50"
|
||||
NavMenuWidth="250"
|
||||
NavMenuTitle="Navigation" />
|
||||
```
|
||||
|
||||
## Navigation Components
|
||||
|
||||
### FluentNavMenu
|
||||
|
||||
Collapsible navigation menu with keyboard support.
|
||||
|
||||
```razor
|
||||
<FluentNavMenu Width="250"
|
||||
Collapsible="true"
|
||||
@bind-Expanded="@menuExpanded"
|
||||
Title="Main navigation"
|
||||
CollapsedChildNavigation="true"
|
||||
Margin="4px 0">
|
||||
<FluentNavLink Href="/" Icon="@(Icons.Regular.Size20.Home)" Match="NavLinkMatch.All">
|
||||
Home
|
||||
</FluentNavLink>
|
||||
<FluentNavLink Href="/counter" Icon="@(Icons.Regular.Size20.NumberSymbol)">
|
||||
Counter
|
||||
</FluentNavLink>
|
||||
<FluentNavGroup Title="Admin" Icon="@(Icons.Regular.Size20.Shield)" @bind-Expanded="@adminExpanded">
|
||||
<FluentNavLink Href="/admin/users">Users</FluentNavLink>
|
||||
<FluentNavLink Href="/admin/roles">Roles</FluentNavLink>
|
||||
</FluentNavGroup>
|
||||
</FluentNavMenu>
|
||||
```
|
||||
|
||||
Key parameters:
|
||||
- `Width` — width in pixels (40px when collapsed)
|
||||
- `Collapsible` — enables expand/collapse toggle
|
||||
- `Expanded` / `ExpandedChanged` — bindable collapse state
|
||||
- `CollapsedChildNavigation` — shows flyout menus for groups when collapsed
|
||||
- `CustomToggle` — for mobile hamburger button patterns
|
||||
- `Title` — aria-label for accessibility
|
||||
|
||||
### FluentNavGroup
|
||||
|
||||
Expandable group within a nav menu.
|
||||
|
||||
```razor
|
||||
<FluentNavGroup Title="Settings"
|
||||
Icon="@(Icons.Regular.Size20.Settings)"
|
||||
@bind-Expanded="@settingsExpanded"
|
||||
Gap="2">
|
||||
<FluentNavLink Href="/settings/general">General</FluentNavLink>
|
||||
<FluentNavLink Href="/settings/profile">Profile</FluentNavLink>
|
||||
</FluentNavGroup>
|
||||
```
|
||||
|
||||
Parameters: `Title`, `Expanded`/`ExpandedChanged`, `Icon`, `IconColor`, `HideExpander`, `Gap`, `MaxHeight`, `TitleTemplate`.
|
||||
|
||||
### FluentNavLink
|
||||
|
||||
Navigation link with active state tracking.
|
||||
|
||||
```razor
|
||||
<FluentNavLink Href="/page"
|
||||
Icon="@(Icons.Regular.Size20.Document)"
|
||||
Match="NavLinkMatch.Prefix"
|
||||
Target="_blank"
|
||||
Disabled="false">
|
||||
Page Title
|
||||
</FluentNavLink>
|
||||
```
|
||||
|
||||
Parameters: `Href`, `Target`, `Match` (`NavLinkMatch.Prefix` default, or `All`), `ActiveClass`, `Icon`, `IconColor`, `Disabled`, `Tooltip`.
|
||||
|
||||
All nav components inherit from `FluentNavBase` which provides: `Icon`, `IconColor`, `CustomColor`, `Disabled`, `Tooltip`.
|
||||
|
||||
### FluentBreadcrumb / FluentBreadcrumbItem
|
||||
|
||||
```razor
|
||||
<FluentBreadcrumb>
|
||||
<FluentBreadcrumbItem Href="/">Home</FluentBreadcrumbItem>
|
||||
<FluentBreadcrumbItem Href="/products">Products</FluentBreadcrumbItem>
|
||||
<FluentBreadcrumbItem>Current Page</FluentBreadcrumbItem>
|
||||
</FluentBreadcrumb>
|
||||
```
|
||||
|
||||
### FluentTab / FluentTabs
|
||||
|
||||
```razor
|
||||
<FluentTabs @bind-ActiveTabId="@activeTab">
|
||||
<FluentTab Id="tab1" Label="Details">
|
||||
Details content
|
||||
</FluentTab>
|
||||
<FluentTab Id="tab2" Label="History">
|
||||
History content
|
||||
</FluentTab>
|
||||
</FluentTabs>
|
||||
```
|
||||
@@ -0,0 +1,129 @@
|
||||
# Setup and Configuration
|
||||
|
||||
## NuGet Packages
|
||||
|
||||
| Package | Purpose |
|
||||
|---|---|
|
||||
| `Microsoft.FluentUI.AspNetCore.Components` | Core component library (required) |
|
||||
| `Microsoft.FluentUI.AspNetCore.Components.Icons` | Icon package (optional, recommended) |
|
||||
| `Microsoft.FluentUI.AspNetCore.Components.Emojis` | Emoji package (optional) |
|
||||
| `Microsoft.FluentUI.AspNetCore.Components.DataGrid.EntityFrameworkAdapter` | EF Core adapter for DataGrid (optional) |
|
||||
| `Microsoft.FluentUI.AspNetCore.Components.DataGrid.ODataAdapter` | OData adapter for DataGrid (optional) |
|
||||
|
||||
## Program.cs Registration
|
||||
|
||||
```csharp
|
||||
builder.Services.AddFluentUIComponents();
|
||||
```
|
||||
|
||||
### Configuration Options (LibraryConfiguration)
|
||||
|
||||
| Property | Type | Default | Notes |
|
||||
|---|---|---|---|
|
||||
| `UseTooltipServiceProvider` | `bool` | `true` | Registers `ITooltipService`. If true, you MUST add `<FluentTooltipProvider>` to layout |
|
||||
| `RequiredLabel` | `MarkupString` | Red `*` | Custom markup for required field indicators |
|
||||
| `HideTooltipOnCursorLeave` | `bool` | `false` | Close tooltip when cursor leaves both anchor and tooltip |
|
||||
| `ServiceLifetime` | `ServiceLifetime` | `Scoped` | Only `Scoped` or `Singleton`. `Transient` throws! |
|
||||
| `ValidateClassNames` | `bool` | `true` | Validates CSS class names against `^-?[_a-zA-Z]+[_a-zA-Z0-9-]*$` |
|
||||
| `CollocatedJavaScriptQueryString` | `Func<string, string>?` | `v={version}` | Cache-busting for JS files |
|
||||
|
||||
### ServiceLifetime by hosting model
|
||||
|
||||
| Hosting model | ServiceLifetime |
|
||||
|---|---|
|
||||
| Blazor Server | `Scoped` (default) |
|
||||
| Blazor WebAssembly Standalone | `Singleton` |
|
||||
| Blazor Web App (Interactive) | `Scoped` (default) |
|
||||
| Blazor Hybrid (MAUI) | `Singleton` |
|
||||
|
||||
## MainLayout.razor Template
|
||||
|
||||
```razor
|
||||
@inherits LayoutComponentBase
|
||||
|
||||
<FluentLayout>
|
||||
<FluentHeader Height="50">
|
||||
My App
|
||||
</FluentHeader>
|
||||
|
||||
<FluentStack Orientation="Orientation.Horizontal" HorizontalGap="0" Style="height: 100%;">
|
||||
<FluentNavMenu Width="250" Collapsible="true" Title="Navigation">
|
||||
<FluentNavLink Href="/" Icon="@(Icons.Regular.Size20.Home)" Match="NavLinkMatch.All">Home</FluentNavLink>
|
||||
<FluentNavLink Href="/counter" Icon="@(Icons.Regular.Size20.NumberSymbol)">Counter</FluentNavLink>
|
||||
<FluentNavGroup Title="Settings" Icon="@(Icons.Regular.Size20.Settings)">
|
||||
<FluentNavLink Href="/settings/general">General</FluentNavLink>
|
||||
<FluentNavLink Href="/settings/profile">Profile</FluentNavLink>
|
||||
</FluentNavGroup>
|
||||
</FluentNavMenu>
|
||||
|
||||
<FluentBodyContent>
|
||||
<FluentStack Orientation="Orientation.Vertical" Style="padding: 1rem;">
|
||||
@Body
|
||||
</FluentStack>
|
||||
</FluentBodyContent>
|
||||
</FluentStack>
|
||||
</FluentLayout>
|
||||
|
||||
@* Required providers — place after FluentLayout *@
|
||||
<FluentToastProvider />
|
||||
<FluentDialogProvider />
|
||||
<FluentMessageBarProvider />
|
||||
<FluentTooltipProvider />
|
||||
<FluentKeyCodeProvider />
|
||||
|
||||
@* Theme — place at root *@
|
||||
<FluentDesignTheme Mode="DesignThemeModes.System"
|
||||
OfficeColor="OfficeColor.Teams"
|
||||
StorageName="mytheme" />
|
||||
```
|
||||
|
||||
Or use the convenience component:
|
||||
|
||||
```razor
|
||||
<FluentMainLayout Header="@header"
|
||||
NavMenuContent="@navMenu"
|
||||
Body="@body"
|
||||
HeaderHeight="50"
|
||||
NavMenuWidth="250"
|
||||
NavMenuTitle="Navigation" />
|
||||
|
||||
@code {
|
||||
private RenderFragment header = @<span>My App</span>;
|
||||
private RenderFragment navMenu = @<div>
|
||||
<FluentNavLink Href="/">Home</FluentNavLink>
|
||||
</div>;
|
||||
private RenderFragment body = @<div>@Body</div>;
|
||||
}
|
||||
```
|
||||
|
||||
## _Imports.razor
|
||||
|
||||
Add this to your `_Imports.razor`:
|
||||
|
||||
```razor
|
||||
@using Microsoft.FluentUI.AspNetCore.Components
|
||||
@using Icons = Microsoft.FluentUI.AspNetCore.Components.Icons
|
||||
```
|
||||
|
||||
## Static Web Assets
|
||||
|
||||
No manual `<link>` or `<script>` tags are needed. The library uses:
|
||||
- **CSS**: `reboot.css` (normalization) + component-scoped CSS — auto-loaded via static web assets
|
||||
- **JS**: `lib.module.js` — auto-loaded via Blazor's JS initializer system
|
||||
- Component-specific JS (e.g. DataGrid, Autocomplete) — lazy-loaded on demand
|
||||
|
||||
All served from `_content/Microsoft.FluentUI.AspNetCore.Components/`.
|
||||
|
||||
## Services Registered
|
||||
|
||||
Services automatically registered by `AddFluentUIComponents()`:
|
||||
|
||||
| Service | Implementation | Purpose |
|
||||
|---|---|---|
|
||||
| `GlobalState` | `GlobalState` | Shared application state |
|
||||
| `IToastService` | `ToastService` | Toast notifications (needs `FluentToastProvider`) |
|
||||
| `IDialogService` | `DialogService` | Dialogs and panels (needs `FluentDialogProvider`) |
|
||||
| `IMessageService` | `MessageService` | Message bars (needs `FluentMessageBarProvider`) |
|
||||
| `IKeyCodeService` | `KeyCodeService` | Keyboard shortcuts (needs `FluentKeyCodeProvider`) |
|
||||
| `IMenuService` | `MenuService` | Context menus |
|
||||
| `ITooltipService` | `TooltipService` | Tooltips (needs `FluentTooltipProvider`, opt-in via `UseTooltipServiceProvider`) |
|
||||
@@ -0,0 +1,103 @@
|
||||
# Theming
|
||||
|
||||
## FluentDesignTheme (recommended)
|
||||
|
||||
The primary theming component. Place it at the root of your app.
|
||||
|
||||
```razor
|
||||
<FluentDesignTheme Mode="DesignThemeModes.System"
|
||||
OfficeColor="OfficeColor.Teams"
|
||||
StorageName="mytheme" />
|
||||
```
|
||||
|
||||
### Parameters
|
||||
|
||||
| Parameter | Type | Default | Description |
|
||||
|---|---|---|---|
|
||||
| `Mode` | `DesignThemeModes` | `System` | `Light`, `Dark`, or `System` (follows OS) |
|
||||
| `CustomColor` | `string?` | null | Hex accent color (e.g. `"#0078D4"`) |
|
||||
| `OfficeColor` | `OfficeColor?` | null | Preset accent: `Teams`, `Word`, `Excel`, `PowerPoint`, `Outlook`, `OneNote` |
|
||||
| `NeutralBaseColor` | `string?` | null | Neutral palette base hex color |
|
||||
| `StorageName` | `string?` | null | Persist theme to localStorage under this key |
|
||||
| `Direction` | `LocalizationDirection?` | null | `Ltr` or `Rtl` |
|
||||
| `OnLuminanceChanged` | `EventCallback<LuminanceChangedEventArgs>` | | Fired when dark/light mode changes |
|
||||
| `OnLoaded` | `EventCallback<LoadedEventArgs>` | | Fired when theme is loaded from storage |
|
||||
|
||||
### Two-way binding
|
||||
|
||||
```razor
|
||||
<FluentDesignTheme @bind-Mode="@themeMode"
|
||||
@bind-OfficeColor="@officeColor"
|
||||
@bind-CustomColor="@customColor"
|
||||
StorageName="mytheme" />
|
||||
|
||||
<FluentSelect Items="@(Enum.GetValues<DesignThemeModes>())"
|
||||
@bind-SelectedOption="@themeMode"
|
||||
OptionText="@(m => m.ToString())" />
|
||||
|
||||
@code {
|
||||
private DesignThemeModes themeMode = DesignThemeModes.System;
|
||||
private OfficeColor? officeColor = OfficeColor.Teams;
|
||||
private string? customColor;
|
||||
}
|
||||
```
|
||||
|
||||
### Important: JS interop dependency
|
||||
|
||||
`FluentDesignTheme` uses JavaScript interop internally. It will NOT work during server-side pre-rendering. If you need to react to theme changes:
|
||||
|
||||
```csharp
|
||||
// Use OnAfterRenderAsync, NOT OnInitialized
|
||||
protected override async Task OnAfterRenderAsync(bool firstRender)
|
||||
{
|
||||
if (firstRender)
|
||||
{
|
||||
// Safe to interact with design tokens here
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## FluentDesignSystemProvider (advanced)
|
||||
|
||||
For scoping design tokens to a subtree of the component tree. Provides 50+ CSS custom properties.
|
||||
|
||||
```razor
|
||||
<FluentDesignSystemProvider AccentBaseColor="#0078D4"
|
||||
NeutralBaseColor="#808080"
|
||||
BaseLayerLuminance="0.95">
|
||||
<FluentButton Appearance="Appearance.Accent">Themed Button</FluentButton>
|
||||
</FluentDesignSystemProvider>
|
||||
```
|
||||
|
||||
## Design Token Classes (DI-based, advanced)
|
||||
|
||||
For programmatic token control via dependency injection. Each token is a generated service.
|
||||
|
||||
```csharp
|
||||
@inject AccentBaseColor AccentBaseColor
|
||||
|
||||
protected override async Task OnAfterRenderAsync(bool firstRender)
|
||||
{
|
||||
if (firstRender)
|
||||
{
|
||||
// Set token for a specific element
|
||||
await AccentBaseColor.SetValueFor(myElement, "#FF0000".ToSwatch());
|
||||
|
||||
// Read token value
|
||||
var currentColor = await AccentBaseColor.GetValueFor(myElement);
|
||||
|
||||
// Remove override
|
||||
await AccentBaseColor.DeleteValueFor(myElement);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Available DesignThemeModes
|
||||
|
||||
- `DesignThemeModes.Light` — light theme
|
||||
- `DesignThemeModes.Dark` — dark theme
|
||||
- `DesignThemeModes.System` — follows OS preference
|
||||
|
||||
## Available OfficeColor presets
|
||||
|
||||
`Teams`, `Word`, `Excel`, `PowerPoint`, `Outlook`, `OneNote`, `Loop`, `Planner`, `SharePoint`, `Stream`, `Sway`, `Viva`, `VivaEngage`, `VivaInsights`, `VivaLearning`, `VivaTopics`.
|
||||
Reference in New Issue
Block a user