@@ -65,28 +65,9 @@ export class ToolbarPattern<V> {
6565 keydown = computed ( ( ) => {
6666 const manager = new KeyboardEventManager ( ) ;
6767
68- /** When a toolbar widget is active and disabled, prevent selection */
69- if (
70- this . focusManager . activeItem ( ) . disabled ( ) &&
71- this . focusManager . activeItem ( ) instanceof ToolbarWidgetPattern
72- ) {
73- return manager
74- . on ( ' ' , ( ) => { } )
75- . on ( 'Enter' , ( ) => { } )
76- . on ( this . prevKey , ( ) => this . navigation . prev ( ) )
77- . on ( this . nextKey , ( ) => this . navigation . next ( ) )
78- . on ( 'Home' , ( ) => this . navigation . first ( ) )
79- . on ( 'End' , ( ) => this . navigation . last ( ) ) ;
80- }
81-
82- /** When in Active Descendant mode, Toolbar controls which group receives selection */
83- if ( this . inputs . focusMode ( ) === 'activedescendant' ) {
84- manager
85- . on ( ' ' , ( ) => this . toolbarSelectOverride ( ) )
86- . on ( 'Enter' , ( ) => this . toolbarSelectOverride ( ) ) ;
87- }
88-
8968 return manager
69+ . on ( ' ' , ( ) => this . toolbarSelectOverride ( ) )
70+ . on ( 'Enter' , ( ) => this . toolbarSelectOverride ( ) )
9071 . on ( this . prevKey , ( ) => this . navigation . prev ( ) )
9172 . on ( this . nextKey , ( ) => this . navigation . next ( ) )
9273 . on ( 'Home' , ( ) => this . navigation . first ( ) )
@@ -98,12 +79,13 @@ export class ToolbarPattern<V> {
9879
9980 /** If the active item is a Radio Button, indicate to the group the selection */
10081 if ( activeItem instanceof RadioButtonPattern ) {
101- if ( activeItem . group ( ) ) {
102- activeItem . group ( ) ! ! . selection . selectOne ( ) ;
82+ const group = activeItem . group ( ) ;
83+ if ( group && ! group . readonly ( ) ) {
84+ group . selection . selectOne ( ) ;
10385 }
10486 } else {
10587 /** Item is a Toolbar Widget, manually select it */
106- activeItem . element ( ) . click ( ) ;
88+ if ( activeItem . element ( ) ) activeItem . element ( ) . click ( ) ;
10789 }
10890 }
10991
@@ -115,7 +97,7 @@ export class ToolbarPattern<V> {
11597 return manager . on ( e => this . goto ( e ) ) ;
11698 } ) ;
11799
118- /** Navigates to the radio button associated with the given pointer event. */
100+ /** Navigates to the widget associated with the given pointer event. */
119101 goto ( event : PointerEvent ) {
120102 const item = this . _getItem ( event ) ;
121103
@@ -142,7 +124,7 @@ export class ToolbarPattern<V> {
142124 return undefined ;
143125 }
144126
145- // Assumes the target or its ancestor has role="radio" or button
127+ // Assumes the target or its ancestor has role="radio" or role=" button"
146128 const element = e . target . closest ( '[role="button"], [role="radio"]' ) ;
147129 return this . inputs . items ( ) . find ( i => i . element ( ) === element ) ;
148130 }
@@ -182,6 +164,21 @@ export class ToolbarPattern<V> {
182164 this . inputs . activeIndex . set ( firstItem . index ( ) ) ;
183165 }
184166 }
167+ /** Validates the state of the toolbar and returns a list of accessibility violations. */
168+ validate ( ) : string [ ] {
169+ const violations : string [ ] = [ ] ;
170+
171+ if ( this . inputs . skipDisabled ( ) ) {
172+ for ( const item of this . inputs . items ( ) ) {
173+ if ( item instanceof RadioButtonPattern && item . selected ( ) && item . disabled ( ) ) {
174+ violations . push (
175+ "Accessibility Violation: A selected radio button inside the toolbar is disabled while 'skipDisabled' is true, making the selection unreachable via keyboard." ,
176+ ) ;
177+ }
178+ }
179+ }
180+ return violations ;
181+ }
185182}
186183
187184export type ToolbarWidget = {
@@ -190,14 +187,14 @@ export type ToolbarWidget = {
190187 disabled : SignalLike < boolean > ;
191188} ;
192189
193- /** Represents the required inputs for a radio button in a radio group . */
190+ /** Represents the required inputs for a toolbar widget in a toolbar . */
194191export interface ToolbarWidgetInputs extends ListNavigationItem , ListFocusItem {
195- /** A reference to the parent radio group . */
196- parentToolbar : SignalLike < ToolbarPattern < null > | undefined > ;
192+ /** A reference to the parent toolbar . */
193+ parentToolbar : SignalLike < ToolbarPattern < null > > ;
197194}
198195
199196export class ToolbarWidgetPattern {
200- /** A unique identifier for the radio button . */
197+ /** A unique identifier for the widget . */
201198 id : SignalLike < string > ;
202199 /** The html element that should receive focus. */ // might not be needed
203200 readonly element : SignalLike < HTMLElement > ;
@@ -207,9 +204,8 @@ export class ToolbarWidgetPattern {
207204 /** A reference to the parent toolbar. */
208205 parentToolbar : SignalLike < ToolbarPattern < null > | undefined > ;
209206
210- // expose tab index have tabindex -1 if roving manage 1/0
211- /** The tabindex of the radio button. */
212- tabindex = computed ( ( ) => this . parentToolbar ( ) ?. focusManager . getItemTabindex ( this ) ) ;
207+ /** The tabindex of the widgdet. */
208+ tabindex = computed ( ( ) => this . inputs . parentToolbar ( ) . focusManager . getItemTabindex ( this ) ) ;
213209
214210 /** The position of the widget within the group. */
215211 index = computed (
@@ -219,8 +215,8 @@ export class ToolbarWidgetPattern {
219215 . findIndex ( i => i . id ( ) === this . id ( ) ) ?? - 1 ,
220216 ) ;
221217
222- /** Whether the radio button is currently the active one (focused). */
223- active = computed ( ( ) => this . parentToolbar ( ) ? .focusManager . activeItem ( ) === this ) ;
218+ /** Whether the widhet is currently the active one (focused). */
219+ active = computed ( ( ) => this . inputs . parentToolbar ( ) . focusManager . activeItem ( ) === this ) ;
224220
225221 constructor ( readonly inputs : ToolbarWidgetInputs ) {
226222 this . id = inputs . id ;
0 commit comments