FractalDataWorks.UI.Components.RazorConsole
0.1.0-preview.15
dotnet add package FractalDataWorks.UI.Components.RazorConsole --version 0.1.0-preview.15
NuGet\Install-Package FractalDataWorks.UI.Components.RazorConsole -Version 0.1.0-preview.15
<PackageReference Include="FractalDataWorks.UI.Components.RazorConsole" Version="0.1.0-preview.15" />
<PackageVersion Include="FractalDataWorks.UI.Components.RazorConsole" Version="0.1.0-preview.15" />
<PackageReference Include="FractalDataWorks.UI.Components.RazorConsole" />
paket add FractalDataWorks.UI.Components.RazorConsole --version 0.1.0-preview.15
#r "nuget: FractalDataWorks.UI.Components.RazorConsole, 0.1.0-preview.15"
#:package FractalDataWorks.UI.Components.RazorConsole@0.1.0-preview.15
#addin nuget:?package=FractalDataWorks.UI.Components.RazorConsole&version=0.1.0-preview.15&prerelease
#tool nuget:?package=FractalDataWorks.UI.Components.RazorConsole&version=0.1.0-preview.15&prerelease
FractalDataWorks.UI.Components.RazorConsole
Razor-syntax terminal UI framework that compiles declarative markup to Spectre.Console at build time. Provides a Blazor-like developer experience for creating terminal applications with compile-time validation and IntelliSense support.
Overview
RazorConsole enables writing terminal UI components using Razor syntax that compiles to Spectre.Console rendering code. Components inherit from a CRTP base class that provides lifecycle methods and Spectre.Console integration.
Status: Early implementation. The source generator compiles .cshtml files to C# partial classes with Prompt() and Render() method stubs.
Key Features:
- Razor syntax with
@inherits,@using, and@codeblocks - Component base class with Blazor-like lifecycle methods
- Spectre.Console integration through TUIComponent base
- Source generator produces partial classes from .cshtml files
Target Framework: net10.0
Dependencies:
- FractalDataWorks.UI.Abstractions
- FractalDataWorks.UI.Components.TUI
- Spectre.Console
- Microsoft.AspNetCore.Components
Architecture
.cshtml file
|
v
RazorConsoleSourceGenerator (build-time)
|
v
Generated .g.cs partial class
|
v
RazorConsoleComponent<TModel> base class
|
v
TUIComponent<TSelf, TModel> (Spectre.Console integration)
Component Base Class
From RazorConsoleComponent.cs:15-92:
/// <summary>
/// Base class for RazorConsole components.
/// Inherits from TUIComponent to provide Spectre.Console integration.
/// </summary>
/// <typeparam name="TModel">The model type this component renders</typeparam>
public abstract class RazorConsoleComponent<TModel> : TUIComponent<RazorConsoleComponent<TModel>, TModel>
{
/// <summary>
/// The console instance to render to.
/// Set by generated code or consumer.
/// </summary>
protected IAnsiConsole Console { get; set; } = AnsiConsole.Console;
/// <summary>
/// Gets or sets the model being rendered.
/// Alias for Value property from base class for Razor compatibility.
/// </summary>
public TModel Model
{
get => Value!;
set => Value = value;
}
/// <summary>
/// Called when component initializes.
/// Override in derived components for initialization logic.
/// </summary>
protected virtual void OnInitialized()
{
}
/// <summary>
/// Async version of OnInitialized.
/// </summary>
protected virtual Task OnInitializedAsync()
{
return Task.CompletedTask;
}
/// <summary>
/// Called when parameters are set.
/// </summary>
protected virtual void OnParametersSet()
{
}
/// <summary>
/// Async version of OnParametersSet.
/// </summary>
protected virtual Task OnParametersSetAsync()
{
return Task.CompletedTask;
}
/// <summary>
/// Prompts for interactive input.
/// Generated by source generator from .cshtml markup.
/// </summary>
public abstract override Task<TModel?> Prompt(IAnsiConsole console);
/// <summary>
/// Renders component to console (display-only).
/// Generated by source generator from .cshtml markup.
/// </summary>
public abstract override void Render(IAnsiConsole console);
}
Parameter Attributes
From ParameterAttribute.cs:1-12:
/// <summary>
/// Marks a property as a component parameter.
/// Parameters can be set by parent components.
/// </summary>
[AttributeUsage(AttributeTargets.Property, AllowMultiple = false, Inherited = true)]
public sealed class ParameterAttribute : Attribute
{
}
From CascadingParameterAttribute.cs:1-16:
/// <summary>
/// Marks a property as a cascading parameter.
/// Cascading parameters flow down the component tree.
/// </summary>
[AttributeUsage(AttributeTargets.Property, AllowMultiple = false, Inherited = true)]
public sealed class CascadingParameterAttribute : Attribute
{
/// <summary>
/// Optional name for this cascading parameter.
/// </summary>
public string? Name { get; set; }
}
Source Generator
The source generator compiles .cshtml files to C# partial classes.
From RazorConsoleSourceGenerator.cs:14-39:
/// <summary>
/// Source generator that compiles .cshtml files to Spectre.Console rendering code.
/// </summary>
[Generator(LanguageNames.CSharp)]
public sealed class RazorConsoleSourceGenerator : IIncrementalGenerator
{
/// <summary>
/// Initializes the source generator to find and compile Razor files.
/// </summary>
/// <param name="context">The incremental generator initialization context.</param>
public void Initialize(IncrementalGeneratorInitializationContext context)
{
// Find all .cshtml files
var razorFiles = context.AdditionalTextsProvider
.Where(static file => file.Path.EndsWith(".cshtml", StringComparison.OrdinalIgnoreCase));
// Compile each Razor file
context.RegisterSourceOutput(razorFiles, static (context, file) =>
{
var result = RazorCompiler.Compile(file);
if (result != null)
{
var fileName = System.IO.Path.GetFileNameWithoutExtension(file.Path);
context.AddSource($"{fileName}.g.cs", SourceText.From(result, Encoding.UTF8));
}
});
}
}
TUI Component Base
RazorConsoleComponent inherits from TUIComponent, which provides Spectre.Console integration.
From TUIComponent.cs:16-72:
/// <summary>
/// CRTP base for Terminal UI components using Spectre.Console.
/// Provides interactive prompting and rich console rendering.
/// </summary>
/// <typeparam name="TSelf">The derived TUI component type (CRTP)</typeparam>
/// <typeparam name="TModel">The model type being rendered</typeparam>
public abstract class TUIComponent<TSelf, TModel> : ComponentBase<TSelf, TModel>
where TSelf : TUIComponent<TSelf, TModel>
{
/// <summary>
/// Theme configuration for this component.
/// </summary>
public TUIThemeConfiguration? Theme { get; set; }
/// <summary>
/// Prompts the user to enter/edit the model value interactively.
/// </summary>
/// <param name="console">The console to prompt on</param>
/// <returns>The entered/edited model value</returns>
public abstract Task<TModel?> Prompt(IAnsiConsole console);
/// <summary>
/// Renders the current model value to the console (read-only display).
/// </summary>
/// <param name="console">The console to render to</param>
public abstract void Render(IAnsiConsole console);
/// <summary>
/// Gets display text for this component (for use in lists/tables).
/// </summary>
public virtual string GetDisplayText()
{
return Value?.ToString() ?? "[dim]null[/]";
}
/// <summary>
/// Renders a section header with the component name.
/// </summary>
protected virtual void RenderHeader(IAnsiConsole console, string? title = null)
{
var headerTitle = title ?? typeof(TModel).Name;
var color = Theme?.Colors.Primary ?? Color.Yellow;
console.Write(new Rule($"[{color}]{headerTitle}[/]").LeftJustified());
}
/// <summary>
/// Prompts for a TypeCollection selection.
/// </summary>
protected virtual int PromptTypeCollectionId<TCollection, TOption>(
IAnsiConsole console,
string promptText,
int currentId = 0)
where TCollection : class
where TOption : class, ITypeOption
{
return Prompts.TypeCollectionPromptHelper.Prompt<TCollection, TOption>(
console,
promptText,
currentId,
Theme);
}
}
Theme Configuration
From TUIThemeConfiguration.cs:1-80:
/// <summary>
/// Theme configuration for Terminal UI components.
/// </summary>
public class TUIThemeConfiguration
{
private IMenuTheme _theme;
/// <summary>
/// Initializes a new instance with the default dark theme.
/// </summary>
public TUIThemeConfiguration()
{
_theme = MenuThemes.ByName("Dark");
}
/// <summary>
/// Initializes a new instance with the specified theme.
/// </summary>
/// <param name="theme">The menu theme to use.</param>
public TUIThemeConfiguration(IMenuTheme theme)
{
_theme = theme;
}
/// <summary>
/// Gets or sets the theme by Id.
/// </summary>
public int ThemeId
{
get => _theme.Id;
set => _theme = MenuThemes.ById(value);
}
/// <summary>
/// Gets or sets the theme by name.
/// </summary>
public string ThemeName
{
get => _theme.Name;
set => _theme = MenuThemes.ByName(value);
}
/// <summary>
/// Gets the current theme.
/// </summary>
public IMenuTheme Theme => _theme;
/// <summary>
/// Gets the color palette from the current theme.
/// </summary>
public IColorPalette Colors => _theme.Colors;
/// <summary>
/// Gets the border style from the current theme.
/// </summary>
public IBorderStyle Borders => _theme.Borders;
/// <summary>
/// Gets the icon set from the current theme.
/// </summary>
public IIconSet Icons => _theme.Icons;
/// <summary>
/// Gets or sets whether to use color in output.
/// </summary>
public bool UseColor { get; set; } = true;
/// <summary>
/// Gets or sets whether to use emoji/icons in output.
/// </summary>
public bool UseEmoji { get; set; } = true;
}
Validation Support
The UI.Abstractions package provides validation result types that can be used with RazorConsole components.
From ValidationResult.cs:9-88:
/// <summary>
/// Represents the result of a component validation.
/// </summary>
public sealed class ValidationResult
{
private readonly List<ValidationMessage> _messages;
private ValidationResult(bool isValid, IEnumerable<ValidationMessage>? messages = null)
{
IsValid = isValid;
_messages = messages?.ToList() ?? [];
}
/// <summary>
/// Gets a value indicating whether the validation passed.
/// </summary>
public bool IsValid { get; }
/// <summary>
/// Gets the validation messages.
/// </summary>
public IReadOnlyList<ValidationMessage> Messages => _messages.AsReadOnly();
/// <summary>
/// Gets the first error message, if any.
/// </summary>
public string? FirstError => _messages
.FirstOrDefault(m => m.Severity == ValidationSeverity.Error)?.Message;
/// <summary>
/// Creates a successful validation result.
/// </summary>
public static ValidationResult Success() => new(true);
/// <summary>
/// Creates a failed validation result with an error message.
/// </summary>
public static ValidationResult Error(string error)
=> new(false, [new ValidationMessage(error, ValidationSeverity.Error)]);
/// <summary>
/// Combines multiple validation results.
/// </summary>
public static ValidationResult Combine(params ValidationResult[] results)
{
var allMessages = results.SelectMany(r => r.Messages).ToList();
var isValid = results.All(r => r.IsValid);
return new ValidationResult(isValid, allMessages);
}
}
Current Limitations
The source generator is in early development. Current implementation:
- Parses .cshtml files using Microsoft.AspNetCore.Razor.Language
- Generates partial class stubs with abstract method implementations
- Placeholder code generation for Prompt and Render methods
Planned features (not yet implemented):
- Custom component tags (
<Panel>,<Property>,<Collection>, etc.) - Property binding with
@bind-Value - Conditional rendering
- Loop support
- Component composition
Best Practices
- Keep components focused on a single responsibility
- Use
[Parameter]attribute for properties set by parent components - Use
[CascadingParameter]for values that flow down the component tree - Override lifecycle methods (
OnInitialized,OnParametersSet) for initialization logic - Inject
TUIThemeConfigurationvia cascading parameter for consistent theming
See Also
- UI.Abstractions - Pure CRTP base classes
- UI.Components.TUI - Imperative TUI with Spectre.Console
- UI.Components.Blazor - Blazor web implementation
- Configuration.UI.SourceGenerators - Auto-generation from configs
- Spectre.Console Documentation - Terminal rendering framework
- Razor Syntax Reference - Razor language syntax
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net10.0 is compatible. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
-
net10.0
- FractalDataWorks.UI.Abstractions (>= 0.1.0-preview.15)
- FractalDataWorks.UI.Components.TUI (>= 0.1.0-preview.15)
- Microsoft.AspNetCore.Components (>= 10.0.0)
- Spectre.Console (>= 0.54.1-alpha.0.7)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated |
|---|---|---|
| 0.1.0-preview.15 | 0 | 1/15/2026 |
| 0.1.0-preview.11 | 38 | 1/12/2026 |
| 0.1.0-preview.10 | 36 | 1/12/2026 |
| 0.1.0-preview.9 | 39 | 1/9/2026 |
| 0.1.0-preview.7 | 103 | 1/7/2026 |