administrate-bootstrap-theme 0.1.0 → 0.1.9

Sign up to get free protection for your applications and to get access to all the features.
Files changed (112) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +25 -11
  3. data/Rakefile +10 -14
  4. data/app/assets/config/administrate-bootstrap-theme_manifest.js +1 -0
  5. data/app/assets/javascripts/administrate-bootstrap-theme/theme.js +2 -0
  6. data/app/assets/stylesheets/administrate-bootstrap-theme/_base.scss +17 -1
  7. data/app/assets/stylesheets/administrate-bootstrap-theme/components/_content_body.scss +17 -3
  8. data/app/assets/stylesheets/administrate-bootstrap-theme/components/_form.scss +52 -16
  9. data/app/assets/stylesheets/administrate-bootstrap-theme/theme.scss +12 -0
  10. data/lib/administrate-bootstrap-theme/engine.rb +2 -0
  11. data/lib/administrate-bootstrap-theme/version.rb +1 -1
  12. data/node_modules/bootstrap/js/src/alert.js +141 -0
  13. data/node_modules/bootstrap/js/src/base-component.js +46 -0
  14. data/node_modules/bootstrap/js/src/button.js +95 -0
  15. data/node_modules/bootstrap/js/src/carousel.js +624 -0
  16. data/node_modules/bootstrap/js/src/collapse.js +410 -0
  17. data/node_modules/bootstrap/js/src/dom/data.js +57 -0
  18. data/node_modules/bootstrap/js/src/dom/event-handler.js +331 -0
  19. data/node_modules/bootstrap/js/src/dom/manipulator.js +80 -0
  20. data/node_modules/bootstrap/js/src/dom/selector-engine.js +75 -0
  21. data/node_modules/bootstrap/js/src/dropdown.js +543 -0
  22. data/node_modules/bootstrap/js/src/modal.js +582 -0
  23. data/node_modules/bootstrap/js/src/offcanvas.js +279 -0
  24. data/node_modules/bootstrap/js/src/popover.js +171 -0
  25. data/node_modules/bootstrap/js/src/scrollspy.js +319 -0
  26. data/node_modules/bootstrap/js/src/tab.js +220 -0
  27. data/node_modules/bootstrap/js/src/toast.js +219 -0
  28. data/node_modules/bootstrap/js/src/tooltip.js +802 -0
  29. data/node_modules/bootstrap/js/src/util/index.js +253 -0
  30. data/node_modules/bootstrap/js/src/util/sanitizer.js +127 -0
  31. data/node_modules/bootstrap/js/src/util/scrollbar.js +70 -0
  32. data/node_modules/bootstrap/scss/_accordion.scss +116 -0
  33. data/node_modules/bootstrap/scss/_alert.scss +57 -0
  34. data/node_modules/bootstrap/scss/_badge.scss +29 -0
  35. data/node_modules/bootstrap/scss/_breadcrumb.scss +28 -0
  36. data/node_modules/bootstrap/scss/_button-group.scss +139 -0
  37. data/node_modules/bootstrap/scss/_buttons.scss +111 -0
  38. data/node_modules/bootstrap/scss/_card.scss +215 -0
  39. data/node_modules/bootstrap/scss/_carousel.scss +229 -0
  40. data/node_modules/bootstrap/scss/_close.scss +40 -0
  41. data/node_modules/bootstrap/scss/_containers.scss +41 -0
  42. data/node_modules/bootstrap/scss/_dropdown.scss +246 -0
  43. data/node_modules/bootstrap/scss/_forms.scss +9 -0
  44. data/node_modules/bootstrap/scss/_functions.scss +205 -0
  45. data/node_modules/bootstrap/scss/_grid.scss +22 -0
  46. data/node_modules/bootstrap/scss/_helpers.scss +7 -0
  47. data/node_modules/bootstrap/scss/_images.scss +42 -0
  48. data/node_modules/bootstrap/scss/_list-group.scss +174 -0
  49. data/node_modules/bootstrap/scss/_mixins.scss +41 -0
  50. data/node_modules/bootstrap/scss/_modal.scss +237 -0
  51. data/node_modules/bootstrap/scss/_nav.scss +139 -0
  52. data/node_modules/bootstrap/scss/_navbar.scss +306 -0
  53. data/node_modules/bootstrap/scss/_offcanvas.scss +77 -0
  54. data/node_modules/bootstrap/scss/_pagination.scss +64 -0
  55. data/node_modules/bootstrap/scss/_popover.scss +158 -0
  56. data/node_modules/bootstrap/scss/_progress.scss +48 -0
  57. data/node_modules/bootstrap/scss/_reboot.scss +621 -0
  58. data/node_modules/bootstrap/scss/_root.scss +16 -0
  59. data/node_modules/bootstrap/scss/_spinners.scss +69 -0
  60. data/node_modules/bootstrap/scss/_tables.scss +150 -0
  61. data/node_modules/bootstrap/scss/_toasts.scss +51 -0
  62. data/node_modules/bootstrap/scss/_tooltip.scss +115 -0
  63. data/node_modules/bootstrap/scss/_transitions.scss +21 -0
  64. data/node_modules/bootstrap/scss/_type.scss +104 -0
  65. data/node_modules/bootstrap/scss/_utilities.scss +594 -0
  66. data/node_modules/bootstrap/scss/_variables.scss +1464 -0
  67. data/node_modules/bootstrap/scss/bootstrap-grid.scss +65 -0
  68. data/node_modules/bootstrap/scss/bootstrap-reboot.scss +15 -0
  69. data/node_modules/bootstrap/scss/bootstrap-utilities.scss +18 -0
  70. data/node_modules/bootstrap/scss/bootstrap.scss +52 -0
  71. data/node_modules/bootstrap/scss/forms/_floating-labels.scss +61 -0
  72. data/node_modules/bootstrap/scss/forms/_form-check.scss +152 -0
  73. data/node_modules/bootstrap/scss/forms/_form-control.scss +219 -0
  74. data/node_modules/bootstrap/scss/forms/_form-range.scss +91 -0
  75. data/node_modules/bootstrap/scss/forms/_form-select.scss +67 -0
  76. data/node_modules/bootstrap/scss/forms/_form-text.scss +11 -0
  77. data/node_modules/bootstrap/scss/forms/_input-group.scss +121 -0
  78. data/node_modules/bootstrap/scss/forms/_labels.scss +36 -0
  79. data/node_modules/bootstrap/scss/forms/_validation.scss +12 -0
  80. data/node_modules/bootstrap/scss/helpers/_clearfix.scss +3 -0
  81. data/node_modules/bootstrap/scss/helpers/_colored-links.scss +12 -0
  82. data/node_modules/bootstrap/scss/helpers/_position.scss +30 -0
  83. data/node_modules/bootstrap/scss/helpers/_ratio.scss +26 -0
  84. data/node_modules/bootstrap/scss/helpers/_stretched-link.scss +15 -0
  85. data/node_modules/bootstrap/scss/helpers/_text-truncation.scss +7 -0
  86. data/node_modules/bootstrap/scss/helpers/_visually-hidden.scss +8 -0
  87. data/node_modules/bootstrap/scss/mixins/_alert.scss +11 -0
  88. data/node_modules/bootstrap/scss/mixins/_border-radius.scss +78 -0
  89. data/node_modules/bootstrap/scss/mixins/_box-shadow.scss +18 -0
  90. data/node_modules/bootstrap/scss/mixins/_breakpoints.scss +127 -0
  91. data/node_modules/bootstrap/scss/mixins/_buttons.scss +133 -0
  92. data/node_modules/bootstrap/scss/mixins/_caret.scss +64 -0
  93. data/node_modules/bootstrap/scss/mixins/_clearfix.scss +9 -0
  94. data/node_modules/bootstrap/scss/mixins/_container.scss +9 -0
  95. data/node_modules/bootstrap/scss/mixins/_deprecate.scss +10 -0
  96. data/node_modules/bootstrap/scss/mixins/_forms.scss +134 -0
  97. data/node_modules/bootstrap/scss/mixins/_gradients.scss +47 -0
  98. data/node_modules/bootstrap/scss/mixins/_grid.scss +120 -0
  99. data/node_modules/bootstrap/scss/mixins/_image.scss +16 -0
  100. data/node_modules/bootstrap/scss/mixins/_list-group.scss +24 -0
  101. data/node_modules/bootstrap/scss/mixins/_lists.scss +7 -0
  102. data/node_modules/bootstrap/scss/mixins/_pagination.scss +31 -0
  103. data/node_modules/bootstrap/scss/mixins/_reset-text.scss +17 -0
  104. data/node_modules/bootstrap/scss/mixins/_resize.scss +6 -0
  105. data/node_modules/bootstrap/scss/mixins/_table-variants.scss +21 -0
  106. data/node_modules/bootstrap/scss/mixins/_text-truncate.scss +8 -0
  107. data/node_modules/bootstrap/scss/mixins/_transition.scss +26 -0
  108. data/node_modules/bootstrap/scss/mixins/_utilities.scss +68 -0
  109. data/node_modules/bootstrap/scss/mixins/_visually-hidden.scss +29 -0
  110. data/node_modules/bootstrap/scss/utilities/_api.scss +47 -0
  111. data/node_modules/bootstrap/scss/vendor/_rfs.scss +312 -0
  112. metadata +106 -19
