Skip to content

Instantly share code, notes, and snippets.

@davepermen
Created March 11, 2025 15:32
Show Gist options
  • Save davepermen/00efd667005ddb8159f5e652a85aa37c to your computer and use it in GitHub Desktop.
Save davepermen/00efd667005ddb8159f5e652a85aa37c to your computer and use it in GitHub Desktop.
<section>
@if (NotSelectedItems().Any())
{
<select @bind="@currentIndex" @bind:after="@AddItem">
<option selected hidden disabled value="-1"></option>
@foreach (var item in NotSelectedItems())
{
<option value="@item.Index">@item.Item</option>
}
</select>
}
@if (SelectedItems().Any() == false)
{
<span>@Placeholder</span>
}
<ul>
@foreach (var item in SelectedItems())
{
<li><button @onclick=@(() => RemoveItem(item.Index))>@item.Item</button></li>
}
</ul>
</section>
@code {
[Parameter]
public string[] Items { get; set; } = [];
[Parameter]
public string Placeholder { get; set; } = "select items";
[Parameter]
public string[] Selected { get; set; } = [];
[Parameter]
public EventCallback<string[]> SelectedChanged { get; set; }
HashSet<int> indicees = [];
int currentIndex = -1;
IEnumerable<(int Index, string Item)> SelectedItems() => Items.Index().Where(t => indicees.Contains(t.Index));
IEnumerable<(int Index, string Item)> NotSelectedItems() => Items.Index().Where(t => indicees.Contains(t.Index) == false);
override protected void OnParametersSet()
{
indicees = [..Selected.Select(selected => Array.IndexOf(Items, selected)).Where(index => index >= 0)];
}
async Task AddItem()
{
indicees.Add(currentIndex);
currentIndex = -1;
await SelectedChanged.InvokeAsync(SelectedItems().Select(item => item.Item).ToArray());
}
async Task RemoveItem(int index)
{
indicees.Remove(index);
currentIndex = -1;
await SelectedChanged.InvokeAsync(SelectedItems().Select(item => item.Item).ToArray());
}
}
section {
display: grid;
grid-template-areas: "all";
height: 2rem;
background: #ddd
}
section > * {
grid-area: all;
background: transparent
}
ul {
display: flex;
gap: 1ch;
padding-left: 0;
margin-block: 0;
margin-inline: 1ch;
width: min-content
}
li {
display: contents
}
li button::after {
content: "🞪";
padding-inline-start: 1ch;
}
select, option {
text-align: center;
border: none;
background: #ddd
}
span {
place-self: center;
opacity: 0.7;
font-style: italic;
pointer-events: none
}
button {
margin: 0.125rem;
border: 0;
background: #abf
}
*:focus, *:focus-visible, *:focus-within {
outline: none
}
* {
border: none
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment