bootstrap 5.1.1 → 5.2.0

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 +1 -1
  3. data/assets/javascripts/bootstrap/alert.js +18 -153
  4. data/assets/javascripts/bootstrap/base-component.js +44 -127
  5. data/assets/javascripts/bootstrap/button.js +16 -80
  6. data/assets/javascripts/bootstrap/carousel.js +225 -497
  7. data/assets/javascripts/bootstrap/collapse.js +79 -262
  8. data/assets/javascripts/bootstrap/dom/data.js +6 -8
  9. data/assets/javascripts/bootstrap/dom/event-handler.js +95 -133
  10. data/assets/javascripts/bootstrap/dom/manipulator.js +25 -29
  11. data/assets/javascripts/bootstrap/dom/selector-engine.js +17 -59
  12. data/assets/javascripts/bootstrap/dropdown.js +124 -342
  13. data/assets/javascripts/bootstrap/modal.js +122 -767
  14. data/assets/javascripts/bootstrap/offcanvas.js +102 -671
  15. data/assets/javascripts/bootstrap/popover.js +42 -124
  16. data/assets/javascripts/bootstrap/scrollspy.js +186 -269
  17. data/assets/javascripts/bootstrap/tab.js +222 -221
  18. data/assets/javascripts/bootstrap/toast.js +41 -227
  19. data/assets/javascripts/bootstrap/tooltip.js +283 -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 +16 -7
  31. data/assets/javascripts/bootstrap.js +2094 -1891
  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 +52 -24
  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 +3 -0
  41. data/assets/stylesheets/bootstrap/_buttons.scss +97 -22
  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 +83 -75
  46. data/assets/stylesheets/bootstrap/_functions.scss +7 -7
  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 +44 -27
  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 +91 -150
  54. data/assets/stylesheets/bootstrap/_offcanvas.scss +119 -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 +38 -25
  63. data/assets/stylesheets/bootstrap/_toasts.scss +35 -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 +118 -124
  68. data/assets/stylesheets/bootstrap/bootstrap-utilities.scss +3 -6
  69. data/assets/stylesheets/bootstrap/forms/_floating-labels.scss +14 -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 +2 -1
  73. data/assets/stylesheets/bootstrap/forms/_input-group.scss +15 -7
  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 +8 -0
  85. data/assets/stylesheets/bootstrap/mixins/_gradients.scss +1 -1
  86. data/assets/stylesheets/bootstrap/mixins/_grid.scss +13 -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 +12 -4
  91. data/assets/stylesheets/bootstrap/mixins/_visually-hidden.scss +1 -1
  92. data/bootstrap.gemspec +1 -1
  93. data/lib/bootstrap/version.rb +2 -2
  94. data/tasks/updater/js.rb +9 -4
  95. metadata +16 -4
@@ -1,286 +1,282 @@
1
1
  /*!
2
- * Bootstrap tab.js v5.1.1 (https://getbootstrap.com/)
3
- * Copyright 2011-2021 The Bootstrap Authors (https://github.com/twbs/bootstrap/graphs/contributors)
2
+ * Bootstrap tab.js v5.2.0 (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
- function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
12
+ const _interopDefaultLegacy = e => e && typeof e === 'object' && 'default' in e ? e : { default: e };
13
13
 
14
- var EventHandler__default = /*#__PURE__*/_interopDefaultLegacy(EventHandler);
15
- var SelectorEngine__default = /*#__PURE__*/_interopDefaultLegacy(SelectorEngine);
16
- var BaseComponent__default = /*#__PURE__*/_interopDefaultLegacy(BaseComponent);
14
+ const EventHandler__default = /*#__PURE__*/_interopDefaultLegacy(EventHandler);
15
+ const SelectorEngine__default = /*#__PURE__*/_interopDefaultLegacy(SelectorEngine);
16
+ const BaseComponent__default = /*#__PURE__*/_interopDefaultLegacy(BaseComponent);
17
17
 
