bootstrap 5.0.1 → 5.1.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (65) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +2 -2
  3. data/assets/javascripts/bootstrap/alert.js +89 -58
  4. data/assets/javascripts/bootstrap/base-component.js +53 -39
  5. data/assets/javascripts/bootstrap/button.js +31 -25
  6. data/assets/javascripts/bootstrap/carousel.js +126 -89
  7. data/assets/javascripts/bootstrap/collapse.js +125 -133
  8. data/assets/javascripts/bootstrap/dom/data.js +5 -5
  9. data/assets/javascripts/bootstrap/dom/event-handler.js +11 -5
  10. data/assets/javascripts/bootstrap/dom/manipulator.js +6 -6
  11. data/assets/javascripts/bootstrap/dom/selector-engine.js +49 -7
  12. data/assets/javascripts/bootstrap/dropdown.js +147 -140
  13. data/assets/javascripts/bootstrap/modal.js +397 -180
  14. data/assets/javascripts/bootstrap/offcanvas.js +333 -138
  15. data/assets/javascripts/bootstrap/popover.js +36 -54
  16. data/assets/javascripts/bootstrap/scrollspy.js +58 -68
  17. data/assets/javascripts/bootstrap/tab.js +53 -26
  18. data/assets/javascripts/bootstrap/toast.js +138 -41
  19. data/assets/javascripts/bootstrap/tooltip.js +137 -120
  20. data/assets/javascripts/bootstrap-sprockets.js +8 -8
  21. data/assets/javascripts/bootstrap.js +937 -886
  22. data/assets/javascripts/bootstrap.min.js +2 -2
  23. data/assets/stylesheets/_bootstrap-grid.scss +3 -1
  24. data/assets/stylesheets/_bootstrap-reboot.scss +2 -4
  25. data/assets/stylesheets/_bootstrap.scss +2 -1
  26. data/assets/stylesheets/bootstrap/_buttons.scss +1 -0
  27. data/assets/stylesheets/bootstrap/_card.scss +7 -6
  28. data/assets/stylesheets/bootstrap/_carousel.scss +2 -2
  29. data/assets/stylesheets/bootstrap/_dropdown.scss +4 -4
  30. data/assets/stylesheets/bootstrap/_functions.scss +100 -3
  31. data/assets/stylesheets/bootstrap/_grid.scss +11 -0
  32. data/assets/stylesheets/bootstrap/_helpers.scss +2 -0
  33. data/assets/stylesheets/bootstrap/_images.scss +1 -1
  34. data/assets/stylesheets/bootstrap/_mixins.scss +1 -0
  35. data/assets/stylesheets/bootstrap/_modal.scss +5 -15
  36. data/assets/stylesheets/bootstrap/_navbar.scss +30 -1
  37. data/assets/stylesheets/bootstrap/_offcanvas.scss +8 -2
  38. data/assets/stylesheets/bootstrap/_placeholders.scss +51 -0
  39. data/assets/stylesheets/bootstrap/_popover.scss +10 -10
  40. data/assets/stylesheets/bootstrap/_reboot.scss +12 -8
  41. data/assets/stylesheets/bootstrap/_root.scss +40 -2
  42. data/assets/stylesheets/bootstrap/_tables.scss +9 -5
  43. data/assets/stylesheets/bootstrap/_toasts.scss +3 -3
  44. data/assets/stylesheets/bootstrap/_tooltip.scss +4 -4
  45. data/assets/stylesheets/bootstrap/_transitions.scss +6 -0
  46. data/assets/stylesheets/bootstrap/_utilities.scss +44 -8
  47. data/assets/stylesheets/bootstrap/_variables.scss +206 -29
  48. data/assets/stylesheets/bootstrap/bootstrap-utilities.scss +1 -1
  49. data/assets/stylesheets/bootstrap/forms/_floating-labels.scss +3 -1
  50. data/assets/stylesheets/bootstrap/forms/_form-check.scss +1 -1
  51. data/assets/stylesheets/bootstrap/forms/_form-control.scss +1 -1
  52. data/assets/stylesheets/bootstrap/forms/_form-range.scss +1 -1
  53. data/assets/stylesheets/bootstrap/forms/_form-select.scss +5 -0
  54. data/assets/stylesheets/bootstrap/helpers/_stacks.scss +15 -0
  55. data/assets/stylesheets/bootstrap/helpers/_vr.scss +8 -0
  56. data/assets/stylesheets/bootstrap/mixins/_backdrop.scss +14 -0
  57. data/assets/stylesheets/bootstrap/mixins/_buttons.scss +1 -1
  58. data/assets/stylesheets/bootstrap/mixins/_grid.scss +35 -9
  59. data/assets/stylesheets/bootstrap/mixins/_utilities.scss +27 -6
  60. data/assets/stylesheets/bootstrap/mixins/_visually-hidden.scss +1 -1
  61. data/assets/stylesheets/bootstrap/vendor/_rfs.scss +55 -13
  62. data/bootstrap.gemspec +3 -3
  63. data/lib/bootstrap/version.rb +2 -2
  64. data/tasks/updater/js.rb +6 -2
  65. metadata +12 -8
