@@ -387,6 +387,7 @@ class Render {
387387 const highlighted = this . content . list . querySelectorAll ( '.' + this . classes . highlighted ) ;
388388 highlighted . forEach ( el => el . classList . remove ( this . classes . highlighted ) ) ;
389389 this . content . search . input . removeAttribute ( 'aria-activedescendant' ) ;
390+ this . main . main . removeAttribute ( 'aria-activedescendant' ) ;
390391 }
391392 constructor ( settings , classes , store , callbacks ) {
392393 var _a ;
@@ -438,7 +439,7 @@ class Render {
438439 open ( ) {
439440 this . main . arrow . path . setAttribute ( 'd' , this . classes . arrowOpen ) ;
440441 this . main . main . classList . add ( this . settings . openPosition === 'up' ? this . classes . openAbove : this . classes . openBelow ) ;
441- this . content . search . input . setAttribute ( 'aria-expanded' , 'true' ) ;
442+ this . main . main . setAttribute ( 'aria-expanded' , 'true' ) ;
442443 this . moveContent ( ) ;
443444 const selectedOptions = this . store . getSelectedOptions ( ) ;
444445 if ( selectedOptions . length ) {
@@ -459,7 +460,8 @@ class Render {
459460 }
460461 close ( ) {
461462 this . main . main . classList . remove ( this . classes . openAbove , this . classes . openBelow ) ;
462- this . content . search . input . setAttribute ( 'aria-expanded' , 'false' ) ;
463+ this . content . search . input . removeAttribute ( 'aria-expanded' ) ;
464+ this . main . main . setAttribute ( 'aria-expanded' , 'false' ) ;
463465 this . content . main . classList . remove ( this . classes . openAbove , this . classes . openBelow ) ;
464466 this . main . arrow . path . setAttribute ( 'd' , this . classes . arrowClose ) ;
465467 if ( this . scrollHandler ) {
@@ -503,18 +505,21 @@ class Render {
503505 this . content . list . setAttribute ( 'role' , 'listbox' ) ;
504506 this . content . list . setAttribute ( 'id' , this . content . main . id + '-list' ) ;
505507 this . content . list . setAttribute ( 'aria-label' , this . settings . contentAriaLabel ) ;
508+ this . main . main . setAttribute ( 'role' , 'combobox' ) ;
509+ this . main . main . setAttribute ( 'aria-controls' , this . content . list . id ) ;
510+ this . main . main . setAttribute ( 'aria-haspopup' , 'listbox' ) ;
511+ this . main . main . setAttribute ( 'aria-expanded' , 'false' ) ;
506512 if ( this . settings . isMultiple ) {
507513 this . content . list . setAttribute ( 'aria-multiselectable' , 'true' ) ;
508514 }
509515 this . main . main . removeAttribute ( 'aria-labelledby' ) ;
510516 this . main . main . removeAttribute ( 'aria-label' ) ;
511517 const input = this . content . search . input ;
512- input . setAttribute ( 'role' , 'combobox' ) ;
513- input . setAttribute ( 'aria-haspopup' , 'listbox' ) ;
518+ input . setAttribute ( 'role' , 'searchbox' ) ;
514519 input . setAttribute ( 'aria-controls' , this . content . list . id ) ;
515520 input . setAttribute ( 'aria-owns' , this . content . list . id ) ;
516- input . setAttribute ( 'aria-expanded' , 'false' ) ;
517521 input . setAttribute ( 'aria-autocomplete' , 'list' ) ;
522+ input . removeAttribute ( 'aria-expanded' ) ;
518523 let labelledById = ( this . settings . ariaLabelledBy || '' ) . trim ( ) ;
519524 let labelEl = null ;
520525 if ( ! labelledById ) {
@@ -566,28 +571,49 @@ class Render {
566571 main . onkeydown = ( e ) => {
567572 if ( e . target !== main )
568573 return true ;
574+ const focusAndThen = ( fn ) => {
575+ this . callbacks . open ( ) ;
576+ requestAnimationFrame ( ( ) => {
577+ this . searchFocus ( ) ;
578+ fn ( ) ;
579+ } ) ;
580+ } ;
569581 switch ( e . key ) {
570- case 'ArrowUp' :
571582 case 'ArrowDown' :
572- this . callbacks . open ( ) ;
573- e . key === 'ArrowDown' ? this . highlight ( 'down' ) : this . highlight ( 'up' ) ;
583+ e . preventDefault ( ) ;
584+ focusAndThen ( ( ) => this . highlight ( 'down' ) ) ;
585+ return false ;
586+ case 'ArrowUp' :
587+ e . preventDefault ( ) ;
588+ focusAndThen ( ( ) => this . highlight ( 'up' ) ) ;
574589 return false ;
575590 case 'Tab' :
576591 this . callbacks . close ( ) ;
577592 return true ;
578593 case 'Enter' :
579594 case ' ' :
580- this . callbacks . open ( ) ;
581- const highlighted = this . content . list . querySelector ( '.' + this . classes . highlighted ) ;
582- if ( highlighted )
583- highlighted . click ( ) ;
584- return false ;
585- case 'Escape' :
586- this . callbacks . close ( ) ;
595+ e . preventDefault ( ) ;
596+ focusAndThen ( ( ) => {
597+ const highlighted = this . content . list . querySelector ( '.' + this . classes . highlighted ) ;
598+ if ( highlighted )
599+ highlighted . click ( ) ;
600+ } ) ;
587601 return false ;
588602 }
589- if ( e . key . length === 1 ) {
603+ if ( e . key . length === 1 && ! e . ctrlKey && ! e . metaKey && ! e . altKey ) {
604+ e . preventDefault ( ) ;
590605 this . callbacks . open ( ) ;
606+ requestAnimationFrame ( ( ) => {
607+ var _a , _b ;
608+ this . searchFocus ( ) ;
609+ const inp = this . content . search . input ;
610+ const selStart = ( _a = inp . selectionStart ) !== null && _a !== void 0 ? _a : inp . value . length ;
611+ const selEnd = ( _b = inp . selectionEnd ) !== null && _b !== void 0 ? _b : inp . value . length ;
612+ inp . value = inp . value . slice ( 0 , selStart ) + e . key + inp . value . slice ( selEnd ) ;
613+ inp . setSelectionRange ( selStart + 1 , selStart + 1 ) ;
614+ this . callbacks . search ( inp . value ) ;
615+ } ) ;
616+ return false ;
591617 }
592618 return true ;
593619 } ;
@@ -702,6 +728,7 @@ class Render {
702728 const placeholder = document . createElement ( 'div' ) ;
703729 placeholder . classList . add ( this . classes . placeholder ) ;
704730 placeholder . innerHTML = placeholderText ;
731+ placeholder . setAttribute ( 'aria-hidden' , 'true' ) ;
705732 return placeholder ;
706733 }
707734 renderValues ( ) {
@@ -717,6 +744,7 @@ class Render {
717744 return o . selected && ! o . placeholder ;
718745 } , false ) ;
719746 const selectedSingle = selected . length > 0 ? selected [ 0 ] : null ;
747+ this . main . values . removeAttribute ( 'role' ) ;
720748 if ( ! selectedSingle ) {
721749 this . main . values . innerHTML = this . placeholder ( ) . outerHTML ;
722750 }
@@ -744,10 +772,12 @@ class Render {
744772 return opt . selected && opt . display ;
745773 } , false ) ;
746774 if ( selectedOptions . length === 0 ) {
775+ this . main . values . removeAttribute ( 'role' ) ;
747776 this . main . values . innerHTML = this . placeholder ( ) . outerHTML ;
748777 return ;
749778 }
750779 else {
780+ this . main . values . setAttribute ( 'role' , 'list' ) ;
751781 const placeholder = this . main . values . querySelector ( '.' + this . classes . placeholder ) ;
752782 if ( placeholder ) {
753783 placeholder . remove ( ) ;
@@ -1125,6 +1155,8 @@ class Render {
11251155 if ( options . length === 1 ) {
11261156 if ( ! options [ 0 ] . classList . contains ( this . classes . highlighted ) ) {
11271157 options [ 0 ] . classList . add ( this . classes . highlighted ) ;
1158+ const id = options [ 0 ] . id ;
1159+ this . setActiveDescendant ( id ) ;
11281160 return ;
11291161 }
11301162 }
@@ -1138,6 +1170,7 @@ class Render {
11381170 for ( const o of options ) {
11391171 if ( o . classList . contains ( this . classes . selected ) ) {
11401172 o . classList . add ( this . classes . highlighted ) ;
1173+ this . setActiveDescendant ( o . id ) ;
11411174 break ;
11421175 }
11431176 }
@@ -1146,16 +1179,9 @@ class Render {
11461179 if ( options [ i ] . classList . contains ( this . classes . highlighted ) ) {
11471180 const prevOption = options [ i ] ;
11481181 prevOption . classList . remove ( this . classes . highlighted ) ;
1149- const prevParent = prevOption . parentElement ;
1150- if ( prevParent && prevParent . classList . contains ( this . classes . open ) ) {
1151- const optgroupLabel = prevParent . querySelector ( '.' + this . classes . optgroupLabel ) ;
1152- if ( optgroupLabel ) {
1153- optgroupLabel . click ( ) ;
1154- }
1155- }
1156- let selectOption = options [ dir === 'down' ? ( i + 1 < options . length ? i + 1 : 0 ) : i - 1 >= 0 ? i - 1 : options . length - 1 ] ;
1182+ const selectOption = options [ dir === 'down' ? ( i + 1 < options . length ? i + 1 : 0 ) : i - 1 >= 0 ? i - 1 : options . length - 1 ] ;
11571183 selectOption . classList . add ( this . classes . highlighted ) ;
1158- this . content . search . input . setAttribute ( 'aria-activedescendant' , selectOption . id ) ;
1184+ this . setActiveDescendant ( selectOption . id ) ;
11591185 this . ensureElementInView ( this . content . list , selectOption ) ;
11601186 const selectParent = selectOption . parentElement ;
11611187 if ( selectParent && selectParent . classList . contains ( this . classes . close ) ) {
@@ -1169,7 +1195,7 @@ class Render {
11691195 }
11701196 const newly = options [ dir === 'down' ? 0 : options . length - 1 ] ;
11711197 newly . classList . add ( this . classes . highlighted ) ;
1172- this . content . search . input . setAttribute ( 'aria-activedescendant' , newly . id ) ;
1198+ this . setActiveDescendant ( newly . id ) ;
11731199 this . ensureElementInView ( this . content . list , newly ) ;
11741200 }
11751201 listDiv ( ) {
@@ -1410,7 +1436,7 @@ class Render {
14101436 if ( option . selected ) {
14111437 optionEl . classList . add ( this . classes . selected ) ;
14121438 optionEl . setAttribute ( 'aria-selected' , 'true' ) ;
1413- this . content . search . input . setAttribute ( 'aria-activedescendant' , optionEl . id ) ;
1439+ this . setActiveDescendant ( optionEl . id ) ;
14141440 }
14151441 else {
14161442 optionEl . classList . remove ( this . classes . selected ) ;
@@ -1441,8 +1467,8 @@ class Render {
14411467 if ( ! this . settings . closeOnSelect ) {
14421468 if ( e . shiftKey && this . lastSelectedOption ) {
14431469 const options = this . store . getDataOptions ( ) ;
1444- let lastClickedOptionIndex = options . findIndex ( ( o ) => o . id === this . lastSelectedOption . id ) ;
1445- let currentOptionIndex = options . findIndex ( ( o ) => o . id === option . id ) ;
1470+ const lastClickedOptionIndex = options . findIndex ( ( o ) => o . id === this . lastSelectedOption . id ) ;
1471+ const currentOptionIndex = options . findIndex ( ( o ) => o . id === option . id ) ;
14461472 if ( lastClickedOptionIndex >= 0 && currentOptionIndex >= 0 ) {
14471473 const startIndex = Math . min ( lastClickedOptionIndex , currentOptionIndex ) ;
14481474 const endIndex = Math . max ( lastClickedOptionIndex , currentOptionIndex ) ;
@@ -1585,6 +1611,15 @@ class Render {
15851611 deselectButton . classList . add ( hideClass ) ;
15861612 }
15871613 }
1614+ setActiveDescendant ( id ) {
1615+ if ( ! id ) {
1616+ this . main . main . removeAttribute ( 'aria-activedescendant' ) ;
1617+ this . content . search . input . removeAttribute ( 'aria-activedescendant' ) ;
1618+ return ;
1619+ }
1620+ this . main . main . setAttribute ( 'aria-activedescendant' , id ) ;
1621+ this . content . search . input . setAttribute ( 'aria-activedescendant' , id ) ;
1622+ }
15881623}
15891624Render . _livePolite = null ;
15901625Render . _liveAssertive = null ;
0 commit comments