From 51c75546fbaa322a2606f20af793a2b8ccd68bce Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?kusutori=E3=82=AF=E3=82=B9=E3=81=A8=E3=82=8A?=
<100983934+kusutori@users.noreply.github.com>
Date: Wed, 14 Oct 2026 21:36:11 +0800
Subject: [PATCH 1/3] Add typed ResourceBuilder overloads for native styling
values
---
docs/_pipeline/templates/styling.md.dt | 13 ++-
docs/guide/styling.md | 13 ++-
.../reactor-dsl/references/reactor.api.txt | 6 +
skills/reactor.api.txt | 6 +
src/Reactor/Elements/ResourceBuilder.cs | 51 ++++++++-
.../Fixtures/TypedResourceOverrideFixtures.cs | 105 ++++++++++++++++++
.../SelfTest/SelfTestFixtureRegistry.cs | 4 +
.../Reactor.Tests/LightweightStylingTests.cs | 95 ++++++++++++++++
8 files changed, 285 insertions(+), 8 deletions(-)
create mode 100644 tests/Reactor.AppTests.Host/SelfTest/Fixtures/TypedResourceOverrideFixtures.cs
diff --git a/docs/_pipeline/templates/styling.md.dt b/docs/_pipeline/templates/styling.md.dt
index 4ad626662..7ce27fabb 100644
--- a/docs/_pipeline/templates/styling.md.dt
+++ b/docs/_pipeline/templates/styling.md.dt
@@ -206,9 +206,16 @@ pressed, disabled) automatically respect your overrides:

-`ResourceBuilder` supports `.Set(key, ThemeRef)` for theme-reactive
-overrides, `.Set(key, string)` for hex colors, `.Set(key, double)` for
-numeric values, and `.Set(key, CornerRadius)` for corner radius.
+`ResourceBuilder.Set` has explicit overloads for `ThemeRef`, `Brush`,
+color strings, `double`, `CornerRadius`, `Thickness`, `FontWeight`,
+`FontFamily`, `bool`, `Color`, and `GridLength`. Use `Thickness` for padding
+or border thickness, and `FontWeight` / `FontFamily` for typography resources.
+Literal values retain their types; `ThemeRef` overrides re-resolve on theme changes.
+
+The `Color` overload stores a color value, not a brush. The string overload
+still parses a hex or named color into a brush; it does not store arbitrary
+text. Integer literals continue to select the `double` overload, so pass the
+value type expected by the WinUI resource key rather than relying on conversion.
Overrides cascade to child elements through WinUI's resource dictionary
hierarchy.
diff --git a/docs/guide/styling.md b/docs/guide/styling.md
index fa5bf8f82..3160d1fea 100644
--- a/docs/guide/styling.md
+++ b/docs/guide/styling.md
@@ -353,9 +353,16 @@ class LightweightStylingExample : Component