@@ -1,21 +1,27 @@
1
1
  /*!
2
- * Bootstrap modal.js v5.0.1 (https://getbootstrap.com/)
2
+ * Bootstrap modal.js v5.1.2 (https://getbootstrap.com/)
3
3
  * Copyright 2011-2021 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/selector-engine.js'), require('./dom/event-handler.js'), require('./dom/manipulator.js'), require('./base-component.js')) :
8
- typeof define === 'function' && define.amd ? define(['./dom/selector-engine', './dom/event-handler', './dom/manipulator', './base-component'], factory) :
9
- (global = typeof globalThis !== 'undefined' ? globalThis : global || self, global.Modal = factory(global.SelectorEngine, global.EventHandler, global.Manipulator, global.Base));
10
- }(this, (function (SelectorEngine, EventHandler, Manipulator, BaseComponent) { 'use strict';
7
+ typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory(require('./dom/event-handler.js'), require('./dom/manipulator.js'), require('./dom/selector-engine.js'), require('./base-component.js')) :
8
+ typeof define === 'function' && define.amd ? define(['./dom/event-handler', './dom/manipulator', './dom/selector-engine', './base-component'], factory) :
9
+ (global = typeof globalThis !== 'undefined' ? globalThis : global || self, global.Modal = factory(global.EventHandler, global.Manipulator, global.SelectorEngine, global.Base));
10
+ })(this, (function (EventHandler, Manipulator, 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 SelectorEngine__default = /*#__PURE__*/_interopDefaultLegacy(SelectorEngine);
15
- var EventHandler__default = /*#__PURE__*/_interopDefaultLegacy(EventHandler);
16
- var Manipulator__default = /*#__PURE__*/_interopDefaultLegacy(Manipulator);
17
- var BaseComponent__default = /*#__PURE__*/_interopDefaultLegacy(BaseComponent);
14
+ const EventHandler__default = /*#__PURE__*/_interopDefaultLegacy(EventHandler);
15
+ const Manipulator__default = /*#__PURE__*/_interopDefaultLegacy(Manipulator);
16
+ const SelectorEngine__default = /*#__PURE__*/_interopDefaultLegacy(SelectorEngine);
17
+ const BaseComponent__default = /*#__PURE__*/_interopDefaultLegacy(BaseComponent);
18
18
 
19
+ /**
20
+ * --------------------------------------------------------------------------
21
+ * Bootstrap (v5.1.2): util/index.js
22
+ * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
23
+ * --------------------------------------------------------------------------
24
+ */
19
25
  const MILLISECONDS_MULTIPLIER = 1000;
20
26
  const TRANSITION_END = 'transitionend'; // Shoutout AngusCroll (https://goo.gl/pxwQGp)
21
27
 
@@ -95,22 +101,17 @@
95
101
  return typeof obj.nodeType !== 'undefined';
96
102
  };
97
103
 
