Skip to content

Commit 113997b

Browse files
tinayuangaojelbourn
authored andcommitted
fix(select): Improve the a11y of select component by making overlay
always exist in the DOM
1 parent afb0ee3 commit 113997b

File tree

6 files changed

+146
-45
lines changed

6 files changed

+146
-45
lines changed

src/cdk/overlay/overlay-directives.spec.ts

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,18 @@ describe('Overlay directives', () => {
120120
'Expected overlay to have been detached.');
121121
});
122122

123+
it('should not close when pressing escape when changed the setting of "disableClose"', () => {
124+
fixture.componentInstance.isOpen = true;
125+
fixture.componentInstance.disableClose = true;
126+
fixture.detectChanges();
127+
128+
dispatchKeyboardEvent(document.body, 'keydown', ESCAPE);
129+
fixture.detectChanges();
130+
131+
expect(overlayContainerElement.textContent!.trim()).not.toBe('',
132+
'Expected overlay to have not been detached.');
133+
});
134+
123135
it('should not depend on the order in which the `origin` and `open` are set', async(() => {
124136
fixture.destroy();
125137

@@ -479,6 +491,7 @@ describe('Overlay directives', () => {
479491
[cdkConnectedOverlayFlexibleDimensions]="flexibleDimensions"
480492
[cdkConnectedOverlayGrowAfterOpen]="growAfterOpen"
481493
[cdkConnectedOverlayPush]="push"
494+
[cdkConnectedOverlayDisableClose]="disableClose"
482495
cdkConnectedOverlayBackdropClass="mat-test-class"
483496
(backdropClick)="backdropClickHandler($event)"
484497
[cdkConnectedOverlayOffsetX]="offsetX"
@@ -511,6 +524,7 @@ class ConnectedOverlayDirectiveTest {
511524
flexibleDimensions: boolean;
512525
growAfterOpen: boolean;
513526
push: boolean;
527+
disableClose: boolean = false;
514528
backdropClickHandler = jasmine.createSpy('backdropClick handler');
515529
positionChangeHandler = jasmine.createSpy('positionChange handler');
516530
keydownHandler = jasmine.createSpy('keydown handler');

src/cdk/overlay/overlay-directives.ts

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,8 @@ export class CdkConnectedOverlay implements OnDestroy, OnChanges {
114114
private _offsetX: number;
115115
private _offsetY: number;
116116
private _position: FlexibleConnectedPositionStrategy;
117+
private _disableClose = false;
118+
private _open = false;
117119

118120
/** Origin for the connected overlay. */
119121
@Input('cdkConnectedOverlayOrigin') origin: CdkOverlayOrigin;
@@ -165,8 +167,15 @@ export class CdkConnectedOverlay implements OnDestroy, OnChanges {
165167
@Input('cdkConnectedOverlayScrollStrategy') scrollStrategy: ScrollStrategy =
166168
this._scrollStrategy();
167169

170+
/** Whether the overlay closes when the user pressed the Escape key. */
171+
@Input('cdkConnectedOverlayDisableClose')
172+
get disableClose() { return this._disableClose; }
173+
set disableClose(value: any) { this._disableClose = coerceBooleanProperty(value); }
174+
168175
/** Whether the overlay is open. */
169-
@Input('cdkConnectedOverlayOpen') open: boolean = false;
176+
@Input('cdkConnectedOverlayOpen')
177+
get open() { return this._open; }
178+
set open(value: any) { this._open = coerceBooleanProperty(value); }
170179

171180
/** Whether or not the overlay should attach a backdrop. */
172181
@Input('cdkConnectedOverlayHasBackdrop')
@@ -340,7 +349,7 @@ export class CdkConnectedOverlay implements OnDestroy, OnChanges {
340349
this._overlayRef!.keydownEvents().subscribe((event: KeyboardEvent) => {
341350
this.overlayKeydown.next(event);
342351

343-
if (event.keyCode === ESCAPE) {
352+
if (!this.disableClose && event.keyCode === ESCAPE) {
344353
this._detachOverlay();
345354
}
346355
});
@@ -359,11 +368,9 @@ export class CdkConnectedOverlay implements OnDestroy, OnChanges {
359368
this.attach.emit();
360369
}
361370

362-
if (this.hasBackdrop) {
363-
this._backdropSubscription = this._overlayRef.backdropClick().subscribe(event => {
364-
this.backdropClick.emit(event);
365-
});
366-
}
371+
this._backdropSubscription = this._overlayRef.backdropClicks().subscribe(event => {
372+
this.backdropClick.emit(event);
373+
});
367374
}
368375

369376
/** Detaches the overlay and unsubscribes to backdrop clicks if backdrop exists */

src/cdk/overlay/overlay-ref.ts

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -124,7 +124,7 @@ export class OverlayRef implements PortalOutlet, OverlayReference {
124124
this._togglePointerEvents(true);
125125

126126
if (this._config.hasBackdrop) {
127-
this._attachBackdrop();
127+
this.attachBackdrop();
128128
}
129129

130130
if (this._config.panelClass) {
@@ -213,6 +213,10 @@ export class OverlayRef implements PortalOutlet, OverlayReference {
213213
return this._portalOutlet.hasAttached();
214214
}
215215

216+
backdropClicks() {
217+
return this._backdropClick;
218+
}
219+
216220
/** Gets an observable that emits when the backdrop has been clicked. */
217221
backdropClick(): Observable<MouseEvent> {
218222
return this._backdropClick.asObservable();
@@ -293,7 +297,7 @@ export class OverlayRef implements PortalOutlet, OverlayReference {
293297
}
294298

295299
/** Attaches a backdrop for this overlay. */
296-
private _attachBackdrop() {
300+
attachBackdrop() {
297301
const showingClass = 'cdk-overlay-backdrop-showing';
298302

299303
this._backdropElement = this._document.createElement('div');

src/lib/select/select.html

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -18,32 +18,31 @@
1818
<ng-template
1919
cdk-connected-overlay
2020
cdkConnectedOverlayLockPosition
21-
cdkConnectedOverlayHasBackdrop
21+
cdkConnectedOverlayOpen
22+
cdkConnectedOverlayDisableClose
2223
cdkConnectedOverlayBackdropClass="cdk-overlay-transparent-backdrop"
2324
[cdkConnectedOverlayScrollStrategy]="_scrollStrategy"
2425
[cdkConnectedOverlayOrigin]="origin"
25-
[cdkConnectedOverlayOpen]="panelOpen"
2626
[cdkConnectedOverlayPositions]="_positions"
2727
[cdkConnectedOverlayMinWidth]="_triggerRect?.width"
2828
[cdkConnectedOverlayOffsetY]="_offsetY"
2929
(backdropClick)="close()"
3030
(attach)="_onAttached()"
3131
(detach)="close()">
32-
3332
<div
3433
#panel
3534
class="mat-select-panel {{ _getPanelTheme() }}"
35+
[class.cdk-visually-hidden]="!panelOpen"
3636
[ngClass]="panelClass"
37-
[@transformPanel]="multiple ? 'showing-multiple' : 'showing'"
37+
[@transformPanel]="_transformPanel"
3838
(@transformPanel.done)="_panelDoneAnimatingStream.next($event.toState)"
3939
[style.transformOrigin]="_transformOrigin"
4040
[class.mat-select-panel-done-animating]="_panelDoneAnimating"
4141
[style.font-size.px]="_triggerFontSize"
4242
(keydown)="_handleKeydown($event)">
43-
4443
<div
4544
class="mat-select-content"
46-
[@fadeInContent]="'showing'"
45+
[@fadeInContent]="panelOpen ? 'showing' : 'void'"
4746
(@fadeInContent.done)="_onFadeInDone()">
4847
<ng-content></ng-content>
4948
</div>

0 commit comments

Comments
 (0)