Skip to content

Commit 5bd1d5e

Browse files
committed
fix(cdk-experimental/combobox): refactor combobox filtering
1 parent 8d8afa8 commit 5bd1d5e

27 files changed

+1020
-1051
lines changed

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

Lines changed: 369 additions & 560 deletions
Large diffs are not rendered by default.

src/cdk-experimental/combobox/combobox.ts

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,9 @@ import {
1313
ElementRef,
1414
inject,
1515
input,
16+
model,
1617
signal,
18+
untracked,
1719
WritableSignal,
1820
} from '@angular/core';
1921
import {DeferredContent, DeferredContentAware} from '@angular/cdk-experimental/deferred-content';
@@ -53,17 +55,16 @@ export class CdkCombobox<V> {
5355
/** Whether the combobox is focused. */
5456
readonly isFocused = signal(false);
5557

56-
/** The function used to filter the options in the popup based on the input text. */
57-
filter = input<(inputText: string, itemText: string) => boolean>((inputText, itemText) =>
58-
itemText.toLowerCase().includes(inputText.toLowerCase()),
59-
);
58+
/** The value of the first matching item in the popup. */
59+
firstMatch = input<V | undefined>(undefined);
6060

6161
/** Whether the listbox has received focus yet. */
6262
private _hasBeenFocused = signal(false);
6363

6464
/** The combobox ui pattern. */
6565
readonly pattern = new ComboboxPattern<any, V>({
6666
...this,
67+
inputValue: signal(''),
6768
inputEl: signal(undefined),
6869
containerEl: () => this._elementRef.nativeElement,
6970
popupControls: () => this.popup()?.controls(),
@@ -89,6 +90,7 @@ export class CdkCombobox<V> {
8990
exportAs: 'cdkComboboxInput',
9091
host: {
9192
'role': 'combobox',
93+
'[value]': 'value()',
9294
'[attr.aria-expanded]': 'combobox.pattern.expanded()',
9395
'[attr.aria-activedescendant]': 'combobox.pattern.activedescendant()',
9496
'[attr.aria-controls]': 'combobox.pattern.popupId()',
@@ -98,15 +100,25 @@ export class CdkCombobox<V> {
98100
})
99101
export class CdkComboboxInput {
100102
/** The element that the combobox is attached to. */
101-
private readonly _elementRef = inject(ElementRef);
103+
private readonly _elementRef = inject<ElementRef<HTMLInputElement>>(ElementRef);
102104

103105
/** The combobox that the input belongs to. */
104106
readonly combobox = inject(CdkCombobox);
105107

108+
/** The value of the input. */
109+
value = model<string>('');
110+
106111
constructor() {
107112
(this.combobox.pattern.inputs.inputEl as WritableSignal<HTMLInputElement>).set(
108113
this._elementRef.nativeElement,
109114
);
115+
this.combobox.pattern.inputs.inputValue = this.value;
116+
117+
/** Focuses & selects the first item in the combobox if the user changes the input value. */
118+
afterRenderEffect(() => {
119+
this.combobox.popup()?.controls()?.items();
120+
untracked(() => this.combobox.pattern.onFilter());
121+
});
110122
}
111123
}
112124

src/cdk-experimental/listbox/listbox.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -197,7 +197,6 @@ export class CdkListbox<V> {
197197
'[attr.tabindex]': 'pattern.tabindex()',
198198
'[attr.aria-selected]': 'pattern.selected()',
199199
'[attr.aria-disabled]': 'pattern.disabled()',
200-
'[attr.inert]': 'pattern.inert()',
201200
},
202201
})
203202
export class CdkOption<V> {

src/cdk-experimental/tree/tree.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -222,7 +222,6 @@ export class CdkTree<V> {
222222
'[attr.aria-setsize]': 'pattern.setsize()',
223223
'[attr.aria-posinset]': 'pattern.posinset()',
224224
'[attr.tabindex]': 'pattern.tabindex()',
225-
'[attr.inert]': 'pattern.inert()',
226225
},
227226
})
228227
export class CdkTreeItem<V> implements OnInit, OnDestroy, HasElement {

src/cdk-experimental/ui-patterns/behaviors/list-focus/list-focus.ts

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -22,9 +22,6 @@ export interface ListFocusItem {
2222

2323
/** The index of the item in the list. */
2424
index: SignalLike<number>;
25-
26-
/** Whether the item is currently focused. */
27-
inert?: SignalLike<true | null>;
2825
}
2926

3027
/** Represents the required inputs for a collection that contains focusable items. */
@@ -115,6 +112,6 @@ export class ListFocus<T extends ListFocusItem> {
115112

116113
/** Returns true if the given item can be navigated to. */
117114
isFocusable(item: T): boolean {
118-
return (!item.disabled() || !this.inputs.skipDisabled()) && !item.inert?.();
115+
return !item.disabled() || !this.inputs.skipDisabled();
119116
}
120117
}

0 commit comments

Comments
 (0)