77 */
88
99import {
10+ booleanAttribute ,
1011 computed ,
1112 contentChildren ,
1213 Directive ,
@@ -18,7 +19,7 @@ import {
1819 signal ,
1920} from '@angular/core' ;
2021import { OptionPattern } from '@angular/cdk-experimental/ui-patterns/listbox/option' ;
21- import { ListboxInputs , ListboxPattern } from '@angular/cdk-experimental/ui-patterns/listbox/listbox' ;
22+ import { ListboxPattern } from '@angular/cdk-experimental/ui-patterns/listbox/listbox' ;
2223import { Directionality } from '@angular/cdk/bidi' ;
2324import { startWith , takeUntil } from 'rxjs/operators' ;
2425import { Subject } from 'rxjs' ;
@@ -43,31 +44,43 @@ import {Subject} from 'rxjs';
4344 host : {
4445 'role' : 'listbox' ,
4546 'class' : 'cdk-listbox' ,
46- '[attr.tabindex]' : 'state .tabindex()' ,
47- '[attr.aria-disabled]' : 'state .disabled()' ,
48- '[attr.aria-multiselectable]' : 'state .multiselectable()' ,
49- '[attr.aria-activedescendant]' : 'state .activedescendant()' ,
50- '[attr.aria-orientation]' : 'state .orientation()' ,
51- '(focusin)' : 'state .onFocus()' ,
52- '(keydown)' : 'state .onKeydown($event)' ,
53- '(mousedown)' : 'state .onMousedown($event)' ,
47+ '[attr.tabindex]' : 'pattern .tabindex()' ,
48+ '[attr.aria-disabled]' : 'pattern .disabled()' ,
49+ '[attr.aria-multiselectable]' : 'pattern .multiselectable()' ,
50+ '[attr.aria-activedescendant]' : 'pattern .activedescendant()' ,
51+ '[attr.aria-orientation]' : 'pattern .orientation()' ,
52+ '(focusin)' : 'pattern .onFocus()' ,
53+ '(keydown)' : 'pattern .onKeydown($event)' ,
54+ '(mousedown)' : 'pattern .onMousedown($event)' ,
5455 } ,
5556} )
56- export class CdkListbox implements ListboxInputs , OnDestroy {
57+ export class CdkListbox implements OnDestroy {
5758 /** The directionality (LTR / RTL) context for the application (or a subtree of it). */
5859 private _dir = inject ( Directionality ) ;
5960
61+ /** A signal wrapper for directionality. */
62+ private directionality = signal < 'ltr' | 'rtl' > ( 'ltr' ) ;
63+
64+ /** The CdkOptions nested inside of the CdkListbox. */
65+ private _cdkOptions = contentChildren ( CdkOption , { descendants : true } ) ;
66+
67+ /** The Option UIPatterns of the child CdkOptions. */
68+ private items = computed ( ( ) => this . _cdkOptions ( ) . map ( option => option . pattern ) ) ;
69+
70+ /** Emits when the list has been destroyed. */
71+ private readonly _destroyed = new Subject < void > ( ) ;
72+
6073 /** Whether the list is vertically or horizontally oriented. */
6174 orientation = input < 'vertical' | 'horizontal' > ( 'vertical' ) ;
6275
6376 /** Whether multiple items in the list can be selected at once. */
64- multiselectable = input < boolean > ( false ) ;
77+ multiselectable = input ( false , { transform : booleanAttribute } ) ;
6578
6679 /** Whether focus should wrap when navigating. */
67- wrap = input < boolean > ( true ) ;
80+ wrap = input ( true , { transform : booleanAttribute } ) ;
6881
6982 /** Whether disabled items in the list should be skipped when navigating. */
70- skipDisabled = input < boolean > ( true ) ;
83+ skipDisabled = input ( true , { transform : booleanAttribute } ) ;
7184
7285 /** The focus strategy used by the list. */
7386 focusMode = input < 'roving' | 'activedescendant' > ( 'roving' ) ;
@@ -76,31 +89,23 @@ export class CdkListbox implements ListboxInputs, OnDestroy {
7689 selectionMode = input < 'follow' | 'explicit' > ( 'follow' ) ;
7790
7891 /** The amount of time before the typeahead search is reset. */
79- delay = input < number > ( 0.5 ) ; // Picked arbitrarily.
92+ typeaheadDelay = input < number > ( 0.5 ) ; // Picked arbitrarily.
93+
94+ /** Whether the listbox is disabled. */
95+ disabled = input ( false , { transform : booleanAttribute } ) ;
8096
8197 /** The ids of the current selected items. */
8298 selectedIds = model < string [ ] > ( [ ] ) ;
8399
84100 /** The current index that has been navigated to. */
85101 activeIndex = model < number > ( 0 ) ;
86102
87- /** The CdkOptions nested inside of the CdkListbox. */
88- private _cdkOptions = contentChildren ( CdkOption , { descendants : true } ) ;
89-
90- /** The Option UIPatterns of the child CdkOptions. */
91- items = computed ( ( ) => this . _cdkOptions ( ) . map ( option => option . state ) ) ;
92-
93- /** A signal wrapper for directionality. */
94- directionality = signal < 'ltr' | 'rtl' > ( 'ltr' ) ;
95-
96- /** Emits when the list has been destroyed. */
97- private readonly _destroyed = new Subject < void > ( ) ;
98-
99- /** Whether the listbox is disabled. */
100- disabled = input < boolean > ( false ) ;
101-
102103 /** The Listbox UIPattern. */
103- state : ListboxPattern = new ListboxPattern ( this ) ;
104+ pattern : ListboxPattern = new ListboxPattern ( {
105+ ...this ,
106+ items : this . items ,
107+ directionality : this . directionality ,
108+ } ) ;
104109
105110 constructor ( ) {
106111 this . _dir . change
@@ -113,16 +118,19 @@ export class CdkListbox implements ListboxInputs, OnDestroy {
113118 }
114119}
115120
121+ // TODO(wagnermaciel): Figure out how we actually want to do this.
122+ let count = 0 ;
123+
116124/** A selectable option in a CdkListbox. */
117125@Directive ( {
118126 selector : '[cdkOption]' ,
119127 exportAs : 'cdkOption' ,
120128 host : {
121129 'role' : 'option' ,
122130 'class' : 'cdk-option' ,
123- '[attr.aria-selected]' : 'state .selected()' ,
124- '[attr.tabindex]' : 'state .tabindex()' ,
125- '[attr.aria-disabled]' : 'state .disabled()' ,
131+ '[attr.aria-selected]' : 'pattern .selected()' ,
132+ '[attr.tabindex]' : 'pattern .tabindex()' ,
133+ '[attr.aria-disabled]' : 'pattern .disabled()' ,
126134 } ,
127135} )
128136export class CdkOption {
@@ -132,21 +140,30 @@ export class CdkOption {
132140 /** The parent CdkListbox. */
133141 private _cdkListbox = inject ( CdkListbox ) ;
134142
135- /** Whether an item is disabled . */
136- disabled = input < boolean > ( false ) ;
143+ /** A unique identifier for the option . */
144+ private id = computed ( ( ) => ` ${ count ++ } ` ) ;
137145
138146 /** The text used by the typeahead search. */
139- label = input < string > ( ) ;
147+ private searchTerm = computed ( ( ) => this . label ( ) ?? this . element ( ) . textContent ) ;
140148
141- /** The text used by the typeahead search . */
142- searchTerm = computed ( ( ) => this . label ( ) ?? this . element ( ) . textContent ) ;
149+ /** The parent Listbox UIPattern . */
150+ private listbox = computed ( ( ) => this . _cdkListbox . pattern ) ;
143151
144- /** A reference to the option element. */
145- element = computed ( ( ) => this . _elementRef . nativeElement ) ;
152+ /** A reference to the option element to be focused on navigation . */
153+ private element = computed ( ( ) => this . _elementRef . nativeElement ) ;
146154
147- /** The parent Listbox UIPattern. */
148- listbox = computed ( ( ) => this . _cdkListbox . state ) ;
155+ /** Whether an item is disabled. */
156+ disabled = input ( false , { transform : booleanAttribute } ) ;
157+
158+ /** The text used by the typeahead search. */
159+ label = input < string > ( ) ;
149160
150161 /** The Option UIPattern. */
151- state = new OptionPattern ( this ) ;
162+ pattern = new OptionPattern ( {
163+ ...this ,
164+ id : this . id ,
165+ listbox : this . listbox ,
166+ element : this . element ,
167+ searchTerm : this . searchTerm ,
168+ } ) ;
152169}
0 commit comments