Skip to content

Commit 290b9ee

Browse files
authored
fix(carousel): arrow keys break animation if carousel sliding (#34307)
1 parent 8be957b commit 290b9ee

File tree

2 files changed

+81
-15
lines changed

2 files changed

+81
-15
lines changed

js/src/carousel.js

Lines changed: 14 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,11 @@ const ORDER_PREV = 'prev'
5959
const DIRECTION_LEFT = 'left'
6060
const DIRECTION_RIGHT = 'right'
6161

62+
const KEY_TO_DIRECTION = {
63+
[ARROW_LEFT_KEY]: DIRECTION_RIGHT,
64+
[ARROW_RIGHT_KEY]: DIRECTION_LEFT
65+
}
66+
6267
const EVENT_SLIDE = `slide${EVENT_KEY}`
6368
const EVENT_SLID = `slid${EVENT_KEY}`
6469
const EVENT_KEYDOWN = `keydown${EVENT_KEY}`
@@ -134,9 +139,7 @@ class Carousel extends BaseComponent {
134139
// Public
135140

136141
next() {
137-
if (!this._isSliding) {
138-
this._slide(ORDER_NEXT)
139-
}
142+
this._slide(ORDER_NEXT)
140143
}
141144

142145
nextWhenVisible() {
@@ -148,9 +151,7 @@ class Carousel extends BaseComponent {
148151
}
149152

150153
prev() {
151-
if (!this._isSliding) {
152-
this._slide(ORDER_PREV)
153-
}
154+
this._slide(ORDER_PREV)
154155
}
155156

156157
pause(event) {
@@ -319,12 +320,10 @@ class Carousel extends BaseComponent {
319320
return
320321
}
321322

322-
if (event.key === ARROW_LEFT_KEY) {
323-
event.preventDefault()
324-
this._slide(DIRECTION_RIGHT)
325-
} else if (event.key === ARROW_RIGHT_KEY) {
323+
const direction = KEY_TO_DIRECTION[event.key]
324+
if (direction) {
326325
event.preventDefault()
327-
this._slide(DIRECTION_LEFT)
326+
this._slide(direction)
328327
}
329328
}
330329

@@ -408,6 +407,10 @@ class Carousel extends BaseComponent {
408407
return
409408
}
410409

410+
if (this._isSliding) {
411+
return
412+
}
413+
411414
const slideEvent = this._triggerSlideEvent(nextElement, eventDirectionName)
412415
if (slideEvent.defaultPrevented) {
413416
return

js/tests/unit/carousel.spec.js

Lines changed: 67 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -203,6 +203,26 @@ describe('Carousel', () => {
203203
expect(spySlide).not.toHaveBeenCalled()
204204
})
205205

206+
it('should not slide if arrow key is pressed and carousel is sliding', () => {
207+
fixtureEl.innerHTML = '<div></div>'
208+
209+
const carouselEl = fixtureEl.querySelector('div')
210+
const carousel = new Carousel(carouselEl, {})
211+
212+
spyOn(carousel, '_triggerSlideEvent')
213+
214+
carousel._isSliding = true;
215+
216+
['ArrowLeft', 'ArrowRight'].forEach(key => {
217+
const keydown = createEvent('keydown')
218+
keydown.key = key
219+
220+
carouselEl.dispatchEvent(keydown)
221+
})
222+
223+
expect(carousel._triggerSlideEvent).not.toHaveBeenCalled()
224+
})
225+
206226
it('should wrap around from end to start when wrap option is true', done => {
207227
fixtureEl.innerHTML = [
208228
'<div id="myCarousel" class="carousel slide">',
@@ -487,6 +507,49 @@ describe('Carousel', () => {
487507
})
488508
})
489509

510+
it('should not slide when swiping and carousel is sliding', done => {
511+
Simulator.setType('touch')
512+
clearPointerEvents()
513+
document.documentElement.ontouchstart = () => {}
514+
515+
fixtureEl.innerHTML = [
516+
'<div class="carousel" data-bs-interval="false">',
517+
' <div class="carousel-inner">',
518+
' <div id="item" class="carousel-item active">',
519+
' <img alt="">',
520+
' </div>',
521+
' <div class="carousel-item">',
522+
' <img alt="">',
523+
' </div>',
524+
' </div>',
525+
'</div>'
526+
].join('')
527+
528+
const carouselEl = fixtureEl.querySelector('.carousel')
529+
const carousel = new Carousel(carouselEl)
530+
carousel._isSliding = true
531+
532+
spyOn(carousel, '_triggerSlideEvent')
533+
534+
Simulator.gestures.swipe(carouselEl, {
535+
deltaX: 300,
536+
deltaY: 0
537+
})
538+
539+
Simulator.gestures.swipe(carouselEl, {
540+
pos: [300, 10],
541+
deltaX: -300,
542+
deltaY: 0
543+
})
544+
545+
setTimeout(() => {
546+
expect(carousel._triggerSlideEvent).not.toHaveBeenCalled()
547+
delete document.documentElement.ontouchstart
548+
restorePointerEvents()
549+
done()
550+
}, 300)
551+
})
552+
490553
it('should not allow pinch with touch events', done => {
491554
Simulator.setType('touch')
492555
clearPointerEvents()
@@ -552,12 +615,12 @@ describe('Carousel', () => {
552615
const carouselEl = fixtureEl.querySelector('div')
553616
const carousel = new Carousel(carouselEl, {})
554617

555-
spyOn(carousel, '_slide')
618+
spyOn(carousel, '_triggerSlideEvent')
556619

557620
carousel._isSliding = true
558621
carousel.next()
559622

560-
expect(carousel._slide).not.toHaveBeenCalled()
623+
expect(carousel._triggerSlideEvent).not.toHaveBeenCalled()
561624
})
562625

563626
it('should not fire slid when slide is prevented', done => {
@@ -763,12 +826,12 @@ describe('Carousel', () => {
763826
const carouselEl = fixtureEl.querySelector('div')
764827
const carousel = new Carousel(carouselEl, {})
765828

766-
spyOn(carousel, '_slide')
829+
spyOn(carousel, '_triggerSlideEvent')
767830

768831
carousel._isSliding = true
769832
carousel.prev()
770833

771-
expect(carousel._slide).not.toHaveBeenCalled()
834+
expect(carousel._triggerSlideEvent).not.toHaveBeenCalled()
772835
})
773836
})
774837

0 commit comments

Comments
 (0)