bootstrap 5.0.0.beta3 → 5.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (42) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +2 -2
  3. data/assets/javascripts/bootstrap-sprockets.js +1 -1
  4. data/assets/javascripts/bootstrap.js +509 -459
  5. data/assets/javascripts/bootstrap.min.js +2 -2
  6. data/assets/javascripts/bootstrap/alert.js +4 -4
  7. data/assets/javascripts/bootstrap/base-component.js +9 -7
  8. data/assets/javascripts/bootstrap/button.js +3 -3
  9. data/assets/javascripts/bootstrap/carousel.js +11 -12
  10. data/assets/javascripts/bootstrap/collapse.js +5 -5
  11. data/assets/javascripts/bootstrap/dom/data.js +2 -2
  12. data/assets/javascripts/bootstrap/dom/event-handler.js +32 -14
  13. data/assets/javascripts/bootstrap/dom/manipulator.js +2 -2
  14. data/assets/javascripts/bootstrap/dom/selector-engine.js +2 -2
  15. data/assets/javascripts/bootstrap/dropdown.js +109 -94
  16. data/assets/javascripts/bootstrap/modal.js +262 -177
  17. data/assets/javascripts/bootstrap/offcanvas.js +219 -56
  18. data/assets/javascripts/bootstrap/popover.js +3 -3
  19. data/assets/javascripts/bootstrap/scrollspy.js +18 -22
  20. data/assets/javascripts/bootstrap/tab.js +21 -8
  21. data/assets/javascripts/bootstrap/toast.js +4 -5
  22. data/assets/javascripts/bootstrap/tooltip.js +7 -9
  23. data/assets/stylesheets/_bootstrap-grid.scss +1 -1
  24. data/assets/stylesheets/_bootstrap-reboot.scss +1 -1
  25. data/assets/stylesheets/_bootstrap.scss +1 -1
  26. data/assets/stylesheets/bootstrap/_accordion.scss +4 -2
  27. data/assets/stylesheets/bootstrap/_dropdown.scss +7 -13
  28. data/assets/stylesheets/bootstrap/_list-group.scss +1 -1
  29. data/assets/stylesheets/bootstrap/_mixins.scss +1 -0
  30. data/assets/stylesheets/bootstrap/_modal.scss +0 -9
  31. data/assets/stylesheets/bootstrap/_offcanvas.scss +11 -11
  32. data/assets/stylesheets/bootstrap/_spinners.scss +2 -2
  33. data/assets/stylesheets/bootstrap/_variables.scss +7 -7
  34. data/assets/stylesheets/bootstrap/bootstrap-utilities.scss +1 -1
  35. data/assets/stylesheets/bootstrap/forms/_form-control.scss +5 -5
  36. data/assets/stylesheets/bootstrap/mixins/_color-scheme.scss +7 -0
  37. data/assets/stylesheets/bootstrap/mixins/_forms.scss +7 -4
  38. data/assets/stylesheets/bootstrap/mixins/_grid.scss +8 -3
  39. data/bootstrap.gemspec +1 -1
  40. data/lib/bootstrap/version.rb +2 -2
  41. data/tasks/updater/js.rb +1 -1
  42. metadata +7 -6
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * Bootstrap offcanvas.js v5.0.0-beta3 (https://getbootstrap.com/)
2
+ * Bootstrap offcanvas.js v5.0.0 (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
  */
@@ -19,11 +19,12 @@
19
19
 
20
20
  /**
21
21
  * --------------------------------------------------------------------------
22
- * Bootstrap (v5.0.0-beta3): util/index.js
22
+ * Bootstrap (v5.0.0): util/index.js
23
23
  * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
24
24
  * --------------------------------------------------------------------------
25
25
  */
26
26
  const MILLISECONDS_MULTIPLIER = 1000;
27
+ const TRANSITION_END = 'transitionend'; // Shoutout AngusCroll (https://goo.gl/pxwQGp)
27
28
 
28
29
  const toType = obj => {
29
30
  if (obj === null || obj === undefined) {
@@ -48,7 +49,7 @@
48
49
 
49
50
 
50
51
  if (hrefAttr.includes('#') && !hrefAttr.startsWith('#')) {
51
- hrefAttr = '#' + hrefAttr.split('#')[1];
52
+ hrefAttr = `#${hrefAttr.split('#')[1]}`;
52
53
  }
53
54
 
54
55
  selector = hrefAttr && hrefAttr !== '#' ? hrefAttr.trim() : null;
@@ -57,16 +58,6 @@
57
58
  return selector;
58
59
  };
59
60
 
60
- const getSelectorFromElement = element => {
61
- const selector = getSelector(element);
62
-
63
- if (selector) {
64
- return document.querySelector(selector) ? selector : null;
65
- }
66
-
67
- return null;
68
- };
69
-
70
61
  const getElementFromSelector = element => {
71
62
  const selector = getSelector(element);
72
63
  return selector ? document.querySelector(selector) : null;
@@ -95,8 +86,30 @@
95
86
  return (Number.parseFloat(transitionDuration) + Number.parseFloat(transitionDelay)) * MILLISECONDS_MULTIPLIER;
96
87
  };
97
88
 
89
+ const triggerTransitionEnd = element => {
90
+ element.dispatchEvent(new Event(TRANSITION_END));
91
+ };
92
+
98
93
  const isElement = obj => (obj[0] || obj).nodeType;
99
94
 
95
+ const emulateTransitionEnd = (element, duration) => {
96
+ let called = false;
97
+ const durationPadding = 5;
98
+ const emulatedDuration = duration + durationPadding;
99
+
100
+ function listener() {
101
+ called = true;
102
+ element.removeEventListener(TRANSITION_END, listener);
103
+ }
104
+
105
+ element.addEventListener(TRANSITION_END, listener);
106
+ setTimeout(() => {
107
+ if (!called) {
108
+ triggerTransitionEnd(element);
109
+ }
110
+ }, emulatedDuration);
111
+ };
112
+
100
113
  const typeCheckConfig = (componentName, config, configTypes) => {
101
114
  Object.keys(configTypes).forEach(property => {
102
115
  const expectedTypes = configTypes[property];
@@ -104,7 +117,7 @@
104
117
  const valueType = value && isElement(value) ? 'element' : toType(value);
105
118
 
106
119
  if (!new RegExp(expectedTypes).test(valueType)) {
107
- throw new TypeError(`${componentName.toUpperCase()}: ` + `Option "${property}" provided type "${valueType}" ` + `but expected type "${expectedTypes}".`);
120
+ throw new TypeError(`${componentName.toUpperCase()}: Option "${property}" provided type "${valueType}" but expected type "${expectedTypes}".`);
108
121
  }
109
122
  });
110
123
  };
@@ -139,6 +152,8 @@
139
152
  return element.hasAttribute('disabled') && element.getAttribute('disabled') !== 'false';
140
153
  };
141
154
 
155
+ const reflow = element => element.offsetHeight;
156
+
142
157
  const getjQuery = () => {
143
158
  const {
144
159
  jQuery
@@ -177,13 +192,19 @@
177
192
  });
178
193
  };
179
194
 
195
+ const execute = callback => {
196
+ if (typeof callback === 'function') {
197
+ callback();
198
+ }
199
+ };
200
+
180
201
  /**
181
202
  * --------------------------------------------------------------------------
182
- * Bootstrap (v5.0.0-beta3): util/scrollBar.js
203
+ * Bootstrap (v5.0.0): util/scrollBar.js
183
204
  * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
184
205
  * --------------------------------------------------------------------------
185
206
  */
186
- const SELECTOR_FIXED_CONTENT = '.fixed-top, .fixed-bottom, .is-fixed';
207
+ const SELECTOR_FIXED_CONTENT = '.fixed-top, .fixed-bottom, .is-fixed, .sticky-top';
187
208
  const SELECTOR_STICKY_CONTENT = '.sticky-top';
188
209
 
189
210
  const getWidth = () => {
@@ -193,13 +214,25 @@
193
214
  };
194
215
 
195
216
  const hide = (width = getWidth()) => {
196
- document.body.style.overflow = 'hidden';
217
+ _disableOverFlow(); // give padding to element to balances the hidden scrollbar width
218
+
219
+
220
+ _setElementAttributes('body', 'paddingRight', calculatedValue => calculatedValue + width); // trick: We adjust positive paddingRight and negative marginRight to sticky-top elements, to keep shown fullwidth
221
+
197
222
 
198
223
  _setElementAttributes(SELECTOR_FIXED_CONTENT, 'paddingRight', calculatedValue => calculatedValue + width);
199
224
 
200
225
  _setElementAttributes(SELECTOR_STICKY_CONTENT, 'marginRight', calculatedValue => calculatedValue - width);
226
+ };
201
227
 
202
- _setElementAttributes('body', 'paddingRight', calculatedValue => calculatedValue + width);
228
+ const _disableOverFlow = () => {
229
+ const actualValue = document.body.style.overflow;
230
+
231
+ if (actualValue) {
232
+ Manipulator__default['default'].setDataAttribute(document.body, 'overflow', actualValue);
233
+ }
234
+
235
+ document.body.style.overflow = 'hidden';
203
236
  };
204
237
 
205
238
  const _setElementAttributes = (selector, styleProp, callback) => {
@@ -212,25 +245,25 @@
212
245
  const actualValue = element.style[styleProp];
213
246
  const calculatedValue = window.getComputedStyle(element)[styleProp];
214
247
  Manipulator__default['default'].setDataAttribute(element, styleProp, actualValue);
215
- element.style[styleProp] = callback(Number.parseFloat(calculatedValue)) + 'px';
248
+ element.style[styleProp] = `${callback(Number.parseFloat(calculatedValue))}px`;
216
249
  });
