Skip to content

Commit

Permalink
[HxMultiSelect] Adds Floating Label type to MultiSelect component (#899)
Browse files Browse the repository at this point in the history
* Adds Floating label type to MultiSelect

* Adds floating label type to MultiSelect

* reverted basic demo + separate testing page

* CSS class moved to outermost element, CssClassHelper usage

* RenderOrder override consolidation

* HxFormValueComponentRenderer_Label usage (instead of direct <label> rendering)

* doc - add HxMultiSelect to list of components supporting floating labels

---------

Co-authored-by: Robert Haken <[email protected]>
  • Loading branch information
mmonteagudo and hakenr authored Nov 26, 2024
1 parent 8aa6521 commit 0c99e76
Show file tree
Hide file tree
Showing 7 changed files with 108 additions and 15 deletions.
24 changes: 23 additions & 1 deletion Havit.Blazor.Components.Web.Bootstrap/Forms/HxMultiSelect.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ namespace Havit.Blazor.Components.Web.Bootstrap;
/// </summary>
/// <typeparam name="TValue">Type of values.</typeparam>
/// <typeparam name="TItem">Type of items.</typeparam>
public class HxMultiSelect<TValue, TItem> : HxInputBase<List<TValue>>, IInputWithSize
public class HxMultiSelect<TValue, TItem> : HxInputBase<List<TValue>>, IInputWithSize, IInputWithLabelType
{
/// <summary>
/// Return <see cref="HxMultiSelect{TValue, TItem}"/> defaults.
Expand Down Expand Up @@ -161,6 +161,26 @@ public class HxMultiSelect<TValue, TItem> : HxInputBase<List<TValue>>, IInputWit
[Parameter] public IconBase FilterClearIcon { get; set; }
protected IconBase FilterClearIconEffective => FilterClearIcon ?? GetSettings()?.FilterClearIcon ?? GetDefaults().FilterClearIcon;

/// <inheritdoc cref="Bootstrap.LabelType" />
[Parameter] public LabelType? LabelType { get; set; }
protected LabelType LabelTypeEffective => LabelType ?? GetSettings()?.LabelType ?? GetDefaults()?.LabelType ?? HxSetup.Defaults.LabelType;
LabelType IInputWithLabelType.LabelTypeEffective => LabelTypeEffective;
protected override LabelValueRenderOrder RenderOrder
{
get
{
if (LabelTypeEffective == Bootstrap.LabelType.Floating)
{
// Floating label type renders the label in HxMultiSelectInternal component.
return LabelValueRenderOrder.ValueOnly;
}
else
{
return LabelValueRenderOrder.LabelValue;
}
}
}

private List<TItem> _itemsToRender;
private HxMultiSelectInternal<TValue, TItem> _hxMultiSelectInternalComponent;

Expand Down Expand Up @@ -212,6 +232,8 @@ protected override void BuildRenderInput(RenderTreeBuilder builder)
builder.AddAttribute(102, nameof(HxMultiSelectInternal<TValue, TItem>.InputCssClass), GetInputCssClassToRender());
builder.AddAttribute(103, nameof(HxMultiSelectInternal<TValue, TItem>.InputText), GetInputText());
builder.AddAttribute(104, nameof(HxMultiSelectInternal<TValue, TItem>.EnabledEffective), EnabledEffective);
builder.AddAttribute(125, nameof(HxMultiSelectInternal<TValue, TItem>.LabelTypeEffective), LabelTypeEffective);
builder.AddAttribute(126, nameof(HxMultiSelectInternal<TValue, TItem>.FormValueComponent), this);
builder.AddAttribute(105, nameof(HxMultiSelectInternal<TValue, TItem>.ItemsToRender), _itemsToRender);
builder.AddAttribute(106, nameof(HxMultiSelectInternal<TValue, TItem>.TextSelector), TextSelector);
builder.AddAttribute(107, nameof(HxMultiSelectInternal<TValue, TItem>.ValueSelector), ValueSelector);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
bool enabled = EnabledEffective && (ItemsToRender != null);
}
<div class="@CssClassHelper.Combine("hx-multi-select",
HasInputGroups ? "input-group" : null,
HasInputGroups ? "input-group" : null,
HasInputGroupEnd ? "input-group-end" : null,
HasInputGroupStart ? "input-group-start" : null,
InputGroupCssClass)">
Expand All @@ -16,19 +16,26 @@
}

@InputGroupStartTemplate
<div @ref="_elementReference" class="dropdown" role="listbox">
<div @ref="_elementReference"
class="@CssClassHelper.Combine("dropdown", (LabelTypeEffective == LabelType.Floating) ? "form-floating": null)"
role="listbox">

<input @ref="_inputElementReference"
type="text"
id="@InputId"
class="@InputCssClass"
value="@(((ItemsToRender == null) && !String.IsNullOrEmpty(NullDataText)) ? NullDataText : InputText)"
disabled="@(!enabled)"
readonly="true"
aria-expanded="@_isShown"
data-bs-toggle="@(enabled ? "dropdown" : null)"
data-bs-auto-close="outside"
@attributes="this.AdditionalAttributes" />
type="text"
id="@InputId"
class="@InputCssClass"
value="@(((ItemsToRender == null) && !String.IsNullOrEmpty(NullDataText)) ? NullDataText : InputText)"
disabled="@(!enabled)"
readonly="true"
aria-expanded="@_isShown"
data-bs-toggle="@(enabled ? "dropdown" : null)"
data-bs-auto-close="outside"
@attributes="this.AdditionalAttributes" />

