feat(Themes): introduce ColorSliderTrackButton and ComboBoxTextBox with associated themes

This commit is contained in:
chinboy
2026-08-03 10:47:13 +08:00
parent 9d26f10fa0
commit fcfdbf714d
9 changed files with 118 additions and 67 deletions
@@ -0,0 +1,7 @@
using Avalonia.Controls;
namespace AtomUI.Desktop.Controls;
internal class ColorSliderTrackButton : RepeatButton
{
}
@@ -29,34 +29,10 @@
Value="{TemplateBinding Value, Mode=TwoWay}"
ClipToBounds="False">
<atom:ColorPickerSliderTrack.DecreaseButton>
<RepeatButton Name="PART_DecreaseButton"
Background="Transparent"
Focusable="False"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch">
<RepeatButton.Template>
<ControlTemplate>
<Border Name="FocusTarget"
Background="Transparent"
Margin="0,-10" />
</ControlTemplate>
</RepeatButton.Template>
</RepeatButton>
<atom:ColorSliderTrackButton Name="PART_DecreaseButton" />
</atom:ColorPickerSliderTrack.DecreaseButton>
<atom:ColorPickerSliderTrack.IncreaseButton>
<RepeatButton Name="PART_IncreaseButton"
Background="Transparent"
Focusable="False"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch">
<RepeatButton.Template>
<ControlTemplate>
<Border Name="FocusTarget"
Background="Transparent"
Margin="0,-10" />
</ControlTemplate>
</RepeatButton.Template>
</RepeatButton>
<atom:ColorSliderTrackButton Name="PART_IncreaseButton" />
</atom:ColorPickerSliderTrack.IncreaseButton>
<atom:ColorSliderThumb Name="ColorSliderThumb"
Margin="0"
@@ -0,0 +1,19 @@
<ControlTheme xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:atom="https://atomui.net"
x:Class="AtomUI.Desktop.Controls.Themes.ColorSliderTrackButtonTheme"
x:ClassModifier="internal"
TargetType="atom:ColorSliderTrackButton">
<Setter Property="Background" Value="Transparent" />
<Setter Property="Focusable" Value="False" />
<Setter Property="HorizontalAlignment" Value="Stretch" />
<Setter Property="VerticalAlignment" Value="Stretch" />
<Setter Property="Template">
<ControlTemplate TargetType="atom:ColorSliderTrackButton">
<Border Name="FocusTarget"
Background="Transparent"
Margin="0,-10" />
</ControlTemplate>
</Setter>
</ControlTheme>
@@ -0,0 +1,7 @@
using Avalonia.Styling;
namespace AtomUI.Desktop.Controls.Themes;
internal class ColorSliderTrackButtonTheme : ControlTheme
{
}
@@ -0,0 +1,5 @@
namespace AtomUI.Desktop.Controls;
internal class ComboBoxTextBox : Avalonia.Controls.TextBox
{
}
@@ -0,0 +1,45 @@
<ControlTheme xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:atom="https://atomui.net"
x:Class="AtomUI.Desktop.Controls.Themes.ComboBoxTextBoxTheme"
x:ClassModifier="internal"
TargetType="atom:ComboBoxTextBox">
<Setter Property="Template">
<ControlTemplate TargetType="atom:ComboBoxTextBox">
<ScrollViewer
Name="ScrollViewer"
Cursor="Ibeam"
HorizontalScrollBarVisibility="{TemplateBinding ScrollViewer.HorizontalScrollBarVisibility}"
VerticalScrollBarVisibility="{TemplateBinding ScrollViewer.VerticalScrollBarVisibility}">
<Panel>
<atom:TextBlock
Name="Placeholder"
HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
Text="{TemplateBinding PlaceholderText}"
Foreground="{TemplateBinding PlaceholderForeground}"
LineHeight="{TemplateBinding LineHeight}"
TextAlignment="{TemplateBinding TextAlignment}"
TextWrapping="{TemplateBinding TextWrapping}" />
<atom:InputTextPresenter
Name="PART_TextPresenter"
HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
CaretBlinkInterval="{TemplateBinding CaretBlinkInterval}"
CaretBrush="{TemplateBinding CaretBrush}"
CaretIndex="{TemplateBinding CaretIndex}"
LineHeight="{TemplateBinding LineHeight}"
PasswordChar="{TemplateBinding PasswordChar}"
RevealPassword="{TemplateBinding RevealPassword}"
SelectionBrush="{TemplateBinding SelectionBrush}"
SelectionStart="{TemplateBinding SelectionStart}"
SelectionEnd="{TemplateBinding SelectionEnd}"
SelectionForegroundBrush="{TemplateBinding SelectionForegroundBrush}"
Text="{TemplateBinding Text, Mode=TwoWay}"
TextAlignment="{TemplateBinding TextAlignment}"
TextWrapping="{TemplateBinding TextWrapping}" />
</Panel>
</ScrollViewer>
</ControlTemplate>
</Setter>
</ControlTheme>
@@ -0,0 +1,7 @@
using Avalonia.Styling;
namespace AtomUI.Desktop.Controls.Themes;
internal class ComboBoxTextBoxTheme : ControlTheme
{
}
@@ -62,7 +62,7 @@
atom:OverflowTip.ShowDelay="{TemplateBinding OverflowTipDelay}"
atom:OverflowTip.Placement="{TemplateBinding OverflowTipPlacement}"
atom:OverflowTip.PlacementTarget="{Binding $parent[atom:AddOnDecoratedBox]}" />
<TextBox
<atom:ComboBoxTextBox
Name="PART_EditableTextBox"
HorizontalAlignment="Stretch"
VerticalAlignment="Center"
@@ -75,46 +75,7 @@
Text="{TemplateBinding Text, Mode=TwoWay}"
PlaceholderText="{TemplateBinding PlaceholderText}"
PlaceholderForeground="{TemplateBinding PlaceholderForeground}"
IsVisible="{TemplateBinding IsEditable}">
<TextBox.Template>
<ControlTemplate TargetType="TextBox">
<ScrollViewer
Name="ScrollViewer"
Cursor="Ibeam"
HorizontalScrollBarVisibility="{TemplateBinding ScrollViewer.HorizontalScrollBarVisibility}"
VerticalScrollBarVisibility="{TemplateBinding ScrollViewer.VerticalScrollBarVisibility}">
<Panel>
<atom:TextBlock
Name="Placeholder"
HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
Text="{TemplateBinding PlaceholderText}"
Foreground="{TemplateBinding PlaceholderForeground}"
LineHeight="{TemplateBinding LineHeight}"
TextAlignment="{TemplateBinding TextAlignment}"
TextWrapping="{TemplateBinding TextWrapping}" />
<atom:InputTextPresenter
Name="PART_TextPresenter"
HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
CaretBlinkInterval="{TemplateBinding CaretBlinkInterval}"
CaretBrush="{TemplateBinding CaretBrush}"
CaretIndex="{TemplateBinding CaretIndex}"
LineHeight="{TemplateBinding LineHeight}"
PasswordChar="{TemplateBinding PasswordChar}"
RevealPassword="{TemplateBinding RevealPassword}"
SelectionBrush="{TemplateBinding SelectionBrush}"
SelectionStart="{TemplateBinding SelectionStart}"
SelectionEnd="{TemplateBinding SelectionEnd}"
SelectionForegroundBrush="{TemplateBinding SelectionForegroundBrush}"
Text="{TemplateBinding Text, Mode=TwoWay}"
TextAlignment="{TemplateBinding TextAlignment}"
TextWrapping="{TemplateBinding TextWrapping}" />
</Panel>
</ScrollViewer>
</ControlTemplate>
</TextBox.Template>
</TextBox>
IsVisible="{TemplateBinding IsEditable}" />
</Panel>
</atom:AddOnDecoratedBox>
@@ -37,6 +37,30 @@ public class ThemeSelectorBoundaryTests
violations.Count.ShouldBe(0, string.Join(Environment.NewLine, violations));
}
[Fact]
public void Production_ControlThemes_Do_Not_Override_Child_Control_Templates()
{
var repositoryRoot = GetRepositoryRoot();
var sourceRoot = Path.Combine(repositoryRoot, "src");
var violations = new List<string>();
foreach (var path in Directory.EnumerateFiles(sourceRoot, "*.axaml", SearchOption.AllDirectories))
{
var document = XDocument.Load(path);
foreach (var theme in document.Descendants().Where(element => element.Name.LocalName == "ControlTheme"))
{
foreach (var templateProperty in theme.Descendants()
.Where(element => element.Name.LocalName.EndsWith(".Template", StringComparison.Ordinal)))
{
violations.Add(
$"{Path.GetRelativePath(repositoryRoot, path)}: {templateProperty.Name.LocalName}");
}
}
}
violations.Count.ShouldBe(0, string.Join(Environment.NewLine, violations));
}
private static int CountTemplateBoundaries(string selector)
{
var count = 0;