@@ -88,8 +88,8 @@ export class ComboboxPattern {
8888 return 'none' ;
8989 } ) ;
9090
91- /** A relay for keyboard events to the popup. */
92- readonly keyboardEventRelay = signal < KeyboardEvent | undefined > ( undefined ) ;
91+ /** A relay queue for keyboard events to the popup. */
92+ readonly keyboardEventRelay = signal < KeyboardEvent [ ] > ( [ ] ) ;
9393
9494 /** Whether the combobox is focused. */
9595 readonly isFocused = signal ( false ) ;
@@ -137,44 +137,43 @@ export class ComboboxPattern {
137137 . on (
138138 'ArrowLeft' ,
139139 e => {
140- this . keyboardEventRelay . set ( e ) ;
140+ this . _relayKeydown ( e ) ;
141141 } ,
142142 { preventDefault : this . popupType ( ) !== 'listbox' , ignoreRepeat : false } ,
143143 )
144144 . on (
145145 'ArrowRight' ,
146146 e => {
147- this . keyboardEventRelay . set ( e ) ;
147+ this . _relayKeydown ( e ) ;
148148 } ,
149149 { preventDefault : this . popupType ( ) !== 'listbox' , ignoreRepeat : false } ,
150150 )
151- . on ( 'ArrowUp' , e => this . keyboardEventRelay . set ( e ) , { ignoreRepeat : false } )
152- . on ( 'ArrowDown' , e => this . keyboardEventRelay . set ( e ) , { ignoreRepeat : false } )
153- . on ( Modifier . Shift , 'ArrowUp' , e => this . keyboardEventRelay . set ( e ) , { ignoreRepeat : false } )
154- . on ( Modifier . Shift , 'ArrowDown' , e => this . keyboardEventRelay . set ( e ) , { ignoreRepeat : false } )
155- . on ( 'Home' , e => this . keyboardEventRelay . set ( e ) )
156- . on ( 'End' , e => this . keyboardEventRelay . set ( e ) )
157- . on ( 'PageUp' , e => this . keyboardEventRelay . set ( e ) )
158- . on ( 'PageDown' , e => this . keyboardEventRelay . set ( e ) )
151+ . on ( 'ArrowUp' , e => this . _relayKeydown ( e ) , { ignoreRepeat : false } )
152+ . on ( 'ArrowDown' , e => this . _relayKeydown ( e ) , { ignoreRepeat : false } )
153+ . on ( Modifier . Shift , 'ArrowUp' , e => this . _relayKeydown ( e ) , { ignoreRepeat : false } )
154+ . on ( Modifier . Shift , 'ArrowDown' , e => this . _relayKeydown ( e ) , { ignoreRepeat : false } )
155+ . on ( 'Home' , e => this . _relayKeydown ( e ) )
156+ . on ( 'End' , e => this . _relayKeydown ( e ) )
157+ . on ( 'PageUp' , e => this . _relayKeydown ( e ) )
158+ . on ( 'PageDown' , e => this . _relayKeydown ( e ) )
159159 . on ( 'Escape' , ( ) => {
160160 if ( ! this . inputs . alwaysExpanded ( ) ) {
161161 this . inputs . expanded . set ( false ) ;
162+ this . keyboardEventRelay . set ( [ ] ) ;
162163 }
163164 } ) ;
164165
165166 if ( ! this . readonly ( ) ) {
166- manager . on ( 'Enter' , e => this . keyboardEventRelay . set ( e ) ) ;
167+ manager . on ( 'Enter' , e => this . _relayKeydown ( e ) ) ;
167168 }
168169
169170 if ( ! this . isEditable ( ) && ! this . readonly ( ) ) {
170171 manager
171- . on ( ' ' , e => this . keyboardEventRelay . set ( e ) )
172- . on ( [ Modifier . Ctrl , Modifier . Meta ] , 'a' , e => this . keyboardEventRelay . set ( e ) )
173- . on ( [ Modifier . Ctrl , Modifier . Meta ] , 'A' , e => this . keyboardEventRelay . set ( e ) )
174- . on ( Modifier . Shift , 'Home' , e => this . keyboardEventRelay . set ( e ) )
175- . on ( Modifier . Shift , 'End' , e => this . keyboardEventRelay . set ( e ) )
172+ . on ( [ Modifier . Ctrl , Modifier . Meta ] , 'A' , e => this . _relayKeydown ( e ) )
173+ . on ( Modifier . Shift , 'Home' , e => this . _relayKeydown ( e ) )
174+ . on ( Modifier . Shift , 'End' , e => this . _relayKeydown ( e ) )
176175 . on ( / ^ .$ / , e => {
177- this . keyboardEventRelay . set ( e ) ;
176+ this . _relayKeydown ( e ) ;
178177 } ) ;
179178 }
180179
@@ -196,6 +195,11 @@ export class ComboboxPattern {
196195 this . value = inputs . value ;
197196 }
198197
198+ /** Queues a keyboard event to be relayed to the popup. */
199+ private _relayKeydown ( event : KeyboardEvent ) {
200+ this . keyboardEventRelay . update ( events => [ ...events , event ] ) ;
201+ }
202+
199203 /** Handles keydown events for the combobox. */
200204 onKeydown ( event : KeyboardEvent ) {
201205 if ( ! this . inputs . disabled ( ) ) {
@@ -266,19 +270,24 @@ export class ComboboxPattern {
266270
267271 /** Relays keyboard events to the popup. */
268272 keyboardEventRelayEffect ( ) {
269- const event = this . keyboardEventRelay ( ) ;
270- if ( event === undefined ) return ;
273+ const events = this . keyboardEventRelay ( ) ;
274+ if ( events . length === 0 ) return ;
271275
272276 // Reset isDeleting when the user navigates, so that the highlight effect can run again.
273277 this . isDeleting . set ( false ) ;
274278
275- untracked ( ( ) => {
276- const popup = this . inputs . popup ( ) ;
277- if ( this . isExpanded ( ) ) {
278- const relayedEvent = new KeyboardEvent ( event . type , event ) ;
279- popup ?. controlTarget ( ) ?. dispatchEvent ( relayedEvent ) ;
280- }
281- } ) ;
279+ if ( ! untracked ( ( ) => this . isExpanded ( ) ) ) {
280+ this . keyboardEventRelay . set ( [ ] ) ;
281+ return ;
282+ }
283+
284+ const target = this . inputs . popup ( ) ?. controlTarget ( ) ;
285+ if ( ! target ) return ;
286+
287+ this . keyboardEventRelay . set ( [ ] ) ;
288+ for ( const event of events ) {
289+ target . dispatchEvent ( new KeyboardEvent ( event . type , event ) ) ;
290+ }
282291 }
283292}
284293
0 commit comments