mirror of
https://github.com/twbs/bootstrap.git
synced 2025-08-15 01:55:46 +02:00
Fix: Popover with hover and click triggers closes on mouseleave (#41511)
* Fix: Popover with hover and click triggers closes on mouseleave When a popover is configured with `trigger: 'hover click'`, if you open it by a click, it would incorrectly close when the mouse pointer leaves the trigger element. This was because the `mouseleave` event (part of the hover trigger) would hide the popover without adequately respecting the click trigger's intent to keep it open. This commit modifies the click event listener within `Tooltip.js` (which Popover extends) to explicitly manage the `_activeTrigger[TRIGGER_CLICK]` state: - When a click opens the popover or makes a hover-opened popover sticky, `_activeTrigger[TRIGGER_CLICK]` is set to `true`. - When a click closes an already click-activated popover, `_activeTrigger[TRIGGER_CLICK]` is set to `false`. The `_leave()` method, called by `mouseleave`, already checks `_isWithActiveTrigger()`. With `_activeTrigger[TRIGGER_CLICK]` now accurately reflecting the click state, `_leave()` will not hide a click-activated popover when the mouse leaves the trigger element. The popover will now correctly remain open until a subsequent click closes it. * Removed `test-popover.html` * Fix linting issues * Add unit test --------- Co-authored-by: google-labs-jules[bot] <161369871+google-labs-jules[bot]@users.noreply.github.com> Co-authored-by: Julien Déramond <juderamond@gmail.com>
This commit is contained in:
@@ -448,6 +448,7 @@ class Tooltip extends BaseComponent {
|
|||||||
if (trigger === 'click') {
|
if (trigger === 'click') {
|
||||||
EventHandler.on(this._element, this.constructor.eventName(EVENT_CLICK), this._config.selector, event => {
|
EventHandler.on(this._element, this.constructor.eventName(EVENT_CLICK), this._config.selector, event => {
|
||||||
const context = this._initializeOnDelegatedTarget(event)
|
const context = this._initializeOnDelegatedTarget(event)
|
||||||
|
context._activeTrigger[TRIGGER_CLICK] = !(context._isShown() && context._activeTrigger[TRIGGER_CLICK])
|
||||||
context.toggle()
|
context.toggle()
|
||||||
})
|
})
|
||||||
} else if (trigger !== TRIGGER_MANUAL) {
|
} else if (trigger !== TRIGGER_MANUAL) {
|
||||||
|
@@ -1,6 +1,8 @@
|
|||||||
import EventHandler from '../../src/dom/event-handler.js'
|
import EventHandler from '../../src/dom/event-handler.js'
|
||||||
import Popover from '../../src/popover.js'
|
import Popover from '../../src/popover.js'
|
||||||
import { clearFixture, getFixture, jQueryMock } from '../helpers/fixture.js'
|
import {
|
||||||
|
clearFixture, getFixture, jQueryMock, createEvent
|
||||||
|
} from '../helpers/fixture.js'
|
||||||
|
|
||||||
describe('Popover', () => {
|
describe('Popover', () => {
|
||||||
let fixtureEl
|
let fixtureEl
|
||||||
@@ -313,6 +315,28 @@ describe('Popover', () => {
|
|||||||
popover.show()
|
popover.show()
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
it('should keep popover open when mouse leaves after click trigger', () => {
|
||||||
|
return new Promise(resolve => {
|
||||||
|
fixtureEl.innerHTML = '<a href="#" title="Popover" data-bs-content="https://x.com/getbootstrap" data-bs-trigger="hover click">BS X</a>'
|
||||||
|
|
||||||
|
const popoverEl = fixtureEl.querySelector('a')
|
||||||
|
new Popover(popoverEl) // eslint-disable-line no-new
|
||||||
|
|
||||||
|
popoverEl.addEventListener('shown.bs.popover', () => {
|
||||||
|
popoverEl.dispatchEvent(createEvent('mouseout'))
|
||||||
|
|
||||||
|
popoverEl.addEventListener('hide.bs.popover', () => {
|
||||||
|
throw new Error('Popover should not hide when mouse leaves after click')
|
||||||
|
})
|
||||||
|
|
||||||
|
expect(document.querySelector('.popover')).not.toBeNull()
|
||||||
|
resolve()
|
||||||
|
})
|
||||||
|
|
||||||
|
popoverEl.click()
|
||||||
|
})
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
describe('hide', () => {
|
describe('hide', () => {
|
||||||
|
Reference in New Issue
Block a user