Skip to content

Commit

Permalink
feat: handle focus / blur / animation / suggest layer display in rela…
Browse files Browse the repository at this point in the history
…tion to the animation result / escape key
  • Loading branch information
andreassteinmann committed Dec 20, 2024
1 parent b8ec5c4 commit f2db9b3
Show file tree
Hide file tree
Showing 5 changed files with 337 additions and 26 deletions.
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
<div class="search clearfix search-box-wide" [ngClass]="{ 'scale-up-horizontal-right': inputFocused }">
<div
#searchBox
class="search clearfix sparque-search-box"
[ngClass]="{ focus: searchBoxFocused, 'scaled-up': searchBoxScaledUp }"
>
<input
#searchInput
[placeholder]="configuration?.placeholder || ''"
Expand All @@ -7,36 +11,41 @@
class="form-control searchTerm"
(input)="searchSuggest($event.target)"
[value]="inputSearchTerms$ | async"
(focus)="focus()"
(blur)="blur()"
(keydown)="focus()"
(keydown.esc)="blur()"
(keydown.esc)="handleEscKey()"
(keydown.arrowleft)="selectSuggestedTerm(-1)"
(keydown.arrowright)="selectSuggestedTerm(-1)"
(keydown.arrowdown)="selectSuggestedTerm(activeIndex + 1)"
(keydown.arrowup)="selectSuggestedTerm(activeIndex - 1)"
(keydown.enter)="submitSearch(searchInput.value)"
(focus)="focus()"
/>

<div class="buttons">
<button
#searchInputReset
*ngIf="inputSearchTerms$ | async"
class="btn-reset btn btn-primary"
type="reset"
name="reset"
[title]="'search.searchbox.button.reset.title' | translate"
style="right: 40px"
(focus)="focus()"
(click)="searchSuggest(''); searchInput.focus()"
(blur)="blur()"
>
<fa-icon [icon]="['fas', 'times-circle']" />
</button>

<button
#searchInputSubmit
class="btn-search btn btn-primary"
type="submit"
name="search"
[title]="'search.searchbox.button.title' | translate"
(focus)="focus()"
(click)="submitSearch(searchInput.value)"
(blur)="blur()"
>
<!-- search button with icon -->
<ng-container *ngIf="!configuration?.buttonText; else textBlock">
Expand All @@ -48,7 +57,7 @@
</div>

<ng-container *ngIf="isTypedEnoughCharactersToShowSuggest() && searchResults$ | async as results">
<ul *ngIf="results.length && inputFocused" class="search-suggest-results">
<ul *ngIf="results.length && searchBoxFocused" class="search-suggest-results">
<li
*ngFor="let result of results | slice : 0 : configuration?.maxAutoSuggests; let liIndex = index"
[class.active-suggestion]="activeIndex === liIndex"
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
import {
AfterViewInit,
ChangeDetectionStrategy,
Component,
DestroyRef,
ElementRef,
HostListener,
Input,
OnInit,
ViewChild,
Expand Down Expand Up @@ -35,22 +37,42 @@ import { GenerateLazyComponent } from 'ish-core/utils/module-loader/generate-laz
changeDetection: ChangeDetectionStrategy.OnPush,
})
@GenerateLazyComponent()
export class SparqueSearchBoxComponent implements OnInit {
export class SparqueSearchBoxComponent implements OnInit, AfterViewInit {
/**
* the search box configuration for this component
*/
@Input() configuration: SearchBoxConfiguration;

@ViewChild('searchBox') searchBox: ElementRef;
@ViewChild('searchInput') searchInput: ElementRef;
@ViewChild('searchInputReset') searchInputReset: ElementRef;
@ViewChild('searchInputSubmit') searchInputSubmit: ElementRef;

searchResults$: Observable<SuggestTerm[]>;
inputSearchTerms$ = new ReplaySubject<string>(1);

activeIndex = -1;
inputFocused: boolean;
searchBoxFocused = false;
searchBoxInitialWidth: number;
searchBoxScaledUp = false;

// handle browser tab focus
isTabOut = false;

private destroyRef = inject(DestroyRef);

@HostListener('transitionend', ['$event'])
onTransitionEnd(event: TransitionEvent) {
if (event.propertyName === 'width' && event.target === this.searchBox.nativeElement) {
const newWidth = this.searchInput.nativeElement.offsetWidth;
if (newWidth > this.searchBoxInitialWidth) {
this.searchBoxScaledUp = true;
} else {
this.searchBoxScaledUp = false;
}
}
}

constructor(private shoppingFacade: ShoppingFacade, private router: Router) {}

get usedIcon(): IconName {
Expand All @@ -71,13 +93,41 @@ export class SparqueSearchBoxComponent implements OnInit {
.searchResults$(this.inputSearchTerms$)
.pipe(map(results => (results as SparqueSuggestions).keywordSuggestions?.map(s => ({ term: s.keyword }))));
}

ngAfterViewInit() {
this.searchBoxInitialWidth = this.searchBox.nativeElement.offsetWidth;
}

blur() {
this.inputFocused = false;
if (!SSR) {
if (!document.hasFocus()) {
this.isTabOut = true;
return; // skip handling blur if browser tab loses focus
}
this.isTabOut = false; // reset flag

if (
document.activeElement !== this.searchInput.nativeElement ||
document.activeElement !== this.searchInputReset.nativeElement ||
document.activeElement !== this.searchInputSubmit.nativeElement
) {
this.focus(false);
}
}
this.activeIndex = -1;
}

focus() {
this.inputFocused = true;
focus(expand: boolean = true) {
if (expand) {
this.searchBoxFocused = true;
} else {
this.searchBoxFocused = false;
}
}

handleEscKey() {
this.focus(false);
this.inputSearchTerms$.next('');
}

searchSuggest(source: string | EventTarget) {
Expand All @@ -90,7 +140,7 @@ export class SparqueSearchBoxComponent implements OnInit {
}

// remove focus when switching to search page
this.inputFocused = false;
this.focus(false);

if (this.activeIndex !== -1) {
// something was selected via keyboard
Expand Down
15 changes: 0 additions & 15 deletions src/styles/components/header/search-container.scss
Original file line number Diff line number Diff line change
Expand Up @@ -37,21 +37,6 @@
}
}

// Sliding open Search-Box
@media (min-width: $screen-sm) {
.search-box-wide {
position: absolute;
top: calc($search-container-height / -2);
right: 0;
width: 100%;
transition: width 0.3s ease 0.1s;

&.scale-up-horizontal-right {
width: 250%;
}
}
}

ul.search-suggest-results {
position: absolute;
top: 37px;
Expand Down
Loading

0 comments on commit f2db9b3

Please sign in to comment.