diff --git a/Documentation/api-filter.yml b/Documentation/api-filter.yml
index 41aa629..ddfd856 100644
--- a/Documentation/api-filter.yml
+++ b/Documentation/api-filter.yml
@@ -15,6 +15,9 @@ apiRules:
- exclude:
uidRegex: ^ActiproSoftware\.Licensing
type: Namespace
+- exclude:
+ uidRegex: ^ActiproSoftware\.Tests
+ type: Namespace
- exclude:
uidRegex: ^ActiproSoftware\..*\.Internal
type: Namespace
diff --git a/Documentation/topics/shared/media.md b/Documentation/topics/shared/media.md
index 4fda58e..e4da240 100644
--- a/Documentation/topics/shared/media.md
+++ b/Documentation/topics/shared/media.md
@@ -5,29 +5,37 @@ order: 9
---
# Media
-The [ActiproSoftware.UI.Avalonia.Media](xref:@ActiproUIRoot.Media) namespace defines a [UIColor](xref:@ActiproUIRoot.Media.UIColor) structure for working with colors.
+The [ActiproSoftware.UI.Avalonia.Media](xref:@ActiproUIRoot.Media) namespace defines a [UIColor](xref:@ActiproUIRoot.Media.UIColor) structure for working with colors and an extension method to easily convert `Avalonia.Media.Color` to a [UIColor](xref:@ActiproUIRoot.Media.UIColor).
## UIColor Structure
-The [UIColor](xref:@ActiproUIRoot.Media.UIColor) structure provides an enhanced representation of a color that supports the RGB, HSL, and HSV color models, conversion between models, and numerous other helper methods. Static methods on the structure are used to create instances of the structure based on the supported models.
+The [UIColor](xref:@ActiproUIRoot.Media.UIColor) structure provides an enhanced representation of a color that supports the RGB, HSL, HSV, OKLAB, and OKLCH color models, conversion between models, and numerous other helper methods. Static methods on the structure are used to create instances of the structure based on the supported models.
These instance members are found in the structure:
| Member | Description |
|-----|-----|
-| [Alpha](xref:@ActiproUIRoot.Media.UIColor.Alpha) Property | Gets or sets the alpha component of the color, which is a percentage value in the range `0.0` to `1.0`. |
-| [HslHue](xref:@ActiproUIRoot.Media.UIColor.HslHue) Property | Gets or sets the HSL hue component of the color, which is a color wheel degree value in the range `0` to `360`. |
-| [HslLightness](xref:@ActiproUIRoot.Media.UIColor.HslLightness) Property | Gets or sets the HSL lightness component of the color, which is a percentage value in the range `0.0` to `1.0`. |
-| [HslSaturation](xref:@ActiproUIRoot.Media.UIColor.HslSaturation) Property | Gets or sets the HSL saturation component of the color, which is a percentage value in the range `0.0` to `1.0`. |
-| [HsvHue](xref:@ActiproUIRoot.Media.UIColor.HsvHue) Property | Gets or sets the HSV hue component of the color, which is a percentage value in the range `0.0` to `1.0`. |
-| [HsvSaturation](xref:@ActiproUIRoot.Media.UIColor.HsvSaturation) Property | Gets or sets the HSV saturation component of the color, which is a percentage value in the range `0.0` to `1.0`. |
-| [HsvValue](xref:@ActiproUIRoot.Media.UIColor.HsvValue) Property | Gets or sets the HSV value (brightness) component of the color, which is a percentage value in the range `0.0` to `1.0`. |
+| [Alpha](xref:@ActiproUIRoot.Media.UIColor.Alpha) Property | The alpha component of the color, which is a percentage value in the range `0.0` to `1.0`. |
+| [HslHue](xref:@ActiproUIRoot.Media.UIColor.HslHue) Property | The HSL hue component of the color, which is a color wheel degree value in the range `0` to `360`. |
+| [HslLightness](xref:@ActiproUIRoot.Media.UIColor.HslLightness) Property | The HSL lightness component of the color, which is a percentage value in the range `0.0` to `1.0`. |
+| [HslSaturation](xref:@ActiproUIRoot.Media.UIColor.HslSaturation) Property | The HSL saturation component of the color, which is a percentage value in the range `0.0` to `1.0`. |
+| [HsvHue](xref:@ActiproUIRoot.Media.UIColor.HsvHue) Property | The HSV hue component of the color, which is a percentage value in the range `0.0` to `1.0`. |
+| [HsvSaturation](xref:@ActiproUIRoot.Media.UIColor.HsvSaturation) Property | The HSV saturation component of the color, which is a percentage value in the range `0.0` to `1.0`. |
+| [HsvValue](xref:@ActiproUIRoot.Media.UIColor.HsvValue) Property | The HSV value (brightness) component of the color, which is a percentage value in the range `0.0` to `1.0`. |
| [IsDark](xref:@ActiproUIRoot.Media.UIColor.IsDark) Property | Gets whether the color is a dark color. |
| [IsLight](xref:@ActiproUIRoot.Media.UIColor.IsLight) Property | Gets whether the color is a light color. |
-| [RbgAlpha](xref:@ActiproUIRoot.Media.UIColor.RgbAlpha) Property | Gets or sets the RGB alpha component of the color, which is a byte value in the range `0` to `255`. |
-| [RbgBlue](xref:@ActiproUIRoot.Media.UIColor.RgbBlue) Property | Gets or sets the RGB blue component of the color, which is a byte value in the range `0` to `255`. |
-| [RbgGreen](xref:@ActiproUIRoot.Media.UIColor.RgbGreen) Property | Gets or sets the RGB green component of the color, which is a byte value in the range `0` to `255`. |
-| [RbgRed](xref:@ActiproUIRoot.Media.UIColor.RgbRed) Property | Gets or sets the RGB red component of the color, which is a byte value in the range `0` to `255`. |
+| [OklabAChromaticity](xref:@ActiproUIRoot.Media.UIColor.OklabAChromaticity) Property | The OKLAB A chromaticity component of the color, which is a value in the range `-0.4`..`0.4`. |
+| [OklabBChromaticity](xref:@ActiproUIRoot.Media.UIColor.OklabBChromaticity) Property | The OKLAB B chromaticity component of the color, which is a value in the range `-0.4`..`0.4`. |
+| [OklabLightness](xref:@ActiproUIRoot.Media.UIColor.OklabLightness) Property | The OKLAB lightness component of the color, which is a percentage value in the range `0.0` to `1.0`. |
+| [OklchChroma](xref:@ActiproUIRoot.Media.UIColor.OklchChroma) Property | The OKLCH chroma (saturation) component of the color, which is a value in the range `0.0`..`0.4`. |
+| [OklchHue](xref:@ActiproUIRoot.Media.UIColor.OklchHue) Property | The OKLCH hue component of the color, which is a color wheel degree value in the range `0`..`360`. |
+| [OklchLightness](xref:@ActiproUIRoot.Media.UIColor.OklchLightness) Property | The OKLCH lightness component of the color, which is a percentage value in the range `0.0` to `1.0`. |
+| [RbgAlpha](xref:@ActiproUIRoot.Media.UIColor.RgbAlpha) Property | The RGB alpha component of the color, which is a byte value in the range `0` to `255`. |
+| [RbgBlue](xref:@ActiproUIRoot.Media.UIColor.RgbBlue) Property | The RGB blue component of the color, which is a byte value in the range `0` to `255`. |
+| [RbgGreen](xref:@ActiproUIRoot.Media.UIColor.RgbGreen) Property | The RGB green component of the color, which is a byte value in the range `0` to `255`. |
+| [RbgRed](xref:@ActiproUIRoot.Media.UIColor.RgbRed) Property | The RGB red component of the color, which is a byte value in the range `0` to `255`. |
+| [ToChromaticAdaptation](xref:@ActiproUIRoot.Media.UIColor.ToChromaticAdaptation*) Method | Uses chromatic adaptation to create a new [UIColor](xref:@ActiproUIRoot.Media.UIColor) that renders clearly on the specified background color. Chromatic adaptation is commonly used to adapt a color that was intended for use with light backgrounds to render properly on dark backgrounds. |
+| [ToGrayscale](xref:@ActiproUIRoot.Media.UIColor.ToGrayscale*) Method | Creates a new [UIColor](xref:@ActiproUIRoot.Media.UIColor) that is a grayscale transformation of the specified color. |
| [ToHexString](xref:@ActiproUIRoot.Media.UIColor.ToHexString*) Method | Converts the color value to an RGB hexadecimal string (e.g., `"#ff00ff"`, `"#80ff00ff"`). |
| [ToHsl](xref:@ActiproUIRoot.Media.UIColor.ToHsl*) Method | Converts the color value to an `HslColor` instance that represents the color in the HSL (hue, saturation, and lightness) color model. |
| [ToHsv](xref:@ActiproUIRoot.Media.UIColor.ToHsv*) Method | Converts the color value to an `HsvColor` instance that represents the color in the HSV (hue, saturation, and value) color model. |
@@ -40,9 +48,25 @@ These static members are found in the structure:
| Member | Description |
|-----|-----|
-| [FromHsl](xref:@ActiproUIRoot.Media.UIColor.FromHsl*) Method | Creates a `UIColor` instance from the specified HSL (hue, saturation, lightness, and optional alpha) components or `HslColor` instance. |
-| [FromHsv](xref:@ActiproUIRoot.Media.UIColor.FromHsv*) Method | Creates a `UIColor` instance from the specified HSV (hue, saturation, value, and optional alpha) components or `HsvColor` instance. |
+| [FromHsl](xref:@ActiproUIRoot.Media.UIColor.FromHsl*) Method | Creates a `UIColor` instance from the specified HSL (hue, saturation, and lightness) and optional alpha components, or `HslColor` instance. |
+| [FromHsv](xref:@ActiproUIRoot.Media.UIColor.FromHsv*) Method | Creates a `UIColor` instance from the specified HSV (hue, saturation, and value) and optional alpha components, or `HsvColor` instance. |
| [FromMix](xref:@ActiproUIRoot.Media.UIColor.FromMix*) Method | Creates a `UIColor` instance that is the specified percentage between the value of two `Color` objects. |
-| [FromRgb](xref:@ActiproUIRoot.Media.UIColor.FromRgb*) Method | Creates a `UIColor` instance from the specified RGB (red, green, blue, and optional alpha) components or `Color` instance. |
+| [FromOklab](xref:@ActiproUIRoot.Media.UIColor.FromOklab*) Method | Creates a `UIColor` instance from the specified OKLAB (lightness, A, and B) and optional alpha components. |
+| [FromOklch](xref:@ActiproUIRoot.Media.UIColor.FromOklch*) Method | Creates a `UIColor` instance from the specified OKLCH (lightness, chroma, and hue) and optional alpha components. |
+| [FromRgb](xref:@ActiproUIRoot.Media.UIColor.FromRgb*) Method | Creates a `UIColor` instance from the specified RGB (red, green, and blue) and optional alpha components, or `Color` instance. |
| [Parse](xref:@ActiproUIRoot.Media.UIColor.Parse*) Method | Creates a `UIColor` instance from the specified color name, RGB hexadecimal string, or any other color string supported by `Color.Parse`. |
-| [TryParse](xref:@ActiproUIRoot.Media.UIColor.Parse*) Method | Tries to creates a `UIColor` instance from the specified color name, RGB hexadecimal string, or any other color string supported by `Color.Parse`. |
\ No newline at end of file
+| [TryParse](xref:@ActiproUIRoot.Media.UIColor.Parse*) Method | Tries to creates a `UIColor` instance from the specified color name, RGB hexadecimal string, or any other color string supported by `Color.Parse`. |
+
+> [!TIP]
+> [UIColor](xref:@ActiproUIRoot.Media.UIColor) defines several implicit cast overloads to easily convert to/from [UIColor](xref:@ActiproUIRoot.Media.UIColor) and the Avalonia types for `Color`, `HslColor`, and `HsvColor`.
+
+## Color Extensions
+
+The following extension methods to `Avalonia.Media.Color` are defined on [ColorExtensions](xref:@ActiproUIRoot.Media.ColorExtensions):
+
+| Member | Description |
+|-----|-----|
+| [ToUIColor](xref:@ActiproUIRoot.Media.ColorExtensions.ToUIColor*) Method | Creates a new [UIColor](xref:@ActiproUIRoot.Media.UIColor) initialized from the `Color` for easily accessing the additional capabilities of [UIColor](xref:@ActiproUIRoot.Media.UIColor). |
+
+> [!IMPORTANT]
+> The [ActiproSoftware.UI.Avalonia.Media](xref:@ActiproUIRoot.Media) namespace must be imported with a `using` statement to access the extensions.
\ No newline at end of file
diff --git a/Documentation/topics/themes/getting-started.md b/Documentation/topics/themes/getting-started.md
index 37c4043..cc11ba0 100644
--- a/Documentation/topics/themes/getting-started.md
+++ b/Documentation/topics/themes/getting-started.md
@@ -174,6 +174,9 @@ When using all controls:
```
+> [!WARNING]
+> The `ModernTheme.Includes` property dynamically includes `Styles` instances that apply control themes for various product assemblies. While this simplifies the Application XAML, it can lead to a runtime exception when executing an application that uses the `PublishAot` project setting for Native AOT (Ahead-of-Time) support and hasn't been published with `dotnet publish` or an IDE's equivalent publish feature. See the [Troubleshooting](../troubleshooting.md) topic for details on how to statically include appropriate `Styles` instances, avoiding AOT errors.
+
### Native Control Themes Setting
Native Avalonia controls must have themes applied or else an application window will render without most or all content being visible. Avalonia ships with the *Simple* and *Fluent* themes as built-in options. Actipro's theme also defines control themes for all native Avalonia controls and can be used in place of the *Simple*, *Fluent*, or other themes.
diff --git a/Documentation/topics/themes/native-control-themes.md b/Documentation/topics/themes/native-control-themes.md
index d9c5916..9f876a2 100644
--- a/Documentation/topics/themes/native-control-themes.md
+++ b/Documentation/topics/themes/native-control-themes.md
@@ -183,6 +183,8 @@ These style class names trigger special behaviors:
- [ButtonSpinnerOutline](xref:@ActiproUIRoot.Themes.ControlThemeKind.ButtonSpinnerOutline) (`theme-outline`) - Has an outline appearance.
- [ButtonSpinnerSoft](xref:@ActiproUIRoot.Themes.ControlThemeKind.ButtonSpinnerSoft) (`theme-soft`) - Has a soft fill appearance.
+Set the [ThemeProperties](xref:@ActiproUIRoot.Themes.ThemeProperties).[SpinnerHasHorizontalOrientation](xref:@ActiproUIRoot.Themes.ThemeProperties.SpinnerHasHorizontalOrientationProperty) attached property on a `ButtonSpinner` to `true` to arrange spinner buttons horizontally instead of vertically. Horizontal arrangement is better for touch-friendly user interfaces since each button gets twice the amount of surface area. [Theme Definitions](theme-definitions.md) also provide a global default value for this attached property that can be altered.
+
The following additional control theme is available for the `Button` used by the default control theme:
- [SpinnerButton](xref:@ActiproUIRoot.Themes.ControlThemeKind.SpinnerButton)
@@ -243,6 +245,8 @@ The following additional control theme is used by the default control theme:
- [NumericUpDownOutline](xref:@ActiproUIRoot.Themes.ControlThemeKind.NumericUpDownOutline) (`theme-outline`) - Has an outline appearance.
- [NumericUpDownSoft](xref:@ActiproUIRoot.Themes.ControlThemeKind.NumericUpDownSoft) (`theme-soft`) - Has a soft fill appearance.
+Set the [ThemeProperties](xref:@ActiproUIRoot.Themes.ThemeProperties).[SpinnerHasHorizontalOrientation](xref:@ActiproUIRoot.Themes.ThemeProperties.SpinnerHasHorizontalOrientationProperty) attached property on a `NumericUpDown` to `true` to arrange spinner buttons horizontally instead of vertically. Horizontal arrangement is better for touch-friendly user interfaces since each button gets twice the amount of surface area. [Theme Definitions](theme-definitions.md) also provide a global default value for this attached property that can be altered.
+
#### TextBox Type
![Screenshot](images/text-box-themes.png)
diff --git a/Documentation/topics/themes/theme-definitions.md b/Documentation/topics/themes/theme-definitions.md
index ce6bb4b..bc2c8eb 100644
--- a/Documentation/topics/themes/theme-definitions.md
+++ b/Documentation/topics/themes/theme-definitions.md
@@ -85,6 +85,7 @@ Color ramp name properties should be set to [Hue](xref:@ActiproUIRoot.Themes.Gen
|-----|-----|
| [ButtonAppearanceKind](xref:@ActiproUIRoot.Themes.Generation.ThemeDefinition.ButtonAppearanceKind) | The [ButtonAppearanceKind](xref:@ActiproUIRoot.Themes.Generation.ButtonAppearanceKind) that indicates the default appearance for various button controls (e.g., `Button`, `SplitButton`). |
| [EditAppearanceKind](xref:@ActiproUIRoot.Themes.Generation.ThemeDefinition.EditAppearanceKind) | The [EditAppearanceKind](xref:@ActiproUIRoot.Themes.Generation.EditAppearanceKind) that indicates the default appearance for various edit controls (e.g., `ComboBox`, `TextBox`). |
+| [SpinnerHasHorizontalOrientation](xref:@ActiproUIRoot.Themes.Generation.ThemeDefinition.SpinnerHasHorizontalOrientation) | Whether to arrange `ButtonSpinner` buttons horizontally.
| [TabAppearanceKind](xref:@ActiproUIRoot.Themes.Generation.ThemeDefinition.TabAppearanceKind) | The [TabAppearanceKind](xref:@ActiproUIRoot.Themes.Generation.TabAppearanceKind) that indicates the default appearance for various tab controls (e.g., `TabControl`). |
## Custom Theme Generators
diff --git a/Documentation/topics/themes/user-interface-density.md b/Documentation/topics/themes/user-interface-density.md
index 06a0d03..3d89e91 100644
--- a/Documentation/topics/themes/user-interface-density.md
+++ b/Documentation/topics/themes/user-interface-density.md
@@ -74,6 +74,9 @@ if (ModernTheme.TryGetCurrent(out var modernTheme) && (modernTheme.Definition is
_ => 14.0, // Normal, Spacious
};
+ // Arrange spinner buttons horizontally in Spacious density
+ definition.SpinnerHasHorizontalOrientation = (density == UserInterfaceDensity.Spacious);
+
// Set the new UI density
modernTheme.Definition.UserInterfaceDensity = newDensity;
diff --git a/Documentation/topics/troubleshooting.md b/Documentation/topics/troubleshooting.md
index 0220d77..7490762 100644
--- a/Documentation/topics/troubleshooting.md
+++ b/Documentation/topics/troubleshooting.md
@@ -42,6 +42,46 @@ It is very important to note that the data binding errors are NOT problems in ou
So just to reiterate, the data binding error messages are not problems with our code, and are simple warnings due to data bindings trying to resolve themselves before the targets' visual trees are created. You may safely ignore these error messages.
+## Native AOT (Ahead-of-Time) Generates "No precompiled XAML found for avares:..." Error in Debugger
+
+Applications that want to take advantage of Native AOT add the `