-`ResourceBuilder` supports `.Set(key, ThemeRef)` for theme-reactive
-overrides, `.Set(key, string)` for hex colors, `.Set(key, double)` for
-numeric values, and `.Set(key, CornerRadius)` for corner radius.
+`ResourceBuilder.Set` has explicit overloads for `ThemeRef`, `Brush`,
+color strings, `double`, `CornerRadius`, `Thickness`, `FontWeight`,
+`FontFamily`, `bool`, `Color`, and `GridLength`. Use `Thickness` for padding
+or border thickness, and `FontWeight` / `FontFamily` for typography resources.
+Literal values retain their types; `ThemeRef` overrides re-resolve on theme changes.
+
+The `Color` overload stores a color value, not a brush. The string overload
+still parses a hex or named color into a brush; it does not store arbitrary
+text. Integer literals continue to select the `double` overload, so pass the
+value type expected by the WinUI resource key rather than relying on conversion.
Overrides cascade to child elements through WinUI's resource dictionary
hierarchy.
diff --git a/plugins/reactor/skills/reactor-dsl/references/reactor.api.txt b/plugins/reactor/skills/reactor-dsl/references/reactor.api.txt
index fbf6b92ce..fb3c99790 100644
--- a/plugins/reactor/skills/reactor-dsl/references/reactor.api.txt
+++ b/plugins/reactor/skills/reactor-dsl/references/reactor.api.txt
@@ -4901,8 +4901,14 @@ ToString() → string
### class ResourceBuilder
new()
Set(string key, Brush brush) → ResourceBuilder
+Set(string key, Color value) → ResourceBuilder
Set(string key, CornerRadius value) → ResourceBuilder
+Set(string key, FontFamily value) → ResourceBuilder
+Set(string key, FontWeight value) → ResourceBuilder
+Set(string key, GridLength value) → ResourceBuilder
Set(string key, ThemeRef themeRef) → ResourceBuilder
+Set(string key, Thickness value) → ResourceBuilder
+Set(string key, bool value) → ResourceBuilder
Set(string key, double value) → ResourceBuilder
Set(string key, string color) → ResourceBuilder
diff --git a/skills/reactor.api.txt b/skills/reactor.api.txt
index fbf6b92ce..fb3c99790 100644
--- a/skills/reactor.api.txt
+++ b/skills/reactor.api.txt
@@ -4901,8 +4901,14 @@ ToString() → string
### class ResourceBuilder
new()
Set(string key, Brush brush) → ResourceBuilder
+Set(string key, Color value) → ResourceBuilder
Set(string key, CornerRadius value) → ResourceBuilder
+Set(string key, FontFamily value) → ResourceBuilder
+Set(string key, FontWeight value) → ResourceBuilder
+Set(string key, GridLength value) → ResourceBuilder
Set(string key, ThemeRef themeRef) → ResourceBuilder
+Set(string key, Thickness value) → ResourceBuilder
+Set(string key, bool value) → ResourceBuilder
Set(string key, double value) → ResourceBuilder
Set(string key, string color) → ResourceBuilder
diff --git a/src/Reactor/Elements/ResourceBuilder.cs b/src/Reactor/Elements/ResourceBuilder.cs
index c45a049db..1477be76f 100644
--- a/src/Reactor/Elements/ResourceBuilder.cs
+++ b/src/Reactor/Elements/ResourceBuilder.cs
@@ -1,12 +1,14 @@
using Microsoft.UI.Reactor.Core;
using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Media;
+using Windows.UI;
+using Windows.UI.Text;
namespace Microsoft.UI.Reactor.Elements;
///
/// Immutable snapshot of per-control resource overrides built by .
-/// Contains both literal values (colors, doubles, corner radii) and theme-reactive
+/// Contains both literal resource values and theme-reactive
/// entries that are re-resolved on theme change.
///
public sealed record ResourceOverrides(
@@ -64,7 +66,7 @@ public ResourceBuilder Set(string key, ThemeRef themeRef)
return this;
}
- /// Sets a numeric resource override (e.g., ButtonBorderThemeThickness).
+ /// Sets a numeric resource override (e.g., BreadcrumbBarItemThemeFontSize).
public ResourceBuilder Set(string key, double value)
{
_literals[key] = value;
@@ -78,6 +80,51 @@ public ResourceBuilder Set(string key, CornerRadius value)
return this;
}
+ /// Sets a thickness resource override (e.g., BreadcrumbBarChevronPadding).
+ public ResourceBuilder Set(string key, Thickness value)
+ {
+ _literals[key] = value;
+ return this;
+ }
+
+ /// Sets a font weight resource override (e.g., BreadcrumbBarItemFontWeight).
+ public ResourceBuilder Set(string key, FontWeight value)
+ {
+ _literals[key] = value;
+ return this;
+ }
+
+ /// Sets a font family resource override (e.g., ContentControlThemeFontFamily).
+ public ResourceBuilder Set(string key, FontFamily value)
+ {
+ _literals[key] = value;
+ return this;
+ }
+
+ /// Sets a Boolean resource override (e.g., GridViewItemSelectionCheckMarkVisualEnabled).
+ public ResourceBuilder Set(string key, bool value)
+ {
+ _literals[key] = value;
+ return this;
+ }
+
+ ///
+ /// Sets a literal color resource override, not a brush. Use the string or
+ /// overload for resources that expect a brush.
+ ///
+ public ResourceBuilder Set(string key, Color value)
+ {
+ _literals[key] = value;
+ return this;
+ }
+
+ /// Sets a grid length resource override (e.g., ContentDialogButtonSpacing).
+ public ResourceBuilder Set(string key, GridLength value)
+ {
+ _literals[key] = value;
+ return this;
+ }
+
/// Builds an immutable snapshot.
internal ResourceOverrides Build()
{
diff --git a/tests/Reactor.AppTests.Host/SelfTest/Fixtures/TypedResourceOverrideFixtures.cs b/tests/Reactor.AppTests.Host/SelfTest/Fixtures/TypedResourceOverrideFixtures.cs
new file mode 100644
index 000000000..857948ed3
--- /dev/null
+++ b/tests/Reactor.AppTests.Host/SelfTest/Fixtures/TypedResourceOverrideFixtures.cs
@@ -0,0 +1,105 @@
+using Microsoft.UI.Reactor.Core;
+using Microsoft.UI.Xaml;
+using Microsoft.UI.Xaml.Controls;
+using Microsoft.UI.Xaml.Media;
+using static Microsoft.UI.Reactor.Factories;
+
+namespace Microsoft.UI.Reactor.AppTests.Host.SelfTest.Fixtures;
+
+internal static class TypedResourceOverrideFixtures
+{
+ internal sealed class MountUpdateAndRemoval(Harness h) : SelfTestFixtureBase(h)
+ {
+ public override async Task RunAsync()
+ {
+ var family = new FontFamily("Consolas");
+ var updatedFamily = new FontFamily("Segoe UI");
+ Action? setPhase = null;
+ var host = H.CreateHost();
+ host.Mount(ctx =>
+ {
+ var (phase, update) = ctx.UseState(0);
+ setPhase = update;
+ var element = Button("typed resource overrides");
+ if (phase < 2)
+ element = element.Resources(r => r
+ .Set("TypedPadding", Padding(phase))
+ .Set("TypedWeight", new global::Windows.UI.Text.FontWeight((ushort)(phase == 0 ? 700 : 400)))
+ .Set("TypedFont", phase == 0 ? family : updatedFamily)
+ .Set("TypedBoolean", phase == 0)
+ .Set("TypedColor", Color(phase))
+ .Set("TypedGridLength", Length(phase))
+ .Set("TypedBrush", "#123456"));
+ return element;
+ });
+
+ await Harness.Render();
+ var control = H.FindControl