@@ -0,0 +1,543 @@
1
+ /**
2
+ * --------------------------------------------------------------------------
3
+ * Bootstrap (v5.0.0-beta3): dropdown.js
4
+ * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
5
+ * --------------------------------------------------------------------------
6
+ */
7
+
8
+ import * as Popper from '@popperjs/core'
9
+
10
+ import {
11
+ defineJQueryPlugin,
12
+ getElementFromSelector,
13
+ isElement,
14
+ isVisible,
15
+ isRTL,
16
+ noop,
17
+ typeCheckConfig
18
+ } from './util/index'
19
+ import Data from './dom/data'
20
+ import EventHandler from './dom/event-handler'
21
+ import Manipulator from './dom/manipulator'
22
+ import SelectorEngine from './dom/selector-engine'
23
+ import BaseComponent from './base-component'
24
+
25
+ /**
26
+ * ------------------------------------------------------------------------
27
+ * Constants
28
+ * ------------------------------------------------------------------------
29
+ */
30
+
31
+ const NAME = 'dropdown'
32
+ const DATA_KEY = 'bs.dropdown'
33
+ const EVENT_KEY = `.${DATA_KEY}`
34
+ const DATA_API_KEY = '.data-api'
35
+
36
+ const ESCAPE_KEY = 'Escape'
37
+ const SPACE_KEY = 'Space'
38
+ const TAB_KEY = 'Tab'
39
+ const ARROW_UP_KEY = 'ArrowUp'
40
+ const ARROW_DOWN_KEY = 'ArrowDown'
41
+ const RIGHT_MOUSE_BUTTON = 2 // MouseEvent.button value for the secondary button, usually the right button
42
+
43
+ const REGEXP_KEYDOWN = new RegExp(`${ARROW_UP_KEY}|${ARROW_DOWN_KEY}|${ESCAPE_KEY}`)
44
+
45
+ const EVENT_HIDE = `hide${EVENT_KEY}`
46
+ const EVENT_HIDDEN = `hidden${EVENT_KEY}`
47
+ const EVENT_SHOW = `show${EVENT_KEY}`
48
+ const EVENT_SHOWN = `shown${EVENT_KEY}`
49
+ const EVENT_CLICK = `click${EVENT_KEY}`
50
+ const EVENT_CLICK_DATA_API = `click${EVENT_KEY}${DATA_API_KEY}`
51
+ const EVENT_KEYDOWN_DATA_API = `keydown${EVENT_KEY}${DATA_API_KEY}`
52
+ const EVENT_KEYUP_DATA_API = `keyup${EVENT_KEY}${DATA_API_KEY}`
53
+
54
+ const CLASS_NAME_DISABLED = 'disabled'
55
+ const CLASS_NAME_SHOW = 'show'
56
+ const CLASS_NAME_DROPUP = 'dropup'
57
+ const CLASS_NAME_DROPEND = 'dropend'
58
+ const CLASS_NAME_DROPSTART = 'dropstart'
59
+ const CLASS_NAME_NAVBAR = 'navbar'
60
+
61
+ const SELECTOR_DATA_TOGGLE = '[data-bs-toggle="dropdown"]'
62
+ const SELECTOR_MENU = '.dropdown-menu'
63
+ const SELECTOR_NAVBAR_NAV = '.navbar-nav'
64
+ const SELECTOR_VISIBLE_ITEMS = '.dropdown-menu .dropdown-item:not(.disabled):not(:disabled)'
65
+
66
+ const PLACEMENT_TOP = isRTL() ? 'top-end' : 'top-start'
67
+ const PLACEMENT_TOPEND = isRTL() ? 'top-start' : 'top-end'
68
+ const PLACEMENT_BOTTOM = isRTL() ? 'bottom-end' : 'bottom-start'
69
+ const PLACEMENT_BOTTOMEND = isRTL() ? 'bottom-start' : 'bottom-end'
70
+ const PLACEMENT_RIGHT = isRTL() ? 'left-start' : 'right-start'
71
+ const PLACEMENT_LEFT = isRTL() ? 'right-start' : 'left-start'
72
+
73
+ const Default = {
74
+ offset: [0, 2],
75
+ boundary: 'clippingParents',
76
+ reference: 'toggle',
77
+ display: 'dynamic',
78
+ popperConfig: null
79
+ }
80
+
81
+ const DefaultType = {
82
+ offset: '(array|string|function)',
83
+ boundary: '(string|element)',
84
+ reference: '(string|element|object)',
85
+ display: 'string',
86
+ popperConfig: '(null|object|function)'
87
+ }
88
+
89
+ /**
90
+ * ------------------------------------------------------------------------
91
+ * Class Definition
92
+ * ------------------------------------------------------------------------
93
+ */
94
+
95
+ class Dropdown extends BaseComponent {
96
+ constructor(element, config) {
97
+ super(element)
98
+
99
+ this._popper = null
100
+ this._config = this._getConfig(config)
101
+ this._menu = this._getMenuElement()
102
+ this._inNavbar = this._detectNavbar()
103
+
104
+ this._addEventListeners()
105
+ }
106
+
107
+ // Getters
108
+
109
+ static get Default() {
110
+ return Default
111
+ }
112
+
113
+ static get DefaultType() {
114
+ return DefaultType
115
+ }
116
+
117
+ static get DATA_KEY() {
118
+ return DATA_KEY
119
+ }
120
+
121
+ // Public
122
+
123
+ toggle() {
124
+ if (this._element.disabled || this._element.classList.contains(CLASS_NAME_DISABLED)) {
125
+ return
126
+ }
127
+
128
+ const isActive = this._element.classList.contains(CLASS_NAME_SHOW)
129
+
130
+ Dropdown.clearMenus()
131
+
132
+ if (isActive) {
133
+ return
134
+ }
135
+
136
+ this.show()
137
+ }
138
+
139
+ show() {
140
+ if (this._element.disabled || this._element.classList.contains(CLASS_NAME_DISABLED) || this._menu.classList.contains(CLASS_NAME_SHOW)) {
141
+ return
142
+ }
143
+
144
+ const parent = Dropdown.getParentFromElement(this._element)
145
+ const relatedTarget = {
146
+ relatedTarget: this._element
147
+ }
148
+
149
+ const showEvent = EventHandler.trigger(this._element, EVENT_SHOW, relatedTarget)
150
+
151
+ if (showEvent.defaultPrevented) {
152
+ return
153
+ }
154
+
155
+ // Totally disable Popper for Dropdowns in Navbar
156
+ if (this._inNavbar) {
157
+ Manipulator.setDataAttribute(this._menu, 'popper', 'none')
158
+ } else {
159
+ if (typeof Popper === 'undefined') {
160
+ throw new TypeError('Bootstrap\'s dropdowns require Popper (https://popper.js.org)')
161
+ }
162
+
163
+ let referenceElement = this._element
164
+
165
+ if (this._config.reference === 'parent') {
166
+ referenceElement = parent
167
+ } else if (isElement(this._config.reference)) {
168
+ referenceElement = this._config.reference
169
+
170
+ // Check if it's jQuery element
171
+ if (typeof this._config.reference.jquery !== 'undefined') {
172
+ referenceElement = this._config.reference[0]
173
+ }
174
+ } else if (typeof this._config.reference === 'object') {
175
+ referenceElement = this._config.reference
176
+ }
177
+
178
+ const popperConfig = this._getPopperConfig()
179
+ const isDisplayStatic = popperConfig.modifiers.find(modifier => modifier.name === 'applyStyles' && modifier.enabled === false)
180
+
181
+ this._popper = Popper.createPopper(referenceElement, this._menu, popperConfig)
182
+
183
+ if (isDisplayStatic) {
184
+ Manipulator.setDataAttribute(this._menu, 'popper', 'static')
185
+ }
186
+ }
187
+
188
+ // If this is a touch-enabled device we add extra
189
+ // empty mouseover listeners to the body's immediate children;
190
+ // only needed because of broken event delegation on iOS
191
+ // https://www.quirksmode.org/blog/archives/2014/02/mouse_event_bub.html
192
+ if ('ontouchstart' in document.documentElement &&
193
+ !parent.closest(SELECTOR_NAVBAR_NAV)) {
194
+ [].concat(...document.body.children)
195
+ .forEach(elem => EventHandler.on(elem, 'mouseover', null, noop()))
196
+ }
197
+
198
+ this._element.focus()
199
+ this._element.setAttribute('aria-expanded', true)
200
+
201
+ this._menu.classList.toggle(CLASS_NAME_SHOW)
202
+ this._element.classList.toggle(CLASS_NAME_SHOW)
203
+ EventHandler.trigger(this._element, EVENT_SHOWN, relatedTarget)
204
+ }
205
+
206
+ hide() {
207
+ if (this._element.disabled || this._element.classList.contains(CLASS_NAME_DISABLED) || !this._menu.classList.contains(CLASS_NAME_SHOW)) {
208
+ return
209
+ }
210
+
211
+ const relatedTarget = {
212
+ relatedTarget: this._element
213
+ }
214
+
215
+ const hideEvent = EventHandler.trigger(this._element, EVENT_HIDE, relatedTarget)
216
+
217
+ if (hideEvent.defaultPrevented) {
218
+ return
219
+ }
220
+
221
+ if (this._popper) {
222
+ this._popper.destroy()
223
+ }
224
+
225
+ this._menu.classList.toggle(CLASS_NAME_SHOW)
226
+ this._element.classList.toggle(CLASS_NAME_SHOW)
227
+ Manipulator.removeDataAttribute(this._menu, 'popper')
228
+ EventHandler.trigger(this._element, EVENT_HIDDEN, relatedTarget)
229
+ }
230
+
231
+ dispose() {
232
+ EventHandler.off(this._element, EVENT_KEY)
233
+ this._menu = null
234
+
235
+ if (this._popper) {
236
+ this._popper.destroy()
237
+ this._popper = null
238
+ }
239
+
240
+ super.dispose()
241
+ }
242
+
243
+ update() {
244
+ this._inNavbar = this._detectNavbar()
245
+ if (this._popper) {
246
+ this._popper.update()
247
+ }
248
+ }
249
+
250
+ // Private
251
+
252
+ _addEventListeners() {
253
+ EventHandler.on(this._element, EVENT_CLICK, event => {
254
+ event.preventDefault()
255
+ this.toggle()
256
+ })
257
+ }
258
+
259
+ _getConfig(config) {
260
+ config = {
261
+ ...this.constructor.Default,
262
+ ...Manipulator.getDataAttributes(this._element),
263
+ ...config
264
+ }
265
+
266
+ typeCheckConfig(NAME, config, this.constructor.DefaultType)
267
+
268
+ if (typeof config.reference === 'object' && !isElement(config.reference) &&
269
+ typeof config.reference.getBoundingClientRect !== 'function'
270
+ ) {
271
+ // Popper virtual elements require a getBoundingClientRect method
272
+ throw new TypeError(`${NAME.toUpperCase()}: Option "reference" provided type "object" without a required "getBoundingClientRect" method.`)
273
+ }
274
+
275
+ return config
276
+ }
277
+
278
+ _getMenuElement() {
279
+ return SelectorEngine.next(this._element, SELECTOR_MENU)[0]
280
+ }
281
+
282
+ _getPlacement() {
283
+ const parentDropdown = this._element.parentNode
284
+
285
+ if (parentDropdown.classList.contains(CLASS_NAME_DROPEND)) {
286
+ return PLACEMENT_RIGHT
287
+ }
288
+
289
+ if (parentDropdown.classList.contains(CLASS_NAME_DROPSTART)) {
290
+ return PLACEMENT_LEFT
291
+ }
292
+
293
+ // We need to trim the value because custom properties can also include spaces
294
+ const isEnd = getComputedStyle(this._menu).getPropertyValue('--bs-position').trim() === 'end'
295
+
296
+ if (parentDropdown.classList.contains(CLASS_NAME_DROPUP)) {
297
+ return isEnd ? PLACEMENT_TOPEND : PLACEMENT_TOP
298
+ }
299
+
300
+ return isEnd ? PLACEMENT_BOTTOMEND : PLACEMENT_BOTTOM
301
+ }
302
+
303
+ _detectNavbar() {
304
+ return this._element.closest(`.${CLASS_NAME_NAVBAR}`) !== null
305
+ }
306
+
307
+ _getOffset() {
308
+ const { offset } = this._config
309
+
310
+ if (typeof offset === 'string') {
311
+ return offset.split(',').map(val => Number.parseInt(val, 10))
312
+ }
313
+
314
+ if (typeof offset === 'function') {
315
+ return popperData => offset(popperData, this._element)
316
+ }
317
+
318
+ return offset
319
+ }
320
+
321
+ _getPopperConfig() {
322
+ const defaultBsPopperConfig = {
323
+ placement: this._getPlacement(),
324
+ modifiers: [{
325
+ name: 'preventOverflow',
326
+ options: {
327
+ boundary: this._config.boundary
328
+ }
329
+ },
330
+ {
331
+ name: 'offset',
332
+ options: {
333
+ offset: this._getOffset()
334
+ }
335
+ }]
336
+ }
337
+
338
+ // Disable Popper if we have a static display
339
+ if (this._config.display === 'static') {
340
+ defaultBsPopperConfig.modifiers = [{
341
+ name: 'applyStyles',
342
+ enabled: false
343
+ }]
344
+ }
345
+
346
+ return {
347
+ ...defaultBsPopperConfig,
348
+ ...(typeof this._config.popperConfig === 'function' ? this._config.popperConfig(defaultBsPopperConfig) : this._config.popperConfig)
349
+ }
350
+ }
351
+
352
+ // Static
353
+
354
+ static dropdownInterface(element, config) {
355
+ let data = Data.get(element, DATA_KEY)
356
+ const _config = typeof config === 'object' ? config : null
357
+
358
+ if (!data) {
359
+ data = new Dropdown(element, _config)
360
+ }
361
+
362
+ if (typeof config === 'string') {
363
+ if (typeof data[config] === 'undefined') {
364
+ throw new TypeError(`No method named "${config}"`)
365
+ }
366
+
367
+ data[config]()
368
+ }
369
+ }
370
+
371
+ static jQueryInterface(config) {
372
+ return this.each(function () {
373
+ Dropdown.dropdownInterface(this, config)
374
+ })
375
+ }
376
+
377
+ static clearMenus(event) {
378
+ if (event) {
379
+ if (event.button === RIGHT_MOUSE_BUTTON || (event.type === 'keyup' && event.key !== TAB_KEY)) {
380
+ return
381
+ }
382
+
383
+ if (/input|select|textarea|form/i.test(event.target.tagName)) {
384
+ return
385
+ }
386
+ }
387
+
388
+ const toggles = SelectorEngine.find(SELECTOR_DATA_TOGGLE)
389
+
390
+ for (let i = 0, len = toggles.length; i < len; i++) {
391
+ const context = Data.get(toggles[i], DATA_KEY)
392
+ const relatedTarget = {
393
+ relatedTarget: toggles[i]
394
+ }
395
+
396
+ if (event && event.type === 'click') {
397
+ relatedTarget.clickEvent = event
398
+ }
399
+
400
+ if (!context) {
401
+ continue
402
+ }
403
+
404
+ const dropdownMenu = context._menu
405
+ if (!toggles[i].classList.contains(CLASS_NAME_SHOW)) {
406
+ continue
407
+ }
408
+
409
+ if (event) {
410
+ // Don't close the menu if the clicked element or one of its parents is the dropdown button
411
+ if ([context._element].some(element => event.composedPath().includes(element))) {
412
+ continue
413
+ }
414
+
415
+ // Tab navigation through the dropdown menu shouldn't close the menu
416
+ if (event.type === 'keyup' && event.key === TAB_KEY && dropdownMenu.contains(event.target)) {
417
+ continue
418
+ }
419
+ }
420
+
421
+ const hideEvent = EventHandler.trigger(toggles[i], EVENT_HIDE, relatedTarget)
422
+ if (hideEvent.defaultPrevented) {
423
+ continue
424
+ }
425
+
426
+ // If this is a touch-enabled device we remove the extra
427
+ // empty mouseover listeners we added for iOS support
428
+ if ('ontouchstart' in document.documentElement) {
429
+ [].concat(...document.body.children)
430
+ .forEach(elem => EventHandler.off(elem, 'mouseover', null, noop()))
431
+ }
432
+
433
+ toggles[i].setAttribute('aria-expanded', 'false')
434
+
435
+ if (context._popper) {
436
+ context._popper.destroy()
437
+ }
438
+
439
+ dropdownMenu.classList.remove(CLASS_NAME_SHOW)
440
+ toggles[i].classList.remove(CLASS_NAME_SHOW)
441
+ Manipulator.removeDataAttribute(dropdownMenu, 'popper')
442
+ EventHandler.trigger(toggles[i], EVENT_HIDDEN, relatedTarget)
443
+ }
444
+ }
445
+
446
+ static getParentFromElement(element) {
447
+ return getElementFromSelector(element) || element.parentNode
448
+ }
449
+
450
+ static dataApiKeydownHandler(event) {
451
+ // If not input/textarea:
452
+ // - And not a key in REGEXP_KEYDOWN => not a dropdown command
453
+ // If input/textarea:
454
+ // - If space key => not a dropdown command
455
+ // - If key is other than escape
456
+ // - If key is not up or down => not a dropdown command
457
+ // - If trigger inside the menu => not a dropdown command
458
+ if (/input|textarea/i.test(event.target.tagName) ?
459
+ event.key === SPACE_KEY || (event.key !== ESCAPE_KEY &&
460
+ ((event.key !== ARROW_DOWN_KEY && event.key !== ARROW_UP_KEY) ||
461
+ event.target.closest(SELECTOR_MENU))) :
462
+ !REGEXP_KEYDOWN.test(event.key)) {
463
+ return
464
+ }
465
+
466
+ event.preventDefault()
467
+ event.stopPropagation()
468
+
469
+ if (this.disabled || this.classList.contains(CLASS_NAME_DISABLED)) {
470
+ return
471
+ }
472
+
473
+ const parent = Dropdown.getParentFromElement(this)
474
+ const isActive = this.classList.contains(CLASS_NAME_SHOW)
475
+
476
+ if (event.key === ESCAPE_KEY) {
477
+ const button = this.matches(SELECTOR_DATA_TOGGLE) ? this : SelectorEngine.prev(this, SELECTOR_DATA_TOGGLE)[0]
478
+ button.focus()
479
+ Dropdown.clearMenus()
480
+ return
481
+ }
482
+
483
+ if (!isActive && (event.key === ARROW_UP_KEY || event.key === ARROW_DOWN_KEY)) {
484
+ const button = this.matches(SELECTOR_DATA_TOGGLE) ? this : SelectorEngine.prev(this, SELECTOR_DATA_TOGGLE)[0]
485
+ button.click()
486
+ return
487
+ }
488
+
489
+ if (!isActive || event.key === SPACE_KEY) {
490
+ Dropdown.clearMenus()
491
+ return
492
+ }
493
+
494
+ const items = SelectorEngine.find(SELECTOR_VISIBLE_ITEMS, parent).filter(isVisible)
495
+
496
+ if (!items.length) {
497
+ return
498
+ }
499
+
500
+ let index = items.indexOf(event.target)
501
+
502
+ // Up
503
+ if (event.key === ARROW_UP_KEY && index > 0) {
504
+ index--
505
+ }
506
+
507
+ // Down
508
+ if (event.key === ARROW_DOWN_KEY && index < items.length - 1) {
509
+ index++
510
+ }
511
+
512
+ // index is -1 if the first keydown is an ArrowUp
513
+ index = index === -1 ? 0 : index
514
+
515
+ items[index].focus()
516
+ }
517
+ }
518
+
519
+ /**
520
+ * ------------------------------------------------------------------------
521
+ * Data Api implementation
522
+ * ------------------------------------------------------------------------
523
+ */
524
+
525
+ EventHandler.on(document, EVENT_KEYDOWN_DATA_API, SELECTOR_DATA_TOGGLE, Dropdown.dataApiKeydownHandler)
526
+ EventHandler.on(document, EVENT_KEYDOWN_DATA_API, SELECTOR_MENU, Dropdown.dataApiKeydownHandler)
527
+ EventHandler.on(document, EVENT_CLICK_DATA_API, Dropdown.clearMenus)
528
+ EventHandler.on(document, EVENT_KEYUP_DATA_API, Dropdown.clearMenus)
529
+ EventHandler.on(document, EVENT_CLICK_DATA_API, SELECTOR_DATA_TOGGLE, function (event) {
530
+ event.preventDefault()
531
+ Dropdown.dropdownInterface(this)
532
+ })
533
+
534
+ /**
535
+ * ------------------------------------------------------------------------
536
+ * jQuery
537
+ * ------------------------------------------------------------------------
538
+ * add .Dropdown to jQuery only if jQuery is present
539
+ */
540
+
541
+ defineJQueryPlugin(NAME, Dropdown)
542
+
543
+ export default Dropdown