Skip to content

Commit

Permalink
feat: Add refocus prop to prevent refocus after close (#272)
Browse files Browse the repository at this point in the history
* feat: Add refocus prop to prevent refocus after close

* refactor: Add option to component instance and type interface

* Add tests for the refocus prop

Co-authored-by: Dan <[email protected]>
  • Loading branch information
gavmck and DanWebb authored Feb 18, 2020
1 parent 52a7d60 commit 9d2bdbf
Show file tree
Hide file tree
Showing 6 changed files with 70 additions and 31 deletions.
41 changes: 11 additions & 30 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 6 additions & 0 deletions src/app/doc/parts/options/options.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,12 @@ export class OptionsComponent implements OnInit {
type: 'string',
defaultValue: 'undefined',
description: 'Define an accessible description for your modal. Enter the id of your description content.'
},
{
name: 'refocus',
type: 'boolean',
defaultValue: 'true',
description: 'Refocus on the last focused element after closing the modal.'
}
];
// tslint:enable:max-line-length
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@ export class NgxSmartModalComponent implements OnInit, OnDestroy, AfterViewInit
@Input() public ariaLabel: string | null = null;
@Input() public ariaLabelledBy: string | null = null;
@Input() public ariaDescribedBy: string | null = null;
@Input() public refocus: boolean = true;

@Output() public visibleChange: EventEmitter<boolean> = new EventEmitter<boolean>();
@Output() public onClose: EventEmitter<any> = new EventEmitter();
Expand Down
1 change: 1 addition & 0 deletions src/ngx-smart-modal/src/config/ngx-smart-modal.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,4 +16,5 @@ export interface INgxSmartModalOptions {
ariaLabel?: string;
ariaLabelledBy?: string;
ariaDescribedBy?: string;
refocus?: boolean;
}
5 changes: 4 additions & 1 deletion src/ngx-smart-modal/src/services/ngx-smart-modal.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -255,6 +255,7 @@ export class NgxSmartModalService {
if (typeof options.ariaLabel === 'string') { componentRef.instance.ariaLabel = options.ariaLabel; }
if (typeof options.ariaLabelledBy === 'string') { componentRef.instance.ariaLabelledBy = options.ariaLabelledBy; }
if (typeof options.ariaDescribedBy === 'string') { componentRef.instance.ariaDescribedBy = options.ariaDescribedBy; }
if (typeof options.refocus === 'boolean') { componentRef.instance.refocus = options.refocus; }

this._appRef.attachView(componentRef.hostView);

Expand Down Expand Up @@ -383,7 +384,9 @@ export class NgxSmartModalService {
modal.markForCheck();
modal.onCloseFinished.emit(modal);
modal.onAnyCloseEventFinished.emit(modal);
this.lastElementFocused.focus();
if (modal.refocus) {
this.lastElementFocused.focus();
}
}, modal.hideDelay);

return true;
Expand Down
47 changes: 47 additions & 0 deletions src/ngx-smart-modal/tests/services/ngx-smart-modal.service.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -354,6 +354,53 @@ describe('NgxSmartModalService', () => {
service.create('test2', 'test content');
}));

it('should refocus on close', fakeAsync(inject([NgxSmartModalService], (service: NgxSmartModalService) => {
const fixture = TestBed.createComponent(NgxSmartModalComponent);
const focusElement = fixture.nativeElement.appendChild(document.createElement('input'));
const app = fixture.debugElement.componentInstance;
app.identifier = 'test';
app.target = 'test-target';

service.addModal({ id: 'test', modal: app });
focusElement.focus();

expect(document.activeElement === focusElement).toBeTruthy();

service.open('test');
tick(501);

expect(document.activeElement === focusElement).toBeFalsy();

service.close('test');
tick(501);

expect(document.activeElement === focusElement).toBeTruthy();
})));

it('should not refocus on close if refocus is turned off', fakeAsync(inject([NgxSmartModalService], (service: NgxSmartModalService) => {
const fixture = TestBed.createComponent(NgxSmartModalComponent);
const focusElement = fixture.nativeElement.appendChild(document.createElement('input'));
const app = fixture.debugElement.componentInstance;
app.identifier = 'test';
app.target = 'test-target';
app.refocus = false;

service.addModal({ id: 'test', modal: app });
focusElement.focus();

expect(document.activeElement === focusElement).toBeTruthy();

service.open('test');
tick(501);

expect(document.activeElement === focusElement).toBeFalsy();

service.close('test');
tick(501);

expect(document.activeElement === focusElement).toBeFalsy();
})));

it('should resolve content', inject([NgxSmartModalService], (service: NgxSmartModalService) => {
(service as any)._resolveNgContent('test content');
(service as any)._resolveNgContent(FakeComponent);
Expand Down

1 comment on commit 9d2bdbf

@vercel
Copy link

@vercel vercel bot commented on 9d2bdbf Feb 18, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.