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">
|
<div class="search-container">
|
||||||
<input type="text"
|
<input @ref=InputText
|
||||||
|
type="text"
|
||||||
class="search-field"
|
class="search-field"
|
||||||
placeholder="@Placeholder"
|
placeholder="@Placeholder"
|
||||||
@bind=@Text
|
@bind=@Text
|
||||||
@bind:event="oninput"
|
@bind:event="oninput"
|
||||||
@bind:after=HandleTextChanged />
|
@bind:after=HandleTextChanged
|
||||||
|
@onfocusin=HandleFocusIn/>
|
||||||
|
|
||||||
@if (!string.IsNullOrEmpty(Text))
|
@if (!string.IsNullOrEmpty(Text))
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -9,8 +9,11 @@ public partial class SearchInput
|
|||||||
[Parameter] public EventCallback<string> TextChanged { get; set; }
|
[Parameter] public EventCallback<string> TextChanged { get; set; }
|
||||||
[Parameter] public EventCallback ClearClicked { get; set; }
|
[Parameter] public EventCallback ClearClicked { get; set; }
|
||||||
[Parameter] public EventCallback SearchClicked { get; set; }
|
[Parameter] public EventCallback SearchClicked { get; set; }
|
||||||
|
[Parameter] public EventCallback FocusIn { get; set; }
|
||||||
[Parameter] public SearchInputIcon Icon { get; set; }
|
[Parameter] public SearchInputIcon Icon { get; set; }
|
||||||
|
|
||||||
|
private ElementReference InputText;
|
||||||
|
|
||||||
protected override void OnInitialized()
|
protected override void OnInitialized()
|
||||||
{
|
{
|
||||||
Text = string.Empty;
|
Text = string.Empty;
|
||||||
@@ -36,5 +39,10 @@ public partial class SearchInput
|
|||||||
{
|
{
|
||||||
await TextChanged.InvokeAsync(Text);
|
await TextChanged.InvokeAsync(Text);
|
||||||
await SearchClicked.InvokeAsync();
|
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
|
@using GameIdeas.BlazorApp.Shared.Components.Select.Components
|
||||||
@typeparam TItem
|
@typeparam TItem
|
||||||
|
|
||||||
<div class="select-list" tabindex="1001" @ref="BaseElement">
|
<div class="select-list">
|
||||||
<div class="select-button @(Enum.GetName(Theme)?.ToLower())" @onfocusin=HandleFocusIn @onfocusout=HandleFocusOut>
|
<div class="select-button @(Enum.GetName(Theme)?.ToLower())">
|
||||||
<SearchInput @ref=SearchInput
|
<SearchInput @ref=SearchInput
|
||||||
Icon="SearchInputIcon.Dropdown"
|
Icon="SearchInputIcon.Dropdown"
|
||||||
Placeholder="@Placeholder"
|
Placeholder="@Placeholder"
|
||||||
TextChanged="HandleTextChanged"
|
TextChanged="HandleTextChanged"
|
||||||
ClearClicked="HandleTextChanged"
|
ClearClicked="HandleTextChanged"
|
||||||
SearchClicked="HandleSearchClicked" />
|
SearchClicked="HandleSearchClicked"
|
||||||
|
FocusIn="HandleTextFocusIn"/>
|
||||||
</div>
|
</div>
|
||||||
<div class="select-container @(AlignRight ? "align-right" : "")"
|
<div class="select-container @(AlignRight ? "align-right" : "")">
|
||||||
tabindex="1000"
|
|
||||||
@ref=ContentElement
|
|
||||||
@onfocusin=HandleContentFocusIn
|
|
||||||
@onfocusout=HandleContentFocusOut>
|
|
||||||
|
|
||||||
@if (IsContentOpen)
|
@if (IsContentOpen)
|
||||||
{
|
{
|
||||||
@@ -32,3 +30,6 @@
|
|||||||
</div>
|
</div>
|
||||||
</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 bool AlignRight { get; set; }
|
||||||
[Parameter] public string? Placeholder { get; set; }
|
[Parameter] public string? Placeholder { get; set; }
|
||||||
|
|
||||||
private bool IsContentOpen
|
private bool IsContentOpen = false;
|
||||||
{
|
|
||||||
get => InputFocus || ContentFocus;
|
|
||||||
}
|
|
||||||
|
|
||||||
private bool InputFocus = false;
|
|
||||||
private bool ContentFocus = false;
|
|
||||||
private SearchInput? SearchInput;
|
private SearchInput? SearchInput;
|
||||||
private ElementReference ContentElement;
|
|
||||||
private ElementReference BaseElement;
|
|
||||||
|
|
||||||
private async Task HandleItemClicked(SelectElement<TItem> selectedValue)
|
private async Task HandleItemClicked(SelectElement<TItem> selectedValue)
|
||||||
{
|
{
|
||||||
|
selectedValue.IsSelected = !selectedValue.IsSelected;
|
||||||
|
|
||||||
Values = Items.Where(x => x.IsSelected && x.Item != null).Select(x => x.Item!);
|
Values = Items.Where(x => x.IsSelected && x.Item != null).Select(x => x.Item!);
|
||||||
SearchInput?.SetText(string.Join(", ", Values));
|
SearchInput?.SetText(string.Join(", ", Values));
|
||||||
|
|
||||||
await ValuesChanged.InvokeAsync(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 HandleContentClosed()
|
||||||
private void HandleContentFocusIn()
|
|
||||||
{
|
{
|
||||||
ContentFocus = true;
|
IsContentOpen = false;
|
||||||
}
|
}
|
||||||
|
private void HandleTextFocusIn()
|
||||||
private async Task HandleContentFocusOut()
|
|
||||||
{
|
{
|
||||||
await Task.Delay(TimeSpan.FromSeconds(0.3));
|
IsContentOpen = true;
|
||||||
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();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -47,5 +47,10 @@
|
|||||||
height: 24px;
|
height: 24px;
|
||||||
width: 210px;
|
width: 210px;
|
||||||
border: 2px solid var(--input-selected);
|
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-layout: 100;
|
||||||
--index-component: 300;
|
--index-component: 300;
|
||||||
--index-floating: 500;
|
--index-floating: 500;
|
||||||
--index-dropdown: 700;
|
--index-backdrop: 700;
|
||||||
--index-backdrop: 900;
|
--index-dropdown: 900;
|
||||||
--index-popup: 1000;
|
--index-popup: 1000;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user