bootstrap 5.0.1 → 5.1.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 (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
+ }));