|
6 | 6 | <div class="@ClassValue fluent-autocomplete-multiselect"
|
7 | 7 | style="@StyleValue"
|
8 | 8 | @attributes="AdditionalAttributes"
|
| 9 | + single-select="@GetSingleSelect()" |
9 | 10 | auto-height="@(!string.IsNullOrEmpty(MaxAutoHeight))">
|
10 | 11 | <FluentKeyCode Anchor="@Id" OnKeyDown="@KeyDownHandlerAsync" Only="@CatchOnly" PreventDefaultOnly="@PreventOnly" />
|
11 | 12 |
|
|
31 | 32 | autofocus="@Autofocus"
|
32 | 33 | Style="@ComponentWidth">
|
33 | 34 | @* Selected Items *@
|
34 |
| - @if (this.SelectedOptions?.Any() == true) |
| 35 | + @if (this.SelectedOptions?.Any() == true || this.SelectedOption is not null) |
35 | 36 | {
|
36 | 37 | @* Normal (single) line height *@
|
37 | 38 | if (string.IsNullOrEmpty(MaxAutoHeight))
|
|
67 | 68 | @RenderSelectedOptions
|
68 | 69 | </div>
|
69 | 70 | }
|
70 |
| - |
71 | 71 | }
|
72 | 72 | @if (!Disabled && !ReadOnly)
|
73 | 73 | {
|
74 |
| - if (this.SelectedOptions?.Any() == true || !string.IsNullOrEmpty(ValueText)) |
| 74 | + if (this.SelectedOptions?.Any() == true || !string.IsNullOrEmpty(ValueText) || this.SelectedOption is not null) |
75 | 75 | {
|
76 | 76 | if (IconDismiss != null)
|
77 | 77 | {
|
78 |
| - <FluentIcon Value="@IconDismiss" |
79 |
| - Width="12px" |
80 |
| - Style="cursor: pointer;" |
81 |
| - Slot="end" |
82 |
| - Title="@AccessibilityIconDismiss" |
83 |
| - Focusable="true" |
84 |
| - @onfocus="@(e => { IsReachedMaxItems = false; IsMultiSelectOpened = false; })" |
85 |
| - OnClick="@OnClearAsync" /> |
| 78 | + <FluentIcon Value="@IconDismiss" |
| 79 | + Width="12px" |
| 80 | + Style="cursor: pointer;" |
| 81 | + Slot="end" |
| 82 | + Title="@(Multiple == false ? string.Format(AccessibilityRemoveItem, GetOptionText(SelectedOption)) : AccessibilityIconDismiss)" |
| 83 | + Focusable="true" |
| 84 | + @onfocus="@(e => { IsReachedMaxItems = false; IsMultiSelectOpened = false; })" |
| 85 | + OnClick="@OnClearAsync" /> |
86 | 86 | }
|
87 | 87 | }
|
88 | 88 | else
|
89 | 89 | {
|
90 | 90 | if (IconSearch != null)
|
91 | 91 | {
|
92 |
| - <FluentIcon Value="@IconSearch" |
93 |
| - Width="16px" |
94 |
| - Style="cursor: pointer;" |
95 |
| - Slot="end" |
96 |
| - Title="@AccessibilityIconSearch" |
97 |
| - Focusable="true" |
98 |
| - @onfocus="@(e => { IsReachedMaxItems = false; IsMultiSelectOpened = false; })" |
99 |
| - OnClick="@OnDropDownExpandedAsync" /> |
| 92 | + <FluentIcon Value="@IconSearch" |
| 93 | + Width="16px" |
| 94 | + Style="cursor: pointer;" |
| 95 | + Slot="end" |
| 96 | + Title="@AccessibilityIconSearch" |
| 97 | + Focusable="true" |
| 98 | + @onfocus="@(e => { IsReachedMaxItems = false; IsMultiSelectOpened = false; })" |
| 99 | + OnClick="@OnDropDownExpandedAsync" /> |
100 | 100 | }
|
101 | 101 | }
|
102 | 102 | }
|
|
107 | 107 | {
|
108 | 108 | @if (SelectValueOnTab)
|
109 | 109 | {
|
110 |
| - <FluentKeyCode Anchor="@Id" |
111 |
| - OnKeyDown="@KeyDownHandlerAsync" |
112 |
| - Only="@SelectValueOnTabOnly" |
113 |
| - PreventDefaultOnly="@SelectValueOnTabOnly" /> |
| 110 | + <FluentKeyCode Anchor="@Id" |
| 111 | + OnKeyDown="@KeyDownHandlerAsync" |
| 112 | + Only="@SelectValueOnTabOnly" |
| 113 | + PreventDefaultOnly="@SelectValueOnTabOnly" /> |
114 | 114 | }
|
115 | 115 |
|
116 | 116 | <FluentOverlay OnClose="@(e => IsMultiSelectOpened = false)" Visible="true" Transparent="true" FullScreen="true" />
|
|
122 | 122 | Shadow="ElevationShadow.Flyout">
|
123 | 123 | @if (HeaderContent != null)
|
124 | 124 | {
|
125 |
| - @HeaderContent(Items ?? Array.Empty<TOption>()) |
| 125 | + @HeaderContent(Items ?? Array.Empty<TOption>()) |
126 | 126 | }
|
127 | 127 |
|
128 | 128 | <div id="@IdPopup" role="listbox" style="@ListStyleValue" tabindex="0">
|
129 | 129 | @if (Items != null)
|
130 | 130 | {
|
131 |
| - var selectableItem = GetOptionValue(SelectableItem); |
| 131 | + var selectableItem = GetOptionValue(SelectableItem); |
132 | 132 |
|
133 |
| - @if (Virtualize) |
134 |
| - { |
135 |
| - <Virtualize ItemsProvider="LoadFilteredItemsAsync" @ref="VirtualizationContainer" ItemSize="ItemSize"> |
136 |
| - @RenderOption((context, selectableItem)) |
137 |
| - </Virtualize> |
138 |
| - } |
139 |
| - else |
140 |
| - { |
141 |
| - foreach (TOption item in Items) |
| 133 | + @if (Virtualize) |
| 134 | + { |
| 135 | + <Virtualize ItemsProvider="LoadFilteredItemsAsync" @ref="VirtualizationContainer" ItemSize="ItemSize"> |
| 136 | + @RenderOption((context, selectableItem)) |
| 137 | + </Virtualize> |
| 138 | + } |
| 139 | + else |
142 | 140 | {
|
143 |
| - @RenderOption((item, selectableItem)) |
| 141 | + foreach (TOption item in Items) |
| 142 | + { |
| 143 | + @RenderOption((item, selectableItem)) |
| 144 | + } |
144 | 145 | }
|
145 |
| - } |
146 | 146 | }
|
147 | 147 | </div>
|
148 | 148 |
|
149 | 149 | @if (FooterContent != null)
|
150 | 150 | {
|
151 |
| - @FooterContent(Items ?? Array.Empty<TOption>()) |
| 151 | + @FooterContent(Items ?? Array.Empty<TOption>()) |
152 | 152 | }
|
153 | 153 | </FluentAnchoredRegion>
|
154 | 154 | }
|
|
174 | 174 | {
|
175 | 175 | var optionValue = GetOptionValue(context.Item);
|
176 | 176 | <FluentOption TOption="TOption"
|
177 |
| - @key="@context.Item" |
178 |
| - Value="@optionValue" |
179 |
| - Style="@OptionStyle" |
180 |
| - Class="@OptionClass" |
181 |
| - Selected="@GetOptionSelected(context.Item)" |
182 |
| - Disabled="@(GetOptionDisabled(context.Item) ?? false)" |
183 |
| - OnSelect="@OnSelectCallback(context.Item)" |
184 |
| - aria-selected="@(GetOptionSelected(context.Item) || optionValue == context.SelectableItem ? "true" : "false")" |
185 |
| - selectable="@(optionValue == context.SelectableItem)"> |
| 177 | + @key="@context.Item" |
| 178 | + Value="@optionValue" |
| 179 | + Style="@OptionStyle" |
| 180 | + Class="@OptionClass" |
| 181 | + Selected="@GetOptionSelected(context.Item)" |
| 182 | + Disabled="@(GetOptionDisabled(context.Item) ?? false)" |
| 183 | + OnSelect="@OnSelectCallback(context.Item)" |
| 184 | + aria-selected="@(GetOptionSelected(context.Item) || optionValue == context.SelectableItem ? "true" : "false")" |
| 185 | + selectable="@(optionValue == context.SelectableItem)"> |
186 | 186 | @if (OptionTemplate == null)
|
187 | 187 | {
|
188 | 188 | @GetOptionText(context.Item)
|
|
196 | 196 |
|
197 | 197 | private RenderFragment RenderSelectedOptions => __builder =>
|
198 | 198 | {
|
199 |
| - if (SelectedOptions != null) |
| 199 | + var selectedOptions = new List<TOption>(); |
| 200 | + if (Multiple && (SelectedOptions?.Any() ?? false)) |
| 201 | + { |
| 202 | + selectedOptions.AddRange(SelectedOptions); |
| 203 | + } |
| 204 | + if (!Multiple && SelectedOption is not null) |
200 | 205 | {
|
201 |
| - foreach (var item in SelectedOptions) |
| 206 | + selectedOptions.Add(SelectedOption); |
| 207 | + } |
| 208 | + |
| 209 | + if (selectedOptions.Any()) |
| 210 | + { |
| 211 | + foreach (var item in selectedOptions) |
202 | 212 | {
|
203 | 213 | if (SelectedOptionTemplate == null)
|
204 | 214 | {
|
205 | 215 | var text = @GetOptionText(item);
|
206 | 216 |
|
207 |
| - if (ReadOnly || Disabled) |
| 217 | + if (Multiple == false) |
| 218 | + { |
| 219 | + <FluentLabel tabindex="0" aria-label="@GetOptionText(item)" role="checkbox" aria-checked="true">@text</FluentLabel> |
| 220 | + } |
| 221 | + else if (ReadOnly || Disabled) |
208 | 222 | {
|
209 | 223 | <FluentBadge Appearance="@AspNetCore.Components.Appearance.Neutral"
|
210 |
| - aria-label="@GetOptionText(item)"> |
| 224 | + aria-label="@GetOptionText(item)"> |
211 | 225 | @text
|
212 | 226 | </FluentBadge>
|
213 | 227 | }
|
214 | 228 | else
|
215 | 229 | {
|
216 | 230 | <FluentBadge Appearance="@AspNetCore.Components.Appearance.Neutral"
|
217 |
| - OnDismissClick="@(e => RemoveSelectedItemAsync(item))" |
218 |
| - DismissTitle="@(string.Format(AccessibilityRemoveItem, text))" |
219 |
| - aria-label="@GetOptionText(item)"> |
| 231 | + OnDismissClick="@(e => RemoveSelectedItemAsync(item))" |
| 232 | + DismissTitle="@(string.Format(AccessibilityRemoveItem, text))" |
| 233 | + aria-label="@GetOptionText(item)"> |
220 | 234 | @text
|
221 | 235 | </FluentBadge>
|
222 | 236 | }
|
|
0 commit comments