diff --git a/.agents/skills/blazor/SKILL.md b/.agents/skills/blazor/SKILL.md new file mode 100644 index 0000000..7c59392 --- /dev/null +++ b/.agents/skills/blazor/SKILL.md @@ -0,0 +1,145 @@ +--- +name: blazor +description: "Author, extend, and review BitBlazor library components — accessible, Bootstrap Italia-styled Blazor UI kit components for .NET 9+. USE FOR: creating a new Bit component, extending an existing component, adding a form field, reviewing component markup or parameters, writing bUnit tests for a component. DO NOT USE FOR: unrelated stacks or building Blazor applications with BitBlazor (not authoring the library itself). INVOKES: inspect the repository context, edit targeted files, and run relevant build and test commands when changes are made." +compatibility: "Requires .NET 9+. Library targets net9.0 and uses Bootstrap Italia for all styling." +--- + +# BitBlazor Component Authoring + +## Trigger On + +- creating a new `Bit` prefixed component (e.g., `BitAlert`, `BitTextField`) +- extending an existing BitBlazor component with new parameters or behaviour +- adding a form field component that integrates with `EditForm` and `EditContext` +- reviewing component markup, parameter declarations, or CSS class composition +- writing or reviewing bUnit tests for a library component +- integrating with JavaScript from a library component + +## Documentation + +- [Blazor Overview](https://learn.microsoft.com/en-us/aspnet/core/blazor/?view=aspnetcore-10.0) +- [Blazor Component Lifecycle](https://learn.microsoft.com/en-us/aspnet/core/blazor/components/lifecycle?view=aspnetcore-10.0) +- [Blazor Performance Best Practices](https://learn.microsoft.com/en-us/aspnet/core/blazor/performance?view=aspnetcore-10.0) +- [Blazor JS Interop](https://learn.microsoft.com/en-us/aspnet/core/blazor/javascript-interoperability/?view=aspnetcore-10.0) +- [Bootstrap Italia](https://italia.github.io/bootstrap-italia/docs) +- [bUnit Testing](https://bunit.dev/docs/getting-started/) + +### References + +- [patterns.md](references/patterns.md) — General-purpose and form component code patterns, CSS class composition, performance, JS interop +- [anti-patterns.md](references/anti-patterns.md) — BitBlazor-specific mistakes and how to avoid them +- [testing.md](references/testing.md) — bUnit testing patterns and conventions +- [stories.md](references/stories.md) — BlazingStory file structure and conventions +- [docs-template.md](references/docs-template.md) — Documentation page template and structure + +## Component Authoring Workflow + +1. **Choose the right base class** (see Base Class Hierarchy below) +2. **Create the two component files** in `src/BitBlazor/Components//` or `src/BitBlazor/Form//`: + - `BitXxx.razor` — markup only; inline `@code` for trivial render helpers + - `BitXxx.razor.cs` — partial class with all `[Parameter]` declarations, private state, and computed properties +3. **Declare parameters** with XML `` docs; use enum types (`Color`, `Size`, `Variant`) instead of raw strings +4. **Compose the CSS class string** using `CssClassBuilder`; always call `AddCustomCssClass()` before `Build()` +5. **Write semantic markup** using native HTML elements; forward unknown attributes via `@attributes="AdditionalAttributes"` +6. **Wire ARIA attributes** for interactive and form components (see [Accessibility](#accessibility) section) +7. **Create a test file** in `tests/BitBlazor.Test/Components//` or `tests/BitBlazor.Test/Form//` — see [testing.md](references/testing.md) +8. **Create a story file** mirroring the component's namespace under `stories/BitBlazor.Stories/Components/Stories/` — see [stories.md](references/stories.md) +9. **Write the documentation page** in `docs/components/` or `docs/form/` — see [docs-template.md](references/docs-template.md) + +## Base Class Hierarchy + +Choose the base class that matches the component's role: + +| Base Class | When to Use | Key Members Provided | +|------------|-------------|----------------------| +| `BitComponentBase` | General-purpose display and interactive components (alert, badge, card, button, …) | `CssClass`, `Id`, `AdditionalAttributes`, `AddCustomCssClass()` | +| `BitFormComponentBase` | Form components that bind a value | Everything above + `Label`, `Value`, `ValueChanged`, `ValueExpression`, `Required`, `Disabled`, `AdditionalText`, `AdditionalTextId`, `CurrentEditContext` | +| `BitInputFieldBase` | Text-like input fields | Everything above + `Readonly`, `Plaintext`, `Placeholder`, `Size` | + +**Never inherit directly from `ComponentBase`.** See [patterns.md](references/patterns.md) for full component examples. + +## CSS Class Composition + +Use `CssClassBuilder` (from `BitBlazor.Core`) to compose CSS class strings — never concatenate manually. Always call `AddCustomCssClass()` before `Build()`: + +```csharp +var builder = new CssClassBuilder("btn") + .Add($"btn-{Color.ToCssClass()}") + .Add("btn-sm", Size == Size.Small); +AddCustomCssClass(builder); +return builder.Build(); +``` + +Use Bootstrap Italia CSS class names exclusively. See [patterns.md](references/patterns.md) for complete examples. + + +## Design Token Enums + +Always use the project's enum types as parameter types — never raw strings: + +| Enum | Values | Example Parameter | +|------|--------|-------------------| +| `Color` | `Primary`, `Secondary`, `Success`, `Warning`, `Danger`, … | `public Color Color { get; set; }` | +| `Size` | `Default`, `Small`, `Large` | `public Size Size { get; set; } = Size.Default;` | +| `Variant` | `Solid`, `Outline`, `Ghost`, … | `public Variant Variant { get; set; } = Variant.Solid;` | +| `Ratio` | Aspect ratio values | `public Ratio Ratio { get; set; }` | +| `Typography` | Typography scale values | `public Typography Typography { get; set; }` | + +## Render Mode Compatibility + +Library components must work in **all render modes** used by the consuming application. Follow these rules: + +| Concern | Rule | +|---------|------| +| JS Interop | Always use `IJSRuntime` async APIs; never synchronous interop | +| State | Components are stateless by design — values flow in via parameters, changes flow out via `EventCallback` | +| No DB / HTTP calls | Library components never access services directly; they are pure UI | +| `EventCallback` | Use `EventCallback` (not `Action`/`Func`) for callbacks to ensure correct rendering | + +## Accessibility + +Accessibility is a **first-class requirement** for every component in this library. The authoritative ruleset is [`a11y.instructions.md`](../../../.github/instructions/a11y.instructions.md), which is automatically active on every `.razor`, `.razor.cs`, and `.razor.css` edit — read it before authoring any interactive component. + +The checks most commonly missed when creating a new BitBlazor component are: + +| Check | Rule | +|-------|------| +| **BL1** — `@onclick` on `
` or `` | Always use `