18
18
  /**
19
19
  * --------------------------------------------------------------------------
20
- * Bootstrap (v5.1.1): util/index.js
21
- * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
22
- * --------------------------------------------------------------------------
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
- /**
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.1): tab.js
20
+ * Bootstrap (v5.2.0): tab.js
135
21
  * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
136
22
  * --------------------------------------------------------------------------
137
23
  */
138
24
  /**
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 SELECTOR_DROPDOWN_ITEM = '.dropdown-item';
49
+ const NOT_SELECTOR_DROPDOWN_TOGGLE = ':not(.dropdown-toggle)';
50
+ const SELECTOR_TAB_PANEL = '.list-group, .nav, [role="tablist"]';
51
+ const SELECTOR_OUTER = '.nav-item, .list-group-item';
52
+ const SELECTOR_INNER = `.nav-link${NOT_SELECTOR_DROPDOWN_TOGGLE}, .list-group-item${NOT_SELECTOR_DROPDOWN_TOGGLE}, [role="tab"]${NOT_SELECTOR_DROPDOWN_TOGGLE}`;
53
+ const SELECTOR_DATA_TOGGLE = '[data-bs-toggle="tab"], [data-bs-toggle="pill"], [data-bs-toggle="list"]'; // todo:v6: could be only `tab`
54
+
55
+ const SELECTOR_INNER_ELEM = `${SELECTOR_INNER}, ${SELECTOR_DATA_TOGGLE}`;
56
+ 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
57
  /**
165
- * ------------------------------------------------------------------------
166
- * Class Definition
167
- * ------------------------------------------------------------------------
58
+ * Class definition
168
59
  */
169
60
 
