diff --git a/src/app/components/dropdown/dropdown.html b/src/app/components/dropdown/dropdown.html index b10e209..976eb58 100644 --- a/src/app/components/dropdown/dropdown.html +++ b/src/app/components/dropdown/dropdown.html @@ -3,9 +3,9 @@ {{ icon() }} } - + (input)="onSearch($event)" (click)="handleInputClick($event)" [attr.placeholder]="translation.common.selectOption"> @if (!isOpen()) { {{ selectedLabel() }} diff --git a/src/app/components/dropdown/dropdown.scss b/src/app/components/dropdown/dropdown.scss index 644fc78..e38f992 100644 --- a/src/app/components/dropdown/dropdown.scss +++ b/src/app/components/dropdown/dropdown.scss @@ -67,6 +67,17 @@ $default_animation_duration: 0.2s; outline: none; } + .dropdown-input:empty:before { + content: attr(placeholder); + opacity: 50%; + } + + .dropdown-input:not(.focus-mode) { + caret-color: transparent; + user-select: none; + cursor: text; + } + .dropdown-input.hidden { position: absolute; diff --git a/src/app/components/dropdown/dropdown.ts b/src/app/components/dropdown/dropdown.ts index 7a0283c..7e2dad2 100644 --- a/src/app/components/dropdown/dropdown.ts +++ b/src/app/components/dropdown/dropdown.ts @@ -38,6 +38,7 @@ export interface DropdownOption { '[class.open]': 'isOpen()', tabindex: '0', '(click)': 'toggle()', + '(mousedown)': 'onMouseDown($event)', '(keydown)': 'onKeyDown($event)', '(keydown.enter)': 'onEnter($event)', '(keydown.space)': 'onSpaceDown($event)', @@ -65,9 +66,10 @@ export class Dropdown implements OnInit { private static nextId = 0; dropdownId = `dropdown-${Dropdown.nextId++}`; + private wasInside = false; constructor(private element: ElementRef) { - effect(() => this.filteredOptions()) + effect(() => this.filteredOptions()); effect(() => { const isDropdownOpen = this.isOpen(); @@ -122,10 +124,17 @@ export class Dropdown implements OnInit { searchInputElement.focus(); this.setCursorToEnd(searchInputElement); - }) + }); } } + private checkIfInputFocus(event: Event) { + let triggerInputFocus = this.searchInput()!.nativeElement.contains( + event.target! as HTMLElement, + ); + return this.isOpen() && triggerInputFocus; + } + close() { this.isOpen.set(false); this.focusedIndex.set(-1); @@ -138,7 +147,7 @@ export class Dropdown implements OnInit { } onConfirm(event: Event) { - event.preventDefault() + event.preventDefault(); if (this.isOpen()) { const currentIndex = this.focusedIndex(); @@ -151,11 +160,13 @@ export class Dropdown implements OnInit { } } - onEnter(event: Event) { this.onConfirm(event) } + onEnter(event: Event) { + this.onConfirm(event); + } onSpaceDown(event: Event) { if (this.isOpen() && this.inputFocusMode()) return; - this.onConfirm(event) + this.onConfirm(event); } onArrowDown(event: Event) { @@ -191,22 +202,39 @@ export class Dropdown implements OnInit { } onKeyDown(event: KeyboardEvent) { - if (event.ctrlKey || event.metaKey || event.altKey || event.shiftKey || event.key == 'Tab') return; + if (event.ctrlKey || event.metaKey || event.altKey || event.shiftKey || event.key == 'Tab') + return; if (!this.isOpen() || this.inputFocusMode()) return; this.inputFocusMode.set(true); } - @HostListener('document:click', ['$event']) - onDocumentClick(event: MouseEvent) { - if (!this.element.nativeElement.contains(event.target)) { - this.close(); + onMouseDown(event: MouseEvent) { + this.wasInside = this.element.nativeElement.contains(event.target); + + if (this.checkIfInputFocus(event)) { + if (!this.inputFocusMode()) this.inputFocusMode.set(true); } } - onSearch(event: Event) { - const text = (event.target as HTMLElement).innerText; + @HostListener('document:click', ['$event']) + onDocumentClick(event: MouseEvent) { + if (!this.element.nativeElement.contains(event.target) && !this.wasInside) { + this.close(); + } + this.wasInside = false; + } + handleInputClick(event: MouseEvent) { + event.stopPropagation(); + this.wasInside = false; + } + + onSearch(event: Event) { + const element = event.target as HTMLElement; + const text = element.innerText; + + if (text.trim().length <= 0) element.innerHTML = ''; this.focusedIndex.set(0); this.searchQuery.set(text); }