bootstrap 5.1.3 → 5.2.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (95) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +24 -4
  3. data/assets/javascripts/bootstrap/alert.js +11 -146
  4. data/assets/javascripts/bootstrap/base-component.js +37 -120
  5. data/assets/javascripts/bootstrap/button.js +10 -74
  6. data/assets/javascripts/bootstrap/carousel.js +213 -485
  7. data/assets/javascripts/bootstrap/collapse.js +65 -249
  8. data/assets/javascripts/bootstrap/dom/data.js +3 -5
  9. data/assets/javascripts/bootstrap/dom/event-handler.js +94 -132
  10. data/assets/javascripts/bootstrap/dom/manipulator.js +23 -27
  11. data/assets/javascripts/bootstrap/dom/selector-engine.js +16 -58
  12. data/assets/javascripts/bootstrap/dropdown.js +103 -317
  13. data/assets/javascripts/bootstrap/modal.js +107 -749
  14. data/assets/javascripts/bootstrap/offcanvas.js +90 -659
  15. data/assets/javascripts/bootstrap/popover.js +36 -118
  16. data/assets/javascripts/bootstrap/scrollspy.js +183 -262
  17. data/assets/javascripts/bootstrap/tab.js +215 -214
  18. data/assets/javascripts/bootstrap/toast.js +36 -218
  19. data/assets/javascripts/bootstrap/tooltip.js +280 -629
  20. data/assets/javascripts/bootstrap/util/backdrop.js +165 -0
  21. data/assets/javascripts/bootstrap/util/component-functions.js +46 -0
  22. data/assets/javascripts/bootstrap/util/config.js +79 -0
  23. data/assets/javascripts/bootstrap/util/focustrap.js +129 -0
  24. data/assets/javascripts/bootstrap/util/index.js +350 -0
  25. data/assets/javascripts/bootstrap/util/sanitizer.js +122 -0
  26. data/assets/javascripts/bootstrap/util/scrollbar.js +138 -0
  27. data/assets/javascripts/bootstrap/util/swipe.js +155 -0
  28. data/assets/javascripts/bootstrap/util/template-factory.js +177 -0
  29. data/assets/javascripts/bootstrap-global-this-define.js +1 -1
  30. data/assets/javascripts/bootstrap-sprockets.js +17 -8
  31. data/assets/javascripts/bootstrap.js +2093 -1881
  32. data/assets/javascripts/bootstrap.min.js +3 -3
  33. data/assets/stylesheets/_bootstrap-grid.scss +3 -6
  34. data/assets/stylesheets/_bootstrap-reboot.scss +3 -7
  35. data/assets/stylesheets/_bootstrap.scss +4 -6
  36. data/assets/stylesheets/bootstrap/_accordion.scss +56 -25
  37. data/assets/stylesheets/bootstrap/_alert.scss +18 -4
  38. data/assets/stylesheets/bootstrap/_badge.scss +14 -5
  39. data/assets/stylesheets/bootstrap/_breadcrumb.scss +22 -10
  40. data/assets/stylesheets/bootstrap/_button-group.scss +4 -1
  41. data/assets/stylesheets/bootstrap/_buttons.scss +125 -29
  42. data/assets/stylesheets/bootstrap/_card.scss +55 -37
  43. data/assets/stylesheets/bootstrap/_close.scss +1 -1
  44. data/assets/stylesheets/bootstrap/_containers.scss +1 -1
  45. data/assets/stylesheets/bootstrap/_dropdown.scss +85 -76
  46. data/assets/stylesheets/bootstrap/_functions.scss +8 -8
  47. data/assets/stylesheets/bootstrap/_grid.scss +3 -3
  48. data/assets/stylesheets/bootstrap/_helpers.scss +1 -0
  49. data/assets/stylesheets/bootstrap/_list-group.scss +48 -30
  50. data/assets/stylesheets/bootstrap/_maps.scss +54 -0
  51. data/assets/stylesheets/bootstrap/_modal.scss +71 -43
  52. data/assets/stylesheets/bootstrap/_nav.scss +53 -20
  53. data/assets/stylesheets/bootstrap/_navbar.scss +93 -150
  54. data/assets/stylesheets/bootstrap/_offcanvas.scss +120 -59
  55. data/assets/stylesheets/bootstrap/_pagination.scss +66 -21
  56. data/assets/stylesheets/bootstrap/_placeholders.scss +1 -1
  57. data/assets/stylesheets/bootstrap/_popover.scss +90 -52
  58. data/assets/stylesheets/bootstrap/_progress.scss +20 -9
  59. data/assets/stylesheets/bootstrap/_reboot.scss +25 -40
  60. data/assets/stylesheets/bootstrap/_root.scss +40 -21
  61. data/assets/stylesheets/bootstrap/_spinners.scss +38 -22
  62. data/assets/stylesheets/bootstrap/_tables.scss +32 -23
  63. data/assets/stylesheets/bootstrap/_toasts.scss +38 -16
  64. data/assets/stylesheets/bootstrap/_tooltip.scss +61 -56
  65. data/assets/stylesheets/bootstrap/_type.scss +2 -0
  66. data/assets/stylesheets/bootstrap/_utilities.scss +43 -26
  67. data/assets/stylesheets/bootstrap/_variables.scss +128 -135
  68. data/assets/stylesheets/bootstrap/bootstrap-utilities.scss +3 -6
  69. data/assets/stylesheets/bootstrap/forms/_floating-labels.scss +15 -3
  70. data/assets/stylesheets/bootstrap/forms/_form-check.scss +28 -5
  71. data/assets/stylesheets/bootstrap/forms/_form-control.scss +12 -37
  72. data/assets/stylesheets/bootstrap/forms/_form-select.scss +0 -1
  73. data/assets/stylesheets/bootstrap/forms/_input-group.scss +19 -8
  74. data/assets/stylesheets/bootstrap/helpers/_color-bg.scss +10 -0
  75. data/assets/stylesheets/bootstrap/helpers/_colored-links.scss +2 -2
  76. data/assets/stylesheets/bootstrap/helpers/_position.scss +7 -1
  77. data/assets/stylesheets/bootstrap/helpers/_ratio.scss +2 -2
  78. data/assets/stylesheets/bootstrap/helpers/_vr.scss +1 -1
  79. data/assets/stylesheets/bootstrap/mixins/_alert.scss +7 -3
  80. data/assets/stylesheets/bootstrap/mixins/_banner.scss +9 -0
  81. data/assets/stylesheets/bootstrap/mixins/_breakpoints.scss +8 -8
  82. data/assets/stylesheets/bootstrap/mixins/_buttons.scss +32 -95
  83. data/assets/stylesheets/bootstrap/mixins/_container.scss +4 -2
  84. data/assets/stylesheets/bootstrap/mixins/_forms.scss +18 -10
  85. data/assets/stylesheets/bootstrap/mixins/_gradients.scss +1 -1
  86. data/assets/stylesheets/bootstrap/mixins/_grid.scss +12 -12
  87. data/assets/stylesheets/bootstrap/mixins/_pagination.scss +4 -25
  88. data/assets/stylesheets/bootstrap/mixins/_reset-text.scss +1 -1
  89. data/assets/stylesheets/bootstrap/mixins/_table-variants.scss +12 -9
  90. data/assets/stylesheets/bootstrap/mixins/_utilities.scss +13 -5
  91. data/bootstrap.gemspec +1 -1
  92. data/lib/bootstrap/version.rb +2 -2
  93. data/tasks/updater/js.rb +10 -5
  94. data/tasks/updater.rb +2 -2
  95. metadata +16 -4
