UNPKG

2.83 kBJavaScriptView Raw
1import BaseComponent from 'bootstrap/js/src/base-component.js'
2
3import EventHandler from 'bootstrap/js/src/dom/event-handler'
4import SelectorEngine from 'bootstrap/js/src/dom/selector-engine'
5
6import { focusSimbling } from './util/dom'
7
8const NAME = 'accordion'
9const DATA_KEY = 'bs.accordion'
10const EVENT_KEY = `.${DATA_KEY}`
11const DATA_API_KEY = '.data-api'
12
13const EVENT_KEYDOWN = `keydown${EVENT_KEY}`
14const EVENT_KEYDOWN_DATA_API = `keydown${EVENT_KEY}${DATA_API_KEY}`
15
16const SELECTOR_HEADBTN_WRAPPER = '.accordion'
17const SELECTOR_HEADBTN = '.accordion-item > .accordion-header [data-bs-toggle="collapse"]'
18
19class Accordion extends BaseComponent {
20 constructor(element) {
21 super(element)
22
23 this._bindEvents()
24 }
25
26 // Getters
27
28 static get NAME() {
29 return NAME
30 }
31
32 // Public
33 handleKeyDown(keyName, target, evt) {
34 const eventKeyCallback = {
35 ArrowDown: (target) => this._focusNext(target),
36 ArrowUp: (target) => this._focusPrev(target),
37 Home: (target) => this._focusFirst(target),
38 End: (target) => this._focusLast(target),
39 }
40 if (typeof eventKeyCallback[keyName] === 'function') {
41 if (evt) {
42 evt.preventDefault()
43 }
44 eventKeyCallback[keyName](target)
45 }
46 }
47
48 // Private
49 _bindEvents() {
50 //fix collapse accessibility (arrow keys, home key, end key functionality)
51
52 SelectorEngine.find(SELECTOR_HEADBTN, this._element).forEach((accHead) => {
53 EventHandler.on(accHead, EVENT_KEYDOWN, (evt) => {
54 this.handleKeyDown(evt.key, evt.currentTarget, evt)
55 })
56 })
57 }
58
59 _getHeadButtons() {
60 return SelectorEngine.find(':scope > ' + SELECTOR_HEADBTN, this._element)
61 }
62
63 _focusNext(target) {
64 focusSimbling(target, this._getHeadButtons(), { loop: true })
65 }
66
67 _focusPrev(target) {
68 focusSimbling(target, this._getHeadButtons(), { isDirectionTop: true, loop: true })
69 }
70
71 _focusFirst(target) {
72 focusSimbling(target, this._getHeadButtons(), { isDirectionTop: true, isLimit: true })
73 }
74
75 _focusLast(target) {
76 focusSimbling(target, this._getHeadButtons(), { isLimit: true })
77 }
78}
79
80/**
81 * ------------------------------------------------------------------------
82 * Data Api implementation
83 * ------------------------------------------------------------------------
84 */
85/*const accordions = SelectorEngine.find(SELECTOR_HEADBTN_WRAPPER)
86accordions.forEach((acc) => {
87 Accordion.getOrCreateInstance(acc)
88})*/
89
90const accordionToggles = SelectorEngine.find(SELECTOR_HEADBTN)
91accordionToggles.forEach((toggle) => {
92 EventHandler.one(toggle, EVENT_KEYDOWN_DATA_API, (evt) => {
93 const parent = toggle.closest(SELECTOR_HEADBTN_WRAPPER)
94 if (parent) {
95 const accordion = Accordion.getOrCreateInstance(parent)
96 accordion.handleKeyDown(evt.key, toggle, evt)
97 }
98 })
99})
100
101export default Accordion