@coreui/coreui 4.0.5 → 4.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (140) hide show
  1. package/README.md +4 -7
  2. package/dist/css/coreui-grid.css +254 -205
  3. package/dist/css/coreui-grid.css.map +1 -1
  4. package/dist/css/coreui-grid.min.css +2 -2
  5. package/dist/css/coreui-grid.min.css.map +1 -1
  6. package/dist/css/coreui-grid.rtl.css +255 -206
  7. package/dist/css/coreui-grid.rtl.css.map +1 -1
  8. package/dist/css/coreui-grid.rtl.min.css +3 -3
  9. package/dist/css/coreui-grid.rtl.min.css.map +1 -1
  10. package/dist/css/coreui-reboot.css +63 -8
  11. package/dist/css/coreui-reboot.css.map +1 -1
  12. package/dist/css/coreui-reboot.min.css +2 -2
  13. package/dist/css/coreui-reboot.min.css.map +1 -1
  14. package/dist/css/coreui-reboot.rtl.css +64 -9
  15. package/dist/css/coreui-reboot.rtl.css.map +1 -1
  16. package/dist/css/coreui-reboot.rtl.min.css +3 -3
  17. package/dist/css/coreui-reboot.rtl.min.css.map +1 -1
  18. package/dist/css/coreui-utilities.css +181 -81
  19. package/dist/css/coreui-utilities.css.map +1 -1
  20. package/dist/css/coreui-utilities.min.css +2 -2
  21. package/dist/css/coreui-utilities.min.css.map +1 -1
  22. package/dist/css/coreui-utilities.rtl.css +182 -82
  23. package/dist/css/coreui-utilities.rtl.css.map +1 -1
  24. package/dist/css/coreui-utilities.rtl.min.css +3 -3
  25. package/dist/css/coreui-utilities.rtl.min.css.map +1 -1
  26. package/dist/css/coreui.css +693 -327
  27. package/dist/css/coreui.css.map +1 -1
  28. package/dist/css/coreui.min.css +2 -2
  29. package/dist/css/coreui.min.css.map +1 -1
  30. package/dist/css/coreui.rtl.css +676 -325
  31. package/dist/css/coreui.rtl.css.map +1 -1
  32. package/dist/css/coreui.rtl.min.css +3 -3
  33. package/dist/css/coreui.rtl.min.css.map +1 -1
  34. package/dist/js/coreui.bundle.js +776 -702
  35. package/dist/js/coreui.bundle.js.map +1 -1
  36. package/dist/js/coreui.bundle.min.js +2 -2
  37. package/dist/js/coreui.bundle.min.js.map +1 -1
  38. package/dist/js/coreui.esm.js +659 -611
  39. package/dist/js/coreui.esm.js.map +1 -1
  40. package/dist/js/coreui.esm.min.js +2 -2
  41. package/dist/js/coreui.esm.min.js.map +1 -1
  42. package/dist/js/coreui.js +669 -623
  43. package/dist/js/coreui.js.map +1 -1
  44. package/dist/js/coreui.min.js +2 -2
  45. package/dist/js/coreui.min.js.map +1 -1
  46. package/js/dist/alert.js +81 -48
  47. package/js/dist/alert.js.map +1 -1
  48. package/js/dist/base-component.js +25 -17
  49. package/js/dist/base-component.js.map +1 -1
  50. package/js/dist/button.js +22 -12
  51. package/js/dist/button.js.map +1 -1
  52. package/js/dist/carousel.js +69 -44
  53. package/js/dist/carousel.js.map +1 -1
  54. package/js/dist/collapse.js +117 -131
  55. package/js/dist/collapse.js.map +1 -1
  56. package/js/dist/dom/data.js +5 -5
  57. package/js/dist/dom/data.js.map +1 -1
  58. package/js/dist/dom/event-handler.js +14 -5
  59. package/js/dist/dom/event-handler.js.map +1 -1
  60. package/js/dist/dom/manipulator.js +6 -6
  61. package/js/dist/dom/manipulator.js.map +1 -1
  62. package/js/dist/dom/selector-engine.js +53 -8
  63. package/js/dist/dom/selector-engine.js.map +1 -1
  64. package/js/dist/dropdown.js +99 -106
  65. package/js/dist/dropdown.js.map +1 -1
  66. package/js/dist/modal.js +244 -87
  67. package/js/dist/modal.js.map +1 -1
  68. package/js/dist/offcanvas.js +205 -56
  69. package/js/dist/offcanvas.js.map +1 -1
  70. package/js/dist/popover.js +28 -58
  71. package/js/dist/popover.js.map +1 -1
  72. package/js/dist/scrollspy.js +40 -30
  73. package/js/dist/scrollspy.js.map +1 -1
  74. package/js/dist/tab.js +44 -22
  75. package/js/dist/tab.js.map +1 -1
  76. package/js/dist/toast.js +127 -29
  77. package/js/dist/toast.js.map +1 -1
  78. package/js/dist/tooltip.js +122 -104
  79. package/js/dist/tooltip.js.map +1 -1
  80. package/js/src/alert.js +21 -47
  81. package/js/src/base-component.js +3 -3
  82. package/js/src/button.js +1 -1
  83. package/js/src/carousel.js +9 -4
  84. package/js/src/collapse.js +66 -119
  85. package/js/src/dom/data.js +1 -1
  86. package/js/src/dom/event-handler.js +1 -2
  87. package/js/src/dom/manipulator.js +3 -3
  88. package/js/src/dom/selector-engine.js +18 -1
  89. package/js/src/dropdown.js +53 -68
  90. package/js/src/modal.js +24 -35
  91. package/js/src/navigation.js +1 -1
  92. package/js/src/offcanvas.js +16 -18
  93. package/js/src/popover.js +7 -49
  94. package/js/src/scrollspy.js +1 -1
  95. package/js/src/sidebar.js +3 -3
  96. package/js/src/tab.js +1 -1
  97. package/js/src/toast.js +11 -11
  98. package/js/src/tooltip.js +66 -50
  99. package/js/src/util/backdrop.js +6 -5
  100. package/js/src/util/component-functions.js +34 -0
  101. package/js/src/util/focustrap.js +105 -0
  102. package/js/src/util/index.js +14 -5
  103. package/js/src/util/sanitizer.js +21 -22
  104. package/js/src/util/scrollbar.js +1 -1
  105. package/package.json +47 -44
  106. package/scss/_buttons.scss +1 -2
  107. package/scss/_card.scss +2 -1
  108. package/scss/_dropdown.scss +1 -1
  109. package/scss/_functions.scss +51 -12
  110. package/scss/_grid.scss +0 -23
  111. package/scss/_helpers.scss +2 -0
  112. package/scss/_mixins.scss +1 -0
  113. package/scss/_modal.scss +1 -11
  114. package/scss/_navbar.scss +30 -1
  115. package/scss/_offcanvas.scss +6 -2
  116. package/scss/_placeholders.scss +51 -0
  117. package/scss/_reboot.scss +12 -8
  118. package/scss/_root.scss +36 -7
  119. package/scss/_tables.scss +9 -5
  120. package/scss/_toasts.scss +2 -2
  121. package/scss/_transitions.scss +6 -0
  122. package/scss/_utilities.scss +31 -8
  123. package/scss/_variables.scss +184 -12
  124. package/scss/coreui-grid.rtl.scss +1 -1
  125. package/scss/coreui-grid.scss +3 -1
  126. package/scss/coreui-reboot.rtl.scss +1 -1
  127. package/scss/coreui-reboot.scss +2 -4
  128. package/scss/coreui-utilities.rtl.scss +1 -1
  129. package/scss/coreui-utilities.scss +1 -1
  130. package/scss/coreui.rtl.scss +1 -1
  131. package/scss/coreui.scss +2 -1
  132. package/scss/forms/_form-control.scss +1 -1
  133. package/scss/forms/_form-select.scss +2 -0
  134. package/scss/helpers/_stacks.scss +15 -0
  135. package/scss/helpers/_vr.scss +8 -0
  136. package/scss/mixins/_backdrop.scss +14 -0
  137. package/scss/mixins/_grid.scss +26 -7
  138. package/scss/mixins/_ltr-rtl.scss +21 -0
  139. package/scss/mixins/_utilities.scss +26 -26
  140. package/scss/mixins/_visually-hidden.scss +1 -1
