99import { KeyboardEventManager , PointerEventManager } from '../behaviors/event-manager' ;
1010import { computed , signal , untracked } from '@angular/core' ;
1111import { SignalLike , WritableSignalLike } from '../behaviors/signal-like/signal-like' ;
12+ import { ComboboxLike , ComboboxNavigation } from '../combobox/combobox' ;
1213import { ExpansionItem } from '../behaviors/expansion/expansion' ;
1314
1415/** Represents the required inputs for a simple combobox. */
15- export interface SimpleComboboxInputs extends ExpansionItem {
16+ export interface SimpleComboboxInputs < V > extends ExpansionItem {
1617 /** The value of the combobox. */
1718 value : WritableSignalLike < string > ;
1819
@@ -25,18 +26,27 @@ export interface SimpleComboboxInputs extends ExpansionItem {
2526 /** An inline suggestion to be displayed in the input. */
2627 inlineSuggestion : SignalLike < string | undefined > ;
2728
29+ /** The active value in the popup (the option's value). */
30+ activeValue : SignalLike < V | undefined > ;
31+
2832 /** Whether the combobox is disabled. */
2933 disabled : SignalLike < boolean > ;
34+
35+ /** The filtering mode for the combobox. */
36+ filterMode : SignalLike < 'manual' | 'auto-select' | 'highlight' > ;
3037}
3138
3239/** Controls the state of a simple combobox. */
33- export class SimpleComboboxPattern {
40+ export class SimpleComboboxPattern < V > {
3441 /** Whether the combobox is expanded. */
3542 readonly expanded : WritableSignalLike < boolean > ;
3643
3744 /** The value of the combobox. */
3845 readonly value : WritableSignalLike < string > ;
3946
47+ /** The ID of the currently highlighted item in the popup. */
48+ readonly highlightedItem = signal < string | undefined > ( undefined ) ;
49+
4050 /** The element that the combobox is attached to. */
4151 readonly element = ( ) => this . inputs . element ( ) ;
4252
@@ -147,7 +157,7 @@ export class SimpleComboboxPattern {
147157 return manager ;
148158 } ) ;
149159
150- constructor ( readonly inputs : SimpleComboboxInputs ) {
160+ constructor ( readonly inputs : SimpleComboboxInputs < V > ) {
151161 this . expanded = inputs . expanded ;
152162 this . value = inputs . value ;
153163 }
@@ -227,6 +237,13 @@ export class SimpleComboboxPattern {
227237 const comboboxFocused = this . isFocused ( ) ;
228238 const popupFocused = ! ! this . inputs . popup ( ) ?. isFocused ( ) ;
229239 if ( expanded && ! comboboxFocused && ! popupFocused ) {
240+ const activeValue = untracked ( ( ) => this . inputs . activeValue ?.( ) ) ;
241+
242+ // Auto-commit highlighted item on blur for non-manual modes (auto-select and highlight).
243+ // The Listbox pushes its highlighted value here, letting the headless directive sync it.
244+ if ( activeValue && this . inputs . filterMode ( ) !== 'manual' ) {
245+ this . value . set ( activeValue as any ) ; // Type assertion if needed
246+ }
230247 this . expanded . set ( false ) ;
231248 }
232249 }
@@ -245,6 +262,18 @@ export interface SimpleComboboxPopupInputs {
245262
246263 /** The ID of the popup. */
247264 popupId : SignalLike < string | undefined > ;
265+
266+ /** Navigates to the first item in the popup. */
267+ first : ( ) => void ;
268+
269+ /** Navigates to the last item in the popup. */
270+ last : ( ) => void ;
271+
272+ /** Focuses the currently selected item in the popup. */
273+ focusSelected : ( ) => void ;
274+
275+ /** Focuses the popup with the given navigation instruction when ready. */
276+ focusOnReady : ( nav : ComboboxNavigation ) => void ;
248277}
249278
250279/** Controls the state of a simple combobox popup. */
@@ -264,6 +293,29 @@ export class SimpleComboboxPopupPattern {
264293 /** Whether the popup is focused. */
265294 readonly isFocused = signal ( false ) ;
266295
296+ /** Navigates to the first item in the popup. */
297+ first ( ) {
298+ this . inputs . first ( ) ;
299+ }
300+
301+ /** Navigates to the last item in the popup. */
302+ last ( ) {
303+ this . inputs . last ( ) ;
304+ }
305+
306+ /** Focuses the currently selected item in the popup. */
307+ focusSelected ( ) {
308+ this . inputs . focusSelected ( ) ;
309+ }
310+
311+ /**
312+ * Focuses the popup with the given navigation instruction when ready.
313+ * This is used for lazy rendering (when the popup isn't in the DOM yet synchronously).
314+ */
315+ focusOnReady ( nav : ComboboxNavigation ) {
316+ this . inputs . focusOnReady ( nav ) ;
317+ }
318+
267319 constructor ( readonly inputs : SimpleComboboxPopupInputs ) { }
268320
269321 /** Handles focus in events for the popup. */
0 commit comments