11import Vue from '../../utils/vue'
22import KeyCodes from '../../utils/key-codes'
3- import { attemptFocus , isVisible , selectAll } from '../../utils/dom'
3+ import { attemptFocus , contains , isVisible , selectAll } from '../../utils/dom'
44import normalizeSlotMixin from '../../mixins/normalize-slot'
55
6+ // --- Constants ---
7+
68const ITEM_SELECTOR = [
79 '.btn:not(.disabled):not([disabled]):not(.dropdown-item)' ,
810 '.form-control:not(.disabled):not([disabled])' ,
@@ -11,6 +13,15 @@ const ITEM_SELECTOR = [
1113 'input[type="radio"]:not(.disabled)'
1214] . join ( ',' )
1315
16+ // --- Utility methods ---
17+
18+ const stopEvent = evt => {
19+ evt . preventDefault ( )
20+ evt . stopPropagation ( )
21+ }
22+
23+ // --- Main component ---
24+
1425// @vue /component
1526export const BButtonToolbar = /*#__PURE__*/ Vue . extend ( {
1627 name : 'BButtonToolbar' ,
@@ -26,37 +37,20 @@ export const BButtonToolbar = /*#__PURE__*/ Vue.extend({
2637 }
2738 } ,
2839 mounted ( ) {
40+ // Pre-set the tabindexes if the markup does not include
41+ // `tabindex="-1"` on the toolbar items
2942 if ( this . keyNav ) {
30- // Pre-set the tabindexes if the markup does not include tabindex="-1" on the toolbar items
3143 this . getItems ( )
3244 }
3345 } ,
3446 methods : {
35- onFocusin ( evt ) {
36- if ( evt . target === this . $el ) {
37- evt . preventDefault ( )
38- evt . stopPropagation ( )
39- this . focusFirst ( evt )
40- }
41- } ,
42- stop ( evt ) {
43- evt . preventDefault ( )
44- evt . stopPropagation ( )
45- } ,
46- onKeydown ( evt ) {
47- if ( ! this . keyNav ) {
48- /* istanbul ignore next: should never happen */
49- return
50- }
51- const key = evt . keyCode
52- const shift = evt . shiftKey
53- if ( key === KeyCodes . UP || key === KeyCodes . LEFT ) {
54- this . stop ( evt )
55- shift ? this . focusFirst ( evt ) : this . focusPrev ( evt )
56- } else if ( key === KeyCodes . DOWN || key === KeyCodes . RIGHT ) {
57- this . stop ( evt )
58- shift ? this . focusLast ( evt ) : this . focusNext ( evt )
59- }
47+ getItems ( ) {
48+ const items = selectAll ( ITEM_SELECTOR , this . $el )
49+ // Ensure `tabindex="-1"` is set on every item
50+ items . forEach ( item => {
51+ item . tabIndex = - 1
52+ } )
53+ return items . filter ( el => isVisible ( el ) )
6054 } ,
6155 focusFirst ( ) {
6256 const items = this . getItems ( )
@@ -82,13 +76,22 @@ export const BButtonToolbar = /*#__PURE__*/ Vue.extend({
8276 const items = this . getItems ( ) . reverse ( )
8377 attemptFocus ( items [ 0 ] )
8478 } ,
85- getItems ( ) {
86- const items = selectAll ( ITEM_SELECTOR , this . $el )
87- items . forEach ( item => {
88- // Ensure tabfocus is -1 on any new elements
89- item . tabIndex = - 1
90- } )
91- return items . filter ( el => isVisible ( el ) )
79+ onFocusin ( evt ) {
80+ const { $el } = this
81+ if ( evt . target === $el && ! contains ( $el , evt . relatedTarget ) ) {
82+ stopEvent ( evt )
83+ this . focusFirst ( evt )
84+ }
85+ } ,
86+ onKeydown ( evt ) {
87+ const { keyCode, shiftKey } = evt
88+ if ( keyCode === KeyCodes . UP || keyCode === KeyCodes . LEFT ) {
89+ stopEvent ( evt )
90+ shiftKey ? this . focusFirst ( evt ) : this . focusPrev ( evt )
91+ } else if ( keyCode === KeyCodes . DOWN || keyCode === KeyCodes . RIGHT ) {
92+ stopEvent ( evt )
93+ shiftKey ? this . focusLast ( evt ) : this . focusNext ( evt )
94+ }
9295 }
9396 } ,
9497 render ( h ) {
0 commit comments