@@ -1,13 +1,13 @@
1
1
  /*!
2
- * Bootstrap tab.js v5.1.3 (https://getbootstrap.com/)
3
- * Copyright 2011-2021 The Bootstrap Authors (https://github.com/twbs/bootstrap/graphs/contributors)
2
+ * Bootstrap tab.js v5.2.2 (https://getbootstrap.com/)
3
+ * Copyright 2011-2022 The Bootstrap Authors (https://github.com/twbs/bootstrap/graphs/contributors)
4
4
  * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
5
5
  */
6
6
  (function (global, factory) {
7
- typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory(require('./dom/event-handler.js'), require('./dom/selector-engine.js'), require('./base-component.js')) :
8
- typeof define === 'function' && define.amd ? define(['./dom/event-handler', './dom/selector-engine', './base-component'], factory) :
9
- (global = typeof globalThis !== 'undefined' ? globalThis : global || self, global.Tab = factory(global.EventHandler, global.SelectorEngine, global.Base));
10
- })(this, (function (EventHandler, SelectorEngine, BaseComponent) { 'use strict';
7
+ typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory(require('./util/index'), require('./dom/event-handler'), require('./dom/selector-engine'), require('./base-component')) :
8
+ typeof define === 'function' && define.amd ? define(['./util/index', './dom/event-handler', './dom/selector-engine', './base-component'], factory) :
9
+ (global = typeof globalThis !== 'undefined' ? globalThis : global || self, global.Tab = factory(global.Index, global.EventHandler, global.SelectorEngine, global.BaseComponent));
10
+ })(this, (function (index, EventHandler, SelectorEngine, BaseComponent) { 'use strict';
11
11
 
12
12
  const _interopDefaultLegacy = e => e && typeof e === 'object' && 'default' in e ? e : { default: e };
13
13
 
@@ -17,270 +17,266 @@
17
17
 
18
18
  /**
19
19
  * --------------------------------------------------------------------------
20
- * Bootstrap (v5.1.3): util/index.js
20
+ * Bootstrap (v5.2.2): tab.js
21
21
  * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
22
22
  * --------------------------------------------------------------------------
23
23
  */
24
-
25
- const getSelector = element => {
26
- let selector = element.getAttribute('data-bs-target');
27
-
28
- if (!selector || selector === '#') {
29
- let hrefAttr = element.getAttribute('href'); // The only valid content that could double as a selector are IDs or classes,
30
- // so everything starting with `#` or `.`. If a "real" URL is used as the selector,
31
- // `document.querySelector` will rightfully complain it is invalid.
32
- // See https://github.com/twbs/bootstrap/issues/32273
33
-
34
- if (!hrefAttr || !hrefAttr.includes('#') && !hrefAttr.startsWith('.')) {
35
- return null;
36
- } // Just in case some CMS puts out a full URL with the anchor appended
37
-
38
-
39
- if (hrefAttr.includes('#') && !hrefAttr.startsWith('#')) {
40
- hrefAttr = `#${hrefAttr.split('#')[1]}`;
41
- }
42
-
43
- selector = hrefAttr && hrefAttr !== '#' ? hrefAttr.trim() : null;
44
- }
45
-
46
- return selector;
47
- };
48
-
49
- const getElementFromSelector = element => {
50
- const selector = getSelector(element);
51
- return selector ? document.querySelector(selector) : null;
52
- };
53
-
54
- const isDisabled = element => {
55
- if (!element || element.nodeType !== Node.ELEMENT_NODE) {
56
- return true;
57
- }
58
-
59
- if (element.classList.contains('disabled')) {
60
- return true;
61
- }
62
-
63
- if (typeof element.disabled !== 'undefined') {
64
- return element.disabled;
65
- }
66
-
67
- return element.hasAttribute('disabled') && element.getAttribute('disabled') !== 'false';
68
- };
69
24
  /**
70
- * Trick to restart an element's animation
71
- *
72
- * @param {HTMLElement} element
73
- * @return void
74
- *
75
- * @see https://www.charistheo.io/blog/2021/02/restart-a-css-animation-with-javascript/#restarting-a-css-animation
76
- */
77
-
78
-
79
- const reflow = element => {
80
- // eslint-disable-next-line no-unused-expressions
81
- element.offsetHeight;
82
- };
83
-
84
- const getjQuery = () => {
85
- const {
86
- jQuery
87
- } = window;
88
-
89
- if (jQuery && !document.body.hasAttribute('data-bs-no-jquery')) {
90
- return jQuery;
91
- }
92
-
93
- return null;
94
- };
95
-
96
- const DOMContentLoadedCallbacks = [];
97
-
98
- const onDOMContentLoaded = callback => {
99
- if (document.readyState === 'loading') {
100
- // add listener on the first call when the document is in loading state
101
- if (!DOMContentLoadedCallbacks.length) {
102
- document.addEventListener('DOMContentLoaded', () => {
103
- DOMContentLoadedCallbacks.forEach(callback => callback());
104
- });
105
- }
106
-
107
- DOMContentLoadedCallbacks.push(callback);
108
- } else {
109
- callback();
110
- }
111
- };
112
-
113
- const defineJQueryPlugin = plugin => {
114
- onDOMContentLoaded(() => {
115
- const $ = getjQuery();
116
- /* istanbul ignore if */
117
-
118
- if ($) {
119
- const name = plugin.NAME;
120
- const JQUERY_NO_CONFLICT = $.fn[name];
121
- $.fn[name] = plugin.jQueryInterface;
122
- $.fn[name].Constructor = plugin;
123
-
124
- $.fn[name].noConflict = () => {
125
- $.fn[name] = JQUERY_NO_CONFLICT;
126
- return plugin.jQueryInterface;
127
- };
128
- }
129
- });
130
- };
131
-
132
- /**
133
- * --------------------------------------------------------------------------
134
- * Bootstrap (v5.1.3): tab.js
135
- * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
136
- * --------------------------------------------------------------------------
137
- */
138
- /**
139
- * ------------------------------------------------------------------------
140
25
  * Constants
141
- * ------------------------------------------------------------------------
142
26
  */
143
27
 
144
28
  const NAME = 'tab';
145
29
  const DATA_KEY = 'bs.tab';
146
30
  const EVENT_KEY = `.${DATA_KEY}`;
147
- const DATA_API_KEY = '.data-api';
148
31
  const EVENT_HIDE = `hide${EVENT_KEY}`;
149
32
  const EVENT_HIDDEN = `hidden${EVENT_KEY}`;
150
33
  const EVENT_SHOW = `show${EVENT_KEY}`;
151
34
  const EVENT_SHOWN = `shown${EVENT_KEY}`;
152
- const EVENT_CLICK_DATA_API = `click${EVENT_KEY}${DATA_API_KEY}`;
153
- const CLASS_NAME_DROPDOWN_MENU = 'dropdown-menu';
35
+ const EVENT_CLICK_DATA_API = `click${EVENT_KEY}`;
36
+ const EVENT_KEYDOWN = `keydown${EVENT_KEY}`;
37
+ const EVENT_LOAD_DATA_API = `load${EVENT_KEY}`;
38
+ const ARROW_LEFT_KEY = 'ArrowLeft';
39
+ const ARROW_RIGHT_KEY = 'ArrowRight';
40
+ const ARROW_UP_KEY = 'ArrowUp';
41
+ const ARROW_DOWN_KEY = 'ArrowDown';
154
42
  const CLASS_NAME_ACTIVE = 'active';
155
43
  const CLASS_NAME_FADE = 'fade';
156
44
  const CLASS_NAME_SHOW = 'show';
157
- const SELECTOR_DROPDOWN = '.dropdown';
158
- const SELECTOR_NAV_LIST_GROUP = '.nav, .list-group';
159
- const SELECTOR_ACTIVE = '.active';
160
- const SELECTOR_ACTIVE_UL = ':scope > li > .active';
161
- const SELECTOR_DATA_TOGGLE = '[data-bs-toggle="tab"], [data-bs-toggle="pill"], [data-bs-toggle="list"]';
45
+ const CLASS_DROPDOWN = 'dropdown';
162
46
  const SELECTOR_DROPDOWN_TOGGLE = '.dropdown-toggle';
163
- const SELECTOR_DROPDOWN_ACTIVE_CHILD = ':scope > .dropdown-menu .active';
47
+ const SELECTOR_DROPDOWN_MENU = '.dropdown-menu';
48
+ const NOT_SELECTOR_DROPDOWN_TOGGLE = ':not(.dropdown-toggle)';
49
+ const SELECTOR_TAB_PANEL = '.list-group, .nav, [role="tablist"]';
50
+ const SELECTOR_OUTER = '.nav-item, .list-group-item';
51
+ const SELECTOR_INNER = `.nav-link${NOT_SELECTOR_DROPDOWN_TOGGLE}, .list-group-item${NOT_SELECTOR_DROPDOWN_TOGGLE}, [role="tab"]${NOT_SELECTOR_DROPDOWN_TOGGLE}`;
52
+ const SELECTOR_DATA_TOGGLE = '[data-bs-toggle="tab"], [data-bs-toggle="pill"], [data-bs-toggle="list"]'; // todo:v6: could be only `tab`
53
+
54
+ const SELECTOR_INNER_ELEM = `${SELECTOR_INNER}, ${SELECTOR_DATA_TOGGLE}`;
55
+ const SELECTOR_DATA_TOGGLE_ACTIVE = `.${CLASS_NAME_ACTIVE}[data-bs-toggle="tab"], .${CLASS_NAME_ACTIVE}[data-bs-toggle="pill"], .${CLASS_NAME_ACTIVE}[data-bs-toggle="list"]`;
164
56
  /**
165
- * ------------------------------------------------------------------------
166
- * Class Definition
167
- * ------------------------------------------------------------------------
57
+ * Class definition
168
58
  */
169
59
 
170
60
  class Tab extends BaseComponent__default.default {
171
- // Getters
61
+ constructor(element) {
62
+ super(element);
63
+ this._parent = this._element.closest(SELECTOR_TAB_PANEL);
64
+
65
+ if (!this._parent) {
66
+ return; // todo: should Throw exception on v6
67
+ // throw new TypeError(`${element.outerHTML} has not a valid parent ${SELECTOR_INNER_ELEM}`)
68
+ } // Set up initial aria attributes
69
+
70
+
71
+ this._setInitialAttributes(this._parent, this._getChildren());
72
+
73
+ EventHandler__default.default.on(this._element, EVENT_KEYDOWN, event => this._keydown(event));
74
+ } // Getters
75
+
76
+
172
77
  static get NAME() {
173
78
  return NAME;
174
79
  } // Public
175
80
 
176
81
 
177
82
  show() {
178
- if (this._element.parentNode && this._element.parentNode.nodeType === Node.ELEMENT_NODE && this._element.classList.contains(CLASS_NAME_ACTIVE)) {
179
- return;
180
- }
83
+ // Shows this elem and deactivate the active sibling if exists
84
+ const innerElem = this._element;
181
85
 
182
- let previous;
183
- const target = getElementFromSelector(this._element);
86
+ if (this._elemIsActive(innerElem)) {
87
+ return;
88
+ } // Search for active tab on same parent to deactivate it
184
89
 
185
- const listElement = this._element.closest(SELECTOR_NAV_LIST_GROUP);
186
90
 
187
- if (listElement) {
188
- const itemSelector = listElement.nodeName === 'UL' || listElement.nodeName === 'OL' ? SELECTOR_ACTIVE_UL : SELECTOR_ACTIVE;
189
- previous = SelectorEngine__default.default.find(itemSelector, listElement);
190
- previous = previous[previous.length - 1];
191
- }
91
+ const active = this._getActiveElem();
192
92
 
193
- const hideEvent = previous ? EventHandler__default.default.trigger(previous, EVENT_HIDE, {
194
- relatedTarget: this._element
93
+ const hideEvent = active ? EventHandler__default.default.trigger(active, EVENT_HIDE, {
94
+ relatedTarget: innerElem
195
95
  }) : null;
196
- const showEvent = EventHandler__default.default.trigger(this._element, EVENT_SHOW, {
197
- relatedTarget: previous
96
+ const showEvent = EventHandler__default.default.trigger(innerElem, EVENT_SHOW, {
97
+ relatedTarget: active
198
98
  });
199
99
 
200
- if (showEvent.defaultPrevented || hideEvent !== null && hideEvent.defaultPrevented) {
100
+ if (showEvent.defaultPrevented || hideEvent && hideEvent.defaultPrevented) {
201
101
  return;
202
102
  }
203
103
 
204
- this._activate(this._element, listElement);
104
+ this._deactivate(active, innerElem);
105
+
106
+ this._activate(innerElem, active);
107
+ } // Private
108
+
109
+
110
+ _activate(element, relatedElem) {
111
+ if (!element) {
112
+ return;
113
+ }
114
+
115
+ element.classList.add(CLASS_NAME_ACTIVE);
116
+
117
+ this._activate(index.getElementFromSelector(element)); // Search and activate/show the proper section
118
+
205
119
 
206
120
  const complete = () => {
207
- EventHandler__default.default.trigger(previous, EVENT_HIDDEN, {
208
- relatedTarget: this._element
121
+ if (element.getAttribute('role') !== 'tab') {
122
+ element.classList.add(CLASS_NAME_SHOW);
123
+ return;
124
+ }
125
+
126
+ element.removeAttribute('tabindex');
127
+ element.setAttribute('aria-selected', true);
128
+
129
+ this._toggleDropDown(element, true);
130
+
131
+ EventHandler__default.default.trigger(element, EVENT_SHOWN, {
132
+ relatedTarget: relatedElem
209
133
  });
210
- EventHandler__default.default.trigger(this._element, EVENT_SHOWN, {
211
- relatedTarget: previous
134
+ };
135
+
136
+ this._queueCallback(complete, element, element.classList.contains(CLASS_NAME_FADE));
137
+ }
138
+
139
+ _deactivate(element, relatedElem) {
140
+ if (!element) {
141
+ return;
142
+ }
143
+
144
+ element.classList.remove(CLASS_NAME_ACTIVE);
145
+ element.blur();
146
+
147
+ this._deactivate(index.getElementFromSelector(element)); // Search and deactivate the shown section too
148
+
149
+
150
+ const complete = () => {
151
+ if (element.getAttribute('role') !== 'tab') {
152
+ element.classList.remove(CLASS_NAME_SHOW);
153
+ return;
154
+ }
155
+
156
+ element.setAttribute('aria-selected', false);
157
+ element.setAttribute('tabindex', '-1');
158
+
159
+ this._toggleDropDown(element, false);
160
+
161
+ EventHandler__default.default.trigger(element, EVENT_HIDDEN, {
162
+ relatedTarget: relatedElem
212
163
  });
213
164
  };
214
165
 
215
- if (target) {
216
- this._activate(target, target.parentNode, complete);
217
- } else {
218
- complete();
166
+ this._queueCallback(complete, element, element.classList.contains(CLASS_NAME_FADE));
167
+ }
168
+
169
+ _keydown(event) {
170
+ if (![ARROW_LEFT_KEY, ARROW_RIGHT_KEY, ARROW_UP_KEY, ARROW_DOWN_KEY].includes(event.key)) {
171
+ return;
219
172
  }
220
- } // Private
221
173
 
174
+ event.stopPropagation(); // stopPropagation/preventDefault both added to support up/down keys without scrolling the page
222
175
 
223
- _activate(element, container, callback) {
224
- const activeElements = container && (container.nodeName === 'UL' || container.nodeName === 'OL') ? SelectorEngine__default.default.find(SELECTOR_ACTIVE_UL, container) : SelectorEngine__default.default.children(container, SELECTOR_ACTIVE);
225
- const active = activeElements[0];
226
- const isTransitioning = callback && active && active.classList.contains(CLASS_NAME_FADE);
176
+ event.preventDefault();
177
+ const isNext = [ARROW_RIGHT_KEY, ARROW_DOWN_KEY].includes(event.key);
178
+ const nextActiveElement = index.getNextActiveElement(this._getChildren().filter(element => !index.isDisabled(element)), event.target, isNext, true);
227
179
 
228
- const complete = () => this._transitionComplete(element, active, callback);
180
+ if (nextActiveElement) {
181
+ nextActiveElement.focus({
182
+ preventScroll: true
183
+ });
184
+ Tab.getOrCreateInstance(nextActiveElement).show();
185
+ }
186
+ }
229
187
 
230
- if (active && isTransitioning) {
231
- active.classList.remove(CLASS_NAME_SHOW);
188
+ _getChildren() {
189
+ // collection of inner elements
190
+ return SelectorEngine__default.default.find(SELECTOR_INNER_ELEM, this._parent);
191
+ }
232
192
 
233
- this._queueCallback(complete, element, true);
234
- } else {
235
- complete();
193
+ _getActiveElem() {
194
+ return this._getChildren().find(child => this._elemIsActive(child)) || null;
195
+ }
196
+
197
+ _setInitialAttributes(parent, children) {
198
+ this._setAttributeIfNotExists(parent, 'role', 'tablist');
199
+
200
+ for (const child of children) {
201
+ this._setInitialAttributesOnChild(child);
236
202
  }
237
203
  }
238
204
 
239
- _transitionComplete(element, active, callback) {
240
- if (active) {
241
- active.classList.remove(CLASS_NAME_ACTIVE);
242
- const dropdownChild = SelectorEngine__default.default.findOne(SELECTOR_DROPDOWN_ACTIVE_CHILD, active.parentNode);
205
+ _setInitialAttributesOnChild(child) {
206
+ child = this._getInnerElement(child);
243
207
 
244
- if (dropdownChild) {
245
- dropdownChild.classList.remove(CLASS_NAME_ACTIVE);
246
- }
208
+ const isActive = this._elemIsActive(child);
247
209
 
248
- if (active.getAttribute('role') === 'tab') {
249
- active.setAttribute('aria-selected', false);
250
- }
210
+ const outerElem = this._getOuterElement(child);
211
+
212
+ child.setAttribute('aria-selected', isActive);
213
+
214
+ if (outerElem !== child) {
215
+ this._setAttributeIfNotExists(outerElem, 'role', 'presentation');
251
216
  }
252
217
 
253
- element.classList.add(CLASS_NAME_ACTIVE);
218
+ if (!isActive) {
219
+ child.setAttribute('tabindex', '-1');
220
+ }
254
221
 
255
- if (element.getAttribute('role') === 'tab') {
256
- element.setAttribute('aria-selected', true);
222
+ this._setAttributeIfNotExists(child, 'role', 'tab'); // set attributes to the related panel too
223
+
224
+
225
+ this._setInitialAttributesOnTargetPanel(child);
226
+ }
227
+
228
+ _setInitialAttributesOnTargetPanel(child) {
229
+ const target = index.getElementFromSelector(child);
230
+
231
+ if (!target) {
232
+ return;
257
233
  }
258
234
 
259
- reflow(element);
235
+ this._setAttributeIfNotExists(target, 'role', 'tabpanel');
260
236
 
261
- if (element.classList.contains(CLASS_NAME_FADE)) {
262
- element.classList.add(CLASS_NAME_SHOW);
237
+ if (child.id) {
238
+ this._setAttributeIfNotExists(target, 'aria-labelledby', `#${child.id}`);
263
239
  }
240
+ }
264
241
 
265
- let parent = element.parentNode;
242
+ _toggleDropDown(element, open) {
243
+ const outerElem = this._getOuterElement(element);
266
244
 
267
- if (parent && parent.nodeName === 'LI') {
268
- parent = parent.parentNode;
245
+ if (!outerElem.classList.contains(CLASS_DROPDOWN)) {
246
+ return;
269
247
  }
270
248
 
271
- if (parent && parent.classList.contains(CLASS_NAME_DROPDOWN_MENU)) {
272
- const dropdownElement = element.closest(SELECTOR_DROPDOWN);
249
+ const toggle = (selector, className) => {
250
+ const element = SelectorEngine__default.default.findOne(selector, outerElem);
273
251
 
274
- if (dropdownElement) {
275
- SelectorEngine__default.default.find(SELECTOR_DROPDOWN_TOGGLE, dropdownElement).forEach(dropdown => dropdown.classList.add(CLASS_NAME_ACTIVE));
252
+ if (element) {
253
+ element.classList.toggle(className, open);
276
254
  }
255
+ };
277
256
 
278
- element.setAttribute('aria-expanded', true);
279
- }
257
+ toggle(SELECTOR_DROPDOWN_TOGGLE, CLASS_NAME_ACTIVE);
258
+ toggle(SELECTOR_DROPDOWN_MENU, CLASS_NAME_SHOW);
259
+ outerElem.setAttribute('aria-expanded', open);
260
+ }
280
261
 
281
- if (callback) {
282
- callback();
262
+ _setAttributeIfNotExists(element, attribute, value) {
263
+ if (!element.hasAttribute(attribute)) {
264
+ element.setAttribute(attribute, value);
283
265
  }
266
+ }
267
+
268
+ _elemIsActive(elem) {
269
+ return elem.classList.contains(CLASS_NAME_ACTIVE);
270
+ } // Try to get the inner element (usually the .nav-link)
271
+
272
+
273
+ _getInnerElement(elem) {
274
+ return elem.matches(SELECTOR_INNER_ELEM) ? elem : SelectorEngine__default.default.findOne(SELECTOR_INNER_ELEM, elem);
275
+ } // Try to get the outer element (usually the .nav-item)
276
+
277
+
278
+ _getOuterElement(elem) {
279
+ return elem.closest(SELECTOR_OUTER) || elem;
284
280
  } // Static
285
281
 
286
282
 
@@ -288,21 +284,21 @@
288
284
  return this.each(function () {
289
285
  const data = Tab.getOrCreateInstance(this);
290
286
 
291
- if (typeof config === 'string') {
292
- if (typeof data[config] === 'undefined') {
293
- throw new TypeError(`No method named "${config}"`);
294
- }
287
+ if (typeof config !== 'string') {
288
+ return;
289
+ }
295
290
 
296
- data[config]();
291
+ if (data[config] === undefined || config.startsWith('_') || config === 'constructor') {
292
+ throw new TypeError(`No method named "${config}"`);
297
293
  }
294
+
295
+ data[config]();
298
296
  });
299
297
  }
300
298
 
301
299
  }
302
300
  /**
303
- * ------------------------------------------------------------------------
304
- * Data Api implementation
305
- * ------------------------------------------------------------------------
301
+ * Data API implementation
306
302
  */
307
303
 
308
304
 
@@ -311,21 +307,26 @@
311
307
  event.preventDefault();
312
308
  }
313
309
 
314
- if (isDisabled(this)) {
310
+ if (index.isDisabled(this)) {
315
311
  return;
316
312
  }
317
313
 
318
- const data = Tab.getOrCreateInstance(this);
319
- data.show();
314
+ Tab.getOrCreateInstance(this).show();
315
+ });
316
+ /**
317
+ * Initialize on focus
318
+ */
319
+
320
+ EventHandler__default.default.on(window, EVENT_LOAD_DATA_API, () => {
321
+ for (const element of SelectorEngine__default.default.find(SELECTOR_DATA_TOGGLE_ACTIVE)) {
322
+ Tab.getOrCreateInstance(element);
323
+ }
320
324
  });
321
325
  /**
322
- * ------------------------------------------------------------------------
323
326
  * jQuery
324
- * ------------------------------------------------------------------------
325
- * add .Tab to jQuery only if jQuery is present
326
327
  */
327
328
 
328
- defineJQueryPlugin(Tab);
329
+ index.defineJQueryPlugin(Tab);
329
330
 
330
331
  return Tab;
331
332