Update Dropdown to Improve Support for Unicode Characters

This commit is contained in:
copecone committed 2026-04-20 01:17:35 +09:00
1 parent 35d20eab76
commit 9c7f3cf542
3 files changed
+39 -10

No files matched your search

+3 -2
View File
@@ -4,8 +4,9 @@
}
<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"
(input)="onSearch($event)" (click)="handleInputClick($event)" [attr.placeholder]="translation.common.selectOption"></div>
contenteditable="true" role="textbox" aria-multiline="false" [aria-placeholder]="translation.common.selectOption"
[attr.placeholder]="translation.common.selectOption" tabindex="-1" spellcheck="false"
(input)="onSearch($event)" (click)="handleInputClick($event)" (mousedown)="handleInputMouseDown()"></div>
@if (!isOpen()) {
<span class="placeholder">{{ selectedLabel() }}</span>
+4 -1
View File
@@ -75,7 +75,6 @@ $default_animation_duration: 0.2s;
.dropdown-input:not(.focus-mode) {
caret-color: transparent;
user-select: none;
cursor: text;
}
.dropdown-input.hidden {
@@ -87,6 +86,10 @@ $default_animation_duration: 0.2s;
visibility: hidden;
}
.dropdown-input {
cursor: text;
}
.placeholder, .dropdown-input {
flex-grow: 1;
font-size: 18px;
+32 -7
View File
@@ -38,6 +38,7 @@ export interface DropdownOption {
'[class.open]': 'isOpen()',
tabindex: '0',
'(click)': 'toggle()',
'(focus)': 'onFocus($event)',
'(mousedown)': 'onMouseDown($event)',
'(keydown)': 'onKeyDown($event)',
'(keydown.enter)': 'onEnter($event)',
@@ -65,8 +66,9 @@ export class Dropdown implements OnInit {
searchQuery = signal('');
private static nextId = 0;
private isLatestMouseDownInsideInput = false;
dropdownId = `dropdown-${Dropdown.nextId++}`;
private wasInside = false;
private isLatestMouseDownInsideContainer = false;
constructor(private element: ElementRef) {
effect(() => this.filteredOptions());
@@ -104,16 +106,21 @@ export class Dropdown implements OnInit {
});
filteredOptions = computed(() => {
const query = this.searchQuery().toLowerCase().trim();
const query = this.searchQuery().toLowerCase().trim().normalize("NFKD");
const opts = this.normalizedOptions();
if (!this.inputFocusMode()) 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() {
if (this.isLatestMouseDownInsideInput) {
this.isLatestMouseDownInsideInput = false;
return;
}
this.isOpen.update((v) => !v);
if (this.isOpen()) {
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) {
let triggerInputFocus = this.searchInput()!.nativeElement.contains(
event.target! as HTMLElement,
@@ -209,8 +225,12 @@ export class Dropdown implements OnInit {
this.inputFocusMode.set(true);
}
handleInputMouseDown() {
this.isLatestMouseDownInsideInput = true;
}
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.inputFocusMode()) this.inputFocusMode.set(true);
@@ -219,16 +239,21 @@ export class Dropdown implements OnInit {
@HostListener('document:click', ['$event'])
onDocumentClick(event: MouseEvent) {
if (!this.element.nativeElement.contains(event.target) && !this.wasInside) {
if (
!this.element.nativeElement.contains(event.target) &&
!this.isLatestMouseDownInsideContainer
) {
this.close();
}
this.wasInside = false;
this.isLatestMouseDownInsideInput = false;
this.isLatestMouseDownInsideContainer = false;
}
handleInputClick(event: MouseEvent) {
event.stopPropagation();
this.wasInside = false;
this.isLatestMouseDownInsideInput = false;
this.isLatestMouseDownInsideContainer = false;
}
onSearch(event: Event) {