217
250
  };
218
251
 
219
252
  const reset = () => {
220
- document.body.style.overflow = 'auto';
253
+ _resetElementAttributes('body', 'overflow');
254
+
255
+ _resetElementAttributes('body', 'paddingRight');
221
256
 
222
257
  _resetElementAttributes(SELECTOR_FIXED_CONTENT, 'paddingRight');
223
258
 
224
259
  _resetElementAttributes(SELECTOR_STICKY_CONTENT, 'marginRight');
225
-
226
- _resetElementAttributes('body', 'paddingRight');
227
260
  };
228
261
 
229
262
  const _resetElementAttributes = (selector, styleProp) => {
230
263
  SelectorEngine__default['default'].find(selector).forEach(element => {
231
264
  const value = Manipulator__default['default'].getDataAttribute(element, styleProp);
232
265
 
233
- if (typeof value === 'undefined' && element === document.body) {
266
+ if (typeof value === 'undefined') {
234
267
  element.style.removeProperty(styleProp);
235
268
  } else {
236
269
  Manipulator__default['default'].removeDataAttribute(element, styleProp);
@@ -241,7 +274,135 @@
241
274
 
242
275
  /**
243
276
  * --------------------------------------------------------------------------
244
- * Bootstrap (v5.0.0-beta3): offcanvas.js
277
+ * Bootstrap (v5.0.0): util/backdrop.js
278
+ * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
279
+ * --------------------------------------------------------------------------
280
+ */
281
+ const Default$1 = {
282
+ isVisible: true,
283
+ // if false, we use the backdrop helper without adding any element to the dom
284
+ isAnimated: false,
285
+ rootElement: document.body,
286
+ // give the choice to place backdrop under different elements
287
+ clickCallback: null
288
+ };
289
+ const DefaultType$1 = {
290
+ isVisible: 'boolean',
291
+ isAnimated: 'boolean',
292
+ rootElement: 'element',
293
+ clickCallback: '(function|null)'
294
+ };
295
+ const NAME$1 = 'backdrop';
296
+ const CLASS_NAME_BACKDROP = 'modal-backdrop';
297
+ const CLASS_NAME_FADE = 'fade';
298
+ const CLASS_NAME_SHOW$1 = 'show';
299
+ const EVENT_MOUSEDOWN = `mousedown.bs.${NAME$1}`;
300
+
301
+ class Backdrop {
302
+ constructor(config) {
303
+ this._config = this._getConfig(config);
304
+ this._isAppended = false;
305
+ this._element = null;
306
+ }
307
+
308
+ show(callback) {
309
+ if (!this._config.isVisible) {
310
+ execute(callback);
311
+ return;
312
+ }
313
+
314
+ this._append();
315
+
316
+ if (this._config.isAnimated) {
317
+ reflow(this._getElement());
318
+ }
319
+
320
+ this._getElement().classList.add(CLASS_NAME_SHOW$1);
321
+
322
+ this._emulateAnimation(() => {
323
+ execute(callback);
324
+ });
325
+ }
326
+
327
+ hide(callback) {
328
+ if (!this._config.isVisible) {
329
+ execute(callback);
330
+ return;
331
+ }
332
+
333
+ this._getElement().classList.remove(CLASS_NAME_SHOW$1);
334
+
335
+ this._emulateAnimation(() => {
336
+ this.dispose();
337
+ execute(callback);
338
+ });
339
+ } // Private
340
+
341
+
342
+ _getElement() {
343
+ if (!this._element) {
344
+ const backdrop = document.createElement('div');
345
+ backdrop.className = CLASS_NAME_BACKDROP;
346
+
347
+ if (this._config.isAnimated) {
348
+ backdrop.classList.add(CLASS_NAME_FADE);
349
+ }
350
+
351
+ this._element = backdrop;
352
+ }
353
+
354
+ return this._element;
355
+ }
356
+
357
+ _getConfig(config) {
358
+ config = { ...Default$1,
359
+ ...(typeof config === 'object' ? config : {})
360
+ };
361
+ typeCheckConfig(NAME$1, config, DefaultType$1);
362
+ return config;
363
+ }
364
+
365
+ _append() {
366
+ if (this._isAppended) {
367
+ return;
368
+ }
369
+
370
+ this._config.rootElement.appendChild(this._getElement());
371
+
372
+ EventHandler__default['default'].on(this._getElement(), EVENT_MOUSEDOWN, () => {
373
+ execute(this._config.clickCallback);
374
+ });
375
+ this._isAppended = true;
376
+ }
377
+
378
+ dispose() {
379
+ if (!this._isAppended) {
380
+ return;
381
+ }
382
+
383
+ EventHandler__default['default'].off(this._element, EVENT_MOUSEDOWN);
384
+
385
+ this._getElement().parentNode.removeChild(this._element);
386
+
387
+ this._isAppended = false;
388
+ }
389
+
390
+ _emulateAnimation(callback) {
391
+ if (!this._config.isAnimated) {
392
+ execute(callback);
393
+ return;
394
+ }
395
+
396
+ const backdropTransitionDuration = getTransitionDurationFromElement(this._getElement());
397
+ EventHandler__default['default'].one(this._getElement(), 'transitionend', () => execute(callback));
398
+ emulateTransitionEnd(this._getElement(), backdropTransitionDuration);
399
+ }
400
+
401
+ }
402
+
403
+ /**
404
+ * --------------------------------------------------------------------------
405
+ * Bootstrap (v5.0.0): offcanvas.js
245
406
  * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
246
407
  * --------------------------------------------------------------------------
247
408
  */
@@ -267,11 +428,8 @@
267
428
  keyboard: 'boolean',
268
429
  scroll: 'boolean'
269
430
  };
270
- const CLASS_NAME_BACKDROP_BODY = 'offcanvas-backdrop';
271
431
  const CLASS_NAME_SHOW = 'show';
272
- const CLASS_NAME_TOGGLING = 'offcanvas-toggling';
273
432
  const OPEN_SELECTOR = '.offcanvas.show';
274
- const ACTIVE_SELECTOR = `${OPEN_SELECTOR}, .${CLASS_NAME_TOGGLING}`;
275
433
  const EVENT_SHOW = `show${EVENT_KEY}`;
276
434
  const EVENT_SHOWN = `shown${EVENT_KEY}`;
277
435
  const EVENT_HIDE = `hide${EVENT_KEY}`;
@@ -279,6 +437,7 @@
279
437
  const EVENT_FOCUSIN = `focusin${EVENT_KEY}`;
280
438
  const EVENT_CLICK_DATA_API = `click${EVENT_KEY}${DATA_API_KEY}`;
281
439
  const EVENT_CLICK_DISMISS = `click.dismiss${EVENT_KEY}`;
440
+ const EVENT_KEYDOWN_DISMISS = `keydown.dismiss${EVENT_KEY}`;
282
441
  const SELECTOR_DATA_DISMISS = '[data-bs-dismiss="offcanvas"]';
283
442
  const SELECTOR_DATA_TOGGLE = '[data-bs-toggle="offcanvas"]';
284
443
  /**
@@ -292,6 +451,7 @@
292
451
  super(element);
293
452
  this._config = this._getConfig(config);
294
453
  this._isShown = false;
454
+ this._backdrop = this._initializeBackDrop();
295
455
 
296
456
  this._addEventListeners();
297
457
  } // Getters
@@ -326,15 +486,13 @@
326
486
  this._isShown = true;
327
487
  this._element.style.visibility = 'visible';
328
488
 
329
- if (this._config.backdrop) {
330
- document.body.classList.add(CLASS_NAME_BACKDROP_BODY);
331
- }
489
+ this._backdrop.show();
332
490
 
333
491
  if (!this._config.scroll) {
334
492
  hide();
335
- }
336
493
 
337
- this._element.classList.add(CLASS_NAME_TOGGLING);
494
+ this._enforceFocusOnElement(this._element);
495
+ }
338
496
 
339
497
  this._element.removeAttribute('aria-hidden');
340
498
 
@@ -345,16 +503,14 @@
345
503
  this._element.classList.add(CLASS_NAME_SHOW);
346
504
 
347
505
  const completeCallBack = () => {
348
- this._element.classList.remove(CLASS_NAME_TOGGLING);
349
-
350
506
  EventHandler__default['default'].trigger(this._element, EVENT_SHOWN, {
351
507
  relatedTarget
352
508
  });
353
-
354
- this._enforceFocusOnElement(this._element);
355
509
  };
356
510
 
357
- setTimeout(completeCallBack, getTransitionDurationFromElement(this._element));
511
+ const transitionDuration = getTransitionDurationFromElement(this._element);
512
+ EventHandler__default['default'].one(this._element, 'transitionend', completeCallBack);
513
+ emulateTransitionEnd(this._element, transitionDuration);
358
514
  }
359
515
 
360
516
  hide() {
@@ -368,8 +524,6 @@
368
524
  return;
369
525
  }
370
526
 
371
- this._element.classList.add(CLASS_NAME_TOGGLING);
372
-
373
527
  EventHandler__default['default'].off(document, EVENT_FOCUSIN);
374
528
 
375
529
  this._element.blur();
@@ -378,6 +532,8 @@
378
532
 
379
533
  this._element.classList.remove(CLASS_NAME_SHOW);
380
534
 
535
+ this._backdrop.hide();
536
+
381
537
  const completeCallback = () => {
382
538
  this._element.setAttribute('aria-hidden', true);
383
539
 
@@ -387,20 +543,25 @@
387
543
 
388
544
  this._element.style.visibility = 'hidden';
389
545
 
390
- if (this._config.backdrop) {
391
- document.body.classList.remove(CLASS_NAME_BACKDROP_BODY);
392
- }
393
-
394
546
  if (!this._config.scroll) {
395
547
  reset();
396
548
  }
397
549
 
398
550
  EventHandler__default['default'].trigger(this._element, EVENT_HIDDEN);
399
-
400
- this._element.classList.remove(CLASS_NAME_TOGGLING);
401
551
  };
402
552
 
403
- setTimeout(completeCallback, getTransitionDurationFromElement(this._element));
553
+ const transitionDuration = getTransitionDurationFromElement(this._element);
554
+ EventHandler__default['default'].one(this._element, 'transitionend', completeCallback);
555
+ emulateTransitionEnd(this._element, transitionDuration);
556
+ }
557
+
558
+ dispose() {
559
+ this._backdrop.dispose();
560
+
561
+ super.dispose();
562
+ EventHandler__default['default'].off(document, EVENT_FOCUSIN);
563
+ this._config = null;
564
+ this._backdrop = null;
404
565
  } // Private
405
566
 
406
567
 
@@ -413,6 +574,15 @@
413
574
  return config;
414
575
  }
415
576
 
577
+ _initializeBackDrop() {
578
+ return new Backdrop({
579
+ isVisible: this._config.backdrop,
580
+ isAnimated: true,
581
+ rootElement: this._element.parentNode,
582
+ clickCallback: () => this.hide()
583
+ });
584
+ }
585
+
416
586
  _enforceFocusOnElement(element) {
417
587
  EventHandler__default['default'].off(document, EVENT_FOCUSIN); // guard against infinite focus loop
418
588
 
@@ -426,18 +596,11 @@
426
596
 
427
597
  _addEventListeners() {
428
598
  EventHandler__default['default'].on(this._element, EVENT_CLICK_DISMISS, SELECTOR_DATA_DISMISS, () => this.hide());
429
- EventHandler__default['default'].on(document, 'keydown', event => {
599
+ EventHandler__default['default'].on(this._element, EVENT_KEYDOWN_DISMISS, event => {
430
600
  if (this._config.keyboard && event.key === ESCAPE_KEY) {
431
601
  this.hide();
432
602
  }
433
603
  });
434
- EventHandler__default['default'].on(document, EVENT_CLICK_DATA_API, event => {
435
- const target = SelectorEngine__default['default'].findOne(getSelectorFromElement(event.target));
436
-
437
- if (!this._element.contains(event.target) && target !== this._element) {
438
- this.hide();
439
- }
440
- });
441
604
  } // Static
442
605
 
443
606
 
@@ -483,10 +646,10 @@
483
646
  }
484
647
  }); // avoid conflict when clicking a toggler of an offcanvas, while another is open
485
648
 
486
- const allReadyOpen = SelectorEngine__default['default'].findOne(ACTIVE_SELECTOR);
649
+ const allReadyOpen = SelectorEngine__default['default'].findOne(OPEN_SELECTOR);
487
650
 
488
651
  if (allReadyOpen && allReadyOpen !== target) {
489
- return;
652
+ Offcanvas.getInstance(allReadyOpen).hide();
490
653
  }
491
654
 
492
655
  const data = Data__default['default'].get(target, DATA_KEY) || new Offcanvas(target);