bootstrap 5.0.0 → 5.1.1

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 +77 -106
  4. data/assets/javascripts/bootstrap/base-component.js +126 -7
  5. data/assets/javascripts/bootstrap/button.js +24 -24
  6. data/assets/javascripts/bootstrap/carousel.js +115 -128
  7. data/assets/javascripts/bootstrap/collapse.js +119 -176
  8. data/assets/javascripts/bootstrap/dom/data.js +2 -2
  9. data/assets/javascripts/bootstrap/dom/event-handler.js +3 -4
  10. data/assets/javascripts/bootstrap/dom/manipulator.js +4 -4
  11. data/assets/javascripts/bootstrap/dom/selector-engine.js +47 -5
  12. data/assets/javascripts/bootstrap/dropdown.js +142 -130
  13. data/assets/javascripts/bootstrap/modal.js +376 -171
  14. data/assets/javascripts/bootstrap/offcanvas.js +328 -133
  15. data/assets/javascripts/bootstrap/popover.js +27 -59
  16. data/assets/javascripts/bootstrap/scrollspy.js +51 -56
  17. data/assets/javascripts/bootstrap/tab.js +39 -66
  18. data/assets/javascripts/bootstrap/toast.js +175 -86
  19. data/assets/javascripts/bootstrap/tooltip.js +141 -185
  20. data/assets/javascripts/bootstrap-sprockets.js +6 -6
  21. data/assets/javascripts/bootstrap.js +1031 -1026
  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/_card.scss +7 -6
  27. data/assets/stylesheets/bootstrap/_carousel.scss +2 -2
  28. data/assets/stylesheets/bootstrap/_dropdown.scss +4 -4
  29. data/assets/stylesheets/bootstrap/_functions.scss +100 -3
  30. data/assets/stylesheets/bootstrap/_grid.scss +11 -0
  31. data/assets/stylesheets/bootstrap/_helpers.scss +2 -0
  32. data/assets/stylesheets/bootstrap/_images.scss +1 -1
  33. data/assets/stylesheets/bootstrap/_list-group.scss +5 -5
  34. data/assets/stylesheets/bootstrap/_mixins.scss +1 -0
  35. data/assets/stylesheets/bootstrap/_modal.scss +7 -26
  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 +1 -0
  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 +200 -25
  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 +6 -6
  52. data/assets/stylesheets/bootstrap/forms/_form-range.scss +1 -1
  53. data/assets/stylesheets/bootstrap/forms/_form-select.scss +3 -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/_forms.scss +8 -1
  59. data/assets/stylesheets/bootstrap/mixins/_grid.scss +33 -8
  60. data/assets/stylesheets/bootstrap/mixins/_utilities.scss +27 -6
  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,25 +1,24 @@
1
1
  /*!
2
- * Bootstrap offcanvas.js v5.0.0 (https://getbootstrap.com/)
2
+ * Bootstrap offcanvas.js v5.1.1 (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/manipulator.js'), require('./dom/data.js'), require('./dom/event-handler.js'), require('./base-component.js')) :
8
- typeof define === 'function' && define.amd ? define(['./dom/selector-engine', './dom/manipulator', './dom/data', './dom/event-handler', './base-component'], factory) :
9
- (global = typeof globalThis !== 'undefined' ? globalThis : global || self, global.Offcanvas = factory(global.SelectorEngine, global.Manipulator, global.Data, global.EventHandler, global.Base));
10
- }(this, (function (SelectorEngine, Manipulator, Data, EventHandler, BaseComponent) { 'use strict';
7
+ typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory(require('./dom/selector-engine.js'), require('./dom/manipulator.js'), require('./dom/event-handler.js'), require('./base-component.js')) :
8
+ typeof define === 'function' && define.amd ? define(['./dom/selector-engine', './dom/manipulator', './dom/event-handler', './base-component'], factory) :
9
+ (global = typeof globalThis !== 'undefined' ? globalThis : global || self, global.Offcanvas = factory(global.SelectorEngine, global.Manipulator, global.EventHandler, global.Base));
10
+ }(this, (function (SelectorEngine, Manipulator, EventHandler, BaseComponent) { 'use strict';
11
11
 
12
12
  function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
13
13
 
14
14
  var SelectorEngine__default = /*#__PURE__*/_interopDefaultLegacy(SelectorEngine);
