66 * found in the LICENSE file at https://angular.dev/license
77 */
88
9- import { contentChild , Directive , inject } from '@angular/core' ;
9+ import {
10+ afterRenderEffect ,
11+ contentChild ,
12+ Directive ,
13+ ElementRef ,
14+ inject ,
15+ input ,
16+ model ,
17+ signal ,
18+ WritableSignal ,
19+ } from '@angular/core' ;
1020import { DeferredContent , DeferredContentAware } from '@angular/cdk-experimental/deferred-content' ;
21+ import { ComboboxPattern , ComboboxPopupControls } from '../ui-patterns' ;
1122
1223@Directive ( {
1324 selector : '[cdkCombobox]' ,
@@ -18,25 +29,75 @@ import {DeferredContent, DeferredContentAware} from '@angular/cdk-experimental/d
1829 inputs : [ 'preserveContent' ] ,
1930 } ,
2031 ] ,
32+ host : {
33+ '[attr.data-expanded]' : 'pattern.expanded()' ,
34+ '(input)' : 'pattern.onInput($event)' ,
35+ '(keydown)' : 'pattern.onKeydown($event)' ,
36+ '(pointerup)' : 'pattern.onPointerup($event)' ,
37+ '(focusin)' : 'pattern.onFocusIn()' ,
38+ '(focusout)' : 'pattern.onFocusOut($event)' ,
39+ } ,
2140} )
22- export class CdkCombobox {
41+ export class CdkCombobox < V > {
42+ /** The element that the combobox is attached to. */
43+ private readonly _elementRef = inject ( ElementRef ) ;
44+
2345 /** The DeferredContentAware host directive. */
2446 private readonly _deferredContentAware = inject ( DeferredContentAware , { optional : true } ) ;
2547
2648 /** The combobox popup. */
27- readonly popup = contentChild ( CdkComboboxPopup ) ;
49+ readonly popup = contentChild < CdkComboboxPopup < V > > ( CdkComboboxPopup ) ;
50+
51+ /** The filter mode for the combobox. */
52+ filterMode = input < 'manual' | 'auto-select' | 'highlight' > ( 'manual' ) ;
53+
54+ /** Whether the combobox is focused. */
55+ readonly isFocused = signal ( false ) ;
56+
57+ /** The values of the current selected items. */
58+ value = model < V | undefined > ( undefined ) ;
59+
60+ /** The combobox ui pattern. */
61+ readonly pattern = new ComboboxPattern < any , V > ( {
62+ ...this ,
63+ inputEl : signal ( undefined ) ,
64+ containerEl : signal ( undefined ) ,
65+ popupControls : ( ) => this . popup ( ) ?. actions ( ) ,
66+ } ) ;
2867
2968 constructor ( ) {
30- this . _deferredContentAware ?. contentVisible . set ( true ) ;
69+ ( this . pattern . inputs . containerEl as WritableSignal < HTMLElement > ) . set (
70+ this . _elementRef . nativeElement ,
71+ ) ;
72+
73+ afterRenderEffect ( ( ) => {
74+ this . _deferredContentAware ?. contentVisible . set ( this . pattern . isFocused ( ) ) ;
75+ } ) ;
3176 }
3277}
3378
3479@Directive ( {
3580 selector : 'input[cdkComboboxInput]' ,
3681 exportAs : 'cdkComboboxInput' ,
37- host : { 'role' : 'combobox' } ,
82+ host : {
83+ 'role' : 'combobox' ,
84+ '[attr.aria-expanded]' : 'combobox.pattern.expanded()' ,
85+ '[attr.aria-activedescendant]' : 'combobox.pattern.activedescendant()' ,
86+ } ,
3887} )
39- export class CdkComboboxInput { }
88+ export class CdkComboboxInput {
89+ /** The element that the combobox is attached to. */
90+ private readonly _elementRef = inject ( ElementRef ) ;
91+
92+ /** The combobox that the input belongs to. */
93+ readonly combobox = inject ( CdkCombobox ) ;
94+
95+ constructor ( ) {
96+ ( this . combobox . pattern . inputs . inputEl as WritableSignal < HTMLInputElement > ) . set (
97+ this . _elementRef . nativeElement ,
98+ ) ;
99+ }
100+ }
40101
41102@Directive ( {
42103 selector : 'ng-template[cdkComboboxPopupContent]' ,
@@ -49,7 +110,10 @@ export class CdkComboboxPopupContent {}
49110 selector : '[cdkComboboxPopup]' ,
50111 exportAs : 'cdkComboboxPopup' ,
51112} )
52- export class CdkComboboxPopup {
113+ export class CdkComboboxPopup < V > {
53114 /** The combobox that the popup belongs to. */
54- readonly combobox = inject ( CdkCombobox , { optional : true } ) ;
115+ readonly combobox = inject < CdkCombobox < V > > ( CdkCombobox , { optional : true } ) ;
116+
117+ /** The actions that the combobox can perform on the popup. */
118+ readonly actions = signal < ComboboxPopupControls < any , V > | undefined > ( undefined ) ;
55119}
0 commit comments