Fix dropdown with backdrop filter
This commit is contained in:
@@ -0,0 +1,55 @@
|
||||
@if (IsVisible)
|
||||
{
|
||||
<div class="backdrop-filter @Color.ToString().ToLower()" @onclick="HandleBackdropClicked"></div>
|
||||
}
|
||||
|
||||
@code {
|
||||
[Inject] private IJSRuntime Js { get; set; } = default!;
|
||||
[Parameter] public EventCallback OnClick { get; set; }
|
||||
[Parameter] public bool AllowBodyScroll { get; set; }
|
||||
[Parameter] public BackdropFilterColor Color { get; set; } = BackdropFilterColor.Overlay;
|
||||
[Parameter] public bool CloseOnClick { get; set; } = true;
|
||||
[Parameter] public bool IsVisible { get; set; }
|
||||
|
||||
public async Task Show()
|
||||
{
|
||||
IsVisible = true;
|
||||
await HandleBodyOverflow();
|
||||
}
|
||||
|
||||
public async Task Hide()
|
||||
{
|
||||
IsVisible = false;
|
||||
await HandleBodyOverflow();
|
||||
}
|
||||
|
||||
private async Task HandleBodyOverflow()
|
||||
{
|
||||
try
|
||||
{
|
||||
if (AllowBodyScroll) return;
|
||||
|
||||
if (IsVisible)
|
||||
{
|
||||
await Js.InvokeVoidAsync("setBodyOverflow", "hidden");
|
||||
}
|
||||
else
|
||||
{
|
||||
await Js.InvokeVoidAsync("setBodyOverflow", "auto");
|
||||
}
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
// ignored because js not loaded
|
||||
}
|
||||
}
|
||||
|
||||
private async Task HandleBackdropClicked()
|
||||
{
|
||||
if (!CloseOnClick) return;
|
||||
|
||||
await Hide();
|
||||
await OnClick.InvokeAsync();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
.backdrop-filter {
|
||||
position: fixed;
|
||||
inset: 0;
|
||||
z-index: var(--index-backdrop);
|
||||
}
|
||||
|
||||
.backdrop-filter.overlay {
|
||||
background-color: var(--grey-filter);
|
||||
}
|
||||
|
||||
.backdrop-filter.transparent {
|
||||
background-color: transparent;
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
window.setBodyOverflow = (overflow) => {
|
||||
document.getElementsByTagName('html')[0].style.overflow = overflow;
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
namespace GameIdeas.BlazorApp.Shared.Components.BackdropFilter;
|
||||
|
||||
public enum BackdropFilterColor
|
||||
{
|
||||
Overlay,
|
||||
Transparent
|
||||
}
|
||||
@@ -1,10 +1,12 @@
|
||||
<div class="search-container">
|
||||
<input type="text"
|
||||
<input @ref=InputText
|
||||
type="text"
|
||||
class="search-field"
|
||||
placeholder="@Placeholder"
|
||||
@bind=@Text
|
||||
@bind:event="oninput"
|
||||
@bind:after=HandleTextChanged />
|
||||
@bind:after=HandleTextChanged
|
||||
@onfocusin=HandleFocusIn/>
|
||||
|
||||
@if (!string.IsNullOrEmpty(Text))
|
||||
{
|
||||
|
||||
@@ -9,8 +9,11 @@ public partial class SearchInput
|
||||
[Parameter] public EventCallback<string> TextChanged { get; set; }
|
||||
[Parameter] public EventCallback ClearClicked { get; set; }
|
||||
[Parameter] public EventCallback SearchClicked { get; set; }
|
||||
[Parameter] public EventCallback FocusIn { get; set; }
|
||||
[Parameter] public SearchInputIcon Icon { get; set; }
|
||||
|
||||
private ElementReference InputText;
|
||||
|
||||
protected override void OnInitialized()
|
||||
{
|
||||
Text = string.Empty;
|
||||
@@ -36,5 +39,10 @@ public partial class SearchInput
|
||||
{
|
||||
await TextChanged.InvokeAsync(Text);
|
||||
await SearchClicked.InvokeAsync();
|
||||
await InputText.FocusAsync();
|
||||
}
|
||||
private async Task HandleFocusIn()
|
||||
{
|
||||
await FocusIn.InvokeAsync();
|
||||
}
|
||||
}
|
||||
@@ -1,21 +1,19 @@
|
||||
@using GameIdeas.BlazorApp.Shared.Components.Search
|
||||
@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" tabindex="1001" @ref="BaseElement">
|
||||
<div class="select-button @(Enum.GetName(Theme)?.ToLower())" @onfocusin=HandleFocusIn @onfocusout=HandleFocusOut>
|
||||
<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" />
|
||||
SearchClicked="HandleSearchClicked"
|
||||
FocusIn="HandleTextFocusIn"/>
|
||||
</div>
|
||||
<div class="select-container @(AlignRight ? "align-right" : "")"
|
||||
tabindex="1000"
|
||||
@ref=ContentElement
|
||||
@onfocusin=HandleContentFocusIn
|
||||
@onfocusout=HandleContentFocusOut>
|
||||
<div class="select-container @(AlignRight ? "align-right" : "")">
|
||||
|
||||
@if (IsContentOpen)
|
||||
{
|
||||
@@ -32,3 +30,6 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<BackdropFilter AllowBodyScroll=true CloseOnClick=true Color="BackdropFilterColor.Transparent"
|
||||
IsVisible=IsContentOpen OnClick="HandleContentClosed" />
|
||||
|
||||
|
||||
@@ -13,60 +13,34 @@ public partial class MultipleSelectList<TItem>
|
||||
[Parameter] public bool AlignRight { get; set; }
|
||||
[Parameter] public string? Placeholder { get; set; }
|
||||
|
||||
private bool IsContentOpen
|
||||
{
|
||||
get => InputFocus || ContentFocus;
|
||||
}
|
||||
|
||||
private bool InputFocus = false;
|
||||
private bool ContentFocus = false;
|
||||
private bool IsContentOpen = false;
|
||||
private SearchInput? SearchInput;
|
||||
private ElementReference ContentElement;
|
||||
private ElementReference BaseElement;
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
private async Task HandleTextChanged()
|
||||
private void HandleTextChanged()
|
||||
{
|
||||
await BaseElement.FocusAsync();
|
||||
IsContentOpen = false;
|
||||
}
|
||||
|
||||
private void HandleFocusIn()
|
||||
private void HandleSearchClicked()
|
||||
{
|
||||
InputFocus = true;
|
||||
IsContentOpen = !IsContentOpen;
|
||||
}
|
||||
|
||||
private void HandleContentFocusIn()
|
||||
private void HandleContentClosed()
|
||||
{
|
||||
ContentFocus = true;
|
||||
IsContentOpen = false;
|
||||
}
|
||||
|
||||
private async Task HandleContentFocusOut()
|
||||
private void HandleTextFocusIn()
|
||||
{
|
||||
await Task.Delay(TimeSpan.FromSeconds(0.3));
|
||||
ContentFocus = false;
|
||||
}
|
||||
|
||||
private async Task HandleFocusOut()
|
||||
{
|
||||
await Task.Delay(TimeSpan.FromSeconds(0.3));
|
||||
InputFocus = false;
|
||||
}
|
||||
|
||||
private async Task HandleSearchClicked()
|
||||
{
|
||||
if (!IsContentOpen)
|
||||
{
|
||||
await ContentElement.FocusAsync();
|
||||
}
|
||||
else
|
||||
{
|
||||
await BaseElement.FocusAsync();
|
||||
}
|
||||
IsContentOpen = true;
|
||||
}
|
||||
}
|
||||
@@ -47,5 +47,10 @@
|
||||
height: 24px;
|
||||
width: 210px;
|
||||
border: 2px solid var(--input-selected);
|
||||
background: var(--input-secondary);
|
||||
}
|
||||
|
||||
::deep .select-button.advancedfilter .search-container input::placeholder {
|
||||
color: #ddd;
|
||||
}
|
||||
|
||||
|
||||
@@ -25,8 +25,8 @@
|
||||
--index-layout: 100;
|
||||
--index-component: 300;
|
||||
--index-floating: 500;
|
||||
--index-dropdown: 700;
|
||||
--index-backdrop: 900;
|
||||
--index-backdrop: 700;
|
||||
--index-dropdown: 900;
|
||||
--index-popup: 1000;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user