Select button instead of dropdown-item

This commit is contained in:
shamoon 2024-03-31 23:21:42 -07:00
parent ed10c7e066
commit 26539854aa
4 changed files with 34 additions and 26 deletions

View File

@ -9,11 +9,11 @@
</form> </form>
<ng-template #resultItemTemplate let-item="item" let-nameProp="nameProp" let-type="type" let-icon="icon"> <ng-template #resultItemTemplate let-item="item" let-nameProp="nameProp" let-type="type" let-icon="icon">
<div #resultItem ngbDropdownItem class="py-2 d-flex align-items-center focus-ring border-0 cursor-pointer" (click)="primaryAction(type, item)"> <div #resultItem ngbDropdownItem class="py-2 d-flex align-items-center focus-ring border-0 cursor-pointer" tabindex="-1" (click)="primaryAction(type, item)">
<i-bs width="1.2em" height="1.2em" name="{{icon}}" class="me-2 text-muted"></i-bs> <i-bs width="1.2em" height="1.2em" name="{{icon}}" class="me-2 text-muted"></i-bs>
<span>{{item[nameProp]}}</span> <span class="text-truncate">{{item[nameProp]}}</span>
<div class="btn-group ms-auto"> <div class="btn-group ms-auto">
<button type="button" class="btn btn-sm btn-outline-primary" (click)="primaryAction(type, item); $event.stopPropagation()"> <button #primaryButton type="button" class="btn btn-sm btn-outline-primary" (click)="primaryAction(type, item); $event.stopPropagation()">
@if (type === 'document' || type === 'workflow' || type === 'customField' || type === 'group' || type === 'user') { @if (type === 'document' || type === 'workflow' || type === 'customField' || type === 'group' || type === 'user') {
<i-bs width="1em" height="1em" name="pencil"></i-bs> <i-bs width="1em" height="1em" name="pencil"></i-bs>
} @else { } @else {
@ -21,7 +21,7 @@
} }
</button> </button>
@if (type !== 'workflow' && type !== 'customField' && type !== 'group' && type !== 'user') { @if (type !== 'workflow' && type !== 'customField' && type !== 'group' && type !== 'user') {
<button type="button" class="btn btn-sm btn-outline-secondary" (click)="secondaryAction(type, item); $event.stopPropagation()"> <button #secondaryButton type="button" class="btn btn-sm btn-outline-primary" (click)="secondaryAction(type, item); $event.stopPropagation()">
@if (type === 'document') { @if (type === 'document') {
<i-bs width="1em" height="1em" name="download"></i-bs> <i-bs width="1em" height="1em" name="download"></i-bs>
} @else { } @else {

View File

@ -58,3 +58,7 @@ form {
.mh-75 { .mh-75 {
max-height: 75vh; max-height: 75vh;
} }
.dropdown-item:has(button:focus) {
background-color: var(--pngx-bg-alt);
}

View File

@ -161,7 +161,7 @@ describe('GlobalSearchComponent', () => {
component['currentItemIndex'] = 0 component['currentItemIndex'] = 0
const firstItemFocusSpy = jest.spyOn( const firstItemFocusSpy = jest.spyOn(
component.resultItems.get(1).nativeElement, component.primaryButtons.get(1).nativeElement,
'focus' 'focus'
) )
component.handleKeyboardEvent( component.handleKeyboardEvent(
@ -170,8 +170,22 @@ describe('GlobalSearchComponent', () => {
expect(component['currentItemIndex']).toBe(1) expect(component['currentItemIndex']).toBe(1)
expect(firstItemFocusSpy).toHaveBeenCalled() expect(firstItemFocusSpy).toHaveBeenCalled()
const secondaryItemFocusSpy = jest.spyOn(
component.secondaryButtons.get(1).nativeElement,
'focus'
)
component.handleKeyboardEvent(
new KeyboardEvent('keydown', { key: 'ArrowRight' })
)
expect(secondaryItemFocusSpy).toHaveBeenCalled()
component.handleKeyboardEvent(
new KeyboardEvent('keydown', { key: 'ArrowLeft' })
)
expect(firstItemFocusSpy).toHaveBeenCalled()
const zeroItemSpy = jest.spyOn( const zeroItemSpy = jest.spyOn(
component.resultItems.get(0).nativeElement, component.primaryButtons.get(0).nativeElement,
'focus' 'focus'
) )
component.handleKeyboardEvent( component.handleKeyboardEvent(
@ -189,15 +203,6 @@ describe('GlobalSearchComponent', () => {
) )
expect(component['currentItemIndex']).toBe(-1) expect(component['currentItemIndex']).toBe(-1)
expect(inputFocusSpy).toHaveBeenCalled() expect(inputFocusSpy).toHaveBeenCalled()
const actionSpy = jest.spyOn(component, 'primaryAction')
component.handleKeyboardEvent(
new KeyboardEvent('keydown', { key: 'ArrowDown' })
)
component.handleKeyboardEvent(
new KeyboardEvent('keydown', { key: 'Enter' })
)
expect(actionSpy).toHaveBeenCalled()
}) })
it('should search', fakeAsync(() => { it('should search', fakeAsync(() => {
@ -314,7 +319,7 @@ describe('GlobalSearchComponent', () => {
component.searchResults = searchResults as any component.searchResults = searchResults as any
fixture.detectChanges() fixture.detectChanges()
const focusSpy = jest.spyOn( const focusSpy = jest.spyOn(
component.resultItems.get(0).nativeElement, component.primaryButtons.get(0).nativeElement,
'focus' 'focus'
) )
component['currentItemIndex'] = 0 component['currentItemIndex'] = 0

View File

@ -47,7 +47,8 @@ export class GlobalSearchComponent {
@ViewChild('searchInput') searchInput: ElementRef @ViewChild('searchInput') searchInput: ElementRef
@ViewChild('resultsDropdown') resultsDropdown: NgbDropdown @ViewChild('resultsDropdown') resultsDropdown: NgbDropdown
@ViewChildren('resultItem') resultItems: QueryList<ElementRef> @ViewChildren('primaryButton') primaryButtons: QueryList<ElementRef>
@ViewChildren('secondaryButton') secondaryButtons: QueryList<ElementRef>
@HostListener('document:keydown', ['$event']) @HostListener('document:keydown', ['$event'])
handleKeyboardEvent(event: KeyboardEvent) { handleKeyboardEvent(event: KeyboardEvent) {
@ -57,7 +58,7 @@ export class GlobalSearchComponent {
if (this.searchResults && this.resultsDropdown.isOpen()) { if (this.searchResults && this.resultsDropdown.isOpen()) {
if (event.key === 'ArrowDown') { if (event.key === 'ArrowDown') {
if (this.currentItemIndex < this.resultItems.length - 1) { if (this.currentItemIndex < this.searchResults.total - 1) {
this.currentItemIndex++ this.currentItemIndex++
this.setCurrentItem() this.setCurrentItem()
event.preventDefault() event.preventDefault()
@ -71,12 +72,10 @@ export class GlobalSearchComponent {
this.searchInput.nativeElement.focus() this.searchInput.nativeElement.focus()
this.currentItemIndex = -1 this.currentItemIndex = -1
} }
} else if ( } else if (event.key === 'ArrowRight') {
event.key === 'Enter' && this.secondaryButtons.get(this.currentItemIndex).nativeElement.focus()
document.activeElement !== this.searchInput.nativeElement } else if (event.key === 'ArrowLeft') {
) { this.primaryButtons.get(this.currentItemIndex).nativeElement.focus()
this.resultItems.get(this.currentItemIndex).nativeElement.click()
event.preventDefault()
} }
} }
} }
@ -211,7 +210,7 @@ export class GlobalSearchComponent {
} }
private setCurrentItem() { private setCurrentItem() {
const item: ElementRef = this.resultItems.get(this.currentItemIndex) const item: ElementRef = this.primaryButtons.get(this.currentItemIndex)
item.nativeElement.focus() item.nativeElement.focus()
} }
@ -228,7 +227,7 @@ export class GlobalSearchComponent {
this.searchResults?.total === 1 && this.searchResults?.total === 1 &&
this.resultsDropdown.isOpen() this.resultsDropdown.isOpen()
) { ) {
this.resultItems.first.nativeElement.click() this.primaryButtons.first.nativeElement.click()
} else if (event.key === 'Escape' && !this.resultsDropdown.isOpen()) { } else if (event.key === 'Escape' && !this.resultsDropdown.isOpen()) {
this.reset(true) this.reset(true)
} }