15
15
  var Manipulator__default = /*#__PURE__*/_interopDefaultLegacy(Manipulator);
16
- var Data__default = /*#__PURE__*/_interopDefaultLegacy(Data);
17
16
  var EventHandler__default = /*#__PURE__*/_interopDefaultLegacy(EventHandler);
18
17
  var BaseComponent__default = /*#__PURE__*/_interopDefaultLegacy(BaseComponent);
19
18
 
20
19
  /**
21
20
  * --------------------------------------------------------------------------
22
- * Bootstrap (v5.0.0): util/index.js
21
+ * Bootstrap (v5.1.1): util/index.js
23
22
  * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
24
23
  * --------------------------------------------------------------------------
25
24
  */
@@ -90,24 +89,29 @@
90
89
  element.dispatchEvent(new Event(TRANSITION_END));
91
90
  };
92
91
 
93
- const isElement = obj => (obj[0] || obj).nodeType;
92
+ const isElement = obj => {
93
+ if (!obj || typeof obj !== 'object') {
94
+ return false;
95
+ }
94
96
 
95
- const emulateTransitionEnd = (element, duration) => {
96
- let called = false;
97
- const durationPadding = 5;
98
- const emulatedDuration = duration + durationPadding;
97
+ if (typeof obj.jquery !== 'undefined') {
98
+ obj = obj[0];
99
+ }
99
100
 
100
- function listener() {
101
- called = true;
102
- element.removeEventListener(TRANSITION_END, listener);
101
+ return typeof obj.nodeType !== 'undefined';
102
+ };
103
+
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;
103
108
  }
104
109
 
105
- element.addEventListener(TRANSITION_END, listener);
106
- setTimeout(() => {
107
- if (!called) {
108
- triggerTransitionEnd(element);
109
- }
110
- }, emulatedDuration);
110
+ if (typeof obj === 'string' && obj.length > 0) {
111
+ return document.querySelector(obj);
112
+ }
113
+
114
+ return null;
111
115
  };
112
116
 
113
117
  const typeCheckConfig = (componentName, config, configTypes) => {
@@ -123,17 +127,11 @@
123
127
  };
124
128
 
