Skip to content

Commit aae8cc5

Browse files
committed
refactor(combobox): only throw error in coercing open action in dev mode, condense click and focus handlers into one.
1 parent c411ad9 commit aae8cc5

File tree

2 files changed

+27
-36
lines changed

2 files changed

+27
-36
lines changed

src/cdk-experimental/combobox/combobox-panel.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,16 +28,17 @@ export class CdkComboboxPanel<T = unknown> {
2828
contentType: AriaHasPopupValue;
2929

3030
constructor(
31-
readonly _templateRef: TemplateRef<unknown>,
32-
readonly _elementRef: ElementRef<HTMLElement>
31+
readonly _templateRef: TemplateRef<unknown>
3332
) {}
3433

3534
/** Tells the parent combobox to close the panel and sends back the content value. */
3635
closePanel(data?: T) {
3736
this.valueUpdated.next(data);
3837
}
3938

39+
// TODO: instead of using a focus function, potentially use cdk/a11y focus trapping
4040
focusContent() {
41+
// TODO: Use an injected document here
4142
document.getElementById(this.contentId)?.focus();
4243
}
4344

src/cdk-experimental/combobox/combobox.ts

Lines changed: 24 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
* found in the LICENSE file at https://angular.io/license
77
*/
88

9+
910
export type OpenAction = 'focus' | 'click' | 'downKey' | 'toggle';
1011
export type OpenActionInput = OpenAction | OpenAction[] | string | null | undefined;
1112

@@ -14,7 +15,7 @@ import {
1415
Directive,
1516
ElementRef,
1617
EventEmitter, HostListener,
17-
Input,
18+
Input, isDevMode,
1819
OnDestroy,
1920
Optional,
2021
Output, ViewContainerRef
@@ -32,16 +33,18 @@ import {Directionality} from '@angular/cdk/bidi';
3233
import {BooleanInput, coerceBooleanProperty, coerceArray} from '@angular/cdk/coercion';
3334
import {DOWN_ARROW, ESCAPE} from '@angular/cdk/keycodes';
3435

36+
const allowedOpenActions = ['focus', 'click', 'downKey', 'toggle'];
3537

3638
@Directive({
3739
selector: '[cdkCombobox]',
3840
exportAs: 'cdkCombobox',
3941
host: {
4042
'role': 'combobox',
4143
'class': 'cdk-combobox',
42-
'(click)': 'onClick()',
43-
'(focus)': 'onFocus()',
44+
'(click)': '_handleInteractions("click")',
45+
'(focus)': '_handleInteractions("focus")',
4446
'(keydown)': 'keydown($event)',
47+
'(document:click)': '_attemptClose($event)',
4548
'[attr.aria-disabled]': 'disabled',
4649
'[attr.aria-owns]': 'contentId',
4750
'[attr.aria-haspopup]': 'contentType',
@@ -109,22 +112,6 @@ export class CdkCombobox<T = unknown> implements OnDestroy, AfterContentInit {
109112
this.panelValueChanged.complete();
110113
}
111114

112-
onClick() {
113-
if (this._openActions.indexOf('toggle') !== -1) {
114-
this.toggle();
115-
} else if (this._openActions.indexOf('click') !== -1) {
116-
this.open();
117-
}
118-
}
119-
120-
onFocus() {
121-
if (this._openActions.indexOf('focus') === -1) {
122-
return;
123-
}
124-
125-
this.open();
126-
}
127-
128115
keydown(event: KeyboardEvent) {
129116
const {keyCode} = event;
130117

@@ -136,7 +123,20 @@ export class CdkCombobox<T = unknown> implements OnDestroy, AfterContentInit {
136123
}
137124
}
138125

139-
@HostListener('document:click', ['$event'])
126+
_handleInteractions(interaction: string) {
127+
if (interaction === 'click') {
128+
if (this._openActions.indexOf('toggle') !== -1) {
129+
this.toggle();
130+
} else if (this._openActions.indexOf('click') !== -1) {
131+
this.open();
132+
}
133+
} else if (interaction === 'focus') {
134+
if (this._openActions.indexOf('focus') !== -1) {
135+
this.open();
136+
}
137+
}
138+
}
139+
140140
_attemptClose(event: MouseEvent) {
141141
if (this.isOpen()) {
142142
let target = event.composedPath ? event.composedPath()[0] : event.target;
@@ -240,21 +240,11 @@ export class CdkCombobox<T = unknown> implements OnDestroy, AfterContentInit {
240240
}
241241

242242
private _coerceOpenActionProperty(input: string | OpenAction[]): OpenAction[] {
243-
let actions: OpenAction[] = [];
244-
const viableActions = ['focus', 'click', 'downKey', 'toggle'];
245-
246-
if (typeof input === 'string') {
247-
const tokens = input.trim().split(/[ ,]+/);
248-
for (const token of tokens) {
249-
if (viableActions.indexOf(token) === -1) {
250-
throw Error(`${token} is not a supported open action`);
251-
}
252-
actions.push(token as OpenAction);
253-
}
254-
} else {
255-
actions = coerceArray(input);
243+
let actions = typeof input === 'string' ? input.trim().split(/[ ,]+/) : input;
244+
if (isDevMode() && actions.some(a => allowedOpenActions.indexOf(a) === -1)) {
245+
throw Error(`${input} is not a support open action for CdkCombobox`);
256246
}
257-
return actions;
247+
return actions as OpenAction[];
258248
}
259249

260250
static ngAcceptInputType_openActions: OpenActionInput;

0 commit comments

Comments
 (0)