@if (LabelTypeEffective == LabelType.Floating)
{
<HxFormValueComponentRenderer_Label FormValueComponent="@FormValueComponent" />
}

@* Must be always rendered otherwise does not work after disable->enabled scenario *@
<ul class="@CssClassHelper.Combine("dropdown-menu", _isShown ? "show" : null)">
Expand All @@ -45,7 +52,7 @@
autocomplete="off"
value="@_filterText"
@oninput="HandleFilterInputChanged"
@onclick:stopPropagation
@onclick:stopPropagation
onfocusin="this.select()" />

<div class="hx-multi-select-filter-input-icon">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,12 @@ public partial class HxMultiSelectInternal<TValue, TItem> : IAsyncDisposable

[Parameter] public string InputText { get; set; }

[Parameter] public IFormValueComponent FormValueComponent { get; set; }

[Parameter] public bool EnabledEffective { get; set; }

[Parameter] public LabelType LabelTypeEffective { get; set; }

[Parameter] public List<TItem> ItemsToRender { get; set; }

[Parameter] public List<TValue> SelectedValues { get; set; }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,11 @@ public record MultiSelectSettings : InputSettings
/// </summary>
public InputSize? InputSize { get; set; }

/// <summary>
/// The label type.
/// </summary>
public LabelType? LabelType { get; set; }

/// <summary>
/// Enables filtering capabilities.
/// </summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,9 @@
<p>
Floating labels provide a sleek and simple design, floating elegantly over your input fields.
See <a href="https://getbootstrap.com/docs/5.3/forms/floating-labels/">Bootstrap 5 documentation on Floating labels</a>.<br />
They are supported by <code>HxInputText</code>, <code>HxInputTextArea</code>, <code>HxInputNumber</code>, <code>HxInputDate</code>, <code>HxAutosuggest</code>, <code>HxSelect</code>, and <code>HxInputTags</code>.
They are supported by <code>HxInputText</code>, <code>HxInputTextArea</code>,
<code>HxInputNumber</code>, <code>HxInputDate</code>, <code>HxAutosuggest</code>,
<code>HxSelect</code>, <code>HxMultiSelect</code> and <code>HxInputTags</code>.
</p>
<DocAlert Type="DocAlertType.Warning">
Inputs with floating labels can't have the <code>Placeholder</code> parameter set.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4699,6 +4699,9 @@
Icon displayed in filter input for clearing the filter.
</summary>
</member>
<member name="P:Havit.Blazor.Components.Web.Bootstrap.HxMultiSelect`2.LabelType">
<inheritdoc cref="T:Havit.Blazor.Components.Web.Bootstrap.LabelType" />
</member>
<member name="M:Havit.Blazor.Components.Web.Bootstrap.HxMultiSelect`2.FocusAsync">
<inheritdoc cref="M:Havit.Blazor.Components.Web.Bootstrap.HxInputBase`1.FocusAsync"/>
</member>
Expand Down Expand Up @@ -5429,6 +5432,11 @@
Input size.
</summary>
</member>
<member name="P:Havit.Blazor.Components.Web.Bootstrap.MultiSelectSettings.LabelType">
<summary>
The label type.
</summary>
</member>
<member name="P:Havit.Blazor.Components.Web.Bootstrap.MultiSelectSettings.AllowFiltering">
<summary>
Enables filtering capabilities.
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
@page "/HxMultiSelect_FloatingLabel"
@rendermode InteractiveServer
@inject IDemoDataService DemoDataService

<div class="m-3">

<HxMultiSelect Label="HxMultiSelect"
TItem="EmployeeDto"
TValue="int"
Data="@employees"
LabelType="LabelType.Floating"
@bind-Value="selectedEmployeeIds"
TextSelector="@(p => p.Name)"
ValueSelector="@(p => p.Id)"
NullDataText="Loading employees..."
EmptyText="-select employees-" />

For visual reference:
<HxSelect TItem="EmployeeDto"
TValue="int?"
Label="HxSelect"
LabelType="LabelType.Floating"
Data="employees"
@bind-Value="selectedEmployeeId"
TextSelector="@(employee => employee.Name)"
ValueSelector="@(employee => employee.Id)"
Nullable="true"
NullText="-select employee-"
NullDataText="Loading employees..." />

</div>


<p class="mt-3">Selected employees (IDs): @String.Join(", ", selectedEmployeeIds.Select(e => e.ToString()))</p>

@code {
private IEnumerable<EmployeeDto> employees;
private List<int> selectedEmployeeIds = new();
private int? selectedEmployeeId;

protected override async Task OnInitializedAsync()
{
employees = await DemoDataService.GetAllEmployeesAsync();
}
}

0 comments on commit 0c99e76

Please sign in to comment.