125
129
  const isVisible = element => {
126
- if (!element) {
130
+ if (!isElement(element) || element.getClientRects().length === 0) {
127
131
  return false;
128
132
  }
129
133
 
130
- if (element.style && element.parentNode && element.parentNode.style) {
131
- const elementStyle = getComputedStyle(element);
132
- const parentNodeStyle = getComputedStyle(element.parentNode);
133
- return elementStyle.display !== 'none' && parentNodeStyle.display !== 'none' && elementStyle.visibility !== 'hidden';
134
- }
135
-
136
- return false;
134
+ return getComputedStyle(element).getPropertyValue('visibility') === 'visible';
137
135
  };
138
136
 
139
137
  const isDisabled = element => {
@@ -151,8 +149,20 @@
151
149
 
152
150
  return element.hasAttribute('disabled') && element.getAttribute('disabled') !== 'false';
153
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
+
154
161
 
155
- const reflow = element => element.offsetHeight;
162
+ const reflow = element => {
163
+ // eslint-disable-next-line no-unused-expressions
164
+ element.offsetHeight;
165
+ };
156
166
 
157
167
  const getjQuery = () => {
158
168
  const {
@@ -166,20 +176,30 @@
166
176
  return null;
167
177
  };
168
178
 
179
+ const DOMContentLoadedCallbacks = [];
180
+
169
181
  const onDOMContentLoaded = callback => {
170
182
  if (document.readyState === 'loading') {
171
- 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);
172
191
  } else {
173
192
  callback();
174
193
  }
175
194
  };
176
195
 
177
- const defineJQueryPlugin = (name, plugin) => {
196
+ const defineJQueryPlugin = plugin => {
178
197
  onDOMContentLoaded(() => {
179
198
  const $ = getjQuery();
180
199
  /* istanbul ignore if */
181
200
 
182
201
  if ($) {
202
+ const name = plugin.NAME;
183
203
  const JQUERY_NO_CONFLICT = $.fn[name];
184
204
  $.fn[name] = plugin.jQueryInterface;
185
205
  $.fn[name].Constructor = plugin;
@@ -198,105 +218,166 @@
198
218
  }
199
219
  };
200
220
 
221
+ const executeAfterTransition = (callback, transitionElement, waitForTransition = true) => {
222
+ if (!waitForTransition) {
223
+ execute(callback);
224
+ return;
225
+ }
226
+
227
+ const durationPadding = 5;
228
+ const emulatedDuration = getTransitionDurationFromElement(transitionElement) + durationPadding;
229
+ let called = false;
230
+
231
+ const handler = ({
232
+ target
233
+ }) => {
234
+ if (target !== transitionElement) {
235
+ return;
236
+ }
237
+
238
+ called = true;
239
+ transitionElement.removeEventListener(TRANSITION_END, handler);
240
+ execute(callback);
241
+ };
242
+
243
+ transitionElement.addEventListener(TRANSITION_END, handler);
244
+ setTimeout(() => {
245
+ if (!called) {
246
+ triggerTransitionEnd(transitionElement);
247
+ }
248
+ }, emulatedDuration);
249
+ };
250
+
201
251
  /**
202
252
  * --------------------------------------------------------------------------
203
- * Bootstrap (v5.0.0): util/scrollBar.js
253
+ * Bootstrap (v5.1.1): util/scrollBar.js
204
254
  * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
205
255
  * --------------------------------------------------------------------------
206
256
  */
207
257
  const SELECTOR_FIXED_CONTENT = '.fixed-top, .fixed-bottom, .is-fixed, .sticky-top';
208
258
  const SELECTOR_STICKY_CONTENT = '.sticky-top';
209
259
 
210
- const getWidth = () => {
211
- // https://developer.mozilla.org/en-US/docs/Web/API/Window/innerWidth#usage_notes
212
- const documentWidth = document.documentElement.clientWidth;
213
- return Math.abs(window.innerWidth - documentWidth);
214
- };
260
+ class ScrollBarHelper {
261
+ constructor() {
262
+ this._element = document.body;
263
+ }
215
264
 
216
- const hide = (width = getWidth()) => {
217
- _disableOverFlow(); // give padding to element to balances the hidden scrollbar width
265
+ getWidth() {
266
+ // https://developer.mozilla.org/en-US/docs/Web/API/Window/innerWidth#usage_notes
267
+ const documentWidth = document.documentElement.clientWidth;
268
+ return Math.abs(window.innerWidth - documentWidth);
269
+ }
218
270
 
271
+ hide() {
272
+ const width = this.getWidth();
219
273
 
220
- _setElementAttributes('body', 'paddingRight', calculatedValue => calculatedValue + width); // trick: We adjust positive paddingRight and negative marginRight to sticky-top elements, to keep shown fullwidth
274
+ this._disableOverFlow(); // give padding to element to balance the hidden scrollbar width
221
275
 
222
276
 
223
- _setElementAttributes(SELECTOR_FIXED_CONTENT, 'paddingRight', calculatedValue => calculatedValue + width);
277
+ this._setElementAttributes(this._element, 'paddingRight', calculatedValue => calculatedValue + width); // trick: We adjust positive paddingRight and negative marginRight to sticky-top elements to keep showing fullwidth
224
278
 
225
- _setElementAttributes(SELECTOR_STICKY_CONTENT, 'marginRight', calculatedValue => calculatedValue - width);
226
- };
227
279
 
228
- const _disableOverFlow = () => {
229
- const actualValue = document.body.style.overflow;
280
+ this._setElementAttributes(SELECTOR_FIXED_CONTENT, 'paddingRight', calculatedValue => calculatedValue + width);
230
281
 
231
- if (actualValue) {
232
- Manipulator__default['default'].setDataAttribute(document.body, 'overflow', actualValue);
282
+ this._setElementAttributes(SELECTOR_STICKY_CONTENT, 'marginRight', calculatedValue => calculatedValue - width);
233
283
  }
234
284
 
235
- document.body.style.overflow = 'hidden';
236
- };
285
+ _disableOverFlow() {
286
+ this._saveInitialAttribute(this._element, 'overflow');
237
287
 
238
- const _setElementAttributes = (selector, styleProp, callback) => {
239
- const scrollbarWidth = getWidth();
240
- SelectorEngine__default['default'].find(selector).forEach(element => {
241
- if (element !== document.body && window.innerWidth > element.clientWidth + scrollbarWidth) {
242
- return;
243
- }
288
+ this._element.style.overflow = 'hidden';
289
+ }
244
290
 
245
- const actualValue = element.style[styleProp];
246
- const calculatedValue = window.getComputedStyle(element)[styleProp];
247
- Manipulator__default['default'].setDataAttribute(element, styleProp, actualValue);
248
- element.style[styleProp] = `${callback(Number.parseFloat(calculatedValue))}px`;
249
- });
250
- };
291
+ _setElementAttributes(selector, styleProp, callback) {
292
+ const scrollbarWidth = this.getWidth();
293
+
294
+ const manipulationCallBack = element => {
295
+ if (element !== this._element && window.innerWidth > element.clientWidth + scrollbarWidth) {
296
+ return;
297
+ }
251
298
 
252
- const reset = () => {
253
- _resetElementAttributes('body', 'overflow');
299
+ this._saveInitialAttribute(element, styleProp);
254
300
 
255
- _resetElementAttributes('body', 'paddingRight');
301
+ const calculatedValue = window.getComputedStyle(element)[styleProp];
302
+ element.style[styleProp] = `${callback(Number.parseFloat(calculatedValue))}px`;
303
+ };
256
304
 
257
- _resetElementAttributes(SELECTOR_FIXED_CONTENT, 'paddingRight');
305
+ this._applyManipulationCallback(selector, manipulationCallBack);
306
+ }
258
307
 
259
- _resetElementAttributes(SELECTOR_STICKY_CONTENT, 'marginRight');
260
- };
308
+ reset() {
309
+ this._resetElementAttributes(this._element, 'overflow');
261
310
 
262
- const _resetElementAttributes = (selector, styleProp) => {
263
- SelectorEngine__default['default'].find(selector).forEach(element => {
264
- const value = Manipulator__default['default'].getDataAttribute(element, styleProp);
311
+ this._resetElementAttributes(this._element, 'paddingRight');
265
312
 
266
- if (typeof value === 'undefined') {
267
- element.style.removeProperty(styleProp);
313
+ this._resetElementAttributes(SELECTOR_FIXED_CONTENT, 'paddingRight');
314
+
315
+ this._resetElementAttributes(SELECTOR_STICKY_CONTENT, 'marginRight');
316
+ }
317
+
318
+ _saveInitialAttribute(element, styleProp) {
319
+ const actualValue = element.style[styleProp];
320
+
321
+ if (actualValue) {
322
+ Manipulator__default['default'].setDataAttribute(element, styleProp, actualValue);
323
+ }
324
+ }
325
+
326
+ _resetElementAttributes(selector, styleProp) {
327
+ const manipulationCallBack = element => {
328
+ const value = Manipulator__default['default'].getDataAttribute(element, styleProp);
329
+
330
+ if (typeof value === 'undefined') {
331
+ element.style.removeProperty(styleProp);
332
+ } else {
333
+ Manipulator__default['default'].removeDataAttribute(element, styleProp);
334
+ element.style[styleProp] = value;
335
+ }
336
+ };
337
+
338
+ this._applyManipulationCallback(selector, manipulationCallBack);
339
+ }
340
+
341
+ _applyManipulationCallback(selector, callBack) {
342
+ if (isElement(selector)) {
343
+ callBack(selector);
268
344
  } else {
269
- Manipulator__default['default'].removeDataAttribute(element, styleProp);
270
- element.style[styleProp] = value;
345
+ SelectorEngine__default['default'].find(selector, this._element).forEach(callBack);
271
346
  }
272
- });
273
- };
347
+ }
348
+
349
+ isOverflowing() {
350
+ return this.getWidth() > 0;
351
+ }
352
+
353
+ }
274
354
 
275
355
  /**
276
356
  * --------------------------------------------------------------------------
277
- * Bootstrap (v5.0.0): util/backdrop.js
357
+ * Bootstrap (v5.1.1): util/backdrop.js
278
358
  * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
279
359
  * --------------------------------------------------------------------------
280
360
  */
281
- const Default$1 = {
361
+ const Default$2 = {
362
+ className: 'modal-backdrop',
282
363
  isVisible: true,
283
364
  // if false, we use the backdrop helper without adding any element to the dom
284
365
  isAnimated: false,
285
- rootElement: document.body,
366
+ rootElement: 'body',
286
367
  // give the choice to place backdrop under different elements
287
368
  clickCallback: null
288
369
  };
289
- const DefaultType$1 = {
370
+ const DefaultType$2 = {
371
+ className: 'string',
290
372
  isVisible: 'boolean',
291
373
  isAnimated: 'boolean',
292
- rootElement: 'element',
374
+ rootElement: '(element|string)',
293
375
  clickCallback: '(function|null)'
294
376
  };
295
- const NAME$1 = 'backdrop';
296
- const CLASS_NAME_BACKDROP = 'modal-backdrop';
377
+ const NAME$2 = 'backdrop';
297
378
  const CLASS_NAME_FADE = 'fade';
298
379
  const CLASS_NAME_SHOW$1 = 'show';
299
- const EVENT_MOUSEDOWN = `mousedown.bs.${NAME$1}`;
380
+ const EVENT_MOUSEDOWN = `mousedown.bs.${NAME$2}`;
300
381
 
301
382
  class Backdrop {
302
383
  constructor(config) {
@@ -342,7 +423,7 @@
342
423
  _getElement() {
343
424
  if (!this._element) {
344
425
  const backdrop = document.createElement('div');
345
- backdrop.className = CLASS_NAME_BACKDROP;
426
+ backdrop.className = this._config.className;
346
427
 
347
428
  if (this._config.isAnimated) {
348
429
  backdrop.classList.add(CLASS_NAME_FADE);
@@ -355,10 +436,12 @@
355
436
  }
356
437
 
357
438
  _getConfig(config) {
358
- config = { ...Default$1,
439
+ config = { ...Default$2,
359
440
  ...(typeof config === 'object' ? config : {})
360
- };
361
- typeCheckConfig(NAME$1, config, DefaultType$1);
441
+ }; // use getElement() with the default "body" to get a fresh Element on each instantiation
442
+
443
+ config.rootElement = getElement(config.rootElement);
444
+ typeCheckConfig(NAME$2, config, DefaultType$2);
362
445
  return config;
363
446
  }
364
447
 
@@ -367,7 +450,7 @@
367
450
  return;
368
451
  }
369
452
 
370
- this._config.rootElement.appendChild(this._getElement());
453
+ this._config.rootElement.append(this._getElement());
371
454
 
372
455
  EventHandler__default['default'].on(this._getElement(), EVENT_MOUSEDOWN, () => {
373
456
  execute(this._config.clickCallback);
@@ -382,27 +465,149 @@
382
465
 
383
466
  EventHandler__default['default'].off(this._element, EVENT_MOUSEDOWN);
384
467
 
385
- this._getElement().parentNode.removeChild(this._element);
468
+ this._element.remove();
386
469
 
387
470
  this._isAppended = false;
388
471
  }
389
472
 
390
473
  _emulateAnimation(callback) {
391
- if (!this._config.isAnimated) {
392
- execute(callback);
474
+ executeAfterTransition(callback, this._getElement(), this._config.isAnimated);
475
+ }
476
+
477
+ }
478
+
479
+ /**
480
+ * --------------------------------------------------------------------------
481
+ * Bootstrap (v5.1.1): util/focustrap.js
482
+ * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
483
+ * --------------------------------------------------------------------------
484
+ */
485
+ const Default$1 = {
486
+ trapElement: null,
487
+ // The element to trap focus inside of
488
+ autofocus: true
489
+ };
490
+ const DefaultType$1 = {
491
+ trapElement: 'element',
492
+ autofocus: 'boolean'
493
+ };
494
+ const NAME$1 = 'focustrap';
495
+ const DATA_KEY$1 = 'bs.focustrap';
496
+ const EVENT_KEY$1 = `.${DATA_KEY$1}`;
497
+ const EVENT_FOCUSIN = `focusin${EVENT_KEY$1}`;
498
+ const EVENT_KEYDOWN_TAB = `keydown.tab${EVENT_KEY$1}`;
499
+ const TAB_KEY = 'Tab';
500
+ const TAB_NAV_FORWARD = 'forward';
501
+ const TAB_NAV_BACKWARD = 'backward';
502
+
503
+ class FocusTrap {
504
+ constructor(config) {
505
+ this._config = this._getConfig(config);
506
+ this._isActive = false;
507
+ this._lastTabNavDirection = null;
508
+ }
509
+
510
+ activate() {
511
+ const {
512
+ trapElement,
513
+ autofocus
514
+ } = this._config;
515
+
516
+ if (this._isActive) {
517
+ return;
518
+ }
519
+
520
+ if (autofocus) {
521
+ trapElement.focus();
522
+ }
523
+
524
+ EventHandler__default['default'].off(document, EVENT_KEY$1); // guard against infinite focus loop
525
+
526
+ EventHandler__default['default'].on(document, EVENT_FOCUSIN, event => this._handleFocusin(event));
527
+ EventHandler__default['default'].on(document, EVENT_KEYDOWN_TAB, event => this._handleKeydown(event));
528
+ this._isActive = true;
529
+ }
530
+
531
+ deactivate() {
532
+ if (!this._isActive) {
533
+ return;
534
+ }
535
+
536
+ this._isActive = false;
537
+ EventHandler__default['default'].off(document, EVENT_KEY$1);
538
+ } // Private
539
+
540
+
541
+ _handleFocusin(event) {
542
+ const {
543
+ target
544
+ } = event;
545
+ const {
546
+ trapElement
547
+ } = this._config;
548
+
549
+ if (target === document || target === trapElement || trapElement.contains(target)) {
550
+ return;
551
+ }
552
+
553
+ const elements = SelectorEngine__default['default'].focusableChildren(trapElement);
554
+
555
+ if (elements.length === 0) {
556
+ trapElement.focus();
557
+ } else if (this._lastTabNavDirection === TAB_NAV_BACKWARD) {
558
+ elements[elements.length - 1].focus();
559
+ } else {
560
+ elements[0].focus();
561
+ }
562
+ }
563
+
564
+ _handleKeydown(event) {
565
+ if (event.key !== TAB_KEY) {
393
566
  return;
394
567
  }
395
568
 
396
- const backdropTransitionDuration = getTransitionDurationFromElement(this._getElement());
397
- EventHandler__default['default'].one(this._getElement(), 'transitionend', () => execute(callback));
398
- emulateTransitionEnd(this._getElement(), backdropTransitionDuration);
569
+ this._lastTabNavDirection = event.shiftKey ? TAB_NAV_BACKWARD : TAB_NAV_FORWARD;
570
+ }
571
+
572
+ _getConfig(config) {
573
+ config = { ...Default$1,
574
+ ...(typeof config === 'object' ? config : {})
575
+ };
576
+ typeCheckConfig(NAME$1, config, DefaultType$1);
577
+ return config;
399
578
  }
400
579
 
401
580
  }
402
581
 
403
582
  /**
404
583
  * --------------------------------------------------------------------------
405
- * Bootstrap (v5.0.0): offcanvas.js
584
+ * Bootstrap (v5.1.1): util/component-functions.js
585
+ * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
586
+ * --------------------------------------------------------------------------
587
+ */
588
+
589
+ const enableDismissTrigger = (component, method = 'hide') => {
590
+ const clickEvent = `click.dismiss${component.EVENT_KEY}`;
591
+ const name = component.NAME;
592
+ EventHandler__default['default'].on(document, clickEvent, `[data-bs-dismiss="${name}"]`, function (event) {
593
+ if (['A', 'AREA'].includes(this.tagName)) {
594
+ event.preventDefault();
595
+ }
596
+
597
+ if (isDisabled(this)) {
598
+ return;
599
+ }
600
+
601
+ const target = getElementFromSelector(this) || this.closest(`.${name}`);
602
+ const instance = component.getOrCreateInstance(target); // Method argument is left, for Alert and only, as it doesn't implement the 'hide' method
603
+
604
+ instance[method]();
605
+ });
606
+ };
607
+
608
+ /**
609
+ * --------------------------------------------------------------------------
610
+ * Bootstrap (v5.1.1): offcanvas.js
406
611
  * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
407
612
  * --------------------------------------------------------------------------
408
613
  */
@@ -429,16 +634,14 @@
429
634
  scroll: 'boolean'
430
635
  };
431
636
  const CLASS_NAME_SHOW = 'show';
637
+ const CLASS_NAME_BACKDROP = 'offcanvas-backdrop';
432
638
  const OPEN_SELECTOR = '.offcanvas.show';
433
639
  const EVENT_SHOW = `show${EVENT_KEY}`;
434
640
  const EVENT_SHOWN = `shown${EVENT_KEY}`;
435
641
  const EVENT_HIDE = `hide${EVENT_KEY}`;
436
642
  const EVENT_HIDDEN = `hidden${EVENT_KEY}`;
437
- const EVENT_FOCUSIN = `focusin${EVENT_KEY}`;
438
643
  const EVENT_CLICK_DATA_API = `click${EVENT_KEY}${DATA_API_KEY}`;
439
- const EVENT_CLICK_DISMISS = `click.dismiss${EVENT_KEY}`;
440
644
  const EVENT_KEYDOWN_DISMISS = `keydown.dismiss${EVENT_KEY}`;
441
- const SELECTOR_DATA_DISMISS = '[data-bs-dismiss="offcanvas"]';
442
645
  const SELECTOR_DATA_TOGGLE = '[data-bs-toggle="offcanvas"]';
443
646
  /**
444
647
  * ------------------------------------------------------------------------
@@ -452,17 +655,18 @@
452
655
  this._config = this._getConfig(config);
453
656
  this._isShown = false;
454
657
  this._backdrop = this._initializeBackDrop();
658
+ this._focustrap = this._initializeFocusTrap();
455
659
 
456
660
  this._addEventListeners();
457
661
  } // Getters
458
662
 
459
663
 
460
- static get Default() {
461
- return Default;
664
+ static get NAME() {
665
+ return NAME;
462
666
  }
463
667
 
464
- static get DATA_KEY() {
465
- return DATA_KEY;
668
+ static get Default() {
669
+ return Default;
466
670
  } // Public
467
671
 
468
672
 
@@ -489,9 +693,7 @@
489
693
  this._backdrop.show();
490
694
 
491
695
  if (!this._config.scroll) {
492
- hide();
493
-
494
- this._enforceFocusOnElement(this._element);
696
+ new ScrollBarHelper().hide();
495
697
  }
496
698
 
497
699
  this._element.removeAttribute('aria-hidden');
@@ -503,14 +705,16 @@
503
705
  this._element.classList.add(CLASS_NAME_SHOW);
504
706
 
505
707
  const completeCallBack = () => {
708
+ if (!this._config.scroll) {
709
+ this._focustrap.activate();
710
+ }
711
+
506
712
  EventHandler__default['default'].trigger(this._element, EVENT_SHOWN, {
507
713
  relatedTarget
508
714
  });
509
715
  };
510
716
 
511
- const transitionDuration = getTransitionDurationFromElement(this._element);
512
- EventHandler__default['default'].one(this._element, 'transitionend', completeCallBack);
513
- emulateTransitionEnd(this._element, transitionDuration);
717
+ this._queueCallback(completeCallBack, this._element, true);
514
718
  }
515
719
 
516
720
  hide() {
@@ -524,7 +728,7 @@
524
728
  return;
525
729
  }
526
730
 
527
- EventHandler__default['default'].off(document, EVENT_FOCUSIN);
731
+ this._focustrap.deactivate();
528
732
 
529
733
  this._element.blur();
530
734
 
@@ -544,24 +748,21 @@
544
748
  this._element.style.visibility = 'hidden';
545
749
 
546
750
  if (!this._config.scroll) {
547
- reset();
751
+ new ScrollBarHelper().reset();
548
752
  }
549
753
 
550
754
  EventHandler__default['default'].trigger(this._element, EVENT_HIDDEN);
551
755
  };
552
756
 
553
- const transitionDuration = getTransitionDurationFromElement(this._element);
554
- EventHandler__default['default'].one(this._element, 'transitionend', completeCallback);
555
- emulateTransitionEnd(this._element, transitionDuration);
757
+ this._queueCallback(completeCallback, this._element, true);
556
758
  }
557
759
 
558
760
  dispose() {
559
761
  this._backdrop.dispose();
560
762
 
763
+ this._focustrap.deactivate();
764
+
561
765
  super.dispose();
562
- EventHandler__default['default'].off(document, EVENT_FOCUSIN);
563
- this._config = null;
564
- this._backdrop = null;
565
766
  } // Private
566
767
 
567
768
 
@@ -576,6 +777,7 @@
576
777
 
577
778
  _initializeBackDrop() {
578
779
  return new Backdrop({
780
+ className: CLASS_NAME_BACKDROP,
579
781
  isVisible: this._config.backdrop,
580
782
  isAnimated: true,
581
783
  rootElement: this._element.parentNode,
@@ -583,19 +785,13 @@
583
785
  });
584
786
  }
585
787
 
586
- _enforceFocusOnElement(element) {
587
- EventHandler__default['default'].off(document, EVENT_FOCUSIN); // guard against infinite focus loop
588
-
589
- EventHandler__default['default'].on(document, EVENT_FOCUSIN, event => {
590
- if (document !== event.target && element !== event.target && !element.contains(event.target)) {
591
- element.focus();
592
- }
788
+ _initializeFocusTrap() {
789
+ return new FocusTrap({
790
+ trapElement: this._element
593
791
  });
594
- element.focus();
595
792
  }
596
793
 
597
794
  _addEventListeners() {
598
- EventHandler__default['default'].on(this._element, EVENT_CLICK_DISMISS, SELECTOR_DATA_DISMISS, () => this.hide());
599
795
  EventHandler__default['default'].on(this._element, EVENT_KEYDOWN_DISMISS, event => {
600
796
  if (this._config.keyboard && event.key === ESCAPE_KEY) {
601
797
  this.hide();
@@ -606,7 +802,7 @@
606
802
 
607
803
  static jQueryInterface(config) {
608
804
  return this.each(function () {
609
- const data = Data__default['default'].get(this, DATA_KEY) || new Offcanvas(this, typeof config === 'object' ? config : {});
805
+ const data = Offcanvas.getOrCreateInstance(this, config);
610
806
 
611
807
  if (typeof config !== 'string') {
612
808
  return;
@@ -652,19 +848,18 @@
652
848
  Offcanvas.getInstance(allReadyOpen).hide();
653
849
  }
654
850
 
655
- const data = Data__default['default'].get(target, DATA_KEY) || new Offcanvas(target);
851
+ const data = Offcanvas.getOrCreateInstance(target);
656
852
  data.toggle(this);
657
853
  });
658
- EventHandler__default['default'].on(window, EVENT_LOAD_DATA_API, () => {
659
- SelectorEngine__default['default'].find(OPEN_SELECTOR).forEach(el => (Data__default['default'].get(el, DATA_KEY) || new Offcanvas(el)).show());
660
- });
854
+ EventHandler__default['default'].on(window, EVENT_LOAD_DATA_API, () => SelectorEngine__default['default'].find(OPEN_SELECTOR).forEach(el => Offcanvas.getOrCreateInstance(el).show()));
855
+ enableDismissTrigger(Offcanvas);
661
856
  /**
662
857
  * ------------------------------------------------------------------------
663
858
  * jQuery
664
859
  * ------------------------------------------------------------------------
665
860
  */
666
861
 
667
- defineJQueryPlugin(NAME, Offcanvas);
862
+ defineJQueryPlugin(Offcanvas);
668
863
 
669
864
  return Offcanvas;
670
865