diff --git a/apps/red-ui/src/app/components/spotlight-search/spotlight-search-action.ts b/apps/red-ui/src/app/components/spotlight-search/spotlight-search-action.ts index 76601b616..47a39ad27 100644 --- a/apps/red-ui/src/app/components/spotlight-search/spotlight-search-action.ts +++ b/apps/red-ui/src/app/components/spotlight-search/spotlight-search-action.ts @@ -1,6 +1,6 @@ export interface SpotlightSearchAction { - text: string; - action: (query: string) => void; - icon?: string; - hide?: boolean; + readonly text: string; + readonly action: (query: string) => void; + readonly icon?: string; + readonly hide?: boolean; } diff --git a/apps/red-ui/src/app/components/spotlight-search/spotlight-search-dialog-data.ts b/apps/red-ui/src/app/components/spotlight-search/spotlight-search-dialog-data.ts index cfbeca85c..d817800e2 100644 --- a/apps/red-ui/src/app/components/spotlight-search/spotlight-search-dialog-data.ts +++ b/apps/red-ui/src/app/components/spotlight-search/spotlight-search-dialog-data.ts @@ -1,6 +1,6 @@ import { SpotlightSearchAction } from './spotlight-search-action'; export interface SpotlightSearchDialogData { - actionsConfig: SpotlightSearchAction[]; - placeholder: string; + readonly actionsConfig: SpotlightSearchAction[]; + readonly placeholder: string; } diff --git a/apps/red-ui/src/app/components/spotlight-search/spotlight-search.component.html b/apps/red-ui/src/app/components/spotlight-search/spotlight-search.component.html index 065a072ea..ce8f7bc99 100644 --- a/apps/red-ui/src/app/components/spotlight-search/spotlight-search.component.html +++ b/apps/red-ui/src/app/components/spotlight-search/spotlight-search.component.html @@ -1,43 +1,30 @@ -
-
-
+
+ +
+ + + + + diff --git a/apps/red-ui/src/app/components/spotlight-search/spotlight-search.component.scss b/apps/red-ui/src/app/components/spotlight-search/spotlight-search.component.scss index d25232d1a..5f7657fc6 100644 --- a/apps/red-ui/src/app/components/spotlight-search/spotlight-search.component.scss +++ b/apps/red-ui/src/app/components/spotlight-search/spotlight-search.component.scss @@ -2,8 +2,6 @@ .spotlight-wrapper { overflow: hidden; - width: 750px; - margin: auto; position: absolute; top: 15%; left: 0; @@ -13,10 +11,9 @@ } .spotlight-row { - display: block; - width: 750px; + display: flex; + align-items: center; height: 60px; - margin: auto; text-align: left; font-size: 16px; font-weight: 500; @@ -27,7 +24,13 @@ background-color: $white; } -.focus:focus { +.spotlight-row, +.spotlight-wrapper { + width: 750px; + margin: auto; +} + +.highlight { background-color: $grey-2; } @@ -41,10 +44,6 @@ background-color: rgba(226, 228, 233, 0.9); } -input { - width: 668px !important; -} - mat-icon { width: 14px; height: 14px; diff --git a/apps/red-ui/src/app/components/spotlight-search/spotlight-search.component.ts b/apps/red-ui/src/app/components/spotlight-search/spotlight-search.component.ts index c2d5799e1..420816a1c 100644 --- a/apps/red-ui/src/app/components/spotlight-search/spotlight-search.component.ts +++ b/apps/red-ui/src/app/components/spotlight-search/spotlight-search.component.ts @@ -1,9 +1,9 @@ -import { ChangeDetectionStrategy, Component, ElementRef, HostListener, Inject, QueryList, ViewChildren } from '@angular/core'; +import { ChangeDetectionStrategy, Component, HostListener, Inject } from '@angular/core'; import { FormBuilder } from '@angular/forms'; -import { debounceTime, map, startWith, tap } from 'rxjs/operators'; -import { debounce } from '@utils/debounce'; +import { debounceTime, distinctUntilChanged, map, startWith } from 'rxjs/operators'; import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog'; import { SpotlightSearchDialogData } from '@components/spotlight-search/spotlight-search-dialog-data'; +import { BehaviorSubject } from 'rxjs'; @Component({ selector: 'redaction-spotlight-search', @@ -12,58 +12,48 @@ import { SpotlightSearchDialogData } from '@components/spotlight-search/spotligh changeDetection: ChangeDetectionStrategy.OnPush }) export class SpotlightSearchComponent { - @ViewChildren('actions') - private readonly _actions: QueryList; - private _currentActionIdx = 0; + private readonly _currentActionIdx$ = new BehaviorSubject(0); - formGroup = this._formBuilder.group({ query: [''] }); - query$ = this.formGroup.get('query').valueChanges.pipe(startWith('')); - showActions$ = this.query$.pipe( + readonly currentActionIdx$ = this._currentActionIdx$.asObservable().pipe(distinctUntilChanged()); + readonly shownActions = this.data.actionsConfig.filter(a => !a.hide); + readonly formGroup = this._formBuilder.group({ query: [''] }); + readonly showActions$ = this.formGroup.get('query').valueChanges.pipe( + startWith(''), debounceTime(300), - tap(value => this._restoreFocusOnAction(value === '')), map(value => value !== '') ); constructor( private readonly _formBuilder: FormBuilder, - private readonly _dialogRef: MatDialogRef, + readonly dialogRef: MatDialogRef, @Inject(MAT_DIALOG_DATA) readonly data: SpotlightSearchDialogData ) {} - close() { - this._dialogRef.close(); + @HostListener('document:keydown', ['$event']) + handleKeyDown(event: KeyboardEvent): void { + if (['ArrowDown', 'ArrowUp'].includes(event.code)) { + event.preventDefault(); + return event.stopPropagation(); + } } @HostListener('document:keyup', ['$event']) - handleKeyDown(event: KeyboardEvent) { - if (event.code === 'ArrowDown' && this._actions) { - this._currentActionIdx++; - return this._restoreFocusOnAction(this._currentActionIdx === this._actions.length); + handleKeyUp(event: KeyboardEvent): void { + if (['ArrowDown', 'ArrowUp'].includes(event.code)) { + event.preventDefault(); + event.stopPropagation(); + const index = this._currentActionIdx + event.code === 'ArrowDown' ? 1 : -1; + return this._currentActionIdx$.next(this._fixIndexOutOfBound(index)); } - - if (event.code === 'ArrowUp' && this._actions) { - if (this._currentActionIdx === 0) this._currentActionIdx = this._actions.length - 1; - else this._currentActionIdx--; - return this._restoreFocusOnAction(); - } - - if (['Tab'].includes(event.code)) { - return; - } - - if (this._actions.find((_, index) => index === this._currentActionIdx)?.nativeElement === document.activeElement) { - let query = this.formGroup.get('query').value as string; - if (event.code === 'Backspace') query = query.substring(0, query.length - 1); - else if (event.key.length === 1) query = query + event.key; - this.formGroup.patchValue({ query: query }); - } - document.getElementById('query').focus(); } - @debounce(50) - private _restoreFocusOnAction(resetToFirst = false) { - if (resetToFirst) this._currentActionIdx = 0; - this._actions.find((_, index) => index === this._currentActionIdx)?.nativeElement.focus(); + private get _currentActionIdx(): number { + return this._currentActionIdx$.getValue(); + } + + private _fixIndexOutOfBound(index: number): number { + const indexOutOfBound = index < 0 || index >= this.shownActions.length; + return indexOutOfBound ? Math.abs(this.shownActions.length - Math.abs(index)) : index; } }