1- import { attr , FASTElement , Observable , observable , Updates } from '@microsoft/fast-element' ;
1+ import { attr , FASTElement , Observable , observable } from '@microsoft/fast-element' ;
22import { findLastIndex } from '@microsoft/fast-web-utilities' ;
33import { Radio } from '../radio/radio.js' ;
44import { isRadio } from '../radio/radio.options.js' ;
5- import { getDirection } from '../utils/direction.js' ;
6- import { getRootActiveElement } from '../utils/root-active-element.js' ;
75import { RadioGroupOrientation } from './radio-group.options.js' ;
86
97/**
@@ -64,7 +62,6 @@ export class BaseRadioGroup extends FASTElement {
6462 this . radios ?. forEach ( radio => {
6563 radio . disabled = ! ! radio . disabledAttribute || ! ! this . disabled ;
6664 } ) ;
67- this . restrictFocus ( ) ;
6865 }
6966 }
7067
@@ -170,6 +167,13 @@ export class BaseRadioGroup extends FASTElement {
170167
171168 radio . name = this . name ?? radio . name ;
172169 radio . disabled = ! ! this . disabled || ! ! radio . disabledAttribute ;
170+
171+ if ( radio . checked && ! radio . disabled ) {
172+ // Update.enqueu() would be too soon for this operation.
173+ requestAnimationFrame ( ( ) => {
174+ radio . toggleAttribute ( 'focusgroupstart' , true ) ;
175+ } ) ;
176+ }
173177 } ) ;
174178
175179 if ( ! this . dirtyState && this . initialValue ) {
@@ -196,10 +200,6 @@ export class BaseRadioGroup extends FASTElement {
196200 if ( radioIds ) {
197201 this . setAttribute ( 'aria-owns' , radioIds ) ;
198202 }
199-
200- Updates . enqueue ( ( ) => {
201- this . restrictFocus ( ) ;
202- } ) ;
203203 }
204204
205205 /**
@@ -422,6 +422,13 @@ export class BaseRadioGroup extends FASTElement {
422422 this . enabledRadios [ Math . max ( 0 , this . checkedIndex ) ] ?. focus ( ) ;
423423 }
424424
425+ formResetCallback ( ) : void {
426+ this . dirtyState = false ;
427+ this . checkedIndex = - 1 ;
428+ this . setFormValue ( this . value ) ;
429+ this . setValidity ( ) ;
430+ }
431+
425432 /**
426433 * Enables tabbing through the radio group when the group receives focus.
427434 *
@@ -430,93 +437,35 @@ export class BaseRadioGroup extends FASTElement {
430437 */
431438 public focusinHandler ( e : FocusEvent ) : boolean | void {
432439 if ( ! this . disabled ) {
433- this . enabledRadios . forEach ( radio => {
434- radio . tabIndex = 0 ;
440+ // Uncheck the checked disabled radio, if any.
441+ this . radios ?. forEach ( radio => {
442+ if ( radio . disabled && radio . checked ) {
443+ radio . checked = false ;
444+ }
435445 } ) ;
436- }
437-
438- return true ;
439- }
440446
441- /**
442- * Sets the tabindex of the radios based on the checked state when the radio group loses focus.
443- *
444- * @param e - the focusout event
445- * @internal
446- */
447- public focusoutHandler ( e : FocusEvent ) : boolean | void {
448- if ( this . radios ?. includes ( e . relatedTarget as Radio ) && this . radios ?. some ( x => x . checked ) ) {
449- this . restrictFocus ( ) ;
447+ const index = this . enabledRadios . indexOf ( e . target as Radio ) ;
448+ if ( index > - 1 ) {
449+ this . checkRadio ( index , true ) ;
450+ }
450451 }
451452
452453 return true ;
453454 }
454455
455- formResetCallback ( ) : void {
456- this . dirtyState = false ;
457- this . checkedIndex = - 1 ;
458- this . setFormValue ( this . value ) ;
459- this . setValidity ( ) ;
460- }
461-
462- private getEnabledIndexInBounds ( index : number , upperBound = this . enabledRadios . length ) : number {
463- if ( upperBound === 0 ) {
464- return - 1 ;
465- }
466-
467- return ( index + upperBound ) % upperBound ;
468- }
469-
470456 /**
471457 * Handles keydown events for the radio group.
472458 *
473459 * @param e - the keyboard event
474460 * @internal
475461 */
476462 public keydownHandler ( e : KeyboardEvent ) : boolean | void {
477- const isRtl = getDirection ( this ) === 'rtl' ;
478- const checkedIndex = this . enabledRadios . findIndex ( x => x === getRootActiveElement ( this ) ) ?? this . checkedIndex ;
479- let increment = 0 ;
480-
481463 switch ( e . key ) {
482- case 'ArrowLeft' : {
483- increment = isRtl ? 1 : - 1 ;
484- break ;
485- }
486-
487- case 'ArrowUp' : {
488- increment = - 1 ;
489- break ;
490- }
491-
492- case 'ArrowRight' : {
493- increment = isRtl ? - 1 : 1 ;
494- break ;
495- }
496-
497- case 'ArrowDown' : {
498- increment = 1 ;
499- break ;
500- }
501-
502- case 'Tab' : {
503- this . restrictFocus ( ) ;
504- break ;
505- }
506-
507- case ' ' : {
464+ case ' ' :
508465 this . checkRadio ( ) ;
509466 break ;
510- }
511467 }
512-
513- if ( ! increment ) {
514- return true ;
515- }
516-
517- const nextIndex = checkedIndex + increment ;
518- this . checkRadio ( this . getEnabledIndexInBounds ( nextIndex ) , true ) ;
519- this . enabledRadios [ this . checkedIndex ] ?. focus ( ) ;
468+ return true ;
520469 }
521470
522471 /**
@@ -540,26 +489,6 @@ export class BaseRadioGroup extends FASTElement {
540489 return this . elementInternals . reportValidity ( ) ;
541490 }
542491
543- /**
544- * Resets the `tabIndex` for all child radios when the radio group loses focus.
545- *
546- * @internal
547- */
548- private restrictFocus ( ) {
549- let activeIndex = Math . max ( this . checkedIndex , 0 ) ;
550- const focusedRadioIndex = this . enabledRadios . indexOf ( getRootActiveElement ( this ) as Radio ) ;
551-
552- if ( focusedRadioIndex !== - 1 ) {
553- activeIndex = focusedRadioIndex ;
554- }
555-
556- activeIndex = this . getEnabledIndexInBounds ( activeIndex ) ;
557-
558- this . enabledRadios . forEach ( ( item , index ) => {
559- item . tabIndex = index === activeIndex ? 0 : - 1 ;
560- } ) ;
561- }
562-
563492 /**
564493 * Reflects the {@link https://developer.mozilla.org/docs/Web/API/ElementInternals/setFormValue | `ElementInternals.setFormValue()`} method.
565494 *
0 commit comments