@coreui/coreui 4.1.4 → 4.2.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 (208) hide show
  1. package/LICENSE +2 -2
  2. package/README.md +64 -11
  3. package/dist/css/bootstrap-reboot.css +488 -0
  4. package/dist/css/bootstrap-reboot.css.map +1 -0
  5. package/dist/css/bootstrap-reboot.min.css +8 -0
  6. package/dist/css/bootstrap-reboot.min.css.map +1 -0
  7. package/dist/css/coreui-grid.css +23 -949
  8. package/dist/css/coreui-grid.css.map +1 -1
  9. package/dist/css/coreui-grid.min.css +3 -3
  10. package/dist/css/coreui-grid.min.css.map +1 -1
  11. package/dist/css/coreui-grid.rtl.css +25 -951
  12. package/dist/css/coreui-grid.rtl.css.map +1 -1
  13. package/dist/css/coreui-grid.rtl.min.css +5 -5
  14. package/dist/css/coreui-grid.rtl.min.css.map +1 -1
  15. package/dist/css/coreui-reboot.css +35 -42
  16. package/dist/css/coreui-reboot.css.map +1 -1
  17. package/dist/css/coreui-reboot.min.css +3 -3
  18. package/dist/css/coreui-reboot.min.css.map +1 -1
  19. package/dist/css/coreui-reboot.rtl.css +36 -44
  20. package/dist/css/coreui-reboot.rtl.css.map +1 -1
  21. package/dist/css/coreui-reboot.rtl.min.css +5 -5
  22. package/dist/css/coreui-reboot.rtl.min.css.map +1 -1
  23. package/dist/css/coreui-utilities.css +279 -951
  24. package/dist/css/coreui-utilities.css.map +1 -1
  25. package/dist/css/coreui-utilities.min.css +3 -3
  26. package/dist/css/coreui-utilities.min.css.map +1 -1
  27. package/dist/css/coreui-utilities.rtl.css +275 -953
  28. package/dist/css/coreui-utilities.rtl.css.map +1 -1
  29. package/dist/css/coreui-utilities.rtl.min.css +5 -5
  30. package/dist/css/coreui-utilities.rtl.min.css.map +1 -1
  31. package/dist/css/coreui.css +2203 -2295
  32. package/dist/css/coreui.css.map +1 -1
  33. package/dist/css/coreui.min.css +3 -3
  34. package/dist/css/coreui.min.css.map +1 -1
  35. package/dist/css/coreui.rtl.css +2190 -2289
  36. package/dist/css/coreui.rtl.css.map +1 -1
  37. package/dist/css/coreui.rtl.min.css +5 -5
  38. package/dist/css/coreui.rtl.min.css.map +1 -1
  39. package/dist/js/coreui.bundle.js +2101 -1908
  40. package/dist/js/coreui.bundle.js.map +1 -1
  41. package/dist/js/coreui.bundle.min.js +2 -2
  42. package/dist/js/coreui.bundle.min.js.map +1 -1
  43. package/dist/js/coreui.esm.js +2098 -1909
  44. package/dist/js/coreui.esm.js.map +1 -1
  45. package/dist/js/coreui.esm.min.js +2 -2
  46. package/dist/js/coreui.esm.min.js.map +1 -1
  47. package/dist/js/coreui.js +2099 -1910
  48. package/dist/js/coreui.js.map +1 -1
  49. package/dist/js/coreui.min.js +2 -2
  50. package/dist/js/coreui.min.js.map +1 -1
  51. package/js/dist/alert.js +10 -148
  52. package/js/dist/alert.js.map +1 -1
  53. package/js/dist/base-component.js +36 -122
  54. package/js/dist/base-component.js.map +1 -1
  55. package/js/dist/button.js +9 -76
  56. package/js/dist/button.js.map +1 -1
  57. package/js/dist/carousel.js +212 -507
  58. package/js/dist/carousel.js.map +1 -1
  59. package/js/dist/collapse.js +64 -251
  60. package/js/dist/collapse.js.map +1 -1
  61. package/js/dist/dom/data.js +2 -4
  62. package/js/dist/dom/data.js.map +1 -1
  63. package/js/dist/dom/event-handler.js +82 -133
  64. package/js/dist/dom/event-handler.js.map +1 -1
  65. package/js/dist/dom/manipulator.js +22 -26
  66. package/js/dist/dom/manipulator.js.map +1 -1
  67. package/js/dist/dom/selector-engine.js +16 -81
  68. package/js/dist/dom/selector-engine.js.map +1 -1
  69. package/js/dist/dropdown.js +99 -338
  70. package/js/dist/dropdown.js.map +1 -1
  71. package/js/dist/modal.js +106 -774
  72. package/js/dist/modal.js.map +1 -1
  73. package/js/dist/navigation.js +309 -0
  74. package/js/dist/navigation.js.map +1 -0
  75. package/js/dist/offcanvas.js +88 -680
  76. package/js/dist/offcanvas.js.map +1 -1
  77. package/js/dist/popover.js +35 -120
  78. package/js/dist/popover.js.map +1 -1
  79. package/js/dist/scrollspy.js +178 -264
  80. package/js/dist/scrollspy.js.map +1 -1
  81. package/js/dist/sidebar.js +347 -0
  82. package/js/dist/sidebar.js.map +1 -0
  83. package/js/dist/tab.js +226 -216
  84. package/js/dist/tab.js.map +1 -1
  85. package/js/dist/toast.js +27 -216
  86. package/js/dist/toast.js.map +1 -1
  87. package/js/dist/tooltip.js +271 -618
  88. package/js/dist/tooltip.js.map +1 -1
  89. package/js/dist/util/backdrop.js +166 -0
  90. package/js/dist/util/backdrop.js.map +1 -0
  91. package/js/dist/util/component-functions.js +47 -0
  92. package/js/dist/util/component-functions.js.map +1 -0
  93. package/js/dist/util/config.js +80 -0
  94. package/js/dist/util/config.js.map +1 -0
  95. package/js/dist/util/focustrap.js +130 -0
  96. package/js/dist/util/focustrap.js.map +1 -0
  97. package/js/dist/util/index.js +354 -0
  98. package/js/dist/util/index.js.map +1 -0
  99. package/js/dist/util/sanitizer.js +126 -0
  100. package/js/dist/util/sanitizer.js.map +1 -0
  101. package/js/dist/util/scrollbar.js +139 -0
  102. package/js/dist/util/scrollbar.js.map +1 -0
  103. package/js/dist/util/swipe.js +156 -0
  104. package/js/dist/util/swipe.js.map +1 -0
  105. package/js/dist/util/template-factory.js +178 -0
  106. package/js/dist/util/template-factory.js.map +1 -0
  107. package/js/src/alert.js +3 -15
  108. package/js/src/base-component.js +28 -18
  109. package/js/src/button.js +3 -15
  110. package/js/src/carousel.js +203 -320
  111. package/js/src/collapse.js +61 -94
  112. package/js/src/dom/data.js +1 -3
  113. package/js/src/dom/event-handler.js +74 -107
  114. package/js/src/dom/manipulator.js +22 -31
  115. package/js/src/dom/selector-engine.js +10 -19
  116. package/js/src/dropdown.js +84 -138
  117. package/js/src/modal.js +94 -158
  118. package/js/src/navigation.js +12 -13
  119. package/js/src/offcanvas.js +71 -60
  120. package/js/src/popover.js +31 -62
  121. package/js/src/scrollspy.js +166 -171
  122. package/js/src/sidebar.js +5 -8
  123. package/js/src/tab.js +201 -110
  124. package/js/src/toast.js +19 -41
  125. package/js/src/tooltip.js +264 -374
  126. package/js/src/util/backdrop.js +55 -36
  127. package/js/src/util/component-functions.js +1 -1
  128. package/js/src/util/config.js +66 -0
  129. package/js/src/util/focustrap.js +38 -28
  130. package/js/src/util/index.js +41 -57
  131. package/js/src/util/sanitizer.js +9 -17
  132. package/js/src/util/scrollbar.js +47 -30
  133. package/js/src/util/swipe.js +146 -0
  134. package/js/src/util/template-factory.js +160 -0
  135. package/package.json +40 -40
  136. package/scss/_accordion.scss +53 -25
  137. package/scss/_alert.scss +29 -9
  138. package/scss/_badge.scss +15 -6
  139. package/scss/_breadcrumb.scss +23 -11
  140. package/scss/_button-group.scss +3 -0
  141. package/scss/_buttons.scss +71 -50
  142. package/scss/_callout.scss +18 -6
  143. package/scss/_card.scss +55 -37
  144. package/scss/_carousel.scss +6 -6
  145. package/scss/_close.scss +4 -4
  146. package/scss/_containers.scss +1 -1
  147. package/scss/_dropdown.scss +86 -64
  148. package/scss/_footer.scss +15 -5
  149. package/scss/_functions.scss +11 -24
  150. package/scss/_grid.scss +3 -3
  151. package/scss/_header.scss +59 -34
  152. package/scss/_helpers.scss +1 -0
  153. package/scss/_images.scss +3 -3
  154. package/scss/_list-group.scss +47 -29
  155. package/scss/_maps.scss +54 -0
  156. package/scss/_modal.scss +70 -43
  157. package/scss/_nav.scss +53 -20
  158. package/scss/_navbar.scss +84 -94
  159. package/scss/_offcanvas.scss +120 -60
  160. package/scss/_pagination.scss +66 -21
  161. package/scss/_popover.scss +90 -52
  162. package/scss/_progress.scss +20 -9
  163. package/scss/_reboot.scss +31 -58
  164. package/scss/_root.scss +41 -21
  165. package/scss/_spinners.scss +37 -21
  166. package/scss/_subheader.scss +9 -9
  167. package/scss/_tables.scss +34 -36
  168. package/scss/_toasts.scss +35 -19
  169. package/scss/_tooltip.scss +61 -56
  170. package/scss/_utilities.scss +42 -27
  171. package/scss/_variables.scss +169 -148
  172. package/scss/bootstrap-reboot.scss +14 -0
  173. package/scss/coreui-grid.rtl.scss +2 -2
  174. package/scss/coreui-grid.scss +3 -2
  175. package/scss/coreui-reboot.rtl.scss +2 -2
  176. package/scss/coreui-reboot.scss +2 -2
  177. package/scss/coreui-utilities.rtl.scss +2 -2
  178. package/scss/coreui-utilities.scss +3 -2
  179. package/scss/coreui.rtl.scss +2 -2
  180. package/scss/coreui.scss +3 -2
  181. package/scss/forms/_floating-labels.scss +14 -3
  182. package/scss/forms/_form-check.scss +42 -19
  183. package/scss/forms/_form-control.scss +25 -50
  184. package/scss/forms/_form-range.scss +8 -8
  185. package/scss/forms/_form-select.scss +8 -8
  186. package/scss/forms/_form-text.scss +1 -1
  187. package/scss/forms/_input-group.scss +3 -3
  188. package/scss/forms/_labels.scss +2 -2
  189. package/scss/helpers/_color-bg.scss +10 -0
  190. package/scss/helpers/_colored-links.scss +2 -2
  191. package/scss/helpers/_position.scss +7 -1
  192. package/scss/helpers/_ratio.scss +2 -2
  193. package/scss/helpers/_vr.scss +1 -0
  194. package/scss/mixins/_alert.scss +10 -10
  195. package/scss/mixins/_breakpoints.scss +8 -8
  196. package/scss/mixins/_buttons.scss +45 -47
  197. package/scss/mixins/_container.scss +4 -2
  198. package/scss/mixins/_css-vars.scss +47 -47
  199. package/scss/mixins/_forms.scss +10 -2
  200. package/scss/mixins/_gradients.scss +1 -1
  201. package/scss/mixins/_grid.scss +11 -11
  202. package/scss/mixins/_list-group.scss +7 -9
  203. package/scss/mixins/_pagination.scss +4 -25
  204. package/scss/mixins/_table-variants.scss +20 -12
  205. package/scss/mixins/_utilities.scss +8 -3
  206. package/scss/sidebar/_sidebar-narrow.scss +10 -10
  207. package/scss/sidebar/_sidebar-nav.scss +33 -32
  208. package/scss/sidebar/_sidebar.scss +110 -56
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * --------------------------------------------------------------------------
3
- * CoreUI (v4.1.4): dom/manipulator.js
3
+ * CoreUI (v4.2.0): dom/manipulator.js
4
4
  * Licensed under MIT (https://coreui.io/license)
5
5
  *
6
6
  * This component is a modified version of the Bootstrap's dom/manipulator.js
@@ -8,24 +8,32 @@
8
8
  * --------------------------------------------------------------------------
9
9
  */
10
10
 
11
- function normalizeData(val) {
12
- if (val === 'true') {
11
+ function normalizeData(value) {
12
+ if (value === 'true') {
13
13
  return true
14
14
  }
15
15
 
16
- if (val === 'false') {
16
+ if (value === 'false') {
17
17
  return false
18
18
  }
19
19
 
20
- if (val === Number(val).toString()) {
21
- return Number(val)
20
+ if (value === Number(value).toString()) {
21
+ return Number(value)
22
22
  }
23
23
 
24
- if (val === '' || val === 'null') {
24
+ if (value === '' || value === 'null') {
25
25
  return null
26
26
  }
27
27
 
28
- return val
28
+ if (typeof value !== 'string') {
29
+ return value
30
+ }
31
+
32
+ try {
33
+ return JSON.parse(decodeURIComponent(value))
34
+ } catch {
35
+ return value
36
+ }
29
37
  }
30
38
 
31
39
  function normalizeDataKey(key) {
@@ -47,36 +55,19 @@ const Manipulator = {
47
55
  }
48
56
 
49
57
  const attributes = {}
58
+ const coreuiKeys = Object.keys(element.dataset).filter(key => key.startsWith('coreui') && !key.startsWith('coreuiConfig'))
50
59
 
51
- Object.keys(element.dataset)
52
- .filter(key => key.startsWith('coreui'))
53
- .forEach(key => {
54
- let pureKey = key.replace(/^coreui/, '')
55
- pureKey = pureKey.charAt(0).toLowerCase() + pureKey.slice(1, pureKey.length)
56
- attributes[pureKey] = normalizeData(element.dataset[key])
57
- })
60
+ for (const key of coreuiKeys) {
61
+ let pureKey = key.replace(/^coreui/, '')
62
+ pureKey = pureKey.charAt(0).toLowerCase() + pureKey.slice(1, pureKey.length)
63
+ attributes[pureKey] = normalizeData(element.dataset[key])
64
+ }
58
65
 
59
66
  return attributes
60
67
  },
61
68
 
62
69
  getDataAttribute(element, key) {
63
70
  return normalizeData(element.getAttribute(`data-coreui-${normalizeDataKey(key)}`))
64
- },
65
-
66
- offset(element) {
67
- const rect = element.getBoundingClientRect()
68
-
69
- return {
70
- top: rect.top + window.pageYOffset,
71
- left: rect.left + window.pageXOffset
72
- }
73
- },
74
-
75
- position(element) {
76
- return {
77
- top: element.offsetTop,
78
- left: element.offsetLeft
79
- }
80
71
  }
81
72
  }
82
73
 
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * --------------------------------------------------------------------------
3
- * CoreUI (v4.1.4): dom/selector-engine.js
3
+ * CoreUI (v4.2.0): dom/selector-engine.js
4
4
  * Licensed under MIT (https://coreui.io/license)
5
5
  *
6
6
  * This component is a modified version of the Bootstrap's dom/selector-engine.js
@@ -8,16 +8,12 @@
8
8
  * --------------------------------------------------------------------------
9
9
  */
10
10
 
11
+ import { isDisabled, isVisible } from '../util/index'
12
+
11
13
  /**
12
- * ------------------------------------------------------------------------
13
14
  * Constants
14
- * ------------------------------------------------------------------------
15
15
  */
16
16
 
17
- import { isDisabled, isVisible } from '../util/index'
18
-
19
- const NODE_TEXT = 3
20
-
21
17
  const SelectorEngine = {
22
18
  find(selector, element = document.documentElement) {
23
19
  return [].concat(...Element.prototype.querySelectorAll.call(element, selector))
@@ -28,21 +24,16 @@ const SelectorEngine = {
28
24
  },
29
25
 
30
26
  children(element, selector) {
31
- return [].concat(...element.children)
32
- .filter(child => child.matches(selector))
27
+ return [].concat(...element.children).filter(child => child.matches(selector))
33
28
  },
34
29
 
35
30
  parents(element, selector) {
36
31
  const parents = []
32
+ let ancestor = element.parentNode.closest(selector)
37
33
 
38
- let ancestor = element.parentNode
39
-
40
- while (ancestor && ancestor.nodeType === Node.ELEMENT_NODE && ancestor.nodeType !== NODE_TEXT) {
41
- if (ancestor.matches(selector)) {
42
- parents.push(ancestor)
43
- }
44
-
45
- ancestor = ancestor.parentNode
34
+ while (ancestor) {
35
+ parents.push(ancestor)
36
+ ancestor = ancestor.parentNode.closest(selector)
46
37
  }
47
38
 
48
39
  return parents
@@ -61,7 +52,7 @@ const SelectorEngine = {
61
52
 
62
53
  return []
63
54
  },
64
-
55
+ // TODO: this is now unused; remove later along with prev()
65
56
  next(element, selector) {
66
57
  let next = element.nextElementSibling
67
58
 
@@ -86,7 +77,7 @@ const SelectorEngine = {
86
77
  'details',
87
78
  '[tabindex]',
88
79
  '[contenteditable="true"]'
89
- ].map(selector => `${selector}:not([tabindex^="-"])`).join(', ')
80
+ ].map(selector => `${selector}:not([tabindex^="-"])`).join(',')
90
81
 
91
82
  return this.find(focusables, element).filter(el => !isDisabled(el) && isVisible(el))
92
83
  }
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * --------------------------------------------------------------------------
3
- * CoreUI (v4.1.4): dropdown.js
3
+ * CoreUI (v4.2.0): dropdown.js
4
4
  * Licensed under MIT (https://coreui.io/license)
5
5
  *
6
6
  * This component is a modified version of the Bootstrap's dropdown.js
@@ -9,18 +9,15 @@
9
9
  */
10
10
 
11
11
  import * as Popper from '@popperjs/core'
12
-
13
12
  import {
14
13
  defineJQueryPlugin,
15
14
  getElement,
16
- getElementFromSelector,
17
15
  getNextActiveElement,
18
16
  isDisabled,
19
17
  isElement,
20
18
  isRTL,
21
19
  isVisible,
22
- noop,
23
- typeCheckConfig
20
+ noop
24
21
  } from './util/index'
25
22
  import EventHandler from './dom/event-handler'
26
23
  import Manipulator from './dom/manipulator'
@@ -28,9 +25,7 @@ import SelectorEngine from './dom/selector-engine'
28
25
  import BaseComponent from './base-component'
29
26
 
30
27
  /**
31
- * ------------------------------------------------------------------------
32
28
  * Constants
33
- * ------------------------------------------------------------------------
34
29
  */
35
30
 
36
31
  const NAME = 'dropdown'
@@ -39,14 +34,11 @@ const EVENT_KEY = `.${DATA_KEY}`
39
34
  const DATA_API_KEY = '.data-api'
40
35
 
41
36
  const ESCAPE_KEY = 'Escape'
42
- const SPACE_KEY = 'Space'
43
37
  const TAB_KEY = 'Tab'
44
38
  const ARROW_UP_KEY = 'ArrowUp'
45
39
  const ARROW_DOWN_KEY = 'ArrowDown'
46
40
  const RIGHT_MOUSE_BUTTON = 2 // MouseEvent.button value for the secondary button, usually the right button
47
41
 
48
- const REGEXP_KEYDOWN = new RegExp(`${ARROW_UP_KEY}|${ARROW_DOWN_KEY}|${ESCAPE_KEY}`)
49
-
50
42
  const EVENT_HIDE = `hide${EVENT_KEY}`
51
43
  const EVENT_HIDDEN = `hidden${EVENT_KEY}`
52
44
  const EVENT_SHOW = `show${EVENT_KEY}`
@@ -59,10 +51,13 @@ const CLASS_NAME_SHOW = 'show'
59
51
  const CLASS_NAME_DROPUP = 'dropup'
60
52
  const CLASS_NAME_DROPEND = 'dropend'
61
53
  const CLASS_NAME_DROPSTART = 'dropstart'
62
- const CLASS_NAME_NAVBAR = 'navbar'
54
+ const CLASS_NAME_DROPUP_CENTER = 'dropup-center'
55
+ const CLASS_NAME_DROPDOWN_CENTER = 'dropdown-center'
63
56
 
64
- const SELECTOR_DATA_TOGGLE = '[data-coreui-toggle="dropdown"]'
57
+ const SELECTOR_DATA_TOGGLE = '[data-coreui-toggle="dropdown"]:not(.disabled):not(:disabled)'
58
+ const SELECTOR_DATA_TOGGLE_SHOWN = `${SELECTOR_DATA_TOGGLE}.${CLASS_NAME_SHOW}`
65
59
  const SELECTOR_MENU = '.dropdown-menu'
60
+ const SELECTOR_NAVBAR = '.navbar'
66
61
  const SELECTOR_NAVBAR_NAV = '.navbar-nav'
67
62
  const SELECTOR_VISIBLE_ITEMS = '.dropdown-menu .dropdown-item:not(.disabled):not(:disabled)'
68
63
 
@@ -72,43 +67,42 @@ const PLACEMENT_BOTTOM = isRTL() ? 'bottom-end' : 'bottom-start'
72
67
  const PLACEMENT_BOTTOMEND = isRTL() ? 'bottom-start' : 'bottom-end'
73
68
  const PLACEMENT_RIGHT = isRTL() ? 'left-start' : 'right-start'
74
69
  const PLACEMENT_LEFT = isRTL() ? 'right-start' : 'left-start'
70
+ const PLACEMENT_TOPCENTER = 'top'
71
+ const PLACEMENT_BOTTOMCENTER = 'bottom'
75
72
 
76
73
  const Default = {
77
- offset: [0, 2],
74
+ autoClose: true,
78
75
  boundary: 'clippingParents',
79
- reference: 'toggle',
80
76
  display: 'dynamic',
77
+ offset: [0, 2],
81
78
  popperConfig: null,
82
- autoClose: true
79
+ reference: 'toggle'
83
80
  }
84
81
 
85
82
  const DefaultType = {
86
- offset: '(array|string|function)',
83
+ autoClose: '(boolean|string)',
87
84
  boundary: '(string|element)',
88
- reference: '(string|element|object)',
89
85
  display: 'string',
86
+ offset: '(array|string|function)',
90
87
  popperConfig: '(null|object|function)',
91
- autoClose: '(boolean|string)'
88
+ reference: '(string|element|object)'
92
89
  }
93
90
 
94
91
  /**
95
- * ------------------------------------------------------------------------
96
- * Class Definition
97
- * ------------------------------------------------------------------------
92
+ * Class definition
98
93
  */
99
94
 
100
95
  class Dropdown extends BaseComponent {
101
96
  constructor(element, config) {
102
- super(element)
97
+ super(element, config)
103
98
 
104
99
  this._popper = null
105
- this._config = this._getConfig(config)
106
- this._menu = this._getMenuElement()
100
+ this._parent = this._element.parentNode // dropdown wrapper
101
+ this._menu = SelectorEngine.findOne(SELECTOR_MENU, this._parent)
107
102
  this._inNavbar = this._detectNavbar()
108
103
  }
109
104
 
110
105
  // Getters
111
-
112
106
  static get Default() {
113
107
  return Default
114
108
  }
@@ -122,13 +116,12 @@ class Dropdown extends BaseComponent {
122
116
  }
123
117
 
124
118
  // Public
125
-
126
119
  toggle() {
127
120
  return this._isShown() ? this.hide() : this.show()
128
121
  }
129
122
 
130
123
  show() {
131
- if (isDisabled(this._element) || this._isShown(this._menu)) {
124
+ if (isDisabled(this._element) || this._isShown()) {
132
125
  return
133
126
  }
134
127
 
@@ -142,22 +135,16 @@ class Dropdown extends BaseComponent {
142
135
  return
143
136
  }
144
137
 
145
- const parent = Dropdown.getParentFromElement(this._element)
146
- // Totally disable Popper for Dropdowns in Navbar
147
- if (this._inNavbar) {
148
- Manipulator.setDataAttribute(this._menu, 'popper', 'none')
149
- } else {
150
- this._createPopper(parent)
151
- }
138
+ this._createPopper()
152
139
 
153
140
  // If this is a touch-enabled device we add extra
154
141
  // empty mouseover listeners to the body's immediate children;
155
142
  // only needed because of broken event delegation on iOS
156
143
  // https://www.quirksmode.org/blog/archives/2014/02/mouse_event_bub.html
157
- if ('ontouchstart' in document.documentElement &&
158
- !parent.closest(SELECTOR_NAVBAR_NAV)) {
159
- [].concat(...document.body.children)
160
- .forEach(elem => EventHandler.on(elem, 'mouseover', noop))
144
+ if ('ontouchstart' in document.documentElement && !this._parent.closest(SELECTOR_NAVBAR_NAV)) {
145
+ for (const element of [].concat(...document.body.children)) {
146
+ EventHandler.on(element, 'mouseover', noop)
147
+ }
161
148
  }
162
149
 
163
150
  this._element.focus()
@@ -169,7 +156,7 @@ class Dropdown extends BaseComponent {
169
156
  }
170
157
 
171
158
  hide() {
172
- if (isDisabled(this._element) || !this._isShown(this._menu)) {
159
+ if (isDisabled(this._element) || !this._isShown()) {
173
160
  return
174
161
  }
175
162
 
@@ -196,7 +183,6 @@ class Dropdown extends BaseComponent {
196
183
  }
197
184
 
198
185
  // Private
199
-
200
186
  _completeHide(relatedTarget) {
201
187
  const hideEvent = EventHandler.trigger(this._element, EVENT_HIDE, relatedTarget)
202
188
  if (hideEvent.defaultPrevented) {
@@ -206,8 +192,9 @@ class Dropdown extends BaseComponent {
206
192
  // If this is a touch-enabled device we remove the extra
207
193
  // empty mouseover listeners we added for iOS support
208
194
  if ('ontouchstart' in document.documentElement) {
209
- [].concat(...document.body.children)
210
- .forEach(elem => EventHandler.off(elem, 'mouseover', noop))
195
+ for (const element of [].concat(...document.body.children)) {
196
+ EventHandler.off(element, 'mouseover', noop)
197
+ }
211
198
  }
212
199
 
213
200
  if (this._popper) {
@@ -222,13 +209,7 @@ class Dropdown extends BaseComponent {
222
209
  }
223
210
 
224
211
  _getConfig(config) {
225
- config = {
226
- ...this.constructor.Default,
227
- ...Manipulator.getDataAttributes(this._element),
228
- ...config
229
- }
230
-
231
- typeCheckConfig(NAME, config, this.constructor.DefaultType)
212
+ config = super._getConfig(config)
232
213
 
233
214
  if (typeof config.reference === 'object' && !isElement(config.reference) &&
234
215
  typeof config.reference.getBoundingClientRect !== 'function'
@@ -240,7 +221,7 @@ class Dropdown extends BaseComponent {
240
221
  return config
241
222
  }
242
223
 
243
- _createPopper(parent) {
224
+ _createPopper() {
244
225
  if (typeof Popper === 'undefined') {
245
226
  throw new TypeError('Bootstrap\'s dropdowns require Popper (https://popper.js.org)')
246
227
  }
@@ -248,7 +229,7 @@ class Dropdown extends BaseComponent {
248
229
  let referenceElement = this._element
249
230
 
250
231
  if (this._config.reference === 'parent') {
251
- referenceElement = parent
232
+ referenceElement = this._parent
252
233
  } else if (isElement(this._config.reference)) {
253
234
  referenceElement = getElement(this._config.reference)
254
235
  } else if (typeof this._config.reference === 'object') {
@@ -256,25 +237,15 @@ class Dropdown extends BaseComponent {
256
237
  }
257
238
 
258
239
  const popperConfig = this._getPopperConfig()
259
- const isDisplayStatic = popperConfig.modifiers.find(modifier => modifier.name === 'applyStyles' && modifier.enabled === false)
260
-
261
240
  this._popper = Popper.createPopper(referenceElement, this._menu, popperConfig)
262
-
263
- if (isDisplayStatic) {
264
- Manipulator.setDataAttribute(this._menu, 'popper', 'static')
265
- }
266
241
  }
267
242
 
268
- _isShown(element = this._element) {
269
- return element.classList.contains(CLASS_NAME_SHOW)
270
- }
271
-
272
- _getMenuElement() {
273
- return SelectorEngine.next(this._element, SELECTOR_MENU)[0]
243
+ _isShown() {
244
+ return this._menu.classList.contains(CLASS_NAME_SHOW)
274
245
  }
275
246
 
276
247
  _getPlacement() {
277
- const parentDropdown = this._element.parentNode
248
+ const parentDropdown = this._parent
278
249
 
279
250
  if (parentDropdown.classList.contains(CLASS_NAME_DROPEND)) {
280
251
  return PLACEMENT_RIGHT
@@ -284,6 +255,14 @@ class Dropdown extends BaseComponent {
284
255
  return PLACEMENT_LEFT
285
256
  }
286
257
 
258
+ if (parentDropdown.classList.contains(CLASS_NAME_DROPUP_CENTER)) {
259
+ return PLACEMENT_TOPCENTER
260
+ }
261
+
262
+ if (parentDropdown.classList.contains(CLASS_NAME_DROPDOWN_CENTER)) {
263
+ return PLACEMENT_BOTTOMCENTER
264
+ }
265
+
287
266
  // We need to trim the value because custom properties can also include spaces
288
267
  const isEnd = getComputedStyle(this._menu).getPropertyValue('--cui-position').trim() === 'end'
289
268
 
@@ -295,14 +274,14 @@ class Dropdown extends BaseComponent {
295
274
  }
296
275
 
297
276
  _detectNavbar() {
298
- return this._element.closest(`.${CLASS_NAME_NAVBAR}`) !== null
277
+ return this._element.closest(SELECTOR_NAVBAR) !== null
299
278
  }
300
279
 
301
280
  _getOffset() {
302
281
  const { offset } = this._config
303
282
 
304
283
  if (typeof offset === 'string') {
305
- return offset.split(',').map(val => Number.parseInt(val, 10))
284
+ return offset.split(',').map(value => Number.parseInt(value, 10))
306
285
  }
307
286
 
308
287
  if (typeof offset === 'function') {
@@ -329,8 +308,9 @@ class Dropdown extends BaseComponent {
329
308
  }]
330
309
  }
331
310
 
332
- // Disable Popper if we have a static display
333
- if (this._config.display === 'static') {
311
+ // Disable Popper if we have a static display or Dropdown is in Navbar
312
+ if (this._inNavbar || this._config.display === 'static') {
313
+ Manipulator.setDataAttribute(this._menu, 'popper', 'static') // todo:v6 remove
334
314
  defaultBsPopperConfig.modifiers = [{
335
315
  name: 'applyStyles',
336
316
  enabled: false
@@ -344,7 +324,7 @@ class Dropdown extends BaseComponent {
344
324
  }
345
325
 
346
326
  _selectMenuItem({ key, target }) {
347
- const items = SelectorEngine.find(SELECTOR_VISIBLE_ITEMS, this._menu).filter(isVisible)
327
+ const items = SelectorEngine.find(SELECTOR_VISIBLE_ITEMS, this._menu).filter(element => isVisible(element))
348
328
 
349
329
  if (!items.length) {
350
330
  return
@@ -356,7 +336,6 @@ class Dropdown extends BaseComponent {
356
336
  }
357
337
 
358
338
  // Static
359
-
360
339
  static jQueryInterface(config) {
361
340
  return this.each(function () {
362
341
  const data = Dropdown.getOrCreateInstance(this, config)
@@ -374,111 +353,81 @@ class Dropdown extends BaseComponent {
374
353
  }
375
354
 
376
355
  static clearMenus(event) {
377
- if (event && (event.button === RIGHT_MOUSE_BUTTON || (event.type === 'keyup' && event.key !== TAB_KEY))) {
356
+ if (event.button === RIGHT_MOUSE_BUTTON || (event.type === 'keyup' && event.key !== TAB_KEY)) {
378
357
  return
379
358
  }
380
359
 
381
- const toggles = SelectorEngine.find(SELECTOR_DATA_TOGGLE)
360
+ const openToggles = SelectorEngine.find(SELECTOR_DATA_TOGGLE_SHOWN)
382
361
 
383
- for (let i = 0, len = toggles.length; i < len; i++) {
384
- const context = Dropdown.getInstance(toggles[i])
362
+ for (const toggle of openToggles) {
363
+ const context = Dropdown.getInstance(toggle)
385
364
  if (!context || context._config.autoClose === false) {
386
365
  continue
387
366
  }
388
367
 
389
- if (!context._isShown()) {
368
+ const composedPath = event.composedPath()
369
+ const isMenuTarget = composedPath.includes(context._menu)
370
+ if (
371
+ composedPath.includes(context._element) ||
372
+ (context._config.autoClose === 'inside' && !isMenuTarget) ||
373
+ (context._config.autoClose === 'outside' && isMenuTarget)
374
+ ) {
390
375
  continue
391
376
  }
392
377
 
393
- const relatedTarget = {
394
- relatedTarget: context._element
378
+ // Tab navigation through the dropdown menu or events from contained inputs shouldn't close the menu
379
+ if (context._menu.contains(event.target) && ((event.type === 'keyup' && event.key === TAB_KEY) || /input|select|option|textarea|form/i.test(event.target.tagName))) {
380
+ continue
395
381
  }
396
382
 
397
- if (event) {
398
- const composedPath = event.composedPath()
399
- const isMenuTarget = composedPath.includes(context._menu)
400
- if (
401
- composedPath.includes(context._element) ||
402
- (context._config.autoClose === 'inside' && !isMenuTarget) ||
403
- (context._config.autoClose === 'outside' && isMenuTarget)
404
- ) {
405
- continue
406
- }
407
-
408
- // Tab navigation through the dropdown menu or events from contained inputs shouldn't close the menu
409
- if (context._menu.contains(event.target) && ((event.type === 'keyup' && event.key === TAB_KEY) || /input|select|option|textarea|form/i.test(event.target.tagName))) {
410
- continue
411
- }
383
+ const relatedTarget = { relatedTarget: context._element }
412
384
 
413
- if (event.type === 'click') {
414
- relatedTarget.clickEvent = event
415
- }
385
+ if (event.type === 'click') {
386
+ relatedTarget.clickEvent = event
416
387
  }
417
388
 
418
389
  context._completeHide(relatedTarget)
419
390
  }
420
391
  }
421
392
 
422
- static getParentFromElement(element) {
423
- return getElementFromSelector(element) || element.parentNode
424
- }
425
-
426
393
  static dataApiKeydownHandler(event) {
427
- // If not input/textarea:
428
- // - And not a key in REGEXP_KEYDOWN => not a dropdown command
429
- // If input/textarea:
430
- // - If space key => not a dropdown command
431
- // - If key is other than escape
432
- // - If key is not up or down => not a dropdown command
433
- // - If trigger inside the menu => not a dropdown command
434
- if (/input|textarea/i.test(event.target.tagName) ?
435
- event.key === SPACE_KEY || (event.key !== ESCAPE_KEY &&
436
- ((event.key !== ARROW_DOWN_KEY && event.key !== ARROW_UP_KEY) ||
437
- event.target.closest(SELECTOR_MENU))) :
438
- !REGEXP_KEYDOWN.test(event.key)) {
439
- return
440
- }
394
+ // If not an UP | DOWN | ESCAPE key => not a dropdown command
395
+ // If input/textarea && if key is other than ESCAPE => not a dropdown command
441
396
 
442
- const isActive = this.classList.contains(CLASS_NAME_SHOW)
397
+ const isInput = /input|textarea/i.test(event.target.tagName)
398
+ const isEscapeEvent = event.key === ESCAPE_KEY
399
+ const isUpOrDownEvent = [ARROW_UP_KEY, ARROW_DOWN_KEY].includes(event.key)
443
400
 
444
- if (!isActive && event.key === ESCAPE_KEY) {
401
+ if (!isUpOrDownEvent && !isEscapeEvent) {
445
402
  return
446
403
  }
447
404
 
448
- event.preventDefault()
449
- event.stopPropagation()
450
-
451
- if (isDisabled(this)) {
405
+ if (isInput && !isEscapeEvent) {
452
406
  return
453
407
  }
454
408
 
455
- const getToggleButton = this.matches(SELECTOR_DATA_TOGGLE) ? this : SelectorEngine.prev(this, SELECTOR_DATA_TOGGLE)[0]
456
- const instance = Dropdown.getOrCreateInstance(getToggleButton)
457
-
458
- if (event.key === ESCAPE_KEY) {
459
- instance.hide()
460
- return
461
- }
409
+ event.preventDefault()
462
410
 
463
- if (event.key === ARROW_UP_KEY || event.key === ARROW_DOWN_KEY) {
464
- if (!isActive) {
465
- instance.show()
466
- }
411
+ const getToggleButton = SelectorEngine.findOne(SELECTOR_DATA_TOGGLE, event.delegateTarget.parentNode)
412
+ const instance = Dropdown.getOrCreateInstance(getToggleButton)
467
413
 
414
+ if (isUpOrDownEvent) {
415
+ event.stopPropagation()
416
+ instance.show()
468
417
  instance._selectMenuItem(event)
469
418
  return
470
419
  }
471
420
 
472
- if (!isActive || event.key === SPACE_KEY) {
473
- Dropdown.clearMenus()
421
+ if (instance._isShown()) { // else is escape and we check if it is shown
422
+ event.stopPropagation()
423
+ instance.hide()
424
+ getToggleButton.focus()
474
425
  }
475
426
  }
476
427
  }
477
428
 
478
429
  /**
479
- * ------------------------------------------------------------------------
480
- * Data Api implementation
481
- * ------------------------------------------------------------------------
430
+ * Data API implementation
482
431
  */
483
432
 
484
433
  EventHandler.on(document, EVENT_KEYDOWN_DATA_API, SELECTOR_DATA_TOGGLE, Dropdown.dataApiKeydownHandler)
@@ -491,10 +440,7 @@ EventHandler.on(document, EVENT_CLICK_DATA_API, SELECTOR_DATA_TOGGLE, function (
491
440
  })
492
441
 
493
442
  /**
494
- * ------------------------------------------------------------------------
495
443
  * jQuery
496
- * ------------------------------------------------------------------------
497
- * add .Dropdown to jQuery only if jQuery is present
498
444
  */
499
445
 
500
446
  defineJQueryPlugin(Dropdown)