Skip to content

Commit

Permalink
fix: (CXSPA-965) - SearchBox focus managment (#19181)
Browse files Browse the repository at this point in the history
  • Loading branch information
Pio-Bar authored Sep 16, 2024
1 parent 84b5cf6 commit 5f80201
Show file tree
Hide file tree
Showing 4 changed files with 56 additions and 3 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -520,6 +520,11 @@ export interface FeatureTogglesInterface {
*/
a11yDialogsHeading?: boolean;

/**
* `SearchBoxComponent` should no longer lose focus after closing the popup the esc key.
*/
a11ySearchBoxFocusOnEscape?: boolean;

/**
* In OCC cart requests, it puts parameters of a cart name and cart description
* into a request body, instead of query params.
Expand Down Expand Up @@ -624,6 +629,7 @@ export const defaultFeatureToggles: Required<FeatureTogglesInterface> = {
a11yQuickOrderAriaControls: false,
a11yRemoveStatusLoadedRole: false,
a11yDialogsHeading: false,
a11ySearchBoxFocusOnEscape: false,
occCartNameAndDescriptionInHttpRequestBody: false,
cmsBottomHeaderSlotUsingFlexStyles: false,
useSiteThemeService: false,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -366,6 +366,7 @@ if (environment.cpq) {
a11yQuickOrderAriaControls: true,
a11yRemoveStatusLoadedRole: true,
a11yDialogsHeading: true,
a11ySearchBoxFocusOnEscape: true,
cmsBottomHeaderSlotUsingFlexStyles: true,
useSiteThemeService: false,
};
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,17 @@
import { Component, Input, Pipe, PipeTransform } from '@angular/core';
import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';
import {
ComponentFixture,
fakeAsync,
TestBed,
tick,
waitForAsync,
} from '@angular/core/testing';
import { By } from '@angular/platform-browser';
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
import { RouterModule } from '@angular/router';
import {
CmsSearchBoxComponent,
FeatureConfigService,
I18nTestingModule,
PageType,
ProductSearchService,
Expand Down Expand Up @@ -98,6 +105,12 @@ class MockRoutingService implements Partial<RoutingService> {
getRouterState = () => routerState$.asObservable();
}

class MockFeatureConfigService {
isEnabled() {
return true;
}
}

describe('SearchBoxComponent', () => {
let searchBoxComponent: SearchBoxComponent;
let fixture: ComponentFixture<SearchBoxComponent>;
Expand Down Expand Up @@ -169,6 +182,10 @@ describe('SearchBoxComponent', () => {
provide: RoutingService,
useClass: MockRoutingService,
},
{
provide: FeatureConfigService,
useClass: MockFeatureConfigService,
},
],
}).compileComponents();
}));
Expand Down Expand Up @@ -287,6 +304,20 @@ describe('SearchBoxComponent', () => {
expect(searchBoxComponent.getTabIndex(true)).toBe(0);
expect(searchBoxComponent.getTabIndex(false)).toBe(0);
});

it('should focus the search input if search box is closed with the escape key press', fakeAsync(() => {
fixture.detectChanges();
searchBoxComponent.searchBoxActive = true;
const mockSearchInput = fixture.debugElement.query(
By.css('.searchbox > input')
).nativeElement;
spyOn(mockSearchInput, 'focus');

searchBoxComponent.onEscape();
tick();

expect(mockSearchInput.focus).toHaveBeenCalled();
}));
});

it('should contain 1 product after search', () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import {
ChangeDetectorRef,
Component,
ElementRef,
HostListener,
Input,
OnDestroy,
OnInit,
Expand Down Expand Up @@ -73,6 +74,20 @@ export class SearchBoxComponent implements OnInit, OnDestroy {

@ViewChild('searchButton') searchButton: ElementRef<HTMLElement>;

@HostListener('keydown.escape')
onEscape() {
if (
(this.featureConfigService?.isEnabled('a11ySearchBoxFocusOnEscape') &&
this.winRef.document.activeElement !==
this.searchInput.nativeElement) ||
this.searchBoxActive
) {
setTimeout(() => {
this.searchInput.nativeElement.focus();
});
}
}

iconTypes = ICON_TYPE;

searchBoxActive: boolean = false;
Expand Down Expand Up @@ -212,7 +227,7 @@ export class SearchBoxComponent implements OnInit, OnDestroy {
true
);
this.searchBoxActive = true;
this.searchInput.nativeElement.focus();
this.searchInput?.nativeElement.focus();
}
} else {
this.searchBoxComponentService.toggleBodyClass(SEARCHBOX_IS_ACTIVE, true);
Expand Down Expand Up @@ -256,7 +271,7 @@ export class SearchBoxComponent implements OnInit, OnDestroy {
// TODO: (CXSPA-6929) - Remove feature flag next major release
if (this.a11ySearchBoxMobileFocusEnabled) {
this.changeDetecorRef?.detectChanges();
this.searchButton.nativeElement.focus();
this.searchButton?.nativeElement.focus();
} else {
if (event && event.target) {
(<HTMLElement>event.target).blur();
Expand Down

0 comments on commit 5f80201

Please sign in to comment.