@@ -92,18 +92,92 @@ const dropdownOptions = (item) => {
9292const handleClickOutside = (e ) => {
9393 closeDropdowns ();
9494};
95+
96+
97+ const moveToNextButton = (e ) => {
98+ const currentButton = e .target ;
99+ const nextButton = e .target .closest (' .toolbar-item-ctn' ).nextElementSibling ;
100+ if (nextButton) {
101+ currentButton .setAttribute (' tabindex' , ' -1' );
102+ nextButton .setAttribute (' tabindex' , ' 0' );
103+ nextButton .focus ();
104+ }
105+ };
106+
107+ const moveToPreviousButton = (e ) => {
108+ const currentButton = e .target ;
109+ const previousButton = e .target .closest (' .toolbar-item-ctn' ).previousElementSibling ;
110+ if (previousButton) {
111+ currentButton .setAttribute (' tabindex' , ' -1' );
112+ previousButton .setAttribute (' tabindex' , ' 0' );
113+ previousButton .focus ();
114+ }
115+ };
116+
117+ const moveToNextButtonGroup = (e ) => {
118+ const nextButtonGroup = e .target .closest (' .button-group' ).nextElementSibling ;
119+ if (nextButtonGroup) {
120+ nextButtonGroup .setAttribute (' tabindex' , ' 0' );
121+ nextButtonGroup .focus ();
122+ }
123+ };
124+
125+ const moveToPreviousButtonGroup = (e ) => {
126+ const previousButtonGroup = e .target .closest (' .button-group' ).previousElementSibling ;
127+ if (previousButtonGroup) {
128+ previousButtonGroup .setAttribute (' tabindex' , ' 0' );
129+ previousButtonGroup .focus ();
130+ }
131+ };
132+
133+ // Implement keyboard navigation using Roving Tabindex
134+ // https://www.w3.org/WAI/ARIA/apg/practices/keyboard-interface/#kbd_roving_tabindex
135+ // Set tabindex to 0 for the current focused button
136+ // Set tabindex to -1 for all other buttons
137+ const handleKeyDown = (e ) => {
138+ e .preventDefault ();
139+ e .stopPropagation ();
140+
141+ switch (e .key ) {
142+ case ' ArrowRight' :
143+ moveToNextButton (e);
144+ break ;
145+ case ' ArrowLeft' :
146+ moveToPreviousButton (e);
147+ break ;
148+ case ' Tab' :
149+ if (e .shiftKey ) {
150+ moveToPreviousButtonGroup (e);
151+ } else {
152+ moveToNextButtonGroup (e);
153+ }
154+ break ;
155+ default :
156+ break ;
157+ }
158+ };
159+ const handleFocus = (e ) => {
160+ // Set the focus to the first button inside the button group that is not disabled
161+ const firstButton = e .target .closest (' .button-group' ).querySelector (' .toolbar-item-ctn:not(.disabled)' );
162+ if (firstButton) {
163+ // Force focus on the first button
164+ firstButton .focus ();
165+ }
166+ };
95167< / script>
96168
97169< template>
98- < div : style= " getPositionStyle" class = " button-group" >
170+ < div : style= " getPositionStyle" class = " button-group" @keydown = " handleKeyDown " @focus = " handleFocus " >
99171 < div
100- v- for = " item in toolbarItems"
172+ v- for = " ( item, index) in toolbarItems"
101173 : key= " item.id.value"
102174 : class = " {
103175 narrow: item.isNarrow.value,
104176 wide: item.isWide.value,
177+ disabled: item.disabled.value,
105178 }"
106179 class = " toolbar-item-ctn"
180+ : tabindex= " index === 0 ? 0 : -1"
107181 >
108182 <!-- toolbar separator -->
109183 < ToolbarSeparator v- if = " isSeparator(item)" style= " width: 20px" / >
@@ -125,6 +199,7 @@ const handleClickOutside = (e) => {
125199 < template #trigger>
126200 < ToolbarButton
127201 : toolbar- item= " item"
202+ : disabled= " item.disabled.value"
128203 @textSubmit= " handleToolbarButtonTextSubmit(item, $event)"
129204 @buttonClick= " handleToolbarButtonClick(item)"
130205 / >
0 commit comments