@@ -6,6 +6,12 @@ const isFocusableElement = (el: Element): el is HTMLElement =>
66 ! el . ariaHidden &&
77 ! el . hasAttribute ( 'hidden' ) ;
88
9+ export interface RovingTabindexControllerOptions < Item extends HTMLElement > {
10+ getElement ?: ( ) => Element ;
11+ getItems ?: ( ) => Item [ ] ;
12+ getItemContainer ?: ( ) => HTMLElement ;
13+ }
14+
915/**
1016 * Implements roving tabindex, as described in WAI-ARIA practices, [Managing Focus Within
1117 * Components Using a Roving
@@ -30,8 +36,6 @@ export class RovingTabindexController<
3036 /** array of all focusable elements */
3137 #items: Item [ ] = [ ] ;
3238
33- #getElement: ( ) => Element | null ;
34-
3539 /**
3640 * finds focusable items from a group of items
3741 */
@@ -121,16 +125,30 @@ export class RovingTabindexController<
121125 return this . #caseSensitive;
122126 }
123127
124- constructor ( public host : ReactiveControllerHost , options ?: {
125- getElement : ( ) => Element ;
126- } ) {
127- this . #getElement = options ?. getElement ?? ( ( ) => host instanceof Element ? host : null ) ;
128+ #options: {
129+ getElement ( ) : Element | null ;
130+ getItems ?( ) : Item [ ] ;
131+ getItemContainer ?( ) : HTMLElement ;
132+ } ;
133+
134+ constructor (
135+ public host : ReactiveControllerHost ,
136+ options ?: RovingTabindexControllerOptions < Item > ,
137+ ) {
138+ this . #options = {
139+ getElement : options ?. getElement ?? ( ( ) => host instanceof HTMLElement ? host : null ) ,
140+ getItems : options ?. getItems ,
141+ getItemContainer : options ?. getItemContainer ,
142+ } ;
128143 const instance = RovingTabindexController . hosts . get ( host ) ;
129144 if ( instance ) {
130145 return instance as RovingTabindexController < Item > ;
131146 }
132147 RovingTabindexController . hosts . set ( host , this ) ;
133148 this . host . addController ( this ) ;
149+ if ( typeof this . #options?. getItems === 'function' ) {
150+ this . initItems ( this . #options. getItems ( ) , this . #options. getItemContainer ?.( ) ) ;
151+ }
134152 }
135153
136154 #nextMatchingItem( key : string ) {
@@ -157,7 +175,7 @@ export class RovingTabindexController<
157175 return ;
158176 }
159177
160- const orientation = this . #getElement( ) ?. getAttribute ( 'aria-orientation' ) ;
178+ const orientation = this . #options . getElement ( ) ?. getAttribute ( 'aria-orientation' ) ;
161179
162180 const item = this . activeItem ;
163181 let shouldPreventDefault = false ;
@@ -252,8 +270,8 @@ export class RovingTabindexController<
252270 /**
253271 * Focuses next focusable item
254272 */
255- updateItems ( items : Item [ ] ) {
256- const hasActive = document . activeElement && this . #getElement( ) ?. contains ( document . activeElement ) ;
273+ updateItems ( items : Item [ ] = this . #options . getItems ?. ( ) ?? [ ] ) {
274+ const hasActive = document . activeElement && this . #options . getElement ( ) ?. contains ( document . activeElement ) ;
257275 const sequence = [ ...items . slice ( this . #itemIndex - 1 ) , ...items . slice ( 0 , this . #itemIndex - 1 ) ] ;
258276 const first = sequence . find ( item => this . #focusableItems. includes ( item ) ) ;
259277 this . #items = items ?? [ ] ;
@@ -268,6 +286,7 @@ export class RovingTabindexController<
268286
269287 /**
270288 * from array of HTML items, and sets active items
289+ * @deprecated : use getItems and getItemContainer option functions
271290 */
272291 initItems ( items : Item [ ] , itemsContainer ?: Element ) {
273292 this . #items = items ?? [ ] ;
@@ -276,12 +295,12 @@ export class RovingTabindexController<
276295 this . #activeItem = focusableItem ;
277296 this . #updateTabindex( ) ;
278297
279- itemsContainer ??= this . #getElement( ) ?? undefined ;
298+ itemsContainer ??= this . #options . getElement ( ) ?? undefined ;
280299
281300 /**
282301 * removes listener on previous contained and applies it to new container
283302 */
284- if ( ! this . #itemsContainer || itemsContainer !== this . #itemsContainer) {
303+ if ( itemsContainer !== this . #itemsContainer) {
285304 this . #itemsContainer?. removeEventListener ( 'keydown' , this . #onKeydown) ;
286305 this . #itemsContainer = itemsContainer ;
287306 this . hostConnected ( ) ;
0 commit comments