package/js/src/tooltip.js CHANGED
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * --------------------------------------------------------------------------
3
- * CoreUI (v4.0.5): tooltip.js
3
+ * CoreUI (v4.1.0): tooltip.js
4
4
  * Licensed under MIT (https://coreui.io/license)
5
5
  *
6
6
  * This component is a modified version of the Bootstrap's tooltip.js
@@ -20,10 +20,7 @@ import {
20
20
  noop,
21
21
  typeCheckConfig
22
22
  } from './util/index'
23
- import {
24
- DefaultAllowlist,
25
- sanitizeHtml
26
- } from './util/sanitizer'
23
+ import { DefaultAllowlist, sanitizeHtml } from './util/sanitizer'
27
24
  import Data from './dom/data'
28
25
  import EventHandler from './dom/event-handler'
29
26
  import Manipulator from './dom/manipulator'
@@ -40,7 +37,6 @@ const NAME = 'tooltip'
40
37
  const DATA_KEY = 'coreui.tooltip'
41
38
  const EVENT_KEY = `.${DATA_KEY}`
42
39
  const CLASS_PREFIX = 'bs-tooltip'
43
- const BSCLS_PREFIX_REGEX = new RegExp(`(^|\\s)${CLASS_PREFIX}\\S+`, 'g')
44
40
  const DISALLOWED_ATTRIBUTES = new Set(['sanitize', 'allowList', 'sanitizeFn'])
45
41
 
46
42
  const DefaultType = {
@@ -115,6 +111,9 @@ const HOVER_STATE_SHOW = 'show'
115
111
  const HOVER_STATE_OUT = 'out'
116
112
 
117
113
  const SELECTOR_TOOLTIP_INNER = '.tooltip-inner'
114
+ const SELECTOR_MODAL = `.${CLASS_NAME_MODAL}`
115
+
116
+ const EVENT_MODAL_HIDE = 'hide.coreui.modal'
118
117
 
119
118
  const TRIGGER_HOVER = 'hover'
120
119
  const TRIGGER_FOCUS = 'focus'
@@ -209,16 +208,13 @@ class Tooltip extends BaseComponent {
209
208
  dispose() {
210
209
  clearTimeout(this._timeout)
211
210
 
212
- EventHandler.off(this._element.closest(`.${CLASS_NAME_MODAL}`), 'hide.coreui.modal', this._hideModalHandler)
211
+ EventHandler.off(this._element.closest(SELECTOR_MODAL), EVENT_MODAL_HIDE, this._hideModalHandler)
213
212
 
214
213
  if (this.tip) {
215
214
  this.tip.remove()
216
215
  }
217
216
 
218
- if (this._popper) {
219
- this._popper.destroy()
220
- }
221
-
217
+ this._disposePopper()
222
218
  super.dispose()
223
219
  }
224
220
 
@@ -241,14 +237,20 @@ class Tooltip extends BaseComponent {
241
237
  return
242
238
  }
243
239
 
240
+ // A trick to recreate a tooltip in case a new title is given by using the NOT documented `data-coreui-original-title`
241
+ // This will be removed later in favor of a `setContent` method
242
+ if (this.constructor.NAME === 'tooltip' && this.tip && this.getTitle() !== this.tip.querySelector(SELECTOR_TOOLTIP_INNER).innerHTML) {
243
+ this._disposePopper()
244
+ this.tip.remove()
245
+ this.tip = null
246
+ }
247
+
244
248
  const tip = this.getTipElement()
245
249
  const tipId = getUID(this.constructor.NAME)
246
250
 
247
251
  tip.setAttribute('id', tipId)
248
252
  this._element.setAttribute('aria-describedby', tipId)
249
253
 
250
- this.setContent()
251
-
252
254
  if (this._config.animation) {
253
255
  tip.classList.add(CLASS_NAME_FADE)
254
256
  }
@@ -264,7 +266,7 @@ class Tooltip extends BaseComponent {
264
266
  Data.set(tip, this.constructor.DATA_KEY, this)
265
267
 
266
268
  if (!this._element.ownerDocument.documentElement.contains(this.tip)) {
267
- container.appendChild(tip)
269
+ container.append(tip)
268
270
  EventHandler.trigger(this._element, this.constructor.Event.INSERTED)
269
271
  }
270
272
 
@@ -276,7 +278,7 @@ class Tooltip extends BaseComponent {
276
278
 
277
279
  tip.classList.add(CLASS_NAME_SHOW)
278
280
 
279
- const customClass = typeof this._config.customClass === 'function' ? this._config.customClass() : this._config.customClass
281
+ const customClass = this._resolvePossibleFunction(this._config.customClass)
280
282
  if (customClass) {
281
283
  tip.classList.add(...customClass.split(' '))
282
284
  }
@@ -325,10 +327,7 @@ class Tooltip extends BaseComponent {
325
327
  this._element.removeAttribute('aria-describedby')
326
328
  EventHandler.trigger(this._element, this.constructor.Event.HIDDEN)
327
329
 
328
- if (this._popper) {
329
- this._popper.destroy()
330
- this._popper = null
331
- }
330
+ this._disposePopper()
332
331
  }
333
332
 
334
333
  const hideEvent = EventHandler.trigger(this._element, this.constructor.Event.HIDE)
@@ -374,14 +373,28 @@ class Tooltip extends BaseComponent {
374
373
  const element = document.createElement('div')
375
374
  element.innerHTML = this._config.template
376
375
 
377
- this.tip = element.children[0]
376
+ const tip = element.children[0]
377
+ this.setContent(tip)
378
+ tip.classList.remove(CLASS_NAME_FADE, CLASS_NAME_SHOW)
379
+
380
+ this.tip = tip
378
381
  return this.tip
379
382
  }
380
383
 
381
- setContent() {
382
- const tip = this.getTipElement()
383
- this.setElementContent(SelectorEngine.findOne(SELECTOR_TOOLTIP_INNER, tip), this.getTitle())
384
- tip.classList.remove(CLASS_NAME_FADE, CLASS_NAME_SHOW)
384
+ setContent(tip) {
385
+ this._sanitizeAndSetContent(tip, this.getTitle(), SELECTOR_TOOLTIP_INNER)
386
+ }
387
+
388
+ _sanitizeAndSetContent(template, content, selector) {
389
+ const templateElement = SelectorEngine.findOne(selector, template)
390
+
391
+ if (!content && templateElement) {
392
+ templateElement.remove()
393
+ return
394
+ }
395
+
396
+ // we use append for html objects to maintain js events
397
+ this.setElementContent(templateElement, content)
385
398
  }
386
399
 
387
400
  setElementContent(element, content) {
@@ -396,7 +409,7 @@ class Tooltip extends BaseComponent {
396
409
  if (this._config.html) {
397
410
  if (content.parentNode !== element) {
398
411
  element.innerHTML = ''
399
- element.appendChild(content)
412
+ element.append(content)
400
413
  }
401
414
  } else {
402
415
  element.textContent = content.textContent
@@ -417,15 +430,9 @@ class Tooltip extends BaseComponent {
417
430
  }
418
431
 
419
432
  getTitle() {
420
- let title = this._element.getAttribute('data-coreui-original-title')
421
-
422
- if (!title) {
423
- title = typeof this._config.title === 'function' ?
424
- this._config.title.call(this._element) :
425
- this._config.title
426
- }
433
+ const title = this._element.getAttribute('data-coreui-original-title') || this._config.title
427
434
 
428
- return title
435
+ return this._resolvePossibleFunction(title)
429
436
  }
430
437
 
431
438
  updateAttachment(attachment) {
@@ -443,15 +450,7 @@ class Tooltip extends BaseComponent {
443
450
  // Private
444
451
 
445
452
  _initializeOnDelegatedTarget(event, context) {
446
- const dataKey = this.constructor.DATA_KEY
447
- context = context || Data.get(event.delegateTarget, dataKey)
448
-
449
- if (!context) {
450
- context = new this.constructor(event.delegateTarget, this._getDelegateConfig())
451
- Data.set(event.delegateTarget, dataKey, context)
452
- }
453
-
454
- return context
453
+ return context || this.constructor.getOrCreateInstance(event.delegateTarget, this._getDelegateConfig())
455
454
  }
456
455
 
457
456
  _getOffset() {
@@ -468,6 +467,10 @@ class Tooltip extends BaseComponent {
468
467
  return offset
469
468
  }
470
469
 
470
+ _resolvePossibleFunction(content) {
471
+ return typeof content === 'function' ? content.call(this._element) : content
472
+ }
473
+
471
474
  _getPopperConfig(attachment) {
472
475
  const defaultBsPopperConfig = {
473
476
  placement: attachment,
@@ -517,7 +520,7 @@ class Tooltip extends BaseComponent {
517
520
  }
518
521
 
519
522
  _addAttachmentClass(attachment) {
520
- this.getTipElement().classList.add(`${CLASS_PREFIX}-${this.updateAttachment(attachment)}`)
523
+ this.getTipElement().classList.add(`${this._getBasicClassPrefix()}-${this.updateAttachment(attachment)}`)
521
524
  }
522
525
 
523
526
  _getAttachment(placement) {
@@ -549,7 +552,7 @@ class Tooltip extends BaseComponent {
549
552
  }
550
553
  }
551
554
 
552
- EventHandler.on(this._element.closest(`.${CLASS_NAME_MODAL}`), 'hide.coreui.modal', this._hideModalHandler)
555
+ EventHandler.on(this._element.closest(SELECTOR_MODAL), EVENT_MODAL_HIDE, this._hideModalHandler)
553
556
 
554
557
  if (this._config.selector) {
555
558
  this._config = {
@@ -689,26 +692,32 @@ class Tooltip extends BaseComponent {
689
692
  _getDelegateConfig() {
690
693
  const config = {}
691
694
 
692
- if (this._config) {
693
- for (const key in this._config) {
694
- if (this.constructor.Default[key] !== this._config[key]) {
695
- config[key] = this._config[key]
696
- }
695
+ for (const key in this._config) {
696
+ if (this.constructor.Default[key] !== this._config[key]) {
697
+ config[key] = this._config[key]
697
698
  }
698
699
  }
699
700
 
701
+ // In the future can be replaced with:
702
+ // const keysWithDifferentValues = Object.entries(this._config).filter(entry => this.constructor.Default[entry[0]] !== this._config[entry[0]])
703
+ // `Object.fromEntries(keysWithDifferentValues)`
700
704
  return config
701
705
  }
702
706
 
703
707
  _cleanTipClass() {
704
708
  const tip = this.getTipElement()
705
- const tabClass = tip.getAttribute('class').match(BSCLS_PREFIX_REGEX)
709
+ const basicClassPrefixRegex = new RegExp(`(^|\\s)${this._getBasicClassPrefix()}\\S+`, 'g')
710
+ const tabClass = tip.getAttribute('class').match(basicClassPrefixRegex)
706
711
  if (tabClass !== null && tabClass.length > 0) {
707
712
  tabClass.map(token => token.trim())
708
713
  .forEach(tClass => tip.classList.remove(tClass))
709
714
  }
710
715
  }
711
716
 
717
+ _getBasicClassPrefix() {
718
+ return CLASS_PREFIX
719
+ }
720
+
712
721
  _handlePopperPlacementChange(popperData) {
713
722
  const { state } = popperData
714
723
 
@@ -721,6 +730,13 @@ class Tooltip extends BaseComponent {
721
730
  this._addAttachmentClass(this._getAttachment(state.placement))
722
731
  }
723
732
 
733
+ _disposePopper() {
734
+ if (this._popper) {
735
+ this._popper.destroy()
736
+ this._popper = null
737
+ }
738
+ }
739
+
724
740
  // Static
725
741
 
726
742
  static jQueryInterface(config) {
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * --------------------------------------------------------------------------
3
- * Bootstrap (v5.0.2): util/backdrop.js
4
- * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
3
+ * Bootstrap (v5.1.3): util/backdrop.js
4
+ * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
5
5
  * --------------------------------------------------------------------------
6
6
  */
7
7
 
@@ -9,6 +9,7 @@ import EventHandler from '../dom/event-handler'
9
9
  import { execute, executeAfterTransition, getElement, reflow, typeCheckConfig } from './index'
10
10
 
11
11
  const Default = {
12
+ className: 'modal-backdrop',
12
13
  isVisible: true, // if false, we use the backdrop helper without adding any element to the dom
13
14
  isAnimated: false,
14
15
  rootElement: 'body', // give the choice to place backdrop under different elements
@@ -16,13 +17,13 @@ const Default = {
16
17
  }
17
18
 
18
19
  const DefaultType = {
20
+ className: 'string',
19
21
  isVisible: 'boolean',
20
22
  isAnimated: 'boolean',
21
23
  rootElement: '(element|string)',
22
24
  clickCallback: '(function|null)'
23
25
  }
24
26
  const NAME = 'backdrop'
25
- const CLASS_NAME_BACKDROP = 'modal-backdrop'
26
27
  const CLASS_NAME_FADE = 'fade'
27
28
  const CLASS_NAME_SHOW = 'show'
28
29
 
@@ -73,7 +74,7 @@ class Backdrop {
73
74
  _getElement() {
74
75
  if (!this._element) {
75
76
  const backdrop = document.createElement('div')
76
- backdrop.className = CLASS_NAME_BACKDROP
77
+ backdrop.className = this._config.className
77
78
  if (this._config.isAnimated) {
78
79
  backdrop.classList.add(CLASS_NAME_FADE)
79
80
  }
@@ -101,7 +102,7 @@ class Backdrop {
101
102
  return
102
103
  }
103
104
 
104
- this._config.rootElement.appendChild(this._getElement())
105
+ this._config.rootElement.append(this._getElement())
105
106
 
106
107
  EventHandler.on(this._getElement(), EVENT_MOUSEDOWN, () => {
107
108
  execute(this._config.clickCallback)
@@ -0,0 +1,34 @@
1
+ /**
2
+ * --------------------------------------------------------------------------
3
+ * Bootstrap (v5.1.3): util/component-functions.js
4
+ * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
5
+ * --------------------------------------------------------------------------
6
+ */
7
+
8
+ import EventHandler from '../dom/event-handler'
9
+ import { getElementFromSelector, isDisabled } from './index'
10
+
11
+ const enableDismissTrigger = (component, method = 'hide') => {
12
+ const clickEvent = `click.dismiss${component.EVENT_KEY}`
13
+ const name = component.NAME
14
+
15
+ EventHandler.on(document, clickEvent, `[data-coreui-dismiss="${name}"]`, function (event) {
16
+ if (['A', 'AREA'].includes(this.tagName)) {
17
+ event.preventDefault()
18
+ }
19
+
20
+ if (isDisabled(this)) {
21
+ return
22
+ }
23
+
24
+ const target = getElementFromSelector(this) || this.closest(`.${name}`)
25
+ const instance = component.getOrCreateInstance(target)
26
+
27
+ // Method argument is left, for Alert and only, as it doesn't implement the 'hide' method
28
+ instance[method]()
29
+ })
30
+ }
31
+
32
+ export {
33
+ enableDismissTrigger
34
+ }
@@ -0,0 +1,105 @@
1
+ /**
2
+ * --------------------------------------------------------------------------
3
+ * Bootstrap (v5.1.3): util/focustrap.js
4
+ * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
5
+ * --------------------------------------------------------------------------
6
+ */
7
+
8
+ import EventHandler from '../dom/event-handler'
9
+ import SelectorEngine from '../dom/selector-engine'
10
+ import { typeCheckConfig } from './index'
11
+
12
+ const Default = {
13
+ trapElement: null, // The element to trap focus inside of
14
+ autofocus: true
15
+ }
16
+
17
+ const DefaultType = {
18
+ trapElement: 'element',
19
+ autofocus: 'boolean'
20
+ }
21
+
22
+ const NAME = 'focustrap'
23
+ const DATA_KEY = 'coreui.focustrap'
24
+ const EVENT_KEY = `.${DATA_KEY}`
25
+ const EVENT_FOCUSIN = `focusin${EVENT_KEY}`
26
+ const EVENT_KEYDOWN_TAB = `keydown.tab${EVENT_KEY}`
27
+
28
+ const TAB_KEY = 'Tab'
29
+ const TAB_NAV_FORWARD = 'forward'
30
+ const TAB_NAV_BACKWARD = 'backward'
31
+
32
+ class FocusTrap {
33
+ constructor(config) {
34
+ this._config = this._getConfig(config)
35
+ this._isActive = false
36
+ this._lastTabNavDirection = null
37
+ }
38
+
39
+ activate() {
40
+ const { trapElement, autofocus } = this._config
41
+
42
+ if (this._isActive) {
43
+ return
44
+ }
45
+
46
+ if (autofocus) {
47
+ trapElement.focus()
48
+ }
49
+
50
+ EventHandler.off(document, EVENT_KEY) // guard against infinite focus loop
51
+ EventHandler.on(document, EVENT_FOCUSIN, event => this._handleFocusin(event))
52
+ EventHandler.on(document, EVENT_KEYDOWN_TAB, event => this._handleKeydown(event))
53
+
54
+ this._isActive = true
55
+ }
56
+
57
+ deactivate() {
58
+ if (!this._isActive) {
59
+ return
60
+ }
61
+
62
+ this._isActive = false
63
+ EventHandler.off(document, EVENT_KEY)
64
+ }
65
+
66
+ // Private
67
+
68
+ _handleFocusin(event) {
69
+ const { target } = event
70
+ const { trapElement } = this._config
71
+
72
+ if (target === document || target === trapElement || trapElement.contains(target)) {
73
+ return
74
+ }
75
+
76
+ const elements = SelectorEngine.focusableChildren(trapElement)
77
+
78
+ if (elements.length === 0) {
79
+ trapElement.focus()
80
+ } else if (this._lastTabNavDirection === TAB_NAV_BACKWARD) {
81
+ elements[elements.length - 1].focus()
82
+ } else {
83
+ elements[0].focus()
84
+ }
85
+ }
86
+
87
+ _handleKeydown(event) {
88
+ if (event.key !== TAB_KEY) {
89
+ return
90
+ }
91
+
92
+ this._lastTabNavDirection = event.shiftKey ? TAB_NAV_BACKWARD : TAB_NAV_FORWARD
93
+ }
94
+
95
+ _getConfig(config) {
96
+ config = {
97
+ ...Default,
98
+ ...(typeof config === 'object' ? config : {})
99
+ }
100
+ typeCheckConfig(NAME, config, DefaultType)
101
+ return config
102
+ }
103
+ }
104
+
105
+ export default FocusTrap
@@ -1,8 +1,6 @@
1
- import SelectorEngine from '../dom/selector-engine'
2
-
3
1
  /**
4
2
  * --------------------------------------------------------------------------
5
- * CoreUI (v4.0.5): alert.js
3
+ * CoreUI (v4.1.0): alert.js
6
4
  * Licensed under MIT (https://coreui.io/license)
7
5
  *
8
6
  * This component is a modified version of the Bootstrap's util/index.js
@@ -123,7 +121,7 @@ const getElement = obj => {
123
121
  }
124
122
 
125
123
  if (typeof obj === 'string' && obj.length > 0) {
126
- return SelectorEngine.findOne(obj)
124
+ return document.querySelector(obj)
127
125
  }
128
126
 
129
127
  return null
@@ -192,7 +190,18 @@ const findShadowRoot = element => {
192
190
 
193
191
  const noop = () => {}
194
192
 
195
- const reflow = element => element.offsetHeight
193
+ /**
194
+ * Trick to restart an element's animation
195
+ *
196
+ * @param {HTMLElement} element
197
+ * @return void
198
+ *
199
+ * @see https://www.charistheo.io/blog/2021/02/restart-a-css-animation-with-javascript/#restarting-a-css-animation
200
+ */
201
+ const reflow = element => {
202
+ // eslint-disable-next-line no-unused-expressions
203
+ element.offsetHeight
204
+ }
196
205
 
197
206
  const getjQuery = () => {
198
207
  const { jQuery } = window
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * --------------------------------------------------------------------------
3
- * CoreUI (v4.0.5): alert.js
3
+ * CoreUI (v4.1.0): alert.js
4
4
  * Licensed under MIT (https://coreui.io/license)
5
5
  *
6
6
  * This component is a modified version of the Bootstrap's util/sanitizer.js
@@ -8,7 +8,7 @@
8
8
  * --------------------------------------------------------------------------
9
9
  */
10
10
 
11
- const uriAttrs = new Set([
11
+ const uriAttributes = new Set([
12
12
  'background',
13
13
  'cite',
14
14
  'href',
@@ -24,33 +24,33 @@ const ARIA_ATTRIBUTE_PATTERN = /^aria-[\w-]*$/i
24
24
  /**
25
25
  * A pattern that recognizes a commonly useful subset of URLs that are safe.
26
26
  *
27
- * Shoutout to Angular 7 https://github.com/angular/angular/blob/7.2.4/packages/core/src/sanitization/url_sanitizer.ts
27
+ * Shoutout to Angular https://github.com/angular/angular/blob/12.2.x/packages/core/src/sanitization/url_sanitizer.ts
28
28
  */
29
- const SAFE_URL_PATTERN = /^(?:(?:https?|mailto|ftp|tel|file):|[^#&/:?]*(?:[#/?]|$))/i
29
+ const SAFE_URL_PATTERN = /^(?:(?:https?|mailto|ftp|tel|file|sms):|[^#&/:?]*(?:[#/?]|$))/i
30
30
 
31
31
  /**
32
32
  * A pattern that matches safe data URLs. Only matches image, video and audio types.
33
33
  *
34
- * Shoutout to Angular 7 https://github.com/angular/angular/blob/7.2.4/packages/core/src/sanitization/url_sanitizer.ts
34
+ * Shoutout to Angular https://github.com/angular/angular/blob/12.2.x/packages/core/src/sanitization/url_sanitizer.ts
35
35
  */
36
36
  const DATA_URL_PATTERN = /^data:(?:image\/(?:bmp|gif|jpeg|jpg|png|tiff|webp)|video\/(?:mpeg|mp4|ogg|webm)|audio\/(?:mp3|oga|ogg|opus));base64,[\d+/a-z]+=*$/i
37
37
 
38
- const allowedAttribute = (attr, allowedAttributeList) => {
39
- const attrName = attr.nodeName.toLowerCase()
38
+ const allowedAttribute = (attribute, allowedAttributeList) => {
39
+ const attributeName = attribute.nodeName.toLowerCase()
40
40
 
41
- if (allowedAttributeList.includes(attrName)) {
42
- if (uriAttrs.has(attrName)) {
43
- return Boolean(SAFE_URL_PATTERN.test(attr.nodeValue) || DATA_URL_PATTERN.test(attr.nodeValue))
41
+ if (allowedAttributeList.includes(attributeName)) {
42
+ if (uriAttributes.has(attributeName)) {
43
+ return Boolean(SAFE_URL_PATTERN.test(attribute.nodeValue) || DATA_URL_PATTERN.test(attribute.nodeValue))
44
44
  }
45
45
 
46
46
  return true
47
47
  }
48
48
 
49
- const regExp = allowedAttributeList.filter(attrRegex => attrRegex instanceof RegExp)
49
+ const regExp = allowedAttributeList.filter(attributeRegex => attributeRegex instanceof RegExp)
50
50
 
51
51
  // Check if a regular expression validates the attribute.
52
52
  for (let i = 0, len = regExp.length; i < len; i++) {
53
- if (regExp[i].test(attrName)) {
53
+ if (regExp[i].test(attributeName)) {
54
54
  return true
55
55
  }
56
56
  }
@@ -103,25 +103,24 @@ export function sanitizeHtml(unsafeHtml, allowList, sanitizeFn) {
103
103
 
104
104
  const domParser = new window.DOMParser()
105
105
  const createdDocument = domParser.parseFromString(unsafeHtml, 'text/html')
106
- const allowlistKeys = Object.keys(allowList)
107
106
  const elements = [].concat(...createdDocument.body.querySelectorAll('*'))
108
107
 
109
108
  for (let i = 0, len = elements.length; i < len; i++) {
110
- const el = elements[i]
111
- const elName = el.nodeName.toLowerCase()
109
+ const element = elements[i]
110
+ const elementName = element.nodeName.toLowerCase()
112
111
 
113
- if (!allowlistKeys.includes(elName)) {
114
- el.remove()
112
+ if (!Object.keys(allowList).includes(elementName)) {
113
+ element.remove()
115
114
 
116
115
  continue
117
116
  }
118
117
 
119
- const attributeList = [].concat(...el.attributes)
120
- const allowedAttributes = [].concat(allowList['*'] || [], allowList[elName] || [])
118
+ const attributeList = [].concat(...element.attributes)
119
+ const allowedAttributes = [].concat(allowList['*'] || [], allowList[elementName] || [])
121
120
 
122
- attributeList.forEach(attr => {
123
- if (!allowedAttribute(attr, allowedAttributes)) {
124
- el.removeAttribute(attr.nodeName)
121
+ attributeList.forEach(attribute => {
122
+ if (!allowedAttribute(attribute, allowedAttributes)) {
123
+ element.removeAttribute(attribute.nodeName)
125
124
  }
126
125
  })
127
126
  }
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * --------------------------------------------------------------------------
3
- * Bootstrap (v5.0.2): util/scrollBar.js
3
+ * Bootstrap (v5.1.3): util/scrollBar.js
4
4
  * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
5
5
  * --------------------------------------------------------------------------
6
6
  */