170
- class Tab extends BaseComponent__default['default'] {
171
- // Getters
61
+ class Tab extends BaseComponent__default.default {
62
+ constructor(element) {
63
+ super(element);
64
+ this._parent = this._element.closest(SELECTOR_TAB_PANEL);
65
+
66
+ if (!this._parent) {
67
+ return; // todo: should Throw exception on v6
68
+ // throw new TypeError(`${element.outerHTML} has not a valid parent ${SELECTOR_INNER_ELEM}`)
69
+ } // Set up initial aria attributes
70
+
71
+
72
+ this._setInitialAttributes(this._parent, this._getChildren());
73
+
74
+ EventHandler__default.default.on(this._element, EVENT_KEYDOWN, event => this._keydown(event));
75
+ } // Getters
76
+
77
+
172
78
  static get NAME() {
173
79
  return NAME;
174
80
  } // Public
175
81
 
176
82
 
177
83
  show() {
178
- if (this._element.parentNode && this._element.parentNode.nodeType === Node.ELEMENT_NODE && this._element.classList.contains(CLASS_NAME_ACTIVE)) {
179
- return;
180
- }
84
+ // Shows this elem and deactivate the active sibling if exists
85
+ const innerElem = this._element;
181
86
 
182
- let previous;
183
- const target = getElementFromSelector(this._element);
87
+ if (this._elemIsActive(innerElem)) {
88
+ return;
89
+ } // Search for active tab on same parent to deactivate it
184
90
 
185
- const listElement = this._element.closest(SELECTOR_NAV_LIST_GROUP);
186
91
 
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
- }
92
+ const active = this._getActiveElem();
192
93
 
193
- const hideEvent = previous ? EventHandler__default['default'].trigger(previous, EVENT_HIDE, {
194
- relatedTarget: this._element
94
+ const hideEvent = active ? EventHandler__default.default.trigger(active, EVENT_HIDE, {
95
+ relatedTarget: innerElem
195
96
  }) : null;
196
- const showEvent = EventHandler__default['default'].trigger(this._element, EVENT_SHOW, {
197
- relatedTarget: previous
97
+ const showEvent = EventHandler__default.default.trigger(innerElem, EVENT_SHOW, {
98
+ relatedTarget: active
198
99
  });
199
100
 
200
- if (showEvent.defaultPrevented || hideEvent !== null && hideEvent.defaultPrevented) {
101
+ if (showEvent.defaultPrevented || hideEvent && hideEvent.defaultPrevented) {
201
102
  return;
202
103
  }
203
104
 
204
- this._activate(this._element, listElement);
105
+ this._deactivate(active, innerElem);
106
+
107
+ this._activate(innerElem, active);
108
+ } // Private
109
+
110
+
111
+ _activate(element, relatedElem) {
112
+ if (!element) {
113
+ return;
114
+ }
115
+
116
+ element.classList.add(CLASS_NAME_ACTIVE);
117
+
118
+ this._activate(index.getElementFromSelector(element)); // Search and activate/show the proper section
119
+
205
120
 
206
121
  const complete = () => {
207
- EventHandler__default['default'].trigger(previous, EVENT_HIDDEN, {
208
- relatedTarget: this._element
122
+ if (element.getAttribute('role') !== 'tab') {
123
+ element.classList.add(CLASS_NAME_SHOW);
124
+ return;
125
+ }
126
+
127
+ element.focus();
128
+ element.removeAttribute('tabindex');
129
+ element.setAttribute('aria-selected', true);
130
+
131
+ this._toggleDropDown(element, true);
132
+
133
+ EventHandler__default.default.trigger(element, EVENT_SHOWN, {
134
+ relatedTarget: relatedElem
209
135
  });
210
- EventHandler__default['default'].trigger(this._element, EVENT_SHOWN, {
211
- relatedTarget: previous
136
+ };
137
+
138
+ this._queueCallback(complete, element, element.classList.contains(CLASS_NAME_FADE));
139
+ }
140
+
141
+ _deactivate(element, relatedElem) {
142
+ if (!element) {
143
+ return;
144
+ }
145
+
146
+ element.classList.remove(CLASS_NAME_ACTIVE);
147
+ element.blur();
148
+
149
+ this._deactivate(index.getElementFromSelector(element)); // Search and deactivate the shown section too
150
+
151
+
152
+ const complete = () => {
153
+ if (element.getAttribute('role') !== 'tab') {
154
+ element.classList.remove(CLASS_NAME_SHOW);
155
+ return;
156
+ }
157
+
158
+ element.setAttribute('aria-selected', false);
159
+ element.setAttribute('tabindex', '-1');
160
+
161
+ this._toggleDropDown(element, false);
162
+
163
+ EventHandler__default.default.trigger(element, EVENT_HIDDEN, {
164
+ relatedTarget: relatedElem
212
165
  });
213
166
  };
214
167
 
215
- if (target) {
216
- this._activate(target, target.parentNode, complete);
217
- } else {
218
- complete();
168
+ this._queueCallback(complete, element, element.classList.contains(CLASS_NAME_FADE));
169
+ }
170
+
171
+ _keydown(event) {
172
+ if (![ARROW_LEFT_KEY, ARROW_RIGHT_KEY, ARROW_UP_KEY, ARROW_DOWN_KEY].includes(event.key)) {
173
+ return;
219
174
  }
220
- } // Private
221
175
 
176
+ event.stopPropagation(); // stopPropagation/preventDefault both added to support up/down keys without scrolling the page
222
177
 
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);
178
+ event.preventDefault();
179
+ const isNext = [ARROW_RIGHT_KEY, ARROW_DOWN_KEY].includes(event.key);
180
+ const nextActiveElement = index.getNextActiveElement(this._getChildren().filter(element => !index.isDisabled(element)), event.target, isNext, true);
227
181
 
228
- const complete = () => this._transitionComplete(element, active, callback);
182
+ if (nextActiveElement) {
183
+ Tab.getOrCreateInstance(nextActiveElement).show();
184
+ }
185
+ }
229
186
 
230
- if (active && isTransitioning) {
231
- active.classList.remove(CLASS_NAME_SHOW);
187
+ _getChildren() {
188
+ // collection of inner elements
189
+ return SelectorEngine__default.default.find(SELECTOR_INNER_ELEM, this._parent);
190
+ }
232
191
 
233
- this._queueCallback(complete, element, true);
234
- } else {
235
- complete();
192
+ _getActiveElem() {
193
+ return this._getChildren().find(child => this._elemIsActive(child)) || null;
194
+ }
195
+
196
+ _setInitialAttributes(parent, children) {
197
+ this._setAttributeIfNotExists(parent, 'role', 'tablist');
198
+
199
+ for (const child of children) {
200
+ this._setInitialAttributesOnChild(child);
236
201
  }
237
202
  }
238
203
 
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);
204
+ _setInitialAttributesOnChild(child) {
205
+ child = this._getInnerElement(child);
243
206
 
244
- if (dropdownChild) {
245
- dropdownChild.classList.remove(CLASS_NAME_ACTIVE);
246
- }
207
+ const isActive = this._elemIsActive(child);
247
208
 
248
- if (active.getAttribute('role') === 'tab') {
249
- active.setAttribute('aria-selected', false);
250
- }
209
+ const outerElem = this._getOuterElement(child);
210
+
211
+ child.setAttribute('aria-selected', isActive);
212
+
213
+ if (outerElem !== child) {
214
+ this._setAttributeIfNotExists(outerElem, 'role', 'presentation');
251
215
  }
252
216
 
253
- element.classList.add(CLASS_NAME_ACTIVE);
217
+ if (!isActive) {
218
+ child.setAttribute('tabindex', '-1');
219
+ }
254
220
 
255
- if (element.getAttribute('role') === 'tab') {
256
- element.setAttribute('aria-selected', true);
221
+ this._setAttributeIfNotExists(child, 'role', 'tab'); // set attributes to the related panel too
222
+
223
+
224
+ this._setInitialAttributesOnTargetPanel(child);
225
+ }
226
+
227
+ _setInitialAttributesOnTargetPanel(child) {
228
+ const target = index.getElementFromSelector(child);
229
+
230
+ if (!target) {
231
+ return;
257
232
  }
258
233
 
259
- reflow(element);
234
+ this._setAttributeIfNotExists(target, 'role', 'tabpanel');
260
235
 
261
- if (element.classList.contains(CLASS_NAME_FADE)) {
262
- element.classList.add(CLASS_NAME_SHOW);
236
+ if (child.id) {
237
+ this._setAttributeIfNotExists(target, 'aria-labelledby', `#${child.id}`);
263
238
  }
239
+ }
264
240
 
265
- let parent = element.parentNode;
241
+ _toggleDropDown(element, open) {
242
+ const outerElem = this._getOuterElement(element);
266
243
 
267
- if (parent && parent.nodeName === 'LI') {
268
- parent = parent.parentNode;
244
+ if (!outerElem.classList.contains(CLASS_DROPDOWN)) {
245
+ return;
269
246
  }
270
247
 
271
- if (parent && parent.classList.contains(CLASS_NAME_DROPDOWN_MENU)) {
272
- const dropdownElement = element.closest(SELECTOR_DROPDOWN);
248
+ const toggle = (selector, className) => {
249
+ const element = SelectorEngine__default.default.findOne(selector, outerElem);
273
250
 
274
- if (dropdownElement) {
275
- SelectorEngine__default['default'].find(SELECTOR_DROPDOWN_TOGGLE, dropdownElement).forEach(dropdown => dropdown.classList.add(CLASS_NAME_ACTIVE));
251
+ if (element) {
252
+ element.classList.toggle(className, open);
276
253
  }
254
+ };
277
255
 
278
- element.setAttribute('aria-expanded', true);
279
- }
256
+ toggle(SELECTOR_DROPDOWN_TOGGLE, CLASS_NAME_ACTIVE);
257
+ toggle(SELECTOR_DROPDOWN_MENU, CLASS_NAME_SHOW);
258
+ toggle(SELECTOR_DROPDOWN_ITEM, CLASS_NAME_ACTIVE);
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,45 +284,50 @@
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
 
309
- EventHandler__default['default'].on(document, EVENT_CLICK_DATA_API, SELECTOR_DATA_TOGGLE, function (event) {
305
+ EventHandler__default.default.on(document, EVENT_CLICK_DATA_API, SELECTOR_DATA_TOGGLE, function (event) {
310
306
  if (['A', 'AREA'].includes(this.tagName)) {
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
 
332
- })));
333
+ }));