diff --git a/ShellUI.Tests/TemplateSyncTests.cs b/ShellUI.Tests/TemplateSyncTests.cs index 4c1894e..a54226a 100644 --- a/ShellUI.Tests/TemplateSyncTests.cs +++ b/ShellUI.Tests/TemplateSyncTests.cs @@ -129,6 +129,13 @@ public class TemplateSyncTests [InlineData("command-option", "CommandOption.razor")] [InlineData("command-empty", "CommandEmpty.razor")] [InlineData("command-separator", "CommandSeparator.razor")] + [InlineData("label", "Label.razor")] + [InlineData("file-upload", "FileUpload.razor")] + [InlineData("carousel-item", "CarouselItem.razor")] + [InlineData("menubar", "Menubar.razor")] + [InlineData("sheet-content", "SheetContent.razor")] + [InlineData("drawer-content", "DrawerContent.razor")] + [InlineData("sidebar-menu-button", "SidebarMenuButton.razor")] public void TemplateCodeBlock_MatchesLiveLibrary(string templateName, string razorFileName) { if (AllowedDrift.ContainsKey(templateName)) return; @@ -152,6 +159,29 @@ public void TemplateCodeBlock_MatchesLiveLibrary(string templateName, string raz DiffSummary(normalizedLive, normalizedTemplate)); } + [Theory] + [InlineData("label", "Label.razor")] + [InlineData("file-upload", "FileUpload.razor")] + [InlineData("carousel-item", "CarouselItem.razor")] + [InlineData("menubar", "Menubar.razor")] + [InlineData("sheet-content", "SheetContent.razor")] + [InlineData("drawer-content", "DrawerContent.razor")] + [InlineData("sidebar-menu-button", "SidebarMenuButton.razor")] + [InlineData("theme-toggle", "ThemeToggle.razor")] + public void TemplateMarkup_MatchesLiveLibrary(string templateName, string razorFileName) + { + var liveContent = File.ReadAllText(GetLiveRazorPath(razorFileName)); + var templateContent = ComponentRegistry.GetComponentContent(templateName) + ?? throw new InvalidOperationException($"Template '{templateName}' not found in registry"); + + var normalizedLive = Normalize(ExtractMarkup(liveContent)); + var normalizedTemplate = Normalize(ExtractMarkup(templateContent)); + + Assert.True(normalizedLive == normalizedTemplate, + $"Markup drift between live {razorFileName} and template {templateName}.\n\n" + + DiffSummary(normalizedLive, normalizedTemplate)); + } + [Fact] public void ChartVariantsTemplate_MatchesLiveLibrary() { @@ -204,6 +234,15 @@ private static string DiffSummary(string live, string template) return diffs.Length == 0 ? "(no per-line diff — file lengths differ)" : diffs.ToString(); } + // Everything before `@code`, without the @namespace and @using lines that differ by design. + private static string ExtractMarkup(string razor) + { + var match = Regex.Match(razor, @"@code\s*\{"); + var head = match.Success ? razor.Substring(0, match.Index) : razor; + var lines = head.Split('\n').Where(l => !Regex.IsMatch(l.Trim(), @"^@(namespace|using)\b")); + return string.Join("\n", lines); + } + /// Body of the first `@code { }` block, or null if missing or unbalanced. private static string? ExtractCodeBlock(string razor) { diff --git a/docs/COMPONENT_ROADMAP.md b/docs/COMPONENT_ROADMAP.md index 30af5bd..95b5b94 100644 --- a/docs/COMPONENT_ROADMAP.md +++ b/docs/COMPONENT_ROADMAP.md @@ -73,15 +73,10 @@ The current registry provides explicit sub-components for these parent component - [x] **Popover** — `PopoverTrigger`, `PopoverContent` - [x] **HoverCard** — `HoverCardTrigger`, `HoverCardContent` - [x] **Drawer and Sheet** — explicit trigger/content and variant support - -### Package only (CLI templates pending) - -These parts exist in the `ShellUI.Components` NuGet package, but their CLI templates are empty placeholders, so CLI installs only get the parent component. - -- [ ] **Select** — `SelectTrigger`, `SelectContent`, `SelectItem` (the native select works in both) -- [ ] **ContextMenu** — `ContextMenuTrigger`, `ContextMenuContent`, `ContextMenuOption` -- [ ] **NavigationMenu** — `NavList`, `NavItem`, `NavTrigger`, `NavContent` -- [ ] **Carousel** — `CarouselList`, `CarouselSlide` +- [x] **Select** — `SelectTrigger`, `SelectContent`, `SelectItem` (the native select still works) +- [x] **ContextMenu** — `ContextMenuTrigger`, `ContextMenuContent`, `ContextMenuOption` +- [x] **NavigationMenu** — `NavList`, `NavItem`, `NavTrigger`, `NavContent` +- [x] **Carousel** — `CarouselList`, `CarouselSlide` The intended pattern is explicit child components, cascaded state and callbacks, value/label parameters, and Tailwind utility classes matching the shadcn-style API. diff --git a/src/ShellUI.Components/Components/Drawer.razor b/src/ShellUI.Components/Components/Drawer.razor index 9dde347..76bd72d 100644 --- a/src/ShellUI.Components/Components/Drawer.razor +++ b/src/ShellUI.Components/Components/Drawer.razor @@ -9,7 +9,7 @@ else if (Open) {
-
+
@if (!string.IsNullOrEmpty(Title)) diff --git a/src/ShellUI.Components/Components/DrawerContent.razor b/src/ShellUI.Components/Components/DrawerContent.razor index a2510ae..d3ea80a 100644 --- a/src/ShellUI.Components/Components/DrawerContent.razor +++ b/src/ShellUI.Components/Components/DrawerContent.razor @@ -6,7 +6,7 @@ @if (Parent?.Open == true) {
-