98
- const emulateTransitionEnd = (element, duration) => {
99
- let called = false;
100
- const durationPadding = 5;
101
- const emulatedDuration = duration + durationPadding;
104
+ const getElement = obj => {
105
+ if (isElement(obj)) {
106
+ // it's a jQuery object or a node element
107
+ return obj.jquery ? obj[0] : obj;
108
+ }
102
109
 
103
- function listener() {
104
- called = true;
105
- element.removeEventListener(TRANSITION_END, listener);
110
+ if (typeof obj === 'string' && obj.length > 0) {
111
+ return document.querySelector(obj);
106
112
  }
107
113
 
108
- element.addEventListener(TRANSITION_END, listener);
109
- setTimeout(() => {
110
- if (!called) {
111
- triggerTransitionEnd(element);
112
- }
113
- }, emulatedDuration);
114
+ return null;
114
115
  };
115
116
 
116
117
  const typeCheckConfig = (componentName, config, configTypes) => {
@@ -126,20 +127,42 @@
126
127
  };
127
128
 
128
129
  const isVisible = element => {
129
- if (!element) {
130
+ if (!isElement(element) || element.getClientRects().length === 0) {
130
131
  return false;
131
132
  }
132
133
 
133
- if (element.style && element.parentNode && element.parentNode.style) {
134
- const elementStyle = getComputedStyle(element);
135
- const parentNodeStyle = getComputedStyle(element.parentNode);
136
- return elementStyle.display !== 'none' && parentNodeStyle.display !== 'none' && elementStyle.visibility !== 'hidden';
134
+ return getComputedStyle(element).getPropertyValue('visibility') === 'visible';
135
+ };
136
+
137
+ const isDisabled = element => {
138
+ if (!element || element.nodeType !== Node.ELEMENT_NODE) {
139
+ return true;
140
+ }
141
+
142
+ if (element.classList.contains('disabled')) {
143
+ return true;
137
144
  }
138
145
 
139
- return false;
146
+ if (typeof element.disabled !== 'undefined') {
147
+ return element.disabled;
148
+ }
149
+
150
+ return element.hasAttribute('disabled') && element.getAttribute('disabled') !== 'false';
140
151
  };
152
+ /**
153
+ * Trick to restart an element's animation
154
+ *
155
+ * @param {HTMLElement} element
156
+ * @return void
157
+ *
158
+ * @see https://www.charistheo.io/blog/2021/02/restart-a-css-animation-with-javascript/#restarting-a-css-animation
159
+ */
160
+
141
161
 
142
- const reflow = element => element.offsetHeight;
162
+ const reflow = element => {
163
+ // eslint-disable-next-line no-unused-expressions
164
+ element.offsetHeight;
165
+ };
143
166
 
144
167
  const getjQuery = () => {
145
168
  const {
@@ -153,9 +176,18 @@
153
176
  return null;
154
177
  };
155
178
 
179
+ const DOMContentLoadedCallbacks = [];
180
+
156
181
  const onDOMContentLoaded = callback => {
157
182
  if (document.readyState === 'loading') {
158
- document.addEventListener('DOMContentLoaded', callback);
183
+ // add listener on the first call when the document is in loading state
184
+ if (!DOMContentLoadedCallbacks.length) {
185
+ document.addEventListener('DOMContentLoaded', () => {
186
+ DOMContentLoadedCallbacks.forEach(callback => callback());
187
+ });
188
+ }
189
+
190
+ DOMContentLoadedCallbacks.push(callback);
159
191
  } else {
160
192
  callback();
161
193
  }
@@ -188,105 +220,166 @@
188
220
  }
189
221
  };
190
222
 
223
+ const executeAfterTransition = (callback, transitionElement, waitForTransition = true) => {
224
+ if (!waitForTransition) {
225
+ execute(callback);
226
+ return;
227
+ }
228
+
229
+ const durationPadding = 5;
230
+ const emulatedDuration = getTransitionDurationFromElement(transitionElement) + durationPadding;
231
+ let called = false;
232
+
233
+ const handler = ({
234
+ target
235
+ }) => {
236
+ if (target !== transitionElement) {
237
+ return;
238
+ }
239
+
240
+ called = true;
241
+ transitionElement.removeEventListener(TRANSITION_END, handler);
242
+ execute(callback);
243
+ };
244
+
245
+ transitionElement.addEventListener(TRANSITION_END, handler);
246
+ setTimeout(() => {
247
+ if (!called) {
248
+ triggerTransitionEnd(transitionElement);
249
+ }
250
+ }, emulatedDuration);
251
+ };
252
+
191
253
  /**
192
254
  * --------------------------------------------------------------------------
193
- * Bootstrap (v5.0.1): util/scrollBar.js
255
+ * Bootstrap (v5.1.2): util/scrollBar.js
194
256
  * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
195
257
  * --------------------------------------------------------------------------
196
258
  */
197
259
  const SELECTOR_FIXED_CONTENT = '.fixed-top, .fixed-bottom, .is-fixed, .sticky-top';
198
260
  const SELECTOR_STICKY_CONTENT = '.sticky-top';
199
261
 
200
- const getWidth = () => {
201
- // https://developer.mozilla.org/en-US/docs/Web/API/Window/innerWidth#usage_notes
202
- const documentWidth = document.documentElement.clientWidth;
203
- return Math.abs(window.innerWidth - documentWidth);
204
- };
262
+ class ScrollBarHelper {
263
+ constructor() {
264
+ this._element = document.body;
265
+ }
205
266
 
206
- const hide = (width = getWidth()) => {
207
- _disableOverFlow(); // give padding to element to balances the hidden scrollbar width
267
+ getWidth() {
268
+ // https://developer.mozilla.org/en-US/docs/Web/API/Window/innerWidth#usage_notes
269
+ const documentWidth = document.documentElement.clientWidth;
270
+ return Math.abs(window.innerWidth - documentWidth);
271
+ }
208
272
 
273
+ hide() {
274
+ const width = this.getWidth();
209
275
 
210
- _setElementAttributes('body', 'paddingRight', calculatedValue => calculatedValue + width); // trick: We adjust positive paddingRight and negative marginRight to sticky-top elements, to keep shown fullwidth
276
+ this._disableOverFlow(); // give padding to element to balance the hidden scrollbar width
211
277
 
212
278
 
213
- _setElementAttributes(SELECTOR_FIXED_CONTENT, 'paddingRight', calculatedValue => calculatedValue + width);
279
+ this._setElementAttributes(this._element, 'paddingRight', calculatedValue => calculatedValue + width); // trick: We adjust positive paddingRight and negative marginRight to sticky-top elements to keep showing fullwidth
214
280
 
215
- _setElementAttributes(SELECTOR_STICKY_CONTENT, 'marginRight', calculatedValue => calculatedValue - width);
216
- };
217
281
 
218
- const _disableOverFlow = () => {
219
- const actualValue = document.body.style.overflow;
282
+ this._setElementAttributes(SELECTOR_FIXED_CONTENT, 'paddingRight', calculatedValue => calculatedValue + width);
220
283
 
221
- if (actualValue) {
222
- Manipulator__default['default'].setDataAttribute(document.body, 'overflow', actualValue);
284
+ this._setElementAttributes(SELECTOR_STICKY_CONTENT, 'marginRight', calculatedValue => calculatedValue - width);
223
285
  }
224
286
 
225
- document.body.style.overflow = 'hidden';
226
- };
287
+ _disableOverFlow() {
288
+ this._saveInitialAttribute(this._element, 'overflow');
227
289
 
228
- const _setElementAttributes = (selector, styleProp, callback) => {
229
- const scrollbarWidth = getWidth();
230
- SelectorEngine__default['default'].find(selector).forEach(element => {
231
- if (element !== document.body && window.innerWidth > element.clientWidth + scrollbarWidth) {
232
- return;
233
- }
290
+ this._element.style.overflow = 'hidden';
291
+ }
234
292
 
235
- const actualValue = element.style[styleProp];
236
- const calculatedValue = window.getComputedStyle(element)[styleProp];
237
- Manipulator__default['default'].setDataAttribute(element, styleProp, actualValue);
238
- element.style[styleProp] = `${callback(Number.parseFloat(calculatedValue))}px`;
239
- });
240
- };
293
+ _setElementAttributes(selector, styleProp, callback) {
294
+ const scrollbarWidth = this.getWidth();
241
295
 
242
- const reset = () => {
243
- _resetElementAttributes('body', 'overflow');
296
+ const manipulationCallBack = element => {
297
+ if (element !== this._element && window.innerWidth > element.clientWidth + scrollbarWidth) {
298
+ return;
299
+ }
300
+
301
+ this._saveInitialAttribute(element, styleProp);
244
302
 
245
- _resetElementAttributes('body', 'paddingRight');
303
+ const calculatedValue = window.getComputedStyle(element)[styleProp];
304
+ element.style[styleProp] = `${callback(Number.parseFloat(calculatedValue))}px`;
305
+ };
246
306
 
247
- _resetElementAttributes(SELECTOR_FIXED_CONTENT, 'paddingRight');
307
+ this._applyManipulationCallback(selector, manipulationCallBack);
308
+ }
248
309
 
249
- _resetElementAttributes(SELECTOR_STICKY_CONTENT, 'marginRight');
250
- };
310
+ reset() {
311
+ this._resetElementAttributes(this._element, 'overflow');
251
312
 
252
- const _resetElementAttributes = (selector, styleProp) => {
253
- SelectorEngine__default['default'].find(selector).forEach(element => {
254
- const value = Manipulator__default['default'].getDataAttribute(element, styleProp);
313
+ this._resetElementAttributes(this._element, 'paddingRight');
314
+
315
+ this._resetElementAttributes(SELECTOR_FIXED_CONTENT, 'paddingRight');
316
+
317
+ this._resetElementAttributes(SELECTOR_STICKY_CONTENT, 'marginRight');
318
+ }
319
+
320
+ _saveInitialAttribute(element, styleProp) {
321
+ const actualValue = element.style[styleProp];
322
+
323
+ if (actualValue) {
324
+ Manipulator__default.default.setDataAttribute(element, styleProp, actualValue);
325
+ }
326
+ }
327
+
328
+ _resetElementAttributes(selector, styleProp) {
329
+ const manipulationCallBack = element => {
330
+ const value = Manipulator__default.default.getDataAttribute(element, styleProp);
331
+
332
+ if (typeof value === 'undefined') {
333
+ element.style.removeProperty(styleProp);
334
+ } else {
335
+ Manipulator__default.default.removeDataAttribute(element, styleProp);
336
+ element.style[styleProp] = value;
337
+ }
338
+ };
255
339
 
256
- if (typeof value === 'undefined') {
257
- element.style.removeProperty(styleProp);
340
+ this._applyManipulationCallback(selector, manipulationCallBack);
341
+ }
342
+
343
+ _applyManipulationCallback(selector, callBack) {
344
+ if (isElement(selector)) {
345
+ callBack(selector);
258
346
  } else {
259
- Manipulator__default['default'].removeDataAttribute(element, styleProp);
260
- element.style[styleProp] = value;
347
+ SelectorEngine__default.default.find(selector, this._element).forEach(callBack);
261
348
  }
262
- });
263
- };
349
+ }
350
+
351
+ isOverflowing() {
352
+ return this.getWidth() > 0;
353
+ }
354
+
355
+ }
264
356
 
265
357
  /**
266
358
  * --------------------------------------------------------------------------
267
- * Bootstrap (v5.0.1): util/backdrop.js
268
- * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
359
+ * Bootstrap (v5.1.2): util/backdrop.js
360
+ * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
269
361
  * --------------------------------------------------------------------------
270
362
  */
271
- const Default$1 = {
363
+ const Default$2 = {
364
+ className: 'modal-backdrop',
272
365
  isVisible: true,
273
366
  // if false, we use the backdrop helper without adding any element to the dom
274
367
  isAnimated: false,
275
- rootElement: document.body,
368
+ rootElement: 'body',
276
369
  // give the choice to place backdrop under different elements
277
370
  clickCallback: null
278
371
  };
279
- const DefaultType$1 = {
372
+ const DefaultType$2 = {
373
+ className: 'string',
280
374
  isVisible: 'boolean',
281
375
  isAnimated: 'boolean',
282
- rootElement: 'element',
376
+ rootElement: '(element|string)',
283
377
  clickCallback: '(function|null)'
284
378
  };
285
- const NAME$1 = 'backdrop';
286
- const CLASS_NAME_BACKDROP = 'modal-backdrop';
379
+ const NAME$2 = 'backdrop';
287
380
  const CLASS_NAME_FADE$1 = 'fade';
288
381
  const CLASS_NAME_SHOW$1 = 'show';
289
- const EVENT_MOUSEDOWN = `mousedown.bs.${NAME$1}`;
382
+ const EVENT_MOUSEDOWN = `mousedown.bs.${NAME$2}`;
290
383
 
291
384
  class Backdrop {
292
385
  constructor(config) {
@@ -332,7 +425,7 @@
332
425
  _getElement() {
333
426
  if (!this._element) {
334
427
  const backdrop = document.createElement('div');
335
- backdrop.className = CLASS_NAME_BACKDROP;
428
+ backdrop.className = this._config.className;
336
429
 
337
430
  if (this._config.isAnimated) {
338
431
  backdrop.classList.add(CLASS_NAME_FADE$1);
@@ -345,11 +438,12 @@
345
438
  }
346
439
 
347
440
  _getConfig(config) {
348
- config = { ...Default$1,
441
+ config = { ...Default$2,
349
442
  ...(typeof config === 'object' ? config : {})
350
- };
351
- config.rootElement = config.rootElement || document.body;
352
- typeCheckConfig(NAME$1, config, DefaultType$1);
443
+ }; // use getElement() with the default "body" to get a fresh Element on each instantiation
444
+
445
+ config.rootElement = getElement(config.rootElement);
446
+ typeCheckConfig(NAME$2, config, DefaultType$2);
353
447
  return config;
354
448
  }
355
449
 
@@ -358,9 +452,9 @@
358
452
  return;
359
453
  }
360
454
 
361
- this._config.rootElement.appendChild(this._getElement());
455
+ this._config.rootElement.append(this._getElement());
362
456
 
363
- EventHandler__default['default'].on(this._getElement(), EVENT_MOUSEDOWN, () => {
457
+ EventHandler__default.default.on(this._getElement(), EVENT_MOUSEDOWN, () => {
364
458
  execute(this._config.clickCallback);
365
459
  });
366
460
  this._isAppended = true;
@@ -371,29 +465,151 @@
371
465
  return;
372
466
  }
373
467
 
374
- EventHandler__default['default'].off(this._element, EVENT_MOUSEDOWN);
468
+ EventHandler__default.default.off(this._element, EVENT_MOUSEDOWN);
375
469
 
376
- this._getElement().parentNode.removeChild(this._element);
470
+ this._element.remove();
377
471
 
378
472
  this._isAppended = false;
379
473
  }
380
474
 
381
475
  _emulateAnimation(callback) {
382
- if (!this._config.isAnimated) {
383
- execute(callback);
476
+ executeAfterTransition(callback, this._getElement(), this._config.isAnimated);
477
+ }
478
+
479
+ }
480
+
481
+ /**
482
+ * --------------------------------------------------------------------------
483
+ * Bootstrap (v5.1.2): util/focustrap.js
484
+ * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
485
+ * --------------------------------------------------------------------------
486
+ */
487
+ const Default$1 = {
488
+ trapElement: null,
489
+ // The element to trap focus inside of
490
+ autofocus: true
491
+ };
492
+ const DefaultType$1 = {
493
+ trapElement: 'element',
494
+ autofocus: 'boolean'
495
+ };
496
+ const NAME$1 = 'focustrap';
497
+ const DATA_KEY$1 = 'bs.focustrap';
498
+ const EVENT_KEY$1 = `.${DATA_KEY$1}`;
499
+ const EVENT_FOCUSIN = `focusin${EVENT_KEY$1}`;
500
+ const EVENT_KEYDOWN_TAB = `keydown.tab${EVENT_KEY$1}`;
501
+ const TAB_KEY = 'Tab';
502
+ const TAB_NAV_FORWARD = 'forward';
503
+ const TAB_NAV_BACKWARD = 'backward';
504
+
505
+ class FocusTrap {
506
+ constructor(config) {
507
+ this._config = this._getConfig(config);
508
+ this._isActive = false;
509
+ this._lastTabNavDirection = null;
510
+ }
511
+
512
+ activate() {
513
+ const {
514
+ trapElement,
515
+ autofocus
516
+ } = this._config;
517
+
518
+ if (this._isActive) {
384
519
  return;
385
520
  }
386
521
 
387
- const backdropTransitionDuration = getTransitionDurationFromElement(this._getElement());
388
- EventHandler__default['default'].one(this._getElement(), 'transitionend', () => execute(callback));
389
- emulateTransitionEnd(this._getElement(), backdropTransitionDuration);
522
+ if (autofocus) {
523
+ trapElement.focus();
524
+ }
525
+
526
+ EventHandler__default.default.off(document, EVENT_KEY$1); // guard against infinite focus loop
527
+
528
+ EventHandler__default.default.on(document, EVENT_FOCUSIN, event => this._handleFocusin(event));
529
+ EventHandler__default.default.on(document, EVENT_KEYDOWN_TAB, event => this._handleKeydown(event));
530
+ this._isActive = true;
531
+ }
532
+
533
+ deactivate() {
534
+ if (!this._isActive) {
535
+ return;
536
+ }
537
+
538
+ this._isActive = false;
539
+ EventHandler__default.default.off(document, EVENT_KEY$1);
540
+ } // Private
541
+
542
+
543
+ _handleFocusin(event) {
544
+ const {
545
+ target
546
+ } = event;
547
+ const {
548
+ trapElement
549
+ } = this._config;
550
+
551
+ if (target === document || target === trapElement || trapElement.contains(target)) {
552
+ return;
553
+ }
554
+
555
+ const elements = SelectorEngine__default.default.focusableChildren(trapElement);
556
+
557
+ if (elements.length === 0) {
558
+ trapElement.focus();
559
+ } else if (this._lastTabNavDirection === TAB_NAV_BACKWARD) {
560
+ elements[elements.length - 1].focus();
561
+ } else {
562
+ elements[0].focus();
563
+ }
564
+ }
565
+
566
+ _handleKeydown(event) {
567
+ if (event.key !== TAB_KEY) {
568
+ return;
569
+ }
570
+
571
+ this._lastTabNavDirection = event.shiftKey ? TAB_NAV_BACKWARD : TAB_NAV_FORWARD;
572
+ }
573
+
574
+ _getConfig(config) {
575
+ config = { ...Default$1,
576
+ ...(typeof config === 'object' ? config : {})
577
+ };
578
+ typeCheckConfig(NAME$1, config, DefaultType$1);
579
+ return config;
390
580
  }
391
581
 
392
582
  }
393
583
 
394
584
  /**
395
585
  * --------------------------------------------------------------------------
396
- * Bootstrap (v5.0.1): modal.js
586
+ * Bootstrap (v5.1.2): util/component-functions.js
587
+ * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
588
+ * --------------------------------------------------------------------------
589
+ */
590
+
591
+ const enableDismissTrigger = (component, method = 'hide') => {
592
+ const clickEvent = `click.dismiss${component.EVENT_KEY}`;
593
+ const name = component.NAME;
594
+ EventHandler__default.default.on(document, clickEvent, `[data-bs-dismiss="${name}"]`, function (event) {
595
+ if (['A', 'AREA'].includes(this.tagName)) {
596
+ event.preventDefault();
597
+ }
598
+
599
+ if (isDisabled(this)) {
600
+ return;
601
+ }
602
+
603
+ const target = getElementFromSelector(this) || this.closest(`.${name}`);
604
+ const instance = component.getOrCreateInstance(target); // Method argument is left, for Alert and only, as it doesn't implement the 'hide' method
605
+
606
+ instance[method]();
607
+ });
608
+ };
609
+
610
+ /**
611
+ * --------------------------------------------------------------------------
612
+ * Bootstrap (v5.1.2): modal.js
397
613
  * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
398
614
  * --------------------------------------------------------------------------
399
615
  */
@@ -423,7 +639,6 @@
423
639
  const EVENT_HIDDEN = `hidden${EVENT_KEY}`;
424
640
  const EVENT_SHOW = `show${EVENT_KEY}`;
425
641
  const EVENT_SHOWN = `shown${EVENT_KEY}`;
426
- const EVENT_FOCUSIN = `focusin${EVENT_KEY}`;
427
642
  const EVENT_RESIZE = `resize${EVENT_KEY}`;
428
643
  const EVENT_CLICK_DISMISS = `click.dismiss${EVENT_KEY}`;
429
644
  const EVENT_KEYDOWN_DISMISS = `keydown.dismiss${EVENT_KEY}`;
@@ -434,25 +649,27 @@
434
649
  const CLASS_NAME_FADE = 'fade';
435
650
  const CLASS_NAME_SHOW = 'show';
436
651
  const CLASS_NAME_STATIC = 'modal-static';
652
+ const OPEN_SELECTOR = '.modal.show';
437
653
  const SELECTOR_DIALOG = '.modal-dialog';
438
654
  const SELECTOR_MODAL_BODY = '.modal-body';
439
655
  const SELECTOR_DATA_TOGGLE = '[data-bs-toggle="modal"]';
440
- const SELECTOR_DATA_DISMISS = '[data-bs-dismiss="modal"]';
441
656
  /**
442
657
  * ------------------------------------------------------------------------
443
658
  * Class Definition
444
659
  * ------------------------------------------------------------------------
445
660
  */
446
661
 
447
- class Modal extends BaseComponent__default['default'] {
662
+ class Modal extends BaseComponent__default.default {
448
663
  constructor(element, config) {
449
664
  super(element);
450
665
  this._config = this._getConfig(config);
451
- this._dialog = SelectorEngine__default['default'].findOne(SELECTOR_DIALOG, this._element);
666
+ this._dialog = SelectorEngine__default.default.findOne(SELECTOR_DIALOG, this._element);
452
667
  this._backdrop = this._initializeBackDrop();
668
+ this._focustrap = this._initializeFocusTrap();
453
669
  this._isShown = false;
454
670
  this._ignoreBackdropClick = false;
455
671
  this._isTransitioning = false;
672
+ this._scrollBar = new ScrollBarHelper();
456
673
  } // Getters
457
674
 
458
675
 
@@ -474,20 +691,22 @@
474
691
  return;
475
692
  }
476
693
 
477
- if (this._isAnimated()) {
478
- this._isTransitioning = true;
479
- }
480
-
481
- const showEvent = EventHandler__default['default'].trigger(this._element, EVENT_SHOW, {
694
+ const showEvent = EventHandler__default.default.trigger(this._element, EVENT_SHOW, {
482
695
  relatedTarget
483
696
  });
484
697
 
485
- if (this._isShown || showEvent.defaultPrevented) {
698
+ if (showEvent.defaultPrevented) {
486
699
  return;
487
700
  }
488
701
 
489
702
  this._isShown = true;
490
- hide();
703
+
704
+ if (this._isAnimated()) {
705
+ this._isTransitioning = true;
706
+ }
707
+
708
+ this._scrollBar.hide();
709
+
491
710
  document.body.classList.add(CLASS_NAME_OPEN);
492
711
 
493
712
  this._adjustDialog();
@@ -496,9 +715,8 @@
496
715
 
497
716
  this._setResizeEvent();
498
717
 
499
- EventHandler__default['default'].on(this._element, EVENT_CLICK_DISMISS, SELECTOR_DATA_DISMISS, event => this.hide(event));
500
- EventHandler__default['default'].on(this._dialog, EVENT_MOUSEDOWN_DISMISS, () => {
501
- EventHandler__default['default'].one(this._element, EVENT_MOUSEUP_DISMISS, event => {
718
+ EventHandler__default.default.on(this._dialog, EVENT_MOUSEDOWN_DISMISS, () => {
719
+ EventHandler__default.default.one(this._element, EVENT_MOUSEUP_DISMISS, event => {
502
720
  if (event.target === this._element) {
503
721
  this._ignoreBackdropClick = true;
504
722
  }
@@ -508,16 +726,12 @@
508
726
  this._showBackdrop(() => this._showElement(relatedTarget));
509
727
  }
510
728
 
511
- hide(event) {
512
- if (event) {
513
- event.preventDefault();
514
- }
515
-
729
+ hide() {
516
730
  if (!this._isShown || this._isTransitioning) {
517
731
  return;
518
732
  }
519
733
 
520
- const hideEvent = EventHandler__default['default'].trigger(this._element, EVENT_HIDE);
734
+ const hideEvent = EventHandler__default.default.trigger(this._element, EVENT_HIDE);
521
735
 
522
736
  if (hideEvent.defaultPrevented) {
523
737
  return;
@@ -535,29 +749,24 @@
535
749
 
536
750
  this._setResizeEvent();
537
751
 
538
- EventHandler__default['default'].off(document, EVENT_FOCUSIN);
752
+ this._focustrap.deactivate();
539
753
 
540
754
  this._element.classList.remove(CLASS_NAME_SHOW);
541
755
 
542
- EventHandler__default['default'].off(this._element, EVENT_CLICK_DISMISS);
543
- EventHandler__default['default'].off(this._dialog, EVENT_MOUSEDOWN_DISMISS);
756
+ EventHandler__default.default.off(this._element, EVENT_CLICK_DISMISS);
757
+ EventHandler__default.default.off(this._dialog, EVENT_MOUSEDOWN_DISMISS);
544
758
 
545
759
  this._queueCallback(() => this._hideModal(), this._element, isAnimated);
546
760
  }
547
761
 
548
762
  dispose() {
549
- [window, this._dialog].forEach(htmlElement => EventHandler__default['default'].off(htmlElement, EVENT_KEY));
763
+ [window, this._dialog].forEach(htmlElement => EventHandler__default.default.off(htmlElement, EVENT_KEY));
550
764
 
551
765
  this._backdrop.dispose();
552
766
 
553
- super.dispose();
554
- /**
555
- * `document` has 2 events `EVENT_FOCUSIN` and `EVENT_CLICK_DATA_API`
556
- * Do not move `document` in `htmlElements` array
557
- * It will remove `EVENT_CLICK_DATA_API` event that should remain
558
- */
767
+ this._focustrap.deactivate();
559
768
 
560
- EventHandler__default['default'].off(document, EVENT_FOCUSIN);
769
+ super.dispose();
561
770
  }
562
771
 
563
772
  handleUpdate() {
@@ -573,10 +782,16 @@
573
782
  });
574
783
  }
575
784
 
785
+ _initializeFocusTrap() {
786
+ return new FocusTrap({
787
+ trapElement: this._element
788
+ });
789
+ }
790
+
576
791
  _getConfig(config) {
577
792
  config = { ...Default,
578
- ...Manipulator__default['default'].getDataAttributes(this._element),
579
- ...config
793
+ ...Manipulator__default.default.getDataAttributes(this._element),
794
+ ...(typeof config === 'object' ? config : {})
580
795
  };
581
796
  typeCheckConfig(NAME, config, DefaultType);
582
797
  return config;
@@ -585,11 +800,11 @@
585
800
  _showElement(relatedTarget) {
586
801
  const isAnimated = this._isAnimated();
587
802
 
588
- const modalBody = SelectorEngine__default['default'].findOne(SELECTOR_MODAL_BODY, this._dialog);
803
+ const modalBody = SelectorEngine__default.default.findOne(SELECTOR_MODAL_BODY, this._dialog);
589
804
 
590
805
  if (!this._element.parentNode || this._element.parentNode.nodeType !== Node.ELEMENT_NODE) {
591
806
  // Don't move modal's DOM position
592
- document.body.appendChild(this._element);
807
+ document.body.append(this._element);
593
808
  }
594
809
 
595
810
  this._element.style.display = 'block';
@@ -612,17 +827,13 @@
612
827
 
613
828
  this._element.classList.add(CLASS_NAME_SHOW);
614
829
 
615
- if (this._config.focus) {
616
- this._enforceFocus();
617
- }
618
-
619
830
  const transitionComplete = () => {
620
831
  if (this._config.focus) {
621
- this._element.focus();
832
+ this._focustrap.activate();
622
833
  }
623
834
 
624
835
  this._isTransitioning = false;
625
- EventHandler__default['default'].trigger(this._element, EVENT_SHOWN, {
836
+ EventHandler__default.default.trigger(this._element, EVENT_SHOWN, {
626
837
  relatedTarget
627
838
  });
628
839
  };
@@ -630,19 +841,9 @@
630
841
  this._queueCallback(transitionComplete, this._dialog, isAnimated);
631
842
  }
632
843
 
633
- _enforceFocus() {
634
- EventHandler__default['default'].off(document, EVENT_FOCUSIN); // guard against infinite focus loop
635
-
636
- EventHandler__default['default'].on(document, EVENT_FOCUSIN, event => {
637
- if (document !== event.target && this._element !== event.target && !this._element.contains(event.target)) {
638
- this._element.focus();
639
- }
640
- });
641
- }
642
-
643
844
  _setEscapeEvent() {
644
845
  if (this._isShown) {
645
- EventHandler__default['default'].on(this._element, EVENT_KEYDOWN_DISMISS, event => {
846
+ EventHandler__default.default.on(this._element, EVENT_KEYDOWN_DISMISS, event => {
646
847
  if (this._config.keyboard && event.key === ESCAPE_KEY) {
647
848
  event.preventDefault();
648
849
  this.hide();
@@ -651,15 +852,15 @@
651
852
  }
652
853
  });
653
854
  } else {
654
- EventHandler__default['default'].off(this._element, EVENT_KEYDOWN_DISMISS);
855
+ EventHandler__default.default.off(this._element, EVENT_KEYDOWN_DISMISS);
655
856
  }
656
857
  }
657
858
 
658
859
  _setResizeEvent() {
659
860
  if (this._isShown) {
660
- EventHandler__default['default'].on(window, EVENT_RESIZE, () => this._adjustDialog());
861
+ EventHandler__default.default.on(window, EVENT_RESIZE, () => this._adjustDialog());
661
862
  } else {
662
- EventHandler__default['default'].off(window, EVENT_RESIZE);
863
+ EventHandler__default.default.off(window, EVENT_RESIZE);
663
864
  }
664
865
  }
665
866
 
@@ -679,13 +880,14 @@
679
880
 
680
881
  this._resetAdjustments();
681
882
 
682
- reset();
683
- EventHandler__default['default'].trigger(this._element, EVENT_HIDDEN);
883
+ this._scrollBar.reset();
884
+
885
+ EventHandler__default.default.trigger(this._element, EVENT_HIDDEN);
684
886
  });
685
887
  }
686
888
 
687
889
  _showBackdrop(callback) {
688
- EventHandler__default['default'].on(this._element, EVENT_CLICK_DISMISS, event => {
890
+ EventHandler__default.default.on(this._element, EVENT_CLICK_DISMISS, event => {
689
891
  if (this._ignoreBackdropClick) {
690
892
  this._ignoreBackdropClick = false;
691
893
  return;
@@ -710,33 +912,38 @@
710
912
  }
711
913
 
712
914
  _triggerBackdropTransition() {
713
- const hideEvent = EventHandler__default['default'].trigger(this._element, EVENT_HIDE_PREVENTED);
915
+ const hideEvent = EventHandler__default.default.trigger(this._element, EVENT_HIDE_PREVENTED);
714
916
 
715
917
  if (hideEvent.defaultPrevented) {
716
918
  return;
717
919
  }
718
920
 
719
- const isModalOverflowing = this._element.scrollHeight > document.documentElement.clientHeight;
921
+ const {
922
+ classList,
923
+ scrollHeight,
924
+ style
925
+ } = this._element;
926
+ const isModalOverflowing = scrollHeight > document.documentElement.clientHeight; // return if the following background transition hasn't yet completed
927
+
928
+ if (!isModalOverflowing && style.overflowY === 'hidden' || classList.contains(CLASS_NAME_STATIC)) {
929
+ return;
930
+ }
720
931
 
721
932
  if (!isModalOverflowing) {
722
- this._element.style.overflowY = 'hidden';
933
+ style.overflowY = 'hidden';
723
934
  }
724
935
 
725
- this._element.classList.add(CLASS_NAME_STATIC);
936
+ classList.add(CLASS_NAME_STATIC);
726
937
 
727
- const modalTransitionDuration = getTransitionDurationFromElement(this._dialog);
728
- EventHandler__default['default'].off(this._element, 'transitionend');
729
- EventHandler__default['default'].one(this._element, 'transitionend', () => {
730
- this._element.classList.remove(CLASS_NAME_STATIC);
938
+ this._queueCallback(() => {
939
+ classList.remove(CLASS_NAME_STATIC);
731
940
 
732
941
  if (!isModalOverflowing) {
733
- EventHandler__default['default'].one(this._element, 'transitionend', () => {
734
- this._element.style.overflowY = '';
735
- });
736
- emulateTransitionEnd(this._element, modalTransitionDuration);
942
+ this._queueCallback(() => {
943
+ style.overflowY = '';
944
+ }, this._dialog);
737
945
  }
738
- });
739
- emulateTransitionEnd(this._element, modalTransitionDuration);
946
+ }, this._dialog);
740
947
 
741
948
  this._element.focus();
742
949
  } // ----------------------------------------------------------------------
@@ -746,7 +953,9 @@
746
953
 
747
954
  _adjustDialog() {
748
955
  const isModalOverflowing = this._element.scrollHeight > document.documentElement.clientHeight;
749
- const scrollbarWidth = getWidth();
956
+
957
+ const scrollbarWidth = this._scrollBar.getWidth();
958
+
750
959
  const isBodyOverflowing = scrollbarWidth > 0;
751
960
 
752
961
  if (!isBodyOverflowing && isModalOverflowing && !isRTL() || isBodyOverflowing && !isModalOverflowing && isRTL()) {
@@ -766,7 +975,7 @@
766
975
 
767
976
  static jQueryInterface(config, relatedTarget) {
768
977
  return this.each(function () {
769
- const data = Modal.getInstance(this) || new Modal(this, typeof config === 'object' ? config : {});
978
+ const data = Modal.getOrCreateInstance(this, config);
770
979
 
771
980
  if (typeof config !== 'string') {
772
981
  return;
@@ -788,28 +997,36 @@
788
997
  */
789
998
 
790
999
 
791
- EventHandler__default['default'].on(document, EVENT_CLICK_DATA_API, SELECTOR_DATA_TOGGLE, function (event) {
1000
+ EventHandler__default.default.on(document, EVENT_CLICK_DATA_API, SELECTOR_DATA_TOGGLE, function (event) {
792
1001
  const target = getElementFromSelector(this);
793
1002
 
794
1003
  if (['A', 'AREA'].includes(this.tagName)) {
795
1004
  event.preventDefault();
796
1005
  }
797
1006
 
798
- EventHandler__default['default'].one(target, EVENT_SHOW, showEvent => {
1007
+ EventHandler__default.default.one(target, EVENT_SHOW, showEvent => {
799
1008
  if (showEvent.defaultPrevented) {
800
1009
  // only register focus restorer if modal will actually get shown
801
1010
  return;
802
1011
  }
803
1012
 
804
- EventHandler__default['default'].one(target, EVENT_HIDDEN, () => {
1013
+ EventHandler__default.default.one(target, EVENT_HIDDEN, () => {
805
1014
  if (isVisible(this)) {
806
1015
  this.focus();
807
1016
  }
808
1017
  });
809
- });
810
- const data = Modal.getInstance(target) || new Modal(target);
1018
+ }); // avoid conflict when clicking moddal toggler while another one is open
1019
+
1020
+ const allReadyOpen = SelectorEngine__default.default.findOne(OPEN_SELECTOR);
1021
+
1022
+ if (allReadyOpen) {
1023
+ Modal.getInstance(allReadyOpen).hide();
1024
+ }
1025
+
1026
+ const data = Modal.getOrCreateInstance(target);
811
1027
  data.toggle(this);
812
1028
  });
1029
+ enableDismissTrigger(Modal);
813
1030
  /**
814
1031
  * ------------------------------------------------------------------------
815
1032
  * jQuery
@@ -821,4 +1038,4 @@
821
1038
 
822
1039
  return Modal;
823
1040
 
824
- })));
1041
+ }));