Update Dropdown to Improve Support for Unicode Characters
This commit is contained in:
1 parent
35d20eab76
commit
9c7f3cf542
3 files changed
+39
-10
No files matched your search
@@ -4,8 +4,9 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
<div #searchInput class="dropdown-input" [class.hidden]="!isOpen()" [class.focus-mode]="inputFocusMode()"
|
<div #searchInput class="dropdown-input" [class.hidden]="!isOpen()" [class.focus-mode]="inputFocusMode()"
|
||||||
contenteditable="true" role="textbox" aria-multiline="false" [aria-placeholder]="translation.common.selectOption" tabindex="-1" spellcheck="false"
|
contenteditable="true" role="textbox" aria-multiline="false" [aria-placeholder]="translation.common.selectOption"
|
||||||
(input)="onSearch($event)" (click)="handleInputClick($event)" [attr.placeholder]="translation.common.selectOption"></div>
|
[attr.placeholder]="translation.common.selectOption" tabindex="-1" spellcheck="false"
|
||||||
|
(input)="onSearch($event)" (click)="handleInputClick($event)" (mousedown)="handleInputMouseDown()"></div>
|
||||||
|
|
||||||
@if (!isOpen()) {
|
@if (!isOpen()) {
|
||||||
<span class="placeholder">{{ selectedLabel() }}</span>
|
<span class="placeholder">{{ selectedLabel() }}</span>
|
||||||
|
|||||||
@@ -75,7 +75,6 @@ $default_animation_duration: 0.2s;
|
|||||||
.dropdown-input:not(.focus-mode) {
|
.dropdown-input:not(.focus-mode) {
|
||||||
caret-color: transparent;
|
caret-color: transparent;
|
||||||
user-select: none;
|
user-select: none;
|
||||||
cursor: text;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.dropdown-input.hidden {
|
.dropdown-input.hidden {
|
||||||
@@ -87,6 +86,10 @@ $default_animation_duration: 0.2s;
|
|||||||
visibility: hidden;
|
visibility: hidden;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.dropdown-input {
|
||||||
|
cursor: text;
|
||||||
|
}
|
||||||
|
|
||||||
.placeholder, .dropdown-input {
|
.placeholder, .dropdown-input {
|
||||||
flex-grow: 1;
|
flex-grow: 1;
|
||||||
font-size: 18px;
|
font-size: 18px;
|
||||||
|
|||||||
@@ -38,6 +38,7 @@ export interface DropdownOption {
|
|||||||
'[class.open]': 'isOpen()',
|
'[class.open]': 'isOpen()',
|
||||||
tabindex: '0',
|
tabindex: '0',
|
||||||
'(click)': 'toggle()',
|
'(click)': 'toggle()',
|
||||||
|
'(focus)': 'onFocus($event)',
|
||||||
'(mousedown)': 'onMouseDown($event)',
|
'(mousedown)': 'onMouseDown($event)',
|
||||||
'(keydown)': 'onKeyDown($event)',
|
'(keydown)': 'onKeyDown($event)',
|
||||||
'(keydown.enter)': 'onEnter($event)',
|
'(keydown.enter)': 'onEnter($event)',
|
||||||
@@ -65,8 +66,9 @@ export class Dropdown implements OnInit {
|
|||||||
searchQuery = signal('');
|
searchQuery = signal('');
|
||||||
|
|
||||||
private static nextId = 0;
|
private static nextId = 0;
|
||||||
|
private isLatestMouseDownInsideInput = false;
|
||||||
dropdownId = `dropdown-${Dropdown.nextId++}`;
|
dropdownId = `dropdown-${Dropdown.nextId++}`;
|
||||||
private wasInside = false;
|
private isLatestMouseDownInsideContainer = false;
|
||||||
|
|
||||||
constructor(private element: ElementRef) {
|
constructor(private element: ElementRef) {
|
||||||
effect(() => this.filteredOptions());
|
effect(() => this.filteredOptions());
|
||||||
@@ -104,16 +106,21 @@ export class Dropdown implements OnInit {
|
|||||||
});
|
});
|
||||||
|
|
||||||
filteredOptions = computed(() => {
|
filteredOptions = computed(() => {
|
||||||
const query = this.searchQuery().toLowerCase().trim();
|
const query = this.searchQuery().toLowerCase().trim().normalize("NFKD");
|
||||||
const opts = this.normalizedOptions();
|
const opts = this.normalizedOptions();
|
||||||
|
|
||||||
if (!this.inputFocusMode()) return opts;
|
if (!this.inputFocusMode()) return opts;
|
||||||
if (!query) return opts;
|
if (!query) return opts;
|
||||||
|
|
||||||
return opts.filter((o) => o.label.toLowerCase().includes(query));
|
return opts.filter((o) => o.label.toLowerCase().normalize('NFKD').includes(query));
|
||||||
});
|
});
|
||||||
|
|
||||||
toggle() {
|
toggle() {
|
||||||
|
if (this.isLatestMouseDownInsideInput) {
|
||||||
|
this.isLatestMouseDownInsideInput = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
this.isOpen.update((v) => !v);
|
this.isOpen.update((v) => !v);
|
||||||
if (this.isOpen()) {
|
if (this.isOpen()) {
|
||||||
this.searchQuery.set('');
|
this.searchQuery.set('');
|
||||||
@@ -128,6 +135,15 @@ export class Dropdown implements OnInit {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
onFocus(event: Event) {
|
||||||
|
if (this.isOpen()) {
|
||||||
|
const searchInputElement = this.searchInput()!.nativeElement;
|
||||||
|
|
||||||
|
searchInputElement.focus();
|
||||||
|
this.setCursorToEnd(searchInputElement);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private checkIfInputFocus(event: Event) {
|
private checkIfInputFocus(event: Event) {
|
||||||
let triggerInputFocus = this.searchInput()!.nativeElement.contains(
|
let triggerInputFocus = this.searchInput()!.nativeElement.contains(
|
||||||
event.target! as HTMLElement,
|
event.target! as HTMLElement,
|
||||||
@@ -209,8 +225,12 @@ export class Dropdown implements OnInit {
|
|||||||
this.inputFocusMode.set(true);
|
this.inputFocusMode.set(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
handleInputMouseDown() {
|
||||||
|
this.isLatestMouseDownInsideInput = true;
|
||||||
|
}
|
||||||
|
|
||||||
onMouseDown(event: MouseEvent) {
|
onMouseDown(event: MouseEvent) {
|
||||||
this.wasInside = this.element.nativeElement.contains(event.target);
|
this.isLatestMouseDownInsideContainer = this.element.nativeElement.contains(event.target);
|
||||||
|
|
||||||
if (this.checkIfInputFocus(event)) {
|
if (this.checkIfInputFocus(event)) {
|
||||||
if (!this.inputFocusMode()) this.inputFocusMode.set(true);
|
if (!this.inputFocusMode()) this.inputFocusMode.set(true);
|
||||||
@@ -219,16 +239,21 @@ export class Dropdown implements OnInit {
|
|||||||
|
|
||||||
@HostListener('document:click', ['$event'])
|
@HostListener('document:click', ['$event'])
|
||||||
onDocumentClick(event: MouseEvent) {
|
onDocumentClick(event: MouseEvent) {
|
||||||
if (!this.element.nativeElement.contains(event.target) && !this.wasInside) {
|
if (
|
||||||
|
!this.element.nativeElement.contains(event.target) &&
|
||||||
|
!this.isLatestMouseDownInsideContainer
|
||||||
|
) {
|
||||||
this.close();
|
this.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
this.wasInside = false;
|
this.isLatestMouseDownInsideInput = false;
|
||||||
|
this.isLatestMouseDownInsideContainer = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
handleInputClick(event: MouseEvent) {
|
handleInputClick(event: MouseEvent) {
|
||||||
event.stopPropagation();
|
event.stopPropagation();
|
||||||
this.wasInside = false;
|
this.isLatestMouseDownInsideInput = false;
|
||||||
|
this.isLatestMouseDownInsideContainer = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
onSearch(event: Event) {
|
onSearch(event: Event) {
|
||||||
|
|||||||
Reference in new issue
Block a user