Rework select component (#14)
Reviewed-on: #14
This commit was merged in pull request #14.
This commit is contained in:
@@ -1,15 +0,0 @@
|
||||
using GameIdeas.BlazorApp.Shared.Components.Select.Models;
|
||||
using Microsoft.AspNetCore.Components;
|
||||
|
||||
namespace GameIdeas.BlazorApp.Shared.Components.Select.Components;
|
||||
|
||||
public partial class SelectListElement<TItem>
|
||||
{
|
||||
[Parameter] public EventCallback<SelectElement<TItem>?> ValueChanged { get; set; }
|
||||
[Parameter] public SelectElement<TItem>? Value { get; set; }
|
||||
[Parameter] public SelectListTheme Theme { get; set; }
|
||||
private async Task HandleItemClicked()
|
||||
{
|
||||
await ValueChanged.InvokeAsync(Value);
|
||||
}
|
||||
}
|
||||
@@ -1,81 +0,0 @@
|
||||
.select-element {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
width: auto;
|
||||
gap: 6px;
|
||||
height: 20px;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.select-element:hover {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.selected {
|
||||
width: 12px;
|
||||
min-width: 12px;
|
||||
height: 12px;
|
||||
min-height: 12px;
|
||||
border: 1px solid var(--line);
|
||||
}
|
||||
|
||||
.selected svg {
|
||||
display: block;
|
||||
fill: var(--white)
|
||||
}
|
||||
|
||||
/***** Navigation Theme *****/
|
||||
.navigation {
|
||||
padding: 4px 8px;
|
||||
}
|
||||
.navigation:hover {
|
||||
background: var(--violet-selected);
|
||||
}
|
||||
|
||||
.navigation .selected {
|
||||
display: none;
|
||||
}
|
||||
|
||||
/***** Sort Theme *****/
|
||||
.sort {
|
||||
padding: 2px 6px;
|
||||
}
|
||||
|
||||
.sort:hover {
|
||||
background: var(--input-selected);
|
||||
}
|
||||
|
||||
.sort .select-label {
|
||||
text-wrap: nowrap;
|
||||
margin-right: 6px;
|
||||
}
|
||||
|
||||
/***** Filter Theme *****/
|
||||
.filter {
|
||||
padding: 2px 6px;
|
||||
}
|
||||
|
||||
.filter:hover {
|
||||
background: var(--input-selected);
|
||||
}
|
||||
|
||||
.filter .select-label {
|
||||
text-wrap: nowrap;
|
||||
margin-right: 6px;
|
||||
}
|
||||
|
||||
/***** Advanced Filter Theme *****/
|
||||
.advancedfilter {
|
||||
padding: 2px 6px;
|
||||
}
|
||||
|
||||
.advancedfilter:hover {
|
||||
background: var(--input-selected);
|
||||
}
|
||||
|
||||
.advancedfilter .select-label {
|
||||
text-wrap: nowrap;
|
||||
margin-right: 6px;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,15 +1,16 @@
|
||||
@typeparam TItem
|
||||
@using GameIdeas.BlazorApp.Shared.Components.Select.Helpers
|
||||
|
||||
<div class="select-element @(Enum.GetName(Theme)?.ToLower())" @onclick=HandleItemClicked>
|
||||
<div class="select-element @SelectHelper.GetClassFromTheme(Theme)"
|
||||
@onclick=HandleElementClicked>
|
||||
<div class="selected">
|
||||
@if (Value != null && Value.IsSelected)
|
||||
@if (IsSelected == true)
|
||||
{
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
|
||||
<path d="M9,20.42L2.79,14.21L5.62,11.38L9,14.77L18.88,4.88L21.71,7.71L9,20.42Z" />
|
||||
</svg>
|
||||
}
|
||||
</div>
|
||||
<div class="select-label">
|
||||
@Value?.Label
|
||||
<div class="label">
|
||||
@Label
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -0,0 +1,16 @@
|
||||
using GameIdeas.BlazorApp.Shared.Components.Select.Models;
|
||||
using Microsoft.AspNetCore.Components;
|
||||
|
||||
namespace GameIdeas.BlazorApp.Shared.Components.Select.Components;
|
||||
|
||||
public partial class SelectRow
|
||||
{
|
||||
[Parameter] public bool? IsSelected { get; set; }
|
||||
[Parameter] public string? Label { get; set; }
|
||||
[Parameter] public SelectTheme Theme { get; set; }
|
||||
[Parameter] public EventCallback OnClick { get; set; }
|
||||
private async Task HandleElementClicked()
|
||||
{
|
||||
await OnClick.InvokeAsync();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
.select-element {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
width: auto;
|
||||
gap: 6px;
|
||||
height: 20px;
|
||||
align-items: center;
|
||||
padding: 2px 6px;
|
||||
}
|
||||
|
||||
.select-element:hover {
|
||||
cursor: pointer;
|
||||
background: var(--input-selected);
|
||||
}
|
||||
|
||||
.selected {
|
||||
width: 12px;
|
||||
min-width: 12px;
|
||||
height: 12px;
|
||||
min-height: 12px;
|
||||
border: 1px solid var(--line);
|
||||
}
|
||||
|
||||
.selected svg {
|
||||
display: block;
|
||||
fill: var(--white)
|
||||
}
|
||||
|
||||
.label {
|
||||
text-wrap: nowrap;
|
||||
margin-right: 6px;
|
||||
}
|
||||
|
||||
/***** Navigation Theme *****/
|
||||
.navigation {
|
||||
padding: 4px 8px;
|
||||
}
|
||||
|
||||
.navigation:hover {
|
||||
background: var(--violet-selected);
|
||||
}
|
||||
|
||||
.navigation .selected {
|
||||
display: none;
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
using GameIdeas.BlazorApp.Shared.Components.Select.Models;
|
||||
|
||||
namespace GameIdeas.BlazorApp.Shared.Components.Select.Helpers;
|
||||
|
||||
public static class SelectHelper
|
||||
{
|
||||
public static string GetClassFromTheme(SelectTheme selectTheme)
|
||||
{
|
||||
return selectTheme switch
|
||||
{
|
||||
SelectTheme.Navigation => "navigation",
|
||||
SelectTheme.Sort => "sort",
|
||||
SelectTheme.Filter => "filter",
|
||||
SelectTheme.AdvancedFilter => "advanced-filter",
|
||||
SelectTheme.Creation => "creation",
|
||||
_ => string.Empty
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -1,9 +0,0 @@
|
||||
namespace GameIdeas.BlazorApp.Shared.Components.Select.Models;
|
||||
|
||||
public class SelectElement<TItem>(TItem item, string? label)
|
||||
{
|
||||
public TItem Item { get; set; } = item;
|
||||
public string? Label { get; set; } = label;
|
||||
public bool IsSelected { get; set; } = false;
|
||||
public bool IsNew { get; set; } = false;
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
namespace GameIdeas.BlazorApp.Shared.Components.Select.Models;
|
||||
|
||||
public class SelectParams<TItem, THeader>
|
||||
{
|
||||
public List<TItem> Items { get; set; } = [];
|
||||
public TItem? DefaultItem { get; set; }
|
||||
public Func<TItem, string> GetItemLabel { get; set; } = _ => string.Empty;
|
||||
public List<THeader> Headers { get; set; } = [];
|
||||
public THeader? DefaultHeader { get; set; }
|
||||
public Func<THeader, string> GetHeaderLabel { get; set; } = _ => string.Empty;
|
||||
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
namespace GameIdeas.BlazorApp.Shared.Components.Select.Models;
|
||||
|
||||
public enum SelectListTheme
|
||||
public enum SelectTheme
|
||||
{
|
||||
Navigation,
|
||||
Sort,
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
namespace GameIdeas.BlazorApp.Shared.Components.Select.Models;
|
||||
|
||||
public enum SelectType
|
||||
{
|
||||
Single,
|
||||
Multiple
|
||||
}
|
||||
@@ -1,35 +0,0 @@
|
||||
@using GameIdeas.BlazorApp.Shared.Components.BackdropFilter
|
||||
@using GameIdeas.BlazorApp.Shared.Components.Search
|
||||
@using GameIdeas.BlazorApp.Shared.Components.Select.Components
|
||||
@typeparam TItem
|
||||
|
||||
<div class="select-list">
|
||||
<div class="select-button @(Enum.GetName(Theme)?.ToLower())">
|
||||
<SearchInput @ref=SearchInput
|
||||
Icon="SearchInputIcon.Dropdown"
|
||||
Placeholder="@Placeholder"
|
||||
TextChanged="HandleTextChanged"
|
||||
ClearClicked="HandleTextChanged"
|
||||
SearchClicked="HandleSearchClicked"
|
||||
FocusIn="HandleTextFocusIn"/>
|
||||
</div>
|
||||
<div class="select-container">
|
||||
|
||||
@if (IsContentOpen)
|
||||
{
|
||||
<div class="select-content @(Enum.GetName(Theme)?.ToLower())">
|
||||
@foreach (var item in Items)
|
||||
{
|
||||
<SelectListElement TItem="TItem"
|
||||
Value="item"
|
||||
ValueChanged="HandleItemClicked"
|
||||
Theme="Theme" />
|
||||
}
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<BackdropFilter AllowBodyScroll=true CloseOnClick=true Color="BackdropFilterColor.Transparent"
|
||||
IsVisible=IsContentOpen OnClick="HandleContentClosed" />
|
||||
|
||||
@@ -1,65 +0,0 @@
|
||||
using GameIdeas.BlazorApp.Shared.Components.Search;
|
||||
using GameIdeas.BlazorApp.Shared.Components.Select.Models;
|
||||
using Microsoft.AspNetCore.Components;
|
||||
using Microsoft.JSInterop;
|
||||
|
||||
namespace GameIdeas.BlazorApp.Shared.Components.Select;
|
||||
|
||||
public partial class MultipleSelectList<TItem>
|
||||
{
|
||||
[Inject] IJSRuntime JS { get; set; } = default!;
|
||||
[Parameter] public IEnumerable<TItem>? Values { get; set; }
|
||||
[Parameter] public EventCallback<IEnumerable<TItem>?> ValuesChanged { get; set; }
|
||||
[Parameter] public IEnumerable<SelectElement<TItem>> Items { get; set; } = [];
|
||||
[Parameter] public SelectListTheme Theme { get; set; }
|
||||
[Parameter] public bool AlignRight { get; set; }
|
||||
[Parameter] public string? Placeholder { get; set; }
|
||||
|
||||
private bool IsContentOpen = false;
|
||||
private SearchInput? SearchInput;
|
||||
|
||||
|
||||
protected override async Task OnAfterRenderAsync(bool firstRender)
|
||||
{
|
||||
await JS.InvokeVoidAsync("addResizeListener");
|
||||
|
||||
await base.OnAfterRenderAsync(firstRender);
|
||||
}
|
||||
|
||||
private async Task HandleItemClicked(SelectElement<TItem> selectedValue)
|
||||
{
|
||||
selectedValue.IsSelected = !selectedValue.IsSelected;
|
||||
|
||||
Values = Items.Where(x => x.IsSelected && x.Item != null).Select(x => x.Item!);
|
||||
SearchInput?.SetText(string.Join(", ", Values));
|
||||
|
||||
await ValuesChanged.InvokeAsync(Values);
|
||||
StateHasChanged();
|
||||
}
|
||||
|
||||
private async Task HandleTextChanged()
|
||||
{
|
||||
IsContentOpen = false;
|
||||
|
||||
foreach (var item in Items)
|
||||
{
|
||||
item.IsSelected = false;
|
||||
}
|
||||
|
||||
Values = Items.Where(x => x.IsSelected && x.Item != null).Select(x => x.Item!);
|
||||
await ValuesChanged.InvokeAsync(Values);
|
||||
}
|
||||
|
||||
private void HandleSearchClicked()
|
||||
{
|
||||
IsContentOpen = !IsContentOpen;
|
||||
}
|
||||
private void HandleContentClosed()
|
||||
{
|
||||
IsContentOpen = false;
|
||||
}
|
||||
private void HandleTextFocusIn()
|
||||
{
|
||||
IsContentOpen = true;
|
||||
}
|
||||
}
|
||||
@@ -1,72 +0,0 @@
|
||||
.select-list {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.select-container {
|
||||
overflow: auto;
|
||||
right: 0;
|
||||
min-width: 100%;
|
||||
margin-top: 4px;
|
||||
position: absolute;
|
||||
z-index: var(--index-dropdown);
|
||||
border-radius: var(--small-radius);
|
||||
}
|
||||
|
||||
.select-content {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
animation-name: fade-in;
|
||||
animation-duration: 0.4s;
|
||||
background: var(--dropdown-content);
|
||||
box-shadow: var(--drop-shadow);
|
||||
padding: 4px 0;
|
||||
}
|
||||
|
||||
.select-button {
|
||||
z-index: var(--index-component)
|
||||
}
|
||||
|
||||
.line {
|
||||
margin: 2px 6px;
|
||||
border-bottom: 2px solid var(--input-selected);
|
||||
}
|
||||
/* Advanced filter */
|
||||
::deep .select-button.advancedfilter .search-container {
|
||||
height: 24px;
|
||||
background: var(--input-secondary);
|
||||
}
|
||||
|
||||
::deep .select-button.advancedfilter .search-container input::placeholder {
|
||||
color: #bbb;
|
||||
}
|
||||
|
||||
/* Creation */
|
||||
::deep .select-button.creation .search-container {
|
||||
height: 24px;
|
||||
background: var(--input-secondary);
|
||||
border: solid 1px var(--input-selected);
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
/* width */
|
||||
.select-container::-webkit-scrollbar {
|
||||
width: 10px;
|
||||
}
|
||||
|
||||
/* Track */
|
||||
.select-container::-webkit-scrollbar-track {
|
||||
background: var(--input-secondary);
|
||||
border-radius: 0 var(--small-radius) var(--small-radius) 0;
|
||||
}
|
||||
|
||||
/* Handle */
|
||||
.select-container::-webkit-scrollbar-thumb {
|
||||
background: #555;
|
||||
border-radius: var(--small-radius);
|
||||
}
|
||||
|
||||
/* Handle on hover */
|
||||
.select-container::-webkit-scrollbar-thumb:hover {
|
||||
background: #777;
|
||||
}
|
||||
|
||||
@@ -1,19 +0,0 @@
|
||||
function offset(el) {
|
||||
var rect = el.getBoundingClientRect(),
|
||||
scrollLeft = window.scrollY || document.documentElement.scrollLeft,
|
||||
scrollTop = window.scrollX || document.documentElement.scrollTop;
|
||||
return { top: rect.top + scrollTop, left: rect.left + scrollLeft }
|
||||
}
|
||||
|
||||
function resizeSelectContent() {
|
||||
const height = window.innerHeight;
|
||||
const selects = document.getElementsByClassName('select-container');
|
||||
for (var i = 0; i < selects.length; i++) {
|
||||
selects[i].style.maxHeight = height - offset(selects[i]).top - 10 + "px";
|
||||
}
|
||||
}
|
||||
|
||||
window.addResizeListener = () => {
|
||||
resizeSelectContent();
|
||||
window.addEventListener('resize', resizeSelectContent);
|
||||
};
|
||||
@@ -0,0 +1,47 @@
|
||||
@using GameIdeas.BlazorApp.Shared.Components.BackdropFilter
|
||||
@using GameIdeas.BlazorApp.Shared.Components.Select.Components
|
||||
@using GameIdeas.BlazorApp.Shared.Components.Select.Helpers
|
||||
|
||||
@typeparam TItem
|
||||
@typeparam THeader
|
||||
|
||||
<div class="select-container">
|
||||
<div class="button" @onclick=HandleButtonClicked>
|
||||
@ChildContent
|
||||
</div>
|
||||
|
||||
<div class="dropdown @SelectHelper.GetClassFromTheme(Theme)">
|
||||
@if (IsContentOpen)
|
||||
{
|
||||
<div class="content">
|
||||
@if (Params.Headers != null)
|
||||
{
|
||||
@foreach (var header in Params.Headers)
|
||||
{
|
||||
<SelectRow IsSelected=HeaderValues?.Contains(header)
|
||||
Label="@Params.GetHeaderLabel(header)" Theme=Theme
|
||||
OnClick="_ => HandleHeaderClicked(header)" />
|
||||
}
|
||||
}
|
||||
|
||||
@if (Params.Headers?.Any() == true)
|
||||
{
|
||||
<span class="line"></span>
|
||||
}
|
||||
|
||||
@if (Params.Items != null)
|
||||
{
|
||||
@foreach (var item in Params.Items)
|
||||
{
|
||||
<SelectRow IsSelected=Values?.Contains(item)
|
||||
Label="@Params.GetItemLabel(item)" Theme=Theme
|
||||
OnClick="_ => HandleValueClicked(item)" />
|
||||
}
|
||||
}
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<BackdropFilter AllowBodyScroll=true CloseOnClick=true Color="BackdropFilterColor.Transparent"
|
||||
IsVisible=IsContentOpen OnClick="HandleContentClosed" />
|
||||
@@ -0,0 +1,85 @@
|
||||
using GameIdeas.BlazorApp.Shared.Components.Select.Models;
|
||||
using Microsoft.AspNetCore.Components;
|
||||
|
||||
namespace GameIdeas.BlazorApp.Shared.Components.Select;
|
||||
|
||||
public partial class Select<TItem, THeader>
|
||||
{
|
||||
[Parameter] public RenderFragment? ChildContent { get; set; }
|
||||
[Parameter] public List<TItem> Values { get; set; } = [];
|
||||
[Parameter] public EventCallback<IEnumerable<TItem>> ValuesChanged { get; set; }
|
||||
[Parameter] public List<THeader> HeaderValues { get; set; } = [];
|
||||
[Parameter] public EventCallback<IEnumerable<THeader>> HeaderValuesChanged { get; set; }
|
||||
[Parameter] public SelectParams<TItem, THeader> Params { get; set; } = new();
|
||||
[Parameter] public SelectTheme Theme { get; set; }
|
||||
[Parameter] public SelectType Type { get; set; } = SelectType.Single;
|
||||
[Parameter] public bool DisableClicked { get; set; } = false;
|
||||
|
||||
private bool IsContentOpen = false;
|
||||
|
||||
public void Close() =>
|
||||
IsContentOpen = false;
|
||||
|
||||
public void Open() =>
|
||||
IsContentOpen = true;
|
||||
|
||||
private void HandleButtonClicked()
|
||||
{
|
||||
if (!DisableClicked)
|
||||
IsContentOpen = !IsContentOpen;
|
||||
}
|
||||
|
||||
private void HandleContentClosed() =>
|
||||
IsContentOpen = false;
|
||||
|
||||
protected override void OnInitialized()
|
||||
{
|
||||
if (Params.DefaultItem != null)
|
||||
{
|
||||
Values.Add(Params.DefaultItem);
|
||||
}
|
||||
|
||||
if (Params.DefaultHeader != null)
|
||||
{
|
||||
HeaderValues.Add(Params.DefaultHeader);
|
||||
}
|
||||
}
|
||||
|
||||
private async Task HandleValueClicked(TItem value)
|
||||
{
|
||||
if (Type != SelectType.Multiple || Values == null)
|
||||
{
|
||||
Values = [];
|
||||
}
|
||||
|
||||
if (Values?.Contains(value) == true)
|
||||
{
|
||||
Values.Remove(value);
|
||||
}
|
||||
else
|
||||
{
|
||||
Values!.Add(value);
|
||||
}
|
||||
|
||||
await ValuesChanged.InvokeAsync(Values);
|
||||
}
|
||||
|
||||
private async Task HandleHeaderClicked(THeader header)
|
||||
{
|
||||
if (Type != SelectType.Multiple || HeaderValues == null)
|
||||
{
|
||||
HeaderValues = [];
|
||||
}
|
||||
|
||||
if (HeaderValues?.Contains(header) == true)
|
||||
{
|
||||
HeaderValues.Remove(header);
|
||||
}
|
||||
else
|
||||
{
|
||||
HeaderValues!.Add(header);
|
||||
}
|
||||
|
||||
await HeaderValuesChanged.InvokeAsync(HeaderValues);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,75 @@
|
||||
.select-container {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.button {
|
||||
z-index: var(--index-component)
|
||||
}
|
||||
|
||||
.dropdown {
|
||||
overflow: auto;
|
||||
margin-top: 4px;
|
||||
position: absolute;
|
||||
z-index: var(--index-dropdown);
|
||||
border-radius: var(--small-radius);
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.content {
|
||||
background: var(--dropdown-content);
|
||||
overflow: hidden;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
animation-name: fade-in;
|
||||
animation-duration: 0.2s;
|
||||
box-shadow: var(--drop-shadow);
|
||||
}
|
||||
|
||||
.line {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.dropdown::-webkit-scrollbar {
|
||||
width: 10px;
|
||||
}
|
||||
|
||||
.dropdown::-webkit-scrollbar-track {
|
||||
background: var(--input-secondary);
|
||||
border-radius: 0 var(--small-radius) var(--small-radius) 0;
|
||||
}
|
||||
|
||||
.dropdown::-webkit-scrollbar-thumb {
|
||||
background: #555;
|
||||
border-radius: var(--small-radius);
|
||||
}
|
||||
|
||||
.dropdown::-webkit-scrollbar-thumb:hover {
|
||||
background: #777;
|
||||
}
|
||||
|
||||
/***** Navigation Theme *****/
|
||||
.dropdown.navigation {
|
||||
width: auto;
|
||||
right: 0;
|
||||
}
|
||||
|
||||
.navigation .content {
|
||||
background: var(--violet);
|
||||
}
|
||||
|
||||
/***** Sort Theme *****/
|
||||
.dropdown.sort {
|
||||
width: auto;
|
||||
}
|
||||
|
||||
.sort .content {
|
||||
padding: 4px 0;
|
||||
}
|
||||
|
||||
.sort .content .line {
|
||||
display: block;
|
||||
margin: 2px 6px;
|
||||
border-bottom: 2px solid var(--input-selected);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,40 +0,0 @@
|
||||
@using GameIdeas.BlazorApp.Shared.Components.BackdropFilter
|
||||
@using GameIdeas.BlazorApp.Shared.Components.Select.Components
|
||||
@typeparam TItem
|
||||
@typeparam THeader
|
||||
|
||||
<div class="select-list">
|
||||
<div class="select-button" @onclick=HandleButtonClicked>
|
||||
@ChildContent
|
||||
</div>
|
||||
|
||||
<div class="select-container @(AlignRight ? "align-right" : "")">
|
||||
@if (IsContentOpen)
|
||||
{
|
||||
<div class="select-content @(Enum.GetName(Theme)?.ToLower())">
|
||||
@foreach (var header in Headers)
|
||||
{
|
||||
<SelectListElement TItem="THeader"
|
||||
Value="header"
|
||||
ValueChanged="HandleHeaderClicked"
|
||||
Theme="Theme" />
|
||||
}
|
||||
@if (Headers.Any())
|
||||
{
|
||||
<span class="line"></span>
|
||||
}
|
||||
@foreach (var item in Items)
|
||||
{
|
||||
<SelectListElement TItem="TItem"
|
||||
Value="item"
|
||||
ValueChanged="HandleItemClicked"
|
||||
Theme="Theme" />
|
||||
}
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<BackdropFilter AllowBodyScroll=true CloseOnClick=true Color="BackdropFilterColor.Transparent"
|
||||
IsVisible=IsContentOpen OnClick="HandleContentClosed" />
|
||||
|
||||
@@ -1,56 +0,0 @@
|
||||
using GameIdeas.BlazorApp.Shared.Components.Select.Models;
|
||||
using Microsoft.AspNetCore.Components;
|
||||
|
||||
namespace GameIdeas.BlazorApp.Shared.Components.Select;
|
||||
|
||||
public partial class SelectList<TItem, THeader>
|
||||
{
|
||||
[Parameter] public RenderFragment? ChildContent { get; set; }
|
||||
[Parameter] public TItem? Value { get; set; }
|
||||
[Parameter] public EventCallback<TItem?> ValueChanged { get; set; }
|
||||
[Parameter] public THeader? Header { get; set; }
|
||||
[Parameter] public EventCallback<THeader?> HeaderChanged { get; set; }
|
||||
[Parameter] public IEnumerable<SelectElement<TItem>> Items { get; set; } = [];
|
||||
[Parameter] public IEnumerable<SelectElement<THeader>> Headers { get; set; } = [];
|
||||
[Parameter] public SelectListTheme Theme { get; set; }
|
||||
[Parameter] public bool AlignRight { get; set; }
|
||||
|
||||
private bool IsContentOpen = false;
|
||||
|
||||
public void Close() =>
|
||||
IsContentOpen = false;
|
||||
|
||||
private void HandleButtonClicked() =>
|
||||
IsContentOpen = !IsContentOpen;
|
||||
|
||||
private void HandleContentClosed()
|
||||
{
|
||||
IsContentOpen = false;
|
||||
}
|
||||
|
||||
private async Task HandleItemClicked(SelectElement<TItem> selectedValue)
|
||||
{
|
||||
foreach (var item in Items)
|
||||
{
|
||||
item.IsSelected = false;
|
||||
}
|
||||
|
||||
selectedValue.IsSelected = true;
|
||||
|
||||
Value = selectedValue.Item;
|
||||
await ValueChanged.InvokeAsync(Value);
|
||||
}
|
||||
|
||||
private async Task HandleHeaderClicked(SelectElement<THeader> selectedValue)
|
||||
{
|
||||
foreach (var header in Headers)
|
||||
{
|
||||
header.IsSelected = false;
|
||||
}
|
||||
|
||||
selectedValue.IsSelected = true;
|
||||
|
||||
Header = selectedValue.Item;
|
||||
await HeaderChanged.InvokeAsync(Header);
|
||||
}
|
||||
}
|
||||
@@ -1,45 +0,0 @@
|
||||
.select-list {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.select-container {
|
||||
margin-top: 4px;
|
||||
position: absolute;
|
||||
z-index: var(--index-dropdown)
|
||||
}
|
||||
|
||||
.align-right {
|
||||
right: 0;
|
||||
}
|
||||
|
||||
.select-content {
|
||||
overflow: hidden;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
border-radius: var(--small-radius);
|
||||
animation-name: fade-in;
|
||||
animation-duration: 0.4s;
|
||||
}
|
||||
|
||||
.select-button {
|
||||
z-index: var(--index-component)
|
||||
}
|
||||
|
||||
.line {
|
||||
margin: 2px 6px;
|
||||
border-bottom: 2px solid var(--input-selected);
|
||||
}
|
||||
|
||||
|
||||
/***** Navigation Theme *****/
|
||||
.select-content.navigation {
|
||||
background: var(--violet);
|
||||
box-shadow: var(--drop-shadow);
|
||||
}
|
||||
|
||||
/***** Sort Theme *****/
|
||||
.select-content.sort {
|
||||
background: var(--dropdown-content);
|
||||
box-shadow: var(--drop-shadow);
|
||||
padding: 4px 0;
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
@using GameIdeas.BlazorApp.Shared.Components.Search
|
||||
@using GameIdeas.BlazorApp.Shared.Components.Select
|
||||
@using GameIdeas.BlazorApp.Shared.Components.Select.Helpers
|
||||
@using GameIdeas.BlazorApp.Shared.Components.Select.Models
|
||||
|
||||
@typeparam TItem
|
||||
|
||||
<Select @ref=Select TItem="TItem" THeader="string" Theme="Theme" Type="SelectType.Multiple" DisableClicked=true
|
||||
Params="SelectParams" Values=Values ValuesChanged="HandleValuesChanged">
|
||||
|
||||
<div class="@SelectHelper.GetClassFromTheme(Theme)">
|
||||
<SearchInput @ref=SearchInput Icon="SearchInputIcon.Dropdown" Placeholder="@Placeholder"
|
||||
TextChanged="HandleClearClicked" ClearClicked="HandleClearClicked"
|
||||
FocusIn="HandleFocusIn" SearchClicked="HandleFocusIn" />
|
||||
</div>
|
||||
|
||||
</Select>
|
||||
@@ -0,0 +1,46 @@
|
||||
using GameIdeas.BlazorApp.Shared.Components.Search;
|
||||
using GameIdeas.BlazorApp.Shared.Components.Select.Models;
|
||||
using GameIdeas.BlazorApp.Shared.Components.Select;
|
||||
using Microsoft.AspNetCore.Components;
|
||||
|
||||
namespace GameIdeas.BlazorApp.Shared.Components.SelectSearch;
|
||||
|
||||
public partial class SelectSearch<TItem>
|
||||
{
|
||||
[Parameter] public SelectTheme Theme { get; set; }
|
||||
[Parameter] public List<TItem> Items { get; set; } = [];
|
||||
[Parameter] public Func<TItem, string> GetLabel { get; set; } = _ => string.Empty;
|
||||
[Parameter] public List<TItem> Values { get; set; } = [];
|
||||
[Parameter] public EventCallback<List<TItem>> ValuesChanged { get; set; }
|
||||
[Parameter] public string Placeholder { get; set; } = string.Empty;
|
||||
|
||||
private SelectParams<TItem, string> SelectParams = new();
|
||||
private SearchInput? SearchInput;
|
||||
private Select<TItem, string>? Select;
|
||||
protected override void OnParametersSet()
|
||||
{
|
||||
SelectParams = new()
|
||||
{
|
||||
Items = Items,
|
||||
GetItemLabel = GetLabel
|
||||
};
|
||||
|
||||
base.OnParametersSet();
|
||||
}
|
||||
private async Task HandleValuesChanged(IEnumerable<TItem> values)
|
||||
{
|
||||
Values = values.ToList();
|
||||
SearchInput?.SetText(string.Join(", ", Values.Select(GetLabel)));
|
||||
await ValuesChanged.InvokeAsync(values.ToList());
|
||||
}
|
||||
|
||||
private void HandleClearClicked()
|
||||
{
|
||||
Values = [];
|
||||
}
|
||||
|
||||
private void HandleFocusIn()
|
||||
{
|
||||
Select?.Open();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
/* Advanced filter */
|
||||
.advanced-filter ::deep.search-container {
|
||||
height: 24px;
|
||||
background: var(--input-secondary);
|
||||
}
|
||||
|
||||
.advanced-filter ::deep.search-container input::placeholder {
|
||||
color: #bbb;
|
||||
}
|
||||
|
||||
/* Creation */
|
||||
.creation ::deep.search-container {
|
||||
height: 24px;
|
||||
background: var(--input-secondary);
|
||||
border: solid 1px var(--input-selected);
|
||||
box-sizing: border-box;
|
||||
}
|
||||
Reference in New Issue
Block a user