FractalDataWorks.UI.Web.Abstractions
0.1.0-preview.11
dotnet add package FractalDataWorks.UI.Web.Abstractions --version 0.1.0-preview.11
NuGet\Install-Package FractalDataWorks.UI.Web.Abstractions -Version 0.1.0-preview.11
<PackageReference Include="FractalDataWorks.UI.Web.Abstractions" Version="0.1.0-preview.11" />
<PackageVersion Include="FractalDataWorks.UI.Web.Abstractions" Version="0.1.0-preview.11" />
<PackageReference Include="FractalDataWorks.UI.Web.Abstractions" />
paket add FractalDataWorks.UI.Web.Abstractions --version 0.1.0-preview.11
#r "nuget: FractalDataWorks.UI.Web.Abstractions, 0.1.0-preview.11"
#:package FractalDataWorks.UI.Web.Abstractions@0.1.0-preview.11
#addin nuget:?package=FractalDataWorks.UI.Web.Abstractions&version=0.1.0-preview.11&prerelease
#tool nuget:?package=FractalDataWorks.UI.Web.Abstractions&version=0.1.0-preview.11&prerelease
FractalDataWorks.UI.Web.Abstractions
Framework-agnostic web component abstractions with JavaScript interop capabilities. Provides a metadata-driven rendering system that works with Blazor, React, Vue, Angular, or any JavaScript framework.
Overview
This package extends the pure abstractions from FractalDataWorks.UI.Abstractions to add web-specific capabilities:
- Component Metadata - Serializable to JSON for JavaScript consumption
- JavaScript Interop - Generic interface for JS communication
- HTML Rendering - Framework-agnostic HTML generation
- Property Metadata - Describes form fields for any UI framework
- TypeCollections - RenderModes and ComponentTypes for type-safe UI patterns
Target Framework: netstandard2.0, net10.0 Dependencies:
- FractalDataWorks.UI.Abstractions
- FractalDataWorks.Collections
- System.Text.Json
Key Types
IWebComponent
From IWebComponent.cs:1-34:
/// <summary>
/// Base interface for web components that can export metadata.
/// </summary>
public interface IWebComponent
{
/// <summary>
/// Gets component metadata for serialization.
/// </summary>
ComponentMetadata GetMetadata();
/// <summary>
/// Serializes component to JSON.
/// </summary>
string ToJson();
/// <summary>
/// Renders component to HTML string.
/// </summary>
string RenderToHtml();
/// <summary>
/// Gets property metadata.
/// </summary>
IList<PropertyMetadata> GetPropertyMetadata();
/// <summary>
/// Gets child components.
/// </summary>
IList<IWebComponent> GetChildComponents();
}
WebComponentBase<TSelf, TModel>
From WebComponentBase.cs:1-77:
/// <summary>
/// CRTP-based web component that can render to ANY JavaScript framework.
/// Exports metadata that can be consumed by Blazor, React, Vue, Angular, etc.
/// </summary>
public abstract class WebComponentBase<TSelf, TModel> : ComponentBase<TSelf, TModel>, IWebComponent
where TSelf : WebComponentBase<TSelf, TModel>
{
private static readonly JsonSerializerOptions JsonOptions = new()
{
PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
WriteIndented = true
};
/// <summary>
/// JavaScript interop implementation (set by framework).
/// </summary>
public IJavaScriptInterop? JSInterop { get; set; }
/// <summary>
/// Render mode ID (reference to RenderModes TypeCollection).
/// </summary>
public int RenderModeId { get; set; } = 1; // Default: View
/// <summary>
/// Gets metadata that ANY JavaScript framework can understand.
/// </summary>
public new virtual ComponentMetadata GetMetadata()
{
return new ComponentMetadata
{
ComponentType = typeof(TSelf).Name,
ModelType = typeof(TModel).Name,
Properties = GetPropertyMetadata(),
ChildComponents = GetChildComponents()
.Select(c => c.GetMetadata())
.ToList(),
RenderModeId = RenderModeId
};
}
/// <summary>
/// Serializes component to JSON for JavaScript consumption.
/// </summary>
public string ToJson()
{
return JsonSerializer.Serialize(GetMetadata(), JsonOptions);
}
/// <summary>
/// Renders component to HTML string (framework-agnostic).
/// </summary>
public virtual string RenderToHtml()
{
var metadata = GetMetadata();
return HtmlRenderer.Render(metadata);
}
/// <summary>
/// Gets property metadata for all properties.
/// Must be implemented by derived classes.
/// </summary>
public abstract IList<PropertyMetadata> GetPropertyMetadata();
/// <summary>
/// Gets child components (for nested structures).
/// Must be implemented by derived classes.
/// </summary>
public abstract IList<IWebComponent> GetChildComponents();
}
ComponentMetadata
From ComponentMetadata.cs:1-46:
/// <summary>
/// Framework-agnostic component metadata that can be serialized to JSON.
/// Consumed by ANY JavaScript framework (Blazor, React, Vue, Angular, etc.).
/// </summary>
public class ComponentMetadata
{
/// <summary>
/// Type name of the component (e.g., "EmailConfigurationWebComponent").
/// </summary>
public string ComponentType { get; set; } = "";
/// <summary>
/// Type name of the model (e.g., "EmailConfiguration").
/// </summary>
public string ModelType { get; set; } = "";
/// <summary>
/// Property metadata for all properties.
/// </summary>
public IList<PropertyMetadata> Properties { get; set; } = new List<PropertyMetadata>();
/// <summary>
/// Child components (for nested structures).
/// </summary>
public IList<ComponentMetadata> ChildComponents { get; set; } = new List<ComponentMetadata>();
/// <summary>
/// Additional component-level attributes.
/// </summary>
public IDictionary<string, object> Attributes { get; set; } = new Dictionary<string, object>(StringComparer.Ordinal);
/// <summary>
/// Render mode ID (reference to RenderModes TypeCollection).
/// </summary>
public int RenderModeId { get; set; }
/// <summary>
/// Gets render mode name for serialization.
/// </summary>
public string RenderMode => RenderModes.ById(RenderModeId)?.Name ?? "View";
}
PropertyMetadata
From PropertyMetadata.cs:1-80:
/// <summary>
/// Describes a single property's UI representation.
/// </summary>
public class PropertyMetadata
{
/// <summary>
/// Property name (e.g., "SmtpHost").
/// </summary>
public string Name { get; set; } = "";
/// <summary>
/// C# type name (e.g., "string", "int").
/// </summary>
public string PropertyType { get; set; } = "";
/// <summary>
/// Component type ID (reference to ComponentTypes TypeCollection).
/// </summary>
public int ComponentTypeId { get; set; }
/// <summary>
/// Gets component type name for serialization.
/// </summary>
public string ComponentType => ComponentTypes.ById(ComponentTypeId)?.Name ?? "TextInput";
/// <summary>
/// Current property value.
/// </summary>
public object? Value { get; set; }
/// <summary>
/// Display label.
/// </summary>
public string? Label { get; set; }
/// <summary>
/// Help text / description.
/// </summary>
public string? HelpText { get; set; }
/// <summary>
/// Placeholder text for inputs.
/// </summary>
public string? Placeholder { get; set; }
/// <summary>
/// Is this field required?
/// </summary>
public bool Required { get; set; }
/// <summary>
/// Is this field read-only?
/// </summary>
public bool ReadOnly { get; set; }
/// <summary>
/// Display order (for sorting).
/// </summary>
public int DisplayOrder { get; set; }
/// <summary>
/// Display group (for grouping).
/// </summary>
public string? DisplayGroup { get; set; }
/// <summary>
/// Validation rules (pattern, min, max, etc.).
/// </summary>
public IDictionary<string, object> ValidationRules { get; set; } = new Dictionary<string, object>(StringComparer.Ordinal);
/// <summary>
/// Additional property-level attributes.
/// </summary>
public IDictionary<string, object> Attributes { get; set; } = new Dictionary<string, object>(StringComparer.Ordinal);
}
IJavaScriptInterop
From IJavaScriptInterop.cs:1-27:
/// <summary>
/// Generic JavaScript interop interface.
/// Implementations vary by framework (Blazor, Node.js, browser).
/// </summary>
public interface IJavaScriptInterop
{
/// <summary>
/// Invokes a JavaScript function and returns a value.
/// </summary>
/// <typeparam name="T">The type of value to return from the JavaScript function.</typeparam>
/// <param name="identifier">The JavaScript function identifier to invoke.</param>
/// <param name="args">Arguments to pass to the JavaScript function.</param>
/// <returns>A task that represents the asynchronous operation, containing the result of the JavaScript function.</returns>
Task<T> Invoke<T>(string identifier, params object[] args);
/// <summary>
/// Invokes a JavaScript function without returning a value.
/// </summary>
/// <param name="identifier">The JavaScript function identifier to invoke.</param>
/// <param name="args">Arguments to pass to the JavaScript function.</param>
/// <returns>A task that represents the asynchronous operation.</returns>
Task InvokeVoid(string identifier, params object[] args);
}
HtmlRenderer
From HtmlRenderer.cs:1-57:
/// <summary>
/// Renders component metadata to HTML string.
/// </summary>
public static class HtmlRenderer
{
/// <summary>
/// Renders component metadata to HTML.
/// </summary>
/// <param name="metadata">The component metadata to render.</param>
/// <returns>HTML string representation of the component.</returns>
public static string Render(ComponentMetadata metadata)
{
var html = new StringBuilder();
html.Append($"<div class=\"component {metadata.ComponentType.ToLowerInvariant()}\">");
html.Append($"{Environment.NewLine}");
foreach (var property in metadata.Properties.OrderBy(p => p.DisplayOrder))
{
html.Append($"{RenderProperty(property)}");
}
foreach (var child in metadata.ChildComponents)
{
html.Append($"{Render(child)}");
}
html.Append($"</div>{Environment.NewLine}");
return html.ToString();
}
private static string RenderProperty(PropertyMetadata property)
{
var componentType = ComponentTypes.ByName(property.ComponentType);
if (componentType == null)
{
return RenderGenericInput(property);
}
// Use TypeCollection to determine rendering
return componentType.Id switch
{
1 => RenderTextInput(property), // TextInput
2 => RenderNumericInput(property), // NumericInput
3 => RenderTextArea(property), // TextArea
4 => RenderSwitch(property), // Switch
5 => RenderDatePicker(property), // DatePicker
10 => RenderDropdown(property), // Dropdown
_ => RenderGenericInput(property)
};
}
// ... additional private rendering methods
}
TypeCollections
RenderModes
From RenderModes.cs:1-89:
/// <summary>
/// Collection of render modes for web components.
/// </summary>
[TypeCollection(typeof(RenderModeBase), typeof(IRenderMode), typeof(RenderModes))]
public abstract partial class RenderModes : TypeCollectionBase<RenderModeBase, IRenderMode>
{
}
/// <summary>
/// Base class for render mode types.
/// </summary>
public abstract class RenderModeBase : TypeOptionBase<int, RenderModeBase>, IRenderMode
{
protected RenderModeBase(int id, string name, string displayName, string description)
: base(id, name, $"RenderModes:{name}", displayName, description, "RenderModes")
{
}
}
// Available render modes:
// ViewRenderMode (Id=1) - Read-only display
// EditRenderMode (Id=2) - Editable input
// CreateRenderMode (Id=3) - Create new items
// BothRenderMode (Id=4) - View and edit simultaneously
ComponentTypes
From ComponentTypes.cs:1-225:
/// <summary>
/// Collection of UI component types.
/// </summary>
[TypeCollection(typeof(ComponentTypeBase), typeof(IComponentType), typeof(ComponentTypes))]
public abstract partial class ComponentTypes : TypeCollectionBase<ComponentTypeBase, IComponentType>
{
}
/// <summary>
/// Base class for component types.
/// </summary>
public abstract class ComponentTypeBase : TypeOptionBase<int, ComponentTypeBase>, IComponentType
{
public new string Category { get; }
protected ComponentTypeBase(int id, string name, string displayName, string category, string description)
: base(id, name, $"ComponentTypes:{name}", displayName, description, category)
{
Category = category;
}
}
// Available component types:
// Input: TextInput(1), NumericInput(2), TextArea(3), Switch(4), DatePicker(5), DateTimePicker(6), FileUpload(16)
// Selection: Dropdown(7), MultiSelect(8), RadioGroup(9), CheckboxList(10)
// Complex: Collection(11), TypeCollectionDropdown(12), JsonEditor(15)
Architecture
Framework Agnostic Design
The same component metadata works with:
- Blazor (via RenderTreeBuilder)
- React (via JSInterop and React components)
- Vue (via JSInterop and Vue components)
- Angular (via JSInterop and Angular components)
- Vanilla JavaScript (via HTML string rendering)
TypeCollection Integration
Components use TypeCollection IDs rather than string constants:
RenderModeIdreferencesRenderModesTypeCollectionComponentTypeIdreferencesComponentTypesTypeCollection
This enables type-safe lookups via RenderModes.ById() and ComponentTypes.ByName().
Best Practices
- Keep Metadata Serializable - Only use JSON-compatible types in metadata
- Use TypeCollection IDs - Reference
ComponentTypeIdandRenderModeIdrather than strings - Implement Abstract Methods - Derived classes must implement
GetPropertyMetadata()andGetChildComponents() - Framework Independence - Don't couple to specific JavaScript frameworks
- Validation in Metadata - Use the
ValidationRulesdictionary for client-side validation - Ordering Properties - Use
DisplayOrderto control property rendering sequence - Grouping Properties - Use
DisplayGroupto organize related properties
Dependencies
- FractalDataWorks.UI.Abstractions - Pure CRTP base classes
- FractalDataWorks.Collections - TypeCollection infrastructure
- System.Text.Json - JSON serialization
Related Packages
- FractalDataWorks.UI.Abstractions - Pure CRTP base classes
- FractalDataWorks.Collections - TypeCollection framework
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net5.0 was computed. net5.0-windows was computed. net6.0 was computed. net6.0-android was computed. net6.0-ios was computed. net6.0-maccatalyst was computed. net6.0-macos was computed. net6.0-tvos was computed. net6.0-windows was computed. net7.0 was computed. net7.0-android was computed. net7.0-ios was computed. net7.0-maccatalyst was computed. net7.0-macos was computed. net7.0-tvos was computed. net7.0-windows was computed. net8.0 was computed. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. net9.0 was computed. net9.0-android was computed. net9.0-browser was computed. net9.0-ios was computed. net9.0-maccatalyst was computed. net9.0-macos was computed. net9.0-tvos was computed. net9.0-windows was computed. net10.0 was computed. 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. |
| .NET Core | netcoreapp2.0 was computed. netcoreapp2.1 was computed. netcoreapp2.2 was computed. netcoreapp3.0 was computed. netcoreapp3.1 was computed. |
| .NET Standard | netstandard2.0 is compatible. netstandard2.1 was computed. |
| .NET Framework | net461 was computed. net462 was computed. net463 was computed. net47 was computed. net471 was computed. net472 was computed. net48 was computed. net481 was computed. |
| MonoAndroid | monoandroid was computed. |
| MonoMac | monomac was computed. |
| MonoTouch | monotouch was computed. |
| Tizen | tizen40 was computed. tizen60 was computed. |
| Xamarin.iOS | xamarinios was computed. |
| Xamarin.Mac | xamarinmac was computed. |
| Xamarin.TVOS | xamarintvos was computed. |
| Xamarin.WatchOS | xamarinwatchos was computed. |
-
.NETStandard 2.0
- FractalDataWorks.Collections (>= 0.1.0-preview.11)
- FractalDataWorks.UI.Abstractions (>= 0.1.0-preview.11)
- System.Collections.Immutable (>= 10.0.1)
- System.Text.Json (>= 10.0.0)
NuGet packages (1)
Showing the top 1 NuGet packages that depend on FractalDataWorks.UI.Web.Abstractions:
| Package | Downloads |
|---|---|
|
FractalDataWorks.UI.Components.Blazor
Development tools and utilities for the FractalDataWorks ecosystem. Build: |
GitHub repositories
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated |
|---|---|---|
| 0.1.0-preview.11 | 3 | 1/12/2026 |
| 0.1.0-preview.10 | 14 | 1/12/2026 |
| 0.1.0-preview.9 | 34 | 1/9/2026 |
| 0.1.0-preview.7 | 98 | 1/7/2026 |