Add TagClose support for Select

This commit is contained in:
chinboy
2025-11-01 09:08:02 +08:00
parent 8a3df3dd8d
commit 5df89aa6d8
21 changed files with 535 additions and 81 deletions
@@ -706,8 +706,6 @@ namespace AtomUI.Controls.DesignTokens
public static readonly TokenResourceKey MultiModePaddingLG = new TokenResourceKey("Select.MultiModePaddingLG");
public static readonly TokenResourceKey MultiModePaddingSM = new TokenResourceKey("Select.MultiModePaddingSM");
public static readonly TokenResourceKey MultipleItemBg = new TokenResourceKey("Select.MultipleItemBg");
public static readonly TokenResourceKey MultipleItemBorderColor = new TokenResourceKey("Select.MultipleItemBorderColor");
public static readonly TokenResourceKey MultipleItemBorderColorDisabled = new TokenResourceKey("Select.MultipleItemBorderColorDisabled");
public static readonly TokenResourceKey MultipleItemColorDisabled = new TokenResourceKey("Select.MultipleItemColorDisabled");
public static readonly TokenResourceKey MultipleItemHeight = new TokenResourceKey("Select.MultipleItemHeight");
public static readonly TokenResourceKey MultipleItemHeightLG = new TokenResourceKey("Select.MultipleItemHeightLG");
+1 -1
View File
@@ -4,6 +4,7 @@ using AtomUI.Theme.Utils;
using Avalonia;
using Avalonia.Controls;
using Avalonia.Controls.Primitives;
using Avalonia.Input;
using Avalonia.Media;
namespace AtomUI.Controls;
@@ -143,5 +144,4 @@ public class TextBox : AvaloniaTextBox,
{
Clear();
}
}
@@ -94,6 +94,7 @@
</Setter>
<Style Selector="^:is(atom|TextBox)">
<Setter Property="Background" Value="Transparent" />
<Setter Property="SelectionBrush" Value="{DynamicResource {x:Static atom:SharedTokenKey.SelectionBackground}}" />
<Setter Property="CaretBrush" Value="{DynamicResource {x:Static atom:SharedTokenKey.ColorText}}" />
<Setter Property="SelectionForegroundBrush"
@@ -253,5 +253,4 @@ internal class ListDefaultView : SelectingItemsControl
}
}
}
}
@@ -36,6 +36,7 @@ internal class AddOnDecoratedBox : ContentControl,
IMotionAwareControl
{
public const string AddOnDecoratedBoxPart = "PART_AddOnDecoratedBox";
#region 公共属性定义
public static readonly StyledProperty<object?> LeftAddOnProperty =
@@ -180,6 +181,11 @@ internal class AddOnDecoratedBox : ContentControl,
AvaloniaProperty.RegisterDirect<AddOnDecoratedBox, bool>(nameof(IsInnerBoxHover),
o => o.IsInnerBoxHover,
(o, v) => o.IsInnerBoxHover = v);
internal static readonly DirectProperty<AddOnDecoratedBox, bool> IsInnerBoxPressedProperty =
AvaloniaProperty.RegisterDirect<AddOnDecoratedBox, bool>(nameof(IsInnerBoxPressed),
o => o.IsInnerBoxPressed,
(o, v) => o.IsInnerBoxPressed = v);
private CornerRadius _innerBoxCornerRadius;
@@ -228,6 +234,14 @@ internal class AddOnDecoratedBox : ContentControl,
get => _isInnerBoxHover;
set => SetAndRaise(IsInnerBoxHoverProperty, ref _isInnerBoxHover, value);
}
private bool _isInnerBoxPressed;
internal bool IsInnerBoxPressed
{
get => _isInnerBoxPressed;
set => SetAndRaise(IsInnerBoxPressedProperty, ref _isInnerBoxPressed, value);
}
Control IControlSharedTokenResourcesHost.HostControl => this;
string IControlSharedTokenResourcesHost.TokenId => AddOnDecoratedBoxToken.ID;
@@ -376,6 +390,14 @@ internal class AddOnDecoratedBox : ContentControl,
{
IsInnerBoxHover = false;
};
ContentFrame.PointerPressed += (sender, args) =>
{
IsInnerBoxPressed = true;
};
ContentFrame.PointerReleased += (sender, args) =>
{
IsInnerBoxPressed = false;
};
}
ConfigureInnerBoxCornerRadius();
@@ -287,7 +287,7 @@
<Style Selector="^:pressed">
<Setter Property="BorderBrush"
Value="{DynamicResource {x:Static atom:SharedTokenKey.ColorError}}" />
Value="{DynamicResource {x:Static atom:SharedTokenKey.ColorWarning}}" />
</Style>
</Style>
</Style>
+57 -24
View File
@@ -1,4 +1,3 @@
using System.Collections;
using System.Diagnostics;
using System.Reactive.Disposables;
using AtomUI.Controls.Data;
@@ -12,6 +11,7 @@ using Avalonia.Controls;
using Avalonia.Controls.Primitives;
using Avalonia.Controls.Templates;
using Avalonia.Input;
using Avalonia.Interactivity;
using Avalonia.Media;
using Avalonia.Metadata;
using Avalonia.VisualTree;
@@ -474,7 +474,8 @@ public class Select : TemplatedControl,
private SelectSearchTextBox? _singleSearchInput;
private readonly CompositeDisposable _subscriptionsOnOpen = new ();
private ListFilterDescription? _filterDescription;
private string? _filterValue;
static Select()
{
FocusableProperty.OverrideDefaultValue<Select>(true);
@@ -483,6 +484,8 @@ public class Select : TemplatedControl,
target.HandleClearRequest();
});
OptionsSourceProperty.Changed.AddClassHandler<Select>((x, e) => x.HandleOptionsSourcePropertyChanged(e));
SelectSearchTextBox.TextChangedEvent.AddClassHandler<Select>((x, e) => x.HandleSearchInputTextChanged(e));
SelectTag.ClosedEvent.AddClassHandler<Select>((x, e) => x.HandleTagCloseRequest(e));
}
public Select()
@@ -639,6 +642,7 @@ public class Select : TemplatedControl,
{
_optionsBox.SelectionChanged += HandleOptionsBoxSelectionChanged;
}
_popup = e.NameScope.Get<Popup>(SelectThemeConstants.PopupPart);
_popup.Opened += PopupOpened;
_popup.Closed += PopupClosed;
@@ -669,21 +673,18 @@ public class Select : TemplatedControl,
}
else
{
var selectedOptions = new List<SelectOption>();
var selectedOptions = new HashSet<SelectOption>();
if (SelectedOptions != null)
{
foreach (var option in SelectedOptions)
{
if (!selectedOptions.Contains(option))
{
selectedOptions.Add(option);
}
selectedOptions.Add(option);
}
}
foreach (var item in e.RemovedItems)
{
if (item is SelectOption selectOption)
if (item is SelectOption selectOption && !selectOption.IsSelected)
{
selectedOptions.Remove(selectOption);
}
@@ -691,17 +692,22 @@ public class Select : TemplatedControl,
foreach (var item in e.AddedItems)
{
if (item is SelectOption selectOption && !selectedOptions.Contains(selectOption))
if (item is SelectOption selectOption && !selectedOptions.Contains(selectOption) && selectOption.IsSelected)
{
selectedOptions.Add(selectOption);
}
}
SetCurrentValue(SelectedOptionsProperty, selectedOptions);
var oldSelectedOptions = SelectedOptions?.ToHashSet() ?? new HashSet<SelectOption>();
if (!oldSelectedOptions.SetEquals(selectedOptions))
{
SetCurrentValue(SelectedOptionsProperty, selectedOptions.ToList());
}
}
}
protected override void OnPropertyChanged(AvaloniaPropertyChangedEventArgs change)
{
base.OnPropertyChanged(change);
if (change.Property == SelectedOptionsProperty)
{
ConfigurePlaceholderVisible();
@@ -735,7 +741,6 @@ public class Select : TemplatedControl,
{
HandleOptionFilterPropChanged();
}
base.OnPropertyChanged(change);
}
private void PopupClosed(object? sender, EventArgs e)
@@ -750,6 +755,8 @@ public class Select : TemplatedControl,
_singleSearchInput.Width = double.NaN;
}
}
_filterValue = null;
}
private void PopupOpened(object? sender, EventArgs e)
@@ -761,11 +768,6 @@ public class Select : TemplatedControl,
parent.GetObservable(IsVisibleProperty).Subscribe(IsVisibleChanged).DisposeWith(_subscriptionsOnOpen);
}
if (_optionsBox != null)
{
_optionsBox.SelectedItem = SelectedOption;
_optionsBox.SelectedItems = (IList?)SelectedOptions;
}
DropDownOpened?.Invoke(this, EventArgs.Empty);
if (Mode == SelectMode.Single)
{
@@ -786,8 +788,25 @@ public class Select : TemplatedControl,
public void Clear()
{
if (SelectedOptions != null)
{
foreach (var option in SelectedOptions)
{
option.IsSelected = false;
}
}
if (SelectedOption != null)
{
SelectedOption.IsSelected = false;
}
SelectedOptions = null;
SelectedOption = null;
if (_optionsBox != null)
{
_optionsBox.SelectedItems = null;
_optionsBox.SelectedItem = null;
}
}
private void ConfigureMaxDropdownHeight()
@@ -825,7 +844,7 @@ public class Select : TemplatedControl,
private void ConfigurePlaceholderVisible()
{
SetCurrentValue(IsPlaceholderTextVisibleProperty, (Mode == SelectMode.Single && SelectedOption == null) ||
(Mode != SelectMode.Single && SelectedOptions == null || SelectedOptions?.Count == 0));
(Mode != SelectMode.Single && (SelectedOptions == null || SelectedOptions?.Count == 0) && string.IsNullOrEmpty(_filterValue)));
}
private void ConfigureSelectionIsEmpty()
@@ -841,16 +860,20 @@ public class Select : TemplatedControl,
{
_singleSearchInput.Width = _singleSearchInput.Bounds.Width;
}
_singleSearchInput.TextChanged += HandleSearchInputTextChanged;
}
}
private void HandleSearchInputTextChanged(object? sender, TextChangedEventArgs e)
private void HandleSearchInputTextChanged(TextChangedEventArgs e)
{
if (_optionsBox != null && _optionsBox.FilterDescriptions != null)
{
var filterValue = _singleSearchInput?.Text;
if (string.IsNullOrEmpty(filterValue))
if (e.Source is TextBox textBox)
{
_filterValue = textBox.Text;
}
ConfigurePlaceholderVisible();
if (string.IsNullOrEmpty(_filterValue))
{
_optionsBox.FilterDescriptions.Clear();
}
@@ -861,13 +884,13 @@ public class Select : TemplatedControl,
var oldFilter = _filterDescription;
Debug.Assert(oldFilter.FilterConditions.Count == 1);
var oldFilterValue = oldFilter.FilterConditions.First().ToString();
if (oldFilterValue != filterValue)
if (oldFilterValue != _filterValue)
{
_filterDescription = new ListFilterDescription()
{
PropertyPath = _filterDescription.PropertyPath,
Filter = _filterDescription.Filter,
FilterConditions = [filterValue]
FilterConditions = [_filterValue]
};
_optionsBox.FilterDescriptions.Remove(oldFilter);
_optionsBox.FilterDescriptions.Add(_filterDescription);
@@ -879,12 +902,22 @@ public class Select : TemplatedControl,
{
PropertyPath = OptionFilterProp,
Filter = FilterFn,
FilterConditions = [filterValue],
FilterConditions = [_filterValue],
};
_optionsBox.FilterDescriptions.Add(_filterDescription);
}
}
}
e.Handled = true;
}
private void HandleTagCloseRequest(RoutedEventArgs e)
{
if (e.Source is SelectTag tag && tag.Option != null)
{
_optionsBox?.DeSelect(tag.Option);
}
e.Handled = true;
}
private void HandleOptionFilterPropChanged()
@@ -13,6 +13,9 @@ internal class SelectAddOnDecoratedBox : AddOnDecoratedBox
o => o.IsSelectionEmpty,
(o, v) => o.IsSelectionEmpty = v);
public static readonly StyledProperty<bool> IsDropDownOpenProperty =
AvaloniaProperty.Register<SelectAddOnDecoratedBox, bool>(nameof(IsDropDownOpen));
public SelectMode Mode
{
get => GetValue(ModeProperty);
@@ -26,4 +29,10 @@ internal class SelectAddOnDecoratedBox : AddOnDecoratedBox
get => _isSelectionEmpty;
set => SetAndRaise(IsSelectionEmptyProperty, ref _isSelectionEmpty, value);
}
public bool IsDropDownOpen
{
get => GetValue(IsDropDownOpenProperty);
set => SetValue(IsDropDownOpenProperty, value);
}
}
@@ -11,6 +11,9 @@ internal class SelectHandle : TemplatedControl
public static readonly StyledProperty<bool> IsInputHoverProperty =
AvaloniaProperty.Register<SelectHandle, bool>(nameof(IsInputHover));
public static readonly StyledProperty<bool> IsInputPressedProperty =
AvaloniaProperty.Register<SelectHandle, bool>(nameof(IsInputPressed));
public static readonly StyledProperty<bool> IsSearchEnabledProperty =
AvaloniaProperty.Register<SelectHandle, bool>(nameof(IsSearchEnabled));
@@ -35,6 +38,12 @@ internal class SelectHandle : TemplatedControl
set => SetValue(IsInputHoverProperty, value);
}
public bool IsInputPressed
{
get => GetValue(IsInputPressedProperty);
set => SetValue(IsInputPressedProperty, value);
}
public bool IsSearchEnabled
{
get => GetValue(IsSearchEnabledProperty);
@@ -10,4 +10,6 @@ public record SelectOption : ISelectOption
public string Header { get; set; } = string.Empty;
public bool IsEnabled { get; set; } = true;
public object? Value { get; set; }
internal bool IsSelected { get; set; } = false;
}
+60 -9
View File
@@ -1,6 +1,5 @@
using System.Reactive.Disposables;
using AtomUI.Data;
using AtomUI.Utils;
using Avalonia;
using Avalonia.Controls;
using Avalonia.Input;
@@ -18,7 +17,7 @@ internal class SelectOptions : List
return new SelectOptionItem();
}
private void DoSelectOption(Control container)
private void LogicalSelectOption(Control container)
{
if (ListDefaultView != null)
{
@@ -29,22 +28,69 @@ internal class SelectOptions : List
{
return;
}
var mode = SelectionMode;
var item = ListDefaultView.ItemFromContainer(container);
var mode = SelectionMode;
if (mode == SelectionMode.Single)
{
ListDefaultView.Selection.Select(index);
}
else if (mode == SelectionMode.Multiple)
{
if (ListDefaultView.Selection.IsSelected(index))
if (item is SelectOption option)
{
ListDefaultView.Selection.Deselect(index);
if (ListDefaultView.Selection.IsSelected(index))
{
option.IsSelected = false;
ListDefaultView.Selection.Deselect(index);
}
else
{
option.IsSelected = true;
ListDefaultView.Selection.Select(index);
}
}
else
}
}
}
}
public void Select(SelectOption option)
{
if (ListDefaultView != null)
{
var container = ListDefaultView.ContainerFromItem(option);
if (container != null)
{
var index = ListDefaultView.IndexFromContainer(container);
if (index != -1)
{
if (index < 0 || index >= ItemCount)
{
ListDefaultView.Selection.Select(index);
return;
}
option.IsSelected = true;
ListDefaultView.Selection.Select(index);
}
}
}
}
public void DeSelect(SelectOption option)
{
if (ListDefaultView != null)
{
var container = ListDefaultView.ContainerFromItem(option);
if (container != null)
{
var index = ListDefaultView.IndexFromContainer(container);
if (index != -1)
{
if (index < 0 || index >= ItemCount)
{
return;
}
option.IsSelected = false;
ListDefaultView.Selection.Deselect(index);
}
}
}
@@ -55,7 +101,7 @@ internal class SelectOptions : List
var container = GetContainerFromEventSource(source);
if (container != null)
{
DoSelectOption(container);
LogicalSelectOption(container);
return true;
}
return false;
@@ -81,6 +127,11 @@ internal class SelectOptions : List
{
listItem.SetCurrentValue(IsEnabledProperty, data.IsEnabled);
}
if (!listItem.IsSet(SelectOptionItem.IsSelectedProperty))
{
listItem.SetCurrentValue(SelectOptionItem.IsSelectedProperty, data.IsSelected);
}
}
}
@@ -3,6 +3,7 @@ using Avalonia;
using Avalonia.Controls;
using Avalonia.Controls.Primitives;
using Avalonia.Input;
using Avalonia.Layout;
namespace AtomUI.Controls;
@@ -20,6 +21,9 @@ internal class SelectResultOptionsBox : TemplatedControl
public static readonly StyledProperty<bool> IsSearchEnabledProperty =
Select.IsSearchEnabledProperty.AddOwner<SelectResultOptionsBox>();
public static readonly StyledProperty<bool> IsDropDownOpenProperty =
AvaloniaProperty.Register<SelectResultOptionsBox, bool>(nameof(IsDropDownOpen));
private IList<SelectOption>? _selectedOptions;
public IList<SelectOption>? SelectedOptions
@@ -39,8 +43,15 @@ internal class SelectResultOptionsBox : TemplatedControl
get => GetValue(IsSearchEnabledProperty);
set => SetValue(IsSearchEnabledProperty, value);
}
public bool IsDropDownOpen
{
get => GetValue(IsDropDownOpenProperty);
set => SetValue(IsDropDownOpenProperty, value);
}
private WrapPanel? _defaultPanel;
private SelectSearchTextBox? _searchTextBox;
protected override void OnPropertyChanged(AvaloniaPropertyChangedEventArgs change)
{
@@ -49,6 +60,15 @@ internal class SelectResultOptionsBox : TemplatedControl
{
HandleSelectedOptionsChanged();
}
else if (change.Property == IsSearchEnabledProperty ||
change.Property == ModeProperty)
{
ConfigureSearchTextControl();
}
else if (change.Property == IsDropDownOpenProperty)
{
ConfigureSearchTextReadOnly();
}
}
protected override void OnPointerPressed(PointerPressedEventArgs e)
@@ -66,25 +86,80 @@ internal class SelectResultOptionsBox : TemplatedControl
protected override void OnApplyTemplate(TemplateAppliedEventArgs e)
{
base.OnApplyTemplate(e);
_defaultPanel = e.NameScope.Find<WrapPanel>(SelectResultOptionsBoxThemeConstants.DefaultPanelPart);
_defaultPanel = e.NameScope.Find<WrapPanel>(SelectResultOptionsBoxThemeConstants.DefaultPanelPart);
_searchTextBox = new SelectSearchTextBox()
{
HorizontalAlignment = HorizontalAlignment.Stretch
};
if (IsSearchEnabled)
{
if (Mode == SelectMode.Multiple)
{
_defaultPanel?.Children.Add(_searchTextBox);
}
}
}
private void HandleSelectedOptionsChanged()
{
if (_defaultPanel != null)
{
_searchTextBox?.Clear();
_defaultPanel.Children.Clear();
if (_selectedOptions != null)
{
foreach (var option in _selectedOptions)
{
_defaultPanel.Children.Add(new Tag()
_defaultPanel.Children.Add(new SelectTag()
{
TagText = option.Header,
Bordered = false
Option = option
});
}
}
if (_searchTextBox != null)
{
_defaultPanel.Children.Add(_searchTextBox);
_searchTextBox.Focus();
}
}
}
private void ConfigureSearchTextControl()
{
if (_searchTextBox != null)
{
if (Mode == SelectMode.Multiple)
{
if (_defaultPanel != null)
{
if (IsSearchEnabled)
{
_defaultPanel.Children.Add(_searchTextBox);
}
else
{
_defaultPanel.Children.Remove(_searchTextBox);
}
}
}
}
}
private void ConfigureSearchTextReadOnly()
{
if (_searchTextBox != null)
{
if (IsDropDownOpen)
{
_searchTextBox.IsReadOnly = false;
}
else
{
_searchTextBox.Clear();
_searchTextBox.IsReadOnly = true;
}
}
}
}
+6
View File
@@ -0,0 +1,6 @@
namespace AtomUI.Controls;
internal class SelectTag : Tag
{
public SelectOption? Option { get; set; }
}
-14
View File
@@ -15,12 +15,6 @@ internal class SelectToken : AbstractControlDesignToken
/// </summary>
public Color MultipleItemBg { get; set; }
/// <summary>
/// 多选标签边框色
/// Border color of multiple tag
/// </summary>
public Color MultipleItemBorderColor { get; set; }
/// <summary>
/// 多选标签高度
/// Height of multiple tag
@@ -51,12 +45,6 @@ internal class SelectToken : AbstractControlDesignToken
/// </summary>
public Color MultipleItemColorDisabled { get; set; }
/// <summary>
/// 多选标签禁用边框色
/// Border color of multiple tag when disabled
/// </summary>
public Color MultipleItemBorderColorDisabled { get; set; }
/// <summary>
/// 选项选中时文本颜色
/// Text color when option is selected
@@ -165,13 +153,11 @@ internal class SelectToken : AbstractControlDesignToken
OptionFontSize = SharedToken.FontSize;
OptionHeight = SharedToken.ControlHeight;
MultipleItemBg = SharedToken.ColorFillSecondary;
MultipleItemBorderColor = Colors.Transparent;
MultipleItemHeight = multipleItemHeight;
MultipleItemHeightSM = multipleItemHeightSM;
MultipleItemHeightLG = multipleItemHeightLG;
MultipleSelectorBgDisabled = SharedToken.ColorBgContainerDisabled;
MultipleItemColorDisabled = SharedToken.ColorTextDisabled;
MultipleItemBorderColorDisabled = Colors.Transparent;
SelectAffixPadding = SharedToken.PaddingXXS;
PopupBorderRadius = SharedToken.BorderRadiusLG;
@@ -0,0 +1,70 @@
using System.Collections.Specialized;
using Avalonia;
using Avalonia.Controls;
namespace AtomUI.Controls;
internal class SelectWrapPanel : WrapPanel
{
private SelectSearchTextBox? _searchTextBox;
protected override Size ArrangeOverride(Size finalSize)
{
var size = base.ArrangeOverride(finalSize);
if (_searchTextBox != null)
{
if (Children.Count == 1)
{
_searchTextBox.Arrange(new Rect(0, 0, finalSize.Width, finalSize.Height));
}
else
{
// 找最后一个
var indexOf = Children.IndexOf(_searchTextBox);
var lastIndex = indexOf - 1;
var lastTag = Children[lastIndex];
var lastBounds = lastTag.Bounds;
var offestX = lastBounds.Right + ItemSpacing;
var offsetY = lastBounds.Top;
var width = finalSize.Width - offestX;
if ((offestX + _searchTextBox.DesiredSize.Width) > finalSize.Width)
{
offestX = 0;
offsetY += lastBounds.Height + LineSpacing;
width = finalSize.Width;
}
var targetSearchBoxBounds = new Rect(offestX, offsetY, width, _searchTextBox.DesiredSize.Height);
_searchTextBox.Arrange(targetSearchBoxBounds);
}
}
return size;
}
protected override void ChildrenChanged(object? sender, NotifyCollectionChangedEventArgs e)
{
base.ChildrenChanged(sender, e);
if (e.OldItems != null)
{
foreach (var oldItem in e.OldItems)
{
if (oldItem is SelectSearchTextBox)
{
_searchTextBox = null;
}
}
}
if (e.NewItems != null)
{
foreach (var newItem in e.NewItems)
{
if (newItem is SelectSearchTextBox searchTextBox)
{
_searchTextBox = searchTextBox;
}
}
}
}
}
@@ -10,24 +10,183 @@
</ControlTheme.BasedOn>
<Style Selector="^:is(atom|SelectAddOnDecoratedBox)">
<Style Selector="^:not(^[Mode=Single])^[IsSelectionEmpty=False]">
<Style Selector="^[SizeType=Large]">
<Style Selector="^ /template/ Border#PART_ContentFrame">
<Setter Property="Padding"
Value="{DynamicResource {x:Static atom:SelectTokenKey.MultiModePaddingLG}}" />
<Style Selector="^:not(^[Mode=Single])">
<Style Selector="^[IsSelectionEmpty=False]">
<Style Selector="^[SizeType=Large]">
<Style Selector="^ /template/ Border#PART_ContentFrame">
<Setter Property="Padding"
Value="{DynamicResource {x:Static atom:SelectTokenKey.MultiModePaddingLG}}" />
</Style>
</Style>
<Style Selector="^[SizeType=Middle]">
<Style Selector="^ /template/ Border#PART_ContentFrame">
<Setter Property="Padding"
Value="{DynamicResource {x:Static atom:SelectTokenKey.MultiModePadding}}" />
</Style>
</Style>
<Style Selector="^[SizeType=Small]">
<Style Selector="^ /template/ Border#PART_ContentFrame">
<Setter Property="Padding"
Value="{DynamicResource {x:Static atom:SelectTokenKey.MultiModePaddingSM}}" />
</Style>
</Style>
</Style>
<Style Selector="^[SizeType=Middle]">
<Style Selector="^ /template/ Border#PART_ContentFrame">
<Setter Property="Padding"
Value="{DynamicResource {x:Static atom:SelectTokenKey.MultiModePadding}}" />
</Style>
<Style Selector="^[StyleVariant=Outline]">
<Setter Property="BorderBrush" Value="{DynamicResource {x:Static atom:SharedTokenKey.ColorBorder}}" />
<Style Selector="^[IsInnerBoxHover=True]">
<Setter Property="BorderBrush"
Value="{DynamicResource {x:Static atom:AddOnDecoratedBoxTokenKey.HoverBorderColor}}" />
</Style>
<Style Selector="^:focus-within">
<Setter Property="BorderBrush"
Value="{DynamicResource {x:Static atom:AddOnDecoratedBoxTokenKey.ActiveBorderColor}}" />
</Style>
<Style Selector="^:pressed">
<Setter Property="BorderBrush"
Value="{DynamicResource {x:Static atom:AddOnDecoratedBoxTokenKey.ActiveBorderColor}}" />
</Style>
<Style Selector="^[IsDropDownOpen=True]">
<Setter Property="BorderBrush"
Value="{DynamicResource {x:Static atom:AddOnDecoratedBoxTokenKey.ActiveBorderColor}}" />
</Style>
<Style Selector="^[Status=Error]">
<Setter Property="BorderBrush"
Value="{DynamicResource {x:Static atom:SharedTokenKey.ColorError}}" />
<Style Selector="^[IsInnerBoxHover=True]">
<Setter Property="BorderBrush"
Value="{DynamicResource {x:Static atom:SharedTokenKey.ColorErrorBorderHover}}" />
</Style>
<Style Selector="^:focus-within">
<Setter Property="BorderBrush"
Value="{DynamicResource {x:Static atom:SharedTokenKey.ColorError}}" />
</Style>
<Style Selector="^:pressed">
<Setter Property="BorderBrush"
Value="{DynamicResource {x:Static atom:SharedTokenKey.ColorError}}" />
</Style>
<Style Selector="^[IsDropDownOpen=True]">
<Setter Property="BorderBrush"
Value="{DynamicResource {x:Static atom:SharedTokenKey.ColorError}}" />
</Style>
</Style>
<Style Selector="^[SizeType=Small]">
<Style Selector="^ /template/ Border#PART_ContentFrame">
<Setter Property="Padding"
Value="{DynamicResource {x:Static atom:SelectTokenKey.MultiModePaddingSM}}" />
<Style Selector="^[Status=Warning]">
<Setter Property="BorderBrush"
Value="{DynamicResource {x:Static atom:SharedTokenKey.ColorWarning}}" />
<Style Selector="^[IsInnerBoxHover=True]">
<Setter Property="BorderBrush"
Value="{DynamicResource {x:Static atom:SharedTokenKey.ColorWarningBorderHover}}" />
</Style>
<Style Selector="^:focus-within">
<Setter Property="BorderBrush"
Value="{DynamicResource {x:Static atom:SharedTokenKey.ColorWarning}}" />
</Style>
<Style Selector="^:pressed">
<Setter Property="BorderBrush"
Value="{DynamicResource {x:Static atom:SharedTokenKey.ColorWarning}}" />
</Style>
<Style Selector="^[IsDropDownOpen=True]">
<Setter Property="BorderBrush"
Value="{DynamicResource {x:Static atom:SharedTokenKey.ColorWarning}}" />
</Style>
</Style>
</Style>
<Style Selector="^[StyleVariant=Filled]">
<Setter Property="BorderBrush" Value="Transparent" />
<Setter Property="Background"
Value="{DynamicResource {x:Static atom:SharedTokenKey.ColorFillTertiary}}" />
<Style Selector="^[IsInnerBoxHover=True]">
<Setter Property="Background"
Value="{DynamicResource {x:Static atom:SharedTokenKey.ColorFillSecondary}}" />
</Style>
<Style Selector="^:focus-within">
<Setter Property="BorderBrush"
Value="{DynamicResource {x:Static atom:AddOnDecoratedBoxTokenKey.ActiveBorderColor}}" />
<Setter Property="Background" Value="Transparent" />
</Style>
<Style Selector="^:pressed">
<Setter Property="BorderBrush"
Value="{DynamicResource {x:Static atom:AddOnDecoratedBoxTokenKey.ActiveBorderColor}}" />
</Style>
<Style Selector="^[IsDropDownOpen=True]">
<Setter Property="BorderBrush"
Value="{DynamicResource {x:Static atom:AddOnDecoratedBoxTokenKey.ActiveBorderColor}}" />
</Style>
<Style Selector="^[Status=Error]">
<Setter Property="BorderBrush"
Value="Transparent" />
<Setter Property="Background"
Value="{DynamicResource {x:Static atom:SharedTokenKey.ColorErrorBg}}" />
<Style Selector="^[IsInnerBoxHover=True]">
<Setter Property="Background"
Value="{DynamicResource {x:Static atom:SharedTokenKey.ColorErrorBgHover}}" />
</Style>
<Style Selector="^:focus-within">
<Setter Property="BorderBrush"
Value="{DynamicResource {x:Static atom:SharedTokenKey.ColorError}}" />
<Setter Property="Background"
Value="{DynamicResource {x:Static atom:AddOnDecoratedBoxTokenKey.ActiveBg}}" />
</Style>
<Style Selector="^:pressed">
<Setter Property="BorderBrush"
Value="{DynamicResource {x:Static atom:SharedTokenKey.ColorError}}" />
</Style>
<Style Selector="^[IsDropDownOpen=True]">
<Setter Property="BorderBrush"
Value="{DynamicResource {x:Static atom:SharedTokenKey.ColorError}}" />
</Style>
</Style>
<Style Selector="^[Status=Warning]">
<Setter Property="BorderBrush" Value="Transparent" />
<Setter Property="Background"
Value="{DynamicResource {x:Static atom:SharedTokenKey.ColorWarningBg}}" />
<Style Selector="^[IsInnerBoxHover=True]">
<Setter Property="Background"
Value="{DynamicResource {x:Static atom:SharedTokenKey.ColorWarningBgHover}}" />
</Style>
<Style Selector="^:focus-within">
<Setter Property="BorderBrush"
Value="{DynamicResource {x:Static atom:SharedTokenKey.ColorWarning}}" />
<Setter Property="Background"
Value="{DynamicResource {x:Static atom:AddOnDecoratedBoxTokenKey.ActiveBg}}" />
</Style>
<Style Selector="^:pressed">
<Setter Property="BorderBrush"
Value="{DynamicResource {x:Static atom:SharedTokenKey.ColorWarning}}" />
</Style>
<Style Selector="^[IsDropDownOpen=True]">
<Setter Property="BorderBrush"
Value="{DynamicResource {x:Static atom:SharedTokenKey.ColorWarning}}" />
</Style>
</Style>
</Style>
@@ -66,14 +66,20 @@
</Style>
<Style Selector="^[IsClearable=True]">
<Style Selector="^[IsInputHover=True][IsSelectionEmpty=False]">
<Style Selector="^ /template/ atom|Icon#OpenIndicator">
<Setter Property="IsVisible" Value="False" />
</Style>
<Style Selector="^ /template/ atom|IconButton#PART_ClearButton">
<Setter Property="IsVisible" Value="True" />
<Style Selector="^[IsSelectionEmpty=False]">
<Style Selector="^[IsInputHover=True]">
<Style Selector="^ /template/ atom|Icon#OpenIndicator">
<Setter Property="IsVisible" Value="False" />
</Style>
<Style Selector="^ /template/ atom|Icon#SearchIndicator">
<Setter Property="IsVisible" Value="False" />
</Style>
<Style Selector="^ /template/ atom|IconButton#PART_ClearButton">
<Setter Property="IsVisible" Value="True" />
</Style>
</Style>
</Style>
</Style>
</ControlTheme>
@@ -7,12 +7,12 @@
<Setter Property="Template">
<ControlTemplate>
<Panel Name="RootLayout">
<WrapPanel Name="{x:Static atom:SelectResultOptionsBoxThemeConstants.DefaultPanelPart}"/>
<atom:SelectWrapPanel Name="{x:Static atom:SelectResultOptionsBoxThemeConstants.DefaultPanelPart}"/>
</Panel>
</ControlTemplate>
</Setter>
<Style Selector="^ /template/ WrapPanel#PART_DefaultPanel">
<Style Selector="^ /template/ atom|SelectWrapPanel#PART_DefaultPanel">
<Setter Property="ItemSpacing" Value="{DynamicResource {x:Static atom:SharedTokenKey.SpacingXXS}}"/>
<Setter Property="LineSpacing" Value="{DynamicResource {x:Static atom:SharedTokenKey.SpacingXXS}}"/>
</Style>
@@ -0,0 +1,20 @@
<ResourceDictionary
xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:atom="https://atomui.net"
xmlns:themes="using:AtomUI.Controls.Themes"
x:ClassModifier="internal">
<ControlTheme x:Key="{x:Type atom:SelectTag}" TargetType="atom:SelectTag">
<ControlTheme.BasedOn>
<themes:TagTheme TargetType="atom:SelectTag" />
</ControlTheme.BasedOn>
<Style Selector="^:is(atom|SelectTag)">
<Setter Property="Bordered" Value="False"/>
<Setter Property="Background" Value="{DynamicResource {x:Static atom:SelectTokenKey.MultipleItemBg}}" />
<Setter Property="IsClosable" Value="True" />
<Setter Property="FontSize" Value="{DynamicResource {x:Static atom:SelectTokenKey.OptionFontSize}}" />
</Style>
</ControlTheme>
</ResourceDictionary>
@@ -23,7 +23,8 @@
ContentLeftAddOn="{TemplateBinding ContentLeftAddOn}"
ContentLeftAddOnTemplate="{TemplateBinding ContentLeftAddOnTemplate}"
Mode="{TemplateBinding Mode}"
IsSelectionEmpty="{TemplateBinding IsSelectionEmpty}">
IsSelectionEmpty="{TemplateBinding IsSelectionEmpty}"
IsDropDownOpen="{TemplateBinding IsDropDownOpen}">
<atom:AddOnDecoratedBox.ContentRightAddOn>
<StackPanel Orientation="Horizontal"
Spacing="{DynamicResource {x:Static atom:SharedTokenKey.SpacingXS}}">
@@ -39,7 +40,8 @@
IsClearable="{Binding IsAllowClear, RelativeSource={RelativeSource AncestorType=atom:Select}}"
IsSelectionEmpty="{Binding IsSelectionEmpty, RelativeSource={RelativeSource AncestorType=atom:Select}}"
IsDropDownOpen="{Binding IsDropDownOpen, RelativeSource={RelativeSource AncestorType=atom:Select}}"
IsInputHover="{Binding IsInnerBoxHover, RelativeSource={RelativeSource AncestorType=atom:AddOnDecoratedBox}}"/>
IsInputHover="{Binding IsInnerBoxHover, RelativeSource={RelativeSource AncestorType=atom:AddOnDecoratedBox}}"
IsInputPressed="{Binding IsInnerBoxPressed, RelativeSource={RelativeSource AncestorType=atom:AddOnDecoratedBox}}"/>
</StackPanel>
</atom:AddOnDecoratedBox.ContentRightAddOn>
<Panel>
@@ -66,11 +68,14 @@
Watermark="{TemplateBinding SelectedOption, Converter={StaticResource OptionHeaderConverter}}"/>
<atom:SelectResultOptionsBox
Name="SelectedOptionsBox"
HorizontalAlignment="Left"
HorizontalAlignment="Stretch"
VerticalAlignment="Center"
Mode="{TemplateBinding Mode}"
SelectedOptions="{TemplateBinding SelectedOptions}"
IsSearchEnabled="{TemplateBinding IsSearchEnabled}"
IsVisible="False"/>
IsDropDownOpen="{TemplateBinding IsDropDownOpen}"
IsVisible="False"
Focusable="True"/>
</Panel>
</atom:SelectAddOnDecoratedBox>
<atom:Popup Name="{x:Static atom:SelectThemeConstants.PopupPart}"
@@ -157,7 +162,9 @@
<Style Selector="^ /template/ atom|SelectResultOptionsBox#SelectedOptionsBox">
<Setter Property="IsVisible" Value="True" />
</Style>
<Style Selector="^[IsSearchEnabled=False]">
<Setter Property="Cursor" Value="Hand"/>
</Style>
<Style Selector="^ /template/ atom|SelectOptions#PART_OptionsBox">
<Setter Property="IsShowSelectedIndicator" Value="True" />
<Setter Property="SelectionMode" Value="Multiple" />
@@ -7,6 +7,7 @@
<ResourceInclude Source="SelectResultOptionsBoxTheme.axaml"/>
<ResourceInclude Source="SelectSearchTextBoxTheme.axaml"/>
<ResourceInclude Source="SelectTheme.axaml"/>
<ResourceInclude Source="SelectTagTheme.axaml"/>
<ResourceInclude Source="SelectOptionsTheme.axaml"/>
<ResourceInclude Source="SelectOptionItemTheme.axaml"/>
<ResourceInclude Source="SelectAddOnDecoratedBoxTheme.axaml"/>